commit 8f7196e3e8e8f4c94bff710f844f9926d27524a7 Author: Marco Hladik Date: Mon Feb 14 00:13:05 2022 -0800 Initial commit. I made it compile on modern systems I think. There may be some timidity fixes too, but those could have been done to my rott fork too. I don't remember sorry. diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..dfb355f --- /dev/null +++ b/Makefile @@ -0,0 +1,202 @@ +#-----------------------------------------------------------------------------# +# Duke3D makefile. +#-----------------------------------------------------------------------------# + +linux_ppc := false +beos := false +macosx := false +freebsd := false +solaris := false +shareware := false +controls_menu := true +#use_asm := true + +#-----------------------------------------------------------------------------# +# If this makefile fails to detect Cygwin correctly, or you want to force +# the build process's behaviour, set it to "true" or "false" (w/o quotes). +#-----------------------------------------------------------------------------# +#cygwin := true +#cygwin := false +cygwin := autodetect + +# you only need to set these for Cygwin at the moment. +SDL_INC_DIR = /cygdrive/c/SDL/include +SDL_LIB_DIR = /cygdrive/c/SDL/lib + +CC = gcc + +# need this for now. +ifeq ($(strip $(beos)),true) + use_asm := false +endif + +# Don't touch anything below this line unless you know what you're doing. + +ifeq ($(strip $(cygwin)),autodetect) + ifneq ($(strip $(shell gcc -v 2>&1 |grep "cygwin")),) + cygwin := true + else + cygwin := false + endif +endif + + +ifeq ($(strip $(cygwin)),true) + ifeq ($(strip $(SDL_INC_DIR)),please_set_me_cygwin_users) + $(error Cygwin users need to set the SDL_INC_DIR envr var.) + else + SDL_CFLAGS := -I$(SDL_INC_DIR) + endif + + ifeq ($(strip $(SDL_LIB_DIR)),please_set_me_cygwin_users) + $(error Cygwin users need to set the SDL_LIB_DIR envr var.) + else + SDL_LDFLAGS := -L$(SDL_LIB_DIR) -lSDL + endif + +else + ifneq ($(strip $(freebsd)),true) + SDL_CFLAGS := $(shell sdl-config --cflags) + SDL_LDFLAGS := $(shell sdl-config --libs) -L. + endif +endif + +ifeq ($(strip $(macosx)),true) + EXTRACFLAGS += -DPLATFORM_MACOSX=1 + EXTRALDFLAGS += -lSDLmain +endif + +ifeq ($(strip $(freebsd)),true) + EXTRACFLAGS += -DPLATFORM_FREEBSD=1 + SDL_CFLAGS := $(shell sdl11-config --cflags) + SDL_LDFLAGS := $(shell sdl11-config --libs) -L. +endif + +ifeq ($(strip $(linux_ppc)),true) + EXTRACFLAGS += -DPLATFORM_LINUXPPC=1 +endif + +ifneq ($(strip $(cygwin)),true) + ifneq ($(strip $(macosx)),true) + ifneq ($(strip $(beos)),true) + EXTRACFLAGS += -DUSE_EXECINFO=1 + endif + endif +endif + +ifeq ($(strip $(solaris)),true) + CC = cc + EXTRALDFLAGS += -lsocket -lnsl + CFLAGS += -DPLATFORM_SOLARIS +endif + +ifeq ($(strip $(shareware)),true) + EXTRACFLAGS += -DVOLUMEONE +else + EXTRACFLAGS += -DVOLUMEALL +endif + +ifeq ($(strip $(controls_menu)),true) + EXTRACFLAGS += -DCONTROLS_CONFIG_MENU=1 +endif + +BUILDOBJS := \ + buildengine/cache1d.o \ + buildengine/engine.o \ + buildengine/sdl_driver.o \ + buildengine/mmulti.o \ + buildengine/pragmas.o \ + buildengine/unix_compat.o + +ifeq ($(strip $(use_asm)),true) + BUILDOBJS += buildengine/a_gnu.o buildengine/a_nasm.o +else + BUILDOBJS += buildengine/a.o +endif + +CFLAGS=-m32 -c -g $(SDL_CFLAGS) -DUSE_SDL=1 -DPLATFORM_UNIX=1 $(EXTRACFLAGS) + +ifeq ($(strip $(solaris)),true) + CFLAGS += -xO5 -xchar=u +else + # Always turn OFF strict aliasing, even when optimizing. Otherwise, this + # is just an accident waiting to happen... --ryan. + CFLAGS += -fno-strict-aliasing + CFLAGS += -W -Wall -Wno-unused -funsigned-char + ifeq ($(strip $(macosx)),true) + OPTIMIZE = -O3 -mdynamic-no-pic -falign-loops=16 + else + OPTIMIZE = -O2 + endif +endif + +# Uncomment this to compile with the Intel compiler (v6.0) +#CC = icc +#CFLAGS = -g $(SDL_CFLAGS) -DUSE_SDL=1 -DPLATFORM_UNIX=1 -DUSE_I386_ASM=1 $(EXTRACFLAGS) -O2 + +LDLIBS = -lSDL -lSDL_mixer $(EXTRALDFLAGS) + +ifeq ($(strip $(freebsd)),true) +LDLIBS = -lSDL_mixer $(EXTRALDFLAGS) +endif + +# !!! FIXME: Do we even need this? It doesn't fly on MacOS X. --ryan. +#LDLIBS += -Wl,-E + +.PHONY: duke3d build buildengine clean distclean +all: buildengine duke3d build + + +%.o : %.c + $(CC) $(CFLAGS) $(OPTIMIZE) -o $@ $< + +# Animation playback crashes due to optimization error on MacOS X. --ryan. +ifeq ($(strip $(macosx)),true) +animlib.o : animlib.c + $(CC) $(CFLAGS) -o $@ $< +endif + +# Animation playback crashes due to optimization error on Linux PPC. --Felipe Barriga. +ifeq ($(strip $(linux_ppc)),true) +animlib.o : animlib.c + $(CC) $(CFLAGS) -o $@ $< +endif + +audiolib/audiolib.a: + $(MAKE) -C audiolib CC="$(CC)" CFLAGS="$(CFLAGS)" LDLIBS="$(LDLIBS)" + +buildengine: + make -C buildengine + +duke3d: \ + actors.o \ + animlib.o \ + control.o \ + config.o \ + game.o \ + gamedef.o \ + global.o \ + keyboard.o \ + menues.o \ + player.o \ + premap.o \ + rts.o \ + scriplib.o \ + sector.o \ + sounds.o \ + dukemusc.o \ + audiolib/audiolib.a + $(CC) -m32 $^ $(BUILDOBJS) $(LDLIBS) -o $@ + +build: astub.o + $(CC) -m32 $^ $(BUILDOBJS) buildengine/build.o $(LDLIBS) -o $@ + +clean: + $(MAKE) -C audiolib clean + $(MAKE) -C buildengine clean + rm -rf duke3d build *.o + +distclean: clean + $(MAKE) -C audiolib distclean + $(MAKE) -C buildengine distclean + rm -rf *~ diff --git a/_animlib.h b/_animlib.h new file mode 100755 index 0000000..eaa67b5 --- /dev/null +++ b/_animlib.h @@ -0,0 +1,42 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment + +This file is part of Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Original Source: 1996 - Todd Replogle +Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms +*/ +//------------------------------------------------------------------------- + +///////////////////////////////////////////////////////////////////////////// +// +// ANIMLIB.H +// +///////////////////////////////////////////////////////////////////////////// + +#ifndef _animlib_private_ +#define _animlib_private_ +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +}; +#endif +#endif diff --git a/_functio.h b/_functio.h new file mode 100755 index 0000000..47a81a4 --- /dev/null +++ b/_functio.h @@ -0,0 +1,247 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment + +This file is part of Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Original Source: 1996 - Todd Replogle +Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms +*/ +//------------------------------------------------------------------------- + +// _functio.h + +// file created by makehead.exe +// these headers contain default key assignments, as well as +// default button assignments and game function names +// axis defaults are also included + + +#ifndef _function_private_ +#define _function_private_ +#ifdef __cplusplus +extern "C" { +#endif +char * gamefunctions[] = + { + "Move_Forward", + "Move_Backward", + "Turn_Left", + "Turn_Right", + "Strafe", + "Fire", + "Open", + "Run", + "AutoRun", + "Jump", + "Crouch", + "Look_Up", + "Look_Down", + "Look_Left", + "Look_Right", + "Strafe_Left", + "Strafe_Right", + "Aim_Up", + "Aim_Down", + "Weapon_1", + "Weapon_2", + "Weapon_3", + "Weapon_4", + "Weapon_5", + "Weapon_6", + "Weapon_7", + "Weapon_8", + "Weapon_9", + "Weapon_10", + "Inventory", + "Inventory_Left", + "Inventory_Right", + "Holo_Duke", + "Jetpack", + "NightVision", + "MedKit", + "TurnAround", + "SendMessage", + "Map", + "Shrink_Screen", + "Enlarge_Screen", + "Center_View", + "Holster_Weapon", + "Show_Opponents_Weapon", + "Map_Follow_Mode", + "See_Coop_View", + "Mouse_Aiming", + "Toggle_Crosshair", + "Steroids", + "Quick_Kick", + "Next_Weapon", + "Previous_Weapon", + }; +#ifdef __SETUP__ + +#define NUMKEYENTRIES 52 + +static char * keydefaults[] = + { + "Move_Forward", "Up", "Kpad8", + "Move_Backward", "Down", "Kpad2", + "Turn_Left", "Left", "Kpad4", + "Turn_Right", "Right", "KPad6", + "Strafe", "LAlt", "RAlt", + "Fire", "LCtrl", "RCtrl", + "Open", "Space", "", + "Run", "LShift", "RShift", + "AutoRun", "CapLck", "", + "Jump", "A", "/", + "Crouch", "Z", "", + "Look_Up", "PgUp", "Kpad9", + "Look_Down", "PgDn", "Kpad3", + "Look_Left", "Insert", "Kpad0", + "Look_Right", "Delete", "Kpad.", + "Strafe_Left", ",", "", + "Strafe_Right", ".", "", + "Aim_Up", "Home", "KPad7", + "Aim_Down", "End", "Kpad1", + "Weapon_1", "1", "", + "Weapon_2", "2", "", + "Weapon_3", "3", "", + "Weapon_4", "4", "", + "Weapon_5", "5", "", + "Weapon_6", "6", "", + "Weapon_7", "7", "", + "Weapon_8", "8", "", + "Weapon_9", "9", "", + "Weapon_10", "0", "", + "Inventory", "Enter", "KpdEnt", + "Inventory_Left", "[", "", + "Inventory_Right", "]", "", + "Holo_Duke", "H", "", + "Jetpack", "J", "", + "NightVision", "N", "", + "MedKit", "M", "", + "TurnAround", "BakSpc", "", + "SendMessage", "T", "", + "Map", "Tab", "", + "Shrink_Screen", "-", "Kpad-", + "Enlarge_Screen", "=", "Kpad+", + "Center_View", "KPad5", "", + "Holster_Weapon", "ScrLck", "", + "Show_Opponents_Weapon", "W", "", + "Map_Follow_Mode", "F", "", + "See_Coop_View", "K", "", + "Mouse_Aiming", "U", "", + "Toggle_Crosshair", "I", "", + "Steroids", "R", "", + "Quick_Kick", "`", "", + "Next_Weapon", "'", "", + "Previous_Weapon", ";", "", + }; + + +static char * mousedefaults[] = + { + "Fire", + "Strafe", + "Move_Forward", + }; + + +static char * mouseclickeddefaults[] = + { + "", + "Open", + "", + }; + + +static char * joystickdefaults[] = + { + "Fire", + "Strafe", + "Run", + "Open", + "Aim_Down", + "Look_Right", + "Aim_Up", + "Look_Left", + }; + + +static char * joystickclickeddefaults[] = + { + "", + "Inventory", + "Jump", + "Crouch", + "", + "", + "", + "", + }; + + +static char * mouseanalogdefaults[] = + { + "analog_turning", + "analog_moving", + }; + + +static char * mousedigitaldefaults[] = + { + "", + "", + "", + "", + }; + + +static char * gamepaddigitaldefaults[] = + { + "Turn_Left", + "Turn_Right", + "Move_Forward", + "Move_Backward", + }; + + +static char * joystickanalogdefaults[] = + { + "analog_turning", + "analog_moving", + "analog_strafing", + "", + }; + + +static char * joystickdigitaldefaults[] = + { + "", + "", + "", + "", + "", + "", + "Run", + "", + }; +#endif +#ifdef __cplusplus +}; +#endif +#endif diff --git a/_rts.h b/_rts.h new file mode 100755 index 0000000..98272a9 --- /dev/null +++ b/_rts.h @@ -0,0 +1,54 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment + +This file is part of Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Original Source: 1996 - Todd Replogle +Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms +*/ +//------------------------------------------------------------------------- + +#ifndef __rts_private__ +#define __rts_private__ + +//=============== +// TYPES +//=============== + +typedef struct + { + char name[8]; + int32 handle,position,size; + } lumpinfo_t; + +typedef struct + { + char identification[4]; // should be IWAD + int32 numlumps; + int32 infotableofs; + } wadinfo_t; + +typedef struct + { + int32 filepos; + int32 size; + char name[8]; + } filelump_t; + +#endif diff --git a/actors.c b/actors.c new file mode 100755 index 0000000..26c7c4e --- /dev/null +++ b/actors.c @@ -0,0 +1,7138 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment + +This file is part of Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Original Source: 1996 - Todd Replogle +Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms +*/ +//------------------------------------------------------------------------- + +#include "duke3d.h" + +extern char numenvsnds,actor_tog; + +// this should be a proper prototype included from a header file + +void updateinterpolations() //Stick at beginning of domovethings +{ + long i; + + for(i=numinterpolations-1;i>=0;i--) oldipos[i] = *curipos[i]; +} + + +void setinterpolation(long *posptr) +{ + long i; + + if (numinterpolations >= MAXINTERPOLATIONS) return; + for(i=numinterpolations-1;i>=0;i--) + if (curipos[i] == posptr) return; + curipos[numinterpolations] = posptr; + oldipos[numinterpolations] = *posptr; + numinterpolations++; +} + +void stopinterpolation(long *posptr) +{ + long i; + + for(i=numinterpolations-1;i>=startofdynamicinterpolations;i--) + if (curipos[i] == posptr) + { + numinterpolations--; + oldipos[i] = oldipos[numinterpolations]; + bakipos[i] = bakipos[numinterpolations]; + curipos[i] = curipos[numinterpolations]; + } +} + +void dointerpolations(long smoothratio) //Stick at beginning of drawscreen +{ + long i, j, odelta, ndelta; + + ndelta = 0; j = 0; + for(i=numinterpolations-1;i>=0;i--) + { + bakipos[i] = *curipos[i]; + odelta = ndelta; ndelta = (*curipos[i])-oldipos[i]; + if (odelta != ndelta) j = mulscale16(ndelta,smoothratio); + *curipos[i] = oldipos[i]+j; + } +} + +void restoreinterpolations() //Stick at end of drawscreen +{ + long i; + + for(i=numinterpolations-1;i>=0;i--) *curipos[i] = bakipos[i]; +} + +long ceilingspace(short sectnum) +{ + if( (sector[sectnum].ceilingstat&1) && sector[sectnum].ceilingpal == 0 ) + { + switch(sector[sectnum].ceilingpicnum) + { + case MOONSKY1: + case BIGORBIT1: + return 1; + } + } + return 0; +} + +long floorspace(short sectnum) +{ + if( (sector[sectnum].floorstat&1) && sector[sectnum].ceilingpal == 0 ) + { + switch(sector[sectnum].floorpicnum) + { + case MOONSKY1: + case BIGORBIT1: + return 1; + } + } + return 0; +} + +void addammo( short weapon,struct player_struct *p,short amount) +{ + p->ammo_amount[weapon] += amount; + + if( p->ammo_amount[weapon] > max_ammo_amount[weapon] ) + p->ammo_amount[weapon] = max_ammo_amount[weapon]; +} + +void addweapon( struct player_struct *p,short weapon) +{ + if ( p->gotweapon[weapon] == 0 ) + { + p->gotweapon[weapon] = 1; + if(weapon == SHRINKER_WEAPON) + p->gotweapon[GROW_WEAPON] = 1; + } + + p->random_club_frame = 0; + + if(p->holster_weapon == 0) + { + p->weapon_pos = -1; + p->last_weapon = p->curr_weapon; + } + else + { + p->weapon_pos = 10; + p->holster_weapon = 0; + p->last_weapon = -1; + } + + p->kickback_pic = 0; + p->curr_weapon = weapon; + + switch(weapon) + { + case KNEE_WEAPON: + case TRIPBOMB_WEAPON: + case HANDREMOTE_WEAPON: + case HANDBOMB_WEAPON: break; + case SHOTGUN_WEAPON: spritesound(SHOTGUN_COCK,p->i);break; + case PISTOL_WEAPON: spritesound(INSERT_CLIP,p->i);break; + default: spritesound(SELECT_WEAPON,p->i);break; + } +} + +void checkavailinven( struct player_struct *p ) +{ + + if(p->firstaid_amount > 0) + p->inven_icon = 1; + else if(p->steroids_amount > 0) + p->inven_icon = 2; + else if(p->holoduke_amount > 0) + p->inven_icon = 3; + else if(p->jetpack_amount > 0) + p->inven_icon = 4; + else if(p->heat_amount > 0) + p->inven_icon = 5; + else if(p->scuba_amount > 0) + p->inven_icon = 6; + else if(p->boot_amount > 0) + p->inven_icon = 7; + else p->inven_icon = 0; +} + +void checkavailweapon( struct player_struct *p ) +{ + short i,snum; + int32 weap; + + if(p->wantweaponfire >= 0) + { + weap = p->wantweaponfire; + p->wantweaponfire = -1; + + if(weap == p->curr_weapon) return; + else if( p->gotweapon[weap] && p->ammo_amount[weap] > 0 ) + { + addweapon(p,weap); + return; + } + } + + weap = p->curr_weapon; + if( p->gotweapon[weap] && p->ammo_amount[weap] > 0 ) + return; + + snum = sprite[p->i].yvel; + + for(i=0;i<10;i++) + { + weap = ud.wchoice[snum][i]; +#ifdef VOLUMEONE + if(weap > 6) continue; +#endif + + if(weap == 0) weap = 9; + else weap--; + + if( weap == 0 || ( p->gotweapon[weap] && p->ammo_amount[weap] > 0 ) ) + break; + } + + if(i == 10) weap = 0; + + // Found the weapon + + p->last_weapon = p->curr_weapon; + p->random_club_frame = 0; + p->curr_weapon = weap; + p->kickback_pic = 0; + if(p->holster_weapon == 1) + { + p->holster_weapon = 0; + p->weapon_pos = 10; + } + else p->weapon_pos = -1; +} + + /* +void checkavailweapon( struct player_struct *p ) +{ + short i,okay,check_shoot,check_bombs; + + if(p->ammo_amount[p->curr_weapon] > 0) return; + okay = check_shoot = check_bombs = 0; + + switch(p->curr_weapon) + { + case PISTOL_WEAPON: + case CHAINGUN_WEAPON: + case SHOTGUN_WEAPON: +#ifndef VOLUMEONE + case FREEZE_WEAPON: + case DEVISTATOR_WEAPON: + case SHRINKER_WEAPON: + case GROW_WEAPON: +#endif + case RPG_WEAPON: + case KNEE_WEAPON: + check_shoot = 1; + break; + case HANDBOMB_WEAPON: + case HANDREMOTE_WEAPON: +#ifndef VOLUMEONE + case TRIPBOMB_WEAPON: +#endif + check_bombs = 1; + break; + } + + CHECK_SHOOT: + if(check_shoot) + { + for(i = p->curr_weapon+1; i < MAX_WEAPONS;i++) + switch(i) + { + case PISTOL_WEAPON: + case CHAINGUN_WEAPON: + case SHOTGUN_WEAPON: +#ifndef VOLUMEONE + case FREEZE_WEAPON: + case SHRINKER_WEAPON: + case GROW_WEAPON: + case DEVISTATOR_WEAPON: +#endif + if ( p->gotweapon[i] && p->ammo_amount[i] > 0 ) + { + okay = i; + goto OKAY_HERE; + } + break; + } + + for(i = p->curr_weapon-1; i > 0;i--) + switch(i) + { + case PISTOL_WEAPON: + case CHAINGUN_WEAPON: + case SHOTGUN_WEAPON: +#ifndef VOLUMEONE + case FREEZE_WEAPON: + case DEVISTATOR_WEAPON: + case SHRINKER_WEAPON: + case GROW_WEAPON: +#endif + if ( p->gotweapon[i] && p->ammo_amount[i] > 0 ) + { + okay = i; + goto OKAY_HERE; + } + break; + } + + if( p->gotweapon[RPG_WEAPON] && p->ammo_amount[RPG_WEAPON] > 0 ) + { + okay = RPG_WEAPON; + goto OKAY_HERE; + } + + if(check_bombs == 0) + check_bombs = 1; + else + { + addweapon(p,KNEE_WEAPON); + return; + } + } + + if(check_bombs) + { + for(i = p->curr_weapon-1; i > 0;i--) + switch(i) + { + case HANDBOMB_WEAPON: +#ifndef VOLUMEONE + case TRIPBOMB_WEAPON: +#endif + if ( p->gotweapon[i] && p->ammo_amount[i] > 0 ) + { + okay = i; + goto OKAY_HERE; + } + break; + } + + for(i = p->curr_weapon+1; i < MAX_WEAPONS;i++) + switch(i) + { + case HANDBOMB_WEAPON: +#ifdef VOLUMEONE + case TRIPBOMB_WEAPON: +#endif + if ( p->gotweapon[i] && p->ammo_amount[i] > 0 ) + { + okay = i; + goto OKAY_HERE; + } + break; + } + + if(check_shoot == 0) + { + check_shoot = 1; + goto CHECK_SHOOT; + } + else + { + addweapon(p,KNEE_WEAPON); + return; + } + } + + OKAY_HERE: + + if(okay) + { + p->last_weapon = p->curr_weapon; + p->random_club_frame = 0; + p->curr_weapon = okay; + p->kickback_pic = 0; + if(p->holster_weapon == 1) + { + p->holster_weapon = 0; + p->weapon_pos = 10; + } + else p->weapon_pos = -1; + return; + } +} + */ + +long ifsquished(short i, short p) +{ + sectortype *sc; + char squishme; + long floorceildist; + + if(PN == APLAYER && ud.clipping) + return 0; + + sc = §or[SECT]; + floorceildist = sc->floorz - sc->ceilingz; + + if(sc->lotag != 23) + { + if(sprite[i].pal == 1) + squishme = floorceildist < (32<<8) && (sc->lotag&32768) == 0; + else + squishme = floorceildist < (12<<8); // && (sc->lotag&32768) == 0; + } + else squishme = 0; + + if( squishme ) + { + FTA(10,&ps[p]); + + if(badguy(&sprite[i])) sprite[i].xvel = 0; + + if(sprite[i].pal == 1) + { + hittype[i].picnum = SHOTSPARK1; + hittype[i].extra = 1; + return 0; + } + + return 1; + } + return 0; +} + +void hitradius( short i, long r, long hp1, long hp2, long hp3, long hp4 ) +{ + spritetype *s,*sj; + walltype *wal; + long d, q, x1, y1; + long sectcnt, sectend, dasect, startwall, endwall, nextsect; + short j,k,p,x,nextj,sect; + char statlist[] = {0,1,6,10,12,2,5}; + short *tempshort = (short *)tempbuf; + + s = &sprite[i]; + + if(s->picnum == RPG && s->xrepeat < 11) goto SKIPWALLCHECK; + + if(s->picnum != SHRINKSPARK) + { + tempshort[0] = s->sectnum; + dasect = s->sectnum; + sectcnt = 0; sectend = 1; + + do + { + dasect = tempshort[sectcnt++]; + if(((sector[dasect].ceilingz-s->z)>>8) < r) + { + d = klabs(wall[sector[dasect].wallptr].x-s->x)+klabs(wall[sector[dasect].wallptr].y-s->y); + if(d < r) + checkhitceiling(dasect); + else + { + d = klabs(wall[wall[wall[sector[dasect].wallptr].point2].point2].x-s->x)+klabs(wall[wall[wall[sector[dasect].wallptr].point2].point2].y-s->y); + if(d < r) + checkhitceiling(dasect); + } + } + + startwall = sector[dasect].wallptr; + endwall = startwall+sector[dasect].wallnum; + for(x=startwall,wal=&wall[startwall];xx-s->x)+klabs(wal->y-s->y) ) < r) + { + nextsect = wal->nextsector; + if (nextsect >= 0) + { + for(dasect=sectend-1;dasect>=0;dasect--) + if (tempshort[dasect] == nextsect) break; + if (dasect < 0) tempshort[sectend++] = nextsect; + } + x1 = (((wal->x+wall[wal->point2].x)>>1)+s->x)>>1; + y1 = (((wal->y+wall[wal->point2].y)>>1)+s->y)>>1; + updatesector(x1,y1,§); + if( sect >= 0 && cansee(x1,y1,s->z,sect,s->x,s->y,s->z,s->sectnum ) ) + checkhitwall(i,x,wal->x,wal->y,s->z,s->picnum); + } + } + while (sectcnt < sectend); + } + + SKIPWALLCHECK: + + q = -(16<<8)+(TRAND&((32<<8)-1)); + + for(x = 0;x<7;x++) + { + j = headspritestat[(int)statlist[x]]; + while(j >= 0) + { + nextj = nextspritestat[j]; + sj = &sprite[j]; + + if( x == 0 || x >= 5 || AFLAMABLE(sj->picnum) ) + { + if( s->picnum != SHRINKSPARK || (sj->cstat&257) ) + if( dist( s, sj ) < r ) + { + if( badguy(sj) && !cansee( sj->x, sj->y,sj->z+q, sj->sectnum, s->x, s->y, s->z+q, s->sectnum) ) + goto BOLT; + checkhitsprite( j, i ); + } + } + else if( sj->extra >= 0 && sj != s && ( sj->picnum == TRIPBOMB || badguy(sj) || sj->picnum == QUEBALL || sj->picnum == STRIPEBALL || (sj->cstat&257) || sj->picnum == DUKELYINGDEAD ) ) + { + if( s->picnum == SHRINKSPARK && sj->picnum != SHARK && ( j == s->owner || sj->xrepeat < 24 ) ) + { + j = nextj; + continue; + } + if( s->picnum == MORTER && j == s->owner) + { + j = nextj; + continue; + } + + if(sj->picnum == APLAYER) sj->z -= PHEIGHT; + d = dist( s, sj ); + if(sj->picnum == APLAYER) sj->z += PHEIGHT; + + if ( d < r && cansee( sj->x, sj->y, sj->z-(8<<8), sj->sectnum, s->x, s->y, s->z-(12<<8), s->sectnum) ) + { + hittype[j].ang = getangle(sj->x-s->x,sj->y-s->y); + + if ( s->picnum == RPG && sj->extra > 0) + hittype[j].picnum = RPG; + else + { + if( s->picnum == SHRINKSPARK ) + hittype[j].picnum = SHRINKSPARK; + else hittype[j].picnum = RADIUSEXPLOSION; + } + + if(s->picnum != SHRINKSPARK) + { + if ( d < r/3 ) + { + if(hp4 == hp3) hp4++; + hittype[j].extra = hp3 + (TRAND%(hp4-hp3)); + } + else if ( d < 2*r/3 ) + { + if(hp3 == hp2) hp3++; + hittype[j].extra = hp2 + (TRAND%(hp3-hp2)); + } + else if ( d < r ) + { + if(hp2 == hp1) hp2++; + hittype[j].extra = hp1 + (TRAND%(hp2-hp1)); + } + + if( sprite[j].picnum != TANK && sprite[j].picnum != ROTATEGUN && sprite[j].picnum != RECON && sprite[j].picnum != BOSS1 && sprite[j].picnum != BOSS2 && sprite[j].picnum != BOSS3 && sprite[j].picnum != BOSS4 ) + { + if(sj->xvel < 0) sj->xvel = 0; + sj->xvel += (s->extra<<2); + } + + if( sj->picnum == PODFEM1 || sj->picnum == FEM1 || + sj->picnum == FEM2 || sj->picnum == FEM3 || + sj->picnum == FEM4 || sj->picnum == FEM5 || + sj->picnum == FEM6 || sj->picnum == FEM7 || + sj->picnum == FEM8 || sj->picnum == FEM9 || + sj->picnum == FEM10 || sj->picnum == STATUE || + sj->picnum == STATUEFLASH || sj->picnum == SPACEMARINE || sj->picnum == QUEBALL || sj->picnum == STRIPEBALL) + checkhitsprite( j, i ); + } + else if(s->extra == 0) hittype[j].extra = 0; + + if ( sj->picnum != RADIUSEXPLOSION && + s->owner >= 0 && sprite[s->owner].statnum < MAXSTATUS ) + { + if(sj->picnum == APLAYER) + { + p = sj->yvel; + if(ps[p].newowner >= 0) + { + ps[p].newowner = -1; + ps[p].posx = ps[p].oposx; + ps[p].posy = ps[p].oposy; + ps[p].posz = ps[p].oposz; + ps[p].ang = ps[p].oang; + updatesector(ps[p].posx,ps[p].posy,&ps[p].cursectnum); + setpal(&ps[p]); + + k = headspritestat[1]; + while(k >= 0) + { + if(sprite[k].picnum==CAMERA1) + sprite[k].yvel = 0; + k = nextspritestat[k]; + } + } + } + hittype[j].owner = s->owner; + } + } + } + BOLT: + j = nextj; + } + } +} + + +short movesprite(short spritenum, long xchange, long ychange, long zchange, unsigned long cliptype) +{ + long daz,h, oldx, oldy; + short retval, dasectnum, a, cd; + char bg; + + bg = badguy(&sprite[spritenum]); + + if(sprite[spritenum].statnum == 5 || (bg && sprite[spritenum].xrepeat < 4 ) ) + { + sprite[spritenum].x += (xchange*TICSPERFRAME)>>2; + sprite[spritenum].y += (ychange*TICSPERFRAME)>>2; + sprite[spritenum].z += (zchange*TICSPERFRAME)>>2; + if(bg) + setsprite(spritenum,sprite[spritenum].x,sprite[spritenum].y,sprite[spritenum].z); + return 0; + } + + dasectnum = sprite[spritenum].sectnum; + + daz = sprite[spritenum].z; + h = ((tilesizy[sprite[spritenum].picnum]*sprite[spritenum].yrepeat)<<1); + daz -= h; + + if( bg ) + { + oldx = sprite[spritenum].x; + oldy = sprite[spritenum].y; + + if( sprite[spritenum].xrepeat > 60 ) + retval = clipmove(&sprite[spritenum].x,&sprite[spritenum].y,&daz,&dasectnum,((xchange*TICSPERFRAME)<<11),((ychange*TICSPERFRAME)<<11),1024L,(4<<8),(4<<8),cliptype); + else + { + if(sprite[spritenum].picnum == LIZMAN) + cd = 292L; + else if( (actortype[sprite[spritenum].picnum]&3) ) + cd = sprite[spritenum].clipdist<<2; + else + cd = 192L; + + retval = clipmove(&sprite[spritenum].x,&sprite[spritenum].y,&daz,&dasectnum,((xchange*TICSPERFRAME)<<11),((ychange*TICSPERFRAME)<<11),cd,(4<<8),(4<<8),cliptype); + } + + if( dasectnum < 0 || ( dasectnum >= 0 && + ( ( hittype[spritenum].actorstayput >= 0 && hittype[spritenum].actorstayput != dasectnum ) || + ( ( sprite[spritenum].picnum == BOSS2 ) && sprite[spritenum].pal == 0 && sector[dasectnum].lotag != 3 ) || + ( ( sprite[spritenum].picnum == BOSS1 || sprite[spritenum].picnum == BOSS2 ) && sector[dasectnum].lotag == 1 ) || + ( sector[dasectnum].lotag == 1 && ( sprite[spritenum].picnum == LIZMAN || ( sprite[spritenum].picnum == LIZTROOP && sprite[spritenum].zvel == 0 ) ) ) + ) ) + ) + { + sprite[spritenum].x = oldx; + sprite[spritenum].y = oldy; + if(sector[dasectnum].lotag == 1 && sprite[spritenum].picnum == LIZMAN) + sprite[spritenum].ang = (TRAND&2047); + else if( (hittype[spritenum].temp_data[0]&3) == 1 && sprite[spritenum].picnum != COMMANDER ) + sprite[spritenum].ang = (TRAND&2047); + setsprite(spritenum,oldx,oldy,sprite[spritenum].z); + if(dasectnum < 0) dasectnum = 0; + return (16384+dasectnum); + } + if( (retval&49152) >= 32768 && (hittype[spritenum].cgg==0) ) sprite[spritenum].ang += 768; + } + else + { + if(sprite[spritenum].statnum == 4) + retval = + clipmove(&sprite[spritenum].x,&sprite[spritenum].y,&daz,&dasectnum,((xchange*TICSPERFRAME)<<11),((ychange*TICSPERFRAME)<<11),8L,(4<<8),(4<<8),cliptype); + else + retval = + clipmove(&sprite[spritenum].x,&sprite[spritenum].y,&daz,&dasectnum,((xchange*TICSPERFRAME)<<11),((ychange*TICSPERFRAME)<<11),(long)(sprite[spritenum].clipdist<<2),(4<<8),(4<<8),cliptype); + } + + if( dasectnum >= 0) + if ( (dasectnum != sprite[spritenum].sectnum) ) + changespritesect(spritenum,dasectnum); + daz = sprite[spritenum].z + ((zchange*TICSPERFRAME)>>3); + if ((daz > hittype[spritenum].ceilingz) && (daz <= hittype[spritenum].floorz)) + sprite[spritenum].z = daz; + else + if (retval == 0) + return(16384+dasectnum); + + return(retval); +} + + +short ssp(short i,unsigned long cliptype) //The set sprite function +{ + spritetype *s; + long movetype; + + s = &sprite[i]; + + movetype = movesprite(i, + (s->xvel*(sintable[(s->ang+512)&2047]))>>14, + (s->xvel*(sintable[s->ang&2047]))>>14,s->zvel, + cliptype); + + return (movetype==0); +} + +void insertspriteq(short i) +{ + if(spriteqamount > 0) + { + if(spriteq[spriteqloc] >= 0) + sprite[spriteq[spriteqloc]].xrepeat = 0; + spriteq[spriteqloc] = i; + spriteqloc = (spriteqloc+1)%spriteqamount; + } + else sprite[i].xrepeat = sprite[i].yrepeat = 0; +} + +void lotsofmoney(spritetype *s, short n) +{ + short i ,j; + for(i=n;i>0;i--) + { + j = EGS(s->sectnum,s->x,s->y,s->z-(TRAND%(47<<8)),MONEY,-32,8,8,TRAND&2047,0,0,0,5); + sprite[j].cstat = TRAND&12; + } +} + +void lotsofmail(spritetype *s, short n) +{ + short i ,j; + for(i=n;i>0;i--) + { + j = EGS(s->sectnum,s->x,s->y,s->z-(TRAND%(47<<8)),MAIL,-32,8,8,TRAND&2047,0,0,0,5); + sprite[j].cstat = TRAND&12; + } +} + +void lotsofpaper(spritetype *s, short n) +{ + short i ,j; + for(i=n;i>0;i--) + { + j = EGS(s->sectnum,s->x,s->y,s->z-(TRAND%(47<<8)),PAPER,-32,8,8,TRAND&2047,0,0,0,5); + sprite[j].cstat = TRAND&12; + } +} + + + +void guts(spritetype *s,short gtype, short n, short p) +{ + long gutz,floorz; + short i,a,j; + char sx,sy; + signed char pal; + + if(badguy(s) && s->xrepeat < 16) + sx = sy = 8; + else sx = sy = 32; + + gutz = s->z-(8<<8); + floorz = getflorzofslope(s->sectnum,s->x,s->y); + + if( gutz > ( floorz-(8<<8) ) ) + gutz = floorz-(8<<8); + + if(s->picnum == COMMANDER) + gutz -= (24<<8); + + if( badguy(s) && s->pal == 6) + pal = 6; + else pal = 0; + + for(j=0;jsectnum,s->x+(TRAND&255)-128,s->y+(TRAND&255)-128,gutz-(TRAND&8191),gtype,-32,sx,sy,a,48+(TRAND&31),-512-(TRAND&2047),ps[p].i,5); + if(PN == JIBS2) + { + sprite[i].xrepeat >>= 2; + sprite[i].yrepeat >>= 2; + } + if(pal == 6) + sprite[i].pal = 6; + } +} + +void gutsdir(spritetype *s,short gtype, short n, short p) +{ + long gutz,floorz; + short i,a,j; + char sx,sy; + + if(badguy(s) && s->xrepeat < 16) + sx = sy = 8; + else sx = sy = 32; + + gutz = s->z-(8<<8); + floorz = getflorzofslope(s->sectnum,s->x,s->y); + + if( gutz > ( floorz-(8<<8) ) ) + gutz = floorz-(8<<8); + + if(s->picnum == COMMANDER) + gutz -= (24<<8); + + for(j=0;jsectnum,s->x,s->y,gutz,gtype,-32,sx,sy,a,256+(TRAND&127),-512-(TRAND&2047),ps[p].i,5); + } +} + +void setsectinterpolate(short i) +{ + long j, k, startwall,endwall; + + startwall = sector[SECT].wallptr; + endwall = startwall+sector[SECT].wallnum; + + for(j=startwall;j= 0) + { + setinterpolation(&wall[k].x); + setinterpolation(&wall[k].y); + k = wall[k].point2; + setinterpolation(&wall[k].x); + setinterpolation(&wall[k].y); + } + } +} + +void clearsectinterpolate(short i) +{ + short j,startwall,endwall; + + startwall = sector[SECT].wallptr; + endwall = startwall+sector[SECT].wallnum; + for(j=startwall;j= 0) + { + stopinterpolation(&wall[wall[j].nextwall].x); + stopinterpolation(&wall[wall[j].nextwall].y); + } + } +} + +void ms(short i) +{ + //T1,T2 and T3 are used for all the sector moving stuff!!! + + short startwall,endwall,x; + long tx,ty,j,k; + spritetype *s; + + s = &sprite[i]; + + s->x += (s->xvel*(sintable[(s->ang+512)&2047]))>>14; + s->y += (s->xvel*(sintable[s->ang&2047]))>>14; + + j = T2; + k = T3; + + startwall = sector[s->sectnum].wallptr; + endwall = startwall+sector[s->sectnum].wallnum; + for(x=startwall;xx+tx,s->y+ty); + + j++; + } +} + +void movefta(void) +{ + long x, px, py, sx, sy; + short i, j, p, psect, ssect, nexti; + spritetype *s; + + i = headspritestat[2]; + while(i >= 0) + { + nexti = nextspritestat[i]; + + s = &sprite[i]; + p = findplayer(s,&x); + + ssect = psect = s->sectnum; + + if(sprite[ps[p].i].extra > 0 ) + { + if( x < 30000 ) + { + hittype[i].timetosleep++; + if( hittype[i].timetosleep >= (x>>8) ) + { + if(badguy(s)) + { + px = ps[p].oposx+64-(TRAND&127); + py = ps[p].oposy+64-(TRAND&127); + updatesector(px,py,&psect); + if(psect == -1) + { + i = nexti; + continue; + } + sx = s->x+64-(TRAND&127); + sy = s->y+64-(TRAND&127); + updatesector(px,py,&ssect); + if(ssect == -1) + { + i = nexti; + continue; + } + j = cansee(sx,sy,s->z-(TRAND%(52<<8)),s->sectnum,px,py,ps[p].oposz-(TRAND%(32<<8)),ps[p].cursectnum); + } + else + j = cansee(s->x,s->y,s->z-((TRAND&31)<<8),s->sectnum,ps[p].oposx,ps[p].oposy,ps[p].oposz-((TRAND&31)<<8),ps[p].cursectnum); + + // j = 1; + + if(j) switch(s->picnum) + { + case RUBBERCAN: + case EXPLODINGBARREL: + case WOODENHORSE: + case HORSEONSIDE: + case CANWITHSOMETHING: + case CANWITHSOMETHING2: + case CANWITHSOMETHING3: + case CANWITHSOMETHING4: + case FIREBARREL: + case FIREVASE: + case NUKEBARREL: + case NUKEBARRELDENTED: + case NUKEBARRELLEAKED: + case TRIPBOMB: + if (sector[s->sectnum].ceilingstat&1) + s->shade = sector[s->sectnum].ceilingshade; + else s->shade = sector[s->sectnum].floorshade; + + hittype[i].timetosleep = 0; + changespritestat(i,6); + break; + default: + hittype[i].timetosleep = 0; + check_fta_sounds(i); + changespritestat(i,1); + break; + } + else hittype[i].timetosleep = 0; + } + } + if( badguy( s ) ) + { + if (sector[s->sectnum].ceilingstat&1) + s->shade = sector[s->sectnum].ceilingshade; + else s->shade = sector[s->sectnum].floorshade; + } + } + i = nexti; + } +} + +short ifhitsectors(short sectnum) +{ + short i; + + i = headspritestat[5]; + while(i >= 0) + { + if( PN == EXPLOSION2 && sectnum == SECT ) + return i; + i = nextspritestat[i]; + } + return -1; +} + +short ifhitbyweapon(short sn) +{ + short j, k, p; + spritetype *npc; + + if( hittype[sn].extra >= 0 ) + { + if(sprite[sn].extra >= 0 ) + { + npc = &sprite[sn]; + + if(npc->picnum == APLAYER) + { + if(ud.god && hittype[sn].picnum != SHRINKSPARK ) return -1; + + p = npc->yvel; + j = hittype[sn].owner; + + if( j >= 0 && + sprite[j].picnum == APLAYER && + ud.coop == 1 && + ud.ffire == 0 ) + return -1; + + npc->extra -= hittype[sn].extra; + + if(j >= 0) + { + if(npc->extra <= 0 && hittype[sn].picnum != FREEZEBLAST) + { + npc->extra = 0; + + ps[p].wackedbyactor = j; + + if( sprite[hittype[sn].owner].picnum == APLAYER && p != sprite[hittype[sn].owner].yvel ) + ps[p].frag_ps = sprite[j].yvel; + + hittype[sn].owner = ps[p].i; + } + } + + switch(hittype[sn].picnum) + { + case RADIUSEXPLOSION: + case RPG: + case HYDRENT: + case HEAVYHBOMB: + case SEENINE: + case OOZFILTER: + case EXPLODINGBARREL: + ps[p].posxv += + hittype[sn].extra*(sintable[(hittype[sn].ang+512)&2047])<<2; + ps[p].posyv += + hittype[sn].extra*(sintable[hittype[sn].ang&2047])<<2; + break; + default: + ps[p].posxv += + hittype[sn].extra*(sintable[(hittype[sn].ang+512)&2047])<<1; + ps[p].posyv += + hittype[sn].extra*(sintable[hittype[sn].ang&2047])<<1; + break; + } + } + else + { + if(hittype[sn].extra == 0 ) + if( hittype[sn].picnum == SHRINKSPARK && npc->xrepeat < 24 ) + return -1; + + npc->extra -= hittype[sn].extra; + if(npc->picnum != RECON && npc->owner >= 0 && sprite[npc->owner].statnum < MAXSTATUS ) + npc->owner = hittype[sn].owner; + } + + hittype[sn].extra = -1; + return hittype[sn].picnum; + } + } + + hittype[sn].extra = -1; + return -1; +} + +void movecyclers(void) +{ + short q, j, x, t, s, *c; + walltype *wal; + char cshade; + + for(q=numcyclers-1;q>=0;q--) + { + + c = &cyclers[q][0]; + s = c[0]; + + t = c[3]; + j = t+(sintable[c[1]&2047]>>10); + cshade = c[2]; + + if( j < cshade ) j = cshade; + else if( j > t ) j = t; + + c[1] += sector[s].extra; + if(c[5]) + { + wal = &wall[sector[s].wallptr]; + for(x = sector[s].wallnum;x>0;x--,wal++) + if( wal->hitag != 1 ) + { + wal->shade = j; + + if( (wal->cstat&2) && wal->nextwall >= 0) + wall[wal->nextwall].shade = j; + + } + sector[s].floorshade = sector[s].ceilingshade = j; + } + } +} + +void movedummyplayers(void) +{ + short i, p, nexti; + + i = headspritestat[13]; + while(i >= 0) + { + nexti = nextspritestat[i]; + + p = sprite[OW].yvel; + + if( ps[p].on_crane >= 0 || sector[ps[p].cursectnum].lotag != 1 || sprite[ps[p].i].extra <= 0 ) + { + ps[p].dummyplayersprite = -1; + KILLIT(i); + } + else + { + if(ps[p].on_ground && ps[p].on_warping_sector == 1 && sector[ps[p].cursectnum].lotag == 1 ) + { + CS = 257; + SZ = sector[SECT].ceilingz+(27<<8); + SA = ps[p].ang; + if(T1 == 8) + T1 = 0; + else T1++; + } + else + { + if(sector[SECT].lotag != 2) SZ = sector[SECT].floorz; + CS = (short) 32768; + } + } + + SX += (ps[p].posx-ps[p].oposx); + SY += (ps[p].posy-ps[p].oposy); + setsprite(i,SX,SY,SZ); + + BOLT: + + i = nexti; + } +} + + +short otherp; +void moveplayers(void) //Players +{ + short i , nexti; + long otherx; + spritetype *s; + struct player_struct *p; + + i = headspritestat[10]; + while(i >= 0) + { + nexti = nextspritestat[i]; + + s = &sprite[i]; + p = &ps[s->yvel]; + if(s->owner >= 0) + { + if(p->newowner >= 0 ) //Looking thru the camera + { + s->x = p->oposx; + s->y = p->oposy; + hittype[i].bposz = s->z = p->oposz+PHEIGHT; + s->ang = p->oang; + setsprite(i,s->x,s->y,s->z); + } + else + { + if(ud.multimode > 1) + otherp = findotherplayer(s->yvel,&otherx); + else + { + otherp = s->yvel; + otherx = 0; + } + + execute(i,s->yvel,otherx); + + if(ud.multimode > 1) + if( sprite[ps[otherp].i].extra > 0 ) + { + if( s->yrepeat > 32 && sprite[ps[otherp].i].yrepeat < 32) + { + if( otherx < 1400 && p->knee_incs == 0 ) + { + p->knee_incs = 1; + p->weapon_pos = -1; + p->actorsqu = ps[otherp].i; + } + } + } + if(ud.god) + { + s->extra = max_player_health; + s->cstat = 257; + p->jetpack_amount = 1599; + } + + + if( s->extra > 0 ) + { + hittype[i].owner = i; + + if(ud.god == 0) + if( ceilingspace(s->sectnum) || floorspace(s->sectnum) ) + quickkill(p); + } + else + { + + p->posx = s->x; + p->posy = s->y; + p->posz = s->z-(20<<8); + + p->newowner = -1; + + if( p->wackedbyactor >= 0 && sprite[p->wackedbyactor].statnum < MAXSTATUS ) + { + p->ang += getincangle(p->ang,getangle(sprite[p->wackedbyactor].x-p->posx,sprite[p->wackedbyactor].y-p->posy))>>1; + p->ang &= 2047; + } + + } + s->ang = p->ang; + } + } + else + { + if(p->holoduke_on == -1) + KILLIT(i); + + hittype[i].bposx = s->x; + hittype[i].bposy = s->y; + hittype[i].bposz = s->z; + + s->cstat = 0; + + if(s->xrepeat < 42) + { + s->xrepeat += 4; + s->cstat |= 2; + } + else s->xrepeat = 42; + if(s->yrepeat < 36) + s->yrepeat += 4; + else + { + s->yrepeat = 36; + if(sector[s->sectnum].lotag != 2) + makeitfall(i); + if(s->zvel == 0 && sector[s->sectnum].lotag == 1) + s->z += (32<<8); + } + + if(s->extra < 8) + { + s->xvel = 128; + s->ang = p->ang; + s->extra++; + ssp(i,CLIPMASK0); //IFMOVING; + } + else + { + s->ang = 2047-p->ang; + setsprite(i,s->x,s->y,s->z); + } + } + + if (sector[s->sectnum].ceilingstat&1) + s->shade += (sector[s->sectnum].ceilingshade-s->shade)>>1; + else + s->shade += (sector[s->sectnum].floorshade-s->shade)>>1; + + BOLT: + i = nexti; + } +} + + +void movefx(void) +{ + short i, j, nexti, p; + long x, ht; + spritetype *s; + + i = headspritestat[11]; + while(i >= 0) + { + s = &sprite[i]; + + nexti = nextspritestat[i]; + + switch(s->picnum) + { + case RESPAWN: + if(sprite[i].extra == 66) + { + j = spawn(i,SHT); +// sprite[j].pal = sprite[i].pal; + KILLIT(i); + } + else if(sprite[i].extra > (66-13)) + sprite[i].extra++; + break; + + case MUSICANDSFX: + + ht = s->hitag; + + if(T2 != SoundToggle) + { + T2 = SoundToggle; + T1 = 0; + } + + if(s->lotag >= 1000 && s->lotag < 2000) + { + x = ldist(&sprite[ps[screenpeek].i],s); + if( x < ht && T1 == 0 ) + { + FX_SetReverb( s->lotag - 1000 ); + T1 = 1; + } + if( x >= ht && T1 == 1 ) + { + FX_SetReverb(0); + FX_SetReverbDelay(0); + T1 = 0; + } + } + else if(s->lotag < 999 && (unsigned)sector[s->sectnum].lotag < 9 && AmbienceToggle && sector[SECT].floorz != sector[SECT].ceilingz) + { + if( (soundm[s->lotag]&2) ) + { + x = dist(&sprite[ps[screenpeek].i],s); + if( x < ht && T1 == 0 && FX_VoiceAvailable(soundpr[s->lotag]-1) ) + { + if(numenvsnds == NumVoices) + { + j = headspritestat[11]; + while(j >= 0) + { + if( PN == MUSICANDSFX && j != i && sprite[j].lotag < 999 && hittype[j].temp_data[0] == 1 && dist(&sprite[j],&sprite[ps[screenpeek].i]) > x ) + { + stopenvsound(sprite[j].lotag,j); + break; + } + j = nextspritestat[j]; + } + if(j == -1) goto BOLT; + } + spritesound(s->lotag,i); + T1 = 1; + } + if( x >= ht && T1 == 1 ) + { + T1 = 0; + stopenvsound(s->lotag,i); + } + } + if( (soundm[s->lotag]&16) ) + { + if(T5 > 0) T5--; + else for(p=connecthead;p>=0;p=connectpoint2[p]) + if( p == myconnectindex && ps[p].cursectnum == s->sectnum ) + { + j = s->lotag+((unsigned)global_random%(s->hitag+1)); + sound(j); + T5 = 26*40 + (global_random%(26*40)); + } + } + } + break; + } + BOLT: + i = nexti; + } +} + + + +void movefallers(void) +{ + short i, nexti, sect, j; + spritetype *s; + long x; + + i = headspritestat[12]; + while(i >= 0) + { + nexti = nextspritestat[i]; + s = &sprite[i]; + + sect = s->sectnum; + + if( T1 == 0 ) + { + s->z -= (16<<8); + T2 = s->ang; + x = s->extra; + IFHIT + { + if( j == FIREEXT || j == RPG || j == RADIUSEXPLOSION || j == SEENINE || j == OOZFILTER ) + { + if(s->extra <= 0) + { + T1 = 1; + j = headspritestat[12]; + while(j >= 0) + { + if(sprite[j].hitag == SHT) + { + hittype[j].temp_data[0] = 1; + sprite[j].cstat &= (65535-64); + if(sprite[j].picnum == CEILINGSTEAM || sprite[j].picnum == STEAM) + sprite[j].cstat |= 32768; + } + j = nextspritestat[j]; + } + } + } + else + { + hittype[i].extra = 0; + s->extra = x; + } + } + s->ang = T2; + s->z += (16<<8); + } + else if(T1 == 1) + { + if(s->lotag > 0) + { + s->lotag-=3; + if(s->lotag <= 0) + { + s->xvel = ((32+TRAND)&63); + s->zvel = -(1024+(TRAND&1023)); + } + } + else + { + if( s->xvel > 0) + { + s->xvel -= 8; + ssp(i,CLIPMASK0); + } + + if( floorspace(s->sectnum) ) x = 0; + else + { + if(ceilingspace(s->sectnum)) + x = gc/6; + else + x = gc; + } + + if( s->z < (sector[sect].floorz-FOURSLEIGHT) ) + { + s->zvel += x; + if(s->zvel > 6144) + s->zvel = 6144; + s->z += s->zvel; + } + if( (sector[sect].floorz-s->z) < (16<<8) ) + { + j = 1+(TRAND&7); + for(x=0;x= 0) + { + nexti = nextspritestat[i]; + + t = &hittype[i].temp_data[0]; + s = &sprite[i]; + sect = s->sectnum; + + if( sect < 0 ) KILLIT(i); + + hittype[i].bposx = s->x; + hittype[i].bposy = s->y; + hittype[i].bposz = s->z; + + IFWITHIN(CRANE,CRANE+3) + { + //t[0] = state + //t[1] = checking sector number + + if(s->xvel) getglobalz(i); + + if( t[0] == 0 ) //Waiting to check the sector + { + j = headspritesect[t[1]]; + while(j>=0) + { + nextj = nextspritesect[j]; + switch( sprite[j].statnum ) + { + case 1: + case 2: + case 6: + case 10: + s->ang = getangle(msx[t[4]+1]-s->x,msy[t[4]+1]-s->y); + setsprite(j,msx[t[4]+1],msy[t[4]+1],sprite[j].z); + t[0]++; + goto BOLT; + } + j = nextj; + } + } + + else if(t[0]==1) + { + if( s->xvel < 184 ) + { + s->picnum = CRANE+1; + s->xvel += 8; + } + ssp(i,CLIPMASK0); //IFMOVING; + if(sect == t[1]) + t[0]++; + } + else if(t[0]==2 || t[0]==7) + { + s->z += (1024+512); + + if(t[0]==2) + { + if( (sector[sect].floorz - s->z) < (64<<8) ) + if(s->picnum > CRANE) s->picnum--; + + if( (sector[sect].floorz - s->z) < (4096+1024)) + t[0]++; + } + if(t[0]==7) + { + if( (sector[sect].floorz - s->z) < (64<<8) ) + { + if(s->picnum > CRANE) s->picnum--; + else + { + if(s->owner==-2) + { + spritesound(DUKE_GRUNT,ps[p].i); + p = findplayer(s,&x); + if(ps[p].on_crane == i) + ps[p].on_crane = -1; + } + t[0]++; + s->owner = -1; + } + } + } + } + else if(t[0]==3) + { + s->picnum++; + if( s->picnum == (CRANE+2) ) + { + p = checkcursectnums(t[1]); + if(p >= 0 && ps[p].on_ground) + { + s->owner = -2; + ps[p].on_crane = i; + spritesound(DUKE_GRUNT,ps[p].i); + ps[p].ang = s->ang+1024; + } + else + { + j = headspritesect[t[1]]; + while(j>=0) + { + switch( sprite[j].statnum ) + { + case 1: + case 6: + s->owner = j; + break; + } + j = nextspritesect[j]; + } + } + + t[0]++;//Grabbed the sprite + t[2]=0; + goto BOLT; + } + } + else if(t[0]==4) //Delay before going up + { + t[2]++; + if(t[2] > 10) + t[0]++; + } + else if(t[0]==5 || t[0] == 8) + { + if(t[0]==8 && s->picnum < (CRANE+2)) + if( (sector[sect].floorz-s->z) > 8192) + s->picnum++; + + if(s->z < msx[t[4]+2]) + { + t[0]++; + s->xvel = 0; + } + else + s->z -= (1024+512); + } + else if(t[0]==6) + { + if( s->xvel < 192 ) + s->xvel += 8; + s->ang = getangle(msx[t[4]]-s->x,msy[t[4]]-s->y); + ssp(i,CLIPMASK0); //IFMOVING; + if( ((s->x-msx[t[4]])*(s->x-msx[t[4]])+(s->y-msy[t[4]])*(s->y-msy[t[4]]) ) < (128*128) ) + t[0]++; + } + + else if(t[0]==9) + t[0] = 0; + + setsprite(msy[t[4]+2],s->x,s->y,s->z-(34<<8)); + + if(s->owner != -1) + { + p = findplayer(s,&x); + + IFHIT + { + if(s->owner == -2) + if(ps[p].on_crane == i) + ps[p].on_crane = -1; + s->owner = -1; + s->picnum = CRANE; + goto BOLT; + } + + if(s->owner >= 0) + { + setsprite(s->owner,s->x,s->y,s->z); + + hittype[s->owner].bposx = s->x; + hittype[s->owner].bposy = s->y; + hittype[s->owner].bposz = s->z; + + s->zvel = 0; + } + else if(s->owner == -2) + { + ps[p].oposx = ps[p].posx = s->x-(sintable[(ps[p].ang+512)&2047]>>6); + ps[p].oposy = ps[p].posy = s->y-(sintable[ps[p].ang&2047]>>6); + ps[p].oposz = ps[p].posz = s->z+(2<<8); + setsprite(ps[p].i,ps[p].posx,ps[p].posy,ps[p].posz); + ps[p].cursectnum = sprite[ps[p].i].sectnum; + } + } + + goto BOLT; + } + + IFWITHIN(WATERFOUNTAIN,WATERFOUNTAIN+3) + { + if(t[0] > 0) + { + if( t[0] < 20 ) + { + t[0]++; + + s->picnum++; + + if( s->picnum == ( WATERFOUNTAIN+3 ) ) + s->picnum = WATERFOUNTAIN+1; + } + else + { + p = findplayer(s,&x); + + if(x > 512) + { + t[0] = 0; + s->picnum = WATERFOUNTAIN; + } + else t[0] = 1; + } + } + goto BOLT; + } + + if( AFLAMABLE(s->picnum) ) + { + if(T1 == 1) + { + T2++; + if( (T2&3) > 0) goto BOLT; + + if( s->picnum == TIRE && T2 == 32 ) + { + s->cstat = 0; + j = spawn(i,BLOODPOOL); + sprite[j].shade = 127; + } + else + { + if(s->shade < 64) s->shade++; + else KILLIT(i); + } + + j = s->xrepeat-(TRAND&7); + if(j < 10) + { + KILLIT(i); + } + + s->xrepeat = j; + + j = s->yrepeat-(TRAND&7); + if(j < 4) { KILLIT(i); } + s->yrepeat = j; + } + if(s->picnum == BOX) + { + makeitfall(i); + hittype[i].ceilingz = sector[s->sectnum].ceilingz; + } + goto BOLT; + } + + if(s->picnum == TRIPBOMB) + { + if(T3 > 0) + { + T3--; + if(T3 == 8) + { + spritesound(LASERTRIP_EXPLODE,i); + for(j=0;j<5;j++) RANDOMSCRAP; + x = s->extra; + hitradius( i, tripbombblastradius, x>>2,x>>1,x-(x>>2),x); + + j = spawn(i,EXPLOSION2); + sprite[j].ang = s->ang; + sprite[j].xvel = 348; + ssp(j,CLIPMASK0); + + j = headspritestat[5]; + while(j >= 0) + { + if(sprite[j].picnum == LASERLINE && s->hitag == sprite[j].hitag) + sprite[j].xrepeat = sprite[j].yrepeat = 0; + j = nextspritestat[j]; + } + KILLIT(i); + } + goto BOLT; + } + else + { + x = s->extra; + s->extra = 1; + l = s->ang; + IFHIT { T3 = 16; } + s->extra = x; + s->ang = l; + } + + if( T1 < 32 ) + { + p = findplayer(s,&x); + if( x > 768 ) T1++; + else if(T1 > 16) T1++; + } + if( T1 == 32 ) + { + l = s->ang; + s->ang = T6; + + T4 = s->x;T5 = s->y; + s->x += sintable[(T6+512)&2047]>>9; + s->y += sintable[(T6)&2047]>>9; + s->z -= (3<<8); + setsprite(i,s->x,s->y,s->z); + + x = hitasprite(i,&m); + + hittype[i].lastvx = x; + + s->ang = l; + + k = 0; + + while(x > 0) + { + j = spawn(i,LASERLINE); + setsprite(j,sprite[j].x,sprite[j].y,sprite[j].z); + sprite[j].hitag = s->hitag; + hittype[j].temp_data[1] = sprite[j].z; + + s->x += sintable[(T6+512)&2047]>>4; + s->y += sintable[(T6)&2047]>>4; + + if( x < 1024 ) + { + sprite[j].xrepeat = x>>5; + break; + } + x -= 1024; + } + + T1++; + s->x = T4;s->y = T5; + s->z += (3<<8); + setsprite(i,s->x,s->y,s->z); + T4 = 0; + if( m >= 0 ) + { + T3 = 13; + spritesound(LASERTRIP_ARMING,i); + } + else T3 = 0; + } + if(T1 == 33) + { + T2++; + + + T4 = s->x;T5 = s->y; + s->x += sintable[(T6+512)&2047]>>9; + s->y += sintable[(T6)&2047]>>9; + s->z -= (3<<8); + setsprite(i,s->x,s->y,s->z); + + x = hitasprite(i,&m); + + s->x = T4;s->y = T5; + s->z += (3<<8); + setsprite(i,s->x,s->y,s->z); + + if( hittype[i].lastvx != x ) + { + T3 = 13; + spritesound(LASERTRIP_ARMING,i); + } + } + goto BOLT; + } + + + if( s->picnum >= CRACK1 && s->picnum <= CRACK4 ) + { + if(s->hitag > 0) + { + t[0] = s->cstat; + t[1] = s->ang; + j = ifhitbyweapon(i); + if(j == FIREEXT || j == RPG || j == RADIUSEXPLOSION || j == SEENINE || j == OOZFILTER ) + { + j = headspritestat[6]; + while(j >= 0) + { + if(s->hitag == sprite[j].hitag && ( sprite[j].picnum == OOZFILTER || sprite[j].picnum == SEENINE ) ) + if(sprite[j].shade != -32) + sprite[j].shade = -32; + j = nextspritestat[j]; + } + + goto DETONATE; + } + else + { + s->cstat = t[0]; + s->ang = t[1]; + s->extra = 0; + } + } + goto BOLT; + } + + if( s->picnum == FIREEXT ) + { + j = ifhitbyweapon(i); + if( j == -1 ) goto BOLT; + + for(k=0;k<16;k++) + { + j = EGS(SECT,SX,SY,SZ-(TRAND%(48<<8)),SCRAP3+(TRAND&3),-8,48,48,TRAND&2047,(TRAND&63)+64,-(TRAND&4095)-(sprite[i].zvel>>2),i,5); + sprite[j].pal = 2; + } + + spawn(i,EXPLOSION2); + spritesound(PIPEBOMB_EXPLODE,i); + spritesound(GLASS_HEAVYBREAK,i); + + if(s->hitag > 0) + { + j = headspritestat[6]; + while(j >= 0) + { + if(s->hitag == sprite[j].hitag && ( sprite[j].picnum == OOZFILTER || sprite[j].picnum == SEENINE ) ) + if(sprite[j].shade != -32) + sprite[j].shade = -32; + j = nextspritestat[j]; + } + + x = s->extra; + spawn(i,EXPLOSION2); + hitradius( i, pipebombblastradius,x>>2, x-(x>>1),x-(x>>2), x); + spritesound(PIPEBOMB_EXPLODE,i); + + goto DETONATE; + } + else + { + hitradius(i,seenineblastradius,10,15,20,25); + KILLIT(i); + } + goto BOLT; + } + + if(s->picnum == OOZFILTER || s->picnum == SEENINE || s->picnum == SEENINEDEAD || s->picnum == (SEENINEDEAD+1) ) + { + if(s->shade != -32 && s->shade != -33) + { + if(s->xrepeat) + j = (ifhitbyweapon(i) >= 0); + else + j = 0; + + if( j || s->shade == -31 ) + { + if(j) s->lotag = 0; + + t[3] = 1; + + j = headspritestat[6]; + while(j >= 0) + { + if(s->hitag == sprite[j].hitag && ( sprite[j].picnum == SEENINE || sprite[j].picnum == OOZFILTER ) ) + sprite[j].shade = -32; + j = nextspritestat[j]; + } + } + } + else + { + if(s->shade == -32) + { + if(s->lotag > 0) + { + s->lotag-=3; + if(s->lotag <= 0) s->lotag = -99; + } + else + s->shade = -33; + } + else + { + if( s->xrepeat > 0 ) + { + T3++; + if(T3 == 3) + { + if( s->picnum == OOZFILTER ) + { + T3 = 0; + goto DETONATE; + } + if( s->picnum != (SEENINEDEAD+1) ) + { + T3 = 0; + + if(s->picnum == SEENINEDEAD) s->picnum++; + else if(s->picnum == SEENINE) + s->picnum = SEENINEDEAD; + } + else goto DETONATE; + } + goto BOLT; + } + + DETONATE: + + earthquaketime = 16; + + j = headspritestat[3]; + while(j >= 0) + { + if( s->hitag == sprite[j].hitag ) + { + if(sprite[j].lotag == 13) + { + if( hittype[j].temp_data[2] == 0 ) + hittype[j].temp_data[2] = 1; + } + else if(sprite[j].lotag == 8) + hittype[j].temp_data[4] = 1; + else if(sprite[j].lotag == 18) + { + if(hittype[j].temp_data[0] == 0) + hittype[j].temp_data[0] = 1; + } + else if(sprite[j].lotag == 21) + hittype[j].temp_data[0] = 1; + } + j = nextspritestat[j]; + } + + s->z -= (32<<8); + + if( ( t[3] == 1 && s->xrepeat ) || s->lotag == -99 ) + { + x = s->extra; + spawn(i,EXPLOSION2); + hitradius( i,seenineblastradius,x>>2, x-(x>>1),x-(x>>2), x); + spritesound(PIPEBOMB_EXPLODE,i); + } + + if(s->xrepeat) + for(x=0;x<8;x++) RANDOMSCRAP; + + KILLIT(i); + } + } + goto BOLT; + } + + if(s->picnum == MASTERSWITCH) + { + if(s->yvel == 1) + { + s->hitag--; + if(s->hitag <= 0) + { + operatesectors(sect,i); + + j = headspritesect[sect]; + while(j >= 0) + { + if(sprite[j].statnum == 3) + { + switch(sprite[j].lotag) + { + case 2: + case 21: + case 31: + case 32: + case 36: + hittype[j].temp_data[0] = 1; + break; + case 3: + hittype[j].temp_data[4] = 1; + break; + } + } + else if(sprite[j].statnum == 6) + { + switch(sprite[j].picnum) + { + case SEENINE: + case OOZFILTER: + sprite[j].shade = -31; + break; + } + } + j = nextspritesect[j]; + } + KILLIT(i); + } + } + goto BOLT; + } + + switch(s->picnum) + { + case VIEWSCREEN: + case VIEWSCREEN2: + + if(s->xrepeat == 0) KILLIT(i); + + p = findplayer(s, &x); + + if( x < 2048 ) + { + if( SP == 1 ) + camsprite = i; + } + else if( camsprite != -1 && T1 == 1) + { + camsprite = -1; + T1 = 0; + loadtile(s->picnum); + } + + goto BOLT; + + case TRASH: + + if(s->xvel == 0) s->xvel = 1; + IFMOVING + { + makeitfall(i); + if(TRAND&1) s->zvel -= 256; + if( klabs(s->xvel) < 48 ) + s->xvel += (TRAND&3); + } + else KILLIT(i); + break; + + case SIDEBOLT1: + case SIDEBOLT1+1: + case SIDEBOLT1+2: + case SIDEBOLT1+3: + p = findplayer(s, &x); + if( x > 20480 ) goto BOLT; + + CLEAR_THE_BOLT2: + if(t[2]) + { + t[2]--; + goto BOLT; + } + if( (s->xrepeat|s->yrepeat) == 0 ) + { + s->xrepeat=t[0]; + s->yrepeat=t[1]; + } + if( (TRAND&8) == 0 ) + { + t[0]=s->xrepeat; + t[1]=s->yrepeat; + t[2] = global_random&4; + s->xrepeat=s->yrepeat=0; + goto CLEAR_THE_BOLT2; + } + s->picnum++; + + if(l&1) s->cstat ^= 2; + + if( (TRAND&1) && sector[sect].floorpicnum == HURTRAIL ) + spritesound(SHORT_CIRCUIT,i); + + if(s->picnum == SIDEBOLT1+4) s->picnum = SIDEBOLT1; + + goto BOLT; + + case BOLT1: + case BOLT1+1: + case BOLT1+2: + case BOLT1+3: + p = findplayer(s, &x); + if( x > 20480 ) goto BOLT; + + if( t[3] == 0 ) + t[3]=sector[sect].floorshade; + + CLEAR_THE_BOLT: + if(t[2]) + { + t[2]--; + sector[sect].floorshade = 20; + sector[sect].ceilingshade = 20; + goto BOLT; + } + if( (s->xrepeat|s->yrepeat) == 0 ) + { + s->xrepeat=t[0]; + s->yrepeat=t[1]; + } + else if( (TRAND&8) == 0 ) + { + t[0]=s->xrepeat; + t[1]=s->yrepeat; + t[2] = global_random&4; + s->xrepeat=s->yrepeat=0; + goto CLEAR_THE_BOLT; + } + s->picnum++; + + l = global_random&7; + s->xrepeat=l+8; + + if(l&1) s->cstat ^= 2; + + if( s->picnum == (BOLT1+1) && (TRAND&7) == 0 && sector[sect].floorpicnum == HURTRAIL ) + spritesound(SHORT_CIRCUIT,i); + + if(s->picnum==BOLT1+4) s->picnum=BOLT1; + + if(s->picnum&1) + { + sector[sect].floorshade = 0; + sector[sect].ceilingshade = 0; + } + else + { + sector[sect].floorshade = 20; + sector[sect].ceilingshade = 20; + } + goto BOLT; + + case WATERDRIP: + + if( t[1] ) + { + t[1]--; + if(t[1] == 0) + s->cstat &= 32767; + } + else + { + makeitfall(i); + ssp(i,CLIPMASK0); + if(s->xvel > 0) s->xvel -= 2; + + if(s->zvel == 0) + { + s->cstat |= 32768; + + if(s->pal != 2 && s->hitag == 0) + spritesound(SOMETHING_DRIPPING,i); + + if(sprite[s->owner].picnum != WATERDRIP) + { + KILLIT(i); + } + else + { + hittype[i].bposz = s->z = t[0]; + t[1] = 48+(TRAND&31); + } + } + } + + + goto BOLT; + + case DOORSHOCK: + j = klabs(sector[sect].ceilingz-sector[sect].floorz)>>9; + s->yrepeat = j+4; + s->xrepeat = 16; + s->z = sector[sect].floorz; + goto BOLT; + + case TOUCHPLATE: + if( t[1] == 1 && s->hitag >= 0) //Move the sector floor + { + x = sector[sect].floorz; + + if(t[3] == 1) + { + if(x >= t[2]) + { + sector[sect].floorz = x; + t[1] = 0; + } + else + { + sector[sect].floorz += sector[sect].extra; + p = checkcursectnums(sect); + if(p >= 0) ps[p].posz += sector[sect].extra; + } + } + else + { + if(x <= s->z) + { + sector[sect].floorz = s->z; + t[1] = 0; + } + else + { + sector[sect].floorz -= sector[sect].extra; + p = checkcursectnums(sect); + if(p >= 0) + ps[p].posz -= sector[sect].extra; + } + } + goto BOLT; + } + + if(t[5] == 1) goto BOLT; + + p = checkcursectnums(sect); + if( p >= 0 && ( ps[p].on_ground || s->ang == 512) ) + { + if( t[0] == 0 && !check_activator_motion(s->lotag) ) + { + t[0] = 1; + t[1] = 1; + t[3] = !t[3]; + operatemasterswitches(s->lotag); + operateactivators(s->lotag,p); + if(s->hitag > 0) + { + s->hitag--; + if(s->hitag == 0) t[5] = 1; + } + } + } + else t[0] = 0; + + if(t[1] == 1) + { + j = headspritestat[6]; + while(j >= 0) + { + if(j != i && sprite[j].picnum == TOUCHPLATE && sprite[j].lotag == s->lotag) + { + hittype[j].temp_data[1] = 1; + hittype[j].temp_data[3] = t[3]; + } + j = nextspritestat[j]; + } + } + goto BOLT; + + case CANWITHSOMETHING: + case CANWITHSOMETHING2: + case CANWITHSOMETHING3: + case CANWITHSOMETHING4: + makeitfall(i); + IFHIT + { + spritesound(VENT_BUST,i); + for(j=0;j<10;j++) + RANDOMSCRAP; + + if(s->lotag) spawn(i,s->lotag); + + KILLIT(i); + } + goto BOLT; + + case EXPLODINGBARREL: + case WOODENHORSE: + case HORSEONSIDE: + case FLOORFLAME: + case FIREBARREL: + case FIREVASE: + case NUKEBARREL: + case NUKEBARRELDENTED: + case NUKEBARRELLEAKED: + case TOILETWATER: + case RUBBERCAN: + case STEAM: + case CEILINGSTEAM: + p = findplayer(s, &x); + execute(i,p,x); + goto BOLT; + case WATERBUBBLEMAKER: + p = findplayer(s, &x); + execute(i,p,x); + goto BOLT; + } + + BOLT: + i = nexti; + } +} + +void bounce(short i) +{ + long k, l, daang, dax, day, daz, xvect, yvect, zvect; + short hitsect; + spritetype *s = &sprite[i]; + + xvect = mulscale10(s->xvel,sintable[(s->ang+512)&2047]); + yvect = mulscale10(s->xvel,sintable[s->ang&2047]); + zvect = s->zvel; + + hitsect = s->sectnum; + + k = sector[hitsect].wallptr; l = wall[k].point2; + daang = getangle(wall[l].x-wall[k].x,wall[l].y-wall[k].y); + + if ( s->z < (hittype[i].floorz+hittype[i].ceilingz)>>1) + k = sector[hitsect].ceilingheinum; + else + k = sector[hitsect].floorheinum; + + dax = mulscale14(k,sintable[(daang)&2047]); + day = mulscale14(k,sintable[(daang+1536)&2047]); + daz = 4096; + + k = xvect*dax+yvect*day+zvect*daz; + l = dax*dax+day*day+daz*daz; + if ((klabs(k)>>14) < l) + { + k = divscale17(k,l); + xvect -= mulscale16(dax,k); + yvect -= mulscale16(day,k); + zvect -= mulscale16(daz,k); + } + + s->zvel = zvect; + s->xvel = ksqrt(dmulscale8(xvect,xvect,yvect,yvect)); + s->ang = getangle(xvect,yvect); +} + +void moveweapons(void) +{ + short i, j, k, nexti, p, q, tempsect; + long dax,day,daz, x, l, ll, x1, y1; + unsigned long qq; + spritetype *s; + + i = headspritestat[4]; + while(i >= 0) + { + nexti = nextspritestat[i]; + s = &sprite[i]; + + if(s->sectnum < 0) KILLIT(i); + + hittype[i].bposx = s->x; + hittype[i].bposy = s->y; + hittype[i].bposz = s->z; + + switch(s->picnum) + { + case RADIUSEXPLOSION: + case KNEE: + KILLIT(i); + case TONGUE: + T1 = sintable[(T2)&2047]>>9; + T2 += 32; + if(T2 > 2047) KILLIT(i); + + if(sprite[s->owner].statnum == MAXSTATUS) + if(badguy(&sprite[s->owner]) == 0) + KILLIT(i); + + s->ang = sprite[s->owner].ang; + s->x = sprite[s->owner].x; + s->y = sprite[s->owner].y; + if(sprite[s->owner].picnum == APLAYER) + s->z = sprite[s->owner].z-(34<<8); + for(k=0;ksectnum, + s->x+((k*sintable[(s->ang+512)&2047])>>9), + s->y+((k*sintable[s->ang&2047])>>9), + s->z+((k*ksgn(s->zvel))*klabs(s->zvel/12)),TONGUE,-40+(k<<1), + 8,8,0,0,0,i,5); + sprite[q].cstat = 128; + sprite[q].pal = 8; + } + q = EGS(s->sectnum, + s->x+((k*sintable[(s->ang+512)&2047])>>9), + s->y+((k*sintable[s->ang&2047])>>9), + s->z+((k*ksgn(s->zvel))*klabs(s->zvel/12)),INNERJAW,-40, + 32,32,0,0,0,i,5); + sprite[q].cstat = 128; + if( T2 > 512 && T2 < (1024) ) + sprite[q].picnum = INNERJAW+1; + + goto BOLT; + + case FREEZEBLAST: + if(s->yvel < 1 || s->extra < 2 || (s->xvel|s->zvel) == 0) + { + j = spawn(i,TRANSPORTERSTAR); + sprite[j].pal = 1; + sprite[j].xrepeat = 32; + sprite[j].yrepeat = 32; + KILLIT(i); + } + case SHRINKSPARK: + case RPG: + case FIRELASER: + case SPIT: + case COOLEXPLOSION1: + + if( s->picnum == COOLEXPLOSION1 ) + if( Sound[WIERDSHOT_FLY].num == 0 ) + spritesound(WIERDSHOT_FLY,i); + + p = -1; + + if(s->picnum == RPG && sector[s->sectnum].lotag == 2) + { + k = s->xvel>>1; + ll = s->zvel>>1; + } + else + { + k = s->xvel; + ll = s->zvel; + } + + dax = s->x; day = s->y; daz = s->z; + + getglobalz(i); + qq = CLIPMASK1; + + switch(s->picnum) + { + case RPG: + if(hittype[i].picnum != BOSS2 && s->xrepeat >= 10 && sector[s->sectnum].lotag != 2) + { + j = spawn(i,SMALLSMOKE); + sprite[j].z += (1<<8); + } + break; + } + + j = movesprite(i, + (k*(sintable[(s->ang+512)&2047]))>>14, + (k*(sintable[s->ang&2047]))>>14,ll,qq); + + if(s->picnum == RPG && s->yvel >= 0) + if( FindDistance2D(s->x-sprite[s->yvel].x,s->y-sprite[s->yvel].y) < 256 ) + j = 49152|s->yvel; + + if(s->sectnum < 0) { KILLIT(i); } + + if( (j&49152) != 49152) + if(s->picnum != FREEZEBLAST) + { + if(s->z < hittype[i].ceilingz) + { + j = 16384|(s->sectnum); + s->zvel = -1; + } + else + if( ( s->z > hittype[i].floorz && sector[s->sectnum].lotag != 1 ) || + ( s->z > hittype[i].floorz+(16<<8) && sector[s->sectnum].lotag == 1 ) ) + { + j = 16384|(s->sectnum); + if(sector[s->sectnum].lotag != 1) + s->zvel = 1; + } + } + + if(s->picnum == FIRELASER) + { + for(k=-3;k<2;k++) + { + x = EGS(s->sectnum, + s->x+((k*sintable[(s->ang+512)&2047])>>9), + s->y+((k*sintable[s->ang&2047])>>9), + s->z+((k*ksgn(s->zvel))*klabs(s->zvel/24)),FIRELASER,-40+(k<<2), + s->xrepeat,s->yrepeat,0,0,0,s->owner,5); + + sprite[x].cstat = 128; + sprite[x].pal = s->pal; + } + } + else if(s->picnum == SPIT) if(s->zvel < 6144) + s->zvel += gc-112; + + if( j != 0 ) + { + if(s->picnum == COOLEXPLOSION1) + { + if( (j&49152) == 49152 && sprite[j&(MAXSPRITES-1)].picnum != APLAYER) + goto BOLT; + s->xvel = 0; + s->zvel = 0; + } + + if( (j&49152) == 49152 ) + { + j &= (MAXSPRITES-1); + + if(s->picnum == FREEZEBLAST && sprite[j].pal == 1 ) + if( badguy(&sprite[j]) || sprite[j].picnum == APLAYER ) + { + j = spawn(i,TRANSPORTERSTAR); + sprite[j].pal = 1; + sprite[j].xrepeat = 32; + sprite[j].yrepeat = 32; + + KILLIT(i); + } + + checkhitsprite(j,i); + + if(sprite[j].picnum == APLAYER) + { + p = sprite[j].yvel; + spritesound(PISTOL_BODYHIT,j); + + if(s->picnum == SPIT) + { + ps[p].horiz += 32; + ps[p].return_to_center = 8; + + if(ps[p].loogcnt == 0) + { + if(Sound[DUKE_LONGTERM_PAIN].num < 1) + spritesound(DUKE_LONGTERM_PAIN,ps[p].i); + + j = 3+(TRAND&3); + ps[p].numloogs = j; + ps[p].loogcnt = 24*4; + for(x=0;x < j;x++) + { + ps[p].loogiex[x] = TRAND%xdim; + ps[p].loogiey[x] = TRAND%ydim; + } + } + } + } + } + else if( (j&49152) == 32768 ) + { + j &= (MAXWALLS-1); + + if(s->picnum != RPG && s->picnum != FREEZEBLAST && s->picnum != SPIT && ( wall[j].overpicnum == MIRROR || wall[j].picnum == MIRROR ) ) + { + k = getangle( + wall[wall[j].point2].x-wall[j].x, + wall[wall[j].point2].y-wall[j].y); + s->ang = ((k<<1) - s->ang)&2047; + s->owner = i; + spawn(i,TRANSPORTERSTAR); + goto BOLT; + } + else + { + setsprite(i,dax,day,daz); + checkhitwall(i,j,s->x,s->y,s->z,s->picnum); + + if(s->picnum == FREEZEBLAST) + { + if( wall[j].overpicnum != MIRROR && wall[j].picnum != MIRROR ) + { + s->extra >>= 1; + s->yvel--; + } + + k = getangle( + wall[wall[j].point2].x-wall[j].x, + wall[wall[j].point2].y-wall[j].y); + s->ang = ((k<<1) - s->ang)&2047; + goto BOLT; + } + } + } + else if( (j&49152) == 16384) + { + setsprite(i,dax,day,daz); + + if(s->zvel < 0) + { + if( sector[s->sectnum].ceilingstat&1 ) + if(sector[s->sectnum].ceilingpal == 0) + KILLIT(i); + + checkhitceiling(s->sectnum); + } + + if(s->picnum == FREEZEBLAST) + { + bounce(i); + ssp(i,qq); + s->extra >>= 1; + if(s->xrepeat > 8) + s->xrepeat -= 2; + if(s->yrepeat > 8) + s->yrepeat -= 2; + s->yvel--; + goto BOLT; + } + } + + if(s->picnum != SPIT) + { + if(s->picnum == RPG) + { + k = spawn(i,EXPLOSION2); + sprite[k].x = dax; + sprite[k].y = day; + sprite[k].z = daz; + + if(s->xrepeat < 10) + { + sprite[k].xrepeat = 6; + sprite[k].yrepeat = 6; + } + else if( (j&49152) == 16384) + { + if( s->zvel > 0) + spawn(i,EXPLOSION2BOT); + else { sprite[k].cstat |= 8; sprite[k].z += (48<<8); } + } + } + else if(s->picnum == SHRINKSPARK) + { + spawn(i,SHRINKEREXPLOSION); + spritesound(SHRINKER_HIT,i); + hitradius(i,shrinkerblastradius,0,0,0,0); + } + else if( s->picnum != COOLEXPLOSION1 && s->picnum != FREEZEBLAST && s->picnum != FIRELASER) + { + k = spawn(i,EXPLOSION2); + sprite[k].xrepeat = sprite[k].yrepeat = s->xrepeat>>1; + if( (j&49152) == 16384) + { + if( s->zvel < 0) + { sprite[k].cstat |= 8; sprite[k].z += (72<<8); } + } + } + if( s->picnum == RPG ) + { + spritesound(RPG_EXPLODE,i); + + if(s->xrepeat >= 10) + { + x = s->extra; + hitradius( i,rpgblastradius, x>>2,x>>1,x-(x>>2),x); + } + else + { + x = s->extra+(global_random&3); + hitradius( i,(rpgblastradius>>1),x>>2,x>>1,x-(x>>2),x); + } + } + } + if(s->picnum != COOLEXPLOSION1) KILLIT(i); + } + if(s->picnum == COOLEXPLOSION1) + { + s->shade++; + if(s->shade >= 40) KILLIT(i); + } + else if(s->picnum == RPG && sector[s->sectnum].lotag == 2 && s->xrepeat >= 10 && rnd(140)) + spawn(i,WATERBUBBLE); + + goto BOLT; + + + case SHOTSPARK1: + p = findplayer(s,&x); + execute(i,p,x); + goto BOLT; + } + BOLT: + i = nexti; + } +} + + +void movetransports(void) +{ + char warpspriteto; + short i, j, k, l, p, sect, sectlotag, nexti, nextj, nextk; + long ll,onfloorz,q; + + i = headspritestat[9]; //Transporters + + while(i >= 0) + { + sect = SECT; + sectlotag = sector[sect].lotag; + + nexti = nextspritestat[i]; + + if(OW == i) + { + i = nexti; + continue; + } + + onfloorz = T5; + + if(T1 > 0) T1--; + + j = headspritesect[sect]; + while(j >= 0) + { + nextj = nextspritesect[j]; + + switch(sprite[j].statnum) + { + case 10: // Player + + if( sprite[j].owner != -1 ) + { + p = sprite[j].yvel; + + ps[p].on_warping_sector = 1; + + if( ps[p].transporter_hold == 0 && ps[p].jumping_counter == 0 ) + { + if(ps[p].on_ground && sectlotag == 0 && onfloorz && ps[p].jetpack_on == 0 ) + { + if(sprite[i].pal == 0) + { + spawn(i,TRANSPORTERBEAM); + spritesound(TELEPORTER,i); + } + + for(k=connecthead;k>=0;k=connectpoint2[k]) + if(ps[k].cursectnum == sprite[OW].sectnum) + { + ps[k].frag_ps = p; + sprite[ps[k].i].extra = 0; + } + + ps[p].ang = sprite[OW].ang; + + if(sprite[OW].owner != OW) + { + T1 = 13; + hittype[OW].temp_data[0] = 13; + ps[p].transporter_hold = 13; + } + + ps[p].bobposx = ps[p].oposx = ps[p].posx = sprite[OW].x; + ps[p].bobposy = ps[p].oposy = ps[p].posy = sprite[OW].y; + ps[p].oposz = ps[p].posz = sprite[OW].z-PHEIGHT; + + changespritesect(j,sprite[OW].sectnum); + ps[p].cursectnum = sprite[j].sectnum; + + if(sprite[i].pal == 0) + { + k = spawn(OW,TRANSPORTERBEAM); + spritesound(TELEPORTER,k); + } + + break; + } + } + else if( !(sectlotag == 1 && ps[p].on_ground == 1) ) break; + + if(onfloorz == 0 && klabs(SZ-ps[p].posz) < 6144 ) + if( (ps[p].jetpack_on == 0 ) || (ps[p].jetpack_on && (sync[p].bits&1) ) || + (ps[p].jetpack_on && (sync[p].bits&2) ) ) + { + ps[p].oposx = ps[p].posx += sprite[OW].x-SX; + ps[p].oposy = ps[p].posy += sprite[OW].y-SY; + + if( ps[p].jetpack_on && ( (sync[p].bits&1) || ps[p].jetpack_on < 11 ) ) + ps[p].posz = sprite[OW].z-6144; + else ps[p].posz = sprite[OW].z+6144; + ps[p].oposz = ps[p].posz; + + hittype[ps[p].i].bposx = ps[p].posx; + hittype[ps[p].i].bposy = ps[p].posy; + hittype[ps[p].i].bposz = ps[p].posz; + + changespritesect(j,sprite[OW].sectnum); + ps[p].cursectnum = sprite[OW].sectnum; + + break; + } + + k = 0; + + if( onfloorz && sectlotag == 1 && ps[p].on_ground && ps[p].posz > (sector[sect].floorz-(16<<8)) && ( (sync[p].bits&2) || ps[p].poszv > 2048 ) ) +// if( onfloorz && sectlotag == 1 && ps[p].posz > (sector[sect].floorz-(6<<8)) ) + { + k = 1; + if(screenpeek == p) + { + FX_StopAllSounds(); + clearsoundlocks(); + } + if(sprite[ps[p].i].extra > 0) + spritesound(DUKE_UNDERWATER,j); + ps[p].oposz = ps[p].posz = + sector[sprite[OW].sectnum].ceilingz+(7<<8); + + ps[p].posxv = 4096-(TRAND&8192); + ps[p].posyv = 4096-(TRAND&8192); + + } + + if( onfloorz && sectlotag == 2 && ps[p].posz < (sector[sect].ceilingz+(6<<8)) ) + { + k = 1; +// if( sprite[j].extra <= 0) break; + if(screenpeek == p) + { + FX_StopAllSounds(); + clearsoundlocks(); + } + spritesound(DUKE_GASP,j); + + ps[p].oposz = ps[p].posz = + sector[sprite[OW].sectnum].floorz-(7<<8); + + ps[p].jumping_toggle = 1; + ps[p].jumping_counter = 0; + } + + if(k == 1) + { + ps[p].oposx = ps[p].posx += sprite[OW].x-SX; + ps[p].oposy = ps[p].posy += sprite[OW].y-SY; + + if(sprite[OW].owner != OW) + ps[p].transporter_hold = -2; + ps[p].cursectnum = sprite[OW].sectnum; + + changespritesect(j,sprite[OW].sectnum); + setsprite(ps[p].i,ps[p].posx,ps[p].posy,ps[p].posz+PHEIGHT); + + setpal(&ps[p]); + + if( (TRAND&255) < 32 ) + spawn(j,WATERSPLASH2); + + if(sectlotag == 1) + for(l = 0;l < 9;l++) + { + q = spawn(ps[p].i,WATERBUBBLE); + sprite[q].z += TRAND&16383; + } + } + } + break; + + case 1: + switch(sprite[j].picnum) + { + case SHARK: + case COMMANDER: + case OCTABRAIN: + case GREENSLIME: + case GREENSLIME+1: + case GREENSLIME+2: + case GREENSLIME+3: + case GREENSLIME+4: + case GREENSLIME+5: + case GREENSLIME+6: + case GREENSLIME+7: + if(sprite[j].extra > 0) + goto JBOLT; + } + case 4: + case 5: + case 12: + case 13: + + ll = klabs(sprite[j].zvel); + + { + warpspriteto = 0; + if( ll && sectlotag == 2 && sprite[j].z < (sector[sect].ceilingz+ll) ) + warpspriteto = 1; + + if( ll && sectlotag == 1 && sprite[j].z > (sector[sect].floorz-ll) ) + warpspriteto = 1; + + if( sectlotag == 0 && ( onfloorz || klabs(sprite[j].z-SZ) < 4096) ) + { + if( sprite[OW].owner != OW && onfloorz && T1 > 0 && sprite[j].statnum != 5 ) + { + T1++; + goto BOLT; + } + warpspriteto = 1; + } + + if( warpspriteto ) switch(sprite[j].picnum) + { + case TRANSPORTERSTAR: + case TRANSPORTERBEAM: + case TRIPBOMB: + case BULLETHOLE: + case WATERSPLASH2: + case BURNING: + case BURNING2: + case FIRE: + case FIRE2: + case TOILETWATER: + case LASERLINE: + goto JBOLT; + case PLAYERONWATER: + if(sectlotag == 2) + { + sprite[j].cstat &= 32767; + break; + } + default: + if(sprite[j].statnum == 5 && !(sectlotag == 1 || sectlotag == 2) ) + break; + + case WATERBUBBLE: +// if( rnd(192) && sprite[j].picnum == WATERBUBBLE) + // break; + + if(sectlotag > 0) + { + k = spawn(j,WATERSPLASH2); + if( sectlotag == 1 && sprite[j].statnum == 4 ) + { + sprite[k].xvel = sprite[j].xvel>>1; + sprite[k].ang = sprite[j].ang; + ssp(k,CLIPMASK0); + } + } + + switch(sectlotag) + { + case 0: + if(onfloorz) + { + if( sprite[j].statnum == 4 || ( checkcursectnums(sect) == -1 && checkcursectnums(sprite[OW].sectnum) == -1 ) ) + { + sprite[j].x += (sprite[OW].x-SX); + sprite[j].y += (sprite[OW].y-SY); + sprite[j].z -= SZ - sector[sprite[OW].sectnum].floorz; + sprite[j].ang = sprite[OW].ang; + + hittype[j].bposx = sprite[j].x; + hittype[j].bposy = sprite[j].y; + hittype[j].bposz = sprite[j].z; + + if(sprite[i].pal == 0) + { + k = spawn(i,TRANSPORTERBEAM); + spritesound(TELEPORTER,k); + + k = spawn(OW,TRANSPORTERBEAM); + spritesound(TELEPORTER,k); + } + + if( sprite[OW].owner != OW ) + { + T1 = 13; + hittype[OW].temp_data[0] = 13; + } + + changespritesect(j,sprite[OW].sectnum); + } + } + else + { + sprite[j].x += (sprite[OW].x-SX); + sprite[j].y += (sprite[OW].y-SY); + sprite[j].z = sprite[OW].z+4096; + + hittype[j].bposx = sprite[j].x; + hittype[j].bposy = sprite[j].y; + hittype[j].bposz = sprite[j].z; + + changespritesect(j,sprite[OW].sectnum); + } + break; + case 1: + sprite[j].x += (sprite[OW].x-SX); + sprite[j].y += (sprite[OW].y-SY); + sprite[j].z = sector[sprite[OW].sectnum].ceilingz+ll; + + hittype[j].bposx = sprite[j].x; + hittype[j].bposy = sprite[j].y; + hittype[j].bposz = sprite[j].z; + + changespritesect(j,sprite[OW].sectnum); + + break; + case 2: + sprite[j].x += (sprite[OW].x-SX); + sprite[j].y += (sprite[OW].y-SY); + sprite[j].z = sector[sprite[OW].sectnum].floorz-ll; + + hittype[j].bposx = sprite[j].x; + hittype[j].bposy = sprite[j].y; + hittype[j].bposz = sprite[j].z; + + changespritesect(j,sprite[OW].sectnum); + + break; + } + + break; + } + } + break; + + } + JBOLT: + j = nextj; + } + BOLT: + i = nexti; + } +} + + + +void moveactors(void) +{ + long x, m, l, *t; + short a, i, j, nexti, nextj, sect, p; + spritetype *s; + unsigned short k; + + i = headspritestat[1]; + while(i >= 0) + { + nexti = nextspritestat[i]; + + s = &sprite[i]; + + sect = s->sectnum; + + if( s->xrepeat == 0 || sect < 0 || sect >= MAXSECTORS) + KILLIT(i); + + t = &hittype[i].temp_data[0]; + + hittype[i].bposx = s->x; + hittype[i].bposy = s->y; + hittype[i].bposz = s->z; + + + switch(s->picnum) + { + case DUCK: + case TARGET: + if(s->cstat&32) + { + t[0]++; + if(t[0] > 60) + { + t[0] = 0; + s->cstat = 128+257+16; + s->extra = 1; + } + } + else + { + j = ifhitbyweapon(i); + if( j >= 0 ) + { + s->cstat = 32+128; + k = 1; + + j = headspritestat[1]; + while(j >= 0) + { + if( sprite[j].lotag == s->lotag && + sprite[j].picnum == s->picnum ) + { + if( ( sprite[j].hitag && !(sprite[j].cstat&32) ) || + ( !sprite[j].hitag && (sprite[j].cstat&32) ) + ) + { + k = 0; + break; + } + } + + j = nextspritestat[j]; + } + + if(k == 1) + { + operateactivators(s->lotag,-1); + operateforcefields(i,s->lotag); + operatemasterswitches(s->lotag); + } + } + } + goto BOLT; + + case RESPAWNMARKERRED: + case RESPAWNMARKERYELLOW: + case RESPAWNMARKERGREEN: + T1++; + if(T1 > respawnitemtime) + { + KILLIT(i); + } + if( T1 >= (respawnitemtime>>1) && T1 < ((respawnitemtime>>1)+(respawnitemtime>>2)) ) + PN = RESPAWNMARKERYELLOW; + else if( T1 > ((respawnitemtime>>1)+(respawnitemtime>>2)) ) + PN = RESPAWNMARKERGREEN; + makeitfall(i); + break; + + case HELECOPT: + case DUKECAR: + + s->z += s->zvel; + t[0]++; + + if(t[0] == 4) spritesound(WAR_AMBIENCE2,i); + + if( t[0] > (26*8) ) + { + sound(RPG_EXPLODE); + for(j=0;j<32;j++) RANDOMSCRAP; + earthquaketime = 16; + KILLIT(i); + } + else if((t[0]&3) == 0) + spawn(i,EXPLOSION2); + ssp(i,CLIPMASK0); + break; + case RAT: + makeitfall(i); + IFMOVING + { + if( (TRAND&255) < 3 ) spritesound(RATTY,i); + s->ang += (TRAND&31)-15+(sintable[(t[0]<<8)&2047]>>11); + } + else + { + T1++; + if(T1 > 1) { KILLIT(i); } + else s->ang = (TRAND&2047); + } + if(s->xvel < 128) + s->xvel+=2; + s->ang += (TRAND&3)-6; + break; + case QUEBALL: + case STRIPEBALL: + if(s->xvel) + { + j = headspritestat[0]; + while(j >= 0) + { + nextj = nextspritestat[j]; + if( sprite[j].picnum == POCKET && ldist(&sprite[j],s) < 52 ) KILLIT(i); + j = nextj; + } + + j = clipmove(&s->x,&s->y,&s->z,&s->sectnum, + (((s->xvel*(sintable[(s->ang+512)&2047]))>>14)*TICSPERFRAME)<<11, + (((s->xvel*(sintable[s->ang&2047]))>>14)*TICSPERFRAME)<<11, + 24L,(4<<8),(4<<8),CLIPMASK1); + + if(j&49152) + { + if( (j&49152) == 32768 ) + { + j &= (MAXWALLS-1); + k = getangle( + wall[wall[j].point2].x-wall[j].x, + wall[wall[j].point2].y-wall[j].y); + s->ang = ((k<<1) - s->ang)&2047; + } + else if( (j&49152) == 49152 ) + { + j &= (MAXSPRITES-1); + checkhitsprite(i,j); + } + } + s->xvel --; + if(s->xvel < 0) s->xvel = 0; + if( s->picnum == STRIPEBALL ) + { + s->cstat = 257; + s->cstat |= 4&s->xvel; + s->cstat |= 8&s->xvel; + } + } + else + { + p = findplayer(s,&x); + + if( x < 1596) + { + +// if(s->pal == 12) + { + j = getincangle(ps[p].ang,getangle(s->x-ps[p].posx,s->y-ps[p].posy)); + if( j > -64 && j < 64 && (sync[p].bits&(1<<29)) ) + if(ps[p].toggle_key_flag == 1) + { + a = headspritestat[1]; + while(a >= 0) + { + if(sprite[a].picnum == QUEBALL || sprite[a].picnum == STRIPEBALL) + { + j = getincangle(ps[p].ang,getangle(sprite[a].x-ps[p].posx,sprite[a].y-ps[p].posy)); + if( j > -64 && j < 64 ) + { + findplayer(&sprite[a],&l); + if(x > l) break; + } + } + a = nextspritestat[a]; + } + if(a == -1) + { + if(s->pal == 12) + s->xvel = 164; + else s->xvel = 140; + s->ang = ps[p].ang; + ps[p].toggle_key_flag = 2; + } + } + } + } + if( x < 512 && s->sectnum == ps[p].cursectnum ) + { + s->ang = getangle(s->x-ps[p].posx,s->y-ps[p].posy); + s->xvel = 48; + } + } + + break; + case FORCESPHERE: + + if(s->yvel == 0) + { + s->yvel = 1; + + for(l=512;l<(2048-512);l+= 128) + for(j=0;j<2048;j += 128) + { + k = spawn(i,FORCESPHERE); + sprite[k].cstat = 257+128; + sprite[k].clipdist = 64; + sprite[k].ang = j; + sprite[k].zvel = sintable[l&2047]>>5; + sprite[k].xvel = sintable[(l+512)&2047]>>9; + sprite[k].owner = i; + } + } + + if(t[3] > 0) + { + if(s->zvel < 6144) + s->zvel += 192; + s->z += s->zvel; + if(s->z > sector[sect].floorz) + s->z = sector[sect].floorz; + t[3]--; + if(t[3] == 0) + KILLIT(i); + } + else if(t[2] > 10) + { + j = headspritestat[5]; + while(j >= 0) + { + if(sprite[j].owner == i && sprite[j].picnum == FORCESPHERE) + hittype[j].temp_data[1] = 1+(TRAND&63); + j = nextspritestat[j]; + } + t[3] = 64; + } + + goto BOLT; + + case RECON: + + getglobalz(i); + + if (sector[s->sectnum].ceilingstat&1) + s->shade += (sector[s->sectnum].ceilingshade-s->shade)>>1; + else s->shade += (sector[s->sectnum].floorshade-s->shade)>>1; + + if( s->z < sector[sect].ceilingz+(32<<8) ) + s->z = sector[sect].ceilingz+(32<<8); + + if( ud.multimode < 2 ) + { + if( actor_tog == 1) + { + s->cstat = (short)32768; + goto BOLT; + } + else if(actor_tog == 2) s->cstat = 257; + } + IFHIT + { + if( s->extra < 0 && t[0] != -1 ) + { + t[0] = -1; + s->extra = 0; + } + spritesound(RECO_PAIN,i); + RANDOMSCRAP; + } + + if(t[0] == -1) + { + s->z += 1024; + t[2]++; + if( (t[2]&3) == 0) spawn(i,EXPLOSION2); + getglobalz(i); + s->ang += 96; + s->xvel = 128; + j = ssp(i,CLIPMASK0); + if(j != 1 || s->z > hittype[i].floorz) + { + for(l=0;l<16;l++) + RANDOMSCRAP; + spritesound(LASERTRIP_EXPLODE,i); + spawn(i,PIGCOP); + ps[myconnectindex].actors_killed++; + KILLIT(i); + } + goto BOLT; + } + else + { + if( s->z > hittype[i].floorz-(48<<8) ) + s->z = hittype[i].floorz-(48<<8); + } + + p = findplayer(s,&x); + j = s->owner; + + // 3 = findplayerz, 4 = shoot + + if( t[0] >= 4 ) + { + t[2]++; + if( (t[2]&15) == 0 ) + { + a = s->ang; + s->ang = hittype[i].tempang; + spritesound(RECO_ATTACK,i); + shoot(i,FIRELASER); + s->ang = a; + } + if( t[2] > (26*3) || !cansee(s->x,s->y,s->z-(16<<8),s->sectnum, ps[p].posx,ps[p].posy,ps[p].posz,ps[p].cursectnum ) ) + { + t[0] = 0; + t[2] = 0; + } + else hittype[i].tempang += + getincangle(hittype[i].tempang,getangle(ps[p].posx-s->x,ps[p].posy-s->y))/3; + } + else if(t[0] == 2 || t[0] == 3) + { + t[3] = 0; + if(s->xvel > 0) s->xvel -= 16; + else s->xvel = 0; + + if(t[0] == 2) + { + l = ps[p].posz-s->z; + if( klabs(l) < (48<<8) ) t[0] = 3; + else s->z += sgn(ps[p].posz-s->z)<<10; + } + else + { + t[2]++; + if( t[2] > (26*3) || !cansee(s->x,s->y,s->z-(16<<8),s->sectnum, ps[p].posx,ps[p].posy,ps[p].posz,ps[p].cursectnum ) ) + { + t[0] = 1; + t[2] = 0; + } + else if( (t[2]&15) == 0 ) + { + spritesound(RECO_ATTACK,i); + shoot(i,FIRELASER); + } + } + s->ang += getincangle(s->ang,getangle(ps[p].posx-s->x,ps[p].posy-s->y))>>2; + } + + if( t[0] != 2 && t[0] != 3 ) + { + l = ldist(&sprite[j],s); + if(l <= 1524) + { + a = s->ang; + s->xvel >>= 1; + } + else a = getangle(sprite[j].x-s->x,sprite[j].y-s->y); + + if(t[0] == 1 || t[0] == 4) // Found a locator and going with it + { + l = dist(&sprite[j],s); + + if( l <= 1524 ) { if(t[0] == 1) t[0] = 0; else t[0] = 5; } + else + { + // Control speed here + if(l > 1524) { if( s->xvel < 256 ) s->xvel += 32; } + else + { + if(s->xvel > 0) s->xvel -= 16; + else s->xvel = 0; + } + } + + if(t[0] < 2) t[2]++; + + if( x < 6144 && t[0] < 2 && t[2] > (26*4) ) + { + t[0] = 2+(TRAND&2); + t[2] = 0; + hittype[i].tempang = s->ang; + } + } + + if(t[0] == 0 || t[0] == 5) + { + if(t[0] == 0) + t[0] = 1; + else t[0] = 4; + j = s->owner = LocateTheLocator(s->hitag,-1); + if(j == -1) + { + s->hitag = j = hittype[i].temp_data[5]; + s->owner = LocateTheLocator(j,-1); + j = s->owner; + if(j == -1) KILLIT(i); + } + else s->hitag++; + } + + t[3] = getincangle(s->ang,a); + s->ang += t[3]>>3; + + if(s->z < sprite[j].z) + s->z += 1024; + else s->z -= 1024; + } + + if(Sound[RECO_ROAM].num == 0 ) + spritesound(RECO_ROAM,i); + + ssp(i,CLIPMASK0); + + goto BOLT; + + case OOZ: + case OOZ2: + + getglobalz(i); + + j = (hittype[i].floorz-hittype[i].ceilingz)>>9; + if(j > 255) j = 255; + + x = 25-(j>>1); + if(x < 8) x = 8; + else if(x > 48) x = 48; + + s->yrepeat = j; + s->xrepeat = x; + s->z = hittype[i].floorz; + + goto BOLT; + + case GREENSLIME: + case GREENSLIME+1: + case GREENSLIME+2: + case GREENSLIME+3: + case GREENSLIME+4: + case GREENSLIME+5: + case GREENSLIME+6: + case GREENSLIME+7: + +// #ifndef VOLUMEONE + if( ud.multimode < 2 ) + { + if( actor_tog == 1) + { + s->cstat = (short)32768; + goto BOLT; + } + else if(actor_tog == 2) s->cstat = 257; + } +// #endif + + t[1]+=128; + + if(sector[sect].floorstat&1) + KILLIT(i); + + p = findplayer(s,&x); + + if(x > 20480) + { + hittype[i].timetosleep++; + if( hittype[i].timetosleep > SLEEPTIME ) + { + hittype[i].timetosleep = 0; + changespritestat(i,2); + goto BOLT; + } + } + + if(t[0] == -5) // FROZEN + { + t[3]++; + if(t[3] > 280) + { + s->pal = 0; + t[0] = 0; + goto BOLT; + } + makeitfall(i); + s->cstat = 257; + s->picnum = GREENSLIME+2; + s->extra = 1; + s->pal = 1; + IFHIT + { + if(j == FREEZEBLAST) goto BOLT; + for(j=16; j >= 0 ;j--) + { + k = EGS(SECT,SX,SY,SZ,GLASSPIECES+(j%3),-32,36,36,TRAND&2047,32+(TRAND&63),1024-(TRAND&1023),i,5); + sprite[k].pal = 1; + } + spritesound(GLASS_BREAKING,i); + KILLIT(i); + } + else if(x < 1024 && ps[p].quick_kick == 0) + { + j = getincangle(ps[p].ang,getangle(SX-ps[p].posx,SY-ps[p].posy)); + if( j > -128 && j < 128 ) + ps[p].quick_kick = 14; + } + + goto BOLT; + } + + if(x < 1596) + s->cstat = 0; + else s->cstat = 257; + + if(t[0] == -4) //On the player + { + if( sprite[ps[p].i].extra < 1 ) + { + t[0] = 0; + goto BOLT; + } + + setsprite(i,s->x,s->y,s->z); + + s->ang = ps[p].ang; + + if( ( (sync[p].bits&4) || (ps[p].quick_kick > 0) ) && sprite[ps[p].i].extra > 0 ) + if( ps[p].quick_kick > 0 || ( ps[p].curr_weapon != HANDREMOTE_WEAPON && ps[p].curr_weapon != HANDBOMB_WEAPON && ps[p].curr_weapon != TRIPBOMB_WEAPON && ps[p].ammo_amount[ps[p].curr_weapon] >= 0) ) + { + for(x=0;x<8;x++) + { + j = EGS(sect,s->x,s->y,s->z-(8<<8),SCRAP3+(TRAND&3),-8,48,48,TRAND&2047,(TRAND&63)+64,-(TRAND&4095)-(s->zvel>>2),i,5); + sprite[j].pal = 6; + } + + spritesound(SLIM_DYING,i); + spritesound(SQUISHED,i); + if( (TRAND&255) < 32 ) + { + j = spawn(i,BLOODPOOL); + sprite[j].pal = 0; + } + ps[p].actors_killed ++; + t[0] = -3; + if(ps[p].somethingonplayer == i) + ps[p].somethingonplayer = -1; + KILLIT(i); + } + + s->z = ps[p].posz+ps[p].pyoff-t[2]+(8<<8); + + s->z += (100-ps[p].horiz)<<4; + + if( t[2] > 512) + t[2] -= 128; + + if( t[2] < 348) + t[2] += 128; + + if(ps[p].newowner >= 0) + { + ps[p].newowner = -1; + ps[p].posx = ps[p].oposx; + ps[p].posy = ps[p].oposy; + ps[p].posz = ps[p].oposz; + ps[p].ang = ps[p].oang; + + updatesector(ps[p].posx,ps[p].posy,&ps[p].cursectnum); + setpal(&ps[p]); + + j = headspritestat[1]; + while(j >= 0) + { + if(sprite[j].picnum==CAMERA1) sprite[j].yvel = 0; + j = nextspritestat[j]; + } + } + + if(t[3]>0) + { + short frames[] = {5,5,6,6,7,7,6,5}; + + s->picnum = GREENSLIME+frames[t[3]]; + + if( t[3] == 5 ) + { + sprite[ps[p].i].extra += -(5+(TRAND&3)); + spritesound(SLIM_ATTACK,i); + } + + if(t[3] < 7) t[3]++; + else t[3] = 0; + + } + else + { + s->picnum = GREENSLIME+5; + if(rnd(32)) + t[3] = 1; + } + + s->xrepeat = 20+(sintable[t[1]&2047]>>13); + s->yrepeat = 15+(sintable[t[1]&2047]>>13); + + s->x = ps[p].posx + (sintable[(ps[p].ang+512)&2047]>>7); + s->y = ps[p].posy + (sintable[ps[p].ang&2047]>>7); + + goto BOLT; + } + + else if(s->xvel < 64 && x < 768) + { + if(ps[p].somethingonplayer == -1) + { + ps[p].somethingonplayer = i; + if(t[0] == 3 || t[0] == 2) //Falling downward + t[2] = (12<<8); + else t[2] = -(13<<8); //Climbing up duke + t[0] = -4; + } + } + + IFHIT + { + spritesound(SLIM_DYING,i); + + ps[p].actors_killed ++; + if(ps[p].somethingonplayer == i) + ps[p].somethingonplayer = -1; + + if(j == FREEZEBLAST) + { + spritesound(SOMETHINGFROZE,i); t[0] = -5 ; t[3] = 0 ; + goto BOLT; + } + + if( (TRAND&255) < 32 ) + { + j = spawn(i,BLOODPOOL); + sprite[j].pal = 0; + } + + for(x=0;x<8;x++) + { + j = EGS(sect,s->x,s->y,s->z-(8<<8),SCRAP3+(TRAND&3),-8,48,48,TRAND&2047,(TRAND&63)+64,-(TRAND&4095)-(s->zvel>>2),i,5); + sprite[j].pal = 6; + } + t[0] = -3; + KILLIT(i); + } + // All weap + if(t[0] == -1) //Shrinking down + { + makeitfall(i); + + s->cstat &= 65535-8; + s->picnum = GREENSLIME+4; + +// if(s->yrepeat > 62) + // guts(s,JIBS6,5,myconnectindex); + + if(s->xrepeat > 32) s->xrepeat -= TRAND&7; + if(s->yrepeat > 16) s->yrepeat -= TRAND&7; + else + { + s->xrepeat = 40; + s->yrepeat = 16; + t[5] = -1; + t[0] = 0; + } + + goto BOLT; + } + else if(t[0] != -2) getglobalz(i); + + if(t[0] == -2) //On top of somebody + { + makeitfall(i); + sprite[t[5]].xvel = 0; + + l = sprite[t[5]].ang; + + s->z = sprite[t[5]].z; + s->x = sprite[t[5]].x+(sintable[(l+512)&2047]>>11); + s->y = sprite[t[5]].y+(sintable[l&2047]>>11); + + s->picnum = GREENSLIME+2+(global_random&1); + + if(s->yrepeat < 64) s->yrepeat+=2; + else + { + if(s->xrepeat < 32) s->xrepeat += 4; + else + { + t[0] = -1; + x = ldist(s,&sprite[t[5]]); + if(x < 768) sprite[t[5]].xrepeat = 0; + } + } + + goto BOLT; + } + + //Check randomly to see of there is an actor near + if(rnd(32)) + { + j = headspritesect[sect]; + while(j>=0) + { + switch(sprite[j].picnum) + { + case LIZTROOP: + case LIZMAN: + case PIGCOP: + case NEWBEAST: + if( ldist(s,&sprite[j]) < 768 && (klabs(s->z-sprite[j].z)<8192) ) //Gulp them + { + t[5] = j; + t[0] = -2; + t[1] = 0; + goto BOLT; + } + } + + j = nextspritesect[j]; + } + } + + //Moving on the ground or ceiling + + if(t[0] == 0 || t[0] == 2) + { + s->picnum = GREENSLIME; + + if( (TRAND&511) == 0 ) + spritesound(SLIM_ROAM,i); + + if(t[0]==2) + { + s->zvel = 0; + s->cstat &= (65535-8); + + if( (sector[sect].ceilingstat&1) || (hittype[i].ceilingz+6144) < s->z) + { + s->z += 2048; + t[0] = 3; + goto BOLT; + } + } + else + { + s->cstat |= 8; + makeitfall(i); + } + + if( everyothertime&1 ) ssp(i,CLIPMASK0); + + if(s->xvel > 96) + { + s->xvel -= 2; + goto BOLT; + } + else + { + if(s->xvel < 32) s->xvel += 4; + s->xvel = 64 - (sintable[(t[1]+512)&2047]>>9); + + s->ang += getincangle(s->ang, + getangle(ps[p].posx-s->x,ps[p].posy-s->y))>>3; +// TJR + } + + s->xrepeat = 36 + (sintable[(t[1]+512)&2047]>>11); + s->yrepeat = 16 + (sintable[t[1]&2047]>>13); + + if(rnd(4) && (sector[sect].ceilingstat&1) == 0 && + klabs(hittype[i].floorz-hittype[i].ceilingz) + < (192<<8) ) + { + s->zvel = 0; + t[0]++; + } + + } + + if(t[0]==1) + { + s->picnum = GREENSLIME; + if(s->yrepeat < 40) s->yrepeat+=8; + if(s->xrepeat > 8) s->xrepeat-=4; + if(s->zvel > -(2048+1024)) + s->zvel -= 348; + s->z += s->zvel; + if(s->z < hittype[i].ceilingz+4096) + { + s->z = hittype[i].ceilingz+4096; + s->xvel = 0; + t[0] = 2; + } + } + + if(t[0]==3) + { + s->picnum = GREENSLIME+1; + + makeitfall(i); + + if(s->z > hittype[i].floorz-(8<<8)) + { + s->yrepeat-=4; + s->xrepeat+=2; + } + else + { + if(s->yrepeat < (40-4)) s->yrepeat+=8; + if(s->xrepeat > 8) s->xrepeat-=4; + } + + if(s->z > hittype[i].floorz-2048) + { + s->z = hittype[i].floorz-2048; + t[0] = 0; + s->xvel = 0; + } + } + goto BOLT; + + case BOUNCEMINE: + case MORTER: + j = spawn(i,FRAMEEFFECT1); + hittype[j].temp_data[0] = 3; + + case HEAVYHBOMB: + + if( (s->cstat&32768) ) + { + t[2]--; + if(t[2] <= 0) + { + spritesound(TELEPORTER,i); + spawn(i,TRANSPORTERSTAR); + s->cstat = 257; + } + goto BOLT; + } + + p = findplayer(s,&x); + + if( x < 1220 ) s->cstat &= ~257; + else s->cstat |= 257; + + if(t[3] == 0 ) + { + j = ifhitbyweapon(i); + if(j >= 0) + { + t[3] = 1; + t[4] = 0; + l = 0; + s->xvel = 0; + goto DETONATEB; + } + } + + if( s->picnum != BOUNCEMINE ) + { + makeitfall(i); + + if( sector[sect].lotag != 1 && s->z >= hittype[i].floorz-(FOURSLEIGHT) && s->yvel < 3 ) + { + if( s->yvel > 0 || (s->yvel == 0 && hittype[i].floorz == sector[sect].floorz )) + spritesound(PIPEBOMB_BOUNCE,i); + s->zvel = -((4-s->yvel)<<8); + if(sector[s->sectnum].lotag== 2) + s->zvel >>= 2; + s->yvel++; + } + if( s->z < hittype[i].ceilingz ) // && sector[sect].lotag != 2 ) + { + s->z = hittype[i].ceilingz+(3<<8); + s->zvel = 0; + } + } + + j = movesprite(i, + (s->xvel*(sintable[(s->ang+512)&2047]))>>14, + (s->xvel*(sintable[s->ang&2047]))>>14, + s->zvel,CLIPMASK0); + + if(sector[SECT].lotag == 1 && s->zvel == 0) + { + s->z += (32<<8); + if(t[5] == 0) + { + t[5] = 1; + spawn(i,WATERSPLASH2); + } + } + else t[5] = 0; + + if(t[3] == 0 && ( s->picnum == BOUNCEMINE || s->picnum == MORTER ) && (j || x < 844) ) + { + t[3] = 1; + t[4] = 0; + l = 0; + s->xvel = 0; + goto DETONATEB; + } + + if(sprite[s->owner].picnum == APLAYER) + l = sprite[s->owner].yvel; + else l = -1; + + if(s->xvel > 0) + { + s->xvel -= 5; + if(sector[sect].lotag == 2) + s->xvel -= 10; + + if(s->xvel < 0) + s->xvel = 0; + if(s->xvel&8) s->cstat ^= 4; + } + + if( (j&49152) == 32768 ) + { + j &= (MAXWALLS-1); + + checkhitwall(i,j,s->x,s->y,s->z,s->picnum); + + k = getangle( + wall[wall[j].point2].x-wall[j].x, + wall[wall[j].point2].y-wall[j].y); + + s->ang = ((k<<1) - s->ang)&2047; + s->xvel >>= 1; + } + + DETONATEB: + + if( ( l >= 0 && ps[l].hbomb_on == 0 ) || t[3] == 1) + { + t[4]++; + + if(t[4] == 2) + { + x = s->extra; + m = 0; + switch(s->picnum) + { + case HEAVYHBOMB: m = pipebombblastradius;break; + case MORTER: m = morterblastradius;break; + case BOUNCEMINE: m = bouncemineblastradius;break; + } + + hitradius( i, m,x>>2,x>>1,x-(x>>2),x); + spawn(i,EXPLOSION2); + if( s->zvel == 0 ) + spawn(i,EXPLOSION2BOT); + spritesound(PIPEBOMB_EXPLODE,i); + for(x=0;x<8;x++) + RANDOMSCRAP; + } + + if(s->yrepeat) + { + s->yrepeat = 0; + goto BOLT; + } + + if(t[4] > 20) + { + if(s->owner != i || ud.respawn_items == 0) + { + KILLIT(i); + } + else + { + t[2] = respawnitemtime; + spawn(i,RESPAWNMARKERRED); + s->cstat = (short) 32768; + s->yrepeat = 9; + goto BOLT; + } + } + } + else if(s->picnum == HEAVYHBOMB && x < 788 && t[0] > 7 && s->xvel == 0) + if( cansee(s->x,s->y,s->z-(8<<8),s->sectnum,ps[p].posx,ps[p].posy,ps[p].posz,ps[p].cursectnum) ) + if(ps[p].ammo_amount[HANDBOMB_WEAPON] < max_ammo_amount[HANDBOMB_WEAPON] ) + { + if(ud.coop >= 1 && s->owner == i) + { + for(j=0;jpicnum) + goto BOLT; + + if(ps[p].weapreccnt < 255) + ps[p].weaprecs[ps[p].weapreccnt++] = s->picnum; + } + + addammo(HANDBOMB_WEAPON,&ps[p],1); + spritesound(DUKE_GET,ps[p].i); + + if( ps[p].gotweapon[HANDBOMB_WEAPON] == 0 || s->owner == ps[p].i ) + addweapon(&ps[p],HANDBOMB_WEAPON); + + if( sprite[s->owner].picnum != APLAYER ) + { + ps[p].pals[0] = 0; + ps[p].pals[1] = 32; + ps[p].pals[2] = 0; + ps[p].pals_time = 32; + } + + if( s->owner != i || ud.respawn_items == 0 ) + { + if(s->owner == i && ud.coop >= 1) + goto BOLT; + KILLIT(i); + } + else + { + t[2] = respawnitemtime; + spawn(i,RESPAWNMARKERRED); + s->cstat = (short) 32768; + } + } + + if(t[0] < 8) t[0]++; + goto BOLT; + + case REACTORBURNT: + case REACTOR2BURNT: + goto BOLT; + + case REACTOR: + case REACTOR2: + + if( t[4] == 1 ) + { + j = headspritesect[sect]; + while(j >= 0) + { + switch(sprite[j].picnum) + { + case SECTOREFFECTOR: + if(sprite[j].lotag == 1) + { + sprite[j].lotag = (short) 65535; + sprite[j].hitag = (short) 65535; + } + break; + case REACTOR: + sprite[j].picnum = REACTORBURNT; + break; + case REACTOR2: + sprite[j].picnum = REACTOR2BURNT; + break; + case REACTORSPARK: + case REACTOR2SPARK: + sprite[j].cstat = (short) 32768; + break; + } + j = nextspritesect[j]; + } + goto BOLT; + } + + if(t[1] >= 20) + { + t[4] = 1; + goto BOLT; + } + + p = findplayer(s,&x); + + t[2]++; + if( t[2] == 4 ) t[2]=0; + + if( x < 4096 ) + { + if( (TRAND&255) < 16 ) + { + if(Sound[DUKE_LONGTERM_PAIN].num < 1) + spritesound(DUKE_LONGTERM_PAIN,ps[p].i); + + spritesound(SHORT_CIRCUIT,i); + + sprite[ps[p].i].extra --; + ps[p].pals_time = 32; + ps[p].pals[0] = 32; + ps[p].pals[1] = 0; + ps[p].pals[2] = 0; + } + t[0] += 128; + if( t[3] == 0 ) + t[3] = 1; + } + else t[3] = 0; + + if( t[1] ) + { + t[1]++; + + t[4] = s->z; + s->z = sector[sect].floorz-(TRAND%(sector[sect].floorz-sector[sect].ceilingz)); + + switch( t[1] ) + { + case 3: + //Turn on all of those flashing sectoreffector. + hitradius( i, 4096, + impact_damage<<2, + impact_damage<<2, + impact_damage<<2, + impact_damage<<2 ); +/* + j = headspritestat[3]; + while(j>=0) + { + if( sprite[j].lotag == 3 ) + hittype[j].temp_data[4]=1; + else if(sprite[j].lotag == 12) + { + hittype[j].temp_data[4] = 1; + sprite[j].lotag = 3; + sprite[j].owner = 0; + hittype[j].temp_data[0] = s->shade; + } + j = nextspritestat[j]; + } +*/ + j = headspritestat[6]; + while(j >= 0) + { + if(sprite[j].picnum == MASTERSWITCH) + if(sprite[j].hitag == s->hitag) + if(sprite[j].yvel == 0) + sprite[j].yvel = 1; + j = nextspritestat[j]; + } + break; + + case 4: + case 7: + case 10: + case 15: + j = headspritesect[sect]; + while(j >= 0) + { + l = nextspritesect[j]; + + if(j != i) + { + deletesprite(j); + break; + } + j = l; + } + break; + } + for(x=0;x<16;x++) + RANDOMSCRAP; + + s->z = t[4]; + t[4] = 0; + + } + else + { + IFHIT + { + for(x=0;x<32;x++) + RANDOMSCRAP; + if(s->extra < 0) + t[1] = 1; + } + } + goto BOLT; + + case CAMERA1: + + if( t[0] == 0 ) + { + t[1]+=8; + if(camerashitable) + { + IFHIT + { + t[0] = 1; // static + s->cstat = (short)32768; + for(x=0;x<5;x++) RANDOMSCRAP; + goto BOLT; + } + } + + if(s->hitag > 0) + { + if(t[1]hitag) + s->ang+=8; + else if(t[1]<(s->hitag*3)) + s->ang-=8; + else if(t[1] < (s->hitag<<2) ) + s->ang+=8; + else + { + t[1]=8; + s->ang+=16; + } + } + } + goto BOLT; + } + + +// #ifndef VOLOMEONE + if( ud.multimode < 2 && badguy(s) ) + { + if( actor_tog == 1) + { + s->cstat = (short)32768; + goto BOLT; + } + else if(actor_tog == 2) s->cstat = 257; + } +// #endif + + p = findplayer(s,&x); + + execute(i,p,x); + + BOLT: + + i = nexti; + } + +} + + +void moveexplosions(void) // STATNUM 5 +{ + short i, j, k, nexti, sect, p; + long l, x, *t; + spritetype *s; + + i = headspritestat[5]; + while(i >= 0) + { + nexti = nextspritestat[i]; + + t = &hittype[i].temp_data[0]; + s = &sprite[i]; + sect = s->sectnum; + + if( sect < 0 || s->xrepeat == 0 ) KILLIT(i); + + hittype[i].bposx = s->x; + hittype[i].bposy = s->y; + hittype[i].bposz = s->z; + + switch(s->picnum) + { + case NEON1: + case NEON2: + case NEON3: + case NEON4: + case NEON5: + case NEON6: + + if( (global_random/(s->lotag+1)&31) > 4) s->shade = -127; + else s->shade = 127; + goto BOLT; + + case BLOODSPLAT1: + case BLOODSPLAT2: + case BLOODSPLAT3: + case BLOODSPLAT4: + + if( t[0] == 7*26 ) goto BOLT; + s->z += 16+(TRAND&15); + t[0]++; + if( (t[0]%9) == 0 ) s->yrepeat++; + goto BOLT; + + case NUKEBUTTON: + case NUKEBUTTON+1: + case NUKEBUTTON+2: + case NUKEBUTTON+3: + + if(t[0]) + { + t[0]++; + if(t[0] == 8) s->picnum = NUKEBUTTON+1; + else if(t[0] == 16) + { + s->picnum = NUKEBUTTON+2; + ps[sprite[s->owner].yvel].fist_incs = 1; + } + if( ps[sprite[s->owner].yvel].fist_incs == 26 ) + s->picnum = NUKEBUTTON+3; + } + goto BOLT; + + case FORCESPHERE: + + l = s->xrepeat; + if(t[1] > 0) + { + t[1]--; + if(t[1] == 0) + { + KILLIT(i); + } + } + if(hittype[s->owner].temp_data[1] == 0) + { + if(t[0] < 64) + { + t[0]++; + l += 3; + } + } + else + if(t[0] > 64) + { + t[0]--; + l -= 3; + } + + s->x = sprite[s->owner].x; + s->y = sprite[s->owner].y; + s->z = sprite[s->owner].z; + s->ang += hittype[s->owner].temp_data[0]; + + if(l > 64) l = 64; + else if(l < 1) l = 1; + + s->xrepeat = l; + s->yrepeat = l; + s->shade = (l>>1)-48; + + for(j=t[0];j > 0;j--) + ssp(i,CLIPMASK0); + goto BOLT; + case WATERSPLASH2: + + t[0]++; + if(t[0] == 1 ) + { + if(sector[sect].lotag != 1 && sector[sect].lotag != 2) + KILLIT(i); +/* else + { + l = getflorzofslope(sect,s->x,s->y)-s->z; + if( l > (16<<8) ) KILLIT(i); + } + else */ if(Sound[ITEM_SPLASH].num == 0) + spritesound(ITEM_SPLASH,i); + } + if(t[0] == 3) + { + t[0] = 0; + t[1]++; + } + if(t[1] == 5) + deletesprite(i); + goto BOLT; + + case FRAMEEFFECT1: + + if(s->owner >= 0) + { + t[0]++; + + if( t[0] > 7 ) + { + KILLIT(i); + } + else if( t[0] > 4 ) + s->cstat |= 512+2; + else if( t[0] > 2 ) + s->cstat |= 2; + s->xoffset = sprite[s->owner].xoffset; + s->yoffset = sprite[s->owner].yoffset; + } + goto BOLT; + case INNERJAW: + case INNERJAW+1: + + p = findplayer(s,&x); + if(x < 512) + { + ps[p].pals_time = 32; + ps[p].pals[0] = 32; + ps[p].pals[1] = 0; + ps[p].pals[2] = 0; + sprite[ps[p].i].extra -= 4; + } + + case FIRELASER: + if(s->extra != 999) + s->extra = 999; + else KILLIT(i); + break; + case TONGUE: + KILLIT(i); + case MONEY+1: + case MAIL+1: + case PAPER+1: + hittype[i].floorz = s->z = getflorzofslope(s->sectnum,s->x,s->y); + break; + case MONEY: + case MAIL: + case PAPER: + + s->xvel = (TRAND&7)+(sintable[T1&2047]>>9); + T1 += (TRAND&63); + if( (T1&2047) > 512 && (T1&2047) < 1596) + { + if(sector[sect].lotag == 2) + { + if(s->zvel < 64) + s->zvel += (gc>>5)+(TRAND&7); + } + else + if(s->zvel < 144) + s->zvel += (gc>>5)+(TRAND&7); + } + + ssp(i,CLIPMASK0); + + if( (TRAND&3) == 0 ) + setsprite(i,s->x,s->y,s->z); + + if(s->sectnum == -1) KILLIT(i); + l = getflorzofslope(s->sectnum,s->x,s->y); + + if( s->z > l ) + { + s->z = l; + + insertspriteq(i); + PN ++; + + j = headspritestat[5]; + while(j >= 0) + { + if(sprite[j].picnum == BLOODPOOL) + if(ldist(s,&sprite[j]) < 348) + { + s->pal = 2; + break; + } + j = nextspritestat[j]; + } + } + + break; + + case JIBS1: + case JIBS2: + case JIBS3: + case JIBS4: + case JIBS5: + case JIBS6: + case HEADJIB1: + case ARMJIB1: + case LEGJIB1: + case LIZMANHEAD1: + case LIZMANARM1: + case LIZMANLEG1: + case DUKETORSO: + case DUKEGUN: + case DUKELEG: + + if(s->xvel > 0) s->xvel--; + else s->xvel = 0; + + if( t[5] < 30*10 ) + t[5]++; + else { KILLIT(i); } + + + if(s->zvel > 1024 && s->zvel < 1280) + { + setsprite(i,s->x,s->y,s->z); + sect = s->sectnum; + } + + l = getflorzofslope(sect,s->x,s->y); + x = getceilzofslope(sect,s->x,s->y); + if(x == l || sect < 0 || sect >= MAXSECTORS) KILLIT(i); + + if( s->z < l-(2<<8) ) + { + if(t[1] < 2) t[1]++; + else if(sector[sect].lotag != 2) + { + t[1] = 0; + if( s->picnum == DUKELEG || s->picnum == DUKETORSO || s->picnum == DUKEGUN ) + { + if(t[0] > 6) t[0] = 0; + else t[0]++; + } + else + { + if(t[0] > 2) + t[0] = 0; + else t[0]++; + } + } + + if(s->zvel < 6144) + { + if(sector[sect].lotag == 2) + { + if(s->zvel < 1024) + s->zvel += 48; + else s->zvel = 1024; + } + else s->zvel += gc-50; + } + + s->x += (s->xvel*sintable[(s->ang+512)&2047])>>14; + s->y += (s->xvel*sintable[s->ang&2047])>>14; + s->z += s->zvel; + + } + else + { + if(t[2] == 0) + { + if( s->sectnum == -1) { KILLIT(i); } + if( (sector[s->sectnum].floorstat&2) ) { KILLIT(i); } + t[2]++; + } + l = getflorzofslope(s->sectnum,s->x,s->y); + + s->z = l-(2<<8); + s->xvel = 0; + + if(s->picnum == JIBS6) + { + t[1]++; + if( (t[1]&3) == 0 && t[0] < 7) + t[0]++; + if(t[1] > 20) KILLIT(i); + } + else { s->picnum = JIBS6; t[0] = 0; t[1] = 0; } + } + goto BOLT; + + case BLOODPOOL: + case PUKE: + + if(t[0] == 0) + { + t[0] = 1; + if(sector[sect].floorstat&2) { KILLIT(i); } + else insertspriteq(i); + } + + makeitfall(i); + + p = findplayer(s,&x); + + s->z = hittype[i].floorz-(FOURSLEIGHT); + + if(t[2] < 32) + { + t[2]++; + if(hittype[i].picnum == TIRE) + { + if(s->xrepeat < 64 && s->yrepeat < 64) + { + s->xrepeat += TRAND&3; + s->yrepeat += TRAND&3; + } + } + else + { + if(s->xrepeat < 32 && s->yrepeat < 32) + { + s->xrepeat += TRAND&3; + s->yrepeat += TRAND&3; + } + } + } + + if(x < 844 && s->xrepeat > 6 && s->yrepeat > 6) + { + if( s->pal == 0 && (TRAND&255) < 16 && s->picnum != PUKE) + { + if(ps[p].boot_amount > 0) + ps[p].boot_amount--; + else + { + if(Sound[DUKE_LONGTERM_PAIN].num < 1) + spritesound(DUKE_LONGTERM_PAIN,ps[p].i); + sprite[ps[p].i].extra --; + ps[p].pals_time = 32; + ps[p].pals[0] = 16; + ps[p].pals[1] = 0; + ps[p].pals[2] = 0; + } + } + + if(t[1] == 1) goto BOLT; + t[1] = 1; + + if(hittype[i].picnum == TIRE) + ps[p].footprintcount = 10; + else ps[p].footprintcount = 3; + + ps[p].footprintpal = s->pal; + ps[p].footprintshade = s->shade; + + if(t[2] == 32) + { + s->xrepeat -= 6; + s->yrepeat -= 6; + } + } + else t[1] = 0; + goto BOLT; + + case BURNING: + case BURNING2: + case FECES: + case WATERBUBBLE: + case SMALLSMOKE: + case EXPLOSION2: + case SHRINKEREXPLOSION: + case EXPLOSION2BOT: + case BLOOD: + case LASERSITE: + case FORCERIPPLE: + case TRANSPORTERSTAR: + case TRANSPORTERBEAM: + p = findplayer(s,&x); + execute(i,p,x); + goto BOLT; + + case SHELL: + case SHOTGUNSHELL: + + ssp(i,CLIPMASK0); + + if(sect < 0 || ( sector[sect].floorz+(24<<8) ) < s->z ) KILLIT(i); + + if(sector[sect].lotag == 2) + { + t[1]++; + if(t[1] > 8) + { + t[1] = 0; + t[0]++; + t[0] &= 3; + } + if(s->zvel < 128) s->zvel += (gc/13); // 8 + else s->zvel -= 64; + if(s->xvel > 0) + s->xvel -= 4; + else s->xvel = 0; + } + else + { + t[1]++; + if(t[1] > 3) + { + t[1] = 0; + t[0]++; + t[0] &= 3; + } + if(s->zvel < 512) s->zvel += (gc/3); // 52; + if(s->xvel > 0) + s->xvel --; + else KILLIT(i); + } + + goto BOLT; + + case GLASSPIECES: + case GLASSPIECES+1: + case GLASSPIECES+2: + + makeitfall(i); + + if(s->zvel > 4096) s->zvel = 4096; + if(sect < 0) KILLIT(i); + + if( s->z == hittype[i].floorz-(FOURSLEIGHT) && t[0] < 3) + { + s->zvel = -((3-t[0])<<8)-(TRAND&511); + if(sector[sect].lotag == 2) + s->zvel >>= 1; + s->xrepeat >>= 1; + s->yrepeat >>= 1; + if( rnd(96) ) + setsprite(i,s->x,s->y,s->z); + t[0]++;//Number of bounces + } + else if( t[0] == 3 ) KILLIT(i); + + if(s->xvel > 0) + { + s->xvel -= 2; + s->cstat = ((s->xvel&3)<<2); + } + else s->xvel = 0; + + ssp(i,CLIPMASK0); + + goto BOLT; + } + + IFWITHIN(SCRAP6,SCRAP5+3) + { + if(s->xvel > 0) + s->xvel--; + else s->xvel = 0; + + if(s->zvel > 1024 && s->zvel < 1280) + { + setsprite(i,s->x,s->y,s->z); + sect = s->sectnum; + } + + if( s->z < sector[sect].floorz-(2<<8) ) + { + if(t[1] < 1) t[1]++; + else + { + t[1] = 0; + + if(s->picnum < SCRAP6+8) + { + if(t[0] > 6) + t[0] = 0; + else t[0]++; + } + else + { + if(t[0] > 2) + t[0] = 0; + else t[0]++; + } + } + if(s->zvel < 4096) s->zvel += gc-50; + s->x += (s->xvel*sintable[(s->ang+512)&2047])>>14; + s->y += (s->xvel*sintable[s->ang&2047])>>14; + s->z += s->zvel; + } + else + { + if(s->picnum == SCRAP1 && s->yvel > 0) + { + j = spawn(i,s->yvel); + setsprite(j,s->x,s->y,s->z); + getglobalz(j); + sprite[j].hitag = sprite[j].lotag = 0; + } + KILLIT(i); + } + goto BOLT; + } + + BOLT: + i = nexti; + } +} + +void moveeffectors(void) //STATNUM 3 +{ + long q=0l, l=0l, m=0l, x=0l, st=0l, j=0l, *t=NULL; + short i=0, k=0, nexti=0, nextk=0, p=0, sh=0, nextj=0; + spritetype *s=NULL; + sectortype *sc=NULL; + walltype *wal=NULL; + + fricxv = fricyv = 0; + + i = headspritestat[3]; + while(i >= 0) + { + nexti = nextspritestat[i]; + s = &sprite[i]; + + sc = §or[s->sectnum]; + st = s->lotag; + sh = s->hitag; + + t = &hittype[i].temp_data[0]; + + switch(st) + { + case 0: + { + long zchange = 0; + + zchange = 0; + + j = s->owner; + + if( sprite[j].lotag == (short) 65535 ) + KILLIT(i); + + q = sc->extra>>3; + l = 0; + + if(sc->lotag == 30) + { + q >>= 2; + + if( sprite[i].extra == 1 ) + { + if(hittype[i].tempang < 256) + { + hittype[i].tempang += 4; + if(hittype[i].tempang >= 256) + callsound(s->sectnum,i); + if(s->clipdist) l = 1; + else l = -1; + } + else hittype[i].tempang = 256; + + if( sc->floorz > s->z ) //z's are touching + { + sc->floorz -= 512; + zchange = -512; + if( sc->floorz < s->z ) + sc->floorz = s->z; + } + + else if( sc->floorz < s->z ) //z's are touching + { + sc->floorz += 512; + zchange = 512; + if( sc->floorz > s->z ) + sc->floorz = s->z; + } + } + else if(sprite[i].extra == 3) + { + if(hittype[i].tempang > 0) + { + hittype[i].tempang -= 4; + if(hittype[i].tempang <= 0) + callsound(s->sectnum,i); + if( s->clipdist ) l = -1; + else l = 1; + } + else hittype[i].tempang = 0; + + if( sc->floorz > T4 ) //z's are touching + { + sc->floorz -= 512; + zchange = -512; + if( sc->floorz < T4 ) + sc->floorz = T4; + } + + else if( sc->floorz < T4 ) //z's are touching + { + sc->floorz += 512; + zchange = 512; + if( sc->floorz > T4 ) + sc->floorz = T4; + } + } + + s->ang += (l*q); + t[2] += (l*q); + } + else + { + if( hittype[j].temp_data[0] == 0 ) break; + if( hittype[j].temp_data[0] == 2 ) KILLIT(i); + + if( sprite[j].ang > 1024 ) + l = -1; + else l = 1; + if( t[3] == 0 ) + t[3] = ldist(s,&sprite[j]); + s->xvel = t[3]; + s->x = sprite[j].x; + s->y = sprite[j].y; + s->ang += (l*q); + t[2] += (l*q); + } + + if( l && (sc->floorstat&64) ) + { + for(p=connecthead;p>=0;p=connectpoint2[p]) + { + if( ps[p].cursectnum == s->sectnum && ps[p].on_ground == 1) + { + + ps[p].ang += (l*q); + ps[p].ang &= 2047; + + ps[p].posz += zchange; + + rotatepoint( sprite[j].x,sprite[j].y, + ps[p].posx,ps[p].posy,(q*l), + &m,&x); + + ps[p].bobposx += m-ps[p].posx; + ps[p].bobposy += x-ps[p].posy; + + ps[p].posx = m; + ps[p].posy = x; + + if(sprite[ps[p].i].extra <= 0) + { + sprite[ps[p].i].x = m; + sprite[ps[p].i].y = x; + } + } + } + + p = headspritesect[s->sectnum]; + while(p >= 0) + { + if(sprite[p].statnum != 3 && sprite[p].statnum != 4) + if( sprite[p].picnum != LASERLINE ) + { + if(sprite[p].picnum == APLAYER && sprite[p].owner >= 0) + { + p = nextspritesect[p]; + continue; + } + + sprite[p].ang += (l*q); + sprite[p].ang &= 2047; + + sprite[p].z += zchange; + + rotatepoint(sprite[j].x,sprite[j].y, + sprite[p].x,sprite[p].y,(q*l), + &sprite[p].x,&sprite[p].y); + + } + p = nextspritesect[p]; + } + + } + + ms(i); + } + + break; + case 1: //Nothing for now used as the pivot + if(s->owner == -1) //Init + { + s->owner = i; + + j = headspritestat[3]; + while(j >= 0) + { + if( sprite[j].lotag == 19 && sprite[j].hitag == sh ) + { + t[0] = 0; + break; + } + j = nextspritestat[j]; + } + } + + break; + case 6: + k = sc->extra; + + if(t[4] > 0) + { + t[4]--; + if( t[4] >= (k-(k>>3)) ) + s->xvel -= (k>>5); + if( t[4] > ((k>>1)-1) && t[4] < (k-(k>>3)) ) + s->xvel = 0; + if( t[4] < (k>>1) ) + s->xvel += (k>>5); + if( t[4] < ((k>>1)-(k>>3)) ) + { + t[4] = 0; + s->xvel = k; + } + } + else s->xvel = k; + + j = headspritestat[3]; + while( j >= 0) + { + if( (sprite[j].lotag == 14) && (sh == sprite[j].hitag) && (hittype[j].temp_data[0] == t[0]) ) + { + sprite[j].xvel = s->xvel; +// if( t[4] == 1 ) + { + if(hittype[j].temp_data[5] == 0) + hittype[j].temp_data[5] = dist(&sprite[j],s); + x = sgn( dist(&sprite[j],s)-hittype[j].temp_data[5] ); + if(sprite[j].extra) + x = -x; + s->xvel += x; + } + hittype[j].temp_data[4] = t[4]; + } + j = nextspritestat[j]; + } + x = 0; + + + case 14: + if(s->owner==-1) + s->owner = LocateTheLocator((short)t[3],(short)t[0]); + + if(s->owner == -1) + { + sprintf(tempbuf,"Could not find any locators for SE# 6 and 14 with a hitag of %ld.\n",t[3]); + gameexit(tempbuf); + } + + j = ldist(&sprite[s->owner],s); + + if( j < 1024L ) + { + if(st==6) + if(sprite[s->owner].hitag&1) + t[4]=sc->extra; //Slow it down + t[3]++; + s->owner = LocateTheLocator(t[3],t[0]); + if(s->owner==-1) + { + t[3]=0; + s->owner = LocateTheLocator(0,t[0]); + } + } + + if(s->xvel) + { + x = getangle(sprite[s->owner].x-s->x,sprite[s->owner].y-s->y); + q = getincangle(s->ang,x)>>3; + + t[2] += q; + s->ang += q; + + if(s->xvel == sc->extra ) + { + if( (sc->floorstat&1) == 0 && (sc->ceilingstat&1) == 0 ) + { + if( Sound[hittype[i].lastvx].num == 0 ) + spritesound(hittype[i].lastvx,i); + } + else if( ud.monsters_off == 0 && sc->floorpal == 0 && (sc->floorstat&1) && rnd(8) ) + { + p = findplayer(s,&x); + if(x < 20480) + { + j = s->ang; + s->ang = getangle(s->x-ps[p].posx,s->y-ps[p].posy); + shoot(i,RPG); + s->ang = j; + } + } + } + + if(s->xvel <= 64 && (sc->floorstat&1) == 0 && (sc->ceilingstat&1) == 0 ) + stopsound(hittype[i].lastvx); + + if( (sc->floorz-sc->ceilingz) < (108<<8) ) + { + if(ud.clipping == 0 && s->xvel >= 192) + for(p=connecthead;p>=0;p=connectpoint2[p]) + if(sprite[ps[p].i].extra > 0) + { + k = ps[p].cursectnum; + updatesector(ps[p].posx,ps[p].posy,&k); + if( ( k == -1 && ud.clipping == 0 ) || ( k == s->sectnum && ps[p].cursectnum != s->sectnum ) ) + { + ps[p].posx = s->x; + ps[p].posy = s->y; + ps[p].cursectnum = s->sectnum; + + setsprite(ps[p].i,s->x,s->y,s->z); + quickkill(&ps[p]); + } + } + } + + m = (s->xvel*sintable[(s->ang+512)&2047])>>14; + x = (s->xvel*sintable[s->ang&2047])>>14; + + for(p = connecthead;p >= 0;p=connectpoint2[p]) + if(sector[ps[p].cursectnum].lotag != 2) + { + if(po[p].os == s->sectnum) + { + po[p].ox += m; + po[p].oy += x; + } + + if(s->sectnum == sprite[ps[p].i].sectnum) + { + rotatepoint(s->x,s->y,ps[p].posx,ps[p].posy,q,&ps[p].posx,&ps[p].posy); + + ps[p].posx += m; + ps[p].posy += x; + + ps[p].bobposx += m; + ps[p].bobposy += x; + + ps[p].ang += q; + + if(numplayers > 1) + { + ps[p].oposx = ps[p].posx; + ps[p].oposy = ps[p].posy; + } + if( sprite[ps[p].i].extra <= 0 ) + { + sprite[ps[p].i].x = ps[p].posx; + sprite[ps[p].i].y = ps[p].posy; + } + } + } + j = headspritesect[s->sectnum]; + while(j >= 0) + { + if (sprite[j].statnum != 10 && sector[sprite[j].sectnum].lotag != 2 && sprite[j].picnum != SECTOREFFECTOR && sprite[j].picnum != LOCATORS ) + { + rotatepoint(s->x,s->y, + sprite[j].x,sprite[j].y,q, + &sprite[j].x,&sprite[j].y); + + sprite[j].x+= m; + sprite[j].y+= x; + + sprite[j].ang+=q; + + if(numplayers > 1) + { + hittype[j].bposx = sprite[j].x; + hittype[j].bposy = sprite[j].y; + } + } + j = nextspritesect[j]; + } + + ms(i); + setsprite(i,s->x,s->y,s->z); + + if( (sc->floorz-sc->ceilingz) < (108<<8) ) + { + if(ud.clipping == 0 && s->xvel >= 192) + for(p=connecthead;p>=0;p=connectpoint2[p]) + if(sprite[ps[p].i].extra > 0) + { + k = ps[p].cursectnum; + updatesector(ps[p].posx,ps[p].posy,&k); + if( ( k == -1 && ud.clipping == 0 ) || ( k == s->sectnum && ps[p].cursectnum != s->sectnum ) ) + { + ps[p].oposx = ps[p].posx = s->x; + ps[p].oposy = ps[p].posy = s->y; + ps[p].cursectnum = s->sectnum; + + setsprite(ps[p].i,s->x,s->y,s->z); + quickkill(&ps[p]); + } + } + + j = headspritesect[sprite[OW].sectnum]; + while(j >= 0) + { + l = nextspritesect[j]; + if (sprite[j].statnum == 1 && badguy(&sprite[j]) && sprite[j].picnum != SECTOREFFECTOR && sprite[j].picnum != LOCATORS ) + { + k = sprite[j].sectnum; + updatesector(sprite[j].x,sprite[j].y,&k); + if( sprite[j].extra >= 0 && k == s->sectnum ) + { + gutsdir(&sprite[j],JIBS6,72,myconnectindex); + spritesound(SQUISHED,i); + deletesprite(j); + } + } + j = l; + } + } + } + + break; + + case 30: + if(s->owner == -1) + { + t[3] = !t[3]; + s->owner = LocateTheLocator(t[3],t[0]); + } + else + { + + if(t[4] == 1) // Starting to go + { + if( ldist( &sprite[s->owner],s ) < (2048-128) ) + t[4] = 2; + else + { + if(s->xvel == 0) + operateactivators(s->hitag+(!t[3]),-1); + if(s->xvel < 256) + s->xvel += 16; + } + } + if(t[4] == 2) + { + l = FindDistance2D(sprite[s->owner].x-s->x,sprite[s->owner].y-s->y); + + if(l <= 128) + s->xvel = 0; + + if( s->xvel > 0 ) + s->xvel -= 16; + else + { + s->xvel = 0; + operateactivators(s->hitag+(short)t[3],-1); + s->owner = -1; + s->ang += 1024; + t[4] = 0; + operateforcefields(i,s->hitag); + + j = headspritesect[s->sectnum]; + while(j >= 0) + { + if(sprite[j].picnum != SECTOREFFECTOR && sprite[j].picnum != LOCATORS ) + { + hittype[j].bposx = sprite[j].x; + hittype[j].bposy = sprite[j].y; + } + j = nextspritesect[j]; + } + + } + } + } + + if(s->xvel) + { + l = (s->xvel*sintable[(s->ang+512)&2047])>>14; + x = (s->xvel*sintable[s->ang&2047])>>14; + + if( (sc->floorz-sc->ceilingz) < (108<<8) ) + if(ud.clipping == 0) + for(p=connecthead;p>=0;p=connectpoint2[p]) + if(sprite[ps[p].i].extra > 0) + { + k = ps[p].cursectnum; + updatesector(ps[p].posx,ps[p].posy,&k); + if( ( k == -1 && ud.clipping == 0 ) || ( k == s->sectnum && ps[p].cursectnum != s->sectnum ) ) + { + ps[p].posx = s->x; + ps[p].posy = s->y; + ps[p].cursectnum = s->sectnum; + + setsprite(ps[p].i,s->x,s->y,s->z); + quickkill(&ps[p]); + } + } + + for(p = connecthead;p >= 0;p = connectpoint2[p]) + { + if( sprite[ps[p].i].sectnum == s->sectnum ) + { + ps[p].posx += l; + ps[p].posy += x; + + if(numplayers > 1) + { + ps[p].oposx = ps[p].posx; + ps[p].oposy = ps[p].posy; + } + + ps[p].bobposx += l; + ps[p].bobposy += x; + } + + if( po[p].os == s->sectnum ) + { + po[p].ox += l; + po[p].oy += x; + } + } + + j = headspritesect[s->sectnum]; + while(j >= 0) + { + if(sprite[j].picnum != SECTOREFFECTOR && sprite[j].picnum != LOCATORS ) + { + if(numplayers < 2) + { + hittype[j].bposx = sprite[j].x; + hittype[j].bposy = sprite[j].y; + } + + sprite[j].x += l; + sprite[j].y += x; + + if(numplayers > 1) + { + hittype[j].bposx = sprite[j].x; + hittype[j].bposy = sprite[j].y; + } + } + j = nextspritesect[j]; + } + + ms(i); + setsprite(i,s->x,s->y,s->z); + + if( (sc->floorz-sc->ceilingz) < (108<<8) ) + { + if(ud.clipping == 0) + for(p=connecthead;p>=0;p=connectpoint2[p]) + if(sprite[ps[p].i].extra > 0) + { + k = ps[p].cursectnum; + updatesector(ps[p].posx,ps[p].posy,&k); + if( ( k == -1 && ud.clipping == 0 ) || ( k == s->sectnum && ps[p].cursectnum != s->sectnum ) ) + { + ps[p].posx = s->x; + ps[p].posy = s->y; + + ps[p].oposx = ps[p].posx; + ps[p].oposy = ps[p].posy; + + ps[p].cursectnum = s->sectnum; + + setsprite(ps[p].i,s->x,s->y,s->z); + quickkill(&ps[p]); + } + } + + j = headspritesect[sprite[OW].sectnum]; + while(j >= 0) + { + l = nextspritesect[j]; + if (sprite[j].statnum == 1 && badguy(&sprite[j]) && sprite[j].picnum != SECTOREFFECTOR && sprite[j].picnum != LOCATORS ) + { + // if(sprite[j].sectnum != s->sectnum) + { + k = sprite[j].sectnum; + updatesector(sprite[j].x,sprite[j].y,&k); + if( sprite[j].extra >= 0 && k == s->sectnum ) + { + gutsdir(&sprite[j],JIBS6,24,myconnectindex); + spritesound(SQUISHED,j); + deletesprite(j); + } + } + + } + j = l; + } + } + } + + break; + + + case 2://Quakes + if(t[4] > 0 && t[0] == 0 ) + { + if( t[4] < sh ) + t[4]++; + else t[0] = 1; + } + + if(t[0] > 0) + { + t[0]++; + + s->xvel = 3; + + if(t[0] > 96) + { + t[0] = -1; //Stop the quake + t[4] = -1; + KILLIT(i); + } + else + { + if( (t[0]&31) == 8 ) + { + earthquaketime = 48; + spritesound(EARTHQUAKE,ps[screenpeek].i); + } + + if( klabs( sc->floorheinum-t[5] ) < 8 ) + sc->floorheinum = t[5]; + else sc->floorheinum += ( sgn(t[5]-sc->floorheinum)<<4 ); + } + + m = (s->xvel*sintable[(s->ang+512)&2047])>>14; + x = (s->xvel*sintable[s->ang&2047])>>14; + + + for(p=connecthead;p>=0;p=connectpoint2[p]) + if(ps[p].cursectnum == s->sectnum && ps[p].on_ground) + { + ps[p].posx += m; + ps[p].posy += x; + + ps[p].bobposx += m; + ps[p].bobposy += x; + } + + j = headspritesect[s->sectnum]; + while(j >= 0) + { + nextj = nextspritesect[j]; + + if (sprite[j].picnum != SECTOREFFECTOR) + { + sprite[j].x+=m; + sprite[j].y+=x; + setsprite(j,sprite[j].x,sprite[j].y,sprite[j].z); + } + j = nextj; + } + ms(i); + setsprite(i,s->x,s->y,s->z); + } + break; + + //Flashing sector lights after reactor EXPLOSION2 + + case 3: + + if( t[4] == 0 ) break; + p = findplayer(s,&x); + + // if(t[5] > 0) { t[5]--; break; } + + if( (global_random/(sh+1)&31) < 4 && !t[2]) + { + // t[5] = 4+(global_random&7); + sc->ceilingpal = s->owner>>8; + sc->floorpal = s->owner&0xff; + t[0] = s->shade + (global_random&15); + } + else + { + // t[5] = 4+(global_random&3); + sc->ceilingpal = s->pal; + sc->floorpal = s->pal; + t[0] = t[3]; + } + + sc->ceilingshade = t[0]; + sc->floorshade = t[0]; + + wal = &wall[sc->wallptr]; + + for(x=sc->wallnum;x > 0;x--,wal++) + { + if( wal->hitag != 1 ) + { + wal->shade = t[0]; + if((wal->cstat&2) && wal->nextwall >= 0) + { + wall[wal->nextwall].shade = wal->shade; + } + } + } + + break; + + case 4: + + if((global_random/(sh+1)&31) < 4 ) + { + t[1] = s->shade + (global_random&15);//Got really bright + t[0] = s->shade + (global_random&15); + sc->ceilingpal = s->owner>>8; + sc->floorpal = s->owner&0xff; + j = 1; + } + else + { + t[1] = t[2]; + t[0] = t[3]; + + sc->ceilingpal = s->pal; + sc->floorpal = s->pal; + + j = 0; + } + + sc->floorshade = t[1]; + sc->ceilingshade = t[1]; + + wal = &wall[sc->wallptr]; + + for(x=sc->wallnum;x > 0; x--,wal++) + { + if(j) wal->pal = (s->owner&0xff); + else wal->pal = s->pal; + + if( wal->hitag != 1 ) + { + wal->shade = t[0]; + if((wal->cstat&2) && wal->nextwall >= 0) + wall[wal->nextwall].shade = wal->shade; + } + } + + j = headspritesect[SECT]; + while(j >= 0) + { + if(sprite[j].cstat&16) + { + if (sc->ceilingstat&1) + sprite[j].shade = sc->ceilingshade; + else sprite[j].shade = sc->floorshade; + } + + j = nextspritesect[j]; + } + + if(t[4]) KILLIT(i); + + break; + + //BOSS + case 5: + p = findplayer(s,&x); + if(x < 8192) + { + j = s->ang; + s->ang = getangle(s->x-ps[p].posx,s->y-ps[p].posy); + shoot(i,FIRELASER); + s->ang = j; + } + + if(s->owner==-1) //Start search + { + t[4]=0; + l = 0x7fffffff; + while(1) //Find the shortest dist + { + s->owner = LocateTheLocator((short)t[4],-1); //t[0] hold sectnum + + if(s->owner==-1) break; + + m = ldist(&sprite[ps[p].i],&sprite[s->owner]); + + if(l > m) + { + q = s->owner; + l = m; + } + + t[4]++; + } + + s->owner = q; + s->zvel = ksgn(sprite[q].z-s->z)<<4; + } + + if(ldist(&sprite[s->owner],s) < 1024) + { + short ta; + ta = s->ang; + s->ang = getangle(ps[p].posx-s->x,ps[p].posy-s->y); + s->ang = ta; + s->owner = -1; + goto BOLT; + + } + else s->xvel=256; + + x = getangle(sprite[s->owner].x-s->x,sprite[s->owner].y-s->y); + q = getincangle(s->ang,x)>>3; + s->ang += q; + + if(rnd(32)) + { + t[2]+=q; + sc->ceilingshade = 127; + } + else + { + t[2] += + getincangle(t[2]+512,getangle(ps[p].posx-s->x,ps[p].posy-s->y))>>2; + sc->ceilingshade = 0; + } + IFHIT + { + t[3]++; + if(t[3] == 5) + { + s->zvel += 1024; + FTA(7,&ps[myconnectindex]); + } + } + + s->z += s->zvel; + sc->ceilingz += s->zvel; + sector[t[0]].ceilingz += s->zvel; + ms(i); + setsprite(i,s->x,s->y,s->z); + break; + + + case 8: + case 9: + + // work only if its moving + + j = -1; + + if(hittype[i].temp_data[4]) + { + hittype[i].temp_data[4]++; + if( hittype[i].temp_data[4] > 8 ) KILLIT(i); + j = 1; + } + else j = getanimationgoal(&sc->ceilingz); + + if( j >= 0 ) + { + short sn; + + if( (sc->lotag&0x8000) || hittype[i].temp_data[4] ) + x = -t[3]; + else + x = t[3]; + + if ( st == 9 ) x = -x; + + j = headspritestat[3]; + while(j >= 0) + { + if( ((sprite[j].lotag) == st ) && (sprite[j].hitag) == sh ) + { + sn = sprite[j].sectnum; + m = sprite[j].shade; + + wal = &wall[sector[sn].wallptr]; + + for(l=sector[sn].wallnum;l>0;l--,wal++) + { + if( wal->hitag != 1 ) + { + wal->shade+=x; + + if(wal->shade < m) + wal->shade = m; + else if(wal->shade > hittype[j].temp_data[2]) + wal->shade = hittype[j].temp_data[2]; + + if(wal->nextwall >= 0) + if(wall[wal->nextwall].hitag != 1) + wall[wal->nextwall].shade = wal->shade; + } + } + + sector[sn].floorshade += x; + sector[sn].ceilingshade += x; + + if(sector[sn].floorshade < m) + sector[sn].floorshade = m; + else if(sector[sn].floorshade > hittype[j].temp_data[0]) + sector[sn].floorshade = hittype[j].temp_data[0]; + + if(sector[sn].ceilingshade < m) + sector[sn].ceilingshade = m; + else if(sector[sn].ceilingshade > hittype[j].temp_data[1]) + sector[sn].ceilingshade = hittype[j].temp_data[1]; + + } + j = nextspritestat[j]; + } + } + break; + case 10: + + if( (sc->lotag&0xff) == 27 || ( sc->floorz > sc->ceilingz && (sc->lotag&0xff) != 23 ) || sc->lotag == (short) 32791 ) + { + j = 1; + + if( (sc->lotag&0xff) != 27) + for(p=connecthead;p>=0;p=connectpoint2[p]) + if( sc->lotag != 30 && sc->lotag != 31 && sc->lotag != 0 ) + if(s->sectnum == sprite[ps[p].i].sectnum) + j = 0; + + if(j == 1) + { + if(t[0] > sh ) + switch(sector[s->sectnum].lotag) + { + case 20: + case 21: + case 22: + case 26: + if( getanimationgoal(§or[s->sectnum].ceilingz) >= 0 ) + break; + default: + activatebysector(s->sectnum,i); + t[0] = 0; + break; + } + else t[0]++; + } + } + else t[0]=0; + break; + case 11: //Swingdoor + + if( t[5] > 0) + { + t[5]--; + break; + } + + if( t[4] ) + { + short startwall,endwall; + + startwall = sc->wallptr; + endwall = startwall+sc->wallnum; + + for(j=startwall;j= 0) + { + if( sprite[k].extra > 0 && badguy(&sprite[k]) && clipinsidebox(sprite[k].x,sprite[k].y,j,256L) == 1 ) + goto BOLT; + k = nextspritestat[k]; + } + + k = headspritestat[10]; + while(k >= 0) + { + if( sprite[k].owner >= 0 && clipinsidebox(sprite[k].x,sprite[k].y,j,144L) == 1 ) + { + t[5] = 8; // Delay + k = (SP>>3)*t[3]; + t[2]-=k; + t[4]-=k; + ms(i); + setsprite(i,s->x,s->y,s->z); + goto BOLT; + } + k = nextspritestat[k]; + } + } + + k = (SP>>3)*t[3]; + t[2]+=k; + t[4]+=k; + ms(i); + setsprite(i,s->x,s->y,s->z); + + if(t[4] <= -511 || t[4] >= 512) + { + t[4] = 0; + t[2] &= 0xffffff00; + ms(i); + setsprite(i,s->x,s->y,s->z); + break; + } + } + break; + case 12: + if( t[0] == 3 || t[3] == 1 ) //Lights going off + { + sc->floorpal = 0; + sc->ceilingpal = 0; + + wal = &wall[sc->wallptr]; + for(j = sc->wallnum;j > 0; j--, wal++) + if(wal->hitag != 1) + { + wal->shade = t[1]; + wal->pal = 0; + } + + sc->floorshade = t[1]; + sc->ceilingshade = t[2]; + t[0]=0; + + j = headspritesect[SECT]; + while(j >= 0) + { + if(sprite[j].cstat&16) + { + if (sc->ceilingstat&1) + sprite[j].shade = sc->ceilingshade; + else sprite[j].shade = sc->floorshade; + } + j = nextspritesect[j]; + + } + + if(t[3] == 1) KILLIT(i); + } + if( t[0] == 1 ) //Lights flickering on + { + if( sc->floorshade > s->shade ) + { + sc->floorpal = s->pal; + sc->ceilingpal = s->pal; + + sc->floorshade -= 2; + sc->ceilingshade -= 2; + + wal = &wall[sc->wallptr]; + for(j=sc->wallnum;j>0;j--,wal++) + if(wal->hitag != 1) + { + wal->pal = s->pal; + wal->shade -= 2; + } + } + else t[0] = 2; + + j = headspritesect[SECT]; + while(j >= 0) + { + if(sprite[j].cstat&16) + { + if (sc->ceilingstat&1) + sprite[j].shade = sc->ceilingshade; + else sprite[j].shade = sc->floorshade; + } + j = nextspritesect[j]; + } + } + break; + + + case 13: + if( t[2] ) + { + j = (SP<<5)|1; + + if( s->ang == 512 ) + { + if( s->owner ) + { + if( klabs(t[0]-sc->ceilingz) >= j ) + sc->ceilingz += sgn(t[0]-sc->ceilingz)*j; + else sc->ceilingz = t[0]; + } + else + { + if( klabs(t[1]-sc->floorz) >= j ) + sc->floorz += sgn(t[1]-sc->floorz)*j; + else sc->floorz = t[1]; + } + } + else + { + if( klabs(t[1]-sc->floorz) >= j ) + sc->floorz += sgn(t[1]-sc->floorz)*j; + else sc->floorz = t[1]; + if( klabs(t[0]-sc->ceilingz) >= j ) + sc->ceilingz += sgn(t[0]-sc->ceilingz)*j; + sc->ceilingz = t[0]; + } + + if( t[3] == 1 ) + { + //Change the shades + + t[3]++; + sc->ceilingstat ^= 1; + + if(s->ang == 512) + { + wal = &wall[sc->wallptr]; + for(j=sc->wallnum;j>0;j--,wal++) + wal->shade = s->shade; + + sc->floorshade = s->shade; + + if(ps[0].one_parallax_sectnum >= 0) + { + sc->ceilingpicnum = + sector[ps[0].one_parallax_sectnum].ceilingpicnum; + sc->ceilingshade = + sector[ps[0].one_parallax_sectnum].ceilingshade; + } + } + } + t[2]++; + if(t[2] > 256) + KILLIT(i); + } + + + if( t[2] == 4 && s->ang != 512) + for(x=0;x<7;x++) RANDOMSCRAP; + break; + + + case 15: + + if(t[4]) + { + s->xvel = 16; + + if(t[4] == 1) //Opening + { + if( t[3] >= (SP>>3) ) + { + t[4] = 0; //Turn off the sliders + callsound(s->sectnum,i); + break; + } + t[3]++; + } + else if(t[4] == 2) + { + if(t[3]<1) + { + t[4] = 0; + callsound(s->sectnum,i); + break; + } + t[3]--; + } + + ms(i); + setsprite(i,s->x,s->y,s->z); + } + break; + + case 16: //Reactor + + t[2]+=32; + if(sc->floorzceilingz) s->shade=0; + + else if( sc->ceilingz < t[3] ) + { + + //The following code check to see if + //there is any other sprites in the sector. + //If there isn't, then kill this sectoreffector + //itself..... + + j = headspritesect[s->sectnum]; + while(j >= 0) + { + if(sprite[j].picnum == REACTOR || sprite[j].picnum == REACTOR2) + break; + j = nextspritesect[j]; + } + if(j == -1) { KILLIT(i); } + else s->shade=1; + } + + if(s->shade) sc->ceilingz+=1024; + else sc->ceilingz-=512; + + ms(i); + setsprite(i,s->x,s->y,s->z); + + break; + + case 17: + + q = t[0]*(SP<<2); + + sc->ceilingz += q; + sc->floorz += q; + + j = headspritesect[s->sectnum]; + while(j >= 0) + { + if(sprite[j].statnum == 10 && sprite[j].owner >= 0) + { + p = sprite[j].yvel; + if(numplayers < 2) + ps[p].oposz = ps[p].posz; + ps[p].posz += q; + ps[p].truefz += q; + ps[p].truecz += q; + if(numplayers > 1) + ps[p].oposz = ps[p].posz; + } + if( sprite[j].statnum != 3 ) + { + hittype[j].bposz = sprite[j].z; + sprite[j].z += q; + } + + hittype[j].floorz = sc->floorz; + hittype[j].ceilingz = sc->ceilingz; + + j = nextspritesect[j]; + } + + if( t[0] ) if(t[0]) //If in motion + { + if( klabs(sc->floorz-t[2]) <= SP) + { + activatewarpelevators(i,0); + break; + } + + if(t[0]==-1) + { + if( sc->floorz > t[3] ) + break; + } + else if( sc->ceilingz < t[4] ) break; + + if( t[1] == 0 ) break; + t[1] = 0; + + j = headspritestat[3]; + while(j >= 0) + { + if( i != j && (sprite[j].lotag) == 17) + if( (sc->hitag-t[0]) == + (sector[sprite[j].sectnum].hitag) + && sh == (sprite[j].hitag)) + break; + j = nextspritestat[j]; + } + + if(j == -1) break; + + k = headspritesect[s->sectnum]; + while(k >= 0) + { + nextk = nextspritesect[k]; + + if(sprite[k].statnum == 10 && sprite[k].owner >= 0) + { + p = sprite[k].yvel; + + ps[p].posx += sprite[j].x-s->x; + ps[p].posy += sprite[j].y-s->y; + ps[p].posz = sector[sprite[j].sectnum].floorz-(sc->floorz-ps[p].posz); + + hittype[k].floorz = sector[sprite[j].sectnum].floorz; + hittype[k].ceilingz = sector[sprite[j].sectnum].ceilingz; + + ps[p].bobposx = ps[p].oposx = ps[p].posx; + ps[p].bobposy = ps[p].oposy = ps[p].posy; + ps[p].oposz = ps[p].posz; + + ps[p].truefz = hittype[k].floorz; + ps[p].truecz = hittype[k].ceilingz; + ps[p].bobcounter = 0; + + changespritesect(k,sprite[j].sectnum); + ps[p].cursectnum = sprite[j].sectnum; + } + else if( sprite[k].statnum != 3 ) + { + sprite[k].x += + sprite[j].x-s->x; + sprite[k].y += + sprite[j].y-s->y; + sprite[k].z = sector[sprite[j].sectnum].floorz- + (sc->floorz-sprite[k].z); + + hittype[k].bposx = sprite[k].x; + hittype[k].bposy = sprite[k].y; + hittype[k].bposz = sprite[k].z; + + changespritesect(k,sprite[j].sectnum); + setsprite(k,sprite[k].x,sprite[k].y,sprite[k].z); + + hittype[k].floorz = sector[sprite[j].sectnum].floorz; + hittype[k].ceilingz = sector[sprite[j].sectnum].ceilingz; + + } + k = nextk; + } + } + break; + + case 18: + if(t[0]) + { + if(s->pal) + { + if(s->ang == 512) + { + sc->ceilingz -= sc->extra; + if(sc->ceilingz <= t[1]) + { + sc->ceilingz = t[1]; + KILLIT(i); + } + } + else + { + sc->floorz += sc->extra; + j = headspritesect[s->sectnum]; + while(j >= 0) + { + if(sprite[j].picnum == APLAYER && sprite[j].owner >= 0) + if( ps[sprite[j].yvel].on_ground == 1 ) + ps[sprite[j].yvel].posz += sc->extra; + if( sprite[j].zvel == 0 && sprite[j].statnum != 3 && sprite[j].statnum != 4) + { + hittype[j].bposz = sprite[j].z += sc->extra; + hittype[j].floorz = sc->floorz; + } + j = nextspritesect[j]; + } + if(sc->floorz >= t[1]) + { + sc->floorz = t[1]; + KILLIT(i); + } + } + } + else + { + if(s->ang == 512) + { + sc->ceilingz += sc->extra; + if(sc->ceilingz >= s->z) + { + sc->ceilingz = s->z; + KILLIT(i); + } + } + else + { + sc->floorz -= sc->extra; + j = headspritesect[s->sectnum]; + while(j >= 0) + { + if(sprite[j].picnum == APLAYER && sprite[j].owner >= 0) + if( ps[sprite[j].yvel].on_ground == 1 ) + ps[sprite[j].yvel].posz -= sc->extra; + if( sprite[j].zvel == 0 && sprite[j].statnum != 3 && sprite[j].statnum != 4) + { + hittype[j].bposz = sprite[j].z -= sc->extra; + hittype[j].floorz = sc->floorz; + } + j = nextspritesect[j]; + } + if(sc->floorz <= s->z) + { + sc->floorz = s->z; + KILLIT(i); + } + } + } + + t[2]++; + if(t[2] >= s->hitag) + { + t[2] = 0; + t[0] = 0; + } + } + break; + + case 19: //Battlestar galactia shields + + if(t[0]) + { + if(t[0] == 1) + { + t[0]++; + x = sc->wallptr; + q = x+sc->wallnum; + for(j=x;j= 0) + { + wall[wall[j].nextwall].overpicnum = 0; + wall[wall[j].nextwall].cstat &= (128+32+8+4+2); + } + } + } + + if(sc->ceilingz < sc->floorz) + sc->ceilingz += SP; + else + { + sc->ceilingz = sc->floorz; + + j = headspritestat[3]; + while(j >= 0) + { + if(sprite[j].lotag == 0 && sprite[j].hitag==sh) + { + q = sprite[sprite[j].owner].sectnum; + sector[sprite[j].sectnum].floorpal = sector[sprite[j].sectnum].ceilingpal = + sector[q].floorpal; + sector[sprite[j].sectnum].floorshade = sector[sprite[j].sectnum].ceilingshade = + sector[q].floorshade; + + hittype[sprite[j].owner].temp_data[0] = 2; + } + j = nextspritestat[j]; + } + KILLIT(i); + } + } + else //Not hit yet + { + IFHITSECT + { + FTA(8,&ps[myconnectindex]); + + l = headspritestat[3]; + while(l >= 0) + { + x = sprite[l].lotag&0x7fff; + switch( x ) + { + case 0: + if(sprite[l].hitag == sh) + { + q = sprite[l].sectnum; + sector[q].floorshade = + sector[q].ceilingshade = + sprite[sprite[l].owner].shade; + sector[q].floorpal = + sector[q].ceilingpal = + sprite[sprite[l].owner].pal; + } + break; + + case 1: + case 12: +// case 18: + case 19: + + if( sh == sprite[l].hitag ) + if( hittype[l].temp_data[0] == 0 ) + { + hittype[l].temp_data[0] = 1; //Shut them all on + sprite[l].owner = i; + } + + break; + } + l = nextspritestat[l]; + } + } + } + + break; + + case 20: //Extend-o-bridge + + if( t[0] == 0 ) break; + if( t[0] == 1 ) s->xvel = 8; + else s->xvel = -8; + + if( s->xvel ) //Moving + { + x = (s->xvel*sintable[(s->ang+512)&2047])>>14; + l = (s->xvel*sintable[s->ang&2047])>>14; + + t[3] += s->xvel; + + s->x += x; + s->y += l; + + if( t[3] <= 0 || (t[3]>>6) >= (SP>>6) ) + { + s->x -= x; + s->y -= l; + t[0] = 0; + callsound(s->sectnum,i); + break; + } + + j = headspritesect[s->sectnum]; + while(j >= 0) + { + nextj = nextspritesect[j]; + + if( sprite[j].statnum != 3 && sprite[j].zvel == 0) + { + sprite[j].x += x; + sprite[j].y += l; + setsprite(j,sprite[j].x,sprite[j].y,sprite[j].z); + if( sector[sprite[j].sectnum].floorstat&2 ) + if(sprite[j].statnum == 2) + makeitfall(j); + } + j = nextj; + } + + dragpoint((short)t[1],wall[t[1]].x+x,wall[t[1]].y+l); + dragpoint((short)t[2],wall[t[2]].x+x,wall[t[2]].y+l); + + for(p=connecthead;p>=0;p=connectpoint2[p]) + if(ps[p].cursectnum == s->sectnum && ps[p].on_ground) + { + ps[p].posx += x; + ps[p].posy += l; + + ps[p].oposx = ps[p].posx; + ps[p].oposy = ps[p].posy; + + setsprite(ps[p].i,ps[p].posx,ps[p].posy,ps[p].posz+PHEIGHT); + } + + sc->floorxpanning-=x>>3; + sc->floorypanning-=l>>3; + + sc->ceilingxpanning-=x>>3; + sc->ceilingypanning-=l>>3; + } + + break; + + case 21: // Cascading effect + + if( t[0] == 0 ) break; + + if( s->ang == 1536 ) + l = (long) &sc->ceilingz; + else + l = (long) &sc->floorz; + + if( t[0] == 1 ) //Decide if the s->sectnum should go up or down + { + s->zvel = ksgn(s->z-*(long *)l) * (SP<<4); + t[0]++; + } + + if( sc->extra == 0 ) + { + *(long *)l += s->zvel; + + if(klabs(*(long *)l-s->z) < 1024) + { + *(long *)l = s->z; + KILLIT(i); //All done + } + } + else sc->extra--; + break; + + case 22: + + if( t[1] ) + { + if(getanimationgoal(§or[t[0]].ceilingz) >= 0) + sc->ceilingz += sc->extra*9; + else t[1] = 0; + } + break; + + case 24: + case 34: + + if(t[4]) break; + + x = (SP*sintable[(s->ang+512)&2047])>>18; + l = (SP*sintable[s->ang&2047])>>18; + + k = 0; + + j = headspritesect[s->sectnum]; + while(j >= 0) + { + nextj = nextspritesect[j]; + if(sprite[j].zvel >= 0) + switch(sprite[j].statnum) + { + case 5: + switch(sprite[j].picnum) + { + case BLOODPOOL: + case PUKE: + case FOOTPRINTS: + case FOOTPRINTS2: + case FOOTPRINTS3: + case FOOTPRINTS4: + case BULLETHOLE: + case BLOODSPLAT1: + case BLOODSPLAT2: + case BLOODSPLAT3: + case BLOODSPLAT4: + sprite[j].xrepeat = sprite[j].yrepeat = 0; + j = nextj; + continue; + case LASERLINE: + j = nextj; + continue; + } + case 6: + if(sprite[j].picnum == TRIPBOMB) break; + case 1: + case 0: + if( + sprite[j].picnum == BOLT1 || + sprite[j].picnum == BOLT1+1 || + sprite[j].picnum == BOLT1+2 || + sprite[j].picnum == BOLT1+3 || + sprite[j].picnum == SIDEBOLT1 || + sprite[j].picnum == SIDEBOLT1+1 || + sprite[j].picnum == SIDEBOLT1+2 || + sprite[j].picnum == SIDEBOLT1+3 || + wallswitchcheck(j) + ) + break; + + if( !(sprite[j].picnum >= CRANE && sprite[j].picnum <= (CRANE+3))) + { + if( sprite[j].z > (hittype[j].floorz-(16<<8)) ) + { + hittype[j].bposx = sprite[j].x; + hittype[j].bposy = sprite[j].y; + + sprite[j].x += x>>2; + sprite[j].y += l>>2; + + setsprite(j,sprite[j].x,sprite[j].y,sprite[j].z); + + if( sector[sprite[j].sectnum].floorstat&2 ) + if(sprite[j].statnum == 2) + makeitfall(j); + } + } + break; + } + j = nextj; + } + + p = myconnectindex; + if(ps[p].cursectnum == s->sectnum && ps[p].on_ground) + if( klabs(ps[p].posz-ps[p].truefz) < PHEIGHT+(9<<8) ) + { + fricxv += x<<3; + fricyv += l<<3; + } + + sc->floorxpanning += SP>>7; + + break; + + case 35: + if(sc->ceilingz > s->z) + for(j = 0;j < 8;j++) + { + s->ang += TRAND&511; + k = spawn(i,SMALLSMOKE); + sprite[k].xvel = 96+(TRAND&127); + ssp(k,CLIPMASK0); + setsprite(k,sprite[k].x,sprite[k].y,sprite[k].z); + if( rnd(16) ) + spawn(i,EXPLOSION2); + } + + switch(t[0]) + { + case 0: + sc->ceilingz += s->yvel; + if(sc->ceilingz > sc->floorz) + sc->floorz = sc->ceilingz; + if(sc->ceilingz > s->z+(32<<8)) + t[0]++; + break; + case 1: + sc->ceilingz-=(s->yvel<<2); + if(sc->ceilingz < t[4]) + { + sc->ceilingz = t[4]; + t[0] = 0; + } + break; + } + break; + + case 25: //PISTONS + + if( t[4] == 0 ) break; + + if(sc->floorz <= sc->ceilingz) + s->shade = 0; + else if( sc->ceilingz <= t[3]) + s->shade = 1; + + if(s->shade) + { + sc->ceilingz += SP<<4; + if(sc->ceilingz > sc->floorz) + sc->ceilingz = sc->floorz; + } + else + { + sc->ceilingz -= SP<<4; + if(sc->ceilingz < t[3]) + sc->ceilingz = t[3]; + } + + break; + + case 26: + + s->xvel = 32; + l = (s->xvel*sintable[(s->ang+512)&2047])>>14; + x = (s->xvel*sintable[s->ang&2047])>>14; + + s->shade++; + if( s->shade > 7 ) + { + s->x = t[3]; + s->y = t[4]; + sc->floorz -= ((s->zvel*s->shade)-s->zvel); + s->shade = 0; + } + else + sc->floorz += s->zvel; + + j = headspritesect[s->sectnum]; + while( j >= 0 ) + { + nextj = nextspritesect[j]; + if(sprite[j].statnum != 3 && sprite[j].statnum != 10) + { + hittype[j].bposx = sprite[j].x; + hittype[j].bposy = sprite[j].y; + + sprite[j].x += l; + sprite[j].y += x; + + sprite[j].z += s->zvel; + setsprite(j,sprite[j].x,sprite[j].y,sprite[j].z); + } + j = nextj; + } + + p = myconnectindex; + if(sprite[ps[p].i].sectnum == s->sectnum && ps[p].on_ground) + { + fricxv += l<<5; + fricyv += x<<5; + } + + for(p = connecthead;p >= 0;p = connectpoint2[p]) + if(sprite[ps[p].i].sectnum == s->sectnum && ps[p].on_ground) + ps[p].posz += s->zvel; + + ms(i); + setsprite(i,s->x,s->y,s->z); + + break; + + + case 27: + + if(ud.recstat == 0) break; + + hittype[i].tempang = s->ang; + + p = findplayer(s,&x); + if( sprite[ps[p].i].extra > 0 && myconnectindex == screenpeek) + { + if( t[0] < 0 ) + { + ud.camerasprite = i; + t[0]++; + } + else if(ud.recstat == 2 && ps[p].newowner == -1) + { + if(cansee(s->x,s->y,s->z,SECT,ps[p].posx,ps[p].posy,ps[p].posz,ps[p].cursectnum)) + { + if((unsigned)x < (unsigned)sh) + { + ud.camerasprite = i; + t[0] = 999; + s->ang += getincangle(s->ang,getangle(ps[p].posx-s->x,ps[p].posy-s->y))>>3; + SP = 100+((s->z-ps[p].posz)/257); + + } + else if(t[0] == 999) + { + if(ud.camerasprite == i) + t[0] = 0; + else t[0] = -10; + ud.camerasprite = i; + + } + } + else + { + s->ang = getangle(ps[p].posx-s->x,ps[p].posy-s->y); + + if(t[0] == 999) + { + if(ud.camerasprite == i) + t[0] = 0; + else t[0] = -20; + ud.camerasprite = i; + } + } + } + } + break; + case 28: + if(t[5] > 0) + { + t[5]--; + break; + } + + if(T1 == 0) + { + p = findplayer(s,&x); + if( x > 15500 ) + break; + T1 = 1; + T2 = 64 + (TRAND&511); + T3 = 0; + } + else + { + T3++; + if(T3 > T2) + { + T1 = 0; + ps[screenpeek].visibility = ud.const_visibility; + break; + } + else if( T3 == (T2>>1) ) + spritesound(THUNDER,i); + else if(T3 == (T2>>3) ) + spritesound(LIGHTNING_SLAP,i); + else if( T3 == (T2>>2) ) + { + j = headspritestat[0]; + while(j >= 0) + { + if( sprite[j].picnum == NATURALLIGHTNING && sprite[j].hitag == s->hitag) + sprite[j].cstat |= 32768; + j = nextspritestat[j]; + } + } + else if(T3 > (T2>>3) && T3 < (T2>>2) ) + { + if( cansee(s->x,s->y,s->z,s->sectnum,ps[screenpeek].posx,ps[screenpeek].posy,ps[screenpeek].posz,ps[screenpeek].cursectnum ) ) + j = 1; + else j = 0; + + if( rnd(192) && (T3&1) ) + { + if(j) + ps[screenpeek].visibility = 0; + } + else if(j) + ps[screenpeek].visibility = ud.const_visibility; + + j = headspritestat[0]; + while(j >= 0) + { + if( sprite[j].picnum == NATURALLIGHTNING && sprite[j].hitag == s->hitag) + { + if ( rnd(32) && (T3&1) ) + { + sprite[j].cstat &= 32767; + spawn(j,SMALLSMOKE); + + p = findplayer(s,&x); + x = ldist(&sprite[ps[p].i], &sprite[j]); + if( x < 768 ) + { + if(Sound[DUKE_LONGTERM_PAIN].num < 1) + spritesound(DUKE_LONGTERM_PAIN,ps[p].i); + spritesound(SHORT_CIRCUIT,ps[p].i); + sprite[ps[p].i].extra -= 8+(TRAND&7); + ps[p].pals_time = 32; + ps[p].pals[0] = 16; + ps[p].pals[1] = 0; + ps[p].pals[2] = 0; + } + break; + } + else sprite[j].cstat |= 32768; + } + + j = nextspritestat[j]; + } + } + } + break; + case 29: + s->hitag += 64; + l = mulscale12((long)s->yvel,sintable[s->hitag&2047]); + sc->floorz = s->z + l; + break; + case 31: // True Drop Floor + if(t[0] == 1) + { + // Choose dir + + if(t[3] > 0) + { + t[3]--; + break; + } + + if(t[2] == 1) // Retract + { + if(SA != 1536) + { + if( klabs( sc->floorz - s->z ) < SP ) + { + sc->floorz = s->z; + t[2] = 0; + t[0] = 0; + t[3] = s->hitag; + callsound(s->sectnum,i); + } + else + { + l = sgn(s->z-sc->floorz)*SP; + sc->floorz += l; + + j = headspritesect[s->sectnum]; + while(j >= 0) + { + if(sprite[j].picnum == APLAYER && sprite[j].owner >= 0) + if( ps[sprite[j].yvel].on_ground == 1 ) + ps[sprite[j].yvel].posz += l; + if( sprite[j].zvel == 0 && sprite[j].statnum != 3 && sprite[j].statnum != 4) + { + hittype[j].bposz = sprite[j].z += l; + hittype[j].floorz = sc->floorz; + } + j = nextspritesect[j]; + } + } + } + else + { + if( klabs( sc->floorz - t[1] ) < SP ) + { + sc->floorz = t[1]; + callsound(s->sectnum,i); + t[2] = 0; + t[0] = 0; + t[3] = s->hitag; + } + else + { + l = sgn(t[1]-sc->floorz)*SP; + sc->floorz += l; + + j = headspritesect[s->sectnum]; + while(j >= 0) + { + if(sprite[j].picnum == APLAYER && sprite[j].owner >= 0) + if( ps[sprite[j].yvel].on_ground == 1 ) + ps[sprite[j].yvel].posz += l; + if( sprite[j].zvel == 0 && sprite[j].statnum != 3 && sprite[j].statnum != 4 ) + { + hittype[j].bposz = sprite[j].z += l; + hittype[j].floorz = sc->floorz; + } + j = nextspritesect[j]; + } + } + } + break; + } + + if( (s->ang&2047) == 1536) + { + if( klabs( s->z-sc->floorz ) < SP ) + { + callsound(s->sectnum,i); + t[0] = 0; + t[2] = 1; + t[3] = s->hitag; + } + else + { + l = sgn(s->z-sc->floorz)*SP; + sc->floorz += l; + + j = headspritesect[s->sectnum]; + while(j >= 0) + { + if(sprite[j].picnum == APLAYER && sprite[j].owner >= 0) + if( ps[sprite[j].yvel].on_ground == 1 ) + ps[sprite[j].yvel].posz += l; + if( sprite[j].zvel == 0 && sprite[j].statnum != 3 && sprite[j].statnum != 4 ) + { + hittype[j].bposz = sprite[j].z += l; + hittype[j].floorz = sc->floorz; + } + j = nextspritesect[j]; + } + } + } + else + { + if( klabs( sc->floorz-t[1] ) < SP ) + { + t[0] = 0; + callsound(s->sectnum,i); + t[2] = 1; + t[3] = s->hitag; + } + else + { + l = sgn(s->z-t[1])*SP; + sc->floorz -= l; + + j = headspritesect[s->sectnum]; + while(j >= 0) + { + if(sprite[j].picnum == APLAYER && sprite[j].owner >= 0) + if( ps[sprite[j].yvel].on_ground == 1 ) + ps[sprite[j].yvel].posz -= l; + if(sprite[j].zvel == 0 && sprite[j].statnum != 3 && sprite[j].statnum != 4 ) + { + hittype[j].bposz = sprite[j].z -= l; + hittype[j].floorz = sc->floorz; + } + j = nextspritesect[j]; + } + } + } + } + break; + + case 32: // True Drop Ceiling + if(t[0] == 1) + { + // Choose dir + + if(t[2] == 1) // Retract + { + if(SA != 1536) + { + if( klabs( sc->ceilingz - s->z ) < + (SP<<1) ) + { + sc->ceilingz = s->z; + callsound(s->sectnum,i); + t[2] = 0; + t[0] = 0; + } + else sc->ceilingz += + sgn(s->z-sc->ceilingz)*SP; + } + else + { + if( klabs( sc->ceilingz - t[1] ) < + (SP<<1) ) + { + sc->ceilingz = t[1]; + callsound(s->sectnum,i); + t[2] = 0; + t[0] = 0; + } + else sc->ceilingz += + sgn(t[1]-sc->ceilingz)*SP; + } + break; + } + + if( (s->ang&2047) == 1536) + { + if( klabs(sc->ceilingz-s->z ) < + (SP<<1) ) + { + t[0] = 0; + t[2] = !t[2]; + callsound(s->sectnum,i); + sc->ceilingz = s->z; + } + else sc->ceilingz += + sgn(s->z-sc->ceilingz)*SP; + } + else + { + if( klabs(sc->ceilingz-t[1] ) < (SP<<1) ) + { + t[0] = 0; + t[2] = !t[2]; + callsound(s->sectnum,i); + } + else sc->ceilingz -= sgn(s->z-t[1])*SP; + } + } + break; + + case 33: + if( earthquaketime > 0 && (TRAND&7) == 0 ) + RANDOMSCRAP; + break; + case 36: + + if( t[0] ) + { + if( t[0] == 1 ) + shoot(i,sc->extra); + else if( t[0] == 26*5 ) + t[0] = 0; + t[0]++; + } + break; + + case 128: //SE to control glass breakage + + wal = &wall[t[2]]; + + if(wal->cstat|32) + { + wal->cstat &= (255-32); + wal->cstat |= 16; + if(wal->nextwall >= 0) + { + wall[wal->nextwall].cstat &= (255-32); + wall[wal->nextwall].cstat |= 16; + } + } + else break; + + wal->overpicnum++; + if(wal->nextwall >= 0) + wall[wal->nextwall].overpicnum++; + + if(t[0] < t[1]) t[0]++; + else + { + wal->cstat &= (128+32+8+4+2); + if(wal->nextwall >= 0) + wall[wal->nextwall].cstat &= (128+32+8+4+2); + KILLIT(i); + } + break; + + case 130: + if(t[0] > 80) { KILLIT(i); } + else t[0]++; + + x = sc->floorz-sc->ceilingz; + + if( rnd(64) ) + { + k = spawn(i,EXPLOSION2); + sprite[k].xrepeat = sprite[k].yrepeat = 2+(TRAND&7); + sprite[k].z = sc->floorz-(TRAND%x); + sprite[k].ang += 256-(TRAND%511); + sprite[k].xvel = TRAND&127; + ssp(k,CLIPMASK0); + } + break; + case 131: + if(t[0] > 40) { KILLIT(i); } + else t[0]++; + + x = sc->floorz-sc->ceilingz; + + if( rnd(32) ) + { + k = spawn(i,EXPLOSION2); + sprite[k].xrepeat = sprite[k].yrepeat = 2+(TRAND&3); + sprite[k].z = sc->floorz-(TRAND%x); + sprite[k].ang += 256-(TRAND%511); + sprite[k].xvel = TRAND&127; + ssp(k,CLIPMASK0); + } + break; + } + BOLT: + i = nexti; + } + + //Sloped sin-wave floors! + for(i=headspritestat[3];i>=0;i=nextspritestat[i]) + { + s = &sprite[i]; + if (s->lotag != 29) continue; + sc = §or[s->sectnum]; + if (sc->wallnum != 4) continue; + wal = &wall[sc->wallptr+2]; + alignflorslope(s->sectnum,wal->x,wal->y,sector[wal->nextsector].floorz); + } +} + diff --git a/animlib.c b/animlib.c new file mode 100755 index 0000000..c515cb7 --- /dev/null +++ b/animlib.c @@ -0,0 +1,384 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment + +This file is part of Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Original Source: 1996 - Todd Replogle +Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms +*/ +//------------------------------------------------------------------------- + +#include +#include +#include +#include + +#include "duke3d.h" +#include "types.h" +#include "develop.h" +#include "util_lib.h" +#include "_animlib.h" +#include "animlib.h" + +//**************************************************************************** +// +// GLOBALS +// +//**************************************************************************** + +//**************************************************************************** +// +// LOCALS +// +//**************************************************************************** +anim_t * anim=NULL; +static boolean Anim_Started = false; + +//**************************************************************************** +// +// CheckAnimStarted () +// +//**************************************************************************** + +void CheckAnimStarted ( char * funcname ) + { + if (!Anim_Started) + Error("ANIMLIB_%s: Anim has not been initialized\n",funcname); + } +//**************************************************************************** +// +// findpage () +// - given a frame number return the large page number it resides in +// +//**************************************************************************** + +uint16 findpage (uint16 framenumber) + { + uint16 i; + + CheckAnimStarted ( "findpage" ); + for(i=0; ilpheader.nLps; i++) + { + if + ( + anim->LpArray[i].baseRecord <= framenumber && + anim->LpArray[i].baseRecord + anim->LpArray[i].nRecords > framenumber + ) + return(i); + } + return(i); + } + + +//**************************************************************************** +// +// loadpage () +// - seek out and load in the large page specified +// +//**************************************************************************** + +void loadpage (uint16 pagenumber, uint16 *pagepointer) + { + int32 size; + byte * buffer; + + CheckAnimStarted ( "loadpage" ); + buffer = anim->buffer; + if (anim->curlpnum != pagenumber) + { + anim->curlpnum = pagenumber; + buffer += 0xb00 + (pagenumber*0x10000); + size = sizeof(lp_descriptor); + memcpy(&anim->curlp,buffer,size); + #if PLATFORM_BIGENDIAN + anim->curlp.baseRecord = BUILDSWAP_INTEL16(anim->curlp.baseRecord); + anim->curlp.nRecords = BUILDSWAP_INTEL16(anim->curlp.nRecords); + anim->curlp.nBytes = BUILDSWAP_INTEL16(anim->curlp.nBytes); + #endif + buffer += size + sizeof(uint16); + + // most of pagepointer is 8-bit data, the 16-bit stuff is byteswapped + // on the fly in renderframe() and CPlayRunSkipDump(), below. --ryan. + memcpy(pagepointer,buffer,anim->curlp.nBytes+(anim->curlp.nRecords*2)); + } + } + + +//**************************************************************************** +// +// CPlayRunSkipDump () +// - This version of the decompressor is here for portability to non PC's +// +//**************************************************************************** + +void CPlayRunSkipDump (char *srcP, char *dstP) + { + signed char cnt; + uint16 wordCnt; + byte pixel; + +nextOp: + cnt = (signed char) *srcP++; + if (cnt > 0) + goto dump; + if (cnt == 0) + goto run; + cnt -= 0x80; + if (cnt == 0) + goto longOp; +/* shortSkip */ + dstP += cnt; /* adding 7-bit count to 32-bit pointer */ + goto nextOp; +dump: + do + { + *dstP++ = *srcP++; + } while (--cnt); + goto nextOp; +run: + wordCnt = (byte)*srcP++; /* 8-bit unsigned count */ + pixel = *srcP++; + do + { + *dstP++ = pixel; + } while (--wordCnt); + + goto nextOp; +longOp: + wordCnt = *((uint16 *)srcP); + +#if PLATFORM_BIGENDIAN + wordCnt = BUILDSWAP_INTEL16(wordCnt); +#endif + + srcP += sizeof(uint16); + if ((int16)wordCnt <= 0) + goto notLongSkip; /* Do SIGNED test. */ + +/* longSkip. */ + dstP += wordCnt; + goto nextOp; + +notLongSkip: + if (wordCnt == 0) + goto stop; + wordCnt -= 0x8000; /* Remove sign bit. */ + if (wordCnt >= 0x4000) + goto longRun; + +/* longDump. */ + do + { + *dstP++ = *srcP++; + } while (--wordCnt); + goto nextOp; + +longRun: + wordCnt -= 0x4000; /* Clear "longRun" bit. */ + pixel = *srcP++; + do + { + *dstP++ = pixel; + } while (--wordCnt); + goto nextOp; + +stop: /* all done */ + ; + } + + +//**************************************************************************** +// +// renderframe () +// - draw the frame sepcified from the large page in the buffer pointed to +// +//**************************************************************************** + +void renderframe (uint16 framenumber, uint16 *pagepointer) + { + uint16 offset=0; + uint16 i; + uint16 destframe; + uint16 pp1; + byte *ppointer; + + CheckAnimStarted ( "renderframe" ); + destframe = framenumber - anim->curlp.baseRecord; + + for(i = 0; i < destframe; i++) + { + offset += BUILDSWAP_INTEL16(pagepointer[i]); + } + ppointer = (byte *)pagepointer; + + ppointer+=anim->curlp.nRecords*2+offset; + if(ppointer[1]) + { + uint16 pp1 = BUILDSWAP_INTEL16(((uint16 *)ppointer)[1]); + ppointer += (4 + (pp1 + (pp1 & 1))); + } + else + { + ppointer+=4; + } + + CPlayRunSkipDump (ppointer, anim->imagebuffer); + } + + +//**************************************************************************** +// +// drawframe () +// - high level frame draw routine +// +//**************************************************************************** + +void drawframe (uint16 framenumber) + { + CheckAnimStarted ( "drawframe" ); + loadpage(findpage(framenumber), anim->thepage); + renderframe(framenumber, anim->thepage); + } + + +//**************************************************************************** +// +// ANIM_LoadAnim () +// +//**************************************************************************** + +void ANIM_LoadAnim (char * buffer) +{ + uint16 i; + int32 size; + + assert(sizeof(lp_descriptor) == 6); + assert(sizeof(lpfileheader) == 128); + assert(sizeof(anim->LpArray) == 1536); + + if (!Anim_Started) Anim_Started = true; + + anim->buffer = buffer; + anim->curlpnum = 0xffff; + anim->currentframe = -1; + size = sizeof(lpfileheader); + memcpy(&anim->lpheader, buffer, size ); + +#if PLATFORM_BIGENDIAN + anim->lpheader.id = BUILDSWAP_INTEL32(anim->lpheader.id); + anim->lpheader.maxLps = BUILDSWAP_INTEL16(anim->lpheader.maxLps); + anim->lpheader.nLps = BUILDSWAP_INTEL16(anim->lpheader.nLps); + anim->lpheader.nRecords = BUILDSWAP_INTEL32(anim->lpheader.nRecords); + anim->lpheader.maxRecsPerLp = BUILDSWAP_INTEL16(anim->lpheader.maxRecsPerLp); + anim->lpheader.lpfTableOffset = BUILDSWAP_INTEL16(anim->lpheader.lpfTableOffset); + anim->lpheader.contentType = BUILDSWAP_INTEL32(anim->lpheader.contentType); + anim->lpheader.width = BUILDSWAP_INTEL16(anim->lpheader.width); + anim->lpheader.height = BUILDSWAP_INTEL16(anim->lpheader.height); + anim->lpheader.nFrames = BUILDSWAP_INTEL32(anim->lpheader.nFrames); + anim->lpheader.framesPerSecond = BUILDSWAP_INTEL16(anim->lpheader.framesPerSecond); + //uint16 pad2[29]; // 58 bytes of filler to round up to 128 bytes total. +#endif + + buffer += size+128; + // load the color palette + for (i = 0; i < 768; i += 3) + { + anim->pal[i+2] = *buffer++; + anim->pal[i+1] = *buffer++; + anim->pal[i] = *buffer++; + buffer++; + } + // read in large page descriptors + size = sizeof(anim->LpArray); + memcpy(&anim->LpArray,buffer,size); + +#if PLATFORM_BIGENDIAN + for (i = 0; i < sizeof (anim->LpArray) / sizeof (anim->LpArray[0]); i++) + { + lp_descriptor *d = &anim->LpArray[i]; + d->baseRecord = BUILDSWAP_INTEL16(d->baseRecord); + d->nRecords = BUILDSWAP_INTEL16(d->nRecords); + d->nBytes = BUILDSWAP_INTEL16(d->nBytes); + } +#endif +} + +//**************************************************************************** +// +// ANIM_FreeAnim () +// +//**************************************************************************** + +void ANIM_FreeAnim ( void ) + { + if (Anim_Started) + { +// SafeFree(anim); + Anim_Started = false; + } + } + +//**************************************************************************** +// +// ANIM_NumFrames () +// +//**************************************************************************** + +int32 ANIM_NumFrames ( void ) + { + CheckAnimStarted ( "NumFrames" ); + return anim->lpheader.nRecords; + } + +//**************************************************************************** +// +// ANIM_DrawFrame () +// +//**************************************************************************** + +byte * ANIM_DrawFrame (int32 framenumber) + { + int32 cnt; + + CheckAnimStarted ( "DrawFrame" ); + if ((anim->currentframe != -1) && (anim->currentframe<=framenumber)) + { + for (cnt = anim->currentframe; cnt < framenumber; cnt++) + drawframe (cnt); + } + else + { + for (cnt = 0; cnt < framenumber; cnt++) + drawframe (cnt); + } + anim->currentframe = framenumber; + return anim->imagebuffer; + } + +//**************************************************************************** +// +// ANIM_GetPalette () +// +//**************************************************************************** + +byte * ANIM_GetPalette ( void ) + { + CheckAnimStarted ( "GetPalette" ); + return anim->pal; + } diff --git a/animlib.h b/animlib.h new file mode 100755 index 0000000..802eafe --- /dev/null +++ b/animlib.h @@ -0,0 +1,155 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment + +This file is part of Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Original Source: 1996 - Todd Replogle +Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms +*/ +//------------------------------------------------------------------------- + +///////////////////////////////////////////////////////////////////////////// +// +// ANIMLIB.H +// +///////////////////////////////////////////////////////////////////////////// + +#ifndef _animlib_public_ +#define _animlib_public_ +#ifdef __cplusplus +extern "C" { +#endif + + +// structure declarations for deluxe animate large page files */ + +typedef struct + { + uint32 id; // 4 character ID == "LPF " */ + uint16 maxLps; // max # largePages allowed. 256 FOR NOW. */ + uint16 nLps; // # largePages in this file. */ + uint32 nRecords; // # records in this file. 65534 is current limit plus */ + // one for last-to-first delta for looping the animation */ + uint16 maxRecsPerLp; // # records permitted in an lp. 256 FOR NOW. */ + uint16 lpfTableOffset; // Absolute Seek position of lpfTable. 1280 FOR NOW. + // The lpf Table is an array of 256 large page structures + // that is used to facilitate finding records in an anim + // file without having to seek through all of the Large + // Pages to find which one a specific record lives in. */ + uint32 contentType; // 4 character ID == "ANIM" */ + uint16 width; // Width of screen in pixels. */ + uint16 height; // Height of screen in pixels. */ + byte variant; // 0==ANIM. */ + byte version; // 0==frame rate is multiple of 18 cycles/sec. + // 1==frame rate is multiple of 70 cycles/sec. */ + byte hasLastDelta; // 1==Last record is a delta from last-to-first frame. */ + byte lastDeltaValid; // 0==The last-to-first delta (if present) hasn't been + // updated to match the current first&last frames, so it + // should be ignored. */ + byte pixelType; // /* 0==256 color. */ + byte CompressionType;// /* 1==(RunSkipDump) Only one used FOR NOW. */ + byte otherRecsPerFrm;// /* 0 FOR NOW. */ + byte bitmaptype; // /* 1==320x200, 256-color. Only one implemented so far. */ + byte recordTypes[32];// /* Not yet implemented. */ + uint32 nFrames; // /* In case future version adds other records at end of + // file, we still know how many actual frames. + // NOTE: DOES include last-to-first delta when present. */ + uint16 framesPerSecond; // Number of frames to play per second. */ + uint16 pad2[29]; // 58 bytes of filler to round up to 128 bytes total. */ + } lpfileheader; + +// this is the format of a large page structure +typedef struct + { + uint16 baseRecord; // Number of first record in this large page. + uint16 nRecords; // Number of records in lp. + // bit 15 of "nRecords" == "has continuation from previous lp". + // bit 14 of "nRecords" == "final record continues on next lp". + uint16 nBytes; // Total number of bytes of contents, excluding header. + } lp_descriptor; + +typedef struct + { + uint16 framecount; // current frame of anim + lpfileheader lpheader; // file header will be loaded into this structure + lp_descriptor LpArray[256]; // arrays of large page structs used to find frames + uint16 curlpnum; // initialize to an invalid Large page number + lp_descriptor curlp; // header of large page currently in memory + uint16 thepage[0x8000]; // buffer where current large page is loaded + byte imagebuffer[0x10000]; // buffer where anim frame is decoded + byte * buffer; + byte pal[768]; + int32 currentframe; + } anim_t; + +//**************************************************************************** +// +// ANIM_LoadAnim () +// +// Setup internal anim data structure +// +//**************************************************************************** + +void ANIM_LoadAnim (char * buffer); + +//**************************************************************************** +// +// ANIM_FreeAnim () +// +// Free up internal anim data structure +// +//**************************************************************************** + +void ANIM_FreeAnim ( void ); + +//**************************************************************************** +// +// ANIM_NumFrames () +// +// returns the number of frames in the current anim +// +//**************************************************************************** + +int32 ANIM_NumFrames ( void ); + +//**************************************************************************** +// +// ANIM_DrawFrame () +// +// Draw the frame to a returned buffer +// +//**************************************************************************** + +byte * ANIM_DrawFrame (int32 framenumber); + +//**************************************************************************** +// +// ANIM_GetPalette () +// +// return the palette of the anim +//**************************************************************************** + +byte * ANIM_GetPalette ( void ); + +extern anim_t * anim; + +#ifdef __cplusplus +}; +#endif +#endif diff --git a/astub.c b/astub.c new file mode 100755 index 0000000..8d8c7f9 --- /dev/null +++ b/astub.c @@ -0,0 +1,2365 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment + +This file is part of Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Original Source: 1996 - Allen Blum +Prepared for public release: 05/24/2003 - Charlie Wiederhold, 3D Realms +*/ +//------------------------------------------------------------------------- + +/* +******************************************************** + + ASTUB.C (c) 1996 Allen H. Blum III + +******************************************************** + + +Specs: + +Duke Lookup Table + + 1 : Blue + 2 : Red + 3 : Normal for Sky + 4 : Black Shadow + 5 : + 6 : Night Vision + 7 : Yellow + 8 : Green + + Duke Sprite + + 9 : Blue + 10 : Red + 11 : Green + 12 : Grey + 13 : Ninja + 14 : G.I. Duke + 15 : Brown + 16 : Postal Duke (Dark Blue) + + 21 : Blue -> Red + 22 : Blue -> Green + 23 : Blue -> Yellow + +******************************************************** +*/ + +#if PLATFORM_DOS +#include +#endif + +#include +#include +#include +#include +#include +#include +#include "buildengine/engine.h" +#include "buildengine/platform.h" +#include "buildengine/build.h" +#include "buildengine/pragmas.h" +#include "buildengine/bstub.h" +#include "buildengine/cache1d.h" /* rcg05232001 need groupfile support. */ +#include "buildengine/display.h" /* rcg05232001 need some "vesa" routines. */ +#include "names.h" + + +/* defined in build.c ... */ +void editinput(void); +void clearmidstatbar16(void); +short getnumber16(char namestart[80], short num, long maxnumber); +void printmessage16(char name[82]); + +#define TICSPERFRAME 3 + + +//#include "water.c" + +char *Myname = "stryker@metronet.com"; + +extern char keystatus[]; +extern short defaultspritecstat; +extern long posx, posy, posz, horiz, qsetmode; +extern short ang, cursectnum; +extern short ceilingheinum, floorheinum; +extern char names[MAXTILES][17]; + +extern long zmode, kensplayerheight, zlock; + +extern short editstatus, searchit; +extern long searchx, searchy; //search input +extern short searchsector, searchwall, searchstat; //search output + +static short temppicnum, tempcstat; +static char tempshade, tempxrepeat, tempyrepeat, somethingintab = 255; +static long temphitag,templotag; + +static long ototalclock = 0; + +static long clockval[16], clockcnt = 0; + +#define NUMOPTIONS 8 +#define NUMKEYS 19 + +static long vesares[13][2] = { {320,200}, {360,200}, {320,240}, {360,240}, + {320,400}, {360,400}, {640,350}, {640,400}, + {640,480}, {800,600}, {1024,768},{1280,1024}, + {1600,1200} }; + +static char option[NUMOPTIONS] = {0,0,0,0,0,0,1,0}; +static char keys[NUMKEYS] = + { + 0xc8,0xd0,0xcb,0xcd,0x2a,0x9d,0x1d,0x39, + 0x1e,0x2c,0xd1,0xc9,0x47,0x49, + 0x9c,0x1c,0xd,0xc,0xf, + }; +extern char buildkeys[NUMKEYS]; + + + + + + +//extern void __interrupt __far timerhandler(void); + +long xoldtimerhandler; + +#define COKE 52 + +#define MAXHELP2D 9 +char *Help2d[MAXHELP2D]= +{ + " ' M = Memory", + " ' 1 = Captions ", +// " ' 2 = ", + " ' 3 = Captions Toggle", +// " ' 4 = MIN FRAMES RATE", +// " ' 5 = MOTORCYCLE", + " ' 9 = Swap HI LO", +// " ' 0 = SHRINK MAP 50", + " F8 = Current Wall/Sprite", + " F9 = Current Sector", + " [ = Search Forward", + " ] = Search Backward", + " ~ = HELP OFF" +}; + +#define MAXMODE32D 7 +char *Mode32d[MAXMODE32D]= +{ + "NONE", + "SECTORS", + "WALLS", + "SPRITES", + "ALL", + "ITEMS ONLY", + "CURRENT SPRITE ONLY" +}; + +#define MAXSKILL 5 +char *SKILLMODE[MAXSKILL]= +{ + "BEGINNER", + "EASY", + "NORMAL", + "NOT EASY", + "ALL", +}; + +#define MAXNOSPRITES 4 +char *ALPHABEASTLOADOMAGA1[MAXNOSPRITES]= +{ + "DISPLAY ALL SPRITES", + "NO EFFECTORS", + "NO ACTORS", + "NONE", +}; + +short MinRate=24, MinD=3; +// CTW - MODIFICATION +// Good to know Allen has changed in all these years. ;) +// CTW END - MODIFICATION +char *Slow[8]= +{ + "SALES = 0,000,000 ***********************", + "100% OF NOTHING IS !! ********************", + "RENDER IN PROGRESS ***********************", + "YOUR MOTHER IS A WHORE *******************", + "YOU SUCK DONKEY **************************", + "FUCKIN PISS ANT **************************", + "PISS ANT *********************************", + "SLOW *************************************" +}; + +#define MAXHELP3D 15 +char *Help3d[MAXHELP3D]= +{ + "3D KEYS HELP", + " ", + " F1 = HELP TOGGLE", + " ' R = FRAMERATE TOGGLE", + " ' D = SKILL MODE", + " ' W = TOGGLE SPRITE DISPLAY", + " ' G = GRAPHIC TOGGLE", + " ' Y = TOGGLE PURPLE BACKGROUND", + " ' ENTER = COPY GRAPHIC ONLY", + " ' T = CHANGE LOTAG", + " ' H = CHANGE HITAG", + " ' S = CHANGE SHADE", + " ' V = CHANGE VISIBILITY", + " ' C = CHANGE GLOBAL SHADE", + " ' DEL = CSTAT=0", +}; + + +/******* VARS ********/ + +static char tempbuf[1024]; //1024 +static int numsprite[MAXSPRITES]; +static int multisprite[MAXSPRITES]; +static char lo[32]; +static const char *levelname; +static short curwall=0,wallpicnum=0,curwallnum=0; +static short cursprite=0,curspritenum=0; +static short cursector_lotag=0,cursectornum=0; +static short search_lotag=0,search_hitag=0; +static char wallsprite=0; +static char helpon=0; +static char on2d3d=0; +//static char onwater=0; +static char onnames=4; +static char usedcount=0; +long mousxplc,mousyplc; +long ppointhighlight; +static int counter=0; +char nosprites=0,purpleon=0,skill=4; +char framerateon=1,tabgraphic=0; + + +static char sidemode=0; +extern long vel, svel, angvel; +long xvel, yvel, hvel, timeoff; + +static char once=0; + +void Ver() +{ + sprintf(tempbuf,"DUKE NUKEM BUILD: V032696"); + if (qsetmode == 200) //In 3D mode + { printext256(60*8,24*8,11,-1,tempbuf,1); + rotatesprite((320-8)<<16,(200-8)<<16,64<<9,0,SPINNINGNUKEICON+(((4-totalclock>>3))&7),0,0,0,0,0,xdim-1,ydim-1); + }else + { printext16(0,0,15,-1,tempbuf,0); + } +} + +void PrintStatus(char *string,int num,char x,char y,char color) +{ + sprintf(tempbuf,"%s %d",string,num); + printext16(x*8,y*8,color,-1,tempbuf,0); +} + +void SpriteName(short spritenum, char *lo2) +{ + sprintf(lo2,names[sprite[spritenum].picnum]); +}// end SpriteName + +void ExtLoadMap(const char *mapname) +{ + + + long i; + long sky=0; + int j; + + + // PreCache Wall Tiles + for(j=0;j=20 && sprite[j].picnum<=59) + { + if(sprite[j].picnum==26) {sprite[j].xrepeat = 8; sprite[j].yrepeat = 8;} + else {sprite[j].xrepeat = 32; sprite[j].yrepeat = 32;} + } + + } + + + + levelname=mapname; + pskyoff[0]=0; + for(i=0;i<8;i++) pskyoff[i]=0; + + for(i=0;i>2)+((stat&16)>>2)^((stat&8)>>1), + windowx1,windowy1,windowx2,windowy2); +} + +void putsprite (long thex, long they, long zoom, short rot, short tilenum, signed char shade, char dapalnum) +{char stat=0; + rotatesprite(thex<<16,they<<16,65536L-zoom,(rot+(stat&8))<<7,tilenum,shade,dapalnum, + ((stat&1^1)<<4)+(stat&2)+((stat&4)>>2)+((stat&16)>>2)^((stat&8)>>1), + windowx1,windowy1,windowx2,windowy2); +} + + +void ExtSaveMap(const char *mapname) +{ + saveboard("backup.map",&posx,&posy,&posz,&ang,&cursectnum); +} + +const char *ExtGetSectorCaption(short sectnum) +{ + + if(!(onnames==1 || onnames==4)) + { + tempbuf[0] = 0; + return(tempbuf); + } + + + if ((sector[sectnum].lotag|sector[sectnum].hitag) == 0) + { + tempbuf[0] = 0; + } + else + { + switch((unsigned short)sector[sectnum].lotag) + { +// case 1 : sprintf(lo,"WATER"); break; +// case 2 : sprintf(lo,"UNDERWATER"); break; +// case 3 : sprintf(lo,"EARTHQUAKE"); break; + default : sprintf(lo,"%hu",(unsigned short)sector[sectnum].lotag); break; + } + sprintf(tempbuf,"%hu,%s", + (unsigned short)sector[sectnum].hitag, + lo); + } + return(tempbuf); +} + +const char *ExtGetWallCaption(short wallnum) +{ + long i=0; + + if(!(onnames==2 || onnames==4)) + { + tempbuf[0] = 0; + return(tempbuf); + } + + + if(keystatus[0x57]>0) // f11 Grab pic 0x4e + + { + wallpicnum = wall[curwall].picnum; + sprintf(tempbuf,"Grabed Wall Picnum %d",wallpicnum); + printmessage16(tempbuf); + } + + + // HERE + + if(keystatus[0x1a]>0) // [ search backward + { + keystatus[0x1a]=0; + if(wallsprite==0) + { SearchSectorsBackward(); + } else + + if(wallsprite==1) + { + if(curwallnum>0) curwallnum--; + for(i=curwallnum;i>=0;i--) + { + if( + (wall[i].picnum==wall[curwall].picnum) + &&((search_lotag==0)|| + (search_lotag!=0 && search_lotag==wall[i].lotag)) + &&((search_hitag==0)|| + (search_hitag!=0 && search_hitag==wall[i].hitag)) + ) + { + posx=(wall[i].x)-(( (wall[i].x)-(wall[wall[i].point2].x) )/2); + posy=(wall[i].y)-(( (wall[i].y)-(wall[wall[i].point2].y) )/2); + printmessage16("< Wall Search : Found"); +// curwallnum--; + keystatus[0x1a]=0; + return(tempbuf); + } + curwallnum--; + } + printmessage16("< Wall Search : none"); + } else + + if(wallsprite==2) + { + if(curspritenum>0) curspritenum--; + for(i=curspritenum;i>=0;i--) + { + + if( + (sprite[i].picnum==sprite[cursprite].picnum && + sprite[i].statnum==0 ) + &&((search_lotag==0)|| + (search_lotag!=0 && search_lotag==sprite[i].lotag)) + &&((search_hitag==0)|| + (search_hitag!=0 && search_hitag==sprite[i].hitag)) + ) + { + posx=sprite[i].x; + posy=sprite[i].y; + ang= sprite[i].ang; + printmessage16("< Sprite Search : Found"); +// curspritenum--; + keystatus[0x1a]=0; + return(tempbuf); + } + curspritenum--; + } + printmessage16("< Sprite Search : none"); + } + } + + + if(keystatus[0x1b]>0) // ] search forward + { + keystatus[0x1b]=0; + if(wallsprite==0) + { SearchSectorsForward(); + } else + + if(wallsprite==1) + { + if(curwallnum Wall Search : Found"); +// curwallnum++; + keystatus[0x1b]=0; + return(tempbuf); + } + curwallnum++; + } + printmessage16("> Wall Search : none"); + } else + + if(wallsprite==2) + { + if(curspritenum Sprite Search : Found"); +// curspritenum++; + keystatus[0x1b]=0; + return(tempbuf); + } + curspritenum++; + } + printmessage16("> Sprite Search : none"); + } + } + + + if ((wall[wallnum].lotag|wall[wallnum].hitag) == 0) + { + tempbuf[0] = 0; + } + else + { + sprintf(tempbuf,"%hu,%hu",(unsigned short)wall[wallnum].hitag, + (unsigned short)wall[wallnum].lotag); + } + return(tempbuf); +} //end + +const char *ExtGetSpriteCaption(short spritenum) +{ + + + if( onnames!=5 && + onnames!=6 && + (!(onnames==3 || onnames==4)) + ) + { + tempbuf[0] = 0; + return(tempbuf); + } + + if( onnames==5 && + ( ((unsigned short)sprite[spritenum].picnum <= 9 ) || + ((unsigned short)sprite[spritenum].picnum == SEENINE ) + ) + ) + { tempbuf[0] = 0; return(tempbuf); } + + if( onnames==6 && + (unsigned short)sprite[spritenum].picnum != (unsigned short)sprite[cursprite].picnum + ) + { tempbuf[0] = 0; return(tempbuf); } + + tempbuf[0] = 0; + if ((sprite[spritenum].lotag|sprite[spritenum].hitag) == 0) + { + SpriteName(spritenum,lo); + if(lo[0]!=0) + { + if(sprite[spritenum].pal==1) sprintf(tempbuf,"%s-M",lo); + else sprintf(tempbuf,"%s",lo); + } + } + else + if( (unsigned short)sprite[spritenum].picnum == 175) + { + sprintf(lo,"%hu",(unsigned short)sprite[spritenum].lotag); + sprintf(tempbuf,"%hu,%s",(unsigned short)sprite[spritenum].hitag,lo); + } + else + { + SpriteName(spritenum,lo); + sprintf(tempbuf,"%hu,%hu %s", + (unsigned short)sprite[spritenum].hitag, + (unsigned short)sprite[spritenum].lotag, + lo); + } + return(tempbuf); +} //end + +//printext16 parameters: +//printext16(long xpos, long ypos, short col, short backcol, +// char name[82], char fontsize) +// xpos 0-639 (top left) +// ypos 0-479 (top left) +// col 0-15 +// backcol 0-15, -1 is transparent background +// name +// fontsize 0=8*8, 1=3*5 + +//drawline16 parameters: +// drawline16(long x1, long y1, long x2, long y2, char col) +// x1, x2 0-639 +// y1, y2 0-143 (status bar is 144 high, origin is top-left of STATUS BAR) +// col 0-15 + + + +void TotalMem() +{ + char incache[8192]; + int i,j,tottiles,totsprites,totactors; + + for(i=0;i<4096;i++) incache[i] = 0; + + for(i=0;i= 0) + incache[wall[i].overpicnum] = 1; + } + + tottiles = 0; + for(i=0;i<4096;i++) + if (incache[i] > 0) + tottiles += tilesizx[i]*tilesizy[i]; + + + + for(i=0;i<4096;i++) incache[i] = 0; + + for(i=0;i 0) + { + switch(i) + { + case LIZTROOP : + case LIZTROOPRUNNING : + case LIZTROOPSTAYPUT : + case LIZTROOPSHOOT : + case LIZTROOPJETPACK : + case LIZTROOPONTOILET : + case LIZTROOPDUCKING : + totactors+=ActorMem(LIZTROOP); + incache[LIZTROOP]=0; + incache[LIZTROOPRUNNING]=0; + incache[LIZTROOPSTAYPUT]=0; + incache[LIZTROOPSHOOT]=0; + incache[LIZTROOPJETPACK]=0; + incache[LIZTROOPONTOILET]=0; + incache[LIZTROOPDUCKING]=0; + break; + case OCTABRAIN : + case OCTABRAINSTAYPUT: + totactors+=ActorMem(OCTABRAIN); + incache[OCTABRAIN]=0; + incache[OCTABRAINSTAYPUT]=0; + break; + case DRONE : + totactors+=ActorMem(DRONE); + incache[DRONE]=0; + break; + case COMMANDER : + totactors+=ActorMem(COMMANDER); + incache[COMMANDER]=0; + break; + case RECON : + totactors+=ActorMem(RECON); + incache[RECON]=0; + break; + case PIGCOP : + totactors+=ActorMem(COMMANDER); + incache[PIGCOP]=0; + break; + case LIZMAN : + case LIZMANSTAYPUT : + case LIZMANSPITTING : + case LIZMANFEEDING : + case LIZMANJUMP : + totactors+=ActorMem(LIZMAN); + incache[LIZMAN]=0; + incache[LIZMANSTAYPUT]=0; + incache[LIZMANSPITTING]=0; + incache[LIZMANFEEDING]=0; + incache[LIZMANJUMP]=0; + break; + case BOSS1 : + totactors+=ActorMem(BOSS1); + incache[BOSS1]=0; + break; + case BOSS2 : + totactors+=ActorMem(BOSS2); + incache[BOSS2]=0; + break; + case BOSS3 : + totactors+=ActorMem(BOSS3); + incache[BOSS3]=0; + break; + + default: totsprites += tilesizx[i]*tilesizy[i]; + } + } + } + + + + + + clearmidstatbar16(); + printext16(1*8,4*8,11,-1,"Memory Status",0); + + PrintStatus("Total Tiles = ",tottiles,2,6,11); + PrintStatus("Total Sprites = ",totsprites,2,7,11); + PrintStatus("Total Actors = ",totactors,2,8,11); + + PrintStatus("Total Memory = ",(tottiles+totsprites+totactors),2,10,11); + + PrintStatus("Total W/Duke = ",(tottiles+totsprites+totactors+ActorMem(APLAYER)),2,12,11); + +} + +void ExtShowSectorData(short sectnum) //F5 +{ + short statnum=0; + int x,x2,y; + int nexti; + int i,c=0; + int secrets=0; + int totalactors1=0,totalactors2=0,totalactors3=0,totalactors4=0; + int totalrespawn=0; + for(i=0;ixmax) xmax=x; + } + tempbuf[x]=0; + printext16(xx*4,(y*6)+2,11,-1,tempbuf,1); + x=0; y++; + if(y>18) {col++; y=6; xx+=xmax; xmax=0;} + } + + kclose(fp); + +}// end Show2dText + +void Show3dText(char *name) +{ + int i,fp; + char x=0,y=4,xmax=0,xx=0,col=0,t; + if((fp=kopen4load(name,0)) == -1) + { + printext256(1*4,4*8,11,-1,"ERROR: file not found.",0); + return; + } + t=65; + while(t!=EOF && col<5) + { + kread(fp,&t,1); + while(t!=EOF && t!='\n' && x<250) + { + tempbuf[x]=t; + kread(fp,&t,1); + x++; if(x>xmax) xmax=x; + } + tempbuf[x]=0; + printext256(xx*4,(y*6)+2,11,-1,tempbuf,1); + x=0; y++; + if(y>18) {col++; y=6; xx+=xmax; xmax=0;} + } + + kclose(fp); +}// end Show3dText + + +void ShowHelpText(char *name) +{ + FILE *fp; + int i,t; + char x=0,y=4,xmax=0,xx=0,col=0; + if((fp=fopen("helpdoc.txt","rb")) == NULL) + { + printext256(1*4,4*8,11,-1,"ERROR: file not found.",0); + return; + } +/* + fgets(tempbuf,80,fp); + while(!feof(fp) && strcmp(tempbuf,"SectorEffector")) + { + fgets(tempbuf,80,fp); + } +*/ + y=2; + fgets(tempbuf,80,fp); + strcat(tempbuf,"\n"); + while(!feof(fp) && !(strcmp(tempbuf,"SectorEffector")==0)) + { + fgets(tempbuf,80,fp); + strcat(tempbuf,"\n"); + printext256(x*4,(y*6)+2,11,-1,tempbuf,1); + y++; + } + + fclose(fp); +}// end ShowHelpText + + + + + + + +void ExtShowSpriteData(short spritenum) //F6 +{ + Show2dText("sehelp.hlp"); +}// end ExtShowSpriteData + +void ExtEditSectorData(short sectnum) //F7 +{ + Show2dText("sthelp.hlp"); +}// end ExtEditSectorData + +void ExtEditWallData(short wallnum) //F8 +{ + if(qsetmode!=480) return; + wallsprite=1; + curwall = wallnum; + curwallnum = 0; + curspritenum = 0; + cursectornum = 0; + search_lotag=getnumber16("Enter Wall Search Lo-Tag : ", search_lotag, 65536L); + search_hitag=getnumber16("Enter Wall Search Hi-Tag : ", search_hitag, 65536L); + sprintf(tempbuf,"Current Wall %d lo=%d hi=%d", + curwall,search_lotag,search_hitag); + printmessage16(tempbuf); + +} + +void ExtEditSpriteData(short spritenum) //F8 +{ + if(qsetmode!=480) return; + wallsprite=2; + cursprite = spritenum; + curwallnum = 0; + curspritenum = 0; + cursectornum = 0; + search_lotag=getnumber16("Enter Sprite Search Lo-Tag : ", search_lotag, 65536L); + search_hitag=getnumber16("Enter Sprite Search Hi-Tag : ", search_hitag, 65536L); + sprintf(tempbuf,"Current Sprite %d %s lo=%d hi=%d", + cursprite,names[sprite[cursprite].picnum],search_lotag,search_hitag); + printmessage16(tempbuf); + +} + +char GAMEpalette[768]; +char WATERpalette[768]; +char SLIMEpalette[768]; +char TITLEpalette[768]; +char REALMSpalette[768]; +char BOSS1palette[768]; + +ReadGamePalette() +{ + int i,fp; + if((fp=kopen4load("palette.dat",0)) == -1) return; + kread(fp,GAMEpalette,768); + for(i=0;i<768;++i) GAMEpalette[i]=GAMEpalette[i]; + kclose(fp); +} + + +void ReadPaletteTable() +{ + int i,j,fp; + char num_tables,lookup_num; + if((fp=kopen4load("lookup.dat",0)) == -1) return; + kread(fp,&num_tables,1); + for(j=0;j4) skill=0; + sprintf(tempbuf,"%s",SKILLMODE[skill]); + printext256(1*4,1*8,11,-1,tempbuf,0); + } +*/ + if(keystatus[0x28]==1 && keystatus[0x22]==1) // ' g + { + keystatus[0x22] = 0; + tabgraphic=!tabgraphic; + if(tabgraphic) printext256(1*4,1*8,11,-1,"Graphics ON",0); + else printext256(1*4,1*8,11,-1,"Graphics OFF",0); + } + + if(keystatus[0x28]==1 && keystatus[0x13]==1) // ' r + { + keystatus[0x13] = 0; + framerateon=!framerateon; + if(framerateon) printext256(1*4,1*8,11,-1,"Framerate ON",0); + else printext256(1*4,1*8,11,-1,"Framerate OFF",0); + } + + if(keystatus[0x28]==1 && keystatus[0x11]==1) // ' w + { + keystatus[0x11] = 0; + nosprites++; if(nosprites>3) nosprites=0; + sprintf(tempbuf,"%s",ALPHABEASTLOADOMAGA1[nosprites]); + printext256(1*4,1*8,11,-1,tempbuf,0); + } + + if(keystatus[0x28]==1 && keystatus[0x15]==1) // ' y + { + keystatus[0x15] = 0; + purpleon=!purpleon; if(nosprites>3) nosprites=0; + if(purpleon) printext256(1*4,1*8,11,-1,"Purple ON",0); + else printext256(1*4,1*8,11,-1,"Purple OFF",0); + } + + if(keystatus[0x28]==1 && keystatus[0x2e]==1) // ' C + { + keystatus[0x2e] = 0; + switch (searchstat) + { + case 0: case 4: + for(i=0;i0) // TAB : USED + { + usedcount=!usedcount; + + count=0; + for(i=0;i>= 1; + sector[i].floorz >>= 1; + } + for(i=0;i>= 1; + wall[i].y >>= 1; + wall[i].yrepeat = min(wall[i].yrepeat<<1,255); + } + for(i=0;i>= 1; + sprite[i].y >>= 1; + sprite[i].z >>= 1; + sprite[i].xrepeat = max(sprite[i].xrepeat>>1,1); + sprite[i].yrepeat = max(sprite[i].yrepeat>>1,1); + } + } + + +/* shrink + if(keystatus[0x28]==1 && keystatus[0x0b]==1) // ' 0 + { + keystatus[0x0b]=0; + for(i=0;i>= 1; + sector[i].floorz >>= 1; + } + for(i=0;i>= 1; + wall[i].y >>= 1; + wall[i].yrepeat = min(wall[i].yrepeat<<1,255); + } + for(i=0;i>= 1; + sprite[i].y >>= 1; + sprite[i].z >>= 1; + sprite[i].xrepeat = max(sprite[i].xrepeat>>1,1); + sprite[i].yrepeat = max(sprite[i].yrepeat>>1,1); + } + } +*/ + + + if(keystatus[0x28]==1 && keystatus[0x02]==1) // ' 1 + { on2d3d=!on2d3d; keystatus[0x02]=0; + } + + if(keystatus[0x28]==1 && keystatus[0x04]==1) // ' 3 + { onnames++; if(onnames>6) onnames=0; + keystatus[0x04]=0; + sprintf(tempbuf,"Mode %d %s",onnames,Mode32d[onnames]); + printmessage16(tempbuf); +// clearmidstatbar16(); +// for(i=0;i=20 && sprite[i].picnum<=59) + { + sprite[i].xrepeat = 32; + sprite[i].yrepeat = 32; + } + } + + } +*/ + + + /* Motorcycle ha ha ha + if(keystatus[0x28]==1 && keystatus[0x06]==1) // ' 5 + { + keystatus[0x06]=0; + sidemode++; if (sidemode > 2) sidemode = 0; + if (sidemode == 1) + { + editstatus = 0; + zmode = 2; + posz = ((sector[cursectnum].ceilingz+sector[cursectnum].floorz)>>1); + } + else + { + editstatus = 1; + zmode = 1; + } + } + */ + + if(keystatus[0x28]==1 && keystatus[0x0a]==1) // ' 9 : swap hilo + { keystatus[0x0b]=0; + temp=sprite[cursprite].lotag; + sprite[cursprite].lotag=sprite[cursprite].hitag; + sprite[cursprite].hitag=temp; + } + + if(keystatus[0x28]==1 && keystatus[0x32]==1) // ' m : Memory Usage + { keystatus[0x32]=0; + TotalMem(); + } + + +}// end key2d + + +void ExtInit(void) +{ + long fil; + + printf("------------------------------------------------------------------------------\n"); + printf("BUILD.EXE Copyright (c) 1993 - 1996 Ken Silverman, 3D Realms Entertainment.\n"); + printf("This version of BUILD was created for Duke Nukem 3D and parts were modified\n"); + printf("by Allen H. Blum III.\n"); + printf("\n"); + printf("IMPORTANT: The Build Editor and associated tools and utilities are NOT\n"); + printf("shareware and may NOT be freely distributed to any BBS, CD, floppy, or\n"); + printf("any other media. These tools may NOT be sold or repackaged for sale in\n"); + printf("a commercial product.\n"); + printf("\n"); + printf("Any levels created with these editors and tools may only be used with the\n"); + printf("full (registered) copy of Duke Nukem 3D, and not the shareware version.\n"); + printf("Please refer to LICENSE.DOC for further information on levels created with\n"); + printf("BUILD.EXE.\n"); + printf("\n"); + printf("Please help us protect against software piracy (which drives up software\n"); + printf("prices) by following these simple rules.\n"); + printf("\n"); + printf("Thank You!\n"); + printf("------------------------------------------------------------------------------\n"); + //getch(); + + initgroupfile("duke3d.grp"); + + if ((fil = kopen4load("setup.dat",0)) != -1) + { + kread(fil,option,NUMOPTIONS); + kread(fil,keys,NUMKEYS); + memcpy((void *)buildkeys,(void *)keys,NUMKEYS); //Trick to make build use setup.dat keys + kclose(fil); + } + // if (option[3] != 0) moustat = + initmouse(); + +// CTW - MODIFICATION +// I just updated this quickly to force it to work. +// You'll want to update it properly to support other video modes. + initengine(); + setgamemode(2,320L,200L); +/* switch(option[0]+1) + { + case 1: initengine(1,vesares[option[6]&15][0],vesares[option[6]&15][1]); break; + default: initengine(option[0]+1,320L,200L); break; + }*/ + +// CTW END - MODIFICATION + + kensplayerheight = 40; //32 + zmode = 1; + zlock = kensplayerheight<<8; + defaultspritecstat = 0; + + ReadPaletteTable(); +// InitWater(); +} + +void ExtUnInit(void) +{ + uninitgroupfile(); +} + +static char lockbyte4094; +void ExtPreCheckKeys(void) // just before drawrooms +{ + if (qsetmode == 200) //In 3D mode + { + if(purpleon) clearview(255); + if (sidemode != 0) + { + lockbyte4094 = 1; + if (waloff[4094] == 0) + allocache(&waloff[4094],320L*200L,&lockbyte4094); + setviewtotile(4094,320L,200L); + searchx ^= searchy; searchy ^= searchx; searchx ^= searchy; + searchx = ydim-1-searchx; + } + } +} + +void ExtAnalyzeSprites(void) +{ + long i, j, k; + spritetype *tspr; + char frames=0; + + for(i=0,tspr=&tsprite[0];ipicnum<11) tspr->xrepeat=0; + + if(nosprites==1||nosprites==3) + switch(tspr->picnum) + { + case SEENINE : + tspr->xrepeat=0; + } + + switch(tspr->picnum) + { +// 5-frame walk + case 1550 : // Shark + frames=5; + + +// 2-frame walk + case 1445 : // duke kick + case LIZTROOPSHOOT : + case LIZTROOPDUCKING : + case 2030 : // pig shot + case PIGCOPDIVE : + case 2190 : // liz capt shot + case BOSS1SHOOT : + case BOSS1LOB : + if(frames==0) frames=2; + +// 4-frame walk + case 1491 : // duke crawl + case LIZTROOP : + case LIZTROOPRUNNING : + case PIGCOP : + case LIZMAN : + case BOSS1 : + case BOSS2 : + case BOSS3 : + if(frames==0) frames=4; + + case LIZTROOPJETPACK : + case OCTABRAIN : + case DRONE : + case COMMANDER : + case RECON : + if(frames==0) frames=10; + + case GREENSLIME : + case EGG : + case PIGCOPSTAYPUT : + case LIZMANSTAYPUT: + case LIZTROOPSTAYPUT : + case LIZMANSPITTING : + case LIZMANFEEDING : + case LIZMANJUMP : + if(skill!=4) + { + if(tspr->lotag>skill) + { tspr->xrepeat=0; break; } + } + case APLAYER : + + if(nosprites==2||nosprites==3) + { tspr->xrepeat=0; +// tspr->cstat|=32768; + } +// else tspr->cstat&=32767; + + if(frames!=0) + { + if(frames==10) frames=0; + k = getangle(tspr->x-posx,tspr->y-posy); + k = (((tspr->ang+3072+128-k)&2047)>>8)&7; + //This guy has only 5 pictures for 8 angles (3 are x-flipped) + if (k <= 4) + { + tspr->picnum += k; + tspr->cstat &= 0xfb; //clear x-flipping bit + } + else + { + tspr->picnum += 8-k; + tspr->cstat |= 4; //set x-flipping bit + } + } + + if(frames==2) tspr->picnum+=((((4-totalclock>>6))&1)*5); + if(frames==4) tspr->picnum+=((((4-totalclock>>6))&3)*5); + if(frames==5) tspr->picnum+=(((totalclock>>6)%5))*5; + + if(tilesizx[tspr->picnum] == 0) + tspr->picnum -= 5; //Hack, for actors + + break; + default: + break; + + + } + } +} + + + + +int intro=0; + +void ExtCheckKeys(void) +{ + long i,count,nexti; + short statnum=0; + if (qsetmode == 200) //In 3D mode + { + if (sidemode != 0) + { + setviewback(); + + + // !!! FIXME: This doesn't compile! + //rotatesprite(320<<15,200<<15,65536,(horiz-100)<<2,4094,0,0,2+4); + + + + lockbyte4094 = 0; + searchx = ydim-1-searchx; + searchx ^= searchy; searchy ^= searchx; searchx ^= searchy; + +// overwritesprite(160L,170L,1153,0,1+2,0); + + + // !!! FIXME: This doesn't compile! + //rotatesprite(160<<16,170<<16,65536,(100-horiz+1024)<<3,1153,0,0,2); + + } + + if(intro<100) + { + intro++; +// rotatesprite((160-8)<<16,(100-8)<<16,(200-intro)<<9,0,SPINNINGNUKEICON+(((4-totalclock>>3))&7),0,0,0,0,0,xdim-1,ydim-1); + Ver(); + } + + Keys3d(); + if (sidemode != 1) editinput(); + if(usedcount) + { + if(tabgraphic) + rotatesprite((320-32)<<16,(64)<<16,64<<9,0,temppicnum,0,0,0,0,0,xdim-1,ydim-1); + if(searchstat!=3) + { + count=0; + for(i=0;i=5) counter=0; + + if (totalclock < ototalclock+TICSPERFRAME) return; + if (qsetmode != 200) return; + if (sidemode != 1) return; + ototalclock = totalclock; + + oposx = posx; oposy = posy; + hitwall = clipmove(&posx,&posy,&posz,&cursectnum,xvel,yvel,128L,4L<<8,4L<<8,0); + xvel = ((posx-oposx)<<14); yvel = ((posy-oposy)<<14); + + yvel += 80000; + if ((hitwall&0xc000) == 32768) + { + hitwall &= (MAXWALLS-1); + i = wall[hitwall].point2; + daang = getangle(wall[i].x-wall[hitwall].x,wall[i].y-wall[hitwall].y); + + xvel -= (xvel>>4); + if (xvel < 0) xvel++; + if (xvel > 0) xvel--; + + yvel -= (yvel>>4); + if (yvel < 0) yvel++; + if (yvel > 0) yvel--; + + i = 4-keystatus[buildkeys[4]]; + xvel += mulscale(vel,(long)sintable[(ang+512)&2047],i); + yvel += mulscale(vel,(long)sintable[ang&2047],i); + + if (((daang-ang)&2047) < 1024) + ang = ((ang+((((daang-ang)&2047)+24)>>4))&2047); + else + ang = ((ang-((((ang-daang)&2047)+24)>>4))&2047); + + timeoff = ototalclock; + } + else + { + if (ototalclock > timeoff+32) + ang = ((ang+((timeoff+32-ototalclock)>>4))&2047); + } + + getzrange(posx,posy,posz,cursectnum,&hiz,&hihit,&loz,&lohit,128L,0); + + oposx -= posx; oposy -= posy; + + dist = ksqrt(oposx*oposx+oposy*oposy); + if (ototalclock > timeoff+32) dist = 0; + + daang = mulscale(dist,angvel,9); + posz += (daang<<6); + if (posz > loz-(4<<8)) posz = loz-(4<<8), hvel = 0; + if (posz < hiz+(4<<8)) posz = hiz+(4<<8), hvel = 0; + + horiz = ((horiz*7+(100-(daang>>1)))>>3); + if (horiz < 100) horiz++; + if (horiz > 100) horiz--; + + if(keystatus[0x28]==1 && keystatus[0x06]==1) // ' 5 + { + keystatus[0x06]=0; + editstatus = 1; + sidemode = 2; + } +} + +ActorMem(int i) +{int total=0,j; + switch(i) + { + case APLAYER : + for(j=APLAYER;j<(APLAYER+131);j++) total +=tilesizx[j]*tilesizy[j]; + for(j=1780;j<(1780+32);j++) total +=tilesizx[j]*tilesizy[j]; + break; + case LIZTROOP : + case LIZTROOPRUNNING : + case LIZTROOPSTAYPUT : + case LIZTROOPSHOOT : + case LIZTROOPJETPACK : + case LIZTROOPONTOILET : + case LIZTROOPDUCKING : + for(j=LIZTROOP;j<(LIZTROOP+100);j++) total +=tilesizx[j]*tilesizy[j]; + break; + case OCTABRAIN : + for(j=OCTABRAIN;j<(OCTABRAIN+40);j++) total +=tilesizx[j]*tilesizy[j]; + break; + case DRONE : + for(j=DRONE;j<(DRONE+10);j++) total +=tilesizx[j]*tilesizy[j]; + break; + case COMMANDER : + for(j=COMMANDER;j<(COMMANDER+40);j++) total +=tilesizx[j]*tilesizy[j]; + break; + case RECON : + for(j=RECON;j<(RECON+10);j++) total +=tilesizx[j]*tilesizy[j]; + break; + case PIGCOP : + for(j=PIGCOP;j<(PIGCOP+61);j++) total +=tilesizx[j]*tilesizy[j]; + break; + case LIZMAN : + case LIZMANSTAYPUT: + case LIZMANSPITTING : + case LIZMANFEEDING : + case LIZMANJUMP : + for(j=LIZMAN;j<(LIZMAN+80);j++) total +=tilesizx[j]*tilesizy[j]; + break; + case BOSS1 : + for(j=BOSS1;j<(BOSS1+60);j++) total +=tilesizx[j]*tilesizy[j]; + break; + case BOSS2 : + for(j=BOSS2;j<(BOSS2+50);j++) total +=tilesizx[j]*tilesizy[j]; + break; + case BOSS3 : + for(j=BOSS3;j<(BOSS3+50);j++) total +=tilesizx[j]*tilesizy[j]; + break; + + default: total += tilesizx[i]*tilesizy[i]; + } + return(total); +} + +int curpalette=0; + +SetBOSS1Palette() +{int x; + if(curpalette==3) return; + curpalette=3; + kensetpalette(BOSS1palette); +} + + +SetSLIMEPalette() +{int x; + if(curpalette==2) return; + curpalette=2; + kensetpalette(SLIMEpalette); +} + +SetWATERPalette() +{int x; + if(curpalette==1) return; + curpalette=1; + kensetpalette(WATERpalette); +} + + +SetGAMEPalette() +{int x; + if(curpalette==0) return; + curpalette=0; + kensetpalette(GAMEpalette); +} + +kensetpalette(char *vgapal) +{ + long i; + char vesapal[1024]; + + for(i=0;i<256;i++) + { + vesapal[i*4+0] = vgapal[i*3+2]; + vesapal[i*4+1] = vgapal[i*3+1]; + vesapal[i*4+2] = vgapal[i*3+0]; + vesapal[i*4+3] = 0; + } + VBE_setPalette(0L,256L,vesapal); +} + +SearchSectorsForward() +{ + long ii=0; + if(cursector_lotag!=0) + { + if(cursectornum Sector Search : Found"); +// cursectornum++; + keystatus[0x1b]=0; // ] + return; + } + cursectornum++; + } + } + printmessage16("> Sector Search : none"); +} + +SearchSectorsBackward() +{ + long ii=0; + if(cursector_lotag!=0) + { + if(cursectornum>0) cursectornum--; + for(ii=cursectornum;ii>=0;ii--) + { + if(sector[ii].lotag==cursector_lotag) + { + posx=wall[sector[ii].wallptr].x; + posy=wall[sector[ii].wallptr].y; + printmessage16("< Sector Search : Found"); +// cursectornum--; + keystatus[0x1a]=0; // [ + return; + } + cursectornum--; + } + } + printmessage16("< Sector Search : none"); +} + + + diff --git a/audiolib/Makefile b/audiolib/Makefile new file mode 100755 index 0000000..26c4a44 --- /dev/null +++ b/audiolib/Makefile @@ -0,0 +1,24 @@ +CC=gcc +AR=ar +RANLIB=ranlib +CFLAGS=-m32 -g -O2 +LDLIBS= + +CFLAGS += $(shell /usr/bin/32/sdl-config --cflags) +LDLIBS += $(shell /usr/bin/32/sdl-config --libs) + +OBJ=fx_man.o dsl.o ll_man.o multivoc.o mv_mix.o mvreverb.o nodpmi.o \ + pitch.o user.o usrhooks.o + +audiolib.a: $(OBJ) + rm -rf $@ + $(AR) rc $@ $^ +ifneq ($(strip $(solaris)),true) + $(RANLIB) $@ +endif + +clean: + rm -rf audiolib.a *.o + +distclean: clean + rm -rf *~ diff --git a/audiolib/_al_midi.h b/audiolib/_al_midi.h new file mode 100755 index 0000000..4e58749 --- /dev/null +++ b/audiolib/_al_midi.h @@ -0,0 +1,174 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef ___AL_MIDI_H +#define ___AL_MIDI_H + +#define NO_ADLIB_DETECTION "NOAL" + +#define STEREO_DETUNE 5 + +#define lobyte( num ) ( ( unsigned )*( ( char * )&( num ) ) ) +#define hibyte( num ) ( ( unsigned )*( ( ( char * )&( num ) ) + 1 ) ) + +#define AL_VoiceNotFound -1 + +#define alFreqH 0xb0 +#define alEffects 0xbd + +/* Number of slots for the voices on the chip */ +#define NumChipSlots 18 + +#define NUM_VOICES 9 +#define NUM_CHANNELS 16 + +#define NOTE_ON 0x2000 /* Used to turn note on or toggle note */ +#define NOTE_OFF 0x0000 + +#define MAX_VELOCITY 0x7f +#define MAX_OCTAVE 7 +#define MAX_NOTE ( MAX_OCTAVE * 12 + 11 ) +#define FINETUNE_MAX 31 +#define FINETUNE_RANGE ( FINETUNE_MAX + 1 ) + +#define PITCHBEND_CENTER 1638400 + +#define note_off 0x80 +#define note_on 0x90 +#define poly_aftertouch 0xa0 +#define control_change 0xb0 +#define program_chng 0xc0 +#define channel_aftertouch 0xd0 +#define pitch_wheel 0xe0 + +#define MIDI_VOLUME 7 +#define MIDI_PAN 10 +#define MIDI_DETUNE 94 +#define MIDI_ALL_NOTES_OFF 0x7B +#define MIDI_RESET_ALL_CONTROLLERS 0x79 +#define MIDI_RPN_MSB 100 +#define MIDI_RPN_LSB 101 +#define MIDI_DATAENTRY_MSB 6 +#define MIDI_DATAENTRY_LSB 38 +#define MIDI_PITCHBEND_RPN 0 + +enum cromatic_scale + { + C = 0x157, + C_SHARP = 0x16B, + D_FLAT = 0x16B, + D = 0x181, + D_SHARP = 0x198, + E_FLAT = 0x198, + E = 0x1B0, + F_FLAT = 0x1B0, + E_SHARP = 0x1CA, + F = 0x1CA, + F_SHARP = 0x1E5, + G_FLAT = 0x1E5, + G = 0x202, + G_SHARP = 0x220, + A_FLAT = 0x220, + A = 0x241, + A_SHARP = 0x263, + B_FLAT = 0x263, + B = 0x287, + C_FLAT = 0x287, + B_SHARP = 0x2AE, + }; + +/* Definition of octave information to be ORed onto F-Number */ + +enum octaves + { + OCTAVE_0 = 0x0000, + OCTAVE_1 = 0x0400, + OCTAVE_2 = 0x0800, + OCTAVE_3 = 0x0C00, + OCTAVE_4 = 0x1000, + OCTAVE_5 = 0x1400, + OCTAVE_6 = 0x1800, + OCTAVE_7 = 0x1C00 + }; + +typedef struct VOICE + { + struct VOICE *next; + struct VOICE *prev; + + unsigned num; + unsigned key; + unsigned velocity; + unsigned channel; + unsigned pitchleft; + unsigned pitchright; + int timbre; + int port; + unsigned status; + } VOICE; + +typedef struct + { + VOICE *start; + VOICE *end; + } VOICELIST; + +typedef struct + { + VOICELIST Voices; + int Timbre; + int Pitchbend; + int KeyOffset; + unsigned KeyDetune; + unsigned Volume; + unsigned EffectiveVolume; + int Pan; + int Detune; + unsigned RPN; + short PitchBendRange; + short PitchBendSemiTones; + short PitchBendHundreds; + } CHANNEL; + +typedef struct + { + unsigned char SAVEK[ 2 ]; + unsigned char Level[ 2 ]; + unsigned char Env1[ 2 ]; + unsigned char Env2[ 2 ]; + unsigned char Wave[ 2 ]; + unsigned char Feedback; + signed char Transpose; + signed char Velocity; + } TIMBRE; + +extern TIMBRE ADLIB_TimbreBank[ 256 ]; + +static void AL_ResetVoices( void ); +static void AL_CalcPitchInfo( void ); +static void AL_SetVoiceTimbre( int voice ); +static void AL_SetVoiceVolume( int voice ); +static int AL_AllocVoice( void ); +static int AL_GetVoice( int channel, int key ); +static void AL_SetVoicePitch( int voice ); +static void AL_SetChannelVolume( int channel, int volume ); +static void AL_SetChannelPan( int channel, int pan ); +static void AL_SetChannelDetune( int channel, int detune ); + +#endif diff --git a/audiolib/_blaster.h b/audiolib/_blaster.h new file mode 100755 index 0000000..49f8220 --- /dev/null +++ b/audiolib/_blaster.h @@ -0,0 +1,133 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: _BLASTER.H + + author: James R. Dose + date: February 4, 1994 + + Private header for for BLASTER.C + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#ifndef ___BLASTER_H +#define ___BLASTER_H + +#define VALID ( 1 == 1 ) +#define INVALID ( !VALID ) + +#define TRUE ( 1 == 1 ) +#define FALSE ( !TRUE ) + +#define YES ( 1 == 1 ) +#define NO ( !YES ) + +#define lobyte( num ) ( ( int )*( ( char * )&( num ) ) ) +#define hibyte( num ) ( ( int )*( ( ( char * )&( num ) ) + 1 ) ) + +#define BLASTER_MixerAddressPort 0x04 +#define BLASTER_MixerDataPort 0x05 +#define BLASTER_ResetPort 0x06 +#define BLASTER_ReadPort 0x0A +#define BLASTER_WritePort 0x0C +#define BLASTER_DataAvailablePort 0x0E +#define BLASTER_Ready 0xAA +#define BLASTER_16BitDMAAck 0x0F + +#define MIXER_DSP4xxISR_Ack 0x82 +#define MIXER_DSP4xxISR_Enable 0x83 +#define MIXER_MPU401_INT 0x4 +#define MIXER_16BITDMA_INT 0x2 +#define MIXER_8BITDMA_INT 0x1 +#define MIXER_DisableMPU401Interrupts 0xB +#define MIXER_SBProOutputSetting 0x0E +#define MIXER_SBProStereoFlag 0x02 +#define MIXER_SBProVoice 0x04 +#define MIXER_SBProMidi 0x26 +#define MIXER_SB16VoiceLeft 0x32 +#define MIXER_SB16VoiceRight 0x33 +#define MIXER_SB16MidiLeft 0x34 +#define MIXER_SB16MidiRight 0x35 + +#define DSP_Version1xx 0x0100 +#define DSP_Version2xx 0x0200 +#define DSP_Version201 0x0201 +#define DSP_Version3xx 0x0300 +#define DSP_Version4xx 0x0400 +#define DSP_SB16Version DSP_Version4xx + +#define DSP_MaxNormalRate 22000 +#define DSP_MaxHighSpeedRate 44000 + +#define DSP_8BitAutoInitRecord 0x2c +#define DSP_8BitHighSpeedAutoInitRecord 0x98 +#define DSP_Old8BitADC 0x24 +#define DSP_8BitAutoInitMode 0x1c +#define DSP_8BitHighSpeedAutoInitMode 0x90 +#define DSP_SetBlockLength 0x48 +#define DSP_Old8BitDAC 0x14 +#define DSP_16BitDAC 0xB6 +#define DSP_8BitDAC 0xC6 +#define DSP_8BitADC 0xCe +#define DSP_SetTimeConstant 0x40 +#define DSP_Set_DA_Rate 0x41 +#define DSP_Set_AD_Rate 0x42 +#define DSP_Halt8bitTransfer 0xd0 +#define DSP_Continue8bitTransfer 0xd4 +#define DSP_Halt16bitTransfer 0xd5 +#define DSP_Continue16bitTransfer 0xd6 +#define DSP_SpeakerOn 0xd1 +#define DSP_SpeakerOff 0xd3 +#define DSP_GetVersion 0xE1 +#define DSP_Reset 0xFFFF + +#define DSP_SignedBit 0x10 +#define DSP_StereoBit 0x20 + +#define DSP_UnsignedMonoData 0x00 +#define DSP_SignedMonoData ( DSP_SignedBit ) +#define DSP_UnsignedStereoData ( DSP_StereoBit ) +#define DSP_SignedStereoData ( DSP_SignedBit | DSP_StereoBit ) + +#define BlasterEnv_Address 'A' +#define BlasterEnv_Interrupt 'I' +#define BlasterEnv_8bitDma 'D' +#define BlasterEnv_16bitDma 'H' +#define BlasterEnv_Type 'T' +#define BlasterEnv_Midi 'P' +#define BlasterEnv_EmuAddress 'E' + +#define CalcTimeConstant( rate, samplesize ) \ + ( ( 65536L - ( 256000000L / ( ( samplesize ) * ( rate ) ) ) ) >> 8 ) + +#define CalcSamplingRate( tc ) \ + ( 256000000L / ( 65536L - ( tc << 8 ) ) ) + +typedef struct + { + int IsSupported; + int HasMixer; + int MaxMixMode; + int MinSamplingRate; + int MaxSamplingRate; + } CARD_CAPABILITY; + +#endif diff --git a/audiolib/_guswave.h b/audiolib/_guswave.h new file mode 100755 index 0000000..c7e5097 --- /dev/null +++ b/audiolib/_guswave.h @@ -0,0 +1,164 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + file: _GUSWAVE.H + + author: James R. Dose + date: March 23, 1994 + + Private header for GUSWAVE.C + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#ifndef ___GUSWAVE_H +#define ___GUSWAVE_H + +#define TRUE ( 1 == 1 ) +#define FALSE ( !TRUE ) + +#define LOADDS _loadds + +#define VOC_8BIT 0x0 +#define VOC_CT4_ADPCM 0x1 +#define VOC_CT3_ADPCM 0x2 +#define VOC_CT2_ADPCM 0x3 +#define VOC_16BIT 0x4 +#define VOC_ALAW 0x6 +#define VOC_MULAW 0x7 +#define VOC_CREATIVE_ADPCM 0x200 + +#define MAX_BLOCK_LENGTH 0x8000 + +#define GF1BSIZE 896L /* size of buffer per wav on GUS */ +//#define GF1BSIZE 512L /* size of buffer per wav on GUS */ + +//#define VOICES 8 /* maximum amount of concurrent wav files */ +#define VOICES 2 /* maximum amount of concurrent wav files */ +#define MAX_VOICES 32 /* This should always be 32 */ +#define MAX_VOLUME 4095 +#define BUFFER 2048U /* size of DMA buffer for patch loading */ + +typedef enum + { + Raw, + VOC, + DemandFeed, + WAV + } wavedata; + +typedef enum + { + NoMoreData, + KeepPlaying, + SoundDone + } playbackstatus; + + +typedef volatile struct VoiceNode + { + struct VoiceNode *next; + struct VoiceNode *prev; + + wavedata wavetype; + int bits; + playbackstatus ( *GetSound )( struct VoiceNode *voice ); + + int num; + + unsigned long mem; /* location in ultrasound memory */ + int Active; /* this instance in use */ + int GF1voice; /* handle to active voice */ + + char *NextBlock; + char *LoopStart; + char *LoopEnd; + unsigned LoopCount; + unsigned long LoopSize; + unsigned long BlockLength; + + unsigned long PitchScale; + + unsigned char *sound; + unsigned long length; + unsigned long SamplingRate; + unsigned long RateScale; + int Playing; + + int handle; + int priority; + + void ( *DemandFeed )( char **ptr, unsigned long *length ); + + unsigned long callbackval; + + int Volume; + int Pan; + } +VoiceNode; + +typedef struct + { + VoiceNode *start; + VoiceNode *end; + } +voicelist; + +typedef volatile struct voicestatus + { + VoiceNode *Voice; + int playing; + } +voicestatus; + +typedef struct + { + char RIFF[ 4 ]; + unsigned long file_size; + char WAVE[ 4 ]; + char fmt[ 4 ]; + unsigned long format_size; + } riff_header; + +typedef struct + { + unsigned short wFormatTag; + unsigned short nChannels; + unsigned long nSamplesPerSec; + unsigned long nAvgBytesPerSec; + unsigned short nBlockAlign; + unsigned short nBitsPerSample; + } format_header; + +typedef struct + { + unsigned char DATA[ 4 ]; + unsigned long size; + } data_header; + +playbackstatus GUSWAVE_GetNextVOCBlock( VoiceNode *voice ); +VoiceNode *GUSWAVE_GetVoice( int handle ); + +int GUSWAVE_Play( VoiceNode *voice, int angle, int volume, int channels ); + +VoiceNode *GUSWAVE_AllocVoice( int priority ); +static int GUSWAVE_InitVoices( void ); + +#endif diff --git a/audiolib/_midi.h b/audiolib/_midi.h new file mode 100755 index 0000000..d96bd1e --- /dev/null +++ b/audiolib/_midi.h @@ -0,0 +1,290 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: _MIDI.H + + author: James R. Dose + date: May 25, 1994 + + Private header for MIDI.C. Midi song file playback routines. + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#ifndef ___MIDI_H +#define ___MIDI_H + +#define RELATIVE_BEAT( measure, beat, tick ) \ + ( ( tick ) + ( ( beat ) << 9 ) + ( ( measure ) << 16 ) ) + +//Bobby Prince thinks this may be 100 +//#define GENMIDI_DefaultVolume 100 +#define GENMIDI_DefaultVolume 90 + +#define MAX_FORMAT 1 + +#define NUM_MIDI_CHANNELS 16 + +#define TIME_PRECISION 16 + +#define MIDI_HEADER_SIGNATURE 0x6468544d // "MThd" +#define MIDI_TRACK_SIGNATURE 0x6b72544d // "MTrk" + +#define MIDI_VOLUME 7 +#define MIDI_PAN 10 +#define MIDI_DETUNE 94 +#define MIDI_RHYTHM_CHANNEL 9 +#define MIDI_RPN_MSB 100 +#define MIDI_RPN_LSB 101 +#define MIDI_DATAENTRY_MSB 6 +#define MIDI_DATAENTRY_LSB 38 +#define MIDI_PITCHBEND_MSB 0 +#define MIDI_PITCHBEND_LSB 0 +#define MIDI_RUNNING_STATUS 0x80 +#define MIDI_NOTE_OFF 0x8 +#define MIDI_NOTE_ON 0x9 +#define MIDI_POLY_AFTER_TCH 0xA +#define MIDI_CONTROL_CHANGE 0xB +#define MIDI_PROGRAM_CHANGE 0xC +#define MIDI_AFTER_TOUCH 0xD +#define MIDI_PITCH_BEND 0xE +#define MIDI_SPECIAL 0xF +#define MIDI_SYSEX 0xF0 +#define MIDI_SYSEX_CONTINUE 0xF7 +#define MIDI_META_EVENT 0xFF +#define MIDI_END_OF_TRACK 0x2F +#define MIDI_TEMPO_CHANGE 0x51 +#define MIDI_TIME_SIGNATURE 0x58 +#define MIDI_RESET_ALL_CONTROLLERS 0x79 +#define MIDI_ALL_NOTES_OFF 0x7b +#define MIDI_MONO_MODE_ON 0x7E +#define MIDI_SYSTEM_RESET 0xFF + +#define GET_NEXT_EVENT( track, data ) \ + ( data ) = *( track )->pos; \ + ( track )->pos += 1 + +#define GET_MIDI_CHANNEL( event ) ( ( event ) & 0xf ) +#define GET_MIDI_COMMAND( event ) ( ( event ) >> 4 ) + +#define EMIDI_INFINITE -1 +#define EMIDI_END_LOOP_VALUE 127 +#define EMIDI_ALL_CARDS 127 +#define EMIDI_INCLUDE_TRACK 110 +#define EMIDI_EXCLUDE_TRACK 111 +#define EMIDI_PROGRAM_CHANGE 112 +#define EMIDI_VOLUME_CHANGE 113 +#define EMIDI_CONTEXT_START 114 +#define EMIDI_CONTEXT_END 115 +#define EMIDI_LOOP_START 116 +#define EMIDI_LOOP_END 117 +#define EMIDI_SONG_LOOP_START 118 +#define EMIDI_SONG_LOOP_END 119 + +#define EMIDI_GeneralMIDI 0 +#define EMIDI_SoundCanvas 1 +#define EMIDI_AWE32 2 +#define EMIDI_WaveBlaster 3 +#define EMIDI_SoundBlaster 4 +#define EMIDI_ProAudio 5 +#define EMIDI_SoundMan16 6 +#define EMIDI_Adlib 7 +#define EMIDI_Soundscape 8 +#define EMIDI_Ultrasound 9 + +#define EMIDI_AffectsCurrentCard( c, type ) \ + ( ( ( c ) == EMIDI_ALL_CARDS ) || ( ( c ) == ( type ) ) ) + + +#define EMIDI_NUM_CONTEXTS 7 +typedef struct + { + unsigned char *pos; + unsigned char *loopstart; + short loopcount; + short RunningStatus; + unsigned time; + long FPSecondsPerTick; + short tick; + short beat; + short measure; + short BeatsPerMeasure; + short TicksPerBeat; + short TimeBase; + long delay; + short active; + } songcontext; + +typedef struct + { + unsigned char *start; + unsigned char *pos; + + long delay; + short active; + short RunningStatus; + + short currentcontext; + songcontext context[ EMIDI_NUM_CONTEXTS ]; + + char EMIDI_IncludeTrack; + char EMIDI_ProgramChange; + char EMIDI_VolumeChange; + } track; + +static long _MIDI_ReadNumber( void *from, size_t size ); +static long _MIDI_ReadDelta( track *ptr ); +static void _MIDI_ResetTracks( void ); +static void _MIDI_AdvanceTick( void ); +static void _MIDI_MetaEvent( track *Track ); +static void _MIDI_SysEx( track *Track ); +static int _MIDI_InterpretControllerInfo( track *Track, int TimeSet, + int channel, int c1, int c2 ); +//static + void _MIDI_ServiceRoutine( task *Task ); +static int _MIDI_SendControlChange( int channel, int c1, int c2 ); +static void _MIDI_SetChannelVolume( int channel, int volume ); +static void _MIDI_SendChannelVolumes( void ); +static int _MIDI_ProcessNextTick( void ); +static void _MIDI_InitEMIDI( void ); + +/* + if ( c1 == EMIDI_LOOP_START ) + { + if ( c2 == 0 ) + { + Track->context[ 0 ].loopcount = EMIDI_INFINITE; + } + else + { + Track->context[ 0 ].loopcount = c2; + } + + Track->context[ 0 ].pos = Track->pos; + Track->context[ 0 ].loopstart = Track->pos; + Track->context[ 0 ].RunningStatus = Track->RunningStatus; + Track->context[ 0 ].time = _MIDI_Time; + Track->context[ 0 ].FPSecondsPerTick = _MIDI_FPSecondsPerTick; + Track->context[ 0 ].tick = _MIDI_Tick; + Track->context[ 0 ].beat = _MIDI_Beat; + Track->context[ 0 ].measure = _MIDI_Measure; + Track->context[ 0 ].BeatsPerMeasure = _MIDI_BeatsPerMeasure; + Track->context[ 0 ].TicksPerBeat = _MIDI_TicksPerBeat; + Track->context[ 0 ].TimeBase = _MIDI_TimeBase; + break; + } + + if ( ( c1 == EMIDI_LOOP_END ) && + ( c2 == EMIDI_END_LOOP_VALUE ) ) + { + if ( ( Track->context[ 0 ].loopstart != NULL ) && + ( Track->context[ 0 ].loopcount != 0 ) ) + { + if ( Track->context[ 0 ].loopcount != EMIDI_INFINITE ) + { + Track->context[ 0 ].loopcount--; + } + + Track->pos = Track->context[ 0 ].loopstart; + Track->RunningStatus = Track->context[ 0 ].RunningStatus; + + if ( !TimeSet ) + { + _MIDI_Time = Track->context[ 0 ].time; + _MIDI_FPSecondsPerTick = Track->context[ 0 ].FPSecondsPerTick; + _MIDI_Tick = Track->context[ 0 ].tick; + _MIDI_Beat = Track->context[ 0 ].beat; + _MIDI_Measure = Track->context[ 0 ].measure; + _MIDI_BeatsPerMeasure = Track->context[ 0 ].BeatsPerMeasure; + _MIDI_TicksPerBeat = Track->context[ 0 ].TicksPerBeat; + _MIDI_TimeBase = Track->context[ 0 ].TimeBase; + TimeSet = TRUE; + } + } + break; + } + + if ( c1 == MIDI_MONO_MODE_ON ) + { + Track->pos++; + } + + if ( ( c1 == MIDI_VOLUME ) && ( !Track->EMIDI_VolumeChange ) ) + { + _MIDI_SetChannelVolume( channel, c2 ); + break; + } + else if ( ( c1 == EMIDI_VOLUME_CHANGE ) && + ( Track->EMIDI_VolumeChange ) ) + { + _MIDI_SetChannelVolume( channel, c2 ); + break; + } + + if ( ( c1 == EMIDI_PROGRAM_CHANGE ) && + ( Track->EMIDI_ProgramChange ) ) + { + _MIDI_Funcs->ProgramChange( channel, MIDI_PatchMap[ c2 & 0x7f ] ); + break; + } + + if ( c1 == EMIDI_CONTEXT_START ) + { + break; + } + + if ( c1 == EMIDI_CONTEXT_END ) + { + if ( ( Track->currentcontext != _MIDI_Context ) || + ( Track->context[ _MIDI_Context ].pos == NULL ) + { + break; + } + + Track->currentcontext = _MIDI_Context; + Track->context[ 0 ].loopstart = Track->context[ _MIDI_Context ].loopstart; + Track->context[ 0 ].loopcount = Track->context[ _MIDI_Context ].loopcount; + Track->pos = Track->context[ _MIDI_Context ].pos; + Track->RunningStatus = Track->context[ _MIDI_Context ].RunningStatus; + + if ( TimeSet ) + { + break; + } + + _MIDI_Time = Track->context[ _MIDI_Context ].time; + _MIDI_FPSecondsPerTick = Track->context[ _MIDI_Context ].FPSecondsPerTick; + _MIDI_Tick = Track->context[ _MIDI_Context ].tick; + _MIDI_Beat = Track->context[ _MIDI_Context ].beat; + _MIDI_Measure = Track->context[ _MIDI_Context ].measure; + _MIDI_BeatsPerMeasure = Track->context[ _MIDI_Context ].BeatsPerMeasure; + _MIDI_TicksPerBeat = Track->context[ _MIDI_Context ].TicksPerBeat; + _MIDI_TimeBase = Track->context[ _MIDI_Context ].TimeBase; + TimeSet = TRUE; + break; + } + + if ( _MIDI_Funcs->ControlChange ) + { + _MIDI_Funcs->ControlChange( channel, c1, c2 ); + } + */ + +#endif diff --git a/audiolib/_multivc.h b/audiolib/_multivc.h new file mode 100755 index 0000000..0d5d19c --- /dev/null +++ b/audiolib/_multivc.h @@ -0,0 +1,286 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + file: _MULTIVC.H + + author: James R. Dose + date: December 20, 1993 + + Private header for MULTIVOC.C + + (c) Copyright 1993 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#ifndef ___MULTIVC_H +#define ___MULTIVC_H + +#define TRUE ( 1 == 1 ) +#define FALSE ( !TRUE ) + +#define VOC_8BIT 0x0 +#define VOC_CT4_ADPCM 0x1 +#define VOC_CT3_ADPCM 0x2 +#define VOC_CT2_ADPCM 0x3 +#define VOC_16BIT 0x4 +#define VOC_ALAW 0x6 +#define VOC_MULAW 0x7 +#define VOC_CREATIVE_ADPCM 0x200 + +#define T_SIXTEENBIT_STEREO 0 +#define T_8BITS 1 +#define T_MONO 2 +#define T_16BITSOURCE 4 +#define T_LEFTQUIET 8 +#define T_RIGHTQUIET 16 +#define T_DEFAULT T_SIXTEENBIT_STEREO + +#define MV_MaxPanPosition 31 +#define MV_NumPanPositions ( MV_MaxPanPosition + 1 ) +#define MV_MaxTotalVolume 255 +//#define MV_MaxVolume 63 +#define MV_NumVoices 8 + +#define MIX_VOLUME( volume ) \ + ( ( max( 0, min( ( volume ), 255 ) ) * ( MV_MaxVolume + 1 ) ) >> 8 ) +// ( ( max( 0, min( ( volume ), 255 ) ) ) >> 2 ) + +//#define SILENCE_16BIT 0x80008000 +#define SILENCE_16BIT 0 +#define SILENCE_8BIT 0x80808080 +//#define SILENCE_16BIT_PAS 0 + +#define MixBufferSize 256 + +#define NumberOfBuffers 16 +#define TotalBufferSize ( MixBufferSize * NumberOfBuffers ) + +#define PI 3.1415926536 + +typedef enum + { + Raw, + VOC, + DemandFeed, + WAV + } wavedata; + +typedef enum + { + NoMoreData, + KeepPlaying + } playbackstatus; + + +typedef struct VoiceNode + { + struct VoiceNode *next; + struct VoiceNode *prev; + + wavedata wavetype; + char bits; + + playbackstatus ( *GetSound )( struct VoiceNode *voice ); + + void ( *mix )( unsigned long position, unsigned long rate, + const char *start, unsigned long length ); + + char *NextBlock; + char *LoopStart; + char *LoopEnd; + unsigned LoopCount; + unsigned long LoopSize; + unsigned long BlockLength; + + unsigned long PitchScale; + unsigned long FixedPointBufferSize; + + char *sound; + unsigned long length; + unsigned long SamplingRate; + unsigned long RateScale; + unsigned long position; + int Playing; + + int handle; + int priority; + + void ( *DemandFeed )( char **ptr, unsigned long *length ); + + short *LeftVolume; + short *RightVolume; + + unsigned long callbackval; + + } VoiceNode; + +typedef struct + { + VoiceNode *start; + VoiceNode *end; + } VList; + +typedef struct + { + unsigned char left; + unsigned char right; + } Pan; + +typedef signed short MONO16; +typedef signed char MONO8; + +typedef struct + { + MONO16 left; + MONO16 right; +// unsigned short left; +// unsigned short right; + } STEREO16; + +typedef struct + { + MONO16 left; + MONO16 right; + } SIGNEDSTEREO16; + +typedef struct + { +// MONO8 left; +// MONO8 right; + char left; + char right; + } STEREO8; + +typedef struct + { + char RIFF[ 4 ]; + unsigned long file_size; + char WAVE[ 4 ]; + char fmt[ 4 ]; + unsigned long format_size; + } riff_header; + +typedef struct + { + unsigned short wFormatTag; + unsigned short nChannels; + unsigned long nSamplesPerSec; + unsigned long nAvgBytesPerSec; + unsigned short nBlockAlign; + unsigned short nBitsPerSample; + } format_header; + +typedef struct + { + unsigned char DATA[ 4 ]; + unsigned long size; + } data_header; + +typedef MONO8 VOLUME8[ 256 ]; +typedef MONO16 VOLUME16[ 256 ]; + +typedef char HARSH_CLIP_TABLE_8[ MV_NumVoices * 256 ]; + +static void MV_Mix( VoiceNode *voice, int buffer ); +static void MV_PlayVoice( VoiceNode *voice ); +static void MV_StopVoice( VoiceNode *voice ); +static void MV_ServiceVoc( void ); + +static playbackstatus MV_GetNextVOCBlock( VoiceNode *voice ); +static playbackstatus MV_GetNextDemandFeedBlock( VoiceNode *voice ); +static playbackstatus MV_GetNextRawBlock( VoiceNode *voice ); +static playbackstatus MV_GetNextWAVBlock( VoiceNode *voice ); + +static void MV_ServiceRecord( void ); +static VoiceNode *MV_GetVoice( int handle ); +static VoiceNode *MV_AllocVoice( int priority ); + +static short *MV_GetVolumeTable( int vol ); + +static void MV_SetVoiceMixMode( VoiceNode *voice ); + +static void MV_SetVoicePitch( VoiceNode *voice, unsigned long rate, int pitchoffset ); +static void MV_CalcVolume( int MaxLevel ); +static void MV_CalcPanTable( void ); + +#ifdef PLAT_DOS +#define ATR_INDEX 0x3c0 +#define STATUS_REGISTER_1 0x3da + +#define SetBorderColor(color) \ + { \ + inp (STATUS_REGISTER_1); \ + outp (ATR_INDEX,0x31); \ + outp (ATR_INDEX,color); \ + } +#endif + +void ClearBuffer_DW( void *ptr, unsigned data, int length ); + +#ifdef PLAT_DOS +#pragma aux ClearBuffer_DW = \ + "cld", \ + "push es", \ + "push ds", \ + "pop es", \ + "rep stosd", \ + "pop es", \ +parm [ edi ] [ eax ] [ ecx ] modify exact [ ecx edi ]; +#endif + +void MV_Mix8BitMono( unsigned long position, unsigned long rate, + const char *start, unsigned long length ); + +void MV_Mix8BitStereo( unsigned long position, + unsigned long rate, const char *start, unsigned long length ); + +void MV_Mix16BitMono( unsigned long position, + unsigned long rate, const char *start, unsigned long length ); + +void MV_Mix16BitStereo( unsigned long position, + unsigned long rate, const char *start, unsigned long length ); + +void MV_Mix16BitMono16( unsigned long position, + unsigned long rate, const char *start, unsigned long length ); + +void MV_Mix8BitMono16( unsigned long position, unsigned long rate, + const char *start, unsigned long length ); + +void MV_Mix8BitStereo16( unsigned long position, + unsigned long rate, const char *start, unsigned long length ); + +void MV_Mix16BitStereo16( unsigned long position, + unsigned long rate, const char *start, unsigned long length ); + +void MV_16BitReverb( const char *src, char *dest, const VOLUME16 *volume, int count ); + +void MV_8BitReverb( const signed char *src, signed char *dest, const VOLUME16 *volume, int count ); + +void MV_16BitReverbFast( const char *src, char *dest, int count, int shift ); + +void MV_8BitReverbFast( const signed char *src, signed char *dest, int count, int shift ); + +#ifdef PLAT_DOS +#pragma aux MV_16BitReverb parm [eax] [edx] [ebx] [ecx] modify exact [eax ebx ecx edx esi edi] +#pragma aux MV_8BitReverb parm [eax] [edx] [ebx] [ecx] modify exact [eax ebx ecx edx esi edi] +#pragma aux MV_16BitReverbFast parm [eax] [edx] [ebx] [ecx] modify exact [eax ebx ecx edx esi edi] +#pragma aux MV_8BitReverbFast parm [eax] [edx] [ebx] [ecx] modify exact [eax ebx ecx edx esi edi] +#endif + +#endif diff --git a/audiolib/_pas16.h b/audiolib/_pas16.h new file mode 100755 index 0000000..ad1827d --- /dev/null +++ b/audiolib/_pas16.h @@ -0,0 +1,250 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: _PAS16.H + + author: James R. Dose + date: March 27, 1994 + + Private header for for PAS16.C + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#ifndef ___PAS16_H +#define ___PAS16_H + +#define TRUE ( 1 == 1 ) +#define FALSE ( !TRUE ) + +#define VALID ( 1 == 1 ) +#define INVALID ( !VALID ) + +#define lobyte( num ) ( ( int )*( ( char * )&( num ) ) ) +#define hibyte( num ) ( ( int )*( ( ( char * )&( num ) ) + 1 ) ) + +#define STEREO 1 +#define SIXTEEN_BIT 2 + +#define MONO_8BIT 0 +#define STEREO_8BIT ( STEREO ) +#define MONO_16BIT ( SIXTEEN_BIT ) +#define STEREO_16BIT ( STEREO | SIXTEEN_BIT ) + +#define PAS_MaxMixMode STEREO_16BIT + +#define MONO_8BIT_SAMPLE_SIZE 1 +#define MONO_16BIT_SAMPLE_SIZE 2 +#define STEREO_8BIT_SAMPLE_SIZE ( 2 * MONO_8BIT_SAMPLE_SIZE ) +#define STEREO_16BIT_SAMPLE_SIZE ( 2 * MONO_16BIT_SAMPLE_SIZE ) + +#define PAS_RevisionBits 0xe0 + +#define AudioFilterControl 0xb8a +#define InterruptControl 0xb8b +#define InterruptStatus 0xb89 +#define PCMDataRegister 0xf88 +#define CrossChannelControl 0xf8a +#define SampleRateTimer 0x1388 +#define SampleBufferCount 0x1389 +#define LocalSpeakerTimerCount 0x138a +#define LocalTimerControl 0x138b +#define SampleSizeConfiguration 0x8389 + +#define AudioMuteFlag 0x20 +#define SampleRateTimerGateFlag 0x40 +#define SampleBufferCountGateFlag 0x80 + +#define SampleRateInterruptFlag 0x04 +#define SampleBufferInterruptFlag 0x08 + +#define PAS_SampleSizeMask 0xf3 +#define PAS_SignedSampleMask 0xe3 +#define PAS_16BitSampleFlag 0x04 +#define PAS_UnsignedSampleFlag 0x10 +//bSC2msbinv equ 00010000b ;; invert MSB from standard method + +#define PAS_OverSamplingMask 0xfc + +#define PAS_1xOverSampling 0x00 +#define PAS_2xOverSampling 0x01 +#define PAS_4xOverSampling 0x03 + +#define PAS_StereoFlag 0x20 + +#define PAS_AudioMuteFlag 0x20 + +#define DEFAULT_BASE ( 0x0388 ^ 0x388 ) /* default base I/O address */ +#define ALT_BASE_1 ( 0x0384 ^ 0x388 ) /* first alternate address */ +#define ALT_BASE_2 ( 0x038C ^ 0x388 ) /* second alternate address */ +#define ALT_BASE_3 ( 0x0288 ^ 0x388 ) /* third alternate address */ + +#define PAS_DMAEnable 0x80 +#define PAS_ChannelConnectMask 0x0f +#define PAS_PCMStartDAC 0xD0 +#define PAS_PCMStartADC 0xC0 +#define PAS_PCMStopMask 0x3f + +#define RECORD 0 +#define PLAYBACK 1 + +#define SelectSampleRateTimer 0x36 // 00110110b +#define SelectSampleBufferCount 0x74 // 01110100b + +#define CalcTimeInterval( rate ) \ + ( 1193180UL / ( rate ) ) + +#define CalcSamplingRate( interval ) \ + ( 1193180UL / ( interval ) ) + +#define MV_Signature 0x4d56 +#define MV_SoundInt 0x2f +#define MV_CheckForDriver 0xbc00 +#define MV_GetVersion 0xbc01 +#define MV_GetPointerToStateTable 0xbc02 +#define MV_GetPointerToFunctionTable 0xbc03 +#define MV_GetDmaIrqInt 0xbc04 +#define MV_SendCommandStructure 0xbc05 +#define MV_GetDriverMessage 0xbc06 +#define MV_SetHotkeyScanCodes 0xbc0a +#define MV_GetPathToDriver 0xbc0b + +#define OUTPUTMIXER 0x00 /* output mixer H/W select */ +#define INPUTMIXER 0x40 /* input mixer select */ +#define DEFMIXER -1 /* use last mixer selected */ + +/* left channel values */ + +#define L_FM 0x01 +#define L_IMIXER 0x02 +#define L_EXT 0x03 +#define L_INT 0x04 +#define L_MIC 0x05 +#define L_PCM 0x06 +#define L_SPEAKER 0x07 +#define L_FREE 0x00 +#define L_SBDAC 0x00 + +/* right channel values */ + +#define R_FM 0x08 +#define R_IMIXER 0x09 +#define R_EXT 0x0A +#define R_INT 0x0B +#define R_MIC 0x0C +#define R_PCM 0x0D +#define R_SPEAKER 0x0E +#define R_FREE 0x0F +#define R_SBDAC 0x0F + +typedef struct + { + unsigned char sysspkrtmr; /* 42 System Speaker Timer Address */ + unsigned char systmrctlr; /* 43 System Timer Control */ + unsigned char sysspkrreg; /* 61 System Speaker Register */ + unsigned char joystick; /* 201 Joystick Register */ + unsigned char lfmaddr; /* 388 Left FM Synth Address */ + unsigned char lfmdata; /* 389 Left FM Synth Data */ + unsigned char rfmaddr; /* 38A Right FM Synth Address */ + unsigned char rfmdata; /* 38B Right FM Synth Data */ + unsigned char dfmaddr; /* 788 Dual FM Synth Address */ + unsigned char dfmdata; /* 789 Dual FM Synth Data */ + unsigned char RESRVD1[1]; /* reserved */ + unsigned char paudiomixr; /* 78B Paralllel Audio Mixer Control*/ + unsigned char audiomixr; /* B88 Audio Mixer Control */ + unsigned char intrctlrst; /* B89 Interrupt Status */ + unsigned char audiofilt; /* B8A Audio Filter Control */ + unsigned char intrctlr; /* B8B Interrupt Control */ + unsigned char pcmdata; /* F88 PCM Data I/O Register */ + unsigned char RESRVD2; /* reserved */ + unsigned char crosschannel; /* F8A Cross Channel */ + unsigned char RESRVD3; /* reserved */ + unsigned short samplerate; /* 1388 Sample Rate Timer */ + unsigned short samplecnt; /* 1389 Sample Count Register */ + unsigned short spkrtmr; /* 138A Shadow Speaker Timer Count */ + unsigned char tmrctlr; /* 138B Shadow Speaker Timer Control */ + unsigned char mdirqvect; /* 1788 MIDI IRQ Vector Register */ + unsigned char mdsysctlr; /* 1789 MIDI System Control Register */ + unsigned char mdsysstat; /* 178A MIDI IRQ Status Register */ + unsigned char mdirqclr; /* 178B MIDI IRQ Clear Register */ + unsigned char mdgroup1; /* 1B88 MIDI Group #1 Register */ + unsigned char mdgroup2; /* 1B89 MIDI Group #2 Register */ + unsigned char mdgroup3; /* 1B8A MIDI Group #3 Register */ + unsigned char mdgroup4; /* 1B8B MIDI Group #4 Register */ + } MVState; + +typedef struct + { + unsigned long SetMixer; + unsigned long SetVolume; + unsigned long SetFilter; + unsigned long SetCrossChannel; + unsigned long GetMixer; + unsigned long GetVolume; + unsigned long GetFilter; + unsigned long GetCrossChannel; + unsigned long ReadSound; + unsigned long FMSplit; + } MVFunc; + +int PAS_CheckForDriver( void ); +MVState *PAS_GetStateTable( void ); +MVFunc *PAS_GetFunctionTable( void ); +int PAS_GetCardSettings( void ); +void PAS_EnableInterrupt( void ); +void PAS_DisableInterrupt( void ); +void interrupt far PAS_ServiceInterrupt( void ); +//void interrupt PAS_ServiceInterrupt( void ); +void PAS_Write( int Register, int Data ); +int PAS_Read( int Register ); +void PAS_SetSampleRateTimer( void ); +void PAS_SetSampleBufferCount( void ); +int PAS_SetupDMABuffer( char *BufferPtr, int BufferSize, int mode ); +int PAS_GetFilterSetting( int rate ); +void PAS_BeginTransfer( int mode ); +int PAS_TestAddress( int address ); +int PAS_FindCard( void ); +int PAS_CallMVFunction( unsigned long function, int ebx, int ecx, int edx ); +void PAS_SaveState( void ); +void PAS_RestoreState( void ); + + +#pragma aux PAS_TestAddress = \ + "mov dx, 0b8bh", \ + "xor dx, ax", \ + "in al, dx", \ + "cmp al, 0ffh", \ + "je TestExit", \ + "mov ah, al", \ + "xor al, 0e0h", \ + "out dx, al", \ + "jmp TestDelay1", \ + "TestDelay1:", \ + "jmp TestDelay2", \ + "TestDelay2:", \ + "in al, dx", \ + "xchg al, ah", \ + "out dx, al", \ + "sub al, ah", \ + "TestExit:", \ + "and eax, 0ffh" \ + parm [ eax ] modify exact [ eax dx ]; + +#endif diff --git a/audiolib/_sndscap.h b/audiolib/_sndscap.h new file mode 100755 index 0000000..7c1f02a --- /dev/null +++ b/audiolib/_sndscap.h @@ -0,0 +1,136 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: _SNDSCAP.H + + author: James R. Dose + date: October 26, 1994 + + Private header for SNDSCAPE.C + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#ifndef ___SNDSCAP_H +#define ___SNDSCAP_H + +#define VALID ( 1 == 1 ) +#define INVALID ( !VALID ) + +#define TRUE ( 1 == 1 ) +#define FALSE ( !TRUE ) + +#define lobyte( num ) ( ( int )*( ( char * )&( num ) ) ) +#define hibyte( num ) ( ( int )*( ( ( char * )&( num ) ) + 1 ) ) + +#define STEREO 1 +#define SIXTEEN_BIT 2 + +#define MONO_8BIT 0 +#define STEREO_8BIT ( STEREO ) +#define MONO_16BIT ( SIXTEEN_BIT ) +#define STEREO_16BIT ( STEREO | SIXTEEN_BIT ) + +#define SOUNDSCAPE_MaxMixMode STEREO_16BIT + +#define MONO_8BIT_SAMPLE_SIZE 1 +#define MONO_16BIT_SAMPLE_SIZE 2 +#define STEREO_8BIT_SAMPLE_SIZE ( 2 * MONO_8BIT_SAMPLE_SIZE ) +#define STEREO_16BIT_SAMPLE_SIZE ( 2 * MONO_16BIT_SAMPLE_SIZE ) + +#define SOUNDSCAPE_DefaultSampleRate 11000 +#define SOUNDSCAPE_DefaultMixMode MONO_8BIT +#define SOUNDSCAPE_MaxIrq 15 + +/* Ensoniq gate-array chip defines ... */ +#define ODIE 0 /* ODIE gate array */ +#define OPUS 1 /* OPUS gate array */ +#define MMIC 2 /* MiMIC gate array */ + +/* relevant direct register defines - offsets from base address */ +#define GA_HOSTCSTAT 2 /* host port ctrl/stat reg */ +#define GA_HOSTDATA 3 /* host port data reg */ +#define GA_REGADDR 4 /* indirect address reg */ +#define GA_REGDATA 5 /* indirect data reg */ +#define SB_IACK 0x22e /* SoundBlaster IACK register */ + +/* relevant indirect register defines */ +#define GA_DMACHB 3 /* DMA chan B assign reg */ +#define GA_INTCFG 4 /* interrupt configuration reg */ +#define GA_DMACFG 5 /* DMA config reg */ +#define GA_CDCFG 6 /* CD-ROM (AD-1848) config reg */ +#define GA_HMCTL 9 /* host master control reg */ +#define GA_CHIPSEL 10 /* programmable external chip select */ + +/* AD-1848 chip defines ... */ +/* relevant direct register defines */ +#define AD_REGADDR 0 /* indirect address reg */ +#define AD_REGDATA 1 /* indirect data reg */ +#define AD_STATUS 2 /* status register */ +#define AD_OFFSET 8 /* for some boards, a fixed BasePort offset */ + +/* relevant indirect register defines */ +#define AD_LEFTOUT 6 /* left DAC output control reg */ +#define AD_RIGHTOUT 7 /* right DAC output control reg */ +#define AD_FORMAT 8 /* clock and data format reg */ +#define AD_CONFIG 9 /* interface config register */ +#define AD_PINCTRL 10 /* external pin control reg */ +#define AD_UCOUNT 14 /* upper count reg */ +#define AD_LCOUNT 15 /* lower count reg */ + +/* some firmware command and communication defines */ +#define SET_CTL 0x88 /* set a control value */ +#define GET_CTL 0x89 /* get a control value */ +#define SET_REV 0xb0 /* set synth reverb */ +#define SYNTH_VOL 0x04 /* Synth Vol control number */ +#define RXRDY 0x01 /* Receive-Ready bit mask */ +#define TXRDY 0x02 /* Transmit-Ready bit mask */ + +/* some miscellaneous defines ... soundscape reg values, sytem int regs, ... */ +#define INTCONT1 0x20 /* Interrupt Controller 1 control register */ +#define INTCONT2 0xa0 /* Interrupt Controller 2 control register */ +#define INTMASK1 0x21 /* Interrupt Controller 1 mask register */ +#define INTMASK2 0xa1 /* Interrupt Controller 2 mask register */ +#define VECTBASE1 0x08 /* vector base for XT interrupts */ +#define VECTBASE2 0x70 /* vector base for AT extended interrupts */ +#define EOI 0x20 /* End Of Interrupt command */ +#define AUTO_OUT 0x58 /* DMA controller mode */ + +static void SOUNDSCAPE_EnableInterrupt( void ); +static void SOUNDSCAPE_DisableInterrupt( void ); +static void __interrupt __far SOUNDSCAPE_ServiceInterrupt( void ); +static int ga_read( int rnum ); +static void ga_write( int rnum, int value ); +static int ad_read( int rnum ); +static void ad_write( int rnum, int value ); +static void tdelay( void ); +static void pcm_format( void ); +static int SOUNDSCAPE_SetupDMABuffer( char *BufferPtr, int BufferSize, int mode ); +static int SOUNDSCAPE_BeginPlayback( int length ); +static void SOUNDSCAPE_LockEnd( void ); +static void SOUNDSCAPE_UnlockMemory( void ); +static int SOUNDSCAPE_LockMemory( void ); +static unsigned short allocateTimerStack( unsigned short size ); +static void deallocateTimerStack( unsigned short selector ); +static int parse( char *val, char *str, FILE *p1 ); +static int SOUNDSCAPE_FindCard( void ); +static int SOUNDSCAPE_Setup( void ); + +#endif diff --git a/audiolib/adlibfx.c b/audiolib/adlibfx.c new file mode 100755 index 0000000..2e6618b --- /dev/null +++ b/audiolib/adlibfx.c @@ -0,0 +1,552 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: ADLIBFX.C + + author: James R. Dose + date: April 1, 1994 + + Low level routines to support Adlib sound effects created by Muse. + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#include +#include +#include +#include "dpmi.h" +#include "task_man.h" +#include "interrup.h" +#include "al_midi.h" +#include "adlibfx.h" + +#define TRUE ( 1 == 1 ) +#define FALSE ( !TRUE ) + +static void ADLIBFX_SendOutput( int reg, int data ); +static void ADLIBFX_Service( task *Task ); + +static long ADLIBFX_LengthLeft; +static int ADLIBFX_Block; +static ALSound *ADLIBFX_Sound = NULL; +static char *ADLIBFX_SoundPtr = NULL; +static int ADLIBFX_Priority; +static unsigned long ADLIBFX_CallBackVal; +static void ( *ADLIBFX_CallBackFunc )( unsigned long ) = NULL; +static int ADLIBFX_SoundVolume; +static int ADLIBFX_TotalVolume = ADLIBFX_MaxVolume; +static task *ADLIBFX_ServiceTask = NULL; +static int ADLIBFX_VoiceHandle = ADLIBFX_MinVoiceHandle; + +int ADLIBFX_Installed = FALSE; + +int ADLIBFX_ErrorCode = ADLIBFX_Ok; + +#define ADLIBFX_SetErrorCode( status ) \ + ADLIBFX_ErrorCode = ( status ); + + +/*--------------------------------------------------------------------- + Function: ADLIBFX_ErrorString + + Returns a pointer to the error message associated with an error + number. A -1 returns a pointer the current error. +---------------------------------------------------------------------*/ + +char *ADLIBFX_ErrorString + ( + int ErrorNumber + ) + + { + char *ErrorString; + + switch( ErrorNumber ) + { + case ADLIBFX_Warning : + case ADLIBFX_Error : + ErrorString = ADLIBFX_ErrorString( ADLIBFX_ErrorCode ); + break; + + case ADLIBFX_Ok : + ErrorString = "Adlib FX ok."; + break; + + case ADLIBFX_NoVoices : + ErrorString = "No free voices available in Adlib FX."; + break; + + case ADLIBFX_VoiceNotFound : + ErrorString = "No voice with matching handle found."; + break; + + case ADLIBFX_DPMI_Error : + ErrorString = "DPMI Error in AdlibFX."; + break; + + default : + ErrorString = "Unknown Adlib FX error code."; + break; + } + + return( ErrorString ); + } + + +/********************************************************************** + + Memory locked functions: + +**********************************************************************/ + + +#define ADLIBFX_LockStart ADLIBFX_SendOutput + +/*--------------------------------------------------------------------- + Function: ADLIBFX_SendOutput + + Writes a byte of data to the specified register on the Adlib card. +---------------------------------------------------------------------*/ + +static void ADLIBFX_SendOutput + ( + int reg, + int data + ) + + { + int i; + int adlib_port = 0x388; + unsigned flags; + + flags = DisableInterrupts(); + + outp( adlib_port, reg ); + + for( i = 6; i ; i-- ) + { + inp( adlib_port ); + } + + outp( adlib_port + 1, data ); + + for( i = 35; i ; i-- ) + { + inp( adlib_port ); + } + + RestoreInterrupts( flags ); + } + + +/*--------------------------------------------------------------------- + Function: ADLIBFX_Stop + + Halts playback of the currently playing sound effect. +---------------------------------------------------------------------*/ + +int ADLIBFX_Stop + ( + int handle + ) + + { + unsigned flags; + + if ( ( handle != ADLIBFX_VoiceHandle ) || ( ADLIBFX_Sound == NULL ) ) + { + ADLIBFX_SetErrorCode( ADLIBFX_VoiceNotFound ); + return( ADLIBFX_Warning ); + } + + flags = DisableInterrupts(); + + ADLIBFX_SendOutput( 0xb0, 0 ); + + ADLIBFX_Sound = NULL; + ADLIBFX_SoundPtr = NULL; + ADLIBFX_LengthLeft = 0; + ADLIBFX_Priority = 0; + + RestoreInterrupts( flags ); + + if ( ADLIBFX_CallBackFunc ) + { + ADLIBFX_CallBackFunc( ADLIBFX_CallBackVal ); + } + + return( ADLIBFX_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: ADLIBFX_Service + + Task Manager routine to perform the playback of a sound effect. +---------------------------------------------------------------------*/ + +static void ADLIBFX_Service + ( + task *Task + ) + + { + int value; + + if ( ADLIBFX_SoundPtr ) + { + value = *ADLIBFX_SoundPtr++; + if ( value != 0 ) + { + ADLIBFX_SendOutput( 0xa0, value ); + ADLIBFX_SendOutput( 0xb0, ADLIBFX_Block ); + } + else + { + ADLIBFX_SendOutput( 0xb0, 0 ); + } + + ADLIBFX_LengthLeft--; + if ( ADLIBFX_LengthLeft <= 0 ) + { + ADLIBFX_Stop( ADLIBFX_VoiceHandle ); + } + } + } + + +/*--------------------------------------------------------------------- + Function: ADLIBFX_SetVolume + + Sets the volume of the currently playing sound effect. +---------------------------------------------------------------------*/ + +int ADLIBFX_SetVolume + ( + int handle, + int volume + ) + + { + unsigned flags; + int carrierlevel; + + flags = DisableInterrupts(); + if ( ( handle != ADLIBFX_VoiceHandle ) || ( ADLIBFX_Sound == NULL ) ) + { + RestoreInterrupts( flags ); + ADLIBFX_SetErrorCode( ADLIBFX_VoiceNotFound ); + return( ADLIBFX_Warning ); + } + + volume = min( volume, ADLIBFX_MaxVolume ); + volume = max( volume, 0 ); + ADLIBFX_SoundVolume = volume; + + volume *= ADLIBFX_TotalVolume; + volume /= ADLIBFX_MaxVolume; + + carrierlevel = ADLIBFX_Sound->cScale & 0x3f; + carrierlevel ^= 0x3f; + carrierlevel *= ( volume / 2 ) + 0x80; + carrierlevel /= ADLIBFX_MaxVolume; + carrierlevel ^= 0x3f; + carrierlevel |= ADLIBFX_Sound->cScale & 0xc0; + + ADLIBFX_SendOutput( 0x43, carrierlevel ); + + RestoreInterrupts( flags ); + return( ADLIBFX_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: ADLIBFX_SetTotalVolume + + Sets the total volume of the sound effect. +---------------------------------------------------------------------*/ + +int ADLIBFX_SetTotalVolume + ( + int volume + ) + + { + volume = max( volume, 0 ); + volume = min( volume, ADLIBFX_MaxVolume ); + + ADLIBFX_TotalVolume = volume; + ADLIBFX_SetVolume( ADLIBFX_VoiceHandle, ADLIBFX_SoundVolume ); + + return( ADLIBFX_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: ADLIBFX_GetTotalVolume + + Returns the total volume of the sound effect. +---------------------------------------------------------------------*/ + +int ADLIBFX_GetTotalVolume + ( + void + ) + + { + return( ADLIBFX_TotalVolume ); + } + + +/*--------------------------------------------------------------------- + Function: ADLIBFX_VoiceAvailable + + Checks if a voice can be play at the specified priority. +---------------------------------------------------------------------*/ + +int ADLIBFX_VoiceAvailable + ( + int priority + ) + + { + if ( priority < ADLIBFX_Priority ) + { + return( FALSE ); + } + + return( TRUE ); + } + + +/*--------------------------------------------------------------------- + Function: ADLIBFX_Play + + Starts playback of a Muse sound effect. +---------------------------------------------------------------------*/ + +int ADLIBFX_Play + ( + ALSound *sound, + int volume, + int priority, + unsigned long callbackval + ) + + { + unsigned flags; + int carrierlevel; + + if ( priority < ADLIBFX_Priority ) + { + ADLIBFX_SetErrorCode( ADLIBFX_NoVoices ); + return( ADLIBFX_Warning ); + } + + ADLIBFX_Stop( ADLIBFX_VoiceHandle ); + + ADLIBFX_VoiceHandle++; + if ( ADLIBFX_VoiceHandle < ADLIBFX_MinVoiceHandle ) + { + ADLIBFX_VoiceHandle = ADLIBFX_MinVoiceHandle; + } + + flags = DisableInterrupts(); + + ADLIBFX_LengthLeft = sound->length; + ADLIBFX_Priority = priority; + ADLIBFX_Sound = sound; + ADLIBFX_SoundPtr = &sound->data; + ADLIBFX_CallBackVal = callbackval; + + ADLIBFX_Block = ( ( sound->block & 7 ) << 2 ) | 0x20; + + volume = min( volume, ADLIBFX_MaxVolume ); + volume = max( volume, 0 ); + ADLIBFX_SoundVolume = volume; + + volume *= ADLIBFX_TotalVolume; + volume /= ADLIBFX_MaxVolume; + + carrierlevel = sound->cScale & 0x3f; + carrierlevel ^= 0x3f; + carrierlevel *= ( volume / 2 ) + 0x80; + carrierlevel /= ADLIBFX_MaxVolume; + carrierlevel ^= 0x3f; + carrierlevel |= sound->cScale & 0xc0; + + ADLIBFX_SendOutput( 0x20, sound->mChar ); + ADLIBFX_SendOutput( 0x40, sound->mScale ); + ADLIBFX_SendOutput( 0x60, sound->mAttack ); + ADLIBFX_SendOutput( 0x80, sound->mSus ); + ADLIBFX_SendOutput( 0xe0, sound->mWave ); + + ADLIBFX_SendOutput( 0x23, sound->cChar ); + ADLIBFX_SendOutput( 0x43, carrierlevel ); + ADLIBFX_SendOutput( 0x63, sound->cAttack ); + ADLIBFX_SendOutput( 0x83, sound->cSus ); + ADLIBFX_SendOutput( 0xe3, sound->cWave ); + + ADLIBFX_SendOutput( 0xc0, 0 ); + + RestoreInterrupts( flags ); + + return( ADLIBFX_VoiceHandle ); + } + + +/*--------------------------------------------------------------------- + Function: ADLIBFX_SoundPlaying + + Checks if a sound effect is currently playing. +---------------------------------------------------------------------*/ + +int ADLIBFX_SoundPlaying + ( + int handle + ) + + { + int status; + + status = FALSE; + if ( ( handle == ADLIBFX_VoiceHandle ) && ( ADLIBFX_LengthLeft > 0 ) ) + { + status = TRUE; + } + + return( status ); + } + + +/*--------------------------------------------------------------------- + Function: ADLIBFX_LockEnd + + Used for determining the length of the functions to lock in memory. +---------------------------------------------------------------------*/ + +static void ADLIBFX_LockEnd + ( + void + ) + + { + } + + +/*--------------------------------------------------------------------- + Function: ADLIBFX_SetCallBack + + Set the function to call when a voice stops. +---------------------------------------------------------------------*/ + +void ADLIBFX_SetCallBack + ( + void ( *function )( unsigned long ) + ) + + { + ADLIBFX_CallBackFunc = function; + } + + +/*--------------------------------------------------------------------- + Function: ADLIBFX_Init + + Initializes the sound effect engine. +---------------------------------------------------------------------*/ + +int ADLIBFX_Init + ( + void + ) + + { + int status; + + if ( ADLIBFX_Installed ) + { + ADLIBFX_Shutdown(); + } + + status = DPMI_LockMemoryRegion( ADLIBFX_LockStart, ADLIBFX_LockEnd ); + status |= DPMI_Lock( ADLIBFX_VoiceHandle ); + status |= DPMI_Lock( ADLIBFX_Sound ); + status |= DPMI_Lock( ADLIBFX_ErrorCode ); + status |= DPMI_Lock( ADLIBFX_SoundPtr ); + status |= DPMI_Lock( ADLIBFX_LengthLeft ); + status |= DPMI_Lock( ADLIBFX_Priority ); + status |= DPMI_Lock( ADLIBFX_CallBackFunc ); + status |= DPMI_Lock( ADLIBFX_Block ); + + if ( status != DPMI_Ok ) + { + ADLIBFX_SetErrorCode( ADLIBFX_DPMI_Error ); + return( ADLIBFX_Error ); + } + +//JIM +// AL_ReserveVoice( 0 ); + ADLIBFX_Stop( ADLIBFX_VoiceHandle ); + ADLIBFX_ServiceTask = TS_ScheduleTask( &ADLIBFX_Service, 140, 2, NULL ); + TS_Dispatch(); + ADLIBFX_Installed = TRUE; + ADLIBFX_CallBackFunc = NULL; + + ADLIBFX_SetErrorCode( ADLIBFX_Ok ); + return( ADLIBFX_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: ADLIBFX_Shutdown + + Ends the use of the sound effect engine. +---------------------------------------------------------------------*/ + +int ADLIBFX_Shutdown + ( + void + ) + + { + if ( ADLIBFX_Installed ) + { + ADLIBFX_Stop( ADLIBFX_VoiceHandle ); + TS_Terminate( ADLIBFX_ServiceTask ); + ADLIBFX_ServiceTask = NULL; +//JIM +// AL_ReleaseVoice( 0 ); + ADLIBFX_Installed = FALSE; + + DPMI_UnlockMemoryRegion( ADLIBFX_LockStart, ADLIBFX_LockEnd ); + DPMI_Unlock( ADLIBFX_VoiceHandle ); + DPMI_Unlock( ADLIBFX_Sound ); + DPMI_Unlock( ADLIBFX_ErrorCode ); + DPMI_Unlock( ADLIBFX_SoundPtr ); + DPMI_Unlock( ADLIBFX_LengthLeft ); + DPMI_Unlock( ADLIBFX_Priority ); + DPMI_Unlock( ADLIBFX_CallBackFunc ); + DPMI_Unlock( ADLIBFX_Block ); + } + + ADLIBFX_SetErrorCode( ADLIBFX_Ok ); + return( ADLIBFX_Ok ); + } diff --git a/audiolib/adlibfx.h b/audiolib/adlibfx.h new file mode 100755 index 0000000..d310a6e --- /dev/null +++ b/audiolib/adlibfx.h @@ -0,0 +1,80 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: ADLIBFX.H + + author: James R. Dose + date: April 1, 1994 + + Public header for ADLIBFX.C + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#ifndef __ADLIBFX_H +#define __ADLIBFX_H + +enum ADLIBFX_Errors + { + ADLIBFX_Warning = -2, + ADLIBFX_Error = -1, + ADLIBFX_Ok = 0, + ADLIBFX_NoVoices, + ADLIBFX_VoiceNotFound, + ADLIBFX_DPMI_Error + }; + +typedef struct + { + unsigned long length; + short int priority; + char mChar, cChar; + char mScale, cScale; + char mAttack, cAttack; + char mSus, cSus; + char mWave, cWave; + char nConn; + char voice; + char mode; + char unused[ 3 ]; + char block; + char data[]; + } ALSound; + +#define ADLIBFX_MaxVolume 255 +#define ADLIBFX_MinVoiceHandle 1 + +char *ADLIBFX_ErrorString( int ErrorNumber ); +int ADLIBFX_Stop( int handle ); +int ADLIBFX_SetVolume( int handle, int volume ); +int ADLIBFX_SetTotalVolume( int volume ); +int ADLIBFX_GetTotalVolume( void ); +int ADLIBFX_VoiceAvailable( int priority ); +int ADLIBFX_Play( ALSound *sound, int volume, int priority, unsigned long callbackval ); +int ADLIBFX_SoundPlaying( int handle ); +void ADLIBFX_SetCallBack( void ( *function )( unsigned long ) ); +int ADLIBFX_Init( void ); +int ADLIBFX_Shutdown( void ); + #pragma aux ADLIBFX_Shutdown frame; +void PCFX_UnlockMemory( void ); + #pragma aux ADLIBFX_UnlockMemory frame; +int PCFX_LockMemory( void ); + +#endif diff --git a/audiolib/al_midi.c b/audiolib/al_midi.c new file mode 100755 index 0000000..871280c --- /dev/null +++ b/audiolib/al_midi.c @@ -0,0 +1,1510 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: AL_MIDI.C + + author: James R. Dose + date: April 1, 1994 + + Low level routines to support General MIDI music on Adlib compatible + cards. + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#include +#include +#include +#include +//#include +#include "dpmi.h" +#include "interrup.h" +#include "sndcards.h" +#include "blaster.h" +#include "user.h" +#include "al_midi.h" +#include "_al_midi.h" +#include "ll_man.h" + +#define TRUE ( 1 == 1 ) +#define FALSE ( !TRUE ) + +static unsigned OctavePitch[ MAX_OCTAVE + 1 ] = + { + OCTAVE_0, OCTAVE_1, OCTAVE_2, OCTAVE_3, + OCTAVE_4, OCTAVE_5, OCTAVE_6, OCTAVE_7, + }; + +static unsigned NoteMod12[ MAX_NOTE + 1 ]; +static unsigned NoteDiv12[ MAX_NOTE + 1 ]; + +// Pitch table + +//static unsigned NotePitch[ FINETUNE_MAX + 1 ][ 12 ] = +// { +// { C, C_SHARP, D, D_SHARP, E, F, F_SHARP, G, G_SHARP, A, A_SHARP, B }, +// }; + +static unsigned NotePitch[ FINETUNE_MAX + 1 ][ 12 ] = + { + { 0x157, 0x16b, 0x181, 0x198, 0x1b0, 0x1ca, 0x1e5, 0x202, 0x220, 0x241, 0x263, 0x287 }, + { 0x157, 0x16b, 0x181, 0x198, 0x1b0, 0x1ca, 0x1e5, 0x202, 0x220, 0x242, 0x264, 0x288 }, + { 0x158, 0x16c, 0x182, 0x199, 0x1b1, 0x1cb, 0x1e6, 0x203, 0x221, 0x243, 0x265, 0x289 }, + { 0x158, 0x16c, 0x183, 0x19a, 0x1b2, 0x1cc, 0x1e7, 0x204, 0x222, 0x244, 0x266, 0x28a }, + { 0x159, 0x16d, 0x183, 0x19a, 0x1b3, 0x1cd, 0x1e8, 0x205, 0x223, 0x245, 0x267, 0x28b }, + { 0x15a, 0x16e, 0x184, 0x19b, 0x1b3, 0x1ce, 0x1e9, 0x206, 0x224, 0x246, 0x268, 0x28c }, + { 0x15a, 0x16e, 0x185, 0x19c, 0x1b4, 0x1ce, 0x1ea, 0x207, 0x225, 0x247, 0x269, 0x28e }, + { 0x15b, 0x16f, 0x185, 0x19d, 0x1b5, 0x1cf, 0x1eb, 0x208, 0x226, 0x248, 0x26a, 0x28f }, + { 0x15b, 0x170, 0x186, 0x19d, 0x1b6, 0x1d0, 0x1ec, 0x209, 0x227, 0x249, 0x26b, 0x290 }, + { 0x15c, 0x170, 0x187, 0x19e, 0x1b7, 0x1d1, 0x1ec, 0x20a, 0x228, 0x24a, 0x26d, 0x291 }, + { 0x15d, 0x171, 0x188, 0x19f, 0x1b7, 0x1d2, 0x1ed, 0x20b, 0x229, 0x24b, 0x26e, 0x292 }, + { 0x15d, 0x172, 0x188, 0x1a0, 0x1b8, 0x1d3, 0x1ee, 0x20c, 0x22a, 0x24c, 0x26f, 0x293 }, + { 0x15e, 0x172, 0x189, 0x1a0, 0x1b9, 0x1d4, 0x1ef, 0x20d, 0x22b, 0x24d, 0x270, 0x295 }, + { 0x15f, 0x173, 0x18a, 0x1a1, 0x1ba, 0x1d4, 0x1f0, 0x20e, 0x22c, 0x24e, 0x271, 0x296 }, + { 0x15f, 0x174, 0x18a, 0x1a2, 0x1bb, 0x1d5, 0x1f1, 0x20f, 0x22d, 0x24f, 0x272, 0x297 }, + { 0x160, 0x174, 0x18b, 0x1a3, 0x1bb, 0x1d6, 0x1f2, 0x210, 0x22e, 0x250, 0x273, 0x298 }, + { 0x161, 0x175, 0x18c, 0x1a3, 0x1bc, 0x1d7, 0x1f3, 0x211, 0x22f, 0x251, 0x274, 0x299 }, + { 0x161, 0x176, 0x18c, 0x1a4, 0x1bd, 0x1d8, 0x1f4, 0x212, 0x230, 0x252, 0x276, 0x29b }, + { 0x162, 0x176, 0x18d, 0x1a5, 0x1be, 0x1d9, 0x1f5, 0x212, 0x231, 0x254, 0x277, 0x29c }, + { 0x162, 0x177, 0x18e, 0x1a6, 0x1bf, 0x1d9, 0x1f5, 0x213, 0x232, 0x255, 0x278, 0x29d }, + { 0x163, 0x178, 0x18f, 0x1a6, 0x1bf, 0x1da, 0x1f6, 0x214, 0x233, 0x256, 0x279, 0x29e }, + { 0x164, 0x179, 0x18f, 0x1a7, 0x1c0, 0x1db, 0x1f7, 0x215, 0x235, 0x257, 0x27a, 0x29f }, + { 0x164, 0x179, 0x190, 0x1a8, 0x1c1, 0x1dc, 0x1f8, 0x216, 0x236, 0x258, 0x27b, 0x2a1 }, + { 0x165, 0x17a, 0x191, 0x1a9, 0x1c2, 0x1dd, 0x1f9, 0x217, 0x237, 0x259, 0x27c, 0x2a2 }, + { 0x166, 0x17b, 0x192, 0x1aa, 0x1c3, 0x1de, 0x1fa, 0x218, 0x238, 0x25a, 0x27e, 0x2a3 }, + { 0x166, 0x17b, 0x192, 0x1aa, 0x1c3, 0x1df, 0x1fb, 0x219, 0x239, 0x25b, 0x27f, 0x2a4 }, + { 0x167, 0x17c, 0x193, 0x1ab, 0x1c4, 0x1e0, 0x1fc, 0x21a, 0x23a, 0x25c, 0x280, 0x2a6 }, + { 0x168, 0x17d, 0x194, 0x1ac, 0x1c5, 0x1e0, 0x1fd, 0x21b, 0x23b, 0x25d, 0x281, 0x2a7 }, + { 0x168, 0x17d, 0x194, 0x1ad, 0x1c6, 0x1e1, 0x1fe, 0x21c, 0x23c, 0x25e, 0x282, 0x2a8 }, + { 0x169, 0x17e, 0x195, 0x1ad, 0x1c7, 0x1e2, 0x1ff, 0x21d, 0x23d, 0x260, 0x283, 0x2a9 }, + { 0x16a, 0x17f, 0x196, 0x1ae, 0x1c8, 0x1e3, 0x1ff, 0x21e, 0x23e, 0x261, 0x284, 0x2ab }, + { 0x16a, 0x17f, 0x197, 0x1af, 0x1c8, 0x1e4, 0x200, 0x21f, 0x23f, 0x262, 0x286, 0x2ac } + }; + +// Slot numbers as a function of the voice and the operator. +// ( melodic only) + +static int slotVoice[ NUM_VOICES ][ 2 ] = + { + { 0, 3 }, // voice 0 + { 1, 4 }, // 1 + { 2, 5 }, // 2 + { 6, 9 }, // 3 + { 7, 10 }, // 4 + { 8, 11 }, // 5 + { 12, 15 }, // 6 + { 13, 16 }, // 7 + { 14, 17 }, // 8 + }; + +static int VoiceLevel[ NumChipSlots ][ 2 ]; +static int VoiceKsl[ NumChipSlots ][ 2 ]; + +// This table gives the offset of each slot within the chip. +// offset = fn( slot) + +static char offsetSlot[ NumChipSlots ] = + { + 0, 1, 2, 3, 4, 5, + 8, 9, 10, 11, 12, 13, + 16, 17, 18, 19, 20, 21 + }; + +static int VoiceReserved[ NUM_VOICES * 2 ] = + { + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE + }; + +static VOICE Voice[ NUM_VOICES * 2 ]; +static VOICELIST Voice_Pool; + +static CHANNEL Channel[ NUM_CHANNELS ]; + +static int AL_LeftPort = 0x388; +static int AL_RightPort = 0x388; +static int AL_Stereo = FALSE; +static int AL_SendStereo = FALSE; +static int AL_OPL3 = FALSE; +static int AL_MaxMidiChannel = 16; + + +/********************************************************************** + + Memory locked functions: + +**********************************************************************/ + + +#define AL_LockStart AL_SendOutputToPort + + +/*--------------------------------------------------------------------- + Function: AL_SendOutputToPort + + Sends data to the Adlib using a specified port. +---------------------------------------------------------------------*/ + +void AL_SendOutputToPort + ( + int port, + int reg, + int data + ) + + { + int delay; + + outp( port, reg ); + + for( delay = 6; delay > 0 ; delay-- ) +// for( delay = 2; delay > 0 ; delay-- ) + { + inp( port ); + } + + outp( port + 1, data ); + +// for( delay = 35; delay > 0 ; delay-- ) + for( delay = 27; delay > 0 ; delay-- ) +// for( delay = 2; delay > 0 ; delay-- ) + { + inp( port ); + } + } + + +/*--------------------------------------------------------------------- + Function: AL_SendOutput + + Sends data to the Adlib. +---------------------------------------------------------------------*/ + +void AL_SendOutput + ( + int voice, + int reg, + int data + ) + + { + int port; + + if ( AL_SendStereo ) + { + AL_SendOutputToPort( AL_LeftPort, reg, data ); + AL_SendOutputToPort( AL_RightPort, reg, data ); + } + else + { + port = ( voice == 0 ) ? AL_RightPort : AL_LeftPort; + AL_SendOutputToPort( port, reg, data ); + } + } + + +/*--------------------------------------------------------------------- + Function: AL_SetVoiceTimbre + + Programs the specified voice's timbre. +---------------------------------------------------------------------*/ + +static void AL_SetVoiceTimbre + ( + int voice + ) + + { + int off; + int slot; + int port; + int voc; + int patch; + int channel; + TIMBRE *timbre; + + channel = Voice[ voice ].channel; + + if ( channel == 9 ) + { + patch = Voice[ voice ].key + 128; + } + else + { + patch = Channel[ channel ].Timbre; + } + + if ( Voice[ voice ].timbre == patch ) + { + return; + } + + Voice[ voice ].timbre = patch; + timbre = &ADLIB_TimbreBank[ patch ]; + + port = Voice[ voice ].port; + voc = ( voice >= NUM_VOICES ) ? voice - NUM_VOICES : voice; + slot = slotVoice[ voc ][ 0 ]; + off = offsetSlot[ slot ]; + + VoiceLevel[ slot ][ port ] = 63 - ( timbre->Level[ 0 ] & 0x3f ); + VoiceKsl[ slot ][ port ] = timbre->Level[ 0 ] & 0xc0; + + AL_SendOutput( port, 0xA0 + voc, 0 ); + AL_SendOutput( port, 0xB0 + voc, 0 ); + + // Let voice clear the release + AL_SendOutput( port, 0x80 + off, 0xff ); + + AL_SendOutput( port, 0x60 + off, timbre->Env1[ 0 ] ); + AL_SendOutput( port, 0x80 + off, timbre->Env2[ 0 ] ); + AL_SendOutput( port, 0x20 + off, timbre->SAVEK[ 0 ] ); + AL_SendOutput( port, 0xE0 + off, timbre->Wave[ 0 ] ); + + AL_SendOutput( port, 0x40 + off, timbre->Level[ 0 ] ); + slot = slotVoice[ voc ][ 1 ]; + + if ( AL_SendStereo ) + { + AL_SendOutputToPort( AL_LeftPort, 0xC0 + voice, + ( timbre->Feedback & 0x0f ) | 0x20 ); + AL_SendOutputToPort( AL_RightPort, 0xC0 + voice, + ( timbre->Feedback & 0x0f ) | 0x10 ); + } + else + { + if ( AL_OPL3 ) + { + AL_SendOutput( port, 0xC0 + voc, ( timbre->Feedback & 0x0f ) | + 0x30 ); + } + else + { + AL_SendOutputToPort( ADLIB_PORT, 0xC0 + voice, timbre->Feedback ); + } + } + + off = offsetSlot[ slot ]; + + VoiceLevel[ slot ][ port ] = 63 - ( timbre->Level[ 1 ] & 0x3f ); + VoiceKsl[ slot ][ port ] = timbre->Level[ 1 ] & 0xc0; + AL_SendOutput( port, 0x40 + off, 63 ); + + // Let voice clear the release + AL_SendOutput( port, 0x80 + off, 0xff ); + + AL_SendOutput( port, 0x60 + off, timbre->Env1[ 1 ] ); + AL_SendOutput( port, 0x80 + off, timbre->Env2[ 1 ] ); + AL_SendOutput( port, 0x20 + off, timbre->SAVEK[ 1 ] ); + AL_SendOutput( port, 0xE0 + off, timbre->Wave[ 1 ] ); + } + + +/*--------------------------------------------------------------------- + Function: AL_SetVoiceVolume + + Sets the volume of the specified voice. +---------------------------------------------------------------------*/ + +static void AL_SetVoiceVolume + ( + int voice + ) + + { + int channel; + int velocity; + int slot; + int port; + int voc; + unsigned long t1; + unsigned long t2; + unsigned long volume; + TIMBRE *timbre; + + channel = Voice[ voice ].channel; + + timbre = &ADLIB_TimbreBank[ Voice[ voice ].timbre ]; + + velocity = Voice[ voice ].velocity + timbre->Velocity; + velocity = min( velocity, MAX_VELOCITY ); + + voc = ( voice >= NUM_VOICES ) ? voice - NUM_VOICES : voice; + slot = slotVoice[ voc ][ 1 ]; + port = Voice[ voice ].port; + + // amplitude + t1 = ( unsigned )VoiceLevel[ slot ][ port ]; + t1 *= ( velocity + 0x80 ); + t1 = ( Channel[ channel ].Volume * t1 ) >> 15; + + if ( !AL_SendStereo ) + { + volume = t1 ^ 63; + volume |= ( unsigned )VoiceKsl[ slot ][ port ]; + + AL_SendOutput( port, 0x40 + offsetSlot[ slot ], volume ); + + // Check if this timbre is Additive + if ( timbre->Feedback & 0x01 ) + { + slot = slotVoice[ voc ][ 0 ]; + + // amplitude + t2 = ( unsigned )VoiceLevel[ slot ][ port ]; + t2 *= ( velocity + 0x80 ); + t2 = ( Channel[ channel ].Volume * t1 ) >> 15; + + volume = t2 ^ 63; + volume |= ( unsigned )VoiceKsl[ slot ][ port ]; + + AL_SendOutput( port, 0x40 + offsetSlot[ slot ], volume ); + } + } + else + { + // Set left channel volume + volume = t1; + if ( Channel[ channel ].Pan < 64 ) + { + volume *= Channel[ channel ].Pan; + volume >>= 6; + } + + volume ^= 63; + volume |= ( unsigned )VoiceKsl[ slot ][ port ]; + + AL_SendOutputToPort( AL_LeftPort, 0x40 + offsetSlot[ slot ], volume ); + + // Set right channel volume + volume = t1; + if ( Channel[ channel ].Pan > 64 ) + { + volume *= 127 - Channel[ channel ].Pan; + volume >>= 6; + } + + volume ^= 63; + volume |= ( unsigned )VoiceKsl[ slot ][ port ]; + + AL_SendOutputToPort( AL_RightPort, 0x40 + offsetSlot[ slot ], volume ); + + // Check if this timbre is Additive + if ( timbre->Feedback & 0x01 ) + { + // amplitude + t2 = ( unsigned )VoiceLevel[ slot ][ port ]; + t2 *= ( velocity + 0x80 ); + t2 = ( Channel[ channel ].Volume * t1 ) >> 15; + + slot = slotVoice[ voc ][ 0 ]; + + // Set left channel volume + volume = t2; + if ( Channel[ channel ].Pan < 64 ) + { + volume *= Channel[ channel ].Pan; + volume >>= 6; + } + + volume ^= 63; + volume |= ( unsigned )VoiceKsl[ slot ][ port ]; + + AL_SendOutputToPort( AL_LeftPort, 0x40 + offsetSlot[ slot ], volume ); + + // Set right channel volume + volume = t2; + if ( Channel[ channel ].Pan > 64 ) + { + volume *= 127 - Channel[ channel ].Pan; + volume >>= 6; + } + + volume ^= 63; + volume |= ( unsigned )VoiceKsl[ slot ][ port ]; + + AL_SendOutputToPort( AL_RightPort, 0x40 + offsetSlot[ slot ], volume ); + } + } + } + + +/*--------------------------------------------------------------------- + Function: AL_AllocVoice + + Retrieves a free voice from the voice pool. +---------------------------------------------------------------------*/ + +static int AL_AllocVoice + ( + void + ) + + { + int voice; + + if ( Voice_Pool.start ) + { + voice = Voice_Pool.start->num; + LL_Remove( VOICE, &Voice_Pool, &Voice[ voice ] ); + return( voice ); + } + + return( AL_VoiceNotFound ); + } + + +/*--------------------------------------------------------------------- + Function: AL_GetVoice + + Determines which voice is associated with a specified note and + MIDI channel. +---------------------------------------------------------------------*/ + +static int AL_GetVoice + ( + int channel, + int key + ) + + { + VOICE *voice; + + voice = Channel[ channel ].Voices.start; + + while( voice != NULL ) + { + if ( voice->key == key ) + { + return( voice->num ); + } + voice = voice->next; + } + + return( AL_VoiceNotFound ); + } + + +/*--------------------------------------------------------------------- + Function: AL_SetVoicePitch + + Programs the pitch of the specified voice. +---------------------------------------------------------------------*/ + +static void AL_SetVoicePitch + ( + int voice + ) + + { + int note; + int channel; + int patch; + int detune; + int ScaleNote; + int Octave; + int pitch; + int port; + int voc; + + port = Voice[ voice ].port; + voc = ( voice >= NUM_VOICES ) ? voice - NUM_VOICES : voice; + channel = Voice[ voice ].channel; + + if ( channel == 9 ) + { + patch = Voice[ voice ].key + 128; + note = ADLIB_TimbreBank[ patch ].Transpose; + } + else + { + patch = Channel[ channel ].Timbre; + note = Voice[ voice ].key + ADLIB_TimbreBank[ patch ].Transpose; + } + + note += Channel[ channel ].KeyOffset - 12; + if ( note > MAX_NOTE ) + { + note = MAX_NOTE; + } + if ( note < 0 ) + { + note = 0; + } + + detune = Channel[ channel ].KeyDetune; + + ScaleNote = NoteMod12[ note ]; + Octave = NoteDiv12[ note ]; + + pitch = OctavePitch[ Octave ] | NotePitch[ detune ][ ScaleNote ]; + + Voice[ voice ].pitchleft = pitch; + + pitch |= Voice[ voice ].status; + + if ( !AL_SendStereo ) + { + AL_SendOutput( port, 0xA0 + voc, pitch ); + AL_SendOutput( port, 0xB0 + voc, pitch >> 8 ); + } + else + { + AL_SendOutputToPort( AL_LeftPort, 0xA0 + voice, pitch ); + AL_SendOutputToPort( AL_LeftPort, 0xB0 + voice, pitch >> 8 ); + + if ( channel != 9 ) + { + detune += STEREO_DETUNE; + } + + if ( detune > FINETUNE_MAX ) + { + detune -= FINETUNE_RANGE; + if ( note < MAX_NOTE ) + { + note++; + ScaleNote = NoteMod12[ note ]; + Octave = NoteDiv12[ note ]; + } + } + + pitch = OctavePitch[ Octave ] | NotePitch[ detune ][ ScaleNote ]; + + Voice[ voice ].pitchright = pitch; + + pitch |= Voice[ voice ].status; + + AL_SendOutputToPort( AL_RightPort, 0xA0 + voice, pitch ); + AL_SendOutputToPort( AL_RightPort, 0xB0 + voice, pitch >> 8 ); + } + } + + +/*--------------------------------------------------------------------- + Function: AL_SetChannelVolume + + Sets the volume of the specified MIDI channel. +---------------------------------------------------------------------*/ + +static void AL_SetChannelVolume + ( + int channel, + int volume + ) + + { + VOICE *voice; + + volume = max( 0, volume ); + volume = min( volume, AL_MaxVolume ); + Channel[ channel ].Volume = volume; + + voice = Channel[ channel ].Voices.start; + while( voice != NULL ) + { + AL_SetVoiceVolume( voice->num ); + voice = voice->next; + } + } + + +/*--------------------------------------------------------------------- + Function: AL_SetChannelPan + + Sets the pan position of the specified MIDI channel. +---------------------------------------------------------------------*/ + +static void AL_SetChannelPan + ( + int channel, + int pan + ) + + { + // Don't pan drum sounds + if ( channel != 9 ) + { + Channel[ channel ].Pan = pan; + } + } + + +/*--------------------------------------------------------------------- + Function: AL_SetChannelDetune + + Sets the stereo voice detune of the specified MIDI channel. +---------------------------------------------------------------------*/ + +static void AL_SetChannelDetune + ( + int channel, + int detune + ) + + { + Channel[ channel ].Detune = detune; + } + + +/*--------------------------------------------------------------------- + Function: AL_ResetVoices + + Sets all voice info to the default state. +---------------------------------------------------------------------*/ + +static void AL_ResetVoices + ( + void + ) + + { + int index; + int numvoices; + + Voice_Pool.start = NULL; + Voice_Pool.end = NULL; + + numvoices = NUM_VOICES; + if ( ( AL_OPL3 ) && ( !AL_Stereo ) ) + { + numvoices = NUM_VOICES * 2; + } + for( index = 0; index < numvoices; index++ ) + { + if ( VoiceReserved[ index ] == FALSE ) + { + Voice[ index ].num = index; + Voice[ index ].key = 0; + Voice[ index ].velocity = 0; + Voice[ index ].channel = -1; + Voice[ index ].timbre = -1; + Voice[ index ].port = ( index < NUM_VOICES ) ? 0 : 1; + Voice[ index ].status = NOTE_OFF; + LL_AddToTail( VOICE, &Voice_Pool, &Voice[ index ] ); + } + } + + for( index = 0; index < NUM_CHANNELS; index++ ) + { + Channel[ index ].Voices.start = NULL; + Channel[ index ].Voices.end = NULL; + Channel[ index ].Timbre = 0; + Channel[ index ].Pitchbend = 0; + Channel[ index ].KeyOffset = 0; + Channel[ index ].KeyDetune = 0; + Channel[ index ].Volume = AL_DefaultChannelVolume; + Channel[ index ].Pan = 64; + Channel[ index ].RPN = 0; + Channel[ index ].PitchBendRange = AL_DefaultPitchBendRange; + Channel[ index ].PitchBendSemiTones = AL_DefaultPitchBendRange / 100; + Channel[ index ].PitchBendHundreds = AL_DefaultPitchBendRange % 100; + } + } + + +/*--------------------------------------------------------------------- + Function: AL_CalcPitchInfo + + Calculates the pitch table. +---------------------------------------------------------------------*/ + +static void AL_CalcPitchInfo + ( + void + ) + + { + int note; +// int finetune; +// double detune; + + for( note = 0; note <= MAX_NOTE; note++ ) + { + NoteMod12[ note ] = note % 12; + NoteDiv12[ note ] = note / 12; + } + +// for( finetune = 1; finetune <= FINETUNE_MAX; finetune++ ) +// { +// detune = pow( 2, ( double )finetune / ( 12.0 * FINETUNE_RANGE ) ); +// for( note = 0; note < 12; note++ ) +// { +// NotePitch[ finetune ][ note ] = ( ( double )NotePitch[ 0 ][ note ] * detune ); +// } +// } + } + + +/*--------------------------------------------------------------------- + Function: AL_FlushCard + + Sets all voices to a known (quiet) state. +---------------------------------------------------------------------*/ + +void AL_FlushCard + ( + int port + ) + + { + int i; + unsigned slot1; + unsigned slot2; + + for( i = 0 ; i < NUM_VOICES; i++ ) + { + if ( VoiceReserved[ i ] == FALSE ) + { + slot1 = offsetSlot[ slotVoice[ i ][ 0 ] ]; + slot2 = offsetSlot[ slotVoice[ i ][ 1 ] ]; + + AL_SendOutputToPort( port, 0xA0 + i, 0 ); + AL_SendOutputToPort( port, 0xB0 + i, 0 ); + + AL_SendOutputToPort( port, 0xE0 + slot1, 0 ); + AL_SendOutputToPort( port, 0xE0 + slot2, 0 ); + + // Set the envelope to be fast and quiet + AL_SendOutputToPort( port, 0x60 + slot1, 0xff ); + AL_SendOutputToPort( port, 0x60 + slot2, 0xff ); + AL_SendOutputToPort( port, 0x80 + slot1, 0xff ); + AL_SendOutputToPort( port, 0x80 + slot2, 0xff ); + + // Maximum attenuation + AL_SendOutputToPort( port, 0x40 + slot1, 0xff ); + AL_SendOutputToPort( port, 0x40 + slot2, 0xff ); + } + } + } + + +/*--------------------------------------------------------------------- + Function: AL_StereoOn + + Sets the card send info in stereo. +---------------------------------------------------------------------*/ + +void AL_StereoOn + ( + void + ) + + { + if ( ( AL_Stereo ) && ( !AL_SendStereo ) ) + { + AL_SendStereo = TRUE; + if ( AL_OPL3 ) + { + // Set card to OPL3 operation + AL_SendOutputToPort( AL_RightPort, 0x5, 1 ); + } + } + else if ( AL_OPL3 ) + { + // Set card to OPL3 operation + AL_SendOutputToPort( AL_RightPort, 0x5, 1 ); + } + } + + +/*--------------------------------------------------------------------- + Function: AL_StereoOff + + Sets the card send info in mono. +---------------------------------------------------------------------*/ + +void AL_StereoOff + ( + void + ) + + { + if ( ( AL_Stereo ) && ( AL_SendStereo ) ) + { + AL_SendStereo = FALSE; + if ( AL_OPL3 ) + { + // Set card back to OPL2 operation + AL_SendOutputToPort( AL_RightPort, 0x5, 0 ); + } + } + else if ( AL_OPL3 ) + { + // Set card back to OPL2 operation + AL_SendOutputToPort( AL_RightPort, 0x5, 0 ); + } + } + + +/*--------------------------------------------------------------------- + Function: AL_Reset + + Sets the card to a known (quiet) state. +---------------------------------------------------------------------*/ + +void AL_Reset + ( + void + ) + + { + AL_SendOutputToPort( ADLIB_PORT, 1, 0x20 ); + AL_SendOutputToPort( ADLIB_PORT, 0x08, 0 ); + + // Set the values: AM Depth, VIB depth & Rhythm + AL_SendOutputToPort( ADLIB_PORT, 0xBD, 0 ); + + AL_StereoOn(); + + if ( ( AL_SendStereo ) || ( AL_OPL3 ) ) + { + AL_FlushCard( AL_LeftPort ); + AL_FlushCard( AL_RightPort ); + } + else + { + AL_FlushCard( ADLIB_PORT ); + } + } + + +/*--------------------------------------------------------------------- + Function: AL_ReserveVoice + + Marks a voice as being not available for use. This allows the + driver to use the rest of the card while another driver uses the + reserved voice. +---------------------------------------------------------------------*/ + +int AL_ReserveVoice + ( + int voice + ) + + { + unsigned flags; + + if ( ( voice < 0 ) || ( voice >= NUM_VOICES ) ) + { + return( AL_Error ); + } + + if ( VoiceReserved[ voice ] ) + { + return( AL_Warning ); + } + + flags = DisableInterrupts(); + + if ( Voice[ voice ].status == NOTE_ON ) + { + AL_NoteOff( Voice[ voice ].channel, Voice[ voice ].key, 0 ); + } + + VoiceReserved[ voice ] = TRUE; + LL_Remove( VOICE, &Voice_Pool, &Voice[ voice ] ); + + RestoreInterrupts( flags ); + return( AL_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: AL_ReleaseVoice + + Marks a previously reserved voice as being free to use. +---------------------------------------------------------------------*/ + +int AL_ReleaseVoice + ( + int voice + ) + + { + unsigned flags; + + if ( ( voice < 0 ) || ( voice >= NUM_VOICES ) ) + { + return( AL_Error ); + } + + if ( !VoiceReserved[ voice ] ) + { + return( AL_Warning ); + } + + flags = DisableInterrupts(); + + VoiceReserved[ voice ] = FALSE; + LL_AddToTail( VOICE, &Voice_Pool, &Voice[ voice ] ); + + RestoreInterrupts( flags ); + return( AL_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: AL_NoteOff + + Turns off a note on the specified MIDI channel. +---------------------------------------------------------------------*/ + +void AL_NoteOff + ( + int channel, + int key, + int velocity + ) + + { + int voice; + int port; + int voc; + + // We only play channels 1 through 10 + if ( channel > AL_MaxMidiChannel ) + { + return; + } + + voice = AL_GetVoice( channel, key ); + + if ( voice == AL_VoiceNotFound ) + { + return; + } + + Voice[ voice ].status = NOTE_OFF; + + port = Voice[ voice ].port; + voc = ( voice >= NUM_VOICES ) ? voice - NUM_VOICES : voice; + + if ( AL_SendStereo ) + { + AL_SendOutputToPort( AL_LeftPort, 0xB0 + voice, + hibyte( Voice[ voice ].pitchleft ) ); + AL_SendOutputToPort( AL_RightPort, 0xB0 + voice, + hibyte( Voice[ voice ].pitchright ) ); + } + else + { + AL_SendOutput( port, 0xB0 + voc, hibyte( Voice[ voice ].pitchleft ) ); + } + + LL_Remove( VOICE, &Channel[ channel ].Voices, &Voice[ voice ] ); + LL_AddToTail( VOICE, &Voice_Pool, &Voice[ voice ] ); + } + + +/*--------------------------------------------------------------------- + Function: AL_NoteOn + + Plays a note on the specified MIDI channel. +---------------------------------------------------------------------*/ + +void AL_NoteOn + ( + int channel, + int key, + int velocity + ) + + { + int voice; + + // We only play channels 1 through 10 + if ( channel > AL_MaxMidiChannel ) + { + return; + } + + if ( velocity == 0 ) + { + AL_NoteOff( channel, key, velocity ); + return; + } + + voice = AL_AllocVoice(); + + if ( voice == AL_VoiceNotFound ) + { + if ( Channel[ 9 ].Voices.start ) + { + AL_NoteOff( 9, Channel[ 9 ].Voices.start->key, 0 ); + voice = AL_AllocVoice(); + } + if ( voice == AL_VoiceNotFound ) + { + return; + } + } + + Voice[ voice ].key = key; + Voice[ voice ].channel = channel; + Voice[ voice ].velocity = velocity; + Voice[ voice ].status = NOTE_ON; + + LL_AddToTail( VOICE, &Channel[ channel ].Voices, &Voice[ voice ] ); + + AL_SetVoiceTimbre( voice ); + AL_SetVoiceVolume( voice ); + AL_SetVoicePitch( voice ); + } + + +/*--------------------------------------------------------------------- + Function: AL_AllNotesOff + + Turns off all currently playing voices. +---------------------------------------------------------------------*/ + +void AL_AllNotesOff + ( + int channel + ) + + { + while( Channel[ channel ].Voices.start != NULL ) + { + AL_NoteOff( channel, Channel[ channel ].Voices.start->key, 0 ); + } + } + + +/*--------------------------------------------------------------------- + Function: AL_ControlChange + + Sets the value of a controller on the specified MIDI channel. +---------------------------------------------------------------------*/ + +void AL_ControlChange + ( + int channel, + int type, + int data + ) + + { + // We only play channels 1 through 10 + if ( channel > AL_MaxMidiChannel ) + { + return; + } + + switch( type ) + { + case MIDI_VOLUME : + AL_SetChannelVolume( channel, data ); + break; + + case MIDI_PAN : + AL_SetChannelPan( channel, data ); + break; + + case MIDI_DETUNE : + AL_SetChannelDetune( channel, data ); + break; + + case MIDI_ALL_NOTES_OFF : + AL_AllNotesOff( channel ); + break; + + case MIDI_RESET_ALL_CONTROLLERS : + AL_ResetVoices(); + AL_SetChannelVolume( channel, AL_DefaultChannelVolume ); + AL_SetChannelPan( channel, 64 ); + AL_SetChannelDetune( channel, 0 ); + break; + + case MIDI_RPN_MSB : + Channel[ channel ].RPN &= 0x00FF; + Channel[ channel ].RPN |= ( data & 0xFF ) << 8; + break; + + case MIDI_RPN_LSB : + Channel[ channel ].RPN &= 0xFF00; + Channel[ channel ].RPN |= data & 0xFF; + break; + + case MIDI_DATAENTRY_MSB : + if ( Channel[ channel ].RPN == MIDI_PITCHBEND_RPN ) + { + Channel[ channel ].PitchBendSemiTones = data; + Channel[ channel ].PitchBendRange = + Channel[ channel ].PitchBendSemiTones * 100 + + Channel[ channel ].PitchBendHundreds; + } + break; + + case MIDI_DATAENTRY_LSB : + if ( Channel[ channel ].RPN == MIDI_PITCHBEND_RPN ) + { + Channel[ channel ].PitchBendHundreds = data; + Channel[ channel ].PitchBendRange = + Channel[ channel ].PitchBendSemiTones * 100 + + Channel[ channel ].PitchBendHundreds; + } + break; + } + } + + +/*--------------------------------------------------------------------- + Function: AL_ProgramChange + + Selects the instrument to use on the specified MIDI channel. +---------------------------------------------------------------------*/ + +void AL_ProgramChange + ( + int channel, + int patch + ) + + { + // We only play channels 1 through 10 + if ( channel > AL_MaxMidiChannel ) + { + return; + } + + Channel[ channel ].Timbre = patch; + } + + +/*--------------------------------------------------------------------- + Function: AL_SetPitchBend + + Sets the pitch bend amount on the specified MIDI channel. +---------------------------------------------------------------------*/ + +void AL_SetPitchBend + ( + int channel, + int lsb, + int msb + ) + + { + int pitchbend; + unsigned long TotalBend; + VOICE *voice; + + // We only play channels 1 through 10 + if ( channel > AL_MaxMidiChannel ) + { + return; + } + + pitchbend = lsb + ( msb << 8 ); + Channel[ channel ].Pitchbend = pitchbend; + + TotalBend = pitchbend * Channel[ channel ].PitchBendRange; + TotalBend /= ( PITCHBEND_CENTER / FINETUNE_RANGE ); + + Channel[ channel ].KeyOffset = ( int )( TotalBend / FINETUNE_RANGE ); + Channel[ channel ].KeyOffset -= Channel[ channel ].PitchBendSemiTones; + + Channel[ channel ].KeyDetune = ( unsigned )( TotalBend % FINETUNE_RANGE ); + + voice = Channel[ channel ].Voices.start; + while( voice != NULL ) + { + AL_SetVoicePitch( voice->num ); + voice = voice->next; + } + } + + +/*--------------------------------------------------------------------- + Function: AL_DetectFM + + Determines if an Adlib compatible card is installed in the machine. +---------------------------------------------------------------------*/ + +int AL_DetectFM + ( + void + ) + + { + int status1; + int status2; + int i; + + if ( USER_CheckParameter( NO_ADLIB_DETECTION ) ) + { + return( FALSE ); + } + + AL_SendOutputToPort( ADLIB_PORT, 4, 0x60 ); // Reset T1 & T2 + AL_SendOutputToPort( ADLIB_PORT, 4, 0x80 ); // Reset IRQ + + status1 = inp( ADLIB_PORT ); + + AL_SendOutputToPort( ADLIB_PORT, 2, 0xff ); // Set timer 1 + AL_SendOutputToPort( ADLIB_PORT, 4, 0x21 ); // Start timer 1 + + for( i = 100; i > 0; i-- ) + { + inp( ADLIB_PORT ); + } + + status2 = inp( ADLIB_PORT ); + + AL_SendOutputToPort( ADLIB_PORT, 4, 0x60 ); + AL_SendOutputToPort( ADLIB_PORT, 4, 0x80 ); + + return( ( ( status1 & 0xe0 ) == 0x00 ) && ( ( status2 & 0xe0 ) == 0xc0 ) ); + } + + +/*--------------------------------------------------------------------- + Function: AL_LockEnd + + Used for determining the length of the functions to lock in memory. +---------------------------------------------------------------------*/ + +static void AL_LockEnd + ( + void + ) + + { + } + + +/*--------------------------------------------------------------------- + Function: AL_Shutdown + + Ends use of the sound card and resets it to a quiet state. +---------------------------------------------------------------------*/ + +void AL_Shutdown + ( + void + ) + + { + AL_StereoOff(); + + AL_OPL3 = FALSE; + AL_ResetVoices(); + AL_Reset(); + + DPMI_UnlockMemoryRegion( AL_LockStart, AL_LockEnd ); + DPMI_Unlock( slotVoice ); + DPMI_Unlock( VoiceLevel ); + DPMI_Unlock( VoiceKsl ); + DPMI_Unlock( offsetSlot ); + DPMI_Unlock( NotePitch ); + DPMI_Unlock( OctavePitch ); + DPMI_Unlock( NoteMod12 ); + DPMI_Unlock( NoteDiv12 ); + DPMI_Unlock( VoiceReserved ); + DPMI_Unlock( Voice ); + DPMI_Unlock( Voice_Pool ); + DPMI_Unlock( Channel ); + DPMI_Unlock( AL_LeftPort ); + DPMI_Unlock( AL_RightPort ); + DPMI_Unlock( AL_Stereo ); + DPMI_Unlock( AL_SendStereo ); + DPMI_Unlock( AL_OPL3 ); + DPMI_Unlock( AL_MaxMidiChannel ); + } + + +/*--------------------------------------------------------------------- + Function: AL_SetMaxMidiChannel + + Sets the maximum MIDI channel that FM cards respond to. +---------------------------------------------------------------------*/ + +void AL_SetMaxMidiChannel + ( + int channel + ) + + { + AL_MaxMidiChannel = channel - 1; + } + +/*--------------------------------------------------------------------- + Function: AL_Init + + Begins use of the sound card. +---------------------------------------------------------------------*/ + +int AL_Init + ( + int soundcard + ) + + { + BLASTER_CONFIG Blaster; + int status; + + status = DPMI_LockMemoryRegion( AL_LockStart, AL_LockEnd ); + status |= DPMI_Lock( slotVoice ); + status |= DPMI_Lock( VoiceLevel ); + status |= DPMI_Lock( VoiceKsl ); + status |= DPMI_Lock( offsetSlot ); + status |= DPMI_Lock( NotePitch ); + status |= DPMI_Lock( OctavePitch ); + status |= DPMI_Lock( NoteMod12 ); + status |= DPMI_Lock( NoteDiv12 ); + status |= DPMI_Lock( VoiceReserved ); + status |= DPMI_Lock( Voice ); + status |= DPMI_Lock( Voice_Pool ); + status |= DPMI_Lock( Channel ); + status |= DPMI_Lock( AL_LeftPort ); + status |= DPMI_Lock( AL_RightPort ); + status |= DPMI_Lock( AL_Stereo ); + status |= DPMI_Lock( AL_SendStereo ); + status |= DPMI_Lock( AL_OPL3 ); + status |= DPMI_Lock( AL_MaxMidiChannel ); + + if ( status != DPMI_Ok ) + { + return( AL_Error ); + } + + AL_Stereo = FALSE; + AL_OPL3 = FALSE; + AL_LeftPort = 0x388; + AL_RightPort = 0x388; + + switch( soundcard ) + { + case ProAudioSpectrum : + case SoundMan16 : + AL_OPL3 = TRUE; + AL_LeftPort = 0x388; + AL_RightPort = 0x38A; + break; + + case SoundBlaster : + status = BLASTER_GetCardSettings( &Blaster ); + if ( status != BLASTER_Ok ) + { + status = BLASTER_GetEnv( &Blaster ); + if ( status != BLASTER_Ok ) + { + break; + } + } + + switch( Blaster.Type ) + { + case SBPro2 : + case SB16 : + AL_OPL3 = TRUE; + AL_LeftPort = Blaster.Address; + AL_RightPort = Blaster.Address + 2; + break; + } + break; + } +// Temporarally commented out for ROTT. +// Stereo FM seems to take too long on some computers and +// causes the mouse driver to miss interrupts. + +/* + switch( soundcard ) + { + case ProAudioSpectrum : + case SoundMan16 : + AL_OPL3 = TRUE; + AL_Stereo = TRUE; + AL_LeftPort = 0x388; + AL_RightPort = 0x38A; + break; + + case SoundBlaster : + status = BLASTER_GetCardSettings( &Blaster ); + if ( status != BLASTER_Ok ) + { + status = BLASTER_GetEnv( &Blaster ); + if ( status != BLASTER_Ok ) + { + break; + } + } + + switch( Blaster.Type ) + { + case SBPro2 : + case SB16 : + AL_OPL3 = TRUE; + AL_Stereo = TRUE; + AL_LeftPort = Blaster.Address; + AL_RightPort = Blaster.Address + 2; + break; + + case SBPro : + AL_Stereo = TRUE; + AL_LeftPort = Blaster.Address; + AL_RightPort = Blaster.Address + 2; + break; + } + break; + } +*/ + + AL_CalcPitchInfo(); + AL_Reset(); + AL_ResetVoices(); + + return( AL_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: AL_RegisterTimbreBank + + Copies user supplied timbres over the default timbre bank. +---------------------------------------------------------------------*/ + +void AL_RegisterTimbreBank + ( + unsigned char *timbres + ) + + { + int i; + + for( i = 0; i < 256; i++ ) + { + ADLIB_TimbreBank[ i ].SAVEK[ 0 ] = *( timbres++ ); + ADLIB_TimbreBank[ i ].SAVEK[ 1 ] = *( timbres++ ); + ADLIB_TimbreBank[ i ].Level[ 0 ] = *( timbres++ ); + ADLIB_TimbreBank[ i ].Level[ 1 ] = *( timbres++ ); + ADLIB_TimbreBank[ i ].Env1[ 0 ] = *( timbres++ ); + ADLIB_TimbreBank[ i ].Env1[ 1 ] = *( timbres++ ); + ADLIB_TimbreBank[ i ].Env2[ 0 ] = *( timbres++ ); + ADLIB_TimbreBank[ i ].Env2[ 1 ] = *( timbres++ ); + ADLIB_TimbreBank[ i ].Wave[ 0 ] = *( timbres++ ); + ADLIB_TimbreBank[ i ].Wave[ 1 ] = *( timbres++ ); + ADLIB_TimbreBank[ i ].Feedback = *( timbres++ ); + ADLIB_TimbreBank[ i ].Transpose = *( signed char * )( timbres++ ); + ADLIB_TimbreBank[ i ].Velocity = *( signed char * )( timbres++ ); + } + } diff --git a/audiolib/al_midi.h b/audiolib/al_midi.h new file mode 100755 index 0000000..8f11adf --- /dev/null +++ b/audiolib/al_midi.h @@ -0,0 +1,58 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef __AL_MIDI_H +#define __AL_MIDI_H + +enum AL_Errors + { + AL_Warning = -2, + AL_Error = -1, + AL_Ok = 0, + }; + +#define AL_MaxVolume 127 +#define AL_DefaultChannelVolume 90 +//#define AL_DefaultPitchBendRange 2 +#define AL_DefaultPitchBendRange 200 + +#define ADLIB_PORT 0x388 + +void AL_SendOutputToPort( int port, int reg, int data ); +void AL_SendOutput( int voice, int reg, int data ); +void AL_StereoOn( void ); +void AL_StereoOff( void ); +int AL_ReserveVoice( int voice ); +int AL_ReleaseVoice( int voice ); +void AL_Shutdown( void ); +int AL_Init( int soundcard ); +void AL_SetMaxMidiChannel( int channel ); +void AL_Reset( void ); +void AL_NoteOff( int channel, int key, int velocity ); +void AL_NoteOn( int channel, int key, int vel ); +//Turned off to test if it works with Watcom 10a +// #pragma aux AL_NoteOn frame; +void AL_AllNotesOff( int channel ); +void AL_ControlChange( int channel, int type, int data ); +void AL_ProgramChange( int channel, int patch ); +void AL_SetPitchBend( int channel, int lsb, int msb ); +int AL_DetectFM( void ); +void AL_RegisterTimbreBank( unsigned char *timbres ); + +#endif diff --git a/audiolib/assert.h b/audiolib/assert.h new file mode 100755 index 0000000..ab42fa9 --- /dev/null +++ b/audiolib/assert.h @@ -0,0 +1,45 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef __ASSERT_H + + #define __ASSERT_H + + #ifdef NDEBUG + + #define ASSERT(f) + + #else + + #pragma aux _Assert aborts; /* _Assert will not return */ + extern void _Assert( char *strFile, unsigned uLine ); /*prototype */ + + #define ASSERT(f) \ + if (f) \ + ; \ + else \ + _Assert( __FILE__, __LINE__ ) + + #endif + +#else + + #error Multiple definition of ASSERT() + +#endif diff --git a/audiolib/awe32.c b/audiolib/awe32.c new file mode 100755 index 0000000..9f01411 --- /dev/null +++ b/audiolib/awe32.c @@ -0,0 +1,540 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: AWE32.C + + author: James R. Dose + date: August 23, 1994 + + Cover functions for calling the AWE32 low-level library. + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#include +#include +#include "dpmi.h" +#include "blaster.h" +#include "ctaweapi.h" +#include "awe32.h" + +#define _inp inp +#define _outp outp + +/* DSP defines */ +#define MPU_ACK_OK 0xfe +#define MPU_RESET_CMD 0xff +#define MPU_ENTER_UART 0x3f + +static WORD wSBCBaseAddx; /* Sound Blaster base address */ +static WORD wEMUBaseAddx; /* EMU8000 subsystem base address */ +static WORD wMpuBaseAddx; /* MPU401 base address */ + +static unsigned short NoteFlags[ 128 ]; + +/* macros */ +#define SBCPort( x ) ( ( x ) + wSBCBaseAddx ) +#define MPUPort( x ) ( ( x ) + wMpuBaseAddx ) + +static SOUND_PACKET spSound = + { + 0 + }; + +static LONG lBankSizes[ MAXBANKS ] = + { + 0 + }; + +unsigned SetES( void ); +#pragma aux SetES = \ + "xor eax, eax" \ + "mov ax, es" \ + "mov bx, ds" \ + "mov es, bx" \ + modify [ eax ebx ]; + +void RestoreES( unsigned num ); +#pragma aux RestoreES = \ + "mov es, ax" \ + parm [ eax ]; + +int AWE32_ErrorCode = AWE32_Ok; + +#define AWE32_SetErrorCode( status ) \ + AWE32_ErrorCode = ( status ); + + +/*--------------------------------------------------------------------- + Function: AWE32_ErrorString + + Returns a pointer to the error message associated with an error + number. A -1 returns a pointer the current error. +---------------------------------------------------------------------*/ + +char *AWE32_ErrorString + ( + int ErrorNumber + ) + + { + char *ErrorString; + + switch( ErrorNumber ) + { + case AWE32_Warning : + case AWE32_Error : + ErrorString = AWE32_ErrorString( AWE32_ErrorCode ); + break; + + case AWE32_Ok : + ErrorString = "AWE32 ok."; + break; + + case AWE32_SoundBlasterError : + ErrorString = BLASTER_ErrorString( BLASTER_Error ); + break; + + case AWE32_NotDetected : + ErrorString = "Could not detect AWE32."; + break; + + case AWE32_UnableToInitialize : + ErrorString = "Unable to initialize AWE32."; + + case AWE32_MPU401Error : + ErrorString = "MPU-401 initialization failed in AWE32."; + break; + + case AWE32_DPMI_Error : + ErrorString = "DPMI Error in AWE32."; + break; + + default : + ErrorString = "Unknown AWE32 error code."; + break; + } + + return( ErrorString ); + } + + +/********************************************************************** + + Memory locked functions: + +**********************************************************************/ + + +#define AWE32_LockStart AWE32_NoteOff + + +void AWE32_NoteOff + ( + int channel, + int key, + int velocity + ) + + { + unsigned temp; + + temp = SetES(); + awe32NoteOff( channel, key, velocity ); + RestoreES( temp ); + NoteFlags[ key ] ^= ( 1 << channel ); + } + +void AWE32_NoteOn + ( + int channel, + int key, + int velocity + ) + + { + unsigned temp; + + temp = SetES(); + awe32NoteOn( channel, key, velocity ); + RestoreES( temp ); + NoteFlags[ key ] |= ( 1 << channel ); + } + +void AWE32_PolyAftertouch + ( + int channel, + int key, + int pressure + ) + + { + unsigned temp; + + temp = SetES(); + awe32PolyKeyPressure( channel, key, pressure ); + RestoreES( temp ); + } + +void AWE32_ChannelAftertouch + ( + int channel, + int pressure + ) + + { + unsigned temp; + + temp = SetES(); + awe32ChannelPressure( channel, pressure ); + RestoreES( temp ); + } + +void AWE32_ControlChange + ( + int channel, + int number, + int value + ) + + { + unsigned temp; + int i; + unsigned channelmask; + + temp = SetES(); + + if ( number == 0x7b ) + { + channelmask = 1 << channel; + for( i = 0; i < 128; i++ ) + { + if ( NoteFlags[ i ] & channelmask ) + { + awe32NoteOff( channel, i, 0 ); + NoteFlags[ i ] ^= channelmask; + } + } + } + else + { + awe32Controller( channel, number, value ); + } + RestoreES( temp ); + } + +void AWE32_ProgramChange + ( + int channel, + int program + ) + + { + unsigned temp; + + temp = SetES(); + awe32ProgramChange( channel, program ); + RestoreES( temp ); + } + +void AWE32_PitchBend + ( + int channel, + int lsb, + int msb + ) + + { + unsigned temp; + + temp = SetES(); + awe32PitchBend( channel, lsb, msb ); + RestoreES( temp ); + } + + +/*--------------------------------------------------------------------- + Function: AWE32_LockEnd + + Used for determining the length of the functions to lock in memory. +---------------------------------------------------------------------*/ + +static void AWE32_LockEnd + ( + void + ) + + { + } + + +/* +static int InitMPU + ( + void + ) + + { + volatile DWORD dwCount; + + for (dwCount=0; dwCount<0x2000; dwCount++) ; + dwCount = 0x2000; + while (dwCount && _inp(MPUPort(1)) & 0x40) --dwCount; + _outp(MPUPort(1), MPU_RESET_CMD); + + for (dwCount=0; dwCount<0x2000; dwCount++) ; + dwCount = 0x2000; + while (dwCount && _inp(MPUPort(1)) & 0x80) --dwCount; + _inp(MPUPort(0)); + + for (dwCount=0; dwCount<0x2000; dwCount++) ; + dwCount = 0x2000; + while (dwCount && _inp(MPUPort(1)) & 0x40) --dwCount; + _outp(MPUPort(1), MPU_RESET_CMD); + + for (dwCount=0; dwCount<0x2000; dwCount++) ; + dwCount = 0x2000; + while (dwCount && _inp(MPUPort(1)) & 0x80) --dwCount; + _inp(MPUPort(0)); + + for (dwCount=0; dwCount<0x2000; dwCount++) ; + dwCount = 0x2000; + while (dwCount && _inp(MPUPort(1)) & 0x40) --dwCount; + _outp(MPUPort(1), MPU_ENTER_UART); + + for (dwCount=0; dwCount<0x2000; dwCount++) ; + dwCount = 0x2000; + while (dwCount && _inp(MPUPort(1)) & 0x80) --dwCount; + if (!dwCount) return TRUE; + if (_inp(MPUPort(0)) != MPU_ACK_OK) return TRUE; + + // mask MPU-401 interrupt + _outp(SBCPort(0x4), 0x83); + _outp(SBCPort(0x5), _inp(SBCPort(0x5)) & ~0x04); + + return FALSE; + } +*/ + +/*ÕÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͸*/ +/*³ ShutdownMPU ³*/ +/*³ Cleans up Sound Blaster to normal state. ³*/ +/*ÔÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ;*/ + +static void ShutdownMPU + ( + void + ) + + { + volatile DWORD dwCount; + + for (dwCount=0; dwCount<0x2000; dwCount++) ; + dwCount = 0x2000; + while (dwCount && _inp(MPUPort(1)) & 0x40) --dwCount; + _outp(MPUPort(1), MPU_RESET_CMD); + for (dwCount=0; dwCount<0x2000; dwCount++) ; + _inp(MPUPort(0)); + + for (dwCount=0; dwCount<0x2000; dwCount++) ; + dwCount = 0x2000; + while (dwCount && _inp(MPUPort(1)) & 0x40) --dwCount; + _outp(MPUPort(1), MPU_RESET_CMD); + for (dwCount=0; dwCount<0x2000; dwCount++) ; + _inp(MPUPort(0)); + } + + +/*ÕÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͸*/ +/*³ LoadSBK ³*/ +/*ÔÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ;*/ + +static void LoadSBK + ( + void + ) + + { + /* use embeded preset objects */ + spSound.bank_no = 0; /* load as Bank 0 */ + spSound.total_banks = 1; /* use 1 bank first */ + lBankSizes[ 0 ] = 0; /* ram is not needed */ + + spSound.banksizes = lBankSizes; + awe32DefineBankSizes( &spSound ); + awe32SoundPad.SPad1 = awe32SPad1Obj; + awe32SoundPad.SPad2 = awe32SPad2Obj; + awe32SoundPad.SPad3 = awe32SPad3Obj; + awe32SoundPad.SPad4 = awe32SPad4Obj; + awe32SoundPad.SPad5 = awe32SPad5Obj; + awe32SoundPad.SPad6 = awe32SPad6Obj; + awe32SoundPad.SPad7 = awe32SPad7Obj; + } + + +int AWE32_Init + ( + void + ) + + { + int status; + BLASTER_CONFIG Blaster; + + wSBCBaseAddx = 0x220; + wEMUBaseAddx = 0x620; + wMpuBaseAddx = 0x330; + + status = BLASTER_GetCardSettings( &Blaster ); + if ( status != BLASTER_Ok ) + { + status = BLASTER_GetEnv( &Blaster ); + if ( status != BLASTER_Ok ) + { + AWE32_SetErrorCode( AWE32_SoundBlasterError ); + return( AWE32_Error ); + } + } + + wSBCBaseAddx = Blaster.Address; + if ( wSBCBaseAddx == UNDEFINED ) + { + wSBCBaseAddx = 0x220; + } + + wMpuBaseAddx = Blaster.Midi; + if ( wMpuBaseAddx == UNDEFINED ) + { + wMpuBaseAddx = 0x330; + } + + wEMUBaseAddx = Blaster.Emu; + if ( wEMUBaseAddx <= 0 ) + { + wEMUBaseAddx = wSBCBaseAddx + 0x400; + } + + status = awe32Detect( wEMUBaseAddx ); + if ( status ) + { + AWE32_SetErrorCode( AWE32_NotDetected ); + return( AWE32_Error ); + } + + status = awe32InitHardware(); + if ( status ) + { + AWE32_SetErrorCode( AWE32_UnableToInitialize ); + return( AWE32_Error ); + } + + + status = awe32InitMIDI(); + if ( status ) + { + AWE32_Shutdown(); + AWE32_SetErrorCode( AWE32_MPU401Error ) + return( AWE32_Error ); + } + +/* + status = InitMPU(); + if ( status ) + { + ShutdownMPU(); + status = InitMPU(); + if ( status ) + { + ShutdownMPU(); + status = InitMPU(); + if ( status ) + { + AWE32_Shutdown(); + AWE32_SetErrorCode( AWE32_MPU401Error ) + return( AWE32_Error ); + } + } + } +*/ + status = DPMI_LockMemoryRegion( AWE32_LockStart, AWE32_LockEnd ); + status |= DPMI_Lock( wSBCBaseAddx ); + status |= DPMI_Lock( wEMUBaseAddx ); + status |= DPMI_Lock( wMpuBaseAddx ); + status |= DPMI_Lock( spSound ); + status |= DPMI_Lock( lBankSizes ); + status |= DPMI_LockMemory( NoteFlags, sizeof( NoteFlags ) ); + + // Lock awe32 library + status = DPMI_LockMemoryRegion( __midieng_code, __midieng_ecode ); + status = DPMI_LockMemoryRegion( __midieng_code(), __midieng_ecode() ); + status = DPMI_LockMemoryRegion( __nrpn_code, __nrpn_ecode ); + status = DPMI_LockMemoryRegion( __nrpn_code(), __nrpn_ecode() ); + status = DPMI_LockMemoryRegion( &__midivar_data, &__midivar_edata ); + status = DPMI_LockMemoryRegion( &__nrpnvar_data, &__nrpnvar_edata ); + status = DPMI_LockMemoryRegion( &__embed_data, &__embed_edata ); + + if ( status != DPMI_Ok ) + { + ShutdownMPU(); + awe32Terminate(); + AWE32_SetErrorCode( AWE32_DPMI_Error ); + return( AWE32_Error ); + } + + // Set the number of voices to use to 32 + awe32NumG = 32; + + awe32TotalPatchRam(&spSound); + + LoadSBK(); + awe32InitMIDI(); + awe32InitNRPN(); + + memset( NoteFlags, 0, sizeof( NoteFlags ) ); + + return( AWE32_Ok ); + } + +void AWE32_Shutdown + ( + void + ) + + { + ShutdownMPU(); + awe32Terminate(); + + DPMI_UnlockMemoryRegion( AWE32_LockStart, AWE32_LockEnd ); + DPMI_Unlock( wSBCBaseAddx ); + DPMI_Unlock( wEMUBaseAddx ); + DPMI_Unlock( wMpuBaseAddx ); + DPMI_Unlock( spSound ); + DPMI_Unlock( lBankSizes ); + DPMI_UnlockMemory( NoteFlags, sizeof( NoteFlags ) ); + + // Unlock awe32 library + DPMI_UnlockMemoryRegion( __midieng_code, __midieng_ecode ); + DPMI_UnlockMemoryRegion( __midieng_code(), __midieng_ecode() ); + DPMI_UnlockMemoryRegion( __nrpn_code, __nrpn_ecode ); + DPMI_UnlockMemoryRegion( __nrpn_code(), __nrpn_ecode() ); + DPMI_UnlockMemoryRegion( &__midivar_data, &__midivar_edata ); + DPMI_UnlockMemoryRegion( &__nrpnvar_data, &__nrpnvar_edata ); + DPMI_UnlockMemoryRegion( &__embed_data, &__embed_edata ); + } diff --git a/audiolib/awe32.h b/audiolib/awe32.h new file mode 100755 index 0000000..a234b17 --- /dev/null +++ b/audiolib/awe32.h @@ -0,0 +1,58 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: AWE32.H + + author: James R. Dose + date: August 23, 1994 + + Public header for AWE32.C Cover functions for calling the + AWE32 low-level library. + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#ifndef __AWE32_H +#define __AWE32_H + +enum AWE32_ERRORS + { + AWE32_Warning = -2, + AWE32_Error = -1, + AWE32_Ok = 0, + AWE32_SoundBlasterError, + AWE32_NotDetected, + AWE32_UnableToInitialize, + AWE32_MPU401Error, + AWE32_DPMI_Error + }; + +char *AWE32_ErrorString( int ErrorNumber ); +int AWE32_Init( void ); +void AWE32_Shutdown( void ); +void AWE32_NoteOff( int channel, int key, int velocity ); +void AWE32_NoteOn( int channel, int key, int velocity ); +void AWE32_PolyAftertouch( int channel, int key, int pressure ); +void AWE32_ChannelAftertouch( int channel, int pressure ); +void AWE32_ControlChange( int channel, int number, int value ); +void AWE32_ProgramChange( int channel, int program ); +void AWE32_PitchBend( int channel, int lsb, int msb ); + +#endif diff --git a/audiolib/blaster.c b/audiolib/blaster.c new file mode 100755 index 0000000..8ff3935 --- /dev/null +++ b/audiolib/blaster.c @@ -0,0 +1,2330 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: BLASTER.C + + author: James R. Dose + date: February 4, 1994 + + Low level routines to support Sound Blaster, Sound Blaster Pro, + Sound Blaster 16, and compatible sound cards. + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "dpmi.h" +#include "dma.h" +#include "irq.h" +#include "blaster.h" +#include "_blaster.h" + +#define USESTACK + +const int BLASTER_Interrupts[ BLASTER_MaxIrq + 1 ] = + { + INVALID, INVALID, 0xa, 0xb, + INVALID, 0xd, INVALID, 0xf, + INVALID, INVALID, 0x72, 0x73, + 0x74, INVALID, INVALID, 0x77 + }; + +const int BLASTER_SampleSize[ BLASTER_MaxMixMode + 1 ] = + { + MONO_8BIT_SAMPLE_SIZE, STEREO_8BIT_SAMPLE_SIZE, + MONO_16BIT_SAMPLE_SIZE, STEREO_16BIT_SAMPLE_SIZE + }; + +const CARD_CAPABILITY BLASTER_CardConfig[ BLASTER_MaxCardType + 1 ] = + { + { FALSE, INVALID, INVALID, INVALID, INVALID }, // Unsupported + { TRUE, NO, MONO_8BIT, 4000, 23000 }, // SB 1.0 + { TRUE, YES, STEREO_8BIT, 4000, 44100 }, // SBPro + { TRUE, NO, MONO_8BIT, 4000, 23000 }, // SB 2.xx + { TRUE, YES, STEREO_8BIT, 4000, 44100 }, // SBPro 2 + { FALSE, INVALID, INVALID, INVALID, INVALID }, // Unsupported + { TRUE, YES, STEREO_16BIT, 5000, 44100 }, // SB16 + }; + +CARD_CAPABILITY BLASTER_Card; + +static void ( __interrupt __far *BLASTER_OldInt )( void ); + +BLASTER_CONFIG BLASTER_Config = + { + UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED, UNDEFINED + }; + +static int BLASTER_Installed = FALSE; + +int BLASTER_Version; + +static char *BLASTER_DMABuffer; +static char *BLASTER_DMABufferEnd; +static char *BLASTER_CurrentDMABuffer; +static int BLASTER_TotalDMABufferSize; + +static int BLASTER_TransferLength = 0; +static int BLASTER_MixMode = BLASTER_DefaultMixMode; +static int BLASTER_SamplePacketSize = MONO_16BIT_SAMPLE_SIZE; +static unsigned BLASTER_SampleRate = BLASTER_DefaultSampleRate; + +static unsigned BLASTER_HaltTransferCommand = DSP_Halt8bitTransfer; + +volatile int BLASTER_SoundPlaying; +volatile int BLASTER_SoundRecording; + +void ( *BLASTER_CallBack )( void ); + +static int BLASTER_IntController1Mask; +static int BLASTER_IntController2Mask; + +static int BLASTER_MixerAddress = UNDEFINED; +static int BLASTER_MixerType = 0; +static int BLASTER_OriginalMidiVolumeLeft = 255; +static int BLASTER_OriginalMidiVolumeRight = 255; +static int BLASTER_OriginalVoiceVolumeLeft = 255; +static int BLASTER_OriginalVoiceVolumeRight = 255; + +static int BLASTER_WaveBlasterState = 0x0F; + +// adequate stack size +#define kStackSize 2048 + +static unsigned short StackSelector = NULL; +static unsigned long StackPointer; + +static unsigned short oldStackSelector; +static unsigned long oldStackPointer; + +// This is defined because we can't create local variables in a +// function that switches stacks. +static int GlobalStatus; + +// These declarations are necessary to use the inline assembly pragmas. + +extern void GetStack(unsigned short *selptr,unsigned long *stackptr); +extern void SetStack(unsigned short selector,unsigned long stackptr); + +// This function will get the current stack selector and pointer and save +// them off. +#pragma aux GetStack = \ + "mov [edi],esp" \ + "mov ax,ss" \ + "mov [esi],ax" \ + parm [esi] [edi] \ + modify [eax esi edi]; + +// This function will set the stack selector and pointer to the specified +// values. +#pragma aux SetStack = \ + "mov ss,ax" \ + "mov esp,edx" \ + parm [ax] [edx] \ + modify [eax edx]; + +int BLASTER_DMAChannel; + +int BLASTER_ErrorCode = BLASTER_Ok; + +#define BLASTER_SetErrorCode( status ) \ + BLASTER_ErrorCode = ( status ); + + +/*--------------------------------------------------------------------- + Function: BLASTER_ErrorString + + Returns a pointer to the error message associated with an error + number. A -1 returns a pointer the current error. +---------------------------------------------------------------------*/ + +char *BLASTER_ErrorString + ( + int ErrorNumber + ) + + { + char *ErrorString; + + switch( ErrorNumber ) + { + case BLASTER_Warning : + case BLASTER_Error : + ErrorString = BLASTER_ErrorString( BLASTER_ErrorCode ); + break; + + case BLASTER_Ok : + ErrorString = "Sound Blaster ok."; + break; + + case BLASTER_EnvNotFound : + ErrorString = "BLASTER environment variable not set."; + break; + + case BLASTER_AddrNotSet : + ErrorString = "Sound Blaster address not set."; + break; + + case BLASTER_DMANotSet : + ErrorString = "Sound Blaster 8-bit DMA channel not set."; + break; + + case BLASTER_DMA16NotSet : + ErrorString = "Sound Blaster 16-bit DMA channel not set."; + break; + + case BLASTER_InvalidParameter : + ErrorString = "Invalid parameter in BLASTER environment variable."; + break; + + case BLASTER_CardNotReady : + ErrorString = "Sound Blaster not responding on selected port."; + break; + + case BLASTER_NoSoundPlaying : + ErrorString = "No sound playing on Sound Blaster."; + break; + + case BLASTER_InvalidIrq : + ErrorString = "Invalid Sound Blaster Irq."; + break; + + case BLASTER_UnableToSetIrq : + ErrorString = "Unable to set Sound Blaster IRQ. Try selecting an IRQ of 7 or below."; + break; + + case BLASTER_DmaError : + ErrorString = DMA_ErrorString( DMA_Error ); + break; + + case BLASTER_NoMixer : + ErrorString = "Mixer not available on selected Sound Blaster card."; + break; + + case BLASTER_DPMI_Error : + ErrorString = "DPMI Error in Blaster."; + break; + + case BLASTER_OutOfMemory : + ErrorString = "Out of conventional memory in Blaster."; + break; + + default : + ErrorString = "Unknown Sound Blaster error code."; + break; + } + + return( ErrorString ); + } + + +/********************************************************************** + + Memory locked functions: + +**********************************************************************/ + + +#define BLASTER_LockStart BLASTER_EnableInterrupt + + +/*--------------------------------------------------------------------- + Function: BLASTER_EnableInterrupt + + Enables the triggering of the sound card interrupt. +---------------------------------------------------------------------*/ + +void BLASTER_EnableInterrupt + ( + void + ) + + { + int Irq; + int mask; + + // Unmask system interrupt + Irq = BLASTER_Config.Interrupt; + if ( Irq < 8 ) + { + mask = inp( 0x21 ) & ~( 1 << Irq ); + outp( 0x21, mask ); + } + else + { + mask = inp( 0xA1 ) & ~( 1 << ( Irq - 8 ) ); + outp( 0xA1, mask ); + + mask = inp( 0x21 ) & ~( 1 << 2 ); + outp( 0x21, mask ); + } + + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_DisableInterrupt + + Disables the triggering of the sound card interrupt. +---------------------------------------------------------------------*/ + +void BLASTER_DisableInterrupt + ( + void + ) + + { + int Irq; + int mask; + + // Restore interrupt mask + Irq = BLASTER_Config.Interrupt; + if ( Irq < 8 ) + { + mask = inp( 0x21 ) & ~( 1 << Irq ); + mask |= BLASTER_IntController1Mask & ( 1 << Irq ); + outp( 0x21, mask ); + } + else + { + mask = inp( 0x21 ) & ~( 1 << 2 ); + mask |= BLASTER_IntController1Mask & ( 1 << 2 ); + outp( 0x21, mask ); + + mask = inp( 0xA1 ) & ~( 1 << ( Irq - 8 ) ); + mask |= BLASTER_IntController2Mask & ( 1 << ( Irq - 8 ) ); + outp( 0xA1, mask ); + } + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_ServiceInterrupt + + Handles interrupt generated by sound card at the end of a voice + transfer. Calls the user supplied callback function. +---------------------------------------------------------------------*/ + +void __interrupt __far BLASTER_ServiceInterrupt + ( + void + ) + + { + #ifdef USESTACK + // save stack + GetStack( &oldStackSelector, &oldStackPointer ); + + // set our stack + SetStack( StackSelector, StackPointer ); + #endif + + // Acknowledge interrupt + // Check if this is this an SB16 or newer + if ( BLASTER_Version >= DSP_Version4xx ) + { + outp( BLASTER_Config.Address + BLASTER_MixerAddressPort, + MIXER_DSP4xxISR_Ack ); + + GlobalStatus = inp( BLASTER_Config.Address + BLASTER_MixerDataPort ); + + // Check if a 16-bit DMA interrupt occurred + if ( GlobalStatus & MIXER_16BITDMA_INT ) + { + // Acknowledge 16-bit transfer interrupt + inp( BLASTER_Config.Address + BLASTER_16BitDMAAck ); + } + else if ( GlobalStatus & MIXER_8BITDMA_INT ) + { + inp( BLASTER_Config.Address + BLASTER_DataAvailablePort ); + } + else + { + #ifdef USESTACK + // restore stack + SetStack( oldStackSelector, oldStackPointer ); + #endif + + // Wasn't our interrupt. Call the old one. + _chain_intr( BLASTER_OldInt ); + } + } + else + { + // Older card - can't detect if an interrupt occurred. + inp( BLASTER_Config.Address + BLASTER_DataAvailablePort ); + } + + // Keep track of current buffer + BLASTER_CurrentDMABuffer += BLASTER_TransferLength; + + if ( BLASTER_CurrentDMABuffer >= BLASTER_DMABufferEnd ) + { + BLASTER_CurrentDMABuffer = BLASTER_DMABuffer; + } + + // Continue playback on cards without autoinit mode + if ( BLASTER_Version < DSP_Version2xx ) + { + if ( BLASTER_SoundPlaying ) + { + BLASTER_DSP1xx_BeginPlayback( BLASTER_TransferLength ); + } + + if ( BLASTER_SoundRecording ) + { + BLASTER_DSP1xx_BeginRecord( BLASTER_TransferLength ); + } + } + + // Call the caller's callback function + if ( BLASTER_CallBack != NULL ) + { + BLASTER_CallBack(); + } + + #ifdef USESTACK + // restore stack + SetStack( oldStackSelector, oldStackPointer ); + #endif + + // send EOI to Interrupt Controller + if ( BLASTER_Config.Interrupt > 7 ) + { + outp( 0xA0, 0x20 ); + } + + outp( 0x20, 0x20 ); + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_WriteDSP + + Writes a byte of data to the sound card's DSP. +---------------------------------------------------------------------*/ + +int BLASTER_WriteDSP + ( + unsigned data + ) + + { + int port; + unsigned count; + int status; + + port = BLASTER_Config.Address + BLASTER_WritePort; + + status = BLASTER_Error; + + count = 0xFFFF; + + do + { + if ( ( inp( port ) & 0x80 ) == 0 ) + { + outp( port, data ); + status = BLASTER_Ok; + break; + } + + count--; + } + while( count > 0 ); + + if ( status != BLASTER_Ok ) + { + BLASTER_SetErrorCode( BLASTER_CardNotReady ); + } + + return( status ); + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_ReadDSP + + Reads a byte of data from the sound card's DSP. +---------------------------------------------------------------------*/ + +int BLASTER_ReadDSP + ( + void + ) + + { + int port; + unsigned count; + int status; + + port = BLASTER_Config.Address + BLASTER_DataAvailablePort; + + status = BLASTER_Error; + + count = 0xFFFF; + + do + { + if ( inp( port ) & 0x80 ) + { + status = inp( BLASTER_Config.Address + BLASTER_ReadPort ); + break; + } + + count--; + } + while( count > 0 ); + + if ( status == BLASTER_Error ) + { + BLASTER_SetErrorCode( BLASTER_CardNotReady ); + } + + return( status ); + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_ResetDSP + + Sends a reset command to the sound card's Digital Signal Processor + (DSP), causing it to perform an initialization. +---------------------------------------------------------------------*/ + +int BLASTER_ResetDSP + ( + void + ) + + { + volatile int count; + int port; + int status; + + port = BLASTER_Config.Address + BLASTER_ResetPort; + + status = BLASTER_CardNotReady; + + outp( port, 1 ); + +/* What the hell am I doing here? + count = 100; + + do + { + if ( inp( port ) == 255 ) + { + break; + } + + count--; + } + while( count > 0 ); +*/ + + count = 0x100; + do + { + count--; + } + while( count > 0 ); + + outp( port, 0 ); + + count = 100; + + do + { + if ( BLASTER_ReadDSP() == BLASTER_Ready ) + { + status = BLASTER_Ok; + break; + } + + count--; + } + while( count > 0 ); + + return( status ); + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_GetDSPVersion + + Returns the version number of the sound card's DSP. +---------------------------------------------------------------------*/ + +int BLASTER_GetDSPVersion + ( + void + ) + + { + int MajorVersion; + int MinorVersion; + int version; + + BLASTER_WriteDSP( DSP_GetVersion ); + + MajorVersion = BLASTER_ReadDSP(); + MinorVersion = BLASTER_ReadDSP(); + + if ( ( MajorVersion == BLASTER_Error ) || + ( MinorVersion == BLASTER_Error ) ) + { + BLASTER_SetErrorCode( BLASTER_CardNotReady ); + return( BLASTER_Error ); + } + + version = ( MajorVersion << 8 ) + MinorVersion; + + if ( version >= DSP_Version4xx ) + { + BLASTER_Card.IsSupported = TRUE; + BLASTER_Card.HasMixer = YES; + BLASTER_Card.MaxMixMode = STEREO_16BIT; + BLASTER_Card.MinSamplingRate = 5000; + BLASTER_Card.MaxSamplingRate = 44100; + BLASTER_MixerType = SB16; + } + else if ( version >= DSP_Version3xx ) + { + BLASTER_Card.IsSupported = TRUE; + BLASTER_Card.HasMixer = YES; + BLASTER_Card.MaxMixMode = STEREO_8BIT; + BLASTER_Card.MinSamplingRate = 4000; + BLASTER_Card.MaxSamplingRate = 44100; + BLASTER_MixerType = SBPro; + } + else if ( version >= DSP_Version2xx ) + { + BLASTER_Card.IsSupported = TRUE; + BLASTER_Card.HasMixer = NO; + BLASTER_Card.MaxMixMode = MONO_8BIT; + BLASTER_Card.MinSamplingRate = 4000; + BLASTER_Card.MaxSamplingRate = 23000; + BLASTER_MixerType = 0; + } + else + { + // DSP_Version1xx + BLASTER_Card.IsSupported = TRUE; + BLASTER_Card.HasMixer = NO; + BLASTER_Card.MaxMixMode = MONO_8BIT; + BLASTER_Card.MinSamplingRate = 4000; + BLASTER_Card.MaxSamplingRate = 23000; + BLASTER_MixerType = 0; + } + + return( version ); + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_SpeakerOn + + Enables output from the DAC. +---------------------------------------------------------------------*/ + +void BLASTER_SpeakerOn + ( + void + ) + + { + BLASTER_WriteDSP( DSP_SpeakerOn ); + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_SpeakerOff + + Disables output from the DAC. +---------------------------------------------------------------------*/ + +void BLASTER_SpeakerOff + ( + void + ) + + { + BLASTER_WriteDSP( DSP_SpeakerOff ); + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_SetPlaybackRate + + Sets the rate at which the digitized sound will be played in + hertz. +---------------------------------------------------------------------*/ + +void BLASTER_SetPlaybackRate + ( + unsigned rate + ) + + { + int LoByte; + int HiByte; + + if ( BLASTER_Version < DSP_Version4xx ) + { + int timeconstant; + long ActualRate; + + // Send sampling rate as time constant for older Sound + // Blaster compatible cards. + + ActualRate = rate * BLASTER_SamplePacketSize; + if ( ActualRate < BLASTER_Card.MinSamplingRate ) + { + rate = BLASTER_Card.MinSamplingRate / BLASTER_SamplePacketSize; + } + + if ( ActualRate > BLASTER_Card.MaxSamplingRate ) + { + rate = BLASTER_Card.MaxSamplingRate / BLASTER_SamplePacketSize; + } + + timeconstant = ( int )CalcTimeConstant( rate, BLASTER_SamplePacketSize ); + + // Keep track of what the actual rate is + BLASTER_SampleRate = ( unsigned )CalcSamplingRate( timeconstant ); + BLASTER_SampleRate /= BLASTER_SamplePacketSize; + + BLASTER_WriteDSP( DSP_SetTimeConstant ); + BLASTER_WriteDSP( timeconstant ); + } + else + { + // Send literal sampling rate for cards with DSP version + // 4.xx (Sound Blaster 16) + + BLASTER_SampleRate = rate; + + if ( BLASTER_SampleRate < BLASTER_Card.MinSamplingRate ) + { + BLASTER_SampleRate = BLASTER_Card.MinSamplingRate; + } + + if ( BLASTER_SampleRate > BLASTER_Card.MaxSamplingRate ) + { + BLASTER_SampleRate = BLASTER_Card.MaxSamplingRate; + } + + HiByte = hibyte( BLASTER_SampleRate ); + LoByte = lobyte( BLASTER_SampleRate ); + + // Set playback rate + BLASTER_WriteDSP( DSP_Set_DA_Rate ); + BLASTER_WriteDSP( HiByte ); + BLASTER_WriteDSP( LoByte ); + + // Set recording rate + BLASTER_WriteDSP( DSP_Set_AD_Rate ); + BLASTER_WriteDSP( HiByte ); + BLASTER_WriteDSP( LoByte ); + } + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_GetPlaybackRate + + Returns the rate at which the digitized sound will be played in + hertz. +---------------------------------------------------------------------*/ + +unsigned BLASTER_GetPlaybackRate + ( + void + ) + + { + return( BLASTER_SampleRate ); + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_SetMixMode + + Sets the sound card to play samples in mono or stereo. +---------------------------------------------------------------------*/ + +int BLASTER_SetMixMode + ( + int mode + ) + + { + int port; + int data; + int CardType; + + CardType = BLASTER_Config.Type; + + mode &= BLASTER_MaxMixMode; + + if ( !( BLASTER_Card.MaxMixMode & STEREO ) ) + { + mode &= ~STEREO; + } + + if ( !( BLASTER_Card.MaxMixMode & SIXTEEN_BIT ) ) + { + mode &= ~SIXTEEN_BIT; + } + + BLASTER_MixMode = mode; + BLASTER_SamplePacketSize = BLASTER_SampleSize[ mode ]; + + // For the Sound Blaster Pro, we have to set the mixer chip + // to play mono or stereo samples. + + if ( ( CardType == SBPro ) || ( CardType == SBPro2 ) ) + { + port = BLASTER_Config.Address + BLASTER_MixerAddressPort; + outp( port, MIXER_SBProOutputSetting ); + + port = BLASTER_Config.Address + BLASTER_MixerDataPort; + + // Get current mode + data = inp( port ); + + // set stereo mode bit + if ( mode & STEREO ) + { + data |= MIXER_SBProStereoFlag; + } + else + { + data &= ~MIXER_SBProStereoFlag; + } + + // set the mode + outp( port, data ); + + BLASTER_SetPlaybackRate( BLASTER_SampleRate ); + } + + return( mode ); + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_StopPlayback + + Ends the DMA transfer of digitized sound to the sound card. +---------------------------------------------------------------------*/ + +void BLASTER_StopPlayback + ( + void + ) + + { + int DmaChannel; + + // Don't allow anymore interrupts + BLASTER_DisableInterrupt(); + + if ( BLASTER_HaltTransferCommand == DSP_Reset ) + { + BLASTER_ResetDSP(); + } + else + { + BLASTER_WriteDSP( BLASTER_HaltTransferCommand ); + } + + // Disable the DMA channel + if ( BLASTER_MixMode & SIXTEEN_BIT ) + { + DmaChannel = BLASTER_Config.Dma16; + } + else + { + DmaChannel = BLASTER_Config.Dma8; + } + DMA_EndTransfer( DmaChannel ); + + // Turn off speaker + BLASTER_SpeakerOff(); + + BLASTER_SoundPlaying = FALSE; + BLASTER_SoundRecording = FALSE; + + BLASTER_DMABuffer = NULL; + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_SetupDMABuffer + + Programs the DMAC for sound transfer. +---------------------------------------------------------------------*/ + +int BLASTER_SetupDMABuffer + ( + char *BufferPtr, + int BufferSize, + int mode + ) + + { + int DmaChannel; + int DmaStatus; + int errorcode; + + if ( BLASTER_MixMode & SIXTEEN_BIT ) + { + DmaChannel = BLASTER_Config.Dma16; + errorcode = BLASTER_DMA16NotSet; + } + else + { + DmaChannel = BLASTER_Config.Dma8; + errorcode = BLASTER_DMANotSet; + } + + if ( DmaChannel == UNDEFINED ) + { + BLASTER_SetErrorCode( errorcode ); + return( BLASTER_Error ); + } + + DmaStatus = DMA_SetupTransfer( DmaChannel, BufferPtr, BufferSize, mode ); + if ( DmaStatus == DMA_Error ) + { + BLASTER_SetErrorCode( BLASTER_DmaError ); + return( BLASTER_Error ); + } + + BLASTER_DMAChannel = DmaChannel; + + BLASTER_DMABuffer = BufferPtr; + BLASTER_CurrentDMABuffer = BufferPtr; + BLASTER_TotalDMABufferSize = BufferSize; + BLASTER_DMABufferEnd = BufferPtr + BufferSize; + + return( BLASTER_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_GetCurrentPos + + Returns the offset within the current sound being played. +---------------------------------------------------------------------*/ + +int BLASTER_GetCurrentPos + ( + void + ) + + { + char *CurrentAddr; + int DmaChannel; + int offset; + + if ( !BLASTER_SoundPlaying ) + { + BLASTER_SetErrorCode( BLASTER_NoSoundPlaying ); + return( BLASTER_Error ); + } + + if ( BLASTER_MixMode & SIXTEEN_BIT ) + { + DmaChannel = BLASTER_Config.Dma16; + } + else + { + DmaChannel = BLASTER_Config.Dma8; + } + + if ( DmaChannel == UNDEFINED ) + { + BLASTER_SetErrorCode( BLASTER_DMANotSet ); + return( BLASTER_Error ); + } + + CurrentAddr = DMA_GetCurrentPos( DmaChannel ); + + offset = ( int )( ( ( unsigned long )CurrentAddr ) - + ( ( unsigned long )BLASTER_CurrentDMABuffer ) ); + + if ( BLASTER_MixMode & SIXTEEN_BIT ) + { + offset >>= 1; + } + + if ( BLASTER_MixMode & STEREO ) + { + offset >>= 1; + } + + return( offset ); + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_DSP1xx_BeginPlayback + + Starts playback of digitized sound on cards compatible with DSP + version 1.xx. +---------------------------------------------------------------------*/ + +int BLASTER_DSP1xx_BeginPlayback + ( + int length + ) + + { + int SampleLength; + int LoByte; + int HiByte; + + SampleLength = length - 1; + HiByte = hibyte( SampleLength ); + LoByte = lobyte( SampleLength ); + + // Program DSP to play sound + BLASTER_WriteDSP( DSP_Old8BitDAC ); + BLASTER_WriteDSP( LoByte ); + BLASTER_WriteDSP( HiByte ); + + BLASTER_HaltTransferCommand = DSP_Halt8bitTransfer; + + BLASTER_SoundPlaying = TRUE; + + return( BLASTER_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_DSP2xx_BeginPlayback + + Starts playback of digitized sound on cards compatible with DSP + version 2.xx. +---------------------------------------------------------------------*/ + +int BLASTER_DSP2xx_BeginPlayback + ( + int length + ) + + { + int SampleLength; + int LoByte; + int HiByte; + + SampleLength = length - 1; + HiByte = hibyte( SampleLength ); + LoByte = lobyte( SampleLength ); + + BLASTER_WriteDSP( DSP_SetBlockLength ); + BLASTER_WriteDSP( LoByte ); + BLASTER_WriteDSP( HiByte ); + + if ( ( BLASTER_Version >= DSP_Version201 ) && ( DSP_MaxNormalRate < + ( BLASTER_SampleRate * BLASTER_SamplePacketSize ) ) ) + { + BLASTER_WriteDSP( DSP_8BitHighSpeedAutoInitMode ); + BLASTER_HaltTransferCommand = DSP_Reset; + } + else + { + BLASTER_WriteDSP( DSP_8BitAutoInitMode ); + BLASTER_HaltTransferCommand = DSP_Halt8bitTransfer; + } + + BLASTER_SoundPlaying = TRUE; + + return( BLASTER_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_DSP4xx_BeginPlayback + + Starts playback of digitized sound on cards compatible with DSP + version 4.xx, such as the Sound Blaster 16. +---------------------------------------------------------------------*/ + +int BLASTER_DSP4xx_BeginPlayback + ( + int length + ) + + { + int TransferCommand; + int TransferMode; + int SampleLength; + int LoByte; + int HiByte; + + if ( BLASTER_MixMode & SIXTEEN_BIT ) + { + TransferCommand = DSP_16BitDAC; + SampleLength = ( length / 2 ) - 1; + BLASTER_HaltTransferCommand = DSP_Halt16bitTransfer; + if ( BLASTER_MixMode & STEREO ) + { + TransferMode = DSP_SignedStereoData; + } + else + { + TransferMode = DSP_SignedMonoData; + } + } + else + { + TransferCommand = DSP_8BitDAC; + SampleLength = length - 1; + BLASTER_HaltTransferCommand = DSP_Halt8bitTransfer; + if ( BLASTER_MixMode & STEREO ) + { + TransferMode = DSP_UnsignedStereoData; + } + else + { + TransferMode = DSP_UnsignedMonoData; + } + } + + HiByte = hibyte( SampleLength ); + LoByte = lobyte( SampleLength ); + + // Program DSP to play sound + BLASTER_WriteDSP( TransferCommand ); + BLASTER_WriteDSP( TransferMode ); + BLASTER_WriteDSP( LoByte ); + BLASTER_WriteDSP( HiByte ); + + BLASTER_SoundPlaying = TRUE; + + return( BLASTER_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_BeginBufferedPlayback + + Begins multibuffered playback of digitized sound on the sound card. +---------------------------------------------------------------------*/ + +int BLASTER_BeginBufferedPlayback + ( + char *BufferStart, + int BufferSize, + int NumDivisions, + unsigned SampleRate, + int MixMode, + void ( *CallBackFunc )( void ) + ) + + { + int DmaStatus; + int TransferLength; + +//JIM +// if ( BLASTER_SoundPlaying || BLASTER_SoundRecording ) + { + BLASTER_StopPlayback(); + } + + BLASTER_SetMixMode( MixMode ); + + DmaStatus = BLASTER_SetupDMABuffer( BufferStart, BufferSize, DMA_AutoInitRead ); + if ( DmaStatus == BLASTER_Error ) + { + return( BLASTER_Error ); + } + + BLASTER_SetPlaybackRate( SampleRate ); + + BLASTER_SetCallBack( CallBackFunc ); + + BLASTER_EnableInterrupt(); + + // Turn on speaker + BLASTER_SpeakerOn(); + + TransferLength = BufferSize / NumDivisions; + BLASTER_TransferLength = TransferLength; + + // Program the sound card to start the transfer. + if ( BLASTER_Version < DSP_Version2xx ) + { + BLASTER_DSP1xx_BeginPlayback( TransferLength ); + } + else if ( BLASTER_Version < DSP_Version4xx ) + { + BLASTER_DSP2xx_BeginPlayback( TransferLength ); + } + else + { + BLASTER_DSP4xx_BeginPlayback( TransferLength ); + } + + return( BLASTER_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_DSP4xx_BeginRecord + + Starts recording of digitized sound on cards compatible with DSP + version 4.xx, such as the Sound Blaster 16. +---------------------------------------------------------------------*/ + +int BLASTER_DSP4xx_BeginRecord + ( + int length + ) + + { + int TransferCommand; + int TransferMode; + int SampleLength; + int LoByte; + int HiByte; + + TransferCommand = DSP_8BitADC; + SampleLength = length - 1; + BLASTER_HaltTransferCommand = DSP_Halt8bitTransfer; + + TransferMode = DSP_UnsignedMonoData; + + HiByte = hibyte( SampleLength ); + LoByte = lobyte( SampleLength ); + + // Program DSP to play sound + BLASTER_WriteDSP( TransferCommand ); + BLASTER_WriteDSP( TransferMode ); + BLASTER_WriteDSP( LoByte ); + BLASTER_WriteDSP( HiByte ); + + BLASTER_SoundRecording = TRUE; + + return( BLASTER_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_DSP2xx_BeginRecord + + Starts recording of digitized sound on cards compatible with DSP + version 2.xx. +---------------------------------------------------------------------*/ + +int BLASTER_DSP2xx_BeginRecord + ( + int length + ) + + { + int SampleLength; + int LoByte; + int HiByte; + + SampleLength = length - 1; + HiByte = hibyte( SampleLength ); + LoByte = lobyte( SampleLength ); + + BLASTER_WriteDSP( DSP_SetBlockLength ); + BLASTER_WriteDSP( LoByte ); + BLASTER_WriteDSP( HiByte ); + + if ( ( BLASTER_Version >= DSP_Version201 ) && ( DSP_MaxNormalRate < + ( BLASTER_SampleRate * BLASTER_SamplePacketSize ) ) ) + { + BLASTER_WriteDSP( DSP_8BitHighSpeedAutoInitRecord ); + BLASTER_HaltTransferCommand = DSP_Reset; + } + else + { + BLASTER_WriteDSP( DSP_8BitAutoInitRecord ); + BLASTER_HaltTransferCommand = DSP_Halt8bitTransfer; + } + + BLASTER_SoundRecording = TRUE; + + return( BLASTER_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_DSP1xx_BeginRecord + + Starts recording of digitized sound on cards compatible with DSP + version 1.xx. +---------------------------------------------------------------------*/ + +int BLASTER_DSP1xx_BeginRecord + ( + int length + ) + + { + int SampleLength; + int LoByte; + int HiByte; + + SampleLength = length - 1; + HiByte = hibyte( SampleLength ); + LoByte = lobyte( SampleLength ); + + // Program DSP to play sound + BLASTER_WriteDSP( DSP_Old8BitADC ); + BLASTER_WriteDSP( LoByte ); + BLASTER_WriteDSP( HiByte ); + + BLASTER_HaltTransferCommand = DSP_Halt8bitTransfer; + + BLASTER_SoundRecording = TRUE; + + return( BLASTER_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_BeginBufferedRecord + + Begins multibuffered recording of digitized sound on the sound card. +---------------------------------------------------------------------*/ + +int BLASTER_BeginBufferedRecord + ( + char *BufferStart, + int BufferSize, + int NumDivisions, + unsigned SampleRate, + int MixMode, + void ( *CallBackFunc )( void ) + ) + + { + int DmaStatus; + int TransferLength; + +//JIM +// if ( BLASTER_SoundPlaying || BLASTER_SoundRecording ) + { + BLASTER_StopPlayback(); + } + + BLASTER_SetMixMode( MixMode ); + + DmaStatus = BLASTER_SetupDMABuffer( BufferStart, BufferSize, DMA_AutoInitWrite ); + if ( DmaStatus == BLASTER_Error ) + { + return( BLASTER_Error ); + } + + BLASTER_SetPlaybackRate( SampleRate ); + + BLASTER_SetCallBack( CallBackFunc ); + + BLASTER_EnableInterrupt(); + + // Turn off speaker + BLASTER_SpeakerOff(); + + TransferLength = BufferSize / NumDivisions; + BLASTER_TransferLength = TransferLength; + + // Program the sound card to start the transfer. + if ( BLASTER_Version < DSP_Version2xx ) + { + BLASTER_DSP1xx_BeginRecord( TransferLength ); + } + else if ( BLASTER_Version < DSP_Version4xx ) + { + BLASTER_DSP2xx_BeginRecord( TransferLength ); + } + else + { + BLASTER_DSP4xx_BeginRecord( TransferLength ); + } + + return( BLASTER_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_WriteMixer + + Writes a byte of data to the Sound Blaster's mixer chip. +---------------------------------------------------------------------*/ + +void BLASTER_WriteMixer + ( + int reg, + int data + ) + + { + outp( BLASTER_MixerAddress + BLASTER_MixerAddressPort, reg ); + outp( BLASTER_MixerAddress + BLASTER_MixerDataPort, data ); + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_ReadMixer + + Reads a byte of data from the Sound Blaster's mixer chip. +---------------------------------------------------------------------*/ + +int BLASTER_ReadMixer + ( + int reg + ) + + { + int data; + + outp( BLASTER_MixerAddress + BLASTER_MixerAddressPort, reg ); + data = inp( BLASTER_MixerAddress + BLASTER_MixerDataPort ); + return( data ); + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_GetVoiceVolume + + Reads the average volume of the digitized sound channel from the + Sound Blaster's mixer chip. +---------------------------------------------------------------------*/ + +int BLASTER_GetVoiceVolume + ( + void + ) + + { + int volume; + int left; + int right; + + switch( BLASTER_MixerType ) + { + case SBPro : + case SBPro2 : + left = BLASTER_ReadMixer( MIXER_SBProVoice ); + right = ( left & 0x0f ) << 4; + left &= 0xf0; + volume = ( left + right ) / 2; + break; + + case SB16 : + left = BLASTER_ReadMixer( MIXER_SB16VoiceLeft ); + right = BLASTER_ReadMixer( MIXER_SB16VoiceRight ); + volume = ( left + right ) / 2; + break; + + default : + BLASTER_SetErrorCode( BLASTER_NoMixer ); + volume = BLASTER_Error; + } + + return( volume ); + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_SetVoiceVolume + + Sets the volume of the digitized sound channel on the Sound + Blaster's mixer chip. +---------------------------------------------------------------------*/ + +int BLASTER_SetVoiceVolume + ( + int volume + ) + + { + int data; + int status; + + volume = min( 255, volume ); + volume = max( 0, volume ); + + status = BLASTER_Ok; + switch( BLASTER_MixerType ) + { + case SBPro : + case SBPro2 : + data = ( volume & 0xf0 ) + ( volume >> 4 ); + BLASTER_WriteMixer( MIXER_SBProVoice, data ); + break; + + case SB16 : + BLASTER_WriteMixer( MIXER_SB16VoiceLeft, volume & 0xf8 ); + BLASTER_WriteMixer( MIXER_SB16VoiceRight, volume & 0xf8 ); + break; + + default : + BLASTER_SetErrorCode( BLASTER_NoMixer ); + status = BLASTER_Error; + } + + return( status ); + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_GetMidiVolume + + Reads the average volume of the Midi sound channel from the + Sound Blaster's mixer chip. +---------------------------------------------------------------------*/ + +int BLASTER_GetMidiVolume + ( + void + ) + + { + int volume; + int left; + int right; + + switch( BLASTER_MixerType ) + { + case SBPro : + case SBPro2 : + left = BLASTER_ReadMixer( MIXER_SBProMidi ); + right = ( left & 0x0f ) << 4; + left &= 0xf0; + volume = ( left + right ) / 2; + break; + + case SB16 : + left = BLASTER_ReadMixer( MIXER_SB16MidiLeft ); + right = BLASTER_ReadMixer( MIXER_SB16MidiRight ); + volume = ( left + right ) / 2; + break; + + default : + BLASTER_SetErrorCode( BLASTER_NoMixer ); + volume = BLASTER_Error; + } + + return( volume ); + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_SetMidiVolume + + Sets the volume of the Midi sound channel on the Sound + Blaster's mixer chip. +---------------------------------------------------------------------*/ + +int BLASTER_SetMidiVolume + ( + int volume + ) + + { + int data; + int status; + + volume = min( 255, volume ); + volume = max( 0, volume ); + + status = BLASTER_Ok; + switch( BLASTER_MixerType ) + { + case SBPro : + case SBPro2 : + data = ( volume & 0xf0 ) + ( volume >> 4 ); + BLASTER_WriteMixer( MIXER_SBProMidi, data ); + break; + + case SB16 : + BLASTER_WriteMixer( MIXER_SB16MidiLeft, volume & 0xf8 ); + BLASTER_WriteMixer( MIXER_SB16MidiRight, volume & 0xf8 ); + break; + + default : + BLASTER_SetErrorCode( BLASTER_NoMixer ); + status = BLASTER_Error; + } + + return( status ); + } + +/*--------------------------------------------------------------------- + Function: BLASTER_CardHasMixer + + Checks if the selected Sound Blaster card has a mixer. +---------------------------------------------------------------------*/ + +int BLASTER_CardHasMixer + ( + void + ) + + { + return( BLASTER_Card.HasMixer ); + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_SaveVoiceVolume + + Saves the user's voice mixer settings. +---------------------------------------------------------------------*/ + +void BLASTER_SaveVoiceVolume + ( + void + ) + + { + switch( BLASTER_MixerType ) + { + case SBPro : + case SBPro2 : + BLASTER_OriginalVoiceVolumeLeft = + BLASTER_ReadMixer( MIXER_SBProVoice ); + break; + + case SB16 : + BLASTER_OriginalVoiceVolumeLeft = + BLASTER_ReadMixer( MIXER_SB16VoiceLeft ); + BLASTER_OriginalVoiceVolumeRight = + BLASTER_ReadMixer( MIXER_SB16VoiceRight ); + break; + } + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_RestoreVoiceVolume + + Restores the user's voice mixer settings. +---------------------------------------------------------------------*/ + +void BLASTER_RestoreVoiceVolume + ( + void + ) + + { + switch( BLASTER_MixerType ) + { + case SBPro : + case SBPro2 : + BLASTER_WriteMixer( MIXER_SBProVoice, + BLASTER_OriginalVoiceVolumeLeft ); + break; + + case SB16 : + BLASTER_WriteMixer( MIXER_SB16VoiceLeft, + BLASTER_OriginalVoiceVolumeLeft ); + BLASTER_WriteMixer( MIXER_SB16VoiceRight, + BLASTER_OriginalVoiceVolumeRight ); + break; + } + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_SaveMidiVolume + + Saves the user's FM mixer settings. +---------------------------------------------------------------------*/ + +void BLASTER_SaveMidiVolume + ( + void + ) + + { + switch( BLASTER_MixerType ) + { + case SBPro : + case SBPro2 : + BLASTER_OriginalMidiVolumeLeft = + BLASTER_ReadMixer( MIXER_SBProMidi ); + break; + + case SB16 : + BLASTER_OriginalMidiVolumeLeft = + BLASTER_ReadMixer( MIXER_SB16MidiLeft ); + BLASTER_OriginalMidiVolumeRight = + BLASTER_ReadMixer( MIXER_SB16MidiRight ); + break; + } + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_RestoreMidiVolume + + Restores the user's FM mixer settings. +---------------------------------------------------------------------*/ + +void BLASTER_RestoreMidiVolume + ( + void + ) + + { + switch( BLASTER_MixerType ) + { + case SBPro : + case SBPro2 : + BLASTER_WriteMixer( MIXER_SBProMidi, + BLASTER_OriginalMidiVolumeLeft ); + break; + + case SB16 : + BLASTER_WriteMixer( MIXER_SB16MidiLeft, + BLASTER_OriginalMidiVolumeLeft ); + BLASTER_WriteMixer( MIXER_SB16MidiRight, + BLASTER_OriginalMidiVolumeRight ); + break; + } + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_GetEnv + + Retrieves the BLASTER environment settings and returns them to + the caller. +---------------------------------------------------------------------*/ + +int BLASTER_GetEnv + ( + BLASTER_CONFIG *Config + ) + + { + char *Blaster; + char parameter; + + Config->Address = UNDEFINED; + Config->Type = UNDEFINED; + Config->Interrupt = UNDEFINED; + Config->Dma8 = UNDEFINED; + Config->Dma16 = UNDEFINED; + Config->Midi = UNDEFINED; + Config->Emu = UNDEFINED; + + Blaster = getenv( "BLASTER" ); + if ( Blaster == NULL ) + { + BLASTER_SetErrorCode( BLASTER_EnvNotFound ); + return( BLASTER_Error ); + } + + while( *Blaster != 0 ) + { + if ( *Blaster == ' ' ) + { + Blaster++; + continue; + } + + parameter = toupper( *Blaster ); + Blaster++; + + if ( !isxdigit( *Blaster ) ) + { + BLASTER_SetErrorCode( BLASTER_InvalidParameter ); + return( BLASTER_Error ); + } + + switch( parameter ) + { + case BlasterEnv_Address : + sscanf( Blaster, "%x", &Config->Address ); + break; + case BlasterEnv_Interrupt : + sscanf( Blaster, "%d", &Config->Interrupt ); + break; + case BlasterEnv_8bitDma : + sscanf( Blaster, "%d", &Config->Dma8 ); + break; + case BlasterEnv_Type : + sscanf( Blaster, "%d", &Config->Type ); + break; + case BlasterEnv_16bitDma : + sscanf( Blaster, "%d", &Config->Dma16 ); + break; + case BlasterEnv_Midi : + sscanf( Blaster, "%x", &Config->Midi ); + break; + case BlasterEnv_EmuAddress : + sscanf( Blaster, "%x", &Config->Emu ); + break; + default : + // Skip the offending data + // sscanf( Blaster, "%*s" ); + break; + } + + while( isxdigit( *Blaster ) ) + { + Blaster++; + } + } + + return( BLASTER_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_SetCardSettings + + Sets up the sound card's parameters. +---------------------------------------------------------------------*/ + +int BLASTER_SetCardSettings + ( + BLASTER_CONFIG Config + ) + + { + if ( BLASTER_Installed ) + { + BLASTER_Shutdown(); + } + + BLASTER_Config.Address = Config.Address; + BLASTER_Config.Type = Config.Type; + BLASTER_Config.Interrupt = Config.Interrupt; + BLASTER_Config.Dma8 = Config.Dma8; + BLASTER_Config.Dma16 = Config.Dma16; + BLASTER_Config.Midi = Config.Midi; + BLASTER_Config.Emu = Config.Emu; + BLASTER_MixerAddress = Config.Address; + BLASTER_MixerType = Config.Type; + + if ( BLASTER_Config.Emu == UNDEFINED ) + { + BLASTER_Config.Emu = BLASTER_Config.Address + 0x400; + } + + return( BLASTER_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_GetCardSettings + + Sets up the sound card's parameters. +---------------------------------------------------------------------*/ + +int BLASTER_GetCardSettings + ( + BLASTER_CONFIG *Config + ) + + { + if ( BLASTER_Config.Address == UNDEFINED ) + { + return( BLASTER_Warning ); + } + else + { + Config->Address = BLASTER_Config.Address; + Config->Type = BLASTER_Config.Type; + Config->Interrupt = BLASTER_Config.Interrupt; + Config->Dma8 = BLASTER_Config.Dma8; + Config->Dma16 = BLASTER_Config.Dma16; + Config->Midi = BLASTER_Config.Midi; + Config->Emu = BLASTER_Config.Emu; + } + + return( BLASTER_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_GetCardInfo + + Returns the maximum number of bits that can represent a sample + (8 or 16) and the number of channels (1 for mono, 2 for stereo). +---------------------------------------------------------------------*/ + +int BLASTER_GetCardInfo + ( + int *MaxSampleBits, + int *MaxChannels + ) + + { + if ( BLASTER_Card.MaxMixMode & STEREO ) + { + *MaxChannels = 2; + } + else + { + *MaxChannels = 1; + } + + if ( BLASTER_Card.MaxMixMode & SIXTEEN_BIT ) + { + *MaxSampleBits = 16; + } + else + { + *MaxSampleBits = 8; + } + + return( BLASTER_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_SetCallBack + + Specifies the user function to call at the end of a sound transfer. +---------------------------------------------------------------------*/ + +void BLASTER_SetCallBack + ( + void ( *func )( void ) + ) + + { + BLASTER_CallBack = func; + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_LockEnd + + Used for determining the length of the functions to lock in memory. +---------------------------------------------------------------------*/ + +static void BLASTER_LockEnd + ( + void + ) + + { + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_UnlockMemory + + Unlocks all neccessary data. +---------------------------------------------------------------------*/ + +void BLASTER_UnlockMemory + ( + void + ) + + { + DPMI_UnlockMemoryRegion( BLASTER_LockStart, BLASTER_LockEnd ); + DPMI_UnlockMemory( ( void * )&BLASTER_Interrupts[ 0 ], + sizeof( BLASTER_Interrupts ) ); + DPMI_UnlockMemory( ( void * )&BLASTER_SampleSize[ 0 ], + sizeof( BLASTER_SampleSize ) ); + DPMI_Unlock( BLASTER_Card ); + DPMI_Unlock( BLASTER_OldInt ); + DPMI_Unlock( BLASTER_Config ); + DPMI_Unlock( BLASTER_Installed ); + DPMI_Unlock( BLASTER_Version ); + DPMI_Unlock( BLASTER_DMABuffer ); + DPMI_Unlock( BLASTER_DMABufferEnd ); + DPMI_Unlock( BLASTER_CurrentDMABuffer ); + DPMI_Unlock( BLASTER_TotalDMABufferSize ); + DPMI_Unlock( BLASTER_TransferLength ); + DPMI_Unlock( BLASTER_MixMode ); + DPMI_Unlock( BLASTER_SamplePacketSize ); + DPMI_Unlock( BLASTER_SampleRate ); + DPMI_Unlock( BLASTER_HaltTransferCommand ); + DPMI_Unlock( ( int )BLASTER_SoundPlaying ); + DPMI_Unlock( ( int )BLASTER_SoundRecording ); + DPMI_Unlock( BLASTER_CallBack ); + DPMI_Unlock( BLASTER_IntController1Mask ); + DPMI_Unlock( BLASTER_IntController2Mask ); + DPMI_Unlock( BLASTER_MixerAddress ); + DPMI_Unlock( BLASTER_MixerType ); + DPMI_Unlock( BLASTER_OriginalMidiVolumeLeft ); + DPMI_Unlock( BLASTER_OriginalMidiVolumeRight ); + DPMI_Unlock( BLASTER_OriginalVoiceVolumeLeft ); + DPMI_Unlock( BLASTER_OriginalVoiceVolumeRight ); + DPMI_Unlock( GlobalStatus ); + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_LockMemory + + Locks all neccessary data. +---------------------------------------------------------------------*/ + +int BLASTER_LockMemory + ( + void + ) + + { + int status; + + status = DPMI_LockMemoryRegion( BLASTER_LockStart, BLASTER_LockEnd ); + status |= DPMI_LockMemory( ( void * )&BLASTER_Interrupts[ 0 ], + sizeof( BLASTER_Interrupts ) ); + status |= DPMI_LockMemory( ( void * )&BLASTER_SampleSize[ 0 ], + sizeof( BLASTER_SampleSize ) ); + status |= DPMI_Lock( BLASTER_Card ); + status |= DPMI_Lock( BLASTER_OldInt ); + status |= DPMI_Lock( BLASTER_Config ); + status |= DPMI_Lock( BLASTER_Installed ); + status |= DPMI_Lock( BLASTER_Version ); + status |= DPMI_Lock( BLASTER_DMABuffer ); + status |= DPMI_Lock( BLASTER_DMABufferEnd ); + status |= DPMI_Lock( BLASTER_CurrentDMABuffer ); + status |= DPMI_Lock( BLASTER_TotalDMABufferSize ); + status |= DPMI_Lock( BLASTER_TransferLength ); + status |= DPMI_Lock( BLASTER_MixMode ); + status |= DPMI_Lock( BLASTER_SamplePacketSize ); + status |= DPMI_Lock( BLASTER_SampleRate ); + status |= DPMI_Lock( BLASTER_HaltTransferCommand ); + status |= DPMI_Lock( ( ( int )BLASTER_SoundPlaying ) ); + status |= DPMI_Lock( ( ( int )BLASTER_SoundRecording ) ); + status |= DPMI_Lock( BLASTER_CallBack ); + status |= DPMI_Lock( BLASTER_IntController1Mask ); + status |= DPMI_Lock( BLASTER_IntController2Mask ); + status |= DPMI_Lock( BLASTER_MixerAddress ); + status |= DPMI_Lock( BLASTER_MixerType ); + status |= DPMI_Lock( BLASTER_OriginalMidiVolumeLeft ); + status |= DPMI_Lock( BLASTER_OriginalMidiVolumeRight ); + status |= DPMI_Lock( BLASTER_OriginalVoiceVolumeLeft ); + status |= DPMI_Lock( BLASTER_OriginalVoiceVolumeRight ); + status |= DPMI_Lock( GlobalStatus ); + + if ( status != DPMI_Ok ) + { + BLASTER_UnlockMemory(); + BLASTER_SetErrorCode( BLASTER_DPMI_Error ); + return( BLASTER_Error ); + } + + return( BLASTER_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: allocateTimerStack + + Allocate a block of memory from conventional (low) memory and return + the selector (which can go directly into a segment register) of the + memory block or 0 if an error occured. +---------------------------------------------------------------------*/ + +static unsigned short allocateTimerStack + ( + unsigned short size + ) + + { + union REGS regs; + + // clear all registers + memset( ®s, 0, sizeof( regs ) ); + + // DPMI allocate conventional memory + regs.w.ax = 0x100; + + // size in paragraphs + regs.w.bx = ( size + 15 ) / 16; + + int386( 0x31, ®s, ®s ); + if (!regs.w.cflag) + { + // DPMI call returns selector in dx + // (ax contains real mode segment + // which is ignored here) + + return( regs.w.dx ); + } + + // Couldn't allocate memory. + return( NULL ); + } + + +/*--------------------------------------------------------------------- + Function: deallocateTimerStack + + Deallocate a block of conventional (low) memory given a selector to + it. Assumes the block was allocated with DPMI function 0x100. +---------------------------------------------------------------------*/ + +static void deallocateTimerStack + ( + unsigned short selector + ) + + { + union REGS regs; + + if ( selector != NULL ) + { + // clear all registers + memset( ®s, 0, sizeof( regs ) ); + + regs.w.ax = 0x101; + regs.w.dx = selector; + int386( 0x31, ®s, ®s ); + } + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_SetupWaveBlaster + + Allows the WaveBlaster to play music while the Sound Blaster 16 + plays digital sound. +---------------------------------------------------------------------*/ + +void BLASTER_SetupWaveBlaster + ( + void + ) + + { + + if ( BLASTER_MixerType == SB16 ) + { + // Disable MPU401 interrupts. If they are not disabled, + // the SB16 will not produce sound or music. + BLASTER_WaveBlasterState = BLASTER_ReadMixer( MIXER_DSP4xxISR_Enable ); + BLASTER_WriteMixer( MIXER_DSP4xxISR_Enable, MIXER_DisableMPU401Interrupts ); + } + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_ShutdownWaveBlaster + + Restores WaveBlaster mixer to original state. +---------------------------------------------------------------------*/ + +void BLASTER_ShutdownWaveBlaster + ( + void + ) + + { + if ( BLASTER_MixerType == SB16 ) + { + // Restore the state of MPU401 interrupts. If they are not disabled, + // the SB16 will not produce sound or music. + BLASTER_WriteMixer( MIXER_DSP4xxISR_Enable, BLASTER_WaveBlasterState ); + } + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_Init + + Initializes the sound card and prepares the module to play + digitized sounds. +---------------------------------------------------------------------*/ + +int BLASTER_Init + ( + void + ) + + { + int Irq; + int Interrupt; + int status; + + if ( BLASTER_Installed ) + { + BLASTER_Shutdown(); + } + + if ( BLASTER_Config.Address == UNDEFINED ) + { + BLASTER_SetErrorCode( BLASTER_AddrNotSet ); + return( BLASTER_Error ); + } + + // Save the interrupt masks + BLASTER_IntController1Mask = inp( 0x21 ); + BLASTER_IntController2Mask = inp( 0xA1 ); + + status = BLASTER_ResetDSP(); + if ( status == BLASTER_Ok ) + { + BLASTER_SaveVoiceVolume(); + + BLASTER_SoundPlaying = FALSE; + + BLASTER_SetCallBack( NULL ); + + BLASTER_DMABuffer = NULL; + + BLASTER_Version = BLASTER_GetDSPVersion(); + + BLASTER_SetPlaybackRate( BLASTER_DefaultSampleRate ); + BLASTER_SetMixMode( BLASTER_DefaultMixMode ); + + if ( BLASTER_Config.Dma16 != UNDEFINED ) + { + status = DMA_VerifyChannel( BLASTER_Config.Dma16 ); + if ( status == DMA_Error ) + { + BLASTER_SetErrorCode( BLASTER_DmaError ); + return( BLASTER_Error ); + } + } + + if ( BLASTER_Config.Dma8 != UNDEFINED ) + { + status = DMA_VerifyChannel( BLASTER_Config.Dma8 ); + if ( status == DMA_Error ) + { + BLASTER_SetErrorCode( BLASTER_DmaError ); + return( BLASTER_Error ); + } + } + + // Install our interrupt handler + Irq = BLASTER_Config.Interrupt; + if ( !VALID_IRQ( Irq ) ) + { + BLASTER_SetErrorCode( BLASTER_InvalidIrq ); + return( BLASTER_Error ); + } + + Interrupt = BLASTER_Interrupts[ Irq ]; + if ( Interrupt == INVALID ) + { + BLASTER_SetErrorCode( BLASTER_InvalidIrq ); + return( BLASTER_Error ); + } + + status = BLASTER_LockMemory(); + if ( status != BLASTER_Ok ) + { + BLASTER_UnlockMemory(); + return( status ); + } + + StackSelector = allocateTimerStack( kStackSize ); + if ( StackSelector == NULL ) + { + BLASTER_UnlockMemory(); + BLASTER_SetErrorCode( BLASTER_OutOfMemory ); + return( BLASTER_Error ); + } + + // Leave a little room at top of stack just for the hell of it... + StackPointer = kStackSize - sizeof( long ); + + BLASTER_OldInt = _dos_getvect( Interrupt ); + if ( Irq < 8 ) + { + _dos_setvect( Interrupt, BLASTER_ServiceInterrupt ); + } + else + { + status = IRQ_SetVector( Interrupt, BLASTER_ServiceInterrupt ); + if ( status != IRQ_Ok ) + { + BLASTER_UnlockMemory(); + deallocateTimerStack( StackSelector ); + StackSelector = NULL; + BLASTER_SetErrorCode( BLASTER_UnableToSetIrq ); + return( BLASTER_Error ); + } + } + + BLASTER_Installed = TRUE; + status = BLASTER_Ok; + } + + BLASTER_SetErrorCode( status ); + return( status ); + } + + +/*--------------------------------------------------------------------- + Function: BLASTER_Shutdown + + Ends transfer of sound data to the sound card and restores the + system resources used by the card. +---------------------------------------------------------------------*/ + +void BLASTER_Shutdown + ( + void + ) + + { + int Irq; + int Interrupt; + + // Halt the DMA transfer + BLASTER_StopPlayback(); + + BLASTER_RestoreVoiceVolume(); + + // Reset the DSP + BLASTER_ResetDSP(); + + // Restore the original interrupt + Irq = BLASTER_Config.Interrupt; + Interrupt = BLASTER_Interrupts[ Irq ]; + if ( Irq >= 8 ) + { + IRQ_RestoreVector( Interrupt ); + } + _dos_setvect( Interrupt, BLASTER_OldInt ); + + BLASTER_SoundPlaying = FALSE; + + BLASTER_DMABuffer = NULL; + + BLASTER_SetCallBack( NULL ); + + BLASTER_UnlockMemory(); + + deallocateTimerStack( StackSelector ); + StackSelector = NULL; + + BLASTER_Installed = FALSE; + } diff --git a/audiolib/blaster.h b/audiolib/blaster.h new file mode 100755 index 0000000..f56324b --- /dev/null +++ b/audiolib/blaster.h @@ -0,0 +1,148 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: BLASTER.H + + author: James R. Dose + date: February 4, 1994 + + Public header for BLASTER.C + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#ifndef __BLASTER_H +#define __BLASTER_H + +typedef struct + { + unsigned Address; + unsigned Type; + unsigned Interrupt; + unsigned Dma8; + unsigned Dma16; + unsigned Midi; + unsigned Emu; + } BLASTER_CONFIG; + +extern BLASTER_CONFIG BLASTER_Config; +extern int BLASTER_DMAChannel; + +#define UNDEFINED -1 + +enum BLASTER_ERRORS + { + BLASTER_Warning = -2, + BLASTER_Error = -1, + BLASTER_Ok = 0, + BLASTER_EnvNotFound, + BLASTER_AddrNotSet, + BLASTER_DMANotSet, + BLASTER_DMA16NotSet, + BLASTER_InvalidParameter, + BLASTER_CardNotReady, + BLASTER_NoSoundPlaying, + BLASTER_InvalidIrq, + BLASTER_UnableToSetIrq, + BLASTER_DmaError, + BLASTER_NoMixer, + BLASTER_DPMI_Error, + BLASTER_OutOfMemory + }; + +enum BLASTER_Types + { + SB = 1, + SBPro = 2, + SB20 = 3, + SBPro2 = 4, + SB16 = 6 + }; + +#define BLASTER_MinCardType SB +#define BLASTER_MaxCardType SB16 + +#define STEREO 1 +#define SIXTEEN_BIT 2 + +#define MONO_8BIT 0 +#define STEREO_8BIT ( STEREO ) +#define MONO_16BIT ( SIXTEEN_BIT ) +#define STEREO_16BIT ( STEREO | SIXTEEN_BIT ) + +#define BLASTER_MaxMixMode STEREO_16BIT + +#define MONO_8BIT_SAMPLE_SIZE 1 +#define MONO_16BIT_SAMPLE_SIZE 2 +#define STEREO_8BIT_SAMPLE_SIZE ( 2 * MONO_8BIT_SAMPLE_SIZE ) +#define STEREO_16BIT_SAMPLE_SIZE ( 2 * MONO_16BIT_SAMPLE_SIZE ) + +#define BLASTER_DefaultSampleRate 11000 +#define BLASTER_DefaultMixMode MONO_8BIT +#define BLASTER_MaxIrq 15 + +char *BLASTER_ErrorString( int ErrorNumber ); +void BLASTER_EnableInterrupt( void ); +void BLASTER_DisableInterrupt( void ); +int BLASTER_WriteDSP( unsigned data ); +int BLASTER_ReadDSP( void ); +int BLASTER_ResetDSP( void ); +int BLASTER_GetDSPVersion( void ); +void BLASTER_SpeakerOn( void ); +void BLASTER_SpeakerOff( void ); +void BLASTER_SetPlaybackRate( unsigned rate ); +unsigned BLASTER_GetPlaybackRate( void ); +int BLASTER_SetMixMode( int mode ); +void BLASTER_StopPlayback( void ); +int BLASTER_SetupDMABuffer( char *BufferPtr, int BufferSize, int mode ); +int BLASTER_GetCurrentPos( void ); +int BLASTER_DSP1xx_BeginPlayback( int length ); +int BLASTER_DSP2xx_BeginPlayback( int length ); +int BLASTER_DSP4xx_BeginPlayback( int length ); +int BLASTER_BeginBufferedRecord( char *BufferStart, int BufferSize, + int NumDivisions, unsigned SampleRate, int MixMode, + void ( *CallBackFunc )( void ) ); +int BLASTER_BeginBufferedPlayback( char *BufferStart, + int BufferSize, int NumDivisions, unsigned SampleRate, + int MixMode, void ( *CallBackFunc )( void ) ); +void BLASTER_WriteMixer( int reg, int data ); +int BLASTER_ReadMixer( int reg ); +int BLASTER_GetVoiceVolume( void ); +int BLASTER_SetVoiceVolume( int volume ); +int BLASTER_GetMidiVolume( void ); +int BLASTER_SetMidiVolume( int volume ); +int BLASTER_CardHasMixer( void ); +void BLASTER_SaveVoiceVolume( void ); +void BLASTER_RestoreVoiceVolume( void ); +void BLASTER_SaveMidiVolume( void ); +void BLASTER_RestoreMidiVolume( void ); +int BLASTER_GetEnv( BLASTER_CONFIG *Config ); +int BLASTER_SetCardSettings( BLASTER_CONFIG Config ); +int BLASTER_GetCardSettings( BLASTER_CONFIG *Config ); +int BLASTER_GetCardInfo( int *MaxSampleBits, int *MaxChannels ); +void BLASTER_SetCallBack( void ( *func )( void ) ); +void BLASTER_SetupWaveBlaster( void ); +void BLASTER_ShutdownWaveBlaster( void ); +int BLASTER_Init( void ); +void BLASTER_Shutdown( void ); +void BLASTER_UnlockMemory( void ); +int BLASTER_LockMemory( void ); + +#endif diff --git a/audiolib/ctaweapi.h b/audiolib/ctaweapi.h new file mode 100755 index 0000000..d398f43 --- /dev/null +++ b/audiolib/ctaweapi.h @@ -0,0 +1,352 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/****************************************************************************\ +* * +* CTAWEAPI.H SB AWE32 DOS API header * +* * +* (C) Copyright Creative Technology Ltd. 1992-94. All rights reserved * +* worldwide. * +* * +* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY * +* KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE * +* IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR * +* PURPOSE. * +* * +* You have a royalty-free right to use, modify, reproduce and * +* distribute the Sample Files (and/or any modified version) in * +* any way you find useful, provided that you agree to * +* the Creative's Software Licensing Aggreement and you also agree that * +* Creative has no warranty obligations or liability for any Sample Files. * +* * +\****************************************************************************/ + +/****************************************************************************\ +* File name : CTAWEAPI.H * +* * +* Programmer : Creative SB AWE32 Team * +* Creative Technology Ltd, 1994. All rights reserved. * +* * +* Version : 2.0b * +* * +\****************************************************************************/ + +#ifndef _CTAWEAPI +#define _CTAWEAPI + + +#define MAXBANKS 64 /* maximum number of banks */ +#define MAXNRPN 32 /* maximum number of NRPN */ + + +#if defined(__FLAT__) || defined(__HIGHC__) || defined(DOS386) +#define PACKETSIZE 8192 /* packet size for 32bit libraries */ +#else +#define PACKETSIZE 512 /* packet size for real mode libraries */ +#endif + + +#if defined(__FLAT__) + #define NEAR + #define FAR +#endif + + +#if defined(__SC__) + #pragma pack(1) + #if defined(DOS386) + #define NEAR + #define FAR + #endif +#endif + + +#if defined(__WATCOMC__) + #pragma pack(1) +#endif + + +#if defined(__HIGHC__) + #define NEAR + #define FAR + #define PASCAL _DCC((_DEFAULT_CALLING_CONVENTION|_CALLEE_POPS_STACK) & \ + ~ (_REVERSE_PARMS|_OVERLOADED)) + #pragma Push_align_members(1) + #pragma Global_aliasing_convention("_%r") +#endif + + +typedef int BOOL; +#define FALSE 0 +#define TRUE 1 + +typedef unsigned char BYTE; +typedef unsigned short WORD; +typedef unsigned long DWORD; + +typedef short int SHORT; +typedef unsigned int UINT; +typedef signed long LONG; + +#ifndef FAR +#define FAR __far +#endif + +#ifndef HUGE +#define HUGE __huge +#endif + +#ifndef PASCAL +#define PASCAL __pascal +#endif + +typedef void FAR* LPVOID; +typedef BYTE FAR* LPBYTE; +typedef WORD FAR* LPWORD; +typedef DWORD FAR* LPDWORD; + +#define LOBYTE(w) ((BYTE)(w)) +#define HIBYTE(w) ((BYTE)(((UINT)(w) >> 8) & 0xFF)) + +#define LOWORD(l) ((WORD)(DWORD)(l)) +#define HIWORD(l) ((WORD)((((DWORD)(l)) >> 16) & 0xFFFF)) + + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* Start of modules */ +extern int* __midieng_code(void); +extern int* __hardware_code(void); +extern int* __sbkload_code(void); +extern int* __nrpn_code(void); +extern int __midivar_data; +extern int __nrpnvar_data; +extern int __embed_data; + + +typedef char SCRATCH[702]; +typedef char SOUNDFONT[124]; +typedef char GCHANNEL[20]; +typedef char MIDICHANNEL[32]; +typedef char NRPNCHANNEL[96]; + +typedef struct { + SHORT bank_no; /* Slot number being used */ + SHORT total_banks; /* Total number of banks */ + LONG FAR* banksizes; /* Pointer to a list of bank sizes */ + LONG file_size; /* exact size of the sound font file */ + char FAR* data; /* Address of buffer of size >= PACKETSIZE */ + char FAR* presets; /* Allocated memory for preset data */ + + LONG total_patch_ram; /* Total patch ram available */ + SHORT no_sample_packets;/* Number of packets of sound sample to stream */ + LONG sample_seek; /* Start file location of sound sample */ + LONG preset_seek; /* Address of preset_seek location */ + LONG preset_read_size; /* Number of bytes from preset_seek to allocate and read */ + LONG preset_size; /* Preset actual size */ +} SOUND_PACKET; + +typedef struct { + SHORT tag; /* Must be 0x100 or 0x101 */ + SHORT preset_size; /* Preset table of this size is required */ + SHORT no_wave_packets; /* Number of packets of Wave sample to stream. */ + LONG reserved; + + SHORT bank_no; /* bank number */ + char FAR* data; /* Address of packet of size PACKETSIZE */ + char FAR* presets; /* Allocated memory for preset data */ + LONG sample_size; /* Sample size, i.e. number of samples */ + LONG samples_per_sec; /* Samples per second */ + SHORT bits_per_sample; /* Bits per sample, 8 or 16 */ + SHORT no_channels; /* Number of channels, 1=mono, 2=stereo */ + SHORT looping; /* Looping? 0=no, 1=yes */ + LONG startloop; /* if looping, then these are the addresses */ + LONG endloop; + SHORT release; /* release time, 0=24ms, 8191=23.78s */ +} WAVE_PACKET; + +typedef struct { + LPBYTE SPad1; + LPBYTE SPad2; + LPBYTE SPad3; + LPBYTE SPad4; + LPBYTE SPad5; + LPBYTE SPad6; + LPBYTE SPad7; +} SOUNDPAD; + +/* AWE32 variables */ +extern WORD awe32NumG; +extern WORD awe32BaseAddx; +extern DWORD awe32DramSize; + +/* MIDI variables */ +extern SCRATCH awe32Scratch; +extern SOUNDFONT awe32SFont[4]; +extern GCHANNEL awe32GChannel[32]; +extern MIDICHANNEL awe32MIDIChannel[16]; +extern SOUNDPAD awe32SoundPad; + +/* NRPN variables */ +extern NRPNCHANNEL awe32NRPNChannel[16]; + +/* SoundFont objects */ +extern BYTE awe32SPad1Obj[]; +extern BYTE awe32SPad2Obj[]; +extern BYTE awe32SPad3Obj[]; +extern BYTE awe32SPad4Obj[]; +extern BYTE awe32SPad5Obj[]; +extern BYTE awe32SPad6Obj[]; +extern BYTE awe32SPad7Obj[]; + +/* AWE register functions */ +extern void PASCAL awe32RegW(WORD, WORD); +extern WORD PASCAL awe32RegRW(WORD); +extern void PASCAL awe32RegDW(WORD, DWORD); +extern DWORD PASCAL awe32RegRDW(WORD); + +/* MIDI support functions */ +extern WORD PASCAL awe32InitMIDI(void); +extern WORD PASCAL awe32NoteOn(WORD, WORD, WORD); +extern WORD PASCAL awe32NoteOff(WORD, WORD, WORD); +extern WORD PASCAL awe32ProgramChange(WORD, WORD); +extern WORD PASCAL awe32Controller(WORD, WORD, WORD); +extern WORD PASCAL awe32PolyKeyPressure(WORD, WORD, WORD); +extern WORD PASCAL awe32ChannelPressure(WORD, WORD); +extern WORD PASCAL awe32PitchBend(WORD, WORD, WORD); +extern WORD PASCAL awe32Sysex(WORD, LPBYTE, WORD); +extern WORD PASCAL __awe32NoteOff(WORD, WORD, WORD, WORD); +extern WORD PASCAL __awe32IsPlaying(WORD, WORD, WORD, WORD); + +/* NRPN support functions */ +extern WORD PASCAL awe32InitNRPN(void); + +/* Hardware support functions */ +extern WORD PASCAL awe32Detect(WORD); +extern WORD PASCAL awe32InitHardware(void); +extern WORD PASCAL awe32Terminate(void); + +/* SoundFont support functions */ +extern WORD PASCAL awe32TotalPatchRam(SOUND_PACKET FAR*); +extern WORD PASCAL awe32DefineBankSizes(SOUND_PACKET FAR*); +extern WORD PASCAL awe32SFontLoadRequest(SOUND_PACKET FAR*); +extern WORD PASCAL awe32StreamSample(SOUND_PACKET FAR*); +extern WORD PASCAL awe32SetPresets(SOUND_PACKET FAR*); +extern WORD PASCAL awe32ReleaseBank(SOUND_PACKET FAR*); +extern WORD PASCAL awe32ReleaseAllBanks(SOUND_PACKET FAR*); +extern WORD PASCAL awe32WPLoadRequest(WAVE_PACKET FAR*); +extern WORD PASCAL awe32WPLoadWave(WAVE_PACKET FAR*); +extern WORD PASCAL awe32WPStreamWave(WAVE_PACKET FAR*); +extern WORD PASCAL awe32WPBuildSFont(WAVE_PACKET FAR*); + +/* End of modules */ +extern int* __midieng_ecode(void); +extern int* __hardware_ecode(void); +extern int* __sbkload_ecode(void); +extern int* __nrpn_ecode(void); +extern int __midivar_edata; +extern int __nrpnvar_edata; +extern int __embed_edata; + + +#if defined(__cplusplus) +} +#endif + + +#if defined(__SC__) + #pragma pack() +#endif + + +#if defined(__HIGHC__) + #pragma Pop_align_members + #pragma Global_aliasing_convention() + #pragma Alias(awe32RegW,"AWE32REGW") + #pragma Alias(awe32RegRW,"AWE32REGRW") + #pragma Alias(awe32RegDW,"AWE32REGDW") + #pragma Alias(awe32RegRDW,"AWE32REGRDW") + #pragma Alias(awe32InitMIDI,"AWE32INITMIDI") + #pragma Alias(awe32NoteOn,"AWE32NOTEON") + #pragma Alias(awe32NoteOff,"AWE32NOTEOFF") + #pragma Alias(awe32ProgramChange,"AWE32PROGRAMCHANGE") + #pragma Alias(awe32Controller,"AWE32CONTROLLER") + #pragma Alias(awe32PolyKeyPressure,"AWE32POLYKEYPRESSURE") + #pragma Alias(awe32ChannelPressure,"AWE32CHANNELPRESSURE") + #pragma Alias(awe32PitchBend,"AWE32PITCHBEND") + #pragma Alias(awe32Sysex,"AWE32SYSEX") + #pragma Alias(__awe32NoteOff,"__AWE32NOTEOFF") + #pragma Alias(__awe32IsPlaying,"__AWE32ISPLAYING") + #pragma Alias(awe32InitNRPN,"AWE32INITNRPN") + #pragma Alias(awe32Detect,"AWE32DETECT") + #pragma Alias(awe32InitHardware,"AWE32INITHARDWARE") + #pragma Alias(awe32Terminate,"AWE32TERMINATE") + #pragma Alias(awe32TotalPatchRam,"AWE32TOTALPATCHRAM") + #pragma Alias(awe32DefineBankSizes,"AWE32DEFINEBANKSIZES") + #pragma Alias(awe32SFontLoadRequest,"AWE32SFONTLOADREQUEST") + #pragma Alias(awe32StreamSample,"AWE32STREAMSAMPLE") + #pragma Alias(awe32SetPresets,"AWE32SETPRESETS") + #pragma Alias(awe32ReleaseBank,"AWE32RELEASEBANK") + #pragma Alias(awe32ReleaseAllBanks,"AWE32RELEASEALLBANKS") + #pragma Alias(awe32WPLoadRequest,"AWE32WPLOADREQUEST") + #pragma Alias(awe32WPLoadWave,"AWE32WPLOADWAVE") + #pragma Alias(awe32WPStreamWave,"AWE32WPSTREAMWAVE") + #pragma Alias(awe32WPBuildSFont,"AWE32WPBUILDSFONT") +#endif + + +#if defined(__WATCOMC__) + #pragma pack() + #pragma aux awe32NumG "_*" + #pragma aux awe32BaseAddx "_*" + #pragma aux awe32DramSize "_*" + #pragma aux awe32Scratch "_*" + #pragma aux awe32SFont "_*" + #pragma aux awe32GChannel "_*" + #pragma aux awe32MIDIChannel "_*" + #pragma aux awe32SoundPad "_*" + #pragma aux awe32NRPNChannel "_*" + #pragma aux awe32SPad1Obj "_*" + #pragma aux awe32SPad2Obj "_*" + #pragma aux awe32SPad3Obj "_*" + #pragma aux awe32SPad4Obj "_*" + #pragma aux awe32SPad5Obj "_*" + #pragma aux awe32SPad6Obj "_*" + #pragma aux awe32SPad7Obj "_*" + #pragma aux __midieng_code "_*" + #pragma aux __midieng_ecode "_*" + #pragma aux __hardware_code "_*" + #pragma aux __hardware_ecode "_*" + #pragma aux __sbkload_code "_*" + #pragma aux __sbkload_ecode "_*" + #pragma aux __nrpn_code "_*" + #pragma aux __nrpn_ecode "_*" + #pragma aux __midivar_data "_*" + #pragma aux __midivar_edata "_*" + #pragma aux __nrpnvar_data "_*" + #pragma aux __nrpnvar_edata "_*" + #pragma aux __embed_data "_*" + #pragma aux __embed_edata "_*" +#endif + + +#endif /* _CTAWEAPI */ diff --git a/audiolib/debugio.c b/audiolib/debugio.c new file mode 100755 index 0000000..fb96db5 --- /dev/null +++ b/audiolib/debugio.c @@ -0,0 +1,251 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#include +#include +#include +#include "debugio.h" + +static unsigned short disp_offset = 160 * 24; +static void myutoa( unsigned num, char *string, int radix ); +static void myitoa( int num, char *string, int radix ); + +void DB_SetXY + ( + int x, + int y + ) + + { + disp_offset = ( x * 2 ) + ( y * 160 ); + } + +void DB_PutChar + ( + char ch + ) + + { + int j; + char *disp_start = (char *)( 0xb0000 ); + + if ( disp_offset >= 160 * 24 ) + { + for ( j = 160; j < 160 * 24; j += 2 ) + { + *( disp_start + j - 160 ) = *( disp_start + j ); + } + + disp_offset = 160 * 23; + + for ( j = disp_offset; j < ( 160 * 24 ); j += 2 ) + { + *( disp_start + j ) = ' '; + } + } + + if ( ch >= 32 ) + { + *( disp_start + disp_offset ) = ch; + disp_offset = disp_offset + 2; + } + + if ( ch == '\r' ) + { + disp_offset = disp_offset / 160; + disp_offset = disp_offset * 160; + } + + if ( ch == '\n' ) + { + disp_offset = disp_offset + 160; + if ( disp_offset < 160 * 24 ) + { + for ( j = disp_offset; j < ( ( ( disp_offset / 160 ) + 1 ) * + 160 ); j += 2 ) + { + *( disp_start + j ) = ' '; + } + } + } + } + +int DB_PrintString + ( + char *string + ) + + { + int count; + char *ptr; + + ptr = string; + count = 0; + + while ( *ptr ) + { + DB_PutChar( *ptr ); + count++; + ptr++; + } + + return( count ); + } + +static void myutoa + ( + unsigned num, + char *string, + int radix + ) + + { + int val; + int length; + int pos; + char temp[ 100 ]; + + length = 0; + do + { + val = num % radix; + if ( val < 10 ) + { + temp[ length ] = '0' + val; + } + else + { + temp[ length ] = 'A' + val - 10; + } + num /= radix; + length++; + } + while( num > 0 ); + + pos = 0; + while( length > 0 ) + { + length--; + string[ length ] = temp[ pos ]; + pos++; + } + string[ pos ] = 0; + } + +static void myitoa + ( + int num, + char *string, + int radix + ) + + { + if ( num < 0 ) + { + *string++ = '-'; + num = -num; + } + + myutoa( num, string, radix ); + } + +int DB_PrintNum + ( + int number + ) + + { + char string[ 100 ]; + int count; + + myitoa( number, &string[ 0 ], 10 ); + count = DB_PrintString( &string[ 0 ] ); + + return( count ); + } + +int DB_PrintUnsigned + ( + unsigned long number, + int radix + ) + + { + char string[ 100 ]; + int count; + + myutoa( number, &string[ 0 ], radix ); + count = DB_PrintString( &string[ 0 ] ); + + return( count ); + } + +int DB_printf + ( + char *fmt, + ... + ) + + { + va_list argptr; + int count; + char *ptr; + + va_start( argptr, fmt ); + ptr = fmt; + count = 0; + + while( *ptr != 0 ) + { + if ( *ptr == '%' ) + { + ptr++; + switch( *ptr ) + { + case 0 : + return( EOF ); + break; + case 'd' : + count += DB_PrintNum( va_arg( argptr, int ) ); + break; + case 's' : + count += DB_PrintString( va_arg( argptr, char * ) ); + break; + case 'u' : + count += DB_PrintUnsigned( va_arg( argptr, int ), 10 ); + break; + case 'x' : + case 'X' : + count += DB_PrintUnsigned( va_arg( argptr, int ), 16 ); + break; + } + ptr++; + } + else + { + DB_PutChar( *ptr ); + count++; + ptr++; + } + } + + va_end( argptr ); + + return( count ); + } diff --git a/audiolib/debugio.h b/audiolib/debugio.h new file mode 100755 index 0000000..a6510ba --- /dev/null +++ b/audiolib/debugio.h @@ -0,0 +1,30 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef __DEBUGIO_H +#define __DEBUGIO_H + +void DB_SetXY( int x, int y ); +void DB_PutChar( char ch ); +int DB_PrintString( char *string ); +int DB_PrintNum( int number ); +int DB_PrintUnsigned( unsigned long number, int radix ); +int DB_printf( char *fmt, ... ); + +#endif diff --git a/audiolib/dma.c b/audiolib/dma.c new file mode 100755 index 0000000..6a05872 --- /dev/null +++ b/audiolib/dma.c @@ -0,0 +1,379 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: DMA.C + + author: James R. Dose + date: February 4, 1994 + + Low level routines to for programming the DMA controller for 8 bit + and 16 bit transfers. + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#include +#include +#include +#include "dma.h" + +#define DMA_MaxChannel 7 + +#define VALID ( 1 == 1 ) +#define INVALID ( !VALID ) + +#define BYTE 0 +#define WORD 1 + +typedef struct + { + int Valid; + int Width; + int Mask; + int Mode; + int Clear; + int Page; + int Address; + int Length; + } DMA_PORT; + +static const DMA_PORT DMA_PortInfo[ DMA_MaxChannel + 1 ] = + { + { VALID, BYTE, 0xA, 0xB, 0xC, 0x87, 0x0, 0x1 }, + { VALID, BYTE, 0xA, 0xB, 0xC, 0x83, 0x2, 0x3 }, + { INVALID, BYTE, 0xA, 0xB, 0xC, 0x81, 0x4, 0x5 }, + { VALID, BYTE, 0xA, 0xB, 0xC, 0x82, 0x6, 0x7 }, + { INVALID, WORD, 0xD4, 0xD6, 0xD8, 0x8F, 0xC0, 0xC2 }, + { VALID, WORD, 0xD4, 0xD6, 0xD8, 0x8B, 0xC4, 0xC6 }, + { VALID, WORD, 0xD4, 0xD6, 0xD8, 0x89, 0xC8, 0xCA }, + { VALID, WORD, 0xD4, 0xD6, 0xD8, 0x8A, 0xCC, 0xCE }, + }; + +int DMA_ErrorCode = DMA_Ok; + +#define DMA_SetErrorCode( status ) \ + DMA_ErrorCode = ( status ); + + +/*--------------------------------------------------------------------- + Function: DMA_ErrorString + + Returns a pointer to the error message associated with an error + number. A -1 returns a pointer the current error. +---------------------------------------------------------------------*/ + +char *DMA_ErrorString + ( + int ErrorNumber + ) + + { + char *ErrorString; + + switch( ErrorNumber ) + { + case DMA_Error : + ErrorString = DMA_ErrorString( DMA_ErrorCode ); + break; + + case DMA_Ok : + ErrorString = "DMA channel ok."; + break; + + case DMA_ChannelOutOfRange : + ErrorString = "DMA channel out of valid range."; + break; + + case DMA_InvalidChannel : + ErrorString = "Unsupported DMA channel."; + break; + + default : + ErrorString = "Unknown DMA error code."; + break; + } + + return( ErrorString ); + } + + +/*--------------------------------------------------------------------- + Function: DMA_VerifyChannel + + Verifies whether a DMA channel is available to transfer data. +---------------------------------------------------------------------*/ + +int DMA_VerifyChannel + ( + int channel + ) + + { + int status; + int Error; + + status = DMA_Ok; + Error = DMA_Ok; + + if ( ( channel < 0 ) || ( DMA_MaxChannel < channel ) ) + { + Error = DMA_ChannelOutOfRange; + status = DMA_Error; + } + else if ( DMA_PortInfo[ channel ].Valid == INVALID ) + { + Error = DMA_InvalidChannel; + status = DMA_Error; + } + + DMA_SetErrorCode( Error ); + return( status ); + } + + +/*--------------------------------------------------------------------- + Function: DMA_SetupTransfer + + Programs the specified DMA channel to transfer data. +---------------------------------------------------------------------*/ + +int DMA_SetupTransfer + ( + int channel, + char *address, + int length, + int mode + ) + + { + DMA_PORT *Port; + int addr; + int ChannelSelect; + int Page; + int HiByte; + int LoByte; + int TransferLength; + int status; + + status = DMA_VerifyChannel( channel ); + + if ( status == DMA_Ok ) + { + Port = &DMA_PortInfo[ channel ]; + ChannelSelect = channel & 0x3; + + addr = ( int )address; + + if ( Port->Width == WORD ) + { + Page = ( addr >> 16 ) & 255; + HiByte = ( addr >> 9 ) & 255; + LoByte = ( addr >> 1 ) & 255; + + // Convert the length in bytes to the length in words + TransferLength = ( length + 1 ) >> 1; + + // The length is always one less the number of bytes or words + // that we're going to send + TransferLength--; + } + else + { + Page = ( addr >> 16 ) & 255; + HiByte = ( addr >> 8 ) & 255; + LoByte = addr & 255; + + // The length is always one less the number of bytes or words + // that we're going to send + TransferLength = length - 1; + } + + // Mask off DMA channel + outp( Port->Mask, 4 | ChannelSelect ); + + // Clear flip-flop to lower byte with any data + outp( Port->Clear, 0 ); + + // Set DMA mode + switch( mode ) + { + case DMA_SingleShotRead : + outp( Port->Mode, 0x48 | ChannelSelect ); + break; + + case DMA_SingleShotWrite : + outp( Port->Mode, 0x44 | ChannelSelect ); + break; + + case DMA_AutoInitRead : + outp( Port->Mode, 0x58 | ChannelSelect ); + break; + + case DMA_AutoInitWrite : + outp( Port->Mode, 0x54 | ChannelSelect ); + break; + } + + // Send address + outp( Port->Address, LoByte ); + outp( Port->Address, HiByte ); + + // Send page + outp( Port->Page, Page ); + + // Send length + outp( Port->Length, TransferLength ); + outp( Port->Length, TransferLength >> 8 ); + + // enable DMA channel + outp( Port->Mask, ChannelSelect ); + } + + return( status ); + } + + +/*--------------------------------------------------------------------- + Function: DMA_EndTransfer + + Ends use of the specified DMA channel. +---------------------------------------------------------------------*/ + +int DMA_EndTransfer + ( + int channel + ) + + { + DMA_PORT *Port; + int ChannelSelect; + int status; + + status = DMA_VerifyChannel( channel ); + if ( status == DMA_Ok ) + { + Port = &DMA_PortInfo[ channel ]; + ChannelSelect = channel & 0x3; + + // Mask off DMA channel + outp( Port->Mask, 4 | ChannelSelect ); + + // Clear flip-flop to lower byte with any data + outp( Port->Clear, 0 ); + } + + return( status ); + } + + +/*--------------------------------------------------------------------- + Function: DMA_GetCurrentPos + + Returns the position of the specified DMA transfer. +---------------------------------------------------------------------*/ + +char *DMA_GetCurrentPos + ( + int channel + ) + + { + DMA_PORT *Port; + unsigned long addr; + int status; + + addr = NULL; + status = DMA_VerifyChannel( channel ); + + if ( status == DMA_Ok ) + { + Port = &DMA_PortInfo[ channel ]; + + if ( Port->Width == WORD ) + { + // Get address + addr = inp( Port->Address ) << 1; + addr |= inp( Port->Address ) << 9; + + // Get page + addr |= inp( Port->Page ) << 16; + } + else + { + // Get address + addr = inp( Port->Address ); + addr |= inp( Port->Address ) << 8; + + // Get page + addr |= inp( Port->Page ) << 16; + } + } + + return( ( char * )addr ); + } + + +/*--------------------------------------------------------------------- + Function: DMA_GetTransferCount + + Returns how many bytes are left in the DMA's transfer. +---------------------------------------------------------------------*/ + +int DMA_GetTransferCount + ( + int channel + ) + + { + DMA_PORT *Port; + int count; + int status; + + status = DMA_Ok; + + count = 0; + + if ( ( channel < 0 ) || ( DMA_MaxChannel < channel ) ) + { + status = DMA_ChannelOutOfRange; + } + else if ( DMA_PortInfo[ channel ].Valid == INVALID ) + { + status = DMA_InvalidChannel; + } + + if ( status == DMA_Ok ) + { + Port = &DMA_PortInfo[ channel ]; + + outp( Port->Clear, 0 ); + count = inp( Port->Length ); + count += inp( Port->Length ) << 8; + + if ( Port->Width == WORD ) + { + count <<= 1; + } + } + + DMA_SetErrorCode( status ); + + return( count ); + } diff --git a/audiolib/dma.h b/audiolib/dma.h new file mode 100755 index 0000000..f68d4ea --- /dev/null +++ b/audiolib/dma.h @@ -0,0 +1,83 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + file: DMA.H + + author: James R. Dose + date: February 4, 1994 + + Public header file for DMA.C + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#ifndef __DMA_H +#define __DMA_H + +enum DMA_ERRORS + { + DMA_Error = -1, + DMA_Ok = 0, + DMA_ChannelOutOfRange, + DMA_InvalidChannel + }; + +enum DMA_Modes + { + DMA_SingleShotRead, + DMA_SingleShotWrite, + DMA_AutoInitRead, + DMA_AutoInitWrite + }; + +char *DMA_ErrorString + ( + int ErrorNumber + ); + +int DMA_VerifyChannel + ( + int channel + ); + +int DMA_SetupTransfer + ( + int channel, + char *address, + int length, + int mode + ); + +int DMA_EndTransfer + ( + int channel + ); + +char *DMA_GetCurrentPos + ( + int channel + ); + +int DMA_GetTransferCount + ( + int channel + ); + +#endif diff --git a/audiolib/dpmi.c b/audiolib/dpmi.c new file mode 100755 index 0000000..ea87f51 --- /dev/null +++ b/audiolib/dpmi.c @@ -0,0 +1,250 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: DPMI.C + + author: James R. Dose + date: April 8, 1994 + + Functions for performing DPMI calls. + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#include +#include +#include "dpmi.h" + +#define TRUE ( 1 == 1 ) +#define FALSE ( !TRUE ) + +static union REGS Regs; +static struct SREGS SegRegs; + + +/*--------------------------------------------------------------------- + Function: DPMI_GetRealModeVector + + Returns the vector of a real mode interrupt. +---------------------------------------------------------------------*/ + +unsigned long DPMI_GetRealModeVector + ( + int num + ) + + { + unsigned long vector; + + Regs.x.eax = 0x0200; + Regs.h.bl = num; + int386( 0x31, &Regs, &Regs ); + + vector = Regs.w.cx & 0xffff; + vector <<= 16; + vector |= Regs.w.dx & 0xffff; + + return( vector ); + } + + +/*--------------------------------------------------------------------- + Function: DPMI_SetRealModeVector + + Sets the vector of a real mode interrupt. +---------------------------------------------------------------------*/ + +void DPMI_SetRealModeVector + ( + int num, + unsigned long vector + ) + + { + Regs.x.eax = 0x0201; + Regs.h.bl = num; + Regs.w.dx = vector & 0xffff; + Regs.w.cx = ( vector >> 16 ) & 0xffff; + + int386( 0x31, &Regs, &Regs ); + } + + +/*--------------------------------------------------------------------- + Function: DPMI_CallRealModeFunction + + Performs a call to a real mode function. +---------------------------------------------------------------------*/ + +int DPMI_CallRealModeFunction + ( + dpmi_regs *callregs + ) + + { + // Setup our registers to call DPMI + Regs.w.ax = 0x0301; + Regs.h.bl = 0; + Regs.h.bh = 0; + Regs.w.cx = 0; + + SegRegs.es = FP_SEG( callregs ); + Regs.x.edi = FP_OFF( callregs ); + + // Call Real-mode procedure with Far Return Frame + int386x( 0x31, &Regs, &Regs, &SegRegs ); + + if ( Regs.x.cflag ) + { + return( DPMI_Error ); + } + + return( DPMI_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: DPMI_LockMemory + + Locks a region of memory to keep the virtual memory manager from + paging the region out. +---------------------------------------------------------------------*/ + +int DPMI_LockMemory + ( + void *address, + unsigned length + ) + + { + unsigned linear; + + // Thanks to DOS/4GW's zero-based flat memory model, converting + // a pointer of any type to a linear address is trivial. + + linear = (unsigned) address; + + // DPMI Lock Linear Region + Regs.w.ax = 0x600; + + // Linear address in BX:CX + Regs.w.bx = (linear >> 16); + Regs.w.cx = (linear & 0xFFFF); + + // Length in SI:DI + Regs.w.si = (length >> 16); + Regs.w.di = (length & 0xFFFF); + + int386 (0x31, &Regs, &Regs); + + // Return 0 if can't lock + if ( Regs.w.cflag ) + { + return( DPMI_Error ); + } + + return ( DPMI_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: DPMI_LockMemoryRegion + + Locks a region of memory to keep the virtual memory manager from + paging the region out. +---------------------------------------------------------------------*/ + +int DPMI_LockMemoryRegion + ( + void *start, + void *end + ) + + { + int status; + + status = DPMI_LockMemory( start, ( char * )end - ( char * )start ); + + return( status ); + } + + +/*--------------------------------------------------------------------- + Function: DPMI_UnlockMemory + + Unlocks a region of memory that was previously locked. +---------------------------------------------------------------------*/ + +int DPMI_UnlockMemory + ( + void *address, + unsigned length + ) + + { + unsigned linear; + + // Thanks to DOS/4GW's zero-based flat memory model, converting + // a pointer of any type to a linear address is trivial. + + linear = (unsigned) address; + + // DPMI Unlock Linear Region + Regs.w.ax = 0x601; + + // Linear address in BX:CX + Regs.w.bx = (linear >> 16); + Regs.w.cx = (linear & 0xFFFF); + + // Length in SI:DI + Regs.w.si = (length >> 16); + Regs.w.di = (length & 0xFFFF); + + int386 (0x31, &Regs, &Regs); + + // Return 0 if can't unlock + if ( Regs.w.cflag ) + { + return( DPMI_Error ); + } + + return ( DPMI_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: DPMI_UnlockMemoryRegion + + Unlocks a region of memory that was previously locked. +---------------------------------------------------------------------*/ + +int DPMI_UnlockMemoryRegion + ( + void *start, + void *end + ) + + { + int status; + + status = DPMI_UnlockMemory( start, ( char * )end - ( char * )start ); + + return( status ); + } diff --git a/audiolib/dpmi.h b/audiolib/dpmi.h new file mode 100755 index 0000000..9b76b6f --- /dev/null +++ b/audiolib/dpmi.h @@ -0,0 +1,102 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: DPMI.H + + author: James R. Dose + date: March 31, 1994 + + Inline functions for performing DPMI calls. + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#ifndef __DPMI_H +#define __DPMI_H + +enum DPMI_Errors + { + DPMI_Warning = -2, + DPMI_Error = -1, + DPMI_Ok = 0 + }; + +typedef struct + { + unsigned long EDI; + unsigned long ESI; + unsigned long EBP; + unsigned long Reserved; + unsigned long EBX; + unsigned long EDX; + unsigned long ECX; + unsigned long EAX; + unsigned short Flags; + unsigned short ES; + unsigned short DS; + unsigned short FS; + unsigned short GS; + unsigned short IP; + unsigned short CS; + unsigned short SP; + unsigned short SS; + } dpmi_regs; + +unsigned long DPMI_GetRealModeVector( int num ); +void DPMI_SetRealModeVector( int num, unsigned long vector ); +int DPMI_CallRealModeFunction( dpmi_regs *callregs ); +int DPMI_GetDOSMemory( void **ptr, int *descriptor, unsigned length ); +int DPMI_FreeDOSMemory( int descriptor ); +int DPMI_LockMemory( void *address, unsigned length ); +int DPMI_LockMemoryRegion( void *start, void *end ); +int DPMI_UnlockMemory( void *address, unsigned length ); +int DPMI_UnlockMemoryRegion( void *start, void *end ); + +#define DPMI_Lock( variable ) \ + ( DPMI_LockMemory( (void *) &( variable ), sizeof( variable ) ) ) + +#define DPMI_Unlock( variable ) \ + ( DPMI_UnlockMemory( (void *) &( variable ), sizeof( variable ) ) ) + +#ifdef PLAT_DOS +#pragma aux DPMI_GetDOSMemory = \ + "mov eax, 0100h", \ + "add ebx, 15", \ + "shr ebx, 4", \ + "int 31h", \ + "jc DPMI_Exit", \ + "movzx eax, ax", \ + "shl eax, 4", \ + "mov [ esi ], eax", \ + "mov [ edi ], edx", \ + "sub eax, eax", \ + "DPMI_Exit:", \ + parm [ esi ] [ edi ] [ ebx ] modify exact [ eax ebx edx ]; + +#pragma aux DPMI_FreeDOSMemory = \ + "mov eax, 0101h", \ + "int 31h", \ + "jc DPMI_Exit", \ + "sub eax, eax", \ + "DPMI_Exit:", \ + parm [ edx ] modify exact [ eax ]; +#endif + +#endif diff --git a/audiolib/dsl.c b/audiolib/dsl.c new file mode 100755 index 0000000..b165ea8 --- /dev/null +++ b/audiolib/dsl.c @@ -0,0 +1,239 @@ +#include +#include + +#include "dsl.h" +#include "util.h" + +#include "SDL.h" +#include "SDL_mixer.h" + +extern volatile int MV_MixPage; + +static int DSL_ErrorCode = DSL_Ok; + +static int mixer_initialized; + +static void ( *_CallBackFunc )( void ); +static volatile char *_BufferStart; +static int _BufferSize; +static int _NumDivisions; +static int _SampleRate; +static int _remainder; + +static Mix_Chunk *blank; +static unsigned char *blank_buf; + +/* +possible todo ideas: cache sdl/sdl mixer error messages. +*/ + +char *DSL_ErrorString( int ErrorNumber ) +{ + char *ErrorString; + + switch (ErrorNumber) { + case DSL_Warning: + case DSL_Error: + ErrorString = DSL_ErrorString(DSL_ErrorCode); + break; + + case DSL_Ok: + ErrorString = "SDL Driver ok."; + break; + + case DSL_SDLInitFailure: + ErrorString = "SDL Audio initialization failed."; + break; + + case DSL_MixerActive: + ErrorString = "SDL Mixer already initialized."; + break; + + case DSL_MixerInitFailure: + ErrorString = "SDL Mixer initialization failed."; + break; + + default: + ErrorString = "Unknown SDL Driver error."; + break; + } + + return ErrorString; +} + +static void DSL_SetErrorCode(int ErrorCode) +{ + DSL_ErrorCode = ErrorCode; +} + +int DSL_Init( void ) +{ + DSL_SetErrorCode(DSL_Ok); + + if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) { + DSL_SetErrorCode(DSL_SDLInitFailure); + + return DSL_Error; + } + + return DSL_Ok; +} + +void DSL_Shutdown( void ) +{ + DSL_StopPlayback(); +} + +static void mixer_callback(int chan, void *stream, int len, void *udata) +{ + Uint8 *stptr; + Uint8 *fxptr; + int copysize; + + /* len should equal _BufferSize, else this is screwed up */ + + stptr = (Uint8 *)stream; + + if (_remainder > 0) { + copysize = min(len, _remainder); + + fxptr = (Uint8 *)(&_BufferStart[MV_MixPage * + _BufferSize]); + + memcpy(stptr, fxptr+(_BufferSize-_remainder), copysize); + + len -= copysize; + _remainder -= copysize; + + stptr += copysize; + } + + while (len > 0) { + /* new buffer */ + + _CallBackFunc(); + + fxptr = (Uint8 *)(&_BufferStart[MV_MixPage * + _BufferSize]); + + copysize = min(len, _BufferSize); + + memcpy(stptr, fxptr, copysize); + + len -= copysize; + + stptr += copysize; + } + + _remainder = len; +} + +int DSL_BeginBufferedPlayback( char *BufferStart, + int BufferSize, int NumDivisions, unsigned SampleRate, + int MixMode, void ( *CallBackFunc )( void ) ) +{ + Uint16 format; + Uint8 *tmp; + int channels; + int chunksize; + + if (mixer_initialized) { + DSL_SetErrorCode(DSL_MixerActive); + + return DSL_Error; + } + + _CallBackFunc = CallBackFunc; + _BufferStart = BufferStart; + _BufferSize = (BufferSize / NumDivisions); + _NumDivisions = NumDivisions; + _SampleRate = SampleRate; + + _remainder = 0; + + format = (MixMode & SIXTEEN_BIT) ? AUDIO_S16SYS : AUDIO_U8; + channels = (MixMode & STEREO) ? 2 : 1; + +/* + 23ms is typically ideal (11025,22050,44100) + 46ms isn't bad +*/ + + chunksize = 512; + + if (SampleRate >= 16000) chunksize *= 2; + if (SampleRate >= 32000) chunksize *= 2; + +/* +// SDL mixer does this already + if (MixMode & SIXTEEN_BIT) chunksize *= 2; + if (MixMode & STEREO) chunksize *= 2; +*/ + + if (Mix_OpenAudio(SampleRate, format, channels, chunksize) < 0) { + DSL_SetErrorCode(DSL_MixerInitFailure); + + return DSL_Error; + } + +/* + Mix_SetPostMix(mixer_callback, NULL); +*/ + /* have to use a channel because postmix will overwrite the music... */ + Mix_RegisterEffect(0, mixer_callback, NULL, NULL); + + /* create a dummy sample just to allocate that channel */ + blank_buf = (Uint8 *)malloc(4096); + memset(blank_buf, 0, 4096); + + blank = Mix_QuickLoad_RAW(blank_buf, 4096); + + Mix_PlayChannel(0, blank, -1); + + mixer_initialized = 1; + + return DSL_Ok; +} + +void DSL_StopPlayback( void ) +{ + if (mixer_initialized) { + Mix_HaltChannel(0); + } + + if (blank != NULL) { + Mix_FreeChunk(blank); + } + + blank = NULL; + + if (blank_buf != NULL) { + free(blank_buf); + } + + blank_buf = NULL; + + if (mixer_initialized) { + SDL_UnlockAudio(); /* just in case */ + Mix_CloseAudio(); + } + + mixer_initialized = 0; +} + +unsigned DSL_GetPlaybackRate( void ) +{ + return _SampleRate; +} + +unsigned long DisableInterrupts( void ) +{ + SDL_LockAudio(); + return 0; +} + +void RestoreInterrupts( unsigned long flags ) +{ + SDL_UnlockAudio(); +} + diff --git a/audiolib/dsl.h b/audiolib/dsl.h new file mode 100755 index 0000000..1067052 --- /dev/null +++ b/audiolib/dsl.h @@ -0,0 +1,28 @@ +#ifndef AUDIOLIB__DSL_H +#define AUDIOLIB__DSL_H + +#define MONO_8BIT 0 +#define STEREO 1 +#define SIXTEEN_BIT 2 +#define STEREO_16BIT ( STEREO | SIXTEEN_BIT ) + +enum DSL_ERRORS + { + DSL_Warning = -2, + DSL_Error = -1, + DSL_Ok = 0, + DSL_SDLInitFailure, + DSL_MixerActive, + DSL_MixerInitFailure + }; + +char *DSL_ErrorString( int ErrorNumber ); +int DSL_Init( void ); +void DSL_StopPlayback( void ); +unsigned DSL_GetPlaybackRate( void ); +int DSL_BeginBufferedPlayback( char *BufferStart, + int BufferSize, int NumDivisions, unsigned SampleRate, + int MixMode, void ( *CallBackFunc )( void ) ); +void DSL_Shutdown( void ); + +#endif diff --git a/audiolib/fx_man.c b/audiolib/fx_man.c new file mode 100755 index 0000000..aa32c03 --- /dev/null +++ b/audiolib/fx_man.c @@ -0,0 +1,1376 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: FX_MAN.C + + author: James R. Dose + date: March 17, 1994 + + Device independant sound effect routines. + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#include +#include +#include "sndcards.h" +#include "multivoc.h" + +#ifdef PLAT_DOS +#include "blaster.h" +#include "pas16.h" +#include "sndscape.h" +#include "guswave.h" +#include "sndsrc.h" +#else +#include "dsl.h" +#endif + +#include "ll_man.h" +#include "user.h" +#include "fx_man.h" + +#define TRUE ( 1 == 1 ) +#define FALSE ( !TRUE ) + +static unsigned FX_MixRate; + +int FX_SoundDevice = -1; +int FX_ErrorCode = FX_Ok; +int FX_Installed = FALSE; + +#define FX_SetErrorCode( status ) \ + FX_ErrorCode = ( status ); + +/*--------------------------------------------------------------------- + Function: FX_ErrorString + + Returns a pointer to the error message associated with an error + number. A -1 returns a pointer the current error. +---------------------------------------------------------------------*/ + +char *FX_ErrorString + ( + int ErrorNumber + ) + + { + char *ErrorString; + + switch( ErrorNumber ) + { + case FX_Warning : + case FX_Error : + ErrorString = FX_ErrorString( FX_ErrorCode ); + break; + + case FX_Ok : + ErrorString = "Fx ok."; + break; + + case FX_ASSVersion : + ErrorString = "Apogee Sound System Version " ASS_VERSION_STRING " " + "Programmed by Jim Dose\n" + "(c) Copyright 1995 James R. Dose. All Rights Reserved.\n"; + break; + +#ifdef PLAT_DOS + case FX_BlasterError : + ErrorString = BLASTER_ErrorString( BLASTER_Error ); + break; +#endif + + case FX_SoundCardError : +#ifdef PLAT_DOS + switch( FX_SoundDevice ) + { + case SoundBlaster : + case Awe32 : + ErrorString = BLASTER_ErrorString( BLASTER_Error ); + break; + + case ProAudioSpectrum : + case SoundMan16 : + ErrorString = PAS_ErrorString( PAS_Error ); + break; + + case SoundScape : + ErrorString = SOUNDSCAPE_ErrorString( SOUNDSCAPE_Error ); + break; + + case UltraSound : + ErrorString = GUSWAVE_ErrorString( GUSWAVE_Error ); + break; + + case SoundSource : + case TandySoundSource : + ErrorString = SS_ErrorString( SS_Error ); + break; + } +#else + ErrorString = DSL_ErrorString( DSL_Error ); +#endif + break; + + case FX_InvalidCard : + ErrorString = "Invalid Sound Fx device."; + break; + + case FX_MultiVocError : + ErrorString = MV_ErrorString( MV_Error ); + break; + + case FX_DPMI_Error : + ErrorString = "DPMI Error in FX_MAN."; + break; + + default : + ErrorString = "Unknown Fx error code."; + break; + } + + return( ErrorString ); + } + + +/*--------------------------------------------------------------------- + Function: FX_SetupCard + + Sets the configuration of a sound device. +---------------------------------------------------------------------*/ + +int FX_SetupCard + ( + int SoundCard, + fx_device *device + ) + + { + int status; + int DeviceStatus; + + if ( USER_CheckParameter( "ASSVER" ) ) + { + FX_SetErrorCode( FX_ASSVersion ); + return( FX_Error ); + } + + FX_SoundDevice = SoundCard; + + status = FX_Ok; + FX_SetErrorCode( FX_Ok ); + +#ifdef PLAT_DOS + switch( SoundCard ) + { + case SoundBlaster : + case Awe32 : + DeviceStatus = BLASTER_Init(); + if ( DeviceStatus != BLASTER_Ok ) + { + FX_SetErrorCode( FX_SoundCardError ); + status = FX_Error; + break; + } + + device->MaxVoices = 32; + BLASTER_GetCardInfo( &device->MaxSampleBits, &device->MaxChannels ); + break; + + case ProAudioSpectrum : + case SoundMan16 : + DeviceStatus = PAS_Init(); + if ( DeviceStatus != PAS_Ok ) + { + FX_SetErrorCode( FX_SoundCardError ); + status = FX_Error; + break; + } + + device->MaxVoices = 32; + PAS_GetCardInfo( &device->MaxSampleBits, &device->MaxChannels ); + break; + + case GenMidi : + case SoundCanvas : + case WaveBlaster : + device->MaxVoices = 0; + device->MaxSampleBits = 0; + device->MaxChannels = 0; + break; + + case SoundScape : + device->MaxVoices = 32; + DeviceStatus = SOUNDSCAPE_GetCardInfo( &device->MaxSampleBits, + &device->MaxChannels ); + if ( DeviceStatus != SOUNDSCAPE_Ok ) + { + FX_SetErrorCode( FX_SoundCardError ); + status = FX_Error; + } + break; + + case UltraSound : + if ( GUSWAVE_Init( 8 ) != GUSWAVE_Ok ) + { + FX_SetErrorCode( FX_SoundCardError ); + status = FX_Error; + break; + } + + device->MaxVoices = 8; + device->MaxSampleBits = 0; + device->MaxChannels = 0; + break; + + case SoundSource : + case TandySoundSource : + DeviceStatus = SS_Init( SoundCard ); + if ( DeviceStatus != SS_Ok ) + { + FX_SetErrorCode( FX_SoundCardError ); + status = FX_Error; + break; + } + SS_Shutdown(); + device->MaxVoices = 32; + device->MaxSampleBits = 8; + device->MaxChannels = 1; + break; + default : + FX_SetErrorCode( FX_InvalidCard ); + status = FX_Error; + } +#else + DeviceStatus = DSL_Init(); + if ( DeviceStatus != DSL_Ok ) + { + FX_SetErrorCode( FX_SoundCardError ); + status = FX_Error; + } + else + { + device->MaxVoices = 32; + device->MaxSampleBits = 0; + device->MaxChannels = 0; + } +#endif + + return( status ); + } + + +/*--------------------------------------------------------------------- + Function: FX_GetBlasterSettings + + Returns the current BLASTER environment variable settings. +---------------------------------------------------------------------*/ + +int FX_GetBlasterSettings + ( + fx_blaster_config *blaster + ) + + { +#ifdef PLAT_DOS + int status; + BLASTER_CONFIG Blaster; + + FX_SetErrorCode( FX_Ok ); + + status = BLASTER_GetEnv( &Blaster ); + if ( status != BLASTER_Ok ) + { + FX_SetErrorCode( FX_BlasterError ); + return( FX_Error ); + } + + blaster->Type = Blaster.Type; + blaster->Address = Blaster.Address; + blaster->Interrupt = Blaster.Interrupt; + blaster->Dma8 = Blaster.Dma8; + blaster->Dma16 = Blaster.Dma16; + blaster->Midi = Blaster.Midi; + blaster->Emu = Blaster.Emu; +#endif + + return( FX_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: FX_SetupSoundBlaster + + Handles manual setup of the Sound Blaster information. +---------------------------------------------------------------------*/ + +int FX_SetupSoundBlaster + ( + fx_blaster_config blaster, + int *MaxVoices, + int *MaxSampleBits, + int *MaxChannels + ) + + { +#ifdef PLAT_DOS + int DeviceStatus; + BLASTER_CONFIG Blaster; + + FX_SetErrorCode( FX_Ok ); + + FX_SoundDevice = SoundBlaster; + + Blaster.Type = blaster.Type; + Blaster.Address = blaster.Address; + Blaster.Interrupt = blaster.Interrupt; + Blaster.Dma8 = blaster.Dma8; + Blaster.Dma16 = blaster.Dma16; + Blaster.Midi = blaster.Midi; + Blaster.Emu = blaster.Emu; + + BLASTER_SetCardSettings( Blaster ); + + DeviceStatus = BLASTER_Init(); + if ( DeviceStatus != BLASTER_Ok ) + { + FX_SetErrorCode( FX_SoundCardError ); + return( FX_Error ); + } + + *MaxVoices = 8; + BLASTER_GetCardInfo( MaxSampleBits, MaxChannels ); +#endif + + return( FX_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: FX_Init + + Selects which sound device to use. +---------------------------------------------------------------------*/ + +int FX_Init + ( + int SoundCard, + int numvoices, + int numchannels, + int samplebits, + unsigned mixrate + ) + + { + int status; + int devicestatus; + + if ( FX_Installed ) + { + FX_Shutdown(); + } + + if ( USER_CheckParameter( "ASSVER" ) ) + { + FX_SetErrorCode( FX_ASSVersion ); + return( FX_Error ); + } + + status = LL_LockMemory(); + if ( status != LL_Ok ) + { + FX_SetErrorCode( FX_DPMI_Error ); + return( FX_Error ); + } + + FX_MixRate = mixrate; + + status = FX_Ok; + FX_SoundDevice = SoundCard; + switch( SoundCard ) + { + case SoundBlaster : + case Awe32 : + case ProAudioSpectrum : + case SoundMan16 : + case SoundScape : + case SoundSource : + case TandySoundSource : + case UltraSound : + devicestatus = MV_Init( SoundCard, FX_MixRate, numvoices, + numchannels, samplebits ); + if ( devicestatus != MV_Ok ) + { + FX_SetErrorCode( FX_MultiVocError ); + status = FX_Error; + } + break; + + default : + FX_SetErrorCode( FX_InvalidCard ); + status = FX_Error; + } + + if ( status != FX_Ok ) + { + LL_UnlockMemory(); + } + else + { + FX_Installed = TRUE; + } + + return( status ); + } + + +/*--------------------------------------------------------------------- + Function: FX_Shutdown + + Terminates use of sound device. +---------------------------------------------------------------------*/ + +int FX_Shutdown + ( + void + ) + + { + int status; + + if ( !FX_Installed ) + { + return( FX_Ok ); + } + + status = FX_Ok; + switch( FX_SoundDevice ) + { + case SoundBlaster : + case Awe32 : + case ProAudioSpectrum : + case SoundMan16 : + case SoundScape : + case SoundSource : + case TandySoundSource : + case UltraSound : + status = MV_Shutdown(); + if ( status != MV_Ok ) + { + FX_SetErrorCode( FX_MultiVocError ); + status = FX_Error; + } + break; + + default : + FX_SetErrorCode( FX_InvalidCard ); + status = FX_Error; + } + + FX_Installed = FALSE; + LL_UnlockMemory(); + + return( status ); + } + + +/*--------------------------------------------------------------------- + Function: FX_SetCallback + + Sets the function to call when a voice is done. +---------------------------------------------------------------------*/ + +int FX_SetCallBack + ( + void ( *function )( unsigned long ) + ) + + { + int status; + + status = FX_Ok; + + switch( FX_SoundDevice ) + { + case SoundBlaster : + case Awe32 : + case ProAudioSpectrum : + case SoundMan16 : + case SoundScape : + case SoundSource : + case TandySoundSource : + case UltraSound : + MV_SetCallBack( function ); + break; + + default : + FX_SetErrorCode( FX_InvalidCard ); + status = FX_Error; + } + + return( status ); + } + + +/*--------------------------------------------------------------------- + Function: FX_SetVolume + + Sets the volume of the current sound device. +---------------------------------------------------------------------*/ + +void FX_SetVolume + ( + int volume + ) + + { + int status; + +#ifdef PLAT_DOS + switch( FX_SoundDevice ) + { + case SoundBlaster : + case Awe32 : + if ( BLASTER_CardHasMixer() ) + { + BLASTER_SetVoiceVolume( volume ); + } + else + { + MV_SetVolume( volume ); + } + break; + + case ProAudioSpectrum : + case SoundMan16 : + status = PAS_SetPCMVolume( volume ); + if ( status != PAS_Ok ) + { + MV_SetVolume( volume ); + } + break; + + case GenMidi : + case SoundCanvas : + case WaveBlaster : + break; + + case SoundScape : + MV_SetVolume( volume ); + break; + + case UltraSound : + GUSWAVE_SetVolume( volume ); + break; + + case SoundSource : + case TandySoundSource : + MV_SetVolume( volume ); + break; + } +#else + MV_SetVolume( volume ); +#endif + } + + +/*--------------------------------------------------------------------- + Function: FX_GetVolume + + Returns the volume of the current sound device. +---------------------------------------------------------------------*/ + +int FX_GetVolume + ( + void + ) + + { + int volume; + +#ifdef PLAT_DOS + switch( FX_SoundDevice ) + { + case SoundBlaster : + case Awe32 : + if ( BLASTER_CardHasMixer() ) + { + volume = BLASTER_GetVoiceVolume(); + } + else + { + volume = MV_GetVolume(); + } + break; + + case ProAudioSpectrum : + case SoundMan16 : + volume = PAS_GetPCMVolume(); + if ( volume == PAS_Error ) + { + volume = MV_GetVolume(); + } + break; + + case GenMidi : + case SoundCanvas : + case WaveBlaster : + volume = 255; + break; + + case SoundScape : + volume = MV_GetVolume(); + break; + + case UltraSound : + volume = GUSWAVE_GetVolume(); + break; + + case SoundSource : + case TandySoundSource : + volume = MV_GetVolume(); + break; + + default : + volume = 0; + } +#else + volume = MV_GetVolume(); +#endif + + return( volume ); + } + + +/*--------------------------------------------------------------------- + Function: FX_SetReverseStereo + + Set the orientation of the left and right channels. +---------------------------------------------------------------------*/ + +void FX_SetReverseStereo + ( + int setting + ) + + { + MV_SetReverseStereo( setting ); + } + + +/*--------------------------------------------------------------------- + Function: FX_GetReverseStereo + + Returns the orientation of the left and right channels. +---------------------------------------------------------------------*/ + +int FX_GetReverseStereo + ( + void + ) + + { + return MV_GetReverseStereo(); + } + + +/*--------------------------------------------------------------------- + Function: FX_SetReverb + + Sets the reverb level. +---------------------------------------------------------------------*/ + +void FX_SetReverb + ( + int reverb + ) + + { + MV_SetReverb( reverb ); + } + + +/*--------------------------------------------------------------------- + Function: FX_SetFastReverb + + Sets the reverb level. +---------------------------------------------------------------------*/ + +void FX_SetFastReverb + ( + int reverb + ) + + { + MV_SetFastReverb( reverb ); + } + + +/*--------------------------------------------------------------------- + Function: FX_GetMaxReverbDelay + + Returns the maximum delay time for reverb. +---------------------------------------------------------------------*/ + +int FX_GetMaxReverbDelay + ( + void + ) + + { + return MV_GetMaxReverbDelay(); + } + + +/*--------------------------------------------------------------------- + Function: FX_GetReverbDelay + + Returns the current delay time for reverb. +---------------------------------------------------------------------*/ + +int FX_GetReverbDelay + ( + void + ) + + { + return MV_GetReverbDelay(); + } + + +/*--------------------------------------------------------------------- + Function: FX_SetReverbDelay + + Sets the delay level of reverb to add to mix. +---------------------------------------------------------------------*/ + +void FX_SetReverbDelay + ( + int delay + ) + + { + MV_SetReverbDelay( delay ); + } + + +/*--------------------------------------------------------------------- + Function: FX_VoiceAvailable + + Checks if a voice can be play at the specified priority. +---------------------------------------------------------------------*/ + +int FX_VoiceAvailable + ( + int priority + ) + + { + return MV_VoiceAvailable( priority ); + } + +/*--------------------------------------------------------------------- + Function: FX_EndLooping + + Stops the voice associated with the specified handle from looping + without stoping the sound. +---------------------------------------------------------------------*/ + +int FX_EndLooping + ( + int handle + ) + + { + int status; + + status = MV_EndLooping( handle ); + if ( status == MV_Error ) + { + FX_SetErrorCode( FX_MultiVocError ); + status = FX_Warning; + } + + return( status ); + } + +/*--------------------------------------------------------------------- + Function: FX_SetPan + + Sets the stereo and mono volume level of the voice associated + with the specified handle. +---------------------------------------------------------------------*/ + +int FX_SetPan + ( + int handle, + int vol, + int left, + int right + ) + + { + int status; + + status = MV_SetPan( handle, vol, left, right ); + if ( status == MV_Error ) + { + FX_SetErrorCode( FX_MultiVocError ); + status = FX_Warning; + } + + return( status ); + } + + +/*--------------------------------------------------------------------- + Function: FX_SetPitch + + Sets the pitch of the voice associated with the specified handle. +---------------------------------------------------------------------*/ + +int FX_SetPitch + ( + int handle, + int pitchoffset + ) + + { + int status; + + status = MV_SetPitch( handle, pitchoffset ); + if ( status == MV_Error ) + { + FX_SetErrorCode( FX_MultiVocError ); + status = FX_Warning; + } + + return( status ); + } + + +/*--------------------------------------------------------------------- + Function: FX_SetFrequency + + Sets the frequency of the voice associated with the specified handle. +---------------------------------------------------------------------*/ + +int FX_SetFrequency + ( + int handle, + int frequency + ) + + { + int status; + + status = MV_SetFrequency( handle, frequency ); + if ( status == MV_Error ) + { + FX_SetErrorCode( FX_MultiVocError ); + status = FX_Warning; + } + + return( status ); + } + + +/*--------------------------------------------------------------------- + Function: FX_PlayVOC + + Begin playback of sound data with the given volume and priority. +---------------------------------------------------------------------*/ + +int FX_PlayVOC + ( + char *ptr, + int pitchoffset, + int vol, + int left, + int right, + int priority, + unsigned long callbackval + ) + + { + int handle; + + handle = MV_PlayVOC( ptr, pitchoffset, vol, left, right, + priority, callbackval ); + if ( handle < MV_Ok ) + { + FX_SetErrorCode( FX_MultiVocError ); + handle = FX_Warning; + } + + return( handle ); + } + + +/*--------------------------------------------------------------------- + Function: FX_PlayLoopedVOC + + Begin playback of sound data with the given volume and priority. +---------------------------------------------------------------------*/ + +int FX_PlayLoopedVOC + ( + char *ptr, + long loopstart, + long loopend, + int pitchoffset, + int vol, + int left, + int right, + int priority, + unsigned long callbackval + ) + + { + int handle; + + handle = MV_PlayLoopedVOC( ptr, loopstart, loopend, pitchoffset, + vol, left, right, priority, callbackval ); + if ( handle < MV_Ok ) + { + FX_SetErrorCode( FX_MultiVocError ); + handle = FX_Warning; + } + + return( handle ); + } + + +/*--------------------------------------------------------------------- + Function: FX_PlayWAV + + Begin playback of sound data with the given volume and priority. +---------------------------------------------------------------------*/ + +int FX_PlayWAV + ( + char *ptr, + int pitchoffset, + int vol, + int left, + int right, + int priority, + unsigned long callbackval + ) + + { + int handle; + + handle = MV_PlayWAV( ptr, pitchoffset, vol, left, right, + priority, callbackval ); + if ( handle < MV_Ok ) + { + FX_SetErrorCode( FX_MultiVocError ); + handle = FX_Warning; + } + + return( handle ); + } + + +/*--------------------------------------------------------------------- + Function: FX_PlayWAV + + Begin playback of sound data with the given volume and priority. +---------------------------------------------------------------------*/ + +int FX_PlayLoopedWAV + ( + char *ptr, + long loopstart, + long loopend, + int pitchoffset, + int vol, + int left, + int right, + int priority, + unsigned long callbackval + ) + + { + int handle; + + handle = MV_PlayLoopedWAV( ptr, loopstart, loopend, + pitchoffset, vol, left, right, priority, callbackval ); + if ( handle < MV_Ok ) + { + FX_SetErrorCode( FX_MultiVocError ); + handle = FX_Warning; + } + + return( handle ); + } + + +/*--------------------------------------------------------------------- + Function: FX_PlayVOC3D + + Begin playback of sound data at specified angle and distance + from listener. +---------------------------------------------------------------------*/ + +int FX_PlayVOC3D + ( + char *ptr, + int pitchoffset, + int angle, + int distance, + int priority, + unsigned long callbackval + ) + + { + int handle; + + handle = MV_PlayVOC3D( ptr, pitchoffset, angle, distance, + priority, callbackval ); + if ( handle < MV_Ok ) + { + FX_SetErrorCode( FX_MultiVocError ); + handle = FX_Warning; + } + + return( handle ); + } + + +/*--------------------------------------------------------------------- + Function: FX_PlayWAV3D + + Begin playback of sound data at specified angle and distance + from listener. +---------------------------------------------------------------------*/ + +int FX_PlayWAV3D + ( + char *ptr, + int pitchoffset, + int angle, + int distance, + int priority, + unsigned long callbackval + ) + + { + int handle; + + handle = MV_PlayWAV3D( ptr, pitchoffset, angle, distance, + priority, callbackval ); + if ( handle < MV_Ok ) + { + FX_SetErrorCode( FX_MultiVocError ); + handle = FX_Warning; + } + + return( handle ); + } + + +/*--------------------------------------------------------------------- + Function: FX_PlayRaw + + Begin playback of raw sound data with the given volume and priority. +---------------------------------------------------------------------*/ + +int FX_PlayRaw + ( + char *ptr, + unsigned long length, + unsigned rate, + int pitchoffset, + int vol, + int left, + int right, + int priority, + unsigned long callbackval + ) + + { + int handle; + + handle = MV_PlayRaw( ptr, length, rate, pitchoffset, + vol, left, right, priority, callbackval ); + if ( handle < MV_Ok ) + { + FX_SetErrorCode( FX_MultiVocError ); + handle = FX_Warning; + } + + return( handle ); + } + + +/*--------------------------------------------------------------------- + Function: FX_PlayLoopedRaw + + Begin playback of raw sound data with the given volume and priority. +---------------------------------------------------------------------*/ + +int FX_PlayLoopedRaw + ( + char *ptr, + unsigned long length, + char *loopstart, + char *loopend, + unsigned rate, + int pitchoffset, + int vol, + int left, + int right, + int priority, + unsigned long callbackval + ) + + { + int handle; + + handle = MV_PlayLoopedRaw( ptr, length, loopstart, loopend, + rate, pitchoffset, vol, left, right, priority, callbackval ); + if ( handle < MV_Ok ) + { + FX_SetErrorCode( FX_MultiVocError ); + handle = FX_Warning; + } + + return( handle ); + } + + +/*--------------------------------------------------------------------- + Function: FX_Pan3D + + Set the angle and distance from the listener of the voice associated + with the specified handle. +---------------------------------------------------------------------*/ + +int FX_Pan3D + ( + int handle, + int angle, + int distance + ) + + { + int status; + + status = MV_Pan3D( handle, angle, distance ); + if ( status != MV_Ok ) + { + FX_SetErrorCode( FX_MultiVocError ); + status = FX_Warning; + } + + return( status ); + } + + +/*--------------------------------------------------------------------- + Function: FX_SoundActive + + Tests if the specified sound is currently playing. +---------------------------------------------------------------------*/ + +int FX_SoundActive + ( + int handle + ) + + { + return( MV_VoicePlaying( handle ) ); + } + + +/*--------------------------------------------------------------------- + Function: FX_SoundsPlaying + + Reports the number of voices playing. +---------------------------------------------------------------------*/ + +int FX_SoundsPlaying + ( + void + ) + + { + return( MV_VoicesPlaying() ); + } + + +/*--------------------------------------------------------------------- + Function: FX_StopSound + + Halts playback of a specific voice +---------------------------------------------------------------------*/ + +int FX_StopSound + ( + int handle + ) + + { + int status; + + status = MV_Kill( handle ); + if ( status != MV_Ok ) + { + FX_SetErrorCode( FX_MultiVocError ); + return( FX_Warning ); + } + + return( FX_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: FX_StopAllSounds + + Halts playback of all sounds. +---------------------------------------------------------------------*/ + +int FX_StopAllSounds + ( + void + ) + + { + int status; + + status = MV_KillAllVoices(); + if ( status != MV_Ok ) + { + FX_SetErrorCode( FX_MultiVocError ); + return( FX_Warning ); + } + + return( FX_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: FX_StartDemandFeedPlayback + + Plays a digitized sound from a user controlled buffering system. +---------------------------------------------------------------------*/ + +int FX_StartDemandFeedPlayback + ( + void ( *function )( char **ptr, unsigned long *length ), + int rate, + int pitchoffset, + int vol, + int left, + int right, + int priority, + unsigned long callbackval + ) + + { + int handle; + + handle = MV_StartDemandFeedPlayback( function, rate, + pitchoffset, vol, left, right, priority, callbackval ); + if ( handle < MV_Ok ) + { + FX_SetErrorCode( FX_MultiVocError ); + handle = FX_Warning; + } + + return( handle ); + } + + +/*--------------------------------------------------------------------- + Function: FX_StartRecording + + Starts the sound recording engine. +---------------------------------------------------------------------*/ + +int FX_StartRecording + ( + int MixRate, + void ( *function )( char *ptr, int length ) + ) + + { + int status; + +#ifdef PLAT_DOS + switch( FX_SoundDevice ) + { + case SoundBlaster : + case Awe32 : + case ProAudioSpectrum : + case SoundMan16 : + status = MV_StartRecording( MixRate, function ); + if ( status != MV_Ok ) + { + FX_SetErrorCode( FX_MultiVocError ); + status = FX_Warning; + } + else + { + status = FX_Ok; + } + break; + + default : + FX_SetErrorCode( FX_InvalidCard ); + status = FX_Warning; + break; + } +#else + FX_SetErrorCode( FX_InvalidCard ); + status = FX_Warning; +#endif + + return( status ); + } + + +/*--------------------------------------------------------------------- + Function: FX_StopRecord + + Stops the sound record engine. +---------------------------------------------------------------------*/ + +void FX_StopRecord + ( + void + ) + + { +#ifdef PLAT_DOS + // Stop sound playback + switch( FX_SoundDevice ) + { + case SoundBlaster : + case Awe32 : + case ProAudioSpectrum : + case SoundMan16 : + MV_StopRecord(); + break; + } +#endif + } diff --git a/audiolib/fx_man.h b/audiolib/fx_man.h new file mode 100755 index 0000000..cdbb5a1 --- /dev/null +++ b/audiolib/fx_man.h @@ -0,0 +1,135 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: FX_MAN.H + + author: James R. Dose + date: March 17, 1994 + + Public header for FX_MAN.C + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#ifndef __FX_MAN_H +#define __FX_MAN_H + +#include "sndcards.h" + +typedef struct + { + int MaxVoices; + int MaxSampleBits; + int MaxChannels; + } fx_device; + +#define MonoFx 1 +#define StereoFx 2 + +typedef struct + { + unsigned long Address; + unsigned long Type; + unsigned long Interrupt; + unsigned long Dma8; + unsigned long Dma16; + unsigned long Midi; + unsigned long Emu; + } fx_blaster_config; + +enum FX_ERRORS + { + FX_Warning = -2, + FX_Error = -1, + FX_Ok = 0, + FX_ASSVersion, + FX_BlasterError, + FX_SoundCardError, + FX_InvalidCard, + FX_MultiVocError, + FX_DPMI_Error + }; + +enum fx_BLASTER_Types + { + fx_SB = 1, + fx_SBPro = 2, + fx_SB20 = 3, + fx_SBPro2 = 4, + fx_SB16 = 6 + }; + + +char *FX_ErrorString( int ErrorNumber ); +int FX_SetupCard( int SoundCard, fx_device *device ); +int FX_GetBlasterSettings( fx_blaster_config *blaster ); +int FX_SetupSoundBlaster( fx_blaster_config blaster, int *MaxVoices, int *MaxSampleBits, int *MaxChannels ); +int FX_Init( int SoundCard, int numvoices, int numchannels, int samplebits, unsigned mixrate ); +int FX_Shutdown( void ); +int FX_SetCallBack( void ( *function )( unsigned long ) ); +void FX_SetVolume( int volume ); +int FX_GetVolume( void ); + +void FX_SetReverseStereo( int setting ); +int FX_GetReverseStereo( void ); +void FX_SetReverb( int reverb ); +void FX_SetFastReverb( int reverb ); +int FX_GetMaxReverbDelay( void ); +int FX_GetReverbDelay( void ); +void FX_SetReverbDelay( int delay ); + +int FX_VoiceAvailable( int priority ); +int FX_EndLooping( int handle ); +int FX_SetPan( int handle, int vol, int left, int right ); +int FX_SetPitch( int handle, int pitchoffset ); +int FX_SetFrequency( int handle, int frequency ); + +int FX_PlayVOC( char *ptr, int pitchoffset, int vol, int left, int right, + int priority, unsigned long callbackval ); +int FX_PlayLoopedVOC( char *ptr, long loopstart, long loopend, + int pitchoffset, int vol, int left, int right, int priority, + unsigned long callbackval ); +int FX_PlayWAV( char *ptr, int pitchoffset, int vol, int left, int right, + int priority, unsigned long callbackval ); +int FX_PlayLoopedWAV( char *ptr, long loopstart, long loopend, + int pitchoffset, int vol, int left, int right, int priority, + unsigned long callbackval ); +int FX_PlayVOC3D( char *ptr, int pitchoffset, int angle, int distance, + int priority, unsigned long callbackval ); +int FX_PlayWAV3D( char *ptr, int pitchoffset, int angle, int distance, + int priority, unsigned long callbackval ); +int FX_PlayRaw( char *ptr, unsigned long length, unsigned rate, + int pitchoffset, int vol, int left, int right, int priority, + unsigned long callbackval ); +int FX_PlayLoopedRaw( char *ptr, unsigned long length, char *loopstart, + char *loopend, unsigned rate, int pitchoffset, int vol, int left, + int right, int priority, unsigned long callbackval ); +int FX_Pan3D( int handle, int angle, int distance ); +int FX_SoundActive( int handle ); +int FX_SoundsPlaying( void ); +int FX_StopSound( int handle ); +int FX_StopAllSounds( void ); +int FX_StartDemandFeedPlayback( void ( *function )( char **ptr, unsigned long *length ), + int rate, int pitchoffset, int vol, int left, int right, + int priority, unsigned long callbackval ); +int FX_StartRecording( int MixRate, void ( *function )( char *ptr, int length ) ); +void FX_StopRecord( void ); + +#endif diff --git a/audiolib/gmtimbre.c b/audiolib/gmtimbre.c new file mode 100755 index 0000000..fff88e0 --- /dev/null +++ b/audiolib/gmtimbre.c @@ -0,0 +1,290 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +typedef struct + { + unsigned char SAVEK[ 2 ]; + unsigned char Level[ 2 ]; + unsigned char Env1[ 2 ]; + unsigned char Env2[ 2 ]; + unsigned char Wave[ 2 ]; + unsigned char Feedback; + signed char Transpose; + signed char Velocity; + } TIMBRE; + +TIMBRE ADLIB_TimbreBank[ 256 ] = + { + { { 33, 33 }, { 143, 6 }, { 242, 242 }, { 69, 118 }, { 0, 0 }, 8, 0 }, + { { 49, 33 }, { 75, 0 }, { 242, 242 }, { 84, 86 }, { 0, 0 }, 8, 0 }, + { { 49, 33 }, { 73, 0 }, { 242, 242 }, { 85, 118 }, { 0, 0 }, 8, 0 }, + { { 177, 97 }, { 14, 0 }, { 242, 243 }, { 59, 11 }, { 0, 0 }, 6, 0 }, + { { 1, 33 }, { 87, 0 }, { 241, 241 }, { 56, 40 }, { 0, 0 }, 0, 0 }, + { { 1, 33 }, { 147, 0 }, { 241, 241 }, { 56, 40 }, { 0, 0 }, 0, 0 }, + { { 33, 54 }, { 128, 14 }, { 162, 241 }, { 1, 213 }, { 0, 0 }, 8, 0 }, + { { 1, 1 }, { 146, 0 }, { 194, 194 }, { 168, 88 }, { 0, 0 }, 10, 0 }, + { { 12, 129 }, { 92, 0 }, { 246, 243 }, { 84, 181 }, { 0, 0 }, 0, 0 }, + { { 7, 17 }, { 151, 128 }, { 246, 245 }, { 50, 17 }, { 0, 0 }, 2, 0 }, + { { 23, 1 }, { 33, 0 }, { 86, 246 }, { 4, 4 }, { 0, 0 }, 2, 0 }, + { { 24, 129 }, { 98, 0 }, { 243, 242 }, { 230, 246 }, { 0, 0 }, 0, 0 }, + { { 24, 33 }, { 35, 0 }, { 247, 229 }, { 85, 216 }, { 0, 0 }, 0, 0 }, + { { 21, 1 }, { 145, 0 }, { 246, 246 }, { 166, 230 }, { 0, 0 }, 4, 0 }, + { { 69, 129 }, { 89, 128 }, { 211, 163 }, { 130, 227 }, { 0, 0 }, 12, 0 }, + { { 3, 129 }, { 73, 128 }, { 116, 179 }, { 85, 5 }, { 1, 0 }, 4, 0 }, + { { 113, 49 }, { 146, 0 }, { 246, 241 }, { 20, 7 }, { 0, 0 }, 2, 0 }, + { { 114, 48 }, { 20, 0 }, { 199, 199 }, { 88, 8 }, { 0, 0 }, 2, 0 }, + { { 112, 177 }, { 68, 0 }, { 170, 138 }, { 24, 8 }, { 0, 0 }, 4, 0 }, + { { 35, 177 }, { 147, 0 }, { 151, 85 }, { 35, 20 }, { 1, 0 }, 4, 0 }, + { { 97, 177 }, { 19, 128 }, { 151, 85 }, { 4, 4 }, { 1, 0 }, 0, 0 }, + { { 36, 177 }, { 72, 0 }, { 152, 70 }, { 42, 26 }, { 1, 0 }, 12, 0 }, + { { 97, 33 }, { 19, 0 }, { 145, 97 }, { 6, 7 }, { 1, 0 }, 10, 0 }, + { { 33, 161 }, { 19, 137 }, { 113, 97 }, { 6, 7 }, { 0, 0 }, 6, 0 }, + { { 2, 65 }, { 156, 128 }, { 243, 243 }, { 148, 200 }, { 1, 0 }, 12, 0 }, + { { 3, 17 }, { 84, 0 }, { 243, 241 }, { 154, 231 }, { 1, 0 }, 12, 0 }, + { { 35, 33 }, { 95, 0 }, { 241, 242 }, { 58, 248 }, { 0, 0 }, 0, 0 }, + { { 3, 33 }, { 135, 128 }, { 246, 243 }, { 34, 243 }, { 1, 0 }, 6, 0 }, + { { 3, 33 }, { 71, 0 }, { 249, 246 }, { 84, 58 }, { 0, 0 }, 0, 0 }, + { { 35, 33 }, { 72, 0 }, { 149, 132 }, { 25, 25 }, { 1, 0 }, 8, 0 }, + { { 35, 33 }, { 74, 0 }, { 149, 148 }, { 25, 25 }, { 1, 0 }, 8, 0 }, + { { 9, 132 }, { 161, 128 }, { 32, 209 }, { 79, 248 }, { 0, 0 }, 8, 0 }, + { { 33, 162 }, { 30, 0 }, { 148, 195 }, { 6, 166 }, { 0, 0 }, 2, 0 }, + { { 49, 49 }, { 18, 0 }, { 241, 241 }, { 40, 24 }, { 0, 0 }, 10, 0 }, + { { 49, 49 }, { 141, 0 }, { 241, 241 }, { 232, 120 }, { 0, 0 }, 10, 0 }, + { { 49, 50 }, { 91, 0 }, { 81, 113 }, { 40, 72 }, { 0, 0 }, 12, 0 }, + { { 1, 33 }, { 139, 64 }, { 161, 242 }, { 154, 223 }, { 0, 0 }, 8, 0 }, + { { 1, 33 }, { 137, 64 }, { 161, 242 }, { 154, 223 }, { 0, 0 }, 8, 0 }, + { { 49, 49 }, { 139, 0 }, { 244, 241 }, { 232, 120 }, { 0, 0 }, 10, 0 }, + { { 49, 49 }, { 18, 0 }, { 241, 241 }, { 40, 24 }, { 0, 0 }, 10, 0 }, + { { 49, 33 }, { 21, 0 }, { 221, 86 }, { 19, 38 }, { 1, 0 }, 8, 0 }, + { { 49, 33 }, { 22, 0 }, { 221, 102 }, { 19, 6 }, { 1, 0 }, 8, 0 }, + { { 113, 49 }, { 73, 0 }, { 209, 97 }, { 28, 12 }, { 1, 0 }, 8, 0 }, + { { 33, 35 }, { 77, 128 }, { 113, 114 }, { 18, 6 }, { 1, 0 }, 2, 0 }, + { { 241, 225 }, { 64, 0 }, { 241, 111 }, { 33, 22 }, { 1, 0 }, 2, 0 }, + { { 2, 1 }, { 26, 128 }, { 245, 133 }, { 117, 53 }, { 1, 0 }, 0, 0 }, + { { 2, 1 }, { 29, 128 }, { 245, 243 }, { 117, 244 }, { 1, 0 }, 0, 0 }, + { { 16, 17 }, { 65, 0 }, { 245, 242 }, { 5, 195 }, { 1, 0 }, 2, 0 }, + { { 33, 162 }, { 155, 1 }, { 177, 114 }, { 37, 8 }, { 1, 0 }, 14, 0 }, + { { 161, 33 }, { 152, 0 }, { 127, 63 }, { 3, 7 }, { 1, 1 }, 0, 0 }, + { { 161, 97 }, { 147, 0 }, { 193, 79 }, { 18, 5 }, { 0, 0 }, 10, 0 }, + { { 33, 97 }, { 24, 0 }, { 193, 79 }, { 34, 5 }, { 0, 0 }, 12, 0 }, + { { 49, 114 }, { 91, 131 }, { 244, 138 }, { 21, 5 }, { 0, 0 }, 0, 0 }, + { { 161, 97 }, { 144, 0 }, { 116, 113 }, { 57, 103 }, { 0, 0 }, 0, 0 }, + { { 113, 114 }, { 87, 0 }, { 84, 122 }, { 5, 5 }, { 0, 0 }, 12, 0 }, + { { 144, 65 }, { 0, 0 }, { 84, 165 }, { 99, 69 }, { 0, 0 }, 8, 0 }, + { { 33, 33 }, { 146, 1 }, { 133, 143 }, { 23, 9 }, { 0, 0 }, 12, 0 }, + { { 33, 33 }, { 148, 5 }, { 117, 143 }, { 23, 9 }, { 0, 0 }, 12, 0 }, + { { 33, 97 }, { 148, 0 }, { 118, 130 }, { 21, 55 }, { 0, 0 }, 12, 0 }, + { { 49, 33 }, { 67, 0 }, { 158, 98 }, { 23, 44 }, { 1, 1 }, 2, 0 }, + { { 33, 33 }, { 155, 0 }, { 97, 127 }, { 106, 10 }, { 0, 0 }, 2, 0 }, + { { 97, 34 }, { 138, 6 }, { 117, 116 }, { 31, 15 }, { 0, 0 }, 8, 0 }, + { { 161, 33 }, { 134, 13 }, { 114, 113 }, { 85, 24 }, { 1, 0 }, 0, 0 }, + { { 33, 33 }, { 77, 0 }, { 84, 166 }, { 60, 28 }, { 0, 0 }, 8, 0 }, + { { 49, 97 }, { 143, 0 }, { 147, 114 }, { 2, 11 }, { 1, 0 }, 8, 0 }, + { { 49, 97 }, { 142, 0 }, { 147, 114 }, { 3, 9 }, { 1, 0 }, 8, 0 }, + { { 49, 97 }, { 145, 0 }, { 147, 130 }, { 3, 9 }, { 1, 0 }, 10, 0 }, + { { 49, 97 }, { 142, 0 }, { 147, 114 }, { 15, 15 }, { 1, 0 }, 10, 0 }, + { { 33, 33 }, { 75, 0 }, { 170, 143 }, { 22, 10 }, { 1, 0 }, 8, 0 }, + { { 49, 33 }, { 144, 0 }, { 126, 139 }, { 23, 12 }, { 1, 1 }, 6, 0 }, + { { 49, 50 }, { 129, 0 }, { 117, 97 }, { 25, 25 }, { 1, 0 }, 0, 0 }, + { { 50, 33 }, { 144, 0 }, { 155, 114 }, { 33, 23 }, { 0, 0 }, 4, 0 }, + { { 225, 225 }, { 31, 0 }, { 133, 101 }, { 95, 26 }, { 0, 0 }, 0, 0 }, + { { 225, 225 }, { 70, 0 }, { 136, 101 }, { 95, 26 }, { 0, 0 }, 0, 0 }, + { { 161, 33 }, { 156, 0 }, { 117, 117 }, { 31, 10 }, { 0, 0 }, 2, 0 }, + { { 49, 33 }, { 139, 0 }, { 132, 101 }, { 88, 26 }, { 0, 0 }, 0, 0 }, + { { 225, 161 }, { 76, 0 }, { 102, 101 }, { 86, 38 }, { 0, 0 }, 0, 0 }, + { { 98, 161 }, { 203, 0 }, { 118, 85 }, { 70, 54 }, { 0, 0 }, 0, 0 }, + { { 98, 161 }, { 153, 0 }, { 87, 86 }, { 7, 7 }, { 0, 0 }, 11, 0 }, + { { 98, 161 }, { 147, 0 }, { 119, 118 }, { 7, 7 }, { 0, 0 }, 11, 0 }, + { { 34, 33 }, { 89, 0 }, { 255, 255 }, { 3, 15 }, { 2, 0 }, 0, 0 }, + { { 33, 33 }, { 14, 0 }, { 255, 255 }, { 15, 15 }, { 1, 1 }, 0, 0 }, + { { 34, 33 }, { 70, 128 }, { 134, 100 }, { 85, 24 }, { 0, 0 }, 0, 0 }, + { { 33, 161 }, { 69, 0 }, { 102, 150 }, { 18, 10 }, { 0, 0 }, 0, 0 }, + { { 33, 34 }, { 139, 0 }, { 146, 145 }, { 42, 42 }, { 1, 0 }, 0, 0 }, + { { 162, 97 }, { 158, 64 }, { 223, 111 }, { 5, 7 }, { 0, 0 }, 2, 0 }, + { { 32, 96 }, { 26, 0 }, { 239, 143 }, { 1, 6 }, { 0, 2 }, 0, 0 }, + { { 33, 33 }, { 143, 128 }, { 241, 244 }, { 41, 9 }, { 0, 0 }, 10, 0 }, + { { 119, 161 }, { 165, 0 }, { 83, 160 }, { 148, 5 }, { 0, 0 }, 2, 0 }, + { { 97, 177 }, { 31, 128 }, { 168, 37 }, { 17, 3 }, { 0, 0 }, 10, 0 }, + { { 97, 97 }, { 23, 0 }, { 145, 85 }, { 52, 22 }, { 0, 0 }, 12, 0 }, + { { 113, 114 }, { 93, 0 }, { 84, 106 }, { 1, 3 }, { 0, 0 }, 0, 0 }, + { { 33, 162 }, { 151, 0 }, { 33, 66 }, { 67, 53 }, { 0, 0 }, 8, 0 }, + { { 161, 33 }, { 28, 0 }, { 161, 49 }, { 119, 71 }, { 1, 1 }, 0, 0 }, + { { 33, 97 }, { 137, 3 }, { 17, 66 }, { 51, 37 }, { 0, 0 }, 10, 0 }, + { { 161, 33 }, { 21, 0 }, { 17, 207 }, { 71, 7 }, { 1, 0 }, 0, 0 }, + { { 58, 81 }, { 206, 0 }, { 248, 134 }, { 246, 2 }, { 0, 0 }, 2, 0 }, + { { 33, 33 }, { 21, 0 }, { 33, 65 }, { 35, 19 }, { 1, 0 }, 0, 0 }, + { { 6, 1 }, { 91, 0 }, { 116, 165 }, { 149, 114 }, { 0, 0 }, 0, 0 }, + { { 34, 97 }, { 146, 131 }, { 177, 242 }, { 129, 38 }, { 0, 0 }, 12, 0 }, + { { 65, 66 }, { 77, 0 }, { 241, 242 }, { 81, 245 }, { 1, 0 }, 0, 0 }, + { { 97, 163 }, { 148, 128 }, { 17, 17 }, { 81, 19 }, { 1, 0 }, 6, 0 }, + { { 97, 161 }, { 140, 128 }, { 17, 29 }, { 49, 3 }, { 0, 0 }, 6, 0 }, + { { 164, 97 }, { 76, 0 }, { 243, 129 }, { 115, 35 }, { 1, 0 }, 4, 0 }, + { { 2, 7 }, { 133, 3 }, { 210, 242 }, { 83, 246 }, { 0, 1 }, 0, 0 }, + { { 17, 19 }, { 12, 128 }, { 163, 162 }, { 17, 229 }, { 1, 0 }, 0, 0 }, + { { 17, 17 }, { 6, 0 }, { 246, 242 }, { 65, 230 }, { 1, 2 }, 4, 0 }, + { { 147, 145 }, { 145, 0 }, { 212, 235 }, { 50, 17 }, { 0, 1 }, 8, 0 }, + { { 4, 1 }, { 79, 0 }, { 250, 194 }, { 86, 5 }, { 0, 0 }, 12, 0 }, + { { 33, 34 }, { 73, 0 }, { 124, 111 }, { 32, 12 }, { 0, 1 }, 6, 0 }, + { { 49, 33 }, { 133, 0 }, { 221, 86 }, { 51, 22 }, { 1, 0 }, 10, 0 }, + { { 32, 33 }, { 4, 129 }, { 218, 143 }, { 5, 11 }, { 2, 0 }, 6, 0 }, + { { 5, 3 }, { 106, 128 }, { 241, 195 }, { 229, 229 }, { 0, 0 }, 6, 0 }, + { { 7, 2 }, { 21, 0 }, { 236, 248 }, { 38, 22 }, { 0, 0 }, 10, 0 }, + { { 5, 1 }, { 157, 0 }, { 103, 223 }, { 53, 5 }, { 0, 0 }, 8, 0 }, + { { 24, 18 }, { 150, 0 }, { 250, 248 }, { 40, 229 }, { 0, 0 }, 10, 0 }, + { { 16, 0 }, { 134, 3 }, { 168, 250 }, { 7, 3 }, { 0, 0 }, 6, 0 }, + { { 17, 16 }, { 65, 3 }, { 248, 243 }, { 71, 3 }, { 2, 0 }, 4, 0 }, + { { 1, 16 }, { 142, 0 }, { 241, 243 }, { 6, 2 }, { 2, 0 }, 14, 0 }, + { { 14, 192 }, { 0, 0 }, { 31, 31 }, { 0, 255 }, { 0, 3 }, 14, 0 }, + { { 6, 3 }, { 128, 136 }, { 248, 86 }, { 36, 132 }, { 0, 2 }, 14, 0 }, + { { 14, 208 }, { 0, 5 }, { 248, 52 }, { 0, 4 }, { 0, 3 }, 14, 0 }, + { { 14, 192 }, { 0, 0 }, { 246, 31 }, { 0, 2 }, { 0, 3 }, 14, 0 }, + { { 213, 218 }, { 149, 64 }, { 55, 86 }, { 163, 55 }, { 0, 0 }, 0, 0 }, + { { 53, 20 }, { 92, 8 }, { 178, 244 }, { 97, 21 }, { 2, 0 }, 10, 0 }, + { { 14, 208 }, { 0, 0 }, { 246, 79 }, { 0, 245 }, { 0, 3 }, 14, 0 }, + { { 38, 228 }, { 0, 0 }, { 255, 18 }, { 1, 22 }, { 0, 1 }, 14, 0 }, + { { 0, 0 }, { 0, 0 }, { 243, 246 }, { 240, 201 }, { 0, 2 }, 14, 0 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 0, 0 }, { 0, 0 }, { 252, 250 }, { 5, 23 }, { 2, 0 }, 14, 52 }, + { { 0, 1 }, { 2, 0 }, { 255, 255 }, { 7, 8 }, { 0, 0 }, 0, 48 }, + { { 0, 0 }, { 0, 0 }, { 252, 250 }, { 5, 23 }, { 2, 0 }, 14, 58 }, + { { 0, 0 }, { 0, 0 }, { 246, 246 }, { 12, 6 }, { 0, 0 }, 4, 60 }, + { { 12, 18 }, { 0, 0 }, { 246, 251 }, { 8, 71 }, { 0, 2 }, 10, 47 }, + { { 0, 0 }, { 3, 0 }, { 248, 246 }, { 42, 69 }, { 0, 1 }, 4, 43 }, + { { 12, 18 }, { 0, 0 }, { 246, 251 }, { 8, 71 }, { 0, 2 }, 10, 49 }, + { { 0, 0 }, { 3, 0 }, { 248, 246 }, { 42, 69 }, { 0, 1 }, 4, 43 }, + { { 12, 18 }, { 0, 0 }, { 246, 251 }, { 8, 71 }, { 0, 2 }, 10, 51 }, + { { 0, 0 }, { 3, 0 }, { 248, 246 }, { 42, 69 }, { 0, 1 }, 4, 43 }, + { { 12, 18 }, { 0, 0 }, { 246, 251 }, { 8, 71 }, { 0, 2 }, 10, 54 }, + { { 12, 18 }, { 0, 0 }, { 246, 251 }, { 8, 71 }, { 0, 2 }, 10, 57 }, + { { 0, 0 }, { 3, 0 }, { 248, 246 }, { 42, 69 }, { 0, 1 }, 4, 72 }, + { { 12, 18 }, { 0, 0 }, { 246, 251 }, { 8, 71 }, { 0, 2 }, 10, 60 }, + { { 14, 208 }, { 0, 10 }, { 245, 159 }, { 48, 2 }, { 0, 0 }, 14, 76 }, + { { 14, 7 }, { 10, 93 }, { 228, 245 }, { 228, 229 }, { 3, 1 }, 6, 84 }, + { { 2, 5 }, { 3, 10 }, { 180, 151 }, { 4, 247 }, { 0, 0 }, 14, 36 }, + { { 78, 158 }, { 0, 0 }, { 246, 159 }, { 0, 2 }, { 0, 3 }, 14, 76 }, + { { 17, 16 }, { 69, 8 }, { 248, 243 }, { 55, 5 }, { 2, 0 }, 8, 84 }, + { { 14, 208 }, { 0, 0 }, { 246, 159 }, { 0, 2 }, { 0, 3 }, 14, 83 }, + { { 128, 16 }, { 0, 13 }, { 255, 255 }, { 3, 20 }, { 3, 0 }, 12, 84 }, + { { 14, 7 }, { 8, 81 }, { 248, 244 }, { 66, 228 }, { 0, 3 }, 14, 24 }, + { { 14, 208 }, { 0, 10 }, { 245, 159 }, { 48, 2 }, { 0, 0 }, 14, 77 }, + { { 1, 2 }, { 0, 0 }, { 250, 200 }, { 191, 151 }, { 0, 0 }, 7, 60 }, + { { 1, 1 }, { 81, 0 }, { 250, 250 }, { 135, 183 }, { 0, 0 }, 6, 65 }, + { { 1, 2 }, { 84, 0 }, { 250, 248 }, { 141, 184 }, { 0, 0 }, 6, 59 }, + { { 1, 2 }, { 89, 0 }, { 250, 248 }, { 136, 182 }, { 0, 0 }, 6, 51 }, + { { 1, 0 }, { 0, 0 }, { 249, 250 }, { 10, 6 }, { 3, 0 }, 14, 45 }, + { { 0, 0 }, { 128, 0 }, { 249, 246 }, { 137, 108 }, { 3, 0 }, 14, 71 }, + { { 3, 12 }, { 128, 8 }, { 248, 246 }, { 136, 182 }, { 3, 0 }, 15, 60 }, + { { 3, 12 }, { 133, 0 }, { 248, 246 }, { 136, 182 }, { 3, 0 }, 15, 58 }, + { { 14, 0 }, { 64, 8 }, { 118, 119 }, { 79, 24 }, { 0, 2 }, 14, 53 }, + { { 14, 3 }, { 64, 0 }, { 200, 155 }, { 73, 105 }, { 0, 2 }, 14, 64 }, + { { 215, 199 }, { 220, 0 }, { 173, 141 }, { 5, 5 }, { 3, 0 }, 14, 71 }, + { { 215, 199 }, { 220, 0 }, { 168, 136 }, { 4, 4 }, { 3, 0 }, 14, 61 }, + { { 128, 17 }, { 0, 0 }, { 246, 103 }, { 6, 23 }, { 3, 3 }, 14, 61 }, + { { 128, 17 }, { 0, 9 }, { 245, 70 }, { 5, 22 }, { 2, 3 }, 14, 48 }, + { { 6, 21 }, { 63, 0 }, { 0, 247 }, { 244, 245 }, { 0, 0 }, 1, 48 }, + { { 6, 18 }, { 63, 0 }, { 0, 247 }, { 244, 245 }, { 3, 0 }, 0, 69 }, + { { 6, 18 }, { 63, 0 }, { 0, 247 }, { 244, 245 }, { 0, 0 }, 1, 68 }, + { { 1, 2 }, { 88, 0 }, { 103, 117 }, { 231, 7 }, { 0, 0 }, 0, 63 }, + { { 65, 66 }, { 69, 8 }, { 248, 117 }, { 72, 5 }, { 0, 0 }, 0, 74 }, + { { 10, 30 }, { 64, 78 }, { 224, 255 }, { 240, 5 }, { 3, 0 }, 8, 60 }, + { { 10, 30 }, { 124, 82 }, { 224, 255 }, { 240, 2 }, { 3, 0 }, 8, 80 }, + { { 14, 0 }, { 64, 8 }, { 122, 123 }, { 74, 27 }, { 0, 2 }, 14, 64 }, + { { 14, 7 }, { 10, 64 }, { 228, 85 }, { 228, 57 }, { 3, 1 }, 6, 69 }, + { { 5, 4 }, { 5, 64 }, { 249, 214 }, { 50, 165 }, { 3, 0 }, 14, 73 }, + { { 2, 21 }, { 63, 0 }, { 0, 247 }, { 243, 245 }, { 3, 0 }, 8, 75 }, + { { 1, 2 }, { 79, 0 }, { 250, 248 }, { 141, 181 }, { 0, 0 }, 7, 68 }, + { { 0, 0 }, { 0, 0 }, { 246, 246 }, { 12, 6 }, { 0, 0 }, 4, 48 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 53 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35 } + }; diff --git a/audiolib/gus.c b/audiolib/gus.c new file mode 100755 index 0000000..26cdc92 --- /dev/null +++ b/audiolib/gus.c @@ -0,0 +1,283 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + file: GUS.C + + author: James R. Dose + date: September 7, 1994 + + Gravis Ultrasound initialization routines. + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include "usrhooks.h" +#include "interrup.h" +#include "newgf1.h" +#include "gusmidi.h" +#include "guswave.h" +#include "_guswave.h" + +#define TRUE ( 1 == 1 ) +#define FALSE ( !TRUE ) + +// size of DMA buffer for patch loading +#define DMABUFFSIZE 2048U + +struct gf1_dma_buff GUS_HoldBuffer; +static int HoldBufferAllocated = FALSE; + +static int GUS_Installed = 0; + +extern VoiceNode GUSWAVE_Voices[ VOICES ]; +extern int GUSWAVE_Installed; + +unsigned long GUS_TotalMemory; +int GUS_MemConfig; + +int GUS_AuxError = 0; + +int GUS_ErrorCode = GUS_Ok; + +#define GUS_SetErrorCode( status ) \ + GUS_ErrorCode = ( status ); + + +/*--------------------------------------------------------------------- + Function: GUS_ErrorString + + Returns a pointer to the error message associated with an error + number. A -1 returns a pointer the current error. +---------------------------------------------------------------------*/ + +char *GUS_ErrorString + ( + int ErrorNumber + ) + + { + char *ErrorString; + + switch( ErrorNumber ) + { + case GUS_Warning : + case GUS_Error : + ErrorString = GUS_ErrorString( GUS_ErrorCode ); + break; + + case GUS_Ok : + ErrorString = "Ultrasound music ok."; + break; + + case GUS_OutOfMemory : + ErrorString = "Out of memory in GusMidi."; + break; + + case GUS_OutOfDosMemory : + ErrorString = "Out of conventional (640K) memory in GusMidi."; + break; + + case GUS_GF1Error : + ErrorString = gf1_error_str( GUS_AuxError ); + break; + + case GUS_InvalidIrq : + ErrorString = "Ultrasound IRQ must be 7 or less."; + break; + + case GUS_ULTRADIRNotSet : + ErrorString = "ULTRADIR environment variable not set."; + break; + + case GUS_MissingConfig : +// ErrorString = "Can't find GUSMIDI.INI file."; + ErrorString = "Can't find ULTRAMID.INI file."; + break; + + case GUS_FileError : + ErrorString = strerror( GUS_AuxError ); + break; + + default : + ErrorString = "Unknown Ultrasound error code."; + break; + } + + return( ErrorString ); + } + + + +/*--------------------------------------------------------------------- + Function: D32DosMemAlloc + + Allocate a block of Conventional memory. +---------------------------------------------------------------------*/ + +void *D32DosMemAlloc + ( + unsigned size + ) + + { + union REGS r; + + // DPMI allocate DOS memory + r.x.eax = 0x0100; + + // Number of paragraphs requested + r.x.ebx = ( size + 15 ) >> 4; + int386( 0x31, &r, &r ); + if ( r.x.cflag ) + { + // Failed + return( NULL ); + } + + return( ( void * )( ( r.x.eax & 0xFFFF ) << 4 ) ); + } + + +/*--------------------------------------------------------------------- + Function: GUS_Init + + Initializes the Gravis Ultrasound for sound and music playback. +---------------------------------------------------------------------*/ + +int GUS_Init + ( + void + ) + + { + struct load_os os; + int ret; + + if ( GUS_Installed > 0 ) + { + GUS_Installed++; + return( GUS_Ok ); + } + + GUS_SetErrorCode( GUS_Ok ); + + GUS_Installed = 0; + + GetUltraCfg( &os ); + + if ( os.forced_gf1_irq > 7 ) + { + GUS_SetErrorCode( GUS_InvalidIrq ); + return( GUS_Error ); + } + + if ( !HoldBufferAllocated ) + { + GUS_HoldBuffer.vptr = D32DosMemAlloc( DMABUFFSIZE ); + if ( GUS_HoldBuffer.vptr == NULL ) + { + GUS_SetErrorCode( GUS_OutOfDosMemory ); + return( GUS_Error ); + } + GUS_HoldBuffer.paddr = ( unsigned long )GUS_HoldBuffer.vptr; + + HoldBufferAllocated = TRUE; + } + + os.voices = 24; + ret = gf1_load_os( &os ); + if ( ret ) + { + GUS_AuxError = ret; + GUS_SetErrorCode( GUS_GF1Error ); + return( GUS_Error ); + } + + GUS_TotalMemory = gf1_mem_avail(); + GUS_MemConfig = ( GUS_TotalMemory - 1 ) >> 18; + + GUS_Installed = 1; + return( GUS_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: GUS_Shutdown + + Ends use of the Gravis Ultrasound. Must be called the same number + of times as GUS_Init. +---------------------------------------------------------------------*/ + +void GUS_Shutdown + ( + void + ) + + { + if ( GUS_Installed > 0 ) + { + GUS_Installed--; + if ( GUS_Installed == 0 ) + { + gf1_unload_os(); + } + } + } + + +/*--------------------------------------------------------------------- + Function: GUSWAVE_Shutdown + + Terminates use of the Gravis Ultrasound for digitized sound playback. +---------------------------------------------------------------------*/ + +void GUSWAVE_Shutdown + ( + void + ) + + { + int i; + + if ( GUSWAVE_Installed ) + { + GUSWAVE_KillAllVoices(); + + // free memory + for ( i = 0; i < VOICES; i++ ) + { + if ( GUSWAVE_Voices[ i ].mem != NULL ) + { + gf1_free( GUSWAVE_Voices[ i ].mem ); + GUSWAVE_Voices[ i ].mem = NULL; + } + } + + GUS_Shutdown(); + GUSWAVE_Installed = FALSE; + } + } diff --git a/audiolib/gusmidi.c b/audiolib/gusmidi.c new file mode 100755 index 0000000..9a23045 --- /dev/null +++ b/audiolib/gusmidi.c @@ -0,0 +1,561 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/*********** *********************************************************** + file: GUSMIDI.C + + author: James R. Dose + date: March 23, 1994 + + General MIDI playback functions for the Gravis Ultrasound + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +// Module MUST be compiled with structure allignment set to a maximum +// of 1 byte ( zp1 ). + +#include +#include +#include +#include +#include +#include +#include +#include "usrhooks.h" +#include "interrup.h" +#include "newgf1.h" +#include "gusmidi.h" + +#define TRUE ( 1 == 1 ) +#define FALSE ( !TRUE ) + +// size of DMA buffer for patch loading +#define DMABUFFSIZE 2048U + +#define MAX_MEM_CONFIG 3 + +// size of patch array (128 perc, 128 melodic) +#define NUM_PATCHES 256 + +// size of largest patch name +#define BIGGEST_NAME 9 + +#define UNUSED_PATCH -1 + +static struct patch Patch[ NUM_PATCHES ]; +static unsigned char *PatchWaves[ NUM_PATCHES ]; + +static int PatchMap[ NUM_PATCHES ][ MAX_MEM_CONFIG + 1 ]; +static char ProgramName[ NUM_PATCHES ][ BIGGEST_NAME ]; +static char PatchLoaded[ NUM_PATCHES ]; + +static char ConfigFileName[] = "ULTRAMID.INI"; +static char ConfigDirectory[ 80 ] = { '\0' }; + +// The name of the configuration directory +static char InstrumentDirectory[ 80 ]; + +extern struct gf1_dma_buff GUS_HoldBuffer; + +extern unsigned long GUS_TotalMemory; +extern int GUS_MemConfig; + +static int GUSMIDI_Volume = 255; + +extern int GUS_AuxError; +extern int GUS_ErrorCode; + +int GUSMIDI_Installed = FALSE; + +#define GUS_SetErrorCode( status ) \ + GUS_ErrorCode = ( status ); + + +/*--------------------------------------------------------------------- + Function: GUS_GetPatchMap + + Reads the patch map from disk. +---------------------------------------------------------------------*/ + +int GUS_GetPatchMap + ( + char *name + ) + + { + char text[ 80 ]; + char *ud; + int index; + int ignore; + FILE *fp; + + for( index = 0; index < NUM_PATCHES; index++ ) + { + PatchMap[ index ][ 0 ] = UNUSED_PATCH; + PatchMap[ index ][ 1 ] = UNUSED_PATCH; + PatchMap[ index ][ 2 ] = UNUSED_PATCH; + PatchMap[ index ][ 3 ] = UNUSED_PATCH; + ProgramName[ index ][ 0 ] = 0; + } + + ud = getenv( "ULTRADIR" ); + if ( ud == NULL ) + { + GUS_SetErrorCode( GUS_ULTRADIRNotSet ); + return( GUS_Error ); + } + + strcpy( InstrumentDirectory, ud ); + strcat( InstrumentDirectory, "\\midi\\" ); + strcpy( ConfigDirectory, ud ); + strcat( ConfigDirectory, "\\midi\\" ); + strcpy( text, name ); + + fp = fopen( text, "r" ); + if ( fp == NULL ) + { + strcpy( text, InstrumentDirectory ); + strcat( text, name ); + + fp = fopen( text, "r" ); + if ( fp == NULL ) + { + GUS_SetErrorCode( GUS_MissingConfig ); + return( GUS_Error ); + } + } + + while( 1 ) + { + if ( fgets( text, 80, fp ) == NULL ) + { + break; + } + + if ( text[ 0 ] == '#' ) + { + continue; + } + + if ( sscanf( text, "%d", &index ) != 1 ) + { + continue; + } + + sscanf( text, "%d, %d, %d, %d, %d, %s\n", &ignore, + &PatchMap[ index ][ 0 ], + &PatchMap[ index ][ 1 ], + &PatchMap[ index ][ 2 ], + &PatchMap[ index ][ 3 ], + ProgramName[ index ] ); + } + + fclose( fp ); + + return( GUS_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: GUSMIDI_UnloadPatch + + Unloads a patch from the GUS's memory. +---------------------------------------------------------------------*/ + +int GUSMIDI_UnloadPatch + ( + int prognum + ) + + { + int prog; + unsigned flags; + + prog = PatchMap[ prognum ][ GUS_MemConfig ]; + + if ( PatchLoaded[ prog ] ) + { + flags = DisableInterrupts(); + + gf1_unload_patch( &Patch[ prog ] ); + if ( PatchWaves[ prog ] != NULL ) + { + USRHOOKS_FreeMem( PatchWaves[ prog ] ); + PatchWaves[ prog ] = NULL; + } + + // just in case sequence is still playing + Patch[ prog ].nlayers = 0; + PatchLoaded[ prog ] = FALSE; + + RestoreInterrupts( flags ); + } + + return( GUS_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: GUSMIDI_LoadPatch + + Loads a patch into the GUS's memory. +---------------------------------------------------------------------*/ + +int GUSMIDI_LoadPatch + ( + int prognum + ) + + { + int prog; + char text[ 80 ]; + int ret; + unsigned char *wave_buff; + struct patchinfo patchi; + int status; + + prog = PatchMap[ prognum ][ GUS_MemConfig ]; + + if ( ( PatchLoaded[ prog ] ) || ( prog == UNUSED_PATCH ) ) + { + return( GUS_Ok ); + } + + if ( !ProgramName[ prog ][ 0 ] ) + { + return( GUS_Ok ); + } + + strcpy( text, InstrumentDirectory ); + strcat( text, ProgramName[ prog ] ); + strcat( text, ".pat" ); + + ret = gf1_get_patch_info( text, &patchi ); + if ( ret != OK ) + { + GUS_AuxError = ret; + GUS_SetErrorCode( GUS_GF1Error ); + return( GUS_Error ); + } + + status = USRHOOKS_GetMem( &wave_buff, patchi.header.wave_forms * + sizeof( struct wave_struct ) ); + if ( status != USRHOOKS_Ok ) + { + GUS_SetErrorCode( GUS_OutOfMemory ); + return( GUS_Error ); + } + + ret = gf1_load_patch( text, &patchi, &Patch[ prog ], &GUS_HoldBuffer, + DMABUFFSIZE, ( unsigned char * )wave_buff, PATCH_LOAD_8_BIT ); + + if ( ret != OK ) + { + USRHOOKS_FreeMem( wave_buff ); + GUS_AuxError = ret; + GUS_SetErrorCode( GUS_GF1Error ); + return( GUS_Error ); + } + + PatchWaves[ prog ] = wave_buff; + PatchLoaded[ prog ] = TRUE; + + return( GUS_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: GUSMIDI_ProgramChange + + Selects the instrument to use on the specified MIDI channel. +---------------------------------------------------------------------*/ + +void GUSMIDI_ProgramChange + ( + int channel, + int prognum + ) + + { + int prog; + + prog = PatchMap[ prognum ][ GUS_MemConfig ]; + + if ( PatchLoaded[ prog ] ) + { + gf1_midi_change_program( &Patch[ prog ], channel ); + } + else + { + gf1_midi_change_program( NULL, channel ); + } + } + + +/*--------------------------------------------------------------------- + Function: GUSMIDI_NoteOn + + Plays a note on the specified channel. +---------------------------------------------------------------------*/ + +void GUSMIDI_NoteOn + ( + int chan, + int note, + int velocity + ) + + { + int prog; + + if ( chan == 9 ) + { + prog = PatchMap[ note + 128 ][ GUS_MemConfig ]; + + if ( PatchLoaded[ prog ] ) + { + gf1_midi_note_on( &Patch[ note + 128 ], 1, + note, velocity, 9 ); + } + } + else + { + gf1_midi_note_on( 0L, 1, note, velocity, chan ); + } + } + + +/*--------------------------------------------------------------------- + Function: GUSMIDI_NoteOff + + Turns off a note on the specified channel. +---------------------------------------------------------------------*/ +#pragma warn -par +void GUSMIDI_NoteOff + ( + int chan, + int note, + int velocity + ) + + { + gf1_midi_note_off( note, chan ); + } +#pragma warn .par + + +/*--------------------------------------------------------------------- + Function: GUSMIDI_ControlChange + + Sets the value of a controller on the specified channel. +---------------------------------------------------------------------*/ + +void GUSMIDI_ControlChange + ( + int channel, + int number, + int value + ) + + { + gf1_midi_parameter( channel, number, value ); + } + + +/*--------------------------------------------------------------------- + Function: GUSMIDI_PitchBend + + Sets the pitch bend on the specified MIDI channel. +---------------------------------------------------------------------*/ + +void GUSMIDI_PitchBend + ( + int channel, + int lsb, + int msb + ) + + { + gf1_midi_pitch_bend( channel, lsb, msb ); + } + + +/*--------------------------------------------------------------------- + Function: GUSMIDI_ReleasePatches + + Removes all the instruments from the GUS's memory. +---------------------------------------------------------------------*/ + +void GUSMIDI_ReleasePatches + ( + void + ) + + { + int i; + + for( i = 0; i < 256; i++ ) + { + GUSMIDI_UnloadPatch( i ); + } + } + + +/*--------------------------------------------------------------------- + Function: GUSMIDI_SetVolume + + Sets the total music volume. +---------------------------------------------------------------------*/ + +void GUSMIDI_SetVolume + ( + int volume + ) + + { + // Set the minimum to 2 because 0 has a tremolo problem + volume = max( 2, volume ); + volume = min( volume, 255 ); + + GUSMIDI_Volume = volume; + + // range = 0 to 127 + gf1_midi_synth_volume( 0, volume >> 1 ); + } + + +/*--------------------------------------------------------------------- + Function: GUSMIDI_GetVolume + + Returns the total music volume. +---------------------------------------------------------------------*/ + +int GUSMIDI_GetVolume + ( + void + ) + + { + return( GUSMIDI_Volume ); + } + + +/*--------------------------------------------------------------------- + Function: GUSMIDI_Init + + Initializes the Gravis Ultrasound for music playback. +---------------------------------------------------------------------*/ + +int GUSMIDI_Init + ( + void + ) + + { + int ret; + int i; + int startmem; +// unsigned long mem; + extern int GUSWAVE_Installed; + + if ( GUSMIDI_Installed ) + { + GUSMIDI_Shutdown(); + } + + ret = GUS_Init(); + if ( ret != GUS_Ok ) + { + return( ret ); + } + + if ( GUS_MemConfig < 0 ) + { + GUS_MemConfig = 0; + } + + if ( GUS_MemConfig > MAX_MEM_CONFIG ) + { + GUS_MemConfig = MAX_MEM_CONFIG; + } + + for( i = 0; i < NUM_PATCHES; i++ ) + { + ProgramName[ i ][ 0 ] = '\0'; + PatchWaves[ i ] = NULL; + PatchLoaded[ i ] = FALSE; + } + + GUSMIDI_SetVolume( 255 ); + + GUSMIDI_Installed = TRUE; + + ret = GUS_GetPatchMap( ConfigFileName ); + if ( ret != GUS_Ok ) + { + GUSMIDI_Shutdown(); + return( ret ); + } + +// if ( !GUSWAVE_Installed ) +// { +// mem = gf1_malloc( 8192 ); +// } + + startmem = gf1_mem_avail(); + for( i = 0; i < NUM_PATCHES; i++ ) + { + ret = GUSMIDI_LoadPatch( i ); + if ( ret != GUS_Ok ) + { + } +// if ( ret != GUS_Ok ) +// { +// return( ret ); +// } + } + +// if ( !GUSWAVE_Installed ) +// { +// gf1_free( mem ); +// } + + GUSMIDI_Installed = TRUE; + + return( GUS_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: GUSMIDI_Shutdown + + Ends use of the Gravis Ultrasound for music playback. +---------------------------------------------------------------------*/ + +void GUSMIDI_Shutdown + ( + void + ) + + { + GUSMIDI_ReleasePatches(); + GUS_Shutdown(); + GUSMIDI_Installed = FALSE; + } diff --git a/audiolib/gusmidi.h b/audiolib/gusmidi.h new file mode 100755 index 0000000..12a5b9f --- /dev/null +++ b/audiolib/gusmidi.h @@ -0,0 +1,59 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef __GUSMIDI_H +#define __GUSMIDI_H + +extern struct gf1_dma_buff GUS_HoldBuffer; + +enum GUS_Errors + { + GUS_Warning = -2, + GUS_Error = -1, + GUS_Ok = 0, + GUS_OutOfMemory, + GUS_OutOfDosMemory, + GUS_OutOfDRAM, + GUS_GF1Error, + GUS_InvalidIrq, + GUS_ULTRADIRNotSet, + GUS_MissingConfig, + GUS_FileError + }; + +char *GUS_ErrorString( int ErrorNumber ); +int GUS_GetPatchMap( char *name ); +int GUSMIDI_UnloadPatch( int prog ); +int GUSMIDI_LoadPatch( int prog ); +void GUSMIDI_ProgramChange( int channel, int prog ); +void GUSMIDI_NoteOn( int chan, int note, int velocity ); +void GUSMIDI_NoteOff( int chan, int note, int velocity ); +void GUSMIDI_ControlChange( int channel, int number, int value ); +void GUSMIDI_PitchBend( int channel, int lsb, int msb ); +void GUSMIDI_ReleasePatches( void ); +void GUSMIDI_SetVolume( int volume ); +int GUSMIDI_GetVolume( void ); +int GUS_Init( void ); +void GUS_Shutdown( void ); +#pragma aux GUS_Shutdown frame; +int GUSMIDI_Init( void ); +void GUSMIDI_Shutdown( void ); +void *D32DosMemAlloc( unsigned size ); + +#endif diff --git a/audiolib/guswave.c b/audiolib/guswave.c new file mode 100755 index 0000000..b0baf6f --- /dev/null +++ b/audiolib/guswave.c @@ -0,0 +1,1773 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + file: GUSWAVE.C + + author: James R. Dose + date: March 23, 1994 + + Digitized sound playback routines for the Gravis Ultrasound. + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "debugio.h" +#include "interrup.h" +#include "ll_man.h" +#include "pitch.h" +#include "user.h" +#include "multivoc.h" +#include "_guswave.h" +#include "newgf1.h" +#include "gusmidi.h" +#include "guswave.h" + +#define ATR_INDEX 0x3c0 +#define STATUS_REGISTER_1 0x3da + +#define SetBorderColor(color) \ + { \ + inp (STATUS_REGISTER_1); \ + outp (ATR_INDEX,0x31); \ + outp (ATR_INDEX,color); \ + } + +static const int GUSWAVE_PanTable[ 32 ] = + { + 8, 9, 10, 11, 11, 12, 13, 14, + 15, 14, 13, 12, 11, 10, 9, 8, + 7, 6, 5, 4, 4, 3, 2, 1, + 0, 1, 2, 3, 4, 5, 6, 7 + }; + +static voicelist VoiceList; +static voicelist VoicePool; + +static voicestatus VoiceStatus[ MAX_VOICES ]; +//static +VoiceNode GUSWAVE_Voices[ VOICES ]; + +static int GUSWAVE_VoiceHandle = GUSWAVE_MinVoiceHandle; +static int GUSWAVE_MaxVoices = VOICES; +//static +int GUSWAVE_Installed = FALSE; + +static void ( *GUSWAVE_CallBackFunc )( unsigned long ) = NULL; + +// current volume for dig audio - from 0 to 4095 +static int GUSWAVE_Volume = MAX_VOLUME; + +static int GUSWAVE_SwapLeftRight = FALSE; + +static int GUS_Debug = FALSE; + +extern int GUSMIDI_Installed; + +int GUSWAVE_ErrorCode = GUSWAVE_Ok; + +#define GUSWAVE_SetErrorCode( status ) \ + GUSWAVE_ErrorCode = ( status ); + + +/*--------------------------------------------------------------------- + Function: GUSWAVE_ErrorString + + Returns a pointer to the error message associated with an error + number. A -1 returns a pointer the current error. +---------------------------------------------------------------------*/ + +char *GUSWAVE_ErrorString + ( + int ErrorNumber + ) + + { + char *ErrorString; + + switch( ErrorNumber ) + { + case GUSWAVE_Warning : + case GUSWAVE_Error : + ErrorString = GUSWAVE_ErrorString( GUSWAVE_ErrorCode ); + break; + + case GUSWAVE_Ok : + ErrorString = "GUSWAVE ok."; + break; + + case GUSWAVE_GUSError : + ErrorString = GUS_ErrorString( GUS_Error ); + break; + + case GUSWAVE_NotInstalled : + ErrorString = "GUSWAVE not installed."; + break; + + case GUSWAVE_NoVoices : + ErrorString = "No free voices available to GUSWAVE."; + break; + + case GUSWAVE_UltraNoMem : + ErrorString = "Not enough Ultrasound memory available for GUSWAVE."; + break; + + case GUSWAVE_UltraNoMemMIDI : + ErrorString = "Not enough Ultrasound memory available for GUSWAVE. " + "Try initializing Sound FX before Music."; + break; + + case GUSWAVE_VoiceNotFound : + ErrorString = "No voice with matching handle found."; + break; + + case GUSWAVE_InvalidVOCFile : + ErrorString = "Invalid VOC file passed in to GUSWAVE."; + break; + + case GUSWAVE_InvalidWAVFile : + ErrorString = "Invalid WAV file passed in to GUSWAVE."; + break; + + default : + ErrorString = "Unknown GUSWAVE error code."; + break; + } + + return( ErrorString ); + } + + +/*--------------------------------------------------------------------- + Function: GUSWAVE_CallBack + + GF1 callback service routine. +---------------------------------------------------------------------*/ + +char GUS_Silence8[ 1024 ] = //256 ] = + { + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 + + + }; + +//unsigned short GUS_Silence16[ 128 ] = +unsigned short GUS_Silence16[ 512 ] = + { + 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, 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, 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, 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 + }; + +static int LOADDS GUSWAVE_CallBack + ( + int reason, + int voice, + unsigned char **buf, + unsigned long *size + ) + + { + VoiceNode *Voice; + playbackstatus status; + + // this function is called from an interrupt + // remember not to make any DOS or BIOS calls from here + // also don't call any C library functions unless you are sure that + // they are reentrant + // restore our DS register + + if ( VoiceStatus[ voice ].playing == FALSE ) + { + return( DIG_DONE ); + } + + if ( reason == DIG_MORE_DATA ) + { +// SetBorderColor(16); + Voice = VoiceStatus[ voice ].Voice; + + if ( ( Voice != NULL ) && ( Voice->Playing ) ) +/* + { + *buf = ( unsigned char * )GUS_Silence16; + *size = 1024; + + SetBorderColor(0); + return( DIG_MORE_DATA ); + } + */ + { + status = Voice->GetSound( Voice ); + if ( status != SoundDone ) + { + if ( ( Voice->sound == NULL ) || ( status == NoMoreData ) ) + { + if ( Voice->bits == 8 ) + { + *buf = GUS_Silence8; + } + else + { + *buf = ( unsigned char * )GUS_Silence16; + } + *size = 256; + } + else + { + *buf = Voice->sound; + *size = Voice->length; + } + return( DIG_MORE_DATA ); + } + } +// SetBorderColor(16); + return( DIG_DONE ); + } + + if ( reason == DIG_DONE ) + { + Voice = VoiceStatus[ voice ].Voice; + VoiceStatus[ voice ].playing = FALSE; + + if ( Voice != NULL ) + { + Voice->Active = FALSE; + Voice->Playing = FALSE; + +// I'm commenting this out because a -1 could cause a crash if it +// is sent to the GF1 code. This shouldn't be necessary since +// Active should be false when GF1voice is -1, but this is just +// a precaution. Adjust the pan on the wrong voice is a lot +// more pleasant than a crash! +// Voice->GF1voice = -1; + + LL_Remove( VoiceNode, &VoiceList, Voice ); + LL_AddToTail( VoiceNode, &VoicePool, Voice ); + } + + if ( GUSWAVE_CallBackFunc ) + { + GUSWAVE_CallBackFunc( Voice->callbackval ); + } + } + + return( DIG_DONE ); + } + + +/*--------------------------------------------------------------------- + Function: GUSWAVE_DebugCallBack + + GF1 callback service routine with debugging info. +---------------------------------------------------------------------*/ + +static int LOADDS GUSWAVE_DebugCallBack + ( + int reason, + int voice, + unsigned char **buf, + unsigned long *size + ) + + { + VoiceNode *Voice; + + // this function is called from an interrupt + // remember not to make any DOS or BIOS calls from here + // also don't call any C library functions unless you are sure that + // they are reentrant + // restore our DS register + + if ( VoiceStatus[ voice ].playing == FALSE ) + { +// DB_printf( "GUS Voice %d not playing.\n", voice ); + DB_printf( "GUS Voice " ); + DB_PrintNum( voice ); + DB_printf( " not playing.\n" ); + return( DIG_DONE ); + } + + if ( reason == DIG_MORE_DATA ) + { + Voice = VoiceStatus[ voice ].Voice; + +// DB_printf( "Voice %d : More data -- ", Voice ); + DB_printf( "Voice " ); + DB_PrintNum( voice ); + DB_printf( " : More data -- " ); + if ( Voice != NULL ) + { + if ( Voice->Playing ) + { + GUSWAVE_GetNextVOCBlock( Voice ); + if ( Voice->Playing ) + { +// DB_printf( "More data -- size = %u blocklength = %u\n", +// Voice->length, Voice->BlockLength ); + DB_printf( "More data -- size = " ); + DB_PrintNum( Voice->length ); + DB_printf( " blocklength = " ); + DB_PrintNum( Voice->BlockLength ); + DB_printf( "\n" ); + *buf = Voice->sound; + *size = Voice->length; + return( DIG_MORE_DATA ); + } + else + { + DB_printf( "Voice done.\n" ); + } + } + else + { + DB_printf( "Voice not active.\n" ); + } + } + else + { + DB_printf( " NULL Voice\n" ); + } + + return( DIG_DONE ); + } + + if ( reason == DIG_DONE ) + { + VoiceStatus[ voice ].playing = FALSE; + Voice = VoiceStatus[ voice ].Voice; +// DB_printf( "Voice %d : Done -- ", Voice ); + DB_printf( "Voice " ); + DB_PrintNum( voice ); + DB_printf( " : Done -- " ); + + if ( Voice != NULL ) + { + DB_printf( "Ok\n" ); + + Voice->Active = FALSE; + Voice->Playing = FALSE; + +// I'm commenting this out because a -1 could cause a crash if it +// is sent to the GF1 code. This shouldn't be necessary since +// Active should be false when GF1voice is -1, but this is just +// a precaution. Adjust the pan on the wrong voice is a lot +// more pleasant than a crash! +// Voice->GF1voice = -1; + + LL_Remove( VoiceNode, &VoiceList, Voice ); + LL_AddToTail( VoiceNode, &VoicePool, Voice ); + } + else + { + DB_printf( "Null voice\n" ); + } + + if ( GUSWAVE_CallBackFunc ) + { + GUSWAVE_CallBackFunc( Voice->callbackval ); + } + } + + return( DIG_DONE ); + } + + +/*--------------------------------------------------------------------- + Function: GUSWAVE_GetVoice + + Locates the voice with the specified handle. +---------------------------------------------------------------------*/ + +static VoiceNode *GUSWAVE_GetVoice + ( + int handle + ) + + { + VoiceNode *voice; + unsigned flags; + + flags = DisableInterrupts(); + + voice = VoiceList.start; + + while( voice != NULL ) + { + if ( handle == voice->handle ) + { + break; + } + + voice = voice->next; + } + + RestoreInterrupts( flags ); + + if ( voice == NULL ) + { + GUSWAVE_SetErrorCode( GUSWAVE_VoiceNotFound ); + } + + return( voice ); + } + + +/*--------------------------------------------------------------------- + Function: GUSWAVE_VoicePlaying + + Checks if the voice associated with the specified handle is + playing. +---------------------------------------------------------------------*/ + +int GUSWAVE_VoicePlaying + ( + int handle + ) + + { + VoiceNode *voice; + + voice = GUSWAVE_GetVoice( handle ); + if ( voice != NULL ) + { + return( voice->Active ); + } + + return( FALSE ); + } + + +/*--------------------------------------------------------------------- + Function: GUSWAVE_VoicesPlaying + + Determines the number of currently active voices. +---------------------------------------------------------------------*/ + +int GUSWAVE_VoicesPlaying + ( + void + ) + + { + int index; + int NumVoices = 0; + unsigned flags; + + flags = DisableInterrupts(); + + for( index = 0; index < GUSWAVE_MaxVoices; index++ ) + { + if ( GUSWAVE_Voices[ index ].Active ) + { + NumVoices++; + } + } + + RestoreInterrupts( flags ); + + if ( GUS_Debug ) + { + DB_printf( "Number of voices = %d.\n", NumVoices ); + } + + return( NumVoices ); + } + + +/*--------------------------------------------------------------------- + Function: GUSWAVE_Kill + + Stops output of the voice associated with the specified handle. +---------------------------------------------------------------------*/ + +int GUSWAVE_Kill + ( + int handle + ) + + { + VoiceNode *voice; + unsigned flags; + + flags = DisableInterrupts(); + + voice = GUSWAVE_GetVoice( handle ); + + if ( voice == NULL ) + { + RestoreInterrupts( flags ); + GUSWAVE_SetErrorCode( GUSWAVE_VoiceNotFound ); + + if ( GUS_Debug ) + { + DB_printf( "Could not find voice to kill.\n" ); + } + + return( GUSWAVE_Warning ); + } + + RestoreInterrupts( flags ); + + if ( !GUS_Debug ) + { + if ( voice->Active ) + { + gf1_stop_digital( voice->GF1voice ); + } + } + else + { + DB_printf( "Kill - GUS Voice %d ", voice->GF1voice ); + if ( voice->Active ) + { + DB_printf( "active\n" ); + gf1_stop_digital( voice->GF1voice ); + } + else + { + DB_printf( "inactive\n" ); + } + } + +// RestoreInterrupts( flags ); + + return( GUSWAVE_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: GUSWAVE_KillAllVoices + + Stops output of all currently active voices. +---------------------------------------------------------------------*/ + +int GUSWAVE_KillAllVoices + ( + void + ) + + { + int i; + unsigned flags; + + if ( !GUSWAVE_Installed ) + { + return( GUSWAVE_Ok ); + } + + if ( GUS_Debug ) + { + DB_printf( "Kill All Voices\n" ); + } + + flags = DisableInterrupts(); + + // Remove all the voices from the list + for( i = 0; i < GUSWAVE_MaxVoices; i++ ) + { + if ( GUSWAVE_Voices[ i ].Active ) + { +// GUSWAVE_Kill( GUSWAVE_Voices[ i ].handle ); + + gf1_stop_digital( GUSWAVE_Voices[ i ].GF1voice ); + } + } + + for( i = 0; i < MAX_VOICES; i++ ) + { + VoiceStatus[ i ].playing = FALSE; + VoiceStatus[ i ].Voice = NULL; + } + + VoicePool.start = NULL; + VoicePool.end = NULL; + VoiceList.start = NULL; + VoiceList.end = NULL; + + for( i = 0; i < GUSWAVE_MaxVoices; i++ ) + { + GUSWAVE_Voices[ i ].Active = FALSE; + if ( GUSWAVE_Voices[ i ].mem != NULL ) + { + LL_AddToTail( VoiceNode, &VoicePool, &GUSWAVE_Voices[ i ] ); + } + } + + RestoreInterrupts( flags ); + + return( GUSWAVE_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: GUSWAVE_SetPitch + + Sets the pitch for the voice associated with the specified handle. +---------------------------------------------------------------------*/ + +int GUSWAVE_SetPitch + ( + int handle, + int pitchoffset + ) + + { + VoiceNode *voice; + unsigned flags; + + flags = DisableInterrupts(); + + voice = GUSWAVE_GetVoice( handle ); + + if ( voice == NULL ) + { + RestoreInterrupts( flags ); + + GUSWAVE_SetErrorCode( GUSWAVE_VoiceNotFound ); + return( GUSWAVE_Warning ); + } + + if ( voice->Active ) + { + voice->PitchScale = PITCH_GetScale( pitchoffset ); + voice->RateScale = ( voice->SamplingRate * voice->PitchScale ) >> 16; + gf1_dig_set_freq( voice->GF1voice, voice->RateScale ); + } + + RestoreInterrupts( flags ); + + return( GUSWAVE_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: GUSWAVE_SetPan3D + + Sets the pan position of the voice with the specified handle. +---------------------------------------------------------------------*/ + +int GUSWAVE_SetPan3D + ( + int handle, + int angle, + int distance + ) + + { + VoiceNode *voice; + int pan; + unsigned flags; + + flags = DisableInterrupts(); + + voice = GUSWAVE_GetVoice( handle ); + + if ( voice == NULL ) + { + RestoreInterrupts( flags ); + + GUSWAVE_SetErrorCode( GUSWAVE_VoiceNotFound ); + return( GUSWAVE_Warning ); + } + + if ( voice->Active ) + { + angle &= 31; + + pan = GUSWAVE_PanTable[ angle ]; + if ( GUSWAVE_SwapLeftRight ) + { + pan = 15 - pan; + } + + distance = max( 0, distance ); + distance = min( 255, distance ); + + voice->Volume = 255 - distance; + voice->Pan = pan; + + gf1_dig_set_pan( voice->GF1voice, pan ); + gf1_dig_set_vol( voice->GF1voice, GUSWAVE_Volume - distance * 4 ); + } + + RestoreInterrupts( flags ); + + return( GUSWAVE_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: GUSWAVE_SetVolume + + Sets the total volume of the digitized sounds. +---------------------------------------------------------------------*/ + +void GUSWAVE_SetVolume + ( + int volume + ) + + { + int i; + + volume = max( 0, volume ); + volume = min( 255, volume ); + GUSWAVE_Volume = MAX_VOLUME - ( 255 - volume ) * 4; + + for( i = 0; i < GUSWAVE_MaxVoices; i++ ) + { + if ( GUSWAVE_Voices[ i ].Active ) + { + gf1_dig_set_vol( GUSWAVE_Voices[ i ].GF1voice, + GUSWAVE_Volume - ( 255 - GUSWAVE_Voices[ i ].Volume ) * 4 ); + } + } + } + + +/*--------------------------------------------------------------------- + Function: GUSWAVE_GetVolume + + Returns the total volume of the digitized sounds. +---------------------------------------------------------------------*/ + +int GUSWAVE_GetVolume + ( + void + ) + + { + return( 255 - ( ( MAX_VOLUME - GUSWAVE_Volume ) / 4 ) ); + } + + +/*--------------------------------------------------------------------- + Function: GUSWAVE_AllocVoice + + Retrieve an inactive or lower priority voice for output. +---------------------------------------------------------------------*/ + +static VoiceNode *GUSWAVE_AllocVoice + ( + int priority + ) + + { + VoiceNode *voice; + VoiceNode *node; + unsigned flags; + + // If we don't have any free voices, check if we have a higher + // priority than one that is playing. + if ( GUSWAVE_VoicesPlaying() >= GUSWAVE_MaxVoices ) + { + flags = DisableInterrupts(); + + node = VoiceList.start; + voice = node; + while( node != NULL ) + { + if ( node->priority < voice->priority ) + { + voice = node; + } + + node = node->next; + } + + RestoreInterrupts( flags ); + + if ( priority >= voice->priority ) + { + GUSWAVE_Kill( voice->handle ); + } + } + + // Check if any voices are in the voice pool + flags = DisableInterrupts(); + + voice = VoicePool.start; + if ( voice != NULL ) + { + LL_Remove( VoiceNode, &VoicePool, voice ); + } + + RestoreInterrupts( flags ); + + if ( voice != NULL ) + { + do + { + GUSWAVE_VoiceHandle++; + if ( GUSWAVE_VoiceHandle < GUSWAVE_MinVoiceHandle ) + { + GUSWAVE_VoiceHandle = GUSWAVE_MinVoiceHandle; + } + } + while( GUSWAVE_VoicePlaying( GUSWAVE_VoiceHandle ) ); + + voice->handle = GUSWAVE_VoiceHandle; + } + + return( voice ); + } + + +/*--------------------------------------------------------------------- + Function: GUSWAVE_VoiceAvailable + + Checks if a voice can be play at the specified priority. +---------------------------------------------------------------------*/ + +int GUSWAVE_VoiceAvailable + ( + int priority + ) + + { + VoiceNode *voice; + VoiceNode *node; + unsigned flags; + + if ( GUSWAVE_VoicesPlaying() < GUSWAVE_MaxVoices ) + { + return( TRUE ); + } + + flags = DisableInterrupts(); + + node = VoiceList.start; + voice = node; + while( node != NULL ) + { + if ( node->priority < voice->priority ) + { + voice = node; + } + + node = node->next; + } + + RestoreInterrupts( flags ); + + if ( priority >= voice->priority ) + { + return( TRUE ); + } + + return( FALSE ); + } + + +/*--------------------------------------------------------------------- + Function: GUSWAVE_GetNextVOCBlock + + Interperate the information of a VOC format sound file. +---------------------------------------------------------------------*/ + +playbackstatus GUSWAVE_GetNextVOCBlock + ( + VoiceNode *voice + ) + + { + unsigned char *ptr; + int blocktype; + int lastblocktype; + unsigned long blocklength; + unsigned long samplespeed; + unsigned int tc; + int packtype; + int voicemode; + int done; + unsigned BitsPerSample; + unsigned Channels; + unsigned Format; + + if ( voice->BlockLength > 0 ) + { + voice->sound += MAX_BLOCK_LENGTH; + voice->length = min( voice->BlockLength, MAX_BLOCK_LENGTH ); + voice->BlockLength -= voice->length; + return( KeepPlaying ); + } + + ptr = ( unsigned char * )voice->NextBlock; + + voice->Playing = TRUE; + + voicemode = 0; + lastblocktype = 0; + packtype = 0; + + done = FALSE; + while( !done ) + { + // Stop playing if we get a NULL pointer + if ( ptr == NULL ) + { + voice->Playing = FALSE; + done = TRUE; + break; + } + + blocktype = ( int )*ptr; + blocklength = ( *( unsigned long * )( ptr + 1 ) ) & 0x00ffffff; + ptr += 4; + + switch( blocktype ) + { + case 0 : + // End of data + voice->Playing = FALSE; + done = TRUE; + break; + + case 1 : + // Sound data block + voice->bits = 8; + if ( lastblocktype != 8 ) + { + tc = ( unsigned int )*ptr << 8; + packtype = *( ptr + 1 ); + } + + ptr += 2; + blocklength -= 2; + + samplespeed = 256000000L / ( 65536 - tc ); + + // Skip packed or stereo data + if ( ( packtype != 0 ) || ( voicemode != 0 ) ) + { + ptr += blocklength; + } + else + { + done = TRUE; + } + voicemode = 0; + break; + + case 2 : + // Sound continuation block + samplespeed = voice->SamplingRate; + done = TRUE; + break; + + case 3 : + // Silence + // Not implimented. + ptr += blocklength; + break; + + case 4 : + // Marker + // Not implimented. + ptr += blocklength; + break; + + case 5 : + // ASCII string + // Not implimented. + ptr += blocklength; + break; + + case 6 : + // Repeat begin + voice->LoopCount = *( unsigned short * )ptr; + ptr += blocklength; + voice->LoopStart = ptr; + break; + + case 7 : + // Repeat end + ptr += blocklength; + if ( lastblocktype == 6 ) + { + voice->LoopCount = 0; + } + else + { + if ( ( voice->LoopCount > 0 ) && ( voice->LoopStart != NULL ) ) + { + ptr = voice->LoopStart; + if ( voice->LoopCount < 0xffff ) + { + voice->LoopCount--; + if ( voice->LoopCount == 0 ) + { + voice->LoopStart = NULL; + } + } + } + } + break; + + case 8 : + // Extended block + voice->bits = 8; + tc = *( unsigned short * )ptr; + packtype = *( ptr + 2 ); + voicemode = *( ptr + 3 ); + ptr += blocklength; + break; + + case 9 : + // New sound data block + samplespeed = *( unsigned long * )ptr; + BitsPerSample = ( unsigned )*( ptr + 4 ); + Channels = ( unsigned )*( ptr + 5 ); + Format = ( unsigned )*( unsigned short * )( ptr + 6 ); + + if ( ( BitsPerSample == 8 ) && ( Channels == 1 ) && + ( Format == VOC_8BIT ) ) + { + ptr += 12; + blocklength -= 12; + voice->bits = 8; + done = TRUE; + } + else if ( ( BitsPerSample == 16 ) && ( Channels == 1 ) && + ( Format == VOC_16BIT ) ) + { + ptr += 12; + blocklength -= 12; + voice->bits = 16; + done = TRUE; + } + else + { + ptr += blocklength; + } + break; + + default : + // Unknown data. Probably not a VOC file. + voice->Playing = FALSE; + done = TRUE; + break; + } + + lastblocktype = blocktype; + } + + if ( voice->Playing ) + { + voice->NextBlock = ptr + blocklength; + voice->sound = ptr; + + voice->SamplingRate = samplespeed; + voice->RateScale = ( voice->SamplingRate * voice->PitchScale ) >> 16; + + voice->length = min( blocklength, MAX_BLOCK_LENGTH ); + voice->BlockLength = blocklength - voice->length; + + return( KeepPlaying ); + } + + return( SoundDone ); + } + + +/*--------------------------------------------------------------------- + Function: GUSWAVE_GetNextWAVBlock + + Controls playback of demand fed data. +---------------------------------------------------------------------*/ + +playbackstatus GUSWAVE_GetNextWAVBlock + ( + VoiceNode *voice + ) + + { + if ( voice->BlockLength <= 0 ) + { + if ( voice->LoopStart == NULL ) + { + voice->Playing = FALSE; + return( SoundDone ); + } + + voice->BlockLength = voice->LoopSize; + voice->NextBlock = voice->LoopStart; + voice->length = 0; + } + + voice->sound = voice->NextBlock; + voice->length = min( voice->BlockLength, 0x8000 ); + voice->NextBlock += voice->length; + voice->BlockLength -= voice->length; + + return( KeepPlaying ); + } + + +/*--------------------------------------------------------------------- + Function: GUSWAVE_GetNextDemandFeedBlock + + Controls playback of demand fed data. +---------------------------------------------------------------------*/ + +playbackstatus GUSWAVE_GetNextDemandFeedBlock + ( + VoiceNode *voice + ) + + { + if ( voice->BlockLength > 0 ) + { + voice->sound += voice->length; + voice->length = min( voice->BlockLength, 0x8000 ); + voice->BlockLength -= voice->length; + + return( KeepPlaying ); + } + + if ( voice->DemandFeed == NULL ) + { + return( SoundDone ); + } + + ( voice->DemandFeed )( &voice->sound, &voice->BlockLength ); +// voice->sound = GUS_Silence16; +// voice->BlockLength = 256; + + voice->length = min( voice->BlockLength, 0x8000 ); + voice->BlockLength -= voice->length; + + if ( ( voice->length > 0 ) && ( voice->sound != NULL ) ) + { + return( KeepPlaying ); + } + return( NoMoreData ); + } + + +/*--------------------------------------------------------------------- + Function: GUSWAVE_Play + + Begins playback of digitized sound. +---------------------------------------------------------------------*/ + +int GUSWAVE_Play + ( + VoiceNode *voice, + int angle, + int volume, + int channels + ) + + { + int VoiceNumber; + int type; + int pan; + unsigned flags; + int ( *servicefunction )( int reason, int voice, unsigned char **buf, unsigned long *size ); + + type = 0; + if ( channels != 1 ) + { + type |= TYPE_STEREO; + } + + if ( voice->bits == 8 ) + { + type |= TYPE_8BIT; + type |= TYPE_INVERT_MSB; + } + + voice->GF1voice = -1; + + angle &= 31; + pan = GUSWAVE_PanTable[ angle ]; + if ( GUSWAVE_SwapLeftRight ) + { + pan = 15 - pan; + } + + voice->Pan = pan; + + volume = max( 0, volume ); + volume = min( 255, volume ); + voice->Volume = volume; + + if ( !GUS_Debug ) + { + servicefunction = GUSWAVE_CallBack; + } + else + { + servicefunction = GUSWAVE_DebugCallBack; + } + + VoiceNumber = gf1_play_digital( 0, voice->sound, voice->length, + voice->mem, GUSWAVE_Volume - ( 255 - volume ) * 4, pan, + voice->RateScale, type, &GUS_HoldBuffer, servicefunction ); + + if ( VoiceNumber == NO_MORE_VOICES ) + { + if ( GUS_Debug ) + { + DB_printf( "Out of voices.\n" ); + } + + flags = DisableInterrupts(); + LL_AddToTail( VoiceNode, &VoicePool, voice ); + RestoreInterrupts( flags ); + + GUSWAVE_SetErrorCode( GUSWAVE_NoVoices ); + return( GUSWAVE_Warning ); + } + + flags = DisableInterrupts(); + voice->GF1voice = VoiceNumber; + voice->Active = TRUE; + LL_AddToTail( VoiceNode, &VoiceList, voice ); + VoiceStatus[ VoiceNumber ].playing = TRUE; + VoiceStatus[ VoiceNumber ].Voice = voice; + + if ( GUS_Debug ) + { + DB_printf( "GUS voice %d playing\n", VoiceNumber ); + } + + RestoreInterrupts( flags ); + + return( voice->handle ); + } + + +/*--------------------------------------------------------------------- + Function: GUSWAVE_PlayVOC + + Begins playback of digitized sound. +---------------------------------------------------------------------*/ + +int GUSWAVE_PlayVOC + ( + char *sample, + int pitchoffset, + int angle, + int volume, + int priority, + unsigned long callbackval + ) + + { + int handle; + int status; + playbackstatus soundstatus; + VoiceNode *voice; + unsigned flags; + + // Make sure it's a valid VOC file. + status = strncmp( sample, "Creative Voice File", 19 ); + if ( status != 0 ) + { + // Tell multivoc that we had a bad VOC file + MV_ErrorCode = MV_InvalidVOCFile; + + GUSWAVE_SetErrorCode( GUSWAVE_InvalidVOCFile ); + return( GUSWAVE_Error ); + } + + // Request a voice from the voice pool + voice = GUSWAVE_AllocVoice( priority ); + if ( voice == NULL ) + { + if ( GUS_Debug ) + { + DB_printf( "No more voices. Skipping sound.\n" ); + } + GUSWAVE_SetErrorCode( GUSWAVE_NoVoices ); + return( GUSWAVE_Warning ); + } + + voice->NextBlock = sample + *( unsigned short int * )( sample + 0x14 ); + voice->LoopStart = NULL; + voice->LoopCount = 0; + voice->BlockLength = 0; + voice->PitchScale = PITCH_GetScale( pitchoffset ); + voice->wavetype = VOC; + voice->bits = 8; + voice->GetSound = GUSWAVE_GetNextVOCBlock; + voice->length = 0; + voice->next = NULL; + voice->prev = NULL; + voice->priority = priority; + voice->callbackval = callbackval; + + soundstatus = GUSWAVE_GetNextVOCBlock( voice ); + if ( soundstatus == SoundDone ) + { + flags = DisableInterrupts(); + LL_AddToTail( VoiceNode, &VoicePool, voice ); + RestoreInterrupts( flags ); + + if ( GUS_Debug ) + { + DB_printf( "Voice ended before playback.\n" ); + } + + // Tell multivoc that we had a bad VOC file + MV_ErrorCode = MV_InvalidVOCFile; + + GUSWAVE_SetErrorCode( GUSWAVE_InvalidVOCFile ); + return( GUSWAVE_Error ); + } + + handle = GUSWAVE_Play( voice, angle, volume, 1 ); + return( handle ); + } + + +/*--------------------------------------------------------------------- + Function: GUSWAVE_PlayWAV + + Begins playback of digitized sound. +---------------------------------------------------------------------*/ + +int GUSWAVE_PlayWAV + ( + char *sample, + int pitchoffset, + int angle, + int volume, + int priority, + unsigned long callbackval + ) + + { + VoiceNode *voice; + int handle; + int channels; + int bits; + int length; + riff_header *riff; + format_header *format; + data_header *data; + + riff = ( riff_header * )sample; + + if ( ( strncmp( riff->RIFF, "RIFF", 4 ) != 0 ) || + ( strncmp( riff->WAVE, "WAVE", 4 ) != 0 ) || + ( strncmp( riff->fmt, "fmt ", 4) != 0 ) ) + { + GUSWAVE_SetErrorCode( GUSWAVE_InvalidWAVFile ); + return( GUSWAVE_Error ); + } + + format = ( format_header * )( riff + 1 ); + data = ( data_header * )( ( ( char * )format ) + riff->format_size ); + + if ( format->wFormatTag != 1 ) + { + GUSWAVE_SetErrorCode( GUSWAVE_InvalidWAVFile ); + return( GUSWAVE_Error ); + } + + channels = format->nChannels; + if ( ( channels != 1 ) && ( channels != 2 ) ) + { + GUSWAVE_SetErrorCode( GUSWAVE_InvalidWAVFile ); + return( GUSWAVE_Error ); + } + + bits = format->nBitsPerSample; + if ( ( bits != 8 ) && ( bits != 16 ) ) + { + GUSWAVE_SetErrorCode( GUSWAVE_InvalidWAVFile ); + return( GUSWAVE_Error ); + } + + if ( strncmp( data->DATA, "data", 4 ) != 0 ) + { + GUSWAVE_SetErrorCode( GUSWAVE_InvalidWAVFile ); + return( GUSWAVE_Error ); + } + + // Request a voice from the voice pool + voice = GUSWAVE_AllocVoice( priority ); + if ( voice == NULL ) + { + if ( GUS_Debug ) + { + DB_printf( "No more voices. Skipping sound.\n" ); + } + GUSWAVE_SetErrorCode( GUSWAVE_NoVoices ); + return( GUSWAVE_Warning ); + } + + voice->wavetype = WAV; + voice->bits = bits; + voice->GetSound = GUSWAVE_GetNextWAVBlock; + + length = data->size; + + voice->Playing = TRUE; + voice->DemandFeed = NULL; + voice->LoopStart = NULL; + voice->LoopCount = 0; + voice->length = min( length, 0x8000 ); + voice->BlockLength = length - voice->length;// min( loopend + 1, data->size ); + voice->sound = ( char * )( data + 1 ); + voice->NextBlock = voice->sound + voice->length; + voice->next = NULL; + voice->prev = NULL; + voice->priority = priority; + voice->callbackval = callbackval; + voice->LoopStart = NULL;// voice->NextBlock + loopstart; + voice->LoopEnd = NULL;//voice->NextBlock + min( loopend, data->size - 1 ); + voice->LoopSize = 0;//( voice->LoopEnd - voice->LoopStart ) + 1; + voice->PitchScale = PITCH_GetScale( pitchoffset ); + voice->SamplingRate = format->nSamplesPerSec; + voice->RateScale = ( voice->SamplingRate * voice->PitchScale ) >> 16; + + handle = GUSWAVE_Play( voice, angle, volume, channels ); + + return( handle ); + } + + +/*--------------------------------------------------------------------- + Function: GUSWAVE_StartDemandFeedPlayback + + Begins playback of digitized sound. +---------------------------------------------------------------------*/ + +int GUSWAVE_StartDemandFeedPlayback + ( + void ( *function )( char **ptr, unsigned long *length ), + int channels, + int bits, + int rate, + int pitchoffset, + int angle, + int volume, + int priority, + unsigned long callbackval + ) + + { + VoiceNode *voice; + int handle; + + // Request a voice from the voice pool + voice = GUSWAVE_AllocVoice( priority ); + if ( voice == NULL ) + { + if ( GUS_Debug ) + { + DB_printf( "No more voices. Skipping sound.\n" ); + } + GUSWAVE_SetErrorCode( GUSWAVE_NoVoices ); + return( GUSWAVE_Warning ); + } + + voice->wavetype = DemandFeed; + voice->bits = bits; + voice->GetSound = GUSWAVE_GetNextDemandFeedBlock; + voice->Playing = TRUE; + voice->DemandFeed = function; + voice->LoopStart = NULL; + voice->LoopCount = 0; + voice->BlockLength = 0; + voice->length = 256; + voice->sound = ( bits == 8 ) ? GUS_Silence8 : ( char * )GUS_Silence16; + voice->NextBlock = NULL; + voice->next = NULL; + voice->prev = NULL; + voice->priority = priority; + voice->callbackval = callbackval; + voice->PitchScale = PITCH_GetScale( pitchoffset ); + voice->SamplingRate = rate; + voice->RateScale = ( voice->SamplingRate * voice->PitchScale ) >> 16; + + handle = GUSWAVE_Play( voice, angle, volume, channels ); + + return( handle ); + } + + +/*--------------------------------------------------------------------- + Function: GUSWAVE_SetReverseStereo + + Set the orientation of the left and right channels. +---------------------------------------------------------------------*/ + +void GUSWAVE_SetReverseStereo + ( + int setting + ) + + { + GUSWAVE_SwapLeftRight = setting; + } + + +/*--------------------------------------------------------------------- + Function: GUSWAVE_GetReverseStereo + + Returns the orientation of the left and right channels. +---------------------------------------------------------------------*/ + +int GUSWAVE_GetReverseStereo + ( + void + ) + + { + return( GUSWAVE_SwapLeftRight ); + } + + +/*--------------------------------------------------------------------- + Function: GUSWAVE_InitVoices + + Begins playback of digitized sound. +---------------------------------------------------------------------*/ + +static int GUSWAVE_InitVoices + ( + void + ) + + { + int i; + + for( i = 0; i < MAX_VOICES; i++ ) + { + VoiceStatus[ i ].playing = FALSE; + VoiceStatus[ i ].Voice = NULL; + } + + VoicePool.start = NULL; + VoicePool.end = NULL; + VoiceList.start = NULL; + VoiceList.end = NULL; + + for( i = 0; i < VOICES; i++ ) + { + GUSWAVE_Voices[ i ].num = -1; + GUSWAVE_Voices[ i ].Active = FALSE; + GUSWAVE_Voices[ i ].GF1voice = -1; + GUSWAVE_Voices[ i ].mem = NULL; + } + + for( i = 0; i < VOICES; i++ ) + { + GUSWAVE_Voices[ i ].num = i; + GUSWAVE_Voices[ i ].Active = FALSE; + GUSWAVE_Voices[ i ].GF1voice = 0; + + GUSWAVE_Voices[ i ].mem = gf1_malloc( GF1BSIZE ); + if ( GUSWAVE_Voices[ i ].mem == NULL ) + { + GUSWAVE_MaxVoices = i; + if ( i < 1 ) + { + if ( GUSMIDI_Installed ) + { + GUSWAVE_SetErrorCode( GUSWAVE_UltraNoMemMIDI ); + } + else + { + GUSWAVE_SetErrorCode( GUSWAVE_UltraNoMem ); + } + return( GUSWAVE_Error ); + } + + break; + } + + LL_AddToTail( VoiceNode, &VoicePool, &GUSWAVE_Voices[ i ] ); + } + + return( GUSWAVE_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: GUSWAVE_SetCallBack + + Set the function to call when a voice stops. +---------------------------------------------------------------------*/ + +void GUSWAVE_SetCallBack + ( + void ( *function )( unsigned long ) + ) + + { + GUSWAVE_CallBackFunc = function; + } + + +/*--------------------------------------------------------------------- + Function: GUSWAVE_Init + + Initializes the Gravis Ultrasound for digitized sound playback. +---------------------------------------------------------------------*/ + +int GUSWAVE_Init + ( + int numvoices + ) + + { + int status; + + if ( GUSWAVE_Installed ) + { + GUSWAVE_Shutdown(); + } + + GUSWAVE_SetErrorCode( GUSWAVE_Ok ); + + status = GUS_Init(); + if ( status != GUS_Ok ) + { + GUSWAVE_SetErrorCode( GUSWAVE_GUSError ); + return( GUSWAVE_Error ); + } + + GUS_Debug = USER_CheckParameter( "DEBUGGUS" ); + + GUSWAVE_MaxVoices = min( numvoices, VOICES ); + GUSWAVE_MaxVoices = max( GUSWAVE_MaxVoices, 0 ); + + status = GUSWAVE_InitVoices(); + if ( status != GUSWAVE_Ok ) + { + GUS_Shutdown(); + return( status ); + } + + GUSWAVE_SetReverseStereo( FALSE ); + + GUSWAVE_CallBackFunc = NULL; + GUSWAVE_Installed = TRUE; + + return( GUSWAVE_Ok ); + } diff --git a/audiolib/guswave.h b/audiolib/guswave.h new file mode 100755 index 0000000..5d029e4 --- /dev/null +++ b/audiolib/guswave.h @@ -0,0 +1,75 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: GUSWAVE.H + + author: James R. Dose + date: March 23, 1994 + + Public header for for GUSWAVE.C + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#ifndef __GUSWAVE_H +#define __GUSWAVE_H + +#define GUSWAVE_MinVoiceHandle 1 + +enum GUSWAVE_Errors + { + GUSWAVE_Warning = -2, + GUSWAVE_Error = -1, + GUSWAVE_Ok = 0, + GUSWAVE_GUSError, + GUSWAVE_NotInstalled, + GUSWAVE_NoVoices, + GUSWAVE_UltraNoMem, + GUSWAVE_UltraNoMemMIDI, + GUSWAVE_VoiceNotFound, + GUSWAVE_InvalidVOCFile, + GUSWAVE_InvalidWAVFile + }; + +char *GUSWAVE_ErrorString( int ErrorNumber ); +int GUSWAVE_VoicePlaying( int handle ); +int GUSWAVE_VoicesPlaying( void ); +int GUSWAVE_Kill( int handle ); +int GUSWAVE_KillAllVoices( void ); +int GUSWAVE_SetPitch( int handle, int pitchoffset ); +int GUSWAVE_SetPan3D( int handle, int angle, int distance ); +void GUSWAVE_SetVolume( int volume ); +int GUSWAVE_GetVolume( void ); +int GUSWAVE_VoiceAvailable( int priority ); +int GUSWAVE_PlayVOC( char *sample, int pitchoffset, int angle, int volume, + int priority, unsigned long callbackval ); +int GUSWAVE_PlayWAV( char *sample, int pitchoffset, int angle, int volume, + int priority, unsigned long callbackval ); +int GUSWAVE_StartDemandFeedPlayback( void ( *function )( char **ptr, unsigned long *length ), + int channels, int bits, int rate, int pitchoffset, int angle, + int volume, int priority, unsigned long callbackval ); +void GUSWAVE_SetCallBack( void ( *function )( unsigned long ) ); +void GUSWAVE_SetReverseStereo( int setting ); +int GUSWAVE_GetReverseStereo( void ); +int GUSWAVE_Init( int numvoices ); +void GUSWAVE_Shutdown( void ); +#pragma aux GUSWAVE_Shutdown frame; + +#endif diff --git a/audiolib/interrup.h b/audiolib/interrup.h new file mode 100755 index 0000000..e8d78b9 --- /dev/null +++ b/audiolib/interrup.h @@ -0,0 +1,50 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: INTERRUP.H + + author: James R. Dose + date: March 31, 1994 + + Inline functions for disabling and restoring the interrupt flag. + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#ifndef __INTERRUPT_H +#define __INTERRUPT_H + +unsigned long DisableInterrupts( void ); +void RestoreInterrupts( unsigned long flags ); + +#ifdef PLAT_DOS +#pragma aux DisableInterrupts = \ + "pushfd", \ + "pop eax", \ + "cli" \ + modify [ eax ]; + +#pragma aux RestoreInterrupts = \ + "push eax", \ + "popfd" \ + parm [ eax ]; +#endif + +#endif diff --git a/audiolib/irq.c b/audiolib/irq.c new file mode 100755 index 0000000..607abd7 --- /dev/null +++ b/audiolib/irq.c @@ -0,0 +1,325 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: IRQ.C + + author: James R. Dose + date: August 26, 1994 + + Low level routines to set and restore IRQ's through DPMI. + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#include +#include +#include "irq.h" + +#define D32RealSeg(P) ( ( ( ( unsigned long )( P ) ) >> 4 ) & 0xFFFF ) +#define D32RealOff(P) ( ( ( unsigned long )( P ) ) & 0xF ) + +typedef struct + { + unsigned long drdi; + unsigned long drsi; + unsigned long drbp; + unsigned long drxx; + unsigned long drbx; + unsigned long drdx; + unsigned long drcx; + unsigned long drax; + + unsigned short drflags; + unsigned short dres; + unsigned short drds; + unsigned short drfs; + unsigned short drgs; + unsigned short drip; + unsigned short drcs; + unsigned short drsp; + unsigned short drss; + } DPMI_REGS; + +static DPMI_REGS rmregs = { 0 }; +static void ( __interrupt __far *IRQ_Callback )( void ) = NULL; + +static char *IRQ_RealModeCode = NULL; + +static unsigned short IRQ_CallBackSegment; +static unsigned short IRQ_CallBackOffset; +static unsigned short IRQ_RealModeSegment; +static unsigned short IRQ_RealModeOffset; +static unsigned long IRQ_ProtectedModeOffset; +static unsigned short IRQ_ProtectedModeSelector; + +static union REGS Regs; +static struct SREGS SegRegs; + +static void *D32DosMemAlloc + ( + unsigned long size + ) + + { + // DPMI allocate DOS memory + Regs.x.eax = 0x0100; + + // Number of paragraphs requested + Regs.x.ebx = ( size + 15 ) >> 4; + + int386( 0x31, &Regs, &Regs ); + + if ( Regs.x.cflag != 0 ) + { + // Failed + return ( ( unsigned long )0 ); + } + + return( ( void * )( ( Regs.x.eax & 0xFFFF ) << 4 ) ); + } + +// Intermediary function: DPMI calls this, making it +// easier to write in C +// handle 16-bit incoming stack + +void fixebp + ( + void + ); + +#pragma aux fixebp = \ + "mov bx, ss" \ + "lar ebx, ebx" \ + "bt ebx, 22" \ + "jc bigstk" \ + "movzx esp, sp" \ + "mov ebp, esp" \ + "bigstk:" \ +modify exact [ ebx ]; + +#pragma aux rmcallback parm []; + +void rmcallback + ( + unsigned short _far *stkp + ) + + { + // "Pop" the real mode return frame so we + // can resume where we left off + rmregs.drip = *stkp++; + rmregs.drcs = *stkp++; + + rmregs.drsp = FP_OFF(stkp); + + // Call protected-mode handler + IRQ_Callback(); + } + +static void _interrupt _cdecl callback_x + ( + // regs pushed in this order by prologue + + int rgs, + int rfs, + int res, + int rds, + int rdi, + int rsi, + int rbp, + int rsp, + int rbx, + int rdx, + int rcx, + int rax + ) + + { +// unsigned short _far *stkp; +// return; + + fixebp(); + rmcallback (MK_FP(rds, rsi)); + } + +/* +static void _interrupt _cdecl callback_x + ( + // regs pushed in this order by prologue + + int rgs, + int rfs, + int res, + int rds, + int rdi, + int rsi, + int rbp, + int rsp, + int rbx, + int rdx, + int rcx, + int rax + ) + + { + unsigned short _far *stkp; + + fixebp(); + stkp = MK_FP(rds, rsi); + + // "Pop" the real mode return frame so we + // can resume where we left off + rmregs.drip = *stkp++; + rmregs.drcs = *stkp++; + + rmregs.drsp = FP_OFF(stkp); + + // Call protected-mode handler + IRQ_Callback(); + } +*/ + + +int IRQ_SetVector + ( + int vector, + void ( __interrupt __far *function )( void ) + ) + + { + void far *fp; + + IRQ_Callback = function; + + // Save the starting real-mode and protected-mode handler addresses + + // DPMI get protected mode vector */ + Regs.w.ax = 0x0204; + Regs.w.bx = vector; + int386( 0x31, &Regs, &Regs ); + IRQ_ProtectedModeSelector = Regs.w.cx; + IRQ_ProtectedModeOffset = Regs.x.edx; + + // DPMI get real mode vector + Regs.w.ax = 0x0200; + Regs.w.bx = vector; + int386( 0x31, &Regs, &Regs ); + IRQ_RealModeSegment = Regs.w.cx; + IRQ_RealModeOffset = Regs.w.dx; + + // Set up callback + // DPMI allocate real mode callback + Regs.w.ax = 0x0303; + fp = ( void far * )callback_x; + SegRegs.ds = FP_SEG( fp ); + Regs.x.esi = FP_OFF( fp ); + fp = ( void _far * )&rmregs; + SegRegs.es = FP_SEG( fp ); + Regs.x.edi = FP_OFF( fp ); + int386x( 0x31, &Regs, &Regs, &SegRegs ); + + IRQ_CallBackSegment = Regs.w.cx; + IRQ_CallBackOffset = Regs.w.dx; + + if ( Regs.x.cflag != 0 ) + { + return( IRQ_Error ); + } + + if ( IRQ_RealModeCode == NULL ) + { + // Allocate 6 bytes of low memory for real mode interrupt handler + IRQ_RealModeCode = D32DosMemAlloc( 6 ); + if ( IRQ_RealModeCode == NULL ) + { + // Free callback + Regs.w.ax = 0x304; + Regs.w.cx = IRQ_CallBackSegment; + Regs.w.dx = IRQ_CallBackOffset; + int386x( 0x31, &Regs, &Regs, &SegRegs ); + + return( IRQ_Error ); + } + } + + // Poke code (to call callback) into real mode handler + + // CALL FAR PTR (callback) + IRQ_RealModeCode[ 0 ] = '\x9A'; + *( ( unsigned short * )&IRQ_RealModeCode[ 1 ] ) = IRQ_CallBackOffset; + *( ( unsigned short * )&IRQ_RealModeCode[ 3 ] ) = IRQ_CallBackSegment; + + // IRET + IRQ_RealModeCode[ 5 ] = '\xCF'; + + // Install protected mode handler + // DPMI set protected mode vector + Regs.w.ax = 0x0205; + Regs.w.bx = vector; + fp = function; + + Regs.w.cx = FP_SEG( fp ); + Regs.x.edx = FP_OFF( fp ); + int386( 0x31, &Regs, &Regs ); + + // Install callback address as real mode handler + // DPMI set real mode vector + Regs.w.ax = 0x0201; + Regs.w.bx = vector; + Regs.w.cx = D32RealSeg( IRQ_RealModeCode ); + Regs.w.dx = D32RealOff( IRQ_RealModeCode ); + int386( 0x31, &Regs, &Regs ); + + return( IRQ_Ok ); + } + +int IRQ_RestoreVector + ( + int vector + ) + + { + // Restore original interrupt handlers + // DPMI set real mode vector + Regs.w.ax = 0x0201; + Regs.w.bx = vector; + Regs.w.cx = IRQ_RealModeSegment; + Regs.w.dx = IRQ_RealModeOffset; + int386( 0x31, &Regs, &Regs ); + + Regs.w.ax = 0x0205; + Regs.w.bx = vector; + Regs.w.cx = IRQ_ProtectedModeSelector; + Regs.x.edx = IRQ_ProtectedModeOffset; + int386( 0x31, &Regs, &Regs ); + + // Free callback + Regs.w.ax = 0x304; + Regs.w.cx = IRQ_CallBackSegment; + Regs.w.dx = IRQ_CallBackOffset; + int386x( 0x31, &Regs, &Regs, &SegRegs ); + + if ( Regs.x.cflag ) + { + return( IRQ_Error ); + } + + return( IRQ_Ok ); + } diff --git a/audiolib/irq.h b/audiolib/irq.h new file mode 100755 index 0000000..dc505a1 --- /dev/null +++ b/audiolib/irq.h @@ -0,0 +1,54 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: IRQ.H + + author: James R. Dose + date: August 8, 1994 + + Public header for IRQ.C + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#ifndef __IRQ_H +#define __IRQ_H + +enum IRQ_ERRORS + { + IRQ_Warning = -2, + IRQ_Error = -1, + IRQ_Ok = 0, + }; + +#define VALID_IRQ( irq ) ( ( ( irq ) >= 0 ) && ( ( irq ) <= 15 ) ) + +int IRQ_SetVector + ( + int vector, + void ( __interrupt *function )( void ) + ); +int IRQ_RestoreVector + ( + int vector + ); + + +#endif diff --git a/audiolib/leetimbr.c b/audiolib/leetimbr.c new file mode 100755 index 0000000..13f8163 --- /dev/null +++ b/audiolib/leetimbr.c @@ -0,0 +1,290 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +typedef struct + { + unsigned char SAVEK[ 2 ]; + unsigned char Level[ 2 ]; + unsigned char Env1[ 2 ]; + unsigned char Env2[ 2 ]; + unsigned char Wave[ 2 ]; + unsigned char Feedback; + signed char Transpose; + signed char Velocity; + } TIMBRE; + +TIMBRE ADLIB_TimbreBank[ 256 ] = + { + { { 33, 49 }, { 79, 0 }, { 242, 210 }, { 82, 115 }, { 0, 0 }, 6, 0 }, + { { 19, 17 }, { 198, 10 }, { 242, 241 }, { 245, 245 }, { 1, 0 }, 0, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 3, 18 }, { 48, 16 }, { 246, 242 }, { 25, 244 }, { 0, 0 }, 15, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 24, 129 }, { 98, 0 }, { 243, 242 }, { 230, 246 }, { 0, 0 }, 0, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 23, 2 }, { 79, 16 }, { 242, 242 }, { 96, 114 }, { 0, 0 }, 8, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 178, 176 }, { 192, 134 }, { 159, 148 }, { 6, 15 }, { 1, 1 }, 9, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 178, 176 }, { 192, 128 }, { 159, 148 }, { 6, 15 }, { 1, 1 }, 9, 0 }, + { { 130, 128 }, { 192, 134 }, { 145, 145 }, { 246, 246 }, { 1, 1 }, 9, 0 }, + { { 36, 49 }, { 79, 27 }, { 242, 82 }, { 11, 11 }, { 0, 0 }, 14, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 35, 33 }, { 72, 0 }, { 149, 132 }, { 25, 25 }, { 1, 0 }, 8, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 19, 49 }, { 150, 128 }, { 254, 242 }, { 33, 148 }, { 0, 0 }, 10, 0 }, + { { 1, 17 }, { 77, 0 }, { 242, 245 }, { 83, 116 }, { 1, 1 }, 8, 0 }, + { { 33, 40 }, { 1, 9 }, { 148, 148 }, { 25, 9 }, { 0, 0 }, 6, 0 }, + { { 33, 40 }, { 1, 19 }, { 148, 148 }, { 25, 9 }, { 0, 0 }, 6, 0 }, + { { 36, 194 }, { 138, 3 }, { 250, 145 }, { 111, 248 }, { 0, 0 }, 8, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 33 }, { 26, 0 }, { 241, 246 }, { 207, 72 }, { 0, 0 }, 10, 0 }, + { { 1, 34 }, { 29, 0 }, { 183, 196 }, { 34, 55 }, { 0, 0 }, 14, 0 }, + { { 49, 34 }, { 30, 0 }, { 242, 241 }, { 239, 104 }, { 0, 0 }, 14, 0 }, + { { 49, 34 }, { 30, 0 }, { 242, 245 }, { 239, 120 }, { 0, 0 }, 14, 0 }, + { { 49, 34 }, { 30, 0 }, { 242, 245 }, { 239, 120 }, { 0, 0 }, 14, 0 }, + { { 17, 49 }, { 5, 9 }, { 249, 241 }, { 37, 52 }, { 0, 0 }, 10, 0 }, + { { 17, 49 }, { 5, 0 }, { 249, 241 }, { 37, 52 }, { 0, 0 }, 10, 0 }, + { { 49, 114 }, { 138, 0 }, { 213, 97 }, { 25, 27 }, { 0, 0 }, 12, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 17, 17 }, { 150, 128 }, { 165, 245 }, { 85, 179 }, { 2, 1 }, 12, 0 }, + { { 1, 17 }, { 156, 128 }, { 128, 240 }, { 5, 6 }, { 0, 0 }, 0, 0 }, + { { 17, 17 }, { 150, 128 }, { 165, 245 }, { 85, 179 }, { 2, 1 }, 12, 0 }, + { { 2, 1 }, { 153, 128 }, { 245, 246 }, { 85, 83 }, { 0, 0 }, 0, 0 }, + { { 192, 0 }, { 13, 0 }, { 165, 212 }, { 67, 35 }, { 2, 1 }, 0, 0 }, + { { 33, 32 }, { 88, 0 }, { 194, 97 }, { 227, 22 }, { 1, 3 }, 0, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 34 }, { 22, 0 }, { 176, 179 }, { 129, 44 }, { 0, 1 }, 12, 0 }, + { { 49, 114 }, { 91, 131 }, { 244, 138 }, { 21, 5 }, { 0, 0 }, 0, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 33 }, { 29, 0 }, { 113, 129 }, { 174, 158 }, { 0, 0 }, 14, 0 }, + { { 49, 97 }, { 28, 128 }, { 65, 146 }, { 11, 59 }, { 0, 0 }, 14, 0 }, + { { 49, 241 }, { 28, 0 }, { 65, 146 }, { 11, 27 }, { 0, 0 }, 10, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 33 }, { 155, 0 }, { 97, 127 }, { 106, 10 }, { 0, 0 }, 2, 0 }, + { { 225, 226 }, { 21, 3 }, { 113, 129 }, { 174, 158 }, { 0, 0 }, 14, 0 }, + { { 33, 33 }, { 29, 0 }, { 113, 129 }, { 174, 158 }, { 0, 0 }, 14, 0 }, + { { 33, 33 }, { 77, 0 }, { 84, 166 }, { 60, 28 }, { 0, 0 }, 8, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 50 }, { 79, 0 }, { 113, 82 }, { 83, 76 }, { 0, 0 }, 10, 0 }, + { { 33, 50 }, { 79, 0 }, { 113, 82 }, { 83, 76 }, { 0, 0 }, 10, 0 }, + { { 32, 49 }, { 78, 0 }, { 113, 82 }, { 104, 94 }, { 0, 0 }, 10, 0 }, + { { 33, 33 }, { 75, 0 }, { 170, 143 }, { 22, 10 }, { 1, 0 }, 8, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 50, 97 }, { 154, 130 }, { 81, 162 }, { 27, 59 }, { 0, 0 }, 12, 0 }, + { { 50, 33 }, { 192, 0 }, { 155, 114 }, { 33, 7 }, { 0, 0 }, 4, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 162 }, { 131, 141 }, { 116, 101 }, { 23, 23 }, { 0, 0 }, 7, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 225, 98 }, { 236, 0 }, { 110, 101 }, { 143, 42 }, { 0, 0 }, 14, 0 }, + { { 50, 33 }, { 144, 0 }, { 155, 114 }, { 33, 23 }, { 0, 0 }, 4, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 245, 242 }, { 154, 128 }, { 12, 96 }, { 199, 165 }, { 0, 0 }, 13, 0 }, + { { 98, 161 }, { 147, 0 }, { 119, 118 }, { 7, 7 }, { 0, 0 }, 11, 0 }, + { { 34, 33 }, { 89, 8 }, { 255, 255 }, { 3, 15 }, { 2, 0 }, 0, 0 }, + { { 33, 33 }, { 29, 0 }, { 113, 129 }, { 14, 14 }, { 0, 0 }, 14, 0 }, + { { 34, 33 }, { 70, 128 }, { 134, 100 }, { 85, 24 }, { 0, 0 }, 0, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 113, 114 }, { 93, 0 }, { 84, 106 }, { 1, 3 }, { 0, 0 }, 0, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 0, 17 }, { 13, 128 }, { 241, 80 }, { 255, 255 }, { 0, 0 }, 6, 0 }, + { { 33, 97 }, { 137, 3 }, { 17, 66 }, { 51, 37 }, { 0, 0 }, 10, 0 }, + { { 0, 49 }, { 16, 128 }, { 17, 176 }, { 239, 15 }, { 0, 0 }, 10, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 164, 97 }, { 76, 16 }, { 243, 129 }, { 115, 35 }, { 1, 0 }, 4, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 1, 1 }, { 0, 0 }, { 255, 255 }, { 7, 7 }, { 0, 0 }, 7, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 1, 221 }, { 0, 0 }, { 246, 31 }, { 0, 6 }, { 2, 3 }, 12, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 36 }, + { { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 36 }, + { { 3, 15 }, { 0, 0 }, { 251, 245 }, { 43, 11 }, { 2, 0 }, 15, 36 }, + { { 33, 0 }, { 128, 0 }, { 255, 249 }, { 7, 7 }, { 0, 1 }, 14, 36 }, + { { 240, 229 }, { 192, 0 }, { 255, 251 }, { 255, 240 }, { 3, 0 }, 14, 48 }, + { { 33, 0 }, { 128, 0 }, { 255, 248 }, { 10, 25 }, { 0, 1 }, 14, 36 }, + { { 1, 0 }, { 0, 0 }, { 250, 242 }, { 124, 4 }, { 0, 0 }, 0, 48 }, + { { 12, 18 }, { 0, 0 }, { 246, 251 }, { 8, 71 }, { 0, 2 }, 10, 69 }, + { { 1, 0 }, { 0, 0 }, { 250, 242 }, { 124, 4 }, { 0, 0 }, 0, 52 }, + { { 14, 0 }, { 64, 8 }, { 118, 119 }, { 79, 24 }, { 0, 2 }, 14, 48 }, + { { 1, 0 }, { 0, 0 }, { 250, 242 }, { 124, 4 }, { 0, 0 }, 0, 55 }, + { { 2, 5 }, { 3, 10 }, { 180, 151 }, { 4, 247 }, { 0, 0 }, 14, 57 }, + { { 1, 0 }, { 0, 0 }, { 250, 242 }, { 124, 4 }, { 0, 0 }, 0, 58 }, + { { 1, 0 }, { 0, 0 }, { 250, 242 }, { 124, 4 }, { 0, 0 }, 0, 60 }, + { { 1, 221 }, { 12, 0 }, { 246, 159 }, { 0, 2 }, { 0, 3 }, 12, 62 }, + { { 1, 0 }, { 0, 0 }, { 250, 242 }, { 124, 4 }, { 0, 0 }, 0, 63 }, + { { 12, 18 }, { 0, 0 }, { 246, 203 }, { 2, 67 }, { 0, 2 }, 10, 70 }, + { { 12, 18 }, { 0, 0 }, { 246, 203 }, { 2, 19 }, { 0, 2 }, 10, 70 }, + { { 14, 7 }, { 6, 68 }, { 248, 244 }, { 66, 228 }, { 3, 3 }, 14, 53 }, + { { 14, 0 }, { 64, 8 }, { 150, 183 }, { 79, 24 }, { 0, 2 }, 14, 48 }, + { { 1, 221 }, { 0, 0 }, { 246, 159 }, { 0, 2 }, { 2, 3 }, 12, 84 }, + { { 2, 9 }, { 27, 0 }, { 245, 246 }, { 118, 214 }, { 2, 0 }, 4, 43 }, + { { 0, 223 }, { 9, 0 }, { 246, 147 }, { 0, 67 }, { 0, 2 }, 14, 56 }, + { { 128, 144 }, { 13, 0 }, { 248, 159 }, { 0, 4 }, { 2, 3 }, 14, 24 }, + { { 12, 18 }, { 0, 0 }, { 246, 203 }, { 2, 67 }, { 0, 2 }, 10, 65 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 1, 2 }, { 84, 0 }, { 250, 248 }, { 141, 184 }, { 0, 0 }, 6, 48 }, + { { 1, 2 }, { 84, 0 }, { 250, 248 }, { 141, 184 }, { 0, 0 }, 6, 51 }, + { { 1, 2 }, { 84, 0 }, { 250, 248 }, { 141, 184 }, { 0, 0 }, 6, 54 }, + { { 2, 4 }, { 0, 0 }, { 250, 200 }, { 191, 151 }, { 0, 0 }, 11, 42 }, + { { 2, 4 }, { 0, 0 }, { 250, 200 }, { 191, 151 }, { 0, 0 }, 11, 39 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 14, 0 }, { 64, 8 }, { 118, 119 }, { 79, 24 }, { 0, 2 }, 14, 64 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 128, 17 }, { 0, 0 }, { 255, 111 }, { 6, 22 }, { 3, 0 }, 14, 52 }, + { { 128, 17 }, { 0, 0 }, { 255, 79 }, { 6, 22 }, { 3, 0 }, 14, 52 }, + { { 6, 21 }, { 63, 0 }, { 0, 247 }, { 244, 245 }, { 0, 0 }, 1, 60 }, + { { 6, 21 }, { 63, 0 }, { 0, 247 }, { 244, 245 }, { 0, 0 }, 1, 66 }, + { { 6, 21 }, { 63, 0 }, { 0, 247 }, { 244, 245 }, { 0, 0 }, 1, 59 }, + { { 65, 66 }, { 69, 0 }, { 252, 105 }, { 69, 5 }, { 0, 0 }, 0, 91 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 23, 2 }, { 79, 16 }, { 242, 242 }, { 96, 114 }, { 0, 0 }, 8, 109 }, + { { 14, 0 }, { 64, 8 }, { 118, 119 }, { 79, 24 }, { 0, 2 }, 14, 64 }, + { { 133, 132 }, { 5, 64 }, { 249, 214 }, { 50, 165 }, { 3, 0 }, 14, 79 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 }, + { { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 0 } + }; diff --git a/audiolib/linklist.h b/audiolib/linklist.h new file mode 100755 index 0000000..a0a581f --- /dev/null +++ b/audiolib/linklist.h @@ -0,0 +1,118 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef __linklist_h +#define __linklist_h +#ifdef __cplusplus +extern "C" { +#endif + + +#define NewNode(type) ((type*)SafeMalloc(sizeof(type))) + + +#define LL_CreateNewLinkedList(rootnode,type,next,prev) \ + { \ + (rootnode) = NewNode(type); \ + (rootnode)->prev = (rootnode); \ + (rootnode)->next = (rootnode); \ + } + + + +#define LL_AddNode(rootnode, newnode, next, prev) \ + { \ + (newnode)->next = (rootnode); \ + (newnode)->prev = (rootnode)->prev; \ + (rootnode)->prev->next = (newnode); \ + (rootnode)->prev = (newnode); \ + } + +#define LL_TransferList(oldroot,newroot,next,prev) \ + { \ + if ((oldroot)->prev != (oldroot)) \ + { \ + (oldroot)->prev->next = (newroot); \ + (oldroot)->next->prev = (newroot)->prev; \ + (newroot)->prev->next = (oldroot)->next; \ + (newroot)->prev = (oldroot)->prev; \ + (oldroot)->next = (oldroot); \ + (oldroot)->prev = (oldroot); \ + } \ + } + +#define LL_ReverseList(root,type,next,prev) \ + { \ + type *newend,*trav,*tprev; \ + \ + newend = (root)->next; \ + for(trav = (root)->prev; trav != newend; trav = tprev) \ + { \ + tprev = trav->prev; \ + LL_MoveNode(trav,newend,next,prev); \ + } \ + } + + +#define LL_RemoveNode(node,next,prev) \ + { \ + (node)->prev->next = (node)->next; \ + (node)->next->prev = (node)->prev; \ + (node)->next = (node); \ + (node)->prev = (node); \ + } + + +#define LL_SortedInsertion(rootnode,insertnode,next,prev,type,sortparm) \ + { \ + type *hoya; \ + \ + hoya = (rootnode)->next; \ + while((hoya != (rootnode)) && ((insertnode)->sortparm > hoya->sortparm)) \ + { \ + hoya = hoya->next; \ + } \ + LL_AddNode(hoya,(insertnode),next,prev); \ + } + +#define LL_MoveNode(node,newroot,next,prev) \ + { \ + LL_RemoveNode((node),next,prev); \ + LL_AddNode((newroot),(node),next,prev); \ + } + +#define LL_ListEmpty(list,next,prev) \ + ( \ + ((list)->next == (list)) && \ + ((list)->prev == (list)) \ + ) + +#define LL_Free(list) SafeFree(list) +#define LL_Reset(list,next,prev) (list)->next = (list)->prev = (list) +#define LL_New LL_CreateNewLinkedList +#define LL_Remove LL_RemoveNode +#define LL_Add LL_AddNode +#define LL_Empty LL_ListEmpty +#define LL_Move LL_MoveNode + + +#ifdef __cplusplus +}; +#endif +#endif diff --git a/audiolib/ll_man.c b/audiolib/ll_man.c new file mode 100755 index 0000000..56e97da --- /dev/null +++ b/audiolib/ll_man.c @@ -0,0 +1,173 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: LL_MAN.C + + author: James R. Dose + date: January 1, 1994 + + Linked list management routines. + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#define LOCKMEMORY + +#include +#include "ll_man.h" + +#ifdef LOCKMEMORY +#include "dpmi.h" +#endif + +#define OFFSET( structure, offset ) \ + ( *( ( char ** )&( structure )[ offset ] ) ) + + +/********************************************************************** + + Memory locked functions: + +**********************************************************************/ + + +#define LL_LockStart LL_AddNode + + +void LL_AddNode + ( + char *item, + char **head, + char **tail, + int next, + int prev + ) + + { + OFFSET( item, prev ) = NULL; + OFFSET( item, next ) = *head; + + if ( *head ) + { + OFFSET( *head, prev ) = item; + } + else + { + *tail = item; + } + + *head = item; + } + +void LL_RemoveNode + ( + char *item, + char **head, + char **tail, + int next, + int prev + ) + + { + if ( OFFSET( item, prev ) == NULL ) + { + *head = OFFSET( item, next ); + } + else + { + OFFSET( OFFSET( item, prev ), next ) = OFFSET( item, next ); + } + + if ( OFFSET( item, next ) == NULL ) + { + *tail = OFFSET( item, prev ); + } + else + { + OFFSET( OFFSET( item, next ), prev ) = OFFSET( item, prev ); + } + + OFFSET( item, next ) = NULL; + OFFSET( item, prev ) = NULL; + } + + +/*--------------------------------------------------------------------- + Function: LL_LockEnd + + Used for determining the length of the functions to lock in memory. +---------------------------------------------------------------------*/ + +static void LL_LockEnd + ( + void + ) + + { + } + + +/*--------------------------------------------------------------------- + Function: LL_UnlockMemory + + Unlocks all neccessary data. +---------------------------------------------------------------------*/ + +void LL_UnlockMemory + ( + void + ) + + { +#ifdef LOCKMEMORY + + DPMI_UnlockMemoryRegion( LL_LockStart, LL_LockEnd ); + +#endif + } + + +/*--------------------------------------------------------------------- + Function: LL_LockMemory + + Locks all neccessary data. +---------------------------------------------------------------------*/ + +int LL_LockMemory + ( + void + ) + + { + +#ifdef LOCKMEMORY + + int status; + + status = DPMI_LockMemoryRegion( LL_LockStart, LL_LockEnd ); + if ( status != DPMI_Ok ) + { + return( LL_Error ); + } + +#endif + + return( LL_Ok ); + } diff --git a/audiolib/ll_man.h b/audiolib/ll_man.h new file mode 100755 index 0000000..375b1e1 --- /dev/null +++ b/audiolib/ll_man.h @@ -0,0 +1,76 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: LL_MAN.H + + author: James R. Dose + date: February 4, 1994 + + Public header for LL_MAN.C. Linked list management routines. + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#ifndef __LL_MAN_H +#define __LL_MAN_H + +enum LL_Errors + { + LL_Warning = -2, + LL_Error = -1, + LL_Ok = 0 + }; + +typedef struct list + { + void *start; + void *end; + } list; + +void LL_AddNode( char *node, char **head, char **tail, int next, int prev ); +void LL_RemoveNode( char *node, char **head, char **tail, int next, int prev ); +void LL_UnlockMemory( void ); +int LL_LockMemory( void ); + +#define LL_AddToHead( type, listhead, node ) \ + LL_AddNode( ( char * )( node ), \ + ( char ** )&( ( listhead )->start ), \ + ( char ** )&( ( listhead )->end ), \ + ( int )&( ( type * ) 0 )->next, \ + ( int )&( ( type * ) 0 )->prev ) + +#define LL_AddToTail( type, listhead, node ) \ + LL_AddNode( ( char * )( node ), \ + ( char ** )&( ( listhead )->end ), \ + ( char ** )&( ( listhead )->start ), \ + ( int )&( ( type * ) 0 )->prev, \ + ( int )&( ( type * ) 0 )->next ) + +#define LL_Remove( type, listhead, node ) \ + LL_RemoveNode( ( char * )( node ), \ + ( char ** )&( ( listhead )->start ), \ + ( char ** )&( ( listhead )->end ), \ + ( int )&( ( type * ) 0 )->next, \ + ( int )&( ( type * ) 0 )->prev ) + +#define LL_NextNode( node ) ( ( node )->next ) +#define LL_PreviousNode( node ) ( ( node )->prev ) + +#endif diff --git a/audiolib/midi.c b/audiolib/midi.c new file mode 100755 index 0000000..81eb3d8 --- /dev/null +++ b/audiolib/midi.c @@ -0,0 +1,2265 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: MIDI.C + + author: James R. Dose + date: May 25, 1994 + + Midi song file playback routines. + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#include +#include +#include +#include +#include "sndcards.h" +#include "interrup.h" +#include "dpmi.h" +#include "standard.h" +#include "task_man.h" +#include "ll_man.h" +#include "usrhooks.h" +#include "music.h" +#include "_midi.h" +#include "midi.h" +#include "debugio.h" + +extern int MUSIC_SoundDevice; + +static const int _MIDI_CommandLengths[ NUM_MIDI_CHANNELS ] = + { + 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 1, 1, 2, 0 + }; + +static int cdecl ( *_MIDI_RerouteFunctions[ NUM_MIDI_CHANNELS ] ) + ( + int event, + int c1, + int c2 + ) = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; + +static track *_MIDI_TrackPtr = NULL; +static int _MIDI_TrackMemSize; +static int _MIDI_NumTracks; + +static int _MIDI_SongActive = FALSE; +static int _MIDI_SongLoaded = FALSE; +static int _MIDI_Loop = FALSE; + +static task *_MIDI_PlayRoutine = NULL; + +static int _MIDI_Division; +static int _MIDI_Tick = 0; +static int _MIDI_Beat = 1; +static int _MIDI_Measure = 1; +static unsigned _MIDI_Time; +static int _MIDI_BeatsPerMeasure; +static int _MIDI_TicksPerBeat; +static int _MIDI_TimeBase; +static long _MIDI_FPSecondsPerTick; +static unsigned _MIDI_TotalTime; +static int _MIDI_TotalTicks; +static int _MIDI_TotalBeats; +static int _MIDI_TotalMeasures; + +static unsigned long _MIDI_PositionInTicks; + +static int _MIDI_Context; + +static int _MIDI_ActiveTracks; +static int _MIDI_TotalVolume = MIDI_MaxVolume; + +static int _MIDI_ChannelVolume[ NUM_MIDI_CHANNELS ]; +static int _MIDI_UserChannelVolume[ NUM_MIDI_CHANNELS ] = + { + 256, 256, 256, 256, 256, 256, 256, 256, + 256, 256, 256, 256, 256, 256, 256, 256 + }; + +static midifuncs *_MIDI_Funcs = NULL; + +static int Reset = FALSE; + +int MIDI_Tempo = 120; + +char MIDI_PatchMap[ 128 ]; + + +/********************************************************************** + + Memory locked functions: + +**********************************************************************/ + + +#define MIDI_LockStart _MIDI_ReadNumber + + +/*--------------------------------------------------------------------- + Function: _MIDI_ReadNumber + + Reads a variable length number from a MIDI track. +---------------------------------------------------------------------*/ + +static long _MIDI_ReadNumber + ( + void *from, + size_t size + ) + + { + unsigned char *FromPtr; + long value; + + if ( size > 4 ) + { + size = 4; + } + + FromPtr = ( unsigned char * )from; + + value = 0; + while( size-- ) + { + value <<= 8; + value += *FromPtr++; + } + + return( value ); + } + + +/*--------------------------------------------------------------------- + Function: _MIDI_ReadDelta + + Reads a variable length encoded delta delay time from the MIDI data. +---------------------------------------------------------------------*/ + +static long _MIDI_ReadDelta + ( + track *ptr + ) + + { + long value; + unsigned char c; + + GET_NEXT_EVENT( ptr, value ); + + if ( value & 0x80 ) + { + value &= 0x7f; + do + { + GET_NEXT_EVENT( ptr, c ); + value = ( value << 7 ) + ( c & 0x7f ); + } + while ( c & 0x80 ); + } + + return( value ); + } + + +/*--------------------------------------------------------------------- + Function: _MIDI_ResetTracks + + Sets the track pointers to the beginning of the song. +---------------------------------------------------------------------*/ + +static void _MIDI_ResetTracks + ( + void + ) + + { + int i; + track *ptr; + + _MIDI_Tick = 0; + _MIDI_Beat = 1; + _MIDI_Measure = 1; + _MIDI_Time = 0; + _MIDI_BeatsPerMeasure = 4; + _MIDI_TicksPerBeat = _MIDI_Division; + _MIDI_TimeBase = 4; + + _MIDI_PositionInTicks = 0; + _MIDI_ActiveTracks = 0; + _MIDI_Context = 0; + + ptr = _MIDI_TrackPtr; + for( i = 0; i < _MIDI_NumTracks; i++ ) + { + ptr->pos = ptr->start; + ptr->delay = _MIDI_ReadDelta( ptr ); + ptr->active = ptr->EMIDI_IncludeTrack; + ptr->RunningStatus = 0; + ptr->currentcontext = 0; + ptr->context[ 0 ].loopstart = ptr->start; + ptr->context[ 0 ].loopcount = 0; + + if ( ptr->active ) + { + _MIDI_ActiveTracks++; + } + + ptr++; + } + } + + +/*--------------------------------------------------------------------- + Function: _MIDI_AdvanceTick + + Increment tick counters. +---------------------------------------------------------------------*/ + +static void _MIDI_AdvanceTick + ( + void + ) + + { + _MIDI_PositionInTicks++; + _MIDI_Time += _MIDI_FPSecondsPerTick; + + _MIDI_Tick++; + while( _MIDI_Tick > _MIDI_TicksPerBeat ) + { + _MIDI_Tick -= _MIDI_TicksPerBeat; + _MIDI_Beat++; + } + while( _MIDI_Beat > _MIDI_BeatsPerMeasure ) + { + _MIDI_Beat -= _MIDI_BeatsPerMeasure; + _MIDI_Measure++; + } + } + + +/*--------------------------------------------------------------------- + Function: _MIDI_SysEx + + Interpret SysEx Event. +---------------------------------------------------------------------*/ + +static void _MIDI_SysEx + ( + track *Track + ) + + { + int length; + + length = _MIDI_ReadDelta( Track ); + Track->pos += length; + } + + +/*--------------------------------------------------------------------- + Function: _MIDI_MetaEvent + + Interpret Meta Event. +---------------------------------------------------------------------*/ + +static void _MIDI_MetaEvent + ( + track *Track + ) + + { + int command; + int length; + int denominator; + long tempo; + + GET_NEXT_EVENT( Track, command ); + GET_NEXT_EVENT( Track, length ); + + switch( command ) + { + case MIDI_END_OF_TRACK : + Track->active = FALSE; + + _MIDI_ActiveTracks--; + break; + + case MIDI_TEMPO_CHANGE : + tempo = 60000000L / _MIDI_ReadNumber( Track->pos, 3 ); + MIDI_SetTempo( tempo ); + break; + + case MIDI_TIME_SIGNATURE : + if ( ( _MIDI_Tick > 0 ) || ( _MIDI_Beat > 1 ) ) + { + _MIDI_Measure++; + } + + _MIDI_Tick = 0; + _MIDI_Beat = 1; + + _MIDI_BeatsPerMeasure = (int)*Track->pos; + denominator = (int)*( Track->pos + 1 ); + _MIDI_TimeBase = 1; + while( denominator > 0 ) + { + _MIDI_TimeBase += _MIDI_TimeBase; + denominator--; + } + _MIDI_TicksPerBeat = ( _MIDI_Division * 4 ) / _MIDI_TimeBase; + break; + } + + Track->pos += length; + } + + +/*--------------------------------------------------------------------- + Function: _MIDI_InterpretControllerInfo + + Interprets the MIDI controller info. +---------------------------------------------------------------------*/ + +static int _MIDI_InterpretControllerInfo + ( + track *Track, + int TimeSet, + int channel, + int c1, + int c2 + ) + + { + track *trackptr; + int tracknum; + int loopcount; + + switch( c1 ) + { + case MIDI_MONO_MODE_ON : + Track->pos++; + break; + + case MIDI_VOLUME : + if ( !Track->EMIDI_VolumeChange ) + { + _MIDI_SetChannelVolume( channel, c2 ); + } + break; + + case EMIDI_INCLUDE_TRACK : + case EMIDI_EXCLUDE_TRACK : + break; + + case EMIDI_PROGRAM_CHANGE : + if ( Track->EMIDI_ProgramChange ) + { + _MIDI_Funcs->ProgramChange( channel, MIDI_PatchMap[ c2 & 0x7f ] ); + } + break; + + case EMIDI_VOLUME_CHANGE : + if ( Track->EMIDI_VolumeChange ) + { + _MIDI_SetChannelVolume( channel, c2 ); + } + break; + + case EMIDI_CONTEXT_START : + break; + + case EMIDI_CONTEXT_END : + if ( ( Track->currentcontext == _MIDI_Context ) || + ( _MIDI_Context < 0 ) || + ( Track->context[ _MIDI_Context ].pos == NULL ) ) + { + break; + } + + Track->currentcontext = _MIDI_Context; + Track->context[ 0 ].loopstart = Track->context[ _MIDI_Context ].loopstart; + Track->context[ 0 ].loopcount = Track->context[ _MIDI_Context ].loopcount; + Track->pos = Track->context[ _MIDI_Context ].pos; + Track->RunningStatus = Track->context[ _MIDI_Context ].RunningStatus; + + if ( TimeSet ) + { + break; + } + + _MIDI_Time = Track->context[ _MIDI_Context ].time; + _MIDI_FPSecondsPerTick = Track->context[ _MIDI_Context ].FPSecondsPerTick; + _MIDI_Tick = Track->context[ _MIDI_Context ].tick; + _MIDI_Beat = Track->context[ _MIDI_Context ].beat; + _MIDI_Measure = Track->context[ _MIDI_Context ].measure; + _MIDI_BeatsPerMeasure = Track->context[ _MIDI_Context ].BeatsPerMeasure; + _MIDI_TicksPerBeat = Track->context[ _MIDI_Context ].TicksPerBeat; + _MIDI_TimeBase = Track->context[ _MIDI_Context ].TimeBase; + TimeSet = TRUE; + break; + + case EMIDI_LOOP_START : + case EMIDI_SONG_LOOP_START : + if ( c2 == 0 ) + { + loopcount = EMIDI_INFINITE; + } + else + { + loopcount = c2; + } + + if ( c1 == EMIDI_SONG_LOOP_START ) + { + trackptr = _MIDI_TrackPtr; + tracknum = _MIDI_NumTracks; + } + else + { + trackptr = Track; + tracknum = 1; + } + + while( tracknum > 0 ) + { + trackptr->context[ 0 ].loopcount = loopcount; + trackptr->context[ 0 ].pos = trackptr->pos; + trackptr->context[ 0 ].loopstart = trackptr->pos; + trackptr->context[ 0 ].RunningStatus = trackptr->RunningStatus; + trackptr->context[ 0 ].active = trackptr->active; + trackptr->context[ 0 ].delay = trackptr->delay; + trackptr->context[ 0 ].time = _MIDI_Time; + trackptr->context[ 0 ].FPSecondsPerTick = _MIDI_FPSecondsPerTick; + trackptr->context[ 0 ].tick = _MIDI_Tick; + trackptr->context[ 0 ].beat = _MIDI_Beat; + trackptr->context[ 0 ].measure = _MIDI_Measure; + trackptr->context[ 0 ].BeatsPerMeasure = _MIDI_BeatsPerMeasure; + trackptr->context[ 0 ].TicksPerBeat = _MIDI_TicksPerBeat; + trackptr->context[ 0 ].TimeBase = _MIDI_TimeBase; + trackptr++; + tracknum--; + } + break; + + case EMIDI_LOOP_END : + case EMIDI_SONG_LOOP_END : + if ( ( c2 != EMIDI_END_LOOP_VALUE ) || + ( Track->context[ 0 ].loopstart == NULL ) || + ( Track->context[ 0 ].loopcount == 0 ) ) + { + break; + } + + if ( c1 == EMIDI_SONG_LOOP_END ) + { + trackptr = _MIDI_TrackPtr; + tracknum = _MIDI_NumTracks; + _MIDI_ActiveTracks = 0; + } + else + { + trackptr = Track; + tracknum = 1; + _MIDI_ActiveTracks--; + } + + while( tracknum > 0 ) + { + if ( trackptr->context[ 0 ].loopcount != EMIDI_INFINITE ) + { + trackptr->context[ 0 ].loopcount--; + } + + trackptr->pos = trackptr->context[ 0 ].loopstart; + trackptr->RunningStatus = trackptr->context[ 0 ].RunningStatus; + trackptr->delay = trackptr->context[ 0 ].delay; + trackptr->active = trackptr->context[ 0 ].active; + if ( trackptr->active ) + { + _MIDI_ActiveTracks++; + } + + if ( !TimeSet ) + { + _MIDI_Time = trackptr->context[ 0 ].time; + _MIDI_FPSecondsPerTick = trackptr->context[ 0 ].FPSecondsPerTick; + _MIDI_Tick = trackptr->context[ 0 ].tick; + _MIDI_Beat = trackptr->context[ 0 ].beat; + _MIDI_Measure = trackptr->context[ 0 ].measure; + _MIDI_BeatsPerMeasure = trackptr->context[ 0 ].BeatsPerMeasure; + _MIDI_TicksPerBeat = trackptr->context[ 0 ].TicksPerBeat; + _MIDI_TimeBase = trackptr->context[ 0 ].TimeBase; + TimeSet = TRUE; + } + + trackptr++; + tracknum--; + } + break; + + default : + if ( _MIDI_Funcs->ControlChange ) + { + _MIDI_Funcs->ControlChange( channel, c1, c2 ); + } + } + + return TimeSet; + } + + +/*--------------------------------------------------------------------- + Function: _MIDI_ServiceRoutine + + Task that interperates the MIDI data. +---------------------------------------------------------------------*/ +// NOTE: We have to use a stack frame here because of a strange bug +// that occurs with Watcom. This means that we cannot access Task! +//Turned off to test if it works with Watcom 10a +//#pragma aux _MIDI_ServiceRoutine frame; +/* +static void test + ( + task *Task + ) + { + _MIDI_ServiceRoutine( Task ); + _MIDI_ServiceRoutine( Task ); + _MIDI_ServiceRoutine( Task ); + _MIDI_ServiceRoutine( Task ); + } +*/ +static void _MIDI_ServiceRoutine + ( + task *Task + ) + + { + int event; + int channel; + int command; + track *Track; + int tracknum; + int status; + int c1; + int c2; + int TimeSet = FALSE; + + if ( !_MIDI_SongActive ) + { + return; + } + + Track = _MIDI_TrackPtr; + tracknum = 0; + while( tracknum < _MIDI_NumTracks ) + { + while ( ( Track->active ) && ( Track->delay == 0 ) ) + { + GET_NEXT_EVENT( Track, event ); + + if ( GET_MIDI_COMMAND( event ) == MIDI_SPECIAL ) + { + switch( event ) + { + case MIDI_SYSEX : + case MIDI_SYSEX_CONTINUE : + _MIDI_SysEx( Track ); + break; + + case MIDI_META_EVENT : + _MIDI_MetaEvent( Track ); + break; + } + + if ( Track->active ) + { + Track->delay = _MIDI_ReadDelta( Track ); + } + + continue; + } + + if ( event & MIDI_RUNNING_STATUS ) + { + Track->RunningStatus = event; + } + else + { + event = Track->RunningStatus; + Track->pos--; + } + + channel = GET_MIDI_CHANNEL( event ); + command = GET_MIDI_COMMAND( event ); + + if ( _MIDI_CommandLengths[ command ] > 0 ) + { + GET_NEXT_EVENT( Track, c1 ); + if ( _MIDI_CommandLengths[ command ] > 1 ) + { + GET_NEXT_EVENT( Track, c2 ); + } + } + + if ( _MIDI_RerouteFunctions[ channel ] != NULL ) + { + status = _MIDI_RerouteFunctions[ channel ]( event, c1, c2 ); + + if ( status == MIDI_DONT_PLAY ) + { + Track->delay = _MIDI_ReadDelta( Track ); + continue; + } + } + + switch ( command ) + { + case MIDI_NOTE_OFF : + if ( _MIDI_Funcs->NoteOff ) + { + _MIDI_Funcs->NoteOff( channel, c1, c2 ); + } + break; + + case MIDI_NOTE_ON : + if ( _MIDI_Funcs->NoteOn ) + { + _MIDI_Funcs->NoteOn( channel, c1, c2 ); + } + break; + + case MIDI_POLY_AFTER_TCH : + if ( _MIDI_Funcs->PolyAftertouch ) + { + _MIDI_Funcs->PolyAftertouch( channel, c1, c2 ); + } + break; + + case MIDI_CONTROL_CHANGE : + TimeSet = _MIDI_InterpretControllerInfo( Track, TimeSet, + channel, c1, c2 ); + break; + + case MIDI_PROGRAM_CHANGE : + if ( ( _MIDI_Funcs->ProgramChange ) && + ( !Track->EMIDI_ProgramChange ) ) + { + _MIDI_Funcs->ProgramChange( channel, MIDI_PatchMap[ c1 & 0x7f ] ); + } + break; + + case MIDI_AFTER_TOUCH : + if ( _MIDI_Funcs->ChannelAftertouch ) + { + _MIDI_Funcs->ChannelAftertouch( channel, c1 ); + } + break; + + case MIDI_PITCH_BEND : + if ( _MIDI_Funcs->PitchBend ) + { + _MIDI_Funcs->PitchBend( channel, c1, c2 ); + } + break; + + default : + break; + } + + Track->delay = _MIDI_ReadDelta( Track ); + } + + Track->delay--; + Track++; + tracknum++; + + if ( _MIDI_ActiveTracks == 0 ) + { + _MIDI_ResetTracks(); + if ( _MIDI_Loop ) + { + tracknum = 0; + Track = _MIDI_TrackPtr; + } + else + { + _MIDI_SongActive = FALSE; + break; + } + } + } + + _MIDI_AdvanceTick(); + } + + +/*--------------------------------------------------------------------- + Function: _MIDI_SendControlChange + + Sends a control change to the proper device +---------------------------------------------------------------------*/ + +static int _MIDI_SendControlChange + ( + int channel, + int c1, + int c2 + ) + + { + int status; + + if ( _MIDI_RerouteFunctions[ channel ] != NULL ) + { + status = _MIDI_RerouteFunctions[ channel ]( 0xB0 + channel, + c1, c2 ); + if ( status == MIDI_DONT_PLAY ) + { + return( MIDI_Ok ); + } + } + + if ( _MIDI_Funcs == NULL ) + { + return( MIDI_Error ); + } + + if ( _MIDI_Funcs->ControlChange == NULL ) + { + return( MIDI_Error ); + } + + _MIDI_Funcs->ControlChange( channel, c1, c2 ); + + return( MIDI_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: MIDI_RerouteMidiChannel + + Sets callback function to reroute MIDI commands from specified + function. +---------------------------------------------------------------------*/ + +void MIDI_RerouteMidiChannel + ( + int channel, + int cdecl ( *function )( int event, int c1, int c2 ) + ) + + { + if ( ( channel >= 1 ) && ( channel <= 16 ) ) + { + _MIDI_RerouteFunctions[ channel - 1 ] = function; + } + } + + +/*--------------------------------------------------------------------- + Function: MIDI_AllNotesOff + + Sends all notes off commands on all midi channels. +---------------------------------------------------------------------*/ + +int MIDI_AllNotesOff + ( + void + ) + + { + int channel; + + for( channel = 0; channel < NUM_MIDI_CHANNELS; channel++ ) + { + _MIDI_SendControlChange( channel, 0x40, 0 ); + _MIDI_SendControlChange( channel, MIDI_ALL_NOTES_OFF, 0 ); + _MIDI_SendControlChange( channel, 0x78, 0 ); + } + + return( MIDI_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: _MIDI_SetChannelVolume + + Sets the volume of the specified midi channel. +---------------------------------------------------------------------*/ + +static void _MIDI_SetChannelVolume + ( + int channel, + int volume + ) + + { + int status; + int remotevolume; + + _MIDI_ChannelVolume[ channel ] = volume; + + if ( _MIDI_RerouteFunctions[ channel ] != NULL ) + { + remotevolume = volume * _MIDI_TotalVolume; + remotevolume *= _MIDI_UserChannelVolume[ channel ]; + remotevolume /= MIDI_MaxVolume; + remotevolume >>= 8; + + status = _MIDI_RerouteFunctions[ channel ]( 0xB0 + channel, + MIDI_VOLUME, remotevolume ); + if ( status == MIDI_DONT_PLAY ) + { + return; + } + } + + if ( _MIDI_Funcs == NULL ) + { + return; + } + + if ( _MIDI_Funcs->ControlChange == NULL ) + { + return; + } + + // For user volume + volume *= _MIDI_UserChannelVolume[ channel ]; + + if ( _MIDI_Funcs->SetVolume == NULL ) + { + volume *= _MIDI_TotalVolume; + volume /= MIDI_MaxVolume; + } + + // For user volume + volume >>= 8; + + _MIDI_Funcs->ControlChange( channel, MIDI_VOLUME, volume ); + } + + +/*--------------------------------------------------------------------- + Function: MIDI_SetUserChannelVolume + + Sets the volume of the specified midi channel. +---------------------------------------------------------------------*/ + +void MIDI_SetUserChannelVolume + ( + int channel, + int volume + ) + + { + // Convert channel from 1-16 to 0-15 + channel--; + + volume = max( 0, volume ); + volume = min( volume, 256 ); + + if ( ( channel >= 0 ) && ( channel < NUM_MIDI_CHANNELS ) ) + { + _MIDI_UserChannelVolume[ channel ] = volume; + _MIDI_SetChannelVolume( channel, _MIDI_ChannelVolume[ channel ] ); + } + } + + +/*--------------------------------------------------------------------- + Function: MIDI_ResetUserChannelVolume + + Sets the volume of the specified midi channel. +---------------------------------------------------------------------*/ + +void MIDI_ResetUserChannelVolume + ( + void + ) + + { + int channel; + + for( channel = 0; channel < NUM_MIDI_CHANNELS; channel++ ) + { + _MIDI_UserChannelVolume[ channel ] = 256; + } + + _MIDI_SendChannelVolumes(); + } + + +/*--------------------------------------------------------------------- + Function: _MIDI_SendChannelVolumes + + Sets the volume on all the midi channels. +---------------------------------------------------------------------*/ + +static void _MIDI_SendChannelVolumes + ( + void + ) + + { + int channel; + + for( channel = 0; channel < NUM_MIDI_CHANNELS; channel++ ) + { + _MIDI_SetChannelVolume( channel, _MIDI_ChannelVolume[ channel ] ); + } + } + + +/*--------------------------------------------------------------------- + Function: MIDI_Reset + + Resets the MIDI device to General Midi defaults. +---------------------------------------------------------------------*/ + +int MIDI_Reset + ( + void + ) + + { + int channel; + long time; + unsigned flags; + + MIDI_AllNotesOff(); + + flags = DisableInterrupts(); + _enable(); + time = clock() + CLOCKS_PER_SEC/24; + while(clock() < time) + ; + + RestoreInterrupts( flags ); + + for( channel = 0; channel < NUM_MIDI_CHANNELS; channel++ ) + { + _MIDI_SendControlChange( channel, MIDI_RESET_ALL_CONTROLLERS, 0 ); + _MIDI_SendControlChange( channel, MIDI_RPN_MSB, MIDI_PITCHBEND_MSB ); + _MIDI_SendControlChange( channel, MIDI_RPN_LSB, MIDI_PITCHBEND_LSB ); + _MIDI_SendControlChange( channel, MIDI_DATAENTRY_MSB, 2 ); /* Pitch Bend Sensitivity MSB */ + _MIDI_SendControlChange( channel, MIDI_DATAENTRY_LSB, 0 ); /* Pitch Bend Sensitivity LSB */ + _MIDI_ChannelVolume[ channel ] = GENMIDI_DefaultVolume; + } + + _MIDI_SendChannelVolumes(); + + Reset = TRUE; + + return( MIDI_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: MIDI_SetVolume + + Sets the total volume of the music. +---------------------------------------------------------------------*/ + +int MIDI_SetVolume + ( + int volume + ) + + { + int i; + + if ( _MIDI_Funcs == NULL ) + { + return( MIDI_NullMidiModule ); + } + + volume = min( MIDI_MaxVolume, volume ); + volume = max( 0, volume ); + + _MIDI_TotalVolume = volume; + + if ( _MIDI_Funcs->SetVolume ) + { + _MIDI_Funcs->SetVolume( volume ); + + for( i = 0; i < NUM_MIDI_CHANNELS; i++ ) + { + if ( _MIDI_RerouteFunctions[ i ] != NULL ) + { + _MIDI_SetChannelVolume( i, _MIDI_ChannelVolume[ i ] ); + } + } + } + else + { + _MIDI_SendChannelVolumes(); + } + + return( MIDI_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: MIDI_GetVolume + + Returns the total volume of the music. +---------------------------------------------------------------------*/ + +int MIDI_GetVolume + ( + void + ) + + { + int volume; + + if ( _MIDI_Funcs == NULL ) + { + return( MIDI_NullMidiModule ); + } + + if ( _MIDI_Funcs->GetVolume ) + { + volume = _MIDI_Funcs->GetVolume(); + } + else + { + volume = _MIDI_TotalVolume; + } + + return( volume ); + } + + +/*--------------------------------------------------------------------- + Function: MIDI_SetContext + + Sets the song context. +---------------------------------------------------------------------*/ + +void MIDI_SetContext + ( + int context + ) + + { + if ( ( context > 0 ) && ( context < EMIDI_NUM_CONTEXTS ) ) + { + _MIDI_Context = context; + } + } + + +/*--------------------------------------------------------------------- + Function: MIDI_GetContext + + Returns the current song context. +---------------------------------------------------------------------*/ + +int MIDI_GetContext + ( + void + ) + + { + return _MIDI_Context; + } + + +/*--------------------------------------------------------------------- + Function: MIDI_SetLoopFlag + + Sets whether the song should loop when finished or not. +---------------------------------------------------------------------*/ + +void MIDI_SetLoopFlag + ( + int loopflag + ) + + { + _MIDI_Loop = loopflag; + } + + +/*--------------------------------------------------------------------- + Function: MIDI_ContinueSong + + Continues playback of a paused song. +---------------------------------------------------------------------*/ + +void MIDI_ContinueSong + ( + void + ) + + { + if ( _MIDI_SongLoaded ) + { + _MIDI_SongActive = TRUE; + } + } + + +/*--------------------------------------------------------------------- + Function: MIDI_PauseSong + + Pauses playback of the current song. +---------------------------------------------------------------------*/ + +void MIDI_PauseSong + ( + void + ) + + { + if ( _MIDI_SongLoaded ) + { + _MIDI_SongActive = FALSE; + MIDI_AllNotesOff(); + } + } + + +/*--------------------------------------------------------------------- + Function: MIDI_SongPlaying + + Returns whether a song is playing or not. +---------------------------------------------------------------------*/ + +int MIDI_SongPlaying + ( + void + ) + + { + return( _MIDI_SongActive ); + } + + +/*--------------------------------------------------------------------- + Function: MIDI_SetMidiFuncs + + Selects the routines that send the MIDI data to the music device. +---------------------------------------------------------------------*/ + +void MIDI_SetMidiFuncs + ( + midifuncs *funcs + ) + + { + _MIDI_Funcs = funcs; + } + + +/*--------------------------------------------------------------------- + Function: MIDI_StopSong + + Stops playback of the currently playing song. +---------------------------------------------------------------------*/ + +void MIDI_StopSong + ( + void + ) + + { + if ( _MIDI_SongLoaded ) + { + TS_Terminate( _MIDI_PlayRoutine ); + + _MIDI_PlayRoutine = NULL; + _MIDI_SongActive = FALSE; + _MIDI_SongLoaded = FALSE; + + MIDI_Reset(); + _MIDI_ResetTracks(); + + if ( _MIDI_Funcs->ReleasePatches ) + { + _MIDI_Funcs->ReleasePatches(); + } + + DPMI_UnlockMemory( _MIDI_TrackPtr, _MIDI_TrackMemSize ); + USRHOOKS_FreeMem( _MIDI_TrackPtr ); + + _MIDI_TrackPtr = NULL; + _MIDI_NumTracks = 0; + _MIDI_TrackMemSize = 0; + + _MIDI_TotalTime = 0; + _MIDI_TotalTicks = 0; + _MIDI_TotalBeats = 0; + _MIDI_TotalMeasures = 0; + } + } + + +/*--------------------------------------------------------------------- + Function: MIDI_PlaySong + + Begins playback of a MIDI song. +---------------------------------------------------------------------*/ + +int MIDI_PlaySong + ( + unsigned char *song, + int loopflag + ) + + { + int numtracks; + int format; + long headersize; + long tracklength; + track *CurrentTrack; + unsigned char *ptr; + int status; + + if ( _MIDI_SongLoaded ) + { + MIDI_StopSong(); + } + + _MIDI_Loop = loopflag; + + if ( _MIDI_Funcs == NULL ) + { + return( MIDI_NullMidiModule ); + } + + if ( *( unsigned long * )song != MIDI_HEADER_SIGNATURE ) + { + return( MIDI_InvalidMidiFile ); + } + + song += 4; + + headersize = _MIDI_ReadNumber( song, 4 ); + song += 4; + format = _MIDI_ReadNumber( song, 2 ); + _MIDI_NumTracks = _MIDI_ReadNumber( song + 2, 2 ); + _MIDI_Division = _MIDI_ReadNumber( song + 4, 2 ); + if ( _MIDI_Division < 0 ) + { + // If a SMPTE time division is given, just set to 96 so no errors occur + _MIDI_Division = 96; + } + + if ( format > MAX_FORMAT ) + { + return( MIDI_UnknownMidiFormat ); + } + + ptr = song + headersize; + + if ( _MIDI_NumTracks == 0 ) + { + return( MIDI_NoTracks ); + } + + _MIDI_TrackMemSize = _MIDI_NumTracks * sizeof( track ); + status = USRHOOKS_GetMem( &_MIDI_TrackPtr, _MIDI_TrackMemSize ); + if ( status != USRHOOKS_Ok ) + { + return( MIDI_NoMemory ); + } + + status = DPMI_LockMemory( _MIDI_TrackPtr, _MIDI_TrackMemSize ); + if ( status != DPMI_Ok ) + { + USRHOOKS_FreeMem( _MIDI_TrackPtr ); + + _MIDI_TrackPtr = NULL; + _MIDI_TrackMemSize = 0; + _MIDI_NumTracks = 0; +// MIDI_SetErrorCode( MIDI_DPMI_Error ); + return( MIDI_Error ); + } + + CurrentTrack = _MIDI_TrackPtr; + numtracks = _MIDI_NumTracks; + while( numtracks-- ) + { + if ( *( unsigned long * )ptr != MIDI_TRACK_SIGNATURE ) + { + DPMI_UnlockMemory( _MIDI_TrackPtr, _MIDI_TrackMemSize ); + + USRHOOKS_FreeMem( _MIDI_TrackPtr ); + + _MIDI_TrackPtr = NULL; + _MIDI_TrackMemSize = 0; + + return( MIDI_InvalidTrack ); + } + + tracklength = _MIDI_ReadNumber( ptr + 4, 4 ); + ptr += 8; + CurrentTrack->start = ptr; + ptr += tracklength; + CurrentTrack++; + } + + if ( _MIDI_Funcs->GetVolume != NULL ) + { + _MIDI_TotalVolume = _MIDI_Funcs->GetVolume(); + } + + _MIDI_InitEMIDI(); + + if ( _MIDI_Funcs->LoadPatch ) + { + MIDI_LoadTimbres(); + } + + _MIDI_ResetTracks(); + + if ( !Reset ) + { + MIDI_Reset(); + } + + Reset = FALSE; + + _MIDI_PlayRoutine = TS_ScheduleTask( _MIDI_ServiceRoutine, 100, 1, NULL ); +// _MIDI_PlayRoutine = TS_ScheduleTask( test, 100, 1, NULL ); + MIDI_SetTempo( 120 ); + TS_Dispatch(); + + _MIDI_SongLoaded = TRUE; + _MIDI_SongActive = TRUE; + + return( MIDI_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: MIDI_SetTempo + + Sets the song tempo. +---------------------------------------------------------------------*/ + +void MIDI_SetTempo + ( + int tempo + ) + + { + long tickspersecond; + + MIDI_Tempo = tempo; + tickspersecond = ( tempo * _MIDI_Division ) / 60; + if ( _MIDI_PlayRoutine != NULL ) + { + TS_SetTaskRate( _MIDI_PlayRoutine, tickspersecond ); +// TS_SetTaskRate( _MIDI_PlayRoutine, tickspersecond / 4 ); + } + _MIDI_FPSecondsPerTick = ( 1 << TIME_PRECISION ) / tickspersecond; + } + + +/*--------------------------------------------------------------------- + Function: MIDI_GetTempo + + Returns the song tempo. +---------------------------------------------------------------------*/ + +int MIDI_GetTempo + ( + void + ) + + { + return( MIDI_Tempo ); + } + + +/*--------------------------------------------------------------------- + Function: _MIDI_ProcessNextTick + + Sets the position of the song pointer. +---------------------------------------------------------------------*/ + +static int _MIDI_ProcessNextTick + ( + void + ) + + { + int event; + int channel; + int command; + track *Track; + int tracknum; + int status; + int c1; + int c2; + int TimeSet = FALSE; + + Track = _MIDI_TrackPtr; + tracknum = 0; + while( ( tracknum < _MIDI_NumTracks ) && ( Track != NULL ) ) + { + while ( ( Track->active ) && ( Track->delay == 0 ) ) + { + GET_NEXT_EVENT( Track, event ); + + if ( GET_MIDI_COMMAND( event ) == MIDI_SPECIAL ) + { + switch( event ) + { + case MIDI_SYSEX : + case MIDI_SYSEX_CONTINUE : + _MIDI_SysEx( Track ); + break; + + case MIDI_META_EVENT : + _MIDI_MetaEvent( Track ); + break; + } + + if ( Track->active ) + { + Track->delay = _MIDI_ReadDelta( Track ); + } + + continue; + } + + if ( event & MIDI_RUNNING_STATUS ) + { + Track->RunningStatus = event; + } + else + { + event = Track->RunningStatus; + Track->pos--; + } + + channel = GET_MIDI_CHANNEL( event ); + command = GET_MIDI_COMMAND( event ); + + if ( _MIDI_CommandLengths[ command ] > 0 ) + { + GET_NEXT_EVENT( Track, c1 ); + if ( _MIDI_CommandLengths[ command ] > 1 ) + { + GET_NEXT_EVENT( Track, c2 ); + } + } + + if ( _MIDI_RerouteFunctions[ channel ] != NULL ) + { + status = _MIDI_RerouteFunctions[ channel ]( event, c1, c2 ); + + if ( status == MIDI_DONT_PLAY ) + { + Track->delay = _MIDI_ReadDelta( Track ); + continue; + } + } + + switch ( command ) + { + case MIDI_NOTE_OFF : + break; + + case MIDI_NOTE_ON : + break; + + case MIDI_POLY_AFTER_TCH : + if ( _MIDI_Funcs->PolyAftertouch ) + { + _MIDI_Funcs->PolyAftertouch( channel, c1, c2 ); + } + break; + + case MIDI_CONTROL_CHANGE : + TimeSet = _MIDI_InterpretControllerInfo( Track, TimeSet, + channel, c1, c2 ); + break; + + case MIDI_PROGRAM_CHANGE : + if ( ( _MIDI_Funcs->ProgramChange ) && + ( !Track->EMIDI_ProgramChange ) ) + { + _MIDI_Funcs->ProgramChange( channel, c1 ); + } + break; + + case MIDI_AFTER_TOUCH : + if ( _MIDI_Funcs->ChannelAftertouch ) + { + _MIDI_Funcs->ChannelAftertouch( channel, c1 ); + } + break; + + case MIDI_PITCH_BEND : + if ( _MIDI_Funcs->PitchBend ) + { + _MIDI_Funcs->PitchBend( channel, c1, c2 ); + } + break; + + default : + break; + } + + Track->delay = _MIDI_ReadDelta( Track ); + } + + Track->delay--; + Track++; + tracknum++; + + if ( _MIDI_ActiveTracks == 0 ) + { + break; + } + } + + _MIDI_AdvanceTick(); + + return( TimeSet ); + } + + +/*--------------------------------------------------------------------- + Function: MIDI_SetSongTick + + Sets the position of the song pointer. +---------------------------------------------------------------------*/ + +void MIDI_SetSongTick + ( + unsigned long PositionInTicks + ) + + { + if ( !_MIDI_SongLoaded ) + { + return; + } + + MIDI_PauseSong(); + + if ( PositionInTicks < _MIDI_PositionInTicks ) + { + _MIDI_ResetTracks(); + MIDI_Reset(); + } + + while( _MIDI_PositionInTicks < PositionInTicks ) + { + if ( _MIDI_ProcessNextTick() ) + { + break; + } + if ( _MIDI_ActiveTracks == 0 ) + { + _MIDI_ResetTracks(); + if ( !_MIDI_Loop ) + { + return; + } + break; + } + } + + MIDI_SetVolume( _MIDI_TotalVolume ); + MIDI_ContinueSong(); + } + + +/*--------------------------------------------------------------------- + Function: MIDI_SetSongTime + + Sets the position of the song pointer. +---------------------------------------------------------------------*/ + +void MIDI_SetSongTime + ( + unsigned long milliseconds + ) + + { + unsigned long mil; + unsigned long sec; + unsigned long newtime; + + if ( !_MIDI_SongLoaded ) + { + return; + } + + MIDI_PauseSong(); + + mil = ( ( milliseconds % 1000 ) << TIME_PRECISION ) / 1000; + sec = ( milliseconds / 1000 ) << TIME_PRECISION; + newtime = sec + mil; + + if ( newtime < _MIDI_Time ) + { + _MIDI_ResetTracks(); + MIDI_Reset(); + } + + while( _MIDI_Time < newtime ) + { + if ( _MIDI_ProcessNextTick() ) + { + break; + } + if ( _MIDI_ActiveTracks == 0 ) + { + _MIDI_ResetTracks(); + if ( !_MIDI_Loop ) + { + return; + } + break; + } + } + + MIDI_SetVolume( _MIDI_TotalVolume ); + MIDI_ContinueSong(); + } + + +/*--------------------------------------------------------------------- + Function: MIDI_SetSongPosition + + Sets the position of the song pointer. +---------------------------------------------------------------------*/ + +void MIDI_SetSongPosition + ( + int measure, + int beat, + int tick + ) + + { + unsigned long pos; + + if ( !_MIDI_SongLoaded ) + { + return; + } + + MIDI_PauseSong(); + + pos = RELATIVE_BEAT( measure, beat, tick ); + + if ( pos < RELATIVE_BEAT( _MIDI_Measure, _MIDI_Beat, _MIDI_Tick ) ) + { + _MIDI_ResetTracks(); + MIDI_Reset(); + } + + while( RELATIVE_BEAT( _MIDI_Measure, _MIDI_Beat, _MIDI_Tick ) < pos ) + { + if ( _MIDI_ProcessNextTick() ) + { + break; + } + if ( _MIDI_ActiveTracks == 0 ) + { + _MIDI_ResetTracks(); + if ( !_MIDI_Loop ) + { + return; + } + break; + } + } + + MIDI_SetVolume( _MIDI_TotalVolume ); + MIDI_ContinueSong(); + } + + +/*--------------------------------------------------------------------- + Function: MIDI_GetSongPosition + + Returns the position of the song pointer in Measures, beats, ticks. +---------------------------------------------------------------------*/ + +void MIDI_GetSongPosition + ( + songposition *pos + ) + + { + unsigned long mil; + unsigned long sec; + + mil = ( _MIDI_Time & ( ( 1 << TIME_PRECISION ) - 1 ) ) * 1000; + sec = _MIDI_Time >> TIME_PRECISION; + pos->milliseconds = ( mil >> TIME_PRECISION ) + ( sec * 1000 ); + pos->tickposition = _MIDI_PositionInTicks; + pos->measure = _MIDI_Measure; + pos->beat = _MIDI_Beat; + pos->tick = _MIDI_Tick; + } + + +/*--------------------------------------------------------------------- + Function: MIDI_GetSongLength + + Returns the length of the song. +---------------------------------------------------------------------*/ + +void MIDI_GetSongLength + ( + songposition *pos + ) + + { + unsigned long mil; + unsigned long sec; + + mil = ( _MIDI_TotalTime & ( ( 1 << TIME_PRECISION ) - 1 ) ) * 1000; + sec = _MIDI_TotalTime >> TIME_PRECISION; + + pos->milliseconds = ( mil >> TIME_PRECISION ) + ( sec * 1000 ); + pos->measure = _MIDI_TotalMeasures; + pos->beat = _MIDI_TotalBeats; + pos->tick = _MIDI_TotalTicks; + pos->tickposition = 0; + } + + +/*--------------------------------------------------------------------- + Function: MIDI_InitEMIDI + + Sets up the EMIDI +---------------------------------------------------------------------*/ + +static void _MIDI_InitEMIDI + ( + void + ) + + { + int event; + int command; + int channel; + int length; + int IncludeFound; + track *Track; + int tracknum; + int type; + int c1; + int c2; + + type = EMIDI_GeneralMIDI; + switch( MUSIC_SoundDevice ) + { + case SoundBlaster : + type = EMIDI_SoundBlaster; + break; + + case ProAudioSpectrum : + type = EMIDI_ProAudio; + break; + + case SoundMan16 : + type = EMIDI_SoundMan16; + break; + + case Adlib : + type = EMIDI_Adlib; + break; + + case GenMidi : + type = EMIDI_GeneralMIDI; + break; + + case SoundCanvas : + type = EMIDI_SoundCanvas; + break; + + case Awe32 : + type = EMIDI_AWE32; + break; + + case WaveBlaster : + type = EMIDI_WaveBlaster; + break; + + case SoundScape : + type = EMIDI_Soundscape; + break; + + case UltraSound : + type = EMIDI_Ultrasound; + break; + } + + _MIDI_ResetTracks(); + + _MIDI_TotalTime = 0; + _MIDI_TotalTicks = 0; + _MIDI_TotalBeats = 0; + _MIDI_TotalMeasures = 0; + + Track = _MIDI_TrackPtr; + tracknum = 0; + while( ( tracknum < _MIDI_NumTracks ) && ( Track != NULL ) ) + { + _MIDI_Tick = 0; + _MIDI_Beat = 1; + _MIDI_Measure = 1; + _MIDI_Time = 0; + _MIDI_BeatsPerMeasure = 4; + _MIDI_TicksPerBeat = _MIDI_Division; + _MIDI_TimeBase = 4; + + _MIDI_PositionInTicks = 0; + _MIDI_ActiveTracks = 0; + _MIDI_Context = -1; + + Track->RunningStatus = 0; + Track->active = TRUE; + + Track->EMIDI_ProgramChange = FALSE; + Track->EMIDI_VolumeChange = FALSE; + Track->EMIDI_IncludeTrack = TRUE; + + memset( Track->context, 0, sizeof( Track->context ) ); + + while( Track->delay > 0 ) + { + _MIDI_AdvanceTick(); + Track->delay--; + } + + IncludeFound = FALSE; + while ( Track->active ) + { + GET_NEXT_EVENT( Track, event ); + + if ( GET_MIDI_COMMAND( event ) == MIDI_SPECIAL ) + { + switch( event ) + { + case MIDI_SYSEX : + case MIDI_SYSEX_CONTINUE : + _MIDI_SysEx( Track ); + break; + + case MIDI_META_EVENT : + _MIDI_MetaEvent( Track ); + break; + } + + if ( Track->active ) + { + Track->delay = _MIDI_ReadDelta( Track ); + while( Track->delay > 0 ) + { + _MIDI_AdvanceTick(); + Track->delay--; + } + } + + continue; + } + + if ( event & MIDI_RUNNING_STATUS ) + { + Track->RunningStatus = event; + } + else + { + event = Track->RunningStatus; + Track->pos--; + } + + channel = GET_MIDI_CHANNEL( event ); + command = GET_MIDI_COMMAND( event ); + length = _MIDI_CommandLengths[ command ]; + + if ( command == MIDI_CONTROL_CHANGE ) + { + if ( *Track->pos == MIDI_MONO_MODE_ON ) + { + length++; + } + GET_NEXT_EVENT( Track, c1 ); + GET_NEXT_EVENT( Track, c2 ); + length -= 2; + + switch( c1 ) + { + case EMIDI_LOOP_START : + case EMIDI_SONG_LOOP_START : + if ( c2 == 0 ) + { + Track->context[ 0 ].loopcount = EMIDI_INFINITE; + } + else + { + Track->context[ 0 ].loopcount = c2; + } + + Track->context[ 0 ].pos = Track->pos; + Track->context[ 0 ].loopstart = Track->pos; + Track->context[ 0 ].RunningStatus = Track->RunningStatus; + Track->context[ 0 ].time = _MIDI_Time; + Track->context[ 0 ].FPSecondsPerTick = _MIDI_FPSecondsPerTick; + Track->context[ 0 ].tick = _MIDI_Tick; + Track->context[ 0 ].beat = _MIDI_Beat; + Track->context[ 0 ].measure = _MIDI_Measure; + Track->context[ 0 ].BeatsPerMeasure = _MIDI_BeatsPerMeasure; + Track->context[ 0 ].TicksPerBeat = _MIDI_TicksPerBeat; + Track->context[ 0 ].TimeBase = _MIDI_TimeBase; + break; + + case EMIDI_LOOP_END : + case EMIDI_SONG_LOOP_END : + if ( c2 == EMIDI_END_LOOP_VALUE ) + { + Track->context[ 0 ].loopstart = NULL; + Track->context[ 0 ].loopcount = 0; + } + break; + + case EMIDI_INCLUDE_TRACK : + if ( EMIDI_AffectsCurrentCard( c2, type ) ) + { + //printf( "Include track %d on card %d\n", tracknum, c2 ); + IncludeFound = TRUE; + Track->EMIDI_IncludeTrack = TRUE; + } + else if ( !IncludeFound ) + { + //printf( "Track excluded %d on card %d\n", tracknum, c2 ); + IncludeFound = TRUE; + Track->EMIDI_IncludeTrack = FALSE; + } + break; + + case EMIDI_EXCLUDE_TRACK : + if ( EMIDI_AffectsCurrentCard( c2, type ) ) + { + //printf( "Exclude track %d on card %d\n", tracknum, c2 ); + Track->EMIDI_IncludeTrack = FALSE; + } + break; + + case EMIDI_PROGRAM_CHANGE : + if ( !Track->EMIDI_ProgramChange ) + //printf( "Program change on track %d\n", tracknum ); + Track->EMIDI_ProgramChange = TRUE; + break; + + case EMIDI_VOLUME_CHANGE : + if ( !Track->EMIDI_VolumeChange ) + //printf( "Volume change on track %d\n", tracknum ); + Track->EMIDI_VolumeChange = TRUE; + break; + + case EMIDI_CONTEXT_START : + if ( ( c2 > 0 ) && ( c2 < EMIDI_NUM_CONTEXTS ) ) + { + Track->context[ c2 ].pos = Track->pos; + Track->context[ c2 ].loopstart = Track->context[ 0 ].loopstart; + Track->context[ c2 ].loopcount = Track->context[ 0 ].loopcount; + Track->context[ c2 ].RunningStatus = Track->RunningStatus; + Track->context[ c2 ].time = _MIDI_Time; + Track->context[ c2 ].FPSecondsPerTick = _MIDI_FPSecondsPerTick; + Track->context[ c2 ].tick = _MIDI_Tick; + Track->context[ c2 ].beat = _MIDI_Beat; + Track->context[ c2 ].measure = _MIDI_Measure; + Track->context[ c2 ].BeatsPerMeasure = _MIDI_BeatsPerMeasure; + Track->context[ c2 ].TicksPerBeat = _MIDI_TicksPerBeat; + Track->context[ c2 ].TimeBase = _MIDI_TimeBase; + } + break; + + case EMIDI_CONTEXT_END : + break; + } + } + + Track->pos += length; + Track->delay = _MIDI_ReadDelta( Track ); + + while( Track->delay > 0 ) + { + _MIDI_AdvanceTick(); + Track->delay--; + } + } + + _MIDI_TotalTime = max( _MIDI_TotalTime, _MIDI_Time ); + if ( RELATIVE_BEAT( _MIDI_Measure, _MIDI_Beat, _MIDI_Tick ) > + RELATIVE_BEAT( _MIDI_TotalMeasures, _MIDI_TotalBeats, + _MIDI_TotalTicks ) ) + { + _MIDI_TotalTicks = _MIDI_Tick; + _MIDI_TotalBeats = _MIDI_Beat; + _MIDI_TotalMeasures = _MIDI_Measure; + } + + Track++; + tracknum++; + } + + _MIDI_ResetTracks(); + } + + +/*--------------------------------------------------------------------- + Function: MIDI_LoadTimbres + + Preloads the timbres on cards that use patch-caching. +---------------------------------------------------------------------*/ + +void MIDI_LoadTimbres + ( + void + ) + + { + int event; + int command; + int channel; + int length; + int Finished; + track *Track; + int tracknum; + + Track = _MIDI_TrackPtr; + tracknum = 0; + while( ( tracknum < _MIDI_NumTracks ) && ( Track != NULL ) ) + { + Finished = FALSE; + while ( !Finished ) + { + GET_NEXT_EVENT( Track, event ); + + if ( GET_MIDI_COMMAND( event ) == MIDI_SPECIAL ) + { + switch( event ) + { + case MIDI_SYSEX : + case MIDI_SYSEX_CONTINUE : + length = _MIDI_ReadDelta( Track ); + Track->pos += length; + break; + + case MIDI_META_EVENT : + GET_NEXT_EVENT( Track, command ); + GET_NEXT_EVENT( Track, length ); + + if ( command == MIDI_END_OF_TRACK ) + { + Finished = TRUE; + } + + Track->pos += length; + break; + } + + if ( !Finished ) + { + _MIDI_ReadDelta( Track ); + } + + continue; + } + + if ( event & MIDI_RUNNING_STATUS ) + { + Track->RunningStatus = event; + } + else + { + event = Track->RunningStatus; + Track->pos--; + } + + channel = GET_MIDI_CHANNEL( event ); + command = GET_MIDI_COMMAND( event ); + length = _MIDI_CommandLengths[ command ]; + + if ( command == MIDI_CONTROL_CHANGE ) + { + if ( *Track->pos == MIDI_MONO_MODE_ON ) + { + length++; + } + + if ( *Track->pos == EMIDI_PROGRAM_CHANGE ) + { + _MIDI_Funcs->LoadPatch( *( Track->pos + 1 ) ); + } + } + + if ( channel == MIDI_RHYTHM_CHANNEL ) + { + if ( command == MIDI_NOTE_ON ) + { + _MIDI_Funcs->LoadPatch( 128 + *Track->pos ); + } + } + else + { + if ( command == MIDI_PROGRAM_CHANGE ) + { + _MIDI_Funcs->LoadPatch( *Track->pos ); + } + } + Track->pos += length; + _MIDI_ReadDelta( Track ); + } + Track++; + tracknum++; + } + + _MIDI_ResetTracks(); + } + + +/*--------------------------------------------------------------------- + Function: MIDI_LockEnd + + Used for determining the length of the functions to lock in memory. +---------------------------------------------------------------------*/ + +static void MIDI_LockEnd + ( + void + ) + + { + } + + +/*--------------------------------------------------------------------- + Function: MIDI_UnlockMemory + + Unlocks all neccessary data. +---------------------------------------------------------------------*/ + +void MIDI_UnlockMemory + ( + void + ) + + { + DPMI_UnlockMemoryRegion( MIDI_LockStart, MIDI_LockEnd ); + DPMI_UnlockMemory( ( void * )&_MIDI_CommandLengths[ 0 ], + sizeof( _MIDI_CommandLengths ) ); + DPMI_Unlock( _MIDI_TrackPtr ); + DPMI_Unlock( _MIDI_NumTracks ); + DPMI_Unlock( _MIDI_SongActive ); + DPMI_Unlock( _MIDI_SongLoaded ); + DPMI_Unlock( _MIDI_Loop ); + DPMI_Unlock( _MIDI_PlayRoutine ); + DPMI_Unlock( _MIDI_Division ); + DPMI_Unlock( _MIDI_ActiveTracks ); + DPMI_Unlock( _MIDI_TotalVolume ); + DPMI_Unlock( _MIDI_ChannelVolume ); + DPMI_Unlock( _MIDI_Funcs ); + DPMI_Unlock( _MIDI_PositionInTicks ); + DPMI_Unlock( _MIDI_Division ); + DPMI_Unlock( _MIDI_Tick ); + DPMI_Unlock( _MIDI_Beat ); + DPMI_Unlock( _MIDI_Measure ); + DPMI_Unlock( _MIDI_Time ); + DPMI_Unlock( _MIDI_BeatsPerMeasure ); + DPMI_Unlock( _MIDI_TicksPerBeat ); + DPMI_Unlock( _MIDI_TimeBase ); + DPMI_Unlock( _MIDI_FPSecondsPerTick ); + DPMI_Unlock( _MIDI_Context ); + DPMI_Unlock( _MIDI_TotalTime ); + DPMI_Unlock( _MIDI_TotalTicks ); + DPMI_Unlock( _MIDI_TotalBeats ); + DPMI_Unlock( _MIDI_TotalMeasures ); + DPMI_Unlock( MIDI_Tempo ); + } + + +/*--------------------------------------------------------------------- + Function: MIDI_LockMemory + + Locks all neccessary data. +---------------------------------------------------------------------*/ + +int MIDI_LockMemory + ( + void + ) + + { + int status; + + status = DPMI_LockMemoryRegion( MIDI_LockStart, MIDI_LockEnd ); + status |= DPMI_LockMemory( ( void * )&_MIDI_CommandLengths[ 0 ], + sizeof( _MIDI_CommandLengths ) ); + status |= DPMI_Lock( _MIDI_TrackPtr ); + status |= DPMI_Lock( _MIDI_NumTracks ); + status |= DPMI_Lock( _MIDI_SongActive ); + status |= DPMI_Lock( _MIDI_SongLoaded ); + status |= DPMI_Lock( _MIDI_Loop ); + status |= DPMI_Lock( _MIDI_PlayRoutine ); + status |= DPMI_Lock( _MIDI_Division ); + status |= DPMI_Lock( _MIDI_ActiveTracks ); + status |= DPMI_Lock( _MIDI_TotalVolume ); + status |= DPMI_Lock( _MIDI_ChannelVolume ); + status |= DPMI_Lock( _MIDI_Funcs ); + status |= DPMI_Lock( _MIDI_PositionInTicks ); + status |= DPMI_Lock( _MIDI_Division ); + status |= DPMI_Lock( _MIDI_Tick ); + status |= DPMI_Lock( _MIDI_Beat ); + status |= DPMI_Lock( _MIDI_Measure ); + status |= DPMI_Lock( _MIDI_Time ); + status |= DPMI_Lock( _MIDI_BeatsPerMeasure ); + status |= DPMI_Lock( _MIDI_TicksPerBeat ); + status |= DPMI_Lock( _MIDI_TimeBase ); + status |= DPMI_Lock( _MIDI_FPSecondsPerTick ); + status |= DPMI_Lock( _MIDI_Context ); + status |= DPMI_Lock( _MIDI_TotalTime ); + status |= DPMI_Lock( _MIDI_TotalTicks ); + status |= DPMI_Lock( _MIDI_TotalBeats ); + status |= DPMI_Lock( _MIDI_TotalMeasures ); + status |= DPMI_Lock( MIDI_Tempo ); + + if ( status != DPMI_Ok ) + { + MIDI_UnlockMemory(); +// MIDI_SetErrorCode( MIDI_DPMI_Error ); + return( MIDI_Error ); + } + + return( MIDI_Ok ); + } diff --git a/audiolib/midi.h b/audiolib/midi.h new file mode 100755 index 0000000..7de1e2e --- /dev/null +++ b/audiolib/midi.h @@ -0,0 +1,98 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: MIDI.H + + author: James R. Dose + date: May 25, 1994 + + Public header for MIDI.C. Midi song file playback routines. + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#ifndef __MIDI_H +#define __MIDI_H + +enum MIDI_Errors + { + MIDI_Warning = -2, + MIDI_Error = -1, + MIDI_Ok = 0, + MIDI_NullMidiModule, + MIDI_InvalidMidiFile, + MIDI_UnknownMidiFormat, + MIDI_NoTracks, + MIDI_InvalidTrack, + MIDI_NoMemory, + MIDI_DPMI_Error + }; + + +#define MIDI_PASS_THROUGH 1 +#define MIDI_DONT_PLAY 0 + +#define MIDI_MaxVolume 255 + +extern char MIDI_PatchMap[ 128 ]; + +typedef struct + { + void ( *NoteOff )( int channel, int key, int velocity ); + void ( *NoteOn )( int channel, int key, int velocity ); + void ( *PolyAftertouch )( int channel, int key, int pressure ); + void ( *ControlChange )( int channel, int number, int value ); + void ( *ProgramChange )( int channel, int program ); + void ( *ChannelAftertouch )( int channel, int pressure ); + void ( *PitchBend )( int channel, int lsb, int msb ); + void ( *ReleasePatches )( void ); + void ( *LoadPatch )( int number ); + void ( *SetVolume )( int volume ); + int ( *GetVolume )( void ); + } midifuncs; + +void MIDI_RerouteMidiChannel( int channel, int cdecl ( *function )( int event, int c1, int c2 ) ); +int MIDI_AllNotesOff( void ); +void MIDI_SetUserChannelVolume( int channel, int volume ); +void MIDI_ResetUserChannelVolume( void ); +int MIDI_Reset( void ); +int MIDI_SetVolume( int volume ); +int MIDI_GetVolume( void ); +void MIDI_SetMidiFuncs( midifuncs *funcs ); +void MIDI_SetContext( int context ); +int MIDI_GetContext( void ); +void MIDI_SetLoopFlag( int loopflag ); +void MIDI_ContinueSong( void ); +void MIDI_PauseSong( void ); +int MIDI_SongPlaying( void ); +void MIDI_StopSong( void ); +int MIDI_PlaySong( unsigned char *song, int loopflag ); +void MIDI_SetTempo( int tempo ); +int MIDI_GetTempo( void ); +void MIDI_SetSongTick( unsigned long PositionInTicks ); +void MIDI_SetSongTime( unsigned long milliseconds ); +void MIDI_SetSongPosition( int measure, int beat, int tick ); +void MIDI_GetSongPosition( songposition *pos ); +void MIDI_GetSongLength( songposition *pos ); +void MIDI_LoadTimbres( void ); +void MIDI_UnlockMemory( void ); +int MIDI_LockMemory( void ); + +#endif diff --git a/audiolib/mpu401.c b/audiolib/mpu401.c new file mode 100755 index 0000000..e812b70 --- /dev/null +++ b/audiolib/mpu401.c @@ -0,0 +1,451 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: MPU401.C + + author: James R. Dose + date: January 1, 1994 + + Low level routines to support sending of MIDI data to MPU401 + compatible MIDI interfaces. + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#include +#include +#include +#include +#include "dpmi.h" +#include "user.h" +#include "mpu401.h" + +#define MIDI_NOTE_OFF 0x80 +#define MIDI_NOTE_ON 0x90 +#define MIDI_POLY_AFTER_TCH 0xA0 +#define MIDI_CONTROL_CHANGE 0xB0 +#define MIDI_PROGRAM_CHANGE 0xC0 +#define MIDI_AFTER_TOUCH 0xD0 +#define MIDI_PITCH_BEND 0xE0 +#define MIDI_META_EVENT 0xFF +#define MIDI_END_OF_TRACK 0x2F +#define MIDI_TEMPO_CHANGE 0x51 +#define MIDI_MONO_MODE_ON 0x7E +#define MIDI_ALL_NOTES_OFF 0x7B + +int MPU_BaseAddr = MPU_DefaultAddress; + +//unsigned MPU_Delay = 500; +//unsigned MPU_Delay = 5000; +unsigned MPU_Delay = 0x5000; + + +/********************************************************************** + + Memory locked functions: + +**********************************************************************/ + + +#define MPU_LockStart MPU_SendMidi + + +/*--------------------------------------------------------------------- + Function: MPU_SendMidi + + Sends a byte of MIDI data to the music device. +---------------------------------------------------------------------*/ + +void MPU_SendMidi + ( + int data + ) + + { + int port = MPU_BaseAddr + 1; + unsigned count; + + count = MPU_Delay; + while( count > 0 ) + { + // check if status port says we're ready for write + if ( !( inp( port ) & MPU_ReadyToWrite ) ) + { + break; + } + + count--; + } + + port--; + + // Send the midi data + outp( port, data ); + } + + +/*--------------------------------------------------------------------- + Function: MPU_NoteOff + + Sends a full MIDI note off event out to the music device. +---------------------------------------------------------------------*/ + +void MPU_NoteOff + ( + int channel, + int key, + int velocity + ) + + { + MPU_SendMidi( MIDI_NOTE_OFF | channel ); + MPU_SendMidi( key ); + MPU_SendMidi( velocity ); + } + + +/*--------------------------------------------------------------------- + Function: MPU_NoteOn + + Sends a full MIDI note on event out to the music device. +---------------------------------------------------------------------*/ + +void MPU_NoteOn + ( + int channel, + int key, + int velocity + ) + + { + MPU_SendMidi( MIDI_NOTE_ON | channel ); + MPU_SendMidi( key ); + MPU_SendMidi( velocity ); + } + + +/*--------------------------------------------------------------------- + Function: MPU_PolyAftertouch + + Sends a full MIDI polyphonic aftertouch event out to the music device. +---------------------------------------------------------------------*/ + +void MPU_PolyAftertouch + ( + int channel, + int key, + int pressure + ) + + { + MPU_SendMidi( MIDI_POLY_AFTER_TCH | channel ); + MPU_SendMidi( key ); + MPU_SendMidi( pressure ); + } + + +/*--------------------------------------------------------------------- + Function: MPU_ControlChange + + Sends a full MIDI control change event out to the music device. +---------------------------------------------------------------------*/ + +void MPU_ControlChange + ( + int channel, + int number, + int value + ) + + { + MPU_SendMidi( MIDI_CONTROL_CHANGE | channel ); + MPU_SendMidi( number ); + MPU_SendMidi( value ); + } + + +/*--------------------------------------------------------------------- + Function: MPU_ProgramChange + + Sends a full MIDI program change event out to the music device. +---------------------------------------------------------------------*/ + +void MPU_ProgramChange + ( + int channel, + int program + ) + + { + MPU_SendMidi( MIDI_PROGRAM_CHANGE | channel ); + MPU_SendMidi( program ); + } + + +/*--------------------------------------------------------------------- + Function: MPU_ChannelAftertouch + + Sends a full MIDI channel aftertouch event out to the music device. +---------------------------------------------------------------------*/ + +void MPU_ChannelAftertouch + ( + int channel, + int pressure + ) + + { + MPU_SendMidi( MIDI_AFTER_TOUCH | channel ); + MPU_SendMidi( pressure ); + } + + +/*--------------------------------------------------------------------- + Function: MPU_PitchBend + + Sends a full MIDI pitch bend event out to the music device. +---------------------------------------------------------------------*/ + +void MPU_PitchBend + ( + int channel, + int lsb, + int msb + ) + + { + MPU_SendMidi( MIDI_PITCH_BEND | channel ); + MPU_SendMidi( lsb ); + MPU_SendMidi( msb ); + } + + +/*--------------------------------------------------------------------- + Function: MPU_SendCommand + + Sends a command to the MPU401 card. +---------------------------------------------------------------------*/ + +void MPU_SendCommand + ( + int data + ) + + { + int port = MPU_BaseAddr + 1; + unsigned count; + + count = 0xffff; + while( count > 0 ) + { + // check if status port says we're ready for write + if ( !( inp( port ) & MPU_ReadyToWrite ) ) + { + break; + } + count--; + } + + outp( port, data ); + } + + +/*--------------------------------------------------------------------- + Function: MPU_Reset + + Resets the MPU401 card. +---------------------------------------------------------------------*/ + +int MPU_Reset + ( + void + ) + + { + int port = MPU_BaseAddr + 1; + unsigned count; + + // Output "Reset" command via Command port + MPU_SendCommand( MPU_CmdReset ); + + // Wait for status port to be ready for read + count = 0xffff; + while( count > 0 ) + { + if ( !( inp( port ) & MPU_ReadyToRead ) ) + { + port--; + + // Check for a successful reset + if ( inp( port ) == MPU_CmdAcknowledge ) + { + return( MPU_Ok ); + } + + port++; + } + count--; + } + + // Failed to reset : MPU-401 not detected + return( MPU_NotFound ); + } + + +/*--------------------------------------------------------------------- + Function: MPU_EnterUART + + Sets the MPU401 card to operate in UART mode. +---------------------------------------------------------------------*/ + +int MPU_EnterUART + ( + void + ) + + { + int port = MPU_BaseAddr + 1; + unsigned count; + + // Output "Enter UART" command via Command port + MPU_SendCommand( MPU_CmdEnterUART ); + + // Wait for status port to be ready for read + count = 0xffff; + while( count > 0 ) + { + if ( !( inp( port ) & MPU_ReadyToRead ) ) + { + port--; + + // Check for a successful reset + if ( inp( port ) == MPU_CmdAcknowledge ) + { + return( MPU_Ok ); + } + + port++; + } + count--; + } + + // Failed to reset : MPU-401 not detected + return( MPU_UARTFailed ); + } + + +/*--------------------------------------------------------------------- + Function: MPU_Init + + Detects and initializes the MPU401 card. +---------------------------------------------------------------------*/ + +int MPU_Init + ( + int addr + ) + + { + int status; + int count; + char *ptr; + + ptr = USER_GetText( "MPUDELAY" ); + if ( ptr != NULL ) + { + MPU_Delay = ( unsigned )atol( ptr ); + } + + MPU_BaseAddr = addr; + + count = 4; + while( count > 0 ) + { + status = MPU_Reset(); + if ( status == MPU_Ok ) + { + return( MPU_EnterUART() ); + } + count--; + } + + return( status ); + } + + +/*--------------------------------------------------------------------- + Function: MPU_LockEnd + + Used for determining the length of the functions to lock in memory. +---------------------------------------------------------------------*/ + +static void MPU_LockEnd + ( + void + ) + + { + } + + +/*--------------------------------------------------------------------- + Function: MPU_UnlockMemory + + Locks all neccessary data. +---------------------------------------------------------------------*/ + +void MPU_UnlockMemory + ( + void + ) + + { + DPMI_UnlockMemoryRegion( MPU_LockStart, MPU_LockEnd ); + DPMI_Unlock( MPU_BaseAddr ); + DPMI_Unlock( MPU_Delay ); + } + + +/*--------------------------------------------------------------------- + Function: MPU_LockMemory + + Locks all neccessary data. +---------------------------------------------------------------------*/ + +int MPU_LockMemory + ( + void + ) + + { + int status; + + status = DPMI_LockMemoryRegion( MPU_LockStart, MPU_LockEnd ); + status |= DPMI_Lock( MPU_BaseAddr ); + status |= DPMI_Lock( MPU_Delay ); + + if ( status != DPMI_Ok ) + { + MPU_UnlockMemory(); + return( MPU_Error ); + } + + return( MPU_Ok ); + } diff --git a/audiolib/mpu401.h b/audiolib/mpu401.h new file mode 100755 index 0000000..c66f6a2 --- /dev/null +++ b/audiolib/mpu401.h @@ -0,0 +1,61 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef __MPU401_H +#define __MPU401_H + +#define MPU_DefaultAddress 0x330 + +enum MPU_ERRORS + { + MPU_Warning = -2, + MPU_Error = -1, + MPU_Ok = 0, + MPU_DPMI_Error + }; + +#define MPU_NotFound -1 +#define MPU_UARTFailed -2 + +#define MPU_ReadyToWrite 0x40 +#define MPU_ReadyToRead 0x80 +#define MPU_CmdEnterUART 0x3f +#define MPU_CmdReset 0xff +#define MPU_CmdAcknowledge 0xfe + +extern int MPU_BaseAddr; +extern unsigned MPU_Delay; + +void MPU_SendCommand( int data ); +void MPU_SendMidi( int data ); +int MPU_Reset( void ); +int MPU_EnterUART( void ); +int MPU_Init( int addr ); +void MPU_ResetMidi( void ); +void MPU_NoteOff( int channel, int key, int velocity ); +void MPU_NoteOn( int channel, int key, int velocity ); +void MPU_PolyAftertouch( int channel, int key, int pressure ); +void MPU_ControlChange( int channel, int number, int value ); +void MPU_ProgramChange( int channel, int program ); +void MPU_ChannelAftertouch( int channel, int pressure ); +void MPU_PitchBend( int channel, int lsb, int msb ); +void MPU_UnlockMemory( void ); +int MPU_LockMemory( void ); + +#endif diff --git a/audiolib/multivoc.c b/audiolib/multivoc.c new file mode 100755 index 0000000..85feee6 --- /dev/null +++ b/audiolib/multivoc.c @@ -0,0 +1,3556 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: MULTIVOC.C + + author: James R. Dose + date: December 20, 1993 + + Routines to provide multichannel digitized sound playback for + Sound Blaster compatible sound cards. + + (c) Copyright 1993 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#include +#include +#include +#include + +#ifdef PLAT_DOS +#include +#include +#endif + +#include "util.h" +#include "dpmi.h" +#include "usrhooks.h" +#include "interrup.h" +#include "dma.h" +#include "linklist.h" +#include "sndcards.h" + +#ifdef PLAT_DOS +#include "blaster.h" +#include "sndscape.h" +#include "sndsrc.h" +#include "pas16.h" +#include "guswave.h" +#else +#include "dsl.h" +#endif + +#include "pitch.h" +#include "multivoc.h" +#include "_multivc.h" +#include "debugio.h" + +#define RoundFixed( fixedval, bits ) \ + ( \ + ( \ + (fixedval) + ( 1 << ( (bits) - 1 ) )\ + ) >> (bits) \ + ) + +#define IS_QUIET( ptr ) ( ( void * )( ptr ) == ( void * )&MV_VolumeTable[ 0 ] ) + +static int MV_ReverbLevel; +static int MV_ReverbDelay; +static VOLUME16 *MV_ReverbTable = NULL; + +//static signed short MV_VolumeTable[ MV_MaxVolume + 1 ][ 256 ]; +static signed short MV_VolumeTable[ 63 + 1 ][ 256 ]; + +//static Pan MV_PanTable[ MV_NumPanPositions ][ MV_MaxVolume + 1 ]; +static Pan MV_PanTable[ MV_NumPanPositions ][ 63 + 1 ]; + +static int MV_Installed = FALSE; +static int MV_SoundCard = SoundBlaster; +static int MV_TotalVolume = MV_MaxTotalVolume; +static int MV_MaxVoices = 1; +static int MV_Recording; + +static int MV_BufferSize = MixBufferSize; +static int MV_BufferLength; + +static int MV_NumberOfBuffers = NumberOfBuffers; + +static int MV_MixMode = MONO_8BIT; +static int MV_Channels = 1; +static int MV_Bits = 8; + +static int MV_Silence = SILENCE_8BIT; +static int MV_SwapLeftRight = FALSE; + +static int MV_RequestedMixRate; +static int MV_MixRate; + +static int MV_DMAChannel = -1; +static int MV_BuffShift; + +static int MV_TotalMemory; + +static int MV_BufferDescriptor; +static int MV_BufferEmpty[ NumberOfBuffers ]; +char *MV_MixBuffer[ NumberOfBuffers + 1 ]; + +static VoiceNode *MV_Voices = NULL; + +static volatile VoiceNode VoiceList; +static volatile VoiceNode VoicePool; + +/*static*/ int MV_MixPage = 0; +static int MV_VoiceHandle = MV_MinVoiceHandle; + +static void ( *MV_CallBackFunc )( unsigned long ) = NULL; +static void ( *MV_RecordFunc )( char *ptr, int length ) = NULL; +static void ( *MV_MixFunction )( VoiceNode *voice, int buffer ); + +static int MV_MaxVolume = 63; + +char *MV_HarshClipTable; +char *MV_MixDestination; +short *MV_LeftVolume; +short *MV_RightVolume; +int MV_SampleSize = 1; +int MV_RightChannelOffset; + +unsigned long MV_MixPosition; + +int MV_ErrorCode = MV_Ok; + +#define MV_SetErrorCode( status ) \ + MV_ErrorCode = ( status ); + + +/*--------------------------------------------------------------------- + Function: MV_ErrorString + + Returns a pointer to the error message associated with an error + number. A -1 returns a pointer the current error. +---------------------------------------------------------------------*/ + +char *MV_ErrorString + ( + int ErrorNumber + ) + + { + char *ErrorString; + + switch( ErrorNumber ) + { + case MV_Warning : + case MV_Error : + ErrorString = MV_ErrorString( MV_ErrorCode ); + break; + + case MV_Ok : + ErrorString = "Multivoc ok."; + break; + + case MV_UnsupportedCard : + ErrorString = "Selected sound card is not supported by Multivoc."; + break; + + case MV_NotInstalled : + ErrorString = "Multivoc not installed."; + break; + + case MV_NoVoices : + ErrorString = "No free voices available to Multivoc."; + break; + + case MV_NoMem : + ErrorString = "Out of memory in Multivoc."; + break; + + case MV_VoiceNotFound : + ErrorString = "No voice with matching handle found."; + break; + +#ifdef PLAT_DOS + case MV_BlasterError : + ErrorString = BLASTER_ErrorString( BLASTER_Error ); + break; + + case MV_PasError : + ErrorString = PAS_ErrorString( PAS_Error ); + break; + + case MV_SoundScapeError : + ErrorString = SOUNDSCAPE_ErrorString( SOUNDSCAPE_Error ); + break; + + #ifndef SOUNDSOURCE_OFF + case MV_SoundSourceError : + ErrorString = SS_ErrorString( SS_Error ); + break; + #endif +#endif + + case MV_DPMI_Error : + ErrorString = "DPMI Error in Multivoc."; + break; + + case MV_InvalidVOCFile : + ErrorString = "Invalid VOC file passed in to Multivoc."; + break; + + case MV_InvalidWAVFile : + ErrorString = "Invalid WAV file passed in to Multivoc."; + break; + + case MV_InvalidMixMode : + ErrorString = "Invalid mix mode request in Multivoc."; + break; + + case MV_SoundSourceFailure : + ErrorString = "Sound Source playback failed."; + break; + + case MV_IrqFailure : + ErrorString = "Playback failed, possibly due to an invalid or conflicting IRQ."; + break; + + case MV_DMAFailure : + ErrorString = "Playback failed, possibly due to an invalid or conflicting DMA channel."; + break; + + case MV_DMA16Failure : + ErrorString = "Playback failed, possibly due to an invalid or conflicting DMA channel. \n" + "Make sure the 16-bit DMA channel is correct."; + break; + + case MV_NullRecordFunction : + ErrorString = "Null record function passed to MV_StartRecording."; + break; + + default : + ErrorString = "Unknown Multivoc error code."; + break; + } + + return( ErrorString ); + } + + +/********************************************************************** + + Memory locked functions: + +**********************************************************************/ + + +#define MV_LockStart MV_Mix + + +/*--------------------------------------------------------------------- + Function: MV_Mix + + Mixes the sound into the buffer. +---------------------------------------------------------------------*/ + +static void MV_Mix + ( + VoiceNode *voice, + int buffer + ) + + { + char *start; + int length; + long voclength; + unsigned long position; + unsigned long rate; + unsigned long FixedPointBufferSize; + + if ( ( voice->length == 0 ) && + ( voice->GetSound != NULL ) && + ( voice->GetSound( voice ) != KeepPlaying ) ) + { + return; + } + + length = MixBufferSize; + FixedPointBufferSize = voice->FixedPointBufferSize; + + MV_MixDestination = MV_MixBuffer[ buffer ]; + MV_LeftVolume = voice->LeftVolume; + MV_RightVolume = voice->RightVolume; + + if ( ( MV_Channels == 2 ) && ( IS_QUIET( MV_LeftVolume ) ) ) + { + MV_LeftVolume = MV_RightVolume; + MV_MixDestination += MV_RightChannelOffset; + } + + // Add this voice to the mix + while( length > 0 ) + { + start = voice->sound; + rate = voice->RateScale; + position = voice->position; + + // Check if the last sample in this buffer would be + // beyond the length of the sample block + if ( ( position + FixedPointBufferSize ) >= voice->length ) + { + if ( position < voice->length ) + { + voclength = ( voice->length - position + rate - 1 ) / rate; + } + else + { + voice->GetSound( voice ); + return; + } + } + else + { + voclength = length; + } + + voice->mix( position, rate, start, voclength ); + + if ( voclength & 1 ) + { + MV_MixPosition += rate; + voclength -= 1; + } + voice->position = MV_MixPosition; + + length -= voclength; + + if ( voice->position >= voice->length ) + { + // Get the next block of sound + if ( voice->GetSound( voice ) != KeepPlaying ) + { + return; + } + + if ( length > 0 ) + { + // Get the position of the last sample in the buffer + FixedPointBufferSize = voice->RateScale * ( length - 1 ); + } + } + } + } + + +/*--------------------------------------------------------------------- + Function: MV_PlayVoice + + Adds a voice to the play list. +---------------------------------------------------------------------*/ + +void MV_PlayVoice + ( + VoiceNode *voice + ) + + { + unsigned flags; + + flags = DisableInterrupts(); + LL_SortedInsertion( &VoiceList, voice, prev, next, VoiceNode, priority ); + + RestoreInterrupts( flags ); + } + + +/*--------------------------------------------------------------------- + Function: MV_StopVoice + + Removes the voice from the play list and adds it to the free list. +---------------------------------------------------------------------*/ + +void MV_StopVoice + ( + VoiceNode *voice + ) + + { + unsigned flags; + + flags = DisableInterrupts(); + + // move the voice from the play list to the free list + LL_Remove( voice, next, prev ); + LL_Add( (VoiceNode *)&VoicePool, voice, next, prev ); + + RestoreInterrupts( flags ); + } + + +/*--------------------------------------------------------------------- + Function: MV_ServiceVoc + + Starts playback of the waiting buffer and mixes the next one. +---------------------------------------------------------------------*/ + +// static int backcolor = 1; + +void MV_ServiceVoc + ( + void + ) + + { + VoiceNode *voice; + VoiceNode *next; + char *buffer; + +#ifdef PLAT_DOS + if ( MV_DMAChannel >= 0 ) + { + // Get the currently playing buffer + buffer = ( char * )DMA_GetCurrentPos( MV_DMAChannel ); + MV_MixPage = ( unsigned )( buffer - MV_MixBuffer[ 0 ] ); + MV_MixPage >>= MV_BuffShift; + } +#endif + + // Toggle which buffer we'll mix next + MV_MixPage++; + if ( MV_MixPage >= MV_NumberOfBuffers ) + { + MV_MixPage -= MV_NumberOfBuffers; + } + + if ( MV_ReverbLevel == 0 ) + { + // Initialize buffer + //Commented out so that the buffer is always cleared. + //This is so the guys at Echo Speech can mix into the + //buffer even when no sounds are playing. + //if ( !MV_BufferEmpty[ MV_MixPage ] ) + { + ClearBuffer_DW( MV_MixBuffer[ MV_MixPage ], MV_Silence, MV_BufferSize >> 2 ); + if ( ( MV_SoundCard == UltraSound ) && ( MV_Channels == 2 ) ) + { + ClearBuffer_DW( MV_MixBuffer[ MV_MixPage ] + MV_RightChannelOffset, + MV_Silence, MV_BufferSize >> 2 ); + } + MV_BufferEmpty[ MV_MixPage ] = TRUE; + } + } + else + { + char *end; + char *source; + char *dest; + int count; + int length; + + end = MV_MixBuffer[ 0 ] + MV_BufferLength;; + dest = MV_MixBuffer[ MV_MixPage ]; + source = MV_MixBuffer[ MV_MixPage ] - MV_ReverbDelay; + if ( source < MV_MixBuffer[ 0 ] ) + { + source += MV_BufferLength; + } + + length = MV_BufferSize; + while( length > 0 ) + { + count = length; + if ( source + count > end ) + { + count = end - source; + } + + if ( MV_Bits == 16 ) + { + if ( MV_ReverbTable != NULL ) + { + MV_16BitReverb( source, dest, (const VOLUME16 *)MV_ReverbTable, count / 2 ); + if ( ( MV_SoundCard == UltraSound ) && ( MV_Channels == 2 ) ) + { + MV_16BitReverb( source + MV_RightChannelOffset, + dest + MV_RightChannelOffset, (const VOLUME16 *)MV_ReverbTable, count / 2 ); + } + } + else + { + MV_16BitReverbFast( source, dest, count / 2, MV_ReverbLevel ); + if ( ( MV_SoundCard == UltraSound ) && ( MV_Channels == 2 ) ) + { + MV_16BitReverbFast( source + MV_RightChannelOffset, + dest + MV_RightChannelOffset, count / 2, MV_ReverbLevel ); + } + } + } + else + { + if ( MV_ReverbTable != NULL ) + { + MV_8BitReverb( source, dest, (const VOLUME16 *)MV_ReverbTable, count ); + if ( ( MV_SoundCard == UltraSound ) && ( MV_Channels == 2 ) ) + { + MV_8BitReverb( source + MV_RightChannelOffset, + dest + MV_RightChannelOffset, (const VOLUME16 *)MV_ReverbTable, count ); + } + } + else + { + MV_8BitReverbFast( source, dest, count, MV_ReverbLevel ); + if ( ( MV_SoundCard == UltraSound ) && ( MV_Channels == 2 ) ) + { + MV_8BitReverbFast( source + MV_RightChannelOffset, + dest + MV_RightChannelOffset, count, MV_ReverbLevel ); + } + } + } + + // if we go through the loop again, it means that we've wrapped around the buffer + source = MV_MixBuffer[ 0 ]; + dest += count; + length -= count; + } + } + + // Play any waiting voices + for( voice = VoiceList.next; voice != &VoiceList; voice = next ) + { +// if ( ( voice < &MV_Voices[ 0 ] ) || ( voice > &MV_Voices[ 8 ] ) ) +// { +// SetBorderColor(backcolor++); +// break; +// } + + MV_BufferEmpty[ MV_MixPage ] = FALSE; + + if (MV_MixFunction != NULL) + MV_MixFunction( voice, MV_MixPage ); + + next = voice->next; + + // Is this voice done? + if ( !voice->Playing ) + { + MV_StopVoice( voice ); + + if ( MV_CallBackFunc ) + { + MV_CallBackFunc( voice->callbackval ); + } + } + } + } + + +int leftpage = -1; +int rightpage = -1; + +void MV_ServiceGus( char **ptr, unsigned long *length ) + { + if ( leftpage == MV_MixPage ) + { + MV_ServiceVoc(); + } + + leftpage = MV_MixPage; + + *ptr = MV_MixBuffer[ MV_MixPage ]; + *length = MV_BufferSize; + } + +void MV_ServiceRightGus( char **ptr, unsigned long *length ) + { + if ( rightpage == MV_MixPage ) + { + MV_ServiceVoc(); + } + + rightpage = MV_MixPage; + + *ptr = MV_MixBuffer[ MV_MixPage ] + MV_RightChannelOffset; + *length = MV_BufferSize; + } + +/*--------------------------------------------------------------------- + Function: MV_GetNextVOCBlock + + Interperate the information of a VOC format sound file. +---------------------------------------------------------------------*/ +static __inline unsigned int get_le32(void *p0) +{ + //unsigned char *p = p0; + //return p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24); + unsigned int val = *((unsigned int *) p0); + return(BUILDSWAP_INTEL32(val)); +} + +static __inline unsigned int get_le16(void *p0) +{ + //unsigned char *p = p0; + //return p[0] | (p[1]<<8); + unsigned short val = *((unsigned short *) p0); + return( (unsigned int) (BUILDSWAP_INTEL16(val)) ); +} + +playbackstatus MV_GetNextVOCBlock + ( + VoiceNode *voice + ) + + { + unsigned char *ptr; + int blocktype=0; + int lastblocktype=0; + unsigned long blocklength=0l; + unsigned long samplespeed=0l; + unsigned int tc=0; + int packtype=0; + int voicemode=0; + int done=0; + unsigned BitsPerSample; + unsigned Channels; + unsigned Format; + + if ( voice->BlockLength > 0 ) + { + voice->position -= voice->length; + voice->sound += voice->length >> 16; + if ( voice->bits == 16 ) + { + voice->sound += voice->length >> 16; + } + voice->length = min( voice->BlockLength, 0x8000 ); + voice->BlockLength -= voice->length; + voice->length <<= 16; + return( KeepPlaying ); + } + + if ( ( voice->length > 0 ) && ( voice->LoopEnd != NULL ) && + ( voice->LoopStart != NULL ) ) + { + voice->BlockLength = voice->LoopSize; + voice->sound = voice->LoopStart; + voice->position = 0; + voice->length = min( voice->BlockLength, 0x8000 ); + voice->BlockLength -= voice->length; + voice->length <<= 16; + return( KeepPlaying ); + } + + ptr = ( unsigned char * )voice->NextBlock; + + voice->Playing = TRUE; + + voicemode = 0; + lastblocktype = 0; + packtype = 0; + + done = FALSE; + while( !done ) + { + // Stop playing if we get a NULL pointer + if ( ptr == NULL ) + { + voice->Playing = FALSE; + done = TRUE; + break; + } + + { + unsigned tmp = get_le32(ptr); + blocktype = tmp&255; + blocklength = tmp>>8; + } + ptr += 4; + + switch( blocktype ) + { + case 0 : + // End of data + if ( ( voice->LoopStart == NULL ) || + ( (unsigned char *)voice->LoopStart >= ( ptr - 4 ) ) ) + { + voice->Playing = FALSE; + done = TRUE; + } + else + { + voice->BlockLength = ( ptr - 4 ) - (unsigned char *)voice->LoopStart; + voice->sound = voice->LoopStart; + voice->position = 0; + voice->length = min( voice->BlockLength, 0x8000 ); + voice->BlockLength -= voice->length; + voice->length <<= 16; + return( KeepPlaying ); + } + break; + + case 1 : + // Sound data block + voice->bits = 8; + if ( lastblocktype != 8 ) + { + tc = ( unsigned int )*ptr << 8; + packtype = *( ptr + 1 ); + } + + ptr += 2; + blocklength -= 2; + + samplespeed = 256000000L / ( 65536 - tc ); + + // Skip packed or stereo data + if ( ( packtype != 0 ) || ( voicemode != 0 ) ) + { + ptr += blocklength; + } + else + { + done = TRUE; + } + voicemode = 0; + break; + + case 2 : + // Sound continuation block + samplespeed = voice->SamplingRate; + done = TRUE; + break; + + case 3 : + // Silence + // Not implimented. + ptr += blocklength; + break; + + case 4 : + // Marker + // Not implimented. + ptr += blocklength; + break; + + case 5 : + // ASCII string + // Not implimented. + ptr += blocklength; + break; + + case 6 : + // Repeat begin + if ( voice->LoopEnd == NULL ) + { + voice->LoopCount = get_le16(ptr); + voice->LoopStart = ptr + blocklength; + } + ptr += blocklength; + break; + + case 7 : + // Repeat end + ptr += blocklength; + if ( lastblocktype == 6 ) + { + voice->LoopCount = 0; + } + else + { + if ( ( voice->LoopCount > 0 ) && ( voice->LoopStart != NULL ) ) + { + ptr = voice->LoopStart; + if ( voice->LoopCount < 0xffff ) + { + voice->LoopCount--; + if ( voice->LoopCount == 0 ) + { + voice->LoopStart = NULL; + } + } + } + } + break; + + case 8 : + // Extended block + voice->bits = 8; + tc = get_le16(ptr); + packtype = *( ptr + 2 ); + voicemode = *( ptr + 3 ); + ptr += blocklength; + break; + + case 9 : + // New sound data block + samplespeed = get_le32(ptr); + BitsPerSample = ptr[4]; + Channels = ptr[5]; + Format = get_le16(ptr+6); + + if ( ( BitsPerSample == 8 ) && ( Channels == 1 ) && + ( Format == VOC_8BIT ) ) + { + ptr += 12; + blocklength -= 12; + voice->bits = 8; + done = TRUE; + } + else if ( ( BitsPerSample == 16 ) && ( Channels == 1 ) && + ( Format == VOC_16BIT ) ) + { + ptr += 12; + blocklength -= 12; + voice->bits = 16; + done = TRUE; + } + else + { + ptr += blocklength; + } + break; + + default : + // Unknown data. Probably not a VOC file. + voice->Playing = FALSE; + done = TRUE; + break; + } + + lastblocktype = blocktype; + } + + if ( voice->Playing ) + { + voice->NextBlock = ptr + blocklength; + voice->sound = ptr; + + voice->SamplingRate = samplespeed; + voice->RateScale = ( voice->SamplingRate * voice->PitchScale ) / MV_MixRate; + + // Multiply by MixBufferSize - 1 + voice->FixedPointBufferSize = ( voice->RateScale * MixBufferSize ) - + voice->RateScale; + + if ( voice->LoopEnd != NULL ) + { + if ( blocklength > ( unsigned long )voice->LoopEnd ) + { + blocklength = ( unsigned long )voice->LoopEnd; + } + else + { + voice->LoopEnd = ( char * )blocklength; + } + + voice->LoopStart = voice->sound + ( unsigned long )voice->LoopStart; + voice->LoopEnd = voice->sound + ( unsigned long )voice->LoopEnd; + voice->LoopSize = voice->LoopEnd - voice->LoopStart; + } + + if ( voice->bits == 16 ) + { + blocklength /= 2; + } + + voice->position = 0; + voice->length = min( blocklength, 0x8000 ); + voice->BlockLength = blocklength - voice->length; + voice->length <<= 16; + + MV_SetVoiceMixMode( voice ); + + return( KeepPlaying ); + } + + return( NoMoreData ); + } + + +/*--------------------------------------------------------------------- + Function: MV_GetNextDemandFeedBlock + + Controls playback of demand fed data. +---------------------------------------------------------------------*/ + +playbackstatus MV_GetNextDemandFeedBlock + ( + VoiceNode *voice + ) + + { + if ( voice->BlockLength > 0 ) + { + voice->position -= voice->length; + voice->sound += voice->length >> 16; + voice->length = min( voice->BlockLength, 0x8000 ); + voice->BlockLength -= voice->length; + voice->length <<= 16; + + return( KeepPlaying ); + } + + if ( voice->DemandFeed == NULL ) + { + return( NoMoreData ); + } + + voice->position = 0; + ( voice->DemandFeed )( &voice->sound, &voice->BlockLength ); + voice->length = min( voice->BlockLength, 0x8000 ); + voice->BlockLength -= voice->length; + voice->length <<= 16; + + if ( ( voice->length > 0 ) && ( voice->sound != NULL ) ) + { + return( KeepPlaying ); + } + return( NoMoreData ); + } + + +/*--------------------------------------------------------------------- + Function: MV_GetNextRawBlock + + Controls playback of demand fed data. +---------------------------------------------------------------------*/ + +playbackstatus MV_GetNextRawBlock + ( + VoiceNode *voice + ) + + { + if ( voice->BlockLength <= 0 ) + { + if ( voice->LoopStart == NULL ) + { + voice->Playing = FALSE; + return( NoMoreData ); + } + + voice->BlockLength = voice->LoopSize; + voice->NextBlock = voice->LoopStart; + voice->length = 0; + voice->position = 0; + } + + voice->sound = voice->NextBlock; + voice->position -= voice->length; + voice->length = min( voice->BlockLength, 0x8000 ); + voice->NextBlock += voice->length; + if ( voice->bits == 16 ) + { + voice->NextBlock += voice->length; + } + voice->BlockLength -= voice->length; + voice->length <<= 16; + + return( KeepPlaying ); + } + + +/*--------------------------------------------------------------------- + Function: MV_GetNextWAVBlock + + Controls playback of demand fed data. +---------------------------------------------------------------------*/ + +playbackstatus MV_GetNextWAVBlock + ( + VoiceNode *voice + ) + + { + if ( voice->BlockLength <= 0 ) + { + if ( voice->LoopStart == NULL ) + { + voice->Playing = FALSE; + return( NoMoreData ); + } + + voice->BlockLength = voice->LoopSize; + voice->NextBlock = voice->LoopStart; + voice->length = 0; + voice->position = 0; + } + + voice->sound = voice->NextBlock; + voice->position -= voice->length; + voice->length = min( voice->BlockLength, 0x8000 ); + voice->NextBlock += voice->length; + if ( voice->bits == 16 ) + { + voice->NextBlock += voice->length; + } + voice->BlockLength -= voice->length; + voice->length <<= 16; + + return( KeepPlaying ); + } + + +/*--------------------------------------------------------------------- + Function: MV_ServiceRecord + + Starts recording of the waiting buffer. +---------------------------------------------------------------------*/ + +static void MV_ServiceRecord + ( + void + ) + + { + if ( MV_RecordFunc ) + { + MV_RecordFunc( MV_MixBuffer[ 0 ] + MV_MixPage * MixBufferSize, + MixBufferSize ); + } + + // Toggle which buffer we'll mix next + MV_MixPage++; + if ( MV_MixPage >= NumberOfBuffers ) + { + MV_MixPage = 0; + } + } + + +/*--------------------------------------------------------------------- + Function: MV_GetVoice + + Locates the voice with the specified handle. +---------------------------------------------------------------------*/ + +VoiceNode *MV_GetVoice + ( + int handle + ) + + { + VoiceNode *voice; + unsigned flags; + + flags = DisableInterrupts(); + + for( voice = VoiceList.next; voice != &VoiceList; voice = voice->next ) + { + if ( handle == voice->handle ) + { + break; + } + } + + RestoreInterrupts( flags ); + + if ( voice == &VoiceList ) + { + MV_SetErrorCode( MV_VoiceNotFound ); + + // SBF - should this return null? + return NULL; + } + + return( voice ); + } + + +/*--------------------------------------------------------------------- + Function: MV_VoicePlaying + + Checks if the voice associated with the specified handle is + playing. +---------------------------------------------------------------------*/ + +int MV_VoicePlaying + ( + int handle + ) + + { + VoiceNode *voice; + + if ( !MV_Installed ) + { + MV_SetErrorCode( MV_NotInstalled ); + return( FALSE ); + } + + voice = MV_GetVoice( handle ); + + if ( voice == NULL ) + { + return( FALSE ); + } + + return( TRUE ); + } + + +/*--------------------------------------------------------------------- + Function: MV_KillAllVoices + + Stops output of all currently active voices. +---------------------------------------------------------------------*/ + +int MV_KillAllVoices + ( + void + ) + + { + if ( !MV_Installed ) + { + MV_SetErrorCode( MV_NotInstalled ); + return( MV_Error ); + } + + // Remove all the voices from the list + while( VoiceList.next != &VoiceList ) + { + MV_Kill( VoiceList.next->handle ); + } + + return( MV_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: MV_Kill + + Stops output of the voice associated with the specified handle. +---------------------------------------------------------------------*/ + +int MV_Kill + ( + int handle + ) + + { + VoiceNode *voice; + unsigned flags; + unsigned long callbackval; + + if ( !MV_Installed ) + { + MV_SetErrorCode( MV_NotInstalled ); + return( MV_Error ); + } + + flags = DisableInterrupts(); + + voice = MV_GetVoice( handle ); + if ( voice == NULL ) + { + RestoreInterrupts( flags ); + MV_SetErrorCode( MV_VoiceNotFound ); + return( MV_Error ); + } + + callbackval = voice->callbackval; + + MV_StopVoice( voice ); + + RestoreInterrupts( flags ); + + if ( MV_CallBackFunc ) + { + MV_CallBackFunc( callbackval ); + } + + return( MV_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: MV_VoicesPlaying + + Determines the number of currently active voices. +---------------------------------------------------------------------*/ + +int MV_VoicesPlaying + ( + void + ) + + { + VoiceNode *voice; + int NumVoices = 0; + unsigned flags; + + if ( !MV_Installed ) + { + MV_SetErrorCode( MV_NotInstalled ); + return( 0 ); + } + + flags = DisableInterrupts(); + + for( voice = VoiceList.next; voice != &VoiceList; voice = voice->next ) + { + NumVoices++; + } + + RestoreInterrupts( flags ); + + return( NumVoices ); + } + + +/*--------------------------------------------------------------------- + Function: MV_AllocVoice + + Retrieve an inactive or lower priority voice for output. +---------------------------------------------------------------------*/ + +VoiceNode *MV_AllocVoice + ( + int priority + ) + + { + VoiceNode *voice; + VoiceNode *node; + unsigned flags; + +//return( NULL ); + if ( MV_Recording ) + { + return( NULL ); + } + + flags = DisableInterrupts(); + + // Check if we have any free voices + if ( LL_Empty( &VoicePool, next, prev ) ) + { + // check if we have a higher priority than a voice that is playing. + voice = VoiceList.next; + for( node = voice->next; node != &VoiceList; node = node->next ) + { + if ( node->priority < voice->priority ) + { + voice = node; + } + } + + if ( priority >= voice->priority ) + { + MV_Kill( voice->handle ); + } + } + + // Check if any voices are in the voice pool + if ( LL_Empty( &VoicePool, next, prev ) ) + { + // No free voices + RestoreInterrupts( flags ); + return( NULL ); + } + + voice = VoicePool.next; + LL_Remove( voice, next, prev ); + RestoreInterrupts( flags ); + + // Find a free voice handle + do + { + MV_VoiceHandle++; + if ( MV_VoiceHandle < MV_MinVoiceHandle ) + { + MV_VoiceHandle = MV_MinVoiceHandle; + } + } + while( MV_VoicePlaying( MV_VoiceHandle ) ); + + voice->handle = MV_VoiceHandle; + + return( voice ); + } + + +/*--------------------------------------------------------------------- + Function: MV_VoiceAvailable + + Checks if a voice can be play at the specified priority. +---------------------------------------------------------------------*/ + +int MV_VoiceAvailable + ( + int priority + ) + + { + VoiceNode *voice; + VoiceNode *node; + unsigned flags; + + // Check if we have any free voices + if ( !LL_Empty( &VoicePool, next, prev ) ) + { + return( TRUE ); + } + + flags = DisableInterrupts(); + + // check if we have a higher priority than a voice that is playing. + voice = VoiceList.next; + for( node = VoiceList.next; node != &VoiceList; node = node->next ) + { + if ( node->priority < voice->priority ) + { + voice = node; + } + } + + RestoreInterrupts( flags ); + + if ( ( voice != &VoiceList ) && ( priority >= voice->priority ) ) + { + return( TRUE ); + } + + return( FALSE ); + } + + +/*--------------------------------------------------------------------- + Function: MV_SetVoicePitch + + Sets the pitch for the specified voice. +---------------------------------------------------------------------*/ + +void MV_SetVoicePitch + ( + VoiceNode *voice, + unsigned long rate, + int pitchoffset + ) + + { + voice->SamplingRate = rate; + voice->PitchScale = PITCH_GetScale( pitchoffset ); + voice->RateScale = ( rate * voice->PitchScale ) / MV_MixRate; + + // Multiply by MixBufferSize - 1 + voice->FixedPointBufferSize = ( voice->RateScale * MixBufferSize ) - + voice->RateScale; + } + + +/*--------------------------------------------------------------------- + Function: MV_SetPitch + + Sets the pitch for the voice associated with the specified handle. +---------------------------------------------------------------------*/ + +int MV_SetPitch + ( + int handle, + int pitchoffset + ) + + { + VoiceNode *voice; + + if ( !MV_Installed ) + { + MV_SetErrorCode( MV_NotInstalled ); + return( MV_Error ); + } + + voice = MV_GetVoice( handle ); + if ( voice == NULL ) + { + MV_SetErrorCode( MV_VoiceNotFound ); + return( MV_Error ); + } + + MV_SetVoicePitch( voice, voice->SamplingRate, pitchoffset ); + + return( MV_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: MV_SetFrequency + + Sets the frequency for the voice associated with the specified handle. +---------------------------------------------------------------------*/ + +int MV_SetFrequency + ( + int handle, + int frequency + ) + + { + VoiceNode *voice; + + if ( !MV_Installed ) + { + MV_SetErrorCode( MV_NotInstalled ); + return( MV_Error ); + } + + voice = MV_GetVoice( handle ); + if ( voice == NULL ) + { + MV_SetErrorCode( MV_VoiceNotFound ); + return( MV_Error ); + } + + MV_SetVoicePitch( voice, frequency, 0 ); + + return( MV_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: MV_GetVolumeTable + + Returns a pointer to the volume table associated with the specified + volume. +---------------------------------------------------------------------*/ + +static short *MV_GetVolumeTable + ( + int vol + ) + + { + int volume; + short *table; + + volume = MIX_VOLUME( vol ); + + table = (short *)&MV_VolumeTable[ volume ]; + + return( table ); + } + + +/*--------------------------------------------------------------------- + Function: MV_SetVoiceMixMode + + Selects which method should be used to mix the voice. +---------------------------------------------------------------------*/ + +static void MV_SetVoiceMixMode + ( + VoiceNode *voice + ) + + { + unsigned flags; + int test; + + flags = DisableInterrupts(); + + test = T_DEFAULT; + if ( MV_Bits == 8 ) + { + test |= T_8BITS; + } + + if ( voice->bits == 16 ) + { + test |= T_16BITSOURCE; + } + + if ( MV_Channels == 1 ) + { + test |= T_MONO; + } + else + { + if ( IS_QUIET( voice->RightVolume ) ) + { + test |= T_RIGHTQUIET; + } + else if ( IS_QUIET( voice->LeftVolume ) ) + { + test |= T_LEFTQUIET; + } + } + + // Default case + voice->mix = MV_Mix8BitMono; + + switch( test ) + { + case T_8BITS | T_MONO | T_16BITSOURCE : + voice->mix = MV_Mix8BitMono16; + break; + + case T_8BITS | T_MONO : + voice->mix = MV_Mix8BitMono; + break; + + case T_8BITS | T_16BITSOURCE | T_LEFTQUIET : + MV_LeftVolume = MV_RightVolume; + voice->mix = MV_Mix8BitMono16; + break; + + case T_8BITS | T_LEFTQUIET : + MV_LeftVolume = MV_RightVolume; + voice->mix = MV_Mix8BitMono; + break; + + case T_8BITS | T_16BITSOURCE | T_RIGHTQUIET : + voice->mix = MV_Mix8BitMono16; + break; + + case T_8BITS | T_RIGHTQUIET : + voice->mix = MV_Mix8BitMono; + break; + + case T_8BITS | T_16BITSOURCE : + voice->mix = MV_Mix8BitStereo16; + break; + + case T_8BITS : + voice->mix = MV_Mix8BitStereo; + break; + + case T_MONO | T_16BITSOURCE : + voice->mix = MV_Mix16BitMono16; + break; + + case T_MONO : + voice->mix = MV_Mix16BitMono; + break; + + case T_16BITSOURCE | T_LEFTQUIET : + MV_LeftVolume = MV_RightVolume; + voice->mix = MV_Mix16BitMono16; + break; + + case T_LEFTQUIET : + MV_LeftVolume = MV_RightVolume; + voice->mix = MV_Mix16BitMono; + break; + + case T_16BITSOURCE | T_RIGHTQUIET : + voice->mix = MV_Mix16BitMono16; + break; + + case T_RIGHTQUIET : + voice->mix = MV_Mix16BitMono; + break; + + case T_16BITSOURCE : + voice->mix = MV_Mix16BitStereo16; + break; + + case T_SIXTEENBIT_STEREO : + voice->mix = MV_Mix16BitStereo; + break; + + default : + voice->mix = MV_Mix8BitMono; + } + + RestoreInterrupts( flags ); + } + + +/*--------------------------------------------------------------------- + Function: MV_SetVoiceVolume + + Sets the stereo and mono volume level of the voice associated + with the specified handle. +---------------------------------------------------------------------*/ + +void MV_SetVoiceVolume + ( + VoiceNode *voice, + int vol, + int left, + int right + ) + + { + if ( MV_Channels == 1 ) + { + left = vol; + right = vol; + } + + if ( MV_SwapLeftRight ) + { + // SBPro uses reversed panning + voice->LeftVolume = MV_GetVolumeTable( right ); + voice->RightVolume = MV_GetVolumeTable( left ); + } + else + { + voice->LeftVolume = MV_GetVolumeTable( left ); + voice->RightVolume = MV_GetVolumeTable( right ); + } + + MV_SetVoiceMixMode( voice ); + } + + +/*--------------------------------------------------------------------- + Function: MV_EndLooping + + Stops the voice associated with the specified handle from looping + without stoping the sound. +---------------------------------------------------------------------*/ + +int MV_EndLooping + ( + int handle + ) + + { + VoiceNode *voice; + unsigned flags; + + if ( !MV_Installed ) + { + MV_SetErrorCode( MV_NotInstalled ); + return( MV_Error ); + } + + flags = DisableInterrupts(); + + voice = MV_GetVoice( handle ); + if ( voice == NULL ) + { + RestoreInterrupts( flags ); + MV_SetErrorCode( MV_VoiceNotFound ); + return( MV_Warning ); + } + + voice->LoopCount = 0; + voice->LoopStart = NULL; + voice->LoopEnd = NULL; + + RestoreInterrupts( flags ); + + return( MV_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: MV_SetPan + + Sets the stereo and mono volume level of the voice associated + with the specified handle. +---------------------------------------------------------------------*/ + +int MV_SetPan + ( + int handle, + int vol, + int left, + int right + ) + + { + VoiceNode *voice; + + if ( !MV_Installed ) + { + MV_SetErrorCode( MV_NotInstalled ); + return( MV_Error ); + } + + voice = MV_GetVoice( handle ); + if ( voice == NULL ) + { + MV_SetErrorCode( MV_VoiceNotFound ); + return( MV_Warning ); + } + + MV_SetVoiceVolume( voice, vol, left, right ); + + return( MV_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: MV_Pan3D + + Set the angle and distance from the listener of the voice associated + with the specified handle. +---------------------------------------------------------------------*/ + +int MV_Pan3D + ( + int handle, + int angle, + int distance + ) + + { + int left; + int right; + int mid; + int volume; + int status; + + if ( distance < 0 ) + { + distance = -distance; + angle += MV_NumPanPositions / 2; + } + + volume = MIX_VOLUME( distance ); + + // Ensure angle is within 0 - 31 + angle &= MV_MaxPanPosition; + + left = MV_PanTable[ angle ][ volume ].left; + right = MV_PanTable[ angle ][ volume ].right; + mid = max( 0, 255 - distance ); + + status = MV_SetPan( handle, mid, left, right ); + + return( status ); + } + + +/*--------------------------------------------------------------------- + Function: MV_SetReverb + + Sets the level of reverb to add to mix. +---------------------------------------------------------------------*/ + +void MV_SetReverb + ( + int reverb + ) + + { + MV_ReverbLevel = MIX_VOLUME( reverb ); + MV_ReverbTable = &MV_VolumeTable[ MV_ReverbLevel ]; + } + + +/*--------------------------------------------------------------------- + Function: MV_SetFastReverb + + Sets the level of reverb to add to mix. +---------------------------------------------------------------------*/ + +void MV_SetFastReverb + ( + int reverb + ) + + { + MV_ReverbLevel = max( 0, min( 16, reverb ) ); + MV_ReverbTable = NULL; + } + + +/*--------------------------------------------------------------------- + Function: MV_GetMaxReverbDelay + + Returns the maximum delay time for reverb. +---------------------------------------------------------------------*/ + +int MV_GetMaxReverbDelay + ( + void + ) + + { + int maxdelay; + + maxdelay = MixBufferSize * MV_NumberOfBuffers; + + return maxdelay; + } + + +/*--------------------------------------------------------------------- + Function: MV_GetReverbDelay + + Returns the current delay time for reverb. +---------------------------------------------------------------------*/ + +int MV_GetReverbDelay + ( + void + ) + + { + return MV_ReverbDelay / MV_SampleSize; + } + + +/*--------------------------------------------------------------------- + Function: MV_SetReverbDelay + + Sets the delay level of reverb to add to mix. +---------------------------------------------------------------------*/ + +void MV_SetReverbDelay + ( + int delay + ) + + { + int maxdelay; + + maxdelay = MV_GetMaxReverbDelay(); + MV_ReverbDelay = max( MixBufferSize, min( delay, maxdelay ) ); + MV_ReverbDelay *= MV_SampleSize; + } + + +/*--------------------------------------------------------------------- + Function: MV_SetMixMode + + Prepares Multivoc to play stereo of mono digitized sounds. +---------------------------------------------------------------------*/ + +int MV_SetMixMode + ( + int numchannels, + int samplebits + ) + + { + int mode; + + if ( !MV_Installed ) + { + MV_SetErrorCode( MV_NotInstalled ); + return( MV_Error ); + } + + mode = 0; + if ( numchannels == 2 ) + { + mode |= STEREO; + } + if ( samplebits == 16 ) + { + mode |= SIXTEEN_BIT; + } + +#ifdef PLAT_DOS + switch( MV_SoundCard ) + { + case UltraSound : + MV_MixMode = mode; + break; + + case SoundBlaster : + case Awe32 : + MV_MixMode = BLASTER_SetMixMode( mode ); + break; + + case ProAudioSpectrum : + case SoundMan16 : + MV_MixMode = PAS_SetMixMode( mode ); + break; + + case SoundScape : + MV_MixMode = SOUNDSCAPE_SetMixMode( mode ); + break; + + #ifndef SOUNDSOURCE_OFF + case SoundSource : + case TandySoundSource : + MV_MixMode = SS_SetMixMode( mode ); + break; + #endif + } +#else + MV_MixMode = mode; +#endif + + MV_Channels = 1; + if ( MV_MixMode & STEREO ) + { + MV_Channels = 2; + } + + MV_Bits = 8; + if ( MV_MixMode & SIXTEEN_BIT ) + { + MV_Bits = 16; + } + + MV_BuffShift = 7 + MV_Channels; + MV_SampleSize = sizeof( MONO8 ) * MV_Channels; + + if ( MV_Bits == 8 ) + { + MV_Silence = SILENCE_8BIT; + } + else + { + MV_Silence = SILENCE_16BIT; + MV_BuffShift += 1; + MV_SampleSize *= 2; + } + + MV_BufferSize = MixBufferSize * MV_SampleSize; + MV_NumberOfBuffers = TotalBufferSize / MV_BufferSize; + MV_BufferLength = TotalBufferSize; + + MV_RightChannelOffset = MV_SampleSize / 2; + if ( ( MV_SoundCard == UltraSound ) && ( MV_Channels == 2 ) ) + { + MV_SampleSize /= 2; + MV_BufferSize /= 2; + MV_RightChannelOffset = MV_BufferSize * MV_NumberOfBuffers; + MV_BufferLength /= 2; + } + + return( MV_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: MV_StartPlayback + + Starts the sound playback engine. +---------------------------------------------------------------------*/ + +int MV_StartPlayback + ( + void + ) + + { + int status; + int buffer; + + // Initialize the buffers + ClearBuffer_DW( MV_MixBuffer[ 0 ], MV_Silence, TotalBufferSize >> 2 ); + for( buffer = 0; buffer < MV_NumberOfBuffers; buffer++ ) + { + MV_BufferEmpty[ buffer ] = TRUE; + } + + // Set the mix buffer variables + MV_MixPage = 1; + + MV_MixFunction = MV_Mix; + +//JIM +// MV_MixRate = MV_RequestedMixRate; +// return( MV_Ok ); + + // Start playback +#ifdef PLAT_DOS + switch( MV_SoundCard ) + { + case SoundBlaster : + case Awe32 : + status = BLASTER_BeginBufferedPlayback( MV_MixBuffer[ 0 ], + TotalBufferSize, MV_NumberOfBuffers, + MV_RequestedMixRate, MV_MixMode, MV_ServiceVoc ); + + if ( status != BLASTER_Ok ) + { + MV_SetErrorCode( MV_BlasterError ); + return( MV_Error ); + } + + MV_MixRate = BLASTER_GetPlaybackRate(); + MV_DMAChannel = BLASTER_DMAChannel; + break; + + case UltraSound : + + status = GUSWAVE_StartDemandFeedPlayback( MV_ServiceGus, 1, + MV_Bits, MV_RequestedMixRate, 0, ( MV_Channels == 1 ) ? + 0 : 24, 255, 0xffff, 0 ); + if ( status < GUSWAVE_Ok ) + { + MV_SetErrorCode( MV_BlasterError ); + return( MV_Error ); + } + + if ( MV_Channels == 2 ) + { + status = GUSWAVE_StartDemandFeedPlayback( MV_ServiceRightGus, 1, + MV_Bits, MV_RequestedMixRate, 0, 8, 255, 0xffff, 0 ); + if ( status < GUSWAVE_Ok ) + { + GUSWAVE_KillAllVoices(); + MV_SetErrorCode( MV_BlasterError ); + return( MV_Error ); + } + } + + MV_MixRate = MV_RequestedMixRate; + MV_DMAChannel = -1; + break; + + case ProAudioSpectrum : + case SoundMan16 : + status = PAS_BeginBufferedPlayback( MV_MixBuffer[ 0 ], + TotalBufferSize, MV_NumberOfBuffers, + MV_RequestedMixRate, MV_MixMode, MV_ServiceVoc ); + + if ( status != PAS_Ok ) + { + MV_SetErrorCode( MV_PasError ); + return( MV_Error ); + } + + MV_MixRate = PAS_GetPlaybackRate(); + MV_DMAChannel = PAS_DMAChannel; + break; + + case SoundScape : + status = SOUNDSCAPE_BeginBufferedPlayback( MV_MixBuffer[ 0 ], + TotalBufferSize, MV_NumberOfBuffers, MV_RequestedMixRate, + MV_MixMode, MV_ServiceVoc ); + + if ( status != SOUNDSCAPE_Ok ) + { + MV_SetErrorCode( MV_SoundScapeError ); + return( MV_Error ); + } + + MV_MixRate = SOUNDSCAPE_GetPlaybackRate(); + MV_DMAChannel = SOUNDSCAPE_DMAChannel; + break; + + #ifndef SOUNDSOURCE_OFF + case SoundSource : + case TandySoundSource : + SS_BeginBufferedPlayback( MV_MixBuffer[ 0 ], + TotalBufferSize, MV_NumberOfBuffers, + MV_ServiceVoc ); + MV_MixRate = SS_SampleRate; + MV_DMAChannel = -1; + break; + #endif + } +#else + status = DSL_BeginBufferedPlayback( MV_MixBuffer[ 0 ], + TotalBufferSize, MV_NumberOfBuffers, + MV_RequestedMixRate, MV_MixMode, MV_ServiceVoc ); + + if ( status != DSL_Ok ) + { + MV_SetErrorCode( MV_BlasterError ); + return( MV_Error ); + } + + MV_MixRate = DSL_GetPlaybackRate(); +#endif + + return( MV_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: MV_StopPlayback + + Stops the sound playback engine. +---------------------------------------------------------------------*/ + +void MV_StopPlayback + ( + void + ) + + { + VoiceNode *voice; + VoiceNode *next; + unsigned flags; + +#ifdef PLAT_DOS + // Stop sound playback + switch( MV_SoundCard ) + { + case SoundBlaster : + case Awe32 : + BLASTER_StopPlayback(); + break; + + case UltraSound : + GUSWAVE_KillAllVoices(); + break; + + case ProAudioSpectrum : + case SoundMan16 : + PAS_StopPlayback(); + break; + + case SoundScape : + SOUNDSCAPE_StopPlayback(); + break; + + #ifndef SOUNDSOURCE_OFF + case SoundSource : + case TandySoundSource : + SS_StopPlayback(); + break; + #endif + } +#else + DSL_StopPlayback(); +#endif + + // Make sure all callbacks are done. + flags = DisableInterrupts(); + + for( voice = VoiceList.next; voice != &VoiceList; voice = next ) + { + next = voice->next; + + MV_StopVoice( voice ); + + if ( MV_CallBackFunc ) + { + MV_CallBackFunc( voice->callbackval ); + } + } + + RestoreInterrupts( flags ); + } + + +/*--------------------------------------------------------------------- + Function: MV_StartRecording + + Starts the sound recording engine. +---------------------------------------------------------------------*/ + +int MV_StartRecording + ( + int MixRate, + void ( *function )( char *ptr, int length ) + ) + + { +#ifdef PLAT_DOS + int status; + + switch( MV_SoundCard ) + { + case SoundBlaster : + case Awe32 : + case ProAudioSpectrum : + case SoundMan16 : + break; + + default : + MV_SetErrorCode( MV_UnsupportedCard ); + return( MV_Error ); + break; + } + + if ( function == NULL ) + { + MV_SetErrorCode( MV_NullRecordFunction ); + return( MV_Error ); + } + + MV_StopPlayback(); + + // Initialize the buffers + ClearBuffer_DW( MV_MixBuffer[ 0 ], SILENCE_8BIT, TotalBufferSize >> 2 ); + + // Set the mix buffer variables + MV_MixPage = 0; + + MV_RecordFunc = function; + + // Start playback + switch( MV_SoundCard ) + { + case SoundBlaster : + case Awe32 : + status = BLASTER_BeginBufferedRecord( MV_MixBuffer[ 0 ], + TotalBufferSize, NumberOfBuffers, MixRate, MONO_8BIT, + MV_ServiceRecord ); + + if ( status != BLASTER_Ok ) + { + MV_SetErrorCode( MV_BlasterError ); + return( MV_Error ); + } + break; + + case ProAudioSpectrum : + case SoundMan16 : + status = PAS_BeginBufferedRecord( MV_MixBuffer[ 0 ], + TotalBufferSize, NumberOfBuffers, MixRate, MONO_8BIT, + MV_ServiceRecord ); + + if ( status != PAS_Ok ) + { + MV_SetErrorCode( MV_PasError ); + return( MV_Error ); + } + break; + } + + MV_Recording = TRUE; + return( MV_Ok ); +#else + MV_SetErrorCode( MV_UnsupportedCard ); + return( MV_Error ); +#endif + } + + +/*--------------------------------------------------------------------- + Function: MV_StopRecord + + Stops the sound record engine. +---------------------------------------------------------------------*/ + +void MV_StopRecord + ( + void + ) + + { +#ifdef PLAT_DOS + // Stop sound playback + switch( MV_SoundCard ) + { + case SoundBlaster : + case Awe32 : + BLASTER_StopPlayback(); + break; + + case ProAudioSpectrum : + case SoundMan16 : + PAS_StopPlayback(); + break; + } + + MV_Recording = FALSE; + MV_StartPlayback(); +#endif + } + + +/*--------------------------------------------------------------------- + Function: MV_StartDemandFeedPlayback + + Plays a digitized sound from a user controlled buffering system. +---------------------------------------------------------------------*/ + +int MV_StartDemandFeedPlayback + ( + void ( *function )( char **ptr, unsigned long *length ), + int rate, + int pitchoffset, + int vol, + int left, + int right, + int priority, + unsigned long callbackval + ) + + { + VoiceNode *voice; + + if ( !MV_Installed ) + { + MV_SetErrorCode( MV_NotInstalled ); + return( MV_Error ); + } + + // Request a voice from the voice pool + voice = MV_AllocVoice( priority ); + if ( voice == NULL ) + { + MV_SetErrorCode( MV_NoVoices ); + return( MV_Error ); + } + + voice->wavetype = DemandFeed; + voice->bits = 8; + voice->GetSound = MV_GetNextDemandFeedBlock; + voice->NextBlock = NULL; + voice->DemandFeed = function; + voice->LoopStart = NULL; + voice->LoopCount = 0; + voice->BlockLength = 0; + voice->position = 0; + voice->sound = NULL; + voice->length = 0; + voice->BlockLength = 0; + voice->Playing = TRUE; + voice->next = NULL; + voice->prev = NULL; + voice->priority = priority; + voice->callbackval = callbackval; + + MV_SetVoicePitch( voice, rate, pitchoffset ); + MV_SetVoiceVolume( voice, vol, left, right ); + MV_PlayVoice( voice ); + + return( voice->handle ); + } + + +/*--------------------------------------------------------------------- + Function: MV_PlayRaw + + Begin playback of sound data with the given sound levels and + priority. +---------------------------------------------------------------------*/ + +int MV_PlayRaw + ( + char *ptr, + unsigned long length, + unsigned rate, + int pitchoffset, + int vol, + int left, + int right, + int priority, + unsigned long callbackval + ) + + { + int status; + + status = MV_PlayLoopedRaw( ptr, length, NULL, NULL, rate, pitchoffset, + vol, left, right, priority, callbackval ); + + return( status ); + } + + +/*--------------------------------------------------------------------- + Function: MV_PlayLoopedRaw + + Begin playback of sound data with the given sound levels and + priority. +---------------------------------------------------------------------*/ + +int MV_PlayLoopedRaw + ( + char *ptr, + unsigned long length, + char *loopstart, + char *loopend, + unsigned rate, + int pitchoffset, + int vol, + int left, + int right, + int priority, + unsigned long callbackval + ) + + { + VoiceNode *voice; + + if ( !MV_Installed ) + { + MV_SetErrorCode( MV_NotInstalled ); + return( MV_Error ); + } + + // Request a voice from the voice pool + voice = MV_AllocVoice( priority ); + if ( voice == NULL ) + { + MV_SetErrorCode( MV_NoVoices ); + return( MV_Error ); + } + + voice->wavetype = Raw; + voice->bits = 8; + voice->GetSound = MV_GetNextRawBlock; + voice->Playing = TRUE; + voice->NextBlock = ptr; + voice->position = 0; + voice->BlockLength = length; + voice->length = 0; + voice->next = NULL; + voice->prev = NULL; + voice->priority = priority; + voice->callbackval = callbackval; + voice->LoopStart = loopstart; + voice->LoopEnd = loopend; + voice->LoopSize = ( voice->LoopEnd - voice->LoopStart ) + 1; + + MV_SetVoicePitch( voice, rate, pitchoffset ); + MV_SetVoiceVolume( voice, vol, left, right ); + MV_PlayVoice( voice ); + + return( voice->handle ); + } + + +/*--------------------------------------------------------------------- + Function: MV_PlayWAV + + Begin playback of sound data with the given sound levels and + priority. +---------------------------------------------------------------------*/ + +int MV_PlayWAV + ( + char *ptr, + int pitchoffset, + int vol, + int left, + int right, + int priority, + unsigned long callbackval + ) + + { + int status; + + status = MV_PlayLoopedWAV( ptr, -1, -1, pitchoffset, vol, left, right, + priority, callbackval ); + + return( status ); + } + + +/*--------------------------------------------------------------------- + Function: MV_PlayWAV3D + + Begin playback of sound data at specified angle and distance + from listener. +---------------------------------------------------------------------*/ + +int MV_PlayWAV3D + ( + char *ptr, + int pitchoffset, + int angle, + int distance, + int priority, + unsigned long callbackval + ) + + { + int left; + int right; + int mid; + int volume; + int status; + + if ( !MV_Installed ) + { + MV_SetErrorCode( MV_NotInstalled ); + return( MV_Error ); + } + + if ( distance < 0 ) + { + distance = -distance; + angle += MV_NumPanPositions / 2; + } + + volume = MIX_VOLUME( distance ); + + // Ensure angle is within 0 - 31 + angle &= MV_MaxPanPosition; + + left = MV_PanTable[ angle ][ volume ].left; + right = MV_PanTable[ angle ][ volume ].right; + mid = max( 0, 255 - distance ); + + status = MV_PlayWAV( ptr, pitchoffset, mid, left, right, priority, + callbackval ); + + return( status ); + } + + +/*--------------------------------------------------------------------- + Function: MV_PlayLoopedWAV + + Begin playback of sound data with the given sound levels and + priority. +---------------------------------------------------------------------*/ + +int MV_PlayLoopedWAV + ( + char *ptr, + long loopstart, + long loopend, + int pitchoffset, + int vol, + int left, + int right, + int priority, + unsigned long callbackval + ) + + { + riff_header *riff; + format_header *format; + data_header *data; + VoiceNode *voice; + int length; + int absloopend; + int absloopstart; + + if ( !MV_Installed ) + { + MV_SetErrorCode( MV_NotInstalled ); + return( MV_Error ); + } + + riff = ( riff_header * )ptr; + + if ( ( strncmp( riff->RIFF, "RIFF", 4 ) != 0 ) || + ( strncmp( riff->WAVE, "WAVE", 4 ) != 0 ) || + ( strncmp( riff->fmt, "fmt ", 4) != 0 ) ) + { + MV_SetErrorCode( MV_InvalidWAVFile ); + return( MV_Error ); + } + + format = ( format_header * )( riff + 1 ); + data = ( data_header * )( ( ( char * )format ) + riff->format_size ); + + // Check if it's PCM data. + if ( format->wFormatTag != 1 ) + { + MV_SetErrorCode( MV_InvalidWAVFile ); + return( MV_Error ); + } + + if ( format->nChannels != 1 ) + { + MV_SetErrorCode( MV_InvalidWAVFile ); + return( MV_Error ); + } + + if ( ( format->nBitsPerSample != 8 ) && + ( format->nBitsPerSample != 16 ) ) + { + MV_SetErrorCode( MV_InvalidWAVFile ); + return( MV_Error ); + } + + if ( strncmp( data->DATA, "data", 4 ) != 0 ) + { + MV_SetErrorCode( MV_InvalidWAVFile ); + return( MV_Error ); + } + + // Request a voice from the voice pool + voice = MV_AllocVoice( priority ); + if ( voice == NULL ) + { + MV_SetErrorCode( MV_NoVoices ); + return( MV_Error ); + } + + voice->wavetype = WAV; + voice->bits = format->nBitsPerSample; + voice->GetSound = MV_GetNextWAVBlock; + + length = data->size; + absloopstart = loopstart; + absloopend = loopend; + if ( voice->bits == 16 ) + { + loopstart *= 2; + data->size &= ~1; + loopend *= 2; + length /= 2; + } + + loopend = min( loopend, (long)data->size ); + absloopend = min( absloopend, length ); + + voice->Playing = TRUE; + voice->DemandFeed = NULL; + voice->LoopStart = NULL; + voice->LoopCount = 0; + voice->position = 0; + voice->length = 0; + voice->BlockLength = absloopend; + voice->NextBlock = ( char * )( data + 1 ); + voice->next = NULL; + voice->prev = NULL; + voice->priority = priority; + voice->callbackval = callbackval; + voice->LoopStart = voice->NextBlock + loopstart; + voice->LoopEnd = voice->NextBlock + loopend; + voice->LoopSize = absloopend - absloopstart; + + if ( ( loopstart >= (long)data->size ) || ( loopstart < 0 ) ) + { + voice->LoopStart = NULL; + voice->LoopEnd = NULL; + voice->BlockLength = length; + } + + MV_SetVoicePitch( voice, format->nSamplesPerSec, pitchoffset ); + MV_SetVoiceVolume( voice, vol, left, right ); + MV_PlayVoice( voice ); + + return( voice->handle ); + } + + +/*--------------------------------------------------------------------- + Function: MV_PlayVOC3D + + Begin playback of sound data at specified angle and distance + from listener. +---------------------------------------------------------------------*/ + +int MV_PlayVOC3D + ( + char *ptr, + int pitchoffset, + int angle, + int distance, + int priority, + unsigned long callbackval + ) + + { + int left; + int right; + int mid; + int volume; + int status; + + if ( !MV_Installed ) + { + MV_SetErrorCode( MV_NotInstalled ); + return( MV_Error ); + } + + if ( distance < 0 ) + { + distance = -distance; + angle += MV_NumPanPositions / 2; + } + + volume = MIX_VOLUME( distance ); + + // Ensure angle is within 0 - 31 + angle &= MV_MaxPanPosition; + + left = MV_PanTable[ angle ][ volume ].left; + right = MV_PanTable[ angle ][ volume ].right; + mid = max( 0, 255 - distance ); + + status = MV_PlayVOC( ptr, pitchoffset, mid, left, right, priority, + callbackval ); + + return( status ); + } + + +/*--------------------------------------------------------------------- + Function: MV_PlayVOC + + Begin playback of sound data with the given sound levels and + priority. +---------------------------------------------------------------------*/ + +int MV_PlayVOC + ( + char *ptr, + int pitchoffset, + int vol, + int left, + int right, + int priority, + unsigned long callbackval + ) + + { + int status; + + status = MV_PlayLoopedVOC( ptr, -1, -1, pitchoffset, vol, left, right, + priority, callbackval ); + + return( status ); + } + + +/*--------------------------------------------------------------------- + Function: MV_PlayLoopedVOC + + Begin playback of sound data with the given sound levels and + priority. +---------------------------------------------------------------------*/ + +int MV_PlayLoopedVOC + ( + char *ptr, + long loopstart, + long loopend, + int pitchoffset, + int vol, + int left, + int right, + int priority, + unsigned long callbackval + ) + + { + VoiceNode *voice; + int status; + unsigned short nextpos; + + if ( !MV_Installed ) + { + MV_SetErrorCode( MV_NotInstalled ); + return( MV_Error ); + } + + // Make sure it's a valid VOC file. + status = strncmp( ptr, "Creative Voice File", 19 ); + if ( status != 0 ) + { + MV_SetErrorCode( MV_InvalidVOCFile ); + return( MV_Error ); + } + + // Request a voice from the voice pool + voice = MV_AllocVoice( priority ); + if ( voice == NULL ) + { + MV_SetErrorCode( MV_NoVoices ); + return( MV_Error ); + } + + voice->wavetype = VOC; + voice->bits = 8; + voice->GetSound = MV_GetNextVOCBlock; + + nextpos = *( unsigned short * )( ptr + 0x14 ); + voice->NextBlock = ptr + BUILDSWAP_INTEL16(nextpos); + + voice->DemandFeed = NULL; + voice->LoopStart = NULL; + voice->LoopCount = 0; + voice->BlockLength = 0; + voice->PitchScale = PITCH_GetScale( pitchoffset ); + voice->length = 0; + voice->next = NULL; + voice->prev = NULL; + voice->priority = priority; + voice->callbackval = callbackval; + voice->LoopStart = ( char * )loopstart; + voice->LoopEnd = ( char * )loopend; + voice->LoopSize = loopend - loopstart + 1; + + if ( loopstart < 0 ) + { + voice->LoopStart = NULL; + voice->LoopEnd = NULL; + } + + MV_SetVoiceVolume( voice, vol, left, right ); + MV_PlayVoice( voice ); + + return( voice->handle ); + } + + +/*--------------------------------------------------------------------- + Function: MV_LockEnd + + Used for determining the length of the functions to lock in memory. +---------------------------------------------------------------------*/ + +static void MV_LockEnd + ( + void + ) + + { + } + + +/*--------------------------------------------------------------------- + Function: MV_CreateVolumeTable + + Create the table used to convert sound data to a specific volume + level. +---------------------------------------------------------------------*/ + +void MV_CreateVolumeTable + ( + int index, + int volume, + int MaxVolume + ) + + { + int val; + int level; + int i; + + level = ( volume * MaxVolume ) / MV_MaxTotalVolume; + if ( MV_Bits == 16 ) + { + for( i = 0; i < 65536; i += 256 ) + { + val = i - 0x8000; + val *= level; + val /= MV_MaxVolume; + MV_VolumeTable[ index ][ i / 256 ] = val; + } + } + else + { + for( i = 0; i < 256; i++ ) + { + val = i - 0x80; + val *= level; + val /= MV_MaxVolume; + MV_VolumeTable[ volume ][ i ] = val; + } + } + } + + +/*--------------------------------------------------------------------- + Function: MV_CalcVolume + + Create the table used to convert sound data to a specific volume + level. +---------------------------------------------------------------------*/ + +void MV_CalcVolume + ( + int MaxVolume + ) + + { + int volume; + + for( volume = 0; volume < 128; volume++ ) + { + MV_HarshClipTable[ volume ] = 0; + MV_HarshClipTable[ volume + 384 ] = 255; + } + for( volume = 0; volume < 256; volume++ ) + { + MV_HarshClipTable[ volume + 128 ] = volume; + } + + // For each volume level, create a translation table with the + // appropriate volume calculated. + for( volume = 0; volume <= MV_MaxVolume; volume++ ) + { + MV_CreateVolumeTable( volume, volume, MaxVolume ); + } + } + + +/*--------------------------------------------------------------------- + Function: MV_CalcPanTable + + Create the table used to determine the stereo volume level of + a sound located at a specific angle and distance from the listener. +---------------------------------------------------------------------*/ + +void MV_CalcPanTable + ( + void + ) + + { + int level; + int angle; + int distance; + int HalfAngle; + int ramp; + + HalfAngle = ( MV_NumPanPositions / 2 ); + + for( distance = 0; distance <= MV_MaxVolume; distance++ ) + { + level = ( 255 * ( MV_MaxVolume - distance ) ) / MV_MaxVolume; + for( angle = 0; angle <= HalfAngle / 2; angle++ ) + { + ramp = level - ( ( level * angle ) / + ( MV_NumPanPositions / 4 ) ); + + MV_PanTable[ angle ][ distance ].left = ramp; + MV_PanTable[ HalfAngle - angle ][ distance ].left = ramp; + MV_PanTable[ HalfAngle + angle ][ distance ].left = level; + MV_PanTable[ MV_MaxPanPosition - angle ][ distance ].left = level; + + MV_PanTable[ angle ][ distance ].right = level; + MV_PanTable[ HalfAngle - angle ][ distance ].right = level; + MV_PanTable[ HalfAngle + angle ][ distance ].right = ramp; + MV_PanTable[ MV_MaxPanPosition - angle ][ distance ].right = ramp; + } + } + } + + +/*--------------------------------------------------------------------- + Function: MV_SetVolume + + Sets the volume of digitized sound playback. +---------------------------------------------------------------------*/ + +void MV_SetVolume + ( + int volume + ) + + { + volume = max( 0, volume ); + volume = min( volume, MV_MaxTotalVolume ); + + MV_TotalVolume = volume; + + // Calculate volume table + MV_CalcVolume( volume ); + } + + +/*--------------------------------------------------------------------- + Function: MV_GetVolume + + Returns the volume of digitized sound playback. +---------------------------------------------------------------------*/ + +int MV_GetVolume + ( + void + ) + + { + return( MV_TotalVolume ); + } + + +/*--------------------------------------------------------------------- + Function: MV_SetCallBack + + Set the function to call when a voice stops. +---------------------------------------------------------------------*/ + +void MV_SetCallBack + ( + void ( *function )( unsigned long ) + ) + + { + MV_CallBackFunc = function; + } + + +/*--------------------------------------------------------------------- + Function: MV_SetReverseStereo + + Set the orientation of the left and right channels. +---------------------------------------------------------------------*/ + +void MV_SetReverseStereo + ( + int setting + ) + + { + MV_SwapLeftRight = setting; + } + + +/*--------------------------------------------------------------------- + Function: MV_GetReverseStereo + + Returns the orientation of the left and right channels. +---------------------------------------------------------------------*/ + +int MV_GetReverseStereo + ( + void + ) + + { + return( MV_SwapLeftRight ); + } + + +/*--------------------------------------------------------------------- + Function: MV_TestPlayback + + Checks if playback has started. +---------------------------------------------------------------------*/ + +int MV_TestPlayback + ( + void + ) + + { +#ifdef PLAT_DOS + unsigned flags; + long time; + int start; + int status; + int pos; + + if ( MV_SoundCard == UltraSound ) + { + return( MV_Ok ); + } + + flags = DisableInterrupts(); + _enable(); + + status = MV_Error; + start = MV_MixPage; + time = clock() + CLOCKS_PER_SEC * 2; + + while( clock() < time ) + { + if ( MV_MixPage != start ) + { + status = MV_Ok; + } + } + + RestoreInterrupts( flags ); + + if ( status != MV_Ok ) + { + // Just in case an error doesn't get reported + MV_SetErrorCode( MV_DMAFailure ); + + switch( MV_SoundCard ) + { + case SoundBlaster : + case Awe32 : + pos = BLASTER_GetCurrentPos(); + break; + + case ProAudioSpectrum : + case SoundMan16 : + pos = PAS_GetCurrentPos(); + break; + + case SoundScape : + pos = SOUNDSCAPE_GetCurrentPos(); + break; + + #ifndef SOUNDSOURCE_OFF + case SoundSource : + case TandySoundSource : + MV_SetErrorCode( MV_SoundSourceFailure ); + pos = -1; + break; + #endif + + default : + MV_SetErrorCode( MV_UnsupportedCard ); + pos = -2; + break; + } + + if ( pos > 0 ) + { + MV_SetErrorCode( MV_IrqFailure ); + } + else if ( pos == 0 ) + { + if ( MV_Bits == 16 ) + { + MV_SetErrorCode( MV_DMA16Failure ); + } + else + { + MV_SetErrorCode( MV_DMAFailure ); + } + } + } + + return( status ); +#else + return MV_Ok; +#endif + } + + +/*--------------------------------------------------------------------- + Function: MV_Init + + Perform the initialization of variables and memory used by + Multivoc. +---------------------------------------------------------------------*/ + +int MV_Init + ( + int soundcard, + int MixRate, + int Voices, + int numchannels, + int samplebits + ) + + { + char *ptr; + int status; + int buffer; + int index; + + if ( MV_Installed ) + { + MV_Shutdown(); + } + + MV_SetErrorCode( MV_Ok ); + + status = MV_LockMemory(); + if ( status != MV_Ok ) + { + return( status ); + } + + MV_TotalMemory = Voices * sizeof( VoiceNode ) + sizeof( HARSH_CLIP_TABLE_8 ); + status = USRHOOKS_GetMem( ( void ** )&ptr, MV_TotalMemory ); + if ( status != USRHOOKS_Ok ) + { + MV_UnlockMemory(); + MV_SetErrorCode( MV_NoMem ); + return( MV_Error ); + } + + status = DPMI_LockMemory( ptr, MV_TotalMemory ); + if ( status != DPMI_Ok ) + { + USRHOOKS_FreeMem( ptr ); + MV_UnlockMemory(); + MV_SetErrorCode( MV_DPMI_Error ); + return( MV_Error ); + } + + MV_Voices = ( VoiceNode * )ptr; + MV_HarshClipTable = ptr + ( MV_TotalMemory - sizeof( HARSH_CLIP_TABLE_8 ) ); + + // Set number of voices before calculating volume table + MV_MaxVoices = Voices; + + LL_Reset( (VoiceNode *)&VoiceList, next, prev ); + LL_Reset( (VoiceNode *)&VoicePool, next, prev ); + + for( index = 0; index < Voices; index++ ) + { + LL_Add( (VoiceNode *)&VoicePool, &MV_Voices[ index ], next, prev ); + } + + // Allocate mix buffer within 1st megabyte + status = DPMI_GetDOSMemory( ( void ** )&ptr, &MV_BufferDescriptor, + 2 * TotalBufferSize ); + + if ( status ) + { + DPMI_UnlockMemory( MV_Voices, MV_TotalMemory ); + USRHOOKS_FreeMem( MV_Voices ); + MV_Voices = NULL; + MV_TotalMemory = 0; + MV_UnlockMemory(); + + MV_SetErrorCode( MV_NoMem ); + return( MV_Error ); + } + + MV_SetReverseStereo( FALSE ); + + // Initialize the sound card +#ifdef PLAT_DOS + switch( soundcard ) + { + case UltraSound : + status = GUSWAVE_Init( 2 ); + if ( status != GUSWAVE_Ok ) + { + //JIM + MV_SetErrorCode( MV_BlasterError ); + } + break; + + case SoundBlaster : + case Awe32 : + status = BLASTER_Init(); + if ( status != BLASTER_Ok ) + { + MV_SetErrorCode( MV_BlasterError ); + } + + if ( ( BLASTER_Config.Type == SBPro ) || + ( BLASTER_Config.Type == SBPro2 ) ) + { + MV_SetReverseStereo( TRUE ); + } + break; + + case ProAudioSpectrum : + case SoundMan16 : + status = PAS_Init(); + if ( status != PAS_Ok ) + { + MV_SetErrorCode( MV_PasError ); + } + break; + + case SoundScape : + status = SOUNDSCAPE_Init(); + if ( status != SOUNDSCAPE_Ok ) + { + MV_SetErrorCode( MV_SoundScapeError ); + } + break; + + #ifndef SOUNDSOURCE_OFF + case SoundSource : + case TandySoundSource : + status = SS_Init( soundcard ); + if ( status != SS_Ok ) + { + MV_SetErrorCode( MV_SoundSourceError ); + } + break; + #endif + + default : + MV_SetErrorCode( MV_UnsupportedCard ); + break; + } +#else + status = DSL_Init(); + if ( status != DSL_Ok ) + { + MV_SetErrorCode( MV_BlasterError ); + } +#endif + + if ( MV_ErrorCode != MV_Ok ) + { + status = MV_ErrorCode; + + DPMI_UnlockMemory( MV_Voices, MV_TotalMemory ); + USRHOOKS_FreeMem( MV_Voices ); + MV_Voices = NULL; + MV_TotalMemory = 0; + + DPMI_FreeDOSMemory( MV_BufferDescriptor ); + MV_UnlockMemory(); + + MV_SetErrorCode( status ); + return( MV_Error ); + } + + MV_SoundCard = soundcard; + MV_Installed = TRUE; + MV_CallBackFunc = NULL; + MV_RecordFunc = NULL; + MV_Recording = FALSE; + MV_ReverbLevel = 0; + MV_ReverbTable = NULL; + + // Set the sampling rate + MV_RequestedMixRate = MixRate; + + // Set Mixer to play stereo digitized sound + MV_SetMixMode( numchannels, samplebits ); + MV_ReverbDelay = MV_BufferSize * 3; + +#ifdef PLAT_DOS + // Make sure we don't cross a physical page + if ( ( ( unsigned long )ptr & 0xffff ) + TotalBufferSize > 0x10000 ) + { + ptr = ( char * )( ( ( unsigned long )ptr & 0xff0000 ) + 0x10000 ); + } +#endif + + MV_MixBuffer[ MV_NumberOfBuffers ] = ptr; + for( buffer = 0; buffer < MV_NumberOfBuffers; buffer++ ) + { + MV_MixBuffer[ buffer ] = ptr; + ptr += MV_BufferSize; + } + + // Calculate pan table + MV_CalcPanTable(); + + MV_SetVolume( MV_MaxTotalVolume ); + + // Start the playback engine + status = MV_StartPlayback(); + if ( status != MV_Ok ) + { + // Preserve error code while we shutdown. + status = MV_ErrorCode; + MV_Shutdown(); + MV_SetErrorCode( status ); + return( MV_Error ); + } + + if ( MV_TestPlayback() != MV_Ok ) + { + status = MV_ErrorCode; + MV_Shutdown(); + MV_SetErrorCode( status ); + return( MV_Error ); + } + + return( MV_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: MV_Shutdown + + Restore any resources allocated by Multivoc back to the system. +---------------------------------------------------------------------*/ + +int MV_Shutdown + ( + void + ) + + { + int buffer; + unsigned flags; + + if ( !MV_Installed ) + { + return( MV_Ok ); + } + + flags = DisableInterrupts(); + + MV_KillAllVoices(); + + MV_Installed = FALSE; + + // Stop the sound recording engine + if ( MV_Recording ) + { + MV_StopRecord(); + } + + // Stop the sound playback engine + MV_StopPlayback(); + + // Shutdown the sound card +#ifdef PLAT_DOS + switch( MV_SoundCard ) + { + case UltraSound : + GUSWAVE_Shutdown(); + break; + + case SoundBlaster : + case Awe32 : + BLASTER_Shutdown(); + break; + + case ProAudioSpectrum : + case SoundMan16 : + PAS_Shutdown(); + break; + + case SoundScape : + SOUNDSCAPE_Shutdown(); + break; + + #ifndef SOUNDSOURCE_OFF + case SoundSource : + case TandySoundSource : + SS_Shutdown(); + break; + #endif + } +#else + DSL_Shutdown(); +#endif + + RestoreInterrupts( flags ); + + // Free any voices we allocated + DPMI_UnlockMemory( MV_Voices, MV_TotalMemory ); + USRHOOKS_FreeMem( MV_Voices ); + MV_Voices = NULL; + MV_TotalMemory = 0; + + LL_Reset( (VoiceNode *)&VoiceList, next, prev ); + LL_Reset( (VoiceNode *)&VoicePool, next, prev ); + + MV_MaxVoices = 1; + + // Release the descriptor from our mix buffer + DPMI_FreeDOSMemory( MV_BufferDescriptor ); + for( buffer = 0; buffer < NumberOfBuffers; buffer++ ) + { + MV_MixBuffer[ buffer ] = NULL; + } + + return( MV_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: MV_UnlockMemory + + Unlocks all neccessary data. +---------------------------------------------------------------------*/ + +void MV_UnlockMemory + ( + void + ) + + { + PITCH_UnlockMemory(); + + DPMI_UnlockMemoryRegion( MV_LockStart, MV_LockEnd ); + DPMI_Unlock( MV_VolumeTable ); + DPMI_Unlock( MV_PanTable ); + DPMI_Unlock( MV_Installed ); + DPMI_Unlock( MV_SoundCard ); + DPMI_Unlock( MV_TotalVolume ); + DPMI_Unlock( MV_MaxVoices ); + DPMI_Unlock( MV_BufferSize ); + DPMI_Unlock( MV_BufferLength ); + DPMI_Unlock( MV_SampleSize ); + DPMI_Unlock( MV_NumberOfBuffers ); + DPMI_Unlock( MV_MixMode ); + DPMI_Unlock( MV_Channels ); + DPMI_Unlock( MV_Bits ); + DPMI_Unlock( MV_Silence ); + DPMI_Unlock( MV_SwapLeftRight ); + DPMI_Unlock( MV_RequestedMixRate ); + DPMI_Unlock( MV_MixRate ); + DPMI_Unlock( MV_BufferDescriptor ); + DPMI_Unlock( MV_MixBuffer ); + DPMI_Unlock( MV_BufferEmpty ); + DPMI_Unlock( MV_Voices ); + DPMI_Unlock( VoiceList ); + DPMI_Unlock( VoicePool ); + DPMI_Unlock( MV_MixPage ); + DPMI_Unlock( MV_VoiceHandle ); + DPMI_Unlock( MV_CallBackFunc ); + DPMI_Unlock( MV_RecordFunc ); + DPMI_Unlock( MV_Recording ); + DPMI_Unlock( MV_MixFunction ); + DPMI_Unlock( MV_HarshClipTable ); + DPMI_Unlock( MV_MixDestination ); + DPMI_Unlock( MV_LeftVolume ); + DPMI_Unlock( MV_RightVolume ); + DPMI_Unlock( MV_MixPosition ); + DPMI_Unlock( MV_ErrorCode ); + DPMI_Unlock( MV_DMAChannel ); + DPMI_Unlock( MV_BuffShift ); + DPMI_Unlock( MV_ReverbLevel ); + DPMI_Unlock( MV_ReverbDelay ); + DPMI_Unlock( MV_ReverbTable ); + } + + +/*--------------------------------------------------------------------- + Function: MV_LockMemory + + Locks all neccessary data. +---------------------------------------------------------------------*/ + +int MV_LockMemory + ( + void + ) + + { + int status; + int pitchstatus; + + status = DPMI_LockMemoryRegion( MV_LockStart, MV_LockEnd ); + status |= DPMI_Lock( MV_VolumeTable ); + status |= DPMI_Lock( MV_PanTable ); + status |= DPMI_Lock( MV_Installed ); + status |= DPMI_Lock( MV_SoundCard ); + status |= DPMI_Lock( MV_TotalVolume ); + status |= DPMI_Lock( MV_MaxVoices ); + status |= DPMI_Lock( MV_BufferSize ); + status |= DPMI_Lock( MV_BufferLength ); + status |= DPMI_Lock( MV_SampleSize ); + status |= DPMI_Lock( MV_NumberOfBuffers ); + status |= DPMI_Lock( MV_MixMode ); + status |= DPMI_Lock( MV_Channels ); + status |= DPMI_Lock( MV_Bits ); + status |= DPMI_Lock( MV_Silence ); + status |= DPMI_Lock( MV_SwapLeftRight ); + status |= DPMI_Lock( MV_RequestedMixRate ); + status |= DPMI_Lock( MV_MixRate ); + status |= DPMI_Lock( MV_BufferDescriptor ); + status |= DPMI_Lock( MV_MixBuffer ); + status |= DPMI_Lock( MV_BufferEmpty ); + status |= DPMI_Lock( MV_Voices ); + status |= DPMI_Lock( VoiceList ); + status |= DPMI_Lock( VoicePool ); + status |= DPMI_Lock( MV_MixPage ); + status |= DPMI_Lock( MV_VoiceHandle ); + status |= DPMI_Lock( MV_CallBackFunc ); + status |= DPMI_Lock( MV_RecordFunc ); + status |= DPMI_Lock( MV_Recording ); + status |= DPMI_Lock( MV_MixFunction ); + status |= DPMI_Lock( MV_HarshClipTable ); + status |= DPMI_Lock( MV_MixDestination ); + status |= DPMI_Lock( MV_LeftVolume ); + status |= DPMI_Lock( MV_RightVolume ); + status |= DPMI_Lock( MV_MixPosition ); + status |= DPMI_Lock( MV_ErrorCode ); + status |= DPMI_Lock( MV_DMAChannel ); + status |= DPMI_Lock( MV_BuffShift ); + status |= DPMI_Lock( MV_ReverbLevel ); + status |= DPMI_Lock( MV_ReverbDelay ); + status |= DPMI_Lock( MV_ReverbTable ); + + pitchstatus = PITCH_LockMemory(); + if ( ( pitchstatus != PITCH_Ok ) || ( status != DPMI_Ok ) ) + { + MV_UnlockMemory(); + MV_SetErrorCode( MV_DPMI_Error ); + return( MV_Error ); + } + + return( MV_Ok ); + } + +#ifndef PLAT_DOS +void ClearBuffer_DW( void *ptr, unsigned data, int length ) +{ + unsigned *d = (unsigned *)ptr; + + while (length--) { + *d = data; + + d++; + } +} +#endif diff --git a/audiolib/multivoc.h b/audiolib/multivoc.h new file mode 100755 index 0000000..2733a8c --- /dev/null +++ b/audiolib/multivoc.h @@ -0,0 +1,123 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + file: MULTIVOC.H + + author: James R. Dose + date: December 20, 1993 + + Public header for MULTIVOC.C + + (c) Copyright 1993 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#ifndef __MULTIVOC_H +#define __MULTIVOC_H + +// platform.h is in buildengine, but I need the byteswapping macros... --ryan. +#include "../buildengine/platform.h" + +#define MV_MinVoiceHandle 1 + +extern int MV_ErrorCode; + +enum MV_Errors + { + MV_Warning = -2, + MV_Error = -1, + MV_Ok = 0, + MV_UnsupportedCard, + MV_NotInstalled, + MV_NoVoices, + MV_NoMem, + MV_VoiceNotFound, + MV_BlasterError, + MV_PasError, + MV_SoundScapeError, + MV_SoundSourceError, + MV_DPMI_Error, + MV_InvalidVOCFile, + MV_InvalidWAVFile, + MV_InvalidMixMode, + MV_SoundSourceFailure, + MV_IrqFailure, + MV_DMAFailure, + MV_DMA16Failure, + MV_NullRecordFunction + }; + +char *MV_ErrorString( int ErrorNumber ); +int MV_VoicePlaying( int handle ); +int MV_KillAllVoices( void ); +int MV_Kill( int handle ); +int MV_VoicesPlaying( void ); +int MV_VoiceAvailable( int priority ); +int MV_SetPitch( int handle, int pitchoffset ); +int MV_SetFrequency( int handle, int frequency ); +int MV_EndLooping( int handle ); +int MV_SetPan( int handle, int vol, int left, int right ); +int MV_Pan3D( int handle, int angle, int distance ); +void MV_SetReverb( int reverb ); +void MV_SetFastReverb( int reverb ); +int MV_GetMaxReverbDelay( void ); +int MV_GetReverbDelay( void ); +void MV_SetReverbDelay( int delay ); +int MV_SetMixMode( int numchannels, int samplebits ); +int MV_StartPlayback( void ); +void MV_StopPlayback( void ); +int MV_StartRecording( int MixRate, void ( *function )( char *ptr, int length ) ); +void MV_StopRecord( void ); +int MV_StartDemandFeedPlayback( void ( *function )( char **ptr, unsigned long *length ), + int rate, int pitchoffset, int vol, int left, int right, + int priority, unsigned long callbackval ); +int MV_PlayRaw( char *ptr, unsigned long length, + unsigned rate, int pitchoffset, int vol, int left, + int right, int priority, unsigned long callbackval ); +int MV_PlayLoopedRaw( char *ptr, unsigned long length, + char *loopstart, char *loopend, unsigned rate, int pitchoffset, + int vol, int left, int right, int priority, + unsigned long callbackval ); +int MV_PlayWAV( char *ptr, int pitchoffset, int vol, int left, + int right, int priority, unsigned long callbackval ); +int MV_PlayWAV3D( char *ptr, int pitchoffset, int angle, int distance, + int priority, unsigned long callbackval ); +int MV_PlayLoopedWAV( char *ptr, long loopstart, long loopend, + int pitchoffset, int vol, int left, int right, int priority, + unsigned long callbackval ); +int MV_PlayVOC3D( char *ptr, int pitchoffset, int angle, int distance, + int priority, unsigned long callbackval ); +int MV_PlayVOC( char *ptr, int pitchoffset, int vol, int left, int right, + int priority, unsigned long callbackval ); +int MV_PlayLoopedVOC( char *ptr, long loopstart, long loopend, + int pitchoffset, int vol, int left, int right, int priority, + unsigned long callbackval ); +void MV_CreateVolumeTable( int index, int volume, int MaxVolume ); +void MV_SetVolume( int volume ); +int MV_GetVolume( void ); +void MV_SetCallBack( void ( *function )( unsigned long ) ); +void MV_SetReverseStereo( int setting ); +int MV_GetReverseStereo( void ); +int MV_Init( int soundcard, int MixRate, int Voices, int numchannels, + int samplebits ); +int MV_Shutdown( void ); +void MV_UnlockMemory( void ); +int MV_LockMemory( void ); + +#endif diff --git a/audiolib/music.c b/audiolib/music.c new file mode 100755 index 0000000..e9397e1 --- /dev/null +++ b/audiolib/music.c @@ -0,0 +1,1035 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: MUSIC.C + + author: James R. Dose + date: March 25, 1994 + + Device independant music playback routines. + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#include +#include +#include "task_man.h" +#include "sndcards.h" +#include "music.h" +#include "midi.h" +#include "al_midi.h" +#include "pas16.h" +#include "blaster.h" +#include "gusmidi.h" +#include "mpu401.h" +#include "awe32.h" +#include "sndscape.h" +#include "ll_man.h" +#include "user.h" + +#define TRUE ( 1 == 1 ) +#define FALSE ( !TRUE ) + +void TextMode( void ); +#pragma aux TextMode = \ + "mov ax, 0003h", \ + "int 10h" \ + modify [ ax ]; + +int MUSIC_SoundDevice = -1; +int MUSIC_ErrorCode = MUSIC_Ok; + +static midifuncs MUSIC_MidiFunctions; + +static int MUSIC_FadeLength; +static int MUSIC_FadeRate; +static unsigned MUSIC_CurrentFadeVolume; +static unsigned MUSIC_LastFadeVolume; +static int MUSIC_EndingFadeVolume; +static task *MUSIC_FadeTask = NULL; + +int MUSIC_InitAWE32( midifuncs *Funcs ); +int MUSIC_InitFM( int card, midifuncs *Funcs ); +int MUSIC_InitMidi( int card, midifuncs *Funcs, int Address ); +int MUSIC_InitGUS( midifuncs *Funcs ); + +#define MUSIC_SetErrorCode( status ) \ + MUSIC_ErrorCode = ( status ); + +/*--------------------------------------------------------------------- + Function: MUSIC_ErrorString + + Returns a pointer to the error message associated with an error + number. A -1 returns a pointer the current error. +---------------------------------------------------------------------*/ + +char *MUSIC_ErrorString + ( + int ErrorNumber + ) + + { + char *ErrorString; + + switch( ErrorNumber ) + { + case MUSIC_Warning : + case MUSIC_Error : + ErrorString = MUSIC_ErrorString( MUSIC_ErrorCode ); + break; + + case MUSIC_Ok : + ErrorString = "Music ok."; + break; + + case MUSIC_ASSVersion : + ErrorString = "Apogee Sound System Version " ASS_VERSION_STRING " " + "Programmed by Jim Dose\n" + "(c) Copyright 1996 James R. Dose. All Rights Reserved.\n"; + break; + + case MUSIC_SoundCardError : + switch( MUSIC_SoundDevice ) + { + case SoundBlaster : + case WaveBlaster : + ErrorString = BLASTER_ErrorString( BLASTER_Error ); + break; + + case ProAudioSpectrum : + case SoundMan16 : + ErrorString = PAS_ErrorString( PAS_Error ); + break; + + case Adlib : + ErrorString = "Adlib error."; + break; + + case GenMidi : + case SoundCanvas : + ErrorString = "Could not detect MPU-401."; + break; + + case SoundScape : + ErrorString = SOUNDSCAPE_ErrorString( SOUNDSCAPE_Error ); + break; + + case Awe32 : + ErrorString = AWE32_ErrorString( AWE32_Error ); + break; + + case UltraSound : + ErrorString = GUS_ErrorString( GUS_Error ); + break; + + default : + ErrorString = MUSIC_ErrorString( MUSIC_InvalidCard ); + break; + } + break; + + case MUSIC_MPU401Error : + ErrorString = "Could not detect MPU-401."; + break; + + case MUSIC_InvalidCard : + ErrorString = "Invalid Music device."; + break; + + case MUSIC_MidiError : + ErrorString = "Error playing MIDI file."; + break; + + case MUSIC_TaskManError : + ErrorString = "TaskMan error."; + break; + + case MUSIC_FMNotDetected : + ErrorString = "Could not detect FM chip."; + break; + + case MUSIC_DPMI_Error : + ErrorString = "DPMI Error in MUSIC."; + break; + + default : + ErrorString = "Unknown Music error code."; + break; + } + + return( ErrorString ); + } + + +/*--------------------------------------------------------------------- + Function: MUSIC_Init + + Selects which sound device to use. +---------------------------------------------------------------------*/ + +int MUSIC_Init + ( + int SoundCard, + int Address + ) + + { + int i; + int status; + + if ( USER_CheckParameter( "ASSVER" ) ) + { + MUSIC_SetErrorCode( MUSIC_ASSVersion ); + return( MUSIC_Error ); + } + + status = LL_LockMemory(); + if ( status != LL_Ok ) + { + MUSIC_SetErrorCode( MUSIC_DPMI_Error ); + return( MUSIC_Error ); + } + + for( i = 0; i < 128; i++ ) + { + MIDI_PatchMap[ i ] = i; + } + + status = MUSIC_Ok; + MUSIC_SoundDevice = SoundCard; + + switch( SoundCard ) + { + case SoundBlaster : + case Adlib : + case ProAudioSpectrum : + case SoundMan16 : + status = MUSIC_InitFM( SoundCard, &MUSIC_MidiFunctions ); + break; + + case GenMidi : + case SoundCanvas : + case WaveBlaster : + case SoundScape : + status = MUSIC_InitMidi( SoundCard, &MUSIC_MidiFunctions, Address ); + break; + + case Awe32 : + status = MUSIC_InitAWE32( &MUSIC_MidiFunctions ); + break; + + case UltraSound : + status = MUSIC_InitGUS( &MUSIC_MidiFunctions ); + break; + + case SoundSource : + case PC : + default : + MUSIC_SetErrorCode( MUSIC_InvalidCard ); + status = MUSIC_Error; + } + + if ( status != MUSIC_Ok ) + { + LL_UnlockMemory(); + } + + return( status ); + } + + +/*--------------------------------------------------------------------- + Function: MUSIC_Shutdown + + Terminates use of sound device. +---------------------------------------------------------------------*/ + +int MUSIC_Shutdown + ( + void + ) + + { + int status; + + status = MUSIC_Ok; + + MIDI_StopSong(); + + if ( MUSIC_FadeTask != NULL ) + { + MUSIC_StopFade(); + } + + switch ( MUSIC_SoundDevice ) + { + case Adlib : + AL_Shutdown(); + break; + + case SoundBlaster : + AL_Shutdown(); + BLASTER_RestoreMidiVolume(); + break; + + case GenMidi : + case SoundCanvas : + case SoundScape : + MPU_Reset(); + break; + + case WaveBlaster : + BLASTER_ShutdownWaveBlaster(); + MPU_Reset(); + BLASTER_RestoreMidiVolume(); + break; + + case Awe32 : + AWE32_Shutdown(); + BLASTER_RestoreMidiVolume(); + break; + + case ProAudioSpectrum : + case SoundMan16 : + AL_Shutdown(); + PAS_RestoreMusicVolume(); + break; + + case UltraSound : + GUSMIDI_Shutdown(); + break; + } + + LL_UnlockMemory(); + + return( status ); + } + + +/*--------------------------------------------------------------------- + Function: MUSIC_SetMaxFMMidiChannel + + Sets the maximum MIDI channel that FM cards respond to. +---------------------------------------------------------------------*/ + +void MUSIC_SetMaxFMMidiChannel + ( + int channel + ) + + { + AL_SetMaxMidiChannel( channel ); + } + + +/*--------------------------------------------------------------------- + Function: MUSIC_SetVolume + + Sets the volume of music playback. +---------------------------------------------------------------------*/ + +void MUSIC_SetVolume + ( + int volume + ) + + { + volume = max( 0, volume ); + volume = min( volume, 255 ); + + if ( MUSIC_SoundDevice != -1 ) + { + MIDI_SetVolume( volume ); + } + } + + +/*--------------------------------------------------------------------- + Function: MUSIC_SetMidiChannelVolume + + Sets the volume of music playback on the specified MIDI channel. +---------------------------------------------------------------------*/ + +void MUSIC_SetMidiChannelVolume + ( + int channel, + int volume + ) + + { + MIDI_SetUserChannelVolume( channel, volume ); + } + + +/*--------------------------------------------------------------------- + Function: MUSIC_ResetMidiChannelVolumes + + Sets the volume of music playback on all MIDI channels to full volume. +---------------------------------------------------------------------*/ + +void MUSIC_ResetMidiChannelVolumes + ( + void + ) + + { + MIDI_ResetUserChannelVolume(); + } + + +/*--------------------------------------------------------------------- + Function: MUSIC_GetVolume + + Returns the volume of music playback. +---------------------------------------------------------------------*/ + +int MUSIC_GetVolume + ( + void + ) + + { + if ( MUSIC_SoundDevice == -1 ) + { + return( 0 ); + } + return( MIDI_GetVolume() ); + } + + +/*--------------------------------------------------------------------- + Function: MUSIC_SetLoopFlag + + Set whether the music will loop or end when it reaches the end of + the song. +---------------------------------------------------------------------*/ + +void MUSIC_SetLoopFlag + ( + int loopflag + ) + + { + MIDI_SetLoopFlag( loopflag ); + } + + +/*--------------------------------------------------------------------- + Function: MUSIC_SongPlaying + + Returns whether there is a song playing. +---------------------------------------------------------------------*/ + +int MUSIC_SongPlaying + ( + void + ) + + { + return( MIDI_SongPlaying() ); + } + + +/*--------------------------------------------------------------------- + Function: MUSIC_Continue + + Continues playback of a paused song. +---------------------------------------------------------------------*/ + +void MUSIC_Continue + ( + void + ) + + { + MIDI_ContinueSong(); + } + + +/*--------------------------------------------------------------------- + Function: MUSIC_Pause + + Pauses playback of a song. +---------------------------------------------------------------------*/ + +void MUSIC_Pause + ( + void + ) + + { + MIDI_PauseSong(); + } + + +/*--------------------------------------------------------------------- + Function: MUSIC_StopSong + + Stops playback of current song. +---------------------------------------------------------------------*/ + +int MUSIC_StopSong + ( + void + ) + + { + MUSIC_StopFade(); + MIDI_StopSong(); + MUSIC_SetErrorCode( MUSIC_Ok ); + return( MUSIC_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: MUSIC_PlaySong + + Begins playback of MIDI song. +---------------------------------------------------------------------*/ + +int MUSIC_PlaySong + ( + unsigned char *song, + int loopflag + ) + + { + int status; + + switch( MUSIC_SoundDevice ) + { + case SoundBlaster : + case Adlib : + case ProAudioSpectrum : + case SoundMan16 : + case GenMidi : + case SoundCanvas : + case WaveBlaster : + case SoundScape : + case Awe32 : + case UltraSound : + MIDI_StopSong(); + status = MIDI_PlaySong( song, loopflag ); + if ( status != MIDI_Ok ) + { + MUSIC_SetErrorCode( MUSIC_MidiError ); + return( MUSIC_Warning ); + } + break; + + case SoundSource : + case PC : + default : + MUSIC_SetErrorCode( MUSIC_InvalidCard ); + return( MUSIC_Warning ); + break; + } + + return( MUSIC_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: MUSIC_SetContext + + Sets the song context. +---------------------------------------------------------------------*/ + +void MUSIC_SetContext + ( + int context + ) + + { + MIDI_SetContext( context ); + } + + +/*--------------------------------------------------------------------- + Function: MUSIC_GetContext + + Returns the current song context. +---------------------------------------------------------------------*/ + +int MUSIC_GetContext + ( + void + ) + + { + return MIDI_GetContext(); + } + + +/*--------------------------------------------------------------------- + Function: MUSIC_SetSongTick + + Sets the position of the song pointer. +---------------------------------------------------------------------*/ + +void MUSIC_SetSongTick + ( + unsigned long PositionInTicks + ) + + { + MIDI_SetSongTick( PositionInTicks ); + } + + +/*--------------------------------------------------------------------- + Function: MUSIC_SetSongTime + + Sets the position of the song pointer. +---------------------------------------------------------------------*/ + +void MUSIC_SetSongTime + ( + unsigned long milliseconds + ) + + { + MIDI_SetSongTime( milliseconds ); + } + + +/*--------------------------------------------------------------------- + Function: MUSIC_SetSongPosition + + Sets the position of the song pointer. +---------------------------------------------------------------------*/ + +void MUSIC_SetSongPosition + ( + int measure, + int beat, + int tick + ) + + { + MIDI_SetSongPosition( measure, beat, tick ); + } + + +/*--------------------------------------------------------------------- + Function: MUSIC_GetSongPosition + + Returns the position of the song pointer. +---------------------------------------------------------------------*/ + +void MUSIC_GetSongPosition + ( + songposition *pos + ) + + { + MIDI_GetSongPosition( pos ); + } + + +/*--------------------------------------------------------------------- + Function: MUSIC_GetSongLength + + Returns the length of the song. +---------------------------------------------------------------------*/ + +void MUSIC_GetSongLength + ( + songposition *pos + ) + + { + MIDI_GetSongLength( pos ); + } + + +int MUSIC_InitAWE32 + ( + midifuncs *Funcs + ) + + { + int status; + + status = AWE32_Init(); + if ( status != AWE32_Ok ) + { + MUSIC_SetErrorCode( MUSIC_SoundCardError ); + return( MUSIC_Error ); + } + + Funcs->NoteOff = AWE32_NoteOff; + Funcs->NoteOn = AWE32_NoteOn; + Funcs->PolyAftertouch = AWE32_PolyAftertouch; + Funcs->ControlChange = AWE32_ControlChange; + Funcs->ProgramChange = AWE32_ProgramChange; + Funcs->ChannelAftertouch = AWE32_ChannelAftertouch; + Funcs->PitchBend = AWE32_PitchBend; + Funcs->ReleasePatches = NULL; + Funcs->LoadPatch = NULL; + Funcs->SetVolume = NULL; + Funcs->GetVolume = NULL; + + if ( BLASTER_CardHasMixer() ) + { + BLASTER_SaveMidiVolume(); + Funcs->SetVolume = BLASTER_SetMidiVolume; + Funcs->GetVolume = BLASTER_GetMidiVolume; + } + + status = MUSIC_Ok; + MIDI_SetMidiFuncs( Funcs ); + + return( status ); + } + + +int MUSIC_InitFM + ( + int card, + midifuncs *Funcs + ) + + { + int status; + int passtatus; + + status = MIDI_Ok; + + if ( !AL_DetectFM() ) + { + MUSIC_SetErrorCode( MUSIC_FMNotDetected ); + return( MUSIC_Error ); + } + + // Init the fm routines + AL_Init( card ); + + Funcs->NoteOff = AL_NoteOff; + Funcs->NoteOn = AL_NoteOn; + Funcs->PolyAftertouch = NULL; + Funcs->ControlChange = AL_ControlChange; + Funcs->ProgramChange = AL_ProgramChange; + Funcs->ChannelAftertouch = NULL; + Funcs->PitchBend = AL_SetPitchBend; + Funcs->ReleasePatches = NULL; + Funcs->LoadPatch = NULL; + Funcs->SetVolume = NULL; + Funcs->GetVolume = NULL; + + switch( card ) + { + case SoundBlaster : + if ( BLASTER_CardHasMixer() ) + { + BLASTER_SaveMidiVolume(); + Funcs->SetVolume = BLASTER_SetMidiVolume; + Funcs->GetVolume = BLASTER_GetMidiVolume; + } + else + { + Funcs->SetVolume = NULL; + Funcs->GetVolume = NULL; + } + break; + + case Adlib : + Funcs->SetVolume = NULL; + Funcs->GetVolume = NULL; + break; + + case ProAudioSpectrum : + case SoundMan16 : + Funcs->SetVolume = NULL; + Funcs->GetVolume = NULL; + + passtatus = PAS_SaveMusicVolume(); + if ( passtatus == PAS_Ok ) + { + Funcs->SetVolume = PAS_SetFMVolume; + Funcs->GetVolume = PAS_GetFMVolume; + } + break; + } + + MIDI_SetMidiFuncs( Funcs ); + + return( status ); + } + +int MUSIC_InitMidi + ( + int card, + midifuncs *Funcs, + int Address + ) + + { + int status; + + status = MUSIC_Ok; + + if ( ( card == WaveBlaster ) || ( card == SoundCanvas ) || + ( card == GenMidi ) ) + { + // Setup WaveBlaster Daughterboard clone + // (ie. SoundCanvas DB, TurtleBeach Rio) + BLASTER_SetupWaveBlaster(); + } + + if ( card == SoundScape ) + { + Address = SOUNDSCAPE_GetMIDIPort(); + if ( Address < SOUNDSCAPE_Ok ) + { + MUSIC_SetErrorCode( MUSIC_SoundCardError ); + return( MUSIC_Error ); + } + } + + if ( MPU_Init( Address ) != MPU_Ok ) + { + MUSIC_SetErrorCode( MUSIC_MPU401Error ); + return( MUSIC_Error ); + } + + Funcs->NoteOff = MPU_NoteOff; + Funcs->NoteOn = MPU_NoteOn; + Funcs->PolyAftertouch = MPU_PolyAftertouch; + Funcs->ControlChange = MPU_ControlChange; + Funcs->ProgramChange = MPU_ProgramChange; + Funcs->ChannelAftertouch = MPU_ChannelAftertouch; + Funcs->PitchBend = MPU_PitchBend; + Funcs->ReleasePatches = NULL; + Funcs->LoadPatch = NULL; + Funcs->SetVolume = NULL; + Funcs->GetVolume = NULL; + + if ( card == WaveBlaster ) + { + if ( BLASTER_CardHasMixer() ) + { + BLASTER_SaveMidiVolume(); + Funcs->SetVolume = BLASTER_SetMidiVolume; + Funcs->GetVolume = BLASTER_GetMidiVolume; + } + } + + MIDI_SetMidiFuncs( Funcs ); + + return( status ); + } + +int MUSIC_InitGUS + ( + midifuncs *Funcs + ) + + { + int status; + + status = MUSIC_Ok; + + if ( GUSMIDI_Init() != GUS_Ok ) + { + MUSIC_SetErrorCode( MUSIC_SoundCardError ); + return( MUSIC_Error ); + } + + Funcs->NoteOff = GUSMIDI_NoteOff; + Funcs->NoteOn = GUSMIDI_NoteOn; + Funcs->PolyAftertouch = NULL; + Funcs->ControlChange = GUSMIDI_ControlChange; + Funcs->ProgramChange = GUSMIDI_ProgramChange; + Funcs->ChannelAftertouch = NULL; + Funcs->PitchBend = GUSMIDI_PitchBend; + Funcs->ReleasePatches = NULL;//GUSMIDI_ReleasePatches; + Funcs->LoadPatch = NULL;//GUSMIDI_LoadPatch; + Funcs->SetVolume = GUSMIDI_SetVolume; + Funcs->GetVolume = GUSMIDI_GetVolume; + + MIDI_SetMidiFuncs( Funcs ); + + return( status ); + } + + +/*--------------------------------------------------------------------- + Function: MUSIC_FadeRoutine + + Fades music volume from current level to another over a specified + period of time. +---------------------------------------------------------------------*/ + +static void MUSIC_FadeRoutine + ( + task *Task + ) + + { + int volume; + + MUSIC_CurrentFadeVolume += MUSIC_FadeRate; + if ( MUSIC_FadeLength == 0 ) + { + MIDI_SetVolume( MUSIC_EndingFadeVolume ); + TS_Terminate( Task ); + MUSIC_FadeTask = NULL; + } + else + { + MUSIC_FadeLength--; +// if ( ( MUSIC_SoundDevice == GenMidi ) && +// ( ( MUSIC_FadeLength % 12 ) != 0 ) ) +// { +// return; +// } + + volume = MUSIC_CurrentFadeVolume >> 7; + if ( MUSIC_LastFadeVolume != volume ) + { + MUSIC_LastFadeVolume = volume; + MIDI_SetVolume( volume ); + } + } + } + + +/*--------------------------------------------------------------------- + Function: MUSIC_FadeVolume + + Fades music volume from current level to another over a specified + period of time. +---------------------------------------------------------------------*/ + +int MUSIC_FadeVolume + ( + int tovolume, + int milliseconds + ) + + { + int fromvolume; + + if ( ( MUSIC_SoundDevice == ProAudioSpectrum ) || + ( MUSIC_SoundDevice == SoundMan16 ) || + ( MUSIC_SoundDevice == GenMidi ) || + ( MUSIC_SoundDevice == SoundScape ) || + ( MUSIC_SoundDevice == SoundCanvas ) ) + { + MIDI_SetVolume( tovolume ); + return( MUSIC_Ok ); + } + + if ( MUSIC_FadeTask != NULL ) + { + MUSIC_StopFade(); + } + + tovolume = max( 0, tovolume ); + tovolume = min( 255, tovolume ); + fromvolume = MUSIC_GetVolume(); + + MUSIC_FadeLength = milliseconds / 25; + MUSIC_FadeRate = ( ( tovolume - fromvolume ) << 7 ) / MUSIC_FadeLength; + MUSIC_LastFadeVolume = fromvolume; + MUSIC_CurrentFadeVolume = fromvolume << 7; + MUSIC_EndingFadeVolume = tovolume; + + MUSIC_FadeTask = TS_ScheduleTask( MUSIC_FadeRoutine, 40, 1, NULL ); + if ( MUSIC_FadeTask == NULL ) + { + MUSIC_SetErrorCode( MUSIC_TaskManError ); + return( MUSIC_Warning ); + } + + TS_Dispatch(); + return( MUSIC_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: MUSIC_FadeActive + + Returns whether the fade routine is active. +---------------------------------------------------------------------*/ + +int MUSIC_FadeActive + ( + void + ) + + { + return( MUSIC_FadeTask != NULL ); + } + + +/*--------------------------------------------------------------------- + Function: MUSIC_StopFade + + Stops fading the music. +---------------------------------------------------------------------*/ + +void MUSIC_StopFade + ( + void + ) + + { + if ( MUSIC_FadeTask != NULL ) + { + TS_Terminate( MUSIC_FadeTask ); + MUSIC_FadeTask = NULL; + } + } + + +/*--------------------------------------------------------------------- + Function: MUSIC_RerouteMidiChannel + + Sets callback function to reroute MIDI commands from specified + function. +---------------------------------------------------------------------*/ + +void MUSIC_RerouteMidiChannel + ( + int channel, + int cdecl ( *function )( int event, int c1, int c2 ) + ) + + { + MIDI_RerouteMidiChannel( channel, function ); + } + + +/*--------------------------------------------------------------------- + Function: MUSIC_RegisterTimbreBank + + Halts playback of all sounds. +---------------------------------------------------------------------*/ + +void MUSIC_RegisterTimbreBank + ( + unsigned char *timbres + ) + + { + AL_RegisterTimbreBank( timbres ); + } diff --git a/audiolib/music.h b/audiolib/music.h new file mode 100755 index 0000000..3a3a06c --- /dev/null +++ b/audiolib/music.h @@ -0,0 +1,96 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: MUSIC.H + + author: James R. Dose + date: March 25, 1994 + + Public header for MUSIC.C + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#ifndef __MUSIC_H +#define __MUSIC_H + +#include "sndcards.h" + +#ifndef PLAT_DOS +#define cdecl +#endif + +extern int MUSIC_ErrorCode; + +enum MUSIC_ERRORS + { + MUSIC_Warning = -2, + MUSIC_Error = -1, + MUSIC_Ok = 0, + MUSIC_ASSVersion, + MUSIC_SoundCardError, + MUSIC_MPU401Error, + MUSIC_InvalidCard, + MUSIC_MidiError, + MUSIC_TaskManError, + MUSIC_FMNotDetected, + MUSIC_DPMI_Error + }; + +typedef struct + { + unsigned long tickposition; + unsigned long milliseconds; + unsigned int measure; + unsigned int beat; + unsigned int tick; + } songposition; + +#define MUSIC_LoopSong ( 1 == 1 ) +#define MUSIC_PlayOnce ( !MUSIC_LoopSong ) + +char *MUSIC_ErrorString( int ErrorNumber ); +int MUSIC_Init( int SoundCard, int Address ); +int MUSIC_Shutdown( void ); +void MUSIC_SetMaxFMMidiChannel( int channel ); +void MUSIC_SetVolume( int volume ); +void MUSIC_SetMidiChannelVolume( int channel, int volume ); +void MUSIC_ResetMidiChannelVolumes( void ); +int MUSIC_GetVolume( void ); +void MUSIC_SetLoopFlag( int loopflag ); +int MUSIC_SongPlaying( void ); +void MUSIC_Continue( void ); +void MUSIC_Pause( void ); +int MUSIC_StopSong( void ); +int MUSIC_PlaySong( unsigned char *song, int loopflag ); +void MUSIC_SetContext( int context ); +int MUSIC_GetContext( void ); +void MUSIC_SetSongTick( unsigned long PositionInTicks ); +void MUSIC_SetSongTime( unsigned long milliseconds ); +void MUSIC_SetSongPosition( int measure, int beat, int tick ); +void MUSIC_GetSongPosition( songposition *pos ); +void MUSIC_GetSongLength( songposition *pos ); +int MUSIC_FadeVolume( int tovolume, int milliseconds ); +int MUSIC_FadeActive( void ); +void MUSIC_StopFade( void ); +void MUSIC_RerouteMidiChannel( int channel, int cdecl ( *function )( int event, int c1, int c2 ) ); +void MUSIC_RegisterTimbreBank( unsigned char *timbres ); + +#endif diff --git a/audiolib/mv_mix.asm b/audiolib/mv_mix.asm new file mode 100755 index 0000000..2bd398d --- /dev/null +++ b/audiolib/mv_mix.asm @@ -0,0 +1,505 @@ + IDEAL + + p386 + MODEL flat + + dataseg + CODESEG + + MASM + ALIGN 4 + +EXTRN _MV_HarshClipTable:DWORD +EXTRN _MV_MixDestination:DWORD +EXTRN _MV_MixPosition:DWORD +EXTRN _MV_LeftVolume:DWORD +EXTRN _MV_RightVolume:DWORD +EXTRN _MV_SampleSize:DWORD +EXTRN _MV_RightChannelOffset:DWORD + +;================ +; +; MV_Mix8BitMono +; +;================ + +; eax - position +; edx - rate +; ebx - start +; ecx - number of samples to mix + +PROC MV_Mix8BitMono_ +PUBLIC MV_Mix8BitMono_ +; Two at once + pushad + + mov ebp, eax + + mov esi, ebx ; Source pointer + + ; Sample size + mov ebx, _MV_SampleSize + mov eax,OFFSET apatch7+2 ; convice tasm to modify code... + mov [eax],bl + mov eax,OFFSET apatch8+2 ; convice tasm to modify code... + mov [eax],bl + mov eax,OFFSET apatch9+3 ; convice tasm to modify code... + mov [eax],bl + + ; Volume table ptr + mov ebx, _MV_LeftVolume ; Since we're mono, use left volume + mov eax,OFFSET apatch1+4 ; convice tasm to modify code... + mov [eax],ebx + mov eax,OFFSET apatch2+4 ; convice tasm to modify code... + mov [eax],ebx + + ; Harsh Clip table ptr + mov ebx, _MV_HarshClipTable + add ebx, 128 + mov eax,OFFSET apatch3+2 ; convice tasm to modify code... + mov [eax],ebx + mov eax,OFFSET apatch4+2 ; convice tasm to modify code... + mov [eax],ebx + + ; Rate scale ptr + mov eax,OFFSET apatch5+2 ; convice tasm to modify code... + mov [eax],edx + mov eax,OFFSET apatch6+2 ; convice tasm to modify code... + mov [eax],edx + + mov edi, _MV_MixDestination ; Get the position to write to + + ; Number of samples to mix + shr ecx, 1 ; double sample count + cmp ecx, 0 + je short exit8m + +; eax - scratch +; ebx - scratch +; edx - scratch +; ecx - count +; edi - destination +; esi - source +; ebp - frac pointer +; apatch1 - volume table +; apatch2 - volume table +; apatch3 - harsh clip table +; apatch4 - harsh clip table +; apatch5 - sample rate +; apatch6 - sample rate + + mov eax,ebp ; begin calculating first sample + add ebp,edx ; advance frac pointer + shr eax,16 ; finish calculation for first sample + + mov ebx,ebp ; begin calculating second sample + add ebp,edx ; advance frac pointer + shr ebx,16 ; finish calculation for second sample + + movzx eax, byte ptr [esi+eax] ; get first sample + movzx ebx, byte ptr [esi+ebx] ; get second sample + + ALIGN 4 +mix8Mloop: + movzx edx, byte ptr [edi] ; get current sample from destination +apatch1: + movsx eax, byte ptr [2*eax+12345678h] ; volume translate first sample +apatch2: + movsx ebx, byte ptr [2*ebx+12345678h] ; volume translate second sample + add eax, edx ; mix first sample +apatch9: + movzx edx, byte ptr [edi + 1] ; get current sample from destination +apatch3: + mov eax, [eax + 12345678h] ; harsh clip new sample + add ebx, edx ; mix second sample + mov [edi], al ; write new sample to destination + mov edx, ebp ; begin calculating third sample +apatch4: + mov ebx, [ebx + 12345678h] ; harsh clip new sample +apatch5: + add ebp,12345678h ; advance frac pointer + shr edx, 16 ; finish calculation for third sample + mov eax, ebp ; begin calculating fourth sample +apatch7: + add edi, 1 ; move destination to second sample + shr eax, 16 ; finish calculation for fourth sample + mov [edi], bl ; write new sample to destination +apatch6: + add ebp,12345678h ; advance frac pointer + movzx ebx, byte ptr [esi+eax] ; get fourth sample + movzx eax, byte ptr [esi+edx] ; get third sample +apatch8: + add edi, 2 ; move destination to third sample + dec ecx ; decrement count + jnz mix8Mloop ; loop + + mov _MV_MixDestination, edi ; Store the current write position + mov _MV_MixPosition, ebp ; return position +exit8m: + popad + ret +ENDP MV_Mix8BitMono_ + +;================ +; +; MV_Mix8BitStereo +; +;================ + +; eax - position +; edx - rate +; ebx - start +; ecx - number of samples to mix + +PROC MV_Mix8BitStereo_ +PUBLIC MV_Mix8BitStereo_ + + pushad + mov ebp, eax + + mov esi, ebx ; Source pointer + + ; Sample size + mov ebx, _MV_SampleSize + mov eax,OFFSET bpatch8+2 ; convice tasm to modify code... + mov [eax],bl + + ; Right channel offset + mov ebx, _MV_RightChannelOffset + mov eax,OFFSET bpatch6+3 ; convice tasm to modify code... + mov [eax],ebx + mov eax,OFFSET bpatch7+2 ; convice tasm to modify code... + mov [eax],ebx + + ; Volume table ptr + mov ebx, _MV_LeftVolume + mov eax,OFFSET bpatch1+4 ; convice tasm to modify code... + mov [eax],ebx + + mov ebx, _MV_RightVolume + mov eax,OFFSET bpatch2+4 ; convice tasm to modify code... + mov [eax],ebx + + ; Rate scale ptr + mov eax,OFFSET bpatch3+2 ; convice tasm to modify code... + mov [eax],edx + + ; Harsh Clip table ptr + mov ebx, _MV_HarshClipTable + add ebx,128 + mov eax,OFFSET bpatch4+2 ; convice tasm to modify code... + mov [eax],ebx + mov eax,OFFSET bpatch5+2 ; convice tasm to modify code... + mov [eax],ebx + + mov edi, _MV_MixDestination ; Get the position to write to + + ; Number of samples to mix + cmp ecx, 0 + je short exit8S + +; eax - scratch +; ebx - scratch +; edx - scratch +; ecx - count +; edi - destination +; esi - source +; ebp - frac pointer +; bpatch1 - left volume table +; bpatch2 - right volume table +; bpatch3 - sample rate +; bpatch4 - harsh clip table +; bpatch5 - harsh clip table + + mov eax,ebp ; begin calculating first sample + shr eax,16 ; finish calculation for first sample + + movzx ebx, byte ptr [esi+eax] ; get first sample + + ALIGN 4 +mix8Sloop: +bpatch1: + movsx eax, byte ptr [2*ebx+12345678h] ; volume translate left sample + movzx edx, byte ptr [edi] ; get current sample from destination +bpatch2: + movsx ebx, byte ptr [2*ebx+12345678h] ; volume translate right sample + add eax, edx ; mix left sample +bpatch3: + add ebp,12345678h ; advance frac pointer +bpatch6: + movzx edx, byte ptr [edi+12345678h] ; get current sample from destination +bpatch4: + mov eax, [eax + 12345678h] ; harsh clip left sample + add ebx, edx ; mix right sample + mov [edi], al ; write left sample to destination +bpatch5: + mov ebx, [ebx + 12345678h] ; harsh clip right sample + mov edx, ebp ; begin calculating second sample +bpatch7: + mov [edi+12345678h], bl ; write right sample to destination + shr edx, 16 ; finish calculation for second sample +bpatch8: + add edi, 2 ; move destination to second sample + movzx ebx, byte ptr [esi+edx] ; get second sample + dec ecx ; decrement count + jnz mix8Sloop ; loop + + mov _MV_MixDestination, edi ; Store the current write position + mov _MV_MixPosition, ebp ; return position + +EXIT8S: + popad + ret +ENDP MV_Mix8BitStereo_ + +;================ +; +; MV_Mix16BitMono +; +;================ + +; eax - position +; edx - rate +; ebx - start +; ecx - number of samples to mix + +PROC MV_Mix16BitMono_ +PUBLIC MV_Mix16BitMono_ +; Two at once + pushad + + mov ebp, eax + + mov esi, ebx ; Source pointer + + ; Sample size + mov ebx, _MV_SampleSize + mov eax,OFFSET cpatch5+3 ; convice tasm to modify code... + mov [eax],bl + mov eax,OFFSET cpatch6+3 ; convice tasm to modify code... + mov [eax],bl + mov eax,OFFSET cpatch7+2 ; convice tasm to modify code... + add bl,bl + mov [eax],bl + + ; Volume table ptr + mov ebx, _MV_LeftVolume + mov eax,OFFSET cpatch1+4 ; convice tasm to modify code... + mov [eax],ebx + mov eax,OFFSET cpatch2+4 ; convice tasm to modify code... + mov [eax],ebx + + ; Rate scale ptr + mov eax,OFFSET cpatch3+2 ; convice tasm to modify code... + mov [eax],edx + mov eax,OFFSET cpatch4+2 ; convice tasm to modify code... + mov [eax],edx + + mov edi, _MV_MixDestination ; Get the position to write to + + ; Number of samples to mix + shr ecx, 1 ; double sample count + cmp ecx, 0 + je exit16M + +; eax - scratch +; ebx - scratch +; edx - scratch +; ecx - count +; edi - destination +; esi - source +; ebp - frac pointer +; cpatch1 - volume table +; cpatch2 - volume table +; cpatch3 - sample rate +; cpatch4 - sample rate + + mov eax,ebp ; begin calculating first sample + add ebp,edx ; advance frac pointer + shr eax,16 ; finish calculation for first sample + + mov ebx,ebp ; begin calculating second sample + add ebp,edx ; advance frac pointer + shr ebx,16 ; finish calculation for second sample + + movzx eax, byte ptr [esi+eax] ; get first sample + movzx ebx, byte ptr [esi+ebx] ; get second sample + + ALIGN 4 +mix16Mloop: + movsx edx, word ptr [edi] ; get current sample from destination +cpatch1: + movsx eax, word ptr [2*eax+12345678h] ; volume translate first sample +cpatch2: + movsx ebx, word ptr [2*ebx+12345678h] ; volume translate second sample + add eax, edx ; mix first sample +cpatch5: + movsx edx, word ptr [edi + 2] ; get current sample from destination + + cmp eax, -32768 ; Harsh clip sample + jge short m16skip1 + mov eax, -32768 + jmp short m16skip2 +m16skip1: + cmp eax, 32767 + jle short m16skip2 + mov eax, 32767 +m16skip2: + add ebx, edx ; mix second sample + mov [edi], ax ; write new sample to destination + mov edx, ebp ; begin calculating third sample + + cmp ebx, -32768 ; Harsh clip sample + jge short m16skip3 + mov ebx, -32768 + jmp short m16skip4 +m16skip3: + cmp ebx, 32767 + jle short m16skip4 + mov ebx, 32767 +m16skip4: +cpatch3: + add ebp,12345678h ; advance frac pointer + shr edx, 16 ; finish calculation for third sample + mov eax, ebp ; begin calculating fourth sample +cpatch6: + mov [edi + 2], bx ; write new sample to destination + shr eax, 16 ; finish calculation for fourth sample + +cpatch4: + add ebp,12345678h ; advance frac pointer + movzx ebx, byte ptr [esi+eax] ; get fourth sample +cpatch7: + add edi, 4 ; move destination to third sample + movzx eax, byte ptr [esi+edx] ; get third sample + dec ecx ; decrement count + jnz mix16Mloop ; loop + + mov _MV_MixDestination, edi ; Store the current write position + mov _MV_MixPosition, ebp ; return position +EXIT16M: + popad + ret +ENDP MV_Mix16BitMono_ + +;================ +; +; MV_Mix16BitStereo +; +;================ + +; eax - position +; edx - rate +; ebx - start +; ecx - number of samples to mix + +PROC MV_Mix16BitStereo_ +PUBLIC MV_Mix16BitStereo_ + + pushad + mov ebp, eax + + mov esi, ebx ; Source pointer + + ; Sample size + mov ebx, _MV_SampleSize + mov eax,OFFSET dpatch6+2 ; convice tasm to modify code... + mov [eax],bl + + ; Right channel offset + mov ebx, _MV_RightChannelOffset + mov eax,OFFSET dpatch4+3 ; convice tasm to modify code... + mov [eax],ebx + mov eax,OFFSET dpatch5+3 ; convice tasm to modify code... + mov [eax],ebx + + ; Volume table ptr + mov ebx, _MV_LeftVolume + mov eax,OFFSET dpatch1+4 ; convice tasm to modify code... + mov [eax],ebx + + mov ebx, _MV_RightVolume + mov eax,OFFSET dpatch2+4 ; convice tasm to modify code... + mov [eax],ebx + + ; Rate scale ptr + mov eax,OFFSET dpatch3+2 ; convice tasm to modify code... + mov [eax],edx + + mov edi, _MV_MixDestination ; Get the position to write to + + ; Number of samples to mix + cmp ecx, 0 + je exit16S + +; eax - scratch +; ebx - scratch +; edx - scratch +; ecx - count +; edi - destination +; esi - source +; ebp - frac pointer +; dpatch1 - left volume table +; dpatch2 - right volume table +; dpatch3 - sample rate + + mov eax,ebp ; begin calculating first sample + shr eax,16 ; finish calculation for first sample + + movzx ebx, byte ptr [esi+eax] ; get first sample + + ALIGN 4 +mix16Sloop: +dpatch1: + movsx eax, word ptr [2*ebx+12345678h] ; volume translate left sample + movsx edx, word ptr [edi] ; get current sample from destination +dpatch2: + movsx ebx, word ptr [2*ebx+12345678h] ; volume translate right sample + add eax, edx ; mix left sample +dpatch3: + add ebp,12345678h ; advance frac pointer +dpatch4: + movsx edx, word ptr [edi+12345678h] ; get current sample from destination + + cmp eax, -32768 ; Harsh clip sample + jge short s16skip1 + mov eax, -32768 + jmp short s16skip2 +s16skip1: + cmp eax, 32767 + jle short s16skip2 + mov eax, 32767 +s16skip2: + add ebx, edx ; mix right sample + mov [edi], ax ; write left sample to destination + + cmp ebx, -32768 ; Harsh clip sample + jge short s16skip3 + mov ebx, -32768 + jmp short s16skip4 +s16skip3: + cmp ebx, 32767 + jle short s16skip4 + mov ebx, 32767 +s16skip4: + + mov edx, ebp ; begin calculating second sample +dpatch5: + mov [edi+12345678h], bx ; write right sample to destination + shr edx, 16 ; finish calculation for second sample +dpatch6: + add edi, 4 ; move destination to second sample + movzx ebx, byte ptr [esi+edx] ; get second sample + dec ecx ; decrement count + jnz mix16Sloop ; loop + + mov _MV_MixDestination, edi ; Store the current write position + mov _MV_MixPosition, ebp ; return position +exit16S: + popad + ret +ENDP MV_Mix16BitStereo_ + + ENDS + + END diff --git a/audiolib/mv_mix.c b/audiolib/mv_mix.c new file mode 100755 index 0000000..75a0691 --- /dev/null +++ b/audiolib/mv_mix.c @@ -0,0 +1,293 @@ +#include "multivoc.h" + +extern char *MV_MixDestination; +extern unsigned long MV_MixPosition; + +extern char *MV_LeftVolume; +extern char *MV_RightVolume; + +extern unsigned char *MV_HarshClipTable; + +extern int MV_RightChannelOffset; +extern int MV_SampleSize; + +void MV_Mix8BitMono( unsigned long position, unsigned long rate, + const char *start, unsigned long length ) +{ + const unsigned char *src; + unsigned char *dest; + unsigned int i; + + src = (const unsigned char *)start; + dest = (unsigned char *)MV_MixDestination; + + for (i = 0; i < length; i++) { + int s = src[position >> 16]; + int d = *dest; + + s = MV_LeftVolume[s * 2]; + + s += d; + + s = MV_HarshClipTable[s + 0x80]; + + *dest = (s & 0xff); + + position += rate; + dest += MV_SampleSize; + } + + MV_MixPosition = position; + MV_MixDestination = (char *)dest; +} + +void MV_Mix8BitStereo( unsigned long position, + unsigned long rate, const char *start, unsigned long length ) +{ + const unsigned char *src; + unsigned char *dest; + unsigned int i; + + src = (const unsigned char *)start; + dest = (unsigned char *)MV_MixDestination; + + for (i = 0; i < length; i++) { + int s = src[(position >> 16)]; + int dl = dest[0]; + int dr = dest[MV_RightChannelOffset]; + + dl += MV_LeftVolume[s * 2]; + dr += MV_RightVolume[s * 2]; + + dl = MV_HarshClipTable[dl + 0x80]; + dr = MV_HarshClipTable[dr + 0x80]; + + dest[0] = (dl & 0xff); + dest[MV_RightChannelOffset] = (dr & 0xff); + + position += rate; + dest += MV_SampleSize; + } + + MV_MixPosition = position; + MV_MixDestination = (char *)dest; +} + +void MV_Mix16BitMono( unsigned long position, + unsigned long rate, const char *start, unsigned long length ) +{ + const short *MV_LeftVolumeS; + const unsigned char *src; + short *dest; + unsigned int i; + + src = (const unsigned char *)start; + dest = (short *)MV_MixDestination; + + MV_LeftVolumeS = (const short *)MV_LeftVolume; + + for (i = 0; i < length; i++) { + int s = src[position >> 16]; + int d = dest[0]; + + s = MV_LeftVolumeS[s]; + + s += d; + + if (s < -32768) s = -32768; + if (s > 32767) s = 32767; + + *dest = (short) s; + + position += rate; + dest += MV_SampleSize/2; + } + + MV_MixPosition = position; + MV_MixDestination = (char *)dest; +} + +void MV_Mix16BitStereo( unsigned long position, + unsigned long rate, const char *start, unsigned long length ) +{ + const short *MV_LeftVolumeS; + const short *MV_RightVolumeS; + const unsigned char *src; + short *dest; + unsigned int i; + + src = (unsigned char *)start; + dest = (short *)MV_MixDestination; + + MV_LeftVolumeS = (const short *)MV_LeftVolume; + MV_RightVolumeS = (const short *)MV_RightVolume; + + for (i = 0; i < length; i++) { + int s = src[position >> 16]; + int dl = dest[0]; + int dr = dest[MV_RightChannelOffset/2]; + + dl += MV_LeftVolumeS[s]; + dr += MV_RightVolumeS[s]; + + if (dl < -32768) dl = -32768; + if (dl > 32767) dl = 32767; + if (dr < -32768) dr = -32768; + if (dr > 32767) dr = 32767; + + dest[0] = (short) dl; + dest[MV_RightChannelOffset/2] = (short) dr; + + position += rate; + dest += MV_SampleSize/2; + } + + MV_MixPosition = position; + MV_MixDestination = (char *)dest; +} + +void MV_Mix8BitMono16( unsigned long position, unsigned long rate, + const char *start, unsigned long length ) +{ + const char *src; + unsigned char *dest; + unsigned int i; + + src = (const char *)start + 1; + dest = (unsigned char *)MV_MixDestination; + + for (i = 0; i < length; i++) { + int s = (int)src[(position >> 16) * 2] + 0x80; + int d = *dest; + + s = MV_LeftVolume[s * 2]; + + s += d; + + s = MV_HarshClipTable[s + 0x80]; + + *dest = (s & 0xff); + + position += rate; + dest += MV_SampleSize; + } + + MV_MixPosition = position; + MV_MixDestination = (char *)dest; +} + +void MV_Mix8BitStereo16( unsigned long position, + unsigned long rate, const char *start, unsigned long length ) +{ + const char *src; + unsigned char *dest; + unsigned int i; + + src = (const char *)start + 1; + dest = (unsigned char *)MV_MixDestination; + + for (i = 0; i < length; i++) { + int s = src[(position >> 16) * 2] + 0x80; + int dl = dest[0]; + int dr = dest[MV_RightChannelOffset]; + + dl += MV_LeftVolume[s * 2]; + dr += MV_RightVolume[s * 2]; + + dl = MV_HarshClipTable[dl + 0x80]; + dr = MV_HarshClipTable[dr + 0x80]; + + dest[0] = (dl & 0xff); + dest[MV_RightChannelOffset] = (dr & 0xff); + + position += rate; + dest += MV_SampleSize; + } + + MV_MixPosition = position; + MV_MixDestination = (char *)dest; +} + +void MV_Mix16BitMono16( unsigned long position, + unsigned long rate, const char *start, unsigned long length ) +{ + const short *MV_LeftVolumeS; + const unsigned char *src; + short *dest; + unsigned int i; + + src = (const unsigned char *)start; + dest = (short *)MV_MixDestination; + + MV_LeftVolumeS = (const short *)MV_LeftVolume; + + for (i = 0; i < length; i++) { + int sl = src[(position >> 16) * 2 + 0]; + int sh = src[(position >> 16) * 2 + 1] ^ 0x80; + + int d = *dest; + + sl = MV_LeftVolume[sl * 2 + 1]; + sh = MV_LeftVolumeS[sh]; + + d = sl + sh + 0x80 + d; + + if (d < -32768) d = -32768; + if (d > 32767) d = 32767; + + *dest = (short) d; + + position += rate; + dest += MV_SampleSize/2; + } + + MV_MixPosition = position; + MV_MixDestination = (char *)dest; +} + +void MV_Mix16BitStereo16( unsigned long position, + unsigned long rate, const char *start, unsigned long length ) +{ + const short *MV_LeftVolumeS; + const short *MV_RightVolumeS; + const unsigned char *src; + short *dest; + unsigned int i; + + src = (const unsigned char *)start; + dest = (short *)MV_MixDestination; + + MV_LeftVolumeS = (const short *)MV_LeftVolume; + MV_RightVolumeS = (const short *)MV_RightVolume; + + for (i = 0; i < length; i++) { + int sl = src[(position >> 16) * 2 + 0]; + int sh = src[(position >> 16) * 2 + 1] ^ 0x80; + + int dl = dest[0]; + int dr = dest[MV_RightChannelOffset/2]; + + int sll = MV_LeftVolume[sl * 2 + 1]; + int slh = MV_LeftVolumeS[sh]; + + int srl = MV_RightVolume[sl * 2 + 1]; + int srh = MV_RightVolumeS[sh]; + + dl = sll + slh + 0x80 + dl; + dr = srl + srh + 0x80 + dr; + + if (dl < -32768) dl = -32768; + if (dl > 32767) dl = 32767; + if (dr < -32768) dr = -32768; + if (dr > 32767) dr = 32767; + + dest[0] = (short) dl; + dest[MV_RightChannelOffset/2] = (short) dr; + + position += rate; + dest += MV_SampleSize/2; + } + + MV_MixPosition = position; + MV_MixDestination = (char *)dest; +} diff --git a/audiolib/mv_mix16.asm b/audiolib/mv_mix16.asm new file mode 100755 index 0000000..f36cf47 --- /dev/null +++ b/audiolib/mv_mix16.asm @@ -0,0 +1,524 @@ + IDEAL + + p386 + MODEL flat + + dataseg + CODESEG + + MASM + ALIGN 4 + +EXTRN _MV_HarshClipTable:DWORD +EXTRN _MV_MixDestination:DWORD +EXTRN _MV_MixPosition:DWORD +EXTRN _MV_LeftVolume:DWORD +EXTRN _MV_RightVolume:DWORD +EXTRN _MV_SampleSize:DWORD +EXTRN _MV_RightChannelOffset:DWORD + +;================ +; +; MV_Mix8BitMono16 +; +;================ + +; eax - position +; edx - rate +; ebx - start +; ecx - number of samples to mix + +PROC MV_Mix8BitMono16_ +PUBLIC MV_Mix8BitMono16_ +; Two at once + pushad + mov ebp, eax + + mov esi, ebx ; Source pointer + inc esi + + ; Sample size + mov ebx, _MV_SampleSize + mov eax,OFFSET apatch7+2 ; convice tasm to modify code... + mov [eax],bl + mov eax,OFFSET apatch8+2 ; convice tasm to modify code... + mov [eax],bl + mov eax,OFFSET apatch9+3 ; convice tasm to modify code... + mov [eax],bl + + ; Volume table ptr + mov ebx, _MV_LeftVolume ; Since we're mono, use left volume + mov eax,OFFSET apatch1+4 ; convice tasm to modify code... + mov [eax],ebx + mov eax,OFFSET apatch2+4 ; convice tasm to modify code... + mov [eax],ebx + + ; Harsh Clip table ptr + mov ebx, _MV_HarshClipTable + add ebx, 128 + mov eax,OFFSET apatch3+2 ; convice tasm to modify code... + mov [eax],ebx + mov eax,OFFSET apatch4+2 ; convice tasm to modify code... + mov [eax],ebx + + ; Rate scale ptr + mov eax,OFFSET apatch5+2 ; convice tasm to modify code... + mov [eax],edx + mov eax,OFFSET apatch6+2 ; convice tasm to modify code... + mov [eax],edx + + mov edi, _MV_MixDestination ; Get the position to write to + + ; Number of samples to mix + shr ecx, 1 ; double sample count + cmp ecx, 0 + je exit8m + +; eax - scratch +; ebx - scratch +; edx - scratch +; ecx - count +; edi - destination +; esi - source +; ebp - frac pointer +; apatch1 - volume table +; apatch2 - volume table +; apatch3 - harsh clip table +; apatch4 - harsh clip table +; apatch5 - sample rate +; apatch6 - sample rate + + mov eax,ebp ; begin calculating first sample + add ebp,edx ; advance frac pointer + shr eax,16 ; finish calculation for first sample + + mov ebx,ebp ; begin calculating second sample + add ebp,edx ; advance frac pointer + shr ebx,16 ; finish calculation for second sample + + movsx eax, byte ptr [esi+2*eax] ; get first sample + movsx ebx, byte ptr [esi+2*ebx] ; get second sample + add eax, 80h + add ebx, 80h + + ALIGN 4 +mix8Mloop: + movzx edx, byte ptr [edi] ; get current sample from destination +apatch1: + movsx eax, byte ptr [2*eax+12345678h] ; volume translate first sample +apatch2: + movsx ebx, byte ptr [2*ebx+12345678h] ; volume translate second sample + add eax, edx ; mix first sample +apatch9: + movzx edx, byte ptr [edi + 1] ; get current sample from destination +apatch3: + mov eax, [eax + 12345678h] ; harsh clip new sample + add ebx, edx ; mix second sample + mov [edi], al ; write new sample to destination + mov edx, ebp ; begin calculating third sample +apatch4: + mov ebx, [ebx + 12345678h] ; harsh clip new sample +apatch5: + add ebp,12345678h ; advance frac pointer + shr edx, 16 ; finish calculation for third sample + mov eax, ebp ; begin calculating fourth sample +apatch7: + add edi, 2 ; move destination to second sample + shr eax, 16 ; finish calculation for fourth sample + mov [edi], bl ; write new sample to destination +apatch6: + add ebp,12345678h ; advance frac pointer + movsx ebx, byte ptr [esi+2*eax] ; get fourth sample + movsx eax, byte ptr [esi+2*edx] ; get third sample + add ebx, 80h + add eax, 80h +apatch8: + add edi, 2 ; move destination to third sample + dec ecx ; decrement count + jnz mix8Mloop ; loop + + mov _MV_MixDestination, edi ; Store the current write position + mov _MV_MixPosition, ebp ; return position +exit8m: + popad + ret +ENDP MV_Mix8BitMono16_ + +;================ +; +; MV_Mix8BitStereo16 +; +;================ + +; eax - position +; edx - rate +; ebx - start +; ecx - number of samples to mix + +PROC MV_Mix8BitStereo16_ +PUBLIC MV_Mix8BitStereo16_ + + pushad + mov ebp, eax + + mov esi, ebx ; Source pointer + inc esi + + ; Sample size + mov ebx, _MV_SampleSize + mov eax,OFFSET bpatch8+2 ; convice tasm to modify code... + mov [eax],bl + ; mov eax,OFFSET bpatch9+2 ; convice tasm to modify code... + ; mov [eax],bl + + ; Right channel offset + mov ebx, _MV_RightChannelOffset + mov eax,OFFSET bpatch6+3 ; convice tasm to modify code... + mov [eax],ebx + mov eax,OFFSET bpatch7+2 ; convice tasm to modify code... + mov [eax],ebx + + ; Volume table ptr + mov ebx, _MV_LeftVolume + mov eax,OFFSET bpatch1+4 ; convice tasm to modify code... + mov [eax],ebx + + mov ebx, _MV_RightVolume + mov eax,OFFSET bpatch2+4 ; convice tasm to modify code... + mov [eax],ebx + + ; Rate scale ptr + mov eax,OFFSET bpatch3+2 ; convice tasm to modify code... + mov [eax],edx + + ; Harsh Clip table ptr + mov ebx, _MV_HarshClipTable + add ebx,128 + mov eax,OFFSET bpatch4+2 ; convice tasm to modify code... + mov [eax],ebx + mov eax,OFFSET bpatch5+2 ; convice tasm to modify code... + mov [eax],ebx + + mov edi, _MV_MixDestination ; Get the position to write to + + ; Number of samples to mix + cmp ecx, 0 + je short exit8S + +; eax - scratch +; ebx - scratch +; edx - scratch +; ecx - count +; edi - destination +; esi - source +; ebp - frac pointer +; bpatch1 - left volume table +; bpatch2 - right volume table +; bpatch3 - sample rate +; bpatch4 - harsh clip table +; bpatch5 - harsh clip table + + mov eax,ebp ; begin calculating first sample + shr eax,16 ; finish calculation for first sample + + movsx ebx, byte ptr [esi+2*eax] ; get first sample + add ebx, 80h + + ALIGN 4 +mix8Sloop: +bpatch1: + movsx eax, byte ptr [2*ebx+12345678h] ; volume translate left sample + movzx edx, byte ptr [edi] ; get current sample from destination +bpatch2: + movsx ebx, byte ptr [2*ebx+12345678h] ; volume translate right sample + add eax, edx ; mix left sample +bpatch3: + add ebp,12345678h ; advance frac pointer +bpatch6: + movzx edx, byte ptr [edi+12345678h] ; get current sample from destination +bpatch4: + mov eax, [eax + 12345678h] ; harsh clip left sample + add ebx, edx ; mix right sample + mov [edi], al ; write left sample to destination +bpatch5: + mov ebx, [ebx + 12345678h] ; harsh clip right sample + mov edx, ebp ; begin calculating second sample +bpatch7: + mov [edi+12345678h], bl ; write right sample to destination + shr edx, 16 ; finish calculation for second sample +bpatch8: + add edi, 1 ; move destination to second sample + movsx ebx, byte ptr [esi+2*edx] ; get second sample + add ebx, 80h + dec ecx ; decrement count + jnz mix8Sloop ; loop + + mov _MV_MixDestination, edi ; Store the current write position + mov _MV_MixPosition, ebp ; return position + +EXIT8S: + popad + ret +ENDP MV_Mix8BitStereo16_ + +;================ +; +; MV_Mix16BitMono16 +; +;================ + +; eax - position +; edx - rate +; ebx - start +; ecx - number of samples to mix + +PROC MV_Mix16BitMono16_ +PUBLIC MV_Mix16BitMono16_ + + pushad + mov ebp, eax + + mov esi, ebx ; Source pointer + + ; Sample size + mov ebx, _MV_SampleSize + mov eax,OFFSET cpatch4+2 ; convice tasm to modify code... + mov [eax],bl + mov eax,OFFSET cpatch5+3 ; convice tasm to modify code... + mov [eax],bl + + ; Volume table ptr + mov ebx, _MV_LeftVolume + mov eax,OFFSET cpatch2+4 ; convice tasm to modify code... + mov [eax],ebx + mov eax,OFFSET cpatch1+4 ; convice tasm to modify code... + inc ebx + mov [eax],ebx + + ; Rate scale ptr + mov eax,OFFSET cpatch3+2 ; convice tasm to modify code... + mov [eax],edx + + mov edi, _MV_MixDestination ; Get the position to write to + + ; Number of samples to mix + cmp ecx, 0 + je exit16M + +; eax - scratch +; ebx - scratch +; edx - scratch +; ecx - count +; edi - destination +; esi - source +; ebp - frac pointer +; cpatch1 - volume table +; cpatch2 - volume table +; cpatch3 - sample rate +; cpatch4 - sample rate + + mov ebx,ebp ; begin calculating first sample + add ebp,edx ; advance frac pointer + shr ebx,16 ; finish calculation for first sample + movzx eax, word ptr [esi+2*ebx] ; get low byte of sample + xor eax, 8000h + movzx ebx, ah + sub ah, ah + + movsx edx, word ptr [edi] ; get current sample from destination + + ALIGN 4 +mix16Mloop: +cpatch1: + movsx eax, byte ptr [2*eax+12345678h] ; volume translate low byte of sample +cpatch2: + movsx ebx, word ptr [2*ebx+12345678h] ; volume translate high byte of sample + lea eax, [ eax + ebx + 80h ] ; mix high byte of sample + add eax, edx ; mix low byte of sample +cpatch5: + movsx edx, word ptr [edi + 2] ; get current sample from destination + + cmp eax, -32768 ; Harsh clip sample + jge short m16skip1 + mov eax, -32768 + jmp short m16skip2 +m16skip1: + cmp eax, 32767 + jle short m16skip2 + mov eax, 32767 +m16skip2: + mov ebx, ebp ; begin calculating second sample + mov [edi], ax ; write new sample to destination + + shr ebx, 16 ; finish calculation for second sample +cpatch3: + add ebp, 12345678h ; advance frac pointer + + movzx eax, word ptr [esi+2*ebx] ; get second sample +cpatch4: + add edi, 2 ; move destination to second sample + xor eax, 8000h + movzx ebx, ah + sub ah, ah + + dec ecx ; decrement count + jnz mix16Mloop ; loop + + mov _MV_MixDestination, edi ; Store the current write position + mov _MV_MixPosition, ebp ; return position +EXIT16M: + popad + ret +ENDP MV_Mix16BitMono16_ + +;================ +; +; MV_Mix16BitStereo16 +; +;================ + +; eax - position +; edx - rate +; ebx - start +; ecx - number of samples to mix + +PROC MV_Mix16BitStereo16_ +PUBLIC MV_Mix16BitStereo16_ + + pushad + mov ebp, eax + + mov esi, ebx ; Source pointer + + ; Sample size + mov ebx, _MV_SampleSize + mov eax,OFFSET dpatch9+2 ; convice tasm to modify code... + mov [eax],bl + + ; Right channel offset + mov ebx, _MV_RightChannelOffset + mov eax,OFFSET dpatch7+3 ; convice tasm to modify code... + mov [eax],ebx + mov eax,OFFSET dpatch8+3 ; convice tasm to modify code... + mov [eax],ebx + + ; Volume table ptr + mov ebx, _MV_LeftVolume + mov eax,OFFSET dpatch1+4 ; convice tasm to modify code... + mov [eax],ebx + mov eax,OFFSET dpatch2+4 ; convice tasm to modify code... + inc ebx + mov [eax],ebx + + mov ebx, _MV_RightVolume + mov eax,OFFSET dpatch3+4 ; convice tasm to modify code... + mov [eax],ebx + mov eax,OFFSET dpatch4+4 ; convice tasm to modify code... + inc ebx + mov [eax],ebx + + ; Rate scale ptr + mov eax,OFFSET dpatch5+2 ; convice tasm to modify code... + mov [eax],edx + + ; Source ptr + mov eax,OFFSET dpatch6+4 ; convice tasm to modify code... + mov [eax],esi + + mov edi, _MV_MixDestination ; Get the position to write to + + ; Number of samples to mix + cmp ecx, 0 + je exit16S + +; eax - scratch +; ebx - scratch +; edx - scratch +; esi - scratch +; ecx - count +; edi - destination +; ebp - frac pointer +; dpatch1 - left volume table +; dpatch2 - right volume table +; dpatch3 - sample rate + + mov ebx,ebp ; begin calculating first sample + shr ebx,16 ; finish calculation for first sample + + movzx edx, word ptr [esi+2*ebx] ; get first sample + xor edx, 8000h ; Change from signed to unsigned + movzx esi, dh ; put high byte in esi + sub dh, dh ; lo byte in edx + + ALIGN 4 +mix16Sloop: + ; Left channel +dpatch1: + movsx eax, word ptr [2*esi+12345678h] ; volume translate high byte of sample +dpatch2: + movsx ebx, byte ptr [2*edx+12345678h] ; volume translate low byte of sample + lea eax, [ eax + ebx + 80h ] ; mix high byte of sample + + ; Right channel +dpatch3: + movsx esi, word ptr [2*esi+12345678h] ; volume translate high byte of sample +dpatch4: + movsx ebx, byte ptr [2*edx+12345678h] ; volume translate low byte of sample + lea ebx, [ esi + ebx + 80h ] ; mix high byte of sample + +dpatch7: + movsx edx, word ptr [edi+12345678h] ; get current sample from destination +dpatch5: + add ebp,12345678h ; advance frac pointer + + add eax, edx ; mix left sample + + cmp eax, -32768 ; Harsh clip sample + jge short s16skip1 + mov eax, -32768 + jmp short s16skip2 +s16skip1: + cmp eax, 32767 + jle short s16skip2 + mov eax, 32767 +s16skip2: + movsx edx, word ptr [edi+2] ; get current sample from destination + mov [edi], ax ; write left sample to destination + add ebx, edx ; mix right sample + + cmp ebx, -32768 ; Harsh clip sample + jge short s16skip3 + mov ebx, -32768 + jmp short s16skip4 +s16skip3: + cmp ebx, 32767 + jle short s16skip4 + mov ebx, 32767 +s16skip4: + + mov edx, ebp ; begin calculating second sample +dpatch8: + mov [edi+12345678h], bx ; write right sample to destination + shr edx, 16 ; finish calculation for second sample +dpatch9: + add edi, 4 ; move destination to second sample + +dpatch6: + movzx edx, word ptr [2*edx+12345678h] ; get second sample + xor edx, 8000h ; Change from signed to unsigned + movzx esi, dh ; put high byte in esi + sub dh, dh ; lo byte in edx + + dec ecx ; decrement count + jnz mix16Sloop ; loop + + mov _MV_MixDestination, edi ; Store the current write position + mov _MV_MixPosition, ebp ; return position +exit16S: + popad + ret +ENDP MV_Mix16BitStereo16_ + + ENDS + + END diff --git a/audiolib/mvreverb.asm b/audiolib/mvreverb.asm new file mode 100755 index 0000000..8a23ccc --- /dev/null +++ b/audiolib/mvreverb.asm @@ -0,0 +1,181 @@ + IDEAL + + p386 + MODEL flat + + dataseg + CODESEG + + MASM + ALIGN 4 + +;================ +; +; MV_16BitReverb +; +;================ + +; eax - source position +; edx - destination position +; ebx - Volume table +; ecx - number of samples + +PROC MV_16BitReverb_ +PUBLIC MV_16BitReverb_ + + mov esi, eax + lea edi, [edx - 2] + + ALIGN 4 +rev16loop: + movzx eax, word ptr [esi] ; get sample + add edi, 2 + + movzx edx, ah + sub ah, ah + + movsx eax, byte ptr [2*eax+ebx+1] ; volume translate low byte of sample + xor edx, 80h + + movsx edx, word ptr [2*edx+ebx] ; volume translate high byte of sample + add esi, 2 + + lea eax, [ eax + edx + 80h ] ; mix high byte of sample + dec ecx ; decrement count + + mov [edi], ax ; write new sample to destination + jnz rev16loop ; loop + + ret +ENDP MV_16BitReverb_ + +;================ +; +; MV_8BitReverb +; +;================ + +; eax - source position +; edx - destination position +; ebx - Volume table +; ecx - number of samples + +PROC MV_8BitReverb_ +PUBLIC MV_8BitReverb_ + + mov esi, eax + lea edi, [edx - 1] + + xor eax, eax + + ALIGN 4 +rev8loop: +; movzx eax, byte ptr [esi] ; get sample + mov al, byte ptr [esi] ; get sample + inc edi + +; movsx eax, byte ptr [2*eax+ebx] ; volume translate sample + mov al, byte ptr [2*eax+ebx] ; volume translate sample + inc esi + +; add eax, 80h + add al, 80h + dec ecx ; decrement count + + mov [edi], al ; write new sample to destination + jnz rev8loop ; loop + + ret +ENDP MV_8BitReverb_ + +;================ +; +; MV_16BitReverbFast +; +;================ + +; eax - source position +; edx - destination position +; ebx - number of samples +; ecx - shift + +PROC MV_16BitReverbFast_ +PUBLIC MV_16BitReverbFast_ + + mov esi, eax + mov eax,OFFSET rpatch16+3 + + mov [eax],cl + lea edi, [edx - 2] + + ALIGN 4 +frev16loop: + mov ax, word ptr [esi] ; get sample + add edi, 2 + +rpatch16: + sar ax, 5 ;;;;Add 1 before shift + add esi, 2 + + mov [edi], ax ; write new sample to destination + dec ebx ; decrement count + + jnz frev16loop ; loop + + ret +ENDP MV_16BITREVERBFAST_ + +;================ +; +; MV_8BitReverbFast +; +;================ + +; eax - source position +; edx - destination position +; ebx - number of samples +; ecx - shift + +PROC MV_8BitReverbFast_ +PUBLIC MV_8BitReverbFast_ + mov esi, eax + mov eax,OFFSET rpatch8+2 + + mov edi, edx + mov edx, 80h + + mov [eax],cl + mov eax, 80h + + shr eax, cl + + dec edi + sub edx, eax + + ALIGN 4 +frev8loop: + mov al, byte ptr [esi] ; get sample + inc esi + + mov ecx, eax + inc edi + +rpatch8: + shr eax, 3 + xor ecx, 80h ; flip the sign bit + + shr ecx, 7 ; shift the sign down to 1 + add eax, edx + + add eax, ecx ; add sign bit to round to 0 + dec ebx ; decrement count + + mov [edi], al ; write new sample to destination + jnz frev8loop ; loop + + ret +ENDP MV_8BITREVERBFAST_ + + ENDS + + END diff --git a/audiolib/mvreverb.c b/audiolib/mvreverb.c new file mode 100755 index 0000000..f818df7 --- /dev/null +++ b/audiolib/mvreverb.c @@ -0,0 +1,63 @@ +#include "multivoc.h" +#include "_multivc.h" + +void MV_16BitReverb( const char *src, char *dest, const VOLUME16 *volume, int count ) +{ + int i; + + short *pdest = (short *)dest; + + for (i = 0; i < count; i++) { + #if PLATFORM_BIGENDIAN + int sl = src[i*2+1]; + int sh = src[i*2+0] ^ 0x80; + #else + int sl = src[i*2+0]; + int sh = src[i*2+1] ^ 0x80; + #endif + + sl = (*volume)[sl] >> 8; + sh = (*volume)[sh]; + + pdest[i] = (short)(sl + sh + 0x80); + } +} + +void MV_8BitReverb( const signed char *src, signed char *dest, const VOLUME16 *volume, int count ) +{ + int i; + + for (i = 0; i < count; i++) { + unsigned char s = (unsigned char) src[i]; + + s = (*volume)[s] & 0xff; + + dest[i] = (char)(s + 0x80); + } +} + +void MV_16BitReverbFast( const char *src, char *dest, int count, int shift ) +{ + int i; + + short *pdest = (short *)dest; + const short *psrc = (const short *)src; + + for (i = 0; i < count; i++) { + pdest[i] = psrc[i] >> shift; + } +} + +void MV_8BitReverbFast( const signed char *src, signed char *dest, int count, int shift ) +{ + int i; + + unsigned char sh = 0x80 - (0x80 >> shift); + + for (i = 0; i < count; i++) { + unsigned char a = ((unsigned char) src[i]) >> shift; + unsigned char c = (((unsigned char) src[i]) ^ 0x80) >> 7; + + dest[i] = (signed char) (a + sh + c); + } +} diff --git a/audiolib/myprint.c b/audiolib/myprint.c new file mode 100755 index 0000000..e8b2c45 --- /dev/null +++ b/audiolib/myprint.c @@ -0,0 +1,310 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#include +#include +#include +#include "myprint.h" + +static unsigned short disp_offset = 160 * 24; + +void DrawText + ( + int x, + int y, + int ch, + int foreground, + int background + ) + + { + char *vid; + + vid = ( char * )( 0xb0000 ); + vid += y * 160; + vid += x * 2; + + if ( ch != NONE ) + { + *vid = ch; + } + vid++; + *vid = ( ( background & 0x0f ) << 4 ) | ( foreground & 0x0f ); + } + +void TextBox + ( + int x1, + int y1, + int x2, + int y2, + int ch, + int foreground, + int background + ) + + { + int x; + int y; + + for( x = x1; x <= x2; x++ ) + { + for( y = y1; y <= y2; y++ ) + { + DrawText( x, y, ch, foreground, background ); + } + } + } + +void TextFrame + ( + int x1, + int y1, + int x2, + int y2, + int type, + int foreground, + int background + ) + + { + int x; + int y; + + if ( type == 0 ) + { + for( x = x1 + 1; x < x2; x++ ) + { + DrawText( x, y1, type, foreground, background ); + DrawText( x, y2, type, foreground, background ); + } + for( y = y1 + 1; y < y2; y++ ) + { + DrawText( x1, y, type, foreground, background ); + DrawText( x2, y, type, foreground, background ); + } + } + if ( type == SINGLE_FRAME ) + { + DrawText( x1, y1, 'Ú', foreground, background ); + DrawText( x2, y1, '¿', foreground, background ); + DrawText( x1, y2, 'À', foreground, background ); + DrawText( x2, y2, 'Ù', foreground, background ); + for( x = x1 + 1; x < x2; x++ ) + { + DrawText( x, y1, 'Ä', foreground, background ); + DrawText( x, y2, 'Ä', foreground, background ); + } + for( y = y1 + 1; y < y2; y++ ) + { + DrawText( x1, y, '³', foreground, background ); + DrawText( x2, y, '³', foreground, background ); + } + } + if ( type == DOUBLE_FRAME ) + { + DrawText( x1, y1, 'É', foreground, background ); + DrawText( x2, y1, '»', foreground, background ); + DrawText( x1, y2, 'È', foreground, background ); + DrawText( x2, y2, '¼', foreground, background ); + for( x = x1 + 1; x < x2; x++ ) + { + DrawText( x, y1, 'Í', foreground, background ); + DrawText( x, y2, 'Í', foreground, background ); + } + for( y = y1 + 1; y < y2; y++ ) + { + DrawText( x1, y, 'º', foreground, background ); + DrawText( x2, y, 'º', foreground, background ); + } + } + } + +void mysetxy + ( + int x, + int y + ) + + { + disp_offset = ( x * 2 ) + ( y * 160 ); + } + +void myputch + ( + char ch + ) + + { + int j; + char *disp_start = (char *)( 0xb0000 ); + + if ( disp_offset >= 160 * 24 ) + { + for ( j = 160; j < 160 * 24; j += 2 ) + { + *( disp_start + j - 160 ) = *( disp_start + j ); + } + + disp_offset = 160 * 23; + + for ( j = disp_offset; j < ( 160 * 24 ); j += 2 ) + { + *( disp_start + j ) = ' '; + } + } + + if ( ch >= 32 ) + { + *( disp_start + disp_offset ) = ch; + disp_offset = disp_offset + 2; + } + + if ( ch == '\r' ) + { + disp_offset = disp_offset / 160; + disp_offset = disp_offset * 160; + } + + if ( ch == '\n' ) + { + disp_offset = disp_offset + 160; + if ( disp_offset < 160 * 24 ) + { + for ( j = disp_offset; j < ( ( ( disp_offset / 160 ) + 1 ) * + 160 ); j += 2 ) + { + *( disp_start + j ) = ' '; + } + } + } + } + +int printstring + ( + char *string + ) + + { + int count; + char *ptr; + + ptr = string; + count = 0; + + while ( *ptr ) + { + myputch( *ptr ); + count++; + ptr++; + } + + return( count ); + } + + +int printnum + ( + int number + ) + + { + char string[ 100 ]; + int count; + + itoa( number, string, 10 ); + count = printstring( string ); + + return( count ); + } + +int printunsigned + ( + unsigned long number, + int radix + ) + + { + char string[ 100 ]; + int count; + + ultoa( number, string, radix ); + count = printstring( string ); + + return( count ); + } + +int myprintf + ( + char *fmt, + ... + ) + + { + va_list argptr; + int count; + char *ptr; + + return( 0 ); + + // DEBUG + mysetxy( 0, 0 ); + + va_start( argptr, fmt ); + ptr = fmt; + count = 0; + + while( *ptr != 0 ) + { + if ( *ptr == '%' ) + { + ptr++; + switch( *ptr ) + { + case 0 : + return( EOF ); + break; + case 'd' : + count += printnum( va_arg( argptr, int ) ); + break; + case 's' : + count += printstring( va_arg( argptr, char * ) ); + break; + case 'u' : + count += printunsigned( va_arg( argptr, int ), 10 ); + break; + case 'x' : + case 'X' : + count += printunsigned( va_arg( argptr, int ), 16 ); + break; + } + ptr++; + } + else + { + myputch( *ptr ); + count++; + ptr++; + } + } + + va_end( argptr ); + + return( count ); + } diff --git a/audiolib/myprint.h b/audiolib/myprint.h new file mode 100755 index 0000000..19a5d0f --- /dev/null +++ b/audiolib/myprint.h @@ -0,0 +1,43 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +#ifndef __MYPRINT_H +#define __MYPRINT_H + +enum COLORS + { + BLACK, BLUE, GREEN, CYAN, RED, MAGENTA, BROWN, LIGHTGRAY, DARKGRAY, + LIGHTBLUE, LIGHTGREEN, LIGHTCYAN, LIGHTRED, LIGHTMAGENTA, YELLOW, WHITE + }; + +#define NONE -1 +#define SINGLE_FRAME -1 +#define DOUBLE_FRAME -2 + +void DrawText( int x, int y, int ch, int foreground, int background ); +void TextBox( int x1, int y1, int x2, int y2, int ch, int foreground, int background ); +void TextFrame( int x1, int y1, int x2, int y2, int type, int foreground, int background ); +void mysetxy( int x, int y ); +void myputch( char ch ); +int printstring( char *string ); +int printnum( int number ); +int printunsigned( unsigned long number, int radix ); +int myprintf( char *fmt, ... ); + +#endif diff --git a/audiolib/newgf1.h b/audiolib/newgf1.h new file mode 100755 index 0000000..fe9c857 --- /dev/null +++ b/audiolib/newgf1.h @@ -0,0 +1,431 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/*************************************************************************** +* NAME: GF1.H +** COPYRIGHT: +** "Copyright (c) 1991,1992, by FORTE +** +** "This software is furnished under a license and may be used, +** copied, or disclosed only in accordance with the terms of such +** license and with the inclusion of the above copyright notice. +** This software or any other copies thereof may not be provided or +** otherwise made available to any other person. No title to and +** ownership of the software is hereby transfered." +**************************************************************************** +* CREATION DATE: 07/01/92 +*--------------------------------------------------------------------------* +* VERSION DATE NAME DESCRIPTION +*> 1.0 07/01/92 Original +***************************************************************************/ + +#ifndef _GF1_H /* allow header to be processed only once */ +#define _GF1_H + +/* error codes */ +#define OK 0 +#define NO_MORE_VOICES -1 +#define BASE_NOT_FOUND 1 +#define BAD_IRQ 2 +#define BAD_DMA 3 +#define OS_LOADED 4 +#define NOT_LOADED 5 +#define NO_MEMORY 6 +#define DMA_BUSY 7 +#define NO_MORE_HANDLERS 8 +#define DMA_HUNG 9 +#define CARD_NOT_FOUND 10 +#define CARD_BEING_USED 11 +#define NO_MORE_INTERRUPTS 12 +#define BAD_TIMER 13 +#define BAD_PATCH 14 +#define OLD_PATCH 15 +#define DOS_ERROR 16 +#define FILE_NOT_FOUND 17 + +/* bits */ +#define BIT0 0x01 +#define BIT1 0x02 +#define BIT2 0x04 +#define BIT3 0x08 +#define BIT4 0x10 +#define BIT5 0x20 +#define BIT6 0x40 +#define BIT7 0x80 + +/* bounds for volume enveloping functions */ +#define MIN_OFFSET 5U +#define MAX_OFFSET 251U + +/* bounds for voice allocation */ +#define MIN_VOICES 14 +#define MAX_VOICES 32 + +/* DMA control bits */ +#define DMA_ENABLE BIT0 +#define DMA_READ BIT1 +#define DMA_WIDTH_16 BIT2 /* width of DMA channel */ +#define DMA_RATE_DIV_1 BIT3 +#define DMA_RATE_DIV_2 BIT4 +#define DMA_IRQ_ENABLE BIT5 +#define DMA_IRQ_PRESENT BIT6 +#define DMA_DATA_16 BIT6 /* width of data */ +#define DMA_INVERT_MSB BIT7 + +/* SAMPLE control bits */ +#define DMA_STEREO 2 + +/* DMA flags */ +#define GF1_RECORD 0 /* use dma control or sample control */ +#define GF1_DMA 1 + +/* MIDI control register */ +#define MIDI_RESET (BIT0|BIT1) +#define MIDI_TD_INT BIT5 +#define MIDI_RD_INT BIT7 + +/* MIDI_STATUS_REGISTER */ +#define MIDI_RD BIT0 +#define MIDI_TD BIT1 +#define MIDI_ERR_FRAMING BIT4 +#define MIDI_ERR_OVERRUN BIT5 + +/* digital playback flags */ +#define TYPE_8BIT BIT0 /* 1 use 8 bit data */ + /* 0 use 16 bit data */ +#define TYPE_PRELOAD BIT1 /* preload data */ +#define TYPE_INVERT_MSB BIT2 /* invert most significant bit during dma */ +#define TYPE_STEREO BIT3 /* 1 for stereo data */ + +/* sound effects and digital music types */ +#define SND_LOOP_MASK (BIT0|BIT1) +#define SND_LOOP_NONE 0 +#define SND_LOOP 1 +#define SND_LOOP_BIDIR 2 +#define SND_8BIT (BIT2) +#define SND_BACKWARD (BIT3) + +#define SOUND_PLAYING 2 +#define SOUND_ACTIVE 1 + +/* patch macros */ +#define HEADER_SIZE 12 +#define ID_SIZE 10 +#define DESC_SIZE 60 +#define RESERVED_SIZE 40 +#define PATCH_HEADER_RESERVED_SIZE 36 +#define LAYER_RESERVED_SIZE 40 +#define PATCH_DATA_RESERVED_SIZE 36 +#define GF1_HEADER_TEXT "GF1PATCH110" +#define INST_NAME_SIZE 16 +#define ENVELOPES 6 +#define MAX_LAYERS 4 + +/* patch modes */ +#define PATCH_16 BIT0 +#define PATCH_UNSIGNED BIT1 +#define PATCH_LOOPEN BIT2 +#define PATCH_BIDIR BIT3 +#define PATCH_BACKWARD BIT4 +#define PATCH_SUSTAIN BIT5 +#define PATCH_NO_SRELEASE BIT6 +#define PATCH_FAST_REL BIT7 + +/* flags for patch loading */ +#define PATCH_LOAD_8_BIT BIT0 + +/* digital playback callback reasons & return values */ +#define DIG_DONE 0 +#define DIG_MORE_DATA 1 +#define DIG_BUFFER_DONE 2 +#define DIG_PAUSE 3 + +/* log table used for vibrato and pitch bend. log table made public for +** developers use */ +#define LOG_TAB_SIZE 12 +extern long gf1_log_table[LOG_TAB_SIZE]; + +#if defined(__BORLANDC__) +#undef RFAR +#define RFAR far +#elif defined(_MSC_VER) && (_MSC_VER <= 600) +#define RFAR far +#elif defined(_MSC_VER) && (_MSC_VER > 600) +#define RFAR __far +#else +#undef RFAR +#define RFAR +#endif + +/* structure definitions */ +struct load_os +{ + unsigned short voices; + unsigned short forced_base_port; + unsigned char forced_gf1_irq; + unsigned char forced_midi_irq; + unsigned char forced_channel_in; + unsigned char forced_channel_out; +}; + +struct patchheader +{ + char header[ HEADER_SIZE ]; + char gravis_id[ ID_SIZE ]; /* Id = "ID#000002" */ + char description[ DESC_SIZE ]; + unsigned char instruments; + char voices; + char channels; + unsigned short wave_forms; + unsigned short master_volume; + unsigned long data_size; + char reserved[ PATCH_HEADER_RESERVED_SIZE ]; +}; + +struct instrumentdata +{ + unsigned short instrument; + char instrument_name[ INST_NAME_SIZE ]; + long instrument_size; + char layers; + char reserved[ RESERVED_SIZE ]; +}; + +struct layerdata +{ + char layer_duplicate; + char layer; + long layer_size; + char samples; + char reserved[ LAYER_RESERVED_SIZE ]; +}; + +struct patchdata +{ + char wave_name[7]; + unsigned char fractions; + long wave_size; + long start_loop; + long end_loop; + unsigned short sample_rate; + long low_frequency; + long high_frequency; + long root_frequency; + short tune; + unsigned char balance; + unsigned char envelope_rate[ ENVELOPES ]; + unsigned char envelope_offset[ ENVELOPES ]; + unsigned char tremolo_sweep; + unsigned char tremolo_rate; + unsigned char tremolo_depth; + unsigned char vibrato_sweep; + unsigned char vibrato_rate; + unsigned char vibrato_depth; + char modes; + short scale_frequency; + unsigned short scale_factor; /* from 0 to 2048 or 0 to 2 */ + char reserved[ PATCH_DATA_RESERVED_SIZE ]; +}; + +struct wave_struct +{ + unsigned long start_loop; + unsigned long end_loop; + long low_frequency; + long high_frequency; + long root_frequency; + unsigned long mem; + unsigned short scale_frequency; + unsigned short sample_rate; + unsigned short scale_factor; + unsigned short start_acc_low; + unsigned short start_acc_high; + unsigned short start_low; + unsigned short start_high; + unsigned short end_low; + unsigned short end_high; + unsigned short end_acc_low; + unsigned short end_acc_high; + unsigned short sample_ratio; + unsigned long wave_size; + unsigned char fractions; + unsigned char balance; + unsigned char envelope_rate[ ENVELOPES ]; + unsigned char envelope_offset[ ENVELOPES ]; + unsigned char tremolo_sweep; + unsigned char tremolo_rate; + unsigned char tremolo_depth; + unsigned char vibrato_sweep; + unsigned char vibrato_rate; + unsigned char vibrato_depth; + unsigned char modes; +}; + +struct patchinfo { + struct patchheader header; + struct instrumentdata idata; +}; + +struct patch { + short nlayers; + struct wave_struct RFAR *layer_waves[MAX_LAYERS]; + short layer_nwaves[MAX_LAYERS]; + unsigned short detune; +}; + +struct gf1_dma_buff { + unsigned char RFAR *vptr; + unsigned long paddr; +}; + +struct gf1_sound { + unsigned long mem_pos; + unsigned long start_loop; + unsigned long end_loop; + unsigned char type; +}; + +/* GLOBAL VARIABLES (flags) */ +extern char gf1_linear_volumes; +extern char gf1_dig_use_extra_voice; + +/* FUNCTION PROTOTYPES */ +/* Initializeation routines */ +int gf1_init_ports(int); +int gf1_load_os(struct load_os RFAR *os); +int gf1_unload_os(void); +void gf1_set_appname(char RFAR *); +void reset_ultra(int); +int gf1_asm_init(void); +unsigned char gf1_peek(unsigned long address); +void gf1_poke(unsigned long address, unsigned char data); +void gf1_poke_block(unsigned char RFAR *data, unsigned long address, unsigned long len, unsigned char dma_control); +char gf1_good_dram(unsigned long address); +int GetUltraCfg(struct load_os RFAR *os); +unsigned long gf1_malloc(unsigned long); +void gf1_free(unsigned long); +unsigned long gf1_mem_avail(void); +unsigned long gf1_mem_largest_avail(void); +void gf1_delay(void); +int gf1_allocate_voice(int priority, void (RFAR *steal_notify)(int)); +void gf1_free_voice(unsigned int i); +void gf1_adjust_priority(int voice, int priority); +int gf1_dram_xfer(struct gf1_dma_buff RFAR *dptr, unsigned long size, unsigned long dram_address, unsigned char dma_control, unsigned short flags); +void gf1_stop_dma(void); +long convert_to_16bit(long address); +int gf1_wait_dma(void); +int gf1_dma_ready(void); +unsigned long gf1_amount_xferred(void); +int gf1_detect_card(unsigned short port); +char *gf1_error_str(int); +int gf1_play_digital(unsigned short priority, unsigned char RFAR *buffer, + unsigned long size, unsigned long gf1_addr, unsigned short volume, + unsigned short pan, unsigned short frequency, unsigned char type, + struct gf1_dma_buff RFAR *dptr, + int (RFAR *callback)(int, int, unsigned char RFAR * RFAR *, unsigned long RFAR *)); +void gf1_restart_digital(int voice); +void gf1_start_digital(int voice); +void gf1_pause_digital(int voice); +void RFAR gf1_stop_digital(int voice); +void gf1_dig_set_dma_rate(unsigned short rate); +unsigned long gf1_digital_position(int voice); +int gf1_myatoi(void); +int gf1_update_waveform(struct wave_struct RFAR *wave_info); +int gf1_get_patch_info(char RFAR *patch_file, struct patchinfo RFAR *patch); +int gf1_load_patch(char RFAR *patch_file, struct patchinfo RFAR *patchinfo, + struct patch RFAR *patch, + struct gf1_dma_buff RFAR *dptr, unsigned short size, + unsigned char RFAR *wavemem, int flags); +void gf1_unload_patch(struct patch RFAR *patch); +void gf1_detune_patch(struct patch RFAR *patch, unsigned short detune); +unsigned short gf1_calc_fc(unsigned int sample_ratio,long root,long frequency); +void gf1_midi_stop_voice(int voice); +void gf1_midi_wait_voice(int voice); +unsigned short gf1_midi_status_note(int voice); +unsigned short gf1_midi_status_voice(int voice); +void RFAR gf1_midi_stop_note(int note_voice); +void gf1_midi_note_on(struct patch RFAR *patch, int priority, int note, int velocity, int channel); +void gf1_midi_note_off(int note, int channel); +void gf1_midi_silence_patch_notes(struct patch RFAR *patch); +void gf1_midi_patch_removed(struct patch RFAR *patch); +int gf1_enable_timer1(int (RFAR *callback)(void), int resolution); +int gf1_enable_timer2(int (RFAR *callback)(void), int resolution); +void gf1_disable_timer1(void); +void gf1_disable_timer2(void); +void gf1_channel_pitch_bend(int channel, unsigned int bend); +void gf1_midi_synth_volume(unsigned short synth, int master_volume); +void gf1_midi_change_program(struct patch RFAR *patch, int channel); +void gf1_midi_set_vibrato(int channel, int value); +void gf1_midi_change_volume(int channel, unsigned int volume); +void gf1_midi_set_balance(int balance, int channel); +void gf1_midi_channel_sustain(int channel, int sustain); +void gf1_midi_all_notes_off(int channel); +void gf1_midi_pitch_bend(int channel, int lsb, int msb); +void gf1_midi_parameter(int channel, int control, int value); +int gf1_midi_get_channel_notes(int channel, int notes[]); +int gf1_midi_get_channel_volume(int channel); +int gf1_midi_get_master_volume(void); +int gf1_midi_get_volume(int voice); +unsigned short gf1_read(int handle, void RFAR *io_buffer, unsigned short size); +unsigned short gf1_close_file(int handle); +unsigned int gf1_seek(int handle, unsigned long offset, int method); +int gf1_open(char RFAR *name); +#ifdef __FLAT__ +int gf1_atoi(char RFAR **str, int base); +#else +int gf1_atoi(void); +#endif +void gf1_leave(void); +short gf1_enter(void); +void gf1_enter1(void); +int gf1_play_next_buffer(int voice, unsigned char RFAR *buff, unsigned long size); +void gf1_dig_set_vol(unsigned short voice, unsigned short vol); +void gf1_dig_set_pan(unsigned short voice, unsigned short pan); +int gf1_set_external_semaphore(void RFAR *addr); +int gf1_clear_external_semaphore(void RFAR *addr); +void gf1_midi_reset(int c); +int gf1_add_midi_recv_handler(int (RFAR *handler)()); +int gf1_add_dma_handler(int (*handler)()); +int gf1_add_voice_handler(int (*handler)(int)); +int gf1_add_volume_handler(int (*handler)(int)); +int gf1_add_timer_handler(int timer, int (RFAR *handler)(void)); +void gf1_set_record_rate(unsigned long rate); +void gf1_create_patch(struct patch RFAR *patch); +int gf1_add_layer(struct patch RFAR *patch, int layer, char RFAR *wavemem); +void gf1_get_waveform_info(struct patch RFAR *patch, int layer, int waven, + struct wave_struct RFAR *wave); +void gf1_set_waveform_info(struct patch RFAR *patch, int layer, int waven, + struct wave_struct RFAR *wave); +void gf1_enable_line_in(void); +void gf1_disable_line_in(void); +void gf1_enable_mic_in(void); +void gf1_disable_mic_in(void); +void gf1_enable_output(void); +void gf1_disable_output(void); +void gf1_sound_volume(unsigned short voice, int volume, + unsigned long period /* us*10 */); +void gf1_sound_pan(unsigned short voice, unsigned short pan); +void gf1_sound_frequency(unsigned short voice, unsigned long freq); +void RFAR gf1_sound_stop(int voice); +void gf1_sound_mode(int voice, struct gf1_sound RFAR *sound, + unsigned char type); +int gf1_sound_start(unsigned short priority, struct gf1_sound RFAR *sound, + short volume, unsigned long period, short pan, unsigned long freq); +int gf1_sound_playing(int voice); +#endif diff --git a/audiolib/nodpmi.c b/audiolib/nodpmi.c new file mode 100755 index 0000000..cc8a30c --- /dev/null +++ b/audiolib/nodpmi.c @@ -0,0 +1,179 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: DPMI.C + + author: James R. Dose + date: April 8, 1994 + + Functions for performing DPMI calls. + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#include +#include +#include "dpmi.h" + +#define TRUE ( 1 == 1 ) +#define FALSE ( !TRUE ) + +/*--------------------------------------------------------------------- + Function: DPMI_GetRealModeVector + + Returns the vector of a real mode interrupt. +---------------------------------------------------------------------*/ + +unsigned long DPMI_GetRealModeVector + ( + int num + ) + + { + return 0; + } + + +/*--------------------------------------------------------------------- + Function: DPMI_SetRealModeVector + + Sets the vector of a real mode interrupt. +---------------------------------------------------------------------*/ + +void DPMI_SetRealModeVector + ( + int num, + unsigned long vector + ) + + { + } + + +/*--------------------------------------------------------------------- + Function: DPMI_CallRealModeFunction + + Performs a call to a real mode function. +---------------------------------------------------------------------*/ + +int DPMI_CallRealModeFunction + ( + dpmi_regs *callregs + ) + + { + return( DPMI_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: DPMI_LockMemory + + Locks a region of memory to keep the virtual memory manager from + paging the region out. +---------------------------------------------------------------------*/ + +int DPMI_LockMemory + ( + void *address, + unsigned length + ) + + { + return ( DPMI_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: DPMI_LockMemoryRegion + + Locks a region of memory to keep the virtual memory manager from + paging the region out. +---------------------------------------------------------------------*/ + +int DPMI_LockMemoryRegion + ( + void *start, + void *end + ) + + { + int status; + + status = DPMI_LockMemory( start, ( char * )end - ( char * )start ); + + return( status ); + } + + +/*--------------------------------------------------------------------- + Function: DPMI_UnlockMemory + + Unlocks a region of memory that was previously locked. +---------------------------------------------------------------------*/ + +int DPMI_UnlockMemory + ( + void *address, + unsigned length + ) + + { + return ( DPMI_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: DPMI_UnlockMemoryRegion + + Unlocks a region of memory that was previously locked. +---------------------------------------------------------------------*/ + +int DPMI_UnlockMemoryRegion + ( + void *start, + void *end + ) + + { + int status; + + status = DPMI_UnlockMemory( start, ( char * )end - ( char * )start ); + + return( status ); + } + +int DPMI_GetDOSMemory( void **ptr, int *descriptor, unsigned length ) +{ + /* Lovely... */ + + *ptr = (void *)malloc(length); + + *descriptor = (int) *ptr; + + return (descriptor == 0) ? DPMI_Error : DPMI_Ok; +} + +int DPMI_FreeDOSMemory( int descriptor ) +{ + free((void *)descriptor); + + return (descriptor == 0) ? DPMI_Error : DPMI_Ok; +} diff --git a/audiolib/nomusic.c b/audiolib/nomusic.c new file mode 100755 index 0000000..d655944 --- /dev/null +++ b/audiolib/nomusic.c @@ -0,0 +1,115 @@ +#include "music.h" + +char *MUSIC_ErrorString(int ErrorNumber) +{ + return ""; +} + +int MUSIC_Init(int SoundCard, int Address) +{ + return 0; +} + +int MUSIC_Shutdown(void) +{ + return 0; +} + +void MUSIC_SetMaxFMMidiChannel(int channel) +{ +} + +void MUSIC_SetVolume(int volume) +{ +} + +void MUSIC_SetMidiChannelVolume(int channel, int volume) +{ +} + +void MUSIC_ResetMidiChannelVolumes(void) +{ +} + +int MUSIC_GetVolume(void) +{ + return 0; +} + +void MUSIC_SetLoopFlag(int loopflag) +{ +} + +int MUSIC_SongPlaying(void) +{ + return 0; +} + +void MUSIC_Continue(void) +{ +} + +void MUSIC_Pause(void) +{ +} + +int MUSIC_StopSong(void) +{ + return 0; +} + +int MUSIC_PlaySong(unsigned char *song, int loopflag) +{ + return 0; +} + +void MUSIC_SetContext(int context) +{ +} + +int MUSIC_GetContext(void) +{ + return 0; +} + +void MUSIC_SetSongTick(unsigned long PositionInTicks) +{ +} + +void MUSIC_SetSongTime(unsigned long milliseconds) +{ +} + +void MUSIC_SetSongPosition(int measure, int beat, int tick) +{ +} + +void MUSIC_GetSongPosition(songposition *pos) +{ +} + +void MUSIC_GetSongLength(songposition *pos) +{ +} + +int MUSIC_FadeVolume(int tovolume, int milliseconds) +{ + return 0; +} + +int MUSIC_FadeActive(void) +{ + return 0; +} + +void MUSIC_StopFade(void) +{ +} + +void MUSIC_RerouteMidiChannel(int channel, int cdecl function( int event, int c1, int c2 )) +{ +} + +void MUSIC_RegisterTimbreBank(unsigned char *timbres) +{ +} diff --git a/audiolib/pas16.c b/audiolib/pas16.c new file mode 100755 index 0000000..d809739 --- /dev/null +++ b/audiolib/pas16.c @@ -0,0 +1,1924 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: PAS16.C + + author: James R. Dose + date: March 27, 1994 + + Low level routines to support Pro AudioSpectrum and compatible + sound cards. + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#include +#include +#include +#include +#include +#include "dpmi.h" +#include "dma.h" +#include "interrup.h" +#include "irq.h" +#include "pas16.h" +#include "_pas16.h" + +#define USESTACK + +static const int PAS_Interrupts[ PAS_MaxIrq + 1 ] = + { + INVALID, INVALID, 0xa, 0xb, + INVALID, 0xd, INVALID, 0xf, + INVALID, INVALID, 0x72, 0x73, + 0x74, INVALID, INVALID, 0x77 + }; + +static void ( interrupt far *PAS_OldInt )( void ); + +static int PAS_IntController1Mask; +static int PAS_IntController2Mask; + +static int PAS_Installed = FALSE; +static int PAS_TranslateCode = DEFAULT_BASE; + +static int PAS_OriginalPCMLeftVolume = 75; +static int PAS_OriginalPCMRightVolume = 75; + +static int PAS_OriginalFMLeftVolume = 75; +static int PAS_OriginalFMRightVolume = 75; + +unsigned int PAS_DMAChannel; +static int PAS_Irq; + +static MVState *PAS_State = NULL; +static MVFunc *PAS_Func = NULL; + +static MVState PAS_OriginalState; +static int PAS_SampleSizeConfig; + +static char *PAS_DMABuffer; +static char *PAS_DMABufferEnd; +static char *PAS_CurrentDMABuffer; +static int PAS_TotalDMABufferSize; + +static int PAS_TransferLength = 0; +static int PAS_MixMode = PAS_DefaultMixMode; +static unsigned PAS_SampleRate = PAS_DefaultSampleRate; +static int PAS_TimeInterval = 0; + +volatile int PAS_SoundPlaying; + +void ( *PAS_CallBack )( void ); + +// adequate stack size +#define kStackSize 2048 + +static unsigned short StackSelector = NULL; +static unsigned long StackPointer; + +static unsigned short oldStackSelector; +static unsigned long oldStackPointer; + +// This is defined because we can't create local variables in a +// function that switches stacks. +static int irqstatus; + +// These declarations are necessary to use the inline assembly pragmas. + +extern void GetStack(unsigned short *selptr,unsigned long *stackptr); +extern void SetStack(unsigned short selector,unsigned long stackptr); + +// This function will get the current stack selector and pointer and save +// them off. +#pragma aux GetStack = \ + "mov [edi],esp" \ + "mov ax,ss" \ + "mov [esi],ax" \ + parm [esi] [edi] \ + modify [eax esi edi]; + +// This function will set the stack selector and pointer to the specified +// values. +#pragma aux SetStack = \ + "mov ss,ax" \ + "mov esp,edx" \ + parm [ax] [edx] \ + modify [eax edx]; + +int PAS_ErrorCode = PAS_Ok; + +#define PAS_SetErrorCode( status ) \ + PAS_ErrorCode = ( status ); + +/*--------------------------------------------------------------------- + Function: PAS_ErrorString + + Returns a pointer to the error message associated with an error + number. A -1 returns a pointer the current error. +---------------------------------------------------------------------*/ + +char *PAS_ErrorString + ( + int ErrorNumber + ) + + { + char *ErrorString; + + switch( ErrorNumber ) + { + case PAS_Warning : + case PAS_Error : + ErrorString = PAS_ErrorString( PAS_ErrorCode ); + break; + + case PAS_Ok : + ErrorString = "Pro AudioSpectrum ok."; + break; + + case PAS_DriverNotFound : + ErrorString = "MVSOUND.SYS not loaded."; + break; + + case PAS_DmaError : + ErrorString = DMA_ErrorString( DMA_Error ); + break; + + case PAS_InvalidIrq : + ErrorString = "Invalid Pro AudioSpectrum Irq."; + break; + + case PAS_UnableToSetIrq : + ErrorString = "Unable to set Pro AudioSpectrum IRQ. Try selecting an IRQ of 7 or below."; + break; + + case PAS_Dos4gwIrqError : + ErrorString = "Unsupported Pro AudioSpectrum Irq."; + break; + + case PAS_NoSoundPlaying : + ErrorString = "No sound playing on Pro AudioSpectrum."; + break; + + case PAS_CardNotFound : + ErrorString = "Could not find Pro AudioSpectrum."; + break; + + case PAS_DPMI_Error : + ErrorString = "DPMI Error in PAS16."; + break; + + case PAS_OutOfMemory : + ErrorString = "Out of conventional memory in PAS16."; + break; + + default : + ErrorString = "Unknown Pro AudioSpectrum error code."; + break; + } + + return( ErrorString ); + } + + +/********************************************************************** + + Memory locked functions: + +**********************************************************************/ + + +#define PAS_LockStart PAS_CheckForDriver + + +/*--------------------------------------------------------------------- + Function: PAS_CheckForDriver + + Checks to see if MVSOUND.SYS is installed. +---------------------------------------------------------------------*/ + +int PAS_CheckForDriver + ( + void + ) + + { + union REGS regs; + unsigned result; + + regs.w.ax = MV_CheckForDriver; + regs.w.bx = 0x3f3f; + + #ifdef __386__ + int386( MV_SoundInt, ®s, ®s ); + #else + int86( MV_SoundInt, ®s, ®s ); + #endif + + if ( regs.w.ax != MV_CheckForDriver ) + { + PAS_SetErrorCode( PAS_DriverNotFound ); + return( PAS_Error ); + } + + result = regs.w.bx ^ regs.w.cx ^ regs.w.dx; + if ( result != MV_Signature ) + { + PAS_SetErrorCode( PAS_DriverNotFound ); + return( PAS_Error ); + } + + return( PAS_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: PAS_GetStateTable + + Returns a pointer to the state table containing hardware state + information. The state table is necessary because the Pro Audio- + Spectrum contains only write-only registers. +---------------------------------------------------------------------*/ + +MVState *PAS_GetStateTable + ( + void + ) + + { + union REGS regs; + MVState *ptr; + + regs.w.ax = MV_GetPointerToStateTable; + + #ifdef __386__ + int386( MV_SoundInt, ®s, ®s ); + #else + int86( MV_SoundInt, ®s, ®s ); + #endif + + if ( regs.w.ax != MV_Signature ) + { + PAS_SetErrorCode( PAS_DriverNotFound ); + return( NULL ); + } + + #if defined(__WATCOMC__) && defined(__FLAT__) + ptr = ( MVState * )( ( ( ( unsigned )regs.w.dx ) << 4 ) + + ( ( unsigned )regs.w.bx ) ); + #else + ptr = MK_FP( regs.w.dx, regs.w.bx ); + #endif + + return( ptr ); + } + + +/*--------------------------------------------------------------------- + Function: PAS_GetFunctionTable + + Returns a pointer to the function table containing addresses of + driver functions. +---------------------------------------------------------------------*/ + +MVFunc *PAS_GetFunctionTable + ( + void + ) + + { + union REGS regs; + MVFunc *ptr; + + regs.w.ax = MV_GetPointerToFunctionTable; + + #ifdef __386__ + int386( MV_SoundInt, ®s, ®s ); + #else + int86( MV_SoundInt, ®s, ®s ); + #endif + + if ( regs.w.ax != MV_Signature ) + { + PAS_SetErrorCode( PAS_DriverNotFound ); + return( NULL ); + } + + #if defined(__WATCOMC__) && defined(__FLAT__) + ptr = ( MVFunc * )( ( ( ( unsigned )regs.w.dx ) << 4 ) + + ( ( unsigned )regs.w.bx ) ); + #else + ptr = MK_FP( regs.w.dx, regs.w.bx ); + #endif + + return( ptr ); + } + + +/*--------------------------------------------------------------------- + Function: PAS_GetCardSettings + + Returns the DMA and the IRQ channels of the sound card. +---------------------------------------------------------------------*/ + +int PAS_GetCardSettings + ( + void + ) + + { + union REGS regs; + int status; + + regs.w.ax = MV_GetDmaIrqInt; + + #ifdef __386__ + int386( MV_SoundInt, ®s, ®s ); + #else + int86( MV_SoundInt, ®s, ®s ); + #endif + + if ( regs.w.ax != MV_Signature ) + { + PAS_SetErrorCode( PAS_DriverNotFound ); + return( PAS_Error ); + } + + PAS_DMAChannel = regs.w.bx; + PAS_Irq = regs.w.cx; + + if ( PAS_Irq > PAS_MaxIrq ) + { + PAS_SetErrorCode( PAS_Dos4gwIrqError ); + return( PAS_Error ); + } + + if ( !VALID_IRQ( PAS_Irq ) ) + { + PAS_SetErrorCode( PAS_InvalidIrq ); + return( PAS_Error ); + } + + if ( PAS_Interrupts[ PAS_Irq ] == INVALID ) + { + PAS_SetErrorCode( PAS_InvalidIrq ); + return( PAS_Error ); + } + + status = DMA_VerifyChannel( PAS_DMAChannel ); + if ( status == DMA_Error ) + { + PAS_SetErrorCode( PAS_DmaError ); + return( PAS_Error ); + } + + return( PAS_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: PAS_EnableInterrupt + + Enables the triggering of the sound card interrupt. +---------------------------------------------------------------------*/ + +void PAS_EnableInterrupt + ( + void + ) + + { + int mask; + int data; + unsigned flags; + + flags = DisableInterrupts(); + + if ( PAS_Irq < 8 ) + { + mask = inp( 0x21 ) & ~( 1 << PAS_Irq ); + outp( 0x21, mask ); + } + else + { + mask = inp( 0xA1 ) & ~( 1 << ( PAS_Irq - 8 ) ); + outp( 0xA1, mask ); + + mask = inp( 0x21 ) & ~( 1 << 2 ); + outp( 0x21, mask ); + } + + // Flush any pending interrupts + PAS_Write( InterruptStatus, PAS_Read( InterruptStatus ) & 0x40 ); + + // Enable the interrupt on the PAS + data = PAS_State->intrctlr; + data |= SampleBufferInterruptFlag; + PAS_Write( InterruptControl, data ); + PAS_State->intrctlr = data; + + RestoreInterrupts( flags ); + } + + +/*--------------------------------------------------------------------- + Function: PAS_DisableInterrupt + + Disables the triggering of the sound card interrupt. +---------------------------------------------------------------------*/ + +void PAS_DisableInterrupt + ( + void + ) + + { + int mask; + int data; + unsigned flags; + + flags = DisableInterrupts(); + + // Disable the interrupt on the PAS + data = PAS_State->intrctlr; + data &= ~( SampleRateInterruptFlag | SampleBufferInterruptFlag ); + PAS_Write( InterruptControl, data ); + PAS_State->intrctlr = data; + + // Restore interrupt mask + if ( PAS_Irq < 8 ) + { + mask = inp( 0x21 ) & ~( 1 << PAS_Irq ); + mask |= PAS_IntController1Mask & ( 1 << PAS_Irq ); + outp( 0x21, mask ); + } + else + { + mask = inp( 0x21 ) & ~( 1 << 2 ); + mask |= PAS_IntController1Mask & ( 1 << 2 ); + outp( 0x21, mask ); + + mask = inp( 0xA1 ) & ~( 1 << ( PAS_Irq - 8 ) ); + mask |= PAS_IntController2Mask & ( 1 << ( PAS_Irq - 8 ) ); + outp( 0xA1, mask ); + } + + RestoreInterrupts( flags ); + } + + +/*--------------------------------------------------------------------- + Function: PAS_ServiceInterrupt + + Handles interrupt generated by sound card at the end of a voice + transfer. Calls the user supplied callback function. +---------------------------------------------------------------------*/ + +void interrupt far PAS_ServiceInterrupt + ( + void + ) + + { + #ifdef USESTACK + // save stack + GetStack( &oldStackSelector, &oldStackPointer ); + + // set our stack + SetStack( StackSelector, StackPointer ); + #endif + + irqstatus = PAS_Read( InterruptStatus ); + if ( ( irqstatus & SampleBufferInterruptFlag ) == 0 ) + { + #ifdef USESTACK + // restore stack + SetStack( oldStackSelector, oldStackPointer ); + #endif + + _chain_intr( PAS_OldInt ); + } + + // Clear the interrupt + irqstatus &= ~SampleBufferInterruptFlag; + PAS_Write( InterruptStatus, irqstatus ); + + // send EOI to Interrupt Controller + if ( PAS_Irq > 7 ) + { + outp( 0xA0, 0x20 ); + } + outp( 0x20, 0x20 ); + + + // Keep track of current buffer + PAS_CurrentDMABuffer += PAS_TransferLength; + if ( PAS_CurrentDMABuffer >= PAS_DMABufferEnd ) + { + PAS_CurrentDMABuffer = PAS_DMABuffer; + } + + // Call the caller's callback function + if ( PAS_CallBack != NULL ) + { + PAS_CallBack(); + } + + #ifdef USESTACK + // restore stack + SetStack( oldStackSelector, oldStackPointer ); + #endif + } + + +/*--------------------------------------------------------------------- + Function: PAS_Write + + Writes a byte of data to the sound card. +---------------------------------------------------------------------*/ + +void PAS_Write + ( + int Register, + int Data + ) + + { + int port; + + port = Register ^ PAS_TranslateCode; + outp( port, Data ); + } + + +/*--------------------------------------------------------------------- + Function: PAS_Read + + Reads a byte of data from the sound card. +---------------------------------------------------------------------*/ + +int PAS_Read + ( + int Register + ) + + { + int port; + int data; + + port = Register ^ PAS_TranslateCode; + data = inp( port ); + return( data ); + } + + +/*--------------------------------------------------------------------- + Function: PAS_SetSampleRateTimer + + Programs the Sample Rate Timer. +---------------------------------------------------------------------*/ + +void PAS_SetSampleRateTimer + ( + void + ) + + { + int LoByte; + int HiByte; + int data; + unsigned flags; + + flags = DisableInterrupts(); + + // Disable the Sample Rate Timer + data = PAS_State->audiofilt; + data &= ~SampleRateTimerGateFlag; + PAS_Write( AudioFilterControl, data ); + PAS_State->audiofilt = data; + + // Select the Sample Rate Timer + data = SelectSampleRateTimer; + PAS_Write( LocalTimerControl, data ); + PAS_State->tmrctlr = data; + + LoByte = lobyte( PAS_TimeInterval ); + HiByte = hibyte( PAS_TimeInterval ); + + // Program the Sample Rate Timer + PAS_Write( SampleRateTimer, LoByte ); + PAS_Write( SampleRateTimer, HiByte ); + PAS_State->samplerate = PAS_TimeInterval; + + RestoreInterrupts( flags ); + } + + +/*--------------------------------------------------------------------- + Function: PAS_SetSampleBufferCount + + Programs the Sample Buffer Count. +---------------------------------------------------------------------*/ + +void PAS_SetSampleBufferCount + ( + void + ) + + { + int LoByte; + int HiByte; + int count; + int data; + unsigned flags; + + flags = DisableInterrupts(); + + // Disable the Sample Buffer Count + data = PAS_State->audiofilt; + data &= ~SampleBufferCountGateFlag; + PAS_Write( AudioFilterControl, data ); + PAS_State->audiofilt = data; + + // Select the Sample Buffer Count + data = SelectSampleBufferCount; + PAS_Write( LocalTimerControl, data ); + PAS_State->tmrctlr = data; + + count = PAS_TransferLength; + + // Check if we're using a 16-bit DMA channel + if ( PAS_DMAChannel > 3 ) + { + count >>= 1; + } + + LoByte = lobyte( count ); + HiByte = hibyte( count ); + + // Program the Sample Buffer Count + PAS_Write( SampleBufferCount, LoByte ); + PAS_Write( SampleBufferCount, HiByte ); + PAS_State->samplecnt = count; + + RestoreInterrupts( flags ); + } + + +/*--------------------------------------------------------------------- + Function: PAS_SetPlaybackRate + + Sets the rate at which the digitized sound will be played in + hertz. +---------------------------------------------------------------------*/ + +void PAS_SetPlaybackRate + ( + unsigned rate + ) + + { + if ( rate < PAS_MinSamplingRate ) + { + rate = PAS_MinSamplingRate; + } + + if ( rate > PAS_MaxSamplingRate ) + { + rate = PAS_MaxSamplingRate; + } + + PAS_TimeInterval = ( unsigned )CalcTimeInterval( rate ); + if ( PAS_MixMode & STEREO ) + { + PAS_TimeInterval /= 2; + } + + // Keep track of what the actual rate is + PAS_SampleRate = CalcSamplingRate( PAS_TimeInterval ); + if ( PAS_MixMode & STEREO ) + { + PAS_SampleRate /= 2; + } + } + + +/*--------------------------------------------------------------------- + Function: PAS_GetPlaybackRate + + Returns the rate at which the digitized sound will be played in + hertz. +---------------------------------------------------------------------*/ + +unsigned PAS_GetPlaybackRate + ( + void + ) + + { + return( PAS_SampleRate ); + } + + +/*--------------------------------------------------------------------- + Function: PAS_SetMixMode + + Sets the sound card to play samples in mono or stereo. +---------------------------------------------------------------------*/ + +int PAS_SetMixMode + ( + int mode + ) + + { + mode &= PAS_MaxMixMode; + + // Check board revision. Revision # 0 can't play 16-bit data. + if ( ( PAS_State->intrctlr & 0xe0 ) == 0 ) + { + // Force the mode to 8-bit data. + mode &= ~SIXTEEN_BIT; + } + + PAS_MixMode = mode; + + PAS_SetPlaybackRate( PAS_SampleRate ); + + return( mode ); + } + + +/*--------------------------------------------------------------------- + Function: PAS_StopPlayback + + Ends the DMA transfer of digitized sound to the sound card. +---------------------------------------------------------------------*/ + +void PAS_StopPlayback + ( + void + ) + + { + int data; + + // Don't allow anymore interrupts + PAS_DisableInterrupt(); + + // Stop the transfer of digital data + data = PAS_State->crosschannel; + data &= PAS_PCMStopMask; + PAS_Write( CrossChannelControl, data ); + PAS_State->crosschannel = data; + + // Turn off 16-bit unsigned data + data = PAS_Read( SampleSizeConfiguration ); + data &= PAS_SampleSizeMask; + PAS_Write( SampleSizeConfiguration, data ); + + // Disable the DMA channel + DMA_EndTransfer( PAS_DMAChannel ); + + PAS_SoundPlaying = FALSE; + + PAS_DMABuffer = NULL; + } + + +/*--------------------------------------------------------------------- + Function: PAS_SetupDMABuffer + + Programs the DMAC for sound transfer. +---------------------------------------------------------------------*/ + +int PAS_SetupDMABuffer + ( + char *BufferPtr, + int BufferSize, + int mode + ) + + { + int DmaStatus; + int data; + + // Enable PAS Dma + data = PAS_State->crosschannel; + data |= PAS_DMAEnable; + PAS_Write( CrossChannelControl, data ); + PAS_State->crosschannel = data; + + DmaStatus = DMA_SetupTransfer( PAS_DMAChannel, BufferPtr, BufferSize, mode ); + if ( DmaStatus == DMA_Error ) + { + PAS_SetErrorCode( PAS_DmaError ); + return( PAS_Error ); + } + + PAS_DMABuffer = BufferPtr; + PAS_CurrentDMABuffer = BufferPtr; + PAS_TotalDMABufferSize = BufferSize; + PAS_DMABufferEnd = BufferPtr + BufferSize; + + return( PAS_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: PAS_GetCurrentPos + + Returns the offset within the current sound being played. +---------------------------------------------------------------------*/ + +int PAS_GetCurrentPos + ( + void + ) + + { + char *CurrentAddr; + int offset; + + if ( !PAS_SoundPlaying ) + { + PAS_SetErrorCode( PAS_NoSoundPlaying ); + return( PAS_Error ); + } + + CurrentAddr = DMA_GetCurrentPos( PAS_DMAChannel ); + if ( CurrentAddr == NULL ) + { + PAS_SetErrorCode( PAS_DmaError ); + return( PAS_Error ); + } + + offset = ( int )( ( ( unsigned long )CurrentAddr ) - + ( ( unsigned long )PAS_CurrentDMABuffer ) ); + + if ( PAS_MixMode & SIXTEEN_BIT ) + { + offset >>= 1; + } + + if ( PAS_MixMode & STEREO ) + { + offset >>= 1; + } + + return( offset ); + } + + +/*--------------------------------------------------------------------- + Function: PAS_GetFilterSetting + + Returns the bit settings for the appropriate filter level. +---------------------------------------------------------------------*/ + +int PAS_GetFilterSetting + ( + int rate + ) + + { + /* CD Quality 17897hz */ + if ( ( unsigned long )rate > ( unsigned long )17897L * 2 ) + { + /* 00001b 20hz to 17.8khz */ + return( 0x01 ); + } + + /* Cassette Quality 15090hz */ + if ( ( unsigned long )rate > ( unsigned long )15909L * 2 ) + { + /* 00010b 20hz to 15.9khz */ + return( 0x02 ); + } + + /* FM Radio Quality 11931hz */ + if ( ( unsigned long )rate > ( unsigned long )11931L * 2 ) + { + /* 01001b 20hz to 11.9khz */ + return( 0x09 ); + } + + /* AM Radio Quality 8948hz */ + if ( ( unsigned long )rate > ( unsigned long )8948L * 2 ) + { + /* 10001b 20hz to 8.9khz */ + return( 0x11 ); + } + + /* Telphone Quality 5965hz */ + if ( ( unsigned long )rate > ( unsigned long )5965L * 2 ) + { + /* 00100b 20hz to 5.9khz */ + return( 0x19 ); + } + + /* Male voice quality 2982hz */ + /* 111001b 20hz to 2.9khz */ + return( 0x04 ); + } + + +/*--------------------------------------------------------------------- + Function: PAS_BeginTransfer + + Starts playback of digitized sound on the sound card. +---------------------------------------------------------------------*/ + +void PAS_BeginTransfer + ( + int mode + ) + + { + int data; + + PAS_SetSampleRateTimer(); + + PAS_SetSampleBufferCount(); + + PAS_EnableInterrupt(); + + // Get sample size configuration + data = PAS_Read( SampleSizeConfiguration ); + + // Check board revision. Revision # 0 can't play 16-bit data. + if ( PAS_State->intrctlr & 0xe0 ) + { + data &= PAS_SampleSizeMask; + + // set sample size bit + if ( PAS_MixMode & SIXTEEN_BIT ) + { + data |= PAS_16BitSampleFlag; + } + } + + // set oversampling rate + data &= PAS_OverSamplingMask; + data |= PAS_4xOverSampling; + + // Set sample size configuration + PAS_Write( SampleSizeConfiguration, data ); + + // Get Cross channel setting + data = PAS_State->crosschannel; + data &= PAS_ChannelConnectMask; + if ( mode == RECORD ) + { + data |= PAS_PCMStartADC; + } + else + { + data |= PAS_PCMStartDAC; + } + + // set stereo mode bit + if ( !( PAS_MixMode & STEREO ) ) + { + data |= PAS_StereoFlag; + } + + PAS_Write( CrossChannelControl, data ); + PAS_State->crosschannel = data; + + // Get the filter appropriate filter setting + data = PAS_GetFilterSetting( PAS_SampleRate ); + + // Enable the Sample Rate Timer and Sample Buffer Count + data |= SampleRateTimerGateFlag | SampleBufferCountGateFlag; + + if ( mode != RECORD ) + { + // Enable audio (not Audio Mute) + data |= PAS_AudioMuteFlag; + } + + PAS_Write( AudioFilterControl, data ); + PAS_State->audiofilt = data; + + PAS_SoundPlaying = TRUE; + } + + +/*--------------------------------------------------------------------- + Function: PAS_BeginBufferedPlayback + + Begins multibuffered playback of digitized sound on the sound card. +---------------------------------------------------------------------*/ + +int PAS_BeginBufferedPlayback + ( + char *BufferStart, + int BufferSize, + int NumDivisions, + unsigned SampleRate, + int MixMode, + void ( *CallBackFunc )( void ) + ) + + { + int DmaStatus; + + PAS_StopPlayback(); + + PAS_SetMixMode( MixMode ); + PAS_SetPlaybackRate( SampleRate ); + + PAS_TransferLength = BufferSize / NumDivisions; + PAS_SetCallBack( CallBackFunc ); + + DmaStatus = PAS_SetupDMABuffer( BufferStart, BufferSize, DMA_AutoInitRead ); + if ( DmaStatus == PAS_Error ) + { + return( PAS_Error ); + } + + PAS_BeginTransfer( PLAYBACK ); + + return( PAS_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: PAS_BeginBufferedRecord + + Begins multibuffered recording of digitized sound on the sound card. +---------------------------------------------------------------------*/ + +int PAS_BeginBufferedRecord + ( + char *BufferStart, + int BufferSize, + int NumDivisions, + unsigned SampleRate, + int MixMode, + void ( *CallBackFunc )( void ) + ) + + { + int DmaStatus; + + PAS_StopPlayback(); + + PAS_SetMixMode( MixMode ); + PAS_SetPlaybackRate( SampleRate ); + + PAS_TransferLength = BufferSize / NumDivisions; + PAS_SetCallBack( CallBackFunc ); + + DmaStatus = PAS_SetupDMABuffer( BufferStart, BufferSize, DMA_AutoInitWrite ); + if ( DmaStatus == PAS_Error ) + { + return( PAS_Error ); + } + + PAS_BeginTransfer( RECORD ); + + return( PAS_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: PAS_CallInt + + Calls interrupt 2fh. +---------------------------------------------------------------------*/ + +int PAS_CallInt( int ebx, int ecx, int edx ); +#pragma aux PAS_CallInt = \ + "int 2fh", \ + parm [ ebx ] [ ecx ] [ edx ] modify exact [ eax ebx ecx edx esi edi ] value [ ebx ]; + + +/*--------------------------------------------------------------------- + Function: PAS_CallMVFunction + + Performs a call to a real mode function. +---------------------------------------------------------------------*/ + +int PAS_CallMVFunction + ( + unsigned long function, + int ebx, + int ecx, + int edx + ) + + { + dpmi_regs callregs; + int status; + + callregs.EBX = ebx; + callregs.ECX = ecx; + callregs.EDX = edx; + + callregs.SS = 0; + callregs.SP = 0; + + callregs.DS = 0; + callregs.ES = 0; + callregs.FS = 0; + callregs.GS = 0; + + callregs.IP = function; + callregs.CS = function >> 16; + + status = DPMI_CallRealModeFunction( &callregs ); + if ( status != DPMI_Ok ) + { + return( PAS_Error ); + } + + return( callregs.EBX & 0xff ); + } + + +/*--------------------------------------------------------------------- + Function: PAS_SetPCMVolume + + Sets the volume of digitized sound playback. +---------------------------------------------------------------------*/ + +int PAS_SetPCMVolume + ( + int volume + ) + + { + int status; + + volume = max( 0, volume ); + volume = min( volume, 255 ); + + volume *= 100; + volume /= 255; + + status = PAS_CallMVFunction( PAS_Func->SetMixer, volume, + OUTPUTMIXER, L_PCM ); + if ( status == PAS_Error ) + { + return( status ); + } + + status = PAS_CallMVFunction( PAS_Func->SetMixer, volume, + OUTPUTMIXER, R_PCM ); + if ( status == PAS_Error ) + { + return( status ); + } + + return( PAS_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: PAS_GetPCMVolume + + Returns the current volume of digitized sound playback. +---------------------------------------------------------------------*/ + +int PAS_GetPCMVolume + ( + void + ) + + { + int leftvolume; + int rightvolume; + int totalvolume; + + if ( PAS_Func == NULL ) + { + return( PAS_Error ); + } + + leftvolume = PAS_CallMVFunction( PAS_Func->GetMixer, 0, + OUTPUTMIXER, L_PCM ); + rightvolume = PAS_CallMVFunction( PAS_Func->GetMixer, 0, + OUTPUTMIXER, R_PCM ); + + if ( ( leftvolume == PAS_Error ) || ( rightvolume == PAS_Error ) ) + { + return( PAS_Error ); + } + + leftvolume &= 0xff; + rightvolume &= 0xff; + + totalvolume = ( rightvolume + leftvolume ) / 2; + totalvolume *= 255; + totalvolume /= 100; + return( totalvolume ); + } + + +/*--------------------------------------------------------------------- + Function: PAS_SetFMVolume + + Sets the volume of FM sound playback. +---------------------------------------------------------------------*/ + +void PAS_SetFMVolume + ( + int volume + ) + + { + volume = max( 0, volume ); + volume = min( volume, 255 ); + + volume *= 100; + volume /= 255; + if ( PAS_Func ) + { + PAS_CallMVFunction( PAS_Func->SetMixer, volume, OUTPUTMIXER, L_FM ); + PAS_CallMVFunction( PAS_Func->SetMixer, volume, OUTPUTMIXER, R_FM ); + } + } + + +/*--------------------------------------------------------------------- + Function: PAS_GetFMVolume + + Returns the current volume of FM sound playback. +---------------------------------------------------------------------*/ + +int PAS_GetFMVolume + ( + void + ) + + { + int leftvolume; + int rightvolume; + int totalvolume; + + if ( PAS_Func == NULL ) + { + return( 255 ); + } + + leftvolume = PAS_CallMVFunction( PAS_Func->GetMixer, 0, + OUTPUTMIXER, L_FM ) & 0xff; + rightvolume = PAS_CallMVFunction( PAS_Func->GetMixer, 0, + OUTPUTMIXER, R_FM ) & 0xff; + + totalvolume = ( rightvolume + leftvolume ) / 2; + totalvolume *= 255; + totalvolume /= 100; + totalvolume = min( 255, totalvolume ); + + return( totalvolume ); + } + + +/*--------------------------------------------------------------------- + Function: PAS_GetCardInfo + + Returns the maximum number of bits that can represent a sample + (8 or 16) and the number of channels (1 for mono, 2 for stereo). +---------------------------------------------------------------------*/ + +int PAS_GetCardInfo + ( + int *MaxSampleBits, + int *MaxChannels + ) + + { + int status; + + if ( PAS_State == NULL ) + { + status = PAS_CheckForDriver(); + if ( status != PAS_Ok ) + { + return( status ); + } + + PAS_State = PAS_GetStateTable(); + if ( PAS_State == NULL ) + { + return( PAS_Error ); + } + } + + *MaxChannels = 2; + + // Check board revision. Revision # 0 can't play 16-bit data. + if ( ( PAS_State->intrctlr & 0xe0 ) == 0 ) + { + *MaxSampleBits = 8; + } + else + { + *MaxSampleBits = 16; + } + + return( PAS_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: PAS_SetCallBack + + Specifies the user function to call at the end of a sound transfer. +---------------------------------------------------------------------*/ + +void PAS_SetCallBack + ( + void ( *func )( void ) + ) + + { + PAS_CallBack = func; + } + + +/*--------------------------------------------------------------------- + Function: PAS_FindCard + + Auto-detects the port the Pro AudioSpectrum is set for. +---------------------------------------------------------------------*/ + +int PAS_FindCard + ( + void + ) + + { + int status; + + status = PAS_TestAddress( DEFAULT_BASE ); + if ( status == 0 ) + { + PAS_TranslateCode = DEFAULT_BASE; + return( PAS_Ok ); + } + + status = PAS_TestAddress( ALT_BASE_1 ); + if ( status == 0 ) + { + PAS_TranslateCode = ALT_BASE_1; + return( PAS_Ok ); + } + + status = PAS_TestAddress( ALT_BASE_2 ); + if ( status == 0 ) + { + PAS_TranslateCode = ALT_BASE_2; + return( PAS_Ok ); + } + + status = PAS_TestAddress( ALT_BASE_3 ); + if ( status == 0 ) + { + PAS_TranslateCode = ALT_BASE_3; + return( PAS_Ok ); + } + + PAS_SetErrorCode( PAS_CardNotFound ); + return( PAS_Error ); + } + + +/*--------------------------------------------------------------------- + Function: PAS_SaveMusicVolume + + Saves the user's FM mixer settings. +---------------------------------------------------------------------*/ + +int PAS_SaveMusicVolume + ( + void + ) + + { + int status; + int data; + + if ( !PAS_Installed ) + { + status = PAS_CheckForDriver(); + if ( status != PAS_Ok ) + { + return( status ); + } + + PAS_State = PAS_GetStateTable(); + if ( PAS_State == NULL ) + { + return( PAS_Error ); + } + + PAS_Func = PAS_GetFunctionTable(); + if ( PAS_Func == NULL ) + { + return( PAS_Error ); + } + + status = PAS_GetCardSettings(); + if ( status != PAS_Ok ) + { + return( status ); + } + + status = PAS_FindCard(); + if ( status != PAS_Ok ) + { + return( status ); + } + + // Enable PAS Sound + data = PAS_State->audiofilt; + data |= PAS_AudioMuteFlag; + + PAS_Write( AudioFilterControl, data ); + PAS_State->audiofilt = data; + } + + status = PAS_CallMVFunction( PAS_Func->GetMixer, 0, OUTPUTMIXER, L_FM ); + if ( status != PAS_Error ) + { + PAS_OriginalFMLeftVolume = PAS_CallMVFunction( PAS_Func->GetMixer, + 0, OUTPUTMIXER, L_FM ) & 0xff; + + PAS_OriginalFMRightVolume = PAS_CallMVFunction( PAS_Func->GetMixer, + 0, OUTPUTMIXER, R_FM ) & 0xff; + + return( PAS_Ok ); + } + + return( PAS_Warning ); + } + + +/*--------------------------------------------------------------------- + Function: PAS_RestoreMusicVolume + + Restores the user's FM mixer settings. +---------------------------------------------------------------------*/ + +void PAS_RestoreMusicVolume + ( + void + ) + + { + if ( PAS_Func ) + { + PAS_CallMVFunction( PAS_Func->SetMixer, PAS_OriginalFMLeftVolume, + OUTPUTMIXER, L_FM ); + PAS_CallMVFunction( PAS_Func->SetMixer, PAS_OriginalFMRightVolume, + OUTPUTMIXER, R_FM ); + } + } + + +/*--------------------------------------------------------------------- + Function: PAS_SaveState + + Saves the original state of the PAS prior to use. +---------------------------------------------------------------------*/ + +void PAS_SaveState + ( + void + ) + + { + PAS_OriginalState.intrctlr = PAS_State->intrctlr; + PAS_OriginalState.audiofilt = PAS_State->audiofilt; + PAS_OriginalState.tmrctlr = PAS_State->tmrctlr; + PAS_OriginalState.samplerate = PAS_State->samplerate; + PAS_OriginalState.samplecnt = PAS_State->samplecnt; + PAS_OriginalState.crosschannel = PAS_State->crosschannel; + PAS_SampleSizeConfig = PAS_Read( SampleSizeConfiguration ); + } + + +/*--------------------------------------------------------------------- + Function: PAS_RestoreState + + Restores the original state of the PAS after use. +---------------------------------------------------------------------*/ + +void PAS_RestoreState + ( + void + ) + + { + int LoByte; + int HiByte; + + // Select the Sample Rate Timer + PAS_Write( LocalTimerControl, SelectSampleRateTimer ); + PAS_State->tmrctlr = SelectSampleRateTimer; + + PAS_Write( SampleRateTimer, PAS_OriginalState.samplerate ); + PAS_State->samplerate = PAS_OriginalState.samplerate; + + // Select the Sample Buffer Count + PAS_Write( LocalTimerControl, SelectSampleBufferCount ); + PAS_State->tmrctlr = SelectSampleBufferCount; + + LoByte = lobyte( PAS_OriginalState.samplecnt ); + HiByte = hibyte( PAS_OriginalState.samplecnt ); + PAS_Write( SampleRateTimer, LoByte ); + PAS_Write( SampleRateTimer, HiByte ); + PAS_State->samplecnt = PAS_OriginalState.samplecnt; + + PAS_Write( CrossChannelControl, PAS_OriginalState.crosschannel ); + PAS_State->crosschannel = PAS_OriginalState.crosschannel; + + PAS_Write( SampleSizeConfiguration, PAS_SampleSizeConfig ); + + PAS_Write( InterruptControl, PAS_OriginalState.intrctlr ); + PAS_State->intrctlr = PAS_OriginalState.intrctlr; + + PAS_Write( AudioFilterControl, PAS_OriginalState.audiofilt ); + PAS_State->audiofilt = PAS_OriginalState.audiofilt; + + PAS_Write( LocalTimerControl, PAS_OriginalState.tmrctlr ); + PAS_State->tmrctlr = PAS_OriginalState.tmrctlr; + } + + +/*--------------------------------------------------------------------- + Function: PAS_LockEnd + + Used for determining the length of the functions to lock in memory. +---------------------------------------------------------------------*/ + +static void PAS_LockEnd + ( + void + ) + + { + } + + +/*--------------------------------------------------------------------- + Function: allocateTimerStack + + Allocate a block of memory from conventional (low) memory and return + the selector (which can go directly into a segment register) of the + memory block or 0 if an error occured. +---------------------------------------------------------------------*/ + +static unsigned short allocateTimerStack + ( + unsigned short size + ) + + { + union REGS regs; + + // clear all registers + memset( ®s, 0, sizeof( regs ) ); + + // DPMI allocate conventional memory + regs.w.ax = 0x100; + + // size in paragraphs + regs.w.bx = ( size + 15 ) / 16; + + int386( 0x31, ®s, ®s ); + if (!regs.w.cflag) + { + // DPMI call returns selector in dx + // (ax contains real mode segment + // which is ignored here) + + return( regs.w.dx ); + } + + // Couldn't allocate memory. + return( NULL ); + } + + +/*--------------------------------------------------------------------- + Function: deallocateTimerStack + + Deallocate a block of conventional (low) memory given a selector to + it. Assumes the block was allocated with DPMI function 0x100. +---------------------------------------------------------------------*/ + +static void deallocateTimerStack + ( + unsigned short selector + ) + + { + union REGS regs; + + if ( selector != NULL ) + { + // clear all registers + memset( ®s, 0, sizeof( regs ) ); + + regs.w.ax = 0x101; + regs.w.dx = selector; + int386( 0x31, ®s, ®s ); + } + } + + +/*--------------------------------------------------------------------- + Function: PAS_Init + + Initializes the sound card and prepares the module to play + digitized sounds. +---------------------------------------------------------------------*/ + +int PAS_Init + ( + void + ) + + { + int Interrupt; + int status; + int data; + + if ( PAS_Installed ) + { + return( PAS_Ok ); + } + + PAS_IntController1Mask = inp( 0x21 ); + PAS_IntController2Mask = inp( 0xA1 ); + + status = PAS_CheckForDriver(); + if ( status != PAS_Ok ) + { + return( status ); + } + + PAS_State = PAS_GetStateTable(); + if ( PAS_State == NULL ) + { + return( PAS_Error ); + } + + PAS_Func = PAS_GetFunctionTable(); + if ( PAS_Func == NULL ) + { + return( PAS_Error ); + } + + status = PAS_GetCardSettings(); + if ( status != PAS_Ok ) + { + return( status ); + } + + status = PAS_FindCard(); + if ( status != PAS_Ok ) + { + return( status ); + } + + PAS_SaveState(); + + PAS_OriginalPCMLeftVolume = PAS_CallMVFunction( PAS_Func->GetMixer, 0, + OUTPUTMIXER, L_PCM ) & 0xff; + PAS_OriginalPCMRightVolume = PAS_CallMVFunction( PAS_Func->GetMixer, 0, + OUTPUTMIXER, R_PCM ) & 0xff; + + PAS_SoundPlaying = FALSE; + + PAS_SetCallBack( NULL ); + + PAS_DMABuffer = NULL; + + status = PAS_LockMemory(); + if ( status != PAS_Ok ) + { + PAS_UnlockMemory(); + return( status ); + } + + StackSelector = allocateTimerStack( kStackSize ); + if ( StackSelector == NULL ) + { + PAS_UnlockMemory(); + PAS_SetErrorCode( PAS_OutOfMemory ); + return( PAS_Error ); + } + + // Leave a little room at top of stack just for the hell of it... + StackPointer = kStackSize - sizeof( long ); + + // Install our interrupt handler + Interrupt = PAS_Interrupts[ PAS_Irq ]; + PAS_OldInt = _dos_getvect( Interrupt ); + if ( PAS_Irq < 8 ) + { + _dos_setvect( Interrupt, PAS_ServiceInterrupt ); + } + else + { + status = IRQ_SetVector( Interrupt, PAS_ServiceInterrupt ); + if ( status != IRQ_Ok ) + { + PAS_UnlockMemory(); + deallocateTimerStack( StackSelector ); + StackSelector = NULL; + PAS_SetErrorCode( PAS_UnableToSetIrq ); + return( PAS_Error ); + } + } + + // Enable PAS Sound + data = PAS_State->audiofilt; + data |= PAS_AudioMuteFlag; + + PAS_Write( AudioFilterControl, data ); + PAS_State->audiofilt = data; + + PAS_SetPlaybackRate( PAS_DefaultSampleRate ); + PAS_SetMixMode( PAS_DefaultMixMode ); + + PAS_Installed = TRUE; + + PAS_SetErrorCode( PAS_Ok ); + return( PAS_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: PAS_Shutdown + + Ends transfer of sound data to the sound card and restores the + system resources used by the card. +---------------------------------------------------------------------*/ + +void PAS_Shutdown + ( + void + ) + + { + int Interrupt; + + if ( PAS_Installed ) + { + // Halt the DMA transfer + PAS_StopPlayback(); + + // Restore the original interrupt + Interrupt = PAS_Interrupts[ PAS_Irq ]; + if ( PAS_Irq >= 8 ) + { + IRQ_RestoreVector( Interrupt ); + } + _dos_setvect( Interrupt, PAS_OldInt ); + + PAS_SoundPlaying = FALSE; + + PAS_DMABuffer = NULL; + + PAS_SetCallBack( NULL ); + + PAS_CallMVFunction( PAS_Func->SetMixer, PAS_OriginalPCMLeftVolume, + OUTPUTMIXER, L_PCM ); + PAS_CallMVFunction( PAS_Func->SetMixer, PAS_OriginalPCMRightVolume, + OUTPUTMIXER, R_PCM ); + +// DEBUG +// PAS_RestoreState(); + + PAS_UnlockMemory(); + + deallocateTimerStack( StackSelector ); + StackSelector = NULL; + + PAS_Installed = FALSE; + } + } + + +/*--------------------------------------------------------------------- + Function: PAS_UnlockMemory + + Unlocks all neccessary data. +---------------------------------------------------------------------*/ + +void PAS_UnlockMemory + ( + void + ) + + { + DPMI_UnlockMemoryRegion( PAS_LockStart, PAS_LockEnd ); + DPMI_Unlock( PAS_Interrupts ); + DPMI_Unlock( PAS_OldInt ); + DPMI_Unlock( PAS_IntController1Mask ); + DPMI_Unlock( PAS_IntController2Mask ); + DPMI_Unlock( PAS_Installed ); + DPMI_Unlock( PAS_TranslateCode ); + DPMI_Unlock( PAS_OriginalPCMLeftVolume ); + DPMI_Unlock( PAS_OriginalPCMRightVolume ); + DPMI_Unlock( PAS_OriginalFMLeftVolume ); + DPMI_Unlock( PAS_OriginalFMRightVolume ); + DPMI_Unlock( PAS_DMAChannel ); + DPMI_Unlock( PAS_Irq ); + DPMI_Unlock( PAS_State ); + DPMI_Unlock( PAS_Func ); + DPMI_Unlock( PAS_OriginalState ); + DPMI_Unlock( PAS_SampleSizeConfig ); + DPMI_Unlock( PAS_DMABuffer ); + DPMI_Unlock( PAS_DMABufferEnd ); + DPMI_Unlock( PAS_CurrentDMABuffer ); + DPMI_Unlock( PAS_TotalDMABufferSize ); + DPMI_Unlock( PAS_TransferLength ); + DPMI_Unlock( PAS_MixMode ); + DPMI_Unlock( PAS_SampleRate ); + DPMI_Unlock( PAS_TimeInterval ); + DPMI_Unlock( PAS_SoundPlaying ); + DPMI_Unlock( PAS_CallBack ); + DPMI_Unlock( PAS_ErrorCode ); + DPMI_Unlock( irqstatus ); + } + + +/*--------------------------------------------------------------------- + Function: PAS_LockMemory + + Locks all neccessary data. +---------------------------------------------------------------------*/ + +int PAS_LockMemory + ( + void + ) + + { + int status; + + status = DPMI_LockMemoryRegion( PAS_LockStart, PAS_LockEnd ); + status |= DPMI_Lock( PAS_Interrupts ); + status |= DPMI_Lock( PAS_OldInt ); + status |= DPMI_Lock( PAS_IntController1Mask ); + status |= DPMI_Lock( PAS_IntController2Mask ); + status |= DPMI_Lock( PAS_Installed ); + status |= DPMI_Lock( PAS_TranslateCode ); + status |= DPMI_Lock( PAS_OriginalPCMLeftVolume ); + status |= DPMI_Lock( PAS_OriginalPCMRightVolume ); + status |= DPMI_Lock( PAS_OriginalFMLeftVolume ); + status |= DPMI_Lock( PAS_OriginalFMRightVolume ); + status |= DPMI_Lock( PAS_DMAChannel ); + status |= DPMI_Lock( PAS_Irq ); + status |= DPMI_Lock( PAS_State ); + status |= DPMI_Lock( PAS_Func ); + status |= DPMI_Lock( PAS_OriginalState ); + status |= DPMI_Lock( PAS_SampleSizeConfig ); + status |= DPMI_Lock( PAS_DMABuffer ); + status |= DPMI_Lock( PAS_DMABufferEnd ); + status |= DPMI_Lock( PAS_CurrentDMABuffer ); + status |= DPMI_Lock( PAS_TotalDMABufferSize ); + status |= DPMI_Lock( PAS_TransferLength ); + status |= DPMI_Lock( PAS_MixMode ); + status |= DPMI_Lock( PAS_SampleRate ); + status |= DPMI_Lock( PAS_TimeInterval ); + status |= DPMI_Lock( PAS_SoundPlaying ); + status |= DPMI_Lock( PAS_CallBack ); + status |= DPMI_Lock( PAS_ErrorCode ); + status |= DPMI_Lock( irqstatus ); + + if ( status != DPMI_Ok ) + { + PAS_UnlockMemory(); + PAS_SetErrorCode( PAS_DPMI_Error ); + return( PAS_Error ); + } + + return( PAS_Ok ); + } diff --git a/audiolib/pas16.h b/audiolib/pas16.h new file mode 100755 index 0000000..5d63b6c --- /dev/null +++ b/audiolib/pas16.h @@ -0,0 +1,81 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: PAS16.H + + author: James R. Dose + date: March 27, 1994 + + Public header for for PAS16.C + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#ifndef __PAS16_H +#define __PAS16_H + +enum PAS_ERRORS + { + PAS_Warning = -2, + PAS_Error = -1, + PAS_Ok = 0, + PAS_DriverNotFound, + PAS_DmaError, + PAS_InvalidIrq, + PAS_UnableToSetIrq, + PAS_Dos4gwIrqError, + PAS_NoSoundPlaying, + PAS_CardNotFound, + PAS_DPMI_Error, + PAS_OutOfMemory + }; + +#define PAS_MaxMixMode STEREO_16BIT +#define PAS_DefaultSampleRate 11000 +#define PAS_DefaultMixMode MONO_8BIT +#define PAS_MaxIrq 15 + +#define PAS_MinSamplingRate 4000 +#define PAS_MaxSamplingRate 44000 + +extern unsigned int PAS_DMAChannel; + +char *PAS_ErrorString( int ErrorNumber ); +void PAS_SetPlaybackRate( unsigned rate ); +unsigned PAS_GetPlaybackRate( void ); +int PAS_SetMixMode( int mode ); +void PAS_StopPlayback( void ); +int PAS_GetCurrentPos( void ); +int PAS_BeginBufferedPlayback( char *BufferStart, int BufferSize, int NumDivisions, unsigned SampleRate, int MixMode, void ( *CallBackFunc )( void ) ); +int PAS_BeginBufferedRecord( char *BufferStart, int BufferSize, int NumDivisions, unsigned SampleRate, int MixMode, void ( *CallBackFunc )( void ) ); +int PAS_SetPCMVolume( int volume ); +int PAS_GetPCMVolume( void ); +void PAS_SetFMVolume( int volume ); +int PAS_GetFMVolume( void ); +int PAS_GetCardInfo( int *MaxSampleBits, int *MaxChannels ); +void PAS_SetCallBack( void ( *func )( void ) ); +int PAS_SaveMusicVolume( void ); +void PAS_RestoreMusicVolume( void ); +int PAS_Init( void ); +void PAS_Shutdown( void ); +void PAS_UnlockMemory( void ); +int PAS_LockMemory( void ); + +#endif diff --git a/audiolib/pitch.c b/audiolib/pitch.c new file mode 100755 index 0000000..dc63828 --- /dev/null +++ b/audiolib/pitch.c @@ -0,0 +1,258 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: PITCH.C + + author: James R. Dose + date: June 14, 1993 + + Routines for pitch scaling. + + (c) Copyright 1993 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#include +//#include +#include "dpmi.h" +#include "standard.h" +#include "pitch.h" + +#define MAXDETUNE 25 + +static unsigned long PitchTable[ 12 ][ MAXDETUNE ] = + { + { 0x10000, 0x10097, 0x1012f, 0x101c7, 0x10260, 0x102f9, 0x10392, 0x1042c, + 0x104c6, 0x10561, 0x105fb, 0x10696, 0x10732, 0x107ce, 0x1086a, 0x10907, + 0x109a4, 0x10a41, 0x10adf, 0x10b7d, 0x10c1b, 0x10cba, 0x10d59, 0x10df8, + 0x10e98 }, + { 0x10f38, 0x10fd9, 0x1107a, 0x1111b, 0x111bd, 0x1125f, 0x11302, 0x113a5, + 0x11448, 0x114eb, 0x1158f, 0x11634, 0x116d8, 0x1177e, 0x11823, 0x118c9, + 0x1196f, 0x11a16, 0x11abd, 0x11b64, 0x11c0c, 0x11cb4, 0x11d5d, 0x11e06, + 0x11eaf }, + { 0x11f59, 0x12003, 0x120ae, 0x12159, 0x12204, 0x122b0, 0x1235c, 0x12409, + 0x124b6, 0x12563, 0x12611, 0x126bf, 0x1276d, 0x1281c, 0x128cc, 0x1297b, + 0x12a2b, 0x12adc, 0x12b8d, 0x12c3e, 0x12cf0, 0x12da2, 0x12e55, 0x12f08, + 0x12fbc }, + { 0x1306f, 0x13124, 0x131d8, 0x1328d, 0x13343, 0x133f9, 0x134af, 0x13566, + 0x1361d, 0x136d5, 0x1378d, 0x13846, 0x138fe, 0x139b8, 0x13a72, 0x13b2c, + 0x13be6, 0x13ca1, 0x13d5d, 0x13e19, 0x13ed5, 0x13f92, 0x1404f, 0x1410d, + 0x141cb }, + { 0x1428a, 0x14349, 0x14408, 0x144c8, 0x14588, 0x14649, 0x1470a, 0x147cc, + 0x1488e, 0x14951, 0x14a14, 0x14ad7, 0x14b9b, 0x14c5f, 0x14d24, 0x14dea, + 0x14eaf, 0x14f75, 0x1503c, 0x15103, 0x151cb, 0x15293, 0x1535b, 0x15424, + 0x154ee }, + { 0x155b8, 0x15682, 0x1574d, 0x15818, 0x158e4, 0x159b0, 0x15a7d, 0x15b4a, + 0x15c18, 0x15ce6, 0x15db4, 0x15e83, 0x15f53, 0x16023, 0x160f4, 0x161c5, + 0x16296, 0x16368, 0x1643a, 0x1650d, 0x165e1, 0x166b5, 0x16789, 0x1685e, + 0x16934 }, + { 0x16a09, 0x16ae0, 0x16bb7, 0x16c8e, 0x16d66, 0x16e3e, 0x16f17, 0x16ff1, + 0x170ca, 0x171a5, 0x17280, 0x1735b, 0x17437, 0x17513, 0x175f0, 0x176ce, + 0x177ac, 0x1788a, 0x17969, 0x17a49, 0x17b29, 0x17c09, 0x17cea, 0x17dcc, + 0x17eae }, + { 0x17f91, 0x18074, 0x18157, 0x1823c, 0x18320, 0x18406, 0x184eb, 0x185d2, + 0x186b8, 0x187a0, 0x18888, 0x18970, 0x18a59, 0x18b43, 0x18c2d, 0x18d17, + 0x18e02, 0x18eee, 0x18fda, 0x190c7, 0x191b5, 0x192a2, 0x19391, 0x19480, + 0x1956f }, + { 0x1965f, 0x19750, 0x19841, 0x19933, 0x19a25, 0x19b18, 0x19c0c, 0x19d00, + 0x19df4, 0x19ee9, 0x19fdf, 0x1a0d5, 0x1a1cc, 0x1a2c4, 0x1a3bc, 0x1a4b4, + 0x1a5ad, 0x1a6a7, 0x1a7a1, 0x1a89c, 0x1a998, 0x1aa94, 0x1ab90, 0x1ac8d, + 0x1ad8b }, + { 0x1ae89, 0x1af88, 0x1b088, 0x1b188, 0x1b289, 0x1b38a, 0x1b48c, 0x1b58f, + 0x1b692, 0x1b795, 0x1b89a, 0x1b99f, 0x1baa4, 0x1bbaa, 0x1bcb1, 0x1bdb8, + 0x1bec0, 0x1bfc9, 0x1c0d2, 0x1c1dc, 0x1c2e6, 0x1c3f1, 0x1c4fd, 0x1c609, + 0x1c716 }, + { 0x1c823, 0x1c931, 0x1ca40, 0x1cb50, 0x1cc60, 0x1cd70, 0x1ce81, 0x1cf93, + 0x1d0a6, 0x1d1b9, 0x1d2cd, 0x1d3e1, 0x1d4f6, 0x1d60c, 0x1d722, 0x1d839, + 0x1d951, 0x1da69, 0x1db82, 0x1dc9c, 0x1ddb6, 0x1ded1, 0x1dfec, 0x1e109, + 0x1e225 }, + { 0x1e343, 0x1e461, 0x1e580, 0x1e6a0, 0x1e7c0, 0x1e8e0, 0x1ea02, 0x1eb24, + 0x1ec47, 0x1ed6b, 0x1ee8f, 0x1efb4, 0x1f0d9, 0x1f1ff, 0x1f326, 0x1f44e, + 0x1f576, 0x1f69f, 0x1f7c9, 0x1f8f3, 0x1fa1e, 0x1fb4a, 0x1fc76, 0x1fda3, + 0x1fed1 } + }; + + +//static int PITCH_Installed = FALSE; + + +/*--------------------------------------------------------------------- + Function: PITCH_Init + + Initializes pitch table. +---------------------------------------------------------------------*/ +/* +void PITCH_Init + ( + void + ) + + { + int note; + int detune; + + if ( !PITCH_Installed ) + { + for( note = 0; note < 12; note++ ) + { + for( detune = 0; detune < MAXDETUNE; detune++ ) + { + PitchTable[ note ][ detune ] = 0x10000 * + pow( 2, ( note * MAXDETUNE + detune ) / ( 12.0 * MAXDETUNE ) ); + } + } + + PITCH_Installed = TRUE; + } + } +*/ + +/********************************************************************** + + Memory locked functions: + +**********************************************************************/ + + +#define PITCH_LockStart PITCH_GetScale + + +/*--------------------------------------------------------------------- + Function: PITCH_GetScale + + Returns a fixed-point value to scale number the specified amount. +---------------------------------------------------------------------*/ + +unsigned long PITCH_GetScale + ( + int pitchoffset + ) + + { + unsigned long scale; + int octaveshift; + int noteshift; + int note; + int detune; + +// if ( !PITCH_Installed ) +// { +// PITCH_Init(); +// } + + if ( pitchoffset == 0 ) + { + return( PitchTable[ 0 ][ 0 ] ); + } + + noteshift = pitchoffset % 1200; + if ( noteshift < 0 ) + { + noteshift += 1200; + } + + note = noteshift / 100; + detune = ( noteshift % 100 ) / ( 100 / MAXDETUNE ); + octaveshift = ( pitchoffset - noteshift ) / 1200; + + if ( detune < 0 ) + { + detune += ( 100 / MAXDETUNE ); + note--; + if ( note < 0 ) + { + note += 12; + octaveshift--; + } + } + + scale = PitchTable[ note ][ detune ]; + + if ( octaveshift < 0 ) + { + scale >>= -octaveshift; + } + else + { + scale <<= octaveshift; + } + + return( scale ); + } + + +/*--------------------------------------------------------------------- + Function: PITCH_LockEnd + + Used for determining the length of the functions to lock in memory. +---------------------------------------------------------------------*/ + +static void PITCH_LockEnd + ( + void + ) + + { + } + + +/*--------------------------------------------------------------------- + Function: PITCH_UnlockMemory + + Unlocks all neccessary data. +---------------------------------------------------------------------*/ + +void PITCH_UnlockMemory + ( + void + ) + + { + DPMI_UnlockMemoryRegion( PITCH_LockStart, PITCH_LockEnd ); + DPMI_Unlock( PitchTable ); +// DPMI_Unlock( PITCH_Installed ); + } + + +/*--------------------------------------------------------------------- + Function: PITCH_LockMemory + + Unlocks all neccessary data. +---------------------------------------------------------------------*/ + +int PITCH_LockMemory + ( + void + ) + + { + int status; + + status = DPMI_LockMemoryRegion( PITCH_LockStart, PITCH_LockEnd ); + status |= DPMI_Lock( PitchTable ); +// status |= DPMI_Lock( PITCH_Installed ); + + if ( status != DPMI_Ok ) + { + PITCH_UnlockMemory(); + return( PITCH_Error ); + } + + return( PITCH_Ok ); + } diff --git a/audiolib/pitch.h b/audiolib/pitch.h new file mode 100755 index 0000000..f4f5c63 --- /dev/null +++ b/audiolib/pitch.h @@ -0,0 +1,45 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: PITCH.H + + author: James R. Dose + date: June 14, 1994 + + Public header for PITCH.C + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#ifndef __PITCH_H +#define __PITCH_H + +enum PITCH_ERRORS + { + PITCH_Warning = -2, + PITCH_Error = -1, + PITCH_Ok = 0, + }; + +//void PITCH_Init( void ); +unsigned long PITCH_GetScale( int pitchoffset ); +void PITCH_UnlockMemory( void ); +int PITCH_LockMemory( void ); +#endif diff --git a/audiolib/sndcards.h b/audiolib/sndcards.h new file mode 100755 index 0000000..39878b7 --- /dev/null +++ b/audiolib/sndcards.h @@ -0,0 +1,55 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: SNDCARDS.H + + author: James R. Dose + date: March 31, 1994 + + Contains enumerated type definitions for sound cards. + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#ifndef __SNDCARDS_H +#define __SNDCARDS_H + +#define ASS_VERSION_STRING "1.12" + +typedef enum + { +// ASS_NoSound, + SoundBlaster, + ProAudioSpectrum, + SoundMan16, + Adlib, + GenMidi, + SoundCanvas, + Awe32, + WaveBlaster, + SoundScape, + UltraSound, + SoundSource, + TandySoundSource, + PC, + NumSoundCards + } soundcardnames; + +#endif diff --git a/audiolib/sndscape.c b/audiolib/sndscape.c new file mode 100755 index 0000000..a177265 --- /dev/null +++ b/audiolib/sndscape.c @@ -0,0 +1,1661 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: SNDSCAPE.C + + author: James R. Dose + date: October 25, 1994 + + Low level routines to support the Ensoniq Soundscape. + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include "interrup.h" +#include "dpmi.h" +#include "dma.h" +#include "irq.h" +#include "sndscape.h" +#include "_sndscap.h" + +const int SOUNDSCAPE_Interrupts[ SOUNDSCAPE_MaxIrq + 1 ] = + { + INVALID, INVALID, 0xa, INVALID, + INVALID, 0xd, INVALID, 0xf, + INVALID, INVALID, 0x72, INVALID, + INVALID, INVALID, INVALID, INVALID + }; + +const int SOUNDSCAPE_SampleSize[ SOUNDSCAPE_MaxMixMode + 1 ] = + { + MONO_8BIT_SAMPLE_SIZE, STEREO_8BIT_SAMPLE_SIZE, + MONO_16BIT_SAMPLE_SIZE, STEREO_16BIT_SAMPLE_SIZE + }; + +static void ( __interrupt __far *SOUNDSCAPE_OldInt )( void ); + +static int SOUNDSCAPE_Installed = FALSE; +static int SOUNDSCAPE_FoundCard = FALSE; + +static char *SOUNDSCAPE_DMABuffer; +static char *SOUNDSCAPE_DMABufferEnd; +static char *SOUNDSCAPE_CurrentDMABuffer; +static int SOUNDSCAPE_TotalDMABufferSize; + +static int SOUNDSCAPE_TransferLength = 0; +static int SOUNDSCAPE_MixMode = SOUNDSCAPE_DefaultMixMode; +static int SOUNDSCAPE_SamplePacketSize = MONO_16BIT_SAMPLE_SIZE; +static unsigned SOUNDSCAPE_SampleRate = SOUNDSCAPE_DefaultSampleRate; + +volatile int SOUNDSCAPE_SoundPlaying; + +void ( *SOUNDSCAPE_CallBack )( void ); + +static int SOUNDSCAPE_IntController1Mask; +static int SOUNDSCAPE_IntController2Mask; + +// some globals for chip type, ports, DMA, IRQs ... and stuff +static struct + { + int BasePort; // base address of the Ensoniq gate-array chip + int WavePort; // the AD-1848 base address + int DMAChan; // the DMA channel used for PCM + int WaveIRQ; // the PCM IRQ + int MIDIIRQ; // the MPU-401 IRQ + int ChipID; // the Ensoniq chip type + int SBEmul; // SoundBlaster emulation flag + int CDROM; // CD-ROM flag + int IRQIndx; // the Wave IRQ index - for hardware regs + int OldIRQs; // Old IRQs flag to support older HW + } SOUNDSCAPE_Config; + +// adequate stack size +#define kStackSize 2048 + +static unsigned short StackSelector = NULL; +static unsigned long StackPointer; + +static unsigned short oldStackSelector; +static unsigned long oldStackPointer; + +// These declarations are necessary to use the inline assembly pragmas. + +extern void GetStack(unsigned short *selptr,unsigned long *stackptr); +extern void SetStack(unsigned short selector,unsigned long stackptr); + +// This function will get the current stack selector and pointer and save +// them off. +#pragma aux GetStack = \ + "mov [edi],esp" \ + "mov ax,ss" \ + "mov [esi],ax" \ + parm [esi] [edi] \ + modify [eax esi edi]; + +// This function will set the stack selector and pointer to the specified +// values. +#pragma aux SetStack = \ + "mov ss,ax" \ + "mov esp,edx" \ + parm [ax] [edx] \ + modify [eax edx]; + +int SOUNDSCAPE_DMAChannel = -1; + +int SOUNDSCAPE_ErrorCode = SOUNDSCAPE_Ok; + +#define SOUNDSCAPE_SetErrorCode( status ) \ + SOUNDSCAPE_ErrorCode = ( status ); + + +/*--------------------------------------------------------------------- + Function: SOUNDSCAPE_ErrorString + + Returns a pointer to the error message associated with an error + number. A -1 returns a pointer the current error. +---------------------------------------------------------------------*/ + +char *SOUNDSCAPE_ErrorString + ( + int ErrorNumber + ) + + { + char *ErrorString; + + switch( ErrorNumber ) + { + case SOUNDSCAPE_Warning : + case SOUNDSCAPE_Error : + ErrorString = SOUNDSCAPE_ErrorString( SOUNDSCAPE_ErrorCode ); + break; + + case SOUNDSCAPE_Ok : + ErrorString = "SoundScape ok."; + break; + + case SOUNDSCAPE_EnvNotFound : + ErrorString = "SNDSCAPE environment variable not set. This is used to locate \n" + "SNDSCAPE.INI which is used to describe your sound card setup."; + break; + + case SOUNDSCAPE_InitFileNotFound : + ErrorString = "Missing SNDSCAPE.INI file for SoundScape. This file should be \n" + "located in the directory indicated by the SNDSCAPE environment \n" + "variable or in 'C:\SNDSCAPE' if SNDSCAPE is not set."; + break; + + case SOUNDSCAPE_MissingProductInfo : + ErrorString = "Missing 'Product' field in SNDSCAPE.INI file for SoundScape."; + break; + + case SOUNDSCAPE_MissingPortInfo : + ErrorString = "Missing 'Port' field in SNDSCAPE.INI file for SoundScape."; + break; + + case SOUNDSCAPE_MissingDMAInfo : + ErrorString = "Missing 'DMA' field in SNDSCAPE.INI file for SoundScape."; + break; + + case SOUNDSCAPE_MissingIRQInfo : + ErrorString = "Missing 'IRQ' field in SNDSCAPE.INI file for SoundScape."; + break; + + case SOUNDSCAPE_MissingSBIRQInfo : + ErrorString = "Missing 'SBIRQ' field in SNDSCAPE.INI file for SoundScape."; + break; + + case SOUNDSCAPE_MissingSBENABLEInfo : + ErrorString = "Missing 'SBEnable' field in SNDSCAPE.INI file for SoundScape."; + break; + + case SOUNDSCAPE_MissingWavePortInfo : + ErrorString = "Missing 'WavePort' field in SNDSCAPE.INI file for SoundScape."; + break; + + case SOUNDSCAPE_HardwareError : + ErrorString = "Could not detect SoundScape. Make sure your SNDSCAPE.INI file \n" + "contains correct information about your hardware setup."; + break; + + case SOUNDSCAPE_NoSoundPlaying : + ErrorString = "No sound playing on SoundScape."; + break; + + case SOUNDSCAPE_InvalidSBIrq : + ErrorString = "Invalid SoundScape Irq in SBIRQ field of SNDSCAPE.INI."; + break; + + case SOUNDSCAPE_UnableToSetIrq : + ErrorString = "Unable to set SoundScape IRQ. Try selecting an IRQ of 7 or below."; + break; + + case SOUNDSCAPE_DmaError : + ErrorString = DMA_ErrorString( DMA_Error ); + break; + + case SOUNDSCAPE_DPMI_Error : + ErrorString = "DPMI Error in SoundScape."; + break; + + case SOUNDSCAPE_OutOfMemory : + ErrorString = "Out of conventional memory in SoundScape."; + break; + + default : + ErrorString = "Unknown SoundScape error code."; + break; + } + + return( ErrorString ); + } + + +/********************************************************************** + + Memory locked functions: + +**********************************************************************/ + + +#define SOUNDSCAPE_LockStart SOUNDSCAPE_EnableInterrupt + + +/*--------------------------------------------------------------------- + Function: SOUNDSCAPE_EnableInterrupt + + Enables the triggering of the sound card interrupt. +---------------------------------------------------------------------*/ + +static void SOUNDSCAPE_EnableInterrupt + ( + void + ) + + { + int mask; + + // Unmask system interrupt + if ( SOUNDSCAPE_Config.WaveIRQ < 8 ) + { + mask = inp( 0x21 ) & ~( 1 << SOUNDSCAPE_Config.WaveIRQ ); + outp( 0x21, mask ); + } + else + { + mask = inp( 0xA1 ) & ~( 1 << ( SOUNDSCAPE_Config.WaveIRQ - 8 ) ); + outp( 0xA1, mask ); + + mask = inp( 0x21 ) & ~( 1 << 2 ); + outp( 0x21, mask ); + } + + } + + +/*--------------------------------------------------------------------- + Function: SOUNDSCAPE_DisableInterrupt + + Disables the triggering of the sound card interrupt. +---------------------------------------------------------------------*/ + +static void SOUNDSCAPE_DisableInterrupt + ( + void + ) + + { + int mask; + + // Restore interrupt mask + if ( SOUNDSCAPE_Config.WaveIRQ < 8 ) + { + mask = inp( 0x21 ) & ~( 1 << SOUNDSCAPE_Config.WaveIRQ ); + mask |= SOUNDSCAPE_IntController1Mask & ( 1 << SOUNDSCAPE_Config.WaveIRQ ); + outp( 0x21, mask ); + } + else + { + mask = inp( 0x21 ) & ~( 1 << 2 ); + mask |= SOUNDSCAPE_IntController1Mask & ( 1 << 2 ); + outp( 0x21, mask ); + + mask = inp( 0xA1 ) & ~( 1 << ( SOUNDSCAPE_Config.WaveIRQ - 8 ) ); + mask |= SOUNDSCAPE_IntController2Mask & ( 1 << ( SOUNDSCAPE_Config.WaveIRQ - 8 ) ); + outp( 0xA1, mask ); + } + } + + +/*--------------------------------------------------------------------- + Function: SOUNDSCAPE_ServiceInterrupt + + Handles interrupt generated by sound card at the end of a voice + transfer. Calls the user supplied callback function. +---------------------------------------------------------------------*/ + +static void __interrupt __far SOUNDSCAPE_ServiceInterrupt + ( + void + ) + + { + // save stack + GetStack( &oldStackSelector, &oldStackPointer ); + + // set our stack + SetStack( StackSelector, StackPointer ); + + if ( !( inp( SOUNDSCAPE_Config.WavePort + AD_STATUS ) & 0x01 ) ) + { + // restore stack + SetStack( oldStackSelector, oldStackPointer ); + + // Wasn't our interrupt. Call the old one. + _chain_intr( SOUNDSCAPE_OldInt ); + } + + // clear the AD-1848 interrupt + outp( SOUNDSCAPE_Config.WavePort + AD_STATUS, 0x00 ); + + // Keep track of current buffer + SOUNDSCAPE_CurrentDMABuffer += SOUNDSCAPE_TransferLength; + if ( SOUNDSCAPE_CurrentDMABuffer >= SOUNDSCAPE_DMABufferEnd ) + { + SOUNDSCAPE_CurrentDMABuffer = SOUNDSCAPE_DMABuffer; + } + + // Call the caller's callback function + if ( SOUNDSCAPE_CallBack != NULL ) + { + SOUNDSCAPE_CallBack(); + } + + // restore stack + SetStack( oldStackSelector, oldStackPointer ); + + // send EOI to Interrupt Controller + if ( SOUNDSCAPE_Config.WaveIRQ > 7 ) + { + outp( 0xA0, 0x20 ); + } + outp( 0x20, 0x20 ); + } + + +/*--------------------------------------------------------------------- + Function: ga_read + + Reads Ensoniq indirect registers. +---------------------------------------------------------------------*/ + +static int ga_read + ( + int rnum + ) + + { + int data; + + outp( SOUNDSCAPE_Config.BasePort + GA_REGADDR, rnum ); + data = inp( SOUNDSCAPE_Config.BasePort + GA_REGDATA ); + return( data ); + } + + +/*--------------------------------------------------------------------- + Function: ga_write + + Writes to Ensoniq indirect registers. +---------------------------------------------------------------------*/ + +static void ga_write + ( + int rnum, + int value + ) + + { + outp( SOUNDSCAPE_Config.BasePort + GA_REGADDR, rnum ); + outp( SOUNDSCAPE_Config.BasePort + GA_REGDATA, value ); + } + + +/*--------------------------------------------------------------------- + Function: ad_read + + Reads the AD-1848 indirect registers. This function should not be + used while the AD-1848 mode change is enabled +---------------------------------------------------------------------*/ + +static int ad_read + ( + int rnum + ) + + { + int data; + + outp( SOUNDSCAPE_Config.WavePort + AD_REGADDR, rnum ); + data = inp( SOUNDSCAPE_Config.WavePort + AD_REGDATA ); + return( data ); + } + + +/*--------------------------------------------------------------------- + Function: ad_write + + Writes to the AD-1848 indirect registers. This function should + not be used while the AD-1848 mode change is enabled. +---------------------------------------------------------------------*/ + +static void ad_write + ( + int rnum, + int value + ) + + { + outp( SOUNDSCAPE_Config.WavePort + AD_REGADDR, rnum ); + outp( SOUNDSCAPE_Config.WavePort + AD_REGDATA, value ); + } + + +/*--------------------------------------------------------------------- + Function: tdelay + + Delay function - 250ms - for AD-1848 re-synch and autocalibration. +---------------------------------------------------------------------*/ + +static void tdelay + ( + void + ) + + { + long time; + unsigned flags; + + flags = DisableInterrupts(); + _enable(); + time = clock() + CLOCKS_PER_SEC/4; + while(clock() < time) + ; + + RestoreInterrupts( flags ); + } + + +/*--------------------------------------------------------------------- + Function: pcm_format + + Sets the PCM data format. +---------------------------------------------------------------------*/ + +static void pcm_format + ( + void + ) + + { + int format; + + // build the register value based on format + format = 0; + + switch( SOUNDSCAPE_SampleRate ) + { + case 11025: + format = 0x03; + break; + + case 22050: + format = 0x07; + break; + + case 44100: + format = 0x0b; + break; + + default: + // Set it to 11025 hz + format = 0x03; + break; + } + + // set other format bits and format globals + if ( SOUNDSCAPE_MixMode & SIXTEEN_BIT ) + { + format |= 0x40; + } + + if ( SOUNDSCAPE_MixMode & STEREO ) + { + format |= 0x10; + } + + // enable mode change, point to format reg + outp( SOUNDSCAPE_Config.WavePort + AD_REGADDR, 0x40 | AD_FORMAT ); + + // write the format + outp( SOUNDSCAPE_Config.WavePort + AD_REGDATA, format ); + + // delay for internal re-synch + tdelay(); + + // exit mode change state + outp( SOUNDSCAPE_Config.WavePort + AD_REGADDR, 0x00 ); + + // delay for autocalibration + tdelay(); + } + + +/*--------------------------------------------------------------------- + Function: SOUNDSCAPE_SetPlaybackRate + + Sets the rate at which the digitized sound will be played in + hertz. +---------------------------------------------------------------------*/ + +void SOUNDSCAPE_SetPlaybackRate + ( + unsigned rate + ) + + { + if ( rate < 20000 ) + { + rate = 11025; + } + else if ( rate < 30000 ) + { + rate = 22050; + } + else + { + rate = 44100; + } + + SOUNDSCAPE_SampleRate = rate; + + // Set the rate + pcm_format(); + } + + +/*--------------------------------------------------------------------- + Function: SOUNDSCAPE_GetPlaybackRate + + Returns the rate at which the digitized sound will be played in + hertz. +---------------------------------------------------------------------*/ + +unsigned SOUNDSCAPE_GetPlaybackRate + ( + void + ) + + { + return( SOUNDSCAPE_SampleRate ); + } + + +/*--------------------------------------------------------------------- + Function: SOUNDSCAPE_SetMixMode + + Sets the sound card to play samples in mono or stereo. +---------------------------------------------------------------------*/ + +int SOUNDSCAPE_SetMixMode + ( + int mode + ) + + { + SOUNDSCAPE_MixMode = mode & SOUNDSCAPE_MaxMixMode; + SOUNDSCAPE_SamplePacketSize = SOUNDSCAPE_SampleSize[ SOUNDSCAPE_MixMode ]; + + // Set the mixmode + pcm_format(); + + return( mode ); + } + + +/*--------------------------------------------------------------------- + Function: SOUNDSCAPE_StopPlayback + + Ends the DMA transfer of digitized sound to the sound card. +---------------------------------------------------------------------*/ + +void SOUNDSCAPE_StopPlayback + ( + void + ) + + { + // Don't allow anymore interrupts + SOUNDSCAPE_DisableInterrupt(); + + /* stop the AD-1848 */ + ad_write( AD_CONFIG, 0x00 ); + + /* let it finish it's cycles */ + tdelay(); + + // Disable the DMA channel + DMA_EndTransfer( SOUNDSCAPE_Config.DMAChan ); + + SOUNDSCAPE_SoundPlaying = FALSE; + + SOUNDSCAPE_DMABuffer = NULL; + } + + +/*--------------------------------------------------------------------- + Function: SOUNDSCAPE_SetupDMABuffer + + Programs the DMAC for sound transfer. +---------------------------------------------------------------------*/ + +static int SOUNDSCAPE_SetupDMABuffer + ( + char *BufferPtr, + int BufferSize, + int mode + ) + + { + int DmaStatus; + + DmaStatus = DMA_SetupTransfer( SOUNDSCAPE_Config.DMAChan, BufferPtr, BufferSize, mode ); + if ( DmaStatus == DMA_Error ) + { + SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_DmaError ); + return( SOUNDSCAPE_Error ); + } + + SOUNDSCAPE_DMAChannel = SOUNDSCAPE_Config.DMAChan; + SOUNDSCAPE_DMABuffer = BufferPtr; + SOUNDSCAPE_CurrentDMABuffer = BufferPtr; + SOUNDSCAPE_TotalDMABufferSize = BufferSize; + SOUNDSCAPE_DMABufferEnd = BufferPtr + BufferSize; + + return( SOUNDSCAPE_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: SOUNDSCAPE_GetCurrentPos + + Returns the offset within the current sound being played. +---------------------------------------------------------------------*/ + +int SOUNDSCAPE_GetCurrentPos + ( + void + ) + + { + char *CurrentAddr; + int offset; + + if ( !SOUNDSCAPE_SoundPlaying ) + { + SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_NoSoundPlaying ); + return( SOUNDSCAPE_Error ); + } + + CurrentAddr = DMA_GetCurrentPos( SOUNDSCAPE_Config.DMAChan ); + + offset = ( int )( ( ( unsigned long )CurrentAddr ) - + ( ( unsigned long )SOUNDSCAPE_CurrentDMABuffer ) ); + + if ( SOUNDSCAPE_MixMode & SIXTEEN_BIT ) + { + offset >>= 1; + } + + if ( SOUNDSCAPE_MixMode & STEREO ) + { + offset >>= 1; + } + + return( offset ); + } + + +/*--------------------------------------------------------------------- + Function: SOUNDSCAPE_BeginPlayback + + Starts playback of digitized sound. +---------------------------------------------------------------------*/ + +static int SOUNDSCAPE_BeginPlayback + ( + int length + ) + + { + int SampleLength; + int LoByte; + int HiByte; + + if ( SOUNDSCAPE_MixMode & SIXTEEN_BIT ) + { + SampleLength = length / 2; + } + else + { + SampleLength = length; + } + + if ( SOUNDSCAPE_MixMode & STEREO ) + { + SampleLength >>= 1; + } + + SampleLength--; + + // setup the AD-1848 interrupt count + // set the interrupt count value based on the format. + // count will decrement every sample period and generate + // an interrupt when in rolls over. we want this always + // to be at every 1/2 buffer, regardless of the data format, + // so the count must be adjusted accordingly. + HiByte = hibyte( SampleLength ); + LoByte = lobyte( SampleLength ); + ad_write( AD_LCOUNT, LoByte ); + ad_write( AD_UCOUNT, HiByte ); + + /* unmask the host DMA controller */ + SOUNDSCAPE_EnableInterrupt(); + + /* start the AD-1848 */ + ad_write(AD_CONFIG, 0x01); + + SOUNDSCAPE_SoundPlaying = TRUE; + + return( SOUNDSCAPE_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: SOUNDSCAPE_BeginBufferedPlayback + + Begins multibuffered playback of digitized sound on the sound card. +---------------------------------------------------------------------*/ + +int SOUNDSCAPE_BeginBufferedPlayback + ( + char *BufferStart, + int BufferSize, + int NumDivisions, + unsigned SampleRate, + int MixMode, + void ( *CallBackFunc )( void ) + ) + + { + int DmaStatus; + int TransferLength; + + if ( SOUNDSCAPE_SoundPlaying ) + { + SOUNDSCAPE_StopPlayback(); + } + + SOUNDSCAPE_SetMixMode( MixMode ); + + DmaStatus = SOUNDSCAPE_SetupDMABuffer( BufferStart, BufferSize, + DMA_AutoInitRead ); + if ( DmaStatus == SOUNDSCAPE_Error ) + { + return( SOUNDSCAPE_Error ); + } + + SOUNDSCAPE_SetPlaybackRate( SampleRate ); + + SOUNDSCAPE_SetCallBack( CallBackFunc ); + + SOUNDSCAPE_EnableInterrupt(); + + TransferLength = BufferSize / NumDivisions; + SOUNDSCAPE_TransferLength = TransferLength; + + SOUNDSCAPE_BeginPlayback( TransferLength ); + + return( SOUNDSCAPE_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: SOUNDSCAPE_GetCardInfo + + Returns the maximum number of bits that can represent a sample + (8 or 16) and the number of channels (1 for mono, 2 for stereo). +---------------------------------------------------------------------*/ + +int SOUNDSCAPE_GetCardInfo + ( + int *MaxSampleBits, + int *MaxChannels + ) + + { + int status; + + status = SOUNDSCAPE_FindCard(); + if ( status == SOUNDSCAPE_Ok ) + { + *MaxChannels = 2; + *MaxSampleBits = 16; + return( SOUNDSCAPE_Ok ); + } + + return( status ); + } + + +/*--------------------------------------------------------------------- + Function: SOUNDSCAPE_SetCallBack + + Specifies the user function to call at the end of a sound transfer. +---------------------------------------------------------------------*/ + +void SOUNDSCAPE_SetCallBack + ( + void ( *func )( void ) + ) + + { + SOUNDSCAPE_CallBack = func; + } + + +/*--------------------------------------------------------------------- + Function: SOUNDSCAPE_LockEnd + + Used for determining the length of the functions to lock in memory. +---------------------------------------------------------------------*/ + +static void SOUNDSCAPE_LockEnd + ( + void + ) + + { + } + + +/*--------------------------------------------------------------------- + Function: SOUNDSCAPE_UnlockMemory + + Unlocks all neccessary data. +---------------------------------------------------------------------*/ + +static void SOUNDSCAPE_UnlockMemory + ( + void + ) + + { + DPMI_UnlockMemoryRegion( SOUNDSCAPE_LockStart, SOUNDSCAPE_LockEnd ); + DPMI_Unlock( SOUNDSCAPE_Config ); + DPMI_Unlock( SOUNDSCAPE_OldInt ); + DPMI_Unlock( SOUNDSCAPE_Installed ); + DPMI_Unlock( SOUNDSCAPE_DMABuffer ); + DPMI_Unlock( SOUNDSCAPE_DMABufferEnd ); + DPMI_Unlock( SOUNDSCAPE_CurrentDMABuffer ); + DPMI_Unlock( SOUNDSCAPE_TotalDMABufferSize ); + DPMI_Unlock( SOUNDSCAPE_TransferLength ); + DPMI_Unlock( SOUNDSCAPE_MixMode ); + DPMI_Unlock( SOUNDSCAPE_SamplePacketSize ); + DPMI_Unlock( SOUNDSCAPE_SampleRate ); + DPMI_Unlock( SOUNDSCAPE_SoundPlaying ); + DPMI_Unlock( SOUNDSCAPE_CallBack ); + DPMI_Unlock( SOUNDSCAPE_IntController1Mask ); + DPMI_Unlock( SOUNDSCAPE_IntController2Mask ); + } + + +/*--------------------------------------------------------------------- + Function: SOUNDSCAPE_LockMemory + + Locks all neccessary data. +---------------------------------------------------------------------*/ + +static int SOUNDSCAPE_LockMemory + ( + void + ) + + { + int status; + + status = DPMI_LockMemoryRegion( SOUNDSCAPE_LockStart, SOUNDSCAPE_LockEnd ); + status |= DPMI_Lock( SOUNDSCAPE_Config ); + status |= DPMI_Lock( SOUNDSCAPE_OldInt ); + status |= DPMI_Lock( SOUNDSCAPE_Installed ); + status |= DPMI_Lock( SOUNDSCAPE_DMABuffer ); + status |= DPMI_Lock( SOUNDSCAPE_DMABufferEnd ); + status |= DPMI_Lock( SOUNDSCAPE_CurrentDMABuffer ); + status |= DPMI_Lock( SOUNDSCAPE_TotalDMABufferSize ); + status |= DPMI_Lock( SOUNDSCAPE_TransferLength ); + status |= DPMI_Lock( SOUNDSCAPE_MixMode ); + status |= DPMI_Lock( SOUNDSCAPE_SamplePacketSize ); + status |= DPMI_Lock( SOUNDSCAPE_SampleRate ); + status |= DPMI_Lock( SOUNDSCAPE_SoundPlaying ); + status |= DPMI_Lock( SOUNDSCAPE_CallBack ); + status |= DPMI_Lock( SOUNDSCAPE_IntController1Mask ); + status |= DPMI_Lock( SOUNDSCAPE_IntController2Mask ); + + if ( status != DPMI_Ok ) + { + SOUNDSCAPE_UnlockMemory(); + SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_DPMI_Error ); + return( SOUNDSCAPE_Error ); + } + + return( SOUNDSCAPE_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: allocateTimerStack + + Allocate a block of memory from conventional (low) memory and return + the selector (which can go directly into a segment register) of the + memory block or 0 if an error occured. +---------------------------------------------------------------------*/ + +static unsigned short allocateTimerStack + ( + unsigned short size + ) + + { + union REGS regs; + + // clear all registers + memset( ®s, 0, sizeof( regs ) ); + + // DPMI allocate conventional memory + regs.w.ax = 0x100; + + // size in paragraphs + regs.w.bx = ( size + 15 ) / 16; + + int386( 0x31, ®s, ®s ); + if (!regs.w.cflag) + { + // DPMI call returns selector in dx + // (ax contains real mode segment + // which is ignored here) + + return( regs.w.dx ); + } + + // Couldn't allocate memory. + return( NULL ); + } + + +/*--------------------------------------------------------------------- + Function: deallocateTimerStack + + Deallocate a block of conventional (low) memory given a selector to + it. Assumes the block was allocated with DPMI function 0x100. +---------------------------------------------------------------------*/ + +static void deallocateTimerStack + ( + unsigned short selector + ) + + { + union REGS regs; + + if ( selector != NULL ) + { + // clear all registers + memset( ®s, 0, sizeof( regs ) ); + + regs.w.ax = 0x101; + regs.w.dx = selector; + int386( 0x31, ®s, ®s ); + } + } + + +/*--------------------------------------------------------------------- + Function: parse + + Parses for the right hand string of an .INI file equate. +---------------------------------------------------------------------*/ + +static int parse + ( + char *val, + char *str, + FILE *p1 + ) + + { + int i; + int j; + char tmpstr[ 81 ]; + + rewind( p1 ); + + while( !feof( p1 ) ) + { + // get a new string + fgets( tmpstr, 81, p1 ); + if( ( tmpstr[ 0 ] == '[' ) || ( tmpstr[ 0 ] == ';' ) || + ( tmpstr[ 0 ] == '\n' ) ) + { + continue; + } + + // parse up to the '=' + i = 0; + while( ( tmpstr[ i ] != '=' ) && ( tmpstr[ i ] != '\n' ) ) + { + i++; + } + + if( tmpstr[ i ] != '=' ) + { + continue; + } + + tmpstr[ i ] = '\0'; + + // see if it's the one we want + if ( strcmp( tmpstr, str ) ) + { + continue; + } + + // copy the right hand value to the destination string + i++; + for( j = 0; j < 32; j++ ) + { + if ( ( tmpstr[ i ] == ' ' ) || ( tmpstr[ i ] == '\t' ) || + ( tmpstr[ i ] == ',' ) || ( tmpstr[ i ] == '\n' ) ) + { + break; + } + + val[ j ] = tmpstr[ i ]; + i++; + } + val[j] = '\0'; + + return( TRUE ); + } + + return( FALSE ); + } + + +/*--------------------------------------------------------------------- + Function: SOUNDSCAPE_FindCard + + Determines if a SoundScape is present and where it is located. +---------------------------------------------------------------------*/ + +static int SOUNDSCAPE_FindCard + ( + void + ) + + { + int found; + int status; + int tmp; + char *cp; + char str[ 33 ]; + FILE *fp; + + if ( SOUNDSCAPE_FoundCard ) + { + return( SOUNDSCAPE_Ok ); + } + + cp = getenv( "SNDSCAPE" ); + if ( cp == NULL ) + { + strcpy( str, "C:\\SNDSCAPE" ); + } + else + { + strcpy( str, cp ); + } + + strcat(str, "\\SNDSCAPE.INI"); + + fp = fopen( str, "r" ); + if ( fp == NULL ) + { + if ( cp == NULL ) + { + SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_EnvNotFound ); + return( SOUNDSCAPE_Error ); + } + + SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_InitFileNotFound ); + return( SOUNDSCAPE_Error ); + } + + found = parse( str, "Product", fp ); + if ( !found ) + { + fclose( fp ); + SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_MissingProductInfo ); + return( SOUNDSCAPE_Error ); + } + + if( strstr( str, "SoundFX" ) == NULL ) + { + SOUNDSCAPE_Config.OldIRQs = FALSE; + } + else + { + SOUNDSCAPE_Config.OldIRQs = TRUE; + } + + found = parse( str, "Port", fp ); + if ( !found ) + { + fclose( fp ); + SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_MissingPortInfo ); + return( SOUNDSCAPE_Error ); + } + + SOUNDSCAPE_Config.BasePort = strtol( str, ( char ** )0, 16); + + found = parse( str, "DMA", fp ); + if ( !found ) + { + fclose( fp ); + SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_MissingDMAInfo ); + return( SOUNDSCAPE_Error ); + } + + SOUNDSCAPE_Config.DMAChan = ( int )strtol( str, ( char ** )0, 10 ); + status = DMA_VerifyChannel( SOUNDSCAPE_Config.DMAChan ); + if ( status == DMA_Error ) + { + fclose( fp ); + SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_DmaError ); + return( SOUNDSCAPE_Error ); + } + + found = parse( str, "IRQ", fp ); + if ( !found ) + { + fclose( fp ); + SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_MissingIRQInfo ); + return( SOUNDSCAPE_Error ); + } + + SOUNDSCAPE_Config.MIDIIRQ = ( int )strtol( str, ( char ** )0, 10 ); + if ( SOUNDSCAPE_Config.MIDIIRQ == 2 ) + { + SOUNDSCAPE_Config.MIDIIRQ = 9; + } + + found = parse( str, "SBIRQ", fp ); + if ( !found ) + { + fclose( fp ); + SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_MissingSBIRQInfo ); + return( SOUNDSCAPE_Error ); + } + + SOUNDSCAPE_Config.WaveIRQ = ( int )strtol( str, ( char ** )0, 10 ); + if ( SOUNDSCAPE_Config.WaveIRQ == 2 ) + { + SOUNDSCAPE_Config.WaveIRQ = 9; + } + + if ( !VALID_IRQ( SOUNDSCAPE_Config.WaveIRQ ) ) + { + fclose( fp ); + SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_InvalidSBIrq ); + return( SOUNDSCAPE_Error ); + } + + if ( SOUNDSCAPE_Interrupts[ SOUNDSCAPE_Config.WaveIRQ ] == INVALID ) + { + fclose( fp ); + SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_InvalidSBIrq ); + return( SOUNDSCAPE_Error ); + } + + found = parse( str, "SBEnable", fp ); + if ( !found ) + { + fclose( fp ); + SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_MissingSBENABLEInfo ); + return( SOUNDSCAPE_Error ); + } + + if( !strcmp( str, "false" ) ) + { + SOUNDSCAPE_Config.SBEmul = FALSE; + } + else + { + SOUNDSCAPE_Config.SBEmul = TRUE; + } + + // do a hardware test + outp( SOUNDSCAPE_Config.BasePort + GA_REGADDR, 0x00f5 ); + tmp = inp( SOUNDSCAPE_Config.BasePort + GA_REGADDR ); + if ( ( tmp & 0x000f ) != 0x0005 ) + { + fclose( fp ); + SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_HardwareError ); + return( SOUNDSCAPE_Error ); + } + + if( ( tmp & 0x00f0 ) == 0x00f0 ) + { + fclose( fp ); + SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_HardwareError ); + return( SOUNDSCAPE_Error ); + } + + // formulate the chip ID + tmp >>= 4; + if( tmp == 0 ) + { + SOUNDSCAPE_Config.ChipID = ODIE; + } + else if ( !( tmp & 0x0008 ) ) + { + SOUNDSCAPE_Config.ChipID = OPUS; + } + else + { + SOUNDSCAPE_Config.ChipID = MMIC; + } + + // parse for the AD-1848 address if necessary + if( SOUNDSCAPE_Config.ChipID == ODIE ) + { + found = parse( str, "WavePort", fp ); + if ( !found ) + { + fclose( fp ); + SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_MissingWavePortInfo ); + return( SOUNDSCAPE_Error ); + } + + SOUNDSCAPE_Config.WavePort = strtol( str, ( char ** )0, 16 ); + } + else + { + // otherwise, the base address is fixed + SOUNDSCAPE_Config.WavePort = SOUNDSCAPE_Config.BasePort + AD_OFFSET; + } + + // we're done with the file + fclose( fp ); + + // if it's an ODIE board, note CD-ROM decode enable + if ( SOUNDSCAPE_Config.ChipID == ODIE ) + { + SOUNDSCAPE_Config.CDROM = ga_read( GA_CDCFG ) & 0x80; + } + + // build the Wave IRQ index value + if( !SOUNDSCAPE_Config.OldIRQs ) + { + switch( SOUNDSCAPE_Config.WaveIRQ ) + { + case 9 : + SOUNDSCAPE_Config.IRQIndx = 0; + break; + + case 5 : + SOUNDSCAPE_Config.IRQIndx = 1; + break; + + case 7 : + SOUNDSCAPE_Config.IRQIndx = 2; + break; + + default : + SOUNDSCAPE_Config.IRQIndx = 3; + break; + } + } + else + { + switch( SOUNDSCAPE_Config.WaveIRQ ) + { + case 9 : + SOUNDSCAPE_Config.IRQIndx = 0; + break; + + case 5 : + SOUNDSCAPE_Config.IRQIndx = 2; + break; + + case 7 : + SOUNDSCAPE_Config.IRQIndx = 1; + break; + + default : + SOUNDSCAPE_Config.IRQIndx = 3; + break; + } + } + + SOUNDSCAPE_FoundCard = TRUE; + SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_Ok ); + return( SOUNDSCAPE_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: SOUNDSCAPE_Setup + + Setup the Soundscape card for native mode PCM. +---------------------------------------------------------------------*/ + +static int SOUNDSCAPE_Setup + ( + void + ) + + { + int tmp; + int Interrupt; + int status; + + // if necessary, clear any pending SB ints + if ( SOUNDSCAPE_Config.SBEmul ) + { + inp( SB_IACK ); + } + + SOUNDSCAPE_DisableInterrupt(); + + // make sure the AD-1848 is not running + if ( ad_read( AD_CONFIG ) & 0x01 ) + { + SOUNDSCAPE_StopPlayback(); + } + + // if necessary, do some signal re-routing + if( SOUNDSCAPE_Config.ChipID != MMIC ) + { + // get the gate-array off of the DMA channel + ga_write( GA_DMACHB, 0x20 ); + + if ( !SOUNDSCAPE_Config.OldIRQs ) + { + switch( SOUNDSCAPE_Config.MIDIIRQ ) + { + case 5 : + tmp = 1; + break; + + case 7 : + tmp = 2; + break; + + case 9 : + tmp = 0; + break; + + default : + tmp = 3; + break; + } + } + else + { + switch( SOUNDSCAPE_Config.MIDIIRQ ) + { + case 5 : + tmp = 2; + break; + + case 7 : + tmp = 1; + break; + + case 9 : + tmp = 0; + break; + + default : + tmp = 3; + break; + } + } + + // set HostIRQ to MIDIIRQ for now + ga_write( GA_INTCFG, 0xf0 | ( tmp << 2 ) | tmp ); + + // now, route the AD-1848 stuff ... + if ( SOUNDSCAPE_Config.ChipID == OPUS ) + { + // set the AD-1848 chip decode + ga_write( GA_HMCTL, ( ga_read( GA_HMCTL ) & 0xcf ) | 0x10 ); + } + // setup the DMA polarity + ga_write( GA_DMACFG, 0x50 ); + + // init the CD-ROM (AD-1848) config register + ga_write( GA_CDCFG, 0x89 | ( SOUNDSCAPE_Config.DMAChan << 4 ) | ( SOUNDSCAPE_Config.IRQIndx << 1 ) ); + + // enable mode change, point to config reg + outp( SOUNDSCAPE_Config.WavePort + AD_REGADDR, 0x40 | AD_CONFIG ); + + // set interf cnfg reg for DMA mode, single chan, autocal on + outp( SOUNDSCAPE_Config.WavePort + AD_REGDATA, 0x0c ); + + // exit mode change state + outp( SOUNDSCAPE_Config.WavePort + AD_REGADDR, 0x00 ); + + // delay for autocalibration + tdelay(); + } + + // Install our interrupt handler + Interrupt = SOUNDSCAPE_Interrupts[ SOUNDSCAPE_Config.WaveIRQ ]; + SOUNDSCAPE_OldInt = _dos_getvect( Interrupt ); + if ( SOUNDSCAPE_Config.WaveIRQ < 8 ) + { + _dos_setvect( Interrupt, SOUNDSCAPE_ServiceInterrupt ); + } + else + { + status = IRQ_SetVector( Interrupt, SOUNDSCAPE_ServiceInterrupt ); + if ( status != IRQ_Ok ) + { + SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_UnableToSetIrq ); + return( SOUNDSCAPE_Error ); + } + } + + // max left and right volumes + ad_write( AD_LEFTOUT, 0 ); + ad_write( AD_RIGHTOUT, 0 ); + + // clear any pending interrupt condition + outp( SOUNDSCAPE_Config.WavePort + AD_STATUS, 0x00 ); + + // enable the interrupt pin + ad_write( AD_PINCTRL, ad_read( AD_PINCTRL ) | 0x02 ); + + SOUNDSCAPE_EnableInterrupt(); + + SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_Ok ); + return( SOUNDSCAPE_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: SOUNDSCAPE_GetMIDIPort + + Gets the address of the SoundScape MIDI port. +---------------------------------------------------------------------*/ + +int SOUNDSCAPE_GetMIDIPort + ( + void + ) + + { + int status; + + status = SOUNDSCAPE_FindCard(); + if ( status != SOUNDSCAPE_Ok ) + { + return( status ); + } + + return( SOUNDSCAPE_Config.BasePort ); + } + + +/*--------------------------------------------------------------------- + Function: SOUNDSCAPE_Init + + Initializes the sound card and prepares the module to play + digitized sounds. +---------------------------------------------------------------------*/ + +int SOUNDSCAPE_Init + ( + void + ) + + { + int status; + + if ( SOUNDSCAPE_Installed ) + { + SOUNDSCAPE_Shutdown(); + } + + // Save the interrupt masks + SOUNDSCAPE_IntController1Mask = inp( 0x21 ); + SOUNDSCAPE_IntController2Mask = inp( 0xA1 ); + + SOUNDSCAPE_SoundPlaying = FALSE; + SOUNDSCAPE_SetCallBack( NULL ); + SOUNDSCAPE_DMABuffer = NULL; + + status = SOUNDSCAPE_FindCard(); + if ( status != SOUNDSCAPE_Ok ) + { + return( status ); + } + + status = SOUNDSCAPE_LockMemory(); + if ( status != SOUNDSCAPE_Ok ) + { + SOUNDSCAPE_UnlockMemory(); + return( status ); + } + + StackSelector = allocateTimerStack( kStackSize ); + if ( StackSelector == NULL ) + { + SOUNDSCAPE_UnlockMemory(); + SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_OutOfMemory ); + return( SOUNDSCAPE_Error ); + } + + // Leave a little room at top of stack just for the hell of it... + StackPointer = kStackSize - sizeof( long ); + + SOUNDSCAPE_Installed = TRUE; + + status = SOUNDSCAPE_Setup(); + if ( status != SOUNDSCAPE_Ok ) + { + SOUNDSCAPE_Shutdown(); + return( status ); + } + +// printf("Testing DMA and IRQ ...\n"); +// if( test_dma_irq() ) +// { +// printf("\t\007Hardware Not Responding\n\n"); +// close_soundscape(); +// return( SOUNDSCAPE_Error ); +// } + + SOUNDSCAPE_SetPlaybackRate( SOUNDSCAPE_DefaultSampleRate ); + SOUNDSCAPE_SetMixMode( SOUNDSCAPE_DefaultMixMode ); + + SOUNDSCAPE_SetErrorCode( SOUNDSCAPE_Ok ); + return( SOUNDSCAPE_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: SOUNDSCAPE_Shutdown + + Ends transfer of sound data to the sound card and restores the + system resources used by the card. +---------------------------------------------------------------------*/ + +void SOUNDSCAPE_Shutdown + ( + void + ) + + { + int Interrupt; + + // Halt the DMA transfer + SOUNDSCAPE_StopPlayback(); + + // disable the AD-1848 interrupt pin + ad_write( AD_PINCTRL, ad_read( AD_PINCTRL ) & 0xfd ); + + // if necessary, do some signal re-routing + if ( SOUNDSCAPE_Config.ChipID != MMIC ) + { + // re-init the CD-ROM (AD-1848) config register as needed. + // this will disable the AD-1848 interface. + if ( SOUNDSCAPE_Config.ChipID == ODIE ) + { + ga_write( GA_CDCFG, SOUNDSCAPE_Config.CDROM ); + } + else + { + ga_write( GA_CDCFG, ga_read( GA_CDCFG ) & 0x7f); + } + + // if necessary, reset the SoundBlaster IRQ + if ( SOUNDSCAPE_Config.SBEmul ) + { + ga_write( GA_INTCFG, ( ga_read( GA_INTCFG ) & 0xf3 ) | + ( SOUNDSCAPE_Config.IRQIndx << 2 ) ); + } + + // re-assign the gate-array DMA channel + ga_write( GA_DMACHB, 0x80 | ( SOUNDSCAPE_Config.DMAChan << 4 ) ); + } + + // Restore the original interrupt + Interrupt = SOUNDSCAPE_Interrupts[ SOUNDSCAPE_Config.WaveIRQ ]; + if ( SOUNDSCAPE_Config.WaveIRQ >= 8 ) + { + IRQ_RestoreVector( Interrupt ); + } + _dos_setvect( Interrupt, SOUNDSCAPE_OldInt ); + + SOUNDSCAPE_SoundPlaying = FALSE; + + SOUNDSCAPE_DMABuffer = NULL; + + SOUNDSCAPE_SetCallBack( NULL ); + + SOUNDSCAPE_UnlockMemory(); + + if ( StackSelector != NULL ) + { + deallocateTimerStack( StackSelector ); + StackSelector = NULL; + } + + SOUNDSCAPE_Installed = FALSE; + } diff --git a/audiolib/sndscape.h b/audiolib/sndscape.h new file mode 100755 index 0000000..18cd705 --- /dev/null +++ b/audiolib/sndscape.h @@ -0,0 +1,73 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: SNDSCAPE.H + + author: James R. Dose + date: October 26, 1994 + + Public header for SNDSCAPE.C + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#ifndef __SNDSCAPE_H +#define __SNDSCAPE_H + +extern int SOUNDSCAPE_DMAChannel; +extern int SOUNDSCAPE_ErrorCode; + +enum SOUNDSCAPE_ERRORS + { + SOUNDSCAPE_Warning = -2, + SOUNDSCAPE_Error = -1, + SOUNDSCAPE_Ok = 0, + SOUNDSCAPE_EnvNotFound, + SOUNDSCAPE_InitFileNotFound, + SOUNDSCAPE_MissingProductInfo, + SOUNDSCAPE_MissingPortInfo, + SOUNDSCAPE_MissingDMAInfo, + SOUNDSCAPE_MissingIRQInfo, + SOUNDSCAPE_MissingSBIRQInfo, + SOUNDSCAPE_MissingSBENABLEInfo, + SOUNDSCAPE_MissingWavePortInfo, + SOUNDSCAPE_HardwareError, + SOUNDSCAPE_NoSoundPlaying, + SOUNDSCAPE_InvalidSBIrq, + SOUNDSCAPE_UnableToSetIrq, + SOUNDSCAPE_DmaError, + SOUNDSCAPE_DPMI_Error, + SOUNDSCAPE_OutOfMemory + }; + +char *SOUNDSCAPE_ErrorString( int ErrorNumber ); +void SOUNDSCAPE_SetPlaybackRate( unsigned rate ); +unsigned SOUNDSCAPE_GetPlaybackRate( void ); +int SOUNDSCAPE_SetMixMode( int mode ); +void SOUNDSCAPE_StopPlayback( void ); +int SOUNDSCAPE_GetCurrentPos( void ); +int SOUNDSCAPE_BeginBufferedPlayback( char *BufferStart, int BufferSize, int NumDivisions, unsigned SampleRate, int MixMode, void ( *CallBackFunc )( void ) ); +int SOUNDSCAPE_GetCardInfo( int *MaxSampleBits, int *MaxChannels ); +void SOUNDSCAPE_SetCallBack( void ( *func )( void ) ); +int SOUNDSCAPE_GetMIDIPort( void ); +int SOUNDSCAPE_Init( void ); +void SOUNDSCAPE_Shutdown( void ); + +#endif diff --git a/audiolib/sndsrc.c b/audiolib/sndsrc.c new file mode 100755 index 0000000..771fa6d --- /dev/null +++ b/audiolib/sndsrc.c @@ -0,0 +1,658 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: SNDSRC.C + + author: James R. Dose + date: March 26, 1994 + + Low level routines to support the Disney Sound Source. + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#define STEREO 1 +#define SIXTEEN_BIT 2 + +#define MONO_8BIT 0 +#define STEREO_8BIT ( STEREO ) +#define MONO_16BIT ( SIXTEEN_BIT ) +#define STEREO_16BIT ( STEREO | SIXTEEN_BIT ) + +#include +#include +#include +#include "dpmi.h" +#include "task_man.h" +#include "sndcards.h" +#include "user.h" +#include "sndsrc.h" + +#define TRUE ( 1 == 1 ) +#define FALSE ( !TRUE ) + +static int SS_Installed = FALSE; + +static int SS_Port = SS_DefaultPort; +static int SS_OffCommand = 0xc; + +static char *SS_BufferStart; +static char *SS_BufferEnd; +static char *SS_CurrentBuffer; +static int SS_BufferNum = 0; +static int SS_NumBuffers = 0; +static int SS_TotalBufferSize = 0; +static int SS_TransferLength = 0; +static int SS_CurrentLength = 0; + +static char *SS_SoundPtr; +volatile int SS_SoundPlaying; + +static task *SS_Timer; + +void ( *SS_CallBack )( void ); + +int SS_ErrorCode = SS_Ok; + +#define SS_SetErrorCode( status ) \ + SS_ErrorCode = ( status ); + +/*--------------------------------------------------------------------- + Function: SS_ErrorString + + Returns a pointer to the error message associated with an error + number. A -1 returns a pointer the current error. +---------------------------------------------------------------------*/ + +char *SS_ErrorString + ( + int ErrorNumber + ) + + { + char *ErrorString; + + switch( ErrorNumber ) + { + case SS_Error : + ErrorString = SS_ErrorString( SS_ErrorCode ); + break; + + case SS_Ok : + ErrorString = "Sound Source ok."; + break; + + case SS_NotFound : + ErrorString = "Could not detect Sound Source."; + break; + + case SS_NoSoundPlaying : + ErrorString = "No sound playing in SndSrc."; + break; + + case SS_DPMI_Error : + ErrorString = "DPMI Error in SndSrc."; + break; + + default : + ErrorString = "Unknown Sound Source error code."; + break; + } + + return( ErrorString ); + } + + +/********************************************************************** + + Memory locked functions: + +**********************************************************************/ + + +#define SS_LockStart SS_ServiceInterrupt + + +/*--------------------------------------------------------------------- + Function: SS_ServiceInterrupt + + Handles interrupt generated by sound card at the end of a voice + transfer. Calls the user supplied callback function. +---------------------------------------------------------------------*/ + +static void SS_ServiceInterrupt + ( + task *Task + ) + + { + int port = SS_Port; + int count; + + count = 0; + while( ( inp( port + 1 ) & 0x40 ) == 0 ) + { + outp( port, *SS_SoundPtr++ ); + outp( port + 2, SS_OffCommand ); + outp( port + 2, 4 ); + + SS_CurrentLength--; + if ( SS_CurrentLength == 0 ) + { + // Keep track of current buffer + SS_CurrentBuffer += SS_TransferLength; + SS_BufferNum++; + if ( SS_BufferNum >= SS_NumBuffers ) + { + SS_BufferNum = 0; + SS_CurrentBuffer = SS_BufferStart; + } + + SS_CurrentLength = SS_TransferLength; + SS_SoundPtr = SS_CurrentBuffer; + + // Call the caller's callback function + if ( SS_CallBack != NULL ) + { + SS_CallBack(); + } + } + + count++; + // Only do at most 14 samples per tick + if ( count > 13 ) + { + break; + } + } + } + + +/*--------------------------------------------------------------------- + Function: SS_StopPlayback + + Ends the transfer of digitized sound to the Sound Source. +---------------------------------------------------------------------*/ + +void SS_StopPlayback + ( + void + ) + + { + if ( SS_SoundPlaying ) + { + TS_Terminate( SS_Timer ); + + outp( SS_Port, 0x80 ); + outp( SS_Port + 2, SS_OffCommand ); + outp( SS_Port + 2, 4 ); + + SS_SoundPlaying = FALSE; + + SS_BufferStart = NULL; + } + } + + +/*--------------------------------------------------------------------- + Function: SS_GetCurrentPos + + Returns the offset within the current sound being played. +---------------------------------------------------------------------*/ + +int SS_GetCurrentPos + ( + void + ) + + { + int offset; + + if ( !SS_SoundPlaying ) + { + SS_SetErrorCode( SS_NoSoundPlaying ); + return( SS_Warning ); + } + + offset = ( int )( ( ( unsigned long )SS_SoundPtr ) - + ( ( unsigned long )SS_CurrentBuffer ) ); + + return( offset ); + } + + +/*--------------------------------------------------------------------- + Function: SS_LockEnd + + Used for determining the length of the functions to lock in memory. +---------------------------------------------------------------------*/ + +static void SS_LockEnd + ( + void + ) + + { + } + + +/*--------------------------------------------------------------------- + Function: SS_BeginBufferedPlayback + + Begins multibuffered playback of digitized sound on the Sound Source. +---------------------------------------------------------------------*/ + +int SS_BeginBufferedPlayback + ( + char *BufferStart, + int BufferSize, + int NumDivisions, + void ( *CallBackFunc )( void ) + ) + + { + if ( SS_SoundPlaying ) + { + SS_StopPlayback(); + } + + SS_SetCallBack( CallBackFunc ); + + SS_BufferStart = BufferStart; + SS_CurrentBuffer = BufferStart; + SS_SoundPtr = BufferStart; + SS_TotalBufferSize = BufferSize; + SS_BufferEnd = BufferStart + BufferSize; + SS_TransferLength = BufferSize / NumDivisions; + SS_CurrentLength = SS_TransferLength; + SS_BufferNum = 0; + SS_NumBuffers = NumDivisions; + + SS_SoundPlaying = TRUE; + +// SS_Timer = TS_ScheduleTask( SS_ServiceInterrupt, 438, 1, NULL ); + SS_Timer = TS_ScheduleTask( SS_ServiceInterrupt, 510, 1, NULL ); + TS_Dispatch(); + + return( SS_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: SS_GetPlaybackRate + + Returns the rate at which the digitized sound will be played in + hertz. +---------------------------------------------------------------------*/ + +int SS_GetPlaybackRate + ( + void + ) + + { + return( SS_SampleRate ); + } + + +/*--------------------------------------------------------------------- + Function: SS_SetMixMode + + Sets the sound card to play samples in mono or stereo. +---------------------------------------------------------------------*/ + +int SS_SetMixMode + ( + int mode + ) + + { + mode = MONO_8BIT; + return( mode ); + } + + +/*--------------------------------------------------------------------- + Function: SS_SetPort + + Selects which port to use to write to the Sound Source. +---------------------------------------------------------------------*/ + +int SS_SetPort + ( + int port + ) + + { + if ( SS_Installed ) + { + SS_Shutdown(); + } + + SS_Port = port; + + return( SS_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: SS_SetCallBack + + Specifies the user function to call at the end of a sound transfer. +---------------------------------------------------------------------*/ + +void SS_SetCallBack + ( + void ( *func )( void ) + ) + + { + SS_CallBack = func; + } + + +/*--------------------------------------------------------------------- + Function: SS_TestTimer + + Used as a delay in SS_TestSoundSource. +---------------------------------------------------------------------*/ + +void SS_TestTimer + ( + task *Task + ) + + { + ( *( int * )( Task->data ) )++; + } + + +/*--------------------------------------------------------------------- + Function: SS_TestSoundSource + + Detect if the Sound Source is located at the specified port. +---------------------------------------------------------------------*/ + +int SS_TestSoundSource + ( + int port + ) + + { + int present; + task *timer; + volatile int ticks; + int i; + + present = FALSE; + + timer = TS_ScheduleTask( SS_TestTimer, 140, 1, &ticks ); + TS_Dispatch(); + + outp( port + 2, 4 ); + + ticks = 0; + + while( ticks < 4 ) + { + // Do nothing for a while + } + + TS_Terminate( timer ); + + if ( ( inp( port + 1 ) & 0x40 ) == 0 ) + { + for( i = 32; i > 0; i-- ) + { + outp( port, 0x80 ); + outp( port + 2, SS_OffCommand ); + outp( port + 2, 4 ); + } + + if ( inp( port + 1 ) & 0x40 ) + { + present = TRUE; + } + } + + outp( port + 2, SS_OffCommand ); + + return( present ); + } + + +/*--------------------------------------------------------------------- + Function: SS_DetectSoundSource + + Detects which port the Sound Source is located. +---------------------------------------------------------------------*/ + +int SS_DetectSoundSource + ( + void + ) + + { + if ( USER_CheckParameter( SELECT_SOUNDSOURCE_PORT1 ) ) + { + SS_Port = SS_Port1; + return( TRUE ); + } + + if ( USER_CheckParameter( SELECT_SOUNDSOURCE_PORT2 ) ) + { + SS_Port = SS_Port2; + return( TRUE ); + } + + if ( USER_CheckParameter( SELECT_SOUNDSOURCE_PORT3 ) ) + { + SS_Port = SS_Port3; + return( TRUE ); + } + + if ( SS_TestSoundSource( SS_Port1 ) ) + { + SS_Port = SS_Port1; + return( TRUE ); + } + + if ( SS_TestSoundSource( SS_Port2 ) ) + { + SS_Port = SS_Port2; + return( TRUE ); + } + + if ( SS_TestSoundSource( SS_Port3 ) ) + { + SS_Port = SS_Port3; + return( TRUE ); + } + + return( FALSE ); + } + + +/*--------------------------------------------------------------------- + Function: SS_Init + + Initializes the Sound Source prepares the module to play digitized + sounds. +---------------------------------------------------------------------*/ + +int SS_Init + ( + int soundcard + ) + + { + int status; + + if ( SS_Installed ) + { + SS_Shutdown(); + } + + if ( ( soundcard == TandySoundSource ) || + ( USER_CheckParameter( SELECT_TANDY_SOUNDSOURCE ) ) ) + { + // Tandy + SS_OffCommand = 0x0e; + } + else + { + // Disney + SS_OffCommand = 0x0c; + } + + status = SS_DetectSoundSource(); + if ( !status ) + { + SS_SetErrorCode( SS_NotFound ); + return( SS_Warning ); + } + + status = SS_LockMemory(); + if ( status != SS_Ok ) + { + SS_UnlockMemory(); + return( status ); + } + + status = SS_Ok; + + outp( SS_Port + 2, 4 ); + + SS_SoundPlaying = FALSE; + + SS_SetCallBack( NULL ); + + SS_BufferStart = NULL; + + SS_Installed = TRUE; + + SS_SetErrorCode( status ); + return( status ); + } + + +/*--------------------------------------------------------------------- + Function: SS_Shutdown + + Ends transfer of sound data to the Sound Source. +---------------------------------------------------------------------*/ + +void SS_Shutdown + ( + void + ) + + { + // Halt the transfer + SS_StopPlayback(); + + outp( SS_Port + 2, SS_OffCommand ); + + SS_SoundPlaying = FALSE; + + SS_BufferStart = NULL; + + SS_SetCallBack( NULL ); + + SS_UnlockMemory(); + + SS_Installed = FALSE; + } + + +/*--------------------------------------------------------------------- + Function: SS_UnlockMemory + + Unlocks all neccessary data. +---------------------------------------------------------------------*/ + +void SS_UnlockMemory + ( + void + ) + + { + DPMI_UnlockMemoryRegion( SS_LockStart, SS_LockEnd ); + DPMI_Unlock( SS_Installed ); + DPMI_Unlock( SS_Port ); + DPMI_Unlock( SS_OffCommand ); + DPMI_Unlock( SS_BufferStart ); + DPMI_Unlock( SS_BufferEnd ); + DPMI_Unlock( SS_CurrentBuffer ); + DPMI_Unlock( SS_BufferNum ); + DPMI_Unlock( SS_NumBuffers ); + DPMI_Unlock( SS_TotalBufferSize ); + DPMI_Unlock( SS_TransferLength ); + DPMI_Unlock( SS_CurrentLength ); + DPMI_Unlock( SS_SoundPtr ); + DPMI_Unlock( SS_SoundPlaying ); + DPMI_Unlock( SS_Timer ); + DPMI_Unlock( SS_CallBack ); + DPMI_Unlock( SS_ErrorCode ); + } + + +/*--------------------------------------------------------------------- + Function: SS_LockMemory + + Locks all neccessary data. +---------------------------------------------------------------------*/ + +int SS_LockMemory + ( + void + ) + + { + int status; + + status = DPMI_LockMemoryRegion( SS_LockStart, SS_LockEnd ); + status |= DPMI_Lock( SS_Installed ); + status |= DPMI_Lock( SS_Port ); + status |= DPMI_Lock( SS_OffCommand ); + status |= DPMI_Lock( SS_BufferStart ); + status |= DPMI_Lock( SS_BufferEnd ); + status |= DPMI_Lock( SS_CurrentBuffer ); + status |= DPMI_Lock( SS_BufferNum ); + status |= DPMI_Lock( SS_NumBuffers ); + status |= DPMI_Lock( SS_TotalBufferSize ); + status |= DPMI_Lock( SS_TransferLength ); + status |= DPMI_Lock( SS_CurrentLength ); + status |= DPMI_Lock( SS_SoundPtr ); + status |= DPMI_Lock( SS_SoundPlaying ); + status |= DPMI_Lock( SS_Timer ); + status |= DPMI_Lock( SS_CallBack ); + status |= DPMI_Lock( SS_ErrorCode ); + + if ( status != DPMI_Ok ) + { + SS_UnlockMemory(); + SS_SetErrorCode( SS_DPMI_Error ); + return( SS_Error ); + } + + return( SS_Ok ); + } diff --git a/audiolib/sndsrc.h b/audiolib/sndsrc.h new file mode 100755 index 0000000..fbb82c5 --- /dev/null +++ b/audiolib/sndsrc.h @@ -0,0 +1,70 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: SNDSRC.H + + author: James R. Dose + date: March 26, 1994 + + Public header for for SNDSRC.C + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#ifndef __SNDSRC_H +#define __SNDSRC_H + +enum SS_ERRORS + { + SS_Warning = -2, + SS_Error = -1, + SS_Ok = 0, + SS_NotFound, + SS_NoSoundPlaying, + SS_DPMI_Error + }; + +#define SELECT_SOUNDSOURCE_PORT1 "ss1" +#define SELECT_SOUNDSOURCE_PORT2 "ss2" +#define SELECT_SOUNDSOURCE_PORT3 "ss3" +#define SELECT_TANDY_SOUNDSOURCE "sst" + +#define SS_Port1 0x3bc +#define SS_Port2 0x378 +#define SS_Port3 0x278 + +#define SS_DefaultPort 0x378 +#define SS_SampleRate 7000 +#define SS_DMAChannel -1 + +char *SS_ErrorString( int ErrorNumber ); +void SS_StopPlayback( void ); +int SS_GetCurrentPos( void ); +int SS_BeginBufferedPlayback( char *BufferStart, int BufferSize, int NumDivisions, void ( *CallBackFunc )( void ) ); +int SS_GetPlaybackRate( void ); +int SS_SetMixMode( int mode ); +int SS_SetPort( int port ); +void SS_SetCallBack( void ( *func )( void ) ); +int SS_Init( int soundcard ); +void SS_Shutdown( void ); +void SS_UnlockMemory( void ); +int SS_LockMemory( void ); + +#endif diff --git a/audiolib/standard.h b/audiolib/standard.h new file mode 100755 index 0000000..e9344e3 --- /dev/null +++ b/audiolib/standard.h @@ -0,0 +1,72 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: STANDARD.H + + author: James R. Dose + date: May 25, 1994 + + Header containing standard definitions. + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#ifndef __STANDARD_H +#define __STANDARD_H + +typedef int boolean; +typedef int errorcode; + +#ifndef TRUE + #define TRUE ( 1 == 1 ) + #define FALSE ( !TRUE ) +#endif + +enum STANDARD_ERRORS + { + Warning = -2, + FatalError = -1, + Success = 0 + }; + +#define BITSET( data, bit ) \ + ( ( ( data ) & ( bit ) ) == ( bit ) ) + +#define ARRAY_LENGTH( array ) \ + ( sizeof( array ) / sizeof( ( array )[ 0 ] ) ) + +#define WITHIN_BOUNDS( array, index ) \ + ( ( 0 <= ( index ) ) && ( ( index ) < ARRAY_LENGTH( array ) ) ) + +#define FOREVER for( ; ; ) + +#ifdef NDEBUG + #define DEBUGGING 0 +#else + #define DEBUGGING 1 +#endif + +#define DEBUG_CODE \ + if ( DEBUGGING == 0 ) \ + { \ + } \ + else + +#endif diff --git a/audiolib/task_man.c b/audiolib/task_man.c new file mode 100755 index 0000000..c39135f --- /dev/null +++ b/audiolib/task_man.c @@ -0,0 +1,976 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: TASK_MAN.C + + author: James R. Dose + date: July 25, 1994 + + Low level timer task scheduler. + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#define TRUE ( 1 == 1 ) +#define FALSE ( !TRUE ) + +//#define USESTACK +#define LOCKMEMORY +#define NOINTS +#define USE_USRHOOKS + +#include +#include +#include +#include +#include "interrup.h" +#include "linklist.h" +#include "task_man.h" + +#ifdef USESTACK +#include "dpmi.h" +#endif +#ifdef LOCKMEMORY +#include "dpmi.h" +#endif + +#ifdef USE_USRHOOKS +#include "usrhooks.h" +#define FreeMem( ptr ) USRHOOKS_FreeMem( ( ptr ) ) +#else +#define FreeMem( ptr ) free( ( ptr ) ) +#endif + +typedef struct + { + task *start; + task *end; + } tasklist; + + +/*--------------------------------------------------------------------- + Global variables +---------------------------------------------------------------------*/ + +#ifdef USESTACK + +// adequate stack size +#define kStackSize 2048 + +static unsigned short StackSelector = NULL; +static unsigned long StackPointer; + +static unsigned short oldStackSelector; +static unsigned long oldStackPointer; + +#endif + +static task HeadTask; +static task *TaskList = &HeadTask; + +static void ( __interrupt __far *OldInt8 )( void ); + +static volatile long TaskServiceRate = 0x10000L; +static volatile long TaskServiceCount = 0; + +#ifndef NOINTS +static volatile int TS_TimesInInterrupt; +#endif + +static char TS_Installed = FALSE; + +volatile int TS_InInterrupt = FALSE; + +/*--------------------------------------------------------------------- + Function prototypes +---------------------------------------------------------------------*/ + +static void TS_FreeTaskList( void ); +static void TS_SetClockSpeed( long speed ); +static long TS_SetTimer( long TickBase ); +static void TS_SetTimerToMaxTaskRate( void ); +static void __interrupt __far TS_ServiceSchedule( void ); +static void __interrupt __far TS_ServiceScheduleIntEnabled( void ); +static void TS_AddTask( task *ptr ); +static int TS_Startup( void ); +static void RestoreRealTimeClock( void ); + +// These declarations are necessary to use the inline assembly pragmas. + +extern void GetStack(unsigned short *selptr,unsigned long *stackptr); +extern void SetStack(unsigned short selector,unsigned long stackptr); + +// This function will get the current stack selector and pointer and save +// them off. +#pragma aux GetStack = \ + "mov [edi],esp" \ + "mov ax,ss" \ + "mov [esi],ax" \ + parm [esi] [edi] \ + modify [eax esi edi]; + +// This function will set the stack selector and pointer to the specified +// values. +#pragma aux SetStack = \ + "mov ss,ax" \ + "mov esp,edx" \ + parm [ax] [edx] \ + modify [eax edx]; + + +/********************************************************************** + + Memory locked functions: + +**********************************************************************/ + + +#define TS_LockStart TS_FreeTaskList + + +/*--------------------------------------------------------------------- + Function: TS_FreeTaskList + + Terminates all tasks and releases any memory used for control + structures. +---------------------------------------------------------------------*/ + +static void TS_FreeTaskList + ( + void + ) + + { + task *node; + task *next; + unsigned flags; + + flags = DisableInterrupts(); + + node = TaskList->next; + while( node != TaskList ) + { + next = node->next; + FreeMem( node ); + node = next; + } + + TaskList->next = TaskList; + TaskList->prev = TaskList; + + RestoreInterrupts( flags ); + } + + +/*--------------------------------------------------------------------- + Function: TS_SetClockSpeed + + Sets the rate of the 8253 timer. +---------------------------------------------------------------------*/ + +static void TS_SetClockSpeed + ( + long speed + ) + + { + unsigned flags; + + flags = DisableInterrupts(); + + if ( ( speed > 0 ) && ( speed < 0x10000L ) ) + { + TaskServiceRate = speed; + } + else + { + TaskServiceRate = 0x10000L; + } + + outp( 0x43, 0x36 ); + outp( 0x40, TaskServiceRate ); + outp( 0x40, TaskServiceRate >> 8 ); + + RestoreInterrupts( flags ); + } + + +/*--------------------------------------------------------------------- + Function: TS_SetTimer + + Calculates the rate at which a task will occur and sets the clock + speed if necessary. +---------------------------------------------------------------------*/ + +static long TS_SetTimer + ( + long TickBase + ) + + { + long speed; + + speed = 1192030L / TickBase; + if ( speed < TaskServiceRate ) + { + TS_SetClockSpeed( speed ); + } + + return( speed ); + } + + +/*--------------------------------------------------------------------- + Function: TS_SetTimerToMaxTaskRate + + Finds the fastest running task and sets the clock to operate at + that speed. +---------------------------------------------------------------------*/ + +static void TS_SetTimerToMaxTaskRate + ( + void + ) + + { + task *ptr; + long MaxServiceRate; + unsigned flags; + + flags = DisableInterrupts(); + + MaxServiceRate = 0x10000L; + + ptr = TaskList->next; + while( ptr != TaskList ) + { + if ( ptr->rate < MaxServiceRate ) + { + MaxServiceRate = ptr->rate; + } + + ptr = ptr->next; + } + + if ( TaskServiceRate != MaxServiceRate ) + { + TS_SetClockSpeed( MaxServiceRate ); + } + + RestoreInterrupts( flags ); + } + + +#ifdef NOINTS +/*--------------------------------------------------------------------- + Function: TS_ServiceSchedule + + Interrupt service routine +---------------------------------------------------------------------*/ + +static void __interrupt __far TS_ServiceSchedule + ( + void + ) + + { + task *ptr; + task *next; + + + TS_InInterrupt = TRUE; + + #ifdef USESTACK + // save stack + GetStack( &oldStackSelector, &oldStackPointer ); + + // set our stack + SetStack( StackSelector, StackPointer ); + #endif + + ptr = TaskList->next; + while( ptr != TaskList ) + { + next = ptr->next; + + if ( ptr->active ) + { + ptr->count += TaskServiceRate; +//JIM +// if ( ptr->count >= ptr->rate ) + while( ptr->count >= ptr->rate ) + { + ptr->count -= ptr->rate; + ptr->TaskService( ptr ); + } + } + ptr = next; + } + + #ifdef USESTACK + // restore stack + SetStack( oldStackSelector, oldStackPointer ); + #endif + + TaskServiceCount += TaskServiceRate; + if ( TaskServiceCount > 0xffffL ) + { + TaskServiceCount &= 0xffff; + _chain_intr( OldInt8 ); + } + + outp( 0x20,0x20 ); + + TS_InInterrupt = FALSE; + } + +#else + +/*--------------------------------------------------------------------- + Function: TS_ServiceScheduleIntEnabled + + Interrupt service routine with interrupts enabled. +---------------------------------------------------------------------*/ + +static void __interrupt __far TS_ServiceScheduleIntEnabled + ( + void + ) + + { + task *ptr; + task *next; + + TS_TimesInInterrupt++; + TaskServiceCount += TaskServiceRate; + if ( TaskServiceCount > 0xffffL ) + { + TaskServiceCount &= 0xffff; + _chain_intr( OldInt8 ); + } + + outp( 0x20,0x20 ); + + if ( TS_InInterrupt ) + { + return; + } + + TS_InInterrupt = TRUE; + _enable(); + + #ifdef USESTACK + // save stack + GetStack( &oldStackSelector, &oldStackPointer ); + + // set our stack + SetStack( StackSelector, StackPointer ); + #endif + + while( TS_TimesInInterrupt ) + { + ptr = TaskList->next ; + while( ptr != TaskList ) + { + next = ptr->next; + + if ( ptr->active ) + { + ptr->count += TaskServiceRate; + if ( ptr->count >= ptr->rate ) + { + ptr->count -= ptr->rate; + ptr->TaskService( ptr ); + } + } + ptr = next; + } + TS_TimesInInterrupt--; + } + + _disable(); + + #ifdef USESTACK + // restore stack + SetStack( oldStackSelector, oldStackPointer ); + #endif + + TS_InInterrupt = FALSE; + } +#endif + + +#ifdef USESTACK + +/*--------------------------------------------------------------------- + Function: allocateTimerStack + + Allocate a block of memory from conventional (low) memory and return + the selector (which can go directly into a segment register) of the + memory block or 0 if an error occured. +---------------------------------------------------------------------*/ + +static unsigned short allocateTimerStack + ( + unsigned short size + ) + + { + union REGS regs; + + // clear all registers + memset( ®s, 0, sizeof( regs ) ); + + // DPMI allocate conventional memory + regs.w.ax = 0x100; + + // size in paragraphs + regs.w.bx = ( size + 15 ) / 16; + + int386( 0x31, ®s, ®s ); + if (!regs.w.cflag) + { + // DPMI call returns selector in dx + // (ax contains real mode segment + // which is ignored here) + + return( regs.w.dx ); + } + + // Couldn't allocate memory. + return( NULL ); + } + + +/*--------------------------------------------------------------------- + Function: deallocateTimerStack + + Deallocate a block of conventional (low) memory given a selector to + it. Assumes the block was allocated with DPMI function 0x100. +---------------------------------------------------------------------*/ + +static void deallocateTimerStack + ( + unsigned short selector + ) + + { + union REGS regs; + + if ( selector != NULL ) + { + // clear all registers + memset( ®s, 0, sizeof( regs ) ); + + regs.w.ax = 0x101; + regs.w.dx = selector; + int386( 0x31, ®s, ®s ); + } + } + +#endif + +/*--------------------------------------------------------------------- + Function: TS_Startup + + Sets up the task service routine. +---------------------------------------------------------------------*/ + +static int TS_Startup + ( + void + ) + + { + if ( !TS_Installed ) + { +#ifdef LOCKMEMORY + + int status; + + status = TS_LockMemory(); + if ( status != TASK_Ok ) + { + TS_UnlockMemory(); + return( status ); + } + +#endif + +#ifdef USESTACK + + StackSelector = allocateTimerStack( kStackSize ); + if ( StackSelector == NULL ) + { + +#ifdef LOCKMEMORY + + TS_UnlockMemory(); + +#endif + return( TASK_Error ); + } + + // Leave a little room at top of stack just for the hell of it... + StackPointer = kStackSize - sizeof( long ); + +#endif + +//static const task *TaskList = &HeadTask; + TaskList->next = TaskList; + TaskList->prev = TaskList; + + TaskServiceRate = 0x10000L; + TaskServiceCount = 0; + +#ifndef NOINTS + TS_TimesInInterrupt = 0; +#endif + + OldInt8 = _dos_getvect( 0x08 ); + #ifdef NOINTS + _dos_setvect( 0x08, TS_ServiceSchedule ); + #else + _dos_setvect( 0x08, TS_ServiceScheduleIntEnabled ); + #endif + + TS_Installed = TRUE; + } + + return( TASK_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: TS_Shutdown + + Ends processing of all tasks. +---------------------------------------------------------------------*/ + +void TS_Shutdown + ( + void + ) + + { + if ( TS_Installed ) + { + TS_FreeTaskList(); + + TS_SetClockSpeed( 0 ); + + _dos_setvect( 0x08, OldInt8 ); + +#ifdef USESTACK + + deallocateTimerStack( StackSelector ); + StackSelector = NULL; + +#endif + + // Set Date and Time from CMOS +// RestoreRealTimeClock(); + +#ifdef LOCKMEMORY + + TS_UnlockMemory(); + +#endif + TS_Installed = FALSE; + } + } + + +/*--------------------------------------------------------------------- + Function: TS_ScheduleTask + + Schedules a new task for processing. +---------------------------------------------------------------------*/ + +task *TS_ScheduleTask + ( + void ( *Function )( task * ), + int rate, + int priority, + void *data + ) + + { + task *ptr; + +#ifdef USE_USRHOOKS + int status; + + ptr = NULL; + + status = USRHOOKS_GetMem( &ptr, sizeof( task ) ); + if ( status == USRHOOKS_Ok ) +#else + ptr = malloc( sizeof( task ) ); + if ( ptr != NULL ) +#endif + { + if ( !TS_Installed ) + { + status = TS_Startup(); + if ( status != TASK_Ok ) + { + FreeMem( ptr ); + return( NULL ); + } + } + + ptr->TaskService = Function; + ptr->data = data; + ptr->rate = TS_SetTimer( rate ); + ptr->count = 0; + ptr->priority = priority; + ptr->active = FALSE; + + TS_AddTask( ptr ); + } + + return( ptr ); + } + + +/*--------------------------------------------------------------------- + Function: TS_AddTask + + Adds a new task to our list of tasks. +---------------------------------------------------------------------*/ + +static void TS_AddTask + ( + task *node + ) + + { + LL_SortedInsertion( TaskList, node, next, prev, task, priority ); + } + + +/*--------------------------------------------------------------------- + Function: TS_Terminate + + Ends processing of a specific task. +---------------------------------------------------------------------*/ + +int TS_Terminate + ( + task *NodeToRemove + ) + + { + task *ptr; + task *next; + unsigned flags; + + flags = DisableInterrupts(); + + ptr = TaskList->next; + while( ptr != TaskList ) + { + next = ptr->next; + + if ( ptr == NodeToRemove ) + { + LL_RemoveNode( NodeToRemove, next, prev ); + NodeToRemove->next = NULL; + NodeToRemove->prev = NULL; + FreeMem( NodeToRemove ); + + TS_SetTimerToMaxTaskRate(); + + RestoreInterrupts( flags ); + + return( TASK_Ok ); + } + + ptr = next; + } + + RestoreInterrupts( flags ); + + return( TASK_Warning ); + } + + +/*--------------------------------------------------------------------- + Function: TS_Dispatch + + Begins processing of all inactive tasks. +---------------------------------------------------------------------*/ + +void TS_Dispatch + ( + void + ) + + { + task *ptr; + unsigned flags; + + flags = DisableInterrupts(); + + ptr = TaskList->next; + while( ptr != TaskList ) + { + ptr->active = TRUE; + ptr = ptr->next; + } + + RestoreInterrupts( flags ); + } + + +/*--------------------------------------------------------------------- + Function: TS_SetTaskRate + + Sets the rate at which the specified task is serviced. +---------------------------------------------------------------------*/ + +void TS_SetTaskRate + ( + task *Task, + int rate + ) + + { + unsigned flags; + + flags = DisableInterrupts(); + + Task->rate = TS_SetTimer( rate ); + TS_SetTimerToMaxTaskRate(); + + RestoreInterrupts( flags ); + } + + +#ifdef LOCKMEMORY + +/*--------------------------------------------------------------------- + Function: TS_LockEnd + + Used for determining the length of the functions to lock in memory. +---------------------------------------------------------------------*/ + +static void TS_LockEnd + ( + void + ) + + { + } + + +/*--------------------------------------------------------------------- + Function: TS_UnlockMemory + + Unlocks all neccessary data. +---------------------------------------------------------------------*/ + +void TS_UnlockMemory + ( + void + ) + + { + DPMI_UnlockMemoryRegion( TS_LockStart, TS_LockEnd ); + DPMI_Unlock( TaskList ); + DPMI_Unlock( OldInt8 ); + DPMI_Unlock( TaskServiceRate ); + DPMI_Unlock( TaskServiceCount ); + DPMI_Unlock( TS_Installed ); + +#ifndef NOINTS + DPMI_Unlock( TS_TimesInInterrupt ); +#endif + +#ifdef USESTACK + DPMI_Unlock( StackSelector ); + DPMI_Unlock( StackPointer ); + DPMI_Unlock( oldStackSelector ); + DPMI_Unlock( oldStackPointer ); +#endif + } + + +/*--------------------------------------------------------------------- + Function: TS_LockMemory + + Locks all neccessary data. +---------------------------------------------------------------------*/ + +int TS_LockMemory + ( + void + ) + + { + int status; + + status = DPMI_LockMemoryRegion( TS_LockStart, TS_LockEnd ); + status |= DPMI_Lock( TaskList ); + status |= DPMI_Lock( OldInt8 ); + status |= DPMI_Lock( TaskServiceRate ); + status |= DPMI_Lock( TaskServiceCount ); + status |= DPMI_Lock( TS_Installed ); + +#ifndef NOINTS + status |= DPMI_Lock( TS_TimesInInterrupt ); +#endif + +#ifdef USESTACK + status |= DPMI_Lock( StackSelector ); + status |= DPMI_Lock( StackPointer ); + status |= DPMI_Lock( oldStackSelector ); + status |= DPMI_Lock( oldStackPointer ); +#endif + + if ( status != DPMI_Ok ) + { + TS_UnlockMemory(); + return( TASK_Error ); + } + + return( TASK_Ok ); + } + +#endif + +/* +// Converts a hex byte to an integer + +static int btoi + ( + unsigned char bcd + ) + + { + unsigned b; + unsigned c; + unsigned d; + + b = bcd / 16; + c = bcd - b * 16; + d = b * 10 + c; + return( d ); + } + + +static void RestoreRealTimeClock + ( + void + ) + + { + int read; + int i; + int hr; + int min; + int sec; + int cent; + int yr; + int mo; + int day; + int year; + union REGS inregs; + + // Read Real Time Clock Time. + read = FALSE; + inregs.h.ah = 0x02; + for( i = 1; i <= 3; i++ ) + { + int386( 0x1A, &inregs, &inregs ); + if ( inregs.x.cflag == 0 ) + { + read = TRUE; + } + } + + if ( read ) + { + //and convert BCD to integer format + hr = btoi( inregs.h.ch ); + min = btoi( inregs.h.cl ); + sec = btoi( inregs.h.dh ); + + // Read Real Time Clock Date. + inregs.h.ah = 0x04; + int386( 0x1A, &inregs, &inregs ); + if ( inregs.x.cflag == 0 ) + { + //and convert BCD to integer format + cent = btoi( inregs.h.ch ); + yr = btoi( inregs.h.cl ); + mo = btoi( inregs.h.dh ); + day = btoi( inregs.h.dl ); + year = cent * 100 + yr; + + // Set System Time. + inregs.h.ch = hr; + inregs.h.cl = min; + inregs.h.dh = sec; + inregs.h.dl = 0; + inregs.h.ah = 0x2D; + int386( 0x21, &inregs, &inregs ); + + // Set System Date. + inregs.w.cx = year; + inregs.h.dh = mo; + inregs.h.dl = day; + inregs.h.ah = 0x2B; + int386( 0x21, &inregs, &inregs ); + } + } + } +*/ +/* + struct dostime_t time; + struct dosdate_t date; + + outp(0x70,0); + time.second=inp(0x71); + outp(0x70,2); + time.minute=inp(0x71); + outp(0x70,4); + time.hour=inp(0x71); + + outp(0x70,7); + date.day=inp(0x71); + outp(0x70,8); + date.month=inp(0x71); + outp(0x70,9); + date.year=inp(0x71); + + time.second=(time.second&0x0f)+((time.second>>4)*10); + time.minute=(time.minute&0x0f)+((time.minute>>4)*10); + time.hour=(time.hour&0x0f)+((time.hour>>4)*10); + + date.day=(date.day&0x0f)+((date.day>>4)*10); + date.month=(date.month&0x0f)+((date.month>>4)*10); + date.year=(date.year&0x0f)+((date.year>>4)*10); + + _dos_settime(&time); + _dos_setdate(&date); + +*/ diff --git a/audiolib/task_man.h b/audiolib/task_man.h new file mode 100755 index 0000000..7e24606 --- /dev/null +++ b/audiolib/task_man.h @@ -0,0 +1,68 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: TASK_MAN.C + + author: James R. Dose + date: July 25, 1994 + + Public header for TASK_MAN.C, a low level timer task scheduler. + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#ifndef __TASK_MAN_H +#define __TASK_MAN_H + +enum TASK_ERRORS + { + TASK_Warning = -2, + TASK_Error = -1, + TASK_Ok = 0 + }; + +typedef struct task +{ + struct task *next; + struct task *prev; + void ( *TaskService )( struct task * ); + void *data; + long rate; + volatile long count; + int priority; + int active; +} task; + +// TS_InInterrupt is TRUE during a taskman interrupt. +// Use this if you have code that may be used both outside +// and within interrupts. + +extern volatile int TS_InInterrupt; + +void TS_Shutdown( void ); +task *TS_ScheduleTask( void ( *Function )( task * ), int rate, + int priority, void *data ); +int TS_Terminate( task *ptr ); +void TS_Dispatch( void ); +void TS_SetTaskRate( task *Task, int rate ); +void TS_UnlockMemory( void ); +int TS_LockMemory( void ); + +#endif diff --git a/audiolib/user.c b/audiolib/user.c new file mode 100755 index 0000000..c3363a9 --- /dev/null +++ b/audiolib/user.c @@ -0,0 +1,133 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: USER.C + + author: James R. Dose + date: April 26, 1994 + + Routines to parse command line options. + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#ifdef PLAT_DOS +#include +#endif + +#include +#include "user.h" + +#define TRUE ( 1 == 1 ) +#define FALSE ( !TRUE ) + +#ifdef PLAT_DOS +extern int _argc; +extern char **_argv; +#endif + +/*--------------------------------------------------------------------- + Function: USER_CheckParameter + + Checks if the specified string is present in the command line. +---------------------------------------------------------------------*/ + +int USER_CheckParameter + ( + const char *parameter + ) + + { +#ifdef PLAT_DOS + int i; + int found; + char *ptr; + + found = FALSE; + i = 1; + while( i < _argc ) + { + ptr = _argv[ i ]; + + // Only check parameters preceded by - or / + if ( ( *ptr == '-' ) || ( *ptr == '/' ) ) + { + ptr++; + if ( stricmp( parameter, ptr ) == 0 ) + { + found = TRUE; + break; + } + } + + i++; + } + + return( found ); +#else + return FALSE; +#endif + } + + +/*--------------------------------------------------------------------- + Function: USER_GetText + + Checks if the specified string is present in the command line + and returns a pointer to the text following it. +---------------------------------------------------------------------*/ + +char *USER_GetText + ( + const char *parameter + ) + + { +#ifdef PLAT_DOS + int i; + char *text; + char *ptr; + + text = NULL; + i = 1; + while( i < _argc ) + { + ptr = _argv[ i ]; + + // Only check parameters preceded by - or / + if ( ( *ptr == '-' ) || ( *ptr == '/' ) ) + { + ptr++; + if ( stricmp( parameter, ptr ) == 0 ) + { + i++; + text = _argv[ i ]; + break; + } + } + + i++; + } + + return( text ); +#else + return NULL; +#endif + } diff --git a/audiolib/user.h b/audiolib/user.h new file mode 100755 index 0000000..b81b3cf --- /dev/null +++ b/audiolib/user.h @@ -0,0 +1,38 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: USER.H + + author: James R. Dose + phone: (214)-271-1365 Ext #221 + date: April 26, 1994 + + Public header for USER.C + + (c) Copyright 1994 James R. Dose. All Rights Reserved. +**********************************************************************/ + +#ifndef __USER_H +#define __USER_H + +int USER_CheckParameter( const char *parameter ); +char *USER_GetText( const char *parameter ); + +#endif diff --git a/audiolib/usrhooks.c b/audiolib/usrhooks.c new file mode 100755 index 0000000..e012dc4 --- /dev/null +++ b/audiolib/usrhooks.c @@ -0,0 +1,84 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: USRHOOKS.C + + author: James R. Dose + date: July 26, 1994 + + This module contains cover functions for operations the library + needs that may be restricted by the calling program. This code + is left public for you to modify. +**********************************************************************/ + +#include +#include "usrhooks.h" + + +/*--------------------------------------------------------------------- + Function: USRHOOKS_GetMem + + Allocates the requested amount of memory and returns a pointer to + its location, or NULL if an error occurs. NOTE: pointer is assumed + to be dword aligned. +---------------------------------------------------------------------*/ + +int USRHOOKS_GetMem + ( + void **ptr, + unsigned long size + ) + + { + void *memory; + + memory = malloc( size ); + if ( memory == NULL ) + { + return( USRHOOKS_Error ); + } + + *ptr = memory; + + return( USRHOOKS_Ok ); + } + + +/*--------------------------------------------------------------------- + Function: USRHOOKS_FreeMem + + Deallocates the memory associated with the specified pointer. +---------------------------------------------------------------------*/ + +int USRHOOKS_FreeMem + ( + void *ptr + ) + + { + if ( ptr == NULL ) + { + return( USRHOOKS_Error ); + } + + free( ptr ); + + return( USRHOOKS_Ok ); + } diff --git a/audiolib/usrhooks.h b/audiolib/usrhooks.h new file mode 100755 index 0000000..8dc2e0e --- /dev/null +++ b/audiolib/usrhooks.h @@ -0,0 +1,55 @@ +/* +Copyright (C) 1994-1995 Apogee Software, Ltd. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/********************************************************************** + module: USRHOOKS.H + + author: James R. Dose + date: July 26, 1994 + + Public header file for USRHOOKS.C. + + This module contains cover functions for operations the library + needs that may be restricted by the calling program. The function + prototypes in this header should not be modified. +**********************************************************************/ + +#ifndef __USRHOOKS_H +#define __USRHOOKS_H + +/*--------------------------------------------------------------------- + Error definitions +---------------------------------------------------------------------*/ + +enum USRHOOKS_Errors + { + USRHOOKS_Warning = -2, + USRHOOKS_Error = -1, + USRHOOKS_Ok = 0 + }; + + +/*--------------------------------------------------------------------- + Function Prototypes +---------------------------------------------------------------------*/ + +int USRHOOKS_GetMem( void **ptr, unsigned long size ); +int USRHOOKS_FreeMem( void *ptr ); + +#endif diff --git a/audiolib/util.h b/audiolib/util.h new file mode 100755 index 0000000..2960501 --- /dev/null +++ b/audiolib/util.h @@ -0,0 +1,13 @@ +#ifndef AUDIOLIB__UTIL_H +#define AUDIOLIB__UTIL_H + +#ifndef min +#define min(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#ifndef max +#define max(a, b) ((a) > (b) ? (a) : (b)) +#endif + +#endif + diff --git a/buildengine/BUILDLIC.TXT b/buildengine/BUILDLIC.TXT new file mode 100755 index 0000000..939a6f4 --- /dev/null +++ b/buildengine/BUILDLIC.TXT @@ -0,0 +1,77 @@ +(Note from Ryan: This is Ken's BUILD license. It is NOT GPL. Please respect + his license, and also keep in mind that Ken does NOT work on the Linux port. + Please don't harrass him for bug fixes and enhancements to the Linux version. + He did the DOS version. --ryan.) + + +BUILD SOURCE CODE LICENSE TERMS: 06/20/2000 + +[1] I give you permission to make modifications to my Build source and + distribute it, BUT: + +[2] Any derivative works based on my Build source may be distributed ONLY + through the INTERNET. + +[3] Distribution of any derivative works MUST be done completely FREE of + charge - no commercial exploitation whatsoever. + +[4] Anything you distribute which uses a part of my Build Engine source + code MUST include: + + [A] The following message somewhere in the archive: + + // "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman + // Ken Silverman's official web site: "http://www.advsys.net/ken" + // See the included license file "BUILDLIC.TXT" for license info. + + [B] This text file "BUILDLIC.TXT" along with it. + + [C] Any source files that you modify must include this message as well: + + // This file has been modified from Ken Silverman's original release + +[5] The use of the Build Engine for commercial purposes will require an + appropriate license arrangement with me. Contact information is + on my web site. + +[6] I take no responsibility for damage to your system. + +[7] Technical support: Before contacting me with questions, please read + and do ALL of the following! + + [A] Look through ALL of my text files. There are 7 of them (including this + one). I like to think that I wrote them for a reason. You will find + many of your answers in the history section of BUILD.TXT and + BUILD2.TXT (they're located inside SRC.ZIP). + + [B] If that doesn't satisfy you, then try going to: + + "http://www.advsys.net/ken/buildsrc" + + where I will maintain a Build Source Code FAQ (or perhaps I might + just provide a link to a good FAQ). + + [C] I am willing to respond to questions, but ONLY if they come at a rate + that I can handle. + + PLEASE TRY TO AVOID ASKING DUPLICATE QUESTIONS! + + As my line of defense, I will post my current policy about + answering Build source questions (right below the E-mail address + on my web site.) You can check there to see if I'm getting + overloaded with questions or not. + + If I'm too busy, it might say something like this: + + I'm too busy to answer Build source questions right now. + Sorry, but don't expect a reply from me any time soon. + + If I'm open for Build source questions, please state your question + clearly and don't include any unsolicited attachments unless + they're really small (like less than 50k). Assume that I have + a 28.8k modem. Also, don't leave out important details just + to make your question appear shorter - making me guess what + you're asking doesn't save me time! + +---------------------------------------------------------------------------- +-Ken S. (official web site: http://www.advsys.net/ken) diff --git a/buildengine/CHANGELOG b/buildengine/CHANGELOG new file mode 100755 index 0000000..2cd66c5 --- /dev/null +++ b/buildengine/CHANGELOG @@ -0,0 +1,566 @@ +/* + * CHANGELOG. + * + * Please do NOT harrass Ken Silverman about any code modifications + * (including this file) to BUILD. + */ + +07112000 - Initial release from icculus. C code compiles, doesn't link, lots + of bastard assembly. +07122000 - LOTS of ASM cleanups by Andrew Henderson. +07132000 - Ryan adds some missing functionality: SDL equivalents for most of + the VESA functions, filelength(), and some other piddly stuff. +07142000 - Dan Olson cleans up the code a bunch, fills in a bunch of the + ASM routines with C equivalents, and puts some VESA replacements + in place. Other good stuff. Ryan cleans up some, too, put some + more stubs/implementations in place, and continues to flesh out + the SDL driver. +07212000 - A BUTTLOAD of updates. "build" links, and segfaults, because I + screwed up all the inline ASM that I did. Will be correcting, + shortly. "game" doesn't link yet. Haven't looked at it in detail. + Moved anything with i/o port calls into dos_driver.c, and put + stub equivalents in sdl_driver.c ... The setupmouse() function got + commented out because it was getting called before the video got + setup, I think. Will check. (never released.) +07272000 - Assembly in pragmas.c was borked (thanks to RYAN.), and is now + halfway fixed. Ryan will be fixing this completely Real Soon Now. + Other ASM may be screwey, too, if Ryan touched it, but the NASM + code that Andrew did is probably fine (mostly because he knows + what he's doing... :) ) +07282000 - Fixed borked ASM code. Fixed a text file reading routine that + depended on finding DOS-style newlines. Moved some more stuff to + sdl_driver.c and dos_driver.c ... +07292000 - Fixes in pragmas.c by Dan Olson, who also knows more about this + inline ASM stuff than Ryan. Dan also cleaned up engine.c's ASM. + Thanks to Dan and Ryan, game.c now compiles, albeit with a + thousand warnings. "game" does not link yet. +07312000 - Thanks to Dan, "game" now links, other minor fixups by Ryan. Broke + up CHANGELOG into some standard docs. (README, CREDITS, etc...) +08012000 - Andrew does some graphic porting. Looks like we've got blocks where + fonts should be, and a mouse cursor. Huh. Ryan abstracts 0xa0000 + addresses to VIDEOBASE define. Under non-DOS platforms, this is + currently "surface->pixels". Basic events were hooked up. Added + FreeVGA to README. Lots of fun new segfaults. +08042000 - Ryan gets the keyboard working apparently fully, and the mouse + sorta. The grid now draws correctly. No more segfaults on exit. + You can zoom in and out on the grid with the 'Z' and 'A' keys. + Fun, huh? sdl_driver's drawing routines (most notably, drawline16) + are MUCH more robust. Some minor structure changes. Other things + seem to work within build (space draws a line from a point to the + mouse, etc.), but I dunno what any of this means; must find a + BUILD HOWTO. Probably other stuff. Timer is hooked up, but SDL + won't fire a timer faster than every 10ms, or 100 times a second. + BUILD expects this timer to fire every 8.3~ seconds, or 120 times + a second. This may be problematic in the game, but it probably won't + be a problem in the BUILD editor, where it just handles keyboard + updates. An alternate timer system might get swapped in later. + Game still links, but aborts on initing the timer, since I need to + sync with the editor; Ken saw it fit to commit the mortal sin of + cut-and-paste instead of having a unified BUILD_Init() function, + so I need to update it to the new structure (using sdl_driver or + dos_driver, calling _platform_init(), blah blah blah...) +08052000 - Dan fixed an ASM screwup in getkensmessagecrc(). Ryan fixed the + mouse button event code. Added event thread, and some bits of + thread safety in sdl_driver.c. Mouse now seems to move okay if the + X11 cursor is hidden, and we grab the input. Goes to fullscreen + and grabs input by default; export BUILD_WINDOWED=y and + BUILD_NO_MOUSE_GRAB=y, respectively, to disable. Got myself a + copy of Duke3D Atomic Edition for the data files. Fixed the + #pragma packs in build.h. Fixed _platform_init() functions. + Improved SDL driver. Commented out a bunch of self-modifying ASM. + Dan got the fonts to display. Ryan got the correct palette loaded. + Lots of other little cleanups. Good stuff. +08062000 - Ryan fixed clear2dscreen() in SDL driver. It's (hopefully) correct, + now. Also, all that missing text should (hopefully) now display. + drawline16 is more correct now. Other little cleanups and + move-arounds. It seems that "pageoffset" is the big enemy around + here today. Hum. +08072000 - Ryan gets the BUILD title text to stop flickering. Prints our names + at exit (maybe someone will want to hump OUR legs, too). Added the + _idle() function to dos_driver and sdl_driver, and sprinkled some + calls through overheadeditor() in build.c ... ideally, we'd + eventually want to not have the editor wipe the surface and + redraw everything like mad constantly, but rather wipe and draw + as needed to choke the processor even less. Added implementation + of getfilenames() in build.c...seems to work well enough. Got + map loading dialog to appear (in the wrong place), but the arrow + keys don't seem to work to test further. Added caption to window's + title bar. Dan completely the Herculean effort of cleaning up + EVERY compiler warning in the editor. Other tinkering. + Adrian Neill and Christian Zander cleaned up all the compile + warnings in game.c and multi.c. Christian also supplied a shell + script to set the BUILD_* variables for developing. Ryan fixed + permissions of map files in saveboard() in engine.c. game.c had a + static variable called "sync" that conflicted with unistd.h's + sync() function, so the static's been changed to _sync. Fixed + more graphic stuff; pageoffset is just blindly set to zero on + Unix, now, and that seems to fix some stuff. printext16() was + changed to statusbar_printext16() in the appropriate places, so + I could remove my ypos += 336 hack in the actual implementation, + make this #define to regular printext16 on DOS, and be a one-line + function to add 336 to ypos in Unix. sdl_key_filter now has + support for extended keys; in init_new_res_vars(), just add keys + with values of 0xE0** where "**" is the normal value. This allowed + me to add the arrow keys and the keypad enter key. Tried loading + Ken's maps, and they WORK. With today's graphic fixes and the + arrow keys, you can select a file from the loading menu, and + navigate around in 2D mode. Cool. Switching to 3D mode segfaults + immediately. :) Changed sdl_driver to NOT double buffer, and + the SDL_Flip() call is now a screen-wide SDL_UpdateRect(). Added + Ken's maps for his test game to the archive. +08082000 - Added key bindings to sdl_driver: ALT-Enter (or ALT-Return) to + toggle between windowed and fullscreen, and CTRL-G to grab/ungrab + the mouse pointer. Increased sensitivity of mouse movement. Dan + fixed the editor's status bar; it now draws. I think Dan also + squashed the rest of the pageoffset annoyances in the editor. + Dan tracked down the line drawing problem, and Ryan patched some + ASM (clearbufbyte(), specifically), so you can add walls, now. + Things are REALLY starting to look good. +08092000 - ASM day. Fixes and fights from Dan and Ryan, with lots of wisdom + from Andrew. Realized that we were in violation of Ken Silverman's + license by not updating/including his copyright header on all + source files. This has been fixed; sorry, Ken. Other video stuff. + Tweakage. 3D mode no longer segfaults, but is still garbage. +08112000 - Fixed a bug; ALT-Enter wasn't changing sdl_flags, so next time you + changed resolutions, you went back to your original (non)windowed + state. Did the same for mouse grab state. Dan converted the ASM + for some more engine.c functions, and added a missing key to our + SDL scancode table. Hooked up keybindings in the (still not + functional) 3D mode. Discovered that we were missing some data + files. More sdl_driver tinkering. Moved stuff out of dos_driver's + _nextpage(), and back into the abstract engine.c section. + I don't know what I changed, but the sprite and vector squares + don't draw in the correct place anymore in engine.c's + draw2dscreen() ... culprit is something in sdl_driver.c...someone + diff this version against the last. Grrr. Generally, I'd fix this + before sending out a tarball, but it's 5:00a.m., and I need to get + something out the door here. Will fix for tommorow, and it doesn't + otherwise impede your use. +08122000 - Turned optimizations back on, and the broken drawing from last + night works again. Yikes. Dan stubbed out lots of the missing C + functions in a.c (someday, we'll fill really these in, I hope.), + and made mad progress on attacking our palette issues. Some compile + fixes (incomplete) to allow building without SUPERBUILD defined + (for removing voxel support...might be needed for pre-voxel games + like Duke3D...) The self-modifying ASM passes function parameters + in registers, so I needed to do an inline wrapper. This also now + sits in a.c. (Still crashes and otherwise doesn't WORK the same + in 3D mode, but still...) Added tiles000.art to the archive from + Duke3D shareware's duke3d.GRP file. I hope this doesn't violate + anyone's copyrights. +08132000 - (For reference, apparently GCC requires -O2 for inline asm to work. + That would explain the drawing barfs...) Dan fixed the status bar + (after Ryan broke it again. :) ), and moved krecipasm() into + a_linux.asm, since FPU opcodes don't inline correctly. Added Ken's + stuff.dat. As a milestone, 3D mode now seems to work a LITTLE. + Looking in the wrong place causes a segfault, and generally, what + very little draws seems mostly incorrect, but progress is being + made. Changed out all the collected data files with Ken's original + STUFF.DAT. initgroupfile() now aborts the program if it can't + open a data file. (Without stuff.dat, you get a blank surface, and + you have to blindly feel your way out of the program.) Dan also + started work on the command line tools, like kextract. Those are + in a separate tarball on the website. +08152000 - (Stuck at LinuxWorld...sorry for delays.) 3D mode now does not (by + default) segfault, and you can stumble around. Some walls seem to + render correctly. Lots of things cause segfaults. Disabled the MMX + overlays for now, as that is a little less self-modified code in + use. Dan fixed some keyboard scancodes (and also independently + fixed the same 3D mode things. hah. :) ) +08192000 - Back from LinuxWorld. Added an obnoxious hall of mirrors detector + for 3D mode. _asm_slopevlin now returns immediately, which for now + stops most 3D mode segfaults. This will have to change, but it + helps for now. Put in a hack for checking frames-per-second. + Added some new keyboard scancodes. +08212000 - Another keyboard scancode added by Dan. Changed 3D mode to prompt + to save changes before dropping out of graphics mode; the stdio + thing was pretty obnoxious. Now we are basically waiting on a copy + of Watcom C to show up, so I can trace through the original code + and verify that I'm getting sane parameters and return values. + Needless to say, productivity has dropped off quite a bit. +08232000 - Dan found a screwup in the inlined dmulscale32()'s return value. + Consequently, now the hall of mirrors are gone. Cool. Walls seem + to render correctly all the time now. Other visual problems, and + no floors or ceilings, but this is a BIG win. Thanks, Dan! (A few + other ASM functions in pragmas.c had this problem. dmulscale32() + was the most noticable fix, though.) +08242000 - Dan added/fixed some more ASM. The SDL parachute is now in place, + so we will go back to the correct resolution, and the mouse + will ungrab in case of a segfault. A C version (mostly working?) + of qinterpolatedown16short() has been added to pragmas.c, and + the ASM version had a fix that allows ceilings to show (though they + render incorrectly in the correct place, and now certain sprites + segfault. Ugh. PageUp/PageDown scancodes now work, so you can + raise and lower ceilings and floors. Changed caption in titlebar + of windowed mode. +08292000 - Matt Helsley contributed some ASM -> C conversions, and some test + code to help with further porting. Cleaned up some cruft in the + sdl_driver. Dan nailed another clobber list issue in pragmas.c. + Thanks to Nicholas Vining, we now have a copy of Watcom C. Ryan + sat down and stepped through the ASM in gdb (NOT fun at all), + while Nicholas stepped through the DOS version in parallel. + Eventually we stumbled upon some misassembled opcodes; we ended + up filling some registers with a pointer, and not what the pointer + pointed at! Ryan went through a_linux.asm and fixed all these, + and now 3D mode is almost entirely FLAWLESS. This is so cool. + Bedtime; I hope you all enjoy this. :) Thanks Nicholas! +08302000 - GAME now works. There was something awful in multi.c, probably + memory corruption with a static initializer, so SDL_Init() would + die in XOpenDisplay(NULL). Yikes. I've stubbed out what game.c + needs for multiplayer and put it in multi_tcpip.c (guess what + THAT'S for. :) ). The original multiplayer code is completely + modem and COMit based, and is useless anywhere but DOS, so this + isn't a big loss. Added some support for building under Cygwin, + but not much. Note that distributing binaries of BUILD built with + Cygwin violates the GPL, due to newlib's license, so don't do it. + But you can try compiling your own local copies. Where the hell + did CONTRIB go? Quick rewrite of that file. Minor glitches and + sound (and networking?) are the only things pending. +08302000 - Temporary fix; either nsqrtasm() or its tables are not correct + (our C rewrite gives exactly the same results as the ASM version, + too), so we've replaced it with a call to the C runtime's sqrt() + function, which seems to work fine. I hacked at getting better + calls to timerhandler(); still not happy with the results. + I also fixed some stuff in sdl_driver.c, so you can have + resolutions > 320x200 in 3D mode. Use F4 in the game to change + modes. Dunno how you change it in the editor, but you'll note that + the 3D mode defaults to 640x480 now...this is where the editor + SHOULD be, but I had 320, 320 hardcoded in _setgamemode() for some + strange reason. Oh, and CONTRIB was lowercased. That's where it + went. URL for this project is now listed on Ken's homepage. +09012000 - Happy September. Code tree is now available via CVS, thanks to + Matt and "witten". Dan fixed another keysym. port i/o macros were + being called when changing to 3D mode in the editor; #ifdef'd to + PLATFORM_DOS, now. Misassembled opcode in msqrtasm() is now fixed, + so the function operates correctly. Removed the #if 0, so that + ASM now gets used. +09032000 - Dan fixed some printext16 calls in 2D mode. Added a BUILD_NOPENTIUM + environment variable: if set, it disables PentiumPro/PentiumII/MMX + optimizations. The code runs at more than 10fps less without + the Pentium overlays on my box (62fps to 50fps in the start of + nukeland.map at 640x480). I tried adding all the crazy compiler + optimizations I could think of. First, anything above -O2 causes + engine.c's compile to fail with a duplicate label from setgotpic. + This is an optimizer bug in inline asm. It cuts and pastes it + to inline it into each function, despite __volatile__ and the + lack of an inline keyword on the function where the ASM exists, + and you get a duplicate label. It's dumb. All the other + optimizations I threw at it worked, including pentiumpro + compilation, -fexpensive-optimizations, and -funroll-loops, but + there was absolutely NO increase in frame rate. I imagine most of + the time in 3D mode is being spent in a_linux.asm anyhow. If we + ever get this converted to C, those optimizations will be more + handy, I imagine, but for now, I've not committed the Makefile. + Cleaned up the README. After some tinkering, I managed to get + build to compile and RUN on Windows 98 with Cygwin. I can't + distribute binaries of this, as it would violate the GPL. + However, I will be merging the changes back into the main source + once I figure out the best way how. Mostly, the inline ASM needed + some hacks, but nothing I can cleanly #ifdef. Amazingly, + mprotect() worked identically on Linux and Cygwin. The mind + boggles. Changes that have made it into the CVS repository for the + Cygwin work follow: Removed dependency on the SDL event thread + (SDL_Init() fails on Win32 if you request an event thread), and + put SDL_PumpEvents() calls into _idle() and _nextpage(). This + seems to work fine, but there can be some breakage if there's a + keyboard polling loop somewhere that doesn't call either of these + functions. Added some %define macros to a_linux.asm to handle + C compilers that append an underscore to C identifiers. Updated the + Makefile for cygwin and other improvements. +09052000 - Checked if Duke3d maps can be edited. Apparently they can be, + but only sorta. Quitting from 2D mode only prompts you to save + if you've changed something, now. Fixed the CVS info in README. + Added Duke3D and Shadow Warrior data file info to README. Minor + cleanups in the Makefile. Moved VIDEOBASE defines to display.h. + _platform_init() now takes icon and titlebar titles, and has been + updated in all drivers. +02102001 - Someone on the 3DRealms Web Forums finds icculus.org: + http://www.3drealms.com/cgi-bin/ultimatebb.cgi?ubb=get_topic&f=5&t=001318 +02132001 - (Five months later...ugh.) Dan noticed that my webpage is being + discussed on the 3DRealms forums, so I went back into the code + and finished the work to get this running under Cygwin. Here's + the list of that work: Makefile is now more robust, added a + non-__attribute__ version of asm_prohlineasm4() to a.h, moved some + #includes in cache1d.c to prevent a double-definition of O_BINARY. + Fixed the inline asm in engine.c and pragmas.c to handle C + compilers that add underscores to identifiers. Removed the + SDL_HWSURFACE flag in sdl_driver.c (didn't realize this is + actually slower on most hardware, and it also breaks fullscreen + mode in Win32 on my box). Had to #ifndef CYGWIN the fnmatch stuff + in build.c until I find a portable, non-GPL solution. +02142001 - Dan Olson nailed an assembly bug that caused segfaults in the + 2nd overhead view in Ken's game. After that fix was applied, I + tagged the current CVS as "final-non-win32", as I start the effort + to make this thing compile as a native win32 executable with + (gasp!) Watcom C. Lots of stuff is getting torn around, as + assumptions get challenged: PLATFORM_UNIX vs. PLATFORM_DOS? Now + there's a PLATFORM_WIN32. unix_compat.h's display stuff has been + moved to display.h, and all the files include "platform.h" instead + of unix_compat.h, which allows us to choose the correct + compatibility header at compile time (win32_compat.h, + unix_compat.h, or doscmpat.h). All the platform-specific includes + (io.h, and such) have been moved into their respective compat + header, which cleaned up a lot of mess. Just to keep it real with + Cygwin, the Makefile now autodetects Cygwin, and sets the build + properties accordingly. Using a non-Cygwin GCC on Linux doesn't + set the Cygwin-related properties. SDL_INC_DIR and SDL_LIB_DIR can + be set as environment variables, so you never need to touch the + Makefile directly with Cygwin. "make clean" now cleans up various + Watcom C output, and vi's annoying "~" backup files. Tons of + patches and enhancements and little cleanups just to get this + to build on Watcom. Thing builds now, but has lots of problems + running, which will be resolved, hopefully, tonight. The Linux + version still works fine, and presumably so will the Cygwin + version. Overall, the quality of the port's codebase is improving + through this effort. I wonder if the DOS version will build now... +02152001 - Did initial work to get a protected mode DOS binary running again. + Hey, why not? Not complete (compiles clean, no link). Lots of + cleanups, and again, this is improving the quality of the port's + codebase. As usual, the Linux, and presumably Cygwin, versions + still compile clean and run. Haven't tried Watcom/Win32 tonight. + Renamed dos_driver.c to dos_drvr.c, so you can build the DOS bits + on a regular FAT filesystem. Added a Makefile.dos for use with + Watcom C's wmake (based on Ken's original). Lots of other files + touched. Added a "make package" rule to the Makefile, to improve + the quality of my own life. Added (har) a FILEID.DIZ file, which + is really used for the package's zipfile comment, but I always + wanted to have one of those. :) +02182001 - Removed the ENDLINE_CHAR stuff in build.c; that textfile reading + code is now able to handle '\n', '\r', and "\r\n" endlines. + The findfirst/findnext/whatnot code now works on Linux, Cygwin, + and Watcom C (dos, and win32). It's still kludgy, though. More + compat header cleanups. Figured out how to get SDL working fully + with Watcom C (-ei command line to wcc386.exe, and declare your + SDL callbacks as __cdecl, etc.). +02192001 - More Watcom fixes; build.exe's 3D mode is now fully operational. + One graphical glitch in 2D mode, still, but otherwise appears + fully functional. Put safety checks in a.h. Put a fix in build.c's + overheadeditor(), so it doesn't try to reference element -1 in an + array when clicking the left mouse button. Other ASM cleanups. + Fixed an annoying function declaration in bstub.c. Fixed an + incorrect assumption in sdl_driver.c's VBE_setPalette() that was + exposed by game.c under Watcom/win32. One quick addition of the + keyword "extern" to game.c, and we have a working game.exe under + Windows that isn't GPL encumbered. Woohoo! Added a Watcom/win32 + Makefile, updated the README, and released win32 binaries. +02202001 - Turned on more optimizations in the Watcom makefile, and cleaned + it up/abstracted it for public use. Added an nt_win option to that + makefile to make it not pop up a console window when started from + an icon. Added README-win32bins.txt to the CVS repository. Fixme + note to self added in engine.c, and an incorrect use of ASM in + pragmas.h was repaired. Now the drawpixel16 function is working, + closing the last bug specific to the Watcom/win32 port. Yay. +02212001 - Fixed the timer bug! It was a one line change in game.c, pointed + out by Matt Saettler. Amen. This led to a better abstraction: + PLATFORM_TIMER_HZ, defined in platform.h ... Removed the wedged-in + call to SDL_PumpEvents() in game.c...not needed anymore. +02222001 - Ported the codebase back to DOS. Point wmake.exe at Makefile.dos. +02262001 - Added code to enable write access to self-modified ASM memory pages + so this will work on WinNT and Win2K. Discovered it wasn't needed, + and the real problem is that Watcom produces an incorrect PE + header in the generated EXE files. Steven Fuller dug up a program + that fixes this, and did a ton of debugging. Added him to the + CONTRIB file. Fixed Makefile.w32 and changed the default builds + to optimized and not debug to make binary distribution easier. + Automated the packaging of binary releases in Makefile. +04262001 - EDuke 2.1 goes into private beta. Will it be the last release based + on Ken Silverman's original BUILD object code for Duke Nukem 3D? +05102001 - Embedded a Perl interpreter that runs a function in game.pl once + per frame into the KenBuild game. This is just a test for a future + project, and probably shouldn't be compiled by the average person. + Changes to the Makefile, game.c, game.pl, and buildperl.[ch] were + added. Changed all occurances of my email address from + lokigames.com to linuxgames.com. One or two comment tweaks + elsewhere. Updated README with SDL12 CVS instructions. +05192001 - Demands SDL_HWPALETTE, which seems to fix 8bit color targets. Added + other debugging info to sdl_driver.c, and put the (commented out) + starts of hardware surface/double buffering/page flipping support. + Updated TODO. +05222001 - Updated TODO again. Cleaned up engine.c's forward function + references. Put together engine.h, so that the engine's exported + functionality can be referenced via one header instead of a list + of function declarations plugged into every file. Made everything + that shouldn't be exported from engine.c static, but this is an + error-prone process, so it'll probably get tweaked as other Build + related code gets tried with this engine. Similar cleanups in + build.c, display.h, and elsewhere. Laid foundation for an OpenGL + renderer. No actual rendering is done, just context creation and + library setup when _setgamemode() is called on a system that uses + the SDL driver. This work may never get finished, but why not try? + Flip the "useopengl" flag in the Makefile to use this code. + Cleaned out a commented-out printf in maskwallscan(). Moved + New static flag in engine.c: initengine_called is set when + (surprise) initengine() is called. This is currently just used + with the MMX overlay code...now dommxoverlay is no longer exposed; + use setmmxoverlay() and getmmxoverlay() instead. Updated + build2.txt with this information. Removed global var: cachedebug + in engine.c, and put #define BUILD_CACHEDEBUG 0 at the top of the + source. Flip it to 1 if you ever need to tinker in the cache code. + Removed krecip() from engine.c, since nothing uses it (it just + wrapped krecipasm(), which IS used all over the place). + Other cleanups were made, along with update in build.txt. Lots of + code was touched in ways not appropriate to mention in polite + company. +05232001 - Added lookup.dat support code, thanks to TerminX's help. Changed + initgroupfile() to not exit() if the groupfile won't open(). + instead, we check for failed return values in ExtInit() (bstub.c), + like we should have done from the start. Added check in ExtInit() + for the environment variable BUILD_GROUPFILE, which will be the + groupfile to open if the variable exists. If the variable isn't + set, we default to Ken's "stuff.dat". Between this and TerminX's + lookup.dat code, we should be able to wander around a Duke3D map + without segfaults all over the place. Changed initgroupfile() and + kopen4load() to take a (const char *) argument. Should probably + show some diligence in adding this elsewhere, too, for the sake + of cleanliness and bughunting. Added some more function + declarations to engine.h. Updated README with new info on + Mapster and Duke3D. +05262001 - Finally unearthed a copy of Watcom 11.0! Fixed up all the GNU + inline asm so that the Watcom preprocessor wouldn't puke on it, + and built new win32 binaries...apparently Watcom 11, unlike 10.6, + can make a PE header that WinNT and Win2000 will accept. Moved the + Win32 version up to SDL 1.2.0 from SDL-1.1.8, and added a Watcom + __cdecl pragma in display.h for SDL_VideoDriverName(). Updated + TODO. +05272001 - Added engine.h to dos_drvr.c to get the DOS binaries to compile. + Added README and CHANGELOG to the win32 and dos bin distros, and + updated README-dosbins.txt and README-win32bins.txt. Updated + README with info on Watcom 10 vs 11, porting to new OSes, etc. + Updated TODO, AGAIN. :) Wrote a hopefully-robust function that + toggles the screen surface between windowed and full screen + without using SDL_WM_ToggleFullScreen(), so that you can use + ALT-Enter on Win32. Accordingly, removed references to + SDL_WM_ToggleFullScreen() in display.h and sdl_driver.c ... + The new fullscreen toggle code throws up on Windows if you destroy + the window (via SDL_SetVideoMode()) while in the middle of + handling one of its events...we were processing all events via the + SDL event filter during the SDL_PumpEvents() call. I've added + handle_events() to sdl_driver.c, and replaced all the PumpEvents + calls with that. This gets its events via SDL_PollEvent(), and + passes them on to our filter manually. That's just generally better + practice anyhow. Put hardcoded environment variables in + sdl_driver.c into constants. Hall of mirror debugging, and all the + BUILDSDL output to stderr is now all compiled in, and trigged by + the existence of the BUILD_SDLDEBUG environment variable. Build + now always claims to have standard resolutions (up to the largest + your system claims to handle) available, and SDL will fake it if + they aren't there. This should fix the Win32 F4 problem, and + people without other modelines listed in their XF86Config. Also, + by setting the environment variable BUILD_SCREENRES, you can add + one window of any dimension to the list. For example, + "export BUILD_SCREENRES=666x666". +05282001 - Added a maximum screen resolution of 1600x1200. This can be raised + or lowered with an environment variable: export + BUILD_MAXSCREENRES=1024x768, if you like. Renamed + BUILD_NO_MOUSE_GRAB to BUILD_NOMOUSEGRAB for consistency. Renamed + BUILD_SCREENRES to BUILD_USERSCREENRES. Rewrote the spaghetti that + all this resolution management code had quickly become. The fight + with attempt_fullscreen_toggle() continues: gave up, and just + called setbrightness() to fix the palettes. Now tries to use + SDL_WM_ToggleFullscreen() first before doing it The Hard Way, and + just returns if there's no window manager reported by + SDL_GetVideoInfo->wm_available. All the debugging output (of which + there is still more added today) has been cleaned up and is + passed through a function called sdldebug() that is used like + fprintf(stderr), but adds the "BUILDSDL: " string to the front, + a newline to the end, and prints nothing if debugging is disabled. + TODO is, as usual, expanding. Added BUILD_HALLOFMIRRORS environment + var, so that it isn't bound to BUILD_SDLDEBUG anymore. The + BUILD_SDLDEBUG variable now needs a value: the file to write debug + information to. The value can be "-" to write to stdout. This is + for that obnoxious win32 platform. :) +05292001 - Added a hack for Windows systems using the "windib" driver. + Apparently windib has no way to distinguish between the return key + and the keypad enter, and they both come up as the former. Now, if + you hold down SHIFT while hitting either return or the keypad + enter, sdl_driver.c reports to the engine that the keypad enter + was pressed. Now I can get into 3D mode on WinNT 4.0. :) +05302001 - More toggle_fulscreen work. Check to see if the debug output file + was opened, and printf() a warning if not. setbuf(..., NULL) was + no longer called on stderr and stdout in sdl_driver.c's version + of _platform_init(), but the buffer is set to NULL for the debug + file now, which may or may not be stdout. Just for a goof, I added + vmWare virtual machine detection code, which returns false in the + portable C version, and does some lowlevel voodoo in i386 asm. +06012001 - Added sdldebug() output to list the version of SDL we compiled + against, and the version we are linked (dynamically) against. +06082001 - It's Neurotic Cleanup Day! Started putting support for compiling + with Visual C in place, and found how anal their anal settings + can be (does this beat -ansi -pendantic on Linux? Probably not.). + Converted all the "//" comments to "/*" (ugh), and added explicit + casting where needed. Replaced references to "long long" with + "__int64", which is #defined appropriately in the compat headers. + Now compiling the codebase with -ansi and -pendantic on Linux and + Cygwin. Changed PORTSIG in build.h. Moved the sound stubs out of + sdl_driver.c and into a #ifndef PLATFORM_DOS block in game.c; it's + KenBuild-specific, and I'm not interested in implementing it + cleanly, or at all, for non-DOS platforms. Cleaned up rest of + the forward references in game.c and build.c. Cleaned up the + OpenGL debugging output (it's now unified with the sdldebug() + code). Renamed a_linux.asm to a_nasm.asm, since it's used on Linux + and Windows (and probably everywhere else that there's an x86 + system that isn't using Watcom). Implemented stricmp() on unix + (damned -ansi flag). Updated TODO and README. Changed the display + driver function _initkeys into initkeys. This will force a link + error in Build games, so they can be updated to call the driver's + init function; updated this in build.txt, too. +06122001 - Made mmulti.c compile with -ansi and -pedantic, as that might be + needed later. Testing the OpenGL waters again. Added string_dupe() + to replace strdup(), and changed a snprintf() call to sprintf() in + sdl_driver.c, so I could remove the _GNU_SOURCE define. +06132001 - Changed Unix makefile, so that you can (by setting usedlls=true) + compile buildengine.so and buildnet.so, and the game and build + binaries only statically link what is absolutely necessary. Setting + usedlls=false statically links all the Build code together, + although currently external libraries like SDL are still + linked dynamically. Platform drivers now need to store _argv and + _argc. Commented a few functions in engine.c as I start to grok + what each bit of code does. +06232001 - Cleaned up some whitespace issues in pragmas.c. The one SDL + dependency in engine.c has been abstracted into + _updateScreenRect() and implemented in the display drivers. + OpenGL should now always be compiled in unless you can't even + build it (and thus, I've officially flipped useopengl to "true" + in the Makefile). You can now choose your renderer at runtime by + setting the BUILD_RENDERER environment variable: Set it to + "software" for the usual drill, "opengl2d" for using OpenGL to + move the software-rendered framebuffer to the screen (got this + idea from zsnes. cool.), and "opengl3d" to try to render an actual + 3D scene in OpenGL. Default is "software". The 3D stuff hasn't + even been started, since it'll need an actual implementation in + engine.c. The gl2D stuff is an hour's work. After the 3D + implementation is in there, I'll be adding Makefile flags and code + #ifdefs to prevent compilation of the software renderer, which + will end the need for most, if not all, of the assembly, and get + us running on different platforms. I know, easier said than done. + Other little cleanups and enhancements. +06242001 - Followed through on my threat, and split off most of the OpenGL + code into buildgl.c. :) Added more GL func pointers, and tried + (failingly) to get OpenGL2D more working. It's way too slow; + I guess all that conversion from 8-bit, through the lookup tables, + to 32-bit, back to whatever the screen depth is, etc is expensive. + Looks like it's just software rendering and full 3D. Sigh. + More SDL cleanups. (committed on Aug 1st). +07082001 - Implemented support for PhysicsFS in cache1d.c; this allows you to + replace your GRP file with a compressed ZIP file. This is optional, + since it's an extra dependency. PhysicsFS is another one of my + projects, and information and source for it can be found at: + http://www.icculus.org/physfs/ ... (committed on Aug 1st). +07162001 - Moved CVS repository to icculus.org. Updated README. +08012001 - Committed some stuff, fixed a bug in the PhysicsFS code. Flipped + the useopengl flag in the Makefile back to false for now. Added + PhysicsFS info to README. Changed all occurances of my email + address from linuxgames.com to clutteredmind.org. +08232001 - Moved a.c to a_gnu.c and pragmas.c to pragmas_gnu.c. Added + pragmas_visual.c and a_visualc.c, and got everything compiling on + Visual C. Added VisualC.zip. Unzip it and use those files to build + with Visual C. Updated Makefiles, READMEs, etc with the new + *_[gnu|visualc]* files. Cleanups elsewhere. Added a "distclean" + target which just calls "clean". The Visual C project doesn't work + right now; I gave up on it. +06232001 - Fixed a hang when lotagging a wall (closing bugzilla bug #25). + +--ryan. (icculus@clutteredmind.org) + +/* end of CHANGELOG ... */ + diff --git a/buildengine/CONTRIB b/buildengine/CONTRIB new file mode 100755 index 0000000..148b70a --- /dev/null +++ b/buildengine/CONTRIB @@ -0,0 +1,17 @@ +// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman +// Ken Silverman's official web site: "http://www.advsys.net/ken" +// See the included license file "BUILDLIC.TXT" for license info. + +Ryan C. Gordon +Dan Olson +Andrew Henderson +Christian Zander +Adrian Neill +Matt Helsley +Nicholas Vining +Matt Saettler +Steven Fuller + + +Others I've probably forgotten (sorry! email me if you should be here. --ryan.) + diff --git a/buildengine/Engine.dsp b/buildengine/Engine.dsp new file mode 100755 index 0000000..7024691 --- /dev/null +++ b/buildengine/Engine.dsp @@ -0,0 +1,198 @@ +# Microsoft Developer Studio Project File - Name="Engine" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=Engine - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "Engine.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "Engine.mak" CFG="Engine - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Engine - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "Engine - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Engine - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "ReleaseVC6" +# PROP Intermediate_Dir "ReleaseVC6" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /GX /Ot /Ow /Oi /Op /Oy /Ob1 /I "SDL-1.2.5\include" /D "_LIB" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "USE_I386_ASM" /D "PLATFORM_WIN32" /D "UDP_NETWORKING" /YX /J /FD /c +# SUBTRACT CPP /Oa /Og /Os +# ADD BASE RSC /l 0xc09 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "Engine - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "DebugVC6" +# PROP Intermediate_Dir "DebugVC6" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /Gm /GX /ZI /Od /I "SDL-1.2.5\include" /D "_LIB" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "USE_I386_ASM" /D "PLATFORM_WIN32" /D "UDP_NETWORKING" /FR /YX /J /FD /GZ /c +# ADD BASE RSC /l 0xc09 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "Engine - Win32 Release" +# Name "Engine - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=a_nasm.asm + +!IF "$(CFG)" == "Engine - Win32 Release" + +# Begin Custom Build +TargetDir=.\ReleaseVC6 +InputPath=a_nasm.asm + +"$(TargetDir)\a_nasm.obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + nasmw.exe -f win32 -DC_IDENTIFIERS_UNDERSCORED -o $(TargetDir)\a_nasm.obj $(InputPath) + +# End Custom Build + +!ELSEIF "$(CFG)" == "Engine - Win32 Debug" + +# Begin Custom Build +TargetDir=.\DebugVC6 +InputPath=a_nasm.asm + +"$(TargetDir)\a_nasm.obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + nasmw.exe -f win32 -DC_IDENTIFIERS_UNDERSCORED -o $(TargetDir)\a_nasm.obj $(InputPath) + +# End Custom Build + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=.\a_visualc.c +# End Source File +# Begin Source File + +SOURCE=.\cache1d.c +# End Source File +# Begin Source File + +SOURCE=.\engine.c +# End Source File +# Begin Source File + +SOURCE=.\mmulti.c +# End Source File +# Begin Source File + +SOURCE=.\pragmas.c +# End Source File +# Begin Source File + +SOURCE=.\sdl_driver.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\a.h +# End Source File +# Begin Source File + +SOURCE=.\bstub.h +# End Source File +# Begin Source File + +SOURCE=.\build.h +# End Source File +# Begin Source File + +SOURCE=.\buildgl.h +# End Source File +# Begin Source File + +SOURCE=.\buildperl.h +# End Source File +# Begin Source File + +SOURCE=.\cache1d.h +# End Source File +# Begin Source File + +SOURCE=.\display.h +# End Source File +# Begin Source File + +SOURCE=.\engine.h +# End Source File +# Begin Source File + +SOURCE=.\names.h +# End Source File +# Begin Source File + +SOURCE=.\platform.h +# End Source File +# Begin Source File + +SOURCE=.\pragmas.h +# End Source File +# Begin Source File + +SOURCE=.\ves2.h +# End Source File +# Begin Source File + +SOURCE=.\win32_compat.h +# End Source File +# End Group +# End Target +# End Project diff --git a/buildengine/Engine.vcproj b/buildengine/Engine.vcproj new file mode 100755 index 0000000..14e6483 --- /dev/null +++ b/buildengine/Engine.vcproj @@ -0,0 +1,200 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/buildengine/FILEID.DIZ b/buildengine/FILEID.DIZ new file mode 100755 index 0000000..00877c9 --- /dev/null +++ b/buildengine/FILEID.DIZ @@ -0,0 +1,13 @@ +// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman +// Ken Silverman's official web site: "http://www.advsys.net/ken" +// See the included license file "BUILDLIC.TXT" for license info. + +Port of BUILD engine from Ken Silverman's original DOS386 codebase to Linux +and Win32. BUILD is the engine that powers games like Duke Nukem 3D, Blood, +Shadow Warrior, Redneck Rampage, and others. + +Please read the included README for all the dirty details. + +--ryan. (icculus@clutteredmind.org) + + diff --git a/buildengine/Makefile b/buildengine/Makefile new file mode 100755 index 0000000..e666310 --- /dev/null +++ b/buildengine/Makefile @@ -0,0 +1,337 @@ + +# Makefile for building BUILD on Unix/Cygwin systems. +# +# Written by Ryan C. Gordon (icculus@clutteredmind.org) +# Do NOT contact Ken Silverman for support of BUILD on Unix or Linux. +#---------------------------------------------------------------------------- + +linux_ppc := false +beos := false +macosx := false +freebsd := false +solaris := false +linux64 := false + +#-----------------------------------------------------------------------------# +# If this makefile fails to detect Cygwin correctly, or you want to force +# the build process's behaviour, set it to "true" or "false" (w/o quotes). +#-----------------------------------------------------------------------------# +#cygwin := true +#cygwin := false +cygwin := autodetect + +#-----------------------------------------------------------------------------# +# You only need to set SDL_INC_DIR and SDL_LIB_DIR if you are using cygwin. +# SDL_INC_DIR is where SDL.h and associated headers can be found, and +# SDL_LIB_DIR is where SDL.lib and SDL.dll are located. These may be set as +# environment variables, if you'd prefer to not hack the Makefile. +# +# examples: +# SDL_INC_DIR := C:/2/SDL-1.1.8/include +# SDL_LIB_DIR := C:/2/SDL-1.1.8/lib +#-----------------------------------------------------------------------------# +ifeq ($(strip $(SDL_INC_DIR)),) + SDL_INC_DIR := please_set_me_cygwin_users +endif + +ifeq ($(strip $(SDL_LIB_DIR)),) + SDL_LIB_DIR := please_set_me_cygwin_users +endif + +CC = gcc +LINKER = gcc + +#-----------------------------------------------------------------------------# +# To use a different platform's ASM or portable C, change this. +#-----------------------------------------------------------------------------# +#USE_ASM := -DUSE_I386_ASM + + +#-----------------------------------------------------------------------------# +# Don't touch this unless you know what you are doing. +#-----------------------------------------------------------------------------# +#useperl := true +useperl := false + +#useopengl := true +useopengl := false +GL_INCLDIR := /usr/X11R6/include + +#usedlls := true +usedlls := false + +#usephysfs := true +usephysfs := false + +#networking := stubbed +networking := udp + + +#-----------------------------------------------------------------------------# +# Everything below this line is probably okay. +#-----------------------------------------------------------------------------# + +# been told this doesn't work on BeOS right now... +ifeq ($(strip $(beos)),true) + networking := stubbed + USE_ASM := +endif + +CFLAGS += -m32 +LDFLAGS +=-m32 -L/usr/lib + + +ifeq ($(strip $(solaris)),true) + LINKER= cc + CC = cc + LDFLAGS += -lsocket -lnsl + CFLAGS += -DPLATFORM_SOLARIS +endif + +ifeq ($(strip $(cygwin)),autodetect) + ifneq ($(strip $(shell gcc -v 2>&1 |grep "cygwin")),) + cygwin := true + else + cygwin := false + endif +endif + + +ifeq ($(strip $(cygwin)),true) + # (no choice on Cygwin right now...) + usedlls := false + + ifeq ($(strip $(SDL_INC_DIR)),please_set_me_cygwin_users) + $(error Cygwin users need to set the SDL_INC_DIR envr var.) + else + SDL_CFLAGS := -I$(SDL_INC_DIR) + endif + + ifeq ($(strip $(SDL_LIB_DIR)),please_set_me_cygwin_users) + $(error Cygwin users need to set the SDL_LIB_DIR envr var.) + else + SDL_LDFLAGS := -L$(SDL_LIB_DIR) -lSDL + endif +else + ifneq ($(strip $(freebsd)),true) + SDL_CFLAGS := $(shell /usr/bin/32/sdl-config --cflags) + SDL_LDFLAGS := $(shell /usr/bin/32/sdl-config --libs) + endif +endif + +# Uncomment to use the Intel compiler (v6.0) +# Note: Version 6.0 Build 020312Z fails to compile engine.c +#CC = icc +#CFLAGS = -g $(SDL_CFLAGS) -DUSE_SDL=1 -O2 + +ifeq ($(strip $(cygwin)),true) + ASM = nasmw + DLL_EXT = .dll + EXE_EXT = .exe + ASMOBJFMT = win32 + ASMDEFS = -dC_IDENTIFIERS_UNDERSCORED + CFLAGS += -DC_IDENTIFIERS_UNDERSCORED +else + ASM = nasm + DLL_EXT = .so + EXE_EXT = + ASMOBJFMT = elf +endif + +ifeq ($(strip $(macosx)),true) + CFLAGS += -DPLATFORM_MACOSX=1 -faltivec -mdynamic-no-pic -falign-loops=32 -falign-functions=32 + LDFLAGS += -framework AppKit -lSDL -lSDLmain +endif + +ifeq ($(strip $(freebsd)),true) + CFLAGS += -DPLATFORM_FREEBSD=1 + SDL_CFLAGS := $(shell sdl11-config --cflags) + SDL_LDFLAGS := $(shell sdl11-config --libs) -L. +endif + +ifeq ($(strip $(linux_ppc)),true) + CFLAGS += -DPLATFORM_LINUXPPC=1 +endif + +ifeq ($(strip $(useopengl)),true) + CFLAGS += -DUSE_OPENGL -I$(GL_INCLDIR) +endif + +ifeq ($(strip $(useperl)),true) + CFLAGS += -DUSE_PERL + LDPERL := $(shell perl -MExtUtils::Embed -e ldopts) + CCPERL := $(shell perl -MExtUtils::Embed -e ccopts) + # !!! can I lose the explicit path somehow? + PERLOBJS += buildperl.o /usr/lib/perl5/i386-linux/CORE/libperl.a +endif + +ifeq ($(strip $(usephysfs)),true) + CFLAGS += -DUSE_PHYSICSFS + LDFLAGS += -lphysfs +endif + +ifeq ($(strip $(usedlls)),true) +ENGINEBASE = buildengine +ENGINEDLL = $(strip $(ENGINEBASE))$(strip $(DLL_EXT)) +NETBASE = buildnet +NETDLL = $(strip $(NETBASE))$(strip $(DLL_EXT)) +endif + +ifeq ($(strip $(networking)),stubbed) + CFLAGS += -DSTUB_NETWORKING=1 +endif + +ifeq ($(strip $(networking)),udp) + CFLAGS += -DUDP_NETWORKING=1 +endif + +# fixes code generation bug. +ifeq ($(strip $(beos)),true) + CFLAGS += -no-fpic +endif + +ENGINESRCS = engine.c cache1d.c sdl_driver.c unix_compat.c +ifeq ($(strip $(USE_ASM)),-DUSE_I386_ASM) +ENGINESRCS += a_nasm.asm pragmas.c a_gnu.c +else +ENGINESRCS += a.c pragmas.c +endif + +ifeq ($(strip $(useopengl)),true) +ENGINESRCS += buildgl.c +endif + + +NETSRCS = mmulti.c + +GAMEEXE = game +GAMESRCS = game.c +#GAMESRCS += multi.c k.asm kdmeng.c +ifneq ($(strip $(usedlls)),true) +GAMESRCS += $(ENGINESRCS) +GAMESRCS += $(NETSRCS) +endif + +BUILDEXE = build +BUILDSRCS = build.c bstub.c +ifneq ($(strip $(usedlls)),true) +BUILDSRCS += $(ENGINESRCS) +endif + + +ENGINEDIR = . +ASMFLAGS = -f $(ASMOBJFMT) $(ASMDEFS) +CFLAGS += $(USE_ASM) -DPLATFORM_UNIX -g $(SDL_CFLAGS) +LDFLAGS += -g $(SDL_LDFLAGS) + +ifeq ($(strip $(solaris)),true) +CFLAGS += -xO5 -xchar=u +else +# Always turn OFF strict aliasing, even when optimizing. Otherwise, this is +# just an accident waiting to happen... --ryan. +CFLAGS += -fno-strict-aliasing +CFLAGS += -fno-omit-frame-pointer -Wall -O3 -funsigned-char +endif + +# Rules for turning source files into .o files +%.o: %.c + $(CC) -c -o $@ $< $(CFLAGS) + +%.o: %.asm + $(ASM) $(ASMFLAGS) -o $@ $< + +# Rule for getting list of objects from source +ENGINEOBJS1 := $(ENGINESRCS:.c=.o) +ENGINEOBJS := $(ENGINEOBJS1:.asm=.o) +NETOBJS1 := $(NETSRCS:.c=.o) +NETOBJS := $(NETOBJS1:.asm=.o) +GAMEOBJS1 := $(GAMESRCS:.c=.o) +GAMEOBJS := $(GAMEOBJS1:.asm=.o) +BUILDOBJS1 := $(BUILDSRCS:.c=.o) +BUILDOBJS := $(BUILDOBJS1:.asm=.o) + +CLEANUP = $(GAMEOBJS) $(BUILDOBJS) $(PERLOBJS) $(NETOBJS) \ + $(GAMEEXE) $(BUILDEXE) $(ENGINEOBJS) $(ENGINEDLL) \ + $(wildcard *.exe) $(wildcard *.obj) \ + $(wildcard *~) $(wildcard *.err) \ + $(wildcard .\#*) core + +all: $(BUILDEXE) $(GAMEEXE) + +ifeq ($(strip $(useperl)),true) +buildperl.o : buildperl.c + $(CC) -c -o $@ $< $(CFLAGS) $(CCPERL) +endif + +ifeq ($(strip $(usedlls)),true) +$(ENGINEDLL) : $(ENGINEOBJS) + $(LINKER) -shared -o $(ENGINEDLL) $(LDFLAGS) $(ENGINEOBJS) + +$(NETDLL) : $(NETOBJS) + $(LINKER) -shared -o $(NETDLL) $(LDFLAGS) $(NETOBJS) +endif + +$(GAMEEXE) : $(ENGINEDLL) $(NETDLL) $(GAMEOBJS) $(PERLOBJS) + $(LINKER) -o $(GAMEEXE) $(LDFLAGS) $(LDPERL) $(PERLOBJS) $(GAMEOBJS) $(ENGINEDLL) $(NETDLL) + +$(BUILDEXE) : $(ENGINEDLL) $(BUILDOBJS) + $(LINKER) -o $(BUILDEXE) $(LDFLAGS) $(BUILDOBJS) $(ENGINEDLL) + +listclean: + @echo "A 'make clean' would remove" $(CLEANUP) + +distclean: clean + +clean: + rm -f $(CLEANUP) + + +#-----------------------------------------------------------------------------# +# This section is pretty much just for Ryan's use to make distributions. +# You Probably Should Not Touch. +#-----------------------------------------------------------------------------# + +# These are the files needed in a binary distribution, regardless of what +# platform is being used. +BINSCOMMON = build$(strip $(EXE_EXT)) game$(strip $(EXE_EXT)) +BINSCOMMON += ascboard.map boards.map evilal.map kensig.map nsnoal.map +BINSCOMMON += test.map nukeland.map +BINSCOMMON += stuff.dat +BINSCOMMON += BUILDLIC.TXT +BINSCOMMON += names.h + + +package: clean + cd .. ; zip -9rz ./BUILD-engine-$(shell date +%m%d%Y).zip buildengine -x "*CVS*" < buildengine/FILEID.DIZ + + +ifeq ($(strip $(cygwin)),true) +msbins: win32bins dosbins + +win32bins: + wmake -f Makefile.w32 clean + wmake -f Makefile.w32 + cp $(SDL_LIB_DIR)/SDL.dll . + echo -e "\r\n\r\n\r\nHEY YOU.\r\n\r\n\r\nTake a look at README-win32bins.txt FIRST.\r\n\r\n\r\n--ryan. (icculus@clutteredmind.org)\r\n\r\n" |zip -9rz ../BUILD-win32bins-$(shell date +%m%d%Y).zip $(BINSCOMMON) SDL.dll README-win32bins.txt README CHANGELOG + +dosbins: + wmake -f Makefile.dos clean + wmake -f Makefile.dos + cp C:/WATCOM/BINW/DOS4GW.EXE . + echo -e "\r\n\r\n\r\nHEY YOU.\r\n\r\n\r\nTake a look at README-dosbins.txt FIRST.\r\n\r\n\r\n--ryan. (icculus@clutteredmind.org)\r\n\r\n" |zip -9rz ../BUILD-dosbins-$(shell date +%m%d%Y).zip $(BINSCOMMON) README-dosbins.txt README CHANGELOG DOS4GW.EXE + +else +msbins: nocygwin +win32bins: nocygwin +dosbins: nocygwin +endif + +nocygwin: + @echo This must be done on a Windows box in the Cygwin environment. + +#-----------------------------------------------------------------------------# +# End packaging section. +#-----------------------------------------------------------------------------# + +# end of Makefile ... + diff --git a/buildengine/Makefile.dos b/buildengine/Makefile.dos new file mode 100755 index 0000000..b2830b3 --- /dev/null +++ b/buildengine/Makefile.dos @@ -0,0 +1,120 @@ +#-----------------------------------------------------------------------------# +# Makefile for Watcom C 10.6 compilation for DOS i386 protected mode target. +# +# Written by Ryan C. Gordon. (icculus@clutteredmind.org) +# +# PLEASE FOLLOW ALL THE INSTRUCTIONS BEFORE BUILDING. +#-----------------------------------------------------------------------------# + +#-----------------------------------------------------------------------------# +# Don't touch this '!define BLANK ""' line. +#-----------------------------------------------------------------------------# +!define BLANK "" + +#-----------------------------------------------------------------------------# +# Directory where Watcom C is installed. Should have an "h" child directory, +# so if you specify "C:\WATCOM", there should be a "C:\WATCOM\h" directory +# on your drive. DON'T ADD THE TRAILING '\' CHARACTER! +#-----------------------------------------------------------------------------# +WATCOMDIR = C:\WATCOM + +#-----------------------------------------------------------------------------# +# When debugging, use "-d2", otherwise use the blank line. +#-----------------------------------------------------------------------------# +#DEBUGFLAGS = -d2 +DEBUGFLAGS = + +#-----------------------------------------------------------------------------# +# When debugging, use "d all", otherwise use the "op el" line. +#-----------------------------------------------------------------------------# +#LINKDEBUGFLAGS = d all +LINKDEBUGFLAGS = op el + +#-----------------------------------------------------------------------------# +# Choose one, or mix and match. Releases should use the full line, +# debug builds should probably use the blank one. +#-----------------------------------------------------------------------------# +#OPTIMIZEFLAGS = +OPTIMIZEFLAGS = -oa -oe -of+ -ol -ol+ -om -oc -oi -or -otexan + + +#-----------------------------------------------------------------------------# +# Okay, you're done. Save this file and run "wmake -f Makefile.dos" ... +#-----------------------------------------------------------------------------# + + + +#-----------------------------------------------------------------------------# +#-----------------------------------------------------------------------------# +# Don't touch anything below this line, unless you know what you're doing. +#-----------------------------------------------------------------------------# +#-----------------------------------------------------------------------------# + +LINKSYS=dos4g + +WATCOM_INC_DIR = $(WATCOMDIR)\h + +INCLUDES = -i=$(WATCOM_INC_DIR) +DEFINES = -dUSE_I386_ASM -dPLATFORM_DOS + +CFLAGS = $(INCLUDES) $(DEFINES) -w4 -we -e25 -ei -zq & + $(OPTIMIZEFLAGS) $(DEBUGFLAGS) -5r -bt=dos -mf +ASMFLAGS = $(INCLUDES) -mf -5r -w4 -we -e25 -zq + +CC = wcc386.exe +ASM = wasm.exe + +BUILDOBJS = a.obj bstub.obj build.obj cache1d.obj engine.obj & + multi_tcpip.obj dos_drvr.obj +GAMEOBJS = a.obj game.obj cache1d.obj engine.obj multi_tcpip.obj & + dos_drvr.obj kdmeng.obj k.obj + +BUILDOBJS_COMMAS = a.obj,bstub.obj,build.obj,cache1d.obj,engine.obj,multi_tcpip.obj,dos_drvr.obj +GAMEOBJS_COMMAS = a.obj,game.obj,cache1d.obj,engine.obj,multi_tcpip.obj,dos_drvr.obj,kdmeng.obj,k.obj + +all : project .SYMBOLIC + +project : build.exe game.exe .SYMBOLIC + +clean : .SYMBOLIC + erase *.obj + erase *.exe + erase *.o + erase *~ + +.asm.obj : .AUTODEPEND + *$(ASM) $[* $(ASMFLAGS) + +.c.obj : .AUTODEPEND + *$(CC) $[* $(CFLAGS) + +build.exe : $(BUILDOBJS) .AUTODEPEND + @%write build.lk1 NAME build + @%append build.lk1 FIL $(BUILDOBJS_COMMAS) + @%append build.lk1 +!ifneq BLANK "" + *wlib -q -n -b build.imp + @%append build.lk1 LIBR build.imp +!endif + *wlink $(LINKDEBUGFLAGS) SYS $(LINKSYS) op c op maxe=25 op q @build.lk1 + erase build.lk1 +!ifneq BLANK "" + wrc -q -ad -t build.exe +!endif + +game.exe : $(GAMEOBJS) .AUTODEPEND + @%write game.lk1 NAME game + @%append game.lk1 FIL $(GAMEOBJS_COMMAS) + @%append game.lk1 +!ifneq BLANK "" + *wlib -q -n -b game.imp + @%append game.lk1 LIBR game.imp +!endif + *wlink $(LINKDEBUGFLAGS) SYS $(LINKSYS) op c op maxe=25 op q @game.lk1 + erase game.lk1 +!ifneq BLANK "" + wrc -q -ad -t game.exe +!endif + +# end of Makefile.w32 ... + diff --git a/buildengine/Makefile.w32 b/buildengine/Makefile.w32 new file mode 100755 index 0000000..c64641f --- /dev/null +++ b/buildengine/Makefile.w32 @@ -0,0 +1,136 @@ +#-----------------------------------------------------------------------------# +# Makefile for creating Build with Watcom C for win32. +# +# Written by Ryan C. Gordon. (icculus@clutteredmind.org) +# +# PLEASE FOLLOW ALL THE INSTRUCTIONS BEFORE BUILDING. +#-----------------------------------------------------------------------------# + +#-----------------------------------------------------------------------------# +# Don't touch this '!define BLANK ""' line. +#-----------------------------------------------------------------------------# +!define BLANK "" + +#-----------------------------------------------------------------------------# +# Directory where Watcom C is installed. Should have an "h" child directory, +# so if you specify "C:\WATCOM", there should be a "C:\WATCOM\h" directory +# on your drive. DON'T ADD THE TRAILING '\' CHARACTER! +#-----------------------------------------------------------------------------# +WATCOMDIR = C:\WATCOM + +#-----------------------------------------------------------------------------# +# Directory where Simple Directmedia Layer (SDL) is installed. SDL can be +# downloaded from http://www.libsdl.org/. There should be "include" and "lib" +# child directories, so if you specify "C:\SDL-1.1.8", there should be +# C:\SDL-1.1.8\lib" and "C:\SDL-1.1.8\include" directories on your drive. +# DON'T ADD THE TRAILING '\' CHARACTER! +#-----------------------------------------------------------------------------# +SDLDIR = C:\SDL-1.2.0 + + +#-----------------------------------------------------------------------------# +# When debugging, use "d all", otherwise use the "op el" line. +#-----------------------------------------------------------------------------# +#LINKDEBUGFLAGS = d all +LINKDEBUGFLAGS = op el + + +#-----------------------------------------------------------------------------# +# Choose one, or mix and match. Releases should use the full line, +# debug builds should probably use the blank one. +#-----------------------------------------------------------------------------# +#OPTIMIZEFLAGS = +OPTIMIZEFLAGS = -oa -oe -of+ -ol -ol+ -om -oc -oi -or -otexan + +#-----------------------------------------------------------------------------# +# Set this to "nt" to create a console window for viewing stdio output +# along with the usual graphical windows. This is for debugging only. +# Set it to nt_win to just get the graphical windows. This is for release +# builds. +#-----------------------------------------------------------------------------# +#LINKSYS=nt +LINKSYS=nt_win + + +#-----------------------------------------------------------------------------# +# Okay, you're done. Save this file and run "wmake -f Makefile.w32" ... +#-----------------------------------------------------------------------------# + + + +#-----------------------------------------------------------------------------# +#-----------------------------------------------------------------------------# +# Don't touch anything below this line, unless you know what you're doing. +#-----------------------------------------------------------------------------# +#-----------------------------------------------------------------------------# + +WATCOM_INC_DIR = $(WATCOMDIR)\h;$(WATCOMDIR)\h\nt +SDL_INC_DIR = $(SDLDIR)\include +SDL_LIB_DIR = $(SDLDIR)\lib + +INCLUDES = -i=$(WATCOM_INC_DIR);$(SDL_INC_DIR) +DEFINES = -dUSE_I386_ASM -dPLATFORM_WIN32 + +CFLAGS = $(INCLUDES) $(DEFINES) -w4 -we -e25 -ei -zq & + $(OPTIMIZEFLAGS) $(DEBUGFLAGS) -bm -5r -bt=nt -mf +ASMFLAGS = $(INCLUDES) -mf -5r -w4 -we -e25 -zq + +CC = wcc386.exe +ASM = wasm.exe + +BUILDOBJS = a.obj bstub.obj build.obj cache1d.obj engine.obj & + multi_tcpip.obj sdl_driver.obj +GAMEOBJS = a.obj game.obj cache1d.obj engine.obj multi_tcpip.obj & + sdl_driver.obj + +BUILDOBJS_COMMAS = a.obj,bstub.obj,build.obj,cache1d.obj,engine.obj,multi_tcpip.obj,sdl_driver.obj +GAMEOBJS_COMMAS = a.obj,game.obj,cache1d.obj,engine.obj,multi_tcpip.obj,sdl_driver.obj + +all : project .SYMBOLIC + +project : build.exe game.exe .SYMBOLIC + +clean : .SYMBOLIC + erase *.obj + erase *.exe + erase *.o + erase *~ + +.asm.obj : .AUTODEPEND + *$(ASM) $[* $(ASMFLAGS) + +.c.obj : .AUTODEPEND + *$(CC) $[* $(CFLAGS) + +build.exe : $(BUILDOBJS) .AUTODEPEND + @%write build.lk1 NAME build + @%append build.lk1 FIL $(BUILDOBJS_COMMAS) + @%append build.lk1 +!ifneq BLANK "" + *wlib -q -n -b build.imp + @%append build.lk1 LIBR build.imp +!endif + *wlink $(LINKDEBUGFLAGS) SYS $(LINKSYS) libp $(SDL_LIB_DIR) libf SDL.lib & +$(LINKDEBUGFLAGS) op c op maxe=25 op q @build.lk1 + erase build.lk1 +!ifneq BLANK "" + wrc -q -ad -t build.exe +!endif + +game.exe : $(GAMEOBJS) .AUTODEPEND + @%write game.lk1 NAME game + @%append game.lk1 FIL $(GAMEOBJS_COMMAS) + @%append game.lk1 +!ifneq BLANK "" + *wlib -q -n -b game.imp + @%append game.lk1 LIBR game.imp +!endif + *wlink $(LINKDEBUGFLAGS) SYS $(LINKSYS) libp $(SDL_LIB_DIR) libf SDL.lib & +$(LINKDEBUGFLAGS) op c op maxe=25 op q @game.lk1 + erase game.lk1 +!ifneq BLANK "" + wrc -q -ad -t game.exe +!endif + +# end of Makefile.w32 ... + diff --git a/buildengine/README b/buildengine/README new file mode 100755 index 0000000..d153e67 --- /dev/null +++ b/buildengine/README @@ -0,0 +1,249 @@ +// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman +// Ken Silverman's official web site: "http://www.advsys.net/ken" +// See the included license file "BUILDLIC.TXT" for license info. + +/* + * README. + * + * Please do NOT harrass Ken Silverman about any code modifications + * (including this file) to BUILD. + */ + +(This code DOES run on Windows. Read on.) + +For building on Linux, you NEED gcc 2.95.2 (or maybe later) to compile this +code correctly. You'll also need Netwide Assembler (NASM). Get it at: + + http://www.kernel.org/pub/software/devel/nasm/ + + +(May I reiterate? Earlier than 2.95.2 revisions of GCC and EGCS do NOT +compile this code correctly! It will run, but there will be all sorts of +strange graphic glitches and odd crashes.) + + +For building on Win32, you need Watcom C v11.0. With the Win32 target (Perhaps +they call it the "NT" target?) installed. You can maybe get by with Watcom C +version 10.x, but the binaries tend not to work on WinNT in that case. You +can also compile the code on Win32 with Cygwin and NASM. Read below for more +details in either case. + + +For building under DOS, you need Watcom C v11 or v10 with the DOS target +installed. + + +This code uses Simple Directmedia Layer (SDL) for graphics, sound, and other +platform abstractions. Build relies on a fairly recent SDL code snapshot. + +Get SDL from CVS like this: + +cvs -d :pserver:guest@cvs.lokigames.com:/cvs login +# password is "guest", without the quotes. +cvs -z3 -d :pserver:guest@cvs.lokigames.com:/cvs checkout SDL12 +cd SDL12; ./autogen.sh; make; make install + + +CVS is also good if you want the up-to-the-minute changes of BUILD: + +cvs -z3 -d:pserver:anonymous@icculus.org:/cvs/cvsroot login +# password is "anonymous", without the quotes. +cvs -z3 -d:anonymous@icculus.org:/cvs/cvsroot co buildengine + + +There is a win32 CVS client available for download here: + http://www.icculus.org/misc/cvs-over-ssh-win32.zip + +You can get more information about CVS from http://cvshome.org/ ... + + +PLEASE READ THE CHANGELOG AND TODO FILE FOR DETAILS ON WHAT'S NEW AND + WHAT'S NEEDED! They're in the tarball. + +Have fun! + +--ryan. (icculus@clutteredmind.org) + + +INFO: +- Patches go to Ryan at icculus@clutteredmind.org. +- Please try to keep it so the original source can still be compiled with + Watcom C for DOS. Maybe if we do a good enough job, we can just get Ken + to make this his official version, although this is not the goal right now. + You may #ifdef DOSisms with PLATFORM_DOS, and Unixism with PLATFORM_UNIX, but + try not to touch the original code if you can circumvent it (i.e. reimplement + the functionality of missing functions in a separate file, #define + __interrupt to be blank, etc...) Reference unix_compat.[ch] and sdl_driver.c + for examples of this behaviour. +- See us in #loki at irc.openprojects.net with questions. +- This is NOT a Loki-sponsored project. We are (er...WERE) Loki employees + that get off on this stuff. Don't harrass info@lokigames.com about it. +- Yes, you CAN edit Duke3D maps with this. Sort of. + Find your DUKE3D.GRP file, and set this environment variable: + + (on Windows: "set BUILD_GROUPFILE=C:\where\grpfile\is\DUKE3D.GRP") + (on Linux/bash: "export BUILD_GROUPFILE=/where/grpfile/is/DUKE3D.GRP") + + Without this environment variable, Build looks for "stuff.dat" in the + current directory; that's KenBuild's groupfile. + + Now go get a Duke3D map off the net and open it in build. + I haven't tried Blood, Shadow Warrior, or anything else, but someone sent + me screenshots of Shadow Warrior. Your mileage may vary. + + Either way, there's lots of screenshots up at: + http://www.icculus.org/BUILD/screenshots/duke3d_data_files/ + http://www.icculus.org/BUILD/screenshots/shadow_warrior_data_files/ + + There is still much missing from Build that is needed to use it as a Duke3D + editor, and that is not the focus of this project. It is DEFINITELY not + enough to PLAY duke3d, as there is no CON interpreter or correct physics + or enemy AI or equivilent sector tags etc. + + If an editor is all you want, there is a project called Mapster + (http://mapster-rtcm.totalconversions.com/) that is a KenBuild source + modification to support all of DukeBUILD's features, and add some new + enhancements, too. Stay tuned, as there may be a win32 (and Linux?) version + of Mapster sooner or later. + + In short, is this enough to play Duke/Shadow/Blood? No. But it's a good start. + +- Can Windows users use this code? You bet. Binaries available. + +- To build this from source under Windows: + You can use Cygwin, a Windows port of the GNU C compiler. Cygwin is free (as + in speech and beer), and can be downloaded from + http://sources.redhat.com/cygwin/. You will also need to have a development + version of SDL installed (I used the prebuilt SDL libraries under + Windows, look at http://www.libsdl.org/). And, as under Linux, you will + need NASM (http://www.kernel.org/pub/software/devel/nasm/). Make sure + nasmw.exe ends up somewhere in your PATH, and SDL is somewhere you have + access to. Once you have all this set up, unpack the BUILD sources. + Make sure you're in the buildengine directory. Set these two environment + variables: + + export SDL_LIB_DIR=C:/where/i/installed/SDL-1.2.0/lib + export SDL_INC_DIR=C:/where/i/installed/SDL-1.2.0/include + + (Yes, those directory separators are backwards; it is intentional.) + + ...then, type "make", and it should produce binaries for you if you did + everything right. + + You will have to make sure that SDL.DLL and CYGWIN1.DLL are in your path + somewhere. + + This isn't all as hard as it sounds. :) + +- To build with Watcom C for Win32: Get SDL (as above). Unpack the source, + edit Makefile.w32 (instructions are in that file). Change the paths at the + top to point to your Watcom and SDL installs. Run "wmake -f Makefile.w32" + ... that's all. I tried this with Watcom C 10.6 and 11.0 using the win32 + (both "nt" and "nt_win") targets. Anything older than Watcom C 11.0 will + NOT build an EXE that will work on Windows NT 4.0 or Windows 2000, even + though the same binary will work on Windows 95 and 98. Your mileage may vary. + +- If anyone wants to make this work with Visual C++ to make this easier + for Windows users, I'll happily accept your changes and additions. + +- One more thing, about licensing. If you build this with Cygwin, you are + NOT permitted to release binaries, as Cygwin's POSIX-support DLL is + under the GPL license, which forbids distribution of code linked with it + that doesn't abide by the OpenSource definition (Ken's license does + not). Harrassing Ken Silverman to change his license to the GPL is not + only rude, it's unproductive. Distributing binaries built with Cygwin + opens you up to lawsuits from Red Hat and the Free Software + Foundation. Do the right thing; if you must distribute BUILD binaries, + don't build them with Cygwin. + +- Does this code still work under DOS? Yup. You use Watcom C the same as you + would for the Windows target, except you use Makefile.dos. Note that the + Windows and Linux versions are better maintained, more stable, and support + more hardware. Don't ask Ken about the DOS port either. He probably wouldn't + recognize his own code after all the mangling we did. :) + +- Wish your GRP files weren't so big? Convert them to PkZip format, build + the engine with PhysicsFS support, and set the environment variable + BUILD_GROUPFILE=mygroupfile.zip ... Look at PhysicsFS's homepage for more + information: http://www.icculus.org/physfs/ ... + + +GOOD REFERENCES: +- VESA i/o reference: http://pm.cse.rmit.edu.au/~steve/vbe/vbe20.htm +- http://www-cgi.cs.cmu.edu/afs/cs.cmu.edu/user/ralf/pub/WWW/files.html + (THE Interrupt List, from Ralf Brown. Good stuff, here.) +- FreeVGA: A VGA documentation project. + http://www.goodnet.com/~tinara/FreeVGA/home.htm +- BUILD keyboard reference: http://home.online.no/~flovstak/duke/bkeys.htm +- mapFAQ: http://mapfaq.3dportal.com/ +- Ken Silverman's homepage: http://www.advsys.net/ken/ +- The Art of Assembly Language, complete text: + http://webster.cs.ucr.edu/Page_asm/ArtofAssembly/ArtofAsm.html + +HOW TO FIX ALL YOUR "//" COMMENTS: +- We now compile BUILD with the most anal compiler settings available for any + given platform. This forces us to write cleaner, more portable, and less + buggy code, but sometimes it limits what we can get away with. Most notably: + comment syntax. There are some compilers on some platforms + (*coughcoughSolariscoughcough*) that are very anal about (the old version + of) the C specification they follow. Therefore, you can NOT use "//" single + line comments in code compiled on those toolchains. Since Ken used nothing + but // comments, I needed to automate the conversion process a little bit. + Here's the quick and dirty way to convert them, using Perl: + + --- snip. --- + + while () { + chomp; + s/(.*)(? myconvertedsrc.c + + (patches to that code are welcome.) + +TO PORT TO NEW COMPILERS AND TOOLCHAINS: +- Try to get nasm to generate object files that your linker can understand. + That is the easiest for the asm modules. Use a_nasm.asm, which is the NASM + version. a.asm is the Watcom Assembler (wasm) version that Ken distributed + with the original Build source release. +- The alternative is to write portable C code to avoid all the self-modifying + ASM. Have the appropriate amount of fun. +- There is inline assembly in engine.c, game.c, pragmas*.c, and pragmas.h. + Every compiler has their own syntax for this. Have more fun. +- Try to find clean syntax fixes that work everywhere instead of #ifdef'ing, + if you can. Platform.h is a good starting point. + +TO PORT TO NEW OPERATING SYSTEMS: +- If Simple Directmedia Layer supports your OS, you're in luck. Just get + everything building (see above). If not, look at display.h for what you + need to implement, and sdl_driver.c and dos_drvr.c for examples. Consider + getting SDL working on your platform instead. +- Your platform needs at least an 8-bit linear framebuffer for video. + Otherwise, you can pray the OpenGL code gets written and is useful to you. +- The code doesn't necessarily NEED a keyboard, but the input device has GOT + to have a lot of buttons. The renderer itself doesn't deal with input, just + the apps (build, game, duke3d) that use it, so this may not be a problem, + depending on your needs. Some apps (the editor itself, for example) seem to + demand a mouse. +- Your platform needs to be 32-bit clean, in all likelihood. You might be able + to make enough band-aids to get this working otherwise. No one's tried it on + a 64-bit platform yet, partially due to all the (32-bit) assembly code. + 16-bits or less will likely be a nightmare. +- Start in platform.h for an idea of where to add anything that's + platform-specific. If you can't get by on PLATFORM_UNIX, then define + PLATFORM_WHATEVER. +- Try not to wedge in platform dependent code, but find good abstractions. + +TO PORT TO NEW PROCESSORS: +- You can either write new ASM for your processor, or better yet, implement + the stuff in portable C, so everyone can benefit. +- Most of your work will be in pragmas.*, a_linux.*, and a.*. Look for + USE_I386_ASM. Define your own version. + +/* end of README ... */ + diff --git a/buildengine/README-dosbins.txt b/buildengine/README-dosbins.txt new file mode 100755 index 0000000..9749a60 --- /dev/null +++ b/buildengine/README-dosbins.txt @@ -0,0 +1,48 @@ +BUILD binaries for DOS (i386 and greater) systems. + +These binaries are BETA quality. Expect crashes. + +Bug reports to Ryan C. Gordon (icculus@clutteredmind.org). + +I've only tested this briefly on a Windows 98 (second edition) box, in a DOS + window. YMMV. + +Please feel free to report success and failure on different Windows platforms. + +This does not play Duke3D, Shadow Warrior, Blood, or any other game but Ken's + test game ("KenBuild"). It can sort of edit Duke3D maps, but the BUILD.EXE on + your commercial Duke3D CD-ROM is better suited. You can also check out Mapster + (http://mapster-rtcm.totalconversions.com/), which might be useful to you. + +Do NOT harrass Ken Silverman about these binaries. He did not compile them. + He did not release them. He is not maintaining this port and he does NOT want + to hear from YOU. + +Here is his license text stuff: + +// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman +// Ken Silverman's official web site: "http://www.advsys.net/ken" +// See the included license file "BUILDLIC.TXT" for license info. +// This file has been modified from Ken Silverman's original release + + +The source code of the Build port (along with screenshots of it running) is +available from http://www.icculus.org/ + +Feel free to send me comments, complaints, suggestions, and donations. + +Enjoy! + +--ryan. (icculus@clutteredmind.org) + + +CHANGELOG of DOS binary releases: +02222001 - first binary release. +02262001 - Improved Makefile system. May not be packaging correctly, though. +05272001 - Compiled with Watcom C 11.0. Can sort of edit Duke3D maps. Read the + README. Lots of non-platform-specific fixes and enhancements. Read + the CHANGELOG. + +// end of README-dosbins.txt ... + + diff --git a/buildengine/README-win32bins.txt b/buildengine/README-win32bins.txt new file mode 100755 index 0000000..0f9d0f0 --- /dev/null +++ b/buildengine/README-win32bins.txt @@ -0,0 +1,71 @@ +BUILD binaries for Win32 systems. + +These binaries are BETA quality. Expect crashes. + +The notable annoyances: +1) No sound. +2) No networking. Boohoo. :) + +Bug reports to Ryan C. Gordon (icculus@clutteredmind.org). + +I've only tested this briefly on a Windows 98 (second edition) box, and even + more briefly on WinNT 4.0 (Service Pack 6) under vmWare. YMMV. + +Please feel free to report success and failure on different Windows platforms. + This, obviously, will not work on a Windows 3.1 platform, for that one + sadistic guy who's going to try it. :) + +This does not play Duke3D, Shadow Warrior, Blood, or any other game but Ken's + test game ("KenBuild"). It can sort of edit Duke3D maps, but the DOS-based + BUILD.EXE on your commercial Duke CD-ROM is better suited. You can also check + out Mapster (http://mapster-rtcm.totalconversions.com). + +Do NOT harrass Ken Silverman about these binaries. He did not compile them. + He did not release them. He did not port this to Windows and he does NOT want + to hear from YOU. + +Here is his license text stuff: + +// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman +// Ken Silverman's official web site: "http://www.advsys.net/ken" +// See the included license file "BUILDLIC.TXT" for license info. +// This file has been modified from Ken Silverman's original release + + +This code also relies on Simple Directmedia Layer (SDL) for graphics and input. + This excellent cross-platform library was put together by Sam Lantinga, and + is available to us under the LGPL license. That means that I can use it + freely, but I have to point you to a place where you can get the source + for yourself (the DLL is in this archive, though, so this is strictly FYI): + + http://www.libsdl.org/ + + +The source code of the Build port (along with screenshots of it running) is +available from http://www.icculus.org/ + +Feel free to send me comments, complaints, suggestions, and donations. + +Enjoy! + +--ryan. (icculus@clutteredmind.org) + + +CHANGELOG of win32 binary releases: +02192001 - first binary release. +02202001 - Fixed rendering bug in 2D editor, enabled optimizations, + disabled debugging. Disabled console window. +02212001 - Fixed too-slow gameplay (Thanks, Matt!). +02222001 - Ported back to DOS/386...since so much code got touched, it's + worth putting out a new binary to make sure nothing broke. +02262001 - Fixed WinNT/Win2k problems. Should run now. YMMV. Automated + packaging system, but not sure if everything is getting included. + time will tell. +05272001 - Built with Watcom C 11.0, so the things work under WinNT and Win2000 + without editing the EXE. Updated to SDL 1.2.0. Can sorta edit Duke3D + maps now (see README) Lots of other non-platform-specific fixes and + updates. See the CHANGELOG. + +// end of README-win32bins.txt ... + + diff --git a/buildengine/TODO b/buildengine/TODO new file mode 100755 index 0000000..9785376 --- /dev/null +++ b/buildengine/TODO @@ -0,0 +1,47 @@ +// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman +// Ken Silverman's official web site: "http://www.advsys.net/ken" +// See the included license file "BUILDLIC.TXT" for license info. + +(questions to Ryan C. Gordon, icculus@clutteredmind.org) + +NEXT ON TAP: +- extern "C" in every header. +- Litter the code with assertions. +- ASM->C port for non-intel boxes? +- Look for the string "!!!" ... these are TODOs in the source. +- Tie the window manager quit request to the program, so it reacts like an + ESC in 3D mode, and a "ESC, Q" in 2D mode. This will allows the user to + abort the shutdown, save if there are changes, etc... +- Make 2D mode only prompt to save changes on exit if there are changes to + save. +- Looking up/down in the editor seems to screw things up. This might not be + the case in 320x200 resolution. Look into it. +- Slopes are misdrawn in kensig.map. (still?) +- Sound. +- Networking. +- Port to Visual C? +- Port to Mingwin32? (the mprotect()s need to be #ifdef'd out. That should + be the biggest change.) +- Port to BeOS? +- Make a statically linked binary option in the Linux Makefile. +- Make a linuxbins target (like msbins target) in the Linux Makefile. +- Hardware surface/page flipping for more rendering speed? +- Can we sync to vblank in SDL? +- OpenGL? This would accelerate rendering, get us out of 8-bit hell, make it + prettier, and take out most of the ASM code, for porting to other processors. + But it will also give us all ulcers. :) +- Update Ken's docs, where applicable. +- Remove all possible global variables, and expose getter/setter functions + instead. +- There's an SDL_UpdateRect() call in engine.c (__printext256().) Do something + about it. +- Can we convert any existing tabs into equivalent spaces ASCII 32 chars, so + the align at 4-space tabstops? Tabs suck. +- Can we move those SDL __cdecl pragmas out of display.h? +- Long filenames confuse the editor's file "dialog". +- boardfilename (and others) in build.c and elsewhere are hardcoded to 13 chars. +- Might be worth moving all that resolution management code from sdl_driver.c + to engine.c ... + +// end of TODO ... + diff --git a/buildengine/a.asm b/buildengine/a.asm new file mode 100755 index 0000000..09447a3 --- /dev/null +++ b/buildengine/a.asm @@ -0,0 +1,2436 @@ +; "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman +; Ken Silverman's official web site: "http://www.advsys.net/ken" +; See the included license file "BUILDLIC.TXT" for license info. + +.586P +.8087 +;include mmx.inc ;Include this if using < WATCOM 11.0 WASM + +;Warning: IN THIS FILE, ALL SEGMENTS ARE REMOVED. THIS MEANS THAT DS:[] +;MUST BE ADDED FOR ALL SELF-MODIFIES FOR MASM TO WORK. +; +;WASM PROBLEMS: +; 1. Requires all scaled registers (*1,*2,*4,*8) to be last thing on line +; 2. Using 'DATA' is nice for self-mod. code, but WDIS only works with 'CODE' +; +;MASM PROBLEMS: +; 1. Requires DS: to be written out for self-modifying code to work +; 2. Doesn't encode short jumps automatically like WASM +; 3. Stupidly adds wait prefix to ffree's + +EXTRN _asm1 : dword +EXTRN _asm2 : dword +EXTRN _asm3 : dword +EXTRN _asm4 : dword +EXTRN _reciptable : near +EXTRN _fpuasm : dword +EXTRN _globalx3 : dword +EXTRN _globaly3 : dword +EXTRN _ylookup : near + +EXTRN _vplce : near +EXTRN _vince : near +EXTRN _palookupoffse : near +EXTRN _bufplce : near + +EXTRN _ebpbak : dword +EXTRN _espbak : dword + +EXTRN _pow2char : near +EXTRN _pow2long : near + +CODE SEGMENT PUBLIC USE32 'DATA' +ASSUME cs:CODE,ds:CODE + +ALIGN 16 +PUBLIC is_vmware_running_ +is_vmware_running_: + mov eax,564d5868h + mov ecx,0000000ah + mov dx,5658h + in eax,dx + cmp ebx,564d5868h + jz vmware_y + xor eax,eax + ret +vmware_y: + mov eax,1h + ret + + +ALIGN 16 +PUBLIC sethlinesizes_ +sethlinesizes_: + mov byte ptr [machxbits1+2], al + mov byte ptr [machxbits2+2], al + mov byte ptr [machxbits3+2], al + neg al + mov byte ptr [hxsiz1+2], al + mov byte ptr [hxsiz2+2], al + mov byte ptr [hxsiz3+2], al + mov byte ptr [hxsiz4+2], al + mov byte ptr [machnegxbits1+2], al + + mov byte ptr [hysiz1+3], bl + mov byte ptr [hysiz2+3], bl + mov byte ptr [hysiz3+3], bl + mov byte ptr [hysiz4+3], bl + mov byte ptr [hmach3a+2], bl + mov byte ptr [hmach3b+2], bl + mov byte ptr [hmach3c+2], bl + mov byte ptr [hmach3d+2], bl + + mov dword ptr [hoffs1+2], ecx + mov dword ptr [hoffs2+2], ecx + mov dword ptr [hoffs3+2], ecx + mov dword ptr [hoffs4+2], ecx + mov dword ptr [hoffs5+2], ecx + mov dword ptr [hoffs6+2], ecx + mov dword ptr [hoffs7+2], ecx + mov dword ptr [hoffs8+2], ecx + + mov edx, -1 + mov cl, al + sub cl, bl + shr edx, cl + mov dword ptr [hmach2a+1], edx + mov dword ptr [hmach2b+1], edx + mov dword ptr [hmach2c+1], edx + mov dword ptr [hmach2d+1], edx + + ret + +ALIGN 16 +PUBLIC prosethlinesizes_ +prosethlinesizes_: + mov dword ptr [prohbuf-4], ecx + neg eax + mov ecx, eax + sub eax, ebx + mov byte ptr [prohshru-1], al ;bl = 32-al-bl + mov eax, -1 + shr eax, cl + mov ecx, ebx + shl eax, cl + mov dword ptr [prohand-4], eax ;((-1>>(-oal))<>(32-xbits) adc al, 88h 1 1/2 + ;bufplc mov cl, byte ptr [edx+88888888h] 1 1/2 + ;paloffs&255 mov bl, byte ptr [ecx+88888888h] 1 1/2 +ALIGN 16 +PUBLIC hlineasm4_ +hlineasm4_: + push ebp + + lea ebp, [eax+1] + + cmp ebp, 8 + jle shorthline + + test edi, 1 + jnz short skipthe1byte + + mov eax, esi +hxsiz1: shr eax, 26 +hysiz1: shld eax, edx, 6 +hoffs1: mov cl, byte ptr [eax+88888888h] +pal1: mov bl, byte ptr [ecx+88888888h] + sub esi, _asm1 + sub edx, _asm2 + mov byte ptr [edi], bl + dec edi + dec ebp + +skipthe1byte: + test edi, 2 + jnz short skipthe2byte + + mov eax, esi +hxsiz2: shr eax, 26 +hysiz2: shld eax, edx, 6 +hoffs2: mov cl, byte ptr [eax+88888888h] +pal2: mov bh, byte ptr [ecx+88888888h] + sub esi, _asm1 + sub edx, _asm2 + + mov eax, esi +hxsiz3: shr eax, 26 +hysiz3: shld eax, edx, 6 +hoffs3: mov cl, byte ptr [eax+88888888h] +pal3: mov bl, byte ptr [ecx+88888888h] + sub esi, _asm1 + sub edx, _asm2 + mov word ptr [edi-1], bx + sub edi, 2 + sub ebp, 2 + +skipthe2byte: + + mov eax, esi +machxbits1: shl esi, 6 ;xbits +machnegxbits1: shr eax, 32-6 ;32-xbits + mov dl, al + + inc edi + + add ebx, ebx + mov eax, edx + jc beginhline64 + + mov eax, _asm1 +machxbits2: rol eax, 6 ;xbits + mov dword ptr [hmach4a+2], eax + mov dword ptr [hmach4b+2], eax + mov dword ptr [hmach4c+2], eax + mov dword ptr [hmach4d+2], eax + mov ebx, eax + mov eax, _asm2 + mov al, bl + mov dword ptr [hmach1a+2], eax + mov dword ptr [hmach1b+2], eax + mov dword ptr [hmach1c+2], eax + mov dword ptr [hmach1d+2], eax + + mov eax, edx + jmp beginhline64 +ALIGN 16 +prebeginhline64: + mov dword ptr [edi], ebx +beginhline64: + +hmach3a: rol eax, 6 +hmach2a: and eax, 00008888h +hmach4a: sub esi, 88888888h +hmach1a: sbb edx, 88888888h + sub edi, 4 +hoffs4: mov cl, byte ptr [eax+88888888h] + mov eax, edx + +hmach3b: rol eax, 6 +hmach2b: and eax, 00008888h +hmach4b: sub esi, 88888888h +hmach1b: sbb edx, 88888888h +pal4: mov bh, byte ptr [ecx+88888888h] +hoffs5: mov cl, byte ptr [eax+88888888h] + mov eax, edx + +hmach3c: rol eax, 6 +pal5: mov bl, byte ptr [ecx+88888888h] +hmach2c: and eax, 00008888h + shl ebx, 16 +hmach4c: sub esi, 88888888h +hmach1c: sbb edx, 88888888h +hoffs6: mov cl, byte ptr [eax+88888888h] + + mov eax, edx + ;( + +hmach3d: rol eax, 6 +hmach2d: and eax, 00008888h +hmach4d: sub esi, 88888888h +hmach1d: sbb edx, 88888888h +pal6: mov bh, byte ptr [ecx+88888888h] +hoffs7: mov cl, byte ptr [eax+88888888h] + mov eax, edx + sub ebp, 4 + nop +pal7: mov bl, byte ptr [ecx+88888888h] + jnc prebeginhline64 +skipthe4byte: + + test ebp, 2 + jz skipdrawthe2 + rol ebx, 16 + mov word ptr [edi+2], bx + sub edi, 2 +skipdrawthe2: + test ebp, 1 + jz skipdrawthe1 + shr ebx, 24 + mov byte ptr [edi+3], bl +skipdrawthe1: + + pop ebp + ret + +shorthline: + test ebp, ebp + jz endshorthline +begshorthline: + mov eax, esi +hxsiz4: shr eax, 26 +hysiz4: shld eax, edx, 6 +hoffs8: mov cl, byte ptr [eax+88888888h] +pal8: mov bl, byte ptr [ecx+88888888h] + sub esi, _asm1 + sub edx, _asm2 + mov byte ptr [edi], bl + dec edi + dec ebp + jnz begshorthline +endshorthline: + pop ebp + ret + + + ;eax: 00000000 00000000 00000000 temp---- + ;ebx: 00000000 00000000 00000000 temp---- + ;ecx: UUUUUUuu uuuuuuuu uuuuuuuu uuuuuuuu + ;edx: VVVVVVvv vvvvvvvv vvvvvvvv vvvvvvvv + ;esi: cnt----- -------- -------- -------- + ;edi: vid----- -------- -------- -------- + ;ebp: paloffs- -------- -------- -------- + ;esp: ???????? ???????? ???????? ???????? +ALIGN 16 +PUBLIC prohlineasm4_ +prohlineasm4_: + push ebp + + lea ebp, [ecx+88888888h] +prohpala: + mov ecx, esi + lea esi, [eax+1] + sub edi, esi + +prohbeg: + mov eax, ecx + shr eax, 20 +prohshru: + mov ebx, edx + shr ebx, 26 +prohshrv: + and eax, 88888888h +prohand: + movzx eax, byte ptr [eax+ebx+88888888h] +prohbuf: + mov al, [eax+ebp] + sub ecx, _asm1 + sub edx, _asm2 + mov [edi+esi], al + dec esi + jnz prohbeg + + pop ebp + ret + + + +ALIGN 16 +PUBLIC setupvlineasm_ +setupvlineasm_: + ;First 2 lines for VLINEASM1, rest for VLINEASM4 + mov byte ptr [premach3a+2], al + mov byte ptr [mach3a+2], al + + push ecx + mov byte ptr [machvsh1+2], al ;32-shy + mov byte ptr [machvsh3+2], al ;32-shy + mov byte ptr [machvsh5+2], al ;32-shy + mov byte ptr [machvsh6+2], al ;32-shy + mov ah, al + sub ah, 16 + mov byte ptr [machvsh8+2], ah ;16-shy + neg al + mov byte ptr [machvsh7+2], al ;shy + mov byte ptr [machvsh9+2], al ;shy + mov byte ptr [machvsh10+2], al ;shy + mov byte ptr [machvsh11+2], al ;shy + mov byte ptr [machvsh12+2], al ;shy + mov cl, al + mov eax, 1 + shl eax, cl + dec eax + mov dword ptr [machvsh2+2], eax ;(1<>sh) + ;vplc3 = (ebp<<(32-sh))+((edx&65535)<<(16-sh)) +machvsh5: shl esi, 88h ;32-sh + mov eax, edx +machvsh6: shl ebp, 88h ;32-sh + and edx, 0000ffffh +machvsh7: shr eax, 88h ;sh + add esi, eax +machvsh8: shl edx, 88h ;16-sh + add ebp, edx + mov dword ptr _vplce[12], esi + mov dword ptr _vplce[4], ebp + + pop ebp + ret + + ;eax: -------temp1------- + ;ebx: -------temp2------- + ;ecx: ylo4 --------- + ;edx: ylo2 --------- + ;esi: yhi1 yhi2 + ;edi: ---videoplc/cnt---- + ;ebp: yhi3 yhi4 + ;esp: +ALIGN 16 +PUBLIC provlineasm4_ +provlineasm4_: + push ebp + + mov eax, dword ptr _ylookup[ecx*4] + add eax, edi + mov dword ptr [promachvline4end1+2], eax + inc eax + mov dword ptr [promachvline4end2+2], eax + inc eax + mov dword ptr [promachvline4end3+2], eax + inc eax + mov dword ptr [promachvline4end4+2], eax + sub eax, 3 + sub edi, eax + + mov eax, dword ptr _bufplce[0] + mov ebx, dword ptr _bufplce[4] + mov ecx, dword ptr _bufplce[8] + mov edx, dword ptr _bufplce[12] + mov dword ptr [promachvbuf1+3], ecx + mov dword ptr [promachvbuf2+3], edx + mov dword ptr [promachvbuf3+3], eax + mov dword ptr [promachvbuf4+3], ebx + + mov eax, dword ptr _palookupoffse[0] + mov ebx, dword ptr _palookupoffse[4] + mov ecx, dword ptr _palookupoffse[8] + mov edx, dword ptr _palookupoffse[12] + mov dword ptr [promachvpal1+2], ecx + mov dword ptr [promachvpal2+2], edx + mov dword ptr [promachvpal3+2], eax + mov dword ptr [promachvpal4+2], ebx + + ; ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ + ;edx: ³v3lo ³v1lo ³ + ; ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄ´ + ;esi: ³v2hi v2lo ³ v3hi³ + ; ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄ´ + ;ebp: ³v0hi v0lo ³ v1hi³ + ; ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÙ + + mov ebp, dword ptr _vince[0] + mov ebx, dword ptr _vince[4] + mov esi, dword ptr _vince[8] + mov eax, dword ptr _vince[12] + and esi, 0fffffe00h + and ebp, 0fffffe00h +promachvsh9: rol eax, 88h ;sh +promachvsh10: rol ebx, 88h ;sh + mov edx, eax + mov ecx, ebx + shr ecx, 16 + and edx, 0ffff0000h + add edx, ecx + and eax, 000001ffh + and ebx, 000001ffh + add esi, eax + add ebp, ebx + ; + mov eax, edx + and eax, 0ffff0000h + mov dword ptr [promachvinc1+2], eax + mov dword ptr [promachvinc2+2], esi + shl edx, 16 + mov dword ptr [promachvinc3+2], edx + mov dword ptr [promachvinc5+2], ebp + + mov ebp, dword ptr _vplce[0] + mov ebx, dword ptr _vplce[4] + mov esi, dword ptr _vplce[8] + mov eax, dword ptr _vplce[12] + and esi, 0fffffe00h + and ebp, 0fffffe00h +promachvsh11: rol eax, 88h ;sh +promachvsh12: rol ebx, 88h ;sh + mov edx, eax + mov ecx, ebx + shr ecx, 16 + and edx, 0ffff0000h + add edx, ecx + and eax, 000001ffh + and ebx, 000001ffh + add esi, eax + add ebp, ebx + + mov eax, esi + mov ecx, edx + shl ecx, 16 + jmp short probeginvlineasm4 +ALIGN 16 + nop + nop + nop +probeginvlineasm4: +promachvsh1: shr eax, 88h ;32-sh + mov ebx, esi +promachvsh2: and ebx, 00000088h ;(1<>sh) + ;vplc3 = (ebp<<(32-sh))+((edx&65535)<<(16-sh)) +promachvsh5: shl esi, 88h ;32-sh + mov eax, edx +promachvsh6: shl ebp, 88h ;32-sh + and edx, 0000ffffh +promachvsh7: shr eax, 88h ;sh + add esi, eax +promachvsh8: shl edx, 88h ;16-sh + add ebp, edx + mov dword ptr _vplce[12], esi + mov dword ptr _vplce[4], ebp + + pop ebp + ret + + +ALIGN 16 +PUBLIC mvlineasm4_ +mvlineasm4_: + push ebp + + mov eax, dword ptr _bufplce[0] + mov ebx, dword ptr _bufplce[4] + mov dword ptr [machmv1+2], eax + mov dword ptr [machmv4+2], ebx + mov eax, dword ptr _bufplce[8] + mov ebx, dword ptr _bufplce[12] + mov dword ptr [machmv7+2], eax + mov dword ptr [machmv10+2], ebx + + mov eax, dword ptr _palookupoffse[0] + mov ebx, dword ptr _palookupoffse[4] + mov dword ptr [machmv2+2], eax + mov dword ptr [machmv5+2], ebx + mov eax, dword ptr _palookupoffse[8] + mov ebx, dword ptr _palookupoffse[12] + mov dword ptr [machmv8+2], eax + mov dword ptr [machmv11+2], ebx + + mov eax, dword ptr _vince[0] ;vince + mov ebx, dword ptr _vince[4] + xor al, al + xor bl, bl + mov dword ptr [machmv3+2], eax + mov dword ptr [machmv6+2], ebx + mov eax, dword ptr _vince[8] + mov ebx, dword ptr _vince[12] + mov dword ptr [machmv9+2], eax + mov dword ptr [machmv12+2], ebx + + mov ebx, ecx + mov ecx, dword ptr _vplce[0] + mov edx, dword ptr _vplce[4] + mov esi, dword ptr _vplce[8] + mov ebp, dword ptr _vplce[12] + mov cl, bl + inc cl + inc bh + mov byte ptr _asm3[0], bh +fixchain2ma: sub edi, 320 + + jmp short beginmvlineasm4 +ALIGN 16 +beginmvlineasm4: + dec cl + jz endmvlineasm4 +beginmvlineasm42: + mov eax, ebp + mov ebx, esi +machmv16: shr eax, 32 +machmv15: shr ebx, 32 +machmv12: add ebp, 88888888h ;vince[3] +machmv9: add esi, 88888888h ;vince[2] +machmv10: mov al, byte ptr [eax+88888888h] ;bufplce[3] +machmv7: mov bl, byte ptr [ebx+88888888h] ;bufplce[2] + cmp al, 255 + adc dl, dl + cmp bl, 255 + adc dl, dl +machmv8: mov bl, byte ptr [ebx+88888888h] ;palookupoffs[2] +machmv11: mov bh, byte ptr [eax+88888888h] ;palookupoffs[3] + + mov eax, edx +machmv14: shr eax, 32 + shl ebx, 16 +machmv4: mov al, byte ptr [eax+88888888h] ;bufplce[1] + cmp al, 255 + adc dl, dl +machmv6: add edx, 88888888h ;vince[1] +machmv5: mov bh, byte ptr [eax+88888888h] ;palookupoffs[1] + + mov eax, ecx +machmv13: shr eax, 32 +machmv3: add ecx, 88888888h ;vince[0] +machmv1: mov al, byte ptr [eax+88888888h] ;bufplce[0] + cmp al, 255 + adc dl, dl +machmv2: mov bl, byte ptr [eax+88888888h] ;palookupoffs[0] + + shl dl, 4 + xor eax, eax +fixchain2mb: add edi, 320 + mov al, dl + add eax, offset mvcase0 + jmp eax ;16 byte cases + +ALIGN 16 +endmvlineasm4: + dec byte ptr _asm3[0] + jnz beginmvlineasm42 + + mov dword ptr _vplce[0], ecx + mov dword ptr _vplce[4], edx + mov dword ptr _vplce[8], esi + mov dword ptr _vplce[12], ebp + pop ebp + ret + + ;5,7,8,8,11,13,12,14,11,13,14,14,12,14,15,7 +ALIGN 16 +mvcase0: + jmp beginmvlineasm4 +ALIGN 16 +mvcase1: + mov byte ptr [edi], bl + jmp beginmvlineasm4 +ALIGN 16 +mvcase2: + mov byte ptr [edi+1], bh + jmp beginmvlineasm4 +ALIGN 16 +mvcase3: + mov word ptr [edi], bx + jmp beginmvlineasm4 +ALIGN 16 +mvcase4: + shr ebx, 16 + mov byte ptr [edi+2], bl + jmp beginmvlineasm4 +ALIGN 16 +mvcase5: + mov byte ptr [edi], bl + shr ebx, 16 + mov byte ptr [edi+2], bl + jmp beginmvlineasm4 +ALIGN 16 + mvcase6: + shr ebx, 8 + mov word ptr [edi+1], bx + jmp beginmvlineasm4 +ALIGN 16 +mvcase7: + mov word ptr [edi], bx + shr ebx, 16 + mov byte ptr [edi+2], bl + jmp beginmvlineasm4 +ALIGN 16 +mvcase8: + shr ebx, 16 + mov byte ptr [edi+3], bh + jmp beginmvlineasm4 +ALIGN 16 +mvcase9: + mov byte ptr [edi], bl + shr ebx, 16 + mov byte ptr [edi+3], bh + jmp beginmvlineasm4 +ALIGN 16 +mvcase10: + mov byte ptr [edi+1], bh + shr ebx, 16 + mov byte ptr [edi+3], bh + jmp beginmvlineasm4 +ALIGN 16 +mvcase11: + mov word ptr [edi], bx + shr ebx, 16 + mov byte ptr [edi+3], bh + jmp beginmvlineasm4 +ALIGN 16 +mvcase12: + shr ebx, 16 + mov word ptr [edi+2], bx + jmp beginmvlineasm4 +ALIGN 16 +mvcase13: + mov byte ptr [edi], bl + shr ebx, 16 + mov word ptr [edi+2], bx + jmp beginmvlineasm4 +ALIGN 16 +mvcase14: + mov byte ptr [edi+1], bh + shr ebx, 16 + mov word ptr [edi+2], bx + jmp beginmvlineasm4 +ALIGN 16 +mvcase15: + mov dword ptr [edi], ebx + jmp beginmvlineasm4 + +ALIGN 16 +PUBLIC setupspritevline_ +setupspritevline_: + mov dword ptr [spal+2], eax + + mov eax, esi ;xinc's + shl eax, 16 + mov dword ptr [smach1+2], eax + mov dword ptr [smach4+2], eax + mov eax, esi + sar eax, 16 + add eax, ebx ;watch out with ebx - it's passed + mov dword ptr [smach2+2], eax + add eax, edx + mov dword ptr [smach5+2], eax + + mov dword ptr [smach3+2], ecx ;yinc's + ret + +ALIGN 16 +PUBLIC spritevline_ + ;eax = 0, ebx = x, ecx = cnt, edx = y, esi = yplc, edi = p +prestartsvline: +smach1: add ebx, 88888888h ;xincshl16 + mov al, byte ptr [esi] +smach2: adc esi, 88888888h ;xincshr16+yalwaysinc + +startsvline: +spal: mov al, [eax+88888888h] ;palookup + mov byte ptr [edi], al +fixchain1s: add edi, 320 + +spritevline_: +smach3: add edx, 88888888h ;dayinc + dec ecx + ja short prestartsvline ;jump if (no carry (add)) and (not zero (dec))! + jz short endsvline +smach4: add ebx, 88888888h ;xincshl16 + mov al, byte ptr [esi] +smach5: adc esi, 88888888h ;xincshr16+yalwaysinc+daydime + jmp short startsvline +endsvline: + ret + +ALIGN 16 +PUBLIC msetupspritevline_ +msetupspritevline_: + mov dword ptr [mspal+2], eax + + mov eax, esi ;xinc's + shl eax, 16 + mov dword ptr [msmach1+2], eax + mov dword ptr [msmach4+2], eax + mov eax, esi + sar eax, 16 + add eax, ebx ;watch out with ebx - it's passed + mov dword ptr [msmach2+2], eax + add eax, edx + mov dword ptr [msmach5+2], eax + + mov dword ptr [msmach3+2], ecx ;yinc's + ret + +ALIGN 16 +PUBLIC mspritevline_ + ;eax = 0, ebx = x, ecx = cnt, edx = y, esi = yplc, edi = p +mprestartsvline: +msmach1: add ebx, 88888888h ;xincshl16 + mov al, byte ptr [esi] +msmach2: adc esi, 88888888h ;xincshr16+yalwaysinc + +mstartsvline: + cmp al, 255 + je short mskipsvline +mspal: mov al, [eax+88888888h] ;palookup + mov byte ptr [edi], al +mskipsvline: +mfixchain1s: add edi, 320 + +mspritevline_: +msmach3: add edx, 88888888h ;dayinc + dec ecx + ja short mprestartsvline ;jump if (no carry (add)) and (not zero (dec))! + jz short mendsvline +msmach4: add ebx, 88888888h ;xincshl16 + mov al, byte ptr [esi] +msmach5: adc esi, 88888888h ;xincshr16+yalwaysinc+daydime + jmp short mstartsvline +mendsvline: + ret + +ALIGN 16 +PUBLIC tsetupspritevline_ +tsetupspritevline_: + mov dword ptr [tspal+2], eax + + mov eax, esi ;xinc's + shl eax, 16 + mov dword ptr [tsmach1+2], eax + mov dword ptr [tsmach4+2], eax + mov eax, esi + sar eax, 16 + add eax, ebx ;watch out with ebx - it's passed + mov dword ptr [tsmach2+2], eax + add eax, edx + mov dword ptr [tsmach5+2], eax + + mov dword ptr [tsmach3+2], ecx ;yinc's + ret + +ALIGN 16 +PUBLIC tspritevline_ +tspritevline_: + ;eax = 0, ebx = x, ecx = cnt, edx = y, esi = yplc, edi = p + push ebp + mov ebp, ebx + xor ebx, ebx + jmp tenterspritevline +ALIGN 16 +tprestartsvline: +tsmach1: add ebp, 88888888h ;xincshl16 + mov al, byte ptr [esi] +tsmach2: adc esi, 88888888h ;xincshr16+yalwaysinc + +tstartsvline: + cmp al, 255 + je short tskipsvline +transrev2: + mov bh, byte ptr [edi] +transrev3: +tspal: mov bl, [eax+88888888h] ;palookup +tmach4: mov al, byte ptr [ebx+88888888h] ;_transluc + mov byte ptr [edi], al +tskipsvline: +tfixchain1s: add edi, 320 + +tenterspritevline: +tsmach3: add edx, 88888888h ;dayinc + dec ecx + ja short tprestartsvline ;jump if (no carry (add)) and (not zero (dec))! + jz short tendsvline +tsmach4: add ebp, 88888888h ;xincshl16 + mov al, byte ptr [esi] +tsmach5: adc esi, 88888888h ;xincshr16+yalwaysinc+daydime + jmp short tstartsvline +tendsvline: + pop ebp + ret + +ALIGN 16 +PUBLIC msethlineshift_ +msethlineshift_: + neg al + mov byte ptr [msh1d+2], al + mov byte ptr [msh2d+3], bl + mov byte ptr [msh3d+2], al + mov byte ptr [msh4d+3], bl + mov byte ptr [msh5d+2], al + mov byte ptr [msh6d+3], bl + ret + +ALIGN 16 +PUBLIC mhline_ +mhline_: + ;_asm1 = bxinc + ;_asm2 = byinc + ;_asm3 = shadeoffs + ;eax = picoffs + ;ebx = bx + ;ecx = cnt + ;edx = ? + ;esi = by + ;edi = p + + mov dword ptr [mmach1d+2], eax + mov dword ptr [mmach5d+2], eax + mov dword ptr [mmach9d+2], eax + mov eax, _asm3 + mov dword ptr [mmach2d+2], eax + mov dword ptr [mmach2da+2], eax + mov dword ptr [mmach2db+2], eax + mov dword ptr [mmach6d+2], eax + mov dword ptr [mmach10d+2], eax + mov eax, _asm1 + mov dword ptr [mmach3d+2], eax + mov dword ptr [mmach7d+2], eax + mov eax, _asm2 + mov dword ptr [mmach4d+2], eax + mov dword ptr [mmach8d+2], eax + jmp short mhlineskipmodify_ + +ALIGN 16 +PUBLIC mhlineskipmodify_ +mhlineskipmodify_: + + push ebp + + xor eax, eax + mov ebp, ebx + + test ecx, 00010000h + jnz short mbeghline + +msh1d: shr ebx, 26 +msh2d: shld ebx, esi, 6 + add ebp, _asm1 +mmach9d: mov al, byte ptr [ebx+88888888h] ;picoffs + add esi, _asm2 + cmp al, 255 + je mskip5 + + mmach10d: mov cl, byte ptr [eax+88888888h] ;shadeoffs + mov byte ptr [edi], cl +mskip5: + inc edi + sub ecx, 65536 + jc mendhline + jmp short mbeghline + +ALIGN 16 +mpreprebeghline: ;1st only + mov al, cl +mmach2d: mov al, byte ptr [eax+88888888h] ;shadeoffs + mov byte ptr [edi], al + +mprebeghline: + add edi, 2 + sub ecx, 131072 + jc short mendhline +mbeghline: +mmach3d: lea ebx, [ebp+88888888h] ;bxinc +msh3d: shr ebp, 26 +msh4d: shld ebp, esi, 6 +mmach4d: add esi, 88888888h ;byinc +mmach1d: mov cl, byte ptr [ebp+88888888h] ;picoffs +mmach7d: lea ebp, [ebx+88888888h] ;bxinc + +msh5d: shr ebx, 26 +msh6d: shld ebx, esi, 6 +mmach8d: add esi, 88888888h ;byinc +mmach5d: mov ch, byte ptr [ebx+88888888h] ;picoffs + + cmp cl, 255 + je short mskip1 + cmp ch, 255 + je short mpreprebeghline + + mov al, cl ;BOTH +mmach2da: mov bl, byte ptr [eax+88888888h] ;shadeoffs + mov al, ch +mmach2db: mov bh, byte ptr [eax+88888888h] ;shadeoffs + mov word ptr [edi], bx + add edi, 2 + sub ecx, 131072 + jnc short mbeghline + jmp mendhline +mskip1: ;2nd only + cmp ch, 255 + je short mprebeghline + + mov al, ch +mmach6d: mov al, byte ptr [eax+88888888h] ;shadeoffs + mov byte ptr [edi+1], al + add edi, 2 + sub ecx, 131072 + jnc short mbeghline +mendhline: + + pop ebp + ret + +ALIGN 16 +PUBLIC tsethlineshift_ +tsethlineshift_: + neg al + mov byte ptr [tsh1d+2], al + mov byte ptr [tsh2d+3], bl + mov byte ptr [tsh3d+2], al + mov byte ptr [tsh4d+3], bl + mov byte ptr [tsh5d+2], al + mov byte ptr [tsh6d+3], bl + ret + +ALIGN 16 +PUBLIC thline_ +thline_: + ;_asm1 = bxinc + ;_asm2 = byinc + ;_asm3 = shadeoffs + ;eax = picoffs + ;ebx = bx + ;ecx = cnt + ;edx = ? + ;esi = by + ;edi = p + + mov dword ptr [tmach1d+2], eax + mov dword ptr [tmach5d+2], eax + mov dword ptr [tmach9d+2], eax + mov eax, _asm3 + mov dword ptr [tmach2d+2], eax + mov dword ptr [tmach6d+2], eax + mov dword ptr [tmach10d+2], eax + mov eax, _asm1 + mov dword ptr [tmach3d+2], eax + mov dword ptr [tmach7d+2], eax + mov eax, _asm2 + mov dword ptr [tmach4d+2], eax + mov dword ptr [tmach8d+2], eax + jmp thlineskipmodify_ + +ALIGN 16 +PUBLIC thlineskipmodify_ +thlineskipmodify_: + + push ebp + + xor eax, eax + xor edx, edx + mov ebp, ebx + + test ecx, 00010000h + jnz short tbeghline + +tsh1d: shr ebx, 26 +tsh2d: shld ebx, esi, 6 + add ebp, _asm1 +tmach9d: mov al, byte ptr [ebx+88888888h] ;picoffs + add esi, _asm2 + cmp al, 255 + je tskip5 + +transrev4: +tmach10d: mov dl, byte ptr [eax+88888888h] ;shadeoffs +transrev5: + mov dh, byte ptr [edi] +tmach1: mov al, byte ptr [edx+88888888h] ;_transluc + mov byte ptr [edi], al +tskip5: + inc edi + sub ecx, 65536 + jc tendhline + jmp short tbeghline + +ALIGN 16 +tprebeghline: + add edi, 2 + sub ecx, 131072 + jc short tendhline +tbeghline: +tmach3d: lea ebx, [ebp+88888888h] ;bxinc +tsh3d: shr ebp, 26 +tsh4d: shld ebp, esi, 6 +tmach4d: add esi, 88888888h ;byinc +tmach1d: mov cl, byte ptr [ebp+88888888h] ;picoffs +tmach7d: lea ebp, [ebx+88888888h] ;bxinc + +tsh5d: shr ebx, 26 +tsh6d: shld ebx, esi, 6 +tmach8d: add esi, 88888888h ;byinc +tmach5d: mov ch, byte ptr [ebx+88888888h] ;picoffs + + cmp cx, 0ffffh + je short tprebeghline + + mov bx, word ptr [edi] + + cmp cl, 255 + je short tskip1 + mov al, cl +transrev6: +tmach2d: mov dl, byte ptr [eax+88888888h] ;shadeoffs +transrev7: + mov dh, bl +tmach2: mov al, byte ptr [edx+88888888h] ;_transluc + mov byte ptr [edi], al + + cmp ch, 255 + je short tskip2 +tskip1: + mov al, ch +transrev8: +tmach6d: mov dl, byte ptr [eax+88888888h] ;shadeoffs +transrev9: + mov dh, bh +tmach3: mov al, byte ptr [edx+88888888h] ;_transluc + mov byte ptr [edi+1], al +tskip2: + + add edi, 2 + sub ecx, 131072 + jnc tbeghline +tendhline: + + pop ebp + ret + + + ;eax=shiftval, ebx=palookup1, ecx=palookup2 +ALIGN 16 +PUBLIC setuptvlineasm2_ +setuptvlineasm2_: + mov byte ptr [tran2shra+2], al + mov byte ptr [tran2shrb+2], al + mov dword ptr [tran2pala+2], ebx + mov dword ptr [tran2palb+2], ecx + mov dword ptr [tran2palc+2], ebx + mov dword ptr [tran2pald+2], ecx + ret + + ;Pass: eax=vplc2, ebx=vinc1, ecx=bufplc1, edx=bufplc2, esi=vplc1, edi=p + ; _asm1=vinc2, _asm2=pend + ;Return: _asm1=vplc1, _asm2=vplc2 +ALIGN 16 +PUBLIC tvlineasm2_ +tvlineasm2_: + push ebp + + mov ebp, eax + + mov dword ptr [tran2inca+2], ebx + mov eax, _asm1 + mov dword ptr [tran2incb+2], eax + + mov dword ptr [tran2bufa+2], ecx ;bufplc1 + mov dword ptr [tran2bufb+2], edx ;bufplc2 + + mov eax, _asm2 + sub edi, eax + mov dword ptr [tran2edia+3], eax + mov dword ptr [tran2edic+2], eax + inc eax + mov dword ptr [tran2edie+2], eax +fixchaint2a: sub eax, 320 + mov dword ptr [tran2edif+2], eax + dec eax + mov dword ptr [tran2edib+3], eax + mov dword ptr [tran2edid+2], eax + + xor ecx, ecx + xor edx, edx + jmp short begintvline2 + + ;eax 0000000000 temp temp + ;ebx 0000000000 odat2 odat1 + ;ecx 0000000000000000 ndat1 + ;edx 0000000000000000 ndat2 + ;esi vplc1 + ;edi videoplc-------------- + ;ebp vplc2 + +ALIGN 16 + ;LEFT ONLY +skipdraw2: +transrev10: +tran2edic: mov ah, byte ptr [edi+88888888h] ;getpixel +transrev11: +tran2palc: mov al, byte ptr [ecx+88888888h] ;palookup1 +fixchaint2d: add edi, 320 +tran2trac: mov bl, byte ptr [eax+88888888h] ;_transluc +tran2edid: mov byte ptr [edi+88888888h-320], bl ;drawpixel + jnc short begintvline2 + jmp endtvline2 + +skipdraw1: + cmp dl, 255 + jne short skipdraw3 +fixchaint2b: add edi, 320 + jc short endtvline2 + +begintvline2: + mov eax, esi +tran2shra: shr eax, 88h ;globalshift + mov ebx, ebp +tran2shrb: shr ebx, 88h ;globalshift +tran2inca: add esi, 88888888h ;vinc1 +tran2incb: add ebp, 88888888h ;vinc2 +tran2bufa: mov cl, byte ptr [eax+88888888h] ;bufplc1 + cmp cl, 255 +tran2bufb: mov dl, byte ptr [ebx+88888888h] ;bufplc2 + je short skipdraw1 + cmp dl, 255 + je short skipdraw2 + + ;mov ax The transluscent reverse of both! + ;mov bl, ah + ;mov ah + ;mov bh + + ;BOTH +transrev12: +tran2edia: mov bx, word ptr [edi+88888888h] ;getpixels +transrev13: + mov ah, bl +transrev14: +tran2pala: mov al, byte ptr [ecx+88888888h] ;palookup1 +transrev15: +tran2palb: mov bl, byte ptr [edx+88888888h] ;palookup2 +fixchaint2c: add edi, 320 +tran2traa: mov al, byte ptr [eax+88888888h] ;_transluc +tran2trab: mov ah, byte ptr [ebx+88888888h] ;_transluc +tran2edib: mov word ptr [edi+88888888h-320], ax ;drawpixels + jnc short begintvline2 + jmp short endtvline2 + + ;RIGHT ONLY +skipdraw3: +transrev16: +tran2edie: mov ah, byte ptr [edi+88888889h] ;getpixel +transrev17: +tran2pald: mov al, byte ptr [edx+88888888h] ;palookup2 +fixchaint2e: add edi, 320 +tran2trad: mov bl, byte ptr [eax+88888888h] ;_transluc +tran2edif: mov byte ptr [edi+88888889h-320], bl ;drawpixel + jnc short begintvline2 + +endtvline2: + mov _asm1, esi + mov _asm2, ebp + + pop ebp + ret + + +BITSOFPRECISION equ 3 +BITSOFPRECISIONPOW equ 8 + +;Double-texture mapping with palette lookup +;eax: ylo1------------|----dat|----dat +;ebx: ylo2--------------------|----cnt +;ecx: 000000000000000000000000|---temp +;edx: xhi1-xlo1---------------|---yhi1 +;esi: xhi2-xlo2---------------|---yhi2 +;edi: ------------------------videopos +;ebp: ----------------------------temp + +ALIGN 16 +PUBLIC setupslopevlin2_ +setupslopevlin2_: + mov dword ptr [slop3+2], edx ;ptr + mov dword ptr [slop7+2], edx ;ptr + mov dword ptr [slop4+2], esi ;tptr + mov dword ptr [slop8+2], esi ;tptr + mov byte ptr [slop2+2], ah ;ybits + mov byte ptr [slop6+2], ah ;ybits + mov dword ptr [slop9+2], edi ;pinc + + mov edx, 1 + mov cl, al + add cl, ah + shl edx, cl + dec edx + mov cl, ah + ror edx, cl + + mov dword ptr [slop1+2], edx ;ybits...xbits + mov dword ptr [slop5+2], edx ;ybits...xbits + + ret + +ALIGN 16 +PUBLIC slopevlin2_ +slopevlin2_: + push ebp + xor ecx, ecx + +slopevlin2begin: + mov ebp, edx +slop1: and ebp, 88000088h ;ybits...xbits +slop2: rol ebp, 6 ;ybits + add eax, _asm1 ;xinc1<>(32-xbits)) +slop3: mov cl, byte ptr [ebp+88888888h] ;bufplc + + mov ebp, esi +slop4: mov al, byte ptr [ecx+88888888h] ;paloffs +slop5: and ebp, 88000088h ;ybits...xbits +slop6: rol ebp, 6 ;ybits + add ebx, _asm3 ;xinc2<>(32-xbits)) +slop8: mov ah, byte ptr [ecx+88888888h] ;paloffs + + dec bl + mov word ptr [edi], ax +slop9: lea edi, [edi+88888888h] ;pinc + jnz short slopevlin2begin + + pop ebp + mov eax, edi + ret + + +ALIGN 16 +PUBLIC setupslopevlin_ +setupslopevlin_: + mov dword ptr [slopmach3+3], ebx ;ptr + mov dword ptr [slopmach5+2], ecx ;pinc + neg ecx + mov dword ptr [slopmach6+2], ecx ;-pinc + + mov edx, 1 + mov cl, al + shl edx, cl + dec edx + mov cl, ah + shl edx, cl + mov dword ptr [slopmach7+2], edx + + neg ah + mov byte ptr [slopmach2+2], ah + + sub ah, al + mov byte ptr [slopmach1+2], ah + + fild dword ptr _asm1 + fstp dword ptr _asm2 + ret + +ALIGN 16 +PUBLIC slopevlin_ +slopevlin_: + mov _ebpbak, ebp + mov _espbak, esp + + sub ecx, esp + mov dword ptr [slopmach4+3], ecx + + fild dword ptr _asm3 +slopmach6: lea ebp, [eax+88888888h] + fadd dword ptr _asm2 + + mov _asm1, ebx + shl ebx, 3 + + mov eax, _globalx3 + mov ecx, _globaly3 + imul eax, ebx + imul ecx, ebx + add esi, eax + add edi, ecx + + mov ebx, edx + jmp short bigslopeloop +ALIGN 16 +bigslopeloop: + fst dword ptr _fpuasm + + mov eax, _fpuasm + add eax, eax + sbb edx, edx + mov ecx, eax + shr ecx, 24 + and eax, 00ffe000h + shr eax, 11 + sub cl, 2 + mov eax, dword ptr _reciptable[eax] + shr eax, cl + xor eax, edx + mov edx, _asm1 + mov ecx, _globalx3 + mov _asm1, eax + sub eax, edx + mov edx, _globaly3 + imul ecx, eax + imul eax, edx + + fadd dword ptr _asm2 + + cmp ebx, BITSOFPRECISIONPOW + mov _asm4, ebx + mov cl, bl + jl short slopeskipmin + mov cl, BITSOFPRECISIONPOW +slopeskipmin: + +;eax: yinc............. +;ebx: 0 0 0 ? +;ecx: xinc......... cnt +;edx: ? +;esi: xplc............. +;edi: yplc............. +;ebp: videopos + + mov ebx, esi + mov edx, edi + +beginnerslopeloop: +slopmach1: shr ebx, 20 + add esi, ecx +slopmach2: shr edx, 26 +slopmach7: and ebx, 88888888h + add edi, eax +slopmach5: add ebp, 88888888h ;pinc +slopmach3: mov dl, byte ptr [ebx+edx+88888888h] ;ptr +slopmach4: mov ebx, dword ptr [esp+88888888h] + sub esp, 4 + dec cl + mov al, byte ptr [ebx+edx] ;tptr + mov ebx, esi + mov [ebp], al + mov edx, edi + jnz short beginnerslopeloop + + mov ebx, _asm4 + sub ebx, BITSOFPRECISIONPOW + jg bigslopeloop + + ffree st(0) + + mov esp, _espbak + mov ebp, _ebpbak + ret + + +ALIGN 16 +PUBLIC setuprhlineasm4_ +setuprhlineasm4_: + mov dword ptr [rmach1a+2], eax + mov dword ptr [rmach1b+2], eax + mov dword ptr [rmach1c+2], eax + mov dword ptr [rmach1d+2], eax + mov dword ptr [rmach1e+2], eax + + mov dword ptr [rmach2a+2], ebx + mov dword ptr [rmach2b+2], ebx + mov dword ptr [rmach2c+2], ebx + mov dword ptr [rmach2d+2], ebx + mov dword ptr [rmach2e+2], ebx + + mov dword ptr [rmach3a+2], ecx + mov dword ptr [rmach3b+2], ecx + mov dword ptr [rmach3c+2], ecx + mov dword ptr [rmach3d+2], ecx + mov dword ptr [rmach3e+2], ecx + + mov dword ptr [rmach4a+2], edx + mov dword ptr [rmach4b+2], edx + mov dword ptr [rmach4c+2], edx + mov dword ptr [rmach4d+2], edx + mov dword ptr [rmach4e+2], edx + + mov dword ptr [rmach5a+2], esi + mov dword ptr [rmach5b+2], esi + mov dword ptr [rmach5c+2], esi + mov dword ptr [rmach5d+2], esi + mov dword ptr [rmach5e+2], esi + ret + + ;Non power of 2, non masking, with palookup method #1 (6 clock cycles) + ;eax: dat dat dat dat + ;ebx: bufplc + ;ecx: 0 dat + ;edx: xlo + ;esi: ylo + ;edi: videopos/cnt + ;ebp: tempvar + ;esp: +ALIGN 16 +PUBLIC rhlineasm4_ +rhlineasm4_: + push ebp + + cmp eax, 0 + jle endrhline + + lea ebp, [edi-4] + sub ebp, eax + mov dword ptr [rmach6a+2], ebp + add ebp, 3 + mov dword ptr [rmach6b+2], ebp + mov edi, eax + test edi, 3 + jz short begrhline + jmp short startrhline1 + +ALIGN 16 +startrhline1: + mov cl, byte ptr [ebx] ;bufplc +rmach1e: sub edx, 88888888h ;xlo + sbb ebp, ebp +rmach2e: sub esi, 88888888h ;ylo +rmach3e: sbb ebx, 88888888h ;xhi*tilesizy + yhi+ycarry +rmach4e: mov al, byte ptr [ecx+88888888h] ;palookup +rmach5e: and ebp, 88888888h ;tilesizy +rmach6b: mov byte ptr [edi+88888888h], al ;vidcntoffs + sub ebx, ebp + dec edi + test edi, 3 + jnz short startrhline1 + test edi, edi + jz endrhline + +begrhline: + mov cl, byte ptr [ebx] ;bufplc +rmach1a: sub edx, 88888888h ;xlo + sbb ebp, ebp +rmach2a: sub esi, 88888888h ;ylo +rmach3a: sbb ebx, 88888888h ;xhi*tilesizy + yhi+ycarry +rmach5a: and ebp, 88888888h ;tilesizy + sub ebx, ebp + +rmach1b: sub edx, 88888888h ;xlo + sbb ebp, ebp +rmach4a: mov ah, byte ptr [ecx+88888888h] ;palookup + mov cl, byte ptr [ebx] ;bufplc +rmach2b: sub esi, 88888888h ;ylo +rmach3b: sbb ebx, 88888888h ;xhi*tilesizy + yhi+ycarry +rmach5b: and ebp, 88888888h ;tilesizy +rmach4b: mov al, byte ptr [ecx+88888888h] ;palookup + sub ebx, ebp + + shl eax, 16 + + mov cl, byte ptr [ebx] ;bufplc +rmach1c: sub edx, 88888888h ;xlo + sbb ebp, ebp +rmach2c: sub esi, 88888888h ;ylo +rmach3c: sbb ebx, 88888888h ;xhi*tilesizy + yhi+ycarry +rmach5c: and ebp, 88888888h ;tilesizy + sub ebx, ebp + +rmach1d: sub edx, 88888888h ;xlo + sbb ebp, ebp +rmach4c: mov ah, byte ptr [ecx+88888888h] ;palookup + mov cl, byte ptr [ebx] ;bufplc +rmach2d: sub esi, 88888888h ;ylo +rmach3d: sbb ebx, 88888888h ;xhi*tilesizy + yhi+ycarry +rmach5d: and ebp, 88888888h ;tilesizy +rmach4d: mov al, byte ptr [ecx+88888888h] ;palookup + sub ebx, ebp + +rmach6a: mov dword ptr [edi+88888888h], eax ;vidcntoffs + sub edi, 4 + jnz begrhline +endrhline: + pop ebp + ret + +ALIGN 16 +PUBLIC setuprmhlineasm4_ +setuprmhlineasm4_: + mov dword ptr [rmmach1+2], eax + mov dword ptr [rmmach2+2], ebx + mov dword ptr [rmmach3+2], ecx + mov dword ptr [rmmach4+2], edx + mov dword ptr [rmmach5+2], esi + ret + +ALIGN 16 +PUBLIC rmhlineasm4_ +rmhlineasm4_: + push ebp + + cmp eax, 0 + jle short endrmhline + + lea ebp, [edi-1] + sub ebp, eax + mov dword ptr [rmmach6+2], ebp + mov edi, eax + jmp short begrmhline + +ALIGN 16 +begrmhline: + mov cl, byte ptr [ebx] ;bufplc +rmmach1: sub edx, 88888888h ;xlo + sbb ebp, ebp +rmmach2: sub esi, 88888888h ;ylo +rmmach3: sbb ebx, 88888888h ;xhi*tilesizy + yhi+ycarry +rmmach5: and ebp, 88888888h ;tilesizy + cmp cl, 255 + je short rmskip +rmmach4: mov al, byte ptr [ecx+88888888h] ;palookup +rmmach6: mov byte ptr [edi+88888888h], al ;vidcntoffs +rmskip: + sub ebx, ebp + dec edi + jnz short begrmhline +endrmhline: + pop ebp + ret + +ALIGN 16 +PUBLIC setupqrhlineasm4_ +setupqrhlineasm4_: + mov dword ptr [qrmach2e+2], ebx + mov dword ptr [qrmach3e+2], ecx + xor edi, edi + sub edi, ecx + mov dword ptr [qrmach7a+2], edi + mov dword ptr [qrmach7b+2], edi + + add ebx, ebx + adc ecx, ecx + mov dword ptr [qrmach2a+2], ebx + mov dword ptr [qrmach2b+2], ebx + mov dword ptr [qrmach3a+2], ecx + mov dword ptr [qrmach3b+2], ecx + + mov dword ptr [qrmach4a+2], edx + mov dword ptr [qrmach4b+2], edx + mov dword ptr [qrmach4c+2], edx + mov dword ptr [qrmach4d+2], edx + mov dword ptr [qrmach4e+2], edx + ret + + ;Non power of 2, non masking, with palookup method (FASTER BUT NO SBB'S) + ;eax: dat dat dat dat + ;ebx: bufplc + ;ecx: 0 dat + ;edx: 0 dat + ;esi: ylo + ;edi: videopos/cnt + ;ebp: ? + ;esp: +ALIGN 16 +PUBLIC qrhlineasm4_ ;4 pixels in 9 cycles! 2.25 cycles/pixel +qrhlineasm4_: + push ebp + + cmp eax, 0 + jle endqrhline + + mov ebp, eax + test ebp, 3 + jz short skipqrhline1 + jmp short startqrhline1 + +ALIGN 16 +startqrhline1: + mov cl, byte ptr [ebx] ;bufplc + dec edi +qrmach2e: sub esi, 88888888h ;ylo + dec ebp +qrmach3e: sbb ebx, 88888888h ;xhi*tilesizy + yhi+ycarry +qrmach4e: mov al, byte ptr [ecx+88888888h] ;palookup + mov byte ptr [edi], al ;vidcntoffs + test ebp, 3 + jnz short startqrhline1 + test ebp, ebp + jz short endqrhline + +skipqrhline1: + mov cl, byte ptr [ebx] ;bufplc + jmp short begqrhline +ALIGN 16 +begqrhline: +qrmach7a: mov dl, byte ptr [ebx+88888888h] ;bufplc +qrmach2a: sub esi, 88888888h ;ylo +qrmach3a: sbb ebx, 88888888h ;xhi*tilesizy + yhi+ycarry +qrmach4a: mov ah, byte ptr [ecx+88888888h] ;palookup +qrmach4b: mov al, byte ptr [edx+88888888h] ;palookup + sub edi, 4 + shl eax, 16 + mov cl, byte ptr [ebx] ;bufplc +qrmach7b: mov dl, byte ptr [ebx+88888888h] ;bufplc +qrmach2b: sub esi, 88888888h ;ylo +qrmach3b: sbb ebx, 88888888h ;xhi*tilesizy + yhi+ycarry +qrmach4c: mov ah, byte ptr [ecx+88888888h] ;palookup +qrmach4d: mov al, byte ptr [edx+88888888h] ;palookup + mov cl, byte ptr [ebx] ;bufplc + mov dword ptr [edi], eax + sub ebp, 4 + jnz short begqrhline + +endqrhline: + pop ebp + ret + + +PUBLIC setupdrawslab_ +setupdrawslab_: + mov dword ptr [voxbpl1+2], eax + mov dword ptr [voxbpl2+2], eax + mov dword ptr [voxbpl3+2], eax + mov dword ptr [voxbpl4+2], eax + mov dword ptr [voxbpl5+2], eax + mov dword ptr [voxbpl6+2], eax + mov dword ptr [voxbpl7+2], eax + mov dword ptr [voxbpl8+2], eax + + mov dword ptr [voxpal1+2], ebx + mov dword ptr [voxpal2+2], ebx + mov dword ptr [voxpal3+2], ebx + mov dword ptr [voxpal4+2], ebx + mov dword ptr [voxpal5+2], ebx + mov dword ptr [voxpal6+2], ebx + mov dword ptr [voxpal7+2], ebx + mov dword ptr [voxpal8+2], ebx + ret + +ALIGN 16 +PUBLIC drawslab_ +drawslab_: + push ebp + cmp eax, 2 + je voxbegdraw2 + ja voxskip2 + xor eax, eax +voxbegdraw1: + mov ebp, ebx + shr ebp, 16 + add ebx, edx + dec ecx + mov al, byte ptr [esi+ebp] +voxpal1: mov al, byte ptr [eax+88888888h] + mov byte ptr [edi], al +voxbpl1: lea edi, [edi+88888888h] + jnz voxbegdraw1 + pop ebp + ret + +voxbegdraw2: + mov ebp, ebx + shr ebp, 16 + add ebx, edx + xor eax, eax + dec ecx + mov al, byte ptr [esi+ebp] +voxpal2: mov al, byte ptr [eax+88888888h] + mov ah, al + mov word ptr [edi], ax +voxbpl2: lea edi, [edi+88888888h] + jnz voxbegdraw2 + pop ebp + ret + +voxskip2: + cmp eax, 4 + jne voxskip4 + xor eax, eax +voxbegdraw4: + mov ebp, ebx + add ebx, edx + shr ebp, 16 + xor eax, eax + mov al, byte ptr [esi+ebp] +voxpal3: mov al, byte ptr [eax+88888888h] + mov ah, al + shl eax, 8 + mov al, ah + shl eax, 8 + mov al, ah + mov dword ptr [edi], eax +voxbpl3: add edi, 88888888h + dec ecx + jnz voxbegdraw4 + pop ebp + ret + +voxskip4: + add eax, edi + + test edi, 1 + jz voxskipslab1 + cmp edi, eax + je voxskipslab1 + + push eax + push ebx + push ecx + push edi +voxbegslab1: + mov ebp, ebx + add ebx, edx + shr ebp, 16 + xor eax, eax + mov al, byte ptr [esi+ebp] +voxpal4: mov al, byte ptr [eax+88888888h] + mov byte ptr [edi], al +voxbpl4: add edi, 88888888h + dec ecx + jnz voxbegslab1 + pop edi + pop ecx + pop ebx + pop eax + inc edi + +voxskipslab1: + push eax + test edi, 2 + jz voxskipslab2 + dec eax + cmp edi, eax + jge voxskipslab2 + + push ebx + push ecx + push edi +voxbegslab2: + mov ebp, ebx + add ebx, edx + shr ebp, 16 + xor eax, eax + mov al, byte ptr [esi+ebp] +voxpal5: mov al, byte ptr [eax+88888888h] + mov ah, al + mov word ptr [edi], ax +voxbpl5: add edi, 88888888h + dec ecx + jnz voxbegslab2 + pop edi + pop ecx + pop ebx + add edi, 2 + +voxskipslab2: + mov eax, [esp] + + sub eax, 3 + cmp edi, eax + jge voxskipslab3 + +voxprebegslab3: + push ebx + push ecx + push edi +voxbegslab3: + mov ebp, ebx + add ebx, edx + shr ebp, 16 + xor eax, eax + mov al, byte ptr [esi+ebp] +voxpal6: mov al, byte ptr [eax+88888888h] + mov ah, al + shl eax, 8 + mov al, ah + shl eax, 8 + mov al, ah + mov dword ptr [edi], eax +voxbpl6: add edi, 88888888h + dec ecx + jnz voxbegslab3 + pop edi + pop ecx + pop ebx + add edi, 4 + + mov eax, [esp] + + sub eax, 3 + cmp edi, eax + jl voxprebegslab3 + +voxskipslab3: + mov eax, [esp] + + dec eax + cmp edi, eax + jge voxskipslab4 + + push ebx + push ecx + push edi +voxbegslab4: + mov ebp, ebx + add ebx, edx + shr ebp, 16 + xor eax, eax + mov al, byte ptr [esi+ebp] +voxpal7: mov al, byte ptr [eax+88888888h] + mov ah, al + mov word ptr [edi], ax +voxbpl7: add edi, 88888888h + dec ecx + jnz voxbegslab4 + pop edi + pop ecx + pop ebx + add edi, 2 + +voxskipslab4: + pop eax + + cmp edi, eax + je voxskipslab5 + +voxbegslab5: + mov ebp, ebx + add ebx, edx + shr ebp, 16 + xor eax, eax + mov al, byte ptr [esi+ebp] +voxpal8: mov al, byte ptr [eax+88888888h] + mov byte ptr [edi], al +voxbpl8: add edi, 88888888h + dec ecx + jnz voxbegslab5 + +voxskipslab5: + pop ebp + ret + +;modify: loinc +;eax: | dat | dat | dat | dat | +;ebx: | loplc1 | +;ecx: | loplc2 | cnthi | cntlo | +;edx: |--------|--------|--------| hiplc1 | +;esi: |--------|--------|--------| hiplc2 | +;edi: |--------|--------|--------| vidplc | +;ebp: |--------|--------|--------| hiinc | + +PUBLIC stretchhline_ +stretchhline_: + push ebp + + mov eax, ebx + shl ebx, 16 + sar eax, 16 + and ecx, 0000ffffh + or ecx, ebx + + add esi, eax + mov eax, edx + mov edx, esi + + mov ebp, eax + shl eax, 16 + sar ebp, 16 + + add ecx, eax + adc esi, ebp + + add eax, eax + adc ebp, ebp + mov dword ptr [loinc1+2], eax + mov dword ptr [loinc2+2], eax + mov dword ptr [loinc3+2], eax + mov dword ptr [loinc4+2], eax + + inc ch + + jmp begloop + +begloop: + mov al, [edx] +loinc1: sub ebx, 88888888h + sbb edx, ebp + mov ah, [esi] +loinc2: sub ecx, 88888888h + sbb esi, ebp + sub edi, 4 + shl eax, 16 +loinc3: sub ebx, 88888888h + mov al, [edx] + sbb edx, ebp + mov ah, [esi] +loinc4: sub ecx, 88888888h + sbb esi, ebp + mov [edi], eax + dec cl + jnz begloop + dec ch + jnz begloop + + pop ebp + ret + + +PUBLIC mmxoverlay_ +mmxoverlay_: + pushfd ;Check if CPUID is available + pop eax + mov ebx, eax + xor eax, 00200000h + push eax + popfd + pushfd + pop eax + cmp eax, ebx + je pentium + xor eax, eax + dw 0a20fh + test eax, eax + jz pentium + mov eax, 1 + dw 0a20fh + and eax, 00000f00h + test edx, 00800000h ;Check if MMX is available + jz nommx + cmp eax, 00000600h ;Check if P6 Family or not + jae pentiumii + jmp pentiummmx +nommx: + cmp eax, 00000600h ;Check if P6 Family or not + jae pentiumpro +pentium: + ret + +;ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ +;³ PENTIUM II Overlays ³ +;ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ +pentiumii: + ;Hline overlay (MMX doens't help) + mov byte ptr [sethlinesizes_], 0xe9 + mov dword ptr [sethlinesizes_+1], (offset prosethlinesizes_)-(offset sethlinesizes_)-5 + mov byte ptr [setpalookupaddress_], 0xe9 + mov dword ptr [setpalookupaddress_+1], (offset prosetpalookupaddress_)-(offset setpalookupaddress_)-5 + mov byte ptr [setuphlineasm4_], 0xc3 ;ret (no code required) + mov byte ptr [hlineasm4_], 0xe9 + mov dword ptr [hlineasm4_+1], (offset prohlineasm4_)-(offset hlineasm4_)-5 + + ;Vline overlay + mov byte ptr [setupvlineasm_], 0xe9 + mov dword ptr [setupvlineasm_+1], (offset prosetupvlineasm_)-(offset setupvlineasm_)-5 + mov byte ptr [vlineasm4_], 0xe9 + mov dword ptr [vlineasm4_+1], (offset provlineasm4_)-(offset vlineasm4_)-5 + + ret + +;ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ +;³ PENTIUM MMX Overlays ³ +;ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ +pentiummmx: + ret + +;ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ +;³ PENTIUM PRO Overlays ³ +;ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ +pentiumpro: + ;Hline overlay (MMX doens't help) + mov byte ptr [sethlinesizes_], 0xe9 + mov dword ptr [sethlinesizes_+1], (offset prosethlinesizes_)-(offset sethlinesizes_)-5 + mov byte ptr [setpalookupaddress_], 0xe9 + mov dword ptr [setpalookupaddress_+1], (offset prosetpalookupaddress_)-(offset setpalookupaddress_)-5 + mov byte ptr [setuphlineasm4_], 0xc3 ;ret (no code required) + mov byte ptr [hlineasm4_], 0xe9 + mov dword ptr [hlineasm4_+1], (offset prohlineasm4_)-(offset hlineasm4_)-5 + + ;Vline overlay + mov byte ptr [setupvlineasm_], 0xe9 + mov dword ptr [setupvlineasm_+1], (offset prosetupvlineasm_)-(offset setupvlineasm_)-5 + mov byte ptr [vlineasm4_], 0xe9 + mov dword ptr [vlineasm4_+1], (offset provlineasm4_)-(offset vlineasm4_)-5 + + ret + +CODE ENDS +END diff --git a/buildengine/a.c b/buildengine/a.c new file mode 100755 index 0000000..bab2262 --- /dev/null +++ b/buildengine/a.c @@ -0,0 +1,1090 @@ +// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman +// Ken Silverman's official web site: "http://www.advsys.net/ken" +// See the included license file "BUILDLIC.TXT" for license info. +// This file has been modified from Ken Silverman's original release + +/* DDOI - This file is an attempt to reimplement a_nasm.asm in C */ + +#include "platform.h" +#include "build.h" + +#define shrd(a,b,c) (((b)<<(32-(c))) | ((a)>>(c))) +#define shld(a,b,c) (((b)>>(32-(c))) | ((a)<<(c))) + +extern long asm1; +extern long asm2; +extern long asm3; +extern long asm4; + +long is_vmware_running(void) +{ + return 0; +} /* is_vmware_running */ + +/* #pragma aux mmxoverlay modify [eax ebx ecx edx] */ +long mmxoverlay(void) +{ + return 0; +} /* mmxoverlay */ + +/* #pragma aux sethlinesizes parm [eax][ebx][ecx] */ +static unsigned char machxbits_al; +static unsigned char machxbits_bl; +static long machxbits_ecx; +void sethlinesizes(long i1, long i2, long i3) +{ + machxbits_al = i1; + machxbits_bl = i2; + machxbits_ecx = i3; +} /* sethlinesizes */ + +static unsigned char* pal_eax; +void setuphlineasm4(long i1, long i2) { } +void setpalookupaddress(unsigned char *i1) { pal_eax = i1; } + +void hlineasm4(long _count, unsigned long unused_source, long _shade, unsigned long _i4, unsigned long _i5, long i6) +{ + /* force into registers (probably only useful on PowerPC)... */ + register unsigned char *dest = (unsigned char *) i6; + register unsigned long i4 = _i4; + register unsigned long i5 = _i5; + register int shifter = ((256-machxbits_al) & 0x1f); + register unsigned long source; + register long shade = _shade & 0xffffff00; + register long count = _count + 1; + register unsigned char bits = machxbits_bl; + register unsigned char *lookup = (unsigned char *) machxbits_ecx; + register unsigned char *pal = (unsigned char *) pal_eax; + register long _asm1 = asm1; + register long _asm2 = asm2; + + while (count) { + source = i5 >> shifter; + source = shld(source,i4,bits); + source = lookup[source]; + *dest = pal[shade|source]; + dest--; + i5 -= _asm1; + i4 -= _asm2; + count--; + } +} + +static long rmach_eax; +static long rmach_ebx; +static long rmach_ecx; +static long rmach_edx; +static long rmach_esi; +void setuprhlineasm4(long i1, long i2, long i3, long i4, long i5, long i6) +{ + rmach_eax = i1; + rmach_ebx = i2; + rmach_ecx = i3; + rmach_edx = i4; + rmach_esi = i5; +} /* setuprhlineasm4 */ + +void rhlineasm4(long i1, long i2, long i3, unsigned long i4, unsigned long i5, long i6) +{ + unsigned long ebp = i6 - i1; + unsigned long rmach6b = ebp-1; + + if (i1 <= 0) return; + + i6 = i1; + do { + i3 = ((i3&0xffffff00)|(*((unsigned char *)i2))); + i4 -= rmach_eax; + ebp = (((i4+rmach_eax) < i4) ? -1 : 0); + i5 -= rmach_ebx; + if ((i5 + rmach_ebx) < i5) i2 -= (rmach_ecx+1); + else i2 -= rmach_ecx; + ebp &= rmach_esi; + i1 = ((i1&0xffffff00)|(((unsigned char *)i3)[rmach_edx])); + ((unsigned char *)rmach6b)[i6] = (i1&0xff); + i2 -= ebp; + i6--; + } while (i6); +} /* rhlineasm4 */ + +static long rmmach_eax; +static long rmmach_ebx; +static long rmmach_ecx; +static long rmmach_edx; +static long rmmach_esi; +void setuprmhlineasm4(long i1, long i2, long i3, long i4, long i5, long i6) +{ + rmmach_eax = i1; + rmmach_ebx = i2; + rmmach_ecx = i3; + rmmach_edx = i4; + rmmach_esi = i5; +} /* setuprmhlineasm4 */ + +/* #pragma aux rmhlineasm4 parm [eax][ebx][ecx][edx][esi][edi] */ +void rmhlineasm4(long i1, long i2, long i3, long i4, long i5, long i6) +{ + unsigned long ebp = i6 - i1; + unsigned long rmach6b = ebp-1; + + if (i1 <= 0) return; + + i6 = i1; + do { + i3 = ((i3&0xffffff00)|(*((unsigned char *)i2))); + i4 -= rmmach_eax; + ebp = (((i4+rmmach_eax) < i4) ? -1 : 0); + i5 -= rmmach_ebx; + if ((i5 + rmmach_ebx) < i5) i2 -= (rmmach_ecx+1); + else i2 -= rmmach_ecx; + ebp &= rmmach_esi; + if ((i3&0xff) != 255) { + i1 = ((i1&0xffffff00)|(((unsigned char *)i3)[rmmach_edx])); + ((unsigned char *)rmach6b)[i6] = (i1&0xff); + } + i2 -= ebp; + i6--; + } while (i6); +} /* rmhlineasm4 */ + + +/* #pragma aux setupqrhlineasm4 parm [eax][ebx][ecx][edx][esi][edi] */ +void setupqrhlineasm4(long i1, long i2, long i3, long i4, long i5, long i6) +{ + setuprhlineasm4(i1,i2,i3,i4,i5,i6); +} /* setupqrhlineasm4 */ + + +/* #pragma aux qrhlineasm4 parm [eax][ebx][ecx][edx][esi][edi] */ +void qrhlineasm4(long i1, long i2, long i3, long i4, long i5, long i6) +{ + rhlineasm4(i1,i2,i3,i4,i5,i6); +} /* qrhlineasm4 */ + +/* #pragma aux setvlinebpl parm [eax] */ +static long fixchain; +void setvlinebpl(long i1) +{ + fixchain = i1; +} /* setvlinebpl */ + +/* #pragma aux fixtransluscence parm [eax] */ +static long tmach; +void fixtransluscence(long i1) +{ + tmach = i1; +} /* fixtransluscence */ + +long vlineasm1(long i1, long i2, long i3, long i4, long i5, long i6); + +/* #pragma aux prevlineasm1 parm [eax][ebx][ecx][edx][esi][edi] */ +static unsigned char mach3_al; +long prevlineasm1(long i1, long i2, long i3, long i4, long i5, long i6) +{ + unsigned char *source = (unsigned char *)i5; + unsigned char *dest = (unsigned char *)i6; + if (i3 == 0) + { + i1 += i4; + i4 = (long) (((unsigned long)i4) >> mach3_al); + i4 = (i4&0xffffff00) | (source[i4]&0xff); + *dest = ((unsigned char*)i2)[i4]; + return i1; + } else { + return vlineasm1(i1,i2,i3,i4,i5,i6); + } +} /* prevlineasm1 */ + +/* #pragma aux vlineasm1 parm [eax][ebx][ecx][edx][esi][edi] */ +long vlineasm1(long vince, long palookupoffse, long i3, long vplce, long bufplce, long i6) +{ + unsigned long temp; + unsigned char *dest = (unsigned char *)i6; + + i3++; + while (i3) + { + temp = ((unsigned)vplce) >> mach3_al; + temp = ((unsigned char *)bufplce)[temp]; + *dest = ((unsigned char*)palookupoffse)[temp]; + vplce += vince; + dest += fixchain; + i3--; + } + return vplce; +} /* vlineasm1 */ + +/* #pragma aux setuptvlineasm parm [eax] */ +static unsigned char transmach3_al = 32; +void setuptvlineasm(long i1) +{ + transmach3_al = (i1 & 0x1f); +} /* setuptvlineasm */ + +/* #pragma aux tvlineasm1 parm [eax][ebx][ecx][edx][esi][edi] */ +static int transrev = 0; +long tvlineasm1(long i1, long i2, long i3, long i4, long i5, long i6) +{ + unsigned char *source = (unsigned char *)i5; + unsigned char *dest = (unsigned char *)i6; + + i3++; + while (i3) + { + unsigned long temp = i4; + temp >>= transmach3_al; + temp = source[temp]; + if (temp != 255) + { + unsigned short val; + val = ((unsigned char *)i2)[temp]; + val |= ((*dest)<<8); + if (transrev) val = ((val>>8)|(val<<8)); + *dest = ((unsigned char *)tmach)[val]; + } + i4 += i1; + dest += fixchain; + i3--; + } + return i4; +} /* tvlineasm1 */ + +/* #pragma aux setuptvlineasm2 parm [eax][ebx][ecx] */ +static unsigned char tran2shr; +static unsigned long tran2pal_ebx; +static unsigned long tran2pal_ecx; +void setuptvlineasm2(long i1, long i2, long i3) +{ + tran2shr = (i1&0x1f); + tran2pal_ebx = i2; + tran2pal_ecx = i3; +} /* */ + +/* #pragma aux tvlineasm2 parm [eax][ebx][ecx][edx][esi][edi] */ +void tvlineasm2(unsigned long i1, unsigned long i2, unsigned long i3, unsigned long i4, unsigned long i5, unsigned long i6) +{ + unsigned long ebp = i1; + unsigned long tran2inca = i2; + unsigned long tran2incb = asm1; + unsigned long tran2bufa = i3; + unsigned long tran2bufb = i4; + unsigned long tran2edi = asm2; + unsigned long tran2edi1 = asm2 + 1; + + i6 -= asm2; + + do { + i1 = i5 >> tran2shr; + i2 = ebp >> tran2shr; + i5 += tran2inca; + ebp += tran2incb; + i3 = ((unsigned char *)tran2bufa)[i1]; + i4 = ((unsigned char *)tran2bufb)[i2]; + if (i3 == 255) { // skipdraw1 + if (i4 != 255) { // skipdraw3 + unsigned short val; + val = ((unsigned char *)tran2pal_ecx)[i4]; + val |= (((unsigned char *)i6)[tran2edi1]<<8); + if (transrev) val = ((val>>8)|(val<<8)); + ((unsigned char *)i6)[tran2edi1] = + ((unsigned char *)tmach)[val]; + } + } else if (i4 == 255) { // skipdraw2 + unsigned short val; + val = ((unsigned char *)tran2pal_ebx)[i3]; + val |= (((unsigned char *)i6)[tran2edi]<<8); + if (transrev) val = ((val>>8)|(val<<8)); + ((unsigned char *)i6)[tran2edi] = + ((unsigned char *)tmach)[val]; + } else { + unsigned short l = ((unsigned char *)i6)[tran2edi]<<8; + unsigned short r = ((unsigned char *)i6)[tran2edi1]<<8; + l |= ((unsigned char *)tran2pal_ebx)[i3]; + r |= ((unsigned char *)tran2pal_ecx)[i4]; + if (transrev) { + l = ((l>>8)|(l<<8)); + r = ((r>>8)|(r<<8)); + } + ((unsigned char *)i6)[tran2edi] = + ((unsigned char *)tmach)[l]; + ((unsigned char *)i6)[tran2edi1] = + ((unsigned char *)tmach)[r]; + } + i6 += fixchain; + } while (i6 > i6 - fixchain); + asm1 = i5; + asm2 = ebp; +} /* tvlineasm2 */ + + +/* #pragma aux mvlineasm1 parm [eax][ebx][ecx][edx][esi][edi] */ +static unsigned char machmv; +long mvlineasm1(long vince, long palookupoffse, long i3, long vplce, long bufplce, long i6) +{ + unsigned long temp; + unsigned char *dest = (unsigned char *)i6; + + while (i3) + { + temp = ((unsigned)vplce) >> machmv; + temp = ((unsigned char *)bufplce)[temp]; + if (temp != 255) *dest = ((unsigned char*)palookupoffse)[temp]; + vplce += vince; + dest += fixchain; + i3--; + } + return vplce; +} /* mvlineasm1 */ + +/* #pragma aux setupvlineasm parm [eax] */ +void setupvlineasm(long i1) +{ + mach3_al = (i1&0x1f); +} /* setupvlineasm */ + +extern long vplce[4], vince[4], palookupoffse[4], bufplce[4]; + +#if HAVE_POWERPC +/* About 25% faster than the scalar version on my 12" Powerbook. --ryan. */ +static void vlineasm4_altivec(long i1, long i2) +{ + unsigned int mach_array[4] = { (unsigned int) mach3_al, + (unsigned int) mach3_al, + (unsigned int) mach3_al, + (unsigned int) mach3_al }; + + unsigned int temp[4]; + unsigned long index = (i2 + ylookup[i1]); + unsigned char *dest = (unsigned char*)(-ylookup[i1]); + + register vector unsigned int vec_temp; + register vector signed int vec_vplce; + register vector signed int vec_vince; + register vector signed int vec_bufplce; + register vector unsigned int vec_shifter; + + register unsigned char *pal0 = (unsigned char *) palookupoffse[0]; + register unsigned char *pal1 = (unsigned char *) palookupoffse[1]; + register unsigned char *pal2 = (unsigned char *) palookupoffse[2]; + register unsigned char *pal3 = (unsigned char *) palookupoffse[3]; + + vec_shifter = vec_ld(0, mach_array); + vec_vplce = vec_ld(0, vplce); + vec_vince = vec_ld(0, vince); + vec_bufplce = vec_ld(0, bufplce); + + do { + vec_temp = (vector unsigned int) vec_sr(vec_vplce, vec_shifter); + vec_temp = (vector unsigned int) vec_add(vec_bufplce, (vector signed int) vec_temp); + vec_st(vec_temp, 0x00, temp); + vec_vplce = vec_add(vec_vplce, vec_vince); + dest[index] = pal0[*((unsigned char *) temp[0])]; + dest[index+1] = pal1[*((unsigned char *) temp[1])]; + dest[index+2] = pal2[*((unsigned char *) temp[2])]; + dest[index+3] = pal3[*((unsigned char *) temp[3])]; + dest += fixchain; + } while (((unsigned)dest - fixchain) < ((unsigned)dest)); + + vec_st(vec_vplce, 0, vplce); +} +#endif + +/* #pragma aux vlineasm4 parm [ecx][edi] modify [eax ebx ecx edx esi edi] */ +void vlineasm4(long i1, long i2) +{ +#if HAVE_POWERPC + if (has_altivec) + vlineasm4_altivec(i1, i2); + else +#endif + { + int i; + unsigned long temp; + unsigned long index = (i2 + ylookup[i1]); + unsigned char *dest = (unsigned char*)(-ylookup[i1]); + do { + for (i = 0; i < 4; i++) + { + temp = ((unsigned)vplce[i]) >> mach3_al; + temp = (((unsigned char*)(bufplce[i]))[temp]); + dest[index+i] = ((unsigned char*)(palookupoffse[i]))[temp]; + vplce[i] += vince[i]; + } + dest += fixchain; + } while (((unsigned)dest - fixchain) < ((unsigned)dest)); + } +} /* vlineasm4 */ + +/* #pragma aux setupmvlineasm parm [eax] */ +void setupmvlineasm(long i1) +{ + machmv = (i1&0x1f); +} /* setupmvlineasm */ + +/* #pragma aux mvlineasm4 parm [ecx][edi] modify [eax ebx ecx edx esi edi] */ +void mvlineasm4(long i1, long i2) +{ + int i; + unsigned long temp; + unsigned long index = (i2 + ylookup[i1]); + unsigned char *dest = (unsigned char*)(-ylookup[i1]); + do { + for (i = 0; i < 4; i++) + { + temp = ((unsigned)vplce[i]) >> machmv; + temp = (((unsigned char*)(bufplce[i]))[temp]); + if (temp != 255) + dest[index+i] = ((unsigned char*)(palookupoffse[i]))[temp]; + vplce[i] += vince[i]; + } + dest += fixchain; + } while (((unsigned)dest - fixchain) < ((unsigned)dest)); +} /* mvlineasm4 */ + +/* #pragma aux setupspritevline parm [eax][ebx][ecx][edx][esi][edi] */ +static long spal_eax; +static long smach_eax; +static long smach2_eax; +static long smach5_eax; +static long smach_ecx; +void setupspritevline(long i1, long i2, long i3, long i4, long i5, long i6) +{ + spal_eax = i1; + smach_eax = (i5<<16); + smach2_eax = (i5>>16)+i2; + smach5_eax = smach2_eax + i4; + smach_ecx = i3; +} /* setupspritevline */ + +/* #pragma aux spritevline parm [eax][ebx][ecx][edx][esi][edi] */ +void spritevline(long i1, unsigned long i2, long i3, unsigned long i4, long i5, long i6) +{ + unsigned char *source = (unsigned char *)i5; + unsigned char *dest = (unsigned char *)i6; + +dumblabel1: + i2 += smach_eax; + i1 = (i1&0xffffff00) | (*source&0xff); + if ((i2 - smach_eax) > i2) source += smach2_eax + 1; + else source += smach2_eax; +dumblabel2: + i1 = (i1&0xffffff00) | (((unsigned char *)spal_eax)[i1]&0xff); + *dest = i1; + dest += fixchain; + + i4 += smach_ecx; + i4--; + if (!((i4 - smach_ecx) > i4) && i4 != 0) + goto dumblabel1; + if (i4 == 0) return; + i2 += smach_eax; + i1 = (i1&0xffffff00) | (*source&0xff); + if ((i2 - smach_eax) > i2) source += smach5_eax + 1; + else source += smach5_eax; + goto dumblabel2; +} /* spritevline */ + +/* #pragma aux msetupspritevline parm [eax][ebx][ecx][edx][esi][edi] */ +static long mspal_eax; +static long msmach_eax; +static long msmach2_eax; +static long msmach5_eax; +static long msmach_ecx; +void msetupspritevline(long i1, long i2, long i3, long i4, long i5, long i6) +{ + mspal_eax = i1; + msmach_eax = (i5<<16); + msmach2_eax = (i5>>16)+i2; + msmach5_eax = smach2_eax + i4; + msmach_ecx = i3; +} /* msetupspritevline */ + +/* #pragma aux mspritevline parm [eax][ebx][ecx][edx][esi][edi] */ +void mspritevline(long i1, long i2, long i3, long i4, long i5, long i6) +{ + unsigned char *source = (unsigned char *)i5; + unsigned char *dest = (unsigned char *)i6; + +msdumblabel1: + i2 += smach_eax; + i1 = (i1&0xffffff00) | (*source&0xff); + if ((i2 - smach_eax) > i2) source += smach2_eax + 1; + else source += smach2_eax; +msdumblabel2: + if ((i1&0xff) != 255) + { + i1 = (i1&0xffffff00) | (((unsigned char *)spal_eax)[i1]&0xff); + *dest = i1; + } + dest += fixchain; + + i4 += smach_ecx; + i4--; + if (!((i4 - smach_ecx) > i4) && i4 != 0) + goto msdumblabel1; + if (i4 == 0) return; + i2 += smach_eax; + i1 = (i1&0xffffff00) | (*source&0xff); + if ((i2 - smach_eax) > i2) source += smach5_eax + 1; + else source += smach5_eax; + goto msdumblabel2; +} /* mspritevline */ + +/* #pragma aux tsetupspritevline parm [eax][ebx][ecx][edx][esi][edi] */ +unsigned long tspal; +unsigned long tsmach_eax1; +unsigned long tsmach_eax2; +unsigned long tsmach_eax3; +unsigned long tsmach_ecx; +void tsetupspritevline(long i1, long i2, long i3, long i4, long i5, long i6) +{ + tspal = i1; + tsmach_eax1 = i5 << 16; + tsmach_eax2 = (i5 >> 16) + i2; + tsmach_eax3 = tsmach_eax2 + i4; + tsmach_ecx = i3; +} /* tsetupspritevline */ + +/* #pragma aux tspritevline parm [eax][ebx][ecx][edx][esi][edi] */ +void tspritevline(long i1, long i2, long i3, unsigned long i4, long i5, long i6) +{ + while (i3) + { + i3--; + if (i3 != 0) + { + unsigned long adder = tsmach_eax2; + i4 += tsmach_ecx; + if (i4 < (i4 - tsmach_ecx)) adder = tsmach_eax3; + i1 = *((unsigned char *)i5); + i2 += tsmach_eax1; + if (i2 < (i2 - tsmach_eax1)) i5++; + i5 += adder; + // tstartsvline + if (i1 != 0xff) + { + unsigned short val; + val = ((unsigned char*)tspal)[i1]; + val |= ((*((unsigned char *)i6))<<8); + if (transrev) val = ((val>>8)|(val<<8)); + i1 = ((unsigned char *)tmach)[val]; + *((unsigned char *)i6) = (i1&0xff); + } + i6 += fixchain; + } + } +} /* tspritevline */ + +/* #pragma aux mhline parm [eax][ebx][ecx][edx][esi][edi] */ +static long mmach_eax; +static long mmach_asm3; +static long mmach_asm1; +static long mmach_asm2; +void mhlineskipmodify(long i1, unsigned long i2, unsigned long i3, long i4, long i5, long i6); +void mhline(long i1, long i2, long i3, long i4, long i5, long i6) +{ + mmach_eax = i1; + mmach_asm3 = asm3; + mmach_asm1 = asm1; + mmach_asm2 = asm2; + mhlineskipmodify(asm2,i2,i3,i4,i5,i6); +} /* mhline */ + +/* #pragma aux mhlineskipmodify parm [eax][ebx][ecx][edx][esi][edi] */ +static unsigned char mshift_al = 26; +static unsigned char mshift_bl = 6; +void mhlineskipmodify(long i1, unsigned long i2, unsigned long i3, long i4, long i5, long i6) +{ + unsigned long ebx; + int counter = (i3>>16); + while (counter >= 0) + { + ebx = i2 >> mshift_al; + ebx = shld (ebx, (unsigned)i5, mshift_bl); + i1 = ((unsigned char *)mmach_eax)[ebx]; + if ((i1&0xff) != 0xff) + *((unsigned char *)i6) = (((unsigned char*)mmach_asm3)[i1]); + + i2 += mmach_asm1; + i5 += mmach_asm2; + i6++; + counter--; + } +} /* mhlineskipmodify */ + +/* #pragma aux msethlineshift parm [eax][ebx] */ +void msethlineshift(long i1, long i2) +{ + i1 = 256-i1; + mshift_al = (i1&0x1f); + mshift_bl = (i2&0x1f); +} /* msethlineshift */ + +/* #pragma aux thline parm [eax][ebx][ecx][edx][esi][edi] */ +static long tmach_eax; +static long tmach_asm3; +static long tmach_asm1; +static long tmach_asm2; +void thlineskipmodify(long i1, unsigned long i2, unsigned long i3, long i4, long i5, long i6); +void thline(long i1, long i2, long i3, long i4, long i5, long i6) +{ + tmach_eax = i1; + tmach_asm3 = asm3; + tmach_asm1 = asm1; + tmach_asm2 = asm2; + thlineskipmodify(asm2,i2,i3,i4,i5,i6); +} /* thline */ + +/* #pragma aux thlineskipmodify parm [eax][ebx][ecx][edx][esi][edi] */ +static unsigned char tshift_al = 26; +static unsigned char tshift_bl = 6; +void thlineskipmodify(long i1, unsigned long i2, unsigned long i3, long i4, long i5, long i6) +{ + unsigned long ebx; + int counter = (i3>>16); + while (counter >= 0) + { + ebx = i2 >> tshift_al; + ebx = shld (ebx, (unsigned)i5, tshift_bl); + i1 = ((unsigned char *)tmach_eax)[ebx]; + if ((i1&0xff) != 0xff) + { + unsigned short val = (((unsigned char*)tmach_asm3)[i1]); + val |= (*((unsigned char *)i6)<<8); + if (transrev) val = ((val>>8)|(val<<8)); + *((unsigned char *)i6) = (((unsigned char*)tmach)[val]); + } + + i2 += tmach_asm1; + i5 += tmach_asm2; + i6++; + counter--; + } +} /* thlineskipmodify */ + +/* #pragma aux tsethlineshift parm [eax][ebx] */ +void tsethlineshift(long i1, long i2) +{ + i1 = 256-i1; + tshift_al = (i1&0x1f); + tshift_bl = (i2&0x1f); +} /* tsethlineshift */ + +/* #pragma aux setupslopevlin parm [eax][ebx][ecx] modify [edx] */ +static long slopemach_ebx; +static long slopemach_ecx; +static long slopemach_edx; +static unsigned char slopemach_ah1; +static unsigned char slopemach_ah2; +static float asm2_f; +typedef union { unsigned int i; float f; } bitwisef2i; +void setupslopevlin(long i1, long i2, long i3) +{ + bitwisef2i c; + slopemach_ebx = i2; + slopemach_ecx = i3; + slopemach_edx = (1<<(i1&0x1f)) - 1; + slopemach_edx <<= ((i1&0x1f00)>>8); + slopemach_ah1 = 32-((i1&0x1f00)>>8); + slopemach_ah2 = (slopemach_ah1 - (i1&0x1f)) & 0x1f; + c.f = asm2_f = (float)asm1; + asm2 = c.i; +} /* setupslopevlin */ + +extern long reciptable[2048]; +extern long globalx3, globaly3; +extern long fpuasm; +#define low32(a) ((a&0xffffffff)) +#define high32(a) ((int)(((__int64)a&(__int64)0xffffffff00000000)>>32)) + +/* #pragma aux slopevlin parm [eax][ebx][ecx][edx][esi][edi] */ +void slopevlin(long i1, unsigned long i2, long i3, long i4, long i5, long i6) +{ + bitwisef2i c; + unsigned long ecx,eax,ebx,edx,esi,edi; + float a = (float) asm3 + asm2_f; + i1 -= slopemach_ecx; + esi = i5 + low32((__int64)globalx3 * (__int64)(i2<<3)); + edi = i6 + low32((__int64)globaly3 * (__int64)(i2<<3)); + ebx = i4; + do { + // ------------- + // All this is calculating a fixed point approx. of 1/a + c.f = a; + fpuasm = eax = c.i; + edx = (((long)eax) < 0) ? 0xffffffff : 0; + eax = eax << 1; + ecx = (eax>>24); // exponent + eax = ((eax&0xffe000)>>11); + ecx = ((ecx&0xffffff00)|((ecx-2)&0xff)); + eax = reciptable[eax/4]; + eax >>= (ecx&0x1f); + eax ^= edx; + // ------------- + edx = i2; + i2 = eax; + eax -= edx; + ecx = low32((__int64)globalx3 * (__int64)eax); + eax = low32((__int64)globaly3 * (__int64)eax); + a += asm2_f; + + asm4 = ebx; + ecx = ((ecx&0xffffff00)|(ebx&0xff)); + if (ebx >= 8) ecx = ((ecx&0xffffff00)|8); + + ebx = esi; + edx = edi; + while ((ecx&0xff)) + { + ebx >>= slopemach_ah2; + esi += ecx; + edx >>= slopemach_ah1; + ebx &= slopemach_edx; + edi += eax; + i1 += slopemach_ecx; + edx = ((edx&0xffffff00)|((((unsigned char *)(ebx+edx))[slopemach_ebx]))); + ebx = *((unsigned long*)i3); // register trickery + i3 -= 4; + eax = ((eax&0xffffff00)|(*((unsigned char *)(ebx+edx)))); + ebx = esi; + *((unsigned char *)i1) = (eax&0xff); + edx = edi; + ecx = ((ecx&0xffffff00)|((ecx-1)&0xff)); + } + ebx = asm4; + ebx -= 8; // BITSOFPRECISIONPOW + } while ((long)ebx > 0); +} /* slopevlin */ + +/* #pragma aux settransnormal parm */ +void settransnormal(void) +{ + transrev = 0; +} /* settransnormal */ + +/* #pragma aux settransreverse parm */ +void settransreverse(void) +{ + transrev = 1; +} /* settransreverse */ + +/* #pragma aux setupdrawslab parm [eax][ebx] */ +long setupdrawslab(long i1, long i2) +{ + long retval = 0; + /* + __asm__ __volatile__ ( + "call _asm_setupdrawslab \n\t" + : "=a" (retval) + : "a" (i1), "b" (i2) + : "cc", "memory"); + */ + return(retval); +/* +_asm_setupdrawslab: + mov dword [voxbpl1+2], eax + mov dword [voxbpl2+2], eax + mov dword [voxbpl3+2], eax + mov dword [voxbpl4+2], eax + mov dword [voxbpl5+2], eax + mov dword [voxbpl6+2], eax + mov dword [voxbpl7+2], eax + mov dword [voxbpl8+2], eax + + mov dword [voxpal1+2], ebx + mov dword [voxpal2+2], ebx + mov dword [voxpal3+2], ebx + mov dword [voxpal4+2], ebx + mov dword [voxpal5+2], ebx + mov dword [voxpal6+2], ebx + mov dword [voxpal7+2], ebx + mov dword [voxpal8+2], ebx + ret +*/ +} /* setupdrawslab */ + +/* #pragma aux drawslab parm [eax][ebx][ecx][edx][esi][edi] */ +long drawslab(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval = 0; + /* + __asm__ __volatile__ ( + "call _asm_drawslab \n\t" + : "=a" (retval) + : "a" (i1), "b" (i2), "c" (i3), "d" (i4), "S" (i5), "D" (i6) + : "cc", "memory"); + */ + return(retval); +/* +_asm_drawslab: + push ebp + cmp eax, 2 + je voxbegdraw2 + ja voxskip2 + xor eax, eax +voxbegdraw1: + mov ebp, ebx + shr ebp, 16 + add ebx, edx + dec ecx + mov al, byte [esi+ebp] +voxpal1: mov al, byte [eax+88888888h] + mov byte [edi], al +voxbpl1: lea edi, [edi+88888888h] + jnz voxbegdraw1 + pop ebp + ret + +voxbegdraw2: + mov ebp, ebx + shr ebp, 16 + add ebx, edx + xor eax, eax + dec ecx + mov al, byte [esi+ebp] +voxpal2: mov al, byte [eax+88888888h] + mov ah, al + mov word [edi], ax +voxbpl2: lea edi, [edi+88888888h] + jnz voxbegdraw2 + pop ebp + ret + +voxskip2: + cmp eax, 4 + jne voxskip4 + xor eax, eax +voxbegdraw4: + mov ebp, ebx + add ebx, edx + shr ebp, 16 + xor eax, eax + mov al, byte [esi+ebp] +voxpal3: mov al, byte [eax+88888888h] + mov ah, al + shl eax, 8 + mov al, ah + shl eax, 8 + mov al, ah + mov dword [edi], eax +voxbpl3: add edi, 88888888h + dec ecx + jnz voxbegdraw4 + pop ebp + ret + +voxskip4: + add eax, edi + + test edi, 1 + jz voxskipslab1 + cmp edi, eax + je voxskipslab1 + + push eax + push ebx + push ecx + push edi +voxbegslab1: + mov ebp, ebx + add ebx, edx + shr ebp, 16 + xor eax, eax + mov al, byte [esi+ebp] +voxpal4: mov al, byte [eax+88888888h] + mov byte [edi], al +voxbpl4: add edi, 88888888h + dec ecx + jnz voxbegslab1 + pop edi + pop ecx + pop ebx + pop eax + inc edi + +voxskipslab1: + push eax + test edi, 2 + jz voxskipslab2 + dec eax + cmp edi, eax + jge voxskipslab2 + + push ebx + push ecx + push edi +voxbegslab2: + mov ebp, ebx + add ebx, edx + shr ebp, 16 + xor eax, eax + mov al, byte [esi+ebp] +voxpal5: mov al, byte [eax+88888888h] + mov ah, al + mov word [edi], ax +voxbpl5: add edi, 88888888h + dec ecx + jnz voxbegslab2 + pop edi + pop ecx + pop ebx + add edi, 2 + +voxskipslab2: + mov eax, [esp] + + sub eax, 3 + cmp edi, eax + jge voxskipslab3 + +voxprebegslab3: + push ebx + push ecx + push edi +voxbegslab3: + mov ebp, ebx + add ebx, edx + shr ebp, 16 + xor eax, eax + mov al, byte [esi+ebp] +voxpal6: mov al, byte [eax+88888888h] + mov ah, al + shl eax, 8 + mov al, ah + shl eax, 8 + mov al, ah + mov dword [edi], eax +voxbpl6: add edi, 88888888h + dec ecx + jnz voxbegslab3 + pop edi + pop ecx + pop ebx + add edi, 4 + + mov eax, [esp] + + sub eax, 3 + cmp edi, eax + jl voxprebegslab3 + +voxskipslab3: + mov eax, [esp] + + dec eax + cmp edi, eax + jge voxskipslab4 + + push ebx + push ecx + push edi +voxbegslab4: + mov ebp, ebx + add ebx, edx + shr ebp, 16 + xor eax, eax + mov al, byte [esi+ebp] +voxpal7: mov al, byte [eax+88888888h] + mov ah, al + mov word [edi], ax +voxbpl7: add edi, 88888888h + dec ecx + jnz voxbegslab4 + pop edi + pop ecx + pop ebx + add edi, 2 + +voxskipslab4: + pop eax + + cmp edi, eax + je voxskipslab5 + +voxbegslab5: + mov ebp, ebx + add ebx, edx + shr ebp, 16 + xor eax, eax + mov al, byte [esi+ebp] +voxpal8: mov al, byte [eax+88888888h] + mov byte [edi], al +voxbpl8: add edi, 88888888h + dec ecx + jnz voxbegslab5 + +voxskipslab5: + pop ebp + ret +*/ +} /* drawslab */ + +/* #pragma aux stretchhline parm [eax][ebx][ecx][edx][esi][edi] */ +long stretchhline(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval = 0; + /* + __asm__ __volatile__ ( + "call _asm_stretchhline \n\t" + : "=a" (retval) + : "a" (i1), "b" (i2), "c" (i3), "d" (i4), "S" (i5), "D" (i6) + : "cc", "memory"); + */ + return(retval); +/* +_asm_stretchhline: + push ebp + + mov eax, ebx + shl ebx, 16 + sar eax, 16 + and ecx, 0000ffffh + or ecx, ebx + + add esi, eax + mov eax, edx + mov edx, esi + + mov ebp, eax + shl eax, 16 + sar ebp, 16 + + add ecx, eax + adc esi, ebp + + add eax, eax + adc ebp, ebp + mov dword [loinc1+2], eax + mov dword [loinc2+2], eax + mov dword [loinc3+2], eax + mov dword [loinc4+2], eax + + inc ch + + jmp begloop + +begloop: + mov al, [edx] +loinc1: sub ebx, 88888888h + sbb edx, ebp + mov ah, [esi] +loinc2: sub ecx, 88888888h + sbb esi, ebp + sub edi, 4 + shl eax, 16 +loinc3: sub ebx, 88888888h + mov al, [edx] + sbb edx, ebp + mov ah, [esi] +loinc4: sub ecx, 88888888h + sbb esi, ebp + mov [edi], eax + dec cl + jnz begloop + dec ch + jnz begloop + + pop ebp + ret +*/ +} /* stretchhline */ diff --git a/buildengine/a.h b/buildengine/a.h new file mode 100755 index 0000000..2cd2670 --- /dev/null +++ b/buildengine/a.h @@ -0,0 +1,181 @@ +/* + * "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman + * Ken Silverman's official web site: "http://www.advsys.net/ken" + * See the included license file "BUILDLIC.TXT" for license info. + * This file IS NOT A PART OF Ken Silverman's original release + */ + +#ifndef _INCLUDE_A_H_ +#define _INCLUDE_A_H_ + +#if (defined __WATCOMC__) +#error Do not include this header with Watcom C. +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +long mmxoverlay(void); +long sethlinesizes(long,long,long); +long setpalookupaddress(char *); +long setuphlineasm4(long,long); +long hlineasm4(long,long,long,long,long,long); +long setuprhlineasm4(long,long,long,long,long,long); +long rhlineasm4(long,long,long,long,long,long); +long setuprmhlineasm4(long,long,long,long,long,long); +long rmhlineasm4(long,long,long,long,long,long); +long setupqrhlineasm4(long,long,long,long,long,long); +long qrhlineasm4(long,long,long,long,long,long); +long setvlinebpl(long); +long fixtransluscence(long); +long prevlineasm1(long,long,long,long,long,long); +long vlineasm1(long,long,long,long,long,long); +long setuptvlineasm(long); +long tvlineasm1(long,long,long,long,long,long); +long setuptvlineasm2(long,long,long); +long tvlineasm2(long,long,long,long,long,long); +long mvlineasm1(long,long,long,long,long,long); +long setupvlineasm(long); +long vlineasm4(long,long); +long setupmvlineasm(long); +long mvlineasm4(long,long); +void setupspritevline(long,long,long,long,long,long); +void spritevline(long,long,long,long,long,long); +void msetupspritevline(long,long,long,long,long,long); +void mspritevline(long,long,long,long,long,long); +void tsetupspritevline(long,long,long,long,long,long); +void tspritevline(long,long,long,long,long,long); +long mhline(long,long,long,long,long,long); +long mhlineskipmodify(long,long,long,long,long,long); +long msethlineshift(long,long); +long thline(long,long,long,long,long,long); +long thlineskipmodify(long,long,long,long,long,long); +long tsethlineshift(long,long); +long setupslopevlin(long,long,long); +long slopevlin(long,long,long,long,long,long); +long settransnormal(void); +long settransreverse(void); +long setupdrawslab(long,long); +long drawslab(long,long,long,long,long,long); +long stretchhline(long,long,long,long,long,long); +long is_vmware_running(void); + + /* !!! This part might be better stated as "USE_ASM". --ryan. */ +#ifdef USE_I386_ASM + long asm_mmxoverlay(void); + long asm_sethlinesizes(long,long,long); + long asm_setpalookupaddress(char *); + long asm_setuphlineasm4(long,long); + long asm_hlineasm4(long,long,long,long,long,long); + long asm_setuprhlineasm4(long,long,long,long,long,long); + long asm_rhlineasm4(long,long,long,long,long,long); + long asm_setuprmhlineasm4(long,long,long,long,long,long); + long asm_rmhlineasm4(long,long,long,long,long,long); + long asm_setupqrhlineasm4(long,long,long,long,long,long); + long asm_qrhlineasm4(long,long,long,long,long,long); + long asm_setvlinebpl(long); + long asm_fixtransluscence(long); + long asm_prevlineasm1(long,long,long,long,long,long); + long asm_vlineasm1(long,long,long,long,long,long); + long asm_setuptvlineasm(long); + long asm_tvlineasm1(long,long,long,long,long,long); + long asm_setuptvlineasm2(long,long,long); + long asm_tvlineasm2(long,long,long,long,long,long); + long asm_mvlineasm1(long,long,long,long,long,long); + long asm_setupvlineasm(long); + long asm_vlineasm4(long,long); + long asm_setupmvlineasm(long); + long asm_mvlineasm4(long,long); + void asm_setupspritevline(long,long,long,long,long,long); + void asm_spritevline(long,long,long,long,long,long); + void asm_msetupspritevline(long,long,long,long,long,long); + void asm_mspritevline(long,long,long,long,long,long); + void asm_tsetupspritevline(long,long,long,long,long,long); + void asm_tspritevline(long,long,long,long,long,long); + long asm_mhline(long,long,long,long,long,long); + long asm_mhlineskipmodify(long,long,long,long,long,long); + long asm_msethlineshift(long,long); + long asm_thline(long,long,long,long,long,long); + long asm_thlineskipmodify(long,long,long,long,long,long); + long asm_tsethlineshift(long,long); + long asm_setupslopevlin(long,long,long); + long asm_slopevlin(long,long,long,long,long,long); + long asm_settransnormal(void); + long asm_settransreverse(void); + long asm_setupdrawslab(long,long); + long asm_drawslab(long,long,long,long,long,long); + long asm_stretchhline(long,long,long,long,long,long); + long asm_isvmwarerunning(void); + + /* + * !!! I need a reference to this, for mprotect(), but the actual function + * !!! is never called in BUILD...just from other ASM routines. --ryan. + */ + long asm_prohlineasm4(void); + + #if ((defined __GNUC__) && (!defined C_IDENTIFIERS_UNDERSCORED)) + + long asm_mmxoverlay(void) __attribute__ ((alias ("_asm_mmxoverlay"))); + long asm_sethlinesizes(long,long,long) __attribute__ ((alias ("_asm_sethlinesizes"))); + long asm_setpalookupaddress(char *) __attribute__ ((alias ("_asm_setpalookupaddress"))); + long asm_setuphlineasm4(long,long) __attribute__ ((alias ("_asm_setuphlineasm4"))); + long asm_hlineasm4(long,long,long,long,long,long) __attribute__ ((alias ("_asm_hlineasm4"))); + long asm_setuprhlineasm4(long,long,long,long,long,long) __attribute__ ((alias ("_asm_setuprhlineasm4"))); + long asm_rhlineasm4(long,long,long,long,long,long) __attribute__ ((alias ("_asm_rhlineasm4"))); + long asm_setuprmhlineasm4(long,long,long,long,long,long) __attribute__ ((alias ("_asm_setuprmhlineasm4"))); + long asm_rmhlineasm4(long,long,long,long,long,long) __attribute__ ((alias ("_asm_rmhlineasm4"))); + long asm_setupqrhlineasm4(long,long,long,long,long,long) __attribute__ ((alias ("_asm_setupqrhlineasm4"))); + long asm_qrhlineasm4(long,long,long,long,long,long) __attribute__ ((alias ("_asm_qrhlineasm4"))); + long asm_setvlinebpl(long) __attribute__ ((alias ("_asm_setvlinebpl"))); + long asm_fixtransluscence(long) __attribute__ ((alias ("_asm_fixtransluscence"))); + long asm_prevlineasm1(long,long,long,long,long,long) __attribute__ ((alias ("_asm_prevlineasm1"))); + long asm_vlineasm1(long,long,long,long,long,long) __attribute__ ((alias ("_asm_vlineasm1"))); + long asm_setuptvlineasm(long) __attribute__ ((alias ("_asm_setuptvlineasm"))); + long asm_tvlineasm1(long,long,long,long,long,long) __attribute__ ((alias ("_asm_tvlineasm1"))); + long asm_setuptvlineasm2(long,long,long) __attribute__ ((alias ("_asm_setuptvlineasm2"))); + long asm_tvlineasm2(long,long,long,long,long,long) __attribute__ ((alias ("_asm_tvlineasm2"))); + long asm_mvlineasm1(long,long,long,long,long,long) __attribute__ ((alias ("_asm_mvlineasm1"))); + long asm_setupvlineasm(long) __attribute__ ((alias ("_asm_setupvlineasm"))); + long asm_vlineasm4(long,long) __attribute__ ((alias ("_asm_vlineasm4"))); + long asm_setupmvlineasm(long) __attribute__ ((alias ("_asm_setupmvlineasm"))); + long asm_mvlineasm4(long,long) __attribute__ ((alias ("_asm_mvlineasm4"))); + void asm_setupspritevline(long,long,long,long,long,long) __attribute__ ((alias ("_asm_setupspritevline"))); + void asm_spritevline(long,long,long,long,long,long) __attribute__ ((alias ("_asm_spritevline"))); + void asm_msetupspritevline(long,long,long,long,long,long) __attribute__ ((alias ("_asm_msetupspritevline"))); + void asm_mspritevline(long,long,long,long,long,long) __attribute__ ((alias ("_asm_mspritevline"))); + void asm_tsetupspritevline(long,long,long,long,long,long) __attribute__ ((alias ("_asm_tsetupspritevline"))); + void asm_tspritevline(long,long,long,long,long,long) __attribute__ ((alias ("_asm_tspritevline"))); + long asm_mhline(long,long,long,long,long,long) __attribute__ ((alias ("_asm_mhline"))); + long asm_mhlineskipmodify(long,long,long,long,long,long) __attribute__ ((alias ("_asm_mhlineskipmodify"))); + long asm_msethlineshift(long,long) __attribute__ ((alias ("_asm_msethlineshift"))); + long asm_thline(long,long,long,long,long,long) __attribute__ ((alias ("_asm_thline"))); + long asm_thlineskipmodify(long,long,long,long,long,long) __attribute__ ((alias ("_asm_thlineskipmodify"))); + long asm_tsethlineshift(long,long) __attribute__ ((alias ("_asm_tsethlineshift"))); + long asm_setupslopevlin(long,long,long) __attribute__ ((alias ("_asm_setupslopevlin"))); + long asm_slopevlin(long,long,long,long,long,long) __attribute__ ((alias ("_asm_slopevlin"))); + long asm_settransnormal(void) __attribute__ ((alias ("_asm_settransnormal"))); + long asm_settransreverse(void) __attribute__ ((alias ("_asm_settransreverse"))); + long asm_setupdrawslab(long,long) __attribute__ ((alias ("_asm_setupdrawslab"))); + long asm_drawslab(long,long,long,long,long,long) __attribute__ ((alias ("_asm_drawslab"))); + long asm_stretchhline(long,long,long,long,long,long) __attribute__ ((alias ("_asm_stretchhline"))); + long asm_isvmwarerunning(void) __attribute__ ((alias ("_asm_isvmwarerunning"))); + + /* + * !!! I need a reference to this, for mprotect(), but the actual function + * !!! is never called in BUILD...just from other ASM routines. --ryan. + */ + long asm_prohlineasm4(void) __attribute__ ((alias ("_asm_prohlineasm4"))); + + #endif /* ELF/GCC */ +#endif /* defined USE_I386_ASM */ + +#ifdef __cplusplus +} +#endif + +#endif /* include-once-blocker. */ + +/* end of a.h ... */ + + diff --git a/buildengine/a_gnu.c b/buildengine/a_gnu.c new file mode 100755 index 0000000..504c7a4 --- /dev/null +++ b/buildengine/a_gnu.c @@ -0,0 +1,546 @@ +/* + * "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman + * Ken Silverman's official web site: "http://www.advsys.net/ken" + * See the included license file "BUILDLIC.TXT" for license info. + * This file has been modified from Ken Silverman's original release + * (Actually, all the ASM was from a.asm, but that's obviously commented out.) + */ + +#include "a.h" + +#if (!defined USE_I386_ASM) +#error Please define USE_I386_ASM if you want to compile this. +#endif + +#if (!defined __GNUC__) && (!defined __ICC) +#error This file is filled with GNU C-specific inline asm. +#endif + + + +long is_vmware_running(void) +{ + int retval; + __asm__ __volatile__ ( + "call _asm_isvmwarerunning \n\t" + : "=a" (retval) + : + : "cc", "ebx", "ecx", "edx", "memory"); + return(retval); +} /* is_vmware_running */ + + +/* #pragma aux mmxoverlay modify [eax ebx ecx edx] */ +long mmxoverlay(void) +{ + long retval; + __asm__ __volatile__ ( + "call _asm_mmxoverlay \n\t" + : "=a" (retval) + : + : "cc", "ebx", "ecx", "edx", "memory"); + return(retval); +} /* mmxoverlay */ + +/* #pragma aux sethlinesizes parm [eax][ebx][ecx] */ +long sethlinesizes(long i1, long i2, long i3) +{ + long retval; + __asm__ __volatile__ ( + "call _asm_sethlinesizes \n\t" + : "=a" (retval) + : "a" (i1), "b" (i2), "c" (i3) + : "cc", "memory"); + return(retval); +} /* sethlinesizes */ + +/* #pragma aux setpalookupaddress parm [eax] */ +long setpalookupaddress(char *i1) +{ + long retval; + __asm__ __volatile__ ( + "call _asm_setpalookupaddress \n\t" + : "=a" (retval) + : "a" (i1) + : "cc", "memory"); + return(retval); +} /* setpalookupaddress */ + +/* #pragma aux setuphlineasm4 parm [eax][ebx] */ +long setuphlineasm4(long i1, long i2) +{ + long retval; + __asm__ __volatile__ ( + "call _asm_setuphlineasm4 \n\t" + : "=a" (retval) + : "a" (i1), "b" (i2) + : "cc", "memory"); + return(retval); +} /* setuphlineasm4 */ + +/* #pragma aux hlineasm4 parm [eax][ebx][ecx][edx][esi][edi] */ +long hlineasm4(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval; + __asm__ __volatile__ ( + "call _asm_hlineasm4 \n\t" + : "=a" (retval) + : "a" (i1), "b" (i2), "c" (i3), "d" (i4), "S" (i5), "D" (i6) + : "cc", "memory"); + return(retval); +} /* hlineasm4 */ + +/* #pragma aux setuprhlineasm4 parm [eax][ebx][ecx][edx][esi][edi] */ +long setuprhlineasm4(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval; + __asm__ __volatile__ ( + "call _asm_setuprhlineasm4 \n\t" + : "=a" (retval) + : "a" (i1), "b" (i2), "c" (i3), "d" (i4), "S" (i5), "D" (i6) + : "cc", "memory"); + return(retval); +} /* setuprhlineasm4 */ + + + +/* #pragma aux rhlineasm4 parm [eax][ebx][ecx][edx][esi][edi] */ +long rhlineasm4(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval; + __asm__ __volatile__ ( + "call _asm_rhlineasm4 \n\t" + : "=a" (retval) + : "a" (i1), "b" (i2), "c" (i3), "d" (i4), "S" (i5), "D" (i6) + : "cc", "memory"); + return(retval); +} /* rhlineasm4 */ + + +/* #pragma aux setuprmhlineasm4 parm [eax][ebx][ecx][edx][esi][edi] */ +long setuprmhlineasm4(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval; + __asm__ __volatile__ ( + "call _asm_setuprmhlineasm4 \n\t" + : "=a" (retval) + : "a" (i1), "b" (i2), "c" (i3), "d" (i4), "S" (i5), "D" (i6) + : "cc", "memory"); + return(retval); +} /* setuprmhlineasm4 */ + +/* #pragma aux rmhlineasm4 parm [eax][ebx][ecx][edx][esi][edi] */ +long rmhlineasm4(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval; + __asm__ __volatile__ ( + "call _asm_rmhlineasm4 \n\t" + : "=a" (retval) + : "a" (i1), "b" (i2), "c" (i3), "d" (i4), "S" (i5), "D" (i6) + : "cc", "memory"); + return(retval); +} /* rmhlineasm4 */ + + +/* #pragma aux setupqrhlineasm4 parm [eax][ebx][ecx][edx][esi][edi] */ +long setupqrhlineasm4(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval; + __asm__ __volatile__ ( + "call _asm_setupqrhlineasm4 \n\t" + : "=a" (retval) + : "a" (i1), "b" (i2), "c" (i3), "d" (i4), "S" (i5), "D" (i6) + : "cc", "memory"); + return(retval); +} /* setupqrhlineasm4 */ + + +/* #pragma aux qrhlineasm4 parm [eax][ebx][ecx][edx][esi][edi] */ +long qrhlineasm4(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval; + __asm__ __volatile__ ( + "call _asm_qrhlineasm4 \n\t" + : "=a" (retval) + : "a" (i1), "b" (i2), "c" (i3), "d" (i4), "S" (i5), "D" (i6) + : "cc", "memory"); + return(retval); +} /* qrhlineasm4 */ + +/* #pragma aux setvlinebpl parm [eax] */ +long setvlinebpl(long i1) +{ + long retval; + __asm__ __volatile__ ( + "call _asm_setvlinebpl \n\t" + : "=a" (retval) + : "a" (i1) + : "cc", "memory"); + return(retval); +} /* setvlinebpl */ + +/* #pragma aux fixtransluscence parm [eax] */ +long fixtransluscence(long i1) +{ + long retval; + __asm__ __volatile__ ( + "call _asm_fixtransluscence \n\t" + : "=a" (retval) + : "a" (i1) + : "cc", "memory"); + return(retval); +} /* fixtransluscence */ + +/* #pragma aux prevlineasm1 parm [eax][ebx][ecx][edx][esi][edi] */ +long prevlineasm1(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval; + __asm__ __volatile__ ( + "call _asm_prevlineasm1 \n\t" + : "=a" (retval) + : "a" (i1), "b" (i2), "c" (i3), "d" (i4), "S" (i5), "D" (i6) + : "cc", "memory"); + return(retval); +} /* prevlineasm1 */ + +/* #pragma aux vlineasm1 parm [eax][ebx][ecx][edx][esi][edi] */ +long vlineasm1(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval; + __asm__ __volatile__ ( + "call _asm_vlineasm1 \n\t" + : "=a" (retval) + : "a" (i1), "b" (i2), "c" (i3), "d" (i4), "S" (i5), "D" (i6) + : "cc", "memory"); + return(retval); +} /* vlineasm1 */ + + +/* #pragma aux setuptvlineasm parm [eax] */ +long setuptvlineasm(long i1) +{ + long retval; + __asm__ __volatile__ ( + "call _asm_setuptvlineasm \n\t" + : "=a" (retval) + : "a" (i1) + : "cc", "memory"); + return(retval); +} /* setuptvlineasm */ + + +/* #pragma aux tvlineasm1 parm [eax][ebx][ecx][edx][esi][edi] */ +long tvlineasm1(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval; + __asm__ __volatile__ ( + "call _asm_tvlineasm1 \n\t" + : "=a" (retval) + : "a" (i1), "b" (i2), "c" (i3), "d" (i4), "S" (i5), "D" (i6) + : "cc", "memory"); + return(retval); +} /* tvlineasm1 */ + +/* #pragma aux setuptvlineasm2 parm [eax][ebx][ecx] */ +long setuptvlineasm2(long i1, long i2, long i3) +{ + long retval; + __asm__ __volatile__ ( + "call _asm_setuptvlineasm2 \n\t" + : "=a" (retval) + : "a" (i1), "b" (i2), "c" (i3) + : "cc", "memory"); + return(retval); +} /* */ + +/* #pragma aux tvlineasm2 parm [eax][ebx][ecx][edx][esi][edi] */ +long tvlineasm2(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval; + __asm__ __volatile__ ( + "call _asm_tvlineasm2 \n\t" + : "=a" (retval) + : "a" (i1), "b" (i2), "c" (i3), "d" (i4), "S" (i5), "D" (i6) + : "cc", "memory"); + return(retval); +} /* tvlineasm2 */ + + +/* #pragma aux mvlineasm1 parm [eax][ebx][ecx][edx][esi][edi] */ +long mvlineasm1(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval; + __asm__ __volatile__ ( + "call _asm_mvlineasm1 \n\t" + : "=a" (retval) + : "a" (i1), "b" (i2), "c" (i3), "d" (i4), "S" (i5), "D" (i6) + : "cc", "memory"); + return(retval); +} /* mvlineasm1 */ + +/* #pragma aux setupvlineasm parm [eax] */ +long setupvlineasm(long i1) +{ + long retval; + __asm__ __volatile__ ( + "call _asm_setupvlineasm \n\t" + : "=a" (retval) + : "a" (i1) + : "cc", "memory"); + return(retval); +} /* setupvlineasm */ + +/* #pragma aux vlineasm4 parm [ecx][edi] modify [eax ebx ecx edx esi edi] */ +long vlineasm4(long i1, long i2) +{ + long retval; + __asm__ __volatile__ ( + "call _asm_vlineasm4 \n\t" + : "=a" (retval) + : "c" (i1), "D" (i2) + : "cc", "ebx", "edx", "esi", "memory"); + return(retval); +} /* vlineasm4 */ + +/* #pragma aux setupmvlineasm parm [eax] */ +long setupmvlineasm(long i1) +{ + long retval; + __asm__ __volatile__ ( + "call _asm_setupmvlineasm \n\t" + : "=a" (retval) + : "a" (i1) + : "cc", "memory"); + return(retval); +} /* setupmvlineasm */ + +/* #pragma aux mvlineasm4 parm [ecx][edi] modify [eax ebx ecx edx esi edi] */ +long mvlineasm4(long i1, long i2) +{ + long retval; + __asm__ __volatile__ ( + "call _asm_mvlineasm4 \n\t" + : "=a" (retval) + : "c" (i1), "D" (i2) + : "cc", "ebx", "edx", "esi", "memory"); + return(retval); +} /* mvlineasm4 */ + +/* #pragma aux setupspritevline parm [eax][ebx][ecx][edx][esi][edi] */ +void setupspritevline(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm__ __volatile__ ( + "call _asm_setupspritevline \n\t" + : + : "a" (i1), "b" (i2), "c" (i3), "d" (i4), "S" (i5), "D" (i6) + : "cc", "memory"); +} /* setupspritevline */ + +/* #pragma aux spritevline parm [eax][ebx][ecx][edx][esi][edi] */ +void spritevline(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm__ __volatile__ ( + "call _asm_spritevline \n\t" + : + : "a" (i1), "b" (i2), "c" (i3), "d" (i4), "S" (i5), "D" (i6) + : "cc", "memory"); +} /* spritevline */ + +/* #pragma aux msetupspritevline parm [eax][ebx][ecx][edx][esi][edi] */ +void msetupspritevline(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm__ __volatile__ ( + "call _asm_msetupspritevline \n\t" + : + : "a" (i1), "b" (i2), "c" (i3), "d" (i4), "S" (i5), "D" (i6) + : "cc", "memory"); +} /* msetupspritevline */ + +/* #pragma aux mspritevline parm [eax][ebx][ecx][edx][esi][edi] */ +void mspritevline(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm__ __volatile__ ( + "call _asm_mspritevline \n\t" + : + : "a" (i1), "b" (i2), "c" (i3), "d" (i4), "S" (i5), "D" (i6) + : "cc", "memory"); +} /* mspritevline */ + +/* #pragma aux tsetupspritevline parm [eax][ebx][ecx][edx][esi][edi] */ +void tsetupspritevline(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm__ __volatile__ ( + "call _asm_tsetupspritevline \n\t" + : + : "a" (i1), "b" (i2), "c" (i3), "d" (i4), "S" (i5), "D" (i6) + : "cc", "memory"); +} /* tsetupspritevline */ + +/* #pragma aux tspritevline parm [eax][ebx][ecx][edx][esi][edi] */ +void tspritevline(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm__ __volatile__ ( + "call _asm_tspritevline \n\t" + : + : "a" (i1), "b" (i2), "c" (i3), "d" (i4), "S" (i5), "D" (i6) + : "cc", "memory"); +} /* tspritevline */ + +/* #pragma aux mhline parm [eax][ebx][ecx][edx][esi][edi] */ +long mhline(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval; + __asm__ __volatile__ ( + "call _asm_mhline \n\t" + : "=a" (retval) + : "a" (i1), "b" (i2), "c" (i3), "d" (i4), "S" (i5), "D" (i6) + : "cc", "memory"); + return(retval); +} /* mhline */ + +/* #pragma aux mhlineskipmodify parm [eax][ebx][ecx][edx][esi][edi] */ +long mhlineskipmodify(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval; + __asm__ __volatile__ ( + "call _asm_mhlineskipmodify \n\t" + : "=a" (retval) + : "a" (i1), "b" (i2), "c" (i3), "d" (i4), "S" (i5), "D" (i6) + : "cc", "memory"); + return(retval); +} /* mhlineskipmodify */ + +/* #pragma aux msethlineshift parm [eax][ebx] */ +long msethlineshift(long i1, long i2) +{ + long retval; + __asm__ __volatile__ ( + "call _asm_msethlineshift \n\t" + : "=a" (retval) + : "a" (i1), "b" (i2) + : "cc", "memory"); + return(retval); +} /* msethlineshift */ + +/* #pragma aux thline parm [eax][ebx][ecx][edx][esi][edi] */ +long thline(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval; + __asm__ __volatile__ ( + "call _asm_thline \n\t" + : "=a" (retval) + : "a" (i1), "b" (i2), "c" (i3), "d" (i4), "S" (i5), "D" (i6) + : "cc", "memory"); + return(retval); +} /* thline */ + +/* #pragma aux thlineskipmodify parm [eax][ebx][ecx][edx][esi][edi] */ +long thlineskipmodify(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval; + __asm__ __volatile__ ( + "call _asm_thlineskipmodify \n\t" + : "=a" (retval) + : "a" (i1), "b" (i2), "c" (i3), "d" (i4), "S" (i5), "D" (i6) + : "cc", "memory"); + return(retval); +} /* thlineskipmodify */ + +/* #pragma aux tsethlineshift parm [eax][ebx] */ +long tsethlineshift(long i1, long i2) +{ + long retval; + __asm__ __volatile__ ( + "call _asm_tsethlineshift \n\t" + : "=a" (retval) + : "a" (i1), "b" (i2) + : "cc", "memory"); + return(retval); +} /* tsethlineshift */ + +/* #pragma aux setupslopevlin parm [eax][ebx][ecx] modify [edx] */ +long setupslopevlin(long i1, long i2, long i3) +{ + long retval; + __asm__ __volatile__ ( + "call _asm_setupslopevlin \n\t" + : "=a" (retval) + : "a" (i1), "b" (i2), "c" (i3) + : "cc", "edx", "memory"); + return(retval); +} /* setupslopevlin */ + +/* #pragma aux slopevlin parm [eax][ebx][ecx][edx][esi][edi] */ +long slopevlin(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval; + __asm__ __volatile__ ( + "call _asm_slopevlin \n\t" + : "=a" (retval) + : "a" (i1), "b" (i2), "c" (i3), "d" (i4), "S" (i5), "D" (i6) + : "cc", "memory"); + return(retval); +} /* slopevlin */ + +/* #pragma aux settransnormal parm */ +long settransnormal(void) +{ + long retval; + __asm__ __volatile__ ( + "call _asm_settransnormal \n\t" + : "=a" (retval) + : + : "cc", "memory"); + return(retval); +} /* settransnormal */ + +/* #pragma aux settransreverse parm */ +long settransreverse(void) +{ + long retval; + __asm__ __volatile__ ( + "call _asm_settransreverse \n\t" + : "=a" (retval) + : + : "cc", "memory"); + return(retval); +} /* settransreverse */ + +/* #pragma aux setupdrawslab parm [eax][ebx] */ +long setupdrawslab(long i1, long i2) +{ + long retval; + __asm__ __volatile__ ( + "call _asm_setupdrawslab \n\t" + : "=a" (retval) + : "a" (i1), "b" (i2) + : "cc", "memory"); + return(retval); +} /* setupdrawslab */ + +/* #pragma aux drawslab parm [eax][ebx][ecx][edx][esi][edi] */ +long drawslab(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval; + __asm__ __volatile__ ( + "call _asm_drawslab \n\t" + : "=a" (retval) + : "a" (i1), "b" (i2), "c" (i3), "d" (i4), "S" (i5), "D" (i6) + : "cc", "memory"); + return(retval); +} /* drawslab */ + +/* #pragma aux stretchhline parm [eax][ebx][ecx][edx][esi][edi] */ +long stretchhline(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval; + __asm__ __volatile__ ( + "call _asm_stretchhline \n\t" + : "=a" (retval) + : "a" (i1), "b" (i2), "c" (i3), "d" (i4), "S" (i5), "D" (i6) + : "cc", "memory"); + return(retval); +} /* drawslab */ + +/* end of a_gnu.c ... */ + diff --git a/buildengine/a_nasm.asm b/buildengine/a_nasm.asm new file mode 100755 index 0000000..c960aee --- /dev/null +++ b/buildengine/a_nasm.asm @@ -0,0 +1,2522 @@ +; // "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman +; // Ken Silverman's official web site: "http://www.advsys.net/ken" +; // See the included license file "BUILDLIC.TXT" for license info. +; // This file has been modified from Ken Silverman's original release + +; These two aren't needed AH +;.586P +;.8087 + +;include mmx.inc ;Include this if using < WATCOM 11.0 WASM + +;Warning: IN THIS FILE, ALL SEGMENTS ARE REMOVED. THIS MEANS THAT DS:[] +;MUST BE ADDED FOR ALL SELF-MODIFIES FOR MASM TO WORK. +; +;WASM PROBLEMS: +; 1. Requires all scaled registers (*1,*2,*4,*8) to be last thing on line +; 2. Using 'DATA' is nice for self-mod. code, but WDIS only works with 'CODE' +; +;MASM PROBLEMS: +; 1. Requires DS: to be written out for self-modifying code to work +; 2. Doesn't encode short jumps automatically like WASM +; 3. Stupidly adds wait prefix to ffree's + +; ************************ +; ** Start Data Block ** +; ************************ +SECTION .data + + ; Some C compilers insert an underscore ('_') character in front of + ; identifiers. In such a case, we need to redefine our references to + ; global indentifiers that exist in the C code. --ryan. +%ifdef C_IDENTIFIERS_UNDERSCORED +%define asm1 _asm1 +%define asm2 _asm2 +%define asm3 _asm3 +%define asm4 _asm4 +%define fpuasm _fpuasm +%define reciptable _reciptable +%define globalx3 _globalx3 +%define globaly3 _globaly3 +%define ylookup _ylookup +%define vplce _vplce +%define vince _vince +%define palookupoffse _palookupoffse +%define bufplce _bufplce +%define ebpbak _ebpbak +%define espbak _espbak +%define pow2char _pow2char +%define pow2long _pow2long +%endif + +extern asm1 +extern asm2 +extern asm3 +extern asm4 +extern fpuasm +extern reciptable +extern globalx3 +extern globaly3 +extern ylookup + +extern vplce +extern vince +extern palookupoffse +extern bufplce + +extern ebpbak +extern espbak + +extern pow2char +extern pow2long + +; These are our globally-scoped labels (i.e. functions) AH + global _asm_krecipasm + global _asm_sethlinesizes + global _asm_prosethlinesizes + global _asm_setvlinebpl + global _asm_setpalookupaddress + global _asm_prosetpalookupaddress + global _asm_setuphlineasm4 + global _asm_hlineasm4 + global _asm_prohlineasm4 + global _asm_setupvlineasm + global _asm_prosetupvlineasm + global _asm_setupmvlineasm + global _asm_setuptvlineasm + global _asm_prevlineasm1 + global _asm_vlineasm1 + global _asm_mvlineasm1 + global _asm_fixtransluscence + global _asm_settransnormal + global _asm_settransreverse + global _asm_tvlineasm1 + global _asm_vlineasm4 + global _asm_provlineasm4 + global _asm_mvlineasm4 + global _asm_setupspritevline + global _asm_spritevline + global _asm_msetupspritevline + global _asm_mspritevline + global _asm_tsetupspritevline + global _asm_tspritevline + global _asm_msethlineshift + global _asm_mhline + global _asm_mhlineskipmodify + global _asm_tsethlineshift + global _asm_thline + global _asm_thlineskipmodify + global _asm_setuptvlineasm2 + global _asm_tvlineasm2 + global _asm_setupslopevlin2 + global _asm_slopevlin2 + global _asm_setupslopevlin + global _asm_slopevlin + global _asm_setuprhlineasm4 + global _asm_rhlineasm4 + global _asm_setuprmhlineasm4 + global _asm_rmhlineasm4 + global _asm_setupqrhlineasm4 + global _asm_qrhlineasm4 + global _asm_setupdrawslab + global _asm_drawslab + global _asm_stretchhline + global _asm_mmxoverlay + + global _asm_isvmwarerunning + + +; ************************ +; ** End Data Block ** +; ************************ + + +; ************************ +; ** Start Code Block ** +; ************************ +SEGMENT .text + +; Ignore all the 'offset's in the code AH +%idefine offset + +; Align entire code block to 16 bit boundaries +ALIGN 16 + +_asm_isvmwarerunning: + mov eax,564d5868h + mov ecx,0000000ah + mov dx,5658h + in eax,dx + cmp ebx,564d5868h + jz vmware_y + xor eax,eax + ret +vmware_y: + mov eax,1h + ret + + +_asm_sethlinesizes: + mov byte [machxbits1+2], al + mov byte [machxbits2+2], al + mov byte [machxbits3+2], al + neg al + mov byte [hxsiz1+2], al + mov byte [hxsiz2+2], al + mov byte [hxsiz3+2], al + mov byte [hxsiz4+2], al + mov byte [machnegxbits1+2], al + + mov byte [hysiz1+3], bl + mov byte [hysiz2+3], bl + mov byte [hysiz3+3], bl + mov byte [hysiz4+3], bl + mov byte [hmach3a+2], bl + mov byte [hmach3b+2], bl + mov byte [hmach3c+2], bl + mov byte [hmach3d+2], bl + + mov dword [hoffs1+2], ecx + mov dword [hoffs2+2], ecx + mov dword [hoffs3+2], ecx + mov dword [hoffs4+2], ecx + mov dword [hoffs5+2], ecx + mov dword [hoffs6+2], ecx + mov dword [hoffs7+2], ecx + mov dword [hoffs8+2], ecx + + mov edx, -1 + mov cl, al + sub cl, bl + shr edx, cl + mov dword [hmach2a+1], edx + mov dword [hmach2b+1], edx + mov dword [hmach2c+1], edx + mov dword [hmach2d+1], edx + ret + +ALIGN 16 +_asm_prosethlinesizes: + mov dword [prohbuf-4], ecx + neg eax + mov ecx, eax + sub eax, ebx + mov byte [prohshru-1], al ;bl = 32-al-bl + mov eax, -1 + shr eax, cl + mov ecx, ebx + shl eax, cl + mov dword [prohand-4], eax ;((-1>>(-oal))<>(32-xbits) adc al, 88h 1 1/2 + ;bufplc mov cl, byte [edx+88888888h] 1 1/2 + ;paloffs&255 mov bl, byte [ecx+88888888h] 1 1/2 + +_asm_hlineasm4: + push ebp + + lea ebp, [eax+1] + + cmp ebp, 8 + jle NEAR shorthline + + test edi, 1 + jnz short skipthe1byte + + mov eax, esi +hxsiz1: shr eax, 26 +hysiz1: shld eax, edx, 6 +hoffs1: mov cl, byte [eax+88888888h] +pal1: mov bl, byte [ecx+88888888h] + sub esi, [asm1] + sub edx, [asm2] + mov byte [edi], bl + dec edi + dec ebp + +skipthe1byte: + test edi, 2 + jnz short skipthe2byte + + mov eax, esi +hxsiz2: shr eax, 26 +hysiz2: shld eax, edx, 6 +hoffs2: mov cl, byte [eax+88888888h] +pal2: mov bh, byte [ecx+88888888h] + sub esi, [asm1] + sub edx, [asm2] + + mov eax, esi +hxsiz3: shr eax, 26 +hysiz3: shld eax, edx, 6 +hoffs3: mov cl, byte [eax+88888888h] +pal3: mov bl, byte [ecx+88888888h] + sub esi, [asm1] + sub edx, [asm2] + mov word [edi-1], bx + sub edi, 2 + sub ebp, 2 + +skipthe2byte: + + mov eax, esi +machxbits1: shl esi, 6 ;xbits +machnegxbits1: shr eax, 32-6 ;32-xbits + mov dl, al + + inc edi + + add ebx, ebx + mov eax, edx + jc beginhline64 + + mov eax, [asm1] +machxbits2: rol eax, 6 ;xbits + mov dword [hmach4a+2], eax + mov dword [hmach4b+2], eax + mov dword [hmach4c+2], eax + mov dword [hmach4d+2], eax + mov ebx, eax + mov eax, [asm2] + mov al, bl + mov dword [hmach1a+2], eax + mov dword [hmach1b+2], eax + mov dword [hmach1c+2], eax + mov dword [hmach1d+2], eax + + mov eax, edx + jmp beginhline64 + +prebeginhline64: + mov dword [edi], ebx +beginhline64: + +hmach3a: rol eax, 6 +hmach2a: and eax, 00008888h +hmach4a: sub esi, 88888888h +hmach1a: sbb edx, 88888888h + sub edi, 4 +hoffs4: mov cl, byte [eax+88888888h] + mov eax, edx + +hmach3b: rol eax, 6 +hmach2b: and eax, 00008888h +hmach4b: sub esi, 88888888h +hmach1b: sbb edx, 88888888h +pal4: mov bh, byte [ecx+88888888h] +hoffs5: mov cl, byte [eax+88888888h] + mov eax, edx + +hmach3c: rol eax, 6 +pal5: mov bl, byte [ecx+88888888h] +hmach2c: and eax, 00008888h + shl ebx, 16 +hmach4c: sub esi, 88888888h +hmach1c: sbb edx, 88888888h +hoffs6: mov cl, byte [eax+88888888h] + + mov eax, edx + ;( + +hmach3d: rol eax, 6 +hmach2d: and eax, 00008888h +hmach4d: sub esi, 88888888h +hmach1d: sbb edx, 88888888h +pal6: mov bh, byte [ecx+88888888h] +hoffs7: mov cl, byte [eax+88888888h] + mov eax, edx + sub ebp, 4 + nop +pal7: mov bl, byte [ecx+88888888h] + jnc NEAR prebeginhline64 +skipthe4byte: + + test ebp, 2 + jz skipdrawthe2 + rol ebx, 16 + mov word [edi+2], bx + sub edi, 2 +skipdrawthe2: + test ebp, 1 + jz skipdrawthe1 + shr ebx, 24 + mov byte [edi+3], bl +skipdrawthe1: + + pop ebp + ret + +shorthline: + test ebp, ebp + jz endshorthline +begshorthline: + mov eax, esi +hxsiz4: shr eax, 26 +hysiz4: shld eax, edx, 6 +hoffs8: mov cl, byte [eax+88888888h] +pal8: mov bl, byte [ecx+88888888h] + sub esi, [asm1] + sub edx, [asm2] + mov byte [edi], bl + dec edi + dec ebp + jnz begshorthline +endshorthline: + pop ebp + ret + + + ;eax: 00000000 00000000 00000000 temp---- + ;ebx: 00000000 00000000 00000000 temp---- + ;ecx: UUUUUUuu uuuuuuuu uuuuuuuu uuuuuuuu + ;edx: VVVVVVvv vvvvvvvv vvvvvvvv vvvvvvvv + ;esi: cnt----- -------- -------- -------- + ;edi: vid----- -------- -------- -------- + ;ebp: paloffs- -------- -------- -------- + ;esp: ???????? ???????? ???????? ???????? + +_asm_prohlineasm4: + push ebp + + lea ebp, [ecx+88888888h] +prohpala: + mov ecx, esi + lea esi, [eax+1] + sub edi, esi + +prohbeg: + mov eax, ecx + shr eax, 20 +prohshru: + mov ebx, edx + shr ebx, 26 +prohshrv: + and eax, 88888888h +prohand: + movzx eax, byte [eax+ebx+88888888h] +prohbuf: + mov al, [eax+ebp] + sub ecx, [asm1] + sub edx, [asm2] + mov [edi+esi], al + dec esi + jnz prohbeg + + pop ebp + ret + +ALIGN 16 +_asm_setupvlineasm: + ;First 2 lines for VLINEASM1, rest for VLINEASM4 + mov byte [premach3a+2], al + mov byte [mach3a+2], al + + push ecx + mov byte [machvsh1+2], al ;32-shy + mov byte [machvsh3+2], al ;32-shy + mov byte [machvsh5+2], al ;32-shy + mov byte [machvsh6+2], al ;32-shy + mov ah, al + sub ah, 16 + mov byte [machvsh8+2], ah ;16-shy + neg al + mov byte [machvsh7+2], al ;shy + mov byte [machvsh9+2], al ;shy + mov byte [machvsh10+2], al ;shy + mov byte [machvsh11+2], al ;shy + mov byte [machvsh12+2], al ;shy + mov cl, al + mov eax, 1 + shl eax, cl + dec eax + mov dword [machvsh2+2], eax ;(1<>sh) + ;vplc3 = (ebp<<(32-sh))+((edx&65535)<<(16-sh)) +machvsh5: shl esi, 88h ;32-sh + mov eax, edx +machvsh6: shl ebp, 88h ;32-sh + and edx, 0000ffffh +machvsh7: shr eax, 88h ;sh + add esi, eax +machvsh8: shl edx, 88h ;16-sh + add ebp, edx + mov dword [vplce + 12], esi + mov dword [vplce + 4], ebp + + pop ebp + ret + + ;eax: -------temp1------- + ;ebx: -------temp2------- + ;ecx: ylo4 --------- + ;edx: ylo2 --------- + ;esi: yhi1 yhi2 + ;edi: ---videoplc/cnt---- + ;ebp: yhi3 yhi4 + ;esp: + +ALIGN 16 +_asm_provlineasm4: + push ebp + + mov eax, dword [ylookup + ecx*4] + add eax, edi + mov dword [promachvline4end1+2], eax + inc eax + mov dword [promachvline4end2+2], eax + inc eax + mov dword [promachvline4end3+2], eax + inc eax + mov dword [promachvline4end4+2], eax + sub eax, 3 + sub edi, eax + + mov eax, dword [bufplce] + mov ebx, dword [bufplce + 4] + mov ecx, dword [bufplce + 8] + mov edx, dword [bufplce + 12] + mov dword [promachvbuf1+3], ecx + mov dword [promachvbuf2+3], edx + mov dword [promachvbuf3+3], eax + mov dword [promachvbuf4+3], ebx + + mov eax, dword [palookupoffse] + mov ebx, dword [palookupoffse + 4] + mov ecx, dword [palookupoffse + 8] + mov edx, dword [palookupoffse + 12] + mov dword [promachvpal1+2], ecx + mov dword [promachvpal2+2], edx + mov dword [promachvpal3+2], eax + mov dword [promachvpal4+2], ebx + + ; ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ + ;edx: ³v3lo ³v1lo ³ + ; ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄ´ + ;esi: ³v2hi v2lo ³ v3hi³ + ; ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄ´ + ;ebp: ³v0hi v0lo ³ v1hi³ + ; ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÙ + + mov ebp, dword [vince] + mov ebx, dword [vince + 4] + mov esi, dword [vince + 8] + mov eax, dword [vince + 12] + and esi, 0fffffe00h + and ebp, 0fffffe00h +promachvsh9: rol eax, 88h ;sh +promachvsh10: rol ebx, 88h ;sh + mov edx, eax + mov ecx, ebx + shr ecx, 16 + and edx, 0ffff0000h + add edx, ecx + and eax, 000001ffh + and ebx, 000001ffh + add esi, eax + add ebp, ebx + ; + mov eax, edx + and eax, 0ffff0000h + mov dword [promachvinc1+2], eax + mov dword [promachvinc2+2], esi + shl edx, 16 + mov dword [promachvinc3+2], edx + mov dword [promachvinc5+2], ebp + + mov ebp, dword [vplce] + mov ebx, dword [vplce + 4] + mov esi, dword [vplce + 8] + mov eax, dword [vplce + 12] + and esi, 0fffffe00h + and ebp, 0fffffe00h +promachvsh11: rol eax, 88h ;sh +promachvsh12: rol ebx, 88h ;sh + mov edx, eax + mov ecx, ebx + shr ecx, 16 + and edx, 0ffff0000h + add edx, ecx + and eax, 000001ffh + and ebx, 000001ffh + add esi, eax + add ebp, ebx + + mov eax, esi + mov ecx, edx + shl ecx, 16 + jmp short probeginvlineasm4 +ALIGN 16 + nop + nop + nop +probeginvlineasm4: +promachvsh1: shr eax, 88h ;32-sh + mov ebx, esi +promachvsh2: and ebx, 00000088h ;(1<>sh) + ;vplc3 = (ebp<<(32-sh))+((edx&65535)<<(16-sh)) +promachvsh5: shl esi, 88h ;32-sh + mov eax, edx +promachvsh6: shl ebp, 88h ;32-sh + and edx, 0000ffffh +promachvsh7: shr eax, 88h ;sh + add esi, eax +promachvsh8: shl edx, 88h ;16-sh + add ebp, edx + mov dword [vplce + 12], esi + mov dword [vplce + 4], ebp + + pop ebp + ret + +ALIGN 16 +_asm_mvlineasm4: + push ebp + + mov eax, dword [bufplce] + mov ebx, dword [bufplce + 4] + mov dword [machmv1+2], eax + mov dword [machmv4+2], ebx + mov eax, dword [bufplce + 8] + mov ebx, dword [bufplce + 12] + mov dword [machmv7+2], eax + mov dword [machmv10+2], ebx + + mov eax, dword [palookupoffse] + mov ebx, dword [palookupoffse + 4] + mov dword [machmv2+2], eax + mov dword [machmv5+2], ebx + mov eax, dword [palookupoffse + 8] + mov ebx, dword [palookupoffse + 12] + mov dword [machmv8+2], eax + mov dword [machmv11+2], ebx + + mov eax, dword [vince] ;vince + mov ebx, dword [vince + 4] + xor al, al + xor bl, bl + mov dword [machmv3+2], eax + mov dword [machmv6+2], ebx + mov eax, dword [vince + 8] + mov ebx, dword [vince + 12] + mov dword [machmv9+2], eax + mov dword [machmv12+2], ebx + + mov ebx, ecx + mov ecx, dword [vplce] + mov edx, dword [vplce + 4] + mov esi, dword [vplce + 8] + mov ebp, dword [vplce + 12] + mov cl, bl + inc cl + inc bh + mov byte [asm3], bh +fixchain2ma: sub edi, 320 + + jmp short beginmvlineasm4 +ALIGN 16 +beginmvlineasm4: + dec cl + jz NEAR endmvlineasm4 +beginmvlineasm42: + mov eax, ebp + mov ebx, esi +machmv16: shr eax, 32 +machmv15: shr ebx, 32 +machmv12: add ebp, 88888888h ;vince[3] +machmv9: add esi, 88888888h ;vince[2] +machmv10: mov al, byte [eax+88888888h] ;bufplce[3] +machmv7: mov bl, byte [ebx+88888888h] ;bufplce[2] + cmp al, 255 + adc dl, dl + cmp bl, 255 + adc dl, dl +machmv8: mov bl, byte [ebx+88888888h] ;palookupoffs[2] +machmv11: mov bh, byte [eax+88888888h] ;palookupoffs[3] + + mov eax, edx +machmv14: shr eax, 32 + shl ebx, 16 +machmv4: mov al, byte [eax+88888888h] ;bufplce[1] + cmp al, 255 + adc dl, dl +machmv6: add edx, 88888888h ;vince[1] +machmv5: mov bh, byte [eax+88888888h] ;palookupoffs[1] + + mov eax, ecx +machmv13: shr eax, 32 +machmv3: add ecx, 88888888h ;vince[0] +machmv1: mov al, byte [eax+88888888h] ;bufplce[0] + cmp al, 255 + adc dl, dl +machmv2: mov bl, byte [eax+88888888h] ;palookupoffs[0] + + shl dl, 4 + xor eax, eax +fixchain2mb: add edi, 320 + mov al, dl + add eax, offset mvcase0 + jmp eax ;16 byte cases + +ALIGN 16 +endmvlineasm4: + dec byte [asm3] + jnz NEAR beginmvlineasm42 + + mov dword [vplce], ecx + mov dword [vplce + 4], edx + mov dword [vplce + 8], esi + mov dword [vplce + 12], ebp + pop ebp + ret + + ;5,7,8,8,11,13,12,14,11,13,14,14,12,14,15,7 +ALIGN 16 +mvcase0: + jmp beginmvlineasm4 +ALIGN 16 +mvcase1: + mov byte [edi], bl + jmp beginmvlineasm4 +ALIGN 16 +mvcase2: + mov byte [edi+1], bh + jmp beginmvlineasm4 +ALIGN 16 +mvcase3: + mov word [edi], bx + jmp beginmvlineasm4 +ALIGN 16 +mvcase4: + shr ebx, 16 + mov byte [edi+2], bl + jmp beginmvlineasm4 +ALIGN 16 +mvcase5: + mov byte [edi], bl + shr ebx, 16 + mov byte [edi+2], bl + jmp beginmvlineasm4 +ALIGN 16 + mvcase6: + shr ebx, 8 + mov word [edi+1], bx + jmp beginmvlineasm4 +ALIGN 16 +mvcase7: + mov word [edi], bx + shr ebx, 16 + mov byte [edi+2], bl + jmp beginmvlineasm4 +ALIGN 16 +mvcase8: + shr ebx, 16 + mov byte [edi+3], bh + jmp beginmvlineasm4 +ALIGN 16 +mvcase9: + mov byte [edi], bl + shr ebx, 16 + mov byte [edi+3], bh + jmp beginmvlineasm4 +ALIGN 16 +mvcase10: + mov byte [edi+1], bh + shr ebx, 16 + mov byte [edi+3], bh + jmp beginmvlineasm4 +ALIGN 16 +mvcase11: + mov word [edi], bx + shr ebx, 16 + mov byte [edi+3], bh + jmp beginmvlineasm4 +ALIGN 16 +mvcase12: + shr ebx, 16 + mov word [edi+2], bx + jmp beginmvlineasm4 +ALIGN 16 +mvcase13: + mov byte [edi], bl + shr ebx, 16 + mov word [edi+2], bx + jmp beginmvlineasm4 +ALIGN 16 +mvcase14: + mov byte [edi+1], bh + shr ebx, 16 + mov word [edi+2], bx + jmp beginmvlineasm4 +ALIGN 16 +mvcase15: + mov dword [edi], ebx + jmp beginmvlineasm4 + +ALIGN 16 + +_asm_setupspritevline: + mov dword [spal+2], eax + + mov eax, esi ;xinc's + shl eax, 16 + mov dword [smach1+2], eax + mov dword [smach4+2], eax + mov eax, esi + sar eax, 16 + add eax, ebx ;watch out with ebx - it's passed + mov dword [smach2+2], eax + add eax, edx + mov dword [smach5+2], eax + + mov dword [smach3+2], ecx ;yinc's + ret + +ALIGN 16 + ;eax = 0, ebx = x, ecx = cnt, edx = y, esi = yplc, edi = p +prestartsvline: +smach1: add ebx, 88888888h ;xincshl16 + mov al, byte [esi] +smach2: adc esi, 88888888h ;xincshr16+yalwaysinc + +startsvline: +spal: mov al, [eax+88888888h] ;palookup + mov byte [edi], al +fixchain1s: add edi, 320 + +_asm_spritevline: +smach3: add edx, 88888888h ;dayinc + dec ecx + ja short prestartsvline ;jump if (no carry (add)) and (not zero (dec))! + jz short endsvline +smach4: add ebx, 88888888h ;xincshl16 + mov al, byte [esi] +smach5: adc esi, 88888888h ;xincshr16+yalwaysinc+daydime + jmp short startsvline +endsvline: + ret + +ALIGN 16 +_asm_msetupspritevline: + mov dword [mspal+2], eax + + mov eax, esi ;xinc's + shl eax, 16 + mov dword [msmach1+2], eax + mov dword [msmach4+2], eax + mov eax, esi + sar eax, 16 + add eax, ebx ;watch out with ebx - it's passed + mov dword [msmach2+2], eax + add eax, edx + mov dword [msmach5+2], eax + + mov dword [msmach3+2], ecx ;yinc's + ret + +ALIGN 16 + ;eax = 0, ebx = x, ecx = cnt, edx = y, esi = yplc, edi = p +mprestartsvline: +msmach1: add ebx, 88888888h ;xincshl16 + mov al, byte [esi] +msmach2: adc esi, 88888888h ;xincshr16+yalwaysinc + +mstartsvline: + cmp al, 255 + je short mskipsvline +mspal: mov al, [eax+88888888h] ;palookup + mov byte [edi], al +mskipsvline: +mfixchain1s: add edi, 320 + +_asm_mspritevline: +msmach3: add edx, 88888888h ;dayinc + dec ecx + ja short mprestartsvline ;jump if (no carry (add)) and (not zero (dec))! + jz short mendsvline +msmach4: add ebx, 88888888h ;xincshl16 + mov al, byte [esi] +msmach5: adc esi, 88888888h ;xincshr16+yalwaysinc+daydime + jmp short mstartsvline +mendsvline: + ret + +ALIGN 16 +_asm_tsetupspritevline: + mov dword [tspal+2], eax + + mov eax, esi ;xinc's + shl eax, 16 + mov dword [tsmach1+2], eax + mov dword [tsmach4+2], eax + mov eax, esi + sar eax, 16 + add eax, ebx ;watch out with ebx - it's passed + mov dword [tsmach2+2], eax + add eax, edx + mov dword [tsmach5+2], eax + + mov dword [tsmach3+2], ecx ;yinc's + ret + +ALIGN 16 +_asm_tspritevline: + ;eax = 0, ebx = x, ecx = cnt, edx = y, esi = yplc, edi = p + push ebp + mov ebp, ebx + xor ebx, ebx + jmp tenterspritevline +ALIGN 16 +tprestartsvline: +tsmach1: add ebp, 88888888h ;xincshl16 + mov al, byte [esi] +tsmach2: adc esi, 88888888h ;xincshr16+yalwaysinc + +tstartsvline: + cmp al, 255 + je short tskipsvline +transrev2: + mov bh, byte [edi] +transrev3: +tspal: mov bl, [eax+88888888h] ;palookup +tmach4: mov al, byte [ebx+88888888h] ;transluc + mov byte [edi], al +tskipsvline: +tfixchain1s: add edi, 320 + +tenterspritevline: +tsmach3: add edx, 88888888h ;dayinc + dec ecx + ja short tprestartsvline ;jump if (no carry (add)) and (not zero (dec))! + jz short tendsvline +tsmach4: add ebp, 88888888h ;xincshl16 + mov al, byte [esi] +tsmach5: adc esi, 88888888h ;xincshr16+yalwaysinc+daydime + jmp short tstartsvline +tendsvline: + pop ebp + ret + +ALIGN 16 +_asm_msethlineshift: + neg al + mov byte [msh1d+2], al + mov byte [msh2d+3], bl + mov byte [msh3d+2], al + mov byte [msh4d+3], bl + mov byte [msh5d+2], al + mov byte [msh6d+3], bl + ret + +ALIGN 16 +_asm_mhline: + ;asm1 = bxinc + ;asm2 = byinc + ;asm3 = shadeoffs + ;eax = picoffs + ;ebx = bx + ;ecx = cnt + ;edx = ? + ;esi = by + ;edi = p + + mov dword [mmach1d+2], eax + mov dword [mmach5d+2], eax + mov dword [mmach9d+2], eax + mov eax, [asm3] + mov dword [mmach2d+2], eax + mov dword [mmach2da+2], eax + mov dword [mmach2db+2], eax + mov dword [mmach6d+2], eax + mov dword [mmach10d+2], eax + mov eax, [asm1] + mov dword [mmach3d+2], eax + mov dword [mmach7d+2], eax + mov eax, [asm2] + mov dword [mmach4d+2], eax + mov dword [mmach8d+2], eax + jmp short _asm_mhlineskipmodify + +ALIGN 16 +_asm_mhlineskipmodify: + + push ebp + + xor eax, eax + mov ebp, ebx + + test ecx, 00010000h + jnz short mbeghline + +msh1d: shr ebx, 26 +msh2d: shld ebx, esi, 6 + add ebp, [asm1] +mmach9d: mov al, byte [ebx+88888888h] ;picoffs + add esi, [asm2] + cmp al, 255 + je mskip5 + + mmach10d: mov cl, byte [eax+88888888h] ;shadeoffs + mov byte [edi], cl +mskip5: + inc edi + sub ecx, 65536 + jc NEAR mendhline + jmp short mbeghline + +ALIGN 16 +mpreprebeghline: ;1st only + mov al, cl +mmach2d: mov al, byte [eax+88888888h] ;shadeoffs + mov byte [edi], al + +mprebeghline: + add edi, 2 + sub ecx, 131072 + jc NEAR mendhline +mbeghline: +mmach3d: lea ebx, [ebp+88888888h] ;bxinc +msh3d: shr ebp, 26 +msh4d: shld ebp, esi, 6 +mmach4d: add esi, 88888888h ;byinc +mmach1d: mov cl, byte [ebp+88888888h] ;picoffs +mmach7d: lea ebp, [ebx+88888888h] ;bxinc + +msh5d: shr ebx, 26 +msh6d: shld ebx, esi, 6 +mmach8d: add esi, 88888888h ;byinc +mmach5d: mov ch, byte [ebx+88888888h] ;picoffs + + cmp cl, 255 + je short mskip1 + cmp ch, 255 + je short mpreprebeghline + + mov al, cl ;BOTH +mmach2da: mov bl, byte [eax+88888888h] ;shadeoffs + mov al, ch +mmach2db: mov bh, byte [eax+88888888h] ;shadeoffs + mov word [edi], bx + add edi, 2 + sub ecx, 131072 + jnc short mbeghline + jmp mendhline +mskip1: ;2nd only + cmp ch, 255 + je short mprebeghline + + mov al, ch +mmach6d: mov al, byte [eax+88888888h] ;shadeoffs + mov byte [edi+1], al + add edi, 2 + sub ecx, 131072 + jnc short mbeghline +mendhline: + + pop ebp + ret + +ALIGN 16 +_asm_tsethlineshift: + neg al + mov byte [tsh1d+2], al + mov byte [tsh2d+3], bl + mov byte [tsh3d+2], al + mov byte [tsh4d+3], bl + mov byte [tsh5d+2], al + mov byte [tsh6d+3], bl + ret + +ALIGN 16 +_asm_thline: + ;asm1 = bxinc + ;asm2 = byinc + ;asm3 = shadeoffs + ;eax = picoffs + ;ebx = bx + ;ecx = cnt + ;edx = ? + ;esi = by + ;edi = p + + mov dword [tmach1d+2], eax + mov dword [tmach5d+2], eax + mov dword [tmach9d+2], eax + mov eax, [asm3] + mov dword [tmach2d+2], eax + mov dword [tmach6d+2], eax + mov dword [tmach10d+2], eax + mov eax, [asm1] + mov dword [tmach3d+2], eax + mov dword [tmach7d+2], eax + mov eax, [asm2] + mov dword [tmach4d+2], eax + mov dword [tmach8d+2], eax + jmp _asm_thlineskipmodify + +ALIGN 16 +_asm_thlineskipmodify: + + push ebp + + xor eax, eax + xor edx, edx + mov ebp, ebx + + test ecx, 00010000h + jnz short tbeghline + +tsh1d: shr ebx, 26 +tsh2d: shld ebx, esi, 6 + add ebp, [asm1] +tmach9d: mov al, byte [ebx+88888888h] ;picoffs + add esi, [asm2] + cmp al, 255 + je tskip5 + +transrev4: +tmach10d: mov dl, byte [eax+88888888h] ;shadeoffs +transrev5: + mov dh, byte [edi] +tmach1: mov al, byte [edx+88888888h] ;transluc + mov byte [edi], al +tskip5: + inc edi + sub ecx, 65536 + jc NEAR tendhline + jmp short tbeghline + +ALIGN 16 +tprebeghline: + add edi, 2 + sub ecx, 131072 + jc short tendhline +tbeghline: +tmach3d: lea ebx, [ebp+88888888h] ;bxinc +tsh3d: shr ebp, 26 +tsh4d: shld ebp, esi, 6 +tmach4d: add esi, 88888888h ;byinc +tmach1d: mov cl, byte [ebp+88888888h] ;picoffs +tmach7d: lea ebp, [ebx+88888888h] ;bxinc + +tsh5d: shr ebx, 26 +tsh6d: shld ebx, esi, 6 +tmach8d: add esi, 88888888h ;byinc +tmach5d: mov ch, byte [ebx+88888888h] ;picoffs + + cmp cx, 0ffffh + je short tprebeghline + + mov bx, word [edi] + + cmp cl, 255 + je short tskip1 + mov al, cl +transrev6: +tmach2d: mov dl, byte [eax+88888888h] ;shadeoffs +transrev7: + mov dh, bl +tmach2: mov al, byte [edx+88888888h] ;transluc + mov byte [edi], al + + cmp ch, 255 + je short tskip2 +tskip1: + mov al, ch +transrev8: +tmach6d: mov dl, byte [eax+88888888h] ;shadeoffs +transrev9: + mov dh, bh +tmach3: mov al, byte [edx+88888888h] ;transluc + mov byte [edi+1], al +tskip2: + + add edi, 2 + sub ecx, 131072 + jnc tbeghline +tendhline: + + pop ebp + ret + + + ;eax=shiftval, ebx=palookup1, ecx=palookup2 +ALIGN 16 +_asm_setuptvlineasm2: + mov byte [tran2shra+2], al + mov byte [tran2shrb+2], al + mov dword [tran2pala+2], ebx + mov dword [tran2palb+2], ecx + mov dword [tran2palc+2], ebx + mov dword [tran2pald+2], ecx + ret + + ;Pass: eax=vplc2, ebx=vinc1, ecx=bufplc1, edx=bufplc2, esi=vplc1, edi=p + ; asm1=vinc2, asm2=pend + ;Return: asm1=vplc1, asm2=vplc2 +ALIGN 16 +_asm_tvlineasm2: + push ebp + + mov ebp, eax + + mov dword [tran2inca+2], ebx + mov eax, [asm1] + mov dword [tran2incb+2], eax + + mov dword [tran2bufa+2], ecx ;bufplc1 + mov dword [tran2bufb+2], edx ;bufplc2 + + mov eax, [asm2] + sub edi, eax + mov dword [tran2edia+3], eax + mov dword [tran2edic+2], eax + inc eax + mov dword [tran2edie+2], eax +fixchaint2a: sub eax, 320 + mov dword [tran2edif+2], eax + dec eax + mov dword [tran2edib+3], eax + mov dword [tran2edid+2], eax + + xor ecx, ecx + xor edx, edx + jmp short begintvline2 + + ;eax 0000000000 temp temp + ;ebx 0000000000 odat2 odat1 + ;ecx 0000000000000000 ndat1 + ;edx 0000000000000000 ndat2 + ;esi vplc1 + ;edi videoplc-------------- + ;ebp vplc2 + +ALIGN 16 + ;LEFT ONLY +skipdraw2: +transrev10: +tran2edic: mov ah, byte [edi+88888888h] ;getpixel +transrev11: +tran2palc: mov al, byte [ecx+88888888h] ;palookup1 +fixchaint2d: add edi, 320 +tran2trac: mov bl, byte [eax+88888888h] ;transluc +tran2edid: mov byte [edi+88888888h-320], bl ;drawpixel + jnc short begintvline2 + jmp endtvline2 + +skipdraw1: + cmp dl, 255 + jne short skipdraw3 +fixchaint2b: add edi, 320 + jc short endtvline2 + +begintvline2: + mov eax, esi +tran2shra: shr eax, 88h ;globalshift + mov ebx, ebp +tran2shrb: shr ebx, 88h ;globalshift +tran2inca: add esi, 88888888h ;vinc1 +tran2incb: add ebp, 88888888h ;vinc2 +tran2bufa: mov cl, byte [eax+88888888h] ;bufplc1 + cmp cl, 255 +tran2bufb: mov dl, byte [ebx+88888888h] ;bufplc2 + je short skipdraw1 + cmp dl, 255 + je short skipdraw2 + + ;mov ax The transluscent reverse of both! + ;mov bl, ah + ;mov ah + ;mov bh + + ;BOTH +transrev12: +tran2edia: mov bx, word [edi+88888888h] ;getpixels +transrev13: + mov ah, bl +transrev14: +tran2pala: mov al, byte [ecx+88888888h] ;palookup1 +transrev15: +tran2palb: mov bl, byte [edx+88888888h] ;palookup2 +fixchaint2c: add edi, 320 +tran2traa: mov al, byte [eax+88888888h] ;transluc +tran2trab: mov ah, byte [ebx+88888888h] ;transluc +tran2edib: mov word [edi+88888888h-320], ax ;drawpixels + jnc short begintvline2 + jmp short endtvline2 + + ;RIGHT ONLY +skipdraw3: +transrev16: +tran2edie: mov ah, byte [edi+88888889h] ;getpixel +transrev17: +tran2pald: mov al, byte [edx+88888888h] ;palookup2 +fixchaint2e: add edi, 320 +tran2trad: mov bl, byte [eax+88888888h] ;transluc +tran2edif: mov byte [edi+88888889h-320], bl ;drawpixel + jnc short begintvline2 + +endtvline2: + mov [asm1], esi + mov [asm2], ebp + + pop ebp + ret + + +BITSOFPRECISION equ 3 +BITSOFPRECISIONPOW equ 8 + +;Double-texture mapping with palette lookup +;eax: ylo1------------|----dat|----dat +;ebx: ylo2--------------------|----cnt +;ecx: 000000000000000000000000|---temp +;edx: xhi1-xlo1---------------|---yhi1 +;esi: xhi2-xlo2---------------|---yhi2 +;edi: ------------------------videopos +;ebp: ----------------------------temp + +ALIGN 16 +setupslopevlin2: + mov dword [slop3+2], edx ;ptr + mov dword [slop7+2], edx ;ptr + mov dword [slop4+2], esi ;tptr + mov dword [slop8+2], esi ;tptr + mov byte [slop2+2], ah ;ybits + mov byte [slop6+2], ah ;ybits + mov dword [slop9+2], edi ;pinc + + mov edx, 1 + mov cl, al + add cl, ah + shl edx, cl + dec edx + mov cl, ah + ror edx, cl + + mov dword [slop1+2], edx ;ybits...xbits + mov dword [slop5+2], edx ;ybits...xbits + + ret + +ALIGN 16 +_asm_slopevlin2: + push ebp + xor ecx, ecx + +slopevlin2begin: + mov ebp, edx +slop1: and ebp, 88000088h ;ybits...xbits +slop2: rol ebp, 6 ;ybits + add eax, [asm1] ;xinc1<>(32-xbits)) +slop3: mov cl, byte [ebp+88888888h] ;bufplc + + mov ebp, esi +slop4: mov al, byte [ecx+88888888h] ;paloffs +slop5: and ebp, 88000088h ;ybits...xbits +slop6: rol ebp, 6 ;ybits + add ebx, [asm3] ;xinc2<>(32-xbits)) +slop8: mov ah, byte [ecx+88888888h] ;paloffs + + dec bl + mov word [edi], ax +slop9: lea edi, [edi+88888888h] ;pinc + jnz short slopevlin2begin + + pop ebp + mov eax, edi + ret + + +ALIGN 16 +_asm_setupslopevlin: + mov dword [slopmach3+3], ebx ;ptr + mov dword [slopmach5+2], ecx ;pinc + neg ecx + mov dword [slopmach6+2], ecx ;-pinc + + mov edx, 1 + mov cl, al + shl edx, cl + dec edx + mov cl, ah + shl edx, cl + mov dword [slopmach7+2], edx + + neg ah + mov byte [slopmach2+2], ah + + sub ah, al + mov byte [slopmach1+2], ah + + fild dword [asm1] + fstp dword [asm2] + ret + +ALIGN 16 +_asm_slopevlin: + mov [ebpbak], ebp ; Added [] AH + mov [espbak], esp ; Added [] AH + + sub ecx, esp + mov dword [slopmach4+3], ecx + + fild dword [asm3] +slopmach6: lea ebp, [eax+88888888h] + fadd dword [asm2] + + mov [asm1], ebx ; Added [] AH + shl ebx, 3 + + mov eax, [globalx3] + mov ecx, [globaly3] + imul eax, ebx + imul ecx, ebx + add esi, eax + add edi, ecx + + mov ebx, edx + jmp short bigslopeloop +ALIGN 16 +bigslopeloop: + fst dword [fpuasm] + + mov eax, [fpuasm] + add eax, eax + sbb edx, edx + mov ecx, eax + shr ecx, 24 + and eax, 00ffe000h + shr eax, 11 + sub cl, 2 + mov eax, dword [reciptable + eax] + shr eax, cl + xor eax, edx + mov edx, [asm1] + mov ecx, [globalx3] + mov [asm1], eax ; Added [] AH + sub eax, edx + mov edx, [globaly3] + imul ecx, eax + imul eax, edx + + fadd dword [asm2] + + cmp ebx, BITSOFPRECISIONPOW + mov [asm4], ebx ; Added [] AH + mov cl, bl + jl short slopeskipmin + mov cl, BITSOFPRECISIONPOW +slopeskipmin: + +;eax: yinc............. +;ebx: 0 0 0 ? +;ecx: xinc......... cnt +;edx: ? +;esi: xplc............. +;edi: yplc............. +;ebp: videopos + + mov ebx, esi + mov edx, edi + +beginnerslopeloop: +slopmach1: shr ebx, 20 + add esi, ecx +slopmach2: shr edx, 26 +slopmach7: and ebx, 88888888h + add edi, eax +slopmach5: add ebp, 88888888h ;pinc +slopmach3: mov dl, byte [ebx+edx+88888888h] ;ptr +slopmach4: mov ebx, dword [esp+88888888h] +slopmach41: sub esp, 4 +slopmach42: dec cl +slopmach43: mov al, byte [ebx+edx] ;tptr +slopmach44: mov ebx, esi +slopmach45: mov [ebp], al +slopmach46: mov edx, edi +slopmach47: jnz short beginnerslopeloop + +slopmach48: mov ebx, [asm4] +slopmach49: sub ebx, BITSOFPRECISIONPOW +slopmach4a: jg NEAR bigslopeloop + +slopmach4b: ffree st0 + +slopmach4c: mov esp, [espbak] +slopmach4d: mov ebp, [ebpbak] + ret + + +ALIGN 16 +_asm_setuprhlineasm4: + mov dword [rmach1a+2], eax + mov dword [rmach1b+2], eax + mov dword [rmach1c+2], eax + mov dword [rmach1d+2], eax + mov dword [rmach1e+2], eax + + mov dword [rmach2a+2], ebx + mov dword [rmach2b+2], ebx + mov dword [rmach2c+2], ebx + mov dword [rmach2d+2], ebx + mov dword [rmach2e+2], ebx + + mov dword [rmach3a+2], ecx + mov dword [rmach3b+2], ecx + mov dword [rmach3c+2], ecx + mov dword [rmach3d+2], ecx + mov dword [rmach3e+2], ecx + + mov dword [rmach4a+2], edx + mov dword [rmach4b+2], edx + mov dword [rmach4c+2], edx + mov dword [rmach4d+2], edx + mov dword [rmach4e+2], edx + + mov dword [rmach5a+2], esi + mov dword [rmach5b+2], esi + mov dword [rmach5c+2], esi + mov dword [rmach5d+2], esi + mov dword [rmach5e+2], esi + ret + + ;Non power of 2, non masking, with palookup method #1 (6 clock cycles) + ;eax: dat dat dat dat + ;ebx: bufplc + ;ecx: 0 dat + ;edx: xlo + ;esi: ylo + ;edi: videopos/cnt + ;ebp: tempvar + ;esp: +ALIGN 16 +_asm_rhlineasm4: + push ebp + + cmp eax, 0 + jle NEAR endrhline + + lea ebp, [edi-4] + sub ebp, eax + mov dword [rmach6a+2], ebp + add ebp, 3 + mov dword [rmach6b+2], ebp + mov edi, eax + test edi, 3 + jz short begrhline + jmp short startrhline1 + +ALIGN 16 +startrhline1: + mov cl, byte [ebx] ;bufplc +rmach1e: sub edx, 88888888h ;xlo + sbb ebp, ebp +rmach2e: sub esi, 88888888h ;ylo +rmach3e: sbb ebx, 88888888h ;xhi*tilesizy + yhi+ycarry +rmach4e: mov al, byte [ecx+88888888h] ;palookup +rmach5e: and ebp, 88888888h ;tilesizy +rmach6b: mov byte [edi+88888888h], al ;vidcntoffs + sub ebx, ebp + dec edi + test edi, 3 + jnz short startrhline1 + test edi, edi + jz NEAR endrhline + +begrhline: + mov cl, byte [ebx] ;bufplc +rmach1a: sub edx, 88888888h ;xlo + sbb ebp, ebp +rmach2a: sub esi, 88888888h ;ylo +rmach3a: sbb ebx, 88888888h ;xhi*tilesizy + yhi+ycarry +rmach5a: and ebp, 88888888h ;tilesizy + sub ebx, ebp + +rmach1b: sub edx, 88888888h ;xlo + sbb ebp, ebp +rmach4a: mov ah, byte [ecx+88888888h] ;palookup + mov cl, byte [ebx] ;bufplc +rmach2b: sub esi, 88888888h ;ylo +rmach3b: sbb ebx, 88888888h ;xhi*tilesizy + yhi+ycarry +rmach5b: and ebp, 88888888h ;tilesizy +rmach4b: mov al, byte [ecx+88888888h] ;palookup + sub ebx, ebp + + shl eax, 16 + + mov cl, byte [ebx] ;bufplc +rmach1c: sub edx, 88888888h ;xlo + sbb ebp, ebp +rmach2c: sub esi, 88888888h ;ylo +rmach3c: sbb ebx, 88888888h ;xhi*tilesizy + yhi+ycarry +rmach5c: and ebp, 88888888h ;tilesizy + sub ebx, ebp + +rmach1d: sub edx, 88888888h ;xlo + sbb ebp, ebp +rmach4c: mov ah, byte [ecx+88888888h] ;palookup + mov cl, byte [ebx] ;bufplc +rmach2d: sub esi, 88888888h ;ylo +rmach3d: sbb ebx, 88888888h ;xhi*tilesizy + yhi+ycarry +rmach5d: and ebp, 88888888h ;tilesizy +rmach4d: mov al, byte [ecx+88888888h] ;palookup + sub ebx, ebp + +rmach6a: mov dword [edi+88888888h], eax ;vidcntoffs + sub edi, 4 + jnz NEAR begrhline +endrhline: + pop ebp + ret + +ALIGN 16 +_asm_setuprmhlineasm4: + mov dword [rmmach1+2], eax + mov dword [rmmach2+2], ebx + mov dword [rmmach3+2], ecx + mov dword [rmmach4+2], edx + mov dword [rmmach5+2], esi + ret + +ALIGN 16 +_asm_rmhlineasm4: + push ebp + + cmp eax, 0 + jle short endrmhline + + lea ebp, [edi-1] + sub ebp, eax + mov dword [rmmach6+2], ebp + mov edi, eax + jmp short begrmhline + +ALIGN 16 +begrmhline: + mov cl, byte [ebx] ;bufplc +rmmach1: sub edx, 88888888h ;xlo + sbb ebp, ebp +rmmach2: sub esi, 88888888h ;ylo +rmmach3: sbb ebx, 88888888h ;xhi*tilesizy + yhi+ycarry +rmmach5: and ebp, 88888888h ;tilesizy + cmp cl, 255 + je short rmskip +rmmach4: mov al, byte [ecx+88888888h] ;palookup +rmmach6: mov byte [edi+88888888h], al ;vidcntoffs +rmskip: + sub ebx, ebp + dec edi + jnz short begrmhline +endrmhline: + pop ebp + ret + +ALIGN 16 +_asm_setupqrhlineasm4: + mov dword [qrmach2e+2], ebx + mov dword [qrmach3e+2], ecx + xor edi, edi + sub edi, ecx + mov dword [qrmach7a+2], edi + mov dword [qrmach7b+2], edi + + add ebx, ebx + adc ecx, ecx + mov dword [qrmach2a+2], ebx + mov dword [qrmach2b+2], ebx + mov dword [qrmach3a+2], ecx + mov dword [qrmach3b+2], ecx + + mov dword [qrmach4a+2], edx + mov dword [qrmach4b+2], edx + mov dword [qrmach4c+2], edx + mov dword [qrmach4d+2], edx + mov dword [qrmach4e+2], edx + ret + + ;Non power of 2, non masking, with palookup method (FASTER BUT NO SBB'S) + ;eax: dat dat dat dat + ;ebx: bufplc + ;ecx: 0 dat + ;edx: 0 dat + ;esi: ylo + ;edi: videopos/cnt + ;ebp: ? + ;esp: +ALIGN 16 +;4 pixels in 9 cycles! 2.25 cycles/pixel +_asm_qrhlineasm4: + push ebp + + cmp eax, 0 + jle NEAR endqrhline + + mov ebp, eax + test ebp, 3 + jz short skipqrhline1 + jmp short startqrhline1 + +ALIGN 16 +startqrhline1: + mov cl, byte [ebx] ;bufplc + dec edi +qrmach2e: sub esi, 88888888h ;ylo + dec ebp +qrmach3e: sbb ebx, 88888888h ;xhi*tilesizy + yhi+ycarry +qrmach4e: mov al, byte [ecx+88888888h] ;palookup + mov byte [edi], al ;vidcntoffs + test ebp, 3 + jnz short startqrhline1 + test ebp, ebp + jz short endqrhline + +skipqrhline1: + mov cl, byte [ebx] ;bufplc + jmp short begqrhline +ALIGN 16 +begqrhline: +qrmach7a: mov dl, byte [ebx+88888888h] ;bufplc +qrmach2a: sub esi, 88888888h ;ylo +qrmach3a: sbb ebx, 88888888h ;xhi*tilesizy + yhi+ycarry +qrmach4a: mov ah, byte [ecx+88888888h] ;palookup +qrmach4b: mov al, byte [edx+88888888h] ;palookup + sub edi, 4 + shl eax, 16 + mov cl, byte [ebx] ;bufplc +qrmach7b: mov dl, byte [ebx+88888888h] ;bufplc +qrmach2b: sub esi, 88888888h ;ylo +qrmach3b: sbb ebx, 88888888h ;xhi*tilesizy + yhi+ycarry +qrmach4c: mov ah, byte [ecx+88888888h] ;palookup +qrmach4d: mov al, byte [edx+88888888h] ;palookup + mov cl, byte [ebx] ;bufplc + mov dword [edi], eax + sub ebp, 4 + jnz short begqrhline + +endqrhline: + pop ebp + ret + +_asm_setupdrawslab: + mov dword [voxbpl1+2], eax + mov dword [voxbpl2+2], eax + mov dword [voxbpl3+2], eax + mov dword [voxbpl4+2], eax + mov dword [voxbpl5+2], eax + mov dword [voxbpl6+2], eax + mov dword [voxbpl7+2], eax + mov dword [voxbpl8+2], eax + + mov dword [voxpal1+2], ebx + mov dword [voxpal2+2], ebx + mov dword [voxpal3+2], ebx + mov dword [voxpal4+2], ebx + mov dword [voxpal5+2], ebx + mov dword [voxpal6+2], ebx + mov dword [voxpal7+2], ebx + mov dword [voxpal8+2], ebx + ret + +ALIGN 16 +_asm_drawslab: + push ebp + cmp eax, 2 + je voxbegdraw2 + ja voxskip2 + xor eax, eax +voxbegdraw1: + mov ebp, ebx + shr ebp, 16 + add ebx, edx + dec ecx + mov al, byte [esi+ebp] +voxpal1: mov al, byte [eax+88888888h] + mov byte [edi], al +voxbpl1: lea edi, [edi+88888888h] + jnz voxbegdraw1 + pop ebp + ret + +voxbegdraw2: + mov ebp, ebx + shr ebp, 16 + add ebx, edx + xor eax, eax + dec ecx + mov al, byte [esi+ebp] +voxpal2: mov al, byte [eax+88888888h] + mov ah, al + mov word [edi], ax +voxbpl2: lea edi, [edi+88888888h] + jnz voxbegdraw2 + pop ebp + ret + +voxskip2: + cmp eax, 4 + jne voxskip4 + xor eax, eax +voxbegdraw4: + mov ebp, ebx + add ebx, edx + shr ebp, 16 + xor eax, eax + mov al, byte [esi+ebp] +voxpal3: mov al, byte [eax+88888888h] + mov ah, al + shl eax, 8 + mov al, ah + shl eax, 8 + mov al, ah + mov dword [edi], eax +voxbpl3: add edi, 88888888h + dec ecx + jnz voxbegdraw4 + pop ebp + ret + +voxskip4: + add eax, edi + + test edi, 1 + jz voxskipslab1 + cmp edi, eax + je voxskipslab1 + + push eax + push ebx + push ecx + push edi +voxbegslab1: + mov ebp, ebx + add ebx, edx + shr ebp, 16 + xor eax, eax + mov al, byte [esi+ebp] +voxpal4: mov al, byte [eax+88888888h] + mov byte [edi], al +voxbpl4: add edi, 88888888h + dec ecx + jnz voxbegslab1 + pop edi + pop ecx + pop ebx + pop eax + inc edi + +voxskipslab1: + push eax + test edi, 2 + jz voxskipslab2 + dec eax + cmp edi, eax + jge voxskipslab2 + + push ebx + push ecx + push edi +voxbegslab2: + mov ebp, ebx + add ebx, edx + shr ebp, 16 + xor eax, eax + mov al, byte [esi+ebp] +voxpal5: mov al, byte [eax+88888888h] + mov ah, al + mov word [edi], ax +voxbpl5: add edi, 88888888h + dec ecx + jnz voxbegslab2 + pop edi + pop ecx + pop ebx + add edi, 2 + +voxskipslab2: + mov eax, [esp] + + sub eax, 3 + cmp edi, eax + jge voxskipslab3 + +voxprebegslab3: + push ebx + push ecx + push edi +voxbegslab3: + mov ebp, ebx + add ebx, edx + shr ebp, 16 + xor eax, eax + mov al, byte [esi+ebp] +voxpal6: mov al, byte [eax+88888888h] + mov ah, al + shl eax, 8 + mov al, ah + shl eax, 8 + mov al, ah + mov dword [edi], eax +voxbpl6: add edi, 88888888h + dec ecx + jnz voxbegslab3 + pop edi + pop ecx + pop ebx + add edi, 4 + + mov eax, [esp] + + sub eax, 3 + cmp edi, eax + jl voxprebegslab3 + +voxskipslab3: + mov eax, [esp] + + dec eax + cmp edi, eax + jge voxskipslab4 + + push ebx + push ecx + push edi +voxbegslab4: + mov ebp, ebx + add ebx, edx + shr ebp, 16 + xor eax, eax + mov al, byte [esi+ebp] +voxpal7: mov al, byte [eax+88888888h] + mov ah, al + mov word [edi], ax +voxbpl7: add edi, 88888888h + dec ecx + jnz voxbegslab4 + pop edi + pop ecx + pop ebx + add edi, 2 + +voxskipslab4: + pop eax + + cmp edi, eax + je voxskipslab5 + +voxbegslab5: + mov ebp, ebx + add ebx, edx + shr ebp, 16 + xor eax, eax + mov al, byte [esi+ebp] +voxpal8: mov al, byte [eax+88888888h] + mov byte [edi], al +voxbpl8: add edi, 88888888h + dec ecx + jnz voxbegslab5 + +voxskipslab5: + pop ebp + ret + +;modify: loinc +;eax: | dat | dat | dat | dat | +;ebx: | loplc1 | +;ecx: | loplc2 | cnthi | cntlo | +;edx: |--------|--------|--------| hiplc1 | +;esi: |--------|--------|--------| hiplc2 | +;edi: |--------|--------|--------| vidplc | +;ebp: |--------|--------|--------| hiinc | + +_asm_stretchhline: + push ebp + + mov eax, ebx + shl ebx, 16 + sar eax, 16 + and ecx, 0000ffffh + or ecx, ebx + + add esi, eax + mov eax, edx + mov edx, esi + + mov ebp, eax + shl eax, 16 + sar ebp, 16 + + add ecx, eax + adc esi, ebp + + add eax, eax + adc ebp, ebp + mov dword [loinc1+2], eax + mov dword [loinc2+2], eax + mov dword [loinc3+2], eax + mov dword [loinc4+2], eax + + inc ch + + jmp begloop + +begloop: + mov al, [edx] +loinc1: sub ebx, 88888888h + sbb edx, ebp + mov ah, [esi] +loinc2: sub ecx, 88888888h + sbb esi, ebp + sub edi, 4 + shl eax, 16 +loinc3: sub ebx, 88888888h + mov al, [edx] + sbb edx, ebp + mov ah, [esi] +loinc4: sub ecx, 88888888h + sbb esi, ebp + mov [edi], eax + dec cl + jnz begloop + dec ch + jnz begloop + + pop ebp + ret + +_asm_mmxoverlay: + pushfd ;Check if CPUID is available + pop eax + mov ebx, eax + xor eax, 00200000h + push eax + popfd + pushfd + pop eax + cmp eax, ebx + je pentium + xor eax, eax + dw 0a20fh + test eax, eax + jz pentium + mov eax, 1 + dw 0a20fh + and eax, 00000f00h + test edx, 00800000h ;Check if MMX is available + jz nommx + cmp eax, 00000600h ;Check if P6 Family or not + jae pentiumii + jmp pentiummmx +nommx: + cmp eax, 00000600h ;Check if P6 Family or not + jae pentiumpro +pentium: + ret + +;ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ +;³ PENTIUM II Overlays ³ +;ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ +pentiumii: + ;Hline overlay (MMX doens't help) + mov byte [_asm_sethlinesizes], 0xe9 + mov dword [_asm_sethlinesizes+1], (offset _asm_prosethlinesizes)-(offset _asm_sethlinesizes)-5 + mov byte [_asm_setpalookupaddress], 0xe9 + mov dword [_asm_setpalookupaddress+1], (offset _asm_prosetpalookupaddress)-(offset _asm_setpalookupaddress)-5 + mov byte [_asm_setuphlineasm4], 0xc3 ;ret (no code required) + mov byte [_asm_hlineasm4], 0xe9 + mov dword [_asm_hlineasm4+1], (offset _asm_prohlineasm4)-(offset _asm_hlineasm4)-5 + + ;Vline overlay + mov byte [_asm_setupvlineasm], 0xe9 + mov dword [_asm_setupvlineasm+1], (offset _asm_prosetupvlineasm)-(offset _asm_setupvlineasm)-5 + mov byte [_asm_vlineasm4], 0xe9 + mov dword [_asm_vlineasm4+1], (offset _asm_provlineasm4)-(offset _asm_vlineasm4)-5 + + ret + +;ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ +;³ PENTIUM MMX Overlays ³ +;ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ +pentiummmx: + ret + +;ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ +;³ PENTIUM PRO Overlays ³ +;ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ +pentiumpro: + ;Hline overlay (MMX doens't help) + mov byte [_asm_sethlinesizes], 0xe9 + mov dword [_asm_sethlinesizes+1], (offset _asm_prosethlinesizes)-(offset _asm_sethlinesizes)-5 + mov byte [_asm_setpalookupaddress], 0xe9 + mov dword [_asm_setpalookupaddress+1], (offset _asm_prosetpalookupaddress)-(offset _asm_setpalookupaddress)-5 + mov byte [_asm_setuphlineasm4], 0xc3 ;ret (no code required) + mov byte [_asm_hlineasm4], 0xe9 + mov dword [_asm_hlineasm4+1], (offset _asm_prohlineasm4)-(offset _asm_hlineasm4)-5 + + ;Vline overlay + mov byte [_asm_setupvlineasm], 0xe9 + mov dword [_asm_setupvlineasm+1], (offset _asm_prosetupvlineasm)-(offset _asm_setupvlineasm)-5 + mov byte [_asm_vlineasm4], 0xe9 + mov dword [_asm_vlineasm4+1], (offset _asm_provlineasm4)-(offset _asm_vlineasm4)-5 + + ret + +ALIGN 16 +; "mov fpuasm, eax",\ +; "fild dword ptr fpuasm",\ +; "add eax, eax",\ +; "fstp dword ptr fpuasm",\ +; "sbb ebx, ebx",\ +; "mov eax, fpuasm",\ +; "mov ecx, eax",\ +; "and eax, 0x007ff000",\ +; "shr eax, 10",\ +; "sub ecx, 0x3f800000",\ +; "shr ecx, 23",\ +; "mov eax, dword ptr reciptable[eax]",\ +; "sar eax, cl",\ +; "xor eax, ebx",\ + +_asm_krecipasm: + mov [fpuasm], eax + fild dword [fpuasm] + add eax, eax + fstp dword [fpuasm] + sbb ebx, ebx + mov eax, dword [fpuasm] + mov ecx, eax + and eax, 007ff000h + shr eax, 10 + sub ecx, 03f800000h + shr ecx, 23 + mov eax, dword [reciptable + eax] + sar eax, cl + xor eax, ebx + ret + +END + +; ************************ +; ** End Code Block ** +; ************************ + diff --git a/buildengine/a_visualc.c b/buildengine/a_visualc.c new file mode 100755 index 0000000..edff0e1 --- /dev/null +++ b/buildengine/a_visualc.c @@ -0,0 +1,715 @@ +/* + * "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman + * Ken Silverman's official web site: "http://www.advsys.net/ken" + * See the included license file "BUILDLIC.TXT" for license info. + * This file has been modified from Ken Silverman's original release + * (Actually, all the ASM was from a.asm, but that's obviously commented out.) + */ + +#include "a.h" + +#if (!defined USE_I386_ASM) +#error Please define USE_I386_ASM if you want to compile this. +#endif + +#if (!defined _MSC_VER) +#error This file is filled with Microsoft Visual C-specific inline asm. +#endif + +long is_vmware_running(void) +{ + int retval; + __asm + { + call asm_isvmwarerunning + mov retval, eax + } /* asm */ + return(retval); +} /* is_vmware_running */ + + +/* #pragma aux mmxoverlay modify [eax ebx ecx edx] */ +long mmxoverlay(void) +{ + long retval; + __asm + { + call asm_mmxoverlay + mov retval, eax + } /* asm */ + return(retval); +} /* mmxoverlay */ + +/* #pragma aux sethlinesizes parm [eax][ebx][ecx] */ +long sethlinesizes(long i1, long i2, long i3) +{ + long retval; + __asm + { + mov eax, i1 + mov ebx, i2 + mov ecx, i3 + call asm_sethlinesizes + mov retval, eax + } /* asm */ + return(retval); +} /* sethlinesizes */ + +/* #pragma aux setpalookupaddress parm [eax] */ +long setpalookupaddress(char *i1) +{ + long retval; + __asm + { + mov eax, i1 + call asm_setpalookupaddress + mov retval, eax + } /* asm */ + return(retval); +} /* setpalookupaddress */ + +/* #pragma aux setuphlineasm4 parm [eax][ebx] */ +long setuphlineasm4(long i1, long i2) +{ + long retval; + __asm + { + mov eax, i1 + mov ebx, i2 + call asm_setuphlineasm4 + mov retval, eax + } /* asm */ + return(retval); +} /* setuphlineasm4 */ + +/* #pragma aux hlineasm4 parm [eax][ebx][ecx][edx][esi][edi] */ +long hlineasm4(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval; + __asm + { + mov eax, i1 + mov ebx, i2 + mov ecx, i3 + mov edx, i4 + mov esi, i5 + mov edi, i6 + call asm_hlineasm4 + mov retval, eax + } /* asm */ + return(retval); +} /* hlineasm4 */ + +/* #pragma aux setuprhlineasm4 parm [eax][ebx][ecx][edx][esi][edi] */ +long setuprhlineasm4(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval; + __asm + { + mov eax, i1 + mov ebx, i2 + mov ecx, i3 + mov edx, i4 + mov esi, i5 + mov edi, i6 + call asm_setuprhlineasm4 + mov retval, eax + } /* asm */ + return(retval); +} /* setuprhlineasm4 */ + + + +/* #pragma aux rhlineasm4 parm [eax][ebx][ecx][edx][esi][edi] */ +long rhlineasm4(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval; + __asm + { + mov eax, i1 + mov ebx, i2 + mov ecx, i3 + mov edx, i4 + mov esi, i5 + mov edi, i6 + call asm_rhlineasm4 + mov retval, eax + } /* asm */ + return(retval); +} /* rhlineasm4 */ + + +/* #pragma aux setuprmhlineasm4 parm [eax][ebx][ecx][edx][esi][edi] */ +long setuprmhlineasm4(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval; + __asm + { + mov eax, i1 + mov ebx, i2 + mov ecx, i3 + mov edx, i4 + mov esi, i5 + mov edi, i6 + call asm_setuprmhlineasm4 + mov retval, eax + } /* asm */ + return(retval); +} /* setuprmhlineasm4 */ + +/* #pragma aux rmhlineasm4 parm [eax][ebx][ecx][edx][esi][edi] */ +long rmhlineasm4(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval; + __asm + { + mov eax, i1 + mov ebx, i2 + mov ecx, i3 + mov edx, i4 + mov esi, i5 + mov edi, i6 + call asm_rmhlineasm4 + mov retval, eax + } /* asm */ + return(retval); +} /* rmhlineasm4 */ + + +/* #pragma aux setupqrhlineasm4 parm [eax][ebx][ecx][edx][esi][edi] */ +long setupqrhlineasm4(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval; + __asm + { + mov eax, i1 + mov ebx, i2 + mov ecx, i3 + mov edx, i4 + mov esi, i5 + mov edi, i6 + call asm_setupqrhlineasm4 + mov retval, eax + } /* asm */ + return(retval); +} /* setupqrhlineasm4 */ + + +/* #pragma aux qrhlineasm4 parm [eax][ebx][ecx][edx][esi][edi] */ +long qrhlineasm4(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval; + __asm + { + mov eax, i1 + mov ebx, i2 + mov ecx, i3 + mov edx, i4 + mov esi, i5 + mov edi, i6 + call asm_qrhlineasm4 + mov retval, eax + } /* asm */ + return(retval); +} /* qrhlineasm4 */ + +/* #pragma aux setvlinebpl parm [eax] */ +long setvlinebpl(long i1) +{ + long retval; + __asm + { + mov eax, i1 + call asm_setvlinebpl + mov retval, eax + } /* asm */ + return(retval); +} /* setvlinebpl */ + +/* #pragma aux fixtransluscence parm [eax] */ +long fixtransluscence(long i1) +{ + long retval; + __asm + { + mov eax, i1 + call asm_fixtransluscence + mov retval, eax + } /* asm */ + return(retval); +} /* fixtransluscence */ + +/* #pragma aux prevlineasm1 parm [eax][ebx][ecx][edx][esi][edi] */ +long prevlineasm1(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval; + __asm + { + mov eax, i1 + mov ebx, i2 + mov ecx, i3 + mov edx, i4 + mov esi, i5 + mov edi, i6 + call asm_prevlineasm1 + mov retval, eax + } /* asm */ + return(retval); +} /* prevlineasm1 */ + +/* #pragma aux vlineasm1 parm [eax][ebx][ecx][edx][esi][edi] */ +long vlineasm1(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval; + __asm + { + mov eax, i1 + mov ebx, i2 + mov ecx, i3 + mov edx, i4 + mov esi, i5 + mov edi, i6 + call asm_vlineasm1 + mov retval, eax + } /* asm */ + return(retval); +} /* vlineasm1 */ + + +/* #pragma aux setuptvlineasm parm [eax] */ +long setuptvlineasm(long i1) +{ + long retval; + __asm + { + mov eax, i1 + call asm_setuptvlineasm + mov retval, eax + } /* asm */ + return(retval); +} /* setuptvlineasm */ + + +/* #pragma aux tvlineasm1 parm [eax][ebx][ecx][edx][esi][edi] */ +long tvlineasm1(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval; + __asm + { + mov eax, i1 + mov ebx, i2 + mov ecx, i3 + mov edx, i4 + mov esi, i5 + mov edi, i6 + call asm_tvlineasm1 + mov retval, eax + } /* asm */ + return(retval); +} /* tvlineasm1 */ + +/* #pragma aux setuptvlineasm2 parm [eax][ebx][ecx] */ +long setuptvlineasm2(long i1, long i2, long i3) +{ + long retval; + __asm + { + mov eax, i1 + mov ebx, i2 + mov ecx, i3 + call asm_setuptvlineasm2 + mov retval, eax + } /* asm */ + return(retval); +} /* */ + +/* #pragma aux tvlineasm2 parm [eax][ebx][ecx][edx][esi][edi] */ +long tvlineasm2(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval; + __asm + { + mov eax, i1 + mov ebx, i2 + mov ecx, i3 + mov edx, i4 + mov esi, i5 + mov edi, i6 + call asm_tvlineasm2 + mov retval, eax + } /* asm */ + return(retval); +} /* tvlineasm2 */ + + +/* #pragma aux mvlineasm1 parm [eax][ebx][ecx][edx][esi][edi] */ +long mvlineasm1(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval; + __asm + { + mov eax, i1 + mov ebx, i2 + mov ecx, i3 + mov edx, i4 + mov esi, i5 + mov edi, i6 + call asm_mvlineasm1 + mov retval, eax + } /* asm */ + return(retval); +} /* mvlineasm1 */ + +/* #pragma aux setupvlineasm parm [eax] */ +long setupvlineasm(long i1) +{ + long retval; + __asm + { + mov eax, i1 + call asm_setupvlineasm + mov retval, eax + } /* asm */ + return(retval); +} /* setupvlineasm */ + +/* #pragma aux vlineasm4 parm [ecx][edi] modify [eax ebx ecx edx esi edi] */ +long vlineasm4(long i1, long i2) +{ + long retval; + __asm + { + mov ecx, i1 + mov edi, i2 + call asm_vlineasm4 + mov retval, eax + } /* asm */ + return(retval); +} /* vlineasm4 */ + +/* #pragma aux setupmvlineasm parm [eax] */ +long setupmvlineasm(long i1) +{ + long retval; + __asm + { + mov eax, i1 + call asm_setupmvlineasm + mov retval, eax + } /* asm */ + return(retval); +} /* setupmvlineasm */ + +/* #pragma aux mvlineasm4 parm [ecx][edi] modify [eax ebx ecx edx esi edi] */ +long mvlineasm4(long i1, long i2) +{ + long retval; + __asm + { + mov ecx, i1 + mov edi, i2 + call asm_mvlineasm4 + mov retval, eax + } /* asm */ + return(retval); +} /* mvlineasm4 */ + +/* #pragma aux setupspritevline parm [eax][ebx][ecx][edx][esi][edi] */ +void setupspritevline(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov ecx, i3 + mov edx, i4 + mov esi, i5 + mov edi, i6 + call asm_setupspritevline + } /* asm */ +} /* setupspritevline */ + +/* #pragma aux spritevline parm [eax][ebx][ecx][edx][esi][edi] */ +void spritevline(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov ecx, i3 + mov edx, i4 + mov esi, i5 + mov edi, i6 + call asm_spritevline + } /* asm */ +} /* spritevline */ + +/* #pragma aux msetupspritevline parm [eax][ebx][ecx][edx][esi][edi] */ +void msetupspritevline(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov ecx, i3 + mov edx, i4 + mov esi, i5 + mov edi, i6 + call asm_msetupspritevline + } /* asm */ +} /* msetupspritevline */ + +/* #pragma aux mspritevline parm [eax][ebx][ecx][edx][esi][edi] */ +void mspritevline(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov ecx, i3 + mov edx, i4 + mov esi, i5 + mov edi, i6 + call asm_mspritevline + } /* asm */ +} /* mspritevline */ + +/* #pragma aux tsetupspritevline parm [eax][ebx][ecx][edx][esi][edi] */ +void tsetupspritevline(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov ecx, i3 + mov edx, i4 + mov esi, i5 + mov edi, i6 + call asm_tsetupspritevline + } /* asm */ +} /* tsetupspritevline */ + +/* #pragma aux tspritevline parm [eax][ebx][ecx][edx][esi][edi] */ +void tspritevline(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov ecx, i3 + mov edx, i4 + mov esi, i5 + mov edi, i6 + call asm_tspritevline + } /* asm */ +} /* tspritevline */ + +/* #pragma aux mhline parm [eax][ebx][ecx][edx][esi][edi] */ +long mhline(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval; + __asm + { + mov eax, i1 + mov ebx, i2 + mov ecx, i3 + mov edx, i4 + mov esi, i5 + mov edi, i6 + call asm_mhline + mov retval, eax + } /* asm */ + return(retval); +} /* mhline */ + +/* #pragma aux mhlineskipmodify parm [eax][ebx][ecx][edx][esi][edi] */ +long mhlineskipmodify(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval; + __asm + { + mov eax, i1 + mov ebx, i2 + mov ecx, i3 + mov edx, i4 + mov esi, i5 + mov edi, i6 + call asm_mhlineskipmodify + mov retval, eax + } /* asm */ + return(retval); +} /* mhlineskipmodify */ + +/* #pragma aux msethlineshift parm [eax][ebx] */ +long msethlineshift(long i1, long i2) +{ + long retval; + __asm + { + mov eax, i1 + mov ebx, i2 + call asm_msethlineshift + mov retval, eax + } /* asm */ + return(retval); +} /* msethlineshift */ + +/* #pragma aux thline parm [eax][ebx][ecx][edx][esi][edi] */ +long thline(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval; + __asm + { + mov eax, i1 + mov ebx, i2 + mov ecx, i3 + mov edx, i4 + mov esi, i5 + mov edi, i6 + call asm_thline + mov retval, eax + } /* asm */ + return(retval); +} /* thline */ + +/* #pragma aux thlineskipmodify parm [eax][ebx][ecx][edx][esi][edi] */ +long thlineskipmodify(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval; + __asm + { + mov eax, i1 + mov ebx, i2 + mov ecx, i3 + mov edx, i4 + mov esi, i5 + mov edi, i6 + call asm_thlineskipmodify + mov retval, eax + } /* asm */ + return(retval); +} /* thlineskipmodify */ + +/* #pragma aux tsethlineshift parm [eax][ebx] */ +long tsethlineshift(long i1, long i2) +{ + long retval; + __asm + { + mov eax, i1 + mov ebx, i2 + call asm_tsethlineshift + mov retval, eax + } /* asm */ + return(retval); +} /* tsethlineshift */ + +/* #pragma aux setupslopevlin parm [eax][ebx][ecx] modify [edx] */ +long setupslopevlin(long i1, long i2, long i3) +{ + long retval; + __asm + { + mov eax, i1 + mov ebx, i2 + mov ecx, i3 + call asm_setupslopevlin + mov retval, eax + } /* asm */ + return(retval); +} /* setupslopevlin */ + +/* #pragma aux slopevlin parm [eax][ebx][ecx][edx][esi][edi] */ +long slopevlin(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval; + __asm + { + mov eax, i1 + mov ebx, i2 + mov ecx, i3 + mov edx, i4 + mov esi, i5 + mov edi, i6 + call asm_slopevlin + mov retval, eax + } /* asm */ + return(retval); +} /* slopevlin */ + +/* #pragma aux settransnormal parm */ +long settransnormal(void) +{ + long retval; + __asm + { + call asm_settransnormal + mov retval, eax + } /* asm */ + return(retval); +} /* settransnormal */ + +/* #pragma aux settransreverse parm */ +long settransreverse(void) +{ + long retval; + __asm + { + call asm_settransreverse + mov retval, eax + } /* asm */ + return(retval); +} /* settransreverse */ + +/* #pragma aux setupdrawslab parm [eax][ebx] */ +long setupdrawslab(long i1, long i2) +{ + long retval; + __asm + { + mov eax, i1 + mov ebx, i2 + call asm_setupdrawslab + mov retval, eax + } /* asm */ + return(retval); +} /* setupdrawslab */ + +/* #pragma aux drawslab parm [eax][ebx][ecx][edx][esi][edi] */ +long drawslab(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval; + __asm + { + mov eax, i1 + mov ebx, i2 + mov ecx, i3 + mov edx, i4 + mov esi, i5 + mov edi, i6 + call asm_drawslab + mov retval, eax + } /* asm */ + return(retval); +} /* drawslab */ + +/* #pragma aux stretchhline parm [eax][ebx][ecx][edx][esi][edi] */ +long stretchhline(long i1, long i2, long i3, long i4, long i5, long i6) +{ + long retval; + __asm + { + mov eax, i1 + mov ebx, i2 + mov ecx, i3 + mov edx, i4 + mov esi, i5 + mov edi, i6 + call asm_stretchhline + mov retval, eax + } /* asm */ + return(retval); +} /* drawslab */ + +/* end of a_visualc.c ... */ + diff --git a/buildengine/ascboard.map b/buildengine/ascboard.map new file mode 100755 index 0000000..f7fd51a Binary files /dev/null and b/buildengine/ascboard.map differ diff --git a/buildengine/boards.map b/buildengine/boards.map new file mode 100755 index 0000000..dd9efd9 Binary files /dev/null and b/buildengine/boards.map differ diff --git a/buildengine/bstub.c b/buildengine/bstub.c new file mode 100755 index 0000000..1f3f714 --- /dev/null +++ b/buildengine/bstub.c @@ -0,0 +1,658 @@ +/* + * "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman + * Ken Silverman's official web site: "http://www.advsys.net/ken" + * See the included license file "BUILDLIC.TXT" for license info. + * This file has been modified from Ken Silverman's original release + */ + +#if PLATFORM_DOS +#include +#endif + +#include +#include +#include +#include +#include +#include +#include "engine.h" +#include "platform.h" +#include "build.h" +#include "pragmas.h" +#include "names.h" +#include "bstub.h" +#include "cache1d.h" /* rcg05232001 need groupfile support. */ +#include "display.h" /* rcg05232001 need some "vesa" routines. */ + +/* !!! temporary externs. */ +extern long total_rendered_frames, total_render_time; + +extern char keystatus[256]; + +static char tempbuf[256]; +extern long qsetmode; +extern short searchsector, searchwall, searchstat; +extern long zmode, kensplayerheight; +extern short defaultspritecstat; + +extern short temppicnum, tempcstat, templotag, temphitag, tempextra; +extern char tempshade, temppal, tempxrepeat, tempyrepeat; +extern char somethingintab; + +#define NUMOPTIONS 8 +#define NUMKEYS 19 +static long vesares[13][2] = { + {320,200},{360,200},{320,240},{360,240},{320,400}, + {360,400},{640,350},{640,400},{640,480},{800,600}, + {1024,768},{1280,1024},{1600,1200} +}; + +static char option[NUMOPTIONS] = {0,0,0,0,0,0,1,0}; +static char keys[NUMKEYS] = +{ + 0xc8,0xd0,0xcb,0xcd,0x2a,0x9d,0x1d,0x39, + 0x1e,0x2c,0xd1,0xc9,0x33,0x34, + 0x9c,0x1c,0xd,0xc,0xf, +}; + +extern char buildkeys[NUMKEYS]; + +extern long frameplace, xdimenscale, ydimen; +extern long posx, posy, posz, horiz; +extern short ang, cursectnum; + +static long hang = 0; + +extern long stretchhline(long,long,long,long,long,long); + +#ifdef PLATFORM_DOS +#pragma aux stretchhline parm [eax][ebx][ecx][edx][esi][edi]; +#endif + +#ifdef PLATFORM_DOS +extern void printext16(long xpos, long ypos, short col, short backcol, + char name[82], char fontsize); +#define statusbar_printext16 printext16 +#define statusbar_printext16_noupdate printext16 +#else +extern void statusbar_printext16(long xpos, long ypos, short col, short backcol, char name[82], char fontsize); +#endif + +/* + * Detecting 2D / 3D mode: + * qsetmode is 200 in 3D mode + * qsetmode is 350/480 in 2D mode + * + * You can read these variables when F5-F8 is pressed in 3D mode only: + * + * If (searchstat == 0) WALL searchsector=sector, searchwall=wall + * If (searchstat == 1) CEILING searchsector=sector + * If (searchstat == 2) FLOOR searchsector=sector + * If (searchstat == 3) SPRITE searchsector=sector, searchwall=sprite + * If (searchstat == 4) MASKED WALL searchsector=sector, searchwall=wall + * + * searchsector is the sector of the selected item for all 5 searchstat's + * + * searchwall is undefined if searchstat is 1 or 2 + * searchwall is the wall if searchstat = 0 or 4 + * searchwall is the sprite if searchstat = 3 (Yeah, I know - it says wall, + * but trust me, it's the sprite number) + */ + +long ofinetotalclock, ototalclock, averagefps; +#define AVERAGEFRAMES 32 +static long frameval[AVERAGEFRAMES], framecnt = 0; + +#ifdef PLATFORM_DOS + +void inittimer42(void); +#pragma aux inittimer42 =\ + "in al, 0x61",\ + "or al, 1",\ + "out 0x61, al",\ + "mov al, 0xb4",\ + "out 0x43, al",\ + "xor al, al",\ + "out 0x42, al",\ + "out 0x42, al",\ + modify exact [eax]\ + + +void uninittimer42(void); +#pragma aux uninittimer42 =\ + "in al, 0x61",\ + "and al, 252",\ + "out 0x61, al",\ + modify exact [eax]\ + + +long gettimer42(void); +#pragma aux gettimer42 =\ + "mov al, 0x84",\ + "out 0x43, al",\ + "in al, 0x42",\ + "shl eax, 24",\ + "in al, 0x42",\ + "rol eax, 8",\ + modify [eax] +#else + void inittimer42(void) {} + void uninittimer42(void) {} + int gettimer42(void) { return(0); } +#endif + + +/* rcg05232001 These are defined in build.c ... */ +void editinput(void); +void clearmidstatbar16(void); +short getnumber16(char namestart[80], short num, long maxnumber); +void printmessage16(char name[82]); + + +/* rcg05232001 much thanks to TerminX (Mapster) for the lookup.dat info! */ +static int use_palette_lookup_file(const char *lookup_file) +{ + int retval = 0; + unsigned char *tempbuf = NULL; + unsigned char *ptr = NULL; + unsigned char num_palettes = 0; + int i = 0; + int bytes = 0; + + long in = kopen4load(lookup_file, 0); + if (in != -1) + { + if (kread(in, &num_palettes, 1) == 1) + { + bytes = ( ((int) num_palettes) * 257 ); + tempbuf = (unsigned char *) malloc((size_t) bytes); + if (tempbuf != NULL) + { + if (kread(in, tempbuf, bytes) == bytes) + { + for (i = 0, ptr = tempbuf; i < num_palettes; i++) + { + makepalookup(*ptr, (char *) ptr + 1, 0, 0, 0, 1); + ptr += 257; + } /* for */ + retval = 1; /* success. */ + } /* if */ + free(tempbuf); + } /* if */ + } /* if */ + kclose(in); + } /* if */ + + return(retval); +} /* use_lookup_dat */ + + +void ExtInit(void) +{ + long i, fil; + const char *grpname = getenv("BUILD_GROUPFILE"); + + /* + printf("------------------------------------------------------------------------------\n"); + printf(" BUILD.EXE copyright(c) 1996 by Ken Silverman. You are granted the\n"); + printf(" right to use this software for your personal use only. This is a\n"); + printf(" special version to be used with \"Happy Fun KenBuild\" and may not work\n"); + printf(" properly with other Build engine games. Please refer to license.doc\n"); + printf(" for distribution rights\n"); + printf("------------------------------------------------------------------------------\n"); + getchar(); + */ + + /* Now we check for an envr variable first, for Duke/SW/etc groups. */ + if (grpname == NULL) + grpname = "stuff.dat"; + + /* rcg08122000 panic if groupfile is missing. */ + if (initgroupfile(grpname) < 0) + { + fprintf(stderr, "BUILDGRP: Cannot open \"%s\"! Aborting...\n", grpname); + exit(55); + } /* if */ + + if ((fil = open("setup.dat",O_BINARY|O_RDWR,S_IREAD)) != -1) + { + read(fil,&option[0],NUMOPTIONS); + read(fil,&keys[0],NUMKEYS); + memcpy((void *)buildkeys,(void *)keys,NUMKEYS); /* Trick to make build use setup.dat keys */ + close(fil); + } + if (option[4] > 0) option[4] = 0; + initmouse(); + initengine(); + vidoption = option[0]; xdim = vesares[option[6]&15][0]; ydim = vesares[option[6]&15][1]; + + /* + * You can load your own palette lookup tables here if you just + * copy the right code! (sez Ken). + * + * We try to use a Duke3D lookup.dat first. If that fails, then + * we revert to KenBuild's original method. (sez Ryan). + */ + if (!use_palette_lookup_file("lookup.dat")) + { + for(i=0;i<256;i++) + tempbuf[i] = ((i+32)&255); /* remap colors for screwy palette sectors */ + makepalookup(16,tempbuf,0,0,0,1); + } /* if */ + + kensplayerheight = 32; + zmode = 0; + defaultspritecstat = 0; + pskyoff[0] = 0; pskyoff[1] = 0; pskybits = 1; +} + +void ExtUnInit(void) +{ + uninittimer42(); + uninitgroupfile(); +} + +static long daviewingrange, daaspect, horizval1, horizval2; +void ExtPreCheckKeys(void) +{ + long cosang, sinang, dx, dy, mindx, i; + + if (keystatus[0x3e]) /* F4 - screen re-size */ + { + keystatus[0x3e] = 0; + + /* cycle through all vesa modes, then screen-buffer mode */ + getvalidvesamodes(); + if (vidoption == 1) + { + for(i=0;i 0) + setgamemode(1,validmodexdim[0],validmodeydim[0]); + + inittimer42(); /* Must init here because VESA 0x4F02 messes timer 2 */ + } + + if (keystatus[0x2a]|keystatus[0x36]) + { + if (keystatus[0xcf]) hang = max(hang-1,-182); + if (keystatus[0xc7]) hang = min(hang+1,182); + } + else + { + if (keystatus[0xcf]) hang = max(hang-8,-182); + if (keystatus[0xc7]) hang = min(hang+8,182); + } + if (keystatus[0x4c]) { hang = 0; horiz = 100; } + if (hang != 0) + { + walock[4094] = 255; + if (waloff[4094] == 0) allocache(&waloff[4094],240L*384L,(unsigned char *) &walock[4094]); + setviewtotile(4094,240L,384L); + + cosang = sintable[(hang+512)&2047]; + sinang = sintable[hang&2047]; + + dx = dmulscale1(320,cosang,200,sinang); mindx = dx; + dy = dmulscale1(-200,cosang,320,sinang); + horizval1 = dy*(320>>1)/dx-1; + + dx = dmulscale1(320,cosang,-200,sinang); mindx = min(dx,mindx); + dy = dmulscale1(200,cosang,320,sinang); + horizval2 = dy*(320>>1)/dx+1; + + daviewingrange = scale(65536,16384*(xdim>>1),mindx-16); + daaspect = scale(daviewingrange,scale(320,tilesizx[4094],tilesizy[4094]),horizval2+6-horizval1); + setaspect(daviewingrange,scale(daaspect,ydim*320,xdim*200)); + horiz = 100-divscale15(horizval1+horizval2,daviewingrange); + } +} + +#define MAXVOXMIPS 5 +extern char *voxoff[][MAXVOXMIPS]; +void ExtAnalyzeSprites(void) +{ + long i, *longptr; + spritetype *tspr; + + for(i=0,tspr=&tsprite[0];ipicnum) + { + case PLAYER: + if (!voxoff[0][0]) qloadkvx(0L,"voxel000.kvx"); + tspr->cstat |= 48; + longptr = (long *)voxoff[0][0]; + tspr->xrepeat = scale(tspr->xrepeat,56,longptr[2]); + tspr->yrepeat = scale(tspr->yrepeat,56,longptr[2]); + tspr->picnum = 0; + tspr->shade -= 6; + break; + case BROWNMONSTER: + if (!voxoff[1][0]) qloadkvx(1L,"voxel001.kvx"); + tspr->cstat |= 48; + tspr->picnum = 1; + break; + } + + tspr->shade += 6; + if (sector[tspr->sectnum].ceilingstat&1) + tspr->shade += sector[tspr->sectnum].ceilingshade; + else + tspr->shade += sector[tspr->sectnum].floorshade; + } +} + +static char timerinited = 0; +void ExtCheckKeys(void) +{ + long i, j, p, y, dx, dy, cosang, sinang, bufplc, tsizy, tsizyup15; + + if (qsetmode == 200) /* In 3D mode */ + { + if (hang != 0) + { + bufplc = waloff[4094]+(mulscale16(horiz-100,xdimenscale)+(tilesizx[4094]>>1))*tilesizy[4094]; + setviewback(); + cosang = sintable[(hang+512)&2047]; + sinang = sintable[hang&2047]; + dx = dmulscale1(xdim,cosang,ydim,sinang); + dy = dmulscale1(-ydim,cosang,xdim,sinang); + + tsizy = tilesizy[4094]; + tsizyup15 = (tsizy<<15); + dx = mulscale14(dx,daviewingrange); + dy = mulscale14(dy,daaspect); + sinang = mulscale14(sinang,daviewingrange); + cosang = mulscale14(cosang,daaspect); + p = ylookup[windowy1]+frameplace+windowx2+1; + for(y=windowy1;y<=windowy2;y++) + { + i = divscale16(tsizyup15,dx); + stretchhline(0,(xdim>>1)*i+tsizyup15,xdim>>2,i,mulscale32(i,dy)*tsizy+bufplc,p); + dx -= sinang; dy += cosang; p += ylookup[1]; + } + walock[4094] = 1; + + sprintf(tempbuf,"%ld",(hang*180)>>10); + printext256(0L,8L,31,-1,tempbuf,1); + } + + if (keystatus[0xa]) setaspect(viewingrange+(viewingrange>>8),yxaspect+(yxaspect>>8)); + if (keystatus[0xb]) setaspect(viewingrange-(viewingrange>>8),yxaspect-(yxaspect>>8)); + if (keystatus[0xc]) setaspect(viewingrange,yxaspect-(yxaspect>>8)); + if (keystatus[0xd]) setaspect(viewingrange,yxaspect+(yxaspect>>8)); + + if (!timerinited) + { + timerinited = 1; + inittimer42(); /* Must init here because VESA 0x4F02 messes timer 2 */ + } + i = totalclock-ototalclock; ototalclock += i; + j = ofinetotalclock-gettimer42(); ofinetotalclock -= j; + i = ((i*(1193181/120)-(j&65535)+32768)&0xffff0000)+(j&65535); + if (i) { frameval[framecnt&(AVERAGEFRAMES-1)] = 11931810/i; framecnt++; } + + /* !!! This ifdef should be temporary! --ryan. !!! */ + /*Print MAX FRAME RATE */ + #ifdef PLATFORM_DOS + i = frameval[(framecnt-1)&(AVERAGEFRAMES-1)]; + for(j=AVERAGEFRAMES-1;j>0;j--) i = max(i,frameval[j]); + averagefps = ((averagefps*3+i)>>2); + sprintf(tempbuf,"%ld.%ld",averagefps/10,averagefps%10); + #else + sprintf(tempbuf,"%.2f", (double) (total_rendered_frames / ((double) total_render_time / 1000.0))); + #endif + + printext256(0L,0L,31,-1,tempbuf,1); + + editinput(); + } + else + { + timerinited = 0; + } +} + +void ExtCleanUp(void) +{ +} + +void ExtLoadMap(const char *mapname) +{ +} + +void ExtSaveMap(const char *mapname) +{ +} + +const char *ExtGetSectorCaption(short sectnum) +{ + if ((sector[sectnum].lotag|sector[sectnum].hitag) == 0) + { + tempbuf[0] = 0; + } + else + { + sprintf(tempbuf,"%hu,%hu",(unsigned short)sector[sectnum].hitag, + (unsigned short)sector[sectnum].lotag); + } + return(tempbuf); +} + +const char *ExtGetWallCaption(short wallnum) +{ + if ((wall[wallnum].lotag|wall[wallnum].hitag) == 0) + { + tempbuf[0] = 0; + } + else + { + sprintf(tempbuf,"%hu,%hu",(unsigned short)wall[wallnum].hitag, + (unsigned short)wall[wallnum].lotag); + } + return(tempbuf); +} + +const char *ExtGetSpriteCaption(short spritenum) +{ + if ((sprite[spritenum].lotag|sprite[spritenum].hitag) == 0) + { + tempbuf[0] = 0; + } + else + { + sprintf(tempbuf,"%hu,%hu",(unsigned short)sprite[spritenum].hitag, + (unsigned short)sprite[spritenum].lotag); + } + return(tempbuf); +} + +/* + * printext16 parameters: + * printext16(long xpos, long ypos, short col, short backcol, + * char name[82], char fontsize) + * xpos 0-639 (top left) + * ypos 0-479 (top left) + * col 0-15 + * backcol 0-15, -1 is transparent background + * name + * fontsize 0=8*8, 1=3*5 + * + * drawline16 parameters: + * drawline16(long x1, long y1, long x2, long y2, char col) + * x1, x2 0-639 + * y1, y2 0-143 (status bar is 144 high, origin is top-left of STATUS BAR) + * col 0-15 + */ + +void ExtShowSectorData(short sectnum) /* F5 */ +{ + if (qsetmode == 200) /* In 3D mode */ + { + } + else + { + clearmidstatbar16(); /* Clear middle of status bar */ + + sprintf(tempbuf,"Sector %d",sectnum); + statusbar_printext16(8,32,11,-1,tempbuf,0); + + statusbar_printext16(8,48,11,-1,"8*8 font: ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz 0123456789",0); + statusbar_printext16(8,56,11,-1,"3*5 font: ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz 0123456789",1); + + drawline16(320,68,344,80,4); /* Draw house */ + drawline16(344,80,344,116,4); + drawline16(344,116,296,116,4); + drawline16(296,116,296,80,4); + drawline16(296,80,320,68,4); + } +} + +void ExtShowWallData(short wallnum) /* F6 */ +{ + if (qsetmode == 200) /* In 3D mode */ + { + } + else + { + clearmidstatbar16(); /* Clear middle of status bar */ + + sprintf(tempbuf,"Wall %d",wallnum); + statusbar_printext16(8,32,11,-1,tempbuf,0); + } +} + +void ExtShowSpriteData(short spritenum) /* F6 */ +{ + if (qsetmode == 200) /* In 3D mode */ + { + } + else + { + clearmidstatbar16(); /* Clear middle of status bar */ + + sprintf(tempbuf,"Sprite %d",spritenum); + statusbar_printext16(8,32,11,-1,tempbuf,0); + } +} + +void ExtEditSectorData(short sectnum) /* F7 */ +{ + short nickdata; + + if (qsetmode == 200) /* In 3D mode */ + { + /* Ceiling */ + if (searchstat == 1) + sector[searchsector].ceilingpicnum++; /* Just a stupid example */ + + /* Floor */ + if (searchstat == 2) + sector[searchsector].floorshade++; /* Just a stupid example */ + } + else /* In 2D mode */ + { + sprintf(tempbuf,"Sector (%d) Nick's variable: ",sectnum); + nickdata = 0; + nickdata = getnumber16(tempbuf,nickdata,65536L); + + printmessage16(""); /* Clear message box (top right of status bar) */ + ExtShowSectorData(sectnum); + } +} + +void ExtEditWallData(short wallnum) /* F8 */ +{ + short nickdata; + + if (qsetmode == 200) /* In 3D mode */ + { + } + else + { + sprintf(tempbuf,"Wall (%d) Nick's variable: ",wallnum); + nickdata = 0; + nickdata = getnumber16(tempbuf,nickdata,65536L); + + printmessage16(""); /* Clear message box (top right of status bar) */ + ExtShowWallData(wallnum); + } +} + +void ExtEditSpriteData(short spritenum) /* F8 */ +{ + short nickdata; + + if (qsetmode == 200) /* In 3D mode */ + { + } + else + { + sprintf(tempbuf,"Sprite (%d) Nick's variable: ",spritenum); + nickdata = 0; + nickdata = getnumber16(tempbuf,nickdata,65536L); + printmessage16(""); + + printmessage16(""); /* Clear message box (top right of status bar) */ + ExtShowSpriteData(spritenum); + } +} + +void faketimerhandler(void) +{ +} + + /* Just thought you might want my getnumber16 code */ + +#if 0 +int getnumber16(char namestart[80], short num, long maxnumber) +{ + char buffer[80]; + long j, k, n, danum, oldnum; + + danum = (long)num; + oldnum = danum; + while ((keystatus[0x1c] != 2) && (keystatus[0x1] == 0)) /* Enter, ESC */ + { + sprintf(&buffer,"%s%ld_ ",namestart,danum); + printmessage16(buffer); + + for(j=2;j<=11;j++) /* Scan numbers 0-9 */ + if (keystatus[j] > 0) + { + keystatus[j] = 0; + k = j-1; + if (k == 10) k = 0; + n = (danum*10)+k; + if (n < maxnumber) danum = n; + } + if (keystatus[0xe] > 0) /* backspace */ + { + danum /= 10; + keystatus[0xe] = 0; + } + if (keystatus[0x1c] == 1) /* L. enter */ + { + oldnum = danum; + keystatus[0x1c] = 2; + asksave = 1; + } + } + keystatus[0x1c] = 0; + keystatus[0x1] = 0; + return((short)oldnum); +} +#endif + + +/* end of bstub.c ... */ + diff --git a/buildengine/bstub.h b/buildengine/bstub.h new file mode 100755 index 0000000..794869f --- /dev/null +++ b/buildengine/bstub.h @@ -0,0 +1,45 @@ +/* + * The following functions must be implemented by someone extending Ken's + * BUILD editor; these are called by the editor to allow you to make hooks + * into the program without having to touch build.c yourself. See Ken's + * bstub.c for an example. + * + * Moved to separate header file by Ryan C. Gordon (icculus@clutteredmind.org). + * + * Please do NOT harrass Ken Silverman about any code modifications + * (including this file) to BUILD. + */ + +/* + * "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman + * Ken Silverman's official web site: "http://www.advsys.net/ken" + * See the included license file "BUILDLIC.TXT" for license info. + * This file IS NOT A PART OF Ken Silverman's original release + */ + +#ifndef _INCLUDE_BSTUB_H_ +#define _INCLUDE_BSTUB_H_ + +void ExtInit(void); +void ExtUnInit(void); +void ExtLoadMap(const char *mapname); +void ExtSaveMap(const char *mapname); +const char *ExtGetSectorCaption(short sectnum); +const char *ExtGetWallCaption(short wallnum); +const char *ExtGetSpriteCaption(short spritenum); +void ExtShowSectorData(short sectnum); +void ExtShowWallData(short wallnum); +void ExtShowSpriteData(short spritenum); +void ExtEditSectorData(short sectnum); +void ExtEditWallData(short wallnum); +void ExtEditSpriteData(short spritenum); +void ExtPreCheckKeys(void); +void ExtAnalyzeSprites(void); +void ExtCheckKeys(void); + +#endif /* !defined _INCLUDE_BSTUB_H_ */ + +/* end of bstub.h ... */ + + + diff --git a/buildengine/build.c b/buildengine/build.c new file mode 100755 index 0000000..0f4c70c --- /dev/null +++ b/buildengine/build.c @@ -0,0 +1,6935 @@ +/* + * "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman + * Ken Silverman's official web site: "http://www.advsys.net/ken" + * See the included license file "BUILDLIC.TXT" for license info. + * This file has been modified from Ken Silverman's original release + */ + +/**@file build.c + * @brief master build editor source file + * + * The main implementation file for the Build Editor. + * + */ + +#include +#include +#include +#include + +#include +#include + +#include "engine.h" +#include "platform.h" +#include "build.h" +#include "pragmas.h" + +#include "display.h" + +#include "bstub.h" + +/* +#if !defined (getch) && defined(PLATFORM_UNIX) +#define getch getchar +#endif +*/ + +#define MAXMENUFILES 256 +#define updatecrc16(crc,dat) (crc = (((crc<<8)&65535)^crctable[((((unsigned short)crc)>>8)&65535)^dat])) +static long crctable[256]; +static char kensig[24]; + +#define KEYFIFOSIZ 64 +volatile unsigned char keystatus[256]; /* Which keys on the keyboard are pressed? */ +static volatile unsigned char keyfifo[KEYFIFOSIZ], keyfifoplc, keyfifoend; +static volatile unsigned char readch, oldreadch, extended, keytemp; + +long vel; /* Camera Velocity in Forward-Backward direction */ +long svel; /* Camera Velocity in Left-Right direction */ +long angvel; /* Camera Velocity in Angular Spin */ + +#define NUMKEYS 19 +unsigned char buildkeys[NUMKEYS] = +{ + 0xc8,0xd0,0xcb,0xcd,0x2a,0x9d,0x1d,0x39, + 0x1e,0x2c,0xd1,0xc9,0x33,0x34, + 0x9c,0x1c,0xd,0xc,0xf, +}; +/* Or, in plain english, for those of us who don't speak keyboard: +unsigned char buildkeys[NUMKEYS] = +{ + [UP]-released,[DOWN]-released,[LEFT]-released,[RIGHT]-released,[L.SHIFT]-pushed,[R.CTRL]-pushed,[L.CTRL]-pushed,[SPACE]-pushed, + [A]-pressed,[Z]-pressed,[PgDn]-released,[PgUp]-released,[,|<]-pressed,[.|>]-pressed, + [KPEnter]-pressed,[ENTER]-pressed,[+|=]-pressed,[-|_]-pressed,[TAB]-pressed, +}; +------------------- +BUILD KEYS: +00 = Up arrow +01 = Down arrow +02 = Left arrow +03 = Right arrow +04 = Left Shift key +05 = Right Ctrl key +06 = Left Ctrl key +07 = Space +08 = A +09 = Z +10 = PageDown +11 = PageUp +12 = < +13 = > +14 = Keypad Enter +15 = Enter +16 = + +17 = - +18 = Tab +------------------- +*/ + +long posx; /* The camera's X position (east travel is positive, west travel negative. */ +long posy; /* The camera's Y position (north travel is negative, south travel positive. */ +long posz; /* The camera's Z position (upwards travel is negative, downwards travel positive. */ +long horiz = 100; +short ang; /* The angle the camera is facing */ +short cursectnum; /* The sector the camera is in currently. */ +long hvel; /* The Z velocity of the camera, used for jumping in gravity mode. */ + /* -512 is the starting value when you jump in gravity mode. */ +static long synctics = 0, lockclock = 0; + +extern volatile long stereomode; +extern char vgacompatible; + +extern char picsiz[MAXTILES]; +extern long startposx, startposy, startposz; +extern short startang, startsectnum; +extern long frameplace, pageoffset, ydim16; + +extern long cachesize, artsize; + +static short oldmousebstatus = 0, brightness = 0; +long zlock = 0x7fffffff, zmode = 0, whitecol, kensplayerheight = 32; +short defaultspritecstat = 0; + +static short localartfreq[MAXTILES]; /* This is used to calculate the number of occurences of a tile + in the map, used mainly in the 3d tile picker (key V in 3D mode.) */ +static short localartlookup[MAXTILES], localartlookupnum; + +char tempbuf[4096]; + +char names[MAXTILES][17]; /* Reserve 17 characters to name each tile. (Names come from names.h.) */ + +short asksave = 0; /* Will be 1 if there are unsaved changes, 0 otherwise. */ +extern short editstatus, searchit; +extern long searchx, searchy; /* search input */ +extern short searchsector, searchwall, searchstat; /* search output */ + +extern short pointhighlight, linehighlight, highlightcnt; + +/* Initial Status of Editor */ +short grid = 3; /* Initial Grid Size is 3. */ +short gridlock = 1; /* Grid Locking is On. */ +short showtags = 1; /* Sector/Sprite/Wall labels is On. */ +long zoom = 768; /* Initial Zoom factor is 768. */ +long gettilezoom = 1; + +int numsprites; + +short highlight[MAXWALLS]; +short highlightsector[MAXSECTORS], highlightsectorcnt = -1; +/*extern char textfont[128][8];*/ + +static char pskysearch[MAXSECTORS]; + +short temppicnum, tempcstat, templotag, temphitag, tempextra; +char tempshade, temppal, tempvis, tempxrepeat, tempyrepeat; +char somethingintab = 255; +static char boardfilename[13], oboardfilename[13]; + +static long repeatcountx, repeatcounty; + +#define BUILD_MAXPATH 255 +static char menuname[MAXMENUFILES][BUILD_MAXPATH+1], curpath[80], menupath[80]; +static long menunamecnt, menuhighlight; + +static long fillist[640]; + +static char scantoasc[128] = +{ + 0,0,'1','2','3','4','5','6','7','8','9','0','-','=',0,0, + 'q','w','e','r','t','y','u','i','o','p','[',']',0,0,'a','s', + 'd','f','g','h','j','k','l',';',39,'`',0,92,'z','x','c','v', + 'b','n','m',',','.','/',0,'*',0,32,0,0,0,0,0,0, + 0,0,0,0,0,0,0,'7','8','9','-','4','5','6','+','1', + '2','3','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, +}; +static char scantoascwithshift[128] = +{ + 0,0,'!','@','#','$','%','^','&','*','(',')','_','+',0,0, + 'Q','W','E','R','T','Y','U','I','O','P','{','}',0,0,'A','S', + 'D','F','G','H','J','K','L',':',34,'~',0,'|','Z','X','C','V', + 'B','N','M','<','>','?',0,'*',0,32,0,0,0,0,0,0, + 0,0,0,0,0,0,0,'7','8','9','-','4','5','6','+','1', + '2','3','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, +}; + + +/**@brief Build Movement and Accelleration routine + * + * This code handles the default turning, walking, and strafing actions. + * This function acts on buildkeys[] 0, 1, 2, 3, 5, 12, and 13. + */ +void keytimerstuff(void) +{ + /* Turn and strafe with the left and right arrow keys. */ + if (keystatus[buildkeys[5]] == 0) /* Is [R.Ctrl] down? */ + { + /* No, it isn't, we want to turn. */ + if (keystatus[buildkeys[2]] > 0) angvel = max(angvel-16,-128); + if (keystatus[buildkeys[3]] > 0) angvel = min(angvel+16,127); + } + else + { + /* Yes, it is, we want to strafe. */ + if (keystatus[buildkeys[2]] > 0) svel = min(svel+8,127); + if (keystatus[buildkeys[3]] > 0) svel = max(svel-8,-128); + } + + /* Move Forward */ + if (keystatus[buildkeys[0]] > 0) vel = min(vel+8,127); + + /* Move Backward */ + if (keystatus[buildkeys[1]] > 0) vel = max(vel-8,-128); + + /* Use the [<] and [>] keys to strafe, too. */ + if (keystatus[buildkeys[12]] > 0) svel = min(svel+8,127); + if (keystatus[buildkeys[13]] > 0) svel = max(svel-8,-128); + + /* Accelleration Limiter for Movement */ + if (angvel < 0) angvel = min(angvel+12,0); + if (angvel > 0) angvel = max(angvel-12,0); + if (svel < 0) svel = min(svel+2,0); + if (svel > 0) svel = max(svel-2,0); + if (vel < 0) vel = min(vel+2,0); + if (vel > 0) vel = max(vel-2,0); +} + + +void __interrupt __far timerhandler(void) +{ + totalclock++; + keytimerstuff(); + + #ifdef PLATFORM_DOS + outp(0x20,0x20); + #endif +} + + +void __interrupt __far keyhandler(void) +{ + /* + * ryan sez: End Of Interrupt call on DOS. This seems like a + * dangerous place to put it, if you ask me, but oh well. --ryan. + */ + #ifdef PLATFORM_DOS + koutp(0x20,0x20); + #endif + + oldreadch = readch; readch = _readlastkeyhit(); + + #if 0 + printf("keyhandler() got a (0x%X) ... \n", readch); + #endif + + /* + * ryan sez: these inp/outp calls read the keyboard state, + * reset the keyboard, and put the original state back in. + * This is apparently needed on some XTs, but not newer boxes, and + * obviously never on Linux. --ryan. + */ + #ifdef PLATFORM_DOS + keytemp = kinp(0x61); koutp(0x61,keytemp|128); koutp(0x61,keytemp&127); + #else + keytemp = readch; + #endif + + if ((readch|1) == 0xe1) { extended = 128; return; } + if (oldreadch != readch) + { + if ((readch&128) == 0) + { + keytemp = readch+extended; + if (keystatus[keytemp] == 0) + { + keystatus[keytemp] = 1; + keyfifo[keyfifoend] = keytemp; + keyfifo[(keyfifoend+1)&(KEYFIFOSIZ-1)] = 1; + keyfifoend = ((keyfifoend+2)&(KEYFIFOSIZ-1)); + } + } + else + { + keytemp = (readch&127)+extended; + keystatus[keytemp] = 0; + keyfifo[keyfifoend] = keytemp; + keyfifo[(keyfifoend+1)&(KEYFIFOSIZ-1)] = 0; + keyfifoend = ((keyfifoend+2)&(KEYFIFOSIZ-1)); + } + } + extended = 0; +} + + +static void _initkeys(void) +{ + long i; + + keyfifoplc = 0; keyfifoend = 0; + for(i=0;i<256;i++) keystatus[i] = 0; + initkeys(); /* rcg06082001 platform driver-specific initialization. */ +} + + +#define loadbyte(fil,tempbuf,bufplc,dat) \ +{ \ + if (bufplc == 0) \ + { \ + for(bufplc=0;bufplc<4096;bufplc++) \ + tempbuf[bufplc] = 0; \ + bufplc = 0; \ + read(fil,tempbuf,4096); \ + } \ + dat = tempbuf[bufplc]; \ + bufplc = ((bufplc+1)&4095); \ +} \ + + + +/**@brief Load Tile Names from names.h + * + * This function will load the names of special tiles into names[], + * provided the file names.h is in the current directory. + * @return -1 on failure, 0 on success. + */ +int loadnames(void) +{ + char buffer[80], firstch, ch; + long fil, i, num, buffercnt, bufplc; + + if ((fil = open("names.h",O_BINARY|O_RDWR,S_IREAD)) == -1) return(-1); + bufplc = 0; + do { loadbyte(fil,tempbuf,bufplc,firstch); } while (firstch != '#'); + + while ((firstch == '#') || (firstch == '/')) + { + do { loadbyte(fil,tempbuf,bufplc,ch); } while (ch > 32); + + buffercnt = 0; + do + { + loadbyte(fil,tempbuf,bufplc,ch); + if (ch > 32) buffer[buffercnt++] = ch; + } + while (ch > 32); + + num = 0; + do + { + loadbyte(fil,tempbuf,bufplc,ch); + if ((ch >= 48) && (ch <= 57)) num = num*10+(ch-48); + } + while ((ch != '\r') && (ch != '\n')); + for(i=0;i=0;i--) + { + if (((k^a)&0x8000) > 0) + a = ((a<<1)&65535) ^ 0x1021; /* 0x1021 = genpoly */ + else + a = ((a<<1)&65535); + k = ((k<<1)&65535); + } + crctable[j] = (a&65535); + } +} + + +void initmenupaths(char *filename) +{ + long i; + + strcpy(curpath,filename); + i = 0; + while ((i < 80) && (curpath[i] != 0)) i++; + while ((i > 0) && (curpath[i] != 92)) i--; + curpath[i] = 0; + strcpy(menupath,curpath); +} + + +/**@brief Draw the mouse in 3D mode. + * + * This function will draw the white 3D mode cursor at + * the location [searchx, searchy]. + * (The mouse routine should set these automatically.) + */ +void showmouse(void) +{ + long i; + + for(i=1;i<=4;i++) + { + plotpixel(searchx+i,searchy,whitecol); + plotpixel(searchx-i,searchy,whitecol); + plotpixel(searchx,searchy-i,whitecol); + plotpixel(searchx,searchy+i,whitecol); + } +} + + +void fixrepeats(short i) +{ + long dax, day, dist; + + dax = wall[wall[i].point2].x-wall[i].x; + day = wall[wall[i].point2].y-wall[i].y; + dist = ksqrt(dax*dax+day*day); + dax = wall[i].xrepeat; day = wall[i].yrepeat; + wall[i].xrepeat = (char)min(max(mulscale10(dist,day),1),255); +} + + +/**@brief Show the tile picker. + * + * This function will show the tile picker and let the user change a tile. + * @param tilenum The current tile (what to return if the user cancels.) + * @return The new user-selected tile. + * @remark Notes: + * Make sure you set searchstat for the right situation if you call this function yourself: + * 0: Wall tile + * 1 or 2: Ceiling or Floor tile. + * 3: Sprite + * 4: Wall Above tile (overpic) -- + * + */ +long gettile(long tilenum) +{ + char snotbuf[80]; + long i, j, k, otilenum, topleft, gap, temp, templong; + long xtiles; /* Number of tiles that will fit horizontally on the screen. */ + long ytiles; /* Number of tiles that will fit vertically on the screen. */ + long tottiles; /* Total tiles that fit on the screen at once. */ + + /* Calculate how the tiles fit, given the tile previews are 32 pixels wide and tall. */ + xtiles = (xdim>>6); ytiles = (ydim>>6); tottiles = xtiles*ytiles; + otilenum = tilenum; /* Back up the old value, in case the user cancels. */ + + keystatus[0x2f] = 0; /* Clear [V] */ + /* Recalculate the tile occurance stats for the "choose commonly used tile" screen. */ + for(i=0;i>1); + do + { + for(i=0;i= 0)) + { + templong = localartfreq[temp]; + localartfreq[temp] = localartfreq[temp+gap]; + localartfreq[temp+gap] = templong; + templong = localartlookup[temp]; + localartlookup[temp] = localartlookup[temp+gap]; + localartlookup[temp+gap] = templong; + + if (tilenum == temp) + tilenum = temp+gap; + else if (tilenum == temp+gap) + tilenum = temp; + + temp -= gap; + } + } + gap >>= 1; + } + while (gap > 0); + localartlookupnum = 0; + while (localartfreq[localartlookupnum] > 0) + localartlookupnum++; + + if (localartfreq[0] == 0) + { + tilenum = otilenum; + localartlookupnum = MAXTILES; + for(i=0;i MAXTILES-(tottiles<<(gettilezoom<<1))) topleft = MAXTILES-(tottiles<<(gettilezoom<<1)); + while ((keystatus[0x1c]|keystatus[1]) == 0) + { + drawtilescreen(topleft,tilenum); + if ((vidoption != 2) && ((vidoption != 1) || (vgacompatible == 1))) limitrate(); + + nextpage(); + synctics = totalclock-lockclock; + lockclock += synctics; + + if ((keystatus[0x37] > 0) && (gettilezoom < 2)) + { + gettilezoom++; + topleft = ((tilenum/(xtiles< MAXTILES-(tottiles<<(gettilezoom<<1))) topleft = MAXTILES-(tottiles<<(gettilezoom<<1)); + keystatus[0x37] = 0; + } + if ((keystatus[0xb5] > 0) && (gettilezoom > 0)) + { + gettilezoom--; + topleft = ((tilenum/(xtiles< MAXTILES-(tottiles<<(gettilezoom<<1))) topleft = MAXTILES-(tottiles<<(gettilezoom<<1)); + keystatus[0xb5] = 0; + } + if ((keystatus[0xcb] > 0) && (tilenum > 0)) + tilenum--, keystatus[0xcb] = 0; + if ((keystatus[0xcd] > 0) && (tilenum < MAXTILES-1)) + tilenum++, keystatus[0xcd] = 0; + if ((keystatus[0xc8] > 0) && (tilenum >= (xtiles< 0) && (tilenum < MAXTILES-(xtiles< 0) && (tilenum >= (xtiles< 0) && (tilenum < MAXTILES-(xtiles<= MAXTILES) tilenum = MAXTILES-1; + keystatus[0xd1] = 0; + } + if (keystatus[0x2f] > 0) /* V */ + { + keystatus[0x2f] = 0; + if (tilenum < localartlookupnum) + tilenum = localartlookup[tilenum]; + else + tilenum = 0; + localartlookupnum = MAXTILES; + for(i=0;i 0) /* G (goto) */ + { + if (tilenum < localartlookupnum) /* Automatically press 'V' */ + tilenum = localartlookup[tilenum]; + else + tilenum = 0; + localartlookupnum = MAXTILES; + for(i=0;i 0) + { + keystatus[((k+9)%10)+2] = 0; + i = (j*10)+k; + if (i < MAXTILES) j = i; + } + if (keystatus[0xe] > 0) + { + keystatus[0xe] = 0; + j /= 10; + } + if (keystatus[0x1c] > 0) + { + keystatus[0x1c] = 0; + tilenum = j; + break; + } + } + } + while (tilenum < topleft) topleft -= (xtiles<= topleft+(tottiles<<(gettilezoom<<1))) topleft += (xtiles< MAXTILES-(tottiles<<(gettilezoom<<1))) topleft = MAXTILES-(tottiles<<(gettilezoom<<1)); + } + + if (keystatus[0x1c] == 0) + { + tilenum = otilenum; + } + else + { + if (tilenum < localartlookupnum) + { + tilenum = localartlookup[tilenum]; + if ((tilesizx[tilenum] == 0) || (tilesizy[tilenum] == 0)) + tilenum = otilenum; + } + else + tilenum = otilenum; + } + keystatus[0x1] = 0; + keystatus[0x1c] = 0; + return(tilenum); +} + + +char changechar(char dachar, long dadir, char smooshyalign, char boundcheck) +{ + if (dadir < 0) + { + if ((dachar > 0) || (boundcheck == 0)) + { + dachar--; + if (smooshyalign > 0) + dachar = (dachar&0xf8); + } + } + else if (dadir > 0) + { + if ((dachar < 255) || (boundcheck == 0)) + { + dachar++; + if (smooshyalign > 0) + { + if (dachar >= 256-8) dachar = 255; + else dachar = ((dachar+7)&0xf8); + } + } + } + return(dachar); +} + + +static char visited[8192]; + +long GetWallZPeg(long nWall) +{ + long z=0, nSector, nNextSector; + + nSector = sectorofwall((short)nWall); + nNextSector = wall[nWall].nextsector; + if (nNextSector == -1) + { + /* 1-sided wall */ + if (wall[nWall].cstat&4) z = sector[nSector].floorz; + else z = sector[nSector].ceilingz; + } + else + { + /* 2-sided wall */ + if (wall[nWall].cstat&4) + z = sector[nSector].ceilingz; + else + { + if (sector[nNextSector].ceilingz > sector[nSector].ceilingz) + z = sector[nNextSector].ceilingz; /* top step */ + if (sector[nNextSector].floorz < sector[nSector].floorz) + z = sector[nNextSector].floorz; /* bottom step */ + } + } + return(z); +} + + +void AlignWalls(long nWall0, long z0, long nWall1, long z1, long nTile) +{ + long n; + + /* do the x alignment */ + wall[nWall1].cstat &= ~0x0108; /* Set to non-flip */ + wall[nWall1].xpanning = (char)((wall[nWall0].xpanning+(wall[nWall0].xrepeat<<3))%tilesizx[nTile]); + + z1 = GetWallZPeg(nWall1); + + for(n=(picsiz[nTile]>>4);((1<>(n+3))); +} + + +void AutoAlignWalls(long nWall0, long ply) +{ + long z0, z1, nTile, nWall1, branch, visible, nNextSector, nSector; + + nTile = wall[nWall0].picnum; + branch = 0; + if (ply == 0) + { + /* clear visited bits */ + memset(visited,0,sizeof(visited)); + visited[nWall0] = 1; + } + + z0 = GetWallZPeg(nWall0); + + nWall1 = wall[nWall0].point2; + + /* loop through walls at this vertex in CCW order */ + while (1) + { + /* break if this wall would connect us in a loop */ + if (visited[nWall1]) break; + + visited[nWall1] = 1; + + /* break if reached back of left wall */ + if (wall[nWall1].nextwall == nWall0) break; + + if (wall[nWall1].picnum == nTile) + { + z1 = GetWallZPeg(nWall1); + visible = 0; + + nNextSector = wall[nWall1].nextsector; + if (nNextSector < 0) + visible = 1; + else + { + /* ignore two sided walls that have no visible face */ + nSector = wall[wall[nWall1].nextwall].nextsector; + if (getceilzofslope((short)nSector,wall[nWall1].x,wall[nWall1].y) < + getceilzofslope((short)nNextSector,wall[nWall1].x,wall[nWall1].y)) + visible = 1; + + if (getflorzofslope((short)nSector,wall[nWall1].x,wall[nWall1].y) > + getflorzofslope((short)nNextSector,wall[nWall1].x,wall[nWall1].y)) + visible = 1; + } + + if (visible) + { + branch++; + AlignWalls(nWall0,z0,nWall1,z1,nTile); + + /* if wall was 1-sided, no need to recurse */ + if (wall[nWall1].nextwall < 0) + { + nWall0 = nWall1; + z0 = GetWallZPeg(nWall0); + nWall1 = wall[nWall0].point2; + branch = 0; + continue; + } + else + AutoAlignWalls(nWall1,ply+1); + } + } + + if (wall[nWall1].nextwall < 0) break; + nWall1 = wall[wall[nWall1].nextwall].point2; + } +} + + +#if (defined PLATFORM_DOS) + +#define statusbar_printext16 printext16 +#define statusbar_printext16_noupdate printext16 + +#else +void statusbar_printext16(long xpos, long ypos, short col, short backcol, char name[82], char fontsize) +{ + printext256(xpos, ypos + 336, col, backcol, name, fontsize); +} + +void statusbar_printext16_noupdate(long xpos, long ypos, short col, short backcol, char name[82], char fontsize) +{ + printext256_noupdate(xpos, ypos + 336, col, backcol, name, fontsize); +} +#endif + + +void printmessage16(char name[82]) +{ + char snotbuf[60]; + long i; + + i = 0; + while ((name[i] != 0) && (i < 54)) + { + snotbuf[i] = name[i]; + i++; + } + while (i < 54) + { + snotbuf[i] = 32; + i++; + } + snotbuf[54] = 0; + + statusbar_printext16(200L, 8L, 0, 6, snotbuf, 0); +} + + +void printmessage256(char name[82]) +{ + char snotbuf[40]; + long i; + + i = 0; + while ((name[i] != 0) && (i < 38)) + { + snotbuf[i] = name[i]; + i++; + } + while (i < 38) + { + snotbuf[i] = 32; + i++; + } + snotbuf[38] = 0; + + printext256(0L,0L,whitecol,0,snotbuf,0); +} + + +short getnumber16(char namestart[80], short num, long maxnumber) +{ + char buffer[80]; + long j, k, n, danum, oldnum; + + danum = (long) num; + oldnum = danum; + while ((keystatus[0x1c] != 2) && (keystatus[0x1] == 0)) + { + sprintf(buffer, "%s%ld_ ", namestart, danum); + printmessage16(buffer); + + _idle(); /* rcg06232002 prevent hang while waiting for input. */ + + for(j=2;j<=11;j++) + if (keystatus[j] > 0) + { + keystatus[j] = 0; + k = j-1; + if (k == 10) k = 0; + n = (danum*10)+k; + if (n < maxnumber) danum = n; + } + if (keystatus[0xe] > 0) /* backspace */ + { + danum /= 10; + keystatus[0xe] = 0; + } + if (keystatus[0x1c] == 1) + { + oldnum = danum; + keystatus[0x1c] = 2; + asksave = 1; + } + } + keystatus[0x1c] = 0; + keystatus[0x1] = 0; + return((short)oldnum); +} + + +short getnumber256(char namestart[80], short num, long maxnumber) +{ + char buffer[80]; + long j, k, n, danum, oldnum; + + danum = (long)num; + oldnum = danum; + while ((keystatus[0x1c] != 2) && (keystatus[0x1] == 0)) + { + drawrooms(posx,posy,posz,ang,horiz,cursectnum); + ExtAnalyzeSprites(); + drawmasks(); + + sprintf(buffer,"%s%ld_ ",namestart,danum); + printmessage256(buffer); + nextpage(); + + for(j=2;j<=11;j++) + if (keystatus[j] > 0) + { + keystatus[j] = 0; + k = j-1; + if (k == 10) k = 0; + n = (danum*10)+k; + if (n < maxnumber) danum = n; + } + if (keystatus[0xe] > 0) /* backspace */ + { + danum /= 10; + keystatus[0xe] = 0; + } + if (keystatus[0x1c] == 1) + { + oldnum = danum; + keystatus[0x1c] = 2; + asksave = 1; + } + } + keystatus[0x1c] = 0; + keystatus[0x1] = 0; + + lockclock = totalclock; /* Reset timing */ + + return((short)oldnum); +} + + +void updatenumsprites(void) +{ + long i; + + numsprites = 0; + for(i=0;i 0)) + if ((fileinfo.name[0] != '.') || (fileinfo.name[1] != 0)) + { + strcpy(menuname[menunamecnt],fileinfo.name); + menuname[menunamecnt][BUILD_MAXPATH] = type; + menunamecnt++; + } + } + while (_dos_findnext(&fileinfo) == 0); + +#elif (defined PLATFORM_UNIX) + + DIR *dir; + struct dirent *dent; + struct stat statbuf; + int add_this; + char *ptr = NULL; + int len = 0; + int subdirs = 0; + + if (strcmp(kind,"SUBD") == 0) + subdirs = 1; + + dir = opendir("."); + if (dir == NULL) + return(-1); + + do + { + add_this = 0; + dent = readdir(dir); + if (dent != NULL) + { + if (stat(dent->d_name, &statbuf) == 0) + { + if (subdirs) + { + if (S_ISDIR(statbuf.st_mode)) + add_this = 1; + } /* if */ + else + { + /* need to expand support if this assertion ever fails. */ + assert(stricmp(kind, "*.MAP") == 0); + len = strlen(dent->d_name); + if (len >= 5) + { + ptr = ((char *) dent->d_name) + len; + ptr += strlen(ptr) - 4; + if (stricmp(ptr, ".MAP") == 0) + add_this = 1; + } /* if */ + } /* else */ + + if (add_this) + { + strcpy(menuname[menunamecnt],dent->d_name); + menuname[menunamecnt][BUILD_MAXPATH] = subdirs; + menunamecnt++; + } /* if */ + } /* if */ + } /* if */ + } while (dent != NULL); + + closedir(dir); + +#endif + return(0); +} + + +void sortfilenames(void) +{ + char sortbuffer[BUILD_MAXPATH+1]; + long i, j, k; + + for(i=1;i>3,0L,640L*336L); +#else + fillscreen16(0,0L,640L*336L); +#endif + if (menuhighlight < 0) menuhighlight = 0; + if (menuhighlight >= menunamecnt) menuhighlight = menunamecnt-1; + + newhighlight = menuhighlight; + do + { + if (menunamecnt <= 36) + { + topplc = 0; + } + else + { + topplc = newhighlight-11; + if (topplc < 0) topplc = 0; + if (topplc > menunamecnt-37) topplc = menunamecnt-37; + } + + for(i=0;i= 0) && (i-topplc <= 36)) + { + if (menuname[i][BUILD_MAXPATH] == 1) + { + #ifdef PLATFORM_DOS + printext16(0L,((i-topplc)<<3)+16L+((399360-pageoffset)/640),4,0,buffer,0); + #else + printext16(0L,((i-topplc)<<3)+16L,4,0,buffer,0); + #endif + } + else + { + #ifdef PLATFORM_DOS + printext16(0L,((i-topplc)<<3)+16L+((399360-pageoffset)/640),7,0,buffer,0); + #else + printext16(0L,((i-topplc)<<3)+16L,7,0,buffer,0); + #endif + } + } + } + + keystatus[0xcb] = 0; + keystatus[0xcd] = 0; + keystatus[0xc8] = 0; + keystatus[0xd0] = 0; + keystatus[0x1c] = 0; + keystatus[1] = 0; + ch = 0; /* Interesting fakery of ch = getch() */ + while (ch == 0) + { + _idle(); + if (keystatus[0xcb] > 0) ch = 75; + if (keystatus[0xcd] > 0) ch = 77; + if (keystatus[0xc8] > 0) ch = 72; + if (keystatus[0xd0] > 0) ch = 80; + if (keystatus[0x1c] > 0) ch = 13; + if (keystatus[1] > 0) ch = 27; + } + + if ((ch == 75) || (ch == 72)) + { + newhighlight--; + if (newhighlight < 0) + newhighlight = menunamecnt-1; + } + if ((ch == 77) || (ch == 80)) + { + newhighlight++; + if (newhighlight >= menunamecnt) + newhighlight = 0; + } + if ((ch == 13) && (menuname[newhighlight][BUILD_MAXPATH] == 1)) + { + if ((menuname[newhighlight][0] == '.') && (menuname[newhighlight][1] == '.')) + { + i = 0; + while ((i < 80) && (menupath[i] != 0)) i++; + while ((i > 0) && (menupath[i] != 92)) i--; + menupath[i] = 0; + } + else + { + #if ((defined PLATFORM_DOS) || (defined PLATFORM_WIN32)) + strcat(menupath,"\\"); + #elif PLATFORM_UNIX + strcat(menupath,"/"); + #else + #error Define your platform! + #endif + strcat(menupath,menuname[newhighlight]); + } + chdir(menuname[newhighlight]); + menunamecnt = 0; + getfilenames("SUBD"); + getfilenames("*.MAP"); + sortfilenames(); + newhighlight = 0; + ch = 0; +#ifdef PLATFORM_DOS + fillscreen16((399360-pageoffset)>>3,0L,640L*336L); +#else + fillscreen16(0, 0L,640L*336L); +#endif + } + } + while ((ch != 13) && (ch != 27)); + + if (ch == 13) + { + menuhighlight = newhighlight; + return(newhighlight); + } + return(-1); +} + + +int fillsector(short sectnum, char fillcolor) +{ + long x1, x2, y1, y2, sy, y, templong; + long lborder, rborder, uborder, dborder, miny, maxy, dax; + short z, zz, startwall, endwall, fillcnt; + + lborder = 0; rborder = 640; + uborder = 0; dborder = ydim16; + + if (sectnum == -1) + return(0); + miny = dborder-1; + maxy = uborder; + startwall = sector[sectnum].wallptr; + endwall = startwall + sector[sectnum].wallnum - 1; + for(z=startwall;z<=endwall;z++) + { + y1 = (((wall[z].y-posy)*zoom)>>14)+200; + y2 = (((wall[wall[z].point2].y-posy)*zoom)>>14)+200; + if (y1 < miny) miny = y1; + if (y2 < miny) miny = y2; + if (y1 > maxy) maxy = y1; + if (y2 > maxy) maxy = y2; + } + if (miny < uborder) miny = uborder; + if (maxy >= dborder) maxy = dborder-1; + + for(sy=miny+(numframes%3);sy<=maxy;sy+=3) + { + y = posy+(((sy-200)<<14)/zoom); + + fillist[0] = lborder; fillcnt = 1; + for(z=startwall;z<=endwall;z++) + { + x1 = wall[z].x; x2 = wall[wall[z].point2].x; + y1 = wall[z].y; y2 = wall[wall[z].point2].y; + if (y1 > y2) + { + templong = x1; x1 = x2; x2 = templong; + templong = y1; y1 = y2; y2 = templong; + } + if ((y1 <= y) && (y2 > y)) + /*if (x1*(y-y2) + x2*(y1-y) <= 0)*/ + { + dax = x1+scale(y-y1,x2-x1,y2-y1); + dax = (((dax-posx)*zoom)>>14)+320; + if (dax >= lborder) + fillist[fillcnt++] = dax; + } + } + if (fillcnt > 0) + { + for(z=1;z rborder) break; + if (fillist[z+1] > rborder) + fillist[z+1] = rborder; + drawline16(fillist[z],sy,fillist[z+1],sy,fillcolor); + } + } + } + return(0); +} + + +int clockdir(short wallstart) /* Returns: 0 is CW, 1 is CCW */ +{ + short i, themin; + long minx, templong, x0, x1, x2, y0, y1, y2; + + minx = 0x7fffffff; + themin = -1; + i = wallstart-1; + do + { + i++; + if (wall[wall[i].point2].x < minx) + { + minx = wall[wall[i].point2].x; + themin = i; + } + } + while ((wall[i].point2 != wallstart) && (i < MAXWALLS)); + + x0 = wall[themin].x; + y0 = wall[themin].y; + x1 = wall[wall[themin].point2].x; + y1 = wall[wall[themin].point2].y; + x2 = wall[wall[wall[themin].point2].point2].x; + y2 = wall[wall[wall[themin].point2].point2].y; + + if ((y1 >= y2) && (y1 <= y0)) return(0); + if ((y1 >= y0) && (y1 <= y2)) return(1); + + templong = (x0-x1)*(y2-y1) - (x2-x1)*(y0-y1); + if (templong < 0) + return(0); + else + return(1); +} + + +short whitelinescan(short dalinehighlight) +{ + long i, j, k; + short sucksect, newnumwalls; + + sucksect = sectorofwall(dalinehighlight); + + memcpy(§or[numsectors],§or[sucksect],sizeof(sectortype)); + sector[numsectors].wallptr = numwalls; + sector[numsectors].wallnum = 0; + i = dalinehighlight; + newnumwalls = numwalls; + do + { + j = lastwall((short)i); + if (wall[j].nextwall >= 0) + { + j = wall[j].point2; + for(k=0;k= 0) /* Check for early exit */ + { + k = wall[i].nextwall; + if ((wall[k].x == x2) && (wall[k].y == y2)) + if ((wall[wall[k].point2].x == x1) && (wall[wall[k].point2].y == y1)) + return(0); + } + + wall[i].nextsector = -1; + wall[i].nextwall = -1; + for(j=0;j= 0) + { + wall[newnumwalls].nextwall += deststartwall-startwall; + wall[newnumwalls].nextsector += destsector-soursector; + } + newnumwalls++; + } + +#if 0 + for(j=deststartwall;j= 0) + checksectorpointer(wall[j].nextwall,wall[j].nextsector); + checksectorpointer((short)j,destsector); + } +#endif + + if (newnumwalls > deststartwall) + { + /* duplicate sectors */ + memcpy(§or[destsector],§or[soursector],sizeof(sectortype)); + sector[destsector].wallptr = deststartwall; + sector[destsector].wallnum = newnumwalls-deststartwall; + + if (copystat == 1) + { + /* duplicate sprites */ + j = headspritesect[soursector]; + while (j >= 0) + { + k = nextspritesect[j]; + + m = insertsprite(destsector,sprite[j].statnum); + memcpy(&sprite[m],&sprite[j],sizeof(spritetype)); + sprite[m].sectnum = destsector; /* Don't let memcpy overwrite sector! */ + + j = k; + } + } + + } +} + + +void showsectordata(short sectnum) +{ + char snotbuf[80]; + + sprintf(snotbuf,"Sector %d",sectnum); + statusbar_printext16(8,32,11,-1,snotbuf,0); + sprintf(snotbuf,"Firstwall: %d",sector[sectnum].wallptr); + statusbar_printext16(8,48,11,-1,snotbuf,0); + sprintf(snotbuf,"Numberofwalls: %d",sector[sectnum].wallnum); + statusbar_printext16(8,56,11,-1,snotbuf,0); + sprintf(snotbuf,"Firstsprite: %d",headspritesect[sectnum]); + statusbar_printext16(8,64,11,-1,snotbuf,0); + sprintf(snotbuf,"Tags: %d, %d",sector[sectnum].hitag,sector[sectnum].lotag); + statusbar_printext16(8,72,11,-1,snotbuf,0); + sprintf(snotbuf," (0x%x), (0x%x)",sector[sectnum].hitag,sector[sectnum].lotag); + statusbar_printext16(8,80,11,-1,snotbuf,0); + sprintf(snotbuf,"Extra: %d",sector[sectnum].extra); + statusbar_printext16(8,88,11,-1,snotbuf,0); + sprintf(snotbuf,"Visibility: %d",sector[sectnum].visibility); + statusbar_printext16(8,96,11,-1,snotbuf,0); + sprintf(snotbuf,"Pixel height: %ld",(sector[sectnum].floorz-sector[sectnum].ceilingz)>>8); + statusbar_printext16(8,104,11,-1,snotbuf,0); + + statusbar_printext16(200,32,11,-1,"CEILINGS:",0); + sprintf(snotbuf,"Flags (hex): %x",sector[sectnum].ceilingstat); + statusbar_printext16(200,48,11,-1,snotbuf,0); + sprintf(snotbuf,"(X,Y)pan: %d, %d",sector[sectnum].ceilingxpanning,sector[sectnum].ceilingypanning); + statusbar_printext16(200,56,11,-1,snotbuf,0); + sprintf(snotbuf,"Shade byte: %d",sector[sectnum].ceilingshade); + statusbar_printext16(200,64,11,-1,snotbuf,0); + sprintf(snotbuf,"Z-coordinate: %ld",sector[sectnum].ceilingz); + statusbar_printext16(200,72,11,-1,snotbuf,0); + sprintf(snotbuf,"Tile number: %d",sector[sectnum].ceilingpicnum); + statusbar_printext16(200,80,11,-1,snotbuf,0); + sprintf(snotbuf,"Ceiling heinum: %d",sector[sectnum].ceilingheinum); + statusbar_printext16(200,88,11,-1,snotbuf,0); + sprintf(snotbuf,"Palookup number: %d",sector[sectnum].ceilingpal); + statusbar_printext16(200,96,11,-1,snotbuf,0); + + statusbar_printext16(400,32,11,-1,"FLOORS:",0); + sprintf(snotbuf,"Flags (hex): %x",sector[sectnum].floorstat); + statusbar_printext16(400,48,11,-1,snotbuf,0); + sprintf(snotbuf,"(X,Y)pan: %d, %d",sector[sectnum].floorxpanning,sector[sectnum].floorypanning); + statusbar_printext16(400,56,11,-1,snotbuf,0); + sprintf(snotbuf,"Shade byte: %d",sector[sectnum].floorshade); + statusbar_printext16(400,64,11,-1,snotbuf,0); + sprintf(snotbuf,"Z-coordinate: %ld",sector[sectnum].floorz); + statusbar_printext16(400,72,11,-1,snotbuf,0); + sprintf(snotbuf,"Tile number: %d",sector[sectnum].floorpicnum); + statusbar_printext16(400,80,11,-1,snotbuf,0); + sprintf(snotbuf,"Floor heinum: %d",sector[sectnum].floorheinum); + statusbar_printext16(400,88,11,-1,snotbuf,0); + sprintf(snotbuf,"Palookup number: %d",sector[sectnum].floorpal); + statusbar_printext16(400,96,11,-1,snotbuf,0); +} + + +void showwalldata(short wallnum) +{ + long dax, day, dist; + char snotbuf[80]; + + sprintf(snotbuf,"Wall %d",wallnum); + statusbar_printext16(8,32,11,-1,snotbuf,0); + sprintf(snotbuf,"X-coordinate: %ld",wall[wallnum].x); + statusbar_printext16(8,48,11,-1,snotbuf,0); + sprintf(snotbuf,"Y-coordinate: %ld",wall[wallnum].y); + statusbar_printext16(8,56,11,-1,snotbuf,0); + sprintf(snotbuf,"Point2: %d",wall[wallnum].point2); + statusbar_printext16(8,64,11,-1,snotbuf,0); + sprintf(snotbuf,"Sector: %d",sectorofwall(wallnum)); + statusbar_printext16(8,72,11,-1,snotbuf,0); + + sprintf(snotbuf,"Tags: %d, %d",wall[wallnum].hitag,wall[wallnum].lotag); + statusbar_printext16(8,88,11,-1,snotbuf,0); + sprintf(snotbuf," (0x%x), (0x%x)",wall[wallnum].hitag,wall[wallnum].lotag); + statusbar_printext16(8,96,11,-1,snotbuf,0); + + statusbar_printext16(200,32,11,-1,names[wall[wallnum].picnum],0); + sprintf(snotbuf,"Flags (hex): %x",wall[wallnum].cstat); + statusbar_printext16(200,48,11,-1,snotbuf,0); + sprintf(snotbuf,"Shade: %d",wall[wallnum].shade); + statusbar_printext16(200,56,11,-1,snotbuf,0); + sprintf(snotbuf,"Pal: %d",wall[wallnum].pal); + statusbar_printext16(200,64,11,-1,snotbuf,0); + sprintf(snotbuf,"(X,Y)repeat: %d, %d",wall[wallnum].xrepeat,wall[wallnum].yrepeat); + statusbar_printext16(200,72,11,-1,snotbuf,0); + sprintf(snotbuf,"(X,Y)pan: %d, %d",wall[wallnum].xpanning,wall[wallnum].ypanning); + statusbar_printext16(200,80,11,-1,snotbuf,0); + sprintf(snotbuf,"Tile number: %d",wall[wallnum].picnum); + statusbar_printext16(200,88,11,-1,snotbuf,0); + sprintf(snotbuf,"OverTile number: %d",wall[wallnum].overpicnum); + statusbar_printext16(200,96,11,-1,snotbuf,0); + + sprintf(snotbuf,"nextsector: %d",wall[wallnum].nextsector); + statusbar_printext16(400,48,11,-1,snotbuf,0); + sprintf(snotbuf,"nextwall: %d",wall[wallnum].nextwall); + statusbar_printext16(400,56,11,-1,snotbuf,0); + + sprintf(snotbuf,"Extra: %d",wall[wallnum].extra); + statusbar_printext16(400,72,11,-1,snotbuf,0); + + dax = wall[wallnum].x-wall[wall[wallnum].point2].x; + day = wall[wallnum].y-wall[wall[wallnum].point2].y; + dist = ksqrt(dax*dax+day*day); + sprintf(snotbuf,"Wall length: %ld",dist>>4); + statusbar_printext16(400,96,11,-1,snotbuf,0); + + dax = (long)sectorofwall(wallnum); + sprintf(snotbuf,"Pixel height: %ld",(sector[dax].floorz-sector[dax].ceilingz)>>8); + statusbar_printext16(400,104,11,-1,snotbuf,0); +} + + +void showspritedata(short spritenum) +{ + char snotbuf[80]; + + sprintf(snotbuf,"Sprite %d",spritenum); + statusbar_printext16(8,32,11,-1,snotbuf,0); + sprintf(snotbuf,"X-coordinate: %ld",sprite[spritenum].x); + statusbar_printext16(8,48,11,-1,snotbuf,0); + sprintf(snotbuf,"Y-coordinate: %ld",sprite[spritenum].y); + statusbar_printext16(8,56,11,-1,snotbuf,0); + sprintf(snotbuf,"Z-coordinate: %ld",sprite[spritenum].z); + statusbar_printext16(8,64,11,-1,snotbuf,0); + + sprintf(snotbuf,"Sectnum: %d",sprite[spritenum].sectnum); + statusbar_printext16(8,72,11,-1,snotbuf,0); + sprintf(snotbuf,"Statnum: %d",sprite[spritenum].statnum); + statusbar_printext16(8,80,11,-1,snotbuf,0); + + sprintf(snotbuf,"Tags: %d, %d",sprite[spritenum].hitag,sprite[spritenum].lotag); + statusbar_printext16(8,96,11,-1,snotbuf,0); + sprintf(snotbuf," (0x%x), (0x%x)",sprite[spritenum].hitag,sprite[spritenum].lotag); + statusbar_printext16(8,104,11,-1,snotbuf,0); + + statusbar_printext16(200,32,11,-1,names[sprite[spritenum].picnum],0); + sprintf(snotbuf,"Flags (hex): %x",sprite[spritenum].cstat); + statusbar_printext16(200,48,11,-1,snotbuf,0); + sprintf(snotbuf,"Shade: %d",sprite[spritenum].shade); + statusbar_printext16(200,56,11,-1,snotbuf,0); + sprintf(snotbuf,"Pal: %d",sprite[spritenum].pal); + statusbar_printext16(200,64,11,-1,snotbuf,0); + sprintf(snotbuf,"(X,Y)repeat: %d, %d",sprite[spritenum].xrepeat,sprite[spritenum].yrepeat); + statusbar_printext16(200,72,11,-1,snotbuf,0); + sprintf(snotbuf,"(X,Y)offset: %d, %d",sprite[spritenum].xoffset,sprite[spritenum].yoffset); + statusbar_printext16(200,80,11,-1,snotbuf,0); + sprintf(snotbuf,"Tile number: %d",sprite[spritenum].picnum); + statusbar_printext16(200,88,11,-1,snotbuf,0); + + sprintf(snotbuf,"Angle (2048 degrees): %d",sprite[spritenum].ang); + statusbar_printext16(400,48,11,-1,snotbuf,0); + sprintf(snotbuf,"X-Velocity: %d",sprite[spritenum].xvel); + statusbar_printext16(400,56,11,-1,snotbuf,0); + sprintf(snotbuf,"Y-Velocity: %d",sprite[spritenum].yvel); + statusbar_printext16(400,64,11,-1,snotbuf,0); + sprintf(snotbuf,"Z-Velocity: %d",sprite[spritenum].zvel); + statusbar_printext16(400,72,11,-1,snotbuf,0); + sprintf(snotbuf,"Owner: %d",sprite[spritenum].owner); + statusbar_printext16(400,80,11,-1,snotbuf,0); + sprintf(snotbuf,"Clipdist: %d",sprite[spritenum].clipdist); + statusbar_printext16(400,88,11,-1,snotbuf,0); + sprintf(snotbuf,"Extra: %d",sprite[spritenum].extra); + statusbar_printext16(400,96,11,-1,snotbuf,0); +} + + + /* Find closest point (*dax, *day) on wall (dawall) to (x, y) */ +void getclosestpointonwall(long x, long y, long dawall, long *nx, long *ny) +{ + walltype *wal; + long i, j, dx, dy; + + wal = &wall[dawall]; + dx = wall[wal->point2].x-wal->x; + dy = wall[wal->point2].y-wal->y; + i = dx*(x-wal->x) + dy*(y-wal->y); + if (i <= 0) { *nx = wal->x; *ny = wal->y; return; } + j = dx*dx+dy*dy; + if (i >= j) { *nx = wal->x+dx; *ny = wal->y+dy; return; } + i = divscale30(i,j); + *nx = wal->x + mulscale30(dx,i); + *ny = wal->y + mulscale30(dy,i); +} + + +int drawtilescreen(long pictopleft, long picbox) +{ + long i, j, vidpos, vidpos2, wallnum, xdime, ydime, cnt, pinc; + long dax, day, scaledown, xtiles, ytiles, tottiles; + char *picptr, snotbuf[80]; + + xtiles = (xdim>>6); ytiles = (ydim>>6); tottiles = xtiles*ytiles; + + pinc = ylookup[1]; + clearview(0L); + for(cnt=0;cnt<(tottiles<<(gettilezoom<<1));cnt++) /* draw the 5*3 grid of tiles */ + { + wallnum = cnt+pictopleft; + if (wallnum < localartlookupnum) + { + wallnum = localartlookup[wallnum]; + if ((tilesizx[wallnum] != 0) && (tilesizy[wallnum] != 0)) + { + if (waloff[wallnum] == 0) loadtile(wallnum); + picptr = (char *)(waloff[wallnum]); + xdime = tilesizx[wallnum]; + ydime = tilesizy[wallnum]; + + dax = ((cnt%(xtiles<>gettilezoom)) && (ydime <= (64>>gettilezoom))) + { + for(i=0;i 64 */ + { + if (xdime > ydime) + scaledown = ((xdime+(63>>gettilezoom))>>(6-gettilezoom)); + else + scaledown = ((ydime+(63>>gettilezoom))>>(6-gettilezoom)); + + for(i=0;i>gettilezoom);i++) + { + plotpixel(dax+i,day,whitecol); + plotpixel(dax+i,day+(63>>gettilezoom),whitecol); + plotpixel(dax,day+i,whitecol); + plotpixel(dax+(63>>gettilezoom),day+i,whitecol); + } + + i = localartlookup[picbox]; + sprintf(snotbuf,"%ld",i); + printext256(0L,ydim-8,whitecol,-1,snotbuf,0); + printext256(xdim-(strlen(names[i])<<3),ydim-8,whitecol,-1,names[i],0); + + return(0); +} + + +void getpoint(long searchxe, long searchye, long *x, long *y) +{ + if (posx <= -131072) posx = -131072; + if (posx >= 131072) posx = 131072; + if (posy <= -131072) posy = -131072; + if (posy >= 131072) posy = 131072; + + *x = posx + divscale14(searchxe-320,zoom); + *y = posy + divscale14(searchye-200,zoom); + + if (*x <= -131072) *x = -131072; + if (*x >= 131072) *x = 131072; + if (*y <= -131072) *y = -131072; + if (*y >= 131072) *y = 131072; +} + + +long getlinehighlight(long xplc, long yplc) +{ + long i, dst, dist, closest, x1, y1, x2, y2, nx, ny; + + if (numwalls == 0) + return(-1); + dist = 0x7fffffff; + closest = numwalls-1; + for(i=0;i= 0) + { /* if red line, allow highlighting of both sides */ + x1 = wall[closest].x; + y1 = wall[closest].y; + x2 = wall[wall[closest].point2].x; + y2 = wall[wall[closest].point2].y; + if (dmulscale32(xplc-x1,y2-y1,-(x2-x1),yplc-y1) >= 0) + closest = wall[closest].nextwall; + } + + return(closest); +} + + +long getpointhighlight(long xplc, long yplc) +{ + long i, dst, dist, closest; + + if (numwalls == 0) + return(-1); + + dist = 0; + if (grid > 0) + dist = 1024; + + closest = -1; + for(i=0;i 0) && (gridlock > 0)) + pointlockdist = (128>>grid); + + dist = pointlockdist; + dax = *xplc; + day = *yplc; + for(i=0;i 0) && (grid > 0)) + { + dax = ((dax+(1024>>grid))&(0xffffffff<<(11-grid))); + day = ((day+(1024>>grid))&(0xffffffff<<(11-grid))); + } + + *xplc = dax; + *yplc = day; + return(0); +} + + +int checkautoinsert(long dax, long day, short danumwalls) +{ + long i, x1, y1, x2, y2; + + if (danumwalls < 0) + danumwalls = numwalls; + for(i=0;i>1);i++) + { + j = numwalls+newnumwalls-i-1; + templong = wall[i].x; wall[i].x = wall[j].x; wall[j].x = templong; + templong = wall[i].y; wall[i].y = wall[j].y; wall[j].y = templong; + } +} + + +int movewalls(long start, long offs) +{ + long i; + + if (offs < 0) /* Delete */ + { + for(i=start;i 0) /* Insert */ + { + for(i=numwalls+offs-1;i>=start+offs;i--) + memcpy(&wall[i],&wall[i-offs],sizeof(walltype)); + } + numwalls += offs; + for(i=0;i= start) wall[i].nextwall += offs; + if (wall[i].point2 >= start) wall[i].point2 += offs; + } + return(0); +} + + +void insertpoint(short linehighlight, long dax, long day) +{ + short sucksect; + long i, j, k; + + j = linehighlight; + sucksect = sectorofwall((short)j); + + sector[sucksect].wallnum++; + for(i=sucksect+1;i= 0) + { + k = wall[j].nextwall; + + sucksect = sectorofwall((short)k); + + sector[sucksect].wallnum++; + for(i=sucksect+1;i= 0) + { + wall[wall[j].nextwall].nextwall = -1; + wall[wall[j].nextwall].nextsector = -1; + } + if (wall[point].nextwall >= 0) + { + wall[wall[point].nextwall].nextwall = -1; + wall[wall[point].nextwall].nextsector = -1; + } + movewalls((long)point,-1L); + + checksectorpointer((short)j,(short)sucksect); +} + + +short deletesector(short sucksect) +{ + long i, j, k, nextk, startwall, endwall; + + while (headspritesect[sucksect] >= 0) + deletesprite(headspritesect[sucksect]); + updatenumsprites(); + + startwall = sector[sucksect].wallptr; + endwall = startwall + sector[sucksect].wallnum - 1; + j = sector[sucksect].wallnum; + + for(i=sucksect;i= startwall) + wall[i].nextsector--; + return(0); +} + + +void fixspritesectors(void) +{ + long i, j, dax, day, daz; + + for(i=numsectors-1;i>=0;i--) + if ((sector[i].wallnum <= 0) || (sector[i].wallptr >= numwalls)) + deletesector((short)i); + + for(i=0;i= getceilzofslope(j,dax,day)) + if (sprite[i].z-daz <= getflorzofslope(j,dax,day)) + { + changespritesect((short)i,(short)j); + break; + } + } + } +} + + +void clearmidstatbar16(void) +{ + long opageoffset; + + opageoffset = pageoffset; /* clear bottom part of status bar */ + pageoffset = 0; + ydim16 = 144; + fillscreen16((640L*25L)>>3,8L,640L*(143L-(25<<1))); + drawline16(0,0,0,143,7); + drawline16(639,0,639,143,7); + pageoffset = opageoffset; + ydim16 = 336; +} + + +short loopinside(long x, long y, short startwall) +{ + long x1, y1, x2, y2, templong; + short i, cnt; + + cnt = clockdir(startwall); + i = startwall; + do + { + x1 = wall[i].x; x2 = wall[wall[i].point2].x; + if ((x1 >= x) || (x2 >= x)) + { + y1 = wall[i].y; y2 = wall[wall[i].point2].y; + if (y1 > y2) + { + templong = x1, x1 = x2, x2 = templong; + templong = y1, y1 = y2, y2 = templong; + } + if ((y1 <= y) && (y2 > y)) + if (x1*(y-y2)+x2*(y1-y) <= x*(y1-y2)) + cnt ^= 1; + } + i = wall[i].point2; + } + while (i != startwall); + return(cnt); +} + + +long numloopsofsector(short sectnum) +{ + long i, numloops, startwall, endwall; + + numloops = 0; + startwall = sector[sectnum].wallptr; + endwall = startwall + sector[sectnum].wallnum; + for(i=startwall;i=0;i--) + { + startwall = sector[highlightsector[i]].wallptr; + endwall = startwall + sector[highlightsector[i]].wallnum; + for(j=startwall;j= 0) + { + for(k=highlightsectorcnt-1;k>=0;k--) + if (highlightsector[k] == wall[j].nextsector) + break; + if (k < 0) + { + wall[wall[j].nextwall].nextwall = -1; + wall[wall[j].nextwall].nextsector = -1; + wall[j].nextwall = -1; + wall[j].nextsector = -1; + } + } + } + } + + for(i=0;i<(MAXWALLS>>3);i++) /* Clear all highlights */ + show2dwall[i] = 0; + for(i=0;i<(MAXSPRITES>>3);i++) + show2dsprite[i] = 0; + + sectorhighlightstat = -1; + newnumwalls = -1; + joinsector[0] = -1; + circlewall = -1; + circlepoints = 7; + oldmousebstatus = 0; + keystatus[buildkeys[14]] = 0; + while ((keystatus[buildkeys[14]]>>1) == 0) + { + _idle(); + + oldmousebstatus = bstatus; + getmousevalues(&mousx,&mousy,&bstatus); + searchx += (mousx>>1); + searchy += (mousy>>1); + if (searchx < 8) searchx = 8; + if (searchx > 631) searchx = 631; + if (searchy < 8) searchy = 8; + if (searchy > 341) searchy = 341; + + if (keystatus[0x3b] > 0) posx--, keystatus[0x3b] = 0; + if (keystatus[0x3c] > 0) posx++, keystatus[0x3c] = 0; + if (keystatus[0x3d] > 0) posy--, keystatus[0x3d] = 0; + if (keystatus[0x3e] > 0) posy++, keystatus[0x3e] = 0; + if (keystatus[0x43] > 0) ang--, keystatus[0x43] = 0; + if (keystatus[0x44] > 0) ang++, keystatus[0x44] = 0; + if (angvel != 0) /* ang += angvel * constant */ + { /* ENGINE calculates angvel for you */ + doubvel = synctics; + if (keystatus[buildkeys[4]] > 0) /* Lt. shift makes turn velocity 50% faster */ + doubvel += (synctics>>1); + ang += ((angvel*doubvel)>>4); + ang = (ang+2048)&2047; + } + if ((vel|svel) != 0) + { + doubvel = synctics; + if (keystatus[buildkeys[4]] > 0) /* Lt. shift doubles forward velocity */ + doubvel += synctics; + xvect = 0, yvect = 0; + if (vel != 0) + { + xvect += ((vel*doubvel*(long)sintable[(ang+2560)&2047])>>3); + yvect += ((vel*doubvel*(long)sintable[(ang+2048)&2047])>>3); + } + if (svel != 0) + { + xvect += ((svel*doubvel*(long)sintable[(ang+2048)&2047])>>3); + yvect += ((svel*doubvel*(long)sintable[(ang+1536)&2047])>>3); + } + clipmove(&posx,&posy,&posz,&cursectnum,xvect,yvect,128L,4L<<8,4L<<8,CLIPMASK0); + } + + getpoint(searchx,searchy,&mousxplc,&mousyplc); + linehighlight = getlinehighlight(mousxplc, mousyplc); + + if (newnumwalls >= numwalls) + { + dax = mousxplc; + day = mousyplc; + adjustmark(&dax,&day,newnumwalls); + wall[newnumwalls].x = dax; + wall[newnumwalls].y = day; + } + + ydim16 = 336; + + templong = numwalls; + numwalls = newnumwalls; + if (numwalls < 0) numwalls = templong; + + clear2dscreen(); + draw2dgrid(posx,posy,ang,zoom,grid); + + x2 = mulscale14(startposx-posx,zoom); /* Draw brown arrow (start) */ + y2 = mulscale14(startposy-posy,zoom); + if (((320+x2) >= 2) && ((320+x2) <= 637)) + if (((200+y2) >= 2) && ((200+y2) <= ydim16-3)) + { + x1 = mulscale11(sintable[(startang+2560)&2047],zoom) / 768; + y1 = mulscale11(sintable[(startang+2048)&2047],zoom) / 768; + drawline16((320+x2)+x1,(200+y2)+y1,(320+x2)-x1,(200+y2)-y1,6); + drawline16((320+x2)+x1,(200+y2)+y1,(320+x2)+y1,(200+y2)-x1,6); + drawline16((320+x2)+x1,(200+y2)+y1,(320+x2)-y1,(200+y2)+x1,6); + } + + draw2dscreen(posx,posy,ang,zoom,grid); + + if ((showtags == 1) && (zoom >= 768)) + { + for(i=0;i startwall) + { + dax /= (endwall-startwall+1); + day /= (endwall-startwall+1); + } + + dax = mulscale14(dax-posx,zoom); + day = mulscale14(day-posy,zoom); + + x1 = 320+dax-(strlen(dabuffer)<<1); + y1 = 200+day-4; + x2 = x1 + (strlen(dabuffer)<<2)+2; + y2 = y1 + 7; + if ((x1 >= 0) && (x2 < 640) && (y1 >= 0) && (y2 < ydim16)) + { + #ifdef PLATFORM_DOS + printext16(x1,y1+(pageoffset/640),0,7,dabuffer,1); + #else + printext16(x1,y1,0,7,dabuffer,1); + #endif + } /* if */ + } + } + + x3 = divscale14(-320,zoom)+posx; + y3 = divscale14(-196,zoom)+posy; + x4 = divscale14(320,zoom)+posx; + y4 = divscale14(ydim16-196,zoom)+posy; + + for(i=numwalls-1,wal=&wall[i];i>=0;i--,wal--) + { + /* Get average point of wall */ + dax = ((wal->x+wall[wal->point2].x)>>1); + day = ((wal->y+wall[wal->point2].y)>>1); + if ((dax > x3) && (dax < x4) && (day > y3) && (day < y4)) + { + dabuffer = (char *)ExtGetWallCaption(i); + if (dabuffer[0] != 0) + { + dax = mulscale14(dax-posx,zoom); + day = mulscale14(day-posy,zoom); + x1 = 320+dax-(strlen(dabuffer)<<1); + y1 = 200+day-4; + x2 = x1 + (strlen(dabuffer)<<2)+2; + y2 = y1 + 7; + if ((x1 >= 0) && (x2 < 640) && (y1 >= 0) && (y2 < ydim16)) + { + #ifdef PLATFORM_DOS + printext16(x1,y1+(pageoffset/640),0,4,dabuffer,1); + #else + printext16(x1,y1,0,4,dabuffer,1); + #endif + } /* if */ + } + } + } + + i = 0; j = numsprites; + while ((j > 0) && (i < MAXSPRITES)) + { + if (sprite[i].statnum < MAXSTATUS) + { + dabuffer = (char *)ExtGetSpriteCaption(i); + if (dabuffer[0] != 0) + { + /* Get average point of sprite */ + dax = sprite[i].x; + day = sprite[i].y; + + dax = mulscale14(dax-posx,zoom); + day = mulscale14(day-posy,zoom); + + x1 = 320+dax-(strlen(dabuffer)<<1); + y1 = 200+day-4; + x2 = x1 + (strlen(dabuffer)<<2)+2; + y2 = y1 + 7; + if ((x1 >= 0) && (x2 < 640) && (y1 >= 0) && (y2 < ydim16)) + { + if ((sprite[i].cstat&1) == 0) col = 3; else col = 5; + { + #ifdef PLATFORM_DOS + printext16(x1,y1+(pageoffset/640),0,col,dabuffer,1); + #else + printext16(x1,y1,0,col,dabuffer,1); + #endif + } /* if */ + } + } + j--; + } + i++; + } + } + + printcoords16(posx,posy,ang); + + numwalls = templong; + + if (highlightsectorcnt > 0) + for(i=0;i= 0) + drawline16(320+x2,200+y2,320+x2,200+y2,15); + else + drawline16(320+x2,200+y2,320+x2,200+y2,5); + + if (keystatus[88] > 0) /* F12 */ + { + keystatus[88] = 0; + i = pageoffset; pageoffset = 92160; + j = ydim16; ydim16 = 480; + outpw(0x3d4,0x000c); + outpw(0x3d4,0x000d); + clear2dscreen(); + draw2dgrid(posx,posy,ang,zoom,grid); + draw2dscreen(posx,posy,ang,zoom,grid); + + screencapture("captxxxx.pcx",keystatus[0x2a]|keystatus[0x36]); + + pageoffset = i; + ydim16 = j; + } + if (keystatus[0x30] > 0) /* B (clip Blocking xor) (2D) */ + { + pointhighlight = getpointhighlight(mousxplc, mousyplc); + linehighlight = getlinehighlight(mousxplc, mousyplc); + + if ((pointhighlight&0xc000) == 16384) + { + sprite[pointhighlight&16383].cstat ^= 1; + sprite[pointhighlight&16383].cstat &= ~256; + sprite[pointhighlight&16383].cstat |= ((sprite[pointhighlight&16383].cstat&1)<<8); + asksave = 1; + } + else if (linehighlight >= 0) + { + wall[linehighlight].cstat ^= 1; + wall[linehighlight].cstat &= ~64; + if ((wall[linehighlight].nextwall >= 0) && ((keystatus[0x2a]|keystatus[0x36]) == 0)) + { + wall[wall[linehighlight].nextwall].cstat &= ~(1+64); + wall[wall[linehighlight].nextwall].cstat |= (wall[linehighlight].cstat&1); + } + asksave = 1; + } + keystatus[0x30] = 0; + } + if (keystatus[0x21] > 0) /* F (F alone does nothing in 2D right now) */ + { + keystatus[0x21] = 0; + if ((keystatus[0x38]|keystatus[0xb8]) > 0) /* ALT-F (relative alignmment flip) */ + { + linehighlight = getlinehighlight(mousxplc, mousyplc); + if (linehighlight >= 0) + { + setfirstwall(sectorofwall(linehighlight),linehighlight); + asksave = 1; + printmessage16("This wall now sector's first wall (sector[].wallptr)"); + } + } + } + + if (keystatus[0x18] > 0) /* O (ornament onto wall) (2D) */ + { + keystatus[0x18] = 0; + if ((pointhighlight&0xc000) == 16384) + { + asksave = 1; + i = (pointhighlight&16383); + + hitscan(sprite[i].x,sprite[i].y,sprite[i].z,sprite[i].sectnum, + sintable[(sprite[i].ang+2560+1024)&2047], + sintable[(sprite[i].ang+2048+1024)&2047], + 0, + &hitsect,&hitwall,&hitsprite,&hitx,&hity,&hitz,CLIPMASK1); + + sprite[i].x = hitx; + sprite[i].y = hity; + sprite[i].z = hitz; + changespritesect(i,hitsect); + if (hitwall >= 0) + sprite[i].ang = ((getangle(wall[wall[hitwall].point2].x-wall[hitwall].x,wall[wall[hitwall].point2].y-wall[hitwall].y)+512)&2047); + + /* Make sure sprite's in right sector */ + if (inside(sprite[i].x,sprite[i].y,sprite[i].sectnum) == 0) + { + j = wall[hitwall].point2; + sprite[i].x -= ksgn(wall[j].y-wall[hitwall].y); + sprite[i].y += ksgn(wall[j].x-wall[hitwall].x); + } + } + } + + if (keystatus[0x33] > 0) /* , (2D) */ + { + if (highlightsectorcnt > 0) + { + k = 0; + dax = 0; + day = 0; + for(i=0;i 0) + { + dax /= k; + day /= k; + } + + k = (keystatus[0x2a]|keystatus[0x36]); + + if (k == 0) + { + if ((gridlock > 0) && (grid > 0)) + { + dax = ((dax+(1024>>grid))&(0xffffffff<<(11-grid))); + day = ((day+(1024>>grid))&(0xffffffff<<(11-grid))); + } + } + + for(i=0;i= 16384) + { + i = pointhighlight-16384; + if ((keystatus[0x2a]|keystatus[0x36]) > 0) + sprite[i].ang = ((sprite[i].ang+2048-1)&2047); + else + { + sprite[i].ang = ((sprite[i].ang+2048-128)&2047); + keystatus[0x33] = 0; + } + + clearmidstatbar16(); + showspritedata((short)pointhighlight-16384); + } + } + } + if (keystatus[0x34] > 0) /* . (2D) */ + { + if (highlightsectorcnt > 0) + { + k = 0; + dax = 0; + day = 0; + for(i=0;i 0) + { + dax /= k; + day /= k; + } + + k = (keystatus[0x2a]|keystatus[0x36]); + + if (k == 0) + { + if ((gridlock > 0) && (grid > 0)) + { + dax = ((dax+(1024>>grid))&(0xffffffff<<(11-grid))); + day = ((day+(1024>>grid))&(0xffffffff<<(11-grid))); + } + } + + for(i=0;i= 16384) + { + i = pointhighlight-16384; + if ((keystatus[0x2a]|keystatus[0x36]) > 0) + sprite[i].ang = ((sprite[i].ang+2048+1)&2047); + else + { + sprite[i].ang = ((sprite[i].ang+2048+128)&2047); + keystatus[0x34] = 0; + } + + clearmidstatbar16(); + showspritedata((short)pointhighlight-16384); + } + } + } + if (keystatus[0x46] > 0) /* Scroll lock (set starting position) */ + { + startposx = posx; + startposy = posy; + startposz = posz; + startang = ang; + startsectnum = cursectnum; + keystatus[0x46] = 0; + asksave = 1; + } + + if (keystatus[0x3f] > 0) /* F5 */ + { + keystatus[0x3f] = 0; + + for (i=0;i 0) /* F6 */ + { + keystatus[0x40] = 0; + + if (pointhighlight >= 16384) + { + i = pointhighlight-16384; + + opageoffset = pageoffset; pageoffset = 0; ydim16 = 144; + ExtShowSpriteData((short)i); + pageoffset = opageoffset; ydim16 = 336; + } + else if (linehighlight >= 0) + { + i = linehighlight; + + opageoffset = pageoffset; pageoffset = 0; ydim16 = 144; + ExtShowWallData((short)i); + pageoffset = opageoffset; ydim16 = 336; + } + } + if (keystatus[0x41] > 0) /* F7 */ + { + keystatus[0x41] = 0; + + for (i=0;i 0) /* F8 */ + { + keystatus[0x42] = 0; + + if (pointhighlight >= 16384) + { + i = pointhighlight-16384; + + opageoffset = pageoffset; pageoffset = 0; ydim16 = 144; + ExtEditSpriteData((short)i); + pageoffset = opageoffset; ydim16 = 336; + } + else if (linehighlight >= 0) + { + i = linehighlight; + + opageoffset = pageoffset; pageoffset = 0; ydim16 = 144; + ExtEditWallData((short)i); + pageoffset = opageoffset; ydim16 = 336; + } + } + + if (keystatus[0x14] > 0) /* T (tag) */ + { + keystatus[0x14] = 0; + if ((keystatus[0x1d]|keystatus[0x9d]) > 0) /* Ctrl-T */ + { + showtags ^= 1; + if (showtags == 0) + printmessage16("Show tags OFF"); + else + printmessage16("Show tags ON"); + } + else if ((keystatus[0x38]|keystatus[0xb8]) > 0) /* ALT */ + { + if (pointhighlight >= 16384) + { + i = pointhighlight-16384; + sprintf(buffer,"Sprite (%ld) Lo-tag: ",i); + sprite[i].lotag = getnumber16(buffer,sprite[i].lotag,65536L); + clearmidstatbar16(); + showspritedata((short)i); + } + else if (linehighlight >= 0) + { + i = linehighlight; + sprintf(buffer,"Wall (%ld) Lo-tag: ",i); + wall[i].lotag = getnumber16(buffer,wall[i].lotag,65536L); + clearmidstatbar16(); + showwalldata((short)i); + } + printmessage16(""); + } + else + { + for (i=0;i 0) /* H (Hi 16 bits of tag) */ + { + keystatus[0x23] = 0; + if ((keystatus[0x1d]|keystatus[0x9d]) > 0) /* Ctrl-H */ + { + pointhighlight = getpointhighlight(mousxplc, mousyplc); + linehighlight = getlinehighlight(mousxplc, mousyplc); + + if ((pointhighlight&0xc000) == 16384) + { + sprite[pointhighlight&16383].cstat ^= 256; + asksave = 1; + } + else if (linehighlight >= 0) + { + wall[linehighlight].cstat ^= 64; + if ((wall[linehighlight].nextwall >= 0) && ((keystatus[0x2a]|keystatus[0x36]) == 0)) + { + wall[wall[linehighlight].nextwall].cstat &= ~64; + wall[wall[linehighlight].nextwall].cstat |= (wall[linehighlight].cstat&64); + } + asksave = 1; + } + } + else if ((keystatus[0x38]|keystatus[0xb8]) > 0) /* ALT */ + { + if (pointhighlight >= 16384) + { + i = pointhighlight-16384; + sprintf(buffer,"Sprite (%ld) Hi-tag: ",i); + sprite[i].hitag = getnumber16(buffer,sprite[i].hitag,65536L); + clearmidstatbar16(); + showspritedata((short)i); + } + else if (linehighlight >= 0) + { + i = linehighlight; + sprintf(buffer,"Wall (%ld) Hi-tag: ",i); + wall[i].hitag = getnumber16(buffer,wall[i].hitag,65536L); + clearmidstatbar16(); + showwalldata((short)i); + } + } + else + { + for (i=0;i 0) /* P (palookup #) */ + { + keystatus[0x19] = 0; + + for (i=0;i 0) /* E (status list) */ + { + if (pointhighlight >= 16384) + { + i = pointhighlight-16384; + sprintf(buffer,"Sprite (%ld) Status list: ",i); + changespritestat(i,getnumber16(buffer,sprite[i].statnum,65536L)); + clearmidstatbar16(); + showspritedata((short)i); + } + + printmessage16(""); + + keystatus[0x12] = 0; + } + + if (keystatus[0x0f] > 0) /* TAB */ + { + clearmidstatbar16(); + + if ((keystatus[0x38]|keystatus[0xb8]) > 0) /* ALT */ + { + if (pointhighlight >= 16384) + showspritedata((short)pointhighlight-16384); + else if (linehighlight >= 0) + showwalldata((short)linehighlight); + } + else + { + for (i=0;i 0) /* Right shift (point highlighting) */ + { + if (highlightcnt == 0) + { + highlightx2 = searchx, highlighty2 = searchy; + ydim16 = 336; + drawline16(highlightx2,highlighty1,highlightx1,highlighty1,5); + drawline16(highlightx2,highlighty2,highlightx1,highlighty2,5); + drawline16(highlightx1,highlighty2,highlightx1,highlighty1,5); + drawline16(highlightx2,highlighty2,highlightx2,highlighty1,5); + } + if (highlightcnt != 0) + { + highlightx1 = searchx; + highlighty1 = searchy; + highlightx2 = searchx; + highlighty2 = searchx; + highlightcnt = 0; + + for(i=0;i<(MAXWALLS>>3);i++) /* Clear all highlights */ + show2dwall[i] = 0; + for(i=0;i<(MAXSPRITES>>3);i++) + show2dsprite[i] = 0; + } + } + else + { + if (highlightcnt == 0) + { + getpoint(highlightx1,highlighty1,&highlightx1,&highlighty1); + getpoint(highlightx2,highlighty2,&highlightx2,&highlighty2); + if (highlightx1 > highlightx2) + { + templong = highlightx1; highlightx1 = highlightx2; highlightx2 = templong; + } + if (highlighty1 > highlighty2) + { + templong = highlighty1; highlighty1 = highlighty2; highlighty2 = templong; + } + + if ((keystatus[0x1d]|keystatus[0x9d]) > 0) + { + if ((linehighlight >= 0) && (linehighlight < MAXWALLS)) + { + i = linehighlight; + do + { + highlight[highlightcnt++] = i; + show2dwall[i>>3] |= (1<<(i&7)); + + for(j=0;j>3] |= (1<<(j&7)); + } + + i = wall[i].point2; + } + while (i != linehighlight); + } + } + else + { + for(i=0;i= highlightx1) && (wall[i].x <= highlightx2)) + if ((wall[i].y >= highlighty1) && (wall[i].y <= highlighty2)) + { + highlight[highlightcnt++] = i; + show2dwall[i>>3] |= (1<<(i&7)); + } + for(i=0;i= highlightx1) && (sprite[i].x <= highlightx2)) + if ((sprite[i].y >= highlighty1) && (sprite[i].y <= highlighty2)) + { + highlight[highlightcnt++] = i+16384; + show2dsprite[i>>3] |= (1<<(i&7)); + } + } + + if (highlightcnt <= 0) + highlightcnt = -1; + } + } + } + if (highlightcnt < 0) + { + if (keystatus[0xb8] > 0) /* Right alt (sector highlighting) */ + { + if (highlightsectorcnt == 0) + { + highlightx2 = searchx, highlighty2 = searchy; + ydim16 = 336; + drawline16(highlightx2,highlighty1,highlightx1,highlighty1,10); + drawline16(highlightx2,highlighty2,highlightx1,highlighty2,10); + drawline16(highlightx1,highlighty2,highlightx1,highlighty1,10); + drawline16(highlightx2,highlighty2,highlightx2,highlighty1,10); + } + if (highlightsectorcnt != 0) + { + for(i=0;i= 0) + checksectorpointer(wall[j].nextwall,wall[j].nextsector); + checksectorpointer((short)j,highlightsector[i]); + } + } + highlightx1 = searchx; + highlighty1 = searchy; + highlightx2 = searchx; + highlighty2 = searchx; + highlightsectorcnt = 0; + } + } + else + { + if (highlightsectorcnt == 0) + { + getpoint(highlightx1,highlighty1,&highlightx1,&highlighty1); + getpoint(highlightx2,highlighty2,&highlightx2,&highlighty2); + if (highlightx1 > highlightx2) + { + templong = highlightx1; highlightx1 = highlightx2; highlightx2 = templong; + } + if (highlighty1 > highlighty2) + { + templong = highlighty1; highlighty1 = highlighty2; highlighty2 = templong; + } + + for(i=0;i highlightx2) bad = 1; + if (wall[j].y < highlighty1) bad = 1; + if (wall[j].y > highlighty2) bad = 1; + if (bad == 1) break; + } + if (bad == 0) + highlightsector[highlightsectorcnt++] = i; + } + if (highlightsectorcnt <= 0) + highlightsectorcnt = -1; + + /* + * White out all bordering lines of grab that are + * not highlighted on both sides + */ + for(i=highlightsectorcnt-1;i>=0;i--) + { + startwall = sector[highlightsector[i]].wallptr; + endwall = startwall + sector[highlightsector[i]].wallnum; + for(j=startwall;j= 0) + { + for(k=highlightsectorcnt-1;k>=0;k--) + if (highlightsector[k] == wall[j].nextsector) + break; + if (k < 0) + { + wall[wall[j].nextwall].nextwall = -1; + wall[wall[j].nextwall].nextsector = -1; + wall[j].nextwall = -1; + wall[j].nextsector = -1; + } + } + } + } + + } + } + } + + /* + * rcg02192001 added pointhighlight check to stop segfault that + * was (miraculously) not exposed before the port to Watcom/win32. + * Not sure of total ramifications of this patch; if left mouse + * button behaviour in the overhead editor suddenly goes screwey, + * this is why. + */ + if (((bstatus&1) < (oldmousebstatus&1)) && (highlightsectorcnt < 0) && (pointhighlight >= 0)) /* after dragging */ + { + j = 1; + if (highlightcnt > 0) + for (i=0;i=0;i--) /* delete points */ + { + if (wall[i].x == wall[wall[i].point2].x) + if (wall[i].y == wall[wall[i].point2].y) + { + deletepoint((short)i); + printmessage16("Point deleted."); + asksave = 1; + } + } + for(i=0;i 0) /* drag points */ + { + if (highlightsectorcnt > 0) + { + if ((bstatus&1) > (oldmousebstatus&1)) + { + newnumwalls = -1; + sectorhighlightstat = -1; + updatesector(mousxplc,mousyplc,&cursectorhighlight); + + if ((cursectorhighlight >= 0) && (cursectorhighlight < numsectors)) + { + for (i=0;i 0) && (grid > 0)) + { + dax = ((dax+(1024>>grid))&(0xffffffff<<(11-grid))); + day = ((day+(1024>>grid))&(0xffffffff<<(11-grid))); + } + sectorhighlightx = dax; + sectorhighlighty = day; + break; + } + } + } + else if (sectorhighlightstat == 1) + { + dax = mousxplc; + day = mousyplc; + if ((gridlock > 0) && (grid > 0)) + { + dax = ((dax+(1024>>grid))&(0xffffffff<<(11-grid))); + day = ((day+(1024>>grid))&(0xffffffff<<(11-grid))); + } + + dax -= sectorhighlightx; + day -= sectorhighlighty; + sectorhighlightx += dax; + sectorhighlighty += day; + + for(i=0;i=0;j=nextspritesect[j]) + { sprite[j].x += dax; sprite[j].y += day; } + } + + #if 0 + for(i=0;i= 0) + checksectorpointer(wall[j].nextwall,wall[j].nextsector); + checksectorpointer((short)j,highlightsector[i]); + } + } + #endif + + asksave = 1; + } + + } + else + { + if ((bstatus&1) > (oldmousebstatus&1)) + pointhighlight = getpointhighlight(mousxplc, mousyplc); + + if (pointhighlight >= 0) + { + dax = mousxplc; + day = mousyplc; + if ((gridlock > 0) && (grid > 0)) + { + dax = ((dax+(1024>>grid))&(0xffffffff<<(11-grid))); + day = ((day+(1024>>grid))&(0xffffffff<<(11-grid))); + } + + j = 1; + if (highlightcnt > 0) + for (i=0;i= getceilzofslope(i,dax,day)) + if (sprite[pointhighlight&16383].z-daz <= getflorzofslope(i,dax,day)) + { + sprite[pointhighlight&16383].x = dax; + sprite[pointhighlight&16383].y = day; + if (sprite[pointhighlight&16383].sectnum != i) + changespritesect(pointhighlight&16383,(short)i); + break; + } + } + } + asksave = 1; + } + } + } + else + { + pointhighlight = getpointhighlight(mousxplc, mousyplc); + sectorhighlightstat = -1; + } + + if ((bstatus&6) > 0) + { + searchx = 320; + searchy = 200; + posx = mousxplc; + posy = mousyplc; + } + + if ((keystatus[buildkeys[8]] > 0) && (zoom < 16384)) zoom += (zoom>>4); + if ((keystatus[buildkeys[9]] > 0) && (zoom > 24)) zoom -= (zoom>>4); + + if (keystatus[0x22] > 0) /* G (grid on/off) */ + { + grid++; + if (grid == 7) grid = 0; + keystatus[0x22] = 0; + } + if (keystatus[0x26] > 0) /* L (grid lock) */ + { + gridlock = 1-gridlock, keystatus[0x26] = 0; + if (gridlock == 0) + printmessage16("Grid locking OFF"); + else + printmessage16("Grid locking ON"); + } + + if (keystatus[0x24] > 0) /* J (join sectors) */ + { + if (joinsector[0] >= 0) + { + joinsector[1] = -1; + for(i=0;i= 0) && (joinsector[0] != joinsector[1])) + { + newnumwalls = numwalls; + + for(k=0;k<2;k++) + { + startwall = sector[joinsector[k]].wallptr; + endwall = startwall + sector[joinsector[k]].wallnum - 1; + for(j=startwall;j<=endwall;j++) + { + if (wall[j].cstat == 255) + continue; + joinsectnum = k; + if (wall[j].nextsector == joinsector[1-joinsectnum]) + { + wall[j].cstat = 255; + continue; + } + + i = j; + m = newnumwalls; + do + { + memcpy(&wall[newnumwalls],&wall[i],sizeof(walltype)); + wall[newnumwalls].point2 = newnumwalls+1; + newnumwalls++; + wall[i].cstat = 255; + + i = wall[i].point2; + if (wall[i].nextsector == joinsector[1-joinsectnum]) + { + i = wall[wall[i].nextwall].point2; + joinsectnum = 1 - joinsectnum; + } + } + while ((wall[i].cstat != 255) && (wall[i].nextsector != joinsector[1-joinsectnum])); + wall[newnumwalls-1].point2 = m; + } + } + + if (newnumwalls > numwalls) + { + memcpy(§or[numsectors],§or[joinsector[0]],sizeof(sectortype)); + sector[numsectors].wallptr = numwalls; + sector[numsectors].wallnum = newnumwalls-numwalls; + + /* fix sprites */ + for(i=0;i<2;i++) + { + j = headspritesect[joinsector[i]]; + while (j != -1) + { + k = nextspritesect[j]; + changespritesect(j,numsectors); + j = k; + } + } + + numsectors++; + + for(i=numwalls;i= 0) + { + wall[wall[i].nextwall].nextwall = i; + wall[wall[i].nextwall].nextsector = numsectors-1; + } + } + + numwalls = newnumwalls; + newnumwalls = -1; + + for(k=0;k<2;k++) + { + startwall = sector[joinsector[k]].wallptr; + endwall = startwall + sector[joinsector[k]].wallnum - 1; + for(j=startwall;j<=endwall;j++) + { + wall[j].nextwall = -1; + wall[j].nextsector = -1; + } + } + + deletesector((short)joinsector[0]); + if (joinsector[0] < joinsector[1]) + joinsector[1]--; + deletesector((short)joinsector[1]); + printmessage16("Sectors joined."); + } + } + joinsector[0] = -1; + } + else + { + joinsector[0] = -1; + for(i=0;i 0) /* ALT-S */ + { + if ((linehighlight >= 0) && (wall[linehighlight].nextwall == -1)) + { + if ((newnumwalls = whitelinescan(linehighlight)) < numwalls) + { + printmessage16("Can't make a sector out there."); + } + else + { + for(i=numwalls;i 0) /* S */ + { + sucksect = -1; + for(i=0;i= 0) + { + dax = mousxplc; + day = mousyplc; + if ((gridlock > 0) && (grid > 0)) + { + dax = ((dax+(1024>>grid))&(0xffffffff<<(11-grid))); + day = ((day+(1024>>grid))&(0xffffffff<<(11-grid))); + } + + i = insertsprite(sucksect,0); + sprite[i].x = dax, sprite[i].y = day; + sprite[i].cstat = defaultspritecstat; + sprite[i].shade = 0; + sprite[i].pal = 0; + sprite[i].xrepeat = 64, sprite[i].yrepeat = 64; + sprite[i].xoffset = 0, sprite[i].yoffset = 0; + sprite[i].ang = 1536; + sprite[i].xvel = 0; sprite[i].yvel = 0; sprite[i].zvel = 0; + sprite[i].owner = -1; + sprite[i].clipdist = 32; + sprite[i].lotag = 0; + sprite[i].hitag = 0; + sprite[i].extra = -1; + + sprite[i].z = getflorzofslope(sucksect,dax,day); + if ((sprite[i].cstat&128) != 0) + sprite[i].z -= ((tilesizy[sprite[i].picnum]*sprite[i].yrepeat)<<1); + + for(k=0;k localartfreq[j]) + j = k; + if (localartfreq[j] > 0) + sprite[i].picnum = j; + else + sprite[i].picnum = 0; + + if (somethingintab == 3) + { + sprite[i].picnum = temppicnum; + if ((tilesizx[temppicnum] <= 0) || (tilesizy[temppicnum] <= 0)) + { + j = 0; + for(k=0;k 0) && (tilesizy[k] > 0)) + { + j = k; + break; + } + sprite[i].picnum = j; + } + sprite[i].shade = tempshade; + sprite[i].pal = temppal; + sprite[i].xrepeat = tempxrepeat; + sprite[i].yrepeat = tempyrepeat; + if (sprite[i].xrepeat < 1) sprite[i].xrepeat = 1; + if (sprite[i].yrepeat < 1) sprite[i].yrepeat = 1; + sprite[i].cstat = tempcstat; + } + + if (tilesizy[sprite[i].picnum] >= 32) + sprite[i].cstat |= 1; + + printmessage16("Sprite inserted."); + updatenumsprites(); + asksave = 1; + } + + keystatus[0x1f] = 0; + } + + if (keystatus[0x2e] > 0) /* C (make circle of points) */ + { + if (circlewall >= 0) + { + circlewall = -1; + } + else + { + if (linehighlight >= 0) + circlewall = linehighlight; + } + keystatus[0x2e] = 0; + } + if (keystatus[0x4a] > 0) /* - */ + { + if (circlepoints > 1) + circlepoints--; + keystatus[0x4a] = 0; + } + if (keystatus[0x4e] > 0) /* + */ + { + if (circlepoints < 63) + circlepoints++; + keystatus[0x4e] = 0; + } + + bad = (keystatus[0x39] > 0); /* Gotta do this to save lots of 3 spaces! */ + + if (circlewall >= 0) + { + x1 = wall[circlewall].x; + y1 = wall[circlewall].y; + x2 = wall[wall[circlewall].point2].x; + y2 = wall[wall[circlewall].point2].y; + x3 = mousxplc; + y3 = mousyplc; + adjustmark(&x3,&y3,newnumwalls); + templong1 = dmulscale4(x3-x2,x1-x3,y1-y3,y3-y2); + templong2 = dmulscale4(y1-y2,x1-x3,y1-y3,x2-x1); + if (templong2 != 0) + { + centerx = (((x1+x2) + scale(y1-y2,templong1,templong2))>>1); + centery = (((y1+y2) + scale(x2-x1,templong1,templong2))>>1); + + dax = mulscale14(centerx-posx,zoom); + day = mulscale14(centery-posy,zoom); + drawline16(320+dax-2,200+day-2,320+dax+2,200+day+2,14); + drawline16(320+dax-2,200+day+2,320+dax+2,200+day-2,14); + + circleang1 = getangle(x1-centerx,y1-centery); + circleang2 = getangle(x2-centerx,y2-centery); + + circleangdir = 1; + k = ((circleang2-circleang1)&2047); + if (mulscale4(x3-x1,y2-y1) < mulscale4(x2-x1,y3-y1)) + { + circleangdir = -1; + k = -((circleang1-circleang2)&2047); + } + + circlerad = (ksqrt(dmulscale4(centerx-x1,centerx-x1,centery-y1,centery-y1))<<2); + + for(i=circlepoints;i>0;i--) + { + j = ((circleang1 + scale(i,k,circlepoints+1))&2047); + dax = centerx+mulscale14(sintable[(j+512)&2047],circlerad); + day = centery+mulscale14(sintable[j],circlerad); + + if (dax <= -131072) dax = -131072; + if (dax >= 131072) dax = 131072; + if (day <= -131072) day = -131072; + if (day >= 131072) day = 131072; + + if (bad > 0) + { + m = 0; + if (wall[circlewall].nextwall >= 0) + if (wall[circlewall].nextwall < circlewall) m = 1; + insertpoint(circlewall,dax,day); + circlewall += m; + } + dax = mulscale14(dax-posx,zoom); + day = mulscale14(day-posy,zoom); + drawline16(320+dax-2,200+day-2,320+dax+2,200+day-2,14); + drawline16(320+dax+2,200+day-2,320+dax+2,200+day+2,14); + drawline16(320+dax+2,200+day+2,320+dax-2,200+day+2,14); + drawline16(320+dax-2,200+day+2,320+dax-2,200+day-2,14); + } + if (bad > 0) + { + bad = 0; + keystatus[0x39] = 0; + asksave = 1; + printmessage16("Circle points inserted."); + circlewall = -1; + } + } + } + + if (bad > 0) /* Space bar test */ + { + keystatus[0x39] = 0; + adjustmark(&mousxplc,&mousyplc,newnumwalls); + if (checkautoinsert(mousxplc,mousyplc,newnumwalls) == 1) + { + printmessage16("You must insert a point there first."); + bad = 0; + } + } + + if (bad > 0) /* Space */ + { + if ((newnumwalls < numwalls) && (numwalls < MAXWALLS-1)) + { + firstx = mousxplc, firsty = mousyplc; /* Make first point */ + newnumwalls = numwalls; + suckwall = -1; + split = 0; + + clearbufbyte((void *) FP_OFF(&wall[newnumwalls]),sizeof(walltype),0L); + wall[newnumwalls].extra = -1; + + wall[newnumwalls].x = mousxplc; + wall[newnumwalls].y = mousyplc; + wall[newnumwalls].nextsector = -1; + wall[newnumwalls].nextwall = -1; + for(i=0;i>1); + day = ((wall[numwalls].y+mousyplc)>>1); + for(i=0;i= 0) + if ((wall[wall[k].point2].x != mousxplc) || (wall[wall[k].point2].y != mousyplc)) + if ((wall[lastwall((short)k)].x != mousxplc) || (wall[lastwall((short)k)].y != mousyplc)) + { + split = 1; + splitsect = i; + splitstartwall = m; + break; + } + } + } + + /* make new point */ + + /* make sure not drawing over old red line */ + bad = 0; + for(i=0;i= 0) + { + if ((wall[i].x == mousxplc) && (wall[i].y == mousyplc)) + if ((wall[wall[i].point2].x == wall[newnumwalls-1].x) && (wall[wall[i].point2].y == wall[newnumwalls-1].y)) + bad = 1; + if ((wall[i].x == wall[newnumwalls-1].x) && (wall[i].y == wall[newnumwalls-1].y)) + if ((wall[wall[i].point2].x == mousxplc) && (wall[wall[i].point2].y == mousyplc)) + bad = 1; + } + } + + if (bad == 0) + { + clearbufbyte((void *) FP_OFF(&wall[newnumwalls]),sizeof(walltype),0L); + wall[newnumwalls].extra = -1; + + wall[newnumwalls].x = mousxplc; + wall[newnumwalls].y = mousyplc; + wall[newnumwalls].nextsector = -1; + wall[newnumwalls].nextwall = -1; + for(i=0;i= numwalls+3)) + { + wall[newnumwalls-1].point2 = numwalls; + + if (suckwall == -1) /* if no connections to other sectors */ + { + k = -1; + for(i=0;i= suckwall) + wall[i].nextwall += j; + if (wall[i].point2 >= suckwall) + wall[i].point2 += j; + } + + for(i=newnumwalls-1;i>=suckwall;i--) + memcpy(&wall[i+j],&wall[i],sizeof(walltype)); + for(i=0;inumwalls;j--) + { + memcpy(&wall[danumwalls],&wall[j],sizeof(walltype)); + wall[danumwalls].nextwall = -1; + wall[danumwalls].nextsector = -1; + wall[danumwalls].point2 = danumwalls+1; + danumwalls++; + } + m = splitstartwall; /* copy rest of loop next */ + while (m != splitendwall) + { + memcpy(&wall[danumwalls],&wall[m],sizeof(walltype)); + wall[danumwalls].point2 = danumwalls+1; + danumwalls++; + m = wall[m].point2; + } + wall[danumwalls-1].point2 = secondstartwall; + + /* Add other loops for 2nd sector */ + loopnum = loopnumofsector(splitsect,splitstartwall); + i = loopnum; + for(j=startwall;j<=endwall;j++) + { + k = loopnumofsector(splitsect,(short)j); + if ((k != i) && (k != loopnum)) + { + i = k; + if (loopinside(wall[j].x,wall[j].y,secondstartwall) == 1) + { + m = j; /* copy loop */ + k = danumwalls; + do + { + memcpy(&wall[danumwalls],&wall[m],sizeof(walltype)); + wall[danumwalls].point2 = danumwalls+1; + danumwalls++; + m = wall[m].point2; + } + while (m != j); + wall[danumwalls-1].point2 = k; + } + } + } + + /* fix all next pointers on old sector line */ + for(j=numwalls;j= 0) + { + wall[wall[j].nextwall].nextwall = j; + if (j < secondstartwall) + wall[wall[j].nextwall].nextsector = numsectors; + else + wall[wall[j].nextwall].nextsector = numsectors+1; + } + } + /* set all next pointers on split */ + for(j=numwalls;j= 0) + checksectorpointer(wall[j].nextwall,wall[j].nextsector); + checksectorpointer((short)j,sectorofwall((short)j)); + } + + /* k now safe to use as temp */ + + for(m=numsectors-2;mnumwalls;j--) + { + memcpy(&wall[danumwalls],&wall[j],sizeof(walltype)); + wall[danumwalls].nextwall = -1; + wall[danumwalls].nextsector = -1; + wall[danumwalls].point2 = danumwalls+1; + danumwalls++; + } + + m = splitstartwall; /* copy rest of loop next */ + do + { + memcpy(&wall[danumwalls],&wall[m],sizeof(walltype)); + wall[danumwalls].point2 = danumwalls+1; + danumwalls++; + m = wall[m].point2; + } while (m != splitstartwall); + wall[danumwalls-1].point2 = numwalls; + + /* Add other loops to sector */ + loopnum = loopnumofsector(splitsect,splitstartwall); + i = loopnum; + for(j=startwall;j<=endwall;j++) + { + k = loopnumofsector(splitsect,(short)j); + if ((k != i) && (k != loopnumofsector(splitsect,splitstartwall)) && (k != loopnumofsector(splitsect,splitendwall))) + { + i = k; + m = j; k = danumwalls; /* copy loop */ + do + { + memcpy(&wall[danumwalls],&wall[m],sizeof(walltype)); + wall[danumwalls].point2 = danumwalls+1; + danumwalls++; + m = wall[m].point2; + } while (m != j); + wall[danumwalls-1].point2 = k; + } + } + + /* fix all next pointers on old sector line */ + for(j=numwalls;j= 0) + { + wall[wall[j].nextwall].nextwall = j; + wall[wall[j].nextwall].nextsector = numsectors; + } + } + + /* copy sector attributes & fix wall pointers */ + memcpy(§or[numsectors],§or[splitsect],sizeof(sectortype)); + sector[numsectors].wallptr = numwalls; + sector[numsectors].wallnum = danumwalls-numwalls; + + /* fix sprites */ + j = headspritesect[splitsect]; + while (j != -1) + { + k = nextspritesect[j]; + changespritesect(j,numsectors); + j = k; + } + + numsectors++; + + /* Back of number of walls of new sector for later */ + k = danumwalls-numwalls; + + /* clear out old sector's next pointers for clean deletesector */ + numwalls = danumwalls; + for(j=startwall;j<=endwall;j++) + { + wall[j].nextwall = -1; + wall[j].nextsector = -1; + } + deletesector(splitsect); + + /* Check pointers */ + for(j=numwalls-k;j= 0) + checksectorpointer(wall[j].nextwall,wall[j].nextsector); + checksectorpointer((short)j,numsectors-1); + } + + newnumwalls = -1; + printmessage16("Loops joined."); + break; + } + } + } + } + } + + if (keystatus[0x1c] > 0) /* Left Enter */ + { + keystatus[0x1c] = 0; + if (keystatus[0x2a]&keystatus[0x1d]) + { + printmessage16("CHECKING ALL POINTERS!"); + for(i=0;i=0;i--) + sector[i].wallnum = sector[i+1].wallptr-sector[i].wallptr; + sector[numsectors-1].wallnum = numwalls-sector[numsectors-1].wallptr; + + for(i=0;i= 0) + { + checksectorpointer(linehighlight,sectorofwall(linehighlight)); + printmessage16("Highlighted line pointers checked."); + asksave = 1; + } + } + } + + if ((keystatus[0x0e] > 0) && (newnumwalls >= numwalls)) /* Backspace */ + { + if (newnumwalls > numwalls) + { + newnumwalls--; + asksave = 1; + keystatus[0x0e] = 0; + } + if (newnumwalls == numwalls) + { + newnumwalls = -1; + asksave = 1; + keystatus[0x0e] = 0; + } + } + + if ((keystatus[0xd3] > 0) && (keystatus[0x9d] > 0) && (numwalls >= 0)) + { /* sector delete */ + keystatus[0xd3] = 0; + + sucksect = -1; + for(i=0;i= 0) + for(j=0;j=0;j--) + { + deletesector(highlightsector[j]); + for(k=j-1;k>=0;k--) + if (highlightsector[k] >= highlightsector[j]) + highlightsector[k]--; + } + printmessage16("Highlighted sectors deleted."); + newnumwalls = -1; + k = 1; + highlightsectorcnt = -1; + break; + } + if (k == 0) + { + deletesector((short)i); + highlightsectorcnt = -1; + printmessage16("Sector deleted."); + } + newnumwalls = -1; + asksave = 1; + break; + } + } + + if ((keystatus[0xd3] > 0) && (pointhighlight >= 0)) + { + if ((pointhighlight&0xc000) == 16384) /* Sprite Delete */ + { + deletesprite(pointhighlight&16383); + printmessage16("Sprite deleted."); + updatenumsprites(); + asksave = 1; + } + keystatus[0xd3] = 0; + } + + if (keystatus[0xd2] > 0) /* InsertPoint */ + { + if (highlightsectorcnt >= 0) + { + newnumsectors = numsectors; + newnumwalls = numwalls; + for(i=0;i= 0) + checksectorpointer(wall[j].nextwall,wall[j].nextsector); + checksectorpointer((short)j,highlightsector[i]); + } + highlightsector[i] = numsectors+i; + } + numsectors = newnumsectors; + numwalls = newnumwalls; + + newnumwalls = -1; + newnumsectors = -1; + + updatenumsprites(); + printmessage16("Sectors duplicated and stamped."); + asksave = 1; + } + else if (highlightcnt >= 0) + { + for(i=0;i= 0) + { + getclosestpointonwall(mousxplc,mousyplc,(long)linehighlight,&dax,&day); + adjustmark(&dax,&day,newnumwalls); + insertpoint(linehighlight,dax,day); + printmessage16("Point inserted."); + + j = 0; + /* Check to see if point was inserted over another point */ + for(i=numwalls-1;i>=0;i--) /* delete points */ + if (wall[i].x == wall[wall[i].point2].x) + if (wall[i].y == wall[wall[i].point2].y) + { + deletepoint((short)i); + j++; + } + for(i=0;i>1); + day = ((wall[linehighlight].y + wall[wall[linehighlight].point2].y)>>1); + if ((dax != wall[linehighlight].x) || (day != wall[linehighlight].y)) + if ((dax != wall[wall[linehighlight].point2].x) || (day != wall[wall[linehighlight].point2].y)) + { + insertpoint(linehighlight,dax,day); + printmessage16("Point inserted at midpoint."); + } + } + #endif + + asksave = 1; + } + keystatus[0xd2] = 0; + } + + ExtCheckKeys(); + + j = 0; + for(i=22-1;i>=0;i--) updatecrc16(j,kensig[i]); + if ((j&0xffff) != 0xebf) + { + setvmode(0x3); + printf("Don't screw with my name.\n"); + exit(0); + } + + statusbar_printext16_noupdate(9L,9L,4,-1,kensig,0); + statusbar_printext16(8L,8L,12,-1,kensig,0); + + nextpage(); + synctics = totalclock-lockclock; + lockclock += synctics; + + if (keystatus[buildkeys[14]] > 0) + { + updatesector(posx,posy,&cursectnum); + if (cursectnum >= 0) + keystatus[buildkeys[14]] = 2; + else + printmessage16("Arrow must be inside a sector before entering 3D mode."); + } + if (keystatus[1] > 0) + { + keystatus[1] = 0; + printmessage16("(N)ew, (L)oad, (S)ave, save (A)s, (Q)uit"); + bad = 1; + while (bad == 1) + { + _idle(); + + if (keystatus[1] > 0) + { + keystatus[1] = 0; + bad = 0; + printmessage16(""); + } + if (keystatus[0x31] > 0) /* N */ + { + bad = 0; + keystatus[0x31] = 0; + printmessage16("Are you sure you want to start a new board?"); + while ((keystatus[1]|keystatus[0x1c]|keystatus[0x39]|keystatus[0x31]) == 0) + { + _idle(); + if (keystatus[0x15] != 0) + { + /* !!! this should probably prompt to save changes to the current map. --ryan. */ + keystatus[0x15] = 0; + + highlightsectorcnt = -1; + highlightcnt = -1; + + for(i=0;i<(MAXWALLS>>3);i++) /* Clear all highlights */ + show2dwall[i] = 0; + for(i=0;i<(MAXSPRITES>>3);i++) + show2dsprite[i] = 0; + + for(i=0;i 0) /* L */ + { + bad = 0; + keystatus[0x26] = 0; + i = menuselect(); + if (i < 0) + { + if (i == -2) + printmessage16("No .MAP files found."); + } + else + { + strcpy(boardfilename,menuname[menuhighlight]); + + if (highlightsectorcnt >= 0) + { + j = 0; k = 0; + for(i=0;i MAXSECTORS) || (numwalls+j > MAXWALLS) || (numsprites+k > MAXSPRITES)) + { + highlightsectorcnt = -1; + } + else + { + /* Put sectors&walls to end of lists */ + j = MAXWALLS; + for(i=0;i=0;i--) + if (sprite[i].statnum < MAXSTATUS) + { + k = sprite[i].sectnum; + for(j=0;j= 0) + { + if ((numsectors+highlightsectorcnt > MAXSECTORS) || (sector[MAXSECTORS-highlightsectorcnt].wallptr < numwalls)) + { + highlightsectorcnt = -1; + } + else + { + /* Re-attach sectors&walls */ + for(i=0;i= 0) + checksectorpointer(wall[j].nextwall,wall[j].nextsector); + checksectorpointer((short)j,highlightsector[i]); + } + } + + } + } + + printmessage16("Map loaded successfully."); + asksave = 0; /* rcg09032000 my add. */ + } + updatenumsprites(); + startposx = posx; /* this is same */ + startposy = posy; + startposz = posz; + startang = ang; + startsectnum = cursectnum; + } + chdir(curpath); + keystatus[0x1c] = 0; + } + if (keystatus[0x1e] > 0) /* A */ + { + bad = 0; + keystatus[0x1e] = 0; + + strcpy(oboardfilename,boardfilename); + + i = 0; + while ((boardfilename[i] != 0) && (i < 13)) + i++; + if (boardfilename[i-4] == '.') + i -= 4; + boardfilename[i] = 0; + + while (bad == 0) + { + _idle(); + sprintf(buffer,"Save as: %s",boardfilename); + printmessage16(buffer); + + if (keystatus[1] > 0) bad = 1; + if (keystatus[0x1c] > 0) bad = 2; + + if (i > 0) + { + if (keystatus[0xe] > 0) + { + keystatus[0xe] = 0; + i--; + boardfilename[i] = 0; + } + } + if (i < 8) + { + if ((keystatus[0x2a]|keystatus[0x36]) > 0) + { + for(j=0;j<128;j++) + if (scantoascwithshift[j] > 0) + if (keystatus[j] > 0) + { + keystatus[j] = 0; + boardfilename[i++] = scantoascwithshift[j]; + boardfilename[i] = 0; + } + } + else + { + for(j=0;j<128;j++) + if (scantoasc[j] > 0) + if (keystatus[j] > 0) + { + keystatus[j] = 0; + boardfilename[i++] = scantoasc[j]; + boardfilename[i] = 0; + } + } + } + } + if (bad == 1) + { + strcpy(boardfilename,oboardfilename); + keystatus[1] = 0; + printmessage16("Operation cancelled"); + } + if (bad == 2) + { + keystatus[0x1c] = 0; + + boardfilename[i] = '.'; + boardfilename[i+1] = 'm'; + boardfilename[i+2] = 'a'; + boardfilename[i+3] = 'p'; + boardfilename[i+4] = 0; + + sprintf(buffer,"Saving to %s...",boardfilename); + printmessage16(buffer); + + fixspritesectors(); /* Do this before saving! */ + updatesector(startposx,startposy,&startsectnum); + saveboard(boardfilename,&startposx,&startposy,&startposz,&startang,&startsectnum); + ExtSaveMap(boardfilename); + printmessage16("Board saved."); + asksave = 0; /* rcg09032000 my add. */ + } + bad = 0; + } + if (keystatus[0x1f] > 0) /* S */ + { + bad = 0; + keystatus[0x1f] = 0; + printmessage16("Saving board..."); + fixspritesectors(); /* Do this before saving! */ + updatesector(startposx,startposy,&startsectnum); + saveboard(boardfilename,&startposx,&startposy,&startposz,&startang,&startsectnum); + ExtSaveMap(boardfilename); + printmessage16("Board saved."); + asksave = 0; /* rcg09032000 my add. */ + } + if (keystatus[0x10] > 0) /* Q */ + { + bad = 0; + keystatus[0x10] = 0; + printmessage16("Are you sure you want to quit?"); + while ((keystatus[1]|keystatus[0x1c]|keystatus[0x39]|keystatus[0x31]) == 0) + { + _idle(); + if (keystatus[0x15] != 0) + { + keystatus[0x15] = 0; /* QUIT! */ + + if (asksave) /* rcg09032000 my add. */ + { + printmessage16("Save changes?"); + while ((keystatus[1]|keystatus[0x1c]|keystatus[0x39]|keystatus[0x31]) == 0) + { + _idle(); + if (keystatus[0x15] > 0) + { + keystatus[0x15] = 0; + + fixspritesectors(); /* Do this before saving! */ + updatesector(startposx,startposy,&startsectnum); + saveboard(boardfilename,&startposx,&startposy,&startposz,&startang,&startsectnum); + ExtSaveMap(boardfilename); + asksave = 0; /* rcg09032000 my add. */ + break; + } + } + } /* if */ + + uninittimer(); + uninitkeys(); + ExtUnInit(); + uninitengine(); + setvmode(0x3); + printf("Memory status: %ld(%ld) bytes\n", cachesize, artsize); + printf("%s\n", kensig); + printf("%s\n", PORTSIG); + exit(0); + } + } + printmessage16(""); + } + } + } + } + + for(i=0;i= 0) + checksectorpointer(wall[j].nextwall,wall[j].nextsector); + checksectorpointer((short)j,highlightsector[i]); + } + } + + fixspritesectors(); + + if (setgamemode(vidoption,xdim,ydim) < 0) + { + ExtUnInit(); + uninitkeys(); + uninittimer(); + printf("%ld * %ld not supported in this graphics mode\n",xdim,ydim); + exit(0); + } + + posz = oposz; + searchx = scale(searchx,xdim,640); + searchy = scale(searchy,ydim,480); +} + + +void editinput(void) +{ + char smooshyalign, repeatpanalign, buffer[80]; + short startwall, endwall, dasector, daang; + short mousx, mousy, mousz, bstatus; + long i, j, k, templong=0, doubvel, changedir; + long dashade[2], goalz, xvect, yvect, hiz, loz; + short hitsect, hitwall, hitsprite; + long hitx, hity, hitz, dax, day, hihit, lohit; + + if (keystatus[0x57] > 0) /* F11 - brightness */ + { + keystatus[0x57] = 0; + brightness++; + if (brightness > 16) brightness = 0; + setbrightness((char) brightness, (unsigned char *) palette); + } + if (keystatus[88] > 0) /* F12 */ + { + screencapture("captxxxx.pcx",keystatus[0x2a]|keystatus[0x36]); + keystatus[88] = 0; + } + + mousz = 0; + getmousevalues(&mousx,&mousy,&bstatus); + searchx += (mousx>>1); + searchy += (mousy>>1); + if (searchx < 4) searchx = 4; + if (searchy < 4) searchy = 4; + if (searchx > xdim-5) searchx = xdim-5; + if (searchy > ydim-5) searchy = ydim-5; + showmouse(); + + if (keystatus[0x3b] > 0) posx--; + if (keystatus[0x3c] > 0) posx++; + if (keystatus[0x3d] > 0) posy--; + if (keystatus[0x3e] > 0) posy++; + if (keystatus[0x43] > 0) ang--; + if (keystatus[0x44] > 0) ang++; + + if (angvel != 0) /* ang += angvel * constant */ + { /* ENGINE calculates angvel for you */ + doubvel = synctics; + if (keystatus[buildkeys[4]] > 0) /* Lt. shift makes turn velocity 50% faster */ + doubvel += (synctics>>1); + ang += ((angvel*doubvel)>>4); + ang = (ang+2048)&2047; + } + if ((vel|svel) != 0) + { + doubvel = synctics; + if (keystatus[buildkeys[4]] > 0) /* Lt. shift doubles forward velocity */ + doubvel += synctics; + xvect = 0, yvect = 0; + if (vel != 0) + { + xvect += ((vel*doubvel*(long)sintable[(ang+2560)&2047])>>3); + yvect += ((vel*doubvel*(long)sintable[(ang+2048)&2047])>>3); + } + if (svel != 0) + { + xvect += ((svel*doubvel*(long)sintable[(ang+2048)&2047])>>3); + yvect += ((svel*doubvel*(long)sintable[(ang+1536)&2047])>>3); + } + clipmove(&posx,&posy,&posz,&cursectnum,xvect,yvect,128L,4L<<8,4L<<8,CLIPMASK0); + } + getzrange(posx,posy,posz,cursectnum,&hiz,&hihit,&loz,&lohit,128L,CLIPMASK0); + + if (keystatus[0x3a] > 0) + { + zmode++; + if (zmode == 3) zmode = 0; + if (zmode == 1) zlock = (loz-posz)&0xfffffc00; + keystatus[0x3a] = 0; + } + + if (zmode == 0) + { + goalz = loz-(kensplayerheight<<8); /* playerheight pixels above floor */ + if (goalz < hiz+(16<<8)) /* ceiling&floor too close */ + goalz = ((loz+hiz)>>1); + goalz += mousz; + if (keystatus[buildkeys[8]] > 0) /* A (stand high) */ + { + if (keystatus[0x1d] > 0) + horiz = max(-100,horiz-((keystatus[buildkeys[4]]+1)<<2)); + else + { + goalz -= (16<<8); + if (keystatus[buildkeys[4]] > 0) /* Either shift key */ + goalz -= (24<<8); + } + } + if (keystatus[buildkeys[9]] > 0) /* Z (stand low) */ + { + if (keystatus[0x1d] > 0) + horiz = min(300,horiz+((keystatus[buildkeys[4]]+1)<<2)); + else + { + goalz += (12<<8); + if (keystatus[buildkeys[4]] > 0) /* Either shift key */ + goalz += (12<<8); + } + } + + if (goalz != posz) + { + if (posz < goalz) hvel += 32; + if (posz > goalz) hvel = ((goalz-posz)>>3); + + posz += hvel; + if (posz > loz-(4<<8)) posz = loz-(4<<8), hvel = 0; + if (posz < hiz+(4<<8)) posz = hiz+(4<<8), hvel = 0; + } + } + else + { + goalz = posz; + if (keystatus[buildkeys[8]] > 0) /* A */ + { + if (keystatus[0x1d] > 0) + horiz = max(-100,horiz-((keystatus[buildkeys[4]]+1)<<2)); + else + { + if (zmode != 1) + goalz -= (8<<8); + else + { + zlock += (4<<8); + keystatus[buildkeys[8]] = 0; + } + } + } + if (keystatus[buildkeys[9]] > 0) /* Z (stand low) */ + { + if (keystatus[0x1d] > 0) + horiz = min(300,horiz+((keystatus[buildkeys[4]]+1)<<2)); + else + { + if (zmode != 1) + goalz += (8<<8); + else if (zlock > 0) + { + zlock -= (4<<8); + keystatus[buildkeys[9]] = 0; + } + } + } + + if (goalz < hiz+(4<<8)) goalz = hiz+(4<<8); + if (goalz > loz-(4<<8)) goalz = loz-(4<<8); + if (zmode == 1) goalz = loz-zlock; + if (goalz < hiz+(4<<8)) goalz = ((loz+hiz)>>1); /* ceiling&floor too close */ + if (zmode == 1) posz = goalz; + + if (goalz != posz) + { + if (posz < goalz) hvel += (32< goalz) hvel -= (32< loz-(4<<8)) posz = loz-(4<<8), hvel = 0; + if (posz < hiz+(4<<8)) posz = hiz+(4<<8), hvel = 0; + } + else + hvel = 0; + } + + searchit = 2; + if (searchstat >= 0) + { + if ((bstatus&1) > 0) + searchit = 0; + if (keystatus[0x4a] > 0) /* - */ + { + keystatus[0x4a] = 0; + if ((keystatus[0x38]|keystatus[0xb8]) > 0) /* ALT */ + { + if ((keystatus[0x1d]|keystatus[0x9d]) > 0) /* CTRL */ + { + if (visibility < 16384) visibility += visibility; + } + else + { + if ((keystatus[0x2a]|keystatus[0x36]) == 0) + k = 16; else k = 1; + + if (highlightsectorcnt >= 0) + for(i=0;i 0) + { + for(i=0;i 0) + { + sector[searchsector].visibility++; + if (sector[searchsector].visibility == 240) + sector[searchsector].visibility = 239; + k--; + } + asksave = 1; + } + } + else + { + k = 0; + if (highlightsectorcnt >= 0) + { + for(i=0;i 0) /* + */ + { + keystatus[0x4e] = 0; + if ((keystatus[0x38]|keystatus[0xb8]) > 0) /* ALT */ + { + if ((keystatus[0x1d]|keystatus[0x9d]) > 0) /* CTRL */ + { + if (visibility > 32) visibility >>= 1; + } + else + { + if ((keystatus[0x2a]|keystatus[0x36]) == 0) + k = 16; else k = 1; + + if (highlightsectorcnt >= 0) + for(i=0;i 0) + { + for(i=0;i 0) + { + sector[searchsector].visibility--; + if (sector[searchsector].visibility == 239) + sector[searchsector].visibility = 240; + k--; + } + asksave = 1; + } + } + else + { + k = 0; + if (highlightsectorcnt >= 0) + { + for(i=0;i 0) /* PGUP */ + { + k = 0; + if (highlightsectorcnt >= 0) + { + for(i=0;i 0) /* CTRL - put sprite on ceiling */ + { + sprite[searchwall].z = getceilzofslope(searchsector,sprite[searchwall].x,sprite[searchwall].y); + if (sprite[searchwall].cstat&128) sprite[searchwall].z -= ((tilesizy[sprite[searchwall].picnum]*sprite[searchwall].yrepeat)<<1); + if ((sprite[searchwall].cstat&48) != 32) + sprite[searchwall].z += ((tilesizy[sprite[searchwall].picnum]*sprite[searchwall].yrepeat)<<2); + } + else + { + k = 0; + if (highlightcnt >= 0) + for(i=0;i 0) /* PGDN */ + { + k = 0; + if (highlightsectorcnt >= 0) + { + for(i=0;i sector[searchsector].floorz) + sector[searchsector].ceilingz = sector[searchsector].floorz; + if (searchstat == 3) + { + if ((keystatus[0x1d]|keystatus[0x9d]) > 0) /* CTRL - put sprite on ground */ + { + sprite[searchwall].z = getflorzofslope(searchsector,sprite[searchwall].x,sprite[searchwall].y); + if (sprite[searchwall].cstat&128) sprite[searchwall].z -= ((tilesizy[sprite[searchwall].picnum]*sprite[searchwall].yrepeat)<<1); + } + else + { + k = 0; + if (highlightcnt >= 0) + for(i=0;i 0) /* TAB */ + { + if (searchstat == 0) + { + temppicnum = wall[searchwall].picnum; + tempshade = wall[searchwall].shade; + temppal = wall[searchwall].pal; + tempxrepeat = wall[searchwall].xrepeat; + tempyrepeat = wall[searchwall].yrepeat; + tempcstat = wall[searchwall].cstat; + templotag = wall[searchwall].lotag; + temphitag = wall[searchwall].hitag; + tempextra = wall[searchwall].extra; + } + if (searchstat == 1) + { + temppicnum = sector[searchsector].ceilingpicnum; + tempshade = sector[searchsector].ceilingshade; + temppal = sector[searchsector].ceilingpal; + tempvis = sector[searchsector].visibility; + tempxrepeat = sector[searchsector].ceilingxpanning; + tempyrepeat = sector[searchsector].ceilingypanning; + tempcstat = sector[searchsector].ceilingstat; + templotag = sector[searchsector].lotag; + temphitag = sector[searchsector].hitag; + tempextra = sector[searchsector].extra; + } + if (searchstat == 2) + { + temppicnum = sector[searchsector].floorpicnum; + tempshade = sector[searchsector].floorshade; + temppal = sector[searchsector].floorpal; + tempvis = sector[searchsector].visibility; + tempxrepeat = sector[searchsector].floorxpanning; + tempyrepeat = sector[searchsector].floorypanning; + tempcstat = sector[searchsector].floorstat; + templotag = sector[searchsector].lotag; + temphitag = sector[searchsector].hitag; + tempextra = sector[searchsector].extra; + } + if (searchstat == 3) + { + temppicnum = sprite[searchwall].picnum; + tempshade = sprite[searchwall].shade; + temppal = sprite[searchwall].pal; + tempxrepeat = sprite[searchwall].xrepeat; + tempyrepeat = sprite[searchwall].yrepeat; + tempcstat = sprite[searchwall].cstat; + templotag = sprite[searchwall].lotag; + temphitag = sprite[searchwall].hitag; + tempextra = sprite[searchwall].extra; + } + if (searchstat == 4) + { + temppicnum = wall[searchwall].overpicnum; + tempshade = wall[searchwall].shade; + temppal = wall[searchwall].pal; + tempxrepeat = wall[searchwall].xrepeat; + tempyrepeat = wall[searchwall].yrepeat; + tempcstat = wall[searchwall].cstat; + templotag = wall[searchwall].lotag; + temphitag = wall[searchwall].hitag; + tempextra = wall[searchwall].extra; + } + somethingintab = searchstat; + keystatus[0x0f] = 0; + } + if (keystatus[0x1c] > 0) /* Left ENTER */ + { + if ((keystatus[0x2a]|keystatus[0x36]) > 0) /* Either shift key */ + { + if (((searchstat == 0) || (searchstat == 4)) && ((keystatus[0x1d]|keystatus[0x9d]) > 0)) /* Ctrl-shift Enter (auto-shade) */ + { + dashade[0] = 127; + dashade[1] = -128; + i = searchwall; + do + { + if ((long)wall[i].shade < dashade[0]) dashade[0] = wall[i].shade; + if ((long)wall[i].shade > dashade[1]) dashade[1] = wall[i].shade; + + i = wall[i].point2; + } + while (i != searchwall); + + daang = getangle(wall[wall[searchwall].point2].x-wall[searchwall].x,wall[wall[searchwall].point2].y-wall[searchwall].y); + i = searchwall; + do + { + j = getangle(wall[wall[i].point2].x-wall[i].x,wall[wall[i].point2].y-wall[i].y); + k = ((j+2048-daang)&2047); + if (k > 1024) + k = 2048-k; + wall[i].shade = dashade[0]+mulscale10(k,dashade[1]-dashade[0]); + + i = wall[i].point2; + } + while (i != searchwall); + } + else if (somethingintab < 255) + { + if (searchstat == 0) wall[searchwall].shade = tempshade, wall[searchwall].pal = temppal; + if (searchstat == 1) + { + sector[searchsector].ceilingshade = tempshade, sector[searchsector].ceilingpal = temppal; + if ((somethingintab == 1) || (somethingintab == 2)) + sector[searchsector].visibility = tempvis; + } + if (searchstat == 2) + { + sector[searchsector].floorshade = tempshade, sector[searchsector].floorpal = temppal; + if ((somethingintab == 1) || (somethingintab == 2)) + sector[searchsector].visibility = tempvis; + } + if (searchstat == 3) sprite[searchwall].shade = tempshade, sprite[searchwall].pal = temppal; + if (searchstat == 4) wall[searchwall].shade = tempshade, wall[searchwall].pal = temppal; + } + } + else if (((searchstat == 0) || (searchstat == 4)) && ((keystatus[0x1d]|keystatus[0x9d]) > 0) && (somethingintab < 255)) /* Either ctrl key */ + { + i = searchwall; + do + { + wall[i].picnum = temppicnum; + wall[i].shade = tempshade; + wall[i].pal = temppal; + if ((somethingintab == 0) || (somethingintab == 4)) + { + wall[i].xrepeat = tempxrepeat; + wall[i].yrepeat = tempyrepeat; + wall[i].cstat = tempcstat; + } + fixrepeats((short)i); + i = wall[i].point2; + } + while (i != searchwall); + } + else if (((searchstat == 1) || (searchstat == 2)) && ((keystatus[0x1d]|keystatus[0x9d]) > 0) && (somethingintab < 255)) /* Either ctrl key */ + { + clearbuf((long *)(&pskysearch[0]),(long)((numsectors+3)>>2),0L); + if (searchstat == 1) + { + i = searchsector; + if ((sector[i].ceilingstat&1) > 0) + pskysearch[i] = 1; + + while (pskysearch[i] == 1) + { + sector[i].ceilingpicnum = temppicnum; + sector[i].ceilingshade = tempshade; + sector[i].ceilingpal = temppal; + if ((somethingintab == 1) || (somethingintab == 2)) + { + sector[i].ceilingxpanning = tempxrepeat; + sector[i].ceilingypanning = tempyrepeat; + sector[i].ceilingstat = tempcstat; + } + pskysearch[i] = 2; + + startwall = sector[i].wallptr; + endwall = startwall + sector[i].wallnum - 1; + for(j=startwall;j<=endwall;j++) + { + k = wall[j].nextsector; + if (k >= 0) + if ((sector[k].ceilingstat&1) > 0) + if (pskysearch[k] == 0) + pskysearch[k] = 1; + } + + for(j=0;j 0) + pskysearch[i] = 1; + + while (pskysearch[i] == 1) + { + sector[i].floorpicnum = temppicnum; + sector[i].floorshade = tempshade; + sector[i].floorpal = temppal; + if ((somethingintab == 1) || (somethingintab == 2)) + { + sector[i].floorxpanning = tempxrepeat; + sector[i].floorypanning = tempyrepeat; + sector[i].floorstat = tempcstat; + } + pskysearch[i] = 2; + + startwall = sector[i].wallptr; + endwall = startwall + sector[i].wallnum - 1; + for(j=startwall;j<=endwall;j++) + { + k = wall[j].nextsector; + if (k >= 0) + if ((sector[k].floorstat&1) > 0) + if (pskysearch[k] == 0) + pskysearch[k] = 1; + } + + for(j=0;j 0) && (tilesizy[k] > 0)) + { + j = k; + break; + } + sprite[searchwall].picnum = j; + } + sprite[searchwall].shade = tempshade; + sprite[searchwall].pal = temppal; + if (somethingintab == 3) + { + sprite[searchwall].xrepeat = tempxrepeat; + sprite[searchwall].yrepeat = tempyrepeat; + if (sprite[searchwall].xrepeat < 1) sprite[searchwall].xrepeat = 1; + if (sprite[searchwall].yrepeat < 1) sprite[searchwall].yrepeat = 1; + sprite[searchwall].cstat = tempcstat; + sprite[searchwall].lotag = templotag; + sprite[searchwall].hitag = temphitag; + sprite[searchwall].extra = tempextra; + } + } + if (searchstat == 4) + { + wall[searchwall].overpicnum = temppicnum; + if (wall[searchwall].nextwall >= 0) + wall[wall[searchwall].nextwall].overpicnum = temppicnum; + wall[searchwall].shade = tempshade; + wall[searchwall].pal = temppal; + if (somethingintab == 4) + { + wall[searchwall].xrepeat = tempxrepeat; + wall[searchwall].yrepeat = tempyrepeat; + wall[searchwall].cstat = tempcstat; + wall[searchwall].lotag = templotag; + wall[searchwall].hitag = temphitag; + wall[searchwall].extra = tempextra; + } + fixrepeats(searchwall); + } + } + asksave = 1; + keystatus[0x1c] = 0; + } + if (keystatus[0x2e] > 0) /* C */ + { + keystatus[0x2e] = 0; + if (keystatus[0x38] > 0) /* Alt-C */ + { + if (somethingintab < 255) + { + switch(searchstat) + { + case 0: + j = wall[searchwall].picnum; + for(i=0;i 0) /* V */ + { + if (searchstat == 0) templong = wall[searchwall].picnum; + if (searchstat == 1) templong = sector[searchsector].ceilingpicnum; + if (searchstat == 2) templong = sector[searchsector].floorpicnum; + if (searchstat == 3) templong = sprite[searchwall].picnum; + if (searchstat == 4) templong = wall[searchwall].overpicnum; + templong = gettile(templong); + if (searchstat == 0) wall[searchwall].picnum = templong; + if (searchstat == 1) sector[searchsector].ceilingpicnum = templong; + if (searchstat == 2) sector[searchsector].floorpicnum = templong; + if (searchstat == 3) sprite[searchwall].picnum = templong; + if (searchstat == 4) + { + wall[searchwall].overpicnum = templong; + if (wall[searchwall].nextwall >= 0) + wall[wall[searchwall].nextwall].overpicnum = templong; + } + asksave = 1; + keystatus[0x2f] = 0; + } + + if (keystatus[0x1a]) /* [ */ + { + keystatus[0x1a] = 0; + if (keystatus[0x38]|keystatus[0xb8]) + { + i = wall[searchwall].nextsector; + if (i >= 0) + switch(searchstat) + { + case 0: case 1: case 4: + alignceilslope(searchsector,wall[searchwall].x,wall[searchwall].y,getceilzofslope(i,wall[searchwall].x,wall[searchwall].y)); + break; + case 2: + alignflorslope(searchsector,wall[searchwall].x,wall[searchwall].y,getflorzofslope(i,wall[searchwall].x,wall[searchwall].y)); + break; + } + } + else + { + i = 512; + if (keystatus[0x36]) i = 8; + if (keystatus[0x2a]) i = 1; + + if (searchstat == 1) + { + if (!(sector[searchsector].ceilingstat&2)) + sector[searchsector].ceilingheinum = 0; + sector[searchsector].ceilingheinum = max(sector[searchsector].ceilingheinum-i,-32768); + } + if (searchstat == 2) + { + if (!(sector[searchsector].floorstat&2)) + sector[searchsector].floorheinum = 0; + sector[searchsector].floorheinum = max(sector[searchsector].floorheinum-i,-32768); + } + } + + if (sector[searchsector].ceilingheinum == 0) + sector[searchsector].ceilingstat &= ~2; + else + sector[searchsector].ceilingstat |= 2; + + if (sector[searchsector].floorheinum == 0) + sector[searchsector].floorstat &= ~2; + else + sector[searchsector].floorstat |= 2; + asksave = 1; + } + if (keystatus[0x1b]) /* ] */ + { + keystatus[0x1b] = 0; + if (keystatus[0x38]|keystatus[0xb8]) + { + i = wall[searchwall].nextsector; + if (i >= 0) + switch(searchstat) + { + case 1: + alignceilslope(searchsector,wall[searchwall].x,wall[searchwall].y,getceilzofslope(i,wall[searchwall].x,wall[searchwall].y)); + break; + case 0: case 2: case 4: + alignflorslope(searchsector,wall[searchwall].x,wall[searchwall].y,getflorzofslope(i,wall[searchwall].x,wall[searchwall].y)); + break; + } + } + else + { + i = 512; + if (keystatus[0x36]) i = 8; + if (keystatus[0x2a]) i = 1; + + if (searchstat == 1) + { + if (!(sector[searchsector].ceilingstat&2)) + sector[searchsector].ceilingheinum = 0; + sector[searchsector].ceilingheinum = min(sector[searchsector].ceilingheinum+i,32767); + } + if (searchstat == 2) + { + if (!(sector[searchsector].floorstat&2)) + sector[searchsector].floorheinum = 0; + sector[searchsector].floorheinum = min(sector[searchsector].floorheinum+i,32767); + } + } + + if (sector[searchsector].ceilingheinum == 0) + sector[searchsector].ceilingstat &= ~2; + else + sector[searchsector].ceilingstat |= 2; + + if (sector[searchsector].floorheinum == 0) + sector[searchsector].floorstat &= ~2; + else + sector[searchsector].floorstat |= 2; + + asksave = 1; + } + + smooshyalign = keystatus[0x4c]; + repeatpanalign = (keystatus[0x2a]|keystatus[0x36]); + if ((keystatus[0x4b]|keystatus[0x4d]) > 0) /* 4 & 6 (keypad) */ + { + repeatcountx++; + + if ((repeatcountx == 1) || (repeatcountx > 16)) + { + changedir = 0; + if (keystatus[0x4b] > 0) changedir = -1; + if (keystatus[0x4d] > 0) changedir = 1; + + if ((searchstat == 0) || (searchstat == 4)) + { + if (repeatpanalign == 0) + wall[searchwall].xrepeat = changechar(wall[searchwall].xrepeat,changedir,smooshyalign,1); + else + wall[searchwall].xpanning = changechar(wall[searchwall].xpanning,changedir,smooshyalign,0); + } + if ((searchstat == 1) || (searchstat == 2)) + { + if (searchstat == 1) + sector[searchsector].ceilingxpanning = changechar(sector[searchsector].ceilingxpanning,changedir,smooshyalign,0); + else + sector[searchsector].floorxpanning = changechar(sector[searchsector].floorxpanning,changedir,smooshyalign,0); + } + if (searchstat == 3) + { + sprite[searchwall].xrepeat = changechar(sprite[searchwall].xrepeat,changedir,smooshyalign,1); + if (sprite[searchwall].xrepeat < 4) + sprite[searchwall].xrepeat = 4; + } + asksave = 1; + } + } + else + repeatcountx = 0; + + if ((keystatus[0x48]|keystatus[0x50]) > 0) /* 2 & 8 (keypad) */ + { + repeatcounty++; + + if ((repeatcounty == 1) || (repeatcounty > 16)) + { + changedir = 0; + if (keystatus[0x48] > 0) changedir = -1; + if (keystatus[0x50] > 0) changedir = 1; + + if ((searchstat == 0) || (searchstat == 4)) + { + if (repeatpanalign == 0) + wall[searchwall].yrepeat = changechar(wall[searchwall].yrepeat,changedir,smooshyalign,1); + else + wall[searchwall].ypanning = changechar(wall[searchwall].ypanning,changedir,smooshyalign,0); + } + if ((searchstat == 1) || (searchstat == 2)) + { + if (searchstat == 1) + sector[searchsector].ceilingypanning = changechar(sector[searchsector].ceilingypanning,changedir,smooshyalign,0); + else + sector[searchsector].floorypanning = changechar(sector[searchsector].floorypanning,changedir,smooshyalign,0); + } + if (searchstat == 3) + { + sprite[searchwall].yrepeat = changechar(sprite[searchwall].yrepeat,changedir,smooshyalign,1); + if (sprite[searchwall].yrepeat < 4) + sprite[searchwall].yrepeat = 4; + } + asksave = 1; + } + } + else + repeatcounty = 0; + + if (keystatus[0x33] > 0) /* , Search & fix panning to the left (3D) */ + { + if (searchstat == 3) + { + i = searchwall; + if ((keystatus[0x2a]|keystatus[0x36]) > 0) + sprite[i].ang = ((sprite[i].ang+2048-1)&2047); + else + { + sprite[i].ang = ((sprite[i].ang+2048-128)&2047); + keystatus[0x33] = 0; + } + } + } + if (keystatus[0x34] > 0) /* . Search & fix panning to the right (3D) */ + { + if ((searchstat == 0) || (searchstat == 4)) + { + AutoAlignWalls((long)searchwall,0L); + +#if 0 + wallfind[0] = searchwall; + cnt = 4096; + do + { + wallfind[1] = wall[wallfind[0]].point2; + j = -1; + if (wall[wallfind[1]].picnum == wall[searchwall].picnum) + j = wallfind[1]; + k = wallfind[1]; + + while ((wall[wallfind[1]].nextwall >= 0) && (wall[wall[wallfind[1]].nextwall].point2 != k)) + { + i = wall[wall[wallfind[1]].nextwall].point2; /* break if going around in circles on red lines with same picture on both sides */ + if (wallfind[1] == wall[wall[i].nextwall].point2) + break; + + wallfind[1] = wall[wall[wallfind[1]].nextwall].point2; + if (wall[wallfind[1]].picnum == wall[searchwall].picnum) + j = wallfind[1]; + } + wallfind[1] = j; + + if ((j >= 0) && (wallfind[1] != searchwall)) + { + j = (wall[wallfind[0]].xpanning+(wall[wallfind[0]].xrepeat<<3)) % tilesizx[wall[wallfind[0]].picnum]; + wall[wallfind[1]].cstat &= ~8; /* Set to non-flip */ + wall[wallfind[1]].cstat |= 4; /* Set y-orientation */ + wall[wallfind[1]].xpanning = j; + + for(k=0;k<2;k++) + { + sectnum = sectorofwall((short)wallfind[k]); + nextsectnum = wall[wallfind[k]].nextsector; + + if (nextsectnum == -1) + { + if ((wall[wallfind[k]].cstat&4) == 0) + daz[k] = sector[sectnum].ceilingz; + else + daz[k] = sector[sectnum].floorz; + } + else /* topstep */ + { + if (sector[nextsectnum].ceilingz > sector[sectnum].ceilingz) + daz[k] = sector[nextsectnum].ceilingz; + else if (sector[nextsectnum].floorz < sector[sectnum].floorz) + daz[k] = sector[nextsectnum].floorz; + } + } + + j = (picsiz[wall[searchwall].picnum]>>4); + if ((1<>(j+3)))&255); + wall[wallfind[1]].ypanning = j; + wall[wallfind[1]].yrepeat = wall[wallfind[0]].yrepeat; + if (nextsectnum >= 0) + if (sector[nextsectnum].ceilingz >= sector[sectnum].ceilingz) + if (sector[nextsectnum].floorz <= sector[sectnum].floorz) + { + if (wall[wall[wallfind[1]].nextwall].picnum == wall[searchwall].picnum) + { + wall[wall[wallfind[1]].nextwall].yrepeat = wall[wallfind[0]].yrepeat; + if ((wall[wall[wallfind[1]].nextwall].cstat&4) == 0) + daz[1] = sector[nextsectnum].floorz; + else + daz[1] = sector[sectnum].ceilingz; + wall[wall[wallfind[1]].nextwall].ypanning = j; + } + } + } + wallfind[0] = wallfind[1]; + cnt--; + } + while ((wall[wallfind[0]].picnum == wall[searchwall].picnum) && (wallfind[0] != searchwall) && (cnt > 0)); +#endif + + keystatus[0x34] = 0; + } + if (searchstat == 3) + { + i = searchwall; + if ((keystatus[0x2a]|keystatus[0x36]) > 0) + sprite[i].ang = ((sprite[i].ang+2048+1)&2047); + else + { + sprite[i].ang = ((sprite[i].ang+2048+128)&2047); + keystatus[0x34] = 0; + } + } + } + if (keystatus[0x35] > 0) /* /? Reset panning&repeat to 0 */ + { + if ((searchstat == 0) || (searchstat == 4)) + { + wall[searchwall].xpanning = 0; + wall[searchwall].ypanning = 0; + wall[searchwall].xrepeat = 8; + wall[searchwall].yrepeat = 8; + wall[searchwall].cstat = 0; + fixrepeats((short)searchwall); + } + if (searchstat == 1) + { + sector[searchsector].ceilingxpanning = 0; + sector[searchsector].ceilingypanning = 0; + sector[searchsector].ceilingstat &= ~2; + sector[searchsector].ceilingheinum = 0; + } + if (searchstat == 2) + { + sector[searchsector].floorxpanning = 0; + sector[searchsector].floorypanning = 0; + sector[searchsector].floorstat &= ~2; + sector[searchsector].floorheinum = 0; + } + if (searchstat == 3) + { + if ((keystatus[0x2a]|keystatus[0x36]) > 0) + { + sprite[searchwall].xrepeat = sprite[searchwall].yrepeat; + } + else + { + sprite[searchwall].xrepeat = 64; + sprite[searchwall].yrepeat = 64; + } + } + keystatus[0x35] = 0; + asksave = 1; + } + + if (keystatus[0x19] > 0) /* P (parallaxing sky) */ + { + if ((keystatus[0x1d]|keystatus[0x9d]) > 0) + { + parallaxtype++; + if (parallaxtype == 3) + parallaxtype = 0; + } + else if ((keystatus[0x38]|keystatus[0xb8]) > 0) + { + switch (searchstat) + { + case 0: case 4: + strcpy(buffer,"Wall pal: "); + wall[searchwall].pal = getnumber256(buffer,wall[searchwall].pal,256L); + break; + case 1: + strcpy(buffer,"Ceiling pal: "); + sector[searchsector].ceilingpal = getnumber256(buffer,sector[searchsector].ceilingpal,256L); + break; + case 2: + strcpy(buffer,"Floor pal: "); + sector[searchsector].floorpal = getnumber256(buffer,sector[searchsector].floorpal,256L); + break; + case 3: + strcpy(buffer,"Sprite pal: "); + sprite[searchwall].pal = getnumber256(buffer,sprite[searchwall].pal,256L); + break; + } + } + else + { + if ((searchstat == 0) || (searchstat == 1) || (searchstat == 4)) + { + sector[searchsector].ceilingstat ^= 1; + asksave = 1; + } + else if (searchstat == 2) + { + sector[searchsector].floorstat ^= 1; + asksave = 1; + } + } + keystatus[0x19] = 0; + } + + if (keystatus[0x20] != 0) /* Alt-D (adjust sprite[].clipdist) */ + { + keystatus[0x20] = 0; + if ((keystatus[0x38]|keystatus[0xb8]) > 0) + { + if (searchstat == 3) + { + strcpy(buffer,"Sprite clipdist: "); + sprite[searchwall].clipdist = getnumber256(buffer,sprite[searchwall].clipdist,256L); + } + } + } + + if (keystatus[0x30] > 0) /* B (clip Blocking xor) (3D) */ + { + if (searchstat == 3) + { + sprite[searchwall].cstat ^= 1; + sprite[searchwall].cstat &= ~256; + sprite[searchwall].cstat |= ((sprite[searchwall].cstat&1)<<8); + asksave = 1; + } + else + { + wall[searchwall].cstat ^= 1; + wall[searchwall].cstat &= ~64; + if ((wall[searchwall].nextwall >= 0) && ((keystatus[0x2a]|keystatus[0x36]) == 0)) + { + wall[wall[searchwall].nextwall].cstat &= ~(1+64); + wall[wall[searchwall].nextwall].cstat |= (wall[searchwall].cstat&1); + } + asksave = 1; + } + keystatus[0x30] = 0; + } + if (keystatus[0x14] > 0) /* T (transluscence for sprites/masked walls) */ + { + #if 0 + if (searchstat == 1) /* Set masked/transluscent ceilings/floors */ + { + i = (sector[searchsector].ceilingstat&(128+256)); + sector[searchsector].ceilingstat &= ~(128+256); + switch(i) + { + case 0: sector[searchsector].ceilingstat |= 128; break; + case 128: sector[searchsector].ceilingstat |= 256; break; + case 256: sector[searchsector].ceilingstat |= 384; break; + case 384: sector[searchsector].ceilingstat |= 0; break; + } + asksave = 1; + } + if (searchstat == 2) + { + i = (sector[searchsector].floorstat&(128+256)); + sector[searchsector].floorstat &= ~(128+256); + switch(i) + { + case 0: sector[searchsector].floorstat |= 128; break; + case 128: sector[searchsector].floorstat |= 256; break; + case 256: sector[searchsector].floorstat |= 384; break; + case 384: sector[searchsector].floorstat |= 0; break; + } + asksave = 1; + } + #endif + + if (searchstat == 3) + { + if ((sprite[searchwall].cstat&2) == 0) + sprite[searchwall].cstat |= 2; + else if ((sprite[searchwall].cstat&512) == 0) + sprite[searchwall].cstat |= 512; + else + sprite[searchwall].cstat &= ~(2+512); + asksave = 1; + } + if (searchstat == 4) + { + if ((wall[searchwall].cstat&128) == 0) + wall[searchwall].cstat |= 128; + else if ((wall[searchwall].cstat&512) == 0) + wall[searchwall].cstat |= 512; + else + wall[searchwall].cstat &= ~(128+512); + + if (wall[searchwall].nextwall >= 0) + { + wall[wall[searchwall].nextwall].cstat &= ~(128+512); + wall[wall[searchwall].nextwall].cstat |= (wall[searchwall].cstat&(128+512)); + } + asksave = 1; + } + keystatus[0x14] = 0; + } + + if (keystatus[0x2] > 0) /* 1 (make 1-way wall) */ + { + if (searchstat != 3) + { + wall[searchwall].cstat ^= 32; + asksave = 1; + } + else + { + sprite[searchwall].cstat ^= 64; + i = sprite[searchwall].cstat; + if ((i&48) == 32) + { + sprite[searchwall].cstat &= ~8; + if ((i&64) > 0) + if (posz > sprite[searchwall].z) + sprite[searchwall].cstat |= 8; + } + asksave = 1; + } + keystatus[0x2] = 0; + } + if (keystatus[0x3] > 0) /* 2 (bottom wall swapping) */ + { + if (searchstat != 3) + { + wall[searchwall].cstat ^= 2; + asksave = 1; + } + keystatus[0x3] = 0; + } + if (keystatus[0x18] > 0) /* O (top/bottom orientation - for doors) */ + { + if ((searchstat == 0) || (searchstat == 4)) + { + wall[searchwall].cstat ^= 4; + asksave = 1; + } + if (searchstat == 3) /* O (ornament onto wall) (2D) */ + { + asksave = 1; + i = searchwall; + + hitscan(sprite[i].x,sprite[i].y,sprite[i].z,sprite[i].sectnum, + sintable[(sprite[i].ang+2560+1024)&2047], + sintable[(sprite[i].ang+2048+1024)&2047], + 0, + &hitsect,&hitwall,&hitsprite,&hitx,&hity,&hitz,CLIPMASK1); + + sprite[i].x = hitx; + sprite[i].y = hity; + sprite[i].z = hitz; + changespritesect(i,hitsect); + if (hitwall >= 0) + sprite[i].ang = ((getangle(wall[wall[hitwall].point2].x-wall[hitwall].x,wall[wall[hitwall].point2].y-wall[hitwall].y)+512)&2047); + + /* Make sure sprite's in right sector */ + if (inside(sprite[i].x,sprite[i].y,sprite[i].sectnum) == 0) + { + j = wall[hitwall].point2; + sprite[i].x -= ksgn(wall[j].y-wall[hitwall].y); + sprite[i].y += ksgn(wall[j].x-wall[hitwall].x); + } + } + keystatus[0x18] = 0; + } + if (keystatus[0x32] > 0) /* M (masking walls) */ + { + if (searchstat != 3) + { + i = wall[searchwall].nextwall; + templong = (keystatus[0x2a]|keystatus[0x36]); + if (i >= 0) + { + wall[searchwall].cstat ^= 16; + if ((wall[searchwall].cstat&16) > 0) + { + wall[searchwall].cstat &= ~8; + if (templong == 0) + { + wall[i].cstat |= 8; /* auto other-side flip */ + wall[i].cstat |= 16; + wall[i].overpicnum = wall[searchwall].overpicnum; + } + } + else + { + wall[searchwall].cstat &= ~8; + if (templong == 0) + { + wall[i].cstat &= ~8; /* auto other-side unflip */ + wall[i].cstat &= ~16; + } + } + wall[searchwall].cstat &= ~32; + if (templong == 0) wall[i].cstat &= ~32; + asksave = 1; + } + } + keystatus[0x32] = 0; + } + if (keystatus[0x23] > 0) /* H (hitscan sensitivity) */ + { + if (searchstat == 3) + { + sprite[searchwall].cstat ^= 256; + asksave = 1; + } + else + { + wall[searchwall].cstat ^= 64; + if ((wall[searchwall].nextwall >= 0) && ((keystatus[0x2a]|keystatus[0x36]) == 0)) + { + wall[wall[searchwall].nextwall].cstat &= ~64; + wall[wall[searchwall].nextwall].cstat |= (wall[searchwall].cstat&64); + } + asksave = 1; + } + keystatus[0x23] = 0; + } + if (keystatus[0x12] > 0) /* E (expand) */ + { + if (searchstat == 1) + { + sector[searchsector].ceilingstat ^= 8; + asksave = 1; + } + if (searchstat == 2) + { + sector[searchsector].floorstat ^= 8; + asksave = 1; + } + keystatus[0x12] = 0; + } + if (keystatus[0x13] > 0) /* R (relative alignment, rotation) */ + { + if (searchstat == 1) + { + sector[searchsector].ceilingstat ^= 64; + asksave = 1; + } + if (searchstat == 2) + { + sector[searchsector].floorstat ^= 64; + asksave = 1; + } + if (searchstat == 3) + { + i = sprite[searchwall].cstat; + if ((i&48) < 32) i += 16; else i &= ~48; + sprite[searchwall].cstat = i; + asksave = 1; + } + keystatus[0x13] = 0; + } + if (keystatus[0x21] > 0) /* F (Flip) */ + { + keystatus[0x21] = 0; + if ((keystatus[0x38]|keystatus[0xb8]) > 0) /* ALT-F (relative alignmment flip) */ + { + if (searchstat != 3) + { + setfirstwall(searchsector,searchwall); + asksave = 1; + } + } + else + { + if ((searchstat == 0) || (searchstat == 4)) + { + i = wall[searchwall].cstat; + i = ((i>>3)&1)+((i>>7)&2); /* 3-x,8-y */ + switch(i) + { + case 0: i = 1; break; + case 1: i = 3; break; + case 2: i = 0; break; + case 3: i = 2; break; + } + i = ((i&1)<<3)+((i&2)<<7); + wall[searchwall].cstat &= ~0x0108; + wall[searchwall].cstat |= i; + asksave = 1; + } + if (searchstat == 1) /* 8-way ceiling flipping (bits 2,4,5) */ + { + i = sector[searchsector].ceilingstat; + i = (i&0x4)+((i>>4)&3); + switch(i) + { + case 0: i = 6; break; + case 6: i = 3; break; + case 3: i = 5; break; + case 5: i = 1; break; + case 1: i = 7; break; + case 7: i = 2; break; + case 2: i = 4; break; + case 4: i = 0; break; + } + i = (i&0x4)+((i&3)<<4); + sector[searchsector].ceilingstat &= ~0x34; + sector[searchsector].ceilingstat |= i; + asksave = 1; + } + if (searchstat == 2) /* 8-way floor flipping (bits 2,4,5) */ + { + i = sector[searchsector].floorstat; + i = (i&0x4)+((i>>4)&3); + switch(i) + { + case 0: i = 6; break; + case 6: i = 3; break; + case 3: i = 5; break; + case 5: i = 1; break; + case 1: i = 7; break; + case 7: i = 2; break; + case 2: i = 4; break; + case 4: i = 0; break; + } + i = (i&0x4)+((i&3)<<4); + sector[searchsector].floorstat &= ~0x34; + sector[searchsector].floorstat |= i; + asksave = 1; + } + if (searchstat == 3) + { + i = sprite[searchwall].cstat; + if (((i&48) == 32) && ((i&64) == 0)) + { + sprite[searchwall].cstat &= ~0xc; + sprite[searchwall].cstat |= ((i&4)^4); + } + else + { + i = ((i>>2)&3); + switch(i) + { + case 0: i = 1; break; + case 1: i = 3; break; + case 2: i = 0; break; + case 3: i = 2; break; + } + i <<= 2; + sprite[searchwall].cstat &= ~0xc; + sprite[searchwall].cstat |= i; + } + asksave = 1; + } + } + } + if (keystatus[0x1f] > 0) /* S (insert sprite) (3D) */ + { + dax = 16384; + day = divscale14(searchx-(xdim>>1),xdim>>1); + rotatepoint(0,0,dax,day,ang,&dax,&day); + + hitscan(posx,posy,posz,cursectnum, /* Start position */ + dax,day,(scale(searchy,200,ydim)-horiz)*2000, /* vector of 3D ang */ + &hitsect,&hitwall,&hitsprite,&hitx,&hity,&hitz,CLIPMASK1); + + if (hitsect >= 0) + { + dax = hitx; + day = hity; + if ((gridlock > 0) && (grid > 0)) + { + if ((searchstat == 0) || (searchstat == 4)) + { + hitz = (hitz&0xfffffc00); + } + else + { + dax = ((dax+(1024>>grid))&(0xffffffff<<(11-grid))); + day = ((day+(1024>>grid))&(0xffffffff<<(11-grid))); + } + } + + i = insertsprite(hitsect,0); + sprite[i].x = dax, sprite[i].y = day; + sprite[i].cstat = defaultspritecstat; + sprite[i].shade = 0; + sprite[i].pal = 0; + sprite[i].xrepeat = 64, sprite[i].yrepeat = 64; + sprite[i].xoffset = 0, sprite[i].yoffset = 0; + sprite[i].ang = 1536; + sprite[i].xvel = 0; sprite[i].yvel = 0; sprite[i].zvel = 0; + sprite[i].owner = -1; + sprite[i].clipdist = 32; + sprite[i].lotag = 0; + sprite[i].hitag = 0; + sprite[i].extra = -1; + + for(k=0;k localartfreq[j]) + j = k; + if (localartfreq[j] > 0) + sprite[i].picnum = j; + else + sprite[i].picnum = 0; + + if (somethingintab == 3) + { + sprite[i].picnum = temppicnum; + if ((tilesizx[temppicnum] <= 0) || (tilesizy[temppicnum] <= 0)) + { + j = 0; + for(k=0;k 0) && (tilesizy[k] > 0)) + { + j = k; + break; + } + sprite[i].picnum = j; + } + sprite[i].shade = tempshade; + sprite[i].pal = temppal; + sprite[i].xrepeat = tempxrepeat; + sprite[i].yrepeat = tempyrepeat; + if (sprite[i].xrepeat < 1) sprite[i].xrepeat = 1; + if (sprite[i].yrepeat < 1) sprite[i].yrepeat = 1; + sprite[i].cstat = tempcstat; + } + + j = ((tilesizy[sprite[i].picnum]*sprite[i].yrepeat)<<1); + if ((sprite[i].cstat&128) == 0) + sprite[i].z = min(max(hitz,getceilzofslope(hitsect,hitx,hity)+(j<<1)),getflorzofslope(hitsect,hitx,hity)); + else + sprite[i].z = min(max(hitz,getceilzofslope(hitsect,hitx,hity)+j),getflorzofslope(hitsect,hitx,hity)-j); + + if ((searchstat == 0) || (searchstat == 4)) + { + sprite[i].cstat |= (16+64); + if (hitwall >= 0) + sprite[i].ang = ((getangle(wall[wall[hitwall].point2].x-wall[hitwall].x,wall[wall[hitwall].point2].y-wall[hitwall].y)+512)&2047); + + /* Make sure sprite's in right sector */ + if (inside(sprite[i].x,sprite[i].y,sprite[i].sectnum) == 0) + { + j = wall[hitwall].point2; + sprite[i].x -= ksgn(wall[j].y-wall[hitwall].y); + sprite[i].y += ksgn(wall[j].x-wall[hitwall].x); + } + } + else + { + if (tilesizy[sprite[i].picnum] >= 32) sprite[i].cstat |= 1; + } + + updatenumsprites(); + asksave = 1; + } + + keystatus[0x1f] = 0; + } + if (keystatus[0xd3] > 0) + { + if (searchstat == 3) + { + deletesprite(searchwall); + updatenumsprites(); + asksave = 1; + } + keystatus[0xd3] = 0; + } + + if ((keystatus[0x3f]|keystatus[0x40]) > 0) /* F5,F6 */ + { + switch(searchstat) + { + case 1: case 2: ExtShowSectorData(searchsector); break; + case 0: case 4: ExtShowWallData(searchwall); break; + case 3: ExtShowSpriteData(searchwall); break; + } + keystatus[0x3f] = 0, keystatus[0x40] = 0; + } + if ((keystatus[0x41]|keystatus[0x42]) > 0) /* F7,F8 */ + { + switch(searchstat) + { + case 1: case 2: ExtEditSectorData(searchsector); break; + case 0: case 4: ExtEditWallData(searchwall); break; + case 3: ExtEditSpriteData(searchwall); break; + } + keystatus[0x41] = 0, keystatus[0x42] = 0; + } + + } + if (keystatus[buildkeys[14]] > 0) /* Enter */ + { + overheadeditor(); + keystatus[buildkeys[14]] = 0; + } +} + + +int main(int argc,char **argv) +{ + char ch, quitflag; + long i, j, k; + + _platform_init(argc, argv, "BUILD editor by Ken Silverman", "BUILD"); + + if (getenv("BUILD_NOPENTIUM") != NULL) + setmmxoverlay(0); + + editstatus = 1; + if (argc >= 2) + { + strcpy(boardfilename,argv[1]); + if (strchr(boardfilename,'.') == 0) + strcat(boardfilename,".map"); + } + else + strcpy(boardfilename,"newboard.map"); + + ExtInit(); + _initkeys(); + inittimer(); + + loadpics("tiles000.art"); + loadnames(); + + strcpy(kensig,"BUILD by Ken Silverman"); + initcrc(); + + if (setgamemode(vidoption,xdim,ydim) < 0) + { + ExtUnInit(); + uninitkeys(); + uninittimer(); + printf("%ld * %ld not supported in this graphics mode\n",xdim,ydim); + exit(0); + } + + k = 0; + for(i=0;i<256;i++) + { + j = ((long)palette[i*3])+((long)palette[i*3+1])+((long)palette[i*3+2]); + if (j > k) { k = j; whitecol = i; } + } + + initmenupaths(argv[0]); + menunamecnt = 0; + menuhighlight = 0; + + for(i=0;i 0) + { + keystatus[1] = 0; + printext256(0,0,whitecol,0,"Really want to quit?",0); + nextpage(); + synctics = totalclock-lockclock; + lockclock += synctics; + + while ((keystatus[1]|keystatus[0x1c]|keystatus[0x39]|keystatus[0x31]) == 0) + { + /* + * rcg08212000 Rewrote this to prompt for changes in + * graphics mode, rather than through stdio later. + */ + _idle(); + + if (keystatus[0x15] != 0) + { + keystatus[0x15] = 0; + quitflag = 1; + if (asksave) + { + asksave = 0; + printext256(0,0,whitecol,0,"Save changes? ",0); + nextpage(); + + while ((keystatus[0x15]|keystatus[0x31]) == 0) + _idle(); + + if (keystatus[0x15]) /* 'y' pressed. */ + { + updatesector(startposx,startposy,&startsectnum); + saveboard(boardfilename,&startposx,&startposy,&startposz,&startang,&startsectnum); + ExtSaveMap(boardfilename); + } /* if */ + } /* if */ + break; + } /* if */ + } + } + } + uninittimer(); + uninitkeys(); + ExtUnInit(); + uninitengine(); + setvmode(0x3); + + if (asksave) + { + printf("Save changes?\n"); + do + { + ch = getchar(); + } + while ((ch != 'y') && (ch != 'Y') && (ch != 'n') && (ch != 'N')); + if ((ch == 'y') || (ch == 'Y')) + { + updatesector(startposx,startposy,&startsectnum); + saveboard(boardfilename,&startposx,&startposy,&startposz,&startang,&startsectnum); + ExtSaveMap(boardfilename); + } + } + printf("Memory status: %ld(%ld) bytes\n",cachesize,artsize); + printf("%s\n",kensig); + printf("%s\n",PORTSIG); + return(0); +} + +/* end of build.c ... */ + diff --git a/buildengine/build.h b/buildengine/build.h new file mode 100755 index 0000000..20ae107 --- /dev/null +++ b/buildengine/build.h @@ -0,0 +1,314 @@ +/* + * "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman + * Ken Silverman's official web site: "http://www.advsys.net/ken" + * See the included license file "BUILDLIC.TXT" for license info. + * This file has been modified from Ken Silverman's original release + */ + +#ifndef _INCLUDE_BUILD_H_ +#define _INCLUDE_BUILD_H_ + +#define MAXSECTORS 1024 +#define MAXWALLS 8192 +#define MAXSPRITES 4096 + +#define MAXTILES 9216 +#define MAXSTATUS 1024 +#define MAXPLAYERS 16 +#define MAXXDIM 1600 +#define MAXYDIM 1200 +#define MAXPALOOKUPS 256 +#define MAXPSKYTILES 256 +#define MAXSPRITESONSCREEN 1024 + +#define CLIPMASK0 (((1L)<<16)+1L) +#define CLIPMASK1 (((256L)<<16)+64L) + + + /* + * Make all variables in BUILD.H defined in the ENGINE, + * and externed in GAME + * (dear lord. --ryan.) + */ +#ifdef ENGINE + #define EXTERN +#else + #define EXTERN extern +#endif + + +#ifdef PLATFORM_DOS +#pragma pack(push,1); +#else +#pragma pack(1) +#endif + +/* + * ceilingstat/floorstat: + * bit 0: 1 = parallaxing, 0 = not "P" + * bit 1: 1 = groudraw, 0 = not + * bit 2: 1 = swap x&y, 0 = not "F" + * bit 3: 1 = double smooshiness "E" + * bit 4: 1 = x-flip "F" + * bit 5: 1 = y-flip "F" + * bit 6: 1 = Align texture to first wall of sector "R" + * bits 7-8: "T" + * 00 = normal floors + * 01 = masked floors + * 10 = transluscent masked floors + * 11 = reverse transluscent masked floors + * bits 9-15: reserved + */ + + /* 40 bytes */ +typedef struct +{ + short wallptr, wallnum; + long ceilingz, floorz; + short ceilingstat, floorstat; + short ceilingpicnum, ceilingheinum; + signed char ceilingshade; + unsigned char ceilingpal, ceilingxpanning, ceilingypanning; + short floorpicnum, floorheinum; + signed char floorshade; + unsigned char floorpal, floorxpanning, floorypanning; + unsigned char visibility, filler; + short lotag, hitag, extra; +} sectortype; + +/* + * cstat: + * bit 0: 1 = Blocking wall (use with clipmove, getzrange) "B" + * bit 1: 1 = bottoms of invisible walls swapped, 0 = not "2" + * bit 2: 1 = align picture on bottom (for doors), 0 = top "O" + * bit 3: 1 = x-flipped, 0 = normal "F" + * bit 4: 1 = masking wall, 0 = not "M" + * bit 5: 1 = 1-way wall, 0 = not "1" + * bit 6: 1 = Blocking wall (use with hitscan / cliptype 1) "H" + * bit 7: 1 = Transluscence, 0 = not "T" + * bit 8: 1 = y-flipped, 0 = normal "F" + * bit 9: 1 = Transluscence reversing, 0 = normal "T" + * bits 10-15: reserved + */ + + /* 32 bytes */ +typedef struct +{ + long x, y; + short point2, nextwall, nextsector, cstat; + short picnum, overpicnum; + signed char shade; + char pal, xrepeat, yrepeat, xpanning, ypanning; + short lotag, hitag, extra; +} walltype; + + +/* + * cstat: + * bit 0: 1 = Blocking sprite (use with clipmove, getzrange) "B" + * bit 1: 1 = transluscence, 0 = normal "T" + * bit 2: 1 = x-flipped, 0 = normal "F" + * bit 3: 1 = y-flipped, 0 = normal "F" + * bits 5-4: 00 = FACE sprite (default) "R" + * 01 = WALL sprite (like masked walls) + * 10 = FLOOR sprite (parallel to ceilings&floors) + * bit 6: 1 = 1-sided sprite, 0 = normal "1" + * bit 7: 1 = Real centered centering, 0 = foot center "C" + * bit 8: 1 = Blocking sprite (use with hitscan / cliptype 1) "H" + * bit 9: 1 = Transluscence reversing, 0 = normal "T" + * bits 10-14: reserved + * bit 15: 1 = Invisible sprite, 0 = not invisible + */ + + /* 44 bytes */ +typedef struct +{ + long x, y, z; + short cstat, picnum; + signed char shade; + unsigned char pal, clipdist, filler; + unsigned char xrepeat, yrepeat; + signed char xoffset, yoffset; + short sectnum, statnum; + short ang, owner, xvel, yvel, zvel; + short lotag, hitag, extra; +} spritetype; + +#ifdef PLATFORM_DOS +#pragma pack(pop); +#else +#pragma pack() +#endif + +EXTERN sectortype sector[MAXSECTORS]; +EXTERN walltype wall[MAXWALLS]; +EXTERN spritetype sprite[MAXSPRITES]; + +EXTERN long spritesortcnt; +EXTERN spritetype tsprite[MAXSPRITESONSCREEN]; + +EXTERN char vidoption; +EXTERN long xdim, ydim, ylookup[MAXYDIM+1], numpages; +EXTERN long yxaspect, viewingrange; + +EXTERN long validmodecnt; +EXTERN short validmode[256]; +EXTERN long validmodexdim[256], validmodeydim[256]; + +EXTERN short numsectors, numwalls; +EXTERN volatile long totalclock; +EXTERN long numframes, randomseed; +EXTERN short sintable[2048]; +EXTERN unsigned char palette[768]; +EXTERN short numpalookups; +EXTERN char *palookup[MAXPALOOKUPS]; +EXTERN char parallaxtype, showinvisibility; +EXTERN long parallaxyoffs, parallaxyscale; +EXTERN long visibility, parallaxvisibility; + +EXTERN long windowx1, windowy1, windowx2, windowy2; +EXTERN short startumost[MAXXDIM], startdmost[MAXXDIM]; + +EXTERN short pskyoff[MAXPSKYTILES], pskybits; + +EXTERN short headspritesect[MAXSECTORS+1], headspritestat[MAXSTATUS+1]; +EXTERN short prevspritesect[MAXSPRITES], prevspritestat[MAXSPRITES]; +EXTERN short nextspritesect[MAXSPRITES], nextspritestat[MAXSPRITES]; + +EXTERN short tilesizx[MAXTILES], tilesizy[MAXTILES]; +EXTERN char walock[MAXTILES]; +EXTERN long numtiles, picanm[MAXTILES], waloff[MAXTILES]; + + /* + * These variables are for auto-mapping with the draw2dscreen function. + * When you load a new board, these bits are all set to 0 - since + * you haven't mapped out anything yet. Note that these arrays are + * bit-mapped. + * If you want draw2dscreen() to show sprite #54 then you say: + * spritenum = 54; + * show2dsprite[spritenum>>3] |= (1<<(spritenum&7)); + * And if you want draw2dscreen() to not show sprite #54 then you say: + * spritenum = 54; + * show2dsprite[spritenum>>3] &= ~(1<<(spritenum&7)); + * Automapping defaults to 0 (do nothing). If you set automapping to 1, + * then in 3D mode, the walls and sprites that you see will show up the + * next time you flip to 2D mode. + */ +EXTERN char show2dsector[(MAXSECTORS+7)>>3]; +EXTERN char show2dwall[(MAXWALLS+7)>>3]; +EXTERN char show2dsprite[(MAXSPRITES+7)>>3]; +EXTERN char automapping; + +EXTERN char gotpic[(MAXTILES+7)>>3]; +EXTERN char gotsector[(MAXSECTORS+7)>>3]; + +/************************************************************************* +POSITION VARIABLES: + + POSX is your x - position ranging from 0 to 65535 + POSY is your y - position ranging from 0 to 65535 + (the length of a side of the grid in EDITBORD would be 1024) + POSZ is your z - position (height) ranging from 0 to 65535, 0 highest. + ANG is your angle ranging from 0 to 2047. Instead of 360 degrees, or + 2 * PI radians, I use 2048 different angles, so 90 degrees would + be 512 in my system. + +SPRITE VARIABLES: + + EXTERN short headspritesect[MAXSECTORS+1], headspritestat[MAXSTATUS+1]; + EXTERN short prevspritesect[MAXSPRITES], prevspritestat[MAXSPRITES]; + EXTERN short nextspritesect[MAXSPRITES], nextspritestat[MAXSPRITES]; + + Example: if the linked lists look like the following: + ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ + ³ Sector lists: Status lists: ³ + ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ + ³ Sector0: 4, 5, 8 Status0: 2, 0, 8 ³ + ³ Sector1: 16, 2, 0, 7 Status1: 4, 5, 16, 7, 3, 9 ³ + ³ Sector2: 3, 9 ³ + ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ + Notice that each number listed above is shown exactly once on both the + left and right side. This is because any sprite that exists must + be in some sector, and must have some kind of status that you define. + + +Coding example #1: + To go through all the sprites in sector 1, the code can look like this: + + sectnum = 1; + i = headspritesect[sectnum]; + while (i != -1) + { + nexti = nextspritesect[i]; + + //your code goes here + //ex: printf("Sprite %d is in sector %d\n",i,sectnum); + + i = nexti; + } + +Coding example #2: + To go through all sprites with status = 1, the code can look like this: + + statnum = 1; //status 1 + i = headspritestat[statnum]; + while (i != -1) + { + nexti = nextspritestat[i]; + + //your code goes here + //ex: printf("Sprite %d has a status of 1 (active)\n",i,statnum); + + i = nexti; + } + + insertsprite(short sectnum, short statnum); + deletesprite(short spritenum); + changespritesect(short spritenum, short newsectnum); + changespritestat(short spritenum, short newstatnum); + +TILE VARIABLES: + NUMTILES - the number of tiles found TILES.DAT. + TILESIZX[MAXTILES] - simply the x-dimension of the tile number. + TILESIZY[MAXTILES] - simply the y-dimension of the tile number. + WALOFF[MAXTILES] - the actual 32-bit offset pointing to the top-left + corner of the tile. + PICANM[MAXTILES] - flags for animating the tile. + +TIMING VARIABLES: + TOTALCLOCK - When the engine is initialized, TOTALCLOCK is set to zero. + From then on, it is incremented 120 times a second by 1. That + means that the number of seconds elapsed is totalclock / 120. + NUMFRAMES - The number of times the draw3dscreen function was called + since the engine was initialized. This helps to determine frame + rate. (Frame rate = numframes * 120 / totalclock.) + +OTHER VARIABLES: + + STARTUMOST[320] is an array of the highest y-coordinates on each column + that my engine is allowed to write to. You need to set it only + once. + STARTDMOST[320] is an array of the lowest y-coordinates on each column + that my engine is allowed to write to. You need to set it only + once. + SINTABLE[2048] is a sin table with 2048 angles rather than the + normal 360 angles for higher precision. Also since SINTABLE is in + all integers, the range is multiplied by 16383, so instead of the + normal -1 = This key attempts to match up all the tiles along a wall. It + scans along the walls towards the right as long as the picture + number of the next wall is the same as the original picture + number. Note that some walls may not work right, especially + floor / ceiling steps. + + F = Flip an object. For sprites and walls, this flips the object + x-wise. For ceilings and floors, the objects are flipped in + 8 possible ways. Just keep pressing 'F' to go through + the 8 ways. + ALT-F = When you use relative alignment mode on ceiling and floor + textures, you can press Alt-F on the ceiling or floor to + choose a new wall to align to. It actually rotates the walls + of a sector by 1. + O = Wall orientation (whether it starts from the top or bottom) + Normally, walls are oriented from the top. For example, if + you hold down 2/8 on the keypad in 3D EDIT MODE, the wall + always starts from the top. Orientation works differently + for white lines and red lines, so if a wall doesn't look + right, just press 'O' anyway to see if it get fixed. + +COPY & PASTE + TAB = COPY. Copy the attibutes of the highlighted objects into a + temporary place. The attributes it remembers are: + tile, shade, x-repeat, y-repeat, and cstat values. + Left ENTER = PASTE. Paste the stored attributes over the highlighted + object. Whenever you press ENTER, the y-repeat values stay + the same, and the x-repeat values are adjusted so the pixels + of the bitmaps have a square-aspect ratio. +Ctrl+L.ENTER = Left ENTER with the ctrl key will paste the attribtues to + every wall in a loop (if a wall is highlighted). +Shft+L.ENTER = Left ENTER with the shift key also pressed copies the shade + only. +Ctrl+Shft+L.ENTER = Auto-shade a sector. First make any wall of the loop + as light as the lightest shade you want. Then make any other + wall of the loop as dark as the darkest shade you want. + Finally press Ctrl-Shift Enter on the wall that should be + lightest. Now the loop should be smoothly shaded. If it + is not smoothly shaded, you may need to insert more points + on the walls. + +SECTOR FLAGS: + + P = Make the ceiling of the given sector have a Parallaxing sky + or just a normal ceiling. + G = Make the floor of the given sector have a Groudraw + (floor with height mapping). I do not recommend using this + attribute very extensively yet. (See the H key for selecting + the height map) + E = An option for ceilings and floors. If for some reason, you + want a tile to be smooshed into the normal 64*64 area, press + E to unExpand the tile. Press E again, and the tile will be + expanded, so the pixel size is the same as the normal 64*64 + ceiling/floor. + R = Relative alignment - switch between relative alignment mode + and normal mode. Allows floor / ceiling textures to align + to the first 2 points of a sector. Textures will rotate/pan + with moving sectors properly. Notice that bit 6 of both + sector[].ceilingstat and sector[].floorstat are relative + alignment bits. + +WALL FLAGS: + + B = Make an invisible wall, such as a window, block you from + going through. Since the wall is invisible, you can also + highlight the ceiling right above the window or floor + right below the window. You can block either the front or + the back of the window. If you block the back only, you + will be able to go onto the window sill. + T = Press to make a maskable wall 50/50 transluscent. Press T + again to put the masked wall back to normal mode. + M = Make a maskable wall. Press in the same place you press 'B'. + The masking wall takes all its attributes from the front of + the wall, so it must have the same repeat, panning, and cstat + values as the walls above or below it (if you have a step). + The masking picture number is stored in overpicnum. Also, + the masking walls is also automatically added the the other + side of the wall, with the picture flipped. (see the 'F' + key descripte above) + Shift + M = Make a maskable wall just like 'M' described above, but only + on the front side. + + 1 = Make a 1-way wall. + 2 = Some walls have two different sections. One step on the + ceiling and one step on the floor. Normally they always + have the same attributes. It is possible though, to give + both the top and bottom different attributes by pressing 2 on + that wall. 2 simply makes the bottom wall's attributes + separately editable. Press 2 on either the top or bottom + wall. + O = Wall orientation (whether it starts from the top or bottom) + Normally, walls are oriented from the top. For example, if + you hold down 2/8 on the keypad in 3D EDIT MODE, the wall + always starts from the top. Orientation works differently + for white lines and red lines, so if a wall doesn't look + right, just press 'O' anyway to see if it get fixed. + H = Toggle hitscan pass through bit. Default is pass through. + +SPRITE FLAGS: + + B = When the mouse cursor is on a sprite, this makes a sprite + block you from walking through. Also makes the sprite + sensitive to hitscan. Sprites with the 'B' attribute will + appear pink in 2D EDIT MODE + T = Press to make a sprite 50/50 transluscent. Press T again + to put sprite back to normal mode. + +ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ +³ 2D EDIT MODE KEYS: ³ +ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ + ESC = Show a menu that says, "(N)ew, (L)oad, (S)ave, (Q)uit" + Press ESC again to cancel the menu. + keypad ENTER = Flip back to the 3D edit mode + + Mouse = Move mouse cursor + Left mouse button = If you hold down the left mouse button, you can drag + existing points. To drag multiple points you can use + the right shift key to first select a rectangular + region of points to highlight, then just drag any of + the highlighted points and the rest move with it. +Right mouse button = Moves the player's positions to the mouse cursor. + This is useful when you accidently get stuck somewhere + in the board, or when you need to edit some part of + a sector that is hard to access. + Right Shift = Select a bunch of points for use with dragging around. + Selects all points inside a box. (Use the left mouse + button to drag) + Ctrl+Right Shift = Select a bunch of points for use with dragging around. + Selects all points on a loop. (Use the left mouse + button to drag) + Right Alt = Select a bunch of sectors for either duplication or + dragging around. (see left mouse button for + dragging and the insert key for duplication). + + Arrows = Move player position in the appropriate directions. + The player will be clipped. To jump to a different part + of the board, use the right mouse button. + Space = Press the space bar when drawing new sectors. There + are several ways of drawing new sectors. The following + three ways of drawing sectors can all be done by only + using the space bar. The computer is smart enough to + decide which method you are using. + + 1. Drawing a FULL LOOP - that is, whenever the new + sector meets the old sector, draw over that line + again. In full loop mode the new sector must not + already be in another sector. The loop is done + when you press the space bar at the first point + again. + 2. SPLITTING a sector - press space bar to draw points + at which you want to split a sector. The computer + knows you are done splitting when you end at + another point that's on the edge of the sector you + are splitting. + 3. Drawing a sector COMPLETELY INSIDE another sector. + (for example, columns) To do this, just press space + bar at every point in the loop. The loop is done + when you press the space bar at the first point + again. + Backspace = When plotting points with the space bar, you can use + backspace to get rid of the last point plotted. You + can press the backspace to get rid of all the points + if you didn't want to start a sector at all. + + Insert = Inserts a new point at the midpoint of the highlighted + line. Then you can drag the point to wherever you like. + (If you insert on a red line, the point will be inserted + on both sides of the sector line.) + If a bunch of sectors are selected (see right ALT) then + instead of inserted points, the selected sector bunch + will be duplicated (stamped). Don't forget to drag + the selected sectors after stamping. + + Delete = Use this to delete sprites (blue circles). To delete + points of a sector border, don't press delete. Instead, + drag the point into one of its 2 neighbor points on the + sector. This is easist done if grid locking is on + (mouse cursor is pink). If 2 neighbor points are equal, + one will automatically be deleted. + Right Ctrl-Delete = This deletes the whole sector that the mouse cursor is + in. Note the right ctrl for protection. + (Note: to delete a point of a sector, just drag that point into the next + point and it will automatically be deleted. You should do this with + grid-locking on) + J = Use to join two neighboring sectors. Press J when mouse + cursor is over the first sector. Then press J again + when the mouse cursor is over the neighboring sector. + The attributes of the combined sector will be taken from + the first sector selected. + ALT-S = When you have a white loop inside a sector, you can + press ALT-S on it (highlight any of its lines) to turn + the whole loop red. + S = Places a sprite at the location under the mouse cursor. + A sprite looks like a blue circle in the overhead map. + + B = Blocks / unblocks you from going through a wall or + sprites. A blocked wall or sprite will appear pink + in 2D EDIT MODE. See the description for 'B' in + the 3D EDIT MODE section for more details. + + C = Turn a line into a circle defined by short line + segments. First press 'C' on a highlighted wall. Then + move the mouse to the right place and press '+' or '-' + if you want to change the number of points on the + circle. Press 'C' again to cancel the circle drawing or + press the Space bar to actually change the map. + +/- = Increase / Decrease the number of points on the circle. + + T = Type in a LO-tag for a sector. Move the mouse cursor to + the inside of a sector that you want to tag first. + ALT-T = Just like 'T' but for walls and sprites. + H = Type in a HI-tag for a sector. Move the mouse cursor to + the inside of a sector that you want to tag first. + ALT-H = Just like 'H' but for walls and sprites. + E = Change a sprite's status list number. + < and > = Changes angle of sprite. Move the mouse cursor to a + sprite first. You can hold down shift with the < and > + to get more precise angles. If you did a sector + highlight, then the selected sector will be rotated + instead. + CTRL-T = Turn tag boxes on/off. + + TAB = Move the mouse cursor to the inside of a sector that you + you want to see the attributes of. It will show them + at the bottom of the status bar. To clear it, press + TAB again at somewhere in the board that is not part + of any sector. This is a useful key for debugging. + ALT-TAB = Works just like TAB, but here, you can see the + attributes of highlighted walls or sprites. For red + lines, the side the mouse cursor is on the line affects + which line is highlighted, since red lines are actually + defined as 2 walls (1 wall for each sector). + + Scroll Lock = Set starting position (brown arrow) to your current + position (white arrow). + + A,Z = Zoom in and out. This is useful for choosing whether + you want to edit finely or not. + G = Change grid resolution. The grid resolution cycles + through this sequence: + (off, 1x, 2x, 4x (default), 8x, 16x) + L = Turns grid locking on or off. If the mouse cursor is + pink then grid locking is on. If it is white then + grid locking is off. There is no grid locking + if the grid is turned off. Also, grid locking will + lock to nearby points. + +ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ +³ EDITART KEYS: ³ +ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ + + ---- Keys you will need to know if you want to select from a section of + a 320*200*256 picture file (.BMP and .PCX only) and put it into the BUILD + engine. + + U - Use this to import a section of a 320*200*256 .BMP, .PCX, or .GIF. + ³ Enter - Convert the image that is inside the rectangular selection + ³ rectangle to the BUILD palette. + ³ Space - Convert the image that is inside the rectangular selection + ³ rectangle without remapping the palette. + ³ P - If in the picture selecting screen (after pressing U and loading + ³ the picture), you press P, then the palette of BUILD can be + ÀÄÄ replaced by the palette of the displayed picture. + PGUP/PGDN - Select tile to edit (4096 tile maximum right now). + G - GOTO a tile by typing in the tile number. + S - Re-size tile. The X and Y sizes can be any unsigned short integer. + X ranges from 0 to 1024, and Y ranges from 0 to 240. + Delete - short cut key to set both the X and Y sizes to 0. + +,- Change the animation setting. (Default: NoAnm = 0.) + To change the animation type, press - when the value is 0. + Ex: If you want an object to have 4 tiles of animation, you can + animate it in 4 different sequences: (0 is the current tile) + NoAnm=4 sequence: 0,0,0,0,0,0,0,0,0,0,0,... (no animation) + Oscis=4 sequence: 0,1,2,3,2,1,0,1,2,3,2,... (oscillate) + AnmFD=4 sequence: 0,1,2,3,0,1,2,3,0,1,2,... (forwards) + AnmBK=4 sequence: 0,-1,-2,-3,0,-1,-2,-3,... (backwards) + A - Set the animation speed of the tile. Press + and - to change the + animation speed. There are 16 different animation speeds. The + animation speed set here set the speed for BUILD and your GAME also. + (Speed is proportional to (totalclock>>animspeed)) + ~' - This key (located just above the TAB key) allows you to center a + sprite. Simply use the arrow keys to get to the desired position. + N - Name a tile. Naming a tile simply changes the #define statement in + NAMES.H. You should include NAMES.H when compiling so you can easily + refer to sprites by name rather than by number. + O - Optimize the size of an individual piece of artwork. Use this for + tiles with invisible pixels on the sides. + V - View and select a tile to edit. + ³ Space - To swap 2 tiles simply press space bar on the first tile, + ³ then space bar on the second. + ³ 1,2,3 - To swap a group of tiles, press 1 on the first tile, + ³ press 2 to remember the region between where you pressed + ³ 1 and 2. Press 3 at the place to where you want to swap + ÀÄÄ all the tiles. +ALT+U- Re-grab artwork from original pictures according to the CAPFIL.TXT + file. If you press ALT-U in the main screen, everything will be + re-grabbed. If you press ALT-U in 'V' mode, then you should first + select the range by pressing '1' and '2' on the range boundaries. +ALT+R- Generate a Tile frequency report by scanning all maps in directory. + Use in 'V' mode only. +F12 - Screen capture (saves image as a *.BMP file, starting as file + name CAPTUR00.BMP and incrementing by 1 each time F12 is + pressed. + + ESC - Quit. + + + + ---- Extra features: (if you actually want to do the artwork in EDITART + or if you want to touch-up some imported art.) + + C - Change all pixels on the tile having the same color under the + graphics cursor to to selected color. + Arrows / Mouse - Move graphics cursor. + Shift + Arrows - Select color. (on bottom right corner of screen) + Space - Plot a pixel with the selected color. + T - Turn drawing trail on / off. + Tab - Select the color under the graphics cursor. + BACKSPACE - Set the color to color 255 (transparent color). + F - Floodfill a region with the current color and with the current + color as a boundary. + M,P - Use M to back up a tile into a temporary buffer in memory and P + to restore it. It may be wise to press M before a floodfill (F) + (because sometimes you miss encapsulating the region by 1 pixel, + and the whole picture gets killed, etc...) + J - Randomly plots dots of current color over any pixels having the + same color as the color under the tile cursor. + [ - Random antialias of colors in color band under graphics cursor. + ] - Non-random antialias of colors in color band under graphics cursor. + ; - 3-Dimentionalize an image. Makes colors in different rows of the + color bar either appear to stick out or stick in to the wall. + ' - 3-Dimentionalize the other way. + R - Rotate the tile in a specified direction. + + 1 - Mark the first corner of a rectangle for a copy/paste operation. + 2 - Mark the other corner of a rectangle for a copy/paste operation. + 3 - Paste the selected rectangle (Note: You must press 1 and 2 in that + order first before pressing 3. Pretty simple 1-2-3 for copy&paste) + + 4 - Flip the copied rectangular region x-wise. + 5 - Flip the copied rectangular region y-wise. + 6 - Swap the x and y coordinates of the copied rectangular region. + + ,.<> - Change the shade of the selected region. + \ - Move the cursor to the center or the tile. + | - Get the coordinates of the cursor. + +ÉÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍ» +ÌÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎ͹ +ÌÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎ͹ +ÌÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎ͹ +ÌÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎ͹ +ÌÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎ͹ +ÌÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎ͹ +ÌÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎ͹ +ÌÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎ͹ +ÈÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊͼ + +ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ +³ IMPORTANT ENGINE FUNCTIONS: ³ +ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ + +initengine(char vidoption, long xdim, long ydim) + Sets up interrupt vectors for keyboard, and initializes many variables + for the BUILD engine. You should call this once before any other + functions of the BUILD engine are used. + + vidoption can be anywhere from 0-6 + xdim,ydim can be any mode x resolution if vidoption = 0 + xdim,ydim can be any vesa resolution if vidoption = 1 + xdim,ydim must be 320*200 for any other mode. + (see graphics mode selection in my setup program) +uninitengine(); + Restores interrupt vectors for keyboard and timer, and frees + buffers. You should call this once at the end of the program + before quitting to dos. +loadboard(char *filename, long *posx, long *posy, long *posz, short *ang, short *cursectnum) + Loads the given board file into memory for the BUILD engine. + Returns -1 if file not found. If no extension is given, .MAP will + be appended to the filename. +saveboard(char *filename, long *posx, long *posy, long *posz, short *ang, short *cursectnum) + Saves the given board from memory inro the specified filename. + Returns -1 if unable to save. If no extension is given, .MAP will + be appended to the filename. +loadpics(char *filename); + Loads the given artwork file into memory for the BUILD engine. + Returns -1 if file not found. If no extension is given, .ART will + be appended to the filename. +setgamemode(); + This function sets the video mode to 320*200*256color graphics. + Since BUILD supports several different modes including mode x, + mode 13h, and other special modes, I don't expect you to write + any graphics output functions. (Soon I have all the necessary + functions) If for some reason, you use your own graphics mode, + you must call this function again before using the BUILD drawing + functions. + +drawrooms(long posx, long posy, long posz, short ang, long horiz, short cursectnum) + This function draws the 3D screen to the current drawing page, + which is not yet shown. This way, you can overwrite some things + over the 3D screen such as a gun. Be sure to call the drawmasks() + function soon after you call the drawrooms() function. To view + the screen, use the nextpage() function. The nextpage() function + should always be called sometime after each draw3dscreen() + function. +drawmasks(); + This function draws all the sprites and masked walls to the current + drawing page which is not yet shown. The reason I have the drawing + split up into these 2 routines is so you can animate just the + sprites that are about to be drawn instead of having to animate + all the sprites on the whole board. Drawrooms() prepares these + variables: spritex[], spritey[], spritepicnum[], thesprite[], + and spritesortcnt. Spritesortcnt is the number of sprites about + to be drawn to the page. To change the sprite's picnum, simply + modify the spritepicnum array If you want to change other parts + of the sprite structure, then you can use the thesprite array to + get an index to the actual sprite number. + +engineinput(); + This function allows the engine to adjust your position depending + on the status of the arrow keys, and other control keys. It + handles timing and clipping. +nextpage(); + After a screen is prepared, use this function to view the screen. + + + +!!! NOTE: qsetmode320200() doesn't exist anymore. setgamemode(), when called +!!! with width and height of 320x200 appears to be equivalent anyhow. +!!! --ryan. + +draw2dscreen(long posxe, long posye, short ange, long zoome, + short gride) + Draws the 2d screen - this function is a direct replacement + for the drawrooms() and drawmasks() functions. Be sure + to call either qsetmode640350() or qsetmode640480() + first. When switching back to 3d mode, be sure to call + qsetmode320200(). + IMPORTANT NOTES: + 1. The overwritesprite function should only be called in + 3D mode. If you do this in 2D mode, junk will be + written to the 2D screen and a crash is possible. + 2. When you switch back to 3D mode, you should call the + permanentwritesprite functions to draw the status bar, + or whatever else you have to draw. + 3. You must call the nextpage() function in both 2D and + 3D modes. +qsetmode320200(); + Set to the game mode and load palette (320*200*256) +qsetmode640350(); + Set to the 2D map mode #1 (640*350*16) +qsetmode640480(); + Set to the 2D map mode #2 (640*480*16) + +doanimations(long numtics); + This function animates anything you use setanimation for (like doors). + You should call it for every frame. Pass the number of tics (lockspeed) + as a parameter to it to tell how much everything should animate. + +kenchaintimer(void (__interrupt __far *datimerchainaddress)(), + short dachainpersecond) + This function makes the engine's timerhandler chain to another timer + handler at any specified interrupt rate. This function forces IRQ0 to + point to my engine's timerhandler. Clockspeed and totalclock will + be fixed at counting 120 per second regardless of the chaining interrupt + rate. If you call this function with a NULL pointer, then the engine's + timerhandler will not chain anymore. + + Here's how you should structure your code if you use this function: + + main() + { + initengine(); + + musicon(); //Turn music on after engine + kenchaintimer(yourtimerhandleraddress,yourtimerrate); + //When IRQ0 goes off, it will now go to + //Ken's timer handler. Then, Ken's timer + (main loop) //handler will make yourtimerhandler + //interrupt yourtimerrate times per second + + kenchaintimer(0,0); //Stop chaining BEFORE music handler dies! + musicoff(); + + uninitengine(); + } + +ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ +³ OTHER ENGINE FUNCTIONS: ³ +ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ + +overwritesprite (long thex, long they, short tilenum, + signed char shade, char orientation, char dapalnum) + + Use this function to draw any sprites that must be drawn to the screen + for every single frame, such as a gun or a menu system. + + If Bit 0 of orientation = 0: (thex, they) is top-left corner + If Bit 0 of orientation = 1: (thex, they) is middle + If Bit 1 of orientation = 0: no relation to viewing window + If Bit 1 of orientation = 1: scale and clip to viewing window + If Bit 2 of orientation = 0: normal + If Bit 2 of orientation = 1: 50/50 transluscent! + If Bit 3 of orientation = 0: normal + If Bit 3 of orientation = 1: x-flipped + If Bit 4 of orientation = 0: normal + If Bit 4 of orientation = 1: y-flipped + + * If it works at full screen, simply set bit 1 of orientation + to 1, and it should automatically scale properly! + + Use this function to write sprites over the 3d view. For example, + you can make a menu system with this function. Be sure + that you call this function for every single frame after the 3d + view is drawn or else it will be flashed on for only 1 frame. + If you want x and y to be the top left corner, set the orientation + to 0. If you want x and y to be the middle of the sprite, set the + orientation to 1. The reason I included the orienation = 1 option + is so that if you want a sprite centered and the size of the tile + changes, you don't need to recompile and guess where the new top + left corner is. Oh yeah, and I forget to mention that if shade is + greater than 32, than overwritesprite does transluscence. (Try it + out!) This function will clip the sprite to the startumost and + startdmost arrays. Dapalnum refers to a palette lookup list + (normally 0). + +rotatesprite (long sx, long sy, long z, short a, short picnum, + signed char dashade, char dapalnum, char dastat, + long cx1, long cy1, long cx2, long cy2) + (sx, sy) is the center of the sprite to draw defined as + screen coordinates shifted up by 16. + (z) is the zoom. Normal zoom is 65536. + Ex: 131072 is zoomed in 2X and 32768 is zoomed out 2X. + (a) is the angle (0 is straight up) + (picnum) is the tile number + (dashade) is 0 normally but can be any standard shade up to 31 or 63. + (dapalnum) can be from 0-255. + if ((dastat&1) == 0) - no transluscence + if ((dastat&1) != 0) - transluscence + if ((dastat&2) == 0) - don't scale to setview's viewing window + if ((dastat&2) != 0) - scale to setview's viewing window (windowx1,etc.) + if ((dastat&4) == 0) - nuttin' special + if ((dastat&4) != 0) - y-flip image + if ((dastat&8) == 0) - clip to startumost/startdmost + if ((dastat&8) != 0) - don't clip to startumost/startdmost + if ((dastat&16) == 0) - use Editart center as point passed + if ((dastat&16) != 0) - force point passed to be top-left corner + if ((dastat&32) == 0) - nuttin' special + if ((dastat&32) != 0) - use reverse transluscence + if ((dastat&64) == 0) - masked drawing (check 255's) (slower) + if ((dastat&64) != 0) - draw everything (don't check 255's) (faster) + + Note: As a special case, if both ((dastat&2) != 0) and ((dastat&8) != 0) + then rotatesprite will scale to the full screen (0,0,xdim-1,ydim-1) + rather than setview's viewing window. (windowx1,windowy1,etc.) This + case is useful for status bars, etc. + + Ex: rotatesprite(160L<<16,100L<<16,65536,totalclock<<4, + DEMOSIGN,2,50L,50L,270L,150L); + This example will draw the DEMOSIGN tile in the center of the + screen and rotate about once per second. The sprite will only + get drawn inside the rectangle from (50,50) to (270,150) + +permanentwritesprite (long thex, long they, short tilenum, signed char shade, + long cx1, long cy1, long cx2, long cy2, char dapalnum) + - Added permanentwritesprite function for status bars or other + sections of the screen that will not be overwritten by the + engine. The format of this function is like overwritesprite + except that the x and y are always top left corner, no + orientation variable, and no translucence. + The 4 last parameters (cx1, cy1) - (cx2, cy2) define a + rectangular clipping window of where permanentwritesprite + can draw to. Dapalnum refers to a palette lookup list + (normally 0). + +printext(long x, long y, char buffer[42], short tilenum, char invisiblecol); + Use this function to print text anywhere on the screen from a font + that you can create in EDITART. Please see my example font in + TILES.ART to see how I lay out the user-defined font. X ranges + from 0-319. Y ranges from 0-199. The buffer is the string to + print. Tilenum specifies which font to use. Invisiblecol tells + printext what color to draw the transparent pixels. If + invisiblecol is 255 then the transpararent pixels are still + transparent. +printnum(long x, long y, long num, short tilenum, char invisiblecol); + Printnum is a function call that will print a long integer (num) + starting at top left corner x, y. Please look at the documentation + for printext, since internally, printnum simply prepares a buffer + and calls the printext function. + +setvmode(long videomode); + If you look at the top of GAME.C, you will see something like this: + #pragma aux setvmode =\... This is how you do in-line assembler in + WATCOM C. All this function is doing is setting the video mode. +showengineinfo(); + Use this function after setting to text mode to view some statics + about the engine, such as frame rate. +resettiming(); + Resets timing, such as setting totalclock = 0. Also resets other + timers. This is for use with the showengineinfo function above. + +ksqrt(long num); returns (long)square root + A square root function optimized for integers. Use this function + only if you want to. +krand() + This simply returns a random number. You can easily set the random + seed by externing the randomseed variable as a long. This is useful + for keeping the random seed the same on multiple computers when playing + multi-player mode. + +getangle(long xvect,long yvect); returns (short)angle; + Use this function call to determine the angle between two points. + For example, if you want a monster to shoot a bullet towards you, + you would get the bullet's angle this way: + sprite[bullet].ang = getangle(posx-sprite[monst].x,posy-sprite[monst].y); + +lastwall(short point); + Use this function as a reverse function of wall[].point2. In order + to save memory, my walls are only on a single linked list. + +rotatepoint(long xpivot, long ypivot, long x, long y, + short daang, long *x2, long *y2); + This function is a very convenient and fast math helper function. + Rotate points easily with this function without having to juggle your + cosines and sines. Simply pass it: + + Input: 1. Pivot point (xpivot,ypivot) + 2. Original point (x,y) + 3. Angle to rotate (0 = nothing, 512 = 90ø CW, etc.) + Output: 4. Rotated point (*x2,*y2) + +clipmove(long *x, long *y, long *z, short *sectnum, long xvect, long yvect, + long walldist, long ceildist, long flordist, char cliptype) + Moves any object (x, y, z) in any direction at any velocity and will + make sure the object will stay a certain distance from walls (walldist) + Pass the pointers of the starting position (x, y, z). Then + pass the starting position's sector number as a pointer also. + Also these values will be modified accordingly. Pass the + direction and velocity by using a vector (xvect, yvect). + If you don't fully understand these equations, please call me. + xvect = velocity * cos(angle) + yvect = velocity * sin(angle) + Walldist tells how close the object can get to a wall. I use + 128L as my default. If you increase walldist all of a sudden + for a certain object, the object might leak through a wall, so + don't do that! + If cliptype is 0, then the clipping is normal (Use 0 to clip you + and monsters). If the cliptype is 1, then the object is clipped to + the same things that hitscan is clipped to (use 1 for all bullets). + + Clipmove can either return 0 (touched nothing) + 32768+wallnum (wall first touched) + 49152+spritenum (sprite first touched) + +getzrange(long x, long y, long z, short sectnum, + long *ceilz, long *ceilhit, + long *florz, long *florhit, + long walldist, char cliptype) + + Use this in conjunction with clipmove. This function will keep the + player from falling off cliffs when you're too close to the edge. This + function finds the highest and lowest z coordinates that your clipping + BOX can get to. It must search for all sectors (and sprites) that go + into your clipping box. This method is better than using + sector[cursectnum].ceilingz and sector[cursectnum].floorz because this + searches the whole clipping box for objects, not just 1 point. + Pass x, y, z, sector normally. Walldist can be 128. Cliptype can be + 0, 1, or 2. (just like movesprite and clipmove) This function returns + the z extents in ceilz and florz. It will return the object hit in ceilhit + and florhit. + Ceilhit and florhit will also be either: + 16384+sector (sector first touched) or + 49152+spritenum (sprite first touched) + +updatesector(long x, long y, §num); + This function updates the sector number according to the x and y values + passed to it. Be careful when you use this function with sprites because + remember that the sprite's sector number should not be modified directly. + If you want to update a sprite's sector, I recomment using the setsprite + function described below. + +inside(long x, long y, short sectnum); + Tests to see whether the overhead point (x, y) is inside sector (sectnum) + Returns either 0 or 1, where 1 means it is inside, and 0 means it is not. + +copytilepiece(long tilenume1, long sourcex1, long sourcey1, + long xsiz, long ysiz, + long tilenume2, long destx1, long desty1) + + This function simply copies any section of a source tile + to any part of a destination tile. It will automatically + skip transparent pixels. It will wrap-around in the + source but not the destination. If for some reason + the destination tile gets removed from the cache, the + destination tile will be reset to original form. This + is why I had to add this second function: + +allocatepermanenttile(short tilenume, long xsiz, long ysiz) + This function allocates a place on the cache as permanent. + Right now, I reset the cache every time you call this + function so I would recommend calling this function + right after loadpics. + +makepalookup(long palnum, char *remapbuf, + signed char r, signed char g, signed char b, + char dastat) + This function allows different shirt colors for sprites. First prepare + remapbuf, which is a 256 byte buffer of chars which the colors to remap. + Palnum can be anywhere from 1-15. Since 0 is where the normal palette is + stored, it is a bad idea to call this function with palnum=0. + In BUILD.H notice I added a new variable, spritepal[MAXSPRITES]. + Usually the value of this is 0 for the default palette. But if you + change it to the palnum in the code between drawrooms() and drawmasks + then the sprite will be drawn with that remapped palette. The last 3 + parameters are the color that the palette fades to as you get further + away. This color is normally black (0,0,0). White would be (63,63,63). + if ((dastat&1) == 0) then makepalookup will allocate & deallocate + the memory block for use but will not waste the time creating a palookup + table (assuming you will create one yourself) + +copytilepiece(long walnume1, long x1, long y1, long xsiz, long ysiz, + long walnume2, long x2, long y2, char shadeoffs); + Copies section of tile 1 (walnume1) with top-left corner (x1,y1) and + rectangular size (xsiz, ysiz) to top-left corner (x2, y2) of tile 2 + (walnume). You can animate tiles with this function. For example, with + this function, you can make a slot machine like in Ken's Labyrinth or an + electronic sign with text sliding from right to left. + +loadtile(short tilenume); + This function will load the tile, tilenum, into the artwork cache. A + tile is not in the cache if (waloff[tilenum] == -1). If + (waloff[tilenum] >= 0) then it is in the cache, and you don't need to call + this function. + +precache(); + This function will go through the tilenums of all sectors, walls, and + sprites and call loadtile() on them. This function will not cache in some + tiles of animations since their tilenums may not all be in the structures. + +hitscan(long xstart, long ystart, long zstart, short startsectnum, + long vectorx, long vectory, long vectorz, + short *hitsect, short *hitwall, short *hitsprite, + long *hitx, long *hity, long *hitz); + + Pass the starting 3D position: + (xstart, ystart, zstart, startsectnum) + Then pass the 3D angle to shoot (defined as a 3D vector): + (vectorx, vectory, vectorz) + Then set up the return values for the object hit: + (hitsect, hitwall, hitsprite) + and the exact 3D point where the ray hits: + (hitx, hity, hitz) + + How to determine what was hit: + * Hitsect is always equal to the sector that was hit (always >= 0). + + * If the ray hits a sprite then: + hitsect = thesectornumber + hitsprite = thespritenumber + hitwall = -1 + + * If the ray hits a wall then: + hitsect = thesectornumber + hitsprite = -1 + hitwall = thewallnumber + + * If the ray hits the ceiling of a sector then: + hitsect = thesectornumber + hitsprite = -1 + hitwall = -1 + vectorz < 0 + (If vectorz < 0 then you're shooting upward which means + that you couldn't have hit a floor) + + * If the ray hits the floor of a sector then: + hitsect = thesectornumber + hitsprite = -1 + hitwall = -1 + vectorz > 0 + (If vectorz > 0 then you're shooting downard which means + that you couldn't have hit a ceiling) + +neartag(long x, long y, long z, short sectnum, short ang, //Starting position & angle + short *neartagsector, //Returns near sector if sector[].tag != 0 + short *neartagwall, //Returns near wall if wall[].tag != 0 + short *neartagsprite, //Returns near sprite if sprite[].tag != 0 + long *neartaghitdist, //Returns actual distance to object (scale: 1024=largest grid size) + long neartagrange, //Choose maximum distance to scan (scale: 1024=largest grid size) + char tagsearch) //1-lotag only, 2-hitag only, 3-lotag&hitag + Neartag works sort of like hitscan, but is optimized to + scan only close objects and scan only objects with + tags != 0. Neartag is perfect for the first line of your space bar code. + It will tell you what door you want to open or what switch you want to + flip. + +cansee(long x1, long y1, long z1, short sectnum1, + long x2, long y2, long z2, short sectnum2); returns 0 or 1 + This function determines whether or not two 3D points can "see" each + other or not. All you do is pass it the coordinates of a 3D line defined + by two 3D points (with their respective sectors) The function will return + a 1 if the points can see each other or a 0 if there is something blocking + the two points from seeing each other. This is how I determine whether a + monster can see you or not. Try playing DOOM1.DAT to fully enjoy this + great function! + +setanimation(long *animptr, long thegoal, long thevel); + This is a function for your convenience that will animate a long + variable, such as sector[].floorz for platforms, or sector[].ceilingz + for doors. All you do is pass it the long pointer into memory, specifying + which long variable is to be animated; you also pass the goal (long value + to animate towards), and the velocity at which the variable is animated. + Velocity = 128 is a normal speed door. You may also modify the animation + arrays directly if you wish: + + The animation arrays are as follows: + long *animateptr[MAXANIMATES], animategoal[MAXANIMATES]; + long animatevel[MAXANIMATES], animatecnt; + +getanimationgoal(long animptr); + Check to see if a certain variable in memory is already being animated + by the engine. If so, an index into the animation arrays is returned, + else -1 is returned. This is function is useful when you are press + space bar near a door, and it is already animating, you simply want + to reverse its direction. + +dragpoint(short wallnum, long newx, long newy); + This function will drag a point in the exact same way a point is dragged + in 2D EDIT MODE using the left mouse button. Simply pass it which wall + to drag and then pass the new x and y coordinates for that point. + Please use this function because if you don't and try to drag points + yourself, I can guarantee that it won't work as well as mine and you + will get confused. Note: Every wall of course has 2 points. When you + pass a wall number to this function, you are actually passing 1 point, + the left side of the wall (given that you are in the sector of that wall) + Got it? + +nextsectorneighborz(short sectnum, long thez, short topbottom, short direction); + This function searches z-coordinates of neighboring sectors to find the + closest (next) ceiling starting at the given z-coordinate (thez). + For example, if you want to find the goal z-coordinate when opening a + door, you might want the door to stop at the next closest neighboring + ceiling z-coordinate. You can get the z-coordinate this way: + + newz = sector[nextsectorneighborz(sectnum,startz,-1,-1)].ceilingz + + topbottom (3rd parameter) -1 = search ceilings + 1 = search floors + direction (4th parameter) -1 = search upwards + 1 = search downwards + +screencapture(char *filename) + Capture the screen and save it as a .BMP file. I don't know why my + .BMP format isn't compatible with other programs. + +ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ +³ SPRITE FUNCTIONS: ³ +ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ + +insertsprite(short sectnum, short statnum); //returns (short)spritenum; + Whenever you insert a sprite, you must pass it the sector + number, and a status number (statnum). The status number can be any + number from 0 to MAXSTATUS-1. Insertsprite works like a memory + allocation function and returns the sprite number. + +deletesprite(short spritenum); + Deletes the sprite. + +changespritesect(short spritenum, short newsectnum); + Changes the sector of sprite (spritenum) to the + newsector (newsectnum). This function may become + internal to the engine in the movesprite function. But + this function is necessary since all the sectors have + their own doubly-linked lists of sprites. + +changespritestat(short spritenum, short newstatnum); + Changes the status of sprite (spritenum) to status + (newstatus). Newstatus can be any number from 0 to MAXSTATUS-1. + You can use this function to put a monster on a list of active sprites + when it first sees you. + +setsprite(short spritenum, long newx, long newy, long newz); + This function simply sets the sprite's position to a specified + coordinate (newx, newy, newz) without any checking to see + whether the position is valid or not. You could directly + modify the sprite[].x, sprite[].y, and sprite[].z values, but + if you use my function, the sprite is guaranteed to be in the + right sector. + +movesprite(short spritenum, long xchange, long ychange, long zchange, + long ceildist, long flordist, char cliptype, long numtics) + This function moves the sprite given by spritenum by the 3 + increments, xchange, ychange, and zchange. If cliptype is 0, then + the clipping is normal (Use 0 to clip you and monsters). If the + cliptype is 1, then the object is clipped to the same things that + hitscan is clipped to (use 1 for all bullets). + Movesprite can either return 0 (touched nothing) + 16384+sectnum (ceiling/floor first touched) + 32768+wallnum (wall first touched) + 49152+spritenum (sprite first touched) + +getspritescreencoord(short spritesortnum, long *scrx, long *scry) + This function returns the actual screen coordinates of a sprite. It + is useful for locking on to a target. Use this function between + drawrooms and drawmasks. Note that spritesortnum is the index into the + spritesortcnt arrays, NOT the normal sprite arrays. Scrx and scry are + actual screen coordinates ranging from 0-319 and 0-199 respectively. + +ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ +³ MULTIPLAYER FUNCTIONS (multi.obj) ³ +ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ + + initmultiplayers(char option[4], char option[5], char priority); + Call this right after initengine. Pass option[4] and option[5] + exactly the way I have it written here. (option[4] is the COM1-COM4, + network option and option[5] is the com speed selection option) + Priority can be used to decide who becomes master. Lower is more + towards the master. + + uninitmultiplayers(); + Call this right before uninitengine. + + sendlogon(); + Use this function after everything's initialized, but before you + go into the main game loop. Right after you call sendlogon(), you + should run a loop that will wait until a specified number of players. + Here's some example code: + + sendlogon(); + while (numplayers < waitplayers) + { + getpackets(); + } + screenpeek = myconnectindex; + + Getpackets reserves the packet header range from 200-255. If you + keep calling getpackets after sendlogon, the numplayers variable will + automatically be incremented when other people log on. + + sendlogoff(); + Call this before leaving, before uninitializing the multiplayer + code. + + sendpacket (short otherconnectindex, char *bufptr, short bufleng) + For COM(modem) communications, the otherconnectindex doesn't matter. + For network communcations, you can specify which computer to send + to by setting otherconnectindex to the proper index number. You + can also do a broadcast by setting otherconnectindex to -1. + Also pass the buffer and length parameters. + + short getpacket (short *otherconnectindex, char *bufptr) returns bufleng + When using getpacket, first check the value it returns. + If the value is 0, then the buffer length is 0 which means there + are no packets available. If the buffer length is greater than + 0, then use that value as the length of the buffer. Getpacket also + tells you what computer the message was received from - + (otherconnectindex). + +ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ +³ DIGITIZED SOUND FUNCTIONS: ³ +ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ +Note: If you want to write your own digitized sound driver, simply delete + these functions from GAME.C. + +initsb(); + Initializes the digitized sound routines. You need to call this + only once at the beginning of the program. Currently, the + sample rate is 11,025 Hz. + +wsay(char *filename, long freq, char volume); + Play the sound file at the given frequency and volume. If you + set freq = 4096, the sound will play at normal frequency (given + the sound was also recorded at 11025 Hz) To play the sound an + octave higher, for example, set freq = 8192. Volume ranges from + 0 (silent) to 255 (full volume). Ex: wsay("blowup.wav",4096L,255); + +uninitsb(); + Turns the speaker off, so sounds don't continue playing while + your back in DOS. + +ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ +³ MUSIC FUNCTIONS: ³ +ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ +Note: If you want to write your own music driver, simply delete these + functions from GAME.C. The BUILD engine uses interrupt vector 0x8 (IRQ0) + and that may complicate things. If you like my music, perhaps I can send + you my MIDI sequencer program (It requires MPU-401, and TSENG-ET4000 SVGA, + but could be standardized if there's enough demand). + +loadmusic(char *filename); + Loads the given song into memory. Be sure INSTS.DAT is in the + current directory. If no extension is given, then .KSM will be + appended to the filename. You should use this function only when + the music is off. +musicon(); + Enable the playing of music. Use this only after loadmusic has + been called. +musicoff(); + Disable the playing of music. Be sure to call this before quitting + to DOS. + +ÉÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍËÍ» +ÌÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎ͹ +ÌÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎ͹ +ÌÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎ͹ +ÌÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎ͹ +ÌÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎ͹ +ÌÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎ͹ +ÌÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎ͹ +ÌÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎÍÎ͹ +ÈÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊÍÊͼ + +ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ +³ BUILD Revision History: ³ +ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ +2/6/94 - Added this revision thing. + - Setup program. + - A faster new mode for standard VGAs called chain mode. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +2/8/94 - Fixed chain mode with groudraws. + - Added sector joining in 2D EDIT MODE - press J on first sector. + Then press J again on sector to join with. Attributes will be + taken from first sector. Possible bugs. + - Improved controls for slower computers. + - Made timer interrupt rate 120/second instead of 240/second. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +2/9/94 - Started to work on status bar in 2D EDIT MODE. + - Added special optimization for the Western Digitial (Paradise) + chipset just like with TSENG ET4000. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +2/10/94 - Added a door attribute to sectors. To make a sector a door, + press "D" on the ceiling of the sector in 3D EDIT MODE. For + the door to work, the ceiling of the door sector must be a + tiny bit lower than lowest neighboring ceiling. To open/close + the door, you may press the space bar. Note: Space Bar is also + used for copy and paste in 3D EDIT MODE. You may have to go + into game mode to test out the doors for now. + - Added a wall orientation attribute to walls. This attribute is + used especially in conjunction with doors. So far, you have + been working with walls that are start from the top. For + example, if you hold down 2/8 on the keypad in 3D EDIT MODE, + the wall always starts from the top. But for doors, you + sometimes need walls to start from the bottom. To do this, + press "O" (for orientation) on the wall, and it will now + start from the bottom. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +2/12/94 - Fixed some bugs for sprites. Sprites don't disappear anymore. + Now you will pick up all sprites when running over them. + Monsters will not stop shooting anymore. + - Made the sound blaster sounds have a 1-sound cache. That is, if + the same sound is to be played several times in a row, it will + only be loaded once. + - Added *.GIF format support to EDITART for 320*200 size images. + - Changed the PASTE key in 3D EDIT MODE from Space bar to Left + Enter because the Space bar conflicted with opening doors. + - Added music as an option in the setup program. To run the music, + you need INSTS.DAT and a song file with a .KSM extension. + - Split the editor from the game. + BUILD is now the map editor - you don't need BUILD.C anymore. + GAME is now the actual game that you will be programming. + I am giving you GAME.C to work with. Its code is simpler + than before because there are no more editing function + calls in it. + - Sprites move in a straight line now until they hit walls. When + they hit walls, they pick a new angle to travel in. + - Remember that tiny little guy with the "Al" on his shirt? + Next time you're in DOOM1.DAT, try shooting him. Then look + at the code in GAME.C. + - In EDITART, when you press, "u", you now select filenames with + the arrow keys and enter rather than having to type in + the exact filename. + - Board maps now have extension .MAP and artwork files now have + extension .ART to help distinguish between the different types + of files. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +2/22/94 - Fixed small bug with EDITART not loading right when names.h + existed with no names defined. + - You can now edit new boards by typing: + BUILD like "BUILD NEWBOARD" + - Added ALT-S in 2D EDIT Mode to change a whole white loop inside a + sector to a red loop. + - When viewing the tiles (pressing "v") you can now use PGUP/PGDN. + - Added a message bar in 2D EDIT Mode. + - Added TAB and L.ALT-TAB keys to view all the attributes of a + sector, wall, or sprite (see above documentation). + - Debugged and bullet-proofed ALT-S. + - Fixed a bug that doesn't allow you to drag points with number + greater than 1023. (There can actually be 4096 walls and 1024 + sectors, and 4096 sprites currently, an easy thing to increase) + - Changed overwritesprite function paramaters. If you are using it + in your c file, you must change it! Now it looks like this: + + overwritesprite (long x, long y, short tilenum, char shade, + char orientation); + + If orientation = 0: x and y are the top left corner. + If orientation = 1: x and y are the middle (like before). + - Added permanentwritesprite function for status bars or other + sections of the screen that will not be overwritten by the + engine. When using this function, you may want to modify the + STARTUMOST / STARTDMOST arrays. The format of this function is + like overwritesprite except that the x and y are always top + left corner, no orientation variable, and no translucence. + + permanentwritesprite (long x, long y, short tilenum, char shade); + + - Added an attribute to the printext and printnum functions. Please + change these function if you use them in your program. The + current formats are: + + printext(long x, long y, char buffer[42], short tilenum, + char invisiblecol) + printnum(long x, long y, long num, short tilenum, + char invisiblecol); + + Invisiblecol tells printext what color to draw the transparent + pixels. If invisiblecol is 255 then the transpararent pixels are + still transparent. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +2/26/94 - Completely reprogrammed EDITART. + IMPORTANT: PLEASE RUN CONVART.EXE ON ALL ARTWORK FILES! (If you have not + already). It will convert PICS.ART in the old format to + TILES.ART in the new format, so you may have to do some + renaming when converting artwork and also rename the loadpics + line in your C file. BUILD WILL NOT RUN UNLESS YOU DO THIS! + With the new artwork file, the tiles can now be any size from + 1*1 to 1024*240 and they no longer have to be powers of 2. + This feature allows parallaxing skies that are 1024 pixels wide + to cover all 360ø, or 320 pixel wide status bars. It can also + be used to display 320*200 title screens. + - When pressing 'U' in EDITART, you can now change directories + and the current loading directory will be remembered. + - When pressing 'U' in EDITART, you can press the mouse button to + readjust the size of the tile. + - When pressing 'U' in EDITART, press ENTER for an automatic + palette conversion or press SPACE BAR for no conversion. + - Walls that are Blocked ('B') in BUILD are now shown in pink. + If the wall does not show pink in your board, just press + 'B' twice to permanently fix it. + - Made smooshiness values easier to work with. Hold down 5 on the + keypad with 2/4/6/8 to align the walls to multiples of the + tile that is used. Also, when you do Tab and L.Enter for + Copy&Paste, the y-repeat values stay the same, and the + x-repeat values are adjusted so the pixels of the bitmaps + have a square-aspect ratio. + - Added masked walls. But since they don't quite work perfectly + yet, and they are extremely hard to edit now, so for now, just + enjoy the technologiy in DOOM1.MAP. Don't worry - you'll get + your hands on this soon! + - Fixed the "earthquake" effect on really high walls. The walls + will not move up and down, but the pixel fuzzyness bug is + still in there. + - Put door variables and tile information into BUILD.H for you to + play around with. + - Made walls, ceilings, and floors also work with the animation + attribute in EDITART. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +3/2/94 - Made power of 2 size tiles work with ceilings & floors. + - When using different size ceilings & floors, made an option in + 3D EDIT MODE. If you want a tile to be smooshed into the normal + 64*64 area, press 'E' to unExpand the tile. + - Groudraws now look more cubical than before. (But be careful of + crashing with them for now) + - IMPORTANT: Changed the Board format. If you tried running BUILD + before reading this, and it didn't work, shame on you! You + should always look at the history section of BUILD.TXT first! + Since from now on, I am writing Board/Art converters, I am + giving you CONVMAP.EXE to convert maps. You can type either: + C:\BUILD>convmap house.map + to convert an individual map or: + C:\BUILD>for %i in (*.map) do convmap %i + to convert all the maps in a directory. + + - IMPORTANT: Sprites are now on 2 different sets of doubly-linked + lists. The big advantage of this method is that when sprites + are deleted, there can be holes in the sprite list with + no slow down. Before I used to have linked lists for each + sector pointing to all the sprites in it. Well, I have updated + that and added more linked lists that tell whether sprites + are active or inactive (not a fun thing to progam) But not + to worry, you don't have to deal with changing the linked + lists, thanks to my very easy function calls. YOU WILL + HAVE TO CHANGE YOUR CODE TO SUPPORT THE NEW LINKED LISTS. + You should know how to search through each list. See BUILD.H + for a detailed description of how the linked lists work, and + see the top of this file for description of the new sprite + function calls. + + insertsprite(short sectnum, short statnum); + deletesprite(short spritenum); + changespritesect(short spritenum, short newsectnum); + changespritestat(short spritenum, short newstatnum); + + In your code, you will have to change the following: + firstsprite[spritenum] --> headspritesect[spritenum] + sprite[spritenum].point2 --> nextspritesect[spritenum] + + Also, you should change the part of your main loop that scans + through all the active sprites to look more like this: + + + i = headspritestat[1]; //head of active sprite list + while (i != -1) + { + nexti = nextspritestat[i]; //back up next sprite in case current + //one is deleted. + + //your code goes here (use i as the sprite number) + +spriteisdeletedskip: + i = nexti; //go to next sprite + } + + + + - Added tagging (naming) to any sector, sprite, or wall. That means + you can change a tag in the BUILD editor by pressing T with the + mouse cursor on the highlighted sector. And in GAME.C, you + can access the tag this way: + sector[sectnum].tag; + sprite[spritenum].tag; + wall[wallnum].tag; + Note: All 3 types of tags are long integers, but in BUILD.C + you can only make them short integers. I am planning to + let you use the upper 16 bits of the tag byte as use for + you only. (like permanently unreserved bits) + - Added serial link. But it doesn't work very well yet. You + may have to try going into GAME several times before it works. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +3/15/94 - Fixed maskable walls - now sort out with sprite better. Easier + to edit. Simply press 'M' at a place where a maskable wall + should be (like where you normally press 'B' for blocking) + - Can flip walls, masked walls, and sprites x-wise by pressing + 'F' in 3D EDIT MODE. Also, it is possible to save space in + sprite rotations, by flipping it x-wise by programming one of + the bits in sprite[].cstat. + - A few other minor things, but I forgot what they were. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +3/19/94 - Fixed one of the many crashing bugs. + For Duke Nukem III team: + CITY.MAP will not crash anymore with new version. The + reason it crashed was because in your TILES.ART, you had + either ANMFD:0, ANMBK:0, or OSCI:0. That caused a MOD 0 + in my animation routine. I bullet-proofed that. How about + fixing tiles #34, #112, or #114 in your TILES.ART. + - Wrote divide by zero handler. Now if there is a divide by zero, + BUILD goes back into text mode and fills the screen with + /0/0/0/0/..., then gives a DOS prompt. (In other words, you + don't have to type "MODE CO80" anymore for /0 crashes) + - Optimized routines in assembly for 486's using my great new + Intel 32-bit optimizing techniques book that dad got for me. + - Fixed ALT-S in BUILD so ANY white loop can be converted into a + red loop except for the 1 and only 1 outermost white loop. + - FINALLY! Splitsector bug is fixed! You can now split a very + complicated sector with tons of sectors inside it or with + plenty of sprites. Also sprites will not get deleted + spontaneously with split sector any more. + - Ctrl-Enter in 3D EDIT MODE is like the normal Enter paste key, + but Ctrl-Enter pastes the attributes to an entire loop of + walls (if a wall is highlighted). +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +3/22/94 - Added doors that open left and right. See sector[].tag #9 in the top + of this file for details - also look at my board, NUKELAND.MAP, + in BUILD to see how to make this type of door. + - Increased the number of status lists. You may recall my active / + inactive sprite lists called headspritestat, prevspritestat, + and nextspritestat. Don't worry - you will NOT have to + change any of your code. The only thing I changed is now + you can have 1024 different lists of sprites rather than just + 2 lists if you want to use them. For example, you might want + to run through all the brown monsters on the board. Instead + of putting all different types of monsters on the active + list, it is faster to have a separate list just for brown + monsters. Use your imagination! +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +3/31/94 - Fixed some palette problems with EDITART. Now when you press 'P' + in 'U' mode, the palette of all the existing tiles are + converted to the new palette. Also the text colors should + be similar colors on different palettes now. + - Changed bit 0 of sprite[].cstat to the hitscan checking / ignoring + bit. You should set this bit to 1 for monsters, 0 for + bullets, 0 for pick-upable objects like coins, and 1 for + objects like columns. Right now, (Since it's not in the + BUILD editor), you must set these bits in your code right + after you load the board. + - I did not document the neartagsector, neartagwall, and + neartagsprite very well, so if you don't know how to use + them alreay, please read on. These 3 variables are modified + by the engine every time you call draw3dscreen(). These + variables are usually -1. These variables will be >= 0 if + all of these cases are true: + 1. You are looking at a wall, sprite, or sector. + 2. You are close enough to the wall, sprite, or sector + to be able to use the action key with it. + 3. The tag of the wall, sprite, or sector is greater or + equal to 1. + As you can see, neartagsector makes a perfect variable for + detecting whether or not you are opening a door. You can + also use neartagwall for switches on walls. Also, you can + use neartagsprite for sprites that are switches. + - PROGRAMMERS: PLEASE MAKE THESE EASY CODE MODIFICATIONS: + I reversed the way variables are stored in BUILD.H. + Now the variables will be local to the ENGINE and externed + to GAME. Before they were local to GAME and externed to the + engine. All you have to do is this: + 1. You can remove the #define MAIN if you want to. + 2. Delete the externs declarations that I used to have + in the beginning of GAME.C, because I put them in + BUILD.H. I will try not to put externs in the GAME + in the future to save you the time of copying and + pasting code. Here is a list of externs I moved: + + EXTERN short neartagsector, neartagwall, neartagsprite; + EXTERN long *animateptr[MAXANIMATES], animategoal[MAXANIMATES]; + EXTERN long animatevel[MAXANIMATES], animatecnt; + EXTERN short tilesizx[MAXTILES], tilesizy[MAXTILES]; + EXTERN long numtiles, picanm[MAXTILES], waloff[MAXTILES]; + - Added a global parallaxing sky type variable. Now I have 3 + different types of parallaxing skies. Here they are: + + 0 - Totally flat parallaxing sky. + 1 - X-only stretching parallaxing sky (This is what DOOM uses). + 2 - X- and Y- stretching parallaxing sky. (This is what BUILD + uses by default) + A good place to set the parallaxing sky is right after you + call initengine(). + - Added local tile selection to the BUILD editor. This means + that when you press V on a sprite, you will see only the + sprites that are on the level so far. If you want to use + a sprite that is not already used on the current board, press + V again and you will be able to select from the huge list + that you are used to from before. The local tile list will + be sorted according to how much each tile is used on the + current board. Note that the local tile list will be + different depending where the mouse cursor was left when you + pressed V (or H). +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +4/4/94 - Changed the way ART files work. YOU MUST READ THIS: + There are some two easy things that you must do 2 things before + you can use the new engine: + + 1. Type CONVART1.EXE to convert your ARTWORK to the new + format. (If I forgot to send this file to you, please call + and torture me.) Now, instead of everything being stored + in one huge file, TILES.ART, I am splitting the artwork into + several files each holding 256 tiles in it. This will allow + you to make infinitely large artwork files in EDITART. + + 2. In GAME.C, you must change the line, + loadpics("tiles.art"); + to: + loadpics("tiles000.art"); + All you have to give loadpics is the first filename of your + artwork, and the engine will automatically know how to + modify the 3 digits at the end and load all the artwork + files properly. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +4/5/94 - Fixed the "fuzzy" pixels on high walls. Now you make walls as + high as skyscrapers, and when you look at it up close, the + pixels will still look like perfect rectangles. Note: This + fix may require you to press 'O' in 3D EDIT MODE to put + your boards back to normal. + - When you pressed ENTER on weird-sized tiles, sometimes in the old + version the pixels would not be square aspect ratio. Now + when you press ENTER, they will be. + - You can now set the starting position in 2D EDIT MODE with the + Scroll Lock key. The starting position will look like a + brown arrow, and your current position will look like a + white arrow. Now you don't have to keep returning to start + when you save your board. + - Added some new things to the structures - guess what this means? + CONVMAP3! THE NEW OBJ'S and BUILD will NOT work until you + run CONVMAP3. (Please call if I forgot to give + you this file) + Notice that I added these things to the structures: + + sectortype: + bit 2 of ceilingstat&floorstat: + 1 = North/South panning, 0 = East/West panning + char ceilingpanning, floorpanning; + walltype: + bit 6 of cstat + 1 = Vertical panning, 0 = Horizontal panning + char panning; + short overpicnum; + spritetype: + char *extra; + + Now an explanation of each: + To the sector structure, I added the capability to pan + the floors and ceilings. Usually ceilingpanning and + floorpanning are set to 0. For example, a good way to make + an earthquake would be to randomly increment or decrement + to panning values. To allow you to pan the ceilings or + floors at any of the standard 90 degree angles, I made + bit 2 of sectortype's ceilingstat/floorstat byte choose + whether the ceilingpanning/floorpanning byte should move + the ceiling/floor North/South or East/West. + To the wall structure, I added panning also. Bit 6 + of cstat and the panning values work in the same as the + ceilings and floors. + To the sprite structure, I added only 1 variable. + The "extra" pointer is intended for your use only, so you + can have the sprite's structure extended if you so desire. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +4/6/94 - In 2D EDIT MODE, you can now press ESC to get a message in the + message bar that says this: + + (N)ew, (L)oad, (S)ave, (Q)uit + + And it all works too. (Press ESC to cancel) + Loading lets you select the file just like 'U' in EDITART. + - The old version of BUILD had the coordinate system all screwed + up in 2D EDIT MODE. I fixed this. Included with + CONVMAP3.EXE is a conversion utility that will make your + boards have the same orientation as in the older BUILD + editors. If you don't care if the whole map gets rotated + in the 2D editor, then press N. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +4/7/94 - Changed the way Orientation works ('O' in 3D EDIT MODE) + + Now, when you draw a normal door in BUILD, you do NOT have to + press 'O' everywhere to make the walls of the door move right. + Now, the default is that everything moves right. Here's a + detailed description of how the new orientation works: + + For white lines (no neighboring sector): + + orientation = 0 (default) means picture is aligned with + sector[].ceilingz. + orientation = 1 means picture aligned with sector[].floorz. + + For red lines (has a neighboring sector): + + orientation = 0 (default) means picture is aligned with + either the ceilingz or floorz of the next sector. + orientation = 1 means picture aligned with + sector[].ceilingz. + + Don't worry if you don't understand the detailed description. + Just know that it's better this way. I have included the + proper conversions in CONVMAP3.EXE. + - Added wall&ceiling x-panning keys to the 3D EDIT MODE. Press + the , or . keys to pan a wall or ceiling left or right. You + can hold down the 5 key on the keypad to align at every eighth + panning value. (Just like with 2,4,6,8). + - Made TAB&ENTER in 3D EDIT MODE also copy the CSTAT byte of + the wall's attributes. This means that attributes such as + the block attribute, 1-way wall attribute, orientation, + and x-flipping attribute are also copied & pasted. + - Added a new function, cansee. + + cansee(long x1, long y1, long z1, short sectnum1, + long x2, long y2, long z2, short sectnum2) + + All you do is pass it the coordinates of a 3D line + and the respective sectors of each point of the line. + The function will return a 1 if the points can see each + other or a 0 if there is something blocking the two points + from seeing each other. This is how I determine whether + a monster can see you or not. Try playing DOOM1.DAT with + digitized sound enabled to fully enjoy this great new + function! +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +4/12/94 - Fixed HITSCAN function. Since it works a little differently + and the parameters are different, let me describe how the + new hitscan works: + + hitscan(long xstart, long ystart, long zstart, short startsectnum, + long vectorx, long vectory, long vectorz, + short *hitsect, short *hitwall, short *hitsprite, + long *hitx, long *hity, long *hitz); + + Pass the starting 3D position: + (xstart, ystart, zstart, startsectnum) + Then pass the 3D angle to shoot (defined as a 3D vector): + (vectorx, vectory, vectorz) + Then set up the return values for the object hit: + (hitsect, hitwall, hitsprite) + and the exact 3D point where the ray hits: + (hitx, hity, hitz) + + How to determine what was hit: + * Hitsect is always equal to the sector that was hit + (always >= 0). + + * If the ray hits a sprite then: + hitsect = thesectornumber + hitsprite = thespritenumber + hitwall = -1 + + * If the ray hits a wall then: + hitsect = thesectornumber + hitsprite = -1 + hitwall = thewallnumber + + * If the ray hits the ceiling of a sector then: + hitsect = thesectornumber + hitsprite = -1 + hitwall = -1 + vectorz < 0 + (If vectorz < 0 then you're shooting upward which means + that you couldn't have hit a floor) + + * If the ray hits the floor of a sector then: + hitsect = thesectornumber + hitsprite = -1 + hitwall = -1 + vectorz > 0 + (If vectorz > 0 then you're shooting downard which means + that you couldn't have hit a ceiling) + + - Added a position window to the bottom of the menu in 2D EDIT + MODE. It shows the posx, posy, and ang variables. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +4/14/94 - Overwritesprite now clips to the startumost / startdmost arrays. + Now the only way to write to the status bar is with + the permanentwritesprite function. + + - ATTENTION PROGRAMMERS! I Split draw3dscreen() into 2 separate + function calls. + + old: draw3dscreen(); //Draws walls, ceilings, floors, p-skies + // groudraws, sprites, and masked walls. + + new: drawrooms(); //Draws walls, ceilings, floors, p-skies + // and groudraws. + drawmasks(); //Draws sprites and masked walls. + + The reason I split draw3dscreen was so you could manipulate only + the sprites that the engine is going to draw to the screen + before the sprites are actually drawn. + + - I think I may have fixed that darn sector line bug! Before, the + bug usually appeared when you were on a (red) sector line where + the ceiling and floor of the sector were very far from each + other. This overflowed some really high positive values into + the negative range and vice versa. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +4/18/94 - Wall clipping now works much better! (You can still VERY RARELY + sneak through walls, however) + ATTENTION PROGRAMMERS: + MOVESPRITE and CLIPMOVE have been changed. They now look + like this: + + clipmove (long *x, long *y, long *z, short *sectnum, + long xvect, long yvect, long walldist, + char cliptype); + + movesprite(short spritenum, + long xchange, long ychange, long zchange, + long walldist, char cliptype); + + To use the new clipmove: + Pass the pointers of the starting position (x, y, z). Then + pass the starting position's sector number as a pointer also. + Also these values will be modified accordingly. Pass the + direction and velocity by using a vector (xvect, yvect). + If you don't fully understand these equations, please call me. + xvect = velocity * cos(angle) + yvect = velocity * sin(angle) + Walldist tells how close the object can get to a wall. I use + 128L as my default. If you increase walldist all of a sudden + for a certain object, the object might leak through a wall, so + don't do that! + + To use the new movesprite: + Works like before, but you also pass walldist (How close the + sprite can get to a wall) + + - New function for sprites: + setsprite(short spritenum, long newx, long newy, long newz); + + This function simply sets the sprite's position to a specified + coordinate (newx, newy, newz) without any checking to see + whether the position is valid or not. You could directly + modify the sprite[].x, sprite[].y, and sprite[].z values, but + if you use my function, the sprite is guaranteed to be in the + right sector. + + - You can now change the angle in 2D EDIT MODE with the + < and > keys. Move the mouse cursor to a sprite first. + Hold down shift with the < and > to get more precise angles. + - You can now press 'B' on sprites in 3D EDIT MODE. This in effect + is xoring bit 0 of sprite[].cstat, which will not only be + sensitive to hitscan, but will also block you from walking + through the sprite. Sprites with the 'B' attribute will + appear pink in 2D EDIT MODE. + - You can now edit the Hi 16 bits of the tag in 2D EDIT MODE. + Just like T and ALT-T, you press H and ALT-H to edit the high + 16-bits. When a structure's attributes are displayed, the tag + will be displayed as 2 unsigned shorts. The first number + represents the hi 16 bits and the second number represents the + lo 16 bits. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +4/23/94 - Added 'G' in Editart to GOTO a tile by typing in the tile number. + - Changed the way masking walls work a little bit. Now the + masking walls use the picture wall[].overpicnum rather than + wall[].picnum. + - Made hitscan hit maskable walls. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +4/24/94 - Made palette.dat support any number of shades up to 64. There + is no change to the palette.dat format. The palette.dat + format is: + + First the palette (768 bytes) Values range from 0-63 + Then the lookup shades (256 * number_of_shades) The + shades are stored in groups of 256 bytes. + + - If you use Mark Dochtermann's palette program, then you can + convert his data files (such as palette.pal and colormap.lmp) + to my palette format, palette.dat, with my great Qbasic + program, PALMP.BAS. To run it, first copy the basic program + into the same directory as the 2 source palette files are in. + Then type: "QBASIC PALMP" and then press SHIFT+F5 (to run it). + + - Added a global variable, HORIZ. Horiz usually equals 100. + Modifying horiz will move the whole screen up / down. I + added 2 keys, +/- in my own game.c to demonstrate this. You + can use this variable for looking up and down if you want. + (Even though this is not "truly" looking up and down, if + you're lucky, you might be able to fake out some people!) + + - New Key in 3D EDIT MODE, the forward slash. Use / with the + tile panning keys (, and .) to flip the horizontal / vertical + orientation bits for walls, ceilings or floors. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +4/28/94 - NEW BOARD VERSION! You must run CONVMAP4.EXE on all your boards. + Here's what I changed in the structures: + + Sectors: + I got rid of: + char sector[].ceilingpanning, sector[].floorpanning; + sector[].ceilingstat/floorstat bit 2 zeroed out + and added: + char sector[].ceilingxpanning, sector[].ceilingypanning; + char sector[].floorgxpanning, sector[].floorypanning; + + Walls: + + I got rid of: + char wall[].panning; + wall[].cstat bit 6 zeroed out + and added: + char wall[].xpanning; + char wall[].ypanning; + + Sprites: + + I got rid of: + short sprite[].vel; + and added: + short sprite[].xvel; + short sprite[].yvel; + The reason I did this was so sprites could be moved in + different directions than sprite[].ang. Please make + use of both xvel and yvel. Here's the equation I would + use to convert from the old to new. For example: + + old: + sprite[i].vel = 256; + new: + sprite[i].xvel = (sintable[(sprite[i].ang+512)&2047]>>6); + sprite[i].yvel = (sintable[sprite[i].ang&2047]>>6); + + The reason I am shifting the sines right by 6 is becuase + my sintable ranges from -16384 to 16384. Dividing by + 64 gives a maximum range of -256 to 256. + + CONVMAP4.EXE also attempts to convert the masked walls so + overpicnum is the masked wall's picnum. + + - Changed 3D EDIT MODE panning keys: + Since panning is now all 4 directions, I got rid of the + , and . keys and put the keys on the keypad using 2,4,6,8. + Usually 2,4,6,8 are for x- and y-repeats, but if you hold + down either shift key, then they act as x- and y- panning + values. + The / key now resets the panning values to 0. + + - Please read the updated descriptions of how to make masking walls + in the 3D EDIT MODE KEYS in the top of build.txt. See + the 'M' and 'Shift + M' keys. + + - Also look at the top of this file for a description of dragpoint(), a + great new function that makes it easy to morph sectors. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +4/29/94 - Added some minor keys to 3D EDIT MODE. Alt. +/- change the + visibility variable. It ranges from 5 (darkest) to 17 + (lightest) and it starts at 13. + + - Made 1-way walls have more options. Now, for example, you can + make rectangular switches on walls. Please look at my + nukeland.map for an example of how to do switches. (The + switches are close to start - just go through the door and + bear left.) + + - For those who asked, here's how some sample bobbing code: + First, calculate the distance actually moved - because if you + are not moving then you shouldn't bob: + + CODE: + oposx = posx; oposy = posy; + clipmove(&posx,&posy,&posz,&cursectnum,xvect,yvect,128L); + dist = ksqrt((posx-oposx)*(posx-oposx)+(posy-oposy)*(posy-oposy)); + + Then modify the horizon value by multiplying the distance + actually moved by a sine wave. (default is horiz = 100). + + CODE: + horiz = 100 + ((dist*sintable[(totalclock<<5)&2047])>>19); + + - Remember that moving block in the slime in NUKELAND.MAP? It + works a lot better now. I am now modifying the floor panning + values to make the floor match up correctly with the block. + + - Fixed the screen capturing (F12) to save captures as PCX files. + This is for BUILD, GAME, and EDITART. + + - Fixed bug in EDITART when you press 'U' on a blank tile. It + should not crash any more. + + - Made Tab & Enter a little smarter in copying the right attributes + to different types of objects. + + - Added ceiling / floor 90ø rotation attributes. All 8 + rotations are possible. 3 bits have been added to both + the sector[].ceilingstat and sector[].floorstat flags. + If you look in BUILD.H, you will see the new flags + descriptions. You can use the 'F' key in 3D EDIT MODE on + a ceiling or floor to change the rotation. + +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +4/30/94 - ATTENTION PROGRAMMERS: + I removed the function, getsector, and added a more expandable + function, updatesector. Also, updatesector is smart enough + to check to see if you are in the same sector OR neighboring + sectors first before going through every single sector. + Getsector used to go though all the sectors every time you + crossed a sector line. + + getsector(); (no arguments, returns nothing - REMOVED) + * used to make sure that CURSECTNUM matched up with + the right sector according to the POSX and POSY values. + updatesector(posx,posy,&cursectnum); + * the new way of writing getsector. You can do a + search&replace on your code. Be careful when you use this + function with sprites because remember that the sprite's + sector number should not be modified directly. For example, + you might want to code it this way: + + tempsectnum = sprite[i].sectnum; + updatesector(sprite[i].x,sprite[i].y,&tempsectnum); + if (tempsectnum != sprite[i].sectnum) + changespritesect(i,tempsectnum); + + Actually, I think the setsprite function is better for + updating a sprite's sector number. + + - Added swinging doors! Look at NUKELAND.MAP in my GAME.EXE for + an example. For swinging doors, I used a new math-helper + function, rotatepoint. + + rotatepoint(long xpivot, long ypivot, + long x, long y, + short deltaang, + long *x2, long *y2); + + Rotatepoint will rotate point(x,y) around point(xpivot,ypivot) + by the deltang value. The resultant point will be s + + - Fixed crashing bug in BUILD when a wall's tile doesn't exist. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +5/02/94 - I improved the pre-level check on the swinging doors, so now + you can have multiple doors in a sector that open any way. + This is how I do my double swinging doors (demonstrated in + NUKELAND.MAP) + + - I added a revolving door! See NUKELAND.MAP for an example. (The + revolving door is beyond the bouncing platforms in the slime + pit) + + - Fixed bug with joining sectors in 2D EDIT MODE. The sprites + don't get deleted any more. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +5/04/94 - Optimized the masked walls. + + - Cleaned up the sprite drawing code (and many bugs that that came + along with it.) +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +5/05/94 - Made cylindrical walls with any number of points VERY easy to + make in BUILD. Here's how you do it: Highlight a wall and + press 'C' on it. Then move the mouse to the proper position + to make a nice circle. You can press '+' or '-' to change + the number of points on the circle. Press 'C' again to cancel + or press space bar to actually change the map. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +5/07/94 - Made a fully-operational subway! Look at subway.map. + + - Made a new type of door - a sliding door where the door doesn't + get "x-smooshed" when it is opened. (See description of + sector tag 16 & wall tag 6) + + - Also note that I my first subroutine in game.c! It is: + operatesector(short dasector) + All the door code is now in this function (with a few + exceptions, such as parts of the swinging doors and revolving + door) +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +5/08/94 - Made EDITART and BUILD support different tile sizes in 'V' mode. + Here are the three possible sizes: + 0. 64*64 - 5*3 grid - views 15 tiles (old default) + 1. 32*32 - 10*6 grid - views 60 tiles (new default) + 2. 16*16 - 20*12 grid - views 240 tiles + Press the '*' and '/' keys in 'V' mode if you want to change + the grid resolution. + + - Added/fixed up a new key in 3D EDIT MODE, the dot key (. or >) + This key attempts to match up all the tiles along a wall. It + scans along the walls towards the right as long as the picture + number of the next wall is the same as the original picture + number. Note that some walls may not work right, especially + floor / ceiling steps. + + - Made 2D EDIT MODE default to this when inserting sprites: + 1. Sprite clipping = on for sprites taller than 32 pixels + 2. Sprite clipping = off for sprites shorter than 32 pixels. + + - Fixed sprite clipping with Z-coordinates +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +5/10/94 - Fixed some sprite dragging bugs + + - Made neartag? maximum sensing distance a global variable called + neartagdist. See build.h. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +5/11/94 - Added sector / groups of sectors selection. When selecting + sectors, hold down the right ALT key. It works just like + right shift. You must completely surround any sector you + wish to select. Once selected, you can drag the mess of + sectors with the mouse. This is great for separating sectors + from each other. + + - Added sector duplication. First select a bunch of sectors. Then + press the insert key. (with the select sectors flashing) Then + This duplication is like stamping. So, you must drag + the sector bunch somewhere else after stamping to see your + great accomplishments. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +5/12/94 - Added group-sector PGUP / PGDN. Here's a neat trick that will + let you move a whole section of a board up / down quickly. + First you select a bunch of sectors with the right ALT key in + 2D mode. Then flip to 3D mode and if you press PGUP / PGDN + on any of the highlighted sectors, the rest of the highlighted + sectors will move also. + + - Added group-sector rotation. Once you do a sector select (right + ALT), you can press the , or . keys to rotate the selected + sectors. Hold down the shift key with the keys to get fine + angle rotation (WARNING: You will get distortion with fine + angle rotation in this version) + + - Added sector count and wall count information at the bottom of + the 2D edit mode status bar. + + - Fixed some stupid bug that you probably wouldn't have found if + you made boards with BUILD for the rest of your life. + + - You can now press 'B' to block / unblock a wall or sprite in + 2D edit mode. + + - Made Ctrl-Shift Enter auto-shade a sector. First make any + wall of the loop as light as the lightest shade you want. + Then make any other wall of the loop as dark as the darkest + shade you want. Finally press Ctrl-Shift Enter on the wall + that should be lightest. Now the loop should be smoothly + shaded. If it is not smoothly shaded, you may need to insert + more points on the walls. + + - Fixed my .PCX format bug. My screen captures now load properly + in Deluxe programs. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +5/13/94 - Made my serial code in Game.c work better. I fixed the bullet + shooting and made all types of doors work. Unfortunately, you + still may have to run at slower COM speeds. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +5/14/94 - Fixed deadly bug with sector copy & sprites. + + - Added hitscan sensitivity bit. It is bit 6 (64) of wall[].cstat. + In 3D edit mode, you can press 'H' to toggle the bit. (H used + to be like 'V' for choosing height tile numbers for groudraws - + I change the 'H' key to Alt-V since I don't think anybody was + using it anyway) By default, hitscan CAN go through maskable + walls. If a hitscan is set to not go through a maskable wall, + The wall will appear BRIGHT pink in 2D edit mode. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +5/15/94 - Made more subroutines in game.c and moved documentation from the + end of game.c into this text file. Added some more comments + also. Game.c is so much easier to read now! The main loop is + less than 50 lines long! + + - Made some optimizations to my serial code now that everything + is in functions. + + - ATTENTION PROGRAMMERS: + I added one new paramater (cliptype) to both the movesprite + and clipmove functions. If the new parameter is a 0, then + the clipping is normal (Use 0 to clip you and monsters). + If the new parameter is a 1, then the object is clipped to + the same things that hitscan is clipped to (use 1 for all + bullets). + See the above documentation for a detailed description of the + parameters. (Remember that I moved the documentation from + GAME.C into the middle BUILD.TXT) + Finally, you can have sprites and bullets going where you + want them to go! +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +5/18/94 - Added support for the Spaceplayer (6-degree of freedom Space ball) + Try out the SETUP program now. + + - Fixed some bugs with the 'E' key in 3D EDIT MODE. As long as both + dimensions of the tile are powers of 2, then the picture should + be visible. It should not be a solid color with a few weird + lines any more. + + - Fixed some bugs with the Z control in 3D EDIT MODE. In normal + operation, BUILD attempts to keep your Z constant even if + you cross sector lines. Then I added a special new mode that + locks your heightofffloor to a certain value. You Z will + change instantly if you cross sector lines. To use this mode, + press the Caps Lock key. Press Caps Lock key again for normal + operation. + + - ATTENTION PROGRAMMERS! I put all of engineinput into GAME.C + This means you have absolutely total control of the Z's. (The + only thing left is some key code I still have in my timer + handler) + + OK, now read carefully! Here's how to convert to the new OBJ's: + + 1. First of all, the Spaceball code is now also in game.c. + A. You will need to put this line in game.c: + include "spw_int.h" + B. And make sure to add spwint.obj your makefile. + 2. Heightoffceiling, heightofffloor, and gravity have been + removed from BUILD.H. If you still want to use them + then you should defined them as globals in your own code. + 3. You should go through every single key of my gameinput() + function in game.c and copy any code you want. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +5/23/94 - GREAT NEW STUFF! + + Be sure to check out GAME.EXE and try out these new keys! + + Rt. Enter = Switch between 3D / 2D modes + Lt. +/- = Zoom in 2D mode + + Added 2D map display with auto-mapping! The 2D maps use a + higher resolution 16-color mode. You have a choice of either + using a 640*350*16 screen or a 640*480*16 screen with a 144-high + status bar (remember that 640*480*16 cannot fit in 256K with 2 + screen pages so I have to cheat with a status bar). + + NEW FUNCTIONS: + + draw2dscreen(long posxe, long posye, short ange, long zoome, + short gride) + Draws the 2d screen - this function is a direct replacement + for the drawrooms() and drawmasks() functions. Be sure + to call either qsetmode640350() or qsetmode640480() + first. When switching back to 3d mode, be sure to call + qsetmode320200(). + + IMPORTANT NOTES: + 1. The overwritesprite function should only be called in + 3D mode. If you do this in 2D mode, junk will be + written to the 2D screen and a crash is possible. + 2. When you switch back to 3D mode, you should call the + permanentwritesprite functions to draw the status bar, + or whatever else you have to draw. + 3. You must call the nextpage() function in both 2D and + 3D modes. + + qsetmode320200(); + Set to the game mode and load palette (320*200*256) + qsetmode640350(); + Set to the 2D map mode #1 (640*350*16) + qsetmode640480(); + Set to the 2D map mode #2 (640*480*16) + + NEW VARIABLES (see description in build.h): + + EXTERN char show2dwall[MAXWALLS>>3]; + EXTERN char show2dsprite[MAXSPRITES>>3]; + EXTERN char automapping; + + - Added parallaxing floors! Works like the parallaxing skies, but + the other side. In 3D EDIT MODE, press P on ceiling for + parallaxing sky, or press P on floor for parallaxing floor. + +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +5/24/94 - There is a new function that I forgot to document in the last + version. Oops! + + doanimations() is this function. + It's not really new, but I split it off of the + drawrooms/drawmasks functions. This function animates anything + that you use setanimation with. Please stick it in your code + somewhere after you draw the screen. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +5/26/94 - You can now do TRANSLUSCENT sprites! I am using bit 1 of + sprite[].cstat to detemine whether or not the sprite is + transluscent or not. In 3D EDIT MODE, you can press 'T' to + toggle the transluscence bit. + IMPORTANT: Transluscence WILL NOT WORK until you run my + TRANSPAL.EXE program. On the command line, simply type: + C:\BUILD>transpal [filename] + If you do not specify a filename, the default will be + palette.dat. If your palette.dat file is now around 40K long, + then you are ready for transluscence! + + - Added TRANSLUSCENCE to masked walls. See bit 7 of wall[].cstat. + Press 'T' on wall to toggle the transluscence bit. + + - In this BUILD update, I have collected many different palettes + for comparison purposes. Try running TRANSPAL.EXE on each of + them and see for yourself which palettes work the best with + transluscence! + +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +5/29/94 - ATTENTION PROGRAMMERS: I completely rewrote the neartag code. + Here's what you have to do to convert your game.c files: + + 1. You should move the neartag variables that I used to + have in BUILD.H into your C code. + 2. You must call the neartag function yourself if you want + to see if you're near a tagged object. Neartag is NOT + automatically updated by the engine any more. + 3. I highly recommend that you put your neartag function + call at the first line in your space bar code. This way, + you can optimize the neartag calculations by only doing + them when you press the space bar. (Exception: For + ladders, I think you'll have to call neartag every single + frame) + + Here's a description of the new neartag function: + Neartag works sort of like hitscan, but is optimized to + scan only close objects and scan only objects with + tags != 0. + + neartag(long x, long y, long z, short sectnum, short ang, //Starting position & angle + short *neartagsector, //Returns near sector if sector[].tag != 0 + short *neartagwall, //Returns near wall if wall[].tag != 0 + short *neartagsprite, //Returns near sprite if sprite[].tag != 0 + long *neartaghitdist, //Returns actual distance to object (scale: 1024=largest grid size) + long neartagrange) //Choose maximum distance to scan (scale: 1024=largest grid size) + +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +5/31/94 - Added a function to get a sprite's screen coordinates. I put + some sample code in my GAME in the analyzesprites function. + Simply hold down the CAPS LOCK key in my GAME.EXE, and the + screen will be centered around the sprite closest to the + center of the screen. + + Here's a new function in the engine I used to do this: + + getspritescreencoord(short spritesortnum, long *scrx, long *scry) + + Note that spritesortnum is the index into the spritesortcnt + arrays, NOT the normal sprite arrays. Scrx and scry are actual + screen coordinates ranging from 0-319 and 0-199 respectively. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +6/6/94 - Made EDITART support sprite centering and animation speed. + + Now when you press 'A' in EDITART, the animation speed is + actually saved to disk and runs the same speed in BUILD + and your GAME. Press + and - to change the animation speed. + There are 16 different animation speeds. + (Speed is proportional to (totalclock>>animspeed)) + + To center a sprite, press the weird ~` key (located just above + the TAB key). You will see some cross hairs. Simply use + the arrow keys to the desired position. + + For both the 'A' and ~` keys, you can press Enter to accept + the new values or ESC to cancel. + + - Added a variable to BUILD.H, lockclock. Lockclock is to + totalclock as lockspeed is to clockspeed. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +6/7/94 - Made 3 different Z coordinate modes in BUILD. + + Mode 0: Game mode (default) + Mode 1: Height lock mode + Mode 2: Float mode + + Press Caps Lock to switch between the 3 modes. + A and Z move up and down for all 3 modes. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +6/10/94 - Added a new function that should solve all your sound problems. + + kenchaintimer(void (__interrupt __far *datimerchainaddress)(), + short dachainpersecond) + + Please look at the IMPORTANT ENGINE FUNCTIONS section above for + a full description. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +6/20/94 - Got rid of the comsend / comgetchar functions. Replaced them + with sendpacket and getpacket. + + - Added network support. + + - Got rid of qsetmode320200(). Just replace it with setgamemode(). + The 2 are exactly the same. + + - Got rid of clockspeed variables. Just replace it with lockspeed. + + - Adjusted my z directions of shooting depending on the horizon. + You may want to readjust your code for this. + + - You now pass the number of tics as a long to doanimations. + doanimations(long numtics); + + - FIXED DEADLY BUG! This may have been causing bigtime crash-city + bugs! The problem was with show2dsprite and show2dwall. In + my engine.c I forgot that they were BIT arrays, not BYTE arrays. + When I initialized the arrays to 0, I initialized 8 times the + length, possibly overwriting your precious data! I initialize + these arrays in the initengine and loadboard functions. + + - ATTENTION PROGRAMMERS: In order to get rid of the posx, posy, + posz, ang, posz, and horiz variables from BUILD.H, I added some + parameters to a few functions. YOU MUST REWRITE YOUR CODE + TO SUPPORT THESE: + loadboard(char *filename, long *posx, long *posy, long *posz, + short *ang, short *cursectnum) + saveboard(char *filename, long *posx, long *posy, long *posz, + short *ang, short *cursectnum) + drawrooms(long posx, long posy, long posz, + short ang, long horiz, short *cursectnum) + + THESE VARIABLES SHOULD BE MOVED INTO GAME.C: + long posx, posy, posz, horiz; + short ang, cursectnum; + long hvel; +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +6/22/94 - ATTENTION PROGRAMMERS: Added 1 parameter to movesprite, the + number of tics (such as lockspeed). + + movesprite(short spritenum, long xchange, long ychange, + long zchange, long walldist, + char cliptype, long numtics) + + - ATTENTION PROGRAMMERS: At one time, I used to have 4 timing + variable in the engine. (totalclock, clockspeed, + lockclock, lockspeed). I got rid of all of them except + totalclock. If you want to use the other 3 variables, you + must simulate them yourself. Here's how you do it: + + Step 1. Define clockspeed, lockclock, and lockspeed as global + longs in your code. + + Step 2. Be sure to zero out all 3 variables just before + starting to play each level. (You could zero out + totalclock also.) + + Step 3. Right after every time you call the nextpage() + function, insert this code line for line: + + lockspeed = totalclock-lockclock; + lockclock += lockspeed; + clockspeed = lockspeed; + + You really don't need clockspeed if you have lockspeed. + You should replace all clockspeed's with lockspeed's. + Before, I had both because both totalclock and clockspeed used + to be incremented in the timer handler and could be changed + at any time. + + - I added my own optional random function, krand() which returns + a pseudo-random number as a long from 0 to 65535. Notice that + I put a randomseed variable in BUILD.H called randomseed. + +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +6/24/94 - I just want to try to explain how all of my multiplayer code + works. Theory: Think of the whole program as 2 functions: + + Function 1. Draw the screen (could be 2D / 3D) + Function 2. Move things. (sprites, walls, sectors, and you!) + + My communications in GAME.C work on a MASTER/SLAVE + system where it would be nice if the faster computer was the + MASTER. (Right now, the first computer in is the MASTER). + The big trick to keeping everything in sync (and I do mean + everything- even moving platforms, revolving doors, & subways) + is to call function #2 with the exact same parameters as input + on all computers the same number of times and in the same + order. Now this might seem like a lot of information but it + really isn't! Let me explain the role of the MASTER and SLAVE: + + The MASTER's job: + 1. Read in own input changes + 2. Read in any slave player input changes + (getpackets function - reads in foreign vel, svel, + angvel, & the bits) + + 3. Just before calling the movethings function, send the + input to the movethings function: + A. Master's tic cnt (synctics) + B. Every player's velocities (syncvel, svel, angvel) + C. Every player's status bits (Space, Ctrl, Shift, etc.) + 4. Call the movethings function + 5. Draw screen + + The SLAVE's job: + 1. Read in own input changes + 2. Send own input changes to master. + 3. Read in all master movethings input parameters and + call movethings function for each packet. This may + mean calling the movethings function more than once + between calling the drawscreen functions. This is + waste, but it's the price you have to pay to keep + things in sync. + 4. Draw screen + + + You may ask how do monsters stay in sync even if you are + not sending any monster information over the line. The + answer to this is simple. + 1. You make sure that a random seed starts the same on + both computers. + 2. Only call the rand() or krand() function in the + movethings function. + + Before you try my demo, I wanted to say that, I have + ABSOLUTELY NO ERROR CORRECTION in my code at this point. It + is most certainly my next project. For serial link, I would + recommend a rate of about 14400 baud. In the future, I think + I can optimize the code enough to work at rates as low at 2400 + baud! Let me explain how well certain setups should work + without error correction: + Ken's guesses on how badly it will crash WITH NO ERROR + CORRECTION (Build the way it is now): + + 1. Serial link using 8250 chips - out of sync after 15 + seconds because a few bytes were missed. + 2. Serial link using 16550 chips - out of sync after 10 + minutes because 16550 chips have a 16 byte FIFO and + therefore don't lose bytes as often as the 8250. + 3. Modem - out of sync after less than 5 seconds. + 4. Network - out of sync after 1 minute. Networks love to + lose full packets here and there. + + I will be working on error correction for all of the above + situations. Any error correction techniques I use will be + internal to the engine and completely transparent to you (so + you can start coding now!) If the demo actually works multi- + player, then you may want to look at my GAME keys at the top + of this file again. There are some significant changes. + + * I replaced the old COM functions section at the top of + BUILD.TXT with a COMMUNICATIONS FUNCTIONS section. Please + look through it for descriptions of at least these 2 + functions: + + sendpacket(short otherconnectnum, char *bufptr, short bufleng) + getpacket(short *otherconnectnum, char *bufptr) + + * Another rule to keep in mind while testing: (as if there + aren't enough already) Always make sure you have the + same EXE's and MAP'S or else the games will get out of sync. + + * Connection numbers and Index numbers: + For networks, each computer has a given connection number. + Connection numbers range from 1 to 100. Player number 1 + might have connection number 5 and player number 2 might have + connection number 17. Since a player's connection number + can be anything between 1 and 100, I don't want you to + allocate 100 of every variable such as posx[100]. My + solution was to make index numbers. So in this case: + + connectnum[0] = 5; connectindex[5] = 0; + connectnum[1] = 17; connectindex[17] = 1; + + * Now I'll will describe some new variables at the top of GAME.C + + myconnectnum - connection number of your computer + myconnectindex - index number of your computer + masterconnectnum - connection number of the MASTER computer + screenpeek - index number of which player's eyes you are + looking through. + numplayers - if numplayers >= 2 then multiplayer mode is + enabled, else single player game. + + connecthead, connectpoint2[MAXPLAYERS] - These 2 variables + form a linked list of all the index numbers. + Here's some example code that traverses the list of + players: + + p = connecthead; + while (p != -1) + { + printf("Player index %d has connection number %d\n",p,connectnum[p]); + p = connectpoint2[p]; + } + + * These variables are used to record / playback a demo. (This + is like POSCAPT.DAT, but with everything in sync!) In my + GAME, i single player mode, I have it so if you press the + Left ENTER, then it will playback everything. These are + the only variables necessary to store a demo run: + + static long reccnt; //Number of frames + static short recsyncvel[16384]; //Vel for each frame + static short recsyncsvel[16384]; //Svel for each frame + static short recsyncangvel[16384]; //Angvel for each frame + static short recsyncbits[16384]; //Bits for each frame + static short recsynctics[16384]; //Tics for each frame + + * These variables are used for communications syncing: + + static short syncvel[MAXPLAYERS+1]; //Vel of each player + static short syncsvel[MAXPLAYERS+1]; //Svel of each player + static short syncangvel[MAXPLAYERS+1]; //Angvel of each player + static short syncbits[MAXPLAYERS+1]; //Bits for each player + static short synctics; //Number of tics of MASTER ONLY + + * Unless I suddenly make BUILD a 6-degree of freedom engine + tomorrow, this should be the most difficult update in a long + time! Good Luck in programming! I'm sure I left a lot of + things out, so I'll be expecting plenty of phone calls! +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +6/27/94 - I scaled the vel, svel and angvel variabile down 1 bit so they + fit into a signed char. (Before they ranged from -256 to 256) + Now they range from (-128 to 127). +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +6/28/94 - Optimized the size of my COM(modem)/network packets in game.c. + I made the tics into a char. I also use some new buffers called + osyncvel, osyncsvel, osyncangvel, and osyncbits. Now I send + extra byte with bit fields that tell whether I need to update + the syncvel, syncsvel, syncangvel, or syncbits variables. If + the bit field of the extra byte is off then I don't send the + byte(s) it represents. You can now play my GAME at 4800 baud. + + static signed char syncvel[MAXPLAYERS+1], osyncvel[MAXPLAYERS+1]; + static signed char syncsvel[MAXPLAYERS+1], osyncsvel[MAXPLAYERS+1]; + static signed char syncangvel[MAXPLAYERS+1], osyncangvel[MAXPLAYERS+1]; + static short syncbits[MAXPLAYERS+1], osyncbits[MAXPLAYERS+1]; + static unsigned char synctics; + + - There was an crashing error with transluscence palette on low + memory configurations. When you exit the BUILD editor, + you normally get some numbers like this. + Memory status: 788979(788979) bytes + If the first number (art memory cache size) was less than the + second number (art file size), then the whole art file did + not fit in memory. The reason for the crashing was because + loadpics() sucks all memory up to the size of the art file. + The 64K transluscent palette is malloc'd when you call the + setgamemode() function for the first time. The was no memory + left to allocate the palette. I fixed this by making the + transluscent palette take 64K of the art memory cache if + it could not malloc the 64K. + + - I programmed some error correction for the COM(modem). Here is + my new of Ken's guesses on how badly it will crash (assuming + that it will always crash eventually.) You will be seeing new + and better correction methods in the future. + + ERROR CORRECTION METHOD #1: + 1. Serial link using 8250 chips - out of sync after 5 minutes. + 2. Serial link using 16550 chips - out of sync after 10 minutes. + 3. Modem - out of sync after 3 minutes - try it! + 4. Network - out of sync after 1 minute. Networks love to + lose full packets here and there. (not changed) +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +6/29/94 - Added some code to my GAME.C that will let you type in messages + and send them to all remote players. Press Tab (or T for + those people who play that other, very bad, game too much) + to start typing in a message. Press either Enter key to send + the message to the other player. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +6/30/94 - ATTENTION PROGRAMMERS: I changed the values that clipmove and + movesprite return! Here's how they work now: + If you did not hit anything, then they return 0. + Movesprite only: If the object hits a ceiling / floor + then movesprite returns 16384+(sectornum hit). + If the first object you hit before sliding was a wall, + then they return the 32768+(wallnum hit). + If the first object you hit before sliding was a sprite, + then they return the 49152+(spritenum hit). + + Be careful when adding these changes to your code since the + return value are sort of reversed: + + return values: º Hit nothing: ³ Hit something: + ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÎÍÍÍÍÍÍÍÍÍÍÍÍÍÍØÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ + Old functions: º 1 ³ 0 + ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ×ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÅÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ- + º ³ 16384+sectnum (Movesprite only) + New functions: º 0 ³ or 32768+wallnum + º ³ or 49152+spritenum + +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +7/1/94 - Made getangle always return an angle from 0 to 2047. Before I + forgot to and it 2047 and sometimes the angle was negative. + + - Made overwritesprite when using the centering option be sensitive + to the Editart centering tool. (The ~` key.) + + - Made Ctrl+Rt.Shift highlight points on a loop rather than points + inside a rectangle. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +7/2/94 - Added some neat features to my GAME.C to make multi-player mode + even more fun. I added a portable bowling ball/bomb-thrower. + kills instantly! (similar to rocket launcher) I also added + water fountains. If you hold the space bar down on them, + you slowly get more life. + + - O.K. I think I actually got the syncronization working perfectly + for COM(modem) play. I haven't had all day to test it out yet! + (Still no error correction with networks) + + Here are some steps in playing over the modem: + 1. Be sure that both people have the exact same version of + the EXEs, ART, and MAPs. + 2. Then go into SETUP and set the COM port to the com port + of your modem. Even though 9600 baud should work, I + would recommend going at 4800 baud because: + A. It works fine at 4800 baud so there is really + no need to go any faster. + B. Fewer errors over the modem so less time + spent re-sending packets. + 3. Then type: MODEM [mapname] (must be same mapname!) + This will bring you into my terminal program. You can + set the modem initialization string in MODEM.BAT by + changing the first command line option of the TERM + line. Please disable modem compression and + correction for least jerky play. Then connect with + the other modem using various methods, such as one + person typing ATA and the other typing ATD or one + person typing ATS0=1 and the other typing + ATDT(phone #). + 4. Wait through the beeps and buzzes until it says CONNECT + on the bottom window. + 5. If you can now chat with each other then things are + going well. When the first person presses ESC, both + computers will automatically quit to DOS and go right + into the GAME. + 6. Play! +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +7/5/94 - Serial moder over COM(modem) should work perfectly now. + + - Added scaredfallz to BUILD.H. It is a global variable that + tells monsters what height is too high to fall through. You + can set cliptype parameter to 2 for movesprite and clipmove. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +7/6/94 - Fixed clipping bug that used to let you go through certain concave + corners. + + - Added new function which works well with clipmove. Ever notice + was when you're at the edge of a cliff and you go just a tiny + bit over, you fall, but shouldn't yet? Unlike what you have + been doing, this new function finds the highest and lowest z + coordinates that your clipping BOX can get to. It must search + for all sectors (and sprites) that go into your clipping box. + Currently, you were searching the z's at the center point only + by simply using the sector[].ceilingz and sector[].floorz + variables. + + getzrange(long x, long y, long z, short sectnum, + long *ceilz, long *florz, + long walldist, char cliptype) + + Pass x, y, z, sector normally. Walldist can be 128. Cliptype + can be 0, 1, or 2. (just like movesprite and clipmove) + This function returnes the 2 z maxes in ceilz and florz. + See GAME.C for an example. + + - Fixed bug with weird vertical lines in transluscent masked walls + in chain mode. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +7/10/94 - Made screen capture (F12) work in 2D modes also. It always + saves to a 256 color PCX file. + + - Made screen re-sizeable. Use this easy new function to re-size + the screen: + + setview(long scrx1, long scry1, long scrx2, long scry2); + + It is TOO easy to use. You simply pass is the Upper-left hand + corner and the bottom-right corner in screen coordinates of the + rectangular region you want the engine to draw to. The engine + automatically centers the horizon at the middle of the window and + scales everything properly. + + Notes: + - Since the engine does extra scaling calculations for + window sizes that are not 320 pixels wide, I do not + recommend making the default mode with a window size + just under 320 pixels wide since the engine can + actually run a little slower. (such as 312-319 + pixels wide) Keep them 320 wide. + - Feel free to modify the startumost / startdmost arrays + AFTER a setview call if you want weird window shapes. + Keep in mind that startumost[0] and startdmost[0] are + always refer to the left edge of the viewing window. + (NOT left edge of screen.) +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +7/19/94 - Finally got around to writing the number-of-tiles-per-file + resizer. Simply type rsizeart. All instructions will be + displayed when running the program before the actual + conversion. + + - Fixed a few bugs in Editart. I hope I fixed those evil bugs that + rarely come by. I'm pretty sure I fixed the bug that made the + screen go blank in 'V' mode, and the bug where a few pixels + in the top left corners of tiles sometimes get overwritten. + + - Added a key in Build 2D edit mode. Press 'E' on a sprite to + change its status list number. + + - Fixed those lousy Editart subdirectory colors in 'U' for those + teams with great color palettes, but don't have my ugly shade + of pink. + + - Fixed bug with non-200 high P-skies. The p-skies are now (by + default) centered on the horizon no matter what the height is. + + - Added multiple size PCX and GIF support in Editart. You can now + load pictures up to 1024*256. (That's all that can fit in VGA + video memory) If you need to load a bigger picture than that, + it will be chopped off at the bottom, but will still load the + top piece. + + - I know that I have introduced some wonderful new bugs with the + sprite drawing. I know why they're happening, but I am + looking for a good solution so as to not make you change + any code. I will put another upload with these bugs fixed + soon. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +7/20/94 - Added TRUE ornamented walls. Right now the actual ornamentation + must be programmed by you with 2 simple functions: + + copytilepiece(long tilenume1, long sourcex1, long sourcey1, + long xsiz, long ysiz, + long tilenume2, long destx1, long desty1) + + * This function simply copies any section of a source tile + to any part of a destination tile. It will automatically + skip transparent pixels. It will wrap-around in the + source but not the destination. If for some reason + the destination tile gets removed from the cache, the + destination tile will be reset to original form. This + is why I had to add this second function: + + allocatepermanenttile(short tilenume, long xsiz, long ysiz) + + * This function allocates a place on the cache as permanent. + Right now, I reset the cache every time you call this + function so I would recommend calling this function + right after loadpics. + + I have an example of both of these functions in GAME.C. Try + playing GAME DOOM1.MAP and go into the secret room with + the pictures of Ken. Shoot some walls there. The pictures + with Ken and the Explosion over it were done with + copytilepiece and allocated permanently at tile 4095. A + good idea for allocating permanent tiles would be to start + at 4095 and decrement. You can also allocate a permanent + tile over the original tile itself. + + - Tile panning matching keys work a lot better. They now work + well with bottom steps. Also, it works well with matching + up windows. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +7/25/94 - A week ago, I uploaded a version of BUILD which unfortunately + had more bugs than the previous version. This upload should + have those bugs fixed - especially the sprite bugs. (I hope) + + - I think I may actually have the sprite feet behind stairs bug + working perfectly. + + - The engine should now be even faster the before last week. (A + week ago, I temporarily changed the parallaxing sky algorithm, + making the engine slower in those areas) + + - Added a variable, parallaxyoffs in BUILD.H. It defaults to 0. + If you set it to 100, then all parallaxing skies will be + properly moved 100 pixels higher. + + - Fixed some weird drawing bug related to parallaxing skies and + sprites. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +7/26/94 - Made sprite's sectors dependent on the z coordinates in the BUILD + editor. (Helpful if you use overlapping in your maps) +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +7/29/94 - Made precache function. Simply call: + precache() (no parameters) + right after you call loadboard(?,?,...) and it will load + all tiles in the current board into the cache. Note that + animations of sprites after the first one will not be + precached. I have included my precacheing code at the + end of game.c for those interested in making the precaching + fancy. + + - Fixed bug in editart which made it sometimes save the art files + and names.h in the wrong directory (the last directory you + were in when you were in 'U' mode). You may want to search + your artwork directories to see if you were a victim of this + bug. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +7/30/94 - Made Ctrl-Enter paste parallaxing sky tiles to all neighboring + parallaxing sky areas also. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +7/31/94 - Fixed (most) crashing bugs - Doesn't even crash on the highest + skyscrapers now! Since I can never be SURE that the crashing + is gone, I need you to test it for me - compare the number + of times it crashes per second since the last version. It + should be much better. + + - Fixed sector line bug! Get close to a step, hold down Shift+Z + and the edges of the step will NOT jitter like before AND you + will not get random walls going through the screen. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +8/1/94 - Got rid of the OLD transluscent stuff from overwritesprite and + permanentwritesprite. (Before it used the 8K shading table + which didn't work very well) + + - Added new true 50/50 transluscence option to overwritesprite. + See bit 2 in the next comment. + + - Fixed overwritesprite so it works with different screen sizes. + You don't need to do any scaling calculations! Should be + compatible with old function. Added new bit 1 to orientation + parameter to determine whether or not the sprite should be + scaled and clipped to the viewing window. + + overwritesprite (long thex, long they, short tilenum, + signed char shade, char orientation) + + If Bit 0 of orientation = 0: (thex, they) is top-left corner + If Bit 0 of orientation = 1: (thex, they) is middle + If Bit 1 of orientation = 0: no relation to viewing window + If Bit 1 of orientation = 1: scale and clip to viewing window + If Bit 2 of orientation = 0: normal + If Bit 2 of orientation = 1: 50/50 transluscent! + + * If it works at full screen, simply set bit 1 of orientation + to 1, and it should automatically scale properly! + + - Made it so 2/4/6/8 keys in 3D EDIT MODE now only move the objects + 1 step rather than continuously, giving more control over the + repeat/panning values of things. + + - Made the / key not only reset the repeats of walls, but also for + sprites. It will set both repeats of the sprite to the default + size of 64. If you hold down shift with / on a sprite, it + will give the sprite a square aspect ratio by setting the + xrepeat to equal the yrepeat value. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +8/2/94 - Doubled the board size from: (0 to 65536, 0 to 65536) to + (-65536 to 65536, -65536 to 65536) Notice that the grid in + 2D EDIT MODE is much bigger than before. Since it is very easy + to double the maximum board size, just tell me if you need + a larger board. The only bad thing about allowing larger + boards is that the map designer is more likely to make some + sectors too large and cause overflow bugs. 32 bits can only + go so far you know! + + - I think I MAY have fixed a bug in BUILD that used to make it crash + when quitting. It had something to do with the vertical grid + lines in 2D EDIT MODE when zoomed way in around the upper left + corner of the map (I think). +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +8/3/94 - Optimized Editart loading and saving. + + - Made 'V' screen in Editart 320*400 instead of 320*200. + + - Before I said I fixed the bug in EDITART where a few pixels in the + top left corners of tiles sometimes got overwritten. Well I + lied. This time I really fixed it. (I hope) +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +8/7/94 - Made x&y repeats, x&y pannings easier to adjust. It now works + like the default keyboard handler. It moves once when you + first press the key. A little later, it starts to move fast. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +8/11/94 - Added great new sprite rotation function which works like + overwritesprite (like 2DRAW sprites) + + rotatesprite(long sx, long sy, long z, short a, short picnum) + + (sx, sy) is the center of the sprite to draw defined as + screen coordinates shifted up by 16. + (z) is the zoom. Normal size is 65536. + Ex: 131072 is zoomed in 2X and 32768 is zoomed out 2X. + (a) is the angle (0 is straight up) + (picnum) is the tile number + + Ex: rotatesprite(160L<<16,100L<<16,65536,lockclock<<4,DEMOSIGN); + This example will draw the DEMOSIGN tile in the center of the + screen and rotate about once per second. + + Rotatesprite clips to the same area as overwritesprite but does + not scale or do transluscence yet. + + - Please look at the new permanentwritesprite documentation at the + top of this file! + + - Network should now work again - It now works great on my network + with 3 players! It may possibly also work with 4 or 5 players + too, but I didn't feel like running between 2 rooms to test it! + I never thought the day would come when I would get NET, COM, + and MODEM all working respectably! + + - Changed setup program so you can select 2, 3, 4, or 5 players in + a network game. (The 5 is just to annoy people who like that + other lousy game) + + - ATTENTION BUILDERS! Added TILE MOVING to EDITART! For now, it + will only work WITHIN THE SAME ART FILE. Do the tile moving + all in 'V' mode. Here are the new keys in 'V' mode: + + To swap 2 tiles: + Simply press space bar on the first tile, then space + bar on the second. + To swap a group of tiles: + Press 1 on the first tile, press 2 to remember the region + between where you pressed 1 and 2. Press 3 at the + place to where you want to swap all the tiles. + + Don't forget that this is all SWAPPING, tiles will (should) + NOT be overwritten using these keys. + + - ATTENTION PROGRAMMERS! Added ceildist and flordist parameters to + both clipmove and movesprite. I always had them all set to + (4<<8) by default. + + clipmove(long *x, long *y, long *z, short *sectnum, + long xvect, long yvect, + long walldist, long ceildist, long flordist, + char cliptype) + + movesprite(short spritenum, long xchange, long ychange, long zchange, + long walldist, long ceildist, long flordist, + char cliptype, long numtics) + + - Moved some com/network code from the getpackets function in game + into the engine. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +8/15/94 - Fixed some network initialization code and it now works with 4 + players. (I tested it.) +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +8/16/94 - Added different shirt color support. Here's how you do it: + + allocatespritepalookup(long palnum, char *remapbuf) + + See more documentation of allocatespritepalookup at the top of + this file. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +8/18/94 - I made it so you can redefine the keys in the setup program under + the input devices menu. + + - ATTENTION EVERYONE - for this new version, you MUST go into my + new SETUP program, and SAVE CHANGES AND QUIT once. The arrow + key code will not work if you don't do this! If you are + one of those people who actually read BUILD.TXT, give yourself + 1 point. I wonder who will get "caught" for not reading this! +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +8/22/94 - Added pixel height and wall length information to 2D EDIT MODE + when you press Tab or Alt-Tab on a sector or wall. + + - Now show the actual number of sprites in 2D EDIT MODE. + + - Improved digitized sound routines. Just thought I'd mention it. + + - Added a "save As" feature to 2D EDIT MODE. + + - Now show all lo and hi tags in 2D EDIT MODE on the map itself! + Note that position of the sector tag's text is put at the + average point of all the points of the sector, so if you have + a weird shape tagged sector, the text might show up at an + inconvenient place. + + - You can turn the tag boxes on or off by pressing CTRL-T or by + zooming out. + + - ATTENTION EVERYONE - for the new BUILD.EXE and OBJ's, you will + need to copy my new TABLES.DAT over your old one. Also, you + must go into SETUP and SAVE&QUIT. I have split the TABLES.DAT + file into 2 separate files. They are: + + TABLES.DAT - 10880 bytes - sin tables, fonts, etc. + SETUP.DAT - 23 bytes - (6 options) + (17 custom keys) + + The SETUP.DAT file is the only file SETUP.EXE accesses now. + This means that from now on, if I want to add something to + TABLES.DAT, you won't have to go into the setup program and reset + the options again. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +8/24/94 - Relative alignment now fully works with ROTATION! Relative + alignment will allow ceilings and floors to align with the + first 2 points of a sector. This will relieve you of + programming special ceiling and floor panning code for moving + sectors. + In 3D EDIT MODE, simply press 'R' on a ceiling / floor to switch + between relative alignment mode and normal mode. Notice that + bit 6 of both sector[].ceilingstat and sector[].floorstat are + relative alignment bits. + I have an example of relative alignment in nukeland.map in the + high blue room off the main octagonal room. Also note that my + subways and dragsectors now use relative alignment for panning. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +8/25/94 - I added a new parameter to printext256 and printext16. I need + to document this stuff! +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +8/27/94 - Made it so you can't shrink sprites so much you can't grab them + any more in 3D EDIT MODE. + + - Added (G)oto feature into Build 'V' mode. Simply press G, type + the tile number and it will go there. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +9/7/94 - Fixed relative alignment bugs I noticed. My subway.map won't + crash anymore and the relatively aligned ceilings and floors + should not pan crazily anymore when looking from a far + distance. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +9/9/94 - ATTENTION PROGRAMMERS: I added a new parameter to + overwritesprite. Dapalnum can be from 0-15 depending on + what palette lookup table is being used. Dapalnum is normally + 0. Overwritesprite now looks like this: + + overwritesprite (long thex, long they, short tilenum, + signed char shade, char orientation, char dapalnum) +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +9/13/94 - ATTENTION PROGRAMMERS: I changed the last parameter of drawrooms + (sector number) to be passed as a value, NOT a pointer anymore. + + drawrooms(long daposx, long daposy, long daposz, + short daang, long dahoriz, short dacursectnum) +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +9/15/94 - ATTENTION PROGRAMMERS: I took out the COM(modem)/network code + from my engine.obj and put it into a separate .obj called + multi.obj. (I also removed the sound from my engine and stuck + it in kdmeng.obj) Please include it in your makefile. Here is + a list of ALL of the variables and functions you will need to + know to program for multiple players: + + VARIABLES: (You should extern these in your game.c) + extern short numplayers, myconnectindex; + extern short connecthead, connectpoint2[MAXPLAYERS]; + extern long *lastpacket2clock; + + FUNCTIONS: + initmultiplayers(option[4],option[5]); + uninitmultiplayers(); + + sendlogon(); + sendlogoff(); + + sendpacket(connecthead,tempbuf,j); + sendpacket(-1,tempbuf,j); + leng = getpacket(&otherconnectindex,tempbuf); + + Please see detailed descriptions of these functions at the top + of this file. + + - Multiplayer code is now MUCH cleaner! + + - Please try my game on your networks again! My game now works + perfectly with 3 players on a network that used to crash at + the DOS4GW prompt just a week ago! My game needs only IPX, + no server to run. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +9/16/94 - ATTENTION PROGRAMMERS: CONVMAP5!!! YOU MUST RUN CONVMAP5 ON + ALL OF YOUR MAPS IF YOU WANT THEM TO WORK WITH THE NEW + BUILD.EXE OR OBJ'S! Following are the exact changes I made + to the new map format: + + * Added numextras + * Added sector[].ceilingpal + * Added sector[].floorpal + * Added sector[].visibility + * Split sector[].tag to sector[].lotag and sector[].hitag + * Added sector[].extra + * Expanded wall[].cstat to a short + * Split wall[].tag to wall[].lotag and wall[].hitag + * Added wall[].extra + * Split sprite[].tag to sprite[].lotag and sprite[].hitag + * Got rid of sprite[].extra (the void * mess) + * Added sprite[].extra + + The only thing programmers have to worry about when converting + are the tags. I split them into lo and hi tags. + (See BUILD.H for new structure formats) + + I got rid of the (void *)extra thing from the sprite + structure. I know I may have made some promises it + wouldn't change and it was for your use only, but what + can I say - it's not needed anymore (in other words, + if you're already using it, TOUGH LUCK). I have my + own, new, method for extending sector, wall, or + sprite structures. You will be able to extend any + structure as much as you want AND be able to edit it + all in the BUILD editor to be saved in the permanent + map format. Notice I added a (short)extra to all 3 + main structures. They default to -1. But if they + are >= 0 then they form a linked list out of the + extra structure. NOTE: THIS EXTRA STUFF IS NOT + PROGRAMMED YET! I'm just mentioning it becuase the + new map format has this extendability. I'll try to + get it done soon though. (9/21/94) - Actually just + ignore the fact that this paragraph ever existed. + I'm just keeping it here for history purposes. + + - Renamed my allocatespritepalookup function to makepalookup since + it now also applies to walls, ceilings, floors, p-skies and + masked walls. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +9/20/94 - Added rotated sprites. These new rotated sprites rotate in the + same way as masked walls. Sounds like a waste since the + engine already has masked walls? NOT AT ALL! With rotated + sprites, you can EASILY do TRUE ornamented walls FULLY inside + the BUILD editor with even MORE versatility than that other + game out there. For example, you can place the ornamentation + anywhere on the wall, with sizing control using 2,4,6,8 on the + keypad, and even ornament with transluscence! In 3D EDIT + MODE, simply press 'R' on a sprite to make it a rotated + sprite (Programmers see bit 4 of sprite[].cstat) + + - Fixed crashing bug with sector (Rt. ALT) copy/paste in 2D EDIT + MODE. + + - You can now copy groups of sectors from 1 map to another! Here's + how you do it: + + Step 1: Capture a bunch of sectors with the Rt. ALT selection + tool. + Step 2: With the sectors still highlighted, you can now load + another map and the highlighted sectors will + automatically be inserted into the new map. (They + will still be highlighted) +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +9/21/94 - Fixed bug with cursectnum not always being right after loading + the board. I now check it and make sure it's right when + saving in BUILD now. + + - Added 'O' key in 2D/3D EDIT MODES. It will push a rotated sprite + backwards (using hitscan) into the first wall and + automatically adjust the angle to make the sprite appear + as if it was part of the wall. + + - You can now press 'S' to insert a sprite in 3D EDIT MODE. Press + 'S' on a ceiling or floor. + + - You can now press delete to delete a sprite in 3D EDIT MODE. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +9/22/94 - Programmed Nick & Peter's BUILD stub to their EXACT + specifications. See WSTUB.C for code & documentation. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +9/27/94 - Fixed Rt. Alt block copying nextsector1 pointer bug. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +9/29/94 - Added special bitmapped effect which I either call lava or + boiling slime. See my initlava and movelava functions + inside GAME.C. + + - I added a bit array call gotpic. The engine will set the + respective gotpic bit for each picnum drawn to the screen, + including ceilings, floors, walls, sprites, masked walls - + even overwritesprites, etc. This array is mainly for + making the game only calculate special bitmapped effects + when that certain picnum is on the screen. + + Note 1: The engine does NOT automatically clear the gotpic + bits for you. If you want to test gotpic for a certain + picnum, you should clear it if you want to test it again. + + Note 2: It is not necessary to use permanentwritesprite + for bitmapped special effects - after all, if you see it, + it MUST be in the cache. + + Added to BUILD.H: + EXTERN char gotpic[MAXTILES>>3]; + + Example code in GAME.C: + if ((gotpic[SLIME>>3]&(1<<(SLIME&7))) > 0) //test bit + { + gotpic[SLIME>>3] &= ~(1<<(SLIME&7)); //clear bit + + if (waloff[SLIME] != -1) //if in cache + movelava((char *)waloff[SLIME]); //calculate! + } + + - Added what some people call gamma correction. I think + brightness is a better description though. + + setbrightness(char brightness); + + Simply call this function where brightness ranges from + 0 to 4. Brightness defaults to 0. Levels 1-4 are all brighter + than 0. If you switch between 2D & 3D modes, the engine will + remember the current brightness level. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +9/30/94 - Added a few keys to fake a multiplayer game all on 1 computer. + In my game, press Insert to add a new player at the starting + position, and Delete to delete the last player. Press + scroll lock to get control of the other players. In the same + way Lt. Enter lets you view other players, Scroll lock will + let you control other players (single player game only) +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +10/2/94 - Moved all doanimations code from engine into game.c. If you + are using the doanimations code, here's exactly what you + need to do to make it work with your code again: + + Step 1: Copy these 3 functions which you should find at + the end of my Game.c: + + doanimations(long numtics) + getanimationgoal(long animptr) + setanimation(long *animptr, long thegoal, long thevel) + + Step 2: Move these variables out of BUILD.H and into your + game.c: + + #define MAXANIMATES 512 + static long *animateptr[MAXANIMATES], animategoal[MAXANIMATES]; + static long animatevel[MAXANIMATES], animatecnt = 0; + + * If you copied my door code, you will probably have to convert + some parameters to longs. (oops!) + + - Got rid of printnum from the engine. It is an outdated function. + Use either printext256 or printext16 instead. + + - Added y-flipping for both normal and rotated sprites. (see bit + 3 of sprite[].cstat in BUILD.H. + + - Added y-flipping for walls. (see bit 8 of wall[].cstat in + BUILD.H. + + - Fixed bug with initialization of Master and Slave for + COM(Modem) only. If both computers went in at the same + time, it used to sometimes think both were Masters. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +10/4/94 - Alt-C in 3D EDIT MODE changes all picnums on the whole map + from the picnum in tab to the picnum under the mouse cursor. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +10/6/94 - Fixed y-flipping bug on walls and masked walls. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +10/16/94 - Fixed bug in editart that didn't convert the maps right after + swapping tiles. + + - Added excellent function to my multi.obj. + + long getoutputcirclesize(); + This function returns the number of bytes that have not + yet been copied. If there are still more than say, 16 bytes, + then you may be sending too many bytes per second. This can + happen if the frame rate of a computer is faster than the + speed of the serial mode (Ex: Try 2400 baud with a Pentium 90!) + this function will tell you how many bytes are left to copy + In other words, if getoutputcirclesize() < 16 then it is safe + to send a packet. If you already have serial mode working + all you have to do to update your code is to copy the lines + in my sync() function the deal with the getoutputcirclesize + function. Everything else in sync() and getpackets() is + pretty much the same. + + - Programmed some example code in my game that will allow players + to change masters and slaves during the game without losing + sync. Simply press 'M' in my multiplayer game, and that + computer will become the master! It is interesting how + the frame rate and controllability changes. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +10/31/94 - Added basic scripting to EDITART. Don't expect it to be + everything you ever dreamed of (yet). + + Scripts are saved in a file called CAPFIL.TXT. You can edit the + text file, but be careful not to screw it up too badly (such + as extra commas, spaces in weird places, etc.) since I am + parsing it in EDITART. + + Whenever you select a box in 'U' mode, a line will be appended to + the CAPFIL.TXT file. + + WRITING THE CAPFIL.TXT FILE: + In 'U' mode, you can press 'O' instead of ENTER to select a tile. + What 'O' does that is different from ENTER is that it takes + the center point of the highlighted rectangle, and searches + outward until a total rectangle of transparent pixels (255) + is reached. This is useful for grabbing sprites - not only + will you not have fine adjust to the exact borders of a + sprite now, but when you re-grab from the pcx's you can + change the size of the sprite freely. + + READING THE CAPFIL.TXT FILE: + There are 2 ways to re-grab from the CAPFIL.TXT file. If you + press ALT-U in the main screen, everything will be re-grabbed. + If you press ALT-U in 'V' mode, then you should first select + the range by pressing '1' and '2' on the range boundaries. + + Format of CAPFIL.TXT lines: + Tile #, Full path/file name, x1, y1, xsize, ysize + + Note: If xsize and ysize are 0, then that means you did + an 'O' grab and EDITART will search from point (x1, y1) + when you do a re-grab. + + Example CAPFIL.TXT file: + 31,D:\CAPTUR00.PCX,220,98,64,64 + 110,D:\CAPTUR00.PCX,49,72,0,0 + + The first line says that tile #31 is a 64*64 tile and the + second line says that tile #110 is unknown size tile (grabbed + with the 'O' key) + + Note: You can only do 1 grab per tile with my scripting system. + You may have done your parallaxing skies with several grabs. + If so then try to make the tile into 1 large PCX and do 1 + grab. (The largest grabbing size right now is 1024*256) + + ------------------------------------------------------------------- + + - Made Editart's screen capture (F12) save to PCX's the exact size + of the tile and not include the status bar at the bottom. It + will also save large tiles to large PCX's - Now it's easy and + lossless to extract a tile from Editart! + + - ATTENTION PROGRAMMES! Added 2 new parameters to getzrange for + returning the objects hit on top and bottom. + (sectors / sprites) See my updated documentation at the top + of this file. + + - Fixed clipping bugs with sprites near sector lines. (I hope) + + - Got 3D Red-Blue glasses mode working for all VGA cards. First + set the graphics mode to red-blue mode in the setup program. + The left eye is red and the right eye is blue. There are + 4 keys that let you adjust the 3D view: + [,] = Adjust width between eyes (3D width) + Shift [,] = Adjust width of parallax (2D width) +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +11/1/94 - Guess what? I turned 19 today. Doesn't that just suck. Now, + if you play my build game on my birthday, all the extemely + evil and scary brown monsters will be replaced with super + happy fun dogs that throw smiley red jelly coconuts at you. + Also, my incredibly evil and scary music will be replaced + with super happy music. Actually this whole paragraph is + a joke (except for the birthday part). + + - Made centering work with rotated sprites. + + - Fix centering with x and y flipped sprites. + + - Rotated sprites now get chopped off by the ceiling or floor in + the same way normal sprites get chopped. Sprites do not get + chopped if there is a parallaxing sky / floor. + + - Made Shift + F12 is BUILD 2D mode inverse black and white. + + - If SETUP.DAT is not found then default options are loaded + instead of quitting to DOS. + + - ATTENTION PROGRAMMERS! Added 3 parameters to makepalookup that + allow you to do FOG effects. The first 2 parameters are the + same as before. The last 3 are the color that the palette + fades to as you get further away. Before, this color was + always black (0,0,0). White would be (63,63,63). + + makepalookup(long palnum, char *remapbuf, + char redvalue, char greenvalue, char bluevalue) + + - ATTENTION PROGRAMMERS! Moved 2 things into BUILD.H. Please + make sure to update it: + + #define MAXPALOOKUPS 256 + and + EXTERN char *palookup[MAXPALOOKUPS]; + + The palookup array is an array of pointers that point to the + first byte of each 8K palette lookup table. All 256 pointers + are initialized to NULL by initengine() except for palookup[0] + which is the default 8K palette. This will allow you to modify + the palette lookup table directly for non-snowy fading effects, + etc. Each palette lookup table has 32 shades. Each shade has + 256 bytes. Shade 0 is closest (actual palette brightness) and + shade 31 is farthest (dark usually). (256*32 = 8192 or 8K) +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +11/3/94 - Now show white lines in 'V' mode of EDITART at ART file tile + boundaries. + + - Added Insert and Delete commands to EDITART! These Insert and + Delete keys WILL shift all tiles after the one being inserted + or deleted just like a regular text editor. To insert or + delete tiles, simply go the 'V' screen in EDITART and bang + away! Don't worry these keys are fully multi-tile file + compatible (unlike swapping right now). + You will notice that the white line boundaries that + I just added will actually move if you press Insert or Delete. + This changes the number of tiles per art file. But that's + ok. If the art files ever get too unbalanced, you can run + the RSIZEART.EXE utility to fix it. + Ken's lesson of the day: For the final release of your + games, you only need 1 art file. The reason I spent my time + programming multiple art files was because of EDITART. + Since EDITART need to READ & WRITE to the art files, it must + hold a whole art file in memory at a time. Since Build and + Game only READ the art files, a caching system can be made + and only 1 art file is necessary even for lo-memory systems. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +11/4/94 - ATTENTION MAP DESIGNERS! Added a long-awaited feature to BUILD + which I call "loop joining". Have you ever gotten this + frustrating message in 2D EDIT MODE before? + + "You can't split sector by connecting different loops." + + Well, you're not going to see it any more because I fixed + it! Yup. You can now split a sector along a line connecting + different loops of the sector. + + Try this - Convert the sector on the left to the sector + on the right: + + Split #1 Split #2 + ÚÄÄÄÄÄÄÄ¿ ÚÄÄÄÂÄÄÄ¿ ÚÄÄÄÂÄÄÄ¿ + ³ ÚÄÄÄ¿ ³ ³ ÚÄÁÄ¿ ³ ³ ÚÄÁÄ¿ ³ + ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ + ³ ÀÄÄÄÙ ³ ³ ÀÄÄÄÙ ³ ³ ÀÄÂÄÙ ³ + ÀÄÄÄÄÄÄÄÙ ÀÄÄÄÄÄÄÄÙ ÀÄÄÄÁÄÄÄÙ + (Given) (Half done) (Result) + (1 sector) (Still 1 sector) (2 sectors) + + Before the only was to do this was to delete all the + sectors and then redraw them again. + + I'm sure loop joining has its share of tricks, as most + BUILD functions do, so you may want to spend some time just + playing around with this new function. + + - Removed my own profiler stuff - Hline calculations, etc. code. + Watcom's sampler and profiler is much better anyway. + + - Fixed neartag divide by zero bug with walls (I hope). + Anyone calling neartag for every player per movethings? + I would try not to - How much is that unnoticable extra 0.02 + frames per second worth to you anyway? +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +11/9/94 - Added new array to BUILD.H called gotsector. It works a lot + like the gotpic array, but this array determines which sectors + were considered during the drawrooms function. Note that + gotsector, unlike gotpic IS cleared to 0 during every call + to drawrooms. + + - Fixed Editart 'U' mode mouse control bug. I typed too fast this + time. + + - Fixed Build split sector bug of accidently deleting sprites. It + should not delete any sprites when splitting sectors now. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +11/15/94 - ATTENTION PROGRAMMERS!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + I moved ALL my timer code and arrow key code into GAME.C. + Here are the exact instructions that you need to follow to + upgrade your code to the new obj's: + + 1. From the end of my GAME.C, take the code from these 4 + functions: + + ---> inittimer(); + ---> uninittimer(); + ---> void __interrupt __far timerhandler(); + ---> keytimerstuff(); + + 2. After each initengine, call inittimer right AFTER: + + initengine(); + ---> inittimer(); + + After each uninitengine, call uninittimer right BEFORE: + + ---> uninittimer(); + uninitengine(); + + 3. You may need to include this (if not already included): + + ---> #include + + 4. Add these 2 lines to declare the timerhandler: + + ---> void (__interrupt __far *oldtimerhandler)(); + ---> void __interrupt __far timerhandler(void); + + 5. Since BUILD.H NO LONGER has vel, svel, and angvel, you + must add the following line to your game: + (These variables are modified inside keytimerstuff()) + + ---> static long vel, svel, angvel; + + 6. Let me list some variables that I recently removed from my + GAME. This may or may not affect you: + + oposx[], oposy[], oang[], etc.. - GONE! + lastpacket2clock - GONE! + lastsynctics - GONE! + drawscreen's smoothratio parameter & related code - GONE! + kenchaintimer - GONE! (Don't think anybody was using it + because it didn't solve sound compatibility problems) +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +11/16/94 - Made swinging door clipping work MUCH better! It is much more + difficult to "sneak" through the door now. With the swinging + door clipping working much better, I made it possible to open + doors even if you are in the same sector as the door itself. + Now you won't have to stand back a certain distance to open + the doors. (It is much less annoying this way) Since neartag + does not normally scan cursectnum's sector tags, you will + need to check cursectnum's tags yourself (if you so desire) + + Example: (extracted from my GAME.C) + + neartag(posx[snum],posy[snum],posz[snum],cursectnum[snum], + ang[snum],&neartagsector,&neartagwall,&neartagsprite, + &neartaghitdist,1024L); + if (neartagsector == -1) //If no neartagsector found... + { + i = cursectnum[snum]; //Test current sector for tagging + if ((sector[i].lotag|sector[i].hitag) != 0) + neartagsector = i; //Cursectnum is the neartagsector! + } + + - Improved my gamma correction algorithm. Since it now uses a new + 1K at the end of my TABLES.DAT, be sure to update all your + TABLES.DAT files! My new gamma correction supports 16 levels + of brightness (0-15). You need not change any code in your + game if you already have gamma correction programmed. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +11/17/94 - Made swinging door clipping code work even better. The bug was: + it only tested the clipping if you were in the same sector as + the door. So I put this handy little function in GAME.C which + simply tests if 2 sectors are neighbors or not: + testneighborsectors(short sect1, short sect2) + Check it out! + + - Rewrote my clipinsidebox function. You probably don't use this + function, but if you copied my swinging door code, then you + will need to update this. Clipinsidebox is used for clipping + to determine whether a player or sprite is too close to a + wall. + + clipinsidebox(long x, long y, short wallnum, long walldist) + X and y are the position of the sprite or player. Wallnum + is the wall to test, and walldist is the fatness of the sprite + or player (same as clipmove). It returns a 1 if the sprite or + player's clipping square intersects the wall or 0 if not. + + Example - You can test all 4 walls of a swinging door and make + sure the door doesn't run you over: + + short swingwall[4]; //4 wall indeces of a swinging door + for (i=0;i<4;i++) + if (clipinsidebox(posx,posy,swingwall[i],128L) == 1) + { + //Swinging door swung into player, so move door back to + //its old position / inverse swinging direction. + + break; + } +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +11/22/94 - Made build posx, posy, posz, ang, cursectnum, and horiz variables + nonstatic. + + - Made hi-res screen capture work. + + - Fixed some of those evil view-clipping bugs with rotated sprites + on red sector lines. I think it should work with rotated + sprites on horizontal or vertical red lines. I'm not sure + about weird angled lines. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +11/23/94 - ATTENTION PROGRAMMERS: Made parallaxing skies tileable in any + equal size chunk where the chunk x size is a power of 2 + from 16-1024. You can now make a 2048 wide parallaxing sky + with 2 chunks of 1024 (gobble gobble). + + These lines were added to BUILD.H: + + #define MAXPSKYTILES 256 + EXTERN short pskyoff[MAXPSKYTILES], pskybits; + + pskyoff[MAXPSKYTILES] is an array of OFFSETS of each tile + from the picnum of the parallaxing sky. + + pskybits is NOT the actual number of tiles, but the + log (base 2) of the number of tiles. Look at this table: + + For 1 tile, pskybits = 0 + For 2 tiles, pskybits = 1 + For 4 tiles, pskybits = 2 + For 8 tiles, pskybits = 3 + For 16 tiles, pskybits = 4 + etc. + + + I know that most teams have a 1024 wide parallaxing sky that + wraps all the way around. Don't worry - this is the + default now. When initengine is called, the variables + default to this: + + pskyoff[0] = 0; + pskybits = 0; + + You may have used a 512 wide parallaxing sky (like in my game) + that repeated every 180 degrees. To make this work with + the new version, set these variables like this right after + initengine is called: + + pskyoff[0] = 0; + pskyoff[1] = 0; + pskybits = 1; + + Note that both pskyoff variables are 0 here. This will + make the parallaxing sky repeat. + + With the new tiling, you can save memory by making small + chuck sizes, such as 64 or 128, and repeating certain + sections. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +11/25/94 - Fixed some really stupid keyboard problem in Build. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +11/29/94 - Added FLOOR SPRITES!!! Here are some things that floor sprites + can do for you: + + * Make bridges and balconies + * Use them for ceiling and floor ornamentation + * Use them in place of a rotating sector - modifying 1 angle + is much faster than rotating tons of points. + * Weapon such as a spinning saw blade or, of course, a smiley + red jelly coconut. (?) + * How about a "walking" hole like in Ken's Labyrinth + * You could throw a footstep on the floor every time you make a + step. The steps would go away after awhile. Maybe if you + step in mud, the next 16 or so footsteps will be plotted. + * You could even fake radial shading with a transluscent floor + sprite. (Transluscent floor sprites not yet programmed) + + Just imagine all the great stuff you can do with floor + sprites combined with wall sprites! I can't wait to see what + you all come up with! + + ÚÄÄ To clear some confusion, and to shorten conversations, let + ³ me give official names to my 3 kinds of sprites: + ³ + ³ Normal stupid sprites - "FACE SPRITES" + ³ Rotated / masked wall sprites - "WALL SPRITES" + ³ New ceiling & floor sprites - "FLOOR SPRITES" + ³ + ³ Also let me clear up the 2 kinds of clipping: + ³ + ³ Clipping when moving something - "MOVEMENT CLIPPING" + ÀÄÄ Clipping when drawing something - "VIEW CLIPPING" + + To make a floor sprite in BUILD, simply press 'R' on any + sprite until it becomes a floor sprite. The xrepeat and + yrepeat values should work perfectly with floor sprites. + Floor sprites can be rotated at any of 2048 degrees, using + the sprite[].ang. Press < / > for course angle adjustment + or < / > with shift for fine angle adjustment. Also, you + can press 'F' on a floor sprite to flip it over like a + mirror. I am using another bit in sprite[].cstat to determine + the type of sprite. See the documentation in BUILD.H. + + Now for the bad news: + + * Floor sprite textures have similar restrictions as normal + ceilings and floors - both dimensions must be a power of 2. + This will most likely not change. + + And some known problems which I will have to fix: + * Transluscence doesn't work yet + * Sorting with other sprites + * View clipping with walls + * Doesn't work too well in hi-res mode + + See NUKELAND.MAP for some examples of floor sprites. I have both + a bridge and a balcony on the level. Please find them! + Remember that floor sprites don't work in mode x or hi-res + mode YET! +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +11/30/94 - Made WALL SPRITE and FLOOR SPRITE correctly do movement clipping. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +12/1/94 - Made new map called BRIDGES.MAP. It is excellent! It has 3 + bridges all crossing each other. Enjoy! + + - For Editart, I added re-centering after delete and / to reset + centering while in centering mode. + + - Debugged more of the floor sprite stuff. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +12/2/94 - Made transluscence with floor sprites work. Check out my fake + radial shading under the lights of SUBWAY.MAP. + + - Optimized floor sprites in assembler. Transluscent floor sprites + are a bit slower than normal floor sprites. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +12/6/94 - Made a special 1-way mode for WALL and FLOOR sprites + (not FACE sprites). In BUILD 3D mode, you can press '1' on + a wall or floor sprite to make it only draw if you are on + 1 side of it. This method of back-face culling will not only + make non-masking objects with thickness draw twice as fast, + but will also make fewer drawing bugs due to sprite drawing + order. Try out my BRIDGES.MAP. There's a new section at the + top and it's not another "ugly Ken's face n' slime" room. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +12/8/94 - Editart and Build now capture with capt#### rather than captur## + allowing 10000 captured pictures. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +12/23/94 - Increased Maximum number of walls to 8192. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +12/28/94 - Made BUILD stub keys F5-F8 work in 3D mode also. See top + of BSTUB.C for full documentation of some new useful + variables that can be used inside the stub: + + extern long qsetmode; + extern short searchsector, searchwall, searchstat; + + In 3D mode, F5 and F6 do the exact same thing and F7 and F8 + do the exact same thing (you don't need the extra key to + distinguish between sectors, walls and sprites, since the + mouse cursor can only be on 1 of the 3 objects in 3D mode. + + Note: Since F5-F8 are called in 3D mode, you must be sure + NOT to use any 2D routines during those calls! This means + you will have to put the 3D/2D case check in all six + subroutines: + ExtShowSectorData, ExtShowWallData, ExtShowSpriteData, + ExtEditSectorData, ExtEditWallData, ExtEditSpriteData + + - KEN'S PROPOSAL (NOT YET DONE) I am thinking of making a new + (and maybe final) map format. But before I do it, I am going + to ask all of you for any suggestions on new fields to add to + my 3 big structures (sector, wall, sprite): + + Here are a few things already on my list to add: + + * char sprite[].clipdist - THIS IS FOR SURE + This will be a sprite's clipping distance. My default + walldist is 128. With this field, you will finally be + able to make a unique fatness for each sprite with no + clipping bugs. I will probably shift this field up 2-4 + bits to give it a range of more than just 0-255. + + * char wall[].pal, sprite[].pal - PRETTY SURE + It should have been this way the whole time. Currently + the wall's palookup number is sector[].floorpal. While + it may save some memory, It has too many limitations. + I can make my map converter automatically convert all + walls of a sector to equal the sector[].floorpal so + don't worry about that type of conversion. If I do + this, I can get rid of the spritepal[] hack. + + * I have decided that the sector[].extra, wall[].extra, and + sprite[].extra will remain in the structures as little + gifts for your use only. That's right! ALL YOURS! + ENJOY!!! + + * char sprite[].xoffset, sprite[].yoffset - NOT SURE YET + Some have asked for monster animations using the same + frame at 2 different times of an animation sequence having + different centers. + These will be signed chars. I'm not sure whether to + make these offsets as offsets to the centering information + from Editart or just make them the absolute offsets where + Editart's data is the default offset. I wonder if there's + a better way to do this without having to waste 8K. + + * Do I have your permission to remove nextsector2 and + nextwall2? Anybody using them? If so, can you use the + extra variable instead? This will save 16K since both + are shorts. (MAXWALLS*short + MAXWALLS*short = 16384) + They were originally intended for 2 stories + but it would be totally ridiculous for me even to think + about programming that now. Besides, you can use wall + and floor sprites to fake 2 story areas. KEN PROMISE: + I will fix those darn view-clipping bugs eventually! + + + Please send any comments/suggestions to my internet address + (kjs@lems.brown.edu) I will consider each suggestion + carefully, because everything you suggest now won't have + to be an ugly hack like spritepal[] later. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +1/1/95 - ÛÛÛÛÛ ÛÛÛÛÛÛ ÛÛÜ ÛÛ ÛÛ ÛÛ ÛÛ ÛÛ ÛÛÛÛÛÛ ÛÛÛÛÛÛ ÛÛÛÛÛÛ ÛÛ + ÛÛ ÛÛ ÛÛ ÛÛÛÜ ÛÛ ÛÛ ÛÛ ÛÛÛÜÜÛÛÛ ÛÛ ÛÛ ÛÛ ÛÛ ÛÛ ÛÛ + ÛÛ ÛÛ ÛÛ ÛÛÛÛÛÛÛ ÛÛÜ ÜÛÛ ÛÛßÛÛßÛÛ ÛÛÛÛÛÛ ÛÛÛÛÛÛ ÛÛÛÛÛÛ ÛÛ + ÛÛ ÛÛ ÛÛ ÛÛ ßÛÛÛ ÛÛÛÛÛ ÛÛ ÛÛ ÛÛ ÛÛ ÛÛ ÛÛ ÛÛ + ÛÛÛÛÛ ÛÛÛÛÛÛ ÛÛ ßÛÛ ßÛß ÛÛ ÛÛ ÛÛ ÛÛ ÛÛ ÛÛÛÛÛÛ ÛÛ + + CONVMAP6! Here is what I changed in the structures: + + * Added wall[].pal, sprite[].pal + * Added sprite[].clipdist + * Expanded sprite[].cstat to a short + * Added sprite[].xoffset, sprite[].yoffset + * Removed wall[].nextsector2, wall[].nextwall2 + * Renamed wall[].nextsector1 to just wall[].nextsector + * Renamed wall[].nextwall1 to just wall[].nextwall + * Scrapped numextras and extratype structure - Don't confuse + this with sector[].extra, wall[].extra, sprite[].extra + which ARE in map version 6. + + Probably the only change above that will affect programmers is + getting rid of the '1' in wall[].nextsector1&wall[].nextwall1. + All the following changes were possible because of the new + map format. + + - Got rid of the spritepal array in BUILD.H. With my grea + new map version 6, you can simply modify sprite[].pal! + + - Made all .pal fields editable in 3D EDIT MODE. Press ALT-P + and simply edit the number as you would in 2D mode. + + - Made sprite[].xoffset and sprite[].yoffset work as + offsets to the offsets that are already in EDITART. + Simple addition. They should work for all 3 types + of sprites. + + - Made BUILD Tab&Enter also copy tags&extra if copying similar + structures. Also fixed some other attributes when + copying between structure types. + + - Made sprites highlighted with Rt. Shift duplicate and stamp + when the insert key is pressed in 2D EDIT MODE. + + - Made sprite[].clipdist work as the FACE SPRITE'S clipping + fatness. NOTE: Sprite[].clipdist is shifted up 2 to + allow a range from 0-1020, so if the sprite[].clipdist + is set to 32, then the clipping radius is actually 128. + + - Removed the walldist parameter from movesprite. Movesprite + now just uses the sprite[spritenum].clipdist field of + whatever sprite is passed (shifted up 2). + + movesprite(short spritenum, long xchange, long ychange, + long zchange, long ceildist, long flordist, + char cliptype, long numtics) + + If you use clipmove or getzrange, you should check that you + are passing the correct walldist parameters. I'm saying + you may want to change some of the 128s to + (sprite[spritenum].clipdist<<2). +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +1/3/95 - Made startumost[], startdmost[] into shorts. + + - Optimized and fixed gamma correction in Stereo Red-Blue mode. + + - Made weapons or anything using overwritesprite in Stereo Red-Blue + mode be at screen depth. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +1/4/95 - Not that anybody would care (except for some crazed mega-hackers) + but I am just mentioning the fact that I did this: + + animateoffs(short tilenum, short fakevar); + where fakevar is sectnum+0 + or wallnum+16384 + or spritenum+32768 + or 49152 (just ignore-it's for rotatesprite) + + Also: I changed one: "mov al, 0" instruction into an + "xor al, al", a net savings of + ONE LOUSY BYTE! Let's not get TOO + excited! (By the way, just kidding) +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +1/5/95 - Fixed the sprite centering with x-flipped FACE SPRITES. + + - Found a bug with my swinging door clipping code. There are 2 + types of swinging doors, forwards (opens CCW) and + backwards (opens CW). The bug was that you could sneak + through a backwards door from the back side. Well, I fixed + it, so now I challenge you to sneak through my swinging doors + now! If you are using my swinging door code, please make + these changes which you should find in my new GAME.C: + + 1. Changed declaration at beginning of GAME.C: + static short swingwall[32][5]; + + 2. Added new line in prepareboard: + swingwall[swingcnt][4] = lastwall(swingwall[swingcnt][3]); + + 3. Modified some stuff in tagcode: + //swingangopendir is -1 if forwards, 1 is backwards + l = (swingangopendir[i] > 0); + for(k=l+3;k>=l;k--) + if... + + - Here are some more functions that have been in the engine for + a while, but I forgot to document... + precache, loadtile, lastwall, rotatepoint + They are now documented at the top of this file. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +1/6/95 - Optimized loading/saving of maps by using fewer read/write calls. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +1/14/95 - Fixed evil crashing bug that I accidently introduced in the + 1/3/95 version of Build. This crashing bug happened mostly + in tall rooms with lots of FACE SPRITES. It used to crash + very infrequently when you were standing almost exactly, but + NOT on the same x & y coordinates of a FACE SPRITE where the + z-distance was high. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +1/15/95 - Fixed up network code so now you can miss 4 packets in row safely + over the network rather than just 2. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +1/16/95 - Added strafe left / strafe right keys to my SETUP.DAT file and + char keys[19] array. If you actually use my keys array for + custom keys, here's what to do: I inserted the new strafing + keys at keys[12] & keys[13], so just add 2 to any keys with + an index >= 12. + + - Made the sprites in 2D EDIT MODE of Build highlight properly + again. + + - Added another parameter to permanentwritesprite, palookup number: + + permanentwritesprite(long thex, long they, short tilenum, + signed char shade, long cx1, long cy1, + long cx2, long cy2, char dapalnum); +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +1/17/95 - You can now select a bunch of sprites in 2D EDIT MODE with + Rt. shift, then go to 3D mode and change the z's of all the + highlighted sprites. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +1/20/95 - Made Tab&Enter in 3D EDIT MODE copy .pal also whenever .shade is + normally copied. Shift+Enter will now copy just + .pal and .shade. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +1/21/95 - Made Splitsector work with overlapping better. + + - In Editart 'U' mode, it now goes automatically to the PCX and + coordinates of a tile if it is already in capfil.txt. + + - In Editart, made capt????.PCX not get overwritten if they already + exist. + + - Fixed Build tab on masked walls. + + - Made zmode and kensplayerheight variables public in BUILD/BSTUB + so you can now compile BUILD to start out with your own + preferred settings. Kensplayerheight defaults to 32 and + zmode defaults to 0. You can over-ride these settings in + the new ExtInit function. + + - Made Editart tiles much easier to center by showing all tiles + in the center of the screen instead of at the top-left corner. + (Editart will not allow you to center tiles larger than + 320*200 right now) + + - Made 'O' (optimize) key in Editart automatically preserve + the centering information. + + - ATTENTION BSTUB PROGRAMMERS! Added ExtInit, ExtUnInit, and + ExtCheckKeys to BSTUB.C. Please just copy mine into your + current BSTUB. ExtInit and ExtUnInit are called only once. + ExtInit is called before loadpics() and after initengine(). + ExtCheckKeys() is called just before nextpage in both 2D + and 3D modes. In 3D mode, you must call editinput inside + ExtCheckKeys just like my example in BSTUB. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +1/24/95 - Fixed vertical line chained mode bug with permanentwritesprites. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +1/31/95 - Fixed parallaxing sky tiling bug. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +2/1/95 - Fixed network crashing bug when call interrupt 0x1c. You call + this interrupt when you chain to the old timer handler. Now + + - Rewrote multiplayer code in game.c a bit. Moved both sync() + and getpackets() into the main program. The master code and + single player game code are now the same. Slaves need to + drawscreen and send packets only when a packet is received + from the master. Got rid of fake sync[MAXPLAYERS] slot by + using a local sync buffers. Rewrote checkmasterslaveswitch(). + If you don't get what I did, it doesn't matter because you + already have working network code! + + - Added new key in EDITART 'V' mode. Press ALT-R to generate + a tile frequency report. It will scan all MAP files in the + same directory as the ART files. The frequency count will + show up as text in the top-left corner of the boxes in + 'V' mode. Press ALT-R again to turn off text. + + - Perfected NCOPY! Copies about 150K / second which is 10 times + faster than a 115200bps serial cable. Since NCOPY already + links with multi.obj, it should not be too difficult to make + joining work in the middle of a network game. Please wait + until I make some sample code for you! + Receiver types: NCOPY (Ex: "NCOPY") + Sender types: NCOPY [filespec] (Ex: "NCOPY *.ART") + + Ken's formula: + NCOPY + Loading&Saving GAMES = joining in middle + of network game! + + - Made a DOOM to BUILD converter. Right now it only converts + ceilings, floors, and walls now, and some of the wall + textures are screwed up. Just because I converted some + lousy stinkin' maps DOES NOT MEAN I AM GOING TO PROGRAM DOOM! + Unfortunately, the converter is programmed in QuickBasic right + now, it won't compile, and I didn't feel like putting up the + 7 MEG converted ART file up. When I convert it to C, I'll + upload it for all! +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +2/7/95 - Fixed overwritesprite bugs with translucence in chained mode + and above top of screen. + + - Made bit 3 of overwritesprite x-flip the picture if set. + + - Optimized various parts of engine. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +2/8/95 - Fixed shading of all sprite types so they match perfectly with + their surroundings. Floor sprites now shade in the exact same + way as ceilings and floors. (Before, the whole floor sprite + had the same shade throughout) +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +2/9/95 - Started on loading and saving game code so I could give some + sample code for joining network games, but none of it works + yet, so just ignore it for now! + + - Added frame rate in BSTUB.C. It averages the last 16 frames. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +2/16/95 - Added another bit to sprite[].cstat for y-centering control. If + bit 7 is set then the sprite's center will be the actual + center rather then at the default position which is at the + bottom of the sprite. If you use this centering bit, + you finally get "WYSIWYG" centering contol in EDITART. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +2/24/95 - Made floor sprites now support any x size by a power of 2 y size. + (That's better than before!) These are the same restrictions + on walls. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +2/25/95 - Got loading / saving code to work with my game. Press Ctrl-L to + load game and Ctrl-S to save game. Saved games are called + SAVE0000.GAME and are about 300K. Don't worry about the large + sizes of the saved game files since they can be easily + compressed to less than 50K. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +2/26/95 - I Finally made my multiplayer code run with fast frame rates AND + pefect controls on ALL computers of a multiplayer game. I am + now sending keystrokes of all computers at a constant rate of + 40 times per second. All computers interpolate between frames + to get screen frame rates of higher or lower than 40 fps + (even in single player mode). + + Here are the exact steps you will need to follow if you want to + update your code: + + 1. WHAT'S THE FAKETIMERHANDLER()? + + To send packets exactly 40 times a second, it would + sure be nice to send them right from the timer interrupt + handler. Too bad network packets just won't get sent + from the interrupt handler. (It may work from the + interrupt handler in Serial/Modem mode) So the solution + is to make a "fake" timer handler that must be called + at least 40 times a second even on the slowest computer. + Throughout my engine, I call faketimerhandler(). If you + have any slow parts in your game code, you may want to + called faketimerhandler() also. + Besides the very first few lines, the rest of the code + was taken directly from my old sync and getpackets + functions. + + 2. BYE BYE SYNCTICS! + + Now that all computers are calling movethings a + constant number of times a second, you don't need any + synctics variables anymore. You can convert all the + synctics variables to a define such as: + "#define TICSPERFRAME 3" + Doing this will guarantee that a game runs the same on + all speed computers. + + 3. FRAME INTERPOLATION (optional): + + static long ototalclock = 0, gotlastpacketclock = 0; + static long oposx[MAXPLAYERS], cposx[MAXPLAYERS]; + static long oposy[MAXPLAYERS], cposy[MAXPLAYERS]; + static long oposz[MAXPLAYERS], cposz[MAXPLAYERS]; + static long ohoriz[MAXPLAYERS], choriz[MAXPLAYERS]; + static long ozoom[MAXPLAYERS], czoom[MAXPLAYERS]; + static short oang[MAXPLAYERS], cang[MAXPLAYERS]; + + Add to prepareboard: + for(i=connecthead;i>=0;i=connectpoint2[i]) + { + oposx[i] = posx[i]; + oposy[i] = (etc.) + } + ototalclock = 0; + gotlastpacketclock = 0; + + Even though you may be getting more than 40fps, you will + only be seeing 40fps unless you interpolate between frames. + The oposx[], etc. variables back up the last posx[], etc. + variables so you can interpolate your actually drawing + position as some fraction between the two. This fraction + is smoothratio. + See beginning of drawscreen code. Here's where I actually + calculate the interpolated position to draw the screen. + + for(i=connecthead;i>=0;i=connectpoint2[i]) + { + cposx[i] = oposx[i]+mulscale(posx[i]-oposx[i],smoothratio,16); + cposy[i] = oposy[i]+mulscale(posy[i]-oposy[i],smoothratio,16); + cposz[i] = oposz[i]+mulscale(posz[i]-oposz[i],smoothratio,16); + choriz[i] = ohoriz[i]+mulscale(horiz[i]-ohoriz[i],smoothratio,16); + czoom[i] = ozoom[i]+mulscale(zoom[i]-ozoom[i],smoothratio,16); + cang[i] = oang[i]+mulscale(((ang[i]+1024-oang[i])&2047)-1024,smoothratio,16); + } + + Draw the screen using cposx[], etc. instead of posx[], etc. + + #pragma aux mulscale =\ + "imul ebx",\ + "shrd eax, edx, cl",\ + parm [eax][ebx][ecx]\ + modify [edx]\ + + It reads: eax = (eax*ebx)>>cl. Unlike C, this will + not overflow even if eax*ebx > 2^31, making full use of + the 64-bit result of the imul instruction. + + 4. MOVETHINGS FIFO: + + static long movefifoplc, movefifoend; + static signed char baksyncvel[64][MAXPLAYERS]; + static signed char baksyncsvel[64][MAXPLAYERS]; + static signed char baksyncangvel[64][MAXPLAYERS]; + static short baksyncbits[64][MAXPLAYERS]; + + Add to prepareboard: movefifoplc = 0; movefifoend = 0; + + It is bad to call movethings inside faketimerhandler + because you don't want things to move while you're drawing + the screen. To solve this, I made movethings just save + away the parameters it was called with using a circular + buffer, and when I'm actually ready to DO the movement code, + I call domovethings. + Rename movethings to domovethings and see my new + movethings. This code is all for the fifo. + + Put this line in movethings: + gotlastpacketclock = totalclock; + + At the top of domovethings, copy my code for loading off + of the fifo. Also set oposx[] = posx[], etc. here. + + 5. You may want to add a global variable that controls whether + you are in continuous packet sending mode or not. Only + in the main loop should ready2send be != 0. + static long ready2send = 0; + + 6. The new main loop can be as short as this, with no case + checking for masters and slaves. + + ready2send = 1; + while (keystatus[1] == 0) //Main loop starts here + { + //Actaully move everything here. + while (movefifoplc != movefifoend) domovethings(); + + //Second parameter is for frame interpolation, + //A fraction that ranges from 0-65536. + drawscreen(screenpeek,(totalclock-gotlastpacketclock)*(65536/TICSPERFRAME)); + } + ready2send = 0; +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +3/6/95 - New key in BUILD. Now when you use relative alignment mode on + ceiling and floor textures, you can press Alt-F on the ceiling + or floor to choose a new wall to align to. It actually + rotates the walls of a sector by 1. + + - Fixed screen capture PCX saving bug in both EDITART and BUILD. + + - Added a parameter to screencapture, a filename. + screencapture(char *filename) + Ex: screencapture("captxxxx.pcx"); + Please specify the full filename. Screencapture will modify + the 4 x's of the string to be a number starting at 0000. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +3/8/95 - Made my rotatesprite function use Editart centering information. + The center is the pivot point of rotation. + + - Added y-flipping to overwritesprite. See above documentation. + + - Added 2 new parameters to rotatesprite, shade and pal + + rotatesprite (long sx, long sy, long z, short a, + short picnum, signed char shade, char pal); + +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +3/10/95 - Fixed sprite showing through closed sectors bug. + + - Made it possible to draw the overhead map in 3D mode by adding + a line drawing function in 3D mode called drawline256. It + draws a line clipped to the viewing rectangle last set in + setview(). Here are the parameters: + + drawline256(long x1, long y1, long x2, long y2, char col); + + Note: The coordinates are all shifted up 12. + Example: drawline256(0L,0L,319L<<12,199L<<12,31); +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +3/11/95 - Made drawline256 draw in a cleaner way, making use of the full + 12 bits of precision. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +3/14/95 - Optimized / cleaned up parts of hitscan, neartag, cansee. + Gee, I hope they all still work! +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +3/18/95 - I'm back in RI! + + - Fixed recently added movesprite z parameter bug that may have + done strange things with monsters, such as stuck in sectors + I thought the following expression: !(cstat&128) + would be true if bit 7 was a 0, but I WAS WRONG! + Get this straight: + ! - logical NOT, returns 0 if != 0 else 1 (!2457=0, !0=1) + ~ - bitwise NOT, xor's it with 0xffffffff (~0x5f=0xa0) +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +3/21/95 - Gave access to some more variables in BSTUB. + + - Made clipmove return a valid sector even if you're not between + its ceiling and floor. If you use overlapping sectors, + clipmove will find the sector closest to your z. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +3/28/95 - Optimized transluscence for masked walls and wall sprites. + + - Today is the day I declare my serial/modem error correction code + perfect! Sure, I may have bragged over and over again about + how perfect my correction method is each time, but this time + I mean it. This is ship-it quality error correction. The old + method had a few dark, evil, and ugly bugs that sometimes + totally screwed up bigtime. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +4/5/95 - Got Master/Slave switching to stay in sync again with new + multiplayer code. Right after the master sends a packet + where a switch is made, I disable the master from sending + any more packets by setting ready2send to 0. Ready2send + will be set back to 1 only after the actual switch in + checkmasterslaveswitch. Here's what I added to movethings: + + //Do this for Master/Slave switching + for(i=connectpoint2[connecthead];i>=0;i=connectpoint2[i]) + if (syncbits[i]&512) ready2send = 0; +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +4/10/95 - Optimized continuous setview calls between 2 different window + sizes. + + - ATTENTION PROGRAMMERS: Moved movesprite code into game.c. It + no longer exists in the engine. It is a "cover-up" function + and it should be yours. + + - Added a circular keyboard buffer to my keyboard handler. It is + fully compatible with the keystatus arrays. Use this buffer + for typing in messages or cheat codes. If you do not use this + buffer (or you wrote your own interrupt handler), you will miss + keys and it is very annoying. + + I added these variables to build.h: + + #define KEYFIFOSIZ 64 + EXTERN volatile char keyfifo[KEYFIFOSIZ], + keyfifoplc, keyfifoend; + + Every time a key is pressed and released, I add 2 bytes to the + circular buffer. The first byte is the scan code. The second + byte is a 1 for key pressed or 0 for key released. You can + ignore the key releases if you wish. You must read 2 bytes at + a time from this buffer. + (scancode,keystat),(scancode,keystat),... + + Here's how you read the keyboard fifo: + while (keyfifoplc != keyfifoend) //More characters to read + { + ch = keyfifo[keyfifoplc]; + keystate = keyfifo[(keyfifoplc+1)&(KEYFIFOSIZ-1)]; + //Increment buffer pointer + keyfifoplc = ((keyfifoplc+2)&(KEYFIFOSIZ-1)); + + printf("Scancode: %d, status: %d\n",ch,keystate); + } + + The interrupt handler does the same as above but writes and + increments using keyfifoend as the index. + You can easily clear the buffer this way: + keyfifoplc = keyfifoend + + - Made clipmove/getzrange not clip on the back side of a 1-sided + wall/floor sprite. It makes the clipping a little faster + and seems to fix a few minor clipping bugs. Don't get too + excited. + + - Fixed getzrange's ceilz/florz mismatch with floor sprites against + normal ceilings and floors. + + - Made Build default to y-centered centering mode when sprites + are inserted (bit 7 of sprite[].cstat) + + - Fixed clipmove bugs with y-centered centering mode. + + - Made it so you don't get stuck sliding along multiple properly + aligned wall/floor sprites. + + - Please update to my new tables.dat. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +4/11/95 - Optimized parts of clipmove / getzrange. Is it faster? Did I + make more bugs? + + - Made the movesprite code in GAME.C now use getzrange. This + allows sprites to walk on floor sprites and bombs roll across + bridges. I will include the original movesprite code that + came from the engine in case you want to start with things + the way they used to be. + + - Made ornamentation in BUILD 3D mode much easier. Now you can + press 'S' to insert a sprite on walls (not just ceilings + and floors). When you insert a sprite on a wall, it will + automatically be set to a wall sprite at the wall's angle. + Also it will be 1-sided with blocking off (The optimal + options for a decorative sprite on a wall). + + - Added ALT-D to BUILD 3D mode. It lets you type in clipdist + for sprites. It works in the same way as ALT-P for palookup + changing. + +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +4/15/95 - Fixed return value bug in setanimation and cleaned up these 3 + functions: doanimations, getanimationgoal, setanimation. + Since they are now in game.c, you will need to copy them to + update. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +4/16/95 - Fixed hitscan not passing through loops bug. + + - Fixed hitscan so it hits wall and floor sprites in the right + places. + + - ATTENTION PROGRAMMERS!!! Made bit 8 of sprite[].cstat the + hitscan clipping bit. It works like the hitscan bit for walls. + Note that both the wall and sprite cstat variables now have + 2 separate bits for clipping, where: + 1 is for use with the clipmove/getzrange function and + 1 is for use with the hitscan function only. + Before, hitscan used to use 1 bit for all sprite clipping. + In your maps, the sprite hitscan bits are all zeros. That's bad! + To make things work like they used to, the sprite hitscan bit + must be set equal to the old sprite blocking bit. So I was nice + enough to make a program, FIXSPRBT.EXE, which will do just that. + + PLEASE RUN FIXSPRBT.EXE ON ALL YOUR MAPS. You don't HAVE to + run it on all your maps since the map format hasn't changed, but + it will save you annoying attribute setting time if you do. + + - Did a few things to make these blocking bits easier to edit: + Since H and ALT-H were already used, I made CTRL-H toggle the + hitscan bit for both walls and sprites in 2D mode. B toggles + the blocking bit. B also now sets the hitscan bit to its + default value when you press it. For sprites, the hitscan bit + default is equal to the clipmove bit. For walls, the hitscan + bit default is always 0. + + - Added new map mode! Check it out in my game. I now have 3 map + modes. Not that this really matters to you game programmers, but + this is how my game works: + dimensionmode[snum] == 1 3D MODE + junky line map + dimensionmode[snum] == 2 SUPER MAP! + dimensionmode[snum] == 3 3D MODE + + I added show2dsector to BUILD.H which controls which works + like the other show2d... bit arrays. It tells which sectors + to show. + EXTERN char show2dsector[MAXSECTORS>>3]; + + I rewrote parts of drawoverheadmap to accommodate this new + mode - so it would be nice if you updated to my new code. + + Added a new function that clears full screen to a specified + color: + clearview(0L); + + Oh and did I forget to mention the big function! Parameters + are the exact same my drawoverheadmap function: + drawmapview(cposx,cposy,czoom,cang); + + Note: The new map mode right now is slowed down bigtime by + the face sprites using the rotatesprite function. The + rotatesprite right now is using a worse than awful + algorithm. When I optimize rotatesprite, the frame rate + of the new map mode will fly! +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +4/18/95 - Added default sprite cstat variable when you insert new sprites. + Set it to 0 if you hate the new centering mode in ExtInit + or 128 if you like the new centering mode. + Add this line to your Bstub if you wish: + extern short defaultspritecstat; + + - If a wall & sprite are same distance away using hitscan, hitscan + now chooses the sprite. + + - Optimized rotatesprite. + + - ATTENTION PROGRAMMERS: Added new paramater at end of + rotatesprite: A char where the first bit tells it to use + transluscence mode or not. + + rotatesprite(long sx, long sy, long z, short a, short picnum, + signed char dashade, char dapalnum, char dastat) + + if ((dastat&1) == 0) - no transluscence + if ((dastat&1) != 0) - transluscence + + - Cleaned up drawmapview further by making ALL floor sprite draw + with the texture in the right place and made the polygon + filling algorithm use higher screen coordinate precision. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +4/19/95 - Added parameter to makepalookup: + + makepalookup(long palnum, char *remapbuf, + signed char r, signed char g, signed char b, + char dastat) + + if ((dastat&1) == 0) then makepalookup will allocate & deallocate + the memory block for use but will not waste the time creating + a palookup table (assuming you will create one yourself) + if ((dastat&1) != 0) then makepalookup will allocate & deallocate + the memory block AND create a palookup table using the rgb + values you pass. + + - Made my ceiling&floor update the self-modified palookup pointers + when palookup[sector[].?pal] changes, not just when + sector[].?pal] changes. Watching for changing pointers rather + than changing indeces should solve the problem with screwy + palookup selection for ceilings&floors. Ignore what I said + before. You should now be able to change palookup pointers + freely. + + - Optimized relative alignment. It should be the same speed as + all other ceilings & floors now. + + - Warning: Since I added the new bit in sprite[].cstat, there are + now 9 bits in use. Make sure to treat it as a short. In my + code, I had some bugs where I did this: + sprite[].cstat &= (255-4); BAD! Cstat's a short! Please + check your code and make sure you clear the bits this way: + sprite[].cstat &= ~4; +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +4/21/95 - Fixed bug with flipping textures on ceilings & floors. In + BUIL0419.ZIP I had a bug whenever a ceiling or floor texture + had bit 4 set. It drew the texture backwards. Well, I + fixed it. Hope you didn't "Build" on this bug! +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +4/22/95 - Fixed really really stupid hitscan returning sector < 0 bug. If + you were calling hitscan from the top-left triangular region + of the board it stupidly returned a -1 for the sector. Well, + I fixed it. + + - ATTENTION EVERYBODY!!! Moved setup.dat loading from the engine + into GAME.C and BSTUB.C. If you copy this code from game.c + into your game / bstub, they will work like it used to: + + ----- NEW GLOBAL VARIABLES: ----- + + #define NUMOPTIONS 8 + #define NUMKEYS 19 + static long chainxres[4] = {256,320,360,400}; + static long chainyres[11] = {200,240,256,270,300,350, + 360,400,480,512,540}; + static long vesares[7][2] = {320,200,640,400,640,480, + 800,600,1024,768, + 1280,1024,1600,1200}; + static char option[NUMOPTIONS] = {0,0,0,0,0,0,1,0}; + static char keys[NUMKEYS] = + { + 0xc8,0xd0,0xcb,0xcd,0x2a,0x9d,0x1d,0x39, + 0x1e,0x2c,0xd1,0xc9,0x47,0x49, + 0x9c,0x1c,0xd,0xc,0xf, + }; + + ----- Put this where you call initengine ----- + + long fil; + + if ((fil = open("setup.dat",O_BINARY|O_RDWR,S_IREAD)) != -1) + { + read(fil,&option[0],NUMOPTIONS); + read(fil,&keys[0],NUMKEYS); + close(fil); + } + if (option[3] != 0) moustat = initmouse(); + + switch(option[0]) + { + case 0: initengine(0,chainxres[option[6]&15],chainyres[option[6]>>4]); break; + case 1: initengine(1,vesares[option[6]&15][0],vesares[option[6]&15][1]); break; + case 2: initengine(2,320L,200L); break; + case 3: initengine(3,320L,200L); break; + case 4: initengine(4,320L,200L); break; + case 5: initengine(5,320L,200L); break; + case 6: initengine(6,320L,200L); break; + } + + ----- That's it! ----- + + Initengine now has 3 parameters: + initengine(char davidoption, long daxdim, long daydim) + See revised initengine description at the top of this file. + + Now that engine.c doesn't use setup.dat, you can use your + own setup program. + + Don't forget to update BSTUB! + + NOTE!!! While MY setup program allows you select many different + video modes, no new modes are supported yet in BUILD! + (It's on my list.) + + + - Fixed keyboard repeating. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +4/26/95 - Hi-res now works in all modes! The code I gave in the 4/22/95 + description is still perfectly valid, so please copy it if + you haven't already looked at it. Here are some important + new variables I put in BUILD.H: + + EXTERN char vidoption; + EXTERN long xdim, ydim, ylookup[MAXYDIM+1]; + + Vidoption is simply the first parameter you pass to + initengine. Xdim and Ydim are the screen sizes you pass to + initengine, such as 320*200 or 640*480. + Ylookup is a lookup table that works like this: + If (vidoption == 0) ylookup[i] = ((i*xdim)>>2); + if (vidoption != 0) ylookup[i] = i*xdim; + There is 1 exception: If you are using a chained mode which + can only fit only 1 viewing page, then the engine actually + does a screen-buffer mode and blits to the chained screen + so for this case, ylookup[i] = i*xdim. + + - Added bit to the dastat parameter of rotatesprite. + if ((dastat&2) != 0) - align to screen size so the gun or + whatever is always over the same relative spot of the screen. + Works like bit 2 of the flags parameter in overwritesprite. + + - Added pixel writing and reading that will work in all BUILD + graphics modes. They work just like you think they should. + + plotpixel(long x, long y, char col); + char getpixel(long x, long y); + + Please do not overuse these functions! They are NOT intended + for fast drawing! + + - Changed tables.dat so parallaxing skies at high resolutions + work accurately. + + - I made bit 15 of sprite[].cstat the invisible bit. If it is + set, then the sprite won't even be considered for sorting and + there is absolutely no speed loss due to its existence. It is + faster to use this bit then manually set thesprite[] to -1. + + Since drawrooms collects the list of sprites drawmasks is about + to sort, make sure the bit is set before drawrooms. If you use + frame interpolation, you usually want to tell drawmasks somehow + to not draw yourself. Before you used to use the + thesprite[] = -1 trick. Now you do it like this: + + sprite[i].cstat |= 0x8000; //Set invisible bit + drawrooms(posx,posy,etc.); + sprite[i].cstat &= ~0x8000; //Restore invisible bit + + - Fixed distance overflow bug (the one that showed garbage + textures if a wall was really far away). +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +4/27/95 - Made an example board, MONWALK.MAP, where monsters walk along + a bridge with no railing, onto a sector, and even up and down + a stairway without falling off it. If you shoot a brown so + it's almost dead, it will turn transluscent. If it's + transluscent, it won't shoot bullets. It is much easier to + test the monsters' walking when they don't shoot! + + - Try my new and improved fake network player mode! Each fake + network player now gets their own window. Use insert and + delete to add or remove players. Use Scroll lock to switch + which window you control. If you have a Pentium, I would + recommend trying this out in 640*480 mode. + + - Noticed a bug with my movesprite code: + For clipmove, I was getting the z-coordinate right, but for + getzrange I forgot to subtract half the sprite's height if + the sprite was using the real centered centering mode. + + These lines set daz to the actual center of sprite i no matter + what centering mode is used: + + daz = sprite[i].z; + if ((sprite[i].cstat&128) == 0) + daz -= ((tilesizy[sprite[i].picnum]*sprite[i].yrepeat)<<1); +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +4/28/95 - ATTENTION PROGRAMMERS! When a tile is not in the cache: + Before it used to be this: + + if (waloff[tilenum] == -1) loadtile(tilenum); + or + if (waloff[tilenum] < 0) loadtile(tilenum); + + Now it's this: + + if (waloff[tilenum] == 0) loadtile(tilenum); + + PLEASE MODIFY YOUR CODE IF YOU USE WALOFF! + + Windows can allocate memory with addresses so high, they + are negative. That makes the (waloff[tilenum] < 0) + method totally stupid and attempt to reload from disk + the tile constantly! I can think of 3 reasons why I + originally designed my system in this fashion: + mestupid, mestinx, and merottts. + + - Fixed visibility for different screen sizes. + + - ATTENTION PROGRAMMERS! Now multiply by visibility rather than + shift right by visiblity so you get a broader range of + visibility. If you want the visiblity to work like before, + use this conversion table: + + Old visibility New visibility + 8 -> 16384 + 9 -> 8192 + 10 -> 4096 + 11 -> 2048 + 12 -> 1024 + 13 -> 512 + 14 -> 256 + 15 -> 128 + + - Made Alt-F make the selected wall the first wall of a sector. + This is useful for quick relative alignment adjustments. + Alt-F for 2D and 3D modes may not work for sectors with loops + inside of them. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +5/1/95 - Optimized horizontal line setup code from 9 multiplies to + 7 multiplies. + + - Fixed dark vertical lines in parallaxing skies bug I recently + introduced. + + - Optimized horizontal line assembly code so it doesn't use the + awful SHLD instruction any more. This is a good speed + improvement for Pentiums only. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +5/2/95 - Added some code to my GAME.C which detects when a computer gets + out of sync in a multiplayer game. It's not as easy as you + may think with all the faketimerhandler and fifo crap. If + you want to put this code in your game, search all areas in + my code with the keyword "syncval". + + - Fixed palookup crashing bug. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +5/6/95 - Moved windowx1, windowy1, windowx2, windowy2 variables into + BUILD.H. They are the exact parameters you passed to the + last setview call. Please DO NOT modify them directly. + Use setview to modify them. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +5/10/95 - Fixed makepalookup bug when shading to non 0. + + - Fixed palookup pointer setting bug. + + - ATTENTION PROGRAMMERS! I made a new cacheing system which allows + any type of object to be allocated in my cache, such as + artwork tiles and sounds or whatever else you may want to + put on the cache. This may or may not affect you. If you + haven't been hacking into my code, then you shouldn't have to + change your code. The cacheing routines have been moved into + a separate module, cache1d.obj. If you link engine.obj, then + you must also link cache1d.obj. Please update your makefiles. + + For anybody who may want to re-write my cacheing system, here's + how it now works: (I have only 3 functions in cache1d.obj + right now, initcache, uninitcache, and allocache) + + Allocate a nice BIG buffer, like from 1MB-4MB and + call initcache(long cachestart, long cachesize) where + + cachestart = (long)(pointer to start of BIG buffer) + cachesize = length of BIG buffer + + Ex: initcache(FP_OFF(pic),cachesize); + + Loadpics calls this function for you so you don't normally + need to call it. + + call allocache(long ptr, long siz) whenever you need to + allocate a temporary buffer, where + + ptr = (long)(pointer to (4-byte pointer to thing))\ + siz = number of bytes + + Ex: if (waloff[tilenume] == 0) + allocache((long)&waloff[tilenume],walsiz[tilenume]); + + Allocache is totally tile independent. To allocate a sound + on the cache, you can call allocache. + + There are 3 functions in the engine which help manage the + cache for you: loadpics - calls initcache + loadtile - calls allocache + allocatepermanenttile - special function + that allocates permanent memory + from the cache. + + - Fixed clipmove crashing bug when passing a sectnum < 0. Whenever + you moved in BUILD and you weren't in a valid sector, memory + was getting trashed. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +5/12/95 - Added ExtPreCheckKeys(void) to BSTUB.C. It is called before + drawrooms / drawmasks in 3D mode, whereas ExtCheckKeys(void) + is called after drawrooms / drawmasks (and before nextpage). + + - Added bit to flags of rotatesprite to allow x-flipping. See + updated documentation. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +5/17/95 - Added aspect ratio for those weird modes like 320*400, etc. + You could call setaspect to properly adjust a mode that is + not exactly correct, or for special effect that stretch + the screen. + + In ENGINE.OBJ, I added a function, setaspect(long daaspect), + where you pass the Y/X aspect ratio scaled up 16 bits, so + 65536 would be normal. You don't need to call this if you + don't want to. By default, in setview, I call setaspect + with these parameters: + + setaspect(divscale16(ydim*320,xdim*200)); + (also written as:) + setaspect(((ydim*320)<<16)/(xdim*200)); + + Note that in 320*200 mode the value passed would be 65536 + which is a 1:1 aspect ratio. + + In BUILD.H, I added yxaspect and xyaspect. + + When you call setaspect(daaspect), + + yxaspect = daaspect; + xyaspect = (1<<32) / yxaspect; //reciprocal + and other internal variables, so DON'T MODIFY YXASPECT + AND XYASPECT DIRECTLY! + + Since drawmapview is also affect by the aspect ratio, you + will need to make sure drawoverheadmap is affected so + the map modes match up. Please look at and copy my updated + drawoverheadmap function into your GAME.C if you use it. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +5/18/95 - Revised caching system so it supports locking. + Here are the new parameters to allocache: + + allocache(long *bufptr, long bufsiz, char *lockptr) + *bufptr = pointer to 4-byte pointer to buffer + bufsiz = number of bytes to allocate + *lockptr = pointer to 1-byte locking char. 1=locked, 0=not + + And uninitcache works a little differently too: + Call uninitcache(0) to remove all UNLOCKED items or + Call uninitcache(1) to remove ALL items. + After calling uninitcache, you do not need to call + initcache to use the cache again. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +5/21/95 - Made changespritesect and changespritestat return 0 instead of -1 + when changing to same value. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +5/25/95 - Added relative visibility for sectors. In 3D EDIT MODE, use + ALT+(keyp.)+/- to change an individual sector's visibility. + Press Shift in addition for fine visibility changine. By + default you change it by 16. Press CTRL+ALT+(keyp.)+/- to + change the global visibility. The global visibility is not + saved in the map. + + - Can now delete many sectors at a time. Select sectors with the + rt. Alt. Then press Ctrl-delete on any highlighted sector to + delete all the highlighted sectors. + + - Fixed build sometimes not saving when quitting from 2D mode bug. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +5/27/95 - Fixed bugs in network work that should make it miss packets + much less often than before. + + - Fixed bug in ncopy so it shouldn't halt or crash anymore. + + - Added spritecstat[] the thesprite arrays. Please use my + thesprite arrays rather than modifying the sprite directly + since hitscan and clipmove use bits 4 and 8 of sprite[].cstat. + + - ATTENTION PROGRAMMERS: Added 1 parameter to neartag that will + allow you to search only lotags or only hitags. See updated + documentation above. + + neartag (long xs, long ys, long zs, short sectnum, short ange, + short *neartagsector, short *neartagwall, short *neartagsprite, + long *neartaghitdist, long neartagrange, char tagsearch) + + If tagsearch = 1, neartag searches lotag only + If tagsearch = 2, neartag searches hitag only + If tagsearch = 3, neartag searches lotag&hitag + + Neartag used to always search both lotag&hitag. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +5/30/95 - Added ExtAnalyzeSprites(void) to BSTUB and a spriteshade array + to BUILD.H. + + - Made circle drawing in 2D EDIT MODE work better at large sizes. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +6/5/95 - Added shareware / registered artwork version control to EDITART. + In 'V' mode, when you press ALT-R to get a report of tile + frequencies of tiles on all the maps in the current directory, + you can toggle the shareware/registered bit with the space bar. + This bit is saved in the top bit of the picanm bits so it is + stored permanently in the art file. Press ALT-D in this mode + to automatically delete all registered tiles. Please before + you do the deleting phase, copy all artwork to a temporary + directory!!! It is safe, however, the toggle the new bit in + the full version. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +6/7/95 - Made 3 main structures defined with typedef so struct prefix + is no longer needed with sectortype, walltype, and spritetype. + + - Added new function to engine: + + short sectorofwall(short dawall); + + It returns the sector of a given wall. It is well optimized + including sector[sector[].nextwall].nextsector if a red wall + and a binary search on the sector[].wallptr's if it is a + white wall. On average, sectorofwall should have to scan + through only 10 different sector indeces to find the right + sector (not 1024!). + + - ATTENTION PROGRAMMERS! Made all the separate thesprite arrays + into a single array of sprite structures call tsprite. See + BUILD.H!!! This means: + + spritepicnum[i] is now tsprite[i].picnum + spritex[i] is now tsprite[i].x + spritey[i] is now tsprite[i].y + spritez[i] is now tsprite[i].z + spriteshade[i] is now tsprite[i].shade + spritecstat[i] is now tsprite[i].cstat + spritepal[i] is now tsprite[i].pal + thesprite[i] is now tsprite[i].owner <<<============ + + Everything above is straight forward, except for thesprite, + which has been renamed to owner. + + All other tsprite parameters, such as .xrepeat, .yoffset, + etc. can also be modified without changing the real + sprite structure so the game won't out of sync. + + - Made tsprite[].statnum be a priority variable for sorting sprites + that are the exact same distance from you. I think higher + means more in front. + + - Made clipmove allow you to cross any red sector line when the z's + of the next sector are farther apart. This may solve clipping + bugs such as when you're in water. You may be able to remove + some work-arounds you may have programmed previously. + + - NEW FILE GROUPING SYSTEM!!! + My system will first search for the stand-alone file in the + directory. If it doesn't find it, then it will search for it + in the group file. If it still doesn't find it then -1 city. + Use KGROUP.EXE to create a grouped file from a lot of other + files. Type KGROUP [grouped filename][filespec][filespec][...] + For example this line will create the new grouped file, + stuff.dat, including all the following files specified: + kgroup stuff.dat *.art *.map tables.dat palette.dat + Feel free to make your own batch files. If there is demand, + I can make kgroup support appending, replacing, and extraction. + + Here is the file format of a grouped file: + ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ + ³ 12 bytes - File grouping ID ³ + ³ 4 bytes - Number of files ³ + ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ + ³For each file: (16 bytes per file) ³ + ³ 12 bytes - Filename with extension (13th byte would be a 0) ³ + ³ 4 bytes - Length of file ³ + ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ + ³ Pure, raw file data, ordered just like you think it would be ³ + ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ + There just couldn't be a simpler format. This format is so + hacker happy that when you view it in a hex editor, all the + filenames line up perfectly since they're multiples of 16. + Anybody who can't figure this out, of course, not only rots, + but is probably one of those really stupid people who would + actually "pay" to get the full version of a game. + + The engine currently supports grouping for: + *.ART, *.MAP, TABLES.DAT and PALETTE.DAT. If you want + to group your own files, you will have to use my loading + routines rather than the standard ones for those files. My + file routines are basically an extra layer around the standard + lo-level functions. Look at these 5 routines I currently + support: + + Welcome to the K-routines! + open -> kopen4load(char *filename) + read -> kread(long handle, void *buffer, long leng) + lseek -> klseek(long handle, long offset, long whence) + filelength -> kfilelength(long handle) + close -> kclose(long handle) + + Note that you only pass the filename to my kopen4load function. + + Here are 2 other routines that you MUST use, whether you like + my file grouping system or not: + + initgroupfile(char *groupfilename) + Call this with the name of your grouped file before + any possible file loading will the k-routines. Note that + tables.dat uses the k-routines and it is in initengine(). + Please don't give your grouped filename an extension that + starts with W, ends with D, and has a vowel in between. + And don't even bother to write your own file grouping + system because even if you do, people still have to write + their own new utilities to read the ART and MAP files. + + uninitgroupfile() + Call before quitting to DOS. + ------------------------------------------------------ + - ATTENTION PROGRAMMERS! Changed kopen4load from: + + kopen4load(char *filename) + to: + kopen4load(char *filename, char searchfirst) + + where: + if searchfirst = 0 then search stand alone first then group file + if searchfirst = 1 then search group file only +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +6/12/95 - Tracked down an OUT OF SYNC bug with my multiplayer code! + In my GAME.C, the way I had my sync arrays organized were + wrong. The problem was that if faketimerhandler was + called during domovethings, the sync arrays may have been + changed, getting the game out of sync. The solution is + to keep the sync arrays in domovethings totally separate + from the sync arrays in faketimerhandler. I split my sync + arrays into 2 separate arrays, sync and fsync, where fsync + and osync are for use BEFORE the FIFO only (such as + faketimerhandler and getpackets), and sync is used AFTER + the FIFO only (such as domovethings). PLEASE SPLIT YOUR + SYNC ARRAYS AS I DESCRIBED! + + - The OUT OF SYNC message doesn't flicker any more. See the + section of code in GAME.C where I set syncstat. + + - Fixed up a waitforeverybody function for network games which + waits for everybody to be at a certain part of the game. + Waitforeverybody also uses getpackets message number 5. + + - Added new clipping function that will push players away from + walls that are too close. It solves A LOT of movement + clipping problems. It can be pretty darn slow if it detects + that you're too close to a wall, so I'd recommend using it + only for players. + + pushmove (long *x, long *y, long *z, short *sectnum, + long walldist, long ceildist, long flordist, char cliptype) + + The parameters are exactly the same as clipmove but with no + xvect or yvect. Pushmove returns either a 0 or -1. If + it returns a -1, then that means that it could not push + the player away from the offending wall after 256 tries. + When this happens, then you should kill the player + instantly, because this only happens when the player is + getting smooshed. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +6/13/95 - Made clipinsidebox and clipinsideboxline return 0 if line doesn't + intersect box, 1 if line intersects box and center of box + is in front of line, or 2 if line intersects box and center + of box is behind line. + + - Cansee should now work properly with overlapping. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +6/19/95 - ATTENTION! Remove work-arounds!!! Found nasty getzrange bug. + Getzrange used to let you fall through red sector line cracks + when you were near more multiple red sector line sharing the + same 2 sectors. Sound familiar anybody? + + - Made pushmove return the sector of whatever x and y end up in. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +6/22/95 - I included cache1d.c renamed to cache1d.txt in this upload. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +6/26/95 - Made face and wall sprites of clipmove, getzrange, hitscan, and + neartag sensitive to the y-offset that you set in Editart. + + - Made one sprite sorting case work perfectly: where multiple + sprites have the same x and y location (and priority). The + sorting still doesn't work perfectly, but this one case can + solve many of the current sprite sorting bugs, such as + inserting a floor sprite of blood below a dead body. + + - Fixed some sprite drawing clipping bugs for wall and floor + sprites. Now, wall sprites and floor sprites should not + show through walls, ceilings, or floors when they're not + supposed to. Also, I fixed a case where wall sprites + disappeared when they happened to be between 2 white walls + that clipped it. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +6/27/95 - Fixed even more sprite drawing clipping bugs for wall sprites. + + - BONUS!!! Wall sprites now clip to white walls! (not red walls) + If you ornament a wall, make sure that neither endpoint of the + wall sprite is behind the wall or else it will get clipped. + Please run lookatme.map from my game.exe which demonstrates + some of the things you can do in build now without bugs. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +6/30/95 - Made drawline256 clip with startumost/startdmost. + + - Moved keyboard handler into GAME.C. Here's what you need to do + to use my keyboard handler (see my GAME.C): + + 1. Some global variables: + + #define KEYFIFOSIZ 64 + void (__interrupt __far *oldkeyhandler)(); + void __interrupt __far keyhandler(void); + volatile char keystatus[256], keyfifo[KEYFIFOSIZ]; + volatile char keyfifoplc, keyfifoend; + volatile char readch, oldreadch, extended, keytemp; + + 2. _initkeys() + + 3. uninitkeys() + + 4. keyhandler() + + 5. Make sure to call _initkeys and uninitkeys. A good place + would be next to where you call inittimer / uninittimer. + + I didn't put my keyboard handler into BSTUB since I am using + keystatus throughout build.obj. Besides I didn't want to anybody + too bad of a headache for one upload. + + [ Updated "initkeys" to "_initkeys", above. This is to + intentionally crash the linking process for games that + haven't updated to use the port's engine; otherwise, the + keyboard driver init won't run, and god knows what would + happen then. --ryan. ] + + - Did you know that screencapture inverses black and white if you + hold either shift key down? This option is useful for + printing out board maps. Since I don't own the keyboard + any more, I had to make screencapture take inverseit as the + second parameter. + + screencapture(char *filename, char inverseit); + + Ex: screencapture("captxxxx.pcx",keystatus[0x2a]|keystatus[0x36]); + + If (inverseit == 0) then nuttin' special + If (inverseit == 1) then super-reverso blacko-whiteo mode! + + I also had to move the stereo adjustment keys into game.c + Just search for the "stereo" keyword in GAME.C. It'll take + through all the necessary places. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +7/5/95 - Moved my keytimerstuff from my timerhandler into getinput. + (which is where it should be) +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +7/10/95 - Added a loadtilelockmode variable to BUILD.H. It's a global + variable that makes future loadtile calls allocate their + buffers on the cache as unlocked (0-default) or locked (1). + I decided to make this a global variable rather than a + parameter to save some people from rewriting code. + + EXTERN char loadtilelockmode; + + - Made my 2D EDIT MODE space bar code clear out new sectors and + wall structures to 0. (except for the extras which are -1) +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +7/20/95 - I forgot to documenent rotatesprite bit 3, which controls + whether or not the sprite will be clipped to the startumost + /startdmost arrays. If the bit is a 1, then the sprite will + not be clipped. This mode is useful for doing status bars + at variable resolutions. What you do is instead of calling + permanentwritesprite, you call rotatesprite with the scaling + bit and startumost/startdmost clipping bit off. For non + screen-buffer modes, be sure to call rotatesprite for each + page of the mode. Use the numpages variable in BUILD.H to + get the number of video pages used. + + - Added clipping box parameters to rotatesprite: Here is the + prototype now: + + rotatesprite (long sx, long sy, long z, short a, short picnum, + signed char dashade, char dapalnum, char dastat, + long cx1, long cy1, long cx2, long cy2) + + For your information, rotatesprite used to choose default + clipping box sizes using this code: + + if ((dastat&8) == 0) + { //0,0,xdim-1,ydim-1 + cx1 = windowx1; cy1 = windowy1; + cx2 = windowx2; cy2 = windowy2; + } + else + { + cx1 = 0; cy1 = 0; + cx2 = xdim-1; cy2 = ydim-1; + } + + Now both permanentwritesprite and overwrite can both be + replaced with rotatesprite which now does everything. + To replace permanentwritesprite, you must make sure to + draw to all the pages in numpages. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +7/27/95 - Fixed recently introduced build 3D mode bug when you press the + L.ENTER key on a blank map. Also made sectorofwall return -1 + if an invalid wall is passed to it. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +7/28/95 - Added a function to my game that shows only the local area of + the map by scanning through the nextsectors of walls and + setting the show2dsector, show2dwall, and show2dsprite + arrays properly. You should call this function any time + (show2dsector[cursectnum>>3] & (1<<(cursectnum&7))) == 0) + That means it's not showing the sector you're currently + in. You should also manipulate show2dsprite any time you + insert or warp a sprite. + + - You know the one thing in my engine that doesn't work in chained + mode? Well I fixed it! + + - Fixed a bug which made it print out of sync when it really + wasn't (This bug probably only affecting my game.) In + getsyncstat, I was calling updatecrc16() with things other + than chars, making it index invalid parts of the crctable + array. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +7/30/95 - Reduced some overhead memory: + * Removed walsiz[] array. (16K saved). If you ACTUALLY used + this array, you can multiply tilesizx[]*tilesizy[] instead. + * Made sqr table from longs to shorts with same precision. + * Removed tantable. (4K saved) + * Reduced internal constant, MAXWALLSB, from 4096 to 2048 + (96K saved). +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +8/1/95 - Added another bit to rotatesprite for top-left corner mode and + made documentation of the stat bits more clear. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +8/3/95 - Fixed a bug with rotatesprite so it now scales perfectly to the + full screen view when enabling bits 2 and 8 of the stat field. + This means that with rotatesprite, you can easily get your + status bars, etc., to work at any resolution. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +8/4/95 - New Doom->Build update! You can now convert doors and lots of + other weird things. Fixed more conversion bugs. Sprites now + convert properly in doom-artwork mode. You can now convert + PWADS. + + - Added some wacky aspect ratio keys to 3D EDIT MODE of BUILD. + Use Rt.Ctrl Rt.Alt Lt.- or Rt.Ctrl Rt.Alt Lt.= to select. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +8/12/95 - Added parameter to initmultiplayers to allow who becomes + master at the start of a multiplayer game. + + - Added parallaxyscale variable to BUILD.H which control the ratio + at which the parallaxing skies scroll in relation to the + horizon. Default is 65536. With lower values, you don't + need as much artwork and can look higher, but I like 65536 + because it is the correct projection. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +8/13/95 - Had MAJOR bug with my searchmap function. If you use it, please + re-copy from my game.c +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +8/14/95 - Fixed some EVIL bugs with Rt.ALT sector copying. It shouldn't + screw up your maps anymore! And if you have maps that were + screwed up with it, you can try my new map correcting key, + L.Ctrl+L.Shift+L.Enter. This key will not affect an already + perfect map. However it can SOMETIMES clean up a map that + was screwed up. I take no responsibility if it screws up + your map even more, so please check them before saving! diff --git a/buildengine/build2.txt b/buildengine/build2.txt new file mode 100755 index 0000000..318ad4a --- /dev/null +++ b/buildengine/build2.txt @@ -0,0 +1,1665 @@ +// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman +// Ken Silverman's official web site: "http://www.advsys.net/ken" +// See the included license file "BUILDLIC.TXT" for license info. + +BUILD engine Notes (7/24/96): + +BUILD programmed by Ken Silverman + +BUILD.TXT CONTINUED... (BUILD.TXT WAS GETTING TOO BIG!!!) +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +8/12/95 - Added parameter to initmultiplayers to allow who becomes + master at the start of a multiplayer game. + + - Added parallaxyscale variable to BUILD.H which control the ratio + at which the parallaxing skies scroll in relation to the + horizon. Default is 65536. With lower values, you don't + need as much artwork and can look higher, but I like 65536 + because it is the correct projection. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +8/13/95 - Had MAJOR bug with my searchmap function. If you use it, please + re-copy from my game.c +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +8/14/95 - Fixed some EVIL bugs with Rt.ALT sector copying. It shouldn't + screw up your maps anymore! And if you have maps that were + screwed up with it, you can try my new map correcting key, + L.Ctrl+L.Shift+L.Enter. This key will not affect an already + perfect map. However it can SOMETIMES clean up a map that + was screwed up. I take no responsibility if it screws up + your map even more, so please check them before saving! +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +8/16/95 - Added error correction to mmulti.obj. Mmulti.obj is like + multi.obj but it is made to work with Mark's real mode + multiplayer driver that he calls COMMIT. + + + MMULTI.OBJ vs. MULTI.OBJ: + * initmultiplayers is the same, but the parameters are ignored + * uninitmultiplayers can be called but does nothing. + * sendlogon can be called but does nothing. + * sendlogoff sends packet 255 to everybody else. It does not + need to be called any more. + * sendpacket and getpacket are the same. + * connecthead, connectpoint2[], numplayers, myconnectindex + are the same. They can be externed just like before. + * getoutputcirclesize always returns 0. It is not needed. + * setsocket does nothing. The socket is now in commit.dat. + * crctable can still be externed. + * syncstate can still be externed but is not used. + * Do not use the option[4] variable. Initmultiplayers will + always return a valid number in numplayers from 1-16. + + + You can link mmulti.obj in place of multi.obj and use + commit.dat as the setup file for multiplayer options. + + There are 2 ways you can run your game through commit: + 1. Set the launch name (usually game.exe) in commit.dat + and type something like "commit map01 /asdf" + 2. Type "commit launch game map01 /asdf". This method + is easier if you want to use the debugger with commit + since you won't have to change commit.dat constantly. + Ex: "commit launch wd /tr=rsi game map01 /asdf" + + I have not tested mmulti.obj with my BUILD game yet because + I have been using 2DRAW as my test program. I may put up a + new version of mmulti.obj with better error correction for + extremely error-prone lines soon. + + - Kgroup can now accept a parameter as a filename with a list of + files to be put into the group file. + Ex: "kgroup @filelist.txt" +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +8/18/95 - Found a way to greatly reduce slave "hitching" on multiplayer + games for faketimerhandler style communications. It's pretty + simple. + + Step 1: In the beginning of faketimerhandler, change + + ototalclock = totalclock; + TO: + ototalclock += TICSPERFRAME; + + This makes the timing of the game more constant and to + never miss ticks. I should have done this in the first + place all along. + + Step 2: In getpackets, (for slaves only) count the number of + times movethings is called. Normally, movethings should + be called exactly once for every time getpackets is called + inside faketimerhandler. The hitching is because + movethings is called in a 0-2-0-2-0-2 cycle instead of the + standard 1-1-1-1-1-1 cycle. This happens because the + timers of the 2 computers are aligning in such a way that + the slave is receiving the master's packets at nearly the + same time as it calls getpackets. To correct the problem, + if movethings is called an even number of times, I randomly + add or subtract (TICSPERFRAME>>1) to ototalclock. Throw + this code at the end of getpackets: + + Beginning of getpackets: + movecnt = 0; + + Where slave receives buffer in getpackets, next to movethings: + movecnt++; + + End of getpackets: + if ((myconnectindex != connecthead) && ((movecnt&1) == 0)) + { + if (rand()&1) ototalclock += (TICSPERFRAME>>1); + else ototalclock -= (TICSPERFRAME>>1); + } + + - Found a way to interpolate anything using the doanimations + code for faketimerhandler style multiplayer games. It's not + as hard as I thought it would be (and it doesn't waste too + much memory!) To smooth out doanimations, since there's no + temporary variables that can be thrown away like with tsprite, + the current doanimations positions must be backed up at the + beginning of drawscreen and restored at the end of drawscreen. + If you want smooth up&down doors, do this: + + Global declaration: + static long oanimateval[MAXANIMATES]; + + Beginning of drawscreen: + for(i=animatecnt-1;i>=0;i--) + { + oanimateval[i] = *animateptr[i]; //Backup doanimations interpolation + + j = *animateptr[i]; + if (j < animategoal[i]) + j = min(j+animatevel[i]*(totalclock-gotlastpacketclock),animategoal[i]); + else + j = max(j-animatevel[i]*(totalclock-gotlastpacketclock),animategoal[i]); + + *animateptr[i] = j; + } + + End of drawscreen: + //Restore doanimations interpolation + for(i=animatecnt-1;i>=0;i--) *animateptr[i] = oanimateval[i]; +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +8/19/95 - Added global invisibility variable. Initengine sets it to 0 + by default. If you set global invisibility to 1, then + all sprites with the invisible bit set (sprite[].cstat&0x8000) + will be shown. This is useful for editing invisiblie sprites. + + - Made the hitscan blocking bit for sprites be the bit checked + when using cliptype 1 instead of the blocking bit. Before + I was accidently using the clipmove blocking bit on sprites + with cliptype 1. I should have done it this way in the first + place. I hope you haven't "built" around this bug too much! + Here's how everything works now: + + Clipmove blocking bits: + Which bits: + wall[].cstat & 1 + sprite[].cstat & 1 + Used in these cases: + clipmove when cliptype = 0 + getzrange when cliptype = 0 + + Hitscan blocking bits: + Which bits: + wall[].cstat & 64 + sprite[].cstat & 256 + Used in these cases: + clipmove when cliptype = 1 + getzrange when cliptype = 1 + hitscan always +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +8/20/95 - Reduced some overhead memory by combining 2 large internal + arrays which were used in different parts of the engine. + This is a total savings of about 90K. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +8/24/95 - Changed the way 'E' mode works on ceiling and floor textures. + 64*64 and 128*128 textures are the same as before so I think + this won't screw up your existing maps. (But I can never be + sure) Now, 'E' mode always smooshes the texture size by 2 for + any size texture. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +8/29/95 - ÜÛÛÛÛÛÛÜ ÛÛ ÜÛÛÛÛÛÛÜ ÜÛÛÛÛÛÛÜ ÜÛÛÛÛÛÛÜ ÜÛÛÛÛÛÛÜ ÛÛ ÛÛ ÛÛ + ÛÛ ÛÛ ÛÛß ßÛÛ ÛÛ ÛÛ ÛÛ ÛÛ ÛÛ ÛÛ ÛÛ + ßÛÛÛÛÛÛÜ ÛÛ ÛÛ ÛÛ ÛÛÛÛÛÛÛß ÛÛÛÛÛÛ ßÛÛÛÛÛÛÜ ÛÛ ÛÛ ÛÛ + ÛÛ ÛÛ ÛÛÜ ÜÛÛ ÛÛ ÛÛ ÛÛ ßß ßß ßß + ßÛÛÛÛÛÛß ßÛÛÛÛÛÛÛ ßÛÛÛÛÛÛß ÛÛ ßÛÛÛÛÛÛß ßÛÛÛÛÛÛß ÛÛ ÛÛ ÛÛ + + New 3D EDIT MODE BUILD keys: + Press [ or ] on a ceiling or floor to change the slope. + Shift + [ or ] on a ceiling or floor to adjust finely. + Press / to reset a ceiling or floor to slope 0. + Use Alt-F in either 2D or 3D mode to change the slope's hinge. + + Sector fields used for slopes: + The useless groudraw fields, ceilingheinum and floorheinum, + are now being used as the slope value. They are treated + as signed shorts, where 0 is slope 0, of course. To enable + slope mode, you must also set bit 1 of the ceilingstat or + floorstat bits. + + Known bugs: + There are still a few bugs that I haven't gotten around to + fixing yet. They're not necessarily hard to fix - it's just + that there are a lot of little things that need to be updated + (on my part). + + - Hitscan does not hit slopes correctly. + - Rare divide overflow bug in my wallmost function only when + you're very close to a red sector line of a slope. + - Relative alignment for slopes not yet programmed. Relative + alignment for slopes will allow square aspect ratio for all + slopes of slopes. + - ALT-F code with passing loops would be nice. + - Visibility not implemented for slopes yet. + - Sometimes an annoying tiny wall is drawn at sector lines. + + Don't call me to tell me about these bugs. I know about them. + And if I didn't list your favorite bug of the day, it will + probably be brought up by the 2 internal teams now working + with BUILD. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +9/4/95 - Made ALT-F select any wall of a sector, even crossing loops. + In 3D mode, ALT-F now sets the selected wall directly to the + first wall. + + - Fixes related to slopes: + * Relative alignment now works. Use relative alignment on high + slopes if you don't like the way the texture is stretched + out. + * Flipping now works + * Panning now works + * Fixed seams for SOME (not all) slope borders + + - My wonderful divide overflow bugs in wallmost aren't quite as + rare as they used to be. Wait a minute - I thought I was + supposed to document bug fixes here! This is what you get + for wanting BUILD tonight. As soon as I fix these darn + divide bugs, I'll put up a new version. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +9/5/95 - Fixed all known divide overflow bugs related to wallmost. I + haven't gotten a divide overflow yet in the last few hours, + but that doesn't guarantee that you'll never get one. Take a + look at GROULAND. It has a cool new cylindrical tunnel. On + the other side of the level is my house in Rhode Island. + + Known bugs with slopes now: + - Hitscan does not hit slopes correctly. + - Visibility not implemented for slopes yet. + - Clipmove will not allow you to walk off high sloped cliffs. + + - Also, I noticed a rare sprite drawing clipping bug. I + don't know if this is new or not. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +9/7/95 - Fixed an exception 0xe bug by using tsprite[MAXSPRITESONSCREEN-2] + instead of tsprite[MAXSPRITESONSCREEN-1]. I don't understand + why this fixed it so I expect that it will come back to haunt + me. Oh happy day. :( + + - I forgot to document 2 new and useful functions in the engine: + + long getceilzofslope(short sectnum, long x, long y); and + long getflorzofslope(short sectnum, long x, long y); + + Returns the z coordinate of the ceiling/floor at that x, y + location. If the sector doesn't have a ceiling/floor slope + then it immediately returns the sector[].floorz or + sector[].ceilingz so it's not that slow. You may want to + check for slopes yourself ceilingstat&2/floorstat&2 if you + think the overhead of calling these functions are too slow. + + - Made clipmove use getceilzofslope and getflorzofslope when + checking for overlapping. + + - Cleaned up mirror code for non-chained modes a little bit. The + mirrors should no longer have a stay line on the right anymore + for these modes. + + - Added Chain-Buffer mode. See my new SETUP.EXE. Chain-Buffer + is a combination of the chain and screen buffer modes - a + buffered chain mode. This mode is faster than standard chain + mode when a lot of screen memory is being read, for example + when you use transluscence or mirrors. Also, Chain-Buffer + mode is cleaner than screen-buffer mode since you don't see + memory being copied to the screen. Unfortunately, in most + cases, Chain-Buffer is the slowest of all modes. Actually, + Chain-Buffer mode sucks. There is a use for this mode, + however! In the future, I may make some kind of chain mode + automatically switch into chain-buffer mode for extra speed + when there is a large area of transluscence, etc. + + ATTENTION PROGRAMMERS: Here is the new order of modes that + initengine accepts: + + 0 = Chain mode + 1 = Chain-Buffer mode + 2 = Screen-Buffer/VESA mode + 3 = TSENG mode + 4 = Paradise mode + 5 = S3 + 6 = Crystal Eyes mode + 7 = Red-Blue mode +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +9/9/95 - Fixed visibility for face sprites in high resolution modes. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +9/14/95 - Added a new bunch of graphics modes using the new VESA 2.0 linear + buffer. (I replaced the useless chain-buffer mode with VESA + 2.0 modes) See my new SETUP. Since most cards only support + VESA 1.2 right now, you will probably need a VESA 2.0 driver. + I have been using the UniVBE(tm) 5.1 from SciTech Software + (ftp: ftp.scitechsoft.com, www: http://www.scitechsoft.com) + Note that since I inserted the new modes between chained mode + and screen buffer mode, you will need to update your setup + program and fix your initengine calls. + + - Programmed a LRU/MRU-style cacheing system. It should be fully + compatible with the old cache1d except for the locking byte. + The locking byte would be better described as a priority byte. + Priority byte: + + 0 - non-cached memory, you NEVER set the byte to 0! + 1-199 - cached unlocked memory + 200-255 - cached locked memory + + When the cacheing system needs to remove a memory block, it + will try to remove the FEWEST number of SMALLEST blocks with + the LOWEST priority. + + Note: Never set the priority byte to a 0! Let the cacheing + system do that for you. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +9/15/95 - Optimized hitscan a little and made it work with slopes. + + - Made some internal things in the build editor work better with + sprites on slopes. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +9/16/95 - Note: Initengine now only does memory allocation for the + graphics modes. The ylookup table is calculated in + setgamemode since with VESA, I don't know certain + variables such as bytesperline until the mode is + actually set. + + - Cansee should now work with slopes properly. + + - Added a new function which is a combination of the + getceilzofslope and getflorzofslope functions. Whenever you + need both the ceiling and floor, it is more optimal to call + this function instead. The parameters are just like the other + functions except the ceiling and floor are returned through + pointers instead of a return value. + + getzsofslope(short sectnum, long x, long y, + long *ceilz, long *florz); + + - Fixed recently introduced hitscan divide overflow bug. + + - Fixed a sprite drawing clipping bug. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +9/17/95 - ATTENTION PROGRAMMERS: I moved the sprite shading code from + the engine into GAME/BSTUB. If you want sprites to shade + like they used to, be sure to copy the code I recently added + to the end of analyzesprites in GAME.C or ExtAnalyzeSprites + in BSTUB.C. + + - Added 2 new interesting functions to the engine to make moving + slope programming easier. These functions will align a slope + to a given (x, y, z) point. It will make the slope pass + through the point. The function will do nothing if the point + is collinear to the first wall of the sector. + + alignceilslope(short sectnum, long x, long y, long z); + and + alignflorslope(short sectnum, long x, long y, long z); +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +9/18/95 - Kgroup will now work with subdirectories. + + - ATTENTION PROGRAMMERS: I have not done this yet, but I am + planning on doing a new map version! Before I do it, I + want to give you a chance to give me any suggestions you may + have. The only changes I am planning on, besides re-arranging + the structures for better alignment is to give the slopes some + more bits precision. This may limit slopes to a maximum slope + of 4 (almost 76ø) which is still extremely high. Here are the + new structures that I am proposing: + + //40 bytes + typedef struct + { + long ceilingz, floorz; + unsigned short wallptr, wallnum; + short ceilingstat, floorstat; + short ceilingpicnum, ceilingheinum; + signed char ceilingshade; + char ceilingpal, ceilingxpanning, ceilingypanning; + short floorpicnum, floorheinum; + signed char floorshade; + char floorpal, floorxpanning, floorypanning; + char visibility, filler; + short lotag, hitag, extra; + } sectortype; + + //32 bytes + typedef struct + { + long x, y; + short point2, nextwall, nextsector, cstat; + short picnum, overpicnum; + signed char shade; + char pal, xrepeat, yrepeat, xpanning, ypanning; + short lotag, hitag, extra; + } walltype; + + //44 bytes + typedef struct + { + long x, y, z; + short cstat, picnum; + signed char shade; + char pal, clipdist, filler; + unsigned char xrepeat, yrepeat; + signed char xoffset, yoffset; + short sectnum, statnum; + short ang, owner, xvel, yvel, zvel; + short lotag, hitag, extra; + } spritetype; + + Note that I am adding 1 byte of filler to the sprite structure + (4K more) and 3 bytes of filler to the sector structure + (3K more). (If I'm a nice guy, one of those bytes may even + be use for fog. (DOH!)) + + - Fixed another wonderful hitscan divide bug. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +9/22/95 - Optimized slopes. On a 486-66 w/ local bus in VESA 2.0 320*200 + mode, a full screen slope was optimized from 24fps to 35fps! +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +9/25/95 - Re-optimized some more assembly. + + - ATTENTION EVERYONE! CONVMAP7! You know what this means. Just + type "convmap7 *.map" and you'll be back in business. P.S. + enjoy the newly aligned structures! + + - ATTENTION PROGRAMMERS! New TRANSPAL! You can now use 2 levels + of transluscence by using just a single 64K transluscent + buffer, such as 33/67 and 67/33 transluscence. I changed the + format of palette.dat, so please run TRANSPAL before you try + running the game with the new OBJS! If you don't, the palette + tables will be screwed up. + + Old PALETTE.DAT: + 768 bytes - VGA palette + numshades*256 bytes - palookup[0] table + 32640 bytes- transluscent palette (smaller from symmetry) + + The way I used to get numshades (fun): + numshades = ((filelength-32640-768)>>8) + + New PALETTE.DAT: + 768 - VGA palette + 2 - numshades + numshades*256 - palookup[0] table + 65536 - transluscent table + + To keep things less confusing, could you all use a + transluscent constant >= 128. For example, I used 170 on + my PALETTE.DAT. + + + READ THIS! New bits added to things: + Bit 5 of rotatesprite, bit 9 of both sprite[].cstat + and bit 9 of wall[].cstat are now used for reverse + transluscence. + + - Added super-cool new feature to 2D EDIT MODE (that should have + been there from the start). Try inserting some points! + + - ATTENTION PROGRAMMERS! Removed overwritesprite. Use + rotatesprite instead. I don't want to support a function that + can totally be done with another better function. I will + eventually optimize rotatesprite for 90ø cases so it's even + faster than the current overwritesprite. If you're too lazy + to convert right now, then you can use this overwritesprite + stub function: + +overwritesprite (long thex, long they, short tilenum, + signed char shade, char stat, char dapalnum) +{ + rotatesprite(thex<<16,they<<16,65536L,(stat&8)<<7,tilenum,shade,dapalnum, + ((stat&1^1)<<4)+(stat&2)+((stat&4)>>2)+((stat&16)>>2)^((stat&8)>>1), + windowx1,windowy1,windowx2,windowy2); +} + + - Fixed the rotatesprite centerting bug in y-flipping mode. Oh + by the way, you know how I originally said the flipping bit + was x? Well, I screwed it up. It was actually y-flipping all + along. + + - This one's for hackers (N&P/Qs) In the engine, I call + getpalookup every time I need a pointer to a 256-byte + palookup table. One big limitation right now is that each + bunch of 256-byte tables has a limit of 64K because a shade + is being returned, not a 4-byte pointer. This means you + could have a maximum of 8 shades, with 8 fogs per palookup. + It's not as expandable as I originally intended since this is + a speed-critical function. It is called EVERY single time a + line is drawn - probably called 50 times more often than + faketimerhandler. + + #pragma aux bound32 =\ + "test eax, 0ffffffe0h",\ + "jz endit",\ + "cmp eax, 80000000h",\ + "sbb eax, eax",\ + "and eax, 31",\ + "endit:",\ + parm [eax]\ + + getpalookup(long davis, long dashade) + { + return(bound32(dashade+(davis>>8))); + } + + This is just a start. Eventually I hope to use some kind of + lookup table, such as: palookup = palptr[davis][dashade], + but I couldn't think of a good way to make the array small + enough for what people need. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +9/26/95 - Fixed drawmapview so it actually clips to the rectangular window + properly. It does not clip to startumost/startdmost so you + should call a rotatesprite to draw the status bar every frame + if it is not rectangular. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +9/30/95 - Fixed recently introduced mirror bug. + + - Fixed rotatesprite x-positioning bug in scale mode for weird + resolutions. + + - Fixed tilting for pure chained modes. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +10/2/95 - Changed setbrightness call: + + setbrightness(char dabrightness, char *dapal) + dabrightness is gamma level(0-15) + dapal is pointer to standard VGA 768 byte palette. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +10/3/95 - Fixed flicker in UNIVBE modes. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +10/6/95 - Added a global visibility variable to BUILD.H specific for + p-skies called parallaxvisibility. Now you can do lightning + effects without modifying the visibility for everything. + + - Really fixed the drawmapview window clipping this time. + + - Made my clearview function clip to the viewing window since it + is usually used just before the drawmapview function. + + - You can now use bit 6 (64) to tell rotatesprite whether or not + the tile has transparent regions or not. If there are no + transparent regions, then it would be faster to set this bit + because it doesn't have to check for color 255 at every pixel. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +10/11/95 - Back in RI! +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +10/13/95 - Cleaned up setup program by having only 1 VESA menu for all + possible VESA modes. The engine will now auto-detect whether + or not your computer supports VESA 2.0. The screen buffer + menu now only supports 320*200. (I noticed that Mark's setup + program doesn't list 320*400 mode even though it is supported + by my game and UNIVBE. 320*400 is considered by some people + the next best mode after 320*200 and 640*480. You have my + permission to annoy him.) + + - I bought UNIVBE by credit card for $28! When you buy UNIVBE, + you don't have to struggle with beeps or date changing - and + it loads instantly. I try not to use TSR's whenever possible, + but I found that UNIVBE is worth wasting 8K. I don't think my + computer has ever crashed due to something related to UNIVBE. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +10/17/95 - Found an easy way to interpolate everything for faketimerhandler + in my game, including swinging doors, revolving doors, and + other moving sectors. My doanimations interpolation now uses + these functions instead. Check them out in my GAME: + + setinterpolation(long *posptr); //Call when door starts + stopinterpolation(long *posptr); //Call when door stops + updateinterpolations(); //Call at start of domovethings + dointerpolations() //Call at start of drawscreen + restoreinterpolations() //Call at end of drawscreen + + Call setinterpolation with a pointer to the long variable + being interpolated. If an object stops moving, you can + speed things up by calling stopinterpolation. For things + that always move, you can call setinterpolation in pre-map + and don't stopinterpolation for those things. Don't forget + to set numinterpolations to 0 in premap whenever changing + levels in the game. + + - Optimized lava. You can re-copy my code if you want. + + - Added auto screen-buffering mode for linear VESA modes. (In + case you didn't know, reading video memory can be 10 times + slower than reading non-video memory.) Auto-buffering + means that if the engine detects that more than 1/8th of the + screen has transluscence or mirrors, then it will switch into + a screen-buffering mode. Screen-buffer mode in linear VESA + not only will still have smooth page flipping, but will be + faster than standard screen buffer mode on some video cards + just because it's linear memory. (That's a good thing) + + - Optimized screen buffer modes so they copy only the viewing + window instead of the whole screen from non-video memory to + video memory. If a permanent sprite is written, as a special + case, it will copy the whole screen - but this doesn't affect + you. Me and my engine babble. + + - Moved the printext function out of the engine and into my game. + Use printext16/printext256 instead. + + - I tried removing chain mode twice and it didn't improve the frame + rates of the other modes at all. So it stays! If you don't + like it, then don't include it in your setup program. + + - Made allocatepermanenttile return 0 instead of -1 if something + bad happens. My GAME.C was crashing in windows with a memory + error because I was assuming all memory pointers were + positive. Please make sure your code will work if an + allocation function returns a negative pointer (Windows often + returns negative pointers). +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +10/19/95 - Tried to make pushmove work with face sprites, but it kept making + the player die too much. Also it presented some interesting + new problems, such as: You get pushed by your own bullets + that you just shot - and get this - if you don't temporarily + set yourself to non-blocking you kill yourself because you're + inside you're own sprite! So I have decided to comment out + this code for now. + + - Fixed hitscan bug with ceiling slopes. + + - ATTENTION PROGRAMMERS!!! PERMANENTWRITESPRITE was removed from + the engine and be put into my game as an emulated function. + If you still use permanentwritesprite, get the emulated + function out of my GAME.C. + + Drawing permanent areas is now easier than ever!!! Simply + call rotatesprite with bit 3 (&8) set or the + permanentwritesprite stub call, and the engine now + automatically takes care of copying the permanent region + to all necessary pages in the future. It even keeps track + of whether the call was before or after drawrooms! + I am using an internal fifo to back up the parameters for each + rotatesprite call. It can support up to 512 calls per + page right now. This number can get reached quicker than + you think, especially if you use fonts with shadows behind + each character. Permanentwritespritetile could also go + over the limit in hi-res modes since each tile is considered + a separate call. + I optimized out the case where an older rotatesprite region gets + completely covered by a newer rotatesprite region with bit 6 + (&64 for non-masking) set. Currently this has a few + limitations - such as the x, y, zoom, and ang must be the same + right now to knock out an older rotatesprite. + + - I corrected an off-by 1 error in my GAME.C for window size + calculations. I simply used more precision. Ex: + * changing (xdim>>1)-(screensize>>1) to ((xdim-screensize)>>1) + * using the scale function instead of a separate mul & div. + By the way, if you haven't already, please stick your screen + re-sizing code BEFORE drawrooms. It will make the screen + re-size update more responsively and you're less likely to get + drawing bugs. + + - Future plans for possible rotatesprite optimizations: + 1. Angle is 0, 512, 1024, 1536 + 2. Bit 6 (&64) is set for non-masking mode + 3. tilesizy[tilenum] is a power of 2 + 4. If coincidentally, x=34562, y=34682, and zoom=67275 +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +10/20/95 - Fixed vertical line shading bugs when looking at walls at harsh + angles. + + - Made masked walls clip to slopes properly. TRY IT! + (hope you didn't "BUILD" on this bug!) + + - Fixed overflow and precision bugs with extremely long walls. + I even got the chance to optimize out a multiply in the + wallmost clipping code! +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +10/25/95 - Now absolutely everything in my game is being interpolated + for smooth play - including subways! No interpolation + disable variable exists any more. The setinterpolation + function is really easy to use. Try it! + + - Programmed VISIBILITY for slopes!!!!! On my P-100, the slopes + are almost as fast as they used to be. You can now start + adjusting the shades of slopes. + + - The shading lines on ceilings and floors now match to the shading + lines on walls. Before they didn't match. (oops). + + + - For those of you who want to program their own palette functions, + using my gamma correction lookup table, here's the code: + + extern char britable[16][64]; + + koutp(0x3c8,0); + for(i=0;i<768;i++) + koutp(0x3c9,britable[curbrightness][palette[i]]); + + If you use this code, don't bother calling setbrightness any + more. The only bad thing about programming this yourself + is that you lose support for red-blue glasses mode. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +10/26/95 - Added support for VESA 2.0 protected mode extensions. With the + protected mode extensions, the page-flipping is less likely to + flicker, if at all. This is because the retrace timing isn't + screwed up as badly as if it had to switch to real mode. + + - Fixed a weird buffer bug in my GAME.C. I was using tempbuf in + faketimerhandler/getpackets for sending packets. I was also + using tempbuf in many other places, such as my printext + function. Unfortunately, since rotatesprite is now called + for each character, faketimerhandler would sometimes get + called and the rest of the word got screwed up. Please make + sure you are not sharing any buffers in faketimerhandler / + getpackets with the rest of your code. + + - Fixed a bug for linear VESA modes. Now, the screen will update + properly when calling rotatesprite and nextpage for the first + time before any drawrooms calls. This used to not work right + at my "waiting for other players" code in this mode. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +10/27/95 - Did you notice I fixed some of the weird cases with slope drawing + in the last upload? I fixed things like when a ceiling of + one sector is partially below the floor of another, etc. + + - Fixed precision of shading lines on slopes. + + - Fixed visibility overflow when slopes are near horizons. This + means you won't see ugly bright pixels any more when you're + looking at a slope at an extremely sharp angle. + + - Fixed a bug in BUILD 3D EDIT MODE with slopes. Now when you + press '/' on a ceiling or floor slope, it stays straight + until you press [ or ] on it again. Before, sometimes the + ceiling would stupidly get sloped again if you pressed [ or ] + on the floor and vice versa. + + - Removed some unnecessary sounds from my game. This doesn't + really affect you people out there. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +10/30/95 - Fixed recently screwed up p-sky tiling. + + - Made Editart work with map version 7 for tile sorting and the + Alt-R command. Alt-R does not scan the heinum's of sectors + any more, and only adds in the overpicnum if a masked or + 1-way wall is actually defined on the map. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +10/31/95 - Fixed a bug with my slopalookup array. It was sometimes writing + up to 3 bytes after the end of the array. + + - Fixed recently screwed up p-sky tiling for real this time. + + - Permanentwritesprite is out of my game. Here it is just in case + I will need it again for future reference. + + permanentwritesprite (long thex, long they, short tilenum, + signed char shade, long cx1, long cy1, + long cx2, long cy2, char dapalnum) + { + rotatesprite(thex<<16,they<<16,65536L,0,tilenum,shade, + dapalnum,8+16,cx1,cy1,cx2,cy2); + } +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +11/1/95 - Guess what? I turned 20 today. This means I'm no longer a + teenage programming genius. Doesn't that just suck. If you + guys don't get a game out by the next time my age plus + plusses, I'm going to get really p-skied off and kill some + people. That would be bad. (When I say killing, I mean + virtual killing in the entertaining game of Ken-Build + in which a fun time is always had by all.) So put on your + happy fun smiles and work out all those rotatesprites, + fsyncsyncvel.bits, and interpolation fifos before it's + ototalclock! + + - Optimized the NON-MASKING cases of rotatesprite for + NON-(un)CHAINED modes. This means that low detail modes, + status bars, and permanent background tiles are now drawn + about as fast as they're ever going to be drawn! Try the + F5 key in my game to compare frame rates if you want. I have + not optimized guns and stuff yet. That's next on my list. + + - Made the engine call new internal functions, kmalloc and kfree, + instead of malloc or free. Unless you're a hacker and wrote + your own memory manager (like N&P/Qs) you can just ignore + this message. + void *kmalloc(size_t size) { return(malloc(size)); } + void kfree(void *buffer) { free(buffer); } + + - Supposedly fixed the new rotatesprite and linear vesa crashing + bugs. Since I'm not totally sure that I fixed the problems, + all I can do is hope that I don't get too many phone calls! +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +11/4/95 - Did some neat optimizations that will make the drawing code + faster, especially in hi-res modes, but I'm sure nobody cares. + Instead I'm probably just going to get 10 totally different + bug report stories. So I'll be talking to you soon! + + - Fixed stupid bugs in cansee. If the 2 objects were in the same + place, sometimes it returned 1 even if it couldn't see you. + I made 2 fixes: + This one to fix overlapping: + + if ((xs == xe) && (ys == ye)) return(sects == secte); + + And I removed the early out return(1) optimization - I + put this after the big loop instead: + + for(i=danum-1;i>=0;i--) + if (clipsectorlist[i] == secte) return(1); +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +11/7/95 - Optimized the awful shld's out of my divscale's in pragmas.h. + You can update to the new pragmas.h if you actually use it. + + - Remember the lovely horizontal lines on top of face sprites. + Well you won't be seeing them any more. At least the case + I trapped works better than before. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +11/8/95 - Made krand generate better random seeds. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +11/9/95 - ATTENTION PROGRAMMERS! Moved part of stat bit 3 of rotatesprite + to bit 7. Have you noticed that your menu code was kind of + screwy in modes where numpages > 1? This is because I made + rotatesprite automatically copy to all pages whenever the + "don't clip to startmost's bit" (bit 3 or +8) was set in + the stat bit of rotatesprite. To give you more control, I + moved the auto copy to all pages bit to bit 7 and left bit 3 + as the don't clip to startmosts bit. If you want your code + to work the same as the last update of BUILD, simply go + through all your rotatesprite calls and add 128 in addition + to the stat bit whenever you were adding 8 before. See the + revised rotatesprite documentation: + +rotatesprite (long sx, long sy, long z, short a, short picnum, + signed char dashade, char dapalnum, char dastat, + long cx1, long cy1, long cx2, long cy2) + + (sx, sy) is the center of the sprite to draw defined as screen coordinates + shifted up by 16. In auto-scale mode, be sure that (sx, sy) is using + a 320*200 size screen even though the real resolution may be different. + (z) is the zoom. Normal zoom is 65536. > is zoomed in, < is zoomed out. + (a) is the angle (0 is straight up) + (picnum) is the tile number + (dashade) is shade number + (dapalnum) is the palookup number + + if ((dastat&1) != 0) - transluscence + if ((dastat&2) != 0) - auto-scale mode + Auto-scale mode will automatically scale from 320*200 resolution + coordinates to the clipping window passed (cx1, cy1, cx2, cy2). In + auto-scale mode, don't pre-scale the (sx, sy) coordinates. Simply pass + (sx, sy) as if the resolution was 320*200 even though it may be + different. This means that you shouldn't use xdim or ydim to get + (sx, sy). + if ((dastat&4) != 0) - y-flip image + if ((dastat&8) != 0) - don't clip to startumost/startdmost + if ((dastat&16) == 0) - use Editart center as point passed + if ((dastat&16) != 0) - force point passed to be top-left corner + if ((dastat&32) != 0) - use reverse transluscence + if ((dastat&64) == 0) - masked drawing (check 255's) (slower) + if ((dastat&64) != 0) - draw everything (don't check 255's) (faster) + if ((dastat&128) != 0) - automatically draws to all pages as they come + + (cx1, cy1, cx2, cy2) - The clipping window. These coordinates are never + scaled, not even in auto-scale mode. Usually you should pass them as + (windowx1,windowy1,windowx2,windowy2) for things scaled to the viewing + window or (0L,0L,xdim-1L,ydim-1L) for things scaled to full screen. + Probably the only time you wouldn't follow this rule is if you program + a non-scaled tiled background function. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +11/21/95 - Optimized cansee - before it was checking each red wall 2 times + as much as it needed to. Now it only checks the side facing + the first object passed to cansee. Since this optimization + is only 1 line, I don't think I messed anything up this time. + + - Made cansee not pass through 1-way walls. This means that the + order of points passed to cansee could give you different + results, but only for 1-way walls. + + - FIXED CRASHING AND PRECISION ON HIGH SLOPES!!! Try it for the + first time again! The bug was: In wallmost, if a slope's + line was getting clipped by both the top and bottom of the + screen, the x-intercept of the bottom was calculated wrong. + And if you were real lucky, if the x-intercept could have been + so wrong that a loop would happily overwrite random chunks of + memory. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +12/1/95 - In my GAME.C, made tilting zoom in smoothly as it rotates to + hide the ugly corners. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +12/4/95 - Made some more optimizations to rotatesprite - added more cases + for removing things from the permanent list early, such as: + any full screen rotatesprite with 64 knocks everything else + off the list, and any rotatesprites with zoom=65536,ang=0, + stat&64 will knock out anything totally under its rectangle. + These optimizations seemed to actually fix some bugs. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +12/10/95 - Well, well, well. It has now been 2 years since you know what + was released and Apogee still hasn't put out a (real) Build + game. Trivia of the year: Did you know that the first Build + game was originally scheduled to be released a month before + Doom was to be released? Maybe I should rename the "Build" + engine to the "ROTTT" engine because it's probably just going + to rot on my hard drive for another year until all the games + just get cancelled. PROVE ME WRONG! + + - Added selectable viewing angles - not locked at 90ø anymore! + Try playing around with the ( ) - = keys on the main keyboard + in my new BSTUB.C. See the example code in BSTUB for setaspect. + Use the setaspect function to control both the viewing range + angle and the y/x aspect ratio. + + setaspect(long daxrange, long daaspect) + + For a standard 90ø 320*200 screen, daxrange and daaspect are + 65536. For square aspect ratio at 320*400, set daaspect + to 131072. Since daxrange is actually zoom, you must + modify the aspect ratio inversely if you only want to + change the viewing angle. + + ATTENTION EVERYONE! To make parallaxing skies work with larger + than 90ø viewing ranges, I had to change some things around + in TABLES.DAT. Don't forget to update to the new one! The + new one is smaller because I removed a useless array. + + - Improved red-blue glasses mode by fixing some palette problems + and removing the overlap problem on the right side of the + screen. It still has some things wrong with it though. + + - Perfected screen tilting by using the new setaspect function. It + now tilts all 360ø smoothly with no zoom change and with no + ugly corners. This is possible only because you can now set + the viewing angle higher than 90ø. + + - Fixed a flicker bug with permanent rotatesprites in multi-page + modes. When rotatesprite was called because drawrooms in a + multipage mode, the rotatesprites were being called in the + wrong order from the fifo for the first page. Note that + before, the auto-knock out feature sometimes hid the problem. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +12/11/95 - Made EDITART work with the new TABLES.DAT. + + - Upgraded to Watcom 10.5. The engine is now about 1K larger, + and 0.0000001% faster. + + - Added some interesting compression routines to cache1d.obj, + dfread and dfwrite. These functions take the same parameters + as fread and fwrite respectively. These functions are useful + for loading/saving games or for recording demos. + + Note: Since these functions need to allocate 118K off of my LRU + cacheing system, you must not call them before + initcache(loadpics) is called. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +12/18/95 - Made rotatesprite use getpalookup to get the palette shade. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +12/31/95 - Cleaned up KGROUP.EXE and wrote a KEXTRACT.EXE utility. With + KEXTRACT, you can extract any files from a group file. + Note that in KGROUP, DOS handles the ? and * wildcards whereas + in KEXTRACT, I had to program the wildcards myself for finding + files inside the group file. The following combinations + should work: *.*, *.map, game.*, tiles???.art, *.k?? + + - NEW NETWORK METHODS! TRY MY GAME IN MULTIPLAYER MODE! MODEM! + + SUMMARY: Lag Time: ZERO! That's right Z.E.R.O. (0) + Smoothness: Perfect on ALL computers! + + My new network code builds upon everything you've already + programed with faketimerhandler, getpackets, movethings, and + domovethings, so you don't need to throw away any of that + great stuff. There are actually 2 totally separate things I + did to improve the multiplayer performance. First I added a + new network mode which sends packets in a different way (this + is way Doom actually does it) Then I found a way to reduce + lag-time to 0 with perfect smoothness. (Doom does NOT do + this, but G&S like it anyway for some reason.) I will first + describe the new network mode: + + ------------------------------------------------------------- + 1. First, let me describe the new network mode. Instead of + a master/slave system, every computer sends its own controls + to every other. You are currently using the master/slave + system which sends 2(n-1) packets per frame where n is the + number of players. My new network mode sends n(n-1) packets + per frame and treats every player evenly. See the chart + below of packets per frame: + + 2(n-1) method: n(n-1) method: + 2 players 2 2 + 3 players 4 6 + 4 players 6 12 + 5 players 8 20 (OUCH!) + 6 players 10 30 (OUCH!) + 7 players 12 42 (OUCH!) + 8 players 14 56 (OUCH!) + + + You may be asking why I am bothering you with this new + network method if it sends more packets then the old one? + I'll explain: With the old network method, slaves had to + wait for their packets to take 2 trips before they could move, + whereas with the new method the packets need to take only 1 + trip. Also with the new method the players are treated + evenly. For 2 players, the new network method is definitly + the mode of choice since it sends the same number of packets + AND the packets can be smaller since each computer only needs + to send its own controls to the other computer, not everyone's + controls (good for modem play). It's up to you what your + break even point is before you switch into the old network + method. I recommend: 1-4 New, 5+ Old. + Now let me explain how the new method REALLY works. Since + every computer must call the movement code in the same order + to stay in sync, all computers must wait until every packet + is received for that frame before it can actually go into + the movement code. You could say that all the computers are + half-slaves. Your computer should always be ahead of the + other computers. If you are player 0, the packets you + currently have might look like this: + + Chart for Player 0: + + Player 0 Player 1 Player 2 + Tic 0: GOTMINE------GOT--------GOT------> MOVE! + Tic 1: GOTMINE------GOT--------GOT------> MOVE! + Tic 2: GOTMINE--X WAITING... GOT CAN'T MOVE! + Tic 3: GOTMINE WAITING... WAITING... CAN'T MOVE! + Tic 4: GOTMINE WAITING... WAITING... CAN'T MOVE! + + As soon as player 0 receives player 1's next packet, + player 0 can call domovethings for tic 2. + One interesting complication of the new network method is + the timing. If for some reason player 0 sends packets faster + than player 1, then player 1 will have no lag and player 0 + will start with twice the normal lag which will increase + until bad things happen. See this chart: + + Player 0's side: | Player 1's side: + Player 0: Player 1: | Player 0: Player 1: + Tic 5: GOTMINE GOT (MOVE) | GOT GOTMINE (MOVE) + Tic 6: GOTMINE WAITING | GOT GOTMINE (MOVE) + Tic 7: GOTMINE WAITING | GOT GOTMINE (MOVE) + Tic 8: GOTMINE WAITING | GOT GOTMINE (MOVE) + Tic 9: GOTMINE WAITING | GOT GOTMINE (MOVE) + | GOT + | GOT + | GOT + + This can be corrected by sending a byte which tells the + other computer how many packets behind it is. You want the + other computer to be a little behind. Player 0's packet + delta in this case would be 4. Player 1's would be -3. + + Another interesting thing about this network method is + that a slave's packet cannot be skipped like in the + master/slave system. + + The actual code for everything described above is already + in my GAME.C and working perfectly. Go through the file + searching for the keyword, "networkmode". If it is non-zero, + that's the new mode. Look mainly at the section inside + faketimerhandler and case 17 of getpackets. + + (I've talked about "2(n-1)" and "n(n-1)" networking modes. + Believe it or not, it's possible to do a network mode as + low as an "n" mode. I haven't done it due to some + inherent problems. I'd be impressed if you can figure out + how this one works) + ------------------------------------------------------------- + 2. Now I'll type about the "KLAG-0 Technology" I promised you. + + The secret to life is, " + NO CARRIER + + Why do you have to wait for another computer to tell you + when to move when you already know where you want to go? + So I added a fake set of variables that simulate + where the player's x, y, z, and ang variables will be after + it does sync crap with other computers. I added a function + called fakedomovethings which is called in the same fashion + that domovethings would be called in a 1-player game. + Fakedomovethings modifies ONLY the fake x, y, z, and ang + variables. It is a shadow of the processinput function. It + only needs the parts of processinput that modify the position + of player[myconnectindex]. If it modifies real variables, + the game will get out of sync. + Sometimes the fake variables can get out of sync with the + real variables. This can happen if you walk into another + player or anything else that moves. This doesn't happen too + often though and when it does, there are things that you can + do to smooth out the jump to the right position. This brings + me to my other new function: fakedomovethingscorrect. + The easy way to correct the player's position in a smooth + way is to say something like: fakex += ((realx-fakex)>>3); + This would effectively move the player 1/8th of the way closer + to the real position. The problem with this method is that + the realx and fakex are not sampled at the same time, + therefore creating more error than isn't any. + So instead of comparing your fake position with where the + real position was a few tics ago, I chose to compare both + of them a few tics ago. FIFO time! To do this, I am keeping + a fifo of the new fake positions and comparing the positions + as the real positions come. Now that they're being compared + at the same tic, correction will only occur when you've truly + run into a moving object. + ------------------------------------------------------------- + I hope all this was as much fun for you to read as it was for + me to type. If you don't understand it, then I was probably + just trying to confuse you with all the possible word + combinations I could come up with that contain the letters in: + "fake", "sync", and "fifo". +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +1/6/96 - Made RT.SHIFT highlighting in build.obj not pick up non-existent + sprites in the selection rectangle. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +1/9/96 - Fixed a rare hitscan overflow bug for sectors that had a + ceiling&floor z-difference of more than 400000 z-units. + (About 20 stories tall) +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +1/15/96 - Changed something in rotatesprite so that status bars could be + clipped easily by using the clipping parameters. (I never + knew this didn't work until now) This change will only affect + your code if you were using bits 2+8 and the clipping window + was something other than the standard (0,0,xdim-1,ydim-1). + + - Improved fakedomovethingscorrect. Before when there was an + error, I was adding the difference into the current + position. This method conflicted with pushmove - where + sometimes it never fully corrected the position leaving you + stuck behind a wall. Now I make your position the position + it would have been if it had predicted the right position + several ticks ago. In other words, I set the my... variables + to the real, older position then call fakedomovethings for + every tic from the time of the real, older position up to + the current time. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +1/19/96 - Added snow reduction code to setpalette. It takes about 4 ms + to set a full palette. I write during the horizontal retrace + period to save time. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +1/23/96 - Added hack to loadboard to make it load a board only from the + group file if the last character of the filename is a 255. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +1/25/96 - Fixed a stupid bug in UNIVBE segmented modes so it doesn't + flicker anymore. Why didn't you guys tell me about this + sooner! +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +2/1/96 - Optimized cansee according to Peter's suggestions. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +2/2/96 - Made setview calls not mess up the stereo vision variables. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +2/5/96 - ATTENTIONS ALL PROGRAMMERS!!! If you use use any VGA registers + (such as 0x3da, or 0x3c6 - 0x3c9), you will need to re-code + those sections of code. Please make your BSTUB's work with + this too! + + 1. If you use register 0x3da, limitrate, or qlimitrate, you + will need to do a special check to see whether or not the + video mode is VGA register compatible. If you do not + check this, then the computer may lock up because register + 0x3da simply doesn't change on certain video cards. + Unless you know the code won't be called in VESA mode, you + need to perform this check. Here's an example of how you + can do this check: + + Instead of calling limitrate (or your own 0x3da function): + limitrate(); + Do this: + //extern char vgacompatible; + if ((vidoption != 1) || (vgacompatible == 1)) limitrate(); + + 2. You must now use my function to set or get any palette + registers. This means that the keywords "3c7", "3c8", + and "3c9" should not even exist in your code. I really + didn't want to force you to use my palette functions, but + since VESA 2.0 supports non VGA compatible cards, you must + do it this way. If you use setbrightness for all of your + palette setting, then you can ignore this. Note that the + palette format here is VESA's palette format, which is + different than my other palette control functions. It's + 4 bytes and RGB are backwards. Here are the function + prototypes: + + VBE_setPalette(long palstart, long palnum, char *dapal); + VBE_getPalette(long palstart, long palnum, char *dapal); + palstart is the offset of the first palette to set + palnum is the number of the palette entries to set + dapal is a pointer to the palette buffer. The palette + buffer must be in this format: + char Blue, Green, Red, reserved; + I think this format stinks, but since VESA 2.0 uses + it, the code will run fastest if the buffer is not + copied. You can make your own cover up function if + you don't like this format. + + This example sets up a wasteful gray scale palette: + + char mypalette[1024]; + for(i=0;i<256;i++) + { + mypalette[i*4+0] = (i>>2); //Blue + mypalette[i*4+1] = (i>>2); //Green + mypalette[i*4+2] = (i>>2); //Red + mypalette[i*4+3] = 0; //reserved + } + VBE_setPalette(0,256,mypalette); +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +2/7/96 - Did some minor optimizations to functions that use cliptype. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +2/9/96 - ATTENTION PROGRAMMERS!!! There is no such thing as a cliptype + anymore! Instead you use clipmasks. Clipmasks are much better + because it gives you full control of which bits are used to + test whether or not a sprite or wall will block things. + + Let me refresh your memory on how cliptypes used to work: + For CLIPMOVE, PUSHMOVE, and GETZRANGE: + If (cliptype == 0) these bits were the blocking bits: + (wall[].cstat&1), (sprite[].cstat&1) + If (cliptype == 1) these bits were the blocking bits: + (wall[].cstat&64), (sprite[].cstat&256) + For HITSCAN, cliptype was not passed and assumed to be 1: + (wall[].cstat&64), (sprite[].cstat&256) + + Note that I added these 2 defines in BUILD.H: + #define CLIPMASK0 (((1L)<<16)+1L) + #define CLIPMASK1 (((256L)<<16)+64L) + + In order to make clipmasks work, I had to change the parameters + to these 4 important functions. CLIPMOVE, PUSHMOVE, GETZRANGE, + and HITSCAN. For CLIPMOVE, PUSHMOVE, and GETZRANGE, I simply + made the cliptype from a char to a long. For HITSCAN, I had to + add the clipmask parameter at the end. Here are the new function + prototypes: + +clipmove (long *x, long *y, long *z, short *sectnum, long xvect, long yvect, + long walldist, long ceildist, long flordist, unsigned long clipmask) + +pushmove (long *x, long *y, long *z, short *sectnum, + long walldist, long ceildist, long flordist, unsigned long clipmask) + +getzrange (long x, long y, long z, short sectnum, + long *ceilz, long *ceilhit, long *florz, long *florhit, + long walldist, unsigned long clipmask) + +hitscan (long xs, long ys, long zs, short sectnum, long vx, long vy, long vz, + short *hitsect, short *hitwall, short *hitsprite, + long *hitx, long *hity, long *hitz, unsigned long clipmask) + + You should convert your source code using these rules: + * For CLIPMOVE, PUSHMOVE, and GETZRANGE, look at the last + parameter. If it is a 0, then change it to say CLIPMASK0. + If it is a 1, then change it to say CLIPMASK1. + + * For HITSCAN, add a new parameter that says CLIPMASK1. + + * If you have your own movesprite function, then you will + need to make the cliptype parameter into a long variable. + + - If you want to set a range for hitscan, or optimize its + performance, you can now extern these 2 variables from + the engine. You can set them just before you call hitscan. + If you DO choose to screw around with these variables, then + you must set them before EVERY hitscan in your code. + I have them defaulting to a really high number, totally out + of range of the map, but not high enough for a subtraction + to overflow it. These variables are used in hitscan only + to compare whether the new hit is closer then the last one. + + long hitscangoalx = (1<<29)-1, hitscangoaly = (1<<29)-1; +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +2/13/96 - Fixed a bug in clipmove that showed up in the latest upload + related to sector searching. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +2/18/96 - Re-wrote waitforeverybody / case 250 of getpackets, so the slave + sends acknowledge packets in a better way. Before there was + a possibility of a slave sending an invalid acknowledge + packet if the last packet received was not 250. + + - ATTENTION PROGRAMMERS! Setgamemode now returns -1 if the mode + is invalid or 0 if it is valid. Since the engine no longer + quits to DOS from an invalid video mode, you must program the + -1 case or else the computer will probably lock up! +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +3/5/96 - Solved tile index corruption bug in EDITART. After looking at + the latest art files I have from you, It looks like SW has + this problem, but DUKE and BLOOD seem ok. Let me explain: + In Editart 'V' mode (with no tile report), when you use + INSERT or DELETE, it very quickly moves all tiles after the + cursor forward or back 1. With multiple art files, this + operation would be very slow, since I'd have to load and + save every art file after the current one. But I figured + out a way to still keep it fast - instead of reading and + writing all the later art files, I instead changed just the + headers that tell which tile indeces the art files start and + end with. This works nice when you have 1 big art file, or + only 1 person using EDITART to change stuff. + Unfortunately, some of you have been passing around + individual art files and this is where the problem comes in. + If either person used INSERT of DELETE in 'V' mode and passed + an individual art file to another person, the headers could + possibly conflict and cause strange lockups or crashes in + EDITART, BUILD, or GAME. + So I fixed the problem by making EDITART only change the + CURRENT art file. Insert mode will now delete the last + tile in the CURRENT art file, so be careful that the last + tile in the CURRENT art file is blank. Delete will now + insert a blank tile at the end of the CURRENT art file. + If your ART files are already corrupt, you can run + RSIZEART.EXE and agree on a number of tiles per file. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +4/27/96 - Fixed a bug where rotatesprite seemed to clip the tile + to the viewing window even though stat&8 (don't clip + to startumosts/startdmosts) was set. The problem was + actually related to an optimization in the VESA blitting + code that copies only the screen if it thinks nothing + was drawn outside of the viewing window. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +6/15/96 - I must have added a whole bunch of unnoticable optimizations + since the last time I typed stuff into this file, but since + I didn't keeping track of it, I couldn't tell you what they + were off hand. + + - I added support for the 'new' Crystal Eyes in such a way where + you don't have to mess with the timer. I use the real-time + clock (IRQ8) in order to avoid conflicts. Crystal Eyes mode + works only in VESA 2.0 modes with at least 4 pages. The nice + thing about this mode is that you can switch in and out of + it easily during the game. There are 2 very simple functions + and 3 variables you can extern. To use Crystal Eyes mode, + simply call initstereo(). Initstereo should be called after + setgamemode and the palette is loaded into the VGA. To + return back to normal mode, simply call uninitstereo(). + Here's what the code would look like: + + extern long stereomode, stereowidth, stereopixelwidth; + + if (KEYTOTOGGLESTEREOMODE) + { + KEYTOTOGGLESTEREOMODE = 0; + if (stereomode == 0) + initstereo(); + else + uninitstereo(); + } + + Notes: + * The following 2 variables can be changed any time, and + should always be >= 0. + + stereowidth: distance between left and right eyes + stereopixelwidth: parallax - pan offset in pixels between + left & right screens + + * initstereo automatically sets stereomode to nonzero and + uninitstereo automatically sets stereomode to 0. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +7/5/96 - Made cache1d.obj support up to 4 group files at the same time. + To use multiple group files, simply call initgroupfile again. + You need to uninitgroupfile only once. This is useful if + users want to add their own .ART, .VOC, or other files and + distribute it all in one file without telling people they + need to back up stuff. For example: + + Beginning of program: + initgroupfile("duke3d.grp"); + if (usergroupfile) + initgroupfile(usergroufile); + + End of program: + uninitgroupfile(); + + Here's the order cache1d will search for a file when + kopen4load is called. Remember that the second parameter + to kopen4load is the searchfirst parameter. If you set + this variable to non-zero, you can tell kopen4load to search + the main group file only. This is useful if invalid user + files are detected. + + if (searchfirst == 0) + { + 1. Look for it as a stand-alone file + 2. Look for it in the 4th group file (user group file) + 3. Look for it in the 3rd group file (user group file) + 4. Look for it in the 2nd group file (user group file) + } + 5. Look for it in the 1st groupfile ("duke3d.grp") + 6. If file still not found, return -1 + + - Fixed a stupid bug with choosing the side of a red line in BUILD + 2D edit mode. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +7/24/96 - Increased MAXTILES to 6144. Fixed some scrolling errors related + to MAXTILES in 'V' mode of EDITART and BUILD. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +8/20/96 - Made it possible to safely default to NORMAL mode 320*200 when + VESA is not supported or found. Check out the beginning of + my setup3dscreen function. It shows how you can offer the + player a choice of quitting to DOS or continuing in NORMAL + mode. It is very annoying when setting up multiplayer games + when the game always quits to DOS because somebody forgot + to load their VESA driver. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +9/6/96 - Moved internal function, setfirstwall, in BUILD.OBJ into + ENGINE.OBJ because it can be useful to game programmers. + This function sets the first wall of a sector to be the + wall index passed. This function is useful for setting + the hinge wall for slopes or relative alignment. (ALT-F + uses this function) Here's the function: + + setfirstwall(short sectnum, short newfirstwall) + + - Added a variable, clipmoveboxtracenum, to ENGINE.OBJ which can + be externed. As a special case, if you set it to 1 just + before calling clipmove, then clipmove will return when it + first hits a wall - in other words, the (x,y,z) that clipmove + returns will be before any sliding calculations occur. Be + sure to set clipmoveboxtracenum back to 3 after calling + clipmove. + + This is how it is defined in ENGINE.OBJ: + long clipmoveboxtracenum = 3; + + Example of calling clipmove with no sliding: + clipmoveboxtracenum = 1; + i = clipmove(...); + clipmoveboxtracenum = 3; +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +9/25/96 - Removed support for specially optimized TSENG, Paradise, and S3 + modes. If you want the engine to run as fast on these cards, + get Scitech Software's latest Vesa 2.0 driver. + + - ATTENTION PROGRAMMERS! Added video mode changing during the game. + I moved the option, xdim, and ydim parameters from initengine + into the setgamemode function. + + Here are the updated prototypes for the 2 functions: + initengine(); + setgamemode(char newvidoption, long newxdim, long newydim); + + You are free to call setgamemode as often as you like. If you + have very low memory, it's possible that the call will fail + and quit to DOS with one of those awful CACHE SPACE ALL LOCKED + UP messages. + + Note: When updating your code, be careful to not rely on + vidoption, xdim, of ydim being valid until your first + setgamemode call. If you're not careful with this, you may + get a divide by zero or something. I had a bug in my GAME.C + where I was calling setview between initengine and + setgamemode. I had to move setview after setgamemode. + + - Added function to the engine that returns all valid VESA modes. + + getvalidvesamodes(); + + This function prepares the list of valid VESA modes in these + new variables which I put in BUILD.H. This function needs to + only be called once, but it doesn't hurt to call it multiple + times since I have a flag that checks if it has already been + called. + + EXTERN long validmodecnt; + EXTERN short validmode[256]; + EXTERN long validmodexdim[256], validmodeydim[256]; + + validmodecnt - number of available 256 color VESA modes. + validmode[] - array of vesa mode numbers (640*480 is 0x101, etc.) + validmodexdim[] - array of x dimensions for each mode + validmodeydim[] - array of y dimensions for each mode + + In my GAME.C, I have code that cycles through all VESA modes + and screen buffer mode when you press F4. Search for the + keyword "//F4" to find it. + + Note: Be careful when you call setgamemode! Be sure that it + is not called inside any function of sub-function of + faketimerhandler because this would be in the middle of the + drawing code. Actually, the safest place to call setgamemode is + right after nextpage in your main drawing loop. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +12/13/96 - Fixed the nasty caching bug first found in the Plutonium version + of Duke3D. I was using copybuf when I should have been using + copybufbyte. + + - Made the '>' key in 3D EDIT MODE not lock up any more for + textures that have non power of 2 tilesizy's. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +2/12/97 - Optimized mirror code so it x-flips only the bounding rectangle + (x AND y). Actually calculates left & right boundaries instead + of using the horizontal line checking stuff which didn't really + work all the time anyway. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +5/22/97 - Frank noticed a divide overflow in clippoly when drawmapview was + in hi-res mode. -fixed by lowered precision from 16 to 12 + bits. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +6/2/97 - Added support for the Nuvision 3D-Spex stereo glasses. I renamed + initstereo to setstereo and got rid of uninitstereo. Here's + complete documentation for all of the new stereo glasses stuff: + + setstereo(0); //Set to default normal non-stereo mode + setstereo(1); //Use Stereographics Simuleyes (white line code) + setstereo(2); //Use Nuvision 3-D Spex stereo (uses LPT1) + + //You can extern these 2 variables from the engine to add + //your own stereo adjustment code + extern long stereowidth = 23040; + extern long stereopixelwidth = 28; + + It would be nice to allow the adjustment of these variables + inside the game, but if you're too lazy, it would be nice to + have some way of modifying it. + Please do not extern stereomode any more since I use it now + to uninit the old mode automatically. Use your own current + stereo mode variable. +ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ +10/4/97 - I have upgraded to Watcom 11.0. The only changes I had to make + in the engine were some "#pragma push" and "#pragma pop" + calls in BUILD.H since the default structure packing alignment + was moved from 1 to 8. The sector, wall, and sprite structures + are already aligned well and must remain the same for .MAP + files to remain compatible. + + - Increase MAXTILES for all utilities (EDITART,BUILD,GAME,etc.) to + 9216 for Xatrix. + + You may have some initial bugs with EDITART when you add new + tiles for the first time. I haven't touched the code in years + and I'm afraid if I did, I'd mess it up more. One bug I know + of is this: Let's say you have 256 tiles per art file, and + then you add 1 silly tile way up at picnum=8500. When you + save and quit, your directory may look like this: + + TILES000.ART + TILES001.ART + TILES002.ART + TILES029.ART + + When you load EDITART again, that 1 tile will not appear unless + you kind of mess with it and scroll around for a while. This + is because EDITART loads TILES###.ART files until 1 is not + found, meaning that it will stop when it doesn't find + TILES003.ART. There are probably some other nasty bugs like + this. To get around it, you could add 1 tile to the next file, + save and quit. Or you could use RSIZEART.EXE to make 1 huge + ART file, add 1 tile way up high (if you have enough memory), + and then run RSIZEART.EXE again to 256 tiles per file or + whatever you like. Remember that the ART files need to be split + in such a way that each individual .ART file must fit in + memory, or else EDITART will crash. + + - It's time I document how you can add voxels to the Build engine. + The code is not the cleanest, but at least it works. First + you must load each voxel into memory using the qloadkvx + function. You specify the filename of the .KVX file and an + index that you want to use to reference the voxel. You can + pack .KVX files in a .GRP file if you want. The index must + be in this range: 0 <= index < MAXVOXELS where MAXVOXELS is + currently 512. This index works sort of like a picnum, but I + have a totally separate array for these indeces so you don't + need to mess with your art file at all. Since qloadkvx + allocates memory off of my cacheing system, you must call it + after loadpics which allocates all memory. + + Function parameters: + void qloadkvx(long voxindex, char *filename) + + loadpics("tiles000.art"); + qloadkvx(0L,"voxel000.kvx"); + qloadkvx(1L,"voxel001.kvx"); + + Now to actually display the voxel, you need to set the + (sprite[?].cstat&48) to equal 48 like this: + sprite[?].cstat |= 48; + I have no special collision code for voxels. They are simply + treated as face sprites. + + If ((sprite[?].cstat&48) == 48) + You should set the sprite[?].picnum to equal the VOXEL + index of the voxel that you passed to qloadkvx. If you don't + do this you will see nothing. To handle this index remapping + it is a good idea to make some array like this: + short picnumtovox[MAXTILES]; + and save the array in some file (or in the .GRP file) + + Many other fields of the sprite structure also affect voxels, + such as: ang, shade, pal, xrepeat, yrepeat. + + Note: To view voxels in the Build editor, you will need to do + the same qloadkvx calls in your BSTUB.C. + + And now a warning: Voxels tend to draw the fastest when + they are tall and thin. For example, a telephone poll + would work just great. They slow down very quickly as + you add detail. This is why you don't see any large + voxels in SW and Blood. + + - Something you should know about this version of the engine: + Over the summer, I got a lot of pressure from GT to add + MMX support to the Build engine, so I bought a Pentium II. + I messed around with the code quite a bit and discovered + that MMX really didn't help at all. In fact, in some ways + it made the code slower. The problem is that the inner + loops of Build are already optimized really well. I have + found that MMX is useful only because it gives you extra + registers. Unfortunately, the Build loops don't need extra + registers since they aren't very complex. + Now there are 2 major differences between an old Pentium and + a Pentium II. A Pentium II is like a Pentium PRO with MMX. + So I tried to optimize Build for Pentium PRO's. I was + actually able to get about a 50% speed increase mostly due + to avoiding those awful partial stalls. But there are + SEVERAL catches: + + 1. First of all, you need to enable WRITE-COMBINING for + video memory to get all this extra speed. One popular + program which does this is FASTVID. You should be able + to find it easily on the net. If you do not enable + WRITE-COMBINING, the engine actually runs SLOWER than + the original version! Unfortunately, neither DOS nor + WINDOWS 95 enable WRITE-COMBINING by default, so you need to + load a driver. Even worse, if you're in WINDOWS 95, the + program which enables WRITE-COMBINING will crash because + you can only set the PPRO registers in Priviledge Level 0. + You can still enable WRITE-COMBINING in WINDOWS 95, but you + have to run the program in your AUTOEXEC.BAT file. I wish + you all good luck on getting the average user to be able + to accomplish this feat. Quake has the same problem. + You'll find the same thing in their documentation. + + 2. The second catch is that my code tries to auto-detect + whether you have a Pentium, Pentium MMX, Pentium PRO, of + Pentium II. Of course this means, that if you don't have + an Intel processor, it's possible that the auto-detect code + may crash. I haven't had the opportunity to test this + myself. And since I can never guarantee it will always work + I made a way for you to disable the new code altogether + should this happen. Here's how you disable the new code + in the Build engine: + + extern long dommxoverlay; //(from engine.obj) + + Before you first call initengine, set dommxoverlay = 0; + + The default is dommxoverlay = 1 and it will run the code. + + !!! THIS IS NO LONGER TRUE. + !!! do #include "engine.h" in your code, and + !!! use setmmxoverlay(1) or setmmxoverlay(0) to set + !!! this BEFORE initengine. It defaults to 1, so you + !!! really only need to call this to disable the + !!! overlay. dommxoverlay is no longer exposed. You + !!! can also call int getmmxoverlay(void) to find out + !!! what you've set it to. The value is locked in + !!! once you call initengine(). --ryan. 05/22/2001 diff --git a/buildengine/buildgl.c b/buildengine/buildgl.c new file mode 100755 index 0000000..3862473 --- /dev/null +++ b/buildengine/buildgl.c @@ -0,0 +1,178 @@ +/* + * OpenGL support code. + * + * Written by Ryan C. Gordon. (icculus@clutteredmind.org) + * + * Please do NOT harrass Ken Silverman about any code modifications + * (including this file) to BUILD. + */ + +/* + * "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman + * Ken Silverman's official web site: "http://www.advsys.net/ken" + * See the included license file "BUILDLIC.TXT" for license info. + * This file IS NOT A PART OF Ken Silverman's original release + */ + +#include +#include +#include +#include "platform.h" +#include "SDL.h" +#include "display.h" +#include "buildgl.h" + +glGetString_t dglGetString = NULL; +glBegin_t dglBegin = NULL; +glEnd_t dglEnd = NULL; +glClear_t dglClear = NULL; +glClearColor_t dglClearColor = NULL; +glDrawPixels_t dglDrawPixels = NULL; +glGetPixelMapfv_t dglGetPixelMapfv = NULL; +glPixelMapfv_t dglPixelMapfv = NULL; +glPixelStorei_t dglPixelStorei = NULL; +glEnable_t dglEnable = NULL; +glDisable_t dglDisable = NULL; +glViewport_t dglViewport = NULL; +glGenTextures_t dglGenTextures = NULL; +glDeleteTextures_t dglDeleteTextures = NULL; +glBindTexture_t dglBindTexture = NULL; +glTexParameteri_t dglTexParameteri = NULL; +glTexImage2D_t dglTexImage2D = NULL; +glTexCoord2f_t dglTexCoord2f = NULL; +glVertex2f_t dglVertex2f = NULL; +glVertex3f_t dglVertex3f = NULL; +glColor3f_t dglColor3f = NULL; +glGetError_t dglGetError = NULL; +glGetIntegerv_t dglGetIntegerv = NULL; +glClearDepth_t dglClearDepth = NULL; +glDepthFunc_t dglDepthFunc = NULL; +glShadeModel_t dglShadeModel = NULL; +glMatrixMode_t dglMatrixMode = NULL; +glLoadIdentity_t dglLoadIdentity = NULL; +glPixelTransferi_t dglPixelTransferi = NULL; + + +void sgldebug(const char *fmt, ...); +static int debug_hall_of_mirrors = 0; + + +static void *opengl_symload(void **ptr, const char *sym) +{ + void *retval = NULL; + + retval = SDL_GL_GetProcAddress(sym); + if (retval == NULL) + sgldebug("Symbol \"%s\" NOT located.", sym); + else + sgldebug("Symbol \"%s\" located.", sym); + + if (ptr != NULL) + *ptr = retval; + + return(retval); +} /* open_symload */ + + +static int opengl_load_symbols(void) +{ + if (!opengl_symload((void **) &dglGetString, "glGetString")) return(-1); + if (!opengl_symload((void **) &dglBegin, "glBegin")) return(-1); + if (!opengl_symload((void **) &dglEnd, "glEnd")) return(-1); + if (!opengl_symload((void **) &dglClear, "glClear")) return(-1); + if (!opengl_symload((void **) &dglClearColor, "glClearColor")) return(-1); + if (!opengl_symload((void **) &dglDrawPixels, "glDrawPixels")) return(-1); + if (!opengl_symload((void **) &dglPixelStorei, "glPixelStorei")) return(-1); + if (!opengl_symload((void **) &dglGetPixelMapfv, "glGetPixelMapfv")) return(-1); + if (!opengl_symload((void **) &dglPixelMapfv, "glPixelMapfv")) return(-1); + if (!opengl_symload((void **) &dglEnable, "glEnable")) return(-1); + if (!opengl_symload((void **) &dglDisable, "glDisable")) return(-1); + if (!opengl_symload((void **) &dglViewport, "glViewport")) return(-1); + if (!opengl_symload((void **) &dglGenTextures, "glGenTextures")) return(-1); + if (!opengl_symload((void **) &dglDeleteTextures, "glDeleteTextures")) return(-1); + if (!opengl_symload((void **) &dglBindTexture, "glBindTexture")) return(-1); + if (!opengl_symload((void **) &dglTexParameteri, "glTexParameteri")) return(-1); + if (!opengl_symload((void **) &dglTexImage2D, "glTexImage2D")) return(-1); + if (!opengl_symload((void **) &dglTexCoord2f, "glTexCoord2f")) return(-1); + if (!opengl_symload((void **) &dglVertex2f, "glVertex2f")) return(-1); + if (!opengl_symload((void **) &dglVertex3f, "glVertex3f")) return(-1); + if (!opengl_symload((void **) &dglColor3f, "glColor3f")) return(-1); + if (!opengl_symload((void **) &dglGetError, "glGetError")) return(-1); + if (!opengl_symload((void **) &dglGetIntegerv, "glGetIntegerv")) return(-1); + if (!opengl_symload((void **) &dglClearDepth, "glClearDepth")) return(-1); + if (!opengl_symload((void **) &dglDepthFunc, "glDepthFunc")) return(-1); + if (!opengl_symload((void **) &dglShadeModel, "glShadeModel")) return(-1); + if (!opengl_symload((void **) &dglMatrixMode, "glMatrixMode")) return(-1); + if (!opengl_symload((void **) &dglLoadIdentity, "glLoadIdentity")) return(-1); + if (!opengl_symload((void **) &dglPixelTransferi, "glPixelTransferi")) return(-1); + + return(0); +} /* opengl_load_symbols */ + + +static int opengl_try_libname(const char *libname) +{ + int rc = -1; + + sgldebug("Trying to open library \"%s\"...", + libname ? libname : "[default]"); + SDL_ClearError(); + rc = SDL_GL_LoadLibrary(libname); + + if (rc == -1) + sgldebug("Library opening failed; [%s].", SDL_GetError()); + else + { + sgldebug("Library opened successfully!"); + rc = opengl_load_symbols(); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + } /* else */ + + return(rc); +} /* opengl_try_libname */ + + +static int opengl_lib_is_loaded = 0; + +int opengl_load_library(void) +{ + char *envlib = getenv(BUILD_GLLIBRARY); + int rc = 0; + + debug_hall_of_mirrors = (getenv(BUILD_HALLOFMIRRORS) != NULL); + + if (!opengl_lib_is_loaded) /* it's cool. Go on. */ + { + rc = opengl_try_libname(envlib); + if (rc == -1) + { + sgldebug("Out of ideas. Giving up."); + return(-1); + } /* if */ + + opengl_lib_is_loaded = 1; + } /* if */ + + return(0); +} /* opengl_load_library */ + + +static Uint8 mirrorcolor = 0; + +void opengl_swapbuffers(void) +{ + if (using_opengl()) + { + SDL_GL_SwapBuffers(); + if (debug_hall_of_mirrors) + { + dglClearColor( ((GLfloat) mirrorcolor) / 255.0, 0.0f, 0.0f, 0.0f ); + mirrorcolor++; + } /* if */ + dglClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + dglEnable(GL_DEPTH_TEST); + } /* if */ +} /* opengl_swapbuffers */ + +/* end of buildgl.c ... */ + diff --git a/buildengine/buildgl.h b/buildengine/buildgl.h new file mode 100755 index 0000000..ae3929b --- /dev/null +++ b/buildengine/buildgl.h @@ -0,0 +1,124 @@ +/* + * Experimental OpenGL support code for Build. + * + * Written by Ryan C. Gordon. (icculus@clutteredmind.org) + * + * Please do NOT harrass Ken Silverman about any code modifications + * (including this file) to BUILD. + */ + +/* + * "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman + * Ken Silverman's official web site: "http://www.advsys.net/ken" + * See the included license file "BUILDLIC.TXT" for license info. + * This file IS NOT A PART OF Ken Silverman's original release + */ + +#ifndef _INCLUDE_BUILDGL_H_ +#define _INCLUDE_BUILDGL_H_ + +#if (!defined USE_OPENGL) +#error USE_OPENGL is not defined. Do you REALLY want to compile this? +#endif + +#include + +typedef const GLubyte* (*glGetString_t)(GLenum name); +extern glGetString_t dglGetString; + +typedef void (*glBegin_t)(GLenum mode); +extern glBegin_t dglBegin; + +typedef void (*glEnd_t)(void); +extern glEnd_t dglEnd; + +typedef void (*glClear_t)(GLbitfield mask); +extern glClear_t dglClear; + +typedef void (*glClearColor_t)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); +extern glClearColor_t dglClearColor; + +typedef void (*glDrawPixels_t)(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +extern glDrawPixels_t dglDrawPixels; + +typedef void (*glGetPixelMapfv_t)(GLenum map, GLfloat *values); +extern glGetPixelMapfv_t dglGetPixelMapfv; + +typedef void (*glPixelMapfv_t)(GLenum map, GLint mapsize, const GLfloat *values); +extern glPixelMapfv_t dglPixelMapfv; + +typedef void (*glPixelStorei_t)(GLenum pname, GLint param); +extern glPixelStorei_t dglPixelStorei; + +typedef void (*glEnable_t)(GLenum cap); +extern glEnable_t dglEnable; + +typedef void (*glDisable_t)(GLenum cap); +extern glDisable_t dglDisable; + +typedef void (*glViewport_t)(GLint x, GLint y, GLsizei width, GLsizei height); +extern glViewport_t dglViewport; + +typedef void (*glGenTextures_t)(GLsizei n, GLuint *textures); +extern glGenTextures_t dglGenTextures; + +typedef void (*glDeleteTextures_t)(GLsizei n, const GLuint *textures); +extern glDeleteTextures_t dglDeleteTextures; + +typedef void (*glBindTexture_t)(GLenum target, GLuint texture); +extern glBindTexture_t dglBindTexture; + +typedef void (*glTexParameteri_t)(GLenum target, GLenum pname, GLint param); +extern glTexParameteri_t dglTexParameteri; + +typedef void (*glTexImage2D_t)(GLenum target, GLint level, + GLint internalFormat, GLsizei width, + GLsizei height, GLint border, GLenum format, + GLenum type, const GLvoid *pixels); +extern glTexImage2D_t dglTexImage2D; + +typedef void (*glTexCoord2f_t)(GLfloat s, GLfloat t); +extern glTexCoord2f_t dglTexCoord2f; + +typedef void (*glVertex2f_t)(GLfloat x, GLfloat y); +extern glVertex2f_t dglVertex2f; + +typedef void (*glVertex3f_t)(GLfloat x, GLfloat y, GLfloat z); +extern glVertex3f_t dglVertex3f; + +typedef void (*glColor3f_t)(GLfloat red, GLfloat green, GLfloat blue); +extern glColor3f_t dglColor3f; + +typedef GLenum (*glGetError_t)(void); +extern glGetError_t dglGetError; + +typedef void (*glGetIntegerv_t)(GLenum pname, GLint *params); +extern glGetIntegerv_t dglGetIntegerv; + +typedef void (*glClearDepth_t)(GLclampd depth); +extern glClearDepth_t dglClearDepth; + +typedef void (*glDepthFunc_t)(GLenum func); +extern glDepthFunc_t dglDepthFunc; + +typedef void (*glShadeModel_t)(GLenum mode); +extern glShadeModel_t dglShadeModel; + +typedef void (*glMatrixMode_t)(GLenum mode); +extern glMatrixMode_t dglMatrixMode; + +typedef void (*glLoadIdentity_t)(void); +extern glLoadIdentity_t dglLoadIdentity; + +typedef void (*glPixelTransferi_t)(GLenum pname, GLint param); +extern glPixelTransferi_t dglPixelTransferi; + +int opengl_load_library(void); +void opengl_gen_2d_textures(int xdim, int ydim); +void opengl_build_2d_quads(int x, int y, int w, int h); +void opengl_swapbuffers(void); + +#endif /* !defined _INCLUDE_BUILDGL_H_ */ + +/* end of buildgl.h ... */ + diff --git a/buildengine/buildinf.txt b/buildengine/buildinf.txt new file mode 100755 index 0000000..22fcd88 --- /dev/null +++ b/buildengine/buildinf.txt @@ -0,0 +1,882 @@ +// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman +// Ken Silverman's official web site: "http://www.advsys.net/ken" +// See the included license file "BUILDLIC.TXT" for license info. + +Build information to get you started: + +The first half of this file explains the .ART, .MAP, and PALETTE.DAT formats. +The second half has documentation about every BUILD engine function, what it + does, and what the parameters are. + +-Ken S. + +------------------------------------------------------------------------------ +Documentation on Ken's .ART file format by Ken Silverman + + I am documenting my ART format to allow you to program your own custom +art utilites if you so desire. I am still planning on writing the script +system. + + All art files must have xxxxx###.ART. When loading an art file you +should keep trying to open new xxxxx###'s, incrementing the number, until +an art file is not found. + + +1. long artversion; + + The first 4 bytes in the art format are the version number. The current + current art version is now 1. If artversion is not 1 then either it's the + wrong art version or something is wrong. + +2. long numtiles; + + Numtiles is not really used anymore. I wouldn't trust it. Actually + when I originally planning art version 1 many months ago, I thought I + would need this variable, but it turned it is was unnecessary. To get + the number of tiles, you should search all art files, and check the + localtilestart and localtileend values for each file. + +3. long localtilestart; + + Localtilestart is the tile number of the first tile in this art file. + +4. long localtileend; + + Localtileend is the tile number of the last tile in this art file. + Note: Localtileend CAN be higher than the last used slot in an art + file. + + Example: If you chose 256 tiles per art file: + TILES000.ART -> localtilestart = 0, localtileend = 255 + TILES001.ART -> localtilestart = 256, localtileend = 511 + TILES002.ART -> localtilestart = 512, localtileend = 767 + TILES003.ART -> localtilestart = 768, localtileend = 1023 + +5. short tilesizx[localtileend-localtilestart+1]; + + This is an array of shorts of all the x dimensions of the tiles + in this art file. If you chose 256 tiles per art file then + [localtileend-localtilestart+1] should equal 256. + +6. short tilesizy[localtileend-localtilestart+1]; + + This is an array of shorts of all the y dimensions. + +7. long picanm[localtileend-localtilestart+1]; + + This array of longs stores a few attributes for each tile that you + can set inside EDITART. You probably won't be touching this array, but + I'll document it anyway. + + Bit: |31 24|23 16|15 8|7 0| + ----------------------------------------------------------------- + | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | + ----------------------------------------------------------------- + | Anim. | Signed char | Signed char | | Animate | + | Speed | Y-center | X-center | | number | + --------| offset | offset | |------------ + --------------------------------| ------------ + | Animate type:| + | 00 - NoAnm | + | 01 - Oscil | + | 10 - AnmFd | + | 11 - AnmBk | + ---------------- + You probably recognize these: + Animate speed - EDITART key: 'A', + and - to adjust + Signed char x&y offset - EDITART key: '`', Arrows to adjust + Animate number&type - EDITART key: +/- on keypad + +8. After the picanm's, the rest of the file is straight-forward rectangular + art data. You must go through the tilesizx and tilesizy arrays to find + where the artwork is actually stored in this file. + + Note: The tiles are stored in the opposite coordinate system than + the screen memory is stored. Example on a 4*4 file: + + Offsets: + ----------------- + | 0 | 4 | 8 |12 | + ----------------- + | 1 | 5 | 9 |13 | + ----------------- + | 2 | 6 |10 |14 | + ----------------- + | 3 | 7 |11 |15 | + ----------------- + + + +---------------------------------------------------------------------------- + If you wish to display the artwork, you will also need to load your +palette. To load the palette, simply read the first 768 bytes of your +palette.dat and write it directly to the video card - like this: + + Example: + long i, fil; + + fil = open("palette.dat",O_BINARY|O_RDWR,S_IREAD); + read(fil,&palette[0],768); + close(fil); + + outp(0x3c8,0); + for(i=0;i<768;i++) + outp(0x3c9,palette[i]); +------------------------------------------------------------------------------ + +Packet format for DUKE3D (specifically for network mode 1, n(n-1) mode): + +Example bunch of packets: +A B C D E F G H I J K L M N... O +--------------------------------------------------------------------- +d9 00 d9 11 01 00 - - - - - - - - - - 4f 16 31 +da 00 da 11 01 00 - - - - - - - - - - b2 b7 9d +db 00 db 11 01 00 - - - - - - - - - - b1 24 62 +dc 00 dc 11 01 00 - - - - - - - - - - ca 1d 58 +dd 00 dd 11 01 00 - - - - - - - - - - a9 94 14 +de 00 de 11 01 05 00 00 - - 03 00 - - - - c5 50 b9 +df 00 df 11 01 0f a1 ff fe 09 00 00 26 - - - e2 88 6f +e0 00 e0 11 01 04 - - - - fd ff - - - - 77 51 d7 +e1 00 e1 11 01 03 1f 00 ff 09 - - - - - - ac 14 b7 +e2 00 e2 11 01 0b 9c 00 fb 09 - - 24 - - - f8 6c 22 + +GAME sends fields D-N +MMULTI adds fields A-C and O for error correction. + +A: Packet count sending modulo 256 +B: Error state. Usually 0. To request a resend, bit 0 is set. In order + to catch up on networks, sending many packets is bad, so 2 packets + are sent in 1 IPX packet. To send 2 packets in 1 packet, bit 1 is set. + In special cases, this value may be different. +C: Packet count receiving modulo 256 + +D: Message header byte. These are all the possible values currently. You + are probably only interested in case 17. Note that fields E-N apply + to case 17 only. + 0: send movement info from master to slave (network mode 0 only) + 1: send movement info from slave to master (network mode 0 only) + 4: user-typed messages + 5: Re-start level with given parameters + 6: Send player name + 7: Play Remote Ridicule sound + 8: Re-start level with given parameters for a user map + 17: send movement info to everybody else (network mode 1 only) + 250: Wait for Everybody (Don't start until everybody's done loading) + 255: Player quit to DOS + +E: Timing byte used to calculate lag time. This prevents the 2 computer's + timers from drifting apart. + +F: Bits field byte. Fields G-M are sent only when certain bits + in this byte are set. + +G: X momentum update (2 bytes). Sent only if ((F&1) != 0) + +H: Y momentum update (2 bytes). Sent only if ((F&2) != 0) + +I: Angle momentum update (2 bytes). Sent only if ((F&4) != 0) + +J: The states of 8 different keys (1 byte). Sent only if ((F&8) != 0) +K: The states of 8 different keys (1 byte). Sent only if ((F&16) != 0) +L: The states of 8 different keys (1 byte). Sent only if ((F&32) != 0) +M: The states of 8 different keys (1 byte). Sent only if ((F&64) != 0) + +N: Sync checking byte. Useful for debugging programming errors. Can be a + variable number of bytes. Actual number of sync checking bytes is + calculated by length of the whole packet minus the rest of the bytes sent. + +O: CRC-16 + +------------------------------------------------------------------------------ +| @@@@@@@@@@@ @@@ @@@ @@@@@@@@@ @@@ @@@@@@@@@ | +| @@@@@@@@@@@@@ @@@ @@@ @@@@@@@@@ @@@ @@@@@@@@@@@ | +| @@@ @@@@ @@@ @@@ @@@ @@@ @@@ @@@@@ | +| @@@ @@@ @@@ @@@ @@@ @@@ @@@ @@@@ | +| @@@ @@@@ @@@ @@@ @@@ @@@ @@@ @@@ | +| @@@@@@@@@@@@@ @@@ @@@ @@@ @@@ @@@ @@@ | +| @@@@@@@@@@@@@ @@@ @@@ @@@ @@@ @@@ @@@ | +| @@@ @@@@ @@@ @@@ @@@ @@@ @@@ @@@ | +| @@@ @@@ @@@ @@@ @@@ @@@ @@@ @@@@ | +| @@@ @@@@ @@@@ @@@@ @@@ @@@ @@@ @@@@@ | +| @@@@@@@@@@@@@ @@@@@@@@@@@ @@@@@@@@@ @@@@@@@@@@@@ @@@@@@@@@@@ | +| @@@@@@@@@@@ @@@@@@@ @@@@@@@@@ @@@@@@@@@@@@ @@@@@@@@@ | +| | +| M A P F O R M A T ! | +------------------------------------------------------------------------------ + +Here is Ken's documentation on the COMPLETE BUILD map format: +BUILD engine and editor programmed completely by Ken Silverman + +Here's how you should read a BUILD map file: +{ + fil = open(???); + + //Load map version number (current version is 7L) + read(fil,&mapversion,4); + + //Load starting position + read(fil,posx,4); + read(fil,posy,4); + read(fil,posz,4); //Note: Z coordinates are all shifted up 4 + read(fil,ang,2); //All angles are from 0-2047, clockwise + read(fil,cursectnum,2); //Sector of starting point + + //Load all sectors (see sector structure described below) + read(fil,&numsectors,2); + read(fil,§or[0],sizeof(sectortype)*numsectors); + + //Load all walls (see wall structure described below) + read(fil,&numwalls,2); + read(fil,&wall[0],sizeof(walltype)*numwalls); + + //Load all sprites (see sprite structure described below) + read(fil,&numsprites,2); + read(fil,&sprite[0],sizeof(spritetype)*numsprites); + + close(fil); +} + + ------------------------------------------------------------- + | @@@@@@@ @@@@@@@ @@@@@@@ @@@@@@@@ @@@@@@@ @@@@@@@ @@@@@@@ | + | @@ @@ @@ @@ @@ @@ @@ @@@ @@ | + | @@@@@@@ @@@@@ @@ @@ @@ @@ @@@@@@@ @@@@@@@ | + | @@ @@ @@ @@ @@ @@ @@ @@@ @@ | + | @@@@@@@ @@@@@@@ @@@@@@@ @@ @@@@@@@ @@ @@ @@@@@@@ | + ------------------------------------------------------------- + + //sizeof(sectortype) = 40 +typedef struct +{ + short wallptr, wallnum; + long ceilingz, floorz; + short ceilingstat, floorstat; + short ceilingpicnum, ceilingheinum; + signed char ceilingshade; + char ceilingpal, ceilingxpanning, ceilingypanning; + short floorpicnum, floorheinum; + signed char floorshade; + char floorpal, floorxpanning, floorypanning; + char visibility, filler; + short lotag, hitag, extra; +} sectortype; +sectortype sector[1024]; + +wallptr - index to first wall of sector +wallnum - number of walls in sector +z's - z coordinate (height) of ceiling / floor at first point of sector +stat's + bit 0: 1 = parallaxing, 0 = not "P" + bit 1: 1 = sloped, 0 = not + bit 2: 1 = swap x&y, 0 = not "F" + bit 3: 1 = double smooshiness "E" + bit 4: 1 = x-flip "F" + bit 5: 1 = y-flip "F" + bit 6: 1 = Align texture to first wall of sector "R" + bits 7-15: reserved +picnum's - texture index into art file +heinum's - slope value (rise/run) (0-parallel to floor, 4096-45 degrees) +shade's - shade offset of ceiling/floor +pal's - palette lookup table number (0 - use standard colors) +panning's - used to align textures or to do texture panning +visibility - determines how fast an area changes shade relative to distance +filler - useless byte to make structure aligned +lotag, hitag, extra - These variables used by the game programmer only + + + ----------------------------------------------- + | @@ @@ @@@@@@@@ @@ @@ @@@@@@@ | + | @@ @@ @@ @@ @@ @@ @@ | + | @@ @@ @@ @@@@@@@@ @@ @@ @@@@@@@ | + | @@ @@@@ @@ @@ @@ @@ @@ @@ | + | @@@ @@@@ @@ @@ @@@@@@@ @@@@@@@ @@@@@@@ | + ----------------------------------------------| + + //sizeof(walltype) = 32 +typedef struct +{ + long x, y; + short point2, nextwall, nextsector, cstat; + short picnum, overpicnum; + signed char shade; + char pal, xrepeat, yrepeat, xpanning, ypanning; + short lotag, hitag, extra; +} walltype; +walltype wall[8192]; + +x, y: Coordinate of left side of wall, get right side from next wall's left side +point2: Index to next wall on the right (always in the same sector) +nextwall: Index to wall on other side of wall (-1 if there is no sector) +nextsector: Index to sector on other side of wall (-1 if there is no sector) +cstat: + bit 0: 1 = Blocking wall (use with clipmove, getzrange) "B" + bit 1: 1 = bottoms of invisible walls swapped, 0 = not "2" + bit 2: 1 = align picture on bottom (for doors), 0 = top "O" + bit 3: 1 = x-flipped, 0 = normal "F" + bit 4: 1 = masking wall, 0 = not "M" + bit 5: 1 = 1-way wall, 0 = not "1" + bit 6: 1 = Blocking wall (use with hitscan / cliptype 1) "H" + bit 7: 1 = Transluscence, 0 = not "T" + bit 8: 1 = y-flipped, 0 = normal "F" + bit 9: 1 = Transluscence reversing, 0 = normal "T" + bits 10-15: reserved +picnum - texture index into art file +overpicnum - texture index into art file for masked walls / 1-way walls +shade - shade offset of wall +pal - palette lookup table number (0 - use standard colors) +repeat's - used to change the size of pixels (stretch textures) +pannings - used to align textures or to do texture panning +lotag, hitag, extra - These variables used by the game programmer only + + ------------------------------------------------------------- + | @@@@@@@ @@@@@@@ @@@@@@@ @@@@@@ @@@@@@@@ @@@@@@@ @@@@@@@ | + | @@ @@ @@ @@ @@@ @@ @@ @@ @@ | + | @@@@@@@ @@@@@@@ @@@@@@@ @@ @@ @@@@@ @@@@@@@ | + | @@ @@ @@ @@ @@ @@ @@ @@ | + | @@@@@@@ @@ @@ @@ @@@@@@ @@ @@@@@@@ @@@@@@@ | + ------------------------------------------------------------- + + //sizeof(spritetype) = 44 +typedef struct +{ + long x, y, z; + short cstat, picnum; + signed char shade; + char pal, clipdist, filler; + unsigned char xrepeat, yrepeat; + signed char xoffset, yoffset; + short sectnum, statnum; + short ang, owner, xvel, yvel, zvel; + short lotag, hitag, extra; +} spritetype; +spritetype sprite[4096]; +x, y, z - position of sprite - can be defined at center bottom or center +cstat: + bit 0: 1 = Blocking sprite (use with clipmove, getzrange) "B" + bit 1: 1 = transluscence, 0 = normal "T" + bit 2: 1 = x-flipped, 0 = normal "F" + bit 3: 1 = y-flipped, 0 = normal "F" + bits 5-4: 00 = FACE sprite (default) "R" + 01 = WALL sprite (like masked walls) + 10 = FLOOR sprite (parallel to ceilings&floors) + bit 6: 1 = 1-sided sprite, 0 = normal "1" + bit 7: 1 = Real centered centering, 0 = foot center "C" + bit 8: 1 = Blocking sprite (use with hitscan / cliptype 1) "H" + bit 9: 1 = Transluscence reversing, 0 = normal "T" + bits 10-14: reserved + bit 15: 1 = Invisible sprite, 0 = not invisible +picnum - texture index into art file +shade - shade offset of sprite +pal - palette lookup table number (0 - use standard colors) +clipdist - the size of the movement clipping square (face sprites only) +filler - useless byte to make structure aligned +repeat's - used to change the size of pixels (stretch textures) +offset's - used to center the animation of sprites +sectnum - current sector of sprite +statnum - current status of sprite (inactive/monster/bullet, etc.) + +ang - angle the sprite is facing +owner, xvel, yvel, zvel, lotag, hitag, extra - These variables used by the + game programmer only +------------------------------------------------------------------------------ + + + + +----------------------------------------------------------------------------- +| IMPORTANT ENGINE FUNCTIONS: | +----------------------------------------------------------------------------- + +initengine() + Initializes many variables for the BUILD engine. You should call this + once before any other functions of the BUILD engine are used. + +uninitengine(); + Frees buffers. You should call this once at the end of the program + before quitting to dos. + +loadboard(char *filename, long *posx, long *posy, long *posz, short *ang, short *cursectnum) +saveboard(char *filename, long *posx, long *posy, long *posz, short *ang, short *cursectnum) + Loads/saves the given board file from memory. Returns -1 if file not + found. If no extension is given, .MAP will be appended to the filename. + +loadpics(char *filename); + Loads the given artwork file into memory for the BUILD engine. + Returns -1 if file not found. If no extension is given, .ART will + be appended to the filename. + +loadtile(short tilenum) + Loads a given tile number from disk into memory if it is not already in + memory. This function calls allocache internally. A tile is not in the + cache if (waloff[tilenum] == 0) + +----------------------------------------------------------------------------- +| SCREEN STATUS FUNCTIONS: | +----------------------------------------------------------------------------- + +setgamemode(char vidoption, long xdim, long ydim); + This function sets the video mode to 320*200*256color graphics. + Since BUILD supports several different modes including mode x, + mode 13h, and other special modes, I don't expect you to write + any graphics output functions. (Soon I have all the necessary + functions) If for some reason, you use your own graphics mode, + you must call this function again before using the BUILD drawing + functions. + + vidoption can be anywhere from 0-6 + xdim,ydim can be any vesa resolution if vidoption = 1 + xdim,ydim must be 320*200 for any other mode. + (see graphics mode selection in my setup program) + +setview(long x1, long y1, long x2, long y2) + Sets the viewing window to a given rectangle of the screen. + Example: For full screen 320*200, call like this: setview(0L,0L,319L,199L); + +nextpage(); + This function flips to the next video page. After a screen is prepared, + use this function to view the screen. + +----------------------------------------------------------------------------- +| DRAWING FUNCTIONS: | +----------------------------------------------------------------------------- + +drawrooms(long posx, long posy, long posz, short ang, long horiz, short cursectnum) + This function draws the 3D screen to the current drawing page, + which is not yet shown. This way, you can overwrite some things + over the 3D screen such as a gun. Be sure to call the drawmasks() + function soon after you call the drawrooms() function. To view + the screen, use the nextpage() function. The nextpage() function + should always be called sometime after each draw3dscreen() + function. + +drawmasks(); + This function draws all the sprites and masked walls to the current + drawing page which is not yet shown. The reason I have the drawing + split up into these 2 routines is so you can animate just the + sprites that are about to be drawn instead of having to animate + all the sprites on the whole board. Drawrooms() prepares these + variables: spritex[], spritey[], spritepicnum[], thesprite[], + and spritesortcnt. Spritesortcnt is the number of sprites about + to be drawn to the page. To change the sprite's picnum, simply + modify the spritepicnum array If you want to change other parts + of the sprite structure, then you can use the thesprite array to + get an index to the actual sprite number. + +clearview(long col) + Clears the current video page to the given color + +clearallviews(long col) + Clears all video pages to the given color + +drawmapview (long x, long y, long zoom, short ang) + Draws the 2-D texturized map at the given position into the viewing window. + +rotatesprite (long sx, long sy, long z, short a, short picnum, + signed char dashade, char dapalnum, char dastat, + long cx1, long cy1, long cx2, long cy2) + (sx, sy) is the center of the sprite to draw defined as + screen coordinates shifted up by 16. + (z) is the zoom. Normal zoom is 65536. + Ex: 131072 is zoomed in 2X and 32768 is zoomed out 2X. + (a) is the angle (0 is straight up) + (picnum) is the tile number + (dashade) is 0 normally but can be any standard shade up to 31 or 63. + (dapalnum) can be from 0-255. + if ((dastat&1) == 0) - no transluscence + if ((dastat&1) != 0) - transluscence + if ((dastat&2) == 0) - don't scale to setview's viewing window + if ((dastat&2) != 0) - scale to setview's viewing window (windowx1,etc.) + if ((dastat&4) == 0) - nuttin' special + if ((dastat&4) != 0) - y-flip image + if ((dastat&8) == 0) - clip to startumost/startdmost + if ((dastat&8) != 0) - don't clip to startumost/startdmost + if ((dastat&16) == 0) - use Editart center as point passed + if ((dastat&16) != 0) - force point passed to be top-left corner + if ((dastat&32) == 0) - nuttin' special + if ((dastat&32) != 0) - use reverse transluscence + if ((dastat&64) == 0) - masked drawing (check 255's) (slower) + if ((dastat&64) != 0) - draw everything (don't check 255's) (faster) + if ((dastat&128) == 0) - nuttin' special + if ((dastat&128) != 0) - automatically draw to all video pages + + Note: As a special case, if both ((dastat&2) != 0) and ((dastat&8) != 0) + then rotatesprite will scale to the full screen (0,0,xdim-1,ydim-1) + rather than setview's viewing window. (windowx1,windowy1,etc.) This + case is useful for status bars, etc. + + Ex: rotatesprite(160L<<16,100L<<16,65536,totalclock<<4, + DEMOSIGN,2,50L,50L,270L,150L); + This example will draw the DEMOSIGN tile in the center of the + screen and rotate about once per second. The sprite will only + get drawn inside the rectangle from (50,50) to (270,150) + +drawline256(long x1, long y1, long x2, long y2, char col) + Draws a solid line from (x1,y1) to (x2,y2) with color (col) + For this function, screen coordinates are all shifted up 16 for precision. + +printext256(long xpos, long ypos, short col, short backcol, + char *message, char fontsize) + Draws a text message to the screen. + (xpos,ypos) - position of top left corner + col - color of text + backcol - background color, if -1, then background is transparent + message - text message + fontsize - 0 - 8*8 font + 1 - 4*6 font + +----------------------------------------------------------------------------- +| MOVEMENT COLLISION FUNCTIONS: | +----------------------------------------------------------------------------- + +clipmove(long *x, long *y, long *z, short *sectnum, long xvect, long yvect, + long walldist, long ceildist, long flordist, unsigned long cliptype) + Moves any object (x, y, z) in any direction at any velocity and will + make sure the object will stay a certain distance from walls (walldist) + Pass the pointers of the starting position (x, y, z). Then + pass the starting position's sector number as a pointer also. + Also these values will be modified accordingly. Pass the + direction and velocity by using a vector (xvect, yvect). + If you don't fully understand these equations, please call me. + xvect = velocity * cos(angle) + yvect = velocity * sin(angle) + Walldist tells how close the object can get to a wall. I use + 128L as my default. If you increase walldist all of a sudden + for a certain object, the object might leak through a wall, so + don't do that! + Cliptype is a mask that tells whether the object should be clipped + to or not. The lower 16 bits are anded with wall[].cstat and the higher + 16 bits are anded with sprite[].cstat. + + Clipmove can either return 0 (touched nothing) + 32768+wallnum (wall first touched) + 49152+spritenum (sprite first touched) + +pushmove (long *x, long *y, long *z, short *sectnum, + long walldist, long ceildist, long flordist, unsigned long cliptype) + This function makes sure a player or monster (defined by x, y, z, sectnum) + is not too close to a wall. If it is, then it attempts to push it away. + If after 256 tries, it is unable to push it away, it returns -1, in which + case the thing should gib. + +getzrange(long x, long y, long z, short sectnum, + long *ceilz, long *ceilhit, + long *florz, long *florhit, + long walldist, unsigned long cliptype) + + Use this in conjunction with clipmove. This function will keep the + player from falling off cliffs when you're too close to the edge. This + function finds the highest and lowest z coordinates that your clipping + BOX can get to. It must search for all sectors (and sprites) that go + into your clipping box. This method is better than using + sector[cursectnum].ceilingz and sector[cursectnum].floorz because this + searches the whole clipping box for objects, not just 1 point. + Pass x, y, z, sector normally. Walldist can be 128. Cliptype is + defined the same way as it is for clipmove. This function returns the + z extents in ceilz and florz. It will return the object hit in ceilhit + and florhit. Ceilhit and florhit will also be either: + 16384+sector (sector first touched) or + 49152+spritenum (sprite first touched) + +hitscan(long xstart, long ystart, long zstart, short startsectnum, + long vectorx, long vectory, long vectorz, + short *hitsect, short *hitwall, short *hitsprite, + long *hitx, long *hity, long *hitz); + + Pass the starting 3D position: + (xstart, ystart, zstart, startsectnum) + Then pass the 3D angle to shoot (defined as a 3D vector): + (vectorx, vectory, vectorz) + Then set up the return values for the object hit: + (hitsect, hitwall, hitsprite) + and the exact 3D point where the ray hits: + (hitx, hity, hitz) + + How to determine what was hit: + * Hitsect is always equal to the sector that was hit (always >= 0). + + * If the ray hits a sprite then: + hitsect = thesectornumber + hitsprite = thespritenumber + hitwall = -1 + + * If the ray hits a wall then: + hitsect = thesectornumber + hitsprite = -1 + hitwall = thewallnumber + + * If the ray hits the ceiling of a sector then: + hitsect = thesectornumber + hitsprite = -1 + hitwall = -1 + vectorz < 0 + (If vectorz < 0 then you're shooting upward which means + that you couldn't have hit a floor) + + * If the ray hits the floor of a sector then: + hitsect = thesectornumber + hitsprite = -1 + hitwall = -1 + vectorz > 0 + (If vectorz > 0 then you're shooting downard which means + that you couldn't have hit a ceiling) + +neartag(long x, long y, long z, short sectnum, short ang, //Starting position & angle + short *neartagsector, //Returns near sector if sector[].tag != 0 + short *neartagwall, //Returns near wall if wall[].tag != 0 + short *neartagsprite, //Returns near sprite if sprite[].tag != 0 + long *neartaghitdist, //Returns actual distance to object (scale: 1024=largest grid size) + long neartagrange, //Choose maximum distance to scan (scale: 1024=largest grid size) + char tagsearch) //1-lotag only, 2-hitag only, 3-lotag&hitag + Neartag works sort of like hitscan, but is optimized to + scan only close objects and scan only objects with + tags != 0. Neartag is perfect for the first line of your space bar code. + It will tell you what door you want to open or what switch you want to + flip. + +cansee(long x1, long y1, long z1, short sectnum1, + long x2, long y2, long z2, short sectnum2); returns 0 or 1 + This function determines whether or not two 3D points can "see" each + other or not. All you do is pass it the coordinates of a 3D line defined + by two 3D points (with their respective sectors) The function will return + a 1 if the points can see each other or a 0 if there is something blocking + the two points from seeing each other. This is how I determine whether a + monster can see you or not. Try playing DOOM1.DAT to fully enjoy this + great function! + +updatesector(long x, long y, §num); + This function updates the sector number according to the x and y values + passed to it. Be careful when you use this function with sprites because + remember that the sprite's sector number should not be modified directly. + If you want to update a sprite's sector, I recomment using the setsprite + function described below. + +inside(long x, long y, short sectnum); + Tests to see whether the overhead point (x, y) is inside sector (sectnum) + Returns either 0 or 1, where 1 means it is inside, and 0 means it is not. + +clipinsidebox(long x, long y, short wallnum, long walldist) + Returns TRUE only if the given line (wallnum) intersects the square with + center (x,y) and radius, walldist. + +dragpoint(short wallnum, long newx, long newy); + This function will drag a point in the exact same way a point is dragged + in 2D EDIT MODE using the left mouse button. Simply pass it which wall + to drag and then pass the new x and y coordinates for that point. + Please use this function because if you don't and try to drag points + yourself, I can guarantee that it won't work as well as mine and you + will get confused. Note: Every wall of course has 2 points. When you + pass a wall number to this function, you are actually passing 1 point, + the left side of the wall (given that you are in the sector of that wall) + Got it? + +----------------------------------------------------------------------------- +| MATH HELPER FUNCTIONS: | +----------------------------------------------------------------------------- + +krand() + Random number function - returns numbers from 0-65535 + +ksqrt(long num) + Returns the integer square root of the number. + +getangle(long xvect, long yvect) + Gets the angle of a vector (xvect,yvect) + These are 2048 possible angles starting from the right, going clockwise + +rotatepoint(long xpivot, long ypivot, long x, long y, + short daang, long *x2, long *y2); + This function is a very convenient and fast math helper function. + Rotate points easily with this function without having to juggle your + cosines and sines. Simply pass it: + + Input: 1. Pivot point (xpivot,ypivot) + 2. Original point (x,y) + 3. Angle to rotate (0 = nothing, 512 = 90ø CW, etc.) + Output: 4. Rotated point (*x2,*y2) + +lastwall(short point); + Use this function as a reverse function of wall[].point2. In order + to save memory, my walls are only on a single linked list. + +nextsectorneighborz(short sectnum, long thez, short topbottom, short direction) + This function is used to tell where elevators should stop. It searches + nearby sectors for the next closest ceilingz or floorz it should stop at. + sectnum - elevator sector + thez - current z to start search from + topbottom - search ceilingz's/floorz's only + direction - search upwards/downwards + +getceilzofslope(short sectnum, long x, long y) +getflorzofslope(short sectnum, long x, long y) +getzsofslope(short sectnum, long x, long y, long *ceilz, long *florz) + These 3 functions get the height of a ceiling and/or floor in a sector + at any (x,y) location. Use getzsofslope only if you need both the ceiling + and floor. + +alignceilslope(short sectnum, long x, long y, long z) +alignflorslope(short sectnum, long x, long y, long z) + Given a sector and assuming it's first wall is the pivot wall of the slope, + this function makes the slope pass through the x,y,z point. One use of + this function is used for sin-wave floors. + +----------------------------------------------------------------------------- +| SPRITE FUNCTIONS: | +----------------------------------------------------------------------------- + +insertsprite(short sectnum, short statnum); //returns (short)spritenum; + Whenever you insert a sprite, you must pass it the sector + number, and a status number (statnum). The status number can be any + number from 0 to MAXSTATUS-1. Insertsprite works like a memory + allocation function and returns the sprite number. + +deletesprite(short spritenum); + Deletes the sprite. + +changespritesect(short spritenum, short newsectnum); + Changes the sector of sprite (spritenum) to the + newsector (newsectnum). This function may become + internal to the engine in the movesprite function. But + this function is necessary since all the sectors have + their own doubly-linked lists of sprites. + +changespritestat(short spritenum, short newstatnum); + Changes the status of sprite (spritenum) to status + (newstatus). Newstatus can be any number from 0 to MAXSTATUS-1. + You can use this function to put a monster on a list of active sprites + when it first sees you. + +setsprite(short spritenum, long newx, long newy, long newz); + This function simply sets the sprite's position to a specified + coordinate (newx, newy, newz) without any checking to see + whether the position is valid or not. You could directly + modify the sprite[].x, sprite[].y, and sprite[].z values, but + if you use my function, the sprite is guaranteed to be in the + right sector. + +----------------------------------------------------------------------------- +| CACHE FUNCTIONS: | +----------------------------------------------------------------------------- +initcache(long dacachestart, long dacachesize) + First allocate a really large buffer (as large as possible), then pass off + the memory bufer the initcache + dacachestart: 32-bit offset in memory of start of cache + dacachesize: number of bytes that were allocated for the cache to use + +allocache (long *bufptr, long bufsiz, char *lockptr) + *bufptr = pointer to 4-byte pointer to buffer. This + allows allocache to remove previously allocated things + from the cache safely by setting the 4-byte pointer to 0. + bufsiz = number of bytes to allocate + *lockptr = pointer to locking char which tells whether + the region can be removed or not. If *lockptr = 0 then + the region is not locked else its locked. + +----------------------------------------------------------------------------- +| GROUP FILE FUNCTIONS: | +----------------------------------------------------------------------------- +initgroupfile(char *filename) + Tells the engine what the group file name is. + You should call this before any of the following group file functions. +uninitgroupfile() + Frees buffers. You should call this once at the end of the program + before quitting to dos. + +kopen4load(char *filename, char searchfirst) + Open a file. First tries to open a stand alone file. Then searches for + it in the group file. If searchfirst is nonzero, it will check the group + file only. + +kread(long handle, void *buffer, long leng) +klseek(long handle, long offset, long whence) +kfilelength(long handle) +kclose(long handle) + These 4 functions simply shadow the dos file functions - they + can do file I/O on the group file in addition to stand-along files. + +----------------------------------------------------------------------------- +| COMMUNICATIONS FUNCTIONS: | +----------------------------------------------------------------------------- + Much of the following code is to keep compatibity with older network code: + +initmultiplayers(char damultioption, char dacomrateoption, char dapriority) + The parameters are ignored - just pass 3 0's +uninitmultiplayers() Does nothing + +sendpacket(long other, char *bufptr, long messleng) + other - who to send the packet to + bufptr - pointer to message to send + messleng - length of message +short getpacket (short *other, char *bufptr) + returns the number of bytes of the packet received, 0 if no packet + other - who the packet was received from + bufptr - pointer to message that was received + +sendlogon() Does nothing +sendlogoff() + Sends a packet to everyone else where the + first byte is 255, and the + second byte is myconnectindex + +getoutputcirclesize() Does nothing - just a stub function, returns 0 +setsocket(short newsocket) Does nothing + +flushpackets() + Clears all packet buffers +genericmultifunction(long other, char *bufptr, long messleng, long command) + Passes a buffer to the commit driver. This command provides a gateway + for game programmer to access COMMIT directly. + +----------------------------------------------------------------------------- +| PALETTE FUNCTIONS: | +----------------------------------------------------------------------------- +VBE_setPalette(long start, long num, char *palettebuffer) +VBE_getPalette(long start, long num, char *palettebuffer) + Set (num) palette palette entries starting at (start) + palette entries are in a 4-byte format in this order: + 0: Blue (0-63) + 1: Green (0-63) + 2: Red (0-63) + 3: Reserved + +makepalookup(long palnum, char *remapbuf, + signed char r, signed char g, signed char b, + char dastat) + This function allows different shirt colors for sprites. First prepare + remapbuf, which is a 256 byte buffer of chars which the colors to remap. + Palnum can be anywhere from 1-15. Since 0 is where the normal palette is + stored, it is a bad idea to call this function with palnum=0. + In BUILD.H notice I added a new variable, spritepal[MAXSPRITES]. + Usually the value of this is 0 for the default palette. But if you + change it to the palnum in the code between drawrooms() and drawmasks + then the sprite will be drawn with that remapped palette. The last 3 + parameters are the color that the palette fades to as you get further + away. This color is normally black (0,0,0). White would be (63,63,63). + if ((dastat&1) == 0) then makepalookup will allocate & deallocate + the memory block for use but will not waste the time creating a palookup + table (assuming you will create one yourself) + +setbrightness(char gammalevel, char *dapal) + Use this function to adjust for gamma correction. + Gammalevel - ranges from 0-15, 0 is darkest, 15 brightest. Default: 0 + dapal: standard VGA palette (768 bytes) + +------------------------------------------------------------------------------ +| This document brought to you by: | +| | +| @@@@@@ @@@@@@ @@@@@@@@@@@@@@@@@@ @@@@@@@@ @@@@@@ | +| @@@@@@ @@@@@@ @@@@@@@@@@@@@@@@@@ @@@@@@@@@ @@@@@@ | +| @@@@@@ @@@@@@@ @@@@@@@@@@@@@@@@@@ @@@@@@@@@@ @@@@@@ | +| @@@@@@ @@@@@@@ @@@@@@ @@@@@@@@@@@ @@@@@@ | +| @@@@@@ @@@@@@@ @@@@@@ @@@@@@@@@@@@ @@@@@@ | +| @@@@@@ @@@@@@@ @@@@@@ @@@@@@@@@@@@@ @@@@@@ | +| @@@@@@@@@@@@ @@@@@@@@@@@@@@@ @@@@@@ @@@@@@@ @@@@@@ | +| @@@@@@@ @@@@@@@@@@@ @@@@@@@@@@@@@@@ @@@@@@ @@@@@@@ @@@@@@ | +| @@@@@@@@@@@@ @@@@@@@@@@@@@@@ @@@@@@ @@@@@@@ @@@@@@ | +| @@@@@@ @@@@@@@ @@@@@@ @@@@@@ @@@@@@@@@@@@@ | +| @@@@@@ @@@@@@@ @@@@@@ @@@@@@ @@@@@@@@@@@@ | +| @@@@@@ @@@@@@@ @@@@@@ @@@@@@ @@@@@@@@@@@ | +| @@@@@@ @@@@@@@ @@@@@@@@@@@@@@@@@@ @@@@@@ @@@@@@@@@@ | +| @@@@@@ @@@@@@ @@@@@@@@@@@@@@@@@@ @@@@@@ @@@@@@@@@ | +| @@@@@@ @@@@@@ @@@@@@@@@@@@@@@@@@ @@@@@@ @@@@@@@@ | +| | +| Ken Silverman of East Greenwich, RI USA | +------------------------------------------------------------------------------ diff --git a/buildengine/buildperl.c b/buildengine/buildperl.c new file mode 100755 index 0000000..eeaebe2 --- /dev/null +++ b/buildengine/buildperl.c @@ -0,0 +1,103 @@ +/* + * Experimental Perl code in Build. + * + * Written by Ryan C. Gordon. (icculus@clutteredmind.org) + * + * Please do NOT harrass Ken Silverman about any code modifications + * (including this file) to BUILD. + */ + +/* + * "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman + * Ken Silverman's official web site: "http://www.advsys.net/ken" + * See the included license file "BUILDLIC.TXT" for license info. + * This file IS NOT A PART OF Ken Silverman's original release + */ + +#include +#include + +#include "buildperl.h" + +static PerlInterpreter *perl = NULL; +static char *embedding[] = { "", "game.pl" }; +//static char *args[] = { NULL }; +static SV *framefunc = NULL; +//static SV *ref_framefunc = NULL; +static HV *stash = NULL; + +int buildperl_init(void) +{ + int retval = -1; + + printf("initializing perl...\n"); + + perl = perl_alloc(); + if (perl == NULL) + printf("no memory!"); + else + { + perl_construct(perl); + + if (perl_parse(perl, NULL, 2, embedding, NULL) == 0) + { + printf("perl initialization was successful.\n" + "running perl mainline...\n"); + perl_run(perl); + printf("perl mainline complete.\n"); + retval = 0; + +// framefunc = get_sv("BUILD_frame", FALSE); + + stash = gv_stashpv("main", FALSE); + if (stash == NULL) + printf("main stash is NULL!\n"); + else + { + framefunc = *(hv_fetch(stash, "BUILD_frame", 11, FALSE)); + if (framefunc == NULL) + printf("framefunc == NULL!\n"); + } + } // if + else + { + printf("perl_parse() failed!\n"); + perl_destruct(perl); + perl_free(perl); + perl = NULL; + } // else + } // else + + return(retval); +} // initialize_perl + + +void buildperl_frame(void) +{ + dSP; + + PUSHMARK(SP); + + if (perl != NULL) + { +// call_argv("BUILD_frame", G_DISCARD | G_NOARGS, args); + call_sv(framefunc, G_DISCARD | G_NOARGS); + } // if +} // buildperl_frame + + +void buildperl_deinit(void) +{ + printf("buildperl_deinit() called.\n"); + + if (perl != NULL) + { + perl_destruct(perl); + perl_free(perl); + perl = NULL; + printf("perl interpreter cleanup successful.\n"); + } // if +} // buildperl_deinit + +// end of buildperl.c ... + diff --git a/buildengine/buildperl.h b/buildengine/buildperl.h new file mode 100755 index 0000000..94deb3a --- /dev/null +++ b/buildengine/buildperl.h @@ -0,0 +1,36 @@ +/* + * Experimental Perl code in Build, include file. + * + * Written by Ryan C. Gordon. (icculus@clutteredmind.org) + * + * Please do NOT harrass Ken Silverman about any code modifications + * (including this file) to BUILD. + */ + +// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman +// Ken Silverman's official web site: "http://www.advsys.net/ken" +// See the included license file "BUILDLIC.TXT" for license info. +// This file IS NOT A PART OF Ken Silverman's original release + +#ifndef _INCLUDE_BUILDPERL_H_ +#define _INCLUDE_BUILDPERL_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#if (!defined USE_PERL) +#error Please define USE_PERL before including this file. +#endif + +int buildperl_init(void); +void buildperl_frame(void); +void buildperl_deinit(void); + +#ifdef __cplusplus +} +#endif + +#endif // include-once-blocker. + +// end of buildperl.h ... diff --git a/buildengine/cache1d.c b/buildengine/cache1d.c new file mode 100755 index 0000000..bf8c96a --- /dev/null +++ b/buildengine/cache1d.c @@ -0,0 +1,985 @@ +/* + * "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman + * Ken Silverman's official web site: "http://www.advsys.net/ken" + * See the included license file "BUILDLIC.TXT" for license info. + * This file has been modified from Ken Silverman's original release + */ + +#include +#include +#include +#include + +#include +#include + +#include "platform.h" +#include "display.h" + +#include "pragmas.h" +#include "cache1d.h" + +#if (defined USE_PHYSICSFS) +#include "physfs.h" +#endif + +/* + * This module keeps track of a standard linear cacheing system. + * To use this module, here's all you need to do: + * + * Step 1: Allocate a nice BIG buffer, like from 1MB-4MB and + * Call initcache(long cachestart, long cachesize) where + * + * cachestart = (long)(pointer to start of BIG buffer) + * cachesize = length of BIG buffer + * + * Step 2: Call allocache(long *bufptr, long bufsiz, char *lockptr) + * whenever you need to allocate a buffer, where: + * + * *bufptr = pointer to 4-byte pointer to buffer + * Confused? Using this method, cache2d can remove + * previously allocated things from the cache safely by + * setting the 4-byte pointer to 0. + * bufsiz = number of bytes to allocate + * *lockptr = pointer to locking char which tells whether + * the region can be removed or not. If *lockptr = 0 then + * the region is not locked else its locked. + * + * Step 3: If you need to remove everything from the cache, or every + * unlocked item from the cache, you can call uninitcache(); + * Call uninitcache(0) to remove all unlocked items, or + * Call uninitcache(1) to remove everything. + * After calling uninitcache, it is still ok to call allocache + * without first calling initcache. + */ + +#define MAXCACHEOBJECTS 9216 + +static long cachesize = 0; +long cachecount = 0; +unsigned char zerochar = 0; +long cachestart = 0, cacnum = 0, agecount = 0; +typedef struct { long *hand, leng; unsigned char *lock; } cactype; +cactype cac[MAXCACHEOBJECTS]; +static long lockrecip[200]; + +void initcache(long dacachestart, long dacachesize) +{ + long i; + + for(i=1;i<200;i++) lockrecip[i] = (1<<28)/(200-i); + + cachestart = dacachestart; + cachesize = dacachesize; + + cac[0].leng = cachesize; + cac[0].lock = &zerochar; + cacnum = 1; +} + +void allocache (long *newhandle, long newbytes, unsigned char *newlockptr) +{ + long i, z, zz, bestz=0, daval, bestval, besto=0, o1, o2, sucklen, suckz; + + newbytes = ((newbytes+15)&0xfffffff0); + + if ((unsigned)newbytes > (unsigned)cachesize) + { + printf("Cachesize: %ld\n",cachesize); + printf("*Newhandle: 0x%x, Newbytes: %ld, *Newlock: %d\n",(unsigned int)newhandle,newbytes,*newlockptr); + reportandexit("BUFFER TOO BIG TO FIT IN CACHE!\n"); + } + + if (*newlockptr == 0) + { + reportandexit("ALLOCACHE CALLED WITH LOCK OF 0!\n"); + } + + /* Find best place */ + bestval = 0x7fffffff; o1 = cachesize; + for(z=cacnum-1;z>=0;z--) + { + o1 -= cac[z].leng; + o2 = o1+newbytes; if (o2 > cachesize) continue; + + daval = 0; + for(i=o1,zz=z;i= 200) { daval = 0x7fffffff; break; } + daval += (long) mulscale32(cac[zz].leng+65536,lockrecip[*cac[zz].lock]); + if (daval >= bestval) break; + } + if (daval < bestval) + { + bestval = daval; besto = o1; bestz = z; + if (bestval == 0) break; + } + } + + /*printf("%ld %ld %ld\n",besto,newbytes,*newlockptr);*/ + + if (bestval == 0x7fffffff) + reportandexit("CACHE SPACE ALL LOCKED UP!\n"); + + /* Suck things out */ + for(sucklen=-newbytes,suckz=bestz;sucklen<0;sucklen+=cac[suckz++].leng) + if (*cac[suckz].lock) *cac[suckz].hand = 0; + + /* Remove all blocks except 1 */ + suckz -= (bestz+1); cacnum -= suckz; + + if (suckz != 0) + copybufbyte(&cac[bestz+suckz],&cac[bestz],(cacnum-bestz)*sizeof(cactype)); + + cac[bestz].hand = newhandle; *newhandle = cachestart+besto; + cac[bestz].leng = newbytes; + cac[bestz].lock = newlockptr; + cachecount++; + + /* Add new empty block if necessary */ + if (sucklen <= 0) return; + + bestz++; + if (bestz == cacnum) + { + cacnum++; if (cacnum > MAXCACHEOBJECTS) reportandexit("Too many objects in cache! (cacnum > MAXCACHEOBJECTS)\n"); + cac[bestz].leng = sucklen; + cac[bestz].lock = &zerochar; + return; + } + + if (*cac[bestz].lock == 0) { cac[bestz].leng += sucklen; return; } + + cacnum++; if (cacnum > MAXCACHEOBJECTS) reportandexit("Too many objects in cache! (cacnum > MAXCACHEOBJECTS)\n"); + for(z=cacnum-1;z>bestz;z--) cac[z] = cac[z-1]; + cac[bestz].leng = sucklen; + cac[bestz].lock = &zerochar; +} + +void suckcache (long *suckptr) +{ + long i; + + /* Can't exit early, because invalid pointer might be same even though lock = 0 */ + for(i=0;i 0) && (*cac[i-1].lock == 0)) + { + cac[i-1].leng += cac[i].leng; + cacnum--; copybuf(&cac[i+1],&cac[i],(cacnum-i)*sizeof(cactype)); + } + else if ((i < cacnum-1) && (*cac[i+1].lock == 0)) + { + cac[i+1].leng += cac[i].leng; + cacnum--; copybuf(&cac[i+1],&cac[i],(cacnum-i)*sizeof(cactype)); + } + } +} + +void agecache(void) +{ + long cnt; + char ch; + + if (agecount >= cacnum) agecount = cacnum-1; + assert(agecount >= 0); + + for(cnt=(cacnum>>4);cnt>=0;cnt--) + { + ch = (*cac[agecount].lock); + if (((ch-2)&255) < 198) + (*cac[agecount].lock) = (unsigned char) (ch-1); + + agecount--; if (agecount < 0) agecount = cacnum-1; + } +} + +void reportandexit(char *errormessage) +{ + long i, j; + + setvmode(0x3); + j = 0; + for(i=0;i= MAXGROUPFILES) return(-1); + + groupfil[numgroupfiles] = open(filename,O_BINARY|O_RDONLY,S_IREAD); + if (groupfil[numgroupfiles] < 0) { + fprintf(stderr, "Unable to open %s\n", filename); + exit(0); + } // if + else { + groupfilpos[numgroupfiles] = 0; + read(groupfil[numgroupfiles],buf,16); + if ((buf[0] != 'K') || (buf[1] != 'e') || (buf[2] != 'n') || + (buf[3] != 'S') || (buf[4] != 'i') || (buf[5] != 'l') || + (buf[6] != 'v') || (buf[7] != 'e') || (buf[8] != 'r') || + (buf[9] != 'm') || (buf[10] != 'a') || (buf[11] != 'n')) + { + close(groupfil[numgroupfiles]); + groupfil[numgroupfiles] = -1; + return(-1); + } + gnumfiles[numgroupfiles] = BUILDSWAP_INTEL32(*((long *)&buf[12])); + + if ((gfilelist[numgroupfiles] = (char *)kmalloc(gnumfiles[numgroupfiles]<<4)) == 0) + { printf("Not enough memory for file grouping system\n"); exit(0); } + if ((gfileoffs[numgroupfiles] = (long *)kmalloc((gnumfiles[numgroupfiles]+1)<<2)) == 0) + { printf("Not enough memory for file grouping system\n"); exit(0); } + + read(groupfil[numgroupfiles],gfilelist[numgroupfiles],gnumfiles[numgroupfiles]<<4); + + j = 0; + for(i=0;i=0;i--) + if (groupfil[i] != -1) + { + kfree(gfilelist[i]); + kfree(gfileoffs[i]); + close(groupfil[i]); + groupfil[i] = -1; + } +#endif +} + +#if (defined USE_PHYSICSFS) +static int locateOneElement(char *buf) +{ + char *ptr; + char **rc; + char **i; + + if (PHYSFS_exists(buf)) + return(1); /* quick rejection: exists in current case. */ + + ptr = strrchr(buf, '/'); /* find entry at end of path. */ + if (ptr == NULL) + { + rc = PHYSFS_enumerateFiles("/"); + ptr = buf; + } /* if */ + else + { + *ptr = '\0'; + rc = PHYSFS_enumerateFiles(buf); + *ptr = '/'; + ptr++; /* point past dirsep to entry itself. */ + } /* else */ + + for (i = rc; *i != NULL; i++) + { + if (stricmp(*i, ptr) == 0) + { + strcpy(ptr, *i); /* found a match. Overwrite with this case. */ + PHYSFS_freeList(rc); + return(1); + } /* if */ + } /* for */ + + /* no match at all... */ + PHYSFS_freeList(rc); + return(0); +} /* locateOneElement */ + + +int PHYSFSEXT_locateCorrectCase(char *buf) +{ + int rc; + char *ptr; + char *prevptr; + + while (*buf == '/') /* skip any '/' at start of string... */ + buf++; + + ptr = prevptr = buf; + if (*ptr == '\0') + return(0); /* Uh...I guess that's success. */ + + while ((ptr = strchr(ptr + 1, '/')) != NULL) + { + *ptr = '\0'; /* block this path section off */ + rc = locateOneElement(buf); + *ptr = '/'; /* restore path separator */ + if (!rc) + return(-2); /* missing element in path. */ + } /* while */ + + /* check final element... */ + return(locateOneElement(buf) ? 0 : -1); +} /* PHYSFSEXT_locateCorrectCase */ +#endif + + +long kopen4load(const char *filename, char searchfirst) +{ +#if (defined USE_PHYSICSFS) + int i; + PHYSFS_file *rc; + char _filename[64]; + + assert(strlen(filename) < sizeof (_filename)); + strcpy(_filename, filename); + PHYSFSEXT_locateCorrectCase(_filename); + + rc = PHYSFS_openRead(_filename); + if (rc == NULL) + return(-1); + + for (i = 0; i < MAXOPENFILES; i++) + { + if (filehan[i] == NULL) + { + filehan[i] = rc; + return(i); + } + } + + PHYSFS_close(rc); /* oh well. */ + return(-1); +#else + long i, j, k, fil, newhandle; + unsigned char bad; + char *gfileptr; + + newhandle = MAXOPENFILES-1; + while (filehan[newhandle] != -1) + { + newhandle--; + if (newhandle < 0) + { + printf("TOO MANY FILES OPEN IN FILE GROUPING SYSTEM!"); + exit(0); + } + } + + if (searchfirst == 0) + if ((fil = open(filename,O_BINARY|O_RDONLY)) != -1) + { + filegrp[newhandle] = 255; + filehan[newhandle] = fil; + filepos[newhandle] = 0; + return(newhandle); + } + for(k=numgroupfiles-1;k>=0;k--) + { + if (searchfirst != 0) k = 0; + if (groupfil[k] != -1) + { + for(i=gnumfiles[k]-1;i>=0;i--) + { + gfileptr = (char *)&gfilelist[k][i<<4]; + + bad = 0; + for(j=0;j<13;j++) + { + if (!filename[j]) break; + if (toupperlookup[(int) filename[j]] != toupperlookup[(int) gfileptr[j]]) + { bad = 1; break; } + } + if (bad) continue; + + filegrp[newhandle] = (unsigned char) k; + filehan[newhandle] = i; + filepos[newhandle] = 0; + return(newhandle); + } + } + } + return(-1); +#endif +} + +long kread(long handle, void *buffer, long leng) +{ +#if (defined USE_PHYSICSFS) + return(PHYSFS_read(filehan[handle], buffer, 1, leng)); +return(leng); +#else + long i, filenum, groupnum; + + filenum = filehan[handle]; + groupnum = filegrp[handle]; + if (groupnum == 255) return(read(filenum,buffer,leng)); + + if (groupfil[groupnum] != -1) + { + i = gfileoffs[groupnum][filenum]+filepos[handle]; + if (i != groupfilpos[groupnum]) + { + lseek(groupfil[groupnum],i+((gnumfiles[groupnum]+1)<<4),SEEK_SET); + groupfilpos[groupnum] = i; + } + leng = min(leng,(gfileoffs[groupnum][filenum+1]-gfileoffs[groupnum][filenum])-filepos[handle]); + leng = read(groupfil[groupnum],buffer,leng); + filepos[handle] += leng; + groupfilpos[groupnum] += leng; + return(leng); + } + + return(0); +#endif +} + +int kread16(long handle, short *buffer) +{ + if (kread(handle, buffer, 2) != 2) + return(0); + + *buffer = BUILDSWAP_INTEL16(*(unsigned short *)buffer); + return(1); +} + +int kread32(long handle, long *buffer) +{ + if (kread(handle, buffer, 4) != 4) + return(0); + + *buffer = BUILDSWAP_INTEL32(*(unsigned long *)buffer); + return(1); +} + +int kread8(long handle, char *buffer) +{ + if (kread(handle, buffer, 1) != 1) + return(0); + + return(1); +} + +long klseek(long handle, long offset, long whence) +{ +#if (defined USE_PHYSICSFS) + if (whence == SEEK_END) /* !!! FIXME: You can try PHYSFS_filelength(). */ + { + printf("UNSUPPORTED SEEK SEMANTIC!\n"); + exit(42); + } /* if */ + + if (whence == SEEK_CUR) + offset += PHYSFS_tell(filehan[handle]); + + if (!PHYSFS_seek(filehan[handle], offset)) + return(-1); + + return(offset); +#else + long i, groupnum; + + groupnum = filegrp[handle]; + + if (groupnum == 255) return(lseek(filehan[handle],offset,whence)); + if (groupfil[groupnum] != -1) + { + switch(whence) + { + case SEEK_SET: filepos[handle] = offset; break; + case SEEK_END: i = filehan[handle]; + filepos[handle] = (gfileoffs[groupnum][i+1]-gfileoffs[groupnum][i])+offset; + break; + case SEEK_CUR: filepos[handle] += offset; break; + } + return(filepos[handle]); + } + return(-1); +#endif +} + +long kfilelength(long handle) +{ +#if (defined USE_PHYSICSFS) + return(PHYSFS_fileLength(filehan[handle])); +#else + long i, groupnum; + + groupnum = filegrp[handle]; + if (groupnum == 255) return(filelength(filehan[handle])); + i = filehan[handle]; + return(gfileoffs[groupnum][i+1]-gfileoffs[groupnum][i]); +#endif +} + +void kclose(long handle) +{ +#if (defined USE_PHYSICSFS) + if (filehan[handle] != NULL) + { + PHYSFS_close(filehan[handle]); + filehan[handle] = NULL; + } /* if */ +#else + if (handle < 0) return; + if (filegrp[handle] == 255) close(filehan[handle]); + filehan[handle] = -1; +#endif +} + + + + + /* Internal LZW variables */ +#define LZWSIZE 16384 /* Watch out for shorts! */ +static char *lzwbuf1, *lzwbuf4, *lzwbuf5; +static unsigned char lzwbuflock[5]; +static short *lzwbuf2, *lzwbuf3; + +void kdfread(void *buffer, size_t dasizeof, size_t count, long fil) +{ + size_t i, j; + long k, kgoal; + short leng; + char *ptr; + + lzwbuflock[0] = lzwbuflock[1] = lzwbuflock[2] = lzwbuflock[3] = lzwbuflock[4] = 200; + if (lzwbuf1 == NULL) allocache((long *)&lzwbuf1,LZWSIZE+(LZWSIZE>>4),&lzwbuflock[0]); + if (lzwbuf2 == NULL) allocache((long *)&lzwbuf2,(LZWSIZE+(LZWSIZE>>4))*2,&lzwbuflock[1]); + if (lzwbuf3 == NULL) allocache((long *)&lzwbuf3,(LZWSIZE+(LZWSIZE>>4))*2,&lzwbuflock[2]); + if (lzwbuf4 == NULL) allocache((long *)&lzwbuf4,LZWSIZE,&lzwbuflock[3]); + if (lzwbuf5 == NULL) allocache((long *)&lzwbuf5,LZWSIZE+(LZWSIZE>>4),&lzwbuflock[4]); + + if (dasizeof > LZWSIZE) { count *= dasizeof; dasizeof = 1; } + ptr = (char *)buffer; + + kread16(fil,&leng); kread(fil,lzwbuf5,(long)leng); + k = 0; + kgoal = uncompress(lzwbuf5,(long)leng,lzwbuf4); + + copybufbyte(lzwbuf4,ptr,(long)dasizeof); + k += (long)dasizeof; + + for(i=1;i= kgoal) + { + kread16(fil,&leng); kread(fil,lzwbuf5,(long)leng); + k = 0; kgoal = uncompress(lzwbuf5,(long)leng,lzwbuf4); + } + for(j=0;j>4),&lzwbuflock[0]); + if (lzwbuf2 == NULL) allocache((long *)&lzwbuf2,(LZWSIZE+(LZWSIZE>>4))*2,&lzwbuflock[1]); + if (lzwbuf3 == NULL) allocache((long *)&lzwbuf3,(LZWSIZE+(LZWSIZE>>4))*2,&lzwbuflock[2]); + if (lzwbuf4 == NULL) allocache((long *)&lzwbuf4,LZWSIZE,&lzwbuflock[3]); + if (lzwbuf5 == NULL) allocache((long *)&lzwbuf5,LZWSIZE+(LZWSIZE>>4),&lzwbuflock[4]); + + if (dasizeof > LZWSIZE) { count *= dasizeof; dasizeof = 1; } + ptr = (char *)buffer; + + fread(&leng,2,1,fil); + leng = BUILDSWAP_INTEL16(leng); + fread(lzwbuf5,(long)leng,1,fil); + k = 0; kgoal = uncompress(lzwbuf5,(long)leng,lzwbuf4); + + copybufbyte(lzwbuf4,ptr,(long)dasizeof); + k += (long)dasizeof; + + for(i=1;i= kgoal) + { + fread(&leng,2,1,fil); + leng = BUILDSWAP_INTEL16(leng); + fread(lzwbuf5,(long)leng,1,fil); + k = 0; kgoal = uncompress(lzwbuf5,(long)leng,lzwbuf4); + } + for(j=0;j>4),&lzwbuflock[0]); + if (lzwbuf2 == NULL) allocache((long *)&lzwbuf2,(LZWSIZE+(LZWSIZE>>4))*2,&lzwbuflock[1]); + if (lzwbuf3 == NULL) allocache((long *)&lzwbuf3,(LZWSIZE+(LZWSIZE>>4))*2,&lzwbuflock[2]); + if (lzwbuf4 == NULL) allocache((long *)&lzwbuf4,LZWSIZE,&lzwbuflock[3]); + if (lzwbuf5 == NULL) allocache((long *)&lzwbuf5,LZWSIZE+(LZWSIZE>>4),&lzwbuflock[4]); + + if (dasizeof > LZWSIZE) { count *= dasizeof; dasizeof = 1; } + ptr = (char *)buffer; + + copybufbyte(ptr,lzwbuf4,(long)dasizeof); + k = dasizeof; + + if (k > LZWSIZE-dasizeof) + { + leng = (short)compress(lzwbuf4,k,lzwbuf5); k = 0; + byteswapped = BUILDSWAP_INTEL16(leng); + fwrite(&byteswapped,2,1,fil); fwrite(lzwbuf5,(long)leng,1,fil); + } + + for(i=1;i LZWSIZE-dasizeof) + { + leng = (short)compress(lzwbuf4,k,lzwbuf5); k = 0; + byteswapped = BUILDSWAP_INTEL16(leng); + fwrite(&byteswapped,2,1,fil); fwrite(lzwbuf5,(long)leng,1,fil); + } + ptr += dasizeof; + } + if (k > 0) + { + leng = (short)compress(lzwbuf4,k,lzwbuf5); + byteswapped = BUILDSWAP_INTEL16(leng); + fwrite(&byteswapped,2,1,fil); fwrite(lzwbuf5,(long)leng,1,fil); + } + lzwbuflock[0] = lzwbuflock[1] = lzwbuflock[2] = lzwbuflock[3] = lzwbuflock[4] = 1; +} + +void dfwrite8(char *_buffer, size_t count, FILE *fil) +{ + dfwrite(_buffer, 1, count, fil); +} + +void dfwrite16(short *_buffer, size_t count, FILE *fil) +{ +#if PLATFORM_BIGENDIAN + unsigned short *buffer = (unsigned short *) _buffer; + int i; + for (i = 0; i < count; i++) + buffer[i] = BUILDSWAP_INTEL16(buffer[i]); +#endif + + dfwrite(_buffer, 2, count, fil); + +#if PLATFORM_BIGENDIAN + for (i = 0; i < count; i++) + buffer[i] = BUILDSWAP_INTEL16(buffer[i]); +#endif +} +void dfwrite32(long *_buffer, size_t count, FILE *fil) +{ +#if PLATFORM_BIGENDIAN + unsigned long *buffer = (unsigned long *) _buffer; + int i; + for (i = 0; i < count; i++) + buffer[i] = BUILDSWAP_INTEL32(buffer[i]); +#endif + + dfwrite(_buffer, 4, count, fil); + +#if PLATFORM_BIGENDIAN + for (i = 0; i < count; i++) + buffer[i] = BUILDSWAP_INTEL32(buffer[i]); +#endif +} + + +long compress(char *lzwinbuf, long uncompleng, char *lzwoutbuf) +{ + long i, addr, newaddr, addrcnt, zx, *longptr; + long bytecnt1, bitcnt, numbits, oneupnumbits; + short *shortptr; + + for(i=255;i>=0;i--) { lzwbuf1[i] = (char) i; lzwbuf3[i] = (short) ((i+1)&255); } + clearbuf((void *) FP_OFF(lzwbuf2),256>>1,0xffffffff); + clearbuf((void *) FP_OFF(lzwoutbuf),((uncompleng+15)+3)>>2,0L); + + addrcnt = 256; bytecnt1 = 0; bitcnt = (4<<3); + numbits = 8; oneupnumbits = (1<<8); + do + { + addr = lzwinbuf[bytecnt1]; + do + { + bytecnt1++; + if (bytecnt1 == uncompleng) break; + if (lzwbuf2[addr] < 0) {lzwbuf2[addr] = (short) addrcnt; break;} + newaddr = lzwbuf2[addr]; + while (lzwbuf1[newaddr] != lzwinbuf[bytecnt1]) + { + zx = lzwbuf3[newaddr]; + if (zx < 0) {lzwbuf3[newaddr] = (short) addrcnt; break;} + newaddr = zx; + } + if (lzwbuf3[newaddr] == addrcnt) break; + addr = newaddr; + } while (addr >= 0); + lzwbuf1[addrcnt] = lzwinbuf[bytecnt1]; + lzwbuf2[addrcnt] = -1; + lzwbuf3[addrcnt] = -1; + + longptr = (long *)&lzwoutbuf[bitcnt>>3]; + *longptr = BUILDSWAP_INTEL32(*longptr); //convert to native format. + *longptr |= (addr<<(bitcnt&7)); // add new data. + *longptr = BUILDSWAP_INTEL32(*longptr); //convert back to littleendian + bitcnt += numbits; + if ((addr&((oneupnumbits>>1)-1)) > ((addrcnt-1)&((oneupnumbits>>1)-1))) + bitcnt--; + + addrcnt++; + if (addrcnt > oneupnumbits) { numbits++; oneupnumbits <<= 1; } + } while ((bytecnt1 < uncompleng) && (bitcnt < (uncompleng<<3))); + + longptr = (long *)&lzwoutbuf[bitcnt>>3]; + *longptr = BUILDSWAP_INTEL32(*longptr); //convert to native format. + *longptr |= (addr<<(bitcnt&7)); + *longptr = BUILDSWAP_INTEL32(*longptr); //convert back. + bitcnt += numbits; + if ((addr&((oneupnumbits>>1)-1)) > ((addrcnt-1)&((oneupnumbits>>1)-1))) + bitcnt--; + + shortptr = (short *)lzwoutbuf; + *shortptr = (short)uncompleng; + *shortptr = BUILDSWAP_INTEL16(*shortptr); + if (((bitcnt+7)>>3) < uncompleng) + { + shortptr[1] = (short)addrcnt; + shortptr[1] = BUILDSWAP_INTEL16(shortptr[1]); + return((bitcnt+7)>>3); + } + shortptr[1] = (short)0; + for(i=0;i>2); + return((long) BUILDSWAP_INTEL16(shortptr[0])); /* uncompleng */ + } + for(i=255;i>=0;i--) { lzwbuf2[i] = (short) i; lzwbuf3[i] = (short) i; } + currstr = 256; bitcnt = (4<<3); outbytecnt = 0; + numbits = 8; oneupnumbits = (1<<8); + do + { + longptr = (long *)&lzwinbuf[bitcnt>>3]; + dat = ((BUILDSWAP_INTEL32(longptr[0])>>(bitcnt&7)) & (oneupnumbits-1)); + bitcnt += numbits; + if ((dat&((oneupnumbits>>1)-1)) > ((currstr-1)&((oneupnumbits>>1)-1))) + { dat &= ((oneupnumbits>>1)-1); bitcnt--; } + + lzwbuf3[currstr] = (short) dat; + + for(leng=0;dat>=256;leng++,dat=lzwbuf3[dat]) + lzwbuf1[leng] = (char) lzwbuf2[dat]; + + lzwoutbuf[outbytecnt++] = (char) dat; + for(i=leng-1;i>=0;i--) lzwoutbuf[outbytecnt++] = lzwbuf1[i]; + + lzwbuf2[currstr-1] = (short) dat; lzwbuf2[currstr] = (short) dat; + currstr++; + if (currstr > oneupnumbits) { numbits++; oneupnumbits <<= 1; } + } while (currstr < strtot); + return((long) BUILDSWAP_INTEL16(shortptr[0])); /* uncompleng */ +} diff --git a/buildengine/cache1d.h b/buildengine/cache1d.h new file mode 100755 index 0000000..daf1ad7 --- /dev/null +++ b/buildengine/cache1d.h @@ -0,0 +1,55 @@ +/* + * Cache1d declarations. + * + * Written by Ryan C. Gordon. (icculus@clutteredmind.org) + * + * Please do NOT harrass Ken Silverman about any code modifications + * (including this file) to BUILD. + */ + +/* + * "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman + * Ken Silverman's official web site: "http://www.advsys.net/ken" + * See the included license file "BUILDLIC.TXT" for license info. + * This file has been modified from Ken Silverman's original release + */ + +#ifndef _INCLUDE_CACHE1D_H_ +#define _INCLUDE_CACHE1D_H_ + +void initcache(long dacachestart, long dacachesize); +void allocache (long *newhandle, long newbytes, unsigned char *newlockptr); +void suckcache (long *suckptr); +void agecache(void); +void reportandexit(char *errormessage); +long initgroupfile(const char *filename); +void uninitgroupfile(void); +long kopen4load(const char *filename, char searchfirst); +long kread(long handle, void *buffer, long leng); +int kread8(long handle, char *buffer); +int kread16(long handle, short *buffer); +int kread32(long handle, long *buffer); +long klseek(long handle, long offset, long whence); +long kfilelength(long handle); +void kclose(long handle); +void kdfread(void *buffer, size_t dasizeof, size_t count, long fil); +void kdfread8(char *buffer, size_t count, long fil); +void kdfread16(short *buffer, size_t count, long fil); +void kdfread32(long *buffer, size_t count, long fil); +void dfread(void *buffer, size_t dasizeof, size_t count, FILE *fil); +void dfread8(char *buffer, size_t count, FILE *fil); +void dfread16(short *buffer, size_t count, FILE *fil); +void dfread32(long *buffer, size_t count, FILE *fil); +void dfwrite(void *buffer, size_t dasizeof, size_t count, FILE *fil); +void dfwrite8(char *buffer, size_t count, FILE *fil); +void dfwrite16(short *buffer, size_t count, FILE *fil); +void dfwrite32(long *buffer, size_t count, FILE *fil); +long compress(char *lzwinbuf, long uncompleng, char *lzwoutbuf); +long uncompress(char *lzwinbuf, long compleng, char *lzwoutbuf); + +#endif /* !defined _INCLUDE_CACHE1D_H_ */ + +/* end of cache1d.h ... */ + + + diff --git a/buildengine/display.h b/buildengine/display.h new file mode 100755 index 0000000..c5eb858 --- /dev/null +++ b/buildengine/display.h @@ -0,0 +1,170 @@ +/* + * "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman + * Ken Silverman's official web site: "http://www.advsys.net/ken" + * See the included license file "BUILDLIC.TXT" for license info. + * This file IS NOT A PART OF Ken Silverman's original release + */ + +#ifndef _INCLUDE_DISPLAY_H_ +#define _INCLUDE_DISPLAY_H_ + +#include "platform.h" + +#if (defined PLATFORM_SUPPORTS_SDL) +#include "SDL.h" + +/* environment variables names... */ +/* These are only honored by the SDL driver. */ +#define BUILD_NOMOUSEGRAB "BUILD_NOMOUSEGRAB" +#define BUILD_WINDOWED "BUILD_WINDOWED" +#define BUILD_SDLDEBUG "BUILD_SDLDEBUG" +#define BUILD_RENDERER "BUILD_RENDERER" +#define BUILD_GLLIBRARY "BUILD_GLLIBRARY" +#define BUILD_USERSCREENRES "BUILD_USERSCREENRES" +#define BUILD_MAXSCREENRES "BUILD_MAXSCREENRES" +#define BUILD_HALLOFMIRRORS "BUILD_HALLOFMIRRORS" +#define BUILD_GLDUMP "BUILD_GLDUMP" +#define BUILD_SDLJOYSTICK "BUILD_SDLJOYSTICK" + +/* This part sucks. */ +#if (defined __WATCOMC__) +#pragma aux (__cdecl) SDL_Init; +#pragma aux (__cdecl) SDL_PumpEvents; +#pragma aux (__cdecl) SDL_PollEvent; +#pragma aux (__cdecl) SDL_GetMouseState; +#pragma aux (__cdecl) SDL_WM_GrabInput; +#pragma aux (__cdecl) SDL_GetError; +#pragma aux (__cdecl) SDL_SetEventFilter; +#pragma aux (__cdecl) SDL_WM_SetCaption; +#pragma aux (__cdecl) SDL_ClearError; +#pragma aux (__cdecl) SDL_SetVideoMode; +#pragma aux (__cdecl) SDL_ClearError; +#pragma aux (__cdecl) SDL_Quit; +#pragma aux (__cdecl) SDL_QuitSubSystem; +#pragma aux (__cdecl) SDL_GetTicks; +#pragma aux (__cdecl) SDL_GetVideoInfo; +#pragma aux (__cdecl) SDL_ListModes; +#pragma aux (__cdecl) SDL_SetColors; +#pragma aux (__cdecl) SDL_ShowCursor; +#pragma aux (__cdecl) SDL_LockSurface; +#pragma aux (__cdecl) SDL_UnlockSurface; +#pragma aux (__cdecl) SDL_FillRect; +#pragma aux (__cdecl) SDL_Delay; +#pragma aux (__cdecl) SDL_AddTimer; +#pragma aux (__cdecl) SDL_RemoveTimer; +#pragma aux (__cdecl) SDL_Flip; +#pragma aux (__cdecl) SDL_UpdateRect; +#pragma aux (__cdecl) SDL_GetVideoSurface; +#pragma aux (__cdecl) SDL_VideoDriverName; +#pragma aux (__cdecl) SDL_SetPalette; +#pragma aux (__cdecl) SDL_VideoModeOK; +#pragma aux (__cdecl) SDL_GetClipRect; +#pragma aux (__cdecl) SDL_SetClipRect; +#pragma aux (__cdecl) SDL_WM_ToggleFullScreen; +#pragma aux (__cdecl) SDL_Linked_Version; +#endif /* defined __WATCOMC__ */ + +#endif /* defined PLATFORM_SUPPORTS_SDL */ + +/* set these in your _platform_init() implementation. */ +extern int _argc; +extern char **_argv; + +/* !!! gads, look at all the namespace polution... */ +extern long xres, yres, bytesperline, imageSize, maxpages; +extern char *screen, vesachecked; +extern long buffermode, origbuffermode, linearmode; +extern char permanentupdate, vgacompatible; +extern char moustat; +extern long *horizlookup, *horizlookup2, horizycent; +extern long oxdimen, oviewingrange, oxyaspect; +extern long curbrightness; +extern long qsetmode; +extern long frameplace, pageoffset, ydim16; +extern char textfont[1024], smalltextfont[1024]; +extern char pow2char[8]; +extern volatile long stereomode, visualpage, activepage, whiteband, blackband; +extern long searchx, searchy; +extern long wx1, wy1, wx2, wy2, ydimen; +extern long xdimen, xdimenrecip, halfxdimen, xdimenscale, xdimscale; + +/* + * !!! used to be static. If we ever put the original setgamemode() back, this + * !!! can be made static again. --ryan. + * !!! (Actually, most of these extern declarations used to be static...rcg.) + */ +extern unsigned char permanentlock; + + +/* these need to be implemented by YOUR driver. */ +void _platform_init(int argc, char **argv, const char *title, const char *icon); +void _idle(void); +void _handle_events(void); +void *_getVideoBase(void); +void initkeys(void); +void uninitkeys(void); +void _nextpage(void); +void _uninitengine(void); +void _joystick_init(void); +void _joystick_deinit(void); +int _joystick_update(void); +int _joystick_axis(int axis); +int _joystick_hat(int hat); +int _joystick_button(int button); + +/* + * VESA replacement code: The Unix (not-actually-VESA) version of this is + * originally using SDL (Simple Directmedia Layer: http://www.libsdl.org/), + * and is stored in sdl_driver.c, but there's no reason another driver + * couldn't be dropped in, so long as it implements these functions. Please + * reference sdl_driver.c and ves2.h (the original code) for all the nuances + * and global variables that need to get set up correctly. + */ +void getvalidvesamodes(void); +int VBE_getPalette(long start, long num, char *dapal); +int VBE_setPalette(long start, long num, char *palettebuffer); +int setvesa(long x, long y); +void uninitvesa(void); +void setvmode(int mode); +unsigned char readpixel(long offset); +void drawpixel(long offset, Uint8 pixel); +void drawpixels(long offset, Uint16 pixels); +void drawpixelses(long offset, Uint32 pixelses); +void drawpixel16(long offset); +void fillscreen16 (long input1, long input2, long input3); +void limitrate(void); +void setactivepage(long dapagenum); +void clear2dscreen(void); +void _updateScreenRect(long x, long y, long w, long h); + +/* mouse/keystuff stuff. Also implemented in sdl_driver.c ... */ +int setupmouse(void); +void readmousexy(short *x, short *y); +void readmousebstatus(short *bstatus); +void __interrupt __far keyhandler(void); +unsigned char _readlastkeyhit(void); + +/* timer krap. */ +void inittimer(void); +void uninittimer(void); + +/* this is implemented in the game, and your driver calls it. */ +void __interrupt __far timerhandler(void); + +/* resolution inits. sdl_driver.c ... */ +int _setgamemode(char davidoption, long daxdim, long daydim); +void qsetmode640350(void); +void qsetmode640480(void); + +unsigned long getticks(); + +void drawline16(long XStart, long YStart, long XEnd, long YEnd, char Color); +void setcolor16(int i1); + +int using_opengl(void); + +#endif /* _INCLUDE_DISPLAY_H_ */ + +/* end of display.h ... */ + + diff --git a/buildengine/dos_drvr.c b/buildengine/dos_drvr.c new file mode 100755 index 0000000..963b54f --- /dev/null +++ b/buildengine/dos_drvr.c @@ -0,0 +1,951 @@ +// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman +// Ken Silverman's official web site: "http://www.advsys.net/ken" +// See the included license file "BUILDLIC.TXT" for license info. + +// This file has been modified from Ken Silverman's original release +// (Actually, most of it was moved here from original BUILD source.) + +#ifndef PLATFORM_DOS +#error Please do not compile this if PLATFORM_DOS is not defined. +#endif + + +// !!! check these includes against original engine.c !!! +#include +#include +#include +#include +#include +#include "pragmas.h" +#include +#include +#include +#include + +#include "platform.h" +#include "display.h" +#include "build.h" +#include "cache1d.h" +#include "ves2.h" +#include "engine.h" + +static unsigned char tempbuf[MAXWALLS]; +extern long transarea; +extern long totalarea; +extern long beforedrawrooms; +extern long stereowidth, stereopixelwidth, ostereopixelwidth; +extern volatile long stereomode, visualpage, activepage, whiteband, blackband; +extern volatile char oa1, o3c2, ortca, ortcb, overtbits, laststereoint; + +extern char pow2char[8]; +extern long pow2long[32]; +extern char kensmessage[128]; + +static short capturecount = 0; +static char screenalloctype = 255; + +static char pcxheader[128] = +{ + 0xa,0x5,0x1,0x8,0x0,0x0,0x0,0x0,0x3f,0x1,0xc7,0x0, + 0x40,0x1,0xc8,0x0,0x0,0x0,0x0,0x8,0x8,0x8,0x10,0x10, + 0x10,0x18,0x18,0x18,0x20,0x20,0x20,0x28,0x28,0x28,0x30,0x30, + 0x30,0x38,0x38,0x38,0x40,0x40,0x40,0x48,0x48,0x48,0x50,0x50, + 0x50,0x58,0x58,0x58,0x60,0x60,0x60,0x68,0x68,0x68,0x70,0x70, + 0x70,0x78,0x78,0x78,0x0,0x1,0x40,0x1,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +}; + + +static char vgapal16[48] = +{ + 00,00,00,00,00,42,00,42,00,00,42,42,42,00,00,42,00,42,42,21,00,42,42,42, + 21,21,21,21,21,63,21,63,21,21,63,63,63,21,21,63,21,63,63,63,21,63,63,63, +}; + +static void (__interrupt __far *oldtimerhandler)(void); +static void (__interrupt __far *oldkeyhandler)(void); + +extern long setvlinebpl(long); +#pragma aux setvlinebpl parm [eax]; + +void *kkmalloc(size_t size); +#pragma aux kkmalloc =\ + "call kmalloc",\ + parm [eax]\ + + +void kkfree(void *buffer); +#pragma aux kkfree =\ + "call kfree",\ + parm [eax]\ + + +unsigned char _readlastkeyhit(void) +{ + return(kinp(0x60)); +} // _readlastkeyhit + + +void _uninitengine(void) +{ + long i; + + if (vidoption == 1) uninitvesa(); + + if (stereomode) setstereo(0L); + + if (screen != NULL) + { + if (screenalloctype == 0) kkfree((void *)screen); + //if (screenalloctype == 1) suckcache(screen); //Cache already gone + screen = NULL; + } + for(i=0;i= 640*336)) + p -= 640*336; + else + p += pageoffset; + + p >>= 3; + + koutp(0x3ce,0x4); + koutp(0x3cf,0); dat = ((readpixel(p+0xa0000)&mask)>0); + koutp(0x3cf,1); dat += (((readpixel(p+0xa0000)&mask)>0)<<1); + koutp(0x3cf,2); dat += (((readpixel(p+0xa0000)&mask)>0)<<2); + koutp(0x3cf,3); dat += (((readpixel(p+0xa0000)&mask)>0)<<3); + return(dat); +} + +int screencapture(char *filename, char inverseit) +{ + char *ptr; + long fil, i, bufplc, p, col, ncol, leng, numbytes, xres; + + filename[4] = ((capturecount/1000)%10)+48; + filename[5] = ((capturecount/100)%10)+48; + filename[6] = ((capturecount/10)%10)+48; + filename[7] = (capturecount%10)+48; + if ((fil=open(filename,O_BINARY|O_CREAT|O_TRUNC|O_WRONLY,S_IWRITE))==-1) + return(-1); + + if (qsetmode == 200) + { + pcxheader[8] = ((xdim-1)&255); pcxheader[9] = (((xdim-1)>>8)&255); + pcxheader[10] = ((ydim-1)&255); pcxheader[11] = (((ydim-1)>>8)&255); + pcxheader[12] = (xdim&255); pcxheader[13] = ((xdim>>8)&255); + pcxheader[14] = (ydim&255); pcxheader[15] = ((ydim>>8)&255); + pcxheader[66] = (xdim&255); pcxheader[67] = ((xdim>>8)&255); + } + else + { + pcxheader[8] = ((640-1)&255); pcxheader[9] = (((640-1)>>8)&255); + pcxheader[10] = ((qsetmode-1)&255); pcxheader[11] = (((qsetmode-1)>>8)&255); + pcxheader[12] = (640&255); pcxheader[13] = ((640>>8)&255); + pcxheader[14] = (qsetmode&255); pcxheader[15] = ((qsetmode>>8)&255); + pcxheader[66] = (640&255); pcxheader[67] = ((640>>8)&255); + } + + write(fil,&pcxheader[0],128); + + if (qsetmode == 200) + { + ptr = (char *)frameplace; + numbytes = xdim*ydim; + xres = xdim; + } + else + { + numbytes = (mul5(qsetmode)<<7); + xres = 640; + } + + bufplc = 0; p = 0; + while (p < numbytes) + { + koutp(97,kinp(97)|3); + + if (qsetmode == 200) { col = *ptr; p++; ptr++; } + else + { + col = readpixel16(p); + p++; + if ((inverseit == 1) && (((col&7) == 0) || ((col&7) == 7))) col ^= 15; + } + + leng = 1; + + if (qsetmode == 200) ncol = *ptr; + else + { + ncol = readpixel16(p); + if ((inverseit == 1) && (((ncol&7) == 0) || ((ncol&7) == 7))) ncol ^= 15; + } + + while ((ncol == col) && (p < numbytes) && (leng < 63) && ((p%xres) != 0)) + { + leng++; + + if (qsetmode == 200) { p++; ptr++; ncol = *ptr; } + else + { + p++; + ncol = readpixel16(p); + if ((inverseit == 1) && (((ncol&7) == 0) || ((ncol&7) == 7))) ncol ^= 15; + } + } + + koutp(97,kinp(97)&252); + + if ((leng > 1) || (col >= 0xc0)) + { + tempbuf[bufplc++] = (leng|0xc0); + if (bufplc == 4096) { bufplc = 0; if (write(fil,&tempbuf[0],4096) < 4096) { close(fil); return(-1); } } + } + tempbuf[bufplc++] = col; + if (bufplc == 4096) { bufplc = 0; if (write(fil,&tempbuf[0],4096) < 4096) { close(fil); return(-1); } } + } + + tempbuf[bufplc++] = 0xc; + if (bufplc == 4096) { bufplc = 0; if (write(fil,&tempbuf[0],4096) < 4096) { close(fil); return(-1); } } + + if (qsetmode == 200) + { + VBE_getPalette(0,256,&tempbuf[4096]); + for(i=0;i<256;i++) + { + tempbuf[bufplc++] = (tempbuf[(i<<2)+4096+2]<<2); + if (bufplc == 4096) { bufplc = 0; if (write(fil,&tempbuf[0],4096) < 4096) { close(fil); return(-1); } } + tempbuf[bufplc++] = (tempbuf[(i<<2)+4096+1]<<2); + if (bufplc == 4096) { bufplc = 0; if (write(fil,&tempbuf[0],4096) < 4096) { close(fil); return(-1); } } + tempbuf[bufplc++] = (tempbuf[(i<<2)+4096+0]<<2); + if (bufplc == 4096) { bufplc = 0; if (write(fil,&tempbuf[0],4096) < 4096) { close(fil); return(-1); } } + } + } + else + { + for(i=0;i<768;i++) + { + if (i < 48) + tempbuf[bufplc++] = (vgapal16[i]<<2); + else + tempbuf[bufplc++] = 0; + if (bufplc == 4096) { bufplc = 0; if (write(fil,&tempbuf[0],4096) < 4096) { close(fil); return(-1); } } + } + + } + + if (bufplc > 0) + if (write(fil,&tempbuf[0],bufplc) < bufplc) { close(fil); return(-1); } + + close(fil); + capturecount++; + return(0); +} + +void printscreeninterrupt(void) +{ + int5(); +} + + +void drawline16(long x1, long y1, long x2, long y2, char col) +{ + long i, dx, dy, p, pinc, d; + char lmask, rmask; + + dx = x2-x1; dy = y2-y1; + if (dx >= 0) + { + if ((x1 > 639) || (x2 < 0)) return; + if (x1 < 0) { if (dy) y1 += scale(0-x1,dy,dx); x1 = 0; } + if (x2 > 639) { if (dy) y2 += scale(639-x2,dy,dx); x2 = 639; } + } + else + { + if ((x2 > 639) || (x1 < 0)) return; + if (x2 < 0) { if (dy) y2 += scale(0-x2,dy,dx); x2 = 0; } + if (x1 > 639) { if (dy) y1 += scale(639-x1,dy,dx); x1 = 639; } + } + if (dy >= 0) + { + if ((y1 >= ydim16) || (y2 < 0)) return; + if (y1 < 0) { if (dx) x1 += scale(0-y1,dx,dy); y1 = 0; } + if (y2 >= ydim16) { if (dx) x2 += scale(ydim16-1-y2,dx,dy); y2 = ydim16-1; } + } + else + { + if ((y2 >= ydim16) || (y1 < 0)) return; + if (y2 < 0) { if (dx) x2 += scale(0-y2,dx,dy); y2 = 0; } + if (y1 >= ydim16) { if (dx) x1 += scale(ydim16-1-y1,dx,dy); y1 = ydim16-1; } + } + + setcolor16((long)col); + if (x1 == x2) + { + if (y2 < y1) i = y1, y1 = y2, y2 = i; + koutpw(0x3ce,0x8+(256<<((x1&7)^7))); //bit mask + vlin16((((mul5(y1)<<7)+x1+pageoffset)>>3)+0xa0000,y2-y1+1); + return; + } + if (y1 == y2) + { + if (x2 < x1) i = x1, x1 = x2, x2 = i; + lmask = (0x00ff>>(x1&7)); + rmask = (0xff80>>(x2&7)); + + p = (((mul5(y1)<<7)+x1+pageoffset)>>3)+0xa0000; + + dx = (x2>>3)-(x1>>3); + if (dx == 0) + { + koutpw(0x3ce,0x8+((lmask&rmask)<<8)); drawpixel(p,readpixel(p)); + return; + } + + dx--; + + koutpw(0x3ce,0x8+(lmask<<8)); drawpixel(p,readpixel(p)); p++; + if (dx > 0) { koutp(0x3cf,0xff); clearbufbyte((void *)p,dx,0L); p += dx; } + koutp(0x3cf,rmask); drawpixel(p,readpixel(p)); + return; + } + + dx = klabs(x2-x1)+1; dy = klabs(y2-y1)+1; + if (dx >= dy) + { + if (x2 < x1) + { + i = x1; x1 = x2; x2 = i; + i = y1; y1 = y2; y2 = i; + } + p = (mul5(y1)<<7)+x1+pageoffset; + d = 0; + if (y2 > y1) pinc = 640; else pinc = -640; + for(i=dx;i>0;i--) + { + drawpixel16(p); + d += dy; + if (d >= dx) { d -= dx; p += pinc; } + p++; + } + return; + } + + if (y2 < y1) + { + i = x1; x1 = x2; x2 = i; + i = y1; y1 = y2; y2 = i; + } + p = (mul5(y1)<<7)+x1+pageoffset; + d = 0; + if (x2 > x1) pinc = 1; else pinc = -1; + for(i=dy;i>0;i--) + { + drawpixel16(p); + d += dx; + if (d >= dy) { d -= dy; p += pinc; } + p += 640; + } +} + + +void qsetmode640350(void) +{ + if (qsetmode != 350) + { + stereomode = 0; + + setvmode(0x10); + + pageoffset = 0; + ydim16 = 350; + koutpw(0x3d4,0xc+((pageoffset>>11)<<8)); + + koutpw(0x3ce,0x0f00); //set/reset + koutpw(0x3ce,0x0f01); //enable set/reset + fillscreen16(0L,0L,640L*350L); + } + qsetmode = 350; +} + +void qsetmode640480(void) +{ + short i; + + if (qsetmode != 480) + { + stereomode = 0; + + setvmode(0x12); + + i = 479-144; + koutpw(0x3d4,0x18+((i&255)<<8)); //line compare + koutp(0x3d4,0x7); koutp(0x3d5,(kinp(0x3d5)&239)|((i&256)>>4)); + koutp(0x3d4,0x9); koutp(0x3d5,(kinp(0x3d5)&191)|((i&512)>>3)); + + pageoffset = 92160; + koutpw(0x3d4,0xc+((pageoffset>>11)<<8)); + + koutpw(0x3ce,0x0f00); //set/reset + koutpw(0x3ce,0x0f01); //enable set/reset + fillscreen16(0L,8L,640L*144L); + fillscreen16((640L*144L)>>3,0L,640L*336L); + pageoffset = 92160; ydim16 = 336; + } + + qsetmode = 480; +} + + +void printext16(long xpos, long ypos, short col, short backcol, char name[82], char fontsize) +{ + long p, z, zz, charxsiz, daxpos; + char ch, dat, mask, *fontptr; + + daxpos = xpos; + + koutp(0x3ce,0x5); koutp(0x3cf,(kinp(0x3cf)&(255-3))+2); + koutp(0x3ce,0x8); + + if (fontsize == 1) + { + fontptr = smalltextfont; + charxsiz = 4; + } + else + { + fontptr = textfont; + charxsiz = 8; + } + + z = 0; + while (name[z] != 0) + { + ch = name[z]; + z++; + + mask = pow2char[8-(daxpos&7)]-1; + p = ypos*80 + (daxpos>>3)+0xa0000; //Do not make ylookup! + + if ((daxpos&7) == 0) + { + for(zz=0;zz<8;zz++) + { + if (backcol >= 0) + { + koutp(0x3cf,0xff); + if (charxsiz == 4) koutp(0x3cf,0x7c); + readpixel(p), drawpixel(p,(long)backcol); + } + koutp(0x3cf,fontptr[(((long)ch)<<3)+zz]); + if (charxsiz == 4) koutp(0x3cf,0x7c&fontptr[(((long)ch)<<3)+zz]); + readpixel(p), drawpixel(p,col); + p += 80; + } + } + else + { + for(zz=0;zz<8;zz++) + { + if (backcol >= 0) + { + if (charxsiz == 8) + { + koutp(0x3cf,mask); + readpixel(p), drawpixel(p,backcol); + koutp(0x3cf,~mask); + readpixel(p+1), drawpixel(p+1,backcol); + } + else + { + koutp(0x3cf,0x7c>>(daxpos&7)); + readpixel(p), drawpixel(p,backcol); + koutp(0x3cf,0x7c<<(8-(daxpos&7))); + readpixel(p+1), drawpixel(p+1,backcol); + } + } + dat = fontptr[(((long)ch)<<3)+zz]; + if (charxsiz == 8) + { + koutp(0x3cf,mask&(dat>>(daxpos&7))); + readpixel(p), drawpixel(p,col); + koutp(0x3cf,(~mask)&(dat<<(8-(daxpos&7)))); + readpixel(p+1), drawpixel(p+1,col); + } + else + { + koutp(0x3cf,(0x7c&dat)>>(daxpos&7)); + readpixel(p), drawpixel(p,col); + koutp(0x3cf,(0x7c&dat)<<(8-(daxpos&7))); + readpixel(p+1), drawpixel(p+1,col); + } + p += 80; //Do not make bytesperline! + } + } + + daxpos += charxsiz; + } + koutp(0x3ce,0x5); koutp(0x3cf,(kinp(0x3cf)&(255-3))+0); +} + +void _nextpage(void) +{ + switch(qsetmode) + { + case 200: + switch(vidoption) + { + case 1: + if (stereomode) + { + stereonextpage(); + if (!origbuffermode) buffermode = transarea = totalarea = 0; + } + else + { + visualpage = activepage; + setvisualpage(visualpage); + if (!origbuffermode) + { + buffermode = ((transarea<<3) > totalarea); + transarea = totalarea = 0; + } + activepage++; if (activepage >= numpages) activepage = 0; + setactivepage(activepage); + } + break; + case 2: + copybuf((void *)frameplace,(void *)0xa0000,64000>>2); + break; + case 6: + if (!activepage) redblueblit(screen,&screen[65536],64000L); + activepage ^= 1; + break; + } + break; + + case 350: + koutpw(0x3d4,0xc+((pageoffset>>11)<<8)); + limitrate(); + pageoffset = 225280-pageoffset; //225280 is 352(multiple of 16)*640 + break; + + case 480: + koutpw(0x3d4,0xc+((pageoffset>>11)<<8)); + limitrate(); + pageoffset = 399360-pageoffset; + break; + } +} // _nextpage + + +void interrupt stereohandler1(void) +{ + //VR flag + if (kinp(0x3c2)&128) + { + laststereoint = 0; + koutpw(0x3d4,((long)(overtbits)<<8)+0x11); + koutp(0x3d5,overtbits+16); + } + if (laststereoint == 1) + { + visualpage ^= 1; + setvisualpage(visualpage|0x80000000); //0x80000000 to ignore qlimitrate + } + laststereoint++; + koutp(0x70,0xc); kinp(0x71); + koutp(0xa0,0x20); + koutp(0x20,0x20); +} + +void interrupt stereohandler2(void) +{ + //VR flag + if (kinp(0x3c2)&128) + { + laststereoint = 0; + koutp(0x378,0xfb+((visualpage&1^1)<<2)); + koutpw(0x3d4,((long)overtbits<<8)+0x11); + koutp(0x3d5,overtbits+16); + } + if (laststereoint == 1) + { + visualpage ^= 1; + setvisualpage(visualpage|0x80000000); //0x80000000 to ignore qlimitrate + } + laststereoint++; + koutp(0x70,0xc); kinp(0x71); + koutp(0xa0,0x20); + koutp(0x20,0x20); +} + +void stereonextpage(void) +{ + koutp(0x70,0xc); kinp(0x71); + //koutpw(0x70,0x420b); + if ((activepage&1) == 0) + { + if (stereomode == 1) + { + clearbuf((void *)(ylookup[ydim-1]+frameplace),xdim>>4,whiteband); + clearbuf((void *)(ylookup[ydim-1]+frameplace+(xdim>>2)),(xdim>>2)-(xdim>>4),blackband); + } + activepage++; + setactivepage(activepage); + return; + } + if (stereomode == 1) + { + clearbuf((void *)(ylookup[ydim-1]+frameplace),(xdim>>2)-(xdim>>4),whiteband); + clearbuf((void *)(ylookup[ydim-1]+frameplace+xdim-(xdim>>2)),xdim>>4,blackband); + } + if (visualpage < (numpages&~1)-2) visualpage += 2; else visualpage &= 1; + if (activepage < (numpages&~1)-1) activepage++; else activepage = 0; + setactivepage(activepage); +} + +void setstereo(long dastereomode) +{ + //long i, dist, blackdist, whitedist, t1, t2, numlines; + //char c1, c2; + long i, dist, blackdist, whitedist; + + if ((vidoption != 1) || (numpages < 2)) return; + + if (stereomode) //---------------Uninitialize old stereo mode + { + if ((xdim == 320) && (ydim == 200)) + { + //back to 70 hz + koutp(0x3c2,o3c2); + } + + //Uninit VR flag + koutpw(0x3d4,(((long)overtbits+32)<<8)+0x11); + + //Uninit RTC + _disable(); + koutp(0xa1,(kinp(0xa1)&~1)|(oa1&1)); + koutp(0x70,0xa); koutp(0x71,ortca); + koutp(0x70,0xb); koutp(0x71,ortcb); + uninstallbistereohandlers(); + _enable(); + + stereomode = 0; + ostereopixelwidth = -1; + setview(windowx1,windowy1,windowx2,windowy2); + if (stereomode == 1) + { + for(i=0;i>2,blackband); + } + setactivepage(activepage); + } + } + + //------------------------------------- Initialize new stereo mode + stereomode = dastereomode; if (!stereomode) return; + + activepage = (visualpage & ~1)+2; + if (activepage >= numpages-1) activepage = 0; + + if (stereomode == 1) + { + blackdist = 0x7fffffff; whitedist = 0x80000000; + koutp(0x3c7,0); + for(i=0;i<256;i++) + { + dist = (kinp(0x3c9)&255)+(kinp(0x3c9)&255)+(kinp(0x3c9)&255); + if (dist < blackdist) { blackdist = dist; blackband = i; } + if (dist > whitedist) { whitedist = dist; whiteband = i; } + } + blackband += (blackband<<8); blackband += (blackband<<16); + whiteband += (whiteband<<8); whiteband += (whiteband<<16); + } + + if ((xdim == 320) && (ydim == 200)) + { + //80 hz + o3c2 = kinp(0x3cc); + koutp(0x3c2,(o3c2&0xf3)+4); + } + + //Init RTC + _disable(); + if (stereomode == 1) installbistereohandlers(stereohandler1); + if (stereomode == 2) installbistereohandlers(stereohandler2); + koutp(0x70,0xa); ortca = kinp(0x71); + if (stereomode == 1) koutp(0x71,0x28); //+8 = 256hz + if (stereomode == 2) koutp(0x71,0x26); //+6 = 1024hz + koutp(0x70,0xb); ortcb = kinp(0x71); koutp(0x71,0x42); + koutp(0x70,0xc); kinp(0x71); + oa1 = kinp(0xa1); koutp(0xa1,oa1&~1); + _enable(); + + //Init VR flag + koutp(0x3d4,0x11); + overtbits = kinp(0x3d5) & ~(16+32); + koutp(0x3d5,overtbits); + koutp(0x3d5,overtbits+16); +} + +#define RTCBUFSIZ 16 +static unsigned short rtcopmsel, rtcormseg, rtcormoff; +static unsigned long rtcopmoff; +//Use bicomc.asm as a template if this asm code needs re-writing +static char rtcrmbuffer[RTCBUFSIZ] = +{ + 0x50, //push ax + 0xb0,0x0c, //mov al, 0ch + 0xe6,0x70, //out 70h, al + 0xe4,0x71, //in al, 71h + 0xb0,0x20, //mov al, 20h + 0xe6,0xa0, //out 0a0h, al + 0xe6,0x20, //out 20h, al + 0x58, //pop ax + 0xcf //iret +}; +void *engconvalloc32 (unsigned long size) +{ + union REGS r; + + r.x.eax = 0x0100; //DPMI allocate DOS memory + r.x.ebx = ((size+15)>>4); //Number of paragraphs requested + int386(0x31,&r,&r); + + if (r.x.cflag != 0) //Failed + return ((unsigned long)0); + return ((void *)((r.x.eax&0xffff)<<4)); //Returns full 32-bit offset +} + +void installbistereohandlers(void far *stereohan) +{ + //char *ptr; + union REGS r; + struct SREGS sr; + void *lowp; + //int c; + + //Get old protected mode handler + r.x.eax = 0x3500+0x70; /* DOS get vector (INT 0Ch) */ + sr.ds = sr.es = 0; + int386x(0x21,&r,&r,&sr); + rtcopmsel = (unsigned short)sr.es; + rtcopmoff = r.x.ebx; + + //Get old real mode handler + r.x.eax = 0x0200; /* DPMI get real mode vector */ + r.h.bl = 0x70; + int386(0x31,&r,&r); + rtcormseg = (unsigned short)r.x.ecx; + rtcormoff = (unsigned short)r.x.edx; + + //Allocate memory in low memory to store real mode handler + if ((lowp = engconvalloc32(RTCBUFSIZ)) == 0) + { + printf("Couldn't allocate conventional memory.\n"); + exit(1); + } + + memcpy(lowp,(void *)rtcrmbuffer,RTCBUFSIZ); + + //Set new protected mode handler + r.x.eax = 0x2500+0x70; /* DOS set vector (INT 0Ch) */ + r.x.edx = FP_OFF(stereohan); + sr.ds = FP_SEG(stereohan); //DS:EDX == &handler + sr.es = 0; + int386x(0x21,&r,&r,&sr); + + //Set new real mode handler (must be after setting protected mode) + r.x.eax = 0x0201; + r.h.bl = 0x70; //CX:DX == real mode &handler + r.x.ecx = ((((long)lowp)>>4)&0xffff); //D32realseg + r.x.edx = (((long)lowp)&0xf); //D32realoff + int386(0x31,&r,&r); +} + +void uninstallbistereohandlers(void) +{ + union REGS r; + struct SREGS sr; + + //restore old protected mode handler + r.x.eax = 0x2500+0x70; /* DOS set vector (INT 0Ch) */ + r.x.edx = rtcopmoff; + sr.ds = rtcopmsel; /* DS:EDX == &handler */ + sr.es = 0; + int386x(0x21,&r,&r,&sr); + + //restore old real mode handler + r.x.eax = 0x0201; /* DPMI set real mode vector */ + r.h.bl = 0x70; + r.x.ecx = (unsigned long)rtcormseg; //CX:DX == real mode &handler + r.x.edx = (unsigned long)rtcormoff; + int386(0x31,&r,&r); +} + +void inittimer(void) +{ + outp(0x43,0x34); outp(0x40,(1193181/120)&255); outp(0x40,(1193181/120)>>8); + oldtimerhandler = _dos_getvect(0x8); + _disable(); _dos_setvect(0x8, timerhandler); _enable(); +} + +void uninittimer(void) +{ + outp(0x43,0x34); outp(0x40,0); outp(0x40,0); //18.2 times/sec + _disable(); _dos_setvect(0x8, oldtimerhandler); _enable(); +} + +void initkeys(void) +{ + oldkeyhandler = _dos_getvect(0x9); + _disable(); _dos_setvect(0x9, keyhandler); _enable(); +} + +void uninitkeys(void) +{ + short *ptr; + + _dos_setvect(0x9, oldkeyhandler); + //Turn off shifts to prevent stucks with quitting + ptr = (short *)0x417; *ptr &= ~0x030f; +} + +int _setgamemode(char davidoption, long daxdim, long daydim) +{ + long i, j, ostereomode; + + if ((qsetmode == 200) && (vidoption == davidoption) && (xdim == daxdim) && (ydim == daydim)) + return(0); + vidoption = davidoption; xdim = daxdim; ydim = daydim; + + strcpy(kensmessage,"!!!! BUILD engine&tools programmed by Ken Silverman of E.G. RI. (c) Copyright 1995 Ken Silverman. Summary: BUILD = Ken. !!!!"); + if (getkensmessagecrc(FP_OFF(kensmessage)) != 0x56c764d4) + { setvmode(0x3); printf("Nice try.\n"); exit(0); } + + ostereomode = stereomode; if (stereomode) setstereo(0L); + + activepage = visualpage = 0; + switch(vidoption) + { + case 1: i = xdim*ydim; break; + case 2: xdim = 320; ydim = 200; i = xdim*ydim; break; + case 6: xdim = 320; ydim = 200; i = 131072; break; + default: return(-1); + } + j = ydim*4*sizeof(long); //Leave room for horizlookup&horizlookup2 + + if (screen != NULL) + { + if (screenalloctype == 0) kkfree((void *)screen); + if (screenalloctype == 1) suckcache((long *)screen); + screen = NULL; + } + screenalloctype = 0; + if ((screen = (char *)kkmalloc(i+(j<<1))) == NULL) + { + allocache((long *)&screen,i+(j<<1),&permanentlock); + screenalloctype = 1; + } + + frameplace = FP_OFF(screen); + horizlookup = (long *)(frameplace+i); + horizlookup2 = (long *)(frameplace+i+j); + horizycent = ((ydim*4)>>1); + + + switch(vidoption) + { + case 1: + //bytesperline is set in this function + if (setvesa(xdim,ydim) < 0) return(-1); + break; + case 2: + horizycent = ((ydim*4)>>1); //HACK for switching to this mode + case 6: + bytesperline = xdim; + setvmode(0x13); + break; + default: return(-1); + } + + //Force drawrooms to call dosetaspect & recalculate stuff + oxyaspect = oxdimen = oviewingrange = -1; + + setvlinebpl(bytesperline); + j = 0; + for(i=0;i<=ydim;i++) ylookup[i] = j, j += bytesperline; + + numpages = 1; + if (vidoption == 1) numpages = min(maxpages,8); + + setview(0L,0L,xdim-1,ydim-1); + clearallviews(0L); + setbrightness(curbrightness, &palette[0]); + + if (searchx < 0) { searchx = halfxdimen; searchy = (ydimen>>1); } + + if (ostereomode) setstereo(ostereomode); + + qsetmode = 200; + return(0); +} + + +void _platform_init(int argc, char **argv, const char *title, const char *icon) +{ + // no op in DOS, currently. --ryan. +} + +void clear2dscreen(void) +{ + if (qsetmode == 350) + fillscreen16(pageoffset>>3,0L,640L*350L); + else if (qsetmode == 480) + { + if (ydim16 <= 336) fillscreen16(pageoffset>>3,0L,640L*336L); + else fillscreen16(pageoffset>>3,0L,640L*480L); + } +} + +void _idle(void) +{ + // no-op in DOS, which is non-multitasking. However, if someone were to + // add Desqview/win95/OS2/etc support, timeslicing would be good. +} + + +void *_getVideoBase(void) +{ + return((void *) 0xa0000); +} + +void _updateScreenRect(long x, long y, long w, long h) +{ +} + +int using_opengl(void) +{ + return(0); +} + +// end of dos_driver.c ... + diff --git a/buildengine/doscmpat.h b/buildengine/doscmpat.h new file mode 100755 index 0000000..b997d08 --- /dev/null +++ b/buildengine/doscmpat.h @@ -0,0 +1,69 @@ +/* + * DOS compatibility header. Takes care of some legacy code issues. + * + * Written by Ryan C. Gordon (icculus@clutteredmind.org) + * + * Please do NOT harrass Ken Silverman about any code modifications + * (including this file) to BUILD. + */ + +// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman +// Ken Silverman's official web site: "http://www.advsys.net/ken" +// See the included license file "BUILDLIC.TXT" for license info. + +#ifndef _INCLUDE_DOS_COMPAT_H_ +#define _INCLUDE_DOS_COMPAT_H_ + +#if (!defined PLATFORM_DOS) +#error PLATFORM_DOS is not defined. +#endif + +#if (defined PLATFORM_SUPPORTS_SDL) +#warning You have PLATFORM_SUPPORTS_SDL defined. +#warning This is almost certainly wrong. +#endif + +#define PLATFORM_TIMER_HZ 280 + +#if ((!defined __WATCOMC__) && (!defined __int64)) +#define __int64 long long +#endif + +// need these for something where we abstracted with SDL... +typedef unsigned long Uint32; +typedef unsigned short Uint16; +typedef unsigned char Uint8; + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#pragma intrinsic(min); +#pragma intrinsic(max); + +void printext16(long xpos, long ypos, short col, short backcol, char name[82], char fontsize); + +void *kkmalloc(size_t size); +void *kmalloc(size_t i1); +void kkfree(void *i1); +void kfree(void *i1); + +void setstereo(long dastereomode); +void printscreeninterrupt(void); + +void setvmode(int i1); +#pragma aux setvmode =\ + "int 0x10",\ + parm [eax]\ + +#endif + +// end of doscmpat.h ... + + diff --git a/buildengine/doxyfile b/buildengine/doxyfile new file mode 100755 index 0000000..33c34fe --- /dev/null +++ b/buildengine/doxyfile @@ -0,0 +1,993 @@ +# Doxyfile 1.2.18 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# General configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = "The Build Engine" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, +# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en +# (Japanese with english messages), Korean, Norwegian, Polish, Portuguese, +# Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish and Ukrainian. + +OUTPUT_LANGUAGE = English + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these class will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited +# members of a class in the documentation of that class as if those members were +# ordinary class members. Constructors, destructors and assignment operators of +# the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. It is allowed to use relative paths in the argument list. + +STRIP_FROM_PATH = + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower case letters. If set to YES upper case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# users are adviced to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like the Qt-style comments (thus requiring an +# explict @brief command for a brief description. + +JAVADOC_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the DETAILS_AT_TOP tag is set to YES then Doxygen +# will output the detailed description near the top, like JavaDoc. +# If set to NO, the detailed description appears after the member +# documentation. + +DETAILS_AT_TOP = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# reimplements. + +INHERIT_DOCS = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consist of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. +# For instance some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources +# only. Doxygen will then generate output that is more tailored for Java. +# For instance namespaces will be presented as packages, qualified scopes +# will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp +# *.h++ *.idl *.odl + +FILE_PATTERNS = *.h + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories +# that are symbolic links (a Unix filesystem feature) are excluded from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. + +EXCLUDE_PATTERNS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. + +INPUT_FILTER = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES (the default) +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output dir. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non empty doxygen will try to run +# the html help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the Html help documentation and to the tree view. + +TOC_EXPAND = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be +# generated containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript and frames is required (for instance Mozilla, Netscape 4.0+, +# or Internet explorer 4.0+). Note that for large projects the tree generation +# can take a very long time. In such cases it is better to disable this feature. +# Windows users are probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = YES + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimised for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assigments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_XML = NO + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_PREDEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse the +# parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::addtions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES tag can be used to specify one or more tagfiles. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in Html, RTF and LaTeX) for classes with base or +# super classes. Setting the tag to NO turns the diagrams off. Note that this +# option is superceded by the HAVE_DOT option below. This is only a fallback. It is +# recommended to install and use dot, since it yield more powerful graphs. + +CLASS_DIAGRAMS = YES + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found on the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_WIDTH = 1024 + +# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_HEIGHT = 1024 + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermedate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::addtions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO + +# The CGI_NAME tag should be the name of the CGI script that +# starts the search engine (doxysearch) with the correct parameters. +# A script with this name will be generated by doxygen. + +CGI_NAME = search.cgi + +# The CGI_URL tag should be the absolute URL to the directory where the +# cgi binaries are located. See the documentation of your http daemon for +# details. + +CGI_URL = + +# The DOC_URL tag should be the absolute URL to the directory where the +# documentation is located. If left blank the absolute path to the +# documentation, with file:// prepended to it, will be used. + +DOC_URL = + +# The DOC_ABSPATH tag should be the absolute path to the directory where the +# documentation is located. If left blank the directory on the local machine +# will be used. + +DOC_ABSPATH = + +# The BIN_ABSPATH tag must point to the directory where the doxysearch binary +# is installed. + +BIN_ABSPATH = /usr/local/bin/ + +# The EXT_DOC_PATHS tag can be used to specify one or more paths to +# documentation generated for other projects. This allows doxysearch to search +# the documentation for these projects as well. + +EXT_DOC_PATHS = diff --git a/buildengine/engine.c b/buildengine/engine.c new file mode 100755 index 0000000..8921455 --- /dev/null +++ b/buildengine/engine.c @@ -0,0 +1,8847 @@ +/* + * "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman + * Ken Silverman's official web site: "http://www.advsys.net/ken" + * See the included license file "BUILDLIC.TXT" for license info. + * This file has been modified from Ken Silverman's original release + */ + +/* SUPERBUILD define is in engine.h ... */ + +#define ENGINE + +/* set this to something non-zero to get loadtile() debugging info on stderr. */ +#define BUILD_CACHEDEBUG 0 + +#include + +#if !PLATFORM_MACOSX && !PLATFORM_FREEBSD +#include +#endif + +#if PLATFORM_FREEBSD +#include +#endif + +#include +#include +#include +#include +#include +#include + +#if (defined USE_OPENGL) +#include "buildgl.h" +#endif + +#include "pragmas.h" + +#include "platform.h" + +#include "build.h" +#include "cache1d.h" + +#include "engine.h" + +long stereowidth = 23040, stereopixelwidth = 28, ostereopixelwidth = -1; +volatile long stereomode = 0, visualpage, activepage, whiteband, blackband; +volatile char oa1, o3c2, ortca, ortcb, overtbits, laststereoint; + +#include "display.h" + +#define MAXCLIPNUM 512 +#define MAXPERMS 512 +#define MAXTILEFILES 256 +#define MAXYSAVES ((MAXXDIM*MAXSPRITES)>>7) +#define MAXNODESPERLINE 42 /* Warning: This depends on MAXYSAVES & MAXYDIM! */ +#define MAXWALLSB 2048 +#define MAXCLIPDIST 1024 + +#ifdef PLATFORM_DOS + /* MUST CALL MALLOC THIS WAY TO FORCE CALLS TO KMALLOC! */ +void *kmalloc(size_t size) { return(malloc(size)); } +void *kkmalloc(size_t size); +#pragma aux kkmalloc =\ + "call kmalloc",\ + parm [eax]\ + + /* MUST CALL FREE THIS WAY TO FORCE CALLS TO KFREE! */ +void kfree(void *buffer) { free(buffer); } +void kkfree(void *buffer); +#pragma aux kkfree =\ + "call kfree",\ + parm [eax]\ + +#endif + +#ifdef SUPERBUILD + /* MUST CALL LOADVOXEL THIS WAY BECAUSE WATCOM STINKS! */ + +/* !!! wtf does this do?! --ryan. */ +static void loadvoxel(long voxindex) +{ + voxindex = 0; /* prevent compiler whining. */ +} + +#if ((defined __WATCOMC__) && (defined PLATFORM_DOS)) +void kloadvoxel(long voxindex); +#pragma aux kloadvoxel =\ + "call loadvoxel",\ + parm [eax]\ + +#else +#define kloadvoxel(a) (loadvoxel(a)) +#endif + + /* These variables need to be copied into BUILD */ +#define MAXXSIZ 128 +#define MAXYSIZ 128 +#define MAXZSIZ 200 +#define MAXVOXELS 512 +#define MAXVOXMIPS 5 +long voxoff[MAXVOXELS][MAXVOXMIPS], voxlock[MAXVOXELS][MAXVOXMIPS]; +static long ggxinc[MAXXSIZ+1], ggyinc[MAXXSIZ+1]; +static long lowrecip[1024], nytooclose, nytoofar; +static unsigned long distrecip[16384]; +#endif + +/* used to be static. --ryan. */ +char moustat = 0; + +long transarea = 0, totalarea = 0, beforedrawrooms = 1; + +/* used to be static. --ryan. */ +long oxdimen = -1, oviewingrange = -1, oxyaspect = -1; + +/* used to be static. --ryan. */ +long curbrightness = 0; + + /* Textured Map variables */ +static char globalpolytype; +static short *dotp1[MAXYDIM], *dotp2[MAXYDIM]; + +static unsigned char tempbuf[MAXWALLS]; + +long ebpbak, espbak; +long slopalookup[16384]; + +/* + * !!! used to be static. If we ever put the original setgamemode() back, this + * !!! can be made static again. --ryan. + */ +unsigned char permanentlock = 255; +long artversion, mapversion; +char *pic = NULL; +char picsiz[MAXTILES], tilefilenum[MAXTILES]; +long lastageclock; +long tilefileoffs[MAXTILES]; + +long artsize = 0, cachesize = 0; + +static short radarang[1280], radarang2[MAXXDIM+1]; +static unsigned short sqrtable[4096], shlookup[4096+256]; +char pow2char[8] = {1,2,4,8,16,32,64,-128}; +long pow2long[32] = +{ + 1L,2L,4L,8L, + 16L,32L,64L,128L, + 256L,512L,1024L,2048L, + 4096L,8192L,16384L,32768L, + 65536L,131072L,262144L,524288L, + 1048576L,2097152L,4194304L,8388608L, + 16777216L,33554432L,67108864L,134217728L, + 268435456L,536870912L,1073741824L,2147483647L, +}; +long reciptable[2048], fpuasm; + +char kensmessage[128]; + +int has_altivec = 0; /* PowerPC-specific. */ + + +/* rcg02132001 Cygwin support. */ +#if (defined C_IDENTIFIERS_UNDERSCORED) +#define SYM_sqrtable "_sqrtable" +#define SYM_walock "_walock" +#define SYM_shlookup "_shlookup" +#define SYM_pow2char "_pow2char" +#define SYM_gotpic "_gotpic" +#define SYM_dmval "_dmval" +#else +#define SYM_sqrtable "sqrtable" +#define SYM_walock "walock" +#define SYM_shlookup "shlookup" +#define SYM_pow2char "pow2char" +#define SYM_gotpic "gotpic" +#define SYM_dmval "dmval" +#endif + +char britable[16][64]; +char textfont[1024], smalltextfont[1024]; + +static long xb1[MAXWALLSB], yb1[MAXWALLSB], xb2[MAXWALLSB], yb2[MAXWALLSB]; +static long rx1[MAXWALLSB], ry1[MAXWALLSB], rx2[MAXWALLSB], ry2[MAXWALLSB]; +static short p2[MAXWALLSB], thesector[MAXWALLSB], thewall[MAXWALLSB]; + +static short bunchfirst[MAXWALLSB], bunchlast[MAXWALLSB]; + +static short smost[MAXYSAVES], smostcnt; +static short smoststart[MAXWALLSB]; +static char smostwalltype[MAXWALLSB]; +static long smostwall[MAXWALLSB], smostwallcnt = -1L; + +static short maskwall[MAXWALLSB], maskwallcnt; +static long spritesx[MAXSPRITESONSCREEN]; +static long spritesy[MAXSPRITESONSCREEN+1]; +static long spritesz[MAXSPRITESONSCREEN]; +static spritetype *tspriteptr[MAXSPRITESONSCREEN]; + +short umost[MAXXDIM+1], dmost[MAXXDIM+1]; +static short bakumost[MAXXDIM+1], bakdmost[MAXXDIM+1]; +short uplc[MAXXDIM+1], dplc[MAXXDIM+1]; +static short uwall[MAXXDIM+1], dwall[MAXXDIM+1]; +static long swplc[MAXXDIM+1], lplc[MAXXDIM+1]; +static long swall[MAXXDIM+1], lwall[MAXXDIM+4]; +long xdimen = -1, xdimenrecip, halfxdimen, xdimenscale, xdimscale; +long wx1, wy1, wx2, wy2, ydimen; +long viewoffset, frameoffset; + +static long rxi[8], ryi[8], rzi[8], rxi2[8], ryi2[8], rzi2[8]; +static long xsi[8], ysi[8]; + +/* used to be static. --ryan. */ +long *horizlookup, *horizlookup2, horizycent; + +long globalposx, globalposy, globalposz, globalhoriz; +short globalang, globalcursectnum; +long globalpal, cosglobalang, singlobalang; +long cosviewingrangeglobalang, sinviewingrangeglobalang; +char *globalpalwritten; +long globaluclip, globaldclip, globvis; +long globalvisibility, globalhisibility, globalpisibility, globalcisibility; +char globparaceilclip, globparaflorclip; + +long xyaspect, viewingrangerecip; + +long asm1, asm2, asm3, asm4; +long vplce[4], vince[4], palookupoffse[4], bufplce[4]; +char globalxshift, globalyshift; +long globalxpanning, globalypanning, globalshade; +short globalpicnum, globalshiftval; +long globalzd, globalbufplc, globalyscale, globalorientation; +long globalx1, globaly1, globalx2, globaly2, globalx3, globaly3, globalzx; +long globalx, globaly, globalz; + +static short sectorborder[256], sectorbordercnt; +static char tablesloaded = 0; +long pageoffset, ydim16, qsetmode = 0; +long startposx, startposy, startposz; +short startang, startsectnum; +short pointhighlight, linehighlight, highlightcnt; +static long lastx[MAXYDIM]; +char *transluc = NULL, paletteloaded = 0; + +#define FASTPALGRIDSIZ 8 +static long rdist[129], gdist[129], bdist[129]; +static char colhere[((FASTPALGRIDSIZ+2)*(FASTPALGRIDSIZ+2)*(FASTPALGRIDSIZ+2))>>3]; +static char colhead[(FASTPALGRIDSIZ+2)*(FASTPALGRIDSIZ+2)*(FASTPALGRIDSIZ+2)]; +static long colnext[256]; +static char coldist[8] = {0,1,2,3,4,3,2,1}; +static long colscan[27]; + +static short clipnum, hitwalls[4]; +long hitscangoalx = (1<<29)-1, hitscangoaly = (1<<29)-1; + +typedef struct { long x1, y1, x2, y2; } linetype; +static linetype clipit[MAXCLIPNUM]; +static short clipsectorlist[MAXCLIPNUM], clipsectnum; +static short clipobjectval[MAXCLIPNUM]; + +typedef struct +{ + long sx, sy, z; + short a, picnum; + signed char dashade; + unsigned char dapalnum, dastat, pagesleft; + long cx1, cy1, cx2, cy2; +} permfifotype; +static permfifotype permfifo[MAXPERMS]; +static long permhead = 0, permtail = 0; + +short numscans, numhits, numbunches; + +short editstatus = 0; +short searchit; +long searchx = -1, searchy; /* search input */ +short searchsector, searchwall, searchstat; /* search output */ + +static char artfilename[20]; +static long numtilefiles, artfil = -1, artfilnum, artfilplc; + +static char inpreparemirror = 0; +static long mirrorsx1, mirrorsy1, mirrorsx2, mirrorsy2; + +long totalclocklock; + + +/* !!! can we move this somewhere? --ryan. */ +#if ((defined USE_I386_ASM) && (defined __WATCOMC__)) +extern long mmxoverlay(); +#pragma aux mmxoverlay modify [eax ebx ecx edx]; +extern long sethlinesizes(long,long,long); +#pragma aux sethlinesizes parm [eax][ebx][ecx]; +extern long setpalookupaddress(char *); +#pragma aux setpalookupaddress parm [eax]; +extern long setuphlineasm4(long,long); +#pragma aux setuphlineasm4 parm [eax][ebx]; +extern long hlineasm4(long,long,long,long,long,long); +#pragma aux hlineasm4 parm [eax][ebx][ecx][edx][esi][edi]; +extern long setuprhlineasm4(long,long,long,long,long,long); +#pragma aux setuprhlineasm4 parm [eax][ebx][ecx][edx][esi][edi]; +extern long rhlineasm4(long,long,long,long,long,long); +#pragma aux rhlineasm4 parm [eax][ebx][ecx][edx][esi][edi]; +extern long setuprmhlineasm4(long,long,long,long,long,long); +#pragma aux setuprmhlineasm4 parm [eax][ebx][ecx][edx][esi][edi]; +extern long rmhlineasm4(long,long,long,long,long,long); +#pragma aux rmhlineasm4 parm [eax][ebx][ecx][edx][esi][edi]; +extern long setupqrhlineasm4(long,long,long,long,long,long); +#pragma aux setupqrhlineasm4 parm [eax][ebx][ecx][edx][esi][edi]; +extern long qrhlineasm4(long,long,long,long,long,long); +#pragma aux qrhlineasm4 parm [eax][ebx][ecx][edx][esi][edi]; +extern long setvlinebpl(long); +#pragma aux setvlinebpl parm [eax]; +extern long fixtransluscence(long); +#pragma aux fixtransluscence parm [eax]; +extern long prevlineasm1(long,long,long,long,long,long); +#pragma aux prevlineasm1 parm [eax][ebx][ecx][edx][esi][edi]; +extern long vlineasm1(long,long,long,long,long,long); +#pragma aux vlineasm1 parm [eax][ebx][ecx][edx][esi][edi]; +extern long setuptvlineasm(long); +#pragma aux setuptvlineasm parm [eax]; +extern long tvlineasm1(long,long,long,long,long,long); +#pragma aux tvlineasm1 parm [eax][ebx][ecx][edx][esi][edi]; +extern long setuptvlineasm2(long,long,long); +#pragma aux setuptvlineasm2 parm [eax][ebx][ecx]; +extern long tvlineasm2(long,long,long,long,long,long); +#pragma aux tvlineasm2 parm [eax][ebx][ecx][edx][esi][edi]; +extern long mvlineasm1(long,long,long,long,long,long); +#pragma aux mvlineasm1 parm [eax][ebx][ecx][edx][esi][edi]; +extern long setupvlineasm(long); +#pragma aux setupvlineasm parm [eax]; +extern long vlineasm4(long,long); +#pragma aux vlineasm4 parm [ecx][edi] modify [eax ebx ecx edx esi edi]; +extern long setupmvlineasm(long); +#pragma aux setupmvlineasm parm [eax]; +extern long mvlineasm4(long,long); +#pragma aux mvlineasm4 parm [ecx][edi] modify [eax ebx ecx edx esi edi]; +extern void setupspritevline(long,long,long,long,long,long); +#pragma aux setupspritevline parm [eax][ebx][ecx][edx][esi][edi]; +extern void spritevline(long,long,long,long,long,long); +#pragma aux spritevline parm [eax][ebx][ecx][edx][esi][edi]; +extern void msetupspritevline(long,long,long,long,long,long); +#pragma aux msetupspritevline parm [eax][ebx][ecx][edx][esi][edi]; +extern void mspritevline(long,long,long,long,long,long); +#pragma aux mspritevline parm [eax][ebx][ecx][edx][esi][edi]; +extern void tsetupspritevline(long,long,long,long,long,long); +#pragma aux tsetupspritevline parm [eax][ebx][ecx][edx][esi][edi]; +extern void tspritevline(long,long,long,long,long,long); +#pragma aux tspritevline parm [eax][ebx][ecx][edx][esi][edi]; +extern long mhline(long,long,long,long,long,long); +#pragma aux mhline parm [eax][ebx][ecx][edx][esi][edi]; +extern long mhlineskipmodify(long,long,long,long,long,long); +#pragma aux mhlineskipmodify parm [eax][ebx][ecx][edx][esi][edi]; +extern long msethlineshift(long,long); +#pragma aux msethlineshift parm [eax][ebx]; +extern long thline(long,long,long,long,long,long); +#pragma aux thline parm [eax][ebx][ecx][edx][esi][edi]; +extern long thlineskipmodify(long,long,long,long,long,long); +#pragma aux thlineskipmodify parm [eax][ebx][ecx][edx][esi][edi]; +extern long tsethlineshift(long,long); +#pragma aux tsethlineshift parm [eax][ebx]; +extern long setupslopevlin(long,long,long); +#pragma aux setupslopevlin parm [eax][ebx][ecx] modify [edx]; +extern long slopevlin(long,long,long,long,long,long); +#pragma aux slopevlin parm [eax][ebx][ecx][edx][esi][edi]; +extern long settransnormal(); +#pragma aux settransnormal parm; +extern long settransreverse(); +#pragma aux settransreverse parm; +extern long setupdrawslab(long,long); +#pragma aux setupdrawslab parm [eax][ebx]; +extern long drawslab(long,long,long,long,long,long); +#pragma aux drawslab parm [eax][ebx][ecx][edx][esi][edi]; +#else +#include "a.h" +#endif + + +#if (defined USE_I386_ASM) + #if (defined __WATCOMC__) + + long nsqrtasm(int param); + #pragma aux nsqrtasm =\ + "test eax, 0xff000000",\ + "mov ebx, eax",\ + "jnz short over24",\ + "shr ebx, 12",\ + "mov cx, word ptr shlookup[ebx*2]",\ + "jmp short under24",\ + "over24: shr ebx, 24",\ + "mov cx, word ptr shlookup[ebx*2+8192]",\ + "under24: shr eax, cl",\ + "mov cl, ch",\ + "mov ax, word ptr sqrtable[eax*2]",\ + "shr eax, cl",\ + parm nomemory [eax]\ + modify exact [eax ebx ecx]\ + + #elif (defined __GNUC__) || (defined __ICC) + static __attribute__((noinline)) long nsqrtasm(int i1) + { + long retval; + __asm__ __volatile__ ( + "\n\t" + "testl $0xff000000, %%eax\n\t" + "movl %%eax, %%ebx\n\t" + "jnz nsqrover24\n\t" + "shrl $12, %%ebx\n\t" + "movw " SYM_shlookup "(, %%ebx, 2), %%cx\n\t" + "jmp nsqrunder24\n\t" + "nsqrover24: shr $24, %%ebx\n\t" + "movw (" SYM_shlookup "+ 8192)(, %%ebx, 2), %%cx\n\t" + "nsqrunder24: shrl %%cl, %%eax\n\t" + "movb %%ch, %%cl\n\t" + "movw " SYM_sqrtable "(, %%eax, 2), %%ax\n\t" + "shrl %%cl, %%eax\n\t" + : "=a" (retval) : "a" (i1) : "ebx", "ecx", "cc"); + return(retval); + } /* nsqrtasm */ + + #elif (defined _MSC_VER) + long nsqrtasm(int param) + { + __asm + { + mov eax, param + test eax, 0xff000000 + mov ebx, eax + jnz short over24 + shr ebx, 12 + mov cx, word ptr shlookup[ebx*2] + jmp short under24 + over24: shr ebx, 24 + mov cx, word ptr shlookup[ebx*2+8192] + under24: shr eax, cl + mov cl, ch + mov ax, word ptr sqrtable[eax*2] + shr eax, cl + mov param, eax + } /* asm */ + return(param); + } + #else + #error Please write Assembly code for your platform! + #endif + +#else /* !defined USE_I386_ASM */ + long nsqrtasm(unsigned long param) + { + unsigned short *shlookup_a = (unsigned short*)shlookup; + unsigned short *sqrtable_a = (unsigned short*)sqrtable; + unsigned short cx; + + if (param & 0xff000000) + cx = shlookup_a[(param>>24)+4096]; + else + cx = shlookup_a[param>>12]; + + param = param >> (cx&0xff); + param = ((param&0xffff0000)|sqrtable_a[param]); + param = param >> ((cx&0xff00)>>8); + + return param; + } +#endif /* defined USE_I386_ASM */ + + +#if (defined USE_I386_ASM) + #if (defined __WATCOMC__) + /* 0x007ff000 is (11<<13), 0x3f800000 is (127<<23) */ + long krecipasm(long param); + #pragma aux krecipasm =\ + "mov fpuasm, eax",\ + "fild dword ptr fpuasm",\ + "add eax, eax",\ + "fstp dword ptr fpuasm",\ + "sbb ebx, ebx",\ + "mov eax, fpuasm",\ + "mov ecx, eax",\ + "and eax, 0x007ff000",\ + "shr eax, 10",\ + "sub ecx, 0x3f800000",\ + "shr ecx, 23",\ + "mov eax, dword ptr reciptable[eax]",\ + "sar eax, cl",\ + "xor eax, ebx",\ + parm [eax]\ + modify exact [eax ebx ecx]\ + + #elif (defined __GNUC__) || (defined __ICC) + static long krecipasm(long i1) + { + long retval; + __asm__ __volatile__ ( + "\n\t" + "call _asm_krecipasm\n\t" + : "=a" (retval) : "a" (i1) + : "cc", "ebx", "ecx", "memory"); + return(retval); + } /* krecipasm */ + + #elif (defined _MSC_VER) + /* 0x007ff000 is (11<<13), 0x3f800000 is (127<<23) */ + long krecipasm(long param) + { + __asm + { + mov eax, param + mov fpuasm, eax + fild dword ptr fpuasm + add eax, eax + fstp dword ptr fpuasm + sbb ebx, ebx + mov eax, fpuasm + mov ecx, eax + and eax, 0x007ff000 + shr eax, 10 + sub ecx, 0x3f800000 + shr ecx, 23 + mov eax, dword ptr reciptable[eax] + sar eax, cl + xor eax, ebx + mov param,eax + } /* asm */ + return(param); + } /* krecipasm */ + #else + #error Please write Assembly for your platform! + #endif + +#else /* USE_I386_ASM */ + + static long krecipasm(long param) + { + unsigned int xormask; + int mantissa; + int exponent; + long recip; + + union { + float f; + unsigned int i; + } fi; + + fi.f = (float) param; + + fpuasm = fi.i; + + xormask = (param < 0) ? 0xffffffff : 0; + + mantissa = (fi.i & 0x007ff000) >> 12; + exponent = (fi.i - 0x3f800000) >> 23; + + recip = (reciptable[mantissa] >> exponent) ^ xormask; + + return recip; + } /* krecipasm */ +/* + static long krecipasm(long x) + { + float xf; + int z; + int not; + + if (x & 0x80000000) + not = 0x0FFFFFFFF; + else + not = 0; + + xf = (float)x; + + + x = *((int*)(&xf)); + z = x; + + x = x & 0x007FF000; + x = x >> 10; + + z = z - 0x03F800000; + z = z >> 23; + + x = shift_algebraic_right(reciptable[(x>>2)], z) ^ not; + return x; + } + */ +#endif /* defined USE_I386_ASM */ + + + +#if (defined USE_I386_ASM) + + #if (defined __WATCOMC__) + int setgotpic(long param); + #pragma aux setgotpic =\ + "mov ebx, eax",\ + "cmp byte ptr walock[eax], 200",\ + "jae skipit",\ + "mov byte ptr walock[eax], 199",\ + "skipit: shr eax, 3",\ + "and ebx, 7",\ + "mov dl, byte ptr gotpic[eax]",\ + "mov bl, byte ptr pow2char[ebx]",\ + "or dl, bl",\ + "mov byte ptr gotpic[eax], dl",\ + parm [eax]\ + modify exact [eax ebx ecx edx]\ + + #elif (defined __GNUC__) || (defined __ICC) + + int __attribute__((noinline)) setgotpic(long i1) + { + int retval = 0; + __asm__ __volatile__ ( + "\n\t" + "movl %%eax, %%ebx\n\t" + "cmpb $200, " SYM_walock "(%%eax)\n\t" + "jae setgotpic_skipit\n\t" + "movb $199, " SYM_walock "(%%eax)\n\t" + "setgotpic_skipit: shrl $3, %%eax\n\t" + "andl $7, %%ebx\n\t" + "movb " SYM_gotpic "(%%eax), %%dl\n\t" + "movb " SYM_pow2char "(%%ebx), %%bl\n\t" + "orb %%bl, %%dl\n\t" + "movb %%dl, (" SYM_gotpic ")(%%eax)\n\t" + : "=a" (retval) : "a" (i1) : "ebx", "ecx", "edx", "cc", "memory"); + return(retval); + } /* setgotpic */ + + #elif (defined _MSC_VER) + int setgotpic(long param) + { + __asm + { + mov eax, param + mov ebx, eax + cmp byte ptr walock[eax], 200 + jae skipit + mov byte ptr walock[eax], 199 + skipit: shr eax, 3 + and ebx, 7 + mov dl, byte ptr gotpic[eax] + mov bl, byte ptr pow2char[ebx] + or dl, bl + mov byte ptr gotpic[eax], dl + mov param, eax + } /* asm */ + return(param); + } /* setgotpic */ + + #else + #error Please write Assembly for your platform! + #endif + +#else /* !defined USE_I386_ASM */ + void setgotpic(unsigned long param) + { + unsigned char *gotpic_a = (unsigned char*)gotpic; + unsigned char *walock_a = (unsigned char*)walock; + unsigned char *pow2char_a = (unsigned char*)pow2char; + + if (walock_a[param] < 200) walock_a[param] = 199; + + gotpic_a[param>>3] |= pow2char_a[param&7]; + } +#endif /* defined USE_I386_ASM */ + + +#if (defined USE_I386_ASM) + #if (defined __WATCOMC__) + long getclipmask(int i1, int i2, int i3, int i4); + #pragma aux getclipmask =\ + "sar eax, 31",\ + "add ebx, ebx",\ + "adc eax, eax",\ + "add ecx, ecx",\ + "adc eax, eax",\ + "add edx, edx",\ + "adc eax, eax",\ + "mov ebx, eax",\ + "shl ebx, 4",\ + "or al, 0xf0",\ + "xor eax, ebx",\ + parm [eax][ebx][ecx][edx]\ + modify exact [eax ebx ecx edx]\ + + #elif (defined __GNUC__) || (defined __ICC) + long getclipmask(int i1, int i2, int i3, int i4) + { + int retval; + __asm__ __volatile__ ( + "\n\t" + "sarl $31, %%eax\n\t" + "addl %%ebx, %%ebx\n\t" + "adcl %%eax, %%eax\n\t" + "addl %%ecx, %%ecx\n\t" + "adcl %%eax, %%eax\n\t" + "addl %%edx, %%edx\n\t" + "adcl %%eax, %%eax\n\t" + "movl %%eax, %%ebx\n\t" + "shll $4, %%ebx\n\t" + "orb $0xf0, %%al\n\t" + "xorl %%ebx, %%eax\n\t" + : "=a" (retval) : "a" (i1), "b" (i2), "c" (i3), "d" (i4) + : "cc", "memory"); + return(retval); + } /* getclipmask */ + + #elif (defined _MSC_VER) + long getclipmask(int i1, int i2, int i3, int i4) + { + __asm + { + mov eax, i1 + mov ebx, i2 + mov ecx, i3 + mov edx, i4 + sar eax, 31 + add ebx, ebx + adc eax, eax + add ecx, ecx + adc eax, eax + add edx, edx + adc eax, eax + mov ebx, eax + shl ebx, 4 + or al, 0xf0 + xor eax, ebx + mov i1, eax + } /* asm */ + return(i1); + } /* getclipmask */ + + #else + #error Please write Assembly for your platform! + #endif + +#else /* !defined USE_I386_ASM */ + long getclipmask(int i1, int i2, int i3, int i4) + { + unsigned long eax; + eax = i1 >> 31; + eax = eax << 1; i2 *= 2; + if (i2&0x80000000) { eax++; } + eax = eax << 1; i3 *= 2; + if (i3&0x80000000) { eax++; } + eax = eax << 1; i4 *= 2; + if (i4&0x80000000) { eax++; } + return ((eax<<4)^(eax|0xf0)); + } +#endif /* defined USE_I386_ASM */ + +static void scansector (short sectnum) +{ + walltype *wal, *wal2; + spritetype *spr; + long xs, ys, x1, y1, x2, y2, xp1, yp1, xp2=0, yp2=0, templong; + short z, zz, startwall, endwall, numscansbefore, scanfirst, bunchfrst; + short nextsectnum; + + if (sectnum < 0) return; + + if (automapping) show2dsector[sectnum>>3] |= pow2char[sectnum&7]; + + sectorborder[0] = sectnum, sectorbordercnt = 1; + do + { + sectnum = sectorborder[--sectorbordercnt]; + + for(z=headspritesect[sectnum];z>=0;z=nextspritesect[z]) + { + spr = &sprite[z]; + if ((((spr->cstat&0x8000) == 0) || (showinvisibility)) && + (spr->xrepeat > 0) && (spr->yrepeat > 0) && + (spritesortcnt < MAXSPRITESONSCREEN)) + { + xs = spr->x-globalposx; ys = spr->y-globalposy; + if ((spr->cstat&48) || (xs*cosglobalang+ys*singlobalang > 0)) + { + copybufbyte(spr,&tsprite[spritesortcnt],sizeof(spritetype)); + tsprite[spritesortcnt++].owner = z; + } + } + } + + gotsector[sectnum>>3] |= pow2char[sectnum&7]; + + bunchfrst = numbunches; + numscansbefore = numscans; + + startwall = sector[sectnum].wallptr; + endwall = startwall + sector[sectnum].wallnum; + scanfirst = numscans; + for(z=startwall,wal=&wall[z];znextsector; + + wal2 = &wall[wal->point2]; + x1 = wal->x-globalposx; y1 = wal->y-globalposy; + x2 = wal2->x-globalposx; y2 = wal2->y-globalposy; + + if ((nextsectnum >= 0) && ((wal->cstat&32) == 0)) + if ((gotsector[nextsectnum>>3]&pow2char[nextsectnum&7]) == 0) + { + templong = x1*y2-x2*y1; + if (((unsigned)templong+262144) < 524288) + if (mulscale5(templong,templong) <= (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)) + sectorborder[sectorbordercnt++] = nextsectnum; + } + + if ((z == startwall) || (wall[z-1].point2 != z)) + { + xp1 = dmulscale6(y1,cosglobalang,-x1,singlobalang); + yp1 = dmulscale6(x1,cosviewingrangeglobalang,y1,sinviewingrangeglobalang); + } + else + { + xp1 = xp2; + yp1 = yp2; + } + xp2 = dmulscale6(y2,cosglobalang,-x2,singlobalang); + yp2 = dmulscale6(x2,cosviewingrangeglobalang,y2,sinviewingrangeglobalang); + if ((yp1 < 256) && (yp2 < 256)) goto skipitaddwall; + + /* If wall's NOT facing you */ + if (dmulscale32(xp1,yp2,-xp2,yp1) >= 0) goto skipitaddwall; + + if (xp1 >= -yp1) + { + if ((xp1 > yp1) || (yp1 == 0)) goto skipitaddwall; + xb1[numscans] = halfxdimen + scale(xp1,halfxdimen,yp1); + if (xp1 >= 0) xb1[numscans]++; /* Fix for SIGNED divide */ + if (xb1[numscans] >= xdimen) xb1[numscans] = xdimen-1; + yb1[numscans] = yp1; + } + else + { + if (xp2 < -yp2) goto skipitaddwall; + xb1[numscans] = 0; + templong = yp1-yp2+xp1-xp2; + if (templong == 0) goto skipitaddwall; + yb1[numscans] = yp1 + scale(yp2-yp1,xp1+yp1,templong); + } + if (yb1[numscans] < 256) goto skipitaddwall; + + if (xp2 <= yp2) + { + if ((xp2 < -yp2) || (yp2 == 0)) goto skipitaddwall; + xb2[numscans] = halfxdimen + scale(xp2,halfxdimen,yp2) - 1; + if (xp2 >= 0) xb2[numscans]++; /* Fix for SIGNED divide */ + if (xb2[numscans] >= xdimen) xb2[numscans] = xdimen-1; + yb2[numscans] = yp2; + } + else + { + if (xp1 > yp1) goto skipitaddwall; + xb2[numscans] = xdimen-1; + templong = xp2-xp1+yp1-yp2; + if (templong == 0) goto skipitaddwall; + yb2[numscans] = yp1 + scale(yp2-yp1,yp1-xp1,templong); + } + if ((yb2[numscans] < 256) || (xb1[numscans] > xb2[numscans])) goto skipitaddwall; + + /* Made it all the way! */ + thesector[numscans] = sectnum; thewall[numscans] = z; + rx1[numscans] = xp1; ry1[numscans] = yp1; + rx2[numscans] = xp2; ry2[numscans] = yp2; + p2[numscans] = numscans+1; + numscans++; +skipitaddwall: + + if ((wall[z].point2 < z) && (scanfirst < numscans)) + p2[numscans-1] = scanfirst, scanfirst = numscans; + } + + for(z=numscansbefore;z= xb1[p2[z]])) + bunchfirst[numbunches++] = p2[z], p2[z] = -1; + + for(z=bunchfrst;z=0;zz=p2[zz]); + bunchlast[z] = zz; + } + } while (sectorbordercnt > 0); +} + + +static void prepwall(long z, walltype *wal) +{ + long i, l=0, ol=0, splc, sinc, x, topinc, top, botinc, bot, walxrepeat; + + walxrepeat = (wal->xrepeat<<3); + + /* lwall calculation */ + i = xb1[z]-halfxdimen; + topinc = -(ry1[z]>>2); + botinc = ((ry2[z]-ry1[z])>>8); + top = mulscale5(rx1[z],xdimen)+mulscale2(topinc,i); + bot = mulscale11(rx1[z]-rx2[z],xdimen)+mulscale2(botinc,i); + + splc = mulscale19(ry1[z],xdimscale); + sinc = mulscale16(ry2[z]-ry1[z],xdimscale); + + x = xb1[z]; + if (bot != 0) + { + l = divscale12(top,bot); + swall[x] = mulscale21(l,sinc)+splc; + l *= walxrepeat; + lwall[x] = (l>>18); + } + while (x+4 <= xb2[z]) + { + top += topinc; bot += botinc; + if (bot != 0) + { + ol = l; l = divscale12(top,bot); + swall[x+4] = mulscale21(l,sinc)+splc; + l *= walxrepeat; + lwall[x+4] = (l>>18); + } + i = ((ol+l)>>1); + lwall[x+2] = (i>>18); + lwall[x+1] = ((ol+i)>>19); + lwall[x+3] = ((l+i)>>19); + swall[x+2] = ((swall[x]+swall[x+4])>>1); + swall[x+1] = ((swall[x]+swall[x+2])>>1); + swall[x+3] = ((swall[x+4]+swall[x+2])>>1); + x += 4; + } + if (x+2 <= xb2[z]) + { + top += (topinc>>1); bot += (botinc>>1); + if (bot != 0) + { + ol = l; l = divscale12(top,bot); + swall[x+2] = mulscale21(l,sinc)+splc; + l *= walxrepeat; + lwall[x+2] = (l>>18); + } + lwall[x+1] = ((l+ol)>>19); + swall[x+1] = ((swall[x]+swall[x+2])>>1); + x += 2; + } + if (x+1 <= xb2[z]) + { + bot += (botinc>>2); + if (bot != 0) + { + l = divscale12(top+(topinc>>2),bot); + swall[x+1] = mulscale21(l,sinc)+splc; + lwall[x+1] = mulscale18(l,walxrepeat); + } + } + + if (lwall[xb1[z]] < 0) lwall[xb1[z]] = 0; + if ((lwall[xb2[z]] >= walxrepeat) && (walxrepeat)) lwall[xb2[z]] = walxrepeat-1; + if (wal->cstat&8) + { + walxrepeat--; + for(x=xb1[z];x<=xb2[z];x++) lwall[x] = walxrepeat-lwall[x]; + } +} + + +static int getpalookup(long davis, long dashade) +{ + return(min(max(dashade+(davis>>8),0),numpalookups-1)); +} + + +static void hline (long xr, long yp) +{ + long xl, r, s; + + xl = lastx[yp]; if (xl > xr) return; + r = horizlookup2[yp-globalhoriz+horizycent]; + asm1 = globalx1*r; + asm2 = globaly2*r; + s = ((long)getpalookup((long)mulscale16(r,globvis),globalshade)<<8); + + hlineasm4(xr-xl,0L,s,globalx2*r+globalypanning,globaly1*r+globalxpanning, + ylookup[yp]+xr+frameoffset); +} + + +static void slowhline (long xr, long yp) +{ + long xl, r; + + xl = lastx[yp]; if (xl > xr) return; + r = horizlookup2[yp-globalhoriz+horizycent]; + asm1 = globalx1*r; + asm2 = globaly2*r; + + asm3 = (long)globalpalwritten + ((long)getpalookup((long)mulscale16(r,globvis),globalshade)<<8); + if (!(globalorientation&256)) + { + mhline(globalbufplc,globaly1*r+globalxpanning-asm1*(xr-xl),(xr-xl)<<16,0L, + globalx2*r+globalypanning-asm2*(xr-xl),ylookup[yp]+xl+frameoffset); + return; + } + thline(globalbufplc,globaly1*r+globalxpanning-asm1*(xr-xl),(xr-xl)<<16,0L, + globalx2*r+globalypanning-asm2*(xr-xl),ylookup[yp]+xl+frameoffset); + transarea += (xr-xl); +} + + +static int animateoffs(short tilenum, short fakevar) +{ + long i, k, offs; + + offs = 0; + i = (totalclocklock>>((picanm[tilenum]>>24)&15)); + if ((picanm[tilenum]&63) > 0) + { + switch(picanm[tilenum]&192) + { + case 64: + k = (i%((picanm[tilenum]&63)<<1)); + if (k < (picanm[tilenum]&63)) + offs = k; + else + offs = (((picanm[tilenum]&63)<<1)-k); + break; + case 128: + offs = (i%((picanm[tilenum]&63)+1)); + break; + case 192: + offs = -(i%((picanm[tilenum]&63)+1)); + } + } + return(offs); +} + + +/* renders non-parallaxed ceilings. --ryan. */ +static void ceilscan (long x1, long x2, long sectnum) +{ + long i, j, ox, oy, x, y1, y2, twall, bwall; + sectortype *sec; + + sec = §or[sectnum]; + if (palookup[sec->ceilingpal] != globalpalwritten) + { + globalpalwritten = palookup[sec->ceilingpal]; + setpalookupaddress(globalpalwritten); + } + + globalzd = sec->ceilingz-globalposz; + if (globalzd > 0) return; + globalpicnum = sec->ceilingpicnum; + if ((unsigned)globalpicnum >= (unsigned)MAXTILES) globalpicnum = 0; + setgotpic(globalpicnum); + if ((tilesizx[globalpicnum] <= 0) || (tilesizy[globalpicnum] <= 0)) return; + if (picanm[globalpicnum]&192) globalpicnum += animateoffs((short)globalpicnum,(short)sectnum); + + if (waloff[globalpicnum] == 0) loadtile(globalpicnum); + globalbufplc = waloff[globalpicnum]; + + globalshade = (long)sec->ceilingshade; + globvis = globalcisibility; + if (sec->visibility != 0) globvis = mulscale4(globvis,(long)((unsigned char)(sec->visibility+16))); + globalorientation = (long)sec->ceilingstat; + + + if ((globalorientation&64) == 0) + { + globalx1 = singlobalang; globalx2 = singlobalang; + globaly1 = cosglobalang; globaly2 = cosglobalang; + globalxpanning = (globalposx<<20); + globalypanning = -(globalposy<<20); + } + else + { + j = sec->wallptr; + ox = wall[wall[j].point2].x - wall[j].x; + oy = wall[wall[j].point2].y - wall[j].y; + i = nsqrtasm(ox*ox+oy*oy); if (i == 0) i = 1024; else i = 1048576/i; + globalx1 = mulscale10(dmulscale10(ox,singlobalang,-oy,cosglobalang),i); + globaly1 = mulscale10(dmulscale10(ox,cosglobalang,oy,singlobalang),i); + globalx2 = -globalx1; + globaly2 = -globaly1; + + ox = ((wall[j].x-globalposx)<<6); oy = ((wall[j].y-globalposy)<<6); + i = dmulscale14(oy,cosglobalang,-ox,singlobalang); + j = dmulscale14(ox,cosglobalang,oy,singlobalang); + ox = i; oy = j; + globalxpanning = globalx1*ox - globaly1*oy; + globalypanning = globaly2*ox + globalx2*oy; + } + globalx2 = mulscale16(globalx2,viewingrangerecip); + globaly1 = mulscale16(globaly1,viewingrangerecip); + globalxshift = (8-(picsiz[globalpicnum]&15)); + globalyshift = (8-(picsiz[globalpicnum]>>4)); + if (globalorientation&8) { globalxshift++; globalyshift++; } + + if ((globalorientation&0x4) > 0) + { + i = globalxpanning; globalxpanning = globalypanning; globalypanning = i; + i = globalx2; globalx2 = -globaly1; globaly1 = -i; + i = globalx1; globalx1 = globaly2; globaly2 = i; + } + if ((globalorientation&0x10) > 0) globalx1 = -globalx1, globaly1 = -globaly1, globalxpanning = -globalxpanning; + if ((globalorientation&0x20) > 0) globalx2 = -globalx2, globaly2 = -globaly2, globalypanning = -globalypanning; + globalx1 <<= globalxshift; globaly1 <<= globalxshift; + globalx2 <<= globalyshift; globaly2 <<= globalyshift; + globalxpanning <<= globalxshift; globalypanning <<= globalyshift; + globalxpanning += (((long)sec->ceilingxpanning)<<24); + globalypanning += (((long)sec->ceilingypanning)<<24); + globaly1 = (-globalx1-globaly1)*halfxdimen; + globalx2 = (globalx2-globaly2)*halfxdimen; + + sethlinesizes(picsiz[globalpicnum]&15,picsiz[globalpicnum]>>4,globalbufplc); + + globalx2 += globaly2*(x1-1); + globaly1 += globalx1*(x1-1); + globalx1 = mulscale16(globalx1,globalzd); + globalx2 = mulscale16(globalx2,globalzd); + globaly1 = mulscale16(globaly1,globalzd); + globaly2 = mulscale16(globaly2,globalzd); + globvis = klabs(mulscale10(globvis,globalzd)); + + if (!(globalorientation&0x180)) + { + y1 = umost[x1]; y2 = y1; + for(x=x1;x<=x2;x++) + { + twall = umost[x]-1; bwall = min(uplc[x],dmost[x]); + if (twall < bwall-1) + { + if (twall >= y2) + { + while (y1 < y2-1) hline(x-1,++y1); + y1 = twall; + } + else + { + while (y1 < twall) hline(x-1,++y1); + while (y1 > twall) lastx[y1--] = x; + } + while (y2 > bwall) hline(x-1,--y2); + while (y2 < bwall) lastx[y2++] = x; + } + else + { + while (y1 < y2-1) hline(x-1,++y1); + if (x == x2) { globalx2 += globaly2; globaly1 += globalx1; break; } + y1 = umost[x+1]; y2 = y1; + } + globalx2 += globaly2; globaly1 += globalx1; + } + while (y1 < y2-1) hline(x2,++y1); + faketimerhandler(); + return; + } + + switch(globalorientation&0x180) + { + case 128: + msethlineshift(picsiz[globalpicnum]&15,picsiz[globalpicnum]>>4); + break; + case 256: + settransnormal(); + tsethlineshift(picsiz[globalpicnum]&15,picsiz[globalpicnum]>>4); + break; + case 384: + settransreverse(); + tsethlineshift(picsiz[globalpicnum]&15,picsiz[globalpicnum]>>4); + break; + } + + y1 = umost[x1]; y2 = y1; + for(x=x1;x<=x2;x++) + { + twall = umost[x]-1; bwall = min(uplc[x],dmost[x]); + if (twall < bwall-1) + { + if (twall >= y2) + { + while (y1 < y2-1) slowhline(x-1,++y1); + y1 = twall; + } + else + { + while (y1 < twall) slowhline(x-1,++y1); + while (y1 > twall) lastx[y1--] = x; + } + while (y2 > bwall) slowhline(x-1,--y2); + while (y2 < bwall) lastx[y2++] = x; + } + else + { + while (y1 < y2-1) slowhline(x-1,++y1); + if (x == x2) { globalx2 += globaly2; globaly1 += globalx1; break; } + y1 = umost[x+1]; y2 = y1; + } + globalx2 += globaly2; globaly1 += globalx1; + } + while (y1 < y2-1) slowhline(x2,++y1); + faketimerhandler(); +} + + +/* renders non-parallaxed floors. --ryan. */ +static void florscan (long x1, long x2, long sectnum) +{ + long i, j, ox, oy, x, y1, y2, twall, bwall; + sectortype *sec; + + sec = §or[sectnum]; + if (palookup[sec->floorpal] != globalpalwritten) + { + globalpalwritten = palookup[sec->floorpal]; + setpalookupaddress(globalpalwritten); + } + + globalzd = globalposz-sec->floorz; + if (globalzd > 0) return; + globalpicnum = sec->floorpicnum; + if ((unsigned)globalpicnum >= (unsigned)MAXTILES) globalpicnum = 0; + setgotpic(globalpicnum); + if ((tilesizx[globalpicnum] <= 0) || (tilesizy[globalpicnum] <= 0)) return; + if (picanm[globalpicnum]&192) globalpicnum += animateoffs((short)globalpicnum,(short)sectnum); + + if (waloff[globalpicnum] == 0) loadtile(globalpicnum); + globalbufplc = waloff[globalpicnum]; + + globalshade = (long)sec->floorshade; + globvis = globalcisibility; + if (sec->visibility != 0) globvis = mulscale4(globvis,(long)((unsigned char)(sec->visibility+16))); + globalorientation = (long)sec->floorstat; + + + if ((globalorientation&64) == 0) + { + globalx1 = singlobalang; globalx2 = singlobalang; + globaly1 = cosglobalang; globaly2 = cosglobalang; + globalxpanning = (globalposx<<20); + globalypanning = -(globalposy<<20); + } + else + { + j = sec->wallptr; + ox = wall[wall[j].point2].x - wall[j].x; + oy = wall[wall[j].point2].y - wall[j].y; + i = nsqrtasm(ox*ox+oy*oy); if (i == 0) i = 1024; else i = 1048576/i; + globalx1 = mulscale10(dmulscale10(ox,singlobalang,-oy,cosglobalang),i); + globaly1 = mulscale10(dmulscale10(ox,cosglobalang,oy,singlobalang),i); + globalx2 = -globalx1; + globaly2 = -globaly1; + + ox = ((wall[j].x-globalposx)<<6); oy = ((wall[j].y-globalposy)<<6); + i = dmulscale14(oy,cosglobalang,-ox,singlobalang); + j = dmulscale14(ox,cosglobalang,oy,singlobalang); + ox = i; oy = j; + globalxpanning = globalx1*ox - globaly1*oy; + globalypanning = globaly2*ox + globalx2*oy; + } + globalx2 = mulscale16(globalx2,viewingrangerecip); + globaly1 = mulscale16(globaly1,viewingrangerecip); + globalxshift = (8-(picsiz[globalpicnum]&15)); + globalyshift = (8-(picsiz[globalpicnum]>>4)); + if (globalorientation&8) { globalxshift++; globalyshift++; } + + if ((globalorientation&0x4) > 0) + { + i = globalxpanning; globalxpanning = globalypanning; globalypanning = i; + i = globalx2; globalx2 = -globaly1; globaly1 = -i; + i = globalx1; globalx1 = globaly2; globaly2 = i; + } + if ((globalorientation&0x10) > 0) globalx1 = -globalx1, globaly1 = -globaly1, globalxpanning = -globalxpanning; + if ((globalorientation&0x20) > 0) globalx2 = -globalx2, globaly2 = -globaly2, globalypanning = -globalypanning; + globalx1 <<= globalxshift; globaly1 <<= globalxshift; + globalx2 <<= globalyshift; globaly2 <<= globalyshift; + globalxpanning <<= globalxshift; globalypanning <<= globalyshift; + globalxpanning += (((long)sec->floorxpanning)<<24); + globalypanning += (((long)sec->floorypanning)<<24); + globaly1 = (-globalx1-globaly1)*halfxdimen; + globalx2 = (globalx2-globaly2)*halfxdimen; + + sethlinesizes(picsiz[globalpicnum]&15,picsiz[globalpicnum]>>4,globalbufplc); + + globalx2 += globaly2*(x1-1); + globaly1 += globalx1*(x1-1); + globalx1 = mulscale16(globalx1,globalzd); + globalx2 = mulscale16(globalx2,globalzd); + globaly1 = mulscale16(globaly1,globalzd); + globaly2 = mulscale16(globaly2,globalzd); + globvis = klabs(mulscale10(globvis,globalzd)); + + if (!(globalorientation&0x180)) + { + y1 = max(dplc[x1],umost[x1]); y2 = y1; + for(x=x1;x<=x2;x++) + { + twall = max(dplc[x],umost[x])-1; bwall = dmost[x]; + if (twall < bwall-1) + { + if (twall >= y2) + { + while (y1 < y2-1) hline(x-1,++y1); + y1 = twall; + } + else + { + while (y1 < twall) hline(x-1,++y1); + while (y1 > twall) lastx[y1--] = x; + } + while (y2 > bwall) hline(x-1,--y2); + while (y2 < bwall) lastx[y2++] = x; + } + else + { + while (y1 < y2-1) hline(x-1,++y1); + if (x == x2) { globalx2 += globaly2; globaly1 += globalx1; break; } + y1 = max(dplc[x+1],umost[x+1]); y2 = y1; + } + globalx2 += globaly2; globaly1 += globalx1; + } + while (y1 < y2-1) hline(x2,++y1); + faketimerhandler(); + return; + } + + switch(globalorientation&0x180) + { + case 128: + msethlineshift(picsiz[globalpicnum]&15,picsiz[globalpicnum]>>4); + break; + case 256: + settransnormal(); + tsethlineshift(picsiz[globalpicnum]&15,picsiz[globalpicnum]>>4); + break; + case 384: + settransreverse(); + tsethlineshift(picsiz[globalpicnum]&15,picsiz[globalpicnum]>>4); + break; + } + + y1 = max(dplc[x1],umost[x1]); y2 = y1; + for(x=x1;x<=x2;x++) + { + twall = max(dplc[x],umost[x])-1; bwall = dmost[x]; + if (twall < bwall-1) + { + if (twall >= y2) + { + while (y1 < y2-1) slowhline(x-1,++y1); + y1 = twall; + } + else + { + while (y1 < twall) slowhline(x-1,++y1); + while (y1 > twall) lastx[y1--] = x; + } + while (y2 > bwall) slowhline(x-1,--y2); + while (y2 < bwall) lastx[y2++] = x; + } + else + { + while (y1 < y2-1) slowhline(x-1,++y1); + if (x == x2) { globalx2 += globaly2; globaly1 += globalx1; break; } + y1 = max(dplc[x+1],umost[x+1]); y2 = y1; + } + globalx2 += globaly2; globaly1 += globalx1; + } + while (y1 < y2-1) slowhline(x2,++y1); + faketimerhandler(); +} + + +/* + * renders walls and parallaxed skies/floors. Look at parascan() for the + * higher level of parallaxing. + * + * x1 == offset of leftmost pixel of wall. 0 is left of surface. + * x2 == offset of rightmost pixel of wall. 0 is left of surface. + * + * apparently, walls are always vertical; there are sloping functions + * (!!!) er...elsewhere. Only the sides need be vertical, as the top and + * bottom of the polygon will need to be angled as the camera perspective + * shifts (user spins in a circle, etc.) + * + * uwal is an array of the upper most pixels, and dwal are the lower most. + * This must be a list, as the top and bottom of the polygon are not + * necessarily horizontal lines. + * + * So, the screen coordinate of the top left of a wall is specified by + * uwal[x1], the bottom left by dwal[x1], the top right by uwal[x2], and + * the bottom right by dwal[x2]. Every physical point on the edge of the + * wall in between is specified by traversing those arrays, one pixel per + * element. + * + * --ryan. + */ +static void wallscan(long x1, long x2, + short *uwal, short *dwal, + long *swal, long *lwal) +{ + long i, x, xnice, ynice, fpalookup; + long y1ve[4], y2ve[4], u4, d4, z, tsizx, tsizy; + char bad; + + tsizx = tilesizx[globalpicnum]; + tsizy = tilesizy[globalpicnum]; + setgotpic(globalpicnum); + if ((tsizx <= 0) || (tsizy <= 0)) return; + if ((uwal[x1] > ydimen) && (uwal[x2] > ydimen)) return; + if ((dwal[x1] < 0) && (dwal[x2] < 0)) return; + + if (waloff[globalpicnum] == 0) loadtile(globalpicnum); + + xnice = (pow2long[picsiz[globalpicnum]&15] == tsizx); + if (xnice) tsizx--; + ynice = (pow2long[picsiz[globalpicnum]>>4] == tsizy); + if (ynice) tsizy = (picsiz[globalpicnum]>>4); + + fpalookup = (long)FP_OFF(palookup[globalpal]); + + setupvlineasm(globalshiftval); + + x = x1; + while ((umost[x] > dmost[x]) && (x <= x2)) x++; + + for(;(x<=x2)&&((x+frameoffset)&3);x++) + { + y1ve[0] = max(uwal[x],umost[x]); + y2ve[0] = min(dwal[x],dmost[x]); + if (y2ve[0] <= y1ve[0]) continue; + + palookupoffse[0] = fpalookup+(getpalookup((long)mulscale16(swal[x],globvis),globalshade)<<8); + + bufplce[0] = lwal[x] + globalxpanning; + if (bufplce[0] >= tsizx) { if (xnice == 0) bufplce[0] %= tsizx; else bufplce[0] &= tsizx; } + if (ynice == 0) bufplce[0] *= tsizy; else bufplce[0] <<= tsizy; + + vince[0] = swal[x]*globalyscale; + vplce[0] = globalzd + vince[0]*(y1ve[0]-globalhoriz+1); + + vlineasm1(vince[0],palookupoffse[0],y2ve[0]-y1ve[0]-1,vplce[0],bufplce[0]+waloff[globalpicnum],x+frameoffset+ylookup[y1ve[0]]); + } + for(;x<=x2-3;x+=4) + { + bad = 0; + for(z=3;z>=0;z--) + { + y1ve[z] = max(uwal[x+z],umost[x+z]); + y2ve[z] = min(dwal[x+z],dmost[x+z])-1; + if (y2ve[z] < y1ve[z]) { bad += pow2char[z]; continue; } + + i = lwal[x+z] + globalxpanning; + if (i >= tsizx) { if (xnice == 0) i %= tsizx; else i &= tsizx; } + if (ynice == 0) i *= tsizy; else i <<= tsizy; + bufplce[z] = waloff[globalpicnum]+i; + + vince[z] = swal[x+z]*globalyscale; + vplce[z] = globalzd + vince[z]*(y1ve[z]-globalhoriz+1); + } + if (bad == 15) continue; + + palookupoffse[0] = fpalookup+(getpalookup((long)mulscale16(swal[x],globvis),globalshade)<<8); + palookupoffse[3] = fpalookup+(getpalookup((long)mulscale16(swal[x+3],globvis),globalshade)<<8); + + if ((palookupoffse[0] == palookupoffse[3]) && ((bad&0x9) == 0)) + { + palookupoffse[1] = palookupoffse[0]; + palookupoffse[2] = palookupoffse[0]; + } + else + { + palookupoffse[1] = fpalookup+(getpalookup((long)mulscale16(swal[x+1],globvis),globalshade)<<8); + palookupoffse[2] = fpalookup+(getpalookup((long)mulscale16(swal[x+2],globvis),globalshade)<<8); + } + + u4 = max(max(y1ve[0],y1ve[1]),max(y1ve[2],y1ve[3])); + d4 = min(min(y2ve[0],y2ve[1]),min(y2ve[2],y2ve[3])); + + if ((bad != 0) || (u4 >= d4)) + { + if (!(bad&1)) prevlineasm1(vince[0],palookupoffse[0],y2ve[0]-y1ve[0],vplce[0],bufplce[0],ylookup[y1ve[0]]+x+frameoffset+0); + if (!(bad&2)) prevlineasm1(vince[1],palookupoffse[1],y2ve[1]-y1ve[1],vplce[1],bufplce[1],ylookup[y1ve[1]]+x+frameoffset+1); + if (!(bad&4)) prevlineasm1(vince[2],palookupoffse[2],y2ve[2]-y1ve[2],vplce[2],bufplce[2],ylookup[y1ve[2]]+x+frameoffset+2); + if (!(bad&8)) prevlineasm1(vince[3],palookupoffse[3],y2ve[3]-y1ve[3],vplce[3],bufplce[3],ylookup[y1ve[3]]+x+frameoffset+3); + continue; + } + + if (u4 > y1ve[0]) vplce[0] = prevlineasm1(vince[0],palookupoffse[0],u4-y1ve[0]-1,vplce[0],bufplce[0],ylookup[y1ve[0]]+x+frameoffset+0); + if (u4 > y1ve[1]) vplce[1] = prevlineasm1(vince[1],palookupoffse[1],u4-y1ve[1]-1,vplce[1],bufplce[1],ylookup[y1ve[1]]+x+frameoffset+1); + if (u4 > y1ve[2]) vplce[2] = prevlineasm1(vince[2],palookupoffse[2],u4-y1ve[2]-1,vplce[2],bufplce[2],ylookup[y1ve[2]]+x+frameoffset+2); + if (u4 > y1ve[3]) vplce[3] = prevlineasm1(vince[3],palookupoffse[3],u4-y1ve[3]-1,vplce[3],bufplce[3],ylookup[y1ve[3]]+x+frameoffset+3); + + if (d4 >= u4) vlineasm4(d4-u4+1,ylookup[u4]+x+frameoffset); + + i = x+frameoffset+ylookup[d4+1]; + if (y2ve[0] > d4) prevlineasm1(vince[0],palookupoffse[0],y2ve[0]-d4-1,vplce[0],bufplce[0],i+0); + if (y2ve[1] > d4) prevlineasm1(vince[1],palookupoffse[1],y2ve[1]-d4-1,vplce[1],bufplce[1],i+1); + if (y2ve[2] > d4) prevlineasm1(vince[2],palookupoffse[2],y2ve[2]-d4-1,vplce[2],bufplce[2],i+2); + if (y2ve[3] > d4) prevlineasm1(vince[3],palookupoffse[3],y2ve[3]-d4-1,vplce[3],bufplce[3],i+3); + } + for(;x<=x2;x++) + { + y1ve[0] = max(uwal[x],umost[x]); + y2ve[0] = min(dwal[x],dmost[x]); + if (y2ve[0] <= y1ve[0]) continue; + + palookupoffse[0] = fpalookup+(getpalookup((long)mulscale16(swal[x],globvis),globalshade)<<8); + + bufplce[0] = lwal[x] + globalxpanning; + if (bufplce[0] >= tsizx) { if (xnice == 0) bufplce[0] %= tsizx; else bufplce[0] &= tsizx; } + if (ynice == 0) bufplce[0] *= tsizy; else bufplce[0] <<= tsizy; + + vince[0] = swal[x]*globalyscale; + vplce[0] = globalzd + vince[0]*(y1ve[0]-globalhoriz+1); + + vlineasm1(vince[0],palookupoffse[0],y2ve[0]-y1ve[0]-1,vplce[0],bufplce[0]+waloff[globalpicnum],x+frameoffset+ylookup[y1ve[0]]); + } + faketimerhandler(); +} + + +/* this renders masking sprites. See wallscan(). --ryan. */ +static void maskwallscan(long x1, long x2, + short *uwal, short *dwal, + long *swal, long *lwal) +{ + long i, x, startx, xnice, ynice, fpalookup; + long y1ve[4], y2ve[4], u4, d4, dax, z, p, tsizx, tsizy; + char bad; + + tsizx = tilesizx[globalpicnum]; + tsizy = tilesizy[globalpicnum]; + setgotpic(globalpicnum); + if ((tsizx <= 0) || (tsizy <= 0)) return; + if ((uwal[x1] > ydimen) && (uwal[x2] > ydimen)) return; + if ((dwal[x1] < 0) && (dwal[x2] < 0)) return; + + if (waloff[globalpicnum] == 0) loadtile(globalpicnum); + + startx = x1; + + xnice = (pow2long[picsiz[globalpicnum]&15] == tsizx); + if (xnice) tsizx = (tsizx-1); + ynice = (pow2long[picsiz[globalpicnum]>>4] == tsizy); + if (ynice) tsizy = (picsiz[globalpicnum]>>4); + + fpalookup = (long)FP_OFF(palookup[globalpal]); + + setupmvlineasm(globalshiftval); + + x = startx; + while ((startumost[x+windowx1] > startdmost[x+windowx1]) && (x <= x2)) x++; + + p = x+frameoffset; + + for(;(x<=x2)&&(p&3);x++,p++) + { + y1ve[0] = max(uwal[x],startumost[x+windowx1]-windowy1); + y2ve[0] = min(dwal[x],startdmost[x+windowx1]-windowy1); + if (y2ve[0] <= y1ve[0]) continue; + + palookupoffse[0] = fpalookup+(getpalookup((long)mulscale16(swal[x],globvis),globalshade)<<8); + + bufplce[0] = lwal[x] + globalxpanning; + if (bufplce[0] >= tsizx) { if (xnice == 0) bufplce[0] %= tsizx; else bufplce[0] &= tsizx; } + if (ynice == 0) bufplce[0] *= tsizy; else bufplce[0] <<= tsizy; + + vince[0] = swal[x]*globalyscale; + vplce[0] = globalzd + vince[0]*(y1ve[0]-globalhoriz+1); + + mvlineasm1(vince[0],palookupoffse[0],y2ve[0]-y1ve[0]-1,vplce[0],bufplce[0]+waloff[globalpicnum],p+ylookup[y1ve[0]]); + } + for(;x<=x2-3;x+=4,p+=4) + { + bad = 0; + for(z=3,dax=x+3;z>=0;z--,dax--) + { + y1ve[z] = max(uwal[dax],startumost[dax+windowx1]-windowy1); + y2ve[z] = min(dwal[dax],startdmost[dax+windowx1]-windowy1)-1; + if (y2ve[z] < y1ve[z]) { bad += pow2char[z]; continue; } + + i = lwal[dax] + globalxpanning; + if (i >= tsizx) { if (xnice == 0) i %= tsizx; else i &= tsizx; } + if (ynice == 0) i *= tsizy; else i <<= tsizy; + bufplce[z] = waloff[globalpicnum]+i; + + vince[z] = swal[dax]*globalyscale; + vplce[z] = globalzd + vince[z]*(y1ve[z]-globalhoriz+1); + } + if (bad == 15) continue; + + palookupoffse[0] = fpalookup+(getpalookup((long)mulscale16(swal[x],globvis),globalshade)<<8); + palookupoffse[3] = fpalookup+(getpalookup((long)mulscale16(swal[x+3],globvis),globalshade)<<8); + + if ((palookupoffse[0] == palookupoffse[3]) && ((bad&0x9) == 0)) + { + palookupoffse[1] = palookupoffse[0]; + palookupoffse[2] = palookupoffse[0]; + } + else + { + palookupoffse[1] = fpalookup+(getpalookup((long)mulscale16(swal[x+1],globvis),globalshade)<<8); + palookupoffse[2] = fpalookup+(getpalookup((long)mulscale16(swal[x+2],globvis),globalshade)<<8); + } + + u4 = max(max(y1ve[0],y1ve[1]),max(y1ve[2],y1ve[3])); + d4 = min(min(y2ve[0],y2ve[1]),min(y2ve[2],y2ve[3])); + + if ((bad > 0) || (u4 >= d4)) + { + if (!(bad&1)) mvlineasm1(vince[0],palookupoffse[0],y2ve[0]-y1ve[0],vplce[0],bufplce[0],ylookup[y1ve[0]]+p+0); + if (!(bad&2)) mvlineasm1(vince[1],palookupoffse[1],y2ve[1]-y1ve[1],vplce[1],bufplce[1],ylookup[y1ve[1]]+p+1); + if (!(bad&4)) mvlineasm1(vince[2],palookupoffse[2],y2ve[2]-y1ve[2],vplce[2],bufplce[2],ylookup[y1ve[2]]+p+2); + if (!(bad&8)) mvlineasm1(vince[3],palookupoffse[3],y2ve[3]-y1ve[3],vplce[3],bufplce[3],ylookup[y1ve[3]]+p+3); + continue; + } + + if (u4 > y1ve[0]) vplce[0] = mvlineasm1(vince[0],palookupoffse[0],u4-y1ve[0]-1,vplce[0],bufplce[0],ylookup[y1ve[0]]+p+0); + if (u4 > y1ve[1]) vplce[1] = mvlineasm1(vince[1],palookupoffse[1],u4-y1ve[1]-1,vplce[1],bufplce[1],ylookup[y1ve[1]]+p+1); + if (u4 > y1ve[2]) vplce[2] = mvlineasm1(vince[2],palookupoffse[2],u4-y1ve[2]-1,vplce[2],bufplce[2],ylookup[y1ve[2]]+p+2); + if (u4 > y1ve[3]) vplce[3] = mvlineasm1(vince[3],palookupoffse[3],u4-y1ve[3]-1,vplce[3],bufplce[3],ylookup[y1ve[3]]+p+3); + + if (d4 >= u4) mvlineasm4(d4-u4+1,ylookup[u4]+p); + + i = p+ylookup[d4+1]; + if (y2ve[0] > d4) mvlineasm1(vince[0],palookupoffse[0],y2ve[0]-d4-1,vplce[0],bufplce[0],i+0); + if (y2ve[1] > d4) mvlineasm1(vince[1],palookupoffse[1],y2ve[1]-d4-1,vplce[1],bufplce[1],i+1); + if (y2ve[2] > d4) mvlineasm1(vince[2],palookupoffse[2],y2ve[2]-d4-1,vplce[2],bufplce[2],i+2); + if (y2ve[3] > d4) mvlineasm1(vince[3],palookupoffse[3],y2ve[3]-d4-1,vplce[3],bufplce[3],i+3); + } + for(;x<=x2;x++,p++) + { + y1ve[0] = max(uwal[x],startumost[x+windowx1]-windowy1); + y2ve[0] = min(dwal[x],startdmost[x+windowx1]-windowy1); + if (y2ve[0] <= y1ve[0]) continue; + + palookupoffse[0] = fpalookup+(getpalookup((long)mulscale16(swal[x],globvis),globalshade)<<8); + + bufplce[0] = lwal[x] + globalxpanning; + if (bufplce[0] >= tsizx) { if (xnice == 0) bufplce[0] %= tsizx; else bufplce[0] &= tsizx; } + if (ynice == 0) bufplce[0] *= tsizy; else bufplce[0] <<= tsizy; + + vince[0] = swal[x]*globalyscale; + vplce[0] = globalzd + vince[0]*(y1ve[0]-globalhoriz+1); + + mvlineasm1(vince[0],palookupoffse[0],y2ve[0]-y1ve[0]-1,vplce[0],bufplce[0]+waloff[globalpicnum],p+ylookup[y1ve[0]]); + } + faketimerhandler(); +} + +/* renders parallaxed skies/floors --ryan. */ +static void parascan(long dax1, long dax2, long sectnum, + char dastat, long bunch) +{ + sectortype *sec; + long j, k, l, m, n, x, z, wallnum, nextsectnum, globalhorizbak; + short *topptr, *botptr; + + sectnum = thesector[bunchfirst[bunch]]; sec = §or[sectnum]; + + globalhorizbak = globalhoriz; + if (parallaxyscale != 65536) + globalhoriz = mulscale16(globalhoriz-(ydimen>>1),parallaxyscale) + (ydimen>>1); + globvis = globalpisibility; + /* globalorientation = 0L; */ + if (sec->visibility != 0) globvis = mulscale4(globvis,(long)((unsigned char)(sec->visibility+16))); + + if (dastat == 0) + { + globalpal = sec->ceilingpal; + globalpicnum = sec->ceilingpicnum; + globalshade = (long)sec->ceilingshade; + globalxpanning = (long)sec->ceilingxpanning; + globalypanning = (long)sec->ceilingypanning; + topptr = umost; + botptr = uplc; + } + else + { + globalpal = sec->floorpal; + globalpicnum = sec->floorpicnum; + globalshade = (long)sec->floorshade; + globalxpanning = (long)sec->floorxpanning; + globalypanning = (long)sec->floorypanning; + topptr = dplc; + botptr = dmost; + } + + if ((unsigned)globalpicnum >= (unsigned)MAXTILES) globalpicnum = 0; + if (picanm[globalpicnum]&192) globalpicnum += animateoffs(globalpicnum,(short)sectnum); + globalshiftval = (picsiz[globalpicnum]>>4); + if (pow2long[globalshiftval] != tilesizy[globalpicnum]) globalshiftval++; + globalshiftval = 32-globalshiftval; + globalzd = (((tilesizy[globalpicnum]>>1)+parallaxyoffs)<=0;z=p2[z]) + { + wallnum = thewall[z]; nextsectnum = wall[wallnum].nextsector; + + if (dastat == 0) j = sector[nextsectnum].ceilingstat; + else j = sector[nextsectnum].floorstat; + + if ((nextsectnum < 0) || (wall[wallnum].cstat&32) || ((j&1) == 0)) + { + if (x == -1) x = xb1[z]; + + if (parallaxtype == 0) + { + n = mulscale16(xdimenrecip,viewingrange); + for(j=xb1[z];j<=xb2[z];j++) + lplc[j] = (((mulscale23(j-halfxdimen,n)+globalang)&2047)>>k); + } + else + { + for(j=xb1[z];j<=xb2[z];j++) + lplc[j] = ((((long)radarang2[j]+globalang)&2047)>>k); + } + if (parallaxtype == 2) + { + n = mulscale16(xdimscale,viewingrange); + for(j=xb1[z];j<=xb2[z];j++) + swplc[j] = mulscale14(sintable[((long)radarang2[j]+512)&2047],n); + } + else + clearbuf(&swplc[xb1[z]],xb2[z]-xb1[z]+1,mulscale16(xdimscale,viewingrange)); + } + else if (x >= 0) + { + l = globalpicnum; m = (picsiz[globalpicnum]&15); + globalpicnum = l+pskyoff[lplc[x]>>m]; + + if (((lplc[x]^lplc[xb1[z]-1])>>m) == 0) + wallscan(x,xb1[z]-1,topptr,botptr,swplc,lplc); + else + { + j = x; + while (x < xb1[z]) + { + n = l+pskyoff[lplc[x]>>m]; + if (n != globalpicnum) + { + wallscan(j,x-1,topptr,botptr,swplc,lplc); + j = x; + globalpicnum = n; + } + x++; + } + if (j < x) + wallscan(j,x-1,topptr,botptr,swplc,lplc); + } + + globalpicnum = l; + x = -1; + } + } + + if (x >= 0) + { + l = globalpicnum; m = (picsiz[globalpicnum]&15); + globalpicnum = l+pskyoff[lplc[x]>>m]; + + if (((lplc[x]^lplc[xb2[bunchlast[bunch]]])>>m) == 0) + wallscan(x,xb2[bunchlast[bunch]],topptr,botptr,swplc,lplc); + else + { + j = x; + while (x <= xb2[bunchlast[bunch]]) + { + n = l+pskyoff[lplc[x]>>m]; + if (n != globalpicnum) + { + wallscan(j,x-1,topptr,botptr,swplc,lplc); + j = x; + globalpicnum = n; + } + x++; + } + if (j <= x) + wallscan(j,x,topptr,botptr,swplc,lplc); + } + globalpicnum = l; + } + globalhoriz = globalhorizbak; +} + + +#define BITSOFPRECISION 3 /* Don't forget to change this in A.ASM also! */ +static void grouscan (long dax1, long dax2, long sectnum, char dastat) +{ + long i, j, l, x, y, dx, dy, wx, wy, y1, y2, daz; + long daslope, dasqr; + long shoffs, shinc, m1, m2, *mptr1, *mptr2, *nptr1, *nptr2; + walltype *wal; + sectortype *sec; + + sec = §or[sectnum]; + + if (dastat == 0) + { + if (globalposz <= getceilzofslope((short) sectnum,globalposx,globalposy)) + return; /* Back-face culling */ + globalorientation = sec->ceilingstat; + globalpicnum = sec->ceilingpicnum; + globalshade = sec->ceilingshade; + globalpal = sec->ceilingpal; + daslope = sec->ceilingheinum; + daz = sec->ceilingz; + } + else + { + if (globalposz >= getflorzofslope((short) sectnum,globalposx,globalposy)) + return; /* Back-face culling */ + globalorientation = sec->floorstat; + globalpicnum = sec->floorpicnum; + globalshade = sec->floorshade; + globalpal = sec->floorpal; + daslope = sec->floorheinum; + daz = sec->floorz; + } + + if ((picanm[globalpicnum]&192) != 0) globalpicnum += animateoffs(globalpicnum,(short) sectnum); + setgotpic(globalpicnum); + if ((tilesizx[globalpicnum] <= 0) || (tilesizy[globalpicnum] <= 0)) return; + if (waloff[globalpicnum] == 0) loadtile(globalpicnum); + + wal = &wall[sec->wallptr]; + wx = wall[wal->point2].x - wal->x; + wy = wall[wal->point2].y - wal->y; + dasqr = krecipasm(nsqrtasm(wx*wx+wy*wy)); + i = mulscale21(daslope,dasqr); + wx *= i; wy *= i; + + globalx = -mulscale19(singlobalang,xdimenrecip); + globaly = mulscale19(cosglobalang,xdimenrecip); + globalx1 = (globalposx<<8); + globaly1 = -(globalposy<<8); + i = (dax1-halfxdimen)*xdimenrecip; + globalx2 = mulscale16(cosglobalang<<4,viewingrangerecip) - mulscale27(singlobalang,i); + globaly2 = mulscale16(singlobalang<<4,viewingrangerecip) + mulscale27(cosglobalang,i); + globalzd = (xdimscale<<9); + globalzx = -dmulscale17(wx,globaly2,-wy,globalx2) + mulscale10(1-globalhoriz,globalzd); + globalz = -dmulscale25(wx,globaly,-wy,globalx); + + if (globalorientation&64) /* Relative alignment */ + { + dx = mulscale14(wall[wal->point2].x-wal->x,dasqr); + dy = mulscale14(wall[wal->point2].y-wal->y,dasqr); + + i = nsqrtasm(daslope*daslope+16777216); + + x = globalx; y = globaly; + globalx = dmulscale16(x,dx,y,dy); + globaly = mulscale12(dmulscale16(-y,dx,x,dy),i); + + x = ((wal->x-globalposx)<<8); y = ((wal->y-globalposy)<<8); + globalx1 = dmulscale16(-x,dx,-y,dy); + globaly1 = mulscale12(dmulscale16(-y,dx,x,dy),i); + + x = globalx2; y = globaly2; + globalx2 = dmulscale16(x,dx,y,dy); + globaly2 = mulscale12(dmulscale16(-y,dx,x,dy),i); + } + if (globalorientation&0x4) + { + i = globalx; globalx = -globaly; globaly = -i; + i = globalx1; globalx1 = globaly1; globaly1 = i; + i = globalx2; globalx2 = -globaly2; globaly2 = -i; + } + if (globalorientation&0x10) { globalx1 = -globalx1, globalx2 = -globalx2, globalx = -globalx; } + if (globalorientation&0x20) { globaly1 = -globaly1, globaly2 = -globaly2, globaly = -globaly; } + + daz = dmulscale9(wx,globalposy-wal->y,-wy,globalposx-wal->x) + ((daz-globalposz)<<8); + globalx2 = mulscale20(globalx2,daz); globalx = mulscale28(globalx,daz); + globaly2 = mulscale20(globaly2,-daz); globaly = mulscale28(globaly,-daz); + + i = 8-(picsiz[globalpicnum]&15); j = 8-(picsiz[globalpicnum]>>4); + if (globalorientation&8) { i++; j++; } + globalx1 <<= (i+12); globalx2 <<= i; globalx <<= i; + globaly1 <<= (j+12); globaly2 <<= j; globaly <<= j; + + if (dastat == 0) + { + globalx1 += (((long)sec->ceilingxpanning)<<24); + globaly1 += (((long)sec->ceilingypanning)<<24); + } + else + { + globalx1 += (((long)sec->floorxpanning)<<24); + globaly1 += (((long)sec->floorypanning)<<24); + } + + asm1 = -(globalzd>>(16-BITSOFPRECISION)); + + globvis = globalvisibility; + if (sec->visibility != 0) globvis = mulscale4(globvis,(long)((unsigned char)(sec->visibility+16))); + globvis = mulscale13(globvis,daz); + globvis = mulscale16(globvis,xdimscale); + j =(long) FP_OFF(palookup[globalpal]); + + setupslopevlin(((long)(picsiz[globalpicnum]&15))+(((long)(picsiz[globalpicnum]>>4))<<8),waloff[globalpicnum],-ylookup[1]); + + l = (globalzd>>16); + + shinc = mulscale16(globalz,xdimenscale); + if (shinc > 0) shoffs = (4<<15); else shoffs = ((16380-ydimen)<<15); + if (dastat == 0) y1 = umost[dax1]; else y1 = max(umost[dax1],dplc[dax1]); + m1 = mulscale16(y1,globalzd) + (globalzx>>6); + /* Avoid visibility overflow by crossing horizon */ + if (globalzd > 0) m1 += (globalzd>>16); else m1 -= (globalzd>>16); + m2 = m1+l; + mptr1 = (long *)&slopalookup[y1+(shoffs>>15)]; mptr2 = mptr1+1; + + for(x=dax1;x<=dax2;x++) + { + if (dastat == 0) { y1 = umost[x]; y2 = min(dmost[x],uplc[x])-1; } + else { y1 = max(umost[x],dplc[x]); y2 = dmost[x]-1; } + if (y1 <= y2) + { + nptr1 = (long *)&slopalookup[y1+(shoffs>>15)]; + nptr2 = (long *)&slopalookup[y2+(shoffs>>15)]; + while (nptr1 <= mptr1) + { + *mptr1-- = j + (getpalookup((long)mulscale24(krecipasm(m1),globvis),globalshade)<<8); + m1 -= l; + } + while (nptr2 >= mptr2) + { + *mptr2++ = j + (getpalookup((long)mulscale24(krecipasm(m2),globvis),globalshade)<<8); + m2 += l; + } + + globalx3 = (globalx2>>10); + globaly3 = (globaly2>>10); + asm3 = mulscale16(y2,globalzd) + (globalzx>>6); + slopevlin(ylookup[y2]+x+frameoffset,krecipasm(asm3>>3),(long)nptr2,y2-y1+1,globalx1,globaly1); + + if ((x&15) == 0) faketimerhandler(); + } + globalx2 += globalx; + globaly2 += globaly; + globalzx += globalz; + shoffs += shinc; + } +} + + +static int owallmost(short *mostbuf, long w, long z) +{ + long bad, inty, xcross, y, yinc; + long s1, s2, s3, s4, ix1, ix2, iy1, iy2, t; + + z <<= 7; + s1 = mulscale20(globaluclip,yb1[w]); s2 = mulscale20(globaluclip,yb2[w]); + s3 = mulscale20(globaldclip,yb1[w]); s4 = mulscale20(globaldclip,yb2[w]); + bad = (zs3)<<2)+((z>s4)<<3); + + ix1 = xb1[w]; iy1 = yb1[w]; + ix2 = xb2[w]; iy2 = yb2[w]; + + if ((bad&3) == 3) + { + clearbufbyte(&mostbuf[ix1],(ix2-ix1+1)*sizeof(mostbuf[0]),0L); + return(bad); + } + + if ((bad&12) == 12) + { + clearbufbyte(&mostbuf[ix1],(ix2-ix1+1)*sizeof(mostbuf[0]),ydimen+(ydimen<<16)); + return(bad); + } + + if (bad&3) + { + t = divscale30(z-s1,s2-s1); + inty = yb1[w] + mulscale30(yb2[w]-yb1[w],t); + xcross = xb1[w] + scale(mulscale30(yb2[w],t),xb2[w]-xb1[w],inty); + + if ((bad&3) == 2) + { + if (xb1[w] <= xcross) { iy2 = inty; ix2 = xcross; } + clearbufbyte(&mostbuf[xcross+1],(xb2[w]-xcross)*sizeof(mostbuf[0]),0L); + } + else + { + if (xcross <= xb2[w]) { iy1 = inty; ix1 = xcross; } + clearbufbyte(&mostbuf[xb1[w]],(xcross-xb1[w]+1)*sizeof(mostbuf[0]),0L); + } + } + + if (bad&12) + { + t = divscale30(z-s3,s4-s3); + inty = yb1[w] + mulscale30(yb2[w]-yb1[w],t); + xcross = xb1[w] + scale(mulscale30(yb2[w],t),xb2[w]-xb1[w],inty); + + if ((bad&12) == 8) + { + if (xb1[w] <= xcross) { iy2 = inty; ix2 = xcross; } + clearbufbyte(&mostbuf[xcross+1],(xb2[w]-xcross)*sizeof(mostbuf[0]),ydimen+(ydimen<<16)); + } + else + { + if (xcross <= xb2[w]) { iy1 = inty; ix1 = xcross; } + clearbufbyte(&mostbuf[xb1[w]],(xcross-xb1[w]+1)*sizeof(mostbuf[0]),ydimen+(ydimen<<16)); + } + } + + y = (scale(z,xdimenscale,iy1)<<4); + yinc = ((scale(z,xdimenscale,iy2)<<4)-y) / (ix2-ix1+1); + qinterpolatedown16short((long *)&mostbuf[ix1],ix2-ix1+1,y+(globalhoriz<<16),yinc); + + if (mostbuf[ix1] < 0) mostbuf[ix1] = 0; + if (mostbuf[ix1] > ydimen) mostbuf[ix1] = ydimen; + if (mostbuf[ix2] < 0) mostbuf[ix2] = 0; + if (mostbuf[ix2] > ydimen) mostbuf[ix2] = ydimen; + + return(bad); +} + + +static int wallmost(short *mostbuf, long w, long sectnum, char dastat) +{ + long bad, i, j, t, y, z, inty, intz, xcross, yinc, fw; + long x1, y1, z1, x2, y2, z2, xv, yv, dx, dy, dasqr, oz1, oz2; + long s1, s2, s3, s4, ix1, ix2, iy1, iy2; + + if (dastat == 0) + { + z = sector[sectnum].ceilingz-globalposz; + if ((sector[sectnum].ceilingstat&2) == 0) return(owallmost(mostbuf,w,z)); + } + else + { + z = sector[sectnum].floorz-globalposz; + if ((sector[sectnum].floorstat&2) == 0) return(owallmost(mostbuf,w,z)); + } + + i = thewall[w]; + if (i == sector[sectnum].wallptr) return(owallmost(mostbuf,w,z)); + + x1 = wall[i].x; x2 = wall[wall[i].point2].x-x1; + y1 = wall[i].y; y2 = wall[wall[i].point2].y-y1; + + fw = sector[sectnum].wallptr; i = wall[fw].point2; + dx = wall[i].x-wall[fw].x; dy = wall[i].y-wall[fw].y; + dasqr = krecipasm(nsqrtasm(dx*dx+dy*dy)); + + if (xb1[w] == 0) + { xv = cosglobalang+sinviewingrangeglobalang; yv = singlobalang-cosviewingrangeglobalang; } + else + { xv = x1-globalposx; yv = y1-globalposy; } + i = xv*(y1-globalposy)-yv*(x1-globalposx); j = yv*x2-xv*y2; + if (klabs(j) > klabs(i>>3)) i = divscale28(i,j); + if (dastat == 0) + { + t = mulscale15(sector[sectnum].ceilingheinum,dasqr); + z1 = sector[sectnum].ceilingz; + } + else + { + t = mulscale15(sector[sectnum].floorheinum,dasqr); + z1 = sector[sectnum].floorz; + } + z1 = dmulscale24(dx*t,mulscale20(y2,i)+((y1-wall[fw].y)<<8), + -dy*t,mulscale20(x2,i)+((x1-wall[fw].x)<<8))+((z1-globalposz)<<7); + + + if (xb2[w] == xdimen-1) + { xv = cosglobalang-sinviewingrangeglobalang; yv = singlobalang+cosviewingrangeglobalang; } + else + { xv = (x2+x1)-globalposx; yv = (y2+y1)-globalposy; } + i = xv*(y1-globalposy)-yv*(x1-globalposx); j = yv*x2-xv*y2; + if (klabs(j) > klabs(i>>3)) i = divscale28(i,j); + if (dastat == 0) + { + t = mulscale15(sector[sectnum].ceilingheinum,dasqr); + z2 = sector[sectnum].ceilingz; + } + else + { + t = mulscale15(sector[sectnum].floorheinum,dasqr); + z2 = sector[sectnum].floorz; + } + z2 = dmulscale24(dx*t,mulscale20(y2,i)+((y1-wall[fw].y)<<8), + -dy*t,mulscale20(x2,i)+((x1-wall[fw].x)<<8))+((z2-globalposz)<<7); + + + s1 = mulscale20(globaluclip,yb1[w]); s2 = mulscale20(globaluclip,yb2[w]); + s3 = mulscale20(globaldclip,yb1[w]); s4 = mulscale20(globaldclip,yb2[w]); + bad = (z1s3)<<2)+((z2>s4)<<3); + + ix1 = xb1[w]; ix2 = xb2[w]; + iy1 = yb1[w]; iy2 = yb2[w]; + oz1 = z1; oz2 = z2; + + if ((bad&3) == 3) + { + clearbufbyte(&mostbuf[ix1],(ix2-ix1+1)*sizeof(mostbuf[0]),0L); + return(bad); + } + + if ((bad&12) == 12) + { + clearbufbyte(&mostbuf[ix1],(ix2-ix1+1)*sizeof(mostbuf[0]),ydimen+(ydimen<<16)); + return(bad); + } + + if (bad&3) + { + /* inty = intz / (globaluclip>>16) */ + t = divscale30(oz1-s1,s2-s1+oz1-oz2); + inty = yb1[w] + mulscale30(yb2[w]-yb1[w],t); + intz = oz1 + mulscale30(oz2-oz1,t); + xcross = xb1[w] + scale(mulscale30(yb2[w],t),xb2[w]-xb1[w],inty); + + /* + * t = divscale30((x1<<4)-xcross*yb1[w],xcross*(yb2[w]-yb1[w])-((x2-x1)<<4)); + * inty = yb1[w] + mulscale30(yb2[w]-yb1[w],t); + * intz = z1 + mulscale30(z2-z1,t); + */ + + if ((bad&3) == 2) + { + if (xb1[w] <= xcross) { z2 = intz; iy2 = inty; ix2 = xcross; } + clearbufbyte(&mostbuf[xcross+1],(xb2[w]-xcross)*sizeof(mostbuf[0]),0L); + } + else + { + if (xcross <= xb2[w]) { z1 = intz; iy1 = inty; ix1 = xcross; } + clearbufbyte(&mostbuf[xb1[w]],(xcross-xb1[w]+1)*sizeof(mostbuf[0]),0L); + } + } + + if (bad&12) + { + /* inty = intz / (globaldclip>>16) */ + t = divscale30(oz1-s3,s4-s3+oz1-oz2); + inty = yb1[w] + mulscale30(yb2[w]-yb1[w],t); + intz = oz1 + mulscale30(oz2-oz1,t); + xcross = xb1[w] + scale(mulscale30(yb2[w],t),xb2[w]-xb1[w],inty); + + /* + * t = divscale30((x1<<4)-xcross*yb1[w],xcross*(yb2[w]-yb1[w])-((x2-x1)<<4)); + * inty = yb1[w] + mulscale30(yb2[w]-yb1[w],t); + * intz = z1 + mulscale30(z2-z1,t); + */ + + if ((bad&12) == 8) + { + if (xb1[w] <= xcross) { z2 = intz; iy2 = inty; ix2 = xcross; } + clearbufbyte(&mostbuf[xcross+1],(xb2[w]-xcross)*sizeof(mostbuf[0]),ydimen+(ydimen<<16)); + } + else + { + if (xcross <= xb2[w]) { z1 = intz; iy1 = inty; ix1 = xcross; } + clearbufbyte(&mostbuf[xb1[w]],(xcross-xb1[w]+1)*sizeof(mostbuf[0]),ydimen+(ydimen<<16)); + } + } + + y = (scale(z1,xdimenscale,iy1)<<4); + yinc = ((scale(z2,xdimenscale,iy2)<<4)-y) / (ix2-ix1+1); + qinterpolatedown16short((long *)&mostbuf[ix1],ix2-ix1+1,y+(globalhoriz<<16),yinc); + + if (mostbuf[ix1] < 0) mostbuf[ix1] = 0; + if (mostbuf[ix1] > ydimen) mostbuf[ix1] = ydimen; + if (mostbuf[ix2] < 0) mostbuf[ix2] = 0; + if (mostbuf[ix2] > ydimen) mostbuf[ix2] = ydimen; + + return(bad); +} + + +static void drawalls(long bunch) +{ + sectortype *sec, *nextsec; + walltype *wal; + long i, x, x1, x2, cz[5], fz[5]; + long z, wallnum, sectnum, nextsectnum; + long startsmostwallcnt, startsmostcnt, gotswall; + char andwstat1, andwstat2; + + z = bunchfirst[bunch]; + sectnum = thesector[z]; sec = §or[sectnum]; + + andwstat1 = 0xff; andwstat2 = 0xff; + for(;z>=0;z=p2[z]) /* uplc/dplc calculation */ + { + andwstat1 &= wallmost(uplc,z,sectnum,(char)0); + andwstat2 &= wallmost(dplc,z,sectnum,(char)1); + } + + if ((andwstat1&3) != 3) /* draw ceilings */ + { + if ((sec->ceilingstat&3) == 2) + grouscan(xb1[bunchfirst[bunch]],xb2[bunchlast[bunch]],sectnum,0); + else if ((sec->ceilingstat&1) == 0) + ceilscan(xb1[bunchfirst[bunch]],xb2[bunchlast[bunch]],sectnum); + else + parascan(xb1[bunchfirst[bunch]],xb2[bunchlast[bunch]],sectnum,0,bunch); + } + if ((andwstat2&12) != 12) /* draw floors */ + { + if ((sec->floorstat&3) == 2) + grouscan(xb1[bunchfirst[bunch]],xb2[bunchlast[bunch]],sectnum,1); + else if ((sec->floorstat&1) == 0) + florscan(xb1[bunchfirst[bunch]],xb2[bunchlast[bunch]],sectnum); + else + parascan(xb1[bunchfirst[bunch]],xb2[bunchlast[bunch]],sectnum,1,bunch); + } + + /* DRAW WALLS SECTION! */ + for(z=bunchfirst[bunch];z>=0;z=p2[z]) + { + x1 = xb1[z]; x2 = xb2[z]; + if (umost[x2] >= dmost[x2]) + { + for(x=x1;x= x2) + { + smostwall[smostwallcnt] = z; + smostwalltype[smostwallcnt] = 0; + smostwallcnt++; + continue; + } + } + + wallnum = thewall[z]; wal = &wall[wallnum]; + nextsectnum = wal->nextsector; nextsec = §or[nextsectnum]; + + gotswall = 0; + + startsmostwallcnt = smostwallcnt; + startsmostcnt = smostcnt; + + if ((searchit == 2) && (searchx >= x1) && (searchx <= x2)) + { + if (searchy <= uplc[searchx]) /* ceiling */ + { + searchsector = sectnum; searchwall = wallnum; + searchstat = 1; searchit = 1; + } + else if (searchy >= dplc[searchx]) /* floor */ + { + searchsector = sectnum; searchwall = wallnum; + searchstat = 2; searchit = 1; + } + } + + if (nextsectnum >= 0) + { + getzsofslope((short)sectnum,wal->x,wal->y,&cz[0],&fz[0]); + getzsofslope((short)sectnum,wall[wal->point2].x,wall[wal->point2].y,&cz[1],&fz[1]); + getzsofslope((short)nextsectnum,wal->x,wal->y,&cz[2],&fz[2]); + getzsofslope((short)nextsectnum,wall[wal->point2].x,wall[wal->point2].y,&cz[3],&fz[3]); + getzsofslope((short)nextsectnum,globalposx,globalposy,&cz[4],&fz[4]); + + if ((wal->cstat&48) == 16) maskwall[maskwallcnt++] = z; + + if (((sec->ceilingstat&1) == 0) || ((nextsec->ceilingstat&1) == 0)) + { + if ((cz[2] <= cz[0]) && (cz[3] <= cz[1])) + { + if (globparaceilclip) + for(x=x1;x<=x2;x++) + if (uplc[x] > umost[x]) + if (umost[x] <= dmost[x]) + { + umost[x] = uplc[x]; + if (umost[x] > dmost[x]) numhits--; + } + } + else + { + wallmost(dwall,z,nextsectnum,(char)0); + if ((cz[2] > fz[0]) || (cz[3] > fz[1])) + for(i=x1;i<=x2;i++) if (dwall[i] > dplc[i]) dwall[i] = dplc[i]; + + if ((searchit == 2) && (searchx >= x1) && (searchx <= x2)) + if (searchy <= dwall[searchx]) /* wall */ + { + searchsector = sectnum; searchwall = wallnum; + searchstat = 0; searchit = 1; + } + + globalorientation = (long)wal->cstat; + globalpicnum = wal->picnum; + if ((unsigned)globalpicnum >= (unsigned)MAXTILES) globalpicnum = 0; + globalxpanning = (long)wal->xpanning; + globalypanning = (long)wal->ypanning; + globalshiftval = (picsiz[globalpicnum]>>4); + if (pow2long[globalshiftval] != tilesizy[globalpicnum]) globalshiftval++; + globalshiftval = 32-globalshiftval; + if (picanm[globalpicnum]&192) globalpicnum += animateoffs(globalpicnum,(short)(wallnum+16384)); + globalshade = (long)wal->shade; + globvis = globalvisibility; + if (sec->visibility != 0) globvis = mulscale4(globvis,(long)((unsigned char)(sec->visibility+16))); + globalpal = (long)wal->pal; + globalyscale = (wal->yrepeat<<(globalshiftval-19)); + if ((globalorientation&4) == 0) + globalzd = (((globalposz-nextsec->ceilingz)*globalyscale)<<8); + else + globalzd = (((globalposz-sec->ceilingz)*globalyscale)<<8); + globalzd += (globalypanning<<24); + if (globalorientation&256) globalyscale = -globalyscale, globalzd = -globalzd; + + if (gotswall == 0) { gotswall = 1; prepwall(z,wal); } + wallscan(x1,x2,uplc,dwall,swall,lwall); + + if ((cz[2] >= cz[0]) && (cz[3] >= cz[1])) + { + for(x=x1;x<=x2;x++) + if (dwall[x] > umost[x]) + if (umost[x] <= dmost[x]) + { + umost[x] = dwall[x]; + if (umost[x] > dmost[x]) numhits--; + } + } + else + { + for(x=x1;x<=x2;x++) + if (umost[x] <= dmost[x]) + { + i = max(uplc[x],dwall[x]); + if (i > umost[x]) + { + umost[x] = i; + if (umost[x] > dmost[x]) numhits--; + } + } + } + } + if ((cz[2] < cz[0]) || (cz[3] < cz[1]) || (globalposz < cz[4])) + { + i = x2-x1+1; + if (smostcnt+i < MAXYSAVES) + { + smoststart[smostwallcnt] = smostcnt; + smostwall[smostwallcnt] = z; + smostwalltype[smostwallcnt] = 1; /* 1 for umost */ + smostwallcnt++; + copybufbyte((long *)&umost[x1],(long *)&smost[smostcnt],i*sizeof(smost[0])); + smostcnt += i; + } + } + } + if (((sec->floorstat&1) == 0) || ((nextsec->floorstat&1) == 0)) + { + if ((fz[2] >= fz[0]) && (fz[3] >= fz[1])) + { + if (globparaflorclip) + for(x=x1;x<=x2;x++) + if (dplc[x] < dmost[x]) + if (umost[x] <= dmost[x]) + { + dmost[x] = dplc[x]; + if (umost[x] > dmost[x]) numhits--; + } + } + else + { + wallmost(uwall,z,nextsectnum,(char)1); + if ((fz[2] < cz[0]) || (fz[3] < cz[1])) + for(i=x1;i<=x2;i++) if (uwall[i] < uplc[i]) uwall[i] = uplc[i]; + + if ((searchit == 2) && (searchx >= x1) && (searchx <= x2)) + if (searchy >= uwall[searchx]) /* wall */ + { + searchsector = sectnum; searchwall = wallnum; + if ((wal->cstat&2) > 0) searchwall = wal->nextwall; + searchstat = 0; searchit = 1; + } + + if ((wal->cstat&2) > 0) + { + wallnum = wal->nextwall; wal = &wall[wallnum]; + globalorientation = (long)wal->cstat; + globalpicnum = wal->picnum; + if ((unsigned)globalpicnum >= (unsigned)MAXTILES) globalpicnum = 0; + globalxpanning = (long)wal->xpanning; + globalypanning = (long)wal->ypanning; + if (picanm[globalpicnum]&192) globalpicnum += animateoffs(globalpicnum,(short)(wallnum+16384)); + globalshade = (long)wal->shade; + globalpal = (long)wal->pal; + wallnum = thewall[z]; wal = &wall[wallnum]; + } + else + { + globalorientation = (long)wal->cstat; + globalpicnum = wal->picnum; + if ((unsigned)globalpicnum >= (unsigned)MAXTILES) globalpicnum = 0; + globalxpanning = (long)wal->xpanning; + globalypanning = (long)wal->ypanning; + if (picanm[globalpicnum]&192) globalpicnum += animateoffs(globalpicnum,(short)(wallnum+16384)); + globalshade = (long)wal->shade; + globalpal = (long)wal->pal; + } + globvis = globalvisibility; + if (sec->visibility != 0) globvis = mulscale4(globvis,(long)((unsigned char)(sec->visibility+16))); + globalshiftval = (picsiz[globalpicnum]>>4); + if (pow2long[globalshiftval] != tilesizy[globalpicnum]) globalshiftval++; + globalshiftval = 32-globalshiftval; + globalyscale = (wal->yrepeat<<(globalshiftval-19)); + if ((globalorientation&4) == 0) + globalzd = (((globalposz-nextsec->floorz)*globalyscale)<<8); + else + globalzd = (((globalposz-sec->ceilingz)*globalyscale)<<8); + globalzd += (globalypanning<<24); + if (globalorientation&256) globalyscale = -globalyscale, globalzd = -globalzd; + + if (gotswall == 0) { gotswall = 1; prepwall(z,wal); } + wallscan(x1,x2,uwall,dplc,swall,lwall); + + if ((fz[2] <= fz[0]) && (fz[3] <= fz[1])) + { + for(x=x1;x<=x2;x++) + if (uwall[x] < dmost[x]) + if (umost[x] <= dmost[x]) + { + dmost[x] = uwall[x]; + if (umost[x] > dmost[x]) numhits--; + } + } + else + { + for(x=x1;x<=x2;x++) + if (umost[x] <= dmost[x]) + { + i = min(dplc[x],uwall[x]); + if (i < dmost[x]) + { + dmost[x] = i; + if (umost[x] > dmost[x]) numhits--; + } + } + } + } + if ((fz[2] > fz[0]) || (fz[3] > fz[1]) || (globalposz > fz[4])) + { + i = x2-x1+1; + if (smostcnt+i < MAXYSAVES) + { + smoststart[smostwallcnt] = smostcnt; + smostwall[smostwallcnt] = z; + smostwalltype[smostwallcnt] = 2; /* 2 for dmost */ + smostwallcnt++; + copybufbyte((long *)&dmost[x1],(long *)&smost[smostcnt],i*sizeof(smost[0])); + smostcnt += i; + } + } + } + if (numhits < 0) return; + if ((!(wal->cstat&32)) && ((gotsector[nextsectnum>>3]&pow2char[nextsectnum&7]) == 0)) + { + if (umost[x2] < dmost[x2]) + scansector((short) nextsectnum); + else + { + for(x=x1;xcstat&32)) /* White/1-way wall */ + { + globalorientation = (long)wal->cstat; + if (nextsectnum < 0) globalpicnum = wal->picnum; + else globalpicnum = wal->overpicnum; + if ((unsigned)globalpicnum >= (unsigned)MAXTILES) globalpicnum = 0; + globalxpanning = (long)wal->xpanning; + globalypanning = (long)wal->ypanning; + if (picanm[globalpicnum]&192) globalpicnum += animateoffs(globalpicnum,(short)(wallnum+16384)); + globalshade = (long)wal->shade; + globvis = globalvisibility; + if (sec->visibility != 0) globvis = mulscale4(globvis,(long)((unsigned char)(sec->visibility+16))); + globalpal = (long)wal->pal; + globalshiftval = (picsiz[globalpicnum]>>4); + if (pow2long[globalshiftval] != tilesizy[globalpicnum]) globalshiftval++; + globalshiftval = 32-globalshiftval; + globalyscale = (wal->yrepeat<<(globalshiftval-19)); + if (nextsectnum >= 0) + { + if ((globalorientation&4) == 0) globalzd = globalposz-nextsec->ceilingz; + else globalzd = globalposz-sec->ceilingz; + } + else + { + if ((globalorientation&4) == 0) globalzd = globalposz-sec->ceilingz; + else globalzd = globalposz-sec->floorz; + } + globalzd = ((globalzd*globalyscale)<<8) + (globalypanning<<24); + if (globalorientation&256) globalyscale = -globalyscale, globalzd = -globalzd; + + if (gotswall == 0) { gotswall = 1; prepwall(z,wal); } + wallscan(x1,x2,uplc,dplc,swall,lwall); + + for(x=x1;x<=x2;x++) + if (umost[x] <= dmost[x]) + { umost[x] = 1; dmost[x] = 0; numhits--; } + smostwall[smostwallcnt] = z; + smostwalltype[smostwallcnt] = 0; + smostwallcnt++; + + if ((searchit == 2) && (searchx >= x1) && (searchx <= x2)) + { + searchit = 1; searchsector = sectnum; searchwall = wallnum; + if (nextsectnum < 0) searchstat = 0; else searchstat = 4; + } + } + } +} + + +static void dosetaspect(void) +{ + long i, j, k, x, xinc; + + if (xyaspect != oxyaspect) + { + oxyaspect = xyaspect; + j = xyaspect*320; + horizlookup2[horizycent-1] = divscale26(131072,j); + for(i=ydim*4-1;i>=0;i--) + if (i != (horizycent-1)) + { + horizlookup[i] = divscale28(1,i-(horizycent-1)); + horizlookup2[i] = divscale14(klabs(horizlookup[i]),j); + } + } + if ((xdimen != oxdimen) || (viewingrange != oviewingrange)) + { + oxdimen = xdimen; + oviewingrange = viewingrange; + xinc = mulscale32(viewingrange*320,xdimenrecip); + x = (640<<16)-mulscale1(xinc,xdimen); + for(i=0;i>16); x += xinc; + if (j != 0) j = mulscale16((long)radarang[k+1]-(long)radarang[k],j); + radarang2[i] = (short)(((long)radarang[k]+j)>>6); + } +#ifdef SUPERBUILD + for(i=1;i<16384;i++) distrecip[i] = divscale20(xdimen,i); + nytooclose = xdimen*2100; + nytoofar = 16384*16384-1048576; +#endif + } +} + + +int wallfront(long l1, long l2) +{ + walltype *wal; + long x11, y11, x21, y21, x12, y12, x22, y22, dx, dy, t1, t2; + + wal = &wall[thewall[l1]]; x11 = wal->x; y11 = wal->y; + wal = &wall[wal->point2]; x21 = wal->x; y21 = wal->y; + wal = &wall[thewall[l2]]; x12 = wal->x; y12 = wal->y; + wal = &wall[wal->point2]; x22 = wal->x; y22 = wal->y; + + dx = x21-x11; dy = y21-y11; + t1 = dmulscale2(x12-x11,dy,-dx,y12-y11); /* p1(l2) vs. l1 */ + t2 = dmulscale2(x22-x11,dy,-dx,y22-y11); /* p2(l2) vs. l1 */ + if (t1 == 0) { t1 = t2; if (t1 == 0) return(-1); } + if (t2 == 0) t2 = t1; + if ((t1^t2) >= 0) + { + t2 = dmulscale2(globalposx-x11,dy,-dx,globalposy-y11); /* pos vs. l1 */ + return((t2^t1) >= 0); + } + + dx = x22-x12; dy = y22-y12; + t1 = dmulscale2(x11-x12,dy,-dx,y11-y12); /* p1(l1) vs. l2 */ + t2 = dmulscale2(x21-x12,dy,-dx,y21-y12); /* p2(l1) vs. l2 */ + if (t1 == 0) { t1 = t2; if (t1 == 0) return(-1); } + if (t2 == 0) t2 = t1; + if ((t1^t2) >= 0) + { + t2 = dmulscale2(globalposx-x12,dy,-dx,globalposy-y12); /* pos vs. l2 */ + return((t2^t1) < 0); + } + return(-2); +} + + +static int bunchfront(long b1, long b2) +{ + long x1b1, x2b1, x1b2, x2b2, b1f, b2f, i; + + b1f = bunchfirst[b1]; x1b1 = xb1[b1f]; x2b2 = xb2[bunchlast[b2]]+1; + if (x1b1 >= x2b2) return(-1); + b2f = bunchfirst[b2]; x1b2 = xb1[b2f]; x2b1 = xb2[bunchlast[b1]]+1; + if (x1b2 >= x2b1) return(-1); + + if (x1b1 >= x1b2) + { + for(i=b2f;xb2[i]>1); + globaluclip = (0-globalhoriz)*xdimscale; + globaldclip = (ydimen-globalhoriz)*xdimscale; + + i = mulscale16(xdimenscale,viewingrangerecip); + globalpisibility = mulscale16(parallaxvisibility,i); + globalvisibility = mulscale16(visibility,i); + globalhisibility = mulscale16(globalvisibility,xyaspect); + globalcisibility = mulscale8(globalhisibility,320); + + globalcursectnum = dacursectnum; + totalclocklock = totalclock; + + cosglobalang = sintable[(globalang+512)&2047]; + singlobalang = sintable[globalang&2047]; + cosviewingrangeglobalang = mulscale16(cosglobalang,viewingrange); + sinviewingrangeglobalang = mulscale16(singlobalang,viewingrange); + + if ((stereomode != 0) || (vidoption == 6)) + { + if (stereopixelwidth != ostereopixelwidth) + { + ostereopixelwidth = stereopixelwidth; + xdimen = (windowx2-windowx1+1)+(stereopixelwidth<<1); halfxdimen = (xdimen>>1); + xdimenrecip = divscale32(1L,xdimen); + setaspect((long)divscale16(xdimen,windowx2-windowx1+1),yxaspect); + } + + if ((!(activepage&1)) ^ inpreparemirror) + { + for(i=windowx1;i>3),0L); + + shortptr1 = (short *)&startumost[windowx1]; + shortptr2 = (short *)&startdmost[windowx1]; + i = xdimen-1; + do + { + umost[i] = shortptr1[i]-windowy1; + dmost[i] = shortptr2[i]-windowy1; + i--; + } while (i != 0); + umost[0] = shortptr1[0]-windowy1; + dmost[0] = shortptr2[0]-windowy1; + +/* + * every cycle counts...and the CRC gets checked at the start, so this only + * would trigger only if they've changed it in memory after loading (and what + * would anyone do that for on purpose?), or if they've just defeated the + * first CRC check...but if they've hacked the binary/source in that way, + * then they'll just take this check out, too. In short, it ain't worth it. + * + * --ryan. + */ +#if 0 + if (smostwallcnt < 0) + if (getkensmessagecrc(FP_OFF(kensmessage)) != 0x56c764d4) + { setvmode(0x3); printf("Nice try.\n"); exit(0); } +#endif + + numhits = xdimen; numscans = 0; numbunches = 0; + maskwallcnt = 0; smostwallcnt = 0; smostcnt = 0; spritesortcnt = 0; + + if (globalcursectnum >= MAXSECTORS) + globalcursectnum -= MAXSECTORS; + else + { + i = globalcursectnum; + updatesector(globalposx,globalposy,&globalcursectnum); + if (globalcursectnum < 0) globalcursectnum = i; + } + + globparaceilclip = 1; + globparaflorclip = 1; + getzsofslope(globalcursectnum,globalposx,globalposy,&cz,&fz); + if (globalposz < cz) globparaceilclip = 0; + if (globalposz > fz) globparaflorclip = 0; + + scansector(globalcursectnum); + + if (inpreparemirror) + { + inpreparemirror = 0; + mirrorsx1 = xdimen-1; mirrorsx2 = 0; + for(i=numscans-1;i>=0;i--) + { + if (wall[thewall[i]].nextsector < 0) continue; + if (xb1[i] < mirrorsx1) mirrorsx1 = xb1[i]; + if (xb2[i] > mirrorsx2) mirrorsx2 = xb2[i]; + } + + if (stereomode) + { + mirrorsx1 += (stereopixelwidth<<1); + mirrorsx2 += (stereopixelwidth<<1); + } + + for(i=0;i 0) && (numhits > 0)) + { + clearbuf(&tempbuf[0],(long)((numbunches+3)>>2),0L); + tempbuf[0] = 1; + + closest = 0; /* Almost works, but not quite :( */ + for(i=1;i=0;z=p2[z]) + show2dwall[thewall[z]>>3] |= pow2char[thewall[z]&7]; + } + + numbunches--; + bunchfirst[closest] = bunchfirst[numbunches]; + bunchlast[closest] = bunchlast[numbunches]; + } +} + + +static int spritewallfront (spritetype *s, long w) +{ + walltype *wal; + long x1, y1; + + wal = &wall[w]; x1 = wal->x; y1 = wal->y; + wal = &wall[wal->point2]; + return (dmulscale32(wal->x-x1,s->y-y1,-(s->x-x1),wal->y-y1) >= 0); +} + + +static void transmaskvline (long x) +{ + long vplc, vinc, p, i, palookupoffs, bufplc; + short y1v, y2v; + + if ((x < 0) || (x >= xdimen)) return; + + y1v = max(uwall[x],startumost[x+windowx1]-windowy1); + y2v = min(dwall[x],startdmost[x+windowx1]-windowy1); + y2v--; + if (y2v < y1v) return; + + palookupoffs = (long)FP_OFF(palookup[globalpal]) + (getpalookup((long)mulscale16(swall[x],globvis),globalshade)<<8); + + vinc = swall[x]*globalyscale; + vplc = globalzd + vinc*(y1v-globalhoriz+1); + + i = lwall[x]+globalxpanning; + if (i >= tilesizx[globalpicnum]) i %= tilesizx[globalpicnum]; + bufplc = waloff[globalpicnum]+i*tilesizy[globalpicnum]; + + p = ylookup[y1v]+x+frameoffset; + + tvlineasm1(vinc,palookupoffs,y2v-y1v,vplc,bufplc,p); + + transarea += y2v-y1v; +} + +static void transmaskvline2 (long x) +{ + long i, y1, y2, x2; + short y1ve[2], y2ve[2]; + + if ((x < 0) || (x >= xdimen)) return; + if (x == xdimen-1) { transmaskvline(x); return; } + + x2 = x+1; + + y1ve[0] = max(uwall[x],startumost[x+windowx1]-windowy1); + y2ve[0] = min(dwall[x],startdmost[x+windowx1]-windowy1)-1; + if (y2ve[0] < y1ve[0]) { transmaskvline(x2); return; } + y1ve[1] = max(uwall[x2],startumost[x2+windowx1]-windowy1); + y2ve[1] = min(dwall[x2],startdmost[x2+windowx1]-windowy1)-1; + if (y2ve[1] < y1ve[1]) { transmaskvline(x); return; } + + palookupoffse[0] = (long)FP_OFF(palookup[globalpal]) + (getpalookup((long)mulscale16(swall[x],globvis),globalshade)<<8); + palookupoffse[1] = (long)FP_OFF(palookup[globalpal]) + (getpalookup((long)mulscale16(swall[x2],globvis),globalshade)<<8); + + setuptvlineasm2(globalshiftval,palookupoffse[0],palookupoffse[1]); + + vince[0] = swall[x]*globalyscale; + vince[1] = swall[x2]*globalyscale; + vplce[0] = globalzd + vince[0]*(y1ve[0]-globalhoriz+1); + vplce[1] = globalzd + vince[1]*(y1ve[1]-globalhoriz+1); + + i = lwall[x] + globalxpanning; + if (i >= tilesizx[globalpicnum]) i %= tilesizx[globalpicnum]; + bufplce[0] = waloff[globalpicnum]+i*tilesizy[globalpicnum]; + + i = lwall[x2] + globalxpanning; + if (i >= tilesizx[globalpicnum]) i %= tilesizx[globalpicnum]; + bufplce[1] = waloff[globalpicnum]+i*tilesizy[globalpicnum]; + + y1 = max(y1ve[0],y1ve[1]); + y2 = min(y2ve[0],y2ve[1]); + + i = x+frameoffset; + + if (y1ve[0] != y1ve[1]) + { + if (y1ve[0] < y1) + vplce[0] = tvlineasm1(vince[0],palookupoffse[0],y1-y1ve[0]-1,vplce[0],bufplce[0],ylookup[y1ve[0]]+i); + else + vplce[1] = tvlineasm1(vince[1],palookupoffse[1],y1-y1ve[1]-1,vplce[1],bufplce[1],ylookup[y1ve[1]]+i+1); + } + + if (y2 > y1) + { + asm1 = vince[1]; + asm2 = ylookup[y2]+i+1; + tvlineasm2(vplce[1],vince[0],bufplce[0],bufplce[1],vplce[0],ylookup[y1]+i); + transarea += ((y2-y1)<<1); + } + else + { + asm1 = vplce[0]; + asm2 = vplce[1]; + } + + if (y2ve[0] > y2ve[1]) + tvlineasm1(vince[0],palookupoffse[0],y2ve[0]-y2-1,asm1,bufplce[0],ylookup[y2+1]+i); + else if (y2ve[0] < y2ve[1]) + tvlineasm1(vince[1],palookupoffse[1],y2ve[1]-y2-1,asm2,bufplce[1],ylookup[y2+1]+i+1); + + faketimerhandler(); +} + +static void transmaskwallscan(long x1, long x2) +{ + long x; + + setgotpic(globalpicnum); + if ((tilesizx[globalpicnum] <= 0) || (tilesizy[globalpicnum] <= 0)) return; + + if (waloff[globalpicnum] == 0) loadtile(globalpicnum); + + setuptvlineasm(globalshiftval); + + x = x1; + while ((startumost[x+windowx1] > startdmost[x+windowx1]) && (x <= x2)) x++; + if ((x <= x2) && (x&1)) transmaskvline(x), x++; + while (x < x2) transmaskvline2(x), x += 2; + while (x <= x2) transmaskvline(x), x++; + faketimerhandler(); +} + + +int loadboard(char *filename, long *daposx, long *daposy, + long *daposz, short *daang, short *dacursectnum) +{ + int x; + short fil, i, numsprites; + sectortype *sect; + spritetype *s; + walltype *w; + + x = 0; + + i = strlen(filename)-1; + if (filename[i] == 255) { filename[i] = 0; i = 1; } else i = 0; + if ((fil = kopen4load(filename,(char) i)) == -1) + { mapversion = 7L; return(-1); } + + kread32(fil,&mapversion); + if (mapversion != 7L) return(-1); + + initspritelists(); + + clearbuf(&show2dsector[0],(long)((MAXSECTORS+3)>>5),0L); + clearbuf(&show2dsprite[0],(long)((MAXSPRITES+3)>>5),0L); + clearbuf(&show2dwall[0],(long)((MAXWALLS+3)>>5),0L); + + kread32(fil,daposx); + kread32(fil,daposy); + kread32(fil,daposz); + kread16(fil,daang); + kread16(fil,dacursectnum); + kread16(fil,&numsectors); + + for (x = 0, sect = §or[0]; x < numsectors; x++, sect++) + { + kread16(fil,§->wallptr); + kread16(fil,§->wallnum); + kread32(fil,§->ceilingz); + kread32(fil,§->floorz); + kread16(fil,§->ceilingstat); + kread16(fil,§->floorstat); + kread16(fil,§->ceilingpicnum); + kread16(fil,§->ceilingheinum); + kread8(fil,§->ceilingshade); + kread8(fil,§->ceilingpal); + kread8(fil,§->ceilingxpanning); + kread8(fil,§->ceilingypanning); + kread16(fil,§->floorpicnum); + kread16(fil,§->floorheinum); + kread8(fil,§->floorshade); + kread8(fil,§->floorpal); + kread8(fil,§->floorxpanning); + kread8(fil,§->floorypanning); + kread8(fil,§->visibility); + kread8(fil,§->filler); + kread16(fil,§->lotag); + kread16(fil,§->hitag); + kread16(fil,§->extra); + } + + kread16(fil,&numwalls); + for (x = 0, w = &wall[0]; x < numwalls; x++, w++) + { + kread32(fil,&w->x); + kread32(fil,&w->y); + kread16(fil,&w->point2); + kread16(fil,&w->nextwall); + kread16(fil,&w->nextsector); + kread16(fil,&w->cstat); + kread16(fil,&w->picnum); + kread16(fil,&w->overpicnum); + kread8(fil,&w->shade); + kread8(fil,&w->pal); + kread8(fil,&w->xrepeat); + kread8(fil,&w->yrepeat); + kread8(fil,&w->xpanning); + kread8(fil,&w->ypanning); + kread16(fil,&w->lotag); + kread16(fil,&w->hitag); + kread16(fil,&w->extra); + } + + kread16(fil,&numsprites); + for (x = 0, s = &sprite[0]; x < numsprites; x++, s++) + { + kread32(fil,&s->x); + kread32(fil,&s->y); + kread32(fil,&s->z); + kread16(fil,&s->cstat); + kread16(fil,&s->picnum); + kread8(fil,&s->shade); + kread8(fil,&s->pal); + kread8(fil,&s->clipdist); + kread8(fil,&s->filler); + kread8(fil,&s->xrepeat); + kread8(fil,&s->yrepeat); + kread8(fil,&s->xoffset); + kread8(fil,&s->yoffset); + kread16(fil,&s->sectnum); + kread16(fil,&s->statnum); + kread16(fil,&s->ang); + kread16(fil,&s->owner); + kread16(fil,&s->xvel); + kread16(fil,&s->yvel); + kread16(fil,&s->zvel); + kread16(fil,&s->lotag); + kread16(fil,&s->hitag); + kread16(fil,&s->extra); + } + + + for(i=0;iwallptr); + write16(fil,sect->wallnum); + write32(fil,sect->ceilingz); + write32(fil,sect->floorz); + write16(fil,sect->ceilingstat); + write16(fil,sect->floorstat); + write16(fil,sect->ceilingpicnum); + write16(fil,sect->ceilingheinum); + write8(fil,sect->ceilingshade); + write8(fil,sect->ceilingpal); + write8(fil,sect->ceilingxpanning); + write8(fil,sect->ceilingypanning); + write16(fil,sect->floorpicnum); + write16(fil,sect->floorheinum); + write8(fil,sect->floorshade); + write8(fil,sect->floorpal); + write8(fil,sect->floorxpanning); + write8(fil,sect->floorypanning); + write8(fil,sect->visibility); + write8(fil,sect->filler); + write16(fil,sect->lotag); + write16(fil,sect->hitag); + write16(fil,sect->extra); + } + + write16(fil,numwalls); + for (x = 0, w = &wall[0]; x < numwalls; x++, w++) + { + write32(fil,w->x); + write32(fil,w->y); + write16(fil,w->point2); + write16(fil,w->nextwall); + write16(fil,w->nextsector); + write16(fil,w->cstat); + write16(fil,w->picnum); + write16(fil,w->overpicnum); + write8(fil,w->shade); + write8(fil,w->pal); + write8(fil,w->xrepeat); + write8(fil,w->yrepeat); + write8(fil,w->xpanning); + write8(fil,w->ypanning); + write16(fil,w->lotag); + write16(fil,w->hitag); + write16(fil,w->extra); + } + + numsprites = 0; + for(j=0;jx); + write32(fil,s->y); + write32(fil,s->z); + write16(fil,s->cstat); + write16(fil,s->picnum); + write8(fil,s->shade); + write8(fil,s->pal); + write8(fil,s->clipdist); + write8(fil,s->filler); + write8(fil,s->xrepeat); + write8(fil,s->yrepeat); + write8(fil,s->xoffset); + write8(fil,s->yoffset); + write16(fil,s->sectnum); + write16(fil,s->statnum); + write16(fil,s->ang); + write16(fil,s->owner); + write16(fil,s->xvel); + write16(fil,s->yvel); + write16(fil,s->zvel); + write16(fil,s->lotag); + write16(fil,s->hitag); + write16(fil,s->extra); + + i = nextspritestat[i]; + } + } + + close(fil); + return(0); +} + + +static void initksqrt(void) +{ + long i, j, k; + + j = 1; k = 0; + for(i=0;i<4096;i++) + { + if (i >= j) { j <<= 2; k++; } + sqrtable[i] = (unsigned short)(msqrtasm((i<<18)+131072)<<1); + shlookup[i] = (k<<1)+((10-k)<<8); + if (i < 256) shlookup[i+4096] = ((k+6)<<1)+((10-(k+6))<<8); + } +} + + +static void loadtables(void) +{ + long i, fil; + + if (tablesloaded == 0) + { + initksqrt(); + + for(i=0;i<2048;i++) reciptable[i] = divscale30(2048L,i+2048); + + if ((fil = kopen4load("tables.dat",0)) != -1) + { + for (i = 0; i < 2048; i++) + kread16(fil,&sintable[i]); + + for (i = 0; i < 640; i++) + kread16(fil,&radarang[i]); + + for(i=0;i<640;i++) radarang[1279-i] = -radarang[i]; + kread(fil,textfont,1024); + kread(fil,smalltextfont,1024); + kread(fil,britable,1024); + kclose(fil); + } + tablesloaded = 1; + } +} + + +static void initfastcolorlookup(long rscale, long gscale, long bscale) +{ + long i, j, x, y, z; + char *pal1; + + j = 0; + for(i=64;i>=0;i--) + { + /*j = (i-64)*(i-64);*/ + rdist[i] = rdist[128-i] = j*rscale; + gdist[i] = gdist[128-i] = j*gscale; + bdist[i] = bdist[128-i] = j*bscale; + j += 129-(i<<1); + } + + clearbufbyte((void *)FP_OFF(colhere),sizeof(colhere),0L); + clearbufbyte((void *)FP_OFF(colhead),sizeof(colhead),0L); + + pal1 = (char *)&palette[768-3]; + for(i=255;i>=0;i--,pal1-=3) + { + j = (pal1[0]>>3)*FASTPALGRIDSIZ*FASTPALGRIDSIZ+(pal1[1]>>3)*FASTPALGRIDSIZ+(pal1[2]>>3)+FASTPALGRIDSIZ*FASTPALGRIDSIZ+FASTPALGRIDSIZ+1; + if (colhere[j>>3]&pow2char[j&7]) colnext[i] = colhead[j]; else colnext[i] = -1; + colhead[j] = i; + colhere[j>>3] |= pow2char[j&7]; + } + + i = 0; + for(x=-FASTPALGRIDSIZ*FASTPALGRIDSIZ;x<=FASTPALGRIDSIZ*FASTPALGRIDSIZ;x+=FASTPALGRIDSIZ*FASTPALGRIDSIZ) + for(y=-FASTPALGRIDSIZ;y<=FASTPALGRIDSIZ;y+=FASTPALGRIDSIZ) + for(z=-1;z<=1;z++) + colscan[i++] = x+y+z; + i = colscan[13]; colscan[13] = colscan[26]; colscan[26] = i; +} + + +static void loadpalette(void) +{ + long i, j, k, dist, fil; + char *ptr; + + if (paletteloaded != 0) return; + if ((fil = kopen4load("palette.dat",0)) == -1) return; + + kread(fil,palette,768); + kread16(fil,&numpalookups); + + if ((palookup[0] = (char *)kkmalloc(numpalookups<<8)) == NULL) + allocache((long *)&palookup[0],numpalookups<<8,&permanentlock); + if ((transluc = (char *)kkmalloc(65536L)) == NULL) + allocache((long *)&transluc,65536,&permanentlock); + + globalpalwritten = palookup[0]; globalpal = 0; + setpalookupaddress(globalpalwritten); + + fixtransluscence((long)FP_OFF(transluc)); + + kread(fil,palookup[globalpal],numpalookups<<8); + + + /*kread(fil,transluc,65536);*/ + for (k = 0; k < (65536 / 4); k++) + kread32(fil, ((long *) transluc) + k); + + kclose(fil); + + initfastcolorlookup(30L,59L,11L); + + paletteloaded = 1; + + if (vidoption == 6) + { + for(k=0;k>1); + } + } +} + + + +int setgamemode(char davidoption, long daxdim, long daydim) +{ + strcpy(kensmessage,"!!!! BUILD engine&tools programmed by Ken Silverman of E.G. RI. (c) Copyright 1995 Ken Silverman. Summary: BUILD = Ken. !!!!"); + if (getkensmessagecrc(FP_OFF(kensmessage)) != 0x56c764d4) + { setvmode(0x3); printf("Nice try.\n"); exit(0); } + return(_setgamemode(davidoption, daxdim, daydim)); +} /* setgamemode */ + + +static int dommxoverlay = 1; +static int initengine_called = 0; + +void setmmxoverlay(int isenabled) +{ + if (!initengine_called) + dommxoverlay = (isenabled) ? 1 : 0; +} /* setmmxoverlay */ + + +int getmmxoverlay(void) +{ + return(dommxoverlay); +} /* getmmxoverlay */ + + +void initengine(void) +{ + long i; + +#ifdef SUPERBUILD + long j; +#endif + + initengine_called = 1; + + memset(tilesizx, '\0', sizeof (tilesizx)); + memset(tilesizy, '\0', sizeof (tilesizy)); + + if (dommxoverlay) + mmxoverlay(); + + loadtables(); + + xyaspect = -1; + + pskyoff[0] = 0; pskybits = 0; + + parallaxtype = 2; parallaxyoffs = 0L; parallaxyscale = 65536; + showinvisibility = 0; + +#ifdef SUPERBUILD + for(i=1;i<1024;i++) lowrecip[i] = ((1<<24)-1)/i; + for(i=0;i>5),0L); + clearbuf(&show2dsprite[0],(long)((MAXSPRITES+3)>>5),0L); + clearbuf(&show2dwall[0],(long)((MAXWALLS+3)>>5),0L); + automapping = 0; + + validmodecnt = 0; + + pointhighlight = -1; + linehighlight = -1; + highlightcnt = 0; + + totalclock = 0; + visibility = 512; + parallaxvisibility = 512; + + loadpalette(); +} + + +void uninitengine(void) +{ + if (transluc != NULL) { kkfree(transluc); transluc = NULL; } + if (pic != NULL) { kkfree(pic); pic = NULL; } + if (artfil != -1) kclose(artfil); + _uninitengine(); /* video driver specific. */ +} + + + /* Assume npoints=4 with polygon on &rx1,&ry1 */ +static int clippoly4(long cx1, long cy1, long cx2, long cy2) +{ + long n, nn, z, zz, x, x1, x2, y, y1, y2, t; + + nn = 0; z = 0; + do + { + zz = ((z+1)&3); + x1 = rx1[z]; x2 = rx1[zz]-x1; + + if ((cx1 <= x1) && (x1 <= cx2)) + rx2[nn] = x1, ry2[nn] = ry1[z], nn++; + + if (x2 <= 0) x = cx2; else x = cx1; + t = x-x1; + if (((t-x2)^t) < 0) + rx2[nn] = x, ry2[nn] = ry1[z]+scale(t,ry1[zz]-ry1[z],x2), nn++; + + if (x2 <= 0) x = cx1; else x = cx2; + t = x-x1; + if (((t-x2)^t) < 0) + rx2[nn] = x, ry2[nn] = ry1[z]+scale(t,ry1[zz]-ry1[z],x2), nn++; + + z = zz; + } while (z != 0); + if (nn < 3) return(0); + + n = 0; z = 0; + do + { + zz = z+1; if (zz == nn) zz = 0; + y1 = ry2[z]; y2 = ry2[zz]-y1; + + if ((cy1 <= y1) && (y1 <= cy2)) + ry1[n] = y1, rx1[n] = rx2[z], n++; + + if (y2 <= 0) y = cy2; else y = cy1; + t = y-y1; + if (((t-y2)^t) < 0) + ry1[n] = y, rx1[n] = rx2[z]+scale(t,rx2[zz]-rx2[z],y2), n++; + + if (y2 <= 0) y = cy1; else y = cy2; + t = y-y1; + if (((t-y2)^t) < 0) + ry1[n] = y, rx1[n] = rx2[z]+scale(t,rx2[zz]-rx2[z],y2), n++; + + z = zz; + } while (z != 0); + return(n); +} + + + +static void dorotatesprite (long sx, long sy, long z, short a, short picnum, + signed char dashade, unsigned char dapalnum, char dastat, long cx1, + long cy1, long cx2, long cy2) +{ + long cosang, sinang, v, nextv, dax1, dax2, oy, bx, by, ny1, ny2; + long i, x, y, x1, y1, x2, y2, gx1, gy1, p, bufplc, palookupoffs; + long xsiz, ysiz, xoff, yoff, npoints, yplc, yinc, lx, rx, xx, xend; + long xv, yv, xv2, yv2, obuffermode=0, qlinemode=0, y1ve[4], y2ve[4], u4, d4; + char bad; + + xsiz = tilesizx[picnum]; ysiz = tilesizy[picnum]; + if (dastat&16) { xoff = 0; yoff = 0; } + else + { + xoff = (long)((signed char)((picanm[picnum]>>8)&255))+(xsiz>>1); + yoff = (long)((signed char)((picanm[picnum]>>16)&255))+(ysiz>>1); + } + + if (dastat&4) yoff = ysiz-yoff; + + cosang = sintable[(a+512)&2047]; sinang = sintable[a&2047]; + + if ((dastat&2) != 0) /* Auto window size scaling */ + { + if ((dastat&8) == 0) + { + x = xdimenscale; /* = scale(xdimen,yxaspect,320); */ + if (stereomode) x = scale(windowx2-windowx1+1,yxaspect,320); + sx = ((cx1+cx2+2)<<15)+scale(sx-(320<<15),xdimen,320); + sy = ((cy1+cy2+2)<<15)+mulscale16(sy-(200<<15),x); + } + else + { + /* + * If not clipping to startmosts, & auto-scaling on, as a + * hard-coded bonus, scale to full screen instead + */ + x = scale(xdim,yxaspect,320); + sx = (xdim<<15)+32768+scale(sx-(320<<15),xdim,320); + sy = (ydim<<15)+32768+mulscale16(sy-(200<<15),x); + } + z = mulscale16(z,x); + } + + xv = mulscale14(cosang,z); + yv = mulscale14(sinang,z); + if (((dastat&2) != 0) || ((dastat&8) == 0)) /* Don't aspect unscaled perms */ + { + xv2 = mulscale16(xv,xyaspect); + yv2 = mulscale16(yv,xyaspect); + } + else + { + xv2 = xv; + yv2 = yv; + } + + ry1[0] = sy - (yv*xoff + xv*yoff); + ry1[1] = ry1[0] + yv*xsiz; + ry1[3] = ry1[0] + xv*ysiz; + ry1[2] = ry1[1]+ry1[3]-ry1[0]; + i = (cy1<<16); if ((ry1[0]i) && (ry1[1]>i) && (ry1[2]>i) && (ry1[3]>i)) return; + + rx1[0] = sx - (xv2*xoff - yv2*yoff); + rx1[1] = rx1[0] + xv2*xsiz; + rx1[3] = rx1[0] - yv2*ysiz; + rx1[2] = rx1[1]+rx1[3]-rx1[0]; + i = (cx1<<16); if ((rx1[0]i) && (rx1[1]>i) && (rx1[2]>i) && (rx1[3]>i)) return; + + gx1 = rx1[0]; gy1 = ry1[0]; /* back up these before clipping */ + + if ((npoints = clippoly4(cx1<<16,cy1<<16,(cx2+1)<<16,(cy2+1)<<16)) < 3) return; + + lx = rx1[0]; rx = rx1[0]; + + nextv = 0; + for(v=npoints-1;v>=0;v--) + { + x1 = rx1[v]; x2 = rx1[nextv]; + dax1 = (x1>>16); if (x1 < lx) lx = x1; + dax2 = (x2>>16); if (x1 > rx) rx = x1; + if (dax1 != dax2) + { + y1 = ry1[v]; y2 = ry1[nextv]; + yinc = divscale16(y2-y1,x2-x1); + if (dax2 > dax1) + { + yplc = y1 + mulscale16((dax1<<16)+65535-x1,yinc); + qinterpolatedown16short((long *)(&uplc[dax1]),dax2-dax1,yplc,yinc); + } + else + { + yplc = y2 + mulscale16((dax2<<16)+65535-x2,yinc); + qinterpolatedown16short((long *)(&dplc[dax2]),dax1-dax2,yplc,yinc); + } + } + nextv = v; + } + + if (waloff[picnum] == 0) loadtile(picnum); + setgotpic(picnum); + bufplc = waloff[picnum]; + + palookupoffs = (long) FP_OFF(palookup[dapalnum]) + (getpalookup(0L,(long)dashade)<<8); + + i = divscale32(1L,z); + xv = mulscale14(sinang,i); + yv = mulscale14(cosang,i); + if (((dastat&2) != 0) || ((dastat&8) == 0)) /* Don't aspect unscaled perms */ + { + yv2 = mulscale16(-xv,yxaspect); + xv2 = mulscale16(yv,yxaspect); + } + else + { + yv2 = -xv; + xv2 = yv; + } + + x1 = (lx>>16); x2 = (rx>>16); + + oy = 0; + x = (x1<<16)-1-gx1; y = (oy<<16)+65535-gy1; + bx = dmulscale16(x,xv2,y,xv); + by = dmulscale16(x,yv2,y,yv); + if (dastat&4) { yv = -yv; yv2 = -yv2; by = (ysiz<<16)-1-by; } + + if ((vidoption == 1) && (origbuffermode == 0)) + { + if (dastat&128) + { + obuffermode = buffermode; + buffermode = 0; + setactivepage(activepage); + } + } + else if (dastat&8) + permanentupdate = 1; + + if ((dastat&1) == 0) + { + if (((a&1023) == 0) && (ysiz <= 256)) /* vlineasm4 has 256 high limit! */ + { + if (dastat&64) setupvlineasm(24L); else setupmvlineasm(24L); + by <<= 8; yv <<= 8; yv2 <<= 8; + + palookupoffse[0] = palookupoffse[1] = palookupoffse[2] = palookupoffse[3] = palookupoffs; + vince[0] = vince[1] = vince[2] = vince[3] = yv; + + for(x=x1;x y1) y1 = startumost[x+xx]; + if (startdmost[x+xx] < y2) y2 = startdmost[x+xx]; + } + if (y2 <= y1) continue; + + by += yv*(y1-oy); oy = y1; + + bufplce[xx] = (bx>>16)*ysiz+bufplc; + vplce[xx] = by; + y1ve[xx] = y1; + y2ve[xx] = y2-1; + bad &= ~pow2char[xx]; + } + + p = x+frameplace; + + u4 = max(max(y1ve[0],y1ve[1]),max(y1ve[2],y1ve[3])); + d4 = min(min(y2ve[0],y2ve[1]),min(y2ve[2],y2ve[3])); + + if (dastat&64) + { + if ((bad != 0) || (u4 >= d4)) + { + if (!(bad&1)) prevlineasm1(vince[0],palookupoffse[0],y2ve[0]-y1ve[0],vplce[0],bufplce[0],ylookup[y1ve[0]]+p+0); + if (!(bad&2)) prevlineasm1(vince[1],palookupoffse[1],y2ve[1]-y1ve[1],vplce[1],bufplce[1],ylookup[y1ve[1]]+p+1); + if (!(bad&4)) prevlineasm1(vince[2],palookupoffse[2],y2ve[2]-y1ve[2],vplce[2],bufplce[2],ylookup[y1ve[2]]+p+2); + if (!(bad&8)) prevlineasm1(vince[3],palookupoffse[3],y2ve[3]-y1ve[3],vplce[3],bufplce[3],ylookup[y1ve[3]]+p+3); + continue; + } + + if (u4 > y1ve[0]) vplce[0] = prevlineasm1(vince[0],palookupoffse[0],u4-y1ve[0]-1,vplce[0],bufplce[0],ylookup[y1ve[0]]+p+0); + if (u4 > y1ve[1]) vplce[1] = prevlineasm1(vince[1],palookupoffse[1],u4-y1ve[1]-1,vplce[1],bufplce[1],ylookup[y1ve[1]]+p+1); + if (u4 > y1ve[2]) vplce[2] = prevlineasm1(vince[2],palookupoffse[2],u4-y1ve[2]-1,vplce[2],bufplce[2],ylookup[y1ve[2]]+p+2); + if (u4 > y1ve[3]) vplce[3] = prevlineasm1(vince[3],palookupoffse[3],u4-y1ve[3]-1,vplce[3],bufplce[3],ylookup[y1ve[3]]+p+3); + + if (d4 >= u4) vlineasm4(d4-u4+1,ylookup[u4]+p); + + i = p+ylookup[d4+1]; + if (y2ve[0] > d4) prevlineasm1(vince[0],palookupoffse[0],y2ve[0]-d4-1,vplce[0],bufplce[0],i+0); + if (y2ve[1] > d4) prevlineasm1(vince[1],palookupoffse[1],y2ve[1]-d4-1,vplce[1],bufplce[1],i+1); + if (y2ve[2] > d4) prevlineasm1(vince[2],palookupoffse[2],y2ve[2]-d4-1,vplce[2],bufplce[2],i+2); + if (y2ve[3] > d4) prevlineasm1(vince[3],palookupoffse[3],y2ve[3]-d4-1,vplce[3],bufplce[3],i+3); + } + else + { + if ((bad != 0) || (u4 >= d4)) + { + if (!(bad&1)) mvlineasm1(vince[0],palookupoffse[0],y2ve[0]-y1ve[0],vplce[0],bufplce[0],ylookup[y1ve[0]]+p+0); + if (!(bad&2)) mvlineasm1(vince[1],palookupoffse[1],y2ve[1]-y1ve[1],vplce[1],bufplce[1],ylookup[y1ve[1]]+p+1); + if (!(bad&4)) mvlineasm1(vince[2],palookupoffse[2],y2ve[2]-y1ve[2],vplce[2],bufplce[2],ylookup[y1ve[2]]+p+2); + if (!(bad&8)) mvlineasm1(vince[3],palookupoffse[3],y2ve[3]-y1ve[3],vplce[3],bufplce[3],ylookup[y1ve[3]]+p+3); + continue; + } + + if (u4 > y1ve[0]) vplce[0] = mvlineasm1(vince[0],palookupoffse[0],u4-y1ve[0]-1,vplce[0],bufplce[0],ylookup[y1ve[0]]+p+0); + if (u4 > y1ve[1]) vplce[1] = mvlineasm1(vince[1],palookupoffse[1],u4-y1ve[1]-1,vplce[1],bufplce[1],ylookup[y1ve[1]]+p+1); + if (u4 > y1ve[2]) vplce[2] = mvlineasm1(vince[2],palookupoffse[2],u4-y1ve[2]-1,vplce[2],bufplce[2],ylookup[y1ve[2]]+p+2); + if (u4 > y1ve[3]) vplce[3] = mvlineasm1(vince[3],palookupoffse[3],u4-y1ve[3]-1,vplce[3],bufplce[3],ylookup[y1ve[3]]+p+3); + + if (d4 >= u4) mvlineasm4(d4-u4+1,ylookup[u4]+p); + + i = p+ylookup[d4+1]; + if (y2ve[0] > d4) mvlineasm1(vince[0],palookupoffse[0],y2ve[0]-d4-1,vplce[0],bufplce[0],i+0); + if (y2ve[1] > d4) mvlineasm1(vince[1],palookupoffse[1],y2ve[1]-d4-1,vplce[1],bufplce[1],i+1); + if (y2ve[2] > d4) mvlineasm1(vince[2],palookupoffse[2],y2ve[2]-d4-1,vplce[2],bufplce[2],i+2); + if (y2ve[3] > d4) mvlineasm1(vince[3],palookupoffse[3],y2ve[3]-d4-1,vplce[3],bufplce[3],i+3); + } + + faketimerhandler(); + } + } + else + { + if (dastat&64) + { + if ((xv2&0x0000ffff) == 0) + { + qlinemode = 1; + setupqrhlineasm4(0L,yv2<<16,(xv2>>16)*ysiz+(yv2>>16),palookupoffs,0L,0L); + } + else + { + qlinemode = 0; + setuprhlineasm4(xv2<<16,yv2<<16,(xv2>>16)*ysiz+(yv2>>16),palookupoffs,ysiz,0L); + } + } + else + setuprmhlineasm4(xv2<<16,yv2<<16,(xv2>>16)*ysiz+(yv2>>16),palookupoffs,ysiz,0L); + + y1 = uplc[x1]; + if (((dastat&8) == 0) && (startumost[x1] > y1)) y1 = startumost[x1]; + y2 = y1; + for(x=x1;x ny1) ny1 = startumost[x]-1; + if (startdmost[x] < ny2) ny2 = startdmost[x]; + } + + if (ny1 < ny2-1) + { + if (ny1 >= y2) + { + while (y1 < y2-1) + { + y1++; if ((y1&31) == 0) faketimerhandler(); + + /* x,y1 */ + bx += xv*(y1-oy); by += yv*(y1-oy); oy = y1; + if (dastat&64) { if (qlinemode) qrhlineasm4(x-lastx[y1],(bx>>16)*ysiz+(by>>16)+bufplc,0L,0L ,by<<16,ylookup[y1]+x+frameplace); + else rhlineasm4(x-lastx[y1],(bx>>16)*ysiz+(by>>16)+bufplc,0L,bx<<16,by<<16,ylookup[y1]+x+frameplace); + } else rmhlineasm4(x-lastx[y1],(bx>>16)*ysiz+(by>>16)+bufplc,0L,bx<<16,by<<16,ylookup[y1]+x+frameplace); + } + y1 = ny1; + } + else + { + while (y1 < ny1) + { + y1++; if ((y1&31) == 0) faketimerhandler(); + + /* x,y1 */ + bx += xv*(y1-oy); by += yv*(y1-oy); oy = y1; + if (dastat&64) { if (qlinemode) qrhlineasm4(x-lastx[y1],(bx>>16)*ysiz+(by>>16)+bufplc,0L,0L ,by<<16,ylookup[y1]+x+frameplace); + else rhlineasm4(x-lastx[y1],(bx>>16)*ysiz+(by>>16)+bufplc,0L,bx<<16,by<<16,ylookup[y1]+x+frameplace); + } else rmhlineasm4(x-lastx[y1],(bx>>16)*ysiz+(by>>16)+bufplc,0L,bx<<16,by<<16,ylookup[y1]+x+frameplace); + } + while (y1 > ny1) lastx[y1--] = x; + } + while (y2 > ny2) + { + y2--; if ((y2&31) == 0) faketimerhandler(); + + /* x,y2 */ + bx += xv*(y2-oy); by += yv*(y2-oy); oy = y2; + if (dastat&64) { if (qlinemode) qrhlineasm4(x-lastx[y2],(bx>>16)*ysiz+(by>>16)+bufplc,0L,0L ,by<<16,ylookup[y2]+x+frameplace); + else rhlineasm4(x-lastx[y2],(bx>>16)*ysiz+(by>>16)+bufplc,0L,bx<<16,by<<16,ylookup[y2]+x+frameplace); + } else rmhlineasm4(x-lastx[y2],(bx>>16)*ysiz+(by>>16)+bufplc,0L,bx<<16,by<<16,ylookup[y2]+x+frameplace); + } + while (y2 < ny2) lastx[y2++] = x; + } + else + { + while (y1 < y2-1) + { + y1++; if ((y1&31) == 0) faketimerhandler(); + + /* x,y1 */ + bx += xv*(y1-oy); by += yv*(y1-oy); oy = y1; + if (dastat&64) { if (qlinemode) qrhlineasm4(x-lastx[y1],(bx>>16)*ysiz+(by>>16)+bufplc,0L,0L ,by<<16,ylookup[y1]+x+frameplace); + else rhlineasm4(x-lastx[y1],(bx>>16)*ysiz+(by>>16)+bufplc,0L,bx<<16,by<<16,ylookup[y1]+x+frameplace); + } else rmhlineasm4(x-lastx[y1],(bx>>16)*ysiz+(by>>16)+bufplc,0L,bx<<16,by<<16,ylookup[y1]+x+frameplace); + } + if (x == x2-1) { bx += xv2; by += yv2; break; } + y1 = uplc[x+1]; + if (((dastat&8) == 0) && (startumost[x+1] > y1)) y1 = startumost[x+1]; + y2 = y1; + } + bx += xv2; by += yv2; + } + while (y1 < y2-1) + { + y1++; if ((y1&31) == 0) faketimerhandler(); + + /* x2,y1 */ + bx += xv*(y1-oy); by += yv*(y1-oy); oy = y1; + if (dastat&64) { if (qlinemode) qrhlineasm4(x2-lastx[y1],(bx>>16)*ysiz+(by>>16)+bufplc,0L,0L ,by<<16,ylookup[y1]+x2+frameplace); + else rhlineasm4(x2-lastx[y1],(bx>>16)*ysiz+(by>>16)+bufplc,0L,bx<<16,by<<16,ylookup[y1]+x2+frameplace); + } else rmhlineasm4(x2-lastx[y1],(bx>>16)*ysiz+(by>>16)+bufplc,0L,bx<<16,by<<16,ylookup[y1]+x2+frameplace); + } + } + } + else + { + if ((dastat&1) == 0) + { + if (dastat&64) + setupspritevline(palookupoffs,(xv>>16)*ysiz,xv<<16,ysiz,yv,0L); + else + msetupspritevline(palookupoffs,(xv>>16)*ysiz,xv<<16,ysiz,yv,0L); + } + else + { + tsetupspritevline(palookupoffs,(xv>>16)*ysiz,xv<<16,ysiz,yv,0L); + if (dastat&32) settransreverse(); else settransnormal(); + } + for(x=x1;x y1) y1 = startumost[x]; + if (startdmost[x] < y2) y2 = startdmost[x]; + } + if (y2 <= y1) continue; + + switch(y1-oy) + { + case -1: bx -= xv; by -= yv; oy = y1; break; + case 0: break; + case 1: bx += xv; by += yv; oy = y1; break; + default: bx += xv*(y1-oy); by += yv*(y1-oy); oy = y1; break; + } + + p = ylookup[y1]+x+frameplace; + + if ((dastat&1) == 0) + { + if (dastat&64) + spritevline(0L,by<<16,y2-y1+1,bx<<16,(bx>>16)*ysiz+(by>>16)+bufplc,p); + else + mspritevline(0L,by<<16,y2-y1+1,bx<<16,(bx>>16)*ysiz+(by>>16)+bufplc,p); + } + else + { + tspritevline(0L,by<<16,y2-y1+1,bx<<16,(bx>>16)*ysiz+(by>>16)+bufplc,p); + transarea += (y2-y1); + } + faketimerhandler(); + } + } + + if ((vidoption == 1) && (dastat&128) && (origbuffermode == 0)) + { + buffermode = obuffermode; + setactivepage(activepage); + } +} + + +void nextpage(void) +{ + long i; + permfifotype *per; + /* long j,k; */ + +#if 0 + char snotbuf[32]; + j = 0; k = 0; + for(i=0;i<4096;i++) + if (waloff[i] != 0) + { + sprintf(snotbuf,"%ld-%ld",i,tilesizx[i]*tilesizy[i]); + printext256((j>>5)*40+32,(j&31)*6,walock[i]>>3,-1,snotbuf,1); + k += tilesizx[i]*tilesizy[i]; + j++; + } + sprintf(snotbuf,"Total: %ld",k); + printext256((j>>5)*40+32,(j&31)*6,31,-1,snotbuf,1); +#endif + + if (qsetmode == 200) + { + for(i=permtail;i!=permhead;i=((i+1)&(MAXPERMS-1))) + { + per = &permfifo[i]; + if ((per->pagesleft > 0) && (per->pagesleft <= numpages)) + dorotatesprite(per->sx,per->sy,per->z,per->a,per->picnum, + per->dashade,per->dapalnum,per->dastat, + per->cx1,per->cy1,per->cx2,per->cy2); + } + } /* if */ + + _nextpage(); /* video driver specific. */ + + + if (qsetmode == 200) + { + for(i=permtail;i!=permhead;i=((i+1)&(MAXPERMS-1))) + { + per = &permfifo[i]; + if (per->pagesleft >= 130) + dorotatesprite(per->sx,per->sy,per->z,per->a,per->picnum, + per->dashade,per->dapalnum,per->dastat, + per->cx1,per->cy1,per->cx2,per->cy2); + if (per->pagesleft&127) per->pagesleft--; + if (((per->pagesleft&127) == 0) && (i == permtail)) + permtail = ((permtail+1)&(MAXPERMS-1)); + } + } /* if */ + + faketimerhandler(); + + if ((totalclock >= lastageclock+8) || (totalclock < lastageclock)) + { lastageclock = totalclock; agecache(); } + + beforedrawrooms = 1; + numframes++; +} + + +void loadtile(short tilenume) +{ + char *ptr; + long i, dasiz; + + if ((unsigned)tilenume >= (unsigned)MAXTILES) return; + dasiz = tilesizx[tilenume]*tilesizy[tilenume]; + if (dasiz <= 0) return; + + i = tilefilenum[tilenume]; + if (i != artfilnum) + { + if (artfil != -1) kclose(artfil); + artfilnum = i; + artfilplc = 0L; + + artfilename[7] = (i%10)+48; + artfilename[6] = ((i/10)%10)+48; + artfilename[5] = ((i/100)%10)+48; + artfil = kopen4load(artfilename,0); + faketimerhandler(); + } + + #if BUILD_CACHEDEBUG + fprintf(stderr, "BUILDCACHE: Tile:%d\n", tilenume); + #endif + + if (waloff[tilenume] == 0) + { + walock[tilenume] = 199; + allocache(&waloff[tilenume],dasiz,(unsigned char *) &walock[tilenume]); + } + + if (artfilplc != tilefileoffs[tilenume]) + { + klseek(artfil,tilefileoffs[tilenume]-artfilplc,SEEK_CUR); + faketimerhandler(); + } + ptr = (char *)waloff[tilenume]; + kread(artfil,ptr,dasiz); + faketimerhandler(); + artfilplc = tilefileoffs[tilenume]+dasiz; +} + + +int allocatepermanenttile(short tilenume, long xsiz, long ysiz) +{ + long j, dasiz; + + if ((xsiz <= 0) || (ysiz <= 0) || ((unsigned)tilenume >= (unsigned)MAXTILES)) + return(0); + + dasiz = xsiz*ysiz; + + walock[tilenume] = 255; + allocache(&waloff[tilenume],dasiz,(unsigned char *) &walock[tilenume]); + + tilesizx[tilenume] = xsiz; + tilesizy[tilenume] = ysiz; + picanm[tilenume] = 0; + + j = 15; while ((j > 1) && (pow2long[j] > xsiz)) j--; + picsiz[tilenume] = ((char)j); + j = 15; while ((j > 1) && (pow2long[j] > ysiz)) j--; + picsiz[tilenume] += ((char)(j<<4)); + + return(waloff[tilenume]); +} + + +int loadpics(char *filename) +{ + long offscount, localtilestart, localtileend, dasiz; + short fil, i, j, k; + + strcpy(artfilename,filename); + + for(i=0;i>5),0L); + + /* try dpmi_DETERMINEMAXREALALLOC! */ + + cachesize = max(artsize,1048576); + while ((pic = (char *)kkmalloc(cachesize)) == NULL) + { + cachesize -= 65536L; + if (cachesize < 65536) return(-1); + } + initcache(((long)FP_OFF(pic)+15)&0xfffffff0,(cachesize-((-(long)FP_OFF(pic))&15))&0xfffffff0); + + for(i=0;i 1) && (pow2long[j] > tilesizx[i])) j--; + picsiz[i] = ((char)j); + j = 15; + while ((j > 1) && (pow2long[j] > tilesizy[i])) j--; + picsiz[i] += ((char)(j<<4)); + } + + artfil = -1; + artfilnum = -1; + artfilplc = 0L; + + return(0); +} + +#ifdef SUPERBUILD +void qloadkvx(long voxindex, char *filename) +{ + long i, fil, dasiz, lengcnt, lengtot; + char *ptr; + + if ((fil = kopen4load(filename,0)) == -1) return; + + lengcnt = 0; + lengtot = kfilelength(fil); + + for(i=0;i= lengtot-768) break; + } + kclose(fil); +} +#endif + + +int clipinsidebox(long x, long y, short wallnum, long walldist) +{ + walltype *wal; + long x1, y1, x2, y2, r; + + r = (walldist<<1); + wal = &wall[wallnum]; x1 = wal->x+walldist-x; y1 = wal->y+walldist-y; + wal = &wall[wal->point2]; x2 = wal->x+walldist-x; y2 = wal->y+walldist-y; + + if ((x1 < 0) && (x2 < 0)) return(0); + if ((y1 < 0) && (y2 < 0)) return(0); + if ((x1 >= r) && (x2 >= r)) return(0); + if ((y1 >= r) && (y2 >= r)) return(0); + + x2 -= x1; y2 -= y1; + if (x2*(walldist-y1) >= y2*(walldist-x1)) /* Front */ + { + if (x2 > 0) x2 *= (0-y1); else x2 *= (r-y1); + if (y2 > 0) y2 *= (r-x1); else y2 *= (0-x1); + return(x2 < y2); + } + if (x2 > 0) x2 *= (r-y1); else x2 *= (0-y1); + if (y2 > 0) y2 *= (0-x1); else y2 *= (r-x1); + return((x2 >= y2)<<1); +} + +int clipinsideboxline(long x, long y, long x1, long y1, long x2, long y2, long walldist) +{ + long r; + + r = (walldist<<1); + + x1 += walldist-x; x2 += walldist-x; + if ((x1 < 0) && (x2 < 0)) return(0); + if ((x1 >= r) && (x2 >= r)) return(0); + + y1 += walldist-y; y2 += walldist-y; + if ((y1 < 0) && (y2 < 0)) return(0); + if ((y1 >= r) && (y2 >= r)) return(0); + + x2 -= x1; y2 -= y1; + if (x2*(walldist-y1) >= y2*(walldist-x1)) /* Front */ + { + if (x2 > 0) x2 *= (0-y1); else x2 *= (r-y1); + if (y2 > 0) y2 *= (r-x1); else y2 *= (0-x1); + return(x2 < y2); + } + if (x2 > 0) x2 *= (r-y1); else x2 *= (0-y1); + if (y2 > 0) y2 *= (0-x1); else y2 *= (r-x1); + return((x2 >= y2)<<1); +} + + +void drawline256 (long x1, long y1, long x2, long y2, unsigned char col) +{ + long dx, dy, i, j, p, inc, plc, daend; + + col = palookup[0][col]; + + dx = x2-x1; dy = y2-y1; + if (dx >= 0) + { + if ((x1 >= wx2) || (x2 < wx1)) return; + if (x1 < wx1) y1 += scale(wx1-x1,dy,dx), x1 = wx1; + if (x2 > wx2) y2 += scale(wx2-x2,dy,dx), x2 = wx2; + } + else + { + if ((x2 >= wx2) || (x1 < wx1)) return; + if (x2 < wx1) y2 += scale(wx1-x2,dy,dx), x2 = wx1; + if (x1 > wx2) y1 += scale(wx2-x1,dy,dx), x1 = wx2; + } + if (dy >= 0) + { + if ((y1 >= wy2) || (y2 < wy1)) return; + if (y1 < wy1) x1 += scale(wy1-y1,dx,dy), y1 = wy1; + if (y2 > wy2) x2 += scale(wy2-y2,dx,dy), y2 = wy2; + } + else + { + if ((y2 >= wy2) || (y1 < wy1)) return; + if (y2 < wy1) x2 += scale(wy1-y2,dx,dy), y2 = wy1; + if (y1 > wy2) x1 += scale(wy2-y1,dx,dy), y1 = wy2; + } + + if (klabs(dx) >= klabs(dy)) + { + if (dx == 0) return; + if (dx < 0) + { + i = x1; x1 = x2; x2 = i; + i = y1; y1 = y2; y2 = i; + } + + inc = divscale12(dy,dx); + plc = y1+mulscale12((2047-x1)&4095,inc); + i = ((x1+2048)>>12); daend = ((x2+2048)>>12); + for(;i>12); + if ((j >= startumost[i]) && (j < startdmost[i])) + drawpixel(ylookup[j]+i+frameplace,col); + plc += inc; + } + } + else + { + if (dy < 0) + { + i = x1; x1 = x2; x2 = i; + i = y1; y1 = y2; y2 = i; + } + + inc = divscale12(dx,dy); + plc = x1+mulscale12((2047-y1)&4095,inc); + i = ((y1+2048)>>12); daend = ((y2+2048)>>12); + p = ylookup[i]+frameplace; + for(;i>12); + if ((i >= startumost[j]) && (i < startdmost[j])) + drawpixel(j+p,col); + plc += inc; p += ylookup[1]; + } + } +} + + +int inside(long x, long y, short sectnum) +{ + walltype *wal; + long i, x1, y1, x2, y2; + unsigned long cnt; + + if ((sectnum < 0) || (sectnum >= numsectors)) return(-1); + + cnt = 0; + wal = &wall[sector[sectnum].wallptr]; + i = sector[sectnum].wallnum; + do + { + y1 = wal->y-y; y2 = wall[wal->point2].y-y; + if ((y1^y2) < 0) + { + x1 = wal->x-x; x2 = wall[wal->point2].x-x; + if ((x1^x2) >= 0) cnt ^= x1; else cnt ^= (x1*y2-x2*y1)^y2; + } + wal++; i--; + } while (i); + return(cnt>>31); +} + + +int getangle(long xvect, long yvect) +{ + if ((xvect|yvect) == 0) return(0); + if (xvect == 0) return(512+((yvect<0)<<10)); + if (yvect == 0) return(((xvect<0)<<10)); + if (xvect == yvect) return(256+((xvect<0)<<10)); + if (xvect == -yvect) return(768+((xvect>0)<<10)); + if (klabs(xvect) > klabs(yvect)) + return(((radarang[640+scale(160,yvect,xvect)]>>6)+((xvect<0)<<10))&2047); + return(((radarang[640-scale(160,xvect,yvect)]>>6)+512+((yvect<0)<<10))&2047); +} + + +int ksqrt(long num) +{ + return(nsqrtasm(num)); +} + + +void copytilepiece(long tilenume1, long sx1, long sy1, long xsiz, long ysiz, + long tilenume2, long sx2, long sy2) +{ + unsigned char *ptr1, *ptr2, dat; + long xsiz1, ysiz1, xsiz2, ysiz2, i, j, x1, y1, x2, y2; + + xsiz1 = tilesizx[tilenume1]; ysiz1 = tilesizy[tilenume1]; + xsiz2 = tilesizx[tilenume2]; ysiz2 = tilesizy[tilenume2]; + if ((xsiz1 > 0) && (ysiz1 > 0) && (xsiz2 > 0) && (ysiz2 > 0)) + { + if (waloff[tilenume1] == 0) loadtile((short) tilenume1); + if (waloff[tilenume2] == 0) loadtile((short) tilenume2); + + x1 = sx1; + for(i=0;i= 0) && (y2 >= 0) && (x2 < xsiz2) && (y2 < ysiz2)) + { + ptr1 = (unsigned char *) (waloff[tilenume1] + x1*ysiz1 + y1); + ptr2 = (unsigned char *) (waloff[tilenume2] + x2*ysiz2 + y2); + dat = *ptr1; + if (dat != 255) + *ptr2 = *ptr1; + } + + y1++; if (y1 >= ysiz1) y1 = 0; + } + x1++; if (x1 >= xsiz1) x1 = 0; + } + } +} + + +static void drawmaskwall(short damaskwallcnt) +{ + long i, j, k, x, z, sectnum, z1, z2, lx, rx; + sectortype *sec, *nsec; + walltype *wal; + + z = maskwall[damaskwallcnt]; + wal = &wall[thewall[z]]; + sectnum = thesector[z]; sec = §or[sectnum]; + nsec = §or[wal->nextsector]; + z1 = max(nsec->ceilingz,sec->ceilingz); + z2 = min(nsec->floorz,sec->floorz); + + wallmost(uwall,z,sectnum,(char)0); + wallmost(uplc,z,(long)wal->nextsector,(char)0); + for(x=xb1[z];x<=xb2[z];x++) if (uplc[x] > uwall[x]) uwall[x] = uplc[x]; + wallmost(dwall,z,sectnum,(char)1); + wallmost(dplc,z,(long)wal->nextsector,(char)1); + for(x=xb1[z];x<=xb2[z];x++) if (dplc[x] < dwall[x]) dwall[x] = dplc[x]; + prepwall(z,wal); + + globalorientation = (long)wal->cstat; + globalpicnum = wal->overpicnum; + if ((unsigned)globalpicnum >= (unsigned)MAXTILES) globalpicnum = 0; + globalxpanning = (long)wal->xpanning; + globalypanning = (long)wal->ypanning; + if (picanm[globalpicnum]&192) globalpicnum += animateoffs(globalpicnum,(short)(thewall[z]+16384)); + globalshade = (long)wal->shade; + globvis = globalvisibility; + if (sec->visibility != 0) globvis = mulscale4(globvis,(long)((unsigned char)(sec->visibility+16))); + globalpal = (long)wal->pal; + globalshiftval = (picsiz[globalpicnum]>>4); + if (pow2long[globalshiftval] != tilesizy[globalpicnum]) globalshiftval++; + globalshiftval = 32-globalshiftval; + globalyscale = (wal->yrepeat<<(globalshiftval-19)); + if ((globalorientation&4) == 0) + globalzd = (((globalposz-z1)*globalyscale)<<8); + else + globalzd = (((globalposz-z2)*globalyscale)<<8); + globalzd += (globalypanning<<24); + if (globalorientation&256) globalyscale = -globalyscale, globalzd = -globalzd; + + for(i=smostwallcnt-1;i>=0;i--) + { + j = smostwall[i]; + if ((xb1[j] > xb2[z]) || (xb2[j] < xb1[z])) continue; + if (wallfront(j,z)) continue; + + lx = max(xb1[j],xb1[z]); rx = min(xb2[j],xb2[z]); + + switch(smostwalltype[i]) + { + case 0: + if (lx <= rx) + { + if ((lx == xb1[z]) && (rx == xb2[z])) return; + clearbufbyte(&dwall[lx],(rx-lx+1)*sizeof(dwall[0]),0L); + } + break; + case 1: + k = smoststart[i] - xb1[j]; + for(x=lx;x<=rx;x++) + if (smost[k+x] > uwall[x]) uwall[x] = smost[k+x]; + break; + case 2: + k = smoststart[i] - xb1[j]; + for(x=lx;x<=rx;x++) + if (smost[k+x] < dwall[x]) dwall[x] = smost[k+x]; + break; + } + } + + /* maskwall */ + if ((searchit >= 1) && (searchx >= xb1[z]) && (searchx <= xb2[z])) + if ((searchy >= uwall[searchx]) && (searchy <= dwall[searchx])) + { + searchsector = sectnum; searchwall = thewall[z]; + searchstat = 4; searchit = 1; + } + + if ((globalorientation&128) == 0) + maskwallscan(xb1[z],xb2[z],uwall,dwall,swall,lwall); + else + { + if (globalorientation&128) + { + if (globalorientation&512) settransreverse(); else settransnormal(); + } + transmaskwallscan(xb1[z],xb2[z]); + } +} + + +static void ceilspritehline (long x2, long y) +{ + long x1, v, bx, by; + + /* + * x = x1 + (x2-x1)t + (y1-y2)u ³ x = 160v + * y = y1 + (y2-y1)t + (x2-x1)u ³ y = (scrx-160)v + * z = z1 = z2 ³ z = posz + (scry-horiz)v + */ + + x1 = lastx[y]; if (x2 < x1) return; + + v = mulscale20(globalzd,horizlookup[y-globalhoriz+horizycent]); + bx = mulscale14(globalx2*x1+globalx1,v) + globalxpanning; + by = mulscale14(globaly2*x1+globaly1,v) + globalypanning; + asm1 = mulscale14(globalx2,v); + asm2 = mulscale14(globaly2,v); + + asm3 = (long)FP_OFF(palookup[globalpal]) + (getpalookup((long)mulscale28(klabs(v),globvis),globalshade)<<8); + + if ((globalorientation&2) == 0) + mhline(globalbufplc,bx,(x2-x1)<<16,0L,by,ylookup[y]+x1+frameoffset); + else + { + thline(globalbufplc,bx,(x2-x1)<<16,0L,by,ylookup[y]+x1+frameoffset); + transarea += (x2-x1); + } +} + + +static void ceilspritescan (long x1, long x2) +{ + long x, y1, y2, twall, bwall; + + y1 = uwall[x1]; y2 = y1; + for(x=x1;x<=x2;x++) + { + twall = uwall[x]-1; bwall = dwall[x]; + if (twall < bwall-1) + { + if (twall >= y2) + { + while (y1 < y2-1) ceilspritehline(x-1,++y1); + y1 = twall; + } + else + { + while (y1 < twall) ceilspritehline(x-1,++y1); + while (y1 > twall) lastx[y1--] = x; + } + while (y2 > bwall) ceilspritehline(x-1,--y2); + while (y2 < bwall) lastx[y2++] = x; + } + else + { + while (y1 < y2-1) ceilspritehline(x-1,++y1); + if (x == x2) break; + y1 = uwall[x+1]; y2 = y1; + } + } + while (y1 < y2-1) ceilspritehline(x2,++y1); + faketimerhandler(); +} + + +#ifdef SUPERBUILD +static void drawvox(long dasprx, long daspry, long dasprz, long dasprang, + long daxscale, long dayscale, unsigned char daindex, + signed char dashade, unsigned char dapal, long *daumost, long *dadmost) +{ + long i, j, k, x, y, syoff, ggxstart, ggystart, nxoff; + long cosang, sinang, sprcosang, sprsinang, backx, backy, gxinc, gyinc; + long daxsiz, daysiz, dazsiz, daxpivot, daypivot, dazpivot; + long daxscalerecip, dayscalerecip, cnt, gxstart, gystart, odayscale; + long l1, l2, slabxoffs, xyvoxoffs, *longptr; + long lx, rx, nx, ny, x1=0, y1=0, z1, x2=0, y2=0, z2, yplc, yinc=0; + long yoff, xs=0, ys=0, xe, ye, xi=0, yi=0, cbackx, cbacky, dagxinc, dagyinc; + short *shortptr; + char *voxptr, *voxend, *davoxptr, oand, oand16, oand32; + + cosang = sintable[(globalang+512)&2047]; + sinang = sintable[globalang&2047]; + sprcosang = sintable[(dasprang+512)&2047]; + sprsinang = sintable[dasprang&2047]; + + i = klabs(dmulscale6(dasprx-globalposx,cosang,daspry-globalposy,sinang)); + j = (long)(getpalookup((long)mulscale21(globvis,i),(long)dashade)<<8); + setupdrawslab(ylookup[1],(long)FP_OFF(palookup[dapal])+j); + j = 1310720; + j *= min(daxscale,dayscale); j >>= 6; /* New hacks (for sized-down voxels) */ + for(k=0;k= MAXVOXMIPS) i = MAXVOXMIPS-1; + + davoxptr = (char *)voxoff[daindex][i]; if (!davoxptr) return; + + daxscale <<= (i+8); dayscale <<= (i+8); + odayscale = dayscale; + daxscale = mulscale16(daxscale,xyaspect); + daxscale = scale(daxscale,xdimenscale,xdimen<<8); + dayscale = scale(dayscale,mulscale16(xdimenscale,viewingrangerecip),xdimen<<8); + + daxscalerecip = (1<<30)/daxscale; + dayscalerecip = (1<<30)/dayscale; + + longptr = (long *)davoxptr; + daxsiz = BUILDSWAP_INTEL32(longptr[0]); + daysiz = BUILDSWAP_INTEL32(longptr[1]); + dazsiz = BUILDSWAP_INTEL32(longptr[2]); + daxpivot = BUILDSWAP_INTEL32(longptr[3]); + daypivot = BUILDSWAP_INTEL32(longptr[4]); + dazpivot = BUILDSWAP_INTEL32(longptr[5]); + davoxptr += (6<<2); + + x = mulscale16(globalposx-dasprx,daxscalerecip); + y = mulscale16(globalposy-daspry,daxscalerecip); + backx = ((dmulscale10(x,sprcosang,y,sprsinang)+daxpivot)>>8); + backy = ((dmulscale10(y,sprcosang,x,-sprsinang)+daypivot)>>8); + cbackx = min(max(backx,0),daxsiz-1); + cbacky = min(max(backy,0),daysiz-1); + + sprcosang = mulscale14(daxscale,sprcosang); + sprsinang = mulscale14(daxscale,sprsinang); + + x = (dasprx-globalposx) - dmulscale18(daxpivot,sprcosang,daypivot,-sprsinang); + y = (daspry-globalposy) - dmulscale18(daypivot,sprcosang,daxpivot,sprsinang); + + cosang = mulscale16(cosang,dayscalerecip); + sinang = mulscale16(sinang,dayscalerecip); + + gxstart = y*cosang - x*sinang; + gystart = x*cosang + y*sinang; + gxinc = dmulscale10(sprsinang,cosang,sprcosang,-sinang); + gyinc = dmulscale10(sprcosang,cosang,sprsinang,sinang); + + x = 0; y = 0; j = max(daxsiz,daysiz); + for(i=0;i<=j;i++) + { + ggxinc[i] = x; x += gxinc; + ggyinc[i] = y; y += gyinc; + } + + if ((klabs(globalposz-dasprz)>>10) >= klabs(odayscale)) return; + syoff = divscale21(globalposz-dasprz,odayscale) + (dazpivot<<7); + yoff = ((klabs(gxinc)+klabs(gyinc))>>1); + longptr = (long *)davoxptr; + xyvoxoffs = ((daxsiz+1)<<2); + + for(cnt=0;cnt<8;cnt++) + { + switch(cnt) + { + case 0: xs = 0; ys = 0; xi = 1; yi = 1; break; + case 1: xs = daxsiz-1; ys = 0; xi = -1; yi = 1; break; + case 2: xs = 0; ys = daysiz-1; xi = 1; yi = -1; break; + case 3: xs = daxsiz-1; ys = daysiz-1; xi = -1; yi = -1; break; + case 4: xs = 0; ys = cbacky; xi = 1; yi = 2; break; + case 5: xs = daxsiz-1; ys = cbacky; xi = -1; yi = 2; break; + case 6: xs = cbackx; ys = 0; xi = 2; yi = 1; break; + case 7: xs = cbackx; ys = daysiz-1; xi = 2; yi = -1; break; + } + xe = cbackx; ye = cbacky; + if (cnt < 4) + { + if ((xi < 0) && (xe >= xs)) continue; + if ((xi > 0) && (xe <= xs)) continue; + if ((yi < 0) && (ye >= ys)) continue; + if ((yi > 0) && (ye <= ys)) continue; + } + else + { + if ((xi < 0) && (xe > xs)) continue; + if ((xi > 0) && (xe < xs)) continue; + if ((yi < 0) && (ye > ys)) continue; + if ((yi > 0) && (ye < ys)) continue; + xe += xi; ye += yi; + } + + i = ksgn(ys-backy)+ksgn(xs-backx)*3+4; + switch(i) + { + case 6: case 7: x1 = 0; y1 = 0; break; + case 8: case 5: x1 = gxinc; y1 = gyinc; break; + case 0: case 3: x1 = gyinc; y1 = -gxinc; break; + case 2: case 1: x1 = gxinc+gyinc; y1 = gyinc-gxinc; break; + } + switch(i) + { + case 2: case 5: x2 = 0; y2 = 0; break; + case 0: case 1: x2 = gxinc; y2 = gyinc; break; + case 8: case 7: x2 = gyinc; y2 = -gxinc; break; + case 6: case 3: x2 = gxinc+gyinc; y2 = gyinc-gxinc; break; + } + oand = pow2char[(xs 0) { dagxinc = gxinc; dagyinc = mulscale16(gyinc,viewingrangerecip); } + else { dagxinc = -gxinc; dagyinc = -mulscale16(gyinc,viewingrangerecip); } + + /* Fix for non 90 degree viewing ranges */ + nxoff = mulscale16(x2-x1,viewingrangerecip); + x1 = mulscale16(x1,viewingrangerecip); + + ggxstart = gxstart+ggyinc[ys]; + ggystart = gystart-ggxinc[ys]; + + for(x=xs;x!=xe;x+=xi) + { + slabxoffs = (long)&davoxptr[BUILDSWAP_INTEL32(longptr[x])]; + shortptr = (short *)&davoxptr[((x*(daysiz+1))<<1)+xyvoxoffs]; + + nx = mulscale16(ggxstart+ggxinc[x],viewingrangerecip)+x1; + ny = ggystart+ggyinc[x]; + for(y=ys;y!=ye;y+=yi,nx+=dagyinc,ny-=dagxinc) + { + if ((ny <= nytooclose) || (ny >= nytoofar)) continue; + voxptr = (char *)(shortptr[y]+slabxoffs); + voxend = (char *)(shortptr[y+1]+slabxoffs); + if (voxptr == voxend) continue; + + lx = mulscale32(nx>>3,distrecip[(ny+y1)>>14])+halfxdimen; + if (lx < 0) lx = 0; + rx = mulscale32((nx+nxoff)>>3,distrecip[(ny+y2)>>14])+halfxdimen; + if (rx > xdimen) rx = xdimen; + if (rx <= lx) continue; + rx -= lx; + + l1 = distrecip[(ny-yoff)>>14]; + l2 = distrecip[(ny+yoff)>>14]; + for(;voxptr= 1024) yinc = divscale16(voxptr[1],z2-z1); + else if (z2 > z1) yinc = (lowrecip[z2-z1]*voxptr[1]>>8); + if (z1 < daumost[lx]) { yplc = yinc*(daumost[lx]-z1); z1 = daumost[lx]; } else yplc = 0; + } + if (z2 > dadmost[lx]) z2 = dadmost[lx]; + z2 -= z1; if (z2 <= 0) continue; + + drawslab(rx,yplc,z2,yinc,(long)&voxptr[3],ylookup[z1]+lx+frameoffset); + } + } + } + } +} +#endif + + +static void drawsprite (long snum) +{ + spritetype *tspr; + sectortype *sec; + long startum, startdm, sectnum, xb, yp, cstat; + long siz, xsiz, ysiz, xoff, yoff, xspan, yspan; + long x1, y1, x2, y2, lx, rx, dalx2, darx2, i, j, k, x, linum, linuminc; + long yinc, z, z1, z2, xp1, yp1, xp2, yp2; + long xv, yv, top, topinc, bot, botinc, hplc, hinc; + long cosang, sinang, dax, day, lpoint, lmax, rpoint, rmax, dax1, dax2, y; + long npoints, npoints2, zz, t, zsgn, zzsgn; + short tilenum, spritenum; + char swapped, daclip; + + #ifdef SUPERBUILD + long *longptr; + #endif + + tspr = tspriteptr[snum]; + + xb = spritesx[snum]; + yp = spritesy[snum]; + tilenum = tspr->picnum; + spritenum = tspr->owner; + cstat = tspr->cstat; + + if ((cstat&48) != 48) + { + if (picanm[tilenum]&192) tilenum += animateoffs(tilenum,(short) (spritenum+32768)); + if ((tilesizx[tilenum] <= 0) || (tilesizy[tilenum] <= 0) || (spritenum < 0)) + return; + } + if ((tspr->xrepeat <= 0) || (tspr->yrepeat <= 0)) return; + + sectnum = tspr->sectnum; sec = §or[sectnum]; + globalpal = tspr->pal; + globalshade = tspr->shade; + if (cstat&2) + { + if (cstat&512) settransreverse(); else settransnormal(); + } + + xoff = (long)((signed char)((picanm[tilenum]>>8)&255))+((long)tspr->xoffset); + yoff = (long)((signed char)((picanm[tilenum]>>16)&255))+((long)tspr->yoffset); + + if ((cstat&48) == 0) + { + if (yp <= (4<<8)) return; + + siz = divscale19(xdimenscale,yp); + + xv = mulscale16(((long)tspr->xrepeat)<<16,xyaspect); + + xspan = tilesizx[tilenum]; + yspan = tilesizy[tilenum]; + xsiz = mulscale30(siz,xv*xspan); + ysiz = mulscale14(siz,tspr->yrepeat*yspan); + + if (((tilesizx[tilenum]>>11) >= xsiz) || (yspan >= (ysiz>>1))) + return; /* Watch out for divscale overflow */ + + x1 = xb-(xsiz>>1); + if (xspan&1) x1 += mulscale31(siz,xv); /* Odd xspans */ + i = mulscale30(siz,xv*xoff); + if ((cstat&4) == 0) x1 -= i; else x1 += i; + + y1 = mulscale16(tspr->z-globalposz,siz); + y1 -= mulscale14(siz,tspr->yrepeat*yoff); + y1 += (globalhoriz<<8)-ysiz; + if (cstat&128) + { + y1 += (ysiz>>1); + if (yspan&1) y1 += mulscale15(siz,tspr->yrepeat); /* Odd yspans */ + } + + x2 = x1+xsiz-1; + y2 = y1+ysiz-1; + if ((y1|255) >= (y2|255)) return; + + lx = (x1>>8)+1; if (lx < 0) lx = 0; + rx = (x2>>8); if (rx >= xdimen) rx = xdimen-1; + if (lx > rx) return; + + yinc = divscale32(yspan,ysiz); + + if ((sec->ceilingstat&3) == 0) + startum = globalhoriz+mulscale24(siz,sec->ceilingz-globalposz)-1; + else + startum = 0; + if ((sec->floorstat&3) == 0) + startdm = globalhoriz+mulscale24(siz,sec->floorz-globalposz)+1; + else + startdm = 0x7fffffff; + if ((y1>>8) > startum) startum = (y1>>8); + if ((y2>>8) < startdm) startdm = (y2>>8); + + if (startum < -32768) startum = -32768; + if (startdm > 32767) startdm = 32767; + if (startum >= startdm) return; + + if ((cstat&4) == 0) + { + linuminc = divscale24(xspan,xsiz); + linum = mulscale8((lx<<8)-x1,linuminc); + } + else + { + linuminc = -divscale24(xspan,xsiz); + linum = mulscale8((lx<<8)-x2,linuminc); + } + if ((cstat&8) > 0) + { + yinc = -yinc; + i = y1; y1 = y2; y2 = i; + } + + for(x=lx;x<=rx;x++) + { + uwall[x] = max(startumost[x+windowx1]-windowy1,(short)startum); + dwall[x] = min(startdmost[x+windowx1]-windowy1,(short)startdm); + } + daclip = 0; + for(i=smostwallcnt-1;i>=0;i--) + { + if (smostwalltype[i]&daclip) continue; + j = smostwall[i]; + if ((xb1[j] > rx) || (xb2[j] < lx)) continue; + if ((yp <= yb1[j]) && (yp <= yb2[j])) continue; + if (spritewallfront(tspr,(long)thewall[j]) && ((yp <= yb1[j]) || (yp <= yb2[j]))) continue; + + dalx2 = max(xb1[j],lx); darx2 = min(xb2[j],rx); + + switch(smostwalltype[i]) + { + case 0: + if (dalx2 <= darx2) + { + if ((dalx2 == lx) && (darx2 == rx)) return; + clearbufbyte(&dwall[dalx2],(darx2-dalx2+1)*sizeof(dwall[0]),0L); + } + break; + case 1: + k = smoststart[i] - xb1[j]; + for(x=dalx2;x<=darx2;x++) + if (smost[k+x] > uwall[x]) uwall[x] = smost[k+x]; + if ((dalx2 == lx) && (darx2 == rx)) daclip |= 1; + break; + case 2: + k = smoststart[i] - xb1[j]; + for(x=dalx2;x<=darx2;x++) + if (smost[k+x] < dwall[x]) dwall[x] = smost[k+x]; + if ((dalx2 == lx) && (darx2 == rx)) daclip |= 2; + break; + } + } + + if (uwall[rx] >= dwall[rx]) + { + for(x=lx;x= 1) && (searchx >= lx) && (searchx <= rx)) + if ((searchy >= uwall[searchx]) && (searchy < dwall[searchx])) + { + searchsector = sectnum; searchwall = spritenum; + searchstat = 3; searchit = 1; + } + + z2 = tspr->z - ((yoff*tspr->yrepeat)<<2); + if (cstat&128) + { + z2 += ((yspan*tspr->yrepeat)<<1); + if (yspan&1) z2 += (tspr->yrepeat<<1); /* Odd yspans */ + } + z1 = z2 - ((yspan*tspr->yrepeat)<<2); + + globalorientation = 0; + globalpicnum = tilenum; + if ((unsigned)globalpicnum >= (unsigned)MAXTILES) globalpicnum = 0; + globalxpanning = 0L; + globalypanning = 0L; + globvis = globalvisibility; + if (sec->visibility != 0) globvis = mulscale4(globvis,(long)((unsigned char)(sec->visibility+16))); + globalshiftval = (picsiz[globalpicnum]>>4); + if (pow2long[globalshiftval] != tilesizy[globalpicnum]) globalshiftval++; + globalshiftval = 32-globalshiftval; + globalyscale = divscale(512,tspr->yrepeat,globalshiftval-19); + globalzd = (((globalposz-z1)*globalyscale)<<8); + if ((cstat&8) > 0) + { + globalyscale = -globalyscale; + globalzd = (((globalposz-z2)*globalyscale)<<8); + } + + qinterpolatedown16((long *)&lwall[lx],rx-lx+1,linum,linuminc); + clearbuf(&swall[lx],rx-lx+1,mulscale19(yp,xdimscale)); + + if ((cstat&2) == 0) + maskwallscan(lx,rx,uwall,dwall,swall,lwall); + else + transmaskwallscan(lx,rx); + } + else if ((cstat&48) == 16) + { + if ((cstat&4) > 0) xoff = -xoff; + if ((cstat&8) > 0) yoff = -yoff; + + xspan = tilesizx[tilenum]; yspan = tilesizy[tilenum]; + xv = tspr->xrepeat*sintable[(tspr->ang+2560+1536)&2047]; + yv = tspr->xrepeat*sintable[(tspr->ang+2048+1536)&2047]; + i = (xspan>>1)+xoff; + x1 = tspr->x-globalposx-mulscale16(xv,i); x2 = x1+mulscale16(xv,xspan); + y1 = tspr->y-globalposy-mulscale16(yv,i); y2 = y1+mulscale16(yv,xspan); + + yp1 = dmulscale6(x1,cosviewingrangeglobalang,y1,sinviewingrangeglobalang); + yp2 = dmulscale6(x2,cosviewingrangeglobalang,y2,sinviewingrangeglobalang); + if ((yp1 <= 0) && (yp2 <= 0)) return; + xp1 = dmulscale6(y1,cosglobalang,-x1,singlobalang); + xp2 = dmulscale6(y2,cosglobalang,-x2,singlobalang); + + x1 += globalposx; y1 += globalposy; + x2 += globalposx; y2 += globalposy; + + swapped = 0; + if (dmulscale32(xp1,yp2,-xp2,yp1) >= 0) /* If wall's NOT facing you */ + { + if ((cstat&64) != 0) return; + i = xp1, xp1 = xp2, xp2 = i; + i = yp1, yp1 = yp2, yp2 = i; + i = x1, x1 = x2, x2 = i; + i = y1, y1 = y2, y2 = i; + swapped = 1; + } + + if (xp1 >= -yp1) + { + if (xp1 > yp1) return; + + if (yp1 == 0) return; + xb1[MAXWALLSB-1] = halfxdimen + scale(xp1,halfxdimen,yp1); + if (xp1 >= 0) xb1[MAXWALLSB-1]++; /* Fix for SIGNED divide */ + if (xb1[MAXWALLSB-1] >= xdimen) xb1[MAXWALLSB-1] = xdimen-1; + yb1[MAXWALLSB-1] = yp1; + } + else + { + if (xp2 < -yp2) return; + xb1[MAXWALLSB-1] = 0; + i = yp1-yp2+xp1-xp2; + if (i == 0) return; + yb1[MAXWALLSB-1] = yp1 + scale(yp2-yp1,xp1+yp1,i); + } + if (xp2 <= yp2) + { + if (xp2 < -yp2) return; + + if (yp2 == 0) return; + xb2[MAXWALLSB-1] = halfxdimen + scale(xp2,halfxdimen,yp2) - 1; + if (xp2 >= 0) xb2[MAXWALLSB-1]++; /* Fix for SIGNED divide */ + if (xb2[MAXWALLSB-1] >= xdimen) xb2[MAXWALLSB-1] = xdimen-1; + yb2[MAXWALLSB-1] = yp2; + } + else + { + if (xp1 > yp1) return; + + xb2[MAXWALLSB-1] = xdimen-1; + i = xp2-xp1+yp1-yp2; + if (i == 0) return; + yb2[MAXWALLSB-1] = yp1 + scale(yp2-yp1,yp1-xp1,i); + } + + if ((yb1[MAXWALLSB-1] < 256) || (yb2[MAXWALLSB-1] < 256) || (xb1[MAXWALLSB-1] > xb2[MAXWALLSB-1])) + return; + + topinc = -mulscale10(yp1,xspan); + top = (((mulscale10(xp1,xdimen) - mulscale9(xb1[MAXWALLSB-1]-halfxdimen,yp1))*xspan)>>3); + botinc = ((yp2-yp1)>>8); + bot = mulscale11(xp1-xp2,xdimen) + mulscale2(xb1[MAXWALLSB-1]-halfxdimen,botinc); + + j = xb2[MAXWALLSB-1]+3; + z = mulscale20(top,krecipasm(bot)); + lwall[xb1[MAXWALLSB-1]] = (z>>8); + for(x=xb1[MAXWALLSB-1]+4;x<=j;x+=4) + { + top += topinc; bot += botinc; + zz = z; z = mulscale20(top,krecipasm(bot)); + lwall[x] = (z>>8); + i = ((z+zz)>>1); + lwall[x-2] = (i>>8); + lwall[x-3] = ((i+zz)>>9); + lwall[x-1] = ((i+z)>>9); + } + + if (lwall[xb1[MAXWALLSB-1]] < 0) lwall[xb1[MAXWALLSB-1]] = 0; + if (lwall[xb2[MAXWALLSB-1]] >= xspan) lwall[xb2[MAXWALLSB-1]] = xspan-1; + + if ((swapped^((cstat&4)>0)) > 0) + { + j = xspan-1; + for(x=xb1[MAXWALLSB-1];x<=xb2[MAXWALLSB-1];x++) + lwall[x] = j-lwall[x]; + } + + rx1[MAXWALLSB-1] = xp1; ry1[MAXWALLSB-1] = yp1; + rx2[MAXWALLSB-1] = xp2; ry2[MAXWALLSB-1] = yp2; + + hplc = divscale19(xdimenscale,yb1[MAXWALLSB-1]); + hinc = divscale19(xdimenscale,yb2[MAXWALLSB-1]); + hinc = (hinc-hplc)/(xb2[MAXWALLSB-1]-xb1[MAXWALLSB-1]+1); + + z2 = tspr->z - ((yoff*tspr->yrepeat)<<2); + if (cstat&128) + { + z2 += ((yspan*tspr->yrepeat)<<1); + if (yspan&1) z2 += (tspr->yrepeat<<1); /* Odd yspans */ + } + z1 = z2 - ((yspan*tspr->yrepeat)<<2); + + globalorientation = 0; + globalpicnum = tilenum; + if ((unsigned)globalpicnum >= (unsigned)MAXTILES) globalpicnum = 0; + globalxpanning = 0L; + globalypanning = 0L; + globvis = globalvisibility; + if (sec->visibility != 0) globvis = mulscale4(globvis,(long)((unsigned char)(sec->visibility+16))); + globalshiftval = (picsiz[globalpicnum]>>4); + if (pow2long[globalshiftval] != tilesizy[globalpicnum]) globalshiftval++; + globalshiftval = 32-globalshiftval; + globalyscale = divscale(512,tspr->yrepeat,globalshiftval-19); + globalzd = (((globalposz-z1)*globalyscale)<<8); + if ((cstat&8) > 0) + { + globalyscale = -globalyscale; + globalzd = (((globalposz-z2)*globalyscale)<<8); + } + + if (((sec->ceilingstat&1) == 0) && (z1 < sec->ceilingz)) + z1 = sec->ceilingz; + if (((sec->floorstat&1) == 0) && (z2 > sec->floorz)) + z2 = sec->floorz; + + owallmost(uwall,(long)(MAXWALLSB-1),z1-globalposz); + owallmost(dwall,(long)(MAXWALLSB-1),z2-globalposz); + for(i=xb1[MAXWALLSB-1];i<=xb2[MAXWALLSB-1];i++) + { swall[i] = (krecipasm(hplc)<<2); hplc += hinc; } + + for(i=smostwallcnt-1;i>=0;i--) + { + j = smostwall[i]; + + if ((xb1[j] > xb2[MAXWALLSB-1]) || (xb2[j] < xb1[MAXWALLSB-1])) continue; + + dalx2 = xb1[j]; darx2 = xb2[j]; + if (max(yb1[MAXWALLSB-1],yb2[MAXWALLSB-1]) > min(yb1[j],yb2[j])) + { + if (min(yb1[MAXWALLSB-1],yb2[MAXWALLSB-1]) > max(yb1[j],yb2[j])) + { + x = 0x80000000; + } + else + { + x = thewall[j]; xp1 = wall[x].x; yp1 = wall[x].y; + x = wall[x].point2; xp2 = wall[x].x; yp2 = wall[x].y; + + z1 = (xp2-xp1)*(y1-yp1) - (yp2-yp1)*(x1-xp1); + z2 = (xp2-xp1)*(y2-yp1) - (yp2-yp1)*(x2-xp1); + if ((z1^z2) >= 0) + x = (z1+z2); + else + { + z1 = (x2-x1)*(yp1-y1) - (y2-y1)*(xp1-x1); + z2 = (x2-x1)*(yp2-y1) - (y2-y1)*(xp2-x1); + + if ((z1^z2) >= 0) + x = -(z1+z2); + else + { + if ((xp2-xp1)*(tspr->y-yp1) == (tspr->x-xp1)*(yp2-yp1)) + { + if (wall[thewall[j]].nextsector == tspr->sectnum) + x = 0x80000000; + else + x = 0x7fffffff; + } + else + { /* INTERSECTION! */ + x = (xp1-globalposx) + scale(xp2-xp1,z1,z1-z2); + y = (yp1-globalposy) + scale(yp2-yp1,z1,z1-z2); + + yp1 = dmulscale14(x,cosglobalang,y,singlobalang); + if (yp1 > 0) + { + xp1 = dmulscale14(y,cosglobalang,-x,singlobalang); + + x = halfxdimen + scale(xp1,halfxdimen,yp1); + if (xp1 >= 0) x++; /* Fix for SIGNED divide */ + + if (z1 < 0) + { if (dalx2 < x) dalx2 = x; } + else + { if (darx2 > x) darx2 = x; } + x = 0x80000001; + } + else + x = 0x7fffffff; + } + } + } + } + if (x < 0) + { + if (dalx2 < xb1[MAXWALLSB-1]) dalx2 = xb1[MAXWALLSB-1]; + if (darx2 > xb2[MAXWALLSB-1]) darx2 = xb2[MAXWALLSB-1]; + switch(smostwalltype[i]) + { + case 0: + if (dalx2 <= darx2) + { + if ((dalx2 == xb1[MAXWALLSB-1]) && (darx2 == xb2[MAXWALLSB-1])) return; + clearbufbyte(&dwall[dalx2],(darx2-dalx2+1)*sizeof(dwall[0]),0L); + } + break; + case 1: + k = smoststart[i] - xb1[j]; + for(x=dalx2;x<=darx2;x++) + if (smost[k+x] > uwall[x]) uwall[x] = smost[k+x]; + break; + case 2: + k = smoststart[i] - xb1[j]; + for(x=dalx2;x<=darx2;x++) + if (smost[k+x] < dwall[x]) dwall[x] = smost[k+x]; + break; + } + } + } + } + + /* sprite */ + if ((searchit >= 1) && (searchx >= xb1[MAXWALLSB-1]) && (searchx <= xb2[MAXWALLSB-1])) + if ((searchy >= uwall[searchx]) && (searchy <= dwall[searchx])) + { + searchsector = sectnum; searchwall = spritenum; + searchstat = 3; searchit = 1; + } + + if ((cstat&2) == 0) + maskwallscan(xb1[MAXWALLSB-1],xb2[MAXWALLSB-1],uwall,dwall,swall,lwall); + else + transmaskwallscan(xb1[MAXWALLSB-1],xb2[MAXWALLSB-1]); + } + else if ((cstat&48) == 32) + { + if ((cstat&64) != 0) + if ((globalposz > tspr->z) == ((cstat&8)==0)) + return; + + if ((cstat&4) > 0) xoff = -xoff; + if ((cstat&8) > 0) yoff = -yoff; + xspan = tilesizx[tilenum]; + yspan = tilesizy[tilenum]; + + /* Rotate center point */ + dax = tspr->x-globalposx; + day = tspr->y-globalposy; + rzi[0] = dmulscale10(cosglobalang,dax,singlobalang,day); + rxi[0] = dmulscale10(cosglobalang,day,-singlobalang,dax); + + /* Get top-left corner */ + i = ((tspr->ang+2048-globalang)&2047); + cosang = sintable[(i+512)&2047]; sinang = sintable[i]; + dax = ((xspan>>1)+xoff)*tspr->xrepeat; + day = ((yspan>>1)+yoff)*tspr->yrepeat; + rzi[0] += dmulscale12(sinang,dax,cosang,day); + rxi[0] += dmulscale12(sinang,day,-cosang,dax); + + /* Get other 3 corners */ + dax = xspan*tspr->xrepeat; + day = yspan*tspr->yrepeat; + rzi[1] = rzi[0]-mulscale12(sinang,dax); + rxi[1] = rxi[0]+mulscale12(cosang,dax); + dax = -mulscale12(cosang,day); + day = -mulscale12(sinang,day); + rzi[2] = rzi[1]+dax; rxi[2] = rxi[1]+day; + rzi[3] = rzi[0]+dax; rxi[3] = rxi[0]+day; + + /* Put all points on same z */ + ryi[0] = scale((tspr->z-globalposz),yxaspect,320<<8); + if (ryi[0] == 0) return; + ryi[1] = ryi[2] = ryi[3] = ryi[0]; + + if ((cstat&4) == 0) + { z = 0; z1 = 1; z2 = 3; } + else + { z = 1; z1 = 0; z2 = 2; } + + dax = rzi[z1]-rzi[z]; day = rxi[z1]-rxi[z]; + bot = dmulscale8(dax,dax,day,day); + if (((klabs(dax)>>13) >= bot) || ((klabs(day)>>13) >= bot)) return; + globalx1 = divscale18(dax,bot); + globalx2 = divscale18(day,bot); + + dax = rzi[z2]-rzi[z]; day = rxi[z2]-rxi[z]; + bot = dmulscale8(dax,dax,day,day); + if (((klabs(dax)>>13) >= bot) || ((klabs(day)>>13) >= bot)) return; + globaly1 = divscale18(dax,bot); + globaly2 = divscale18(day,bot); + + /* Calculate globals for hline texture mapping function */ + globalxpanning = (rxi[z]<<12); + globalypanning = (rzi[z]<<12); + globalzd = (ryi[z]<<12); + + rzi[0] = mulscale16(rzi[0],viewingrange); + rzi[1] = mulscale16(rzi[1],viewingrange); + rzi[2] = mulscale16(rzi[2],viewingrange); + rzi[3] = mulscale16(rzi[3],viewingrange); + + if (ryi[0] < 0) /* If ceilsprite is above you, reverse order of points */ + { + i = rxi[1]; rxi[1] = rxi[3]; rxi[3] = i; + i = rzi[1]; rzi[1] = rzi[3]; rzi[3] = i; + } + + + /* Clip polygon in 3-space */ + npoints = 4; + + /* Clip edge 1 */ + npoints2 = 0; + zzsgn = rxi[0]+rzi[0]; + for(z=0;z= 0) + { + rxi2[npoints2] = rxi[z]; ryi2[npoints2] = ryi[z]; rzi2[npoints2] = rzi[z]; + npoints2++; + } + if ((zsgn^zzsgn) < 0) + { + t = divscale30(zsgn,zsgn-zzsgn); + rxi2[npoints2] = rxi[z] + mulscale30(t,rxi[zz]-rxi[z]); + ryi2[npoints2] = ryi[z] + mulscale30(t,ryi[zz]-ryi[z]); + rzi2[npoints2] = rzi[z] + mulscale30(t,rzi[zz]-rzi[z]); + npoints2++; + } + } + if (npoints2 <= 2) return; + + /* Clip edge 2 */ + npoints = 0; + zzsgn = rxi2[0]-rzi2[0]; + for(z=0;z= 0) + { + rxi2[npoints2] = rxi[z]; + ryi2[npoints2] = ryi[z]; + rzi2[npoints2] = rzi[z]; + npoints2++; + } + if ((zsgn^zzsgn) < 0) + { + t = divscale30(zsgn,zsgn-zzsgn); + rxi2[npoints2] = rxi[z] + mulscale30(t,rxi[zz]-rxi[z]); + ryi2[npoints2] = ryi[z] + mulscale30(t,ryi[zz]-ryi[z]); + rzi2[npoints2] = rzi[z] + mulscale30(t,rzi[zz]-rzi[z]); + npoints2++; + } + } + if (npoints2 <= 2) return; + + /* Clip edge 4 */ + npoints = 0; + zzsgn = ryi2[0]*halfxdimen + (rzi2[0]*(globalhoriz-ydimen)); + for(z=0;z (xdimen<<16)) xsi[z] = (xdimen<<16); + if (ysi[z] < ((long)0<<16)) ysi[z] = ((long)0<<16); + if (ysi[z] > ((long)ydimen<<16)) ysi[z] = ((long)ydimen<<16); + if (xsi[z] < lmax) lmax = xsi[z], lpoint = z; + if (xsi[z] > rmax) rmax = xsi[z], rpoint = z; + } + + /* Get uwall arrays */ + for(z=lpoint;z!=rpoint;z=zz) + { + zz = z+1; if (zz == npoints) zz = 0; + + dax1 = ((xsi[z]+65535)>>16); + dax2 = ((xsi[zz]+65535)>>16); + if (dax2 > dax1) + { + yinc = divscale16(ysi[zz]-ysi[z],xsi[zz]-xsi[z]); + y = ysi[z] + mulscale16((dax1<<16)-xsi[z],yinc); + qinterpolatedown16short((long *)(&uwall[dax1]),dax2-dax1,y,yinc); + } + } + + /* Get dwall arrays */ + for(;z!=lpoint;z=zz) + { + zz = z+1; if (zz == npoints) zz = 0; + + dax1 = ((xsi[zz]+65535)>>16); + dax2 = ((xsi[z]+65535)>>16); + if (dax2 > dax1) + { + yinc = divscale16(ysi[zz]-ysi[z],xsi[zz]-xsi[z]); + y = ysi[zz] + mulscale16((dax1<<16)-xsi[zz],yinc); + qinterpolatedown16short((long *)(&dwall[dax1]),dax2-dax1,y,yinc); + } + } + + + lx = ((lmax+65535)>>16); + rx = ((rmax+65535)>>16); + for(x=lx;x<=rx;x++) + { + uwall[x] = max(uwall[x],startumost[x+windowx1]-windowy1); + dwall[x] = min(dwall[x],startdmost[x+windowx1]-windowy1); + } + + /* Additional uwall/dwall clipping goes here */ + for(i=smostwallcnt-1;i>=0;i--) + { + j = smostwall[i]; + if ((xb1[j] > rx) || (xb2[j] < lx)) continue; + if ((yp <= yb1[j]) && (yp <= yb2[j])) continue; + + /* if (spritewallfront(tspr,thewall[j]) == 0) */ + x = thewall[j]; xp1 = wall[x].x; yp1 = wall[x].y; + x = wall[x].point2; xp2 = wall[x].x; yp2 = wall[x].y; + x = (xp2-xp1)*(tspr->y-yp1)-(tspr->x-xp1)*(yp2-yp1); + if ((yp > yb1[j]) && (yp > yb2[j])) x = -1; + if ((x >= 0) && ((x != 0) || (wall[thewall[j]].nextsector != tspr->sectnum))) continue; + + dalx2 = max(xb1[j],lx); darx2 = min(xb2[j],rx); + + switch(smostwalltype[i]) + { + case 0: + if (dalx2 <= darx2) + { + if ((dalx2 == lx) && (darx2 == rx)) return; + clearbufbyte(&dwall[dalx2],(darx2-dalx2+1)*sizeof(dwall[0]),0L); + } + break; + case 1: + k = smoststart[i] - xb1[j]; + for(x=dalx2;x<=darx2;x++) + if (smost[k+x] > uwall[x]) uwall[x] = smost[k+x]; + break; + case 2: + k = smoststart[i] - xb1[j]; + for(x=dalx2;x<=darx2;x++) + if (smost[k+x] < dwall[x]) dwall[x] = smost[k+x]; + break; + } + } + + /* sprite */ + if ((searchit >= 1) && (searchx >= lx) && (searchx <= rx)) + if ((searchy >= uwall[searchx]) && (searchy <= dwall[searchx])) + { + searchsector = sectnum; searchwall = spritenum; + searchstat = 3; searchit = 1; + } + + globalorientation = cstat; + globalpicnum = tilenum; + if ((unsigned)globalpicnum >= (unsigned)MAXTILES) globalpicnum = 0; + /* if (picanm[globalpicnum]&192) globalpicnum += animateoffs((short)globalpicnum,spritenum+32768); */ + + if (waloff[globalpicnum] == 0) loadtile(globalpicnum); + setgotpic(globalpicnum); + globalbufplc = waloff[globalpicnum]; + + globvis = mulscale16(globalhisibility,viewingrange); + if (sec->visibility != 0) globvis = mulscale4(globvis,(long)((unsigned char)(sec->visibility+16))); + + x = picsiz[globalpicnum]; y = ((x>>4)&15); x &= 15; + if (pow2long[x] != xspan) + { + x++; + globalx1 = mulscale(globalx1,xspan,x); + globalx2 = mulscale(globalx2,xspan,x); + } + + dax = globalxpanning; day = globalypanning; + globalxpanning = -dmulscale6(globalx1,day,globalx2,dax); + globalypanning = -dmulscale6(globaly1,day,globaly2,dax); + + globalx2 = mulscale16(globalx2,viewingrange); + globaly2 = mulscale16(globaly2,viewingrange); + globalzd = mulscale16(globalzd,viewingrangerecip); + + globalx1 = (globalx1-globalx2)*halfxdimen; + globaly1 = (globaly1-globaly2)*halfxdimen; + + if ((cstat&2) == 0) + msethlineshift(x,y); + else + tsethlineshift(x,y); + + /* Draw it! */ + ceilspritescan(lx,rx-1); + } +#ifdef SUPERBUILD + else if ((cstat&48) == 48) + { + lx = 0; rx = xdim-1; + for(x=lx;x<=rx;x++) + { + lwall[x] = (long)startumost[x+windowx1]-windowy1; + swall[x] = (long)startdmost[x+windowx1]-windowy1; + } + for(i=smostwallcnt-1;i>=0;i--) + { + j = smostwall[i]; + if ((xb1[j] > rx) || (xb2[j] < lx)) continue; + if ((yp <= yb1[j]) && (yp <= yb2[j])) continue; + if (spritewallfront(tspr,(long)thewall[j]) && ((yp <= yb1[j]) || (yp <= yb2[j]))) continue; + + dalx2 = max(xb1[j],lx); darx2 = min(xb2[j],rx); + + switch(smostwalltype[i]) + { + case 0: + if (dalx2 <= darx2) + { + if ((dalx2 == lx) && (darx2 == rx)) return; + clearbufbyte(&swall[dalx2],(darx2-dalx2+1)*sizeof(swall[0]),0L); + } + break; + case 1: + k = smoststart[i] - xb1[j]; + for(x=dalx2;x<=darx2;x++) + if (smost[k+x] > lwall[x]) lwall[x] = smost[k+x]; + break; + case 2: + k = smoststart[i] - xb1[j]; + for(x=dalx2;x<=darx2;x++) + if (smost[k+x] < swall[x]) swall[x] = smost[k+x]; + break; + } + } + + if (lwall[rx] >= swall[rx]) + { + for(x=lx;xz -= mulscale6(longptr[5],(long)tspr->yrepeat); + yoff = (long)((signed char)((picanm[sprite[tspr->owner].picnum]>>16)&255))+((long)tspr->yoffset); + tspr->z -= ((yoff*tspr->yrepeat)<<2); + + globvis = globalvisibility; + if (sec->visibility != 0) globvis = mulscale4(globvis,(long)((unsigned char)(sec->visibility+16))); + + if ((searchit >= 1) && (yp > (4<<8)) && (searchy >= lwall[searchx]) && (searchy < swall[searchx])) + { + siz = divscale19(xdimenscale,yp); + + xv = mulscale16(((long)tspr->xrepeat)<<16,xyaspect); + + xspan = ((longptr[0]+longptr[1])>>1); + yspan = longptr[2]; + xsiz = mulscale30(siz,xv*xspan); + ysiz = mulscale14(siz,tspr->yrepeat*yspan); + + /* Watch out for divscale overflow */ + if (((xspan>>11) < xsiz) && (yspan < (ysiz>>1))) + { + x1 = xb-(xsiz>>1); + if (xspan&1) x1 += mulscale31(siz,xv); /* Odd xspans */ + i = mulscale30(siz,xv*xoff); + if ((cstat&4) == 0) x1 -= i; else x1 += i; + + y1 = mulscale16(tspr->z-globalposz,siz); + /*y1 -= mulscale14(siz,tspr->yrepeat*yoff);*/ + y1 += (globalhoriz<<8)-ysiz; + /*if (cstat&128) //Already fixed up above */ + y1 += (ysiz>>1); + + x2 = x1+xsiz-1; + y2 = y1+ysiz-1; + if (((y1|255) < (y2|255)) && (searchx >= (x1>>8)+1) && (searchx <= (x2>>8))) + { + if ((sec->ceilingstat&3) == 0) + startum = globalhoriz+mulscale24(siz,sec->ceilingz-globalposz)-1; + else + startum = 0; + if ((sec->floorstat&3) == 0) + startdm = globalhoriz+mulscale24(siz,sec->floorz-globalposz)+1; + else + startdm = 0x7fffffff; + + /* sprite */ + if ((searchy >= max(startum,(y1>>8))) && (searchy < min(startdm,(y2>>8)))) + { + searchsector = sectnum; searchwall = spritenum; + searchstat = 3; searchit = 1; + } + } + } + } + + drawvox(tspr->x,tspr->y,tspr->z,(long)tspr->ang+1536,(long)tspr->xrepeat,(long)tspr->yrepeat,tilenum,tspr->shade,tspr->pal,lwall,swall); + } +#endif + if (automapping == 1) show2dsprite[spritenum>>3] |= pow2char[spritenum&7]; +} + + +void drawmasks(void) +{ + long i, j, k, l, gap, xs, ys, xp, yp, yoff, yspan; + /* long zs, zp; */ + + for(i=spritesortcnt-1;i>=0;i--) tspriteptr[i] = &tsprite[i]; + for(i=spritesortcnt-1;i>=0;i--) + { + xs = tspriteptr[i]->x-globalposx; ys = tspriteptr[i]->y-globalposy; + yp = dmulscale6(xs,cosviewingrangeglobalang,ys,sinviewingrangeglobalang); + if (yp > (4<<8)) + { + xp = dmulscale6(ys,cosglobalang,-xs,singlobalang); + spritesx[i] = scale(xp+yp,xdimen<<7,yp); + } + else if ((tspriteptr[i]->cstat&48) == 0) + { + spritesortcnt--; /* Delete face sprite if on wrong side! */ + if (i != spritesortcnt) + { + tspriteptr[i] = tspriteptr[spritesortcnt]; + spritesx[i] = spritesx[spritesortcnt]; + spritesy[i] = spritesy[spritesortcnt]; + } + continue; + } + spritesy[i] = yp; + } + + gap = 1; while (gap < spritesortcnt) gap = (gap<<1)+1; + for(gap>>=1;gap>0;gap>>=1) /* Sort sprite list */ + for(i=0;i=0;l-=gap) + { + if (spritesy[l] <= spritesy[l+gap]) break; + swaplong((long *)&tspriteptr[l],(long *)&tspriteptr[l+gap]); + swaplong(&spritesx[l],&spritesx[l+gap]); + swaplong(&spritesy[l],&spritesy[l+gap]); + } + + if (spritesortcnt > 0) + spritesy[spritesortcnt] = (spritesy[spritesortcnt-1]^1); + + ys = spritesy[0]; i = 0; + for(j=1;j<=spritesortcnt;j++) + { + if (spritesy[j] == ys) continue; + ys = spritesy[j]; + if (j > i+1) + { + for(k=i;kz; + if ((tspriteptr[k]->cstat&48) != 32) + { + yoff = (long)((signed char)((picanm[tspriteptr[k]->picnum]>>16)&255))+((long)tspriteptr[k]->yoffset); + spritesz[k] -= ((yoff*tspriteptr[k]->yrepeat)<<2); + yspan = (tilesizy[tspriteptr[k]->picnum]*tspriteptr[k]->yrepeat<<2); + if (!(tspriteptr[k]->cstat&128)) spritesz[k] -= (yspan>>1); + if (klabs(spritesz[k]-globalposz) < (yspan>>1)) spritesz[k] = globalposz; + } + } + for(k=i+1;kstatnum < tspriteptr[l]->statnum) + { + swaplong((long *)&tspriteptr[k],(long *)&tspriteptr[l]); + swaplong(&spritesx[k],&spritesx[l]); + swaplong(&spritesy[k],&spritesy[l]); + } + } + i = j; + } + + /*for(i=spritesortcnt-1;i>=0;i--) + { + xs = tspriteptr[i].x-globalposx; + ys = tspriteptr[i].y-globalposy; + zs = tspriteptr[i].z-globalposz; + + xp = ys*cosglobalang-xs*singlobalang; + yp = (zs<<1); + zp = xs*cosglobalang+ys*singlobalang; + + xs = scale(xp,halfxdimen<<12,zp)+((halfxdimen+windowx1)<<12); + ys = scale(yp,xdimenscale<<12,zp)+((globalhoriz+windowy1)<<12); + + drawline256(xs-65536,ys-65536,xs+65536,ys+65536,31); + drawline256(xs+65536,ys-65536,xs-65536,ys+65536,31); + }*/ + + while ((spritesortcnt > 0) && (maskwallcnt > 0)) /* While BOTH > 0 */ + { + j = maskwall[maskwallcnt-1]; + if (spritewallfront(tspriteptr[spritesortcnt-1],(long)thewall[j]) == 0) + drawsprite(--spritesortcnt); + else + { + /* Check to see if any sprites behind the masked wall... */ + k = -1; + gap = 0; + for(i=spritesortcnt-2;i>=0;i--) + if ((xb1[j] <= (spritesx[i]>>8)) && ((spritesx[i]>>8) <= xb2[j])) + if (spritewallfront(tspriteptr[i],(long)thewall[j]) == 0) + { + drawsprite(i); + tspriteptr[i]->owner = -1; + k = i; + gap++; + } + if (k >= 0) /* remove holes in sprite list */ + { + for(i=k;iowner >= 0) + { + if (i > k) + { + tspriteptr[k] = tspriteptr[i]; + spritesx[k] = spritesx[i]; + spritesy[k] = spritesy[i]; + } + k++; + } + spritesortcnt -= gap; + } + + /* finally safe to draw the masked wall */ + drawmaskwall(--maskwallcnt); + } + } + while (spritesortcnt > 0) drawsprite(--spritesortcnt); + while (maskwallcnt > 0) drawmaskwall(--maskwallcnt); +} + + +int setsprite(short spritenum, long newx, long newy, long newz) +{ + short tempsectnum; + + sprite[spritenum].x = newx; + sprite[spritenum].y = newy; + sprite[spritenum].z = newz; + + tempsectnum = sprite[spritenum].sectnum; + updatesector(newx,newy,&tempsectnum); + if (tempsectnum < 0) + return(-1); + if (tempsectnum != sprite[spritenum].sectnum) + changespritesect(spritenum,tempsectnum); + + return(0); +} + + +void initspritelists(void) +{ + long i; + + for (i=0;i= MAXSECTORS) || (headspritesect[MAXSECTORS] == -1)) + return(-1); /* list full */ + + blanktouse = headspritesect[MAXSECTORS]; + + headspritesect[MAXSECTORS] = nextspritesect[blanktouse]; + if (headspritesect[MAXSECTORS] >= 0) + prevspritesect[headspritesect[MAXSECTORS]] = -1; + + prevspritesect[blanktouse] = -1; + nextspritesect[blanktouse] = headspritesect[sectnum]; + if (headspritesect[sectnum] >= 0) + prevspritesect[headspritesect[sectnum]] = blanktouse; + headspritesect[sectnum] = blanktouse; + + sprite[blanktouse].sectnum = sectnum; + + return(blanktouse); +} + + +int insertspritestat(short statnum) +{ + short blanktouse; + + if ((statnum >= MAXSTATUS) || (headspritestat[MAXSTATUS] == -1)) + return(-1); /* list full */ + + blanktouse = headspritestat[MAXSTATUS]; + + headspritestat[MAXSTATUS] = nextspritestat[blanktouse]; + if (headspritestat[MAXSTATUS] >= 0) + prevspritestat[headspritestat[MAXSTATUS]] = -1; + + prevspritestat[blanktouse] = -1; + nextspritestat[blanktouse] = headspritestat[statnum]; + if (headspritestat[statnum] >= 0) + prevspritestat[headspritestat[statnum]] = blanktouse; + headspritestat[statnum] = blanktouse; + + sprite[blanktouse].statnum = statnum; + + return(blanktouse); +} + + +int deletesprite(short spritenum) +{ + deletespritestat(spritenum); + return(deletespritesect(spritenum)); +} + + +int deletespritesect(short deleteme) +{ + if (sprite[deleteme].sectnum == MAXSECTORS) + return(-1); + + if (headspritesect[sprite[deleteme].sectnum] == deleteme) + headspritesect[sprite[deleteme].sectnum] = nextspritesect[deleteme]; + + if (prevspritesect[deleteme] >= 0) nextspritesect[prevspritesect[deleteme]] = nextspritesect[deleteme]; + if (nextspritesect[deleteme] >= 0) prevspritesect[nextspritesect[deleteme]] = prevspritesect[deleteme]; + + if (headspritesect[MAXSECTORS] >= 0) prevspritesect[headspritesect[MAXSECTORS]] = deleteme; + prevspritesect[deleteme] = -1; + nextspritesect[deleteme] = headspritesect[MAXSECTORS]; + headspritesect[MAXSECTORS] = deleteme; + + sprite[deleteme].sectnum = MAXSECTORS; + return(0); +} + + +int deletespritestat(short deleteme) +{ + if (sprite[deleteme].statnum == MAXSTATUS) + return(-1); + + if (headspritestat[sprite[deleteme].statnum] == deleteme) + headspritestat[sprite[deleteme].statnum] = nextspritestat[deleteme]; + + if (prevspritestat[deleteme] >= 0) nextspritestat[prevspritestat[deleteme]] = nextspritestat[deleteme]; + if (nextspritestat[deleteme] >= 0) prevspritestat[nextspritestat[deleteme]] = prevspritestat[deleteme]; + + if (headspritestat[MAXSTATUS] >= 0) prevspritestat[headspritestat[MAXSTATUS]] = deleteme; + prevspritestat[deleteme] = -1; + nextspritestat[deleteme] = headspritestat[MAXSTATUS]; + headspritestat[MAXSTATUS] = deleteme; + + sprite[deleteme].statnum = MAXSTATUS; + return(0); +} + + +int changespritesect(short spritenum, short newsectnum) +{ + if ((newsectnum < 0) || (newsectnum > MAXSECTORS)) return(-1); + if (sprite[spritenum].sectnum == newsectnum) return(0); + if (sprite[spritenum].sectnum == MAXSECTORS) return(-1); + if (deletespritesect(spritenum) < 0) return(-1); + insertspritesect(newsectnum); + return(0); +} + + +int changespritestat(short spritenum, short newstatnum) +{ + if ((newstatnum < 0) || (newstatnum > MAXSTATUS)) return(-1); + if (sprite[spritenum].statnum == newstatnum) return(0); + if (sprite[spritenum].statnum == MAXSTATUS) return(-1); + if (deletespritestat(spritenum) < 0) return(-1); + insertspritestat(newstatnum); + return(0); +} + + +int nextsectorneighborz(short sectnum, long thez, + short topbottom, short direction) +{ + walltype *wal; + long i, testz, nextz; + short sectortouse; + + if (direction == 1) nextz = 0x7fffffff; else nextz = 0x80000000; + + sectortouse = -1; + + wal = &wall[sector[sectnum].wallptr]; + i = sector[sectnum].wallnum; + do + { + if (wal->nextsector >= 0) + { + if (topbottom == 1) + { + testz = sector[wal->nextsector].floorz; + if (direction == 1) + { + if ((testz > thez) && (testz < nextz)) + { + nextz = testz; + sectortouse = wal->nextsector; + } + } + else + { + if ((testz < thez) && (testz > nextz)) + { + nextz = testz; + sectortouse = wal->nextsector; + } + } + } + else + { + testz = sector[wal->nextsector].ceilingz; + if (direction == 1) + { + if ((testz > thez) && (testz < nextz)) + { + nextz = testz; + sectortouse = wal->nextsector; + } + } + else + { + if ((testz < thez) && (testz > nextz)) + { + nextz = testz; + sectortouse = wal->nextsector; + } + } + } + } + wal++; + i--; + } while (i != 0); + + return(sectortouse); +} + + +int cansee(long x1, long y1, long z1, short sect1, + long x2, long y2, long z2, short sect2) +{ + sectortype *sec; + walltype *wal, *wal2; + long i, cnt, nexts, x, y, z, cz, fz, dasectnum, dacnt, danum; + long x21, y21, z21, x31, y31, x34, y34, bot, t; + + if ((x1 == x2) && (y1 == y2)) return(sect1 == sect2); + + x21 = x2-x1; y21 = y2-y1; z21 = z2-z1; + + clipsectorlist[0] = sect1; danum = 1; + for(dacnt=0;dacntwallnum,wal=&wall[sec->wallptr];cnt>0;cnt--,wal++) + { + wal2 = &wall[wal->point2]; + x31 = wal->x-x1; x34 = wal->x-wal2->x; + y31 = wal->y-y1; y34 = wal->y-wal2->y; + + bot = y21*x34-x21*y34; if (bot <= 0) continue; + t = y21*x31-x21*y31; if ((unsigned)t >= (unsigned)bot) continue; + t = y31*x34-x31*y34; if ((unsigned)t >= (unsigned)bot) continue; + + nexts = wal->nextsector; + if ((nexts < 0) || (wal->cstat&32)) return(0); + + t = divscale24(t,bot); + x = x1 + mulscale24(x21,t); + y = y1 + mulscale24(y21,t); + z = z1 + mulscale24(z21,t); + + getzsofslope((short)dasectnum,x,y,&cz,&fz); + if ((z <= cz) || (z >= fz)) return(0); + getzsofslope((short)nexts,x,y,&cz,&fz); + if ((z <= cz) || (z >= fz)) return(0); + + for(i=danum-1;i>=0;i--) if (clipsectorlist[i] == nexts) break; + if (i < 0) clipsectorlist[danum++] = nexts; + } + } + for(i=danum-1;i>=0;i--) if (clipsectorlist[i] == sect2) return(1); + return(0); +} + + +int lintersect(long x1, long y1, long z1, long x2, long y2, long z2, + long x3, long y3, long x4, long y4, long *intx, + long *inty, long *intz) +{ /* p1 to p2 is a line segment */ + long x21, y21, x34, y34, x31, y31, bot, topt, topu, t; + + x21 = x2-x1; x34 = x3-x4; + y21 = y2-y1; y34 = y3-y4; + bot = x21*y34 - y21*x34; + if (bot >= 0) + { + if (bot == 0) return(0); + x31 = x3-x1; y31 = y3-y1; + topt = x31*y34 - y31*x34; if ((topt < 0) || (topt >= bot)) return(0); + topu = x21*y31 - y21*x31; if ((topu < 0) || (topu >= bot)) return(0); + } + else + { + x31 = x3-x1; y31 = y3-y1; + topt = x31*y34 - y31*x34; if ((topt > 0) || (topt <= bot)) return(0); + topu = x21*y31 - y21*x31; if ((topu > 0) || (topu <= bot)) return(0); + } + t = divscale24(topt,bot); + *intx = x1 + mulscale24(x21,t); + *inty = y1 + mulscale24(y21,t); + *intz = z1 + mulscale24(z2-z1,t); + return(1); +} + + +int rintersect(long x1, long y1, long z1, long vx, long vy, long vz, + long x3, long y3, long x4, long y4, long *intx, + long *inty, long *intz) +{ /* p1 towards p2 is a ray */ + long x34, y34, x31, y31, bot, topt, topu, t; + + x34 = x3-x4; y34 = y3-y4; + bot = vx*y34 - vy*x34; + if (bot >= 0) + { + if (bot == 0) return(0); + x31 = x3-x1; y31 = y3-y1; + topt = x31*y34 - y31*x34; if (topt < 0) return(0); + topu = vx*y31 - vy*x31; if ((topu < 0) || (topu >= bot)) return(0); + } + else + { + x31 = x3-x1; y31 = y3-y1; + topt = x31*y34 - y31*x34; if (topt > 0) return(0); + topu = vx*y31 - vy*x31; if ((topu > 0) || (topu <= bot)) return(0); + } + t = divscale16(topt,bot); + *intx = x1 + mulscale16(vx,t); + *inty = y1 + mulscale16(vy,t); + *intz = z1 + mulscale16(vz,t); + return(1); +} + + +int hitscan(long xs, long ys, long zs, short sectnum, + long vx, long vy, long vz, + short *hitsect, short *hitwall, short *hitsprite, + long *hitx, long *hity, long *hitz, unsigned long cliptype) +{ + sectortype *sec; + walltype *wal, *wal2; + spritetype *spr; + long z, zz, x1, y1=0, z1=0, x2, y2, x3, y3, x4, y4, intx, inty, intz; + long topt, topu, bot, dist, offx, offy, cstat; + long i, j, k, l, tilenum, xoff, yoff, dax, day, daz, daz2; + long ang, cosang, sinang, xspan, yspan, xrepeat, yrepeat; + long dawalclipmask, dasprclipmask; + short tempshortcnt, tempshortnum, dasector, startwall, endwall; + short nextsector; + char clipyou; + + *hitsect = -1; *hitwall = -1; *hitsprite = -1; + if (sectnum < 0) return(-1); + + *hitx = hitscangoalx; *hity = hitscangoaly; + + dawalclipmask = (cliptype&65535); + dasprclipmask = (cliptype>>16); + + clipsectorlist[0] = sectnum; + tempshortcnt = 0; tempshortnum = 1; + do + { + dasector = clipsectorlist[tempshortcnt]; sec = §or[dasector]; + + x1 = 0x7fffffff; + if (sec->ceilingstat&2) + { + wal = &wall[sec->wallptr]; wal2 = &wall[wal->point2]; + dax = wal2->x-wal->x; day = wal2->y-wal->y; + i = nsqrtasm(dax*dax+day*day); if (i == 0) continue; + i = divscale15(sec->ceilingheinum,i); + dax *= i; day *= i; + + j = (vz<<8)-dmulscale15(dax,vy,-day,vx); + if (j != 0) + { + i = ((sec->ceilingz-zs)<<8)+dmulscale15(dax,ys-wal->y,-day,xs-wal->x); + if (((i^j) >= 0) && ((klabs(i)>>1) < klabs(j))) + { + i = divscale30(i,j); + x1 = xs + mulscale30(vx,i); + y1 = ys + mulscale30(vy,i); + z1 = zs + mulscale30(vz,i); + } + } + } + else if ((vz < 0) && (zs >= sec->ceilingz)) + { + z1 = sec->ceilingz; i = z1-zs; + if ((klabs(i)>>1) < -vz) + { + i = divscale30(i,vz); + x1 = xs + mulscale30(vx,i); + y1 = ys + mulscale30(vy,i); + } + } + if ((x1 != 0x7fffffff) && (klabs(x1-xs)+klabs(y1-ys) < klabs((*hitx)-xs)+klabs((*hity)-ys))) + if (inside(x1,y1,dasector) != 0) + { + *hitsect = dasector; *hitwall = -1; *hitsprite = -1; + *hitx = x1; *hity = y1; *hitz = z1; + } + + x1 = 0x7fffffff; + if (sec->floorstat&2) + { + wal = &wall[sec->wallptr]; wal2 = &wall[wal->point2]; + dax = wal2->x-wal->x; day = wal2->y-wal->y; + i = nsqrtasm(dax*dax+day*day); if (i == 0) continue; + i = divscale15(sec->floorheinum,i); + dax *= i; day *= i; + + j = (vz<<8)-dmulscale15(dax,vy,-day,vx); + if (j != 0) + { + i = ((sec->floorz-zs)<<8)+dmulscale15(dax,ys-wal->y,-day,xs-wal->x); + if (((i^j) >= 0) && ((klabs(i)>>1) < klabs(j))) + { + i = divscale30(i,j); + x1 = xs + mulscale30(vx,i); + y1 = ys + mulscale30(vy,i); + z1 = zs + mulscale30(vz,i); + } + } + } + else if ((vz > 0) && (zs <= sec->floorz)) + { + z1 = sec->floorz; i = z1-zs; + if ((klabs(i)>>1) < vz) + { + i = divscale30(i,vz); + x1 = xs + mulscale30(vx,i); + y1 = ys + mulscale30(vy,i); + } + } + if ((x1 != 0x7fffffff) && (klabs(x1-xs)+klabs(y1-ys) < klabs((*hitx)-xs)+klabs((*hity)-ys))) + if (inside(x1,y1,dasector) != 0) + { + *hitsect = dasector; *hitwall = -1; *hitsprite = -1; + *hitx = x1; *hity = y1; *hitz = z1; + } + + startwall = sec->wallptr; endwall = startwall + sec->wallnum; + for(z=startwall,wal=&wall[startwall];zpoint2]; + x1 = wal->x; y1 = wal->y; x2 = wal2->x; y2 = wal2->y; + + if ((x1-xs)*(y2-ys) < (x2-xs)*(y1-ys)) continue; + if (rintersect(xs,ys,zs,vx,vy,vz,x1,y1,x2,y2,&intx,&inty,&intz) == 0) continue; + + if (klabs(intx-xs)+klabs(inty-ys) >= klabs((*hitx)-xs)+klabs((*hity)-ys)) continue; + + nextsector = wal->nextsector; + if ((nextsector < 0) || (wal->cstat&dawalclipmask)) + { + *hitsect = dasector; *hitwall = z; *hitsprite = -1; + *hitx = intx; *hity = inty; *hitz = intz; + continue; + } + getzsofslope(nextsector,intx,inty,&daz,&daz2); + if ((intz <= daz) || (intz >= daz2)) + { + *hitsect = dasector; *hitwall = z; *hitsprite = -1; + *hitx = intx; *hity = inty; *hitz = intz; + continue; + } + + for(zz=tempshortnum-1;zz>=0;zz--) + if (clipsectorlist[zz] == nextsector) break; + if (zz < 0) clipsectorlist[tempshortnum++] = nextsector; + } + + for(z=headspritesect[dasector];z>=0;z=nextspritesect[z]) + { + spr = &sprite[z]; + cstat = spr->cstat; + if ((cstat&dasprclipmask) == 0) continue; + + x1 = spr->x; y1 = spr->y; z1 = spr->z; + switch(cstat&48) + { + case 0: + topt = vx*(x1-xs) + vy*(y1-ys); if (topt <= 0) continue; + bot = vx*vx + vy*vy; if (bot == 0) continue; + + intz = zs+scale(vz,topt,bot); + + i = (tilesizy[spr->picnum]*spr->yrepeat<<2); + if (cstat&128) z1 += (i>>1); + if (picanm[spr->picnum]&0x00ff0000) z1 -= ((long)((signed char)((picanm[spr->picnum]>>16)&255))*spr->yrepeat<<2); + if ((intz > z1) || (intz < z1-i)) continue; + topu = vx*(y1-ys) - vy*(x1-xs); + + offx = scale(vx,topu,bot); + offy = scale(vy,topu,bot); + dist = offx*offx + offy*offy; + i = tilesizx[spr->picnum]*spr->xrepeat; i *= i; + if (dist > (i>>7)) continue; + intx = xs + scale(vx,topt,bot); + inty = ys + scale(vy,topt,bot); + + if (klabs(intx-xs)+klabs(inty-ys) > klabs((*hitx)-xs)+klabs((*hity)-ys)) continue; + + *hitsect = dasector; *hitwall = -1; *hitsprite = z; + *hitx = intx; *hity = inty; *hitz = intz; + break; + case 16: + /* + * These lines get the 2 points of the rotated sprite + * Given: (x1, y1) starts out as the center point + */ + tilenum = spr->picnum; + xoff = (long)((signed char)((picanm[tilenum]>>8)&255))+((long)spr->xoffset); + if ((cstat&4) > 0) xoff = -xoff; + k = spr->ang; l = spr->xrepeat; + dax = sintable[k&2047]*l; day = sintable[(k+1536)&2047]*l; + l = tilesizx[tilenum]; k = (l>>1)+xoff; + x1 -= mulscale16(dax,k); x2 = x1+mulscale16(dax,l); + y1 -= mulscale16(day,k); y2 = y1+mulscale16(day,l); + + if ((cstat&64) != 0) /* back side of 1-way sprite */ + if ((x1-xs)*(y2-ys) < (x2-xs)*(y1-ys)) continue; + + if (rintersect(xs,ys,zs,vx,vy,vz,x1,y1,x2,y2,&intx,&inty,&intz) == 0) continue; + + if (klabs(intx-xs)+klabs(inty-ys) > klabs((*hitx)-xs)+klabs((*hity)-ys)) continue; + + k = ((tilesizy[spr->picnum]*spr->yrepeat)<<2); + if (cstat&128) daz = spr->z+(k>>1); else daz = spr->z; + if (picanm[spr->picnum]&0x00ff0000) daz -= ((long)((signed char)((picanm[spr->picnum]>>16)&255))*spr->yrepeat<<2); + if ((intz < daz) && (intz > daz-k)) + { + *hitsect = dasector; *hitwall = -1; *hitsprite = z; + *hitx = intx; *hity = inty; *hitz = intz; + } + break; + case 32: + if (vz == 0) continue; + intz = z1; + if (((intz-zs)^vz) < 0) continue; + if ((cstat&64) != 0) + if ((zs > intz) == ((cstat&8)==0)) continue; + + intx = xs+scale(intz-zs,vx,vz); + inty = ys+scale(intz-zs,vy,vz); + + if (klabs(intx-xs)+klabs(inty-ys) > klabs((*hitx)-xs)+klabs((*hity)-ys)) continue; + + tilenum = spr->picnum; + xoff = (long)((signed char)((picanm[tilenum]>>8)&255))+((long)spr->xoffset); + yoff = (long)((signed char)((picanm[tilenum]>>16)&255))+((long)spr->yoffset); + if ((cstat&4) > 0) xoff = -xoff; + if ((cstat&8) > 0) yoff = -yoff; + + ang = spr->ang; + cosang = sintable[(ang+512)&2047]; sinang = sintable[ang]; + xspan = tilesizx[tilenum]; xrepeat = spr->xrepeat; + yspan = tilesizy[tilenum]; yrepeat = spr->yrepeat; + + dax = ((xspan>>1)+xoff)*xrepeat; day = ((yspan>>1)+yoff)*yrepeat; + x1 += dmulscale16(sinang,dax,cosang,day)-intx; + y1 += dmulscale16(sinang,day,-cosang,dax)-inty; + l = xspan*xrepeat; + x2 = x1 - mulscale16(sinang,l); + y2 = y1 + mulscale16(cosang,l); + l = yspan*yrepeat; + k = -mulscale16(cosang,l); x3 = x2+k; x4 = x1+k; + k = -mulscale16(sinang,l); y3 = y2+k; y4 = y1+k; + + clipyou = 0; + if ((y1^y2) < 0) + { + if ((x1^x2) < 0) clipyou ^= (x1*y2= 0) clipyou ^= 1; + } + if ((y2^y3) < 0) + { + if ((x2^x3) < 0) clipyou ^= (x2*y3= 0) clipyou ^= 1; + } + if ((y3^y4) < 0) + { + if ((x3^x4) < 0) clipyou ^= (x3*y4= 0) clipyou ^= 1; + } + if ((y4^y1) < 0) + { + if ((x4^x1) < 0) clipyou ^= (x4*y1= 0) clipyou ^= 1; + } + + if (clipyou != 0) + { + *hitsect = dasector; *hitwall = -1; *hitsprite = z; + *hitx = intx; *hity = inty; *hitz = intz; + } + break; + } + } + tempshortcnt++; + } while (tempshortcnt < tempshortnum); + return(0); +} + + +int neartag(long xs, long ys, long zs, short sectnum, short ange, + short *neartagsector, short *neartagwall, short *neartagsprite, + long *neartaghitdist, long neartagrange, char tagsearch) +{ + walltype *wal, *wal2; + spritetype *spr; + long i, z, zz, xe, ye, ze, x1, y1, z1, x2, y2, intx, inty, intz; + long topt, topu, bot, dist, offx, offy, vx, vy, vz; + short tempshortcnt, tempshortnum, dasector, startwall, endwall; + short nextsector, good; + + *neartagsector = -1; *neartagwall = -1; *neartagsprite = -1; + *neartaghitdist = 0; + + if (sectnum < 0) return(0); + if ((tagsearch < 1) || (tagsearch > 3)) return(0); + + vx = mulscale14(sintable[(ange+2560)&2047],neartagrange); xe = xs+vx; + vy = mulscale14(sintable[(ange+2048)&2047],neartagrange); ye = ys+vy; + vz = 0; ze = 0; + + clipsectorlist[0] = sectnum; + tempshortcnt = 0; tempshortnum = 1; + + do + { + dasector = clipsectorlist[tempshortcnt]; + + startwall = sector[dasector].wallptr; + endwall = startwall + sector[dasector].wallnum - 1; + for(z=startwall,wal=&wall[startwall];z<=endwall;z++,wal++) + { + wal2 = &wall[wal->point2]; + x1 = wal->x; y1 = wal->y; x2 = wal2->x; y2 = wal2->y; + + nextsector = wal->nextsector; + + good = 0; + if (nextsector >= 0) + { + if ((tagsearch&1) && sector[nextsector].lotag) good |= 1; + if ((tagsearch&2) && sector[nextsector].hitag) good |= 1; + } + if ((tagsearch&1) && wal->lotag) good |= 2; + if ((tagsearch&2) && wal->hitag) good |= 2; + + if ((good == 0) && (nextsector < 0)) continue; + if ((x1-xs)*(y2-ys) < (x2-xs)*(y1-ys)) continue; + + if (lintersect(xs,ys,zs,xe,ye,ze,x1,y1,x2,y2,&intx,&inty,&intz) == 1) + { + if (good != 0) + { + if (good&1) *neartagsector = nextsector; + if (good&2) *neartagwall = z; + *neartaghitdist = dmulscale14(intx-xs,sintable[(ange+2560)&2047],inty-ys,sintable[(ange+2048)&2047]); + xe = intx; ye = inty; ze = intz; + } + if (nextsector >= 0) + { + for(zz=tempshortnum-1;zz>=0;zz--) + if (clipsectorlist[zz] == nextsector) break; + if (zz < 0) clipsectorlist[tempshortnum++] = nextsector; + } + } + } + + for(z=headspritesect[dasector];z>=0;z=nextspritesect[z]) + { + spr = &sprite[z]; + + good = 0; + if ((tagsearch&1) && spr->lotag) good |= 1; + if ((tagsearch&2) && spr->hitag) good |= 1; + if (good != 0) + { + x1 = spr->x; y1 = spr->y; z1 = spr->z; + + topt = vx*(x1-xs) + vy*(y1-ys); + if (topt > 0) + { + bot = vx*vx + vy*vy; + if (bot != 0) + { + intz = zs+scale(vz,topt,bot); + i = tilesizy[spr->picnum]*spr->yrepeat; + if (spr->cstat&128) z1 += (i<<1); + if (picanm[spr->picnum]&0x00ff0000) z1 -= ((long)((signed char)((picanm[spr->picnum]>>16)&255))*spr->yrepeat<<2); + if ((intz <= z1) && (intz >= z1-(i<<2))) + { + topu = vx*(y1-ys) - vy*(x1-xs); + + offx = scale(vx,topu,bot); + offy = scale(vy,topu,bot); + dist = offx*offx + offy*offy; + i = (tilesizx[spr->picnum]*spr->xrepeat); i *= i; + if (dist <= (i>>7)) + { + intx = xs + scale(vx,topt,bot); + inty = ys + scale(vy,topt,bot); + if (klabs(intx-xs)+klabs(inty-ys) < klabs(xe-xs)+klabs(ye-ys)) + { + *neartagsprite = z; + *neartaghitdist = dmulscale14(intx-xs,sintable[(ange+2560)&2047],inty-ys,sintable[(ange+2048)&2047]); + xe = intx; + ye = inty; + ze = intz; + } + } + } + } + } + } + } + + tempshortcnt++; + } while (tempshortcnt < tempshortnum); + return(0); +} + + +void dragpoint(short pointhighlight, long dax, long day) +{ + short cnt, tempshort; + + wall[pointhighlight].x = dax; + wall[pointhighlight].y = day; + + cnt = MAXWALLS; + tempshort = pointhighlight; /* search points CCW */ + do + { + if (wall[tempshort].nextwall >= 0) + { + tempshort = wall[wall[tempshort].nextwall].point2; + wall[tempshort].x = dax; + wall[tempshort].y = day; + } + else + { + tempshort = pointhighlight; /* search points CW if not searched all the way around */ + do + { + if (wall[lastwall(tempshort)].nextwall >= 0) + { + tempshort = wall[lastwall(tempshort)].nextwall; + wall[tempshort].x = dax; + wall[tempshort].y = day; + } + else + { + break; + } + cnt--; + } + while ((tempshort != pointhighlight) && (cnt > 0)); + break; + } + cnt--; + } + while ((tempshort != pointhighlight) && (cnt > 0)); +} + + +int lastwall(short point) +{ + long i, j, cnt; + + if ((point > 0) && (wall[point-1].point2 == point)) return(point-1); + i = point; + cnt = MAXWALLS; + do + { + j = wall[i].point2; + if (j == point) return(i); + i = j; + cnt--; + } while (cnt > 0); + return(point); +} + +#define addclipline(dax1, day1, dax2, day2, daoval) \ +{ \ + clipit[clipnum].x1 = dax1; clipit[clipnum].y1 = day1; \ + clipit[clipnum].x2 = dax2; clipit[clipnum].y2 = day2; \ + clipobjectval[clipnum] = daoval; \ + clipnum++; \ +} \ + + +static void keepaway (long *x, long *y, long w) +{ + long dx, dy, ox, oy, x1, y1; + char first; + + x1 = clipit[w].x1; dx = clipit[w].x2-x1; + y1 = clipit[w].y1; dy = clipit[w].y2-y1; + ox = ksgn(-dy); oy = ksgn(dx); + first = (klabs(dx) <= klabs(dy)); + while (1) + { + if (dx*(*y-y1) > (*x-x1)*dy) return; + if (first == 0) *x += ox; else *y += oy; + first ^= 1; + } +} + + +static int raytrace(long x3, long y3, long *x4, long *y4) +{ + long x1, y1, x2, y2, bot, topu, nintx, ninty, cnt, z, hitwall; + long x21, y21, x43, y43; + + hitwall = -1; + for(z=clipnum-1;z>=0;z--) + { + x1 = clipit[z].x1; x2 = clipit[z].x2; x21 = x2-x1; + y1 = clipit[z].y1; y2 = clipit[z].y2; y21 = y2-y1; + + topu = x21*(y3-y1) - (x3-x1)*y21; if (topu <= 0) continue; + if (x21*(*y4-y1) > (*x4-x1)*y21) continue; + x43 = *x4-x3; y43 = *y4-y3; + if (x43*(y1-y3) > (x1-x3)*y43) continue; + if (x43*(y2-y3) <= (x2-x3)*y43) continue; + bot = x43*y21 - x21*y43; if (bot == 0) continue; + + cnt = 256; + do + { + cnt--; if (cnt < 0) { *x4 = x3; *y4 = y3; return(z); } + nintx = x3 + scale(x43,topu,bot); + ninty = y3 + scale(y43,topu,bot); + topu--; + } while (x21*(ninty-y1) <= (nintx-x1)*y21); + + if (klabs(x3-nintx)+klabs(y3-ninty) < klabs(x3-*x4)+klabs(y3-*y4)) + { *x4 = nintx; *y4 = ninty; hitwall = z; } + } + return(hitwall); +} + + +/* !!! ugh...move this var into clipmove as a parameter, and update build2.txt! */ +long clipmoveboxtracenum = 3; +int clipmove (long *x, long *y, long *z, short *sectnum, + long xvect, long yvect, long walldist, long ceildist, + long flordist, unsigned long cliptype) +{ + walltype *wal, *wal2; + spritetype *spr; + sectortype *sec, *sec2; + long i, j, templong1, templong2; + long oxvect, oyvect, goalx, goaly, intx, inty, lx, ly, retval; + long k, l, clipsectcnt, startwall, endwall, cstat, dasect; + long x1, y1, x2, y2, cx, cy, rad, xmin, ymin, xmax, ymax, daz, daz2; + long bsz, dax, day, xoff, yoff, xspan, yspan, cosang, sinang, tilenum; + long xrepeat, yrepeat, gx, gy, dx, dy, dasprclipmask, dawalclipmask; + long hitwall, cnt, clipyou; + + if (((xvect|yvect) == 0) || (*sectnum < 0)) return(0); + retval = 0; + + oxvect = xvect; + oyvect = yvect; + + goalx = (*x) + (xvect>>14); + goaly = (*y) + (yvect>>14); + + + clipnum = 0; + + cx = (((*x)+goalx)>>1); + cy = (((*y)+goaly)>>1); + /* Extra walldist for sprites on sector lines */ + gx = goalx-(*x); gy = goaly-(*y); + rad = nsqrtasm(gx*gx + gy*gy) + MAXCLIPDIST+walldist + 8; + xmin = cx-rad; ymin = cy-rad; + xmax = cx+rad; ymax = cy+rad; + + dawalclipmask = (cliptype&65535); /* CLIPMASK0 = 0x00010001 */ + dasprclipmask = (cliptype>>16); /* CLIPMASK1 = 0x01000040 */ + + clipsectorlist[0] = (*sectnum); + clipsectcnt = 0; clipsectnum = 1; + do + { + dasect = clipsectorlist[clipsectcnt++]; + sec = §or[dasect]; + startwall = sec->wallptr; endwall = startwall + sec->wallnum; + for(j=startwall,wal=&wall[startwall];jpoint2]; + if ((wal->x < xmin) && (wal2->x < xmin)) continue; + if ((wal->x > xmax) && (wal2->x > xmax)) continue; + if ((wal->y < ymin) && (wal2->y < ymin)) continue; + if ((wal->y > ymax) && (wal2->y > ymax)) continue; + + x1 = wal->x; y1 = wal->y; x2 = wal2->x; y2 = wal2->y; + + dx = x2-x1; dy = y2-y1; + if (dx*((*y)-y1) < ((*x)-x1)*dy) continue; /* If wall's not facing you */ + + if (dx > 0) dax = dx*(ymin-y1); else dax = dx*(ymax-y1); + if (dy > 0) day = dy*(xmax-x1); else day = dy*(xmin-x1); + if (dax >= day) continue; + + clipyou = 0; + if ((wal->nextsector < 0) || (wal->cstat&dawalclipmask)) clipyou = 1; + else if (editstatus == 0) + { + if (rintersect(*x,*y,0,gx,gy,0,x1,y1,x2,y2,&dax,&day,&daz) == 0) + dax = *x, day = *y; + daz = getflorzofslope((short)dasect,dax,day); + daz2 = getflorzofslope(wal->nextsector,dax,day); + + sec2 = §or[wal->nextsector]; + if (daz2 < daz-(1<<8)) + if ((sec2->floorstat&1) == 0) + if ((*z) >= daz2-(flordist-1)) clipyou = 1; + if (clipyou == 0) + { + daz = getceilzofslope((short)dasect,dax,day); + daz2 = getceilzofslope(wal->nextsector,dax,day); + if (daz2 > daz+(1<<8)) + if ((sec2->ceilingstat&1) == 0) + if ((*z) <= daz2+(ceildist-1)) clipyou = 1; + } + } + + if (clipyou) + { + /* Add 2 boxes at endpoints */ + bsz = walldist; if (gx < 0) bsz = -bsz; + addclipline(x1-bsz,y1-bsz,x1-bsz,y1+bsz,(short)j+32768); + addclipline(x2-bsz,y2-bsz,x2-bsz,y2+bsz,(short)j+32768); + bsz = walldist; if (gy < 0) bsz = -bsz; + addclipline(x1+bsz,y1-bsz,x1-bsz,y1-bsz,(short)j+32768); + addclipline(x2+bsz,y2-bsz,x2-bsz,y2-bsz,(short)j+32768); + + dax = walldist; if (dy > 0) dax = -dax; + day = walldist; if (dx < 0) day = -day; + addclipline(x1+dax,y1+day,x2+dax,y2+day,(short)j+32768); + } + else + { + for(i=clipsectnum-1;i>=0;i--) + if (wal->nextsector == clipsectorlist[i]) break; + if (i < 0) clipsectorlist[clipsectnum++] = wal->nextsector; + } + } + + for(j=headspritesect[dasect];j>=0;j=nextspritesect[j]) + { + spr = &sprite[j]; + cstat = spr->cstat; + if ((cstat&dasprclipmask) == 0) continue; + x1 = spr->x; y1 = spr->y; + switch(cstat&48) + { + case 0: + if ((x1 >= xmin) && (x1 <= xmax) && (y1 >= ymin) && (y1 <= ymax)) + { + k = ((tilesizy[spr->picnum]*spr->yrepeat)<<2); + if (cstat&128) daz = spr->z+(k>>1); else daz = spr->z; + if (picanm[spr->picnum]&0x00ff0000) daz -= ((long)((signed char)((picanm[spr->picnum]>>16)&255))*spr->yrepeat<<2); + if (((*z) < daz+ceildist) && ((*z) > daz-k-flordist)) + { + bsz = (spr->clipdist<<2)+walldist; if (gx < 0) bsz = -bsz; + addclipline(x1-bsz,y1-bsz,x1-bsz,y1+bsz,(short)j+49152); + bsz = (spr->clipdist<<2)+walldist; if (gy < 0) bsz = -bsz; + addclipline(x1+bsz,y1-bsz,x1-bsz,y1-bsz,(short)j+49152); + } + } + break; + case 16: + k = ((tilesizy[spr->picnum]*spr->yrepeat)<<2); + if (cstat&128) daz = spr->z+(k>>1); else daz = spr->z; + if (picanm[spr->picnum]&0x00ff0000) daz -= ((long)((signed char)((picanm[spr->picnum]>>16)&255))*spr->yrepeat<<2); + daz2 = daz-k; + daz += ceildist; daz2 -= flordist; + if (((*z) < daz) && ((*z) > daz2)) + { + /* + * These lines get the 2 points of the rotated sprite + * Given: (x1, y1) starts out as the center point + */ + tilenum = spr->picnum; + xoff = (long)((signed char)((picanm[tilenum]>>8)&255))+((long)spr->xoffset); + if ((cstat&4) > 0) xoff = -xoff; + k = spr->ang; l = spr->xrepeat; + dax = sintable[k&2047]*l; day = sintable[(k+1536)&2047]*l; + l = tilesizx[tilenum]; k = (l>>1)+xoff; + x1 -= mulscale16(dax,k); x2 = x1+mulscale16(dax,l); + y1 -= mulscale16(day,k); y2 = y1+mulscale16(day,l); + if (clipinsideboxline(cx,cy,x1,y1,x2,y2,rad) != 0) + { + dax = mulscale14(sintable[(spr->ang+256+512)&2047],walldist); + day = mulscale14(sintable[(spr->ang+256)&2047],walldist); + + if ((x1-(*x))*(y2-(*y)) >= (x2-(*x))*(y1-(*y))) /* Front */ + { + addclipline(x1+dax,y1+day,x2+day,y2-dax,(short)j+49152); + } + else + { + if ((cstat&64) != 0) continue; + addclipline(x2-dax,y2-day,x1-day,y1+dax,(short)j+49152); + } + + /* Side blocker */ + if ((x2-x1)*((*x)-x1) + (y2-y1)*((*y)-y1) < 0) + { addclipline(x1-day,y1+dax,x1+dax,y1+day,(short)j+49152); } + else if ((x1-x2)*((*x)-x2) + (y1-y2)*((*y)-y2) < 0) + { addclipline(x2+day,y2-dax,x2-dax,y2-day,(short)j+49152); } + } + } + break; + case 32: + daz = spr->z+ceildist; + daz2 = spr->z-flordist; + if (((*z) < daz) && ((*z) > daz2)) + { + if ((cstat&64) != 0) + if (((*z) > spr->z) == ((cstat&8)==0)) continue; + + tilenum = spr->picnum; + xoff = (long)((signed char)((picanm[tilenum]>>8)&255))+((long)spr->xoffset); + yoff = (long)((signed char)((picanm[tilenum]>>16)&255))+((long)spr->yoffset); + if ((cstat&4) > 0) xoff = -xoff; + if ((cstat&8) > 0) yoff = -yoff; + + k = spr->ang; + cosang = sintable[(k+512)&2047]; sinang = sintable[k]; + xspan = tilesizx[tilenum]; xrepeat = spr->xrepeat; + yspan = tilesizy[tilenum]; yrepeat = spr->yrepeat; + + dax = ((xspan>>1)+xoff)*xrepeat; day = ((yspan>>1)+yoff)*yrepeat; + rxi[0] = x1 + dmulscale16(sinang,dax,cosang,day); + ryi[0] = y1 + dmulscale16(sinang,day,-cosang,dax); + l = xspan*xrepeat; + rxi[1] = rxi[0] - mulscale16(sinang,l); + ryi[1] = ryi[0] + mulscale16(cosang,l); + l = yspan*yrepeat; + k = -mulscale16(cosang,l); rxi[2] = rxi[1]+k; rxi[3] = rxi[0]+k; + k = -mulscale16(sinang,l); ryi[2] = ryi[1]+k; ryi[3] = ryi[0]+k; + + dax = mulscale14(sintable[(spr->ang-256+512)&2047],walldist); + day = mulscale14(sintable[(spr->ang-256)&2047],walldist); + + if ((rxi[0]-(*x))*(ryi[1]-(*y)) < (rxi[1]-(*x))*(ryi[0]-(*y))) + { + if (clipinsideboxline(cx,cy,rxi[1],ryi[1],rxi[0],ryi[0],rad) != 0) + addclipline(rxi[1]-day,ryi[1]+dax,rxi[0]+dax,ryi[0]+day,(short)j+49152); + } + else if ((rxi[2]-(*x))*(ryi[3]-(*y)) < (rxi[3]-(*x))*(ryi[2]-(*y))) + { + if (clipinsideboxline(cx,cy,rxi[3],ryi[3],rxi[2],ryi[2],rad) != 0) + addclipline(rxi[3]+day,ryi[3]-dax,rxi[2]-dax,ryi[2]-day,(short)j+49152); + } + + if ((rxi[1]-(*x))*(ryi[2]-(*y)) < (rxi[2]-(*x))*(ryi[1]-(*y))) + { + if (clipinsideboxline(cx,cy,rxi[2],ryi[2],rxi[1],ryi[1],rad) != 0) + addclipline(rxi[2]-dax,ryi[2]-day,rxi[1]-day,ryi[1]+dax,(short)j+49152); + } + else if ((rxi[3]-(*x))*(ryi[0]-(*y)) < (rxi[0]-(*x))*(ryi[3]-(*y))) + { + if (clipinsideboxline(cx,cy,rxi[0],ryi[0],rxi[3],ryi[3],rad) != 0) + addclipline(rxi[0]+dax,ryi[0]+day,rxi[3]+day,ryi[3]-dax,(short)j+49152); + } + } + break; + } + } + } while (clipsectcnt < clipsectnum); + + + hitwall = 0; + cnt = clipmoveboxtracenum; + do + { + intx = goalx; inty = goaly; + if ((hitwall = raytrace(*x, *y, &intx, &inty)) >= 0) + { + lx = clipit[hitwall].x2-clipit[hitwall].x1; + ly = clipit[hitwall].y2-clipit[hitwall].y1; + templong2 = lx*lx + ly*ly; + if (templong2 > 0) + { + templong1 = (goalx-intx)*lx + (goaly-inty)*ly; + + if ((klabs(templong1)>>11) < templong2) + i = divscale20(templong1,templong2); + else + i = 0; + goalx = mulscale20(lx,i)+intx; + goaly = mulscale20(ly,i)+inty; + } + + templong1 = dmulscale6(lx,oxvect,ly,oyvect); + for(i=cnt+1;i<=clipmoveboxtracenum;i++) + { + j = hitwalls[i]; + templong2 = dmulscale6(clipit[j].x2-clipit[j].x1,oxvect,clipit[j].y2-clipit[j].y1,oyvect); + if ((templong1^templong2) < 0) + { + updatesector(*x,*y,sectnum); + return(retval); + } + } + + keepaway(&goalx, &goaly, hitwall); + xvect = ((goalx-intx)<<14); + yvect = ((goaly-inty)<<14); + + if (cnt == clipmoveboxtracenum) retval = clipobjectval[hitwall]; + hitwalls[cnt] = hitwall; + } + cnt--; + + *x = intx; + *y = inty; + } while (((xvect|yvect) != 0) && (hitwall >= 0) && (cnt > 0)); + + for(j=0;j=0;j--) + if (inside(*x,*y,j) == 1) + { + if (sector[j].ceilingstat&2) + templong2 = (getceilzofslope((short)j,*x,*y)-(*z)); + else + templong2 = (sector[j].ceilingz-(*z)); + + if (templong2 > 0) + { + if (templong2 < templong1) + { *sectnum = j; templong1 = templong2; } + } + else + { + if (sector[j].floorstat&2) + templong2 = ((*z)-getflorzofslope((short)j,*x,*y)); + else + templong2 = ((*z)-sector[j].floorz); + + if (templong2 <= 0) + { + *sectnum = j; + return(retval); + } + if (templong2 < templong1) + { *sectnum = j; templong1 = templong2; } + } + } + + return(retval); +} + + +int pushmove(long *x, long *y, long *z, short *sectnum, + long walldist, long ceildist, long flordist, + unsigned long cliptype) +{ + sectortype *sec, *sec2; + walltype *wal; + long i, j, k, t, dx, dy, dax, day, daz, daz2, bad, dir; + long dasprclipmask, dawalclipmask; + short startwall, endwall, clipsectcnt; + char bad2; + + if ((*sectnum) < 0) return(-1); + + dawalclipmask = (cliptype&65535); + dasprclipmask = (cliptype>>16); + + k = 32; + dir = 1; + do + { + bad = 0; + + clipsectorlist[0] = *sectnum; + clipsectcnt = 0; clipsectnum = 1; + do + { + +#if 0 + /*Push FACE sprites */ + for(i=headspritesect[clipsectorlist[clipsectcnt]];i>=0;i=nextspritesect[i]) + { + spr = &sprite[i]; + if (((spr->cstat&48) != 0) && ((spr->cstat&48) != 48)) continue; + if ((spr->cstat&dasprclipmask) == 0) continue; + + dax = (*x)-spr->x; day = (*y)-spr->y; + t = (spr->clipdist<<2)+walldist; + if ((klabs(dax) < t) && (klabs(day) < t)) + { + t = ((tilesizy[spr->picnum]*spr->yrepeat)<<2); + if (spr->cstat&128) daz = spr->z+(t>>1); else daz = spr->z; + if (picanm[spr->picnum]&0x00ff0000) daz -= ((long)((signed char)((picanm[spr->picnum]>>16)&255))*spr->yrepeat<<2); + if (((*z) < daz+ceildist) && ((*z) > daz-t-flordist)) + { + t = (spr->clipdist<<2)+walldist; + + j = getangle(dax,day); + dx = (sintable[(j+512)&2047]>>11); + dy = (sintable[(j)&2047]>>11); + bad2 = 16; + do + { + *x = (*x) + dx; *y = (*y) + dy; + bad2--; if (bad2 == 0) break; + } while ((klabs((*x)-spr->x) < t) && (klabs((*y)-spr->y) < t)); + bad = -1; + k--; if (k <= 0) return(bad); + updatesector(*x,*y,sectnum); + } + } + } +#endif + + sec = §or[clipsectorlist[clipsectcnt]]; + if (dir > 0) + startwall = sec->wallptr, endwall = startwall + sec->wallnum; + else + endwall = sec->wallptr, startwall = endwall + sec->wallnum; + + for(i=startwall,wal=&wall[startwall];i!=endwall;i+=dir,wal+=dir) + if (clipinsidebox(*x,*y,i,walldist-4) == 1) + { + j = 0; + if (wal->nextsector < 0) j = 1; + if (wal->cstat&dawalclipmask) j = 1; + if (j == 0) + { + sec2 = §or[wal->nextsector]; + + + /* Find closest point on wall (dax, day) to (*x, *y) */ + dax = wall[wal->point2].x-wal->x; + day = wall[wal->point2].y-wal->y; + daz = dax*((*x)-wal->x) + day*((*y)-wal->y); + if (daz <= 0) + t = 0; + else + { + daz2 = dax*dax+day*day; + if (daz >= daz2) t = (1<<30); else t = divscale30(daz,daz2); + } + dax = wal->x + mulscale30(dax,t); + day = wal->y + mulscale30(day,t); + + + daz = getflorzofslope(clipsectorlist[clipsectcnt],dax,day); + daz2 = getflorzofslope(wal->nextsector,dax,day); + if ((daz2 < daz-(1<<8)) && ((sec2->floorstat&1) == 0)) + if (*z >= daz2-(flordist-1)) j = 1; + + daz = getceilzofslope(clipsectorlist[clipsectcnt],dax,day); + daz2 = getceilzofslope(wal->nextsector,dax,day); + if ((daz2 > daz+(1<<8)) && ((sec2->ceilingstat&1) == 0)) + if (*z <= daz2+(ceildist-1)) j = 1; + } + if (j != 0) + { + j = getangle(wall[wal->point2].x-wal->x,wall[wal->point2].y-wal->y); + dx = (sintable[(j+1024)&2047]>>11); + dy = (sintable[(j+512)&2047]>>11); + bad2 = 16; + do + { + *x = (*x) + dx; *y = (*y) + dy; + bad2--; if (bad2 == 0) break; + } while (clipinsidebox(*x,*y,i,walldist-4) != 0); + bad = -1; + k--; if (k <= 0) return(bad); + updatesector(*x,*y,sectnum); + } + else + { + for(j=clipsectnum-1;j>=0;j--) + if (wal->nextsector == clipsectorlist[j]) break; + if (j < 0) clipsectorlist[clipsectnum++] = wal->nextsector; + } + } + + clipsectcnt++; + } while (clipsectcnt < clipsectnum); + dir = -dir; + } while (bad != 0); + + return(bad); +} + + +void updatesector(long x, long y, short *sectnum) +{ + walltype *wal; + long i, j; + + if (inside(x,y,*sectnum) == 1) return; + + if ((*sectnum >= 0) && (*sectnum < numsectors)) + { + wal = &wall[sector[*sectnum].wallptr]; + j = sector[*sectnum].wallnum; + do + { + i = wal->nextsector; + if (i >= 0) + if (inside(x,y,(short)i) == 1) + { + *sectnum = i; + return; + } + wal++; + j--; + } while (j != 0); + } + + for(i=numsectors-1;i>=0;i--) + if (inside(x,y,(short)i) == 1) + { + *sectnum = i; + return; + } + + *sectnum = -1; +} + + +void rotatepoint(long xpivot, long ypivot, long x, long y, short daang, long *x2, long *y2) +{ + long dacos, dasin; + + dacos = sintable[(daang+2560)&2047]; + dasin = sintable[(daang+2048)&2047]; + x -= xpivot; + y -= ypivot; + *x2 = dmulscale14(x,dacos,-y,dasin) + xpivot; + *y2 = dmulscale14(y,dacos,x,dasin) + ypivot; +} + + +int initmouse(void) +{ + return(moustat = setupmouse()); +} + + +void getmousevalues(short *mousx, short *mousy, short *bstatus) +{ + if (moustat == 0) { *mousx = 0; *mousy = 0; *bstatus = 0; return; } + readmousexy(mousx,mousy); + readmousebstatus(bstatus); +} + +void draw2dgrid(long posxe, long posye, short ange, long zoome, short gride) +{ + long i, xp1, yp1, xp2=0, yp2, tempy, templong; + char mask; + + if (gride > 0) + { + yp1 = 200-mulscale14(posye+131072,zoome); + if (yp1 < 0) yp1 = 0; + yp2 = 200-mulscale14(posye-131072,zoome); + if (yp2 >= ydim16) yp2 = ydim16-1; + + if ((yp1 < ydim16) && (yp2 >= 0) && (yp2 >= yp1)) + { + setcolor16(8); + #ifdef PLATFORM_DOS + koutp(0x3ce,0x8); + #endif + templong = ((yp1*640+pageoffset)>>3)+(long)_getVideoBase(); + tempy = yp2-yp1+1; + mask = 0; + xp1 = 320-mulscale14(posxe+131072,zoome); + + for(i=-131072;i<=131072;i+=(2048>>gride)) + { + xp2 = xp1; + xp1 = 320-mulscale14(posxe-i,zoome); + + if (xp1 >= 640) break; + if (xp1 >= 0) + { + + #if (defined PLATFORM_DOS) + if ((xp1|7) != (xp2|7)) + { + koutp(0x3cf,mask); + if (((xp2>>3) >= 0) && ((xp2>>3) < 80)) + vlin16first(templong+(xp2>>3),tempy); + mask = 0; + } + mask |= pow2char[(xp1&7)^7]; + #else + drawline16(xp1, yp1, xp1, yp2, 8); // bdragon's fix + #endif + } + } + if ((i >= 131072) && (xp1 < 640)) + xp2 = xp1; + if ((mask != 0) && ((xp2>>3) >= 0) && ((xp2>>3) < 80)) + { + /* !!! Does this code ever get hit? Do something with this! */ +#ifdef PLATFORM_DOS + koutp(0x3cf,mask); + vlin16first(templong+(xp2>>3),tempy); +#else + fprintf (stderr, "STUB: %s:%d\n",__FILE__,__LINE__); +#endif + } + } + + xp1 = mulscale14(posxe+131072,zoome); + xp2 = mulscale14(posxe-131072,zoome); + tempy = 0x80000000; + for(i=-131072;i<=131072;i+=(2048>>gride)) + { + yp1 = (((posye-i)*zoome)>>14); + if (yp1 != tempy) + { + if ((yp1 > 200-ydim16) && (yp1 <= 200)) + { + drawline16(320-xp1,200-yp1,320-xp2,200-yp1,8); + tempy = yp1; + } + } + } + } +} + +void draw2dscreen(long posxe, long posye, short ange, long zoome, short gride) +{ + walltype *wal; + long i, j, xp1, yp1, xp2, yp2, templong; + char col; + + if (qsetmode == 200) return; + + if (editstatus == 0) + { + faketimerhandler(); + clear2dscreen(); + + faketimerhandler(); + draw2dgrid(posxe,posye,ange,zoome,gride); + } + + faketimerhandler(); + for(i=numwalls-1,wal=&wall[i];i>=0;i--,wal--) + { + if (editstatus == 0) + { + if ((show2dwall[i>>3]&pow2char[i&7]) == 0) continue; + j = wal->nextwall; + if ((j >= 0) && (i > j)) + if ((show2dwall[j>>3]&pow2char[j&7]) > 0) continue; + } + else + { + j = wal->nextwall; + if ((j >= 0) && (i > j)) continue; + } + + if (j < 0) + { + col = 7; + if (i == linehighlight) col += ((numframes&2)<<2); + } + else + { + col = 4; + if ((wal->cstat&1) != 0) col = 5; + if ((i == linehighlight) || ((linehighlight >= 0) && (i == wall[linehighlight].nextwall))) + col += ((numframes&2)<<2); + } + + xp1 = mulscale14(wal->x-posxe,zoome); + yp1 = mulscale14(wal->y-posye,zoome); + xp2 = mulscale14(wall[wal->point2].x-posxe,zoome); + yp2 = mulscale14(wall[wal->point2].y-posye,zoome); + + if ((wal->cstat&64) > 0) + { + if (klabs(xp2-xp1) >= klabs(yp2-yp1)) + { + drawline16(320+xp1,200+yp1+1,320+xp2,200+yp2+1,col); + drawline16(320+xp1,200+yp1-1,320+xp2,200+yp2-1,col); + } + else + { + drawline16(320+xp1+1,200+yp1,320+xp2+1,200+yp2,col); + drawline16(320+xp1-1,200+yp1,320+xp2-1,200+yp2,col); + } + col += 8; + } + drawline16(320+xp1,200+yp1,320+xp2,200+yp2,col); + + if ((zoome >= 256) && (editstatus == 1)) + if (((320+xp1) >= 2) && ((320+xp1) <= 637)) + if (((200+yp1) >= 2) && ((200+yp1) <= ydim16-3)) + { + col = 2; + if (i == pointhighlight) col += ((numframes&2)<<2); + else if ((highlightcnt > 0) && (editstatus == 1)) + { + if (show2dwall[i>>3]&pow2char[i&7]) + col += ((numframes&2)<<2); + } + +#ifdef PLATFORM_DOS + templong = (mul5(200+yp1)<<7)+(320+xp1)+pageoffset; +#else + templong = (mul5(200+yp1)<<7)+(320+xp1); +#endif + + setcolor16((long)col); + + drawpixel16(templong-2-1280); + drawpixel16(templong-1-1280); + drawpixel16(templong+0-1280); + drawpixel16(templong+1-1280); + drawpixel16(templong+2-1280); + + drawpixel16(templong-2+1280); + drawpixel16(templong-1+1280); + drawpixel16(templong+0+1280); + drawpixel16(templong+1+1280); + drawpixel16(templong+2+1280); + + drawpixel16(templong-2-640); + drawpixel16(templong-2+0); + drawpixel16(templong-2+640); + + drawpixel16(templong+2-640); + drawpixel16(templong+2+0); + drawpixel16(templong+2+640); + } + } + faketimerhandler(); + + if ((zoome >= 256) || (editstatus == 0)) + for(i=0;i=0;j=nextspritesect[j]) + if ((editstatus == 1) || (show2dsprite[j>>3]&pow2char[j&7])) + { + col = 3; + if ((sprite[j].cstat&1) > 0) col = 5; + if (editstatus == 1) + { + if (j+16384 == pointhighlight) + col += ((numframes&2)<<2); + else if ((highlightcnt > 0) && (editstatus == 1)) + { + if (show2dsprite[j>>3]&pow2char[j&7]) + col += ((numframes&2)<<2); + } + } + + xp1 = mulscale14(sprite[j].x-posxe,zoome); + yp1 = mulscale14(sprite[j].y-posye,zoome); + if (((320+xp1) >= 2) && ((320+xp1) <= 637)) + if (((200+yp1) >= 2) && ((200+yp1) <= ydim16-3)) + { +#ifdef PLATFORM_DOS + templong = (mul5(200+yp1)<<7)+(320+xp1)+pageoffset; +#else + templong = (mul5(200+yp1)<<7)+(320+xp1); +#endif + + setcolor16((long)col); + drawpixel16(templong-1-1280); + drawpixel16(templong+0-1280); + drawpixel16(templong+1-1280); + + drawpixel16(templong-1+1280); + drawpixel16(templong+0+1280); + drawpixel16(templong+1+1280); + + drawpixel16(templong-2-640); + drawpixel16(templong-2+0); + drawpixel16(templong-2+640); + + drawpixel16(templong+2-640); + drawpixel16(templong+2+0); + drawpixel16(templong+2+640); + + drawpixel16(templong+1+640); + drawpixel16(templong-1+640); + drawpixel16(templong+1-640); + drawpixel16(templong-1-640); + + xp2 = mulscale11(sintable[(sprite[j].ang+2560)&2047],zoome) / 768; + yp2 = mulscale11(sintable[(sprite[j].ang+2048)&2047],zoome) / 768; + + if ((sprite[j].cstat&256) > 0) + { + if (((sprite[j].ang+256)&512) == 0) + { + drawline16(320+xp1,200+yp1-1,320+xp1+xp2,200+yp1+yp2-1,col); + drawline16(320+xp1,200+yp1+1,320+xp1+xp2,200+yp1+yp2+1,col); + } + else + { + drawline16(320+xp1-1,200+yp1,320+xp1+xp2-1,200+yp1+yp2,col); + drawline16(320+xp1+1,200+yp1,320+xp1+xp2+1,200+yp1+yp2,col); + } + col += 8; + } + drawline16(320+xp1,200+yp1,320+xp1+xp2,200+yp1+yp2,col); + } + } + + faketimerhandler(); + xp1 = mulscale11(sintable[(ange+2560)&2047],zoome) / 768; /* Draw white arrow */ + yp1 = mulscale11(sintable[(ange+2048)&2047],zoome) / 768; + drawline16(320+xp1,200+yp1,320-xp1,200-yp1,15); + drawline16(320+xp1,200+yp1,320+yp1,200-xp1,15); + drawline16(320+xp1,200+yp1,320-yp1,200+xp1,15); +} + + +/* + * This is ryan's change. SDL requires me to call SDL_UpdateRect() to force + * vid updates without a SDL_Flip() call, but there's no such thing in the + * DOS version of this program, so text won't show up sometimes without + * my update call in Linux. However, to get a nice shadow effect on some + * text, Ken draws a string at an offset and darker, and then on top of it + * draws the actual string. Two SDL_UpdateRect() calls in over top of each + * other cause flicker, so I have this function here so the shadow can + * be drawn with _noupdate, and the actual string is draw with an update. + */ +static void __printext256(long xpos, long ypos, short col, short backcol, char name[82], char fontsize, int should_update) +{ + long stx, i, x, y, charxsiz; + char *fontptr, *letptr, *ptr; + + stx = xpos; + + if (fontsize) { fontptr = smalltextfont; charxsiz = 4; } + else { fontptr = textfont; charxsiz = 8; } + + for(i=0;name[i];i++) + { + letptr = &fontptr[name[i]<<3]; + ptr = (char *)(ylookup[ypos+7]+(stx-fontsize)+frameplace); + for(y=7;y>=0;y--) + { + for(x=charxsiz-1;x>=0;x--) + { + if (letptr[y]&pow2char[7-fontsize-x]) + ptr[x] = (char)col; + else if (backcol >= 0) + ptr[x] = (char)backcol; + } + ptr -= ylookup[1]; + } + stx += charxsiz; + } + + if (should_update) + _updateScreenRect(xpos, ypos, charxsiz * i, 8); +} + + +void printext256(long xpos, long ypos, short col, short backcol, char name[82], char fontsize) +{ + __printext256(xpos, ypos, col, backcol, name, fontsize, 1); +} + + +void printext256_noupdate(long xpos, long ypos, short col, short backcol, char name[82], char fontsize) +{ + __printext256(xpos, ypos, col, backcol, name, fontsize, 0); +} + + +int krand(void) +{ + randomseed = (randomseed*27584621)+1; + return(((unsigned long)randomseed)>>16); +} + + +void getzrange(long x, long y, long z, short sectnum, + long *ceilz, long *ceilhit, long *florz, long *florhit, + long walldist, unsigned long cliptype) +{ + sectortype *sec; + walltype *wal, *wal2; + spritetype *spr; + long clipsectcnt, startwall, endwall, tilenum, xoff, yoff, dax, day; + long xmin, ymin, xmax, ymax, i, j, k, l, daz, daz2, dx, dy; + long x1, y1, x2, y2, x3, y3, x4, y4, ang, cosang, sinang; + long xspan, yspan, xrepeat, yrepeat, dasprclipmask, dawalclipmask; + short cstat; + char clipyou; + + if (sectnum < 0) + { + *ceilz = 0x80000000; *ceilhit = -1; + *florz = 0x7fffffff; *florhit = -1; + return; + } + + /* Extra walldist for sprites on sector lines */ + i = walldist+MAXCLIPDIST+1; + xmin = x-i; ymin = y-i; + xmax = x+i; ymax = y+i; + + getzsofslope(sectnum,x,y,ceilz,florz); + *ceilhit = sectnum+16384; *florhit = sectnum+16384; + + dawalclipmask = (cliptype&65535); + dasprclipmask = (cliptype>>16); + + clipsectorlist[0] = sectnum; + clipsectcnt = 0; clipsectnum = 1; + + do /* Collect sectors inside your square first */ + { + sec = §or[clipsectorlist[clipsectcnt]]; + startwall = sec->wallptr; endwall = startwall + sec->wallnum; + for(j=startwall,wal=&wall[startwall];jnextsector; + if (k >= 0) + { + wal2 = &wall[wal->point2]; + x1 = wal->x; x2 = wal2->x; + if ((x1 < xmin) && (x2 < xmin)) continue; + if ((x1 > xmax) && (x2 > xmax)) continue; + y1 = wal->y; y2 = wal2->y; + if ((y1 < ymin) && (y2 < ymin)) continue; + if ((y1 > ymax) && (y2 > ymax)) continue; + + dx = x2-x1; dy = y2-y1; + if (dx*(y-y1) < (x-x1)*dy) continue; /* back */ + if (dx > 0) dax = dx*(ymin-y1); else dax = dx*(ymax-y1); + if (dy > 0) day = dy*(xmax-x1); else day = dy*(xmin-x1); + if (dax >= day) continue; + + if (wal->cstat&dawalclipmask) continue; + sec = §or[k]; + if (editstatus == 0) + { + if (((sec->ceilingstat&1) == 0) && (z <= sec->ceilingz+(3<<8))) continue; + if (((sec->floorstat&1) == 0) && (z >= sec->floorz-(3<<8))) continue; + } + + for(i=clipsectnum-1;i>=0;i--) if (clipsectorlist[i] == k) break; + if (i < 0) clipsectorlist[clipsectnum++] = k; + + if ((x1 < xmin+MAXCLIPDIST) && (x2 < xmin+MAXCLIPDIST)) continue; + if ((x1 > xmax-MAXCLIPDIST) && (x2 > xmax-MAXCLIPDIST)) continue; + if ((y1 < ymin+MAXCLIPDIST) && (y2 < ymin+MAXCLIPDIST)) continue; + if ((y1 > ymax-MAXCLIPDIST) && (y2 > ymax-MAXCLIPDIST)) continue; + if (dx > 0) dax += dx*MAXCLIPDIST; else dax -= dx*MAXCLIPDIST; + if (dy > 0) day -= dy*MAXCLIPDIST; else day += dy*MAXCLIPDIST; + if (dax >= day) continue; + + /* It actually got here, through all the continue's! */ + getzsofslope((short)k,x,y,&daz,&daz2); + if (daz > *ceilz) { *ceilz = daz; *ceilhit = k+16384; } + if (daz2 < *florz) { *florz = daz2; *florhit = k+16384; } + } + } + clipsectcnt++; + } while (clipsectcnt < clipsectnum); + + for(i=0;i=0;j=nextspritesect[j]) + { + spr = &sprite[j]; + cstat = spr->cstat; + if (cstat&dasprclipmask) + { + x1 = spr->x; y1 = spr->y; + + clipyou = 0; + switch(cstat&48) + { + case 0: + k = walldist+(spr->clipdist<<2)+1; + if ((klabs(x1-x) <= k) && (klabs(y1-y) <= k)) + { + daz = spr->z; + k = ((tilesizy[spr->picnum]*spr->yrepeat)<<1); + if (cstat&128) daz += k; + if (picanm[spr->picnum]&0x00ff0000) daz -= ((long)((signed char)((picanm[spr->picnum]>>16)&255))*spr->yrepeat<<2); + daz2 = daz - (k<<1); + clipyou = 1; + } + break; + case 16: + tilenum = spr->picnum; + xoff = (long)((signed char)((picanm[tilenum]>>8)&255))+((long)spr->xoffset); + if ((cstat&4) > 0) xoff = -xoff; + k = spr->ang; l = spr->xrepeat; + dax = sintable[k&2047]*l; day = sintable[(k+1536)&2047]*l; + l = tilesizx[tilenum]; k = (l>>1)+xoff; + x1 -= mulscale16(dax,k); x2 = x1+mulscale16(dax,l); + y1 -= mulscale16(day,k); y2 = y1+mulscale16(day,l); + if (clipinsideboxline(x,y,x1,y1,x2,y2,walldist+1) != 0) + { + daz = spr->z; k = ((tilesizy[spr->picnum]*spr->yrepeat)<<1); + if (cstat&128) daz += k; + if (picanm[spr->picnum]&0x00ff0000) daz -= ((long)((signed char)((picanm[spr->picnum]>>16)&255))*spr->yrepeat<<2); + daz2 = daz-(k<<1); + clipyou = 1; + } + break; + case 32: + daz = spr->z; daz2 = daz; + + if ((cstat&64) != 0) + if ((z > daz) == ((cstat&8)==0)) continue; + + tilenum = spr->picnum; + xoff = (long)((signed char)((picanm[tilenum]>>8)&255))+((long)spr->xoffset); + yoff = (long)((signed char)((picanm[tilenum]>>16)&255))+((long)spr->yoffset); + if ((cstat&4) > 0) xoff = -xoff; + if ((cstat&8) > 0) yoff = -yoff; + + ang = spr->ang; + cosang = sintable[(ang+512)&2047]; sinang = sintable[ang]; + xspan = tilesizx[tilenum]; xrepeat = spr->xrepeat; + yspan = tilesizy[tilenum]; yrepeat = spr->yrepeat; + + dax = ((xspan>>1)+xoff)*xrepeat; day = ((yspan>>1)+yoff)*yrepeat; + x1 += dmulscale16(sinang,dax,cosang,day)-x; + y1 += dmulscale16(sinang,day,-cosang,dax)-y; + l = xspan*xrepeat; + x2 = x1 - mulscale16(sinang,l); + y2 = y1 + mulscale16(cosang,l); + l = yspan*yrepeat; + k = -mulscale16(cosang,l); x3 = x2+k; x4 = x1+k; + k = -mulscale16(sinang,l); y3 = y2+k; y4 = y1+k; + + dax = mulscale14(sintable[(spr->ang-256+512)&2047],walldist+4); + day = mulscale14(sintable[(spr->ang-256)&2047],walldist+4); + x1 += dax; x2 -= day; x3 -= dax; x4 += day; + y1 += day; y2 += dax; y3 -= day; y4 -= dax; + + if ((y1^y2) < 0) + { + if ((x1^x2) < 0) clipyou ^= (x1*y2= 0) clipyou ^= 1; + } + if ((y2^y3) < 0) + { + if ((x2^x3) < 0) clipyou ^= (x2*y3= 0) clipyou ^= 1; + } + if ((y3^y4) < 0) + { + if ((x3^x4) < 0) clipyou ^= (x3*y4= 0) clipyou ^= 1; + } + if ((y4^y1) < 0) + { + if ((x4^x1) < 0) clipyou ^= (x4*y1= 0) clipyou ^= 1; + } + break; + } + + if (clipyou != 0) + { + if ((z > daz) && (daz > *ceilz)) { *ceilz = daz; *ceilhit = j+49152; } + if ((z < daz2) && (daz2 < *florz)) { *florz = daz2; *florhit = j+49152; } + } + } + } + } +} + + +void setview(long x1, long y1, long x2, long y2) +{ + long i; + + windowx1 = x1; wx1 = (x1<<12); + windowy1 = y1; wy1 = (y1<<12); + windowx2 = x2; wx2 = ((x2+1)<<12); + windowy2 = y2; wy2 = ((y2+1)<<12); + + xdimen = (x2-x1)+1; halfxdimen = (xdimen>>1); + xdimenrecip = divscale32(1L,xdimen); + ydimen = (y2-y1)+1; + + setaspect(65536L,(long)divscale16(ydim*320L,xdim*200L)); + + for(i=0;i>1); + xdimenrecip = divscale32(1L,xdimen); + setaspect((long)divscale16(xdimen,windowx2-windowx1+1),yxaspect); + } +} + + +void setaspect(long daxrange, long daaspect) +{ + viewingrange = daxrange; + viewingrangerecip = divscale32(1L,daxrange); + + yxaspect = daaspect; + xyaspect = divscale32(1,yxaspect); + xdimenscale = scale(xdimen,yxaspect,320); + xdimscale = scale(320,xyaspect,xdimen); +} + + +void flushperms(void) +{ + permhead = permtail = 0; +} + + +void rotatesprite(long sx, long sy, long z, short a, short picnum, + signed char dashade, char dapalnum, char dastat, + long cx1, long cy1, long cx2, long cy2) +{ + long i; + permfifotype *per, *per2; + + if ((cx1 > cx2) || (cy1 > cy2)) return; + if (z <= 16) return; + if (picanm[picnum]&192) picnum += animateoffs(picnum,(short)0xc000); + if ((tilesizx[picnum] <= 0) || (tilesizy[picnum] <= 0)) return; + + if (((dastat&128) == 0) || (numpages < 2) || (beforedrawrooms != 0)) + dorotatesprite(sx,sy,z,a,picnum,dashade,dapalnum,dastat,cx1,cy1,cx2,cy2); + + if ((dastat&64) && (cx1 <= 0) && (cy1 <= 0) && (cx2 >= xdim-1) && (cy2 >= ydim-1) && + (sx == (160<<16)) && (sy == (100<<16)) && (z == 65536L) && (a == 0) && ((dastat&1) == 0)) + permhead = permtail = 0; + + if ((dastat&128) == 0) return; + if (numpages >= 2) + { + per = &permfifo[permhead]; + per->sx = sx; per->sy = sy; per->z = z; per->a = a; + per->picnum = picnum; + per->dashade = dashade; per->dapalnum = dapalnum; + per->dastat = dastat; + per->pagesleft = numpages+((beforedrawrooms&1)<<7); + per->cx1 = cx1; per->cy1 = cy1; per->cx2 = cx2; per->cy2 = cy2; + + /* Would be better to optimize out true bounding boxes */ + if (dastat&64) /* If non-masking write, checking for overlapping cases */ + { + for(i=permtail;i!=permhead;i=((i+1)&(MAXPERMS-1))) + { + per2 = &permfifo[i]; + if ((per2->pagesleft&127) == 0) continue; + if (per2->sx != per->sx) continue; + if (per2->sy != per->sy) continue; + if (per2->z != per->z) continue; + if (per2->a != per->a) continue; + if (tilesizx[per2->picnum] > tilesizx[per->picnum]) continue; + if (tilesizy[per2->picnum] > tilesizy[per->picnum]) continue; + if (per2->cx1 < per->cx1) continue; + if (per2->cy1 < per->cy1) continue; + if (per2->cx2 > per->cx2) continue; + if (per2->cy2 > per->cy2) continue; + per2->pagesleft = 0; + } + if ((per->z == 65536) && (per->a == 0)) + for(i=permtail;i!=permhead;i=((i+1)&(MAXPERMS-1))) + { + per2 = &permfifo[i]; + if ((per2->pagesleft&127) == 0) continue; + if (per2->z != 65536) continue; + if (per2->a != 0) continue; + if (per2->cx1 < per->cx1) continue; + if (per2->cy1 < per->cy1) continue; + if (per2->cx2 > per->cx2) continue; + if (per2->cy2 > per->cy2) continue; + if ((per2->sx>>16) < (per->sx>>16)) continue; + if ((per2->sy>>16) < (per->sy>>16)) continue; + if ((per2->sx>>16)+tilesizx[per2->picnum] > (per->sx>>16)+tilesizx[per->picnum]) continue; + if ((per2->sy>>16)+tilesizy[per2->picnum] > (per->sy>>16)+tilesizy[per->picnum]) continue; + per2->pagesleft = 0; + } + } + + permhead = ((permhead+1)&(MAXPERMS-1)); + } +} + + +static int getclosestcol(long r, long g, long b) +{ + long i, j, k, dist, mindist, retcol; + char *pal1; + + j = (r>>3)*FASTPALGRIDSIZ*FASTPALGRIDSIZ+(g>>3)*FASTPALGRIDSIZ+(b>>3)+FASTPALGRIDSIZ*FASTPALGRIDSIZ+FASTPALGRIDSIZ+1; + mindist = min(rdist[coldist[r&7]+64+8],gdist[coldist[g&7]+64+8]); + mindist = min(mindist,bdist[coldist[b&7]+64+8]); + mindist++; + + r = 64-r; g = 64-g; b = 64-b; + + retcol = -1; + for(k=26;k>=0;k--) + { + i = colscan[k]+j; if ((colhere[i>>3]&pow2char[i&7]) == 0) continue; + i = colhead[i]; + do + { + pal1 = (char *)&palette[i*3]; + dist = gdist[pal1[1]+g]; + if (dist < mindist) + { + dist += rdist[pal1[0]+r]; + if (dist < mindist) + { + dist += bdist[pal1[2]+b]; + if (dist < mindist) { mindist = dist; retcol = i; } + } + } + i = colnext[i]; + } while (i >= 0); + } + if (retcol >= 0) return(retcol); + + mindist = 0x7fffffff; + pal1 = (char *)&palette[768-3]; + for(i=255;i>=0;i--,pal1-=3) + { + dist = gdist[pal1[1]+g]; if (dist >= mindist) continue; + dist += rdist[pal1[0]+r]; if (dist >= mindist) continue; + dist += bdist[pal1[2]+b]; if (dist >= mindist) continue; + mindist = dist; retcol = i; + } + return(retcol); +} + + +void makepalookup(long palnum, char *remapbuf, signed char r, + signed char g, signed char b, char dastat) +{ + long i, j, dist, palscale; + char *ptr, *ptr2; + + if (paletteloaded == 0) return; + + if (palookup[palnum] == NULL) + { + /* Allocate palookup buffer */ + if ((palookup[palnum] = (char *)kkmalloc(numpalookups<<8)) == NULL) + allocache((long *)&palookup[palnum],numpalookups<<8,&permanentlock); + } + + if (dastat == 0) return; + if ((r|g|b|63) != 63) return; + + if ((r|g|b) == 0) + { + for(i=0;i<256;i++) + { + ptr = (char *)(FP_OFF(palookup[0])+remapbuf[i]); + ptr2 = (char *)(FP_OFF(palookup[palnum])+i); + for(j=0;j=0;z--) + { y = ry1[z]; miny = min(miny,y); maxy = max(maxy,y); } + miny = (miny>>12); maxy = (maxy>>12); + if (miny < 0) miny = 0; + if (maxy >= ydim) maxy = ydim-1; + ptr = smost; /* They're pointers! - watch how you optimize this thing */ + for(y=miny;y<=maxy;y++) + { + dotp1[y] = ptr; dotp2[y] = ptr+(MAXNODESPERLINE>>1); + ptr += MAXNODESPERLINE; + } + + for(z=npoints-1;z>=0;z--) + { + zz = xb1[z]; + y1 = ry1[z]; day1 = (y1>>12); + y2 = ry1[zz]; day2 = (y2>>12); + if (day1 != day2) + { + x1 = rx1[z]; x2 = rx1[zz]; + xinc = divscale12(x2-x1,y2-y1); + if (day2 > day1) + { + x1 += mulscale12((day1<<12)+4095-y1,xinc); + for(y=day1;y>12); x1 += xinc; } + } + else + { + x2 += mulscale12((day2<<12)+4095-y2,xinc); + for(y=day2;y>12); x2 += xinc; } + } + } + } + + globalx1 = mulscale16(globalx1,xyaspect); + globaly2 = mulscale16(globaly2,xyaspect); + + oy = miny+1-(ydim>>1); + globalposx += oy*globalx1; + globalposy += oy*globaly2; + + setuphlineasm4(asm1,asm2); + + ptr = smost; + for(y=miny;y<=maxy;y++) + { + cnt = dotp1[y]-ptr; ptr2 = ptr+(MAXNODESPERLINE>>1); + for(z=cnt-1;z>=0;z--) + { + day1 = 0; day2 = 0; + for(zz=z;zz>0;zz--) + { + if (ptr[zz] < ptr[day1]) day1 = zz; + if (ptr2[zz] < ptr2[day2]) day2 = zz; + } + x1 = ptr[day1]; ptr[day1] = ptr[z]; + x2 = ptr2[day2]-1; ptr2[day2] = ptr2[z]; + if (x1 > x2) continue; + + if (globalpolytype < 1) + { + /* maphline */ + ox = x2+1-(xdim>>1); + bx = ox*asm1 + globalposx; + by = ox*asm2 - globalposy; + + p = ylookup[y]+x2+frameplace; + hlineasm4(x2-x1,-1L,globalshade<<8,by,bx,p); + } + else + { + /* maphline */ + ox = x1+1-(xdim>>1); + bx = ox*asm1 + globalposx; + by = ox*asm2 - globalposy; + + p = ylookup[y]+x1+frameplace; + if (globalpolytype == 1) + mhline(globalbufplc,bx,(x2-x1)<<16,0L,by,p); + else + { + thline(globalbufplc,bx,(x2-x1)<<16,0L,by,p); + transarea += (x2-x1); + } + } + } + globalposx += globalx1; + globalposy += globaly2; + ptr += MAXNODESPERLINE; + } + faketimerhandler(); +} + + +static int clippoly (long npoints, long clipstat) +{ + long z, zz, s1, s2, t, npoints2, start2, z1, z2, z3, z4, splitcnt; + long cx1, cy1, cx2, cy2; + + cx1 = windowx1; + cy1 = windowy1; + cx2 = windowx2+1; + cy2 = windowy2+1; + cx1 <<= 12; cy1 <<= 12; cx2 <<= 12; cy2 <<= 12; + + if (clipstat&0xa) /* Need to clip top or left */ + { + npoints2 = 0; start2 = 0; z = 0; splitcnt = 0; + do + { + s2 = cx1-rx1[z]; + do + { + zz = xb1[z]; xb1[z] = -1; + s1 = s2; s2 = cx1-rx1[zz]; + if (s1 < 0) + { + rx2[npoints2] = rx1[z]; ry2[npoints2] = ry1[z]; + xb2[npoints2] = npoints2+1; npoints2++; + } + if ((s1^s2) < 0) + { + rx2[npoints2] = rx1[z]+scale(rx1[zz]-rx1[z],s1,s1-s2); + ry2[npoints2] = ry1[z]+scale(ry1[zz]-ry1[z],s1,s1-s2); + if (s1 < 0) p2[splitcnt++] = npoints2; + xb2[npoints2] = npoints2+1; + npoints2++; + } + z = zz; + } while (xb1[z] >= 0); + + if (npoints2 >= start2+3) + xb2[npoints2-1] = start2, start2 = npoints2; + else + npoints2 = start2; + + z = 1; + while ((z < npoints) && (xb1[z] < 0)) z++; + } while (z < npoints); + if (npoints2 <= 2) return(0); + + for(z=1;z= 0); + + if (npoints >= start2+3) + xb1[npoints-1] = start2, start2 = npoints; + else + npoints = start2; + + z = 1; + while ((z < npoints2) && (xb2[z] < 0)) z++; + } while (z < npoints2); + if (npoints <= 2) return(0); + + for(z=1;z= 0); + + if (npoints2 >= start2+3) + xb2[npoints2-1] = start2, start2 = npoints2; + else + npoints2 = start2; + + z = 1; + while ((z < npoints) && (xb1[z] < 0)) z++; + } while (z < npoints); + if (npoints2 <= 2) return(0); + + for(z=1;z= 0); + + if (npoints >= start2+3) + xb1[npoints-1] = start2, start2 = npoints; + else + npoints = start2; + + z = 1; + while ((z < npoints2) && (xb2[z] < 0)) z++; + } while (z < npoints2); + if (npoints <= 2) return(0); + + for(z=1;z>5),0L); + + cx1 = (windowx1<<12); cy1 = (windowy1<<12); + cx2 = ((windowx2+1)<<12)-1; cy2 = ((windowy2+1)<<12)-1; + zoome <<= 8; + bakgxvect = divscale28(sintable[(1536-ang)&2047],zoome); + bakgyvect = divscale28(sintable[(2048-ang)&2047],zoome); + xvect = mulscale8(sintable[(2048-ang)&2047],zoome); + yvect = mulscale8(sintable[(1536-ang)&2047],zoome); + xvect2 = mulscale16(xvect,yxaspect); + yvect2 = mulscale16(yvect,yxaspect); + + sortnum = 0; + for(s=0,sec=§or[s];s>3]&pow2char[s&7]) + { + npoints = 0; i = 0; + startwall = sec->wallptr; + for(w=sec->wallnum,wal=&wall[startwall];w>0;w--,wal++) + { + ox = wal->x - dax; oy = wal->y - day; + x = dmulscale16(ox,xvect,-oy,yvect) + (xdim<<11); + y = dmulscale16(oy,xvect2,ox,yvect2) + (ydim<<11); + i |= getclipmask(x-cx1,cx2-x,y-cy1,cy2-y); + rx1[npoints] = x; + ry1[npoints] = y; + xb1[npoints] = wal->point2 - startwall; + npoints++; + } + if ((i&0xf0) != 0xf0) continue; + bakx1 = rx1[0]; baky1 = mulscale16(ry1[0]-(ydim<<11),xyaspect)+(ydim<<11); + if (i&0x0f) + { + npoints = clippoly(npoints,i); + if (npoints < 3) continue; + } + + /* Collect floor sprites to draw */ + for(i=headspritesect[s];i>=0;i=nextspritesect[i]) + if ((sprite[i].cstat&48) == 32) + { + if ((sprite[i].cstat&(64+8)) == (64+8)) continue; + tsprite[sortnum++].owner = i; + } + + gotsector[s>>3] |= pow2char[s&7]; + + globalorientation = (long)sec->floorstat; + if ((globalorientation&1) != 0) continue; + + if (palookup[sec->floorpal] != globalpalwritten) + { + globalpalwritten = palookup[sec->floorpal]; + setpalookupaddress(globalpalwritten); + } + globalpicnum = sec->floorpicnum; + if ((unsigned)globalpicnum >= (unsigned)MAXTILES) globalpicnum = 0; + setgotpic(globalpicnum); + if ((tilesizx[globalpicnum] <= 0) || (tilesizy[globalpicnum] <= 0)) continue; + if ((picanm[globalpicnum]&192) != 0) globalpicnum += animateoffs((short)globalpicnum,s); + if (waloff[globalpicnum] == 0) loadtile(globalpicnum); + globalbufplc = waloff[globalpicnum]; + globalshade = max(min(sec->floorshade,numpalookups-1),0); + globvis = globalhisibility; + if (sec->visibility != 0) globvis = mulscale4(globvis,(long)((unsigned char)(sec->visibility+16))); + globalpolytype = 0; + if ((globalorientation&64) == 0) + { + globalposx = dax; globalx1 = bakgxvect; globaly1 = bakgyvect; + globalposy = day; globalx2 = bakgxvect; globaly2 = bakgyvect; + } + else + { + ox = wall[wall[startwall].point2].x - wall[startwall].x; + oy = wall[wall[startwall].point2].y - wall[startwall].y; + i = nsqrtasm(ox*ox+oy*oy); if (i == 0) continue; + i = 1048576/i; + globalx1 = mulscale10(dmulscale10(ox,bakgxvect,oy,bakgyvect),i); + globaly1 = mulscale10(dmulscale10(ox,bakgyvect,-oy,bakgxvect),i); + ox = (bakx1>>4)-(xdim<<7); oy = (baky1>>4)-(ydim<<7); + globalposx = dmulscale28(-oy,globalx1,-ox,globaly1); + globalposy = dmulscale28(-ox,globalx1,oy,globaly1); + globalx2 = -globalx1; + globaly2 = -globaly1; + + daslope = sector[s].floorheinum; + i = nsqrtasm(daslope*daslope+16777216); + globalposy = mulscale12(globalposy,i); + globalx2 = mulscale12(globalx2,i); + globaly2 = mulscale12(globaly2,i); + } + globalxshift = (8-(picsiz[globalpicnum]&15)); + globalyshift = (8-(picsiz[globalpicnum]>>4)); + if (globalorientation&8) {globalxshift++; globalyshift++; } + + sethlinesizes(picsiz[globalpicnum]&15,picsiz[globalpicnum]>>4,globalbufplc); + + if ((globalorientation&0x4) > 0) + { + i = globalposx; globalposx = -globalposy; globalposy = -i; + i = globalx2; globalx2 = globaly1; globaly1 = i; + i = globalx1; globalx1 = -globaly2; globaly2 = -i; + } + if ((globalorientation&0x10) > 0) globalx1 = -globalx1, globaly1 = -globaly1, globalposx = -globalposx; + if ((globalorientation&0x20) > 0) globalx2 = -globalx2, globaly2 = -globaly2, globalposy = -globalposy; + asm1 = (globaly1<floorxpanning)<<24); + globalposy = (globalposy<<(20+globalyshift))-(((long)sec->floorypanning)<<24); + + fillpolygon(npoints); + } + + /* Sort sprite list */ + gap = 1; while (gap < sortnum) gap = (gap<<1)+1; + for(gap>>=1;gap>0;gap>>=1) + for(i=0;i=0;j-=gap) + { + if (sprite[tsprite[j].owner].z <= sprite[tsprite[j+gap].owner].z) break; + swapshort(&tsprite[j].owner,&tsprite[j+gap].owner); + } + + for(s=sortnum-1;s>=0;s--) + { + spr = &sprite[tsprite[s].owner]; + if ((spr->cstat&48) == 32) + { + npoints = 0; + + tilenum = spr->picnum; + xoff = (long)((signed char)((picanm[tilenum]>>8)&255))+((long)spr->xoffset); + yoff = (long)((signed char)((picanm[tilenum]>>16)&255))+((long)spr->yoffset); + if ((spr->cstat&4) > 0) xoff = -xoff; + if ((spr->cstat&8) > 0) yoff = -yoff; + + k = spr->ang; + cosang = sintable[(k+512)&2047]; sinang = sintable[k]; + xspan = tilesizx[tilenum]; xrepeat = spr->xrepeat; + yspan = tilesizy[tilenum]; yrepeat = spr->yrepeat; + + ox = ((xspan>>1)+xoff)*xrepeat; oy = ((yspan>>1)+yoff)*yrepeat; + x1 = spr->x + mulscale(sinang,ox,16) + mulscale(cosang,oy,16); + y1 = spr->y + mulscale(sinang,oy,16) - mulscale(cosang,ox,16); + l = xspan*xrepeat; + x2 = x1 - mulscale(sinang,l,16); + y2 = y1 + mulscale(cosang,l,16); + l = yspan*yrepeat; + k = -mulscale(cosang,l,16); x3 = x2+k; x4 = x1+k; + k = -mulscale(sinang,l,16); y3 = y2+k; y4 = y1+k; + + xb1[0] = 1; xb1[1] = 2; xb1[2] = 3; xb1[3] = 0; + npoints = 4; + + i = 0; + + ox = x1 - dax; oy = y1 - day; + x = dmulscale16(ox,xvect,-oy,yvect) + (xdim<<11); + y = dmulscale16(oy,xvect2,ox,yvect2) + (ydim<<11); + i |= getclipmask(x-cx1,cx2-x,y-cy1,cy2-y); + rx1[0] = x; ry1[0] = y; + + ox = x2 - dax; oy = y2 - day; + x = dmulscale16(ox,xvect,-oy,yvect) + (xdim<<11); + y = dmulscale16(oy,xvect2,ox,yvect2) + (ydim<<11); + i |= getclipmask(x-cx1,cx2-x,y-cy1,cy2-y); + rx1[1] = x; ry1[1] = y; + + ox = x3 - dax; oy = y3 - day; + x = dmulscale16(ox,xvect,-oy,yvect) + (xdim<<11); + y = dmulscale16(oy,xvect2,ox,yvect2) + (ydim<<11); + i |= getclipmask(x-cx1,cx2-x,y-cy1,cy2-y); + rx1[2] = x; ry1[2] = y; + + x = rx1[0]+rx1[2]-rx1[1]; + y = ry1[0]+ry1[2]-ry1[1]; + i |= getclipmask(x-cx1,cx2-x,y-cy1,cy2-y); + rx1[3] = x; ry1[3] = y; + + if ((i&0xf0) != 0xf0) continue; + bakx1 = rx1[0]; baky1 = mulscale16(ry1[0]-(ydim<<11),xyaspect)+(ydim<<11); + if (i&0x0f) + { + npoints = clippoly(npoints,i); + if (npoints < 3) continue; + } + + globalpicnum = spr->picnum; + if ((unsigned)globalpicnum >= (unsigned)MAXTILES) globalpicnum = 0; + setgotpic(globalpicnum); + if ((tilesizx[globalpicnum] <= 0) || (tilesizy[globalpicnum] <= 0)) continue; + if ((picanm[globalpicnum]&192) != 0) globalpicnum += animateoffs((short)globalpicnum,s); + if (waloff[globalpicnum] == 0) loadtile(globalpicnum); + globalbufplc = waloff[globalpicnum]; + if ((sector[spr->sectnum].ceilingstat&1) > 0) + globalshade = ((long)sector[spr->sectnum].ceilingshade); + else + globalshade = ((long)sector[spr->sectnum].floorshade); + globalshade = max(min(globalshade+spr->shade+6,numpalookups-1),0); + asm3 = (long) FP_OFF(palookup[spr->pal]+(globalshade<<8)); + globvis = globalhisibility; + if (sec->visibility != 0) globvis = mulscale4(globvis,(long)((unsigned char)(sec->visibility+16))); + globalpolytype = ((spr->cstat&2)>>1)+1; + + /* relative alignment stuff */ + ox = x2-x1; oy = y2-y1; + i = ox*ox+oy*oy; if (i == 0) continue; i = (65536*16384)/i; + globalx1 = mulscale10(dmulscale10(ox,bakgxvect,oy,bakgyvect),i); + globaly1 = mulscale10(dmulscale10(ox,bakgyvect,-oy,bakgxvect),i); + ox = y1-y4; oy = x4-x1; + i = ox*ox+oy*oy; if (i == 0) continue; i = (65536*16384)/i; + globalx2 = mulscale10(dmulscale10(ox,bakgxvect,oy,bakgyvect),i); + globaly2 = mulscale10(dmulscale10(ox,bakgyvect,-oy,bakgxvect),i); + + ox = picsiz[globalpicnum]; oy = ((ox>>4)&15); ox &= 15; + if (pow2long[ox] != xspan) + { + ox++; + globalx1 = mulscale(globalx1,xspan,ox); + globaly1 = mulscale(globaly1,xspan,ox); + } + + bakx1 = (bakx1>>4)-(xdim<<7); baky1 = (baky1>>4)-(ydim<<7); + globalposx = dmulscale28(-baky1,globalx1,-bakx1,globaly1); + globalposy = dmulscale28(bakx1,globalx2,-baky1,globaly2); + + if ((spr->cstat&2) == 0) + msethlineshift(ox,oy); + else + tsethlineshift(ox,oy); + + if ((spr->cstat&0x4) > 0) globalx1 = -globalx1, globaly1 = -globaly1, globalposx = -globalposx; + asm1 = (globaly1<<2); globalx1 <<= 2; globalposx <<= (20+2); + asm2 = (globalx2<<2); globaly2 <<= 2; globalposy <<= (20+2); + + fillpolygon(npoints); + } + } +} + + +void clearview(long dacol) +{ + long p, y, dx; + + if (qsetmode != 200) return; + + dx = windowx2-windowx1+1; + dacol += (dacol<<8); dacol += (dacol<<16); + if (vidoption == 6) + { + p = (long) FP_OFF(screen)+ylookup[windowy1]+windowx1; + for(y=windowy1;y<=windowy2;y++) + { + clearbufbyte((void *)p,dx,dacol); + clearbufbyte((void *)(p+65536),dx,dacol); + p += ylookup[1]; + } + faketimerhandler(); + return; + } + p = frameplace+ylookup[windowy1]+windowx1; + for(y=windowy1;y<=windowy2;y++) + { clearbufbyte((void *)p,dx,dacol); p += ylookup[1]; } + faketimerhandler(); +} + + +void clearallviews(long dacol) +{ + long i; + + if (qsetmode != 200) return; + dacol += (dacol<<8); dacol += (dacol<<16); + + switch(vidoption) + { + case 1: + for(i=0;i>2,0L); + break; + case 6: + clearbuf(screen,128000L>>2,dacol); + break; + } + faketimerhandler(); +} + + +void plotpixel(long x, long y, char col) +{ + drawpixel(ylookup[y]+x+frameplace,(long)col); +} + + +unsigned char getpixel(long x, long y) +{ + return(readpixel(ylookup[y]+x+frameplace)); +} + + /* MUST USE RESTOREFORDRAWROOMS AFTER DRAWING */ +static long setviewcnt = 0; +static long bakvidoption[4]; +static long bakframeplace[4], bakxsiz[4], bakysiz[4]; +static long bakwindowx1[4], bakwindowy1[4]; +static long bakwindowx2[4], bakwindowy2[4]; + + +void setviewtotile(short tilenume, long xsiz, long ysiz) +{ + long i, j; + + /* DRAWROOMS TO TILE BACKUP&SET CODE */ + tilesizx[tilenume] = xsiz; tilesizy[tilenume] = ysiz; + bakxsiz[setviewcnt] = xsiz; bakysiz[setviewcnt] = ysiz; + bakvidoption[setviewcnt] = vidoption; vidoption = 2; + bakframeplace[setviewcnt] = frameplace; frameplace = waloff[tilenume]; + bakwindowx1[setviewcnt] = windowx1; bakwindowy1[setviewcnt] = windowy1; + bakwindowx2[setviewcnt] = windowx2; bakwindowy2[setviewcnt] = windowy2; + copybufbyte(&startumost[windowx1],&bakumost[windowx1],(windowx2-windowx1+1)*sizeof(bakumost[0])); + copybufbyte(&startdmost[windowx1],&bakdmost[windowx1],(windowx2-windowx1+1)*sizeof(bakdmost[0])); + setview(0,0,ysiz-1,xsiz-1); + setaspect(65536,65536); + j = 0; for(i=0;i<=xsiz;i++) { ylookup[i] = j, j += ysiz; } + setvlinebpl(ysiz); + setviewcnt++; +} + + +void setviewback(void) +{ + long i, j, k; + + if (setviewcnt <= 0) return; + setviewcnt--; + + setview(bakwindowx1[setviewcnt],bakwindowy1[setviewcnt], + bakwindowx2[setviewcnt],bakwindowy2[setviewcnt]); + copybufbyte(&bakumost[windowx1],&startumost[windowx1],(windowx2-windowx1+1)*sizeof(startumost[0])); + copybufbyte(&bakdmost[windowx1],&startdmost[windowx1],(windowx2-windowx1+1)*sizeof(startdmost[0])); + vidoption = bakvidoption[setviewcnt]; + frameplace = bakframeplace[setviewcnt]; + if (setviewcnt == 0) + k = bakxsiz[0]; + else + k = max(bakxsiz[setviewcnt-1],bakxsiz[setviewcnt]); + j = 0; for(i=0;i<=k;i++) ylookup[i] = j, j += bytesperline; + setvlinebpl(bytesperline); +} + + +void squarerotatetile(short tilenume) +{ + long i, j, k, xsiz, ysiz; + unsigned char *ptr1, *ptr2; + + xsiz = tilesizx[tilenume]; ysiz = tilesizy[tilenume]; + + /* supports square tiles only for rotation part */ + if (xsiz == ysiz) + { + k = (xsiz<<1); + for(i=xsiz-1;i>=0;i--) + { + ptr1 = (unsigned char *) (waloff[tilenume]+i*(xsiz+1)); + ptr2 = ptr1; + if ((i&1) != 0) { ptr1--; ptr2 -= xsiz; swapchar(ptr1,ptr2); } + for(j=(i>>1)-1;j>=0;j--) + { ptr1 -= 2; ptr2 -= k; swapchar2(ptr1,ptr2,xsiz); } + } + } +} + + +void preparemirror(long dax, long day, long daz, + short daang, long dahoriz, short dawall, + short dasector, long *tposx, long *tposy, + short *tang) +{ + long i, j, x, y, dx, dy; + + x = wall[dawall].x; dx = wall[wall[dawall].point2].x-x; + y = wall[dawall].y; dy = wall[wall[dawall].point2].y-y; + j = dx*dx + dy*dy; if (j == 0) return; + i = (((dax-x)*dx + (day-y)*dy)<<1); + *tposx = (x<<1) + scale(dx,i,j) - dax; + *tposy = (y<<1) + scale(dy,i,j) - day; + *tang = (((getangle(dx,dy)<<1)-daang)&2047); + + inpreparemirror = 1; +} + + +void completemirror(void) +{ + long i, dy, p; + + /* Can't reverse with uninitialized data */ + if (inpreparemirror) { inpreparemirror = 0; return; } + if (mirrorsx1 > 0) mirrorsx1--; + if (mirrorsx2 < windowx2-windowx1-1) mirrorsx2++; + if (mirrorsx2 < mirrorsx1) return; + + transarea += (mirrorsx2-mirrorsx1)*(windowy2-windowy1); + + p = frameplace+ylookup[windowy1+mirrorsy1]+windowx1+mirrorsx1; + i = windowx2-windowx1-mirrorsx2-mirrorsx1; mirrorsx2 -= mirrorsx1; + for(dy=mirrorsy2-mirrorsy1;dy>=0;dy--) + { + copybufbyte((void *)(p+1),tempbuf,mirrorsx2+1); + tempbuf[mirrorsx2] = tempbuf[mirrorsx2-1]; + copybufreverse(&tempbuf[mirrorsx2],(void *)(p+i),mirrorsx2+1); + p += ylookup[1]; + faketimerhandler(); + } +} + + +int sectorofwall(short theline) +{ + long i, gap; + + if ((theline < 0) || (theline >= numwalls)) return(-1); + i = wall[theline].nextwall; if (i >= 0) return(wall[i].nextsector); + + gap = (numsectors>>1); i = gap; + while (gap > 1) + { + gap >>= 1; + if (sector[i].wallptr < theline) i += gap; else i -= gap; + } + while (sector[i].wallptr > theline) i--; + while (sector[i].wallptr+sector[i].wallnum <= theline) i++; + return(i); +} + + +int getceilzofslope(short sectnum, long dax, long day) +{ + long dx, dy, i, j; + walltype *wal; + + if (!(sector[sectnum].ceilingstat&2)) return(sector[sectnum].ceilingz); + wal = &wall[sector[sectnum].wallptr]; + dx = wall[wal->point2].x-wal->x; dy = wall[wal->point2].y-wal->y; + i = (nsqrtasm(dx*dx+dy*dy)<<5); if (i == 0) return(sector[sectnum].ceilingz); + j = dmulscale3(dx,day-wal->y,-dy,dax-wal->x); + return(sector[sectnum].ceilingz+scale(sector[sectnum].ceilingheinum,j,i)); +} + + +int getflorzofslope(short sectnum, long dax, long day) +{ + long dx, dy, i, j; + walltype *wal; + + if (!(sector[sectnum].floorstat&2)) return(sector[sectnum].floorz); + wal = &wall[sector[sectnum].wallptr]; + dx = wall[wal->point2].x-wal->x; dy = wall[wal->point2].y-wal->y; + i = (nsqrtasm(dx*dx+dy*dy)<<5); if (i == 0) return(sector[sectnum].floorz); + j = dmulscale3(dx,day-wal->y,-dy,dax-wal->x); + return(sector[sectnum].floorz+scale(sector[sectnum].floorheinum,j,i)); +} + + +void getzsofslope(short sectnum, long dax, long day, long *ceilz, long *florz) +{ + long dx, dy, i, j; + walltype *wal, *wal2; + sectortype *sec; + + sec = §or[sectnum]; + *ceilz = sec->ceilingz; *florz = sec->floorz; + if ((sec->ceilingstat|sec->floorstat)&2) + { + wal = &wall[sec->wallptr]; wal2 = &wall[wal->point2]; + dx = wal2->x-wal->x; dy = wal2->y-wal->y; + i = (nsqrtasm(dx*dx+dy*dy)<<5); if (i == 0) return; + j = dmulscale3(dx,day-wal->y,-dy,dax-wal->x); + if (sec->ceilingstat&2) *ceilz = (*ceilz)+scale(sec->ceilingheinum,j,i); + if (sec->floorstat&2) *florz = (*florz)+scale(sec->floorheinum,j,i); + } +} + + +void alignceilslope(short dasect, long x, long y, long z) +{ + long i, dax, day; + walltype *wal; + + wal = &wall[sector[dasect].wallptr]; + dax = wall[wal->point2].x-wal->x; + day = wall[wal->point2].y-wal->y; + + i = (y-wal->y)*dax - (x-wal->x)*day; if (i == 0) return; + sector[dasect].ceilingheinum = scale((z-sector[dasect].ceilingz)<<8, + nsqrtasm(dax*dax+day*day),i); + + if (sector[dasect].ceilingheinum == 0) sector[dasect].ceilingstat &= ~2; + else sector[dasect].ceilingstat |= 2; +} + + +void alignflorslope(short dasect, long x, long y, long z) +{ + long i, dax, day; + walltype *wal; + + wal = &wall[sector[dasect].wallptr]; + dax = wall[wal->point2].x-wal->x; + day = wall[wal->point2].y-wal->y; + + i = (y-wal->y)*dax - (x-wal->x)*day; if (i == 0) return; + sector[dasect].floorheinum = scale((z-sector[dasect].floorz)<<8, + nsqrtasm(dax*dax+day*day),i); + + if (sector[dasect].floorheinum == 0) sector[dasect].floorstat &= ~2; + else sector[dasect].floorstat |= 2; +} + + +int loopnumofsector(short sectnum, short wallnum) +{ + long i, numloops, startwall, endwall; + + numloops = 0; + startwall = sector[sectnum].wallptr; + endwall = startwall + sector[sectnum].wallnum; + for(i=startwall;i= startwall+danumwalls)) return; + for(i=0;i 0) + { + j = 0; + while (loopnumofsector(sectnum,j+startwall) != dagoalloop) j++; + for(i=0;i= danumwalls) k -= danumwalls; + memcpy(&wall[startwall+i],&wall[numwalls+k],sizeof(walltype)); + + wall[startwall+i].point2 += danumwalls-startwall-j; + if (wall[startwall+i].point2 >= danumwalls) + wall[startwall+i].point2 -= danumwalls; + wall[startwall+i].point2 += startwall; + } + newfirstwall += danumwalls-j; + if (newfirstwall >= startwall+danumwalls) newfirstwall -= danumwalls; + } + + for(i=0;i= numwallsofloop) k -= numwallsofloop; + memcpy(&wall[startwall+i],&wall[numwalls+k],sizeof(walltype)); + + wall[startwall+i].point2 += numwallsofloop-newfirstwall; + if (wall[startwall+i].point2 >= numwallsofloop) + wall[startwall+i].point2 -= numwallsofloop; + wall[startwall+i].point2 += startwall; + } + + for(i=startwall;i= 0) wall[wall[i].nextwall].nextwall = i; +} + +/* end of engine.c ... */ + + diff --git a/buildengine/engine.h b/buildengine/engine.h new file mode 100755 index 0000000..0df0536 --- /dev/null +++ b/buildengine/engine.h @@ -0,0 +1,998 @@ +/* + * A list of all symbols exported from engine.c for a game's use. + * + * Put together by Ryan C. Gordon (icculus@clutteredmind.org) + * + * Please do NOT harrass Ken Silverman about any code modifications + * (including this file) to BUILD. + */ + +/* + * "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman + * Ken Silverman's official web site: "http://www.advsys.net/ken" + * See the included license file "BUILDLIC.TXT" for license info. + * This file IS NOT A PART OF Ken Silverman's original release + */ + +/**@file engine.h + * @brief Main engine include file. + * + * A list of all symbols exported from engine.c for a game's use. + */ + +#ifndef _INCLUDE_ENGINE_H_ +#define _INCLUDE_ENGINE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define SUPERBUILD /* don't touch this. */ + +/* + * this must be implemented by every program that uses the BUILD engine. + * engine.c calls this function in several places. + * See Ken's test game (in game.c), and his editor (in bstub.c) for examples. + */ +void faketimerhandler(void); + +/* + * exported engine functions, in absolutely no particular order. + * See build.txt, build2.txt...and anything else with a .txt extention for + * information on using these functions that may or may not be accurate. :) + */ +int initmouse(void); + +/**@brief Set the video mode. + * + * This function sets the video mode. + * If you change the mode in your program, + * you must call this again to reset the mode + * before using the build drawing functions. + * @param davidoption The video modeset to use (0-6). + * Allowed options: + * @arg \c 0 -- + * @arg \c 1 -- VESA mode. Any VESA resolution is allowed. + * @arg \c 2 -- + * @arg \c 3 -- + * @arg \c 4 -- + * @arg \c 5 -- + * @arg \c 6 -- + * @param daxdim The x resolution. (must be 320 if param 1 != 1.) + * @param daydim The y resolution. (must be 200 if param 1 != 1.) + */ +int setgamemode(char davidoption, long daxdim, long daydim); + +/**@brief Get the ceiling z value for a point in a sector. + * + * This function returns the Z value of a ceiling at a point in the sector. + * @param sectnum The sector to look in. + * @param dax The x coordinate to look in. + * @param day The y coordinate to look in. + * @return The z coordinate at that point. + */ +int getceilzofslope(short sectnum, long dax, long day); + +/**@brief Get the floor z value for a point in a sector. + * + * This function returns the Z value of a floor at a point in the sector. + * @param sectnum The sector to look in. + * @param dax The x coordinate to look in. + * @param day The y coordinate to look in. + * @return The z coordinate. + */ +int getflorzofslope(short sectnum, long dax, long day); + +/**@brief Get the floor and ceiling z values for a point. + * + * This function finds the Z value of a floor and ceiling, + * and stores the values in two pointers. + * @param sectnum The sector to look in. + * @param dax The x coordinate to look in. + * @param day The y coordinate to look in. + * @param *ceilz A pointer to write the ceiling z value to. + * @param *florz A pointer to write the floor z value to. + */ +void getzsofslope(short sectnum, long dax, long day, long *ceilz, long *florz); + +/**@brief Set aspect ratio and viewing range angle. + * + * This function sets the aspect ratio + * and viewing range angle of the engine. + * Used for weird video modes or special effects. + * @param daxrange Sets the viewing range angle. + * @param daaspect Sets the aspect ratio. + * @remark Ken's Notes on this function: + * \n---------------------\n + * For a standard 90ø 320*200 screen, daxrange and daaspect are + * 65536. For square aspect ratio at 320*400, set daaspect + * to 131072. Since daxrange is actually zoom, you must + * modify the aspect ratio inversely if you only want to + * change the viewing angle. + * \n---------------------\n + * [for daaspect] you pass the Y/X aspect ratio scaled up 16 bits, so + * 65536 would be normal. You don't need to call this if you + * don't want to. By default, in setview, I call setaspect + * with these parameters: + * setaspect(divscale16(ydim*320,xdim*200)); + * (also written as:) + * setaspect(((ydim*320)<<16)/(xdim*200)); + * Note that in 320*200 mode the value passed would be 65536 + * which is a 1:1 aspect ratio. + * \n---------------------\n + * Since drawmapview is also affect by the aspect ratio, you + * will need to make sure drawoverheadmap is affected so + * the map modes match up. Please look at and copy my updated + * drawoverheadmap function into your GAME.C if you use it. + * + */ +void setaspect(long daxrange, long daaspect); + +/**@brief Insert a sprite into a sector. + * + * This function is used to insert a sprite into a sector. + * @param sectnum The sector number to place the sprite into. + * @param statnum The sprite's status. (cstat) + * @return The number assigned to the new sprite. + */ +int insertsprite(short sectnum, short statnum); + +/**@brief Update a sector pointer, given x and y values. + * + * This function updates a pointer with the sector number + * occupied by an x and y value. + * @param x The x coordinate to look up. + * @param y The y coordinate to look up. + * @param *sectnum A pointer to the variable you want to + * write the result into. + * @remark Ken's Notes on this function: + * \n Be careful when you use this function with sprites because + * remember that the sprite's sector number should not be modified directly. + * If you want to update a sprite's sector, I recommend using the setsprite + * function. + * + */ +void updatesector(long x, long y, short *sectnum); + +/**@brief Find the wall to the left of another wall. + * + * Use this function as a reverse function of wall[].point2. + * @param point The wall to search with. + * @return The wall to the left of \a point. + */ +int lastwall(short point); + +/**@brief Set up the sprite lists. + * + * This function will initialize the doubly-linked + * sprite sector and sprite status lists. + */ +void initspritelists(void); + +/**@brief Delete a sprite from the map. + * + * This function will delete a sprite. + * @param spritenum The sprite number to delete. + */ +int deletesprite(short spritenum); +int insertspritesect(short sectnum); +int deletespritesect(short deleteme); +int deletespritestat (short deleteme); +int insertspritestat(short statnum); +int changespritesect(short spritenum, short newsectnum); +int changespritestat(short spritenum, short newstatnum); +/**@brief Loads a tile into memory + * + * This function will ensure \a tilenume is in memory. + * @param tilenume The tile to load. + * @remark Ken's Notes on this function: + * \n A tile is not in the cache if (waloff[tilenum] == 0) + * + */ +void loadtile(short tilenume); +void setmmxoverlay(int isenabled); +int getmmxoverlay(void); + +/**@brief Flip to next drawing page. + * + * This function flips to the next drawing page. After a page is prepared, + * use this function to show the it on the screen and set up the next + * one for drawing. + * + */ +void nextpage(void); + +/**@brief Draw the 3D screen to the current drawing page. + * + * This function draws the current 3D screen to the current + * drawing page. Remember to call \a nextpage() to actually + * show the page on the screen! + * @param daposx X position of the camera. + * @param daposy Y position of the camera. + * @param daposz Z position of the camera. + * @param daang Viewing angle of the camera. + * @param dahoriz ??? fixme + * @param dacursectnum Sector camera is currently in. + */ +void drawrooms(long daposx, long daposy, long daposz, + short daang, long dahoriz, short dacursectnum); + +/**@brief Loads a map from disk. + * + * This function loads a map from disk and stores the starting + * location in the pointers you pass. + * If no extention is given to \a filename, .MAP is assumed. + * @param filename The filename to load. + * @param *daposx A pointer for the starting X coordinate. + * @param *daposy A pointer for the starting Y coordinate. + * @param *daposz A pointer for the starting Z coordinate. + * @param *daang A pointer for the starting angle. + * @param *dacursectnum A pointer for the starting sector. + * @return -1 if the map is not found. + */ +int loadboard(char *filename, long *daposx, long *daposy, + long *daposz, short *daang, short *dacursectnum); + +/**@brief Draw the sprites and maskwalls to the current drawing page. + * + * This function will draw the visible sprites and masked walls + * to the current drawing page. + * @remark Ken's Notes on this function: + * \n This function draws all the sprites and masked walls to the current + * drawing page which is not yet shown. The reason I have the drawing + * split up into these 2 routines is so you can animate just the + * sprites that are about to be drawn instead of having to animate + * all the sprites on the whole board. Drawrooms() prepares these + * variables: spritex[], spritey[], spritepicnum[], thesprite[], + * and spritesortcnt. Spritesortcnt is the number of sprites about + * to be drawn to the page. To change the sprite's picnum, simply + * modify the spritepicnum array If you want to change other parts + * of the sprite structure, then you can use the thesprite array to + * get an index to the actual sprite number. + */ +void drawmasks(void); + +/**@brief Draws a text message to the screen. + * + * This function will draw a message to the screen + * using one of the built in fonts. + * @param xpos X position of text. + * @param ypos Y position of text. + * @param col Color of text. + * @param backcol Background color of text, or -1 for transparency. + * @param name The text to draw. + * @param fontsize The font size. Legal values: 0 -- 8x8 font. 1 -- 4x6 font. + */ +void printext256(long xpos, long ypos, short col, short backcol, + char name[82], char fontsize); + +/**@brief Draws a text message to the screen without refreshing. + * + * This function will draw a message to the screen + * using one of the built in fonts. + * It will also avoid refreshing the screen. See Ryan's notes below. + * @param xpos X position of text. + * @param ypos Y position of text. + * @param col Color of text. + * @param backcol Background color of text, or -1 for transparency. + * @param name The text to draw. + * @param fontsize The font size. Legal values: 0 -- 8x8 font. 1 -- 4x6 font. + * @remark Ryan's notes on this function: + * \n This is ryan's change. SDL requires me to call SDL_UpdateRect() to force + * vid updates without a SDL_Flip() call, but there's no such thing in the + * DOS version of this program, so text won't show up sometimes without + * my update call in Linux. \n However, to get a nice shadow effect on some + * text, Ken draws a string at an offset and darker, and then on top of it + * draws the actual string. \n Two SDL_UpdateRect() calls in over top of each + * other cause flicker, so I have this function here so the shadow can + * be drawn with _noupdate, and the actual string is draw with an update. + */ +void printext256_noupdate(long xpos, long ypos, short col, short backcol, + char name[82], char fontsize); + +/**@brief Initialize the Build Engine. + * + * This function initializes many variables for the Build Engine. + * You should call this function before using any other Build functions. + */ +void initengine(void); + +/**@brief Uninitialize the Build Engine. + * + * This function frees the buffers used by the build engine. + * You should call this function once before you end your program. + */ +void uninitengine(void); + +/**@brief Loads an artwork file into the engine. + * + * This function is used to load an artwork file into memory + * so the engine knows where to find the tiles + * referenced by the artwork file. + * If no extention is given to \a filename, .ART is assumed. + * @param *filename The name of the artwork file. + * @return -1 if the file was not found. + */ +int loadpics(char *filename); + +/**@brief Saves a map to disk. + * + * This function dumps the working map to disk, + * using the pointers you pass as the starting location. + * If no extention is given to \a filename, .MAP is assumed. + * @param filename The filename to save. + * @param *daposx A pointer containing the starting X coordinate. + * @param *daposy A pointer containing the starting Y coordinate. + * @param *daposz A pointer containing the starting Z coordinate. + * @param *daang A pointer containing the starting angle. + * @param *dacursectnum A pointer containing the starting sector. + */ +int saveboard(char *filename, long *daposx, long *daposy, long *daposz, + short *daang, short *dacursectnum); + +/**@brief Plots a pixel to the screen. + * + * This function can plot a pixel to the screen + * in any graphics mode. \n + * NOTE: This function is not designed to be fast! + * Use it in moderation. + * @param x The x coordinate of the pixel. + * @param y The y coordinate of the pixel. + * @param col The color of the pixel. + */ +void plotpixel(long x, long y, char col); + +/**@brief Returns the color of a pixel on screen. + * + * This function will find the color of a pixel + * in any graphics mode. \n + * NOTE: This function is not designed to be fast! + * -- Use it in moderation. + * @param x The x cordinate of the pixel. + * @param y The y coordinate of the pixel. + * @return The color of the pixel. + */ +unsigned char getpixel(long x, long y); + +/**@brief Adjust the gamma of a VGA palette. + * + * This function will adjust the brightness of colors in \a dapal. + * @param dabrightness The gamma level. Accepted range of 0-15, + * where 0 is the darkest and 15 is the lightest. + * @param *dapal A pointer to a standard 768 byte VGA palette. + */ +void setbrightness(char dabrightness, unsigned char *dapal); + +/**@brief Take a screenshot. + * + * This function will dump a picture of the current screen + * to a file. \n + * Set \a inverseit to 1 if you want the colors inverted. + * @param *filename The filename to write to. + * @param inverseit Set to 1 if you want the colors inverted. + * @remark Notes on \a filename: + * \n If you use "captxxxx.pcx" as your filename, + * Build will automatically replace the x's with + * an automatically incrementing number, starting + * from 0000. + */ +int screencapture(char *filename, char inverseit); + +/**@brief Get the current mouse location and button state. + * + * This function will store the current mouse position and + * the state of the mouse buttons in the pointers you give it. + * @param mousx A pointer to write the X position of the mouse to. + * @param mousy A pointer to write the Y position of the mouse to. + * @param bstatus A pointer to write the current state of the mouse buttons to. + * @remark \a bstatus is a bitmask of the mouse states: + * @arg 1 -- Left button is down. + * @arg 2 -- Right button is down. + * @arg 4 -- Middle button is down. + */ +void getmousevalues(short *mousx, short *mousy, short *bstatus); + +/**@brief Move an object using collision detection. + * + * This function will move any object at any velocity + * and make sure the object stays a certain distance from walls. + * @param *x A pointer to the object's X coordinate. + * @param *y A pointer to the object's Y coordinate. + * @param *z A pointer to the object's Z coordinate. + * @param *sectnum A pointer to the object's current sector. + * @param xvect The desired X velocity of movement. + * @param yvect The desired Y velocity of movement. + * @param walldist The distance the object should stay away from walls. + * @param ceildist The distance the object should stay away from the ceiling. + * @param flordist The distance the object should stay away from the floor. + * @param cliptype See description below. + * @return Status of clipping: + * @arg 0 -- Nothing was touched. + * @arg 32768+wallnum -- Wall first touched. + * @arg 49152+wallnum -- Sprite first touched. + * @remark Notes on this function: + * \n xvect and yvect are calculated with the following equations: + * @arg xvect = velocity * cos(angle) + * @arg yvect = velocity * sin(angle) + * @remark Ken uses 128 for walldist as his default. + * \n Don't suddenly increase walldist -- it may cause an object to go + * throught the wall! + * \n Cliptype is a mask that tells whether the object should be clipped + * to or not. \n The lower 16 bits are anded with wall[].cstat and the higher + * 16 bits are anded with sprite[].cstat. + */ +int clipmove (long *x, long *y, long *z, short *sectnum, long xvect, + long yvect, long walldist, long ceildist, + long flordist, unsigned long cliptype); + +/**@brief Find the highest and lowest z coordinates your clipping box can get to. + * + * This function finds the highest and lowest z coordinates your clipping box can get to. + * @param x X coordinate of location. + * @param y Y coordinate of location. + * @param z Z coordinate of location. + * @param sectnum Current sector. + * @param *ceilz Pointer to store Z extent of ceiling. + * @param *florz Pointer to store Z extent of floor. + * @param *ceilhit First object hit in the up direction. + * @param *florhit First object hit in the down direction. + * @param walldist Size of your clipping box. + * @param cliptype See description below. + * @remark Notes on this function: \n + * \a walldist is suggested to be 128. \n + * \a ceilhit and \a florhit will be the following after the function call: \n + * 16384+sector (sector first touched) or \n + * 49152+spritenum (sprite first touched) + */ +void getzrange(long x, long y, long z, short sectnum, + long *ceilz, long *ceilhit, long *florz, long *florhit, + long walldist, unsigned long cliptype); + +/**@brief Gets the angle of a vector. + * + * This function will return the angle closest to the + * vector you specify. \n + * There are 2048 possible angles, starting from the right (3 o'clock), going clockwise. + * @param xvect The x component. + * @param yvect The y component. + */ +int getangle(long xvect, long yvect); + +/**@brief Adjust the slope of a sector's ceiling to pass through a point + * + * This function will cause the slope of a sector to change + * and the sector plane to pass through the point specified. + * @param dasect The sector to modify. + * @param x The X coordinate to intersect. + * @param y The Y coordinate to intersect. + * @param z The Z coordinate to intersect. + * @remark Given a sector and assuming it's first wall + * is the pivot wall of the slope, + * this function makes the slope pass through the x,y,z point. + */ +void alignceilslope(short dasect, long x, long y, long z); + +/**@brief Adjust the slope of a sector's floor to pass through a point + * + * This function will cause the slope of a sector to change + * and the sector plane to pass through the point specified. + * @param dasect The sector to modify. + * @param x The X coordinate to intersect. + * @param y The Y coordinate to intersect. + * @param z The Z coordinate to intersect. + * @remark Given a sector and assuming it's first wall + * is the pivot wall of the slope, + * this function makes the slope pass through the x,y,z point. \n + * One use of this function is sine-wave floors. + */ +void alignflorslope(short dasect, long x, long y, long z); + +/**@brief Project a ray and report what it hit. + * + * This function will project a ray in the direction + * specified by a 3D vector + * and report where and what the ray hit. + * @param xs Starting X position. + * @param ys Starting Y position. + * @param zs Starting Z position. + * @param sectnum Starting sector. + * @param vx X component of 3D vector. + * @param vy Y component of 3D vector. + * @param vz Z component of 3D vector. + * @param *hitsect The sector that the intersection occured in. + * @param *hitwall The wall that got hit. + * @param *hitsprite The sprite that got hit. + * @param *hitx The X coordinate of the point that the intersection occured. + * @param *hity The Y coordinate of the point that the intersection occured. + * @param *hitz The Z coordinate of the point that the intersection occured. + * @param cliptype See description below. + * @remark Notes on this function: \n + * HOW TO DETERMINE WHAT WAS HIT:\n + * If the ray hits a sprite, then + * @arg hitsprite = thespritenumber. + * @arg hitwall = -1. + * @remark If the ray hits a wall, then + * @arg hitsprite = -1 + * @arg hitwall = thewallnumber + * @remark If the ray hits the ceiling of a sector, then + * @arg hitsprite = -1 + * @arg hitwall = -1 + * @arg vectorz < 0 + * @arg (If vectorz < 0 then you're shooting upward which means + * that you couldn't have hit a floor) + * @remark If the ray hits the floor of a sector, then + * @arg hitsprite = -1 + * @arg hitwall = -1 + * @arg vectorz > 0 + * @arg (If vectorz > 0 then you're shooting downard which means + * that you couldn't have hit a ceiling) + */ +int hitscan(long xs, long ys, long zs, short sectnum, + long vx, long vy, long vz, + short *hitsect, short *hitwall, short *hitsprite, + long *hitx, long *hity, long *hitz, unsigned long cliptype); + +/**@brief Tests to see if a 2d point is in a sector. + * + * This function will check if a 2d point is inside a sector. + * @param x X coordinate of point. + * @param y Y coordinate of point. + * @param sectnum The sector to test against. + */ +int inside (long x, long y, short sectnum); + +/**@brief Sets the first wall of a sector. + * + * This function sets the first wall of a sector. + * It can be used to change the hinge wall of a slope, + * among other things. + * @param sectnum The sector to modify. + * @param newfirstwall The wall to set as the first wall. + */ +void setfirstwall(short sectnum, short newfirstwall); + +/**@brief Rotate / translate a point. + * + * This function is a very convenient and fast math helper function. + * Rotate points easily with this function without having to juggle your + * cosines and sines. + * @param xpivot X coordinate of point to pivot about. + * @param ypivot Y coordinate of point to pivot about. + * @param x X coordinate of point to translate. + * @param y Y coordinate of point to translate. + * @param daang Angle to rotate (CW, relative) + * @param *x2 X coordinate of the translated point. + * @param *y2 Y coordinate of the translated point. + */ +void rotatepoint(long xpivot, long ypivot, long x, long y, short daang, + long *x2, long *y2); + +/**@brief Draw the tile screen. + * + * This function draws the tile chooser in Build. + * (what you get when you press "v".) + * @param pictopleft The first tile to show. + * @param picbox The tile to highlight. + */ +int drawtilescreen(long pictopleft, long picbox); + +/**@brief Clear the current video page to a given color. + * + * This function clears the current video page to the color \a dacol. + * @param dacol The color to clear to. + */ +void clearview(long dacol); + +/**@brief Clear all video pages to a given color. + * + * This function clears all the video pages to the color \a dacol. + * @param dacol The color to clear to. + */ +void clearallviews(long dacol); + +/**@brief Draw a 2D grid. + * + * This function is used by Build to draw the grid in 2D. \n + * NOTE: This function works only in two graphics modes: \n + * 640*350*16col, 640*480*16col. + * @param posxe Left side of visible grid. + * @param posye Top side of visible grid. + * @param ange Not used. + * @param zoome Zoom factor of grid. + * @param gride The grid's scale. + * @remark Please do not use this function. It is only public + * because the build editor needs it. + */ +void draw2dgrid(long posxe, long posye, short ange, long zoome, + short gride); + +/**@brief Draw the 2D screen. + * + * Thus function is used by build to draw the 2d screen. \n + * See draw2dgrid for explanation. + * @remark Please do not use this function. It is only public + * because the build editor needs it. + */ +void draw2dscreen(long posxe, long posye, short ange, long zoome, + short gride); + +/**@brief A fast routine to find the sector that owns a certain wall. + * + * This function will find the sector that owns the wall \a theline. + * @param theline The wall to lookup. + * @return The sector the wall belongs to. + */ +int sectorofwall(short theline); + +/**@brief Puts a sprite somewhere, without checking for validity. + * + * This function will move a sprite to anywhere on the map, + * regardless of whether the new place is valid. + * @param spritenum The sprite to move. + * @param newx The X coordinate to move to. + * @param newy The Y coordinate to move to. + * @param newz The Z coordinate to move to. + */ +int setsprite(short spritenum, long newx, long newy, long newz); + +/**@brief Drag a wall to a new point. + * + * This function will reliabaly drag a point to a new location + * on the map, using a method identical to dragging the point in 2D edit mode. + * @param pointhighlight The wall to drag. + * @param dax The X coordinate to drag to. + * @param day The Y coordinate to drag to. + * @remark Ken's Notes about this function: + * Every wall of course has 2 points. When you + * pass a wall number to this function, you are actually passing 1 point, + * the left side of the wall (given that you are in the sector of that wall) + * Got it? + */ +void dragpoint(short pointhighlight, long dax, long day); + +/**@brief Integer Square Root Function + * + * This function will return an integer approximating + * the square root of a number. + * @param num The number to work on. + * @return The square root of \a num. + */ +int ksqrt(long num); + +/**@brief Find number of walls in sector, up to a known wall. + * + * This function will find the number of walls in a sector, + * up to the specified wall. + * @param sectnum The sector to work on. + * @param wallnum The wall to stop on. + * @return The number of walls in \a sectnum before \a wallnum, + * or -1 if \a wallnum does not occur in \a sectnum. + */ +int loopnumofsector(short sectnum, short wallnum); + +/**@brief Check if two points can see each other. + * + * This function will determine whether there is a line + * of sight between two points. + * @param x1 X coordinate of point 1. + * @param y1 Y coordinate of point 1. + * @param z1 Z coordinate of point 1. + * @param sect1 Point 1's sector. + * @param x2 X coordinate of point 2. + * @param y2 Y coordinate of point 2. + * @param z2 Z coordinate of point 2. + * @param sect2 Point 2's sector. + */ +int cansee(long x1, long y1, long z1, short sect1, + long x2, long y2, long z2, short sect2); +int lintersect(long x1, long y1, long z1, long x2, long y2, long z2, + long x3, long y3, long x4, long y4, long *intx, + long *inty, long *intz); +int rintersect(long x1, long y1, long z1, long vx, long vy, long vz, + long x3, long y3, long x4, long y4, long *intx, + long *inty, long *intz); + +/**@brief Allocate a tile permanently. + * + * This function allocates a place on the cache as permanent. + * @param tilenume The tile number to associate with the memory. + * @param xsiz The width to allocate. + * @param ysiz The height to allocate. + * @remark Ken's Notes on this function: \n + * Right now, I reset the cache every time you call this + * function so I would recommend calling this function + * right after loadpics. + */ +int allocatepermanenttile(short tilenume, long xsiz, long ysiz); + +/**@brief Draw a line. + * + * This function draws a colored, solid line. + * @param x1 X coordinate of starting point. + * @param y1 Y coordinate of starting point. + * @param x2 X coordinate of ending point. + * @param y2 Y coordinate of ending point. + * @param col Color to use. + */ +void drawline256 (long x1, long y1, long x2, long y2, unsigned char col); + +/**@brief Copy a piece of a tile to another tile, skipping transparent pixels. + * + * This function will copy a piece of \a tilenume1 into \a tilenume2, + * skipping transparent parts. If the source coordinates are larger + * than the source tile, the texture will automatically wrap around. \n + * NOTE: IF THE MODIFIED TILE GETS REMOVED FROM THE CACHE, + * \a tilenume2 WILL BE RESET TO ITS ORIGINAL FORM. \n + * IF YOU NEED TO KEEP THE TILE CREATED BY THIS FUNCTION, + * CALL \a allocatepermanenttile ON IT FIRST! + * @param tilenume1 The source tile + * @param sx1 X coordinate to start the copy from + * @param sy1 Y coordinate to start the copy from. + * @param xsiz The width to copy from the source. + * @param ysiz The height to copy from the source. + * @param tilenume2 The destination tile. + * @param sx2 The X coordinate to paste at. + * @param sy2 The Y coordinate to paste at. + */ +void copytilepiece(long tilenume1, long sx1, long sy1, long xsiz, long ysiz, + long tilenume2, long sx2, long sy2); + +/**@brief Find the next closest ceiling or floor in surrounding sectors. + * + * This function will find the next closest ceiling or floor in the sectors surrounding + * the given sector. It is useful for calculating where elevators + * should stop. + * @param sectnum The sector to test with + * @param thez The z coordinate to start the search from. + * @param topbottom Search ceilings/floors only. + * @param direction Search up/down. + * @remark Notes: \n + * \a topbottom: pass -1 to search ceilings, 1 to search floors. \n + * \a direction: pass -1 to search upwards, 1 to search downwards. + */ +int nextsectorneighborz(short sectnum, long thez, + short topbottom, short direction); + +/**@brief Find the closest objects with tags the player is pointing at. + * + * This function will get the nearest tagged objects. It is useful for door + * and switch activation code, among other things. + * @param xs X coordinate to search from. + * @param ys Y coordinate to search from. + * @param zs Z coordinate to search from. + * @param sectnum Sector number to search from. + * @param ange Angle to search from. + * @param *neartagsector The nearest tagged sector. + * @param *neartagwall The nearest tagged wall. + * @param *neartagsprite The nearest tagged sprite. + * @param *neartaghitdist Distance to the found object. + * @param neartagrange Maximum distance to search. + * @param tagsearch What to search for. + * @remark Notes on this function: \n + * For \a tagsearch: + * @arg 1 = search lotag only. + * @arg 2 = search hitag only. + * @arg 3 = search both lotag and hitag. + */ +int neartag(long xs, long ys, long zs, short sectnum, short ange, + short *neartagsector, short *neartagwall, short *neartagsprite, + long *neartaghitdist, long neartagrange, char tagsearch); + +/**@brief Try to keep object away from wall. + * + * This function checks if an object is too close to a wall. + * If it is, it attempts to push it away. + * If it tries to push 256 times, and the object is still too close, + * it returns -1. + * @param *x Object's X coordinate. + * @param *y Object's Y coordinate. + * @param *z Object's Z coordinate. + * @param *sectnum Object's sector. + * @param walldist Distance to avoid walls by. + * @param ceildist Distance to avoid ceilings by. + * @param flordist Distane to avoid floors by. + * @param cliptype See below. + * @remark Notes on this function: \n + * Cliptype is a mask that tells whether the object should be clipped + * to or not. The lower 16 bits are anded with wall[].cstat and the higher + * 16 bits are anded with sprite[].cstat. + */ +int pushmove(long *x, long *y, long *z, short *sectnum, + long walldist, long ceildist, long flordist, + unsigned long cliptype); + +/**@brief Returns a random number. + * + * This function returns a pseudorandom number in the range 0-65535. + * @return A random number. + */ +int krand(void); +void flushperms(void); + +/**@brief Rotate and draw a sprite on the screen. + * + * This function will rotate and draw a sprite onto the screen. + * See notes for proper usage. + * @param sx X center of sprite to draw. + * @param sy Y center of sprite to draw. + * @param z Zoom to draw with. + * @param a Angle to draw at. + * @param picnum The tile to draw. + * @param dashade The shade to draw with. + * @param dapalnum The palette to draw with. + * @param dastat Drawing options. + * @param cx1 Upper left of screen clipping box X. + * @param cy1 Upper left of screen clipping box Y. + * @param cx2 Lower right of screen clipping box X. + * @param cy2 Lower right of screen clipping box Y. + * @remark Ken's Notes on this function. + * @arg (sx, sy) is the center of the sprite to draw defined as + * screen coordinates shifted up by 16. + * @arg (z) is the zoom. Normal zoom is 65536. + * Ex: 131072 is zoomed in 2X and 32768 is zoomed out 2X. + * @arg (a) is the angle (0 is straight up) + * @arg (picnum) is the tile number + * @arg (dashade) is 0 normally but can be any standard shade up to 31 or 63. + * @arg (dapalnum) can be from 0-255. + * @arg if ((dastat&1) == 0) - no transluscence + * @arg if ((dastat&1) != 0) - transluscence + * @arg if ((dastat&2) == 0) - don't scale to setview's viewing window + * @arg if ((dastat&2) != 0) - scale to setview's viewing window (windowx1,etc.) + * @arg if ((dastat&4) == 0) - nuttin' special + * @arg if ((dastat&4) != 0) - y-flip image + * @arg if ((dastat&8) == 0) - clip to startumost/startdmost + * @arg if ((dastat&8) != 0) - don't clip to startumost/startdmost + * @arg if ((dastat&16) == 0) - use Editart center as point passed + * @arg if ((dastat&16) != 0) - force point passed to be top-left corner + * @arg if ((dastat&32) == 0) - nuttin' special + * @arg if ((dastat&32) != 0) - use reverse transluscence + * @arg if ((dastat&64) == 0) - masked drawing (check 255's) (slower) + * @arg if ((dastat&64) != 0) - draw everything (don't check 255's) (faster) + * @arg if ((dastat&128) == 0) - nuttin' special + * @arg if ((dastat&128) != 0) - automatically draw to all video pages + * @remark Note: As a special case, if both ((dastat&2) != 0) and ((dastat&8) != 0) + * then rotatesprite will scale to the full screen (0,0,xdim-1,ydim-1) + * rather than setview's viewing window. (windowx1,windowy1,etc.) + * This case is useful for status bars, etc.\n \n + * Ex: rotatesprite(160L<<16,100L<<16,65536,totalclock<<4, + * DEMOSIGN,2,50L,50L,270L,150L); + * This example will draw the DEMOSIGN tile in the center of the + * screen and rotate about once per second. + * The sprite will only get drawn inside the rectangle from (50,50) to (270,150). + */ +void rotatesprite(long sx, long sy, long z, short a, short picnum, + signed char dashade, char dapalnum, char dastat, + long cx1, long cy1, long cx2, long cy2); +/**@brief Make a lookup table for remapping. + * + * Ken's description of this function: + * This function allows different shirt colors for sprites. + * First prepare \a remapbuf, which is a 256 byte buffer of chars + * with the colors to remap. \n + * Palnum can be anywhere from 1-15. \n + * Since 0 is where the normal palette is stored, it is a bad + * idea to call this function with palnum=0. \n + * In BUILD.H notice I added a new variable, spritepal[MAXSPRITES]. \n + * Usually the value of this is 0 for the default palette. \n + * But if you change it to the palnum in the code between + * drawrooms() and drawmasks then the sprite will be drawn + * with that remapped palette. \n + * The last 3 parameters are the color that the palette fades to + * as you get further away. \n + * This color is normally black (0,0,0). \n White would be (63,63,63). \n + * if ((dastat&1) == 0) then makepalookup will allocate & deallocate + * the memory block for use but will not waste the time creating a palookup + * table (it assumes you will create one yourself). + */ +void makepalookup(long palnum, char *remapbuf, signed char r, + signed char g, signed char b, char dastat); + +/**@brief Draw the overhead textured map view. + * + * This function is used to draw the overhead textured map view. + * @param dax The x coordinate to center on the map. + * @param day The y coordinate to center on the map. + * @param zoome The zoom to apply to the map. + * @param ang The angle to rotate the map by. + */ +void drawmapview(long dax, long day, long zoome, short ang); + +/**@brief Sets the viewing window for 3D mode. + * + * This function will cause the engine to draw + * the 3D view in a specified portion of the screen. + * @param x1 upper left X coordinate. + * @param y1 upper left Y coordinate. + * @param x2 lower right X coordinate. + * @param y2 lower right Y coordinate. + * @remark Example: For full screen 320*200, call like this: setview(0L,0L,319L,199L); + */ +void setview(long x1, long y1, long x2, long y2); + +/**@brief Shows a tile on screen, saving the previous view. + * + * This function will show a tile on screen, saving the previous + * view. You can call this multiple times, and calling \a setviewback + * will go to the last view. If you keep calling \a setback, you + * will eventually get back to your original screen. + * All drawing starts in the top left corner. + * @param tilenume Tile to show. + * @param xsiz X size to draw. + * @param ysiz Y size to draw. + */ +void setviewtotile(short tilenume, long xsiz, long ysiz); + +/**@brief Shows the screen as it was previous to the last \a setviewtotile. + * + * This function will show the screen as it was before the last call to \a setviewtotile. + */ +void setviewback(void); + +/**@brief Rotates a tile's image. + * + * This function will rotate the graphic of a tile. + * It only works with square tiles. + * @param tilenume The tile to perform the rotation on. + */ +void squarerotatetile(short tilenume); +void preparemirror(long dax, long day, long daz, + short daang, long dahoriz, short dawall, + short dasector, long *tposx, long *tposy, + short *tang); +void completemirror(void); + +/**@brief Check if a clipping box intersects a wall + * + * This function will test if a box intersects a wall.\n + * It returns TRUE if an intersection ocurrs. + * @param x Center of box X. + * @param y Center of box Y. + * @param wallnum Wall to test against. + * @param walldist Radius of clipping box. + * @return TRUE if an intersection ocurred. + */ +int clipinsidebox(long x, long y, short wallnum, long walldist); + +#ifdef SUPERBUILD + +/**@brief Load a voxel. + * + * This function will load a voxel that can be used to replace a sprite. \n + * See notes below. + * @param voxindex The voxel number to use. + * @param *filename The voxel file to load. + * @remark Ken's Notes on Using Voxels: \n + * To actually display the voxel, you need to set the + * (sprite[?].cstat&48) to equal 48 like this: \n + * sprite[?].cstat |= 48; \n + * I have no special collision code for voxels. They are simply + * treated as face sprites. \n \n + * You should set the sprite[?].picnum to equal the VOXEL + * index of the voxel that you passed to qloadkvx. If you don't + * do this you will see nothing. To handle this index remapping + * it is a good idea to make some array like this: \n + * short picnumtovox[MAXTILES]; \n + * and save the array in some file (or in the .GRP file) \n + * Many other fields of the sprite structure also affect voxels, + * such as: ang, shade, pal, xrepeat, yrepeat. \n \n + * Note: To view voxels in the Build editor, you will need to do + * the same qloadkvx calls in your BSTUB.C. \n + * And now a warning: Voxels tend to draw the fastest when + * they are tall and thin. \n For example, a telephone pole + * would work just great. \n They slow down very quickly as + * you add detail. \n This is why you don't see any large + * voxels in SW and Blood. + */ +void qloadkvx(long voxindex, char *filename); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* !defined _INCLUDE_ENGINE_H_ */ + +/* end of engine.h ... */ + + + diff --git a/buildengine/engine_protos.h b/buildengine/engine_protos.h new file mode 100755 index 0000000..ac9fa7d --- /dev/null +++ b/buildengine/engine_protos.h @@ -0,0 +1,256 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment + +This file is part of Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +//------------------------------------------------------------------------- + +/* Prototypes for the build engine */ + +#if 0 +/* game.c */ +extern void initsb(char dadigistat, char damusistat, long dasamplerate, char danumspeakers, char dabytespersample, char daintspersec, char daquality); +extern void uninitsb(void); +extern int loadsong(char *filename); +extern void musicon(void); +extern void musicoff(void); +extern void wsayfollow(char *dafilename, long dafreq, long davol, long *daxplc, long *dayplc, char followstat); +extern void wsay(char *dafilename, long dafreq, long volume1, long volume2); +extern void preparesndbuf(void); +extern void setears(long daposx, long daposy, long daxvect, long dayvect); +extern void timerhandler(void); +extern void keyhandler(void); +extern void initlava(void); +extern void movelava(char *dapic); +extern void drawtilebackground(long thex, long they, short tilenum, signed char shade, long cx1, long cy1, long cx2, long cy2, char dapalnum); +extern void printext(long x, long y, char *buffer, short tilenum, char invisiblecol); +extern void drawstatusflytime(short snum); +extern void drawstatusbar(short snum); +extern void setup3dscreen(void); +extern void setinterpolation(long *posptr); +extern void stopinterpolation(long *posptr); +extern void updateinterpolations(void); +extern void restoreinterpolations(void); +extern void searchmap(short startsector); +extern void prepareboard(char *daboardfilename); +extern long changehealth(short snum, short deltahealth); +extern void changenumbombs(short snum, short deltanumbombs); +extern void changenummissiles(short snum, short deltanummissiles); +extern void changenumgrabbers(short snum, short deltanumgrabbers); +extern void findrandomspot(long *x, long *y, short *sectnum); +extern void operatesector(short dasector); +extern void shootgun(short snum, long x, long y, long z, short daang, long dahoriz, short dasectnum, char guntype); +extern void operatesprite(short dasprite); +extern void checktouchsprite(short snum, short sectnum); +extern void checkgrabbertouchsprite(short snum, short sectnum); +extern void activatehitag(short dahitag); +extern void processinput(short snum); +extern void movethings(void); +extern void fakedomovethings(void); +extern void fakedomovethingscorrect(void); +extern void doanimations(void); +extern void warp(long *x, long *y, long *z, short *daang, short *dasector); +extern void warpsprite(short spritenum); +extern int testneighborsectors(short sect1, short sect2); +extern void tagcode(void); +extern void bombexplode(long i); +extern void statuslistcode(void); +extern void checkmasterslaveswitch(void); +extern void getpackets(void); +extern void initplayersprite(short snum); +extern void analyzesprites(long dax, long day); +extern void updatesectorz(long x, long y, long z, short *sectnum); +extern void drawoverheadmap(long cposx, long cposy, long czoom, short cang); +extern void drawscreen(short snum, long dasmoothratio); +extern int loadgame(void); +extern int savegame(void); +extern void faketimerhandler(void); +extern void waitforeverybody(void); +#endif + +/* cache1d.c */ +extern void initcache(long dacachestart, long dacachesize); +extern void allocache(long *newhandle, long newbytes, unsigned char *newlockptr); +extern void suckcache(long *suckptr); +extern void agecache(void); +extern void reportandexit(char *errormessage); +extern long initgroupfile(const char *filename); +extern void uninitgroupfile(void); +extern long kopen4load(const char *filename, char searchfirst); +extern long kread(long handle, void *buffer, long leng); +extern int kread8(long handle, char *buffer); +extern int kread16(long handle, short *buffer); +extern int kread32(long handle, long *buffer); +extern long klseek(long handle, long offset, long whence); +extern long kfilelength(long handle); +extern void kclose(long handle); +extern void kdfread(void *buffer, size_t dasizeof, size_t count, long fil); +extern void kdfread8(char *buffer, size_t count, long fil); +extern void kdfread16(short *buffer, size_t count, long fil); +extern void kdfread32(long *buffer, size_t count, long fil); +extern void dfread(void *buffer, size_t dasizeof, size_t count, FILE *fil); +extern void dfread8(char *buffer, size_t count, FILE *fil); +extern void dfread16(short *buffer, size_t count, FILE *fil); +extern void dfread32(long *buffer, size_t count, FILE *fil); +extern void dfwrite(void *buffer, size_t dasizeof, size_t count, FILE *fil); +extern void dfwrite8(char *buffer, size_t count, FILE *fil); +extern void dfwrite16(short *buffer, size_t count, FILE *fil); +extern void dfwrite32(long *buffer, size_t count, FILE *fil); +extern long compress(char *lzwinbuf, long uncompleng, char *lzwoutbuf); +extern long uncompress(char *lzwinbuf, long compleng, char *lzwoutbuf); + +/* sdl_driver.c */ +extern int using_opengl(void); +extern void _handle_events(void); +extern unsigned char _readlastkeyhit(void); +extern int mprotect_align(const void *addr, size_t len, int prot); +extern void unprotect_ASM_pages(void); +extern void _platform_init(int argc, char **argv, const char *title, const char *icon); +extern int setvesa(long x, long y); +extern int screencapture(char *filename, char inverseit); +extern void setvmode(int mode); +extern int _setgamemode(char davidoption, long daxdim, long daydim); +extern void qsetmode640350(void); +extern void qsetmode640480(void); +extern void getvalidvesamodes(void); +extern int VBE_setPalette(long start, long num, char *palettebuffer); +extern int VBE_getPalette(long start, long num, char *palettebuffer); +extern void _uninitengine(void); +extern void uninitvesa(void); +extern int setupmouse(void); +extern void readmousexy(short *x, short *y); +extern void readmousebstatus(short *bstatus); +extern void _updateScreenRect(long x, long y, long w, long h); +extern void _nextpage(void); +extern unsigned char readpixel(long offset); +extern void drawpixel(long offset, unsigned char pixel); +extern void drawpixels(long offset, unsigned short pixels); +extern void drawpixelses(long offset, unsigned int pixelses); +extern void setcolor16(int col); +extern void drawpixel16(long offset); +extern void fillscreen16(long offset, long color, long blocksize); +extern void drawline16(long XStart, long YStart, long XEnd, long YEnd, char Color); +extern void clear2dscreen(void); +extern void _idle(void); +extern void *_getVideoBase(void); +extern void setactivepage(long dapagenum); +extern void limitrate(void); +extern void inittimer(void); +extern void uninittimer(void); +extern void initkeys(void); +extern void uninitkeys(void); +extern void set16color_palette(void); +extern void restore256_palette(void); +extern unsigned long getticks(void); + +/* mmulti.c */ +extern void callcommit(void); +extern void initcrc(void); +extern long getcrc(char *buffer, short bufleng); +extern void initmultiplayers(char damultioption, char dacomrateoption, char dapriority); +extern void sendpacket(long other, char *bufptr, long messleng); +extern void setpackettimeout(long datimeoutcount, long daresendagaincount); +extern void uninitmultiplayers(void); +extern void sendlogon(void); +extern void sendlogoff(void); +extern int getoutputcirclesize(void); +extern void setsocket(short newsocket); +extern short getpacket(short *other, char *bufptr); +extern void flushpackets(void); +extern void genericmultifunction(long other, char *bufptr, long messleng, long command); + +/* engine.c */ +extern int setgotpic(long i1); +extern long getclipmask(int i1, int i2, int i3, int i4); +extern int wallfront(long l1, long l2); +extern void drawrooms(long daposx, long daposy, long daposz, short daang, long dahoriz, short dacursectnum); +extern int loadboard(char *filename, long *daposx, long *daposy, long *daposz, short *daang, short *dacursectnum); +extern int saveboard(char *filename, long *daposx, long *daposy, long *daposz, short *daang, short *dacursectnum); +extern int setgamemode(char davidoption, long daxdim, long daydim); +extern void setmmxoverlay(int isenabled); +extern int getmmxoverlay(void); +extern void initengine(void); +extern void uninitengine(void); +extern void nextpage(void); +extern void loadtile(short tilenume); +extern int allocatepermanenttile(short tilenume, long xsiz, long ysiz); +extern int loadpics(char *filename); +extern void qloadkvx(long voxindex, char *filename); +extern int clipinsidebox(long x, long y, short wallnum, long walldist); +extern void drawline256(long x1, long y1, long x2, long y2, unsigned char col); +extern int inside(long x, long y, short sectnum); +extern int getangle(long xvect, long yvect); +extern int ksqrt(long num); +extern void copytilepiece(long tilenume1, long sx1, long sy1, long xsiz, long ysiz, long tilenume2, long sx2, long sy2); +extern void drawmasks(void); +extern int setsprite(short spritenum, long newx, long newy, long newz); +extern void initspritelists(void); +extern int insertsprite(short sectnum, short statnum); +extern int insertspritesect(short sectnum); +extern int insertspritestat(short statnum); +extern int deletesprite(short spritenum); +extern int deletespritesect(short deleteme); +extern int deletespritestat(short deleteme); +extern int changespritesect(short spritenum, short newsectnum); +extern int changespritestat(short spritenum, short newstatnum); +extern int nextsectorneighborz(short sectnum, long thez, short topbottom, short direction); +extern int cansee(long x1, long y1, long z1, short sect1, long x2, long y2, long z2, short sect2); +extern int lintersect(long x1, long y1, long z1, long x2, long y2, long z2, long x3, long y3, long x4, long y4, long *intx, long *inty, long *intz); +extern int rintersect(long x1, long y1, long z1, long vx, long vy, long vz, long x3, long y3, long x4, long y4, long *intx, long *inty, long *intz); +extern int hitscan(long xs, long ys, long zs, short sectnum, long vx, long vy, long vz, short *hitsect, short *hitwall, short *hitsprite, long *hitx, long *hity, long *hitz, unsigned long cliptype); +extern int neartag(long xs, long ys, long zs, short sectnum, short ange, short *neartagsector, short *neartagwall, short *neartagsprite, long *neartaghitdist, long neartagrange, char tagsearch); +extern void dragpoint(short pointhighlight, long dax, long day); +extern int lastwall(short point); +extern int clipmove(long *x, long *y, long *z, short *sectnum, long xvect, long yvect, long walldist, long ceildist, long flordist, unsigned long cliptype); +extern int pushmove(long *x, long *y, long *z, short *sectnum, long walldist, long ceildist, long flordist, unsigned long cliptype); +extern void updatesector(long x, long y, short *sectnum); +extern void rotatepoint(long xpivot, long ypivot, long x, long y, short daang, long *x2, long *y2); +extern int initmouse(void); +extern void getmousevalues(short *mousx, short *mousy, short *bstatus); +extern void draw2dgrid(long posxe, long posye, short ange, long zoome, short gride); +extern void draw2dscreen(long posxe, long posye, short ange, long zoome, short gride); +extern void printext256(long xpos, long ypos, short col, short backcol, char name[82], char fontsize); +extern void printext256_noupdate(long xpos, long ypos, short col, short backcol, char name[82], char fontsize); +extern int krand(void); +extern void getzrange(long x, long y, long z, short sectnum, long *ceilz, long *ceilhit, long *florz, long *florhit, long walldist, unsigned long cliptype); +extern void setview(long x1, long y1, long x2, long y2); +extern void setaspect(long daxrange, long daaspect); +extern void flushperms(void); +extern void rotatesprite(long sx, long sy, long z, short a, short picnum, signed char dashade, char dapalnum, char dastat, long cx1, long cy1, long cx2, long cy2); +extern void makepalookup(long palnum, char *remapbuf, signed char r, signed char g, signed char b, char dastat); +extern void setbrightness(char dabrightness, unsigned char *dapal); +extern void drawmapview(long dax, long day, long zoome, short ang); +extern void clearview(long dacol); +extern void clearallviews(long dacol); +extern void plotpixel(long x, long y, char col); +extern unsigned char getpixel(long x, long y); +extern void setviewtotile(short tilenume, long xsiz, long ysiz); +extern void setviewback(void); +extern void squarerotatetile(short tilenume); +extern void preparemirror(long dax, long day, long daz, short daang, long dahoriz, short dawall, short dasector, long *tposx, long *tposy, short *tang); +extern void completemirror(void); +extern int sectorofwall(short theline); +extern int getceilzofslope(short sectnum, long dax, long day); +extern int getflorzofslope(short sectnum, long dax, long day); +extern void getzsofslope(short sectnum, long dax, long day, long *ceilz, long *florz); +extern void alignceilslope(short dasect, long x, long y, long z); +extern void alignflorslope(short dasect, long x, long y, long z); +extern int loopnumofsector(short sectnum, short wallnum); +extern void setfirstwall(short sectnum, short newfirstwall); diff --git a/buildengine/evilal.map b/buildengine/evilal.map new file mode 100755 index 0000000..88e9121 Binary files /dev/null and b/buildengine/evilal.map differ diff --git a/buildengine/game.c b/buildengine/game.c new file mode 100755 index 0000000..1302a2c --- /dev/null +++ b/buildengine/game.c @@ -0,0 +1,6422 @@ +/* + * "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman + * Ken Silverman's official web site: "http://www.advsys.net/ken" + * See the included license file "BUILDLIC.TXT" for license info. + * This file has been modified from Ken Silverman's original release + */ + +#include +#include +#include +#include +#include +#include + +#ifdef USE_PERL +#include "buildperl.h" +#endif + +#include "platform.h" + +#include "cache1d.h" +#include "pragmas.h" +#include "display.h" +#include "build.h" +#include "engine.h" +#include "names.h" + +#define TIMERINTSPERSECOND PLATFORM_TIMER_HZ +#define MOVESPERSECOND 40 +#define TICSPERFRAME 3 +#define MOVEFIFOSIZ 256 +#define EYEHEIGHT (32<<8) /* Normally (32<<8), (51<<8) to make mirrors happy */ + + +/* KenBuild-specific networking functions. */ +void initmultiplayers(char damultioption, char dacomrateoption, char dapriority); +void uninitmultiplayers(void); +void sendlogon(void); +void sendlogoff(void); +short getpacket(short *otherconnectindex, char *bufptr); +void sendpacket(short otherconnectindex, unsigned char *bufptr, short messleng); +int getoutputcirclesize(void); +void waitforeverybody(void); + + +/* + * Not interested in implementing these sound functions in a + * platform-independent manner for KenBuild. Anyone? --ryan. + */ +#if (defined PLATFORM_DOS) + +void initsb(char dadigistat, char damusistat, long dasamplerate, + char danumspeakers, char dabytespersample, + char daintspersec, char daquality); + +void uninitsb(void); +int loadsong(char *filename); +void musicon(void); +void musicoff(void); +void wsayfollow(char *dafilename, long dafreq, long davol, + long *daxplc, long *dayplc, char followstat); +void wsay(char *dafilename, long dafreq, long volume1, long volume2); +void preparesndbuf(void); +void setears(long daposx, long daposy, long daxvect, long dayvect); + +#else /* stubs for non-DOS platforms... */ + +#ifndef __FILE__ +#define __FILE__ "game.c" +#endif + +#ifndef __LINE__ +#define __LINE__ -1 +#endif + +static int audio_disabled = 0; + +void initsb(char dadigistat, char damusistat, long dasamplerate, + char danumspeakers, char dabytespersample, + char daintspersec, char daquality) +{ +#if 0 + audio_disabled = (SDL_Init(SDL_INIT_AUDIO) == -1); + + if (audio_disabled) + { + fprintf(stderr, "BUILDSDL: SDL_Init(SDL_INIT_AUDIO) failed!\n"); + fprintf(stderr, "BUILDSDL: SDL_GetError() says \"%s\".\n", SDL_GetError()); + fprintf(stderr, "BUILDSDL: We'll continue without sound.\n"); + audio_disabled = 1; + return; + } /* if */ +#else + audio_disabled = 1; + fprintf(stderr, "%s, line %d; initsb(): STUB.\n", __FILE__, __LINE__); +#endif +} /* initsb */ + + +void uninitsb(void) +{ + fprintf(stderr, "%s, line %d; uninitsb(): STUB.\n", __FILE__, __LINE__); +} /* uninitsb */ + + +int loadsong(char *filename) +{ + fprintf(stderr, "%s, line %d; loadsong(): STUB.\n", __FILE__, __LINE__); + return 0; +} /* loadsong */ + + +void musicon(void) +{ + fprintf(stderr, "%s, line %d; musicon(): STUB.\n", __FILE__, __LINE__); +} /* musicon */ + + +void musicoff(void) +{ + fprintf(stderr, "%s, line %d; musicoff(): STUB.\n", __FILE__, __LINE__); +} /* musicoff */ + + +void wsayfollow(char *dafilename, long dafreq, long davol, + long *daxplc, long *dayplc, char followstat) +{ + fprintf(stderr, "%s, line %d; wsayfollow(): STUB.\n", __FILE__, __LINE__); +} /* wsayfollow */ + + +void wsay(char *dafilename, long dafreq, long volume1, long volume2) +{ + fprintf(stderr, "%s, line %d; wsay(): STUB.\n", __FILE__, __LINE__); +} /* wsay */ + + +void preparesndbuf(void) +{ + fprintf(stderr,"%s, line %d; preparesndbuf(): STUB.\n", __FILE__, __LINE__); +} /* preparesndbuf */ + + +void setears(long daposx, long daposy, long daxvect, long dayvect) +{ +/* fprintf(stderr, "%s, line %d; setears(): STUB.\n", __FILE__, __LINE__); */ +} /* setears */ + +#endif /* !defined PLATFORM_DOS */ + + +/*************************************************************************** + KEN'S TAG DEFINITIONS: (Please define your own tags for your games) + + sector[?].lotag = 0 Normal sector + sector[?].lotag = 1 If you are on a sector with this tag, then all sectors + with same hi tag as this are operated. Once. + sector[?].lotag = 2 Same as sector[?].tag = 1 but this is retriggable. + sector[?].lotag = 3 A really stupid sector that really does nothing now. + sector[?].lotag = 4 A sector where you are put closer to the floor + (such as the slime in DOOM1.DAT) + sector[?].lotag = 5 A really stupid sector that really does nothing now. + sector[?].lotag = 6 A normal door - instead of pressing D, you tag the + sector with a 6. The reason I make you edit doors + this way is so that can program the doors + yourself. + sector[?].lotag = 7 A door the goes down to open. + sector[?].lotag = 8 A door that opens horizontally in the middle. + sector[?].lotag = 9 A sliding door that opens vertically in the middle. + -Example of the advantages of not using BSP tree. + sector[?].lotag = 10 A warping sector with floor and walls that shade. + sector[?].lotag = 11 A sector with all walls that do X-panning. + sector[?].lotag = 12 A sector with walls using the dragging function. + sector[?].lotag = 13 A sector with some swinging doors in it. + sector[?].lotag = 14 A revolving door sector. + sector[?].lotag = 15 A subway track. + sector[?].lotag = 16 A true double-sliding door. + + wall[?].lotag = 0 Normal wall + wall[?].lotag = 1 Y-panning wall + wall[?].lotag = 2 Switch - If you flip it, then all sectors with same hi + tag as this are operated. + wall[?].lotag = 3 Marked wall to detemine starting dir. (sector tag 12) + wall[?].lotag = 4 Mark on the shorter wall closest to the pivot point + of a swinging door. (sector tag 13) + wall[?].lotag = 5 Mark where a subway should stop. (sector tag 15) + wall[?].lotag = 6 Mark for true double-sliding doors (sector tag 16) + wall[?].lotag = 7 Water fountain + wall[?].lotag = 8 Bouncy wall! + + sprite[?].lotag = 0 Normal sprite + sprite[?].lotag = 1 If you press space bar on an AL, and the AL is tagged + with a 1, he will turn evil. + sprite[?].lotag = 2 When this sprite is operated, a bomb is shot at its + position. + sprite[?].lotag = 3 Rotating sprite. + sprite[?].lotag = 4 Sprite switch. + sprite[?].lotag = 5 Basketball hoop score. + +KEN'S STATUS DEFINITIONS: (Please define your own statuses for your games) + status = 0 Inactive sprite + status = 1 Active monster sprite + status = 2 Monster that becomes active only when it sees you + status = 3 Smoke on the wall for chainguns + status = 4 Splashing sprites (When you shoot slime) + status = 5 Explosion! + status = 6 Travelling bullet + status = 7 Bomb sprial-out explosion + status = 8 Player! + status = 9 EVILALGRAVE shrinking list + status = 10 EVILAL list + status = 11 Sprite respawning list + status = 12 Sprite which does not respawn (Andy's addition) + status = MAXSTATUS Non-existent sprite (this will be true for your + code also) +**************************************************************************/ + +typedef struct +{ + long x, y, z; +} point3d; + +typedef struct +{ + signed char fvel, svel, avel; + short bits; +} input; + +static long screentilt = 0; + +void __interrupt __far timerhandler(void); + +#define KEYFIFOSIZ 64 +void __interrupt __far keyhandler(void); +volatile char keystatus[256], keyfifo[KEYFIFOSIZ], keyfifoplc, keyfifoend; +volatile char readch, oldreadch, extended, keytemp; + +static long fvel, svel, avel; +static long fvel2, svel2, avel2; + +#define NUMOPTIONS 8 +#define NUMKEYS 19 +static long vesares[13][2] = { + {320,200},{360,200},{320,240},{360,240},{320,400}, + {360,400},{640,350},{640,400},{640,480},{800,600}, + {1024,768},{1280,1024},{1600,1200} +}; + +static char option[NUMOPTIONS] = {0,0,0,0,0,0,1,0}; +static char keys[NUMKEYS] = +{ + 0xc8,0xd0,0xcb,0xcd,0x2a,0x9d,0x1d,0x39, + 0x1e,0x2c,0xd1,0xc9,0x33,0x34, + 0x9c,0x1c,0xd,0xc,0xf, +}; + +static long digihz[7] = {6000,8000,11025,16000,22050,32000,44100}; + +static char frame2draw[MAXPLAYERS]; +static long frameskipcnt[MAXPLAYERS]; + +#define LAVASIZ 128 +#define LAVALOGSIZ 7 +#define LAVAMAXDROPS 32 +static char lavabakpic[(LAVASIZ+4)*(LAVASIZ+4)], lavainc[LAVASIZ]; +static long lavanumdrops, lavanumframes; +static long lavadropx[LAVAMAXDROPS], lavadropy[LAVAMAXDROPS]; +static long lavadropsiz[LAVAMAXDROPS], lavadropsizlookup[LAVAMAXDROPS]; +static long lavaradx[24][96], lavarady[24][96], lavaradcnt[32]; + + /* Shared player variables */ +static long posx[MAXPLAYERS], posy[MAXPLAYERS], posz[MAXPLAYERS]; +static long horiz[MAXPLAYERS], zoom[MAXPLAYERS], hvel[MAXPLAYERS]; +static short ang[MAXPLAYERS], cursectnum[MAXPLAYERS], ocursectnum[MAXPLAYERS]; +static short playersprite[MAXPLAYERS], deaths[MAXPLAYERS]; +static long lastchaingun[MAXPLAYERS]; +static long health[MAXPLAYERS], flytime[MAXPLAYERS]; +static short oflags[MAXPLAYERS]; +static short numbombs[MAXPLAYERS]; +static short numgrabbers[MAXPLAYERS]; /* Andy did this */ +static short nummissiles[MAXPLAYERS]; /* Andy did this */ +static char dimensionmode[MAXPLAYERS]; +static char revolvedoorstat[MAXPLAYERS]; +static short revolvedoorang[MAXPLAYERS], revolvedoorrotang[MAXPLAYERS]; +static long revolvedoorx[MAXPLAYERS], revolvedoory[MAXPLAYERS]; + + /* ENGINE CONTROLLED MULTIPLAYER VARIABLES: */ +extern short numplayers, myconnectindex; +extern short connecthead, connectpoint2[MAXPLAYERS]; /* Player linked list variables (indeces, not connection numbers) */ + +static long nummoves; + +/* + * Bug: NUMSTATS used to be equal to the greatest tag number, + * so that the last statrate[] entry was random memory junk + * because stats 0-NUMSTATS required NUMSTATS+1 bytes. -Andy + */ +#define NUMSTATS 13 +static signed char statrate[NUMSTATS] = {-1,0,-1,0,0,0,1,3,0,3,15,-1,-1}; + + /* Input structures */ +static char networkmode; /* 0 is 2(n-1) mode, 1 is n(n-1) mode */ +static long locselectedgun, locselectedgun2; +static input loc, oloc, loc2; +static input ffsync[MAXPLAYERS], osync[MAXPLAYERS], _sync[MAXPLAYERS]; + /* Input faketimerhandler -> movethings fifo */ +static long movefifoplc, movefifoend[MAXPLAYERS]; +static input baksync[MOVEFIFOSIZ][MAXPLAYERS]; + /* Game recording variables */ +static long reccnt, recstat = 1; +static input recsync[16384][2]; + +static signed char otherlag[MAXPLAYERS] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; +static long averagelag[MAXPLAYERS] = {512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512}; + +static long fakemovefifoplc; +static long myx, myy, myz, omyx, omyy, omyz, myzvel; +static long myhoriz, omyhoriz; +static short myang, omyang, mycursectnum; +static long myxbak[MOVEFIFOSIZ], myybak[MOVEFIFOSIZ], myzbak[MOVEFIFOSIZ]; +static long myhorizbak[MOVEFIFOSIZ]; +static short myangbak[MOVEFIFOSIZ]; + + /* MULTI.OBJ sync state variables */ +extern char syncstate; + /* GAME.C sync state variables */ +static char syncstat, syncval[MOVEFIFOSIZ], othersyncval[MOVEFIFOSIZ]; +static long syncvaltottail, syncvalhead, othersyncvalhead, syncvaltail; + +static char detailmode = 0, ready2send = 0; +static long ototalclock = 0, gotlastpacketclock = 0, smoothratio; +static long oposx[MAXPLAYERS], oposy[MAXPLAYERS], oposz[MAXPLAYERS]; +static long ohoriz[MAXPLAYERS], ozoom[MAXPLAYERS]; +static short oang[MAXPLAYERS]; + +static point3d osprite[MAXSPRITES]; + +#define MAXINTERPOLATIONS 1024 +static long numinterpolations = 0, startofdynamicinterpolations = 0; +static long oldipos[MAXINTERPOLATIONS]; +static long bakipos[MAXINTERPOLATIONS]; +static long *curipos[MAXINTERPOLATIONS]; + +extern long cachecount, transarea; + +static char playerreadyflag[MAXPLAYERS]; + + /* Miscellaneous variables */ +static char packbuf[MAXXDIM]; +static char tempbuf[MAXXDIM], boardfilename[80]; +static short tempshort[MAXSECTORS]; +static short screenpeek = 0, oldmousebstatus = 0, brightness = 0; +static short screensize, screensizeflag = 0; +static short neartagsector, neartagwall, neartagsprite; +static long lockclock, neartagdist, neartaghitdist; +extern long frameplace, pageoffset, ydim16; +static long globhiz, globloz, globhihit, globlohit; +/* volatile long stereomode = 0; */ +extern long stereowidth, stereopixelwidth; +extern volatile long activepage; + + /* Over the shoulder mode variables */ +static long cameradist = -1, cameraang = 0, cameraclock = 0; + + /* Board animation variables */ +#define MAXMIRRORS 64 +static short mirrorwall[MAXMIRRORS], mirrorsector[MAXMIRRORS], mirrorcnt; +static short floormirrorsector[64], floormirrorcnt; +static short turnspritelist[16], turnspritecnt; +static short warpsectorlist[64], warpsectorcnt; +static short xpanningsectorlist[16], xpanningsectorcnt; +static short ypanningwalllist[64], ypanningwallcnt; +static short floorpanninglist[64], floorpanningcnt; +static short dragsectorlist[16], dragxdir[16], dragydir[16], dragsectorcnt; +static long dragx1[16], dragy1[16], dragx2[16], dragy2[16], dragfloorz[16]; +static short swingcnt, swingwall[32][5], swingsector[32]; +static short swingangopen[32], swingangclosed[32], swingangopendir[32]; +static short swingang[32], swinganginc[32]; +static long swingx[32][8], swingy[32][8]; +static short revolvesector[4], revolveang[4], revolvecnt; +static long revolvex[4][16], revolvey[4][16]; +static long revolvepivotx[4], revolvepivoty[4]; +static short subwaytracksector[4][128], subwaynumsectors[4], subwaytrackcnt; +static long subwaystop[4][8], subwaystopcnt[4]; +static long subwaytrackx1[4], subwaytracky1[4]; +static long subwaytrackx2[4], subwaytracky2[4]; +static long subwayx[4], subwaygoalstop[4], subwayvel[4], subwaypausetime[4]; +static short waterfountainwall[MAXPLAYERS], waterfountaincnt[MAXPLAYERS]; +static short slimesoundcnt[MAXPLAYERS]; + + /* Variables that let you type messages to other player */ +static char getmessage[162], getmessageleng; +static long getmessagetimeoff; +static char typemessage[162], typemessageleng = 0, typemode = 0; +static char scantoasc[128] = +{ + 0,0,'1','2','3','4','5','6','7','8','9','0','-','=',0,0, + 'q','w','e','r','t','y','u','i','o','p','[',']',0,0,'a','s', + 'd','f','g','h','j','k','l',';',39,'`',0,92,'z','x','c','v', + 'b','n','m',',','.','/',0,'*',0,32,0,0,0,0,0,0, + 0,0,0,0,0,0,0,'7','8','9','-','4','5','6','+','1', + '2','3','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, +}; +static char scantoascwithshift[128] = +{ + 0,0,'!','@','#','$','%','^','&','*','(',')','_','+',0,0, + 'Q','W','E','R','T','Y','U','I','O','P','{','}',0,0,'A','S', + 'D','F','G','H','J','K','L',':',34,'~',0,'|','Z','X','C','V', + 'B','N','M','<','>','?',0,'*',0,32,0,0,0,0,0,0, + 0,0,0,0,0,0,0,'7','8','9','-','4','5','6','+','1', + '2','3','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, +}; + + /* + * These variables are for animating x, y, or z-coordinates of sectors, + * walls, or sprites (They are NOT to be used for changing the [].picnum's) + * See the setanimation(), and getanimategoal() functions for more details. + */ +#define MAXANIMATES 512 +static long *animateptr[MAXANIMATES], animategoal[MAXANIMATES]; +static long animatevel[MAXANIMATES], animateacc[MAXANIMATES], animatecnt = 0; + + /* These parameters are in exact order of sprite structure in BUILD.H */ +#define spawnsprite(newspriteindex2,x2,y2,z2,cstat2,shade2,pal2, \ + clipdist2,xrepeat2,yrepeat2,xoffset2,yoffset2,picnum2,ang2, \ + xvel2,yvel2,zvel2,owner2,sectnum2,statnum2,lotag2,hitag2,extra2) \ +{ \ + spritetype *spr2; \ + newspriteindex2 = insertsprite(sectnum2,statnum2); \ + spr2 = &sprite[newspriteindex2]; \ + spr2->x = x2; spr2->y = y2; spr2->z = z2; \ + spr2->cstat = cstat2; spr2->shade = shade2; \ + spr2->pal = pal2; spr2->clipdist = clipdist2; \ + spr2->xrepeat = xrepeat2; spr2->yrepeat = yrepeat2; \ + spr2->xoffset = xoffset2; spr2->yoffset = yoffset2; \ + spr2->picnum = picnum2; spr2->ang = ang2; \ + spr2->xvel = xvel2; spr2->yvel = yvel2; spr2->zvel = zvel2; \ + spr2->owner = owner2; \ + spr2->lotag = lotag2; spr2->hitag = hitag2; spr2->extra = extra2; \ + copybuf(&spr2->x,&osprite[newspriteindex2].x,3); \ + show2dsprite[newspriteindex2>>3] &= ~(1<<(newspriteindex2&7)); \ + if (show2dsector[sectnum2>>3]&(1<<(sectnum2&7))) \ + show2dsprite[newspriteindex2>>3] |= (1<<(newspriteindex2&7)); \ +} \ + + +void __interrupt __far timerhandler(void) +{ + totalclock++; + /* _chain_intr(oldtimerhandler); */ + + #ifdef PLATFORM_DOS + outp(0x20,0x20); + #endif +} + + +static void _initkeys(void) +{ + long i; + + keyfifoplc = 0; keyfifoend = 0; + for(i=0;i<256;i++) keystatus[i] = 0; + initkeys(); /* rcg06082001 platform driver-specific initialization. */ +} + + +void __interrupt __far keyhandler(void) +{ + /* + * ryan sez: End Of Interrupt call on DOS. This seems like a + * dangerous place to put it, if you ask me, but oh well. --ryan. + */ + #ifdef PLATFORM_DOS + koutp(0x20,0x20); + #endif + + oldreadch = readch; readch = _readlastkeyhit(); + + #if 0 + printf("keyhandler() got a (0x%X) ... \n", readch); + #endif + + /* + * ryan sez: these inp/outp calls read the keyboard state, + * reset the keyboard, and put the original state back in. + * This is apparently needed on some XTs, but not newer boxes, and + * obviously never on Linux. --ryan. + */ + #ifdef PLATFORM_DOS + keytemp = kinp(0x61); koutp(0x61,keytemp|128); koutp(0x61,keytemp&127); + #else + keytemp = readch; + #endif + + if ((readch|1) == 0xe1) { extended = 128; return; } + if (oldreadch != readch) + { + if ((readch&128) == 0) + { + keytemp = readch+extended; + if (!keystatus[(int) keytemp]) + { + keystatus[(int) keytemp] = 1; + keyfifo[(int) keyfifoend] = keytemp; + keyfifo[(int) (keyfifoend+1)&(KEYFIFOSIZ-1)] = 1; + keyfifoend = ((keyfifoend+2)&(KEYFIFOSIZ-1)); + } + } + else + { + keytemp = (readch&127)+extended; + keystatus[(int) keytemp] = 0; + keyfifo[(int) keyfifoend] = keytemp; + keyfifo[(int) (keyfifoend+1)&(KEYFIFOSIZ-1)] = 0; + keyfifoend = ((keyfifoend+2)&(KEYFIFOSIZ-1)); + } + } + extended = 0; +} + +void initlava(void) +{ + long x, y, z, r; + + for(z=0;z<32;z++) lavaradcnt[z] = 0; + for(x=-16;x<=16;x++) + for(y=-16;y<=16;y++) + { + r = ksqrt(x*x + y*y); + lavaradx[r][lavaradcnt[r]] = x; + lavarady[r][lavaradcnt[r]] = y; + lavaradcnt[r]++; + } + + for(z=0;z<16;z++) + lavadropsizlookup[z] = 8 / (ksqrt(z)+1); + + for(z=0;z>4)&7)-4)+12; + + lavanumdrops = 0; + lavanumframes = 0; +} + +#if (defined USE_I386_ASM) + #if (defined __WATCOMC__) + long addlava(int param); + #pragma aux addlava =\ + "mov al, byte ptr [ebx-133]",\ + "mov dl, byte ptr [ebx-1]",\ + "add al, byte ptr [ebx-132]",\ + "add dl, byte ptr [ebx+131]",\ + "add al, byte ptr [ebx-131]",\ + "add dl, byte ptr [ebx+132]",\ + "add al, byte ptr [ebx+1]",\ + "add al, dl",\ + parm [ebx]\ + modify exact [eax edx] + + #elif (defined __GNUC__) + static long addlava (int i1) + { + long retval; + __asm__ __volatile__ ( + "\n\t" + "movb -133(%%edi), %%al\n\t" + "movb -1(%%edi), %%dl\n\t" + "addb -132(%%edi), %%al\n\t" + "addb 131(%%edi), %%dl\n\t" + "addb -131(%%edi), %%al\n\t" + "addb 132(%%edi), %%dl\n\t" + "addb 1(%%edi), %%al\n\t" + "addb %%dl, %%al\n\t" + : "=a" (retval) : "D" (i1) : "edx", "cc", "memory"); + return (retval); + } /* addlava */ + + #elif (defined _MSC_VER) + long addlava(int param) + { + __asm + { + mov ebx, param + mov al, byte ptr [ebx-133] + mov dl, byte ptr [ebx-1] + add al, byte ptr [ebx-132] + add dl, byte ptr [ebx+131] + add al, byte ptr [ebx-131] + add dl, byte ptr [ebx+132] + add al, byte ptr [ebx+1] + add al, dl + mov param, eax + } /* asm */ + return(param); + } /* addlava */ + + #else + #error Please write Assembly code for your platform! + #endif + +#else /* USE_I386_ASM */ + long addlava(int param) + { + unsigned char al; + unsigned char *s = (unsigned char *)param; + unsigned char *t = (unsigned char *)(param-133); + + al = t[0] + t[132] + t[1] + s[131] + t[2] + s[132] + s[1]; + return((param&0xffffff00)|al); + } /* addlava */ +#endif + + +void movelava(char *dapic) +{ + long i, j, x, y, z, zz, dalavadropsiz, dadropsizlookup; + long dalavax, dalavay, *ptr, *ptr2; + + for(z=min(LAVAMAXDROPS-lavanumdrops-1,3);z>=0;z--) + { + lavadropx[lavanumdrops] = (rand()&(LAVASIZ-1)); + lavadropy[lavanumdrops] = (rand()&(LAVASIZ-1)); + lavadropsiz[lavanumdrops] = 1; + lavanumdrops++; + } + + for(z=lavanumdrops-1;z>=0;z--) + { + dadropsizlookup = lavadropsizlookup[lavadropsiz[z]]*(((z&1)<<1)-1); + dalavadropsiz = lavadropsiz[z]; + dalavax = lavadropx[z]; dalavay = lavadropy[z]; + for(zz=lavaradcnt[lavadropsiz[z]]-1;zz>=0;zz--) + { + i = (((lavaradx[dalavadropsiz][zz]+dalavax)&(LAVASIZ-1))< 10) + { + lavanumdrops--; + lavadropx[z] = lavadropx[lavanumdrops]; + lavadropy[z] = lavadropy[lavanumdrops]; + lavadropsiz[z] = lavadropsiz[lavanumdrops]; + } + } + + /* Back up dapic with 1 pixel extra on each boundary */ + /* (to prevent anding for wrap-around) */ + ptr = (long *)dapic; + ptr2 = (long *)((LAVASIZ+4)+1+((long)lavabakpic)); + for(x=0;x>2);y>0;y--) *ptr2++ = ((*ptr++)&0x1f1f1f1f); + ptr2++; + } + for(y=0;y>3)+ + ((addlava(y+1)&0xf8)<<5)+ + ((addlava(y+2)&0xf8)<<13)+ + ((addlava(y+3)&0xf8)<<21)+ + 0xc2c2c2c2; + } + } + + lavanumframes++; +} + + +void drawtilebackground (long thex, long they, short tilenum, + signed char shade, long cx1, long cy1, + long cx2, long cy2, char dapalnum) +{ + long x, y, xsiz, ysiz, tx1, ty1, tx2, ty2; + + xsiz = tilesizx[tilenum]; tx1 = cx1/xsiz; tx2 = cx2/xsiz; + ysiz = tilesizy[tilenum]; ty1 = cy1/ysiz; ty2 = cy2/ysiz; + + for(x=tx1;x<=tx2;x++) + for(y=ty1;y<=ty2;y++) + rotatesprite(x*xsiz<<16,y*ysiz<<16,65536L,0,tilenum,shade,dapalnum,8+16+64+128,cx1,cy1,cx2,cy2); +} + + +void printext(long x, long y, char *buffer, short tilenum, char invisiblecol) +{ + long i; + char ch; + + for(i=0;buffer[i]!=0;i++) + { + ch = buffer[i]; + rotatesprite((x-((8&15)<<3))<<16,(y-((8>>4)<<3))<<16,65536L,0,tilenum,0,0,8+16+64+128,x,y,x+7,y+7); + rotatesprite((x-((ch&15)<<3))<<16,(y-((ch>>4)<<3))<<16,65536L,0,tilenum,0,0,8+16+128,x,y,x+7,y+7); + x += 8; + } +} + + +static long ostatusflytime = 0x80000000; + +void drawstatusflytime(short snum) { /* Andy did this */ + long nstatusflytime; + + if ((snum == screenpeek) && (screensize <= xdim)) { + nstatusflytime = (((flytime[snum] + 119) - lockclock) / 120); + if (nstatusflytime > 1000) nstatusflytime = 1000; + else if (nstatusflytime < 0) nstatusflytime = 0; + if (nstatusflytime != ostatusflytime) { + if (nstatusflytime > 999) sprintf((char*)&tempbuf,"FT:BIG"); + else sprintf((char*)&tempbuf,"FT:%3ld",nstatusflytime); + printext((xdim - 56L),(ydim - 20L),tempbuf,ALPHABET,80); + ostatusflytime = nstatusflytime; + } + } +} + + +void drawstatusbar(short snum) { /* Andy did this */ + long nstatusflytime; + + if ((snum == screenpeek) && (screensize <= xdim)) { + sprintf((char*)&tempbuf,"Deaths:%d",deaths[snum]); + printext((xdim>>1)-(strlen(tempbuf)<<2),ydim-16,tempbuf,ALPHABET,80); + sprintf((char*)&tempbuf,"Health:%3ld",health[snum]); + printext((xdim>>1)-(strlen(tempbuf)<<2),ydim-24,tempbuf,ALPHABET,80); + + sprintf((char*)&tempbuf,"B:%3d",numbombs[snum]); + printext(8L,(ydim - 28L),tempbuf,ALPHABET,80); + sprintf((char*)&tempbuf,"M:%3d",nummissiles[snum]); + printext(8L,(ydim - 20L),tempbuf,ALPHABET,80); + sprintf((char*)&tempbuf,"G:%3d",numgrabbers[snum]); + printext(8L,(ydim - 12L),tempbuf,ALPHABET,80); + + nstatusflytime = (((flytime[snum] + 119) - lockclock) / 120); + if (nstatusflytime < 0) { + sprintf((char*)&tempbuf,"FT: 0"); + ostatusflytime = 0; + } + else if (nstatusflytime > 999) { + sprintf((char*)&tempbuf,"FT:BIG"); + ostatusflytime = 999; + } + else { + sprintf((char*)&tempbuf,"FT:%3ld",nstatusflytime); + ostatusflytime = nstatusflytime; + } + printext((xdim - 56L),(ydim - 20L),tempbuf,ALPHABET,80); + } +} + + +void setup3dscreen(void) +{ + long i, dax, day, dax2, day2; + + i = setgamemode(option[0],vesares[option[6]&15][0],vesares[option[6]&15][1]); + if (i < 0) + { + printf("VESA driver for (%ld * %ld) not found/supported.\n",xdim,ydim); + printf(" Press ENTER to play in NORMAL mode instead\n"); + printf(" Press ESC to quit to DOS\n"); + keystatus[1] = keystatus[0x1c] = keystatus[0x9c] = 0; + while (!keystatus[1]) + if (keystatus[0x1c]|keystatus[0x9c]) + { option[0] = vidoption = 2; i = setgamemode(option[0],vesares[option[6]&15][0],vesares[option[6]&15][1]); break; } + } + if (i < 0) + { + sendlogoff(); + musicoff(); + uninitmultiplayers(); + uninittimer(); + uninitkeys(); + uninitengine(); + uninitsb(); + uninitgroupfile(); + exit(0); + } + + /* Make that ugly pink into black in case it ever shows up! */ + i = 0L; + VBE_setPalette(255,1,(char *)&i); + /*outp(0x3c8,255); outp(0x3c9,0); outp(0x3c9,0); outp(0x3c9,0);*/ + + screensize = xdim; + if (screensize > xdim) + { + dax = 0; day = 0; + dax2 = xdim-1; day2 = ydim-1; + } + else + { + dax = ((xdim-screensize)>>1); + dax2 = dax+screensize-1; + day = (((ydim-32)-scale(screensize,ydim-32,xdim))>>1); + day2 = day + scale(screensize,ydim-32,xdim)-1; + setview(dax,day,dax2,day2); + } + + flushperms(); + + if (screensize < xdim) + drawtilebackground(0L,0L,BACKGROUND,8,0L,0L,xdim-1L,ydim-1L,0); /* Draw background */ + + if (screensize <= xdim) + { + rotatesprite((xdim-320)<<15,(ydim-32)<<16,65536L,0,STATUSBAR,0,0,8+16+64+128,0L,0L,xdim-1L,ydim-1L); + i = ((xdim-320)>>1); + while (i >= 8) i -= 8, rotatesprite(i<<16,(ydim-32)<<16,65536L,0,STATUSBARFILL8,0,0,8+16+64+128,0L,0L,xdim-1L,ydim-1L); + if (i >= 4) i -= 4, rotatesprite(i<<16,(ydim-32)<<16,65536L,0,STATUSBARFILL4,0,0,8+16+64+128,0L,0L,xdim-1L,ydim-1L); + i = ((xdim-320)>>1)+320; + while (i <= xdim-8) rotatesprite(i<<16,(ydim-32)<<16,65536L,0,STATUSBARFILL8,0,0,8+16+64+128,0L,0L,xdim-1L,ydim-1L), i += 8; + if (i <= xdim-4) rotatesprite(i<<16,(ydim-32)<<16,65536L,0,STATUSBARFILL4,0,0,8+16+64+128,0L,0L,xdim-1L,ydim-1L), i += 4; + + drawstatusbar(screenpeek); /* Andy did this */ + } +} + + +void setinterpolation(long *posptr) +{ + long i; + + if (numinterpolations >= MAXINTERPOLATIONS) return; + for(i=numinterpolations-1;i>=0;i--) + if (curipos[i] == posptr) return; + curipos[numinterpolations] = posptr; + oldipos[numinterpolations] = *posptr; + numinterpolations++; +} + + +void stopinterpolation(long *posptr) +{ + long i; + + for(i=numinterpolations-1;i>=startofdynamicinterpolations;i--) + if (curipos[i] == posptr) + { + numinterpolations--; + oldipos[i] = oldipos[numinterpolations]; + bakipos[i] = bakipos[numinterpolations]; + curipos[i] = curipos[numinterpolations]; + } +} + + +void updateinterpolations() /* Stick at beginning of domovethings */ +{ + long i; + + for(i=numinterpolations-1;i>=0;i--) oldipos[i] = *curipos[i]; +} + + +static void dointerpolations() /* Stick at beginning of drawscreen */ +{ + long i, j, odelta, ndelta; + + ndelta = 0; j = 0; + for(i=numinterpolations-1;i>=0;i--) + { + bakipos[i] = *curipos[i]; + odelta = ndelta; ndelta = (*curipos[i])-oldipos[i]; + if (odelta != ndelta) j = mulscale16(ndelta,smoothratio); + *curipos[i] = oldipos[i]+j; + } +} + + +void restoreinterpolations() /* Stick at end of drawscreen */ +{ + long i; + + for(i=numinterpolations-1;i>=0;i--) *curipos[i] = bakipos[i]; +} + + +void searchmap(short startsector) +{ + long i, j, dasect, splc, send, startwall, endwall; + short dapic; + walltype *wal; + + if ((startsector < 0) || (startsector >= numsectors)) return; + for(i=0;i<(MAXSECTORS>>3);i++) show2dsector[i] = 0; + for(i=0;i<(MAXWALLS>>3);i++) show2dwall[i] = 0; + for(i=0;i<(MAXSPRITES>>3);i++) show2dsprite[i] = 0; + + automapping = 0; + + /* Search your area recursively & set all show2dsector/show2dwalls */ + tempshort[0] = startsector; + show2dsector[startsector>>3] |= (1<<(startsector&7)); + dapic = sector[startsector].ceilingpicnum; + if (waloff[dapic] == 0) loadtile(dapic); + dapic = sector[startsector].floorpicnum; + if (waloff[dapic] == 0) loadtile(dapic); + for(splc=0,send=1;splc>3] |= (1<<(i&7)); + dapic = wall[i].picnum; + if (waloff[dapic] == 0) loadtile(dapic); + dapic = wall[i].overpicnum; + if (((dapic&0xfffff000) == 0) && (waloff[dapic] == 0)) loadtile(dapic); + + j = wal->nextsector; + if ((j >= 0) && ((show2dsector[j>>3]&(1<<(j&7))) == 0)) + { + show2dsector[j>>3] |= (1<<(j&7)); + + dapic = sector[j].ceilingpicnum; + if (waloff[dapic] == 0) loadtile(dapic); + dapic = sector[j].floorpicnum; + if (waloff[dapic] == 0) loadtile(dapic); + + tempshort[send++] = (short)j; + } + } + + for(i=headspritesect[dasect];i>=0;i=nextspritesect[i]) + { + show2dsprite[i>>3] |= (1<<(i&7)); + dapic = sprite[i].picnum; + if (waloff[dapic] == 0) loadtile(dapic); + } + } +} + + +void prepareboard(char *daboardfilename) +{ + short startwall, endwall, dasector; + /*long i, j, k, s, dax, day, daz, dax2, day2;*/ + long i, j, k=0, s, dax, day, dax2, day2; + + getmessageleng = 0; + typemessageleng = 0; + + randomseed = 17L; + + /* Clear (do)animation's list */ + animatecnt = 0; + typemode = 0; + locselectedgun = 0; + locselectedgun2 = 0; + + if (loadboard(daboardfilename,&posx[0],&posy[0],&posz[0],&ang[0],&cursectnum[0]) == -1) + { + musicoff(); + uninitmultiplayers(); + uninittimer(); + uninitkeys(); + uninitengine(); + uninitsb(); + uninitgroupfile(); + setvmode(0x3); /* Set back to text mode */ + printf("Board not found\n"); + exit(0); + } + + setup3dscreen(); + + for(i=0;i dax2) dax2 = wall[j].x; + if (wall[j].y > day2) day2 = wall[j].y; + if (wall[j].lotag == 3) k = j; + } + if (wall[k].x == dax) dragxdir[dragsectorcnt] = -16; + if (wall[k].y == day) dragydir[dragsectorcnt] = -16; + if (wall[k].x == dax2) dragxdir[dragsectorcnt] = 16; + if (wall[k].y == day2) dragydir[dragsectorcnt] = 16; + + dasector = wall[startwall].nextsector; + dragx1[dragsectorcnt] = 0x7fffffff; + dragy1[dragsectorcnt] = 0x7fffffff; + dragx2[dragsectorcnt] = 0x80000000; + dragy2[dragsectorcnt] = 0x80000000; + startwall = sector[dasector].wallptr; + endwall = startwall+sector[dasector].wallnum; + for(j=startwall;j dragx2[dragsectorcnt]) dragx2[dragsectorcnt] = wall[j].x; + if (wall[j].y > dragy2[dragsectorcnt]) dragy2[dragsectorcnt] = wall[j].y; + + setinterpolation(§or[dasector].floorz); + setinterpolation(&wall[j].x); + setinterpolation(&wall[j].y); + setinterpolation(&wall[wall[j].nextwall].x); + setinterpolation(&wall[wall[j].nextwall].y); + } + + dragx1[dragsectorcnt] += (wall[sector[i].wallptr].x-dax); + dragy1[dragsectorcnt] += (wall[sector[i].wallptr].y-day); + dragx2[dragsectorcnt] -= (dax2-wall[sector[i].wallptr].x); + dragy2[dragsectorcnt] -= (day2-wall[sector[i].wallptr].y); + + dragfloorz[dragsectorcnt] = sector[i].floorz; + + dragsectorlist[dragsectorcnt++] = i; + break; + case 13: + startwall = sector[i].wallptr; + endwall = startwall+sector[i].wallnum; + for(j=startwall;j dax2) dax2 = wall[j].x; + if (wall[j].y > day2) day2 = wall[j].y; + } + for(j=startwall;j dax) && (wall[j].y > day) && (wall[j].x < dax2) && (wall[j].y < day2)) + { + subwayx[subwaytrackcnt] = wall[j].x; + } + else + { + subwaystop[subwaytrackcnt][subwaystopcnt[subwaytrackcnt]] = wall[j].x; + subwaystopcnt[subwaytrackcnt]++; + } + } + } + + for(j=1;j subwaytrackx1[subwaytrackcnt]) + if (wall[startwall].y > subwaytracky1[subwaytrackcnt]) + if (wall[startwall].x < subwaytrackx2[subwaytrackcnt]) + if (wall[startwall].y < subwaytracky2[subwaytrackcnt]) + { + if (sector[j].floorz != sector[i].floorz) + { + sector[j].ceilingstat |= 64; + sector[j].floorstat |= 64; + } + subwaytracksector[subwaytrackcnt][subwaynumsectors[subwaytrackcnt]] = j; + subwaynumsectors[subwaytrackcnt]++; + } + } + + subwayvel[subwaytrackcnt] = 64; + subwaypausetime[subwaytrackcnt] = 720; + + startwall = sector[i].wallptr; + endwall = startwall+sector[i].wallnum; + for(k=startwall;k subwaytrackx1[subwaytrackcnt]) + if (wall[k].y > subwaytracky1[subwaytrackcnt]) + if (wall[k].x < subwaytrackx2[subwaytrackcnt]) + if (wall[k].y < subwaytracky2[subwaytrackcnt]) + setinterpolation(&wall[k].x); + + for(j=1;j=0;k=nextspritesect[k]) + if (statrate[sprite[k].statnum] < 0) + setinterpolation(&sprite[k].x); + } + + + subwaytrackcnt++; + break; + } + if (sector[i].floorpicnum == FLOORMIRROR) + floormirrorsector[mirrorcnt++] = i; + } + + /* Scan wall tags */ + + mirrorcnt = 0; + tilesizx[MIRROR] = 0; + tilesizy[MIRROR] = 0; + for(i=0;i= 0) && (wall[i].overpicnum == MIRROR) && (wall[i].cstat&32)) + { + if ((sector[s].floorstat&1) == 0) + { + wall[i].overpicnum = MIRRORLABEL+mirrorcnt; + sector[s].ceilingpicnum = MIRRORLABEL+mirrorcnt; + sector[s].floorpicnum = MIRRORLABEL+mirrorcnt; + sector[s].floorstat |= 1; + mirrorwall[mirrorcnt] = i; + mirrorsector[mirrorcnt] = s; + mirrorcnt++; + } + else + wall[i].overpicnum = sector[s].ceilingpicnum; + } + } + + /* Invalidate textures in sector behind mirror */ + for(i=0;i=0;i--) copybuf(&sprite[i].x,&osprite[i].x,3); + + searchmap(cursectnum[connecthead]); + + lockclock = 0; + ototalclock = 0; + gotlastpacketclock = 0; + + screensize = xdim; + dax = ((xdim-screensize)>>1); + dax2 = dax+screensize-1; + day = (((ydim-32)-scale(screensize,ydim-32,xdim))>>1); + day2 = day + scale(screensize,ydim-32,xdim)-1; + setview(dax,day,dax2,day2); + + startofdynamicinterpolations = numinterpolations; +} + + +long changehealth(short snum, short deltahealth) +{ + /*long dax, day;*/ + /*short good, k, startwall, endwall, s;*/ + + if (health[snum] > 0) + { + health[snum] += deltahealth; + if (health[snum] > 999) health[snum] = 999; + + if (health[snum] <= 0) + { + health[snum] = -1; + wsayfollow("death.wav",4096L+(krand()&127)-64,256L,&posx[snum],&posy[snum],1); + sprite[playersprite[snum]].picnum = SKELETON; + } + + if ((snum == screenpeek) && (screensize <= xdim)) + { + if (health[snum] > 0) + sprintf((char*)&tempbuf,"Health:%3ld",health[snum]); + else + sprintf((char*)&tempbuf,"YOU STINK!"); + + printext((xdim>>1)-(strlen(tempbuf)<<2),ydim-24,tempbuf,ALPHABET,80); + } + } + return(health[snum] <= 0); /* You were just injured */ +} + + +void changenumbombs(short snum, short deltanumbombs) { /* Andy did this */ + numbombs[snum] += deltanumbombs; + if (numbombs[snum] > 999) numbombs[snum] = 999; + if (numbombs[snum] <= 0) { + wsayfollow("doh.wav",4096L+(krand()&127)-64,256L,&posx[snum],&posy[snum],1); + numbombs[snum] = 0; + } + + if ((snum == screenpeek) && (screensize <= xdim)) { + sprintf((char*)&tempbuf,"B:%3d",numbombs[snum]); + printext(8L,(ydim - 28L),tempbuf,ALPHABET,80); + } +} + + +void changenummissiles(short snum, short deltanummissiles) { /* Andy did this */ + nummissiles[snum] += deltanummissiles; + if (nummissiles[snum] > 999) nummissiles[snum] = 999; + if (nummissiles[snum] <= 0) { + wsayfollow("doh.wav",4096L+(krand()&127)-64,256L,&posx[snum],&posy[snum],1); + nummissiles[snum] = 0; + } + + if ((snum == screenpeek) && (screensize <= xdim)) { + sprintf((char*)&tempbuf,"M:%3d",nummissiles[snum]); + printext(8L,(ydim - 20L),tempbuf,ALPHABET,80); + } +} + + +void changenumgrabbers(short snum, short deltanumgrabbers) { /* Andy did this */ + numgrabbers[snum] += deltanumgrabbers; + if (numgrabbers[snum] > 999) numgrabbers[snum] = 999; + if (numgrabbers[snum] <= 0) { + wsayfollow("doh.wav",4096L+(krand()&127)-64,256L,&posx[snum],&posy[snum],1); + numgrabbers[snum] = 0; + } + + if ((snum == screenpeek) && (screensize <= xdim)) { + sprintf((char*)&tempbuf,"G:%3d",numgrabbers[snum]); + printext(8L,(ydim - 12L),tempbuf,ALPHABET,80); + } +} + + +void findrandomspot(long *x, long *y, short *sectnum) +{ + short startwall, endwall, s, dasector; + long dax, day, daz, minx, maxx, miny, maxy, cnt; + + for(cnt=256;cnt>=0;cnt--) + { + do + { + dasector = mulscale16(krand(),numsectors); + } while ((sector[dasector].ceilingz+(8<<8) >= sector[dasector].floorz) || ((sector[dasector].lotag|sector[dasector].hitag) != 0) || ((sector[dasector].floorstat&1) != 0)); + + startwall = sector[dasector].wallptr; + endwall = startwall+sector[dasector].wallnum; + if (endwall <= startwall) continue; + + dax = 0L; + day = 0L; + minx = 0x7fffffff; maxx = 0x80000000; + miny = 0x7fffffff; maxy = 0x80000000; + + for(s=startwall;s maxx) maxx = wall[s].x; + if (wall[s].y < miny) miny = wall[s].y; + if (wall[s].y > maxy) maxy = wall[s].y; + } + + if ((maxx-minx <= 256) || (maxy-miny <= 256)) continue; + + dax /= (endwall-startwall); + day /= (endwall-startwall); + + if (inside(dax,day,dasector) == 0) continue; + + daz = sector[dasector].floorz-(32<<8); + if (pushmove(&dax,&day,&daz,&dasector,128L,4<<8,4<<8,CLIPMASK0) < 0) continue; + + *x = dax; *y = day; *sectnum = dasector; + return; + } +} + + +static long getanimationgoal(long animptr) +{ + long i; + + for(i=animatecnt-1;i>=0;i--) + if ((long *)animptr == animateptr[i]) return(i); + return(-1); +} + + +static long setanimation(long *animptr, long thegoal, long thevel, long theacc) +{ + long i, j; + + if (animatecnt >= MAXANIMATES) return(-1); + + j = animatecnt; + for(i=animatecnt-1;i>=0;i--) + if (animptr == animateptr[i]) + { j = i; break; } + + setinterpolation(animptr); + + animateptr[j] = animptr; + animategoal[j] = thegoal; + animatevel[j] = thevel; + animateacc[j] = theacc; + if (j == animatecnt) animatecnt++; + return(j); +} + + +void operatesector(short dasector) +{ /* Door code */ + long i, j, datag; + long daz, dax2, day2, centx, centy; + short startwall, endwall, wallfind[2]; + + datag = sector[dasector].lotag; + + startwall = sector[dasector].wallptr; + endwall = startwall + sector[dasector].wallnum; + centx = 0L, centy = 0L; + for(i=startwall;i= 0) /* If door already moving, reverse its direction */ + { + if (datag == 8) + daz = ((sector[dasector].ceilingz+sector[dasector].floorz)>>1); + else + daz = sector[dasector].floorz; + + if (animategoal[i] == daz) + animategoal[i] = sector[nextsectorneighborz(dasector,sector[dasector].floorz,-1,-1)].ceilingz; + else + animategoal[i] = daz; + animatevel[i] = 0; + } + else /* else insert the door's ceiling on the animation list */ + { + if (sector[dasector].ceilingz == sector[dasector].floorz) + daz = sector[nextsectorneighborz(dasector,sector[dasector].floorz,-1,-1)].ceilingz; + else + { + if (datag == 8) + daz = ((sector[dasector].ceilingz+sector[dasector].floorz)>>1); + else + daz = sector[dasector].floorz; + } + if ((j = setanimation(§or[dasector].ceilingz,daz,6L,6L)) >= 0) + wsayfollow("updowndr.wav",4096L+(krand()&255)-128,256L,¢x,¢y,0); + } + } + /* Simple door that moves down */ + if ((datag == 7) || (datag == 8)) /* If the sector in front's elevator */ + { + i = getanimationgoal((long)§or[dasector].floorz); + if (i >= 0) /* If elevator already moving, reverse its direction */ + { + if (datag == 8) + daz = ((sector[dasector].ceilingz+sector[dasector].floorz)>>1); + else + daz = sector[dasector].ceilingz; + + if (animategoal[i] == daz) + animategoal[i] = sector[nextsectorneighborz(dasector,sector[dasector].ceilingz,1,1)].floorz; + else + animategoal[i] = daz; + animatevel[i] = 0; + } + else /* else insert the elevator's ceiling on the animation list */ + { + if (sector[dasector].floorz == sector[dasector].ceilingz) + daz = sector[nextsectorneighborz(dasector,sector[dasector].ceilingz,1,1)].floorz; + else + { + if (datag == 8) + daz = ((sector[dasector].ceilingz+sector[dasector].floorz)>>1); + else + daz = sector[dasector].ceilingz; + } + if ((j = setanimation(§or[dasector].floorz,daz,6L,6L)) >= 0) + wsayfollow("updowndr.wav",4096L+(krand()&255)-128,256L,¢x,¢y,0); + } + } + + if (datag == 9) /* Smooshy-wall sideways double-door */ + { + /* + * find any points with either same x or same y coordinate + * as center (centx, centy) - should be 2 points found. + */ + wallfind[0] = -1; + wallfind[1] = -1; + for(i=startwall;i>1)-wall[wallfind[j]].x; + day2 = ((wall[i].y+wall[wall[wallfind[j]].point2].y)>>1)-wall[wallfind[j]].y; + if (dax2 != 0) + { + dax2 = wall[wall[wall[wallfind[j]].point2].point2].x; + dax2 -= wall[wall[wallfind[j]].point2].x; + setanimation(&wall[wallfind[j]].x,wall[wallfind[j]].x+dax2,4L,0L); + setanimation(&wall[i].x,wall[i].x+dax2,4L,0L); + setanimation(&wall[wall[wallfind[j]].point2].x,wall[wall[wallfind[j]].point2].x+dax2,4L,0L); + } + else if (day2 != 0) + { + day2 = wall[wall[wall[wallfind[j]].point2].point2].y; + day2 -= wall[wall[wallfind[j]].point2].y; + setanimation(&wall[wallfind[j]].y,wall[wallfind[j]].y+day2,4L,0L); + setanimation(&wall[i].y,wall[i].y+day2,4L,0L); + setanimation(&wall[wall[wallfind[j]].point2].y,wall[wall[wallfind[j]].point2].y+day2,4L,0L); + } + } + else + { + i = wallfind[j]-1; if (i < startwall) i = endwall-1; + dax2 = ((wall[i].x+wall[wall[wallfind[j]].point2].x)>>1)-wall[wallfind[j]].x; + day2 = ((wall[i].y+wall[wall[wallfind[j]].point2].y)>>1)-wall[wallfind[j]].y; + if (dax2 != 0) + { + setanimation(&wall[wallfind[j]].x,centx,4L,0L); + setanimation(&wall[i].x,centx+dax2,4L,0L); + setanimation(&wall[wall[wallfind[j]].point2].x,centx+dax2,4L,0L); + } + else if (day2 != 0) + { + setanimation(&wall[wallfind[j]].y,centy,4L,0L); + setanimation(&wall[i].y,centy+day2,4L,0L); + setanimation(&wall[wall[wallfind[j]].point2].y,centy+day2,4L,0L); + } + } + } + wsayfollow("updowndr.wav",4096L-256L,256L,¢x,¢y,0); + wsayfollow("updowndr.wav",4096L+256L,256L,¢x,¢y,0); + } + + if (datag == 13) /* Swinging door */ + { + for(i=0;i>1) == centx) && (((wall[wallfind[j]].y+wall[wall[wallfind[j]].point2].y)>>1) == centy)) + { /* door was closed */ + /* find what direction door should open */ + i = wallfind[j]-1; if (i < startwall) i = endwall-1; + dax2 = wall[i].x-wall[wallfind[j]].x; + day2 = wall[i].y-wall[wallfind[j]].y; + if (dax2 != 0) + { + dax2 = wall[wall[wall[wall[wallfind[j]].point2].point2].point2].x; + dax2 -= wall[wall[wall[wallfind[j]].point2].point2].x; + setanimation(&wall[wallfind[j]].x,wall[wallfind[j]].x+dax2,4L,0L); + setanimation(&wall[i].x,wall[i].x+dax2,4L,0L); + setanimation(&wall[wall[wallfind[j]].point2].x,wall[wall[wallfind[j]].point2].x+dax2,4L,0L); + setanimation(&wall[wall[wall[wallfind[j]].point2].point2].x,wall[wall[wall[wallfind[j]].point2].point2].x+dax2,4L,0L); + } + else if (day2 != 0) + { + day2 = wall[wall[wall[wall[wallfind[j]].point2].point2].point2].y; + day2 -= wall[wall[wall[wallfind[j]].point2].point2].y; + setanimation(&wall[wallfind[j]].y,wall[wallfind[j]].y+day2,4L,0L); + setanimation(&wall[i].y,wall[i].y+day2,4L,0L); + setanimation(&wall[wall[wallfind[j]].point2].y,wall[wall[wallfind[j]].point2].y+day2,4L,0L); + setanimation(&wall[wall[wall[wallfind[j]].point2].point2].y,wall[wall[wall[wallfind[j]].point2].point2].y+day2,4L,0L); + } + } + else + { /* door was not closed */ + i = wallfind[j]-1; if (i < startwall) i = endwall-1; + dax2 = wall[i].x-wall[wallfind[j]].x; + day2 = wall[i].y-wall[wallfind[j]].y; + if (dax2 != 0) + { + setanimation(&wall[wallfind[j]].x,centx,4L,0L); + setanimation(&wall[i].x,centx+dax2,4L,0L); + setanimation(&wall[wall[wallfind[j]].point2].x,centx,4L,0L); + setanimation(&wall[wall[wall[wallfind[j]].point2].point2].x,centx+dax2,4L,0L); + } + else if (day2 != 0) + { + setanimation(&wall[wallfind[j]].y,centy,4L,0L); + setanimation(&wall[i].y,centy+day2,4L,0L); + setanimation(&wall[wall[wallfind[j]].point2].y,centy,4L,0L); + setanimation(&wall[wall[wall[wallfind[j]].point2].point2].y,centy+day2,4L,0L); + } + } + } + wsayfollow("updowndr.wav",4096L-64L,256L,¢x,¢y,0); + wsayfollow("updowndr.wav",4096L+64L,256L,¢x,¢y,0); + } +} + + + /* + * New movesprite using getzrange. Note that I made the getzrange + * parameters global (&globhiz,&globhihit,&globloz,&globlohit) so they + * don't need to be passed everywhere. Also this should make this + * movesprite function compatible with the older movesprite functions. + */ +static short movesprite(short spritenum, long dx, long dy, long dz, long ceildist, long flordist, long clipmask) +{ + long daz, zoffs; + short retval, dasectnum, datempshort; + spritetype *spr; + + spr = &sprite[spritenum]; + + if ((spr->cstat&128) == 0) + zoffs = -((tilesizy[spr->picnum]*spr->yrepeat)<<1); + else + zoffs = 0; + + dasectnum = spr->sectnum; /* Can't modify sprite sectors directly becuase of linked lists */ + daz = spr->z+zoffs; /* Must do this if not using the new centered centering (of course) */ + retval = clipmove(&spr->x,&spr->y,&daz,&dasectnum,dx,dy, + ((long)spr->clipdist)<<2,ceildist,flordist,clipmask); + + if (dasectnum < 0) retval = -1; + + if ((dasectnum != spr->sectnum) && (dasectnum >= 0)) + changespritesect(spritenum,dasectnum); + + /* + * Set the blocking bit to 0 temporarly so getzrange doesn't pick up + * its own sprite + */ + datempshort = spr->cstat; spr->cstat &= ~1; + getzrange(spr->x,spr->y,spr->z-1,spr->sectnum, + &globhiz,&globhihit,&globloz,&globlohit, + ((long)spr->clipdist)<<2,clipmask); + spr->cstat = datempshort; + + daz = spr->z+zoffs + dz; + if ((daz <= globhiz) || (daz > globloz)) + { + if (retval != 0) return(retval); + return(16384+dasectnum); + } + spr->z = daz-zoffs; + return(retval); +} + + +void shootgun(short snum, long x, long y, long z, + short daang, long dahoriz, short dasectnum, char guntype) +{ + short hitsect, hitwall, hitsprite, daang2; + long j, daz2, hitx, hity, hitz; + + switch(guntype) + { + case 0: /* Shoot chain gun */ + daang2 = ((daang + (krand()&31)-16)&2047); + daz2 = ((100-dahoriz)*2000) + ((krand()-32768)>>1); + + hitscan(x,y,z,dasectnum, /* Start position */ + sintable[(daang2+512)&2047], /* X vector of 3D ang */ + sintable[daang2&2047], /* Y vector of 3D ang */ + daz2, /* Z vector of 3D ang */ + &hitsect,&hitwall,&hitsprite,&hitx,&hity,&hitz,CLIPMASK1); + + if (wall[hitwall].picnum == KENPICTURE) + { + if (waloff[MAXTILES-1] != 0) wall[hitwall].picnum = MAXTILES-1; + wsayfollow("hello.wav",4096L+(krand()&127)-64,256L,&wall[hitwall].x,&wall[hitwall].y,0); + } + else if (((hitwall < 0) && (hitsprite < 0) && (hitz >= z) && ((sector[hitsect].floorpicnum == SLIME) || (sector[hitsect].floorpicnum == FLOORMIRROR))) || ((hitwall >= 0) && (wall[hitwall].picnum == SLIME))) + { /* If you shoot slime, make a splash */ + wsayfollow("splash.wav",4096L+(krand()&511)-256,256L,&hitx,&hity,0); + spawnsprite(j,hitx,hity,hitz,2,0,0,32,64,64,0,0,SPLASH,daang, + 0,0,0,snum+4096,hitsect,4,63,0,0); /* 63=time left for splash */ + } + else + { + wsayfollow("shoot.wav",4096L+(krand()&127)-64,256L,&hitx,&hity,0); + + if ((hitsprite >= 0) && (sprite[hitsprite].statnum < MAXSTATUS)) + switch(sprite[hitsprite].picnum) + { + case BROWNMONSTER: + if (sprite[hitsprite].lotag > 0) sprite[hitsprite].lotag -= 10; + if (sprite[hitsprite].lotag > 0) + { + wsayfollow("hurt.wav",4096L+(krand()&511)-256,256L,&hitx,&hity,0); + if (sprite[hitsprite].lotag <= 25) + sprite[hitsprite].cstat |= 2; + } + else + { + wsayfollow("mondie.wav",4096L+(krand()&127)-64,256L,&hitx,&hity,0); + sprite[hitsprite].z += ((tilesizy[sprite[hitsprite].picnum]*sprite[hitsprite].yrepeat)<<1); + sprite[hitsprite].picnum = GIFTBOX; + sprite[hitsprite].cstat &= ~0x83; /* Should not clip, foot-z */ + changespritestat(hitsprite,12); + + spawnsprite(j,hitx,hity,hitz+(32<<8),0,-4,0,32,64,64, + 0,0,EXPLOSION,daang,0,0,0,snum+4096, + hitsect,5,31,0,0); + } + break; + case EVILAL: + wsayfollow("blowup.wav",4096L+(krand()&127)-64,256L,&hitx,&hity,0); + sprite[hitsprite].picnum = EVILALGRAVE; + sprite[hitsprite].cstat = 0; + sprite[hitsprite].xvel = (krand()&255)-128; + sprite[hitsprite].yvel = (krand()&255)-128; + sprite[hitsprite].zvel = (krand()&4095)-3072; + changespritestat(hitsprite,9); + + spawnsprite(j,hitx,hity,hitz+(32<<8),0,-4,0,32,64,64,0, + 0,EXPLOSION,daang,0,0,0,snum+4096,hitsect,5,31,0,0); + /* 31=time left for explosion */ + + break; + case PLAYER: + for(j=connecthead;j>=0;j=connectpoint2[j]) + if (playersprite[j] == hitsprite) + { + wsayfollow("ouch.wav",4096L+(krand()&127)-64,256L,&hitx,&hity,0); + changehealth((short) j,-10); + break; + } + break; + } + + spawnsprite(j,hitx,hity,hitz+(8<<8),2,-4,0,32,16,16,0,0, + EXPLOSION,daang,0,0,0,snum+4096,hitsect,3,63,0,0); + + /* + * Sprite starts out with center exactly on wall. + * This moves it back enough to see it at all angles. + */ + movesprite((short)j,-(((long)sintable[(512+daang)&2047]*TICSPERFRAME)<<4),-(((long)sintable[daang]*TICSPERFRAME)<<4),0L,4L<<8,4L<<8,CLIPMASK1); + } + break; + case 1: /* Shoot silver sphere bullet */ + spawnsprite(j,x,y,z,1+128,0,0,16,64,64,0,0,BULLET,daang, + sintable[(daang+512)&2047]>>5,sintable[daang&2047]>>5, + (100-dahoriz)<<6,snum+4096,dasectnum,6,0,0,0); + wsayfollow("shoot2.wav",4096L+(krand()&127)-64,128L,&sprite[j].x,&sprite[j].y,1); + break; + case 2: /* Shoot bomb */ + spawnsprite(j,x,y,z,128,0,0,12,16,16,0,0,BOMB,daang, + sintable[(daang+512)&2047]*5>>8,sintable[daang&2047]*5>>8, + (80-dahoriz)<<6,snum+4096,dasectnum,6,0,0,0); + wsayfollow("shoot3.wav",4096L+(krand()&127)-64,192L,&sprite[j].x,&sprite[j].y,1); + break; + case 3: /* Shoot missile (Andy did this) */ + spawnsprite(j,x,y,z,1+128,0,0,16,32,32,0,0,MISSILE,daang, + sintable[(daang+512)&2047]>>4,sintable[daang&2047]>>4, + (100-dahoriz)<<7,snum+4096,dasectnum,6,0,0,0); + wsayfollow("shoot3.wav",4096L+(krand()&127)-64,192L,&sprite[j].x,&sprite[j].y,1); + break; + case 4: /* Shoot grabber (Andy did this) */ + spawnsprite(j,x,y,z,1+128,0,0,16,64,64,0,0,GRABBER,daang, + sintable[(daang+512)&2047]>>5,sintable[daang&2047]>>5, + (100-dahoriz)<<6,snum+4096,dasectnum,6,0,0,0); + wsayfollow("shoot4.wav",4096L+(krand()&127)-64,128L,&sprite[j].x,&sprite[j].y,1); + break; + } +} + + +void operatesprite(short dasprite) +{ + long datag; + + datag = sprite[dasprite].lotag; + + if (datag == 2) /* A sprite that shoots a bomb */ + { + shootgun(dasprite, + sprite[dasprite].x,sprite[dasprite].y,sprite[dasprite].z, + sprite[dasprite].ang,100L,sprite[dasprite].sectnum,2); + } +} + + +void checktouchsprite(short snum, short sectnum) +{ + long i, nexti; + + if ((sectnum < 0) || (sectnum >= numsectors)) return; + + for(i=headspritesect[sectnum];i>=0;i=nexti) + { + nexti = nextspritesect[i]; + if (sprite[i].cstat&0x8000) continue; + if ((klabs(posx[snum]-sprite[i].x)+klabs(posy[snum]-sprite[i].y) < 512) && (klabs((posz[snum]>>8)-((sprite[i].z>>8)-(tilesizy[sprite[i].picnum]>>1))) <= 40)) + { + switch(sprite[i].picnum) + { + case COIN: + wsayfollow("getstuff.wav",4096L+(krand()&127)-64,192L,&sprite[i].x,&sprite[i].y,0); + changehealth(snum,5); + if (sprite[i].statnum == 12) deletesprite((short)i); + else { + sprite[i].cstat |= 0x8000; + sprite[i].extra = 120*60; + changespritestat((short)i,11); + } + break; + case DIAMONDS: + wsayfollow("getstuff.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); + changehealth(snum,15); + if (sprite[i].statnum == 12) deletesprite((short)i); + else { + sprite[i].cstat |= 0x8000; + sprite[i].extra = 120*120; + changespritestat((short)i,11); + } + break; + case COINSTACK: + wsayfollow("getstuff.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); + changehealth(snum,25); + if (sprite[i].statnum == 12) deletesprite((short)i); + else { + sprite[i].cstat |= 0x8000; + sprite[i].extra = 120*180; + changespritestat((short)i,11); + } + break; + case GIFTBOX: + wsayfollow("getstuff.wav",4096L+(krand()&127)+256-mulscale4(sprite[i].xrepeat,sprite[i].yrepeat),208L,&sprite[i].x,&sprite[i].y,0); + changehealth(snum,(short) max(mulscale8(sprite[i].xrepeat,sprite[i].yrepeat),1)); + if (sprite[i].statnum == 12) deletesprite((short)i); + else { + sprite[i].cstat |= 0x8000; + sprite[i].extra = 90*(sprite[i].xrepeat+sprite[i].yrepeat); + changespritestat((short)i,11); + } + break; + case CANNON: + wsayfollow("getstuff.wav",3584L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); + if (snum == myconnectindex) keystatus[4] = 1; + changenumbombs(snum,(short) ((sprite[i].xrepeat+sprite[i].yrepeat)>>1)); + if (sprite[i].statnum == 12) deletesprite((short)i); + else { + sprite[i].cstat |= 0x8000; + sprite[i].extra = 60*(sprite[i].xrepeat+sprite[i].yrepeat); + changespritestat((short)i,11); + } + break; + case LAUNCHER: + wsayfollow("getstuff.wav",3584L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); + if (snum == myconnectindex) keystatus[5] = 1; + changenummissiles(snum,(short) ((sprite[i].xrepeat+sprite[i].yrepeat)>>1)); + if (sprite[i].statnum == 12) deletesprite((short)i); + else { + sprite[i].cstat |= 0x8000; + sprite[i].extra = 90*(sprite[i].xrepeat+sprite[i].yrepeat); + changespritestat((short)i,11); + } + break; + case GRABCANNON: + wsayfollow("getstuff.wav",3584L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); + if (snum == myconnectindex) keystatus[6] = 1; + changenumgrabbers(snum,((sprite[i].xrepeat+sprite[i].yrepeat)>>1)); + if (sprite[i].statnum == 12) deletesprite((short)i); + else { + sprite[i].cstat |= 0x8000; + sprite[i].extra = 120*(sprite[i].xrepeat+sprite[i].yrepeat); + changespritestat((short)i,11); + } + break; + case AIRPLANE: + wsayfollow("getstuff.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); + if (flytime[snum] < lockclock) flytime[snum] = lockclock; + flytime[snum] += 60*(sprite[i].xrepeat+sprite[i].yrepeat); + drawstatusflytime(snum); + if (sprite[i].statnum == 12) deletesprite((short)i); + else { + sprite[i].cstat |= 0x8000; + sprite[i].extra = 120*(sprite[i].xrepeat+sprite[i].yrepeat); + changespritestat((short)i,11); + } + break; + } + } + } +} + + +void checkgrabbertouchsprite(short snum, short sectnum) /* Andy did this */ +{ + long i, nexti; + short onum; + + if ((sectnum < 0) || (sectnum >= numsectors)) return; + onum = (sprite[snum].owner & (MAXSPRITES - 1)); + + for(i=headspritesect[sectnum];i>=0;i=nexti) + { + nexti = nextspritesect[i]; + if (sprite[i].cstat&0x8000) continue; + if ((klabs(sprite[snum].x-sprite[i].x)+klabs(sprite[snum].y-sprite[i].y) < 512) && (klabs((sprite[snum].z>>8)-((sprite[i].z>>8)-(tilesizy[sprite[i].picnum]>>1))) <= 40)) + { + switch(sprite[i].picnum) + { + case COIN: + wsayfollow("getstuff.wav",4096L+(krand()&127)-64,192L,&sprite[i].x,&sprite[i].y,0); + changehealth(onum,5); + if (sprite[i].statnum == 12) deletesprite((short)i); + else { + sprite[i].cstat |= 0x8000; + sprite[i].extra = 120*60; + changespritestat((short)i,11); + } + break; + case DIAMONDS: + wsayfollow("getstuff.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); + changehealth(onum,15); + if (sprite[i].statnum == 12) deletesprite((short)i); + else { + sprite[i].cstat |= 0x8000; + sprite[i].extra = 120*120; + changespritestat((short)i,11); + } + break; + case COINSTACK: + wsayfollow("getstuff.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); + changehealth(onum,25); + if (sprite[i].statnum == 12) deletesprite((short)i); + else { + sprite[i].cstat |= 0x8000; + sprite[i].extra = 120*180; + changespritestat((short)i,11); + } + break; + case GIFTBOX: + wsayfollow("getstuff.wav",4096L+(krand()&127)+256-mulscale4(sprite[i].xrepeat,sprite[i].yrepeat),208L,&sprite[i].x,&sprite[i].y,0); + changehealth(onum,max(mulscale8(sprite[i].xrepeat,sprite[i].yrepeat),1)); + if (sprite[i].statnum == 12) deletesprite((short)i); + else { + sprite[i].cstat |= 0x8000; + sprite[i].extra = 90*(sprite[i].xrepeat+sprite[i].yrepeat); + changespritestat((short)i,11); + } + break; + case CANNON: + wsayfollow("getstuff.wav",3584L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); + if (onum == myconnectindex) keystatus[4] = 1; + changenumbombs(onum,((sprite[i].xrepeat+sprite[i].yrepeat)>>1)); + if (sprite[i].statnum == 12) deletesprite((short)i); + else { + sprite[i].cstat |= 0x8000; + sprite[i].extra = 60*(sprite[i].xrepeat+sprite[i].yrepeat); + changespritestat((short)i,11); + } + break; + case LAUNCHER: + wsayfollow("getstuff.wav",3584L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); + if (onum == myconnectindex) keystatus[5] = 1; + changenummissiles(onum,((sprite[i].xrepeat+sprite[i].yrepeat)>>1)); + if (sprite[i].statnum == 12) deletesprite((short)i); + else { + sprite[i].cstat |= 0x8000; + sprite[i].extra = 90*(sprite[i].xrepeat+sprite[i].yrepeat); + changespritestat((short)i,11); + } + break; + case GRABCANNON: + wsayfollow("getstuff.wav",3584L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); + if (onum == myconnectindex) keystatus[6] = 1; + changenumgrabbers(onum,((sprite[i].xrepeat+sprite[i].yrepeat)>>1)); + if (sprite[i].statnum == 12) deletesprite((short)i); + else { + sprite[i].cstat |= 0x8000; + sprite[i].extra = 120*(sprite[i].xrepeat+sprite[i].yrepeat); + changespritestat((short)i,11); + } + break; + case AIRPLANE: + wsayfollow("getstuff.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); + if (flytime[snum] < lockclock) flytime[snum] = lockclock; + flytime[onum] += 60*(sprite[i].xrepeat+sprite[i].yrepeat); + drawstatusflytime(onum); + if (sprite[i].statnum == 12) deletesprite((short)i); + else { + sprite[i].cstat |= 0x8000; + sprite[i].extra = 120*(sprite[i].xrepeat+sprite[i].yrepeat); + changespritestat((short)i,11); + } + break; + } + } + } +} + + +void activatehitag(short dahitag) +{ + long i, nexti; + + for(i=0;i=0;i=nexti) + { + nexti = nextspritestat[i]; + if (sprite[i].hitag == dahitag) operatesprite(i); + } +} + + +void processinput(short snum) +{ + long i, j, k, doubvel, xvect, yvect, goalz; + long dax, day; + + /* SHARED KEYS: */ + /* Movement code */ + if ((_sync[snum].fvel|_sync[snum].svel) != 0) + { + doubvel = (TICSPERFRAME<<((_sync[snum].bits&256)>0)); + + xvect = 0, yvect = 0; + if (_sync[snum].fvel != 0) + { + xvect += ((((long)_sync[snum].fvel)*doubvel*(long)sintable[(ang[snum]+512)&2047])>>3); + yvect += ((((long)_sync[snum].fvel)*doubvel*(long)sintable[ang[snum]&2047])>>3); + } + if (_sync[snum].svel != 0) + { + xvect += ((((long)_sync[snum].svel)*doubvel*(long)sintable[ang[snum]&2047])>>3); + yvect += ((((long)_sync[snum].svel)*doubvel*(long)sintable[(ang[snum]+1536)&2047])>>3); + } + if (flytime[snum] > lockclock) { xvect += xvect; yvect += yvect; } /* DOuble flying speed */ + clipmove(&posx[snum],&posy[snum],&posz[snum],&cursectnum[snum],xvect,yvect,128L,4<<8,4<<8,CLIPMASK0); + revolvedoorstat[snum] = 1; + } + else + { + revolvedoorstat[snum] = 0; + } + + sprite[playersprite[snum]].cstat &= ~1; + /* Push player away from walls if clipmove doesn't work */ + if (pushmove(&posx[snum],&posy[snum],&posz[snum],&cursectnum[snum],128L,4<<8,4<<8,CLIPMASK0) < 0) + changehealth(snum,-1000); /* If this screws up, then instant death!!! */ + + /* Getzrange returns the highest and lowest z's for an entire box, */ + /* NOT just a point. This prevents you from falling off cliffs */ + /* when you step only slightly over the cliff. */ + getzrange(posx[snum],posy[snum],posz[snum],cursectnum[snum],&globhiz,&globhihit,&globloz,&globlohit,128L,CLIPMASK0); + sprite[playersprite[snum]].cstat |= 1; + + if (_sync[snum].avel != 0) /* ang += avel * constant */ + { /* ENGINE calculates avel for you */ + doubvel = TICSPERFRAME; + if ((_sync[snum].bits&256) > 0) /* Lt. shift makes turn velocity 50% faster */ + doubvel += (TICSPERFRAME>>1); + ang[snum] += ((((long)_sync[snum].avel)*doubvel)>>4); + ang[snum] &= 2047; + } + + if (health[snum] < 0) + { + health[snum] -= TICSPERFRAME; + if (health[snum] <= -160) + { + hvel[snum] = 0; + if (snum == myconnectindex) + fvel = 0, svel = 0, avel = 0, keystatus[3] = 1; + + deaths[snum]++; + health[snum] = 100; + numbombs[snum] = 0; + numgrabbers[snum] = 0; + nummissiles[snum] = 0; + flytime[snum] = 0; + + findrandomspot(&posx[snum],&posy[snum],&cursectnum[snum]); + posz[snum] = getflorzofslope(cursectnum[snum],posx[snum],posy[snum])-(1<<8); + horiz[snum] = 100; + ang[snum] = (krand()&2047); + + sprite[playersprite[snum]].x = posx[snum]; + sprite[playersprite[snum]].y = posy[snum]; + sprite[playersprite[snum]].z = posz[snum]+EYEHEIGHT; + sprite[playersprite[snum]].picnum = PLAYER; + sprite[playersprite[snum]].ang = ang[snum]; + sprite[playersprite[snum]].xrepeat = 64; + sprite[playersprite[snum]].yrepeat = 64; + changespritesect(playersprite[snum],cursectnum[snum]); + + drawstatusbar(snum); /* Andy did this */ + + i = playersprite[snum]; + wsayfollow("zipguns.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,1); + for(k=0;k<16;k++) + { + spawnsprite(j,sprite[i].x,sprite[i].y,sprite[i].z+(8<<8),2,-4,0, + 32,24,24,0,0,EXPLOSION,sprite[i].ang, + (krand()&511)-256,(krand()&511)-256,(krand()&16384)-8192, + sprite[i].owner,sprite[i].sectnum,7,96,0,0); + /* 96=Time left for smoke to be alive */ + } + } + else + { + sprite[playersprite[snum]].xrepeat = max(((128+health[snum])>>1),0); + sprite[playersprite[snum]].yrepeat = max(((128+health[snum])>>1),0); + + hvel[snum] += (TICSPERFRAME<<2); + horiz[snum] = max(horiz[snum]-4,0); + posz[snum] += hvel[snum]; + if (posz[snum] > globloz-(4<<8)) + { + posz[snum] = globloz-(4<<8); + horiz[snum] = min(horiz[snum]+5,200); + hvel[snum] = 0; + } + } + } + + if (((_sync[snum].bits&8) > 0) && (horiz[snum] > 100-(200>>1))) horiz[snum] -= 4; /* - */ + if (((_sync[snum].bits&4) > 0) && (horiz[snum] < 100+(200>>1))) horiz[snum] += 4; /* + */ + + goalz = globloz-EYEHEIGHT; + if (sector[cursectnum[snum]].lotag == 4) /* slime sector */ + if ((globlohit&0xc000) != 49152) /* You're not on a sprite */ + { + goalz = globloz-(8<<8); + if (posz[snum] >= goalz-(2<<8)) + { + clipmove(&posx[snum],&posy[snum],&posz[snum],&cursectnum[snum],-TICSPERFRAME<<14,-TICSPERFRAME<<14,128L,4<<8,4<<8,CLIPMASK0); + + if (slimesoundcnt[snum] >= 0) + { + slimesoundcnt[snum] -= TICSPERFRAME; + while (slimesoundcnt[snum] < 0) + { + slimesoundcnt[snum] += 120; + wsayfollow("slime.wav",4096L+(krand()&127)-64,256L,&posx[snum],&posy[snum],1); + } + } + } + } + if (goalz < globhiz+(16<<8)) /* ceiling&floor too close */ + goalz = ((globloz+globhiz)>>1); + /* goalz += mousz; */ + if (health[snum] >= 0) + { + if ((_sync[snum].bits&1) > 0) /* A (stand high) */ + { + if (flytime[snum] <= lockclock) + { + if (posz[snum] >= globloz-(32<<8)) + { + goalz -= (16<<8); + if (_sync[snum].bits&256) goalz -= (24<<8); + } + } + else + { + hvel[snum] -= 192; + if (_sync[snum].bits&256) hvel[snum] -= 192; + } + } + if ((_sync[snum].bits&2) > 0) /* Z (stand low) */ + { + if (flytime[snum] <= lockclock) + { + goalz += (12<<8); + if (_sync[snum].bits&256) goalz += (12<<8); + } + else + { + hvel[snum] += 192; + if (_sync[snum].bits&256) hvel[snum] += 192; + } + } + } + + if (flytime[snum] <= lockclock) + { + if (posz[snum] < goalz) + hvel[snum] += (TICSPERFRAME<<4); + else + hvel[snum] = (((goalz-posz[snum])*TICSPERFRAME)>>5); + } + else + { + hvel[snum] -= (hvel[snum]>>2); + hvel[snum] -= ksgn(hvel[snum]); + } + + posz[snum] += hvel[snum]; + if (posz[snum] > globloz-(4<<8)) posz[snum] = globloz-(4<<8), hvel[snum] = 0; + if (posz[snum] < globhiz+(4<<8)) posz[snum] = globhiz+(4<<8), hvel[snum] = 0; + + if (dimensionmode[snum] != 3) + { + if (((_sync[snum].bits&32) > 0) && (zoom[snum] > 48)) zoom[snum] -= (zoom[snum]>>4); + if (((_sync[snum].bits&16) > 0) && (zoom[snum] < 4096)) zoom[snum] += (zoom[snum]>>4); + } + + /* Update sprite representation of player */ + /* -should be after movement, but before shooting code */ + setsprite(playersprite[snum],posx[snum],posy[snum],posz[snum]+EYEHEIGHT); + sprite[playersprite[snum]].ang = ang[snum]; + + if (health[snum] >= 0) + { + if ((cursectnum[snum] < 0) || (cursectnum[snum] >= numsectors)) + { /* How did you get in the wrong sector? */ + wsayfollow("ouch.wav",4096L+(krand()&127)-64,64L,&posx[snum],&posy[snum],1); + changehealth(snum,-TICSPERFRAME); + } + else if (globhiz+(8<<8) > globloz) + { /* Ceiling and floor are smooshing you! */ + wsayfollow("ouch.wav",4096L+(krand()&127)-64,64L,&posx[snum],&posy[snum],1); + changehealth(snum,-TICSPERFRAME); + } + } + + if ((waterfountainwall[snum] >= 0) && (health[snum] >= 0)) + if ((wall[neartagwall].lotag != 7) || ((_sync[snum].bits&1024) == 0)) + { + i = waterfountainwall[snum]; + if (wall[i].overpicnum == USEWATERFOUNTAIN) + wall[i].overpicnum = WATERFOUNTAIN; + else if (wall[i].picnum == USEWATERFOUNTAIN) + wall[i].picnum = WATERFOUNTAIN; + + waterfountainwall[snum] = -1; + } + + if ((_sync[snum].bits&1024) > 0) /* Space bar */ + { + /* Continuous triggers... */ + + neartag(posx[snum],posy[snum],posz[snum],cursectnum[snum],ang[snum],&neartagsector,&neartagwall,&neartagsprite,&neartaghitdist,1024L,3); + if (neartagsector == -1) + { + i = cursectnum[snum]; + if ((sector[i].lotag|sector[i].hitag) != 0) + neartagsector = i; + } + + if (wall[neartagwall].lotag == 7) /* Water fountain */ + { + if (wall[neartagwall].overpicnum == WATERFOUNTAIN) + { + wsayfollow("water.wav",4096L+(krand()&127)-64,256L,&posx[snum],&posy[snum],1); + wall[neartagwall].overpicnum = USEWATERFOUNTAIN; + waterfountainwall[snum] = neartagwall; + } + else if (wall[neartagwall].picnum == WATERFOUNTAIN) + { + wsayfollow("water.wav",4096L+(krand()&127)-64,256L,&posx[snum],&posy[snum],1); + wall[neartagwall].picnum = USEWATERFOUNTAIN; + waterfountainwall[snum] = neartagwall; + } + + if (waterfountainwall[snum] >= 0) + { + waterfountaincnt[snum] -= TICSPERFRAME; + while (waterfountaincnt[snum] < 0) + { + waterfountaincnt[snum] += 120; + wsayfollow("water.wav",4096L+(krand()&127)-64,256L,&posx[snum],&posy[snum],1); + changehealth(snum,2); + } + } + } + + /* 1-time triggers... */ + if ((oflags[snum]&1024) == 0) + { + if (neartagsector >= 0) + if (sector[neartagsector].hitag == 0) + operatesector(neartagsector); + + if (neartagwall >= 0) + if (wall[neartagwall].lotag == 2) /* Switch */ + { + activatehitag(wall[neartagwall].hitag); + + j = wall[neartagwall].overpicnum; + if (j == SWITCH1ON) /* 1-time switch */ + { + wall[neartagwall].overpicnum = GIFTBOX; + wall[neartagwall].lotag = 0; + wall[neartagwall].hitag = 0; + } + if (j == GIFTBOX) /* 1-time switch */ + { + wall[neartagwall].overpicnum = SWITCH1ON; + wall[neartagwall].lotag = 0; + wall[neartagwall].hitag = 0; + } + if (j == SWITCH2ON) wall[neartagwall].overpicnum = SWITCH2OFF; + if (j == SWITCH2OFF) wall[neartagwall].overpicnum = SWITCH2ON; + if (j == SWITCH3ON) wall[neartagwall].overpicnum = SWITCH3OFF; + if (j == SWITCH3OFF) wall[neartagwall].overpicnum = SWITCH3ON; + + i = wall[neartagwall].point2; + dax = ((wall[neartagwall].x+wall[i].x)>>1); + day = ((wall[neartagwall].y+wall[i].y)>>1); + wsayfollow("switch.wav",4096L+(krand()&255)-128,256L,&dax,&day,0); + } + + if (neartagsprite >= 0) + { + if (sprite[neartagsprite].lotag == 1) + { /* if you're shoving innocent little AL around, he gets mad! */ + if (sprite[neartagsprite].picnum == AL) + { + sprite[neartagsprite].picnum = EVILAL; + sprite[neartagsprite].cstat |= 2; /* Make him transluscent */ + sprite[neartagsprite].xrepeat = 38; + sprite[neartagsprite].yrepeat = 38; + changespritestat(neartagsprite,10); + } + } + if (sprite[neartagsprite].lotag == 4) + { + activatehitag(sprite[neartagsprite].hitag); + + j = sprite[neartagsprite].picnum; + if (j == SWITCH1ON) /* 1-time switch */ + { + sprite[neartagsprite].picnum = GIFTBOX; + sprite[neartagsprite].lotag = 0; + sprite[neartagsprite].hitag = 0; + } + if (j == GIFTBOX) /* 1-time switch */ + { + sprite[neartagsprite].picnum = SWITCH1ON; + sprite[neartagsprite].lotag = 0; + sprite[neartagsprite].hitag = 0; + } + if (j == SWITCH2ON) sprite[neartagsprite].picnum = SWITCH2OFF; + if (j == SWITCH2OFF) sprite[neartagsprite].picnum = SWITCH2ON; + if (j == SWITCH3ON) sprite[neartagsprite].picnum = SWITCH3OFF; + if (j == SWITCH3OFF) sprite[neartagsprite].picnum = SWITCH3ON; + + dax = sprite[neartagsprite].x; + day = sprite[neartagsprite].y; + wsayfollow("switch.wav",4096L+(krand()&255)-128,256L,&dax,&day,0); + } + } + } + } + + if ((_sync[snum].bits & 2048) > 0) { /* Shoot a bullet */ + if ((numbombs[snum] == 0) && (((_sync[snum].bits >> 13) & 7) == 2) && (myconnectindex == snum)) + locselectedgun = 0; + if ((nummissiles[snum] == 0) && (((_sync[snum].bits >> 13) & 7) == 3) && (myconnectindex == snum)) + locselectedgun = 1; + if ((numgrabbers[snum] == 0) && (((_sync[snum].bits >> 13) & 7) == 4) && (myconnectindex == snum)) + locselectedgun = 1; + + if ((health[snum] >= 0) || ((krand() & 127) > -health[snum])) + switch((_sync[snum].bits >> 13) & 7) { + case 0: + if (lockclock > lastchaingun[snum]+8) { + lastchaingun[snum] = lockclock; + shootgun(snum,posx[snum],posy[snum],posz[snum],ang[snum],horiz[snum],cursectnum[snum],0); + } + break; + case 1: + if ((oflags[snum] & 2048) == 0) + shootgun(snum,posx[snum],posy[snum],posz[snum],ang[snum],horiz[snum],cursectnum[snum],1); + break; + case 2: + if ((oflags[snum] & 2048) == 0) + if (numbombs[snum] > 0) { + shootgun(snum,posx[snum],posy[snum],posz[snum],ang[snum],horiz[snum],cursectnum[snum],2); + changenumbombs(snum,-1); + } + break; + case 3: + if ((oflags[snum] & 2048) == 0) + if (nummissiles[snum] > 0) { + shootgun(snum,posx[snum],posy[snum],posz[snum],ang[snum],horiz[snum],cursectnum[snum],3); + changenummissiles(snum,-1); + } + break; + case 4: + if ((oflags[snum] & 2048) == 0) + if (numgrabbers[snum] > 0) { + shootgun(snum,posx[snum],posy[snum],posz[snum],ang[snum],horiz[snum],cursectnum[snum],4); + changenumgrabbers(snum,-1); + } + break; + } + } + + if ((_sync[snum].bits&4096) > (oflags[snum]&4096)) /* Keypad enter */ + { + dimensionmode[snum]++; + if (dimensionmode[snum] > 3) dimensionmode[snum] = 1; + } + + oflags[snum] = _sync[snum].bits; +} + + +void movethings(void) +{ + long i; + + gotlastpacketclock = totalclock; + for(i=connecthead;i>=0;i=connectpoint2[i]) + { + copybufbyte(&ffsync[i],&baksync[movefifoend[i]][i],sizeof(input)); + movefifoend[i] = ((movefifoend[i]+1)&(MOVEFIFOSIZ-1)); + } +} + +void fakedomovethings(void) +{ + input *syn; + /*long i, j, k, doubvel, xvect, yvect, goalz;*/ + long doubvel, xvect, yvect, goalz; + short bakcstat; + + syn = (input *)&baksync[fakemovefifoplc][myconnectindex]; + + omyx = myx; + omyy = myy; + omyz = myz; + omyang = myang; + omyhoriz = myhoriz; + + bakcstat = sprite[playersprite[myconnectindex]].cstat; + sprite[playersprite[myconnectindex]].cstat &= ~0x101; + + if ((syn->fvel|syn->svel) != 0) + { + doubvel = (TICSPERFRAME<<((syn->bits&256)>0)); + + xvect = 0, yvect = 0; + if (syn->fvel != 0) + { + xvect += ((((long)syn->fvel)*doubvel*(long)sintable[(myang+512)&2047])>>3); + yvect += ((((long)syn->fvel)*doubvel*(long)sintable[myang&2047])>>3); + } + if (syn->svel != 0) + { + xvect += ((((long)syn->svel)*doubvel*(long)sintable[myang&2047])>>3); + yvect += ((((long)syn->svel)*doubvel*(long)sintable[(myang+1536)&2047])>>3); + } + if (flytime[myconnectindex] > lockclock) { xvect += xvect; yvect += yvect; } /* DOuble flying speed */ + clipmove(&myx,&myy,&myz,&mycursectnum,xvect,yvect,128L,4<<8,4<<8,CLIPMASK0); + } + + pushmove(&myx,&myy,&myz,&mycursectnum,128L,4<<8,4<<8,CLIPMASK0); + getzrange(myx,myy,myz,mycursectnum,&globhiz,&globhihit,&globloz,&globlohit,128L,CLIPMASK0); + + if (syn->avel != 0) /* ang += avel * constant */ + { /* ENGINE calculates avel for you */ + doubvel = TICSPERFRAME; + if ((syn->bits&256) > 0) /* Lt. shift makes turn velocity 50% faster */ + doubvel += (TICSPERFRAME>>1); + myang += ((((long)syn->avel)*doubvel)>>4); + myang &= 2047; + } + + if (((syn->bits&8) > 0) && (myhoriz > 100-(200>>1))) myhoriz -= 4; /* - */ + if (((syn->bits&4) > 0) && (myhoriz < 100+(200>>1))) myhoriz += 4; /* + */ + + goalz = globloz-EYEHEIGHT; + if (sector[mycursectnum].lotag == 4) /* slime sector */ + if ((globlohit&0xc000) != 49152) /* You're not on a sprite */ + { + goalz = globloz-(8<<8); + if (myz >= goalz-(2<<8)) + clipmove(&myx,&myy,&myz,&mycursectnum,-TICSPERFRAME<<14,-TICSPERFRAME<<14,128L,4<<8,4<<8,CLIPMASK0); + } + if (goalz < globhiz+(16<<8)) /* ceiling&floor too close */ + goalz = ((globloz+globhiz)>>1); + + if (health[myconnectindex] >= 0) + { + if ((syn->bits&1) > 0) /* A (stand high) */ + { + if (flytime[myconnectindex] <= lockclock) + { + if (myz >= globloz-(32<<8)) + { + goalz -= (16<<8); + if (syn->bits&256) goalz -= (24<<8); + } + } + else + { + myzvel -= 192; + if (syn->bits&256) myzvel -= 192; + } + } + if ((syn->bits&2) > 0) /* Z (stand low) */ + { + if (flytime[myconnectindex] <= lockclock) + { + goalz += (12<<8); + if (syn->bits&256) goalz += (12<<8); + } + else + { + myzvel += 192; + if (syn->bits&256) myzvel += 192; + } + } + } + + if (flytime[myconnectindex] <= lockclock) + { + if (myz < goalz) + myzvel += (TICSPERFRAME<<4); + else + myzvel = (((goalz-myz)*TICSPERFRAME)>>5); + } + else + { + myzvel -= (myzvel>>2); + myzvel -= ksgn(myzvel); + } + + myz += myzvel; + if (myz > globloz-(4<<8)) myz = globloz-(4<<8), myzvel = 0; + if (myz < globhiz+(4<<8)) myz = globhiz+(4<<8), myzvel = 0; + + sprite[playersprite[myconnectindex]].cstat = bakcstat; + + myxbak[fakemovefifoplc] = myx; + myybak[fakemovefifoplc] = myy; + myzbak[fakemovefifoplc] = myz; + myangbak[fakemovefifoplc] = myang; + myhorizbak[fakemovefifoplc] = myhoriz; + fakemovefifoplc = (fakemovefifoplc+1)&(MOVEFIFOSIZ-1); +} + + /* Prediction correction */ +void fakedomovethingscorrect(void) +{ + long i; + + if ((networkmode == 0) && (myconnectindex == connecthead)) return; + + i = ((movefifoplc-1)&(MOVEFIFOSIZ-1)); + + if ((posx[myconnectindex] == myxbak[i]) && + (posy[myconnectindex] == myybak[i]) && + (posz[myconnectindex] == myzbak[i]) && + (horiz[myconnectindex] == myhorizbak[i]) && + (ang[myconnectindex] == myangbak[i])) + return; + + /* Re-start fakedomovethings back to place of error */ + myx = omyx = posx[myconnectindex]; + myy = omyy = posy[myconnectindex]; + myz = omyz = posz[myconnectindex]; myzvel = hvel[myconnectindex]; + myang = omyang = ang[myconnectindex]; + mycursectnum = mycursectnum; + myhoriz = omyhoriz = horiz[myconnectindex]; + + fakemovefifoplc = movefifoplc; + while (fakemovefifoplc != movefifoend[myconnectindex]) fakedomovethings(); +} + + +void doanimations(void) +{ + long i, j; + + for(i=animatecnt-1;i>=0;i--) + { + j = *animateptr[i]; + + if (j < animategoal[i]) + j = min(j+animatevel[i]*TICSPERFRAME,animategoal[i]); + else + j = max(j-animatevel[i]*TICSPERFRAME,animategoal[i]); + animatevel[i] += animateacc[i]; + + *animateptr[i] = j; + + if (j == animategoal[i]) + { + animatecnt--; + if (i != animatecnt) + { + stopinterpolation(animateptr[i]); + animateptr[i] = animateptr[animatecnt]; + animategoal[i] = animategoal[animatecnt]; + animatevel[i] = animatevel[animatecnt]; + animateacc[i] = animateacc[animatecnt]; + } + } + } +} + + +void warp(long *x, long *y, long *z, short *daang, short *dasector) +{ + short startwall, endwall, s; + long i, j, dax, day, ox, oy; + + ox = *x; oy = *y; + + for(i=0;i= warpsectorcnt) i = 0; + } while (sector[warpsectorlist[i]].hitag != j); + *dasector = warpsectorlist[i]; + break; + } + + /* Find center of sector */ + startwall = sector[*dasector].wallptr; + endwall = startwall+sector[*dasector].wallnum; + dax = 0L, day = 0L; + for(s=startwall;s= 0) + i = s; + } + *x = dax / (endwall-startwall); + *y = day / (endwall-startwall); + *z = sector[*dasector].floorz-(32<<8); + updatesector(*x,*y,dasector); + dax = ((wall[i].x+wall[wall[i].point2].x)>>1); + day = ((wall[i].y+wall[wall[i].point2].y)>>1); + *daang = getangle(dax-*x,day-*y); + + wsayfollow("warp.wav",3072L+(krand()&127)-64,192L,&ox,&oy,0); + wsayfollow("warp.wav",4096L+(krand()&127)-64,256L,x,y,0); +} + + +void warpsprite(short spritenum) +{ + short dasectnum; + + dasectnum = sprite[spritenum].sectnum; + warp(&sprite[spritenum].x,&sprite[spritenum].y,&sprite[spritenum].z, + &sprite[spritenum].ang,&dasectnum); + + copybuf(&sprite[spritenum].x,&osprite[spritenum].x,3); + changespritesect(spritenum,dasectnum); + + show2dsprite[spritenum>>3] &= ~(1<<(spritenum&7)); + if (show2dsector[dasectnum>>3]&(1<<(dasectnum&7))) + show2dsprite[spritenum>>3] |= (1<<(spritenum&7)); +} + + +int testneighborsectors(short sect1, short sect2) +{ + short i, startwall, num1, num2; + + num1 = sector[sect1].wallnum; + num2 = sector[sect2].wallnum; + if (num1 < num2) /* Traverse walls of sector with fewest walls (for speed) */ + { + startwall = sector[sect1].wallptr; + for(i=num1-1;i>=0;i--) + if (wall[i+startwall].nextsector == sect2) + return(1); + } + else + { + startwall = sector[sect2].wallptr; + for(i=num2-1;i>=0;i--) + if (wall[i+startwall].nextsector == sect1) + return(1); + } + return(0); +} + + +void tagcode(void) +{ + long i, j, k, l, s, dax, day, cnt, good; + short startwall, endwall, dasector, p, oldang; + + for(p=connecthead;p>=0;p=connectpoint2[p]) + { + if (sector[cursectnum[p]].lotag == 1) + { + activatehitag(sector[cursectnum[p]].hitag); + sector[cursectnum[p]].lotag = 0; + sector[cursectnum[p]].hitag = 0; + } + if ((sector[cursectnum[p]].lotag == 2) && (cursectnum[p] != ocursectnum[p])) + activatehitag(sector[cursectnum[p]].hitag); + } + + for(i=0;i>2); + if (j >= 16) j = 31-j; + { + sector[dasector].ceilingshade = j; + sector[dasector].floorshade = j; + startwall = sector[dasector].wallptr; + endwall = startwall+sector[dasector].wallnum; + for(s=startwall;s=0;p=connectpoint2[p]) + if (sector[cursectnum[p]].lotag == 10) /* warp sector */ + { + if (cursectnum[p] != ocursectnum[p]) + { + warpsprite(playersprite[p]); + posx[p] = sprite[playersprite[p]].x; + posy[p] = sprite[playersprite[p]].y; + posz[p] = sprite[playersprite[p]].z; + ang[p] = sprite[playersprite[p]].ang; + cursectnum[p] = sprite[playersprite[p]].sectnum; + + sprite[playersprite[p]].z += EYEHEIGHT; + + #if 0 + warp(&posx[p],&posy[p],&posz[p],&ang[p],&cursectnum[p]); + /* Update sprite representation of player */ + setsprite(playersprite[p],posx[p],posy[p],posz[p]+EYEHEIGHT); + sprite[playersprite[p]].ang = ang[p]; + #endif + } + } + + for(i=0;i>2)&255); + } + + for(i=0;i>2)&255); + sector[floorpanninglist[i]].floorypanning = ((lockclock>>2)&255); + } + + for(i=0;i dragx2[i]) dragxdir[i] = -16; + if (wall[startwall].y+dragydir[i] > dragy2[i]) dragydir[i] = -16; + + for(j=startwall;j>3); + + for(p=connecthead;p>=0;p=connectpoint2[p]) + if (cursectnum[p] == dasector) + { + posx[p] += dragxdir[i]; + posy[p] += dragydir[i]; + if (p == myconnectindex) + { myx += dragxdir[i]; myy += dragydir[i]; } + /*posz[p] += (sector[dasector].floorz-j);*/ + + /* Update sprite representation of player */ + setsprite(playersprite[p],posx[p],posy[p],posz[p]+EYEHEIGHT); + sprite[playersprite[p]].ang = ang[p]; + } + } + + for(i=0;i=0;p=connectpoint2[p]) + if ((cursectnum[p] == swingsector[i]) || (testneighborsectors(cursectnum[p],swingsector[i]) == 1)) + { + cnt = 256; + do + { + good = 1; + + /* swingangopendir is -1 if forwards, 1 is backwards */ + l = (swingangopendir[i] > 0); + for(k=l+3;k>=l;k--) + if (clipinsidebox(posx[p],posy[p],swingwall[i][k],128L) != 0) + { + good = 0; + break; + } + if (good == 0) + { + if (cnt == 256) + { + swinganginc[i] = -swinganginc[i]; + swingang[i] = oldang; + } + else + { + swingang[i] = ((swingang[i]-swinganginc[i])&2047); + } + for(k=1;k<=3;k++) + rotatepoint(swingx[i][0],swingy[i][0],swingx[i][k],swingy[i][k],swingang[i],&wall[swingwall[i][k]].x,&wall[swingwall[i][k]].y); + if (swingang[i] == swingangclosed[i]) + { + wsayfollow("closdoor.wav",4096L+(krand()&511)-256,256L,&swingx[i][0],&swingy[i][0],0); + swinganginc[i] = 0; + break; + } + if (swingang[i] == swingangopen[i]) + { + swinganginc[i] = 0; + break; + } + cnt--; + } + } while ((good == 0) && (cnt > 0)); + } + } + } + if (swinganginc[i] == 0) + for(j=1;j<=3;j++) + { + stopinterpolation(&wall[swingwall[i][j]].x); + stopinterpolation(&wall[swingwall[i][j]].y); + } + } + + for(i=0;i 2)) + { + dasector = subwaytracksector[i][0]; + startwall = sector[dasector].wallptr; + endwall = startwall+sector[dasector].wallnum; + for(k=startwall;k subwaytrackx1[i]) + if (wall[k].y > subwaytracky1[i]) + if (wall[k].x < subwaytrackx2[i]) + if (wall[k].y < subwaytracky2[i]) + wall[k].x += subwayvel[i]; + + for(j=1;j=0;s=nextspritesect[s]) + sprite[s].x += subwayvel[i]; + } + + for(p=connecthead;p>=0;p=connectpoint2[p]) + if (cursectnum[p] != subwaytracksector[i][0]) + if (sector[cursectnum[p]].floorz != sector[subwaytracksector[i][0]].floorz) + if (posx[p] > subwaytrackx1[i]) + if (posy[p] > subwaytracky1[i]) + if (posx[p] < subwaytrackx2[i]) + if (posy[p] < subwaytracky2[i]) + { + posx[p] += subwayvel[i]; + if (p == myconnectindex) + { myx += subwayvel[i]; } + + /* Update sprite representation of player */ + setsprite(playersprite[p],posx[p],posy[p],posz[p]+EYEHEIGHT); + sprite[playersprite[p]].ang = ang[p]; + } + + subwayx[i] += subwayvel[i]; + } + + j = subwayvel[i]; + k = subwaystop[i][subwaygoalstop[i]] - subwayx[i]; + if (k > 0) + { + if (k > 4096) + { + if (subwayvel[i] < 256) subwayvel[i]++; + } + else + subwayvel[i] = (k>>4)+1; + } + else if (k < 0) + { + if (k < -4096) + { + if (subwayvel[i] > -256) subwayvel[i]--; + } + else + subwayvel[i] = (k>>4)-1; + } + if ((j < 0) && (subwayvel[i] >= 0)) subwayvel[i] = -1; + if ((j > 0) && (subwayvel[i] <= 0)) subwayvel[i] = 1; + + if ((subwayvel[i] <= 2) && (subwayvel[i] >= -2) && (klabs(k) < 2048)) + { + /* Open / close doors */ + if ((subwaypausetime[i] == 720) || ((subwaypausetime[i] >= 120) && (subwaypausetime[i]-TICSPERFRAME < 120))) + activatehitag(sector[subwaytracksector[i][0]].hitag); + + subwaypausetime[i] -= TICSPERFRAME; + if (subwaypausetime[i] < 0) + { + subwaypausetime[i] = 720; + if (subwayvel[i] < 0) + { + subwaygoalstop[i]--; + if (subwaygoalstop[i] < 0) + { + subwaygoalstop[i] = 1; + subwayvel[i] = 1; + } + } + else if (subwayvel[i] > 0) + { + subwaygoalstop[i]++; + if (subwaygoalstop[i] >= subwaystopcnt[i]) + { + subwaygoalstop[i] = subwaystopcnt[i]-2; + subwayvel[i] = -1; + } + } + } + } + } +} + + +void bombexplode(long i) +{ + long j, nextj, k, daang, dax, day, dist; + + spawnsprite(j,sprite[i].x,sprite[i].y,sprite[i].z,0,-4,0, + 32,64,64,0,0,EXPLOSION,sprite[i].ang, + 0,0,0,sprite[i].owner,sprite[i].sectnum,5,31,0,0); + /* 31=Time left for explosion to stay */ + + for(k=0;k<12;k++) + { + spawnsprite(j,sprite[i].x,sprite[i].y,sprite[i].z+(8<<8),2,-4,0, + 32,24,24,0,0,EXPLOSION,sprite[i].ang, + (krand()>>7)-256,(krand()>>7)-256,(krand()>>2)-8192, + sprite[i].owner,sprite[i].sectnum,7,96,0,0); + /* 96=Time left for smoke to be alive */ + } + + for(j=connecthead;j>=0;j=connectpoint2[j]) + { + dist = (posx[j]-sprite[i].x)*(posx[j]-sprite[i].x); + dist += (posy[j]-sprite[i].y)*(posy[j]-sprite[i].y); + dist += ((posz[j]-sprite[i].z)>>4)*((posz[j]-sprite[i].z)>>4); + if (dist < 4194304) + if (cansee(sprite[i].x,sprite[i].y,sprite[i].z-(tilesizy[sprite[i].picnum]<<7),sprite[i].sectnum,posx[j],posy[j],posz[j],cursectnum[j]) == 1) + { + k = ((32768/((dist>>16)+4))>>5); + if (j == myconnectindex) + { + daang = getangle(posx[j]-sprite[i].x,posy[j]-sprite[i].y); + dax = ((k*sintable[(daang+512)&2047])>>14); + day = ((k*sintable[daang&2047])>>14); + fvel += ((dax*sintable[(ang[j]+512)&2047]+day*sintable[ang[j]&2047])>>14); + svel += ((day*sintable[(ang[j]+512)&2047]-dax*sintable[ang[j]&2047])>>14); + } + changehealth(j,-k); /* if changehealth returns 1, you're dead */ + } + } + + for(k=1;k<=2;k++) /* Check for hurting monsters */ + { + for(j=headspritestat[k];j>=0;j=nextj) + { + nextj = nextspritestat[j]; + + dist = (sprite[j].x-sprite[i].x)*(sprite[j].x-sprite[i].x); + dist += (sprite[j].y-sprite[i].y)*(sprite[j].y-sprite[i].y); + dist += ((sprite[j].z-sprite[i].z)>>4)*((sprite[j].z-sprite[i].z)>>4); + if (dist >= 4194304) continue; + if (cansee(sprite[i].x,sprite[i].y,sprite[i].z-(tilesizy[sprite[i].picnum]<<7),sprite[i].sectnum,sprite[j].x,sprite[j].y,sprite[j].z-(tilesizy[sprite[j].picnum]<<7),sprite[j].sectnum) == 0) + continue; + if (sprite[j].picnum == BROWNMONSTER) + { + sprite[j].z += ((tilesizy[sprite[j].picnum]*sprite[j].yrepeat)<<1); + sprite[j].picnum = GIFTBOX; + sprite[j].cstat &= ~0x83; /* Should not clip, foot-z */ + changespritestat(j,12); + } + } + } + + for(j=headspritestat[10];j>=0;j=nextj) /* Check for EVILAL's */ + { + nextj = nextspritestat[j]; + + dist = (sprite[j].x-sprite[i].x)*(sprite[j].x-sprite[i].x); + dist += (sprite[j].y-sprite[i].y)*(sprite[j].y-sprite[i].y); + dist += ((sprite[j].z-sprite[i].z)>>4)*((sprite[j].z-sprite[i].z)>>4); + if (dist >= 4194304) continue; + if (cansee(sprite[i].x,sprite[i].y,sprite[i].z-(tilesizy[sprite[i].picnum]<<7),sprite[i].sectnum,sprite[j].x,sprite[j].y,sprite[j].z-(tilesizy[sprite[j].picnum]<<7),sprite[j].sectnum) == 0) + continue; + + sprite[j].picnum = EVILALGRAVE; + sprite[j].cstat = 0; + sprite[j].xvel = (krand()&255)-128; + sprite[j].yvel = (krand()&255)-128; + sprite[j].zvel = (krand()&4095)-3072; + changespritestat(j,9); + } + + wsayfollow("blowup.wav",3840L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); + deletesprite((short)i); +} + + +void statuslistcode(void) +{ + short p, target, hitobject, daang, osectnum, movestat; + long i, nexti, j, nextj, k, l, dax, day, daz, dist=0, ox, oy, mindist; + long doubvel, xvect, yvect; + + /* Go through active BROWNMONSTER list */ + for(i=headspritestat[1];i>=0;i=nexti) + { + nexti = nextspritestat[i]; + + k = krand(); + + /* Choose a target player */ + mindist = 0x7fffffff; target = connecthead; + for(p=connecthead;p>=0;p=connectpoint2[p]) + { + dist = klabs(sprite[i].x-posx[p])+klabs(sprite[i].y-posy[p]); + if (dist < mindist) mindist = dist, target = p; + } + + /* brown monster decides to shoot bullet */ + if ((k&63) == 23) + { + if (cansee(sprite[i].x,sprite[i].y,sprite[i].z-(tilesizy[sprite[i].picnum]<<7),sprite[i].sectnum,posx[target],posy[target],posz[target],cursectnum[target]) == 0) + { + if ((k&0xf00) == 0xb00) changespritestat(i,2); + } + else + { + wsayfollow("monshoot.wav",5144L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,1); + + doubvel = (TICSPERFRAME<<((_sync[target].bits&256)>0)); + xvect = 0, yvect = 0; + if (_sync[target].fvel != 0) + { + xvect += ((((long)_sync[target].fvel)*doubvel*(long)sintable[(ang[target]+512)&2047])>>3); + yvect += ((((long)_sync[target].fvel)*doubvel*(long)sintable[ang[target]&2047])>>3); + } + if (_sync[target].svel != 0) + { + xvect += ((((long)_sync[target].svel)*doubvel*(long)sintable[ang[target]&2047])>>3); + yvect += ((((long)_sync[target].svel)*doubvel*(long)sintable[(ang[target]+1536)&2047])>>3); + } + + ox = posx[target]; oy = posy[target]; + + /* distance is j */ + j = ksqrt((ox-sprite[i].x)*(ox-sprite[i].x)+(oy-sprite[i].y)*(oy-sprite[i].y)); + + switch((sprite[i].extra>>11)&3) + { + case 1: j = -(j>>1); break; + case 3: j = 0; break; + case 0: case 2: break; + } + sprite[i].extra += 2048; + + /* rate is (TICSPERFRAME<<19) */ + xvect = scale(xvect,j,TICSPERFRAME<<19); + yvect = scale(yvect,j,TICSPERFRAME<<19); + clipmove(&ox,&oy,&posz[target],&cursectnum[target],xvect<<14,yvect<<14,128L,4<<8,4<<8,CLIPMASK0); + ox -= sprite[i].x; + oy -= sprite[i].y; + + daang = ((getangle(ox,oy)+(krand()&7)-4)&2047); + + dax = (sintable[(daang+512)&2047]>>6); + day = (sintable[daang&2047]>>6); + daz = 0; + if (ox != 0) + daz = scale(dax,posz[target]+(8<<8)-sprite[i].z,ox); + else if (oy != 0) + daz = scale(day,posz[target]+(8<<8)-sprite[i].z,oy); + + spawnsprite(j,sprite[i].x,sprite[i].y,sprite[i].z,128,0,0, + 16,sprite[i].xrepeat,sprite[i].yrepeat,0,0,BULLET,daang,dax,day,daz,i,sprite[i].sectnum,6,0,0,0); + + sprite[i].extra &= (~2047); + } + } + + /* Move brown monster */ + dax = sprite[i].x; /* Back up old x&y if stepping off cliff */ + day = sprite[i].y; + + doubvel = max(mulscale7(sprite[i].xrepeat,sprite[i].yrepeat),4); + + osectnum = sprite[i].sectnum; + movestat = movesprite((short)i,(long)sintable[(sprite[i].ang+512)&2047]*doubvel,(long)sintable[sprite[i].ang]*doubvel,0L,4L<<8,4L<<8,CLIPMASK0); + if (globloz > sprite[i].z+(48<<8)) + { sprite[i].x = dax; sprite[i].y = day; movestat = 1; } + else + sprite[i].z = globloz-((tilesizy[sprite[i].picnum]*sprite[i].yrepeat)<<1); + + if ((sprite[i].sectnum != osectnum) && (sector[sprite[i].sectnum].lotag == 10)) + { warpsprite((short)i); movestat = 0; } + + if ((movestat != 0) || ((k&63) == 1)) + { + if (sprite[i].ang == (sprite[i].extra&2047)) + { + daang = (getangle(posx[target]-sprite[i].x,posy[target]-sprite[i].y)&2047); + daang = ((daang+(krand()&1023)-512)&2047); + sprite[i].extra = ((sprite[i].extra&(~2047))|daang); + } + if ((sprite[i].extra-sprite[i].ang)&1024) + { + sprite[i].ang = ((sprite[i].ang-32)&2047); + if (!((sprite[i].extra-sprite[i].ang)&1024)) sprite[i].ang = (sprite[i].extra&2047); + } + else + { + sprite[i].ang = ((sprite[i].ang+32)&2047); + if (((sprite[i].extra-sprite[i].ang)&1024)) sprite[i].ang = (sprite[i].extra&2047); + } + } + } + + for(i=headspritestat[10];i>=0;i=nexti) /* EVILAL list */ + { + nexti = nextspritestat[i]; + + if (sprite[i].yrepeat < 38) continue; + if (sprite[i].yrepeat < 64) + { + sprite[i].xrepeat++; + sprite[i].yrepeat++; + continue; + } + + if ((nummoves-i)&statrate[10]) continue; + + /* Choose a target player */ + mindist = 0x7fffffff; target = connecthead; + for(p=connecthead;p>=0;p=connectpoint2[p]) + { + dist = klabs(sprite[i].x-posx[p])+klabs(sprite[i].y-posy[p]); + if (dist < mindist) mindist = dist, target = p; + } + + k = (krand()&255); + + if ((sprite[i].lotag&32) && (k < 48)) /* Al decides to reproduce */ + { + l = 0; + if ((sprite[i].lotag&64) && (k < 2)) /* Give him a chance to reproduce without seeing you */ + l = 1; + else if (cansee(sprite[i].x,sprite[i].y,sprite[i].z-(tilesizy[sprite[i].picnum]<<7),sprite[i].sectnum,posx[target],posy[target],posz[target],cursectnum[target]) == 1) + l = 1; + if (l != 0) + { + spawnsprite(j,sprite[i].x,sprite[i].y,sprite[i].z,sprite[i].cstat,sprite[i].shade,sprite[i].pal, + sprite[i].clipdist,38,38,sprite[i].xoffset,sprite[i].yoffset,sprite[i].picnum,krand()&2047,0,0,0,i, + sprite[i].sectnum,10,sprite[i].lotag,sprite[i].hitag,sprite[i].extra); + switch(krand()&31) /* Mutations! */ + { + case 0: sprite[i].cstat ^= 2; break; + case 1: sprite[i].cstat ^= 512; break; + case 2: sprite[i].shade++; break; + case 3: sprite[i].shade--; break; + case 4: sprite[i].pal ^= 16; break; + case 5: case 6: case 7: sprite[i].lotag ^= (1<<(krand()&7)); break; + case 8: sprite[i].lotag = (krand()&255); break; + } + } + } + if (k >= 208+((sprite[i].lotag&128)>>2)) /* Al decides to shoot bullet */ + { + if (cansee(sprite[i].x,sprite[i].y,sprite[i].z-(tilesizy[sprite[i].picnum]<<7),sprite[i].sectnum,posx[target],posy[target],posz[target],cursectnum[target]) == 1) + { + wsayfollow("zipguns.wav",5144L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,1); + + spawnsprite(j,sprite[i].x,sprite[i].y, + sector[sprite[i].sectnum].floorz-(24<<8), + 0,0,0,16,32,32,0,0,BULLET, + (getangle(posx[target]-sprite[j].x, + posy[target]-sprite[j].y)+(krand()&15)-8)&2047, + sintable[(sprite[j].ang+512)&2047]>>6, + sintable[sprite[j].ang&2047]>>6, + ((posz[target]+(8<<8)-sprite[j].z)<<8) / + (ksqrt((posx[target]-sprite[j].x) * + (posx[target]-sprite[j].x) + + (posy[target]-sprite[j].y) * + (posy[target]-sprite[j].y))+1), + i,sprite[i].sectnum,6,0,0,0); + } + } + + /* Move Al */ + l = (((sprite[i].lotag&3)+2)<<8); + if (sprite[i].lotag&4) l = -l; + dax = sintable[(sprite[i].ang+512)&2047]*l; + day = sintable[sprite[i].ang]*l; + + osectnum = sprite[i].sectnum; + movestat = movesprite((short)i,dax,day,0L,-8L<<8,-8L<<8,CLIPMASK0); + sprite[i].z = globloz; + if ((sprite[i].sectnum != osectnum) && (sector[sprite[i].sectnum].lotag == 10)) + { + warpsprite((short)i); + movestat = 0; + } + + if (sprite[i].lotag&16) + { + if (((k&124) >= 120) && (cansee(sprite[i].x,sprite[i].y,sprite[i].z-(tilesizy[sprite[i].picnum]<<7),sprite[i].sectnum,posx[target],posy[target],posz[target],cursectnum[target]) == 1)) + sprite[i].ang = getangle(posx[target]-sprite[i].x,posy[target]-sprite[i].y); + else + sprite[i].ang = (krand()&2047); + } + + if (movestat != 0) + { + if ((k&2) && (cansee(sprite[i].x,sprite[i].y,sprite[i].z-(tilesizy[sprite[i].picnum]<<7),sprite[i].sectnum,posx[target],posy[target],posz[target],cursectnum[target]) == 1)) + sprite[i].ang = getangle(posx[target]-sprite[i].x,posy[target]-sprite[i].y); + else + sprite[i].ang = (krand()&2047); + + if ((movestat&49152) == 49152) + if (sprite[movestat&16383].picnum == EVILAL) + if ((k&31) >= 30) + { + wsayfollow("blowup.wav",5144L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); + sprite[i].picnum = EVILALGRAVE; + sprite[i].cstat = 0; + sprite[i].xvel = (krand()&255)-128; + sprite[i].yvel = (krand()&255)-128; + sprite[i].zvel = (krand()&4095)-3072; + changespritestat(i,9); + } + + if (sprite[i].lotag&8) + if ((k&31) >= 30) + { + wsayfollow("blowup.wav",5144L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); + sprite[i].picnum = EVILALGRAVE; + sprite[i].cstat = 0; + sprite[i].xvel = (krand()&255)-128; + sprite[i].yvel = (krand()&255)-128; + sprite[i].zvel = (krand()&4095)-3072; + changespritestat(i,9); + } + + if (movestat == -1) + { + wsayfollow("blowup.wav",5144L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); + sprite[i].picnum = EVILALGRAVE; + sprite[i].cstat = 0; + sprite[i].xvel = (krand()&255)-128; + sprite[i].yvel = (krand()&255)-128; + sprite[i].zvel = (krand()&4095)-3072; + changespritestat(i,9); + } + } + } + + /* Go through travelling bullet sprites */ + for(i=headspritestat[6];i>=0;i=nexti) + { + nexti = nextspritestat[i]; + + if ((nummoves-i)&statrate[6]) continue; + + /* If the sprite is a bullet then... */ + if ((sprite[i].picnum == BULLET) || (sprite[i].picnum == GRABBER) || (sprite[i].picnum == MISSILE) || (sprite[i].picnum == BOMB)) + { + dax = ((((long)sprite[i].xvel)*TICSPERFRAME)<<12); + day = ((((long)sprite[i].yvel)*TICSPERFRAME)<<12); + daz = ((((long)sprite[i].zvel)*TICSPERFRAME)>>2); + if (sprite[i].picnum == BOMB) daz = 0; + + osectnum = sprite[i].sectnum; + hitobject = movesprite((short)i,dax,day,daz,4L<<8,4L<<8,CLIPMASK1); + if ((sprite[i].sectnum != osectnum) && (sector[sprite[i].sectnum].lotag == 10)) + { + warpsprite((short)i); + hitobject = 0; + } + + if (sprite[i].picnum == GRABBER) { /* Andy did this (& Ken) !Homing! */ + checkgrabbertouchsprite(i,sprite[i].sectnum); + l = 0x7fffffff; + for (j = connecthead; j >= 0; j = connectpoint2[j]) /* Players */ + if (j != (sprite[i].owner & (MAXSPRITES - 1))) + if (cansee(sprite[i].x,sprite[i].y,sprite[i].z,sprite[i].sectnum,posx[j],posy[j],posz[j],cursectnum[j])) { + k = ksqrt(sqr(posx[j] - sprite[i].x) + sqr(posy[j] - sprite[i].y) + (sqr(posz[j] - sprite[i].z) >> 8)); + if (k < l) { + l = k; + dax = (posx[j] - sprite[i].x); + day = (posy[j] - sprite[i].y); + daz = (posz[j] - sprite[i].z); + } + } + for(j = headspritestat[1]; j >= 0; j = nextj) { /* Active monsters */ + nextj = nextspritestat[j]; + if (cansee(sprite[i].x,sprite[i].y,sprite[i].z,sprite[i].sectnum,sprite[j].x,sprite[j].y,sprite[j].z,sprite[j].sectnum)) { + k = ksqrt(sqr(sprite[j].x - sprite[i].x) + sqr(sprite[j].y - sprite[i].y) + (sqr(sprite[j].z - sprite[i].z) >> 8)); + if (k < l) { + l = k; + dax = (sprite[j].x - sprite[i].x); + day = (sprite[j].y - sprite[i].y); + daz = (sprite[j].z - sprite[i].z); + } + } + } + for(j = headspritestat[2]; j >= 0; j = nextj) { /* Inactive monsters */ + nextj = nextspritestat[j]; + if (cansee(sprite[i].x,sprite[i].y,sprite[i].z,sprite[i].sectnum,sprite[j].x,sprite[j].y,sprite[j].z,sprite[j].sectnum)) { + k = ksqrt(sqr(sprite[j].x - sprite[i].x) + sqr(sprite[j].y - sprite[i].y) + (sqr(sprite[j].z - sprite[i].z) >> 8)); + if (k < l) { + l = k; + dax = (sprite[j].x - sprite[i].x); + day = (sprite[j].y - sprite[i].y); + daz = (sprite[j].z - sprite[i].z); + } + } + } + if (l != 0x7fffffff) { + sprite[i].xvel = (divscale7(dax,l) + sprite[i].xvel); /* 1/5 of velocity is homing, 4/5 is momentum */ + sprite[i].yvel = (divscale7(day,l) + sprite[i].yvel); /* 1/5 of velocity is homing, 4/5 is momentum */ + sprite[i].zvel = (divscale7(daz,l) + sprite[i].zvel); /* 1/5 of velocity is homing, 4/5 is momentum */ + l = ksqrt((sprite[i].xvel * sprite[i].xvel) + (sprite[i].yvel * sprite[i].yvel) + ((sprite[i].zvel * sprite[i].zvel) >> 8)); + sprite[i].xvel = divscale9(sprite[i].xvel,l); + sprite[i].yvel = divscale9(sprite[i].yvel,l); + sprite[i].zvel = divscale9(sprite[i].zvel,l); + sprite[i].ang = getangle(sprite[i].xvel,sprite[i].yvel); + } + } + + if (sprite[i].picnum == BOMB) + { + j = sprite[i].sectnum; + if ((sector[j].floorstat&2) && (sprite[i].z > globloz-(8<<8))) + { + k = sector[j].wallptr; + daang = getangle(wall[wall[k].point2].x-wall[k].x,wall[wall[k].point2].y-wall[k].y); + sprite[i].xvel += mulscale22(sintable[(daang+1024)&2047],sector[j].floorheinum); + sprite[i].yvel += mulscale22(sintable[(daang+512)&2047],sector[j].floorheinum); + } + } + + if (sprite[i].picnum == BOMB) + { + sprite[i].z += sprite[i].zvel; + sprite[i].zvel += (TICSPERFRAME<<7); + if (sprite[i].z < globhiz+(tilesizy[BOMB]<<6)) + { + sprite[i].z = globhiz+(tilesizy[BOMB]<<6); + sprite[i].zvel = -(sprite[i].zvel>>1); + } + if (sprite[i].z > globloz-(tilesizy[BOMB]<<6)) + { + sprite[i].z = globloz-(tilesizy[BOMB]<<6); + sprite[i].zvel = -(sprite[i].zvel>>1); + } + dax = sprite[i].xvel; day = sprite[i].yvel; + dist = dax*dax+day*day; + if (dist < 512) + { + bombexplode(i); + goto bulletisdeletedskip; + } + if (dist < 4096) + { + sprite[i].xrepeat = ((4096+2048)*16) / (dist+2048); + sprite[i].yrepeat = sprite[i].xrepeat; + sprite[i].xoffset = (krand()&15)-8; + sprite[i].yoffset = (krand()&15)-8; + } + if (mulscale30(krand(),dist) == 0) + { + sprite[i].xvel -= ksgn(sprite[i].xvel); + sprite[i].yvel -= ksgn(sprite[i].yvel); + sprite[i].zvel -= ksgn(sprite[i].zvel); + } + } + + /* Check for bouncy objects before killing bullet */ + if ((hitobject&0xc000) == 16384) /* Bullet hit a ceiling/floor */ + { + k = sector[hitobject&(MAXSECTORS-1)].wallptr; l = wall[k].point2; + daang = getangle(wall[l].x-wall[k].x,wall[l].y-wall[k].y); + + getzsofslope(hitobject&(MAXSECTORS-1),sprite[i].x,sprite[i].y,&k,&l); + if (sprite[i].z < ((k+l)>>1)) k = sector[hitobject&(MAXSECTORS-1)].ceilingheinum; + else k = sector[hitobject&(MAXSECTORS-1)].floorheinum; + + dax = mulscale14(k,sintable[(daang)&2047]); + day = mulscale14(k,sintable[(daang+1536)&2047]); + daz = 4096; + + k = sprite[i].xvel*dax+sprite[i].yvel*day+mulscale4(sprite[i].zvel,daz); + l = dax*dax+day*day+daz*daz; + if ((klabs(k)>>14) < l) + { + k = divscale17(k,l); + sprite[i].xvel -= mulscale16(dax,k); + sprite[i].yvel -= mulscale16(day,k); + sprite[i].zvel -= mulscale12(daz,k); + } + wsayfollow("bouncy.wav",4096L+(krand()&127)-64,255,&sprite[i].x,&sprite[i].y,1); + hitobject = 0; + sprite[i].owner = -1; /* Bullet turns evil! */ + } + else if ((hitobject&0xc000) == 32768) /* Bullet hit a wall */ + { + if (wall[hitobject&4095].lotag == 8) + { + dax = sprite[i].xvel; day = sprite[i].yvel; + if ((sprite[i].picnum != BOMB) || (dax*dax+day*day >= 512)) + { + k = (hitobject&4095); l = wall[k].point2; + j = getangle(wall[l].x-wall[k].x,wall[l].y-wall[k].y)+512; + + /* k = cos(ang) * sin(ang) * 2 */ + k = mulscale13(sintable[(j+512)&2047],sintable[j&2047]); + /* l = cos(ang * 2) */ + l = sintable[((j<<1)+512)&2047]; + + ox = sprite[i].xvel; oy = sprite[i].yvel; + dax = -ox; day = -oy; + sprite[i].xvel = dmulscale14(day,k,dax,l); + sprite[i].yvel = dmulscale14(dax,k,-day,l); + + if (sprite[i].picnum == BOMB) + { + sprite[i].xvel -= (sprite[i].xvel>>3); + sprite[i].yvel -= (sprite[i].yvel>>3); + sprite[i].zvel -= (sprite[i].zvel>>3); + } + ox -= sprite[i].xvel; oy -= sprite[i].yvel; + dist = ((ox*ox+oy*oy)>>8); + wsayfollow("bouncy.wav",4096L+(krand()&127)-64,min(dist,256),&sprite[i].x,&sprite[i].y,1); + hitobject = 0; + sprite[i].owner = -1; /* Bullet turns evil! */ + } + } + } + else if ((hitobject&0xc000) == 49152) /* Bullet hit a sprite */ + { + if (sprite[hitobject&4095].picnum == BOUNCYMAT) + { + if ((sprite[hitobject&4095].cstat&48) == 0) + { + sprite[i].xvel = -sprite[i].xvel; + sprite[i].yvel = -sprite[i].yvel; + sprite[i].zvel = -sprite[i].zvel; + dist = 255; + } + else if ((sprite[hitobject&4095].cstat&48) == 16) + { + j = sprite[hitobject&4095].ang; + + /* k = cos(ang) * sin(ang) * 2 */ + k = mulscale13(sintable[(j+512)&2047],sintable[j&2047]); + /* l = cos(ang * 2) */ + l = sintable[((j<<1)+512)&2047]; + + ox = sprite[i].xvel; oy = sprite[i].yvel; + dax = -ox; day = -oy; + sprite[i].xvel = dmulscale14(day,k,dax,l); + sprite[i].yvel = dmulscale14(dax,k,-day,l); + + ox -= sprite[i].xvel; oy -= sprite[i].yvel; + dist = ((ox*ox+oy*oy)>>8); + } + sprite[i].owner = -1; /* Bullet turns evil! */ + wsayfollow("bouncy.wav",4096L+(krand()&127)-64,min(dist,256),&sprite[i].x,&sprite[i].y,1); + hitobject = 0; + } + } + + if (hitobject != 0) + { + if ((sprite[i].picnum == MISSILE) || (sprite[i].picnum == BOMB)) + { + if ((hitobject&0xc000) == 49152) + if (sprite[hitobject&4095].lotag == 5) /* Basketball hoop */ + { + wsayfollow("niceshot.wav",3840L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); + deletesprite((short)i); + goto bulletisdeletedskip; + } + + bombexplode(i); + goto bulletisdeletedskip; + } + + if ((hitobject&0xc000) == 16384) /* Hits a ceiling / floor */ + { + wsayfollow("bullseye.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); + deletesprite((short)i); + goto bulletisdeletedskip; + } + else if ((hitobject&0xc000) == 32768) /* Bullet hit a wall */ + { + if (wall[hitobject&4095].picnum == KENPICTURE) + { + if (waloff[MAXTILES-1] != 0) + wall[hitobject&4095].picnum = MAXTILES-1; + wsayfollow("hello.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); /* Ken says, "Hello... how are you today!" */ + } + else + wsayfollow("bullseye.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); + + deletesprite((short)i); + goto bulletisdeletedskip; + } + else if ((hitobject&0xc000) == 49152) /* Bullet hit a sprite */ + { + if ((sprite[hitobject&4095].lotag == 5) && (sprite[i].picnum == GRABBER)) { /* Basketball hoop (Andy's addition) */ + wsayfollow("niceshot.wav",3840L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); + switch (krand() & 63) { + case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: + sprite[i].picnum = COIN; break; + case 10: case 11: case 12: case 13: case 14: case 15: case 16: + sprite[i].picnum = DIAMONDS; break; + case 17: case 18: case 19: + sprite[i].picnum = COINSTACK; break; + case 20: case 21: case 22: case 23: + sprite[i].picnum = GIFTBOX; break; + case 24: case 25: + sprite[i].picnum = GRABCANNON; break; + case 26: case 27: + sprite[i].picnum = LAUNCHER; break; + case 28: case 29: case 30: + sprite[i].picnum = CANNON; break; + case 31: + sprite[i].picnum = AIRPLANE; break; + default: + deletesprite((short)i); + goto bulletisdeletedskip; + } + sprite[i].xvel = sprite[i].yvel = sprite[i].zvel = 0; + sprite[i].cstat &= ~0x83; /* Should not clip, foot-z */ + changespritestat(i,12); + goto bulletisdeletedskip; + } + + /* Check if bullet hit a player & find which player it was... */ + if (sprite[hitobject&4095].picnum == PLAYER) + for(j=connecthead;j>=0;j=connectpoint2[j]) + if (sprite[i].owner != j+4096) + if (playersprite[j] == (hitobject&4095)) + { + wsayfollow("ouch.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); + if (sprite[i].picnum == GRABBER) { /* Andy did this */ + k = ((sprite[i].xrepeat * sprite[i].yrepeat) * 3) >> 9; + changehealth((sprite[i].owner - 4096),k); + changehealth(j,-k); + } + else changehealth(j,-mulscale8(sprite[i].xrepeat,sprite[i].yrepeat)); + deletesprite((short)i); + goto bulletisdeletedskip; + } + + /* Check if bullet hit any monsters... */ + j = (hitobject&4095); /* j is the spritenum that the bullet (spritenum i) hit */ + if (sprite[i].owner != j) + { + switch(sprite[j].picnum) + { + case BROWNMONSTER: + if (sprite[j].lotag > 0) { + if (sprite[i].picnum == GRABBER) { /* Andy did this */ + k = ((sprite[i].xrepeat * sprite[i].yrepeat) * 3) >> 9; + changehealth((sprite[i].owner - 4096),k); + sprite[j].lotag -= k; + } + sprite[j].lotag -= mulscale8(sprite[i].xrepeat,sprite[i].yrepeat); + } + if (sprite[j].lotag > 0) + { + if (sprite[j].lotag <= 25) sprite[j].cstat |= 2; + wsayfollow("hurt.wav",4096L+(krand()&511)-256,256L,&sprite[i].x,&sprite[i].y,1); + } + else + { + wsayfollow("mondie.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); + sprite[j].z += ((tilesizy[sprite[j].picnum]*sprite[j].yrepeat)<<1); + sprite[j].picnum = GIFTBOX; + sprite[j].cstat &= ~0x83; /* Should not clip, foot-z */ + + spawnsprite(k,sprite[j].x,sprite[j].y,sprite[j].z, + 0,-4,0,32,64,64,0,0,EXPLOSION,sprite[j].ang, + 0,0,0,j,sprite[j].sectnum,5,31,0,0); + /* 31=Time left for explosion to stay */ + + changespritestat(j,12); + } + deletesprite((short)i); + goto bulletisdeletedskip; + case EVILAL: + wsayfollow("blowup.wav",5144L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); + sprite[j].picnum = EVILALGRAVE; + sprite[j].cstat = 0; + sprite[j].xvel = (krand()&255)-128; + sprite[j].yvel = (krand()&255)-128; + sprite[j].zvel = (krand()&4095)-3072; + changespritestat(j,9); + + deletesprite((short)i); + goto bulletisdeletedskip; + case AL: + wsayfollow("blowup.wav",5144L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); + sprite[j].xrepeat += 2; + sprite[j].yrepeat += 2; + if (sprite[j].yrepeat >= 38) + { + sprite[j].picnum = EVILAL; + #if 0 + sprite[j].cstat |= 2; /* Make him transluscent */ + #endif + changespritestat(j,10); + } + deletesprite((short)i); + goto bulletisdeletedskip; + default: + wsayfollow("bullseye.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); + deletesprite((short)i); + goto bulletisdeletedskip; + } + } + } + } + } +bulletisdeletedskip: continue; + } + + /* Go through monster waiting for you list */ + for(i=headspritestat[2];i>=0;i=nexti) + { + nexti = nextspritestat[i]; + + if ((nummoves-i)&15) continue; + + /* Use dot product to see if monster's angle is towards a player */ + for(p=connecthead;p>=0;p=connectpoint2[p]) + if (sintable[(sprite[i].ang+512)&2047]*(posx[p]-sprite[i].x) + sintable[sprite[i].ang&2047]*(posy[p]-sprite[i].y) >= 0) + if (cansee(sprite[i].x,sprite[i].y,sprite[i].z-(tilesizy[sprite[i].picnum]<<7),sprite[i].sectnum,posx[p],posy[p],posz[p],cursectnum[p]) == 1) + { + changespritestat(i,1); + #if 0 + if (sprite[i].lotag == 100) + { + wsayfollow("iseeyou.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,1); + sprite[i].lotag = 99; + } + #else + wsayfollow("iseeyou.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,1); + #endif + } + } + + /* Go through smoke sprites */ + for(i=headspritestat[3];i>=0;i=nexti) + { + nexti = nextspritestat[i]; + + sprite[i].z -= (TICSPERFRAME<<6); + sprite[i].lotag -= TICSPERFRAME; + if (sprite[i].lotag < 0) deletesprite(i); + } + + /* Go through splash sprites */ + for(i=headspritestat[4];i>=0;i=nexti) + { + nexti = nextspritestat[i]; + + sprite[i].lotag -= TICSPERFRAME; + sprite[i].picnum = SPLASH + ((63-sprite[i].lotag)>>4); + if (sprite[i].lotag < 0) deletesprite(i); + } + + /* Go through explosion sprites */ + for(i=headspritestat[5];i>=0;i=nexti) + { + nexti = nextspritestat[i]; + + sprite[i].lotag -= TICSPERFRAME; + if (sprite[i].lotag < 0) deletesprite(i); + } + + /* Go through bomb spriral-explosion sprites */ + for(i=headspritestat[7];i>=0;i=nexti) + { + nexti = nextspritestat[i]; + + sprite[i].xrepeat = (sprite[i].lotag>>2); + sprite[i].yrepeat = (sprite[i].lotag>>2); + sprite[i].lotag -= (TICSPERFRAME<<2); + if (sprite[i].lotag < 0) { deletesprite(i); continue; } + + if ((nummoves-i)&statrate[7]) continue; + + sprite[i].x += ((sprite[i].xvel*TICSPERFRAME)>>2); + sprite[i].y += ((sprite[i].yvel*TICSPERFRAME)>>2); + sprite[i].z += ((sprite[i].zvel*TICSPERFRAME)>>2); + + sprite[i].zvel += (TICSPERFRAME<<9); + if (sprite[i].z < sector[sprite[i].sectnum].ceilingz+(4<<8)) + { + sprite[i].z = sector[sprite[i].sectnum].ceilingz+(4<<8); + sprite[i].zvel = -(sprite[i].zvel>>1); + } + if (sprite[i].z > sector[sprite[i].sectnum].floorz-(4<<8)) + { + sprite[i].z = sector[sprite[i].sectnum].floorz-(4<<8); + sprite[i].zvel = -(sprite[i].zvel>>1); + } + } + + /* EVILALGRAVE shrinking list */ + for(i=headspritestat[9];i>=0;i=nexti) + { + nexti = nextspritestat[i]; + + sprite[i].xrepeat = (sprite[i].lotag>>2); + sprite[i].yrepeat = (sprite[i].lotag>>2); + sprite[i].lotag -= TICSPERFRAME; + if (sprite[i].lotag < 0) { deletesprite(i); continue; } + + if ((nummoves-i)&statrate[9]) continue; + + sprite[i].x += (sprite[i].xvel*TICSPERFRAME); + sprite[i].y += (sprite[i].yvel*TICSPERFRAME); + sprite[i].z += (sprite[i].zvel*TICSPERFRAME); + + sprite[i].zvel += (TICSPERFRAME<<8); + if (sprite[i].z < sector[sprite[i].sectnum].ceilingz) + { + sprite[i].z = sector[sprite[i].sectnum].ceilingz; + sprite[i].xvel -= (sprite[i].xvel>>2); + sprite[i].yvel -= (sprite[i].yvel>>2); + sprite[i].zvel = -(sprite[i].zvel>>1); + } + if (sprite[i].z > sector[sprite[i].sectnum].floorz) + { + sprite[i].z = sector[sprite[i].sectnum].floorz; + sprite[i].xvel -= (sprite[i].xvel>>2); + sprite[i].yvel -= (sprite[i].yvel>>2); + sprite[i].zvel = -(sprite[i].zvel>>1); + } + } + + /* Re-spawning sprite list */ + for(i=headspritestat[11];i>=0;i=nexti) + { + nexti = nextspritestat[i]; + + sprite[i].extra -= TICSPERFRAME; + if (sprite[i].extra < 0) + { + wsayfollow("warp.wav",6144L+(krand()&127)-64,128L,&sprite[i].x,&sprite[i].y,0); + sprite[i].cstat &= ~0x8000; + sprite[i].extra = -1; + changespritestat((short)i,0); + } + } +} + + +void checkmasterslaveswitch(void) +{ + long i, j; + + if (option[4] == 0) return; + + j = 0; + for(i=connecthead;i>=0;i=connectpoint2[i]) + if (_sync[i].bits&512) j++; + if (j != 1) return; + + i = connecthead; + for(j=connectpoint2[i];j>=0;j=connectpoint2[j]) + { + if (_sync[j].bits&512) + { + connectpoint2[i] = connectpoint2[j]; + connectpoint2[j] = connecthead; + connecthead = (short)j; + + oloc.fvel = loc.fvel+1; + oloc.svel = loc.svel+1; + oloc.avel = loc.avel+1; + oloc.bits = loc.bits+1; + for(i=0;i=0;i=connectpoint2[i]) + { + if (myconnectindex == i) break; + j++; + } + if (j == 1) + strcpy(getmessage,"Player 1 (Master)"); + else + sprintf(getmessage,"Player %ld (Slave)",j); + getmessageleng = strlen(getmessage); + getmessagetimeoff = totalclock+120; + + return; + } + i = j; + } +} + +static void domovethings(void) +{ + short i, j, startwall, endwall; + walltype *wal; + + nummoves++; + + for(i=connecthead;i>=0;i=connectpoint2[i]) + copybufbyte(&baksync[movefifoplc][i],&_sync[i],sizeof(input)); + movefifoplc = ((movefifoplc+1)&(MOVEFIFOSIZ-1)); + + if (option[4] != 0) + { + syncval[syncvalhead] = (char)(randomseed&255); + syncvalhead = ((syncvalhead+1)&(MOVEFIFOSIZ-1)); + } + + for(i=connecthead;i>=0;i=connectpoint2[i]) + { + oposx[i] = posx[i]; + oposy[i] = posy[i]; + oposz[i] = posz[i]; + ohoriz[i] = horiz[i]; + ozoom[i] = zoom[i]; + oang[i] = ang[i]; + } + + for(i=NUMSTATS-1;i>=0;i--) + if (statrate[i] >= 0) + for(j=headspritestat[i];j>=0;j=nextspritestat[j]) + if (((nummoves-j)&statrate[i]) == 0) + copybuf(&sprite[j].x,&osprite[j].x,3); + + for(i=connecthead;i>=0;i=connectpoint2[i]) + ocursectnum[i] = cursectnum[i]; + + updateinterpolations(); + + if ((numplayers <= 2) && (recstat == 1)) + { + j = 0; + for(i=connecthead;i>=0;i=connectpoint2[i]) + { + copybufbyte(&_sync[i],&recsync[reccnt][j],sizeof(input)); + j++; + } + reccnt++; if (reccnt > 16383) reccnt = 16383; + } + + lockclock += TICSPERFRAME; + drawstatusflytime(screenpeek); /* Andy did this */ + + if (cameradist >= 0) + { + cameradist = min(cameradist+((totalclock-cameraclock)<<10),65536); + if (keystatus[0x52]) /* 0 */ + cameraang -= ((totalclock-cameraclock)<<(2+(keystatus[0x2a]|keystatus[0x36]))); + if (keystatus[0x53]) /* . */ + cameraang += ((totalclock-cameraclock)<<(2+(keystatus[0x2a]|keystatus[0x36]))); + cameraclock = totalclock; + } + + for(i=connecthead;i>=0;i=connectpoint2[i]) + { + processinput(i); /* Move player */ + + checktouchsprite(i,cursectnum[i]); /* Pick up coins */ + startwall = sector[cursectnum[i]].wallptr; + endwall = startwall + sector[cursectnum[i]].wallnum; + for(j=startwall,wal=&wall[j];jnextsector >= 0) checktouchsprite(i,wal->nextsector); + } + + doanimations(); + tagcode(); /* Door code, moving sector code, other stuff */ + statuslistcode(); /* Monster / bullet code / explosions */ + + fakedomovethingscorrect(); + + checkmasterslaveswitch(); +} + + +void getpackets(void) +{ + long i, j, k, l; + short other, packbufleng, movecnt; + + if (option[4] == 0) return; + + movecnt = 0; + while ((packbufleng = getpacket(&other,packbuf)) > 0) + { + switch(packbuf[0]) + { + case 0: /* [0] (receive master sync buffer) */ + j = ((numplayers+1)>>1)+1; k = (1<<3); + for(i=connecthead;i>=0;i=connectpoint2[i]) + { + l = (packbuf[k>>3]>>(k&7)); + if (l&1) ffsync[i].fvel = packbuf[j++]; + if (l&2) ffsync[i].svel = packbuf[j++]; + if (l&4) ffsync[i].avel = packbuf[j++]; + if (l&8) + { + ffsync[i].bits = ((short)packbuf[j])+(((short)packbuf[j+1])<<8); + j += 2; + } + k += 4; + } + + while (j != packbufleng) + { + othersyncval[othersyncvalhead] = packbuf[j++]; + othersyncvalhead = ((othersyncvalhead+1)&(MOVEFIFOSIZ-1)); + } + if ((syncvalhead != syncvaltottail) && (othersyncvalhead != syncvaltottail)) + { + syncstat = 0; + do + { + syncstat |= (syncval[syncvaltottail]^othersyncval[syncvaltottail]); + syncvaltottail = ((syncvaltottail+1)&(MOVEFIFOSIZ-1)); + } while ((syncvalhead != syncvaltottail) && (othersyncvalhead != syncvaltottail)); + } + + movethings(); /* Move all players and sprites */ + movecnt++; + break; + case 1: /* [1] (receive slave sync buffer) */ + j = 2; k = packbuf[1]; + if (k&1) ffsync[other].fvel = packbuf[j++]; + if (k&2) ffsync[other].svel = packbuf[j++]; + if (k&4) ffsync[other].avel = packbuf[j++]; + if (k&8) ffsync[other].bits = ((ffsync[other].bits&0xff00)|((short)packbuf[j++])); + if (k&16) ffsync[other].bits = ((ffsync[other].bits&0x00ff)|(((short)packbuf[j++])<<8)); + break; + case 2: + getmessageleng = packbufleng-1; + for(j=getmessageleng-1;j>=0;j--) getmessage[j] = packbuf[j+1]; + getmessagetimeoff = totalclock+360+(getmessageleng<<4); + break; + case 3: + wsay("getstuff.wav",4096L,63L,63L); + break; + case 5: + playerreadyflag[other] = packbuf[1]; + if ((other == connecthead) && (packbuf[1] == 2)) + sendpacket(connecthead,(unsigned char *) packbuf,2); + break; + case 17: + j = 3; k = packbuf[2]; + if (k&1) ffsync[other].fvel = packbuf[j++]; + if (k&2) ffsync[other].svel = packbuf[j++]; + if (k&4) ffsync[other].avel = packbuf[j++]; + if (k&8) ffsync[other].bits = ((ffsync[other].bits&0xff00)|((short)packbuf[j++])); + if (k&16) ffsync[other].bits = ((ffsync[other].bits&0x00ff)|(((short)packbuf[j++])<<8)); + otherlag[other] = packbuf[1]; + + copybufbyte(&ffsync[other],&baksync[movefifoend[other]][other],sizeof(input)); + movefifoend[other] = ((movefifoend[other]+1)&(MOVEFIFOSIZ-1)); + + while (j != packbufleng) + { + othersyncval[othersyncvalhead] = packbuf[j++]; + othersyncvalhead = ((othersyncvalhead+1)&(MOVEFIFOSIZ-1)); + } + if ((syncvalhead != syncvaltottail) && (othersyncvalhead != syncvaltottail)) + { + syncstat = 0; + do + { + syncstat |= (syncval[syncvaltottail]^othersyncval[syncvaltottail]); + syncvaltottail = ((syncvaltottail+1)&(MOVEFIFOSIZ-1)); + } while ((syncvalhead != syncvaltottail) && (othersyncvalhead != syncvaltottail)); + } + + break; + case 255: /* [255] (logout) */ + keystatus[1] = 1; + break; + } + } + if ((networkmode == 0) && (myconnectindex != connecthead) && ((movecnt&1) == 0)) + { + if (rand()&1) ototalclock += (TICSPERFRAME>>1); + else ototalclock -= (TICSPERFRAME>>1); + } +} + + +void initplayersprite(short snum) +{ + long i; + + if (playersprite[snum] >= 0) return; + + spawnsprite(playersprite[snum],posx[snum],posy[snum],posz[snum]+EYEHEIGHT, + 1+256,0,snum,32,64,64,0,0,PLAYER,ang[snum],0,0,0,snum+4096, + cursectnum[snum],8,0,0,0); + + switch(snum) + { + case 1: for(i=0;i<32;i++) tempbuf[i+192] = i+128; break; /* green->red */ + case 2: for(i=0;i<32;i++) tempbuf[i+192] = i+32; break; /* green->blue */ + case 3: for(i=0;i<32;i++) tempbuf[i+192] = i+224; break; /* green->pink */ + case 4: for(i=0;i<32;i++) tempbuf[i+192] = i+64; break; /* green->brown */ + case 5: for(i=0;i<32;i++) tempbuf[i+192] = i+96; break; + case 6: for(i=0;i<32;i++) tempbuf[i+192] = i+160; break; + case 7: for(i=0;i<32;i++) tempbuf[i+192] = i+192; break; + default: for(i=0;i<256;i++) tempbuf[i] = i; break; + } + makepalookup(snum,tempbuf,0,0,0,1); +} + + +#define MAXVOXMIPS 5 +extern char *voxoff[][MAXVOXMIPS]; +void analyzesprites(long dax, long day) +{ + long i, j=0, k, *longptr; + point3d *ospr; + spritetype *tspr; + + /* + * This function is called between drawrooms() and drawmasks() + * It has a list of possible sprites that may be drawn on this frame + */ + for(i=0,tspr=&tsprite[0];ipicnum) + { + case PLAYER: + /* Get which of the 8 angles of the sprite to draw (0-7) */ + /* k ranges from 0-7 */ + #if 0 + k = getangle(tspr->x-dax,tspr->y-day); + k = (((tspr->ang+3072+128-k)&2047)>>8)&7; + + /* This guy has only 5 pictures for 8 angles (3 are x-flipped) */ + if (k <= 4) + { + tspr->picnum += (k<<2); + tspr->cstat &= ~4; /* clear x-flipping bit */ + } + else + { + tspr->picnum += ((8-k)<<2); + tspr->cstat |= 4; /* set x-flipping bit */ + } + #endif + + if ((tspr->cstat&2) == 0) + { + tspr->cstat |= 48; + longptr = (long *)voxoff[0][0]; + tspr->xrepeat = scale(tspr->xrepeat,56,longptr[2]); + tspr->yrepeat = scale(tspr->yrepeat,56,longptr[2]); + tspr->picnum = 0; + tspr->shade -= 6; + } + break; + case BROWNMONSTER: + tspr->cstat |= 48; + tspr->picnum = 1; + break; + } + + k = statrate[tspr->statnum]; + if (k >= 0) /* Interpolate moving sprite */ + { + ospr = &osprite[tspr->owner]; + switch(k) + { + case 0: j = smoothratio; break; + case 1: j = (smoothratio>>1)+(((nummoves-tspr->owner)&1)<<15); break; + case 3: j = (smoothratio>>2)+(((nummoves-tspr->owner)&3)<<14); break; + case 7: j = (smoothratio>>3)+(((nummoves-tspr->owner)&7)<<13); break; + case 15: j = (smoothratio>>4)+(((nummoves-tspr->owner)&15)<<12); break; + } + k = tspr->x-ospr->x; tspr->x = ospr->x; + if (k != 0) tspr->x += mulscale16(k,j); + k = tspr->y-ospr->y; tspr->y = ospr->y; + if (k != 0) tspr->y += mulscale16(k,j); + k = tspr->z-ospr->z; tspr->z = ospr->z; + if (k != 0) tspr->z += mulscale16(k,j); + } + + /* Don't allow close explosion sprites to be transluscent */ + k = tspr->statnum; + if ((k == 3) || (k == 4) || (k == 5) || (k == 7)) + if (klabs(dax-tspr->x) < 256) + if (klabs(day-tspr->y) < 256) + tspr->cstat &= ~2; + + tspr->shade += 6; + if (sector[tspr->sectnum].ceilingstat&1) + tspr->shade += sector[tspr->sectnum].ceilingshade; + else + tspr->shade += sector[tspr->sectnum].floorshade; + } +} + + +void updatesectorz(long x, long y, long z, short *sectnum) +{ + walltype *wal; + long i, j, cz, fz; + + getzsofslope(*sectnum,x,y,&cz,&fz); + if ((z >= cz) && (z <= fz)) + if (inside(x,y,*sectnum) != 0) return; + + if ((*sectnum >= 0) && (*sectnum < numsectors)) + { + wal = &wall[sector[*sectnum].wallptr]; + j = sector[*sectnum].wallnum; + do + { + i = wal->nextsector; + if (i >= 0) + { + getzsofslope(i,x,y,&cz,&fz); + if ((z >= cz) && (z <= fz)) + if (inside(x,y,(short)i) == 1) + { *sectnum = i; return; } + } + wal++; j--; + } while (j != 0); + } + + for(i=numsectors-1;i>=0;i--) + { + getzsofslope(i,x,y,&cz,&fz); + if ((z >= cz) && (z <= fz)) + if (inside(x,y,(short)i) == 1) + { *sectnum = i; return; } + } + + *sectnum = -1; +} + + +static void view(short snum, long *vx, long *vy, long *vz, + short *vsectnum, short ang, long horiz) +{ + spritetype *sp; + long i, nx, ny, nz, hx, hy, hitx, hity, hitz; + short bakcstat, hitsect, hitwall, hitsprite, daang; + + nx = (sintable[(ang+1536)&2047]>>4); + ny = (sintable[(ang+1024)&2047]>>4); + nz = (horiz-100)*128; + + sp = &sprite[snum]; + + bakcstat = sp->cstat; + sp->cstat &= (short)~0x101; + + updatesectorz(*vx,*vy,*vz,vsectnum); + hitscan(*vx,*vy,*vz,*vsectnum,nx,ny,nz,&hitsect,&hitwall,&hitsprite,&hitx,&hity,&hitz,CLIPMASK1); + hx = hitx-(*vx); hy = hity-(*vy); + if (klabs(nx)+klabs(ny) > klabs(hx)+klabs(hy)) + { + *vsectnum = hitsect; + if (hitwall >= 0) + { + daang = getangle(wall[wall[hitwall].point2].x-wall[hitwall].x, + wall[wall[hitwall].point2].y-wall[hitwall].y); + + i = nx*sintable[daang]+ny*sintable[(daang+1536)&2047]; + if (klabs(nx) > klabs(ny)) hx -= mulscale28(nx,i); + else hy -= mulscale28(ny,i); + } + else if (hitsprite < 0) + { + if (klabs(nx) > klabs(ny)) hx -= (nx>>5); + else hy -= (ny>>5); + } + if (klabs(nx) > klabs(ny)) i = divscale16(hx,nx); + else i = divscale16(hy,ny); + if (i < cameradist) cameradist = i; + } + *vx = (*vx)+mulscale16(nx,cameradist); + *vy = (*vy)+mulscale16(ny,cameradist); + *vz = (*vz)+mulscale16(nz,cameradist); + + updatesectorz(*vx,*vy,*vz,vsectnum); + + sp->cstat = bakcstat; +} + + +void drawoverheadmap(long cposx, long cposy, long czoom, short cang) +{ + long i, j, k, l=0, x1, y1, x2=0, y2=0, x3, y3, x4, y4, ox, oy, xoff, yoff; + long dax, day, cosang, sinang, xspan, yspan, sprx, spry; + long xrepeat, yrepeat, z1, z2, startwall, endwall, tilenum, daang; + long xvect, yvect, xvect2, yvect2; + char col; + walltype *wal, *wal2; + spritetype *spr; + + xvect = sintable[(-cang)&2047] * czoom; + yvect = sintable[(1536-cang)&2047] * czoom; + xvect2 = mulscale16(xvect,yxaspect); + yvect2 = mulscale16(yvect,yxaspect); + + /* Draw red lines */ + for(i=0;inextwall; if (k < 0) continue; + + if ((show2dwall[j>>3]&(1<<(j&7))) == 0) continue; + if ((k > j) && ((show2dwall[k>>3]&(1<<(k&7))) > 0)) continue; + + if (sector[wal->nextsector].ceilingz == z1) + if (sector[wal->nextsector].floorz == z2) + if (((wal->cstat|wall[wal->nextwall].cstat)&(16+32)) == 0) continue; + + col = 152; + + if (dimensionmode[screenpeek] == 2) + { + if (sector[i].floorz != sector[i].ceilingz) + if (sector[wal->nextsector].floorz != sector[wal->nextsector].ceilingz) + if (((wal->cstat|wall[wal->nextwall].cstat)&(16+32)) == 0) + if (sector[i].floorz == sector[wal->nextsector].floorz) continue; + if (sector[i].floorpicnum != sector[wal->nextsector].floorpicnum) continue; + if (sector[i].floorshade != sector[wal->nextsector].floorshade) continue; + col = 12; + } + + ox = wal->x-cposx; oy = wal->y-cposy; + x1 = dmulscale16(ox,xvect,-oy,yvect)+(xdim<<11); + y1 = dmulscale16(oy,xvect2,ox,yvect2)+(ydim<<11); + + wal2 = &wall[wal->point2]; + ox = wal2->x-cposx; oy = wal2->y-cposy; + x2 = dmulscale16(ox,xvect,-oy,yvect)+(xdim<<11); + y2 = dmulscale16(oy,xvect2,ox,yvect2)+(ydim<<11); + + drawline256(x1,y1,x2,y2,col); + } + } + + /* Draw sprites */ + k = playersprite[screenpeek]; + for(i=0;i=0;j=nextspritesect[j]) + if ((show2dsprite[j>>3]&(1<<(j&7))) > 0) + { + spr = &sprite[j]; if (spr->cstat&0x8000) continue; + col = 56; + if (spr->cstat&1) col = 248; + if (j == k) col = 31; + + k = statrate[spr->statnum]; + sprx = spr->x; + spry = spr->y; + if (k >= 0) + { + switch(k) + { + case 0: l = smoothratio; break; + case 1: l = (smoothratio>>1)+(((nummoves-j)&1)<<15); break; + case 3: l = (smoothratio>>2)+(((nummoves-j)&3)<<14); break; + case 7: l = (smoothratio>>3)+(((nummoves-j)&7)<<13); break; + case 15: l = (smoothratio>>4)+(((nummoves-j)&15)<<12); break; + } + sprx = osprite[j].x+mulscale16(sprx-osprite[j].x,l); + spry = osprite[j].y+mulscale16(spry-osprite[j].y,l); + } + + switch (spr->cstat&48) + { + case 0: + ox = sprx-cposx; oy = spry-cposy; + x1 = dmulscale16(ox,xvect,-oy,yvect); + y1 = dmulscale16(oy,xvect2,ox,yvect2); + + if (dimensionmode[screenpeek] == 1) + { + ox = (sintable[(spr->ang+512)&2047]>>7); + oy = (sintable[(spr->ang)&2047]>>7); + x2 = dmulscale16(ox,xvect,-oy,yvect); + y2 = dmulscale16(oy,xvect,ox,yvect); + + if (j == playersprite[screenpeek]) + { + x2 = 0L; + y2 = -(czoom<<5); + } + + x3 = mulscale16(x2,yxaspect); + y3 = mulscale16(y2,yxaspect); + + drawline256(x1-x2+(xdim<<11),y1-y3+(ydim<<11), + x1+x2+(xdim<<11),y1+y3+(ydim<<11),col); + drawline256(x1-y2+(xdim<<11),y1+x3+(ydim<<11), + x1+x2+(xdim<<11),y1+y3+(ydim<<11),col); + drawline256(x1+y2+(xdim<<11),y1-x3+(ydim<<11), + x1+x2+(xdim<<11),y1+y3+(ydim<<11),col); + } + else + { + if (((gotsector[i>>3]&(1<<(i&7))) > 0) && (czoom > 96)) + { + daang = (spr->ang-cang)&2047; + if (j == playersprite[screenpeek]) { x1 = 0; y1 = 0; daang = 0; } + rotatesprite((x1<<4)+(xdim<<15),(y1<<4)+(ydim<<15),mulscale16(czoom*spr->yrepeat,yxaspect),daang,spr->picnum,spr->shade,spr->pal,(spr->cstat&2)>>1,windowx1,windowy1,windowx2,windowy2); + } + } + break; + case 16: + x1 = sprx; y1 = spry; + tilenum = spr->picnum; + xoff = (long)((signed char)((picanm[tilenum]>>8)&255))+((long)spr->xoffset); + if ((spr->cstat&4) > 0) xoff = -xoff; + k = spr->ang; l = spr->xrepeat; + dax = sintable[k&2047]*l; day = sintable[(k+1536)&2047]*l; + l = tilesizx[tilenum]; k = (l>>1)+xoff; + x1 -= mulscale16(dax,k); x2 = x1+mulscale16(dax,l); + y1 -= mulscale16(day,k); y2 = y1+mulscale16(day,l); + + ox = x1-cposx; oy = y1-cposy; + x1 = dmulscale16(ox,xvect,-oy,yvect); + y1 = dmulscale16(oy,xvect2,ox,yvect2); + + ox = x2-cposx; oy = y2-cposy; + x2 = dmulscale16(ox,xvect,-oy,yvect); + y2 = dmulscale16(oy,xvect2,ox,yvect2); + + drawline256(x1+(xdim<<11),y1+(ydim<<11), + x2+(xdim<<11),y2+(ydim<<11),col); + + break; + case 32: + if (dimensionmode[screenpeek] == 1) + { + tilenum = spr->picnum; + xoff = (long)((signed char)((picanm[tilenum]>>8)&255))+((long)spr->xoffset); + yoff = (long)((signed char)((picanm[tilenum]>>16)&255))+((long)spr->yoffset); + if ((spr->cstat&4) > 0) xoff = -xoff; + if ((spr->cstat&8) > 0) yoff = -yoff; + + k = spr->ang; + cosang = sintable[(k+512)&2047]; sinang = sintable[k]; + xspan = tilesizx[tilenum]; xrepeat = spr->xrepeat; + yspan = tilesizy[tilenum]; yrepeat = spr->yrepeat; + + dax = ((xspan>>1)+xoff)*xrepeat; day = ((yspan>>1)+yoff)*yrepeat; + x1 = sprx + dmulscale16(sinang,dax,cosang,day); + y1 = spry + dmulscale16(sinang,day,-cosang,dax); + l = xspan*xrepeat; + x2 = x1 - mulscale16(sinang,l); + y2 = y1 + mulscale16(cosang,l); + l = yspan*yrepeat; + k = -mulscale16(cosang,l); x3 = x2+k; x4 = x1+k; + k = -mulscale16(sinang,l); y3 = y2+k; y4 = y1+k; + + ox = x1-cposx; oy = y1-cposy; + x1 = dmulscale16(ox,xvect,-oy,yvect); + y1 = dmulscale16(oy,xvect2,ox,yvect2); + + ox = x2-cposx; oy = y2-cposy; + x2 = dmulscale16(ox,xvect,-oy,yvect); + y2 = dmulscale16(oy,xvect2,ox,yvect2); + + ox = x3-cposx; oy = y3-cposy; + x3 = dmulscale16(ox,xvect,-oy,yvect); + y3 = dmulscale16(oy,xvect2,ox,yvect2); + + ox = x4-cposx; oy = y4-cposy; + x4 = dmulscale16(ox,xvect,-oy,yvect); + y4 = dmulscale16(oy,xvect2,ox,yvect2); + + drawline256(x1+(xdim<<11),y1+(ydim<<11), + x2+(xdim<<11),y2+(ydim<<11),col); + + drawline256(x2+(xdim<<11),y2+(ydim<<11), + x3+(xdim<<11),y3+(ydim<<11),col); + + drawline256(x3+(xdim<<11),y3+(ydim<<11), + x4+(xdim<<11),y4+(ydim<<11),col); + + drawline256(x4+(xdim<<11),y4+(ydim<<11), + x1+(xdim<<11),y1+(ydim<<11),col); + + } + break; + } + } + + /* Draw white lines */ + for(i=0;inextwall >= 0) continue; + + if ((show2dwall[j>>3]&(1<<(j&7))) == 0) continue; + + if (tilesizx[wal->picnum] == 0) continue; + if (tilesizy[wal->picnum] == 0) continue; + + if (j == k) + { x1 = x2; y1 = y2; } + else + { + ox = wal->x-cposx; oy = wal->y-cposy; + x1 = dmulscale16(ox,xvect,-oy,yvect)+(xdim<<11); + y1 = dmulscale16(oy,xvect2,ox,yvect2)+(ydim<<11); + } + + k = wal->point2; wal2 = &wall[k]; + ox = wal2->x-cposx; oy = wal2->y-cposy; + x2 = dmulscale16(ox,xvect,-oy,yvect)+(xdim<<11); + y2 = dmulscale16(oy,xvect2,ox,yvect2)+(ydim<<11); + + drawline256(x1,y1,x2,y2,24); + } + } +} + + +void drawscreen(short snum, long dasmoothratio) +{ + long i, j, k=0, l, charsperline, templong; + long x1, y1, x2, y2, ox1, oy1, ox2, oy2, dist, maxdist; + long cposx, cposy, cposz, choriz, czoom, tposx, tposy; + long tiltlock, *longptr, ovisibility, oparallaxvisibility; + short cang, tang, csect; + char ch, *ptr, *ptr2, *ptr3, *ptr4; + spritetype *tspr; + + smoothratio = max(min(dasmoothratio,65536),0); + + dointerpolations(); + + if ((snum == myconnectindex) && ((networkmode == 1) || (myconnectindex != connecthead))) + { + cposx = omyx+mulscale16(myx-omyx,smoothratio); + cposy = omyy+mulscale16(myy-omyy,smoothratio); + cposz = omyz+mulscale16(myz-omyz,smoothratio); + choriz = omyhoriz+mulscale16(myhoriz-omyhoriz,smoothratio); + cang = omyang+mulscale16((long)(((myang+1024-omyang)&2047)-1024),smoothratio); + } + else + { + cposx = oposx[snum]+mulscale16(posx[snum]-oposx[snum],smoothratio); + cposy = oposy[snum]+mulscale16(posy[snum]-oposy[snum],smoothratio); + cposz = oposz[snum]+mulscale16(posz[snum]-oposz[snum],smoothratio); + choriz = ohoriz[snum]+mulscale16(horiz[snum]-ohoriz[snum],smoothratio); + cang = oang[snum]+mulscale16(((ang[snum]+1024-oang[snum])&2047)-1024,smoothratio); + } + czoom = ozoom[snum]+mulscale16(zoom[snum]-ozoom[snum],smoothratio); + + setears(cposx,cposy,(long)sintable[(cang+512)&2047]<<14,(long)sintable[cang&2047]<<14); + + if (typemode != 0) + { + charsperline = 40; + /*if (dimensionmode[snum] == 2) charsperline = 80;*/ + + for(i=0;i<=typemessageleng;i+=charsperline) + { + for(j=0;j (screensizeflag&32)) && (screensize > 64)) + { + ox1 = ((xdim-screensize)>>1); + ox2 = ox1+screensize-1; + oy1 = (((ydim-32)-scale(screensize,ydim-32,xdim))>>1); + oy2 = oy1 + scale(screensize,ydim-32,xdim)-1; + screensize -= (screensize>>3); + + if (templong > xdim) + { + screensize = xdim; + + flushperms(); + + rotatesprite((xdim-320)<<15,(ydim-32)<<16,65536L,0,STATUSBAR,0,0,8+16+64+128,0L,0L,xdim-1L,ydim-1L); + i = ((xdim-320)>>1); + while (i >= 8) i -= 8, rotatesprite(i<<16,(ydim-32)<<16,65536L,0,STATUSBARFILL8,0,0,8+16+64+128,0L,0L,xdim-1L,ydim-1L); + if (i >= 4) i -= 4, rotatesprite(i<<16,(ydim-32)<<16,65536L,0,STATUSBARFILL4,0,0,8+16+64+128,0L,0L,xdim-1L,ydim-1L); + i = ((xdim-320)>>1)+320; + while (i <= xdim-8) rotatesprite(i<<16,(ydim-32)<<16,65536L,0,STATUSBARFILL8,0,0,8+16+64+128,0L,0L,xdim-1L,ydim-1L), i += 8; + if (i <= xdim-4) rotatesprite(i<<16,(ydim-32)<<16,65536L,0,STATUSBARFILL4,0,0,8+16+64+128,0L,0L,xdim-1L,ydim-1L), i += 4; + + drawstatusbar(screenpeek); /* Andy did this */ + } + + x1 = ((xdim-screensize)>>1); + x2 = x1+screensize-1; + y1 = (((ydim-32)-scale(screensize,ydim-32,xdim))>>1); + y2 = y1 + scale(screensize,ydim-32,xdim)-1; + setview(x1,y1,x2,y2); + + /* + * (ox1,oy1)ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ + * ³ (x1,y1) ³ + * ³ ÚÄÄÄÄÄ¿ ³ + * ³ ³ ³ ³ + * ³ ÀÄÄÄÄÄÙ ³ + * ³ (x2,y2) ³ + * ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ(ox2,oy2) + */ + + drawtilebackground(0L,0L,BACKGROUND,8,ox1,oy1,x1-1,oy2,0); + drawtilebackground(0L,0L,BACKGROUND,8,x2+1,oy1,ox2,oy2,0); + drawtilebackground(0L,0L,BACKGROUND,8,x1,oy1,x2,y1-1,0); + drawtilebackground(0L,0L,BACKGROUND,8,x1,y2+1,x2,oy2,0); + } + if (((loc.bits&16) > (screensizeflag&16)) && (screensize <= xdim)) + { + screensize += (screensize>>3); + if ((screensize > xdim) && (templong == xdim)) + { + screensize = xdim+1; + x1 = 0; y1 = 0; + x2 = xdim-1; y2 = ydim-1; + } + else + { + if (screensize > xdim) screensize = xdim; + x1 = ((xdim-screensize)>>1); + x2 = x1+screensize-1; + y1 = (((ydim-32)-scale(screensize,ydim-32,xdim))>>1); + y2 = y1 + scale(screensize,ydim-32,xdim)-1; + } + setview(x1,y1,x2,y2); + } + screensizeflag = loc.bits; + } + } + + if (dimensionmode[snum] != 2) + { + if ((numplayers > 1) && (option[4] == 0)) + { + /* + * Do not draw other views constantly if they're staying still + * It's a shame this trick will only work in screen-buffer mode + * At least screen-buffer mode covers all the HI hi-res modes + */ + if (vidoption == 2) + { + for(i=connecthead;i>=0;i=connectpoint2[i]) frame2draw[i] = 0; + frame2draw[snum] = 1; + + /* 2-1,3-1,4-2 */ + /* 5-2,6-2,7-2,8-3,9-3,10-3,11-3,12-4,13-4,14-4,15-4,16-5 */ + x1 = posx[snum]; y1 = posy[snum]; + for(j=(numplayers>>2)+1;j>0;j--) + { + maxdist = 0x80000000; + for(i=connecthead;i>=0;i=connectpoint2[i]) + if (frame2draw[i] == 0) + { + x2 = posx[i]-x1; y2 = posy[i]-y1; + dist = dmulscale12(x2,x2,y2,y2); + + if (dist < 64) dist = 16384; + else if (dist > 16384) dist = 64; + else dist = 1048576 / dist; + + dist *= frameskipcnt[i]; + + /* Increase frame rate if screen is moving */ + if ((posx[i] != oposx[i]) || (posy[i] != oposy[i]) || + (posz[i] != oposz[i]) || (ang[i] != oang[i]) || + (horiz[i] != ohoriz[i])) dist += dist; + + if (dist > maxdist) maxdist = dist, k = i; + } + + for(i=connecthead;i>=0;i=connectpoint2[i]) + frameskipcnt[i] += (frameskipcnt[i]>>3)+1; + frameskipcnt[k] = 0; + + frame2draw[k] = 1; + } + } + else + { + for(i=connecthead;i>=0;i=connectpoint2[i]) frame2draw[i] = 1; + } + + for(i=connecthead,j=0;i>=0;i=connectpoint2[i],j++) + if (frame2draw[i] != 0) + { + if (numplayers <= 4) + { + switch(j) + { + case 0: setview(0,0,(xdim>>1)-1,(ydim>>1)-1); break; + case 1: setview((xdim>>1),0,xdim-1,(ydim>>1)-1); break; + case 2: setview(0,(ydim>>1),(xdim>>1)-1,ydim-1); break; + case 3: setview((xdim>>1),(ydim>>1),xdim-1,ydim-1); break; + } + } + else + { + switch(j) + { + case 0: setview(0,0,(xdim>>2)-1,(ydim>>2)-1); break; + case 1: setview(xdim>>2,0,(xdim>>1)-1,(ydim>>2)-1); break; + case 2: setview(xdim>>1,0,xdim-(xdim>>2)-1,(ydim>>2)-1); break; + case 3: setview(xdim-(xdim>>2),0,xdim-1,(ydim>>2)-1); break; + case 4: setview(0,ydim>>2,(xdim>>2)-1,(ydim>>1)-1); break; + case 5: setview(xdim>>2,ydim>>2,(xdim>>1)-1,(ydim>>1)-1); break; + case 6: setview(xdim>>1,ydim>>2,xdim-(xdim>>2)-1,(ydim>>1)-1); break; + case 7: setview(xdim-(xdim>>2),ydim>>2,xdim-1,(ydim>>1)-1); break; + case 8: setview(0,ydim>>1,(xdim>>2)-1,ydim-(ydim>>2)-1); break; + case 9: setview(xdim>>2,ydim>>1,(xdim>>1)-1,ydim-(ydim>>2)-1); break; + case 10: setview(xdim>>1,ydim>>1,xdim-(xdim>>2)-1,ydim-(ydim>>2)-1); break; + case 11: setview(xdim-(xdim>>2),ydim>>1,xdim-1,ydim-(ydim>>2)-1); break; + case 12: setview(0,ydim-(ydim>>2),(xdim>>2)-1,ydim-1); break; + case 13: setview(xdim>>2,ydim-(ydim>>2),(xdim>>1)-1,ydim-1); break; + case 14: setview(xdim>>1,ydim-(ydim>>2),xdim-(xdim>>2)-1,ydim-1); break; + case 15: setview(xdim-(xdim>>2),ydim-(ydim>>2),xdim-1,ydim-1); break; + } + } + + if (i == snum) + { + sprite[playersprite[snum]].cstat |= 0x8000; + drawrooms(cposx,cposy,cposz,cang,choriz,cursectnum[i]); + sprite[playersprite[snum]].cstat &= ~0x8000; + analyzesprites(cposx,cposy); + } + else + { + sprite[playersprite[i]].cstat |= 0x8000; + drawrooms(posx[i],posy[i],posz[i],ang[i],horiz[i],cursectnum[i]); + sprite[playersprite[i]].cstat &= ~0x8000; + analyzesprites(posx[i],posy[i]); + } + drawmasks(); + if ((numgrabbers[i] > 0) || (nummissiles[i] > 0) || (numbombs[i] > 0)) + rotatesprite(160<<16,184L<<16,65536,0,GUNONBOTTOM,sector[cursectnum[i]].floorshade,0,2,windowx1,windowy1,windowx2,windowy2); + + if (lockclock < 384) + { + if (lockclock < 128) + rotatesprite(320<<15,200<<15,lockclock<<9,lockclock<<4,DEMOSIGN,(128-lockclock)>>2,0,1+2,windowx1,windowy1,windowx2,windowy2); + else if (lockclock < 256) + rotatesprite(320<<15,200<<15,65536,0,DEMOSIGN,0,0,2,windowx1,windowy1,windowx2,windowy2); + else + rotatesprite(320<<15,200<<15,(384-lockclock)<<9,lockclock<<4,DEMOSIGN,(lockclock-256)>>2,0,1+2,windowx1,windowy1,windowx2,windowy2); + } + + if (health[i] <= 0) + rotatesprite(320<<15,200<<15,(-health[i])<<11,(-health[i])<<5,NO,0,0,2,windowx1,windowy1,windowx2,windowy2); + } + } + else + { + /* Init for screen rotation */ + tiltlock = screentilt; + if ((tiltlock) || (detailmode)) + { + walock[MAXTILES-2] = 255; + if (waloff[MAXTILES-2] == 0) + allocache(&waloff[MAXTILES-2],320L*320L,(unsigned char *)&walock[MAXTILES-2]); + if ((tiltlock&1023) == 0) + setviewtotile(MAXTILES-2,200L>>detailmode,320L>>detailmode); + else + setviewtotile(MAXTILES-2,320L>>detailmode,320L>>detailmode); + if ((tiltlock&1023) == 512) + { /* Block off unscreen section of 90ø tilted screen */ + j = ((320-60)>>detailmode); + for(i=(60>>detailmode)-1;i>=0;i--) + { + startumost[i] = 1; startumost[i+j] = 1; + startdmost[i] = 0; startdmost[i+j] = 0; + } + } + + i = (tiltlock&511); if (i > 256) i = 512-i; + i = sintable[i+512]*8 + sintable[i]*5L; + setaspect(i>>1,yxaspect); + } + + if ((gotpic[FLOORMIRROR>>3]&(1<<(FLOORMIRROR&7))) > 0) + { + dist = 0x7fffffff; i = 0; + for(k=floormirrorcnt-1;k>=0;k--) + { + j = klabs(wall[sector[floormirrorsector[k]].wallptr].x-cposx); + j += klabs(wall[sector[floormirrorsector[k]].wallptr].y-cposy); + if (j < dist) dist = j, i = k; + } + + j = floormirrorsector[i]; + + if (cameradist < 0) sprite[playersprite[snum]].cstat |= 0x8000; + drawrooms(cposx,cposy,(sector[j].floorz<<1)-cposz,cang,201-choriz,j); + sprite[playersprite[snum]].cstat &= ~0x8000; + analyzesprites(cposx,cposy); + drawmasks(); + + /* Temp horizon */ + l = scale(choriz-100,windowx2-windowx1,320)+((windowy1+windowy2)>>1); + for(y1=windowy1,y2=windowy2;y1>2,31)<<8); + ptr4 = palookup[18]; + ptr4 += (min(klabs(y2-l)>>2,31)<<8); + + j = sintable[((y2+totalclock)<<6)&2047]; + j += sintable[((y2-totalclock)<<7)&2047]; + j >>= 14; + + ptr2 += j; + + for(x1=windowx1;x1<=windowx2;x1++) + { ch = ptr[x1]; ptr[x1] = ptr3[(unsigned int)ptr2[x1]]; ptr2[x1] = ptr4[(unsigned int)ch]; } + } + gotpic[FLOORMIRROR>>3] &= ~(1<<(FLOORMIRROR&7)); + } + + if (gotpic[DAYSKY>>3]&(1<<(DAYSKY&7))) + { + gotpic[DAYSKY>>3] &= ~(1<<(DAYSKY&7)); + pskyoff[0] = 0; pskyoff[1] = 0; pskybits = 1; + } + else if (gotpic[NIGHTSKY>>3]&(1<<(NIGHTSKY&7))) + { + gotpic[NIGHTSKY>>3] &= ~(1<<(NIGHTSKY&7)); + pskyoff[0] = 0; pskyoff[1] = 0; pskyoff[2] = 0; pskyoff[3] = 0; + pskyoff[4] = 0; pskyoff[5] = 0; pskyoff[6] = 0; pskyoff[7] = 0; + pskybits = 3; + } + + /* Over the shoulder mode */ + csect = cursectnum[snum]; + if (cameradist >= 0) + { + cang += cameraang; + view(playersprite[snum],&cposx,&cposy,&cposz,&csect,cang,choriz); + } + + /* WARNING! Assuming (MIRRORLABEL&31) = 0 and MAXMIRRORS = 64 */ + longptr = (long *)FP_OFF(gotpic[MIRRORLABEL>>3]); + /* if ((longptr != NULL) && (longptr[0]|longptr[1])) */ + for(i=MAXMIRRORS-1;i>=0;i--) + if (gotpic[(i+MIRRORLABEL)>>3]&(1<<(i&7))) + { + gotpic[(i+MIRRORLABEL)>>3] &= ~(1<<(i&7)); + + /* + * Prepare drawrooms for drawing mirror and calculate reflected + * position into tposx, tposy, and tang (tposz == cposz) + * Must call preparemirror before drawrooms and + * completemirror after drawrooms + */ + preparemirror(cposx,cposy,cposz,cang,choriz, + mirrorwall[i],mirrorsector[i],&tposx,&tposy,&tang); + + ovisibility = visibility; + oparallaxvisibility = parallaxvisibility; + visibility <<= 1; + parallaxvisibility <<= 1; + ptr = palookup[0]; palookup[0] = palookup[17]; palookup[17] = ptr; + + drawrooms(tposx,tposy,cposz,tang,choriz,mirrorsector[i]|MAXSECTORS); + for(j=0,tspr=&tsprite[0];jcstat&48) == 0) tspr->cstat |= 4; + analyzesprites(tposx,tposy); + drawmasks(); + + ptr = palookup[0]; palookup[0] = palookup[17]; palookup[17] = ptr; + visibility = ovisibility; + parallaxvisibility = oparallaxvisibility; + + completemirror(); /* Reverse screen x-wise in this function */ + + break; + } + + if (cameradist < 0) sprite[playersprite[snum]].cstat |= 0x8000; + drawrooms(cposx,cposy,cposz,cang,choriz,csect); + sprite[playersprite[snum]].cstat &= ~0x8000; + analyzesprites(cposx,cposy); + drawmasks(); + + if ((gotpic[FLOORMIRROR>>3]&(1<<(FLOORMIRROR&7))) > 0) + transarea += (windowx2-windowx1)*(windowy2-windowy1); + + /* Finish for screen rotation */ + if ((tiltlock) || (detailmode)) + { + setviewback(); + i = (tiltlock&511); if (i > 256) i = 512-i; + i = sintable[i+512]*8 + sintable[i]*5L; + if (detailmode == 0) i >>= 1; + rotatesprite(320<<15,200<<15,i,tiltlock+512,MAXTILES-2,0,0,2+4+64,windowx1,windowy1,windowx2,windowy2); + walock[MAXTILES-2] = 1; + } + + if (((numgrabbers[screenpeek] > 0) || (nummissiles[screenpeek] > 0) || (numbombs[screenpeek] > 0)) && (cameradist < 0)) + { + /* Reset startdmost to bottom of screen */ + if ((windowx1 == 0) && (windowx2 == 319) && (yxaspect == 65536) && (tiltlock == 0)) + { + x1 = 160L-(tilesizx[GUNONBOTTOM]>>1); y1 = windowy2+1; + for(i=0;i>2,0,1+2,windowx1,windowy1,windowx2,windowy2); + else if (lockclock < 256) + rotatesprite(320<<15,200<<15,65536,0,DEMOSIGN,0,0,2,windowx1,windowy1,windowx2,windowy2); + else + rotatesprite(320<<15,200<<15,(384-lockclock)<<9,lockclock<<4,DEMOSIGN,(lockclock-256)>>2,0,1+2,windowx1,windowy1,windowx2,windowy2); + } + + if (health[screenpeek] <= 0) + rotatesprite(320<<15,200<<15,(-health[screenpeek])<<11,(-health[screenpeek])<<5,NO,0,0,2,windowx1,windowy1,windowx2,windowy2); + } + } + + /* + * Only animate lava if its picnum is on screen + * gotpic is a bit array where the tile number's bit is set + * whenever it is drawn (ceilings, walls, sprites, etc.) + */ + if ((gotpic[SLIME>>3]&(1<<(SLIME&7))) > 0) + { + gotpic[SLIME>>3] &= ~(1<<(SLIME&7)); + if (waloff[SLIME] != 0) movelava((char *)waloff[SLIME]); + } + + if ((show2dsector[cursectnum[snum]>>3]&(1<<(cursectnum[snum]&7))) == 0) + searchmap(cursectnum[snum]); + + if (dimensionmode[snum] != 3) + { + /* Move back pivot point */ + i = scale(czoom,screensize,320); + if (dimensionmode[snum] == 2) + { + clearview(0L); /* Clear screen to specified color */ + drawmapview(cposx,cposy,i,cang); + } + drawoverheadmap(cposx,cposy,i,cang); + } + + if (getmessageleng > 0) + { + charsperline = 40; + /*if (dimensionmode[snum] == 2) charsperline = 80;*/ + + for(i=0;i<=getmessageleng;i+=charsperline) + { + for(j=0;j getmessagetimeoff) + getmessageleng = 0; + } + if ((numplayers >= 2) && (screenpeek != myconnectindex)) + { + j = 1; + for(i=connecthead;i>=0;i=connectpoint2[i]) + { + if (i == screenpeek) break; + j++; + } + sprintf(tempbuf,"(Player %ld's view)",j); + printext256((xdim>>1)-(strlen(tempbuf)<<2),0,24,-1,tempbuf,0); + } + + if (syncstat != 0) printext256(68L,84L,31,0,"OUT OF SYNC!",0); + if (syncstate != 0) printext256(68L,92L,31,0,"Missed Network packet!",0); + +#if 0 /* Uncomment this to test cache locks */ + extern long cacnum; + typedef struct { long *hand, leng; char *lock; } cactype; + extern cactype cac[]; + + j = 0; + for(i=0;i= 200) + { + sprintf(tempbuf,"Locked- %ld: Leng:%ld, Lock:%ld",i,cac[i].leng,*cac[i].lock); + printext256(0L,j,31,-1,tempbuf,1); j += 6; + } +#endif + + nextpage(); + + if (keystatus[0x3f]) /* F5 */ + { + keystatus[0x3f] = 0; + detailmode ^= 1; + } + if (keystatus[0x58]) /* F12 */ + { + keystatus[0x58] = 0; + screencapture("captxxxx.pcx",keystatus[0x2a]|keystatus[0x36]); + } + if (keystatus[0x3c]) /* F2 (toggle stereo mode) */ + { + keystatus[0x3c] = 0; + stereomode++; if (stereomode >= 3) stereomode = 0; +#ifdef PLATFORM_DOS + setstereo(stereomode); +#endif + } + if (keystatus[0x3e]) /* F4 - screen re-size */ + { + keystatus[0x3e] = 0; + + /* cycle through all vesa modes, then screen-buffer mode */ + getvalidvesamodes(); + if (vidoption == 1) + { + for(i=0;i 0) + { + setgamemode(1,validmodexdim[0],validmodeydim[0]); + screensize = xdim+1; + } + + sprintf(getmessage,"Video mode: %ld x %ld",xdim,ydim); + if (vidoption == 2) strcat(getmessage," (Screen-buffer)"); + getmessageleng = strlen(getmessage); + getmessagetimeoff = totalclock+120*5; + } + if (keystatus[0x57]) /* F11 - brightness */ + { + keystatus[0x57] = 0; + brightness++; + if (brightness > 8) brightness = 0; + setbrightness(brightness, &palette[0]); + } + if (stereomode) /* Adjustments for red-blue / crystal eyes modes */ + { + if (keystatus[0x2a]|keystatus[0x36]) + { + if (keystatus[0xa]) stereopixelwidth = max(stereopixelwidth-1,0); /* Shift ( */ + if (keystatus[0xb]) stereopixelwidth++; /* Shift ) */ + } + else + { + if (keystatus[0xa]) stereowidth = max(stereowidth-512,0); /* ( */ + if (keystatus[0xb]) stereowidth += 512; /* ) */ + } + } + + if (option[4] == 0) /* Single player only keys */ + { + if (keystatus[0xd2]) /* Insert - Insert player */ + { + keystatus[0xd2] = 0; + if (numplayers < MAXPLAYERS) + { + connectpoint2[numplayers-1] = numplayers; + connectpoint2[numplayers] = -1; + + movefifoend[numplayers] = movefifoend[0]; /* HACK 01/05/2000 */ + + initplayersprite(numplayers); + + clearallviews(0L); /* Clear screen to specified color */ + + numplayers++; + } + } + if (keystatus[0xd3]) /* Delete - Delete player */ + { + keystatus[0xd3] = 0; + if (numplayers > 1) + { + numplayers--; + connectpoint2[numplayers-1] = -1; + + deletesprite(playersprite[numplayers]); + playersprite[numplayers] = -1; + + if (myconnectindex >= numplayers) myconnectindex = 0; + if (screenpeek >= numplayers) screenpeek = 0; + + if (numplayers < 2) + setup3dscreen(); + else + clearallviews(0L); /* Clear screen to specified color */ + } + } + if (keystatus[0x46]) /* Scroll Lock */ + { + keystatus[0x46] = 0; + + myconnectindex = connectpoint2[myconnectindex]; + if (myconnectindex < 0) myconnectindex = connecthead; + screenpeek = myconnectindex; + } + } + + restoreinterpolations(); +} + + +static void playback(void) +{ + long i, j, k; + + ready2send = 0; + recstat = 0; i = reccnt; + while (!keystatus[1]) + { + while (totalclock >= lockclock+TICSPERFRAME) + { + if (i >= reccnt) + { + prepareboard(boardfilename); + for(i=connecthead;i>=0;i=connectpoint2[i]) + initplayersprite((short)i); + totalclock = 0; + i = 0; + } + + k = 0; + for(j=connecthead;j>=0;j=connectpoint2[j]) + { + copybufbyte(&recsync[i][k],&ffsync[j],sizeof(input)); + k++; + } + movethings(); domovethings(); + i++; + } + drawscreen(screenpeek,(totalclock-gotlastpacketclock)*(65536/(TIMERINTSPERSECOND/MOVESPERSECOND))); + + if (keystatus[(unsigned int)keys[15]]) + { + keystatus[(unsigned int)keys[15]] = 0; + screenpeek = connectpoint2[screenpeek]; + if (screenpeek < 0) screenpeek = connecthead; + drawstatusbar(screenpeek); /* Andy did this */ + } + if (keystatus[(unsigned int)keys[14]]) + { + keystatus[(unsigned int)keys[14]] = 0; + dimensionmode[screenpeek]++; + if (dimensionmode[screenpeek] > 3) dimensionmode[screenpeek] = 1; + } + } + + musicoff(); + uninitmultiplayers(); + uninittimer(); + uninitkeys(); + uninitengine(); + uninitsb(); + uninitgroupfile(); + setvmode(0x3); /* Set back to text mode */ + exit(0); +} + + +int loadgame(void) +{ + long i; + long fil; + + if ((fil = kopen4load("save0000.gam",0)) == -1) return(-1); + + kdfread(&numplayers,2,1,fil); + kdfread(&myconnectindex,2,1,fil); + kdfread(&connecthead,2,1,fil); + kdfread(connectpoint2,2,MAXPLAYERS,fil); + + /* Make sure palookups get set, sprites will get overwritten later */ + for(i=connecthead;i>=0;i=connectpoint2[i]) initplayersprite((short)i); + + kdfread(posx,4,MAXPLAYERS,fil); + kdfread(posy,4,MAXPLAYERS,fil); + kdfread(posz,4,MAXPLAYERS,fil); + kdfread(horiz,4,MAXPLAYERS,fil); + kdfread(zoom,4,MAXPLAYERS,fil); + kdfread(hvel,4,MAXPLAYERS,fil); + kdfread(ang,2,MAXPLAYERS,fil); + kdfread(cursectnum,2,MAXPLAYERS,fil); + kdfread(ocursectnum,2,MAXPLAYERS,fil); + kdfread(playersprite,2,MAXPLAYERS,fil); + kdfread(deaths,2,MAXPLAYERS,fil); + kdfread(lastchaingun,4,MAXPLAYERS,fil); + kdfread(health,4,MAXPLAYERS,fil); + kdfread(numgrabbers,2,MAXPLAYERS,fil); + kdfread(nummissiles,2,MAXPLAYERS,fil); + kdfread(numbombs,2,MAXPLAYERS,fil); + kdfread(flytime,4,MAXPLAYERS,fil); + kdfread(oflags,2,MAXPLAYERS,fil); + kdfread(dimensionmode,1,MAXPLAYERS,fil); + kdfread(revolvedoorstat,1,MAXPLAYERS,fil); + kdfread(revolvedoorang,2,MAXPLAYERS,fil); + kdfread(revolvedoorrotang,2,MAXPLAYERS,fil); + kdfread(revolvedoorx,4,MAXPLAYERS,fil); + kdfread(revolvedoory,4,MAXPLAYERS,fil); + + kdfread(&numsectors,2,1,fil); + kdfread(sector,sizeof(sectortype),numsectors,fil); + kdfread(&numwalls,2,1,fil); + kdfread(wall,sizeof(walltype),numwalls,fil); + /* Store all sprites (even holes) to preserve indeces */ + kdfread(sprite,sizeof(spritetype),MAXSPRITES,fil); + kdfread(headspritesect,2,MAXSECTORS+1,fil); + kdfread(prevspritesect,2,MAXSPRITES,fil); + kdfread(nextspritesect,2,MAXSPRITES,fil); + kdfread(headspritestat,2,MAXSTATUS+1,fil); + kdfread(prevspritestat,2,MAXSPRITES,fil); + kdfread(nextspritestat,2,MAXSPRITES,fil); + + kdfread(&fvel,4,1,fil); + kdfread(&svel,4,1,fil); + kdfread(&avel,4,1,fil); + + kdfread(&locselectedgun,4,1,fil); + kdfread(&loc.fvel,1,1,fil); + kdfread(&oloc.fvel,1,1,fil); + kdfread(&loc.svel,1,1,fil); + kdfread(&oloc.svel,1,1,fil); + kdfread(&loc.avel,1,1,fil); + kdfread(&oloc.avel,1,1,fil); + kdfread(&loc.bits,2,1,fil); + kdfread(&oloc.bits,2,1,fil); + + kdfread(&locselectedgun2,4,1,fil); + kdfread(&loc2.fvel,sizeof(input),1,fil); + + kdfread(_sync,sizeof(input),MAXPLAYERS,fil); + kdfread(osync,sizeof(input),MAXPLAYERS,fil); + + kdfread(boardfilename,1,80,fil); + kdfread(&screenpeek,2,1,fil); + kdfread(&oldmousebstatus,2,1,fil); + kdfread(&brightness,2,1,fil); + kdfread(&neartagsector,2,1,fil); + kdfread(&neartagwall,2,1,fil); + kdfread(&neartagsprite,2,1,fil); + kdfread(&lockclock,4,1,fil); + kdfread(&neartagdist,4,1,fil); + kdfread(&neartaghitdist,4,1,fil); + + kdfread(turnspritelist,2,16,fil); + kdfread(&turnspritecnt,2,1,fil); + kdfread(warpsectorlist,2,16,fil); + kdfread(&warpsectorcnt,2,1,fil); + kdfread(xpanningsectorlist,2,16,fil); + kdfread(&xpanningsectorcnt,2,1,fil); + kdfread(ypanningwalllist,2,64,fil); + kdfread(&ypanningwallcnt,2,1,fil); + kdfread(floorpanninglist,2,64,fil); + kdfread(&floorpanningcnt,2,1,fil); + kdfread(dragsectorlist,2,16,fil); + kdfread(dragxdir,2,16,fil); + kdfread(dragydir,2,16,fil); + kdfread(&dragsectorcnt,2,1,fil); + kdfread(dragx1,4,16,fil); + kdfread(dragy1,4,16,fil); + kdfread(dragx2,4,16,fil); + kdfread(dragy2,4,16,fil); + kdfread(dragfloorz,4,16,fil); + kdfread(&swingcnt,2,1,fil); + kdfread(swingwall,2,32*5,fil); + kdfread(swingsector,2,32,fil); + kdfread(swingangopen,2,32,fil); + kdfread(swingangclosed,2,32,fil); + kdfread(swingangopendir,2,32,fil); + kdfread(swingang,2,32,fil); + kdfread(swinganginc,2,32,fil); + kdfread(swingx,4,32*8,fil); + kdfread(swingy,4,32*8,fil); + kdfread(revolvesector,2,4,fil); + kdfread(revolveang,2,4,fil); + kdfread(&revolvecnt,2,1,fil); + kdfread(revolvex,4,4*16,fil); + kdfread(revolvey,4,4*16,fil); + kdfread(revolvepivotx,4,4,fil); + kdfread(revolvepivoty,4,4,fil); + kdfread(subwaytracksector,2,4*128,fil); + kdfread(subwaynumsectors,2,4,fil); + kdfread(&subwaytrackcnt,2,1,fil); + kdfread(subwaystop,4,4*8,fil); + kdfread(subwaystopcnt,4,4,fil); + kdfread(subwaytrackx1,4,4,fil); + kdfread(subwaytracky1,4,4,fil); + kdfread(subwaytrackx2,4,4,fil); + kdfread(subwaytracky2,4,4,fil); + kdfread(subwayx,4,4,fil); + kdfread(subwaygoalstop,4,4,fil); + kdfread(subwayvel,4,4,fil); + kdfread(subwaypausetime,4,4,fil); + kdfread(waterfountainwall,2,MAXPLAYERS,fil); + kdfread(waterfountaincnt,2,MAXPLAYERS,fil); + kdfread(slimesoundcnt,2,MAXPLAYERS,fil); + + /* Warning: only works if all pointers are in sector structures! */ + kdfread(animateptr,4,MAXANIMATES,fil); + for(i=MAXANIMATES-1;i>=0;i--) + animateptr[i] = (long *)(animateptr[i]+((long)sector)); + + kdfread(animategoal,4,MAXANIMATES,fil); + kdfread(animatevel,4,MAXANIMATES,fil); + kdfread(animateacc,4,MAXANIMATES,fil); + kdfread(&animatecnt,4,1,fil); + + kdfread((void*)&totalclock,4,1,fil); + kdfread(&numframes,4,1,fil); + kdfread(&randomseed,4,1,fil); + kdfread(&numpalookups,2,1,fil); + + kdfread(&visibility,4,1,fil); + kdfread(¶llaxvisibility,4,1,fil); + kdfread(¶llaxtype,1,1,fil); + kdfread(¶llaxyoffs,4,1,fil); + kdfread(pskyoff,2,MAXPSKYTILES,fil); + kdfread(&pskybits,2,1,fil); + + kdfread(&mirrorcnt,2,1,fil); + kdfread(mirrorwall,2,mirrorcnt,fil); + kdfread(mirrorsector,2,mirrorcnt,fil); + + /* I should save off interpolation list, but they're pointers :( */ + numinterpolations = 0; + startofdynamicinterpolations = 0; + + kclose(fil); + + for(i=connecthead;i>=0;i=connectpoint2[i]) initplayersprite((short)i); + + totalclock = lockclock; + ototalclock = lockclock; + + strcpy(getmessage,"Game loaded."); + getmessageleng = strlen(getmessage); + getmessagetimeoff = totalclock+360+(getmessageleng<<4); + return(0); +} + + +int savegame(void) +{ + long i; + FILE *fil; + + if ((fil = fopen("save0000.gam","wb")) == 0) return(-1); + + dfwrite(&numplayers,2,1,fil); + dfwrite(&myconnectindex,2,1,fil); + dfwrite(&connecthead,2,1,fil); + dfwrite(connectpoint2,2,MAXPLAYERS,fil); + + dfwrite(posx,4,MAXPLAYERS,fil); + dfwrite(posy,4,MAXPLAYERS,fil); + dfwrite(posz,4,MAXPLAYERS,fil); + dfwrite(horiz,4,MAXPLAYERS,fil); + dfwrite(zoom,4,MAXPLAYERS,fil); + dfwrite(hvel,4,MAXPLAYERS,fil); + dfwrite(ang,2,MAXPLAYERS,fil); + dfwrite(cursectnum,2,MAXPLAYERS,fil); + dfwrite(ocursectnum,2,MAXPLAYERS,fil); + dfwrite(playersprite,2,MAXPLAYERS,fil); + dfwrite(deaths,2,MAXPLAYERS,fil); + dfwrite(lastchaingun,4,MAXPLAYERS,fil); + dfwrite(health,4,MAXPLAYERS,fil); + dfwrite(numgrabbers,2,MAXPLAYERS,fil); + dfwrite(nummissiles,2,MAXPLAYERS,fil); + dfwrite(numbombs,2,MAXPLAYERS,fil); + dfwrite(flytime,4,MAXPLAYERS,fil); + dfwrite(oflags,2,MAXPLAYERS,fil); + dfwrite(dimensionmode,1,MAXPLAYERS,fil); + dfwrite(revolvedoorstat,1,MAXPLAYERS,fil); + dfwrite(revolvedoorang,2,MAXPLAYERS,fil); + dfwrite(revolvedoorrotang,2,MAXPLAYERS,fil); + dfwrite(revolvedoorx,4,MAXPLAYERS,fil); + dfwrite(revolvedoory,4,MAXPLAYERS,fil); + + dfwrite(&numsectors,2,1,fil); + dfwrite(sector,sizeof(sectortype),numsectors,fil); + dfwrite(&numwalls,2,1,fil); + dfwrite(wall,sizeof(walltype),numwalls,fil); + /* Store all sprites (even holes) to preserve indeces */ + dfwrite(sprite,sizeof(spritetype),MAXSPRITES,fil); + dfwrite(headspritesect,2,MAXSECTORS+1,fil); + dfwrite(prevspritesect,2,MAXSPRITES,fil); + dfwrite(nextspritesect,2,MAXSPRITES,fil); + dfwrite(headspritestat,2,MAXSTATUS+1,fil); + dfwrite(prevspritestat,2,MAXSPRITES,fil); + dfwrite(nextspritestat,2,MAXSPRITES,fil); + + dfwrite(&fvel,4,1,fil); + dfwrite(&svel,4,1,fil); + dfwrite(&avel,4,1,fil); + + dfwrite(&locselectedgun,4,1,fil); + dfwrite(&loc.fvel,1,1,fil); + dfwrite(&oloc.fvel,1,1,fil); + dfwrite(&loc.svel,1,1,fil); + dfwrite(&oloc.svel,1,1,fil); + dfwrite(&loc.avel,1,1,fil); + dfwrite(&oloc.avel,1,1,fil); + dfwrite(&loc.bits,2,1,fil); + dfwrite(&oloc.bits,2,1,fil); + + dfwrite(&locselectedgun2,4,1,fil); + dfwrite(&loc2.fvel,sizeof(input),1,fil); + + dfwrite(_sync,sizeof(input),MAXPLAYERS,fil); + dfwrite(osync,sizeof(input),MAXPLAYERS,fil); + + dfwrite(boardfilename,1,80,fil); + dfwrite(&screenpeek,2,1,fil); + dfwrite(&oldmousebstatus,2,1,fil); + dfwrite(&brightness,2,1,fil); + dfwrite(&neartagsector,2,1,fil); + dfwrite(&neartagwall,2,1,fil); + dfwrite(&neartagsprite,2,1,fil); + dfwrite(&lockclock,4,1,fil); + dfwrite(&neartagdist,4,1,fil); + dfwrite(&neartaghitdist,4,1,fil); + + dfwrite(turnspritelist,2,16,fil); + dfwrite(&turnspritecnt,2,1,fil); + dfwrite(warpsectorlist,2,16,fil); + dfwrite(&warpsectorcnt,2,1,fil); + dfwrite(xpanningsectorlist,2,16,fil); + dfwrite(&xpanningsectorcnt,2,1,fil); + dfwrite(ypanningwalllist,2,64,fil); + dfwrite(&ypanningwallcnt,2,1,fil); + dfwrite(floorpanninglist,2,64,fil); + dfwrite(&floorpanningcnt,2,1,fil); + dfwrite(dragsectorlist,2,16,fil); + dfwrite(dragxdir,2,16,fil); + dfwrite(dragydir,2,16,fil); + dfwrite(&dragsectorcnt,2,1,fil); + dfwrite(dragx1,4,16,fil); + dfwrite(dragy1,4,16,fil); + dfwrite(dragx2,4,16,fil); + dfwrite(dragy2,4,16,fil); + dfwrite(dragfloorz,4,16,fil); + dfwrite(&swingcnt,2,1,fil); + dfwrite(swingwall,2,32*5,fil); + dfwrite(swingsector,2,32,fil); + dfwrite(swingangopen,2,32,fil); + dfwrite(swingangclosed,2,32,fil); + dfwrite(swingangopendir,2,32,fil); + dfwrite(swingang,2,32,fil); + dfwrite(swinganginc,2,32,fil); + dfwrite(swingx,4,32*8,fil); + dfwrite(swingy,4,32*8,fil); + dfwrite(revolvesector,2,4,fil); + dfwrite(revolveang,2,4,fil); + dfwrite(&revolvecnt,2,1,fil); + dfwrite(revolvex,4,4*16,fil); + dfwrite(revolvey,4,4*16,fil); + dfwrite(revolvepivotx,4,4,fil); + dfwrite(revolvepivoty,4,4,fil); + dfwrite(subwaytracksector,2,4*128,fil); + dfwrite(subwaynumsectors,2,4,fil); + dfwrite(&subwaytrackcnt,2,1,fil); + dfwrite(subwaystop,4,4*8,fil); + dfwrite(subwaystopcnt,4,4,fil); + dfwrite(subwaytrackx1,4,4,fil); + dfwrite(subwaytracky1,4,4,fil); + dfwrite(subwaytrackx2,4,4,fil); + dfwrite(subwaytracky2,4,4,fil); + dfwrite(subwayx,4,4,fil); + dfwrite(subwaygoalstop,4,4,fil); + dfwrite(subwayvel,4,4,fil); + dfwrite(subwaypausetime,4,4,fil); + dfwrite(waterfountainwall,2,MAXPLAYERS,fil); + dfwrite(waterfountaincnt,2,MAXPLAYERS,fil); + dfwrite(slimesoundcnt,2,MAXPLAYERS,fil); + + /* Warning: only works if all pointers are in sector structures! */ + for(i=MAXANIMATES-1;i>=0;i--) + animateptr[i] = (long *)(animateptr[i]-((long)sector)); + dfwrite(animateptr,4,MAXANIMATES,fil); + for(i=MAXANIMATES-1;i>=0;i--) + animateptr[i] = (long *)(animateptr[i]+((long)sector)); + + dfwrite(animategoal,4,MAXANIMATES,fil); + dfwrite(animatevel,4,MAXANIMATES,fil); + dfwrite(animateacc,4,MAXANIMATES,fil); + dfwrite(&animatecnt,4,1,fil); + + dfwrite((void*)&totalclock,4,1,fil); + dfwrite(&numframes,4,1,fil); + dfwrite(&randomseed,4,1,fil); + dfwrite(&numpalookups,2,1,fil); + + dfwrite(&visibility,4,1,fil); + dfwrite(¶llaxvisibility,4,1,fil); + dfwrite(¶llaxtype,1,1,fil); + dfwrite(¶llaxyoffs,4,1,fil); + dfwrite(pskyoff,2,MAXPSKYTILES,fil); + dfwrite(&pskybits,2,1,fil); + + dfwrite(&mirrorcnt,2,1,fil); + dfwrite(mirrorwall,2,mirrorcnt,fil); + dfwrite(mirrorsector,2,mirrorcnt,fil); + + fclose(fil); + + strcpy(getmessage,"Game saved."); + getmessageleng = strlen(getmessage); + getmessagetimeoff = totalclock+360+(getmessageleng<<4); + return(0); +} + + +int main(int argc, char **argv) +{ + long i, j, k, fil, waitplayers, x1, y1, x2, y2; + short other; + +#ifdef USE_PERL + int perl_works = 0; + if (buildperl_init() == 0) + perl_works = 1; +#endif + + _platform_init(argc, argv, "KenBuild by Ken Silverman", "KenBuild"); + + initgroupfile("stuff.dat"); + + if ((argc >= 2) && (stricmp("-net",argv[1]) != 0) && (stricmp("/net",argv[1]) != 0)) + { + strcpy((char*)&boardfilename,argv[1]); + if(strchr(boardfilename,'.') == 0) + strcat(boardfilename,".map"); + } + else + strcpy((char*)&boardfilename,"nukeland.map"); + + if ((fil = open("setup.dat",O_BINARY|O_RDWR,S_IREAD)) != -1) + { + read(fil,&option[0],NUMOPTIONS); + read(fil,&keys[0],NUMKEYS); + close(fil); + } + if (option[3] != 0) initmouse(); + + initengine(); + _initkeys(); + inittimer(); + initmultiplayers(option[4],option[5],0); + + pskyoff[0] = 0; pskyoff[1] = 0; pskybits = 1; + + initsb(option[1],option[2],digihz[option[7]>>4],((option[7]&4)>0)+1,((option[7]&2)>0)+1,60,option[7]&1); + if (strcmp(boardfilename,"klab.map") == 0) + loadsong("klabsong.kdm"); + else + loadsong("neatsong.kdm"); + musicon(); + + loadpics("tiles000.art"); /* Load artwork */ + qloadkvx(0L,"voxel000.kvx"); + qloadkvx(1L,"voxel001.kvx"); + + /* + * Here's an example of TRUE ornamented walls + * The allocatepermanenttile should be called right after loadpics + * Since it resets the tile cache for each call. + */ + if (allocatepermanenttile(SLIME,128,128) == 0) /* If enough memory */ + { + printf("Not enough memory for slime!\n"); + exit(0); + } + if (allocatepermanenttile(MAXTILES-1,64,64) != 0) /* If enough memory */ + { + /* My face with an explosion written over it */ + copytilepiece(KENPICTURE,0,0,64,64,MAXTILES-1,0,0); + copytilepiece(EXPLOSION,0,0,64,64,MAXTILES-1,0,0); + } + + initlava(); + + for(j=0;j<256;j++) + tempbuf[j] = ((j+32)&255); /* remap colors for screwy palette sectors */ + makepalookup(16,tempbuf,0,0,0,1); + + for(j=0;j<256;j++) tempbuf[j] = j; + makepalookup(17,tempbuf,24,24,24,1); + + for(j=0;j<256;j++) tempbuf[j] = j; /* (j&31)+32; */ + makepalookup(18,tempbuf,8,8,48,1); + + prepareboard(boardfilename); /* Load board */ + + if (option[4] > 0) + { + x1 = ((xdim-screensize)>>1); + x2 = x1+screensize-1; + y1 = (((ydim-32)-scale(screensize,ydim-32,xdim))>>1); + y2 = y1 + scale(screensize,ydim-32,xdim)-1; + drawtilebackground(0L,0L,BACKGROUND,8,x1,y1,x2,y2,0); + + sendlogon(); + if (option[4] < 5) waitplayers = 2; else waitplayers = option[4]-3; + while (numplayers < waitplayers) + { + sprintf(tempbuf,"%d of %ld players in...",numplayers,waitplayers); + printext256(68L,84L,31,0,tempbuf,0); + nextpage(); + + if (getpacket(&other,packbuf) > 0) + if (packbuf[0] == 255) + keystatus[1] = 1; + + if (keystatus[1]) + { + sendlogoff(); /* Signing off */ + musicoff(); + uninitmultiplayers(); + uninittimer(); + uninitkeys(); + uninitengine(); + uninitsb(); + uninitgroupfile(); + setvmode(0x3); /* Set back to text mode */ + exit(0); + } + } + screenpeek = myconnectindex; + + if (numplayers <= 3) + networkmode = 1; + else + networkmode = 0; + + j = 1; + for(i=connecthead;i>=0;i=connectpoint2[i]) + { + if (myconnectindex == i) break; + j++; + } + sprintf(getmessage,"Player %ld",j); + if (networkmode == 0) + { + if (j == 1) strcat(getmessage," (Master)"); + else strcat(getmessage," (Slave)"); + } + else + strcat(getmessage," (Even)"); + getmessageleng = strlen(getmessage); + getmessagetimeoff = totalclock+120; + } + + reccnt = 0; + for(i=connecthead;i>=0;i=connectpoint2[i]) initplayersprite((short)i); + + /*waitforeverybody();*/ + totalclock = ototalclock = 0; gotlastpacketclock = 0; nummoves = 0; + + drawscreen(screenpeek,65536L); + + ready2send = 1; + while (!keystatus[1]) /* Main loop starts here */ + { + #ifdef USE_PERL + if (perl_works) + buildperl_frame(); + #endif + + /* backslash (useful only with KDM) */ + if (keystatus[0x2b]) { keystatus[0x2b] = 0; preparesndbuf(); } + + if ((networkmode == 1) || (myconnectindex != connecthead)) + while (fakemovefifoplc != movefifoend[myconnectindex]) fakedomovethings(); + + getpackets(); + + if (typemode == 0) /* if normal game keys active */ + { + if ((keystatus[0x2a]&keystatus[0x36]&keystatus[0x13]) > 0) /* Sh.Sh.R (replay) */ + { + keystatus[0x13] = 0; + playback(); + } + + if (keystatus[0x26]&(keystatus[0x1d]|keystatus[0x9d])) /* Load game */ + { + keystatus[0x26] = 0; + loadgame(); + drawstatusbar(screenpeek); /* Andy did this */ + } + + if (keystatus[0x1f]&(keystatus[0x1d]|keystatus[0x9d])) /* Save game */ + { + keystatus[0x1f] = 0; + savegame(); + } + } + + if ((networkmode == 0) || (option[4] == 0)) + { + while (movefifoplc != movefifoend[0]) domovethings(); + } + else + { + j = connecthead; + if (j == myconnectindex) j = connectpoint2[j]; + averagelag[j] = ((averagelag[j]*7+(((movefifoend[myconnectindex]-movefifoend[j]+otherlag[j]+2)&255)<<8))>>3); + j = max(averagelag[j]>>9,1); + while (((movefifoend[myconnectindex]-movefifoplc)&(MOVEFIFOSIZ-1)) > j) + { + for(i=connecthead;i>=0;i=connectpoint2[i]) + if (movefifoplc == movefifoend[i]) break; + if (i >= 0) break; + if (myconnectindex != connecthead) + { + k = ((movefifoend[myconnectindex]-movefifoend[connecthead]-otherlag[connecthead]+128)&255); + if (k > 128+1) ototalclock++; + if (k < 128-1) ototalclock--; + } + domovethings(); + } + } + i = (totalclock-gotlastpacketclock)*(65536/(TIMERINTSPERSECOND/MOVESPERSECOND)); + drawscreen(screenpeek,i); + if (((stereomode) || (option[0] == 6)) && ((activepage&1))) + drawscreen(screenpeek,i); + } + + sendlogoff(); /* Signing off */ + musicoff(); + uninitmultiplayers(); + uninittimer(); + uninitkeys(); + uninitengine(); + uninitsb(); + uninitgroupfile(); + setvmode(0x3); /* Set back to text mode */ + + if (stereomode) + { + printf("stereowidth was: %ld\n",stereowidth); + printf("stereopixelwidth was: %ld\n",stereopixelwidth); + } + + #ifdef USE_PERL + if (perl_works) + buildperl_deinit(); + #endif + + return(0); +} + + +static void getinput(void) +{ + char ch, keystate; + long i, j; + short mousx, mousy, bstatus; + + if (typemode == 0) /* if normal game keys active */ + { + if (keystatus[(unsigned int)keys[15]]) + { + keystatus[(unsigned int)keys[15]] = 0; + + screenpeek = connectpoint2[screenpeek]; + if (screenpeek < 0) screenpeek = connecthead; + drawstatusbar(screenpeek); /* Andy did this */ + } + + for(i=7;i>=0;i--) + if (keystatus[i+2]) + { keystatus[i+2] = 0; locselectedgun = i; break; } + } + + + /* KEYTIMERSTUFF */ + if (!keystatus[(unsigned int)keys[5]]) + { + if (keystatus[(unsigned int)keys[2]]) avel = max(avel-16*TICSPERFRAME,-128); + if (keystatus[(unsigned int)keys[3]]) avel = min(avel+16*TICSPERFRAME,127); + } + else + { + if (keystatus[(unsigned int)keys[2]]) svel = min(svel+8*TICSPERFRAME,127); + if (keystatus[(unsigned int)keys[3]]) svel = max(svel-8*TICSPERFRAME,-128); + } + if (keystatus[(unsigned int)keys[0]]) fvel = min(fvel+8*TICSPERFRAME,127); + if (keystatus[(unsigned int)keys[1]]) fvel = max(fvel-8*TICSPERFRAME,-128); + if (keystatus[(unsigned int)keys[12]]) svel = min(svel+8*TICSPERFRAME,127); + if (keystatus[(unsigned int)keys[13]]) svel = max(svel-8*TICSPERFRAME,-128); + + if (avel < 0) avel = min(avel+12*TICSPERFRAME,0); + if (avel > 0) avel = max(avel-12*TICSPERFRAME,0); + if (svel < 0) svel = min(svel+2*TICSPERFRAME,0); + if (svel > 0) svel = max(svel-2*TICSPERFRAME,0); + if (fvel < 0) fvel = min(fvel+2*TICSPERFRAME,0); + if (fvel > 0) fvel = max(fvel-2*TICSPERFRAME,0); + + if ((option[4] == 0) && (numplayers >= 2)) + { + if (!keystatus[0x4f]) + { + if (keystatus[0x4b]) avel2 = max(avel2-16*TICSPERFRAME,-128); + if (keystatus[0x4d]) avel2 = min(avel2+16*TICSPERFRAME,127); + } + else + { + if (keystatus[0x4b]) svel2 = min(svel2+8*TICSPERFRAME,127); + if (keystatus[0x4d]) svel2 = max(svel2-8*TICSPERFRAME,-128); + } + if (keystatus[0x48]) fvel2 = min(fvel2+8*TICSPERFRAME,127); + if (keystatus[0x4c]) fvel2 = max(fvel2-8*TICSPERFRAME,-128); + + if (avel2 < 0) avel2 = min(avel2+12*TICSPERFRAME,0); + if (avel2 > 0) avel2 = max(avel2-12*TICSPERFRAME,0); + if (svel2 < 0) svel2 = min(svel2+2*TICSPERFRAME,0); + if (svel2 > 0) svel2 = max(svel2-2*TICSPERFRAME,0); + if (fvel2 < 0) fvel2 = min(fvel2+2*TICSPERFRAME,0); + if (fvel2 > 0) fvel2 = max(fvel2-2*TICSPERFRAME,0); + } + + if (keystatus[0x1a]) screentilt += ((4*TICSPERFRAME)<<(keystatus[0x2a]|keystatus[0x36])); + if (keystatus[0x1b]) screentilt -= ((4*TICSPERFRAME)<<(keystatus[0x2a]|keystatus[0x36])); + + i = (TICSPERFRAME<<1); + while ((screentilt != 0) && (i > 0)) + { screentilt = ((screentilt+ksgn(screentilt-1024))&2047); i--; } + if (keystatus[0x28]) screentilt = 1536; + + + loc.fvel = min(max(fvel,-128+8),127-8); + loc.svel = min(max(svel,-128+8),127-8); + loc.avel = min(max(avel,-128+16),127-16); + + getmousevalues(&mousx,&mousy,&bstatus); + loc.avel = min(max(loc.avel+(mousx<<3),-128),127); + loc.fvel = min(max(loc.fvel-(mousy<<3),-128),127); + + loc.bits = (locselectedgun<<13); + if (typemode == 0) /* if normal game keys active */ + { + loc.bits |= (keystatus[0x32]<<9); /* M (be master) */ + loc.bits |= ((keystatus[(unsigned int)keys[14]]==1)<<12); /* Map mode */ + } + loc.bits |= keystatus[(unsigned int)keys[8]]; /* Stand high */ + loc.bits |= (keystatus[(unsigned int)keys[9]]<<1); /* Stand low */ + loc.bits |= (keystatus[(unsigned int)keys[16]]<<4); /* Zoom in */ + loc.bits |= (keystatus[(unsigned int)keys[17]]<<5); /* Zoom out */ + loc.bits |= (keystatus[(unsigned int)keys[4]]<<8); /* Run */ + loc.bits |= (keystatus[(unsigned int)keys[10]]<<2); /* Look up */ + loc.bits |= (keystatus[(unsigned int)keys[11]]<<3); /* Look down */ + loc.bits |= ((keystatus[(unsigned int)keys[7]]==1)<<10); /* Space */ + loc.bits |= ((keystatus[(unsigned int)keys[6]]==1)<<11); /* Shoot */ + loc.bits |= (((bstatus&6)>(oldmousebstatus&6))<<10); /* Space */ + loc.bits |= (((bstatus&1)>(oldmousebstatus&1))<<11); /* Shoot */ + + oldmousebstatus = bstatus; + if (((loc.bits&2048) > 0) && (locselectedgun == 1)) + oldmousebstatus &= ~1; /* Allow continous fire with mouse for chain gun */ + + /* PRIVATE KEYS: */ + if (keystatus[0xb7]) /* Printscreen */ + { + keystatus[0xb7] = 0; +#ifdef PLATFORM_DOS + printscreeninterrupt(); +#endif + } + + if (keystatus[0x2f]) /* V */ + { + keystatus[0x2f] = 0; + if (cameradist < 0) cameradist = 0; else cameradist = -1; + cameraang = 0; + } + + if (typemode == 0) /* if normal game keys active */ + { + if (keystatus[0x19]) /* P */ + { + keystatus[0x19] = 0; + parallaxtype++; + if (parallaxtype > 2) parallaxtype = 0; + } + if (keystatus[0x38]|keystatus[0xb8]) /* ALT */ + { + if (keystatus[0x4a]) /* Keypad - */ + visibility = min(visibility+(visibility>>3),16384); + if (keystatus[0x4e]) /* Keypad + */ + visibility = max(visibility-(visibility>>3),128); + } + + if (keystatus[(unsigned int)keys[18]]) /* Typing mode */ + { + keystatus[(unsigned int)keys[18]] = 0; + typemode = 1; + keyfifoplc = keyfifoend; /* Reset keyboard fifo */ + } + } + else + { + while (keyfifoplc != keyfifoend) + { + ch = keyfifo[(unsigned int)keyfifoplc]; + keystate = keyfifo[(keyfifoplc+1)&(KEYFIFOSIZ-1)]; + keyfifoplc = ((keyfifoplc+2)&(KEYFIFOSIZ-1)); + + if (keystate != 0) + { + if (ch == 0xe) /* Backspace */ + { + if (typemessageleng == 0) { typemode = 0; break; } + typemessageleng--; + } + if (ch == 0xf) + { + keystatus[0xf] = 0; + typemode = 0; + break; + } + if ((ch == 0x1c) || (ch == 0x9c)) /* Either ENTER */ + { + keystatus[0x1c] = 0; keystatus[0x9c] = 0; + if (typemessageleng > 0) + { + packbuf[0] = 2; /* Sending text is message type 4 */ + for(j=typemessageleng-1;j>=0;j--) + packbuf[j+1] = typemessage[j]; + + for(i=connecthead;i>=0;i=connectpoint2[i]) + if (i != myconnectindex) + sendpacket(i,(unsigned char *) packbuf,typemessageleng+1); + + typemessageleng = 0; + } + typemode = 0; + break; + } + + if ((typemessageleng < 159) && (ch < 128)) + { + if (keystatus[0x2a]|keystatus[0x36]) + ch = scantoascwithshift[(unsigned int)ch]; + else + ch = scantoasc[(unsigned int)ch]; + + if (ch != 0) typemessage[(unsigned int)typemessageleng++] = ch; + } + } + } + /* Here's a trick of making key repeat after a 1/2 second */ + if (keystatus[0xe]) + { + if (keystatus[0xe] < 30) + keystatus[0xe] += TICSPERFRAME; + else + { + if (typemessageleng == 0) + typemode = 0; + else + typemessageleng--; + } + } + } +} + + +void faketimerhandler(void) +{ + short other; + long i, j, k, l; + + if ((totalclock < ototalclock+(TIMERINTSPERSECOND/MOVESPERSECOND)) || (ready2send == 0)) return; + ototalclock += (TIMERINTSPERSECOND/MOVESPERSECOND); + + getpackets(); if (getoutputcirclesize() >= 16) return; + getinput(); + + if (networkmode == 1) + { + packbuf[2] = 0; j = 3; + if (loc.fvel != oloc.fvel) packbuf[j++] = loc.fvel, packbuf[2] |= 1; + if (loc.svel != oloc.svel) packbuf[j++] = loc.svel, packbuf[2] |= 2; + if (loc.avel != oloc.avel) packbuf[j++] = loc.avel, packbuf[2] |= 4; + if ((loc.bits^oloc.bits)&0x00ff) packbuf[j++] = (loc.bits&255), packbuf[2] |= 8; + if ((loc.bits^oloc.bits)&0xff00) packbuf[j++] = ((loc.bits>>8)&255), packbuf[2] |= 16; + copybufbyte(&loc,&oloc,sizeof(input)); + + copybufbyte(&loc,&baksync[movefifoend[myconnectindex]][myconnectindex],sizeof(input)); + movefifoend[myconnectindex] = ((movefifoend[myconnectindex]+1)&(MOVEFIFOSIZ-1)); + + for(i=connecthead;i>=0;i=connectpoint2[i]) + if (i != myconnectindex) + { + packbuf[0] = 17; + packbuf[1] = (char)((movefifoend[myconnectindex]-movefifoend[i])&(MOVEFIFOSIZ-1)); + + k = j; + if ((myconnectindex == connecthead) || ((i == connecthead) && (myconnectindex == connectpoint2[connecthead]))) + { + while (syncvalhead != syncvaltail) + { + packbuf[j++] = syncval[syncvaltail]; + syncvaltail = ((syncvaltail+1)&(MOVEFIFOSIZ-1)); + } + } + sendpacket(i,(unsigned char *) packbuf,j); + j = k; + } + + gotlastpacketclock = totalclock; + return; + } + + /* MASTER (or 1 player game) */ + if ((myconnectindex == connecthead) || (option[4] == 0)) + { + copybufbyte(&loc,&ffsync[myconnectindex],sizeof(input)); + + if (option[4] != 0) + { + packbuf[0] = 0; + j = ((numplayers+1)>>1)+1; + for(k=1;k=0;i=connectpoint2[i]) + { + l = 0; + if (ffsync[i].fvel != osync[i].fvel) packbuf[j++] = ffsync[i].fvel, l |= 1; + if (ffsync[i].svel != osync[i].svel) packbuf[j++] = ffsync[i].svel, l |= 2; + if (ffsync[i].avel != osync[i].avel) packbuf[j++] = ffsync[i].avel, l |= 4; + if (ffsync[i].bits != osync[i].bits) + { + packbuf[j++] = (ffsync[i].bits&255); + packbuf[j++] = ((ffsync[i].bits>>8)&255); + l |= 8; + } + packbuf[k>>3] |= (l<<(k&7)); + k += 4; + + copybufbyte(&ffsync[i],&osync[i],sizeof(input)); + } + + while (syncvalhead != syncvaltail) + { + packbuf[j++] = syncval[syncvaltail]; + syncvaltail = ((syncvaltail+1)&(MOVEFIFOSIZ-1)); + } + + for(i=connectpoint2[connecthead];i>=0;i=connectpoint2[i]) + sendpacket(i,(unsigned char *) packbuf,j); + } + else if (numplayers >= 2) + { + if (keystatus[0xb5]) + { + keystatus[0xb5] = 0; + locselectedgun2++; if (locselectedgun2 >= 3) locselectedgun2 = 0; + } + + /* Second player on 1 computer mode */ + loc2.fvel = min(max(fvel2,-128+8),127-8); + loc2.svel = min(max(svel2,-128+8),127-8); + loc2.avel = min(max(avel2,-128+16),127-16); + loc2.bits = (locselectedgun2<<13); + loc2.bits |= keystatus[0x45]; /* Stand high */ + loc2.bits |= (keystatus[0x47]<<1); /* Stand low */ + loc2.bits |= (1<<8); /* Run */ + loc2.bits |= (keystatus[0x49]<<2); /* Look up */ + loc2.bits |= (keystatus[0x37]<<3); /* Look down */ + loc2.bits |= (keystatus[0x50]<<10); /* Space */ + loc2.bits |= (keystatus[0x52]<<11); /* Shoot */ + + other = connectpoint2[myconnectindex]; + if (other < 0) other = connecthead; + + copybufbyte(&loc2,&ffsync[other],sizeof(input)); + } + movethings(); /* Move EVERYTHING (you too!) */ + } + else /* I am a SLAVE */ + { + packbuf[0] = 1; packbuf[1] = 0; j = 2; + if (loc.fvel != oloc.fvel) packbuf[j++] = loc.fvel, packbuf[1] |= 1; + if (loc.svel != oloc.svel) packbuf[j++] = loc.svel, packbuf[1] |= 2; + if (loc.avel != oloc.avel) packbuf[j++] = loc.avel, packbuf[1] |= 4; + if ((loc.bits^oloc.bits)&0x00ff) packbuf[j++] = (loc.bits&255), packbuf[1] |= 8; + if ((loc.bits^oloc.bits)&0xff00) packbuf[j++] = ((loc.bits>>8)&255), packbuf[1] |= 16; + copybufbyte(&loc,&oloc,sizeof(input)); + sendpacket(connecthead,(unsigned char *) packbuf,j); + } +} + + +void waitforeverybody(void) +{ + long i, j, oldtotalclock; + + if (numplayers < 2) return; + + if (myconnectindex == connecthead) + { + for(j=1;j<=2;j++) + { + for(i=connectpoint2[connecthead];i>=0;i=connectpoint2[i]) + playerreadyflag[i] = 0; + oldtotalclock = totalclock-8; + do + { + _idle(); + getpackets(); + if (totalclock >= oldtotalclock+8) + { + oldtotalclock = totalclock; + packbuf[0] = 5; + packbuf[1] = j; + for(i=connectpoint2[connecthead];i>=0;i=connectpoint2[i]) + { + if (playerreadyflag[i] != j) + sendpacket(i,(unsigned char *) packbuf,2); + } + } + for(i=connectpoint2[connecthead];i>=0;i=connectpoint2[i]) + if (playerreadyflag[i] != j) break; + } while (i >= 0); + } + } + else + { + playerreadyflag[connecthead] = 0; + while (playerreadyflag[connecthead] != 2) + { + _idle(); + getpackets(); + if (playerreadyflag[connecthead] == 1) + { + playerreadyflag[connecthead] = 0; + sendpacket(connecthead,(unsigned char *) packbuf,2); + } + } + } +} + +/* end of game.c ... */ + diff --git a/buildengine/game.pl b/buildengine/game.pl new file mode 100755 index 0000000..84b1316 --- /dev/null +++ b/buildengine/game.pl @@ -0,0 +1,44 @@ +#!/usr/bin/perl -w + +# This is an example of a perl module that is run from inside BUILD. +# +# Written by Ryan C. Gordon. (icculus@clutteredmind.org) +# +# Please do NOT harrass Ken Silverman about any code modifications +# (including this file) to BUILD. +# +# +#// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman +#// Ken Silverman's official web site: "http://www.advsys.net/ken" +#// See the included license file "BUILDLIC.TXT" for license info. +#// This file IS NOT A PART OF Ken Silverman's original release + +use strict; + + +# Global/package data works. +my $build_counter = 0; + + + +# The sub BUILD_frame() is called once before each video frame is rendered. +# This means it may run from < 10 to > 500 times per second, and should +# run AS FAST AS POSSIBLE. + +sub BUILD_frame { + $build_counter++; + + if ($build_counter == 1024) { + $build_counter = 0; + print("INSIDE PERL ROUTINE: build counter hit 1024.\n"); + } +} + + +# Stuff outside a function is mainline code. This is run once when game +# loads. + +print("INSIDE PERL ROUTINE: this is the mainline.\n"); + +# end of game.pl ... + diff --git a/buildengine/k.asm b/buildengine/k.asm new file mode 100755 index 0000000..6d2293a --- /dev/null +++ b/buildengine/k.asm @@ -0,0 +1,549 @@ +; "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman +; Ken Silverman's official web site: "http://www.advsys.net/ken" +; See the included license file "BUILDLIC.TXT" for license info. +; This file has been modified from Ken Silverman's original release + +.386P + +EXTRN _kdmasm1 : dword +EXTRN _kdmasm2 : dword +EXTRN _kdmasm3 : dword +EXTRN _kdmasm4 : dword + +EXTRN _chainbackcnt : dword +EXTRN _chainbackstart : dword +EXTRN _pcsndptr : dword +EXTRN _samplecount : dword +EXTRN _pcsndbufsiz : dword +EXTRN _oldpctimerhandler : far +EXTRN _bufferside : byte + +EXTRN _qualookup : near +EXTRN _pcsndlookup : near +EXTRN _chain_intr_ : near +EXTRN __GETDS : near +EXTRN preparesndbuf_ : near + +_DATA SEGMENT BYTE PUBLIC USE32 'DATA' +_DATA ENDS +DGROUP GROUP _DATA + +CODE SEGMENT BYTE PUBLIC USE32 'CODE' +ASSUME cs:CODE + +PUBLIC monolocomb_ +monolocomb_: + ;eax=temp2,ebx=temp1,ecx=cnt,edx=dat,esi=dasplc,edi=stemp,ebp=dasoff + push ebp + + mov dword ptr ds:[mach1lm+3], ebx ;voloffs1 + + mov ebx, _kdmasm4 + mov dword ptr ds:[mach5lm+2], ebx + + mov ebx, edx + shl ebx, 32-12 + sar edx, 12 + mov dword ptr ds:[mach3lm+2], ebx ;dasinc + mov dword ptr ds:[mach4lm+2], edx ;dasinc + + mov ebp, esi + shl ebp, 32-12 + sar esi, 12 + + xor edx, edx + jmp begitlm + +prebegitlm: + cmp _kdmasm1, 0 + jz enditlm + mov ebx, _kdmasm2 + mov dword ptr ds:[mach5lm+2], ebx + mov _kdmasm4, ebx + mov ebx, _kdmasm3 + mov eax, ebx + shl ebx, 32-12 + sar eax, 12 + sub ebp, ebx + sbb esi, eax + test ecx, ecx + jz enditlm + +begitlm: + ;dl = [(eax>>12)+dasoff]; (QUICK NO MULTIPLY METHOD) +mach5lm: mov dl, byte ptr [esi+88888888h] ;dasoff + + mov ebx, dword ptr [edi] + add edi, 4 +mach1lm: add ebx, dword ptr [edx*4+88888888h] ;voloffs1 +mach3lm: add ebp, 88888888h ;dasinc +mach4lm: adc esi, 88888888h ;dasinc + mov dword ptr [edi-4], ebx + dec ecx + + ja begitlm ;jump if (no carry (add)) and (not zero (dec))! + jc prebegitlm +enditlm: + + shl esi, 12 + shr ebp, 32-12 + lea eax, [esi+ebp] + + pop ebp + ret + +PUBLIC monohicomb_ +monohicomb_: + ;eax=temp2,ebx=temp1,ecx=cnt,edx=dat,esi=dasplc,edi=stemp,ebp=dasoff + push ebp + mov ebp, ecx + + mov dword ptr ds:[mach1hm+3], ebx ;voloffs1 + + mov ebx, _kdmasm4 + mov dword ptr ds:[mach5hm+3], ebx + + mov ebx, edx + shl ebx, 32-12 + sar edx, 12 + mov dword ptr ds:[mach4hm+2], edx ;dasinc + ;mov edx, ebx ;Fake 4-bit counter to save shift + ;shr edx, 20 ; + ;mov bx, dx ; + mov dword ptr ds:[mach3hm+2], ebx ;dasinc + + mov ecx, esi + shl ecx, 32-12 + sar esi, 12 + ;mov edx, ecx ;Fake 4-bit counter to save shift + ;shr edx, 20 ; + ;mov cx, dx ; + + xor edx, edx + sub edi, 4 + jmp begithm + +prebegithm: + cmp _kdmasm1, 0 + jz endithm + mov ebx, _kdmasm2 + mov dword ptr ds:[mach5hm+3], ebx + mov _kdmasm4, ebx + mov ebx, _kdmasm3 + mov eax, ebx + shl ebx, 32-12 + sar eax, 12 + sub ecx, ebx + sbb esi, eax + test ebp, ebp + jz endithm + +begithm: + ;edx = _qualookup[((ebp>>19)&0x00001e00)+(bh-bl)]+bl +mach5hm: mov bx, word ptr [esi+88888888h] + mov eax, ecx + shr eax, 20 + add edi, 4 + mov dl, bl + mov al, bl + sub al, bh + adc ah, ah + add dl, byte ptr _qualookup[eax] + + mov ebx, dword ptr [edi] +mach1hm: add ebx, dword ptr [edx*4+88888888h] ;voloffs1 +mach3hm: add ecx, 88888888h ;dasinc +mach4hm: adc esi, 88888888h ;dasinc + dec ebp + + mov dword ptr [edi], ebx + + ja begithm ;jump if (no carry (add)) and (not zero (dec))! + jc prebegithm +endithm: + + shl esi, 12 + shr ecx, 32-12 + lea eax, [esi+ecx] + + pop ebp + ret + +PUBLIC stereolocomb_ +stereolocomb_: + ;eax=temp2,ebx=temp1,ecx=cnt,edx=dat,esi=dasplc,edi=stemp,ebp=dasoff + push ebp + + mov dword ptr ds:[mach1ls+3], ebx ;voloffs1 + add ebx, 4 + mov dword ptr ds:[mach2ls+3], ebx ;voloffs2 + + mov ebx, _kdmasm4 + mov dword ptr ds:[mach5ls+2], ebx + + mov ebx, edx + shl ebx, 32-12 + sar edx, 12 + mov dword ptr ds:[mach3ls+2], ebx ;dasinc + mov dword ptr ds:[mach4ls+2], edx ;dasinc + + mov ebp, esi + shl ebp, 32-12 + sar esi, 12 + + xor edx, edx + sub edi, 8 + jmp begitls + +prebegitls: + cmp _kdmasm1, 0 + jz enditls + mov ebx, _kdmasm2 + mov dword ptr ds:[mach5ls+2], ebx + mov _kdmasm4, ebx + mov ebx, _kdmasm3 + mov eax, ebx + shl ebx, 32-12 + sar eax, 12 + sub ebp, ebx + sbb esi, eax + test ecx, ecx + jz enditls + jmp begitls + +begitls: + add edi, 8 + + ;dl = [(eax>>12)+dasoff]; (QUICK NO MULTIPLY METHOD) +mach5ls: mov dl, byte ptr [esi+88888888h] ;dasoff + + mov ebx, dword ptr [edi] + mov eax, dword ptr [edi+4] + +mach1ls: add ebx, dword ptr [edx*8+88888888h] ;voloffs1 +mach2ls: add eax, dword ptr [edx*8+88888888h] ;voloffs2 + +mach3ls: add ebp, 88888888h ;dasinc + mov dword ptr [edi], ebx +mach4ls: adc esi, 88888888h ;dasinc + dec ecx + + mov dword ptr [edi+4], eax + + ja begitls ;jump if (no carry (add)) and (not zero (dec))! + jc prebegitls +enditls: + + shl esi, 12 + shr ebp, 32-12 + lea eax, [esi+ebp] + + pop ebp + ret + +PUBLIC stereohicomb_ +stereohicomb_: + ;eax=temp2,ebx=temp1,ecx=cnt,edx=dat,esi=dasplc,edi=stemp,ebp=dasoff + push ebp + mov ebp, ecx + + mov dword ptr ds:[mach1hs+3], ebx ;voloffs1 + add ebx, 4 + mov dword ptr ds:[mach2hs+3], ebx ;voloffs2 + + mov ebx, _kdmasm4 + mov dword ptr ds:[mach5hs+3], ebx + + mov ebx, edx + shl ebx, 32-12 + sar edx, 12 + mov dword ptr ds:[mach4hs+2], edx ;dasinc + ;mov edx, ebx ;Fake 4-bit counter to save shift + ;shr edx, 20 ; + ;mov bx, dx ; + mov dword ptr ds:[mach3hs+2], ebx ;dasinc + + mov ecx, esi + shl ecx, 32-12 + sar esi, 12 + ;mov edx, ecx ;Fake 4-bit counter to save shift + ;shr edx, 20 ; + ;mov cx, dx ; + + xor edx, edx + sub edi, 8 + jmp begiths + +prebegiths: + cmp _kdmasm1, 0 + jz endiths + mov ebx, _kdmasm2 + mov dword ptr ds:[mach5hs+3], ebx + mov _kdmasm4, ebx + mov ebx, _kdmasm3 + mov eax, ebx + shl ebx, 32-12 + sar eax, 12 + sub ecx, ebx + sbb esi, eax + test ebp, ebp + jz endiths + +begiths: + ;edx = _qualookup[((ebp>>19)&0x00001e00)+(bh-bl)]+bl +mach5hs: mov bx, word ptr [esi+88888888h] + mov eax, ecx + shr eax, 20 + add edi, 8 + mov dl, bl + mov al, bl + sub al, bh + adc ah, ah + add dl, byte ptr _qualookup[eax] + + mov eax, dword ptr [edi] +mach1hs: mov ebx, dword ptr [edx*8+88888888h] ;voloffs1 + add ebx, eax + mov eax, dword ptr [edi+4] + mov dword ptr [edi], ebx +mach2hs: mov ebx, dword ptr [edx*8+88888888h] ;voloffs2 + add eax, ebx + +mach3hs: add ecx, 88888888h ;dasinc +mach4hs: adc esi, 88888888h ;dasinc + + dec ebp + + mov dword ptr [edi+4], eax + + ja begiths ;jump if (no carry (add)) and (not zero (dec))! + jc prebegiths +endiths: + + shl esi, 12 + shr ecx, 32-12 + lea eax, [esi+ecx] + + pop ebp + ret + +PUBLIC setuppctimerhandler_ +setuppctimerhandler_: + mov dword ptr ds:[pcmach3+2], eax + + cmp ebx, 65000d + jl short skipsetuppc1 + mov word ptr ds:[pcmach1+0], 0c381h ;81c300000000 = add ebx, 00000000h + mov dword ptr ds:[pcmach1+2], 00000000h + mov word ptr ds:[pcmach2+0], 0c98bh ;8bc9 = mov ecx, ecx +skipsetuppc1: + ret + +PUBLIC pctimerhandler_ +pctimerhandler_: + push eax + mov ax, DGROUP + push ds + mov ds, ax + push edx + + mov edx, dword ptr _pcsndptr + mov al, byte ptr [edx] + out 42h, al + inc edx + mov dword ptr _pcsndptr, edx +pcmach1: dec _chainbackcnt ;samplediv +pcmach2: jz short pc3 + mov al, 20h + out 20h, al +pcmach3: cmp edx, 88888888h ;pcsndptrend + jge short pc1 + + pop edx + pop ds + pop eax + iretd + +pc1: xor byte ptr _bufferside, 1 + mov eax, _pcsndbufsiz + mov edx, _pcsndptr + jnz short pc2 + sub edx, eax + sub edx, eax + mov _pcsndptr, edx +pc2: add eax, edx + mov dword ptr ds:[pcmach3+2], eax + sti + call preparesndbuf_ + pop edx + pop ds + pop eax + iretd + +pc3: sti + cmp edx, dword ptr ds:[pcmach3+2] + jl short pc5 + + xor byte ptr _bufferside, 1 + mov eax, _pcsndbufsiz + mov edx, _pcsndptr + jnz short pc4 + sub edx, eax + sub edx, eax + mov _pcsndptr, edx +pc4: add eax, edx + mov dword ptr ds:[pcmach3+2], eax + sti + call preparesndbuf_ +pc5: + mov eax, _chainbackstart + mov _chainbackcnt, eax + pop edx + pop ds + pop eax + ;Must start interrupt handler like watcom c + pushad + push ds + push es + push fs + push gs + mov ebp, esp + cld + call __GETDS + mov dx, word ptr [_oldpctimerhandler+4] + mov eax, dword ptr [_oldpctimerhandler] + call _chain_intr_ + +PUBLIC pcbound2char_ +pcbound2char_: + push ebp + + add ecx, ecx + lea eax, [ecx+edi] + mov dword ptr ds:[pcmachchar+3], eax + xor edi, edi + sub edi, ecx + xor ecx, ecx + + xor edx, edx + mov ebp, 0ffff0000h +startpcbound2char: + mov ebx, dword ptr [esi] + mov eax, dword ptr [esi+4] + test ebx, ebp + jnz short pcboundit1 +pcboundit1back: + mov dl, bh + mov dword ptr [esi], 32768 + test eax, ebp + mov al, byte ptr _pcsndlookup[edx] + jnz short pcboundit2 +pcboundit2back: + mov dl, ah + mov dword ptr [esi+4], 32768 + mov ah, byte ptr _pcsndlookup[edx] + add esi, 8 +pcmachchar: mov word ptr [edi+88888888h], ax + add edi, 2 + jnc short startpcbound2char + pop ebp + ret +pcboundit1: + cmp ebx, 80000000h + sbb bh, bh + jmp short pcboundit1back +pcboundit2: + cmp eax, 80000000h + sbb ah, ah + jmp short pcboundit2back + + ;for(i=0;i>8); + ; if (j < 0) j = 0; + ; if (j > 255) j = 255; + ; *charptr++ = (char)j; + ;} +PUBLIC bound2char_ +bound2char_: + add ecx, ecx + lea eax, [ecx+edi] + mov dword ptr ds:[machchar+3], eax + xor edi, edi + sub edi, ecx + xor ecx, ecx + + mov edx, 0ffff0000h +startbound2char: + mov ebx, dword ptr [esi] + mov eax, dword ptr [esi+4] + test ebx, edx + jnz short boundchar1 +boundchar1back: + mov dword ptr [esi], 32768 + test eax, edx + jnz short boundchar2 +boundchar2back: + mov dword ptr [esi+4], 32768 + mov al, bh + add esi, 8 +machchar: mov word ptr [edi+88888888h], ax + add edi, 2 + jnc short startbound2char + ret +boundchar1: + cmp ebx, 80000000h + sbb bh, bh + jmp short boundchar1back +boundchar2: + cmp eax, 80000000h + sbb ah, ah + jmp short boundchar2back + + ;for(i=0;i 65535) j = 65535; + ; *shortptr++ = (short)(j^8000h); + ;} +PUBLIC bound2short_ +bound2short_: + shl ecx, 2 + lea eax, [ecx+edi] + mov dword ptr ds:[machshort+2], eax + xor edi, edi + sub edi, ecx + xor ecx, ecx + + mov edx, 0ffff0000h +startbound2short: + mov ebx, dword ptr [esi] + mov eax, dword ptr [esi+4] + test ebx, edx + jnz short boundshort1 +boundshort1back: + mov dword ptr [esi], 32768 + test eax, edx + jnz short boundshort2 +boundshort2back: + shl eax, 16 + mov dword ptr [esi+4], 32768 + mov ax, bx + add esi, 8 + xor eax, 80008000h +machshort: mov dword ptr [edi+88888888h], eax + add edi, 4 + jnc short startbound2short + ret +boundshort1: + cmp ebx, 80000000h + sbb ebx, ebx + jmp short boundshort1back +boundshort2: + cmp eax, 80000000h + sbb eax, eax + jmp short boundshort2back + +CODE ENDS +END diff --git a/buildengine/kdmeng.c b/buildengine/kdmeng.c new file mode 100755 index 0000000..82f2e33 --- /dev/null +++ b/buildengine/kdmeng.c @@ -0,0 +1,1386 @@ +// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman +// Ken Silverman's official web site: "http://www.advsys.net/ken" +// See the included license file "BUILDLIC.TXT" for license info. +// This file has been modified from Ken Silverman's original release + +#include +#include +#include +#include +#include +#include +#include + +#include "platform.h" +#include "pragmas.h" +#include "cache1d.h" + + +#if (!defined PLATFORM_DOS) +#error This should only be compiled for the DOS/386 target. +#endif + + +#define NUMCHANNELS 16 +#define MAXWAVES 256 +#define MAXTRACKS 256 +#define MAXNOTES 8192 +#define MAXEFFECTS 16 + + //Actual sound parameters after initsb was called +long samplerate, numspeakers, bytespersample, intspersec, kdmqual; + + //KWV wave variables +long numwaves; +char instname[MAXWAVES][16]; +long wavleng[MAXWAVES]; +long repstart[MAXWAVES], repleng[MAXWAVES]; +long finetune[MAXWAVES]; + + //Other useful wave variables +long totsndbytes, totsndmem, wavoffs[MAXWAVES]; + + //Effects array +long eff[MAXEFFECTS][256]; + + //KDM song variables: +long kdmversionum, numnotes, numtracks; +char trinst[MAXTRACKS], trquant[MAXTRACKS]; +char trvol1[MAXTRACKS], trvol2[MAXTRACKS]; +long nttime[MAXNOTES]; +char nttrack[MAXNOTES], ntfreq[MAXNOTES]; +char ntvol1[MAXNOTES], ntvol2[MAXNOTES]; +char ntfrqeff[MAXNOTES], ntvoleff[MAXNOTES], ntpaneff[MAXNOTES]; + + //Other useful song variables: +long timecount, notecnt, musicstatus, musicrepeat; + +long kdmasm1, kdmasm2, kdmasm3, kdmasm4; + +static char digistat = 0, musistat = 0; + +char *snd = NULL, kwvname[20] = {""}; + +#define MAXBYTESPERTIC 1024+128 +static long stemp[MAXBYTESPERTIC]; + + //Sound reading information +long splc[NUMCHANNELS], sinc[NUMCHANNELS], soff[NUMCHANNELS]; +long svol1[NUMCHANNELS], svol2[NUMCHANNELS]; +long volookup[NUMCHANNELS<<9]; +long swavenum[NUMCHANNELS]; +long frqeff[NUMCHANNELS], frqoff[NUMCHANNELS]; +long voleff[NUMCHANNELS], voloff[NUMCHANNELS]; +long paneff[NUMCHANNELS], panoff[NUMCHANNELS]; + +static long globposx, globposy, globxvect, globyvect; +static long xplc[NUMCHANNELS], yplc[NUMCHANNELS], vol[NUMCHANNELS]; +static long vdist[NUMCHANNELS], sincoffs[NUMCHANNELS]; +static char chanstat[NUMCHANNELS]; + +long frqtable[256]; + +static long mixerval = 0; + +static long kdminprep = 0, kdmintinprep = 0; +static long dmacheckport, dmachecksiz; + +void (__interrupt __far *oldsbhandler)(); +void __interrupt __far sbhandler(void); + +long samplediv, oldtimerfreq, chainbackcnt, chainbackstart; +char *pcsndptr, pcsndlookup[256], bufferside; +long samplecount, pcsndbufsiz, pcrealmodeint; +static short kdmvect = 0x8; +static unsigned short kdmpsel, kdmrseg, kdmroff; +static unsigned long kdmpoff; + +void (__interrupt __far *oldpctimerhandler)(); +#define KDMCODEBYTES 256 +static char pcrealbuffer[KDMCODEBYTES] = //See pckdm.asm +{ + 0x50,0x53,0x51,0x52,0x32,0xC0,0xE6,0x42,0xB0,0x20, + 0xE6,0x20,0x5A,0x59,0x5B,0x58,0xCF, +}; + + //Sound interrupt information +long sbport = 0x220, sbirq = 0x7, sbdma8 = 0x1, sbdma16 = 0x1; +char dmapagenum[8] = {0x87,0x83,0x81,0x82,0x8f,0x8b,0x89,0x8a}; +long sbdma, sbver; +unsigned short sndselector; +volatile long sndoffs, sndoffsplc, sndoffsxor, sndplc, sndend; +static long bytespertic, sndbufsiz; + +char qualookup[512*16]; +long ramplookup[64]; + +unsigned short sndseg = 0; + +#ifdef PLATFORM_DOS +extern long monolocomb(long,long,long,long,long,long); +#pragma aux monolocomb parm [eax][ebx][ecx][edx][esi][edi]; +extern long monohicomb(long,long,long,long,long,long); +#pragma aux monohicomb parm [eax][ebx][ecx][edx][esi][edi]; +extern long stereolocomb(long,long,long,long,long,long); +#pragma aux stereolocomb parm [eax][ebx][ecx][edx][esi][edi]; +extern long stereohicomb(long,long,long,long,long,long); +#pragma aux stereohicomb parm [eax][ebx][ecx][edx][esi][edi]; +extern long setuppctimerhandler(long,long,long,long,long,long); +#pragma aux setuppctimerhandler parm [eax][ebx][ecx][edx][esi][edi]; +extern void interrupt pctimerhandler(); +extern long pcbound2char(long,long,long); +#pragma aux pcbound2char parm [ecx][esi][edi]; +extern long bound2char(long,long,long); +#pragma aux bound2char parm [ecx][esi][edi]; +extern long bound2short(long,long,long); +#pragma aux bound2short parm [ecx][esi][edi]; + +static long oneshr10 = 0x3a800000, oneshl14 = 0x46800000; +void fsin(long *i1); +#pragma aux fsin =\ + "fldpi",\ + "fimul dword ptr [eax]",\ + "fmul dword ptr [oneshr10]",\ + "fsin",\ + "fmul dword ptr [oneshl14]",\ + "fistp dword ptr [eax]",\ + parm [eax]\ + +unsigned short convallocate(long i1); +#pragma aux convallocate =\ + "mov ax, 0x100",\ + "int 0x31",\ + "jnc nocarry",\ + "mov ax, 0",\ + "nocarry: mov sndselector, dx",\ + parm [bx]\ + modify [eax edx]\ + +void convdeallocate(long i1); +#pragma aux convdeallocate =\ + "mov ax, 0x101",\ + "mov dx, sndselector",\ + "int 0x31",\ + parm [dx]\ + modify [eax edx]\ + +long resetsb(void); +#pragma aux resetsb =\ + "mov edx, sbport",\ + "add edx, 0x6",\ + "mov al, 1",\ + "out dx, al",\ + "xor al, al",\ + "delayreset: dec al",\ + "jnz delayreset",\ + "out dx, al",\ + "mov ecx, 65536",\ + "empty: mov edx, sbport",\ + "add edx, 0xe",\ + "in al, dx",\ + "test al, al",\ + "jns nextattempt",\ + "sub dl, 4",\ + "in al, dx",\ + "cmp al, 0aah",\ + "je resetok",\ + "dec ecx",\ + "nextattempt: jnz empty",\ + "mov eax, -1",\ + "jmp resetend",\ + "resetok: xor eax, eax",\ + "resetend:",\ + modify [ebx ecx edx]\ + +long sbin(void); +#pragma aux sbin =\ + "xor eax, eax",\ + "mov dx, word ptr sbport[0]",\ + "add dl, 0xe",\ + "busy: in al, dx",\ + "or al, al",\ + "jns busy",\ + "sub dl, 4",\ + "in al, dx",\ + modify [edx]\ + +void sbout(long i1); +#pragma aux sbout =\ + "mov dx, word ptr sbport[0]",\ + "add dl, 0xc",\ + "mov ah, al",\ + "busy: in al, dx",\ + "or al, al",\ + "js busy",\ + "mov al, ah",\ + "out dx, al",\ + parm [eax]\ + modify [edx]\ + +long sbmixin(long); +#pragma aux sbmixin =\ + "mov dx, word ptr sbport[0]",\ + "add dl, 0x4",\ + "out dx, al",\ + "inc dx",\ + "xor eax, eax",\ + "in al, dx",\ + parm [eax]\ + modify [edx]\ + +void sbmixout(long i1, long i2); +#pragma aux sbmixout =\ + "mov dx, word ptr sbport[0]",\ + "add dl, 0x4",\ + "out dx, al",\ + "inc dx",\ + "mov al, bl",\ + "out dx, al",\ + parm [eax][ebx]\ + modify [edx]\ + +void findpas(void); +#pragma aux findpas =\ + "mov eax, 0x0000bc00",\ + "mov ebx, 0x00003f3f",\ + "int 0x2f",\ + "xor bx, cx",\ + "xor bx, dx",\ + "cmp bx, 0x4d56",\ + "stc",\ + "jne nopasfound",\ + "mov eax, 0x0000bc04",\ + "int 0x2f",\ + "mov edx, 0x0000ffff",\ + "and ebx, edx",\ + "and ecx, edx",\ + "mov sbdma, ebx",\ + "mov sbirq, ecx",\ + "clc",\ + "nopasfound:",\ + "sbb eax, eax",\ + modify [eax ebx ecx edx]\ + +void calcvolookupmono(long i1, long i2, long i3); +#pragma aux calcvolookupmono =\ + "mov ecx, 64",\ + "lea edx, [eax+ebx]",\ + "add ebx, ebx",\ + "begit: mov dword ptr [edi], eax",\ + "mov dword ptr [edi+4], edx",\ + "add eax, ebx",\ + "add edx, ebx",\ + "mov dword ptr [edi+8], eax",\ + "mov dword ptr [edi+12], edx",\ + "add eax, ebx",\ + "add edx, ebx",\ + "add edi, 16",\ + "dec ecx",\ + "jnz begit",\ + parm [edi][eax][ebx]\ + modify [ecx edx]\ + +void calcvolookupstereo(long i1, long i2, long i3, long i4, long i5); +#pragma aux calcvolookupstereo =\ + "mov esi, 128",\ + "begit: mov dword ptr [edi], eax",\ + "mov dword ptr [edi+4], ecx",\ + "add eax, ebx",\ + "add ecx, edx",\ + "mov dword ptr [edi+8], eax",\ + "mov dword ptr [edi+12], ecx",\ + "add eax, ebx",\ + "add ecx, edx",\ + "add edi, 16",\ + "dec esi",\ + "jnz begit",\ + parm [edi][eax][ebx][ecx][edx]\ + modify [esi]\ + +long gettimerval(void); +#pragma aux gettimerval =\ + "xor eax, eax",\ + "xor ebx, ebx",\ + "mov ecx, 65536",\ + "xor edx, edx",\ + "loopit: mov al, 0x4",\ + "out 0x43, al",\ + "in al, 0x40",\ + "mov dl, al",\ + "in al, 0x40",\ + "mov dh, al",\ + "cmp ebx, edx",\ + "dec ecx",\ + "ja loopit",\ + "jz endit",\ + "mov ebx, edx",\ + "jmp loopit",\ + "endit: mov eax, ebx",\ + modify [eax ebx ecx edx]\ + +#pragma aux klabs =\ + "test eax, eax",\ + "jns skipnegate",\ + "neg eax",\ + "skipnegate:",\ + parm [eax]\ + +#pragma aux mulscale16 =\ + "imul ebx",\ + "shrd eax, edx, 16",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +#pragma aux mulscale24 =\ + "imul ebx",\ + "shrd eax, edx, 24",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +#pragma aux mulscale30 =\ + "imul ebx",\ + "shrd eax, edx, 30",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +#pragma aux dmulscale28 =\ + "imul edx",\ + "mov ebx, eax",\ + "mov eax, esi",\ + "mov esi, edx",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, esi",\ + "shrd eax, edx, 28",\ + parm nomemory [eax][edx][esi][edi]\ + modify exact [eax ebx edx esi]\ + +#pragma aux clearbuf =\ + "snot: mov dword ptr [edi], eax",\ + "add edi, 4",\ + "loop snot",\ + parm [edi][ecx][eax]\ + +#pragma aux copybuf =\ + "snot: mov eax, dword ptr [esi]",\ + "mov dword ptr [edi], eax",\ + "add esi, 4",\ + "add edi, 4",\ + "loop snot",\ + parm [esi][edi][ecx]\ + modify [eax]\ + +#pragma aux koutp =\ + "out dx, al",\ + parm [edx][eax]\ + +#pragma aux koutpw =\ + "out dx, ax",\ + parm [edx][eax]\ + +#pragma aux kinp =\ + "xor eax, eax",\ + "in al, dx",\ + parm [edx]\ + +#pragma aux msqrtasm =\ + "mov eax, 0x40000000",\ + "mov ebx, 0x20000000",\ + "begit: cmp ecx, eax",\ + "jl skip",\ + "sub ecx, eax",\ + "lea eax, [eax+ebx*4]",\ + "skip: sub eax, ebx",\ + "shr eax, 1",\ + "shr ebx, 2",\ + "jnz begit",\ + "cmp ecx, eax",\ + "sbb eax, -1",\ + "shr eax, 1",\ + parm nomemory [ecx]\ + modify exact [eax ebx ecx] +#endif + +void initsb(char dadigistat, char damusistat, long dasamplerate, char danumspeakers, char dabytespersample, char daintspersec, char daquality) +{ +// DDOI - this should probably be stubbed in sdl_driver.c +#ifdef PLATFORM_DOS + long i, j, k; + + digistat = dadigistat; + musistat = damusistat; + + if ((digistat == 0) && (musistat != 1)) + return; + + samplerate = dasamplerate; + if (samplerate < 6000) samplerate = 6000; + if (samplerate > 48000) samplerate = 48000; + numspeakers = danumspeakers; + if (numspeakers < 1) numspeakers = 1; + if (numspeakers > 2) numspeakers = 2; + bytespersample = dabytespersample; + if (bytespersample < 1) bytespersample = 1; + if (bytespersample > 2) bytespersample = 2; + intspersec = daintspersec; + if (intspersec < 1) intspersec = 1; + if (intspersec > 120) intspersec = 120; + kdmqual = daquality; + if (kdmqual < 0) kdmqual = 0; + if (kdmqual > 1) kdmqual = 1; + + switch(digistat) + { + case 1: + getsbset(); + if (resetsb() != 0) { digistat = musistat = 0; break; } + + sbout(0xe1); + sbver = (sbin()<<8); + sbver += sbin(); + + if (sbver < 0x0201) samplerate = min(samplerate,22050); + if (sbver < 0x0300) numspeakers = 1; + if (sbver < 0x0400) + { + samplerate = min(samplerate,44100>>(numspeakers-1)); + bytespersample = 1; + } + + if (bytespersample == 2) sbdma = sbdma16; else sbdma = sbdma8; + + break; + case 2: + findpas(); // If == -1 then print not found & quit + koutp(0xf8a,128); + break; + case 13: + if (numspeakers == 2) numspeakers = 1; + if (bytespersample == 2) bytespersample = 1; + break; + } + + bytespertic = (((samplerate/120)+1)&~1); + sndbufsiz = bytespertic*(120/intspersec); + + if (sndseg == 0) //Allocate DMA buffer in conventional memory + { + if ((sndseg = convallocate(((sndbufsiz<<(bytespersample+numspeakers))+15)>>4)) == 0) + { + printf("Could not allocation conventional memory for digitized music\n"); + exit(0); + } + sndoffs = (((long)sndseg)<<4); + + if ((sndoffs&65535)+(sndbufsiz<<(bytespersample+numspeakers-1)) >= 65536) //64K DMA page check + sndoffs += (sndbufsiz<<(bytespersample+numspeakers-1)); + + sndoffsplc = sndoffs; + sndoffsxor = sndoffsplc ^ (sndoffsplc+(sndbufsiz<<(bytespersample+numspeakers-2))); + } + + j = (((11025L*2093)/samplerate)<<13); + for(i=1;i<76;i++) + { + frqtable[i] = j; + j = mulscale30(j,1137589835); //(pow(2,1/12)<<30) = 1137589835 + } + for(i=0;i>=-14;i--) frqtable[i&255] = (frqtable[(i+12)&255]>>1); + + loadwaves("WAVES.KWV"); + + timecount = notecnt = musicstatus = musicrepeat = 0; + + clearbuf((void *)(FP_OFF(stemp)),sizeof(stemp)>>2,32768L); + for(i=0;i<256;i++) + for(j=0;j<16;j++) + { + qualookup[(j<<9)+i] = (((-i)*j+8)>>4); + qualookup[(j<<9)+i+256] = (((256-i)*j+8)>>4); + } + for(i=0;i<(samplerate>>11);i++) + { + j = 1536 - (i<<10)/(samplerate>>11); + fsin(&j); + ramplookup[i] = ((16384-j)<<1); + } + + for(i=0;i<256;i++) + { + j = i*90; fsin(&j); + eff[0][i] = 65536+j/9; + eff[1][i] = min(58386+((i*(65536-58386))/30),65536); + eff[2][i] = max(69433+((i*(65536-69433))/30),65536); + j = (i*2048)/120; fsin(&j); + eff[3][i] = 65536+(j<<2); + j = (i*2048)/30; fsin(&j); + eff[4][i] = 65536+j; + switch((i>>1)%3) + { + case 0: eff[5][i] = 65536; break; + case 1: eff[5][i] = 65536*330/262; break; + case 2: eff[5][i] = 65536*392/262; break; + } + eff[6][i] = min((i<<16)/120,65536); + eff[7][i] = max(65536-(i<<16)/120,0); + } + + switch(digistat) + { + case 1: case 2: + if (sbirq < 8) + { + oldsbhandler = _dos_getvect(sbirq+0x8); //Set new IRQ7 vector + _disable(); _dos_setvect(sbirq+0x8, sbhandler); _enable(); + koutp(0x21,kinp(0x21) & ~(1<<(sbirq&7))); + } + else + { + oldsbhandler = _dos_getvect(sbirq+0x68); //Set new SB IRQ vector + _disable(); _dos_setvect(sbirq+0x68, sbhandler); _enable(); + koutp(0xa1,kinp(0xa1) & ~(1<<(sbirq&7))); + } + break; + } + + musicoff(); + + if (digistat != 255) + { + preparesndbuf(); + if (digistat != 13) preparesndbuf(); + + if ((digistat == 1) || (digistat == 2)) + { + if (sbdma < 4) + { + dmacheckport = (sbdma<<1)+1; + dmachecksiz = (sndbufsiz<<(bytespersample+numspeakers-1))-1; + + koutp(0xa,sbdma+4); //Set up DMA REGISTERS + koutp(0xc,0); + koutp(0xb,0x58+sbdma); //&H58 - auto-init, &H48 - 1 block only + koutp(sbdma<<1,sndoffs&255); + koutp(sbdma<<1,(sndoffs>>8)&255); + koutp(dmacheckport,dmachecksiz&255); + koutp(dmacheckport,(dmachecksiz>>8)&255); + koutp(dmapagenum[sbdma],((sndoffs>>16)&255)); + koutp(0xa,sbdma); + } + else + { + dmacheckport = ((sbdma&3)<<2)+0xc2; + dmachecksiz = ((sndbufsiz<<(bytespersample+numspeakers-1))>>1)-1; + + koutp(0xd4,sbdma); //Set up DMA REGISTERS + koutp(0xd8,0); + koutp(0xd6,0x58+(sbdma&3)); //&H58 - auto-init, &H48 - 1 block only + koutp(dmacheckport-2,(sndoffs>>1)&255); + koutp(dmacheckport-2,((sndoffs>>1)>>8)&255); + koutp(dmacheckport,dmachecksiz&255); + koutp(dmacheckport,(dmachecksiz>>8)&255); + koutp(dmapagenum[sbdma],((sndoffs>>16)&255)); + koutp(0xd4,sbdma&3); + } + } + + switch(digistat) + { + case 1: + sbout(0xd1); //SB Speaker on + + if (sbver < 0x0400) + { + sbout(0x40); //SB Set speed + sbout(256-(1000000/(samplerate<<(numspeakers-1)))); + } + + if (sbver < 0x0200) + { + sbout(0x14); //SB 1-shot mode + i = sndbufsiz-1; + sbout(i&255); + sbout((i>>8)&255); + } + else + { + if (sbver < 0x0400) + { + //Set length for auto-init mode + i = (sndbufsiz<<(numspeakers+bytespersample-2))-1; + sbout(0x48); + sbout(i&255); + sbout((i>>8)&255); + if (numspeakers == 2) //SB set stereo + { + sbmixout(0L,0L); + sbmixout(0xe,sbmixin(0xe)|2); + } + if ((samplerate<<(numspeakers-1)) <= 22050) + sbout(0x1c); //Start SB interrupts! + else + sbout(0x90); //High Speed DMA + } + else + { + sbout(0x41); + sbout((samplerate>>8)&255); + sbout(samplerate&255); + + sbout(0xc6-((bytespersample-1)<<4)); + sbout(((bytespersample-1)<<4)+((numspeakers-1)<<5)); + i = (sndbufsiz<<(numspeakers-1))-1; + sbout(i&255); + sbout((i>>8)&255); + } + } + break; + case 2: + koutp(0xf88,128); + koutp(0xb8a,0); + + i = (1193180L>>(numspeakers-1)) / samplerate; + koutp(0x138b,0x36); koutp(0x1388,i&255); koutp(0x1388,i>>8); + i = (sndbufsiz<<(bytespersample+numspeakers-2)); + koutp(0x138b,0x74); koutp(0x1389,i&255); koutp(0x1389,i>>8); + + koutp(0x8389,0x3+((bytespersample-1)<<2)); //0x3=8bit/0x7=16bit + koutp(0xb89,0xdf); + koutp(0xb8b,0x8); + koutp(0xf8a,0xd9+((2-numspeakers)<<5)); //0xd9=play/0xc9=record + koutp(0xb8a,0xe1); + break; + case 13: + samplecount = sndbufsiz; + pcsndptr = (char *)sndoffs; + bufferside = 0; + pcsndbufsiz = sndbufsiz; + pcrealmodeint = 0; + + samplediv = 1193280L / samplerate; + + j = 0; + for(i=0;i<256;i++) + { + //Scale (65536 normal) + k = mulscale24(j-(samplediv<<7),160000) + (samplediv>>1); + if (k < 0) k = 0; + if (k > samplerate) k = samplerate; + pcsndlookup[i] = (char)(k+1); + j += samplediv; + } + + oldtimerfreq = gettimerval(); + chainbackstart = oldtimerfreq/samplediv; + chainbackcnt = chainbackstart; + setuppctimerhandler(sndoffs+sndbufsiz,oldtimerfreq,0L,0L,0L,0L); + + _disable(); + oldpctimerhandler = _dos_getvect(0x8); + installbikdmhandlers(); + koutp(0x43,0x34); koutp(0x40,samplediv&255); koutp(0x40,(samplediv>>8)&255); + koutp(0x43,0x90); + koutp(97,kinp(97)|3); + _enable(); + break; + } + } +#else + fprintf(stderr, "%s line %d; initsb() called\n", __FILE__, __LINE__); +#endif +} + +void getsbset(void) +{ + char *sbset; + long i; + + sbset = getenv("BLASTER"); + + i = 0; + while (sbset[i] > 0) + { + switch(sbset[i]) + { + case 'A': case 'a': + i++; + sbport = 0; + while (((sbset[i] >= 48) && (sbset[i] <= 57)) || + ((sbset[i] >= 'A') && (sbset[i] <= 'F')) || + ((sbset[i] >= 'a') && (sbset[i] <= 'f'))) + { + sbport *= 16; + if ((sbset[i] >= 48) && (sbset[i] <= 57)) sbport += sbset[i]-48; + if ((sbset[i] >= 'A') && (sbset[i] <= 'F')) sbport += sbset[i]-55; + if ((sbset[i] >= 'a') && (sbset[i] <= 'f')) sbport += sbset[i]-55-32; + i++; + } + break; + case 'I': case 'i': + i++; + sbirq = 0; + while ((sbset[i] >= 48) && (sbset[i] <= 57)) + { + sbirq *= 10; + sbirq += sbset[i]-48; + i++; + } + break; + case 'D': case 'd': + i++; + sbdma8 = 0; + while ((sbset[i] >= 48) && (sbset[i] <= 57)) + { + sbdma8 *= 10; + sbdma8 += sbset[i]-48; + i++; + } + break; + case 'H': case 'h': + i++; + sbdma16 = 0; + while ((sbset[i] >= 48) && (sbset[i] <= 57)) + { + sbdma16 *= 10; + sbdma16 += sbset[i]-48; + i++; + } + break; + default: + i++; + break; + } + } +} + +#ifdef PLATFORM_DOS +void __interrupt __far sbhandler() +{ + switch(digistat) + { + case 1: + if (sbver < 0x0200) + { + sbout(0x14); //SB 1-shot mode + sbout((sndbufsiz-1)&255); + sbout(((sndbufsiz-1)>>8)&255); + kinp(sbport+0xe); //Acknowledge SB + } + else + { + mixerval = sbmixin(0x82); + if (mixerval&1) kinp(sbport+0xe); //Acknowledge 8-bit DMA + if (mixerval&2) kinp(sbport+0xf); //Acknowledge 16-bit DMA + } + break; + case 2: + if ((kinp(0xb89)&8) > 0) koutp(0xb89,0); + break; + } + if (sbirq >= 8) koutp(0xa0,0x20); + koutp(0x20,0x20); + _enable(); preparesndbuf(); +} +#endif + +uninitsb() +{ +#ifdef PLATFORM_DOS + if ((digistat == 0) && (musistat != 1)) + return; + + if (digistat != 255) + { + if ((digistat == 1) || (digistat == 2)) //Mask off DMA + { + if (sbdma < 4) koutp(0xa,sbdma+4); else koutp(0xd4,sbdma); + } + + switch(digistat) + { + case 1: + if (sbver >= 0x0400) sbout(0xda-(bytespersample-1)); + resetsb(); + sbout(0xd3); //Turn speaker off + break; + case 2: + koutp(0xb8a,32); //Stop interrupts + koutp(0xf8a,0x9); //DMA stop + break; + case 13: + koutp(97,kinp(97)&252); + koutp(0x43,0x34); koutp(0x40,0); koutp(0x40,0); + koutp(0x43,0xbc); + uninstallbikdmhandlers(); + break; + } + } + + if (snd != 0) free(snd), snd = 0; + if (sndseg != 0) convdeallocate(sndseg), sndseg = 0; + + switch(digistat) + { + case 1: case 2: + if (sbirq < 8) + { + koutp(0x21,kinp(0x21) | (1<<(sbirq&7))); + _disable(); _dos_setvect(sbirq+0x8, oldsbhandler); _enable(); + } + else + { + koutp(0xa1,kinp(0xa1) | (1<<(sbirq&7))); + _disable(); _dos_setvect(sbirq+0x68, oldsbhandler); _enable(); + } + break; + } +#else + fprintf (stderr, "%s line %d, uninitsb() called\n",__FILE__,__LINE__); +#endif +} + +void startwave(long wavnum, long dafreq, long davolume1, long davolume2, long dafrqeff, long davoleff, long dapaneff) +{ + long i, /*j,*/ chanum; + + if ((davolume1|davolume2) == 0) return; + + chanum = 0; + for(i=NUMCHANNELS-1;i>0;i--) + if (splc[i] > splc[chanum]) + chanum = i; + + splc[chanum] = 0; //Disable channel temporarily for clean switch + + if (numspeakers == 1) + calcvolookupmono(FP_OFF(volookup)+(chanum<<(9+2)),-(davolume1+davolume2)<<6,(davolume1+davolume2)>>1); + else + calcvolookupstereo(FP_OFF(volookup)+(chanum<<(9+2)),-(davolume1<<7),davolume1,-(davolume2<<7),davolume2); + + sinc[chanum] = dafreq; + svol1[chanum] = davolume1; + svol2[chanum] = davolume2; + soff[chanum] = wavoffs[wavnum]+wavleng[wavnum]; + splc[chanum] = -(wavleng[wavnum]<<12); //splc's modified last + swavenum[chanum] = wavnum; + frqeff[chanum] = dafrqeff; frqoff[chanum] = 0; + voleff[chanum] = davoleff; voloff[chanum] = 0; + paneff[chanum] = dapaneff; panoff[chanum] = 0; + chanstat[chanum] = 0; sincoffs[chanum] = 0; +} + +void setears(long daposx, long daposy, long daxvect, long dayvect) +{ + globposx = daposx; + globposy = daposy; + globxvect = daxvect; + globyvect = dayvect; +} + +void wsayfollow(char *dafilename, long dafreq, long davol, long *daxplc, long *dayplc, char followstat) +{ + char ch1, ch2, bad; + long i, wavnum, chanum; + + if (digistat == 0) return; + if (davol <= 0) return; + + for(wavnum=numwaves-1;wavnum>=0;wavnum--) + { + bad = 0; + + i = 0; + while ((dafilename[i] > 0) && (i < 16)) + { + ch1 = dafilename[i]; if ((ch1 >= 97) && (ch1 <= 123)) ch1 -= 32; + ch2 = instname[wavnum][i]; if ((ch2 >= 97) && (ch2 <= 123)) ch2 -= 32; + if (ch1 != ch2) {bad = 1; break;} + i++; + } + if (bad != 0) continue; + + chanum = 0; + for(i=NUMCHANNELS-1;i>0;i--) if (splc[i] > splc[chanum]) chanum = i; + + splc[chanum] = 0; //Disable channel temporarily for clean switch + + if (followstat == 0) + { + xplc[chanum] = *daxplc; + yplc[chanum] = *dayplc; + } + else + { + xplc[chanum] = ((long)daxplc); + yplc[chanum] = ((long)dayplc); + } + vol[chanum] = davol; + vdist[chanum] = 0; + sinc[chanum] = (dafreq*11025)/samplerate; + svol1[chanum] = davol; + svol2[chanum] = davol; + sincoffs[chanum] = 0; + soff[chanum] = wavoffs[wavnum]+wavleng[wavnum]; + splc[chanum] = -(wavleng[wavnum]<<12); //splc's modified last + swavenum[chanum] = wavnum; + chanstat[chanum] = followstat+1; + frqeff[chanum] = 0; frqoff[chanum] = 0; + voleff[chanum] = 0; voloff[chanum] = 0; + paneff[chanum] = 0; panoff[chanum] = 0; + return; + } +} + +void getsndbufinfo(long *dasndoffsplc, long *dasndbufsiz) +{ + *dasndoffsplc = sndoffsplc; + *dasndbufsiz = (sndbufsiz<<(bytespersample+numspeakers-2)); +} + +void preparesndbuf(void) +{ + long i, j, k, voloffs1, voloffs2, *stempptr; + long daswave, dasinc, dacnt; + long ox, oy, x, y; + //char *sndptr, v1, v2; + + kdmintinprep++; + if (kdminprep != 0) return; + + if ((digistat == 1) || (digistat == 2)) + { + i = kinp(dmacheckport); i += (kinp(dmacheckport)<<8); + if (i <= dmachecksiz) + { + i = ((i > 32) && (i <= (dmachecksiz>>1)+32)); + if ((sndoffsplc<(sndoffsplc^sndoffsxor)) == i) kdmintinprep++; + } + } + + kdminprep = 1; + while (kdmintinprep > 0) + { + sndoffsplc ^= sndoffsxor; + + for (i=NUMCHANNELS-1;i>=0;i--) + if ((splc[i] < 0) && (chanstat[i] > 0)) + { + if (chanstat[i] == 1) + { + ox = xplc[i]; + oy = yplc[i]; + } + else + { + stempptr = (long *)xplc[i]; ox = *stempptr; + stempptr = (long *)yplc[i]; oy = *stempptr; + } + ox -= globposx; oy -= globposy; + x = dmulscale28(oy,globxvect,-ox,globyvect); + y = dmulscale28(ox,globxvect,oy,globyvect); + + if ((klabs(x) >= 32768) || (klabs(y) >= 32768)) + { splc[i] = 0; continue; } + + j = vdist[i]; + vdist[i] = msqrtasm(x*x+y*y); + if (j) + { + j = (sinc[i]<<10)/(min(max(vdist[i]-j,-768),768)+1024)-sinc[i]; + sincoffs[i] = ((sincoffs[i]*7+j)>>3); + } + + voloffs1 = min((vol[i]<<22)/(((x+1536)*(x+1536)+y*y)+1),255); + voloffs2 = min((vol[i]<<22)/(((x-1536)*(x-1536)+y*y)+1),255); + + if (numspeakers == 1) + calcvolookupmono(FP_OFF(volookup)+(i<<(9+2)),-(voloffs1+voloffs2)<<6,(voloffs1+voloffs2)>>1); + else + calcvolookupstereo(FP_OFF(volookup)+(i<<(9+2)),-(voloffs1<<7),voloffs1,-(voloffs2<<7),voloffs2); + } + + for(dacnt=0;dacnt 0) //Gets here 120 times/second + { + while ((notecnt < numnotes) && (timecount >= nttime[notecnt])) + { + j = trinst[nttrack[notecnt]]; + k = mulscale24(frqtable[ntfreq[notecnt]],finetune[j]+748); + + if (ntvol1[notecnt] == 0) //Note off + { + for(i=NUMCHANNELS-1;i>=0;i--) + if (splc[i] < 0) + if (swavenum[i] == j) + if (sinc[i] == k) + splc[i] = 0; + } + else //Note on + startwave(j,k,ntvol1[notecnt],ntvol2[notecnt],ntfrqeff[notecnt],ntvoleff[notecnt],ntpaneff[notecnt]); + + notecnt++; + if (notecnt >= numnotes) + if (musicrepeat > 0) + notecnt = 0, timecount = nttime[0]; + } + timecount++; + } + + for(i=NUMCHANNELS-1;i>=0;i--) + { + if (splc[i] >= 0) continue; + + dasinc = sinc[i]+sincoffs[i]; + + if (frqeff[i] != 0) + { + dasinc = mulscale16(dasinc,eff[frqeff[i]-1][frqoff[i]]); + frqoff[i]++; if (frqoff[i] >= 256) frqeff[i] = 0; + } + if ((voleff[i]) || (paneff[i])) + { + voloffs1 = svol1[i]; + voloffs2 = svol2[i]; + if (voleff[i]) + { + voloffs1 = mulscale16(voloffs1,eff[voleff[i]-1][voloff[i]]); + voloffs2 = mulscale16(voloffs2,eff[voleff[i]-1][voloff[i]]); + voloff[i]++; if (voloff[i] >= 256) voleff[i] = 0; + } + + if (numspeakers == 1) + calcvolookupmono(FP_OFF(volookup)+(i<<(9+2)),-(voloffs1+voloffs2)<<6,(voloffs1+voloffs2)>>1); + else + { + if (paneff[i]) + { + voloffs1 = mulscale16(voloffs1,131072-eff[paneff[i]-1][panoff[i]]); + voloffs2 = mulscale16(voloffs2,eff[paneff[i]-1][panoff[i]]); + panoff[i]++; if (panoff[i] >= 256) paneff[i] = 0; + } + calcvolookupstereo(FP_OFF(volookup)+(i<<(9+2)),-(voloffs1<<7),voloffs1,-(voloffs2<<7),voloffs2); + } + } + + daswave = swavenum[i]; + voloffs1 = FP_OFF(volookup)+(i<<(9+2)); + + kdmasm1 = repleng[daswave]; + kdmasm2 = wavoffs[daswave]+repstart[daswave]+repleng[daswave]; + kdmasm3 = (repleng[daswave]<<12); //repsplcoff + kdmasm4 = soff[i]; + if (numspeakers == 1) + { + if (kdmqual == 0) splc[i] = monolocomb(0L,voloffs1,bytespertic,dasinc,splc[i],FP_OFF(stemp)); + else splc[i] = monohicomb(0L,voloffs1,bytespertic,dasinc,splc[i],FP_OFF(stemp)); + } + else + { + if (kdmqual == 0) splc[i] = stereolocomb(0L,voloffs1,bytespertic,dasinc,splc[i],FP_OFF(stemp)); + else splc[i] = stereohicomb(0L,voloffs1,bytespertic,dasinc,splc[i],FP_OFF(stemp)); + } + soff[i] = kdmasm4; + + if ((kdmqual == 0) || (splc[i] >= 0)) continue; + if (numspeakers == 1) + { + if (kdmqual == 0) monolocomb(0L,voloffs1,samplerate>>11,dasinc,splc[i],FP_OFF(stemp)+(bytespertic<<2)); + else monohicomb(0L,voloffs1,samplerate>>11,dasinc,splc[i],FP_OFF(stemp)+(bytespertic<<2)); + } + else + { + if (kdmqual == 0) stereolocomb(0L,voloffs1,samplerate>>11,dasinc,splc[i],FP_OFF(stemp)+(bytespertic<<3)); + else stereohicomb(0L,voloffs1,samplerate>>11,dasinc,splc[i],FP_OFF(stemp)+(bytespertic<<3)); + } + } + + if (kdmqual) + { + if (numspeakers == 1) + { + for(i=(samplerate>>11)-1;i>=0;i--) + stemp[i] += mulscale16(stemp[i+1024]-stemp[i],ramplookup[i]); + j = bytespertic; k = (samplerate>>11); + copybuf(&stemp[j],&stemp[1024],k); + clearbuf(&stemp[j],k,32768); + } + else + { + for(i=(samplerate>>11)-1;i>=0;i--) + { + j = (i<<1); + stemp[j+0] += mulscale16(stemp[j+1024]-stemp[j+0],ramplookup[i]); + stemp[j+1] += mulscale16(stemp[j+1025]-stemp[j+1],ramplookup[i]); + } + j = (bytespertic<<1); k = ((samplerate>>11)<<1); + copybuf(&stemp[j],&stemp[1024],k); + clearbuf(&stemp[j],k,32768); + } + } + + if (numspeakers == 1) + { + if (bytespersample == 1) + { + if (digistat == 13) pcbound2char(bytespertic>>1,FP_OFF(stemp),sndoffsplc+dacnt); + else bound2char(bytespertic>>1,FP_OFF(stemp),sndoffsplc+dacnt); + } else bound2short(bytespertic>>1,FP_OFF(stemp),sndoffsplc+(dacnt<<1)); + } + else + { + if (bytespersample == 1) bound2char(bytespertic,FP_OFF(stemp),sndoffsplc+(dacnt<<1)); + else bound2short(bytespertic,FP_OFF(stemp),sndoffsplc+(dacnt<<2)); + } + } + kdmintinprep--; + } + kdminprep = 0; +} + +void wsay(char *dafilename, long dafreq, long volume1, long volume2) +{ + unsigned char ch1, ch2; + long i, j, bad; + + if (digistat == 0) return; + + i = numwaves-1; + do + { + bad = 0; + + j = 0; + while ((dafilename[j] > 0) && (j < 16)) + { + ch1 = dafilename[j]; if ((ch1 >= 97) && (ch1 <= 123)) ch1 -= 32; + ch2 = instname[i][j]; if ((ch2 >= 97) && (ch2 <= 123)) ch2 -= 32; + if (ch1 != ch2) {bad = 1; break;} + j++; + } + if (bad == 0) + { + startwave(i,(dafreq*11025)/samplerate,volume1,volume2,0L,0L,0L); + return; + } + + i--; + } while (i >= 0); +} + +void loadwaves(char *wavename) +{ + long fil, i, j, dawaversionum; + char filename[80]; + + strcpy(filename,wavename); + if (strstr(filename,".KWV") == 0) strcat(filename,".KWV"); + if ((fil = kopen4load(filename,0)) == -1) + if (strcmp(filename,"WAVES.KWV") != 0) + { + strcpy(filename,"WAVES.KWV"); + fil = kopen4load(filename,0); + } + + totsndbytes = 0; + + if (fil != -1) + { + if (strcmp(kwvname,filename) == 0) { kclose(fil); return; } + strcpy(kwvname,filename); + + kread(fil,&dawaversionum,4); + if (dawaversionum != 0) { kclose(fil); return; } + + kread(fil,&numwaves,4); + for(i=0;i>4); //Number of paragraphs requested + int386(0x31,&r,&r); + + if (r.x.cflag != 0) //Failed + return ((long)0); + return ((long)((r.x.eax&0xffff)<<4)); //Returns full 32-bit offset +#else + fprintf (stderr, "%s line %d; kdmconvalloc32() called\n", __FILE__, + __LINE__); +#endif +} + +installbikdmhandlers() +{ +#ifdef PLATFORM_DOS + union REGS r; + struct SREGS sr; + long lowp; + void far *fh; + + //Get old protected mode handler + r.x.eax = 0x3500+kdmvect; /* DOS get vector (INT 0Ch) */ + sr.ds = sr.es = 0; + int386x(0x21,&r,&r,&sr); + kdmpsel = (unsigned short)sr.es; + kdmpoff = r.x.ebx; + + //Get old real mode handler + r.x.eax = 0x0200; /* DPMI get real mode vector */ + r.h.bl = kdmvect; + int386(0x31,&r,&r); + kdmrseg = (unsigned short)r.x.ecx; + kdmroff = (unsigned short)r.x.edx; + + + //Allocate memory in low memory to store real mode handler + if ((lowp = kdmconvalloc32(KDMCODEBYTES)) == 0) + { + printf("Can't allocate conventional memory.\n"); + exit; + } + memcpy((void *)lowp,(void *)pcrealbuffer,KDMCODEBYTES); + + //Set new protected mode handler + r.x.eax = 0x2500+kdmvect; /* DOS set vector (INT 0Ch) */ + fh = (void far *)pctimerhandler; + r.x.edx = FP_OFF(fh); + sr.ds = FP_SEG(fh); //DS:EDX == &handler + sr.es = 0; + int386x(0x21,&r,&r,&sr); + + //Set new real mode handler (must be after setting protected mode) + r.x.eax = 0x0201; + r.h.bl = kdmvect; //CX:DX == real mode &handler + r.x.ecx = ((lowp>>4)&0xffff); //D32realseg + r.x.edx = 0L; //D32realoff + int386(0x31,&r,&r); +#else + fprintf(stderr,"%s line %d; installbikdmhandlers() called\n", __FILE__, + __LINE__); +#endif +} + +uninstallbikdmhandlers() +{ +#ifdef PLATFORM_DOS + union REGS r; + struct SREGS sr; + + //restore old protected mode handler + r.x.eax = 0x2500+kdmvect; /* DOS set vector (INT 0Ch) */ + r.x.edx = kdmpoff; + sr.ds = kdmpsel; /* DS:EDX == &handler */ + sr.es = 0; + int386x(0x21,&r,&r,&sr); + + //restore old real mode handler + r.x.eax = 0x0201; /* DPMI set real mode vector */ + r.h.bl = kdmvect; + r.x.ecx = (unsigned long)kdmrseg; //CX:DX == real mode &handler + r.x.edx = (unsigned long)kdmroff; + int386(0x31,&r,&r); +#else + fprintf(stderr,"%s line %d; uninstallbikdmhandlers() called\n", + __FILE__, __LINE__); +#endif +} diff --git a/buildengine/kensig.map b/buildengine/kensig.map new file mode 100755 index 0000000..a08106a Binary files /dev/null and b/buildengine/kensig.map differ diff --git a/buildengine/mmulti.c b/buildengine/mmulti.c new file mode 100755 index 0000000..e95af84 --- /dev/null +++ b/buildengine/mmulti.c @@ -0,0 +1,1545 @@ +/* + * "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman + * Ken Silverman's official web site: "http://www.advsys.net/ken" + * See the included license file "BUILDLIC.TXT" for license info. + * This file has been modified from Ken Silverman's original release + */ + +#include +#include +#include +#include +#include + +#include "platform.h" + +#include "pragmas.h" + +#define MAXPLAYERS 16 +#define BAKSIZ 16384 +#define SIMULATEERRORS 0 +#define SHOWSENDPACKETS 0 +#define SHOWGETPACKETS 0 +#define PRINTERRORS 0 + +#define updatecrc16(crc,dat) crc = (((crc<<8)&65535)^crctable[((((unsigned short)crc)>>8)&65535)^dat]) + +static long incnt[MAXPLAYERS], outcntplc[MAXPLAYERS], outcntend[MAXPLAYERS]; +static char errorgotnum[MAXPLAYERS]; +static char errorfixnum[MAXPLAYERS]; +static char errorresendnum[MAXPLAYERS]; +#if (PRINTERRORS) + static char lasterrorgotnum[MAXPLAYERS]; +#endif + +long crctable[256]; + +static char lastpacket[576], inlastpacket = 0; +static short lastpacketfrom, lastpacketleng; + +extern long totalclock; /* MUST EXTERN 1 ANNOYING VARIABLE FROM GAME */ +static long timeoutcount = 60, resendagaincount = 4, lastsendtime[MAXPLAYERS]; + +static short bakpacketptr[MAXPLAYERS][256], bakpacketlen[MAXPLAYERS][256]; +static char bakpacketbuf[BAKSIZ]; +static long bakpacketplc = 0; + +short myconnectindex, numplayers; +short connecthead, connectpoint2[MAXPLAYERS]; +char syncstate = 0; + +extern int _argc; +extern char **_argv; + +#define MAXPACKETSIZE 2048 +typedef struct +{ + short intnum; /* communication between Game and the driver */ + short command; /* 1-send, 2-get */ + short other; /* dest for send, set by get (-1 = no packet) */ + short numbytes; + short myconnectindex; + short numplayers; + short gametype; /* gametype: 1-serial,2-modem,3-net */ + short filler; + char buffer[MAXPACKETSIZE]; + long longcalladdress; +} gcomtype; +static gcomtype *gcom; + +#define COMMIT_CMD_SEND 1 +#define COMMIT_CMD_GET 2 +#define COMMIT_CMD_SENDTOALL 3 +#define COMMIT_CMD_SENDTOALLOTHERS 4 +#define COMMIT_CMD_SCORE 5 + + +gcomtype *init_network_transport(char **ARGV, int argpos); +void deinit_network_transport(gcomtype *gcom); +void callcommit(void); + + +void initcrc(void) +{ + long i, j, k, a; + + for(j=0;j<256;j++) /* Calculate CRC table */ + { + k = (j<<8); a = 0; + for(i=7;i>=0;i--) + { + if (((k^a)&0x8000) > 0) + a = ((a<<1)&65535) ^ 0x1021; /* 0x1021 = genpoly */ + else + a = ((a<<1)&65535); + k = ((k<<1)&65535); + } + crctable[j] = (a&65535); + } +} + + +long getcrc(char *buffer, short bufleng) +{ + long i, j; + + j = 0; + for(i=bufleng-1;i>=0;i--) updatecrc16(j,buffer[i]); + return(j&65535); +} + +void initmultiplayers(char damultioption, char dacomrateoption, char dapriority) +{ + long i; + + initcrc(); + for(i=0;i 0; i--) + { + const char *arg = _argv[i]; + char ch = *arg; + if ((ch == '-') || (ch == '/')) + { + if (stricmp(arg + 1, "net") == 0) + break; + } + } + + if ((i == 0) || (i+1 == _argc)) + { + numplayers = 1; myconnectindex = 0; + connecthead = 0; connectpoint2[0] = -1; + return; + } + + gcom = init_network_transport(_argv, i+1); + if (gcom == NULL) + { + printf("Network transport initialization failed. Aborting...\n"); + exit(1); + } + + numplayers = gcom->numplayers; + myconnectindex = gcom->myconnectindex-1; +#if (SIMULATEERRORS != 0) + srand(myconnectindex*24572457+345356); +#endif + connecthead = 0; + for(i=0;i lasterrorgotnum[other]) + { + lasterrorgotnum[other]++; + printf(" MeWant %ld",incnt[other]&255); + } +#endif + + if (outcntplc[other]+1 == outcntend[other]) + { /* Send 1 sub-packet */ + k = 0; + gcom->buffer[k++] = (outcntplc[other]&255); + gcom->buffer[k++] = (errorgotnum[other]&7)+((errorresendnum[other]&7)<<3); + gcom->buffer[k++] = (incnt[other]&255); + + j = bakpacketptr[other][outcntplc[other]&255]; + messleng = bakpacketlen[other][outcntplc[other]&255]; + for(i=0;ibuffer[k++] = bakpacketbuf[(i+j)&(BAKSIZ-1)]; + outcntplc[other]++; + } + else + { /* Send 2 sub-packets */ + k = 0; + gcom->buffer[k++] = (outcntplc[other]&255); + gcom->buffer[k++] = (errorgotnum[other]&7)+((errorresendnum[other]&7)<<3)+128; + gcom->buffer[k++] = (incnt[other]&255); + + /* First half-packet */ + j = bakpacketptr[other][outcntplc[other]&255]; + messleng = bakpacketlen[other][outcntplc[other]&255]; + gcom->buffer[k++] = (char)(messleng&255); + gcom->buffer[k++] = (char)(messleng>>8); + for(i=0;ibuffer[k++] = bakpacketbuf[(i+j)&(BAKSIZ-1)]; + outcntplc[other]++; + + /* Second half-packet */ + j = bakpacketptr[other][outcntplc[other]&255]; + messleng = bakpacketlen[other][outcntplc[other]&255]; + for(i=0;ibuffer[k++] = bakpacketbuf[(i+j)&(BAKSIZ-1)]; + outcntplc[other]++; + + } + + dacrc = getcrc(gcom->buffer,k); + gcom->buffer[k++] = (dacrc&255); + gcom->buffer[k++] = (dacrc>>8); + + gcom->other = other+1; + gcom->numbytes = k; + +#if (SHOWSENDPACKETS) + printf("Send(%ld): ",gcom->other); + for(i=0;inumbytes;i++) printf("%2x ",gcom->buffer[i]); + printf("\n"); +#endif + +#if (SIMULATEERRORS != 0) + if (!(rand()&SIMULATEERRORS)) gcom->buffer[rand()%gcom->numbytes] = (rand()&255); + if (rand()&SIMULATEERRORS) +#endif + { gcom->command = 1; callcommit(); } +} + + +void sendpacket(long other, char *bufptr, long messleng) +{ + long i = 0; + long j = 0; + + if (numplayers < 2) return; + + i = 0; + if (bakpacketlen[other][(outcntend[other]-1)&255] == messleng) + { + j = bakpacketptr[other][(outcntend[other]-1)&255]; + for(i=messleng-1;i>=0;i--) + if (bakpacketbuf[(i+j)&(BAKSIZ-1)] != bufptr[i]) break; + } + bakpacketlen[other][outcntend[other]&255] = messleng; + + if (i < 0) /* Point to last packet to save space on bakpacketbuf */ + bakpacketptr[other][outcntend[other]&255] = j; + else + { + bakpacketptr[other][outcntend[other]&255] = bakpacketplc; + for(i=0;i=0;i=connectpoint2[i]) + if (i != myconnectindex) + sendpacket(i,tempbuf,2L); +} + +int getoutputcirclesize(void) +{ + return(0); +} + +void setsocket(short newsocket) +{ +} + + +short getpacket (short *other, char *bufptr) +{ + long i, messleng; + unsigned short dacrc; + + if (numplayers < 2) return(0); + + for(i=connecthead;i>=0;i=connectpoint2[i]) + if (i != myconnectindex) + { + if (totalclock < lastsendtime[i]) lastsendtime[i] = totalclock; + if (totalclock > lastsendtime[i]+timeoutcount) + { +#if (PRINTERRORS) + printf(" TimeOut!"); +#endif + errorgotnum[i] = errorfixnum[i]+1; + + if ((outcntplc[i] == outcntend[i]) && (outcntplc[i] > 0)) + { outcntplc[i]--; lastsendtime[i] = totalclock; } + else + lastsendtime[i] += resendagaincount; + dosendpackets(i); + /* } */ + } + } + + if (inlastpacket != 0) + { + /* 2ND half of good double-packet */ + inlastpacket = 0; + *other = lastpacketfrom; + memcpy(bufptr,lastpacket,lastpacketleng); + return(lastpacketleng); + } + + gcom->command = 2; + callcommit(); + +#if (SHOWGETPACKETS) + if (gcom->other != -1) + { + printf(" Get(%ld): ",gcom->other); + for(i=0;inumbytes;i++) printf("%2x ",gcom->buffer[i]); + printf("\n"); + } +#endif + + if (gcom->other < 0) return(0); + *other = gcom->other-1; + + messleng = gcom->numbytes; + + dacrc = ((unsigned short)gcom->buffer[messleng-2]); + dacrc += (((unsigned short)gcom->buffer[messleng-1])<<8); + if (dacrc != getcrc(gcom->buffer,messleng-2)) /* CRC check */ + { +#if (PRINTERRORS) + printf("\n%ld CRC",gcom->buffer[0]); +#endif + errorgotnum[*other] = errorfixnum[*other]+1; + return(0); + } + + while ((errorfixnum[*other]&7) != ((gcom->buffer[1]>>3)&7)) + errorfixnum[*other]++; + + if ((gcom->buffer[1]&7) != (errorresendnum[*other]&7)) + { + errorresendnum[*other]++; + outcntplc[*other] = (outcntend[*other]&0xffffff00)+gcom->buffer[2]; + if (outcntplc[*other] > outcntend[*other]) outcntplc[*other] -= 256; + } + + if (gcom->buffer[0] != (incnt[*other]&255)) /* CNT check */ + { + if (((incnt[*other]-gcom->buffer[0])&255) > 32) + { + errorgotnum[*other] = errorfixnum[*other]+1; +#if (PRINTERRORS) + printf("\n%ld CNT",gcom->buffer[0]); +#endif + } +#if (PRINTERRORS) + else + { + if (!(gcom->buffer[1]&128)) /* single else double packet */ + printf("\n%ld cnt",gcom->buffer[0]); + else + { + if (((gcom->buffer[0]+1)&255) == (incnt[*other]&255)) + { + /* GOOD! Take second half of double packet */ +#if (PRINTERRORS) + printf("\n%ld-%ld .û ",gcom->buffer[0],(gcom->buffer[0]+1)&255); +#endif + messleng = ((long)gcom->buffer[3]) + (((long)gcom->buffer[4])<<8); + lastpacketleng = gcom->numbytes-7-messleng; + memcpy(bufptr,&gcom->buffer[messleng+5],lastpacketleng); + incnt[*other]++; + return(lastpacketleng); + } + else + printf("\n%ld-%ld cnt ",gcom->buffer[0],(gcom->buffer[0]+1)&255); + } + } +#endif + return(0); + } + + /* PACKET WAS GOOD! */ + if ((gcom->buffer[1]&128) == 0) /* Single packet */ + { +#if (PRINTERRORS) + printf("\n%ld û ",gcom->buffer[0]); +#endif + + messleng = gcom->numbytes-5; + + memcpy(bufptr,&gcom->buffer[3],messleng); + + incnt[*other]++; + return(messleng); + } + + /* Double packet */ +#if (PRINTERRORS) + printf("\n%ld-%ld ûû ",gcom->buffer[0],(gcom->buffer[0]+1)&255); +#endif + + messleng = ((long)gcom->buffer[3]) + (((long)gcom->buffer[4])<<8); + lastpacketleng = gcom->numbytes-7-messleng; + inlastpacket = 1; lastpacketfrom = *other; + + memcpy(bufptr,&gcom->buffer[5],messleng); + memcpy(lastpacket,&gcom->buffer[messleng+5],lastpacketleng); + + incnt[*other] += 2; + return(messleng); +} + +void flushpackets() +{ +#if 0 + long i; + + if (numplayers < 2) return; + + do + { + gcom->command = 2; + callcommit(); + } while (gcom->other >= 0); + + for(i=connecthead;i>=0;i=connectpoint2[i]) + { + incnt[i] = 0L; + outcntplc[i] = 0L; + outcntend[i] = 0L; + errorgotnum[i] = 0; + errorfixnum[i] = 0; + errorresendnum[i] = 0; + lastsendtime[i] = totalclock; + } +#endif +} + +void genericmultifunction(long other, char *bufptr, long messleng, long command) +{ + if (numplayers < 2) return; + + gcom->command = command; + gcom->numbytes = min(messleng,MAXPACKETSIZE); + copybuf(bufptr,gcom->buffer,(gcom->numbytes+3)>>2); + gcom->other = other+1; + callcommit(); +} + + +#if STUB_NETWORKING +gcomtype *init_network_transport(char **ARGV, int argpos) +{ + printf("No networking support built in.\n"); + return NULL; +} /* init_network_transport */ + +void deinit_network_transport(gcomtype *gcom) +{ +} + +void callcommit(void) +{ +} + +#elif (defined PLATFORM_DOS) +gcomtype *init_network_transport(char **ARGV, int argpos) +{ + /* + * How to talk to COMMIT is passed as a pointer to a block of memory + * that COMMIT.EXE configures... + */ + return((gcomtype *)atol(ARGV[argpos])); /* UGH! --ryan. */ +} /* init_network_transport */ + +static union REGS regs; + +#pragma aux longcall =\ + "call eax",\ + parm [eax] + +void callcommit(void) +{ + if (gcom->intnum&0xff00) + longcall(gcom->longcalladdress); + else + int386(gcom->intnum,®s,®s); +} + +void deinit_network_transport(gcomtype *gcom) +{ + /* no-op, apparently. */ +} + + +#elif UDP_NETWORKING + +#if PLATFORM_WIN32 +# include +# define EAGAIN WSAEWOULDBLOCK +# define EWOULDBLOCK WSAEWOULDBLOCK +# define ECONNREFUSED WSAECONNRESET +# define socklen_t size_t +# define netstrerror() win32netstrerror() +# define neterrno() WSAGetLastError() +# define sockettype SOCKET +# define socketclose(x) closesocket(x) +#else +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# define netstrerror() strerror(errno) +# define neterrno() errno +# define sockettype int +# define socketclose(x) close(x) +# ifndef MSG_ERRQUEUE /* legacy glibc header workaround... */ +# define MSG_ERRQUEUE 0x2000 +# endif +# if PLATFORM_MACOSX +# define socklen_t int +# endif +#endif + +#define SOCKET_SHUTDOWN_BOTH 2 + +#include +#include "cache1d.h" /* kopen4load for cfg file. */ +#include "display.h" /* getticks */ + +#define IPSEG1(ip) ((((unsigned int) ip) & 0xFF000000) >> 24) +#define IPSEG2(ip) ((((unsigned int) ip) & 0x00FF0000) >> 16) +#define IPSEG3(ip) ((((unsigned int) ip) & 0x0000FF00) >> 8) +#define IPSEG4(ip) ((((unsigned int) ip) & 0x000000FF) ) + +#define MAX_PLAYERS 16 +#define BUILD_DEFAULT_UDP_PORT 1635 /* eh...why not? */ +#define CLIENT_POLL_DELAY 3000 /* ms between pings at peer-to-peer startup. */ +#define HEADER_PEER_GREETING 245 + +static sockettype udpsocket = -1; +static short udpport = BUILD_DEFAULT_UDP_PORT; + +static struct { + int host; + short port; +} allowed_addresses[MAX_PLAYERS]; /* only respond to these IPs. */ + +volatile int ctrlc_pressed = 0; +static void siginthandler(int sigint) +{ + ctrlc_pressed = 1; +} + +#if PLATFORM_WIN32 +/* + * Figure out what the last failing Win32 API call was, and + * generate a human-readable string for the error message. + * + * The return value is a static buffer that is overwritten with + * each call to this function. + * + * Code lifted from PhysicsFS: http://icculus.org/physfs/ + */ +static const char *win32netstrerror(void) +{ + static TCHAR msgbuf[255]; + TCHAR *ptr = msgbuf; + + FormatMessage( + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + WSAGetLastError(), /*GetLastError(),*/ + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */ + msgbuf, + sizeof (msgbuf) / sizeof (TCHAR), + NULL + ); + + /* chop off newlines. */ + for (ptr = msgbuf; *ptr; ptr++) + { + if ((*ptr == '\n') || (*ptr == '\r')) + { + *ptr = ' '; + break; + } /* if */ + } /* for */ + + return((const char *) msgbuf); +} /* win32strerror */ +#endif + + +typedef enum +{ + udpmode_peer, + udpmode_server, + udpmode_client +} udpmodes; +static udpmodes udpmode = udpmode_peer; + + +static char *static_ipstring(int ip) +{ + static char s[16]; + sprintf(s, "%u.%u.%u.%u", IPSEG1(ip), IPSEG2(ip), IPSEG3(ip), IPSEG4(ip)); + return(s); +} + + +static int send_udp_packet(int ip, short port, void *pkt, size_t pktsize) +{ + /* !!! FIXME: See if this would ever block. */ + /* !!! FIXME: See if this would send a partial packet. */ + struct sockaddr_in addr; + int rc; + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(ip); + addr.sin_port = htons(port); + + rc = sendto(udpsocket, pkt, pktsize, 0, + (struct sockaddr *) &addr, sizeof (addr)); + + if (rc != (int) pktsize) + { + printf("sendto err rc==%d when sending %d to %s:%d [%s].\n", + rc, (int) pktsize, static_ipstring(ip), (int) port, + netstrerror()); + return(0); + } + +/*printf("Sent %d byte packet to %s:%d\n", (int) pktsize, static_ipstring(ip), (int) port);*/ + + return(1); +} + + +static void process_udp_send_queue(void) +{ + /* Fill this in if the non-blocking socket becomes an issue. */ +} + + +static int get_udp_packet(int *ip, short *_port, void *pkt, size_t pktsize) +{ + int err = 0; + struct sockaddr_in addr; + short port; + socklen_t fromlen = sizeof (addr); + int valid = 0; + int i; + + /* FIXME: Will this ever receive a partial packet? */ + int rc = recvfrom(udpsocket, pkt, pktsize, 0, + (struct sockaddr *) &addr, &fromlen); + + if (rc == -1) + err = neterrno(); + +#if !PLATFORM_WIN32 + /* !!! FIXME: Linux specific? */ + if (rc == -1) /* fill in the addr structure on error... */ + { + socklen_t l = sizeof (addr); + recvfrom(udpsocket, NULL, 0, MSG_ERRQUEUE, + (struct sockaddr *) &addr, &l); + } +#endif + + *ip = ntohl(addr.sin_addr.s_addr); + port = ntohs(addr.sin_port); + if (_port) + *_port = port; + + /* + * Reject packets from unallowed IPs. Prevents (ha) DoS attacks and + * other confusion... + */ + if (gcom == NULL) + valid = 1; + else + { + for (i = 1; i <= gcom->numplayers; i++) + { + if ((allowed_addresses[i].host == *ip) && + (allowed_addresses[i].port == port)) + { + valid = i; + break; + } + } + } + + if (!valid) + { + /* + static int unallowed_ip_spam = 0; + if (unallowed_ip_spam <= 100) + { + printf("Packet received from unallowed IP %s:%d\n", + static_ipstring(*ip), (int) port); + if (unallowed_ip_spam == 100) + printf("(Disabling further unallowed IP spam.)\n"); + unallowed_ip_spam++; + } + */ + return(0); + } + + if (rc == -1) + { + if ((err == EAGAIN) || (err == EWOULDBLOCK)) + rc = 0; + + else if (err == ECONNREFUSED) /* "connection reset by peer" in winsock */ + { + /* + * This means that we sent a packet to an unopened port, and + * it responded by telling us to piss off. Take them out of the + * allowed list. We check gcom so that we don't worry about this + * during detection when game might still be loading elsewhere. + */ + if (gcom != NULL) + { + allowed_addresses[valid].host = 0; + printf("%s:%d refused packets. Removed from game.\n", + static_ipstring(*ip), (int) port); + } + /* !!! FIXME: Actually boot player, too. */ + } + + else + { + printf("recvfrom err rc==%d when getting %d from %s:%d [%s].\n", + rc, (int) pktsize, static_ipstring(*ip), (int) port, + netstrerror()); + } + } +/*else printf("Got %d byte packet from %s:%d\n", (int) rc, static_ipstring(*ip), (int) port);*/ + + return(rc); +} + + +static char *read_whole_file(const char *cfgfile) +{ + char *buf; + long len, rc; + long handle; + + if (cfgfile == NULL) + return(NULL); + + handle = kopen4load(cfgfile, 0); + if (handle == -1) + { + printf("ERROR: Failed to open config file [%s].\n", cfgfile); + return(NULL); + } + + len = kfilelength(handle); + buf = (char *) malloc(len + 2); + if (!buf) + { + kclose(handle); + return(NULL); + } + + rc = kread(handle, buf, len); + kclose(handle); + if (rc != len) + { + free(buf); + return(NULL); + } + + buf[len] = '\0'; + buf[len+1] = '\0'; + return(buf); +} + +static char *get_token(char **ptr) +{ + char *retval; + char *p = *ptr; + if (*p == '\0') + return(NULL); + + while ((*p != '\0') && (isspace(*p))) + p++; + + if (*p == '\0') /* nothing but whitespace. */ + return(NULL); + + retval = p; + while ((*p != '\0') && (!isspace(*p))) + p++; + + *p = '\0'; + *ptr = p + 1; + + /*printf("Got token [%s].\n", retval);*/ + return(retval); +} + +static int set_socket_blockmode(int onOrOff) +{ + int flags; + int rc = 0; + + /* set socket to be (non-)blocking. */ + +#if PLATFORM_WIN32 + flags = (onOrOff) ? 0 : 1; + rc = (ioctlsocket(udpsocket, FIONBIO, &flags) == 0); +#else + flags = fcntl(udpsocket, F_GETFL, 0); + if (flags != -1) + { + if (onOrOff) + flags &= ~O_NONBLOCK; + else + flags |= O_NONBLOCK; + rc = (fcntl(udpsocket, F_SETFL, flags) == 0); + } +#endif + + if (!rc) + { + printf("set socket %sblocking failed: %s\n", + ((onOrOff) ? "" : "non-"), netstrerror()); + } + + return(rc); +} + + +static int set_socket_broadcast(int onOrOff) +{ + int f = (onOrOff) ? 1 : 0; + int rc; + + /* give socket clearance to broadcast. */ + rc = setsockopt(udpsocket, SOL_SOCKET, SO_BROADCAST, (const char *) &f, sizeof (f)) == 0; + if (!rc) + { + printf("%sset SO_BROADCAST failed: %s\n", + ((onOrOff) ? "" : "un"), netstrerror()); + } + + return(rc); +} + + +static int open_udp_socket(int ip, int port) +{ + struct sockaddr_in addr; + + printf("Setting up UDP interface %s:%d...\n", static_ipstring(ip), port); + + udpsocket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (udpsocket == -1) + { + printf("socket creation failed: %s\n", netstrerror()); + return(0); + } + + if (!set_socket_blockmode(0)) + return(0); + + #if !PLATFORM_WIN32 && !PLATFORM_MACOSX && !PLATFORM_SOLARIS && !PLATFORM_FREEBSD + { + /* Linux-specific. */ + int flags = 1; + setsockopt(udpsocket, SOL_IP, IP_RECVERR, &flags, sizeof (flags)); + } + #endif + + memset(&addr, '\0', sizeof (addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(ip); + addr.sin_port = htons(port); + if (bind(udpsocket, (struct sockaddr *) &addr, sizeof (addr)) == -1) + { + printf("socket binding failed: %s\n", netstrerror()); + return(0); + } + + return(1); +} + +/* server init. */ +static int wait_for_other_players(gcomtype *gcom, int myip) +{ + printf("Server code NOT implemented!\n"); + return(0); +} + +/* client init. */ +static int connect_to_server(gcomtype *gcom, int myip) +{ + printf("Client code NOT implemented!\n"); + return(0); +} + +typedef struct +{ + unsigned char dummy1; /* so these don't confuse game after load. */ + unsigned char dummy2; /* so these don't confuse game after load. */ + unsigned char dummy3; /* so these don't confuse game after load. */ + unsigned char header; /* always HEADER_PEER_GREETING (245). */ + unsigned short id; +} PacketPeerGreeting; + + +static void send_peer_greeting(int ip, short port, short myid) +{ + PacketPeerGreeting packet; + memset(&packet, '\0', sizeof (packet)); + packet.header = HEADER_PEER_GREETING; + packet.id = BUILDSWAP_INTEL16(myid); + send_udp_packet(ip, port, &packet, sizeof (packet)); +} + + +/* peer to peer init. */ +static int connect_to_everyone(gcomtype *gcom, int myip, int bcast) +{ + PacketPeerGreeting packet; + unsigned short my_id = 0; + int i; + int rc; + int ip; + short port; + int first_send = 1; + unsigned short heard_from[MAX_PLAYERS]; + unsigned long resendat; + int max; + int remaining; + + printf("peer-to-peer init. CTRL-C to abort...\n"); + + if (bcast) + { + if (gcom->numplayers > 1) + { + printf("ERROR: Can't do both 'broadcast' and 'allow'.\n"); + return(0); + } + + if (!set_socket_broadcast(1)) + return(0); + + gcom->numplayers = bcast + 1; + } + + memset(heard_from, '\0', sizeof (heard_from)); + + while (my_id == 0) /* player number is based on id, low to high. */ + my_id = (unsigned short) rand(); + + printf("(This client's ID for this round is 0x%X.)\n\n", my_id); + + resendat = getticks(); + remaining = max = gcom->numplayers - 1; + + printf("Waiting for %d player%s...\n", remaining, remaining==1 ? "":"s"); + if (remaining == 0) + { + printf("Hmmm...don't have time to play with myself.\n"); + return(0); + } + + while ((remaining) && (!ctrlc_pressed)) + { + if (resendat <= getticks()) + { + if (bcast) + { + printf("%sroadcasting greeting...\n", first_send ? "B":"Reb"); + /* !!! FIXME: This is...probably not right. */ + send_peer_greeting(0xFFFFFFFF, udpport, my_id); + } + else + { + for (i = 0; i < max; i++) + { + if (!heard_from[i]) + { + printf("%sending greeting to %s:%d...\n", + first_send ? "S" : "Res", + static_ipstring(allowed_addresses[i].host), + allowed_addresses[i].port); + send_peer_greeting(allowed_addresses[i].host, + allowed_addresses[i].port, + my_id); + } + } + } + first_send = 0; + resendat += CLIENT_POLL_DELAY; + } + + _idle(); + process_udp_send_queue(); + + rc = get_udp_packet(&ip, &port, &packet, sizeof (packet)); + if ( (rc > 0) && (ip) && ((ip != myip) || (port != udpport)) ) + { + char *ipstr = static_ipstring(ip); + + for (i = 0; i < max; i++) + { + if ((ip == allowed_addresses[i].host) && + (port == allowed_addresses[i].port)) + { + break; + } + + if ((bcast) && (allowed_addresses[i].host == 0)) + break; /* select this slot. */ + } + + if (i == max) + printf("%s is not an allowed player.\n", ipstr); + + else if (rc != sizeof (packet)) + printf("Missized packet/packet fragment from %s\n", ipstr); + + else if (packet.header != HEADER_PEER_GREETING) + printf("Unexpected packet type from %s\n", ipstr); + + else if (heard_from[i] == 0) + { + packet.id = BUILDSWAP_INTEL16(packet.id); + heard_from[i] = packet.id; + allowed_addresses[i].host = ip; /* bcast needs this. */ + allowed_addresses[i].port = port; + remaining--; + + printf("Heard from %s (id 0x%X). %d player%s to go.\n", + ipstr, (int) packet.id, + remaining, remaining == 1 ? "" : "s"); + + /* make sure they've heard from us at all... */ + /* !!! FIXME: Could be fatal if packet is dropped... */ + send_peer_greeting(allowed_addresses[i].host, + allowed_addresses[i].port, + my_id); + } + } + } + + if (ctrlc_pressed) + { + printf("Connection attempt aborted.\n"); + return(0); + } + + /* ok, now everyone is talking to you. Sort them into player numbers... */ + + heard_from[max] = my_id; /* so we sort, too... */ + allowed_addresses[max].host = myip; + allowed_addresses[max].port = udpport; + + do + { + remaining = 0; + for (i = 0; i < max; i++) + { + if (heard_from[i] == heard_from[i+1]) /* blah. */ + { + printf("ERROR: Two players have the same random ID!\n"); + printf("ERROR: Please restart the game to generate new IDs.\n"); + return(0); + } + + else if (heard_from[i] > heard_from[i+1]) + { + int tmpi; + short tmps; + + tmps = heard_from[i]; + heard_from[i] = heard_from[i+1]; + heard_from[i+1] = tmps; + + tmpi = allowed_addresses[i].host; + allowed_addresses[i].host = allowed_addresses[i+1].host; + allowed_addresses[i+1].host = tmpi; + + tmps = allowed_addresses[i].port; + allowed_addresses[i].port = allowed_addresses[i+1].port; + allowed_addresses[i+1].port = tmps; + + remaining = 1; /* yay for bubble sorting! */ + } + } + } while (remaining); + + /* + * Now we're sorted. But, the local player is referred to by both his + * player number and player index ZERO, so bump everyone up one to + * their actual index and fill in local player as item zero. + */ + + memmove(&allowed_addresses[1], &allowed_addresses[0], + sizeof (allowed_addresses) - sizeof (allowed_addresses[0])); + allowed_addresses[0].host = myip; + + gcom->myconnectindex = 0; + for (i = 1; i <= gcom->numplayers; i++) + { + ip = allowed_addresses[i].host; + if (ip == myip) + gcom->myconnectindex = i; + + printf("%s is player #%d.\n", static_ipstring(ip), i); + } + assert(gcom->myconnectindex); + + printf("Everyone ready! We are player #%d\n", (int) gcom->myconnectindex); + + /* + * Ok, we should have specific IPs and ports for all players, and + * therefore shouldn't broadcast anymore. Disable permission to do so, + * just in case, so we aren't flooding the LAN with broadcasted packets. + */ + set_socket_broadcast(0); + + return(1); +} + +static int parse_ip(const char *str, int *ip) +{ + int ip1, ip2, ip3, ip4; + + if (stricmp(str, "any") == 0) + { + *ip = 0; + return(1); + } + + if (sscanf(str, "%d.%d.%d.%d", &ip1, &ip2, &ip3, &ip4) != 4) + { + printf("\"%s\" is not a valid IP address.\n", str); + return(0); + } + + /* we _should_ check that 0 <= ip? <= 255, but it'll fail later anyhow. */ + + *ip = ( ((ip1 & 0xFF) << 24) | + ((ip2 & 0xFF) << 16) | + ((ip3 & 0xFF) << 8) | + ((ip4 & 0xFF) ) ); + + return(1); +} + +static int parse_interface(char *str, int *ip, short *udpport) +{ + char *ptr = strchr(str, ':'); + if (ptr) /* portnum specified? */ + *ptr = '\0'; + + if (!parse_ip(str, ip)) + return(0); + + *udpport = BUILD_DEFAULT_UDP_PORT; + if (ptr != NULL) /* port specified? */ + { + ptr++; + if (stricmp(ptr, "any") == 0) + *udpport = 0; + else + *udpport = (short) atoi(ptr); + } + + return(1); +} + +static int initialize_sockets(void) +{ +#if PLATFORM_WIN32 + int rc; + WSADATA data; + printf("initializing WinSock...\n"); + rc = WSAStartup(0x0101, &data); + if (rc != 0) + { + printf("WinSock failed to initialize! [err==%d].\n", rc); + return(0); + } + else + { + printf("WinSock initialized.\n"); + printf(" - Caller uses version %d.%d, highest supported is %d.%d.\n", + data.wVersion >> 8, data.wVersion & 0xFF, + data.wHighVersion >> 8, data.wHighVersion & 0xFF); + printf(" - Implementation description: [%s].\n", data.szDescription); + printf(" - System status: [%s].\n", data.szSystemStatus); + printf(" - Max sockets: %d.\n", data.iMaxSockets); + printf(" - Max UDP datagram size: %d.\n", data.iMaxUdpDg); + } +#endif + + return(1); +} + +static void deinitialize_sockets(void) +{ +#if PLATFORM_WIN32 + WSACleanup(); +#endif +} + +static int parse_udp_config(const char *cfgfile, gcomtype *gcom) +{ + char *buf; + char *tok; + char *ptr; + int ip = 0; /* interface */ + int bcast = 0; + + buf = read_whole_file(cfgfile); /* we must free this. */ + if (buf == NULL) + return(0); + + ptr = buf; + while ((tok = get_token(&ptr)) != NULL) + { + int bogus = 1; + + if (stricmp(tok, "interface") == 0) + { + if ( (tok = get_token(&ptr)) && + (parse_interface(tok, &ip, &udpport)) ) + { + bogus = 0; + } + printf("Interface %s:%d chosen.\n", + static_ipstring(ip), (int) udpport); + } + + else if (stricmp(tok, "mode") == 0) + { + if ((tok = get_token(&ptr)) != NULL) + { + bogus = 0; + if (stricmp(tok, "server") == 0) + udpmode = udpmode_server; + else if (stricmp(tok, "client") == 0) + udpmode = udpmode_client; + else if (stricmp(tok, "peer") == 0) + udpmode = udpmode_peer; + else + bogus = 1; + + if (!bogus) + printf("You want to be in [%s] mode\n", tok); + } + } + + else if (stricmp(tok, "broadcast") == 0) + { + if ((tok = get_token(&ptr)) != NULL) + { + bcast = atoi(tok); + if (bcast > MAX_PLAYERS - 1) + { + printf("WARNING: Too many broadcast players.\n"); + bcast = MAX_PLAYERS - 1; + } + + bogus = 0; + } + } + + else if (stricmp(tok, "allow") == 0) + { + int host; + short port=BUILD_DEFAULT_UDP_PORT; + if ((tok = get_token(&ptr)) != NULL) + { + if (gcom->numplayers >= MAX_PLAYERS - 1) + printf("WARNING: Too many allowed IP addresses.\n"); + + else if (parse_interface(tok, &host, &port)) + { + allowed_addresses[gcom->numplayers].host = host; + allowed_addresses[gcom->numplayers].port = port; + gcom->numplayers++; + bogus = 0; + } + } + } + + if (bogus) + printf("bogus token! [%s]\n", tok); + } + + free(buf); + + if (open_udp_socket(ip, udpport)) + { + gcom->numplayers++; /* that's you. */ + if (udpmode == udpmode_server) + return(wait_for_other_players(gcom, ip)); + else if (udpmode == udpmode_client) + return(connect_to_server(gcom, ip)); + else if (udpmode == udpmode_peer) + return(connect_to_everyone(gcom, ip, bcast)); + + printf("wtf?!"); /* Should be handled by a udpmode above... */ + assert(0); + } + + return(0); +} + + +gcomtype *init_network_transport(char **ARGV, int argpos) +{ + gcomtype *retval; + + printf("\n\nUDP NETWORK TRANSPORT INITIALIZING...\n"); + + ctrlc_pressed = 0; + + if (!initialize_sockets()) + return(NULL); + + srand(time(NULL)); + + retval = (gcomtype *)malloc(sizeof (gcomtype)); + if (retval != NULL) + { + int rc; + char *cfgfile = ARGV[argpos]; + void (*oldsigint)(int); + + memset(retval, '\0', sizeof (gcomtype)); + memset(allowed_addresses, '\0', sizeof (allowed_addresses)); + udpsocket = -1; + udpport = BUILD_DEFAULT_UDP_PORT; + udpmode = udpmode_peer; + + oldsigint = signal(SIGINT, siginthandler); + rc = parse_udp_config(cfgfile, retval); + signal(SIGINT, oldsigint); + + if (!rc) + { + free(retval); + deinit_network_transport(NULL); + return(NULL); + } + retval->gametype = 3; /* gametype: 1-serial,2-modem,3-net */ + } + + return(retval); +} + + +void deinit_network_transport(gcomtype *gcom) +{ + printf("\n\nUDP NETWORK TRANSPORT DEINITIALIZING...\n"); + + if (gcom != NULL) + { + printf(" ...freeing gcom structure...\n"); + free(gcom); + } + + if (udpsocket != -1) + { + printf(" ...closing socket...\n"); + set_socket_blockmode(1); /* block while socket drains. */ + shutdown(udpsocket, SOCKET_SHUTDOWN_BOTH); + socketclose(udpsocket); + udpsocket = -1; + } + + deinitialize_sockets(); + + printf("UDP net deinitialized successfully.\n"); +} + + +void callcommit(void) +{ + int ip, i, rc; + short port; + + if (udpsocket == -1) + return; + + process_udp_send_queue(); + + switch (gcom->command) + { + case COMMIT_CMD_GET: + rc = get_udp_packet(&ip, &port, gcom->buffer, sizeof(gcom->buffer)); + if (rc > 0) + { + gcom->numbytes = rc; /* size of new packet. */ + for (i = 1; i <= gcom->numplayers; i++) + { + if ( (allowed_addresses[i].host == ip) && + (allowed_addresses[i].port == port) ) + { + gcom->other = i; + return; + } + } + /* if you manage to hit this, it'll report no packet avail. */ + } + + gcom->numbytes = 0; + gcom->other = -1; /* no packet available. */ + break; + + case COMMIT_CMD_SEND: + if ((gcom->other < 0) || (gcom->other > gcom->numplayers)) + { + printf("NET TRANSPORT ERROR: send to player out of range\n"); + return; + } + + ip = allowed_addresses[gcom->other].host; + if (ip == 0) /* dropped player? */ + return; + + port = allowed_addresses[gcom->other].port; + + if (!send_udp_packet(ip, port, gcom->buffer, gcom->numbytes)) + { + printf("NET TRANSPORT ERROR: send failed to %s:%d\n", + static_ipstring(ip), (int) port); + } + break; + + case COMMIT_CMD_SENDTOALL: + /* skip player zero, 'cause that's a duplicate of local IP. */ + for (i = 1; i <= gcom->numplayers; i++) + { + ip = allowed_addresses[i].host; + if (ip == 0) /* dropped player? */ + continue; + + port = allowed_addresses[i].port; + + if (!send_udp_packet(ip, port, gcom->buffer, gcom->numbytes)) + { + printf("NET TRANSPORT ERROR: send failed to %s:%d\n", + static_ipstring(ip), (int) port); + } + } + break; + + case COMMIT_CMD_SENDTOALLOTHERS: + /* skip player zero, 'cause that's a duplicate of local IP. */ + for (i = 1; i <= gcom->numplayers; i++) + { + if (i == gcom->myconnectindex) /* local player. */ + continue; + + ip = allowed_addresses[i].host; + if (ip == 0) /* dropped player? */ + continue; + + port = allowed_addresses[i].port; + + if (!send_udp_packet(ip, port, gcom->buffer, gcom->numbytes)) + { + printf("NET TRANSPORT ERROR: send failed to %s:%d\n", + static_ipstring(ip), (int) port); + } + } + break; + + /* Gets used, but doesn't seem to do anything in Duke3D... */ + case COMMIT_CMD_SCORE: + break; + + default: + printf("NET TRANSPORT ERROR: Unknown command %d\n", gcom->command); + gcom->other = -1; /* oh well. */ + break; + } +} + +#else +#error Please define a network transport for your platform. +#endif + +/* end of mmulti.c ... */ + diff --git a/buildengine/multi.c b/buildengine/multi.c new file mode 100755 index 0000000..c2ded00 --- /dev/null +++ b/buildengine/multi.c @@ -0,0 +1,1176 @@ +// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman +// Ken Silverman's official web site: "http://www.advsys.net/ken" +// See the included license file "BUILDLIC.TXT" for license info. +// This file has been modified from Ken Silverman's original release + +#include +#include +#include + +#include "platform.h" + +extern long getcrc(char *buffer, short bufleng); +extern void processreservedmessage(short tempbufleng, char *datempbuf); +extern void initcrc(void); +extern int comon(void); +extern void comoff(void); +extern int neton(void); +extern void netoff(void); +extern void startcom(void); +extern int netinitconnection (long newconnectnum, char *newcompaddr); +extern void installbicomhandlers(void); +extern void uninstallbicomhandlers(void); + +#define COMBUFSIZ 16384 +#define COMCODEBYTES 384 +#define COMCODEOFFS 14 +#define NETCODEBYTES 384 +#define MAXPLAYERS 16 +#define ESC1 0x83 +#define ESC2 0x8f +#define NETBACKPACKETS 4 +#define MAXIPXSIZ 546 + +#define updatecrc16(crc,dat) crc = (((crc<<8)&65535)^crctable[((((unsigned short)crc)>>8)&65535)^dat]) + +char syncstate = 0, hangup = 1; +static char multioption = 0, comrateoption = 0; + + //COM & NET variables +short numplayers = 0, myconnectindex = 0; +short connecthead, connectpoint2[MAXPLAYERS]; +char syncbuf[MAXIPXSIZ]; +long syncbufleng, outbufindex[128], outcnt; +long myconnectnum, otherconnectnum, mypriority; +long crctable[256]; + + //COM ONLY variables +long comnum, comvect, comspeed, comtemp, comi, comescape, comreset; +#ifdef PLATFORM_DOS // !!! this is a real mess. --ryan. +static void interrupt far comhandler(void); +static unsigned short orig_pm_sel, orig_rm_seg, orig_rm_off; +static unsigned long orig_pm_off; +#endif +volatile unsigned char *inbuf, *outbuf, *comerror, *incnt, *comtype; +volatile unsigned char *comresend; +volatile short *inbufplc, *inbufend, *outbufplc, *outbufend, *comport; +#ifdef PLATFORM_DOS // !!! this is a real mess. --ryan. +static char rmbuffer[COMCODEBYTES] = //See realcom.asm +{ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x50,0x53,0x66,0x51,0x52,0x2e, + 0x8b,0x16,0x08,0x00,0x83,0xc2,0x02,0xec,0x24,0x07, + 0x8a,0xe0,0x80,0xfc,0x02,0x74,0x08,0x80,0xfc,0x04, + 0x74,0x62,0xe9,0x89,0x00,0x2e,0x8b,0x16,0x08,0x00, + 0x2e,0x8a,0x0e,0x0a,0x00,0x80,0xe9,0x01,0x78,0x7a, + 0x2e,0x80,0x3e,0x0c,0x00,0x01,0x7c,0x10,0x74,0x04, + 0xb0,0x83,0xeb,0x02,0xb0,0x8f,0xee,0x2e,0xfe,0x0e, + 0x0c,0x00,0xeb,0xe3,0x2e,0x80,0x3e,0x0b,0x00,0x01, + 0x7c,0x12,0x74,0x04,0xb0,0x83,0xeb,0x04,0x2e,0xa0, + 0x0d,0x00,0xee,0x2e,0xfe,0x0e,0x0b,0x00,0xeb,0xc9, + 0x2e,0x8b,0x1e,0x04,0x00,0x2e,0x3b,0x1e,0x06,0x00, + 0x74,0x3c,0x2e,0x8a,0x87,0x80,0x41,0xee,0x43,0x81, + 0xe3,0xff,0x3f,0x2e,0x89,0x1e,0x04,0x00,0xeb,0xab, + 0x2e,0x8b,0x16,0x08,0x00,0xec,0x2e,0x8b,0x1e,0x02, + 0x00,0x2e,0x88,0x87,0x80,0x01,0x43,0x81,0xe3,0xff, + 0x3f,0x2e,0x89,0x1e,0x02,0x00,0x2e,0x80,0x3e,0x0a, + 0x00,0x10,0x75,0x08,0x83,0xc2,0x05,0xec,0xa8,0x01, + 0x75,0xd6,0xf6,0xc4,0x01,0x0f,0x84,0x56,0xff,0xb0, + 0x20,0xe6,0x20,0x5a,0x66,0x59,0x5b,0x58,0xcf, +}; +#endif + + //NET ONLY variables +short socket = 0x4949; +char compaddr[MAXPLAYERS][12], mycompaddr[12]; +char netincnt[MAXPLAYERS], netoutcnt[MAXPLAYERS]; +char getmess[MAXIPXSIZ]; +char omessout[MAXPLAYERS][NETBACKPACKETS][MAXIPXSIZ]; +short omessleng[MAXPLAYERS][NETBACKPACKETS]; +short omessconnectindex[MAXPLAYERS][NETBACKPACKETS]; +short omessnum[MAXPLAYERS]; +long connectnum[MAXPLAYERS], rmoffset32, rmsegment16, neti; +volatile char *ecbget, *ecbput, *ipxin, *ipxout, *messin, *messout; +volatile char *tempinbuf, *tempoutbuf, *rmnethandler, *netinbuf; +volatile short *netinbufplc, *netinbufend; +static char rmnetbuffer[NETCODEBYTES] = +{ + 0xfb,0x2e,0x8a,0x26,0x62,0x00,0x2e,0xa0,0x63,0x00, + 0x83,0xe8,0x1e,0x2e,0x8b,0x1e,0xe2,0x06,0x2e,0x88, + 0x87,0xe4,0x06,0x43,0x81,0xe3,0xff,0x3f,0x2e,0x88, + 0xa7,0xe4,0x06,0x43,0x81,0xe3,0xff,0x3f,0x33,0xf6, + 0x2e,0x8a,0x8c,0xa0,0x00,0x46,0x2e,0x88,0x8f,0xe4, + 0x06,0x43,0x81,0xe3,0xff,0x3f,0x3b,0xf0,0x72,0xec, + 0x2e,0x89,0x1e,0xe2,0x06,0xbb,0x04,0x00,0x8c,0xc8, + 0x8e,0xc0,0xbe,0x00,0x00,0xcd,0x7a,0xcb, +}; +static long my7a = 0; + +#ifdef PLATFORM_DOS +#pragma aux koutp =\ + "out dx, al",\ + parm [edx][eax]\ + +#pragma aux kinp =\ + "in al, dx",\ + parm [edx] +#endif + +long convalloc32 (long size) +{ +#ifdef PLATFORM_DOS + union REGS r; + + r.x.eax = 0x0100; //DPMI allocate DOS memory + r.x.ebx = ((size+15)>>4); //Number of paragraphs requested + int386(0x31,&r,&r); + + if (r.x.cflag != 0) return ((long)0); //Failed + return ((long)((r.x.eax&0xffff)<<4)); //Returns full 32-bit offset +#else + fprintf (stderr, "%s, line %d; convalloc32() called\n", __FILE__, + __LINE__); + return 0; +#endif +} + +#ifdef PLATFORM_DOS +#pragma aux fixregistersaftersimulate =\ + "cld",\ + "push ds",\ + "pop es",\ + +static struct rminfo +{ + long EDI, ESI, EBP, ESP, EBX, EDX, ECX, EAX; + short flags, ES, DS, FS, GS, IP, CS, SP, SS; +} RMI; +#endif + +long simulateint(char intnum, long daeax, long daebx, long daecx, long daedx, long daesi, long daedi) +{ +#ifdef PLATFORM_DOS + union REGS regs; + struct SREGS sregs; + + memset(&RMI,0,sizeof(RMI)); // Set up real-mode call structure + memset(&sregs,0,sizeof(sregs)); + + RMI.EAX = daeax; + RMI.EBX = daebx; + RMI.ECX = daecx; + RMI.EDX = daedx; + RMI.ESI = daesi-rmoffset32; + RMI.EDI = daedi-rmoffset32; + RMI.DS = rmsegment16; + RMI.ES = rmsegment16; + + regs.w.ax = 0x0300; // Use DMPI call 300h to issue the DOS interrupt + regs.h.bl = intnum; + regs.h.bh = 0; + regs.w.cx = 0; + sregs.es = FP_SEG(&RMI); + regs.x.edi = FP_OFF(&RMI); + int386x(0x31,®s,®s,&sregs); + + fixregistersaftersimulate(); + + return(RMI.EAX); +#else + fprintf(stderr, "%s line %d; simulateint() called\n",__FILE__,__LINE__); + return 0; +#endif +} + +void initmultiplayers(char damultioption, char dacomrateoption, char dapriority) +{ + long i; + + multioption = damultioption; + comrateoption = dacomrateoption; + + connecthead = 0; + for(i=MAXPLAYERS-1;i>=0;i--) + connectpoint2[i] = -1, connectnum[i] = 0x7fffffff; + + mypriority = dapriority; + + initcrc(); + + if ((multioption >= 1) && (multioption <= 4)) + { + comnum = multioption; + switch(dacomrateoption&15) + { + case 0: comspeed = 2400; break; + case 1: comspeed = 4800; break; + case 2: comspeed = 9600; break; + case 3: comspeed = 14400; break; + case 4: comspeed = 19200; break; + case 5: comspeed = 28800; break; + } + comon(); + } + if (multioption >= 5) + { + if ((i = neton()) != 0) + { + if (i == -1) printf("IPX driver not found\n"); + if (i == -2) printf("Socket could not be opened\n"); + exit(0); + } + } + numplayers = 1; +} + +void uninitmultiplayers() +{ + if (numplayers > 0) + { + if ((multioption >= 1) && (multioption <= 4)) comoff(); + if (multioption >= 5) netoff(); //Uninstall before timer + } +} + +int neton(void) +{ + long i, j; + + if ((simulateint(0x2f,(long)0x7a00,0L,0L,0L,0L,0L)&255) != 255) return(-1); + if (*(long *)(0x7a<<2) == 0) + { +#ifdef PLATFORM_DOS + printf("Faking int 0x7a to call IPX entry at: %4x:%4x\n",RMI.ES,RMI.EDI&65535); + my7a = convalloc32(16L); + *(short *)((0x7a<<2)+0) = (my7a&15); + *(short *)((0x7a<<2)+2) = (my7a>>4); + + *(char *)(my7a+0) = 0x2e; //call far ptr [L1] + *(char *)(my7a+1) = 0x9a; + *(long *)(my7a+2) = 7L; + *(char *)(my7a+6) = 0xcf; //iret + *(short *)(my7a+7) = (RMI.EDI&65535); //L1: ipxoff + *(short *)(my7a+9) = RMI.ES; // ipxseg +#endif + } + + //Special stuff for WATCOM C + if ((rmoffset32 = convalloc32(1380L+NETCODEBYTES+COMBUFSIZ)) == 0) + { printf("Can't allocate memory for IPX\n"); exit; } + rmsegment16 = (rmoffset32>>4); + + i = rmoffset32; + ecbget = (char *)i; i += 48; + ecbput = (char *)i; i += 48; + ipxin = (char *)i; i += 32; + ipxout = (char *)i; i += 32; + messin = (char *)i; i += 560; + messout = (char *)i; i += 560; + tempinbuf = (char *)i; i += 16; + tempoutbuf = (char *)i; i += 80; + rmnethandler = (char *)i; i += NETCODEBYTES; + netinbufplc = (short *)i; i += 2; + netinbufend = (short *)i; i += 2; + netinbuf = (char *)i; i += COMBUFSIZ; + memcpy((void *)rmnethandler,(void *)rmnetbuffer,NETCODEBYTES); + + simulateint(0x7a,0L,(long)0x1,0L,(long)socket,0L,0L); //Closesocket + if ((simulateint(0x7a,(long)0xff,0L,0L,(long)socket,0L,0L)&255) != 0) return(-2); //Opensocket + + simulateint(0x7a,0L,9L,0L,0L,(long)tempoutbuf,0L); //Getinternetworkaddress + memcpy((void *)&mycompaddr[0],(void *)&tempoutbuf[0],10); + mycompaddr[10] = (socket&255); + mycompaddr[11] = (socket>>8); + myconnectnum = ((long)tempoutbuf[6])+(((long)tempoutbuf[7])<<8)+(((long)(tempoutbuf[8]^tempoutbuf[9]))<<16)+(((long)mypriority)<<24); + + netinitconnection(myconnectnum,mycompaddr); + + ecbget[8] = 1; ecbput[8] = 0; + *netinbufplc = 0; *netinbufend = 0; + + for(i=MAXPLAYERS-1;i>=0;i--) netincnt[i] = 0, netoutcnt[i] = 0; + + for(i=0;i=0;j--) + { + omessleng[i][j] = 0; + omessconnectindex[i][j] = 0; + } + } + + //Netlisten + for(i=0;i<30;i++) ipxin[i] = 0; + for(i=0;i<48;i++) ecbget[i] = 0; + ecbget[4] = (char)(((long)rmnethandler-rmoffset32)&255), ecbget[5] = (char)(((long)rmnethandler-rmoffset32)>>8); + ecbget[6] = (char)(rmsegment16&255), ecbget[7] = (char)(rmsegment16>>8); + ecbget[10] = (socket&255), ecbget[11] = (socket>>8); + ecbget[34] = 2, ecbget[35] = 0; + ecbget[36] = (char)(((long)ipxin-rmoffset32)&255), ecbget[37] = (char)(((long)ipxin-rmoffset32)>>8); + ecbget[38] = (char)(rmsegment16&255), ecbget[39] = (char)(rmsegment16>>8); + ecbget[40] = 30, ecbget[41] = 0; + ecbget[42] = (char)(((long)messin-rmoffset32)&255), ecbget[43] = (char)(((long)messin-rmoffset32)>>8); + ecbget[44] = (char)(rmsegment16&255), ecbget[45] = (char)(rmsegment16>>8); + ecbget[46] = (MAXIPXSIZ&255), ecbget[47] = (MAXIPXSIZ>>8); + simulateint(0x7a,0L,(long)0x4,0L,0L,(long)ecbget,0L); //Receivepacket + + return(0); +} + +int comon() +{ + long divisor, cnt; + short *ptr; + + if ((comnum < 1) || (comnum > 4)) return(-1); + //comvect = 0xb+(comnum&1); + comvect = ((comrateoption>>4)+0x8+2); + installbicomhandlers(); + + *incnt = 0; outcnt = 0; + *inbufplc = 0; *inbufend = 0; *outbufplc = 0; *outbufend = 0; + + ptr = (short *)(0x400L+(long)((comnum-1)<<1)); + *comport = *ptr; + if (*comport == 0) + { + switch(comnum) + { + case 1: *comport = 0x3f8; break; + case 2: *comport = 0x2f8; break; + case 3: *comport = 0x3e8; break; + case 4: *comport = 0x2e8; break; + } + if ((inp((*comport)+5)&0x60) != 0x60) { *comport = 0; return(-1); } + } + if ((comspeed <= 0) || (comspeed > 115200)) return(-1); + + // Baud-Setting,?,?,Parity O/E,Parity Off/On, Stop-1/2,Bits-5/6/7/8 + // 0x0b is odd parity,1 stop bit, 8 bits + +#ifdef PLATFORM_DOS + _disable(); +#endif + koutp((*comport)+3,0x80); //enable latch registers + divisor = 115200 / comspeed; + koutp((*comport)+0,divisor&255); //# = 115200 / bps + koutp((*comport)+1,divisor>>8); + koutp((*comport)+3,0x03); //0x03 = n,8,1 + + koutp((*comport)+2,0x87); //check for a 16550 0=1,64=4,128=8,192=14 + if ((kinp((*comport)+2)&0xf8) == 0xc0) + { + *comtype = 16; + } + else + { + *comtype = 1; + koutp((*comport)+2,0); + } + cnt = *comtype; //Clear any junk already in FIFO + while (((kinp((*comport)+5)&0x1) > 0) && (cnt > 0)) + { kinp(*comport); cnt--; } + + koutp((*comport)+4,0x0b); //setup for interrupts (modem control) + koutp((*comport)+1,0); //com interrupt disable + koutp(0x21,kinp(0x21)&(255-(1<<(comvect&7)))); //Unmask vector + kinp((*comport)+6); + kinp((*comport)+5); + kinp((*comport)+0); + kinp((*comport)+2); + koutp((*comport)+1,0x03); //com interrupt enable + koutp(0x20,0x20); + + comescape = 0; comreset = 0; + *comerror = 0; *comresend = 0; +#ifdef PLATFORM_DOS + _enable(); +#endif + + syncbufleng = 0; + + return(0); +} + +void netoff() +{ + if (my7a) *(long *)(0x7a<<2) = 0L; + simulateint(0x7a,0L,(long)0x1,0L,(long)socket,0L,0L); //Closesocket +} + +void comoff() +{ + long i; + + i = 1048576; + while ((*outbufplc != *outbufend) && (i >= 0)) + { + startcom(); + i--; + } + +#ifdef PLATFORM_DOS + _disable(); +#endif + koutp(0x21,kinp(0x21)|(1<<(comvect&7))); //Mask vector + if (hangup != 0) + { + koutp((*comport)+1,0); + koutp((*comport)+4,0); + } +#ifdef PLATFORM_DOS + _enable(); +#endif + uninstallbicomhandlers(); +} + +void netsend (short otherconnectindex, short messleng) +{ + long i; + + i = 32767; + while ((ecbput[8] != 0) && (i > 0)) i--; + for(i=0;i<30;i++) ipxout[i] = 0; + for(i=0;i<48;i++) ecbput[i] = 0; + ipxout[5] = 4; + if (otherconnectindex < 0) + { + memcpy((void *)&ipxout[6],(void *)&compaddr[0][0],4); + ipxout[10] = 0xff, ipxout[11] = 0xff, ipxout[12] = 0xff; + ipxout[13] = 0xff, ipxout[14] = 0xff, ipxout[15] = 0xff; + ipxout[16] = (socket&255), ipxout[17] = (socket>>8); + } + else + { + memcpy((void *)&ipxout[6],(void *)&compaddr[otherconnectindex][0],12); + } + + ecbput[10] = (socket&255), ecbput[11] = (socket>>8); + if (otherconnectindex < 0) + { + ecbput[28] = 0xff, ecbput[29] = 0xff, ecbput[30] = 0xff; + ecbput[31] = 0xff, ecbput[32] = 0xff, ecbput[33] = 0xff; + } + else + { + memcpy((void *)&ecbput[28],(void *)&compaddr[otherconnectindex][4],6); + } + + ecbput[34] = 2, ecbput[35] = 0; + ecbput[36] = (char)(((long)ipxout-rmoffset32)&255), ecbput[37] = (char)(((long)ipxout-rmoffset32)>>8); + ecbput[38] = (char)(rmsegment16&255), ecbput[39] = (char)(rmsegment16>>8); + ecbput[40] = 30, ecbput[41] = 0; + ecbput[42] = (char)(((long)messout-rmoffset32)&255), ecbput[43] = (char)(((long)messout-rmoffset32)>>8); + ecbput[44] = (char)(rmsegment16&255), ecbput[45] = (char)(rmsegment16>>8); + ecbput[46] = (char)(messleng&255), ecbput[47] = (char)(messleng>>8); + simulateint(0x7a,0L,(long)0x3,0L,0L,(long)ecbput,0L); //Sendpacket +} + +void comsend(char ch) +{ + if (ch == ESC1) + { + outbuf[*outbufend] = ESC1; *outbufend = (((*outbufend)+1)&(COMBUFSIZ-1)); + ch = 128; + } + else if (ch == ESC2) + { + outbuf[*outbufend] = ESC1; *outbufend = (((*outbufend)+1)&(COMBUFSIZ-1)); + ch = 129; + } + outbuf[*outbufend] = ch; *outbufend = (((*outbufend)+1)&(COMBUFSIZ-1)); +} + +void startcom() +{ + if ((kinp((*comport)+5)&0x40) == 0) return; + + if (*comresend != 0) + { + if (*comresend == 2) koutp(*comport,ESC1); + if (*comresend == 1) koutp(*comport,ESC2); + *comresend = (*comresend) - 1; + } + else if (*comerror != 0) + { + if (*comerror == 2) koutp(*comport,ESC1); + if (*comerror == 1) koutp(*comport,*incnt); + *comerror = (*comerror) - 1; + } + else if (*outbufplc != *outbufend) + { + koutp(*comport,(long)outbuf[*outbufplc]); + *outbufplc = (((*outbufplc)+1)&(COMBUFSIZ-1)); + } +} + +void interrupt far comhandler(void) +{ + do + { + comtemp = (kinp((*comport)+2)&7); + if (comtemp == 2) + { + for(comi=(*comtype);comi>0;comi--) + { + if (*comresend != 0) + { + if (*comresend == 2) koutp(*comport,ESC1); + if (*comresend == 1) koutp(*comport,ESC2); + *comresend = (*comresend) - 1; + continue; + } + if (*comerror != 0) + { + if (*comerror == 2) koutp(*comport,ESC1); + if (*comerror == 1) koutp(*comport,*incnt); + *comerror = (*comerror) - 1; + continue; + } + if (*outbufplc != *outbufend) + { + koutp(*comport,(long)outbuf[*outbufplc]); + *outbufplc = (((*outbufplc)+1)&(COMBUFSIZ-1)); + continue; + } + break; + } + } + else if (comtemp == 4) + { + do + { + //comtemp = (rand()&255); + //if (comtemp == 17) + // inbuf[*inbufend] = 17; + //else + inbuf[*inbufend] = (char)kinp(*comport); + + //if (comtemp != 11) *inbufend = (((*inbufend)+1)&(COMBUFSIZ-1)); + //if (comtemp == 24) + //{ + // inbuf[*inbufend] = 17; + *inbufend = (((*inbufend)+1)&(COMBUFSIZ-1)); + //} + //comtemp = 4; + + } while ((*comtype == 16) && ((kinp((*comport)+5)&1) > 0)); + } + } + while ((comtemp&1) == 0); + koutp(0x20,0x20); +} + +int netinitconnection (long newconnectnum, char *newcompaddr) +{ + long i, j, k, newindex, templong; + char tempchar; + + //Check to see if connection number already initialized + for(i=0;i= MAXPLAYERS) return(-1); //Out of space! (more than 16 players) + } + + //Insert connection number on connection number list + numplayers++; + connectnum[newindex] = newconnectnum; + + //Getinternetworkaddress + memcpy((void *)&compaddr[newindex][0],(void *)newcompaddr,10); + compaddr[newindex][10] = (socket&255); + compaddr[newindex][11] = (socket>>8); + + //Sort connection numbers + for(i=1;i 0) + { + i = getcrc(bufptr,messleng); + updatecrc16(i,(((messleng&1)<<7)+outcnt)); + comsend(i&255); comsend(i>>8); + } + outbuf[*outbufend] = ESC2, *outbufend = (((*outbufend)+1)&(COMBUFSIZ-1)); //Not raw + + startcom(); + outcnt = ((outcnt+1)&127); + } + else + { + i = 262144; //Wait for last packet to be sent + while ((i > 0) && (ecbput[8] != 0)) i--; + + messout[0] = myconnectindex; j = 1; + + if ((unsigned char) bufptr[0] >= 200) + { + //Allow initial incnt/outcnt syncing + for(i=0;i=0;k=connectpoint2[k]) + if (k != myconnectindex) + { + omessconnectindex[k][omessnum[k]] = -1; + omessleng[k][omessnum[k]] = messleng; + for(i=0;i=0;i=connectpoint2[i]) + if (i != myconnectindex) + messout[j++] = ((netoutcnt[i]-l)&255); + } + else + { + messout[j++] = otherconnectindex; + messout[j++] = ((netoutcnt[otherconnectindex]-l)&255); + } + messout[j++] = (omessleng[otherconnectindex][k]&255); + messout[j++] = ((omessleng[otherconnectindex][k]>>8)&255); + for(i=0;i=0;i=connectpoint2[i]) + if (i != myconnectindex) + { + netoutcnt[i]++; + omessnum[i] = ((omessnum[i]+1)&(NETBACKPACKETS-1)); + } + } + else + { + netoutcnt[otherconnectindex]++; + omessnum[otherconnectindex] = ((omessnum[otherconnectindex]+1)&(NETBACKPACKETS-1)); + } + } +} + +short getpacket (short *otherconnectindex, char *bufptr) +{ + char toindex, bad, totbad; + short i, j=0, k, messleng, submessleng; + + if (multioption <= 0) return(0); + if (multioption < 5) + { + *otherconnectindex = (myconnectindex^1); + + bad = 0; + while (*inbufplc != *inbufend) + { + i = (short)inbuf[*inbufplc], *inbufplc = (((*inbufplc)+1)&(COMBUFSIZ-1)); + + if (i != ESC2) + { + if (i == ESC1) { comescape++; continue; } + if (comescape != 0) + { + comescape--; + if ((i < 128) && (*comresend == 0) && (((i-outcnt)&127) > 4)) + { + *comresend = 2; + *outbufplc = outbufindex[i]; + startcom(); + continue; + } + if (syncbufleng < MAXIPXSIZ) + { + if (i == 128) { syncbuf[syncbufleng++] = ESC1; continue; } + if (i == 129) { syncbuf[syncbufleng++] = ESC2; continue; } + } + } + if (syncbufleng < MAXIPXSIZ) syncbuf[syncbufleng++] = i; + continue; + } + + if (comescape != 0) + { + comescape = 0; comreset = 0; *comerror = 0; + syncbufleng = 0; + continue; + } + + messleng = syncbufleng-3+(((comrateoption&15)==0)<<1); + if ((syncbuf[0]&127) != *incnt) + { + bad |= 1; //Packetcnt error + if ((*incnt == 1) && (syncbuf[1] == 254)) //Prevent 2 Masters! + myconnectindex = (myconnectnum>7) != (messleng&1)) bad |= 2; //messleng error + for(i=0;i 0) + { + i = getcrc(bufptr,messleng); + updatecrc16(i,syncbuf[0]); + if (((unsigned short)i) != ((long)syncbuf[syncbufleng-2])+((long)syncbuf[syncbufleng-1]<<8)) + bad |= 2; //CRC error + } + + syncbufleng = 0; + if (bad != 0) + { + //Don't send reset again if outbufplc is not before incnt! + if ((bad == 1) && ((((syncbuf[0]&127)-(*incnt))&127) >= 124)) + { + bad = 0; + continue; + } + + bad = 0; + if (comreset != 0) comreset--; + if (((*comerror)|comreset) == 0) + { + *comerror = 2; comreset = 2; + startcom(); + } + continue; + } + + *incnt = (((*incnt)+1)&127); + if ((messleng > 0) && (bufptr[0] >= 200)) //200-255 are messages for engine's use only + processreservedmessage(messleng,bufptr); + + comescape = 0; comreset = 0; *comerror = 0; + return(messleng); + } + return(0); + } + else + { + if (*netinbufplc == *netinbufend) return(0); + + messleng = (short)netinbuf[*netinbufplc] + (((short)netinbuf[((*netinbufplc)+1)&(COMBUFSIZ-1)])<<8); + for(i=0;i= 200) && ( <= 254) + submessleng = messleng-2; // Submessleng not necessary + } + else + { + if (toindex == 0xff) + { + for(i=connecthead;i>=0;i=connectpoint2[i]) + if (i != *otherconnectindex) + { + if (i == myconnectindex) j = getmess[k]; + k++; + } + } + else + j = getmess[k++]; + + if (j != netincnt[*otherconnectindex]) + { + submessleng = (short)getmess[k]+(((short)getmess[k+1])<<8); + k += submessleng+2; + continue; + } + netincnt[*otherconnectindex]++; + + submessleng = (short)getmess[k]+(((short)getmess[k+1])<<8); k += 2; + } + for(i=0;i 0) && (bufptr[0] >= 200)) //200-255 are messages for engine's use only + { + if (bufptr[0] >= 253) + { + processreservedmessage(submessleng,bufptr); + if ((bufptr[0] == 253) || (bufptr[0] == 254)) return(0); + } + return(submessleng); + } + } + if (*otherconnectindex == myconnectindex) return(0); + return(submessleng); //Got good packet + } + + syncstate++; //DON'T WANT TO GET HERE!!! + //Increment inbufplc to make it not continuously screw up! + *netinbufplc = (((*netinbufplc)+messleng+2)&(COMBUFSIZ-1)); + } + return(0); +} + +void initcrc(void) +{ + long i, j, k, a; + + for(j=0;j<256;j++) //Calculate CRC table + { + k = (j<<8); a = 0; + for(i=7;i>=0;i--) + { + if (((k^a)&0x8000) > 0) + a = ((a<<1)&65535) ^ 0x1021; //0x1021 = genpoly + else + a = ((a<<1)&65535); + k = ((k<<1)&65535); + } + crctable[j] = (a&65535); + } +} + +long getcrc(char *buffer, short bufleng) +{ + long i, j; + + j = 0; + for(i=bufleng-1;i>=0;i--) updatecrc16(j,buffer[i]); + return(j&65535); +} + +void installbicomhandlers(void) +{ +#ifdef PLATFORM_DOS + union REGS r; + struct SREGS sr; + long lowp; + void far *fh; + + //Get old protected mode handler + r.x.eax = 0x3500+comvect; /* DOS get vector (INT 0Ch) */ + sr.ds = sr.es = 0; + int386x(0x21,&r,&r,&sr); + orig_pm_sel = (unsigned short)sr.es; + orig_pm_off = r.x.ebx; + + //Get old real mode handler + r.x.eax = 0x0200; /* DPMI get real mode vector */ + r.h.bl = comvect; + int386(0x31,&r,&r); + orig_rm_seg = (unsigned short)r.x.ecx; + orig_rm_off = (unsigned short)r.x.edx; + + //Allocate memory in low memory to store real mode handler + if ((lowp = convalloc32(COMCODEBYTES+(COMBUFSIZ<<1))) == 0) + { printf("Can't allocate conventional memory.\n"); exit; } + + inbufplc = (short *)(lowp+0); + inbufend = (short *)(lowp+2); + outbufplc = (short *)(lowp+4); + outbufend = (short *)(lowp+6); + comport = (short *)(lowp+8); + comtype = (char *)(lowp+10); + comerror = (char *)(lowp+11); + comresend = (char *)(lowp+12); + incnt = (char *)(lowp+13); + inbuf = (char *)(lowp+COMCODEBYTES); + outbuf = (char *)(lowp+COMCODEBYTES+COMBUFSIZ); + + memcpy((void *)lowp,(void *)rmbuffer,COMCODEBYTES); + + //Set new protected mode handler + r.x.eax = 0x2500+comvect; /* DOS set vector (INT 0Ch) */ + fh = (void far *)comhandler; + r.x.edx = FP_OFF(fh); + sr.ds = FP_SEG(fh); //DS:EDX == &handler + sr.es = 0; + int386x(0x21,&r,&r,&sr); + + //Set new real mode handler (must be after setting protected mode) + r.x.eax = 0x0201; + r.h.bl = comvect; //CX:DX == real mode &handler + r.x.ecx = ((lowp>>4)&0xffff); //D32realseg + r.x.edx = COMCODEOFFS; //D32realoff + int386(0x31,&r,&r); +#else + fprintf (stderr,"%s, line %d; installbicomhandlers() called\n", + __FILE__, __LINE__); +#endif +} + +void uninstallbicomhandlers(void) +{ +#ifdef PLATFORM_DOS + union REGS r; + struct SREGS sr; + + //restore old protected mode handler + r.x.eax = 0x2500+comvect; /* DOS set vector (INT 0Ch) */ + r.x.edx = orig_pm_off; + sr.ds = orig_pm_sel; /* DS:EDX == &handler */ + sr.es = 0; + int386x(0x21,&r,&r,&sr); + + //restore old real mode handler + r.x.eax = 0x0201; /* DPMI set real mode vector */ + r.h.bl = comvect; + r.x.ecx = (unsigned long)orig_rm_seg; //CX:DX == real mode &handler + r.x.edx = (unsigned long)orig_rm_off; + int386(0x31,&r,&r); +#else + fprintf (stderr, "%s line %d; uninstallbicomhandlers() called\n", + __FILE__, __LINE__); +#endif +} + +void processreservedmessage(short tempbufleng, char *datempbuf) +{ + long i, j, k, daotherconnectnum, templong; + + switch(datempbuf[0]) + { + //[253] (login, if myconnectnum's lowest, then respond with packet type 254) + case 253: + if (multioption < 5) + { + otherconnectnum = ((long)datempbuf[1])+(((long)datempbuf[2])<<8)+(((long)datempbuf[3])<<16)+(((long)datempbuf[4])<<24); + + datempbuf[0] = 254; + sendpacket(-1,datempbuf,1); + + myconnectindex = 0; + connecthead = 0; connectpoint2[0] = 1; connectpoint2[1] = -1; + numplayers = 2; + } + else if (multioption >= 5) + { + daotherconnectnum = ((long)datempbuf[1])+((long)(datempbuf[2]<<8))+((long)(datempbuf[3]<<16))+((long)(datempbuf[4]<<24)); + if (daotherconnectnum != myconnectnum) + { + netinitconnection(daotherconnectnum,&datempbuf[5]); + + if ((myconnectindex == connecthead) || ((connectnum[connecthead] == daotherconnectnum) && (myconnectindex == connectpoint2[connecthead]))) + { + datempbuf[0] = 254; + j = 1; + for(i=0;i>8)&255); + datempbuf[j++] = ((connectnum[i]>>16)&255); + datempbuf[j++] = ((connectnum[i]>>24)&255); + + for(k=0;k<10;k++) + datempbuf[j++] = compaddr[i][k]; + } + + //While this doesn't have to be a broadcast, sending + //this info again makes good error correction + sendpacket(-1,datempbuf,j); + + for(i=0;i= 5) + { + j = 1; + while (j < tempbufleng) + { + templong = ((long)datempbuf[j])+((long)(datempbuf[j+1]<<8))+((long)(datempbuf[j+2]<<16))+((long)(datempbuf[j+3]<<24)); + netinitconnection(templong,&datempbuf[j+4]); + j += 14; + } + } + break; + case 255: + if (multioption >= 5) + netuninitconnection(datempbuf[1]); + break; + } +} + +void sendlogon(void) +{ + long i; + char tempbuf[16]; + + if (multioption <= 0) + return; + + tempbuf[0] = 253; + if (multioption < 5) + { + tempbuf[1] = kinp(0x40); + tempbuf[2] = kinp(0x40); + tempbuf[3] = kinp(0x40); + tempbuf[4] = mypriority; + myconnectnum = ((long)tempbuf[1])+(((long)tempbuf[2])<<8)+(((long)tempbuf[3])<<16)+(((long)mypriority)<<24); + sendpacket(-1,tempbuf,5); + } + else + { + tempbuf[1] = (myconnectnum&255); + tempbuf[2] = ((myconnectnum>>8)&255); + tempbuf[3] = ((myconnectnum>>16)&255); + tempbuf[4] = ((myconnectnum>>24)&255); + for(i=0;i<10;i++) + tempbuf[i+5] = mycompaddr[i]; + + sendpacket(-1,tempbuf,15); + } +} + +void sendlogoff(void) +{ + char tempbuf[16]; + long i; + + if ((numplayers <= 1) || (multioption <= 0)) return; + + tempbuf[0] = 255; + if (multioption < 5) + { + sendpacket(-1,tempbuf,1); + } + else + { + tempbuf[1] = myconnectindex; + for(i=connecthead;i>=0;i=connectpoint2[i]) + if (i != myconnectindex) + sendpacket(i,tempbuf,2); + } +} + +int getoutputcirclesize(void) +{ + if ((multioption >= 1) && (multioption <= 4)) + { + startcom(); + return(((*outbufend)-(*outbufplc)+COMBUFSIZ)&(COMBUFSIZ-1)); + } + return(0); +} + +int setsocket(short newsocket) +{ + long i; + + if (multioption < 5) + { + socket = newsocket; + return(0); + } + + simulateint(0x7a,0L,(long)0x1,0L,(long)socket,0L,0L); //Closesocket + + socket = newsocket; + + simulateint(0x7a,0L,(long)0x1,0L,(long)socket,0L,0L); //Closesocket + if ((simulateint(0x7a,(long)0xff,0L,0L,(long)socket,0L,0L)&255) != 0) return(-2); //Opensocket + mycompaddr[10] = (socket&255); + mycompaddr[11] = (socket>>8); + ecbget[10] = (socket&255); + ecbget[11] = (socket>>8); + for(i=0;i>8); + } + return(0); +} diff --git a/buildengine/names.h b/buildengine/names.h new file mode 100755 index 0000000..6bd761e --- /dev/null +++ b/buildengine/names.h @@ -0,0 +1,49 @@ +/*Be careful when changing this file - it is parsed by Editart and Build.*/ +#define SWITCH1ON 15 +#define SLIME 34 +#define BACKGROUND 37 +#define KENPICTURE 48 +#define BUILDDISK 49 +#define SWITCH2ON 66 +#define SWITCH2OFF 69 +#define ALPHABET 73 +#define NO 74 +#define DEMOSIGN 75 +#define COIN 76 +#define COINSTACK 77 +#define GIFTBOX 78 +#define DIAMONDS 79 +#define EVILALGRAVE 83 +#define STATUSBAR 87 +#define DAYSKY 89 +#define WATERFOUNTAIN 90 +#define USEWATERFOUNTAIN 91 +#define NIGHTSKY 93 +#define BULLET 98 +#define BOMB 100 +#define CANNON 101 +#define GUNONBOTTOM 102 +#define BOMBEMITTER 103 +#define EXPLOSION 105 +#define SPLASH 106 +#define BROWNMONSTER 110 +#define SKELETON 113 +#define AL 114 +#define EVILAL 115 +#define PLAYER 120 +#define SWITCH3OFF 146 +#define SWITCH3ON 147 +#define AIRPLANE 148 +#define SPIRAL 149 +#define COMPASS 150 +#define FOOTPRINT 156 +#define STATUSBARFILL8 160 +#define STATUSBARFILL4 161 +#define BOUNCYMAT 162 +#define MIRROR 165 +#define FLOORMIRROR 166 +#define GRABBER 167 +#define GRABCANNON 168 +#define MISSILE 169 +#define LAUNCHER 171 +#define MIRRORLABEL 4000 diff --git a/buildengine/nsnoal.map b/buildengine/nsnoal.map new file mode 100755 index 0000000..e62c63c Binary files /dev/null and b/buildengine/nsnoal.map differ diff --git a/buildengine/nukeland.map b/buildengine/nukeland.map new file mode 100755 index 0000000..09ab92b Binary files /dev/null and b/buildengine/nukeland.map differ diff --git a/buildengine/platform.h b/buildengine/platform.h new file mode 100755 index 0000000..73cd177 --- /dev/null +++ b/buildengine/platform.h @@ -0,0 +1,104 @@ +#ifndef _INCLUDE_PLATFORM_H_ +#define _INCLUDE_PLATFORM_H_ + +#if (defined PLATFORM_WIN32) +#include "win32_compat.h" +#elif (defined PLATFORM_MACOSX) +#include "unix_compat.h" +#include +#elif (defined PLATFORM_FREEBSD) +#include "unix_compat.h" +#include +#elif (defined PLATFORM_UNIX) +#include "unix_compat.h" +#if !defined(__SUNPRO_C) +#include +#endif +#elif (defined PLATFORM_DOS) +#include "doscmpat.h" +#else +#error Define your platform! +#endif + +#ifdef PLATFORM_MACOSX + /* may be an x86 Mac, so turn off PowerPC ASM and Altivec if needed... */ + #if __POWERPC__ + #define HAVE_POWERPC 1 + #endif +#endif + +#ifdef PLATFORM_LINUXPPC +#define HAVE_POWERPC 1 +#endif + +#if (!defined __EXPORT__) +#define __EXPORT__ +#endif + +#if ((defined PLATFORM_SUPPORTS_SDL) && (!defined PLATFORM_TIMER_HZ)) +#define PLATFORM_TIMER_HZ 100 +#endif + +#if (!defined PLATFORM_TIMER_HZ) +#error You need to define PLATFORM_TIMER_HZ for your platform. +#endif + +#if (defined __WATCOMC__) +#define snprintf _snprintf +#endif + +#if (defined __SUNPRO_C) +#define __inline inline +#endif + +static __inline unsigned short _swap16(unsigned short D) +{ +#if HAVE_POWERPC + register unsigned short returnValue; + __asm__ volatile("lhbrx %0,0,%1" + : "=r" (returnValue) + : "r" (&D) + ); + return returnValue; +#else + return((D<<8)|(D>>8)); +#endif +} + +static __inline unsigned int _swap32(unsigned int D) +{ +#if HAVE_POWERPC + register unsigned int returnValue; + __asm__ volatile("lwbrx %0,0,%1" + : "=r" (returnValue) + : "r" (&D) + ); + return returnValue; +#else + return((D<<24)|((D<<8)&0x00FF0000)|((D>>8)&0x0000FF00)|(D>>24)); +#endif +} + +#if HAVE_POWERPC +#define PLATFORM_BIGENDIAN 1 +#define BUILDSWAP_INTEL16(x) _swap16(x) +#define BUILDSWAP_INTEL32(x) _swap32(x) +#else +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define PLATFORM_LITTLEENDIAN 1 +#define BUILDSWAP_INTEL16(x) (x) +#define BUILDSWAP_INTEL32(x) (x) +#else +#define PLATFORM_BIGENDIAN 1 +#define BUILDSWAP_INTEL16(x) _swap16(x) +#define BUILDSWAP_INTEL32(x) _swap32(x) +#endif +#endif + +extern int has_altivec; /* PowerPC-specific. */ + +#endif /* !defined _INCLUDE_PLATFORM_H_ */ + +/* end of platform.h ... */ + + diff --git a/buildengine/pragmas.c b/buildengine/pragmas.c new file mode 100755 index 0000000..7009fac --- /dev/null +++ b/buildengine/pragmas.c @@ -0,0 +1,167 @@ +/* + * Inline assembly. + * + * Initial PLATFORM_UNIX work done by Andrew Henderson. The DOS stuff is + * Ken's original code, and was in pragmas.h + * + * Please do NOT harrass Ken Silverman about any code modifications + * (including this file) to BUILD. + */ + +/* + * "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman + * Ken Silverman's official web site: "http://www.advsys.net/ken" + * See the included license file "BUILDLIC.TXT" for license info. + * This file has been modified from Ken Silverman's original release + */ + +#include // memcpy +#include +#include "platform.h" +#include "pragmas.h" + +#define low32(a) ((a&0xffffffff)) + +unsigned long getkensmessagecrc(long param) { + return(0x56c764d4); +} + +long msqrtasm(int i1) +{ + int retval = 0x40000000; + int temp = 0x20000000; + + while (temp != 0) + { + if (i1 >= retval) + { + i1 -= retval; + retval += temp*4; + } + retval -= temp; + retval >>= 1; + temp >>= 2; + } + + if (i1 >= retval) retval--; + retval >>= 1; + return(retval); +} + + +void clearbuf(void *buffer, int size, long fill_value) { + int i; + for (i = 0; i < size; i++) ((long*)buffer)[i] = fill_value; +} + +void clearbufbyte(void *vpbuffer, int size, long fill_value) { + unsigned char *buffer = (unsigned char *) vpbuffer; + int lsize; + switch(size){ + case 0: return; + case 1: *buffer = fill_value; return; + case 2: *((unsigned short*)buffer) = fill_value; return; + case 3: { buffer[2]=buffer[1]=buffer[0] = fill_value;} return; + default: + if ((int)buffer&1) { + *buffer = fill_value; size--; + buffer++; + } + if ((int)buffer&2) { + *((unsigned short*)buffer) = fill_value; size-=2; + buffer += 2; + } + lsize = size>>2; + while(lsize) { + *((unsigned int*)buffer) = fill_value; + lsize--; + buffer += 4; + } + if (size&2) { + *((unsigned short*)buffer) = fill_value; + buffer += 2; + } + if (size&1) { + *((unsigned char*)buffer) = fill_value; + buffer++; + } + } +} + +void copybuf(void *source, void *dest, int size) { + int i; + for (i = 0; i < size; i++) ((long*)dest)[i] = ((long*)source)[i]; +} + +void copybufbyte(void *source, void *dest, int size) { + memcpy(dest,source,size); +} + +void copybufreverse(void *source, void *dest, int size) { + unsigned char *s=source,*d=dest; + do { + *d++ = *s--; + } while(--size); +} + +void qinterpolatedown16 (long *source, int size, int linum, int linum_inc) { + if (size == 0) + { + *source = (linum>>16); + return; + } + + while (size) + { + *source = (linum>>16); + source++; + linum += linum_inc; + size--; + } +} + +void qinterpolatedown16short (long *source, int size, int linum, int linum_inc) +{ + if (size == 0) return; + + if ((long)source & 0x2) + { + unsigned short *src = (unsigned short *) source; + *src = ((linum>>16)&0xffff); + src++; + linum += linum_inc; + source = (long *) src; + + size--; + if (size == 0) return; + } + size -= 2; + if (size < 0) + { + *((unsigned short *)source) = ((linum>>16)&0xffff); + return; + } + + while (size >= 0) + { + // DDOI - this fix is from the Amiga port guys + // http://www.neoscientists.org/~dante/ +#ifdef PLATFORM_BIGENDIAN + int temp = linum & 0xffff0000; + linum += linum_inc; + temp |= (linum>>16); + linum += linum_inc; +#else + int temp = linum>>16; + linum += linum_inc; + temp += (linum&0xffff0000); + linum += linum_inc; +#endif + *source = temp; + source++; + size -= 2; + } + if (size & 1) + *((unsigned short *)source) = ((linum>>16)&0xffff); +} + diff --git a/buildengine/pragmas.h b/buildengine/pragmas.h new file mode 100755 index 0000000..e7afa22 --- /dev/null +++ b/buildengine/pragmas.h @@ -0,0 +1,2628 @@ +/* + * "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman + * Ken Silverman's official web site: "http://www.advsys.net/ken" + * See the included license file "BUILDLIC.TXT" for license info. + * This file has been modified from Ken Silverman's original release + */ + +#ifndef __PRAGMAS_H__ +#define __PRAGMAS_H__ + +#if (defined __WATCOMC__) + +static long dmval = 0; + +long is_vmware_running(void); +#pragma aux is_vmware_running modify exact [eax ebx ecx edx]; + +unsigned long getkensmessagecrc(long param); +#pragma aux getkensmessagecrc =\ + "xor eax, eax",\ + "mov ecx, 32",\ + "beg: mov edx, dword ptr [ebx+ecx*4-4]",\ + "ror edx, cl",\ + "adc eax, edx",\ + "bswap eax",\ + "loop short beg",\ + parm [ebx]\ + modify exact [eax ebx ecx edx]\ + +long msqrtasm(int param); +#pragma aux msqrtasm =\ + "mov eax, 0x40000000",\ + "mov ebx, 0x20000000",\ + "begit: cmp ecx, eax",\ + "jl skip",\ + "sub ecx, eax",\ + "lea eax, [eax+ebx*4]",\ + "skip: sub eax, ebx",\ + "shr eax, 1",\ + "shr ebx, 2",\ + "jnz begit",\ + "cmp ecx, eax",\ + "sbb eax, -1",\ + "shr eax, 1",\ + parm nomemory [ecx]\ + modify exact [eax ebx ecx]\ + +int sqr(int i1); +#pragma aux sqr =\ + "imul eax, eax",\ + parm nomemory [eax]\ + modify exact [eax]\ + value [eax] + +long scale(long i1, long i2, long i3); +#pragma aux scale =\ + "imul edx",\ + "idiv ecx",\ + parm nomemory [eax][edx][ecx]\ + modify exact [eax edx]\ + +long mulscale(long i1, long i2, long i3); +#pragma aux mulscale =\ + "imul edx",\ + "shrd eax, edx, cl",\ + parm nomemory [eax][edx][ecx]\ + modify exact [eax edx]\ + +long mulscale1(long i1, long i2); +#pragma aux mulscale1 =\ + "imul edx",\ + "shrd eax, edx, 1",\ + parm nomemory [eax][edx]\ + modify exact [eax edx]\ + +long mulscale2(long i1, long i2); +#pragma aux mulscale2 =\ + "imul edx",\ + "shrd eax, edx, 2",\ + parm nomemory [eax][edx]\ + modify exact [eax edx]\ + +long mulscale3(long i1, long i2); +#pragma aux mulscale3 =\ + "imul edx",\ + "shrd eax, edx, 3",\ + parm nomemory [eax][edx]\ + modify exact [eax edx]\ + +long mulscale4(long i1, long i2); +#pragma aux mulscale4 =\ + "imul edx",\ + "shrd eax, edx, 4",\ + parm nomemory [eax][edx]\ + modify exact [eax edx]\ + +long mulscale5(long i1, long i2); +#pragma aux mulscale5 =\ + "imul edx",\ + "shrd eax, edx, 5",\ + parm nomemory [eax][edx]\ + modify exact [eax edx]\ + +long mulscale6(long i1, long i2); +#pragma aux mulscale6 =\ + "imul edx",\ + "shrd eax, edx, 6",\ + parm nomemory [eax][edx]\ + modify exact [eax edx]\ + +long mulscale7(long i1, long i2); +#pragma aux mulscale7 =\ + "imul edx",\ + "shrd eax, edx, 7",\ + parm nomemory [eax][edx]\ + modify exact [eax edx]\ + +long mulscale8(long i1, long i2); +#pragma aux mulscale8 =\ + "imul edx",\ + "shrd eax, edx, 8",\ + parm nomemory [eax][edx]\ + modify exact [eax edx]\ + +long mulscale9(long i1, long i2); +#pragma aux mulscale9 =\ + "imul edx",\ + "shrd eax, edx, 9",\ + parm nomemory [eax][edx]\ + modify exact [eax edx]\ + +long mulscale10(long i1, long i2); +#pragma aux mulscale10 =\ + "imul edx",\ + "shrd eax, edx, 10",\ + parm nomemory [eax][edx]\ + modify exact [eax edx]\ + +long mulscale11(long i1, long i2); +#pragma aux mulscale11 =\ + "imul edx",\ + "shrd eax, edx, 11",\ + parm nomemory [eax][edx]\ + modify exact [eax edx]\ + +long mulscale12(long i1, long i2); +#pragma aux mulscale12 =\ + "imul edx",\ + "shrd eax, edx, 12",\ + parm nomemory [eax][edx]\ + modify exact [eax edx]\ + +long mulscale13(long i1, long i2); +#pragma aux mulscale13 =\ + "imul edx",\ + "shrd eax, edx, 13",\ + parm nomemory [eax][edx]\ + modify exact [eax edx]\ + +long mulscale14(long i1, long i2); +#pragma aux mulscale14 =\ + "imul edx",\ + "shrd eax, edx, 14",\ + parm nomemory [eax][edx]\ + modify exact [eax edx]\ + +long mulscale15(long i1, long i2); +#pragma aux mulscale15 =\ + "imul edx",\ + "shrd eax, edx, 15",\ + parm nomemory [eax][edx]\ + modify exact [eax edx]\ + +long mulscale16(long i1, long i2); +#pragma aux mulscale16 =\ + "imul edx",\ + "shrd eax, edx, 16",\ + parm nomemory [eax][edx]\ + modify exact [eax edx]\ + +long mulscale17(long i1, long i2); +#pragma aux mulscale17 =\ + "imul edx",\ + "shrd eax, edx, 17",\ + parm nomemory [eax][edx]\ + modify exact [eax edx]\ + +long mulscale18(long i1, long i2); +#pragma aux mulscale18 =\ + "imul edx",\ + "shrd eax, edx, 18",\ + parm nomemory [eax][edx]\ + modify exact [eax edx]\ + +long mulscale19(long i1, long i2); +#pragma aux mulscale19 =\ + "imul edx",\ + "shrd eax, edx, 19",\ + parm nomemory [eax][edx]\ + modify exact [eax edx]\ + +long mulscale20(long i1, long i2); +#pragma aux mulscale20 =\ + "imul edx",\ + "shrd eax, edx, 20",\ + parm nomemory [eax][edx]\ + modify exact [eax edx]\ + +long mulscale21(long i1, long i2); +#pragma aux mulscale21 =\ + "imul edx",\ + "shrd eax, edx, 21",\ + parm nomemory [eax][edx]\ + modify exact [eax edx]\ + +long mulscale22(long i1, long i2); +#pragma aux mulscale22 =\ + "imul edx",\ + "shrd eax, edx, 22",\ + parm nomemory [eax][edx]\ + modify exact [eax edx]\ + +long mulscale23(long i1, long i2); +#pragma aux mulscale23 =\ + "imul edx",\ + "shrd eax, edx, 23",\ + parm nomemory [eax][edx]\ + modify exact [eax edx]\ + +long mulscale24(long i1, long i2); +#pragma aux mulscale24 =\ + "imul edx",\ + "shrd eax, edx, 24",\ + parm nomemory [eax][edx]\ + modify exact [eax edx]\ + +long mulscale25(long i1, long i2); +#pragma aux mulscale25 =\ + "imul edx",\ + "shrd eax, edx, 25",\ + parm nomemory [eax][edx]\ + modify exact [eax edx]\ + +long mulscale26(long i1, long i2); +#pragma aux mulscale26 =\ + "imul edx",\ + "shrd eax, edx, 26",\ + parm nomemory [eax][edx]\ + modify exact [eax edx]\ + +long mulscale27(long i1, long i2); +#pragma aux mulscale27 =\ + "imul edx",\ + "shrd eax, edx, 27",\ + parm nomemory [eax][edx]\ + modify exact [eax edx]\ + +long mulscale28(long i1, long i2); +#pragma aux mulscale28 =\ + "imul edx",\ + "shrd eax, edx, 28",\ + parm nomemory [eax][edx]\ + modify exact [eax edx]\ + +long mulscale29(long i1, long i2); +#pragma aux mulscale29 =\ + "imul edx",\ + "shrd eax, edx, 29",\ + parm nomemory [eax][edx]\ + modify exact [eax edx]\ + +long mulscale30(long i1, long i2); +#pragma aux mulscale30 =\ + "imul edx",\ + "shrd eax, edx, 30",\ + parm nomemory [eax][edx]\ + modify exact [eax edx]\ + +long mulscale31(long i1, long i2); +#pragma aux mulscale31 =\ + "imul edx",\ + "shrd eax, edx, 31",\ + parm nomemory [eax][edx]\ + modify exact [eax edx]\ + +long mulscale32(long i1, long i2); +#pragma aux mulscale32 =\ + "imul edx",\ + parm nomemory [eax][edx]\ + modify exact [eax edx]\ + value [edx]\ + +long dmulscale(long i1, long i2, long i3, long i4, long i5); +#pragma aux dmulscale =\ + "imul edx",\ + "mov ebx, eax",\ + "mov eax, esi",\ + "mov esi, edx",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, esi",\ + "shrd eax, edx, cl",\ + parm nomemory [eax][edx][esi][edi][ecx]\ + modify exact [eax ebx edx esi]\ + +long dmulscale1(long i1, long i2, long i3, long i4); +#pragma aux dmulscale1 =\ + "imul edx",\ + "mov ebx, eax",\ + "mov eax, esi",\ + "mov esi, edx",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, esi",\ + "shrd eax, edx, 1",\ + parm nomemory [eax][edx][esi][edi]\ + modify exact [eax ebx edx esi]\ + +long dmulscale2(long i1, long i2, long i3, long i4); +#pragma aux dmulscale2 =\ + "imul edx",\ + "mov ebx, eax",\ + "mov eax, esi",\ + "mov esi, edx",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, esi",\ + "shrd eax, edx, 2",\ + parm nomemory [eax][edx][esi][edi]\ + modify exact [eax ebx edx esi]\ + +long dmulscale3(long i1, long i2, long i3, long i4); +#pragma aux dmulscale3 =\ + "imul edx",\ + "mov ebx, eax",\ + "mov eax, esi",\ + "mov esi, edx",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, esi",\ + "shrd eax, edx, 3",\ + parm nomemory [eax][edx][esi][edi]\ + modify exact [eax ebx edx esi]\ + +long dmulscale4(long i1, long i2, long i3, long i4); +#pragma aux dmulscale4 =\ + "imul edx",\ + "mov ebx, eax",\ + "mov eax, esi",\ + "mov esi, edx",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, esi",\ + "shrd eax, edx, 4",\ + parm nomemory [eax][edx][esi][edi]\ + modify exact [eax ebx edx esi]\ + +long dmulscale5(long i1, long i2, long i3, long i4); +#pragma aux dmulscale5 =\ + "imul edx",\ + "mov ebx, eax",\ + "mov eax, esi",\ + "mov esi, edx",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, esi",\ + "shrd eax, edx, 5",\ + parm nomemory [eax][edx][esi][edi]\ + modify exact [eax ebx edx esi]\ + +long dmulscale6(long i1, long i2, long i3, long i4); +#pragma aux dmulscale6 =\ + "imul edx",\ + "mov ebx, eax",\ + "mov eax, esi",\ + "mov esi, edx",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, esi",\ + "shrd eax, edx, 6",\ + parm nomemory [eax][edx][esi][edi]\ + modify exact [eax ebx edx esi]\ + +long dmulscale7(long i1, long i2, long i3, long i4); +#pragma aux dmulscale7 =\ + "imul edx",\ + "mov ebx, eax",\ + "mov eax, esi",\ + "mov esi, edx",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, esi",\ + "shrd eax, edx, 7",\ + parm nomemory [eax][edx][esi][edi]\ + modify exact [eax ebx edx esi]\ + +long dmulscale8(long i1, long i2, long i3, long i4); +#pragma aux dmulscale8 =\ + "imul edx",\ + "mov ebx, eax",\ + "mov eax, esi",\ + "mov esi, edx",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, esi",\ + "shrd eax, edx, 8",\ + parm nomemory [eax][edx][esi][edi]\ + modify exact [eax ebx edx esi]\ + +long dmulscale9(long i1, long i2, long i3, long i4); +#pragma aux dmulscale9 =\ + "imul edx",\ + "mov ebx, eax",\ + "mov eax, esi",\ + "mov esi, edx",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, esi",\ + "shrd eax, edx, 9",\ + parm nomemory [eax][edx][esi][edi]\ + modify exact [eax ebx edx esi]\ + +long dmulscale10(long i1, long i2, long i3, long i4); +#pragma aux dmulscale10 =\ + "imul edx",\ + "mov ebx, eax",\ + "mov eax, esi",\ + "mov esi, edx",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, esi",\ + "shrd eax, edx, 10",\ + parm nomemory [eax][edx][esi][edi]\ + modify exact [eax ebx edx esi]\ + +long dmulscale11(long i1, long i2, long i3, long i4); +#pragma aux dmulscale11 =\ + "imul edx",\ + "mov ebx, eax",\ + "mov eax, esi",\ + "mov esi, edx",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, esi",\ + "shrd eax, edx, 11",\ + parm nomemory [eax][edx][esi][edi]\ + modify exact [eax ebx edx esi]\ + +long dmulscale12(long i1, long i2, long i3, long i4); +#pragma aux dmulscale12 =\ + "imul edx",\ + "mov ebx, eax",\ + "mov eax, esi",\ + "mov esi, edx",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, esi",\ + "shrd eax, edx, 12",\ + parm nomemory [eax][edx][esi][edi]\ + modify exact [eax ebx edx esi]\ + +long dmulscale13(long i1, long i2, long i3, long i4); +#pragma aux dmulscale13 =\ + "imul edx",\ + "mov ebx, eax",\ + "mov eax, esi",\ + "mov esi, edx",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, esi",\ + "shrd eax, edx, 13",\ + parm nomemory [eax][edx][esi][edi]\ + modify exact [eax ebx edx esi]\ + +long dmulscale14(long i1, long i2, long i3, long i4); +#pragma aux dmulscale14 =\ + "imul edx",\ + "mov ebx, eax",\ + "mov eax, esi",\ + "mov esi, edx",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, esi",\ + "shrd eax, edx, 14",\ + parm nomemory [eax][edx][esi][edi]\ + modify exact [eax ebx edx esi]\ + +long dmulscale15(long i1, long i2, long i3, long i4); +#pragma aux dmulscale15 =\ + "imul edx",\ + "mov ebx, eax",\ + "mov eax, esi",\ + "mov esi, edx",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, esi",\ + "shrd eax, edx, 15",\ + parm nomemory [eax][edx][esi][edi]\ + modify exact [eax ebx edx esi]\ + +long dmulscale16(long i1, long i2, long i3, long i4); +#pragma aux dmulscale16 =\ + "imul edx",\ + "mov ebx, eax",\ + "mov eax, esi",\ + "mov esi, edx",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, esi",\ + "shrd eax, edx, 16",\ + parm nomemory [eax][edx][esi][edi]\ + modify exact [eax ebx edx esi]\ + +long dmulscale17(long i1, long i2, long i3, long i4); +#pragma aux dmulscale17 =\ + "imul edx",\ + "mov ebx, eax",\ + "mov eax, esi",\ + "mov esi, edx",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, esi",\ + "shrd eax, edx, 17",\ + parm nomemory [eax][edx][esi][edi]\ + modify exact [eax ebx edx esi]\ + +long dmulscale18(long i1, long i2, long i3, long i4); +#pragma aux dmulscale18 =\ + "imul edx",\ + "mov ebx, eax",\ + "mov eax, esi",\ + "mov esi, edx",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, esi",\ + "shrd eax, edx, 18",\ + parm nomemory [eax][edx][esi][edi]\ + modify exact [eax ebx edx esi]\ + +long dmulscale19(long i1, long i2, long i3, long i4); +#pragma aux dmulscale19 =\ + "imul edx",\ + "mov ebx, eax",\ + "mov eax, esi",\ + "mov esi, edx",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, esi",\ + "shrd eax, edx, 19",\ + parm nomemory [eax][edx][esi][edi]\ + modify exact [eax ebx edx esi]\ + +long dmulscale20(long i1, long i2, long i3, long i4); +#pragma aux dmulscale20 =\ + "imul edx",\ + "mov ebx, eax",\ + "mov eax, esi",\ + "mov esi, edx",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, esi",\ + "shrd eax, edx, 20",\ + parm nomemory [eax][edx][esi][edi]\ + modify exact [eax ebx edx esi]\ + +long dmulscale21(long i1, long i2, long i3, long i4); +#pragma aux dmulscale21 =\ + "imul edx",\ + "mov ebx, eax",\ + "mov eax, esi",\ + "mov esi, edx",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, esi",\ + "shrd eax, edx, 21",\ + parm nomemory [eax][edx][esi][edi]\ + modify exact [eax ebx edx esi]\ + +long dmulscale22(long i1, long i2, long i3, long i4); +#pragma aux dmulscale22 =\ + "imul edx",\ + "mov ebx, eax",\ + "mov eax, esi",\ + "mov esi, edx",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, esi",\ + "shrd eax, edx, 22",\ + parm nomemory [eax][edx][esi][edi]\ + modify exact [eax ebx edx esi]\ + +long dmulscale23(long i1, long i2, long i3, long i4); +#pragma aux dmulscale23 =\ + "imul edx",\ + "mov ebx, eax",\ + "mov eax, esi",\ + "mov esi, edx",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, esi",\ + "shrd eax, edx, 23",\ + parm nomemory [eax][edx][esi][edi]\ + modify exact [eax ebx edx esi]\ + +long dmulscale24(long i1, long i2, long i3, long i4); +#pragma aux dmulscale24 =\ + "imul edx",\ + "mov ebx, eax",\ + "mov eax, esi",\ + "mov esi, edx",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, esi",\ + "shrd eax, edx, 24",\ + parm nomemory [eax][edx][esi][edi]\ + modify exact [eax ebx edx esi]\ + +long dmulscale25(long i1, long i2, long i3, long i4); +#pragma aux dmulscale25 =\ + "imul edx",\ + "mov ebx, eax",\ + "mov eax, esi",\ + "mov esi, edx",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, esi",\ + "shrd eax, edx, 25",\ + parm nomemory [eax][edx][esi][edi]\ + modify exact [eax ebx edx esi]\ + +long dmulscale26(long i1, long i2, long i3, long i4); +#pragma aux dmulscale26 =\ + "imul edx",\ + "mov ebx, eax",\ + "mov eax, esi",\ + "mov esi, edx",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, esi",\ + "shrd eax, edx, 26",\ + parm nomemory [eax][edx][esi][edi]\ + modify exact [eax ebx edx esi]\ + +long dmulscale27(long i1, long i2, long i3, long i4); +#pragma aux dmulscale27 =\ + "imul edx",\ + "mov ebx, eax",\ + "mov eax, esi",\ + "mov esi, edx",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, esi",\ + "shrd eax, edx, 27",\ + parm nomemory [eax][edx][esi][edi]\ + modify exact [eax ebx edx esi]\ + +long dmulscale28(long i1, long i2, long i3, long i4); +#pragma aux dmulscale28 =\ + "imul edx",\ + "mov ebx, eax",\ + "mov eax, esi",\ + "mov esi, edx",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, esi",\ + "shrd eax, edx, 28",\ + parm nomemory [eax][edx][esi][edi]\ + modify exact [eax ebx edx esi]\ + +long dmulscale29(long i1, long i2, long i3, long i4); +#pragma aux dmulscale29 =\ + "imul edx",\ + "mov ebx, eax",\ + "mov eax, esi",\ + "mov esi, edx",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, esi",\ + "shrd eax, edx, 29",\ + parm nomemory [eax][edx][esi][edi]\ + modify exact [eax ebx edx esi]\ + +long dmulscale30(long i1, long i2, long i3, long i4); +#pragma aux dmulscale30 =\ + "imul edx",\ + "mov ebx, eax",\ + "mov eax, esi",\ + "mov esi, edx",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, esi",\ + "shrd eax, edx, 30",\ + parm nomemory [eax][edx][esi][edi]\ + modify exact [eax ebx edx esi]\ + +long dmulscale31(long i1, long i2, long i3, long i4); +#pragma aux dmulscale31 =\ + "imul edx",\ + "mov ebx, eax",\ + "mov eax, esi",\ + "mov esi, edx",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, esi",\ + "shrd eax, edx, 31",\ + parm nomemory [eax][edx][esi][edi]\ + modify exact [eax ebx edx esi]\ + +long dmulscale32(long i1, long i2, long i3, long i4); +#pragma aux dmulscale32 =\ + "imul edx",\ + "mov ebx, eax",\ + "mov eax, esi",\ + "mov esi, edx",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, esi",\ + parm nomemory [eax][edx][esi][edi]\ + modify exact [eax ebx edx esi]\ + value [edx]\ + +long tmulscale1(long i1, long i2, long i3, long i4, long i5, long i6); +#pragma aux tmulscale1 =\ + "imul edx",\ + "xchg eax, ebx",\ + "xchg edx, ecx",\ + "imul edx",\ + "add ebx, eax",\ + "adc ecx, edx",\ + "mov eax, esi",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, ecx",\ + "shrd eax, edx, 1",\ + parm nomemory [eax][edx][ebx][ecx][esi][edi]\ + modify exact [eax ebx ecx edx]\ + +long tmulscale2(long i1, long i2, long i3, long i4, long i5, long i6); +#pragma aux tmulscale2 =\ + "imul edx",\ + "xchg eax, ebx",\ + "xchg edx, ecx",\ + "imul edx",\ + "add ebx, eax",\ + "adc ecx, edx",\ + "mov eax, esi",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, ecx",\ + "shrd eax, edx, 2",\ + parm nomemory [eax][edx][ebx][ecx][esi][edi]\ + modify exact [eax ebx ecx edx]\ + +long tmulscale3(long i1, long i2, long i3, long i4, long i5, long i6); +#pragma aux tmulscale3 =\ + "imul edx",\ + "xchg eax, ebx",\ + "xchg edx, ecx",\ + "imul edx",\ + "add ebx, eax",\ + "adc ecx, edx",\ + "mov eax, esi",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, ecx",\ + "shrd eax, edx, 3",\ + parm nomemory [eax][edx][ebx][ecx][esi][edi]\ + modify exact [eax ebx ecx edx]\ + +long tmulscale4(long i1, long i2, long i3, long i4, long i5, long i6); +#pragma aux tmulscale4 =\ + "imul edx",\ + "xchg eax, ebx",\ + "xchg edx, ecx",\ + "imul edx",\ + "add ebx, eax",\ + "adc ecx, edx",\ + "mov eax, esi",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, ecx",\ + "shrd eax, edx, 4",\ + parm nomemory [eax][edx][ebx][ecx][esi][edi]\ + modify exact [eax ebx ecx edx]\ + +long tmulscale5(long i1, long i2, long i3, long i4, long i5, long i6); +#pragma aux tmulscale5 =\ + "imul edx",\ + "xchg eax, ebx",\ + "xchg edx, ecx",\ + "imul edx",\ + "add ebx, eax",\ + "adc ecx, edx",\ + "mov eax, esi",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, ecx",\ + "shrd eax, edx, 5",\ + parm nomemory [eax][edx][ebx][ecx][esi][edi]\ + modify exact [eax ebx ecx edx]\ + +long tmulscale6(long i1, long i2, long i3, long i4, long i5, long i6); +#pragma aux tmulscale6 =\ + "imul edx",\ + "xchg eax, ebx",\ + "xchg edx, ecx",\ + "imul edx",\ + "add ebx, eax",\ + "adc ecx, edx",\ + "mov eax, esi",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, ecx",\ + "shrd eax, edx, 6",\ + parm nomemory [eax][edx][ebx][ecx][esi][edi]\ + modify exact [eax ebx ecx edx]\ + +long tmulscale7(long i1, long i2, long i3, long i4, long i5, long i6); +#pragma aux tmulscale7 =\ + "imul edx",\ + "xchg eax, ebx",\ + "xchg edx, ecx",\ + "imul edx",\ + "add ebx, eax",\ + "adc ecx, edx",\ + "mov eax, esi",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, ecx",\ + "shrd eax, edx, 7",\ + parm nomemory [eax][edx][ebx][ecx][esi][edi]\ + modify exact [eax ebx ecx edx]\ + +long tmulscale8(long i1, long i2, long i3, long i4, long i5, long i6); +#pragma aux tmulscale8 =\ + "imul edx",\ + "xchg eax, ebx",\ + "xchg edx, ecx",\ + "imul edx",\ + "add ebx, eax",\ + "adc ecx, edx",\ + "mov eax, esi",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, ecx",\ + "shrd eax, edx, 8",\ + parm nomemory [eax][edx][ebx][ecx][esi][edi]\ + modify exact [eax ebx ecx edx]\ + +long tmulscale9(long i1, long i2, long i3, long i4, long i5, long i6); +#pragma aux tmulscale9 =\ + "imul edx",\ + "xchg eax, ebx",\ + "xchg edx, ecx",\ + "imul edx",\ + "add ebx, eax",\ + "adc ecx, edx",\ + "mov eax, esi",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, ecx",\ + "shrd eax, edx, 9",\ + parm nomemory [eax][edx][ebx][ecx][esi][edi]\ + modify exact [eax ebx ecx edx]\ + +long tmulscale10(long i1, long i2, long i3, long i4, long i5, long i6); +#pragma aux tmulscale10 =\ + "imul edx",\ + "xchg eax, ebx",\ + "xchg edx, ecx",\ + "imul edx",\ + "add ebx, eax",\ + "adc ecx, edx",\ + "mov eax, esi",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, ecx",\ + "shrd eax, edx, 10",\ + parm nomemory [eax][edx][ebx][ecx][esi][edi]\ + modify exact [eax ebx ecx edx]\ + +long tmulscale11(long i1, long i2, long i3, long i4, long i5, long i6); +#pragma aux tmulscale11 =\ + "imul edx",\ + "xchg eax, ebx",\ + "xchg edx, ecx",\ + "imul edx",\ + "add ebx, eax",\ + "adc ecx, edx",\ + "mov eax, esi",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, ecx",\ + "shrd eax, edx, 11",\ + parm nomemory [eax][edx][ebx][ecx][esi][edi]\ + modify exact [eax ebx ecx edx]\ + +long tmulscale12(long i1, long i2, long i3, long i4, long i5, long i6); +#pragma aux tmulscale12 =\ + "imul edx",\ + "xchg eax, ebx",\ + "xchg edx, ecx",\ + "imul edx",\ + "add ebx, eax",\ + "adc ecx, edx",\ + "mov eax, esi",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, ecx",\ + "shrd eax, edx, 12",\ + parm nomemory [eax][edx][ebx][ecx][esi][edi]\ + modify exact [eax ebx ecx edx]\ + +long tmulscale13(long i1, long i2, long i3, long i4, long i5, long i6); +#pragma aux tmulscale13 =\ + "imul edx",\ + "xchg eax, ebx",\ + "xchg edx, ecx",\ + "imul edx",\ + "add ebx, eax",\ + "adc ecx, edx",\ + "mov eax, esi",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, ecx",\ + "shrd eax, edx, 13",\ + parm nomemory [eax][edx][ebx][ecx][esi][edi]\ + modify exact [eax ebx ecx edx]\ + +long tmulscale14(long i1, long i2, long i3, long i4, long i5, long i6); +#pragma aux tmulscale14 =\ + "imul edx",\ + "xchg eax, ebx",\ + "xchg edx, ecx",\ + "imul edx",\ + "add ebx, eax",\ + "adc ecx, edx",\ + "mov eax, esi",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, ecx",\ + "shrd eax, edx, 14",\ + parm nomemory [eax][edx][ebx][ecx][esi][edi]\ + modify exact [eax ebx ecx edx]\ + +long tmulscale15(long i1, long i2, long i3, long i4, long i5, long i6); +#pragma aux tmulscale15 =\ + "imul edx",\ + "xchg eax, ebx",\ + "xchg edx, ecx",\ + "imul edx",\ + "add ebx, eax",\ + "adc ecx, edx",\ + "mov eax, esi",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, ecx",\ + "shrd eax, edx, 15",\ + parm nomemory [eax][edx][ebx][ecx][esi][edi]\ + modify exact [eax ebx ecx edx]\ + +long tmulscale16(long i1, long i2, long i3, long i4, long i5, long i6); +#pragma aux tmulscale16 =\ + "imul edx",\ + "xchg eax, ebx",\ + "xchg edx, ecx",\ + "imul edx",\ + "add ebx, eax",\ + "adc ecx, edx",\ + "mov eax, esi",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, ecx",\ + "shrd eax, edx, 16",\ + parm nomemory [eax][edx][ebx][ecx][esi][edi]\ + modify exact [eax ebx ecx edx]\ + +long tmulscale17(long i1, long i2, long i3, long i4, long i5, long i6); +#pragma aux tmulscale17 =\ + "imul edx",\ + "xchg eax, ebx",\ + "xchg edx, ecx",\ + "imul edx",\ + "add ebx, eax",\ + "adc ecx, edx",\ + "mov eax, esi",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, ecx",\ + "shrd eax, edx, 17",\ + parm nomemory [eax][edx][ebx][ecx][esi][edi]\ + modify exact [eax ebx ecx edx]\ + +long tmulscale18(long i1, long i2, long i3, long i4, long i5, long i6); +#pragma aux tmulscale18 =\ + "imul edx",\ + "xchg eax, ebx",\ + "xchg edx, ecx",\ + "imul edx",\ + "add ebx, eax",\ + "adc ecx, edx",\ + "mov eax, esi",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, ecx",\ + "shrd eax, edx, 18",\ + parm nomemory [eax][edx][ebx][ecx][esi][edi]\ + modify exact [eax ebx ecx edx]\ + +long tmulscale19(long i1, long i2, long i3, long i4, long i5, long i6); +#pragma aux tmulscale19 =\ + "imul edx",\ + "xchg eax, ebx",\ + "xchg edx, ecx",\ + "imul edx",\ + "add ebx, eax",\ + "adc ecx, edx",\ + "mov eax, esi",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, ecx",\ + "shrd eax, edx, 19",\ + parm nomemory [eax][edx][ebx][ecx][esi][edi]\ + modify exact [eax ebx ecx edx]\ + +long tmulscale20(long i1, long i2, long i3, long i4, long i5, long i6); +#pragma aux tmulscale20 =\ + "imul edx",\ + "xchg eax, ebx",\ + "xchg edx, ecx",\ + "imul edx",\ + "add ebx, eax",\ + "adc ecx, edx",\ + "mov eax, esi",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, ecx",\ + "shrd eax, edx, 20",\ + parm nomemory [eax][edx][ebx][ecx][esi][edi]\ + modify exact [eax ebx ecx edx]\ + +long tmulscale21(long i1, long i2, long i3, long i4, long i5, long i6); +#pragma aux tmulscale21 =\ + "imul edx",\ + "xchg eax, ebx",\ + "xchg edx, ecx",\ + "imul edx",\ + "add ebx, eax",\ + "adc ecx, edx",\ + "mov eax, esi",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, ecx",\ + "shrd eax, edx, 21",\ + parm nomemory [eax][edx][ebx][ecx][esi][edi]\ + modify exact [eax ebx ecx edx]\ + +long tmulscale22(long i1, long i2, long i3, long i4, long i5, long i6); +#pragma aux tmulscale22 =\ + "imul edx",\ + "xchg eax, ebx",\ + "xchg edx, ecx",\ + "imul edx",\ + "add ebx, eax",\ + "adc ecx, edx",\ + "mov eax, esi",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, ecx",\ + "shrd eax, edx, 22",\ + parm nomemory [eax][edx][ebx][ecx][esi][edi]\ + modify exact [eax ebx ecx edx]\ + +long tmulscale23(long i1, long i2, long i3, long i4, long i5, long i6); +#pragma aux tmulscale23 =\ + "imul edx",\ + "xchg eax, ebx",\ + "xchg edx, ecx",\ + "imul edx",\ + "add ebx, eax",\ + "adc ecx, edx",\ + "mov eax, esi",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, ecx",\ + "shrd eax, edx, 23",\ + parm nomemory [eax][edx][ebx][ecx][esi][edi]\ + modify exact [eax ebx ecx edx]\ + +long tmulscale24(long i1, long i2, long i3, long i4, long i5, long i6); +#pragma aux tmulscale24 =\ + "imul edx",\ + "xchg eax, ebx",\ + "xchg edx, ecx",\ + "imul edx",\ + "add ebx, eax",\ + "adc ecx, edx",\ + "mov eax, esi",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, ecx",\ + "shrd eax, edx, 24",\ + parm nomemory [eax][edx][ebx][ecx][esi][edi]\ + modify exact [eax ebx ecx edx]\ + +long tmulscale25(long i1, long i2, long i3, long i4, long i5, long i6); +#pragma aux tmulscale25 =\ + "imul edx",\ + "xchg eax, ebx",\ + "xchg edx, ecx",\ + "imul edx",\ + "add ebx, eax",\ + "adc ecx, edx",\ + "mov eax, esi",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, ecx",\ + "shrd eax, edx, 25",\ + parm nomemory [eax][edx][ebx][ecx][esi][edi]\ + modify exact [eax ebx ecx edx]\ + +long tmulscale26(long i1, long i2, long i3, long i4, long i5, long i6); +#pragma aux tmulscale26 =\ + "imul edx",\ + "xchg eax, ebx",\ + "xchg edx, ecx",\ + "imul edx",\ + "add ebx, eax",\ + "adc ecx, edx",\ + "mov eax, esi",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, ecx",\ + "shrd eax, edx, 26",\ + parm nomemory [eax][edx][ebx][ecx][esi][edi]\ + modify exact [eax ebx ecx edx]\ + +long tmulscale27(long i1, long i2, long i3, long i4, long i5, long i6); +#pragma aux tmulscale27 =\ + "imul edx",\ + "xchg eax, ebx",\ + "xchg edx, ecx",\ + "imul edx",\ + "add ebx, eax",\ + "adc ecx, edx",\ + "mov eax, esi",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, ecx",\ + "shrd eax, edx, 27",\ + parm nomemory [eax][edx][ebx][ecx][esi][edi]\ + modify exact [eax ebx ecx edx]\ + +long tmulscale28(long i1, long i2, long i3, long i4, long i5, long i6); +#pragma aux tmulscale28 =\ + "imul edx",\ + "xchg eax, ebx",\ + "xchg edx, ecx",\ + "imul edx",\ + "add ebx, eax",\ + "adc ecx, edx",\ + "mov eax, esi",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, ecx",\ + "shrd eax, edx, 28",\ + parm nomemory [eax][edx][ebx][ecx][esi][edi]\ + modify exact [eax ebx ecx edx]\ + +long tmulscale29(long i1, long i2, long i3, long i4, long i5, long i6); +#pragma aux tmulscale29 =\ + "imul edx",\ + "xchg eax, ebx",\ + "xchg edx, ecx",\ + "imul edx",\ + "add ebx, eax",\ + "adc ecx, edx",\ + "mov eax, esi",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, ecx",\ + "shrd eax, edx, 29",\ + parm nomemory [eax][edx][ebx][ecx][esi][edi]\ + modify exact [eax ebx ecx edx]\ + +long tmulscale30(long i1, long i2, long i3, long i4, long i5, long i6); +#pragma aux tmulscale30 =\ + "imul edx",\ + "xchg eax, ebx",\ + "xchg edx, ecx",\ + "imul edx",\ + "add ebx, eax",\ + "adc ecx, edx",\ + "mov eax, esi",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, ecx",\ + "shrd eax, edx, 30",\ + parm nomemory [eax][edx][ebx][ecx][esi][edi]\ + modify exact [eax ebx ecx edx]\ + +long tmulscale31(long i1, long i2, long i3, long i4, long i5, long i6); +#pragma aux tmulscale31 =\ + "imul edx",\ + "xchg eax, ebx",\ + "xchg edx, ecx",\ + "imul edx",\ + "add ebx, eax",\ + "adc ecx, edx",\ + "mov eax, esi",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, ecx",\ + "shrd eax, edx, 31",\ + parm nomemory [eax][edx][ebx][ecx][esi][edi]\ + modify exact [eax ebx ecx edx]\ + +long tmulscale32(long i1, long i2, long i3, long i4, long i5, long i6); +#pragma aux tmulscale32 =\ + "imul edx",\ + "xchg eax, ebx",\ + "xchg edx, ecx",\ + "imul edx",\ + "add ebx, eax",\ + "adc ecx, edx",\ + "mov eax, esi",\ + "imul edi",\ + "add eax, ebx",\ + "adc edx, ecx",\ + parm nomemory [eax][edx][ebx][ecx][esi][edi]\ + modify exact [eax ebx ecx edx]\ + value [edx]\ + +long boundmulscale(long i1, long i2, long i3); +#pragma aux boundmulscale =\ + "imul ebx",\ + "mov ebx, edx",\ + "shrd eax, edx, cl",\ + "sar edx, cl",\ + "xor edx, eax",\ + "js checkit",\ + "xor edx, eax",\ + "jz skipboundit",\ + "cmp edx, 0xffffffff",\ + "je skipboundit",\ + "checkit:",\ + "mov eax, ebx",\ + "sar eax, 31",\ + "xor eax, 0x7fffffff",\ + "skipboundit:",\ + parm nomemory [eax][ebx][ecx]\ + modify exact [eax ebx edx]\ + +long divscale(long i1, long i2, long i3); +#pragma aux divscale =\ + "mov edx, eax",\ + "shl eax, cl",\ + "neg cl",\ + "sar edx, cl",\ + "idiv ebx",\ + parm nomemory [eax][ebx][ecx]\ + modify exact [eax ecx edx]\ + +long divscale1(long i1, long i2); +#pragma aux divscale1 =\ + "add eax, eax",\ + "sbb edx, edx",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale2(long i1, long i2); +#pragma aux divscale2 =\ + "mov edx, eax",\ + "sar edx, 30",\ + "lea eax, [eax*4]",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale3(long i1, long i2); +#pragma aux divscale3 =\ + "mov edx, eax",\ + "sar edx, 29",\ + "lea eax, [eax*8]",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale4(long i1, long i2); +#pragma aux divscale4 =\ + "mov edx, eax",\ + "sar edx, 28",\ + "shl eax, 4",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale5(long i1, long i2); +#pragma aux divscale5 =\ + "mov edx, eax",\ + "sar edx, 27",\ + "shl eax, 5",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale6(long i1, long i2); +#pragma aux divscale6 =\ + "mov edx, eax",\ + "sar edx, 26",\ + "shl eax, 6",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale7(long i1, long i2); +#pragma aux divscale7 =\ + "mov edx, eax",\ + "sar edx, 25",\ + "shl eax, 7",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale8(long i1, long i2); +#pragma aux divscale8 =\ + "mov edx, eax",\ + "sar edx, 24",\ + "shl eax, 8",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale9(long i1, long i2); +#pragma aux divscale9 =\ + "mov edx, eax",\ + "sar edx, 23",\ + "shl eax, 9",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale10(long i1, long i2); +#pragma aux divscale10 =\ + "mov edx, eax",\ + "sar edx, 22",\ + "shl eax, 10",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale11(long i1, long i2); +#pragma aux divscale11 =\ + "mov edx, eax",\ + "sar edx, 21",\ + "shl eax, 11",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale12(long i1, long i2); +#pragma aux divscale12 =\ + "mov edx, eax",\ + "sar edx, 20",\ + "shl eax, 12",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale13(long i1, long i2); +#pragma aux divscale13 =\ + "mov edx, eax",\ + "sar edx, 19",\ + "shl eax, 13",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale14(long i1, long i2); +#pragma aux divscale14 =\ + "mov edx, eax",\ + "sar edx, 18",\ + "shl eax, 14",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale15(long i1, long i2); +#pragma aux divscale15 =\ + "mov edx, eax",\ + "sar edx, 17",\ + "shl eax, 15",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale16(long i1, long i2); +#pragma aux divscale16 =\ + "mov edx, eax",\ + "sar edx, 16",\ + "shl eax, 16",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale17(long i1, long i2); +#pragma aux divscale17 =\ + "mov edx, eax",\ + "sar edx, 15",\ + "shl eax, 17",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale18(long i1, long i2); +#pragma aux divscale18 =\ + "mov edx, eax",\ + "sar edx, 14",\ + "shl eax, 18",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale19(long i1, long i2); +#pragma aux divscale19 =\ + "mov edx, eax",\ + "sar edx, 13",\ + "shl eax, 19",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale20(long i1, long i2); +#pragma aux divscale20 =\ + "mov edx, eax",\ + "sar edx, 12",\ + "shl eax, 20",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale21(long i1, long i2); +#pragma aux divscale21 =\ + "mov edx, eax",\ + "sar edx, 11",\ + "shl eax, 21",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale22(long i1, long i2); +#pragma aux divscale22 =\ + "mov edx, eax",\ + "sar edx, 10",\ + "shl eax, 22",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale23(long i1, long i2); +#pragma aux divscale23 =\ + "mov edx, eax",\ + "sar edx, 9",\ + "shl eax, 23",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale24(long i1, long i2); +#pragma aux divscale24 =\ + "mov edx, eax",\ + "sar edx, 8",\ + "shl eax, 24",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale25(long i1, long i2); +#pragma aux divscale25 =\ + "mov edx, eax",\ + "sar edx, 7",\ + "shl eax, 25",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale26(long i1, long i2); +#pragma aux divscale26 =\ + "mov edx, eax",\ + "sar edx, 6",\ + "shl eax, 26",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale27(long i1, long i2); +#pragma aux divscale27 =\ + "mov edx, eax",\ + "sar edx, 5",\ + "shl eax, 27",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale28(long i1, long i2); +#pragma aux divscale28 =\ + "mov edx, eax",\ + "sar edx, 4",\ + "shl eax, 28",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale29(long i1, long i2); +#pragma aux divscale29 =\ + "mov edx, eax",\ + "sar edx, 3",\ + "shl eax, 29",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale30(long i1, long i2); +#pragma aux divscale30 =\ + "mov edx, eax",\ + "sar edx, 2",\ + "shl eax, 30",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale31(long i1, long i2); +#pragma aux divscale31 =\ + "mov edx, eax",\ + "sar edx, 1",\ + "shl eax, 31",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale32(long i1, long i2); +#pragma aux divscale32 =\ + "xor eax, eax",\ + "idiv ebx",\ + parm nomemory [edx][ebx]\ + modify exact [eax edx]\ + +/* !!! move these into ves.h? --ryan. */ +#ifdef PLATFORM_DOS + +void int5(void); +#pragma aux int5 =\ + "int 0x5",\ + +int setupmouse(void); +#pragma aux setupmouse =\ + "mov ax, 0",\ + "int 33h",\ + "and eax, 0x0000ffff",\ + modify exact [eax]\ + +void readmousexy(short *x, short *y); +#pragma aux readmousexy =\ + "mov ax, 11d",\ + "int 33h",\ + "mov [esi], cx",\ + "mov [edi], dx",\ + parm [esi][edi]\ + modify exact [eax ebx ecx edx]\ + +void readmousebstatus(short *buttons); +#pragma aux readmousebstatus =\ + "mov ax, 5d",\ + "int 33h",\ + "mov [esi], ax",\ + parm [esi]\ + modify exact [eax ebx ecx edx]\ + +unsigned char readpixel(long offset); +#pragma aux readpixel =\ + "mov al, byte ptr [edi]",\ + parm nomemory [edi]\ + modify exact [eax]\ + +void drawpixel(long offset, unsigned char p); +#pragma aux drawpixel =\ + "mov byte ptr [edi], al",\ + parm [edi][eax]\ + modify exact \ + +void drawpixels(long offset, unsigned short p); +#pragma aux drawpixels =\ + "mov word ptr [edi], ax",\ + parm [edi][eax]\ + modify exact \ + +void drawpixelses(long offset, unsigned long p); +#pragma aux drawpixelses =\ + "mov dword ptr [edi], eax",\ + parm [edi][eax]\ + modify exact \ + +#endif + + +void clearbuf(void *buf, long i2, long i3); +#pragma aux clearbuf =\ + "rep stosd",\ + parm [edi][ecx][eax]\ + modify exact [edi ecx]\ + +void clearbufbyte(void *buf, long i2, long i3); +#pragma aux clearbufbyte =\ + "cmp ecx, 4",\ + "jae longcopy",\ + "test cl, 1",\ + "jz preskip",\ + "stosb",\ + "preskip: shr ecx, 1",\ + "rep stosw",\ + "jmp endit",\ + "longcopy: test edi, 1",\ + "jz skip1",\ + "stosb",\ + "dec ecx",\ + "skip1: test edi, 2",\ + "jz skip2",\ + "stosw",\ + "sub ecx, 2",\ + "skip2: mov ebx, ecx",\ + "shr ecx, 2",\ + "rep stosd",\ + "test bl, 2",\ + "jz skip3",\ + "stosw",\ + "skip3: test bl, 1",\ + "jz endit",\ + "stosb",\ + "endit:",\ + parm [edi][ecx][eax]\ + modify [ebx]\ + +void copybuf(void *src, void *dst, long len); +#pragma aux copybuf =\ + "rep movsd",\ + parm [esi][edi][ecx]\ + modify exact [ecx esi edi]\ + +void copybufbyte(void *src, void *dst, long len); +#pragma aux copybufbyte =\ + "cmp ecx, 4",\ + "jae longcopy",\ + "test cl, 1",\ + "jz preskip",\ + "movsb",\ + "preskip: shr ecx, 1",\ + "rep movsw",\ + "jmp endit",\ + "longcopy: test edi, 1",\ + "jz skip1",\ + "movsb",\ + "dec ecx",\ + "skip1: test edi, 2",\ + "jz skip2",\ + "movsw",\ + "sub ecx, 2",\ + "skip2: mov ebx, ecx",\ + "shr ecx, 2",\ + "rep movsd",\ + "test bl, 2",\ + "jz skip3",\ + "movsw",\ + "skip3: test bl, 1",\ + "jz endit",\ + "movsb",\ + "endit:",\ + parm [esi][edi][ecx]\ + modify [ebx]\ + +void copybufreverse(void *src, void *dst, long len); +#pragma aux copybufreverse =\ + "shr ecx, 1",\ + "jnc skipit1",\ + "mov al, byte ptr [esi]",\ + "dec esi",\ + "mov byte ptr [edi], al",\ + "inc edi",\ + "skipit1: shr ecx, 1",\ + "jnc skipit2",\ + "mov ax, word ptr [esi-1]",\ + "sub esi, 2",\ + "ror ax, 8",\ + "mov word ptr [edi], ax",\ + "add edi, 2",\ + "skipit2: test ecx, ecx",\ + "jz endloop",\ + "begloop: mov eax, dword ptr [esi-3]",\ + "sub esi, 4",\ + "bswap eax",\ + "mov dword ptr [edi], eax",\ + "add edi, 4",\ + "dec ecx",\ + "jnz begloop",\ + "endloop:",\ + parm [esi][edi][ecx]\ + +void qinterpolatedown16(long *i1, long i2, long i3, long i4); +#pragma aux qinterpolatedown16 =\ + "mov ebx, ecx",\ + "shr ecx, 1",\ + "jz skipbegcalc",\ + "begqcalc: lea edi, [edx+esi]",\ + "sar edx, 16",\ + "mov dword ptr [eax], edx",\ + "lea edx, [edi+esi]",\ + "sar edi, 16",\ + "mov dword ptr [eax+4], edi",\ + "add eax, 8",\ + "dec ecx",\ + "jnz begqcalc",\ + "test ebx, 1",\ + "jz skipbegqcalc2",\ + "skipbegcalc: sar edx, 16",\ + "mov dword ptr [eax], edx",\ + "skipbegqcalc2:",\ + parm [eax][ecx][edx][esi]\ + modify exact [eax ebx ecx edx edi]\ + +void qinterpolatedown16short(long *i1, long i2, long i3, long i4); +#pragma aux qinterpolatedown16short =\ + "test ecx, ecx",\ + "jz endit",\ + "test al, 2",\ + "jz skipalignit",\ + "mov ebx, edx",\ + "sar ebx, 16",\ + "mov word ptr [eax], bx",\ + "add edx, esi",\ + "add eax, 2",\ + "dec ecx",\ + "jz endit",\ + "skipalignit: sub ecx, 2",\ + "jc finishit",\ + "begqcalc: mov ebx, edx",\ + "add edx, esi",\ + "sar ebx, 16",\ + "mov edi, edx",\ + "and edi, 0ffff0000h",\ + "add edx, esi",\ + "add ebx, edi",\ + "mov dword ptr [eax], ebx",\ + "add eax, 4",\ + "sub ecx, 2",\ + "jnc begqcalc",\ + "test cl, 1",\ + "jz endit",\ + "finishit: mov ebx, edx",\ + "sar ebx, 16",\ + "mov word ptr [eax], bx",\ + "endit:",\ + parm [eax][ecx][edx][esi]\ + modify exact [eax ebx ecx edx edi]\ + + +#if (defined PLATFORM_DOS) /* !!! move this to dos_driver.c? */ + +void setcolor16(int i1); +#pragma aux setcolor16 =\ + "mov dx, 0x3ce",\ + "shl ax, 8",\ + "out dx, ax",\ + parm [eax]\ + modify exact [eax edx]\ + +#endif /* defined PLATFORM_DOS */ + + +void vlin16first(long i1, long i2); +#pragma aux vlin16first =\ + "mov al, byte ptr [edi]",\ + "mov eax, ecx",\ + "shr ecx, 2",\ + "begvlin16firsta: mov byte ptr [edi], al",\ + "mov byte ptr [edi+80], al",\ + "mov byte ptr [edi+160], al",\ + "mov byte ptr [edi+240], al",\ + "add edi, 320",\ + "dec ecx",\ + "jnz begvlin16firsta",\ + "mov ecx, eax",\ + "and ecx, 3",\ + "jz skipfirst",\ + "begvlin16firstb: mov byte ptr [edi], al",\ + "add edi, 80",\ + "dec ecx",\ + "jnz begvlin16firstb",\ + "skipfirst:",\ + parm [edi][ecx]\ + modify exact [eax ecx edi]\ + +void vlin16(long i1, long i2); +#pragma aux vlin16 =\ + "mov esi, edi",\ + "begvlin16: movsb",\ + "add edi, 79",\ + "add esi, 79",\ + "dec ecx",\ + "jnz begvlin16",\ + parm [edi][ecx]\ + modify exact [ecx esi edi]\ + +#if (defined PLATFORM_DOS) /* !!! move this to dos_driver.c? */ + +void drawpixel16(long offset); +#pragma aux drawpixel16 =\ + "mov ecx, edi",\ + "mov eax, 0x00008008",\ + "mov dx, 0x3ce",\ + "ror ah, cl",\ + "shr edi, 3",\ + "out dx, ax",\ + "mov cl, byte ptr [edi+0xa0000]",\ + "mov byte ptr [edi+0xa0000], al",\ + parm [edi]\ + modify exact [eax ecx edx edi]\ + +void fillscreen16(long i1, long i2, long i3); +#pragma aux fillscreen16 =\ + "mov dx, 0x3ce",\ + "shl ax, 8",\ + "out dx, ax",\ + "mov ax, 0xff08",\ + "out dx, ax",\ + "shr ecx, 5",\ + "add edi, 0xa0000",\ + "rep stosd",\ + parm [edi][eax][ecx]\ + modify exact [eax ecx edx edi]\ + +void koutp(long i1, long i); +#pragma aux koutp =\ + "out dx, al",\ + parm [edx][eax]\ + modify exact \ + +void koutpw(long i1, long i); +#pragma aux koutpw =\ + "out dx, ax",\ + parm [edx][eax]\ + modify exact \ + +int kinp(long i); +#pragma aux kinp =\ + "in al, dx",\ + parm nomemory [edx]\ + modify exact [eax]\ + +#endif /* defined PLATFORM_DOS */ + + +long mul3(long i1); +#pragma aux mul3 =\ + "lea eax, [eax+eax*2]",\ + parm nomemory [eax]\ + +long mul5(long i1); +#pragma aux mul5 =\ + "lea eax, [eax+eax*4]",\ + parm nomemory [eax]\ + +long mul9(long i1); +#pragma aux mul9 =\ + "lea eax, [eax+eax*8]",\ + parm nomemory [eax]\ + + /* returns eax/ebx, dmval = eax%edx; */ +long divmod(long i1, long i2); +#pragma aux divmod =\ + "xor edx, edx",\ + "div ebx",\ + "mov dmval, edx",\ + parm [eax][ebx]\ + modify exact [eax edx]\ + value [eax] + + /* returns eax%ebx, dmval = eax/edx; */ +long moddiv(long i1, long i2); +#pragma aux moddiv =\ + "xor edx, edx",\ + "div ebx",\ + "mov dmval, eax",\ + parm [eax][ebx]\ + modify exact [eax edx]\ + value [edx] + +long klabs(long i1); +#pragma aux klabs =\ + "test eax, eax",\ + "jns skipnegate",\ + "neg eax",\ + "skipnegate:",\ + parm nomemory [eax]\ + +long ksgn(long i1); +#pragma aux ksgn =\ + "add ebx, ebx",\ + "sbb eax, eax",\ + "cmp eax, ebx",\ + "adc al, 0",\ + parm nomemory [ebx]\ + modify exact [eax ebx]\ + + /* eax = (unsigned min)umin(eax,ebx) */ +long umin(long i1, long i2); +#pragma aux umin =\ + "sub eax, ebx",\ + "sbb ecx, ecx",\ + "and eax, ecx",\ + "add eax, ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax ecx]\ + + /* eax = (unsigned max)umax(eax,ebx) */ +long umax(long i1, long i2); +#pragma aux umax =\ + "sub eax, ebx",\ + "sbb ecx, ecx",\ + "xor ecx, 0xffffffff",\ + "and eax, ecx",\ + "add eax, ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax ecx]\ + +long kmin(long i1, long i2); +#pragma aux kmin =\ + "cmp eax, ebx",\ + "jl skipit",\ + "mov eax, ebx",\ + "skipit:",\ + parm nomemory [eax][ebx]\ + modify exact [eax]\ + +long kmax(long i1, long i2); +#pragma aux kmax =\ + "cmp eax, ebx",\ + "jg skipit",\ + "mov eax, ebx",\ + "skipit:",\ + parm nomemory [eax][ebx]\ + modify exact [eax]\ + +#if (defined PLATFORM_DOS) /* !!! move to dos_driver.c? */ +void limitrate(void); +#pragma aux limitrate =\ + "mov dx, 0x3da",\ + "wait1: in al, dx",\ + "test al, 8",\ + "jnz wait1",\ + "wait2: in al, dx",\ + "test al, 8",\ + "jz wait2",\ + modify exact [eax edx]\ + +long readtimer(void); +#pragma aux readtimer =\ + "mov al, 0xd2",\ + "out 0x43, al",\ + "in al, 0x40",\ + "shl eax, 24",\ + "in al, 0x40",\ + "rol eax, 8",\ + modify [eax]\ + +void redblueblit(void *i1, void *i2, long i3); +#pragma aux redblueblit = \ + "xor ecx, ecx",\ + "begblit: mov eax, dword ptr [edx+ecx]",\ + "shl eax, 4",\ + "add eax, dword ptr [ebx+ecx]",\ + "mov dword ptr [ecx+0xa0000], eax",\ + "add ecx, 4",\ + "cmp ecx, esi",\ + "jb begblit",\ + parm [ebx][edx][esi]\ + modify exact [eax ecx]\ + +#pragma aux chainblit =\ + "shr ecx, 1",\ + "jnc prebeg",\ + "mov al, byte ptr [esi+8]",\ + "mov ah, byte ptr [esi+12]",\ + "shl eax, 16",\ + "mov al, byte ptr [esi]",\ + "mov ah, byte ptr [esi+4]",\ + "mov dword ptr [edi], eax",\ + "add esi, 16",\ + "add edi, 4",\ + "test ecx, ecx",\ + "prebeg: jz endit",\ + "beg: mov al, byte ptr [esi+8]",\ + "mov bl, byte ptr [esi+24]",\ + "mov ah, byte ptr [esi+12]",\ + "mov bh, byte ptr [esi+28]",\ + "shl eax, 16",\ + "add edi, 8",\ + "shl ebx, 16",\ + "mov al, byte ptr [esi]",\ + "mov bl, byte ptr [esi+16]",\ + "mov ah, byte ptr [esi+4]",\ + "mov bh, byte ptr [esi+20]",\ + "add esi, 32",\ + "mov dword ptr [edi-8], eax",\ + "dec ecx",\ + "mov dword ptr [edi-4], ebx",\ + "jnz beg",\ + "endit:",\ + parm [esi][edi][ecx]\ + modify exact [eax ebx ecx esi edi]\ + +#endif + + +void swapchar(char *i1, char *i2); +#pragma aux swapchar =\ + "mov cl, [eax]",\ + "mov ch, [ebx]",\ + "mov [ebx], cl",\ + "mov [eax], ch",\ + parm [eax][ebx]\ + modify exact [ecx]\ + +void swapshort(short *i1, short *i2); +#pragma aux swapshort =\ + "mov cx, [eax]",\ + "mov dx, [ebx]",\ + "mov [ebx], cx",\ + "mov [eax], dx",\ + parm [eax][ebx]\ + modify exact [ecx edx]\ + +void swaplong(long *i1, long *i2); +#pragma aux swaplong =\ + "mov ecx, [eax]",\ + "mov edx, [ebx]",\ + "mov [ebx], ecx",\ + "mov [eax], edx",\ + parm [eax][ebx]\ + modify exact [ecx edx]\ + +#pragma aux swapbuf4 =\ + "begswap:",\ + "mov esi, [eax]",\ + "mov edi, [ebx]",\ + "mov [ebx], esi",\ + "mov [eax], edi",\ + "add eax, 4",\ + "add ebx, 4",\ + "dec ecx",\ + "jnz short begswap",\ + parm [eax][ebx][ecx]\ + modify exact [eax ebx ecx esi edi]\ + +#pragma aux swap64bit =\ + "mov ecx, [eax]",\ + "mov edx, [ebx]",\ + "mov [ebx], ecx",\ + "mov ecx, [eax+4]",\ + "mov [eax], edx",\ + "mov edx, [ebx+4]",\ + "mov [ebx+4], ecx",\ + "mov [eax+4], edx",\ + parm [eax][ebx]\ + modify exact [ecx edx]\ + + + /* + * swapchar2(ptr1,ptr2,xsiz); is the same as: + * swapchar(ptr1,ptr2); swapchar(ptr1+1,ptr2+xsiz); + */ +void swapchar2(char *ptr1, char *ptr2, long xsiz); +#pragma aux swapchar2 =\ + "add esi, ebx",\ + "mov cx, [eax]",\ + "mov dl, [ebx]",\ + "mov [ebx], cl",\ + "mov dh, [esi]",\ + "mov [esi], ch",\ + "mov [eax], dx",\ + parm [eax][ebx][esi]\ + modify exact [ecx edx esi]\ + +static long timeroffs1mhz; + /* accutimeroffs = -8-(t1-t0); */ +#pragma aux inittimer1mhz =\ + "xor ebx, ebx",\ + "xor ecx, ecx",\ + "in al, 0x61",\ + "or al, 1",\ + "out 0x61, al",\ + "mov al, 0x34",\ + "out 0x43, al",\ + "xor al, al",\ + "out 0x40, al",\ + "mov al, 0xb4",\ + "out 0x43, al",\ + "mov al, 240",\ + "out 0x42, al",\ + "xor al, al",\ + "cli",\ + "out 0x40, al",\ + "dec al",\ + "out 0x42, al",\ + "mov al, 0x04",\ + "out 0x43, al",\ + "in al, 0x40",\ + "mov bl, al",\ + "in al, 0x40",\ + "mov bh, al",\ + "mov al, 0x84",\ + "out 0x43, al",\ + "in al, 0x42",\ + "mov cl, al",\ + "in al, 0x42",\ + "sti",\ + "mov ch, al",\ + "sub ebx, ecx",\ + "sub ebx, 8",\ + "mov timeroffs1mhz, ebx",\ + modify exact [eax ebx ecx]\ + +#pragma aux uninittimer1mhz =\ + "in al, 0x61",\ + "and al, 252",\ + "out 0x61, al",\ + modify exact [eax]\ + + /* t = ((ecx-ebx+timeroffs1mhz)&0xfff0)*4095 + ecx; */ +#pragma aux gettime1mhz =\ + "mov ebx, timeroffs1mhz",\ + "xor ecx, ecx",\ + "mov al, 0x04",\ + "cli",\ + "out 0x43, al",\ + "in al, 0x40",\ + "sub bl, al",\ + "in al, 0x40",\ + "sbb bh, al",\ + "mov al, 0x84",\ + "out 0x43, al",\ + "in al, 0x42",\ + "mov cl, al",\ + "in al, 0x42",\ + "sti",\ + "mov ch, al",\ + "add ebx, ecx",\ + "and ebx, 0x0000fff0",\ + "sub ecx, ebx",\ + "shl ebx, 12",\ + "add ebx, ecx",\ + modify exact [eax ebx ecx]\ + value [ebx]\ + + /* eax = eax-ebx; if (eax < 0) eax += (1<<28) - (1<<16); */ +#pragma aux deltatime1mhz =\ + "sub eax, ebx",\ + "jnc skipit",\ + "add eax, 0x0fff0000",\ + "skipit:",\ + parm [ebx][eax] + +#pragma aux boundmulscale =\ + "imul ebx",\ + "mov ebx, edx",\ + "shrd eax, edx, cl",\ + "sar edx, cl",\ + "xor edx, eax",\ + "js checkit",\ + "xor edx, eax",\ + "jz skipboundit",\ + "cmp edx, 0xffffffff",\ + "je skipboundit",\ + "checkit:",\ + "mov eax, ebx",\ + "sar eax, 31",\ + "xor eax, 0x7fffffff",\ + "skipboundit:",\ + parm nomemory [eax][ebx][ecx]\ + modify exact [eax ebx edx]\ + + +/* FIXME: Why are all these divscale functions in here a second time? */ +long divscale(long i1, long i2, long i3); +#pragma aux divscale =\ + "mov edx, eax",\ + "shl eax, cl",\ + "neg cl",\ + "sar edx, cl",\ + "idiv ebx",\ + parm nomemory [eax][ebx][ecx]\ + modify exact [eax ecx edx] + +long divscale1(long i1, long i2); +#pragma aux divscale1 =\ + "add eax, eax",\ + "sbb edx, edx",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx] + +long divscale2(long i1, long i2); +#pragma aux divscale2 =\ + "mov edx, eax",\ + "sar edx, 30",\ + "lea eax, [eax*4]",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale3(long i1, long i2); +#pragma aux divscale3 =\ + "mov edx, eax",\ + "sar edx, 29",\ + "lea eax, [eax*8]",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale4(long i1, long i2); +#pragma aux divscale4 =\ + "mov edx, eax",\ + "sar edx, 28",\ + "shl eax, 4",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale5(long i1, long i2); +#pragma aux divscale5 =\ + "mov edx, eax",\ + "sar edx, 27",\ + "shl eax, 5",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale6(long i1, long i2); +#pragma aux divscale6 =\ + "mov edx, eax",\ + "sar edx, 26",\ + "shl eax, 6",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale7(long i1, long i2); +#pragma aux divscale7 =\ + "mov edx, eax",\ + "sar edx, 25",\ + "shl eax, 7",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale8(long i1, long i2); +#pragma aux divscale8 =\ + "mov edx, eax",\ + "sar edx, 24",\ + "shl eax, 8",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale9(long i1, long i2); +#pragma aux divscale9 =\ + "mov edx, eax",\ + "sar edx, 23",\ + "shl eax, 9",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale10(long i1, long i2); +#pragma aux divscale10 =\ + "mov edx, eax",\ + "sar edx, 22",\ + "shl eax, 10",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale11(long i1, long i2); +#pragma aux divscale11 =\ + "mov edx, eax",\ + "sar edx, 21",\ + "shl eax, 11",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale12(long i1, long i2); +#pragma aux divscale12 =\ + "mov edx, eax",\ + "sar edx, 20",\ + "shl eax, 12",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale13(long i1, long i2); +#pragma aux divscale13 =\ + "mov edx, eax",\ + "sar edx, 19",\ + "shl eax, 13",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale14(long i1, long i2); +#pragma aux divscale14 =\ + "mov edx, eax",\ + "sar edx, 18",\ + "shl eax, 14",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale15(long i1, long i2); +#pragma aux divscale15 =\ + "mov edx, eax",\ + "sar edx, 17",\ + "shl eax, 15",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale16(long i1, long i2); +#pragma aux divscale16 =\ + "mov edx, eax",\ + "sar edx, 16",\ + "shl eax, 16",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale17(long i1, long i2); +#pragma aux divscale17 =\ + "mov edx, eax",\ + "sar edx, 15",\ + "shl eax, 17",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale18(long i1, long i2); +#pragma aux divscale18 =\ + "mov edx, eax",\ + "sar edx, 14",\ + "shl eax, 18",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale19(long i1, long i2); +#pragma aux divscale19 =\ + "mov edx, eax",\ + "sar edx, 13",\ + "shl eax, 19",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale20(long i1, long i2); +#pragma aux divscale20 =\ + "mov edx, eax",\ + "sar edx, 12",\ + "shl eax, 20",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale21(long i1, long i2); +#pragma aux divscale21 =\ + "mov edx, eax",\ + "sar edx, 11",\ + "shl eax, 21",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale22(long i1, long i2); +#pragma aux divscale22 =\ + "mov edx, eax",\ + "sar edx, 10",\ + "shl eax, 22",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale23(long i1, long i2); +#pragma aux divscale23 =\ + "mov edx, eax",\ + "sar edx, 9",\ + "shl eax, 23",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale24(long i1, long i2); +#pragma aux divscale24 =\ + "mov edx, eax",\ + "sar edx, 8",\ + "shl eax, 24",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale25(long i1, long i2); +#pragma aux divscale25 =\ + "mov edx, eax",\ + "sar edx, 7",\ + "shl eax, 25",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale26(long i1, long i2); +#pragma aux divscale26 =\ + "mov edx, eax",\ + "sar edx, 6",\ + "shl eax, 26",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale27(long i1, long i2); +#pragma aux divscale27 =\ + "mov edx, eax",\ + "sar edx, 5",\ + "shl eax, 27",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale28(long i1, long i2); +#pragma aux divscale28 =\ + "mov edx, eax",\ + "sar edx, 4",\ + "shl eax, 28",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale29(long i1, long i2); +#pragma aux divscale29 =\ + "mov edx, eax",\ + "sar edx, 3",\ + "shl eax, 29",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale30(long i1, long i2); +#pragma aux divscale30 =\ + "mov edx, eax",\ + "sar edx, 2",\ + "shl eax, 30",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale31(long i1, long i2); +#pragma aux divscale31 =\ + "mov edx, eax",\ + "sar edx, 1",\ + "shl eax, 31",\ + "idiv ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax edx]\ + +long divscale32(long i1, long i2); +#pragma aux divscale32 =\ + "xor eax, eax",\ + "idiv ebx",\ + parm nomemory [edx][ebx]\ + modify exact [eax edx] + +#else /* non-Watcom platforms land here: */ + +#include "platform.h" //for __int64 + +static __inline void swapchar(unsigned char *p1, unsigned char *p2) +{ unsigned char tmp = *p1; *p1 = *p2; *p2 = tmp; } +static __inline void swapshort(short *p1, short *p2) +{ short tmp = *p1; *p1 = *p2; *p2 = tmp; } +static __inline void swaplong(long *p1, long *p2) +{ long tmp = *p1; *p1 = *p2; *p2 = tmp; } +static __inline void swapchar2(unsigned char *p1, unsigned char *p2, int xsiz) +{ + swapchar(p1, p2); + swapchar(p1 + 1, p2 + xsiz); +} + + +unsigned long getkensmessagecrc(long param); +long msqrtasm(int i1); + +void vlin16first (long i1, long i2); + +static __inline int sqr (int input1) { return input1*input1; } + +/* internal use:32x32 = 64bit */ +static __inline __int64 mul32_64(int i1,int i2) +{ + return (__int64)i1*i2; +} +static __inline int scale (int input1, int input2, int input3) +{ + return mul32_64(input1,input2)/input3; +} +static __inline int mulscale (int input1, int input2, int input3) +{ + return mul32_64(input1,input2)>>input3; +} +static __inline int dmulscale (int input1, int input2, int input3,int input4,int input5) +{ + return (mul32_64(input1,input2) + mul32_64(input3,input4))>>input5; +} +static __inline int tmulscale(int i1, int i2, int i3, int i4, int i5, int i6,int shift) +{ + return (mul32_64(i1,i2) + mul32_64(i3,i4) + mul32_64(i5,i6))>>shift; +} +static __inline int divscale(int i1, int i2, int i3) +{ + return ((__int64)i1< 0) return 1; + else return 0; +} + +static __inline int sgn(int i1) { return ksgn(i1); } +static __inline int klabs (int i1) +{ + if (i1 < 0) i1 = -i1; + return i1; +} +static __inline int mul3 (int i1) { return i1*3; } +static __inline int mul5 (int i1) { return i1*5; } +static __inline int mul9 (int i1) { return i1*9; } + +void copybufreverse(void *source, void *dest, int size); +void copybuf(void *source, void *dest, int size); +void clearbuf(void *buffer, int size, long fill_value); +void clearbufbyte(void *buffer, int size, long fill_value); +void copybufbyte(void *source, void *dest, int size); + +void qinterpolatedown16 (long *source, int size, int linum, int linum_inc); +void qinterpolatedown16short (long *source, int size, int linum, int linum_inc); + +#endif /* defined __WATCOMC__ */ + +#endif /* !defined _INCLUDE_PRAGMAS_H_ */ + +/* end of pragmas.h ... */ + + diff --git a/buildengine/pragmas_gnu.c b/buildengine/pragmas_gnu.c new file mode 100755 index 0000000..25c4af0 --- /dev/null +++ b/buildengine/pragmas_gnu.c @@ -0,0 +1,2506 @@ +/* + * Inline assembly. + * + * Initial PLATFORM_UNIX work done by Andrew Henderson. The DOS stuff is + * Ken's original code, and was in pragmas.h + * + * Please do NOT harrass Ken Silverman about any code modifications + * (including this file) to BUILD. + */ + +/* + * "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman + * Ken Silverman's official web site: "http://www.advsys.net/ken" + * See the included license file "BUILDLIC.TXT" for license info. + * This file has been modified from Ken Silverman's original release + */ + +#if (defined __WATCOMC__) + #if ((defined PLATFORM_DOS) || (defined PLATFORM_WIN32)) + #error Do not compile this. Just include pragmas.h instead. + #endif +#endif + +#if (defined USE_I386_ASM) + +#if (!defined __GNUC__) && (!defined __ICC) +#error This file is filled with GNU C-specific inline asm. +#endif + +static long dmval; + +/* rcg02132001 Cygwin support. */ +#if (defined C_IDENTIFIERS_UNDERSCORED) +#define SYM_dmval "_dmval" +#else +#define SYM_dmval "dmval" +#endif + +static __inline__ void _touch_dmval_stop_compiler_whining(void) +{ + dmval = 0; +} + +unsigned long getkensmessagecrc(long param) { + long retval; + __asm__ __volatile__ ( + "xorl %%eax, %%eax \n\t" + "movl $32, %%ecx \n\t" + "kensmsgbeg: movl -4(%%ebx,%%ecx,4), %%edx \n\t" + "rorl %%cl, %%edx \n\t" + "adcl %%edx, %%eax \n\t" + "bswapl %%eax \n\t" + "loop kensmsgbeg \n\t" + : "=a" (retval) : "b" (param) : "ecx", "edx", "cc"); + return(retval); +} + +long msqrtasm(int i1) +{ + int retval; + __asm__ __volatile__ ( + "movl $0x40000000, %%eax \n\t" + "movl $0x20000000, %%ebx \n\t" + "msqrasm_begit: cmpl %%eax, %%ecx \n\t" + "jl msqrasm_skip \n\t" + "subl %%eax, %%ecx \n\t" + "leal (%%eax, %%ebx, 4), %%eax \n\t" + "msqrasm_skip: subl %%ebx, %%eax \n\t" + "shrl $1, %%eax \n\t" + "shrl $2, %%ebx \n\t" + "jnz msqrasm_begit \n\t" + "cmpl %%eax, %%ecx \n\t" + "sbbl $-1, %%eax \n\t" + "shrl $1, %%eax \n\t" + : "=a" (retval) : "c" (i1) : "cc", "ebx"); + return(retval); +} /* msqrtasm */ + +int sqr (int i1) { + int retval; + __asm__ __volatile__ ( + "imull %%eax, %%eax \n\t" + : "=a" (retval) : "a" (i1) : "cc"); + return(retval); +} + +int scale (int i1, int i2, int i3) { + int retval; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "idivl %%ecx \n\t" + : "=a" (retval) : "a" (i1), "d" (i2), "c" (i3) : "cc"); + return(retval); +} + +int mulscale (int i1, int i2, short i3) { + int retval; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "shrdl %%cl, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2), "c" (i3) : "cc"); + return(retval); +} + +int mulscale1 (int i1, int i2) { + int retval; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "shrdl $1, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2) : "cc"); + return(retval); +} + +int mulscale2 (int i1, int i2) { + int retval; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "shrdl $2, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2) : "cc"); + return(retval); +} + +int mulscale3 (int i1, int i2) { + int retval; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "shrdl $3, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2) : "cc"); + return(retval); +} + +int mulscale4 (int i1, int i2) { + int retval; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "shrdl $4, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2) : "cc"); + return(retval); +} + +int mulscale5 (int i1, int i2) { + int retval; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "shrdl $5, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2) : "cc"); + return(retval); +} + +int mulscale6 (int i1, int i2) { + int retval; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "shrdl $6, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2) : "cc"); + return(retval); +} + +int mulscale7 (int i1, int i2) { + int retval; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "shrdl $7, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2) : "cc"); + return(retval); +} + +int mulscale8 (int i1, int i2) { + int retval; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "shrdl $8, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2) : "cc"); + return(retval); +} + +int mulscale9 (int i1, int i2) { + int retval; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "shrdl $9, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2) : "cc"); + return(retval); +} + +int mulscale10 (int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "shrdl $10, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2) : "cc"); + return(retval); +} + +int mulscale11 (int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "shrdl $11, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2) : "cc"); + return(retval); +} + +int mulscale12 (int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "shrdl $12, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2) : "cc"); + return(retval); +} + +int mulscale13 (int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "shrdl $13, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2) : "cc"); + return(retval); +} + +int mulscale14 (int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "shrdl $14, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2) : "cc"); + return(retval); +} + +int mulscale15 (int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "shrdl $15, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2) : "cc"); + return(retval); +} + +int mulscale16 (int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "shrdl $16, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2) : "cc"); + return(retval); +} + +int mulscale17 (int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "shrdl $17, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2) : "cc"); + return(retval); +} + +int mulscale18 (int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "shrdl $18, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2) : "cc"); + return(retval); +} + +int mulscale19 (int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "shrdl $19, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2) : "cc"); + return(retval); +} + +int mulscale20 (int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "shrdl $20, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2) : "cc"); + return(retval); +} + +int mulscale21 (int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "shrdl $21, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2) : "cc"); + return(retval); +} + +int mulscale22 (int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "shrdl $22, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2) : "cc"); + return(retval); +} + +int mulscale23 (int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "shrdl $23, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2) : "cc"); + return(retval); +} + +int mulscale24 (int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "shrdl $24, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2) : "cc"); + return(retval); +} + +int mulscale25 (int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "shrdl $25, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2) : "cc"); + return(retval); +} + +int mulscale26 (int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "shrdl $26, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2) : "cc"); + return(retval); +} + +int mulscale27 (int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "shrdl $27, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2) : "cc"); + return(retval); +} + +int mulscale28 (int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "shrdl $28, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2) : "cc"); + return(retval); +} + +int mulscale29 (int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "shrdl $29, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2) : "cc"); + return(retval); +} + +int mulscale30 (int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "shrdl $30, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2) : "cc"); + return(retval); +} + +int mulscale31 (int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "shrdl $31, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2) : "cc"); + return(retval); +} + +int mulscale32 (int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + : "=d" (retval) : "a" (i1), "d" (i2) : "cc"); + return(retval); +} + +int divmod (int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "xorl %%edx, %%edx \n\t" + "divl %%ebx \n\t" + "movl %%edx, " SYM_dmval " \n\t" + : "=a" (retval) : "a" (i1), "b" (i2) : "edx", "memory", "cc"); + return(retval); +} + +int dmulscale(int i1, int i2, int i3, int i4, int i5) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "movl %%eax, %%ebx \n\t" + "movl %%esi, %%eax \n\t" + "movl %%edx, %%esi \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%esi, %%edx \n\t" + "shrdl %%cl, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2), "S" (i3), "D" (i4), "c" (i5) + : "ebx", "cc"); + return(retval); +} + +int dmulscale1(int i1, int i2, int i3, int i4) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "movl %%eax, %%ebx \n\t" + "movl %%esi, %%eax \n\t" + "movl %%edx, %%esi \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%esi, %%edx \n\t" + "shrdl $1, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2), "S" (i3), "D" (i4) + : "ebx", "cc"); + return(retval); +} + +int dmulscale2(int i1, int i2, int i3, int i4) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "movl %%eax, %%ebx \n\t" + "movl %%esi, %%eax \n\t" + "movl %%edx, %%esi \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%esi, %%edx \n\t" + "shrdl $2, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2), "S" (i3), "D" (i4) + : "ebx", "cc"); + return(retval); +} + +int dmulscale3(int i1, int i2, int i3, int i4) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "movl %%eax, %%ebx \n\t" + "movl %%esi, %%eax \n\t" + "movl %%edx, %%esi \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%esi, %%edx \n\t" + "shrdl $3, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2), "S" (i3), "D" (i4) + : "ebx", "cc"); + return(retval); +} + +int dmulscale4(int i1, int i2, int i3, int i4) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "movl %%eax, %%ebx \n\t" + "movl %%esi, %%eax \n\t" + "movl %%edx, %%esi \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%esi, %%edx \n\t" + "shrdl $4, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2), "S" (i3), "D" (i4) + : "ebx", "cc"); + return(retval); +} + +int dmulscale5(int i1, int i2, int i3, int i4) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "movl %%eax, %%ebx \n\t" + "movl %%esi, %%eax \n\t" + "movl %%edx, %%esi \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%esi, %%edx \n\t" + "shrdl $5, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2), "S" (i3), "D" (i4) + : "ebx", "cc"); + return(retval); +} + +int dmulscale6(int i1, int i2, int i3, int i4) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "movl %%eax, %%ebx \n\t" + "movl %%esi, %%eax \n\t" + "movl %%edx, %%esi \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%esi, %%edx \n\t" + "shrdl $6, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2), "S" (i3), "D" (i4) + : "ebx", "cc"); + return(retval); +} + +int dmulscale7(int i1, int i2, int i3, int i4) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "movl %%eax, %%ebx \n\t" + "movl %%esi, %%eax \n\t" + "movl %%edx, %%esi \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%esi, %%edx \n\t" + "shrdl $7, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2), "S" (i3), "D" (i4) + : "ebx", "cc"); + return(retval); +} + +int dmulscale8(int i1, int i2, int i3, int i4) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "movl %%eax, %%ebx \n\t" + "movl %%esi, %%eax \n\t" + "movl %%edx, %%esi \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%esi, %%edx \n\t" + "shrdl $8, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2), "S" (i3), "D" (i4) + : "ebx", "cc"); + return(retval); +} + +int dmulscale9(int i1, int i2, int i3, int i4) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "movl %%eax, %%ebx \n\t" + "movl %%esi, %%eax \n\t" + "movl %%edx, %%esi \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%esi, %%edx \n\t" + "shrdl $9, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2), "S" (i3), "D" (i4) + : "ebx", "cc"); + return(retval); +} + +int dmulscale10(int i1, int i2, int i3, int i4) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "movl %%eax, %%ebx \n\t" + "movl %%esi, %%eax \n\t" + "movl %%edx, %%esi \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%esi, %%edx \n\t" + "shrdl $10, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2), "S" (i3), "D" (i4) + : "ebx", "cc"); + return(retval); +} + +int dmulscale11(int i1, int i2, int i3, int i4) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "movl %%eax, %%ebx \n\t" + "movl %%esi, %%eax \n\t" + "movl %%edx, %%esi \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%esi, %%edx \n\t" + "shrdl $11, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2), "S" (i3), "D" (i4) + : "ebx", "cc"); + return(retval); +} + +int dmulscale12(int i1, int i2, int i3, int i4) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "movl %%eax, %%ebx \n\t" + "movl %%esi, %%eax \n\t" + "movl %%edx, %%esi \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%esi, %%edx \n\t" + "shrdl $12, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2), "S" (i3), "D" (i4) + : "ebx", "cc"); + return(retval); +} + +int dmulscale13(int i1, int i2, int i3, int i4) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "movl %%eax, %%ebx \n\t" + "movl %%esi, %%eax \n\t" + "movl %%edx, %%esi \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%esi, %%edx \n\t" + "shrdl $13, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2), "S" (i3), "D" (i4) + : "ebx", "cc"); + return(retval); +} + +int dmulscale14(int i1, int i2, int i3, int i4) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "movl %%eax, %%ebx \n\t" + "movl %%esi, %%eax \n\t" + "movl %%edx, %%esi \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%esi, %%edx \n\t" + "shrdl $14, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2), "S" (i3), "D" (i4) + : "ebx", "cc"); + return(retval); +} + +int dmulscale15(int i1, int i2, int i3, int i4) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "movl %%eax, %%ebx \n\t" + "movl %%esi, %%eax \n\t" + "movl %%edx, %%esi \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%esi, %%edx \n\t" + "shrdl $15, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2), "S" (i3), "D" (i4) + : "ebx", "cc"); + return(retval); +} + +int dmulscale16(int i1, int i2, int i3, int i4) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "movl %%eax, %%ebx \n\t" + "movl %%esi, %%eax \n\t" + "movl %%edx, %%esi \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%esi, %%edx \n\t" + "shrdl $16, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2), "S" (i3), "D" (i4) + : "ebx", "cc"); + return(retval); +} + +int dmulscale17(int i1, int i2, int i3, int i4) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "movl %%eax, %%ebx \n\t" + "movl %%esi, %%eax \n\t" + "movl %%edx, %%esi \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%esi, %%edx \n\t" + "shrdl $17, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2), "S" (i3), "D" (i4) + : "ebx", "cc"); + return(retval); +} + +int dmulscale18(int i1, int i2, int i3, int i4) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "movl %%eax, %%ebx \n\t" + "movl %%esi, %%eax \n\t" + "movl %%edx, %%esi \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%esi, %%edx \n\t" + "shrdl $18, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2), "S" (i3), "D" (i4) + : "ebx", "cc"); + return(retval); +} + +int dmulscale19(int i1, int i2, int i3, int i4) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "movl %%eax, %%ebx \n\t" + "movl %%esi, %%eax \n\t" + "movl %%edx, %%esi \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%esi, %%edx \n\t" + "shrdl $19, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2), "S" (i3), "D" (i4) + : "ebx", "cc"); + return(retval); +} + +int dmulscale20(int i1, int i2, int i3, int i4) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "movl %%eax, %%ebx \n\t" + "movl %%esi, %%eax \n\t" + "movl %%edx, %%esi \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%esi, %%edx \n\t" + "shrdl $20, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2), "S" (i3), "D" (i4) + : "ebx", "cc"); + return(retval); +} + +int dmulscale21(int i1, int i2, int i3, int i4) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "movl %%eax, %%ebx \n\t" + "movl %%esi, %%eax \n\t" + "movl %%edx, %%esi \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%esi, %%edx \n\t" + "shrdl $21, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2), "S" (i3), "D" (i4) + : "ebx", "cc"); + return(retval); +} + +int dmulscale22(int i1, int i2, int i3, int i4) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "movl %%eax, %%ebx \n\t" + "movl %%esi, %%eax \n\t" + "movl %%edx, %%esi \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%esi, %%edx \n\t" + "shrdl $22, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2), "S" (i3), "D" (i4) + : "ebx", "cc"); + return(retval); +} + +int dmulscale23(int i1, int i2, int i3, int i4) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "movl %%eax, %%ebx \n\t" + "movl %%esi, %%eax \n\t" + "movl %%edx, %%esi \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%esi, %%edx \n\t" + "shrdl $23, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2), "S" (i3), "D" (i4) + : "ebx", "cc"); + return(retval); +} + +int dmulscale24(int i1, int i2, int i3, int i4) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "movl %%eax, %%ebx \n\t" + "movl %%esi, %%eax \n\t" + "movl %%edx, %%esi \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%esi, %%edx \n\t" + "shrdl $24, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2), "S" (i3), "D" (i4) + : "ebx", "cc"); + return(retval); +} + +int dmulscale25(int i1, int i2, int i3, int i4) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "movl %%eax, %%ebx \n\t" + "movl %%esi, %%eax \n\t" + "movl %%edx, %%esi \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%esi, %%edx \n\t" + "shrdl $25, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2), "S" (i3), "D" (i4) + : "ebx", "cc"); + return(retval); +} + +int dmulscale26(int i1, int i2, int i3, int i4) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "movl %%eax, %%ebx \n\t" + "movl %%esi, %%eax \n\t" + "movl %%edx, %%esi \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%esi, %%edx \n\t" + "shrdl $26, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2), "S" (i3), "D" (i4) + : "ebx", "cc"); + return(retval); +} + +int dmulscale27(int i1, int i2, int i3, int i4) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "movl %%eax, %%ebx \n\t" + "movl %%esi, %%eax \n\t" + "movl %%edx, %%esi \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%esi, %%edx \n\t" + "shrdl $27, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2), "S" (i3), "D" (i4) + : "ebx", "cc"); + return(retval); +} + +int dmulscale28(int i1, int i2, int i3, int i4) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "movl %%eax, %%ebx \n\t" + "movl %%esi, %%eax \n\t" + "movl %%edx, %%esi \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%esi, %%edx \n\t" + "shrdl $28, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2), "S" (i3), "D" (i4) + : "ebx", "cc"); + return(retval); +} + +int dmulscale29(int i1, int i2, int i3, int i4) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "movl %%eax, %%ebx \n\t" + "movl %%esi, %%eax \n\t" + "movl %%edx, %%esi \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%esi, %%edx \n\t" + "shrdl $29, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2), "S" (i3), "D" (i4) + : "ebx", "cc"); + return(retval); +} + + +int dmulscale30(int i1, int i2, int i3, int i4) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "movl %%eax, %%ebx \n\t" + "movl %%esi, %%eax \n\t" + "movl %%edx, %%esi \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%esi, %%edx \n\t" + "shrdl $30, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2), "S" (i3), "D" (i4) + : "ebx", "cc"); + return(retval); +} + +int dmulscale31(int i1, int i2, int i3, int i4) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "movl %%eax, %%ebx \n\t" + "movl %%esi, %%eax \n\t" + "movl %%edx, %%esi \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%esi, %%edx \n\t" + "shrdl $31, %%edx, %%eax \n\t" + : "=a" (retval) : "a" (i1), "d" (i2), "S" (i3), "D" (i4) + : "ebx", "cc"); + return(retval); +} + +int dmulscale32(int i1, int i2, int i3, int i4) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "movl %%eax, %%ebx \n\t" + "movl %%esi, %%eax \n\t" + "movl %%edx, %%esi \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%esi, %%edx \n\t" + : "=d" (retval) : "a" (i1), "d" (i2), "S" (i3), "D" (i4) + : "ebx", "cc"); + return(retval); +} + +int tmulscale1(int i1, int i2, int i3, int i4, int i5, int i6) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "xchgl %%ebx, %%eax \n\t" + "xchgl %%ecx, %%edx \n\t" + "imull %%edx \n\t" + "addl %%eax, %%ebx \n\t" + "adcl %%edx, %%ecx \n\t" + "movl %%esi, %%eax \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%ecx, %%edx \n\t" + "shrdl $1, %%edx, %%eax \n\t" + : "=a" (retval) + : "a" (i1), "d" (i2), "b" (i3), "c" (i4), "S" (i5), "D" (i6) + : "cc"); + return(retval); +} + +int tmulscale2(int i1, int i2, int i3, int i4, int i5, int i6) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "xchgl %%ebx, %%eax \n\t" + "xchgl %%ecx, %%edx \n\t" + "imull %%edx \n\t" + "addl %%eax, %%ebx \n\t" + "adcl %%edx, %%ecx \n\t" + "movl %%esi, %%eax \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%ecx, %%edx \n\t" + "shrdl $2, %%edx, %%eax \n\t" + : "=a" (retval) + : "a" (i1), "d" (i2), "b" (i3), "c" (i4), "S" (i5), "D" (i6) + : "cc"); + return(retval); +} + +int tmulscale3(int i1, int i2, int i3, int i4, int i5, int i6) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "xchgl %%ebx, %%eax \n\t" + "xchgl %%ecx, %%edx \n\t" + "imull %%edx \n\t" + "addl %%eax, %%ebx \n\t" + "adcl %%edx, %%ecx \n\t" + "movl %%esi, %%eax \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%ecx, %%edx \n\t" + "shrdl $3, %%edx, %%eax \n\t" + : "=a" (retval) + : "a" (i1), "d" (i2), "b" (i3), "c" (i4), "S" (i5), "D" (i6) + : "cc"); + return(retval); +} + +int tmulscale4(int i1, int i2, int i3, int i4, int i5, int i6) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "xchgl %%ebx, %%eax \n\t" + "xchgl %%ecx, %%edx \n\t" + "imull %%edx \n\t" + "addl %%eax, %%ebx \n\t" + "adcl %%edx, %%ecx \n\t" + "movl %%esi, %%eax \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%ecx, %%edx \n\t" + "shrdl $4, %%edx, %%eax \n\t" + : "=a" (retval) + : "a" (i1), "d" (i2), "b" (i3), "c" (i4), "S" (i5), "D" (i6) + : "cc"); + return(retval); +} + +int tmulscale5(int i1, int i2, int i3, int i4, int i5, int i6) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "xchgl %%ebx, %%eax \n\t" + "xchgl %%ecx, %%edx \n\t" + "imull %%edx \n\t" + "addl %%eax, %%ebx \n\t" + "adcl %%edx, %%ecx \n\t" + "movl %%esi, %%eax \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%ecx, %%edx \n\t" + "shrdl $5, %%edx, %%eax \n\t" + : "=a" (retval) + : "a" (i1), "d" (i2), "b" (i3), "c" (i4), "S" (i5), "D" (i6) + : "cc"); + return(retval); +} + +int tmulscale6(int i1, int i2, int i3, int i4, int i5, int i6) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "xchgl %%ebx, %%eax \n\t" + "xchgl %%ecx, %%edx \n\t" + "imull %%edx \n\t" + "addl %%eax, %%ebx \n\t" + "adcl %%edx, %%ecx \n\t" + "movl %%esi, %%eax \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%ecx, %%edx \n\t" + "shrdl $6, %%edx, %%eax \n\t" + : "=a" (retval) + : "a" (i1), "d" (i2), "b" (i3), "c" (i4), "S" (i5), "D" (i6) + : "cc"); + return(retval); +} + +int tmulscale7(int i1, int i2, int i3, int i4, int i5, int i6) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "xchgl %%ebx, %%eax \n\t" + "xchgl %%ecx, %%edx \n\t" + "imull %%edx \n\t" + "addl %%eax, %%ebx \n\t" + "adcl %%edx, %%ecx \n\t" + "movl %%esi, %%eax \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%ecx, %%edx \n\t" + "shrdl $7, %%edx, %%eax \n\t" + : "=a" (retval) + : "a" (i1), "d" (i2), "b" (i3), "c" (i4), "S" (i5), "D" (i6) + : "cc"); + return(retval); +} + +int tmulscale8(int i1, int i2, int i3, int i4, int i5, int i6) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "xchgl %%ebx, %%eax \n\t" + "xchgl %%ecx, %%edx \n\t" + "imull %%edx \n\t" + "addl %%eax, %%ebx \n\t" + "adcl %%edx, %%ecx \n\t" + "movl %%esi, %%eax \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%ecx, %%edx \n\t" + "shrdl $8, %%edx, %%eax \n\t" + : "=a" (retval) + : "a" (i1), "d" (i2), "b" (i3), "c" (i4), "S" (i5), "D" (i6) + : "cc"); + return(retval); +} + +int tmulscale9(int i1, int i2, int i3, int i4, int i5, int i6) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "xchgl %%ebx, %%eax \n\t" + "xchgl %%ecx, %%edx \n\t" + "imull %%edx \n\t" + "addl %%eax, %%ebx \n\t" + "adcl %%edx, %%ecx \n\t" + "movl %%esi, %%eax \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%ecx, %%edx \n\t" + "shrdl $9, %%edx, %%eax \n\t" + : "=a" (retval) + : "a" (i1), "d" (i2), "b" (i3), "c" (i4), "S" (i5), "D" (i6) + : "cc"); + return(retval); +} + +int tmulscale10(int i1, int i2, int i3, int i4, int i5, int i6) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "xchgl %%ebx, %%eax \n\t" + "xchgl %%ecx, %%edx \n\t" + "imull %%edx \n\t" + "addl %%eax, %%ebx \n\t" + "adcl %%edx, %%ecx \n\t" + "movl %%esi, %%eax \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%ecx, %%edx \n\t" + "shrdl $10, %%edx, %%eax \n\t" + : "=a" (retval) + : "a" (i1), "d" (i2), "b" (i3), "c" (i4), "S" (i5), "D" (i6) + : "cc"); + return(retval); +} + +int tmulscale11(int i1, int i2, int i3, int i4, int i5, int i6) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "xchgl %%ebx, %%eax \n\t" + "xchgl %%ecx, %%edx \n\t" + "imull %%edx \n\t" + "addl %%eax, %%ebx \n\t" + "adcl %%edx, %%ecx \n\t" + "movl %%esi, %%eax \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%ecx, %%edx \n\t" + "shrdl $11, %%edx, %%eax \n\t" + : "=a" (retval) + : "a" (i1), "d" (i2), "b" (i3), "c" (i4), "S" (i5), "D" (i6) + : "cc"); + return(retval); +} + +int tmulscale12(int i1, int i2, int i3, int i4, int i5, int i6) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "xchgl %%ebx, %%eax \n\t" + "xchgl %%ecx, %%edx \n\t" + "imull %%edx \n\t" + "addl %%eax, %%ebx \n\t" + "adcl %%edx, %%ecx \n\t" + "movl %%esi, %%eax \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%ecx, %%edx \n\t" + "shrdl $12, %%edx, %%eax \n\t" + : "=a" (retval) + : "a" (i1), "d" (i2), "b" (i3), "c" (i4), "S" (i5), "D" (i6) + : "cc"); + return(retval); +} + +int tmulscale13(int i1, int i2, int i3, int i4, int i5, int i6) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "xchgl %%ebx, %%eax \n\t" + "xchgl %%ecx, %%edx \n\t" + "imull %%edx \n\t" + "addl %%eax, %%ebx \n\t" + "adcl %%edx, %%ecx \n\t" + "movl %%esi, %%eax \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%ecx, %%edx \n\t" + "shrdl $13, %%edx, %%eax \n\t" + : "=a" (retval) + : "a" (i1), "d" (i2), "b" (i3), "c" (i4), "S" (i5), "D" (i6) + : "cc"); + return(retval); +} + +int tmulscale14(int i1, int i2, int i3, int i4, int i5, int i6) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "xchgl %%ebx, %%eax \n\t" + "xchgl %%ecx, %%edx \n\t" + "imull %%edx \n\t" + "addl %%eax, %%ebx \n\t" + "adcl %%edx, %%ecx \n\t" + "movl %%esi, %%eax \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%ecx, %%edx \n\t" + "shrdl $14, %%edx, %%eax \n\t" + : "=a" (retval) + : "a" (i1), "d" (i2), "b" (i3), "c" (i4), "S" (i5), "D" (i6) + : "cc"); + return(retval); +} + +int tmulscale15(int i1, int i2, int i3, int i4, int i5, int i6) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "xchgl %%ebx, %%eax \n\t" + "xchgl %%ecx, %%edx \n\t" + "imull %%edx \n\t" + "addl %%eax, %%ebx \n\t" + "adcl %%edx, %%ecx \n\t" + "movl %%esi, %%eax \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%ecx, %%edx \n\t" + "shrdl $15, %%edx, %%eax \n\t" + : "=a" (retval) + : "a" (i1), "d" (i2), "b" (i3), "c" (i4), "S" (i5), "D" (i6) + : "cc"); + return(retval); +} + +int tmulscale16(int i1, int i2, int i3, int i4, int i5, int i6) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "xchgl %%ebx, %%eax \n\t" + "xchgl %%ecx, %%edx \n\t" + "imull %%edx \n\t" + "addl %%eax, %%ebx \n\t" + "adcl %%edx, %%ecx \n\t" + "movl %%esi, %%eax \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%ecx, %%edx \n\t" + "shrdl $16, %%edx, %%eax \n\t" + : "=a" (retval) + : "a" (i1), "d" (i2), "b" (i3), "c" (i4), "S" (i5), "D" (i6) + : "cc"); + return(retval); +} + +int tmulscale17(int i1, int i2, int i3, int i4, int i5, int i6) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "xchgl %%ebx, %%eax \n\t" + "xchgl %%ecx, %%edx \n\t" + "imull %%edx \n\t" + "addl %%eax, %%ebx \n\t" + "adcl %%edx, %%ecx \n\t" + "movl %%esi, %%eax \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%ecx, %%edx \n\t" + "shrdl $17, %%edx, %%eax \n\t" + : "=a" (retval) + : "a" (i1), "d" (i2), "b" (i3), "c" (i4), "S" (i5), "D" (i6) + : "cc"); + return(retval); +} + +int tmulscale18(int i1, int i2, int i3, int i4, int i5, int i6) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "xchgl %%ebx, %%eax \n\t" + "xchgl %%ecx, %%edx \n\t" + "imull %%edx \n\t" + "addl %%eax, %%ebx \n\t" + "adcl %%edx, %%ecx \n\t" + "movl %%esi, %%eax \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%ecx, %%edx \n\t" + "shrdl $18, %%edx, %%eax \n\t" + : "=a" (retval) + : "a" (i1), "d" (i2), "b" (i3), "c" (i4), "S" (i5), "D" (i6) + : "cc"); + return(retval); +} + +int tmulscale19(int i1, int i2, int i3, int i4, int i5, int i6) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "xchgl %%ebx, %%eax \n\t" + "xchgl %%ecx, %%edx \n\t" + "imull %%edx \n\t" + "addl %%eax, %%ebx \n\t" + "adcl %%edx, %%ecx \n\t" + "movl %%esi, %%eax \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%ecx, %%edx \n\t" + "shrdl $19, %%edx, %%eax \n\t" + : "=a" (retval) + : "a" (i1), "d" (i2), "b" (i3), "c" (i4), "S" (i5), "D" (i6) + : "cc"); + return(retval); +} + +int tmulscale20(int i1, int i2, int i3, int i4, int i5, int i6) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "xchgl %%ebx, %%eax \n\t" + "xchgl %%ecx, %%edx \n\t" + "imull %%edx \n\t" + "addl %%eax, %%ebx \n\t" + "adcl %%edx, %%ecx \n\t" + "movl %%esi, %%eax \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%ecx, %%edx \n\t" + "shrdl $20, %%edx, %%eax \n\t" + : "=a" (retval) + : "a" (i1), "d" (i2), "b" (i3), "c" (i4), "S" (i5), "D" (i6) + : "cc"); + return(retval); +} + +int tmulscale21(int i1, int i2, int i3, int i4, int i5, int i6) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "xchgl %%ebx, %%eax \n\t" + "xchgl %%ecx, %%edx \n\t" + "imull %%edx \n\t" + "addl %%eax, %%ebx \n\t" + "adcl %%edx, %%ecx \n\t" + "movl %%esi, %%eax \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%ecx, %%edx \n\t" + "shrdl $21, %%edx, %%eax \n\t" + : "=a" (retval) + : "a" (i1), "d" (i2), "b" (i3), "c" (i4), "S" (i5), "D" (i6) + : "cc"); + return(retval); +} + +int tmulscale22(int i1, int i2, int i3, int i4, int i5, int i6) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "xchgl %%ebx, %%eax \n\t" + "xchgl %%ecx, %%edx \n\t" + "imull %%edx \n\t" + "addl %%eax, %%ebx \n\t" + "adcl %%edx, %%ecx \n\t" + "movl %%esi, %%eax \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%ecx, %%edx \n\t" + "shrdl $22, %%edx, %%eax \n\t" + : "=a" (retval) + : "a" (i1), "d" (i2), "b" (i3), "c" (i4), "S" (i5), "D" (i6) + : "cc"); + return(retval); +} + +int tmulscale23(int i1, int i2, int i3, int i4, int i5, int i6) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "xchgl %%ebx, %%eax \n\t" + "xchgl %%ecx, %%edx \n\t" + "imull %%edx \n\t" + "addl %%eax, %%ebx \n\t" + "adcl %%edx, %%ecx \n\t" + "movl %%esi, %%eax \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%ecx, %%edx \n\t" + "shrdl $23, %%edx, %%eax \n\t" + : "=a" (retval) + : "a" (i1), "d" (i2), "b" (i3), "c" (i4), "S" (i5), "D" (i6) + : "cc"); + return(retval); +} + +int tmulscale24(int i1, int i2, int i3, int i4, int i5, int i6) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "xchgl %%ebx, %%eax \n\t" + "xchgl %%ecx, %%edx \n\t" + "imull %%edx \n\t" + "addl %%eax, %%ebx \n\t" + "adcl %%edx, %%ecx \n\t" + "movl %%esi, %%eax \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%ecx, %%edx \n\t" + "shrdl $24, %%edx, %%eax \n\t" + : "=a" (retval) + : "a" (i1), "d" (i2), "b" (i3), "c" (i4), "S" (i5), "D" (i6) + : "cc"); + return(retval); +} + +int tmulscale25(int i1, int i2, int i3, int i4, int i5, int i6) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "xchgl %%ebx, %%eax \n\t" + "xchgl %%ecx, %%edx \n\t" + "imull %%edx \n\t" + "addl %%eax, %%ebx \n\t" + "adcl %%edx, %%ecx \n\t" + "movl %%esi, %%eax \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%ecx, %%edx \n\t" + "shrdl $25, %%edx, %%eax \n\t" + : "=a" (retval) + : "a" (i1), "d" (i2), "b" (i3), "c" (i4), "S" (i5), "D" (i6) + : "cc"); + return(retval); +} + +int tmulscale26(int i1, int i2, int i3, int i4, int i5, int i6) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "xchgl %%ebx, %%eax \n\t" + "xchgl %%ecx, %%edx \n\t" + "imull %%edx \n\t" + "addl %%eax, %%ebx \n\t" + "adcl %%edx, %%ecx \n\t" + "movl %%esi, %%eax \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%ecx, %%edx \n\t" + "shrdl $26, %%edx, %%eax \n\t" + : "=a" (retval) + : "a" (i1), "d" (i2), "b" (i3), "c" (i4), "S" (i5), "D" (i6) + : "cc"); + return(retval); +} + +int tmulscale27(int i1, int i2, int i3, int i4, int i5, int i6) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "xchgl %%ebx, %%eax \n\t" + "xchgl %%ecx, %%edx \n\t" + "imull %%edx \n\t" + "addl %%eax, %%ebx \n\t" + "adcl %%edx, %%ecx \n\t" + "movl %%esi, %%eax \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%ecx, %%edx \n\t" + "shrdl $27, %%edx, %%eax \n\t" + : "=a" (retval) + : "a" (i1), "d" (i2), "b" (i3), "c" (i4), "S" (i5), "D" (i6) + : "cc"); + return(retval); +} + +int tmulscale28(int i1, int i2, int i3, int i4, int i5, int i6) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "xchgl %%ebx, %%eax \n\t" + "xchgl %%ecx, %%edx \n\t" + "imull %%edx \n\t" + "addl %%eax, %%ebx \n\t" + "adcl %%edx, %%ecx \n\t" + "movl %%esi, %%eax \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%ecx, %%edx \n\t" + "shrdl $28, %%edx, %%eax \n\t" + : "=a" (retval) + : "a" (i1), "d" (i2), "b" (i3), "c" (i4), "S" (i5), "D" (i6) + : "cc"); + return(retval); +} + +int tmulscale29(int i1, int i2, int i3, int i4, int i5, int i6) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "xchgl %%ebx, %%eax \n\t" + "xchgl %%ecx, %%edx \n\t" + "imull %%edx \n\t" + "addl %%eax, %%ebx \n\t" + "adcl %%edx, %%ecx \n\t" + "movl %%esi, %%eax \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%ecx, %%edx \n\t" + "shrdl $29, %%edx, %%eax \n\t" + : "=a" (retval) + : "a" (i1), "d" (i2), "b" (i3), "c" (i4), "S" (i5), "D" (i6) + : "cc"); + return(retval); +} + +int tmulscale30(int i1, int i2, int i3, int i4, int i5, int i6) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "xchgl %%ebx, %%eax \n\t" + "xchgl %%ecx, %%edx \n\t" + "imull %%edx \n\t" + "addl %%eax, %%ebx \n\t" + "adcl %%edx, %%ecx \n\t" + "movl %%esi, %%eax \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%ecx, %%edx \n\t" + "shrdl $30, %%edx, %%eax \n\t" + : "=a" (retval) + : "a" (i1), "d" (i2), "b" (i3), "c" (i4), "S" (i5), "D" (i6) + : "cc"); + return(retval); +} + +int tmulscale31(int i1, int i2, int i3, int i4, int i5, int i6) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "xchgl %%ebx, %%eax \n\t" + "xchgl %%ecx, %%edx \n\t" + "imull %%edx \n\t" + "addl %%eax, %%ebx \n\t" + "adcl %%edx, %%ecx \n\t" + "movl %%esi, %%eax \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%ecx, %%edx \n\t" + "shrdl $31, %%edx, %%eax \n\t" + : "=a" (retval) + : "a" (i1), "d" (i2), "b" (i3), "c" (i4), "S" (i5), "D" (i6) + : "cc"); + return(retval); +} + +int tmulscale32(int i1, int i2, int i3, int i4, int i5, int i6) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%edx \n\t" + "xchgl %%ebx, %%eax \n\t" + "xchgl %%ecx, %%edx \n\t" + "imull %%edx \n\t" + "addl %%eax, %%ebx \n\t" + "adcl %%edx, %%ecx \n\t" + "movl %%esi, %%eax \n\t" + "imull %%edi \n\t" + "addl %%ebx, %%eax \n\t" + "adcl %%ecx, %%edx \n\t" + : "=d" (retval) + : "a" (i1), "d" (i2), "b" (i3), "c" (i4), "S" (i5), "D" (i6) + : "cc"); + return(retval); +} + + +int boundmulscale(int i1, int i2, int i3) { + int retval = 0; + __asm__ __volatile__ ( + "imull %%ebx \n\t" + "movl %%edx, %%ebx \n\t" + "shrdl %%cl, %%edx, %%eax \n\t" + "sarl %%cl, %%edx \n\t" + "xorl %%eax, %%edx \n\t" + "js checkit \n\t" + "xorl %%eax, %%edx \n\t" + "jz skipboundit \n\t" + "cmpl $0xffffffff, %%edx \n\t" + "je skipboundit \n\t" + "checkit: \n\t" + "movl %%ebx, %%eax \n\t" + "sarl $31, %%eax \n\t" + "xorl $0x7fffffff, %%eax \n\t" + "skipboundit: \n\t" + : "=a" (retval) : "a" (i1), "b" (i2), "c" (i3) : "edx", "cc"); + return(retval); +} + +int divscale(int i1, int i2, int i3) { + int retval = 0; + __asm__ __volatile__ ( + "movl %%eax, %%edx \n\t" + "shll %%cl, %%eax \n\t" + "negb %%cl \n\t" + "sarl %%cl, %%edx \n\t" + "idivl %%ebx \n\t" + : "=a" (retval) : "a" (i1), "b" (i2), "c" (i3) : "edx", "cc"); + return(retval); +} + +int divscale1(int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "addl %%eax, %%eax \n\t" + "sbbl %%edx, %%edx \n\t" + "idivl %%ebx \n\t" + : "=a" (retval) : "a" (i1), "b" (i2) : "edx", "cc"); + return(retval); +} + + +int divscale2(int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "movl %%eax, %%edx \n\t" + "sarl $30, %%edx \n\t" + "leal (, %%eax, 4), %%eax \n\t" + "idivl %%ebx \n\t" + : "=a" (retval) : "a" (i1), "b" (i2) : "edx", "cc"); + return(retval); +} + +int divscale3(int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "movl %%eax, %%edx \n\t" + "sarl $29, %%edx \n\t" + "leal (, %%eax, 8), %%eax \n\t" + "idivl %%ebx \n\t" + : "=a" (retval) : "a" (i1), "b" (i2) : "edx", "cc"); + return(retval); +} + +int divscale4(int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "movl %%eax, %%edx \n\t" + "sarl $28, %%edx \n\t" + "shll $4, %%eax \n\t" + "idivl %%ebx \n\t" + : "=a" (retval) : "a" (i1), "b" (i2) : "edx", "cc"); + return(retval); +} + +int divscale5(int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "movl %%eax, %%edx \n\t" + "sarl $27, %%edx \n\t" + "shll $5, %%eax \n\t" + "idivl %%ebx \n\t" + : "=a" (retval) : "a" (i1), "b" (i2) : "edx", "cc"); + return(retval); +} + +int divscale6(int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "movl %%eax, %%edx \n\t" + "sarl $26, %%edx \n\t" + "shll $6, %%eax \n\t" + "idivl %%ebx \n\t" + : "=a" (retval) : "a" (i1), "b" (i2) : "edx", "cc"); + return(retval); +} + +int divscale7(int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "movl %%eax, %%edx \n\t" + "sarl $25, %%edx \n\t" + "shll $7, %%eax \n\t" + "idivl %%ebx \n\t" + : "=a" (retval) : "a" (i1), "b" (i2) : "edx", "cc"); + return(retval); +} + +int divscale8(int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "movl %%eax, %%edx \n\t" + "sarl $24, %%edx \n\t" + "shll $8, %%eax \n\t" + "idivl %%ebx \n\t" + : "=a" (retval) : "a" (i1), "b" (i2) : "edx", "cc"); + return(retval); +} + +int divscale9(int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "movl %%eax, %%edx \n\t" + "sarl $23, %%edx \n\t" + "shll $9, %%eax \n\t" + "idivl %%ebx \n\t" + : "=a" (retval) : "a" (i1), "b" (i2) : "edx", "cc"); + return(retval); +} + +int divscale10(int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "movl %%eax, %%edx \n\t" + "sarl $22, %%edx \n\t" + "shll $10, %%eax \n\t" + "idivl %%ebx \n\t" + : "=a" (retval) : "a" (i1), "b" (i2) : "edx", "cc"); + return(retval); +} + +int divscale11(int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "movl %%eax, %%edx \n\t" + "sarl $21, %%edx \n\t" + "shll $11, %%eax \n\t" + "idivl %%ebx \n\t" + : "=a" (retval) : "a" (i1), "b" (i2) : "edx", "cc"); + return(retval); +} + +int divscale12(int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "movl %%eax, %%edx \n\t" + "sarl $20, %%edx \n\t" + "shll $12, %%eax \n\t" + "idivl %%ebx \n\t" + : "=a" (retval) : "a" (i1), "b" (i2) : "edx", "cc"); + return(retval); +} + +int divscale13(int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "movl %%eax, %%edx \n\t" + "sarl $19, %%edx \n\t" + "shll $13, %%eax \n\t" + "idivl %%ebx \n\t" + : "=a" (retval) : "a" (i1), "b" (i2) : "edx", "cc"); + return(retval); +} + +int divscale14(int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "movl %%eax, %%edx \n\t" + "sarl $18, %%edx \n\t" + "shll $14, %%eax \n\t" + "idivl %%ebx \n\t" + : "=a" (retval) : "a" (i1), "b" (i2) : "edx", "cc"); + return(retval); +} + +int divscale15(int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "movl %%eax, %%edx \n\t" + "sarl $17, %%edx \n\t" + "shll $15, %%eax \n\t" + "idivl %%ebx \n\t" + : "=a" (retval) : "a" (i1), "b" (i2) : "edx", "cc"); + return(retval); +} + +int divscale16(int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "movl %%eax, %%edx \n\t" + "sarl $16, %%edx \n\t" + "shll $16, %%eax \n\t" + "idivl %%ebx \n\t" + : "=a" (retval) : "a" (i1), "b" (i2) : "edx", "cc"); + return(retval); +} + +int divscale17(int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "movl %%eax, %%edx \n\t" + "sarl $15, %%edx \n\t" + "shll $17, %%eax \n\t" + "idivl %%ebx \n\t" + : "=a" (retval) : "a" (i1), "b" (i2) : "edx", "cc"); + return(retval); +} + +int divscale18(int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "movl %%eax, %%edx \n\t" + "sarl $14, %%edx \n\t" + "shll $18, %%eax \n\t" + "idivl %%ebx \n\t" + : "=a" (retval) : "a" (i1), "b" (i2) : "edx", "cc"); + return(retval); +} + +int divscale19(int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "movl %%eax, %%edx \n\t" + "sarl $13, %%edx \n\t" + "shll $19, %%eax \n\t" + "idivl %%ebx \n\t" + : "=a" (retval) : "a" (i1), "b" (i2) : "edx", "cc"); + return(retval); +} + +int divscale20(int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "movl %%eax, %%edx \n\t" + "sarl $12, %%edx \n\t" + "shll $20, %%eax \n\t" + "idivl %%ebx \n\t" + : "=a" (retval) : "a" (i1), "b" (i2) : "edx", "cc"); + return(retval); +} + +int divscale21(int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "movl %%eax, %%edx \n\t" + "sarl $11, %%edx \n\t" + "shll $21, %%eax \n\t" + "idivl %%ebx \n\t" + : "=a" (retval) : "a" (i1), "b" (i2) : "edx", "cc"); + return(retval); +} + +int divscale22(int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "movl %%eax, %%edx \n\t" + "sarl $10, %%edx \n\t" + "shll $22, %%eax \n\t" + "idivl %%ebx \n\t" + : "=a" (retval) : "a" (i1), "b" (i2) : "edx", "cc"); + return(retval); +} + +int divscale23(int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "movl %%eax, %%edx \n\t" + "sarl $9, %%edx \n\t" + "shll $23, %%eax \n\t" + "idivl %%ebx \n\t" + : "=a" (retval) : "a" (i1), "b" (i2) : "edx", "cc"); + return(retval); +} + +int divscale24(int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "movl %%eax, %%edx \n\t" + "sarl $8, %%edx \n\t" + "shll $24, %%eax \n\t" + "idivl %%ebx \n\t" + : "=a" (retval) : "a" (i1), "b" (i2) : "edx", "cc"); + return(retval); +} + +int divscale25(int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "movl %%eax, %%edx \n\t" + "sarl $7, %%edx \n\t" + "shll $25, %%eax \n\t" + "idivl %%ebx \n\t" + : "=a" (retval) : "a" (i1), "b" (i2) : "edx", "cc"); + return(retval); +} + +int divscale26(int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "movl %%eax, %%edx \n\t" + "sarl $6, %%edx \n\t" + "shll $26, %%eax \n\t" + "idivl %%ebx \n\t" + : "=a" (retval) : "a" (i1), "b" (i2) : "edx", "cc"); + return(retval); +} + +int divscale27(int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "movl %%eax, %%edx \n\t" + "sarl $5, %%edx \n\t" + "shll $27, %%eax \n\t" + "idivl %%ebx \n\t" + : "=a" (retval) : "a" (i1), "b" (i2) : "edx", "cc"); + return(retval); +} + +int divscale28(int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "movl %%eax, %%edx \n\t" + "sarl $4, %%edx \n\t" + "shll $28, %%eax \n\t" + "idivl %%ebx \n\t" + : "=a" (retval) : "a" (i1), "b" (i2) : "edx", "cc"); + return(retval); +} + +int divscale29(int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "movl %%eax, %%edx \n\t" + "sarl $3, %%edx \n\t" + "shll $29, %%eax \n\t" + "idivl %%ebx \n\t" + : "=a" (retval) : "a" (i1), "b" (i2) : "edx", "cc"); + return(retval); +} + +int divscale30(int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "movl %%eax, %%edx \n\t" + "sarl $2, %%edx \n\t" + "shll $30, %%eax \n\t" + "idivl %%ebx \n\t" + : "=a" (retval) : "a" (i1), "b" (i2) : "edx", "cc"); + return(retval); +} + +int divscale31(int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "movl %%eax, %%edx \n\t" + "sarl $1, %%edx \n\t" + "shll $31, %%eax \n\t" + "idivl %%ebx \n\t" + : "=a" (retval) : "a" (i1), "b" (i2) : "edx", "cc"); + return(retval); +} + +int divscale32(int i1, int i2) { + int retval = 0; + __asm__ __volatile__ ( + "xorl %%eax, %%eax \n\t" + "idivl %%ebx \n\t" + : "=a" (retval) : "d" (i1), "b" (i2): "cc"); + return(retval); +} + +int mul3 (int i1) { + int output; + __asm__ __volatile__ ( + "leal (%1, %1, 2), %1 \n\t" + : "=r" (output) : "r" (i1) : "cc"); + return (output); +} + +int mul5 (int i1) { + int output; + __asm__ __volatile__ ( + "leal (%1, %1, 4), %1 \n\t" + : "=r" (output) : "r" (i1) : "cc"); + return (output); +} + +int mul9 (int i1) { + int output; + __asm__ __volatile__ ( + "leal (%1, %1, 8), %1 \n\t" + : "=r" (output) : "r" (i1) : "cc"); + return (output); +} + +void clearbuf(void *buffer, int size, long fill_value) { + __asm__ __volatile__ ( + "rep \n\t" + "stosl \n\t" + : : "D" (buffer), "c" (size), "a" (fill_value) : "cc"); +} + +void clearbufbyte(void *buffer, int size, long fill_value) { + __asm__ __volatile__ ( + "cmpl $4, %%ecx \n\t" + "jae longcopya \n\t" + "testb $1, %%cl \n\t" + "jz preskipa \n\t" + "stosb \n\t" + "preskipa: shrl $1, %%ecx \n\t" + "rep \n\t" + "stosw \n\t" + "jmp endita \n\t" + "longcopya: testl $1, %%edi \n\t" + "jz skip1a \n\t" + "stosb \n\t" + "decl %%ecx \n\t" + "skip1a: testl $2, %%edi \n\t" + "jz skip2a \n\t" + "stosw \n\t" + "subl $2, %%ecx \n\t" + "skip2a: movl %%ecx, %%ebx \n\t" + "shrl $2, %%ecx \n\t" + "rep \n\t" + "stosl \n\t" + "testb $2, %%bl \n\t" + "jz skip3a \n\t" + "stosw \n\t" + "skip3a: testb $1, %%bl \n\t" + "jz endita \n\t" + "stosb \n\t" + "endita: \n\t" + : : "D" (buffer), "c" (size), "a" (fill_value) : "ebx", "cc"); +} + +void copybuf(void *source, void *dest, int size) { + __asm__ __volatile__ ( + "rep \n\t" + "movsl \n\t" + : : "S" (source), "D" (dest), "c" (size) : "cc"); +} + +void copybufbyte(void *source, void *dest, int size) { + __asm__ __volatile__ ( + "cmpl $4, %%ecx \n\t" + "jae longcopyb \n\t" + "testb $1, %%cl \n\t" + "jz preskipb \n\t" + "movsb \n\t" + "preskipb: shrl $1, %%ecx \n\t" + "rep \n\t" + "movsw \n\t" + "jmp enditb \n\t" + "longcopyb: testl $1, %%edi \n\t" + "jz skip1b \n\t" + "movsb \n\t" + "decl %%ecx \n\t" + "skip1b: testl $2, %%edi \n\t" + "jz skip2b \n\t" + "movsw \n\t" + "sub $2, %%ecx \n\t" + "skip2b: mov %%ecx, %%ebx \n\t" + "shr $2, %%ecx \n\t" + "rep \n\t" + "movsl \n\t" + "testb $2, %%bl \n\t" + "jz skip3b \n\t" + "movsw \n\t" + "skip3b: testb $1, %%bl \n\t" + "jz enditb \n\t" + "movsb \n\t" + "enditb: \n\t" + : : "S" (source), "D" (dest), "c" (size) : "ebx", "cc"); +} + +void copybufreverse(void *source, void *dest, int size) { + __asm__ __volatile__ ( + "shrl $1, %%ecx \n\t" + "jnc skipit1 \n\t" + "movb (%%esi), %%al \n\t" + "decl %%esi \n\t" + "movb %%al, (%%edi) \n\t" + "incl %%edi \n\t" + "skipit1: shrl $1, %%ecx \n\t" + "jnc skipit2 \n\t" + "movw -1(%%esi), %%ax \n\t" + "subl $2, %%esi \n\t" + "rorw $8, %%ax \n\t" + "movw %%ax, (%%edi) \n\t" + "addl $2, %%edi \n\t" + "skipit2: testl %%ecx, %%ecx \n\t" + "jz endloop \n\t" + "begloop: movl -3(%%esi), %%eax \n\t" + "subl $4, %%esi \n\t" + "bswapl %%eax \n\t" + "movl %%eax, (%%edi) \n\t" + "addl $4, %%edi \n\t" + "decl %%ecx \n\t" + "jnz begloop \n\t" + "endloop: \n\t" + : : "S" (source), "D" (dest), "c" (size) : "cc"); +} + +void qinterpolatedown16 (long *source, int size, int linum, int linum_inc) { + __asm__ __volatile__ ( + "movl %%ecx, %%ebx \n\t" + "shrl $1, %%ecx \n\t" + "jz skipbegcalc \n\t" + "begqcalc: leal (%%esi, %%edx), %%edi \n\t" + "sarl $16, %%edx \n\t" + "movl %%edx, (%%eax) \n\t" + "leal (%%edi, %%esi), %%edx \n\t" + "sarl $16, %%edi \n\t" + "movl %%edi, 4(%%eax) \n\t" + "addl $8, %%eax \n\t" + "decl %%ecx \n\t" + "jnz begqcalc \n\t" + "testl $1, %%ebx \n\t" + "jz skipbegqcalc2 \n\t" + "skipbegcalc: sarl $16, %%edx \n\t" + "movl %%edx, (%%eax) \n\t" + "skipbegqcalc2: \n\t" + : :"a" (source), "c" (size), "d" (linum), "S" (linum_inc) : "ebx", "edi", "cc", "memory" ); +} + +void qinterpolatedown16short (long *source, int size, int linum, int linum_inc) +{ + __asm__ __volatile__ ( + "testl %%ecx, %%ecx \n\t" + "jz endit \n\t" + "testb $2, %%al \n\t" + "jz skipalignit \n\t" + "movl %%edx, %%ebx \n\t" + "sarl $16, %%ebx \n\t" + "movw %%bx, (%%eax) \n\t" + "addl %%esi, %%edx \n\t" + "addl $2, %%eax \n\t" + "decl %%ecx \n\t" + "jz endit \n\t" + "skipalignit: subl $2, %%ecx \n\t" + "jc finishit \n\t" + "bbegqcalc: movl %%edx, %%ebx \n\t" + "addl %%esi, %%edx \n\t" + "sarl $16, %%ebx \n\t" + "movl %%edx, %%edi \n\t" + "andl $0xffff0000, %%edi \n\t" + "addl %%esi, %%edx \n\t" + "addl %%edi, %%ebx \n\t" + "movl %%ebx, (%%eax) \n\t" + "addl $4, %%eax \n\t" + "subl $2, %%ecx \n\t" + "jnc bbegqcalc \n\t" + "testb $1, %%cl \n\t" + "jz endit \n\t" + "finishit: movl %%edx, %%ebx \n\t" + "sarl $16, %%ebx \n\t" + "movw %%bx, (%%eax) \n\t" + "endit: \n\t" + : :"a" (source), "c" (size), "d" (linum), "S" (linum_inc) : "ebx", "edi", "cc", "memory"); +} + +void vlin16first (long i1, long i2) { + __asm__ __volatile__ ( + "movb (%%edi), %%al \n\t" + "movl %%ecx, %%eax \n\t" + "shrl $2, %%ecx \n\t" + " \n\t" + "begvlin16firsta: \n\t" + "movb %%al, (%%edi) \n\t" + "movb %%al, 80(%%edi) \n\t" + "movb %%al, 160(%%edi) \n\t" + "movb %%al, 240(%%edi) \n\t" + "addl $320, %%edi \n\t" + "decl %%ecx \n\t" + "jnz begvlin16firsta \n\t" + " \n\t" + "movl %%eax, %%ecx \n\t" + "andl $3, %%ecx \n\t" + "jz skipfirst \n\t" + "begvlin16firstb: \n\t" + "movb %%al, (%%edi) \n\t" + "addl $80, %%edi \n\t" + "decl %%ecx \n\t" + "jnz begvlin16firstb \n\t" + "skipfirst: \n\t" + + : : "D" (i1), "c" (i2) : "cc", "memory"); +} + +void vlin16 (long i1, long i2) { + __asm__ __volatile__ ( + "movl %%edi, %%esi \n\t" + "begvlin16: \n\t" + "movsb \n\t" + "addl $79, %%edi \n\t" + "addl $79, %%esi \n\t" + "decl %%ecx \n\t" + "jnz begvlin16 \n\t" + + : : "D" (i1), "c" (i2) : "cc", "memory"); + +} + +int klabs (int i1) { + int retval = 0; + __asm__ __volatile__ ( + "testl %%eax, %%eax \n\t" + "jns skipnegate \n\t" + "negl %%eax \n\t" + "skipnegate: \n\t" + : "=a" (retval) : "a" (i1) : "cc"); + return(retval); +} + +int ksgn(int i1) { + int retval = 0; + __asm__ __volatile__ ( + "addl %%ebx, %%ebx \n\t" + "sbbl %%eax, %%eax \n\t" + "cmpl %%ebx, %%eax \n\t" + "adcb $0, %%al \n\t" + : "=a" (retval) : "b" (i1) : "cc"); + return(retval); +} + +void swapchar(int i1, int i2) { + __asm__ __volatile__ ( + "movb (%%eax), %%cl \n\t" + "movb (%%ebx), %%ch \n\t" + "movb %%cl, (%%ebx) \n\t" + "movb %%ch, (%%eax) \n\t" + : : "a" (i1), "b" (i2) : "ecx", "cc", "memory"); +} + +void swapshort(int i1, int i2) { + __asm__ __volatile__ ( + "movw (%%eax), %%cx \n\t" + "movw (%%ebx), %%dx \n\t" + "movw %%cx, (%%ebx) \n\t" + "movw %%dx, (%%eax) \n\t" + : : "a" (i1), "b" (i2) : "ecx", "edx", "cc", "memory"); +} + + +void swaplong(int i1, int i2) { + __asm__ __volatile__ ( + "movl (%%eax), %%ecx \n\t" + "movl (%%ebx), %%edx \n\t" + "movl %%ecx, (%%ebx) \n\t" + "movl %%edx, (%%eax) \n\t" + : : "a" (i1), "b" (i2) : "ecx", "edx", "cc", "memory"); +} + + +/* +#pragma aux swapbuf4 =\ + "begswap:",\ + "mov esi, (%%eax)",\ + "mov edi, (%%ebx)",\ + "mov (%%ebx), esi",\ + "mov (%%eax), edi",\ + "add eax, 4",\ + "add ebx, 4",\ + "dec ecx",\ + "jnz short begswap",\ + parm (%%eax)(%%ebx)[ecx]\ + modify exact [eax ebx ecx esi edi]\ + +#pragma aux swap64bit =\ + "mov ecx, (%%eax)",\ + "mov edx, (%%ebx)",\ + "mov (%%ebx), ecx",\ + "mov ecx, [eax+4]",\ + "mov (%%eax), edx",\ + "mov edx, [ebx+4]",\ + "mov [ebx+4], ecx",\ + "mov [eax+4], edx",\ + parm (%%eax)(%%ebx)\ + modify exact [ecx edx]\ +*/ + + + /* + * swapchar2(ptr1,ptr2,xsiz); is the same as: + * swapchar(ptr1,ptr2); swapchar(ptr1+1,ptr2+xsiz); + */ +int swapchar2(int i1, int i2, int i3) { + int retval = 0; + __asm__ __volatile__ ( + "addl %%ebx, %%esi \n\t" + "movw (%%eax), %%cx \n\t" + "movb (%%ebx), %%dl \n\t" + "movb %%cl, (%%ebx) \n\t" + "movb (%%esi), %%dh \n\t" + "movb %%ch, (%%esi) \n\t" + "movw %%dx, (%%eax) \n\t" + : "=a" (retval) : "a" (i1), "b" (i2), "S" (i3) : "ecx", "edx", "cc", "memory"); + return(retval); +} + +/* + + //returns eax%ebx, dmval = eax/edx; +#pragma aux moddiv =\ + "xor edx, edx",\ + "div ebx",\ + "mov dmval, eax",\ + parm [eax][ebx]\ + modify exact [eax edx]\ + value [edx] + + + //eax = (unsigned min)umin(eax,ebx) +#pragma aux umin =\ + "sub eax, ebx",\ + "sbb ecx, ecx",\ + "and eax, ecx",\ + "add eax, ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax ecx]\ + + //eax = (unsigned max)umax(eax,ebx) +#pragma aux umax =\ + "sub eax, ebx",\ + "sbb ecx, ecx",\ + "xor ecx, 0xffffffff",\ + "and eax, ecx",\ + "add eax, ebx",\ + parm nomemory [eax][ebx]\ + modify exact [eax ecx]\ + +#pragma aux kmin =\ + "cmp eax, ebx",\ + "jl skipit",\ + "mov eax, ebx",\ + "skipit:",\ + parm nomemory [eax][ebx]\ + modify exact [eax]\ + +#pragma aux kmax =\ + "cmp eax, ebx",\ + "jg skipit",\ + "mov eax, ebx",\ + "skipit:",\ + parm nomemory [eax][ebx]\ + modify exact [eax]\ + +#pragma aux readtimer =\ + "mov al, 0xd2",\ + "out 0x43, al",\ + "in al, 0x40",\ + "shl eax, 24",\ + "in al, 0x40",\ + "rol eax, 8",\ + modify [eax]\ + +#pragma aux redblueblit = \ + "xor ecx, ecx",\ + "begblit: mov eax, dword ptr [edx+ecx]",\ + "shl eax, 4",\ + "add eax, dword ptr [ebx+ecx]",\ + "mov dword ptr [ecx+0xa0000], eax",\ + "add ecx, 4",\ + "cmp ecx, esi",\ + "jb begblit",\ + parm [ebx][edx][esi]\ + modify exact [eax ecx]\ + +#pragma aux chainblit =\ + "shr ecx, 1",\ + "jnc prebeg",\ + "mov al, byte ptr [esi+8]",\ + "mov ah, byte ptr [esi+12]",\ + "shl eax, 16",\ + "mov al, byte ptr [esi]",\ + "mov ah, byte ptr [esi+4]",\ + "mov dword ptr [edi], eax",\ + "add esi, 16",\ + "add edi, 4",\ + "test ecx, ecx",\ + "prebeg: jz endit",\ + "beg: mov al, byte ptr [esi+8]",\ + "mov bl, byte ptr [esi+24]",\ + "mov ah, byte ptr [esi+12]",\ + "mov bh, byte ptr [esi+28]",\ + "shl eax, 16",\ + "add edi, 8",\ + "shl ebx, 16",\ + "mov al, byte ptr [esi]",\ + "mov bl, byte ptr [esi+16]",\ + "mov ah, byte ptr [esi+4]",\ + "mov bh, byte ptr [esi+20]",\ + "add esi, 32",\ + "mov dword ptr [edi-8], eax",\ + "dec ecx",\ + "mov dword ptr [edi-4], ebx",\ + "jnz beg",\ + "endit:",\ + parm [esi][edi][ecx]\ + modify exact [eax ebx ecx esi edi]\ + +static long timeroffs1mhz; + //accutimeroffs = -8-(t1-t0); +#pragma aux inittimer1mhz =\ + "xor ebx, ebx",\ + "xor ecx, ecx",\ + "in al, 0x61",\ + "or al, 1",\ + "out 0x61, al",\ + "mov al, 0x34",\ + "out 0x43, al",\ + "xor al, al",\ + "out 0x40, al",\ + "mov al, 0xb4",\ + "out 0x43, al",\ + "mov al, 240",\ + "out 0x42, al",\ + "xor al, al",\ + "cli",\ + "out 0x40, al",\ + "dec al",\ + "out 0x42, al",\ + "mov al, 0x04",\ + "out 0x43, al",\ + "in al, 0x40",\ + "mov bl, al",\ + "in al, 0x40",\ + "mov bh, al",\ + "mov al, 0x84",\ + "out 0x43, al",\ + "in al, 0x42",\ + "mov cl, al",\ + "in al, 0x42",\ + "sti",\ + "mov ch, al",\ + "sub ebx, ecx",\ + "sub ebx, 8",\ + "mov timeroffs1mhz, ebx",\ + modify exact [eax ebx ecx]\ + +#pragma aux uninittimer1mhz =\ + "in al, 0x61",\ + "and al, 252",\ + "out 0x61, al",\ + modify exact [eax]\ + + //t = ((ecx-ebx+timeroffs1mhz)&0xfff0)*4095 + ecx; +#pragma aux gettime1mhz =\ + "mov ebx, timeroffs1mhz",\ + "xor ecx, ecx",\ + "mov al, 0x04",\ + "cli",\ + "out 0x43, al",\ + "in al, 0x40",\ + "sub bl, al",\ + "in al, 0x40",\ + "sbb bh, al",\ + "mov al, 0x84",\ + "out 0x43, al",\ + "in al, 0x42",\ + "mov cl, al",\ + "in al, 0x42",\ + "sti",\ + "mov ch, al",\ + "add ebx, ecx",\ + "and ebx, 0x0000fff0",\ + "sub ecx, ebx",\ + "shl ebx, 12",\ + "add ebx, ecx",\ + modify exact [eax ebx ecx]\ + value [ebx]\ + + //eax = eax-ebx; if (eax < 0) eax += (1<<28) - (1<<16); +#pragma aux deltatime1mhz =\ + "sub eax, ebx",\ + "jnc skipit",\ + "add eax, 0x0fff0000",\ + "skipit:",\ + parm [ebx][eax]\ + +*/ + +#else + +/* + * !!! out of respect to Ken, the ASM version needs to be converted to + * portable C, so we can legitimately check this on all platforms. + */ +unsigned long getkensmessagecrc(long param) +{ + return(0x56c764d4); +} /* getkensmessagecrc */ + +void swapchar(unsigned char *p1, unsigned char *p2) +{ + unsigned char tmp = *p1; + *p1 = *p2; + *p2 = tmp; +} /* swapchar */ + +void swapshort(short *p1, short *p2) +{ + short tmp = *p1; + *p1 = *p2; + *p2 = tmp; +} /* swapshort */ + +void swaplong(long *p1, long *p2) +{ + long tmp = *p1; + *p1 = *p2; + *p2 = tmp; +} /* swaplong */ + +void swapchar2(unsigned char *p1, unsigned char *p2, int xsiz) +{ + swapchar(p1, p2); + swapchar(p1 + 1, p2 + xsiz); +} /* swapchar2 */ + +#endif + +/* end of pragmas_gnu.c ... */ + diff --git a/buildengine/pragmas_visualc.c b/buildengine/pragmas_visualc.c new file mode 100755 index 0000000..60d3dba --- /dev/null +++ b/buildengine/pragmas_visualc.c @@ -0,0 +1,3064 @@ +/* + * "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman + * Ken Silverman's official web site: "http://www.advsys.net/ken" + * See the included license file "BUILDLIC.TXT" for license info. + * This file IS NOT A PART OF Ken Silverman's original release. + */ + +#ifndef __PRAGMAS_VISUALC_H__ +#define __PRAGMAS_VISUALC_H__ + +#if (!defined _MSC_VER) +#error This should only be included on Microsoft Visual C compiles. +#else + +/* +This was converted from pragmas.h with the following Perl script and + a bunch of manually editing: + +#!/usr/bin/perl -w + +use strict; + +my $in_block = 0; + +while () { + chomp; + 1 while (s/[ \t]\Z//); # trim ending whitespace. + + if (s/\);\Z/)/) { + print "$_\n{\n __asm\n {\n"; + } + + elsif (/\#pragma aux/) { + $in_block = 1; + } + + elsif ($_ eq "") { + if ($in_block) { + print " }\n}\n\n"; + $in_block = 0; + } else { + print "\n"; + } + } + + else { + if ($in_block) { + 1 while (s/\A[ \t]//); + s/\",\\//; + s/\"//; + print " "; + } + print "$_\n"; + } +} +*/ + + +static long dmval = 0; + +long is_vmware_running(void); + + +unsigned long getkensmessagecrc(long param) +{ + __asm + { + mov ebx, param + xor eax, eax + mov ecx, 32 + beg: mov edx, dword ptr [ebx+ecx*4-4] + ror edx, cl + adc eax, edx + bswap eax + loop short beg + mov param, eax + } /* asm */ + return(param); +} + +long msqrtasm(int param) +{ + __asm + { + mov ecx, param + mov eax, 0x40000000 + mov ebx, 0x20000000 + begit: cmp ecx, eax + jl skip + sub ecx, eax + lea eax, [eax+ebx*4] + skip: sub eax, ebx + shr eax, 1 + shr ebx, 2 + jnz begit + cmp ecx, eax + sbb eax, -1 + shr eax, 1 + mov param, eax + } /* asm */ + return(param); +} + +int sqr(int i1) +{ + __asm + { + mov eax, i1 + imul eax, eax + mov i1, eax + } /* asm */ + return(i1); +} + +long scale(long i1, long i2, long i3) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov ecx, i3 + imul edx + idiv ecx + mov i1, eax + } /* asm */ + return(i1); +} + +long mulscale(long i1, long i2, long i3) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov ecx, i3 + imul edx + shrd eax, edx, cl + mov i1, eax + } /* asm */ + return(i1); +} + +long mulscale1(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov edx, i2 + imul edx + shrd eax, edx, 1 + mov i1, eax + } /* asm */ + return(i1); +} + +long mulscale2(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov edx, i2 + imul edx + shrd eax, edx, 2 + mov i1, eax + } /* asm */ + return(i1); +} + +long mulscale3(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov edx, i2 + imul edx + shrd eax, edx, 3 + mov i1, eax + } /* asm */ + return(i1); +} + +long mulscale4(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov edx, i2 + imul edx + shrd eax, edx, 4 + mov i1, eax + } /* asm */ + return(i1); +} + +long mulscale5(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov edx, i2 + imul edx + shrd eax, edx, 5 + mov i1, eax + } /* asm */ + return(i1); +} + +long mulscale6(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov edx, i2 + imul edx + shrd eax, edx, 6 + mov i1, eax + } /* asm */ + return(i1); +} + +long mulscale7(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov edx, i2 + imul edx + shrd eax, edx, 7 + mov i1, eax + } /* asm */ + return(i1); +} + +long mulscale8(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov edx, i2 + imul edx + shrd eax, edx, 8 + mov i1, eax + } /* asm */ + return(i1); +} + +long mulscale9(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov edx, i2 + imul edx + shrd eax, edx, 9 + mov i1, eax + } /* asm */ + return(i1); +} + +long mulscale10(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov edx, i2 + imul edx + shrd eax, edx, 10 + mov i1, eax + } /* asm */ + return(i1); +} + +long mulscale11(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov edx, i2 + imul edx + shrd eax, edx, 11 + mov i1, eax + } /* asm */ + return(i1); +} + +long mulscale12(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov edx, i2 + imul edx + shrd eax, edx, 12 + mov i1, eax + } /* asm */ + return(i1); +} + +long mulscale13(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov edx, i2 + imul edx + shrd eax, edx, 13 + mov i1, eax + } /* asm */ + return(i1); +} + +long mulscale14(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov edx, i2 + imul edx + shrd eax, edx, 14 + mov i1, eax + } /* asm */ + return(i1); +} + +long mulscale15(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov edx, i2 + imul edx + shrd eax, edx, 15 + mov i1, eax + } /* asm */ + return(i1); +} + +long mulscale16(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov edx, i2 + imul edx + shrd eax, edx, 16 + mov i1, eax + } /* asm */ + return(i1); +} + +long mulscale17(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov edx, i2 + imul edx + shrd eax, edx, 17 + mov i1, eax + } /* asm */ + return(i1); +} + +long mulscale18(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov edx, i2 + imul edx + shrd eax, edx, 18 + mov i1, eax + } /* asm */ + return(i1); +} + +long mulscale19(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov edx, i2 + imul edx + shrd eax, edx, 19 + mov i1, eax + } /* asm */ + return(i1); +} + +long mulscale20(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov edx, i2 + imul edx + shrd eax, edx, 20 + mov i1, eax + } /* asm */ + return(i1); +} + +long mulscale21(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov edx, i2 + imul edx + shrd eax, edx, 21 + mov i1, eax + } /* asm */ + return(i1); +} + +long mulscale22(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov edx, i2 + imul edx + shrd eax, edx, 22 + mov i1, eax + } /* asm */ + return(i1); +} + +long mulscale23(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov edx, i2 + imul edx + shrd eax, edx, 23 + mov i1, eax + } /* asm */ + return(i1); +} + +long mulscale24(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov edx, i2 + imul edx + shrd eax, edx, 24 + mov i1, eax + } /* asm */ + return(i1); +} + +long mulscale25(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov edx, i2 + imul edx + shrd eax, edx, 25 + mov i1, eax + } /* asm */ + return(i1); +} + +long mulscale26(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov edx, i2 + imul edx + shrd eax, edx, 26 + mov i1, eax + } /* asm */ + return(i1); +} + +long mulscale27(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov edx, i2 + imul edx + shrd eax, edx, 27 + mov i1, eax + } /* asm */ + return(i1); +} + +long mulscale28(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov edx, i2 + imul edx + shrd eax, edx, 28 + mov i1, eax + } /* asm */ + return(i1); +} + +long mulscale29(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov edx, i2 + imul edx + shrd eax, edx, 29 + mov i1, eax + } /* asm */ + return(i1); +} + +long mulscale30(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov edx, i2 + imul edx + shrd eax, edx, 30 + mov i1, eax + } /* asm */ + return(i1); +} + +long mulscale31(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov edx, i2 + imul edx + shrd eax, edx, 31 + mov i1, eax + } /* asm */ + return(i1); +} + +long mulscale32(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov edx, i2 + imul edx + mov i1, edx + } /* asm */ + return(i1); +} + +long dmulscale(long i1, long i2, long i3, long i4, long i5) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov esi, i3 + mov edi, i4 + mov ecx, i5 + imul edx + mov ebx, eax + mov eax, esi + mov esi, edx + imul edi + add eax, ebx + adc edx, esi + shrd eax, edx, cl + mov i1, eax + } /* asm */ + return(i1); +} + +long dmulscale1(long i1, long i2, long i3, long i4) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov esi, i3 + mov edi, i4 + imul edx + mov ebx, eax + mov eax, esi + mov esi, edx + imul edi + add eax, ebx + adc edx, esi + shrd eax, edx, 1 + mov i1, eax + } /* asm */ + return(i1); +} + +long dmulscale2(long i1, long i2, long i3, long i4) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov esi, i3 + mov edi, i4 + imul edx + mov ebx, eax + mov eax, esi + mov esi, edx + imul edi + add eax, ebx + adc edx, esi + shrd eax, edx, 2 + mov i1, eax + } /* asm */ + return(i1); +} + +long dmulscale3(long i1, long i2, long i3, long i4) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov esi, i3 + mov edi, i4 + imul edx + mov ebx, eax + mov eax, esi + mov esi, edx + imul edi + add eax, ebx + adc edx, esi + shrd eax, edx, 3 + mov i1, eax + } /* asm */ + return(i1); +} + +long dmulscale4(long i1, long i2, long i3, long i4) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov esi, i3 + mov edi, i4 + imul edx + mov ebx, eax + mov eax, esi + mov esi, edx + imul edi + add eax, ebx + adc edx, esi + shrd eax, edx, 4 + mov i1, eax + } /* asm */ + return(i1); +} + +long dmulscale5(long i1, long i2, long i3, long i4) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov esi, i3 + mov edi, i4 + imul edx + mov ebx, eax + mov eax, esi + mov esi, edx + imul edi + add eax, ebx + adc edx, esi + shrd eax, edx, 5 + mov i1, eax + } /* asm */ + return(i1); +} + +long dmulscale6(long i1, long i2, long i3, long i4) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov esi, i3 + mov edi, i4 + imul edx + mov ebx, eax + mov eax, esi + mov esi, edx + imul edi + add eax, ebx + adc edx, esi + shrd eax, edx, 6 + mov i1, eax + } /* asm */ + return(i1); +} + +long dmulscale7(long i1, long i2, long i3, long i4) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov esi, i3 + mov edi, i4 + imul edx + mov ebx, eax + mov eax, esi + mov esi, edx + imul edi + add eax, ebx + adc edx, esi + shrd eax, edx, 7 + mov i1, eax + } /* asm */ + return(i1); +} + +long dmulscale8(long i1, long i2, long i3, long i4) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov esi, i3 + mov edi, i4 + imul edx + mov ebx, eax + mov eax, esi + mov esi, edx + imul edi + add eax, ebx + adc edx, esi + shrd eax, edx, 8 + mov i1, eax + } /* asm */ + return(i1); +} + +long dmulscale9(long i1, long i2, long i3, long i4) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov esi, i3 + mov edi, i4 + imul edx + mov ebx, eax + mov eax, esi + mov esi, edx + imul edi + add eax, ebx + adc edx, esi + shrd eax, edx, 9 + mov i1, eax + } /* asm */ + return(i1); +} + +long dmulscale10(long i1, long i2, long i3, long i4) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov esi, i3 + mov edi, i4 + imul edx + mov ebx, eax + mov eax, esi + mov esi, edx + imul edi + add eax, ebx + adc edx, esi + shrd eax, edx, 10 + mov i1, eax + } /* asm */ + return(i1); +} + +long dmulscale11(long i1, long i2, long i3, long i4) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov esi, i3 + mov edi, i4 + imul edx + mov ebx, eax + mov eax, esi + mov esi, edx + imul edi + add eax, ebx + adc edx, esi + shrd eax, edx, 11 + mov i1, eax + } /* asm */ + return(i1); +} + +long dmulscale12(long i1, long i2, long i3, long i4) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov esi, i3 + mov edi, i4 + imul edx + mov ebx, eax + mov eax, esi + mov esi, edx + imul edi + add eax, ebx + adc edx, esi + shrd eax, edx, 12 + mov i1, eax + } /* asm */ + return(i1); +} + +long dmulscale13(long i1, long i2, long i3, long i4) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov esi, i3 + mov edi, i4 + imul edx + mov ebx, eax + mov eax, esi + mov esi, edx + imul edi + add eax, ebx + adc edx, esi + shrd eax, edx, 13 + mov i1, eax + } /* asm */ + return(i1); +} + +long dmulscale14(long i1, long i2, long i3, long i4) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov esi, i3 + mov edi, i4 + imul edx + mov ebx, eax + mov eax, esi + mov esi, edx + imul edi + add eax, ebx + adc edx, esi + shrd eax, edx, 14 + mov i1, eax + } /* asm */ + return(i1); +} + +long dmulscale15(long i1, long i2, long i3, long i4) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov esi, i3 + mov edi, i4 + imul edx + mov ebx, eax + mov eax, esi + mov esi, edx + imul edi + add eax, ebx + adc edx, esi + shrd eax, edx, 15 + mov i1, eax + } /* asm */ + return(i1); +} + +long dmulscale16(long i1, long i2, long i3, long i4) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov esi, i3 + mov edi, i4 + imul edx + mov ebx, eax + mov eax, esi + mov esi, edx + imul edi + add eax, ebx + adc edx, esi + shrd eax, edx, 16 + mov i1, eax + } /* asm */ + return(i1); +} + +long dmulscale17(long i1, long i2, long i3, long i4) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov esi, i3 + mov edi, i4 + imul edx + mov ebx, eax + mov eax, esi + mov esi, edx + imul edi + add eax, ebx + adc edx, esi + shrd eax, edx, 17 + mov i1, eax + } /* asm */ + return(i1); +} + +long dmulscale18(long i1, long i2, long i3, long i4) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov esi, i3 + mov edi, i4 + imul edx + mov ebx, eax + mov eax, esi + mov esi, edx + imul edi + add eax, ebx + adc edx, esi + shrd eax, edx, 18 + mov i1, eax + } /* asm */ + return(i1); +} + +long dmulscale19(long i1, long i2, long i3, long i4) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov esi, i3 + mov edi, i4 + imul edx + mov ebx, eax + mov eax, esi + mov esi, edx + imul edi + add eax, ebx + adc edx, esi + shrd eax, edx, 19 + mov i1, eax + } /* asm */ + return(i1); +} + +long dmulscale20(long i1, long i2, long i3, long i4) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov esi, i3 + mov edi, i4 + imul edx + mov ebx, eax + mov eax, esi + mov esi, edx + imul edi + add eax, ebx + adc edx, esi + shrd eax, edx, 20 + mov i1, eax + } /* asm */ + return(i1); +} + +long dmulscale21(long i1, long i2, long i3, long i4) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov esi, i3 + mov edi, i4 + imul edx + mov ebx, eax + mov eax, esi + mov esi, edx + imul edi + add eax, ebx + adc edx, esi + shrd eax, edx, 21 + mov i1, eax + } /* asm */ + return(i1); +} + +long dmulscale22(long i1, long i2, long i3, long i4) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov esi, i3 + mov edi, i4 + imul edx + mov ebx, eax + mov eax, esi + mov esi, edx + imul edi + add eax, ebx + adc edx, esi + shrd eax, edx, 22 + mov i1, eax + } /* asm */ + return(i1); +} + +long dmulscale23(long i1, long i2, long i3, long i4) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov esi, i3 + mov edi, i4 + imul edx + mov ebx, eax + mov eax, esi + mov esi, edx + imul edi + add eax, ebx + adc edx, esi + shrd eax, edx, 23 + mov i1, eax + } /* asm */ + return(i1); +} + +long dmulscale24(long i1, long i2, long i3, long i4) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov esi, i3 + mov edi, i4 + imul edx + mov ebx, eax + mov eax, esi + mov esi, edx + imul edi + add eax, ebx + adc edx, esi + shrd eax, edx, 24 + mov i1, eax + } /* asm */ + return(i1); +} + +long dmulscale25(long i1, long i2, long i3, long i4) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov esi, i3 + mov edi, i4 + imul edx + mov ebx, eax + mov eax, esi + mov esi, edx + imul edi + add eax, ebx + adc edx, esi + shrd eax, edx, 25 + mov i1, eax + } /* asm */ + return(i1); +} + +long dmulscale26(long i1, long i2, long i3, long i4) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov esi, i3 + mov edi, i4 + imul edx + mov ebx, eax + mov eax, esi + mov esi, edx + imul edi + add eax, ebx + adc edx, esi + shrd eax, edx, 26 + mov i1, eax + } /* asm */ + return(i1); +} + +long dmulscale27(long i1, long i2, long i3, long i4) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov esi, i3 + mov edi, i4 + imul edx + mov ebx, eax + mov eax, esi + mov esi, edx + imul edi + add eax, ebx + adc edx, esi + shrd eax, edx, 27 + mov i1, eax + } /* asm */ + return(i1); +} + +long dmulscale28(long i1, long i2, long i3, long i4) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov esi, i3 + mov edi, i4 + imul edx + mov ebx, eax + mov eax, esi + mov esi, edx + imul edi + add eax, ebx + adc edx, esi + shrd eax, edx, 28 + mov i1, eax + } /* asm */ + return(i1); +} + +long dmulscale29(long i1, long i2, long i3, long i4) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov esi, i3 + mov edi, i4 + imul edx + mov ebx, eax + mov eax, esi + mov esi, edx + imul edi + add eax, ebx + adc edx, esi + shrd eax, edx, 29 + mov i1, eax + } /* asm */ + return(i1); +} + +long dmulscale30(long i1, long i2, long i3, long i4) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov esi, i3 + mov edi, i4 + imul edx + mov ebx, eax + mov eax, esi + mov esi, edx + imul edi + add eax, ebx + adc edx, esi + shrd eax, edx, 30 + mov i1, eax + } /* asm */ + return(i1); +} + +long dmulscale31(long i1, long i2, long i3, long i4) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov esi, i3 + mov edi, i4 + imul edx + mov ebx, eax + mov eax, esi + mov esi, edx + imul edi + add eax, ebx + adc edx, esi + shrd eax, edx, 31 + mov i1, eax + } /* asm */ + return(i1); +} + +long dmulscale32(long i1, long i2, long i3, long i4) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov esi, i3 + mov edi, i4 + imul edx + mov ebx, eax + mov eax, esi + mov esi, edx + imul edi + add eax, ebx + adc edx, esi + mov i1, edx + } /* asm */ + return(i1); +} + +long tmulscale1(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov ebx, i3 + mov ecx, i4 + mov esi, i5 + mov edi, i6 + imul edx + xchg eax, ebx + xchg edx, ecx + imul edx + add ebx, eax + adc ecx, edx + mov eax, esi + imul edi + add eax, ebx + adc edx, ecx + shrd eax, edx, 1 + mov i1, eax + } /* asm */ + return(i1); +} + +long tmulscale2(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov ebx, i3 + mov ecx, i4 + mov esi, i5 + mov edi, i6 + imul edx + xchg eax, ebx + xchg edx, ecx + imul edx + add ebx, eax + adc ecx, edx + mov eax, esi + imul edi + add eax, ebx + adc edx, ecx + shrd eax, edx, 2 + mov i1, eax + } /* asm */ + return(i1); +} + +long tmulscale3(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov ebx, i3 + mov ecx, i4 + mov esi, i5 + mov edi, i6 + imul edx + xchg eax, ebx + xchg edx, ecx + imul edx + add ebx, eax + adc ecx, edx + mov eax, esi + imul edi + add eax, ebx + adc edx, ecx + shrd eax, edx, 3 + mov i1, eax + } /* asm */ + return(i1); +} + +long tmulscale4(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov ebx, i3 + mov ecx, i4 + mov esi, i5 + mov edi, i6 + imul edx + xchg eax, ebx + xchg edx, ecx + imul edx + add ebx, eax + adc ecx, edx + mov eax, esi + imul edi + add eax, ebx + adc edx, ecx + shrd eax, edx, 4 + mov i1, eax + } /* asm */ + return(i1); +} + +long tmulscale5(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov ebx, i3 + mov ecx, i4 + mov esi, i5 + mov edi, i6 + imul edx + xchg eax, ebx + xchg edx, ecx + imul edx + add ebx, eax + adc ecx, edx + mov eax, esi + imul edi + add eax, ebx + adc edx, ecx + shrd eax, edx, 5 + mov i1, eax + } /* asm */ + return(i1); +} + +long tmulscale6(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov ebx, i3 + mov ecx, i4 + mov esi, i5 + mov edi, i6 + imul edx + xchg eax, ebx + xchg edx, ecx + imul edx + add ebx, eax + adc ecx, edx + mov eax, esi + imul edi + add eax, ebx + adc edx, ecx + shrd eax, edx, 6 + mov i1, eax + } /* asm */ + return(i1); +} + +long tmulscale7(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov ebx, i3 + mov ecx, i4 + mov esi, i5 + mov edi, i6 + imul edx + xchg eax, ebx + xchg edx, ecx + imul edx + add ebx, eax + adc ecx, edx + mov eax, esi + imul edi + add eax, ebx + adc edx, ecx + shrd eax, edx, 7 + mov i1, eax + } /* asm */ + return(i1); +} + +long tmulscale8(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov ebx, i3 + mov ecx, i4 + mov esi, i5 + mov edi, i6 + imul edx + xchg eax, ebx + xchg edx, ecx + imul edx + add ebx, eax + adc ecx, edx + mov eax, esi + imul edi + add eax, ebx + adc edx, ecx + shrd eax, edx, 8 + mov i1, eax + } /* asm */ + return(i1); +} + +long tmulscale9(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov ebx, i3 + mov ecx, i4 + mov esi, i5 + mov edi, i6 + imul edx + xchg eax, ebx + xchg edx, ecx + imul edx + add ebx, eax + adc ecx, edx + mov eax, esi + imul edi + add eax, ebx + adc edx, ecx + shrd eax, edx, 9 + mov i1, eax + } /* asm */ + return(i1); +} + +long tmulscale10(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov ebx, i3 + mov ecx, i4 + mov esi, i5 + mov edi, i6 + imul edx + xchg eax, ebx + xchg edx, ecx + imul edx + add ebx, eax + adc ecx, edx + mov eax, esi + imul edi + add eax, ebx + adc edx, ecx + shrd eax, edx, 10 + mov i1, eax + } /* asm */ + return(i1); +} + +long tmulscale11(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov ebx, i3 + mov ecx, i4 + mov esi, i5 + mov edi, i6 + imul edx + xchg eax, ebx + xchg edx, ecx + imul edx + add ebx, eax + adc ecx, edx + mov eax, esi + imul edi + add eax, ebx + adc edx, ecx + shrd eax, edx, 11 + mov i1, eax + } /* asm */ + return(i1); +} + +long tmulscale12(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov ebx, i3 + mov ecx, i4 + mov esi, i5 + mov edi, i6 + imul edx + xchg eax, ebx + xchg edx, ecx + imul edx + add ebx, eax + adc ecx, edx + mov eax, esi + imul edi + add eax, ebx + adc edx, ecx + shrd eax, edx, 12 + mov i1, eax + } /* asm */ + return(i1); +} + +long tmulscale13(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov ebx, i3 + mov ecx, i4 + mov esi, i5 + mov edi, i6 + imul edx + xchg eax, ebx + xchg edx, ecx + imul edx + add ebx, eax + adc ecx, edx + mov eax, esi + imul edi + add eax, ebx + adc edx, ecx + shrd eax, edx, 13 + mov i1, eax + } /* asm */ + return(i1); +} + +long tmulscale14(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov ebx, i3 + mov ecx, i4 + mov esi, i5 + mov edi, i6 + imul edx + xchg eax, ebx + xchg edx, ecx + imul edx + add ebx, eax + adc ecx, edx + mov eax, esi + imul edi + add eax, ebx + adc edx, ecx + shrd eax, edx, 14 + mov i1, eax + } /* asm */ + return(i1); +} + +long tmulscale15(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov ebx, i3 + mov ecx, i4 + mov esi, i5 + mov edi, i6 + imul edx + xchg eax, ebx + xchg edx, ecx + imul edx + add ebx, eax + adc ecx, edx + mov eax, esi + imul edi + add eax, ebx + adc edx, ecx + shrd eax, edx, 15 + mov i1, eax + } /* asm */ + return(i1); +} + +long tmulscale16(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov ebx, i3 + mov ecx, i4 + mov esi, i5 + mov edi, i6 + imul edx + xchg eax, ebx + xchg edx, ecx + imul edx + add ebx, eax + adc ecx, edx + mov eax, esi + imul edi + add eax, ebx + adc edx, ecx + shrd eax, edx, 16 + mov i1, eax + } /* asm */ + return(i1); +} + +long tmulscale17(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov ebx, i3 + mov ecx, i4 + mov esi, i5 + mov edi, i6 + imul edx + xchg eax, ebx + xchg edx, ecx + imul edx + add ebx, eax + adc ecx, edx + mov eax, esi + imul edi + add eax, ebx + adc edx, ecx + shrd eax, edx, 17 + mov i1, eax + } /* asm */ + return(i1); +} + +long tmulscale18(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov ebx, i3 + mov ecx, i4 + mov esi, i5 + mov edi, i6 + imul edx + xchg eax, ebx + xchg edx, ecx + imul edx + add ebx, eax + adc ecx, edx + mov eax, esi + imul edi + add eax, ebx + adc edx, ecx + shrd eax, edx, 18 + mov i1, eax + } /* asm */ + return(i1); +} + +long tmulscale19(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov ebx, i3 + mov ecx, i4 + mov esi, i5 + mov edi, i6 + imul edx + xchg eax, ebx + xchg edx, ecx + imul edx + add ebx, eax + adc ecx, edx + mov eax, esi + imul edi + add eax, ebx + adc edx, ecx + shrd eax, edx, 19 + mov i1, eax + } /* asm */ + return(i1); +} + +long tmulscale20(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov ebx, i3 + mov ecx, i4 + mov esi, i5 + mov edi, i6 + imul edx + xchg eax, ebx + xchg edx, ecx + imul edx + add ebx, eax + adc ecx, edx + mov eax, esi + imul edi + add eax, ebx + adc edx, ecx + shrd eax, edx, 20 + mov i1, eax + } /* asm */ + return(i1); +} + +long tmulscale21(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov ebx, i3 + mov ecx, i4 + mov esi, i5 + mov edi, i6 + imul edx + xchg eax, ebx + xchg edx, ecx + imul edx + add ebx, eax + adc ecx, edx + mov eax, esi + imul edi + add eax, ebx + adc edx, ecx + shrd eax, edx, 21 + mov i1, eax + } /* asm */ + return(i1); +} + +long tmulscale22(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov ebx, i3 + mov ecx, i4 + mov esi, i5 + mov edi, i6 + imul edx + xchg eax, ebx + xchg edx, ecx + imul edx + add ebx, eax + adc ecx, edx + mov eax, esi + imul edi + add eax, ebx + adc edx, ecx + shrd eax, edx, 22 + mov i1, eax + } /* asm */ + return(i1); +} + +long tmulscale23(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov ebx, i3 + mov ecx, i4 + mov esi, i5 + mov edi, i6 + imul edx + xchg eax, ebx + xchg edx, ecx + imul edx + add ebx, eax + adc ecx, edx + mov eax, esi + imul edi + add eax, ebx + adc edx, ecx + shrd eax, edx, 23 + mov i1, eax + } /* asm */ + return(i1); +} + +long tmulscale24(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov ebx, i3 + mov ecx, i4 + mov esi, i5 + mov edi, i6 + imul edx + xchg eax, ebx + xchg edx, ecx + imul edx + add ebx, eax + adc ecx, edx + mov eax, esi + imul edi + add eax, ebx + adc edx, ecx + shrd eax, edx, 24 + mov i1, eax + } /* asm */ + return(i1); +} + +long tmulscale25(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov ebx, i3 + mov ecx, i4 + mov esi, i5 + mov edi, i6 + imul edx + xchg eax, ebx + xchg edx, ecx + imul edx + add ebx, eax + adc ecx, edx + mov eax, esi + imul edi + add eax, ebx + adc edx, ecx + shrd eax, edx, 25 + mov i1, eax + } /* asm */ + return(i1); +} + +long tmulscale26(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov ebx, i3 + mov ecx, i4 + mov esi, i5 + mov edi, i6 + imul edx + xchg eax, ebx + xchg edx, ecx + imul edx + add ebx, eax + adc ecx, edx + mov eax, esi + imul edi + add eax, ebx + adc edx, ecx + shrd eax, edx, 26 + mov i1, eax + } /* asm */ + return(i1); +} + +long tmulscale27(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov ebx, i3 + mov ecx, i4 + mov esi, i5 + mov edi, i6 + imul edx + xchg eax, ebx + xchg edx, ecx + imul edx + add ebx, eax + adc ecx, edx + mov eax, esi + imul edi + add eax, ebx + adc edx, ecx + shrd eax, edx, 27 + mov i1, eax + } /* asm */ + return(i1); +} + +long tmulscale28(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov ebx, i3 + mov ecx, i4 + mov esi, i5 + mov edi, i6 + imul edx + xchg eax, ebx + xchg edx, ecx + imul edx + add ebx, eax + adc ecx, edx + mov eax, esi + imul edi + add eax, ebx + adc edx, ecx + shrd eax, edx, 28 + mov i1, eax + } /* asm */ + return(i1); +} + +long tmulscale29(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov ebx, i3 + mov ecx, i4 + mov esi, i5 + mov edi, i6 + imul edx + xchg eax, ebx + xchg edx, ecx + imul edx + add ebx, eax + adc ecx, edx + mov eax, esi + imul edi + add eax, ebx + adc edx, ecx + shrd eax, edx, 29 + mov i1, eax + } /* asm */ + return(i1); +} + +long tmulscale30(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov ebx, i3 + mov ecx, i4 + mov esi, i5 + mov edi, i6 + imul edx + xchg eax, ebx + xchg edx, ecx + imul edx + add ebx, eax + adc ecx, edx + mov eax, esi + imul edi + add eax, ebx + adc edx, ecx + shrd eax, edx, 30 + mov i1, eax + } /* asm */ + return(i1); +} + +long tmulscale31(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov ebx, i3 + mov ecx, i4 + mov esi, i5 + mov edi, i6 + imul edx + xchg eax, ebx + xchg edx, ecx + imul edx + add ebx, eax + adc ecx, edx + mov eax, esi + imul edi + add eax, ebx + adc edx, ecx + shrd eax, edx, 31 + mov i1, eax + } /* asm */ + return(i1); +} + +long tmulscale32(long i1, long i2, long i3, long i4, long i5, long i6) +{ + __asm + { + mov eax, i1 + mov edx, i2 + mov ebx, i3 + mov ecx, i4 + mov esi, i5 + mov edi, i6 + imul edx + xchg eax, ebx + xchg edx, ecx + imul edx + add ebx, eax + adc ecx, edx + mov eax, esi + imul edi + add eax, ebx + adc edx, ecx + mov i1, edx + } /* asm */ + return(i1); +} + +long boundmulscale(long i1, long i2, long i3) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov ecx, i3 + imul ebx + mov ebx, edx + shrd eax, edx, cl + sar edx, cl + xor edx, eax + js checkit + xor edx, eax + jz skipboundit + cmp edx, 0xffffffff + je skipboundit + checkit: + mov eax, ebx + sar eax, 31 + xor eax, 0x7fffffff + skipboundit: + mov i1, eax + } /* asm */ + return(i1); +} + +long divscale(long i1, long i2, long i3) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov ecx, i3 + mov edx, eax + shl eax, cl + neg cl + sar edx, cl + idiv ebx + mov i1, eax + } /* asm */ + return(i1); +} + +long divscale1(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + add eax, eax + sbb edx, edx + idiv ebx + mov i1, eax + } /* asm */ + return(i1); +} + +long divscale2(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov edx, eax + sar edx, 30 + lea eax, [eax*4] + idiv ebx + mov i1, eax + } /* asm */ + return(i1); +} + +long divscale3(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov edx, eax + sar edx, 29 + lea eax, [eax*8] + idiv ebx + mov i1, eax + } /* asm */ + return(i1); +} + +long divscale4(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov edx, eax + sar edx, 28 + shl eax, 4 + idiv ebx + mov i1, eax + } /* asm */ + return(i1); +} + +long divscale5(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov edx, eax + sar edx, 27 + shl eax, 5 + idiv ebx + mov i1, eax + } /* asm */ + return(i1); +} + +long divscale6(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov edx, eax + sar edx, 26 + shl eax, 6 + idiv ebx + mov i1, eax + } /* asm */ + return(i1); +} + +long divscale7(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov edx, eax + sar edx, 25 + shl eax, 7 + idiv ebx + mov i1, eax + } /* asm */ + return(i1); +} + +long divscale8(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov edx, eax + sar edx, 24 + shl eax, 8 + idiv ebx + mov i1, eax + } /* asm */ + return(i1); +} + +long divscale9(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov edx, eax + sar edx, 23 + shl eax, 9 + idiv ebx + mov i1, eax + } /* asm */ + return(i1); +} + +long divscale10(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov edx, eax + sar edx, 22 + shl eax, 10 + idiv ebx + mov i1, eax + } /* asm */ + return(i1); +} + +long divscale11(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov edx, eax + sar edx, 21 + shl eax, 11 + idiv ebx + mov i1, eax + } /* asm */ + return(i1); +} + +long divscale12(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov edx, eax + sar edx, 20 + shl eax, 12 + idiv ebx + mov i1, eax + } /* asm */ + return(i1); +} + +long divscale13(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov edx, eax + sar edx, 19 + shl eax, 13 + idiv ebx + mov i1, eax + } /* asm */ + return(i1); +} + +long divscale14(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov edx, eax + sar edx, 18 + shl eax, 14 + idiv ebx + mov i1, eax + } /* asm */ + return(i1); +} + +long divscale15(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov edx, eax + sar edx, 17 + shl eax, 15 + idiv ebx + mov i1, eax + } /* asm */ + return(i1); +} + +long divscale16(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov edx, eax + sar edx, 16 + shl eax, 16 + idiv ebx + mov i1, eax + } /* asm */ + return(i1); +} + +long divscale17(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov edx, eax + sar edx, 15 + shl eax, 17 + idiv ebx + mov i1, eax + } /* asm */ + return(i1); +} + +long divscale18(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov edx, eax + sar edx, 14 + shl eax, 18 + idiv ebx + mov i1, eax + } /* asm */ + return(i1); +} + +long divscale19(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov edx, eax + sar edx, 13 + shl eax, 19 + idiv ebx + mov i1, eax + } /* asm */ + return(i1); +} + +long divscale20(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov edx, eax + sar edx, 12 + shl eax, 20 + idiv ebx + mov i1, eax + } /* asm */ + return(i1); +} + +long divscale21(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov edx, eax + sar edx, 11 + shl eax, 21 + idiv ebx + mov i1, eax + } /* asm */ + return(i1); +} + +long divscale22(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov edx, eax + sar edx, 10 + shl eax, 22 + idiv ebx + mov i1, eax + } /* asm */ + return(i1); +} + +long divscale23(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov edx, eax + sar edx, 9 + shl eax, 23 + idiv ebx + mov i1, eax + } /* asm */ + return(i1); +} + +long divscale24(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov edx, eax + sar edx, 8 + shl eax, 24 + idiv ebx + mov i1, eax + } /* asm */ + return(i1); +} + +long divscale25(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov edx, eax + sar edx, 7 + shl eax, 25 + idiv ebx + mov i1, eax + } /* asm */ + return(i1); +} + +long divscale26(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov edx, eax + sar edx, 6 + shl eax, 26 + idiv ebx + mov i1, eax + } /* asm */ + return(i1); +} + +long divscale27(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov edx, eax + sar edx, 5 + shl eax, 27 + idiv ebx + mov i1, eax + } /* asm */ + return(i1); +} + +long divscale28(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov edx, eax + sar edx, 4 + shl eax, 28 + idiv ebx + mov i1, eax + } /* asm */ + return(i1); +} + +long divscale29(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov edx, eax + sar edx, 3 + shl eax, 29 + idiv ebx + mov i1, eax + } /* asm */ + return(i1); +} + +long divscale30(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov edx, eax + sar edx, 2 + shl eax, 30 + idiv ebx + mov i1, eax + } /* asm */ + return(i1); +} + +long divscale31(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov edx, eax + sar edx, 1 + shl eax, 31 + idiv ebx + mov i1, eax + } /* asm */ + return(i1); +} + +long divscale32(long i1, long i2) +{ + __asm + { + mov edx, i1 + mov ebx, i2 + xor eax, eax + idiv ebx + mov i1, eax + } /* asm */ + return(i1); +} + +void clearbuf(void *buf, long i2, long i3) +{ + __asm + { + mov edi, buf + mov ecx, i2 + mov eax, i3 + rep stosd + } /* asm */ +} + +void clearbufbyte(void *buf, long i2, long i3) +{ + __asm + { + mov edi, buf + mov ecx, i2 + mov eax, i3 + cmp ecx, 4 + jae longcopy + test cl, 1 + jz preskip + stosb + preskip: shr ecx, 1 + rep stosw + jmp endit + longcopy: test edi, 1 + jz skip1 + stosb + dec ecx + skip1: test edi, 2 + jz skip2 + stosw + sub ecx, 2 + skip2: mov ebx, ecx + shr ecx, 2 + rep stosd + test bl, 2 + jz skip3 + stosw + skip3: test bl, 1 + jz endit + stosb + endit: + } /* asm */ +} + +void copybuf(void *src, void *dst, long len) +{ + __asm + { + mov esi, src + mov edi, dst + mov ecx, len + rep movsd + } /* asm */ +} + +void copybufbyte(void *src, void *dst, long len) +{ + __asm + { + mov esi, src + mov edi, dst + mov ecx, len + cmp ecx, 4 + jae longcopy + test cl, 1 + jz preskip + movsb + preskip: shr ecx, 1 + rep movsw + jmp endit + longcopy: test edi, 1 + jz skip1 + movsb + dec ecx + skip1: test edi, 2 + jz skip2 + movsw + sub ecx, 2 + skip2: mov ebx, ecx + shr ecx, 2 + rep movsd + test bl, 2 + jz skip3 + movsw + skip3: test bl, 1 + jz endit + movsb + endit: + } /* asm */ +} + +void copybufreverse(void *src, void *dst, long len) +{ + __asm + { + mov esi, src + mov edi, dst + mov ecx, len + shr ecx, 1 + jnc skipit1 + mov al, byte ptr [esi] + dec esi + mov byte ptr [edi], al + inc edi + skipit1: shr ecx, 1 + jnc skipit2 + mov ax, word ptr [esi-1] + sub esi, 2 + ror ax, 8 + mov word ptr [edi], ax + add edi, 2 + skipit2: test ecx, ecx + jz endloop + begloop: mov eax, dword ptr [esi-3] + sub esi, 4 + bswap eax + mov dword ptr [edi], eax + add edi, 4 + dec ecx + jnz begloop + endloop: + } /* asm */ +} + +void qinterpolatedown16(long *i1, long i2, long i3, long i4) +{ + __asm + { + mov eax, i1 + mov ecx, i2 + mov edx, i3 + mov esi, i4 + mov ebx, ecx + shr ecx, 1 + jz skipbegcalc + begqcalc: lea edi, [edx+esi] + sar edx, 16 + mov dword ptr [eax], edx + lea edx, [edi+esi] + sar edi, 16 + mov dword ptr [eax+4], edi + add eax, 8 + dec ecx + jnz begqcalc + test ebx, 1 + jz skipbegqcalc2 + skipbegcalc: sar edx, 16 + mov dword ptr [eax], edx + skipbegqcalc2: + } /* asm */ +} + +void qinterpolatedown16short(long *i1, long i2, long i3, long i4) +{ + __asm + { + mov eax, i1 + mov ecx, i2 + mov edx, i3 + mov esi, i4 + test ecx, ecx + jz endit + test al, 2 + jz skipalignit + mov ebx, edx + sar ebx, 16 + mov word ptr [eax], bx + add edx, esi + add eax, 2 + dec ecx + jz endit + skipalignit: sub ecx, 2 + jc finishit + begqcalc: mov ebx, edx + add edx, esi + sar ebx, 16 + mov edi, edx + and edi, 0ffff0000h + add edx, esi + add ebx, edi + mov dword ptr [eax], ebx + add eax, 4 + sub ecx, 2 + jnc begqcalc + test cl, 1 + jz endit + finishit: mov ebx, edx + sar ebx, 16 + mov word ptr [eax], bx + endit: + } /* asm */ +} + +void vlin16first(long i1, long i2) +{ + __asm + { + mov edi, i1 + mov ecx, i2 + mov al, byte ptr [edi] + mov eax, ecx + shr ecx, 2 + begvlin16firsta: mov byte ptr [edi], al + mov byte ptr [edi+80], al + mov byte ptr [edi+160], al + mov byte ptr [edi+240], al + add edi, 320 + dec ecx + jnz begvlin16firsta + mov ecx, eax + and ecx, 3 + jz skipfirst + begvlin16firstb: mov byte ptr [edi], al + add edi, 80 + dec ecx + jnz begvlin16firstb + skipfirst: + } /* asm */ +} + +void vlin16(long i1, long i2) +{ + __asm + { + mov edi, i1 + mov ecx, i2 + mov esi, edi + begvlin16: movsb + add edi, 79 + add esi, 79 + dec ecx + jnz begvlin16 + } /* asm */ +} + +long mul3(long i1) +{ + __asm + { + mov eax, i1 + lea eax, [eax+eax*2] + mov i1, eax + } /* asm */ + return(i1); +} + +long mul5(long i1) +{ + __asm + { + mov eax, i1 + lea eax, [eax+eax*4] + mov i1, eax + } /* asm */ + return(i1); +} + +long mul9(long i1) +{ + __asm + { + mov eax, i1 + lea eax, [eax+eax*8] + mov i1, eax + } /* asm */ + return(i1); +} + + /* returns eax/ebx, dmval = eax%edx; */ +long divmod(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + xor edx, edx + div ebx + mov dmval, edx + mov i1, eax + } /* asm */ + return(i1); +} + + /* returns eax%ebx, dmval = eax/edx; */ +long moddiv(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + xor edx, edx + div ebx + mov dmval, eax + mov i1, edx + } /* asm */ + return(i1); +} + +long klabs(long i1) +{ + __asm + { + mov eax, i1 + test eax, eax + jns skipnegate + neg eax + skipnegate: + mov i1, eax + } /* asm */ + return(i1); +} + +long ksgn(long i1) +{ + __asm + { + mov ebx, i1 + add ebx, ebx + sbb eax, eax + cmp eax, ebx + adc al, 0 + mov i1, eax + } /* asm */ + return(i1); +} + + /* eax = (unsigned min)umin(eax,ebx) */ +long umin(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + sub eax, ebx + sbb ecx, ecx + and eax, ecx + add eax, ebx + mov i1, eax + } /* asm */ + return(i1); +} + + /* eax = (unsigned max)umax(eax,ebx) */ +long umax(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + sub eax, ebx + sbb ecx, ecx + xor ecx, 0xffffffff + and eax, ecx + add eax, ebx + mov i1, eax + } /* asm */ + return(i1); +} + +long kmin(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + cmp eax, ebx + jl skipit + mov eax, ebx + skipit: + mov i1, eax + } /* asm */ + return(i1); +} + +long kmax(long i1, long i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + cmp eax, ebx + jg skipit + mov eax, ebx + skipit: + mov i1, eax + } /* asm */ + return(i1); +} + +void swapchar(char *i1, char *i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov cl, [eax] + mov ch, [ebx] + mov [ebx], cl + mov [eax], ch + mov i1, eax + } /* asm */ +} + +void swapshort(short *i1, short *i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov cx, [eax] + mov dx, [ebx] + mov [ebx], cx + mov [eax], dx + mov i1, eax + } /* asm */ +} + +void swaplong(long *i1, long *i2) +{ + __asm + { + mov eax, i1 + mov ebx, i2 + mov ecx, [eax] + mov edx, [ebx] + mov [ebx], ecx + mov [eax], edx + mov i1, eax + } /* asm */ +} + + + /* + * swapchar2(ptr1,ptr2,xsiz); is the same as: + * swapchar(ptr1,ptr2); swapchar(ptr1+1,ptr2+xsiz); + */ +void swapchar2(char *ptr1, char *ptr2, long xsiz) +{ + __asm + { + mov eax, ptr1 + mov ebx, ptr2 + mov esi, xsiz + add esi, ebx + mov cx, [eax] + mov dl, [ebx] + mov [ebx], cl + mov dh, [esi] + mov [esi], ch + mov [eax], dx + } /* asm */ +} + +#endif /* defined _MSC_VER */ +#endif /* !defined _INCLUDE_PRAGMAS_VISUALC_H_ */ + +/* end of pragmas_visualc.h ... */ + + diff --git a/buildengine/sdl_driver.c b/buildengine/sdl_driver.c new file mode 100755 index 0000000..6a4bc1a --- /dev/null +++ b/buildengine/sdl_driver.c @@ -0,0 +1,2563 @@ +/* + * An SDL replacement for BUILD's VESA code. + * + * Written by Ryan C. Gordon. (icculus@clutteredmind.org) + * + * Please do NOT harrass Ken Silverman about any code modifications + * (including this file) to BUILD. + */ + +/* + * "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman + * Ken Silverman's official web site: "http://www.advsys.net/ken" + * See the included license file "BUILDLIC.TXT" for license info. + * This file IS NOT A PART OF Ken Silverman's original release + */ +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef PLATFORM_WIN32 +#include +#endif +#include "platform.h" + +#if (!defined PLATFORM_SUPPORTS_SDL) +#error This platform apparently does not use SDL. Do not compile this. +#endif + +#include "SDL.h" +#include "build.h" +#include "display.h" +#include "pragmas.h" +#include "engine.h" + +#if (defined USE_OPENGL) +#include "buildgl.h" +#endif + +/* need VirtualProtect() from win32 API... */ +#if ((defined PLATFORM_WIN32) && (defined USE_I386_ASM)) +#define WIN32_LEAN_AND_MEAN 1 +#include +#endif + +typedef enum +{ + RENDERER_SOFTWARE, + RENDERER_OPENGL3D, + RENDERER_TOTAL +} sdl_renderer_type; + +const char *renderer_name[RENDERER_TOTAL]; + +#define ENVRSTR_RENDERER_SOFTWARE "software" +#define ENVRSTR_RENDERER_OPENGL3D "opengl3d" + +static sdl_renderer_type renderer = RENDERER_SOFTWARE; + +/* !!! ugh. Clean this up. */ +#if (!defined __WATCOMC__) +#include "a.h" +#else +extern long setvlinebpl(long); +#pragma aux setvlinebpl parm [eax]; +#endif /* __WATCOMC__ */ + +#include "cache1d.h" + + +/* + * !!! I'd like this to be temporary. --ryan. + * !!! That is, the self-modifying part, so I can ditch the mprotect() stuff. + */ +#if ((defined PLATFORM_UNIX) && (defined USE_I386_ASM)) + +#include +#include + +#ifndef PAGESIZE +#define PAGESIZE 4096 +#endif + +#endif + +#ifdef PLATFORM_MACOSX +#include +#endif + + +/* + * !!! remove the surface_end checks, for speed's sake. They are a + * !!! needed safety right now. --ryan. + */ + +#define DEFAULT_MAXRESWIDTH 1600 +#define DEFAULT_MAXRESHEIGHT 1200 + + +#define UNLOCK_SURFACE_AND_RETURN if (SDL_MUSTLOCK(surface)) SDL_UnlockSurface(surface); return; + +static unsigned char tempbuf[MAXWALLS]; +static char pcxheader[128] = +{ + 0xa,0x5,0x1,0x8,0x0,0x0,0x0,0x0,0x3f,0x1,0xc7,0x0, + 0x40,0x1,0xc8,0x0,0x0,0x0,0x0,0x8,0x8,0x8,0x10,0x10, + 0x10,0x18,0x18,0x18,0x20,0x20,0x20,0x28,0x28,0x28,0x30,0x30, + 0x30,0x38,0x38,0x38,0x40,0x40,0x40,0x48,0x48,0x48,0x50,0x50, + 0x50,0x58,0x58,0x58,0x60,0x60,0x60,0x68,0x68,0x68,0x70,0x70, + 0x70,0x78,0x78,0x78,0x0,0x1,0x40,0x1,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +}; + + +static char vgapal16[48] = +{ + 00,00,00,00,00,42,00,42,00,00,42,42,42,00,00,42,00,42,42,21,00,42,42,42, + 21,21,21,21,21,63,21,63,21,21,63,63,63,21,21,63,21,63,63,63,21,63,63,63, +}; + + +int _argc = 0; +char **_argv = NULL; + + /* !!! move these elsewhere? */ +long xres, yres, bytesperline, frameplace, imageSize, maxpages; +char *screen, vesachecked; +long buffermode, origbuffermode, linearmode; +char permanentupdate = 0, vgacompatible; + +SDL_Surface *surface = NULL; /* This isn't static so that we can use it elsewhere AH */ +static int debug_hall_of_mirrors = 0; +static Uint32 sdl_flags = SDL_HWPALETTE; +static long mouse_x = 0; +static long mouse_y = 0; +static long mouse_relative_x = 0; +static long mouse_relative_y = 0; +static short mouse_buttons = 0; +static int mouse_grabbed = 0; +static unsigned int lastkey = 0; +static SDL_TimerID primary_timer = NULL; +/* so we can make use of setcolor16()... - DDOI */ +static unsigned char drawpixel_color=0; +/* These hold the colors for the 256 color palette when in 16-color mode - DDOI */ +static char backup_palette[48]; +static int in_egapalette = 0; +/* The standard EGA palette in BUILD format - DDOI */ +static char egapalette[] = { 0, 0, 0, + 0, 0, 42, + 0, 42, 0, + 0, 42, 42, + 42, 0, 0, + 42, 0, 42, + 42, 21, 0, + 42, 42, 42, + 21, 21, 21, + 21, 21, 63, + 21, 63, 21, + 21, 63, 63, + 63, 21, 21, + 63, 21, 63, + 63, 63, 21, + 63, 63, 63 + }; + +static unsigned int scancodes[SDLK_LAST]; + +static long last_render_ticks = 0; +long total_render_time = 1; +long total_rendered_frames = 0; + +static char *titlelong = NULL; +static char *titleshort = NULL; + +void restore256_palette (void); +void set16color_palette (void); + + +static FILE *_sdl_debug_file = NULL; + +#ifdef DC +#define sdldebug(fmt,args...) printf("BUILDSDL: " fmt "\n",##args) +#else +static __inline void __out_sdldebug(const char *subsystem, + const char *fmt, va_list ap) +{ + fprintf(_sdl_debug_file, "%s: ", subsystem); + vfprintf(_sdl_debug_file, fmt, ap); + fprintf(_sdl_debug_file, "\n"); + fflush(_sdl_debug_file); +} /* __out_sdldebug */ + + +static void sdldebug(const char *fmt, ...) +{ + va_list ap; + + if (_sdl_debug_file) + { + va_start(ap, fmt); + __out_sdldebug("BUILDSDL", fmt, ap); + va_end(ap); + } /* if */ +} /* sdldebug */ +#endif + +#if (defined USE_OPENGL) +void sgldebug(const char *fmt, ...) +{ + va_list ap; + + if (_sdl_debug_file) + { + va_start(ap, fmt); + __out_sdldebug("BUILDSDL/GL", fmt, ap); + va_end(ap); + } /* if */ +} /* sgldebug */ +#endif + + +static void __append_sdl_surface_flag(SDL_Surface *_surface, char *str, + size_t strsize, Uint32 flag, + const char *flagstr) +{ + if (_surface->flags & flag) + { + if ( (strlen(str) + strlen(flagstr)) >= (strsize - 1) ) + strcpy(str + (strsize - 5), " ..."); + else + strcat(str, flagstr); + } /* if */ +} /* append_sdl_surface_flag */ + + +#define append_sdl_surface_flag(a, b, c, fl) __append_sdl_surface_flag(a, b, c, fl, " " #fl) +#define print_tf_state(str, val) sdldebug("%s: {%s}", str, (val) ? "true" : "false" ) + +static void output_surface_info(SDL_Surface *_surface) +{ + const SDL_VideoInfo *info; + char f[256]; + + if (!_sdl_debug_file) + return; + + if (_surface == NULL) + { + sdldebug("-WARNING- You've got a NULL screen surface!"); + } + else + { + f[0] = '\0'; + sdldebug("screen surface is (%dx%dx%dbpp).", + _surface->w, _surface->h, _surface->format->BitsPerPixel); + + append_sdl_surface_flag(_surface, f, sizeof (f), SDL_SWSURFACE); + append_sdl_surface_flag(_surface, f, sizeof (f), SDL_HWSURFACE); + append_sdl_surface_flag(_surface, f, sizeof (f), SDL_ASYNCBLIT); + append_sdl_surface_flag(_surface, f, sizeof (f), SDL_ANYFORMAT); + append_sdl_surface_flag(_surface, f, sizeof (f), SDL_HWPALETTE); + append_sdl_surface_flag(_surface, f, sizeof (f), SDL_DOUBLEBUF); + append_sdl_surface_flag(_surface, f, sizeof (f), SDL_FULLSCREEN); + append_sdl_surface_flag(_surface, f, sizeof (f), SDL_OPENGL); + append_sdl_surface_flag(_surface, f, sizeof (f), SDL_OPENGLBLIT); + append_sdl_surface_flag(_surface, f, sizeof (f), SDL_RESIZABLE); + append_sdl_surface_flag(_surface, f, sizeof (f), SDL_NOFRAME); + append_sdl_surface_flag(_surface, f, sizeof (f), SDL_HWACCEL); + append_sdl_surface_flag(_surface, f, sizeof (f), SDL_SRCCOLORKEY); + append_sdl_surface_flag(_surface, f, sizeof (f), SDL_RLEACCELOK); + append_sdl_surface_flag(_surface, f, sizeof (f), SDL_RLEACCEL); + append_sdl_surface_flag(_surface, f, sizeof (f), SDL_SRCALPHA); + append_sdl_surface_flag(_surface, f, sizeof (f), SDL_PREALLOC); + + if (f[0] == '\0') + strcpy(f, " (none)"); + + sdldebug("New vidmode flags:%s", f); + + info = SDL_GetVideoInfo(); + assert(info != NULL); + + print_tf_state("hardware surface available", info->hw_available); + print_tf_state("window manager available", info->wm_available); + print_tf_state("accelerated hardware->hardware blits", info->blit_hw); + print_tf_state("accelerated hardware->hardware colorkey blits", info->blit_hw_CC); + print_tf_state("accelerated hardware->hardware alpha blits", info->blit_hw_A); + print_tf_state("accelerated software->hardware blits", info->blit_sw); + print_tf_state("accelerated software->hardware colorkey blits", info->blit_sw_CC); + print_tf_state("accelerated software->hardware alpha blits", info->blit_sw_A); + print_tf_state("accelerated color fills", info->blit_fill); + + sdldebug("video memory: (%d)", info->video_mem); + } /* else */ +} /* output_surface_info */ + + +static void output_driver_info(void) +{ + char buffer[256]; + + if (!_sdl_debug_file) + return; + + sdldebug("Using BUILD renderer \"%s\".", renderer_name[renderer]); + + if (SDL_VideoDriverName(buffer, sizeof (buffer)) == NULL) + { + sdldebug("-WARNING- SDL_VideoDriverName() returned NULL!"); + } /* if */ + else + { + sdldebug("Using SDL video driver \"%s\".", buffer); + } /* else */ +} /* output_driver_info */ + + +static Uint8 *get_framebuffer(void) +{ + assert(renderer != RENDERER_OPENGL3D); + + if (renderer == RENDERER_SOFTWARE) + return((Uint8 *) surface->pixels); + else if (renderer == RENDERER_OPENGL3D) + return((Uint8 *) frameplace); + + return(NULL); +} /* get_framebuffer */ + + +int using_opengl(void) +{ + return(renderer == RENDERER_OPENGL3D); +} /* using_opengl */ + + +/* + * !!! This is almost an entire copy of the original setgamemode(). + * !!! Figure out what is needed for just 2D mode, and separate that + * !!! out. Then, place the original setgamemode() back into engine.c, + * !!! and remove our simple implementation (and this function.) + * !!! Just be sure to keep the non-DOS things, like the window's + * !!! titlebar caption. --ryan. + */ +static char screenalloctype = 255; +static void init_new_res_vars(int davidoption) +{ + int i = 0; + int j = 0; + + setupmouse(); + + SDL_WM_SetCaption(titlelong, titleshort); + + xdim = xres = surface->w; + ydim = yres = surface->h; + + bytesperline = surface->w; + vesachecked = 1; + vgacompatible = 1; + linearmode = 1; + qsetmode = surface->h; + activepage = visualpage = 0; + horizlookup = horizlookup2 = NULL; + + if (renderer == RENDERER_OPENGL3D) + frameplace = (long) NULL; + else + frameplace = (long) ( ((Uint8 *) surface->pixels) ); + + if (screen != NULL) + { + if (screenalloctype == 0) kkfree((void *)screen); + if (screenalloctype == 1) suckcache((long *)screen); + screen = NULL; + } /* if */ + + if (davidoption != -1) + { + switch(vidoption) + { + case 1:i = xdim*ydim; break; + case 2: xdim = 320; ydim = 200; i = xdim*ydim; break; + case 6: xdim = 320; ydim = 200; i = 131072; break; + default: assert(0); + } + j = ydim*4*sizeof(long); /* Leave room for horizlookup&horizlookup2 */ + + screenalloctype = 0; + if ((screen = (char *)kkmalloc(i+(j<<1))) == NULL) + { + allocache((long *)&screen,i+(j<<1),&permanentlock); + screenalloctype = 1; + } + + /* !!! FIXME: Should screen get allocated above if in opengl3d mode? */ + + if (renderer == RENDERER_OPENGL3D) + frameplace = (long) NULL; + else + { + frameplace = FP_OFF(screen); + horizlookup = (long *)(frameplace+i); + horizlookup2 = (long *)(frameplace+i+j); + } /* else */ + } /* if */ + + j = 0; + for(i = 0; i <= ydim; i++) + { + ylookup[i] = j; + j += bytesperline; + } /* for */ + + horizycent = ((ydim*4)>>1); + + /* Force drawrooms to call dosetaspect & recalculate stuff */ + oxyaspect = oxdimen = oviewingrange = -1; + + setvlinebpl(bytesperline); + + if (davidoption != -1) + { + setview(0L,0L,xdim-1,ydim-1); + clearallviews(0L); + } /* if */ + + setbrightness((char) curbrightness, (unsigned char *) &palette[0]); + + if (searchx < 0) { searchx = halfxdimen; searchy = (ydimen>>1); } +} /* init_new_res_vars */ + + +static void go_to_new_vid_mode(int vidoption, int w, int h) +{ + getvalidvesamodes(); + SDL_ClearError(); + surface = SDL_SetVideoMode(w, h, 8, sdl_flags); + if (surface == NULL) + { + fprintf(stderr, "BUILDSDL: Failed to set %dx%d video mode!\n" + "BUILDSDL: SDL_Error() says [%s].\n", + w, h, SDL_GetError()); + SDL_Quit(); + exit(13); + } /* if */ + + output_surface_info(surface); + init_new_res_vars(vidoption); +} /* go_to_new_vid_mode */ + + +static __inline int sdl_mouse_button_filter(SDL_MouseButtonEvent const *event) +{ + /* + * What bits BUILD expects: + * 0 left button pressed if 1 + * 1 right button pressed if 1 + * 2 middle button pressed if 1 + * + * (That is, this is what Int 33h (AX=0x05) returns...) + * + * additionally 3&4 are set for the mouse wheel + */ + Uint8 button = event->button; + if (button >= sizeof (mouse_buttons) * 8) + return(0); + + if (button == SDL_BUTTON_RIGHT) + button = SDL_BUTTON_MIDDLE; + else if (button == SDL_BUTTON_MIDDLE) + button = SDL_BUTTON_RIGHT; + + if (((const SDL_MouseButtonEvent*)event)->state) + mouse_buttons |= 1<<(button-1); + else if (button != 4 && button != 5) + mouse_buttons ^= 1<<(button-1); + +#if 0 + Uint8 bmask = SDL_GetMouseState(NULL, NULL); + mouse_buttons = 0; + if (bmask & SDL_BUTTON_LMASK) mouse_buttons |= 1; + if (bmask & SDL_BUTTON_RMASK) mouse_buttons |= 2; + if (bmask & SDL_BUTTON_MMASK) mouse_buttons |= 4; +#endif + + return(0); +} /* sdl_mouse_up_filter */ + + +static int sdl_mouse_motion_filter(SDL_Event const *event) +{ + if (surface == NULL) + return(0); + + if (event->type == SDL_JOYBALLMOTION) + { + mouse_relative_x = event->jball.xrel/100; + mouse_relative_y = event->jball.yrel/100; + mouse_x += mouse_relative_x; + mouse_y += mouse_relative_y; + } /* if */ + else + { + if (mouse_grabbed) + { + mouse_relative_x += event->motion.xrel; + mouse_relative_y += event->motion.yrel; + mouse_x += mouse_relative_x; + mouse_y += mouse_relative_y; + } /* if */ + else + { + mouse_relative_x += event->motion.x - mouse_x; + mouse_relative_y += event->motion.y - mouse_y; + mouse_x = event->motion.x; + mouse_y = event->motion.y; + } /* else */ + } /* else */ + + if (mouse_x < 0) mouse_x = 0; + if (mouse_x > surface->w) mouse_x = surface->w; + if (mouse_y < 0) mouse_y = 0; + if (mouse_y > surface->h) mouse_y = surface->h; + + return(0); +} /* sdl_mouse_motion_filter */ + + +/** + * Attempt to flip the video surface to fullscreen or windowed mode. + * Attempts to maintain the surface's state, but makes no guarantee + * that pointers (i.e., the surface's pixels field) will be the same + * after this call. + * + * Caveats: Your surface pointers will be changing; if you have any other + * copies laying about, they are invalidated. + * + * Do NOT call this from an SDL event filter on Windows. You can + * call it based on the return values from SDL_PollEvent, etc, just + * not during the function you passed to SDL_SetEventFilter(). + * + * Thread safe? Likely not. + * + * @param surface pointer to surface ptr to toggle. May be different + * pointer on return. MAY BE NULL ON RETURN IF FAILURE! + * @param flags pointer to flags to set on surface. The value pointed + * to will be XOR'd with SDL_FULLSCREEN before use. Actual + * flags set will be filled into pointer. Contents are + * undefined on failure. Can be NULL, in which case the + * surface's current flags are used. + * @return non-zero on success, zero on failure. + */ +static int attempt_fullscreen_toggle(SDL_Surface **surface, Uint32 *flags) +{ + long framesize = 0; + void *pixels = NULL; + SDL_Rect clip; + Uint32 tmpflags = 0; + int w = 0; + int h = 0; + int bpp = 0; + int grabmouse = (SDL_WM_GrabInput(SDL_GRAB_QUERY) == SDL_GRAB_ON); + int showmouse = SDL_ShowCursor(-1); + +#if 0 + SDL_Color *palette = NULL; + int ncolors = 0; +#endif + + sdldebug("attempting to toggle fullscreen flag..."); + + if ( (!surface) || (!(*surface)) ) /* don't try if there's no surface. */ + { + sdldebug("Null surface (?!). Not toggling fullscreen flag."); + return(0); + } /* if */ + + if (SDL_WM_ToggleFullScreen(*surface)) + { + sdldebug("SDL_WM_ToggleFullScreen() seems to work on this system."); + if (flags) + *flags ^= SDL_FULLSCREEN; + return(1); + } /* if */ + +#if !PLATFORM_MACOSX + if ( !(SDL_GetVideoInfo()->wm_available) ) + { + sdldebug("No window manager. Not toggling fullscreen flag."); + return(0); + } /* if */ +#endif + + sdldebug("toggling fullscreen flag The Hard Way..."); + tmpflags = (*surface)->flags; + w = (*surface)->w; + h = (*surface)->h; + bpp = (*surface)->format->BitsPerPixel; + + if (flags == NULL) /* use the surface's flags. */ + flags = &tmpflags; + + SDL_GetClipRect(*surface, &clip); + + /* save the contents of the screen. */ + if ( (!(tmpflags & SDL_OPENGL)) && (!(tmpflags & SDL_OPENGLBLIT)) ) + { + framesize = (w * h) * ((*surface)->format->BytesPerPixel); + pixels = malloc(framesize); + if (pixels == NULL) + return(0); + memcpy(pixels, (*surface)->pixels, framesize); + } /* if */ + +#if 0 + if ((*surface)->format->palette != NULL) + { + ncolors = (*surface)->format->palette->ncolors; + palette = malloc(ncolors * sizeof (SDL_Color)); + if (palette == NULL) + { + free(pixels); + return(0); + } /* if */ + memcpy(palette, (*surface)->format->palette->colors, + ncolors * sizeof (SDL_Color)); + } /* if */ +#endif + + if (grabmouse) + SDL_WM_GrabInput(SDL_GRAB_OFF); + + SDL_ShowCursor(1); + + *surface = SDL_SetVideoMode(w, h, bpp, (*flags) ^ SDL_FULLSCREEN); + + if (*surface != NULL) + *flags ^= SDL_FULLSCREEN; + + else /* yikes! Try to put it back as it was... */ + { + *surface = SDL_SetVideoMode(w, h, bpp, tmpflags); + if (*surface == NULL) /* completely screwed. */ + { + if (pixels != NULL) + free(pixels); + if (palette != NULL) + free(palette); + return(0); + } /* if */ + } /* if */ + + /* Unfortunately, you lose your OpenGL image until the next frame... */ + + if (pixels != NULL) + { + memcpy((*surface)->pixels, pixels, framesize); + free(pixels); + } /* if */ + +#if 0 + if (palette != NULL) + { + /* !!! FIXME : No idea if that flags param is right. */ + SDL_SetPalette(*surface, SDL_LOGPAL, palette, 0, ncolors); + free(palette); + } /* if */ +#else + setbrightness((char) curbrightness, (unsigned char *) &palette[0]); +#endif + + SDL_SetClipRect(*surface, &clip); + + if (grabmouse) + SDL_WM_GrabInput(SDL_GRAB_ON); + + SDL_ShowCursor(showmouse); + + output_surface_info(*surface); + + return(1); +} /* attempt_fullscreen_toggle */ + + + /* + * The windib driver can't alert us to the keypad enter key, which + * Ken's code depends on heavily. It sends it as the same key as the + * regular return key. These users will have to hit SHIFT-ENTER, + * which we check for explicitly, and give the engine a keypad enter + * enter event. + */ +static __inline int handle_keypad_enter_hack(const SDL_Event *event) +{ + static int kp_enter_hack = 0; + int retval = 0; + + if (event->key.keysym.sym == SDLK_RETURN) + { + if (event->key.state == SDL_PRESSED) + { + if (event->key.keysym.mod & KMOD_SHIFT) + { + kp_enter_hack = 1; + lastkey = scancodes[SDLK_KP_ENTER]; + retval = 1; + } /* if */ + } /* if */ + + else /* key released */ + { + if (kp_enter_hack) + { + kp_enter_hack = 0; + lastkey = scancodes[SDLK_KP_ENTER]; + retval = 1; + } /* if */ + } /* if */ + } /* if */ + + return(retval); +} /* handle_keypad_enter_hack */ + + +static int sdl_key_filter(const SDL_Event *event) +{ + SDL_GrabMode grab_mode = SDL_GRAB_OFF; + int extended; + int tmp; + + #if PLATFORM_MACOSX /* Apple-Q */ + { + static Uint32 cmdqticks = 0; + if ( (event->key.keysym.sym == SDLK_q) && + (event->key.state == SDL_PRESSED) && + (event->key.keysym.mod & KMOD_META) ) + { + Uint32 t = SDL_GetTicks(); + if (t - cmdqticks < 500) /* 2 hits within .5 second? */ + { + SDL_Quit(); + exit(0); + } + cmdqticks = t; + } + } + #endif + + + if ( (event->key.keysym.sym == SDLK_g) && + (event->key.state == SDL_PRESSED) && + (event->key.keysym.mod & KMOD_CTRL) ) + { + mouse_grabbed = ((mouse_grabbed) ? 0 : 1); + if (mouse_grabbed) + grab_mode = SDL_GRAB_ON; + SDL_WM_GrabInput(grab_mode); + return(0); + } /* if */ + + else if ( ( (event->key.keysym.sym == SDLK_RETURN) || + (event->key.keysym.sym == SDLK_KP_ENTER) ) && + (event->key.state == SDL_PRESSED) && + (event->key.keysym.mod & KMOD_ALT) ) + { + tmp = ((void *) frameplace == (void *) surface->pixels); + attempt_fullscreen_toggle(&surface, &sdl_flags); + assert(surface != NULL); + if (tmp) + frameplace = (long) surface->pixels; + return(0); + } /* if */ + + if (!handle_keypad_enter_hack(event)) + lastkey = scancodes[event->key.keysym.sym]; + + if (lastkey == 0x0000) /* No DOS equivalent defined. */ + return(0); + + extended = ((lastkey & 0xFF00) >> 8); + if (extended != 0) + { + lastkey = extended; + keyhandler(); + lastkey = (scancodes[event->key.keysym.sym] & 0xFF); + } /* if */ + + if (event->key.state == SDL_RELEASED) + lastkey += 128; /* +128 signifies that the key is released in DOS. */ + + keyhandler(); + return(0); +} /* sdl_key_filter */ + + +static int root_sdl_event_filter(const SDL_Event *event) +{ + switch (event->type) + { + case SDL_KEYUP: + case SDL_KEYDOWN: + return(sdl_key_filter(event)); + case SDL_JOYBALLMOTION: + case SDL_MOUSEMOTION: + return(sdl_mouse_motion_filter(event)); + case SDL_MOUSEBUTTONUP: + case SDL_MOUSEBUTTONDOWN: + return(sdl_mouse_button_filter((const SDL_MouseButtonEvent*)event)); + case SDL_QUIT: + /* !!! rcg TEMP */ + SDL_Quit(); + exit(0); + } /* switch */ + + return(1); +} /* root_sdl_event_filter */ + + +static void handle_events(void) +{ + SDL_Event event; + + while (SDL_PollEvent(&event)) + root_sdl_event_filter(&event); +} /* handle_events */ + + +/* bleh...public version... */ +void _handle_events(void) +{ + handle_events(); +} /* _handle_events */ + + +static SDL_Joystick *joystick = NULL; +void _joystick_init(void) +{ + const char *envr = getenv(BUILD_SDLJOYSTICK); + int favored = 0; + int numsticks; + int i; + + if (joystick != NULL) + { + sdldebug("Joystick appears to be already initialized."); + sdldebug("...deinitializing for stick redetection..."); + _joystick_deinit(); + } /* if */ + + if ((envr != NULL) && (strcmp(envr, "none") == 0)) + { + sdldebug("Skipping joystick detection/initialization at user request"); + return; + } /* if */ + + sdldebug("Initializing SDL joystick subsystem..."); + sdldebug(" (export environment variable BUILD_SDLJOYSTICK=none to skip)"); + + if (SDL_Init(SDL_INIT_JOYSTICK) != 0) + { + sdldebug("SDL_Init(SDL_INIT_JOYSTICK) failed: [%s].", SDL_GetError()); + return; + } /* if */ + + numsticks = SDL_NumJoysticks(); + sdldebug("SDL sees %d joystick%s.", numsticks, numsticks == 1 ? "" : "s"); + if (numsticks == 0) + return; + + for (i = 0; i < numsticks; i++) + { + const char *stickname = SDL_JoystickName(i); + if ((envr != NULL) && (strcmp(envr, stickname) == 0)) + favored = i; + + sdldebug("Stick #%d: [%s]", i, stickname); + } /* for */ + + sdldebug("Using Stick #%d.", favored); + if ((envr == NULL) && (numsticks > 1)) + sdldebug("Set BUILD_SDLJOYSTICK to one of the above names to change."); + + joystick = SDL_JoystickOpen(favored); + if (joystick == NULL) + { + sdldebug("Joystick #%d failed to init: %s", favored, SDL_GetError()); + return; + } /* if */ + + sdldebug("Joystick initialized. %d axes, %d buttons, %d hats, %d balls.", + SDL_JoystickNumAxes(joystick), SDL_JoystickNumButtons(joystick), + SDL_JoystickNumHats(joystick), SDL_JoystickNumBalls(joystick)); + + SDL_JoystickEventState(SDL_QUERY); +} /* _joystick_init */ + + +void _joystick_deinit(void) +{ + if (joystick != NULL) + { + sdldebug("Closing joystick device..."); + SDL_JoystickClose(joystick); + sdldebug("Joystick device closed. Deinitializing SDL subsystem..."); + SDL_QuitSubSystem(SDL_INIT_JOYSTICK); + sdldebug("SDL joystick subsystem deinitialized."); + joystick = NULL; + } /* if */ +} /* _joystick_deinit */ + + +int _joystick_update(void) +{ + if (joystick == NULL) + return(0); + + SDL_JoystickUpdate(); + return(1); +} /* _joystick_update */ + + +int _joystick_axis(int axis) +{ + if (joystick == NULL) + return(0); + + return(SDL_JoystickGetAxis(joystick, axis)); +} /* _joystick_axis */ + +int _joystick_hat(int hat) +{ + if (joystick == NULL) + { + return(-1); + } + + return(SDL_JoystickGetHat(joystick, hat)); +} /* _joystick_axis */ + +int _joystick_button(int button) +{ + if (joystick == NULL) + return(0); + + return(SDL_JoystickGetButton(joystick, button) != 0); +} /* _joystick_button */ + + +unsigned char _readlastkeyhit(void) +{ + return(lastkey); +} /* _readlastkeyhit */ + + +/* !!! I'd like this to be temporary. --ryan. */ +#if (defined USE_I386_ASM) + +# if (defined PLATFORM_UNIX) +# define PROT_R_W_X (PROT_READ | PROT_WRITE | PROT_EXEC) + +# elif (defined PLATFORM_WIN32) +# ifndef PAGESIZE +# define PAGESIZE 4096 +# endif +# define PROT_R_W_X PAGE_EXECUTE_READWRITE + + static int mprotect(void *ptr, size_t len, int prot) + { + BOOL rc; + DWORD old = 0; + rc = VirtualProtect(ptr, len, prot, &old); + return(rc == 0); + } + +#endif + +#ifdef USE_I386_ASM +int mprotect_align(const void *addr, size_t len, int prot) +{ + int retval; + unsigned long l = (unsigned long) addr; + l -= (l % PAGESIZE); + retval = mprotect((void *) l, len * 2, prot); + assert(retval == 0); + return(retval); +} /* mprotect_align */ + + +void unprotect_ASM_pages(void) +{ + mprotect_align((const void *) asm_sethlinesizes, PAGESIZE, PROT_R_W_X); + mprotect_align((const void *) asm_setpalookupaddress, PAGESIZE, PROT_R_W_X); + mprotect_align((const void *) asm_setuphlineasm4, PAGESIZE, PROT_R_W_X); + mprotect_align((const void *) asm_hlineasm4, PAGESIZE, PROT_R_W_X); + mprotect_align((const void *) asm_setupvlineasm, PAGESIZE, PROT_R_W_X); + mprotect_align((const void *) asm_vlineasm4, PAGESIZE, PROT_R_W_X); + mprotect_align((const void *) asm_tvlineasm1, PAGESIZE, PROT_R_W_X); + mprotect_align((const void *) asm_tvlineasm2, PAGESIZE, PROT_R_W_X); + mprotect_align((const void *) asm_tspritevline, PAGESIZE, PROT_R_W_X); + mprotect_align((const void *) asm_thline, PAGESIZE, PROT_R_W_X); + mprotect_align((const void *) asm_prohlineasm4, PAGESIZE, PROT_R_W_X); + mprotect_align((const void *) asm_stretchhline, PAGESIZE, PROT_R_W_X); +} /* unprotect_ASM_pages */ +#endif + + +/* + global _sethlinesizes + + + global _prosethlinesizes + global _setvlinebpl + global _setpalookupaddress + global _prosetpalookupaddress + global _setuphlineasm4 + global _hlineasm4 + global _prohlineasm4 + global _setupvlineasm + global _prosetupvlineasm + global _setupmvlineasm + global _setuptvlineasm + global _prevlineasm1 + global _vlineasm1 + global _mvlineasm1 + global _fixtransluscence + global _settransnormal + global _settransreverse + global _tvlineasm1 + global _vlineasm4 + global _provlineasm4 + global _mvlineasm4 + global _setupspritevline + global _spritevline + global _msetupspritevline + global _mspritevline + global _tsetupspritevline + global _tspritevline + global _msethlineshift + global _mhline + global _mhlineskipmodify + global _tsethlineshift + global _thline + global _thlineskipmodify + global _setuptvlineasm2 + global _tvlineasm2 + global _setupslopevlin2 + global _slopevlin2 + global _setupslopevlin + global _slopevlin + global _setuprhlineasm4 + global _rhlineasm4 + global _setuprmhlineasm4 + global _rmhlineasm4 + global _setupqrhlineasm4 + global _qrhlineasm4 + global _setupdrawslab + global _drawslab + global _stretchhline + global _mmxoverlay +*/ + +#endif + + +static __inline void init_debugging(void) +{ + const char *envr = getenv(BUILD_SDLDEBUG); + + debug_hall_of_mirrors = (getenv(BUILD_HALLOFMIRRORS) != NULL); + + if (_sdl_debug_file != NULL) + { + fclose(_sdl_debug_file); + _sdl_debug_file = NULL; + } /* if */ + + if (envr != NULL) + { + if (strcmp(envr, "-") == 0) + _sdl_debug_file = stdout; + else + _sdl_debug_file = fopen(envr, "w"); + + if (_sdl_debug_file == NULL) + printf("BUILDSDL: -WARNING- Could not open debug file!\n"); + else + setbuf(_sdl_debug_file, NULL); + } /* if */ +} /* init_debugging */ + + +#if (!defined __DATE__) +#define __DATE__ "a long, long time ago" +#endif + +static __inline void output_sdl_versions(void) +{ + const SDL_version *linked_ver = SDL_Linked_Version(); + SDL_version compiled_ver; + + SDL_VERSION(&compiled_ver); + + sdldebug("SDL display driver for the BUILD engine initializing."); + sdldebug(" sdl_driver.c by Ryan C. Gordon (icculus@clutteredmind.org)."); + sdldebug("Compiled %s against SDL version %d.%d.%d ...", __DATE__, + compiled_ver.major, compiled_ver.minor, compiled_ver.patch); + sdldebug("Linked SDL version is %d.%d.%d ...", + linked_ver->major, linked_ver->minor, linked_ver->patch); +} /* output_sdl_versions */ + + +static int in_vmware = 0; +static __inline void detect_vmware(void) +{ +#if 1 + in_vmware = 0; /* oh well. */ +#else + /* !!! need root access to touch i/o ports on Linux. */ + #if (!defined __linux__) + in_vmware = (int) is_vmware_running(); + #endif + sdldebug("vmWare %s running.", (in_vmware) ? "is" : "is not"); +#endif +} /* detect_vmware */ + + +/* lousy -ansi flag. :) */ +static char *string_dupe(const char *str) +{ + char *retval = malloc(strlen(str) + 1); + if (retval != NULL) + strcpy(retval, str); + return(retval); +} /* string_dupe */ + + +static void set_sdl_renderer(void) +{ + const char *envr = getenv(BUILD_RENDERER); + +#ifdef USE_OPENGL + int need_opengl_lib = 1; +#endif + + if ((envr == NULL) || (strcmp(envr, ENVRSTR_RENDERER_SOFTWARE) == 0)) + renderer = RENDERER_SOFTWARE; + +#ifdef USE_OPENGL +#if 0 + else if (strcmp(envr, ENVRSTR_RENDERER_OPENGL3D) == 0) + { + renderer = RENDERER_OPENGL3D; + need_opengl_lib = 1; + } /* else if */ +#endif + +#endif + + else + { + fprintf(stderr, + "BUILDSDL: \"%s\" in the %s environment var is not available.\n", + envr, BUILD_RENDERER); + _exit(1); + } /* else */ + + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) == -1) + { + fprintf(stderr, "BUILDSDL: SDL_Init() failed!\n"); + fprintf(stderr, "BUILDSDL: SDL_GetError() says \"%s\".\n", SDL_GetError()); + exit(1); + } /* if */ + +#ifdef USE_OPENGL + if (need_opengl_lib) + { + if (opengl_load_library() == -1) + { + SDL_Quit(); + fprintf(stderr, "BUILDSDL/GL: Failed to load OpenGL library!\n"); + if (getenv(BUILD_SDLDEBUG) == NULL) + { + fprintf(stderr, "BUILDSDL/GL: Try setting environment variable" + " %s for more info.\n", BUILD_SDLDEBUG); + } /* if */ + _exit(42); + } /* if */ + } /* if */ +#endif + +} /* set_sdl_renderer */ + + +static void init_renderer_names(void) +{ + memset((void *) renderer_name, '\0', sizeof (renderer_name)); + renderer_name[RENDERER_SOFTWARE] = "RENDERER_SOFTWARE"; + renderer_name[RENDERER_OPENGL3D] = "RENDERER_OPENGL3D"; +} /* init_renderer_names */ + + +void set_splash(void) +{ + SDL_Surface *screen; + SDL_Surface *bmp = SDL_LoadBMP("splash.bmp"); + if (bmp == NULL) + return; + + putenv("SDL_VIDEO_WINDOW_POS=center"); + screen = SDL_SetVideoMode(bmp->w, bmp->h, 0, SDL_NOFRAME); + putenv("SDL_VIDEO_WINDOW_POS=nopref"); + + if (screen != NULL) + { + SDL_BlitSurface(bmp, NULL, screen, NULL); + SDL_Flip(screen); + } + + SDL_FreeSurface(bmp); +} /* set_splash */ + + +void _platform_init(int argc, char **argv, const char *title, const char *icon) +{ + #if (defined PLATFORM_MACOSX) + char buf[MAXPATHLEN]; + char realbuf[MAXPATHLEN]; + long cpufeature = 0; + OSErr err; + + has_altivec = 0; + err = Gestalt(gestaltPowerPCProcessorFeatures, &cpufeature); + if (err == noErr) + { + if ((1 << gestaltPowerPCHasVectorInstructions) & cpufeature) + has_altivec = 1; + } /* if */ + + /* deal with Application Bundles on MacOS X... */ + if ((argv[0] != NULL) && (strchr(argv[0], '/') != NULL)) + strcpy(buf, argv[0]); + else + { + if ((getcwd(buf, sizeof (buf)) == NULL) || (strcmp(buf, "/") == 0)) + buf[0] = '\0'; /* oh well. */ + } /* else */ + + if (buf[0]) + { + buf[sizeof (buf) - 1] = '\0'; + if (realpath(buf, realbuf) != NULL) + { + char *ptr = strstr(realbuf, "/Contents/MacOS/"); + if (ptr != NULL) + { + *ptr = '\0'; /* chop off bundle dirs... */ + chdir(realbuf); + } /* if */ + } /* if */ + } /* if */ + #endif + + _argc = argc; + _argv = argv; + + init_renderer_names(); + + init_debugging(); + + #if (defined USE_I386_ASM) + unprotect_ASM_pages(); + #endif + + if (title == NULL) + title = "BUILD"; + + if (icon == NULL) + icon = "BUILD"; + + titlelong = string_dupe(title); + titleshort = string_dupe(icon); + + if (getenv(BUILD_NOMOUSEGRAB) == NULL) + mouse_grabbed = 1; + else + mouse_grabbed = 0; + + sdl_flags = ((getenv(BUILD_WINDOWED) == NULL) ? SDL_FULLSCREEN : 0); + + sdl_flags |= SDL_HWPALETTE; + /*sdl_flags |= SDL_HWSURFACE; !!! */ + /*sdl_flags |= SDL_DOUBLEBUF; */ + + set_sdl_renderer(); + set_splash(); + + output_sdl_versions(); + output_driver_info(); + detect_vmware(); + + memset(scancodes, '\0', sizeof (scancodes)); + scancodes[SDLK_ESCAPE] = 0x01; + scancodes[SDLK_1] = 0x02; + scancodes[SDLK_2] = 0x03; + scancodes[SDLK_3] = 0x04; + scancodes[SDLK_4] = 0x05; + scancodes[SDLK_5] = 0x06; + scancodes[SDLK_6] = 0x07; + scancodes[SDLK_7] = 0x08; + scancodes[SDLK_8] = 0x09; + scancodes[SDLK_9] = 0x0A; + scancodes[SDLK_0] = 0x0B; + scancodes[SDLK_MINUS] = 0x0C; /* was 0x4A */ + scancodes[SDLK_EQUALS] = 0x0D; /* was 0x4E */ + scancodes[SDLK_BACKSPACE] = 0x0E; + scancodes[SDLK_TAB] = 0x0F; + scancodes[SDLK_q] = 0x10; + scancodes[SDLK_w] = 0x11; + scancodes[SDLK_e] = 0x12; + scancodes[SDLK_r] = 0x13; + scancodes[SDLK_t] = 0x14; + scancodes[SDLK_y] = 0x15; + scancodes[SDLK_u] = 0x16; + scancodes[SDLK_i] = 0x17; + scancodes[SDLK_o] = 0x18; + scancodes[SDLK_p] = 0x19; + scancodes[SDLK_LEFTBRACKET] = 0x1A; + scancodes[SDLK_RIGHTBRACKET] = 0x1B; + scancodes[SDLK_RETURN] = 0x1C; + scancodes[SDLK_LCTRL] = 0x1D; + scancodes[SDLK_a] = 0x1E; + scancodes[SDLK_s] = 0x1F; + scancodes[SDLK_d] = 0x20; + scancodes[SDLK_f] = 0x21; + scancodes[SDLK_g] = 0x22; + scancodes[SDLK_h] = 0x23; + scancodes[SDLK_j] = 0x24; + scancodes[SDLK_k] = 0x25; + scancodes[SDLK_l] = 0x26; + scancodes[SDLK_SEMICOLON] = 0x27; + scancodes[SDLK_QUOTE] = 0x28; + scancodes[SDLK_BACKQUOTE] = 0x29; + scancodes[SDLK_LSHIFT] = 0x2A; + scancodes[SDLK_BACKSLASH] = 0x2B; + scancodes[SDLK_z] = 0x2C; + scancodes[SDLK_x] = 0x2D; + scancodes[SDLK_c] = 0x2E; + scancodes[SDLK_v] = 0x2F; + scancodes[SDLK_b] = 0x30; + scancodes[SDLK_n] = 0x31; + scancodes[SDLK_m] = 0x32; + scancodes[SDLK_COMMA] = 0x33; + scancodes[SDLK_PERIOD] = 0x34; + scancodes[SDLK_SLASH] = 0x35; + scancodes[SDLK_RSHIFT] = 0x36; + scancodes[SDLK_KP_MULTIPLY] = 0x37; + scancodes[SDLK_LALT] = 0x38; + scancodes[SDLK_SPACE] = 0x39; + scancodes[SDLK_CAPSLOCK] = 0x3A; + scancodes[SDLK_F1] = 0x3B; + scancodes[SDLK_F2] = 0x3C; + scancodes[SDLK_F3] = 0x3D; + scancodes[SDLK_F4] = 0x3E; + scancodes[SDLK_F5] = 0x3F; + scancodes[SDLK_F6] = 0x40; + scancodes[SDLK_F7] = 0x41; + scancodes[SDLK_F8] = 0x42; + scancodes[SDLK_F9] = 0x43; + scancodes[SDLK_F10] = 0x44; + scancodes[SDLK_NUMLOCK] = 0x45; + scancodes[SDLK_SCROLLOCK] = 0x46; + scancodes[SDLK_KP7] = 0x47; + scancodes[SDLK_KP8] = 0x48; + scancodes[SDLK_KP9] = 0x49; + scancodes[SDLK_KP_MINUS] = 0x4A; + scancodes[SDLK_KP4] = 0x4B; + scancodes[SDLK_KP5] = 0x4C; + scancodes[SDLK_KP6] = 0x4D; + scancodes[SDLK_KP_PLUS] = 0x4E; + scancodes[SDLK_KP1] = 0x4F; + scancodes[SDLK_KP2] = 0x50; + scancodes[SDLK_KP3] = 0x51; + scancodes[SDLK_KP0] = 0x52; + scancodes[SDLK_KP_PERIOD] = 0x53; + scancodes[SDLK_F11] = 0x57; + scancodes[SDLK_F12] = 0x58; + scancodes[SDLK_PAUSE] = 0x59; /* SBF - technically incorrect */ + + /* Some AZERTY keys... */ + scancodes[SDLK_AMPERSAND] = 0x70; + scancodes[SDLK_QUOTEDBL] = 0x71; + scancodes[SDLK_LEFTPAREN] = 0x72; + scancodes[SDLK_EXCLAIM] = 0x73; + scancodes[SDLK_CARET] = 0x74; + scancodes[SDLK_DOLLAR] = 0x75; + scancodes[SDLK_WORLD_0] = 0x76; + scancodes[SDLK_WORLD_1] = 0x77; + scancodes[SDLK_WORLD_2] = 0x78; + scancodes[SDLK_WORLD_3] = 0x79; + scancodes[SDLK_WORLD_4] = 0x7A; + scancodes[SDLK_WORLD_5] = 0x7B; + scancodes[SDLK_RIGHTPAREN] = 0x7C; + scancodes[SDLK_COLON] = 0x7D; + scancodes[SDLK_LESS] = 0x7E; + + /* extended DOS scancodes... */ + scancodes[SDLK_KP_ENTER] = 0xE01C; + scancodes[SDLK_RCTRL] = 0xE01D; + scancodes[SDLK_KP_DIVIDE] = 0xE035; + scancodes[SDLK_PRINT] = 0xE037; /* SBF - technically incorrect */ + scancodes[SDLK_SYSREQ] = 0xE037; /* SBF - for windows... */ + scancodes[SDLK_RALT] = 0xE038; + scancodes[SDLK_HOME] = 0xE047; + scancodes[SDLK_UP] = 0xE048; + scancodes[SDLK_PAGEUP] = 0xE049; + scancodes[SDLK_LEFT] = 0xE04B; + scancodes[SDLK_RIGHT] = 0xE04D; + scancodes[SDLK_END] = 0xE04F; + scancodes[SDLK_DOWN] = 0xE050; + scancodes[SDLK_PAGEDOWN] = 0xE051; + scancodes[SDLK_INSERT] = 0xE052; + scancodes[SDLK_DELETE] = 0xE053; + + if (has_altivec) + sdldebug("CPU feature: Altivec\n"); +} /* _platform_init */ + + +int setvesa(long x, long y) +{ + fprintf(stderr, "setvesa() called in SDL driver!\n"); + exit(23); + return(0); +} /* setvesa */ + +int screencapture(char *_filename, char inverseit) +{ + char *ptr = NULL; + int fil = -1; + long i, bufplc, p, col, ncol, leng, numbytes, xres; + int captcnt; + size_t flen = strlen(_filename); + char *filename = alloca(flen + 1); + strcpy(filename, _filename); + + for (captcnt = 0; (captcnt <= 9999) && (fil == -1); captcnt++) + { + filename[flen-8] = ((captcnt/1000)%10)+48; + filename[flen-7] = ((captcnt/100)%10)+48; + filename[flen-6] = ((captcnt/10)%10)+48; + filename[flen-5] = (captcnt%10)+48; + fil = open(filename, O_BINARY|O_CREAT|O_EXCL|O_WRONLY, + S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH); + } + + if (fil == -1) + return -1; + + if (qsetmode == 200) + { + pcxheader[8] = ((xdim-1)&255); pcxheader[9] = (((xdim-1)>>8)&255); + pcxheader[10] = ((ydim-1)&255); pcxheader[11] = (((ydim-1)>>8)&255); + pcxheader[12] = (xdim&255); pcxheader[13] = ((xdim>>8)&255); + pcxheader[14] = (ydim&255); pcxheader[15] = ((ydim>>8)&255); + pcxheader[66] = (xdim&255); pcxheader[67] = ((xdim>>8)&255); + } + else + { + pcxheader[8] = ((640-1)&255); pcxheader[9] = (((640-1)>>8)&255); + pcxheader[10] = ((qsetmode-1)&255); pcxheader[11] = (((qsetmode-1)>>8)&255); + pcxheader[12] = (640&255); pcxheader[13] = ((640>>8)&255); + pcxheader[14] = (qsetmode&255); pcxheader[15] = ((qsetmode>>8)&255); + pcxheader[66] = (640&255); pcxheader[67] = ((640>>8)&255); + } + + write(fil,&pcxheader[0],128); + + if (qsetmode == 200) + { + ptr = (char *)frameplace; + numbytes = xdim*ydim; + xres = xdim; + } + else + { + numbytes = (mul5(qsetmode)<<7); + xres = 640; + } + + bufplc = 0; p = 0; + while (p < numbytes) + { +// koutp(97,kinp(97)|3); + + if (qsetmode == 200) { col = *ptr; p++; ptr++; } + else + { + col = readpixel(p); + p++; + if ((inverseit == 1) && (((col&7) == 0) || ((col&7) == 7))) col ^= 15; + } + + leng = 1; + + if (qsetmode == 200) ncol = *ptr; + else + { + ncol = readpixel(p); + if ((inverseit == 1) && (((ncol&7) == 0) || ((ncol&7) == 7))) ncol ^= 15; + } + + while ((ncol == col) && (p < numbytes) && (leng < 63) && ((p%xres) != 0)) + { + leng++; + + if (qsetmode == 200) { p++; ptr++; ncol = *ptr; } + else + { + p++; + ncol = readpixel(p); + if ((inverseit == 1) && (((ncol&7) == 0) || ((ncol&7) == 7))) ncol ^= 15; + } + } + + //koutp(97,kinp(97)&252); + + if ((leng > 1) || (col >= 0xc0)) + { + tempbuf[bufplc++] = (leng|0xc0); + if (bufplc == 4096) { bufplc = 0; if (write(fil,&tempbuf[0],4096) < 4096) { close(fil); return(-1); } } + } + tempbuf[bufplc++] = col; + if (bufplc == 4096) { bufplc = 0; if (write(fil,&tempbuf[0],4096) < 4096) { close(fil); return(-1); } } + } + + tempbuf[bufplc++] = 0xc; + if (bufplc == 4096) { bufplc = 0; if (write(fil,&tempbuf[0],4096) < 4096) { close(fil); return(-1); } } + + if (qsetmode == 200) + { + VBE_getPalette(0,256,&tempbuf[4096]); + for(i=0;i<256;i++) + { + tempbuf[bufplc++] = (tempbuf[(i<<2)+4096+2]<<2); + if (bufplc == 4096) { bufplc = 0; if (write(fil,&tempbuf[0],4096) < 4096) { close(fil); return(-1); } } + tempbuf[bufplc++] = (tempbuf[(i<<2)+4096+1]<<2); + if (bufplc == 4096) { bufplc = 0; if (write(fil,&tempbuf[0],4096) < 4096) { close(fil); return(-1); } } + tempbuf[bufplc++] = (tempbuf[(i<<2)+4096+0]<<2); + if (bufplc == 4096) { bufplc = 0; if (write(fil,&tempbuf[0],4096) < 4096) { close(fil); return(-1); } } + } + } + else + { + for(i=0;i<768;i++) + { + if (i < 48) + tempbuf[bufplc++] = (vgapal16[i]<<2); + else + tempbuf[bufplc++] = 0; + if (bufplc == 4096) { bufplc = 0; if (write(fil,&tempbuf[0],4096) < 4096) { close(fil); return(-1); } } + } + + } + + if (bufplc > 0) + if (write(fil,&tempbuf[0],bufplc) < bufplc) { close(fil); return(-1); } + + close(fil); + return(0); +} /* screencapture */ + + +void setvmode(int mode) +{ + int w = -1; + int h = -1; + + if (mode == 0x3) /* text mode. */ + { + SDL_QuitSubSystem(SDL_INIT_VIDEO); + return; + } /* if */ + + if (mode == 0x13) + { + w = 800; + h = 600; + } /* if */ + + else + { + fprintf(stderr, "setvmode(0x%x) is unsupported in SDL driver.\n", mode); + exit(13); + } /* if */ + + assert(w > 0); + assert(h > 0); + + go_to_new_vid_mode(-1, w, h); +} /* setvmode */ + + +int _setgamemode(char davidoption, long daxdim, long daydim) +{ +#ifdef USE_OPENGL + static int shown_gl_strings = 0; + int gl = using_opengl(); + if (gl) + sdl_flags |= SDL_OPENGL; +#endif + + if (daxdim > MAXXDIM || daydim > MAXYDIM) + { + daxdim = 1600; + daydim = 1200; + } + + if (in_egapalette) + restore256_palette(); + + go_to_new_vid_mode((int) davidoption, daxdim, daydim); + + #ifdef USE_OPENGL + if (gl) + { + if (!shown_gl_strings) + { + sgldebug("GL_VENDOR [%s]", (char *) dglGetString(GL_VENDOR)); + sgldebug("GL_RENDERER [%s]", (char *) dglGetString(GL_RENDERER)); + sgldebug("GL_VERSION [%s]", (char *) dglGetString(GL_VERSION)); + sgldebug("GL_EXTENSIONS [%s]", (char *) dglGetString(GL_EXTENSIONS)); + shown_gl_strings = 1; + } /* if */ + + dglViewport(0, 0, daxdim, daydim); + dglEnable(GL_TEXTURE_2D); + dglPixelTransferi(GL_MAP_COLOR, GL_TRUE); + dglPixelTransferi(GL_INDEX_SHIFT, 0); + dglPixelTransferi(GL_INDEX_OFFSET, 0); + dglClearDepth(1.0); + dglDepthFunc(GL_LESS); + dglEnable(GL_DEPTH_TEST); + dglShadeModel(GL_SMOOTH); + dglMatrixMode(GL_PROJECTION); + dglLoadIdentity(); + dglMatrixMode(GL_MODELVIEW); + } /* if */ + #endif + + qsetmode = 200; + last_render_ticks = SDL_GetTicks(); + return(0); +} /* setgamemode */ + + +void qsetmode640350(void) +{ + assert(0); + + #ifdef USE_OPENGL + if (using_opengl()) + sdl_flags |= SDL_OPENGL; + #endif + + go_to_new_vid_mode(-1, 640, 350); +} /* qsetmode640350 */ + + +void qsetmode640480(void) +{ + if (!in_egapalette) + set16color_palette(); + + #ifdef USE_OPENGL + if (using_opengl()) + sdl_flags |= SDL_OPENGL; + #endif + + go_to_new_vid_mode(-1, 640, 480); + pageoffset = 0; /* Make sure it goes to the right place - DDOI */ + fillscreen16(0L,8L,640L*144L); +} /* qsetmode640480 */ + + +static int get_dimensions_from_str(const char *str, long *_w, long *_h) +{ + char *xptr = NULL; + char *ptr = NULL; + long w = -1; + long h = -1; + + if (str == NULL) + return(0); + + xptr = strchr(str, 'x'); + if (xptr == NULL) + return(0); + + w = strtol(str, &ptr, 10); + if (ptr != xptr) + return(0); + + xptr++; + h = strtol(xptr, &ptr, 10); + if ( (*xptr == '\0') || (*ptr != '\0') ) + return(0); + + if ((w <= 1) || (h <= 1)) + return(0); + + if (_w != NULL) + *_w = w; + + if (_h != NULL) + *_h = h; + + return(1); +} /* get_dimensions_from_str */ + + +static __inline void get_max_screen_res(long *max_w, long *max_h) +{ + long w = DEFAULT_MAXRESWIDTH; + long h = DEFAULT_MAXRESHEIGHT; + const char *envr = getenv(BUILD_MAXSCREENRES); + + if (envr != NULL) + { + if (!get_dimensions_from_str(envr, &w, &h)) + { + sdldebug("User's resolution ceiling [%s] is bogus!", envr); + w = DEFAULT_MAXRESWIDTH; + h = DEFAULT_MAXRESHEIGHT; + } /* if */ + } /* if */ + + if (max_w != NULL) + *max_w = w; + + if (max_h != NULL) + *max_h = h; +} /* get_max_screen_res */ + + +static void add_vesa_mode(const char *typestr, int w, int h) +{ + sdldebug("Adding %s resolution (%dx%d).", typestr, w, h); + validmode[validmodecnt] = validmodecnt; + validmodexdim[validmodecnt] = w; + validmodeydim[validmodecnt] = h; + validmodecnt++; +} /* add_vesa_mode */ + + +/* Let the user specify a specific mode via environment variable. */ +static __inline void add_user_defined_resolution(void) +{ + long w; + long h; + const char *envr = getenv(BUILD_USERSCREENRES); + + if (envr == NULL) + return; + + if (get_dimensions_from_str(envr, &w, &h)) + add_vesa_mode("user defined", w, h); + else + sdldebug("User defined resolution [%s] is bogus!", envr); +} /* add_user_defined_resolution */ + + +static __inline SDL_Rect **get_physical_resolutions(void) +{ + const SDL_VideoInfo *vidInfo = SDL_GetVideoInfo(); + SDL_Rect **modes = SDL_ListModes(vidInfo->vfmt, sdl_flags | SDL_FULLSCREEN); + if (modes == NULL) + { + sdl_flags &= ~SDL_FULLSCREEN; + modes = SDL_ListModes(vidInfo->vfmt, sdl_flags); /* try without fullscreen. */ + if (modes == NULL) + modes = (SDL_Rect **) -1; /* fuck it. */ + } /* if */ + + if (modes == (SDL_Rect **) -1) + sdldebug("Couldn't get any physical resolutions."); + else + { + sdldebug("Highest physical resolution is (%dx%d).", + modes[0]->w, modes[0]->h); + } /* else */ + + return(modes); +} /* get_physical_resolutions */ + + +static void remove_vesa_mode(int index, const char *reason) +{ + int i; + + assert(index < validmodecnt); + sdldebug("Removing resolution #%d, %dx%d [%s].", + index, validmodexdim[index], validmodeydim[index], reason); + + for (i = index; i < validmodecnt - 1; i++) + { + validmode[i] = validmode[i + 1]; + validmodexdim[i] = validmodexdim[i + 1]; + validmodeydim[i] = validmodeydim[i + 1]; + } /* for */ + + validmodecnt--; +} /* remove_vesa_mode */ + + +static __inline void cull_large_vesa_modes(void) +{ + long max_w; + long max_h; + int i; + + get_max_screen_res(&max_w, &max_h); + sdldebug("Setting resolution ceiling to (%ldx%ld).", max_w, max_h); + + for (i = 0; i < validmodecnt; i++) + { + if ((validmodexdim[i] > max_w) || (validmodeydim[i] > max_h)) + { + remove_vesa_mode(i, "above resolution ceiling"); + i--; /* list shrinks. */ + } /* if */ + } /* for */ +} /* cull_large_vesa_modes */ + + +static __inline void cull_duplicate_vesa_modes(void) +{ + int i; + int j; + + for (i = 0; i < validmodecnt; i++) + { + for (j = i + 1; j < validmodecnt; j++) + { + if ( (validmodexdim[i] == validmodexdim[j]) && + (validmodeydim[i] == validmodeydim[j]) ) + { + remove_vesa_mode(j, "duplicate"); + j--; /* list shrinks. */ + } /* if */ + } /* for */ + } /* for */ +} /* cull_duplicate_vesa_modes */ + + +#define swap_macro(tmp, x, y) { tmp = x; x = y; y = tmp; } + +/* be sure to call cull_duplicate_vesa_modes() before calling this. */ +static __inline void sort_vesa_modelist(void) +{ + int i; + int sorted; + long tmp; + + do + { + sorted = 1; + for (i = 0; i < validmodecnt - 1; i++) + { + if ( (validmodexdim[i] >= validmodexdim[i+1]) && + (validmodeydim[i] >= validmodeydim[i+1]) ) + { + sorted = 0; + swap_macro(tmp, validmode[i], validmode[i+1]); + swap_macro(tmp, validmodexdim[i], validmodexdim[i+1]); + swap_macro(tmp, validmodeydim[i], validmodeydim[i+1]); + } /* if */ + } /* for */ + } while (!sorted); +} /* sort_vesa_modelist */ + + +static __inline void cleanup_vesa_modelist(void) +{ + cull_large_vesa_modes(); + cull_duplicate_vesa_modes(); + sort_vesa_modelist(); +} /* cleanup_vesa_modelist */ + + +static __inline void output_vesa_modelist(void) +{ + char buffer[256]; + char numbuf[20]; + int i; + + if (!_sdl_debug_file) + return; + + buffer[0] = '\0'; + + for (i = 0; i < validmodecnt; i++) + { + sprintf(numbuf, " (%ldx%ld)", + (long) validmodexdim[i], (long) validmodeydim[i]); + + if ( (strlen(buffer) + strlen(numbuf)) >= (sizeof (buffer) - 1) ) + strcpy(buffer + (sizeof (buffer) - 5), " ..."); + else + strcat(buffer, numbuf); + } /* for */ + + sdldebug("Final sorted modelist:%s", buffer); +} /* output_vesa_modelist */ + + +void getvalidvesamodes(void) +{ + static int already_checked = 0; + int i; + SDL_Rect **modes = NULL; + int stdres[][2] = { + {320, 200}, {320, 240}, {640, 350}, + {640, 480}, {800, 600}, {1024, 768} + }; + + if (already_checked) + return; + + already_checked = 1; + validmodecnt = 0; + vidoption = 1; /* !!! tmp */ + + /* fill in the standard resolutions... */ + for (i = 0; i < sizeof (stdres) / sizeof (stdres[0]); i++) + add_vesa_mode("standard", stdres[i][0], stdres[i][1]); + + /* Anything the hardware can specifically do is added now... */ + modes = get_physical_resolutions(); + for (i = 0; (modes != (SDL_Rect **) -1) && (modes[i] != NULL); i++) + add_vesa_mode("physical", modes[i]->w, modes[i]->h); + + /* Now add specific resolutions that the user wants... */ + add_user_defined_resolution(); + + /* get rid of dupes and bogus resolutions... */ + cleanup_vesa_modelist(); + + /* print it out for debugging purposes... */ + output_vesa_modelist(); +} /* getvalidvesamodes */ + + +int VBE_setPalette(long start, long num, char *palettebuffer) +/* + * (From Ken's docs:) + * Set (num) palette palette entries starting at (start) + * palette entries are in a 4-byte format in this order: + * 0: Blue (0-63) + * 1: Green (0-63) + * 2: Red (0-63) + * 3: Reserved + * + * Naturally, the bytes are in the reverse order that SDL wants them... + * More importantly, SDL wants the color elements in a range from 0-255, + * so we do a conversion. + */ +{ + SDL_Color fmt_swap[256]; + SDL_Color *sdlp = &fmt_swap[start]; + char *p = palettebuffer; + int i; + +#if (defined USE_OPENGL) + int gl = using_opengl(); + GLfloat gl_reds[256]; + GLfloat gl_greens[256]; + GLfloat gl_blues[256]; + GLfloat gl_alphas[256]; + + if (gl) + { + return 255; + dglGetPixelMapfv(GL_PIXEL_MAP_I_TO_R, gl_reds); + dglGetPixelMapfv(GL_PIXEL_MAP_I_TO_G, gl_greens); + dglGetPixelMapfv(GL_PIXEL_MAP_I_TO_B, gl_blues); + dglGetPixelMapfv(GL_PIXEL_MAP_I_TO_A, gl_alphas); + } /* if */ +#endif + + assert( (start + num) <= (sizeof (fmt_swap) / sizeof (SDL_Color)) ); + + for (i = 0; i < num; i++) + { + sdlp->b = (Uint8) ((((float) *p++) / 63.0) * 255.0); + sdlp->g = (Uint8) ((((float) *p++) / 63.0) * 255.0); + sdlp->r = (Uint8) ((((float) *p++) / 63.0) * 255.0); + sdlp->unused = *p++; /* This byte is unused in BUILD, too. */ + +#if (defined USE_OPENGL) + if (gl) + { + gl_reds[i+start] = ((GLfloat) sdlp->r) / 255.0f; + gl_greens[i+start] = ((GLfloat) sdlp->g) / 255.0f; + gl_blues[i+start] = ((GLfloat) sdlp->b) / 255.0f; + gl_alphas[i+start] = 1.0f; + } /* if */ +#endif + + sdlp++; + } /* for */ + +#if (defined USE_OPENGL) + if (gl) + { + dglPixelMapfv(GL_PIXEL_MAP_I_TO_R, start + num, gl_reds); + dglPixelMapfv(GL_PIXEL_MAP_I_TO_G, start + num, gl_greens); + dglPixelMapfv(GL_PIXEL_MAP_I_TO_B, start + num, gl_blues); + dglPixelMapfv(GL_PIXEL_MAP_I_TO_A, start + num, gl_alphas); + } /* if */ +#endif + + return(SDL_SetColors(surface, fmt_swap, start, num)); +} /* VBE_setPalette */ + + +int VBE_getPalette(long start, long num, char *palettebuffer) +{ + SDL_Color *sdlp = surface->format->palette->colors + start; + char *p = palettebuffer + (start * 4); + int i; + + for (i = 0; i < num; i++) + { + *p++ = (Uint8) ((((float) sdlp->b) / 255.0) * 63.0); + *p++ = (Uint8) ((((float) sdlp->g) / 255.0) * 63.0); + *p++ = (Uint8) ((((float) sdlp->r) / 255.0) * 63.0); + *p++ = sdlp->unused; /* This byte is unused in both SDL and BUILD. */ + sdlp++; + } /* for */ + + return(1); +} /* VBE_getPalette */ + + +void _uninitengine(void) +{ + SDL_QuitSubSystem(SDL_INIT_VIDEO); +} /* _uninitengine */ + + +void uninitvesa(void) +{ + SDL_QuitSubSystem(SDL_INIT_VIDEO); +} /* uninitvesa */ + + +int setupmouse(void) +{ + SDL_GrabMode mode = SDL_GRAB_OFF; + + if (surface == NULL) + return(0); + + if (mouse_grabbed) + mode = SDL_GRAB_ON; + + SDL_WM_GrabInput(mode); + SDL_ShowCursor(0); + + mouse_x = surface->w / 2; + mouse_y = surface->h / 2; + mouse_relative_x = mouse_relative_y = 0; + + /* + * this global usually gets set by BUILD, but it's a one-shot + * deal, and we may not have an SDL surface at that point. --ryan. + */ + moustat = 1; + + return(1); +} /* setupmouse */ + + +void readmousexy(short *x, short *y) +{ + if (x) *x = mouse_relative_x << 2; + if (y) *y = mouse_relative_y << 2; + + mouse_relative_x = mouse_relative_y = 0; +} /* readmousexy */ + + +void readmousebstatus(short *bstatus) +{ + if (bstatus) + *bstatus = mouse_buttons; + + // special wheel treatment + if(mouse_buttons&8) mouse_buttons ^= 8; + if(mouse_buttons&16) mouse_buttons ^= 16; + +} /* readmousebstatus */ + + +static unsigned char mirrorcolor = 0; + +void _updateScreenRect(long x, long y, long w, long h) +{ + if (renderer == RENDERER_SOFTWARE) + SDL_UpdateRect(surface, x, y, w, h); +} /* _updatescreenrect */ + + +void _nextpage(void) +{ + Uint32 ticks; + + handle_events(); + + if (renderer == RENDERER_SOFTWARE) + { + if (qsetmode == 200) + memcpy(surface->pixels, (const void *) frameplace, surface->w * surface->h); + SDL_UpdateRect(surface, 0, 0, 0, 0); + /*SDL_Flip(surface); !!! */ + } /* if */ + +#ifdef USE_OPENGL + else if (renderer == RENDERER_OPENGL3D) + { + opengl_swapbuffers(); + } /* else if */ +#endif + + if ((debug_hall_of_mirrors) && (qsetmode == 200) && (frameplace)) + { + memset((void *) frameplace, mirrorcolor, surface->w * surface->h); + mirrorcolor++; + } /* if */ + + ticks = SDL_GetTicks(); + total_render_time = (ticks - last_render_ticks); + if (total_render_time > 1000) + { + total_rendered_frames = 0; + total_render_time = 1; + last_render_ticks = ticks; + } /* if */ + total_rendered_frames++; +} /* _nextpage */ + + +unsigned char readpixel(long offset) +{ + return( *((unsigned char *) offset) ); +} /* readpixel */ + +void drawpixel(long offset, unsigned char pixel) +{ + *((unsigned char *) offset) = pixel; +} /* drawpixel */ + + +/* !!! These are incorrect. */ +void drawpixels(long offset, unsigned short pixels) +{ + Uint8 *surface_end; + Uint16 *pos; + + printf("Blargh!\n"); + exit(91); + + if (SDL_MUSTLOCK(surface)) + SDL_LockSurface(surface); + + surface_end = (((Uint8 *) surface->pixels) + (surface->w * surface->h)) - 2; + pos = (Uint16 *) (((Uint8 *) surface->pixels) + offset); + if ((pos >= (Uint16 *) surface->pixels) && (pos < (Uint16 *) surface_end)) + *pos = pixels; + + if (SDL_MUSTLOCK(surface)) + SDL_UnlockSurface(surface); +} /* drawpixels */ + + +void drawpixelses(long offset, unsigned int pixelses) +{ + Uint8 *surface_end; + Uint32 *pos; + + printf("Blargh!\n"); + exit(91); + + if (SDL_MUSTLOCK(surface)) + SDL_LockSurface(surface); + + surface_end = (((Uint8 *)surface->pixels) + (surface->w * surface->h)) - 2; + pos = (Uint32 *) (((Uint8 *) surface->pixels) + offset); + if ((pos >= (Uint32 *) surface->pixels) && (pos < (Uint32 *) surface_end)) + *pos = pixelses; + + if (SDL_MUSTLOCK(surface)) + SDL_UnlockSurface(surface); +} /* drawpixelses */ + + +/* Fix this up The Right Way (TM) - DDOI */ +void setcolor16(int col) +{ + drawpixel_color = col; +} + +void drawpixel16(long offset) +{ + drawpixel(((long) surface->pixels + offset), drawpixel_color); +} /* drawpixel16 */ + + +void fillscreen16(long offset, long color, long blocksize) +{ + Uint8 *surface_end; + Uint8 *wanted_end; + Uint8 *pixels; + +#if (defined USE_OPENGL) + if (renderer == RENDERER_OPENGL3D) + { + /* !!! dglClearColor() ... */ + return; + } /* if */ +#endif + + if (SDL_MUSTLOCK(surface)) + SDL_LockSurface(surface); + + pixels = get_framebuffer(); + + /* Make this function pageoffset aware - DDOI */ + if (!pageoffset) { + offset = offset << 3; + offset += 640*336; + } + + surface_end = (pixels + (surface->w * surface->h)) - 1; + wanted_end = (pixels + offset) + blocksize; + + if (offset < 0) + offset = 0; + + if (wanted_end > surface_end) + blocksize = ((unsigned long) surface_end) - ((unsigned long) pixels + offset); + + memset(pixels + offset, (int) color, blocksize); + + if (SDL_MUSTLOCK(surface)) + SDL_UnlockSurface(surface); + + _nextpage(); +} /* fillscreen16 */ + + +/* Most of this line code is taken from Abrash's "Graphics Programming Blackbook". +Remember, sharing code is A Good Thing. AH */ +static __inline void DrawHorizontalRun (char **ScreenPtr, int XAdvance, int RunLength, char Color) +{ + int i; + char *WorkingScreenPtr = *ScreenPtr; + + for (i=0; iw; + *ScreenPtr = WorkingScreenPtr; +} + +static __inline void DrawVerticalRun (char **ScreenPtr, int XAdvance, int RunLength, char Color) +{ + int i; + char *WorkingScreenPtr = *ScreenPtr; + + for (i=0; iw; + } + WorkingScreenPtr += XAdvance; + *ScreenPtr = WorkingScreenPtr; +} + +void drawline16(long XStart, long YStart, long XEnd, long YEnd, char Color) +{ + int Temp, AdjUp, AdjDown, ErrorTerm, XAdvance, XDelta, YDelta; + int WholeStep, InitialPixelCount, FinalPixelCount, i, RunLength; + char *ScreenPtr; + long dx, dy; + + if (SDL_MUSTLOCK(surface)) + SDL_LockSurface(surface); + + dx = XEnd-XStart; dy = YEnd-YStart; + if (dx >= 0) + { + if ((XStart > 639) || (XEnd < 0)) return; + if (XStart < 0) { if (dy) YStart += scale(0-XStart,dy,dx); XStart = 0; } + if (XEnd > 639) { if (dy) YEnd += scale(639-XEnd,dy,dx); XEnd = 639; } + } + else + { + if ((XEnd > 639) || (XStart < 0)) return; + if (XEnd < 0) { if (dy) YEnd += scale(0-XEnd,dy,dx); XEnd = 0; } + if (XStart > 639) { if (dy) YStart += scale(639-XStart,dy,dx); XStart = 639; } + } + if (dy >= 0) + { + if ((YStart >= ydim16) || (YEnd < 0)) return; + if (YStart < 0) { if (dx) XStart += scale(0-YStart,dx,dy); YStart = 0; } + if (YEnd >= ydim16) { if (dx) XEnd += scale(ydim16-1-YEnd,dx,dy); YEnd = ydim16-1; } + } + else + { + if ((YEnd >= ydim16) || (YStart < 0)) return; + if (YEnd < 0) { if (dx) XEnd += scale(0-YEnd,dx,dy); YEnd = 0; } + if (YStart >= ydim16) { if (dx) XStart += scale(ydim16-1-YStart,dx,dy); YStart = ydim16-1; } + } + + /* Make sure the status bar border draws correctly - DDOI */ + if (!pageoffset) { YStart += 336; YEnd += 336; } + + /* We'll always draw top to bottom */ + if (YStart > YEnd) { + Temp = YStart; + YStart = YEnd; + YEnd = Temp; + Temp = XStart; + XStart = XEnd; + XEnd = Temp; + } + + /* Point to the bitmap address first pixel to draw */ + ScreenPtr = (char *) (get_framebuffer()) + XStart + (surface->w * YStart); + + /* Figure out whether we're going left or right, and how far we're going horizontally */ + if ((XDelta = XEnd - XStart) < 0) + { + XAdvance = (-1); + XDelta = -XDelta; + } else { + XAdvance = 1; + } + + /* Figure out how far we're going vertically */ + YDelta = YEnd - YStart; + + /* Special cases: Horizontal, vertical, and diagonal lines */ + if (XDelta == 0) + { + for (i=0; i <= YDelta; i++) + { + *ScreenPtr = Color; + ScreenPtr += surface->w; + } + + UNLOCK_SURFACE_AND_RETURN; + } + if (YDelta == 0) + { + for (i=0; i <= XDelta; i++) + { + *ScreenPtr = Color; + ScreenPtr += XAdvance; + } + UNLOCK_SURFACE_AND_RETURN; + } + if (XDelta == YDelta) + { + for (i=0; i <= XDelta; i++) + { + *ScreenPtr = Color; + ScreenPtr += XAdvance + surface->w; + } + UNLOCK_SURFACE_AND_RETURN; + } + + /* Determine whether the line is X or Y major, and handle accordingly */ + if (XDelta >= YDelta) /* X major line */ + { + WholeStep = XDelta / YDelta; + AdjUp = (XDelta % YDelta) * 2; + AdjDown = YDelta * 2; + ErrorTerm = (XDelta % YDelta) - (YDelta * 2); + + InitialPixelCount = (WholeStep / 2) + 1; + FinalPixelCount = InitialPixelCount; + + if ((AdjUp == 0) && ((WholeStep & 0x01) == 0)) InitialPixelCount--; + if ((WholeStep & 0x01) != 0) ErrorTerm += YDelta; + + DrawHorizontalRun(&ScreenPtr, XAdvance, InitialPixelCount, Color); + + for (i=0; i<(YDelta-1); i++) + { + RunLength = WholeStep; + if ((ErrorTerm += AdjUp) > 0) + { + RunLength ++; + ErrorTerm -= AdjDown; + } + + DrawHorizontalRun(&ScreenPtr, XAdvance, RunLength, Color); + } + + DrawHorizontalRun(&ScreenPtr, XAdvance, FinalPixelCount, Color); + + UNLOCK_SURFACE_AND_RETURN; + } else { /* Y major line */ + WholeStep = YDelta / XDelta; + AdjUp = (YDelta % XDelta) * 2; + AdjDown = XDelta * 2; + ErrorTerm = (YDelta % XDelta) - (XDelta * 2); + InitialPixelCount = (WholeStep / 2) + 1; + FinalPixelCount = InitialPixelCount; + + if ((AdjUp == 0) && ((WholeStep & 0x01) == 0)) InitialPixelCount --; + if ((WholeStep & 0x01) != 0) ErrorTerm += XDelta; + + DrawVerticalRun(&ScreenPtr, XAdvance, InitialPixelCount, Color); + + for (i=0; i<(XDelta-1); i++) + { + RunLength = WholeStep; + if ((ErrorTerm += AdjUp) > 0) + { + RunLength ++; + ErrorTerm -= AdjDown; + } + + DrawVerticalRun(&ScreenPtr, XAdvance, RunLength, Color); + } + + DrawVerticalRun(&ScreenPtr, XAdvance, FinalPixelCount, Color); + UNLOCK_SURFACE_AND_RETURN; + } +} /* drawline16 */ + + +void clear2dscreen(void) +{ + SDL_Rect rect; + + rect.x = rect.y = 0; + rect.w = surface->w; + + if (qsetmode == 350) + rect.h = 350; + else if (qsetmode == 480) + { + if (ydim16 <= 336) + rect.h = 336; + else + rect.h = 480; + } /* else if */ + + SDL_FillRect(surface, &rect, 0); +} /* clear2dscreen */ + + +void _idle(void) +{ + if (surface != NULL) + handle_events(); + SDL_Delay(1); +} /* _idle */ + +void *_getVideoBase(void) +{ + return((void *) surface->pixels); +} + +void setactivepage(long dapagenum) +{ + /* !!! Is this really still needed? - DDOI */ + /*fprintf(stderr, "%s, line %d; setactivepage(): STUB.\n", __FILE__, __LINE__);*/ +} /* setactivepage */ + +void limitrate(void) +{ + /* this is a no-op in SDL. It was for buggy VGA cards in DOS. */ +} /* limitrate */ + +static Uint32 _timer_catcher(Uint32 interval, void *bleh) +{ + timerhandler(); + return(1); +} /* _timer_catcher */ + +void inittimer(void) +{ + SDL_ClearError(); + primary_timer = SDL_AddTimer(1000 / PLATFORM_TIMER_HZ, _timer_catcher, NULL); + if (primary_timer == NULL) + { + fprintf(stderr, "BUILDSDL: -ERROR- Problem initializing primary timer!\n"); + fprintf(stderr, "BUILDSDL: Reason: [%s]\n", SDL_GetError()); + SDL_Quit(); + exit(2); + } /* if */ +} + +void uninittimer(void) +{ + if (primary_timer != NULL) + { + SDL_RemoveTimer(primary_timer); + primary_timer = NULL; + } /* if */ +} + +void initkeys(void) +{ + /* does nothing in SDL. Key input handling is set up elsewhere. */ + /* !!! why not here? */ +} + +void uninitkeys(void) +{ + /* does nothing in SDL. Key input handling is set up elsewhere. */ +} + +void set16color_palette(void) +{ + /* Backup old palette */ + /*VBE_getPalette (0, 16, (char *)&backup_palette);*/ + memcpy (&backup_palette, &palette, 16*3); + + /* Set new palette */ + /*VBE_setPalette (0, 16, (char *)&egapalette);*/ + memcpy (&palette, &egapalette, 16*3); + in_egapalette = 1; +} /* set16color_palette */ + +void restore256_palette(void) +{ + /*VBE_setPalette (0, 16, (char *)&backup_palette);*/ + memcpy (&palette, &backup_palette, 16*3); + in_egapalette = 0; +} /* restore256_palette */ + +unsigned long getticks(void) +{ + return(SDL_GetTicks()); +} /* getticks */ + +/* end of sdl_driver.c ... */ + diff --git a/buildengine/setup.dat b/buildengine/setup.dat new file mode 100755 index 0000000..07418a5 Binary files /dev/null and b/buildengine/setup.dat differ diff --git a/buildengine/sreadme.txt b/buildengine/sreadme.txt new file mode 100755 index 0000000..194c5f0 --- /dev/null +++ b/buildengine/sreadme.txt @@ -0,0 +1,185 @@ +// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman +// Ken Silverman's official web site: "http://www.advsys.net/ken" +// See the included license file "BUILDLIC.TXT" for license info. + +All of my Build Engine code is designed specifically for the Watcom C/C++ 11.0 +compiler. You're on your own if you attempt to use any other compiler. + +To best view my source, set your "Tab Stops" to 3! + +--------------- Engine files required to compile a Build game --------------- + +ENGINE.C: All the major C code is in here + Graphics functions: + Function to draw everything in the 3D view + Function to draw the 2D texturized map view + Function to draw status bar pieces + Function to change screen size (+, -, Field of view (shrunk mode)) + Line drawing for both 2D and 3D modes + Simple 8*8 and 3*5 font routines (mostly used in BUILD editor) + Screen capture PCX code + Functions to load palette + Functions to set video modes + Function to flip screen pages + Function to generate palette lookup tables + Function to set gamma correction + Functions to help with mirrors (they weren't fully built in to the engine) + Stereoscopic modes (red blue glasses, Crystal Eyes, Nuvision) + Movement functions: + Function to detect if 2 points can see each other + Function to find where an instant weapon (pistol, shotgun, chaingun) hits + Function to determine if you're near a tagged object + Collision detection for all sprites (with smooth sliding) + Collision detection to keep you away from moving objects + Boring functions: + Functions to load/save MAP files + Function to load ART file + Disk caching system + Functions to manipulate sprite linked lists + Helper functions: + A couple of line intersection functions + A couple of math routines like faster atan2, sqrt, 2D rotation + Functions to help with animation of certain doors & tiles + Function to move vertices connected to many walls + A function that returns what sector something is in + Some Build editor functions also used in games + +CACHE1D.C: + Contains a unique LRU-style caching system + Group file code to handle all file loading transparently + Compression & Decompression routines used in .DMO files + +A.ASM: (pure assembly routines) + 8 routines for horizontal texture mapping, special cases for + masked mapping, translucent masked mapping, and # pixels at a time + 11 routines for vertical texture mapping, special cases for + masked mapping, translucent masked mapping, # pixels at a time, + slopes, voxels + + NOTE: This assembly code is designed for WASM (the assembler that ships + with Watcom C/C++ 11.0) In order to make it work under MASM, you will + have to make some simple modifications: + + 1. At the top of the file, change ".586P" to ".386P" + + 2. If the assembler complains that a jump is out of range, go to the + line of the error and remove the word "short" from the line. For + example, change: "jnc short mylabel" to just: "jnc mylabel" + + 3. If you get an error message like: "Symbol not defined: XE9", you + need to convert the value to a hex format that the assembler + understands. For example, change "mov al, 0xe9" to: "mov al, 0e9h" + (You need an extra 0 in front if the left-most digit is a letter) + +BUILD.H: + Sector, Wall, Sprite structures, defines and other documented shared + variables. While I designed the format of the structures, the "game" + developers were very involved with what went into them. + +PRAGMAS.H: + Tons of Watcom in-line assembly pragmas, such as 64-bit multiply and + divide routines, memory clear & move, and a lot of cute ones for doing + math, etc. + +VES2.H: + VESA 2.0 routines used by the Build engine. This code unfortunately is + somewhat integrated with ENGINE.C (only in the DOS version, now. --ryan.) + +MMULTI.C: + Contains mid-level network routines. This file arbitrated between + COMMIT and the game code. I had to write error correction in this + module because COMMIT didn't have it. + + NOTE: By default, my Build test uses MULTI.C instead of MMULTI.C. My game + is the only Build game that does this; all commercial Build games use + MMULTI.C. + + You can use the COMMIT driver with my test game. You will probably find + that there are more problems in general - this is not because MMULTI.C + or COMMIT are bad; it's because I always used MULTI.C by default with + my Build game. (I used my 2DRAW engine to test the MMULTI.C code.) + Follow these instructions exactly if you want to use MMULTI.C: + + 1. In the makefile, replace all occurrences of "multi" with "mmulti" + + 2. In GAME.C, on line 448, Remove the comment in front of the call to + waitforeverybody(). This needs to be done because my MMULTI.C code + doesn't have a "sendlogon" function. You will get severe lag if you + forget to do this. + + 3. To run the game, you must first setup BOTH setup programs (on ALL + computers) + + A) First edit the parameters inside COMMIT.DAT to match your desired + multiplayer configuration. + + B) Then go into my Build setup program. Under the communications + menu, set the NUMBER OF PLAYERS. For a COMMIT game, the specific + ports, etc. have no effect and don't really matter. Press ENTER + a few times to get through the rest of the menus. I know this + seems silly, but at the time, it seemed like the simplest way to + get my GAME.C code to work with both MULTI.C and MMULTI.C. + +-------- Additional source required to compile Ken's Build test game -------- + +GAME.C: + Sample code for a complete game. Well it's not really complete unless + you loved Ken's Labyrinth. This code wasn't actually used in the + distributed games, but it was an important code base for the developers + to look at when they had questions. Some of their routines were lifted + straight from this code. + +NAMES.H: EDITART updates this file every time you type in a name. This .H + file is just a convenient way to access textures inside the game code. + +MULTI.C: Before I added support for COMMIT, I had my own COM/network routines. + This file is almost identical to MMULTI.C. You will have to change a few + minor things like function parameters if you want to update my game to use + MMULTI.C & COMMIT instead. + +KDMENG.C: KDM (Ken's Digital Music) sound playback engine, C code +K.ASM: KDM (Ken's Digital Music) sound playback engine, Assembly code + +----------- Additional source required to compile the Build editor ---------- + +BUILD.C: + Combine this code with the engine and you get the Build editor. You will + find all of the editing functions from the Build editor in here (2D and 3D) + +BSTUB.C: + Game teams were able to customize certain things in the Build editor with + this module. + +--------------------------------- Make file --------------------------------- + + You can use my makefile if you wish - it shows you my compile options: +MAKEFILE.: A very simple make file. + Type: "wmake" or "wmake game.exe" to compile my build test game + Type: "wmake build.exe" to compile my build editor + +------------------------------- Documentation ------------------------------- + + This is the documentation I wrote for the game programmers. Please keep in + mind that I never gave out the source to my engine (ENGINE.C, CACHE1D.C, + VES2.H, A.ASM) I gave them only OBJ's and my GAME.C code to play with. + These text files mainly tell how to USE my engine, not how to write one. + +BUILDINF.TXT: This text file has the most up-to-date function descriptions. + You should look in here first before searching through the old stuff in + BUILD.TXT and BUILD2.TXT. + +BUILD.TXT: This is my original documentation that I sent along with the + all my library updates to my Build engine. A lot of the information in + here is redundant with BUILDINF.TXT, but I decided to include it anyway + because the history section has a lot of interesting things in it that + reveal how and why I designed things the way I did. + + PLEASE NOTE: The documentation at the top of BUILD.TXT is NOT up to date. + Many of the function parameters are missing or out of order. Use + BUILDINF.TXT (or my website :) for the latest function descriptions. + +BUILD2.TXT: When BUILD.TXT didn't fit in the memory of my old text editor, + I started this new file. + +------------------------------------------------------------------------------- +-Ken S. (web page: http://www.advsys.net/ken) diff --git a/buildengine/stuff.dat b/buildengine/stuff.dat new file mode 100755 index 0000000..c2020b5 Binary files /dev/null and b/buildengine/stuff.dat differ diff --git a/buildengine/test.map b/buildengine/test.map new file mode 100755 index 0000000..3d7fbe1 Binary files /dev/null and b/buildengine/test.map differ diff --git a/buildengine/tests/Makefile b/buildengine/tests/Makefile new file mode 100755 index 0000000..e3857ca --- /dev/null +++ b/buildengine/tests/Makefile @@ -0,0 +1,28 @@ +BINARIES=sartest kreciptest +OBJS=kreciptest.o krecip.o sartest.o sar.o +CFLAGS=-g -Wall +CC=gcc +ASM=nasm + +all: kreciptest sartest + +kreciptest: kreciptest.o krecip.o sar.o + $(CC) $(CFLAGS) -o kreciptest kreciptest.o krecip.o sar.o + +kreciptest.o: kreciptest.c + $(CC) $(CFLAGS) -c kreciptest.c + +krecip.o: krecip.asm + $(ASM) -o krecip.o -f elf krecip.asm + +sartest: sartest.o sar.o + $(CC) $(CFLAGS) -o sartest sartest.o sar.o + +sartest.o: + $(CC) $(CFLAGS) -c sartest.c + +sar.o: sar.c sar.h + $(CC) $(CFLAGS) -c sar.c + +clean: + rm -f *~ core $(BINARIES) $(OBJS) diff --git a/buildengine/tests/compressiontest.c b/buildengine/tests/compressiontest.c new file mode 100755 index 0000000..758f13c --- /dev/null +++ b/buildengine/tests/compressiontest.c @@ -0,0 +1,39 @@ +#include +#include +#include + +#include "engine_protos.h" + +void setvmode(int x) { } + +#define CACHESIZE ((1024 * 1024) * 4) + +int main(int argc, char **argv) +{ + FILE *f = fopen("buildinf.txt", "rb"); + long len = filelength(fileno(f)); + char *inbuf = (char *) malloc(len); + char *cmpbuf = (char *) malloc(len); + char *cachebuf = (char *) malloc(CACHESIZE); + fread(inbuf, len, 1, f); + fclose(f); + + initcache((long) cachebuf, CACHESIZE); + + f = fopen("buildinf.txt.kz", "wb"); + dfwrite(inbuf, len, 1, f); + fclose(f); + + memset(cmpbuf, '\0', len); + f = fopen("buildinf.txt.kz", "rb"); + dfread(cmpbuf, len, 1, f); + fclose(f); + remove("buildinf.txt.kz"); + + printf("%s\n", (memcmp(inbuf, cmpbuf, len) == 0) ? "passed" : "failed"); + + free(inbuf); + free(cmpbuf); + return(0); +} + diff --git a/buildengine/tests/krecip.asm b/buildengine/tests/krecip.asm new file mode 100755 index 0000000..c20ba95 --- /dev/null +++ b/buildengine/tests/krecip.asm @@ -0,0 +1,48 @@ +; ************************ +; ** Start Data Block ** +; ************************ +SECTION .data +extern fpuasm +extern reciptable + +global _asm_krecipasm +; ************************ +; ** Start Code Block ** +; ************************ +SEGMENT .text + +; Ignore all the 'offset's in the code AH +%idefine offset + +ALIGN 16 +; "mov fpuasm, eax",\ +; "fild dword ptr fpuasm",\ +; "add eax, eax",\ +; "fstp dword ptr fpuasm",\ +; "sbb ebx, ebx",\ +; "mov eax, fpuasm",\ +; "mov ecx, eax",\ +; "and eax, 0x007ff000",\ +; "shr eax, 10",\ +; "sub ecx, 0x3f800000",\ +; "shr ecx, 23",\ +; "mov eax, dword ptr reciptable[eax]",\ +; "sar eax, cl",\ +; "xor eax, ebx",\ + +_asm_krecipasm: + mov [fpuasm], eax ; Store parameter to memory + fild dword [fpuasm] ; Convert the 32-bit int to a fp + add eax, eax ; Double the int param's value + fstp dword [fpuasm] ; Put the 32-bit float to memory + sbb ebx, ebx ; Puts 0 - (carry bit) into ebx AFFECTED BY "add eax eax"!!! + mov eax, dword [fpuasm] + mov ecx, eax + and eax, 007ff000h + shr eax, 10 + sub ecx, 03f800000h + shr ecx, 23 + mov eax, dword [reciptable + eax] + sar eax, cl + xor eax, ebx + ret \ No newline at end of file diff --git a/buildengine/tests/kreciptest.c b/buildengine/tests/kreciptest.c new file mode 100755 index 0000000..586fe4f --- /dev/null +++ b/buildengine/tests/kreciptest.c @@ -0,0 +1,78 @@ +#include +#include +#include "sar.h" + +/*extern int _asm_krecipasm (int);*/ +int reciptable[2048], fpuasm; +void init (void) +{ + int i; + for(i=0;i<2048;i++) reciptable[i] = i;/* divscale30(2048L,i+2048);*/ +} + +static int krecipasm(int i1) +{ + int retval; + __asm__ __volatile__ (" + call _asm_krecipasm + " : "=a" (retval) : "a" (i1) + : "cc", "ebx", "ecx", "memory"); + return(retval); +} // krecipasm + +static int ansi_c_krecip (int x) +{ + float xf; + int z; + int not; + + if (x & 0x80000000) /* If the highest bit is set... */ + not = 0x0FFFFFFFF; + else + not = 0; + + xf = (float)x;/* convert the int to a float */ + + /* Pretend the float is an int so we can extract bits */ + x = *((int*)(&xf)); + z = x; + + x = x & 0x007FF000;/* Mask out: 11 << 13 */ + x = x >> 10; /* Divide x by 1024 */ + /* X now contains: 13 high order bits of the mantissa, followed by two 0 bits */ + + /* Now we perform an elaborate extraction + of the exponent from the floating point + numer? WTF is the subtraction for? */ + z = z - 0x03F800000;/* Subtract (127<<23) */ + z = z >> 23; + + /* z now contains the exponent divided by two? */ + x = shift_algebraic_right(reciptable[(x>>2)], z) ^ not; + return x; +} + +static int mykrecipasm(int i1) +{ + int retval; + retval = ansi_c_krecip(i1); + return retval; +} + +int main (int argc, char** argv) +{ + int u; + + init(); + printf("sizeof(long) = %u, sizeof(int) = %u\n", + sizeof(long int), sizeof(int)); + + u = 0; + while(scanf("%d", &u) >= 1){ + printf("Original: %d \tMine: %d\n", + krecipasm(u),mykrecipasm(u)); + u = 0; + } + + return 0; +} diff --git a/buildengine/tests/sar.c b/buildengine/tests/sar.c new file mode 100755 index 0000000..345d4b3 --- /dev/null +++ b/buildengine/tests/sar.c @@ -0,0 +1,25 @@ +#include "sar.h" +/* + SAR Sign extension table + + 256 byte table +*/ +int hbits[64] = +{ + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x80000000,0xC0000000,0xE0000000,0xF0000000, + 0xF8000000,0xFC000000,0xFE000000,0xFF000000, + 0xFF800000,0xFFC00000,0xFFE00000,0xFFF00000, + 0xFFF80000,0xFFFC0000,0xFFFE0000,0xFFFF0000, + 0xFFFF8000,0xFFFFC000,0xFFFFE000,0xFFFFF000, + 0xFFFFF800,0xFFFFFC00,0xFFFFFE00,0xFFFFFF00, + 0xFFFFFF80,0xFFFFFFC0,0xFFFFFFE0,0xFFFFFFF0, + 0xFFFFFFF8,0xFFFFFFFC,0xFFFFFFFE,0xFFFFFFFF +}; diff --git a/buildengine/tests/sar.h b/buildengine/tests/sar.h new file mode 100755 index 0000000..e93d0bf --- /dev/null +++ b/buildengine/tests/sar.h @@ -0,0 +1,10 @@ +#ifndef COMPAT_SAR_H +#define COMPAT_SAR_H 1 + +extern int hbits[64]; + +#define shift_algebraic_right(value,distance) \ +(((value) >> (distance))| \ + (hbits[(distance) + (((value) & 0x80000000) >> 26)])) + +#endif /* COMPAT_SAR_H */ diff --git a/buildengine/tests/sartest.c b/buildengine/tests/sartest.c new file mode 100755 index 0000000..4eef1fb --- /dev/null +++ b/buildengine/tests/sartest.c @@ -0,0 +1,19 @@ +#include +#include +#include "sar.h" + +int main (int argc, char** argv) +{ + unsigned int u,v; + + u = 0; + v = 0; + while(scanf("%x %u\n", &u, &v) >= 2){ + + printf("0x%.8x\n", shift_algebraic_right(u, v)); + u = 0; + v = 0; + } + + return 0; +} diff --git a/buildengine/unix_compat.c b/buildengine/unix_compat.c new file mode 100755 index 0000000..e139fed --- /dev/null +++ b/buildengine/unix_compat.c @@ -0,0 +1,102 @@ +/* + * Unix compatibility code. Takes care of some legacy code issues. + * + * Written by Ryan C. Gordon (icculus@clutteredmind.org) + * + * Please do NOT harrass Ken Silverman about any code modifications + * (including this file) to BUILD. + */ + +/* + * "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman + * Ken Silverman's official web site: "http://www.advsys.net/ken" + * See the included license file "BUILDLIC.TXT" for license info. + * This file IS NOT A PART OF Ken Silverman's original release + */ + +#ifndef PLATFORM_UNIX +#error Please define PLATFORM_UNIX to use this code. +#endif + +#include +#include +#include +#include +#include +#include "unix_compat.h" + +/* + 256 byte table to assist in performing an + algebraic shift right. These values represent + all possible contributions of the sign bit + when shifted by different values. + */ +const int hbits[64] = +{ + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000, + 0x80000000,0xC0000000,0xE0000000,0xF0000000, + 0xF8000000,0xFC000000,0xFE000000,0xFF000000, + 0xFF800000,0xFFC00000,0xFFE00000,0xFFF00000, + 0xFFF80000,0xFFFC0000,0xFFFE0000,0xFFFF0000, + 0xFFFF8000,0xFFFFC000,0xFFFFE000,0xFFFFF000, + 0xFFFFF800,0xFFFFFC00,0xFFFFFE00,0xFFFFFF00, + 0xFFFFFF80,0xFFFFFFC0,0xFFFFFFE0,0xFFFFFFF0, + 0xFFFFFFF8,0xFFFFFFFC,0xFFFFFFFE,0xFFFFFFFF +}; + + +#ifndef DC +int stricmp(const char *x, const char *y) +{ + int ux, uy; + + do + { + ux = toupper((int) *x); + uy = toupper((int) *y); + if (ux > uy) + return(1); + else if (ux < uy) + return(-1); + x++; + y++; + } while ((ux) && (uy)); + + return(0); +} /* stricmp */ +#endif /* DC */ + +long filelength(int fhandle) +{ + long retval = -1; + struct stat stat_buf; + if (fstat(fhandle, &stat_buf) == 0) + retval = (long) stat_buf.st_size; + return(retval); +} /* filelength */ + + +/* !!! remove me later! */ +int _inp_handler(int port, char *source_file, int source_line) +{ + fprintf(stderr, "inp(0x%X) call in %s, line %d.\n", port, source_file, source_line); + return(0); +} /* _inp_handler */ + + +/* !!! remove me later! */ +int _kinp_handler(int port, char *source_file, int source_line) +{ + fprintf(stderr, "kinp(0x%X) call in %s, line %d.\n", port, source_file, source_line); + return(0); +} /* _kinp_handler */ + +/* end of unix_compat.c ... */ + diff --git a/buildengine/unix_compat.h b/buildengine/unix_compat.h new file mode 100755 index 0000000..1d2a99c --- /dev/null +++ b/buildengine/unix_compat.h @@ -0,0 +1,132 @@ +/* + * Unix compatibility header. Takes care of some legacy code issues. + * + * Written by Ryan C. Gordon (icculus@clutteredmind.org) + * + * Please do NOT harrass Ken Silverman about any code modifications + * (including this file) to BUILD. + */ + +/* + * "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman + * Ken Silverman's official web site: "http://www.advsys.net/ken" + * See the included license file "BUILDLIC.TXT" for license info. + * This file IS NOT A PART OF Ken Silverman's original release + */ + +#ifndef _INCLUDE_UNIX_COMPAT_H_ +#define _INCLUDE_UNIX_COMPAT_H_ + +#if (!defined PLATFORM_UNIX) +#error PLATFORM_UNIX is not defined. +#endif + +#define __int64 long long + +#define PLATFORM_SUPPORTS_SDL + +#include +#include +#include +#include +#include + +extern const int hbits[]; + +/* + Do some bitwise magic to approximate an algebraic (sign preserving) + right shift. + */ +#define shift_algebraic_right(value,distance) \ +(((value) >> (distance))| \ + (hbits[(distance) + (((value) & 0x80000000) >> 26)])) + +/* !!! remove me later! */ +/* !!! remove me later! */ +/* !!! remove me later! */ +#define outpw(x, y) printf("outpw(0x%X, 0x%X) call in %s, line %d.\n", \ + (x), (y), __FILE__, __LINE__) + +#define koutpw(x, y) printf("koutpw(0x%X, 0x%X) call in %s, line %d.\n", \ + (x), (y), __FILE__, __LINE__) + +#define outb(x, y) printf("outb(0x%X, 0x%X) call in %s, line %d.\n", \ + (x), (y), __FILE__, __LINE__) + +#define koutb(x, y) printf("koutb(0x%X, 0x%X) call in %s, line %d.\n", \ + (x), (y), __FILE__, __LINE__) + +#define outp(x, y) printf("outp(0x%X, 0x%X) call in %s, line %d.\n", \ + (x), (y), __FILE__, __LINE__) + +#define koutp(x, y) +/* !!! */ + /*printf("koutp(0x%X, 0x%X) call in %s, line %d.\n", + // (x), (y), __FILE__, __LINE__) */ + +#define kinp(x) _kinp_handler((x), __FILE__, __LINE__) +#define inp(x) _inp_handler((x), __FILE__, __LINE__) + +int _inp_handler(int port, char *source_file, int source_line); +int _kinp_handler(int port, char *source_file, int source_line); +/* !!! remove me later! */ +/* !!! remove me later! */ +/* !!! remove me later! */ + + + + +#define __far +#define __interrupt +#define interrupt +#define far +#define kmalloc(x) malloc(x) +#define kkmalloc(x) malloc(x) +#define kfree(x) free(x) +#define kkfree(x) free(x) +#define FP_OFF(x) ((long) (x)) + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +/* damned -ansi flag... :) */ +int stricmp(const char *x, const char *y); + +#if (defined __STRICT_ANSI__) +#define inline __inline__ +#endif + +#define printext16 printext256 +#define printext16_noupdate printext256_noupdate + +/* Other DOSisms. See unix_compat.c for implementation. */ +long filelength(int fhandle); + +/* !!! need an implementation of findfirst()/findnext()! */ +/* Look for references to _dos_findfirst() in build.c! */ + +#if (!defined S_IREAD) +#define S_IREAD S_IRUSR +#endif + +#ifdef DC //bero +#undef stdout +#undef stderr +#define stdout ((FILE*)2) +#define stderr ((FILE*)2) +#endif + +#ifndef max +#define max(x, y) (((x) > (y)) ? (x) : (y)) +#endif + +#ifndef min +#define min(x, y) (((x) < (y)) ? (x) : (y)) +#endif + +#endif + +/* end of unix_compat.h ... */ + + diff --git a/buildengine/utils/BUILDLIC.TXT b/buildengine/utils/BUILDLIC.TXT new file mode 100755 index 0000000..939a6f4 --- /dev/null +++ b/buildengine/utils/BUILDLIC.TXT @@ -0,0 +1,77 @@ +(Note from Ryan: This is Ken's BUILD license. It is NOT GPL. Please respect + his license, and also keep in mind that Ken does NOT work on the Linux port. + Please don't harrass him for bug fixes and enhancements to the Linux version. + He did the DOS version. --ryan.) + + +BUILD SOURCE CODE LICENSE TERMS: 06/20/2000 + +[1] I give you permission to make modifications to my Build source and + distribute it, BUT: + +[2] Any derivative works based on my Build source may be distributed ONLY + through the INTERNET. + +[3] Distribution of any derivative works MUST be done completely FREE of + charge - no commercial exploitation whatsoever. + +[4] Anything you distribute which uses a part of my Build Engine source + code MUST include: + + [A] The following message somewhere in the archive: + + // "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman + // Ken Silverman's official web site: "http://www.advsys.net/ken" + // See the included license file "BUILDLIC.TXT" for license info. + + [B] This text file "BUILDLIC.TXT" along with it. + + [C] Any source files that you modify must include this message as well: + + // This file has been modified from Ken Silverman's original release + +[5] The use of the Build Engine for commercial purposes will require an + appropriate license arrangement with me. Contact information is + on my web site. + +[6] I take no responsibility for damage to your system. + +[7] Technical support: Before contacting me with questions, please read + and do ALL of the following! + + [A] Look through ALL of my text files. There are 7 of them (including this + one). I like to think that I wrote them for a reason. You will find + many of your answers in the history section of BUILD.TXT and + BUILD2.TXT (they're located inside SRC.ZIP). + + [B] If that doesn't satisfy you, then try going to: + + "http://www.advsys.net/ken/buildsrc" + + where I will maintain a Build Source Code FAQ (or perhaps I might + just provide a link to a good FAQ). + + [C] I am willing to respond to questions, but ONLY if they come at a rate + that I can handle. + + PLEASE TRY TO AVOID ASKING DUPLICATE QUESTIONS! + + As my line of defense, I will post my current policy about + answering Build source questions (right below the E-mail address + on my web site.) You can check there to see if I'm getting + overloaded with questions or not. + + If I'm too busy, it might say something like this: + + I'm too busy to answer Build source questions right now. + Sorry, but don't expect a reply from me any time soon. + + If I'm open for Build source questions, please state your question + clearly and don't include any unsolicited attachments unless + they're really small (like less than 50k). Assume that I have + a 28.8k modem. Also, don't leave out important details just + to make your question appear shorter - making me guess what + you're asking doesn't save me time! + +---------------------------------------------------------------------------- +-Ken S. (official web site: http://www.advsys.net/ken) diff --git a/buildengine/utils/CHANGELOG b/buildengine/utils/CHANGELOG new file mode 100755 index 0000000..a248833 --- /dev/null +++ b/buildengine/utils/CHANGELOG @@ -0,0 +1,31 @@ +// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman +// Ken Silverman's official web site: "http://www.advsys.net/ken" +// See the included license file "BUILDLIC.TXT" for license info. + +CHANGELOG for BUILD Utils Package + +08122000 - Initial release. kextract is the only utility that compiles cleanly, + kgroup and the map conversion utilities will work fine once they get + a findfirst/findnext implementation. BUILD needs this too, so it may + get done soon. I haven't touched the rest of the utils yet, since they + look like they'll need files from the BUILD source (pragmas.[ch], + unix_compat.[ch], etc), and I really don't feel like screwing with this + anymore at the moment :) + +08222000 - kgroup now works... realized that kextract has some problems. kgroup + seems to have some too, but they are trivial, like files are sorted + backwards alphabetically in the group file and such. As far as I can + tell, kgroup is stable. + +09042000 - Christian Zander contributed a new (GPL'd) kextract from scratch, + which I've named grpextract. It works under Linux, unlike kextract. + Added Ken's license text. + +09102000 - Editart now compiles (doesn't link yet). Working on that, hopefully + it will link soon, but a lot of work will still need to be done. Ken + used some VGA tricks that don't translate to SDL too well. I don't + doubt that it will immediately segfault once it links, but I guess + we'll see. Other stuff was done, mostly cleanups with the other utils, + such as *_compat.h instead of duplicating a ton of code in each util. + kextract still mystifies me, but that's not as important since we now + have grpextract. Map utils still waiting for opendir stuff. diff --git a/buildengine/utils/Makefile b/buildengine/utils/Makefile new file mode 100755 index 0000000..0361d60 --- /dev/null +++ b/buildengine/utils/Makefile @@ -0,0 +1,48 @@ +#---------------------------------------------------------------------------- +# Makefile for building BUILD utilites on Unix systems. +# +# Written by Ryan C. Gordon (icculus@lokigames.com) +# Do NOT contact Ken Silverman for support of BUILD on Unix or Linux. +#---------------------------------------------------------------------------- + +# Programs to build +BINARIES = grpextract kgroup editart + +CC = gcc -m32 +LINKER = gcc -m32 +CFLAGS = -g -O2 -DPLATFORM_UNIX -DUSE_I386_ASM `sdl-config --cflags` +LDFLAGS = + +# Editart is a beast of a different color +EALDFLAGS = $(LDFLAGS) `sdl-config --libs` + +# Rules for turning source files into .o files +%.o: %.c + $(CC) -c -o $@ $< $(CFLAGS) + +all: $(BINARIES) + +backmap5 : backmap5.o + $(LINKER) -o backmap5 $(LDFLAGS) backmap5.o + +backmap6 : backmap6.o + $(LINKER) -o backmap6 $(LDFLAGS) backmap6.o + +convmap6 : convmap6.o + $(LINKER) -o convmap6 $(LDFLAGS) convmap6.o + +convmap7 : convmap7.o + $(LINKER) -o convmap7 $(LDFLAGS) convmap7.o + +editart : editart.o pragmas.o sdl_driver.o + $(LINKER) -o editart $(EALDFLAGS) editart.o pragmas.o sdl_driver.o + +kextract : kextract.o + $(LINKER) -o kextract $(LDFLAGS) kextract.o + +kgroup : kgroup.o + $(LINKER) -o kgroup $(LDFLAGS) kgroup.o + +clean: + rm -f $(BINARIES) *.o core + diff --git a/buildengine/utils/README b/buildengine/utils/README new file mode 100755 index 0000000..4d1d249 --- /dev/null +++ b/buildengine/utils/README @@ -0,0 +1,13 @@ +// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman +// Ken Silverman's official web site: "http://www.advsys.net/ken" +// See the included license file "BUILDLIC.TXT" for license info. + +README for BUILD Utils Package + +These are the utilities Ken Silverman released along with his BUILD engine. +There is a quick description of what each of these do in the ureadme.txt file. +Most of the utilities in this package either don't work at all or don't work +correctly yet. Normal users won't get much use out of this for now, but +there will hopefully be something interesting quite soon. + +More info in the CHANGELOG and TODO files if you're a hacker and interested. diff --git a/buildengine/utils/TODO b/buildengine/utils/TODO new file mode 100755 index 0000000..797e23b --- /dev/null +++ b/buildengine/utils/TODO @@ -0,0 +1,10 @@ +// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman +// Ken Silverman's official web site: "http://www.advsys.net/ken" +// See the included license file "BUILDLIC.TXT" for license info. + +TODO for BUILD Utilities Package + +- Insert and clean up opendir stuff all around +- Start on the utils that haven't been ported yet (obviously) + +Send patches to icculus@lokigames.com or dolson@raven-games.com diff --git a/buildengine/utils/backmap5.c b/buildengine/utils/backmap5.c new file mode 100755 index 0000000..0a22718 --- /dev/null +++ b/buildengine/utils/backmap5.c @@ -0,0 +1,406 @@ +// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman +// Ken Silverman's official web site: "http://www.advsys.net/ken" +// See the included license file "BUILDLIC.TXT" for license info. + +//These changes are from version 5 to version 6 +//Remember that this is backwards from what this program does! +// +//Added wall[].pal, sprite[].pal +//Added sprite[].clipdist +//Expanded sprite[].cstat to a short +//Added sprite[].xoffset, sprite[].yoffset +//Removed wall[].nextsector2, wall[].nextwall2 +//Renamed wall[].nextsector1 to just wall[].nextsector +//Renamed wall[].nextwall1 to just wall[].nextwall +//Scrapped numextras and extratype structure - Don't confuse this with +// sector[].extra, wall[].extra, sprite[].extra which ARE in map version 6. + +#include +#include +#include +#ifdef PLATFORM_DOS +#include +#include +#include +#include +#include "dos_compat.h" +#else +#include +#include +#include +#include "unix_compat.h" +#endif + +#define NEWMAPVERSION 5 +#define MAXMENUFILES 1024 + +#define MAXSECTORS 1024 +#define MAXWALLS 4096 +#define MAXSPRITES 4096 + +#define MAXSTATUS 1024 +#define MAXTILES 4096 + +static char menuname[MAXMENUFILES][32]; +static long menunamecnt; + +#ifdef PLATFORM_DOS +#pragma pack(push,1); +#endif + +typedef struct +{ + short unsigned int wallptr, wallnum; + short ceilingpicnum, floorpicnum; + short ceilingheinum, floorheinum; + long ceilingz, floorz; + signed char ceilingshade, floorshade; + char ceilingxpanning, floorxpanning; + char ceilingypanning, floorypanning; + char ceilingstat, floorstat; + char ceilingpal, floorpal; + char visibility; + short lotag, hitag; + short extra; +} newsectortype; + +typedef struct +{ + long x, y; + short point2; + short picnum, overpicnum; + signed char shade; + short cstat; + unsigned char xrepeat, yrepeat, xpanning, ypanning; + short nextsector1, nextwall1; + short nextsector2, nextwall2; + short lotag, hitag; + short extra; +} newwalltype; + +typedef struct +{ + long x, y, z; + char cstat; + signed char shade; + unsigned char xrepeat, yrepeat; + short picnum, ang, xvel, yvel, zvel, owner; + short sectnum, statnum; + short lotag, hitag; + short extra; +} newspritetype; + +typedef struct +{ + unsigned short wallptr, wallnum; + short ceilingpicnum, floorpicnum; + short ceilingheinum, floorheinum; + long ceilingz, floorz; + signed char ceilingshade, floorshade; + char ceilingxpanning, floorxpanning; + char ceilingypanning, floorypanning; + char ceilingstat, floorstat; + char ceilingpal, floorpal; + char visibility; + short lotag, hitag, extra; +} sectortype; + +typedef struct +{ + long x, y; + short point2, nextsector, nextwall; + short picnum, overpicnum; + signed char shade; + char pal; + short cstat; + unsigned char xrepeat, yrepeat, xpanning, ypanning; + short lotag, hitag, extra; +} walltype; + +typedef struct +{ + long x, y, z; + short cstat; + signed char shade; + char pal, clipdist; + unsigned char xrepeat, yrepeat; + signed char xoffset, yoffset; + short picnum, ang, xvel, yvel, zvel, owner; + short sectnum, statnum; + short lotag, hitag, extra; +} spritetype; + +#ifdef PLATFORM_DOS +#pragma pack(pop); +#endif + +//************************************************************************** + +static sectortype sector[MAXSECTORS]; +static walltype wall[MAXWALLS]; +static spritetype sprite[MAXSPRITES]; + +static newsectortype newsector[MAXSECTORS]; +static newwalltype newwall[MAXWALLS]; +static newspritetype newsprite[MAXSPRITES]; + +static long posx, posy, posz, mapversion; +static short ang, cursectnum, numsectors, numwalls, numsprites; + +// Function definitions +void convmap(char *filename); +int loadoldboard(char *filename); +int savenewboard(char *filename); +int getfilenames(char *kind); +void sortfilenames(void); + +int main(int argc, char **argv) +{ + long i; + + if (argc != 2) + { + printf("BACKMAP%d [filespec] by Ken Silverman\n",NEWMAPVERSION); + printf("This BACKMAP%d.EXE converts map version %d to map version %d\n",NEWMAPVERSION,NEWMAPVERSION+1,NEWMAPVERSION); + exit(0); + } + menunamecnt = 0; + getfilenames(argv[1]); + sortfilenames(); + + if (menunamecnt == 0) + { + printf("BACKMAP%d [filespec] by Ken Silverman\n",NEWMAPVERSION); + printf("This BACKMAP%d.EXE converts map version %d to map version %d\n",NEWMAPVERSION,NEWMAPVERSION+1,NEWMAPVERSION); + printf("File not found\n"); + exit(0); + } + + printf("Converting map version %d to map version %d\n",NEWMAPVERSION+1,NEWMAPVERSION); + + for(i=0;i 0)) + if ((fileinfo.name[0] != '.') || (fileinfo.name[1] != 0)) + { + if (menunamecnt < MAXMENUFILES) + { + strcpy(menuname[menunamecnt],fileinfo.name); + menuname[menunamecnt][16] = type; + menunamecnt++; + } + //else + // printmessage("Too many files! (max=MAXMENUFILES)"); + } + } + while (_dos_findnext(&fileinfo) == 0); + + return(0); +} + +void sortfilenames(void) +{ + char sortbuffer[32]; + long i, j, k; + + for(i=1;i +#include +#include +#ifdef PLATFORM_DOS +#include +#include +#include +#include +#include "dos_compat.h" +#else +#include +#include +#include +#include "unix_compat.h" +#endif + +#define NEWMAPVERSION 6 +#define MAXMENUFILES 1024 + +#define MAXSECTORS 1024 +#define MAXWALLS 8192 +#define MAXSPRITES 4096 + +#define MAXSTATUS 1024 +#define MAXTILES 4096 + +static char menuname[MAXMENUFILES][32]; +static long menunamecnt; + +#ifdef PLATFORM_DOS +#pragma pack(push,1); +#endif + +typedef struct +{ + unsigned short wallptr, wallnum; + short ceilingpicnum, floorpicnum; + short ceilingheinum, floorheinum; + long ceilingz, floorz; + signed char ceilingshade, floorshade; + char ceilingxpanning, floorxpanning; + char ceilingypanning, floorypanning; + char ceilingstat, floorstat; + char ceilingpal, floorpal; + char visibility; + short lotag, hitag, extra; +} newsectortype; + +typedef struct +{ + long x, y; + short point2, nextsector, nextwall; + short picnum, overpicnum; + signed char shade; + char pal; + short cstat; + unsigned char xrepeat, yrepeat, xpanning, ypanning; + short lotag, hitag, extra; +} newwalltype; + +typedef struct +{ + long x, y, z; + short cstat; + signed char shade; + char pal, clipdist; + unsigned char xrepeat, yrepeat; + signed char xoffset, yoffset; + short picnum, ang, xvel, yvel, zvel, owner; + short sectnum, statnum; + short lotag, hitag, extra; +} newspritetype; + + //40 bytes +typedef struct +{ + short wallptr, wallnum; + long ceilingz, floorz; + short ceilingstat, floorstat; + short ceilingpicnum, ceilingheinum; + signed char ceilingshade; + char ceilingpal, ceilingxpanning, ceilingypanning; + short floorpicnum, floorheinum; + signed char floorshade; + char floorpal, floorxpanning, floorypanning; + char visibility, filler; + short lotag, hitag, extra; +} sectortype; + + //32 bytes +typedef struct +{ + long x, y; + short point2, nextwall, nextsector, cstat; + short picnum, overpicnum; + signed char shade; + char pal, xrepeat, yrepeat, xpanning, ypanning; + short lotag, hitag, extra; +} walltype; + + //44 bytes +typedef struct +{ + long x, y, z; + short cstat, picnum; + signed char shade; + char pal, clipdist, filler; + unsigned char xrepeat, yrepeat; + signed char xoffset, yoffset; + short sectnum, statnum; + short ang, owner, xvel, yvel, zvel; + short lotag, hitag, extra; +} spritetype; + +#ifdef PLATFORM_DOS +#pragma pack(pop); +#endif + +//************************************************************************** + +static sectortype sector[MAXSECTORS]; +static walltype wall[MAXWALLS]; +static spritetype sprite[MAXSPRITES]; + +static newsectortype newsector[MAXSECTORS]; +static newwalltype newwall[MAXWALLS]; +static newspritetype newsprite[MAXSPRITES]; + +static long posx, posy, posz, mapversion; +static short ang, cursectnum, numsectors, numwalls, numsprites; + +// Function definitions +void convmap(char *filename); +int loadoldboard(char *filename); +int savenewboard(char *filename); +int getfilenames(char *kind); +void sortfilenames(void); + +int main(int argc, char **argv) +{ + long i; + + if (argc != 2) + { + printf("BACKMAP%d [filespec] by Ken Silverman\n",NEWMAPVERSION); + printf("This BACKMAP%d.EXE converts map version %d to map version %d\n",NEWMAPVERSION,NEWMAPVERSION+1,NEWMAPVERSION); + exit(0); + } + menunamecnt = 0; + getfilenames(argv[1]); + sortfilenames(); + + if (menunamecnt == 0) + { + printf("BACKMAP%d [filespec] by Ken Silverman\n",NEWMAPVERSION); + printf("This BACKMAP%d.EXE converts map version %d to map version %d\n",NEWMAPVERSION,NEWMAPVERSION+1,NEWMAPVERSION); + printf("File not found\n"); + exit(0); + } + + printf("Converting map version %d to map version %d\n",NEWMAPVERSION+1,NEWMAPVERSION); + + for(i=0;i>5); + newsector[i].ceilingshade = sector[i].ceilingshade; + newsector[i].ceilingpal = sector[i].ceilingpal; + newsector[i].ceilingxpanning = sector[i].ceilingxpanning; + newsector[i].ceilingypanning = sector[i].ceilingypanning; + newsector[i].floorpicnum = sector[i].floorpicnum; + newsector[i].floorheinum = (((long)sector[i].floorheinum)>>5); + newsector[i].floorshade = sector[i].floorshade; + newsector[i].floorpal = sector[i].floorpal; + newsector[i].floorxpanning = sector[i].floorxpanning; + newsector[i].floorypanning = sector[i].floorypanning; + newsector[i].ceilingstat = sector[i].ceilingstat; + if (newsector[i].ceilingheinum == 0) newsector[i].ceilingstat &= ~2; + newsector[i].floorstat = sector[i].floorstat; + if (newsector[i].floorheinum == 0) newsector[i].floorstat &= ~2; + newsector[i].visibility = sector[i].visibility; + newsector[i].lotag = sector[i].lotag; + newsector[i].hitag = sector[i].hitag; + newsector[i].extra = sector[i].extra; + } + for(i=0;i 0)) + if ((fileinfo.name[0] != '.') || (fileinfo.name[1] != 0)) + { + if (menunamecnt < MAXMENUFILES) + { + strcpy(menuname[menunamecnt],fileinfo.name); + menuname[menunamecnt][16] = type; + menunamecnt++; + } + //else + // printmessage("Too many files! (max=MAXMENUFILES)"); + } + } + while (_dos_findnext(&fileinfo) == 0); + + return(0); +} + +void sortfilenames(void) +{ + char sortbuffer[32]; + long i, j, k; + + for(i=1;i +#include +#include +#ifdef PLATFORM_DOS +#include +#include +#include +#include +#include "dos_compat.h" +#else +#include +#include +#include +#include "unix_compat.h" +#endif + +#define NEWMAPVERSION 6 +#define MAXMENUFILES 1024 + +#define MAXSECTORS 1024 +#define MAXWALLS 4096 +#define MAXSPRITES 4096 + +#define MAXSTATUS 1024 +#define MAXTILES 4096 + +static char menuname[MAXMENUFILES][32]; +static long menunamecnt; + +#ifdef PLATFORM_DOS +#pragma pack(push,1); +#endif + +typedef struct +{ + short unsigned int wallptr, wallnum; + short ceilingpicnum, floorpicnum; + short ceilingheinum, floorheinum; + long ceilingz, floorz; + signed char ceilingshade, floorshade; + char ceilingxpanning, floorxpanning; + char ceilingypanning, floorypanning; + char ceilingstat, floorstat; + char ceilingpal, floorpal; + char visibility; + short lotag, hitag; + short extra; +} sectortype; + +typedef struct +{ + long x, y; + short point2; + short picnum, overpicnum; + signed char shade; + short cstat; + unsigned char xrepeat, yrepeat, xpanning, ypanning; + short nextsector1, nextwall1; + short nextsector2, nextwall2; + short lotag, hitag; + short extra; +} walltype; + +typedef struct +{ + long x, y, z; + char cstat; + signed char shade; + unsigned char xrepeat, yrepeat; + short picnum, ang, xvel, yvel, zvel, owner; + short sectnum, statnum; + short lotag, hitag; + short extra; +} spritetype; + +typedef struct +{ + unsigned short wallptr, wallnum; + short ceilingpicnum, floorpicnum; + short ceilingheinum, floorheinum; + long ceilingz, floorz; + signed char ceilingshade, floorshade; + char ceilingxpanning, floorxpanning; + char ceilingypanning, floorypanning; + char ceilingstat, floorstat; + char ceilingpal, floorpal; + char visibility; + short lotag, hitag, extra; +} newsectortype; + +typedef struct +{ + long x, y; + short point2, nextsector, nextwall; + short picnum, overpicnum; + signed char shade; + char pal; + short cstat; + unsigned char xrepeat, yrepeat, xpanning, ypanning; + short lotag, hitag, extra; +} newwalltype; + +typedef struct +{ + long x, y, z; + short cstat; + signed char shade; + char pal, clipdist; + unsigned char xrepeat, yrepeat; + signed char xoffset, yoffset; + short picnum, ang, xvel, yvel, zvel, owner; + short sectnum, statnum; + short lotag, hitag, extra; +} newspritetype; + +#ifdef PLATFORM_DOS +#pragma pack(pop); +#endif + +//************************************************************************** + +static sectortype sector[MAXSECTORS]; +static walltype wall[MAXWALLS]; +static spritetype sprite[MAXSPRITES]; + +static newsectortype newsector[MAXSECTORS]; +static newwalltype newwall[MAXWALLS]; +static newspritetype newsprite[MAXSPRITES]; + +static long posx, posy, posz, mapversion; +static short ang, cursectnum, numsectors, numwalls, numsprites; + +// Function definitions +void convmap(char *filename); +int loadoldboard(char *filename); +int savenewboard(char *filename); +short sectorofwall(short theline); +int getfilenames(char *kind); +void sortfilenames(void); + +int main(int argc, char **argv) +{ + long i; + + if (argc != 2) + { + printf("CONVMAP%d [filespec] by Ken Silverman\n",NEWMAPVERSION); + printf("This CONVMAP%d.EXE converts map version %d to map version %d\n",NEWMAPVERSION,NEWMAPVERSION-1,NEWMAPVERSION); + exit(0); + } + menunamecnt = 0; + getfilenames(argv[1]); + sortfilenames(); + + if (menunamecnt == 0) + { + printf("CONVMAP%d [filespec] by Ken Silverman\n",NEWMAPVERSION); + printf("This CONVMAP%d.EXE converts map version %d to map version %d\n",NEWMAPVERSION,NEWMAPVERSION-1,NEWMAPVERSION); + printf("File not found\n"); + exit(0); + } + + printf("Converting map version %d to map version %d\n",NEWMAPVERSION-1,NEWMAPVERSION); + + for(i=0;i 0) + newsprite[i].pal = sector[j].ceilingpal; + else + newsprite[i].pal = sector[j].floorpal; + + newsprite[i].clipdist = 32; + newsprite[i].xrepeat = sprite[i].xrepeat; + newsprite[i].yrepeat = sprite[i].yrepeat; + newsprite[i].xoffset = 0; + newsprite[i].yoffset = 0; + newsprite[i].picnum = sprite[i].picnum; + newsprite[i].ang = sprite[i].ang; + newsprite[i].xvel = sprite[i].xvel; + newsprite[i].yvel = sprite[i].yvel; + newsprite[i].zvel = sprite[i].zvel; + newsprite[i].owner = sprite[i].owner; + newsprite[i].sectnum = sprite[i].sectnum; + newsprite[i].statnum = sprite[i].statnum; + newsprite[i].lotag = sprite[i].lotag; + newsprite[i].hitag = sprite[i].hitag; + newsprite[i].extra = sprite[i].extra; + } + + mapversion = NEWMAPVERSION; + if (savenewboard(filename) == 0) + printf("%s successfully converted.\n",filename); + else + printf("%s NOT converted for some stupid reason.\n",filename); +} + +int loadoldboard(char *filename) +{ + long fil; + + if ((fil = open(filename,O_BINARY|O_RDWR,S_IREAD)) == -1) + return(-1); + + read(fil,&mapversion,4); + if (mapversion != NEWMAPVERSION-1) + { + close(fil); + return(-2); + } + read(fil,&posx,4); + read(fil,&posy,4); + read(fil,&posz,4); + read(fil,&ang,2); + read(fil,&cursectnum,2); + + read(fil,&numsectors,2); + read(fil,§or[0],sizeof(sectortype)*numsectors); + + read(fil,&numwalls,2); + read(fil,&wall[0],sizeof(walltype)*numwalls); + + read(fil,&numsprites,2); + read(fil,&sprite[0],sizeof(spritetype)*numsprites); + + close(fil); + return(0); +} + +int savenewboard(char *filename) +{ + long fil; + + if ((fil = open(filename,O_BINARY|O_TRUNC|O_CREAT|O_WRONLY,UC_PERMS)) == -1) + return(-1); + + //Version control + write(fil,&mapversion,4); + + //Starting position + write(fil,&posx,4); + write(fil,&posy,4); + write(fil,&posz,4); + write(fil,&ang,2); + write(fil,&cursectnum,2); + + //Sectors + write(fil,&numsectors,2); + write(fil,&newsector[0],sizeof(newsectortype)*numsectors); + + //Walls + write(fil,&numwalls,2); + write(fil,&newwall[0],sizeof(newwalltype)*numwalls); + + //Sprites + write(fil,&numsprites,2); + write(fil,&newsprite[0],sizeof(newspritetype)*numsprites); + + close(fil); + + return(0); +} + +short sectorofwall(short theline) +{ + short i, startwall, endwall, sucksect; + + sucksect = -1; + for(i=0;i= startwall) && (theline <= endwall)) + { + sucksect = i; + break; + } + } + return(sucksect); +} + +int getfilenames(char *kind) +{ + short type; + struct find_t fileinfo; + + if (strcmp(kind,"SUBD") == 0) + { + strcpy(kind,"*.*"); + if (_dos_findfirst(kind,_A_SUBDIR,&fileinfo) != 0) + return(-1); + type = 1; + } + else + { + if (_dos_findfirst(kind,_A_NORMAL,&fileinfo) != 0) + return(-1); + type = 0; + } + do + { + if ((type == 0) || ((fileinfo.attrib&16) > 0)) + if ((fileinfo.name[0] != '.') || (fileinfo.name[1] != 0)) + { + if (menunamecnt < MAXMENUFILES) + { + strcpy(menuname[menunamecnt],fileinfo.name); + menuname[menunamecnt][16] = type; + menunamecnt++; + } + //else + // printmessage("Too many files! (max=MAXMENUFILES)"); + } + } + while (_dos_findnext(&fileinfo) == 0); + + return(0); +} + +void sortfilenames(void) +{ + char sortbuffer[32]; + long i, j, k; + + for(i=1;i +#include +#include +#ifdef PLATFORM_DOS +#include +#include +#include +#include +#include "dos_compat.h" +#else +#include +#include +#include +#include "unix_compat.h" +#endif + +#define NEWMAPVERSION 7 +#define MAXMENUFILES 1024 + +#define MAXSECTORS 1024 +#define MAXWALLS 8192 +#define MAXSPRITES 4096 + +#define MAXSTATUS 1024 +#define MAXTILES 4096 + +static char menuname[MAXMENUFILES][32]; +static long menunamecnt; + +#ifdef PLATFORM_DOS +#pragma pack(push,1); +#endif + +typedef struct +{ + unsigned short wallptr, wallnum; + short ceilingpicnum, floorpicnum; + short ceilingheinum, floorheinum; + long ceilingz, floorz; + signed char ceilingshade, floorshade; + char ceilingxpanning, floorxpanning; + char ceilingypanning, floorypanning; + char ceilingstat, floorstat; + char ceilingpal, floorpal; + char visibility; + short lotag, hitag, extra; +} sectortype; + +typedef struct +{ + long x, y; + short point2, nextsector, nextwall; + short picnum, overpicnum; + signed char shade; + char pal; + short cstat; + unsigned char xrepeat, yrepeat, xpanning, ypanning; + short lotag, hitag, extra; +} walltype; + +typedef struct +{ + long x, y, z; + short cstat; + signed char shade; + char pal, clipdist; + unsigned char xrepeat, yrepeat; + signed char xoffset, yoffset; + short picnum, ang, xvel, yvel, zvel, owner; + short sectnum, statnum; + short lotag, hitag, extra; +} spritetype; + + //40 bytes +typedef struct +{ + short wallptr, wallnum; + long ceilingz, floorz; + short ceilingstat, floorstat; + short ceilingpicnum, ceilingheinum; + signed char ceilingshade; + char ceilingpal, ceilingxpanning, ceilingypanning; + short floorpicnum, floorheinum; + signed char floorshade; + char floorpal, floorxpanning, floorypanning; + char visibility, filler; + short lotag, hitag, extra; +} newsectortype; + + //32 bytes +typedef struct +{ + long x, y; + short point2, nextwall, nextsector, cstat; + short picnum, overpicnum; + signed char shade; + char pal, xrepeat, yrepeat, xpanning, ypanning; + short lotag, hitag, extra; +} newwalltype; + + //44 bytes +typedef struct +{ + long x, y, z; + short cstat, picnum; + signed char shade; + char pal, clipdist, filler; + unsigned char xrepeat, yrepeat; + signed char xoffset, yoffset; + short sectnum, statnum; + short ang, owner, xvel, yvel, zvel; + short lotag, hitag, extra; +} newspritetype; + +#ifdef PLATFORM_DOS +#pragma pack(pop); +#endif + +//************************************************************************** + +static sectortype sector[MAXSECTORS]; +static walltype wall[MAXWALLS]; +static spritetype sprite[MAXSPRITES]; + +static newsectortype newsector[MAXSECTORS]; +static newwalltype newwall[MAXWALLS]; +static newspritetype newsprite[MAXSPRITES]; + +static long posx, posy, posz, mapversion; +static short ang, cursectnum, numsectors, numwalls, numsprites; + +// Function definitions +void convmap(char *filename); +int loadoldboard(char *filename); +int savenewboard(char *filename); +int getfilenames(char *kind); +void sortfilenames(void); + +int main(int argc, char **argv) +{ + long i; + + if (argc != 2) + { + printf("CONVMAP%d [filespec] by Ken Silverman\n",NEWMAPVERSION); + printf("This CONVMAP%d.EXE converts map version %d to map version %d\n",NEWMAPVERSION,NEWMAPVERSION-1,NEWMAPVERSION); + exit(0); + } + menunamecnt = 0; + getfilenames(argv[1]); + sortfilenames(); + + if (menunamecnt == 0) + { + printf("CONVMAP%d [filespec] by Ken Silverman\n",NEWMAPVERSION); + printf("This CONVMAP%d.EXE converts map version %d to map version %d\n",NEWMAPVERSION,NEWMAPVERSION-1,NEWMAPVERSION); + printf("File not found\n"); + exit(0); + } + + printf("Converting map version %d to map version %d\n",NEWMAPVERSION-1,NEWMAPVERSION); + + for(i=0;i 0)) + if ((fileinfo.name[0] != '.') || (fileinfo.name[1] != 0)) + { + if (menunamecnt < MAXMENUFILES) + { + strcpy(menuname[menunamecnt],fileinfo.name); + menuname[menunamecnt][16] = type; + menunamecnt++; + } + //else + // printmessage("Too many files! (max=MAXMENUFILES)"); + } + } + while (_dos_findnext(&fileinfo) == 0); + + return(0); +} + +void sortfilenames(void) +{ + char sortbuffer[32]; + long i, j, k; + + for(i=1;i +#include +#include +#ifdef PLATFORM_DOS +#include +#include +#include +#include +#include +#include +#include "dos_compat.h" +#else +#include +#include +#include +#include +#include "pragmas.h" +#include "sdl_driver.h" +#include "unix_compat.h" +#include // This needs to be last - DDOI +#endif + +#define MAXTILES 9216 +#define MAXMENUFILES 256 +#define MAXTILEFILES 256 +#define NUMPALOOKUPS 32 +#define GIFBUFLEN 4096 +#define MAXMAPS 64 + +// Function Declarations +void reportmaps(void); +void captureit(long x1, long y1, long x2, long y2, long datilenum, char *dafilename, char capfilmode); +void updatescript(long picnumrangestart, long picnumrangeend); +int loadtileofscript(long tilenume, char *filespec, long *x1, long *y1, long *x2 , long *y2); +int selectbox(long *dax1, long *day1, long *dax2, long *day2); +void updatepalette(void); +void updatemaps(void); +int swapwalls(long swapwall1, long swapwall2); +long convalloc32(long size); +char gettrans(char dat1, char dat2); +void gettextcolors(void); +int resizetile(long picnume, long oldx, long oldy, long newx, long newy); +int screencapture(void); +void printmessage(char name[82]); +int printext256(long xpos, long ypos, short col, short backcol, char *name); +int menuselect(void); +void sortfilenames(void); +int getfilenames(char *kind); +void initmenupaths(char *filename); +void savenames(void); +int loadnames(void); +int drawtilescreen(long pictopleft); +long gettile(long tilenum); +void getpalookup(void); +int fillregion(long x, long y, char col, char bound); +void getpaletteconversion(void); +int drawmaskedbox(long x1, long y1, long x2, long y2, char col, char mask1, char mask2); +int drawxorbox(long x1, long y1, long x2, long y2, char col); +void drawmainscreen(void); +int loadgif(char *filename); +int loadpcx(char *filename); +int loadbmp(char *filename); +void loadpicture(char *filename); +void drawcolordot(char thecol); +void updatepanningforumode(long dax, long day); +void updatepanning(void); +int drawdot(char col); +void copywalltoscreen(char *bufptr, long dapicnum, char maskmode); +int showall(char *bufptr); +int savewall(char *bufptr, long wallnum); +int loadwall(char *bufptr, long wallnum); +int savepics(void); +int loadpics(long dapicnum); +int loadtables(void); + + +static struct sectortype +{ + short wallptr, wallnum; + long ceilingz, floorz; + short ceilingstat, floorstat; + short ceilingpicnum, ceilingheinum; + signed char ceilingshade; + char ceilingpal, ceilingxpanning, ceilingypanning; + short floorpicnum, floorheinum; + signed char floorshade; + char floorpal, floorxpanning, floorypanning; + char visibility, filler; + short lotag, hitag, extra; +} mapsector; + +static struct walltype +{ + long x, y; + short point2, nextwall, nextsector, cstat; + short picnum, overpicnum; + signed char shade; + char pal, xrepeat, yrepeat, xpanning, ypanning; + short lotag, hitag, extra; +} mapwall; + +static struct spritetype +{ + long x, y, z; + short cstat, picnum; + signed char shade; + char pal, clipdist, filler; + unsigned char xrepeat, yrepeat; + signed char xoffset, yoffset; + short sectnum, statnum; + short ang, owner, xvel, yvel, zvel; + short lotag, hitag, extra; +} mapsprite; + +short nummaps, numsprites[MAXMAPS]; + +static char *pic; +static short int mousx, mousy, bstatus, moustat; +static unsigned char col, trailstatus, tempbuf[4096]; +static short xfillbuf[4096], yfillbuf[4096]; +static unsigned char printbuf[128]; +static short tilesizx[MAXTILES], tilesizy[MAXTILES]; +static long picanm[MAXTILES], artversion, numtiles; +static long panx, pany, panxforu, panyforu, panyoff = 0, panxdim; +static long lastshowallxdim = 0x7fffffff, lastshowallydim = 0x7fffffff; +static unsigned char buf[1024*512], *buf2; +static long waloff[MAXTILES], totpicmem, xdim, ydim, asksave, c, d, picnum; +static long totpicsiz, animspeed, allasksave, mustsavelocals = 0; +static long needtosavenames = 0, gettilezoom = 1; +static short sintable[2048]; +static char blackmasklookup[256]; + +static short tilookup[MAXTILES], tilookup2[MAXTILES], tilesreported = 0; + +static char artfilename[20]; +static long localtilestart[MAXTILEFILES], localtileend[MAXTILEFILES]; +static long curtilefile, numtilefiles; + +static long xres, yres; +static char pcxheader[128] = +{ + 0xa,0x5,0x1,0x8,0x0,0x0,0x0,0x0,0x3f,0x1,0xc7,0x0, + 0x40,0x1,0xc8,0x0,0x0,0x0,0x0,0x8,0x8,0x8,0x10,0x10, + 0x10,0x18,0x18,0x18,0x20,0x20,0x20,0x28,0x28,0x28,0x30,0x30, + 0x30,0x38,0x38,0x38,0x40,0x40,0x40,0x48,0x48,0x48,0x50,0x50, + 0x50,0x58,0x58,0x58,0x60,0x60,0x60,0x68,0x68,0x68,0x70,0x70, + 0x70,0x78,0x78,0x78,0x0,0x1,0x40,0x1,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, + 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +}; + +static long capfil = -1L; + +static char names[MAXTILES][17]; +static char menuname[MAXMENUFILES][17], curpath[160], menupath[160]; +static long menunamecnt, menuhighlight; + +static char textfont[128][8]; +static char reversemask[16] = {0,8,4,12,2,10,6,14,1,9,5,13,3,11,7,15}; + +static char whitecol, browncol, yellowcol, greencol, blackcol; + +static char palookup[NUMPALOOKUPS][256], palette[768]; +static char palette2[768], palookupe[256], *transluc, translucloaded = 0; + +static unsigned char gifdata[GIFBUFLEN]; +static unsigned char gifsuffix[4100], giffilbuffer[768], giftempstack[4096]; +static short int gifprefix[4100]; + +static long totalclock; +static void (__interrupt __far *oldtimerhandler)(); +static void __interrupt __far timerhandler(void); + +#ifdef PLATFORM_DOS +/* Most of these will be caught in pragmas.c - DDOI */ +#pragma aux scale =\ + "imul ebx",\ + "idiv ecx",\ + parm [eax][ebx][ecx]\ + modify [eax edx]\ + +#pragma aux mulscale =\ + "imul ebx",\ + "shrd eax, edx, cl",\ + parm [eax][ebx][ecx]\ + modify [edx]\ + +#pragma aux boundmulscale =\ + "imul ebx",\ + "mov ebx, edx",\ + "shrd eax, edx, cl",\ + "sar edx, cl",\ + "xor edx, eax",\ + "js checkit",\ + "xor edx, eax",\ + "jz skipboundit",\ + "cmp edx, 0xffffffff",\ + "je skipboundit",\ + "checkit:",\ + "mov eax, ebx",\ + "sar eax, 31",\ + "add eax, 0x80000000",\ + "not eax",\ + "skipboundit:",\ + parm [eax][ebx][ecx]\ + modify [edx]\ + +#pragma aux divscale =\ + "cdq",\ + "shld edx, eax, cl",\ + "sal eax, cl",\ + "idiv ebx",\ + parm [eax][ebx][ecx]\ + modify [edx]\ + +#pragma aux setvmode =\ + "int 0x10",\ + parm [eax]\ + +#pragma aux clearbuf =\ + "rep stosd",\ + parm [edi][ecx][eax]\ + +#pragma aux cleartopbox =\ + "mov dx, 0x3c4",\ + "mov ax, 0x0f02",\ + "out dx, ax",\ + "mov edi, 0xa1000",\ + "mov ecx, 15360",\ + "mov dl, blackcol",\ + "mov dh, dl",\ + "mov eax, edx",\ + "shl eax, 16",\ + "mov ax, dx",\ + "rep stosd",\ + modify [eax ecx edx edi]\ + +#pragma aux getpixel =\ + "xor eax, eax",\ + "mov al, [edi]",\ + parm [edi]\ + +#pragma aux drawchainpixel =\ + "mov dx, 0x3c4",\ + "mov ax, 0x0102",\ + "mov cx, di",\ + "and cl, 3",\ + "shl ah, cl",\ + "out dx, ax",\ + "shr edi, 2",\ + "mov byte ptr [edi+0xa0000], bl",\ + parm [edi][ebx]\ + modify [eax ecx edx]\ + +#pragma aux drawpixel =\ + "mov [edi], al",\ + parm [edi][eax]\ + +#pragma aux drawpixels =\ + "mov [edi], ax",\ + parm [edi][eax]\ + +#pragma aux drawpixelses =\ + "mov [edi], eax",\ + parm [edi][eax]\ + +#pragma aux setupmouse =\ + "mov ax, 0",\ + "int 33h",\ + "mov moustat,1",\ + +#pragma aux readmouse =\ + "mov ax, 11d",\ + "int 33h",\ + "sar cx, 1",\ + "sar dx, 1",\ + "mov mousx, cx",\ + "mov mousy, dx",\ + "mov ax, 5d",\ + "int 33h",\ + "mov bstatus, ax",\ + modify [eax ebx ecx edx]\ + +#pragma aux limitrate =\ + "mov dx, 0x3da",\ + "wait1: in al, dx",\ + "test al, 8",\ + "jnz wait1",\ + "wait2: in al, dx",\ + "test al, 8",\ + "jz wait2",\ + modify [edx]\ + +#pragma aux cleartext =\ + "mov dx, 0x3c4",\ + "mov ax, 0x0f02",\ + "out dx, ax",\ + "mov edi, 0xa0800",\ + "mov ebx, 8",\ + "mov ah, browncol",\ + "mov al, ah",\ + "shl eax, 8",\ + "mov al, ah",\ + "shl eax, 8",\ + "mov al, ah",\ + "begclearit: mov ecx, 14",\ + "rep stosd",\ + "add edi, 200",\ + "sub ebx, 1",\ + "jnz begclearit",\ + modify [eax ebx ecx edx edi]\ + + //the 200 above = 256-28chars*2 + + //eax = (eax>>bitcnt)&((1<= 2) + { + // Weird... GCC wants me to add these casts - DDOI + strcpy((char *)&artfilename,argv[1]); + i = 0; + while ((artfilename[i] != 0) && (i < 5)) + i++; + while (i < 5) + { + artfilename[i] = '_'; + i++; + } + artfilename[5] = '0'; + artfilename[6] = '0'; + artfilename[7] = '0'; + artfilename[8] = '.'; + artfilename[9] = 'a'; + artfilename[10] = 'r'; + artfilename[11] = 't'; + artfilename[12] = 0; + } + else + strcpy((char *)&artfilename,"tiles000.art"); + + panxdim = 1024L; + + setvmode(0x13); + outp(0x3c4,0x4); outp(0x3c5,0x6); + outp(0x3d4,0x14); outp(0x3d5,0x0); + outp(0x3d4,0x17); outp(0x3d5,0xe3); + outp(0x3d4,0x13); outp(0x3d5,panxdim>>3); + + outp(0x3c4,2); outp(0x3c5,15); + clearbuf(VIDEOBASE,16384,0L); + + loadtables(); + + printext256(80L,84L,4,0,"Editart 7/24/96"); + printext256(80L,92L,4,0,"by Kenneth Silverman"); + sprintf(buffer,"Loading %s...",artfilename); + printext256(80L,108L,4,0,buffer); + + initmenupaths(argv[0]); + setupmouse(); + + for(i=0;i 1048576) + { + buf2 = (char *)(FP_OFF(pic)+totpicmem-(1024*512)); + totpicmem -= (1024*512); + } + + for(i=0;i>1); + d = (ydim>>1); + markx = 0; + marky = 0; + markxlen = 0; + markylen = 0; + drawmainscreen(); + while (ch != 27) + { + if (kbhit() != 0) + { + ch = getch(); + + if (ch == 0) + { + ch = getch(); + keystate = *keystateptr; + if ((keystate&3) == 0) + { + drawdot(buf[(d<<10)+c]); + if ((ch == 75) && (c > 0)) c--; + if ((ch == 77) && (c < xdim-1)) c++; + if ((ch == 72) && (d > 0)) d--; + if ((ch == 80) && (d < ydim-1)) d++; + drawdot((buf[(d<<10)+c]+16)&255); + } + else + { + drawcolordot(col); + if ((ch == 75) && (col > 0)) col--; + if ((ch == 77) && (col < 255)) col++; + if ((ch == 72) && (col > 31)) col -= 32; + if ((ch == 80) && (col < 224)) col += 32; + drawcolordot((col+16)&255); + } + if ((ch == 73) && (picnum > 0)) + { + if (savewall(buf,picnum) == 0) + { + picnum--; + loadpics(picnum); + loadwall(buf,picnum); + showall(buf); + drawdot((buf[(d<<10)+c]+16)&255); + } + } + if ((ch == 81) && (picnum < MAXTILES-1)) + { + if (savewall(buf,picnum) == 0) + { + picnum++; + loadpics(picnum); + loadwall(buf,picnum); + showall(buf); + drawdot((buf[(d<<10)+c]+16)&255); + } + } + if (ch == 83) + { + xdim = 0; + ydim = 0; + c = (xdim>>1); + d = (ydim>>1); + asksave = 1; + drawmainscreen(); + } + if (ch == 121) //ALT+2 + { + xdim = 32; + ydim = 32; + c = (xdim>>1); + d = (ydim>>1); + asksave = 1; + drawmainscreen(); + } + if (ch == 22) //Alt-U (update script!) + { + savewall(buf,picnum); + savepics(); + + updatescript(0L,MAXTILES-1L); + + loadpics(picnum); + loadwall(buf,picnum); + drawmainscreen(); + ch = 255; + } + if (ch == 134) //F12 + { + drawdot(buf[(d<<10)+c]); + screencapture(); + drawdot((buf[(d<<10)+c]+16)&255); + } + ch = 0; + } + if ((ch == 'b') || (ch == 'B')) + { + drawdot(buf[(d<<10)+c]); + screencapture(); + drawdot((buf[(d<<10)+c]+16)&255); + } + + if ((ch == 't') || (ch == 'T')) + { + buf[(d<<10)+c] = col, asksave = 1; + trailstatus = 1-trailstatus; + if (trailstatus == 0) + printmessage("Trail OFF"); + else + printmessage("Trail ON"); + } + if ((ch == 32) || (trailstatus == 1)) + buf[(d<<10)+c] = col, asksave = 1; + if (ch == 92) // It'a a \! + { + drawdot(buf[(d<<10)+c]); + c = (xdim>>1); + d = (ydim>>1); + drawdot((buf[(d<<10)+c]+16)&255); + } + if (ch == '|') + { + sprintf((char *)&printbuf,"Coordinates: (%d,%d)",c,d); + printmessage(&printbuf); + } + if (ch == 8) + { + drawcolordot(col); + col = 255; + drawcolordot((col+16)&255); + } + if ((ch == ',') || (ch == '.') || (ch == '<') || (ch == '>')) + { + xstep = 0; + ystep = 0; + if (markx > c) xstep = 1; + if (markx < c) xstep = -1; + if (marky > d) ystep = 1; + if (marky < d) ystep = -1; + i = c-xstep; + do + { + i += xstep; + j = d-ystep; + do + { + j += ystep; + if ((buf[(j<<10)+i]&31) > 0) + if (ch == ',') buf[(j<<10)+i]--; + if ((buf[(j<<10)+i]&31) < 31) + if (ch == '.') buf[(j<<10)+i]++; + if (ch == '<') + { + buf[(j<<10)+i] += 224; + buf[(j<<10)+i] &= 255; + } + if (ch == '>') + { + buf[(j<<10)+i] += 32; + buf[(j<<10)+i] &= 255; + } + } + while (j != marky); + } + while (i != markx); + showall(buf); + asksave = 1; + } + if ((ch == 'M') || (ch == 'm')) + { + if (buf2 == NULL) + { + printmessage("Not enough memory for that!"); + } + else + { + for(i=0;i 0) && (ydim > 0)) + { + if (buf2 == NULL) + { + printmessage("Not enough memory for that!"); + } + else + { + k = (buf[(d<<10)+c]>>5); + for(i=0;i>5) == k) + { + m = buf2[(((j+0)%ydim)<<10)+((i+0)%xdim)]*2, n = 2; + tempchar = buf2[(((j+0)%ydim)<<10)+((i+1)%xdim)]; + if ((tempchar>>5) == k) + m += tempchar, n += 1; + tempchar = buf2[(((j+0)%ydim)<<10)+((i-1)%xdim)]; + if ((tempchar>>5) == k) + m += tempchar, n += 1; + tempchar = buf2[(((j+1)%ydim)<<10)+((i+0)%xdim)]; + if ((tempchar>>5) == k) + m += tempchar, n += 1; + tempchar = buf2[(((j-1)%ydim)<<10)+((i+0)%xdim)]; + if ((tempchar>>5) == k) + m += tempchar, n += 1; + + buf[(j<<10)+i] = (buf[(j<<10)+i]&0xe0)+(((m+(n>>1))/n)&31); + } + showall(buf); + asksave = 1; + } + } + if ((ch == '[') && (xdim > 0) && (ydim > 0)) + { + if (buf2 == NULL) + { + printmessage("Not enough memory for that!"); + } + else + { + k = (buf[(d<<10)+c]>>5); + for(i=0;i>5) == k) + { + m = buf2[(((j+0)%ydim)<<10)+((i+0)%xdim)]*2, n = 2; + + l = rand(); + tempchar = buf2[(((j+0)%ydim)<<10)+((i+1)%xdim)]; + if (((tempchar>>5) == k) && ((l&0x03) == 0)) + m += tempchar, n++; + tempchar = buf2[(((j+0)%ydim)<<10)+((i-1)%xdim)]; + if (((tempchar>>5) == k) && ((l&0x0c) == 0)) + m += tempchar, n++; + tempchar = buf2[(((j+1)%ydim)<<10)+((i+0)%xdim)]; + if (((tempchar>>5) == k) && ((l&0x30) == 0)) + m += tempchar, n++; + tempchar = buf2[(((j-1)%ydim)<<10)+((i+0)%xdim)]; + if (((tempchar>>5) == k) && ((l&0xc0) == 0)) + m += tempchar, n++; + + buf[(j<<10)+i] = (buf[(j<<10)+i]&0xe0)+(((m+(n>>1))/n)&31); + } + showall(buf); + asksave = 1; + } + } + if ((ch == 39) && (xdim > 0) && (ydim > 0)) // It's a ' + { + k = (buf[(d<<10)+c]>>5); + for(i=0;i>5) == k) + { + m = (buf[(j<<10)+i]&31); + tempchar = buf[(((j+0)%ydim)<<10)+((i+1)%xdim)]; + if ((tempchar>>5) != k) + m--; + tempchar = buf[(((j+0)%ydim)<<10)+((i-1)%xdim)]; + if ((tempchar>>5) != k) + m++; + tempchar = buf[(((j+1)%ydim)<<10)+((i+0)%xdim)]; + if ((tempchar>>5) != k) + m--; + tempchar = buf[(((j-1)%ydim)<<10)+((i+0)%xdim)]; + if ((tempchar>>5) != k) + m++; + + if (m < 0) m = 0; + if (m > 31) m = 31; + buf[(j<<10)+i] = (buf[(j<<10)+i]&0xe0)+m; + } + showall(buf); + asksave = 1; + } + if ((ch == ';') && (xdim > 0) && (ydim > 0)) + { + k = (buf[(d<<10)+c]>>5); + for(i=0;i>5) == k) + { + m = (buf[(j<<10)+i]&31); + tempchar = buf[(((j+0)%ydim)<<10)+((i+1)%xdim)]; + if ((tempchar>>5) != k) + m++; + tempchar = buf[(((j+0)%ydim)<<10)+((i-1)%xdim)]; + if ((tempchar>>5) != k) + m--; + tempchar = buf[(((j+1)%ydim)<<10)+((i+0)%xdim)]; + if ((tempchar>>5) != k) + m++; + tempchar = buf[(((j-1)%ydim)<<10)+((i+0)%xdim)]; + if ((tempchar>>5) != k) + m--; + + if (m < 0) m = 0; + if (m > 31) m = 31; + buf[(j<<10)+i] = (buf[(j<<10)+i]&0xe0)+m; + } + showall(buf); + asksave = 1; + } + if (((ch == 'R') || (ch == 'r')) && (xdim > 0) && (ydim > 0)) + { + printmessage("Rotate tile (Use arrows)"); + ch = getch(); + if (ch == 0) + { + ch = getch(); + if (ch == 75) + for(i=xdim-1;i>=1;i--) + for(j=0;j=1;j--) + { + tempchar = buf[(j<<10)+i]; + buf[(j<<10)+i] = buf[(((j+1)%ydim)<<10)+i]; + buf[(((j+1)%ydim)<<10)+i] = tempchar; + } + if (ch == 80) + for(i=0;i x2) + templong = x, x = x2, x2 = templong; + if (y > y2) + templong = y, y = y2, y2 = templong; + markxlen = x2-x+1; + markylen = y2-y+1; + for(i=0;i>1);i++) + for(j=0;j>1);j++) + { + templong = buf2[(j<<10)+i]; + buf2[(j<<10)+i] = buf2[((markylen-1-j)<<10)+i]; + buf2[((markylen-1-j)<<10)+i] = templong; + } + printmessage("Region flipped y-wise"); + } + } + if (ch == '6') + { + if (buf2 == NULL) + { + printmessage("Not enough memory for that!"); + } + else + { + x2 = xdim; + y2 = ydim; + if (x2 > 480) x2 = 480; + if (y2 > 480) y2 = 480; + for(i=0;i j) + { + templong = buf2[(i<<10)+j]; + buf2[(i<<10)+j] = buf2[(j<<10)+i]; + buf2[(j<<10)+i] = templong; + } + templong = markxlen; + markxlen = markylen; + markylen = templong; + printmessage("X and Y swapped"); + } + } + if (ch == '8') + { + if (buf2 == NULL) + { + printmessage("Not enough memory for that!"); + } + else + { + if (translucloaded == 0) + { + if ((transluc = (char *)convalloc32(65536L)) != 0) + { + for(i=0;i<65536;i++) + transluc[i] = 255; + translucloaded = 1; + printmessage("Transparent table allocated"); + } + else + printmessage("Not enough memory for table"); + } + for(i=0;i>1)+1, markylen = (markylen>>1)+1; + for(i=0;i 1024) markxlen = 1024; + if (markylen > 512) markylen = 512; + for(i=markxlen;i>=0;i--) + for(j=markylen;j>=0;j--) + if ((i < xdim) && (j < ydim)) + buf2[(j<<10)+i] = buf2[((j>>1)<<10)+(i>>1)]; + printmessage("Region now double-size"); + } + } + if ((ch == 'F') || (ch == 'f')) + { + fillregion(c,d,col,col); + showall(buf); + printmessage("Flood Fill"); + asksave = 1; + } + if (ch == 9) + { + drawcolordot(col); + col = buf[(d<<10)+c]; + drawcolordot((col+16)&255); + printmessage("Current color updated"); + } + if ((ch == '+') || (ch == '-')) + { + if ((ch == '+') && ((picanm[picnum]&63) < 63)) + picanm[picnum]++; + if (ch == '-') + { + if ((picanm[picnum]&63) > 0) + picanm[picnum]--; + else + picanm[picnum] = ((picanm[picnum]+64)&0x000000c0)+(picanm[picnum]&0xffffff3f); + } + asksave = 1; + showall(buf); + } + if ((ch == 's') || (ch == 'S')) + { + x = xdim; + y = ydim; + + ch = 0; + while ((ch != 13) && (ch != 27)) + { + sprintf((char *)&buffer,"Xdim: %d_ ",xdim); + printmessage(buffer); + + ch = getch(); + if ((ch >= 48) && (ch <= 57)) + { + i = (xdim*10)+(ch-48); + if (i <= 1024) + xdim = i; + } + if (ch == 8) + { + xdim /= 10; + } + } + if (ch == 13) + { + ch = 0; + while ((ch != 13) && (ch != 27)) + { + sprintf((char *)&buffer,"Ydim: %d_ ",ydim); + printmessage(buffer); + + ch = getch(); + if ((ch >= 48) && (ch <= 57)) + { + i = (ydim*10)+(ch-48); + if (i <= 512) + ydim = i; + } + if (ch == 8) + { + ydim /= 10; + } + } + } + if (ch == 13) + { + c = (xdim>>1); + d = (ydim>>1); + asksave = 1; + drawmainscreen(); + } + else + { + xdim = x; + ydim = y; + showall(buf); + cleartext(); + } + ch = 255; + } + if ((ch == 'g') || (ch == 'G')) + { + ch = 0; + j = picnum; + while ((ch != 13) && (ch != 27)) + { + sprintf((char *)&buffer,"Goto tile: %d_ ",j); + printmessage(buffer); + + ch = getch(); + if ((ch >= 48) && (ch <= 57)) + { + i = (j*10)+(ch-48); + if (i < MAXTILES) + j = i; + } + if (ch == 8) + { + j /= 10; + } + } + if (ch == 13) + { + savewall(buf,picnum); + picnum = j; + loadpics(picnum); + loadwall(buf,picnum); + showall(buf); + drawdot((buf[(d<<10)+c]+16)&255); + } + else + { + cleartext(); + } + ch = 255; + } + if (((ch == 'o') || (ch == 'O')) && (xdim > 0) && (ydim > 0)) + { + x = 0; + y = 0; + + l = 0; + m = xdim; + while ((m > 0) && (l == 0)) + { + l = 0; + for(k=0;k 0) && (l == 0)) + { + l = 0; + for(k=0;k 0) && (l == 0)) + { + l = 0; + for(k=0;k 0) && (l == 0)) + { + l = 0; + for(k=0;k>8)&255)); + i -= (x>>1); + if (i < -128) i = -128; + if (i > 127) i = 127; + picanm[picnum] = (picanm[picnum]&0xffff00ff)+((i&255)<<8); + + i = (long)((signed char)((picanm[picnum]>>16)&255)); + i -= (y>>1); + if (i < -128) i = -128; + if (i > 127) i = 127; + picanm[picnum] = (picanm[picnum]&0xff00ffff)+((i&255)<<16); + + c = (xdim>>1); + d = (ydim>>1); + asksave = 1; + drawmainscreen(); + ch = 255; + } + + if ((ch == 'u') || (ch == 'U')) + { + k = 0; + + if (loadtileofscript(picnum,filename,&x1,&y1,&x2,&y2) == 1) + { + strcpy(menupath,filename); + i = strlen(filename)-1; + while ((menupath[i] != '\\') && (i > 0)) i--; + menupath[i] = 0; + + j = 0; i++; + while (filename[i] != 0) buffer[j++] = filename[i++]; + buffer[j] = 0; + loadpicture(buffer); + + if ((k=selectbox(&x1,&y1,&x2,&y2)) == 1) + captureit(x1,y1,x2,y2,picnum,filename,1); + drawmainscreen(); + chdir(curpath); + + menuhighlight = 0; + } + + while (k == 0) + { + i = menuselect(); + if (i < 0) + { + chdir(curpath); //Error or Escape (cancel) + showall(buf); + if (i == -2) + printmessage("No files found."); + break; + } + else + { + menuhighlight = i; + + loadpicture(menuname[menuhighlight]); + + strcpy(filename,menupath); + strcat(filename,"\\"); + strcat(filename,menuname[menuhighlight]); + x1 = 0x80000000; + if ((k=selectbox(&x1,&y1,&x2,&y2)) == 1) + captureit(x1,y1,x2,y2,picnum,filename,1); + drawmainscreen(); + chdir(curpath); + } + } + + drawdot((buf[(d<<10)+c]+16)&255); + ch = 255; + } + if ((ch == 'v') || (ch == 'V')) + { + savewall(buf,picnum); + savepics(); + picnum = gettile(picnum); + loadpics(picnum); + loadwall(buf,picnum); + drawmainscreen(); + ch = 255; + } + if (((ch == 'a') || (ch == 'A')) && ((picanm[picnum]&192) > 0) && ((picanm[picnum]&63) > 0)) + { + savewall(buf,picnum); + sprintf((char *)&printbuf,"Use +/- to change speed"); + printmessage(&printbuf); + i = 1; + ch = 0; + +#ifdef PLATFORM_DOS + // These should be NOPs for Unix - DDOI + oldtimerhandler = _dos_getvect(0x8); + _dos_setvect(0x8, timerhandler); + outp(0x43,54); outp(0x40,9942&255); outp(0x40,9942>>8); +#endif + totalclock = 0L; + + animspeed = ((((unsigned long)picanm[picnum])>>24)&15); + + j = picnum; + + while ((ch != 13) && (ch != 27)) + { + templong = picnum; + + i = (totalclock>>animspeed); + switch(picanm[templong]&192) + { + case 64: + k = (i%((picanm[templong]&63)<<1)); + if (k < (picanm[templong]&63)) + templong += k; + else + templong += (((picanm[templong]&63)<<1)-k); + break; + case 128: + templong += (i%((picanm[templong]&63)+1)); + break; + case 192: + templong -= (i%((picanm[templong]&63)+1)); + } + + if ((templong >= 0) && (templong < MAXTILES)) + loadwall(buf,templong); + + if (templong != j) + { + j = templong; + //if ((xdim < lastshowallxdim) || (ydim < lastshowallydim)) + cleartopbox(); + } + lastshowallxdim = xdim; + lastshowallydim = ydim; + + copywalltoscreen(buf,templong,1); + + if (kbhit() != 0) + { + ch = getch(); + if ((ch == '+') && (animspeed > 0)) animspeed--; + if ((ch == '-') && (animspeed < 15)) animspeed++; + } + } + +#ifdef PLATFORM_DOS + // NOPs for Unix - DDOI + _dos_setvect(0x8, oldtimerhandler); + outp(0x43,54); outp(0x40,255); outp(0x40,255); +#endif + + cleartopbox(); + + cleartext(); + loadwall(buf,picnum); + showall(buf); + + if (ch == 13) + { + picanm[picnum] = (picanm[picnum]&0xf0ffffff) + (((unsigned long)(animspeed&15))<<24); + asksave = 1; + } + + ch = 255; + } + if ((ch == '`') || (ch == '~')) + { + if ((xdim <= 320) && (ydim <= 200)) + { + sprintf((char *)&printbuf,"Use arrows to change center",animspeed); + printmessage(&printbuf); + templong = picanm[picnum]; + ch = 0; + + copywalltoscreen(buf,picnum,1); + + k = whitecol; + while ((ch != 13) && (ch != 27) && (ch != '`') && (ch != '~')) + { + if (kbhit() != 0) + { + ch = getch(); + if ((ch == '/') || (ch == '?')) + { + picanm[picnum] &= 0xff0000ff; + cleartopbox(); + copywalltoscreen(buf,picnum,1); + } + if (ch == 0) + { + ch = getch(); + if (ch == 75) picanm[picnum] = (((picanm[picnum]+(1<<8))&0x0000ff00)+(picanm[picnum]&0xffff00ff)); + if (ch == 77) picanm[picnum] = (((picanm[picnum]+(255<<8))&0x0000ff00)+(picanm[picnum]&0xffff00ff)); + if (ch == 72) picanm[picnum] = (((picanm[picnum]+(1<<16))&0x00ff0000)+(picanm[picnum]&0xff00ffff)); + if (ch == 80) picanm[picnum] = (((picanm[picnum]+(255<<16))&0x00ff0000)+(picanm[picnum]&0xff00ffff)); + cleartopbox(); + copywalltoscreen(buf,picnum,1); + } + } + readmouse(); + if ((mousx != 0) || (mousy != 0)) + { + i = (long)((signed char)((picanm[picnum]>>8)&255)); + i -= mousx; + if (i < -128) i = -128; + if (i > 127) i = 127; + picanm[picnum] = (picanm[picnum]&0xffff00ff)+((i&255)<<8); + + i = (long)((signed char)((picanm[picnum]>>16)&255)); + i -= mousy; + if (i < -128) i = -128; + if (i > 127) i = 127; + picanm[picnum] = (picanm[picnum]&0xff00ffff)+((i&255)<<16); + + cleartopbox(); + copywalltoscreen(buf,picnum,1); + } + + outp(0x3c4,2); outp(0x3c5,15); + for(i=0;i<320;i+=4) + drawpixel(((((100+16-panyoff)*panxdim)+i)>>2)+(long)VIDEOBASE,k); + outp(0x3c4,2); outp(0x3c5,1); + for(j=0;j<200;j++) + drawpixel(((((j+16-panyoff)*panxdim)+160)>>2)+(long)VIDEOBASE,k); + + k ^= whitecol^blackcol; + } + cleartopbox(); + cleartext(); + if (ch == 27) + picanm[picnum] = templong; + else + asksave = 1; + copywalltoscreen(buf,picnum,0); + ch = 255; + } + } + if ((ch == 'n') || (ch == 'N')) + { + strcpy((char *)&buffer,&names[picnum][0]); + i = 0; + while (buffer[i] != 0) + i++; + buffer[i] = '_'; + buffer[i+1] = 0; + strcpy((char *)&buffer2,"Name: "); + strcat((char *)&buffer2,buffer); + printmessage(&buffer2[0]); + ch = 0; + while ((ch != 13) && (ch != 27)) + { + ch = getch(); + if ((ch > 32) && (i < 16)) + { + buffer[i] = ch; + buffer[i+1] = '_'; + buffer[i+2] = 32; + buffer[i+3] = 0; + i++; + strcpy((char *)&buffer2,"Name: "); + strcat((char *)&buffer2,buffer); + printmessage(&buffer2[0]); + } + if ((ch == 8) && (i > 0)) + { + i--; + buffer[i] = '_'; + buffer[i+1] = 32; + buffer[i+2] = 0; + strcpy((char *)&buffer2,"Name: "); + strcat((char *)&buffer2,buffer); + printmessage(&buffer2[0]); + } + } + if (ch == 13) + { + buffer[i] = 0; + strcpy(&names[picnum][0],&buffer[0]); + needtosavenames = 1; + } + cleartext(); + if (names[picnum][0] != 0) + { + strcpy((char *)&buffer2,"Name: "); + strcat((char *)&buffer2,&names[picnum][0]); + printmessage(&buffer2[0]); + } + } + } + if (moustat == 1) + { + readmouse(); + if ((mousx != 0) || (mousy != 0)) + { + drawdot(buf[(d<<10)+c]); + + xstep = c; + ystep = d; + c += mousx; + d += mousy; + if (c < 0) c = 0; + if (c >= xdim) c = xdim-1; + if (d < 0) d = 0; + if (d >= ydim) d = ydim-1; + drawdot((buf[(d<<10)+c]+16)&255); + } + if (bstatus > 0) + { + x = c; + y = d; + j = labs(xstep-x)+labs(ystep-y); + for(i=0;i 0)) i--; + while ((dapicnum > localtileend[i]) && (i < numtilefiles-1)) i++; + + if ((i == curtilefile) && (dapicnum <= localtileend[i])) + return(-1); + + if (curtilefile == -1) + allasksave = 0; + else + savepics(); + + curtilefile = i; + + if (dapicnum > localtileend[i]) + { + localtilestart[numtilefiles] = localtileend[numtilefiles-1]+1; + localtileend[numtilefiles] = localtilestart[numtilefiles]; + localtileend[numtilefiles] += (localtileend[0]-localtilestart[0]); + for(i=localtilestart[numtilefiles];i<=localtileend[numtilefiles];i++) + { + tilesizx[i] = 0; + tilesizy[i] = 0; + picanm[i] = 0L; + waloff[i] = FP_OFF(pic); + } + numtilefiles++; + curtilefile = numtilefiles-1; + totpicsiz = 0L; + return(0); + } + + danum = curtilefile; + + artfilename[7] = (danum%10)+48; + artfilename[6] = ((danum/10)%10)+48; + artfilename[5] = ((danum/100)%10)+48; + if ((fil = open(artfilename,O_BINARY|O_RDONLY,S_IREAD)) == -1) + { + if (danum == 0) + { + artversion = 1; + numtilefiles = 0; + numtiles = 0; + + localtilestart[numtilefiles] = 0; + localtileend[numtilefiles] = 255; + for(i=localtilestart[0];i<=localtileend[0];i++) + { + tilesizx[i] = 0; + tilesizy[i] = 0; + picanm[i] = 0L; + waloff[i] = FP_OFF(pic); + } + numtilefiles++; + curtilefile = numtilefiles-1; + totpicsiz = 0L; + } + return(0); + } + read(fil,&artversion,4); + if (artversion != 1) return(-1); + read(fil,&numtiles,4); + read(fil,&localtilestart[danum],4); + read(fil,&localtileend[danum],4); + read(fil,&tilesizx[localtilestart[danum]],(localtileend[danum]-localtilestart[danum]+1)<<1); + read(fil,&tilesizy[localtilestart[danum]],(localtileend[danum]-localtilestart[danum]+1)<<1); + read(fil,&picanm[localtilestart[danum]],(localtileend[danum]-localtilestart[danum]+1)<<2); + + totpicsiz = 0L; + offscount = 0L; + for(i=localtilestart[danum];i<=localtileend[danum];i++) + { + waloff[i] = offscount+FP_OFF(pic); + siz = tilesizx[i]*tilesizy[i]; + if (siz > 0) + { + offscount += siz; + totpicsiz += siz; + } + } + + if (totpicsiz >= totpicmem) + { + if (buf2 != NULL) + { + buf2 = NULL; + totpicmem += (1024*512); + } + + if (totpicsiz >= totpicmem) + { + printf("Not enough memory to fit artwork data.\n"); + exit(0); + } + } + + read(fil,&pic[0],totpicsiz); + + close(fil); + return(0); +} + +int savepics(void) +{ + char ch, dabuffer[160]; + long i, templong, offscount, siz, danum; + short int fil; + + if (allasksave == 0) + return(0); + allasksave = 0; + + i = 0; + while (curpath[i] != 0) i++; + curpath[i] = 92; + curpath[i+1] = 0; + chdir(curpath); + curpath[i] = 0; + + numtiles = MAXTILES-1; + while ((tilesizx[numtiles] < 2) && (tilesizy[numtiles] < 2) && (numtiles > 0)) + numtiles--; + numtiles++; + + if (mustsavelocals != 0) + { + mustsavelocals = 0; + + for(danum=0;danum localtileend[danum]) + return(0); + + if (localtilestart[danum] >= MAXTILES) + return(0); + if (localtileend[danum] >= MAXTILES) + localtileend[danum] = MAXTILES-1; + + if ((fil = open(artfilename,O_BINARY|O_CREAT|O_TRUNC|O_WRONLY,UC_PERMS))==-1) + return(-1); + write(fil,&artversion,4); + write(fil,&numtiles,4); + write(fil,&localtilestart[danum],4); + write(fil,&localtileend[danum],4); + write(fil,&tilesizx[localtilestart[danum]],(localtileend[danum]-localtilestart[danum]+1)<<1); + write(fil,&tilesizy[localtilestart[danum]],(localtileend[danum]-localtilestart[danum]+1)<<1); + write(fil,&picanm[localtilestart[danum]],(localtileend[danum]-localtilestart[danum]+1)<<2); + + if (write(fil,&pic[0],totpicsiz) < totpicsiz) + { + printf("SAVE UNSUCCESSFUL!\n"); + return(0); + } + + close(fil); + + sprintf(dabuffer,"%s updated.",artfilename); + printmessage(dabuffer); + + return(0); +} + +int loadwall(char *bufptr, long wallnum) +{ + long i, j, vidpos, dat; + char *picptr; + + picptr = (char *)(waloff[wallnum]); + xdim = tilesizx[wallnum]; + ydim = tilesizy[wallnum]; + + clearbuf(buf,(1024*512)>>2,0xffffffff); + + vidpos = 0; + for(i=0;i= xdim) c = xdim-1; + if (d >= ydim) d = ydim-1; + updatepanning(); + + return(0); +} + +int savewall(char *bufptr, long wallnum) +{ + long i, j, vidpos, dat; + char *picptr, ch; + + if (asksave != 0) + { + if (asksave == 1) + { + asksave = 0; + printmessage("Save current tile?"); + do + { + ch = getch(); + } + while ((ch != 'y') && (ch != 'Y') && (ch != 'n') && (ch != 'N')); + if ((ch == 'n') || (ch == 'N')) + return(0); + } + + allasksave = 1; + + if ((xdim != tilesizx[wallnum]) || (ydim != tilesizy[wallnum])) + { + if (resizetile(wallnum,(long)tilesizx[wallnum],(long)tilesizy[wallnum],xdim,ydim) == -1) + { + printmessage("OUT OF MEMORY! (cancelled)"); + return(-1); + } + else + { + tilesizx[wallnum] = xdim; + tilesizy[wallnum] = ydim; + } + } + + picptr = (char *)(waloff[wallnum]); + xdim = tilesizx[wallnum]; + ydim = tilesizy[wallnum]; + + vidpos = 0; + for(i=0;i= 1000) + printbuf[0] = ((xdim/1000)%10)+48; + else + printbuf[0] = 32; + if (xdim >= 100) + printbuf[1] = ((xdim/100)%10)+48; + else + printbuf[1] = 32; + if (xdim >= 10) + printbuf[2] = ((xdim/10)%10)+48; + else + printbuf[2] = 32; + printbuf[3] = (xdim%10)+48; + printbuf[4] = '*'; + printbuf[5] = 32; + printbuf[6] = 32; + printbuf[7] = 32; + printbuf[8] = 0; + if (ydim >= 100) + { + printbuf[5] = ((ydim/100)%10)+48; + printbuf[6] = ((ydim/10)%10)+48; + printbuf[7] = (ydim%10)+48; + } + else if (ydim >= 10) + { + printbuf[5] = ((ydim/10)%10)+48; + printbuf[6] = (ydim%10)+48; + } + else if (ydim >= 1) + { + printbuf[5] = (ydim%10)+48; + } + else + { + printbuf[5] = '0'; + } + printext256(80L,0L,whitecol,blackcol,&printbuf); + } + + sprintf(&printbuf,"Tile:"); + printbuf[5] = 32; + printbuf[6] = 32; + printbuf[7] = 32; + printbuf[8] = 32; + printbuf[9] = 0; + if (picnum >= 1000) + { + printbuf[5] = ((picnum/1000)%10)+48; + printbuf[6] = ((picnum/100)%10)+48; + printbuf[7] = ((picnum/10)%10)+48; + printbuf[8] = (picnum%10)+48; + } + else if (picnum >= 100) + { + printbuf[5] = ((picnum/100)%10)+48; + printbuf[6] = ((picnum/10)%10)+48; + printbuf[7] = (picnum%10)+48; + } + else if (picnum >= 10) + { + printbuf[5] = ((picnum/10)%10)+48; + printbuf[6] = (picnum%10)+48; + } + else if (picnum >= 1) + { + printbuf[5] = (picnum%10)+48; + } + else + { + printbuf[5] = '0'; + } + printext256(0L,0L,whitecol,blackcol,&printbuf); + + if (names[picnum][0] != 0) + printmessage(&names[picnum][0]); + + copywalltoscreen(bufptr,picnum,0); + + return(0); +} + +void copywalltoscreen(char *bufptr, long dapicnum, char maskmode) +{ + char *ptr; + long plane, i, j, jstart, jend, vidpos, dat, daydim, cnt, xoff, yoff; + + xoff = 0; yoff = 0; + if ((xdim <= 320) && (ydim <= 200)) + { + xoff = 160L-(xdim>>1)-(long)((signed char)((picanm[dapicnum]>>8)&255)); + yoff = 100L-(ydim>>1)-(long)((signed char)((picanm[dapicnum]>>16)&255)); + } + + daydim = ydim; + if (daydim > 240) daydim = 240; + + if (maskmode == 1) + blackmasklookup[255] = blackcol; + else + blackmasklookup[255] = 255; + + for(plane=0;plane<4;plane++) + { + outp(0x3c4,2); outp(0x3c5,1<<((plane+xoff)&3)); + + jstart = panyoff; + jend = daydim+panyoff; + if (jstart-panyoff+yoff < 0) jstart = 0+panyoff-yoff; + if (jend-panyoff+yoff > 240) jend = 240+panyoff-yoff; + for(j=jstart;j>2)+VIDEOBASE; + + cnt = xdim-plane; + ptr = (char *)(bufptr+plane+(j<<10)); + + while (cnt > 12) + { + dat = blackmasklookup[*ptr]; + dat += (blackmasklookup[*(ptr+4)]<<8); + dat += (blackmasklookup[*(ptr+8)]<<16); + dat += (blackmasklookup[*(ptr+12)]<<24); + drawpixelses(vidpos,dat); + vidpos += 4; + ptr += 16; + cnt -= 16; + } + while (cnt > 0) + { + drawpixel(vidpos,blackmasklookup[*ptr]); + vidpos++; + ptr += 4; + cnt -= 4; + } + } + } +} + +int drawdot(char col) +{ + long vidpos, dat, xoff, yoff; + + updatepanning(); + + xoff = 0; yoff = 0; + if ((xdim <= 320) && (ydim <= 200)) + { + xoff = 160L-(xdim>>1)-(long)((signed char)((picanm[picnum]>>8)&255)); + yoff = 100L-(ydim>>1)-(long)((signed char)((picanm[picnum]>>16)&255)); + } + + dat = col; + if ((xdim|ydim) == 0) return(-1); + outp(0x3c4,2); outp(0x3c5,1<<((c+xoff)&3)); + vidpos = (((((d+yoff)+16-panyoff)*panxdim)+(c+xoff))>>2)+VIDEOBASE; + drawpixel(vidpos,dat); + + return(0); +} + +void updatepanning(void) +{ + long num, opanyoff; + + panx = 0; + pany = 0; + if (xdim > 320) + { + panx = c-160; + if (panx < 0) panx = 0; + if (panx > xdim-320) panx = xdim-320; + } + if (ydim > 184) + { + pany = d-92; + if (pany < 0) pany = 0; + if (pany > ydim-184) pany = ydim-184; + } + + opanyoff = panyoff; + while ((pany > panyoff+56) && (panyoff < 512)) panyoff += 56; + while ((pany < panyoff) && (panyoff > 0)) panyoff -= 56; + + num = (pany-panyoff+16)*panxdim+panx; + outp(0x3d4,0xc); outp(0x3d5,num>>10); + outp(0x3d4,0xd); outp(0x3d5,(num>>2)&255); + outp(0x3c0,inp(0x3c0)|0x13); outp(0x3c0,(num&3)<<1); + + if (panyoff != opanyoff) + copywalltoscreen(buf,picnum,0); +} + +/* Panning... ick! This should be fun stuff to port - DDOI */ +void updatepanningforumode(long dax, long day) +{ + long num; + + panxforu = 0; + panyforu = 0; + if (xres > 320) + { + panxforu = dax-160; + if (panxforu < 0) panxforu = 0; + if (panxforu > xres-320) panxforu = xres-320; + } + if (yres > 200) + { + panyforu = day-100; + if (panyforu < 0) panyforu = 0; + if (panyforu > yres-200) panyforu = yres-200; + } + + num = panyforu*panxdim+panxforu; + outp(0x3d4,0xc); outp(0x3d5,num>>10); + outp(0x3d4,0xd); outp(0x3d5,(num>>2)&255); + outp(0x3c0,inp(0x3c0)|0x13); outp(0x3c0,(num&3)<<1); +} + +void drawcolordot(char thecol) +{ + long vidpos, dat; + + outp(0x3c4,2); outp(0x3c5,1<<(((col&31)*3+1)&3)); + vidpos = ((((col>>5)*2)*panxdim+((col&31)*3+225))>>2)+VIDEOBASE; + drawpixel(vidpos,(long)thecol); + drawpixel(vidpos+(panxdim>>2),(long)thecol); +} + +void loadpicture(char *filename) +{ + long i; + + outp(0x3c4,2); outp(0x3c5,0xf); + clearbuf(VIDEOBASE,16384L,0L); //clear frame (for small pictures) + + i = 0; + while (filename[i] != '.') i++; + switch(filename[i+1]) + { + case 'B': loadbmp(filename); break; + case 'P': loadpcx(filename); break; + case 'G': loadgif(filename); break; + } + + outp(0x3c7,0); + for(i=0;i<768;i++) + palette2[i] = inp(0x3c9); + getpaletteconversion(); +} + +int loadbmp(char *filename) +{ + long fil, i, j; + + if ((fil = open(filename,O_BINARY|O_RDWR,S_IREAD)) == -1) + return(-1); + read(fil,&tempbuf[0],4); + if ((tempbuf[0] == 'B') && (tempbuf[1] == 'M') && (tempbuf[2] == 'Z') && (tempbuf[3] == 34)) + { + read(fil,&tempbuf[0],22); + read(fil,&tempbuf[0],768); + outp(0x3c8,0); + for(i=0;i<256;i++) + { + outp(0x3c9,tempbuf[i+i+i+2]>>2); + outp(0x3c9,tempbuf[i+i+i+1]>>2); + outp(0x3c9,tempbuf[i+i+i+0]>>2); + } + } + else + { + read(fil,&tempbuf[0],50); + read(fil,&tempbuf[0],1024); + outp(0x3c8,0); + for(i=0;i<1024;i++) + if ((i&3) != 0) + outp(0x3c9,tempbuf[i^3]>>2); + } + + xres = 320; + yres = 200; + + for(j=0;j<200;j++) + { + read(fil,&tempbuf[0],320); + for(i=0;i<320;i++) + { + outp(0x3c4,2); outp(0x3c5,1<<(i&3)); + drawpixel((((199-j)*panxdim+i)>>2)+(long)VIDEOBASE,tempbuf[i]); + } + } + close(fil); + return(0); +} + +int loadpcx(char *filename) +{ + unsigned char dat; + long fil, i, x, y, datcnt, leng; + + if ((fil = open(filename,O_BINARY|O_RDWR,S_IREAD)) == -1) + return(-1); + read(fil,&tempbuf[0],128); + + x = 0; + y = 0; + xres = ((long)tempbuf[12])+(((long)tempbuf[13])<<8); + yres = ((long)tempbuf[14])+(((long)tempbuf[15])<<8); + + read(fil,&tempbuf[0],4096), datcnt = 0; + while (y < yres) + { + dat = tempbuf[datcnt++]; + if (datcnt == 4096) + read(fil,&tempbuf[0],4096), datcnt = 0; + if ((dat&0xc0) == 0xc0) + { + leng = (dat&0x3f); + dat = tempbuf[datcnt++]; + if (datcnt == 4096) + read(fil,&tempbuf[0],4096), datcnt = 0; + for(i=0;i>2)+(long)VIDEOBASE,dat); + } + x++; + if (x >= xres) + { + x = 0; + y++; + } + } + } + else + { + if (y < 256) + { + outp(0x3c4,0x2); outp(0x3c5,1<<(x&3)); + drawpixel((((y*panxdim)+x)>>2)+(long)VIDEOBASE,dat); + } + x++; + if (x >= xres) + { + x = 0; + y++; + } + } + } + dat = tempbuf[datcnt++]; + if (datcnt == 4096) + read(fil,&tempbuf[0],4096), datcnt = 0; + if (dat == 0xc) + { + outp(0x3c8,0); + for(i=0;i<768;i++) + { + dat = tempbuf[datcnt++]; + if (datcnt == 4096) + read(fil,&tempbuf[0],4096), datcnt = 0; + outp(0x3c9,dat>>2); + } + } + close(fil); + + return(0); +} + +int loadgif(char *filename) +{ + unsigned char header[13], imagestat[10], bitcnt, numbits; + unsigned char globalflag, chunkind; + short i, j, k, m; + short currstr, bytecnt, numbitgoal; + short numcols, numpals, dat, fil, blocklen, firstring; + short unsigned int numlines, gifdatacnt; + long x, y; + + if ((strstr(filename,".gif") == 0) && (strstr(filename,".GIF") == 0)) + strcat(filename,".gif"); + if ((fil = open(filename,O_BINARY|O_RDONLY,S_IREAD)) == -1) + return(-1); + gifdatacnt = 0; + read(fil,&gifdata[0],(unsigned)GIFBUFLEN); + for(j=0;j<13;j++) + header[j] = gifdata[j+gifdatacnt]; + gifdatacnt += 13; + if ((header[0] != 'G') || (header[1] != 'I') || (header[2] != 'F')) + return(-1); + globalflag = header[10]; + numcols = (1<<((globalflag&7)+1)); + firstring = numcols+2; + if (header[12] != 0) + return(-1); + if ((globalflag&128) > 0) + { + numpals = numcols+numcols+numcols; + for(j=0;j 0) + gifdatacnt += chunkind; + } + while (chunkind > 0); + chunkind = gifdata[gifdatacnt], gifdatacnt++; + } + if (chunkind == ',') + { + for(j=0;j<9;j++) + imagestat[j] = gifdata[j+gifdatacnt]; + gifdatacnt += 9; + xres = imagestat[4]+(imagestat[5]<<8); + yres = imagestat[6]+(imagestat[7]<<8); + if ((imagestat[8]&128) > 0) //localflag + { + numpals = numcols+numcols+numcols; + for(j=0;j>2); + + x = 0; + y = 0; + + bitcnt = 0; + for(i=0;i>3); + bitcnt = ((bitcnt+numbits)&7); + if (bytecnt > blocklen-3) + { + giffilbuffer[0] = giffilbuffer[bytecnt]; + giffilbuffer[1] = giffilbuffer[bytecnt+1]; + i = blocklen-bytecnt; + blocklen = (short)gifdata[gifdatacnt++]; + if (gifdatacnt+blocklen < GIFBUFLEN) + { + for(m=0;m numcols+1) + { + giftempstack[k++] = gifsuffix[dat]; + dat = gifprefix[dat]; + } + giftempstack[k++] = gifprefix[dat]; + gifsuffix[currstr-1] = dat; + gifsuffix[currstr] = dat; + for(i=k-1;i>=0;i--) + { + if (y < 256) + { + outp(0x3c4,0x2); outp(0x3c5,1<<(x&3)); + drawpixel((((y*panxdim)+x)>>2)+(long)VIDEOBASE,giftempstack[i]); + } + x++; + if (x >= xres) + { + x = 0; + y++; + } + } + currstr++; + } + } + } + close(fil); + return(0); +} + +void drawmainscreen(void) +{ + long i, j, lin, templong, dat; + + outp(0x3c4,2); outp(0x3c5,15); + clearbuf(VIDEOBASE,16384,0L); + + /* Doh! 'Line compare' aren't words I like to see here - DDOI */ + inp(0x3da); outp(0x3c0,0x30); outp(0x3c0,113); //FIX FOR LINE COMPARE + outp(0x3d4,0x11); outp(0x3d5,inp(0x3d5)&(255-128)); //Unlock indeces 0-7 + outp(0x3d4,21); outp(0x3d5,142); + + lin = 399 - 32; + outp(0x3d4,0x18); outp(0x3d5,lin&255); + outp(0x3d4,0x7); outp(0x3d5,(inp(0x3d5)&239)|((lin&256)>>4)); + outp(0x3d4,0x9); outp(0x3d5,(inp(0x3d5)&191)|((lin&512)>>3)); + + outp(0x3c8,0); + for(i=0;i<768;i++) + outp(0x3c9,palette[i]); + for(i=0;i<32;i++) + for(j=0;j<8;j++) + { + templong = (j*2*panxdim)+(i*3+224); + dat = (j<<5)+i; + drawchainpixel(templong,dat); + drawchainpixel(templong+1,dat); + drawchainpixel(templong+2,dat); + drawchainpixel(templong+panxdim,dat); + drawchainpixel(templong+panxdim+1,dat); + drawchainpixel(templong+panxdim+2,dat); + } + + showall(buf); + drawdot((buf[(d<<10)+c]+16)&255); + drawcolordot((col+16)&255); +} + +int drawxorbox(long x1, long y1, long x2, long y2, char col) +{ + long i, p, dat, temp; + + dat = (long)col; + dat += (dat<<8); + if (x1 > x2) temp = x1, x1 = x2, x2 = temp; + if (y1 > y2) temp = y1, y1 = y2, y2 = temp; + + outp(0x3c4,2); outp(0x3c5,1<<(x1&3)); + outp(0x3ce,4); outp(0x3cf,x1&3); + p = VIDEOBASE + (((y1+1)*panxdim+x1)>>2); + for(i=y1+1;i>2); + } + + outp(0x3c4,2); outp(0x3c5,1<<(x2&3)); + outp(0x3ce,4); outp(0x3cf,x2&3); + p = VIDEOBASE + (((y1+1)*panxdim+x2)>>2); + for(i=y1+1;i>2); + } + + for(i=x1;i<=x2;i++) + { + outp(0x3c4,2); outp(0x3c5,1<<(i&3)); + outp(0x3ce,4); outp(0x3cf,i&3); + + p = VIDEOBASE + ((y1*panxdim+i)>>2); + drawpixel(p,getpixel(p)^col); + + p = VIDEOBASE + ((y2*panxdim+i)>>2); + drawpixel(p,getpixel(p)^col); + } + + return(0); +} + +int drawmaskedbox(long x1, long y1, long x2, long y2, char col, char mask1, char mask2) +{ + long i, j, p, pinc, dat, temp; + + dat = (long)col; dat += (dat<<8); dat += (dat<<16); + if (x1 > x2) temp = x1, x1 = x2, x2 = temp; + if (y1 > y2) temp = y1, y1 = y2, y2 = temp; + + pinc = (panxdim>>1); + + outp(0x3c4,2); + outp(0x3c5,mask1); + for(j=y1;j>2); + for(i=((x2-x1)>>4);i>0;i--) { drawpixelses(p,dat); p += 4; } + } + + outp(0x3c5,mask2); + for(j=(y1+1);j>2); + for(i=((x2-x1)>>4);i>0;i--) { drawpixelses(p,dat); p += 4; } + } + + return(0); +} + +void getpaletteconversion(void) +{ + long i, j, totintens1, totintens2, brichang, c1, c2, c3, bestcol, dadist; + long zx; + + totintens1 = 0; + totintens2 = 0; + for(i=0;i<768;i++) + { + totintens1 += palette[i]; + totintens2 += palette2[i]; + } + brichang = (totintens1-totintens2)/768; + for(i=0;i<768;i+=3) + { + c1 = palette2[i]+brichang; + c2 = palette2[i+1]+brichang; + c3 = palette2[i+2]+brichang; + bestcol = 0; + dadist = 65536; + for(j=0;j<768;j+=3) + { + zx = 30*(c1-palette[j])*(c1-palette[j]); + zx += 59*(c2-palette[j+1])*(c2-palette[j+1]); + zx += 11*(c3-palette[j+2])*(c3-palette[j+2]); + if (zx < dadist) + dadist = zx, bestcol = j/3; + } + palookupe[i/3] = bestcol; + } + palookupe[255] = 255; +} + +int fillregion(long x, long y, char col, char bound) +{ + unsigned char tstat, bstat, tlast, blast; + int i, leftz, z, zz, c; + + c = 1; + xfillbuf[c] = x; + yfillbuf[c] = y; + if (buf[(y<<10)+x] == bound) + return(-1); + while (c > 0) + { + z = xfillbuf[c]; + zz = yfillbuf[c]; + c--; + while ((buf[(zz<<10)+(z-1)] != bound) && (z > 0)) + z--; + leftz = z; + tlast = 0; + blast = 0; + while ((buf[(zz<<10)+z] != bound) && (z < xdim)) + { + if (zz > 0) + { + tstat = buf[((zz-1)<<10)+z]; + if ((tstat != bound) && (tstat != col)) + { + if (tlast == 0) + { + c++; + xfillbuf[c] = z; + yfillbuf[c] = zz-1; + tlast = 1; + } + } + else + tlast = 0; + } + if (zz < ydim-1) + { + bstat = buf[((zz+1)<<10)+z]; + if ((bstat != bound) && (bstat != col)) + { + if (blast == 0) + { + c++; + xfillbuf[c] = z; + yfillbuf[c] = zz+1; + blast = 1; + } + } + else + blast = 0; + } + z++; + } + z--; + while (z >= leftz) + { + if ((z >= 0) && (z < xdim)) + buf[(zz<<10)+z] = col; + z--; + } + } + return(0); +} + +void getpalookup(void) +{ + long i, j, k, dist, mindist, c1, c2, c3, closest; + + for(i=0;i>4)); + outp(0x3d4,0x9); outp(0x3d5,(inp(0x3d5)&191)|((lin&512)>>3)); + num = 0; + outp(0x3d4,0xc); outp(0x3d5,num>>10); + outp(0x3d4,0xd); outp(0x3d5,(num>>2)&255); + outp(0x3c0,inp(0x3c0)|0x13); outp(0x3c0,(num&3)<<1); + + panxdim = 512; + outp(0x3d4,0x9); outp(0x3d5,inp(0x3d5) & ~1); + outp(0x3d4,0x13); outp(0x3d5,panxdim>>3); + + otilenum = tilenum; + movetilenum = -1; + movetilenum1 = -1; + movetilenum2 = -1; + + topleft = ((tilenum/(5< MAXTILES-(15<<(gettilezoom<<1))) topleft = MAXTILES-(15<<(gettilezoom<<1)); + drawtilescreen(topleft); + + xorcol = (rand()&255); + x1 = ((tilenum-topleft)%(5<>gettilezoom); + y1 = ((tilenum-topleft)/(5<>gettilezoom); + x2 = x1+(64>>gettilezoom)-1; + y2 = y1+(128>>gettilezoom)-1; + drawxorbox(x1,y1,x2,y2,xorcol); + + ch = 0; + while ((ch != 27) && (ch != 13)) + { + x1 = ((tilenum-topleft)%(5<>gettilezoom); + y1 = ((tilenum-topleft)/(5<>gettilezoom); + x2 = x1+(64>>gettilezoom)-1; + y2 = y1+(128>>gettilezoom)-1; + while (kbhit() == 0) + { + limitrate(); + drawxorbox(x1,y1,x2,y2,xorcol); + xorcol = (rand()&255); + limitrate(); + drawxorbox(x1,y1,x2,y2,xorcol); + } + ch = getch(); + if ((ch == '*') && (gettilezoom < 2)) + { + gettilezoom++; + topleft = ((tilenum/(5< MAXTILES-(15<<(gettilezoom<<1))) topleft = MAXTILES-(15<<(gettilezoom<<1)); + drawtilescreen(topleft); + + x1 = ((tilenum-topleft)%(5<>gettilezoom); + y1 = ((tilenum-topleft)/(5<>gettilezoom); + x2 = x1+(64>>gettilezoom)-1; + y2 = y1+(128>>gettilezoom)-1; + drawxorbox(x1,y1,x2,y2,xorcol); + } + if ((ch == '/') && (gettilezoom > 0)) + { + gettilezoom--; + topleft = ((tilenum/(5< MAXTILES-(15<<(gettilezoom<<1))) topleft = MAXTILES-(15<<(gettilezoom<<1)); + drawtilescreen(topleft); + + x1 = ((tilenum-topleft)%(5<>gettilezoom); + y1 = ((tilenum-topleft)/(5<>gettilezoom); + x2 = x1+(64>>gettilezoom)-1; + y2 = y1+(128>>gettilezoom)-1; + drawxorbox(x1,y1,x2,y2,xorcol); + } + + if (ch == 32) + { + if (tilesreported != 0) //Toggle registered / shareware + { + picanm[tilenum] ^= 0x80000000; + allasksave = 1; + asksave = 1; + drawtilescreen(topleft); + + x1 = ((tilenum-topleft)%(5<>gettilezoom); + y1 = ((tilenum-topleft)/(5<>gettilezoom); + x2 = x1+(64>>gettilezoom)-1; + y2 = y1+(128>>gettilezoom)-1; + drawxorbox(x1,y1,x2,y2,xorcol); + } + else //Swap walls + { + if (movetilenum == -1) + movetilenum = tilenum; + else + { + if (swapwalls(tilenum,movetilenum) == 1) + { + //Redraw screen + drawtilescreen(topleft); + + x1 = ((tilenum-topleft)%(5<>gettilezoom); + y1 = ((tilenum-topleft)/(5<>gettilezoom); + x2 = x1+(64>>gettilezoom)-1; + y2 = y1+(128>>gettilezoom)-1; + drawxorbox(x1,y1,x2,y2,xorcol); + } + movetilenum = -1; + movetilenum1 = -1; + movetilenum2 = -1; + } + } + } + if (ch == '1') movetilenum1 = tilenum; + if (ch == '2') movetilenum2 = tilenum; + if (ch == '3') + { + if ((movetilenum1 >= 0) && (movetilenum2 >= 0)) + { + if (movetilenum1 > movetilenum2) + templong = movetilenum1, movetilenum1 = movetilenum2, movetilenum2 = templong; + + j = 0; + for(i=movetilenum1;i<=movetilenum2;i++) + j |= swapwalls(i,tilenum+i-movetilenum1); + + if (j != 0) + { + //Redraw screen + drawtilescreen(topleft); + + x1 = ((tilenum-topleft)%(5<>gettilezoom); + y1 = ((tilenum-topleft)/(5<>gettilezoom); + x2 = x1+(64>>gettilezoom)-1; + y2 = y1+(128>>gettilezoom)-1; + drawxorbox(x1,y1,x2,y2,xorcol); + } + } + movetilenum = -1; + movetilenum1 = -1; + movetilenum2 = -1; + } + + if (ch == 0) + { + ch = getch(); + + x1 = ((tilenum-topleft)%(5<>gettilezoom); + y1 = ((tilenum-topleft)/(5<>gettilezoom); + x2 = x1+(64>>gettilezoom)-1; + y2 = y1+(128>>gettilezoom)-1; + drawxorbox(x1,y1,x2,y2,xorcol); + + if (ch == 19) //ALT-R (tile frequency report) + { + tilesreported ^= 1; + if (tilesreported == 1) reportmaps(); + + //Redraw screen + drawtilescreen(topleft); + } + if (ch == 32) //Alt-D DELETE ALL REGISTERED TILES!!! + { + drawmaskedbox(0,0,319,7,blackcol,0xff,0xff); + printext256(0L,0L,whitecol,-2,"DELETE ALL REGISTERED TILES NOW?"); + while ((ch != 'y') && (ch != 'Y') && (ch != 'n') && (ch != 'N')) + ch = getch(); + if ((ch == 'y') || (ch == 'Y')) + { + drawmaskedbox(0,0,319,15,blackcol,0xff,0xff); + printext256(0L,0L,whitecol,-2,"DELETING!!! Now you've done it!"); + printext256(0L,0L,whitecol,-2,"(Have a nice day)"); + for(i=0;i= 0) && (movetilenum2 >= 0)) + { + if (movetilenum1 > movetilenum2) + templong = movetilenum1, movetilenum1 = movetilenum2, movetilenum2 = templong; + + updatescript(movetilenum1,movetilenum2); + + outp(0x3c8,0); + for(i=0;i<768;i++) + outp(0x3c9,palette[i]); + + drawtilescreen(topleft); + } + } + if (ch == 82) //Insert tile (localtile trick - fast!) + { + loadpics(tilenum); + + for(i=localtileend[curtilefile];i>=tilenum+1;i--) + { + tilesizx[i] = tilesizx[i-1]; + tilesizy[i] = tilesizy[i-1]; + picanm[i] = picanm[i-1]; + waloff[i] = waloff[i-1]; + + tilookup[i] = tilookup[i-1]; + + for(j=0;j<17;j++) + names[i][j] = names[i-1][j]; + } + tilesizx[tilenum] = 0; + tilesizy[tilenum] = 0; + picanm[tilenum] = 0; + for(j=0;j<17;j++) + names[tilenum][j] = 0; + + needtosavenames = 1; + mustsavelocals = 1; + allasksave = 1; + savepics(); + + drawtilescreen(topleft); + } + if (ch == 83) //Delete tile (localtile trick - fast!) + { + if (tilesreported == 0) + { + loadpics(tilenum); + + if (resizetile(tilenum,(long)tilesizx[tilenum],(long)tilesizy[tilenum],0L,0L) != -1) + { + for(i=tilenum;i<=localtileend[curtilefile];i++) + { + tilesizx[i] = tilesizx[i+1]; + tilesizy[i] = tilesizy[i+1]; + picanm[i] = picanm[i+1]; + waloff[i] = waloff[i+1]; + + tilookup[i] = tilookup[i+1]; + + for(j=0;j<17;j++) + names[i][j] = names[i+1][j]; + } + tilesizx[localtileend[curtilefile]] = 0; + tilesizy[localtileend[curtilefile]] = 0; + picanm[localtileend[curtilefile]] = 0; + for(j=0;j<17;j++) + names[localtileend[curtilefile]][j] = 0; + + needtosavenames = 1; + mustsavelocals = 1; + allasksave = 1; + savepics(); + } + drawtilescreen(topleft); + } + else + { + loadpics(tilenum); + + if (resizetile(tilenum,(long)tilesizx[tilenum],(long)tilesizy[tilenum],0L,0L) != -1) + { + tilesizx[tilenum] = 0; + tilesizy[tilenum] = 0; + allasksave = 1; + savepics(); + } + drawtilescreen(topleft); + } + } + if ((ch == 75) && (tilenum > 0)) tilenum--; + if ((ch == 77) && (tilenum < MAXTILES-1)) tilenum++; + if ((ch == 72) && (tilenum >= (5<= (5<= MAXTILES) tilenum = MAXTILES-1; + } + if (tilenum < topleft) + { + while (tilenum < topleft) + topleft -= (5<= topleft+(15<<(gettilezoom<<1))) + { + while (tilenum >= topleft+(15<<(gettilezoom<<1))) + topleft += (5< MAXTILES-(15<<(gettilezoom<<1))) topleft = MAXTILES-(15<<(gettilezoom<<1)); + drawtilescreen(topleft); + } + + x1 = ((tilenum-topleft)%(5<>gettilezoom); + y1 = ((tilenum-topleft)/(5<>gettilezoom); + x2 = x1+(64>>gettilezoom)-1; + y2 = y1+(128>>gettilezoom)-1; + drawxorbox(x1,y1,x2,y2,xorcol); + } + } + + panxdim = 1024; + outp(0x3d4,0x9); outp(0x3d5,inp(0x3d5) | 1); + outp(0x3d4,0x13); outp(0x3d5,panxdim>>3); + + if (ch != 13) tilenum = otilenum; + return(tilenum); +} + +int drawtilescreen(long pictopleft) +{ + long i, j, k, vidpos, vidpos2, wallnum, xdime, ydime, cnt, scaledown; + long dat, dat2, ocurtilefile; + char *picptr, buffer[16]; + + outp(0x3c4,2); outp(0x3c5,0xf); + clearbuf(VIDEOBASE,(512L*400L)>>4,0L); //clear frame first + + loadpics(pictopleft); + + for(cnt=0;cnt<(15<<(gettilezoom<<1));cnt++) //draw the (5*3)<>gettilezoom); + j = (cnt/(5<>gettilezoom); + if (i > 2) + { + drawxorbox(i-2,j,i-1,j+(128>>gettilezoom)-1,whitecol); + drawxorbox(0,j+(128>>gettilezoom)-2,i-3,j+(128>>gettilezoom)-1,whitecol); + } + if (j > 2) + { + if (i < 2) i = 2; //Safety precaution + drawxorbox(i-2,j-2,319,j-1,whitecol); + } + } + + if ((tilesizx[wallnum] != 0) && (tilesizy[wallnum] != 0)) + { + picptr = (char *)(waloff[wallnum]); + xdime = tilesizx[wallnum]; + ydime = tilesizy[wallnum]; + + vidpos = (cnt/(5<>gettilezoom))+(cnt%(5<>gettilezoom); + if ((xdime <= (64>>gettilezoom)) && (ydime <= (64>>gettilezoom))) + { + for(i=0;i>2)+VIDEOBASE; + for(j=0;j>2),dat); + vidpos2 += (panxdim>>1); + } + vidpos++; + } + } + else //if 1 dimension > (64>>gettilezoom) + { + if (xdime > ydime) + scaledown = ((xdime+(63>>gettilezoom))>>(6-gettilezoom)); + else + scaledown = ((ydime+(63>>gettilezoom))>>(6-gettilezoom)); + + for(i=0;i>2)+VIDEOBASE; + + j = 0; + while (j < ydime) + { + dat = *picptr; drawpixel(vidpos2,dat); + picptr += (scaledown>>1); + + if (j+(scaledown>>1) >= ydime) + break; + + dat2 = *picptr; drawpixel(vidpos2+(panxdim>>2),dat2); + picptr += scaledown-(scaledown>>1); + + vidpos2 += (panxdim>>1); + j += scaledown; + } + vidpos++; + } + } + } + + if (tilesreported == 1) + { + i = (cnt%(5<>gettilezoom); + j = (cnt/(5<>gettilezoom); + if (picanm[wallnum]&0x80000000) + { + drawmaskedbox(i,j,i+(64>>gettilezoom),j+(128>>gettilezoom),whitecol,0x55,0xaa); + printext256(i+(32>>gettilezoom)-11,j+(64>>gettilezoom)-3,blackcol,-1,"Pay"); + printext256(i+(32>>gettilezoom)-12,j+(64>>gettilezoom)-4,whitecol,-1,"Pay"); + } + sprintf(buffer,"%ld",tilookup2[wallnum]); + printext256(i,j,whitecol,blackcol,buffer); + } + } + return(0); +} + +int loadnames(void) +{ + char buffer[160], firstch, ch; + short int fil, i, num, buffercnt; + + if ((fil = open("names.h",O_BINARY|O_RDWR,S_IREAD)) == -1) + return(-1); + + do + { + i = read(fil,&firstch,1); + } + while ((firstch != '#') && (i > 0)); + + while ((firstch == '#') || (firstch == '/')) + { + do + { + read(fil,&ch,1); + } + while (ch > 32); + + buffercnt = 0; + do + { + read(fil,&ch,1); + if (ch > 32) + buffer[buffercnt++] = ch; + } + while (ch > 32); + + num = 0; + do + { + read(fil,&ch,1); + if ((ch >= 48) && (ch <= 57)) + num = num*10+(ch-48); + } + while (ch != 13); + for(i=0;i= 10000) buffer[j++] = ((i/10000)%10)+48; + if (i >= 1000) buffer[j++] = ((i/1000)%10)+48; + if (i >= 100) buffer[j++] = ((i/100)%10)+48; + if (i >= 10) buffer[j++] = ((i/10)%10)+48; + buffer[j++] = (i%10)+48; + + buffer[j++] = 13; + buffer[j++] = 10; + write(fil,&buffer[0],j); + } + + close(fil); + return; +} + +void initmenupaths(char *filename) +{ + long i; + + strcpy((char *)&curpath,filename); + i = 0; + while ((i < 160) && (curpath[i] != 0)) i++; + while ((i > 0) && (curpath[i] != 92)) i--; + curpath[i] = 0; + strcpy((char *)&menupath,curpath); +} + +int getfilenames(char *kind) +{ +#ifdef PLATFORM_DOS + short type; + struct find_t fileinfo; + + if (strcmp(kind,"SUBD") == 0) + { + strcpy(kind,"*.*"); + if (_dos_findfirst(kind,_A_SUBDIR,&fileinfo) != 0) + return(-1); + type = 1; + } + else + { + if (_dos_findfirst(kind,_A_NORMAL,&fileinfo) != 0) + return(-1); + type = 0; + } + do + { + if ((type == 0) || ((fileinfo.attrib&16) > 0)) + if ((fileinfo.name[0] != '.') || (fileinfo.name[1] != 0)) + { + if (menunamecnt < 256) + { + strcpy(menuname[menunamecnt],fileinfo.name); + menuname[menunamecnt][16] = type; + menunamecnt++; + } + else + printmessage("Too many files! (max=256)"); + } + } + while (_dos_findnext(&fileinfo) == 0); +#else + // Similar to the one in build.c, which makes things easy :) - DDOI + DIR *dir; + struct dirent *dent; + struct stat statbuf; + int add_this; + int subdirs = 0; + + if (strcmp (kind, "SUBD") == 0) + subdirs = 1; + dir = opendir ("."); + if (dir == NULL) + return (-1); + + do + { + add_this = 0; + dent = readdir(dir); + if (dent != NULL) + { + if (stat(dent->d_name, &statbuf) == 0) + { + if ((subdirs) && (S_ISDIR(statbuf.st_mode))) + add_this = 1; + else if (fnmatch(kind, dent->d_name, FNM_CASEFOLD) == 0) + add_this = 1; + + if (add_this) + { + if (menunamecnt >= 256) { + printmessage("Too many files! (max=256)"); + } else { + strcpy (menuname[menunamecnt], dent->d_name); + menuname[menunamecnt][16] = subdirs; + menunamecnt++; + } + } + } + } + } while (dent != NULL); + + closedir (dir); +#endif + return(0); +} + +void sortfilenames(void) +{ + char sortbuffer[17]; + long i, j, k, m; + + for(i=1;i= menunamecnt) menuhighlight = menunamecnt-1; + + newhighlight = menuhighlight; + do + { + if (menunamecnt <= 22) + { + topplc = 0; + } + else + { + topplc = newhighlight-11; + if (topplc < 0) topplc = 0; + if (topplc > menunamecnt-23) topplc = menunamecnt-23; + } + + for(i=0;i= 0) && (i-topplc <= 22)) + { + if (menuname[i][16] == 1) + { + printext256(panx,((i-topplc)<<3)+16L+pany-panyoff,greencol,blackcol,buffer); + } + else + { + printext256(panx,((i-topplc)<<3)+16L+pany-panyoff,whitecol,blackcol,buffer); + } + } + } + ch = getch(); + if (ch == 0) + { + ch = getch(); + if ((ch == 75) || (ch == 72)) + { + newhighlight--; + if (newhighlight < 0) + newhighlight = menunamecnt-1; + } + if ((ch == 77) || (ch == 80)) + { + newhighlight++; + if (newhighlight >= menunamecnt) + newhighlight = 0; + } + } + if ((ch == 13) && (menuname[newhighlight][16] == 1)) + { + if ((menuname[newhighlight][0] == '.') && (menuname[newhighlight][1] == '.')) + { + i = 0; + while ((i < 160) && (menupath[i] != 0)) i++; + while ((i > 0) && (menupath[i] != 92)) i--; + menupath[i] = 0; + } + else + { + strcat(&menupath,"\\"); + strcat(&menupath,menuname[newhighlight]); + } + chdir(menuname[newhighlight]); + menunamecnt = 0; + getfilenames("SUBD"); + getfilenames("*.BMP"); + getfilenames("*.PCX"); + getfilenames("*.GIF"); + sortfilenames(); + newhighlight = 0; + ch = 0; + cleartopbox(); + } + } + while ((ch != 13) && (ch != 27)); + if (ch == 13) + { + menuhighlight = newhighlight; + return(newhighlight); + } + cleartopbox(); + return(-1); +} + +// Grab this from sdl_driver.c if you can - DDOI +int printext256(long xpos, long ypos, short col, short backcol, char *name) +{ + char ch, damask; + short shift; + long p, startp, z, zz, zzz; + + outp(0x3c4,2); + startp = ((ypos*panxdim+xpos)>>2)+VIDEOBASE; + + z = 0; + while (name[z] != 0) + { + ch = name[z]; + z++; + + if ((xpos&3) == 0) + { + p = startp; + for(zz=0;zz<8;zz++) + { + if (backcol >= 0) + { + outp(0x3c5,15-reversemask[textfont[ch][zz]>>4]); + drawpixel(p,backcol); + outp(0x3c5,15-reversemask[textfont[ch][zz]&15]); + drawpixel(p+1,backcol); + } + if (backcol == -2) + { + damask = reversemask[textfont[ch][zz]>>4]; + for(zzz=0;zzz<4;zzz++) + { + if ((damask&(1< 0) + { + outp(0x3c5,1< 0) + { + outp(0x3c5,1<>4]); + drawpixel(p,col); + outp(0x3c5,reversemask[textfont[ch][zz]&15]); + drawpixel(p+1,col); + } + p += (panxdim>>2); + } + } + else + { + shift = (xpos&3); + + p = startp; + for(zz=0;zz<8;zz++) + { + if (backcol >= 0) + { + outp(0x3c5,(16-(1<>(shift+4))&reversemask[16-(1<>shift)&15]); + drawpixel(p+1,backcol); + outp(0x3c5,((1<>(shift+4))&reversemask[16-(1< 0) + { + outp(0x3c5,1<>shift)&15]; + for(zzz=0;zzz<4;zzz++) + { + if ((damask&(1< 0) + { + outp(0x3c5,1< 0) + { + outp(0x3c5,1<>(shift+4))&reversemask[16-(1<>shift)&15]); + drawpixel(p+1,col); + outp(0x3c5,reversemask[(textfont[ch][zz]<<(4-shift))&reversemask[(1<>2); + } + } + + startp += 2; + } + return(0); +} + +// Figure out if this is w.r.t screen or line compare - DDOI +void printmessage(char name[82]) +{ + cleartext(); + printext256(0L,8L,yellowcol,browncol,name); +} + +int screencapture(void) +{ + char filename[15], *ptr; + long fil, i, bufplc, p, col, ncol, leng, x, y, capturecount; + + menunamecnt = 0; + getfilenames("CAPT????.PCX"); + sortfilenames(); + + if (menunamecnt >= 256) + { + printmessage("MAXIMUM FILES is 256!"); + return(-1); + } + + capturecount = 0; + if (menunamecnt > 0) + { + capturecount = (menuname[menunamecnt-1][7]-48); + capturecount += (menuname[menunamecnt-1][6]-48)*10; + capturecount += (menuname[menunamecnt-1][5]-48)*100; + capturecount += (menuname[menunamecnt-1][4]-48)*1000; + capturecount++; + } + + strcpy(filename,"captxxxx.pcx"); + filename[4] = ((capturecount/1000)%10)+48; + filename[5] = ((capturecount/100)%10)+48; + filename[6] = ((capturecount/10)%10)+48; + filename[7] = (capturecount%10)+48; + if ((fil=open(filename,O_BINARY|O_CREAT|O_TRUNC|O_WRONLY,UC_PERMS))==-1) + return(-1); + + pcxheader[8] = ((xdim-1)&255); pcxheader[9] = (((xdim-1)>>8)&255); + pcxheader[10] = ((ydim-1)&255); pcxheader[11] = (((ydim-1)>>8)&255); + pcxheader[12] = (xdim&255); pcxheader[13] = ((xdim>>8)&255); + pcxheader[14] = (ydim&255); pcxheader[15] = ((ydim>>8)&255); + pcxheader[66] = (xdim&255); pcxheader[67] = ((xdim>>8)&255); + + write(fil,&pcxheader[0],128); + + bufplc = 0; + x = 0; y = 0; + while (y < ydim) + { + outp(97,inp(97)|3); + + col = buf[(y<<10)+x]; + x++; if (x == xdim) x = 0, y++; + ncol = buf[(y<<10)+x]; + + leng = 1; + + while ((ncol == col) && (x != 0) && (leng < 63)) + { + leng++; + + x++; if (x == xdim) x = 0, y++; + if (y > ydim) break; + ncol = buf[(y<<10)+x]; + } + + outp(97,inp(97)&252); + + if ((leng > 1) || (col >= 0xc0)) + { + tempbuf[bufplc++] = (leng|0xc0); + if (bufplc == 256) + { + bufplc = 0; + if (write(fil,&tempbuf[0],256) < 256) + { close(fil); capturecount--; return(-1); } + } + } + tempbuf[bufplc++] = col; + if (bufplc == 256) + { + bufplc = 0; + if (write(fil,&tempbuf[0],256) < 256) + { close(fil); capturecount--; return(-1); } + } + } + + tempbuf[bufplc++] = 0xc; + if (bufplc == 256) + { + bufplc = 0; + if (write(fil,&tempbuf[0],256) < 256) + { close(fil); capturecount--; return(-1); } + } + + outp(0x3c7,0); + for(i=0;i<768;i++) + { + tempbuf[bufplc++] = (inp(0x3c9)<<2); + if (bufplc == 256) + { + bufplc = 0; + if (write(fil,&tempbuf[0],256) < 256) + { close(fil); capturecount--; return(-1); } + } + } + if (bufplc > 0) + if (write(fil,&tempbuf[0],bufplc) < bufplc) + { close(fil); return(-1); } + close(fil); + return(0); +} + +int resizetile(long picnume, long oldx, long oldy, long newx, long newy) +{ + char *charptr1, *charptr2; + long *longptr1, *longptr2; + long i, j, dat, templong; + + templong = newx*newy-oldx*oldy; + + if (totpicsiz+templong > totpicmem) + return(-1); + + j = 0L; + for(i=localtilestart[curtilefile];i 0) + { + //Be careful with long pointers! The offset of 3 is because + //long pointers still point to the lowest of the 4 bytes + + longptr1 = (long *)(FP_OFF(pic)+totpicsiz-1 - 3); + longptr2 = (long *)(FP_OFF(pic)+totpicsiz-1+templong - 3); + i = j; + while (i < totpicsiz-3) + { + dat = *longptr1--; + *longptr2-- = dat; + i += 4; + } + charptr1 = (char *)(longptr1); + charptr2 = (char *)(longptr2); + charptr1 += 3; + charptr2 += 3; + while (i < totpicsiz) + { + dat = *charptr1--; + *charptr2-- = dat; + i++; + } + } + for(j=picnume+1;j<=localtileend[curtilefile];j++) + waloff[j] += templong; + totpicsiz += templong; + return(0); +} + +void gettextcolors(void) +{ + long i, j, whitedist, browndist, yellowdist, greendist, blackdist, dist; + long r, g, b, dr, dg, db; + + whitedist = 0x7fffffff; + browndist = 0x7fffffff; + yellowdist = 0x7fffffff; + greendist = 0x7fffffff; + blackdist = 0x7fffffff; + j = 0; + for(i=0;i<256;i++) + { + r = palette[j+0]; g = palette[j+1]; b = palette[j+2]; + + dr = r-48; dg = g-48; db = b-48; dist = dr*dr+dg*dg+db*db; + if (dist < whitedist) whitedist = dist, whitecol = i; + + dr = r-32; dg = g-16; db = b-12; dist = dr*dr+dg*dg+db*db; + if (dist < browndist) browndist = dist, browncol = i; + + dr = r-48; dg = g-48; db = b-50; dist = dr*dr+dg*dg+db*db; + if (dist < yellowdist) yellowdist = dist, yellowcol = i; + + dr = r-32; dg = g-63; db = b-32; dist = dr*dr+dg*dg+db*db; + if (dist < greendist) greendist = dist, greencol = i; + + dr = r-0; dg = g-0; db = b-0; dist = dr*dr+dg*dg+db*db; + if (dist < blackdist) blackdist = dist, blackcol = i; + + j += 3; + } +} + +char gettrans(char dat1, char dat2) +{ + char retcol; + long ravg, gavg, bavg; + long tripledat1, tripledat2, closest, zx, triplezx, dar, dag, dab, dist; + + tripledat1 = ((long)dat1<<1)+(long)dat1; + tripledat2 = ((long)dat2<<1)+(long)dat2; + + ravg = ((palette[tripledat1+0] + palette[tripledat2+0])>>1); + gavg = ((palette[tripledat1+1] + palette[tripledat2+1])>>1); + bavg = ((palette[tripledat1+2] + palette[tripledat2+2])>>1); + + retcol = 0; + closest = 0x7fffffff; + triplezx = 0; + for(zx=0;zx<256;zx++) + { + dar = (palette[triplezx+0]-ravg) * 30; + dag = (palette[triplezx+1]-gavg) * 59; + dab = (palette[triplezx+2]-bavg) * 11; + dist = dar*dar + dag*dag + dab*dab; + if (dist < closest) + { + closest = dist; + retcol = zx; + } + triplezx += 3; + } + + return(retcol); +} + +#ifdef PLATFORM_DOS +long convalloc32(long size) +{ + union REGS r; + + r.x.eax = 0x0100; //DPMI allocate DOS memory + r.x.ebx = ((size+15)>>4); //Number of paragraphs requested + int386(0x31,&r,&r); + + if (r.x.cflag != 0) //Failed + return ((long)0); + return ((long)((r.x.eax&0xffff)<<4)); //Returns full 32-bit offset +} +#else +long convalloc32(long size) +{ +#warning convalloc32() needs filling + fprintf (stderr, "Stub, convalloc32: %s line %d\n", __FILE__, __LINE__); +} +#endif + +int swapwalls(long swapwall1, long swapwall2) +{ + char tempchar, *charptr1, *charptr2, *bakcharptr1, *bakcharptr2; + long i, j, templong, numbytes1, numbytes2, numbytes3; + + outp(67,182); outp(66,16); outp(66,16); + + if (swapwall1 == swapwall2) + return(0); + + if (swapwall1 > swapwall2) + templong = swapwall1, swapwall1 = swapwall2, swapwall2 = templong; + + // charptr1 numbytes1 numbytes3 charptr2 numbytes2 + // ³ / ³ ³ / + // ÚÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄ¿ + // ³ TILE1 ³ -----walls between----- ³ TILE2 ³ + // ÀÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÙ + + //Swap memory + numbytes1 = tilesizx[swapwall1]*tilesizy[swapwall1]; + numbytes2 = tilesizx[swapwall2]*tilesizy[swapwall2]; + + charptr1 = (char *)FP_OFF(pic); + for(i=localtilestart[curtilefile];i= numbytes2) + { + outp(97,inp(97)|3); + bakcharptr1 = charptr1; + for(i=0;i>16) == 1) //2Draw map format + { + read(fil,&nummaps,2); + read(fil,&numsprites[0],MAXMAPS<<1); + + i = 4+2+(MAXMAPS<<1); //Global header + for(j=0;j>16) == 2) //Polytex map format + { + } + close(fil); + } + + } + while (_dos_findnext(&fileinfo) == 0); + } +#else +#warning Fix updatemaps() +#endif + printf("MAPS UPDATED.\n"); + printf("Don't forget to recompile - NAMES.H may have changed!\n"); + } + else + printf("MAPS NOT UPDATED.\n"); + } +} + +void updatepalette(void) +{ + unsigned char ch, *ptr; + long i, j, k, m, fil; + + for(i=0;i<768;i++) //Swap palette and palette2 + { + j = palette[i]; + palette[i] = palette2[i]; + palette2[i] = j; + } + getpaletteconversion(); + + getpalookup(); + if ((fil = open("palette.dat",O_BINARY|O_CREAT|O_WRONLY,UC_PERMS)) != -1) + { + write(fil,&palette[0],768); + write(fil,&palookup[0][0],NUMPALOOKUPS*256); + gettextcolors(); + close(fil); + } + + for(m=0;m 0) && (tilesizy[i] > 0)) + { + loadwall(buf,i); + k = tilesizx[i]*tilesizy[i]; + ptr = (char *)waloff[i]; + for(j=0;j>4)); + outp(0x3d4,0x9); outp(0x3d5,(inp(0x3d5)&191)|((lin&512)>>3)); + num = 0; + outp(0x3d4,0xc); outp(0x3d5,num>>10); + outp(0x3d4,0xd); outp(0x3d5,(num>>2)&255); + outp(0x3c0,inp(0x3c0)|0x13); outp(0x3c0,(num&3)<<1); + + if (xres > 1024) xres = 1024; + if (yres > 256) yres = 256; + if (xdim < 1) xdim = 1; + if (ydim < 1) ydim = 1; + + if (*dax1 == 0x80000000) + { + x1 = ((xres-xdim)>>1); x2 = x1+xdim; + y1 = ((yres-ydim)>>1); y2 = y1+ydim; + if (x1 < 0) x1 = 0; + if (y1 < 0) y1 = 0; + if (x2 > xres) x2 = xres; + if (y2 > yres) y2 = yres; + } + else + { + x1 = *dax1; + y1 = *day1; + x2 = *dax2; + y2 = *day2; + if ((x2 <= x1) && (y2 <= y1)) + if ((x1 > 4) && (y1 > 4) && (x1 < xres-4) && (y1 < xres-4)) + { + x1 -= 4; + y1 -= 4; + x2 = x1+8; + y2 = y1+8; + } + } + updatx = ((x1+x2)>>1); updaty = ((y1+y2)>>1); + + xorcol = (rand()&255); + + drawxorbox(x1,y1,x2-1,y2-1,xorcol); + ch = 0; + while ((ch != 13) && (ch != ' ') && (ch != 27) && (ch != 'o') && (ch != 'O')) + { + if (kbhit() == 0) + { + drawxorbox(x1,y1,x2-1,y2-1,xorcol); + limitrate(); + xorcol = (rand()&255); + drawxorbox(x1,y1,x2-1,y2-1,xorcol); + limitrate(); + } + else + { + ch = getch(); + + if ((ch == 'p') || (ch == 'P')) + { + drawxorbox(x1,y1,x2-1,y2-1,xorcol); + printext256(panxforu,panyforu,xorcol,-2,"Make this the new build palette?"); + do + { + printext256(panxforu,panyforu,xorcol,-2,"Make this the new build palette?"); + limitrate(); + xorcol = (rand()&255); + printext256(panxforu,panyforu,xorcol,-2,"Make this the new build palette?"); + limitrate(); + + if (kbhit() != 0) + ch = getch(); + } + while ((ch != 'y') && (ch != 'Y') && (ch != 'n') && (ch != 'N')); + printext256(panxforu,panyforu,xorcol,-2,"Make this the new build palette?"); + drawxorbox(x1,y1,x2-1,y2-1,xorcol); + + if ((ch == 'y') || (ch == 'Y')) + updatepalette(); + } + + if (ch == 0) + { + drawxorbox(x1,y1,x2-1,y2-1,xorcol); + + ch = getch(); + if (bstatus == 0) + { + if ((ch == 75) && (x1 > 0)) x1--, x2--; + if ((ch == 77) && (x2 < xres)) x1++, x2++; + if ((ch == 72) && (y1 > 0)) y1--, y2--; + if ((ch == 80) && (y2 < yres)) y1++, y2++; + updatx = x1; updaty = y1; + } + else + { + if ((ch == 75) && (x2 > x1+1)) x2--; + if ((ch == 77) && (x2 < xres)) x2++; + if ((ch == 72) && (y2 > y1+1)) y2--; + if ((ch == 80) && (y2 < yres)) y2++; + updatx = x2-1; updaty = y2-1; + } + + drawxorbox(x1,y1,x2-1,y2-1,xorcol); + } + } + if (moustat == 1) + { + readmouse(); + if ((mousx != 0) || (mousy != 0)) + { + drawxorbox(x1,y1,x2-1,y2-1,xorcol); + + if (bstatus == 0) + { + x1 += mousx; x2 += mousx; + if (x1 < 0) templong = -x1, x1 += templong, x2 += templong; + if (x2 > xres) templong = x2-xres, x1 -= templong, x2 -= templong; + y1 += mousy; y2 += mousy; + if (y1 < 0) templong = -y1, y1 += templong, y2 += templong; + if (y2 > yres) templong = y2-yres, y1 -= templong, y2 -= templong; + updatx = x1; updaty = y1; + } + else + { + x2 += mousx; + if (x2 < x1+1) x2 = x1+1; + if (x2 > xres) x2 = xres; + y2 += mousy; + if (y2 < y1+1) y2 = y1+1; + if (y2 > yres) y2 = yres; + updatx = x2-1; updaty = y2-1; + } + + drawxorbox(x1,y1,x2-1,y2-1,xorcol); + } + } + updatepanningforumode(updatx,updaty); + } + drawxorbox(x1,y1,x2-1,y2-1,xorcol); + + if ((ch == 13) || (ch == ' ') || (ch == 'o') || (ch == 'O')) + { + if (ch == ' ') + for(i=0;i<256;i++) + palookupe[i] = i; + + if ((ch == 'o') || (ch == 'O')) + { + *dax1 = ((x1+x2)>>1); + *day1 = ((y1+y2)>>1); + *dax2 = ((x1+x2)>>1); + *day2 = ((y1+y2)>>1); + } + else + { + *dax1 = x1; + *day1 = y1; + *dax2 = x2; + *day2 = y2; + } + return(1); + } + return(0); +} + +void updatescript(long picnumrangestart, long picnumrangeend) +{ + char buffer[160], dafilename[160]; + long i, j, k, datilenum, x1, y1, x2, y2; + + if (capfil == -1) + { + capfil = open("capfil.txt",O_BINARY|O_RDWR,S_IREAD); + if (capfil == -1) return; + } + + lseek(capfil,0L,SEEK_SET); + while (eof(capfil) == 0) // FIXME - DDOI + { + i = 0; + do + { + read(capfil,&buffer[i],1); + if ((i == 0) && ((buffer[i] == 10) || (buffer[i] == 13))) + i--; + i++; + } while (((buffer[i-1] != 10) && (buffer[i-1] != 13)) && (eof(capfil) == 0)); + buffer[i] = 0; + + j = 0; k = 0; + while ((buffer[k] != ',') && (k < i)) k++; + buffer[k] = 0; + sscanf(&buffer[j],"%ld",&datilenum); + + j = k+1; k = j; + while ((buffer[k] != ',') && (k < i)) k++; + buffer[k] = 0; + sscanf(&buffer[j],"%s",&dafilename[0]); + + j = k+1; k = j; + while ((buffer[k] != ',') && (k < i)) k++; + buffer[k] = 0; + sscanf(&buffer[j],"%ld",&x1); + + j = k+1; k = j; + while ((buffer[k] != ',') && (k < i)) k++; + buffer[k] = 0; + sscanf(&buffer[j],"%ld",&y1); + + j = k+1; k = j; + while ((buffer[k] != ',') && (k < i)) k++; + buffer[k] = 0; + sscanf(&buffer[j],"%ld",&x2); + + j = k+1; k = j; + while ((buffer[k] != ',') && (k < i)) k++; + buffer[k] = 0; + sscanf(&buffer[j],"%ld",&y2); + + x2 += x1; + y2 += y1; + + if ((datilenum >= picnumrangestart) && (datilenum <= picnumrangeend) && (i > 4)) + { + i = 0; + while ((i < 160) && (dafilename[i] != 0)) i++; + while ((i > 0) && (dafilename[i] != 92)) i--; + dafilename[i] = 0; + chdir(dafilename); + loadpicture(&dafilename[i+1]); + + loadpics(datilenum); + + outp(67,182); outp(66,16); outp(66,16); + outp(97,inp(97)|3); + captureit(x1,y1,x2,y2,datilenum,dafilename,0); + outp(97,inp(97)&252); + + asksave = 2, savewall(buf,datilenum); + } + } + chdir(curpath); +} + +int loadtileofscript(long tilenume, char *filespec, long *x1, long *y1, long *x2, long *y2) +{ + char buffer[160]; + long i, j, k, datilenum; + + if (capfil == -1) + { + capfil = open("capfil.txt",O_BINARY|O_RDWR,S_IREAD); + if (capfil == -1) return(0); + } + + lseek(capfil,0L,SEEK_SET); + while (eof(capfil) == 0) + { + i = 0; + do + { + read(capfil,&buffer[i],1); + if ((i == 0) && ((buffer[i] == 10) || (buffer[i] == 13))) + i--; + i++; + } while (((buffer[i-1] != 10) && (buffer[i-1] != 13)) && (eof(capfil) == 0)); + buffer[i] = 0; + + j = 0; k = 0; + while ((buffer[k] != ',') && (k < i)) k++; + buffer[k] = 0; + sscanf(&buffer[j],"%ld",&datilenum); + + if (datilenum == tilenume) + { + j = k+1; k = j; + while ((buffer[k] != ',') && (k < i)) k++; + buffer[k] = 0; + sscanf(&buffer[j],"%s",filespec); + + j = k+1; k = j; + while ((buffer[k] != ',') && (k < i)) k++; + buffer[k] = 0; + sscanf(&buffer[j],"%ld",x1); + + j = k+1; k = j; + while ((buffer[k] != ',') && (k < i)) k++; + buffer[k] = 0; + sscanf(&buffer[j],"%ld",y1); + + j = k+1; k = j; + while ((buffer[k] != ',') && (k < i)) k++; + buffer[k] = 0; + sscanf(&buffer[j],"%ld",x2); + + j = k+1; k = j; + while ((buffer[k] != ',') && (k < i)) k++; + buffer[k] = 0; + sscanf(&buffer[j],"%ld",y2); + + *x2 = (*x2) + (*x1); + *y2 = (*y2) + (*y1); + + chdir(curpath); + return(1); + } + } + chdir(curpath); + return(0); +} + +void captureit(long x1, long y1, long x2, long y2, long datilenum, char *dafilename, char capfilmode) +{ + char buffer[160]; + long i, j, k, vidpos, bad, dafileng, daothertilenum; + + if (capfilmode == 1) + { + if (capfil == -1) + capfil = open("capfil.txt",O_BINARY|O_RDWR,S_IREAD); + if (capfil != -1) + { + lseek(capfil,0L,SEEK_SET); + dafileng = read(capfil,&buf[0],524288); + if (dafileng < 0) dafileng = 0; + close(capfil); + + j = 0; + while (j < dafileng) + { + i = j; daothertilenum = 0; + while ((buf[i] >= 48) && (buf[i] <= 57) && (i < dafileng)) + daothertilenum = (daothertilenum*10)+(buf[i++]-48); + if (daothertilenum >= datilenum) break; + while (((buf[j] != 10) && (buf[j] != 13)) && (j < dafileng)) j++; + while (((buf[j] == 10) || (buf[j] == 13)) && (j < dafileng)) j++; + } + k = j; + while (k < dafileng) + { + i = k; daothertilenum = 0; + while ((buf[i] >= 48) && (buf[i] <= 57) && (i < dafileng)) + daothertilenum = (daothertilenum*10)+(buf[i++]-48); + if (daothertilenum > datilenum) break; + while (((buf[k] != 10) && (buf[k] != 13)) && (k < dafileng)) k++; + while (((buf[k] == 10) || (buf[k] == 13)) && (k < dafileng)) k++; + } + + capfil = open("capfil.txt",O_BINARY|O_CREAT|O_TRUNC|O_WRONLY,UC_PERMS); + + if (j > 0) write(capfil,&buf[0],j); + sprintf(buffer,"%ld,%s,%ld,%ld,%ld,%ld\r\n",datilenum,dafilename,x1,y1,x2-x1,y2-y1); + write(capfil,buffer,strlen(buffer)); + if (dafileng > k) write(capfil,&buf[k],dafileng-k); + + close(capfil); + capfil = -1; + } + else + { + capfil = open("capfil.txt",O_BINARY|O_CREAT|O_TRUNC|O_WRONLY,UC_PERMS); + + sprintf(buffer,"%ld,%s,%ld,%ld,%ld,%ld\r\n",datilenum,dafilename,x1,y1,x2-x1,y2-y1); + write(capfil,buffer,strlen(buffer)); + + close(capfil); + capfil = -1; + } + } + + if ((x2 <= x1) || (y2 <= y1)) + { + x2 = x1+1; y2 = y1+1; + + outp(0x3ce,4); + + do + { + bad = 0; + + if (x1 > 0) + { + for(j=0;j>2)+VIDEOBASE) != 255) + { + x1--, bad = 1; + break; + } + } + } + if (x2 < xres-1) + { + for(j=0;j>2)+VIDEOBASE) != 255) + { + x2++, bad = 1; + break; + } + } + } + if (y1 > 0) + { + for(i=0;i>2)+VIDEOBASE) != 255) + { + y1--, bad = 1; + break; + } + } + } + if (y2 < yres-1) + { + for(i=0;i>2)+VIDEOBASE) != 255) + { + y2++, bad = 1; + break; + } + } + } + } while (bad == 1); + + x2++; + y2++; + } + + xdim = x2-x1; c = (xdim>>1); + ydim = y2-y1; d = (ydim>>1); + + outp(0x3ce,4); + for(j=0;j>2)+VIDEOBASE)]; + vidpos++; + } + } + asksave = 1; +} + +void reportmaps(void) +{ + long i, j, k, fil, mapversion; + short mapnumsectors, mapnumwalls, mapnumsprites; +#ifdef PLATFORM_DOS + struct find_t fileinfo; +#else + DIR *dir; + struct dirent *dent; +#endif + + i = 0; + while (curpath[i] != 0) i++; + curpath[i] = 92; + curpath[i+1] = 0; + chdir(curpath); + curpath[i] = 0; + + for(i=MAXTILES-1;i>=0;i--) + tilookup2[i] = 0; +#ifdef PLATFORM_DOS + if (_dos_findfirst("*.MAP",_A_NORMAL,&fileinfo) == 0) + { + do + { + if ((fil = open(fileinfo.name,O_BINARY|O_RDWR,S_IREAD)) != -1) + { + read(fil,&mapversion,4); + if (mapversion == 0x00000007) //Build map format + { + lseek(fil,4 + 4+4+4+2+2,SEEK_SET); + read(fil,&mapnumsectors,2); + for(i=0;i>16) == 1) //2Draw map format + { + read(fil,&nummaps,2); + read(fil,&numsprites[0],MAXMAPS<<1); + + i = 4+2+(MAXMAPS<<1); //Global header + for(j=0;j>16) == 2) //Polytex map format + { + } + close(fil); + } + } while (_dos_findnext(&fileinfo) == 0); + } +#else + dir = opendir("."); + if (dir == NULL) return; + + do { + dent = readdir(dir); + if (dent != NULL) { + if (fnmatch("*.MAP", dent->d_name, FNM_CASEFOLD)) + { + // Where the real fun starts - DDOI + if ((fil = open(dent->d_name, O_RDWR, S_IREAD)) != -1) { + read(fil, &mapversion, 4); + if (mapversion == 0x00000007) // Build map format + { + lseek(fil,4+4+4+4+2+2, SEEK_SET); + read(fil, &mapnumsectors, 2); + for (i=0;i>16) == 1) //2Draw map format + { + read(fil,&nummaps,2); + read(fil,&numsprites[0],MAXMAPS<<1); + + i = 4+2+(MAXMAPS<<1); + //Global header + for(j=0;j>16) == 2) //Polytex map format + { + } // else if + close(fil); + } // if + } // if + } // if + } while (dent != NULL); + closedir(dir); +#endif +} diff --git a/buildengine/utils/grpextract.c b/buildengine/utils/grpextract.c new file mode 100755 index 0000000..1e2da08 --- /dev/null +++ b/buildengine/utils/grpextract.c @@ -0,0 +1,148 @@ +/******************************************************************************** + * BUILD group file extractor * + * Copyright (c) 2000 Christian Zander [phoenix@minion.de] * + * * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * * + ********************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PERMS S_IWUSR|S_IWGRP|S_IRUSR|S_IRGRP|S_IROTH +#define CREAT O_TRUNC|O_CREAT|O_WRONLY + +typedef struct _grp_file_entry { + char name[13]; + int extract; + long size; + long offset; +} grp_file_entry; + +int extract(int fdo, grp_file_entry *fp) { + char buf[65536]; + long i, k; + int fdd; + + if ((fdd = open(fp->name, CREAT, PERMS)) == -1) return -1; + + lseek(fdo, fp->offset, SEEK_SET); + + for (i = 0; i < fp->size; i += 65536) { + if ((fp->size - i) < 65536) k = fp->size - i; else k = 65536; + + read(fdo, buf, k); + if (write(fdd, buf, k) < k) return -1; + } + close(fdd); + + printf("Extracted %s\n", fp->name); + + return 0; +} + +int main(int argc, char **argv) { + grp_file_entry *fp; + long filecount, offset; + char buf[16]; + int fd, listonly, i, j; + + if (argc < 2) { + printf("usage: %s [grouped file] [file ...]\n", argv[0]); + printf(" \n" ); + printf(" %s stuff.dat \n", argv[0]); + printf(" %s stuff.dat *.map *.voc \n", argv[0]); + printf(" %s stuff.dat tiles000.art \n", argv[0]); + printf(" \n" ); + exit(0); + } + + if (argc == 2) listonly = 1; else listonly = 0; + + if ((fd = open(argv[1], O_RDONLY)) == -1) { + printf("Error: opening %s, %s\n", argv[1], strerror(errno)); + exit(1); + } + + read(fd, buf, 16); + + if (strncasecmp(buf, "KenSilverman", 12)) { + close(fd); + printf("Error: %s is not a valid group file\n", argv[1]); + exit(1); + } + + filecount = ((long)buf[12] & 0x000000ff) | + ((long)buf[13] << 8 & 0x0000ff00) | + ((long)buf[14] << 16 & 0x00ff0000) | + ((long)buf[15] << 24 & 0xff000000); + + offset = (filecount + 1) * 16; + + fp = malloc(sizeof(grp_file_entry) * filecount); + memset(fp, 0, sizeof(grp_file_entry) * filecount); + + for (i = 0; i < filecount; i++) { + read(fd, buf, 16); + + strncpy(fp[i].name, buf, 12); + + for (j = 0; j < 12; j++) + fp[i].name[j] = (char)tolower(fp[i].name[j]); + + for (j = argc - 1; j > 1; j--) { + if (fnmatch(argv[j], fp[i].name, FNM_NOESCAPE) == 0) + fp[i].extract = 1; + } + + fp[i].size = ((long)buf[12] & 0x000000ff) | + ((long)buf[13] << 8 & 0x0000ff00) | + ((long)buf[14] << 16 & 0x00ff0000) | + ((long)buf[15] << 24 & 0xff000000); + + fp[i].offset = offset; + offset += fp[i].size; + } + + if (listonly) { + + printf("Filename Size\n"); + printf("---------------------\n"); + + for (i = 0; i < filecount; i++) + printf("%-12s %8ld\n", fp[i].name, fp[i].size); + + free(fp); close(fd); + exit(0); + } + + for(i = 0; i < filecount; i++) { + if (fp[i].extract) { + if (extract(fd, &fp[i]) == -1) + printf("Error: extracting %s, %s\n", fp[i].name, strerror(errno)); + } + } + + free(fp); close(fd); + return 0; +} diff --git a/buildengine/utils/kextract.c b/buildengine/utils/kextract.c new file mode 100755 index 0000000..aef2536 --- /dev/null +++ b/buildengine/utils/kextract.c @@ -0,0 +1,189 @@ +// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman +// Ken Silverman's official web site: "http://www.advsys.net/ken" +// See the included license file "BUILDLIC.TXT" for license info. + +#include +#include +#include +#ifdef PLATFORM_DOS +#include +#include +#include +#include +#include +#include "dos_compat.h" +#else +#include +#include +#include +#include "unix_compat.h" +#endif + +#define MAXFILES 4096 + +static char buf[65536]; + +static long numfiles, anyfiles4extraction; +static char marked4extraction[MAXFILES]; +static char filelist[MAXFILES][16]; +static long fileoffs[MAXFILES+1], fileleng[MAXFILES]; + +// Function declarations +void findfiles(char *dafilespec); + +int main(int argc, char **argv) +{ + long i, j, k, l, fil, fil2; + char stuffile[16], filename[128]; + + if (argc < 3) + { + printf("KEXTRACT [grouped file][@file or filespec...] by Kenneth Silverman\n"); + printf(" This program extracts files from a previously grouped group file.\n"); + printf(" You can extract files using the ? and * wildcards.\n"); + printf(" Ex: kextract stuff.dat tiles000.art nukeland.map palette.dat\n"); + printf(" (stuff.dat is the group file, the rest are the files to extract)\n"); + exit(0); + } + + strcpy(stuffile,argv[1]); + + if ((fil = open(stuffile,O_BINARY|O_RDWR,S_IREAD)) == -1) + { + printf("Error: %s could not be opened\n",stuffile); + exit(0); + } + + read(fil,buf,16); + if ((buf[0] != 'K') || (buf[1] != 'e') || (buf[2] != 'n') || + (buf[3] != 'S') || (buf[4] != 'i') || (buf[5] != 'l') || + (buf[6] != 'v') || (buf[7] != 'e') || (buf[8] != 'r') || + (buf[9] != 'm') || (buf[10] != 'a') || (buf[11] != 'n')) + { + close(fil); + // I have NO idea what Ken was thinking with THIS! - DDOI + //printf("Error: %s not a valid group file\n",fil); + printf("Error: %s not a valid group file\n",stuffile); + exit(0); + } + numfiles = ((long)buf[12])+(((long)buf[13])<<8)+(((long)buf[14])<<16)+(((long)buf[15])<<24); + + read(fil,filelist,numfiles<<4); + + j = 0; + for(i=0;i1;i--) + { + strcpy(filename,argv[i]); + if (filename[0] == '@') + { + if ((fil2 = open(&filename[1],O_BINARY|O_RDWR,S_IREAD)) != -1) + { + l = read(fil2,buf,65536); + j = 0; + while ((j < l) && (buf[j] <= 32)) j++; + while (j < l) + { + k = j; + while ((k < l) && (buf[k] > 32)) k++; + + buf[k] = 0; + findfiles(&buf[j]); + j = k+1; + + while ((j < l) && (buf[j] <= 32)) j++; + } + close(fil2); + } + } + else + findfiles(filename); + } + + if (anyfiles4extraction == 0) + { + close(fil); + printf("No files found in group file with those names\n"); + exit(0); + } + + for(i=0;i=0;i--) + { + for(k=0;k<12;k++) buf2[k] = 32; + j = 0; + for(k=0;filelist[i][k];k++) + { + if (filelist[i][k] == '.') j = 8; + buf2[j++] = filelist[i][k]; + } + + bad = 0; + for(j=0;j<12;j++) + { + ch1 = buf1[j]; if ((ch1 >= 97) && (ch1 <= 123)) ch1 -= 32; + ch2 = buf2[j]; if ((ch2 >= 97) && (ch2 <= 123)) ch2 -= 32; + if (ch1 == '*') + { + if (j < 8) j = 8; else j = 12; + continue; + } + if ((ch1 != '?') && (ch1 != ch2)) { bad = 1; break; } + } + if (bad == 0) { marked4extraction[i] = 1; anyfiles4extraction = 1; } + } +} diff --git a/buildengine/utils/kgroup.c b/buildengine/utils/kgroup.c new file mode 100755 index 0000000..b728f73 --- /dev/null +++ b/buildengine/utils/kgroup.c @@ -0,0 +1,195 @@ +// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman +// Ken Silverman's official web site: "http://www.advsys.net/ken" +// See the included license file "BUILDLIC.TXT" for license info. + +#include +#include +#include +#ifdef PLATFORM_DOS +#include +#include +#include +#include +#include +#include "dos_compat.h" +#else +#include +#include +#include +#include +#include "unix_compat.h" +#include +#endif + +#define MAXFILES 4096 + +static char buf[65536]; + +static long numfiles; +static char filespec[MAXFILES][128], filelist[MAXFILES][16]; +static long fileleng[MAXFILES]; + +// Function declarations +void findfiles(char *dafilespec); + +int main(int argc, char **argv) +{ + long i, j, k, l, fil, fil2; + char stuffile[16], filename[128]; + + if (argc < 3) + { + printf("KGROUP [grouped file][@file or filespec...] by Kenneth Silverman\n"); + printf(" This program collects many files into 1 big uncompressed file called a\n"); + printf(" group file\n"); + printf(" Ex: kgroup stuff.dat *.art *.map *.k?? palette.dat tables.dat\n"); + printf(" (stuff.dat is the group file, the rest are the files to add)\n"); + exit(0); + } + + numfiles = 0; + for(i=argc-1;i>1;i--) + { + strcpy(filename,argv[i]); + if (filename[0] == '@') + { + if ((fil = open(&filename[1],O_BINARY|O_RDONLY,S_IREAD)) != -1) + { + l = read(fil,buf,65536); + j = 0; + while ((j < l) && (buf[j] <= 32)) j++; + while (j < l) + { + k = j; + while ((k < l) && (buf[k] > 32)) k++; + + buf[k] = 0; + findfiles(&buf[j]); + j = k+1; + + while ((j < l) && (buf[j] <= 32)) j++; + } + close(fil); + } + } + else + findfiles(filename); + } + + strcpy(stuffile,argv[1]); + + if ((fil = open(stuffile,O_BINARY|O_TRUNC|O_CREAT|O_WRONLY,UC_PERMS)) == -1) + { + printf("Error: %s could not be opened\n",stuffile); + exit(0); + } + strcpy(filename,"KenSilverman"); + write(fil,filename,12); + write(fil,&numfiles,4); + write(fil,filelist,numfiles<<4); + + for(i=0;i 0)) daspeclen--; + if (daspeclen > 0) daspec[daspeclen++] = '\\'; + + if (_dos_findfirst(dafilespec,_A_NORMAL,&fileinfo) != 0) return; + do + { + strcpy(&filelist[numfiles][0],fileinfo.name); + fileleng[numfiles] = fileinfo.size; + filelist[numfiles][12] = (char)(fileleng[numfiles]&255); + filelist[numfiles][13] = (char)((fileleng[numfiles]>>8)&255); + filelist[numfiles][14] = (char)((fileleng[numfiles]>>16)&255); + filelist[numfiles][15] = (char)((fileleng[numfiles]>>24)&255); + + strcpy(&filespec[numfiles][0],daspec); + strcpy(&filespec[numfiles][daspeclen],fileinfo.name); + + numfiles++; + if (numfiles > MAXFILES) + { + printf("FATAL ERROR: TOO MANY FILES SELECTED! (MAX is 4096)\n"); + exit(0); + } + } while (_dos_findnext(&fileinfo) == 0); +#else + DIR *dir; + struct dirent *dent; + struct stat statbuf; + + long daspeclen; + char daspec[128]; + + strcpy(daspec,dafilespec); + for(daspeclen=0;daspec[daspeclen]!=0;daspeclen++); + while ((daspec[daspeclen] != '/') && (daspeclen > 0)) daspeclen--; + if (daspeclen > 0) daspec[daspeclen++] = '/'; + + dir = opendir("."); + if (dir == NULL) return; + + do + { + dent = readdir(dir); + if (dent != NULL) + { + if (fnmatch(dafilespec, dent->d_name, FNM_CASEFOLD) + == 0 && stat(dent->d_name, &statbuf) == 0) { + strcpy(&filelist[numfiles][0], dent->d_name); + fileleng[numfiles] = statbuf.st_size; + filelist[numfiles][12] = (char)((fileleng[numfiles])&255); + filelist[numfiles][13] = (char)((fileleng[numfiles]>>8)&255); + filelist[numfiles][14] = (char)((fileleng[numfiles]>>16)&255); + filelist[numfiles][15] = (char)((fileleng[numfiles]>>24)&255); + + strcpy(&filespec[numfiles][0],daspec); + strcpy(&filespec[numfiles][daspeclen], dent->d_name); + numfiles++; + if (numfiles > MAXFILES) + { + printf("FATAL ERROR: TOO MANY FILES SELECTED! (MAX is 4096)\n"); + exit(0); + } + } + } + } while (dent != NULL); + closedir(dir); +#endif +} diff --git a/buildengine/utils/pragmas.c b/buildengine/utils/pragmas.c new file mode 100755 index 0000000..531d556 --- /dev/null +++ b/buildengine/utils/pragmas.c @@ -0,0 +1,88 @@ +/* + * Inline assembly. + * + * Initial PLATFORM_UNIX work done by Andrew Henderson. The DOS stuff is + * Ken's original code, and was in pragmas.h + * + * Please do NOT harrass Ken Silverman about any code modifications + * (including this file) to BUILD. + */ + +// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman +// Ken Silverman's official web site: "http://www.advsys.net/ken" +// See the included license file "BUILDLIC.TXT" for license info. +// This file has been modified from Ken Silverman's original release + +#ifdef PLATFORM_DOS + +#error Do not compile with pragmas.c on DOS! + +#endif + +#ifdef USE_I386_ASM + +int scale (int i1, int i2, int i3) { + int retval; + __asm__ __volatile__ (" + imull %%edx + idivl %%ecx + " : "=a" (retval) : "a" (i1), "d" (i2), "c" (i3) : "cc"); + return(retval); +} + +int mulscale (int i1, int i2, short i3) { + int retval; + __asm__ __volatile__ (" + imull %%edx + shrdl %%cl, %%edx, %%eax + " : "=a" (retval) : "a" (i1), "d" (i2), "c" (i3) : "cc"); + return(retval); +} + +int boundmulscale(int i1, int i2, int i3) { + int retval = 0; + __asm__ __volatile__ (" + imull %%ebx + movl %%edx, %%ebx + shrdl %%cl, %%edx, %%eax + sarl %%cl, %%edx + xorl %%eax, %%edx + js checkit + xorl %%eax, %%edx + jz skipboundit + cmpl $0xffffffff, %%edx + je skipboundit + checkit: + movl %%ebx, %%eax + sarl $31, %%eax + xorl $0x7fffffff, %%eax + skipboundit: + " : "=a" (retval) : "a" (i1), "b" (i2), "c" (i3) : "edx", "cc"); + return(retval); +} + +int divscale(int i1, int i2, int i3) { + int retval = 0; + __asm__ __volatile__ (" + movl %%eax, %%edx + shll %%cl, %%eax + negb %%cl + sarl %%cl, %%edx + idivl %%ebx + " : "=a" (retval) : "a" (i1), "b" (i2), "c" (i3) : "edx", "cc"); + return(retval); +} + +void clearbuf(void *buffer, int size, long fill_value) { + __asm__ __volatile__ (" + rep + stosl + " : : "D" (buffer), "c" (size), "a" (fill_value) : "cc"); +} + +#else + +#error Sorry, there are no C equivilents for the ASM functions yet + +#endif + diff --git a/buildengine/utils/pragmas.h b/buildengine/utils/pragmas.h new file mode 100755 index 0000000..b3defd3 --- /dev/null +++ b/buildengine/utils/pragmas.h @@ -0,0 +1,35 @@ +/* + * Inline assembly. + * + * Initial PLATFORM_UNIX work done by Andrew Henderson. The DOS stuff is + * Ken's original code, and was in pragmas.h + * + * Please do NOT harrass Ken Silverman about any code modifications + * (including this file) to BUILD. + */ + +// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman +// Ken Silverman's official web site: "http://www.advsys.net/ken" +// See the included license file "BUILDLIC.TXT" for license info. +// This file has been modified from Ken Silverman's original release + +#ifdef PLATFORM_DOS + +#warning I think you included the wrong pragmas.h file! + +#endif + +#ifdef USE_I386_ASM + +int scale (int i1, int i2, int i3); +int mulscale (int i1, int i2, short i3); +int boundmulscale(int i1, int i2, int i3); +int divscale(int i1, int i2, int i3); +void clearbuf(void *buffer, int size, long fill_value); + +#else + +#error Sorry, there are no C equivilents for the ASM functions yet + +#endif + diff --git a/buildengine/utils/sdl_driver.c b/buildengine/utils/sdl_driver.c new file mode 100755 index 0000000..5c3e554 --- /dev/null +++ b/buildengine/utils/sdl_driver.c @@ -0,0 +1,453 @@ +// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman +// Ken Silverman's official web site: "http://www.advsys.net/ken" +// See the included license file "BUILDLIC.TXT" for license info. + +#include +#include +#include + +#include "SDL.h" +#include "unix_compat.h" + +#define BUILD_NOMOUSEGRAB "BUILD_NO_MOUSE_GRAB" +#define BUILD_WINDOWED "BUILD_WINDOWED" + +long xres, yres, bytesperline, frameplace, imageSize, maxpages; +char *screen, vesachecked; +long buffermode, origbuffermode, linearmode; +char permanentupdate = 0, vgacompatible; + +SDL_Surface *surface = NULL; +static Uint32 sdl_flags = 0; +static long mouse_x = 0; +static long mouse_y = 0; +static long mouse_relative_x = 0; +static long mouse_relative_y = 0; +static short mouse_buttons = 0; +static int mouse_grabbed = 0; +static unsigned int lastkey = 0; +static SDL_TimerID primary_timer = NULL; + +static unsigned int scancodes[SDLK_LAST]; + +static long last_render_ticks = 0; +long total_render_time = 1; +long total_rendered_frames = 0; + +static int sdl_mouse_button_filter(SDL_Event const *event) +{ + /* + * What BUILD expects: + * 0 left button pressed if 1 + * 1 right button pressed if 1 + * 2 middle button pressed if 1 + * + * (That is, this is what Int 33h (AX=0x05) returns...) + */ + + Uint8 bmask = SDL_GetMouseState(NULL, NULL); + mouse_buttons = 0; + if (bmask & SDL_BUTTON_LMASK) mouse_buttons |= 1; + if (bmask & SDL_BUTTON_RMASK) mouse_buttons |= 2; + if (bmask & SDL_BUTTON_MMASK) mouse_buttons |= 4; + return(0); +} // sdl_mouse_up_filter + + +static int sdl_mouse_motion_filter(SDL_Event const *event) +{ + if (surface == NULL) + return(0); + + if (event->type == SDL_JOYBALLMOTION) + { + mouse_relative_x = event->jball.xrel/100; + mouse_relative_y = event->jball.yrel/100; + mouse_x += mouse_relative_x; + mouse_y += mouse_relative_y; + } // if + else + { + if (mouse_grabbed) + { + mouse_relative_x = event->motion.xrel; + mouse_relative_y = event->motion.yrel; + mouse_x += mouse_relative_x; + mouse_y += mouse_relative_y; + } // if + else + { + mouse_relative_x = event->motion.x - mouse_x; + mouse_relative_y = event->motion.y - mouse_y; + mouse_x = event->motion.x; + mouse_y = event->motion.y; + } // else + } // else + + if (mouse_x < 0) mouse_x = 0; + if (mouse_x > surface->w) mouse_x = surface->w; + if (mouse_y < 0) mouse_y = 0; + if (mouse_y > surface->h) mouse_y = surface->h; + + return(0); +} // sdl_mouse_motion_filter + + +static int sdl_key_filter(const SDL_Event *event) +{ + SDL_GrabMode grab_mode = SDL_GRAB_OFF; + int extended; + + if ( (event->key.keysym.sym == SDLK_g) && + (event->key.state == SDL_PRESSED) && + (event->key.keysym.mod & KMOD_CTRL) ) + { + mouse_grabbed = ((mouse_grabbed) ? 0 : 1); + if (mouse_grabbed) + grab_mode = SDL_GRAB_ON; + SDL_WM_GrabInput(grab_mode); + return(0); + } // if + + else if ( ( (event->key.keysym.sym == SDLK_RETURN) || + (event->key.keysym.sym == SDLK_KP_ENTER) ) && + (event->key.state == SDL_PRESSED) && + (event->key.keysym.mod & KMOD_ALT) ) + { + sdl_flags ^= SDL_FULLSCREEN; + SDL_WM_ToggleFullScreen(surface); + return(0); + } // if + + lastkey = scancodes[event->key.keysym.sym]; + if (lastkey == 0x0000) // No DOS equivalent defined. + return(0); + + extended = ((lastkey & 0xFF00) >> 8); + if (extended != 0) + { + lastkey = extended; + keyhandler(); + lastkey = (scancodes[event->key.keysym.sym] & 0xFF); + } // if + + if (event->key.state == SDL_RELEASED) + lastkey += 128; // +128 signifies that the key is released in DOS. + + keyhandler(); + return(0); +} // sdl_key_filter + + +unsigned char _readlastkeyhit(void) +{ + return(lastkey); +} // _readlastkeyhit + + +static int root_sdl_event_filter(const SDL_Event *event) +{ + switch (event->type) + { + case SDL_KEYUP: + case SDL_KEYDOWN: + return(sdl_key_filter(event)); + case SDL_JOYBALLMOTION: + case SDL_MOUSEMOTION: + return(sdl_mouse_motion_filter(event)); + case SDL_MOUSEBUTTONUP: + case SDL_MOUSEBUTTONDOWN: + return(sdl_mouse_button_filter(event)); + case SDL_QUIT: + exit(0); // !!! rcg TEMP + } // switch + + return(1); +} // root_sdl_event_filter + +void _platform_init(int argc, char **argv) +{ + if (getenv(BUILD_NOMOUSEGRAB) == NULL) + mouse_grabbed = 1; + else + mouse_grabbed = 0; + + sdl_flags = SDL_HWSURFACE | SDL_FULLSCREEN; + if (getenv(BUILD_WINDOWED) != NULL) + sdl_flags &= ~SDL_FULLSCREEN; + + memset(scancodes, '\0', sizeof (scancodes)); + scancodes[SDLK_ESCAPE] = 0x01; + scancodes[SDLK_1] = 0x02; + scancodes[SDLK_2] = 0x03; + scancodes[SDLK_3] = 0x04; + scancodes[SDLK_4] = 0x05; + scancodes[SDLK_5] = 0x06; + scancodes[SDLK_6] = 0x07; + scancodes[SDLK_7] = 0x08; + scancodes[SDLK_8] = 0x09; + scancodes[SDLK_9] = 0x0A; + scancodes[SDLK_0] = 0x0B; + scancodes[SDLK_EQUALS] = 0x4E; + scancodes[SDLK_BACKSPACE] = 0x0E; + scancodes[SDLK_TAB] = 0x0F; + scancodes[SDLK_q] = 0x10; + scancodes[SDLK_w] = 0x11; + scancodes[SDLK_e] = 0x12; + scancodes[SDLK_r] = 0x13; + scancodes[SDLK_t] = 0x14; + scancodes[SDLK_y] = 0x15; + scancodes[SDLK_u] = 0x16; + scancodes[SDLK_i] = 0x17; + scancodes[SDLK_o] = 0x18; + scancodes[SDLK_p] = 0x19; + scancodes[SDLK_LEFTBRACKET] = 0x1A; + scancodes[SDLK_RIGHTBRACKET] = 0x1B; + scancodes[SDLK_RETURN] = 0x1C; + scancodes[SDLK_LCTRL] = 0x1D; + scancodes[SDLK_a] = 0x1E; + scancodes[SDLK_s] = 0x1F; + scancodes[SDLK_d] = 0x20; + scancodes[SDLK_f] = 0x21; + scancodes[SDLK_g] = 0x22; + scancodes[SDLK_h] = 0x23; + scancodes[SDLK_j] = 0x24; + scancodes[SDLK_k] = 0x25; + scancodes[SDLK_l] = 0x26; + scancodes[SDLK_SEMICOLON] = 0x27; + scancodes[SDLK_QUOTE] = 0x28; + scancodes[SDLK_BACKQUOTE] = 0x29; + scancodes[SDLK_LSHIFT] = 0x2A; + scancodes[SDLK_BACKSLASH] = 0x2B; + scancodes[SDLK_z] = 0x2C; + scancodes[SDLK_x] = 0x2D; + scancodes[SDLK_c] = 0x2E; + scancodes[SDLK_v] = 0x2F; + scancodes[SDLK_b] = 0x30; + scancodes[SDLK_n] = 0x31; + scancodes[SDLK_m] = 0x32; + scancodes[SDLK_COMMA] = 0x33; + scancodes[SDLK_PERIOD] = 0x34; + scancodes[SDLK_SLASH] = 0x35; + scancodes[SDLK_RSHIFT] = 0x36; + scancodes[SDLK_KP_DIVIDE] = 0xE035; + scancodes[SDLK_KP_MULTIPLY] = 0x37; + scancodes[SDLK_LALT] = 0x38; + scancodes[SDLK_RALT] = 0xB8; + scancodes[SDLK_RCTRL] = 0x9D; + scancodes[SDLK_SPACE] = 0x39; + scancodes[SDLK_CAPSLOCK] = 0x3A; + scancodes[SDLK_F1] = 0x3B; + scancodes[SDLK_F2] = 0x3C; + scancodes[SDLK_F3] = 0x3D; + scancodes[SDLK_F4] = 0x3E; + scancodes[SDLK_F5] = 0x3F; + scancodes[SDLK_F6] = 0x40; + scancodes[SDLK_F7] = 0x41; + scancodes[SDLK_F8] = 0x42; + scancodes[SDLK_F9] = 0x43; + scancodes[SDLK_F10] = 0x44; + scancodes[SDLK_F11] = 0x57; + scancodes[SDLK_F12] = 0x58; + scancodes[SDLK_NUMLOCK] = 0x45; + scancodes[SDLK_SCROLLOCK] = 0x46; + scancodes[SDLK_MINUS] = 0x4A; + scancodes[SDLK_KP7] = 0x47; + scancodes[SDLK_KP8] = 0x48; + scancodes[SDLK_KP9] = 0x49; + scancodes[SDLK_HOME] = 0xE047; + scancodes[SDLK_UP] = 0xE048; + scancodes[SDLK_PAGEUP] = 0xE0C9; + scancodes[SDLK_KP_MINUS] = 0xE04A; + scancodes[SDLK_KP4] = 0x4B; + scancodes[SDLK_KP5] = 0x4C; + scancodes[SDLK_KP6] = 0x4D; + scancodes[SDLK_LEFT] = 0xE04B; + scancodes[SDLK_RIGHT] = 0xE04D; + scancodes[SDLK_KP_PLUS] = 0xE04E; + scancodes[SDLK_KP1] = 0x4F; + scancodes[SDLK_KP2] = 0x50; + scancodes[SDLK_KP3] = 0x51; + scancodes[SDLK_END] = 0xE04F; + scancodes[SDLK_DOWN] = 0xE050; + scancodes[SDLK_PAGEDOWN] = 0xE0D1; + scancodes[SDLK_DELETE] = 0xD3; + scancodes[SDLK_KP0] = 0xE052; + scancodes[SDLK_INSERT] = 0xE052; + scancodes[SDLK_KP_ENTER] = 0xE01C; + + if (SDL_Init(SDL_INIT_VIDEO | + SDL_INIT_TIMER | + SDL_INIT_AUDIO | + SDL_INIT_EVENTTHREAD) == -1) + { + fprintf(stderr, "SDL_Init() failed!\n"); + fprintf(stderr, "SDL_GetError() says \"%s\".\n", SDL_GetError()); + } // if +} // _platform_init + +int screencapture(char *filename, char inverseit) +{ + fprintf(stderr, "screencapture() is a stub in the SDL driver.\n"); + return(0); +} // screencapture + +void go_to_new_vid_mode(int vidoption, int w, int h) +{ + SDL_ClearError(); + surface = SDL_SetVideoMode(w, h, 8, sdl_flags); + if (surface == NULL) + { + fprintf(stderr, "Failed to set %dx%d video mode!\n" + " SDL_Error() says [%s].\n", w, h, SDL_GetError()); + SDL_Quit(); + exit(13); + } // if +} // go_to_new_vid_mode + +void setvmode(int mode) +{ + if (mode == 0x3) // text mode. + { + SDL_QuitSubSystem(SDL_INIT_VIDEO); + return; + } + + if (mode == 0x13) + { + go_to_new_vid_mode(-1, 320, 200); + } + + else + { + fprintf(stderr, "setvmode(0x%x) is unsupported in SDL driver.\n", mode); + exit(13); + } +} + +int setupmouse(void) +{ + SDL_GrabMode mode = SDL_GRAB_OFF; + + if (surface == NULL) + return(0); + + if (mouse_grabbed) + mode = SDL_GRAB_ON; + + SDL_WM_GrabInput(mode); + SDL_ShowCursor(0); + + mouse_x = surface->w / 2; + mouse_y = surface->h / 2; + mouse_relative_x = mouse_relative_y = 0; + + return(1); +} // setupmouse + +void readmousexy(short *x, short *y) +{ + if (x) *x = mouse_relative_x << 2; + if (y) *y = mouse_relative_y << 2; + + mouse_relative_x = mouse_relative_y = 0; +} // readmousexy + +void readmousebstatus(short *bstatus) +{ + if (bstatus) + *bstatus = mouse_buttons; +} // readmousebstatus + +void cleartopbox (void) +{ + fprintf (stderr, "FILLME: cleartopbox\n"); +} + +void drawchainpixel (long edi, long ebx) +{ + fprintf (stderr, "FILLME: drawchainpixel\n"); +} + +void cleartext (void) +{ + fprintf (stderr, "FILLME: cleartext\n"); +} + +int gifgetdat (long eax, long ebx, long ecx) +{ + fprintf (stderr, "FILLME: gifgetdat\n"); + return 0; +} + +unsigned char getpixel(long offset) +{ + return( *((unsigned char *) offset) ); +} + +void drawpixel(long offset, Uint8 pixel) +{ + *((Uint8 *) offset) = pixel; +} + +void drawpixels(long offset, Uint16 pixel) +{ + *((Uint16 *) offset) = pixel; +} + +void drawpixelses(long offset, Uint32 pixel) +{ + *((Uint32 *) offset) = pixel; +} + +void clear2dscreen(void) +{ + SDL_Rect rect; + + rect.x = rect.y = 0; + rect.w = surface->w; + rect.h = surface->h; + + SDL_FillRect(surface, &rect, 0); +} // clear2dscreen + +void limitrate(void) +{ + // this is a no-op in SDL. It was for buggy VGA cards in DOS. +} // limitrate + +Uint32 _timer_catcher(Uint32 interval, void *bleh) +{ + timerhandler(); + return(1); +} // _timer_catcher + +void inittimer(void) +{ + primary_timer = SDL_AddTimer(1000 / 120, _timer_catcher, NULL); + if (primary_timer == NULL) + { + SDL_Quit(); + fprintf(stderr, "Error initializing primary timer!\n"); + exit(2); + } // if +} + +void uninittimer(void) +{ + if (primary_timer != NULL) + { + SDL_RemoveTimer(primary_timer); + primary_timer = NULL; + } // if +} + +void _initkeys(void) +{ + // does nothing in SDL. Key input handling is set up elsewhere. +} + +void uninitkeys(void) +{ + // does nothing in SDL. Key input handling is set up elsewhere. +} diff --git a/buildengine/utils/sdl_driver.h b/buildengine/utils/sdl_driver.h new file mode 100755 index 0000000..f77ee2e --- /dev/null +++ b/buildengine/utils/sdl_driver.h @@ -0,0 +1,33 @@ +// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman +// Ken Silverman's official web site: "http://www.advsys.net/ken" +// See the included license file "BUILDLIC.TXT" for license info. + +#ifndef _SDL_DRIVER_H +#define _SDL_DRIVER_H + +#include "SDL.h" + +// Defines +#define kinp(x) _kinp_handler((x), __FILE__, __LINE__) +#define inp(x) _inp_handler((x), __FILE__, __LINE__) + +// Variables +SDL_Surface *surface; + +// Function Declarations +void setvmode(int mode); +void drawpixel(long offset, Uint8 pixel); +void limitrate(void); +void setactivepage(long dapagenum); + +int setupmouse(void); +void readmousexy(short *x, short *y); +void readmousebstatus(short *bstatus); +void keyhandler(void); +unsigned char _readlastkeyhit(void); + +static void timerhandler(void); +int _inp_handler(int port, char *source_file, int source_line); +int _kinp_handler(int port, char *source_file, int source_line); + +#endif diff --git a/buildengine/utils/setup.c b/buildengine/utils/setup.c new file mode 100755 index 0000000..655cd03 --- /dev/null +++ b/buildengine/utils/setup.c @@ -0,0 +1,722 @@ +// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman +// Ken Silverman's official web site: "http://www.advsys.net/ken" +// See the included license file "BUILDLIC.TXT" for license info. + +#include +#include +#include +#include +#include +#include +#include + +#define NUMOPTIONS 8 +#define NUMKEYS 19 + +#define NUMENUS 14 +static int menuoffs[NUMENUS], menuleng[NUMENUS] = {8,9,4,11,13,15,8,7,2,3,14,6,14,19}; +#define MAINMENU 0 +#define GRAPHMENU 1 +#define CHAINXDIMMENU 2 +#define CHAINYDIMMENU 3 +#define VESA2MENU 4 +#define DIGIMENU 5 +#define DIGIOPTIONMENU 6 +#define DIGIHZMENU 7 +#define MUSICMENU 8 +#define INPUTMENU 9 +#define COMMENU 10 +#define COMSPEEDMENU 11 +#define COMIRQMENU 12 +#define KEYMENU 13 + +static unsigned char screeninfo[4000]; +static unsigned char *strtable[135] = +{ + "Graphics Mode", + "Digitized Sound", + "Music", + "Input Devices", + "Communications", + "Ä", + "Ignore Changes and Quit", + "Save Changes and Quit", + + "Chain mode (Mode X) ³ VGA compatible ³ 256*200 to 400*540", + "VESA mode ³ VESA 1.2 / 2.0 ³ 320*200 to 1600*1200", + "Screen-Buffer mode ³ VGA compatible ³ 320*200 only", + "Ä", + "Specially-optimized TSENG ET4000 mode 320*200 only", + "Specially-optimized Paradise WD90Cxx mode 320*200 only", + "Specially-optimized S3 chipset mode 320*200 only", + "Ä", + "Red-Blue Stereo vision (VGA compatible) 320*200 only", + + "256 * X", + "320 * X", + "360 * X", + "400 * X", + + "X * 200", + "X * 240", + "X * 256", + "X * 270", + "X * 300", + "X * 350", + "X * 360", + "X * 400", + "X * 480", + "X * 512", + "X * 540", + + " 320 * 200", + " 360 * 200", + " 320 * 240", + " 360 * 240", + " 320 * 400", + " 360 * 400", + " 640 * 350", + " 640 * 400", + " 640 * 480", + " 800 * 600", + "1024 * 768", + "1280 * 1024", + "1600 * 1200", + + "No digitized sound", + "Ä", + "Sound Blaster", + "Pro Audio Spectrum", + "Sound Man 16", + "Adlib", + "General Midi", + "Sound Canvas", + "Sound Blaster AWE32", + "Wave Blaster", + "Sound Scape", + "Gravis Ultrasound", + "Sound Source", + "Tandy Sound source", + "PC speaker", + + " Mono, 8, lo", + " Mono, 8, HI", + " Mono, 16, lo", + " Mono, 16, HI", + "Stereo, 8, lo", + "Stereo, 8, HI", + "Stereo, 16, lo", + "Stereo, 16, HI", + + " 6000hz ", + " 8000hz ", + " 11025hz ", + " 16000hz ", + " 22050hz ", + " 32000hz ", + " 44100hz ", + + "Music OFF", + "Music ON", + + "Keyboard only", + "Keyboard & Mouse", + "Keyboard & Spaceplayer", + + "None", + "Ä", + "COM1", + "COM2", + "COM3", + "COM4", + "Ä", + "IPX network - 2 Players", + "IPX network - 3 Players", + "IPX network - 4 Players", + "IPX network - 5 Players", + "IPX network - 6 Players", + "IPX network - 7 Players", + "IPX network - 8 Players", + + "2400 bps", + "4800 bps", + "9600 bps", + "14400 bps", + "19200 bps", + "28800 bps", + + "IRQ2", + "IRQ3", + "IRQ4", + "IRQ5", + "IRQ6", + "IRQ7", + "IRQ8", + "IRQ9", + "IRQ10", + "IRQ11", + "IRQ12", + "IRQ13", + "IRQ14", + "IRQ15", + + "Move FORWARD ", + "Move BACKWARD ", + "Turn LEFT ", + "Turn RIGHT ", + "RUN ", + "STRAFE (walk sideways) ", + "SHOOT! ", + "OPEN / CLOSE / USE ", + "Stand HIGH ", + "Stand LOW ", + "Look Up ", + "Look Down ", + "Strafe Left ", + "Strafe Right ", + "2D/3D flip ", + "Player view flip ", + "2D Zoom in ", + "2D Zoom out ", + "Message typing ", +}; + +static unsigned char *keytable[] = +{ + "-","ESC","1","2","3","4","5","6","7","8","9","0","-","=","BACKSPC","TAB", + "Q","W","E","R","T","Y","U","I","O","P","[","]","ENTER","L-CTRL","A","S", + "D","F","G","H","J","K","L",";","'","`","L-SHIFT","|","Z","X","C","V", + "B","N","M",",",".","/","R-SHIFT","KP *","L-ALT","SPACEBAR","CAPSLOCK","F1","F2","F3","F4","F5", + "F6","F7","F8","F9","F10","NUMLOCK","SCROLL","KP 7","KP 8","KP 9","KP -","KP 4","KP 5","KP 6","KP +","KP 1", + "KP 2","KP 3","KP 0","KP .","-","-","-","F11","F12","-","-","-","-","-","-","-", + "-","-","-","-","-","-","-","-","-","-","-","-","-","-","-","-", + "-","-","-","-","-","-","-","-","-","-","-","-","-","-","-","-", + "-","-","-","-","-","-","-","-","-","-","-","-","-","-","-","-", + "-","-","-","-","-","-","-","-","-","-","-","-","KP ENTER","R-CTRL","-","-", + "-","-","-","-","-","-","-","-","-","-","-","-","-","-","-","-", + "-","-","-","-","-","KP /","-","-","R-ALT","-","-","-","-","-","-","-", + "-","-","-","-","-","-","-","HOME","UP","PAGEUP","-","LEFT","-","RIGHT","-","END", + "DOWN","PAGEDOWN","INSERT","DELETE","-","-","-","-","-","-","-","-","-","-","-","-", + "-","-","-","-","-","-","-","-","-","-","-","-","-","-","-","-", + "-","-","-","-","-","-","-","-","-","-","-","-","-","-","-","-" +}; + +static unsigned char defaultkey[NUMKEYS] = +{ + 0xc8,0xd0,0xcb,0xcd,0x2a,0x9d,0x1d,0x39, + 0x1e,0x2c,0xd1,0xc9,0x33,0x34, + 0x9c,0x1c,0xd,0xc,0xf, +}; +volatile unsigned char readch, oldreadch, extended, keystatus[256]; + +static unsigned char option[NUMOPTIONS], keys[NUMKEYS]; + +void (_interrupt _far *oldkeyhandler)(); +void _interrupt _far keyhandler(void); + +#if defined(__386__) + +#pragma aux printchrasm =\ + "add edi, 0xb8000"\ + "rep stosw"\ + parm [edi][ecx][eax]\ + +#pragma aux savescreen =\ + "mov esi, 0xb8000"\ + "mov edi, offset screeninfo"\ + "mov ecx, 1000"\ + "rep movsd"\ + modify [ecx esi edi]\ + +#pragma aux restorescreen =\ + "mov esi, offset screeninfo"\ + "mov edi, 0xb8000"\ + "mov ecx, 1000"\ + "rep movsd"\ + modify [ecx esi edi]\ + +#else + +void printchrasm (int rdi, int rcx, int rax) +{ + _asm + { + cld + mov di, 0b800h + mov es, di + mov di, rdi + mov cx, rcx + mov ax, rax + rep stosw + } +} + +void savescreen () +{ + _asm + { + cld + mov di, offset screeninfo + mov cx, 2000 + mov si, seg screeninfo + mov es, si + push ds + mov si, 0b800h + mov ds, si + xor si, si + rep movsw + pop ds + } +} + +void restorescreen () +{ + _asm + { + cld + mov si, offset screeninfo + mov cx, 2000 + mov di, 0b800h + mov es, di + xor di, di + rep movsw + } +} + +#endif + +void _interrupt _far keyhandler() +{ + oldreadch = readch; + _asm + { + in al, 60h + mov readch, al + in al, 61h + or al, 80h + out 61h, al + and al, 7fh + out 61h, al + } + if ((readch|1) == 0xe1) + extended = 128; + else + { + if (oldreadch != readch) + { + if ((readch&128) == 0) + { + if (keystatus[(readch&127)+extended] == 0) + keystatus[(readch&127)+extended] = 1; + } + else + keystatus[(readch&127)+extended] = 0; + } + extended = 0; + } + _asm + { + mov al, 20h + out 20h, al + } +} + +main() +{ + int i, j; + unsigned char ch, col; + + loadsetup(); + drawscreen(); + savescreen(); + + j = 0; + for(i=0;i= 0) && (i <= 4)) + { + restorescreen(); + i = menu("Main Menu",MAINMENU,i); + restorescreen(); + + switch(i) + { + case 0: + if ((j = menu("Graphics Mode Selection",GRAPHMENU,option[0])) >= 0) + { + option[0] = j; + if (option[0] == 0) + { + restorescreen(); + if ((j = menu("Select X dimension",CHAINXDIMMENU,option[6]&15)) >= 0) + option[6] = ((option[6]&0xf0)|(j&0x0f)); + + restorescreen(); + if ((j = menu("Select Y dimension",CHAINYDIMMENU,(option[6]>>4)&15)) >= 0) + option[6] = ((option[6]&0x0f)|((j<<4)&0xf0)); + } + else if (option[0] == 1) + { + restorescreen(); + if ((j = menu("Select VESA2 mode",VESA2MENU,option[6]&15)) >= 0) + option[6] = ((option[6]&0xf0)|(j&0x0f)); + } + } + break; + case 1: + if ((j = menu("Digitized Sound Selection",DIGIMENU,option[1])) >= 0) + { + option[1] = j; + if (option[1] != 0) + { + restorescreen(); + if ((j = menu("Select sound options",DIGIOPTIONMENU,option[7]&15)) >= 0) + option[7] = ((option[7]&0xf0)|(j&0x0f)); + + restorescreen(); + if ((j = menu("Select playback rate",DIGIHZMENU,(option[7]>>4)&15)) >= 0) + option[7] = ((option[7]&0x0f)|((j<<4)&0xf0)); + } + } + break; + case 2: + if ((j = menu("Music Selection",MUSICMENU,option[2])) >= 0) + option[2] = j; + break; + case 3: + if ((j = menu("Input Device Selection",INPUTMENU,option[3])) >= 0) + { + option[3] = j; + definekeys(); + } + break; + case 4: + if ((j = menu("Communications Selection",COMMENU,option[4])) >= 0) + { + option[4] = j; + + if ((j >= 1) && (j <= 4)) + { + restorescreen(); + if ((j = menu("COM Speed Selection",COMSPEEDMENU,option[5]&15)) >= 0) + option[5] = ((option[5]&0xf0)|(j&0x0f)); + + restorescreen(); + if ((j = menu("COM IRQ Selection",COMIRQMENU,(option[5]>>4)&15)) >= 0) + option[5] = ((option[5]&0x0f)|((j<<4)&0xf0)); + } + } + break; + case 6: + savesetup(); + break; + } + } + + _asm + { + mov ax, 3 + int 10h + } +} + +loadsetup() +{ + int fil, i, j; + + if ((fil = open("setup.dat",O_BINARY|O_RDONLY,S_IREAD)) == -1) + { + for(i=0;i numstrings) selection = numstrings-1; + + xdim = 0; + for(i=firstring;i xdim) + xdim = strlen(&strtable[i][0]); + } + xdim += 4; + ydim = numstrings+2; + x1 = 39-(xdim>>1); + y1 = 12-(ydim>>1); + + printstr((int)39-(strlen(title)>>1),(int)y1-1,title,32); + + buffer[0] = 218; + for(i=1;i= i-(y1+1)) + selection++; + } + else + { + buffer[0] = 179; + for(j=1;j= numstrings) + selection = 0; + } + while (strtable[firstring+selection][0] == 196); + } + if ((ch == 59) && (firstring == menuoffs[KEYMENU])) + return(-256); + ch = 0; + } + if ((ch == 32) && (firstring == menuoffs[KEYMENU])) + return(-257); + } + for(i=ydim-1;i>=0;i--) + if (strtable[firstring+i][0] == 196) + if (selection >= i) + selection--; + if (ch == 27) + return(-1-selection); + else + return(selection); +} + +definekeys() +{ + int i, j, k, keypos; + + for(i=1;i<24;i++) + printchr(1,i,(unsigned char)32,(unsigned char)0x40,78); + + printstr(1,23,"Change selected key by pressing ENTER, then the KEY. ESC returns to main menu.",71); + printstr(26,24," Press F1 for default keys. ",71); + + keypos = 0; + do + { + //Draw and select box + j = menuoffs[KEYMENU]; + for(i=0;i 0) + { + strtable[j][k+50] = keytable[keys[i]][k]; + k++; + } + + do + { + j++; + } while (strtable[j][0] == 196); + } + + i = menu("Custom Key Menu",KEYMENU,keypos); + if (i == -256) //F1 - reset to defaults + { + for(i=0;i= 0) + { + keypos = i; + keys[keypos] = getscancode(keys[keypos]); + } + + } while ((i >= 0) || (i == -256)); +} + +getscancode(unsigned char scancode) +{ +#if defined(__386__) + unsigned char *ptr; +#else + unsigned char far *ptr; +#endif + int i, j; + + for(j=0;j<25;j++) + for(i=0;i<57;i++) + { +#if defined(__386__) + ptr = (unsigned char *)(0xb8000+(((j*80)+i)<<1)+1); +#else + ptr = (unsigned char far *)(0xb8000000+(((j*80)+i)<<1)+1); +#endif + if (*ptr == 75) + *ptr = 19; + } + + for(i=0;i<256;i++) + keystatus[i] = 0; + + oldkeyhandler = _dos_getvect(0x9); + _disable(); _dos_setvect(0x9, keyhandler); _enable(); + + i = 0; + while (1) + { + if (i != 0xaa) + { + if (keystatus[i] != 0) + { + j = i; + break; + } + } + i = ((i+1)&255); + } + + _disable(); _dos_setvect(0x9, oldkeyhandler); _enable(); + + if (j > 1) + return(j); + else + return(scancode); +} diff --git a/buildengine/utils/transpal.c b/buildengine/utils/transpal.c new file mode 100755 index 0000000..ef92965 --- /dev/null +++ b/buildengine/utils/transpal.c @@ -0,0 +1,290 @@ +// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman +// Ken Silverman's official web site: "http://www.advsys.net/ken" +// See the included license file "BUILDLIC.TXT" for license info. + +#include +#ifdef PLATFORM_DOS +#include +#include +#include +#include +#else +#include +#include +#include +#include "unix_compat.h" +#endif +#include +#include +#include "pragmas.h" + +#ifdef PLATFORM_DOS +#pragma intrinsic(min); +#endif + +#define MAXPALOOKUPS 256 + +static long numpalookups, transratio; +static char palettefilename[13], origpalookup[MAXPALOOKUPS<<8]; +static char palette[768], palookup[MAXPALOOKUPS<<8], transluc[65536]; +static char closestcol[64][64][64]; + +#define FASTPALGRIDSIZ 8 +static long rdist[129], gdist[129], bdist[129]; +static char colhere[((FASTPALGRIDSIZ+2)*(FASTPALGRIDSIZ+2)*(FASTPALGRIDSIZ+2))>>3]; +static char colhead[(FASTPALGRIDSIZ+2)*(FASTPALGRIDSIZ+2)*(FASTPALGRIDSIZ+2)]; +static long colnext[256]; +static char coldist[8] = {0,1,2,3,4,3,2,1}; +static long colscan[27]; + +int main(short int argc,char **argv) +{ + char col, ch; + short orignumpalookups; + long fil, i, j, rscale, gscale, bscale; + + if ((argc != 3) && (argc != 6)) + { + printf("TRANSPAL [numshades][trans#(0-inv,256-opa)][r][g][b] by Kenneth Silverman\n"); + printf(" Ex #1: transpal 32 170 30 59 11 (I use these values in my BUILD demo)\n"); + printf(" ÀÄÄÁÄÄÁÄÄÄ The RGB scales are optional\n"); + printf(" Ex #2: transpal 64 160\n\n"); + printf("Once tables are generated, use any of these keys to quit:\n"); + printf(" Press ENTER to update both the shade table and transluscent table\n"); + printf(" Press SPACE to update the transluscent table ONLY\n"); + printf(" Press ESC to quit without saving anything\n"); + exit(0); + } + + strcpy(&palettefilename,"palette.dat"); + numpalookups = atol(argv[1]); + transratio = atol(argv[2]); + + if (argc == 6) + { + rscale = atol(argv[3]); + gscale = atol(argv[4]); + bscale = atol(argv[5]); + } + else + { + rscale = 30; + gscale = 59; + bscale = 11; + } + + if ((numpalookups < 1) || (numpalookups > 256)) + { printf("Invalid number of shades\n"); exit(0); } + if ((transratio < 0) || (transratio > 256)) + { printf("Invalid transluscent ratio\n"); exit(0); } + + if ((fil = open(palettefilename,O_BINARY|O_RDWR,S_IREAD)) == -1) + { + printf("%s not found",palettefilename); + exit(0); + } + read(fil,palette,768); + read(fil,&orignumpalookups,2); + orignumpalookups = min(max(orignumpalookups,1),256); + read(fil,origpalookup,(long)orignumpalookups<<8); + close(fil); + + setvmode(0x13); + koutpw(0x3c4,0x0604); + koutpw(0x3d4,0x0014); + koutpw(0x3d4,0xe317); + + koutpw(0x3d4,9+(0<<8)); + + koutpw(0x3c4,0x0f02); + clearbuf(0xa0000,65536>>2,0L); + + koutp(0x3c8,0); + for(i=0;i<768;i++) koutp(0x3c9,palette[i]); + + initfastcolorlookup(rscale,gscale,bscale); + clearbuf(closestcol,262144>>2,0xffffffff); + + for(i=0;i>2)+0xa0000,(long)col); + drawpixel(((((i<<1)+1)*320+(j+8))>>2)+0xa0000,(long)col); + } + + for(i=0;i<256;i++) + for(j=0;j<6;j++) + { + koutpw(0x3c4,2+(256<<((i+8)&3))); //Draw top line + drawpixel((((j+132+0)*320+(i+8))>>2)+0xa0000,i); + + koutpw(0x3c4,2+(256<<((j+0)&3))); //Draw left line + drawpixel((((i+132+8)*320+(j+0))>>2)+0xa0000,i); + } + + for(i=0;i<256;i++) + for(j=0;j<256;j++) + { + col = gettrans((char)i,(char)j,transratio); + transluc[(i<<8)+j] = col; + + koutpw(0x3c4,2+(256<<((i+8)&3))); + drawpixel((((j+132+8)*320+(i+8))>>2)+0xa0000,(long)col); + } + + do + { + ch = getch(); + } while ((ch != 32) && (ch != 13) && (ch != 27)); + + setvmode(0x3); + + if (ch == 13) + { + if ((fil = open(palettefilename,O_BINARY|O_TRUNC|O_CREAT|O_WRONLY,S_IWRITE)) == -1) + { printf("Couldn't save file",palettefilename); exit(0); } + write(fil,palette,768); + write(fil,&numpalookups,2); + write(fil,palookup,numpalookups<<8); + write(fil,transluc,65536); + close(fil); + printf("Shade table AND transluscent table updated\n"); + } + else if (ch == 32) + { + if ((fil = open(palettefilename,O_BINARY|O_TRUNC|O_CREAT|O_WRONLY,S_IWRITE)) == -1) + { printf("Couldn't save file",palettefilename); exit(0); } + write(fil,palette,768); + write(fil,&orignumpalookups,2); + write(fil,origpalookup,(long)orignumpalookups<<8); + write(fil,transluc,65536); + close(fil); + printf("Transluscent table updated\n"); + } + else + printf("Palette file wasn't touched\n"); +} + +getpalookup(char dashade, char dacol) +{ + long r, g, b, t; + char *ptr; + + ptr = (char *)&palette[dacol*3]; + t = divscale16(numpalookups-dashade,numpalookups); + r = ((ptr[0]*t+32768)>>16); + g = ((ptr[1]*t+32768)>>16); + b = ((ptr[2]*t+32768)>>16); + return(getclosestcol(r,g,b)); +} + +gettrans(char dat1, char dat2, long datransratio) +{ + long r, g, b; + char *ptr, *ptr2; + + ptr = (char *)&palette[dat1*3]; + ptr2 = (char *)&palette[dat2*3]; + r = ptr[0]; r += (((ptr2[0]-r)*datransratio+128)>>8); + g = ptr[1]; g += (((ptr2[1]-g)*datransratio+128)>>8); + b = ptr[2]; b += (((ptr2[2]-b)*datransratio+128)>>8); + return(getclosestcol(r,g,b)); +} + +initfastcolorlookup(long rscale, long gscale, long bscale) +{ + long i, j, x, y, z; + char *ptr; + + j = 0; + for(i=64;i>=0;i--) + { + //j = (i-64)*(i-64); + rdist[i] = rdist[128-i] = j*rscale; + gdist[i] = gdist[128-i] = j*gscale; + bdist[i] = bdist[128-i] = j*bscale; + j += 129-(i<<1); + } + + clearbufbyte(FP_OFF(colhere),sizeof(colhere),0L); + clearbufbyte(FP_OFF(colhead),sizeof(colhead),0L); + + ptr = (char *)&palette[768-3]; + for(i=255;i>=0;i--,ptr-=3) + { + j = (ptr[0]>>3)*FASTPALGRIDSIZ*FASTPALGRIDSIZ+(ptr[1]>>3)*FASTPALGRIDSIZ+(ptr[2]>>3)+FASTPALGRIDSIZ*FASTPALGRIDSIZ+FASTPALGRIDSIZ+1; + if (colhere[j>>3]&(1<<(j&7))) colnext[i] = colhead[j]; else colnext[i] = -1; + colhead[j] = i; + colhere[j>>3] |= (1<<(j&7)); + } + + i = 0; + for(x=-FASTPALGRIDSIZ*FASTPALGRIDSIZ;x<=FASTPALGRIDSIZ*FASTPALGRIDSIZ;x+=FASTPALGRIDSIZ*FASTPALGRIDSIZ) + for(y=-FASTPALGRIDSIZ;y<=FASTPALGRIDSIZ;y+=FASTPALGRIDSIZ) + for(z=-1;z<=1;z++) + colscan[i++] = x+y+z; + i = colscan[13]; colscan[13] = colscan[26]; colscan[26] = i; +} + +getclosestcol(long r, long g, long b) +{ + long i, j, k, dist, mindist, retcol; + long *rlookup, *glookup, *blookup; + char *ptr; + + if (closestcol[r][g][b] != 255) return(closestcol[r][g][b]); + + j = (r>>3)*FASTPALGRIDSIZ*FASTPALGRIDSIZ+(g>>3)*FASTPALGRIDSIZ+(b>>3)+FASTPALGRIDSIZ*FASTPALGRIDSIZ+FASTPALGRIDSIZ+1; + mindist = min(rdist[coldist[r&7]+64+8],gdist[coldist[g&7]+64+8]); + mindist = min(mindist,bdist[coldist[b&7]+64+8]); + mindist++; + + rlookup = (long *)&rdist[64-r]; + glookup = (long *)&gdist[64-g]; + blookup = (long *)&bdist[64-b]; + + retcol = -1; + for(k=26;k>=0;k--) + { + i = colscan[k]+j; if ((colhere[i>>3]&(1<<(i&7))) == 0) continue; + for(i=colhead[i];i>=0;i=colnext[i]) + { + ptr = (char *)&palette[i*3]; + dist = glookup[ptr[1]]; if (dist >= mindist) continue; + dist += rlookup[ptr[0]]; if (dist >= mindist) continue; + dist += blookup[ptr[2]]; if (dist >= mindist) continue; + mindist = dist; retcol = i; + } + } + if (retcol < 0) + { + mindist = 0x7fffffff; + ptr = (char *)&palette[768-3]; + for(i=255;i>=0;i--,ptr-=3) + { + dist = glookup[ptr[1]]; if (dist >= mindist) continue; + dist += rlookup[ptr[0]]; if (dist >= mindist) continue; + dist += blookup[ptr[2]]; if (dist >= mindist) continue; + mindist = dist; retcol = i; + } + } + ptr = (char *)&closestcol[r][g][b]; + *ptr = retcol; + if ((r >= 4) && (ptr[(-2)<<12] == retcol)) ptr[(-3)<<12] = retcol, ptr[(-2)<<12] = retcol, ptr[(-1)<<12] = retcol; + if ((g >= 4) && (ptr[(-2)<<6] == retcol)) ptr[(-3)<<6] = retcol, ptr[(-2)<<6] = retcol, ptr[(-1)<<6] = retcol; + if ((b >= 4) && (ptr[(-2)] == retcol)) ptr[(-3)] = retcol, ptr[(-2)] = retcol, ptr[(-1)] = retcol; + if ((r < 64-4) && (ptr[(2)<<12] == retcol)) ptr[(3)<<12] = retcol, ptr[(2)<<12] = retcol, ptr[(1)<<12] = retcol; + if ((g < 64-4) && (ptr[(2)<<6] == retcol)) ptr[(3)<<6] = retcol, ptr[(2)<<6] = retcol, ptr[(1)<<6] = retcol; + if ((b < 64-4) && (ptr[(2)] == retcol)) ptr[(3)] = retcol, ptr[(2)] = retcol, ptr[(1)] = retcol; + if ((r >= 2) && (ptr[(-1)<<12] == retcol)) ptr[(-1)<<12] = retcol; + if ((g >= 2) && (ptr[(-1)<<6] == retcol)) ptr[(-1)<<6] = retcol; + if ((b >= 2) && (ptr[(-1)] == retcol)) ptr[(-1)] = retcol; + if ((r < 64-2) && (ptr[(1)<<12] == retcol)) ptr[(1)<<12] = retcol; + if ((g < 64-2) && (ptr[(1)<<6] == retcol)) ptr[(1)<<6] = retcol; + if ((b < 64-2) && (ptr[(1)] == retcol)) ptr[(1)] = retcol; + return(retcol); +} diff --git a/buildengine/utils/unix_compat.h b/buildengine/utils/unix_compat.h new file mode 100755 index 0000000..c859b53 --- /dev/null +++ b/buildengine/utils/unix_compat.h @@ -0,0 +1,66 @@ +/* + * Unix compatibility header. Takes care of some legacy code issues. + * + * Written by Ryan C. Gordon (icculus@lokigames.com) + * + * Please do NOT harrass Ken Silverman about any code modifications + * (including this file) to BUILD. + */ + +// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman +// Ken Silverman's official web site: "http://www.advsys.net/ken" +// See the included license file "BUILDLIC.TXT" for license info. + +#ifndef _INCLUDE_UNIX_COMPAT_H_ +#define _INCLUDE_UNIX_COMPAT_H_ + +#if (!defined PLATFORM_UNIX) +#error PLATFORM_UNIX is not defined. +#endif + +// Defines +#define outpw(x, y) +#define koutpw(x, y) +#define outb(x, y) +#define koutb(x, y) +#define outp(x, y) +#define koutp(x, y) + +#define __far +#define __interrupt +#define interrupt +#define far +#define kmalloc(x) malloc(x) +#define kkmalloc(x) malloc(x) +#define kfree(x) free(x) +#define kkfree(x) free(x) +#define FP_OFF(x) ((long) (x)) + +#define VIDEOBASE surface->pixels +// Need this for FNM_CASEFOLD +#define _GNU_SOURCE + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#ifndef stricmp +#define stricmp(a,b) strcasecmp(a,b) +#endif + +#ifndef max +#define max(x, y) (((x) > (y)) ? (x) : (y)) +#endif + +#ifndef min +#define min(x, y) (((x) < (y)) ? (x) : (y)) +#endif + +#ifndef getch +#define getch() getchar() +#endif + +// Sane writing permissions for Unix systems +#define UC_PERMS (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) + +#endif diff --git a/buildengine/utils/ureadme.txt b/buildengine/utils/ureadme.txt new file mode 100755 index 0000000..d261ec5 --- /dev/null +++ b/buildengine/utils/ureadme.txt @@ -0,0 +1,45 @@ +// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman +// Ken Silverman's official web site: "http://www.advsys.net/ken" +// See the included license file "BUILDLIC.TXT" for license info. + +All .C files in this directory are separate programs. Do not link them to +each other. + +To best view my source, set your "Tab Stops" to 3! + +------------------- Brief description of utility files -------------------- + +BACKMAP6.C: Converts Build MAP format from 7 to 6 + +BACKMAP5.C: Converts Build MAP format from 6 to 5 + +CONVMAP6.C: Converts Build MAP format from 5 to 6 + +CONVMAP7.C: Converts Build MAP format from 6 to 7 + +TRANSPAL.C: Palette generation utility + NOTE: This program requires PRAGMAS.H. It is located inside SRC.ZIP. + NOTE: This program requires PALETTE.DAT to be in the directory. You + can extract it from STUFF.DAT by using my KEXTRACT utility. + +EDITART.C: ART collection utility and editor + NOTE: This program requires PALETTE.DAT, TABLES.DAT to be in the + directory you run it from. You can extract these files from + STUFF.DAT by using my KEXTRACT utility. + +KGROUP.C: Use to combine files into a .GRP file (Note: "STUFF.DAT" in my + game directory is actually a .GRP file even though it has a different + file extension) + +KEXTRACT.C: Use to extract files from a .GRP file + +WAD2MAP.C: Doom to Build converter utility. This converts the maps. + Note: this program requires "pragmas.h". It is located inside SRC.ZIP. + +WAD2ART.C: Doom to Build converter utility. This converts the textures. + +SETUP.C: The Build setup program. This code should also work in a 16-bit + compiler. (That's how I got SETUP.EXE so small!) + +----------------------------------------------------------------------------- +-Ken S. (web page: http://www.advsys.net/ken) diff --git a/buildengine/utils/wad2art.c b/buildengine/utils/wad2art.c new file mode 100755 index 0000000..e6d5a79 --- /dev/null +++ b/buildengine/utils/wad2art.c @@ -0,0 +1,310 @@ +// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman +// Ken Silverman's official web site: "http://www.advsys.net/ken" +// See the included license file "BUILDLIC.TXT" for license info. +// This file has been modified from Ken Silverman's original release + +#include +#include +#include +#include +#include +#include + +#define MAXWADS 4096 + +static long artversion, localtilestart, localtileend; +static long fil1, fil2; +static char wadata[MAXWADS][8]; +static long wadplc[MAXWADS], wadlen[MAXWADS], numwads; +static long xoffses[1024], ylookup[256], picanm[MAXWADS]; +static short tilesizx[MAXWADS], tilesizy[MAXWADS]; +static char pal[768], palookup[8192]; +static char screen[65536], tempbuf[131072]; +static long frameplace; + +#pragma aux setvmode =\ + "int 0x10",\ + parm [eax]\ + +#pragma aux drawpixel =\ + "mov byte ptr [edi], al",\ + parm [edi][eax]\ + +#pragma aux clearbuf =\ + "rep stosd",\ + parm [edi][ecx][eax]\ + +#pragma aux copybuf =\ + "rep movsd",\ + parm [esi][edi][ecx]\ + +main(short argc, char **argv) +{ + long i, j, endoffile; + char wadfile[80]; + + printf("Wad2Art! Copyright 1995 by Ken Silverman\n"); + + if (argc != 2) + { + printf("Command line parameters: Wad2Art [Doom IWAD file]\n"); + printf(" Creates TILES000.ART, PALETTE.DAT, and NAMES.H in current directory.\n"); + printf(" Ex: wad2art c:\\doom\\doom.wad\n"); + exit(0); + } + + strcpy(wadfile,argv[1]); + if (strchr(wadfile,'.') == 0) strcat(wadfile,".wad"); + if ((fil1 = open(wadfile,O_BINARY|O_RDWR,S_IREAD)) == -1) + { printf("Wad not found\n"); exit(0); } + if ((fil2 = open("tiles000.art",O_BINARY|O_TRUNC|O_CREAT|O_WRONLY,S_IWRITE)) == -1) + { printf("Can't open art file\n"); exit(0); } + + frameplace = FP_OFF(screen); + + j = 0; + for(i=0;i<256;i++) { ylookup[i] = j; j += 320; } + + printf("Loading wad header...\n"); + loadwadheader(); + setvmode(0x13); + lseek(fil2,16+(numwads<<3),SEEK_SET); + for(i=0;i>= 2; + outp(0x3c9,pal[i]); + } + + i = 0; + while (strnicmp(wadata[i],"COLORMAP",8) != 0) i++; + lseek(fil1,wadplc[i],SEEK_SET); + read(fil1,palookup,8192); + + if ((fil3 = open("palette.dat",O_BINARY|O_TRUNC|O_CREAT|O_WRONLY,S_IWRITE)) == -1) + { printf("Cannot save palette.dat\n"); exit(0); } + write(fil3,pal,768); + danumshades = 32; + write(fil3,&danumshades,2); + write(fil3,palookup,8192); + close(fil3); +} + +saveart (short tilenum, short xlen, short ylen) +{ + long i, x, p, pend; + + pend = ylookup[ylen]; + copybuf(frameplace,0xa0000,pend>>2); + + tilesizx[tilenum] = xlen; + tilesizy[tilenum] = ylen; + i = 0; + for(x=0;x= 10000) buffer[j++] = ((i/10000)%10)+48; + if (i >= 1000) buffer[j++] = ((i/1000)%10)+48; + if (i >= 100) buffer[j++] = ((i/100)%10)+48; + if (i >= 10) buffer[j++] = ((i/10)%10)+48; + buffer[j++] = (i%10)+48; + + buffer[j++] = 13; + buffer[j++] = 10; + write(fil3,&buffer[0],j); + } + + close(fil3); + return; +} + +showart (char *part) +{ + char yoff, ylen; + short xsiz, ysiz; + long i, j, z, zx, zzx, x, y, p, pend, junk, curplc; + + curplc = -1; + if ((strnicmp(part,"L_START",7) == 0) || (strnicmp(part,"S_START",7) == 0) || (strnicmp(part,"P_START",7) == 0)) + { + if (strnicmp(part,"L_START",7) == 0) + z = 462; + else + { + z = 0; + while (strnicmp(wadata[z],part,7) != 0) z++; + z++; + } + + do + { + if (strnicmp(wadata[z],"P1_START",8) == 0) z++; + if (strnicmp(wadata[z],"P1_END",6) == 0) z++; + if (strnicmp(wadata[z],"P2_START",8) == 0) z++; + if (strnicmp(wadata[z],"S_START",7) == 0) break; + if (strnicmp(wadata[z],"S_END",5) == 0) break; + if (strnicmp(wadata[z],"P_END",5) == 0) break; + + if (curplc != wadplc[z]) lseek(fil1,wadplc[z],SEEK_SET); + read(fil1,&tempbuf[0],wadlen[z]); + curplc = wadplc[z]+wadlen[z]; + + xsiz = (long)tempbuf[0]+(((long)tempbuf[1])<<8); + ysiz = (long)tempbuf[2]+(((long)tempbuf[3])<<8); + if ((xsiz <= 0) || (ysiz <= 0) || (xsiz > 320) || (ysiz > 200)) goto skipit; + i = 8; + for(zx=0;zx>2,0xffffffff); + + for(x=0;x +#include +#include +#include +#include +#include +#include "pragmas.h" + +#define MAXWADS 4096 +#define MAXPOINTS 8192 +#define MAXLINES 8192 +#define MAXSIDES 8192 +#define MAXSECTS 2048 +#define MAXTHINGS 4096 +#define MAXTEXTS 1024 +#define MAXPNAMES 1024 +#define MAXTHINGTYPES 3072 + +#define MAXSECTORS 1024 +#define MAXWALLS 8192 +#define MAXSPRITES 4096 + +long asm; +static unsigned short sqrtable[2048]; + +static char iwadata[MAXWADS][9]; +static long inumwads, iwadstart, iwadplc[MAXWADS], iwadlen[MAXWADS]; + +static char pwadata[MAXWADS][9]; +static long pnumwads, pwadstart, pwadplc[MAXWADS], pwadlen[MAXWADS]; + +static short px[MAXPOINTS], py[MAXPOINTS]; + +typedef struct +{ + short p1, p2, flags, special, tag; + short side1, side2; //If side2 = -1, no left +} linedeftype; +static linedeftype line[MAXLINES]; + +typedef struct +{ + short xoffset, yoffset; + char uppertexture[8], lowertexture[8], middletexture[8]; + short sect; +} sidedeftype; +static sidedeftype side[MAXSIDES]; +static short sidetoppic[MAXSIDES], sidebotpic[MAXSIDES], sidemidpic[MAXSIDES]; + +typedef struct +{ + short floorz, ceilingz; + char floorpic[8], ceilingpic[8]; + short shade, type, tag; +} secttype; +static secttype sect[MAXSECTS]; +static short sectspri[MAXSECTS][8]; + +typedef struct +{ + short x, y, ang, type, options; +} thingtype; +static thingtype thing[MAXTHINGS]; + +static char textname[MAXTEXTS][9]; +static long textoffs[MAXTEXTS]; +static short textpname[MAXTEXTS]; + +static char pname[MAXPNAMES][9]; + + //Build map-linking variables +static short picindex[MAXPOINTS], linindex[MAXPOINTS]; +static short wx[MAXPOINTS], wy[MAXPOINTS], wx2[MAXPOINTS], wy2[MAXPOINTS]; +static short point2[MAXPOINTS], slist[MAXPOINTS], sectorofwall[MAXPOINTS]; + +typedef struct +{ + short wallptr, wallnum; + long ceilingz, floorz; + short ceilingstat, floorstat; + short ceilingpicnum, ceilingheinum; + signed char ceilingshade; + char ceilingpal, ceilingxpanning, ceilingypanning; + short floorpicnum, floorheinum; + signed char floorshade; + char floorpal, floorxpanning, floorypanning; + char visibility, filler; + short lotag, hitag, extra; +} sectortype; + +typedef struct +{ + long x, y; + short point2, nextwall, nextsector, cstat; + short picnum, overpicnum; + signed char shade; + char pal, xrepeat, yrepeat, xpanning, ypanning; + short lotag, hitag, extra; +} walltype; + +typedef struct +{ + long x, y, z; + short cstat, picnum; + signed char shade; + char pal, clipdist, filler; + unsigned char xrepeat, yrepeat; + signed char xoffset, yoffset; + short sectnum, statnum; + short ang, owner, xvel, yvel, zvel; + short lotag, hitag, extra; +} spritetype; + +static sectortype sector[MAXSECTORS]; +static walltype wall[MAXWALLS]; +static spritetype sprite[MAXSPRITES]; + +static char tempbuf[16384]; +static short tempshort[4096]; + + + //SCRIPT parsing variables: +static char scriptname[16]; +static char filebuf[16384]; +static long filhandle, filpos, fileng; + +static char definemode = 0, define[16384], *defineptr[4096]; +static long defineval[16384], definecnt = 0, numdefines = 0; + +static char thingtypemode = 0; +static long thingnum[1024], thingnum2[1024], thingoff[1024], numthings = 0; +static short thingfield[4096]; +static char thingop[4096]; +static long thingval[4096], thingopnum = 0; + +static char texturelookupmode = 0; +static short texturelookup[4096]; + +static char tagtypemode = 0; +static long tagnum[1024], tagnum2[1024], tagoff[1024], numtags = 0; +static char tagstruct[4096], tagop[4096]; +static short tagfield[4096]; +static long tagval[4096], tagopnum = 0; + +static char sectypemode = 0; +static long secnum[1024], secnum2[1024], secoff[1024], numsecs = 0; +static short secfield[4096]; +static char secop[4096]; +static long secval[4096], secopnum = 0; + +#define THINGLISTNUM 123 +static short thinglookup[MAXTHINGTYPES]; +typedef struct { short num; char name[8]; } thinglisttype; +static thinglisttype thinglist[THINGLISTNUM] = +{1,"PLAYA1",2,"PLAYA1",3,"PLAYA1",4,"PLAYA1",11,"PLAYA1",14,"",3004,"POSSA1", +84,"SSWVA1",9,"SPOSA1",65,"CPOSA1",3001,"TROOA1",3002,"SARGA1",58,"SARGA1", +3006,"SKULA1",3005,"HEADA1",69,"BOS2A1C1",3003,"BOSSA1",68,"BSPIA1D1", +71,"PAINA1",66,"SKELA1D1",67,"FATTA1",64,"VILEA1D1",7,"SPIDA1D1",16,"CYBRA1", +88,"",89,"",87,"",2005,"CSAWA0",2001,"SHOTA0",82,"SGN2A0",2002,"MGUNA0", +2003,"LAUNA0",2004,"PLASA0",2006,"BFUGA0",2007,"CLIPA0",2008,"SHELA0", +2010,"ROCKA0",2047,"CELLA0",2048,"AMMOA0",2049,"SBOXA0",2046,"BROKA0", +17,"CELPA0",8,"BPAKA0",2011,"STIMA0",2012,"MEDIA0",2014,"BON1A0", +2015,"BON2A0",2018,"ARM1A0",2019,"ARM2A0",83,"MEGAA0",2013,"SOULA0", +2022,"PINVA0",2023,"PSTRA0",2024,"PINSA0",2025,"SUITA0",2026,"PMAPA0", +2045,"PVISA0",5,"BKEYA0",40,"BSKUA0",13,"RKEYA0",38,"RSKUA0",6,"YKEYA0", +39,"YSKUA0",2035,"BAR1A0",72,"KEENA0",48,"ELECA0",30,"COL1A0",32,"COL3A0", +31,"COL2A0",36,"COL5A0",33,"COL4A0",37,"COL6A0",47,"SMITA0",43,"TRE1A0", +54,"TRE2A0",2028,"COLUA0",85,"TLMPA0",86,"TLP2A0",34,"CANDA0",35,"CBRAA0", +44,"TBLUA0",45,"TGRNA0",46,"TREDA0",55,"SMBTA0",56,"SMGTA0",57,"SMRTA0", +70,"FCANA0",41,"CEYEA0",42,"FSKUA0",49,"GOR1A0",63,"GOR1A0",50,"GOR2A0", +59,"GOR2A0",52,"GOR4A0",60,"GOR4A0",51,"GOR5A0",61,"GOR5A0",53,"HDB1A0", +62,"HDB2A0",73,"GOR3A0",74,"GOR3A0",75,"HDB3A0",76,"HDB4A0",77,"HDB5A0", +78,"HDB6A0",25,"POL1A0",26,"BBRNA0",27,"POL4A0",28,"POL2A0",29,"POL3A0", +10,"PLAYW0",12,"PLAYW0",24,"POB1A0",79,"POB2A0",80,"POB2A0",81,"BRS1A0", +15,"PLAYN0",18,"POSSL0",19,"SPOSL0",20,"TROOM0",21,"SARGN0",22,"HEADL0", +23,""}; + +#pragma aux ksqrtasm =\ + "mov asm, eax",\ + "fild dword ptr asm",\ + "fstp dword ptr asm",\ + "mov bl, byte ptr asm[3]",\ + "sub bl, 63+5",\ + "jge over2048",\ + "xor ebx, ebx",\ + "mov bx, sqrtable[eax*2]",\ + "jmp endksqrtasm",\ + "over2048: lea ecx, [ebx*2]",\ + "shr eax, cl",\ + "mov cl, bl",\ + "xor ebx, ebx",\ + "mov bx, sqrtable[eax*2]",\ + "shl ebx, cl",\ + "endksqrtasm: shr ebx, 10",\ + parm [eax]\ + value [ebx]\ + modify exact [eax ebx ecx]\ + +main(short argc, char **argv) +{ + char argstring[5][80]; + char iwadfil[80], pwadfil[80], doommap[16], buildmap[16], picstr[16]; + long w, numwads, numtexts, startnumtexts, danumtexts, numpnames; + long x, y, z, zz, zzz, zzx, zx, cx, cy, gap, p, pp, i, j, k, l, offs; + long dnumpoints, dnumlines, dnumsides, dnumsectors, dnumthings, good; + long minx, maxx, miny, maxy, numsectors, numwalls, wadtype; + long startnumwalls, l1, l2, startpoint2, dapoint2, area; + long fil, ifil, pfil, x1, y1, x2, y2, startwall, endwall; + long mapversion, posx, posy, posz, templong, cnt, boardwadindex; + short ang, cursectnum; + + printf("Wad2Map! Copyright 1995 by Ken Silverman\n"); + + if ((argc < 3) || (argc > 5)) + { + printf("Command line parameters: Wad2Map (PWADName) IWADName MapName (ScriptName)\n"); + printf(" Ex #1: wad2map c:\\doom\\doom.wad e1m1\n"); + printf(" Ex #2: wad2map c:\\doom\\doom.wad e1m1 kenbuild.txt\n"); + printf(" Ex #3: wad2map c:\\doom\\mypwad.wad c:\\doom\\doom.wad e1m1\n"); + printf(" Ex #4: wad2map c:\\doom\\mypwad.wad c:\\doom\\doom.wad e1m1 kenbuild.txt\n"); + exit(0); + } + + for(i=1;i>1);gap>0;gap>>=1) + for(z=0;z=0;zz-=gap) + { + if (stricmp(iwadata[slist[zz]],iwadata[slist[zz+gap]]) <= 0) break; + i = slist[zz]; slist[zz] = slist[zz+gap]; slist[zz+gap] = i; + } + + if (ifil != pfil) + { + read(pfil,&pnumwads,4); + read(pfil,&pwadstart,4); + lseek(pfil,pwadstart,SEEK_SET); + for(z=0;z= 0) + { + lseek(ifil,iwadplc[w],SEEK_SET); + startnumtexts = numtexts; + read(ifil,&danumtexts,4); numtexts += danumtexts; + read(ifil,&textoffs[startnumtexts],(numtexts-startnumtexts)*sizeof(long)); + for(z=startnumtexts;z=boardwadindex;w--) + { + lseek(pfil,pwadplc[w],SEEK_SET); + + if (stricmp(pwadata[w],"VERTEXES") == 0) + { + dnumpoints = (pwadlen[w]>>2); + read(pfil,tempbuf,pwadlen[w]); + offs = 0; + for(z=0;z maxx) maxx = x; + if (y < miny) miny = y; + if (y > maxy) maxy = y; + } + cx = (((minx+maxx)>>1)&0xffffffc0); + cy = (((miny+maxy)>>1)&0xffffffc0); + + numwalls = 0; + + for(z=0;z= 0) && (z == side[line[zz].side2].sect)) + { + wx[numwalls] = px[line[zz].p2]; wy[numwalls] = py[line[zz].p2]; + wx2[numwalls] = px[line[zz].p1]; wy2[numwalls] = py[line[zz].p1]; + picindex[numwalls] = line[zz].side2; linindex[numwalls++] = zz; + } + } + + startpoint2 = startnumwalls; + for(zz=startnumwalls;zz 0)) j = 2; + else if ((wx2[zz+1]-x)*(wy2[zzz]-y) > (wy2[zz+1]-y)*(wx2[zzz]-x)) j = 2; + + if (j == 2) + { + i = wx[zz+1]; wx[zz+1] = wx[zzz]; wx[zzz] = i; + i = wy[zz+1]; wy[zz+1] = wy[zzz]; wy[zzz] = i; + i = wx2[zz+1]; wx2[zz+1] = wx2[zzz]; wx2[zzz] = i; + i = wy2[zz+1]; wy2[zz+1] = wy2[zzz]; wy2[zzz] = i; + i = picindex[zz+1]; picindex[zz+1] = picindex[zzz]; picindex[zzz] = i; + i = linindex[zz+1]; linindex[zz+1] = linindex[zzz]; linindex[zzz] = i; + } + } + point2[zz] = zz+1; + } + if (j == 0) point2[zz] = startpoint2, startpoint2 = zz+1; + } + + sector[z].wallptr = startnumwalls; + sector[z].wallnum = numwalls-startnumwalls; + } + + //Collect sectors + for(z=0;z>3); + if ((sector[z].ceilingstat&1) == 0) sector[z].ceilingshade = j; + if ((sector[z].floorstat&1) == 0) sector[z].floorshade = j; + for(i=startwall;i>1);gap>0;gap>>=1) + for(z=0;z=0;zz-=gap) + { + if (wx[slist[zz]] <= wx[slist[zz+gap]]) break; + i = slist[zz]; slist[zz] = slist[zz+gap]; slist[zz+gap] = i; + } + + for(z=0;z>= 1; + if ((zz+zzz < numwalls) && (wx[slist[zz+zzz]] < x2)) zz += zzz; + zzz >>= 1; + } while (zzz > 0); + + do + { + zzx = slist[zz]; + if (wx[zzx] > x2) break; + if (wy[zzx] == y2) + if ((wx[point2[zzx]] == x1) && (wy[point2[zzx]] == y1)) + { + wall[z].nextwall = zzx; + wall[z].nextsector = sectorofwall[zzx]; + break; + } + zz++; + } while (zz < numwalls); + + if (wall[z].nextwall < 0) + { + wall[z].picnum = sidemidpic[picindex[z]]; + wall[z].overpicnum = 0; + } + else + { + wall[z].picnum = sidetoppic[picindex[z]]; + if (wall[z].picnum <= 0) wall[z].picnum = sidebotpic[picindex[z]]; + if ((wall[z].picnum <= 0) && (wall[z].nextwall >= 0)) + { + zx = picindex[wall[z].nextwall]; + wall[z].picnum = sidetoppic[zx]; + if (wall[z].picnum <= 0) wall[z].picnum = sidebotpic[zx]; + } + wall[z].overpicnum = sidemidpic[picindex[z]]; + if (wall[z].overpicnum >= 0) wall[z].cstat |= (1+4+16); + } + wall[z].xrepeat = 8; + wall[z].yrepeat = 8; + wall[z].xpanning = (char)((-side[picindex[z]].xoffset)&255); + wall[z].ypanning = (char)(((side[picindex[z]].yoffset<<1))&255); + + if (line[linindex[z]].flags&1) wall[z].cstat |= 1; + //if (wall[z].nextwall >= 0) wall[z].cstat |= 4; + //if ((line[linindex[z]].flags&24) && (wall[z].nextwall >= 0)) + // wall[z].cstat |= 4; + } + + for(z=0;z= thingnum[i]) && (thing[z].type <= thingnum2[i])) + for(j=thingoff[i];j tagnum2[i])) continue; + + for(j=tagoff[i];j= 0) + if ((tagfield[j]&128) ^ (picindex[zx] == line[z].side1)) + l = wall[zx].nextsector; + + zzz = sectspri[l][(tagfield[j]>>8)&7]; + if (zzz < 0) + { + zzz = dnumthings++; + sectspri[l][(tagfield[j]>>8)&7] = zzz; + zzx = sector[l].wallptr; x1 = wall[zzx].x; y1 = wall[zzx].y; + zzx = wall[zzx].point2; x2 = wall[zzx].x; y2 = wall[zzx].y; + sprite[zzz].x = ((x1+x2)>>1) + ksgn(y1-y2); + sprite[zzz].y = ((y1+y2)>>1) + ksgn(x2-x1); + sprite[zzz].sectnum = l; + sprite[zzz].z = sector[l].floorz; + sprite[zzz].clipdist = 32; + sprite[zzz].xrepeat = 64; + sprite[zzz].yrepeat = 64; + } + + switch(tagop[j]) + { + case 0: setspritefield(zzz,k,zz); break; + case 1: setspritefield(zzz,k,getspritefield(zzz,k)+zz); break; + case 2: setspritefield(zzz,k,getspritefield(zzz,k)-zz); break; + case 3: setspritefield(zzz,k,getspritefield(zzz,k)|zz); break; + case 4: setspritefield(zzz,k,getspritefield(zzz,k)&zz); break; + case 5: setspritefield(zzz,k,getspritefield(zzz,k)^zz); break; + } + } + else if (k < 64) + { + l = sectorofwall[zx]; + if (wall[zx].nextsector >= 0) + if ((tagfield[j]&128) ^ (picindex[zx] == line[z].side1)) + l = wall[zx].nextsector; + + switch(tagop[j]) + { + case 0: setsectorfield(l,k,zz); break; + case 1: setsectorfield(l,k,getsectorfield(l,k)+zz); break; + case 2: setsectorfield(l,k,getsectorfield(l,k)-zz); break; + case 3: setsectorfield(l,k,getsectorfield(l,k)|zz); break; + case 4: setsectorfield(l,k,getsectorfield(l,k)&zz); break; + case 5: setsectorfield(l,k,getsectorfield(l,k)^zz); break; + } + } + else if (k < 96) + { + l = zx; + if (wall[zx].nextwall >= 0) + if ((tagfield[j]&128) ^ (picindex[zx] == line[z].side1)) + l = wall[zx].nextwall; + + switch(tagop[j]) + { + case 0: setwallfield(l,k,zz); break; + case 1: setwallfield(l,k,getwallfield(l,k)+zz); break; + case 2: setwallfield(l,k,getwallfield(l,k)-zz); break; + case 3: setwallfield(l,k,getwallfield(l,k)|zz); break; + case 4: setwallfield(l,k,getwallfield(l,k)&zz); break; + case 5: setwallfield(l,k,getwallfield(l,k)^zz); break; + } + } + } + } + } + + for(l=0;l= secnum[i]) && (sect[l].type <= secnum2[i])) + { + for(j=secoff[i];j>8)&7]; + if (zzz < 0) + { + zzz = dnumthings++; + sectspri[l][(secfield[j]>>8)&7] = zzz; + zzx = sector[l].wallptr; x1 = wall[zzx].x; y1 = wall[zzx].y; + zzx = wall[zzx].point2; x2 = wall[zzx].x; y2 = wall[zzx].y; + sprite[zzz].x = ((x1+x2)>>1) + ksgn(y1-y2); + sprite[zzz].y = ((y1+y2)>>1) + ksgn(x2-x1); + sprite[zzz].sectnum = l; + sprite[zzz].z = sector[l].floorz; + sprite[zzz].clipdist = 32; + sprite[zzz].xrepeat = 64; + sprite[zzz].yrepeat = 64; + } + + switch(secop[j]) + { + case 0: setspritefield(zzz,k,zz); break; + case 1: setspritefield(zzz,k,getspritefield(zzz,k)+zz); break; + case 2: setspritefield(zzz,k,getspritefield(zzz,k)-zz); break; + case 3: setspritefield(zzz,k,getspritefield(zzz,k)|zz); break; + case 4: setspritefield(zzz,k,getspritefield(zzz,k)&zz); break; + case 5: setspritefield(zzz,k,getspritefield(zzz,k)^zz); break; + } + } + else if (k < 64) + { + switch(secop[j]) + { + case 0: setsectorfield(l,k,zz); break; + case 1: setsectorfield(l,k,getsectorfield(l,k)+zz); break; + case 2: setsectorfield(l,k,getsectorfield(l,k)-zz); break; + case 3: setsectorfield(l,k,getsectorfield(l,k)|zz); break; + case 4: setsectorfield(l,k,getsectorfield(l,k)&zz); break; + case 5: setsectorfield(l,k,getsectorfield(l,k)^zz); break; + } + } + } + } + + for(z=0;z= 32768) || (klabs(y) >= 32768)) + wall[z].xrepeat = 255; + else + { + zx = mulscale10(ksqrtasm(x*x+y*y),wall[z].yrepeat); + wall[z].xrepeat = (char)min(max(zx,1),255); + } + + wall[z].picnum = texturelookup[wall[z].picnum]; + wall[z].overpicnum = texturelookup[wall[z].overpicnum]; + } + + mapversion = 7; posx = 0; posy = 0; posz = 0; ang = 1536; cursectnum = 0; + + //WATCH OUT THAT FOR DNUMTHINGS BEING HIGHER THAN NUMBER ON DOOM MAP! + for(i=0;i0;i--) + { + y1 = wal->y-y; y2 = wall[wal->point2].y-y; + if ((y1^y2) < 0) + { + x1 = wal->x-x; x2 = wall[wal->point2].x-x; + + if ((x1^x2) < 0) + cnt ^= (x1*y2= 0) + cnt ^= 1; + } + wal++; + } + return(cnt); +} + +initksqrt() +{ + unsigned long i, j, num, root; + + for(i=0;i<2048;i++) + { + num = (i<<20); root = 128; + do + { + j = root; root = ((num/root+root)>>1); + } while (klabs(j-root) > 1); + j = root*root-num; + while (klabs((j-(root<<1)+1)) < klabs(j)) { j += -(root<<1)+1; root--; } + while (klabs((j+(root<<1)+1)) < klabs(j)) { j += (root<<1)+1; root++; } + sqrtable[i] = (unsigned short)root; + } +} + +readbyte() +{ + if (filpos >= fileng) return(-1); + if ((filpos&16383) == 0) read(filhandle,filebuf,16384); + filpos++; + return((long)filebuf[(filpos-1)&16383]); +} + +readline() +{ + long i, ch; + + do + { + do + { + ch = readbyte(); + if (ch < 0) return(0); + } while ((ch == 13) || (ch == 10)); + + i = 0; tempbuf[0] = 0; + while ((ch != 13) && (ch != 10)) + { + if (ch < 0) return(0); + if (ch == ';') + { + do + { + if (ch < 0) return(0); + ch = readbyte(); + } while ((ch != 13) && (ch != 10)); + break; + } + if ((ch == 32) || (ch == 9)) ch = ','; + if ((ch != ',') || (i == 0) || (tempbuf[i-1] != ',')) + { tempbuf[i++] = ch; tempbuf[i] = 0; } + ch = readbyte(); + } + if ((i > 0) && (tempbuf[i-1] == ',')) tempbuf[i-1] = 0; + } while (i <= 0); + return(i); +} + +parsescript() +{ + long i, j, k, l, lasti, breakout, tstart, tend, textnum, frontbackstat; + long spritenumstat, slen; + char ch; + + clearbufbyte(FP_OFF(sectspri),MAXSECTS*8*sizeof(short),0xffffffff); + + if (scriptname[0] == 0) + { + for(i=0;i<4096;i++) texturelookup[i] = i; + return; + } + + if ((filhandle = open(scriptname,O_BINARY|O_RDWR,S_IREAD)) == -1) + { + printf("Could not find %s\n",scriptname); + exit(0); + } + filpos = 0; fileng = filelength(filhandle); + while (readline() != 0) + { + i = 0; j = 0; lasti = 0; + while (1) + { + if ((tempbuf[i] == ',') || (tempbuf[i] == 0)) + { + if (tempbuf[i] == 0) { breakout = 1; } + else { breakout = 0, tempbuf[i] = 0; } + + if (j == 0) + { + if (tempbuf[lasti] == '[') + { + definemode = 0; + thingtypemode = 0; + texturelookupmode = 0; + tagtypemode = 0; + sectypemode = 0; + } + + if (stricmp(&tempbuf[lasti],"#define") == 0) + definemode = 1; + + if (thingtypemode == 1) + { + thingoff[numthings] = thingopnum; + + k = lasti; + while ((tempbuf[k] != 0) && (tempbuf[k] != '-')) k++; + + if (tempbuf[k] == '-') + { + tempbuf[k] = 0; + thingnum[numthings] = atol(&tempbuf[lasti]); + thingnum2[numthings] = atol(&tempbuf[k+1]); + } + else + { + thingnum[numthings] = atol(&tempbuf[lasti]); + thingnum2[numthings] = thingnum[numthings]; + } + + numthings++; + } + else if (stricmp(&tempbuf[lasti],"[THINGTYPES]") == 0) + thingtypemode = 1; + + if (texturelookupmode == 1) + { + textnum = 0; + if ((tempbuf[lasti] >= 48) && (tempbuf[lasti] <= 57)) + { + k = lasti; + while ((tempbuf[k] != 0) && (tempbuf[k] != '-')) k++; + + if (tempbuf[k] == '-') + { + tempbuf[k] = 0; + tstart = atol(&tempbuf[lasti]); + tend = atol(&tempbuf[k+1]); + for(k=tstart;k<=tend;k++) + tempshort[textnum++] = k; + } + else + tempshort[textnum++] = atol(&tempbuf[lasti]); + } + else + { + slen = 0; + while (tempbuf[lasti+slen] != 0) + { + ch = tempbuf[lasti+slen]; + if ((ch >= 97) && (ch <= 122)) tempbuf[lasti+slen] -= 32; + slen++; + } + if (slen > 0) + for(k=inumwads-1;k>=0;k--) + if ((iwadata[k][slen] == 0) || (iwadata[k][slen] == 32)) + if ((iwadata[k][slen-1] != 0) && (iwadata[k][slen-1] != 32)) + { + for(l=slen-1;l>=0;l--) + if (tempbuf[lasti+l] != '?') + { + ch = iwadata[k][l]; + if ((ch >= 97) && (ch <= 122)) ch -= 32; + if (tempbuf[lasti+l] != ch) break; + } + if (l < 0) tempshort[textnum++] = k; + } + } + } + else if (stricmp(&tempbuf[lasti],"[TEXTURELOOKUPS]") == 0) + texturelookupmode = 1; + + if (tagtypemode == 1) + { + tagoff[numtags] = tagopnum; + + k = lasti; + while ((tempbuf[k] != 0) && (tempbuf[k] != '-')) k++; + + if (tempbuf[k] == '-') + { + tempbuf[k] = 0; + tagnum[numtags] = atol(&tempbuf[lasti]); + tagnum2[numtags] = atol(&tempbuf[k+1]); + } + else + { + tagnum[numtags] = atol(&tempbuf[lasti]); + tagnum2[numtags] = tagnum[numtags]; + } + + numtags++; + } + else if (stricmp(&tempbuf[lasti],"[TAGCONVERSIONS]") == 0) + tagtypemode = 1; + + if (sectypemode == 1) + { + secoff[numsecs] = secopnum; + + k = lasti; + while ((tempbuf[k] != 0) && (tempbuf[k] != '-')) k++; + + if (tempbuf[k] == '-') + { + tempbuf[k] = 0; + secnum[numsecs] = atol(&tempbuf[lasti]); + secnum2[numsecs] = atol(&tempbuf[k+1]); + } + else + { + secnum[numsecs] = atol(&tempbuf[lasti]); + secnum2[numsecs] = secnum[numsecs]; + } + numsecs++; + } + else if (stricmp(&tempbuf[lasti],"[SECTORCONVERSIONS]") == 0) + sectypemode = 1; + + } + else if (j > 0) + { + if (definemode == 1) + { + defineptr[numdefines] = (char *)(&define[definecnt]); + for(k=lasti;k= 48) && (tempbuf[k+1] <= 57)) + thingval[thingopnum] = atol(&tempbuf[k+1]); + else + { + for(l=0;l= 48) && (tempbuf[lasti] <= 57)) + l = atol(&tempbuf[lasti]); + else + { + for(l=0;l=0;k--) texturelookup[tempshort[k]] = l; + } + + if (tagtypemode == 1) + { + for(k=lasti;k= 48) && (tempbuf[lasti] <= 57)) //1 DIGIT ONLY! + { + spritenumstat = tempbuf[lasti]-48; + lasti++; + } + + if (stricmp(&tempbuf[lasti],"sprite.x") == 0) tagfield[tagopnum] = 0; + if (stricmp(&tempbuf[lasti],"sprite.y") == 0) tagfield[tagopnum] = 1; + if (stricmp(&tempbuf[lasti],"sprite.z") == 0) tagfield[tagopnum] = 2; + if (stricmp(&tempbuf[lasti],"sprite.cstat") == 0) tagfield[tagopnum] = 3; + if (stricmp(&tempbuf[lasti],"sprite.shade") == 0) tagfield[tagopnum] = 4; + if (stricmp(&tempbuf[lasti],"sprite.pal") == 0) tagfield[tagopnum] = 5; + if (stricmp(&tempbuf[lasti],"sprite.clipdist") == 0) tagfield[tagopnum] = 6; + if (stricmp(&tempbuf[lasti],"sprite.xrepeat") == 0) tagfield[tagopnum] = 7; + if (stricmp(&tempbuf[lasti],"sprite.yrepeat") == 0) tagfield[tagopnum] = 8; + if (stricmp(&tempbuf[lasti],"sprite.xoffset") == 0) tagfield[tagopnum] = 9; + if (stricmp(&tempbuf[lasti],"sprite.yoffset") == 0) tagfield[tagopnum] = 10; + if (stricmp(&tempbuf[lasti],"sprite.picnum") == 0) tagfield[tagopnum] = 11; + if (stricmp(&tempbuf[lasti],"sprite.ang") == 0) tagfield[tagopnum] = 12; + if (stricmp(&tempbuf[lasti],"sprite.xvel") == 0) tagfield[tagopnum] = 13; + if (stricmp(&tempbuf[lasti],"sprite.yvel") == 0) tagfield[tagopnum] = 14; + if (stricmp(&tempbuf[lasti],"sprite.zvel") == 0) tagfield[tagopnum] = 15; + if (stricmp(&tempbuf[lasti],"sprite.owner") == 0) tagfield[tagopnum] = 16; + if (stricmp(&tempbuf[lasti],"sprite.sectnum") == 0) tagfield[tagopnum] = 17; + if (stricmp(&tempbuf[lasti],"sprite.statnum") == 0) tagfield[tagopnum] = 18; + if (stricmp(&tempbuf[lasti],"sprite.lotag") == 0) tagfield[tagopnum] = 19; + if (stricmp(&tempbuf[lasti],"sprite.hitag") == 0) tagfield[tagopnum] = 20; + if (stricmp(&tempbuf[lasti],"sprite.extra") == 0) tagfield[tagopnum] = 21; + + if (stricmp(&tempbuf[lasti],"sector.wallptr") == 0) tagfield[tagopnum] = 32; + if (stricmp(&tempbuf[lasti],"sector.wallnum") == 0) tagfield[tagopnum] = 33; + if (stricmp(&tempbuf[lasti],"sector.ceilingpicnum") == 0) tagfield[tagopnum] = 34; + if (stricmp(&tempbuf[lasti],"sector.floorpicnum") == 0) tagfield[tagopnum] = 35; + if (stricmp(&tempbuf[lasti],"sector.ceilingheinum") == 0) tagfield[tagopnum] = 36; + if (stricmp(&tempbuf[lasti],"sector.floorheinum") == 0) tagfield[tagopnum] = 37; + if (stricmp(&tempbuf[lasti],"sector.ceilingz") == 0) tagfield[tagopnum] = 38; + if (stricmp(&tempbuf[lasti],"sector.floorz") == 0) tagfield[tagopnum] = 39; + if (stricmp(&tempbuf[lasti],"sector.ceilingshade") == 0) tagfield[tagopnum] = 40; + if (stricmp(&tempbuf[lasti],"sector.floorshade") == 0) tagfield[tagopnum] = 41; + if (stricmp(&tempbuf[lasti],"sector.ceilingxpanning") == 0) tagfield[tagopnum] = 42; + if (stricmp(&tempbuf[lasti],"sector.floorxpanning") == 0) tagfield[tagopnum] = 43; + if (stricmp(&tempbuf[lasti],"sector.ceilingypanning") == 0) tagfield[tagopnum] = 44; + if (stricmp(&tempbuf[lasti],"sector.floorypanning") == 0) tagfield[tagopnum] = 45; + if (stricmp(&tempbuf[lasti],"sector.ceilingstat") == 0) tagfield[tagopnum] = 46; + if (stricmp(&tempbuf[lasti],"sector.floorstat") == 0) tagfield[tagopnum] = 47; + if (stricmp(&tempbuf[lasti],"sector.ceilingpal") == 0) tagfield[tagopnum] = 48; + if (stricmp(&tempbuf[lasti],"sector.floorpal") == 0) tagfield[tagopnum] = 49; + if (stricmp(&tempbuf[lasti],"sector.visibility") == 0) tagfield[tagopnum] = 50; + if (stricmp(&tempbuf[lasti],"sector.lotag") == 0) tagfield[tagopnum] = 51; + if (stricmp(&tempbuf[lasti],"sector.hitag") == 0) tagfield[tagopnum] = 52; + if (stricmp(&tempbuf[lasti],"sector.extra") == 0) tagfield[tagopnum] = 53; + + if (stricmp(&tempbuf[lasti],"wall.x") == 0) tagfield[tagopnum] = 64; + if (stricmp(&tempbuf[lasti],"wall.y") == 0) tagfield[tagopnum] = 65; + if (stricmp(&tempbuf[lasti],"wall.point2") == 0) tagfield[tagopnum] = 66; + if (stricmp(&tempbuf[lasti],"wall.nextsector") == 0) tagfield[tagopnum] = 67; + if (stricmp(&tempbuf[lasti],"wall.nextwall") == 0) tagfield[tagopnum] = 68; + if (stricmp(&tempbuf[lasti],"wall.picnum") == 0) tagfield[tagopnum] = 69; + if (stricmp(&tempbuf[lasti],"wall.overpicnum") == 0) tagfield[tagopnum] = 70; + if (stricmp(&tempbuf[lasti],"wall.shade") == 0) tagfield[tagopnum] = 71; + if (stricmp(&tempbuf[lasti],"wall.pal") == 0) tagfield[tagopnum] = 72; + if (stricmp(&tempbuf[lasti],"wall.cstat") == 0) tagfield[tagopnum] = 73; + if (stricmp(&tempbuf[lasti],"wall.xrepeat") == 0) tagfield[tagopnum] = 74; + if (stricmp(&tempbuf[lasti],"wall.yrepeat") == 0) tagfield[tagopnum] = 75; + if (stricmp(&tempbuf[lasti],"wall.xpanning") == 0) tagfield[tagopnum] = 76; + if (stricmp(&tempbuf[lasti],"wall.ypanning") == 0) tagfield[tagopnum] = 77; + if (stricmp(&tempbuf[lasti],"wall.lotag") == 0) tagfield[tagopnum] = 78; + if (stricmp(&tempbuf[lasti],"wall.hitag") == 0) tagfield[tagopnum] = 79; + if (stricmp(&tempbuf[lasti],"wall.extra") == 0) tagfield[tagopnum] = 80; + + tagfield[tagopnum] += (frontbackstat<<7) + (spritenumstat<<8); + + if ((tempbuf[k+1] >= 48) && (tempbuf[k+1] <= 57)) + tagval[tagopnum] = atol(&tempbuf[k+1]); + else if (stricmp("tag",&tempbuf[k+1]) == 0) + tagval[tagopnum] = 0x80000000; + else + { + for(l=0;l= 48) && (tempbuf[lasti] <= 57)) //1 DIGIT ONLY! + { + spritenumstat = tempbuf[lasti]-48; + lasti++; + } + + if (stricmp(&tempbuf[lasti],"sprite.x") == 0) secfield[secopnum] = 0; + if (stricmp(&tempbuf[lasti],"sprite.y") == 0) secfield[secopnum] = 1; + if (stricmp(&tempbuf[lasti],"sprite.z") == 0) secfield[secopnum] = 2; + if (stricmp(&tempbuf[lasti],"sprite.cstat") == 0) secfield[secopnum] = 3; + if (stricmp(&tempbuf[lasti],"sprite.shade") == 0) secfield[secopnum] = 4; + if (stricmp(&tempbuf[lasti],"sprite.pal") == 0) secfield[secopnum] = 5; + if (stricmp(&tempbuf[lasti],"sprite.clipdist") == 0) secfield[secopnum] = 6; + if (stricmp(&tempbuf[lasti],"sprite.xrepeat") == 0) secfield[secopnum] = 7; + if (stricmp(&tempbuf[lasti],"sprite.yrepeat") == 0) secfield[secopnum] = 8; + if (stricmp(&tempbuf[lasti],"sprite.xoffset") == 0) secfield[secopnum] = 9; + if (stricmp(&tempbuf[lasti],"sprite.yoffset") == 0) secfield[secopnum] = 10; + if (stricmp(&tempbuf[lasti],"sprite.picnum") == 0) secfield[secopnum] = 11; + if (stricmp(&tempbuf[lasti],"sprite.ang") == 0) secfield[secopnum] = 12; + if (stricmp(&tempbuf[lasti],"sprite.xvel") == 0) secfield[secopnum] = 13; + if (stricmp(&tempbuf[lasti],"sprite.yvel") == 0) secfield[secopnum] = 14; + if (stricmp(&tempbuf[lasti],"sprite.zvel") == 0) secfield[secopnum] = 15; + if (stricmp(&tempbuf[lasti],"sprite.owner") == 0) secfield[secopnum] = 16; + if (stricmp(&tempbuf[lasti],"sprite.sectnum") == 0) secfield[secopnum] = 17; + if (stricmp(&tempbuf[lasti],"sprite.statnum") == 0) secfield[secopnum] = 18; + if (stricmp(&tempbuf[lasti],"sprite.lotag") == 0) secfield[secopnum] = 19; + if (stricmp(&tempbuf[lasti],"sprite.hitag") == 0) secfield[secopnum] = 20; + if (stricmp(&tempbuf[lasti],"sprite.extra") == 0) secfield[secopnum] = 21; + + if (stricmp(&tempbuf[lasti],"sector.wallptr") == 0) secfield[secopnum] = 32; + if (stricmp(&tempbuf[lasti],"sector.wallnum") == 0) secfield[secopnum] = 33; + if (stricmp(&tempbuf[lasti],"sector.ceilingpicnum") == 0) secfield[secopnum] = 34; + if (stricmp(&tempbuf[lasti],"sector.floorpicnum") == 0) secfield[secopnum] = 35; + if (stricmp(&tempbuf[lasti],"sector.ceilingheinum") == 0) secfield[secopnum] = 36; + if (stricmp(&tempbuf[lasti],"sector.floorheinum") == 0) secfield[secopnum] = 37; + if (stricmp(&tempbuf[lasti],"sector.ceilingz") == 0) secfield[secopnum] = 38; + if (stricmp(&tempbuf[lasti],"sector.floorz") == 0) secfield[secopnum] = 39; + if (stricmp(&tempbuf[lasti],"sector.ceilingshade") == 0) secfield[secopnum] = 40; + if (stricmp(&tempbuf[lasti],"sector.floorshade") == 0) secfield[secopnum] = 41; + if (stricmp(&tempbuf[lasti],"sector.ceilingxpanning") == 0) secfield[secopnum] = 42; + if (stricmp(&tempbuf[lasti],"sector.floorxpanning") == 0) secfield[secopnum] = 43; + if (stricmp(&tempbuf[lasti],"sector.ceilingypanning") == 0) secfield[secopnum] = 44; + if (stricmp(&tempbuf[lasti],"sector.floorypanning") == 0) secfield[secopnum] = 45; + if (stricmp(&tempbuf[lasti],"sector.ceilingstat") == 0) secfield[secopnum] = 46; + if (stricmp(&tempbuf[lasti],"sector.floorstat") == 0) secfield[secopnum] = 47; + if (stricmp(&tempbuf[lasti],"sector.ceilingpal") == 0) secfield[secopnum] = 48; + if (stricmp(&tempbuf[lasti],"sector.floorpal") == 0) secfield[secopnum] = 49; + if (stricmp(&tempbuf[lasti],"sector.visibility") == 0) secfield[secopnum] = 50; + if (stricmp(&tempbuf[lasti],"sector.lotag") == 0) secfield[secopnum] = 51; + if (stricmp(&tempbuf[lasti],"sector.hitag") == 0) secfield[secopnum] = 52; + if (stricmp(&tempbuf[lasti],"sector.extra") == 0) secfield[secopnum] = 53; + + secfield[secopnum] += (spritenumstat<<8); + + if ((tempbuf[k+1] >= 48) && (tempbuf[k+1] <= 57)) + secval[secopnum] = atol(&tempbuf[k+1]); + else if (stricmp("tag",&tempbuf[k+1]) == 0) + secval[secopnum] = 0x80000000; + else + { + for(l=0;l0;j>>=1) + if (i+j < inumwads) + if (stricmp(iwadata[slist[i+j]],nam) <= 0) i += j; + if (stricmp(iwadata[slist[i]],nam) == 0) return(slist[i]); + return(-1); +} diff --git a/buildengine/ves2.h b/buildengine/ves2.h new file mode 100755 index 0000000..e745413 --- /dev/null +++ b/buildengine/ves2.h @@ -0,0 +1,770 @@ +// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman +// Ken Silverman's official web site: "http://www.advsys.net/ken" +// See the included license file "BUILDLIC.TXT" for license info. +// This file has been modified from Ken Silverman's original release + +#ifndef _INCLUDE_VES2_H_ +#define _INCLUDE_VES2_H_ + +#if (!defined PLATFORM_DOS) +#error Do not include this file. It is for the DOS target only. +#endif + +#include +#include +#include +#include +#include + +#include "build.h" +#include "pragmas.h" + +#pragma pack(push,1); + +typedef struct +{ + char VESASignature[4]; + short VESAVersion; + long OemStringPtr, Capabilities, VideoModePtr; + short TotalMemory, OemSoftwareRev; + long OemVendorNamePtr, OemProductNamePtr, OemProductRevPtr; + char reserved[222], OemDATA[256]; +} VBE_vgaInfo; + +typedef struct +{ + short ModeAttributes; + char WinAAtributes, WinBAttributes; + short WinGranularity, WinSize, WinASegment, WinBSegment; + long WinFuncPtr; + short BytesPerScanLine, XResolution, YResolution; + char XCharSize, YCharSize, NumberOfPlanes, BitsPerPixel; + char NumberOfBanks, MemoryModel, BankSize, NumberOfImagePages; + char res1; + char RedMaskSize, RedFieldPosition; + char GreenMaskSize, GreenFieldPosition; + char BlueMaskSize, BlueFieldPosition; + char RsvdMaskSize, RsvdFieldPosition, DirectColorModeInfo; + long PhysBasePtr, OffScreenMemOffset; + short OffScreenMemSize; + char res2[206]; +} VBE_modeInfo; + +struct _RMWORDREGS { unsigned short ax, bx, cx, dx, si, di, cflag; }; +struct _RMBYTEREGS { unsigned char al, ah, bl, bh, cl, ch, dl, dh; }; +typedef union { struct _RMWORDREGS x; struct _RMBYTEREGS h; } RMREGS; +typedef struct { unsigned short es, cs, ss, ds; } RMSREGS; + +typedef struct +{ + long edi, esi, ebp, reserved, ebx, edx, ecx, eax; + short flags, es, ds, fs, gs, ip, cs, sp, ss; +} _RMREGS; + +#pragma pack(pop); + +long VESABuf_sel = 0, VESABuf_rseg; +short modelist[256]; +char *screen = NULL, vesachecked = 0; +long xres, yres, bytesperline, frameplace, imageSize, maxpages; +long buffermode, origbuffermode, linearmode; +long setactiveentry = 0, setvisualentry = 0, setpaletteentry = 0; +char permanentupdate = 0, vgacompatible; +short visualpagelookup[64][2]; +long activepagelookup[64]; +static long ves2lastx[MAXYDIM]; +static long davesapageshift; +static VBE_vgaInfo vgaInfo; +long globlinplace; +static long backlinaddress = 0; //Save address for free operation (0x801) + +void faketimerhandler(void); + +void qlimitrate(void); +#pragma aux qlimitrate =\ + "mov dx, 0x3da",\ + "wait1: in al, dx",\ + "test al, 1",\ + "jnz wait1",\ + modify exact [eax edx]\ + +void backupsegs(void); +short ods, oes, oss; +#pragma aux backupsegs =\ + "mov ods, ds",\ + "mov oes, es",\ + "mov oss, ss",\ + modify [eax]\ + +void restoresegs(void); +#pragma aux restoresegs =\ + "mov ds, ods",\ + "mov es, oes",\ + "mov ss, oss",\ + modify [eax]\ + +/* //64-bit copybufbyte +#pragma aux copybufbyte =\ + "cmp ecx, 8",\ + "jae longcopy",\ + "test cl, 1",\ + "jz shortskip1",\ + "movsb",\ + "shortskip1: shr ecx, 2",\ + "jnc shortskip2",\ + "movsw",\ + "shortskip2: rep movsd",\ + "jmp endit",\ + "longcopy: test edi, 1",\ + "jz skip1",\ + "movsb",\ + "dec ecx",\ + "skip1: test edi, 2",\ + "jz skip2",\ + "movsw",\ + "sub ecx, 2",\ + "skip2: test edi, 4",\ + "jz skip3",\ + "movsd",\ + "sub ecx, 4",\ + "skip3: mov ebx, ecx",\ + "shr ecx, 3",\ + "jz skip4",\ + "begloop: fld qword ptr [esi]",\ + "fstp qword ptr [edi]",\ + "add esi, 8",\ + "add edi, 8",\ + "dec ecx",\ + "jnz begloop",\ + "skip4: test bl, 4",\ + "jz skip5",\ + "movsd",\ + "skip5: test bl, 2",\ + "jz skip6",\ + "movsw",\ + "skip6: test bl, 1",\ + "jz endit",\ + "movsb",\ + "endit:",\ + parm [esi][edi][ecx]\ + modify [ebx]\ +*/ + + +void vesasetactive(long i1, long i2, long i3, long i4); +#pragma aux vesasetactive =\ + "call dword ptr [setactiveentry]",\ + parm [eax][ebx][ecx][edx]\ + +void vesasetvisual(long i1, long i2, long i3, long i4); +#pragma aux vesasetvisual =\ + "call dword ptr [setvisualentry]",\ + parm [eax][ebx][ecx][edx]\ + +long vesasetpalette(long i1, long i2, long i3, long i4, long i5, char *i6); +#pragma aux vesasetpalette =\ + "call dword ptr [setpaletteentry]",\ + parm [eax][ebx][ecx][edx][esi][edi]\ + +long DPMI_int86(long intno, RMREGS *in, RMREGS *out) +{ + _RMREGS rmregs; + union REGS r; + struct SREGS sr; + + memset(&rmregs,0,sizeof(rmregs)); + rmregs.eax = in->x.ax; rmregs.ebx = in->x.bx; + rmregs.ecx = in->x.cx; rmregs.edx = in->x.dx; + rmregs.esi = in->x.si; rmregs.edi = in->x.di; + + segread(&sr); + r.w.ax = 0x300; r.h.bl = intno; r.h.bh = 0; r.w.cx = 0; sr.es = sr.ds; + r.x.edi = (unsigned)&rmregs; + backupsegs(); int386x(0x31,&r,&r,&sr); restoresegs(); + + out->x.ax = rmregs.eax; out->x.bx = rmregs.ebx; + out->x.cx = rmregs.ecx; out->x.dx = rmregs.edx; + out->x.si = rmregs.esi; out->x.di = rmregs.edi; + out->x.cflag = rmregs.flags&1; + return(out->x.ax); +} + +long DPMI_int86x(long intno, RMREGS *in, RMREGS *out, RMSREGS *sregs) +{ + _RMREGS rmregs; + union REGS r; + struct SREGS sr; + + memset(&rmregs, 0, sizeof(rmregs)); + rmregs.eax = in->x.ax; rmregs.ebx = in->x.bx; + rmregs.ecx = in->x.cx; rmregs.edx = in->x.dx; + rmregs.esi = in->x.si; rmregs.edi = in->x.di; + rmregs.es = sregs->es; + rmregs.ds = sregs->ds; + + segread(&sr); + r.w.ax = 0x300; r.h.bl = intno; r.h.bh = 0; r.w.cx = 0; sr.es = sr.ds; + r.x.edi = (unsigned)&rmregs; + backupsegs(); int386x(0x31,&r,&r,&sr); restoresegs(); + + out->x.ax = rmregs.eax; out->x.bx = rmregs.ebx; + out->x.cx = rmregs.ecx; out->x.dx = rmregs.edx; + out->x.si = rmregs.esi; out->x.di = rmregs.edi; + sregs->es = rmregs.es; sregs->cs = rmregs.cs; + sregs->ss = rmregs.ss; sregs->ds = rmregs.ds; + out->x.cflag = rmregs.flags&1; + return(out->x.ax); +} + +static void ExitVBEBuf(void) +{ + union REGS r; + r.w.ax = 0x101; r.w.dx = VESABuf_sel; //DPMI free real seg + backupsegs(); int386(0x31,&r,&r); restoresegs(); +} + +void VBE_callESDI(RMREGS *regs, void *buffer, long size) +{ + RMSREGS sregs; + union REGS r; + + if (!VESABuf_sel) //Init Real mode buffer + { + r.w.ax = 0x100; r.w.bx = 1024>>4; + backupsegs(); int386(0x31,&r,&r); restoresegs(); + if (r.w.cflag) { printf("DPMI_allocRealSeg failed!\n"); exit(0); } + VESABuf_sel = r.w.dx; + VESABuf_rseg = r.w.ax; + atexit(ExitVBEBuf); + } + sregs.es = VESABuf_rseg; + regs->x.di = 0; + _fmemcpy(MK_FP(VESABuf_sel,0),buffer,size); + DPMI_int86x(0x10,regs,regs,&sregs); + _fmemcpy(buffer,MK_FP(VESABuf_sel,0),size); +} + +long VBE_getModeInfo(long mode, VBE_modeInfo *modeInfo) +{ + RMREGS regs; + + regs.x.ax = 0x4f01; + regs.x.cx = mode; + VBE_callESDI(®s, modeInfo, sizeof(VBE_modeInfo)); + if (regs.x.ax != 0x004f) return(0); + if ((modeInfo->ModeAttributes&1) == 0) return(0); //1 is vbeMdAvailable + return(1); +} + +GetPtrToLFB(long physAddr) +{ + #define LIMIT (4096*1024)-1 + long sel; + union REGS r; + + r.w.ax = 0; r.w.cx = 1; + backupsegs(); int386(0x31,&r,&r); restoresegs(); + if (r.x.cflag) { printf("DPMI_allocSelector() failed!\n"); exit(0); } + sel = r.w.ax; + r.w.ax = 9; r.w.bx = sel; r.w.cx = 0x8092; + backupsegs(); int386(0x31,&r,&r); restoresegs(); + + r.w.ax = 0x800; r.w.bx = physAddr >> 16; r.w.cx = physAddr & 0xffff; + r.w.si = LIMIT>>16; r.w.di = LIMIT&0xffff; + backupsegs(); int386(0x31,&r,&r); restoresegs(); + if (r.x.cflag) { printf("DPMI_mapPhysicalToLinear() failed!\n"); exit(0); } + backlinaddress = globlinplace = ((long)r.w.bx<<16)+r.w.cx; + + r.w.ax = 7; r.w.bx = sel; + r.w.cx = globlinplace>>16; r.w.dx = globlinplace&0xffff; + backupsegs(); int386(0x31,&r,&r); restoresegs(); + if (r.x.cflag) { printf("DPMI_setSelectorBase() failed!\n"); exit(0); } + + r.w.ax = 8; r.w.bx = sel; + r.w.cx = LIMIT>>16; r.w.dx = LIMIT&0xffff; + backupsegs(); int386(0x31,&r,&r); restoresegs(); + if (r.x.cflag) { printf("DPMI_setSelectorLimit() failed!\n"); exit(0); } +} + +void getvalidvesamodes(void) +{ + long i, j, k; + short *p, *p2; + VBE_modeInfo modeInfo; + RMREGS regs; + + if (vesachecked) return; + vesachecked = 1; + + validmodecnt = 0; + modelist[0] = -1; + + strncpy(vgaInfo.VESASignature,"VBE2",4); + regs.x.ax = 0x4f00; + VBE_callESDI(®s,&vgaInfo,sizeof(VBE_vgaInfo)); + if ((regs.x.ax != 0x004f) || (strncmp(vgaInfo.VESASignature,"VESA",4))) + return; + + //if (vgaInfo.VESAVersion < 0x200) return; + + //LfbMapRealPointer + p = (short *)(((vgaInfo.VideoModePtr&0xffff0000)>>12)+((vgaInfo.VideoModePtr)&0xffff)); + p2 = modelist; + while (*p != -1) *p2++ = *p++; + *p2 = -1; + + for(p=modelist;*p!=-1;p++) + { + regs.x.ax = 0x4f01; regs.x.cx = *p; + VBE_callESDI(®s,&modeInfo,sizeof(VBE_modeInfo)); + if (regs.x.ax != 0x004f) continue; + if (!(modeInfo.ModeAttributes&1)) continue; //1 is vbeMdAvailable + if (modeInfo.MemoryModel != 4) continue; //4 is vbeMemPK + if (modeInfo.BitsPerPixel != 8) continue; + if (modeInfo.NumberOfPlanes != 1) continue; + + validmode[validmodecnt] = *p; + validmodexdim[validmodecnt] = modeInfo.XResolution; + validmodeydim[validmodecnt] = modeInfo.YResolution; + validmodecnt++; + } + + for(i=1;i= 2)) + { + buffermode = 0; + imageSize = 65536; + frameplace = 0xa0000; + } + else + { + buffermode = 1; + imageSize = bytesperline*yres; + frameplace = FP_OFF(screen); + maxpages = 1; + } + } + + origbuffermode = buffermode; + + j = 0; + for(i=0;i= y2) + { + while (y1 < y2-1) + { + y1++; if ((y1&31) == 0) faketimerhandler(); + //x,y1 + i = p+ylookup[y1]+ves2lastx[y1]; + copybufbyte((void *)i,(void *)(i+delta),x-ves2lastx[y1]); + } + y1 = ny1; + } + else + { + while (y1 < ny1) + { + y1++; if ((y1&31) == 0) faketimerhandler(); + //x-1,y1 + i = p+ylookup[y1]+ves2lastx[y1]; + copybufbyte((void *)i,(void *)(i+delta),x-ves2lastx[y1]); + } + while (y1 > ny1) ves2lastx[y1--] = x; + } + while (y2 > ny2) + { + y2--; if ((y2&31) == 0) faketimerhandler(); + //x-1,y2 + i = p+ylookup[y2]+ves2lastx[y2]; + copybufbyte((void *)i,(void *)(i+delta),x-ves2lastx[y2]); + } + while (y2 < ny2) ves2lastx[y2++] = x; + } + else + { + while (y1 < y2-1) + { + y1++; if ((y1&31) == 0) faketimerhandler(); + //x-1,y1 + i = p+ylookup[y1]+ves2lastx[y1]; + copybufbyte((void *)i,(void *)(i+delta),x-ves2lastx[y1]); + } + if (x == cx2) break; + y1 = startumost[x+1]; y2 = y1; + } + } + while (y1 < y2-1) + { + y1++; if ((y1&31) == 0) faketimerhandler(); + //cx2+1,y1 + i = p+ylookup[y1]+ves2lastx[y1]; + copybufbyte((void *)i,(void *)(i+delta),cx2+1-ves2lastx[y1]); + } + } + else + { + p += ylookup[cy1]+cx1; + delta = activepagelookup[dapagenum&0x7fffffff]-FP_OFF(screen); + for(y=cy1;y<=cy2;y++) + { + copybufbyte((void *)p,(void *)(p+delta),dx); + p += ylookup[1]; + if ((y&31) == 0) faketimerhandler(); + } + } + } + else + { + p = ylookup[cy1]+cx1; + for(y=cy1;y<=cy2;y++) + { + if ((p>>16) != curpag) + { + curpag = (p>>16); + + setvesapage(curpag<>16); + setvesapage(curpag<= 0) qlimitrate(); + vesasetvisual(0x4f07,0L,i>>2,i>>18); + } + else + { vesasetvisual(0x4f07,0x80,i>>2,i>>18); } + + } + else + { + regs.x.ax = 0x4f07; + regs.x.cx = visualpagelookup[dapagenum&0x7fffffff][0]; //X-coordinate + regs.x.dx = visualpagelookup[dapagenum&0x7fffffff][1]; //Y-coordinate + if (vgacompatible) + { + regs.x.bx = 0; + if (dapagenum >= 0) qlimitrate(); + DPMI_int86(0x10,®s,®s); + } + else + { regs.x.bx = 0x80; DPMI_int86(0x10,®s,®s); } + } + if (dapagenum >= 0) faketimerhandler(); + } +} + +void uninitvesa(void) +{ + if (backlinaddress) + { + union REGS r; + r.w.ax = 0x801; + r.w.bx = (backlinaddress >> 16); + r.w.cx = (backlinaddress & 0xffff); + backupsegs(); int386(0x31,&r,&r); restoresegs(); + if (r.x.cflag) { printf("Free Physical Address failed!\n"); } + backlinaddress = 0; + } + VESABuf_sel = 0; + vesachecked = 0; +} + +#if 0 // doesn't appear to be used anymore. --ryan. +#pragma aux setpalettequick =\ + "mov edx, 0x3c8",\ + "out dx, al",\ + "inc edx",\ + "lea ecx, [ecx+ecx*2]",\ + "cld",\ + "rep outsb",\ + parm [eax][ecx][esi]\ + modify exact [ecx edx esi] +#endif + +int VBE_setPalette(long start, long num, char *dapal) +{ + RMREGS regs; + long i, j, k; + char palquick[768]; + + if (stereomode == 1) + { + if ((unsigned)((blackband&255)-start) < (unsigned)num) + { + dapal[(((blackband&255)-start)<<2)+0] = 0; + dapal[(((blackband&255)-start)<<2)+1] = 0; + dapal[(((blackband&255)-start)<<2)+2] = 0; + } + if ((unsigned)((whiteband&255)-start) < (unsigned)num) + { + dapal[(((whiteband&255)-start)<<2)+0] = 255; + dapal[(((whiteband&255)-start)<<2)+1] = 255; + dapal[(((whiteband&255)-start)<<2)+2] = 255; + } + } + if ((vgacompatible) || (vgaInfo.VESAVersion < 0x200) || (vidoption != 1)) + { + j = 0; k = (start<<2); + for(i=0;i>1);i>0;i--) + { + koutp(0x3c9,(long) dapal[2]); + while (kinp(0x3da)&1); while (!(kinp(0x3da)&1)); + koutp(0x3c9,(long) dapal[1]); koutp(0x3c9,(long) dapal[0]); + koutp(0x3c9,(long) dapal[6]); koutp(0x3c9,(long) dapal[5]); koutp(0x3c9,(long) dapal[4]); + dapal += 8; + } + if (num&1) + { + koutp(0x3c9,(long) dapal[2]); + while (kinp(0x3da)&1); while (!(kinp(0x3da)&1)); + koutp(0x3c9,(long) dapal[1]); koutp(0x3c9,(long) dapal[0]); + } + return(1); + } + + if (setpaletteentry) + { + i = (vesasetpalette(0x4f09,(vgaInfo.Capabilities&4)<<5, + num,start,0L,dapal)&65535); + } + else + { + regs.x.ax = 0x4f09; regs.h.bl = ((vgaInfo.Capabilities&4)<<5); + regs.x.cx = num; regs.x.dx = start; + VBE_callESDI(®s,dapal,sizeof(dapal)*num); + i = regs.x.ax; + } + if (i != 0x004f) return(0); + return(1); +} + +VBE_getPalette(long start, long num, char *dapal) +{ + RMREGS regs; + long i; + + if ((vgacompatible) || (vgaInfo.VESAVersion < 0x200) || (vidoption != 1)) + { + koutp(0x3c7,start); + for(i=num;i>0;i--) + { + dapal[2] = (char) kinp(0x3c9); + dapal[1] = (char) kinp(0x3c9); + dapal[0] = (char) kinp(0x3c9); + dapal += 4; + } + return(1); + } + + regs.x.ax = 0x4f09; regs.h.bl = 1; + regs.x.cx = num; regs.x.dx = start; + VBE_callESDI(®s,dapal,sizeof(dapal)*num); + i = regs.x.ax; + if (i != 0x004f) return(0); + return(1); +} + +#endif // _INCLUDE_VES2_H_ + +// end of ves2.h ... + + diff --git a/buildengine/win32_compat.h b/buildengine/win32_compat.h new file mode 100755 index 0000000..397c79d --- /dev/null +++ b/buildengine/win32_compat.h @@ -0,0 +1,138 @@ +/* + * win32 compatibility header. Takes care of some legacy code issues + * and incompatibilities at the source level. + * + * Written by Ryan C. Gordon (icculus@clutteredmind.org) + * + * Please do NOT harrass Ken Silverman about any code modifications + * (including this file) to BUILD. + */ + +/* + * "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman + * Ken Silverman's official web site: "http://www.advsys.net/ken" + * See the included license file "BUILDLIC.TXT" for license info. + * This file IS NOT A PART OF Ken Silverman's original release + */ + +#ifndef _INCLUDE_WIN32_COMPAT_H_ +#define _INCLUDE_WIN32_COMPAT_H_ + +#if (!defined PLATFORM_WIN32) +#error PLATFORM_WIN32 is not defined. +#endif + +#define PLATFORM_SUPPORTS_SDL + +#include + +#if (!defined _MSC_VER) +#include +#endif + +#include +#include +#include +#include +#include +#include + +extern const int hbits[]; /* !!! what is this, and why is it here? */ + +/* + Do some bitwise magic to approximate an algebraic (sign preserving) + right shift. + */ +#define shift_algebraic_right(value,distance) \ +(((value) >> (distance))| \ + (hbits[(distance) + (((value) & 0x80000000) >> 26)])) + +/* !!! remove me later! */ +/* !!! remove me later! */ +/* !!! remove me later! */ +#define outpw(x, y) printf("outpw(0x%X, 0x%X) call in %s, line %d.\n", \ + (x), (y), __FILE__, __LINE__) + +#define koutpw(x, y) printf("koutpw(0x%X, 0x%X) call in %s, line %d.\n", \ + (x), (y), __FILE__, __LINE__) + +#define outb(x, y) printf("outb(0x%X, 0x%X) call in %s, line %d.\n", \ + (x), (y), __FILE__, __LINE__) + +#define koutb(x, y) printf("koutb(0x%X, 0x%X) call in %s, line %d.\n", \ + (x), (y), __FILE__, __LINE__) + +#define outp(x, y) printf("outp(0x%X, 0x%X) call in %s, line %d.\n", \ + (x), (y), __FILE__, __LINE__) + +#define koutp(x, y) printf("koutp(0x%X, 0x%X) call in %s, line %d.\n", \ + (x), (y), __FILE__, __LINE__) + +#define kinp(x) _kinp_handler((x), __FILE__, __LINE__) +#define inp(x) _inp_handler((x), __FILE__, __LINE__) + +int _inp_handler(int port, char *source_file, int source_line); +int _kinp_handler(int port, char *source_file, int source_line); +/* !!! remove me later! */ +/* !!! remove me later! */ +/* !!! remove me later! */ + + +#define __far +#define __interrupt +#define interrupt +#define far +#define kmalloc(x) malloc(x) +#define kkmalloc(x) malloc(x) +#define kfree(x) free(x) +#define kkfree(x) free(x) + +#ifdef FP_OFF +#undef FP_OFF +#endif + +#define FP_OFF(x) ((long) (x)) + +/* !!! This might be temporary. */ +#define printext16 printext256 +#define printext16_noupdate printext256_noupdate + +#ifndef max +#define max(x, y) (((x) > (y)) ? (x) : (y)) +#endif + +#ifndef min +#define min(x, y) (((x) < (y)) ? (x) : (y)) +#endif + +#if (defined __WATCOMC__) +#define inline +#pragma intrinsic(min); +#pragma intrinsic(max); +#define __int64 long long +#endif + +#if (defined _MSC_VER) +#if ((!defined _INTEGRAL_MAX_BITS) || (_INTEGRAL_MAX_BITS < 64)) +#error __int64 type not supported +#endif + +#define open _open +#define O_BINARY _O_BINARY +#define O_RDONLY _O_RDONLY +#define O_WRONLY _O_WRONLY +#define O_RDWR _O_RDWR +#define O_TRUNC _O_TRUNC +#define O_CREAT _O_CREAT +#define S_IREAD _S_IREAD +#define S_IWRITE _S_IWRITE +#define S_IRDWR _S_IRDWR +#endif /* defined _MSC_VER */ + +#define snprintf _snprintf +#endif + +/* end of win32_compat.h ... */ + + + diff --git a/config.c b/config.c new file mode 100755 index 0000000..ef680f6 --- /dev/null +++ b/config.c @@ -0,0 +1,811 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment + +This file is part of Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Original Source: 1996 - Todd Replogle +Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms +*/ +//------------------------------------------------------------------------- + +#if PLATFORM_DOS +#include +#include +#endif + +/* this should be a proper prototype included from a header file */ +extern int stricmp(const char *x, const char *y); + +#include +#include +#include +#include +#include +#include "duke3d.h" +#include "scriplib.h" + + +// we load this in to get default button and key assignments +// as well as setting up function mappings + +#include "_functio.h" + +// +// Sound variables +// +int32 FXDevice; +int32 MusicDevice; +int32 FXVolume; +int32 MusicVolume; +int32 SoundToggle; +int32 MusicToggle; +int32 VoiceToggle; +int32 AmbienceToggle; +fx_blaster_config BlasterConfig; +int32 NumVoices; +int32 NumChannels; +int32 NumBits; +int32 MixRate; +int32 MidiPort; +int32 ReverseStereo; + +int32 ControllerType; +int32 MouseAiming; + +// +// Screen variables +// + +int32 ScreenMode; +int32 ScreenWidth; +int32 ScreenHeight; + +static char setupfilename[128]; +static int32 scripthandle; +static int32 setupread=0; +/* +=================== += += CONFIG_GetSetupFilename += +=================== +*/ +#define MAXSETUPFILES 20 +void CONFIG_GetSetupFilename( void ) + { + // this isn't hooked up to read from stdin, so skip it on Unix for now. --ryan. +#if PLATFORM_UNIX + GetPathFromEnvironment(setupfilename, 128, SETUPFILENAME); +#else + struct find_t fblock; + char extension[10]; + char * src; + char * filenames[MAXSETUPFILES]; + clock_t time; + int32 numfiles; + int32 i; + + GetPathFromEnvironment(setupfilename, 128, SETUPFILENAME); + + // determine extension + + src = setupfilename + strlen(setupfilename) - 1; + + while (*src != '.') + { + src--; + } + strcpy (&extension[1],src); + extension[0] = '*'; + + numfiles=0; + if (_dos_findfirst(extension,0,&fblock)==0) + { + do + { + // skip timidity.cfg if it exists; it's needed for MIDI playback + // with SDL_mixer, and isn't a Duke configuration file. --ryan. + if (strcmpi(fblock.name, "timidity.cfg") != 0) + { + filenames[numfiles]=SafeMalloc(128); + strcpy(filenames[numfiles],fblock.name); + numfiles++; + if (numfiles == MAXSETUPFILES) + break; + } + } + while(!_dos_findnext(&fblock)); + } + i = CheckParm (SETUPNAMEPARM); + if (i!=0) + { + numfiles = 0; + strcpy(setupfilename,_argv[i+1]); + } + if (numfiles>1) + { + clock_t oldtime; + int32 count; + + printf("\nMultiple Configuration Files Encountered\n"); + printf("========================================\n"); + printf("Please choose a configuration file from the following list by pressing its\n"); + printf("corresponding letter:\n"); + for (i=0;i\n",'a'+(char)i,filenames[i]); + } + } + printf("\n"); + printf("(%s will be used if no selection is made within 10 seconds.)\n\n",SETUPFILENAME); + KB_FlushKeyboardQueue(); + KB_ClearKeysDown(); + count = 9; + oldtime = clock(); + time=clock()+(10*CLOCKS_PER_SEC); + while (clock()oldtime) + { + printf("%ld seconds left. \r",count); + fflush(stdout); + oldtime = clock()+CLOCKS_PER_SEC; + count--; + } + if (KB_KeyWaiting()) + { + int32 ch = KB_Getch(); + ch -='a'; + if (ch>=0 && ch= MAXMOUSEBUTTONS) + return; + + MouseMapping[whichbutton] = whichfunction; +} + +void CONTROL_MapJoyButton(int32 whichfunction, int32 whichbutton, boolean doubleclicked) +{ + if(whichbutton < 0 || whichbutton >= MAXJOYBUTTONS) + { + return; + } + + if(doubleclicked) + return; // TODO + + JoyButtonMapping[whichbutton] = whichfunction; +} + +void CONTROL_MapJoyHat(int32 whichfunction, int32 whichhat, int32 whichvalue) +{ + if(whichhat < 0 || whichhat >= MAXJOYHATS) + { + return; + } + + JoyHatMapping[whichhat][whichvalue] = whichfunction; +} + +void CONTROL_DefineFlag( int32 which, boolean toggle ) +{ + // STUBBED("CONTROL_DefineFlag"); +} + +boolean CONTROL_FlagActive( int32 which ) +{ + STUBBED("CONTROL_FlagActive"); + return false; +} + +void CONTROL_ClearAssignments( void ) +{ + STUBBED("CONTROL_ClearAssignments"); +} + +void CONTROL_GetUserInput( UserInput *info ) +{ + STUBBED("CONTROL_GetUserInput"); +} + +void CONTROL_GetInput( ControlInfo *info ) +{ + int32 sens = CONTROL_GetMouseSensitivity() >> 9; + int32 mx, my; + int i, j; + memset(info, '\0', sizeof (ControlInfo)); + + mx = my = 0; + + MOUSE_GetDelta(&mx,&my); + + info->dyaw = mx * sens; + + switch(ControllerType) + { + case controltype_keyboardandjoystick: + { + } + break; + case controltype_joystickandmouse: + { + // Mouse should use pitch instead of forward movement. + info->dpitch = my * sens*2; + } + break; + default: + { + // If mouse aim is active + if( myaimmode ) + { + info->dpitch = my * sens*2; + } + else + { + info->dz = my * sens*2; + } + } + break; + } + + // TODO: releasing the mouse button does not honor if a keyboard key with + // the same function is still pressed. how should it? + for(i=0; idyaw += (int32)((float)CONTROL_FilterDeadzone + ( + _joystick_axis(i), + JoyAnalogDeadzone[i] + ) + * JoyAnalogScale[i] + ); + } + break; + case analog_strafing: + { + info->dx += (int32)((float)CONTROL_FilterDeadzone + ( + _joystick_axis(i), + JoyAnalogDeadzone[i] + ) + * JoyAnalogScale[i] + ); + //printf("Joy %d = %d\n", i, info->dx); + } + break; + case analog_lookingupanddown: + info->dpitch += (int32)((float)CONTROL_FilterDeadzone + ( + _joystick_axis(i), + JoyAnalogDeadzone[i] + ) + * JoyAnalogScale[i] + ); + break; + case analog_elevation: //STUB + break; + case analog_rolling: //STUB + break; + case analog_moving: + { + info->dz += (int32)((float)CONTROL_FilterDeadzone + ( + _joystick_axis(i), + JoyAnalogDeadzone[i] + ) + * JoyAnalogScale[i] + ); + } + break; + default: + break; + } + } + for(i=0; i -axisdeadzone)) + { + return 0; + } + + return axisvalue; +} + +int32 CONTROL_GetFilteredAxisValue(int32 axis) +{ +return (int32)((float)CONTROL_FilterDeadzone + ( + _joystick_axis(axis), + JoyAnalogDeadzone[axis] + ) + * JoyAnalogScale[axis] + ); +} + +void CONTROL_PrintAxes( void ) +{ + STUBBED("CONTROL_PrintAxes"); +} + +boolean MOUSE_Init( void ) +{ + memset(MouseMapping,-1,sizeof(MouseMapping)); + return true; +} + +void MOUSE_Shutdown( void ) +{ + STUBBED("MOUSE_Shutdown"); +} + +void MOUSE_ShowCursor( void ) +{ + STUBBED("MOUSE_ShowCursor"); +} + +void MOUSE_HideCursor( void ) +{ + STUBBED("MOUSE_HideCursor"); +} + +static int32 mousePositionX = 0; +static int32 mousePositionY = 0; +static int32 mouseRelativeX = 0; +static int32 mouseRelativeY = 0; + +static void updateMouse(void) +{ + // this is in buildengine. + short x, y; + getmousevalues(&x, &y, &mouseButtons); + + mouseRelativeX += x; + mouseRelativeY += y; + mousePositionX += x; + mousePositionY += y; +} + +int32 MOUSE_GetButtons( void ) +{ + updateMouse(); + return ((int32) mouseButtons); +} + +void MOUSE_GetPosition( int32*x, int32*y ) +{ + if (x) *x = mousePositionX; + if (y) *y = mousePositionY; +} + +void MOUSE_GetDelta( int32*x, int32*y ) +{ + updateMouse(); + + if (x) *x = mouseRelativeX; + if (y) *y = mouseRelativeY; + + mouseRelativeX = mouseRelativeY = 0; +} + +void JOYSTICK_UpdateHats() +{ + int i; + + for(i=0; i31) ? \ + ((CONTROL_ButtonState2>>( (x) - 32) ) & 1) :\ + ((CONTROL_ButtonState1>> (x) ) & 1) \ + ) +#define BUTTONHELD(x) \ + ( \ + ((x)>31) ? \ + ((CONTROL_ButtonHeldState2>>((x)-32)) & 1) :\ + ((CONTROL_ButtonHeldState1>>(x)) & 1)\ + ) +#define BUTTONJUSTPRESSED(x) \ + ( BUTTON( x ) && !BUTTONHELD( x ) ) +#define BUTTONRELEASED(x) \ + ( !BUTTON( x ) && BUTTONHELD( x ) ) +#define BUTTONSTATECHANGED(x) \ + ( BUTTON( x ) != BUTTONHELD( x ) ) + +//*************************************************************************** +// +// TYPEDEFS +// +//*************************************************************************** +typedef enum + { + axis_up, + axis_down, + axis_left, + axis_right + } axisdirection; + +typedef enum + { + analog_turning=0, + analog_strafing=1, + analog_lookingupanddown=2, + analog_elevation=3, + analog_rolling=4, + analog_moving=5, + analog_maxtype + } analogcontrol; + +typedef enum + { + dir_North, + dir_NorthEast, + dir_East, + dir_SouthEast, + dir_South, + dir_SouthWest, + dir_West, + dir_NorthWest, + dir_None + } direction; + +typedef struct + { + boolean button0; + boolean button1; + direction dir; + } UserInput; + +typedef struct + { + fixed dx; + fixed dy; + fixed dz; + fixed dyaw; + fixed dpitch; + fixed droll; + } ControlInfo; + +typedef enum + { + controltype_keyboard, + controltype_keyboardandmouse, + controltype_keyboardandjoystick, + controltype_keyboardandexternal, + controltype_keyboardandgamepad, + controltype_keyboardandflightstick, + controltype_keyboardandthrustmaster, + controltype_joystickandmouse + } controltype; + + +//*************************************************************************** +// +// GLOBALS +// +//*************************************************************************** + +extern boolean CONTROL_RudderEnabled; +extern boolean CONTROL_MousePresent; +extern boolean CONTROL_JoysPresent[ MaxJoys ]; +extern boolean CONTROL_MouseEnabled; +extern boolean CONTROL_JoystickEnabled; +extern byte CONTROL_JoystickPort; +extern uint32 CONTROL_ButtonState1; +extern uint32 CONTROL_ButtonHeldState1; +extern uint32 CONTROL_ButtonState2; +extern uint32 CONTROL_ButtonHeldState2; + + +//*************************************************************************** +// +// PROTOTYPES +// +//*************************************************************************** + +void CONTROL_MapKey( int32 which, kb_scancode key1, kb_scancode key2 ); +void CONTROL_MapButton + ( + int32 whichfunction, + int32 whichbutton, + boolean doubleclicked + ); +void CONTROL_MapJoyButton(int32 whichfunction, int32 whichbutton, boolean doubleclicked); +void CONTROL_MapJoyHat(int32 whichfunction, int32 whichhat, int32 whichvalue); +void CONTROL_DefineFlag( int32 which, boolean toggle ); +boolean CONTROL_FlagActive( int32 which ); +void CONTROL_ClearAssignments( void ); +void CONTROL_GetUserInput( UserInput *info ); +void CONTROL_GetInput( ControlInfo *info ); +void CONTROL_ClearButton( int32 whichbutton ); +void CONTROL_ClearUserInput( UserInput *info ); +void CONTROL_WaitRelease( void ); +void CONTROL_Ack( void ); +void CONTROL_CenterJoystick + ( + void ( *CenterCenter )( void ), + void ( *UpperLeft )( void ), + void ( *LowerRight )( void ), + void ( *CenterThrottle )( void ), + void ( *CenterRudder )( void ) + ); +int32 CONTROL_GetMouseSensitivity( void ); +void CONTROL_SetMouseSensitivity( int32 newsensitivity ); +void CONTROL_Startup + ( + controltype which, + int32 ( *TimeFunction )( void ), + int32 ticspersecond + ); +void CONTROL_Shutdown( void ); + +void CONTROL_MapAnalogAxis + ( + int32 whichaxis, + int32 whichanalog + ); + +void CONTROL_MapDigitalAxis + ( + int32 whichaxis, + int32 whichfunction, + int32 direction + ); +void CONTROL_SetAnalogAxisScale + ( + int32 whichaxis, + float axisscale + ); +void CONTROL_SetAnalogAxisDeadzone + ( + int32 whichaxis, + int32 axisdeadzone + ); +int32 CONTROL_FilterDeadzone + ( + int32 axisvalue, + int32 axisdeadzone + ); +int32 CONTROL_GetFilteredAxisValue(int32 axis); +void CONTROL_PrintAxes( void ); + +void CONTROL_UpdateKeyboardState(int key, int pressed); + +const char *CONTROL_GetMappingName(int32 which); + +#ifdef __cplusplus +}; +#endif +#endif diff --git a/develop.h b/develop.h new file mode 100755 index 0000000..b652a53 --- /dev/null +++ b/develop.h @@ -0,0 +1,65 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment + +This file is part of Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Original Source: 1996 - Todd Replogle +Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms +*/ +//------------------------------------------------------------------------- + +#ifndef _develop_public +#define _develop_public +#ifdef __cplusplus +extern "C" { +#endif + +#define DEVELOPMENT 0 +#define SHAREWARE 0 +#define LOCATIONINFO 1 +#define SOFTWAREERROR 1 +#define MEMORYCORRUPTIONTEST 1 +#define PRECACHETEST 0 +#define DATACORRUPTIONTEST 0 +#define RANDOMNUMBERTEST 0 + + +#if ( LOCATIONINFO == 1 ) + +#define funcstart() \ + { \ + SoftError( "funcstart : module '%s' at line %d.\n", __FILE__, __LINE__ );\ + } + +#define funcend() \ + { \ + SoftError( " funcend : module '%s' at line %d.\n", __FILE__, __LINE__ );\ + } + +#else + +#define funcstart() +#define funcend() + +#endif + +#ifdef __cplusplus +}; +#endif +#endif diff --git a/duke3d.dsp b/duke3d.dsp new file mode 100755 index 0000000..5c9e058 --- /dev/null +++ b/duke3d.dsp @@ -0,0 +1,339 @@ +# Microsoft Developer Studio Project File - Name="Duke3d" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=Duke3d - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "Duke3d.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "Duke3d.mak" CFG="Duke3d - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Duke3d - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "Duke3d - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "Perforce Project" +# PROP Scc_LocalPath "." +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Duke3d - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "ReleaseVC6" +# PROP Intermediate_Dir "ReleaseVC6" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /GX /Ot /Ow /Oi /Op /Oy /Ob1 /I "buildengine\SDL-1.2.5\include" /I "buildengine\SDL_mixer-1.2.5\include" /I ".\buildengine" /D "_CONSOLE" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "USE_I386_ASM" /D "PLATFORM_WIN32" /D "UDP_NETWORKING" /YX /J /FD /c +# ADD BASE RSC /l 0xc09 /d "NDEBUG" +# ADD RSC /l 0x409 /i "wsock32.lib" /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib sdl.lib sdl_mixer.lib /nologo /subsystem:console /machine:I386 /out:"./ReleaseVC6/Duke3d.exe" /libpath:"buildengine\SDL-1.2.5\lib" /libpath:"buildengine\SDL_mixer-1.2.5\lib" +# SUBTRACT LINK32 /debug + +!ELSEIF "$(CFG)" == "Duke3d - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "DebugVC6" +# PROP Intermediate_Dir "DebugVC6" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /Gm /GX /ZI /Od /I "buildengine\SDL-1.2.5\include" /I "buildengine\SDL_mixer-1.2.5\include" /I ".\buildengine" /D "_CONSOLE" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "USE_I386_ASM" /D "PLATFORM_WIN32" /D "UDP_NETWORKING" /FR /YX /J /FD /GZ /c +# ADD BASE RSC /l 0xc09 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib sdl.lib sdl_mixer.lib /nologo /subsystem:console /debug /machine:I386 /out:"./DebugVC6/Duke3d.exe" /pdbtype:sept /libpath:"buildengine\SDL-1.2.5\lib" /libpath:"buildengine\SDL_mixer-1.2.5\lib" + +!ENDIF + +# Begin Target + +# Name "Duke3d - Win32 Release" +# Name "Duke3d - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\actors.c +# End Source File +# Begin Source File + +SOURCE=.\animlib.c +# End Source File +# Begin Source File + +SOURCE=.\config.c +# End Source File +# Begin Source File + +SOURCE=.\control.c +# End Source File +# Begin Source File + +SOURCE=.\audiolib\dsl.c +# End Source File +# Begin Source File + +SOURCE=.\dukemusc.c +# End Source File +# Begin Source File + +SOURCE=.\audiolib\fx_man.c +# End Source File +# Begin Source File + +SOURCE=.\game.c +# End Source File +# Begin Source File + +SOURCE=.\gamedef.c +# End Source File +# Begin Source File + +SOURCE=.\global.c +# End Source File +# Begin Source File + +SOURCE=.\keyboard.c +# End Source File +# Begin Source File + +SOURCE=.\audiolib\ll_man.c +# End Source File +# Begin Source File + +SOURCE=.\menues.c +# End Source File +# Begin Source File + +SOURCE=.\audiolib\multivoc.c +# End Source File +# Begin Source File + +SOURCE=.\audiolib\mv_mix.c +# End Source File +# Begin Source File + +SOURCE=.\audiolib\mvreverb.c +# End Source File +# Begin Source File + +SOURCE=.\audiolib\nodpmi.c +# End Source File +# Begin Source File + +SOURCE=.\audiolib\pitch.c +# End Source File +# Begin Source File + +SOURCE=.\player.c +# End Source File +# Begin Source File + +SOURCE=.\premap.c +# End Source File +# Begin Source File + +SOURCE=.\rts.c +# End Source File +# Begin Source File + +SOURCE=.\scriplib.c +# End Source File +# Begin Source File + +SOURCE=.\sector.c +# End Source File +# Begin Source File + +SOURCE=.\sounds.c +# End Source File +# Begin Source File + +SOURCE=.\audiolib\user.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\_animlib.h +# End Source File +# Begin Source File + +SOURCE=.\_functio.h +# End Source File +# Begin Source File + +SOURCE=.\_rts.h +# End Source File +# Begin Source File + +SOURCE=.\animlib.h +# End Source File +# Begin Source File + +SOURCE=.\build.h +# End Source File +# Begin Source File + +SOURCE=.\config.h +# End Source File +# Begin Source File + +SOURCE=.\control.h +# End Source File +# Begin Source File + +SOURCE=.\develop.h +# End Source File +# Begin Source File + +SOURCE=.\audiolib\dsl.h +# End Source File +# Begin Source File + +SOURCE=.\duke3d.h +# End Source File +# Begin Source File + +SOURCE=.\dukeunix.h +# End Source File +# Begin Source File + +SOURCE=.\dukewin.h +# End Source File +# Begin Source File + +SOURCE=.\file_lib.h +# End Source File +# Begin Source File + +SOURCE=.\funct.h +# End Source File +# Begin Source File + +SOURCE=.\function.h +# End Source File +# Begin Source File + +SOURCE=.\audiolib\fx_man.h +# End Source File +# Begin Source File + +SOURCE=.\fx_man.h +# End Source File +# Begin Source File + +SOURCE=.\gamedefs.h +# End Source File +# Begin Source File + +SOURCE=.\keyboard.h +# End Source File +# Begin Source File + +SOURCE=.\audiolib\ll_man.h +# End Source File +# Begin Source File + +SOURCE=.\mouse.h +# End Source File +# Begin Source File + +SOURCE=.\audiolib\multivoc.h +# End Source File +# Begin Source File + +SOURCE=.\music.h +# End Source File +# Begin Source File + +SOURCE=.\names.h +# End Source File +# Begin Source File + +SOURCE=.\audiolib\pitch.h +# End Source File +# Begin Source File + +SOURCE=.\pragmas.h +# End Source File +# Begin Source File + +SOURCE=.\rts.h +# End Source File +# Begin Source File + +SOURCE=.\scriplib.h +# End Source File +# Begin Source File + +SOURCE=.\sndcards.h +# End Source File +# Begin Source File + +SOURCE=.\soundefs.h +# End Source File +# Begin Source File + +SOURCE=.\sounds.h +# End Source File +# Begin Source File + +SOURCE=.\task_man.h +# End Source File +# Begin Source File + +SOURCE=.\types.h +# End Source File +# Begin Source File + +SOURCE=.\audiolib\user.h +# End Source File +# Begin Source File + +SOURCE=.\util_lib.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/duke3d.dsw b/duke3d.dsw new file mode 100755 index 0000000..c5baa29 --- /dev/null +++ b/duke3d.dsw @@ -0,0 +1,52 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "Duke3d"=.\Duke3d.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + Perforce Project + . + end source code control +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name Engine + End Project Dependency +}}} + +############################################################################### + +Project: "Engine"=.\buildengine\Engine.dsp - Package Owner=<4> + +Package=<5> +{{{ + begin source code control + Perforce Project + .\buildengine + end source code control +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/duke3d.h b/duke3d.h new file mode 100755 index 0000000..ae1c6a9 --- /dev/null +++ b/duke3d.h @@ -0,0 +1,614 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment + +This file is part of Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Original Source: 1996 - Todd Replogle +Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms +*/ +//------------------------------------------------------------------------- +#ifndef _INCL_DUKE3D_H_ +#define _INCL_DUKE3D_H_ + +#include +#include +#include + +#if !PLATFORM_MACOSX && !PLATFORM_FREEBSD +#include +#else +#include +#endif + +#include +#include +#include + +#if (!defined MAX_PATH) + #if (defined MAXPATHLEN) + #define MAX_PATH MAXPATHLEN + #elif (defined PATH_MAX) + #define MAX_PATH PATH_MAX + #else + #define MAX_PATH 256 + #endif +#endif + +#if PLATFORM_DOS +#include +#include +#include +#define PATH_SEP_CHAR '\\' +#define PATH_SEP_STR "\\" +#endif + +#if PLATFORM_UNIX +#include "dukeunix.h" +#endif + +#if PLATFORM_WIN32 +#include "dukewin.h" +#endif + +#ifndef GCC_PACK1_EXT +#define GCC_PACK1_EXT +#endif + +#if USE_SDL +#include "SDL.h" +#include "SDL_mixer.h" +#endif + +#include "buildengine/pragmas.h" +//#undef getch // quick hack +#include "buildengine/build.h" +#include "function.h" + +//#define VOLUMEALL +//#define PLUTOPAK +// #define VOLUMEONE +// #define ONELEVELDEMO + +// Make sure something is defined here (although this is usually +// handled in the makefile now). --ryan. +#if ((!defined VOLUMEALL) && (!defined VOLUMEONE)) +#define VOLUMEALL +#endif + +// Define plutopak if volumeall. --ryan. +#if (defined VOLUMEALL) +#define PLUTOPAK +#endif + +// #define TEN +// #define BETA + +// #define AUSTRALIA + +#define MAXSLEEPDIST 16384 +#define SLEEPTIME 24*64 + +#ifdef VOLUMEONE + #define BYTEVERSION 27 +#else + // 116 is Duke 1.4, 117 is 1.5. --ryan. + //#define BYTEVERSION 116 + #define BYTEVERSION 117 +#endif + +#define NUMPAGES 1 + +#define AUTO_AIM_ANGLE 48 +#define RECSYNCBUFSIZ 2520 //2520 is the (LCM of 1-8)*3 +#define MOVEFIFOSIZ 256 + +#define FOURSLEIGHT (1<<8) + +struct player_struct; + +#include "types.h" +#include "file_lib.h" +#include "develop.h" +#include "gamedefs.h" +#include "keyboard.h" +#include "util_lib.h" +#include "function.h" +#include "fx_man.h" +#include "config.h" +#include "sounds.h" +#include "control.h" +#include "_rts.h" +#include "rts.h" +#include "soundefs.h" + + +#include "task_man.h" +#include "music.h" +#include "sndcards.h" + +#include "names.h" + +#include "buildengine/engine.h" + +#define TICRATE (120) +#define TICSPERFRAME (TICRATE/26) + +// #define GC (TICSPERFRAME*44) + +#define NUM_SOUNDS 450 + +#define ALT_IS_PRESSED ( KB_KeyPressed( sc_RightAlt ) || KB_KeyPressed( sc_LeftAlt ) ) +#define SHIFTS_IS_PRESSED ( KB_KeyPressed( sc_RightShift ) || KB_KeyPressed( sc_LeftShift ) ) +#define RANDOMSCRAP EGS(s->sectnum,s->x+(TRAND&255)-128,s->y+(TRAND&255)-128,s->z-(8<<8)-(TRAND&8191),SCRAP6+(TRAND&15),-8,48,48,TRAND&2047,(TRAND&63)+64,-512-(TRAND&2047),i,5) + +#define BLACK 0 +#define DARKBLUE 1 +#define DARKGREEN 2 +#define DARKCYAN 3 +#define DARKRED 4 +#define DARKPURPLE 5 +#define BROWN 6 +#define LIGHTGRAY 7 + +#define DARKGRAY 8 +#define BLUE 9 +#define GREEN 10 +#define CYAN 11 +#define RED 12 +#define PURPLE 13 +#define YELLOW 14 +#define WHITE 15 + +#define PHEIGHT (38<<8) + +// #define P(X) printf("%ld\n",X); + +#define WAIT(X) ototalclock=totalclock+(X);while(totalclock=(B) && (PN)<=(E)) +#define KILLIT(KX) {deletesprite(KX);goto BOLT;} + + +#define IFMOVING if(ssp(i,CLIPMASK0)) +#define IFHIT j=ifhitbyweapon(i);if(j >= 0) +#define IFHITSECT j=ifhitsectors(s->sectnum);if(j >= 0) + +#define AFLAMABLE(X) (X==BOX||X==TREE1||X==TREE2||X==TIRE||X==CONE) + + +#define IFSKILL1 if(player_skill<1) +#define IFSKILL2 if(player_skill<2) +#define IFSKILL3 if(player_skill<3) +#define IFSKILL4 if(player_skill<4) + +#define rnd(X) ((TRAND>>8)>=(255-(X))) + +typedef struct +{ + short i; + int voice; +} SOUNDOWNER; + +#define __USRHOOKS_H + +enum USRHOOKS_Errors + { + USRHOOKS_Warning = -2, + USRHOOKS_Error = -1, + USRHOOKS_Ok = 0 + }; + +#if HAVE_PRAGMA_PACK +#pragma pack(push, 1) +#endif +typedef struct +{ + signed char avel GCC_PACK1_EXT; + signed char horz GCC_PACK1_EXT; + short fvel GCC_PACK1_EXT; + short svel GCC_PACK1_EXT; + unsigned long bits GCC_PACK1_EXT; +} input; +#if HAVE_PRAGMA_PACK +#pragma pack(pop) +#endif + +/* !!! FIXME: "sync" is defined in unistd.h ... :( --ryan. */ +#define sync duke_sync +extern input inputfifo[MOVEFIFOSIZ][MAXPLAYERS], sync[MAXPLAYERS]; +extern input recsync[RECSYNCBUFSIZ]; + +extern long movefifosendplc; + +typedef struct +{ + char *ptr; + volatile char lock; + int length, num; +} SAMPLE; + +struct animwalltype +{ + short wallnum; + long tag; +}; +extern struct animwalltype animwall[MAXANIMWALLS]; +extern short numanimwalls,probey,lastprobey; + +extern char *mymembuf; +extern char typebuflen,typebuf[41]; +extern char MusicPtr[72000]; +extern long msx[2048],msy[2048]; +extern short cyclers[MAXCYCLERS][6],numcyclers; +extern char myname[32]; + +struct user_defs +{ + char god,warp_on,cashman,eog,showallmap; + char show_help,scrollmode,clipping; + char user_name[MAXPLAYERS][32]; + char ridecule[10][40]; + char savegame[10][22]; + char pwlockout[128],rtsname[128]; + char overhead_on,last_overhead,showweapons; + + short pause_on,from_bonus; + short camerasprite,last_camsprite; + short last_level,secretlevel; + + long const_visibility,uw_framerate; + long camera_time,folfvel,folavel,folx,foly,fola; + long reccnt; + + int32 entered_name,screen_tilting,shadows,fta_on,executions,auto_run; + int32 coords,tickrate,m_coop,coop,screen_size,lockout,crosshair; + int32 wchoice[MAXPLAYERS][MAX_WEAPONS],playerai; + + int32 respawn_monsters,respawn_items,respawn_inventory,recstat,monsters_off,brightness; + int32 m_respawn_items,m_respawn_monsters,m_respawn_inventory,m_recstat,m_monsters_off,detail; + int32 m_ffire,ffire,m_player_skill,m_level_number,m_volume_number,multimode; + int32 player_skill,level_number,volume_number,m_marker,marker,mouseflip; + +}; + +struct player_orig +{ + long ox,oy,oz; + short oa,os; +}; + + +extern char numplayersprites; +extern char picsiz[MAXTILES]; + +void add_ammo( short, short, short, short ); + + +extern long fricxv,fricyv; + +struct player_struct +{ + long zoom,exitx,exity,loogiex[64],loogiey[64],numloogs,loogcnt; + long posx, posy, posz, horiz, ohoriz, ohorizoff, invdisptime; + long bobposx,bobposy,oposx,oposy,oposz,pyoff,opyoff; + long posxv,posyv,poszv,last_pissed_time,truefz,truecz; + long player_par,visibility; + long bobcounter,weapon_sway; + long pals_time,randomflamex,crack_time; + + int32 aim_mode; + + short ang,oang,angvel,cursectnum,look_ang,last_extra,subweapon; + short ammo_amount[MAX_WEAPONS],wackedbyactor,frag,fraggedself; + + short curr_weapon, last_weapon, tipincs, horizoff, wantweaponfire; + short holoduke_amount,newowner,hurt_delay,hbomb_hold_delay; + short jumping_counter,airleft,knee_incs,access_incs; + short fta,ftq,access_wallnum,access_spritenum; + short kickback_pic,got_access,weapon_ang,firstaid_amount; + short somethingonplayer,on_crane,i,one_parallax_sectnum; + short over_shoulder_on,random_club_frame,fist_incs; + short one_eighty_count,cheat_phase; + short dummyplayersprite,extra_extra8,quick_kick; + short heat_amount,actorsqu,timebeforeexit,customexitsound; + + short weaprecs[16],weapreccnt,interface_toggle_flag; + + short rotscrnang,dead_flag,show_empty_weapon; + short scuba_amount,jetpack_amount,steroids_amount,shield_amount; + short holoduke_on,pycount,weapon_pos,frag_ps; + short transporter_hold,last_full_weapon,footprintshade,boot_amount; + + int scream_voice; + + char gm,on_warping_sector,footprintcount; + char hbomb_on,jumping_toggle,rapid_fire_hold,on_ground; + char name[32],inven_icon,buttonpalette; + + char jetpack_on,spritebridge,lastrandomspot; + char scuba_on,footprintpal,heat_on; + + char holster_weapon,falling_counter; + char gotweapon[MAX_WEAPONS],refresh_inventory,*palette; + + char toggle_key_flag,knuckle_incs; // ,select_dir; + char walking_snd_toggle, palookup, hard_landing; + char max_secret_rooms,secret_rooms,/*fire_flag,*/pals[3]; + char max_actors_killed,actors_killed,return_to_center; +}; + +extern unsigned char tempbuf[2048], packbuf[576]; + +extern long gc,max_player_health,max_armour_amount,max_ammo_amount[MAX_WEAPONS]; + +extern long impact_damage,respawnactortime,respawnitemtime; + +#define MOVFIFOSIZ 256 + +extern short spriteq[1024],spriteqloc,spriteqamount; +extern struct player_struct ps[MAXPLAYERS]; +extern struct player_orig po[MAXPLAYERS]; +extern struct user_defs ud; + +// ported build engine has this, too. --ryan. +#if PLATFORM_DOS +extern short int moustat; +#endif + +extern short int global_random; +extern long scaredfallz; +extern char buf[80]; //My own generic input buffer + +extern char fta_quotes[NUMOFFIRSTTIMEACTIVE][64]; +extern char scantoasc[128],ready2send; +extern char scantoascwithshift[128]; + +extern fx_device device; +extern SAMPLE Sound[ NUM_SOUNDS ]; +extern int32 VoiceToggle,AmbienceToggle; +extern SOUNDOWNER SoundOwner[NUM_SOUNDS][4]; + +extern char playerreadyflag[MAXPLAYERS],playerquitflag[MAXPLAYERS]; +extern char sounds[NUM_SOUNDS][14]; + +extern long script[MAXSCRIPTSIZE],*scriptptr,*insptr,*labelcode,labelcnt; +extern char *label,*textptr,error,warning,killit_flag; +extern long *actorscrptr[MAXTILES],*parsing_actor; +extern char actortype[MAXTILES]; +extern char *music_pointer; + +extern char ipath[80],opath[80]; + +extern char music_fn[4][11][13],music_select; +extern char env_music_fn[4][13]; +extern short camsprite; + +// extern char gotz; +extern char inspace(short sectnum); + + +struct weaponhit +{ + char cgg; + short picnum,ang,extra,owner,movflag; + short tempang,actorstayput,dispicnum; + short timetosleep; + long floorz,ceilingz,lastvx,lastvy,bposx,bposy,bposz; + long temp_data[6]; +}; + +extern struct weaponhit hittype[MAXSPRITES]; + +extern input loc; +extern input recsync[RECSYNCBUFSIZ]; +extern long avgfvel, avgsvel, avgavel, avghorz, avgbits; + +extern short numplayers, myconnectindex; +extern short connecthead, connectpoint2[MAXPLAYERS]; //Player linked list variables (indeces, not connection numbers) +extern short screenpeek; + +extern int current_menu; +extern long tempwallptr,animatecnt; +extern long lockclock,frameplace; +extern char display_mirror,loadfromgrouponly,rtsplaying; + +extern long movefifoend[MAXPLAYERS], groupfile; +extern long ototalclock; + +extern long *animateptr[MAXANIMATES], animategoal[MAXANIMATES]; +extern long animatevel[MAXANIMATES]; +// extern long oanimateval[MAXANIMATES]; +extern short neartagsector, neartagwall, neartagsprite; +extern long neartaghitdist; +extern short animatesect[MAXANIMATES]; +extern long movefifoplc, vel,svel,angvel,horiz; + +extern short mirrorwall[64], mirrorsector[64], mirrorcnt; + +#define NUMKEYS 19 + +extern long frameplace, chainplace, chainnumpages; +extern volatile long checksume; + +#include "funct.h" +#include "buildengine/engine_protos.h" + +extern char screencapt; +extern short soundps[NUM_SOUNDS],soundpe[NUM_SOUNDS],soundvo[NUM_SOUNDS]; +extern char soundpr[NUM_SOUNDS],soundm[NUM_SOUNDS]; +extern long soundsiz[NUM_SOUNDS]; +extern char level_names[44][33]; +extern long partime[44],designertime[44]; +extern char volume_names[4][33]; +extern char skill_names[5][33]; +extern char level_file_names[44][128]; + +extern int32 SoundToggle,MusicToggle; +extern short last_threehundred,lastsavedpos; +extern char restorepalette; + +extern short buttonstat; +extern long cachecount; +extern char boardfilename[128],waterpal[768],slimepal[768],titlepal[768],drealms[768],endingpal[768]; +extern char betaname[80]; +extern char cachedebug,earthquaketime; +extern char networkmode; +extern char lumplockbyte[11]; + + //DUKE3D.H - replace the end "my's" with this +extern long myx, omyx, myxvel, myy, omyy, myyvel, myz, omyz, myzvel; +extern short myhoriz, omyhoriz, myhorizoff, omyhorizoff, globalskillsound; +extern short myang, omyang, mycursectnum, myjumpingcounter; +extern char myjumpingtoggle, myonground, myhardlanding,myreturntocenter; +extern long fakemovefifoplc; +extern long myxbak[MOVEFIFOSIZ], myybak[MOVEFIFOSIZ], myzbak[MOVEFIFOSIZ]; +extern long myhorizbak[MOVEFIFOSIZ]; +extern short myangbak[MOVEFIFOSIZ]; + +extern short weaponsandammosprites[15]; + + + + +//DUKE3D.H: +typedef struct +{ + short frag[MAXPLAYERS], got_access, last_extra, shield_amount, curr_weapon; + short ammo_amount[MAX_WEAPONS], holoduke_on; + char gotweapon[MAX_WEAPONS], inven_icon, jetpack_on, heat_on; + short firstaid_amount, steroids_amount, holoduke_amount, jetpack_amount; + short heat_amount, scuba_amount, boot_amount; + short last_weapon, weapon_pos, kickback_pic; + +} STATUSBARTYPE; + +extern STATUSBARTYPE sbar; +extern short frags[MAXPLAYERS][MAXPLAYERS]; +extern long cameradist, cameraclock, dukefriction,show_shareware; +extern char networkmode, movesperpacket; +extern char gamequit; + +extern char pus,pub,camerashitable,freezerhurtowner,lasermode; +extern char syncstat, syncval[MAXPLAYERS][MOVEFIFOSIZ]; +extern signed char multiwho, multipos, multiwhat, multiflag; +extern long syncvalhead[MAXPLAYERS], syncvaltail, syncvaltottail; +extern long numfreezebounces,rpgblastradius,pipebombblastradius,tripbombblastradius,shrinkerblastradius,morterblastradius,bouncemineblastradius,seenineblastradius; +// CTW - MODIFICATION +// extern char stereo,eightytwofifty,playerswhenstarted,playonten,everyothertime; +extern char stereo,eightytwofifty,playerswhenstarted,everyothertime; +// CTW END - MODIFICATION +extern long myminlag[MAXPLAYERS], mymaxlag, otherminlag, bufferjitter; + +extern long numinterpolations, startofdynamicinterpolations; +extern long oldipos[MAXINTERPOLATIONS]; +extern long bakipos[MAXINTERPOLATIONS]; +extern long *curipos[MAXINTERPOLATIONS]; + +extern short numclouds,clouds[128],cloudx[128],cloudy[128]; +extern long cloudtotalclock,totalmemory; + +extern long stereomode, stereowidth, stereopixelwidth; + +extern long myaimmode, myaimstat, omyaimstat; + +extern int32 dukever13; // indicate old version + +#endif // include-once header. + diff --git a/duke3d.sln b/duke3d.sln new file mode 100755 index 0000000..795b8b2 --- /dev/null +++ b/duke3d.sln @@ -0,0 +1,28 @@ +Microsoft Visual Studio Solution File, Format Version 7.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Duke3d", "Duke3d.vcproj", "{F83AC009-740D-4980-8B9B-E414E8CAE826}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Engine", "buildengine\Engine.vcproj", "{2960B59D-CA80-4C18-A4DD-038C38A4113B}" +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + ConfigName.0 = Debug + ConfigName.1 = Release + EndGlobalSection + GlobalSection(ProjectDependencies) = postSolution + {F83AC009-740D-4980-8B9B-E414E8CAE826}.0 = {2960B59D-CA80-4C18-A4DD-038C38A4113B} + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {F83AC009-740D-4980-8B9B-E414E8CAE826}.Debug.ActiveCfg = Debug|Win32 + {F83AC009-740D-4980-8B9B-E414E8CAE826}.Debug.Build.0 = Debug|Win32 + {F83AC009-740D-4980-8B9B-E414E8CAE826}.Release.ActiveCfg = Release|Win32 + {F83AC009-740D-4980-8B9B-E414E8CAE826}.Release.Build.0 = Release|Win32 + {2960B59D-CA80-4C18-A4DD-038C38A4113B}.Debug.ActiveCfg = Debug|Win32 + {2960B59D-CA80-4C18-A4DD-038C38A4113B}.Debug.Build.0 = Debug|Win32 + {2960B59D-CA80-4C18-A4DD-038C38A4113B}.Release.ActiveCfg = Release|Win32 + {2960B59D-CA80-4C18-A4DD-038C38A4113B}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/duke3d.vcproj b/duke3d.vcproj new file mode 100755 index 0000000..e14a716 --- /dev/null +++ b/duke3d.vcproj @@ -0,0 +1,325 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dukemusc.c b/dukemusc.c new file mode 100755 index 0000000..55b734f --- /dev/null +++ b/dukemusc.c @@ -0,0 +1,474 @@ +/* + * A reimplementation of Jim Dose's FX_MAN routines, using SDL_mixer 1.2. + * Whee. FX_MAN is also known as the "Apogee Sound System", or "ASS" for + * short. How strangely appropriate that seems. + * + * Written by Ryan C. Gordon. (icculus@clutteredmind.org) + */ + +#include +#include +#include +#include +#include + +#include "duke3d.h" +#include "buildengine/cache1d.h" + +#if PLATFORM_DOS +// Use the original Apogee Sound System libs instead. --ryan. +#error you probably should not compile this. +#endif + +#if (defined __WATCOMC__) +// This is probably out of date. --ryan. +#include "dukesnd_watcom.h" +#endif + +#if (!defined __WATCOMC__) +#define cdecl +#endif + +#include "SDL.h" +#include "SDL_mixer.h" +#ifdef ROTT +#include "rt_def.h" // ROTT music hack +#include "rt_cfg.h" // ROTT music hack +#include "rt_util.h" // ROTT music hack +#endif +#include "music.h" + +#define __FX_TRUE (1 == 1) +#define __FX_FALSE (!__FX_TRUE) + +#define DUKESND_DEBUG "DUKESND_DEBUG" + +#ifndef min +#define min(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +#ifndef max +#define max(a, b) (((a) > (b)) ? (a) : (b)) +#endif + +int MUSIC_ErrorCode = MUSIC_Ok; + +static char warningMessage[80]; +static char errorMessage[80]; +static int fx_initialized = 0; +static int numChannels = MIX_CHANNELS; +static void (*callback)(unsigned long); +static int reverseStereo = 0; +static int reverbDelay = 256; +static int reverbLevel = 0; +static int fastReverb = 0; +static FILE *debug_file = NULL; +static int initialized_debugging = 0; +static int mixerIsStereo = 1; + +// This gets called all over the place for information and debugging messages. +// If the user set the DUKESND_DEBUG environment variable, the messages +// go to the file that is specified in that variable. Otherwise, they +// are ignored for the expense of the function call. If DUKESND_DEBUG is +// set to "-" (without the quotes), then the output goes to stdout. +static void musdebug(const char *fmt, ...) +{ + va_list ap; + + if (debug_file) + { + fprintf(debug_file, "DUKEMUS: "); + va_start(ap, fmt); + vfprintf(debug_file, fmt, ap); + va_end(ap); + fprintf(debug_file, "\n"); + fflush(debug_file); + } // if +} // musdebug + +static void init_debugging(void) +{ + const char *envr; + + if (initialized_debugging) + return; + + envr = getenv(DUKESND_DEBUG); + if (envr != NULL) + { + if (strcmp(envr, "-") == 0) + debug_file = stdout; + else + debug_file = fopen(envr, "w"); + + if (debug_file == NULL) + fprintf(stderr, "DUKESND: -WARNING- Could not open debug file!\n"); + else + setbuf(debug_file, NULL); + } // if + + initialized_debugging = 1; +} // init_debugging + +static void setWarningMessage(const char *msg) +{ + strncpy(warningMessage, msg, sizeof (warningMessage)); + // strncpy() doesn't add the null char if there isn't room... + warningMessage[sizeof (warningMessage) - 1] = '\0'; + musdebug("Warning message set to [%s].", warningMessage); +} // setErrorMessage + + +static void setErrorMessage(const char *msg) +{ + strncpy(errorMessage, msg, sizeof (errorMessage)); + // strncpy() doesn't add the null char if there isn't room... + errorMessage[sizeof (errorMessage) - 1] = '\0'; + musdebug("Error message set to [%s].", errorMessage); +} // setErrorMessage + +// The music functions... + +char *MUSIC_ErrorString(int ErrorNumber) +{ + switch (ErrorNumber) + { + case MUSIC_Warning: + return(warningMessage); + + case MUSIC_Error: + return(errorMessage); + + case MUSIC_Ok: + return("OK; no error."); + + case MUSIC_ASSVersion: + return("Incorrect sound library version."); + + case MUSIC_SoundCardError: + return("General sound card error."); + + case MUSIC_InvalidCard: + return("Invalid sound card."); + + case MUSIC_MidiError: + return("MIDI error."); + + case MUSIC_MPU401Error: + return("MPU401 error."); + + case MUSIC_TaskManError: + return("Task Manager error."); + + case MUSIC_FMNotDetected: + return("FM not detected error."); + + case MUSIC_DPMI_Error: + return("DPMI error."); + + default: + return("Unknown error."); + } // switch + + assert(0); // shouldn't hit this point. + return(NULL); +} // MUSIC_ErrorString + + +static int music_initialized = 0; +static int music_context = 0; +static int music_loopflag = MUSIC_PlayOnce; +static char *music_songdata = NULL; +static Mix_Music *music_musicchunk = NULL; + +int MUSIC_Init(int SoundCard, int Address) +{ + init_debugging(); + + // eukara: MIDI support. + //Mix_Init(MIX_INIT_MID); + Mix_SetMusicCMD("timidity"); + puts("Music set to use Timidity.\n"); + music_initialized = 1; + return(MUSIC_Ok); +} // MUSIC_Init + + +int MUSIC_Shutdown(void) +{ + musdebug("shutting down sound subsystem."); + + if (!music_initialized) + { + setErrorMessage("Music system is not currently initialized."); + return(MUSIC_Error); + } // if + + MUSIC_StopSong(); + music_context = 0; + music_initialized = 0; + music_loopflag = MUSIC_PlayOnce; + + return(MUSIC_Ok); +} // MUSIC_Shutdown + + +void MUSIC_SetMaxFMMidiChannel(int channel) +{ + musdebug("STUB ... MUSIC_SetMaxFMMidiChannel(%d).\n", channel); +} // MUSIC_SetMaxFMMidiChannel + + +void MUSIC_SetVolume(int volume) +{ + Mix_VolumeMusic(volume >> 1); // convert 0-255 to 0-128. +} // MUSIC_SetVolume + + +void MUSIC_SetMidiChannelVolume(int channel, int volume) +{ + musdebug("STUB ... MUSIC_SetMidiChannelVolume(%d, %d).\n", channel, volume); +} // MUSIC_SetMidiChannelVolume + + +void MUSIC_ResetMidiChannelVolumes(void) +{ + musdebug("STUB ... MUSIC_ResetMidiChannelVolumes().\n"); +} // MUSIC_ResetMidiChannelVolumes + + +int MUSIC_GetVolume(void) +{ + return(Mix_VolumeMusic(-1) << 1); // convert 0-128 to 0-255. +} // MUSIC_GetVolume + + +void MUSIC_SetLoopFlag(int loopflag) +{ + music_loopflag = loopflag; +} // MUSIC_SetLoopFlag + + +int MUSIC_SongPlaying(void) +{ + return((Mix_PlayingMusic()) ? __FX_TRUE : __FX_FALSE); +} // MUSIC_SongPlaying + + +void MUSIC_Continue(void) +{ + if (Mix_PausedMusic()) + Mix_ResumeMusic(); + else if (music_songdata) + MUSIC_PlaySong(music_songdata, MUSIC_PlayOnce); +} // MUSIC_Continue + + +void MUSIC_Pause(void) +{ + Mix_PauseMusic(); +} // MUSIC_Pause + + +int MUSIC_StopSong(void) +{ + //if (!fx_initialized) + if (!Mix_QuerySpec(NULL, NULL, NULL)) + { + setErrorMessage("Need FX system initialized, too. Sorry."); + return(MUSIC_Error); + } // if + + if ( (Mix_PlayingMusic()) || (Mix_PausedMusic()) ) + Mix_HaltMusic(); + + if (music_musicchunk) + Mix_FreeMusic(music_musicchunk); + + music_songdata = NULL; + music_musicchunk = NULL; + return(MUSIC_Ok); +} // MUSIC_StopSong + + +int MUSIC_PlaySong(unsigned char *song, int loopflag) +{ + music_songdata = song; + + // eukara: MIDI support. + Mix_PlayMusic((Mix_Music *) song, loopflag); + + return(MUSIC_Ok); +} // MUSIC_PlaySong + + +extern char ApogeePath[256]; + +// Duke3D-specific. --ryan. +void PlayMusic(char *_filename) +{ + //char filename[MAX_PATH]; + //strcpy(filename, _filename); + //FixFilePath(filename); + + char filename[MAX_PATH]; + long handle; + long size; + void *song; + long rc; + + MUSIC_StopSong(); + + // Read from a groupfile, write it to disk so SDL_mixer can read it. + // Lame. --ryan. + handle = kopen4load(_filename, 0); + if (handle == -1) + return; + + size = kfilelength(handle); + if (size == -1) + { + kclose(handle); + return; + } // if + + song = malloc(size); + if (song == NULL) + { + kclose(handle); + return; + } // if + + rc = kread(handle, song, size); + kclose(handle); + if (rc != size) + { + free(song); + return; + } // if + + // save the file somewhere, so SDL_mixer can load it + GetPathFromEnvironment(filename, MAX_PATH, "tmpsong.mid"); + handle = SafeOpenWrite(filename, filetype_binary); + + SafeWrite(handle, song, size); + close(handle); + free(song); + + //music_songdata = song; + + music_musicchunk = Mix_LoadMUS(filename); + if (music_musicchunk != NULL) + { + // !!! FIXME: I set the music to loop. Hope that's okay. --ryan. + Mix_PlayMusic(music_musicchunk, -1); + } // if +} + + +#if ROTT +// ROTT Special - SBF +int MUSIC_PlaySongROTT(unsigned char *song, int size, int loopflag) +{ + char filename[MAX_PATH]; + int handle; + + MUSIC_StopSong(); + + // save the file somewhere, so SDL_mixer can load it + GetPathFromEnvironment(filename, MAX_PATH, "tmpsong.mid"); + handle = SafeOpenWrite(filename); + + SafeWrite(handle, song, size); + close(handle); + + music_songdata = song; + + // finally, we can load it with SDL_mixer + music_musicchunk = Mix_LoadMUS(filename); + if (music_musicchunk == NULL) { + return MUSIC_Error; + } + + Mix_PlayMusic(music_musicchunk, (loopflag == MUSIC_PlayOnce) ? 0 : -1); + + return(MUSIC_Ok); +} // MUSIC_PlaySongROTT +#endif + + +void MUSIC_SetContext(int context) +{ + musdebug("STUB ... MUSIC_SetContext().\n"); + music_context = context; +} // MUSIC_SetContext + + +int MUSIC_GetContext(void) +{ + return(music_context); +} // MUSIC_GetContext + + +void MUSIC_SetSongTick(unsigned long PositionInTicks) +{ + musdebug("STUB ... MUSIC_SetSongTick().\n"); +} // MUSIC_SetSongTick + + +void MUSIC_SetSongTime(unsigned long milliseconds) +{ + musdebug("STUB ... MUSIC_SetSongTime().\n"); +}// MUSIC_SetSongTime + + +void MUSIC_SetSongPosition(int measure, int beat, int tick) +{ + musdebug("STUB ... MUSIC_SetSongPosition().\n"); +} // MUSIC_SetSongPosition + + +void MUSIC_GetSongPosition(songposition *pos) +{ + musdebug("STUB ... MUSIC_GetSongPosition().\n"); +} // MUSIC_GetSongPosition + + +void MUSIC_GetSongLength(songposition *pos) +{ + musdebug("STUB ... MUSIC_GetSongLength().\n"); +} // MUSIC_GetSongLength + + +int MUSIC_FadeVolume(int tovolume, int milliseconds) +{ + Mix_FadeOutMusic(milliseconds); + return(MUSIC_Ok); +} // MUSIC_FadeVolume + + +int MUSIC_FadeActive(void) +{ + return((Mix_FadingMusic() == MIX_FADING_OUT) ? __FX_TRUE : __FX_FALSE); +} // MUSIC_FadeActive + + +void MUSIC_StopFade(void) +{ + musdebug("STUB ... MUSIC_StopFade().\n"); +} // MUSIC_StopFade + + +void MUSIC_RerouteMidiChannel(int channel, int cdecl (*function)( int event, int c1, int c2 )) +{ + musdebug("STUB ... MUSIC_RerouteMidiChannel().\n"); +} // MUSIC_RerouteMidiChannel + + +void MUSIC_RegisterTimbreBank(unsigned char *timbres) +{ + musdebug("STUB ... MUSIC_RegisterTimbreBank().\n"); +} // MUSIC_RegisterTimbreBank + + +// end of fx_man.c ... diff --git a/dukeunix.h b/dukeunix.h new file mode 100755 index 0000000..fafa191 --- /dev/null +++ b/dukeunix.h @@ -0,0 +1,87 @@ +#ifndef _INCL_DUKEUNIX_H_ +#define _INCL_DUKEUNIX_H_ 1 + +#define cdecl +#define __far +#define __interrupt + +#ifdef __GNUC__ +typedef long long __int64; +#endif + +//#define STUBBED(x) +#ifdef __SUNPRO_C +#define STUBBED(x) fprintf(stderr,"STUB: %s (??? %s:%d)\n",x,__FILE__,__LINE__) +#else +#define STUBBED(x) fprintf(stderr,"STUB: %s (%s, %s:%d)\n",x,__FUNCTION__,__FILE__,__LINE__) +#endif + +#define PATH_SEP_CHAR '/' +#define PATH_SEP_STR "/" +#define ROOTDIR "/" +#define CURDIR "./" + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#include +#include +#include +#include +#include +#include + +struct find_t +{ + DIR *dir; + char pattern[MAX_PATH]; + char name[MAX_PATH]; +}; +int _dos_findfirst(char *filename, int x, struct find_t *f); +int _dos_findnext(struct find_t *f); + +struct dosdate_t +{ + unsigned char day; + unsigned char month; + unsigned int year; + unsigned char dayofweek; +}; + +void _dos_getdate(struct dosdate_t *date); + +#ifndef min +#define min(x, y) ((x) < (y) ? (x) : (y)) +#endif + +#ifndef max +#define max(x, y) ((x) > (y) ? (x) : (y)) +#endif + +#define FP_OFF(x) ((long) (x)) + +#ifndef strcmpi +#define strcmpi(x, y) strcasecmp(x, y) +#endif + +#ifdef DC +#undef stderr +#undef stdout +#undef getchar +/* kos compat */ +#define stderr ((FILE*)2) +#define stdout ((FILE*)2) +#define Z_AvailHeap() ((10 * 1024) * 1024) +#else +// 64 megs should be enough for anybody. :) --ryan. +#define Z_AvailHeap() ((64 * 1024) * 1024) +#endif + +#define printchrasm(x,y,ch) printf("%c", (char) (ch & 0xFF)) + +#ifdef __GNUC__ +#define GCC_PACK1_EXT __attribute__((packed,aligned(1))) +#endif + +#endif diff --git a/dukewin.h b/dukewin.h new file mode 100755 index 0000000..b9fd373 --- /dev/null +++ b/dukewin.h @@ -0,0 +1,85 @@ +#ifndef _INCL_DUKEWIN_H_ +#define _INCL_DUKEWIN_H_ 1 + +#ifndef _MSC_VER /* might need this. */ +typedef long long __int64; +#endif + +#pragma warning(disable:4761) + +#if USE_SDL +#include "SDL.h" +#endif + +#define STUBBED(x) printf("STUB: %s in %s:%d\n", x, __FILE__, __LINE__) + +#define __far +#define __interrupt + +#define PATH_SEP_CHAR '\\' +#define PATH_SEP_STR "\\" + +#include +#include +#include + +struct find_t +{ + long handle; + struct _finddata_t data; + char name[MAX_PATH]; +}; +int _dos_findfirst(char *filename, int x, struct find_t *f); +int _dos_findnext(struct find_t *f); + +struct dosdate_t +{ + unsigned char day; + unsigned char month; + unsigned int year; + unsigned char dayofweek; +}; + +void _dos_getdate(struct dosdate_t *date); + +#ifndef min +#define min(x, y) ((x) < (y) ? (x) : (y)) +#endif + +#ifndef max +#define max(x, y) ((x) > (y) ? (x) : (y)) +#endif + +#ifdef FP_OFF +#undef FP_OFF +#endif +#define FP_OFF(x) ((long) (x)) + +// 64 megs should be enough for anybody. :) --ryan. +#define Z_AvailHeap() ((64 * 1024) * 1024) + +#define printchrasm(x,y,ch) printf("%c", (char) (ch & 0xFF)) + +#define cdecl + +#define open _open +#define O_BINARY _O_BINARY +#define O_RDONLY _O_RDONLY +#define O_WRONLY _O_WRONLY +#define O_RDWR _O_RDWR +#define O_TRUNC _O_TRUNC +#define O_CREAT _O_CREAT +#define S_IREAD _S_IREAD +#define S_IWRITE _S_IWRITE +#define S_IRDWR _S_IRDWR + +#define S_IRUSR S_IREAD +#define S_IWUSR S_IWRITE +#define S_IRGRP 0 +#define S_IWGRP 0 + +#define F_OK 0 + +#define HAVE_PRAGMA_PACK 1 + +#endif diff --git a/file_lib.h b/file_lib.h new file mode 100755 index 0000000..72e9916 --- /dev/null +++ b/file_lib.h @@ -0,0 +1,260 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment + +This file is part of Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Original Source: 1996 - Todd Replogle +Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms +*/ +//------------------------------------------------------------------------- + +#ifndef _file_lib_public +#define _file_lib_public +#ifdef __cplusplus +extern "C" { +#endif + +enum + { + filetype_binary, + filetype_text + }; + +enum + { + access_read, + access_write, + access_append + }; + +//========================================================================== +// +// SafeOpenWrite - Opens a file for writing, returns handle +// +//========================================================================== +int32 SafeOpenWrite ( const char * filename, int32 filetype ); + +//========================================================================== +// +// SafeOpenRead - Opens a file for reading, returns handle +// +//========================================================================== +int32 SafeOpenRead ( const char * filename, int32 filetype ); + +//========================================================================== +// +// SafeOpenAppend - Opens a file for appending, returns handle +// +//========================================================================== +int32 SafeOpenAppend ( const char * filename, int32 filetype ); + +//========================================================================== +// +// SafeClose - Close a file denoted by the file handle +// +//========================================================================== +void SafeClose ( int32 handle ); + +//========================================================================== +// +// SafeFileExists - Checks for existence of file +// +//========================================================================== +boolean SafeFileExists ( const char * filename ); + +//========================================================================== +// +// SafeFileLength - Get length of a file pointed to by handle +// +//========================================================================== +int32 SafeFileLength ( int32 handle ); + +//========================================================================== +// +// SafeRead - reads from a handle +// +// handle - handle of file to read from +// +// buffer - pointer of buffer to read into +// +// count - number of bytes to read +// +//========================================================================== +void SafeRead (int32 handle, void *buffer, int32 count); + +//========================================================================== +// +// SafeWrite - writes to a handle +// +// handle - handle of file to write to +// +// buffer - pointer of buffer to write from +// +// count - number of bytes to write +// +//========================================================================== +void SafeWrite (int32 handle, void *buffer, int32 count); + +//========================================================================== +// +// LoadFile - Load a file +// +// filename - name of file +// +// bufferptr - pointer to pointer of buffer to read into +// +// returns number of bytes read +// +//========================================================================== +int32 LoadFile ( const char * filename, void ** bufferptr ); + +//========================================================================== +// +// SaveFile - Save a file +// +// filename - name of file +// +// bufferptr - pointer to buffer to write from +// +// count - number of bytes to write +// +//========================================================================== +void SaveFile ( const char * filename, void * bufferptr, int32 count ); + +//========================================================================== +// +// GetPathFromEnvironment - Add a pathname described in an environment +// variable to a standard filename. +// +// fullname - final string containing entire path +// +// length - size of the fullname variable +// +// filename - standard filename +// +//========================================================================== +void GetPathFromEnvironment( char *fullname, int32 length, const char *filename ); + +//========================================================================== +// +// DefaultExtension - Add a default extension to a path +// +// path - a path +// +// extension - default extension should include '.' +// +//========================================================================== +void DefaultExtension (char *path, const char *extension); + +//========================================================================== +// +// DefaultPath - Add the default path to a filename if it doesn't have one +// +// path - filename +// +// extension - default path +// +//========================================================================== +void DefaultPath (char *path, const char *basepath); + +//========================================================================== +// +// ExtractFileBase - Extract the base filename from a path +// +// path - the path +// +// dest - where the file base name will be placed +// +//========================================================================== +void ExtractFileBase (char *path, char *dest); + +//========================================================================== +// +// GetExtension - Extract the extension from a name +// returns true if an extension is found +// returns false otherwise +// +//========================================================================== +boolean GetExtension( char *filename, char *extension ); + +//========================================================================== +// +// SetExtension - Sets the extension from a name. Assumes that enough +// space is left at the end of the string to hold an extension. +// +//========================================================================== +void SetExtension( char *filename, const char *extension ); + +#ifdef __MSDOS__ +//****************************************************************************** +// +// GetPath +// +// Purpose +// To parse the directory entered by the user to make the directory. +// +// Parms +// Path - the path to be parsed. +// +// Returns +// Pointer to next path +// +//****************************************************************************** +char * GetPath (char * path, char *dir); + +//****************************************************************************** +// +// ChangeDirectory () +// +// Purpose +// To change to a directory. Checks for drive changes. +// +// Parms +// path - The path to change to. +// +// Returns +// TRUE - If successful. +// FALSE - If unsuccessful. +// +//****************************************************************************** +boolean ChangeDirectory (char * path); + +//****************************************************************************** +// +// ChangeDrive () +// +// Purpose +// To change drives. +// +// Parms +// drive - The drive to change to. +// +// Returns +// TRUE - If drive change successful. +// FALSE - If drive change unsuccessful. +// +//****************************************************************************** +boolean ChangeDrive (char *drive); + +#endif + +#ifdef __cplusplus +}; +#endif +#endif diff --git a/funct.h b/funct.h new file mode 100755 index 0000000..b0e3a0f --- /dev/null +++ b/funct.h @@ -0,0 +1,384 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment + +This file is part of Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Original Source: 1996 - Todd Replogle +Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms +*/ +//------------------------------------------------------------------------- + +/* sounds.c */ +extern void SoundStartup(void); +extern void SoundShutdown(void); +extern void MusicStartup(void); +extern void MusicShutdown(void); +extern int USRHOOKS_GetMem(char **ptr, unsigned long size); +extern int USRHOOKS_FreeMem(char *ptr); +extern void intomenusounds(void); +extern void playmusic(char *fn); +extern char loadsound(unsigned short num); +extern int xyzsound(short num, short i, long x, long y, long z); +extern void sound(short num); +extern int spritesound(unsigned short num, short i); +extern void stopsound(short num); +extern void stopenvsound(short num, short i); +extern void pan3dsound(void); +extern void testcallback(unsigned long num); +extern void clearsoundlocks(void); + +/* sector.c */ +extern short callsound(short sn, short whatsprite); +extern short check_activator_motion(short lotag); +extern char isadoorwall(short dapic); +extern char isanunderoperator(short lotag); +extern char isanearoperator(short lotag); +extern short checkcursectnums(short sect); +extern long ldist(spritetype *s1, spritetype *s2); +extern long dist(spritetype *s1, spritetype *s2); +extern short findplayer(spritetype *s, long *d); +extern short findotherplayer(short p, long *d); +extern void doanimations(void); +extern long getanimationgoal(long *animptr); +extern void animatecamsprite(void); +extern void animatewalls(void); +extern char activatewarpelevators(short s, short d); +extern void operatesectors(short sn, short ii); +extern void operaterespawns(short low); +extern void operateactivators(short low, short snum); +extern void operatemasterswitches(short low); +extern void operateforcefields(short s, short low); +extern char checkhitswitch(short snum, long w, char switchtype); +extern void activatebysector(short sect, short j); +extern void breakwall(short newpn, short spr, short dawallnum); +extern void checkhitwall(short spr, short dawallnum, long x, long y, long z, short atwith); +extern void checkplayerhurt(struct player_struct *p, short j); +extern char checkhitceiling(short sn); +extern void checkhitsprite(short i, short sn); +extern void allignwarpelevators(void); +extern void cheatkeys(short snum); +extern void checksectors(short snum); + +/* rts.c */ +extern void RTS_AddFile(char *filename); +extern void RTS_Init(char *filename); +extern int32 RTS_NumSounds(void); +extern int32 RTS_SoundLength(int32 lump); +extern char *RTS_GetSoundName(int32 i); +extern void RTS_ReadLump(int32 lump, void *dest); +extern void *RTS_GetSound(int32 lump); + +/* premap.c */ +extern void cachespritenum(short i); +extern void cachegoodsprites(void); +extern char getsound(unsigned short num); +extern void precachenecessarysounds(void); +extern void cacheit(void); +extern void docacheit(void); +extern void xyzmirror(short i, short wn); +extern void vscrn(void); +extern void pickrandomspot(short snum); +extern void resetplayerstats(short snum); +extern void resetweapons(short snum); +extern void resetinventory(short snum); +extern void resetprestat(short snum, char g); +extern void setupbackdrop(short sky); +extern void prelevel(char g); +extern void newgame(char vn, char ln, char sk); +extern void resetpspritevars(char g); +extern void clearfrags(void); +extern void resettimevars(void); +extern void genspriteremaps(void); +extern void waitforeverybody(void); +extern void dofrontscreens(void); +extern void clearfifo(void); +extern void resetmys(void); +extern void enterlevel(char g); + +/* player.c */ +extern void setpal(struct player_struct *p); +extern void incur_damage(struct player_struct *p); +extern void quickkill(struct player_struct *p); +extern void forceplayerangle(struct player_struct *p); +extern void tracers(long x1, long y1, long z1, long x2, long y2, long z2, long n); +extern long hits(short i); +extern long hitasprite(short i, short *hitsp); +extern long hitawall(struct player_struct *p, short *hitw); +extern short aim(spritetype *s, short aang); +extern void shoot(short i, short atwith); +extern void displayloogie(short snum); +extern char animatefist(short gs, short snum); +extern char animateknee(short gs, short snum); +extern char animateknuckles(short gs, short snum); +extern void displaymasks(short snum); +extern char animatetip(short gs, short snum); +extern char animateaccess(short gs, short snum); +extern void displayweapon(short snum); +extern void getinput(short snum); +extern char doincrements(struct player_struct *p); +extern void checkweapons(struct player_struct *p); +extern void processinput(short snum); +extern void computergetinput(long snum, input *syn); + +/* menues.c */ +extern void dummyfunc(void); +extern void dummymess(int i, char *c); +extern void cmenu(short cm); +extern void savetemp(char *fn, long daptr, long dasiz); +extern void getangplayers(short snum); +extern int loadplayer(signed char spot); +extern int saveplayer(signed char spot); +extern int probe(int x, int y, int i, int n); +extern int menutext(int x, int y, short s, short p, char *t); +extern int menutextc(int x, int y, short s, short p, char *t); +extern void bar(int x, int y, short *p, short dainc, char damodify, short s, short pa); +extern void dispnames(void); +extern int getfilenames(char kind[6]); +extern void sortfilenames(void); +extern void menus(void); +extern void palto(char r, char g, char b, long e); +extern void drawoverheadmap(long cposx, long cposy, long czoom, short cang); +extern void endanimsounds(long fr); +extern void logoanimsounds(long fr); +extern void intro4animsounds(long fr); +extern void first4animsounds(long fr); +extern void intro42animsounds(long fr); +extern void endanimvol41(long fr); +extern void endanimvol42(long fr); +extern void endanimvol43(long fr); +extern void playanm(char *fn, char t); + +/* gamedef.c */ +extern short getincangle(short a, short na); +extern char ispecial(char c); +extern char isaltok(char c); +extern void getglobalz(short i); +extern void makeitfall(short i); +extern void getlabel(void); +extern long keyword(void); +extern long transword(void); +extern void transnum(void); +extern char parsecommand(void); +extern void passone(void); +extern void copydefaultcons(void); +extern void loadefs(char *filenam, char *mptr); +extern char dodge(spritetype *s); +extern short furthestangle(short i, short angs); +extern short furthestcanseepoint(short i, spritetype *ts, long *dax, long *day); +extern void alterang(short a); +extern void move(void); +extern void parseifelse(long condition); +extern char parse(void); +extern void execute(short i, short p, long x); + +/* config.c */ +extern void CONFIG_GetSetupFilename(void); +extern int32 CONFIG_FunctionNameToNum(char *func); +extern char *CONFIG_FunctionNumToName(int32 func); +extern int32 CONFIG_AnalogNameToNum(char *func); +extern void CONFIG_SetDefaults(void); +extern void CONFIG_ReadKeys(void); +extern void CONFIG_SetupMouse(int32 scripthandle); +extern void CONFIG_SetupGamePad(int32 scripthandle); +extern void CONFIG_SetupJoystick(int32 scripthandle); +extern void readsavenames(void); +extern void CONFIG_ReadSetup(void); +extern void CONFIG_WriteSetup(void); + +/* animlib.c */ +extern void CheckAnimStarted(char *funcname); +extern uint16 findpage(uint16 framenumber); +extern void loadpage(uint16 pagenumber, uint16 *pagepointer); +extern void CPlayRunSkipDump(char *srcP, char *dstP); +extern void renderframe(uint16 framenumber, uint16 *pagepointer); +extern void drawframe(uint16 framenumber); +extern void ANIM_LoadAnim(char *buffer); +extern void ANIM_FreeAnim(void); +extern int32 ANIM_NumFrames(void); +extern byte *ANIM_DrawFrame(int32 framenumber); +extern byte *ANIM_GetPalette(void); + +/* game.c */ +extern void timerhandler(void); +extern int gametext(int x, int y, char *t, char s, short dabits); +extern int gametextpal(int x, int y, char *t, char s, char p); +extern int gametextpart(int x, int y, char *t, char s, short p); +extern int minitext(int x, int y, char *str, char p, char sb); +extern int minitextshade(int x, int y, char *t, char s, char p, char sb); +extern void gamenumber(long x, long y, long n, char s); +extern void allowtimetocorrecterrorswhenquitting(void); +extern void getpackets(void); +extern void faketimerhandler(void); +extern void caches(void); +extern void checksync(void); +extern void check_fta_sounds(short i); +extern short inventory(spritetype *s); +extern short badguy(spritetype *s); +extern short badguypic(short pn); +extern void myos(long x, long y, short tilenum, signed char shade, char orientation); +extern void myospal(long x, long y, short tilenum, signed char shade, char orientation, char p); +extern void invennum(long x, long y, char num1, char ha, char sbits); +extern void weaponnum(short ind, long x, long y, long num1, long num2, char ha); +extern void weaponnum999(char ind, long x, long y, long num1, long num2, char ha); +extern void weapon_amounts(struct player_struct *p, long x, long y, long u); +extern void digitalnumber(long x, long y, long n, char s, char cs); +extern void displayinventory(struct player_struct *p); +extern void displayfragbar(void); +extern void coolgaugetext(short snum); +extern void tics(void); +extern void coords(short snum); +extern void operatefta(void); +extern void FTA(short q, struct player_struct *p); +extern void showtwoscreens(void); +extern void binscreen(void); +extern void gameexit(char *msg); +extern short strget(short x, short y, char *t, short dalen, short c); +extern void typemode(void); +extern void moveclouds(void); +extern void displayrest(long smoothratio); +extern void updatesectorz(long x, long y, long z, short *sectnum); +extern void view(struct player_struct *pp, long *vx, long *vy, long *vz, short *vsectnum, short ang, short horiz); +extern void drawbackground(void); +extern void displayrooms(short snum, long smoothratio); +extern short LocateTheLocator(short n, short sn); +extern short EGS(short whatsect, long s_x, long s_y, long s_z, short s_pn, signed char s_s, signed char s_xr, signed char s_yr, short s_a, short s_ve, long s_zv, short s_ow, signed char s_ss); +extern char wallswitchcheck(short i); +extern short spawn(short j, short pn); +extern void animatesprites(long x, long y, short a, long smoothratio); +extern void cheats(void); +extern void nonsharedkeys(void); +extern void comlinehelp(char **argv); +extern void checkcommandline(int argc, char **argv); +extern void printstr(short x, short y, char string[81], char attribute); +extern void Logo(void); +extern void loadtmb(void); +extern void ShutDown(void); +extern void compilecons(void); +extern void Startup(void); +extern void sendscore(char *s); +extern void getnames(void); +extern void writestring(long a1, long a2, long a3, short a4, long vx, long vy, long vz); +extern char testcd(char *fn); +extern void copyprotect(void); +extern char opendemoread(char which_demo); +extern void opendemowrite(void); +extern void record(void); +extern void closedemowrite(void); +extern long playback(void); +extern char moveloop(void); +extern void fakedomovethingscorrect(void); +extern void fakedomovethings(void); +extern char domovethings(void); +extern void doorders(void); +extern void dobonus(char bonusonly); +extern void cameratext(short i); +extern void vglass(long x, long y, short a, short wn, short n); +extern void lotsofglass(short i, short wallnum, short n); +extern void spriteglass(short i, short n); +extern void ceilingglass(short i, short sectnum, short n); +extern void lotsofcolourglass(short i, short wallnum, short n); +extern void SetupGameButtons(void); +extern void CenterCenter(void); +extern void UpperLeft(void); +extern void LowerRight(void); +extern void CenterThrottle(void); +extern void CenterRudder(void); + +/* + * (This was originally "GetTime", but that conflicts with a function in + * in MacOSX's Carbon. --ryan.) + */ +extern long DUKE3D_GetTime(void); + + +/* Global.c */ +extern void FixFilePath(char *filename); +extern int _dos_findfirst(char *filename, int x, struct find_t *f); +extern int _dos_findnext(struct find_t *f); +extern void _dos_getdate(struct dosdate_t *date); +extern int FindDistance2D(int ix, int iy); +extern int FindDistance3D(int ix, int iy, int iz); +extern void Error(char *error, ...); +extern int32 SafeOpenAppend(const char *_filename, int32 filetype); +extern boolean SafeFileExists(const char *_filename); +extern int32 SafeOpenWrite(const char *_filename, int32 filetype); +extern int32 SafeOpenRead(const char *_filename, int32 filetype); +extern void SafeRead(int32 handle, void *buffer, int32 count); +extern void SafeWrite(int32 handle, void *buffer, int32 count); +extern void SafeWriteString(int handle, char *buffer); +extern void *SafeMalloc(long size); +extern void SafeRealloc(void **x, int32 size); +extern void *SafeLevelMalloc(long size); +extern void SafeFree(void *ptr); +extern short MotoShort(short l); +extern short IntelShort(short l); +extern long MotoLong(long l); +extern long IntelLong(long l); +extern void SwapIntelLong(long *l); +extern void SwapIntelShort(short *s); +extern void SwapIntelLongArray(long *l, int num); +extern void SwapIntelShortArray(short *s, int num); +extern int setup_homedir(void); +extern char CheckParm(char *check); +extern void RegisterShutdownFunction(void (*shutdown)(void)); +extern void Shutdown(void); +extern char *ltoa(long value, char *string, int radix); +extern char *ultoa(unsigned long value, char *string, int radix); +extern int dukescreencapture(char *str, char inverseit); + +/* actors.c */ +extern void updateinterpolations(void); +extern void setinterpolation(long *posptr); +extern void stopinterpolation(long *posptr); +extern void dointerpolations(long smoothratio); +extern void restoreinterpolations(void); +extern long ceilingspace(short sectnum); +extern long floorspace(short sectnum); +extern void addammo(short weapon, struct player_struct *p, short amount); +extern void addweapon(struct player_struct *p, short weapon); +extern void checkavailinven(struct player_struct *p); +extern void checkavailweapon(struct player_struct *p); +extern long ifsquished(short i, short p); +extern void hitradius(short i, long r, long hp1, long hp2, long hp3, long hp4); +extern short movesprite(short spritenum, long xchange, long ychange, long zchange, unsigned long cliptype); +extern short ssp(short i, unsigned long cliptype); +extern void insertspriteq(short i); +extern void lotsofmoney(spritetype *s, short n); +extern void lotsofmail(spritetype *s, short n); +extern void lotsofpaper(spritetype *s, short n); +extern void guts(spritetype *s, short gtype, short n, short p); +extern void gutsdir(spritetype *s, short gtype, short n, short p); +extern void setsectinterpolate(short i); +extern void clearsectinterpolate(short i); +extern void ms(short i); +extern void movefta(void); +extern short ifhitsectors(short sectnum); +extern short ifhitbyweapon(short sn); +extern void movecyclers(void); +extern void movedummyplayers(void); +extern void moveplayers(void); +extern void movefx(void); +extern void movefallers(void); +extern void movestandables(void); +extern void bounce(short i); +extern void moveweapons(void); +extern void movetransports(void); +extern void moveactors(void); +extern void moveexplosions(void); +extern void moveeffectors(void); diff --git a/function.h b/function.h new file mode 100755 index 0000000..4fe8e9f --- /dev/null +++ b/function.h @@ -0,0 +1,103 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment + +This file is part of Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Original Source: 1996 - Todd Replogle +Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms +*/ +//------------------------------------------------------------------------- + +// function.h + +// file created by makehead.exe +// these headers contain default key assignments, as well as +// default button assignments and game function names +// axis defaults are also included + + +#ifndef _function_public_ +#define _function_public_ +#ifdef __cplusplus +extern "C" { +#endif + +#define NUMGAMEFUNCTIONS 52 + +extern char * gamefunctions[]; + +enum + { + gamefunc_Move_Forward, + gamefunc_Move_Backward, + gamefunc_Turn_Left, + gamefunc_Turn_Right, + gamefunc_Strafe, + gamefunc_Fire, + gamefunc_Open, + gamefunc_Run, + gamefunc_AutoRun, + gamefunc_Jump, + gamefunc_Crouch, + gamefunc_Look_Up, + gamefunc_Look_Down, + gamefunc_Look_Left, + gamefunc_Look_Right, + gamefunc_Strafe_Left, + gamefunc_Strafe_Right, + gamefunc_Aim_Up, + gamefunc_Aim_Down, + gamefunc_Weapon_1, + gamefunc_Weapon_2, + gamefunc_Weapon_3, + gamefunc_Weapon_4, + gamefunc_Weapon_5, + gamefunc_Weapon_6, + gamefunc_Weapon_7, + gamefunc_Weapon_8, + gamefunc_Weapon_9, + gamefunc_Weapon_10, + gamefunc_Inventory, + gamefunc_Inventory_Left, + gamefunc_Inventory_Right, + gamefunc_Holo_Duke, + gamefunc_Jetpack, + gamefunc_NightVision, + gamefunc_MedKit, + gamefunc_TurnAround, + gamefunc_SendMessage, + gamefunc_Map, + gamefunc_Shrink_Screen, + gamefunc_Enlarge_Screen, + gamefunc_Center_View, + gamefunc_Holster_Weapon, + gamefunc_Show_Opponents_Weapon, + gamefunc_Map_Follow_Mode, + gamefunc_See_Coop_View, + gamefunc_Mouse_Aiming, + gamefunc_Toggle_Crosshair, + gamefunc_Steroids, + gamefunc_Quick_Kick, + gamefunc_Next_Weapon, + gamefunc_Previous_Weapon, + }; +#ifdef __cplusplus +}; +#endif +#endif diff --git a/fx_man.c b/fx_man.c new file mode 100755 index 0000000..695dd37 --- /dev/null +++ b/fx_man.c @@ -0,0 +1,1456 @@ +/* + * A reimplementation of Jim Dose's FX_MAN routines, using SDL_mixer 1.2. + * Whee. FX_MAN is also known as the "Apogee Sound System", or "ASS" for + * short. How strangely appropriate that seems. + * + * Written by Ryan C. Gordon. (icculus@clutteredmind.org) + */ + +#include +#include +#include +#include +#include + +#include "duke3d.h" +#include "buildengine/cache1d.h" + +#if PLATFORM_DOS +// Use the original Apogee Sound System libs instead. --ryan. +#error you probably should not compile this. +#endif + +#if (defined __WATCOMC__) +// This is probably out of date. --ryan. +#include "dukesnd_watcom.h" +#endif + +#if (!defined __WATCOMC__) +#define cdecl +#endif + +#include "SDL.h" +#include "SDL_mixer.h" +#ifdef ROTT +#include "rt_def.h" // ROTT music hack +#include "rt_cfg.h" // ROTT music hack +#include "rt_util.h" // ROTT music hack +#endif +#include "fx_man.h" +#include "music.h" + +#define __FX_TRUE (1 == 1) +#define __FX_FALSE (!__FX_TRUE) + +#define DUKESND_DEBUG "DUKESND_DEBUG" + +#ifndef min +#define min(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +#ifndef max +#define max(a, b) (((a) > (b)) ? (a) : (b)) +#endif + +typedef struct __DUKECHANINFO +{ + int in_use; // 1 or 0. + int priority; // priority, defined by application. + Uint32 birthday; // ticks when channel was grabbed. + unsigned long callbackval; // callback value from application. +} duke_channel_info; + + +int MUSIC_ErrorCode = MUSIC_Ok; + +static char warningMessage[80]; +static char errorMessage[80]; +static int fx_initialized = 0; +static int numChannels = MIX_CHANNELS; +static void (*callback)(unsigned long); +static int reverseStereo = 0; +static int reverbDelay = 256; +static int reverbLevel = 0; +static int fastReverb = 0; +static FILE *debug_file = NULL; +static int initialized_debugging = 0; +static int maxReverbDelay = 256; +static int mixerIsStereo = 1; +static duke_channel_info *chaninfo = NULL; + +// This...is not ideal. --ryan. +#define CHUNK_CACHE_SIZE 128 +typedef struct __DUKECHUNKCACHE +{ + Mix_Chunk *chunk; + void *dataptr; +} duke_chunk_cache; +static duke_chunk_cache chunkCache[CHUNK_CACHE_SIZE]; + + +#define HandleOffset 1 + +/* these come from the real ASS */ +#define MV_MaxPanPosition 31 +#define MV_NumPanPositions ( MV_MaxPanPosition + 1 ) +#define MV_MaxVolume 63 + +#define MIX_VOLUME( volume ) \ + ( ( max( 0, min( ( volume ), 255 ) ) * ( MV_MaxVolume + 1 ) ) >> 8 ) + +typedef struct +{ + unsigned char left; + unsigned char right; +} Pan; + +static Pan MV_PanTable[ MV_NumPanPositions ][ MV_MaxVolume + 1 ]; + +static void MV_CalcPanTable + ( + void + ) + + { + int level; + int angle; + int distance; + int HalfAngle; + int ramp; + + HalfAngle = ( MV_NumPanPositions / 2 ); + + for( distance = 0; distance <= MV_MaxVolume; distance++ ) + { + level = ( 255 * ( MV_MaxVolume - distance ) ) / MV_MaxVolume; + for( angle = 0; angle <= HalfAngle / 2; angle++ ) + { + ramp = level - ( ( level * angle ) / + ( MV_NumPanPositions / 4 ) ); + + MV_PanTable[ angle ][ distance ].left = ramp; + MV_PanTable[ HalfAngle - angle ][ distance ].left = ramp; + MV_PanTable[ HalfAngle + angle ][ distance ].left = level; + MV_PanTable[ MV_MaxPanPosition - angle ][ distance ].left = level; + + MV_PanTable[ angle ][ distance ].right = level; + MV_PanTable[ HalfAngle - angle ][ distance ].right = level; + MV_PanTable[ HalfAngle + angle ][ distance ].right = ramp; + MV_PanTable[ MV_MaxPanPosition - angle ][ distance ].right = ramp; + } + } + } +/* end ASS copy-pastage */ + +#ifdef __WATCOMC__ +#pragma aux (__cdecl) channelDoneCallback; +#endif + +// This function is called whenever an SDL_mixer channel completes playback. +// We use this for state management and calling the application's callback. +static void channelDoneCallback(int channel) +{ + //Mix_FreeChunk(Mix_GetChunk(channel)); + if (callback) + { + callback(chaninfo[channel].callbackval); + chaninfo[channel].in_use = 0; + } // if +} // channelDoneCallback + + +// This gets called all over the place for information and debugging messages. +// If the user set the DUKESND_DEBUG environment variable, the messages +// go to the file that is specified in that variable. Otherwise, they +// are ignored for the expense of the function call. If DUKESND_DEBUG is +// set to "-" (without the quotes), then the output goes to stdout. +static void snddebug(const char *fmt, ...) +{ + va_list ap; + + if (debug_file) + { + fprintf(debug_file, "DUKESND: "); + va_start(ap, fmt); + vfprintf(debug_file, fmt, ap); + va_end(ap); + fprintf(debug_file, "\n"); + fflush(debug_file); + } // if +} // snddebug + + +// FIXME: Consolidate this code. +// Same as snddebug(), but a different tag is put on each line. +static void musdebug(const char *fmt, ...) +{ + va_list ap; + + if (debug_file) + { + fprintf(debug_file, "DUKEMUS: "); + va_start(ap, fmt); + vfprintf(debug_file, fmt, ap); + va_end(ap); + fprintf(debug_file, "\n"); + fflush(debug_file); + } // if +} // snddebug + + +static void init_debugging(void) +{ + const char *envr; + + if (initialized_debugging) + return; + + envr = getenv(DUKESND_DEBUG); + if (envr != NULL) + { + if (strcmp(envr, "-") == 0) + debug_file = stdout; + else + debug_file = fopen(envr, "w"); + + if (debug_file == NULL) + fprintf(stderr, "DUKESND: -WARNING- Could not open debug file!\n"); + else + setbuf(debug_file, NULL); + } // if + + initialized_debugging = 1; +} // init_debugging + + +// find an available SDL_mixer channel, and reserve it. +// This would be a race condition, but hey, it's for a DOS game. :) +static int grabMixerChannel(int priority) +{ + int replaceable = -1; + int i; + + if (!fx_initialized) + return(-1); + + for (i = 0; i < numChannels; i++) + { + if (chaninfo[i].in_use == 0) + { + chaninfo[i].in_use = 1; + chaninfo[i].priority = priority; + chaninfo[i].birthday = SDL_GetTicks(); + return(i); + } // if + + // !!! FIXME: Should this just be lower priority, or equal too? + if (chaninfo[i].priority <= priority) + { + if ((replaceable == -1) || + (chaninfo[i].birthday < chaninfo[replaceable].birthday)) + { + replaceable = i; + } // if + } // if + } // for + + // if you land here, all mixer channels are playing... + if (replaceable != -1) // nothing expendable right now. + { + chaninfo[replaceable].in_use = 1; + chaninfo[replaceable].priority = priority; + chaninfo[replaceable].birthday = SDL_GetTicks(); + } // if + + return(replaceable); +} // grabMixerChannel + + +// !!! FIXME: Is this correct behaviour? +char *FX_ErrorString( int ErrorNumber ) +{ + switch (ErrorNumber) + { + case FX_Warning: + return(warningMessage); + + case FX_Error: + return(errorMessage); + + case FX_Ok: + return("OK; no error."); + + case FX_ASSVersion: + return("Incorrect sound library version."); + + case FX_BlasterError: + return("SoundBlaster Error."); + + case FX_SoundCardError: + return("General sound card error."); + + case FX_InvalidCard: + return("Invalid sound card."); + + case FX_MultiVocError: + return("Multiple voc error."); + + case FX_DPMI_Error: + return("DPMI error."); + + default: + return("Unknown error."); + } // switch + + assert(0); // shouldn't hit this point. + return(NULL); +} // FX_ErrorString + + +static void setWarningMessage(const char *msg) +{ + strncpy(warningMessage, msg, sizeof (warningMessage)); + // strncpy() doesn't add the null char if there isn't room... + warningMessage[sizeof (warningMessage) - 1] = '\0'; + snddebug("Warning message set to [%s].", warningMessage); +} // setErrorMessage + + +static void setErrorMessage(const char *msg) +{ + strncpy(errorMessage, msg, sizeof (errorMessage)); + // strncpy() doesn't add the null char if there isn't room... + errorMessage[sizeof (errorMessage) - 1] = '\0'; + snddebug("Error message set to [%s].", errorMessage); +} // setErrorMessage + + +int FX_GetBlasterSettings(fx_blaster_config *blaster) +{ + setErrorMessage("No SoundBlaster cards available."); + return(FX_Error); +} // FX_GetBlasterSettings + + +int FX_SetupSoundBlaster(fx_blaster_config blaster, int *MaxVoices, + int *MaxSampleBits, int *MaxChannels) +{ + setErrorMessage("No SoundBlaster cards available."); + return(FX_Error); +} // FX_SetupSoundBlaster + + +int FX_SetupCard( int SoundCard, fx_device *device ) +{ + init_debugging(); + + snddebug("FX_SetupCard looking at card id #%d...", SoundCard); + + if (device == NULL) // sanity check. + { + setErrorMessage("fx_device is NULL in FX_SetupCard!"); + return(FX_Error); + } // if + + // Since the actual hardware is abstracted out on modern operating + // systems, we just pretend that the system's got a SoundScape. + // I always liked that card, even though Ensoniq screwed me on OS/2 + // drivers back in the day. :) + if (SoundCard != SoundScape) + { + setErrorMessage("Card not found."); + snddebug("We pretend to be an Ensoniq SoundScape only."); + return(FX_Error); + } // if + + device->MaxVoices = 8; + device->MaxSampleBits = 16; // SDL_mixer downsamples if needed. + device->MaxChannels = 2; // SDL_mixer converts to mono if needed. + + return(FX_Ok); +} // FX_SetupCard + + +static void output_versions(const char *libname, const SDL_version *compiled, + const SDL_version *linked) +{ + snddebug("This program was compiled against %s %d.%d.%d,\n" + " and is dynamically linked to %d.%d.%d.\n", libname, + compiled->major, compiled->minor, compiled->patch, + linked->major, linked->minor, linked->patch); +} + + +static void output_version_info(void) +{ + SDL_version compiled; + const SDL_version *linked; + + snddebug("Library check..."); + + SDL_VERSION(&compiled); + linked = SDL_Linked_Version(); + output_versions("SDL", &compiled, linked); + + MIX_VERSION(&compiled); + linked = Mix_Linked_Version(); + output_versions("SDL_mixer", &compiled, linked); +} // output_version_info + + +int FX_Init(int SoundCard, int numvoices, int numchannels, + int samplebits, unsigned mixrate) +{ + Uint16 audio_format = 0; + int blocksize; + + init_debugging(); + + snddebug("INIT! card=>%d, voices=>%d, chan=>%d, bits=>%d, rate=>%du...", + SoundCard, numvoices, numchannels, samplebits, mixrate); + + if (fx_initialized) + { + setErrorMessage("Sound system is already initialized.\n"); + return(FX_Error); + } // if + + if (SoundCard != SoundScape) // We pretend there's a SoundScape installed. + { + setErrorMessage("Card not found."); + snddebug("We pretend to be an Ensoniq SoundScape only."); + return(FX_Error); + } // if + + // other sanity checks... + if ((numvoices < 0) || (numvoices > 8)) + { + setErrorMessage("Invalid number of voices to mix (must be 0-8)."); + return(FX_Error); + } // if + + if ((numchannels != MonoFx) && (numchannels != StereoFx)) + { + setErrorMessage("Invalid number of channels (must be 1 or 2)."); + return(FX_Error); + } // if + + if ((samplebits != 8) && (samplebits != 16)) + { + setErrorMessage("Invalid sample size (must be 8 or 16)."); + return(FX_Error); + } // if + + // build pan tables + MV_CalcPanTable(); + + SDL_ClearError(); + if (SDL_Init(SDL_INIT_AUDIO) < 0) + { + setErrorMessage("SDL_Init(SDL_INIT_AUDIO) failed!"); + snddebug("SDL_GetError() reports: [%s].", SDL_GetError()); + return(FX_Error); + } // if + + audio_format = (samplebits == 8) ? AUDIO_U8 : AUDIO_S16; + if (Mix_OpenAudio(mixrate, audio_format, numchannels, 256) < 0) + { + setErrorMessage(SDL_GetError()); + return(FX_Error); + } // if + + output_version_info(); + + numChannels = Mix_AllocateChannels(numvoices); + if (numChannels != numvoices) + { + setErrorMessage(SDL_GetError()); + Mix_CloseAudio(); + return(FX_Error); + } // if + + blocksize = sizeof (duke_channel_info) * numvoices; + chaninfo = malloc(blocksize); + if (chaninfo == NULL) // uhoh. + { + setErrorMessage("Out of memory"); + Mix_CloseAudio(); + return(FX_Error); + } // if + memset(chaninfo, '\0', blocksize); + + Mix_ChannelFinished(channelDoneCallback); + maxReverbDelay = (int) (((float) mixrate) * 0.5); + + Mix_QuerySpec(NULL, NULL, &mixerIsStereo); + mixerIsStereo = (mixerIsStereo == 2); + + memset(chunkCache, '\0', sizeof (chunkCache)); + + fx_initialized = 1; + return(FX_Ok); +} // FX_Init + + +void FX_CleanCache(void) +{ + int total = 0; + int i; + + snddebug("FX_CleanCache halting all channels."); + Mix_HaltChannel(-1); // stop everything. + + snddebug("freeing cached chunks."); + for (i = 0; i < CHUNK_CACHE_SIZE; i++) + { + if (chunkCache[i].chunk != NULL) + { + total++; + Mix_FreeChunk(chunkCache[i].chunk); + chunkCache[i].chunk = NULL; + } // if + chunkCache[i].dataptr = NULL; + } // for + + snddebug("cached chunks deallocation complete. (%d) were deleted.", total); +} // FX_CleanCache + + +int FX_Shutdown( void ) +{ + snddebug("shutting down sound subsystem."); + + if (!fx_initialized) + { + setErrorMessage("Sound system is not currently initialized.\n"); + return(FX_Error); + } // if + + FX_CleanCache(); // stops all channels and music. + Mix_CloseAudio(); + callback = NULL; + free(chaninfo); + chaninfo = NULL; + reverseStereo = 0; + reverbLevel = 0; + fastReverb = 0; + fx_initialized = 0; + maxReverbDelay = 256; + + return(FX_Ok); +} // FX_Shutdown + + +int FX_SetCallBack(void (*func)(unsigned long)) +{ + callback = func; + return(FX_Ok); +} // FX_SetCallBack + + +void FX_SetVolume(int volume) +{ + snddebug("setting master volume to %f.2 percent.", (volume / 255.0) * 100); + Mix_Volume(-1, volume >> 1); // it's 0-128 in SDL_mixer, not 0-255. +} // FX_SetVolume + + +int FX_GetVolume(void) +{ + return(Mix_Volume(-1, -1) << 1); +} // FX_GetVolume + + +void FX_SetReverseStereo(int setting) +{ + snddebug("Reverse stereo set to %s.\n", setting ? "ON" : "OFF"); + Mix_SetReverseStereo(MIX_CHANNEL_POST, setting); + reverseStereo = setting; +} // FX_SetReverseStereo + + +int FX_GetReverseStereo(void) +{ + return(reverseStereo); +} // FX_GetReverseStereo + + +void FX_SetReverb(int reverb) +{ + reverbLevel = reverb; + fastReverb = 0; + +#if 1 + // !!! FIXME + if (reverbLevel) + setWarningMessage("reverb filter is not yet implemented!"); +#endif +} // FX_SetReverb + + +void FX_SetFastReverb(int reverb) +{ + reverbLevel = reverb; + fastReverb = 1; + +#if 1 + // !!! FIXME + if (reverbLevel) + setWarningMessage("fast reverb filter is not yet implemented!"); +#endif +} // FX_SetFastReverb + + +int FX_GetMaxReverbDelay(void) +{ + return(maxReverbDelay); +} // FX_GetMaxReverbDelay + + +int FX_GetReverbDelay(void) +{ + return(reverbDelay); +} // FX_GetReverbDelay + + +void FX_SetReverbDelay(int delay) +{ + // !!! FIXME: Should I be clamping these values? + if (delay < 256) + delay = 256; + + if (delay > maxReverbDelay) + delay = maxReverbDelay; + + reverbDelay = delay; + +#if 1 + // !!! FIXME + setWarningMessage("reverb delay is not yet implemented!"); +#endif +} // FX_SetReverbDelay + + +int FX_VoiceAvailable(int priority) +{ + int chan = grabMixerChannel(priority); + int rc = (chan != -1); + + if (rc) + chaninfo[chan].in_use = 0; + + return(rc); +} // FX_VoiceAvailable + + +static int doSetPan(int handle, int vol, int left, + int right, int checkIfPlaying) +{ + int retval = FX_Warning; + + if ((handle < 0) || (handle >= numChannels)) + setWarningMessage("Invalid handle in doSetPan()."); + else if ((checkIfPlaying) && (!Mix_Playing(handle))) + setWarningMessage("voice is no longer playing in doSetPan()."); + else + { + if (mixerIsStereo) + { + if ((left < 0) || (left > 255) || + (right < 0) || (right > 255)) + { + setErrorMessage("Invalid argument to FX_SetPan()."); + retval = FX_Error; + } // if + + else + { + Mix_SetPanning(handle, left, right); + } // else + } // if + else + { + if ((vol < 0) || (vol > 255)) + { + setErrorMessage("Invalid argument to FX_SetPan()."); + retval = FX_Error; + } // if + else + { + // volume must be from 0-128, so the ">> 1" converts. + Mix_Volume(handle, vol >> 1); + } // else + } // else + + retval = FX_Ok; + } // else + + return(retval); +} // doSetPan + + +int FX_SetPan(int handle, int vol, int left, int right) +{ + return(doSetPan(handle - HandleOffset, vol, left, right, 1)); +} // FX_SetPan + + +int FX_SetPitch(int handle, int pitchoffset) +{ + snddebug("FX_SetPitch() ... NOT IMPLEMENTED YET!"); + return(FX_Ok); +} // FX_SetPitch + + +int FX_SetFrequency(int handle, int frequency) +{ + snddebug("FX_SetFrequency() ... NOT IMPLEMENTED YET!"); + return(FX_Ok); +} // FX_SetFrequency + + +static Mix_Chunk *findChunkInCache(void *ptr) +{ + // !!! FIXME: Optimize! --ryan. + int i; + for (i = 0; i < CHUNK_CACHE_SIZE; i++) + { + if (chunkCache[i].dataptr == ptr) + return(chunkCache[i].chunk); + else if (chunkCache[i].dataptr == NULL) + return(NULL); + } // for + return(NULL); +} // findChunkInCache + + +static void addChunkToCache(Mix_Chunk *chunk, void *ptr) +{ + // !!! FIXME: Optimize! --ryan. + int i; + for (i = 0; i < CHUNK_CACHE_SIZE; i++) + { + if (chunkCache[i].dataptr == NULL) + { + chunkCache[i].dataptr = ptr; + chunkCache[i].chunk = chunk; + return; + } // if + } // for + + snddebug("overflowed chunk cache!"); + assert(0); // !!! FIXME. +} // addChunkToCache + + +// If this returns FX_Ok, then chunk and chan will be filled with the +// the block of audio data in the format desired by the audio device +// and the SDL_mixer channel it will play on, respectively. +// If the value is not FX_Ok, then the warning or error message is set, +// and you should bail. +// size added by SBF for ROTT +static int setupVocPlayback(char *ptr, int size, int priority, unsigned long callbackval, + int *chan, Mix_Chunk **chunk) +{ + SDL_RWops *rw; + + *chan = grabMixerChannel(priority); + if (*chan == -1) + { + setErrorMessage("No available channels"); + return(FX_Error); + } // if + + *chunk = findChunkInCache(ptr); + if (*chunk == NULL) + { + if (size == -1) { + // !!! FIXME: This could be a problem...SDL/SDL_mixer wants a RWops, which + // !!! FIXME: is an i/o abstraction. Since we already have the VOC data + // !!! FIXME: in memory, we fake it with a memory-based RWops. None of + // !!! FIXME: this is a problem, except the RWops wants to know how big + // !!! FIXME: its memory block is (so it can do things like seek on an + // !!! FIXME: offset from the end of the block), and since we don't have + // !!! FIXME: this information, we have to give it SOMETHING. My VOC + // !!! FIXME: decoder never does seeks from EOF, nor checks for + // !!! FIXME: end-of-file, so we should be fine. However, we've got a + // !!! FIXME: limit of 10 megs for one file. I hope that'll cover it. :) + + rw = SDL_RWFromMem((void *) ptr, (10 * 1024) * 1024); /* yikes. */ + } else { + // A valid file size! Excellent. + rw = SDL_RWFromMem((void *) ptr, size); + } + + *chunk = Mix_LoadWAV_RW(rw, 1); + if (*chunk == NULL) + { + setErrorMessage("Couldn't decode voice sample."); + chaninfo[*chan].in_use = 0; + return(FX_Error); + } // if + + addChunkToCache(*chunk, (void *) ptr); + } // if + chaninfo[*chan].callbackval = callbackval; + return(FX_Ok); +} // setupVocPlayback + +static int _FX_SetPosition(int chan, int angle, int distance) +{ + int left; + int right; + int mid; + int volume; + int status; + + if ( distance < 0 ) { + distance = -distance; + angle += MV_NumPanPositions / 2; + } + + volume = MIX_VOLUME( distance ); + + // Ensure angle is within 0 - 31 + angle &= MV_MaxPanPosition; + + left = MV_PanTable[ angle ][ volume ].left; + right = MV_PanTable[ angle ][ volume ].right; + mid = max( 0, 255 - distance ); + + status = doSetPan( chan, mid, left, right, 0 ); + + return status; +} + +int FX_PlayVOC(char *ptr, int pitchoffset, + int vol, int left, int right, + int priority, unsigned long callbackval) +{ + int rc; + int chan; + Mix_Chunk *chunk; + + snddebug("Playing voice: mono (%d), left (%d), right (%d), priority (%d).\n", + vol, left, right, priority); + + rc = setupVocPlayback(ptr, -1, priority, callbackval, &chan, &chunk); + if (rc != FX_Ok) + return(rc); + + // !!! FIXME: Need to do something with pitchoffset. + + rc = doSetPan(chan, vol, left, right, 0); + if (rc != FX_Ok) + { + chaninfo[chan].in_use = 0; + return(rc); + } // if + + Mix_PlayChannel(chan, chunk, 0); + return(HandleOffset + chan); +} // FX_PlayVOC + + +// get the size of a single sample, in bytes. +static int getSampleSize(void) +{ + Uint16 format; + int channels; + + Mix_QuerySpec(NULL, &format, &channels); + return( ((format & 0xFF) / 8) * channels ); +} // getSampleSize + + +int FX_PlayLoopedVOC(char *ptr, long loopstart, long loopend, + int pitchoffset, int vol, int left, int right, int priority, + unsigned long callbackval) +{ + int rc; + int chan; + int samplesize = getSampleSize(); + Uint32 totalsamples; + Mix_Chunk *chunk; + + snddebug("Playing voice: mono (%d), left (%d), right (%d), priority (%d).\n", + vol, left, right, priority); + snddebug("Looping: start (%ld), end (%ld).\n", loopstart, loopend); + + rc = setupVocPlayback(ptr, -1, priority, callbackval, &chan, &chunk); + if (rc != FX_Ok) + return(rc); + + // !!! FIXME: Need to do something with pitchoffset. + + totalsamples = chunk->alen / samplesize; + + if ((loopstart >= 0) && ((unsigned int)loopstart < totalsamples)) + { + if (loopend < 0) loopend = 0; + if ((unsigned int)loopend > totalsamples) loopend = totalsamples; + + if (loopend < loopstart) + { + Mix_FreeChunk(chunk); + chaninfo[chan].in_use = 0; + setErrorMessage("Loop end is before loop start."); + return(FX_Error); + } // if + + chunk->alen = loopend * samplesize; + + if (loopstart > 0) + { + loopstart *= samplesize; + memcpy(chunk->abuf, ((Uint8 *) chunk->abuf) + loopstart, + chunk->alen - loopstart); + chunk->alen -= loopstart; + } // if + } // if + + Mix_PlayChannel(chan, chunk, -1); /* -1 == looping. */ + return(HandleOffset + chan); +} // FX_PlayLoopedVOC + +int FX_PlayVOC3D(char *ptr, int pitchoffset, int angle, int distance, + int priority, unsigned long callbackval) +{ + int rc; + int chan; + Mix_Chunk *chunk; + + snddebug("Playing voice at angle (%d), distance (%d), priority (%d).\n", + angle, distance, priority); + + rc = setupVocPlayback(ptr, -1, priority, callbackval, &chan, &chunk); + if (rc != FX_Ok) + return(rc); + + // !!! FIXME: Need to do something with pitchoffset. + + _FX_SetPosition(chan, angle, distance); + + Mix_PlayChannel(chan, chunk, 0); + return(HandleOffset + chan); +} // FX_PlayVOC3D + +// ROTT Special - SBF +int FX_PlayVOC3D_ROTT(char *ptr, int size, int pitchoffset, int angle, int distance, + int priority, unsigned long callbackval) +{ + int rc; + int chan; + Mix_Chunk *chunk; + + snddebug("Playing voice at angle (%d), distance (%d), priority (%d).\n", + angle, distance, priority); + + rc = setupVocPlayback(ptr, size, priority, callbackval, &chan, &chunk); + if (rc != FX_Ok) + return(rc); + + // !!! FIXME: Need to do something with pitchoffset. + + _FX_SetPosition(chan, angle, distance); + + Mix_PlayChannel(chan, chunk, 0); + + return(HandleOffset + chan); +} // FX_PlayVOC3D_ROTT + + + // it's all the same to SDL_mixer. :) +int FX_PlayWAV( char *ptr, int pitchoffset, int vol, int left, int right, + int priority, unsigned long callbackval ) +{ + return(FX_PlayVOC(ptr, pitchoffset, vol, left, right, priority, callbackval)); +} // FX_PlayWAV + + +int FX_PlayLoopedWAV( char *ptr, long loopstart, long loopend, + int pitchoffset, int vol, int left, int right, int priority, + unsigned long callbackval ) +{ + return(FX_PlayLoopedVOC(ptr, loopstart, loopend, pitchoffset, vol, left, + right, priority, callbackval)); +} // FX_PlayLoopedWAV + + +int FX_PlayWAV3D( char *ptr, int pitchoffset, int angle, int distance, + int priority, unsigned long callbackval ) +{ + return(FX_PlayVOC3D(ptr, pitchoffset, angle, distance, priority, callbackval)); +} // FX_PlayWAV3D + +// ROTT Special - SBF +int FX_PlayWAV3D_ROTT( char *ptr, int size, int pitchoffset, int angle, int distance, + int priority, unsigned long callbackval ) +{ + return(FX_PlayVOC3D_ROTT(ptr, size, pitchoffset, angle, distance, priority, callbackval)); +} // FX_PlayWAV3D_ROTT + + +int FX_PlayRaw( char *ptr, unsigned long length, unsigned rate, + int pitchoffset, int vol, int left, int right, int priority, + unsigned long callbackval ) +{ + setErrorMessage("FX_PlayRaw() ... NOT IMPLEMENTED!"); + return(FX_Error); +} // FX_PlayRaw + + +int FX_PlayLoopedRaw( char *ptr, unsigned long length, char *loopstart, + char *loopend, unsigned rate, int pitchoffset, int vol, int left, + int right, int priority, unsigned long callbackval ) +{ + setErrorMessage("FX_PlayLoopedRaw() ... NOT IMPLEMENTED!"); + return(FX_Error); +} // FX_PlayLoopedRaw + + +int FX_Pan3D(int handle, int angle, int distance) +{ + int retval = FX_Warning; + + handle -= HandleOffset; + + if ((handle < 0) || (handle >= numChannels)) + setWarningMessage("Invalid handle in FX_Pan3D()."); + else if (!Mix_Playing(handle)) + setWarningMessage("voice is no longer playing in FX_Pan3D()."); + else + { + _FX_SetPosition(handle, angle, distance); + + retval = FX_Ok; + } // else + + return(retval); +} // FX_Pan3D + + +int FX_SoundActive(int handle) +{ + handle -= HandleOffset; + + if (chaninfo == NULL) + return(__FX_FALSE); + + if ((handle < 0) || (handle >= numChannels)) + { + setWarningMessage("Invalid handle in FX_SoundActive()."); + return(__FX_FALSE); + } // if + + return(chaninfo[handle].in_use != 0); +} // FX_SoundActive + + +int FX_SoundsPlaying(void) +{ + return(Mix_Playing(-1)); +} // FX_SoundsPlaying + + +int FX_StopSound(int handle) +{ + int retval = FX_Ok; + + snddebug("explicitly halting channel (%d).", handle); + // !!! FIXME: Should the user callback fire for this? + + handle -= HandleOffset; + + if ((handle < 0) || (handle >= numChannels)) + { + setWarningMessage("Invalid handle in FX_Pan3D()."); + retval = FX_Warning; + } // if + else + { + Mix_HaltChannel(handle); + } // else + + return(retval); +} // FX_StopSound + + +int FX_StopAllSounds(void) +{ + snddebug("halting all channels."); + // !!! FIXME: Should the user callback fire for this? + Mix_HaltGroup(-1); + return(FX_Ok); +} // FX_StopAllSounds + + +int FX_StartDemandFeedPlayback( void ( *function )( char **ptr, unsigned long *length ), + int rate, int pitchoffset, int vol, int left, int right, + int priority, unsigned long callbackval ) +{ + setErrorMessage("FX_StartDemandFeedPlayback() ... NOT IMPLEMENTED!"); + return(FX_Error); +} + + +int FX_StartRecording(int MixRate, void (*function)(char *ptr, int length)) +{ + setErrorMessage("FX_StartRecording() ... NOT IMPLEMENTED!"); + return(FX_Error); +} // FX_StartRecording + + +void FX_StopRecord( void ) +{ + setErrorMessage("FX_StopRecord() ... NOT IMPLEMENTED!"); +} // FX_StopRecord + + + +// The music functions... + + +char *MUSIC_ErrorString(int ErrorNumber) +{ + switch (ErrorNumber) + { + case MUSIC_Warning: + return(warningMessage); + + case MUSIC_Error: + return(errorMessage); + + case MUSIC_Ok: + return("OK; no error."); + + case MUSIC_ASSVersion: + return("Incorrect sound library version."); + + case MUSIC_SoundCardError: + return("General sound card error."); + + case MUSIC_InvalidCard: + return("Invalid sound card."); + + case MUSIC_MidiError: + return("MIDI error."); + + case MUSIC_MPU401Error: + return("MPU401 error."); + + case MUSIC_TaskManError: + return("Task Manager error."); + + case MUSIC_FMNotDetected: + return("FM not detected error."); + + case MUSIC_DPMI_Error: + return("DPMI error."); + + default: + return("Unknown error."); + } // switch + + assert(0); // shouldn't hit this point. + return(NULL); +} // MUSIC_ErrorString + + +static int music_initialized = 0; +static int music_context = 0; +static int music_loopflag = MUSIC_PlayOnce; +static char *music_songdata = NULL; +static Mix_Music *music_musicchunk = NULL; + +int MUSIC_Init(int SoundCard, int Address) +{ + init_debugging(); + + // eukara: MIDI support. + Mix_Init(MIX_INIT_MID); + Mix_SetMusicCMD("timidity"); + puts("Music initialized.\n"); + music_initialized = 1; + return(MUSIC_Ok); +} // MUSIC_Init + + +int MUSIC_Shutdown(void) +{ + musdebug("shutting down sound subsystem."); + + if (!music_initialized) + { + setErrorMessage("Music system is not currently initialized."); + return(MUSIC_Error); + } // if + + MUSIC_StopSong(); + music_context = 0; + music_initialized = 0; + music_loopflag = MUSIC_PlayOnce; + + return(MUSIC_Ok); +} // MUSIC_Shutdown + + +void MUSIC_SetMaxFMMidiChannel(int channel) +{ + musdebug("STUB ... MUSIC_SetMaxFMMidiChannel(%d).\n", channel); +} // MUSIC_SetMaxFMMidiChannel + + +void MUSIC_SetVolume(int volume) +{ + Mix_VolumeMusic(volume >> 1); // convert 0-255 to 0-128. +} // MUSIC_SetVolume + + +void MUSIC_SetMidiChannelVolume(int channel, int volume) +{ + musdebug("STUB ... MUSIC_SetMidiChannelVolume(%d, %d).\n", channel, volume); +} // MUSIC_SetMidiChannelVolume + + +void MUSIC_ResetMidiChannelVolumes(void) +{ + musdebug("STUB ... MUSIC_ResetMidiChannelVolumes().\n"); +} // MUSIC_ResetMidiChannelVolumes + + +int MUSIC_GetVolume(void) +{ + return(Mix_VolumeMusic(-1) << 1); // convert 0-128 to 0-255. +} // MUSIC_GetVolume + + +void MUSIC_SetLoopFlag(int loopflag) +{ + music_loopflag = loopflag; +} // MUSIC_SetLoopFlag + + +int MUSIC_SongPlaying(void) +{ + return((Mix_PlayingMusic()) ? __FX_TRUE : __FX_FALSE); +} // MUSIC_SongPlaying + + +void MUSIC_Continue(void) +{ + if (Mix_PausedMusic()) + Mix_ResumeMusic(); + else if (music_songdata) + MUSIC_PlaySong(music_songdata, MUSIC_PlayOnce); +} // MUSIC_Continue + + +void MUSIC_Pause(void) +{ + Mix_PauseMusic(); +} // MUSIC_Pause + + +int MUSIC_StopSong(void) +{ + if (!fx_initialized) + { + setErrorMessage("Need FX system initialized, too. Sorry."); + return(MUSIC_Error); + } // if + + if ( (Mix_PlayingMusic()) || (Mix_PausedMusic()) ) + Mix_HaltMusic(); + + if (music_musicchunk) + Mix_FreeMusic(music_musicchunk); + + music_songdata = NULL; + music_musicchunk = NULL; + return(MUSIC_Ok); +} // MUSIC_StopSong + + +int MUSIC_PlaySong(unsigned char *song, int loopflag) +{ + music_songdata = song; + + // eukara: MIDI support. + Mix_PlayMusic((Mix_Music *) song, loopflag); + + return(MUSIC_Ok); +} // MUSIC_PlaySong + + +extern char ApogeePath[256]; + +// Duke3D-specific. --ryan. +void PlayMusic(char *_filename) +{ + //char filename[MAX_PATH]; + //strcpy(filename, _filename); + //FixFilePath(filename); + + char filename[MAX_PATH]; + long handle; + long size; + void *song; + long rc; + + MUSIC_StopSong(); + + // Read from a groupfile, write it to disk so SDL_mixer can read it. + // Lame. --ryan. + handle = kopen4load(_filename, 0); + if (handle == -1) + return; + + size = kfilelength(handle); + if (size == -1) + { + kclose(handle); + return; + } // if + + song = malloc(size); + if (song == NULL) + { + kclose(handle); + return; + } // if + + rc = kread(handle, song, size); + kclose(handle); + if (rc != size) + { + free(song); + return; + } // if + + // save the file somewhere, so SDL_mixer can load it + //GetPathFromEnvironment(filename, ApogeePath, "tmpsong.mid"); + puts("Write temp midi file to homedir/.duke3d"); + handle = SafeOpenWrite("tmpsong.mid", filetype_binary); + + SafeWrite(handle, song, size); + close(handle); + free(song); + + //music_songdata = song; + + music_musicchunk = Mix_LoadMUS("tmpsong.mid"); + if (music_musicchunk != NULL) + { + // !!! FIXME: I set the music to loop. Hope that's okay. --ryan. + Mix_PlayMusic(music_musicchunk, -1); + } // if +} + + +#if ROTT +// ROTT Special - SBF +int MUSIC_PlaySongROTT(unsigned char *song, int size, int loopflag) +{ + char filename[MAX_PATH]; + int handle; + + MUSIC_StopSong(); + + // save the file somewhere, so SDL_mixer can load it + GetPathFromEnvironment(filename, ApogeePath, "tmpsong.mid"); + handle = SafeOpenWrite(filename); + + SafeWrite(handle, song, size); + close(handle); + + music_songdata = song; + + // finally, we can load it with SDL_mixer + music_musicchunk = Mix_LoadMUS(filename); + if (music_musicchunk == NULL) { + return MUSIC_Error; + } + + Mix_PlayMusic(music_musicchunk, (loopflag == MUSIC_PlayOnce) ? 0 : -1); + + return(MUSIC_Ok); +} // MUSIC_PlaySongROTT +#endif + + +void MUSIC_SetContext(int context) +{ + musdebug("STUB ... MUSIC_SetContext().\n"); + music_context = context; +} // MUSIC_SetContext + + +int MUSIC_GetContext(void) +{ + return(music_context); +} // MUSIC_GetContext + + +void MUSIC_SetSongTick(unsigned long PositionInTicks) +{ + musdebug("STUB ... MUSIC_SetSongTick().\n"); +} // MUSIC_SetSongTick + + +void MUSIC_SetSongTime(unsigned long milliseconds) +{ + musdebug("STUB ... MUSIC_SetSongTime().\n"); +}// MUSIC_SetSongTime + + +void MUSIC_SetSongPosition(int measure, int beat, int tick) +{ + musdebug("STUB ... MUSIC_SetSongPosition().\n"); +} // MUSIC_SetSongPosition + + +void MUSIC_GetSongPosition(songposition *pos) +{ + musdebug("STUB ... MUSIC_GetSongPosition().\n"); +} // MUSIC_GetSongPosition + + +void MUSIC_GetSongLength(songposition *pos) +{ + musdebug("STUB ... MUSIC_GetSongLength().\n"); +} // MUSIC_GetSongLength + + +int MUSIC_FadeVolume(int tovolume, int milliseconds) +{ + Mix_FadeOutMusic(milliseconds); + return(MUSIC_Ok); +} // MUSIC_FadeVolume + + +int MUSIC_FadeActive(void) +{ + return((Mix_FadingMusic() == MIX_FADING_OUT) ? __FX_TRUE : __FX_FALSE); +} // MUSIC_FadeActive + + +void MUSIC_StopFade(void) +{ + musdebug("STUB ... MUSIC_StopFade().\n"); +} // MUSIC_StopFade + + +void MUSIC_RerouteMidiChannel(int channel, int cdecl function( int event, int c1, int c2 )) +{ + musdebug("STUB ... MUSIC_RerouteMidiChannel().\n"); +} // MUSIC_RerouteMidiChannel + + +void MUSIC_RegisterTimbreBank(unsigned char *timbres) +{ + musdebug("STUB ... MUSIC_RegisterTimbreBank().\n"); +} // MUSIC_RegisterTimbreBank + + +// end of fx_man.c ... diff --git a/fx_man.h b/fx_man.h new file mode 100755 index 0000000..ca052a3 --- /dev/null +++ b/fx_man.h @@ -0,0 +1,136 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment + +This file is part of Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Original Source: 1994 - Jim Dose +Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms +*/ +//------------------------------------------------------------------------- + +#ifndef __FX_MAN_H +#define __FX_MAN_H + +#include "sndcards.h" + +typedef struct + { + long MaxVoices; + long MaxSampleBits; + long MaxChannels; + } fx_device; + +#define MonoFx 1 +#define StereoFx 2 + +typedef struct + { + unsigned long Address; + unsigned long Type; + unsigned long Interrupt; + unsigned long Dma8; + unsigned long Dma16; + unsigned long Midi; + unsigned long Emu; + } fx_blaster_config; + +enum FX_ERRORS + { + FX_Warning = -2, + FX_Error = -1, + FX_Ok = 0, + FX_ASSVersion, + FX_BlasterError, + FX_SoundCardError, + FX_InvalidCard, + FX_MultiVocError, + FX_DPMI_Error + }; + +enum fx_BLASTER_Types + { + fx_SB = 1, + fx_SBPro = 2, + fx_SB20 = 3, + fx_SBPro2 = 4, + fx_SB16 = 6 + }; + + +char *FX_ErrorString( int ErrorNumber ); +int FX_SetupCard( int SoundCard, fx_device *device ); +int FX_GetBlasterSettings( fx_blaster_config *blaster ); +int FX_SetupSoundBlaster( fx_blaster_config blaster, int *MaxVoices, int *MaxSampleBits, int *MaxChannels ); +int FX_Init( int SoundCard, int numvoices, int numchannels, int samplebits, unsigned mixrate ); +int FX_Shutdown( void ); +int FX_SetCallBack( void ( *function )( unsigned long ) ); +void FX_SetVolume( int volume ); +int FX_GetVolume( void ); + +void FX_SetReverseStereo( int setting ); +int FX_GetReverseStereo( void ); +void FX_SetReverb( int reverb ); +void FX_SetFastReverb( int reverb ); +int FX_GetMaxReverbDelay( void ); +int FX_GetReverbDelay( void ); +void FX_SetReverbDelay( int delay ); + +int FX_VoiceAvailable( int priority ); +int FX_SetPan( int handle, int vol, int left, int right ); +int FX_SetPitch( int handle, int pitchoffset ); +int FX_SetFrequency( int handle, int frequency ); + +int FX_PlayVOC( char *ptr, int pitchoffset, int vol, int left, int right, + int priority, unsigned long callbackval ); +int FX_PlayLoopedVOC( char *ptr, long loopstart, long loopend, + int pitchoffset, int vol, int left, int right, int priority, + unsigned long callbackval ); +int FX_PlayWAV( char *ptr, int pitchoffset, int vol, int left, int right, + int priority, unsigned long callbackval ); +int FX_PlayLoopedWAV( char *ptr, long loopstart, long loopend, + int pitchoffset, int vol, int left, int right, int priority, + unsigned long callbackval ); +int FX_PlayVOC3D( char *ptr, int pitchoffset, int angle, int distance, + int priority, unsigned long callbackval ); +int FX_PlayWAV3D( char *ptr, int pitchoffset, int angle, int distance, + int priority, unsigned long callbackval ); +int FX_PlayRaw( char *ptr, unsigned long length, unsigned rate, + int pitchoffset, int vol, int left, int right, int priority, + unsigned long callbackval ); +int FX_PlayLoopedRaw( char *ptr, unsigned long length, char *loopstart, + char *loopend, unsigned rate, int pitchoffset, int vol, int left, + int right, int priority, unsigned long callbackval ); +int FX_Pan3D( int handle, int angle, int distance ); +int FX_SoundActive( int handle ); +int FX_SoundsPlaying( void ); +int FX_StopSound( int handle ); +int FX_StopAllSounds( void ); +int FX_StartDemandFeedPlayback( void ( *function )( char **ptr, unsigned long *length ), + int rate, int pitchoffset, int vol, int left, int right, + int priority, unsigned long callbackval ); +int FX_StartRecording( int MixRate, void ( *function )( char *ptr, int length ) ); +void FX_StopRecord( void ); +void PlayMusic(char *_filename); + +// API addition: Call this when you reload/ditch a pile of sound effects. +// (mapchange? Dunno if duke3d blindly loads all sounds at startup). +// Implicitly stops all playing sounds and music. --ryan. +void FX_CleanCache(void); + +#endif diff --git a/game.c b/game.c new file mode 100755 index 0000000..707f09f --- /dev/null +++ b/game.c @@ -0,0 +1,10008 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment + +This file is part of Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Original Source: 1996 - Todd Replogle +Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms +*/ +//------------------------------------------------------------------------- + +#include "types.h" +#include "develop.h" +#include "scriplib.h" +#include "file_lib.h" +#include "gamedefs.h" +#include "keyboard.h" +#include "util_lib.h" +#include "function.h" +#include "control.h" +#include "fx_man.h" +#include "sounds.h" +#include "config.h" +#include "sndcards.h" + +#include "duke3d.h" + +#include +#include + +#ifdef VOLUMEONE + #define VERSION "1.4" +#else + #define VERSION "1.4" +#endif + +#define HEAD "Duke Nukem 3D Unregistered Shareware v"VERSION" " +#ifdef PLUTOPAK +#define HEAD2 "Duke Nukem 3D v"VERSION" - Atomic Edition" +#else +#define HEAD2 "Duke Nukem 3D Full Version v"VERSION +#endif +#define HEADA "Duke Nukem 3D AUSSIE Unregistered Shareware v"VERSION +#define HEAD2A "Duke Nukem 3D AUSSIE Full Version v"VERSION + +#define IDFSIZE 479985668 +// #define IDFSIZE 9961476 +// #define IDFSIZE 16384 +#define IDFILENAME "DUKE3D.IDF" + +#define TIMERUPDATESIZ 32 + +/* this should be a proper prototype included from a header file */ +extern int stricmp(const char *x, const char *y); + +long cameradist = 0, cameraclock = 0; +char eightytwofifty = 0; +char playerswhenstarted; +char qe,cp; + +int32 CommandSoundToggleOff = 0; +int32 CommandMusicToggleOff = 0; + +char confilename[128] = {"GAME.CON"},boardfilename[128] = {0}; +char waterpal[768], slimepal[768], titlepal[768], drealms[768], endingpal[768]; +char firstdemofile[80] = { '\0' }; + +#define patchstatusbar(x1,y1,x2,y2) \ +{ \ + rotatesprite(0,(200-34)<<16,65536L,0,BOTTOMSTATUSBAR,4,0,10+16+64+128, \ + scale(x1,xdim,320),scale(y1,ydim,200), \ + scale(x2,xdim,320)-1,scale(y2,ydim,200)-1); \ +} + +void __interrupt __far newint24( int errval, int ax, int bp, int si ); + +int recfilep,totalreccnt; +char debug_on = 0,actor_tog = 0,*rtsptr,memorycheckoveride=0; + + + +extern char syncstate; +extern int32 numlumps; + +FILE *frecfilep = (FILE *)NULL; +void pitch_test( void ); + +char restorepalette,screencapt,nomorelogohack; +int sendmessagecommand = -1; + +task *TimerPtr=NULL; + +extern long lastvisinc; + +// Build Engine port implements this. --ryan. +#if PLATFORM_DOS +static void timerhandler(task *unused) +{ + totalclock++; +} + +void inittimer() +{ + TimerPtr = TS_ScheduleTask( timerhandler,TICRATE, 1, NULL ); + TS_Dispatch(); +} + +void uninittimer(void) +{ + if (TimerPtr) + TS_Terminate( TimerPtr ); + TimerPtr = NULL; + TS_Shutdown(); +} +#else +void timerhandler(void) +{ + totalclock++; +} +#endif + +int gametext(int x,int y,char *t,char s,short dabits) +{ + short ac,newx; + char centre, *oldt; + + centre = ( x == (320>>1) ); + newx = 0; + oldt = t; + + if(centre) + { + while(*t) + { + if(*t == 32) {newx+=5;t++;continue;} + else ac = *t - '!' + STARTALPHANUM; + + if( ac < STARTALPHANUM || ac > ENDALPHANUM ) break; + + if(*t >= '0' && *t <= '9') + newx += 8; + else newx += tilesizx[ac]; + t++; + } + + t = oldt; + x = (320>>1)-(newx>>1); + } + + while(*t) + { + if(*t == 32) {x+=5;t++;continue;} + else ac = *t - '!' + STARTALPHANUM; + + if( ac < STARTALPHANUM || ac > ENDALPHANUM ) + break; + + rotatesprite(x<<16,y<<16,65536L,0,ac,s,0,dabits,0,0,xdim-1,ydim-1); + + if(*t >= '0' && *t <= '9') + x += 8; + else x += tilesizx[ac]; + + t++; + } + + return (x); +} + +int gametextpal(int x,int y,char *t,char s,char p) +{ + short ac,newx; + char centre, *oldt; + + centre = ( x == (320>>1) ); + newx = 0; + oldt = t; + + if(centre) + { + while(*t) + { + if(*t == 32) {newx+=5;t++;continue;} + else ac = *t - '!' + STARTALPHANUM; + + if( ac < STARTALPHANUM || ac > ENDALPHANUM ) break; + + if(*t >= '0' && *t <= '9') + newx += 8; + else newx += tilesizx[ac]; + t++; + } + + t = oldt; + x = (320>>1)-(newx>>1); + } + + while(*t) + { + if(*t == 32) {x+=5;t++;continue;} + else ac = *t - '!' + STARTALPHANUM; + + if( ac < STARTALPHANUM || ac > ENDALPHANUM ) + break; + + rotatesprite(x<<16,y<<16,65536L,0,ac,s,p,2+8+16,0,0,xdim-1,ydim-1); + if(*t >= '0' && *t <= '9') + x += 8; + else x += tilesizx[ac]; + + t++; + } + + return (x); +} + +int gametextpart(int x,int y,char *t,char s,short p) +{ + short ac,newx, cnt; + char centre, *oldt; + + centre = ( x == (320>>1) ); + newx = 0; + oldt = t; + cnt = 0; + + if(centre) + { + while(*t) + { + if(cnt == p) break; + + if(*t == 32) {newx+=5;t++;continue;} + else ac = *t - '!' + STARTALPHANUM; + + if( ac < STARTALPHANUM || ac > ENDALPHANUM ) break; + + newx += tilesizx[ac]; + t++; + cnt++; + + } + + t = oldt; + x = (320>>1)-(newx>>1); + } + + cnt = 0; + while(*t) + { + if(*t == 32) {x+=5;t++;continue;} + else ac = *t - '!' + STARTALPHANUM; + + if( ac < STARTALPHANUM || ac > ENDALPHANUM ) break; + + if(cnt == p) + { + rotatesprite(x<<16,y<<16,65536L,0,ac,s,1,2+8+16,0,0,xdim-1,ydim-1); + break; + } + else + rotatesprite(x<<16,y<<16,65536L,0,ac,s,0,2+8+16,0,0,xdim-1,ydim-1); + + x += tilesizx[ac]; + + t++; + cnt++; + } + + return (x); +} + +int minitext(int x,int y,char *str,char p,char sb) +{ + short ac; + char buf[128]; + char *t; + + strncpy (buf, str, 128); + buf[127] = 0; + t = buf; + + while(*t) + { + *t = toupper(*t); + if(*t == 32) {x+=5;t++;continue;} + else ac = *t - '!' + MINIFONT; + + rotatesprite(x<<16,y<<16,65536L,0,ac,0,p,sb,0,0,xdim-1,ydim-1); + x += 4; // tilesizx[ac]+1; + + t++; + } + return (x); +} + +int minitextshade(int x,int y,char *str,char s,char p,char sb) +{ + short ac; + char buf[128]; + char *t; + + strncpy (buf, str, 128); + buf[127] = 0; + t = buf; + + while(*t) + { + *t = toupper(*t); + if(*t == 32) {x+=5;t++;continue;} + else ac = *t - '!' + MINIFONT; + + rotatesprite(x<<16,y<<16,65536L,0,ac,s,p,sb,0,0,xdim-1,ydim-1); + x += 4; // tilesizx[ac]+1; + + t++; + } + return (x); +} + +void gamenumber(long x,long y,long n,char s) +{ + char b[10]; + ltoa(n,b,10); + gametext(x,y,b,s,2+8+16); +} + + +char recbuf[80]; +void allowtimetocorrecterrorswhenquitting(void) +{ + long i, j, oldtotalclock; + + ready2send = 0; + + for(j=0;j<8;j++) + { + oldtotalclock = totalclock; + + while (totalclock < oldtotalclock+TICSPERFRAME) + getpackets(); + + if(KB_KeyPressed(sc_Escape)) return; + + packbuf[0] = 127; + for(i=connecthead;i>=0;i=connectpoint2[i]) + if (i != myconnectindex) + sendpacket(i,packbuf,1); + } +} + +#define MAXUSERQUOTES 4 +long quotebot, quotebotgoal; +short user_quote_time[MAXUSERQUOTES]; +char user_quote[MAXUSERQUOTES][128]; +// char typebuflen,typebuf[41]; + +static void adduserquote(char *daquote) +{ + long i; + + for(i=MAXUSERQUOTES-1;i>0;i--) + { + strcpy(user_quote[i],user_quote[i-1]); + user_quote_time[i] = user_quote_time[i-1]; + } + strcpy(user_quote[0],daquote); + user_quote_time[0] = 180; + pub = NUMPAGES; +} + + +void getpackets(void) +{ + long i, j, k, l; + FILE *fp; + short other, packbufleng; + input *osyn, *nsyn; + + if(qe == 0 && KB_KeyPressed(sc_LeftControl) && KB_KeyPressed(sc_LeftAlt) && KB_KeyPressed(sc_Delete)) + { + qe = 1; + gameexit("Quick Exit."); + } + + if (numplayers < 2) return; + while ((packbufleng = getpacket(&other,packbuf)) > 0) + { + switch(packbuf[0]) + { + case 125: + cp = 0; + break; + + case 126: + multiflag = 2; + multiwhat = 0; + multiwho = other; + multipos = packbuf[1]; + loadplayer( multipos ); + multiflag = 0; + break; + case 0: //[0] (receive master sync buffer) + j = 1; + + if ((movefifoend[other]&(TIMERUPDATESIZ-1)) == 0) + for(i=connectpoint2[connecthead];i>=0;i=connectpoint2[i]) + { + if (playerquitflag[i] == 0) continue; + if (i == myconnectindex) + otherminlag = (long)((signed char)packbuf[j]); + j++; + } + + osyn = (input *)&inputfifo[(movefifoend[connecthead]-1)&(MOVEFIFOSIZ-1)][0]; + nsyn = (input *)&inputfifo[(movefifoend[connecthead])&(MOVEFIFOSIZ-1)][0]; + + k = j; + for(i=connecthead;i>=0;i=connectpoint2[i]) + j += playerquitflag[i]; + for(i=connecthead;i>=0;i=connectpoint2[i]) + { + if (playerquitflag[i] == 0) continue; + + l = packbuf[k++]; + if (i == myconnectindex) + { j += ((l&1)<<1)+(l&2)+((l&4)>>2)+((l&8)>>3)+((l&16)>>4)+((l&32)>>5)+((l&64)>>6)+((l&128)>>7); continue; } + + copybufbyte(&osyn[i],&nsyn[i],sizeof(input)); + if (l&1) nsyn[i].fvel = packbuf[j]+((short)packbuf[j+1]<<8), j += 2; + if (l&2) nsyn[i].svel = packbuf[j]+((short)packbuf[j+1]<<8), j += 2; + if (l&4) nsyn[i].avel = (signed char)packbuf[j++]; + if (l&8) nsyn[i].bits = ((nsyn[i].bits&0xffffff00)|((long)packbuf[j++])); + if (l&16) nsyn[i].bits = ((nsyn[i].bits&0xffff00ff)|((long)packbuf[j++])<<8); + if (l&32) nsyn[i].bits = ((nsyn[i].bits&0xff00ffff)|((long)packbuf[j++])<<16); + if (l&64) nsyn[i].bits = ((nsyn[i].bits&0x00ffffff)|((long)packbuf[j++])<<24); + if (l&128) nsyn[i].horz = (signed char)packbuf[j++]; + + if (nsyn[i].bits&(1<<26)) playerquitflag[i] = 0; + movefifoend[i]++; + } + + while (j != packbufleng) + { + for(i=connecthead;i>=0;i=connectpoint2[i]) + if(i != myconnectindex) + { + syncval[i][syncvalhead[i]&(MOVEFIFOSIZ-1)] = packbuf[j]; + syncvalhead[i]++; + } + j++; + } + + for(i=connecthead;i>=0;i=connectpoint2[i]) + if (i != myconnectindex) + for(j=1;j=0;i=connectpoint2[i]) + { + resetweapons(i); + resetinventory(i); + } + + newgame(ud.volume_number,ud.level_number,ud.player_skill); + ud.coop = ud.m_coop; + + enterlevel(MODE_GAME); + + break; + case 6: + if (packbuf[1] != BYTEVERSION) + gameexit("\nYou cannot play Duke with different versions."); + for (i=2;packbuf[i];i++) + ud.user_name[other][i-2] = packbuf[i]; + ud.user_name[other][i-2] = 0; + break; + case 9: + for (i=1;i=0;i=connectpoint2[i]) + { + resetweapons(i); + resetinventory(i); + } + + newgame(ud.volume_number,ud.level_number,ud.player_skill); + enterlevel(MODE_GAME); + break; + + case 16: + movefifoend[other] = movefifoplc = movefifosendplc = fakemovefifoplc = 0; + syncvalhead[other] = syncvaltottail = 0L; + case 17: + j = 1; + + if ((movefifoend[other]&(TIMERUPDATESIZ-1)) == 0) + if (other == connecthead) + for(i=connectpoint2[connecthead];i>=0;i=connectpoint2[i]) + { + if (i == myconnectindex) + otherminlag = (long)((signed char)packbuf[j]); + j++; + } + + osyn = (input *)&inputfifo[(movefifoend[other]-1)&(MOVEFIFOSIZ-1)][0]; + nsyn = (input *)&inputfifo[(movefifoend[other])&(MOVEFIFOSIZ-1)][0]; + + copybufbyte(&osyn[other],&nsyn[other],sizeof(input)); + k = packbuf[j++]; + if (k&1) nsyn[other].fvel = packbuf[j]+((short)packbuf[j+1]<<8), j += 2; + if (k&2) nsyn[other].svel = packbuf[j]+((short)packbuf[j+1]<<8), j += 2; + if (k&4) nsyn[other].avel = (signed char)packbuf[j++]; + if (k&8) nsyn[other].bits = ((nsyn[other].bits&0xffffff00)|((long)packbuf[j++])); + if (k&16) nsyn[other].bits = ((nsyn[other].bits&0xffff00ff)|((long)packbuf[j++])<<8); + if (k&32) nsyn[other].bits = ((nsyn[other].bits&0xff00ffff)|((long)packbuf[j++])<<16); + if (k&64) nsyn[other].bits = ((nsyn[other].bits&0x00ffffff)|((long)packbuf[j++])<<24); + if (k&128) nsyn[other].horz = (signed char)packbuf[j++]; + movefifoend[other]++; + + for(i=1;i packbufleng) + printf("INVALID GAME PACKET!!! (%ld too many bytes)\n",j-packbufleng); + + while (j != packbufleng) + { + syncval[other][syncvalhead[other]&(MOVEFIFOSIZ-1)] = packbuf[j++]; + syncvalhead[other]++; + } + + break; + case 127: + break; + + case 250: + playerreadyflag[other]++; + break; + case 255: + gameexit(" "); + break; + } + } +} + +void faketimerhandler() +{ + long i, j, k, l; +// short who; + input *osyn, *nsyn; + + if(qe == 0 && KB_KeyPressed(sc_LeftControl) && KB_KeyPressed(sc_LeftAlt) && KB_KeyPressed(sc_Delete)) + { + qe = 1; + gameexit("Quick Exit."); + } + + if ((totalclock < ototalclock+TICSPERFRAME) || (ready2send == 0)) return; + ototalclock += TICSPERFRAME; + + getpackets(); if (getoutputcirclesize() >= 16) return; + + for(i=connecthead;i>=0;i=connectpoint2[i]) + if (i != myconnectindex) + if (movefifoend[i] < movefifoend[myconnectindex]-200) return; + + getinput(myconnectindex); + + avgfvel += loc.fvel; + avgsvel += loc.svel; + avgavel += loc.avel; + avghorz += loc.horz; + avgbits |= loc.bits; + if (movefifoend[myconnectindex]&(movesperpacket-1)) + { + copybufbyte(&inputfifo[(movefifoend[myconnectindex]-1)&(MOVEFIFOSIZ-1)][myconnectindex], + &inputfifo[movefifoend[myconnectindex]&(MOVEFIFOSIZ-1)][myconnectindex],sizeof(input)); + movefifoend[myconnectindex]++; + return; + } + nsyn = &inputfifo[movefifoend[myconnectindex]&(MOVEFIFOSIZ-1)][myconnectindex]; + nsyn[0].fvel = avgfvel/movesperpacket; + nsyn[0].svel = avgsvel/movesperpacket; + nsyn[0].avel = avgavel/movesperpacket; + nsyn[0].horz = avghorz/movesperpacket; + nsyn[0].bits = avgbits; + avgfvel = avgsvel = avgavel = avghorz = avgbits = 0; + movefifoend[myconnectindex]++; + + if (numplayers < 2) + { + if (ud.multimode > 1) for(i=connecthead;i>=0;i=connectpoint2[i]) + if(i != myconnectindex) + { + //clearbufbyte(&inputfifo[movefifoend[i]&(MOVEFIFOSIZ-1)][i],sizeof(input),0L); + if(ud.playerai) + computergetinput(i,&inputfifo[movefifoend[i]&(MOVEFIFOSIZ-1)][i]); + movefifoend[i]++; + } + return; + } + + for(i=connecthead;i>=0;i=connectpoint2[i]) + if (i != myconnectindex) + { + k = (movefifoend[myconnectindex]-1)-movefifoend[i]; + myminlag[i] = min(myminlag[i],k); + mymaxlag = max(mymaxlag,k); + } + + if (((movefifoend[myconnectindex]-1)&(TIMERUPDATESIZ-1)) == 0) + { + i = mymaxlag-bufferjitter; mymaxlag = 0; + if (i > 0) bufferjitter += ((3+i)>>2); + else if (i < 0) bufferjitter -= ((1-i)>>2); + } + + if (networkmode == 1) + { + packbuf[0] = 17; + if ((movefifoend[myconnectindex]-1) == 0) packbuf[0] = 16; + j = 1; + + //Fix timers and buffer/jitter value + if (((movefifoend[myconnectindex]-1)&(TIMERUPDATESIZ-1)) == 0) + { + if (myconnectindex != connecthead) + { + i = myminlag[connecthead]-otherminlag; + if (klabs(i) > 8) i >>= 1; + else if (klabs(i) > 2) i = ksgn(i); + else i = 0; + + totalclock -= TICSPERFRAME*i; + myminlag[connecthead] -= i; otherminlag += i; + } + + if (myconnectindex == connecthead) + for(i=connectpoint2[connecthead];i>=0;i=connectpoint2[i]) + packbuf[j++] = min(max(myminlag[i],-128),127); + + for(i=connecthead;i>=0;i=connectpoint2[i]) + myminlag[i] = 0x7fffffff; + } + + osyn = (input *)&inputfifo[(movefifoend[myconnectindex]-2)&(MOVEFIFOSIZ-1)][myconnectindex]; + nsyn = (input *)&inputfifo[(movefifoend[myconnectindex]-1)&(MOVEFIFOSIZ-1)][myconnectindex]; + + k = j; + packbuf[j++] = 0; + + if (nsyn[0].fvel != osyn[0].fvel) + { + packbuf[j++] = (char)nsyn[0].fvel; + packbuf[j++] = (char)(nsyn[0].fvel>>8); + packbuf[k] |= 1; + } + if (nsyn[0].svel != osyn[0].svel) + { + packbuf[j++] = (char)nsyn[0].svel; + packbuf[j++] = (char)(nsyn[0].svel>>8); + packbuf[k] |= 2; + } + if (nsyn[0].avel != osyn[0].avel) + { + packbuf[j++] = (signed char)nsyn[0].avel; + packbuf[k] |= 4; + } + if ((nsyn[0].bits^osyn[0].bits)&0x000000ff) packbuf[j++] = (nsyn[0].bits&255), packbuf[k] |= 8; + if ((nsyn[0].bits^osyn[0].bits)&0x0000ff00) packbuf[j++] = ((nsyn[0].bits>>8)&255), packbuf[k] |= 16; + if ((nsyn[0].bits^osyn[0].bits)&0x00ff0000) packbuf[j++] = ((nsyn[0].bits>>16)&255), packbuf[k] |= 32; + if ((nsyn[0].bits^osyn[0].bits)&0xff000000) packbuf[j++] = ((nsyn[0].bits>>24)&255), packbuf[k] |= 64; + if (nsyn[0].horz != osyn[0].horz) + { + packbuf[j++] = (char)nsyn[0].horz; + packbuf[k] |= 128; + } + + while (syncvalhead[myconnectindex] != syncvaltail) + { + packbuf[j++] = syncval[myconnectindex][syncvaltail&(MOVEFIFOSIZ-1)]; + syncvaltail++; + } + + for(i=connecthead;i>=0;i=connectpoint2[i]) + if (i != myconnectindex) + sendpacket(i,packbuf,j); + + return; + } + if (myconnectindex != connecthead) //Slave + { + //Fix timers and buffer/jitter value + if (((movefifoend[myconnectindex]-1)&(TIMERUPDATESIZ-1)) == 0) + { + i = myminlag[connecthead]-otherminlag; + if (klabs(i) > 8) i >>= 1; + else if (klabs(i) > 2) i = ksgn(i); + else i = 0; + + totalclock -= TICSPERFRAME*i; + myminlag[connecthead] -= i; otherminlag += i; + + for(i=connecthead;i>=0;i=connectpoint2[i]) + myminlag[i] = 0x7fffffff; + } + + packbuf[0] = 1; packbuf[1] = 0; j = 2; + + osyn = (input *)&inputfifo[(movefifoend[myconnectindex]-2)&(MOVEFIFOSIZ-1)][myconnectindex]; + nsyn = (input *)&inputfifo[(movefifoend[myconnectindex]-1)&(MOVEFIFOSIZ-1)][myconnectindex]; + + if (nsyn[0].fvel != osyn[0].fvel) + { + packbuf[j++] = (char)nsyn[0].fvel; + packbuf[j++] = (char)(nsyn[0].fvel>>8); + packbuf[1] |= 1; + } + if (nsyn[0].svel != osyn[0].svel) + { + packbuf[j++] = (char)nsyn[0].svel; + packbuf[j++] = (char)(nsyn[0].svel>>8); + packbuf[1] |= 2; + } + if (nsyn[0].avel != osyn[0].avel) + { + packbuf[j++] = (signed char)nsyn[0].avel; + packbuf[1] |= 4; + } + if ((nsyn[0].bits^osyn[0].bits)&0x000000ff) packbuf[j++] = (nsyn[0].bits&255), packbuf[1] |= 8; + if ((nsyn[0].bits^osyn[0].bits)&0x0000ff00) packbuf[j++] = ((nsyn[0].bits>>8)&255), packbuf[1] |= 16; + if ((nsyn[0].bits^osyn[0].bits)&0x00ff0000) packbuf[j++] = ((nsyn[0].bits>>16)&255), packbuf[1] |= 32; + if ((nsyn[0].bits^osyn[0].bits)&0xff000000) packbuf[j++] = ((nsyn[0].bits>>24)&255), packbuf[1] |= 64; + if (nsyn[0].horz != osyn[0].horz) + { + packbuf[j++] = (char)nsyn[0].horz; + packbuf[1] |= 128; + } + + while (syncvalhead[myconnectindex] != syncvaltail) + { + packbuf[j++] = syncval[myconnectindex][syncvaltail&(MOVEFIFOSIZ-1)]; + syncvaltail++; + } + + sendpacket(connecthead,packbuf,j); + return; + } + + //This allows allow packet-resends + for(i=connecthead;i>=0;i=connectpoint2[i]) + if (movefifoend[i] <= movefifosendplc) + { + packbuf[0] = 127; + for(i=connectpoint2[connecthead];i>=0;i=connectpoint2[i]) + sendpacket(i,packbuf,1); + return; + } + + while (1) //Master + { + for(i=connecthead;i>=0;i=connectpoint2[i]) + if (playerquitflag[i] && (movefifoend[i] <= movefifosendplc)) return; + + osyn = (input *)&inputfifo[(movefifosendplc-1)&(MOVEFIFOSIZ-1)][0]; + nsyn = (input *)&inputfifo[(movefifosendplc )&(MOVEFIFOSIZ-1)][0]; + + //MASTER -> SLAVE packet + packbuf[0] = 0; j = 1; + + //Fix timers and buffer/jitter value + if ((movefifosendplc&(TIMERUPDATESIZ-1)) == 0) + { + for(i=connectpoint2[connecthead];i>=0;i=connectpoint2[i]) + if (playerquitflag[i]) + packbuf[j++] = min(max(myminlag[i],-128),127); + + for(i=connecthead;i>=0;i=connectpoint2[i]) + myminlag[i] = 0x7fffffff; + } + + k = j; + for(i=connecthead;i>=0;i=connectpoint2[i]) + j += playerquitflag[i]; + for(i=connecthead;i>=0;i=connectpoint2[i]) + { + if (playerquitflag[i] == 0) continue; + + packbuf[k] = 0; + if (nsyn[i].fvel != osyn[i].fvel) + { + packbuf[j++] = (char)nsyn[i].fvel; + packbuf[j++] = (char)(nsyn[i].fvel>>8); + packbuf[k] |= 1; + } + if (nsyn[i].svel != osyn[i].svel) + { + packbuf[j++] = (char)nsyn[i].svel; + packbuf[j++] = (char)(nsyn[i].svel>>8); + packbuf[k] |= 2; + } + if (nsyn[i].avel != osyn[i].avel) + { + packbuf[j++] = (signed char)nsyn[i].avel; + packbuf[k] |= 4; + } + if ((nsyn[i].bits^osyn[i].bits)&0x000000ff) packbuf[j++] = (nsyn[i].bits&255), packbuf[k] |= 8; + if ((nsyn[i].bits^osyn[i].bits)&0x0000ff00) packbuf[j++] = ((nsyn[i].bits>>8)&255), packbuf[k] |= 16; + if ((nsyn[i].bits^osyn[i].bits)&0x00ff0000) packbuf[j++] = ((nsyn[i].bits>>16)&255), packbuf[k] |= 32; + if ((nsyn[i].bits^osyn[i].bits)&0xff000000) packbuf[j++] = ((nsyn[i].bits>>24)&255), packbuf[k] |= 64; + if (nsyn[i].horz != osyn[i].horz) + { + packbuf[j++] = (char)nsyn[i].horz; + packbuf[k] |= 128; + } + k++; + } + + while (syncvalhead[myconnectindex] != syncvaltail) + { + packbuf[j++] = syncval[myconnectindex][syncvaltail&(MOVEFIFOSIZ-1)]; + syncvaltail++; + } + + for(i=connectpoint2[connecthead];i>=0;i=connectpoint2[i]) + if (playerquitflag[i]) + { + sendpacket(i,packbuf,j); + if (nsyn[i].bits&(1<<26)) + playerquitflag[i] = 0; + } + + movefifosendplc += movesperpacket; + } +} + +extern long cacnum; +typedef struct { long *hand, leng; char *lock; } cactype; +extern cactype cac[]; + +void caches(void) +{ + short i,k; + + k = 0; + for(i=0;i= 200) + { + sprintf(tempbuf,"Locked- %d: Leng:%ld, Lock:%d",i,cac[i].leng,*cac[i].lock); + printext256(0L,k,31,-1,tempbuf,1); k += 6; + } + + k += 6; + + for(i=1;i<11;i++) + if (lumplockbyte[i] >= 200) + { + sprintf(tempbuf,"RTS Locked %d:",i); + printext256(0L,k,31,-1,tempbuf,1); k += 6; + } + + +} + + + +void checksync(void) +{ + long i, k; + + for(i=connecthead;i>=0;i=connectpoint2[i]) + if (syncvalhead[i] == syncvaltottail) break; + if (i < 0) + { + syncstat = 0; + do + { + for(i=connectpoint2[connecthead];i>=0;i=connectpoint2[i]) + if (syncval[i][syncvaltottail&(MOVEFIFOSIZ-1)] != + syncval[connecthead][syncvaltottail&(MOVEFIFOSIZ-1)]) + syncstat = 1; + syncvaltottail++; + for(i=connecthead;i>=0;i=connectpoint2[i]) + if (syncvalhead[i] == syncvaltottail) break; + } while (i < 0); + } + if (connectpoint2[connecthead] < 0) syncstat = 0; + + if (syncstat) + { + printext256(4L,130L,31,0,"Out Of Sync - Please restart game",0); + //printext256(4L,138L,31,0,"RUN DN3DHELP.EXE for information.",0); + } + if (syncstate) + { + printext256(4L,160L,31,0,"Missed Network packet!",0); + //printext256(4L,138L,31,0,"RUN DN3DHELP.EXE for information.",0); + } +} + + +void check_fta_sounds(short i) +{ + if(sprite[i].extra > 0) switch(PN) + { + case LIZTROOPONTOILET: + case LIZTROOPJUSTSIT: + case LIZTROOPSHOOT: + case LIZTROOPJETPACK: + case LIZTROOPDUCKING: + case LIZTROOPRUNNING: + case LIZTROOP: + spritesound(PRED_RECOG,i); + break; + case LIZMAN: + case LIZMANSPITTING: + case LIZMANFEEDING: + case LIZMANJUMP: + spritesound(CAPT_RECOG,i); + break; + case PIGCOP: + case PIGCOPDIVE: + spritesound(PIG_RECOG,i); + break; + case RECON: + spritesound(RECO_RECOG,i); + break; + case DRONE: + spritesound(DRON_RECOG,i); + break; + case COMMANDER: + case COMMANDERSTAYPUT: + spritesound(COMM_RECOG,i); + break; + case ORGANTIC: + spritesound(TURR_RECOG,i); + break; + case OCTABRAIN: + case OCTABRAINSTAYPUT: + spritesound(OCTA_RECOG,i); + break; + case BOSS1: + sound(BOS1_RECOG); + break; + case BOSS2: + if(sprite[i].pal == 1) + sound(BOS2_RECOG); + else sound(WHIPYOURASS); + break; + case BOSS3: + if(sprite[i].pal == 1) + sound(BOS3_RECOG); + else sound(RIPHEADNECK); + break; + case BOSS4: + case BOSS4STAYPUT: + if(sprite[i].pal == 1) + sound(BOS4_RECOG); + sound(BOSS4_FIRSTSEE); + break; + case GREENSLIME: + spritesound(SLIM_RECOG,i); + break; + } +} + +short inventory(spritetype *s) +{ + switch(s->picnum) + { + case FIRSTAID: + case STEROIDS: + case HEATSENSOR: + case BOOTS: + case JETPACK: + case HOLODUKE: + case AIRTANK: + return 1; + } + return 0; +} + + +short badguy(spritetype *s) +{ + + switch(s->picnum) + { + case SHARK: + case RECON: + case DRONE: + case LIZTROOPONTOILET: + case LIZTROOPJUSTSIT: + case LIZTROOPSTAYPUT: + case LIZTROOPSHOOT: + case LIZTROOPJETPACK: + case LIZTROOPDUCKING: + case LIZTROOPRUNNING: + case LIZTROOP: + case OCTABRAIN: + case COMMANDER: + case COMMANDERSTAYPUT: + case PIGCOP: + case EGG: + case PIGCOPSTAYPUT: + case PIGCOPDIVE: + case LIZMAN: + case LIZMANSPITTING: + case LIZMANFEEDING: + case LIZMANJUMP: + case ORGANTIC: + case BOSS1: + case BOSS2: + case BOSS3: + case BOSS4: + case GREENSLIME: + case GREENSLIME+1: + case GREENSLIME+2: + case GREENSLIME+3: + case GREENSLIME+4: + case GREENSLIME+5: + case GREENSLIME+6: + case GREENSLIME+7: + case RAT: + case ROTATEGUN: + return 1; + } + if( actortype[s->picnum] ) return 1; + + return 0; +} + + +short badguypic(short pn) +{ + + switch(pn) + { + case SHARK: + case RECON: + case DRONE: + case LIZTROOPONTOILET: + case LIZTROOPJUSTSIT: + case LIZTROOPSTAYPUT: + case LIZTROOPSHOOT: + case LIZTROOPJETPACK: + case LIZTROOPDUCKING: + case LIZTROOPRUNNING: + case LIZTROOP: + case OCTABRAIN: + case COMMANDER: + case COMMANDERSTAYPUT: + case PIGCOP: + case EGG: + case PIGCOPSTAYPUT: + case PIGCOPDIVE: + case LIZMAN: + case LIZMANSPITTING: + case LIZMANFEEDING: + case LIZMANJUMP: + case ORGANTIC: + case BOSS1: + case BOSS2: + case BOSS3: + case BOSS4: + case GREENSLIME: + case GREENSLIME+1: + case GREENSLIME+2: + case GREENSLIME+3: + case GREENSLIME+4: + case GREENSLIME+5: + case GREENSLIME+6: + case GREENSLIME+7: + case RAT: + case ROTATEGUN: + return 1; + } + + if( actortype[pn] ) return 1; + + return 0; +} + + + +void myos(long x, long y, short tilenum, signed char shade, char orientation) +{ + char p; + short a; + + if(orientation&4) + a = 1024; + else a = 0; + + p = sector[ps[screenpeek].cursectnum].floorpal; + rotatesprite(x<<16,y<<16,65536L,a,tilenum,shade,p,2|orientation,windowx1,windowy1,windowx2,windowy2); +} + +void myospal(long x, long y, short tilenum, signed char shade, char orientation, char p) +{ + char fp; + short a; + + if(orientation&4) + a = 1024; + else a = 0; + + fp = sector[ps[screenpeek].cursectnum].floorpal; + + rotatesprite(x<<16,y<<16,65536L,a,tilenum,shade,p,2|orientation,windowx1,windowy1,windowx2,windowy2); + +} + +void invennum(long x,long y,char num1,char ha,char sbits) +{ + char dabuf[80] = {0}; + sprintf(dabuf,"%d",num1); + if(num1 > 99) + { + rotatesprite((x-4)<<16,y<<16,65536L,0,THREEBYFIVE+dabuf[0]-'0',ha,0,sbits,0,0,xdim-1,ydim-1); + rotatesprite((x)<<16,y<<16,65536L,0,THREEBYFIVE+dabuf[1]-'0',ha,0,sbits,0,0,xdim-1,ydim-1); + rotatesprite((x+4)<<16,y<<16,65536L,0,THREEBYFIVE+dabuf[2]-'0',ha,0,sbits,0,0,xdim-1,ydim-1); + } + else if(num1 > 9) + { + rotatesprite((x)<<16,y<<16,65536L,0,THREEBYFIVE+dabuf[0]-'0',ha,0,sbits,0,0,xdim-1,ydim-1); + rotatesprite((x+4)<<16,y<<16,65536L,0,THREEBYFIVE+dabuf[1]-'0',ha,0,sbits,0,0,xdim-1,ydim-1); + } + else + rotatesprite((x+4)<<16,y<<16,65536L,0,THREEBYFIVE+dabuf[0]-'0',ha,0,sbits,0,0,xdim-1,ydim-1); +} + +#ifdef VOLUMEONE +void orderweaponnum(short ind,long x,long y,long num1, long num2,char ha) +{ + rotatesprite((x-7)<<16,y<<16,65536L,0,THREEBYFIVE+ind+1,ha-10,7,10+128,0,0,xdim-1,ydim-1); + rotatesprite((x-3)<<16,y<<16,65536L,0,THREEBYFIVE+10,ha,0,10+128,0,0,xdim-1,ydim-1); + + minitextshade(x+1,y-4,"ORDER",26,6,2+8+16+128); +} +#endif + + +void weaponnum(short ind,long x,long y,long num1, long num2,char ha) +{ + char dabuf[80] = {0}; + + rotatesprite((x-7)<<16,y<<16,65536L,0,THREEBYFIVE+ind+1,ha-10,7,10+128,0,0,xdim-1,ydim-1); + rotatesprite((x-3)<<16,y<<16,65536L,0,THREEBYFIVE+10,ha,0,10+128,0,0,xdim-1,ydim-1); + rotatesprite((x+9)<<16,y<<16,65536L,0,THREEBYFIVE+11,ha,0,10+128,0,0,xdim-1,ydim-1); + + if(num1 > 99) num1 = 99; + if(num2 > 99) num2 = 99; + + sprintf(dabuf,"%ld",num1); + if(num1 > 9) + { + rotatesprite((x)<<16,y<<16,65536L,0,THREEBYFIVE+dabuf[0]-'0',ha,0,10+128,0,0,xdim-1,ydim-1); + rotatesprite((x+4)<<16,y<<16,65536L,0,THREEBYFIVE+dabuf[1]-'0',ha,0,10+128,0,0,xdim-1,ydim-1); + } + else rotatesprite((x+4)<<16,y<<16,65536L,0,THREEBYFIVE+dabuf[0]-'0',ha,0,10+128,0,0,xdim-1,ydim-1); + + sprintf(dabuf,"%ld",num2); + if(num2 > 9) + { + rotatesprite((x+13)<<16,y<<16,65536L,0,THREEBYFIVE+dabuf[0]-'0',ha,0,10+128,0,0,xdim-1,ydim-1); + rotatesprite((x+17)<<16,y<<16,65536L,0,THREEBYFIVE+dabuf[1]-'0',ha,0,10+128,0,0,xdim-1,ydim-1); + } + else rotatesprite((x+13)<<16,y<<16,65536L,0,THREEBYFIVE+dabuf[0]-'0',ha,0,10+128,0,0,xdim-1,ydim-1); +} + +void weaponnum999(char ind,long x,long y,long num1, long num2,char ha) +{ + char dabuf[80] = {0}; + + rotatesprite((x-7)<<16,y<<16,65536L,0,THREEBYFIVE+ind+1,ha-10,7,10+128,0,0,xdim-1,ydim-1); + rotatesprite((x-4)<<16,y<<16,65536L,0,THREEBYFIVE+10,ha,0,10+128,0,0,xdim-1,ydim-1); + rotatesprite((x+13)<<16,y<<16,65536L,0,THREEBYFIVE+11,ha,0,10+128,0,0,xdim-1,ydim-1); + + sprintf(dabuf,"%ld",num1); + if(num1 > 99) + { + rotatesprite((x)<<16,y<<16,65536L,0,THREEBYFIVE+dabuf[0]-'0',ha,0,10+128,0,0,xdim-1,ydim-1); + rotatesprite((x+4)<<16,y<<16,65536L,0,THREEBYFIVE+dabuf[1]-'0',ha,0,10+128,0,0,xdim-1,ydim-1); + rotatesprite((x+8)<<16,y<<16,65536L,0,THREEBYFIVE+dabuf[2]-'0',ha,0,10+128,0,0,xdim-1,ydim-1); + } + else if(num1 > 9) + { + rotatesprite((x+4)<<16,y<<16,65536L,0,THREEBYFIVE+dabuf[0]-'0',ha,0,10+128,0,0,xdim-1,ydim-1); + rotatesprite((x+8)<<16,y<<16,65536L,0,THREEBYFIVE+dabuf[1]-'0',ha,0,10+128,0,0,xdim-1,ydim-1); + } + else rotatesprite((x+8)<<16,y<<16,65536L,0,THREEBYFIVE+dabuf[0]-'0',ha,0,10+128,0,0,xdim-1,ydim-1); + + sprintf(dabuf,"%ld",num2); + if(num2 > 99) + { + rotatesprite((x+17)<<16,y<<16,65536L,0,THREEBYFIVE+dabuf[0]-'0',ha,0,10+128,0,0,xdim-1,ydim-1); + rotatesprite((x+21)<<16,y<<16,65536L,0,THREEBYFIVE+dabuf[1]-'0',ha,0,10+128,0,0,xdim-1,ydim-1); + rotatesprite((x+25)<<16,y<<16,65536L,0,THREEBYFIVE+dabuf[2]-'0',ha,0,10+128,0,0,xdim-1,ydim-1); + } + else if(num2 > 9) + { + rotatesprite((x+17)<<16,y<<16,65536L,0,THREEBYFIVE+dabuf[0]-'0',ha,0,10+128,0,0,xdim-1,ydim-1); + rotatesprite((x+21)<<16,y<<16,65536L,0,THREEBYFIVE+dabuf[1]-'0',ha,0,10+128,0,0,xdim-1,ydim-1); + } + else rotatesprite((x+25)<<16,y<<16,65536L,0,THREEBYFIVE+dabuf[0]-'0',ha,0,10+128,0,0,xdim-1,ydim-1); +} + + + //REPLACE FULLY +void weapon_amounts(struct player_struct *p,long x,long y,long u) +{ + int cw; + + cw = p->curr_weapon; + + if (u&4) + { + if ((unsigned long)u != 0xffffffff) patchstatusbar(96,178,96+12,178+6); + weaponnum999(PISTOL_WEAPON,x,y, + p->ammo_amount[PISTOL_WEAPON],max_ammo_amount[PISTOL_WEAPON], + 12-20*(cw == PISTOL_WEAPON) ); + } + if (u&8) + { + if ((unsigned long)u != 0xffffffff) patchstatusbar(96,184,96+12,184+6); + weaponnum999(SHOTGUN_WEAPON,x,y+6, + p->ammo_amount[SHOTGUN_WEAPON],max_ammo_amount[SHOTGUN_WEAPON], + (!p->gotweapon[SHOTGUN_WEAPON]*9)+12-18* + (cw == SHOTGUN_WEAPON) ); + } + if (u&16) + { + if ((unsigned long)u != 0xffffffff) patchstatusbar(96,190,96+12,190+6); + weaponnum999(CHAINGUN_WEAPON,x,y+12, + p->ammo_amount[CHAINGUN_WEAPON],max_ammo_amount[CHAINGUN_WEAPON], + (!p->gotweapon[CHAINGUN_WEAPON]*9)+12-18* + (cw == CHAINGUN_WEAPON) ); + } + if (u&32) + { + if ((unsigned long)u != 0xffffffff) patchstatusbar(135,178,135+8,178+6); + weaponnum(RPG_WEAPON,x+39,y, + p->ammo_amount[RPG_WEAPON],max_ammo_amount[RPG_WEAPON], + (!p->gotweapon[RPG_WEAPON]*9)+12-19* + (cw == RPG_WEAPON) ); + } + if (u&64) + { + if ((unsigned long)u != 0xffffffff) patchstatusbar(135,184,135+8,184+6); + weaponnum(HANDBOMB_WEAPON,x+39,y+6, + p->ammo_amount[HANDBOMB_WEAPON],max_ammo_amount[HANDBOMB_WEAPON], + (((!p->ammo_amount[HANDBOMB_WEAPON])|(!p->gotweapon[HANDBOMB_WEAPON]))*9)+12-19* + ((cw == HANDBOMB_WEAPON) || (cw == HANDREMOTE_WEAPON))); + } + if (u&128) + { + if ((unsigned long)u != 0xffffffff) patchstatusbar(135,190,135+8,190+6); + +#ifdef VOLUMEONE + orderweaponnum(SHRINKER_WEAPON,x+39,y+12, + p->ammo_amount[SHRINKER_WEAPON],max_ammo_amount[SHRINKER_WEAPON], + (!p->gotweapon[SHRINKER_WEAPON]*9)+12-18* + (cw == SHRINKER_WEAPON) ); +#else + if(p->subweapon&(1<ammo_amount[GROW_WEAPON],max_ammo_amount[GROW_WEAPON], + (!p->gotweapon[GROW_WEAPON]*9)+12-18* + (cw == GROW_WEAPON) ); + else + weaponnum(SHRINKER_WEAPON,x+39,y+12, + p->ammo_amount[SHRINKER_WEAPON],max_ammo_amount[SHRINKER_WEAPON], + (!p->gotweapon[SHRINKER_WEAPON]*9)+12-18* + (cw == SHRINKER_WEAPON) ); +#endif + } + if (u&256) + { + if ((unsigned long)u != 0xffffffff) patchstatusbar(166,178,166+8,178+6); + +#ifdef VOLUMEONE + orderweaponnum(DEVISTATOR_WEAPON,x+70,y, + p->ammo_amount[DEVISTATOR_WEAPON],max_ammo_amount[DEVISTATOR_WEAPON], + (!p->gotweapon[DEVISTATOR_WEAPON]*9)+12-18* + (cw == DEVISTATOR_WEAPON) ); +#else + weaponnum(DEVISTATOR_WEAPON,x+70,y, + p->ammo_amount[DEVISTATOR_WEAPON],max_ammo_amount[DEVISTATOR_WEAPON], + (!p->gotweapon[DEVISTATOR_WEAPON]*9)+12-18* + (cw == DEVISTATOR_WEAPON) ); +#endif + } + if (u&512) + { + if ((unsigned long)u != 0xffffffff) patchstatusbar(166,184,166+8,184+6); +#ifdef VOLUMEONE + orderweaponnum(TRIPBOMB_WEAPON,x+70,y+6, + p->ammo_amount[TRIPBOMB_WEAPON],max_ammo_amount[TRIPBOMB_WEAPON], + (!p->gotweapon[TRIPBOMB_WEAPON]*9)+12-18* + (cw == TRIPBOMB_WEAPON) ); +#else + weaponnum(TRIPBOMB_WEAPON,x+70,y+6, + p->ammo_amount[TRIPBOMB_WEAPON],max_ammo_amount[TRIPBOMB_WEAPON], + (!p->gotweapon[TRIPBOMB_WEAPON]*9)+12-18* + (cw == TRIPBOMB_WEAPON) ); +#endif + } + + if (u&65536L) + { + if ((unsigned long)u != 0xffffffff) patchstatusbar(166,190,166+8,190+6); +#ifdef VOLUMEONE + orderweaponnum(-1,x+70,y+12, + p->ammo_amount[FREEZE_WEAPON],max_ammo_amount[FREEZE_WEAPON], + (!p->gotweapon[FREEZE_WEAPON]*9)+12-18* + (cw == FREEZE_WEAPON) ); +#else + weaponnum(-1,x+70,y+12, + p->ammo_amount[FREEZE_WEAPON],max_ammo_amount[FREEZE_WEAPON], + (!p->gotweapon[FREEZE_WEAPON]*9)+12-18* + (cw == FREEZE_WEAPON) ); +#endif + } +} + +void digitalnumber(long x,long y,long n,char s,char cs) +{ + short i, j, k, p, c; + char b[10]; + + ltoa(n,b,10); + i = strlen(b); + j = 0; + + for(k=0;k>1); + + j = 0; + for(k=0;k= 0;i--) + { + overwritesprite(x-2,y,SCRATCH+4,s,0,0); + x += tilesizx[SCRATCH+4]-1; + } + + ni = n%5; + if(ni) overwritesprite(x,y,SCRATCH+ni-1,s,p,0); +} + */ +void displayinventory(struct player_struct *p) +{ + short n, j, xoff, y; + + j = xoff = 0; + + n = (p->jetpack_amount > 0)<<3; if(n&8) j++; + n |= ( p->scuba_amount > 0 )<<5; if(n&32) j++; + n |= (p->steroids_amount > 0)<<1; if(n&2) j++; + n |= ( p->holoduke_amount > 0)<<2; if(n&4) j++; + n |= (p->firstaid_amount > 0); if(n&1) j++; + n |= (p->heat_amount > 0)<<4; if(n&16) j++; + n |= (p->boot_amount > 0)<<6; if(n&64) j++; + + xoff = 160-(j*11); + + j = 0; + + if(ud.screen_size > 4) + y = 154; + else y = 172; + + if(ud.screen_size == 4) + { + if(ud.multimode > 1) + xoff += 56; + else xoff += 65; + } + + while( j <= 9 ) + { + if( n&(1<inven_icon == j+1) + rotatesprite((xoff-2)<<16,(y+19)<<16,65536L,1024,ARROW,-32,0,2+16,windowx1,windowy1,windowx2,windowy2); + } + + j++; + } +} + + + +void displayfragbar(void) +{ + short i, j; + + j = 0; + + for(i=connecthead;i>=0;i=connectpoint2[i]) + if(i > j) j = i; + + rotatesprite(0,0,65600L,0,FRAGBAR,0,0,2+8+16+64+128,0,0,xdim-1,ydim-1); + if(j >= 4) rotatesprite(319,(8)<<16,65600L,0,FRAGBAR,0,0,10+16+64+128,0,0,xdim-1,ydim-1); + if(j >= 8) rotatesprite(319,(16)<<16,65600L,0,FRAGBAR,0,0,10+16+64+128,0,0,xdim-1,ydim-1); + if(j >= 12) rotatesprite(319,(24)<<16,65600L,0,FRAGBAR,0,0,10+16+64+128,0,0,xdim-1,ydim-1); + + for(i=connecthead;i>=0;i=connectpoint2[i]) + { + minitext(21+(73*(i&3)),2+((i&28)<<1),&ud.user_name[i][0],sprite[ps[i].i].pal,2+8+16+128); + sprintf(tempbuf,"%d",ps[i].frag-ps[i].fraggedself); + minitext(17+50+(73*(i&3)),2+((i&28)<<1),tempbuf,sprite[ps[i].i].pal,2+8+16+128); + } +} + +void coolgaugetext(short snum) +{ + struct player_struct *p; + long i, j, o, ss, u; + char c, permbit; + + p = &ps[snum]; + + if (p->invdisptime > 0) displayinventory(p); + + + if(ps[snum].gm&MODE_MENU) + if( (current_menu >= 400 && current_menu <= 405) ) + return; + + ss = ud.screen_size; if (ss < 4) return; + + if ( ud.multimode > 1 && ud.coop != 1 ) + { + if (pus) + { displayfragbar(); } + else + { + for(i=connecthead;i>=0;i=connectpoint2[i]) + if (ps[i].frag != sbar.frag[i]) { displayfragbar(); break; } + } + for(i=connecthead;i>=0;i=connectpoint2[i]) + if (i != myconnectindex) + sbar.frag[i] = ps[i].frag; + } + + if (ss == 4) //DRAW MINI STATUS BAR: + { + rotatesprite(5<<16,(200-28)<<16,65536L,0,HEALTHBOX,0,21,10+16,0,0,xdim-1,ydim-1); + if (p->inven_icon) + rotatesprite(69<<16,(200-30)<<16,65536L,0,INVENTORYBOX,0,21,10+16,0,0,xdim-1,ydim-1); + + if(sprite[p->i].pal == 1 && p->last_extra < 2) + digitalnumber(20,200-17,1,-16,10+16); + else digitalnumber(20,200-17,p->last_extra,-16,10+16); + + rotatesprite(37<<16,(200-28)<<16,65536L,0,AMMOBOX,0,21,10+16,0,0,xdim-1,ydim-1); + + if (p->curr_weapon == HANDREMOTE_WEAPON) i = HANDBOMB_WEAPON; else i = p->curr_weapon; + digitalnumber(53,200-17,p->ammo_amount[i],-16,10+16); + + o = 158; permbit = 0; + if (p->inven_icon) + { + switch(p->inven_icon) + { + case 1: i = FIRSTAID_ICON; break; + case 2: i = STEROIDS_ICON; break; + case 3: i = HOLODUKE_ICON; break; + case 4: i = JETPACK_ICON; break; + case 5: i = HEAT_ICON; break; + case 6: i = AIRTANK_ICON; break; + case 7: i = BOOT_ICON; break; + default: i = -1; + } + if (i >= 0) rotatesprite((231-o)<<16,(200-21)<<16,65536L,0,i,0,0,10+16+permbit,0,0,xdim-1,ydim-1); + + minitext(292-30-o,190,"%",6,10+16+permbit); + + j = 0x80000000; + switch(p->inven_icon) + { + case 1: i = p->firstaid_amount; break; + case 2: i = ((p->steroids_amount+3)>>2); break; + case 3: i = ((p->holoduke_amount+15)/24); j = p->holoduke_on; break; + case 4: i = ((p->jetpack_amount+15)>>4); j = p->jetpack_on; break; + case 5: i = p->heat_amount/12; j = p->heat_on; break; + case 6: i = ((p->scuba_amount+63)>>6); break; + case 7: i = (p->boot_amount>>1); break; + } + invennum(284-30-o,200-6,(char)i,0,10+permbit); + if (j > 0) minitext(288-30-o,180,"ON",0,10+16+permbit); + else if ((unsigned long)j != 0x80000000) minitext(284-30-o,180,"OFF",2,10+16+permbit); + if (p->inven_icon >= 6) minitext(284-35-o,180,"AUTO",2,10+16+permbit); + } + return; + } + + //DRAW/UPDATE FULL STATUS BAR: + + if (pus) { pus = 0; u = 0xffffffff; } else u = 0; + + if (sbar.frag[myconnectindex] != p->frag) { sbar.frag[myconnectindex] = p->frag; u |= 32768; } + if (sbar.got_access != p->got_access) { sbar.got_access = p->got_access; u |= 16384; } + if (sbar.last_extra != p->last_extra) { sbar.last_extra = p->last_extra; u |= 1; } + if (sbar.shield_amount != p->shield_amount) { sbar.shield_amount = p->shield_amount; u |= 2; } + if (sbar.curr_weapon != p->curr_weapon) { sbar.curr_weapon = p->curr_weapon; u |= (4+8+16+32+64+128+256+512+1024+65536L); } + for(i=1;i < 10;i++) + { + if (sbar.ammo_amount[i] != p->ammo_amount[i]) { + sbar.ammo_amount[i] = p->ammo_amount[i]; if(i < 9) u |= ((2<gotweapon[i]) { sbar.gotweapon[i] = + p->gotweapon[i]; if(i < 9 ) u |= ((2<inven_icon) { sbar.inven_icon = p->inven_icon; u |= (2048+4096+8192); } + if (sbar.holoduke_on != p->holoduke_on) { sbar.holoduke_on = p->holoduke_on; u |= (4096+8192); } + if (sbar.jetpack_on != p->jetpack_on) { sbar.jetpack_on = p->jetpack_on; u |= (4096+8192); } + if (sbar.heat_on != p->heat_on) { sbar.heat_on = p->heat_on; u |= (4096+8192); } + if (sbar.firstaid_amount != p->firstaid_amount) { sbar.firstaid_amount = p->firstaid_amount; u |= 8192; } + if (sbar.steroids_amount != p->steroids_amount) { sbar.steroids_amount = p->steroids_amount; u |= 8192; } + if (sbar.holoduke_amount != p->holoduke_amount) { sbar.holoduke_amount = p->holoduke_amount; u |= 8192; } + if (sbar.jetpack_amount != p->jetpack_amount) { sbar.jetpack_amount = p->jetpack_amount; u |= 8192; } + if (sbar.heat_amount != p->heat_amount) { sbar.heat_amount = p->heat_amount; u |= 8192; } + if (sbar.scuba_amount != p->scuba_amount) { sbar.scuba_amount = p->scuba_amount; u |= 8192; } + if (sbar.boot_amount != p->boot_amount) { sbar.boot_amount = p->boot_amount; u |= 8192; } + if (u == 0) return; + + //0 - update health + //1 - update armor + //2 - update PISTOL_WEAPON ammo + //3 - update SHOTGUN_WEAPON ammo + //4 - update CHAINGUN_WEAPON ammo + //5 - update RPG_WEAPON ammo + //6 - update HANDBOMB_WEAPON ammo + //7 - update SHRINKER_WEAPON ammo + //8 - update DEVISTATOR_WEAPON ammo + //9 - update TRIPBOMB_WEAPON ammo + //10 - update ammo display + //11 - update inventory icon + //12 - update inventory on/off + //13 - update inventory % + //14 - update keys + //15 - update kills + //16 - update FREEZE_WEAPON ammo + + if ((unsigned long)u == 0xffffffff) + { + patchstatusbar(0,0,320,200); + if (ud.multimode > 1 && ud.coop != 1) + rotatesprite(277<<16,(200-27)<<16,65536L,0,KILLSICON,0,0,10+16+128,0,0,xdim-1,ydim-1); + } + if (ud.multimode > 1 && ud.coop != 1) + { + if (u&32768) + { + if ((unsigned long)u != 0xffffffff) patchstatusbar(276,183,299,193); + digitalnumber(287,200-17,max(p->frag-p->fraggedself,0),-16,10+16+128); + } + } + else + { + if (u&16384) + { + if ((unsigned long)u != 0xffffffff) patchstatusbar(275,182,299,194); + if (p->got_access&4) rotatesprite(275<<16,182<<16,65536L,0,ACCESS_ICON,0,23,10+16+128,0,0,xdim-1,ydim-1); + if (p->got_access&2) rotatesprite(288<<16,182<<16,65536L,0,ACCESS_ICON,0,21,10+16+128,0,0,xdim-1,ydim-1); + if (p->got_access&1) rotatesprite(281<<16,189<<16,65536L,0,ACCESS_ICON,0,0,10+16+128,0,0,xdim-1,ydim-1); + } + } + if (u&(4+8+16+32+64+128+256+512+65536L)) weapon_amounts(p,96,182,u); + + if (u&1) + { + if ((unsigned long)u != 0xffffffff) patchstatusbar(20,183,43,193); + if(sprite[p->i].pal == 1 && p->last_extra < 2) + digitalnumber(32,200-17,1,-16,10+16+128); + else digitalnumber(32,200-17,p->last_extra,-16,10+16+128); + } + if (u&2) + { + if ((unsigned long)u != 0xffffffff) patchstatusbar(52,183,75,193); + digitalnumber(64,200-17,p->shield_amount,-16,10+16+128); + } + + if (u&1024) + { + if ((unsigned long)u != 0xffffffff) patchstatusbar(196,183,219,193); + if (p->curr_weapon != KNEE_WEAPON) + { + if (p->curr_weapon == HANDREMOTE_WEAPON) i = HANDBOMB_WEAPON; else i = p->curr_weapon; + digitalnumber(230-22,200-17,p->ammo_amount[i],-16,10+16+128); + } + } + + if (u&(2048+4096+8192)) + { + if ((unsigned long)u != 0xffffffff) + { + if (u&(2048+4096)) { patchstatusbar(231,179,265,197); } + else { patchstatusbar(250,190,261,195); } + } + if (p->inven_icon) + { + o = 0; permbit = 128; + + if (u&(2048+4096)) + { + switch(p->inven_icon) + { + case 1: i = FIRSTAID_ICON; break; + case 2: i = STEROIDS_ICON; break; + case 3: i = HOLODUKE_ICON; break; + case 4: i = JETPACK_ICON; break; + case 5: i = HEAT_ICON; break; + case 6: i = AIRTANK_ICON; break; + case 7: i = BOOT_ICON; break; + } + rotatesprite((231-o)<<16,(200-21)<<16,65536L,0,i,0,0,10+16+permbit,0,0,xdim-1,ydim-1); + minitext(292-30-o,190,"%",6,10+16+permbit); + if (p->inven_icon >= 6) minitext(284-35-o,180,"AUTO",2,10+16+permbit); + } + if (u&(2048+4096)) + { + switch(p->inven_icon) + { + case 3: j = p->holoduke_on; break; + case 4: j = p->jetpack_on; break; + case 5: j = p->heat_on; break; + default: j = 0x80000000; + } + if (j > 0) minitext(288-30-o,180,"ON",0,10+16+permbit); + else if ((unsigned long)j != 0x80000000) minitext(284-30-o,180,"OFF",2,10+16+permbit); + } + if (u&8192) + { + switch(p->inven_icon) + { + case 1: i = p->firstaid_amount; break; + case 2: i = ((p->steroids_amount+3)>>2); break; + case 3: i = ((p->holoduke_amount+15)/24); break; + case 4: i = ((p->jetpack_amount+15)>>4); break; + case 5: i = p->heat_amount/12; break; + case 6: i = ((p->scuba_amount+63)>>6); break; + case 7: i = (p->boot_amount>>1); break; + } + invennum(284-30-o,200-6,(char)i,0,10+permbit); + } + } + } +} + + +#define AVERAGEFRAMES 16 +static long frameval[AVERAGEFRAMES], framecnt = 0; + +void tics(void) +{ + long i; + char b[10]; + + i = totalclock; + if (i != frameval[framecnt]) + { + sprintf(b,"%ld",(TICRATE*AVERAGEFRAMES)/(i-frameval[framecnt])); + printext256(windowx1,windowy1,31,-21,b,1); + frameval[framecnt] = i; + } + + framecnt = ((framecnt+1)&(AVERAGEFRAMES-1)); +} + +void coords(short snum) +{ + short y = 0; + + if(ud.coop != 1) + { + if(ud.multimode > 1 && ud.multimode < 5) + y = 8; + else if(ud.multimode > 4) + y = 16; + } + + sprintf(tempbuf,"X= %ld",ps[snum].posx); + printext256(250L,y,31,-1,tempbuf,1); + sprintf(tempbuf,"Y= %ld",ps[snum].posy); + printext256(250L,y+7L,31,-1,tempbuf,1); + sprintf(tempbuf,"Z= %ld",ps[snum].posz); + printext256(250L,y+14L,31,-1,tempbuf,1); + sprintf(tempbuf,"A= %d",ps[snum].ang); + printext256(250L,y+21L,31,-1,tempbuf,1); + sprintf(tempbuf,"ZV= %ld",ps[snum].poszv); + printext256(250L,y+28L,31,-1,tempbuf,1); + sprintf(tempbuf,"OG= %d",ps[snum].on_ground); + printext256(250L,y+35L,31,-1,tempbuf,1); + sprintf(tempbuf,"AM= %d",ps[snum].ammo_amount[GROW_WEAPON]); + printext256(250L,y+43L,31,-1,tempbuf,1); + sprintf(tempbuf,"LFW= %d",ps[snum].last_full_weapon); + printext256(250L,y+50L,31,-1,tempbuf,1); + sprintf(tempbuf,"SECTL= %d",sector[ps[snum].cursectnum].lotag); + printext256(250L,y+57L,31,-1,tempbuf,1); + sprintf(tempbuf,"SEED= %ld",randomseed); + printext256(250L,y+64L,31,-1,tempbuf,1); + sprintf(tempbuf,"THOLD= %d",ps[snum].transporter_hold); + printext256(250L,y+64L+7,31,-1,tempbuf,1); +} + +void operatefta(void) +{ + long i, j, k; + + if(ud.screen_size > 0) j = 200-45; else j = 200-8; + quotebot = min(quotebot,j); + quotebotgoal = min(quotebotgoal,j); + if(ps[myconnectindex].gm&MODE_TYPE) j -= 8; + quotebotgoal = j; j = quotebot; + for(i=0;i 4) + gametext(320>>1,j,user_quote[i],0,2+8+16); + else if (k > 2) gametext(320>>1,j,user_quote[i],0,2+8+16+1); + else gametext(320>>1,j,user_quote[i],0,2+8+16+1+32); + j -= 8; + } + + if (ps[screenpeek].fta <= 1) return; + + if (ud.coop != 1 && ud.screen_size > 0 && ud.multimode > 1) + { + j = 0; k = 8; + for(i=connecthead;i>=0;i=connectpoint2[i]) + if (i > j) j = i; + + if (j >= 4 && j <= 8) k += 8; + else if (j > 8 && j <= 12) k += 16; + else if (j > 12) k += 24; + } + else k = 0; + + if (ps[screenpeek].ftq == 115 || ps[screenpeek].ftq == 116) + { + k = quotebot; + for(i=0;i 4) + gametext(320>>1,k,fta_quotes[ps[screenpeek].ftq],0,2+8+16); + else + if (j > 2) gametext(320>>1,k,fta_quotes[ps[screenpeek].ftq],0,2+8+16+1); + else + gametext(320>>1,k,fta_quotes[ps[screenpeek].ftq],0,2+8+16+1+32); +} + +void FTA(short q,struct player_struct *p) +{ + if( ud.fta_on == 1) + { + if( p->fta > 0 && q != 115 && q != 116 ) + if( p->ftq == 115 || p->ftq == 116 ) return; + + p->fta = 100; + + if( p->ftq != q || q == 26 ) + // || q == 26 || q == 115 || q ==116 || q == 117 || q == 122 ) + { + p->ftq = q; + pub = NUMPAGES; + pus = NUMPAGES; + } + } +} + +void showtwoscreens(void) +{ + short i; + +#ifndef VOLUMEALL + setview(0,0,xdim-1,ydim-1); + flushperms(); + ps[myconnectindex].palette = palette; + for(i=0;i<64;i+=7) palto(0,0,0,i); + KB_FlushKeyboardQueue(); + rotatesprite(0,0,65536L,0,3291,0,0,2+8+16+64, 0,0,xdim-1,ydim-1); + nextpage(); for(i=63;i>0;i-=7) palto(0,0,0,i); + while( !KB_KeyWaiting() ) getpackets(); + + for(i=0;i<64;i+=7) palto(0,0,0,i); + KB_FlushKeyboardQueue(); + rotatesprite(0,0,65536L,0,3290,0,0,2+8+16+64, 0,0,xdim-1,ydim-1); + nextpage(); for(i=63;i>0;i-=7) palto(0,0,0,i); + while( !KB_KeyWaiting() ) getpackets(); +#else +// CTW - REMOVED +/* setview(0,0,xdim-1,ydim-1); + flushperms(); + ps[myconnectindex].palette = palette; + for(i=0;i<64;i+=7) palto(0,0,0,i); + KB_FlushKeyboardQueue(); + clearview(0L); + rotatesprite(0,0,65536L,0,TENSCREEN,0,0,2+8+16+64, 0,0,xdim-1,ydim-1); + nextpage(); for(i=63;i>0;i-=7) palto(0,0,0,i); + totalclock = 0; + while( !KB_KeyWaiting() && totalclock < 2400) getpackets();*/ +// CTW END - REMOVED +#endif +} + +void binscreen(void) +{ +#ifdef PLATFORM_DOS + long fil; +#ifdef VOLUMEONE + fil = kopen4load("dukesw.bin",1); +#else + fil = kopen4load("duke3d.bin",1); +#endif + if(fil == -1) return; + kread(fil,(char *)0xb8000,4000); + kclose(fil); +#endif +} + + +void gameexit(char *msg) +{ + short i; + char t[256]; + + strncpy(t,msg,256); t[255] = 0; + + if(*t != 0) ps[myconnectindex].palette = (char *) &palette[0]; + + if(numplayers > 1) + allowtimetocorrecterrorswhenquitting(); + + if(ud.recstat == 1) + closedemowrite(); + + if(frecfilep != NULL) + { + fclose(frecfilep); + frecfilep = NULL; + } + + if(qe || cp) + goto GOTOHERE; + + if(playerswhenstarted > 1 && ud.coop != 1 && *t == ' ') + { + dobonus(1); +// CTW - MODIFICATION +// setgamemode(); + setgamemode(ScreenMode,ScreenWidth,ScreenHeight); +// CTW END - MODIFICATION + } + + if(playerswhenstarted > 1) + uninitmultiplayers(); /* deinits network transport. */ + +#ifdef ONELEVELDEMO + doorders(); + // DDOI + //t = "You have been playing a ONE LEVEL demo of Duke Nukem 3D."; + strncpy(t, "You have been playing a ONE LEVEL demo of Duke Nukem 3D.", 256); + t[255] = 0; + // DDOI +#endif + +// CTW - MODIFICATION +/* if( *t != 0 && *(t+1) != 'V' && *(t+1) != 'Y' && playonten == 0 ) + showtwoscreens();*/ + if( *t != 0 && *(t+1) != 'V' && *(t+1) != 'Y' && true) + showtwoscreens(); +// CTW END - MODIFICATION + + GOTOHERE: + + Shutdown(); + + if(*t != 0) + { + setvmode(0x3); + binscreen(); +// CTW - MODIFICATION +/* if(playonten == 0) + { + if(*t == ' ' && *(t+1) == 0) *t = 0; + printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); + printf("%s%s","\n",t); + }*/ + if(true) + { + if(*t == ' ' && *(t+1) == 0) *t = 0; + #if PLATFORM_DOS // Is there a good reason for this? --ryan. + printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); + #else + printf("\n\n%s",t); + #endif + } +// CTW END - MODIFICATION + } + + uninitgroupfile(); + + unlink("duke3d.tmp"); + +#ifdef DC + platform_exit(); +#endif + exit(0); +} + + + + +short inputloc = 0; +short strget(short x,short y,char *t,short dalen,short c) +{ + short ch,sc; + + while(KB_KeyWaiting()) + { + sc = 0; + ch = KB_Getch(); + + if (ch == 0) + { + + sc = KB_Getch(); + if( sc == 104) return(1); + + continue; + } + else + { + if(ch == 8) + { + if( inputloc > 0 ) + { + inputloc--; + *(t+inputloc) = 0; + } + } + else + { + if(ch == asc_Enter || sc == 104) + { + KB_ClearKeyDown(sc_Enter); + KB_ClearKeyDown(sc_kpad_Enter); + return (1); + } + else if(ch == asc_Escape) + { + KB_ClearKeyDown(sc_Escape); + return (-1); + } + else if ( ch >= 32 && inputloc < dalen && ch < 127) + { + ch = toupper(ch); + *(t+inputloc) = ch; + *(t+inputloc+1) = 0; + inputloc++; + } + } + } + } + + if( c == 999 ) return(0); + if( c == 998 ) + { + char b[41],ii; + for(ii=0;ii>11); + rotatesprite((x+8)<<16,(y+4)<<16,32768L,0,SPINNINGNUKEICON+((totalclock>>3)%7),c,0,2+8,0,0,xdim-1,ydim-1); + + return (0); +} + +void typemode(void) +{ + short ch, hitstate, i, j; + + if( ps[myconnectindex].gm&MODE_SENDTOWHOM ) + { + if(sendmessagecommand != -1 || ud.multimode < 3 || movesperpacket == 4) + { + tempbuf[0] = 4; + tempbuf[1] = 0; + recbuf[0] = 0; + + if(ud.multimode < 3) + sendmessagecommand = 2; + + strcat(recbuf,ud.user_name[myconnectindex]); + strcat(recbuf,": "); + strcat(recbuf,typebuf); + j = strlen(recbuf); + recbuf[j] = 0; + strcat(tempbuf+1,recbuf); + + if(sendmessagecommand >= ud.multimode || movesperpacket == 4) + { + for(ch=connecthead;ch >= 0;ch=connectpoint2[ch]) + if (ch != myconnectindex) + sendpacket(ch,tempbuf,j+1); + + adduserquote(recbuf); + quotebot += 8; + quotebotgoal = quotebot; + } + else if(sendmessagecommand >= 0) + sendpacket(sendmessagecommand,tempbuf,j+1); + + sendmessagecommand = -1; + ps[myconnectindex].gm &= ~(MODE_TYPE|MODE_SENDTOWHOM); + } + else if(sendmessagecommand == -1) + { + j = 50; + gametext(320>>1,j,"SEND MESSAGE TO...",0,2+8+16); j += 8; + for(i=connecthead;i>=0;i=connectpoint2[i]) +// for(i=0;i>1)-40+1,j+1,"A/ENTER - ALL",26,0,2+8+16); + minitext((320>>1)-40,j,"A/ENTER - ALL",0,2+8+16); j += 7; + } + else + { + sprintf(buf," %d - %s",i+1,ud.user_name[i]); + minitextshade((320>>1)-40-6+1,j+1,buf,26,0,2+8+16); + minitext((320>>1)-40-6,j,buf,0,2+8+16); j += 7; + } + } + minitextshade((320>>1)-40-4+1,j+1," ESC - Abort",26,0,2+8+16); + minitext((320>>1)-40-4,j," ESC - Abort",0,2+8+16); j += 7; + + //sprintf(buf,"PRESS 1-%ld FOR INDIVIDUAL PLAYER.",ud.multimode); + //gametext(320>>1,j,buf,0,2+8+16); j += 8; + //gametext(320>>1,j,"'A' OR 'ENTER' FOR ALL PLAYERS",0,2+8+16); j += 8; + //gametext(320>>1,j,"ESC ABORTS",0,2+8+16); j += 8; + + if (ud.screen_size > 0) j = 200-45; else j = 200-8; + gametext(320>>1,j,typebuf,0,2+8+16); + + if( KB_KeyWaiting() ) + { + i = KB_Getch(); + + if(i == 'A' || i == 'a' || i == 13) + sendmessagecommand = ud.multimode; + else if(i >= '1' || i <= (ud.multimode + '1') ) + sendmessagecommand = i - '1'; + else + { + sendmessagecommand = ud.multimode; + if(i == 27) + { + ps[myconnectindex].gm &= ~(MODE_TYPE|MODE_SENDTOWHOM); + sendmessagecommand = -1; + } + else + typebuf[0] = 0; + } + + KB_ClearKeyDown(sc_1); + KB_ClearKeyDown(sc_2); + KB_ClearKeyDown(sc_3); + KB_ClearKeyDown(sc_4); + KB_ClearKeyDown(sc_5); + KB_ClearKeyDown(sc_6); + KB_ClearKeyDown(sc_7); + KB_ClearKeyDown(sc_8); + KB_ClearKeyDown(sc_A); + KB_ClearKeyDown(sc_Escape); + KB_ClearKeyDown(sc_Enter); + } + } + } + else + { + if(ud.screen_size > 0) j = 200-45; else j = 200-8; + hitstate = strget(320>>1,j,typebuf,30,1); + + if(hitstate == 1) + { + KB_ClearKeyDown(sc_Enter); + ps[myconnectindex].gm |= MODE_SENDTOWHOM; + } + else if(hitstate == -1) + ps[myconnectindex].gm &= ~(MODE_TYPE|MODE_SENDTOWHOM); + else pub = NUMPAGES; + } +} + +void moveclouds(void) +{ + if( totalclock > cloudtotalclock || totalclock < (cloudtotalclock-7)) + { + short i; + + cloudtotalclock = totalclock+6; + + for(i=0;i>9); + cloudy[i] += (sintable[ps[screenpeek].ang&2047]>>9); + + sector[clouds[i]].ceilingxpanning = cloudx[i]>>6; + sector[clouds[i]].ceilingypanning = cloudy[i]>>6; + } + } +} + + +void displayrest(long smoothratio) +{ + long a, i, j; + + struct player_struct *pp; + walltype *wal; + long cposx,cposy,cang; + + pp = &ps[screenpeek]; + + if( pp->pals_time > 0 && pp->loogcnt == 0) + { + palto( pp->pals[0], + pp->pals[1], + pp->pals[2], + pp->pals_time|128); + + restorepalette = 1; + } + else if( restorepalette ) + { + setbrightness(ud.brightness>>2,&pp->palette[0]); + restorepalette = 0; + } + else if(pp->loogcnt > 0) palto(0,64,0,(pp->loogcnt>>1)+128); + + if(ud.show_help) + { + switch(ud.show_help) + { + case 1: + rotatesprite(0,0,65536L,0,TEXTSTORY,0,0,10+16+64, 0,0,xdim-1,ydim-1); + break; + case 2: + rotatesprite(0,0,65536L,0,F1HELP,0,0,10+16+64, 0,0,xdim-1,ydim-1); + break; + } + + if ( KB_KeyPressed(sc_Escape ) ) + { + KB_ClearKeyDown(sc_Escape); + ud.show_help = 0; + if(ud.multimode < 2 && ud.recstat != 2) + { + ready2send = 1; + totalclock = ototalclock; + } + vscrn(); + } + return; + } + + i = pp->cursectnum; + + show2dsector[i>>3] |= (1<<(i&7)); + wal = &wall[sector[i].wallptr]; + for(j=sector[i].wallnum;j>0;j--,wal++) + { + i = wal->nextsector; + if (i < 0) continue; + if (wal->cstat&0x0071) continue; + if (wall[wal->nextwall].cstat&0x0071) continue; + if (sector[i].lotag == 32767) continue; + if (sector[i].ceilingz >= sector[i].floorz) continue; + show2dsector[i>>3] |= (1<<(i&7)); + } + + if(ud.camerasprite == -1) + { + if( ud.overhead_on != 2 ) + { + if(pp->newowner >= 0) + cameratext(pp->newowner); + else + { + displayweapon(screenpeek); + if(pp->over_shoulder_on == 0 ) + displaymasks(screenpeek); + } + moveclouds(); + } + + if( ud.overhead_on > 0 ) + { + smoothratio = min(max(smoothratio,0),65536); + dointerpolations(smoothratio); + if( ud.scrollmode == 0 ) + { + if(pp->newowner == -1) + { + if (screenpeek == myconnectindex && numplayers > 1) + { + cposx = omyx+mulscale16((long)(myx-omyx),smoothratio); + cposy = omyy+mulscale16((long)(myy-omyy),smoothratio); + cang = omyang+mulscale16((long)(((myang+1024-omyang)&2047)-1024),smoothratio); + } + else + { + cposx = pp->oposx+mulscale16((long)(pp->posx-pp->oposx),smoothratio); + cposy = pp->oposy+mulscale16((long)(pp->posy-pp->oposy),smoothratio); + cang = pp->oang+mulscale16((long)(((pp->ang+1024-pp->oang)&2047)-1024),smoothratio); + } + } + else + { + cposx = pp->oposx; + cposy = pp->oposy; + cang = pp->oang; + } + } + else + { + + ud.fola += ud.folavel>>3; + ud.folx += (ud.folfvel*sintable[(512+2048-ud.fola)&2047])>>14; + ud.foly += (ud.folfvel*sintable[(512+1024-512-ud.fola)&2047])>>14; + + cposx = ud.folx; + cposy = ud.foly; + cang = ud.fola; + } + + if(ud.overhead_on == 2) + { + clearview(0L); + drawmapview(cposx,cposy,pp->zoom,cang); + } + drawoverheadmap( cposx,cposy,pp->zoom,cang); + + restoreinterpolations(); + + if(ud.overhead_on == 2) + { + if(ud.screen_size > 0) a = 147; + else a = 182; + + minitext(1,a+6,volume_names[ud.volume_number],0,2+8+16); + minitext(1,a+12,level_names[ud.volume_number*11 + ud.level_number],0,2+8+16); + } + } + } + + coolgaugetext(screenpeek); + operatefta(); + + if( KB_KeyPressed(sc_Escape) && ud.overhead_on == 0 + && ud.show_help == 0 + && ps[myconnectindex].newowner == -1) + { + if( (ps[myconnectindex].gm&MODE_MENU) == MODE_MENU && current_menu < 51) + { + KB_ClearKeyDown(sc_Escape); + ps[myconnectindex].gm &= ~MODE_MENU; + if(ud.multimode < 2 && ud.recstat != 2) + { + ready2send = 1; + totalclock = ototalclock; + cameraclock = totalclock; + cameradist = 65536L; + } + walock[MAXTILES-1] = 199; + vscrn(); + } + else if( (ps[myconnectindex].gm&MODE_MENU) != MODE_MENU && + ps[myconnectindex].newowner == -1 && + (ps[myconnectindex].gm&MODE_TYPE) != MODE_TYPE) + { + KB_ClearKeyDown(sc_Escape); + FX_StopAllSounds(); + clearsoundlocks(); + + intomenusounds(); + + ps[myconnectindex].gm |= MODE_MENU; + + if(ud.multimode < 2 && ud.recstat != 2) ready2send = 0; + + if(ps[myconnectindex].gm&MODE_GAME) cmenu(50); + else cmenu(0); + screenpeek = myconnectindex; + } + } + + if(ps[myconnectindex].newowner == -1 && ud.overhead_on == 0 && ud.crosshair && ud.camerasprite == -1) + rotatesprite((160L-(ps[myconnectindex].look_ang>>1))<<16,100L<<16,65536L,0,CROSSHAIR,0,0,2+1,windowx1,windowy1,windowx2,windowy2); + + if(ps[myconnectindex].gm&MODE_TYPE) + typemode(); + else + menus(); + + if( ud.pause_on==1 && (ps[myconnectindex].gm&MODE_MENU) == 0 ) + menutext(160,100,0,0,"GAME PAUSED"); + + if(ud.coords) + coords(screenpeek); + if(ud.tickrate) + tics(); +} + + +void updatesectorz(long x, long y, long z, short *sectnum) +{ + walltype *wal; + long i, j, cz, fz; + + getzsofslope(*sectnum,x,y,&cz,&fz); + if ((z >= cz) && (z <= fz)) + if (inside(x,y,*sectnum) != 0) return; + + if ((*sectnum >= 0) && (*sectnum < numsectors)) + { + wal = &wall[sector[*sectnum].wallptr]; + j = sector[*sectnum].wallnum; + do + { + i = wal->nextsector; + if (i >= 0) + { + getzsofslope(i,x,y,&cz,&fz); + if ((z >= cz) && (z <= fz)) + if (inside(x,y,(short)i) == 1) + { *sectnum = i; return; } + } + wal++; j--; + } while (j != 0); + } + + for(i=numsectors-1;i>=0;i--) + { + getzsofslope(i,x,y,&cz,&fz); + if ((z >= cz) && (z <= fz)) + if (inside(x,y,(short)i) == 1) + { *sectnum = i; return; } + } + + *sectnum = -1; +} + +void view(struct player_struct *pp, long *vx, long *vy,long *vz,short *vsectnum, short ang, short horiz) +{ + spritetype *sp; + long i, nx, ny, nz, hx, hy, hz, hitx, hity, hitz; + short bakcstat, hitsect, hitwall, hitsprite, daang; + + nx = (sintable[(ang+1536)&2047]>>4); + ny = (sintable[(ang+1024)&2047]>>4); + nz = (horiz-100)*128; + + sp = &sprite[pp->i]; + + bakcstat = sp->cstat; + sp->cstat &= (short)~0x101; + + updatesectorz(*vx,*vy,*vz,vsectnum); + hitscan(*vx,*vy,*vz,*vsectnum,nx,ny,nz,&hitsect,&hitwall,&hitsprite,&hitx,&hity,&hitz,CLIPMASK1); + + if(*vsectnum < 0) + { + sp->cstat = bakcstat; + return; + } + + hx = hitx-(*vx); hy = hity-(*vy); + if (klabs(nx)+klabs(ny) > klabs(hx)+klabs(hy)) + { + *vsectnum = hitsect; + if (hitwall >= 0) + { + daang = getangle(wall[wall[hitwall].point2].x-wall[hitwall].x, + wall[wall[hitwall].point2].y-wall[hitwall].y); + + i = nx*sintable[daang]+ny*sintable[(daang+1536)&2047]; + if (klabs(nx) > klabs(ny)) hx -= mulscale28(nx,i); + else hy -= mulscale28(ny,i); + } + else if (hitsprite < 0) + { + if (klabs(nx) > klabs(ny)) hx -= (nx>>5); + else hy -= (ny>>5); + } + if (klabs(nx) > klabs(ny)) i = divscale16(hx,nx); + else i = divscale16(hy,ny); + if (i < cameradist) cameradist = i; + } + *vx = (*vx)+mulscale16(nx,cameradist); + *vy = (*vy)+mulscale16(ny,cameradist); + *vz = (*vz)+mulscale16(nz,cameradist); + + cameradist = min(cameradist+((totalclock-cameraclock)<<10),65536); + cameraclock = totalclock; + + updatesectorz(*vx,*vy,*vz,vsectnum); + + sp->cstat = bakcstat; +} + + //REPLACE FULLY +void drawbackground(void) +{ + short dapicnum; + long x,y,x1,y1,x2,y2,topy; + + flushperms(); + + switch(ud.m_volume_number) + { + default:dapicnum = BIGHOLE;break; + case 1:dapicnum = BIGHOLE;break; + case 2:dapicnum = BIGHOLE;break; + } + + y1 = 0; y2 = ydim; + if( ready2send || ud.recstat == 2 ) + { + if(ud.coop != 1) + { + if (ud.multimode > 1) y1 += scale(ydim,8,200); + if (ud.multimode > 4) y1 += scale(ydim,8,200); + } + if (ud.screen_size >= 8) y2 = scale(ydim,200-34,200); + } + + for(y=y1;y 8) + { + y = 0; + if(ud.coop != 1) + { + if (ud.multimode > 1) y += 8; + if (ud.multimode > 4) y += 8; + } + + x1 = max(windowx1-4,0); + y1 = max(windowy1-4,y); + x2 = min(windowx2+4,xdim-1); + y2 = min(windowy2+4,scale(ydim,200-34,200)-1); + + for(y=y1+4;y>3]&(1<<(i&7)))) return; + gotpic[i>>3] &= ~(1<<(i&7)); + + floor1=spnum; + + if(sprite[spnum].lotag==42) fofmode=40; + if(sprite[spnum].lotag==43) fofmode=41; + if(sprite[spnum].lotag==44) fofmode=40; + if(sprite[spnum].lotag==45) fofmode=41; + +// fofmode=sprite[spnum].lotag-2; + +// sectnum=sprite[j].sectnum; +// sectnum=cursectnum; + ok++; + +/* recursive? + for(j=0;j= 0) + { + switch(sprite[i].lotag) + { +// case 40: +// case 41: +// SE40_Draw(i,x,y,a,smoothratio); +// break; + case 42: + case 43: + case 44: + case 45: + if(ps[screenpeek].cursectnum == sprite[i].sectnum) + SE40_Draw(i,x,y,z,a,h,smoothratio); + break; + } + i = nextspritestat[i]; + } +} + +static long oyrepeat=-1; + +void displayrooms(short snum,long smoothratio) +{ + long cposx,cposy,cposz,dst,j,fz,cz,hz,lz; + short sect, cang, k, choriz,tsect; + struct player_struct *p; + long tposx,tposy,tposz,dx,dy,thoriz,i; + short tang; + + p = &ps[snum]; + +// if(screencapt == 0 && (p->gm&MODE_MENU) && ( (current_menu/100) == 3 ) || (current_menu >= 1000 && current_menu < 2999 ) ) + // return; + + if(pub > 0) + { + if(ud.screen_size > 8) drawbackground(); + pub = 0; + } + + if( ud.overhead_on == 2 || ud.show_help || p->cursectnum == -1) + return; + + smoothratio = min(max(smoothratio,0),65536); + + visibility = p->visibility; + + if(ud.pause_on || ps[snum].on_crane > -1) smoothratio = 65536; + + sect = p->cursectnum; + if(sect < 0 || sect >= MAXSECTORS) return; + + dointerpolations(smoothratio); + + animatecamsprite(); + + if(ud.camerasprite >= 0) + { + spritetype *s; + + s = &sprite[ud.camerasprite]; + + if(s->yvel < 0) s->yvel = -100; + else if(s->yvel > 199) s->yvel = 300; + + cang = hittype[ud.camerasprite].tempang+mulscale16((long)(((s->ang+1024-hittype[ud.camerasprite].tempang)&2047)-1024),smoothratio); + + se40code(s->x,s->y,s->z,cang,s->yvel,smoothratio); + + drawrooms(s->x,s->y,s->z-(4<<8),cang,s->yvel,s->sectnum); + animatesprites(s->x,s->y,cang,smoothratio); + drawmasks(); + } + else + { + i = divscale22(1,sprite[p->i].yrepeat+28); + if (i != oyrepeat) + { + oyrepeat = i; + setaspect(oyrepeat,yxaspect); + } + + if(screencapt) + { + walock[MAXTILES-1] = 254; + if (waloff[MAXTILES-1] == 0) + allocache((long *)&waloff[MAXTILES-1],100*160,&walock[MAXTILES-1]); + setviewtotile(MAXTILES-1,100L,160L); + } + else if( ( ud.screen_tilting && p->rotscrnang ) || ud.detail==0 ) + { + if (ud.screen_tilting) tang = p->rotscrnang; else tang = 0; + + walock[MAXTILES-2] = 255; + if (waloff[MAXTILES-2] == 0) + allocache(&waloff[MAXTILES-2],320L*320L,&walock[MAXTILES-2]); + if ((tang&1023) == 0) + setviewtotile(MAXTILES-2,200L>>(1-ud.detail),320L>>(1-ud.detail)); + else + setviewtotile(MAXTILES-2,320L>>(1-ud.detail),320L>>(1-ud.detail)); + if ((tang&1023) == 512) + { //Block off unscreen section of 90ø tilted screen + j = ((320-60)>>(1-ud.detail)); + for(i=(60>>(1-ud.detail))-1;i>=0;i--) + { + startumost[i] = 1; startumost[i+j] = 1; + startdmost[i] = 0; startdmost[i+j] = 0; + } + } + + i = (tang&511); if (i > 256) i = 512-i; + i = sintable[i+512]*8 + sintable[i]*5L; + setaspect(i>>1,yxaspect); + } + + if ( (snum == myconnectindex) && (numplayers > 1) ) + { + cposx = omyx+mulscale16((long)(myx-omyx),smoothratio); + cposy = omyy+mulscale16((long)(myy-omyy),smoothratio); + cposz = omyz+mulscale16((long)(myz-omyz),smoothratio); + cang = omyang+mulscale16((long)(((myang+1024-omyang)&2047)-1024),smoothratio); + choriz = omyhoriz+omyhorizoff+mulscale16((long)(myhoriz+myhorizoff-omyhoriz-omyhorizoff),smoothratio); + sect = mycursectnum; + } + else + { + cposx = p->oposx+mulscale16((long)(p->posx-p->oposx),smoothratio); + cposy = p->oposy+mulscale16((long)(p->posy-p->oposy),smoothratio); + cposz = p->oposz+mulscale16((long)(p->posz-p->oposz),smoothratio); + cang = p->oang+mulscale16((long)(((p->ang+1024-p->oang)&2047)-1024),smoothratio); + choriz = p->ohoriz+p->ohorizoff+mulscale16((long)(p->horiz+p->horizoff-p->ohoriz-p->ohorizoff),smoothratio); + } + cang += p->look_ang; + + if (p->newowner >= 0) + { + cang = p->ang+p->look_ang; + choriz = p->horiz+p->horizoff; + cposx = p->posx; + cposy = p->posy; + cposz = p->posz; + sect = sprite[p->newowner].sectnum; + smoothratio = 65536L; + } + + else if( p->over_shoulder_on == 0 ) + cposz += p->opyoff+mulscale16((long)(p->pyoff-p->opyoff),smoothratio); + else view(p,&cposx,&cposy,&cposz,§,cang,choriz); + + cz = hittype[p->i].ceilingz; + fz = hittype[p->i].floorz; + + if(earthquaketime > 0 && p->on_ground == 1) + { + cposz += 256-(((earthquaketime)&1)<<9); + cang += (2-((earthquaketime)&2))<<2; + } + + if(sprite[p->i].pal == 1) cposz -= (18<<8); + + if(p->newowner >= 0) + choriz = 100+sprite[p->newowner].shade; + else if(p->spritebridge == 0) + { + if( cposz < ( p->truecz + (4<<8) ) ) cposz = cz + (4<<8); + else if( cposz > ( p->truefz - (4<<8) ) ) cposz = fz - (4<<8); + } + + if (sect >= 0) + { + getzsofslope(sect,cposx,cposy,&cz,&fz); + if (cposz < cz+(4<<8)) cposz = cz+(4<<8); + if (cposz > fz-(4<<8)) cposz = fz-(4<<8); + } + + if(choriz > 299) choriz = 299; + else if(choriz < -99) choriz = -99; + + se40code(cposx,cposy,cposz,cang,choriz,smoothratio); + + if ((gotpic[MIRROR>>3]&(1<<(MIRROR&7))) > 0) + { + dst = 0x7fffffff; i = 0; + for(k=0;k>1) + (j>>2); + + drawrooms(tposx,tposy,cposz,tang,choriz,mirrorsector[i]+MAXSECTORS); + + display_mirror = 1; + animatesprites(tposx,tposy,tang,smoothratio); + display_mirror = 0; + + drawmasks(); + completemirror(); //Reverse screen x-wise in this function + visibility = j; + } + gotpic[MIRROR>>3] &= ~(1<<(MIRROR&7)); + } + + drawrooms(cposx,cposy,cposz,cang,choriz,sect); + animatesprites(cposx,cposy,cang,smoothratio); + drawmasks(); + + if(screencapt == 1) + { + setviewback(); + walock[MAXTILES-1] = 1; + screencapt = 0; + } + else if( ( ud.screen_tilting && p->rotscrnang) || ud.detail==0 ) + { + if (ud.screen_tilting) tang = p->rotscrnang; else tang = 0; + setviewback(); + picanm[MAXTILES-2] &= 0xff0000ff; + i = (tang&511); if (i > 256) i = 512-i; + i = sintable[i+512]*8 + sintable[i]*5L; + if ((1-ud.detail) == 0) i >>= 1; + rotatesprite(160<<16,100<<16,i,tang+512,MAXTILES-2,0,0,4+2+64,windowx1,windowy1,windowx2,windowy2); + walock[MAXTILES-2] = 199; + } + } + + restoreinterpolations(); + + if (totalclock < lastvisinc) + { + if (klabs(p->visibility-ud.const_visibility) > 8) + p->visibility += (ud.const_visibility-p->visibility)>>2; + } + else p->visibility = ud.const_visibility; +} + + + + + +short LocateTheLocator(short n,short sn) +{ + short i; + + i = headspritestat[7]; + while(i >= 0) + { + if( (sn == -1 || sn == SECT) && n == SLT ) + return i; + i = nextspritestat[i]; + } + return -1; +} + +short EGS(short whatsect,long s_x,long s_y,long s_z,short s_pn,signed char s_s,signed char s_xr,signed char s_yr,short s_a,short s_ve,long s_zv,short s_ow,signed char s_ss) +{ + short i; + spritetype *s; + + i = insertsprite(whatsect,s_ss); + + if( i < 0 ) + gameexit(" Too many sprites spawned."); + + hittype[i].bposx = s_x; + hittype[i].bposy = s_y; + hittype[i].bposz = s_z; + + s = &sprite[i]; + + s->x = s_x; + s->y = s_y; + s->z = s_z; + s->cstat = 0; + s->picnum = s_pn; + s->shade = s_s; + s->xrepeat = s_xr; + s->yrepeat = s_yr; + s->pal = 0; + + s->ang = s_a; + s->xvel = s_ve; + s->zvel = s_zv; + s->owner = s_ow; + s->xoffset = 0; + s->yoffset = 0; + s->yvel = 0; + s->clipdist = 0; + s->pal = 0; + s->lotag = 0; + + hittype[i].picnum = sprite[s_ow].picnum; + + hittype[i].lastvx = 0; + hittype[i].lastvy = 0; + + hittype[i].timetosleep = 0; + hittype[i].actorstayput = -1; + hittype[i].extra = -1; + hittype[i].owner = s_ow; + hittype[i].cgg = 0; + hittype[i].movflag = 0; + hittype[i].tempang = 0; + hittype[i].dispicnum = 0; + hittype[i].floorz = hittype[s_ow].floorz; + hittype[i].ceilingz = hittype[s_ow].ceilingz; + + T1=T3=T4=T6=0; + if( actorscrptr[s_pn] ) + { + s->extra = *actorscrptr[s_pn]; + T5 = *(actorscrptr[s_pn]+1); + T2 = *(actorscrptr[s_pn]+2); + s->hitag = *(actorscrptr[s_pn]+3); + } + else + { + T2=T5=0; + s->extra = 0; + s->hitag = 0; + } + + if (show2dsector[SECT>>3]&(1<<(SECT&7))) show2dsprite[i>>3] |= (1<<(i&7)); + else show2dsprite[i>>3] &= ~(1<<(i&7)); +/* + if(s->sectnum < 0) + { + s->xrepeat = s->yrepeat = 0; + changespritestat(i,5); + } +*/ + return(i); +} + +char wallswitchcheck(short i) +{ + switch(PN) + { + case HANDPRINTSWITCH: + case HANDPRINTSWITCH+1: + case ALIENSWITCH: + case ALIENSWITCH+1: + case MULTISWITCH: + case MULTISWITCH+1: + case MULTISWITCH+2: + case MULTISWITCH+3: + case ACCESSSWITCH: + case ACCESSSWITCH2: + case PULLSWITCH: + case PULLSWITCH+1: + case HANDSWITCH: + case HANDSWITCH+1: + case SLOTDOOR: + case SLOTDOOR+1: + case LIGHTSWITCH: + case LIGHTSWITCH+1: + case SPACELIGHTSWITCH: + case SPACELIGHTSWITCH+1: + case SPACEDOORSWITCH: + case SPACEDOORSWITCH+1: + case FRANKENSTINESWITCH: + case FRANKENSTINESWITCH+1: + case LIGHTSWITCH2: + case LIGHTSWITCH2+1: + case POWERSWITCH1: + case POWERSWITCH1+1: + case LOCKSWITCH1: + case LOCKSWITCH1+1: + case POWERSWITCH2: + case POWERSWITCH2+1: + case DIPSWITCH: + case DIPSWITCH+1: + case DIPSWITCH2: + case DIPSWITCH2+1: + case TECHSWITCH: + case TECHSWITCH+1: + case DIPSWITCH3: + case DIPSWITCH3+1: + return 1; + } + return 0; +} + + +long tempwallptr; +short spawn( short j, short pn ) +{ + short i=0, s=0, startwall=0, endwall=0, sect=0, clostest=0; + long x=0l, y=0l, d=0l; + spritetype *sp=NULL; + + if(j >= 0) + { + i = EGS(sprite[j].sectnum,sprite[j].x,sprite[j].y,sprite[j].z + ,pn,0,0,0,0,0,0,j,0); + hittype[i].picnum = sprite[j].picnum; + } + else + { + i = pn; + + hittype[i].picnum = PN; + hittype[i].timetosleep = 0; + hittype[i].extra = -1; + + hittype[i].bposx = SX; + hittype[i].bposy = SY; + hittype[i].bposz = SZ; + + OW = hittype[i].owner = i; + hittype[i].cgg = 0; + hittype[i].movflag = 0; + hittype[i].tempang = 0; + hittype[i].dispicnum = 0; + hittype[i].floorz = sector[SECT].floorz; + hittype[i].ceilingz = sector[SECT].ceilingz; + + hittype[i].lastvx = 0; + hittype[i].lastvy = 0; + hittype[i].actorstayput = -1; + + T1 = T2 = T3 = T4 = T5 = T6 = 0; + + if( PN != SPEAKER && PN != LETTER && PN != DUCK && PN != TARGET && PN != TRIPBOMB && PN != VIEWSCREEN && PN != VIEWSCREEN2 && (CS&48) ) + if( !(PN >= CRACK1 && PN <= CRACK4) ) + { + if(SS == 127) return i; + if( wallswitchcheck(i) == 1 && (CS&16) ) + { + if( PN != ACCESSSWITCH && PN != ACCESSSWITCH2 && sprite[i].pal) + { + if( (ud.multimode < 2) || (ud.multimode > 1 && ud.coop==1) ) + { + sprite[i].xrepeat = sprite[i].yrepeat = 0; + sprite[i].cstat = SLT = SHT = 0; + return i; + } + } + CS |= 257; + if( sprite[i].pal && PN != ACCESSSWITCH && PN != ACCESSSWITCH2) + sprite[i].pal = 0; + return i; + } + + if( SHT ) + { + changespritestat(i,12); + CS |= 257; + SH = impact_damage; + return i; + } + } + + s = PN; + + if( CS&1 ) CS |= 256; + + if( actorscrptr[s] ) + { + SH = *(actorscrptr[s]); + T5 = *(actorscrptr[s]+1); + T2 = *(actorscrptr[s]+2); + if( *(actorscrptr[s]+3) && SHT == 0 ) + SHT = *(actorscrptr[s]+3); + } + else T2 = T5 = 0; + } + + sp = &sprite[i]; + sect = sp->sectnum; + + switch(sp->picnum) + { + default: + + if( actorscrptr[sp->picnum] ) + { + if( j == -1 && sp->lotag > ud.player_skill ) + { + sp->xrepeat=sp->yrepeat=0; + changespritestat(i,5); + break; + } + + // Init the size + if(sp->xrepeat == 0 || sp->yrepeat == 0) + sp->xrepeat = sp->yrepeat = 1; + + if( actortype[sp->picnum] & 3) + { + if( ud.monsters_off == 1 ) + { + sp->xrepeat=sp->yrepeat=0; + changespritestat(i,5); + break; + } + + makeitfall(i); + + if( actortype[sp->picnum] & 2) + hittype[i].actorstayput = sp->sectnum; + + ps[myconnectindex].max_actors_killed++; + sp->clipdist = 80; + if(j >= 0) + { + if(sprite[j].picnum == RESPAWN) + hittype[i].tempang = sprite[i].pal = sprite[j].pal; + changespritestat(i,1); + } + else changespritestat(i,2); + } + else + { + sp->clipdist = 40; + sp->owner = i; + changespritestat(i,1); + } + + hittype[i].timetosleep = 0; + + if(j >= 0) + sp->ang = sprite[j].ang; + } + break; + case FOF: + sp->xrepeat = sp->yrepeat = 0; + changespritestat(i,5); + break; + case WATERSPLASH2: + if(j >= 0) + { + setsprite(i,sprite[j].x,sprite[j].y,sprite[j].z); + sp->xrepeat = sp->yrepeat = 8+(TRAND&7); + } + else sp->xrepeat = sp->yrepeat = 16+(TRAND&15); + + sp->shade = -16; + sp->cstat |= 128; + if(j >= 0) + { + if(sector[sprite[j].sectnum].lotag == 2) + { + sp->z = getceilzofslope(SECT,SX,SY)+(16<<8); + sp->cstat |= 8; + } + else if( sector[sprite[j].sectnum].lotag == 1) + sp->z = getflorzofslope(SECT,SX,SY); + } + + if(sector[sect].floorpicnum == FLOORSLIME || + sector[sect].ceilingpicnum == FLOORSLIME) + sp->pal = 7; + case NEON1: + case NEON2: + case NEON3: + case NEON4: + case NEON5: + case NEON6: + case DOMELITE: + if(sp->picnum != WATERSPLASH2) + sp->cstat |= 257; + case NUKEBUTTON: + if(sp->picnum == DOMELITE) + sp->cstat |= 257; + case JIBS1: + case JIBS2: + case JIBS3: + case JIBS4: + case JIBS5: + case JIBS6: + case HEADJIB1: + case ARMJIB1: + case LEGJIB1: + case LIZMANHEAD1: + case LIZMANARM1: + case LIZMANLEG1: + case DUKETORSO: + case DUKEGUN: + case DUKELEG: + changespritestat(i,5); + break; + case TONGUE: + if(j >= 0) + sp->ang = sprite[j].ang; + sp->z -= 38<<8; + sp->zvel = 256-(TRAND&511); + sp->xvel = 64-(TRAND&127); + changespritestat(i,4); + break; + case NATURALLIGHTNING: + sp->cstat &= ~257; + sp->cstat |= 32768; + break; + case TRANSPORTERSTAR: + case TRANSPORTERBEAM: + if(j == -1) break; + if(sp->picnum == TRANSPORTERBEAM) + { + sp->xrepeat = 31; + sp->yrepeat = 1; + sp->z = sector[sprite[j].sectnum].floorz-(40<<8); + } + else + { + if(sprite[j].statnum == 4) + { + sp->xrepeat = 8; + sp->yrepeat = 8; + } + else + { + sp->xrepeat = 48; + sp->yrepeat = 64; + if(sprite[j].statnum == 10 || badguy(&sprite[j]) ) + sp->z -= (32<<8); + } + } + + sp->shade = -127; + sp->cstat = 128|2; + sp->ang = sprite[j].ang; + + sp->xvel = 128; + changespritestat(i,5); + ssp(i,CLIPMASK0); + setsprite(i,sp->x,sp->y,sp->z); + break; + + case FRAMEEFFECT1: + if(j >= 0) + { + sp->xrepeat = sprite[j].xrepeat; + sp->yrepeat = sprite[j].yrepeat; + T2 = sprite[j].picnum; + } + else sp->xrepeat = sp->yrepeat = 0; + + changespritestat(i,5); + + break; + + case LASERLINE: + sp->yrepeat = 6; + sp->xrepeat = 32; + + if(lasermode == 1) + sp->cstat = 16 + 2; + else if(lasermode == 0 || lasermode == 2) + sp->cstat = 16; + else + { + sp->xrepeat = 0; + sp->yrepeat = 0; + } + + if(j >= 0) sp->ang = hittype[j].temp_data[5]+512; + changespritestat(i,5); + break; + + case FORCESPHERE: + if(j == -1 ) + { + sp->cstat = (short) 32768; + changespritestat(i,2); + } + else + { + sp->xrepeat = sp->yrepeat = 1; + changespritestat(i,5); + } + break; + + case BLOOD: + sp->xrepeat = sp->yrepeat = 16; + sp->z -= (26<<8); + if( j >= 0 && sprite[j].pal == 6 ) + sp->pal = 6; + changespritestat(i,5); + break; + case BLOODPOOL: + case PUKE: + { + short s1; + s1 = sp->sectnum; + + updatesector(sp->x+108,sp->y+108,&s1); + if(s1 >= 0 && sector[s1].floorz == sector[sp->sectnum].floorz) + { + updatesector(sp->x-108,sp->y-108,&s1); + if(s1 >= 0 && sector[s1].floorz == sector[sp->sectnum].floorz) + { + updatesector(sp->x+108,sp->y-108,&s1); + if(s1 >= 0 && sector[s1].floorz == sector[sp->sectnum].floorz) + { + updatesector(sp->x-108,sp->y+108,&s1); + if(s1 >= 0 && sector[s1].floorz != sector[sp->sectnum].floorz) + { sp->xrepeat = sp->yrepeat = 0;changespritestat(i,5);break;} + } + else { sp->xrepeat = sp->yrepeat = 0;changespritestat(i,5);break;} + } + else { sp->xrepeat = sp->yrepeat = 0;changespritestat(i,5);break;} + } + else { sp->xrepeat = sp->yrepeat = 0;changespritestat(i,5);break;} + } + + if( sector[SECT].lotag == 1 ) + { + changespritestat(i,5); + break; + } + + if(j >= 0 && sp->picnum != PUKE) + { + if( sprite[j].pal == 1) + sp->pal = 1; + else if( sprite[j].pal != 6 && sprite[j].picnum != NUKEBARREL && sprite[j].picnum != TIRE ) + { + if(sprite[j].picnum == FECES) + sp->pal = 7; // Brown + else sp->pal = 2; // Red + } + else sp->pal = 0; // green + + if(sprite[j].picnum == TIRE) + sp->shade = 127; + } + sp->cstat |= 32; + case FECES: + if( j >= 0) + sp->xrepeat = sp->yrepeat = 1; + changespritestat(i,5); + break; + + case BLOODSPLAT1: + case BLOODSPLAT2: + case BLOODSPLAT3: + case BLOODSPLAT4: + sp->cstat |= 16; + sp->xrepeat = 7+(TRAND&7); + sp->yrepeat = 7+(TRAND&7); + sp->z -= (16<<8); + if(j >= 0 && sprite[j].pal == 6) + sp->pal = 6; + insertspriteq(i); + changespritestat(i,5); + break; + + case TRIPBOMB: + if( sp->lotag > ud.player_skill ) + { + sp->xrepeat=sp->yrepeat=0; + changespritestat(i,5); + break; + } + + sp->xrepeat=4; + sp->yrepeat=5; + + sp->owner = i; + sp->hitag = i; + + sp->xvel = 16; + ssp(i,CLIPMASK0); + hittype[i].temp_data[0] = 17; + hittype[i].temp_data[2] = 0; + hittype[i].temp_data[5] = sp->ang; + + case SPACEMARINE: + if(sp->picnum == SPACEMARINE) + { + sp->extra = 20; + sp->cstat |= 257; + } + changespritestat(i,2); + break; + + case HYDRENT: + case PANNEL1: + case PANNEL2: + case SATELITE: + case FUELPOD: + case SOLARPANNEL: + case ANTENNA: + case GRATE1: + case CHAIR1: + case CHAIR2: + case CHAIR3: + case BOTTLE1: + case BOTTLE2: + case BOTTLE3: + case BOTTLE4: + case BOTTLE5: + case BOTTLE6: + case BOTTLE7: + case BOTTLE8: + case BOTTLE10: + case BOTTLE11: + case BOTTLE12: + case BOTTLE13: + case BOTTLE14: + case BOTTLE15: + case BOTTLE16: + case BOTTLE17: + case BOTTLE18: + case BOTTLE19: + case OCEANSPRITE1: + case OCEANSPRITE2: + case OCEANSPRITE3: + case OCEANSPRITE5: + case MONK: + case INDY: + case LUKE: + case JURYGUY: + case SCALE: + case VACUUM: + case FANSPRITE: + case CACTUS: + case CACTUSBROKE: + case HANGLIGHT: + case FETUS: + case FETUSBROKE: + case CAMERALIGHT: + case MOVIECAMERA: + case IVUNIT: + case POT1: + case POT2: + case POT3: + case TRIPODCAMERA: + case SUSHIPLATE1: + case SUSHIPLATE2: + case SUSHIPLATE3: + case SUSHIPLATE4: + case SUSHIPLATE5: + case WAITTOBESEATED: + case VASE: + case PIPE1: + case PIPE2: + case PIPE3: + case PIPE4: + case PIPE5: + case PIPE6: + sp->clipdist = 32; + sp->cstat |= 257; + case OCEANSPRITE4: + changespritestat(i,0); + break; + case FEMMAG1: + case FEMMAG2: + sp->cstat &= ~257; + changespritestat(i,0); + break; + case DUKETAG: + case SIGN1: + case SIGN2: + if(ud.multimode < 2 && sp->pal) + { + sp->xrepeat = sp->yrepeat = 0; + changespritestat(i,5); + } + else sp->pal = 0; + break; + case MASKWALL1: + case MASKWALL2: + case MASKWALL3: + case MASKWALL4: + case MASKWALL5: + case MASKWALL6: + case MASKWALL7: + case MASKWALL8: + case MASKWALL9: + case MASKWALL10: + case MASKWALL11: + case MASKWALL12: + case MASKWALL13: + case MASKWALL14: + case MASKWALL15: + j = sp->cstat&60; + sp->cstat = j|1; + changespritestat(i,0); + break; + case FOOTPRINTS: + case FOOTPRINTS2: + case FOOTPRINTS3: + case FOOTPRINTS4: + if(j >= 0) + { + short s1; + s1 = sp->sectnum; + + updatesector(sp->x+84,sp->y+84,&s1); + if(s1 >= 0 && sector[s1].floorz == sector[sp->sectnum].floorz) + { + updatesector(sp->x-84,sp->y-84,&s1); + if(s1 >= 0 && sector[s1].floorz == sector[sp->sectnum].floorz) + { + updatesector(sp->x+84,sp->y-84,&s1); + if(s1 >= 0 && sector[s1].floorz == sector[sp->sectnum].floorz) + { + updatesector(sp->x-84,sp->y+84,&s1); + if(s1 >= 0 && sector[s1].floorz != sector[sp->sectnum].floorz) + { sp->xrepeat = sp->yrepeat = 0;changespritestat(i,5);break;} + } + else { sp->xrepeat = sp->yrepeat = 0;break;} + } + else { sp->xrepeat = sp->yrepeat = 0;break;} + } + else { sp->xrepeat = sp->yrepeat = 0;break;} + + sp->cstat = 32+((ps[sprite[j].yvel].footprintcount&1)<<2); + sp->ang = sprite[j].ang; + } + + sp->z = sector[sect].floorz; + if(sector[sect].lotag != 1 && sector[sect].lotag != 2) + sp->xrepeat = sp->yrepeat = 32; + + insertspriteq(i); + changespritestat(i,5); + break; + + case FEM1: + case FEM2: + case FEM3: + case FEM4: + case FEM5: + case FEM6: + case FEM7: + case FEM8: + case FEM9: + case FEM10: + case PODFEM1: + case NAKED1: + case STATUE: + case TOUGHGAL: + sp->yvel = sp->hitag; + sp->hitag = -1; + if(sp->picnum == PODFEM1) sp->extra <<= 1; + case BLOODYPOLE: + + case QUEBALL: + case STRIPEBALL: + + if(sp->picnum == QUEBALL || sp->picnum == STRIPEBALL) + { + sp->cstat = 256; + sp->clipdist = 8; + } + else + { + sp->cstat |= 257; + sp->clipdist = 32; + } + + changespritestat(i,2); + break; + + case DUKELYINGDEAD: + if(j >= 0 && sprite[j].picnum == APLAYER) + { + sp->xrepeat = sprite[j].xrepeat; + sp->yrepeat = sprite[j].yrepeat; + sp->shade = sprite[j].shade; + sp->pal = ps[sprite[j].yvel].palookup; + } + case DUKECAR: + case HELECOPT: +// if(sp->picnum == HELECOPT || sp->picnum == DUKECAR) sp->xvel = 1024; + sp->cstat = 0; + sp->extra = 1; + sp->xvel = 292; + sp->zvel = 360; + case RESPAWNMARKERRED: + case BLIMP: + + if(sp->picnum == RESPAWNMARKERRED) + { + sp->xrepeat = sp->yrepeat = 24; + if(j >= 0) sp->z = hittype[j].floorz; // -(1<<4); + } + else + { + sp->cstat |= 257; + sp->clipdist = 128; + } + case MIKE: + if(sp->picnum == MIKE) + sp->yvel = sp->hitag; + case WEATHERWARN: + changespritestat(i,1); + break; + + case SPOTLITE: + T1 = sp->x; + T2 = sp->y; + break; + case BULLETHOLE: + sp->xrepeat = sp->yrepeat = 3; + sp->cstat = 16+(krand()&12); + insertspriteq(i); + case MONEY: + case MAIL: + case PAPER: + if( sp->picnum == MONEY || sp->picnum == MAIL || sp->picnum == PAPER ) + { + hittype[i].temp_data[0] = TRAND&2047; + sp->cstat = TRAND&12; + sp->xrepeat = sp->yrepeat = 8; + sp->ang = TRAND&2047; + } + changespritestat(i,5); + break; + + case VIEWSCREEN: + case VIEWSCREEN2: + sp->owner = i; + sp->lotag = 1; + sp->extra = 1; + changespritestat(i,6); + break; + + case SHELL: //From the player + case SHOTGUNSHELL: + if( j >= 0 ) + { + short snum,a; + + if(sprite[j].picnum == APLAYER) + { + snum = sprite[j].yvel; + a = ps[snum].ang-(TRAND&63)+8; //Fine tune + + T1 = TRAND&1; + if(sp->picnum == SHOTGUNSHELL) + sp->z = (6<<8)+ps[snum].pyoff+ps[snum].posz-((ps[snum].horizoff+ps[snum].horiz-100)<<4); + else sp->z = (3<<8)+ps[snum].pyoff+ps[snum].posz-((ps[snum].horizoff+ps[snum].horiz-100)<<4); + sp->zvel = -(TRAND&255); + } + else + { + a = sp->ang; + sp->z = sprite[j].z-PHEIGHT+(3<<8); + } + + sp->x = sprite[j].x+(sintable[(a+512)&2047]>>7); + sp->y = sprite[j].y+(sintable[a&2047]>>7); + + sp->shade = -8; + + sp->ang = a-512; + sp->xvel = 20; + + sp->xrepeat=sp->yrepeat=4; + + changespritestat(i,5); + } + break; + + case RESPAWN: + sp->extra = 66-13; + case MUSICANDSFX: + if( ud.multimode < 2 && sp->pal == 1) + { + sp->xrepeat = sp->yrepeat = 0; + changespritestat(i,5); + break; + } + sp->cstat = (short)32768; + changespritestat(i,11); + break; + + case EXPLOSION2: + case EXPLOSION2BOT: + case BURNING: + case BURNING2: + case SMALLSMOKE: + case SHRINKEREXPLOSION: + case COOLEXPLOSION1: + + if(j >= 0) + { + sp->ang = sprite[j].ang; + sp->shade = -64; + sp->cstat = 128|(TRAND&4); + } + + if(sp->picnum == EXPLOSION2 || sp->picnum == EXPLOSION2BOT) + { + sp->xrepeat = 48; + sp->yrepeat = 48; + sp->shade = -127; + sp->cstat |= 128; + } + else if(sp->picnum == SHRINKEREXPLOSION ) + { + sp->xrepeat = 32; + sp->yrepeat = 32; + } + else if( sp->picnum == SMALLSMOKE ) + { + // 64 "money" + sp->xrepeat = 24; + sp->yrepeat = 24; + } + else if(sp->picnum == BURNING || sp->picnum == BURNING2) + { + sp->xrepeat = 4; + sp->yrepeat = 4; + } + + if(j >= 0) + { + x = getflorzofslope(sp->sectnum,sp->x,sp->y); + if(sp->z > x-(12<<8) ) + sp->z = x-(12<<8); + } + + changespritestat(i,5); + + break; + + case PLAYERONWATER: + if(j >= 0) + { + sp->xrepeat = sprite[j].xrepeat; + sp->yrepeat = sprite[j].yrepeat; + sp->zvel = 128; + if(sector[sp->sectnum].lotag != 2) + sp->cstat |= 32768; + } + changespritestat(i,13); + break; + + case APLAYER: + sp->xrepeat = sp->yrepeat = 0; + j = ud.coop; + if(j == 2) j = 0; + + if( ud.multimode < 2 || (ud.multimode > 1 && j != sp->lotag) ) + changespritestat(i,5); + else + changespritestat(i,10); + break; + case WATERBUBBLE: + if(j >= 0 && sprite[j].picnum == APLAYER) + sp->z -= (16<<8); + if( sp->picnum == WATERBUBBLE) + { + if( j >= 0 ) + sp->ang = sprite[j].ang; + sp->xrepeat = sp->yrepeat = 4; + } + else sp->xrepeat = sp->yrepeat = 32; + + changespritestat(i,5); + break; + + case CRANE: + + sp->cstat |= 64|257; + + sp->picnum += 2; + sp->z = sector[sect].ceilingz+(48<<8); + T5 = tempwallptr; + + msx[tempwallptr] = sp->x; + msy[tempwallptr] = sp->y; + msx[tempwallptr+2] = sp->z; + + s = headspritestat[0]; + while(s >= 0) + { + if( sprite[s].picnum == CRANEPOLE && SHT == (sprite[s].hitag) ) + { + msy[tempwallptr+2] = s; + + T2 = sprite[s].sectnum; + + sprite[s].xrepeat = 48; + sprite[s].yrepeat = 128; + + msx[tempwallptr+1] = sprite[s].x; + msy[tempwallptr+1] = sprite[s].y; + + sprite[s].x = sp->x; + sprite[s].y = sp->y; + sprite[s].z = sp->z; + sprite[s].shade = sp->shade; + + setsprite(s,sprite[s].x,sprite[s].y,sprite[s].z); + break; + } + s = nextspritestat[s]; + } + + tempwallptr += 3; + sp->owner = -1; + sp->extra = 8; + changespritestat(i,6); + break; + + case WATERDRIP: + if(j >= 0 && (sprite[j].statnum == 10 || sprite[j].statnum == 1)) + { + sp->shade = 32; + if(sprite[j].pal != 1) + { + sp->pal = 2; + sp->z -= (18<<8); + } + else sp->z -= (13<<8); + sp->ang = getangle(ps[connecthead].posx-sp->x,ps[connecthead].posy-sp->y); + sp->xvel = 48-(TRAND&31); + ssp(i,CLIPMASK0); + } + else if(j == -1) + { + sp->z += (4<<8); + T1 = sp->z; + T2 = TRAND&127; + } + case TRASH: + + if(sp->picnum != WATERDRIP) + sp->ang = TRAND&2047; + + case WATERDRIPSPLASH: + + sp->xrepeat = 24; + sp->yrepeat = 24; + + + changespritestat(i,6); + break; + + case PLUG: + sp->lotag = 9999; + changespritestat(i,6); + break; + case TOUCHPLATE: + T3 = sector[sect].floorz; + if(sector[sect].lotag != 1 && sector[sect].lotag != 2) + sector[sect].floorz = sp->z; + if(sp->pal && ud.multimode > 1) + { + sp->xrepeat=sp->yrepeat=0; + changespritestat(i,5); + break; + } + case WATERBUBBLEMAKER: + sp->cstat |= 32768; + changespritestat(i,6); + break; + case BOLT1: + case BOLT1+1: + case BOLT1+2: + case BOLT1+3: + case SIDEBOLT1: + case SIDEBOLT1+1: + case SIDEBOLT1+2: + case SIDEBOLT1+3: + T1 = sp->xrepeat; + T2 = sp->yrepeat; + case MASTERSWITCH: + if(sp->picnum == MASTERSWITCH) + sp->cstat |= 32768; + sp->yvel = 0; + changespritestat(i,6); + break; + case TARGET: + case DUCK: + case LETTER: + sp->extra = 1; + sp->cstat |= 257; + changespritestat(i,1); + break; + case OCTABRAINSTAYPUT: + case LIZTROOPSTAYPUT: + case PIGCOPSTAYPUT: + case LIZMANSTAYPUT: + case BOSS1STAYPUT: + case PIGCOPDIVE: + case COMMANDERSTAYPUT: + case BOSS4STAYPUT: + hittype[i].actorstayput = sp->sectnum; + case BOSS1: + case BOSS2: + case BOSS3: + case BOSS4: + case ROTATEGUN: + case GREENSLIME: + if(sp->picnum == GREENSLIME) + sp->extra = 1; + case DRONE: + case LIZTROOPONTOILET: + case LIZTROOPJUSTSIT: + case LIZTROOPSHOOT: + case LIZTROOPJETPACK: + case LIZTROOPDUCKING: + case LIZTROOPRUNNING: + case LIZTROOP: + case OCTABRAIN: + case COMMANDER: + case PIGCOP: + case LIZMAN: + case LIZMANSPITTING: + case LIZMANFEEDING: + case LIZMANJUMP: + case ORGANTIC: + case RAT: + case SHARK: + + if(sp->pal == 0) + { + switch(sp->picnum) + { + case LIZTROOPONTOILET: + case LIZTROOPSHOOT: + case LIZTROOPJETPACK: + case LIZTROOPDUCKING: + case LIZTROOPRUNNING: + case LIZTROOPSTAYPUT: + case LIZTROOPJUSTSIT: + case LIZTROOP: + sp->pal = 22; + break; + } + } + + if( sp->picnum == BOSS4STAYPUT || sp->picnum == BOSS1 || sp->picnum == BOSS2 || sp->picnum == BOSS1STAYPUT || sp->picnum == BOSS3 || sp->picnum == BOSS4 ) + { + if(j >= 0 && sprite[j].picnum == RESPAWN) + sp->pal = sprite[j].pal; + if(sp->pal) + { + sp->clipdist = 80; + sp->xrepeat = 40; + sp->yrepeat = 40; + } + else + { + sp->xrepeat = 80; + sp->yrepeat = 80; + sp->clipdist = 164; + } + } + else + { + if(sp->picnum != SHARK) + { + sp->xrepeat = 40; + sp->yrepeat = 40; + sp->clipdist = 80; + } + else + { + sp->xrepeat = 60; + sp->yrepeat = 60; + sp->clipdist = 40; + } + } + + if(j >= 0) sp->lotag = 0; + + if( ( sp->lotag > ud.player_skill ) || ud.monsters_off == 1 ) + { + sp->xrepeat=sp->yrepeat=0; + changespritestat(i,5); + break; + } + else + { + makeitfall(i); + + if(sp->picnum == RAT) + { + sp->ang = TRAND&2047; + sp->xrepeat = sp->yrepeat = 48; + sp->cstat = 0; + } + else + { + sp->cstat |= 257; + + if(sp->picnum != SHARK) + ps[myconnectindex].max_actors_killed++; + } + + if(sp->picnum == ORGANTIC) sp->cstat |= 128; + + if(j >= 0) + { + hittype[i].timetosleep = 0; + check_fta_sounds(i); + changespritestat(i,1); + } + else changespritestat(i,2); + } + + if(sp->picnum == ROTATEGUN) + sp->zvel = 0; + + break; + + case LOCATORS: + sp->cstat |= 32768; + changespritestat(i,7); + break; + + case ACTIVATORLOCKED: + case ACTIVATOR: + sp->cstat = (short) 32768; + if(sp->picnum == ACTIVATORLOCKED) + sector[sp->sectnum].lotag |= 16384; + changespritestat(i,8); + break; + + case DOORSHOCK: + sp->cstat |= 1+256; + sp->shade = -12; + changespritestat(i,6); + break; + + case OOZ: + case OOZ2: + sp->shade = -12; + + if(j >= 0) + { + if( sprite[j].picnum == NUKEBARREL ) + sp->pal = 8; + insertspriteq(i); + } + + changespritestat(i,1); + + getglobalz(i); + + j = (hittype[i].floorz-hittype[i].ceilingz)>>9; + + sp->yrepeat = j; + sp->xrepeat = 25-(j>>1); + sp->cstat |= (TRAND&4); + + break; + + case HEAVYHBOMB: + if(j >= 0) + sp->owner = j; + else sp->owner = i; + sp->xrepeat = sp->yrepeat = 9; + sp->yvel = 4; + case REACTOR2: + case REACTOR: + case RECON: + + if(sp->picnum == RECON) + { + if( sp->lotag > ud.player_skill ) + { + sp->xrepeat = sp->yrepeat = 0; + changespritestat(i,5); + return i; + } + ps[myconnectindex].max_actors_killed++; + hittype[i].temp_data[5] = 0; + if(ud.monsters_off == 1) + { + sp->xrepeat = sp->yrepeat = 0; + changespritestat(i,5); + break; + } + sp->extra = 130; + } + + if(sp->picnum == REACTOR || sp->picnum == REACTOR2) + sp->extra = impact_damage; + + CS |= 257; // Make it hitable + + if( ud.multimode < 2 && sp->pal != 0) + { + sp->xrepeat = sp->yrepeat = 0; + changespritestat(i,5); + break; + } + sp->pal = 0; + SS = -17; + + changespritestat(i,2); + break; + + case ATOMICHEALTH: + case STEROIDS: + case HEATSENSOR: + case SHIELD: + case AIRTANK: + case TRIPBOMBSPRITE: + case JETPACK: + case HOLODUKE: + + case FIRSTGUNSPRITE: + case CHAINGUNSPRITE: + case SHOTGUNSPRITE: + case RPGSPRITE: + case SHRINKERSPRITE: + case FREEZESPRITE: + case DEVISTATORSPRITE: + + case SHOTGUNAMMO: + case FREEZEAMMO: + case HBOMBAMMO: + case CRYSTALAMMO: + case GROWAMMO: + case BATTERYAMMO: + case DEVISTATORAMMO: + case RPGAMMO: + case BOOTS: + case AMMO: + case AMMOLOTS: + case COLA: + case FIRSTAID: + case SIXPAK: + if(j >= 0) + { + sp->lotag = 0; + sp->z -= (32<<8); + sp->zvel = -1024; + ssp(i,CLIPMASK0); + sp->cstat = TRAND&4; + } + else + { + sp->owner = i; + sp->cstat = 0; + } + + if( ( ud.multimode < 2 && sp->pal != 0) || (sp->lotag > ud.player_skill) ) + { + sp->xrepeat = sp->yrepeat = 0; + changespritestat(i,5); + break; + } + + sp->pal = 0; + + case ACCESSCARD: + + if(sp->picnum == ATOMICHEALTH) + sp->cstat |= 128; + + if(ud.multimode > 1 && ud.coop != 1 && sp->picnum == ACCESSCARD) + { + sp->xrepeat = sp->yrepeat = 0; + changespritestat(i,5); + break; + } + else + { + if(sp->picnum == AMMO) + sp->xrepeat = sp->yrepeat = 16; + else sp->xrepeat = sp->yrepeat = 32; + } + + sp->shade = -17; + + if(j >= 0) changespritestat(i,1); + else + { + changespritestat(i,2); + makeitfall(i); + } + break; + + case WATERFOUNTAIN: + SLT = 1; + + case TREE1: + case TREE2: + case TIRE: + case CONE: + case BOX: + CS = 257; // Make it hitable + sprite[i].extra = 1; + changespritestat(i,6); + break; + + case FLOORFLAME: + sp->shade = -127; + changespritestat(i,6); + break; + + case BOUNCEMINE: + sp->owner = i; + sp->cstat |= 1+256; //Make it hitable + sp->xrepeat = sp->yrepeat = 24; + sp->shade = -127; + sp->extra = impact_damage<<2; + changespritestat(i,2); + break; + + case CAMERA1: + case CAMERA1+1: + case CAMERA1+2: + case CAMERA1+3: + case CAMERA1+4: + case CAMERAPOLE: + sp->extra = 1; + + if(camerashitable) sp->cstat = 257; + else sp->cstat = 0; + + case GENERICPOLE: + + if( ud.multimode < 2 && sp->pal != 0 ) + { + sp->xrepeat = sp->yrepeat = 0; + changespritestat(i,5); + break; + } + else sp->pal = 0; + if(sp->picnum == CAMERAPOLE || sp->picnum == GENERICPOLE) break; + sp->picnum = CAMERA1; + changespritestat(i,1); + break; + case STEAM: + if(j >= 0) + { + sp->ang = sprite[j].ang; + sp->cstat = 16+128+2; + sp->xrepeat=sp->yrepeat=1; + sp->xvel = -8; + ssp(i,CLIPMASK0); + } + case CEILINGSTEAM: + changespritestat(i,6); + break; + + case SECTOREFFECTOR: + sp->yvel = sector[sect].extra; + sp->cstat |= 32768; + sp->xrepeat = sp->yrepeat = 0; + + switch(sp->lotag) + { + case 28: + T6 = 65;// Delay for lightning + break; + case 7: // Transporters!!!! + case 23:// XPTR END + if(sp->lotag != 23) + { + for(j=0;jcstat = 0; + changespritestat(i,9); + return i; + case 1: + sp->owner = -1; + T1 = 1; + break; + case 18: + + if(sp->ang == 512) + { + T2 = sector[sect].ceilingz; + if(sp->pal) + sector[sect].ceilingz = sp->z; + } + else + { + T2 = sector[sect].floorz; + if(sp->pal) + sector[sect].floorz = sp->z; + } + + sp->hitag <<= 2; + break; + + case 19: + sp->owner = -1; + break; + case 25: // Pistons + T4 = sector[sect].ceilingz; + T5 = 1; + sector[sect].ceilingz = sp->z; + setinterpolation(§or[sect].ceilingz); + break; + case 35: + sector[sect].ceilingz = sp->z; + break; + case 27: + if(ud.recstat == 1) + { + sp->xrepeat=sp->yrepeat=64; + sp->cstat &= 32767; + } + break; + case 12: + + T2 = sector[sect].floorshade; + T3 = sector[sect].ceilingshade; + break; + + case 13: + + T1 = sector[sect].ceilingz; + T2 = sector[sect].floorz; + + if( klabs(T1-sp->z) < klabs(T2-sp->z) ) + sp->owner = 1; + else sp->owner = 0; + + if(sp->ang == 512) + { + if(sp->owner) + sector[sect].ceilingz = sp->z; + else + sector[sect].floorz = sp->z; + } + else + sector[sect].ceilingz = sector[sect].floorz = sp->z; + + if( sector[sect].ceilingstat&1 ) + { + sector[sect].ceilingstat ^= 1; + T4 = 1; + + if(!sp->owner && sp->ang==512) + { + sector[sect].ceilingstat ^= 1; + T4 = 0; + } + + sector[sect].ceilingshade = + sector[sect].floorshade; + + if(sp->ang==512) + { + startwall = sector[sect].wallptr; + endwall = startwall+sector[sect].wallnum; + for(j=startwall;j= 0) + if( !(sector[x].ceilingstat&1) ) + { + sector[sect].ceilingpicnum = + sector[x].ceilingpicnum; + sector[sect].ceilingshade = + sector[x].ceilingshade; + break; //Leave earily + } + } + } + } + + break; + + case 17: + + T3 = sector[sect].floorz; //Stopping loc + + j = nextsectorneighborz(sect,sector[sect].floorz,-1,-1); + T4 = sector[j].ceilingz; + + j = nextsectorneighborz(sect,sector[sect].ceilingz,1,1); + T5 = sector[j].floorz; + + if(numplayers < 2) + { + setinterpolation(§or[sect].floorz); + setinterpolation(§or[sect].ceilingz); + } + + break; + + case 24: + sp->yvel <<= 1; + case 36: + break; + + case 20: + { + long q; + + startwall = sector[sect].wallptr; + endwall = startwall+sector[sect].wallnum; + + //find the two most clostest wall x's and y's + q = 0x7fffffff; + + for(s=startwall;sx-x,sp->y-y); + if( d < q ) + { + q = d; + clostest = s; + } + } + + T2 = clostest; + + q = 0x7fffffff; + + for(s=startwall;sx-x,sp->y-y); + if(d < q && s != T2) + { + q = d; + clostest = s; + } + } + + T3 = clostest; + } + + break; + + case 3: + + T4=sector[sect].floorshade; + + sector[sect].floorshade = sp->shade; + sector[sect].ceilingshade = sp->shade; + + sp->owner = sector[sect].ceilingpal<<8; + sp->owner |= sector[sect].floorpal; + + //fix all the walls; + + startwall = sector[sect].wallptr; + endwall = startwall+sector[sect].wallnum; + + for(s=startwall;sshade; + if( (wall[s].cstat&2) && wall[s].nextwall >= 0) + wall[wall[s].nextwall].shade = sp->shade; + } + break; + + case 31: + T2 = sector[sect].floorz; + // T3 = sp->hitag; + if(sp->ang != 1536) sector[sect].floorz = sp->z; + + startwall = sector[sect].wallptr; + endwall = startwall+sector[sect].wallnum; + + for(s=startwall;shitag; + if(sp->ang != 1536) sector[sect].ceilingz = sp->z; + + startwall = sector[sect].wallptr; + endwall = startwall+sector[sect].wallnum; + + for(s=startwall;sowner = sector[sect].ceilingpal<<8; + sp->owner |= sector[sect].floorpal; + + for(s=startwall;s T4) + T4 = wall[s].shade; + + break; + + case 9: + if( sector[sect].lotag && + labs(sector[sect].ceilingz-sp->z) > 1024) + sector[sect].lotag |= 32768; //If its open + case 8: + //First, get the ceiling-floor shade + + T1 = sector[sect].floorshade; + T2 = sector[sect].ceilingshade; + + startwall = sector[sect].wallptr; + endwall = startwall+sector[sect].wallnum; + + for(s=startwall;s T3) + T3 = wall[s].shade; + + T4 = 1; //Take Out; + + break; + + case 11://Pivitor rotater + if(sp->ang>1024) T4 = 2; + else T4 = -2; + case 0: + case 2://Earthquakemakers + case 5://Boss Creature + case 6://Subway + case 14://Caboos + case 15://Subwaytype sliding door + case 16://That rotating blocker reactor thing + case 26://ESCELATOR + case 30://No rotational subways + + if(sp->lotag == 0) + { + if( sector[sect].lotag == 30 ) + { + if(sp->pal) sprite[i].clipdist = 1; + else sprite[i].clipdist = 0; + T4 = sector[sect].floorz; + sector[sect].hitag = i; + } + + for(j = 0;j < MAXSPRITES;j++) + { + if( sprite[j].statnum < MAXSTATUS ) + if( sprite[j].picnum == SECTOREFFECTOR && + sprite[j].lotag == 1 && + sprite[j].hitag == sp->hitag) + { + if( sp->ang == 512 ) + { + sp->x = sprite[j].x; + sp->y = sprite[j].y; + } + break; + } + } + if(j == MAXSPRITES) + { + sprintf(tempbuf,"Found lonely Sector Effector (lotag 0) at (%ld,%ld)\n",sp->x,sp->y); + gameexit(tempbuf); + } + sp->owner = j; + } + + startwall = sector[sect].wallptr; + endwall = startwall+sector[sect].wallnum; + + T2 = tempwallptr; + for(s=startwall;sx; + msy[tempwallptr] = wall[s].y-sp->y; + tempwallptr++; + if(tempwallptr > 2047) + { + sprintf(tempbuf,"Too many moving sectors at (%ld,%ld).\n",wall[s].x,wall[s].y); + gameexit(tempbuf); + } + } + if( sp->lotag == 30 || sp->lotag == 6 || sp->lotag == 14 || sp->lotag == 5 ) + { + + startwall = sector[sect].wallptr; + endwall = startwall+sector[sect].wallnum; + + if(sector[sect].hitag == -1) + sp->extra = 0; + else sp->extra = 1; + + sector[sect].hitag = i; + + j = 0; + + for(s=startwall;s= 0 && + sector[ wall[ s ].nextsector].hitag == 0 && + sector[ wall[ s ].nextsector].lotag < 3 ) + { + s = wall[s].nextsector; + j = 1; + break; + } + } + + if(j == 0) + { + sprintf(tempbuf,"Subway found no zero'd sectors with locators\nat (%ld,%ld).\n",sp->x,sp->y); + gameexit(tempbuf); + } + + sp->owner = -1; + T1 = s; + + if(sp->lotag != 30) + T4 = sp->hitag; + } + + else if(sp->lotag == 16) + T4 = sector[sect].ceilingz; + + else if( sp->lotag == 26 ) + { + T4 = sp->x; + T5 = sp->y; + if(sp->shade==sector[sect].floorshade) //UP + sp->zvel = -256; + else + sp->zvel = 256; + + sp->shade = 0; + } + else if( sp->lotag == 2) + { + T6 = sector[sp->sectnum].floorheinum; + sector[sp->sectnum].floorheinum = 0; + } + } + + switch(sp->lotag) + { + case 6: + case 14: + j = callsound(sect,i); + if(j == -1) j = SUBWAY; + hittype[i].lastvx = j; + case 30: + if(numplayers > 1) break; + case 0: + case 1: + case 5: + case 11: + case 15: + case 16: + case 26: + setsectinterpolate(i); + break; + } + + switch(sprite[i].lotag) + { + case 40: + case 41: + case 43: + case 44: + case 45: + changespritestat(i,15); + break; + default: + changespritestat(i,3); + break; + } + + break; + + + case SEENINE: + case OOZFILTER: + + sp->shade = -16; + if(sp->xrepeat <= 8) + { + sp->cstat = (short)32768; + sp->xrepeat=sp->yrepeat=0; + } + else sp->cstat = 1+256; + sp->extra = impact_damage<<2; + sp->owner = i; + + changespritestat(i,6); + break; + + case CRACK1: + case CRACK2: + case CRACK3: + case CRACK4: + case FIREEXT: + if(sp->picnum == FIREEXT) + { + sp->cstat = 257; + sp->extra = impact_damage<<2; + } + else + { + sp->cstat |= 17; + sp->extra = 1; + } + + if( ud.multimode < 2 && sp->pal != 0) + { + sp->xrepeat = sp->yrepeat = 0; + changespritestat(i,5); + break; + } + + sp->pal = 0; + sp->owner = i; + changespritestat(i,6); + sp->xvel = 8; + ssp(i,CLIPMASK0); + break; + + case TOILET: + case STALL: + sp->lotag = 1; + sp->cstat |= 257; + sp->clipdist = 8; + sp->owner = i; + break; + case CANWITHSOMETHING: + case CANWITHSOMETHING2: + case CANWITHSOMETHING3: + case CANWITHSOMETHING4: + case RUBBERCAN: + sp->extra = 0; + case EXPLODINGBARREL: + case HORSEONSIDE: + case FIREBARREL: + case NUKEBARREL: + case FIREVASE: + case NUKEBARRELDENTED: + case NUKEBARRELLEAKED: + case WOODENHORSE: + + if(j >= 0) + sp->xrepeat = sp->yrepeat = 32; + sp->clipdist = 72; + makeitfall(i); + if(j >= 0) + sp->owner = j; + else sp->owner = i; + case EGG: + if( ud.monsters_off == 1 && sp->picnum == EGG ) + { + sp->xrepeat = sp->yrepeat = 0; + changespritestat(i,5); + } + else + { + if(sp->picnum == EGG) + sp->clipdist = 24; + sp->cstat = 257|(TRAND&4); + changespritestat(i,2); + } + break; + case TOILETWATER: + sp->shade = -16; + changespritestat(i,6); + break; + } + return i; +} + + +void animatesprites(long x,long y,short a,long smoothratio) +{ + short i, j, k, p, sect; + long l, t1,t3,t4; + spritetype *s,*t; + + for(j=0;j < spritesortcnt; j++) + { + t = &tsprite[j]; + i = t->owner; + s = &sprite[t->owner]; + + switch(t->picnum) + { + case BLOODPOOL: + case PUKE: + case FOOTPRINTS: + case FOOTPRINTS2: + case FOOTPRINTS3: + case FOOTPRINTS4: + if(t->shade == 127) continue; + break; + case RESPAWNMARKERRED: + case RESPAWNMARKERYELLOW: + case RESPAWNMARKERGREEN: + if(ud.marker == 0) + t->xrepeat = t->yrepeat = 0; + continue; + case CHAIR3: + + k = (((t->ang+3072+128-a)&2047)>>8)&7; + if(k>4) + { + k = 8-k; + t->cstat |= 4; + } + else t->cstat &= ~4; + t->picnum = s->picnum+k; + break; + case BLOODSPLAT1: + case BLOODSPLAT2: + case BLOODSPLAT3: + case BLOODSPLAT4: + if(ud.lockout) t->xrepeat = t->yrepeat = 0; + else if(t->pal == 6) + { + t->shade = -127; + continue; + } + case BULLETHOLE: + case CRACK1: + case CRACK2: + case CRACK3: + case CRACK4: + t->shade = 16; + continue; + case NEON1: + case NEON2: + case NEON3: + case NEON4: + case NEON5: + case NEON6: + continue; + case GREENSLIME: + case GREENSLIME+1: + case GREENSLIME+2: + case GREENSLIME+3: + case GREENSLIME+4: + case GREENSLIME+5: + case GREENSLIME+6: + case GREENSLIME+7: + break; + default: + if( ( (t->cstat&16) ) || ( badguy(t) && t->extra > 0) || t->statnum == 10) + continue; + } + + if (sector[t->sectnum].ceilingstat&1) + l = sector[t->sectnum].ceilingshade; + else + l = sector[t->sectnum].floorshade; + + if(l < -127) l = -127; + if(l > 128) l = 127; + t->shade = l; + } + + + for(j=0;j < spritesortcnt; j++ ) //Between drawrooms() and drawmasks() + { //is the perfect time to animate sprites + t = &tsprite[j]; + i = t->owner; + s = &sprite[i]; + + switch(s->picnum) + { + case SECTOREFFECTOR: + if(t->lotag == 27 && ud.recstat == 1) + { + t->picnum = 11+((totalclock>>3)&1); + t->cstat |= 128; + } + else + t->xrepeat = t->yrepeat = 0; + break; + case NATURALLIGHTNING: + t->shade = -127; + break; + case FEM1: + case FEM2: + case FEM3: + case FEM4: + case FEM5: + case FEM6: + case FEM7: + case FEM8: + case FEM9: + case FEM10: + case MAN: + case MAN2: + case WOMAN: + case NAKED1: + case PODFEM1: + case FEMMAG1: + case FEMMAG2: + case FEMPIC1: + case FEMPIC2: + case FEMPIC3: + case FEMPIC4: + case FEMPIC5: + case FEMPIC6: + case FEMPIC7: + case BLOODYPOLE: + case FEM6PAD: + case STATUE: + case STATUEFLASH: + case OOZ: + case OOZ2: + case WALLBLOOD1: + case WALLBLOOD2: + case WALLBLOOD3: + case WALLBLOOD4: + case WALLBLOOD5: + case WALLBLOOD7: + case WALLBLOOD8: + case SUSHIPLATE1: + case SUSHIPLATE2: + case SUSHIPLATE3: + case SUSHIPLATE4: + case FETUS: + case FETUSJIB: + case FETUSBROKE: + case HOTMEAT: + case FOODOBJECT16: + case DOLPHIN1: + case DOLPHIN2: + case TOUGHGAL: + case TAMPON: + case XXXSTACY: + case 4946: + case 4947: + case 693: + case 2254: + case 4560: + case 4561: + case 4562: + case 4498: + case 4957: + if(ud.lockout) + { + t->xrepeat = t->yrepeat = 0; + continue; + } + } + + if( t->statnum == 99 ) continue; + if( s->statnum != 1 && s->picnum == APLAYER && ps[s->yvel].newowner == -1 && s->owner >= 0 ) + { + t->x -= mulscale16(65536-smoothratio,ps[s->yvel].posx-ps[s->yvel].oposx); + t->y -= mulscale16(65536-smoothratio,ps[s->yvel].posy-ps[s->yvel].oposy); + t->z = ps[s->yvel].oposz + mulscale16(smoothratio,ps[s->yvel].posz-ps[s->yvel].oposz); + t->z += (40<<8); + } + else if( ( s->statnum == 0 && s->picnum != CRANEPOLE) || s->statnum == 10 || s->statnum == 6 || s->statnum == 4 || s->statnum == 5 || s->statnum == 1 ) + { + t->x -= mulscale16(65536-smoothratio,s->x-hittype[i].bposx); + t->y -= mulscale16(65536-smoothratio,s->y-hittype[i].bposy); + t->z -= mulscale16(65536-smoothratio,s->z-hittype[i].bposz); + } + + sect = s->sectnum; + t1 = T2;t3 = T4;t4 = T5; + + switch(s->picnum) + { + case DUKELYINGDEAD: + t->z += (24<<8); + break; + case BLOODPOOL: + case FOOTPRINTS: + case FOOTPRINTS2: + case FOOTPRINTS3: + case FOOTPRINTS4: + if(t->pal == 6) + t->shade = -127; + case PUKE: + case MONEY: + case MONEY+1: + case MAIL: + case MAIL+1: + case PAPER: + case PAPER+1: + if(ud.lockout && s->pal == 2) + { + t->xrepeat = t->yrepeat = 0; + continue; + } + break; + case TRIPBOMB: + continue; + case FORCESPHERE: + if(t->statnum == 5) + { + short sqa,sqb; + + sqa = + getangle( + sprite[s->owner].x-ps[screenpeek].posx, + sprite[s->owner].y-ps[screenpeek].posy); + sqb = + getangle( + sprite[s->owner].x-t->x, + sprite[s->owner].y-t->y); + + if( klabs(getincangle(sqa,sqb)) > 512 ) + if( ldist(&sprite[s->owner],t) < ldist(&sprite[ps[screenpeek].i],&sprite[s->owner]) ) + t->xrepeat = t->yrepeat = 0; + } + continue; + case BURNING: + case BURNING2: + if( sprite[s->owner].statnum == 10 ) + { + if( display_mirror == 0 && sprite[s->owner].yvel == screenpeek && ps[sprite[s->owner].yvel].over_shoulder_on == 0 ) + t->xrepeat = 0; + else + { + t->ang = getangle(x-t->x,y-t->y); + t->x = sprite[s->owner].x; + t->y = sprite[s->owner].y; + t->x += sintable[(t->ang+512)&2047]>>10; + t->y += sintable[t->ang&2047]>>10; + } + } + break; + + case ATOMICHEALTH: + t->z -= (4<<8); + break; + case CRYSTALAMMO: + t->shade = (sintable[(totalclock<<4)&2047]>>10); + continue; + case VIEWSCREEN: + case VIEWSCREEN2: + if(camsprite >= 0 && hittype[OW].temp_data[0] == 1) + { + t->picnum = STATIC; + t->cstat |= (rand()&12); + t->xrepeat += 8; + t->yrepeat += 8; + } + break; + + case SHRINKSPARK: + t->picnum = SHRINKSPARK+( (totalclock>>4)&3 ); + break; + case GROWSPARK: + t->picnum = GROWSPARK+( (totalclock>>4)&3 ); + break; + case RPG: + k = getangle(s->x-x,s->y-y); + k = (((s->ang+3072+128-k)&2047)/170); + if(k > 6) + { + k = 12-k; + t->cstat |= 4; + } + else t->cstat &= ~4; + t->picnum = RPG+k; + break; + + case RECON: + + k = getangle(s->x-x,s->y-y); + if( T1 < 4 ) + k = (((s->ang+3072+128-k)&2047)/170); + else k = (((s->ang+3072+128-k)&2047)/170); + + if(k>6) + { + k = 12-k; + t->cstat |= 4; + } + else t->cstat &= ~4; + + if( klabs(t3) > 64 ) k += 7; + t->picnum = RECON+k; + + break; + + case APLAYER: + + p = s->yvel; + + if(t->pal == 1) t->z -= (18<<8); + + if(ps[p].over_shoulder_on > 0 && ps[p].newowner < 0 ) + { + t->cstat |= 2; + if ( screenpeek == myconnectindex && numplayers >= 2 ) + { + t->x = omyx+mulscale16((long)(myx-omyx),smoothratio); + t->y = omyy+mulscale16((long)(myy-omyy),smoothratio); + t->z = omyz+mulscale16((long)(myz-omyz),smoothratio)+(40<<8); + t->ang = omyang+mulscale16((long)(((myang+1024-omyang)&2047)-1024),smoothratio); + t->sectnum = mycursectnum; + } + } + + if( ( display_mirror == 1 || screenpeek != p || s->owner == -1 ) && ud.multimode > 1 && ud.showweapons && sprite[ps[p].i].extra > 0 && ps[p].curr_weapon > 0 ) + { + memcpy((spritetype *)&tsprite[spritesortcnt],(spritetype *)t,sizeof(spritetype)); + + tsprite[spritesortcnt].statnum = 99; + + tsprite[spritesortcnt].yrepeat = ( t->yrepeat>>3 ); + if(t->yrepeat < 4) t->yrepeat = 4; + + tsprite[spritesortcnt].shade = t->shade; + tsprite[spritesortcnt].cstat = 0; + + switch(ps[p].curr_weapon) + { + case PISTOL_WEAPON: tsprite[spritesortcnt].picnum = FIRSTGUNSPRITE; break; + case SHOTGUN_WEAPON: tsprite[spritesortcnt].picnum = SHOTGUNSPRITE; break; + case CHAINGUN_WEAPON: tsprite[spritesortcnt].picnum = CHAINGUNSPRITE; break; + case RPG_WEAPON: tsprite[spritesortcnt].picnum = RPGSPRITE; break; + case HANDREMOTE_WEAPON: + case HANDBOMB_WEAPON: tsprite[spritesortcnt].picnum = HEAVYHBOMB; break; + case TRIPBOMB_WEAPON: tsprite[spritesortcnt].picnum = TRIPBOMBSPRITE; break; + case GROW_WEAPON: tsprite[spritesortcnt].picnum = GROWSPRITEICON; break; + case SHRINKER_WEAPON: tsprite[spritesortcnt].picnum = SHRINKERSPRITE; break; + case FREEZE_WEAPON: tsprite[spritesortcnt].picnum = FREEZESPRITE; break; + case DEVISTATOR_WEAPON: tsprite[spritesortcnt].picnum = DEVISTATORSPRITE; break; + } + + if(s->owner >= 0) + tsprite[spritesortcnt].z = ps[p].posz-(12<<8); + else tsprite[spritesortcnt].z = s->z-(51<<8); + if(ps[p].curr_weapon == HANDBOMB_WEAPON) + { + tsprite[spritesortcnt].xrepeat = 10; + tsprite[spritesortcnt].yrepeat = 10; + } + else + { + tsprite[spritesortcnt].xrepeat = 16; + tsprite[spritesortcnt].yrepeat = 16; + } + tsprite[spritesortcnt].pal = 0; + spritesortcnt++; + } + + if(s->owner == -1) + { + k = (((s->ang+3072+128-a)&2047)>>8)&7; + if(k>4) + { + k = 8-k; + t->cstat |= 4; + } + else t->cstat &= ~4; + + if(sector[t->sectnum].lotag == 2) k += 1795-1405; + else if( (hittype[i].floorz-s->z) > (64<<8) ) k += 60; + + t->picnum += k; + t->pal = ps[p].palookup; + + goto PALONLY; + } + + if( ps[p].on_crane == -1 && (sector[s->sectnum].lotag&0x7ff) != 1 ) + { + l = s->z-hittype[ps[p].i].floorz+(3<<8); + if( l > 1024 && s->yrepeat > 32 && s->extra > 0 ) + s->yoffset = (signed char)(l/(s->yrepeat<<2)); + else s->yoffset=0; + } + + if(ps[p].newowner > -1) + { + t4 = *(actorscrptr[APLAYER]+1); + t3 = 0; + t1 = *(actorscrptr[APLAYER]+2); + } + + if(ud.camerasprite == -1 && ps[p].newowner == -1) + if(s->owner >= 0 && display_mirror == 0 && ps[p].over_shoulder_on == 0 ) + if( ud.multimode < 2 || ( ud.multimode > 1 && p == screenpeek ) ) + { + t->owner = -1; + t->xrepeat = t->yrepeat = 0; + continue; + } + + PALONLY: + + if( sector[sect].floorpal ) + t->pal = sector[sect].floorpal; + + if(s->owner == -1) continue; + + if( t->z > hittype[i].floorz && t->xrepeat < 32 ) + t->z = hittype[i].floorz; + + break; + + case JIBS1: + case JIBS2: + case JIBS3: + case JIBS4: + case JIBS5: + case JIBS6: + case HEADJIB1: + case LEGJIB1: + case ARMJIB1: + case LIZMANHEAD1: + case LIZMANARM1: + case LIZMANLEG1: + case DUKELEG: + case DUKEGUN: + case DUKETORSO: + if(ud.lockout) + { + t->xrepeat = t->yrepeat = 0; + continue; + } + if(t->pal == 6) t->shade = -120; + + case SCRAP1: + case SCRAP2: + case SCRAP3: + case SCRAP4: + case SCRAP5: + case SCRAP6: + case SCRAP6+1: + case SCRAP6+2: + case SCRAP6+3: + case SCRAP6+4: + case SCRAP6+5: + case SCRAP6+6: + case SCRAP6+7: + + if(hittype[i].picnum == BLIMP && t->picnum == SCRAP1 && s->yvel >= 0) + t->picnum = s->yvel; + else t->picnum += T1; + t->shade -= 6; + + if( sector[sect].floorpal ) + t->pal = sector[sect].floorpal; + break; + + case WATERBUBBLE: + if(sector[t->sectnum].floorpicnum == FLOORSLIME) + { + t->pal = 7; + break; + } + default: + + if( sector[sect].floorpal ) + t->pal = sector[sect].floorpal; + break; + } + + if( actorscrptr[s->picnum] ) + { + if(t4) + { + l = *(long *)(t4+8); + + switch( l ) + { + case 2: + k = (((s->ang+3072+128-a)&2047)>>8)&1; + break; + + case 3: + case 4: + k = (((s->ang+3072+128-a)&2047)>>7)&7; + if(k > 3) + { + t->cstat |= 4; + k = 7-k; + } + else t->cstat &= ~4; + break; + + case 5: + k = getangle(s->x-x,s->y-y); + k = (((s->ang+3072+128-k)&2047)>>8)&7; + if(k>4) + { + k = 8-k; + t->cstat |= 4; + } + else t->cstat &= ~4; + break; + case 7: + k = getangle(s->x-x,s->y-y); + k = (((s->ang+3072+128-k)&2047)/170); + if(k>6) + { + k = 12-k; + t->cstat |= 4; + } + else t->cstat &= ~4; + break; + case 8: + k = (((s->ang+3072+128-a)&2047)>>8)&7; + t->cstat &= ~4; + break; + default: + k = 0; + break; + } + + t->picnum += k + ( *(long *)t4 ) + l * t3; + + if(l > 0) while(tilesizx[t->picnum] == 0 && t->picnum > 0 ) + t->picnum -= l; //Hack, for actors + + if( hittype[i].dispicnum >= 0) + hittype[i].dispicnum = t->picnum; + } + else if(display_mirror == 1) + t->cstat |= 4; + } + + if( s->statnum == 13 || badguy(s) || (s->picnum == APLAYER && s->owner >= 0) ) + if(t->statnum != 99 && s->picnum != EXPLOSION2 && s->picnum != HANGLIGHT && s->picnum != DOMELITE) + if(s->picnum != HOTMEAT) + { + if( hittype[i].dispicnum < 0 ) + { + hittype[i].dispicnum++; + continue; + } + else if( ud.shadows && spritesortcnt < (MAXSPRITESONSCREEN-2)) + { + long daz,xrep,yrep; + + if( (sector[sect].lotag&0xff) > 2 || s->statnum == 4 || s->statnum == 5 || s->picnum == DRONE || s->picnum == COMMANDER ) + daz = sector[sect].floorz; + else + daz = hittype[i].floorz; + + if( (s->z-daz) < (8<<8) ) + if( ps[screenpeek].posz < daz ) + { + memcpy((spritetype *)&tsprite[spritesortcnt],(spritetype *)t,sizeof(spritetype)); + + tsprite[spritesortcnt].statnum = 99; + + tsprite[spritesortcnt].yrepeat = ( t->yrepeat>>3 ); + if(t->yrepeat < 4) t->yrepeat = 4; + + tsprite[spritesortcnt].shade = 127; + tsprite[spritesortcnt].cstat |= 2; + + tsprite[spritesortcnt].z = daz; + xrep = tsprite[spritesortcnt].xrepeat;// - (klabs(daz-t->z)>>11); + tsprite[spritesortcnt].xrepeat = xrep; + tsprite[spritesortcnt].pal = 4; + + yrep = tsprite[spritesortcnt].yrepeat;// - (klabs(daz-t->z)>>11); + tsprite[spritesortcnt].yrepeat = yrep; + spritesortcnt++; + } + } + + if( ps[screenpeek].heat_amount > 0 && ps[screenpeek].heat_on ) + { + t->pal = 6; + t->shade = 0; + } + } + + + switch(s->picnum) + { + case LASERLINE: + if(sector[t->sectnum].lotag == 2) t->pal = 8; + t->z = sprite[s->owner].z-(3<<8); + if(lasermode == 2 && ps[screenpeek].heat_on == 0 ) + t->yrepeat = 0; + case EXPLOSION2: + case EXPLOSION2BOT: + case FREEZEBLAST: + case ATOMICHEALTH: + case FIRELASER: + case SHRINKSPARK: + case GROWSPARK: + case CHAINGUN: + case SHRINKEREXPLOSION: + case RPG: + case FLOORFLAME: + if(t->picnum == EXPLOSION2) + { + ps[screenpeek].visibility = -127; + lastvisinc = totalclock+32; + restorepalette = 1; + } + t->shade = -127; + break; + case FIRE: + case FIRE2: + case BURNING: + case BURNING2: + if( sprite[s->owner].picnum != TREE1 && sprite[s->owner].picnum != TREE2 ) + t->z = sector[t->sectnum].floorz; + t->shade = -127; + break; + case COOLEXPLOSION1: + t->shade = -127; + t->picnum += (s->shade>>1); + break; + case PLAYERONWATER: + + k = (((t->ang+3072+128-a)&2047)>>8)&7; + if(k>4) + { + k = 8-k; + t->cstat |= 4; + } + else t->cstat &= ~4; + + t->picnum = s->picnum+k+((T1<4)*5); + t->shade = sprite[s->owner].shade; + + break; + + case WATERSPLASH2: + t->picnum = WATERSPLASH2+t1; + break; + case REACTOR2: + t->picnum = s->picnum + T3; + break; + case SHELL: + t->picnum = s->picnum+(T1&1); + case SHOTGUNSHELL: + t->cstat |= 12; + if(T1 > 1) t->cstat &= ~4; + if(T1 > 2) t->cstat &= ~12; + break; + case FRAMEEFFECT1: + if(s->owner >= 0 && sprite[s->owner].statnum < MAXSTATUS) + { + if(sprite[s->owner].picnum == APLAYER) + if(ud.camerasprite == -1) + if(screenpeek == sprite[s->owner].yvel && display_mirror == 0) + { + t->owner = -1; + break; + } + if( (sprite[s->owner].cstat&32768) == 0 ) + { + t->picnum = hittype[s->owner].dispicnum; + t->pal = sprite[s->owner].pal; + t->shade = sprite[s->owner].shade; + t->ang = sprite[s->owner].ang; + t->cstat = 2|sprite[s->owner].cstat; + } + } + break; + + case CAMERA1: + case RAT: + k = (((t->ang+3072+128-a)&2047)>>8)&7; + if(k>4) + { + k = 8-k; + t->cstat |= 4; + } + else t->cstat &= ~4; + t->picnum = s->picnum+k; + break; + } + + hittype[i].dispicnum = t->picnum; + if(sector[t->sectnum].floorpicnum == MIRROR) + t->xrepeat = t->yrepeat = 0; + } +} + + + +#define NUMCHEATCODES 26 +char cheatquotes[NUMCHEATCODES][14] = { + {"cornholio"}, + {"stuff"}, +#ifndef VOLUMEONE + {"scotty###"}, +#else + {"scotty##"}, +#endif + {"coords"}, + {"view"}, + {"time"}, +#ifndef VOLUMEONE + {"unlock"}, +#else + {""}, +#endif + {"cashman"}, + {"items"}, + {"rate"}, + {"skill#"}, + {"beta"}, + {"hyper"}, + {"monsters"}, +// #ifndef VOLUMEONE +// {"bonus"}, +// #else + {""}, + {""}, +// #endif + {"todd"}, + {"showmap"}, + {"kroz"}, + {"allen"}, + {"clip"}, + {"weapons"}, + {"inventory"}, + {"keys"}, + {"debug"} +// {"ending"} + +}; + + +char cheatbuf[10],cheatbuflen; +void cheats(void) +{ + short ch, i, j, k, keystate, weapon; + + if( (ps[myconnectindex].gm&MODE_TYPE) || (ps[myconnectindex].gm&MODE_MENU)) + return; + +#ifdef BETA + return; +#endif + + if ( ps[myconnectindex].cheat_phase == 1) + { + while (KB_KeyWaiting()) + { + ch = KB_Getch(); + ch = tolower(ch); + + if( !( (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9') ) ) + { + ps[myconnectindex].cheat_phase = 0; +// FTA(46,&ps[myconnectindex]); + return; + } + + cheatbuf[(int)cheatbuflen++] = ch; + cheatbuf[(int)cheatbuflen] = 0; + + if(cheatbuflen > 11) + { + ps[myconnectindex].cheat_phase = 0; + return; + } + + for(k = 0;k < NUMCHEATCODES;k++) + { + for(j = 0;j= '0' && ch <= '9') ) + { + if( cheatquotes[k][j+1] == 0 ) goto FOUNDCHEAT; + if(j == cheatbuflen-1) return; + } + else break; + } + } + + ps[myconnectindex].cheat_phase = 0; + return; + + FOUNDCHEAT: + { + switch(k) + { + case 21: +#ifdef VOLUMEONE + j = 6; +#else + j = 0; +#endif + + for ( weapon = PISTOL_WEAPON;weapon < MAX_WEAPONS-j;weapon++ ) + { + addammo( weapon, &ps[myconnectindex], max_ammo_amount[weapon] ); + ps[myconnectindex].gotweapon[weapon] = 1; + } + + KB_FlushKeyboardQueue(); + ps[myconnectindex].cheat_phase = 0; + FTA(119,&ps[myconnectindex]); + return; + case 22: + KB_FlushKeyboardQueue(); + ps[myconnectindex].cheat_phase = 0; + ps[myconnectindex].steroids_amount = 400; + ps[myconnectindex].heat_amount = 1200; + ps[myconnectindex].boot_amount = 200; + ps[myconnectindex].shield_amount = 100; + ps[myconnectindex].scuba_amount = 6400; + ps[myconnectindex].holoduke_amount = 2400; + ps[myconnectindex].jetpack_amount = 1600; + ps[myconnectindex].firstaid_amount = max_player_health; + FTA(120,&ps[myconnectindex]); + ps[myconnectindex].cheat_phase = 0; + return; + case 23: + ps[myconnectindex].got_access = 7; + KB_FlushKeyboardQueue(); + ps[myconnectindex].cheat_phase = 0; + FTA(121,&ps[myconnectindex]); + return; + case 24: + debug_on = 1-debug_on; + KB_FlushKeyboardQueue(); + ps[myconnectindex].cheat_phase = 0; + break; + case 20: + ud.clipping = 1-ud.clipping; + KB_FlushKeyboardQueue(); + ps[myconnectindex].cheat_phase = 0; + FTA(112+ud.clipping,&ps[myconnectindex]); + return; + + case 15: + ps[myconnectindex].gm = MODE_EOL; + ps[myconnectindex].cheat_phase = 0; + KB_FlushKeyboardQueue(); + return; + + case 19: + FTA(79,&ps[myconnectindex]); + ps[myconnectindex].cheat_phase = 0; + KB_ClearKeyDown(sc_N); + return; + case 0: + case 18: + + ud.god = 1-ud.god; + + if(ud.god) + { + pus = 1; + pub = 1; + sprite[ps[myconnectindex].i].cstat = 257; + + hittype[ps[myconnectindex].i].temp_data[0] = 0; + hittype[ps[myconnectindex].i].temp_data[1] = 0; + hittype[ps[myconnectindex].i].temp_data[2] = 0; + hittype[ps[myconnectindex].i].temp_data[3] = 0; + hittype[ps[myconnectindex].i].temp_data[4] = 0; + hittype[ps[myconnectindex].i].temp_data[5] = 0; + + sprite[ps[myconnectindex].i].hitag = 0; + sprite[ps[myconnectindex].i].lotag = 0; + sprite[ps[myconnectindex].i].pal = + ps[myconnectindex].palookup; + + FTA(17,&ps[myconnectindex]); + } + else + { + ud.god = 0; + sprite[ps[myconnectindex].i].extra = max_player_health; + hittype[ps[myconnectindex].i].extra = -1; + ps[myconnectindex].last_extra = max_player_health; + FTA(18,&ps[myconnectindex]); + } + + sprite[ps[myconnectindex].i].extra = max_player_health; + hittype[ps[myconnectindex].i].extra = 0; + ps[myconnectindex].cheat_phase = 0; + KB_FlushKeyboardQueue(); + + return; + + case 1: + +#ifdef VOLUMEONE + j = 6; +#else + j = 0; +#endif + for ( weapon = PISTOL_WEAPON;weapon < MAX_WEAPONS-j;weapon++ ) + ps[myconnectindex].gotweapon[weapon] = 1; + + for ( weapon = PISTOL_WEAPON; + weapon < (MAX_WEAPONS-j); + weapon++ ) + addammo( weapon, &ps[myconnectindex], max_ammo_amount[weapon] ); + + ps[myconnectindex].ammo_amount[GROW_WEAPON] = 50; + + ps[myconnectindex].steroids_amount = 400; + ps[myconnectindex].heat_amount = 1200; + ps[myconnectindex].boot_amount = 200; + ps[myconnectindex].shield_amount = 100; + ps[myconnectindex].scuba_amount = 6400; + ps[myconnectindex].holoduke_amount = 2400; + ps[myconnectindex].jetpack_amount = 1600; + ps[myconnectindex].firstaid_amount = max_player_health; + + ps[myconnectindex].got_access = 7; + FTA(5,&ps[myconnectindex]); + ps[myconnectindex].cheat_phase = 0; + + +// FTA(21,&ps[myconnectindex]); + ps[myconnectindex].cheat_phase = 0; + KB_FlushKeyboardQueue(); + ps[myconnectindex].inven_icon = 1; + return; + + case 2: + case 10: +#ifdef ONELEVELDEMO + ps[myconnectindex].cheat_phase = 0; + break; +#endif + + if(k == 2) + { + short volnume,levnume; +#ifdef VOLUMEALL + volnume = cheatbuf[6] - '0'; + levnume = (cheatbuf[7] - '0')*10+(cheatbuf[8]-'0'); +#else + volnume = cheatbuf[6] - '0'; + levnume = cheatbuf[7] - '0'; +#endif + + volnume--; + levnume--; +#ifdef VOLUMEONE + if( volnume > 0 ) + { + ps[myconnectindex].cheat_phase = 0; + KB_FlushKeyboardQueue(); + return; + } +#endif +#ifdef PLUTOPAK + if(volnume > 4) + { + ps[myconnectindex].cheat_phase = 0; + KB_FlushKeyboardQueue(); + return; + } + else +#else + if(volnume > 3) + { + ps[myconnectindex].cheat_phase = 0; + KB_FlushKeyboardQueue(); + return; + } + else +#endif + + if(volnume == 0) + { + if(levnume > 5) + { + ps[myconnectindex].cheat_phase = 0; + KB_FlushKeyboardQueue(); + return; + } + } + else + { + if(levnume >= 11) + { + ps[myconnectindex].cheat_phase = 0; + KB_FlushKeyboardQueue(); + return; + } + } + + ud.m_volume_number = ud.volume_number = volnume; + ud.m_level_number = ud.level_number = levnume; + + } + else ud.m_player_skill = ud.player_skill = + cheatbuf[5] - '1'; + + if(numplayers > 1 && myconnectindex == connecthead) + { + tempbuf[0] = 5; + tempbuf[1] = ud.m_level_number; + tempbuf[2] = ud.m_volume_number; + tempbuf[3] = ud.m_player_skill; + tempbuf[4] = ud.m_monsters_off; + tempbuf[5] = ud.m_respawn_monsters; + tempbuf[6] = ud.m_respawn_items; + tempbuf[7] = ud.m_respawn_inventory; + tempbuf[8] = ud.m_coop; + tempbuf[9] = ud.m_marker; + tempbuf[10] = ud.m_ffire; + + for(i=connecthead;i>=0;i=connectpoint2[i]) + sendpacket(i,tempbuf,11); + } + else ps[myconnectindex].gm |= MODE_RESTART; + + ps[myconnectindex].cheat_phase = 0; + KB_FlushKeyboardQueue(); + return; + + case 3: + ps[myconnectindex].cheat_phase = 0; + ud.coords = 1-ud.coords; + KB_FlushKeyboardQueue(); + return; + + case 4: + if( ps[myconnectindex].over_shoulder_on ) + ps[myconnectindex].over_shoulder_on = 0; + else + { + ps[myconnectindex].over_shoulder_on = 1; + cameradist = 0; + cameraclock = totalclock; + } + FTA(22,&ps[myconnectindex]); + ps[myconnectindex].cheat_phase = 0; + KB_FlushKeyboardQueue(); + return; + case 5: + + FTA(21,&ps[myconnectindex]); + ps[myconnectindex].cheat_phase = 0; + KB_FlushKeyboardQueue(); + return; +#ifndef VOLUMEONE + case 6: + for(i=numsectors-1;i>=0;i--) //Unlock + { + j = sector[i].lotag; + if(j == -1 || j == 32767) continue; + if( (j & 0x7fff) > 2 ) + { + if( j&(0xffff-16384) ) + sector[i].lotag &= (0xffff-16384); + operatesectors(i,ps[myconnectindex].i); + } + } + operateforcefields(ps[myconnectindex].i,-1); + + FTA(100,&ps[myconnectindex]); + ps[myconnectindex].cheat_phase = 0; + KB_FlushKeyboardQueue(); + return; +#endif + + case 7: + ud.cashman = 1-ud.cashman; + KB_ClearKeyDown(sc_N); + ps[myconnectindex].cheat_phase = 0; + return; + case 8: + + ps[myconnectindex].steroids_amount = 400; + ps[myconnectindex].heat_amount = 1200; + ps[myconnectindex].boot_amount = 200; + ps[myconnectindex].shield_amount = 100; + ps[myconnectindex].scuba_amount = 6400; + ps[myconnectindex].holoduke_amount = 2400; + ps[myconnectindex].jetpack_amount = 1600; + + ps[myconnectindex].firstaid_amount = max_player_health; + ps[myconnectindex].got_access = 7; + FTA(5,&ps[myconnectindex]); + ps[myconnectindex].cheat_phase = 0; + KB_FlushKeyboardQueue(); + return; + case 17: // SHOW ALL OF THE MAP TOGGLE; + ud.showallmap = 1-ud.showallmap; + if(ud.showallmap) + { + for(i=0;i<(MAXSECTORS>>3);i++) + show2dsector[i] = 255; + for(i=0;i<(MAXWALLS>>3);i++) + show2dwall[i] = 255; + FTA(111,&ps[myconnectindex]); + } + else + { + for(i=0;i<(MAXSECTORS>>3);i++) + show2dsector[i] = 0; + for(i=0;i<(MAXWALLS>>3);i++) + show2dwall[i] = 0; + FTA(1,&ps[myconnectindex]); + } + ps[myconnectindex].cheat_phase = 0; + KB_FlushKeyboardQueue(); + return; + + case 16: + FTA(99,&ps[myconnectindex]); + ps[myconnectindex].cheat_phase = 0; + KB_FlushKeyboardQueue(); + return; + case 9: + ud.tickrate = !ud.tickrate; + ps[myconnectindex].cheat_phase = 0; + KB_FlushKeyboardQueue(); + return; + case 11: + FTA(105,&ps[myconnectindex]); + KB_ClearKeyDown(sc_H); + ps[myconnectindex].cheat_phase = 0; + KB_FlushKeyboardQueue(); + return; + case 12: + ps[myconnectindex].steroids_amount = 399; + ps[myconnectindex].heat_amount = 1200; + ps[myconnectindex].cheat_phase = 0; + FTA(37,&ps[myconnectindex]); + KB_FlushKeyboardQueue(); + return; + case 13: + if(actor_tog == 3) actor_tog = 0; + actor_tog++; + ps[screenpeek].cheat_phase = 0; + KB_FlushKeyboardQueue(); + return; + case 14: + case 25: + ud.eog = 1; + ps[myconnectindex].gm |= MODE_EOL; + KB_FlushKeyboardQueue(); + return; + } + } + } + } + + else + { + if( KB_KeyPressed(sc_D) ) + { + if( ps[myconnectindex].cheat_phase >= 0 && numplayers < 2 && ud.recstat == 0) + ps[myconnectindex].cheat_phase = -1; + } + + if( KB_KeyPressed(sc_N) ) + { + if( ps[myconnectindex].cheat_phase == -1 ) + { + if(ud.player_skill == 4) + { + FTA(22,&ps[myconnectindex]); + ps[myconnectindex].cheat_phase = 0; + } + else + { + ps[myconnectindex].cheat_phase = 1; +// FTA(25,&ps[myconnectindex]); + cheatbuflen = 0; + } + KB_FlushKeyboardQueue(); + } + else if(ps[myconnectindex].cheat_phase != 0) + { + ps[myconnectindex].cheat_phase = 0; + KB_ClearKeyDown(sc_D); + KB_ClearKeyDown(sc_N); + } + } + } +} + + +long nonsharedtimer; +void nonsharedkeys(void) +{ + short i,ch, weapon; + long j; + + if(ud.recstat == 2) + { + ControlInfo noshareinfo; + CONTROL_GetInput( &noshareinfo ); + } + + if( KB_KeyPressed( sc_F12 ) ) + { + KB_ClearKeyDown( sc_F12 ); + dukescreencapture("duke0000.pcx",0); + FTA(103,&ps[myconnectindex]); + } + + if( !ALT_IS_PRESSED && ud.overhead_on == 0) + { + if( BUTTON( gamefunc_Enlarge_Screen ) ) + { + CONTROL_ClearButton( gamefunc_Enlarge_Screen ); + if(ud.screen_size > 0) + sound(THUD); + ud.screen_size -= 4; + vscrn(); + } + if( BUTTON( gamefunc_Shrink_Screen ) ) + { + CONTROL_ClearButton( gamefunc_Shrink_Screen ); + if(ud.screen_size < 64) sound(THUD); + ud.screen_size += 4; + vscrn(); + } + } + + if( ps[myconnectindex].cheat_phase == 1 || ps[myconnectindex].gm&(MODE_MENU|MODE_TYPE)) return; + + if( BUTTON(gamefunc_See_Coop_View) && ( ud.coop == 1 || ud.recstat == 2) ) + { + CONTROL_ClearButton( gamefunc_See_Coop_View ); + screenpeek = connectpoint2[screenpeek]; + if(screenpeek == -1) screenpeek = connecthead; + restorepalette = 1; + } + + if( ud.multimode > 1 && BUTTON(gamefunc_Show_Opponents_Weapon) ) + { + CONTROL_ClearButton(gamefunc_Show_Opponents_Weapon); + ud.showweapons = 1-ud.showweapons; + FTA(82-ud.showweapons,&ps[screenpeek]); + } + + if( BUTTON(gamefunc_Toggle_Crosshair) ) + { + CONTROL_ClearButton(gamefunc_Toggle_Crosshair); + ud.crosshair = 1-ud.crosshair; + FTA(21-ud.crosshair,&ps[screenpeek]); + } + + if(ud.overhead_on && BUTTON(gamefunc_Map_Follow_Mode) ) + { + CONTROL_ClearButton(gamefunc_Map_Follow_Mode); + ud.scrollmode = 1-ud.scrollmode; + if(ud.scrollmode) + { + ud.folx = ps[screenpeek].oposx; + ud.foly = ps[screenpeek].oposy; + ud.fola = ps[screenpeek].oang; + } + FTA(83+ud.scrollmode,&ps[myconnectindex]); + } + + if( SHIFTS_IS_PRESSED || ALT_IS_PRESSED ) + { + i = 0; + if( KB_KeyPressed( sc_F1) ) { KB_ClearKeyDown(sc_F1);i = 1; } + if( KB_KeyPressed( sc_F2) ) { KB_ClearKeyDown(sc_F2);i = 2; } + if( KB_KeyPressed( sc_F3) ) { KB_ClearKeyDown(sc_F3);i = 3; } + if( KB_KeyPressed( sc_F4) ) { KB_ClearKeyDown(sc_F4);i = 4; } + if( KB_KeyPressed( sc_F5) ) { KB_ClearKeyDown(sc_F5);i = 5; } + if( KB_KeyPressed( sc_F6) ) { KB_ClearKeyDown(sc_F6);i = 6; } + if( KB_KeyPressed( sc_F7) ) { KB_ClearKeyDown(sc_F7);i = 7; } + if( KB_KeyPressed( sc_F8) ) { KB_ClearKeyDown(sc_F8);i = 8; } + if( KB_KeyPressed( sc_F9) ) { KB_ClearKeyDown(sc_F9);i = 9; } + if( KB_KeyPressed( sc_F10) ) {KB_ClearKeyDown(sc_F10);i = 10; } + + if(i) + { + if(SHIFTS_IS_PRESSED) + { + if(i == 5 && ps[myconnectindex].fta > 0 && ps[myconnectindex].ftq == 26) + { + music_select++; +#ifdef VOLUMEALL + if(music_select == 44) music_select = 0; +#else + if(music_select == 6) music_select = 0; +#endif + strcpy(&tempbuf[0],"PLAYING "); + strcat(&tempbuf[0],&music_fn[0][(int)music_select][0]); + playmusic(&music_fn[0][(int)music_select][0]); + strcpy(&fta_quotes[26][0],&tempbuf[0]); + FTA(26,&ps[myconnectindex]); + return; + } + + adduserquote(ud.ridecule[i-1]); + + ch = 0; + + tempbuf[ch] = 4; + tempbuf[ch+1] = 0; + strcat(tempbuf+1,ud.ridecule[i-1]); + + i = 1+strlen(ud.ridecule[i-1]); + + if(ud.multimode > 1) + for(ch=connecthead;ch>=0;ch=connectpoint2[ch]) + if (ch != myconnectindex) + sendpacket(ch,tempbuf,i); + + pus = NUMPAGES; + pub = NUMPAGES; + + return; + + } + + if(ud.lockout == 0) + if(SoundToggle && ALT_IS_PRESSED && ( RTS_NumSounds() > 0 ) && rtsplaying == 0 && VoiceToggle ) + { + rtsptr = (char *)RTS_GetSound (i-1); + if(*rtsptr == 'C') + FX_PlayVOC3D( rtsptr,0,0,0,255,-i); + else FX_PlayWAV3D( rtsptr,0,0,0,255,-i); + + rtsplaying = 7; + + if(ud.multimode > 1) + { + tempbuf[0] = 7; + tempbuf[1] = i; + + for(ch=connecthead;ch>=0;ch=connectpoint2[ch]) + if(ch != myconnectindex) + sendpacket(ch,tempbuf,2); + } + + pus = NUMPAGES; + pub = NUMPAGES; + + return; + } + } + } + + if(!ALT_IS_PRESSED && !SHIFTS_IS_PRESSED) + { + + if( ud.multimode > 1 && BUTTON(gamefunc_SendMessage) ) + { + KB_FlushKeyboardQueue(); + CONTROL_ClearButton( gamefunc_SendMessage ); + ps[myconnectindex].gm |= MODE_TYPE; + typebuf[0] = 0; + inputloc = 0; + } + + if( KB_KeyPressed(sc_F1) || ( ud.show_help && ( KB_KeyPressed(sc_Space) || KB_KeyPressed(sc_Enter) || KB_KeyPressed(sc_kpad_Enter) ) ) ) + { + KB_ClearKeyDown(sc_F1); + KB_ClearKeyDown(sc_Space); + KB_ClearKeyDown(sc_kpad_Enter); + KB_ClearKeyDown(sc_Enter); + ud.show_help ++; + + if( ud.show_help > 2 ) + { + ud.show_help = 0; + if(ud.multimode < 2 && ud.recstat != 2) ready2send = 1; + vscrn(); + } + else + { + setview(0,0,xdim-1,ydim-1); + if(ud.multimode < 2 && ud.recstat != 2) + { + ready2send = 0; + totalclock = ototalclock; + } + } + } + +// if(ud.multimode < 2) + { + if(ud.recstat != 2 && KB_KeyPressed( sc_F2 ) ) + { + KB_ClearKeyDown( sc_F2 ); + + if(movesperpacket == 4 && connecthead != myconnectindex) + return; + + FAKE_F2: + if(sprite[ps[myconnectindex].i].extra <= 0) + { + FTA(118,&ps[myconnectindex]); + return; + } + cmenu(350); + screencapt = 1; + displayrooms(myconnectindex,65536); + savetemp("duke3d.tmp",waloff[MAXTILES-1],160*100); + screencapt = 0; + FX_StopAllSounds(); + clearsoundlocks(); + +// setview(0,0,xdim-1,ydim-1); + ps[myconnectindex].gm |= MODE_MENU; + + if(ud.multimode < 2) + { + ready2send = 0; + totalclock = ototalclock; + screenpeek = myconnectindex; + } + } + + if(KB_KeyPressed( sc_F3 )) + { + KB_ClearKeyDown( sc_F3 ); + + if(movesperpacket == 4 && connecthead != myconnectindex) + return; + + cmenu(300); + FX_StopAllSounds(); + clearsoundlocks(); + +// setview(0,0,xdim-1,ydim-1); + ps[myconnectindex].gm |= MODE_MENU; + if(ud.multimode < 2 && ud.recstat != 2) + { + ready2send = 0; + totalclock = ototalclock; + } + screenpeek = myconnectindex; + } + } + + if(KB_KeyPressed( sc_F4 ) && FXDevice != NumSoundCards ) + { + KB_ClearKeyDown( sc_F4 ); + FX_StopAllSounds(); + clearsoundlocks(); + + ps[myconnectindex].gm |= MODE_MENU; + if(ud.multimode < 2 && ud.recstat != 2) + { + ready2send = 0; + totalclock = ototalclock; + } + cmenu(700); + + } + + if( KB_KeyPressed( sc_F6 ) && (ps[myconnectindex].gm&MODE_GAME)) + { + KB_ClearKeyDown( sc_F6 ); + + if(movesperpacket == 4 && connecthead != myconnectindex) + return; + + if(lastsavedpos == -1) goto FAKE_F2; + + KB_FlushKeyboardQueue(); + + if(sprite[ps[myconnectindex].i].extra <= 0) + { + FTA(118,&ps[myconnectindex]); + return; + } + screencapt = 1; + displayrooms(myconnectindex,65536); + savetemp("duke3d.tmp",waloff[MAXTILES-1],160*100); + screencapt = 0; + if( lastsavedpos >= 0 ) + { + inputloc = strlen(&ud.savegame[lastsavedpos][0]); + current_menu = 360+lastsavedpos; + probey = lastsavedpos; + } + FX_StopAllSounds(); + clearsoundlocks(); + + setview(0,0,xdim-1,ydim-1); + ps[myconnectindex].gm |= MODE_MENU; + if(ud.multimode < 2 && ud.recstat != 2) + { + ready2send = 0; + totalclock = ototalclock; + } + } + + if(KB_KeyPressed( sc_F7 ) ) + { + KB_ClearKeyDown(sc_F7); + if( ps[myconnectindex].over_shoulder_on ) + ps[myconnectindex].over_shoulder_on = 0; + else + { + ps[myconnectindex].over_shoulder_on = 1; + cameradist = 0; + cameraclock = totalclock; + } + FTA(109+ps[myconnectindex].over_shoulder_on,&ps[myconnectindex]); + } + + if( KB_KeyPressed( sc_F5 ) && MusicDevice != NumSoundCards ) + { + KB_ClearKeyDown( sc_F5 ); + strcpy(&tempbuf[0],&music_fn[0][(int)music_select][0]); + strcat(&tempbuf[0],". USE SHIFT-F5 TO CHANGE."); + strcpy(&fta_quotes[26][0],&tempbuf[0]); + FTA(26,&ps[myconnectindex]); + + } + + if(KB_KeyPressed( sc_F8 )) + { + KB_ClearKeyDown( sc_F8 ); + ud.fta_on = !ud.fta_on; + if(ud.fta_on) FTA(23,&ps[myconnectindex]); + else + { + ud.fta_on = 1; + FTA(24,&ps[myconnectindex]); + ud.fta_on = 0; + } + } + + if(KB_KeyPressed( sc_F9 ) && (ps[myconnectindex].gm&MODE_GAME) ) + { + KB_ClearKeyDown( sc_F9 ); + + if(movesperpacket == 4 && myconnectindex != connecthead) + return; + + if( lastsavedpos >= 0 ) cmenu(15001); + else cmenu(25000); + FX_StopAllSounds(); + clearsoundlocks(); + ps[myconnectindex].gm |= MODE_MENU; + if(ud.multimode < 2 && ud.recstat != 2) + { + ready2send = 0; + totalclock = ototalclock; + } + } + + if(KB_KeyPressed( sc_F10 )) + { + KB_ClearKeyDown( sc_F10 ); + cmenu(500); + FX_StopAllSounds(); + clearsoundlocks(); + ps[myconnectindex].gm |= MODE_MENU; + if(ud.multimode < 2 && ud.recstat != 2) + { + ready2send = 0; + totalclock = ototalclock; + } + } + + + if( ud.overhead_on != 0) + { + + j = totalclock-nonsharedtimer; nonsharedtimer += j; + if ( BUTTON( gamefunc_Enlarge_Screen ) ) + ps[myconnectindex].zoom += mulscale6(j,max(ps[myconnectindex].zoom,256)); + if ( BUTTON( gamefunc_Shrink_Screen ) ) + ps[myconnectindex].zoom -= mulscale6(j,max(ps[myconnectindex].zoom,256)); + + if( (ps[myconnectindex].zoom > 2048) ) + ps[myconnectindex].zoom = 2048; + if( (ps[myconnectindex].zoom < 48) ) + ps[myconnectindex].zoom = 48; + + } + } + + if( KB_KeyPressed(sc_Escape) && ud.overhead_on && ps[myconnectindex].newowner == -1 ) + { + KB_ClearKeyDown( sc_Escape ); + ud.last_overhead = ud.overhead_on; + ud.overhead_on = 0; + ud.scrollmode = 0; + vscrn(); + } + + if( BUTTON(gamefunc_AutoRun) ) + { + CONTROL_ClearButton(gamefunc_AutoRun); + ud.auto_run = 1-ud.auto_run; + FTA(85+ud.auto_run,&ps[myconnectindex]); + } + + if( BUTTON(gamefunc_Map) ) + { + CONTROL_ClearButton( gamefunc_Map ); + if( ud.last_overhead != ud.overhead_on && ud.last_overhead) + { + ud.overhead_on = ud.last_overhead; + ud.last_overhead = 0; + } + else + { + ud.overhead_on++; + if(ud.overhead_on == 3 ) ud.overhead_on = 0; + ud.last_overhead = ud.overhead_on; + } + restorepalette = 1; + vscrn(); + } + + if(KB_KeyPressed( sc_F11 )) + { + KB_ClearKeyDown( sc_F11 ); + if(SHIFTS_IS_PRESSED) ud.brightness-=4; + else ud.brightness+=4; + + if (ud.brightness > (7<<2) ) + ud.brightness = 0; + else if(ud.brightness < 0) + ud.brightness = (7<<2); + + setbrightness(ud.brightness>>2,&ps[myconnectindex].palette[0]); + if(ud.brightness < 20) FTA( 29 + (ud.brightness>>2) ,&ps[myconnectindex]); + else if(ud.brightness < 40) FTA( 96 + (ud.brightness>>2) - 5,&ps[myconnectindex]); + } +} + + + +void comlinehelp(char **argv) +{ + printf("Command line help. %s [/flags...]\n",argv[0]); + puts(" ?, /? This help message"); + puts(" /l## Level (1-11)"); + puts(" /v# Volume (1-4)"); + puts(" /s# Skill (1-4)"); + puts(" /r Record demo"); + puts(" /dFILE Start to play demo FILE"); + puts(" /m No monsters"); + puts(" /ns No sound"); + puts(" /nm No music"); + puts(" /t# Respawn, 1 = Monsters, 2 = Items, 3 = Inventory, x = All"); + puts(" /c# MP mode, 1 = DukeMatch(spawn), 2 = Coop, 3 = Dukematch(no spawn)"); + puts(" /q# Fake multiplayer (2-8 players)"); + puts(" /a Use player AI (fake multiplayer only)"); + puts(" /i# Network mode (1/0) (multiplayer only) (default == 1)"); + puts(" /f# Send fewer packets (1, 2, 4) (multiplayer only)"); + puts(" /gFILE, /g... Use multiple group files (must be last on command line)"); + puts(" /xFILE Compile FILE (default GAME.CON)"); + puts(" /u######### User's favorite weapon order (default: 3425689071)"); + puts(" /# Load and run a game (slot 0-9)"); + puts(" /z Skip memory check"); + puts(" -map FILE Use a map FILE"); + puts(" -name NAME Foward NAME"); + puts(" -net Net mode game"); + printf("\n\n"); +} + +void checkcommandline(int argc,char **argv) +{ + short i, j; + char *c; + + i = 1; + + ud.fta_on = 1; + ud.god = 0; + ud.m_respawn_items = 0; + ud.m_respawn_monsters = 0; + ud.m_respawn_inventory = 0; + ud.warp_on = 0; + ud.cashman = 0; + ud.m_player_skill = ud.player_skill = 2; + +#ifdef BETA + return; +#endif + + if(argc > 1) + { + while(i < argc) + { + c = argv[i]; + + if (stricmp(c, "-net") == 0) + { + i += 2; // skip filename. + continue; + } + + if(*c == '-') + { + if( *(c+1) == '8' ) eightytwofifty = 1; + i++; + continue; + } + + if(*c == '?') + { + comlinehelp(argv); + exit(-1); + } + + if(*c == '/') + { + c++; + switch(*c) + { + default: + // printf("Unknown command line parameter '%s'\n",argv[i]); + case '?': + comlinehelp(argv); + exit(0); + case 'x': + case 'X': + c++; + if(*c) + { + strcpy(confilename,c); + if(SafeFileExists(c) == 0) + { + printf("Could not find con file '%s'.\n",confilename ); + exit(-1); + } + else printf("Using con file: '%s'\n",confilename); + } + break; + case 'g': + case 'G': + c++; + if(*c) + { + if( strchr(c,'.') == 0) + strcat(c,".grp"); + + j = initgroupfile(c); + if( j == -1 ) + printf("Could not find group file %s.\n",c); + else + { + groupfile = j; + printf("Using group file %s.\n",c); + } + } + + break; + case 'a': + case 'A': + ud.playerai = 1; + puts("Other player AI."); + break; + case 'n': + case 'N': + c++; + if(*c == 's' || *c == 'S') + { + CommandSoundToggleOff = 2; + puts("Sound off."); + } + else if(*c == 'm' || *c == 'M') + { + CommandMusicToggleOff = 1; + puts("Music off."); + } + else + { + comlinehelp(argv); + exit(-1); + } + break; + case 'i': + case 'I': + c++; + if(*c == '0') networkmode = 0; + if(*c == '1') networkmode = 1; + printf("Network Mode %d\n",networkmode); + break; + case 'c': + case 'C': + c++; + if(*c == '1' || *c == '2' || *c == '3' ) + ud.m_coop = *c - '0' - 1; + else ud.m_coop = 0; + + switch(ud.m_coop) + { + case 0: + puts("Dukematch (spawn)."); + break; + case 1: + puts("Cooperative play."); + break; + case 2: + puts("Dukematch (no spawn)."); + break; + } + + break; + case 'z': + case 'Z': + memorycheckoveride = 1; + break; + case 'f': + case 'F': + c++; + if(*c == '1') + movesperpacket = 1; + if(*c == '2') + movesperpacket = 2; + if(*c == '4') + { + movesperpacket = 4; + setpackettimeout(0x3fffffff,0x3fffffff); + } + break; + case 't': + case 'T': + c++; + if(*c == '1') ud.m_respawn_monsters = 1; + else if(*c == '2') ud.m_respawn_items = 1; + else if(*c == '3') ud.m_respawn_inventory = 1; + else + { + ud.m_respawn_monsters = 1; + ud.m_respawn_items = 1; + ud.m_respawn_inventory = 1; + } + puts("Respawn on."); + break; + case 'm': + case 'M': + if( *(c+1) != 'a' && *(c+1) != 'A' ) + { + ud.m_monsters_off = 1; + ud.m_player_skill = ud.player_skill = 0; + puts("Monsters off."); + } + break; + case 'w': + case 'W': + ud.coords = 1; + break; + case 'q': + case 'Q': + puts("Fake multiplayer mode."); + if( *(++c) == 0) ud.multimode = 1; + else ud.multimode = atol(c)%17; + ud.m_coop = ud.coop = 0; + ud.m_marker = ud.marker = 1; + ud.m_respawn_monsters = ud.respawn_monsters = 1; + ud.m_respawn_items = ud.respawn_items = 1; + ud.m_respawn_inventory = ud.respawn_inventory = 1; + + break; + case 'r': + case 'R': + ud.m_recstat = 1; + puts("Demo record mode on."); + break; + case 'd': + case 'D': + c++; + if( strchr(c,'.') == 0) + strcat(c,".dmo"); + printf("Play demo %s.\n",c); + strcpy(firstdemofile,c); + break; + case 'l': + case 'L': + ud.warp_on = 1; + c++; + ud.m_level_number = ud.level_number = (atol(c)-1)%11; + break; + case 'j': + case 'J': +#ifdef VOLUMEALL + #ifdef AUSTRALIA + printf("Duke Nukem 3D (AUSSIE FULL VERSION) v%s\n",VERSION); + #else + printf("Duke Nukem 3D (FULL VERSION) v%s\n",VERSION); + #endif +#else + #ifdef AUSTRALIA + printf("Duke Nukem 3D (AUSSIE SHAREWARE) v%s\n",VERSION); + #else + printf("Duke Nukem 3D (SHAREWARE) v%s\n",VERSION); + #endif +#endif + + exit(0); + + case 'v': + case 'V': + c++; + ud.warp_on = 1; + ud.m_volume_number = ud.volume_number = atol(c)-1; + break; + case 's': + case 'S': + c++; + ud.m_player_skill = ud.player_skill = (atol(c)%5); + if(ud.m_player_skill == 4) + ud.m_respawn_monsters = ud.respawn_monsters = 1; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + ud.warp_on = 2 + (*c) - '0'; + break; + case 'u': + case 'U': + c++; + j = 0; + if(*c) + { + puts("Using favorite weapon order(s)."); + while(*c) + { + ud.wchoice[0][j] = *c-'0'; + c++; + j++; + } + while(j < 10) + { + if(j == 9) + ud.wchoice[0][9] = 1; + else + ud.wchoice[0][j] = 2; + + j++; + } + } + else + { + puts("Using default weapon orders."); + ud.wchoice[0][0] = 3; + ud.wchoice[0][1] = 4; + ud.wchoice[0][2] = 5; + ud.wchoice[0][3] = 7; + ud.wchoice[0][4] = 8; + ud.wchoice[0][5] = 6; + ud.wchoice[0][6] = 0; + ud.wchoice[0][7] = 2; + ud.wchoice[0][8] = 9; + ud.wchoice[0][9] = 1; + } + + break; + } + } + i++; + } + } +} + + + +void printstr(short x, short y, char string[81], char attribute) +{ + char character; + short i, pos; + + pos = (y*80+x)<<1; + i = 0; + while (string[i] != 0) + { + character = string[i]; +// printchrasm(0xb8000+(long)pos,1L,((long)attribute<<8)+(long)character); + printchrasm(0xb8000+(long)pos,1L,(char)(((long)attribute<<8)+(long)character)); + i++; + pos+=2; + } +} + +/* +void cacheicon(void) +{ + if(cachecount > 0) + { + if( (ps[myconnectindex].gm&MODE_MENU) == 0 ) + rotatesprite((320-7)<<16,(200-23)<<16,32768L,0,SPINNINGNUKEICON,0,0,2,windowx1,windowy1,windowx2,windowy2); + cachecount = 0; + } +} + */ + +void Logo(void) +{ + short i,j,soundanm; + + soundanm = 0; + + ready2send = 0; + + KB_FlushKeyboardQueue(); + + setview(0,0,xdim-1,ydim-1); + clearview(0L); + palto(0,0,0,63); + + flushperms(); + nextpage(); + + MUSIC_StopSong(); + +#ifdef VOLUMEALL + + if(!KB_KeyWaiting() && nomorelogohack == 0) + { + getpackets(); + playanm("logo.anm",5); + palto(0,0,0,63); + KB_FlushKeyboardQueue(); + } + + clearview(0L); + nextpage(); +#endif + + playmusic(&env_music_fn[0][0]); + + for(i=0;i<64;i+=7) palto(0,0,0,i); + ps[myconnectindex].palette = drealms; + palto(0,0,0,63); + rotatesprite(0,0,65536L,0,DREALMS,0,0,2+8+16+64, 0,0,xdim-1,ydim-1); + nextpage(); for(i=63;i>0;i-=7) palto(0,0,0,i); + totalclock = 0; + while( totalclock < (120*7) && !KB_KeyWaiting() ) + getpackets(); + + for(i=0;i<64;i+=7) palto(0,0,0,i); + clearview(0L); + nextpage(); + + ps[myconnectindex].palette = titlepal; + flushperms(); + rotatesprite(0,0,65536L,0,BETASCREEN,0,0,2+8+16+64,0,0,xdim-1,ydim-1); + KB_FlushKeyboardQueue(); + nextpage(); + for(i=63;i>0;i-=7) palto(0,0,0,i); + totalclock = 0; + + while(totalclock < (860+120) && !KB_KeyWaiting()) + { + rotatesprite(0,0,65536L,0,BETASCREEN,0,0,2+8+16+64,0,0,xdim-1,ydim-1); + + if( totalclock > 120 && totalclock < (120+60) ) + { + if(soundanm == 0) + { + soundanm = 1; + sound(PIPEBOMB_EXPLODE); + } + rotatesprite(160<<16,104<<16,(totalclock-120)<<10,0,DUKENUKEM,0,0,2+8,0,0,xdim-1,ydim-1); + } + else if( totalclock >= (120+60) ) + rotatesprite(160<<16,(104)<<16,60<<10,0,DUKENUKEM,0,0,2+8,0,0,xdim-1,ydim-1); + + if( totalclock > 220 && totalclock < (220+30) ) + { + if( soundanm == 1) + { + soundanm = 2; + sound(PIPEBOMB_EXPLODE); + } + + rotatesprite(160<<16,(104)<<16,60<<10,0,DUKENUKEM,0,0,2+8,0,0,xdim-1,ydim-1); + rotatesprite(160<<16,(129)<<16,(totalclock - 220 )<<11,0,THREEDEE,0,0,2+8,0,0,xdim-1,ydim-1); + } + else if( totalclock >= (220+30) ) + rotatesprite(160<<16,(129)<<16,30<<11,0,THREEDEE,0,0,2+8,0,0,xdim-1,ydim-1); + + if( totalclock >= 280 && totalclock < 395 ) + { + rotatesprite(160<<16,(151)<<16,(410-totalclock)<<12,0,PLUTOPAKSPRITE+1,0,0,2+8,0,0,xdim-1,ydim-1); + if(soundanm == 2) + { + soundanm = 3; + sound(FLY_BY); + } + } + else if( totalclock >= 395 ) + { + if(soundanm == 3) + { + soundanm = 4; + sound(PIPEBOMB_EXPLODE); + } + rotatesprite(160<<16,(151)<<16,30<<11,0,PLUTOPAKSPRITE+1,0,0,2+8,0,0,xdim-1,ydim-1); + } + + getpackets(); + nextpage(); + } + + if(ud.multimode > 1) + { + rotatesprite(0,0,65536L,0,BETASCREEN,0,0,2+8+16+64,0,0,xdim-1,ydim-1); + + rotatesprite(160<<16,(104)<<16,60<<10,0,DUKENUKEM,0,0,2+8,0,0,xdim-1,ydim-1); + rotatesprite(160<<16,(129)<<16,30<<11,0,THREEDEE,0,0,2+8,0,0,xdim-1,ydim-1); + rotatesprite(160<<16,(151)<<16,30<<11,0,PLUTOPAKSPRITE+1,0,0,2+8,0,0,xdim-1,ydim-1); + + gametext(160,190,"WAITING FOR PLAYERS",14,2); + nextpage(); + } + + waitforeverybody(); + + flushperms(); + clearview(0L); + nextpage(); + + ps[myconnectindex].palette = palette; + sound(NITEVISION_ONOFF); + + palto(0,0,0,0); + clearview(0L); +} + +void loadtmb(void) +{ + char tmb[8000]; + long fil, l; + + fil = kopen4load("d3dtimbr.tmb",0); + if(fil == -1) return; + l = kfilelength(fil); + kread(fil,(char *)tmb,l); + MUSIC_RegisterTimbreBank(tmb); + kclose(fil); +} + +/* +=================== += += ShutDown += +=================== +*/ + +void ShutDown( void ) +{ + SoundShutdown(); + MusicShutdown(); + uninittimer(); + uninitengine(); + CONTROL_Shutdown(); + CONFIG_WriteSetup(); + KB_Shutdown(); +} + +static char todd[] = "Duke Nukem 3D(tm) Copyright 1989, 1996 Todd Replogle and 3D Realms Entertainment"; +static char trees[] = "I want to make a game with trees"; +static char sixteen[] = "16 Possible Dukes"; + +/* +=================== += += Startup += +=================== +*/ + +void compilecons(void) +{ + mymembuf = (char *)&hittype[0]; + labelcode = (long *)§or[0]; + label = (char *)&sprite[0]; + +// printf("%ld %ld %ld\n",sizeof(hittype),sizeof(sector),sizeof(sprite)); +// exit(0); + + loadefs(confilename,mymembuf); + if( loadfromgrouponly ) + { + printf(" * Writing defaults to current directory.\n"); + loadefs(confilename,mymembuf); + } +} + + +void Startup(void) +{ + int i; + + KB_Startup(); + + setup_homedir(); + + CONFIG_GetSetupFilename(); + CONFIG_ReadSetup(); +#ifdef DC + /* force change mode */ + ScreenWidth = 320; + ScreenHeight = 240; +#endif + + compilecons(); + +#ifdef AUSTRALIA + ud.lockout = 1; +#endif + + if(CommandSoundToggleOff) SoundToggle = 0; + if(CommandMusicToggleOff) MusicToggle = 0; + +#ifdef VOLUMEONE + + printf("\n*** You have run Duke Nukem 3D %ld times. ***\n\n",ud.executions); + if(ud.executions >= 50) puts("IT IS NOW TIME TO UPGRADE TO THE COMPLETE VERSION!!!\n"); + +#endif + + CONTROL_Startup( ControllerType, DUKE3D_GetTime, TICRATE ); + +// CTW - MODIFICATION +// initengine(ScreenMode,ScreenWidth,ScreenHeight); + initengine(); +// CTW END - MODIFICATION + inittimer(); + + puts("* Hold Esc to Abort. *"); + puts("Loading art header."); + loadpics("tiles000.art"); + + readsavenames(); + + tilesizx[MIRROR] = tilesizy[MIRROR] = 0; + + for(i=0;i 1) + puts("Multiplayer initialized."); + + ps[myconnectindex].palette = (char *) &palette[0]; + SetupGameButtons(); + + if(networkmode == 255) + networkmode = 1; + +#ifdef PLATFORM_DOS + puts("Checking music inits."); + MusicStartup(); + puts("Checking sound inits."); + SoundStartup(); +#else + /* SBF - wasn't sure if swapping them would harm anything. */ + puts("Checking sound inits."); + SoundStartup(); + puts("Checking music inits."); + MusicStartup(); +#endif + + loadtmb(); +} + + +void sendscore(char *s) +{ + if(numplayers > 1) + genericmultifunction(-1,s,strlen(s)+1,5); +} + + +void getnames(void) +{ + short i,l; + + for(l=0;myname[l];l++) + { + ud.user_name[myconnectindex][l] = toupper(myname[l]); + buf[l+2] = toupper(myname[l]); + } + + if(numplayers > 1) + { + buf[0] = 6; + buf[1] = BYTEVERSION; + + buf[l+2] = 0; + l += 3; + + for(i=connecthead;i>=0;i=connectpoint2[i]) + if( i != myconnectindex ) + sendpacket(i,&buf[0],l); + + // getpackets(); + + l = 1; + buf[0] = 9; + + for(i=0;i<10;i++) + { + ud.wchoice[myconnectindex][i] = ud.wchoice[0][i]; + buf[l] = (char) ud.wchoice[0][i]; + l++; + } + + for(i=connecthead;i>=0;i=connectpoint2[i]) + if(i != myconnectindex) + sendpacket(i,&buf[0],11); + +// getpackets(); + + buf[0] = 10; + buf[1] = ps[0].aim_mode; + ps[myconnectindex].aim_mode = ps[0].aim_mode; + + for(i=connecthead;i>=0;i=connectpoint2[i]) + if(i != myconnectindex) + sendpacket(i,buf,2); + +// getpackets(); + + if(cp == 0) + { + buf[0] = 125; + + for(i=connecthead;i>=0;i=connectpoint2[i]) + if(i != myconnectindex) + sendpacket(i,buf,1); + } + + getpackets(); + + waitforeverybody(); + } + + if(cp == 1) + gameexit("Please put Duke Nukem 3D Atomic Edition CD in drive."); +} + +void writestring(long a1,long a2,long a3,short a4,long vx,long vy,long vz) +{ + + FILE *fp; + + fp = (FILE *)fopen("debug.txt","rt+"); + + fprintf(fp,"%ld %ld %ld %d %ld %ld %ld\n",a1,a2,a3,a4,vx,vy,vz); + + fclose(fp); + +} + + +char testcd( char *fn ) +{ +#if PLATFORM_DOS + short drive_count, drive; + long dalen = 0; + struct find_t dafilet; + int fil; + + union _REGS ir; + union _REGS or; + struct _SREGS sr; + + if( IDFSIZE != 9961476 ) + { + drive = toupper(*fn)-'A'; + + ir.w.ax = 0x1500; + ir.w.bx = 0; /* check that MSCDEX is installed */ + int386(0x2f, &ir, &or); + drive_count = or.w.bx; + + if( drive_count == 0 ) + return 1; + + ir.w.ax = 0x150b; + ir.w.bx = 0; + ir.w.cx = drive; + int386(0x2f, &ir, &or); + + if (or.w.ax == 0 || or.w.bx != 0xadad) + return 1; + + ir.w.ax = 0x1502; + ir.w.bx = FP_OFF(buf); + sr.es = FP_SEG(buf); + ir.w.cx = drive; + int386x(0x2f, &ir, &or, &sr); + + if( or.h.al == 0 || or.h.al == 30) + return 1; + + } + + fil = open(fn,O_RDONLY,S_IREAD); + + if ( fil < 0 ) return 1; + + // ( DO A SEE/Byte check here.) (Not coded in this version) + + + dalen = filelength(fil); + + close(fil); + + return( dalen != IDFSIZE ); + +#else + STUBBED("CD detection."); + return 0; +#endif +} + + +void copyprotect(void) +{ + FILE *fp; + char idfile[256]; + + return; + + cp = 0; + + fp = (FILE *)fopen("cdrom.ini","rt"); + if(fp == (FILE *) NULL) + { + cp = 1; + return; + } + + fscanf(fp,"%s",idfile); + fclose(fp); + + strcat(idfile,IDFILENAME); + + if( testcd(idfile) ) + { + cp = 1; + return; + } +} + + +static int load_duke3d_groupfile(void) +{ + char groupfile[] = "duke3d.grp"; + FixFilePath(groupfile); + return(initgroupfile(groupfile) != -1); +} + + +int main(int argc,char **argv) +{ + long i, j, k, l; + int32 tempautorun; + +#ifdef DC + platform_init(&argc,&argv); +#endif + + copyprotect(); + + setvmode(0x03); + +// This is needed for the icculus.org ported Build Engine. +#if !PLATFORM_DOS + _platform_init(argc, argv, "Duke Nukem 3D", "Duke3D"); +#endif + + setmmxoverlay(getenv("BUILD_NOPENTIUM") == NULL); + + todd[0] = 'T'; + sixteen[0] = 'D'; + trees[0] = 'I'; + +#if PLATFORM_DOS + printstr(0,0," ",79); +#else + printf(" "); +#endif + +#ifdef VOLUMEALL + #ifdef AUSTRALIA + printstr(40-(strlen(HEAD2A)>>1),0,HEAD2A,79); + #else + printstr(40-(strlen(HEAD2)>>1),0,HEAD2,79); + #endif +#else + #ifdef AUSTRALIA + printstr(40-(strlen(HEADA)>>1),0,HEADA,79); + #else + printstr(40-(strlen(HEAD)>>1),0,HEAD,79); + #endif +#endif + +#if !PLATFORM_DOS + printf("\n"); +#endif + +#ifdef BETA + printstr(0,1,"BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION BETA VERSION ",79); +#endif + +#ifdef ONELEVELDEMO + printstr(33,1,"ONE LEVEL DEMO",79); +#endif + + ud.multimode = 1; + printstr(0,1," Copyright (c) 1996 3D Realms Entertainment ",79); + +// printstr(0,2," *** DUKE NUKEM v1.4 BETA VERSION. USED FOR INTERNAL USE ONLY!!! *** ",79); + + printf("\n\n"); + + if (!load_duke3d_groupfile()) + { + printf("ERROR: Could not initialize group file \"duke3d.grp\"\n"); + exit(EXIT_FAILURE); + } + + checkcommandline(argc,argv); + + totalmemory = Z_AvailHeap(); + + if(memorycheckoveride == 0) + { + if(totalmemory < (3162000-350000)) + { + puts("You don't have enough free memory to run Duke Nukem 3D."); + puts("The DOS \"mem\" command should report 6,800K (or 6.8 megs)"); + puts("of \"total memory free\".\n"); + printf("Duke Nukem 3D requires %ld more bytes to run.\n",3162000-350000-totalmemory); + exit(0); + } + } + else + printf("Using %ld bytes for heap.\n",totalmemory); + +#ifndef ONELEVELDEMO +// CTW - REMOVED +/* if(movesperpacket == 4) + TENtext();*/ +// CTW END - REMOVED +#endif + + RegisterShutdownFunction( ShutDown ); + +#ifdef VOLUMEONE + puts("Distribution of shareware Duke Nukem 3D is restricted in certain ways."); + puts("Please read LICENSE.DOC for more details.\n"); +#endif +#ifdef ONELEVELDEMO + puts("DUKE NUKEM 3D SINGLE-LEVEL PROMOTIONAL EDITION\n"); + puts("This single-level promotional edition of Duke Nukem 3D (tm) may not be"); + puts("distributed domestically (North America) by any publication other than"); + puts("Computer Gaming World, a Ziff-Davis publication. It is a promotional"); + puts("version, licensed for a single month's run, and may not be redistributed"); + puts("by any online service, BBS, commercial publisher, magazine or distributor."); + puts("International distribution rights are reserved.\n"); + puts("Please read LICENSE.DOC for further information about this special version."); + puts("NOTE: DUKE NUKEM 3D CONTAINS MATURE CONTENT.\n"); + puts("Press any key to continue."); + getchar(); +#endif + + Startup(); + + if( eightytwofifty && numplayers > 1 && (MusicDevice != NumSoundCards) ) + { + puts("\n========================================================================="); + puts("WARNING: 8250 UART detected."); + puts("Music is being disabled and lower quality sound is being set. We apologize"); + puts("for this, but it is necessary to maintain high frame rates while trying to"); + puts("play the game on an 8250. We suggest upgrading to a 16550 or better UART"); + puts("for maximum performance. Press any key to continue."); + puts("=========================================================================\n"); + + while( !KB_KeyWaiting() ) getpackets(); + } + + if(numplayers > 1) + { + ud.multimode = numplayers; + sendlogon(); + } + else if(boardfilename[0] != 0) + { + ud.m_level_number = 7; + ud.m_volume_number = 0; + ud.warp_on = 1; + } + + getnames(); + + if(ud.multimode > 1) + { + playerswhenstarted = ud.multimode; + + if(ud.warp_on == 0) + { + ud.m_monsters_off = 1; + ud.m_player_skill = 0; + } + } + + ud.last_level = -1; + + RTS_Init(ud.rtsname); + if(numlumps) printf("Using .RTS file:%s\n",ud.rtsname); + + if (CONTROL_JoystickEnabled) + CONTROL_CenterJoystick + ( + CenterCenter, + UpperLeft, + LowerRight, + CenterThrottle, + CenterRudder + ); + + puts("Loading palette/lookups."); + +// CTW - MODIFICATION +/* if( setgamemode(ScreenMode,ScreenWidth,ScreenHeight) < 0 ) + { + printf("\nVESA driver for ( %i * %i ) not found/supported!\n",xdim,ydim); + vidoption = 2; + setgamemode(vidoption,320,200); + }*/ + if( setgamemode(ScreenMode,ScreenWidth,ScreenHeight) < 0 ) + { + printf("\nVESA driver for ( %ld * %ld ) not found/supported!\n",xdim,ydim); + ScreenMode = 2; + ScreenWidth = 320; + ScreenHeight = 200; + setgamemode(ScreenMode,ScreenWidth,ScreenHeight); + } +// CTW END - MODIFICATION + + genspriteremaps(); + +#ifdef VOLUMEONE + if(numplayers > 4 || ud.multimode > 4) + gameexit(" The full version of Duke Nukem 3D supports 5 or more players."); +#endif + + setbrightness(ud.brightness>>2,&ps[myconnectindex].palette[0]); + + ESCESCAPE; + + FX_StopAllSounds(); + clearsoundlocks(); + + if(ud.warp_on > 1 && ud.multimode < 2) + { + clearview(0L); + ps[myconnectindex].palette = palette; + palto(0,0,0,0); + rotatesprite(320<<15,200<<15,65536L,0,LOADSCREEN,0,0,2+8+64,0,0,xdim-1,ydim-1); + menutext(160,105,0,0,"LOADING SAVED GAME..."); + nextpage(); + + j = loadplayer(ud.warp_on-2); + if(j) + ud.warp_on = 0; + } + +// getpackets(); + + MAIN_LOOP_RESTART: + + if(ud.warp_on == 0) + Logo(); + else if(ud.warp_on == 1) + { + newgame(ud.m_volume_number,ud.m_level_number,ud.m_player_skill); + enterlevel(MODE_GAME); + } + else vscrn(); + + tempautorun = ud.auto_run; + + if( ud.warp_on == 0 && playback() ) + { + FX_StopAllSounds(); + clearsoundlocks(); + nomorelogohack = 1; + goto MAIN_LOOP_RESTART; + } + + ud.auto_run = tempautorun; + + ud.warp_on = 0; + + while ( !(ps[myconnectindex].gm&MODE_END) ) //The whole loop!!!!!!!!!!!!!!!!!! + { + if( ud.recstat == 2 || ud.multimode > 1 || ( ud.show_help == 0 && (ps[myconnectindex].gm&MODE_MENU) != MODE_MENU ) ) + if( ps[myconnectindex].gm&MODE_GAME ) + if( moveloop() ) continue; + + if( ps[myconnectindex].gm&MODE_EOL || ps[myconnectindex].gm&MODE_RESTART ) + { + if( ps[myconnectindex].gm&MODE_EOL ) + { +#ifdef ONELEVELDEMO + gameexit(" "); +#endif + closedemowrite(); + + ready2send = 0; + + i = ud.screen_size; + ud.screen_size = 0; + vscrn(); + ud.screen_size = i; + dobonus(0); + + if(ud.eog) + { + ud.eog = 0; + if(ud.multimode < 2) + { +#ifndef VOLUMEALL + doorders(); +#endif + ps[myconnectindex].gm = MODE_MENU; + cmenu(0); + probey = 0; + goto MAIN_LOOP_RESTART; + } + else + { + ud.m_level_number = 0; + ud.level_number = 0; + } + } + } + + ready2send = 0; + if(numplayers > 1) ps[myconnectindex].gm = MODE_GAME; + enterlevel(ps[myconnectindex].gm); + continue; + } + + cheats(); + nonsharedkeys(); + + if( (ud.show_help == 0 && ud.multimode < 2 && !(ps[myconnectindex].gm&MODE_MENU) ) || ud.multimode > 1 || ud.recstat == 2) + i = min(max((totalclock-ototalclock)*(65536L/TICSPERFRAME),0),65536); + else + i = 65536; + + displayrooms(screenpeek,i); + displayrest(i); + +// if( KB_KeyPressed(sc_F) ) +// { +// KB_ClearKeyDown(sc_F); +// addplayer(); +// } + + if(ps[myconnectindex].gm&MODE_DEMO) + goto MAIN_LOOP_RESTART; + + if(debug_on) caches(); + + checksync(); + +#ifdef VOLUMEONE + if(ud.show_help == 0 && show_shareware > 0 && (ps[myconnectindex].gm&MODE_MENU) == 0 ) + rotatesprite((320-50)<<16,9<<16,65536L,0,BETAVERSION,0,0,2+8+16+128,0,0,xdim-1,ydim-1); +#endif + nextpage(); + } + + gameexit(" "); + return(0); +} + +char opendemoread(char which_demo) // 0 = mine +{ + char d[] = "demo_.dmo"; + char *fname = d; + char ver; + short i; + + if(which_demo == 10) + d[4] = 'x'; + else + d[4] = '0' + which_demo; + + ud.reccnt = 0; + + if(which_demo == 1 && firstdemofile[0] != 0) + { + fname = firstdemofile; + if ((recfilep = kopen4load(firstdemofile,loadfromgrouponly)) == -1) return(0); + } + else + if ((recfilep = kopen4load(d,loadfromgrouponly)) == -1) return(0); + + kread32(recfilep,&ud.reccnt); + kread8(recfilep,&ver); + if( (ver != BYTEVERSION) ) // || (ud.reccnt < 512) ) + { + printf("%s is a version %d demo, but we want version %d.\n", + fname, (int) ver, (int) BYTEVERSION); + kclose(recfilep); + return 0; + } + + // Ugh...these are all int32 vars read as 8 and 16 bits...yuck. --ryan. + ud.volume_number = 0; + kread8(recfilep,(char *)&ud.volume_number); + ud.volume_number = BUILDSWAP_INTEL32(ud.volume_number); + + ud.level_number = 0; + kread8(recfilep,(char *)&ud.level_number); + ud.level_number = BUILDSWAP_INTEL32(ud.level_number); + + ud.player_skill = 0; + kread8(recfilep,(char *)&ud.player_skill); + ud.player_skill = BUILDSWAP_INTEL32(ud.player_skill); + + ud.m_coop = 0; + kread8(recfilep,(char *)&ud.m_coop); + ud.m_coop = BUILDSWAP_INTEL32(ud.m_coop); + + ud.m_ffire = 0; + kread8(recfilep,(char *)&ud.m_ffire); + ud.m_ffire = BUILDSWAP_INTEL32(ud.m_ffire); + + ud.multimode = 0; + kread(recfilep,(short *)&ud.multimode,2); + ud.multimode = BUILDSWAP_INTEL32(ud.multimode); + + ud.m_monsters_off = 0; + kread(recfilep,(short *)&ud.m_monsters_off,2); + ud.m_monsters_off = BUILDSWAP_INTEL32(ud.m_monsters_off); + + kread32(recfilep,(int32 *)&ud.m_respawn_monsters); + kread32(recfilep,(int32 *)&ud.m_respawn_items); + kread32(recfilep,(int32 *)&ud.m_respawn_inventory); + kread32(recfilep,(int32 *)&ud.playerai); + kread(recfilep,(char *)&ud.user_name[0][0],sizeof(ud.user_name)); + kread32(recfilep,(int32 *)&ud.auto_run); + kread(recfilep,(char *)boardfilename,sizeof(boardfilename)); + if( boardfilename[0] != 0 ) + { + ud.m_level_number = 7; + ud.m_volume_number = 0; + } + + for(i=0;i=0;i=connectpoint2[i]) + { + copybufbyte(&sync[i],&recsync[ud.reccnt],sizeof(input)); + ud.reccnt++; + totalreccnt++; + if (ud.reccnt >= RECSYNCBUFSIZ) + { + #if PLATFORM_BIGENDIAN + input *inptr = recsync; + int i; + for (i = 0; i < ud.reccnt; i++) + { + inptr->fvel = BUILDSWAP_INTEL16(inptr->fvel); + inptr->svel = BUILDSWAP_INTEL16(inptr->svel); + inptr->bits = BUILDSWAP_INTEL32(inptr->bits); + inptr++; + } + #endif + dfwrite(recsync,sizeof(input)*ud.multimode,ud.reccnt/ud.multimode,frecfilep); + ud.reccnt = 0; + } + } +} + +void closedemowrite(void) +{ + long val32; + + if (ud.recstat == 1) + { + if (ud.reccnt > 0) + { + #if PLATFORM_BIGENDIAN + input *inptr = recsync; + int i; + for (i = 0; i < ud.reccnt; i++) + { + inptr->fvel = BUILDSWAP_INTEL16(inptr->fvel); + inptr->svel = BUILDSWAP_INTEL16(inptr->svel); + inptr->bits = BUILDSWAP_INTEL32(inptr->bits); + inptr++; + } + #endif + dfwrite(recsync,sizeof(input)*ud.multimode,ud.reccnt/ud.multimode,frecfilep); + + fseek(frecfilep,SEEK_SET,0L); + val32 = BUILDSWAP_INTEL32(totalreccnt); + fwrite(&val32,sizeof(long),1,frecfilep); + ud.recstat = ud.m_recstat = 0; + } + fclose(frecfilep); + frecfilep = NULL; + } +} + +// CTW - MODIFICATION +// On my XP machine, demo playback causes the game to crash shortly in. +// Only bug found so far, not sure if it's OS dependent or compiler or what. +// Seems to happen when player input starts being simulated, but just guessing. +// This change effectively disables it. The related code is still enabled. +// (This is working on Linux, so I flipped it back to '1'. --ryan.) + char which_demo = 1; +// CTW END - MODIFICATION + +char in_menu = 0; + +// extern long syncs[]; +long playback(void) +{ + long i,j,k,l,t; + short p; + char foundemo; + + if( ready2send ) return 0; + + foundemo = 0; + + RECHECK: + + in_menu = ps[myconnectindex].gm&MODE_MENU; + + pub = NUMPAGES; + pus = NUMPAGES; + + flushperms(); + + if(numplayers < 2) foundemo = opendemoread(which_demo); + + if(foundemo == 0) + { + if(which_demo > 1) + { + which_demo = 1; + goto RECHECK; + } + for(t=0;t<63;t+=7) palto(0,0,0,t); + drawbackground(); + menus(); + ps[myconnectindex].palette = palette; + nextpage(); + for(t=63;t>0;t-=7) palto(0,0,0,t); + ud.reccnt = 0; + } + else + { + ud.recstat = 2; + which_demo++; + if(which_demo == 10) which_demo = 1; + enterlevel(MODE_DEMO); + } + + if(foundemo == 0 || in_menu || KB_KeyWaiting() || numplayers > 1) + { + FX_StopAllSounds(); + clearsoundlocks(); + ps[myconnectindex].gm |= MODE_MENU; + } + + ready2send = 0; + i = 0; + + KB_FlushKeyboardQueue(); + + k = 0; + + while (ud.reccnt > 0 || foundemo == 0) + { + if(foundemo) while ( totalclock >= (lockclock+TICSPERFRAME) ) + { + if ((i == 0) || (i >= RECSYNCBUFSIZ)) + { + long cnt; + l = min(ud.reccnt,RECSYNCBUFSIZ); + cnt = l/ud.multimode; + kdfread(recsync,sizeof(input)*ud.multimode,cnt,recfilep); + #if PLATFORM_BIGENDIAN + { + input *inptr = (input *) recsync; + cnt *= ud.multimode; + for (i = 0; i < cnt; i++) + { + inptr->fvel = BUILDSWAP_INTEL16(inptr->fvel); + inptr->svel = BUILDSWAP_INTEL16(inptr->svel); + inptr->bits = BUILDSWAP_INTEL32(inptr->bits); + inptr++; + } + } + #endif + i = 0; + } + + for(j=connecthead;j>=0;j=connectpoint2[j]) + { + copybufbyte(&recsync[i],&inputfifo[movefifoend[j]&(MOVEFIFOSIZ-1)][j],sizeof(input)); + movefifoend[j]++; + i++; + ud.reccnt--; + } + domovethings(); + } + + if(foundemo == 0) + drawbackground(); + else + { + nonsharedkeys(); + + j = min(max((totalclock-lockclock)*(65536/TICSPERFRAME),0),65536); + displayrooms(screenpeek,j); + displayrest(j); + + if(ud.multimode > 1 && ps[myconnectindex].gm ) + getpackets(); + } + + if( (ps[myconnectindex].gm&MODE_MENU) && (ps[myconnectindex].gm&MODE_EOL) ) + goto RECHECK; + + extern int ignore_escape; // Hacky McHack. --ryan. + if ((KB_KeyPressed(sc_Escape)) && (!ignore_escape)) + { + KB_ClearKeyDown(sc_Escape); + FX_StopAllSounds(); + clearsoundlocks(); + ps[myconnectindex].gm |= MODE_MENU; + cmenu(0); + intomenusounds(); + } + + if(ps[myconnectindex].gm&MODE_TYPE) + { + typemode(); + if((ps[myconnectindex].gm&MODE_TYPE) != MODE_TYPE) + ps[myconnectindex].gm = MODE_MENU; + } + else + { + menus(); + if( ud.multimode > 1 ) + { + ControlInfo noshareinfo; + CONTROL_GetInput( &noshareinfo ); + if( BUTTON(gamefunc_SendMessage) ) + { + KB_FlushKeyboardQueue(); + CONTROL_ClearButton( gamefunc_SendMessage ); + ps[myconnectindex].gm = MODE_TYPE; + typebuf[0] = 0; + inputloc = 0; + } + } + } + + operatefta(); + + if(ud.last_camsprite != ud.camerasprite) + { + ud.last_camsprite = ud.camerasprite; + ud.camera_time = totalclock+(TICRATE*2); + } + +#ifdef VOLUMEONE + if( ud.show_help == 0 && (ps[myconnectindex].gm&MODE_MENU) == 0 ) + rotatesprite((320-50)<<16,9<<16,65536L,0,BETAVERSION,0,0,2+8+16+128,0,0,xdim-1,ydim-1); +#endif + getpackets(); + nextpage(); + + if( ps[myconnectindex].gm==MODE_END || ps[myconnectindex].gm==MODE_GAME ) + { + if(foundemo) + kclose(recfilep); + return 0; + } + } + kclose(recfilep); + if(ps[myconnectindex].gm&MODE_MENU) goto RECHECK; + return 1; +} + +char moveloop() +{ + long i; + + if (numplayers > 1) + while (fakemovefifoplc < movefifoend[myconnectindex]) fakedomovethings(); + + getpackets(); + + if (numplayers < 2) bufferjitter = 0; + while (movefifoend[myconnectindex]-movefifoplc > bufferjitter) + { + for(i=connecthead;i>=0;i=connectpoint2[i]) + if (movefifoplc == movefifoend[i]) break; + if (i >= 0) break; + if( domovethings() ) return 1; + } + return 0; +} + +void fakedomovethingscorrect(void) +{ + long i; + struct player_struct *p; + + if (numplayers < 2) return; + + i = ((movefifoplc-1)&(MOVEFIFOSIZ-1)); + p = &ps[myconnectindex]; + + if (p->posx == myxbak[i] && p->posy == myybak[i] && p->posz == myzbak[i] + && p->horiz == myhorizbak[i] && p->ang == myangbak[i]) return; + + myx = p->posx; omyx = p->oposx; myxvel = p->posxv; + myy = p->posy; omyy = p->oposy; myyvel = p->posyv; + myz = p->posz; omyz = p->oposz; myzvel = p->poszv; + myang = p->ang; omyang = p->oang; + mycursectnum = p->cursectnum; + myhoriz = p->horiz; omyhoriz = p->ohoriz; + myhorizoff = p->horizoff; omyhorizoff = p->ohorizoff; + myjumpingcounter = p->jumping_counter; + myjumpingtoggle = p->jumping_toggle; + myonground = p->on_ground; + myhardlanding = p->hard_landing; + myreturntocenter = p->return_to_center; + + fakemovefifoplc = movefifoplc; + while (fakemovefifoplc < movefifoend[myconnectindex]) + fakedomovethings(); + +} + +void fakedomovethings(void) +{ + input *syn; + struct player_struct *p; + long i, j, k, doubvel, fz, cz, hz, lz, x, y; + unsigned long sb_snum; + short psect, psectlotag, tempsect, backcstat; + char shrunk, spritebridge; + + syn = (input *)&inputfifo[fakemovefifoplc&(MOVEFIFOSIZ-1)][myconnectindex]; + + p = &ps[myconnectindex]; + + backcstat = sprite[p->i].cstat; + sprite[p->i].cstat &= ~257; + + sb_snum = syn->bits; + + psect = mycursectnum; + psectlotag = sector[psect].lotag; + spritebridge = 0; + + shrunk = (sprite[p->i].yrepeat < 32); + + if( ud.clipping == 0 && ( sector[psect].floorpicnum == MIRROR || psect < 0 || psect >= MAXSECTORS) ) + { + myx = omyx; + myy = omyy; + } + else + { + omyx = myx; + omyy = myy; + } + + omyhoriz = myhoriz; + omyhorizoff = myhorizoff; + omyz = myz; + omyang = myang; + + getzrange(myx,myy,myz,psect,&cz,&hz,&fz,&lz,163L,CLIPMASK0); + + j = getflorzofslope(psect,myx,myy); + + if( (lz&49152) == 16384 && psectlotag == 1 && klabs(myz-j) > PHEIGHT+(16<<8) ) + psectlotag = 0; + + if( p->aim_mode == 0 && myonground && psectlotag != 2 && (sector[psect].floorstat&2) ) + { + x = myx+(sintable[(myang+512)&2047]>>5); + y = myy+(sintable[myang&2047]>>5); + tempsect = psect; + updatesector(x,y,&tempsect); + if (tempsect >= 0) + { + k = getflorzofslope(psect,x,y); + if (psect == tempsect) + myhorizoff += mulscale16(j-k,160); + else if (klabs(getflorzofslope(tempsect,x,y)-k) <= (4<<8)) + myhorizoff += mulscale16(j-k,160); + } + } + if (myhorizoff > 0) myhorizoff -= ((myhorizoff>>3)+1); + else if (myhorizoff < 0) myhorizoff += (((-myhorizoff)>>3)+1); + + if(hz >= 0 && (hz&49152) == 49152) + { + hz &= (MAXSPRITES-1); + if (sprite[hz].statnum == 1 && sprite[hz].extra >= 0) + { + hz = 0; + cz = getceilzofslope(psect,myx,myy); + } + } + + if(lz >= 0 && (lz&49152) == 49152) + { + j = lz&(MAXSPRITES-1); + if ((sprite[j].cstat&33) == 33) + { + psectlotag = 0; + spritebridge = 1; + } + if(badguy(&sprite[j]) && sprite[j].xrepeat > 24 && klabs(sprite[p->i].z-sprite[j].z) < (84<<8) ) + { + j = getangle( sprite[j].x-myx,sprite[j].y-myy); + myxvel -= sintable[(j+512)&2047]<<4; + myyvel -= sintable[j&2047]<<4; + } + } + + if( sprite[p->i].extra <= 0 ) + { + if( psectlotag == 2 ) + { + if(p->on_warping_sector == 0) + { + if( klabs(myz-fz) > (PHEIGHT>>1)) + myz += 348; + } + clipmove(&myx,&myy,&myz,&mycursectnum,0,0,164L,(4L<<8),(4L<<8),CLIPMASK0); + } + + updatesector(myx,myy,&mycursectnum); + pushmove(&myx,&myy,&myz,&mycursectnum,128L,(4L<<8),(20L<<8),CLIPMASK0); + + myhoriz = 100; + myhorizoff = 0; + + goto ENDFAKEPROCESSINPUT; + } + + doubvel = TICSPERFRAME; + + if(p->on_crane >= 0) goto FAKEHORIZONLY; + + if(p->one_eighty_count < 0) myang += 128; + + i = 40; + + if( psectlotag == 2) + { + myjumpingcounter = 0; + + if ( sb_snum&1 ) + { + if(myzvel > 0) myzvel = 0; + myzvel -= 348; + if(myzvel < -(256*6)) myzvel = -(256*6); + } + else if (sb_snum&(1<<1)) + { + if(myzvel < 0) myzvel = 0; + myzvel += 348; + if(myzvel > (256*6)) myzvel = (256*6); + } + else + { + if(myzvel < 0) + { + myzvel += 256; + if(myzvel > 0) + myzvel = 0; + } + if(myzvel > 0) + { + myzvel -= 256; + if(myzvel < 0) + myzvel = 0; + } + } + + if(myzvel > 2048) myzvel >>= 1; + + myz += myzvel; + + if(myz > (fz-(15<<8)) ) + myz += ((fz-(15<<8))-myz)>>1; + + if(myz < (cz+(4<<8)) ) + { + myz = cz+(4<<8); + myzvel = 0; + } + } + + else if(p->jetpack_on) + { + myonground = 0; + myjumpingcounter = 0; + myhardlanding = 0; + + if(p->jetpack_on < 11) + myz -= (p->jetpack_on<<7); //Goin up + + if(shrunk) j = 512; + else j = 2048; + + if (sb_snum&1) //A + myz -= j; + if (sb_snum&(1<<1)) //Z + myz += j; + + if(shrunk == 0 && ( psectlotag == 0 || psectlotag == 2 ) ) k = 32; + else k = 16; + + if(myz > (fz-(k<<8)) ) + myz += ((fz-(k<<8))-myz)>>1; + if(myz < (cz+(18<<8)) ) + myz = cz+(18<<8); + } + else if( psectlotag != 2 ) + { + if (psectlotag == 1 && p->spritebridge == 0) + { + if(shrunk == 0) i = 34; + else i = 12; + } + if(myz < (fz-(i<<8)) && (floorspace(psect)|ceilingspace(psect)) == 0 ) //falling + { + if( (sb_snum&3) == 0 && myonground && (sector[psect].floorstat&2) && myz >= (fz-(i<<8)-(16<<8) ) ) + myz = fz-(i<<8); + else + { + myonground = 0; + + myzvel += (gc+80); + + if(myzvel >= (4096+2048)) myzvel = (4096+2048); + } + } + + else + { + if(psectlotag != 1 && psectlotag != 2 && myonground == 0 && myzvel > (6144>>1)) + myhardlanding = myzvel>>10; + myonground = 1; + + if(i==40) + { + //Smooth on the ground + + k = ((fz-(i<<8))-myz)>>1; + if( klabs(k) < 256 ) k = 0; + myz += k; // ((fz-(i<<8))-myz)>>1; + myzvel -= 768; // 412; + if(myzvel < 0) myzvel = 0; + } + else if(myjumpingcounter == 0) + { + myz += ((fz-(i<<7))-myz)>>1; //Smooth on the water + if(p->on_warping_sector == 0 && myz > fz-(16<<8)) + { + myz = fz-(16<<8); + myzvel >>= 1; + } + } + + if( sb_snum&2 ) + myz += (2048+768); + + if( (sb_snum&1) == 0 && myjumpingtoggle == 1) + myjumpingtoggle = 0; + + else if( (sb_snum&1) && myjumpingtoggle == 0 ) + { + if( myjumpingcounter == 0 ) + if( (fz-cz) > (56<<8) ) + { + myjumpingcounter = 1; + myjumpingtoggle = 1; + } + } + if( myjumpingcounter && (sb_snum&1) == 0 ) + myjumpingcounter = 0; + } + + if(myjumpingcounter) + { + if( (sb_snum&1) == 0 && myjumpingtoggle == 1) + myjumpingtoggle = 0; + + if( myjumpingcounter < (1024+256) ) + { + if(psectlotag == 1 && myjumpingcounter > 768) + { + myjumpingcounter = 0; + myzvel = -512; + } + else + { + myzvel -= (sintable[(2048-128+myjumpingcounter)&2047])/12; + myjumpingcounter += 180; + + myonground = 0; + } + } + else + { + myjumpingcounter = 0; + myzvel = 0; + } + } + + myz += myzvel; + + if(myz < (cz+(4<<8)) ) + { + myjumpingcounter = 0; + if(myzvel < 0) myxvel = myyvel = 0; + myzvel = 128; + myz = cz+(4<<8); + } + + } + + if ( p->fist_incs || + p->transporter_hold > 2 || + myhardlanding || + p->access_incs > 0 || + p->knee_incs > 0 || + (p->curr_weapon == TRIPBOMB_WEAPON && + p->kickback_pic > 1 && + p->kickback_pic < 4 ) ) + { + doubvel = 0; + myxvel = 0; + myyvel = 0; + } + else if ( syn->avel ) //p->ang += syncangvel * constant + { //ENGINE calculates angvel for you + long tempang; + + tempang = syn->avel<<1; + + if(psectlotag == 2) + myang += (tempang-(tempang>>3))*sgn(doubvel); + else myang += (tempang)*sgn(doubvel); + myang &= 2047; + } + + if ( myxvel || myyvel || syn->fvel || syn->svel ) + { + if(p->steroids_amount > 0 && p->steroids_amount < 400) + doubvel <<= 1; + + myxvel += ((syn->fvel*doubvel)<<6); + myyvel += ((syn->svel*doubvel)<<6); + + if( ( p->curr_weapon == KNEE_WEAPON && p->kickback_pic > 10 && myonground ) || ( myonground && (sb_snum&2) ) ) + { + myxvel = mulscale16(myxvel,dukefriction-0x2000); + myyvel = mulscale16(myyvel,dukefriction-0x2000); + } + else + { + if(psectlotag == 2) + { + myxvel = mulscale16(myxvel,dukefriction-0x1400); + myyvel = mulscale16(myyvel,dukefriction-0x1400); + } + else + { + myxvel = mulscale16(myxvel,dukefriction); + myyvel = mulscale16(myyvel,dukefriction); + } + } + + if( abs(myxvel) < 2048 && abs(myyvel) < 2048 ) + myxvel = myyvel = 0; + + if( shrunk ) + { + myxvel = + mulscale16(myxvel,(dukefriction)-(dukefriction>>1)+(dukefriction>>2)); + myyvel = + mulscale16(myyvel,(dukefriction)-(dukefriction>>1)+(dukefriction>>2)); + } + } + +FAKEHORIZONLY: + if(psectlotag == 1 || spritebridge == 1) i = (4L<<8); else i = (20L<<8); + + clipmove(&myx,&myy,&myz,&mycursectnum,myxvel,myyvel,164L,4L<<8,i,CLIPMASK0); + pushmove(&myx,&myy,&myz,&mycursectnum,164L,4L<<8,4L<<8,CLIPMASK0); + + if( p->jetpack_on == 0 && psectlotag != 1 && psectlotag != 2 && shrunk) + myz += 30<<8; + + if ((sb_snum&(1<<18)) || myhardlanding) + myreturntocenter = 9; + + if (sb_snum&(1<<13)) + { + myreturntocenter = 9; + if (sb_snum&(1<<5)) myhoriz += 6; + myhoriz += 6; + } + else if (sb_snum&(1<<14)) + { + myreturntocenter = 9; + if (sb_snum&(1<<5)) myhoriz -= 6; + myhoriz -= 6; + } + else if (sb_snum&(1<<3)) + { + if (sb_snum&(1<<5)) myhoriz += 6; + myhoriz += 6; + } + else if (sb_snum&(1<<4)) + { + if (sb_snum&(1<<5)) myhoriz -= 6; + myhoriz -= 6; + } + + if (myreturntocenter > 0) + if ((sb_snum&(1<<13)) == 0 && (sb_snum&(1<<14)) == 0) + { + myreturntocenter--; + myhoriz += 33-(myhoriz/3); + } + + if(p->aim_mode) + myhoriz += syn->horz>>1; + else + { + if( myhoriz > 95 && myhoriz < 105) myhoriz = 100; + if( myhorizoff > -5 && myhorizoff < 5) myhorizoff = 0; + } + + if (myhardlanding > 0) + { + myhardlanding--; + myhoriz -= (myhardlanding<<4); + } + + if (myhoriz > 299) myhoriz = 299; + else if (myhoriz < -99) myhoriz = -99; + + if(p->knee_incs > 0) + { + myhoriz -= 48; + myreturntocenter = 9; + } + + +ENDFAKEPROCESSINPUT: + + myxbak[fakemovefifoplc&(MOVEFIFOSIZ-1)] = myx; + myybak[fakemovefifoplc&(MOVEFIFOSIZ-1)] = myy; + myzbak[fakemovefifoplc&(MOVEFIFOSIZ-1)] = myz; + myangbak[fakemovefifoplc&(MOVEFIFOSIZ-1)] = myang; + myhorizbak[fakemovefifoplc&(MOVEFIFOSIZ-1)] = myhoriz; + fakemovefifoplc++; + + sprite[p->i].cstat = backcstat; +} + + +char domovethings(void) +{ + short i, j; + char ch; + + for(i=connecthead;i>=0;i=connectpoint2[i]) + if( sync[i].bits&(1<<17) ) + { + multiflag = 2; + multiwhat = (sync[i].bits>>18)&1; + multipos = (unsigned) (sync[i].bits>>19)&15; + multiwho = i; + + if( multiwhat ) + { + saveplayer( multipos ); + multiflag = 0; + + if(multiwho != myconnectindex) + { + strcpy(fta_quotes[122],&ud.user_name[multiwho][0]); + strcat(fta_quotes[122]," SAVED A MULTIPLAYER GAME"); + FTA(122,&ps[myconnectindex]); + } + else + { + strcpy(fta_quotes[122],"MULTIPLAYER GAME SAVED"); + FTA(122,&ps[myconnectindex]); + } + break; + } + else + { +// waitforeverybody(); + + j = loadplayer( multipos ); + + multiflag = 0; + + if(j == 0) + { + if(multiwho != myconnectindex) + { + strcpy(fta_quotes[122],&ud.user_name[multiwho][0]); + strcat(fta_quotes[122]," LOADED A MULTIPLAYER GAME"); + FTA(122,&ps[myconnectindex]); + } + else + { + strcpy(fta_quotes[122],"MULTIPLAYER GAME LOADED"); + FTA(122,&ps[myconnectindex]); + } + return 1; + } + } + } + + ud.camerasprite = -1; + lockclock += TICSPERFRAME; + + if(earthquaketime > 0) earthquaketime--; + if(rtsplaying > 0) rtsplaying--; + + for(i=0;i 0 ) + { + show_shareware--; + if(show_shareware == 0) + { + pus = NUMPAGES; + pub = NUMPAGES; + } + } + + everyothertime++; + + for(i=connecthead;i>=0;i=connectpoint2[i]) + copybufbyte(&inputfifo[movefifoplc&(MOVEFIFOSIZ-1)][i],&sync[i],sizeof(input)); + movefifoplc++; + + updateinterpolations(); + + j = -1; + for(i=connecthead;i>=0;i=connectpoint2[i]) + { + if ((sync[i].bits&(1<<26)) == 0) { j = i; continue; } + + closedemowrite(); + + if (i == myconnectindex) gameexit(" "); + if (screenpeek == i) + { + screenpeek = connectpoint2[i]; + if (screenpeek < 0) screenpeek = connecthead; + } + + if (i == connecthead) connecthead = connectpoint2[connecthead]; + else connectpoint2[j] = connectpoint2[i]; + + numplayers--; + ud.multimode--; + + if (numplayers < 2) + sound(GENERIC_AMBIENCE17); + + pub = NUMPAGES; + pus = NUMPAGES; + vscrn(); + + sprintf(buf,"%s is history!",ud.user_name[i]); + + quickkill(&ps[i]); + deletesprite(ps[i].i); + + adduserquote(buf); + + if(j < 0 && networkmode == 0 ) + gameexit( " \nThe 'MASTER/First player' just quit the game. All\nplayers are returned from the game. This only happens in 5-8\nplayer mode as a different network scheme is used."); + } + + if ((numplayers >= 2) && ((movefifoplc&7) == 7)) + { + ch = (char)(randomseed&255); + for(i=connecthead;i>=0;i=connectpoint2[i]) + ch += ((ps[i].posx+ps[i].posy+ps[i].posz+ps[i].ang+ps[i].horiz)&255); + syncval[myconnectindex][syncvalhead[myconnectindex]&(MOVEFIFOSIZ-1)] = ch; + syncvalhead[myconnectindex]++; + } + + if(ud.recstat == 1) record(); + + if( ud.pause_on == 0 ) + { + global_random = TRAND; + movedummyplayers();//ST 13 + } + + for(i=connecthead;i>=0;i=connectpoint2[i]) + { + cheatkeys(i); + + if( ud.pause_on == 0 ) + { + processinput(i); + checksectors(i); + } + } + + if( ud.pause_on == 0 ) + { + movefta();//ST 2 + moveweapons(); //ST 5 (must be last) + movetransports(); //ST 9 + + moveplayers(); //ST 10 + movefallers(); //ST 12 + moveexplosions(); //ST 4 + + moveactors(); //ST 1 + moveeffectors(); //ST 3 + + movestandables(); //ST 6 + doanimations(); + movefx(); //ST 11 + } + + fakedomovethingscorrect(); + + if( (everyothertime&1) == 0) + { + animatewalls(); + movecyclers(); + pan3dsound(); + } + + + return 0; +} + + +void doorders(void) +{ + short i; + + setview(0,0,xdim-1,ydim-1); + + for(i=0;i<63;i+=7) palto(0,0,0,i); + ps[myconnectindex].palette = palette; + totalclock = 0; + KB_FlushKeyboardQueue(); + rotatesprite(0,0,65536L,0,ORDERING,0,0,2+8+16+64, 0,0,xdim-1,ydim-1); + nextpage(); for(i=63;i>0;i-=7) palto(0,0,0,i); + totalclock = 0;while( !KB_KeyWaiting() ) getpackets(); + + for(i=0;i<63;i+=7) palto(0,0,0,i); + totalclock = 0; + KB_FlushKeyboardQueue(); + rotatesprite(0,0,65536L,0,ORDERING+1,0,0,2+8+16+64, 0,0,xdim-1,ydim-1); + nextpage(); for(i=63;i>0;i-=7) palto(0,0,0,i); + totalclock = 0;while( !KB_KeyWaiting() ) getpackets(); + + for(i=0;i<63;i+=7) palto(0,0,0,i); + totalclock = 0; + KB_FlushKeyboardQueue(); + rotatesprite(0,0,65536L,0,ORDERING+2,0,0,2+8+16+64, 0,0,xdim-1,ydim-1); + nextpage(); for(i=63;i>0;i-=7) palto(0,0,0,i); + totalclock = 0;while( !KB_KeyWaiting() ) getpackets(); + + for(i=0;i<63;i+=7) palto(0,0,0,i); + totalclock = 0; + KB_FlushKeyboardQueue(); + rotatesprite(0,0,65536L,0,ORDERING+3,0,0,2+8+16+64, 0,0,xdim-1,ydim-1); + nextpage(); for(i=63;i>0;i-=7) palto(0,0,0,i); + totalclock = 0;while( !KB_KeyWaiting() ) getpackets(); +} + +void dobonus(char bonusonly) +{ + short t, r, tinc,gfx_offset; + long i, y,xfragtotal,yfragtotal; + short bonuscnt; + + long breathe[] = + { + 0, 30,VICTORY1+1,176,59, + 30, 60,VICTORY1+2,176,59, + 60, 90,VICTORY1+1,176,59, + 90, 120,0 ,176,59 + }; + + long bossmove[] = + { + 0, 120,VICTORY1+3,86,59, + 220, 260,VICTORY1+4,86,59, + 260, 290,VICTORY1+5,86,59, + 290, 320,VICTORY1+6,86,59, + 320, 350,VICTORY1+7,86,59, + 350, 380,VICTORY1+8,86,59 + }; + + bonuscnt = 0; + + for(t=0;t<64;t+=7) palto(0,0,0,t); + setview(0,0,xdim-1,ydim-1); + clearview(0L); + nextpage(); + flushperms(); + + FX_StopAllSounds(); + clearsoundlocks(); + FX_SetReverb(0L); + + if(bonusonly) goto FRAGBONUS; + + if(numplayers < 2 && ud.eog && ud.from_bonus == 0) + switch(ud.volume_number) + { + case 0: + if(ud.lockout == 0) + { + clearview(0L); + rotatesprite(0,50<<16,65536L,0,VICTORY1,0,0,2+8+16+64+128,0,0,xdim-1,ydim-1); + nextpage(); + ps[myconnectindex].palette = endingpal; + for(t=63;t>=0;t--) palto(0,0,0,t); + + KB_FlushKeyboardQueue(); + totalclock = 0; tinc = 0; + while( 1 ) + { + clearview(0L); + rotatesprite(0,50<<16,65536L,0,VICTORY1,0,0,2+8+16+64+128,0,0,xdim-1,ydim-1); + + // boss + if( totalclock > 390 && totalclock < 780 ) + for(t=0;t<35;t+=5) if( bossmove[t+2] && (totalclock%390) > bossmove[t] && (totalclock%390) <= bossmove[t+1] ) + { + if(t==10 && bonuscnt == 1) { sound(SHOTGUN_FIRE);sound(SQUISHED); bonuscnt++; } + rotatesprite(bossmove[t+3]<<16,bossmove[t+4]<<16,65536L,0,bossmove[t+2],0,0,2+8+16+64+128,0,0,xdim-1,ydim-1); + } + + // Breathe + if( totalclock < 450 || totalclock >= 750 ) + { + if(totalclock >= 750) + { + rotatesprite(86<<16,59<<16,65536L,0,VICTORY1+8,0,0,2+8+16+64+128,0,0,xdim-1,ydim-1); + if(totalclock >= 750 && bonuscnt == 2) { sound(DUKETALKTOBOSS); bonuscnt++; } + } + for(t=0;t<20;t+=5) + if( breathe[t+2] && (totalclock%120) > breathe[t] && (totalclock%120) <= breathe[t+1] ) + { + if(t==5 && bonuscnt == 0) + { + sound(BOSSTALKTODUKE); + bonuscnt++; + } + rotatesprite(breathe[t+3]<<16,breathe[t+4]<<16,65536L,0,breathe[t+2],0,0,2+8+16+64+128,0,0,xdim-1,ydim-1); + } + } + + getpackets(); + nextpage(); + if( KB_KeyWaiting() ) break; + } + } + + for(t=0;t<64;t++) palto(0,0,0,t); + + KB_FlushKeyboardQueue(); + ps[myconnectindex].palette = palette; + + rotatesprite(0,0,65536L,0,3292,0,0,2+8+16+64, 0,0,xdim-1,ydim-1); + nextpage(); for(t=63;t>0;t--) palto(0,0,0,t); + while( !KB_KeyWaiting() ) getpackets(); + for(t=0;t<64;t++) palto(0,0,0,t); + MUSIC_StopSong(); + FX_StopAllSounds(); + clearsoundlocks(); + break; + case 1: + MUSIC_StopSong(); + clearview(0L); + nextpage(); + + if(ud.lockout == 0) + { + playanm("cineov2.anm",1); + KB_FlushKeyboardQueue(); + clearview(0L); + nextpage(); + } + + sound(PIPEBOMB_EXPLODE); + + for(t=0;t<64;t++) palto(0,0,0,t); + setview(0,0,xdim-1,ydim-1); + KB_FlushKeyboardQueue(); + ps[myconnectindex].palette = palette; + rotatesprite(0,0,65536L,0,3293,0,0,2+8+16+64, 0,0,xdim-1,ydim-1); + nextpage(); for(t=63;t>0;t--) palto(0,0,0,t); + while( !KB_KeyWaiting() ) getpackets(); + for(t=0;t<64;t++) palto(0,0,0,t); + + break; + + case 3: + + setview(0,0,xdim-1,ydim-1); + + MUSIC_StopSong(); + clearview(0L); + nextpage(); + + if(ud.lockout == 0) + { + KB_FlushKeyboardQueue(); + playanm("vol4e1.anm",8); + clearview(0L); + nextpage(); + playanm("vol4e2.anm",10); + clearview(0L); + nextpage(); + playanm("vol4e3.anm",11); + clearview(0L); + nextpage(); + } + + FX_StopAllSounds(); + clearsoundlocks(); + sound(ENDSEQVOL3SND4); + KB_FlushKeyboardQueue(); + + ps[myconnectindex].palette = palette; + palto(0,0,0,63); + clearview(0L); + menutext(160,60,0,0,"THANKS TO ALL OUR"); + menutext(160,60+16,0,0,"FANS FOR GIVING"); + menutext(160,60+16+16,0,0,"US BIG HEADS."); + menutext(160,70+16+16+16,0,0,"LOOK FOR A DUKE NUKEM 3D"); + menutext(160,70+16+16+16+16,0,0,"SEQUEL SOON."); + nextpage(); + + for(t=63;t>0;t-=3) palto(0,0,0,t); + KB_FlushKeyboardQueue(); + while(!KB_KeyWaiting()) getpackets(); + for(t=0;t<64;t+=3) palto(0,0,0,t); + + clearview(0L); + nextpage(); + + playanm("DUKETEAM.ANM",4); + + KB_FlushKeyboardQueue(); + while(!KB_KeyWaiting()) getpackets(); + + clearview(0L); + nextpage(); + palto(0,0,0,63); + + FX_StopAllSounds(); + clearsoundlocks(); + KB_FlushKeyboardQueue(); + + break; + + case 2: + + MUSIC_StopSong(); + clearview(0L); + nextpage(); + if(ud.lockout == 0) + { + for(t=63;t>=0;t--) palto(0,0,0,t); + playanm("cineov3.anm",2); + KB_FlushKeyboardQueue(); + ototalclock = totalclock+200; + while(totalclock < ototalclock) getpackets(); + clearview(0L); + nextpage(); + + FX_StopAllSounds(); + clearsoundlocks(); + } + + playanm("RADLOGO.ANM",3); + + if( ud.lockout == 0 && !KB_KeyWaiting() ) + { + sound(ENDSEQVOL3SND5); + while(Sound[ENDSEQVOL3SND5].lock>=200) getpackets(); + if(KB_KeyWaiting()) goto ENDANM; + sound(ENDSEQVOL3SND6); + while(Sound[ENDSEQVOL3SND6].lock>=200) getpackets(); + if(KB_KeyWaiting()) goto ENDANM; + sound(ENDSEQVOL3SND7); + while(Sound[ENDSEQVOL3SND7].lock>=200) getpackets(); + if(KB_KeyWaiting()) goto ENDANM; + sound(ENDSEQVOL3SND8); + while(Sound[ENDSEQVOL3SND8].lock>=200) getpackets(); + if(KB_KeyWaiting()) goto ENDANM; + sound(ENDSEQVOL3SND9); + while(Sound[ENDSEQVOL3SND9].lock>=200) getpackets(); + } + + KB_FlushKeyboardQueue(); + totalclock = 0; + while(!KB_KeyWaiting() && totalclock < 120) getpackets(); + + ENDANM: + + FX_StopAllSounds(); + clearsoundlocks(); + + KB_FlushKeyboardQueue(); + + clearview(0L); + + break; + } + + FRAGBONUS: + + ps[myconnectindex].palette = palette; + KB_FlushKeyboardQueue(); + totalclock = 0; tinc = 0; + bonuscnt = 0; + + MUSIC_StopSong(); + FX_StopAllSounds(); + clearsoundlocks(); + + if(playerswhenstarted > 1 && ud.coop != 1 ) + { + if(!(MusicToggle == 0 || MusicDevice == NumSoundCards)) + sound(BONUSMUSIC); + + rotatesprite(0,0,65536L,0,MENUSCREEN,16,0,2+8+16+64,0,0,xdim-1,ydim-1); + rotatesprite(160<<16,34<<16,65536L,0,INGAMEDUKETHREEDEE,0,0,10,0,0,xdim-1,ydim-1); + rotatesprite((260)<<16,36<<16,65536L,0,PLUTOPAKSPRITE+2,0,0,2+8,0,0,xdim-1,ydim-1); + gametext(160,58+2,"MULTIPLAYER TOTALS",0,2+8+16); + gametext(160,58+10,level_names[(ud.volume_number*11)+ud.last_level-1],0,2+8+16); + + gametext(160,165,"PRESS ANY KEY TO CONTINUE",0,2+8+16); + + + t = 0; + minitext(23,80," NAME KILLS",8,2+8+16+128); + for(i=0;i 1) return; + + for(t=0;t<64;t+=7) palto(0,0,0,t); + } + + if(bonusonly || ud.multimode > 1) return; + + switch(ud.volume_number) + { + case 1: + gfx_offset = 5; + break; + default: + gfx_offset = 0; + break; + } + + rotatesprite(0,0,65536L,0,BONUSSCREEN+gfx_offset,0,0,2+8+16+64+128,0,0,xdim-1,ydim-1); + + menutext(160,20-6,0,0,&level_names[(ud.volume_number*11)+ud.last_level-1][0]); + menutext(160,36-6,0,0,"COMPLETED"); + + gametext(160,192,"PRESS ANY KEY TO CONTINUE",16,2+8+16); + + if(!(MusicToggle == 0 || MusicDevice == NumSoundCards)) + sound(BONUSMUSIC); + + nextpage(); + KB_FlushKeyboardQueue(); + for(t=0;t<64;t++) palto(0,0,0,63-t); + bonuscnt = 0; + totalclock = 0; tinc = 0; + + while( 1 ) + { + if(ps[myconnectindex].gm&MODE_EOL) + { + rotatesprite(0,0,65536L,0,BONUSSCREEN+gfx_offset,0,0,2+8+16+64+128,0,0,xdim-1,ydim-1); + + if( totalclock > (1000000000L) && totalclock < (1000000320L) ) + { + switch( (totalclock>>4)%15 ) + { + case 0: + if(bonuscnt == 6) + { + bonuscnt++; + sound(SHOTGUN_COCK); + switch(rand()&3) + { + case 0: + sound(BONUS_SPEECH1); + break; + case 1: + sound(BONUS_SPEECH2); + break; + case 2: + sound(BONUS_SPEECH3); + break; + case 3: + sound(BONUS_SPEECH4); + break; + } + } + case 1: + case 4: + case 5: + rotatesprite(199<<16,31<<16,65536L,0,BONUSSCREEN+3+gfx_offset,0,0,2+8+16+64+128,0,0,xdim-1,ydim-1); + break; + case 2: + case 3: + rotatesprite(199<<16,31<<16,65536L,0,BONUSSCREEN+4+gfx_offset,0,0,2+8+16+64+128,0,0,xdim-1,ydim-1); + break; + } + } + else if( totalclock > (10240+120L) ) break; + else + { + switch( (totalclock>>5)&3 ) + { + case 1: + case 3: + rotatesprite(199<<16,31<<16,65536L,0,BONUSSCREEN+1+gfx_offset,0,0,2+8+16+64+128,0,0,xdim-1,ydim-1); + break; + case 2: + rotatesprite(199<<16,31<<16,65536L,0,BONUSSCREEN+2+gfx_offset,0,0,2+8+16+64+128,0,0,xdim-1,ydim-1); + break; + } + } + + menutext(160,20-6,0,0,&level_names[(ud.volume_number*11)+ud.last_level-1][0]); + menutext(160,36-6,0,0,"COMPLETED"); + + gametext(160,192,"PRESS ANY KEY TO CONTINUE",16,2+8+16); + + if( totalclock > (60*3) ) + { + gametext(10,59+9,"Your Time:",0,2+8+16); + gametext(10,69+9,"Par time:",0,2+8+16); + gametext(10,78+9,"3D Realms' Time:",0,2+8+16); + if(bonuscnt == 0) + bonuscnt++; + + if( totalclock > (60*4) ) + { + if(bonuscnt == 1) + { + bonuscnt++; + sound(PIPEBOMB_EXPLODE); + } + sprintf(tempbuf,"%02ld:%02ld", + (ps[myconnectindex].player_par/(26*60))%60, + (ps[myconnectindex].player_par/26)%60); + gametext((320>>2)+71,60+9,tempbuf,0,2+8+16); + + sprintf(tempbuf,"%02ld:%02ld", + (partime[ud.volume_number*11+ud.last_level-1]/(26*60))%60, + (partime[ud.volume_number*11+ud.last_level-1]/26)%60); + gametext((320>>2)+71,69+9,tempbuf,0,2+8+16); + + sprintf(tempbuf,"%02ld:%02ld", + (designertime[ud.volume_number*11+ud.last_level-1]/(26*60))%60, + (designertime[ud.volume_number*11+ud.last_level-1]/26)%60); + gametext((320>>2)+71,78+9,tempbuf,0,2+8+16); + + } + } + if( totalclock > (60*6) ) + { + gametext(10,94+9,"Enemies Killed:",0,2+8+16); + gametext(10,99+4+9,"Enemies Left:",0,2+8+16); + + if(bonuscnt == 2) + { + bonuscnt++; + sound(FLY_BY); + } + + if( totalclock > (60*7) ) + { + if(bonuscnt == 3) + { + bonuscnt++; + sound(PIPEBOMB_EXPLODE); + } + sprintf(tempbuf,"%-3d",ps[myconnectindex].actors_killed); + gametext((320>>2)+70,93+9,tempbuf,0,2+8+16); + if(ud.player_skill > 3 ) + { + sprintf(tempbuf,"N/A"); + gametext((320>>2)+70,99+4+9,tempbuf,0,2+8+16); + } + else + { + if( (ps[myconnectindex].max_actors_killed-ps[myconnectindex].actors_killed) < 0 ) + sprintf(tempbuf,"%-3d",0); + else sprintf(tempbuf,"%-3d",ps[myconnectindex].max_actors_killed-ps[myconnectindex].actors_killed); + gametext((320>>2)+70,99+4+9,tempbuf,0,2+8+16); + } + } + } + if( totalclock > (60*9) ) + { + gametext(10,120+9,"Secrets Found:",0,2+8+16); + gametext(10,130+9,"Secrets Missed:",0,2+8+16); + if(bonuscnt == 4) bonuscnt++; + + if( totalclock > (60*10) ) + { + if(bonuscnt == 5) + { + bonuscnt++; + sound(PIPEBOMB_EXPLODE); + } + sprintf(tempbuf,"%-3d",ps[myconnectindex].secret_rooms); + gametext((320>>2)+70,120+9,tempbuf,0,2+8+16); + if( ps[myconnectindex].secret_rooms > 0 ) + sprintf(tempbuf,"%-3d",(100*ps[myconnectindex].secret_rooms/ps[myconnectindex].max_secret_rooms)); + sprintf(tempbuf,"%-3d",ps[myconnectindex].max_secret_rooms-ps[myconnectindex].secret_rooms); + gametext((320>>2)+70,130+9,tempbuf,0,2+8+16); + } + } + + if(totalclock > 10240 && totalclock < 10240+10240) + totalclock = 1024; + + if( KB_KeyWaiting() && totalclock > (60*2) ) + { + if( KB_KeyPressed( sc_F12 ) ) + { + KB_ClearKeyDown( sc_F12 ); + dukescreencapture("duke0000.pcx",0); + } + + if( totalclock < (60*13) ) + { + KB_FlushKeyboardQueue(); + totalclock = (60*13); + } + else if( totalclock < (1000000000L)) + totalclock = (1000000000L); + } + } + else break; + nextpage(); + } + + // Stop all noise after score screen, otherwise you'll get overlapping + // music after beating an episode on the duke logo animation. + // Not sure why this doesn't happen in the DOS version. Might be a + // quirk of our newer sound code. --ryan. + MUSIC_StopSong(); + FX_StopAllSounds(); +} + + +void cameratext(short i) +{ + char flipbits; + long x , y; + + if(!T1) + { + rotatesprite(24<<16,33<<16,65536L,0,CAMCORNER,0,0,2,windowx1,windowy1,windowx2,windowy2); + rotatesprite((320-26)<<16,34<<16,65536L,0,CAMCORNER+1,0,0,2,windowx1,windowy1,windowx2,windowy2); + rotatesprite(22<<16,163<<16,65536L,512,CAMCORNER+1,0,0,2+4,windowx1,windowy1,windowx2,windowy2); + rotatesprite((310-10)<<16,163<<16,65536L,512,CAMCORNER+1,0,0,2,windowx1,windowy1,windowx2,windowy2); + if(totalclock&16) + rotatesprite(46<<16,32<<16,65536L,0,CAMLIGHT,0,0,2,windowx1,windowy1,windowx2,windowy2); + } + else + { + flipbits = (totalclock<<1)&48; + for(x=0;x<394;x+=64) + for(y=0;y<200;y+=64) + rotatesprite(x<<16,y<<16,65536L,0,STATIC,0,0,2+flipbits,windowx1,windowy1,windowx2,windowy2); + } +} + +void vglass(long x,long y,short a,short wn,short n) +{ + long z, zincs; + short sect; + + sect = wall[wn].nextsector; + if(sect == -1) return; + zincs = ( sector[sect].floorz-sector[sect].ceilingz ) / n; + + for(z = sector[sect].ceilingz;z < sector[sect].floorz; z += zincs ) + EGS(sect,x,y,z-(TRAND&8191),GLASSPIECES+(z&(TRAND%3)),-32,36,36,a+128-(TRAND&255),16+(TRAND&31),0,-1,5); +} + +void lotsofglass(short i,short wallnum,short n) +{ + long j, xv, yv, z, x1, y1; + short sect, a; + + sect = -1; + + if(wallnum < 0) + { + for(j=n-1; j >= 0 ;j--) + { + a = SA-256+(TRAND&511)+1024; + EGS(SECT,SX,SY,SZ,GLASSPIECES+(j%3),-32,36,36,a,32+(TRAND&63),1024-(TRAND&1023),i,5); + } + return; + } + + j = n+1; + + x1 = wall[wallnum].x; + y1 = wall[wallnum].y; + + xv = wall[wall[wallnum].point2].x-x1; + yv = wall[wall[wallnum].point2].y-y1; + + x1 -= ksgn(yv); + y1 += ksgn(xv); + + xv /= j; + yv /= j; + + for(j=n;j>0;j--) + { + x1 += xv; + y1 += yv; + + updatesector(x1,y1,§); + if(sect >= 0) + { + z = sector[sect].floorz-(TRAND&(klabs(sector[sect].ceilingz-sector[sect].floorz))); + if( z < -(32<<8) || z > (32<<8) ) + z = SZ-(32<<8)+(TRAND&((64<<8)-1)); + a = SA-1024; + EGS(SECT,x1,y1,z,GLASSPIECES+(j%3),-32,36,36,a,32+(TRAND&63),-(TRAND&1023),i,5); + } + } +} + +void spriteglass(short i,short n) +{ + long j, k, a, z; + + for(j=n;j>0;j--) + { + a = TRAND&2047; + z = SZ-((TRAND&16)<<8); + k = EGS(SECT,SX,SY,z,GLASSPIECES+(j%3),TRAND&15,36,36,a,32+(TRAND&63),-512-(TRAND&2047),i,5); + sprite[k].pal = sprite[i].pal; + } +} + +void ceilingglass(short i,short sectnum,short n) +{ + long j, xv, yv, z, x1, y1; + short a,s, startwall,endwall; + + startwall = sector[sectnum].wallptr; + endwall = startwall+sector[sectnum].wallnum; + + for(s=startwall;s<(endwall-1);s++) + { + x1 = wall[s].x; + y1 = wall[s].y; + + xv = (wall[s+1].x-x1)/(n+1); + yv = (wall[s+1].y-y1)/(n+1); + + for(j=n;j>0;j--) + { + x1 += xv; + y1 += yv; + a = TRAND&2047; + z = sector[sectnum].ceilingz+((TRAND&15)<<8); + EGS(sectnum,x1,y1,z,GLASSPIECES+(j%3),-32,36,36,a,(TRAND&31),0,i,5); + } + } +} + + + +void lotsofcolourglass(short i,short wallnum,short n) +{ + long j, xv, yv, z, x1, y1; + short sect = -1, a, k; + + if(wallnum < 0) + { + for(j=n-1; j >= 0 ;j--) + { + a = TRAND&2047; + k = EGS(SECT,SX,SY,SZ-(TRAND&(63<<8)),GLASSPIECES+(j%3),-32,36,36,a,32+(TRAND&63),1024-(TRAND&2047),i,5); + sprite[k].pal = TRAND&15; + } + return; + } + + j = n+1; + x1 = wall[wallnum].x; + y1 = wall[wallnum].y; + + xv = (wall[wall[wallnum].point2].x-wall[wallnum].x)/j; + yv = (wall[wall[wallnum].point2].y-wall[wallnum].y)/j; + + for(j=n;j>0;j--) + { + x1 += xv; + y1 += yv; + + updatesector(x1,y1,§); + z = sector[sect].floorz-(TRAND&(klabs(sector[sect].ceilingz-sector[sect].floorz))); + if( z < -(32<<8) || z > (32<<8) ) + z = SZ-(32<<8)+(TRAND&((64<<8)-1)); + a = SA-1024; + k = EGS(SECT,x1,y1,z,GLASSPIECES+(j%3),-32,36,36,a,32+(TRAND&63),-(TRAND&2047),i,5); + sprite[k].pal = TRAND&7; + } +} + +void SetupGameButtons( void ) +{ + CONTROL_DefineFlag(gamefunc_Move_Forward,false); + CONTROL_DefineFlag(gamefunc_Move_Backward,false); + CONTROL_DefineFlag(gamefunc_Turn_Left,false); + CONTROL_DefineFlag(gamefunc_Turn_Right,false); + CONTROL_DefineFlag(gamefunc_Strafe,false); + CONTROL_DefineFlag(gamefunc_Fire,false); + CONTROL_DefineFlag(gamefunc_Open,false); + CONTROL_DefineFlag(gamefunc_Run,false); + CONTROL_DefineFlag(gamefunc_AutoRun,false); + CONTROL_DefineFlag(gamefunc_Jump,false); + CONTROL_DefineFlag(gamefunc_Crouch,false); + CONTROL_DefineFlag(gamefunc_Look_Up,false); + CONTROL_DefineFlag(gamefunc_Look_Down,false); + CONTROL_DefineFlag(gamefunc_Look_Left,false); + CONTROL_DefineFlag(gamefunc_Look_Right,false); + CONTROL_DefineFlag(gamefunc_Strafe_Left,false); + CONTROL_DefineFlag(gamefunc_Strafe_Right,false); + CONTROL_DefineFlag(gamefunc_Aim_Up,false); + CONTROL_DefineFlag(gamefunc_Aim_Down,false); + CONTROL_DefineFlag(gamefunc_Weapon_1,false); + CONTROL_DefineFlag(gamefunc_Weapon_2,false); + CONTROL_DefineFlag(gamefunc_Weapon_3,false); + CONTROL_DefineFlag(gamefunc_Weapon_4,false); + CONTROL_DefineFlag(gamefunc_Weapon_5,false); + CONTROL_DefineFlag(gamefunc_Weapon_6,false); + CONTROL_DefineFlag(gamefunc_Weapon_7,false); + CONTROL_DefineFlag(gamefunc_Weapon_8,false); + CONTROL_DefineFlag(gamefunc_Weapon_9,false); + CONTROL_DefineFlag(gamefunc_Weapon_10,false); + CONTROL_DefineFlag(gamefunc_Inventory,false); + CONTROL_DefineFlag(gamefunc_Inventory_Left,false); + CONTROL_DefineFlag(gamefunc_Inventory_Right,false); + CONTROL_DefineFlag(gamefunc_Holo_Duke,false); + CONTROL_DefineFlag(gamefunc_Jetpack,false); + CONTROL_DefineFlag(gamefunc_NightVision,false); + CONTROL_DefineFlag(gamefunc_MedKit,false); + CONTROL_DefineFlag(gamefunc_TurnAround,false); + CONTROL_DefineFlag(gamefunc_SendMessage,false); + CONTROL_DefineFlag(gamefunc_Map,false); + CONTROL_DefineFlag(gamefunc_Shrink_Screen,false); + CONTROL_DefineFlag(gamefunc_Enlarge_Screen,false); + CONTROL_DefineFlag(gamefunc_Center_View,false); + CONTROL_DefineFlag(gamefunc_Holster_Weapon,false); + CONTROL_DefineFlag(gamefunc_Show_Opponents_Weapon,false); + CONTROL_DefineFlag(gamefunc_Map_Follow_Mode,false); + CONTROL_DefineFlag(gamefunc_See_Coop_View,false); + CONTROL_DefineFlag(gamefunc_Mouse_Aiming,false); + CONTROL_DefineFlag(gamefunc_Toggle_Crosshair,false); + CONTROL_DefineFlag(gamefunc_Steroids,false); + CONTROL_DefineFlag(gamefunc_Quick_Kick,false); + CONTROL_DefineFlag(gamefunc_Next_Weapon,false); + CONTROL_DefineFlag(gamefunc_Previous_Weapon,false); +} + +/* +=================== += += GetTime += +=================== +*/ + +/* + * (This was originally "GetTime", but that conflicts with a function in + * in MacOSX's Carbon. --ryan.) + */ +long DUKE3D_GetTime(void) + { + return totalclock; + } + + +/* +=================== += += CenterCenter += +=================== +*/ + +void CenterCenter(void) + { + printf("Center the joystick and press a button\n"); + } + +/* +=================== += += UpperLeft += +=================== +*/ + +void UpperLeft(void) + { + printf("Move joystick to upper-left corner and press a button\n"); + } + +/* +=================== += += LowerRight += +=================== +*/ + +void LowerRight(void) + { + printf("Move joystick to lower-right corner and press a button\n"); + } + +/* +=================== += += CenterThrottle += +=================== +*/ + +void CenterThrottle(void) + { + printf("Center the throttle control and press a button\n"); + } + +/* +=================== += += CenterRudder += +=================== +*/ + +void CenterRudder(void) +{ + printf("Center the rudder control and press a button\n"); +} + +// Rare Multiplayer, when dead, total screen screwup back again! +// E3l1 (Coop /w monsters) sprite list corrupt 50% +// Univbe exit, instead, default to screen buffer. +// Check all caches bounds and memory usages +// Fix enlarger weapon selections to perfection +// Need sounds.c +// Spawning a couple of sounds at the same time +// Check Weapon Switching +// FIRE and FIRE2 +// Where should I flash the screen white??? +// Jittery on subs in mp? +// Check accurate memory amounts! +// Why squish sound at hit space when dead? +// Falling Counter Not reset in mp +// Wierd small freezer +// Double freeze on player?, still firing +// Do Mouse Flip option +// Save mouse aiming +// Laser bounce off mirrors +// GEORGE: Ten in text screen. +// Alien: +// Freeze: change +// Press space holding player +// Press space +// tank broke +// 2d mode fucked in fake mp mode +// 207 +// Mail not rolling up on conveyers +// Fix all alien animations +// Do episode names in .CONS +// do syntak check for "{?????" +// Make commline parms set approiate multiplayer flags + +// Check all breakables to see if they are exploding properly +// Fix freezing palette on Alien + +// Do a demo make run overnite +// Fix Super Duck +// Slime Guies, use quickkick. + +// Make Lasers from trip bombs reflect off mirrors +// Remember for lockout of sound swears +// Pass sender in packed, NOT +// Fatal sync give no message for TEN +// Hitting TEN BUTTON(OPTION) no TEN SCreen +// Check multioperateswitches for se 31,32 +// Fix pal for ceilings (SE#18) +// case 31: sprites up one high +// E1l1 No Kill All troops in room, sleep time + +// Fifo for message list + +// Bloodsplat on conveyers + +// Meclanical +// Increase sound +// Mouse Delay at death +// Wierd slowdown + +// Footprints on stuff floating + +// Ken, The inside function is called a lot in -1 sectors +// No loading Univbe message rewrite +// Expander must cycle with rest of weapons +// Duck SHOOT PIPEBOMB, red wall + +// Get commit source from mark + +/* +1. fix pipebomb bug +2. check george maps +4. Save/Restore check (MP and SP) +5. Check TEN +6. Get Commit fixed +8. Is mail slow? +9. Cacheing +10. Blue out "PLAY ON TEN" in MULTIPLAYER +11. Eight Player test +12. Postal.voc not found. +13. All Monsters explode in arcade, + check SEENINE STRENGTH, + Change 28<<8 back to 16<<8 in hitradius + Compare 1.3d to 1.4 +14. Check sounds/gfx for for parr lock +15. Player # Loaded a game +16. Replace Crane code 1.3d to 1.4 +17. Fix Greenslime +18. Small Freeze sprite,below floor +19. Vesa message auto abort in mp? +20. Fucked Palette in my skip ahead in MP +21. Load in main menu +22. Rotated frag screen no game screen +23. Jibs sounds when killed other dukes +24. Ten code and /f4 mode +25. Fix All MP Glitches!! +26. Unrem Menues anim tenbn +27. buy groc,clothes,scanner +28. Why Double Defs in global and game, is so at work +29. Check that all .objs are erased +30. Check why 1.3ds gotweapon gamedef coop code no workie +31. Heavy mods to net code +32. Make sure all commline stuff works, +33. killed all waitfor??? +34. 90k stack +35. double door probs +36: copy protection +* when you start a game the duke saying that is played when you choose a skill the sound is cut off. +* NEWBEASTJUMPING is not deleted at premap in multi-play +if(*c == '4') no work need objs ask ken, commit +{ +movesperpacket = 4; +setpackettimeout(0x3fffffff,0x3fffffff); +} +remember, netcode load +*/ +// Ai Problem in god mode. +// Checkplayerhurtwall for forcefields bigforce +// Nuddie, posters. IMF +// Release commit.c to public? +// Document Save bug with mp +// Check moves per packet /f4 waitforeverybody over net? +// Kill IDF OBJ +// No shotguns under water @ tanker +// Unrem copyprotect +// Look for printf and puts +// Check con rewrites +// erase mmulti.c, or get newest objs +// Why nomonsters screwy in load menu in mp +// load last > 'y' == NOT +// Check xptr oos when dead rising to surface. +// diaginal warping with shotguns +// Test white room. Lasertripbomb arming crash +// The Bog +// Run Duke Out of windows +// Put Version number in con files +// Test diff. version playing together +// Reorganize dukecd +// Put out patch w/ two weeks testing +// Print draw3d +// Double Klick + +/* +Duke Nukem V + +Layout: + + Settings: + Suburbs + Duke inflitrating neighborhoods inf. by aliens + Death Valley: + Sorta like a western. Bull-skulls half buried in the sand + Military compound: Aliens take over nuke-missle silo, duke + must destroy. + Abondend Aircraft field + Vegas: + Blast anything bright! Alien lights camoflauged. + Alien Drug factory. The Blue Liquid + Mountainal Cave: + Interior cave battles. + Jungle: + Trees, canopee, animals, a mysterious hole in the earth with + gas seaping thru. + Penetencury: + Good use of spotlights: + Mental ward: + People whom have claimed to be slowly changing into an + alien species + + Inventory: + Wood, + Metal, + Torch, + Rope, + Plastique, + Cloth, + Wiring, + Glue, + Cigars, + Food, + Duck Tape, + Nails, + Piping, + Petrol, + Uranium, + Gold, + Prism, + Power Cell, + + Hand spikes (Limited usage, they become dull) + Oxygent (Oxygen mixed with stimulant) + + + Player Skills: + R-Left,R-Right,Foward,Back + Strafe, Jump, Double Flip Jump for distance + Help, Escape + Fire/Use + Use Menu + + After a brief resbit, Duke decides to get back to work. + +Cmdr: "Duke, we've got a lot of scared people down there. + Some reports even claim that people are already + slowly changing into aliens." +Duke: "No problem, my speciality is in croud control." +Cmdr: "Croud control, my ass! Remember that incident + during the war? You created nuthin' but death and + destruction." +Duke: "Not destruction, justice." +Cmdr: "I'll take no responsibility for your actions. Your on + your own! Behave your self, damnit! You got that, + soldger?" +Duke: "I've always been on my own... Face it, it's ass kickin' time, + SIR!" +Cmdr: "Get outta here...!" + (Duke gives the Cmdr a hard stair, then cocks his weapon and + walks out of the room) +Cmdr: In a wisper: "Good luck, my friend." + + (Cut to a scene where aliens are injecting genetic material + into an unconcious subject) + +Programming: ( the functions I need ) + Images: Polys + Actors: + Multi-Object sections for change (head,arms,legs,torsoe,all change) + Facial expressions. Pal lookup per poly? + + struct imagetype + { + int *itable; // AngX,AngY,AngZ,Xoff,Yoff,Zoff; + int *idata; + struct imagetype *prev, *next; + } + +*/ + + +// Test frag screen name fuckup +// Test all xptrs +// Make Jibs stick to ceiling +// Save Game menu crash +// Cache len sum err +// Loading in main (MP), reset totalclock? +// White Room +// Sound hitch with repeat bits +// Rewrite saved menues so no crash +// Put a getpackets after loadplayer in menus +// Put "loading..." before waitfor in loadpla +// No ready2send = 0 for loading +// Test Joystick +// Ten +// Bog +// Test Blimp respawn +// move 1 in player??? + + diff --git a/gamedef.c b/gamedef.c new file mode 100755 index 0000000..ea766f4 --- /dev/null +++ b/gamedef.c @@ -0,0 +1,3266 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment + +This file is part of Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Original Source: 1996 - Todd Replogle +Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms +*/ +//------------------------------------------------------------------------- + +#include "duke3d.h" + +extern short otherp; + +static short total_lines,line_number; +static char checking_ifelse,parsing_state,*last_used_text; +static short num_squigilly_brackets; +static long last_used_size; + +static short g_i,g_p; +static long g_x; +static long *g_t; +static spritetype *g_sp; + +#define NUMKEYWORDS 112 + +char *keyw[NUMKEYWORDS] = +{ + "definelevelname", // 0 + "actor", // 1 [#] + "addammo", // 2 [#] + "ifrnd", // 3 [C] + "enda", // 4 [:] + "ifcansee", // 5 [C] + "ifhitweapon", // 6 [#] + "action", // 7 [#] + "ifpdistl", // 8 [#] + "ifpdistg", // 9 [#] + "else", // 10 [#] + "strength", // 11 [#] + "break", // 12 [#] + "shoot", // 13 [#] + "palfrom", // 14 [#] + "sound", // 15 [filename.voc] + "fall", // 16 [] + "state", // 17 + "ends", // 18 + "define", // 19 + "//", // 20 + "ifai", // 21 + "killit", // 22 + "addweapon", // 23 + "ai", // 24 + "addphealth", // 25 + "ifdead", // 26 + "ifsquished", // 27 + "sizeto", // 28 + "{", // 29 + "}", // 30 + "spawn", // 31 + "move", // 32 + "ifwasweapon", // 33 + "ifaction", // 34 + "ifactioncount", // 35 + "resetactioncount", // 36 + "debris", // 37 + "pstomp", // 38 + "/*", // 39 + "cstat", // 40 + "ifmove", // 41 + "resetplayer", // 42 + "ifonwater", // 43 + "ifinwater", // 44 + "ifcanshoottarget", // 45 + "ifcount", // 46 + "resetcount", // 47 + "addinventory", // 48 + "ifactornotstayput",// 49 + "hitradius", // 50 + "ifp", // 51 + "count", // 52 + "ifactor", // 53 + "music", // 54 + "include", // 55 + "ifstrength", // 56 + "definesound", // 57 + "guts", // 58 + "ifspawnedby", // 59 + "gamestartup", // 60 + "wackplayer", // 61 + "ifgapzl", // 62 + "ifhitspace", // 63 + "ifoutside", // 64 + "ifmultiplayer", // 65 + "operate", // 66 + "ifinspace", // 67 + "debug", // 68 + "endofgame", // 69 + "ifbulletnear", // 70 + "ifrespawn", // 71 + "iffloordistl", // 72 + "ifceilingdistl", // 73 + "spritepal", // 74 + "ifpinventory", // 75 + "betaname", // 76 + "cactor", // 77 + "ifphealthl", // 78 + "definequote", // 79 + "quote", // 80 + "ifinouterspace", // 81 + "ifnotmoving", // 82 + "respawnhitag", // 83 + "tip", // 84 + "ifspritepal", // 85 + "money", // 86 + "soundonce", // 87 + "addkills", // 88 + "stopsound", // 89 + "ifawayfromwall", // 90 + "ifcanseetarget", // 91 + "globalsound", // 92 + "lotsofglass", // 93 + "ifgotweaponce", // 94 + "getlastpal", // 95 + "pkick", // 96 + "mikesnd", // 97 + "useractor", // 98 + "sizeat", // 99 + "addstrength", // 100 [#] + "cstator", // 101 + "mail", // 102 + "paper", // 103 + "tossweapon", // 104 + "sleeptime", // 105 + "nullop", // 106 + "definevolumename", // 107 + "defineskillname", // 108 + "ifnosounds", // 109 + "clipdist", // 110 + "ifangdiffl" // 111 +}; + + +short getincangle(short a,short na) +{ + a &= 2047; + na &= 2047; + + if(klabs(a-na) < 1024) + return (na-a); + else + { + if(na > 1024) na -= 2048; + if(a > 1024) a -= 2048; + + na -= 2048; + a -= 2048; + return (na-a); + } +} + +char ispecial(char c) +{ + if(c == 0x0a) + { + line_number++; + return 1; + } + + if(c == ' ' || c == 0x0d) + return 1; + + return 0; +} + +char isaltok(char c) +{ + return ( isalnum(c) || c == '{' || c == '}' || c == '/' || c == '*' || c == '-' || c == '_' || c == '.'); +} + +void getglobalz(short i) +{ + long hz,lz,zr; + + spritetype *s = &sprite[i]; + + if( s->statnum == 10 || s->statnum == 6 || s->statnum == 2 || s->statnum == 1 || s->statnum == 4) + { + if(s->statnum == 4) + zr = 4L; + else zr = 127L; + + getzrange(s->x,s->y,s->z-(FOURSLEIGHT),s->sectnum,&hittype[i].ceilingz,&hz,&hittype[i].floorz,&lz,zr,CLIPMASK0); + + if( (lz&49152) == 49152 && (sprite[lz&(MAXSPRITES-1)].cstat&48) == 0 ) + { + lz &= (MAXSPRITES-1); + if( badguy(&sprite[lz]) && sprite[lz].pal != 1) + { + if( s->statnum != 4 ) + { + hittype[i].dispicnum = -4; // No shadows on actors + s->xvel = -256; + ssp(i,CLIPMASK0); + } + } + else if(sprite[lz].picnum == APLAYER && badguy(s) ) + { + hittype[i].dispicnum = -4; // No shadows on actors + s->xvel = -256; + ssp(i,CLIPMASK0); + } + else if(s->statnum == 4 && sprite[lz].picnum == APLAYER) + if(s->owner == lz) + { + hittype[i].ceilingz = sector[s->sectnum].ceilingz; + hittype[i].floorz = sector[s->sectnum].floorz; + } + } + } + else + { + hittype[i].ceilingz = sector[s->sectnum].ceilingz; + hittype[i].floorz = sector[s->sectnum].floorz; + } +} + + +void makeitfall(short i) +{ + spritetype *s = &sprite[i]; + long hz,lz,c; + + if( floorspace(s->sectnum) ) + c = 0; + else + { + if( ceilingspace(s->sectnum) || sector[s->sectnum].lotag == 2) + c = gc/6; + else c = gc; + } + + if( ( s->statnum == 1 || s->statnum == 10 || s->statnum == 2 || s->statnum == 6 ) ) + getzrange(s->x,s->y,s->z-(FOURSLEIGHT),s->sectnum,&hittype[i].ceilingz,&hz,&hittype[i].floorz,&lz,127L,CLIPMASK0); + else + { + hittype[i].ceilingz = sector[s->sectnum].ceilingz; + hittype[i].floorz = sector[s->sectnum].floorz; + } + + if( s->z < hittype[i].floorz-(FOURSLEIGHT) ) + { + if( sector[s->sectnum].lotag == 2 && s->zvel > 3122 ) + s->zvel = 3144; + if(s->zvel < 6144) + s->zvel += c; + else s->zvel = 6144; + s->z += s->zvel; + } + if( s->z >= hittype[i].floorz-(FOURSLEIGHT) ) + { + s->z = hittype[i].floorz - FOURSLEIGHT; + s->zvel = 0; + } +} + + +void getlabel(void) +{ + long i; + + while( isalnum(*textptr) == 0 ) + { + if(*textptr == 0x0a) line_number++; + textptr++; + if( *textptr == 0) + return; + } + + i = 0; + while( ispecial(*textptr) == 0 ) + label[(labelcnt<<6)+i++] = *(textptr++); + + label[(labelcnt<<6)+i] = 0; +} + +long keyword(void) +{ + long i; + char *temptextptr; + + temptextptr = textptr; + + while( isaltok(*temptextptr) == 0 ) + { + temptextptr++; + if( *temptextptr == 0 ) + return 0; + } + + i = 0; + while( isaltok(*temptextptr) ) + { + tempbuf[i] = *(temptextptr++); + i++; + } + tempbuf[i] = 0; + + for(i=0;i 12 || ( *textptr == '\0' ) || ( *(textptr+1) == '\0' ) ) return 1; + + tw = transword(); + + switch(tw) + { + default: + case -1: + return 0; //End + case 39: //Rem endrem + scriptptr--; + j = line_number; + do + { + textptr++; + if(*textptr == 0x0a) line_number++; + if( *textptr == 0 ) + { +// printf(" * ERROR!(L%d) Found '/*' with no '*/'.\n",j,label+(labelcnt<<6)); + printf(" * ERROR!(L%ld) Found '/*' with no '*/'.\n",j); + error++; + return 0; + } + } + while( *textptr != '*' || *(textptr+1) != '/' ); + textptr+=2; + return 0; + case 17: + if( parsing_actor == 0 && parsing_state == 0 ) + { + getlabel(); + scriptptr--; + labelcode[labelcnt] = (long) scriptptr; + labelcnt++; + + parsing_state = 1; + + return 0; + } + + getlabel(); + + for(i=0;i 0 ) + { + printf(" * ERROR!(L%d) Found more '{' than '}' before 'ends'.\n",line_number); + error++; + } + if( num_squigilly_brackets < 0 ) + { + printf(" * ERROR!(L%d) Found more '}' than '{' before 'ends'.\n",line_number); + error++; + } + parsing_state = 0; + } + return 0; + case 19: + getlabel(); + // Check to see it's already defined + + for(i=0;i= 0) break; + transnum(); + } + for(k=j;k<2;k++) + { + *scriptptr = 0; + scriptptr++; + } + } + return 0; + + case 54: + { + scriptptr--; + transnum(); // Volume Number (0/4) + scriptptr--; + + k = *scriptptr-1; + + if(k >= 0) // if it's background music + { + i = 0; + while(keyword() == -1) + { + while( isaltok(*textptr) == 0 ) + { + if(*textptr == 0x0a) line_number++; + textptr++; + if( *textptr == 0 ) break; + } + j = 0; + while( isaltok(*(textptr+j)) ) + { + music_fn[k][i][j] = textptr[j]; + j++; + } + music_fn[k][i][j] = '\0'; + textptr += j; + if(i > 9) break; + i++; + } + } + else + { + i = 0; + while(keyword() == -1) + { + while( isaltok(*textptr) == 0 ) + { + if(*textptr == 0x0a) line_number++; + textptr++; + if( *textptr == 0 ) break; + } + j = 0; + while( isaltok(*(textptr+j)) ) + { + env_music_fn[i][j] = textptr[j]; + j++; + } + env_music_fn[i][j] = '\0'; + + textptr += j; + if(i > 9) break; + i++; + } + } + } + return 0; + case 55: + scriptptr--; + while( isaltok(*textptr) == 0 ) + { + if(*textptr == 0x0a) line_number++; + textptr++; + if( *textptr == 0 ) break; + } + j = 0; + while( isaltok(*textptr) ) + { + tempbuf[j] = *(textptr++); + j++; + } + tempbuf[j] = '\0'; + + FixFilePath(tempbuf); + fp = kopen4load(tempbuf,loadfromgrouponly); + if(fp <= 0) + { + error++; + printf(" * ERROR!(L%d) Could not find '%s'.\n",line_number,label+(labelcnt<<6)); + return 0; + } + + j = kfilelength(fp); + + printf("Including: '%s'.\n",tempbuf); + + temp_line_number = line_number; + line_number = 1; + temp_ifelse_check = checking_ifelse; + checking_ifelse = 0; + origtptr = textptr; + textptr = last_used_text+last_used_size; + + *(textptr+j) = 0; + + kread(fp,(char *)textptr,j); + kclose(fp); + + do + done = parsecommand(); + while( done == 0 ); + + textptr = origtptr; + total_lines += line_number; + line_number = temp_line_number; + checking_ifelse = temp_ifelse_check; + + return 0; + case 24: + if( parsing_actor || parsing_state ) + transnum(); + else + { + scriptptr--; + getlabel(); + + for(i=0;i= 0) break; + if(j == 2) + { + k = 0; + while(keyword() == -1) + { + transnum(); + scriptptr--; + k |= *scriptptr; + } + *scriptptr = k; + scriptptr++; + return 0; + } + else transnum(); + } + for(k=j;k<3;k++) + { + *scriptptr = 0; + scriptptr++; + } + } + return 0; + + case 7: + if( parsing_actor || parsing_state ) + transnum(); + else + { + scriptptr--; + getlabel(); + // Check to see it's already defined + + for(i=0;i= 0) break; + transnum(); + } + for(k=j;k<5;k++) + { + *scriptptr = 0; + scriptptr++; + } + } + return 0; + + case 1: + if( parsing_state ) + { + printf(" * ERROR!(L%d) Found 'actor' within 'state'.\n",line_number); + error++; + } + + if( parsing_actor ) + { + printf(" * ERROR!(L%d) Found 'actor' within 'actor'.\n",line_number); + error++; + } + + num_squigilly_brackets = 0; + scriptptr--; + parsing_actor = scriptptr; + + transnum(); + scriptptr--; + actorscrptr[*scriptptr] = parsing_actor; + + for(j=0;j<4;j++) + { + *(parsing_actor+j) = 0; + if(j == 3) + { + j = 0; + while(keyword() == -1) + { + transnum(); + scriptptr--; + j |= *scriptptr; + } + *scriptptr = j; + scriptptr++; + break; + } + else + { + if(keyword() >= 0) + { + scriptptr += (4-j); + break; + } + transnum(); + + *(parsing_actor+j) = *(scriptptr-1); + } + } + + checking_ifelse = 0; + + return 0; + + case 98: + + if( parsing_state ) + { + printf(" * ERROR!(L%d) Found 'useritem' within 'state'.\n",line_number); + error++; + } + + if( parsing_actor ) + { + printf(" * ERROR!(L%d) Found 'useritem' within 'actor'.\n",line_number); + error++; + } + + num_squigilly_brackets = 0; + scriptptr--; + parsing_actor = scriptptr; + + transnum(); + scriptptr--; + j = *scriptptr; + + transnum(); + scriptptr--; + actorscrptr[*scriptptr] = parsing_actor; + actortype[*scriptptr] = j; + + for(j=0;j<4;j++) + { + *(parsing_actor+j) = 0; + if(j == 3) + { + j = 0; + while(keyword() == -1) + { + transnum(); + scriptptr--; + j |= *scriptptr; + } + *scriptptr = j; + scriptptr++; + break; + } + else + { + if(keyword() >= 0) + { + scriptptr += (4-j); + break; + } + transnum(); + + *(parsing_actor+j) = *(scriptptr-1); + } + } + + checking_ifelse = 0; + + return 0; + + + + case 11: + case 13: + case 25: + case 31: + case 40: + case 52: + case 69: + case 74: + case 77: + case 80: + case 86: + case 88: + case 68: + case 100: + case 101: + case 102: + case 103: + case 105: + case 110: + transnum(); + return 0; + + case 2: + case 23: + case 28: + case 99: + case 37: + case 48: + case 58: + transnum(); + transnum(); + break; + case 50: + transnum(); + transnum(); + transnum(); + transnum(); + transnum(); + break; + case 10: + if( checking_ifelse ) + { + checking_ifelse--; + tempscrptr = scriptptr; + scriptptr++; //Leave a spot for the fail location + parsecommand(); + *tempscrptr = (long) scriptptr; + } + else + { + scriptptr--; + error++; + printf(" * ERROR!(L%d) Found 'else' with no 'if'.\n",line_number); + } + + return 0; + + case 75: + transnum(); + case 3: + case 8: + case 9: + case 21: + case 33: + case 34: + case 35: + case 41: + case 46: + case 53: + case 56: + case 59: + case 62: + case 72: + case 73: +// case 74: + case 78: + case 85: + case 94: + case 111: + transnum(); + case 43: + case 44: + case 49: + case 5: + case 6: + case 27: + case 26: + case 45: + case 51: + case 63: + case 64: + case 65: + case 67: + case 70: + case 71: + case 81: + case 82: + case 90: + case 91: + case 109: + + if(tw == 51) + { + j = 0; + do + { + transnum(); + scriptptr--; + j |= *scriptptr; + } + while(keyword() == -1); + *scriptptr = j; + scriptptr++; + } + + tempscrptr = scriptptr; + scriptptr++; //Leave a spot for the fail location + + do + { + j = keyword(); + if(j == 20 || j == 39) + parsecommand(); + } while(j == 20 || j == 39); + + parsecommand(); + + *tempscrptr = (long) scriptptr; + + checking_ifelse++; + return 0; + case 29: + num_squigilly_brackets++; + do + done = parsecommand(); + while( done == 0 ); + return 0; + case 30: + num_squigilly_brackets--; + if( num_squigilly_brackets < 0 ) + { + printf(" * ERROR!(L%d) Found more '}' than '{'.\n",line_number); + error++; + } + return 1; + case 76: + scriptptr--; + j = 0; + while( *textptr != 0x0a ) + { + betaname[j] = *textptr; + j++; textptr++; + } + betaname[j] = 0; + return 0; + case 20: + scriptptr--; //Negate the rem + while( *textptr != 0x0a ) + textptr++; + + // line_number++; + return 0; + + case 107: + scriptptr--; + transnum(); + scriptptr--; + j = *scriptptr; + while( *textptr == ' ' ) textptr++; + + i = 0; + + while( *textptr != 0x0a ) + { + volume_names[j][i] = toupper(*textptr); + textptr++,i++; + if(i >= 32) + { + printf(" * ERROR!(L%d) Volume name exceeds character size limit of 32.\n",line_number); + error++; + while( *textptr != 0x0a ) textptr++; + break; + } + } +#ifdef PLATFORM_UNIX + volume_names[j][i] = '\0'; +#else + volume_names[j][i-1] = '\0'; +#endif + return 0; + case 108: + scriptptr--; + transnum(); + scriptptr--; + j = *scriptptr; + while( *textptr == ' ' ) textptr++; + + i = 0; + + while( *textptr != 0x0a ) + { + skill_names[j][i] = toupper(*textptr); + textptr++,i++; + if(i >= 32) + { + printf(" * ERROR!(L%d) Skill name exceeds character size limit of 32.\n",line_number); + error++; + while( *textptr != 0x0a ) textptr++; + break; + } + } +#ifdef PLATFORM_UNIX + skill_names[j][i] = '\0'; +#else + skill_names[j][i-1] = '\0'; +#endif + return 0; + + case 0: + scriptptr--; + transnum(); + scriptptr--; + j = *scriptptr; + transnum(); + scriptptr--; + k = *scriptptr; + while( *textptr == ' ' ) textptr++; + + i = 0; + while( *textptr != ' ' && *textptr != 0x0a ) + { + level_file_names[j*11+k][i] = *textptr; + textptr++,i++; + if(i > 127) + { + printf(" * ERROR!(L%d) Level file name exceeds character size limit of 128.\n",line_number); + error++; + while( *textptr != ' ') textptr++; + break; + } + } +#ifdef PLATFORM_UNIX + level_names[j*11+k][i] = '\0'; +#else + level_names[j*11+k][i-1] = '\0'; +#endif + + while( *textptr == ' ' ) textptr++; + + partime[j*11+k] = + (((*(textptr+0)-'0')*10+(*(textptr+1)-'0'))*26*60)+ + (((*(textptr+3)-'0')*10+(*(textptr+4)-'0'))*26); + + textptr += 5; + while( *textptr == ' ' ) textptr++; + + designertime[j*11+k] = + (((*(textptr+0)-'0')*10+(*(textptr+1)-'0'))*26*60)+ + (((*(textptr+3)-'0')*10+(*(textptr+4)-'0'))*26); + + textptr += 5; + while( *textptr == ' ' ) textptr++; + + i = 0; + + while( *textptr != 0x0a ) + { + level_names[j*11+k][i] = toupper(*textptr); + textptr++,i++; + if(i >= 32) + { + printf(" * ERROR!(L%d) Level name exceeds character size limit of 32.\n",line_number); + error++; + while( *textptr != 0x0a ) textptr++; + break; + } + } +#ifdef PLATFORM_UNIX + level_names[j*11+k][i] = '\0'; +#else + level_names[j*11+k][i-1] = '\0'; +#endif + return 0; + + case 79: + scriptptr--; + transnum(); + k = *(scriptptr-1); + if(k >= NUMOFFIRSTTIMEACTIVE) + { + printf(" * ERROR!(L%d) Quote amount exceeds limit of %d characters.\n",line_number,NUMOFFIRSTTIMEACTIVE); + error++; + } + scriptptr--; + i = 0; + while( *textptr == ' ' ) + textptr++; + + while( *textptr != 0x0a ) + { + fta_quotes[k][i] = *textptr; + textptr++,i++; + if(i >= 64) + { + printf(" * ERROR!(L%d) Quote exceeds character size limit of 64.\n",line_number); + error++; + while( *textptr != 0x0a ) textptr++; + break; + } + } + fta_quotes[k][i] = '\0'; + return 0; + case 57: + scriptptr--; + transnum(); + k = *(scriptptr-1); + if(k >= NUM_SOUNDS) + { + printf(" * ERROR!(L%d) Exceeded sound limit of %d.\n",line_number,NUM_SOUNDS); + error++; + } + scriptptr--; + i = 0; + while( *textptr == ' ') + textptr++; + + while( *textptr != ' ' ) + { + sounds[k][i] = *textptr; + textptr++,i++; + if(i >= 13) + { + puts(sounds[k]); + printf(" * ERROR!(L%d) Sound filename exceeded limit of 13 characters.\n",line_number); + error++; + while( *textptr != ' ' ) textptr++; + break; + } + } + sounds[k][i] = '\0'; + + transnum(); + soundps[k] = *(scriptptr-1); + scriptptr--; + transnum(); + soundpe[k] = *(scriptptr-1); + scriptptr--; + transnum(); + soundpr[k] = *(scriptptr-1); + scriptptr--; + transnum(); + soundm[k] = *(scriptptr-1); + scriptptr--; + transnum(); + soundvo[k] = *(scriptptr-1); + scriptptr--; + return 0; + + case 4: + if( parsing_actor == 0 ) + { + printf(" * ERROR!(L%d) Found 'enda' without defining 'actor'.\n",line_number); + error++; + } +// else + { + if( num_squigilly_brackets > 0 ) + { + printf(" * ERROR!(L%d) Found more '{' than '}' before 'enda'.\n",line_number); + error++; + } + parsing_actor = 0; + } + + return 0; + case 12: + case 16: + case 84: +// case 21: + case 22: //KILLIT + case 36: + case 38: + case 42: + case 47: + case 61: + case 66: + case 83: + case 95: + case 96: + case 97: + case 104: + case 106: + return 0; + case 60: + j = 0; + while(j < 30) + { + // what a crap, skip GRAVITATIONALCONSTANT, MAXGROWAMMO, QSIZE, + // TRIPBOMBLASERMODE + if(dukever13) + { + switch(j) + { + case 7: + gc = 176; + ++j; + break; + case 24: + max_ammo_amount[11] = 50; + ++j; + break; + case 28: + spriteqamount = 1024; + ++j; + break; + case 29: + lasermode = 0; + ++j; + break; + }; + if(j>27) + continue; + } + + transnum(); + scriptptr--; + + switch(j) + { + case 0: + ud.const_visibility = *scriptptr; + break; + case 1: + impact_damage = *scriptptr; + break; + case 2: + max_player_health = *scriptptr; + break; + case 3: + max_armour_amount = *scriptptr; + break; + case 4: + respawnactortime = *scriptptr;break; + case 5: + respawnitemtime = *scriptptr;break; + case 6: + dukefriction = *scriptptr;break; + case 7: + gc = *scriptptr;break; + case 8:rpgblastradius = *scriptptr;break; + case 9:pipebombblastradius = *scriptptr;break; + case 10:shrinkerblastradius = *scriptptr; break; + case 11:tripbombblastradius = *scriptptr; break; + case 12:morterblastradius = *scriptptr;break; + case 13:bouncemineblastradius = *scriptptr;break; + case 14:seenineblastradius = *scriptptr;break; + + case 15: + case 16: + case 17: + case 18: + case 19: + case 20: + case 21: + case 22: + case 23: + case 24: + if(j == 24) + max_ammo_amount[11] = *scriptptr; + else max_ammo_amount[j-14] = *scriptptr; + break; + case 25: + camerashitable = *scriptptr; + break; + case 26: + numfreezebounces = *scriptptr; + break; + case 27: + freezerhurtowner = *scriptptr; + break; + case 28: + spriteqamount = *scriptptr; + if(spriteqamount > 1024) spriteqamount = 1024; + else if(spriteqamount < 0) spriteqamount = 0; + break; + case 29: + lasermode = *scriptptr; + break; + } + j++; + } + scriptptr++; + return 0; + } + return 0; +} + + +void passone(void) +{ + + while( parsecommand() == 0 ); + + if( (error+warning) > 12) + puts( " * ERROR! Too many warnings or errors."); + +} + +char *defaultcons[3] = +{ + "GAME.CON", + "USER.CON", + "DEFS.CON" +}; + +void copydefaultcons(void) +{ + long i, fs, fpi; + FILE *fpo; + + for(i=0;i<3;i++) + { + fpi = kopen4load( defaultcons[i] , 1 ); + fpo = fopen( defaultcons[i],"wb"); + + if(fpi == 0) + { +// CTW - MODIFICATION +// if(fpo == -1) fclose(fpo); + if(fpo == NULL) fclose(fpo); +// CTW END - MODIFICATION + continue; + } +// CTW - MODIFICATION +// if(fpo == -1) + if(fpo == NULL) +// CTW END - MODIFICATION + { + if(fpi == 0) kclose(fpi); + continue; + } + + fs = kfilelength(fpi); + + kread(fpi,&hittype[0],fs); + fwrite(&hittype[0],fs,1,fpo); + + kclose(fpi); + fclose(fpo); + } +} + +void loadefs(char *filenam,char *mptr) +{ + int i; + long fs,fp; + + if(!SafeFileExists(filenam) && loadfromgrouponly == 0) + { + puts("Missing external con file(s)."); + puts("COPY INTERNAL DEFAULTS TO DIRECTORY(Y/n)?"); + + KB_FlushKeyboardQueue(); + while( KB_KeyWaiting() ); + + i = KB_Getch(); + if(i == 'y' || i == 'Y' ) + { + puts(" Yes"); + copydefaultcons(); + } + } + + fp = kopen4load(filenam,loadfromgrouponly); + if( fp <= 0 ) + { + if( loadfromgrouponly == 1 ) + gameexit("\nMissing con file(s)."); + + loadfromgrouponly = 1; + return; //Not there + } + else + { + printf("Compiling: '%s'.\n",filenam); + + fs = kfilelength(fp); + + last_used_text = textptr = (char *) mptr; + last_used_size = fs; + + kread(fp,(char *)textptr,fs); + kclose(fp); + } + +#ifdef PLATFORM_UNIX + textptr[fs - 1] = 0; +#else + textptr[fs - 2] = 0; +#endif + + clearbuf(actorscrptr,MAXSPRITES,0L); + clearbufbyte(actortype,MAXSPRITES,0L); + + labelcnt = 0; + scriptptr = script+1; + warning = 0; + error = 0; + line_number = 1; + total_lines = 0; + + passone(); //Tokenize + *script = (long) scriptptr; + + if(warning|error) + printf("Found %d warning(s), %d error(s).\n",warning,error); + + if( error == 0 && warning != 0) + { + if( groupfile != -1 && loadfromgrouponly == 0 ) + { + printf("\nWarnings found in %s file. You should backup the original copies before\n",filenam); + puts("before attempting to modify them. Do you want to use the"); + puts("INTERNAL DEFAULTS (y/N)?"); + + KB_FlushKeyboardQueue(); + while( KB_KeyWaiting() ); + i = KB_Getch(); + if(i == 'y' || i == 'Y' ) + { + loadfromgrouponly = 1; + puts(" Yes"); + return; + } + } + } + + if(error) + { + if( loadfromgrouponly ) + { + sprintf(buf,"\nError in %s.",filenam); + gameexit(buf); + } + else + { + if( groupfile != -1 && loadfromgrouponly == 0 ) + { + printf("\nErrors found in %s file. You should backup the original copies\n",filenam); + puts("before attempting to modify them. Do you want to use the"); + puts("internal defaults (Y/N)?"); + + KB_FlushKeyboardQueue(); + while( !KB_KeyWaiting() ); + + i = KB_Getch(); + if( i == 'y' || i == 'Y' ) + { + puts(" Yes"); + loadfromgrouponly = 1; + return; + } + else gameexit(""); + } + } + } + else + { + total_lines += line_number; + printf("Code Size:%ld bytes(%ld labels).\n",(long)((scriptptr-script)<<2)-4,labelcnt); + } +} + +char dodge(spritetype *s) +{ + short i; + long bx,by,mx,my,bxvect,byvect,mxvect,myvect,d; + + mx = s->x; + my = s->y; + mxvect = sintable[(s->ang+512)&2047]; myvect = sintable[s->ang&2047]; + + for(i=headspritestat[4];i>=0;i=nextspritestat[i]) //weapons list + { + if( OW == i || SECT != s->sectnum) + continue; + + bx = SX-mx; + by = SY-my; + bxvect = sintable[(SA+512)&2047]; byvect = sintable[SA&2047]; + + if (mxvect*bx + myvect*by >= 0) + if (bxvect*bx + byvect*by < 0) + { + d = bxvect*by - byvect*bx; + if (klabs(d) < 65536*64) + { + s->ang -= 512+(TRAND&1024); + return 1; + } + } + } + return 0; +} + +short furthestangle(short i,short angs) +{ + short j=0, hitsect=0, hitwall=0,hitspr, furthest_angle=0, angincs=0; + long hx=0l, hy=0l, hz=0l, d=0l, greatestd=0l; + spritetype *s = &sprite[i]; + + greatestd = -(1<<30); + angincs = 2048/angs; + + if(s->picnum != APLAYER) + if( (g_t[0]&63) > 2 ) return( s->ang + 1024 ); + + for(j=s->ang;j<(2048+s->ang);j+=angincs) + { + hitscan(s->x, s->y, s->z-(8<<8), s->sectnum, + sintable[(j+512)&2047], + sintable[j&2047],0, + &hitsect,&hitwall,&hitspr,&hx,&hy,&hz,CLIPMASK1); + + d = klabs(hx-s->x) + klabs(hy-s->y); + + if(d > greatestd) + { + greatestd = d; + furthest_angle = j; + } + } + return (furthest_angle&2047); +} + +short furthestcanseepoint(short i,spritetype *ts,long *dax,long *day) +{ + short j, hitsect,hitwall,hitspr, angincs, tempang; + long hx, hy, hz, d, da;//, d, cd, ca,tempx,tempy,cx,cy; + spritetype *s = &sprite[i]; + + if( (g_t[0]&63) ) return -1; + + if(ud.multimode < 2 && ud.player_skill < 3) + angincs = 2048/2; + else angincs = 2048/(1+(TRAND&1)); + + for(j=ts->ang;j<(2048+ts->ang);j+=(angincs-(TRAND&511))) + { + hitscan(ts->x, ts->y, ts->z-(16<<8), ts->sectnum, + sintable[(j+512)&2047], + sintable[j&2047],16384-(TRAND&32767), + &hitsect,&hitwall,&hitspr,&hx,&hy,&hz,CLIPMASK1); + + d = klabs(hx-ts->x)+klabs(hy-ts->y); + da = klabs(hx-s->x)+klabs(hy-s->y); + + if( d < da ) + if(cansee(hx,hy,hz,hitsect,s->x,s->y,s->z-(16<<8),s->sectnum)) + { + *dax = hx; + *day = hy; + return hitsect; + } + } + return -1; +} + + + + +void alterang(short a) +{ + short aang, angdif, goalang,j; + long ticselapsed, *moveptr; + + moveptr = (long *)g_t[1]; + + ticselapsed = (g_t[0])&31; + + aang = g_sp->ang; + + g_sp->xvel += (*moveptr-g_sp->xvel)/5; + if(g_sp->zvel < 648) g_sp->zvel += ((*(moveptr+1)<<4)-g_sp->zvel)/5; + + if(a&seekplayer) + { + j = ps[g_p].holoduke_on; + + if(j >= 0 && cansee(sprite[j].x,sprite[j].y,sprite[j].z,sprite[j].sectnum,g_sp->x,g_sp->y,g_sp->z,g_sp->sectnum) ) + g_sp->owner = j; + else g_sp->owner = ps[g_p].i; + + if(sprite[g_sp->owner].picnum == APLAYER) + goalang = getangle(hittype[g_i].lastvx-g_sp->x,hittype[g_i].lastvy-g_sp->y); + else + goalang = getangle(sprite[g_sp->owner].x-g_sp->x,sprite[g_sp->owner].y-g_sp->y); + + if(g_sp->xvel && g_sp->picnum != DRONE) + { + angdif = getincangle(aang,goalang); + + if(ticselapsed < 2) + { + if( klabs(angdif) < 256) + { + j = 128-(TRAND&256); + g_sp->ang += j; + if( hits(g_i) < 844 ) + g_sp->ang -= j; + } + } + else if(ticselapsed > 18 && ticselapsed < 26) // choose + { + if(klabs(angdif>>2) < 128) g_sp->ang = goalang; + else g_sp->ang += angdif>>2; + } + } + else g_sp->ang = goalang; + } + + if(ticselapsed < 1) + { + j = 2; + if(a&furthestdir) + { + goalang = furthestangle(g_i,j); + g_sp->ang = goalang; + g_sp->owner = ps[g_p].i; + } + + if(a&fleeenemy) + { + goalang = furthestangle(g_i,j); + g_sp->ang = goalang; // += angdif; // = getincangle(aang,goalang)>>1; + } + } +} + +void move() +{ + long l, *moveptr; + short j, a, goalang, angdif; + long daxvel; + + a = g_sp->hitag; + + if(a == -1) a = 0; + + g_t[0]++; + + if(a&face_player) + { + if(ps[g_p].newowner >= 0) + goalang = getangle(ps[g_p].oposx-g_sp->x,ps[g_p].oposy-g_sp->y); + else goalang = getangle(ps[g_p].posx-g_sp->x,ps[g_p].posy-g_sp->y); + angdif = getincangle(g_sp->ang,goalang)>>2; + if(angdif > -8 && angdif < 0) angdif = 0; + g_sp->ang += angdif; + } + + if(a&spin) + g_sp->ang += sintable[ ((g_t[0]<<3)&2047) ]>>6; + + if(a&face_player_slow) + { + if(ps[g_p].newowner >= 0) + goalang = getangle(ps[g_p].oposx-g_sp->x,ps[g_p].oposy-g_sp->y); + else goalang = getangle(ps[g_p].posx-g_sp->x,ps[g_p].posy-g_sp->y); + angdif = ksgn(getincangle(g_sp->ang,goalang))<<5; + if(angdif > -32 && angdif < 0) + { + angdif = 0; + g_sp->ang = goalang; + } + g_sp->ang += angdif; + } + + + if((a&jumptoplayer) == jumptoplayer) + { + if(g_t[0] < 16) + g_sp->zvel -= (sintable[(512+(g_t[0]<<4))&2047]>>5); + } + + if(a&face_player_smart) + { + long newx,newy; + + newx = ps[g_p].posx+(ps[g_p].posxv/768); + newy = ps[g_p].posy+(ps[g_p].posyv/768); + goalang = getangle(newx-g_sp->x,newy-g_sp->y); + angdif = getincangle(g_sp->ang,goalang)>>2; + if(angdif > -8 && angdif < 0) angdif = 0; + g_sp->ang += angdif; + } + + if( g_t[1] == 0 || a == 0 ) + { + if( ( badguy(g_sp) && g_sp->extra <= 0 ) || (hittype[g_i].bposx != g_sp->x) || (hittype[g_i].bposy != g_sp->y) ) + { + hittype[g_i].bposx = g_sp->x; + hittype[g_i].bposy = g_sp->y; + setsprite(g_i,g_sp->x,g_sp->y,g_sp->z); + } + return; + } + + moveptr = (long *)g_t[1]; + + if(a&geth) g_sp->xvel += (*moveptr-g_sp->xvel)>>1; + if(a&getv) g_sp->zvel += ((*(moveptr+1)<<4)-g_sp->zvel)>>1; + + if(a&dodgebullet) + dodge(g_sp); + + if(g_sp->picnum != APLAYER) + alterang(a); + + if(g_sp->xvel > -6 && g_sp->xvel < 6 ) g_sp->xvel = 0; + + a = badguy(g_sp); + + if(g_sp->xvel || g_sp->zvel) + { + if(a && g_sp->picnum != ROTATEGUN) + { + if( (g_sp->picnum == DRONE || g_sp->picnum == COMMANDER) && g_sp->extra > 0) + { + if(g_sp->picnum == COMMANDER) + { + hittype[g_i].floorz = l = getflorzofslope(g_sp->sectnum,g_sp->x,g_sp->y); + if( g_sp->z > (l-(8<<8)) ) + { + if( g_sp->z > (l-(8<<8)) ) g_sp->z = l-(8<<8); + g_sp->zvel = 0; + } + + hittype[g_i].ceilingz = l = getceilzofslope(g_sp->sectnum,g_sp->x,g_sp->y); + if( (g_sp->z-l) < (80<<8) ) + { + g_sp->z = l+(80<<8); + g_sp->zvel = 0; + } + } + else + { + if( g_sp->zvel > 0 ) + { + hittype[g_i].floorz = l = getflorzofslope(g_sp->sectnum,g_sp->x,g_sp->y); + if( g_sp->z > (l-(30<<8)) ) + g_sp->z = l-(30<<8); + } + else + { + hittype[g_i].ceilingz = l = getceilzofslope(g_sp->sectnum,g_sp->x,g_sp->y); + if( (g_sp->z-l) < (50<<8) ) + { + g_sp->z = l+(50<<8); + g_sp->zvel = 0; + } + } + } + } + else if(g_sp->picnum != ORGANTIC) + { + if(g_sp->zvel > 0 && hittype[g_i].floorz < g_sp->z) + g_sp->z = hittype[g_i].floorz; + if( g_sp->zvel < 0) + { + l = getceilzofslope(g_sp->sectnum,g_sp->x,g_sp->y); + if( (g_sp->z-l) < (66<<8) ) + { + g_sp->z = l+(66<<8); + g_sp->zvel >>= 1; + } + } + } + } + else if(g_sp->picnum == APLAYER) + if( (g_sp->z-hittype[g_i].ceilingz) < (32<<8) ) + g_sp->z = hittype[g_i].ceilingz+(32<<8); + + daxvel = g_sp->xvel; + angdif = g_sp->ang; + + if( a && g_sp->picnum != ROTATEGUN ) + { + if( g_x < 960 && g_sp->xrepeat > 16 ) + { + + daxvel = -(1024-g_x); + angdif = getangle(ps[g_p].posx-g_sp->x,ps[g_p].posy-g_sp->y); + + if(g_x < 512) + { + ps[g_p].posxv = 0; + ps[g_p].posyv = 0; + } + else + { + ps[g_p].posxv = mulscale(ps[g_p].posxv,dukefriction-0x2000,16); + ps[g_p].posyv = mulscale(ps[g_p].posyv,dukefriction-0x2000,16); + } + } + else if(g_sp->picnum != DRONE && g_sp->picnum != SHARK && g_sp->picnum != COMMANDER) + { + if( hittype[g_i].bposz != g_sp->z || ( ud.multimode < 2 && ud.player_skill < 2 ) ) + { + if( (g_t[0]&1) || ps[g_p].actorsqu == g_i ) return; + else daxvel <<= 1; + } + else + { + if( (g_t[0]&3) || ps[g_p].actorsqu == g_i ) return; + else daxvel <<= 2; + } + } + } + + hittype[g_i].movflag = movesprite(g_i, + (daxvel*(sintable[(angdif+512)&2047]))>>14, + (daxvel*(sintable[angdif&2047]))>>14,g_sp->zvel,CLIPMASK0); + } + + if( a ) + { + if (sector[g_sp->sectnum].ceilingstat&1) + g_sp->shade += (sector[g_sp->sectnum].ceilingshade-g_sp->shade)>>1; + else g_sp->shade += (sector[g_sp->sectnum].floorshade-g_sp->shade)>>1; + + if( sector[g_sp->sectnum].floorpicnum == MIRROR ) + deletesprite(g_i); + } +} + +char parse(void); + +void parseifelse(long condition) +{ + if( condition ) + { + insptr+=2; + parse(); + } + else + { + insptr = (long *) *(insptr+1); + if(*insptr == 10) + { + insptr+=2; + parse(); + } + } +} + +// long *it = 0x00589a04; + +char parse(void) +{ + long j, l, s; + + if(killit_flag) return 1; + +// if(*it == 1668249134L) gameexit("\nERR"); + + switch(*insptr) + { + case 3: + insptr++; + parseifelse( rnd(*insptr)); + break; + case 45: + + if(g_x > 1024) + { + short temphit, sclip, angdif; + + if( badguy(g_sp) && g_sp->xrepeat > 56 ) + { + sclip = 3084; + angdif = 48; + } + else + { + sclip = 768; + angdif = 16; + } + + j = hitasprite(g_i,&temphit); + if(j == (1<<30)) + { + parseifelse(1); + break; + } + if(j > sclip) + { + if(temphit >= 0 && sprite[temphit].picnum == g_sp->picnum) + j = 0; + else + { + g_sp->ang += angdif;j = hitasprite(g_i,&temphit);g_sp->ang -= angdif; + if(j > sclip) + { + if(temphit >= 0 && sprite[temphit].picnum == g_sp->picnum) + j = 0; + else + { + g_sp->ang -= angdif;j = hitasprite(g_i,&temphit);g_sp->ang += angdif; + if( j > 768 ) + { + if(temphit >= 0 && sprite[temphit].picnum == g_sp->picnum) + j = 0; + else j = 1; + } + else j = 0; + } + } + else j = 0; + } + } + else j = 0; + } + else j = 1; + + parseifelse(j); + break; + case 91: + j = cansee(g_sp->x,g_sp->y,g_sp->z-((TRAND&41)<<8),g_sp->sectnum,ps[g_p].posx,ps[g_p].posy,ps[g_p].posz/*-((TRAND&41)<<8)*/,sprite[ps[g_p].i].sectnum); + parseifelse(j); + if( j ) hittype[g_i].timetosleep = SLEEPTIME; + break; + + case 49: + parseifelse(hittype[g_i].actorstayput == -1); + break; + case 5: + { + spritetype *s; + short sect; + + if(ps[g_p].holoduke_on >= 0) + { + s = &sprite[ps[g_p].holoduke_on]; + j = cansee(g_sp->x,g_sp->y,g_sp->z-(TRAND&((32<<8)-1)),g_sp->sectnum, + s->x,s->y,s->z,s->sectnum); + if(j == 0) + s = &sprite[ps[g_p].i]; + } + else s = &sprite[ps[g_p].i]; + + j = cansee(g_sp->x,g_sp->y,g_sp->z-(TRAND&((47<<8))),g_sp->sectnum, + s->x,s->y,s->z-(24<<8),s->sectnum); + + if(j == 0) + { + if( ( klabs(hittype[g_i].lastvx-g_sp->x)+klabs(hittype[g_i].lastvy-g_sp->y) ) < + ( klabs(hittype[g_i].lastvx-s->x)+klabs(hittype[g_i].lastvy-s->y) ) ) + j = 0; + + if( j == 0 ) + { + j = furthestcanseepoint(g_i,s,&hittype[g_i].lastvx,&hittype[g_i].lastvy); + + if(j == -1) j = 0; + else j = 1; + } + } + else + { + hittype[g_i].lastvx = s->x; + hittype[g_i].lastvy = s->y; + } + + if( j == 1 && ( g_sp->statnum == 1 || g_sp->statnum == 6 ) ) + hittype[g_i].timetosleep = SLEEPTIME; + + parseifelse(j == 1); + break; + } + + case 6: + parseifelse(ifhitbyweapon(g_i) >= 0); + break; + case 27: + parseifelse( ifsquished(g_i, g_p) == 1); + break; + case 26: + { + j = g_sp->extra; + if(g_sp->picnum == APLAYER) + j--; + parseifelse(j < 0); + } + break; + case 24: + insptr++; + g_t[5] = *insptr; + g_t[4] = *(long *)(g_t[5]); // Action + g_t[1] = *(long *)(g_t[5]+4); // move + g_sp->hitag = *(long *)(g_t[5]+8); // Ai + g_t[0] = g_t[2] = g_t[3] = 0; + if(g_sp->hitag&random_angle) + g_sp->ang = TRAND&2047; + insptr++; + break; + case 7: + insptr++; + g_t[2] = 0; + g_t[3] = 0; + g_t[4] = *insptr; + insptr++; + break; + + case 8: + insptr++; + parseifelse(g_x < *insptr); + if(g_x > MAXSLEEPDIST && hittype[g_i].timetosleep == 0) + hittype[g_i].timetosleep = SLEEPTIME; + break; + case 9: + insptr++; + parseifelse(g_x > *insptr); + if(g_x > MAXSLEEPDIST && hittype[g_i].timetosleep == 0) + hittype[g_i].timetosleep = SLEEPTIME; + break; + case 10: + insptr = (long *) *(insptr+1); + break; + case 100: + insptr++; + g_sp->extra += *insptr; + insptr++; + break; + case 11: + insptr++; + g_sp->extra = *insptr; + insptr++; + break; + case 94: + insptr++; + + if(ud.coop >= 1 && ud.multimode > 1) + { + if(*insptr == 0) + { + for(j=0;j < ps[g_p].weapreccnt;j++) + if( ps[g_p].weaprecs[j] == g_sp->picnum ) + break; + + parseifelse(j < ps[g_p].weapreccnt && g_sp->owner == g_i); + } + else if(ps[g_p].weapreccnt < 16) + { + ps[g_p].weaprecs[ps[g_p].weapreccnt++] = g_sp->picnum; + parseifelse(g_sp->owner == g_i); + } + } + else parseifelse(0); + break; + case 95: + insptr++; + if(g_sp->picnum == APLAYER) + g_sp->pal = ps[g_sp->yvel].palookup; + else g_sp->pal = hittype[g_i].tempang; + hittype[g_i].tempang = 0; + break; + case 104: + insptr++; + checkweapons(&ps[g_sp->yvel]); + break; + case 106: + insptr++; + break; + case 97: + insptr++; + if(Sound[g_sp->yvel].num == 0) + spritesound(g_sp->yvel,g_i); + break; + case 96: + insptr++; + + if( ud.multimode > 1 && g_sp->picnum == APLAYER ) + { + if(ps[otherp].quick_kick == 0) + ps[otherp].quick_kick = 14; + } + else if(g_sp->picnum != APLAYER && ps[g_p].quick_kick == 0) + ps[g_p].quick_kick = 14; + break; + case 28: + insptr++; + + j = ((*insptr)-g_sp->xrepeat)<<1; + g_sp->xrepeat += ksgn(j); + + insptr++; + + if( ( g_sp->picnum == APLAYER && g_sp->yrepeat < 36 ) || *insptr < g_sp->yrepeat || ((g_sp->yrepeat*(tilesizy[g_sp->picnum]+8))<<2) < (hittype[g_i].floorz - hittype[g_i].ceilingz) ) + { + j = ((*insptr)-g_sp->yrepeat)<<1; + if( klabs(j) ) g_sp->yrepeat += ksgn(j); + } + + insptr++; + + break; + case 99: + insptr++; + g_sp->xrepeat = (char) *insptr; + insptr++; + g_sp->yrepeat = (char) *insptr; + insptr++; + break; + case 13: + insptr++; + shoot(g_i,(short)*insptr); + insptr++; + break; + case 87: + insptr++; + if( Sound[*insptr].num == 0 ) + spritesound((short) *insptr,g_i); + insptr++; + break; + case 89: + insptr++; + if( Sound[*insptr].num > 0 ) + stopsound((short)*insptr); + insptr++; + break; + case 92: + insptr++; + if(g_p == screenpeek || ud.coop==1) + spritesound((short) *insptr,ps[screenpeek].i); + insptr++; + break; + case 15: + insptr++; + spritesound((short) *insptr,g_i); + insptr++; + break; + case 84: + insptr++; + ps[g_p].tipincs = 26; + break; + case 16: + insptr++; + g_sp->xoffset = 0; + g_sp->yoffset = 0; +// if(!gotz) + { + long c; + + if( floorspace(g_sp->sectnum) ) + c = 0; + else + { + if( ceilingspace(g_sp->sectnum) || sector[g_sp->sectnum].lotag == 2) + c = gc/6; + else c = gc; + } + + if( hittype[g_i].cgg <= 0 || (sector[g_sp->sectnum].floorstat&2) ) + { + getglobalz(g_i); + hittype[g_i].cgg = 6; + } + else hittype[g_i].cgg --; + + if( g_sp->z < (hittype[g_i].floorz-FOURSLEIGHT) ) + { + g_sp->zvel += c; + g_sp->z+=g_sp->zvel; + + if(g_sp->zvel > 6144) g_sp->zvel = 6144; + } + else + { + g_sp->z = hittype[g_i].floorz - FOURSLEIGHT; + + if( badguy(g_sp) || ( g_sp->picnum == APLAYER && g_sp->owner >= 0) ) + { + + if( g_sp->zvel > 3084 && g_sp->extra <= 1) + { + if(g_sp->pal != 1 && g_sp->picnum != DRONE) + { + if(g_sp->picnum == APLAYER && g_sp->extra > 0) + goto SKIPJIBS; + guts(g_sp,JIBS6,15,g_p); + spritesound(SQUISHED,g_i); + spawn(g_i,BLOODPOOL); + } + + SKIPJIBS: + + hittype[g_i].picnum = SHOTSPARK1; + hittype[g_i].extra = 1; + g_sp->zvel = 0; + } + else if(g_sp->zvel > 2048 && sector[g_sp->sectnum].lotag != 1) + { + j = g_sp->sectnum; +// pushmove(&g_sp->x,&g_sp->y,&g_sp->z,&j,128L,(4L<<8),(4L<<8),CLIPMASK0); + pushmove(&g_sp->x, &g_sp->y, &g_sp->z,(short *)&j,128L,(4L<<8),(4L<<8),CLIPMASK0); + if(j != g_sp->sectnum && j >= 0 && j < MAXSECTORS) + changespritesect(g_i,j); + + spritesound(THUD,g_i); + } + } + if(sector[g_sp->sectnum].lotag == 1) + switch (g_sp->picnum) + { + case OCTABRAIN: + case COMMANDER: + case DRONE: + break; + default: + g_sp->z += (24<<8); + break; + } + else g_sp->zvel = 0; + } + } + + break; + case 4: + case 12: + case 18: + return 1; + case 30: + insptr++; + return 1; + case 2: + insptr++; + if( ps[g_p].ammo_amount[*insptr] >= max_ammo_amount[*insptr] ) + { + killit_flag = 2; + break; + } + addammo( *insptr, &ps[g_p], *(insptr+1) ); + if(ps[g_p].curr_weapon == KNEE_WEAPON) + if( ps[g_p].gotweapon[*insptr] ) + addweapon( &ps[g_p], *insptr ); + insptr += 2; + break; + case 86: + insptr++; + lotsofmoney(g_sp,*insptr); + insptr++; + break; + case 102: + insptr++; + lotsofmail(g_sp,*insptr); + insptr++; + break; + case 105: + insptr++; + hittype[g_i].timetosleep = (short)*insptr; + insptr++; + break; + case 103: + insptr++; + lotsofpaper(g_sp,*insptr); + insptr++; + break; + case 88: + insptr++; + ps[g_p].actors_killed += *insptr; + hittype[g_i].actorstayput = -1; + insptr++; + break; + case 93: + insptr++; + spriteglass(g_i,*insptr); + insptr++; + break; + case 22: + insptr++; + killit_flag = 1; + break; + case 23: + insptr++; + if( ps[g_p].gotweapon[*insptr] == 0 ) addweapon( &ps[g_p], *insptr ); + else if( ps[g_p].ammo_amount[*insptr] >= max_ammo_amount[*insptr] ) + { + killit_flag = 2; + break; + } + addammo( *insptr, &ps[g_p], *(insptr+1) ); + if(ps[g_p].curr_weapon == KNEE_WEAPON) + if( ps[g_p].gotweapon[*insptr] ) + addweapon( &ps[g_p], *insptr ); + insptr+=2; + break; + case 68: + insptr++; + printf("%ld\n",*insptr); + insptr++; + break; + case 69: + insptr++; + ps[g_p].timebeforeexit = *insptr; + ps[g_p].customexitsound = -1; + ud.eog = 1; + insptr++; + break; + case 25: + insptr++; + + if(ps[g_p].newowner >= 0) + { + ps[g_p].newowner = -1; + ps[g_p].posx = ps[g_p].oposx; + ps[g_p].posy = ps[g_p].oposy; + ps[g_p].posz = ps[g_p].oposz; + ps[g_p].ang = ps[g_p].oang; + updatesector(ps[g_p].posx,ps[g_p].posy,&ps[g_p].cursectnum); + setpal(&ps[g_p]); + + j = headspritestat[1]; + while(j >= 0) + { + if(sprite[j].picnum==CAMERA1) + sprite[j].yvel = 0; + j = nextspritestat[j]; + } + } + + j = sprite[ps[g_p].i].extra; + + if(g_sp->picnum != ATOMICHEALTH) + { + if( j > max_player_health && *insptr > 0 ) + { + insptr++; + break; + } + else + { + if(j > 0) + j += *insptr; + if ( j > max_player_health && *insptr > 0 ) + j = max_player_health; + } + } + else + { + if( j > 0 ) + j += *insptr; + if ( j > (max_player_health<<1) ) + j = (max_player_health<<1); + } + + if(j < 0) j = 0; + + if(ud.god == 0) + { + if(*insptr > 0) + { + if( ( j - *insptr ) < (max_player_health>>2) && + j >= (max_player_health>>2) ) + spritesound(DUKE_GOTHEALTHATLOW,ps[g_p].i); + + ps[g_p].last_extra = j; + } + + sprite[ps[g_p].i].extra = j; + } + + insptr++; + break; + case 17: + { + long *tempscrptr; + + tempscrptr = insptr+2; + + insptr = (long *) *(insptr+1); + while(1) if(parse()) break; + insptr = tempscrptr; + } + break; + case 29: + insptr++; + while(1) if(parse()) break; + break; + case 32: + g_t[0]=0; + insptr++; + g_t[1] = *insptr; + insptr++; + g_sp->hitag = *insptr; + insptr++; + if(g_sp->hitag&random_angle) + g_sp->ang = TRAND&2047; + break; + case 31: + insptr++; + if(g_sp->sectnum >= 0 && g_sp->sectnum < MAXSECTORS) + spawn(g_i,*insptr); + insptr++; + break; + case 33: + insptr++; + parseifelse( hittype[g_i].picnum == *insptr); + break; + case 21: + insptr++; + parseifelse(g_t[5] == *insptr); + break; + case 34: + insptr++; + parseifelse(g_t[4] == *insptr); + break; + case 35: + insptr++; + parseifelse(g_t[2] >= *insptr); + break; + case 36: + insptr++; + g_t[2] = 0; + break; + case 37: + { + short dnum; + + insptr++; + dnum = *insptr; + insptr++; + + if(g_sp->sectnum >= 0 && g_sp->sectnum < MAXSECTORS) + for(j=(*insptr)-1;j>=0;j--) + { + if(g_sp->picnum == BLIMP && dnum == SCRAP1) + s = 0; + else s = (TRAND%3); + + l = EGS(g_sp->sectnum, + g_sp->x+(TRAND&255)-128,g_sp->y+(TRAND&255)-128,g_sp->z-(8<<8)-(TRAND&8191), + dnum+s,g_sp->shade,32+(TRAND&15),32+(TRAND&15), + TRAND&2047,(TRAND&127)+32, + -(TRAND&2047),g_i,5); + if(g_sp->picnum == BLIMP && dnum == SCRAP1) + sprite[l].yvel = weaponsandammosprites[j%14]; + else sprite[l].yvel = -1; + sprite[l].pal = g_sp->pal; + } + insptr++; + } + break; + case 52: + insptr++; + g_t[0] = (short) *insptr; + insptr++; + break; + case 101: + insptr++; + g_sp->cstat |= (short)*insptr; + insptr++; + break; + case 110: + insptr++; + g_sp->clipdist = (short) *insptr; + insptr++; + break; + case 40: + insptr++; + g_sp->cstat = (short) *insptr; + insptr++; + break; + case 41: + insptr++; + parseifelse(g_t[1] == *insptr); + break; + case 42: + insptr++; + + if(ud.multimode < 2) + { + if( lastsavedpos >= 0 && ud.recstat != 2 ) + { + ps[g_p].gm = MODE_MENU; + KB_ClearKeyDown(sc_Space); + cmenu(15000); + } + else ps[g_p].gm = MODE_RESTART; + killit_flag = 2; + } + else + { + pickrandomspot(g_p); + g_sp->x = hittype[g_i].bposx = ps[g_p].bobposx = ps[g_p].oposx = ps[g_p].posx; + g_sp->y = hittype[g_i].bposy = ps[g_p].bobposy = ps[g_p].oposy =ps[g_p].posy; + g_sp->z = hittype[g_i].bposy = ps[g_p].oposz =ps[g_p].posz; + updatesector(ps[g_p].posx,ps[g_p].posy,&ps[g_p].cursectnum); + setsprite(ps[g_p].i,ps[g_p].posx,ps[g_p].posy,ps[g_p].posz+PHEIGHT); + g_sp->cstat = 257; + + g_sp->shade = -12; + g_sp->clipdist = 64; + g_sp->xrepeat = 42; + g_sp->yrepeat = 36; + g_sp->owner = g_i; + g_sp->xoffset = 0; + g_sp->pal = ps[g_p].palookup; + + ps[g_p].last_extra = g_sp->extra = max_player_health; + ps[g_p].wantweaponfire = -1; + ps[g_p].horiz = 100; + ps[g_p].on_crane = -1; + ps[g_p].frag_ps = g_p; + ps[g_p].horizoff = 0; + ps[g_p].opyoff = 0; + ps[g_p].wackedbyactor = -1; + ps[g_p].shield_amount = max_armour_amount; + ps[g_p].dead_flag = 0; + ps[g_p].pals_time = 0; + ps[g_p].footprintcount = 0; + ps[g_p].weapreccnt = 0; + ps[g_p].fta = 0; + ps[g_p].ftq = 0; + ps[g_p].posxv = ps[g_p].posyv = 0; + ps[g_p].rotscrnang = 0; + + ps[g_p].falling_counter = 0; + + hittype[g_i].extra = -1; + hittype[g_i].owner = g_i; + + hittype[g_i].cgg = 0; + hittype[g_i].movflag = 0; + hittype[g_i].tempang = 0; + hittype[g_i].actorstayput = -1; + hittype[g_i].dispicnum = 0; + hittype[g_i].owner = ps[g_p].i; + + resetinventory(g_p); + resetweapons(g_p); + + cameradist = 0; + cameraclock = totalclock; + } + setpal(&ps[g_p]); + + break; + case 43: + parseifelse( klabs(g_sp->z-sector[g_sp->sectnum].floorz) < (32<<8) && sector[g_sp->sectnum].lotag == 1); + break; + case 44: + parseifelse( sector[g_sp->sectnum].lotag == 2); + break; + case 46: + insptr++; + parseifelse(g_t[0] >= *insptr); + break; + case 53: + insptr++; + parseifelse(g_sp->picnum == *insptr); + break; + case 47: + insptr++; + g_t[0] = 0; + break; + case 48: + insptr+=2; + switch(*(insptr-1)) + { + case 0: + ps[g_p].steroids_amount = *insptr; + ps[g_p].inven_icon = 2; + break; + case 1: + ps[g_p].shield_amount += *insptr;// 100; + if(ps[g_p].shield_amount > max_player_health) + ps[g_p].shield_amount = max_player_health; + break; + case 2: + ps[g_p].scuba_amount = *insptr;// 1600; + ps[g_p].inven_icon = 6; + break; + case 3: + ps[g_p].holoduke_amount = *insptr;// 1600; + ps[g_p].inven_icon = 3; + break; + case 4: + ps[g_p].jetpack_amount = *insptr;// 1600; + ps[g_p].inven_icon = 4; + break; + case 6: + switch(g_sp->pal) + { + case 0: ps[g_p].got_access |= 1;break; + case 21: ps[g_p].got_access |= 2;break; + case 23: ps[g_p].got_access |= 4;break; + } + break; + case 7: + ps[g_p].heat_amount = *insptr; + ps[g_p].inven_icon = 5; + break; + case 9: + ps[g_p].inven_icon = 1; + ps[g_p].firstaid_amount = *insptr; + break; + case 10: + ps[g_p].inven_icon = 7; + ps[g_p].boot_amount = *insptr; + break; + } + insptr++; + break; + case 50: + hitradius(g_i,*(insptr+1),*(insptr+2),*(insptr+3),*(insptr+4),*(insptr+5)); + insptr+=6; + break; + case 51: + { + insptr++; + + l = *insptr; + j = 0; + + s = g_sp->xvel; + + if( (l&8) && ps[g_p].on_ground && (sync[g_p].bits&2) ) + j = 1; + else if( (l&16) && ps[g_p].jumping_counter == 0 && !ps[g_p].on_ground && + ps[g_p].poszv > 2048 ) + j = 1; + else if( (l&32) && ps[g_p].jumping_counter > 348 ) + j = 1; + else if( (l&1) && s >= 0 && s < 8) + j = 1; + else if( (l&2) && s >= 8 && !(sync[g_p].bits&(1<<5)) ) + j = 1; + else if( (l&4) && s >= 8 && sync[g_p].bits&(1<<5) ) + j = 1; + else if( (l&64) && ps[g_p].posz < (g_sp->z-(48<<8)) ) + j = 1; + else if( (l&128) && s <= -8 && !(sync[g_p].bits&(1<<5)) ) + j = 1; + else if( (l&256) && s <= -8 && (sync[g_p].bits&(1<<5)) ) + j = 1; + else if( (l&512) && ( ps[g_p].quick_kick > 0 || ( ps[g_p].curr_weapon == KNEE_WEAPON && ps[g_p].kickback_pic > 0 ) ) ) + j = 1; + else if( (l&1024) && sprite[ps[g_p].i].xrepeat < 32 ) + j = 1; + else if( (l&2048) && ps[g_p].jetpack_on ) + j = 1; + else if( (l&4096) && ps[g_p].steroids_amount > 0 && ps[g_p].steroids_amount < 400 ) + j = 1; + else if( (l&8192) && ps[g_p].on_ground) + j = 1; + else if( (l&16384) && sprite[ps[g_p].i].xrepeat > 32 && sprite[ps[g_p].i].extra > 0 && ps[g_p].timebeforeexit == 0 ) + j = 1; + else if( (l&32768) && sprite[ps[g_p].i].extra <= 0) + j = 1; + else if( (l&65536L) ) + { + if(g_sp->picnum == APLAYER && ud.multimode > 1) + j = getincangle(ps[otherp].ang,getangle(ps[g_p].posx-ps[otherp].posx,ps[g_p].posy-ps[otherp].posy)); + else + j = getincangle(ps[g_p].ang,getangle(g_sp->x-ps[g_p].posx,g_sp->y-ps[g_p].posy)); + + if( j > -128 && j < 128 ) + j = 1; + else + j = 0; + } + + parseifelse((long) j); + + } + break; + case 56: + insptr++; + parseifelse(g_sp->extra <= *insptr); + break; + case 58: + insptr += 2; + guts(g_sp,*(insptr-1),*insptr,g_p); + insptr++; + break; + case 59: + insptr++; +// if(g_sp->owner >= 0 && sprite[g_sp->owner].picnum == *insptr) + // parseifelse(1); +// else + parseifelse( hittype[g_i].picnum == *insptr); + break; + case 61: + insptr++; + forceplayerangle(&ps[g_p]); + return 0; + case 62: + insptr++; + parseifelse( (( hittype[g_i].floorz - hittype[g_i].ceilingz ) >> 8 ) < *insptr); + break; + case 63: // "ifhitspace" in confiles. --ryan. + // this line is actually checking if the key assigned + // to "OPEN" is pressed, but it may not be space. + parseifelse( sync[g_p].bits&(1<<29)); + break; + case 64: + parseifelse(sector[g_sp->sectnum].ceilingstat&1); + break; + case 65: + parseifelse(ud.multimode > 1); + break; + case 66: + insptr++; + if( sector[g_sp->sectnum].lotag == 0 ) + { + neartag(g_sp->x,g_sp->y,g_sp->z-(32<<8),g_sp->sectnum,g_sp->ang,&neartagsector,&neartagwall,&neartagsprite,&neartaghitdist,768L,1); + if( neartagsector >= 0 && isanearoperator(sector[neartagsector].lotag) ) + if( (sector[neartagsector].lotag&0xff) == 23 || sector[neartagsector].floorz == sector[neartagsector].ceilingz ) + if( (sector[neartagsector].lotag&16384) == 0 ) + if( (sector[neartagsector].lotag&32768) == 0 ) + { + j = headspritesect[neartagsector]; + while(j >= 0) + { + if(sprite[j].picnum == ACTIVATOR) + break; + j = nextspritesect[j]; + } + if(j == -1) + operatesectors(neartagsector,g_i); + } + } + break; + case 67: + parseifelse(ceilingspace(g_sp->sectnum)); + break; + + case 74: + insptr++; + if(g_sp->picnum != APLAYER) + hittype[g_i].tempang = g_sp->pal; + g_sp->pal = *insptr; + insptr++; + break; + + case 77: + insptr++; + g_sp->picnum = *insptr; + insptr++; + break; + + case 70: + parseifelse( dodge(g_sp) == 1); + break; + case 71: + if( badguy(g_sp) ) + parseifelse( ud.respawn_monsters ); + else if( inventory(g_sp) ) + parseifelse( ud.respawn_inventory ); + else + parseifelse( ud.respawn_items ); + break; + case 72: + insptr++; +// getglobalz(g_i); + parseifelse( (hittype[g_i].floorz - g_sp->z) <= ((*insptr)<<8)); + break; + case 73: + insptr++; +// getglobalz(g_i); + parseifelse( ( g_sp->z - hittype[g_i].ceilingz ) <= ((*insptr)<<8)); + break; + case 14: + + insptr++; + ps[g_p].pals_time = *insptr; + insptr++; + for(j=0;j<3;j++) + { + ps[g_p].pals[j] = *insptr; + insptr++; + } + break; + +/* case 74: + insptr++; + getglobalz(g_i); + parseifelse( (( hittype[g_i].floorz - hittype[g_i].ceilingz ) >> 8 ) >= *insptr); + break; +*/ + case 78: + insptr++; + parseifelse( sprite[ps[g_p].i].extra < *insptr); + break; + + case 75: + { + insptr++; + j = 0; + switch(*(insptr++)) + { + case 0:if( ps[g_p].steroids_amount != *insptr) + j = 1; + break; + case 1:if(ps[g_p].shield_amount != max_player_health ) + j = 1; + break; + case 2:if(ps[g_p].scuba_amount != *insptr) j = 1;break; + case 3:if(ps[g_p].holoduke_amount != *insptr) j = 1;break; + case 4:if(ps[g_p].jetpack_amount != *insptr) j = 1;break; + case 6: + switch(g_sp->pal) + { + case 0: if(ps[g_p].got_access&1) j = 1;break; + case 21: if(ps[g_p].got_access&2) j = 1;break; + case 23: if(ps[g_p].got_access&4) j = 1;break; + } + break; + case 7:if(ps[g_p].heat_amount != *insptr) j = 1;break; + case 9: + if(ps[g_p].firstaid_amount != *insptr) j = 1;break; + case 10: + if(ps[g_p].boot_amount != *insptr) j = 1;break; + } + + parseifelse(j); + break; + } + case 38: + insptr++; + if( ps[g_p].knee_incs == 0 && sprite[ps[g_p].i].xrepeat >= 40 ) + if( cansee(g_sp->x,g_sp->y,g_sp->z-(4<<8),g_sp->sectnum,ps[g_p].posx,ps[g_p].posy,ps[g_p].posz+(16<<8),sprite[ps[g_p].i].sectnum) ) + { + ps[g_p].knee_incs = 1; + if(ps[g_p].weapon_pos == 0) + ps[g_p].weapon_pos = -1; + ps[g_p].actorsqu = g_i; + } + break; + case 90: + { + short s1; + + s1 = g_sp->sectnum; + + j = 0; + + updatesector(g_sp->x+108,g_sp->y+108,&s1); + if( s1 == g_sp->sectnum ) + { + updatesector(g_sp->x-108,g_sp->y-108,&s1); + if( s1 == g_sp->sectnum ) + { + updatesector(g_sp->x+108,g_sp->y-108,&s1); + if( s1 == g_sp->sectnum ) + { + updatesector(g_sp->x-108,g_sp->y+108,&s1); + if( s1 == g_sp->sectnum ) + j = 1; + } + } + } + parseifelse( j ); + } + + break; + case 80: + insptr++; + FTA(*insptr,&ps[g_p]); + insptr++; + break; + case 81: + parseifelse( floorspace(g_sp->sectnum)); + break; + case 82: + parseifelse( (hittype[g_i].movflag&49152) > 16384 ); + break; + case 83: + insptr++; + switch(g_sp->picnum) + { + case FEM1: + case FEM2: + case FEM3: + case FEM4: + case FEM5: + case FEM6: + case FEM7: + case FEM8: + case FEM9: + case FEM10: + case PODFEM1: + case NAKED1: + case STATUE: + if(g_sp->yvel) operaterespawns(g_sp->yvel); + break; + default: + if(g_sp->hitag >= 0) operaterespawns(g_sp->hitag); + break; + } + break; + case 85: + insptr++; + parseifelse( g_sp->pal == *insptr); + break; + + case 111: + insptr++; + j = klabs(getincangle(ps[g_p].ang,g_sp->ang)); + parseifelse( j <= *insptr); + break; + + case 109: + + for(j=1;jpicnum] == 0 ) return; + + insptr = 4 + (actorscrptr[g_sp->picnum]); + + killit_flag = 0; + + if(g_sp->sectnum < 0 || g_sp->sectnum >= MAXSECTORS) + { + if(badguy(g_sp)) + ps[g_p].actors_killed++; + deletesprite(g_i); + return; + } + + if(g_t[4]) + { + g_sp->lotag += TICSPERFRAME; + if(g_sp->lotag > *(long *)(g_t[4]+16) ) + { + g_t[2]++; + g_sp->lotag = 0; + g_t[3] += *(long *)( g_t[4]+12 ); + } + if( klabs(g_t[3]) >= klabs( *(long *)(g_t[4]+4) * *(long *)(g_t[4]+12) ) ) + g_t[3] = 0; + } + + do + done = parse(); + while( done == 0 ); + + if(killit_flag == 1) + { + if(ps[g_p].actorsqu == g_i) + ps[g_p].actorsqu = -1; + deletesprite(g_i); + } + else + { + move(); + + if( g_sp->statnum == 1) + { + if( badguy(g_sp) ) + { + if( g_sp->xrepeat > 60 ) return; + if( ud.respawn_monsters == 1 && g_sp->extra <= 0 ) return; + } + else if( ud.respawn_items == 1 && (g_sp->cstat&32768) ) return; + + if(hittype[g_i].timetosleep > 1) + hittype[g_i].timetosleep--; + else if(hittype[g_i].timetosleep == 1) + changespritestat(g_i,2); + } + + else if(g_sp->statnum == 6) + switch(g_sp->picnum) + { + case RUBBERCAN: + case EXPLODINGBARREL: + case WOODENHORSE: + case HORSEONSIDE: + case CANWITHSOMETHING: + case FIREBARREL: + case NUKEBARREL: + case NUKEBARRELDENTED: + case NUKEBARRELLEAKED: + case TRIPBOMB: + case EGG: + if(hittype[g_i].timetosleep > 1) + hittype[g_i].timetosleep--; + else if(hittype[g_i].timetosleep == 1) + changespritestat(g_i,2); + break; + } + } +} + + + + + +// "Duke 2000" +// "Virchua Duke" +// "Son of Death +// "Cromium" +// "Potent" +// "Flotsom" + +// Volume One +// "Duke is brain dead", +// "BOOT TO THE HEAD" +// Damage too duke +// Weapons are computer cont. Only logical thinking +// is disappearing. +// " Flips! " +// Flash on screen, inst. +// "BUMS" +// "JAIL"/"MENTAL WARD (Cop code for looney? T. asks Cop.)" +// "GUTS OR GLORY" + +// ( Duke's Mission + +// Duke: "Looks like some kind of transporter...?" +// Byte: "...YES" + +// Duke: "Waa, here goes nuthin'. " +// (Duke puts r. arm in device) + +// Duke: AAAAHHHHHHHHHHHHHHHHHHHHHHHHH!!! +// (Duke's arm is seved.) +// Byte: NO.NO.NO.NO.NO.NO.NO... +// ( Byte directs duke to the nearest heat source) +// (Shut Up Mode) +// ( Duke Staggers, end of arm bleeding, usual oozing arm guts. ) +// Byte: Left, Left, Left, Left, Right. +// ( Duke, loozing consc, trips on broken pipe, ) +// ( hits temple on edge of step. ) +// ( Rats everywhere, byte pushing them away with weapon, +// ( eventually covered, show usual groosums, Duke appears dead +// ( Duke wakes up, in hospital, vision less blurry +// ( Hospital doing brain scan, 1/3 cran. mass MISSING! +// Doc: Hummm? ( Grabbing upper lip to "appear" smart. ) + +// Stand back boys + +// Schrapnel has busted my scull! +// Now I'm insane, Mental ward, got to escape. +// Search light everywhere. + +// (M)Mendor, The Tree Dweller. +// (M)BashMan, The Destructor. +// (M)Lash, The Scavenger. +// (F)Mag, The Slut. +// (F) +// NRA OR SOMETHIN' + +// Duke Nukem +// 5th Dimention +// Pentagon Man! + + +// I Hope your not stupid! +// The 70's meet the future. +// Dirty Harry style. 70's music with futuristic edge +// The Instant De-Welder(tm) +// I think I'm going to puke... +// Badge attitude. +// He's got a Badge(LA 3322), a Bulldog, a Bronco (beat up/bondoed). +// Gfx: +// Lite rail systems +// A church. Large cross +// Sniper Scope, +// Really use the phone +// The Boiler Room +// The IRS, nuking other government buildings? +// You wouldn't have a belt of booz, would ya? +// Slow turning signes +// More persise shooting/descructions +// Faces, use phoneoms and its lookup. Talking, getting in fights. +// Drug dealers, pimps, and all galore +// Weapons, Anything lying around. +// Trees to clime, burning trees. +// Sledge Hammer, Sledge hammer with Spike +// sancurary, get away from it all. +// Goodlife = ( War + Greed ) / Peace +// Monsterism (ACTION) +// Global Hunter (RPG) +// Slick a Wick (PUZZLE) +// Roach Condo (FUNNY) +// AntiProfit (RPG) +// Pen Patrol (TD SIM) +// 97.5 KPIG! - Wanker County +// "Fauna" - Native Indiginouns Animal Life + diff --git a/gamedefs.h b/gamedefs.h new file mode 100755 index 0000000..ec1ae00 --- /dev/null +++ b/gamedefs.h @@ -0,0 +1,195 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment + +This file is part of Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Original Source: 1996 - Todd Replogle +Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms +*/ +//------------------------------------------------------------------------- + +//**************************************************************************** +// +// gamedefs.h +// +// common defines between the game and the setup program +// +//**************************************************************************** + +#ifndef _gamedefs_public_ +#define _gamedefs_public_ +#ifdef __cplusplus +extern "C" { +#endif + +//**************************************************************************** +// +// DEFINES +// +//**************************************************************************** + +// +// Setup program defines +// +#define SETUPFILENAME "duke3d.cfg" + + +// Max number of players + +#define MAXPLAYERS 16 + +// Number of Mouse buttons + +#define MAXMOUSEBUTTONS 7 + +// Number of JOY buttons +#define MAXJOYBUTTONS 32 + +// Number of joystick "top hats" +#define MAXJOYHATS 6 + +// Number of EXTERNAL buttons + +//#define MAXEXTERNALBUTTONS 6 + +// +// modem string defines +// + +#define MAXMODEMSTRING 50 + +// MACRO defines + +#define MAXMACROS 10 +#define MAXMACROLENGTH 34 + +// Phone list defines + +#define PHONENUMBERLENGTH 28 +#define PHONENAMELENGTH 16 +#define MAXPHONEENTRIES 10 + +// length of program functions + +#define MAXFUNCTIONLENGTH 30 + +// length of axis functions + +#define MAXAXISFUNCTIONLENGTH 30 + +// Max Player Name length + +#define MAXPLAYERNAMELENGTH 11 + +// Max RTS Name length + +#define MAXRTSNAMELENGTH 15 + +// Number of Mouse Axes + +#define MAXMOUSEAXES 2 + +// Number of JOY axes + +#define MAXJOYAXES 6 + +// Number of GAMEPAD axes + +#define MAXGAMEPADAXES 2 + +// MIN/MAX scale value for controller scales + +#define MAXCONTROLSCALEVALUE (1<<19) + +// DEFAULT scale value for controller scales + +#define DEFAULTCONTROLSCALEVALUE (1<<16) + +// base value for controller scales + +#define BASECONTROLSCALEVALUE (1<<16) + +// MAX mouse sensitivity scale + +#define MAXMOUSESENSITIVITY (1<<17) + +// DEFAULT mouse sensitivity scale + +#define DEFAULTMOUSESENSITIVITY (1<<15) + +enum + { + gametype_network=3, + gametype_serial=1, + gametype_modem=2 + }; + +enum + { + connecttype_dialing=0, + connecttype_answer=1, + connecttype_alreadyconnected=2 + }; + +enum + { + screenbuffer_320x200, + screenbuffer_640x400, + screenbuffer_640x480, + screenbuffer_800x600, + screenbuffer_1024x768, + screenbuffer_1280x1024, + screenbuffer_1600x1200 + }; + +enum + { + vesa_320x200, + vesa_360x200, + vesa_320x240, + vesa_360x240, + vesa_320x400, + vesa_360x400, + vesa_640x350, + vesa_640x400, + vesa_640x480, + vesa_800x600, + vesa_1024x768, + vesa_1280x1024, + vesa_1600x1200 + }; + +enum + { + screenmode_chained, + screenmode_vesa, + screenmode_buffered, + screenmode_tseng, + screenmode_paradise, + screenmode_s3, + screenmode_crystal, + screenmode_redblue, + }; + + +#ifdef __cplusplus +}; +#endif +#endif + diff --git a/global.c b/global.c new file mode 100755 index 0000000..a8f70c4 --- /dev/null +++ b/global.c @@ -0,0 +1,966 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment + +This file is part of Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Original Source: 1996 - Todd Replogle +Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms +*/ +//------------------------------------------------------------------------- + +#include +#include +#include +#include +#include + +#ifdef __BEOS__ +#include +#endif + +#include "duke3d.h" + +char *mymembuf; +char MusicPtr[72000]; + +short global_random; +short neartagsector, neartagwall, neartagsprite; + +long gc,neartaghitdist,lockclock,max_player_health,max_armour_amount,max_ammo_amount[MAX_WEAPONS]; + +// long temp_data[MAXSPRITES][6]; +struct weaponhit hittype[MAXSPRITES]; +short spriteq[1024],spriteqloc,spriteqamount=64; + +// ported build engine has this, too. --ryan. +#if PLATFORM_DOS +short moustat = 0; +#endif + +struct animwalltype animwall[MAXANIMWALLS]; +short numanimwalls; +long *animateptr[MAXANIMATES], animategoal[MAXANIMATES], animatevel[MAXANIMATES], animatecnt; +// long oanimateval[MAXANIMATES]; +short animatesect[MAXANIMATES]; +long msx[2048],msy[2048]; +short cyclers[MAXCYCLERS][6],numcyclers; + +char fta_quotes[NUMOFFIRSTTIMEACTIVE][64]; + +unsigned char tempbuf[2048], packbuf[576]; + +char buf[80]; + +short camsprite; +short mirrorwall[64], mirrorsector[64], mirrorcnt; + +int current_menu; + +char betaname[80]; + +char level_names[44][33],level_file_names[44][128]; +long partime[44],designertime[44]; +char volume_names[4][33]; +char skill_names[5][33]; + +volatile long checksume; +long soundsiz[NUM_SOUNDS]; + +short soundps[NUM_SOUNDS],soundpe[NUM_SOUNDS],soundvo[NUM_SOUNDS]; +char soundm[NUM_SOUNDS],soundpr[NUM_SOUNDS]; +char sounds[NUM_SOUNDS][14]; + +short title_zoom; + +fx_device device; + +SAMPLE Sound[ NUM_SOUNDS ]; +SOUNDOWNER SoundOwner[NUM_SOUNDS][4]; + +char numplayersprites,loadfromgrouponly,earthquaketime; + +long fricxv,fricyv; +struct player_orig po[MAXPLAYERS]; +struct player_struct ps[MAXPLAYERS]; +struct user_defs ud; + +char pus, pub; +char syncstat, syncval[MAXPLAYERS][MOVEFIFOSIZ]; +long syncvalhead[MAXPLAYERS], syncvaltail, syncvaltottail; + +input sync[MAXPLAYERS], loc; +input recsync[RECSYNCBUFSIZ]; +long avgfvel, avgsvel, avgavel, avghorz, avgbits; + + +input inputfifo[MOVEFIFOSIZ][MAXPLAYERS]; +input recsync[RECSYNCBUFSIZ]; + +long movefifosendplc; + + //Multiplayer syncing variables +short screenpeek; +long movefifoend[MAXPLAYERS]; + + + //Game recording variables + +char playerreadyflag[MAXPLAYERS],ready2send; +char playerquitflag[MAXPLAYERS]; +long vel, svel, angvel, horiz, ototalclock, respawnactortime=768, respawnitemtime=768, groupfile; + +long script[MAXSCRIPTSIZE],*scriptptr,*insptr,*labelcode,labelcnt; +long *actorscrptr[MAXTILES],*parsing_actor; +char *label,*textptr,error,warning,killit_flag; +char *music_pointer; +char actortype[MAXTILES]; + + +char display_mirror,typebuflen,typebuf[41]; + +char music_fn[4][11][13],music_select; +char env_music_fn[4][13]; +char rtsplaying; + + +short weaponsandammosprites[15] = { + RPGSPRITE, + CHAINGUNSPRITE, + DEVISTATORAMMO, + RPGAMMO, + RPGAMMO, + JETPACK, + SHIELD, + FIRSTAID, + STEROIDS, + RPGAMMO, + RPGAMMO, + RPGSPRITE, + RPGAMMO, + FREEZESPRITE, + FREEZEAMMO + }; + +long impact_damage; + + //GLOBAL.C - replace the end "my's" with this +long myx, omyx, myxvel, myy, omyy, myyvel, myz, omyz, myzvel; +short myhoriz, omyhoriz, myhorizoff, omyhorizoff; +short myang, omyang, mycursectnum, myjumpingcounter,frags[MAXPLAYERS][MAXPLAYERS]; + +char myjumpingtoggle, myonground, myhardlanding, myreturntocenter; +signed char multiwho, multipos, multiwhat, multiflag; + +long fakemovefifoplc,movefifoplc; +long myxbak[MOVEFIFOSIZ], myybak[MOVEFIFOSIZ], myzbak[MOVEFIFOSIZ]; +long myhorizbak[MOVEFIFOSIZ],dukefriction = 0xcc00, show_shareware; + +short myangbak[MOVEFIFOSIZ]; +char myname[32],camerashitable,freezerhurtowner=0,lasermode; +// CTW - MODIFICATION +// char networkmode = 255, movesperpacket = 1,gamequit = 0,playonten = 0,everyothertime; +char networkmode = 255, movesperpacket = 1,gamequit = 0,everyothertime; +// CTW END - MODIFICATION +long numfreezebounces=3,rpgblastradius,pipebombblastradius,tripbombblastradius,shrinkerblastradius,morterblastradius,bouncemineblastradius,seenineblastradius; +STATUSBARTYPE sbar; + +long myminlag[MAXPLAYERS], mymaxlag, otherminlag, bufferjitter = 1; +short numclouds,clouds[128],cloudx[128],cloudy[128]; +long cloudtotalclock = 0,totalmemory = 0; +long numinterpolations = 0, startofdynamicinterpolations = 0; +long oldipos[MAXINTERPOLATIONS]; +long bakipos[MAXINTERPOLATIONS]; +long *curipos[MAXINTERPOLATIONS]; + +static char ApogeePath[256]; + +// portability stuff. --ryan. +// A good portion of this was ripped from GPL'd Rise of the Triad. --ryan. + +void FixFilePath(char *filename) +{ +#if defined(PLATFORM_UNIX) && !defined(DC) + char *ptr; + char *lastsep = filename; + + if ((!filename) || (*filename == '\0')) + return; + + if (access(filename, F_OK) == 0) /* File exists; we're good to go. */ + return; + + for (ptr = filename; 1; ptr++) + { + if (*ptr == '\\') + *ptr = PATH_SEP_CHAR; + + if ((*ptr == PATH_SEP_CHAR) || (*ptr == '\0')) + { + char pch = *ptr; + struct dirent *dent = NULL; + DIR *dir; + + if ((pch == PATH_SEP_CHAR) && (*(ptr + 1) == '\0')) + return; /* eos is pathsep; we're done. */ + + if (lastsep == ptr) + continue; /* absolute path; skip to next one. */ + + *ptr = '\0'; + if (lastsep == filename) { + dir = opendir((*lastsep == PATH_SEP_CHAR) ? ROOTDIR : CURDIR); + + if (*lastsep == PATH_SEP_CHAR) { + lastsep++; + } + } + else + { + *lastsep = '\0'; + dir = opendir(filename); + *lastsep = PATH_SEP_CHAR; + lastsep++; + } + + if (dir == NULL) + { + *ptr = PATH_SEP_CHAR; + return; /* maybe dir doesn't exist? give up. */ + } + + while ((dent = readdir(dir)) != NULL) + { + if (strcasecmp(dent->d_name, lastsep) == 0) + { + /* found match; replace it. */ + strcpy(lastsep, dent->d_name); + break; + } + } + + closedir(dir); + *ptr = pch; + lastsep = ptr; + + if (dent == NULL) + return; /* no match. oh well. */ + + if (pch == '\0') /* eos? */ + return; + } + } +#endif +} + + +#if PLATFORM_DOS + /* no-op. */ + +#elif PLATFORM_WIN32 +int _dos_findfirst(char *filename, int x, struct find_t *f) +{ + long rc = _findfirst(filename, &f->data); + f->handle = rc; + if (rc != -1) + { + strncpy(f->name, f->data.name, sizeof (f->name) - 1); + f->name[sizeof (f->name) - 1] = '\0'; + return(0); + } + return(1); +} + +int _dos_findnext(struct find_t *f) +{ + int rc = 0; + if (f->handle == -1) + return(1); /* invalid handle. */ + + rc = _findnext(f->handle, &f->data); + if (rc == -1) + { + _findclose(f->handle); + f->handle = -1; + return(1); + } + + strncpy(f->name, f->data.name, sizeof (f->name) - 1); + f->name[sizeof (f->name) - 1] = '\0'; + return(0); +} + +#elif PLATFORM_UNIX +int _dos_findfirst(char *filename, int x, struct find_t *f) +{ + char *ptr; + + if (strlen(filename) >= sizeof (f->pattern)) + return(1); + + strcpy(f->pattern, filename); + FixFilePath(f->pattern); + ptr = strrchr(f->pattern, PATH_SEP_CHAR); + + if (ptr == NULL) + { + ptr = filename; + f->dir = opendir(CURDIR); + } + else + { + *ptr = '\0'; + f->dir = opendir(f->pattern); + memmove(f->pattern, ptr + 1, strlen(ptr + 1) + 1); + } + + return(_dos_findnext(f)); +} + + +static int check_pattern_nocase(const char *x, const char *y) +{ + if ((x == NULL) || (y == NULL)) + return(0); /* not a match. */ + + while ((*x) && (*y)) + { + if (*x == '*') + { + x++; + while (*y != '\0') + { + if (toupper((int) *x) == toupper((int) *y)) + break; + y++; + } + } + + else if (*x == '?') + { + if (*y == '\0') + return(0); /* anything but EOS is okay. */ + } + + else + { + if (toupper((int) *x) != toupper((int) *y)) + return(0); /* not a match. */ + } + + x++; + y++; + } + + return(*x == *y); /* it's a match (both should be EOS). */ +} + +int _dos_findnext(struct find_t *f) +{ + struct dirent *dent; + + if (f->dir == NULL) + return(1); /* no such dir or we're just done searching. */ + + while ((dent = readdir(f->dir)) != NULL) + { + if (check_pattern_nocase(f->pattern, dent->d_name)) + { + if (strlen(dent->d_name) < sizeof (f->name)) + { + strcpy(f->name, dent->d_name); + return(0); /* match. */ + } + } + } + + closedir(f->dir); + f->dir = NULL; + return(1); /* no match in whole directory. */ +} +#else +#error please define for your platform. +#endif + + +#if !PLATFORM_DOS +void _dos_getdate(struct dosdate_t *date) +{ + time_t curtime = time(NULL); + struct tm *tm; + + if (date == NULL) { + return; + } + + memset(date, 0, sizeof(struct dosdate_t)); + + if ((tm = localtime(&curtime)) != NULL) { + date->day = tm->tm_mday; + date->month = tm->tm_mon + 1; + date->year = tm->tm_year + 1900; + date->dayofweek = tm->tm_wday + 1; + } +} +#endif + + +int FindDistance2D(int ix, int iy) +{ + int t; + + ix= abs(ix); /* absolute values */ + iy= abs(iy); + + if (ix>1); + + return (ix - (ix>>5) - (ix>>7) + (t>>2) + (t>>6)); +} + +int FindDistance3D(int ix, int iy, int iz) +{ + int t; + + ix= abs(ix); /* absolute values */ + iy= abs(iy); + iz= abs(iz); + + if (ix>4) + (t>>2) + (t>>3)); +} + +void Error (char *error, ...) +{ + char msgbuf[300]; + va_list argptr; + static int inerror = 0; + + inerror++; + if (inerror > 1) + return; + + #if USE_SDL + SDL_Quit(); + #endif + + va_start (argptr, error); + vfprintf(stderr, error, argptr); + va_end (argptr); + + exit (1); +} + + +int32 SafeOpenAppend (const char *_filename, int32 filetype) +{ + int handle; + char filename[MAX_PATH]; + strncpy(filename, _filename, sizeof (filename)); + filename[sizeof (filename) - 1] = '\0'; + FixFilePath(filename); + + handle = open(filename,O_RDWR | O_BINARY | O_CREAT | O_APPEND + , S_IREAD | S_IWRITE); + + if (handle == -1) + Error ("Error opening for append %s: %s",filename,strerror(errno)); + + return handle; +} + +boolean SafeFileExists ( const char * _filename ) +{ + char filename[MAX_PATH]; + strncpy(filename, _filename, sizeof (filename)); + filename[sizeof (filename) - 1] = '\0'; + FixFilePath(filename); + + return(access(filename, F_OK) == 0); +} + + +int32 SafeOpenWrite (const char *_filename, int32 filetype) +{ + int handle; + char filename[MAX_PATH]; + strncpy(filename, _filename, sizeof (filename)); + filename[sizeof (filename) - 1] = '\0'; + FixFilePath(filename); + + handle = open(filename,O_RDWR | O_BINARY | O_CREAT | O_TRUNC + , S_IREAD | S_IWRITE); + + if (handle == -1) + Error ("Error opening %s: %s",filename,strerror(errno)); + + return handle; +} + +int32 SafeOpenRead (const char *_filename, int32 filetype) +{ + int handle; + char filename[MAX_PATH]; + strncpy(filename, _filename, sizeof (filename)); + filename[sizeof (filename) - 1] = '\0'; + FixFilePath(filename); + + handle = open(filename,O_RDONLY | O_BINARY); + + if (handle == -1) + Error ("Error opening %s: %s",filename,strerror(errno)); + + return handle; +} + + +void SafeRead (int32 handle, void *buffer, int32 count) +{ + unsigned iocount; + + while (count) + { + iocount = count > 0x8000 ? 0x8000 : count; + if (read (handle,buffer,iocount) != (int)iocount) + Error ("File read failure reading %ld bytes",count); + buffer = (void *)( (byte *)buffer + iocount ); + count -= iocount; + } +} + + +void SafeWrite (int32 handle, void *buffer, int32 count) +{ + unsigned iocount; + + while (count) + { + iocount = count > 0x8000 ? 0x8000 : count; + if (write (handle,buffer,iocount) != (int)iocount) + Error ("File write failure writing %ld bytes",count); + buffer = (void *)( (byte *)buffer + iocount ); + count -= iocount; + } +} + + +void GetPathFromEnvironment( char *fullname, int32 length, const char *filename ) +{ + snprintf(fullname, length-1, "%s%s", ApogeePath, filename); +} + +void SafeWriteString (int handle, char * buffer) +{ + unsigned iocount; + + iocount=strlen(buffer); + if (write (handle,buffer,iocount) != (int)iocount) + Error ("File write string failure writing %s\n",buffer); +} + +void *SafeMalloc (long size) +{ + void *ptr; + +#if 0 + if (zonememorystarted==false) + Error("Called SafeMalloc without starting zone memory\n"); + ptr = Z_Malloc (size,PU_STATIC,NULL); +#else + ptr = malloc(size); +#endif + + if (!ptr) + Error ("SafeMalloc failure for %lu bytes",size); + + return ptr; +} + +void SafeRealloc (void **x, int32 size) +{ + void *ptr; + +#if 0 + if (zonememorystarted==false) + Error("Called SafeMalloc without starting zone memory\n"); + ptr = Z_Malloc (size,PU_STATIC,NULL); +#else + ptr = realloc(*x, size); +#endif + + if (!ptr) + Error ("SafeRealloc failure for %lu bytes",size); + + *x = ptr; +} + +void *SafeLevelMalloc (long size) +{ + void *ptr; + +#if 0 + if (zonememorystarted==false) + Error("Called SafeLevelMalloc without starting zone memory\n"); + ptr = Z_LevelMalloc (size,PU_STATIC,NULL); +#else + ptr = malloc(size); +#endif + + if (!ptr) + Error ("SafeLevelMalloc failure for %lu bytes",size); + + return ptr; +} + +void SafeFree (void * ptr) +{ + if ( ptr == NULL ) + Error ("SafeFree : Tried to free a freed pointer\n"); + +#if 0 + Z_Free (ptr); +#else + free(ptr); +#endif +} + + +#ifndef LITTLE_ENDIAN +#define LITTLE_ENDIAN 1234 +#endif + +#ifndef BIG_ENDIAN +#define BIG_ENDIAN 4321 +#endif + +#if PLATFORM_DOS +#ifndef BYTE_ORDER +#define BYTE_ORDER LITTLE_ENDIAN +#endif +#endif + +#ifdef PLATFORM_WIN32 +#define BYTE_ORDER LITTLE_ENDIAN +#endif + +#ifdef _LITTLE_ENDIAN +#define BYTE_ORDER LITTLE_ENDIAN +#elif defined(_BIG_ENDIAN) +#define BYTE_ORDER BIG_ENDIAN +#endif + +#ifndef BYTE_ORDER +#error Please define your platform. +#endif + +#if (BYTE_ORDER == LITTLE_ENDIAN) +#define KeepShort IntelShort +#define SwapShort MotoShort +#define KeepLong IntelLong +#define SwapLong MotoLong +#else +#define KeepShort MotoShort +#define SwapShort IntelShort +#define KeepLong MotoLong +#define SwapLong IntelLong +#endif + +short SwapShort (short l) +{ + byte b1,b2; + + b1 = l&255; + b2 = (l>>8)&255; + + return (b1<<8) + b2; +} + +short KeepShort (short l) +{ + return l; +} + + +long SwapLong (long l) +{ + byte b1,b2,b3,b4; + + b1 = l&255; + b2 = (l>>8)&255; + b3 = (l>>16)&255; + b4 = (l>>24)&255; + + return ((long)b1<<24) + ((long)b2<<16) + ((long)b3<<8) + b4; +} + +long KeepLong (long l) +{ + return l; +} + + +#undef KeepShort +#undef KeepLong +#undef SwapShort +#undef SwapLong + +void SwapIntelLong(long *l) +{ + *l = IntelLong(*l); +} + +void SwapIntelShort(short *s) +{ + *s = IntelShort(*s); +} + +void SwapIntelLongArray(long *l, int num) +{ + while (num--) { + SwapIntelLong(l); + l++; + } +} + +void SwapIntelShortArray(short *s, int num) +{ + while (num--) { + SwapIntelShort(s); + s++; + } +} + + +/* + Copied over from Wolf3D Linux: http://www.icculus.org/wolf3d/ + Modified for ROTT. + Stolen for Duke3D, too. + */ + +#if PLATFORM_UNIX +char *strlwr(char *s) +{ + char *p = s; + + while (*p) { + *p = tolower(*p); + p++; + } + + return s; +} + +char *strupr(char *s) +{ + char *p = s; + + while (*p) { + *p = toupper(*p); + p++; + } + + return s; +} + +char *itoa(int value, char *string, int radix) +{ + switch (radix) { + case 10: + sprintf(string, "%d", value); + break; + case 16: + sprintf(string, "%x", value); + break; + default: + STUBBED("unknown radix"); + break; + } + + return string; +} + +char *ltoa(long value, char *string, int radix) +{ + switch (radix) { + case 10: + sprintf(string, "%ld", value); + break; + case 16: + sprintf(string, "%lx", value); + break; + default: + STUBBED("unknown radix"); + break; + } + + return string; +} + +char *ultoa(unsigned long value, char *string, int radix) +{ + switch (radix) { + case 10: + sprintf(string, "%lu", value); + break; + case 16: + sprintf(string, "%lux", value); + break; + default: + STUBBED("unknown radix"); + break; + } + + return string; +} +#endif + + +int setup_homedir (void) +{ +#ifdef DC + strcpy (ApogeePath, "/ram/"); +#elif PLATFORM_UNIX + char *cfgpath; + int err; + +#if PLATFORM_MACOSX + snprintf (ApogeePath, sizeof (ApogeePath), "%s/Library/", getenv ("HOME")); + mkdir (ApogeePath, S_IRWXU); + snprintf (ApogeePath, sizeof (ApogeePath), "%s/Library/Application Support/", getenv ("HOME")); + mkdir (ApogeePath, S_IRWXU); + snprintf (ApogeePath, sizeof (ApogeePath), "%s/Library/Application Support/Duke Nukem 3D/", getenv ("HOME")); +#else + snprintf (ApogeePath, sizeof (ApogeePath), "%s/.local/share/games/duke3d/", getenv ("HOME")); +#endif + + err = mkdir (ApogeePath, S_IRWXU); + if (err == -1 && errno != EEXIST) + { + fprintf (stderr, "Couldn't create preferences directory: %s\n", + strerror (errno)); + return -1; + } + + /* copy duke3d.cfg to prefpath if it doesn't exist... */ + cfgpath = alloca(strlen(ApogeePath) + strlen(SETUPFILENAME) + 1); + strcpy(cfgpath, ApogeePath); + strcat(cfgpath, SETUPFILENAME); + if (access(cfgpath, F_OK) == -1) + { + FILE *in = fopen(SETUPFILENAME, "rb"); + if (in) + { + FILE *out = fopen(cfgpath, "wb"); + if (out) + { + int ch; + while ((ch = fgetc(in)) != EOF) + fputc(ch, out); + fclose(out); + } + fclose(in); + } + } +#else + sprintf(ApogeePath, ".%s", PATH_SEP_STR); +#endif + + return 0; +} + + +int dukescreencapture(char *str, char inverseit) +{ +// dos screencapture wants string to be in NAME0000.pcx format. +#ifndef PLATFORM_DOS + // respect prefpath... + const char *SCREENSHOTDIR = "Screenshots"; + size_t slen = strlen(ApogeePath) + strlen(str) + + strlen(PATH_SEP_STR) + strlen(SCREENSHOTDIR) + 1; + char *path = alloca(slen); + strcpy(path, ApogeePath); + strcat(path, SCREENSHOTDIR); + mkdir(path, S_IRWXU); + strcat(path, PATH_SEP_STR); + strcat(path, str); + str = path; +#endif + + return(screencapture(str, inverseit)); +} + + +char CheckParm (char *check) +{ + int i; + for (i = 1; i < _argc; i++) + { + if ((*(_argv[i]) == '-') && (strcmpi(_argv[i] + 1, check) == 0)) + return(i); + } + + return(0); +} + + +static void (*shutdown_func)(void) = NULL; + +void RegisterShutdownFunction( void (* shutdown) (void) ) +{ + shutdown_func = shutdown; +} + +void Shutdown(void) +{ + if (shutdown_func != NULL) + { + shutdown_func(); + shutdown_func = NULL; + } +} + + +/* + * From Ryan's buildengine CHANGELOG: + * Removed global var: cachedebug in engine.c, and put #define + * BUILD_CACHEDEBUG 0 at the top of the source. Flip it to 1 if you ever + * need to tinker in the cache code. + */ +char cachedebug = 0; + diff --git a/gnu.txt b/gnu.txt new file mode 100755 index 0000000..2f3289a --- /dev/null +++ b/gnu.txt @@ -0,0 +1,87 @@ +GNU GENERAL PUBLIC LICENSE +Version 2, June 1991 + +Copyright (C) 1989, 1991 Free Software Foundation, Inc. +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. +Preamble +The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. + +When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. + +To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. + +For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. + +We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. + +Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. + +Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. + +The precise terms and conditions for copying, distribution and modification follow. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION +0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. + +1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. + +You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: + + +a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. + +b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. + +c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) +These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. +Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. + +3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: + +a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, + +b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, + +c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) +The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. +If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. + +4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. + +5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. + +6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. + +7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. + +This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. + +8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. + +9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. + +10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. + +NO WARRANTY + +11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + + +END OF TERMS AND CONDITIONS diff --git a/joystick.h b/joystick.h new file mode 100755 index 0000000..76a38ed --- /dev/null +++ b/joystick.h @@ -0,0 +1,13 @@ +#ifndef __joystick_h +#define __joystick_h +#ifdef __cplusplus +extern "C" { +#endif + +void JOYSTICK_UpdateHats( void ); + +#ifdef __cplusplus +}; + +#endif +#endif /* __joystick_h */ diff --git a/keyboard.c b/keyboard.c new file mode 100755 index 0000000..6114896 --- /dev/null +++ b/keyboard.c @@ -0,0 +1,461 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment + +This file is part of Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Original Source: 1996 - Todd Replogle +Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms +*/ +//------------------------------------------------------------------------- + +#include "duke3d.h" +#include "keyboard.h" + +/* this should be a proper prototype included from a header file */ +extern int stricmp(const char *x, const char *y); + +/* +============================================================================= + + GLOBAL VARIABLES + +============================================================================= +*/ + +volatile byte KB_KeyDown[ MAXKEYBOARDSCAN ]; // Keyboard state array +volatile kb_scancode KB_LastScan; + +static volatile boolean keyIsWaiting = 0; + +static char scancodeToASCII[ MAXKEYBOARDSCAN ]; +static char shiftedScancodeToASCII[ MAXKEYBOARDSCAN ]; +static char extscanToSC[ MAXKEYBOARDSCAN ]; + +/* +============================================================================= +FUNCTIONS +============================================================================= +*/ + +void keyhandler(void) +{ + static boolean gotextended = false; + + int rawkey = _readlastkeyhit(); + int lastkey = rawkey & 0x7f; + + // 128 bit means key was released. + int pressed = !(rawkey & 0x80); + + if (rawkey == 0xe0 && !gotextended) + { + gotextended = true; + return; + } + + if (rawkey == 0xe1) + { + /* SBF - build doesn't actually generate this for Pause/Break */ + STUBBED("Another extended key!"); + return; + } + + if (gotextended) + { + gotextended = false; + + /* remap extended key to Duke3D equivalent */ + lastkey = extscanToSC[lastkey]; + } + + if (lastkey >= MAXKEYBOARDSCAN) + { + STUBBED("Scancode out of range!"); + return; + } + + if (pressed) + { + KB_LastScan = lastkey; + } + + KB_KeyDown[lastkey] = pressed; + + keyIsWaiting = ((keyIsWaiting) || (KB_KeyDown[lastkey])); + + CONTROL_UpdateKeyboardState(lastkey, pressed); +} + +void KB_KeyEvent( int scancode, boolean keypressed ) +{ + STUBBED("KB_KeyEvent"); +} + +boolean KB_KeyWaiting( void ) +{ + _handle_events(); + return keyIsWaiting; +} + +char KB_Getch( void ) +{ + int shifted; + + while (!keyIsWaiting) { _idle(); /* pull the pud. */ } + keyIsWaiting = false; + if (KB_LastScan >= MAXKEYBOARDSCAN) + return(0xFF); + + if (KB_KeyDown[sc_LeftShift] || KB_KeyDown[sc_RightShift]) + return shiftedScancodeToASCII[KB_LastScan]; + + return scancodeToASCII[KB_LastScan]; +} + +void KB_Addch( char ch ) +{ + STUBBED("KB_Addch"); +} + +void KB_FlushKeyboardQueue( void ) +{ + _handle_events(); + keyIsWaiting = false; +} + +void KB_ClearKeysDown( void ) +{ + memset((void *) KB_KeyDown, '\0', sizeof (KB_KeyDown)); + keyIsWaiting = false; +} + +static struct { + char* name; + int code; +} keyname2scancode[] = { + { "Comma", sc_Comma }, + { "Period", sc_Period }, + { "Enter", sc_Return }, + { "Escape", sc_Escape }, + { "Space", sc_Space }, + { "BakSpc", sc_BackSpace }, + { "Tab", sc_Tab }, + { "LAlt", sc_LeftAlt }, + { "LCtrl", sc_LeftControl }, + { "CapLck", sc_CapsLock }, + { "LShift", sc_LeftShift }, + { "RShift", sc_RightShift }, + { "F1", sc_F1 }, + { "F2", sc_F2 }, + { "F3", sc_F3 }, + { "F4", sc_F4 }, + { "F5", sc_F5 }, + { "F6", sc_F6 }, + { "F7", sc_F7 }, + { "F8", sc_F8 }, + { "F9", sc_F9 }, + { "F10", sc_F10 }, + { "F11", sc_F11 }, + { "F12", sc_F12 }, + { "KStar", sc_Kpad_Star }, + { "Pause", sc_Pause }, + { "ScrLck", sc_ScrollLock }, + { "NumLck", sc_NumLock }, + { "Slash", sc_Slash }, + { "Semi", sc_SemiColon }, + { "Quote", sc_Quote }, + { "Tilde", sc_Tilde }, + { "BkSlash", sc_BackSlash }, + { "LBrack", sc_OpenBracket }, + { "RBrack", sc_CloseBracket }, + { "1", sc_1 }, + { "2", sc_2 }, + { "3", sc_3 }, + { "4", sc_4 }, + { "5", sc_5 }, + { "6", sc_6 }, + { "7", sc_7 }, + { "8", sc_8 }, + { "9", sc_9 }, + { "0", sc_0 }, + { "Minus", sc_Minus }, + { "Equals", sc_Equals }, + { "Plus", sc_Plus }, + { "Kpad1", sc_kpad_1 }, + { "Kpad2", sc_kpad_2 }, + { "Kpad3", sc_kpad_3 }, + { "Kpad4", sc_kpad_4 }, + { "Kpad5", sc_kpad_5 }, + { "Kpad6", sc_kpad_6 }, + { "Kpad7", sc_kpad_7 }, + { "Kpad8", sc_kpad_8 }, + { "Kpad9", sc_kpad_9 }, + { "Kpad0", sc_kpad_0 }, + { "KMinus", sc_kpad_Minus }, + { "KPlus", sc_kpad_Plus }, + { "KPeriod", sc_kpad_Period }, + { "A", sc_A }, + { "B", sc_B }, + { "C", sc_C }, + { "D", sc_D }, + { "E", sc_E }, + { "F", sc_F }, + { "G", sc_G }, + { "H", sc_H }, + { "I", sc_I }, + { "J", sc_J }, + { "K", sc_K }, + { "L", sc_L }, + { "M", sc_M }, + { "N", sc_N }, + { "O", sc_O }, + { "P", sc_P }, + { "Q", sc_Q }, + { "R", sc_R }, + { "S", sc_S }, + { "T", sc_T }, + { "U", sc_U }, + { "V", sc_V }, + { "W", sc_W }, + { "X", sc_X }, + { "Y", sc_Y }, + { "Z", sc_Z }, + { "Up", sc_UpArrow }, + { "Down", sc_DownArrow }, + { "Left", sc_LeftArrow }, + { "Right", sc_RightArrow }, + { "Insert", sc_Insert }, + { "Delete", sc_Delete }, + { "Home", sc_Home }, + { "End", sc_End }, + { "PgUp", sc_PgUp }, + { "PgDn", sc_PgDn }, + { "RAlt", sc_RightAlt }, + { "RCtrl", sc_RightControl }, + { "KpdSl", sc_kpad_Slash }, + { "KpdEnt", sc_kpad_Enter }, + { "PrtScn", sc_PrintScreen }, + + // AZERTY hacks... + { "INTL1", sc_INTL1 }, + { "INTL2", sc_INTL2 }, + { "INTL3", sc_INTL3 }, + { "INTL4", sc_INTL4 }, + { "INTL5", sc_INTL5 }, + { "INTL6", sc_INTL6 }, + { "INTL7", sc_INTL7 }, + { "INTL8", sc_INTL8 }, + { "INTL9", sc_INTL9 }, + { "INTL10", sc_INTL10 }, + { "INTL11", sc_INTL11 }, + { "INTL12", sc_INTL12 }, + { "INTL13", sc_INTL13 }, + { "INTL14", sc_INTL14 }, + { "INTL15", sc_INTL15 }, + + { NULL, 0 } +}; + +char *KB_ScanCodeToString( kb_scancode scancode ) +{ + int i; + for(i = 0; keyname2scancode[i].name != NULL; i++) + { + if (keyname2scancode[i].code == scancode) + return keyname2scancode[i].name; + } + + return NULL; +} + +kb_scancode KB_StringToScanCode( char * string ) +{ + char* name = NULL; + int32 i=0; + name = keyname2scancode[i].name; + for(;name;++i, name=keyname2scancode[i].name) + { + if(!stricmp(name,string)) + break; + } + + return keyname2scancode[i].code; +} + +void KB_TurnKeypadOn( void ) +{ + STUBBED("KB_TurnKeypadOn"); +} + +void KB_TurnKeypadOff( void ) +{ + STUBBED("KB_TurnKeypadOff"); +} + +boolean KB_KeypadActive( void ) +{ + STUBBED("KB_KeypadActive"); + return false; +} + +void KB_Startup( void ) +{ + memset(scancodeToASCII, 0xFF, sizeof (scancodeToASCII)); + + // !!! FIXME: incomplete? + scancodeToASCII[sc_A] = 'a'; + scancodeToASCII[sc_B] = 'b'; + scancodeToASCII[sc_C] = 'c'; + scancodeToASCII[sc_D] = 'd'; + scancodeToASCII[sc_E] = 'e'; + scancodeToASCII[sc_F] = 'f'; + scancodeToASCII[sc_G] = 'g'; + scancodeToASCII[sc_H] = 'h'; + scancodeToASCII[sc_I] = 'i'; + scancodeToASCII[sc_J] = 'j'; + scancodeToASCII[sc_K] = 'k'; + scancodeToASCII[sc_L] = 'l'; + scancodeToASCII[sc_M] = 'm'; + scancodeToASCII[sc_N] = 'n'; + scancodeToASCII[sc_O] = 'o'; + scancodeToASCII[sc_P] = 'p'; + scancodeToASCII[sc_Q] = 'q'; + scancodeToASCII[sc_R] = 'r'; + scancodeToASCII[sc_S] = 's'; + scancodeToASCII[sc_T] = 't'; + scancodeToASCII[sc_U] = 'u'; + scancodeToASCII[sc_V] = 'v'; + scancodeToASCII[sc_W] = 'w'; + scancodeToASCII[sc_X] = 'x'; + scancodeToASCII[sc_Y] = 'y'; + scancodeToASCII[sc_Z] = 'z'; + scancodeToASCII[sc_0] = '0'; + scancodeToASCII[sc_1] = '1'; + scancodeToASCII[sc_2] = '2'; + scancodeToASCII[sc_3] = '3'; + scancodeToASCII[sc_4] = '4'; + scancodeToASCII[sc_5] = '5'; + scancodeToASCII[sc_6] = '6'; + scancodeToASCII[sc_7] = '7'; + scancodeToASCII[sc_8] = '8'; + scancodeToASCII[sc_9] = '9'; + scancodeToASCII[sc_Escape] = asc_Escape; + scancodeToASCII[sc_Tab] = asc_Tab; + scancodeToASCII[sc_Space] = asc_Space; + scancodeToASCII[sc_Enter] = asc_Enter; + scancodeToASCII[sc_BackSpace] = asc_BackSpace; + scancodeToASCII[sc_Comma] = ','; + scancodeToASCII[sc_Period] = '.'; + scancodeToASCII[sc_Kpad_Star] = '*'; + scancodeToASCII[sc_Slash] = '/'; + scancodeToASCII[sc_SemiColon] = ';'; + scancodeToASCII[sc_Quote] = '\''; + scancodeToASCII[sc_Tilde] = '`'; + scancodeToASCII[sc_BackSlash] = '\\'; + scancodeToASCII[sc_OpenBracket] = '['; + scancodeToASCII[sc_CloseBracket] = ']'; + scancodeToASCII[sc_Minus] = '-'; + scancodeToASCII[sc_Equals] = '='; + scancodeToASCII[sc_Plus] = '+'; + scancodeToASCII[sc_kpad_Minus] = '-'; + scancodeToASCII[sc_kpad_Period] = '.'; + scancodeToASCII[sc_kpad_Plus] = '+'; + + // !!! FIXME: incomplete? + memset(shiftedScancodeToASCII, 0xFF, sizeof (shiftedScancodeToASCII)); + shiftedScancodeToASCII[sc_A] = 'A'; + shiftedScancodeToASCII[sc_B] = 'B'; + shiftedScancodeToASCII[sc_C] = 'C'; + shiftedScancodeToASCII[sc_D] = 'D'; + shiftedScancodeToASCII[sc_E] = 'E'; + shiftedScancodeToASCII[sc_F] = 'F'; + shiftedScancodeToASCII[sc_G] = 'G'; + shiftedScancodeToASCII[sc_H] = 'H'; + shiftedScancodeToASCII[sc_I] = 'I'; + shiftedScancodeToASCII[sc_J] = 'J'; + shiftedScancodeToASCII[sc_K] = 'K'; + shiftedScancodeToASCII[sc_L] = 'L'; + shiftedScancodeToASCII[sc_M] = 'M'; + shiftedScancodeToASCII[sc_N] = 'N'; + shiftedScancodeToASCII[sc_O] = 'O'; + shiftedScancodeToASCII[sc_P] = 'P'; + shiftedScancodeToASCII[sc_Q] = 'Q'; + shiftedScancodeToASCII[sc_R] = 'R'; + shiftedScancodeToASCII[sc_S] = 'S'; + shiftedScancodeToASCII[sc_T] = 'T'; + shiftedScancodeToASCII[sc_U] = 'U'; + shiftedScancodeToASCII[sc_V] = 'V'; + shiftedScancodeToASCII[sc_W] = 'W'; + shiftedScancodeToASCII[sc_X] = 'X'; + shiftedScancodeToASCII[sc_Y] = 'Y'; + shiftedScancodeToASCII[sc_Z] = 'Z'; + shiftedScancodeToASCII[sc_0] = ')'; + shiftedScancodeToASCII[sc_1] = '!'; + shiftedScancodeToASCII[sc_2] = '@'; + shiftedScancodeToASCII[sc_3] = '#'; + shiftedScancodeToASCII[sc_4] = '$'; + shiftedScancodeToASCII[sc_5] = '%'; + shiftedScancodeToASCII[sc_6] = '^'; + shiftedScancodeToASCII[sc_7] = '&'; + shiftedScancodeToASCII[sc_8] = '*'; + shiftedScancodeToASCII[sc_9] = '('; + shiftedScancodeToASCII[sc_Comma] = '<'; + shiftedScancodeToASCII[sc_Period] = '>'; + shiftedScancodeToASCII[sc_Kpad_Star] = '*'; + shiftedScancodeToASCII[sc_Slash] = '?'; + shiftedScancodeToASCII[sc_SemiColon] = ':'; + shiftedScancodeToASCII[sc_Quote] = '\"'; + shiftedScancodeToASCII[sc_Tilde] = '~'; + shiftedScancodeToASCII[sc_BackSlash] = '|'; + shiftedScancodeToASCII[sc_OpenBracket] = '{'; + shiftedScancodeToASCII[sc_CloseBracket] = '}'; + shiftedScancodeToASCII[sc_Minus] = '_'; + shiftedScancodeToASCII[sc_Equals] = '+'; + shiftedScancodeToASCII[sc_Plus] = '+'; + shiftedScancodeToASCII[sc_kpad_Minus] = '-'; + shiftedScancodeToASCII[sc_kpad_Period] = '.'; + shiftedScancodeToASCII[sc_kpad_Plus] = '+'; + + memset(extscanToSC, '\0', sizeof (extscanToSC)); + + /* map extended keys to their Duke3D equivalents */ + extscanToSC[0x1C] = sc_kpad_Enter; + extscanToSC[0x1D] = sc_RightControl; + extscanToSC[0x35] = sc_kpad_Slash; + extscanToSC[0x37] = sc_PrintScreen; + extscanToSC[0x38] = sc_RightAlt; + extscanToSC[0x47] = sc_Home; + extscanToSC[0x48] = sc_UpArrow; + extscanToSC[0x49] = sc_PgUp; + extscanToSC[0x4B] = sc_LeftArrow; + extscanToSC[0x4D] = sc_RightArrow; + extscanToSC[0x4F] = sc_End; + extscanToSC[0x50] = sc_DownArrow; + extscanToSC[0x51] = sc_PgDn; + extscanToSC[0x52] = sc_Insert; + extscanToSC[0x53] = sc_Delete; + + KB_ClearKeysDown(); +} + +void KB_Shutdown( void ) +{ + KB_ClearKeysDown(); +} + diff --git a/keyboard.h b/keyboard.h new file mode 100755 index 0000000..06ac80f --- /dev/null +++ b/keyboard.h @@ -0,0 +1,241 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment + +This file is part of Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Original Source: 1996 - Todd Replogle +Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms +*/ +//------------------------------------------------------------------------- + +#ifndef _keyboard_public +#define _keyboard_public +#ifdef __cplusplus +extern "C" { +#endif + +/* +============================================================================= + + DEFINES + +============================================================================= +*/ + +typedef uint8 kb_scancode; + +#define sc_None 0 +#define sc_Bad 0xff +#define sc_Comma 0x33 +#define sc_Period 0x34 +#define sc_Return 0x1c +#define sc_Enter sc_Return +#define sc_Escape 0x01 +#define sc_Space 0x39 +#define sc_BackSpace 0x0e +#define sc_Tab 0x0f +#define sc_LeftAlt 0x38 +#define sc_LeftControl 0x1d +#define sc_CapsLock 0x3a +#define sc_LeftShift 0x2a +#define sc_RightShift 0x36 +#define sc_F1 0x3b +#define sc_F2 0x3c +#define sc_F3 0x3d +#define sc_F4 0x3e +#define sc_F5 0x3f +#define sc_F6 0x40 +#define sc_F7 0x41 +#define sc_F8 0x42 +#define sc_F9 0x43 +#define sc_F10 0x44 +#define sc_F11 0x57 +#define sc_F12 0x58 +#define sc_Kpad_Star 0x37 +#define sc_Pause 0x59 +#define sc_ScrollLock 0x46 +#define sc_NumLock 0x45 +#define sc_Slash 0x35 +#define sc_SemiColon 0x27 +#define sc_Quote 0x28 +#define sc_Tilde 0x29 +#define sc_BackSlash 0x2b + +#define sc_OpenBracket 0x1a +#define sc_CloseBracket 0x1b + +#define sc_1 0x02 +#define sc_2 0x03 +#define sc_3 0x04 +#define sc_4 0x05 +#define sc_5 0x06 +#define sc_6 0x07 +#define sc_7 0x08 +#define sc_8 0x09 +#define sc_9 0x0a +#define sc_0 0x0b +#define sc_Minus 0x0c +#define sc_Equals 0x0d +#define sc_Plus 0x0d + +#define sc_kpad_1 0x4f +#define sc_kpad_2 0x50 +#define sc_kpad_3 0x51 +#define sc_kpad_4 0x4b +#define sc_kpad_5 0x4c +#define sc_kpad_6 0x4d +#define sc_kpad_7 0x47 +#define sc_kpad_8 0x48 +#define sc_kpad_9 0x49 +#define sc_kpad_0 0x52 +#define sc_kpad_Minus 0x4a +#define sc_kpad_Plus 0x4e +#define sc_kpad_Period 0x53 + +#define sc_A 0x1e +#define sc_B 0x30 +#define sc_C 0x2e +#define sc_D 0x20 +#define sc_E 0x12 +#define sc_F 0x21 +#define sc_G 0x22 +#define sc_H 0x23 +#define sc_I 0x17 +#define sc_J 0x24 +#define sc_K 0x25 +#define sc_L 0x26 +#define sc_M 0x32 +#define sc_N 0x31 +#define sc_O 0x18 +#define sc_P 0x19 +#define sc_Q 0x10 +#define sc_R 0x13 +#define sc_S 0x1f +#define sc_T 0x14 +#define sc_U 0x16 +#define sc_V 0x2f +#define sc_W 0x11 +#define sc_X 0x2d +#define sc_Y 0x15 +#define sc_Z 0x2c + +// Extended scan codes + +#define sc_UpArrow 0x5a +#define sc_DownArrow 0x6a +#define sc_LeftArrow 0x6b +#define sc_RightArrow 0x6c +#define sc_Insert 0x5e +#define sc_Delete 0x5f +#define sc_Home 0x61 +#define sc_End 0x62 +#define sc_PgUp 0x63 +#define sc_PgDn 0x64 +#define sc_RightAlt 0x65 +#define sc_RightControl 0x66 +#define sc_kpad_Slash 0x67 +#define sc_kpad_Enter 0x68 +#define sc_PrintScreen 0x69 +#define sc_LastScanCode 0x6e + +// AZERTY hacks... +#define sc_INTL1 0x70 +#define sc_INTL2 0x71 +#define sc_INTL3 0x72 +#define sc_INTL4 0x73 +#define sc_INTL5 0x74 +#define sc_INTL6 0x75 +#define sc_INTL7 0x76 +#define sc_INTL8 0x77 +#define sc_INTL9 0x78 +#define sc_INTL10 0x79 +#define sc_INTL11 0x7a +#define sc_INTL12 0x7b +#define sc_INTL13 0x7c +#define sc_INTL14 0x7d +#define sc_INTL15 0x7e + +// Ascii scan codes + +#define asc_Enter 13 +#define asc_Escape 27 +#define asc_BackSpace 8 +#define asc_Tab 9 +#define asc_Space 32 + +#define MAXKEYBOARDSCAN 255 + + +/* +============================================================================= + + GLOBAL VARIABLES + +============================================================================= +*/ + +extern volatile byte KB_KeyDown[ MAXKEYBOARDSCAN ]; // Keyboard state array +extern volatile kb_scancode KB_LastScan; + + +/* +============================================================================= + + MACROS + +============================================================================= +*/ + +#define KB_GetLastScanCode() ( KB_LastScan ) + +#define KB_SetLastScanCode( scancode ) { KB_LastScan = ( scancode ); } + +#define KB_ClearLastScanCode() { KB_SetLastScanCode( sc_None ); } + +#define KB_KeyPressed( scan ) ( KB_KeyDown[ ( scan ) ] != 0 ) + +#define KB_ClearKeyDown( scan ) { KB_KeyDown[ ( scan ) ] = false; } + + +/* +============================================================================= + + FUNCTION PROTOTYPES + +============================================================================= +*/ + +void KB_KeyEvent( int scancode, boolean keypressed ); // Interprets scancodes +boolean KB_KeyWaiting( void ); // Checks if a character is waiting in the keyboard queue +char KB_Getch( void ); // Gets the next keypress +void KB_Addch( char ch ); // Adds key to end of queue +void KB_FlushKeyboardQueue( void ); // Empties the keyboard queue of all waiting characters. +void KB_ClearKeysDown( void ); // Clears all keys down flags. +char * KB_ScanCodeToString( kb_scancode scancode ); // convert scancode into a string +kb_scancode KB_StringToScanCode( char * string ); // convert a string into a scancode +void KB_TurnKeypadOn( void ); // turn the keypad on +void KB_TurnKeypadOff( void ); // turn the keypad off +boolean KB_KeypadActive( void ); // check whether keypad is active +void KB_Startup( void ); +void KB_Shutdown( void ); + +#ifdef __cplusplus +}; +#endif +#endif diff --git a/makefile.dos b/makefile.dos new file mode 100755 index 0000000..09031f3 --- /dev/null +++ b/makefile.dos @@ -0,0 +1,38 @@ +#This make file is used with Watcom C/C++ 32 Compiler v11.0c +#debug = /d2 /w1 +#all = debug all +prod = /5r /s /otexan + +duke3d.exe : game.obj actors.obj gamedef.obj global.obj menues.obj player.obj & + premap.obj sector.obj sounds.obj rts.obj cache1d.obj engine.obj & + a.obj mmulti.obj config.obj animlib.obj + wlink $(all) @makefile.lnk + +compileoptions = $(prod) $(debug) -imact -dPLATFORM_DOS=1 +globaldependencies = makefile. duke3d.h global.c + +game.obj : game.c $(globaldependencies) + wcc386 game $(compileoptions) +actors.obj : actors.c $(globaldependencies) + wcc386 actors $(compileoptions) +gamedef.obj : gamedef.c $(globaldependencies) + wcc386 gamedef $(compileoptions) +global.obj : global.c $(globaldependencies) + wcc386 global $(compileoptions) +menues.obj : menues.c $(globaldependencies) + wcc386 menues $(compileoptions) +player.obj : player.c $(globaldependencies) + wcc386 player $(compileoptions) +premap.obj : premap.c $(globaldependencies) + wcc386 premap $(compileoptions) +sector.obj : sector.c $(globaldependencies) + wcc386 sector $(compileoptions) +sounds.obj : sounds.c $(globaldependencies) + wcc386 sounds /zu $(compileoptions) +rts.obj : rts.c $(globaldependencies) + wcc386 rts $(compileoptions) +config.obj : config.c $(globaldependencies) + wcc386 config $(compileoptions) +animlib.obj : animlib.c $(globaldependencies) + wcc386 animlib $(compileoptions) + diff --git a/menues.c b/menues.c new file mode 100755 index 0000000..095de0f --- /dev/null +++ b/menues.c @@ -0,0 +1,4074 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment + +This file is part of Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Original Source: 1996 - Todd Replogle +Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms +*/ +//------------------------------------------------------------------------- + +#include "duke3d.h" +#include "mouse.h" +#include "animlib.h" + +/* this should be a proper prototype included from a header file */ +extern int stricmp(const char *x, const char *y); + +extern short inputloc; +extern int recfilep; +extern char vgacompatible; +short probey=0,lastprobey=0,last_menu,globalskillsound=-1; +short sh,onbar,buttonstat,deletespot; +short last_zero,last_fifty,last_threehundred = 0; +static char fileselect = 1, menunamecnt, menuname[256][17], curpath[80], menupath[80]; + +int ignore_escape = 0; + +// CTW - REMOVED +/* Error codes */ +/* +#define eTenBnNotInWindows 3801 +#define eTenBnBadGameIni 3802 +#define eTenBnBadTenIni 3803 +#define eTenBnBrowseCancel 3804 +#define eTenBnBadTenInst 3805 + +int tenBnStart(void); +void tenBnSetBrowseRtn(char *(*rtn)(char *str, int len)); +void tenBnSetExitRtn(void (*rtn)(void)); +void tenBnSetEndRtn(void (*rtn)(void));*/ +// CTW END - REMOVED + +void dummyfunc(void) +{ +} + +void dummymess(int i,char *c) +{ +} + +// CTW - REMOVED +/* +void TENtext(void) +{ + long dacount,dalastcount; + + puts("\nDuke Nukem 3D has been licensed exclusively to TEN (Total"); + puts("Entertainment Network) for wide-area networked (WAN) multiplayer"); + puts("games.\n"); + + puts("The multiplayer code within Duke Nukem 3D has been highly"); + puts("customized to run best on TEN, where you'll experience fast and"); + puts("stable performance, plus other special benefits.\n"); + + puts("We do not authorize or recommend the use of Duke Nukem 3D with"); + puts("gaming services other than TEN.\n"); + + puts("Duke Nukem 3D is protected by United States copyright law and"); + puts("international treaty.\n"); + + puts("For the best online multiplayer gaming experience, please call TEN"); + puts("at 800-8040-TEN, or visit TEN's Web Site at www.ten.net.\n"); + + puts("Press any key to continue.\n"); + + _bios_timeofday(0,&dacount); + + while( _bios_keybrd(1) == 0 ) + { + _bios_timeofday(0,&dalastcount); + if( (dacount+240) < dalastcount ) break; + } +} +*/ +// CTW END - REMOVED + +void cmenu(short cm) +{ + current_menu = cm; + + if( (cm >= 1000 && cm <= 1009) ) + return; + + if( cm == 0 ) + probey = last_zero; + else if(cm == 50) + probey = last_fifty; + else if(cm >= 300 && cm < 400) + probey = last_threehundred; + else if(cm == 110) + probey = 1; + else probey = 0; + lastprobey = -1; +} + + +void savetemp(char *fn,long daptr,long dasiz) +{ + int fp; + + fp = open(fn,O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP); + + write(fp,(char *)daptr,dasiz); + + close(fp); +} + +void getangplayers(short snum) +{ + short i,a; + + for(i=connecthead;i>=0;i=connectpoint2[i]) + { + if(i != snum) + { + a = ps[snum].ang+getangle(ps[i].posx-ps[snum].posx,ps[i].posy-ps[snum].posy); + a = a-1024; + rotatesprite( + (320<<15) + (((sintable[(a+512)&2047])>>7)<<15), + (320<<15) - (((sintable[a&2047])>>8)<<15), + klabs(sintable[((a>>1)+768)&2047]<<2),0,APLAYER,0,ps[i].palookup,0,0,0,xdim-1,ydim-1); + } + } +} + +static int loadpheader(char spot,int32 *vn,int32 *ln,int32 *psk,int32 *nump) +{ + + long i; + char filename[] = "game0.sav"; + char fullname[256]; + long fil; + long bv = 0; + + filename[4] = spot+'0'; + GetPathFromEnvironment(fullname, 128, filename); + + if ((fil = kopen4load(fullname,0)) == -1) return(-1); + + walock[MAXTILES-3] = 255; + + kdfread(&bv,4,1,fil); + if(bv != BYTEVERSION) + { + FTA(114,&ps[myconnectindex]); + kclose(fil); + return 1; + } + + kdfread(nump,4,1,fil); + + kdfread(tempbuf,19,1,fil); + kdfread(vn,4,1,fil); + kdfread(ln,4,1,fil); + kdfread(psk,4,1,fil); + + if (waloff[MAXTILES-3] == 0) allocache(&waloff[MAXTILES-3],160*100,&walock[MAXTILES-3]); + tilesizx[MAXTILES-3] = 100; tilesizy[MAXTILES-3] = 160; + kdfread((char *)waloff[MAXTILES-3],160,100,fil); + + kclose(fil); + + return(0); +} + + +int loadplayer(signed char spot) +{ + short k,music_changed; + char fn[] = "game0.sav"; + char mpfn[] = "gameA_00.sav"; + char fullname[128]; + char *fnptr, scriptptrs[MAXSCRIPTSIZE]; + long fil, bv, i, j, x; + int32 nump; + + if(spot < 0) + { + multiflag = 1; + multiwhat = 0; + multipos = -spot-1; + return -1; + } + + if( multiflag == 2 && multiwho != myconnectindex ) + { + mpfn[4] = spot + 'A'; + + if(ud.multimode > 9) + { + mpfn[6] = (multiwho/10) + '0'; + mpfn[7] = (multiwho%10) + '0'; + } + else mpfn[7] = multiwho + '0'; + + GetPathFromEnvironment(fullname, 128, mpfn); + fnptr = fullname; + } + else + { + fn[4] = spot + '0'; + + GetPathFromEnvironment(fullname, 128, fn); + fnptr = fullname; + } + + if ((fil = kopen4load(fnptr,0)) == -1) return(-1); + + ready2send = 0; + + kdfread(&bv,4,1,fil); + if(bv != BYTEVERSION) + { + FTA(114,&ps[myconnectindex]); + kclose(fil); + ototalclock = totalclock; + ready2send = 1; + return 1; + } + + kdfread(&nump,4,1,fil); + if(nump != numplayers) + { + kclose(fil); + ototalclock = totalclock; + ready2send = 1; + FTA(124,&ps[myconnectindex]); + return 1; + } + + if(numplayers > 1) + { + pub = NUMPAGES; + pus = NUMPAGES; + vscrn(); + drawbackground(); + menutext(160,100,0,0,"LOADING..."); + nextpage(); + } + + waitforeverybody(); + + FX_StopAllSounds(); + clearsoundlocks(); + MUSIC_StopSong(); + + if(numplayers > 1) + kdfread(&buf,19,1,fil); + else + kdfread(&ud.savegame[spot][0],19,1,fil); + + music_changed = (music_select != (ud.volume_number*11) + ud.level_number); + + kdfread(&ud.volume_number,4,1,fil); + kdfread(&ud.level_number,4,1,fil); + kdfread(&ud.player_skill,4,1,fil); + + ud.m_level_number = ud.level_number; + ud.m_volume_number = ud.volume_number; + ud.m_player_skill = ud.player_skill; + + //Fake read because lseek won't work with compression + walock[MAXTILES-3] = 1; + if (waloff[MAXTILES-3] == 0) allocache(&waloff[MAXTILES-3],160*100,&walock[MAXTILES-3]); + tilesizx[MAXTILES-3] = 100; tilesizy[MAXTILES-3] = 160; + kdfread((char *)waloff[MAXTILES-3],160,100,fil); + + kdfread(&numwalls,2,1,fil); + kdfread(&wall[0],sizeof(walltype),MAXWALLS,fil); + kdfread(&numsectors,2,1,fil); + kdfread(§or[0],sizeof(sectortype),MAXSECTORS,fil); + kdfread(&sprite[0],sizeof(spritetype),MAXSPRITES,fil); + kdfread(&headspritesect[0],2,MAXSECTORS+1,fil); + kdfread(&prevspritesect[0],2,MAXSPRITES,fil); + kdfread(&nextspritesect[0],2,MAXSPRITES,fil); + kdfread(&headspritestat[0],2,MAXSTATUS+1,fil); + kdfread(&prevspritestat[0],2,MAXSPRITES,fil); + kdfread(&nextspritestat[0],2,MAXSPRITES,fil); + kdfread(&numcyclers,sizeof(numcyclers),1,fil); + kdfread(&cyclers[0][0],12,MAXCYCLERS,fil); + kdfread(ps,sizeof(ps),1,fil); + kdfread(po,sizeof(po),1,fil); + kdfread(&numanimwalls,sizeof(numanimwalls),1,fil); + kdfread(&animwall,sizeof(animwall),1,fil); + kdfread(&msx[0],sizeof(long),sizeof(msx)/sizeof(long),fil); + kdfread(&msy[0],sizeof(long),sizeof(msy)/sizeof(long),fil); + kdfread((short *)&spriteqloc,sizeof(short),1,fil); + kdfread((short *)&spriteqamount,sizeof(short),1,fil); + kdfread((short *)&spriteq[0],sizeof(short),spriteqamount,fil); + kdfread(&mirrorcnt,sizeof(short),1,fil); + kdfread(&mirrorwall[0],sizeof(short),64,fil); + kdfread(&mirrorsector[0],sizeof(short),64,fil); + kdfread(&show2dsector[0],sizeof(char),MAXSECTORS>>3,fil); + kdfread(&actortype[0],sizeof(char),MAXTILES,fil); + kdfread(&boardfilename[0],sizeof(boardfilename),1,fil); + + kdfread(&numclouds,sizeof(numclouds),1,fil); + kdfread(&clouds[0],sizeof(short)<<7,1,fil); + kdfread(&cloudx[0],sizeof(short)<<7,1,fil); + kdfread(&cloudy[0],sizeof(short)<<7,1,fil); + + kdfread(&scriptptrs[0],1,MAXSCRIPTSIZE,fil); + kdfread(&script[0],4,MAXSCRIPTSIZE,fil); + for(i=0;i=0;i--) animateptr[i] = (long *)((long)animateptr[i]+(long)(§or[0])); + kdfread(&animategoal[0],4,MAXANIMATES,fil); + kdfread(&animatevel[0],4,MAXANIMATES,fil); + + kdfread(&earthquaketime,sizeof(earthquaketime),1,fil); + kdfread(&ud.from_bonus,sizeof(ud.from_bonus),1,fil); + kdfread(&ud.secretlevel,sizeof(ud.secretlevel),1,fil); + kdfread(&ud.respawn_monsters,sizeof(ud.respawn_monsters),1,fil); + ud.m_respawn_monsters = ud.respawn_monsters; + kdfread(&ud.respawn_items,sizeof(ud.respawn_items),1,fil); + ud.m_respawn_items = ud.respawn_items; + kdfread(&ud.respawn_inventory,sizeof(ud.respawn_inventory),1,fil); + ud.m_respawn_inventory = ud.respawn_inventory; + + kdfread(&ud.god,sizeof(ud.god),1,fil); + kdfread(&ud.auto_run,sizeof(ud.auto_run),1,fil); + kdfread(&ud.crosshair,sizeof(ud.crosshair),1,fil); + kdfread(&ud.monsters_off,sizeof(ud.monsters_off),1,fil); + ud.m_monsters_off = ud.monsters_off; + kdfread(&ud.last_level,sizeof(ud.last_level),1,fil); + kdfread(&ud.eog,sizeof(ud.eog),1,fil); + + kdfread(&ud.coop,sizeof(ud.coop),1,fil); + ud.m_coop = ud.coop; + kdfread(&ud.marker,sizeof(ud.marker),1,fil); + ud.m_marker = ud.marker; + kdfread(&ud.ffire,sizeof(ud.ffire),1,fil); + ud.m_ffire = ud.ffire; + + kdfread(&camsprite,sizeof(camsprite),1,fil); + kdfread(&connecthead,sizeof(connecthead),1,fil); + kdfread(connectpoint2,sizeof(connectpoint2),1,fil); + kdfread(&numplayersprites,sizeof(numplayersprites),1,fil); + kdfread((short *)&frags[0][0],sizeof(frags),1,fil); + + kdfread(&randomseed,sizeof(randomseed),1,fil); + kdfread(&global_random,sizeof(global_random),1,fil); + kdfread(¶llaxyscale,sizeof(parallaxyscale),1,fil); + + kclose(fil); + + if(ps[myconnectindex].over_shoulder_on != 0) + { + cameradist = 0; + cameraclock = 0; + ps[myconnectindex].over_shoulder_on = 1; + } + + screenpeek = myconnectindex; + + clearbufbyte(gotpic,sizeof(gotpic),0L); + clearsoundlocks(); + cacheit(); + docacheit(); + + if(music_changed == 0) + music_select = (ud.volume_number*11) + ud.level_number; + playmusic(&music_fn[0][(int)music_select][0]); + + ps[myconnectindex].gm = MODE_GAME; + ud.recstat = 0; + + if(ps[myconnectindex].jetpack_on) + spritesound(DUKE_JETPACK_IDLE,ps[myconnectindex].i); + + restorepalette = 1; + setpal(&ps[myconnectindex]); + vscrn(); + + FX_SetReverb(0); + + if(ud.lockout == 0) + { + for(x=0;x= 0 ) + wall[animwall[x].wallnum].picnum = wall[animwall[x].wallnum].extra; + } + else + { + for(x=0;x= 0) + { + switch(sprite[k].lotag) + { + case 31: + setinterpolation(§or[sprite[k].sectnum].floorz); + break; + case 32: + setinterpolation(§or[sprite[k].sectnum].ceilingz); + break; + case 25: + setinterpolation(§or[sprite[k].sectnum].floorz); + setinterpolation(§or[sprite[k].sectnum].ceilingz); + break; + case 17: + setinterpolation(§or[sprite[k].sectnum].floorz); + setinterpolation(§or[sprite[k].sectnum].ceilingz); + break; + case 0: + case 5: + case 6: + case 11: + case 14: + case 15: + case 16: + case 26: + case 30: + setsectinterpolate(k); + break; + } + + k = nextspritestat[k]; + } + + for(i=numinterpolations-1;i>=0;i--) bakipos[i] = *curipos[i]; + for(i = animatecnt-1;i>=0;i--) + setinterpolation(animateptr[i]); + + show_shareware = 0; + everyothertime = 0; + + clearbufbyte(playerquitflag,MAXPLAYERS,0x01010101); + + resetmys(); + + ready2send = 1; + + flushpackets(); + clearfifo(); + waitforeverybody(); + + resettimevars(); + + return(0); +} + +int saveplayer(signed char spot) +{ + long i, j; + char fn[] = "game0.sav"; + char mpfn[] = "gameA_00.sav"; + char fullname[128]; + char *fnptr,scriptptrs[MAXSCRIPTSIZE]; + FILE *fil; + long bv = BYTEVERSION; + + if(spot < 0) + { + multiflag = 1; + multiwhat = 1; + multipos = -spot-1; + return -1; + } + + waitforeverybody(); + + if( multiflag == 2 && multiwho != myconnectindex ) + { + mpfn[4] = spot + 'A'; + + if(ud.multimode > 9) + { + mpfn[6] = (multiwho/10) + '0'; + mpfn[7] = multiwho + '0'; + } + else mpfn[7] = multiwho + '0'; + + GetPathFromEnvironment(fullname, 128, mpfn); + fnptr = fullname; + } + else + { + fn[4] = spot + '0'; + + GetPathFromEnvironment(fullname, 128, fn); + fnptr = fullname; + } + + if ((fil = fopen(fnptr,"wb")) == 0) return(-1); + + ready2send = 0; + + dfwrite(&bv,4,1,fil); + dfwrite(&ud.multimode,sizeof(ud.multimode),1,fil); + + dfwrite(&ud.savegame[spot][0],19,1,fil); + dfwrite(&ud.volume_number,sizeof(ud.volume_number),1,fil); + dfwrite(&ud.level_number,sizeof(ud.level_number),1,fil); + dfwrite(&ud.player_skill,sizeof(ud.player_skill),1,fil); + dfwrite((char *)waloff[MAXTILES-1],160,100,fil); + + dfwrite(&numwalls,2,1,fil); + dfwrite(&wall[0],sizeof(walltype),MAXWALLS,fil); + dfwrite(&numsectors,2,1,fil); + dfwrite(§or[0],sizeof(sectortype),MAXSECTORS,fil); + dfwrite(&sprite[0],sizeof(spritetype),MAXSPRITES,fil); + dfwrite(&headspritesect[0],2,MAXSECTORS+1,fil); + dfwrite(&prevspritesect[0],2,MAXSPRITES,fil); + dfwrite(&nextspritesect[0],2,MAXSPRITES,fil); + dfwrite(&headspritestat[0],2,MAXSTATUS+1,fil); + dfwrite(&prevspritestat[0],2,MAXSPRITES,fil); + dfwrite(&nextspritestat[0],2,MAXSPRITES,fil); + dfwrite(&numcyclers,sizeof(numcyclers),1,fil); + dfwrite(&cyclers[0][0],12,MAXCYCLERS,fil); + dfwrite(ps,sizeof(ps),1,fil); + dfwrite(po,sizeof(po),1,fil); + dfwrite(&numanimwalls,sizeof(numanimwalls),1,fil); + dfwrite(&animwall,sizeof(animwall),1,fil); + dfwrite(&msx[0],sizeof(long),sizeof(msx)/sizeof(long),fil); + dfwrite(&msy[0],sizeof(long),sizeof(msy)/sizeof(long),fil); + dfwrite(&spriteqloc,sizeof(short),1,fil); + dfwrite(&spriteqamount,sizeof(short),1,fil); + dfwrite(&spriteq[0],sizeof(short),spriteqamount,fil); + dfwrite(&mirrorcnt,sizeof(short),1,fil); + dfwrite(&mirrorwall[0],sizeof(short),64,fil); + dfwrite(&mirrorsector[0],sizeof(short),64,fil); + dfwrite(&show2dsector[0],sizeof(char),MAXSECTORS>>3,fil); + dfwrite(&actortype[0],sizeof(char),MAXTILES,fil); + dfwrite(&boardfilename[0],sizeof(boardfilename),1,fil); + + dfwrite(&numclouds,sizeof(numclouds),1,fil); + dfwrite(&clouds[0],sizeof(short)<<7,1,fil); + dfwrite(&cloudx[0],sizeof(short)<<7,1,fil); + dfwrite(&cloudy[0],sizeof(short)<<7,1,fil); + + for(i=0;i= (long)(&script[0]) && (long)script[i] < (long)(&script[MAXSCRIPTSIZE]) ) + { + scriptptrs[i] = 1; + j = (long)script[i] - (long)&script[0]; + script[i] = j; + } + else scriptptrs[i] = 0; + } + + dfwrite(&scriptptrs[0],1,MAXSCRIPTSIZE,fil); + dfwrite(&script[0],4,MAXSCRIPTSIZE,fil); + + for(i=0;i= j && T2 < (long)(&script[MAXSCRIPTSIZE]) ) + { + scriptptrs[i] |= 1; + T2 -= j; + } + if(T5 >= j && T5 < (long)(&script[MAXSCRIPTSIZE]) ) + { + scriptptrs[i] |= 2; + T5 -= j; + } + if(T6 >= j && T6 < (long)(&script[MAXSCRIPTSIZE]) ) + { + scriptptrs[i] |= 4; + T6 -= j; + } + } + + dfwrite(&scriptptrs[0],1,MAXSPRITES,fil); + dfwrite(&hittype[0],sizeof(struct weaponhit),MAXSPRITES,fil); + + for(i=0;i=0;i--) animateptr[i] = (long *)((long)animateptr[i]-(long)(§or[0])); + dfwrite(&animateptr[0],4,MAXANIMATES,fil); + for(i = animatecnt-1;i>=0;i--) animateptr[i] = (long *)((long)animateptr[i]+(long)(§or[0])); + dfwrite(&animategoal[0],4,MAXANIMATES,fil); + dfwrite(&animatevel[0],4,MAXANIMATES,fil); + + dfwrite(&earthquaketime,sizeof(earthquaketime),1,fil); + dfwrite(&ud.from_bonus,sizeof(ud.from_bonus),1,fil); + dfwrite(&ud.secretlevel,sizeof(ud.secretlevel),1,fil); + dfwrite(&ud.respawn_monsters,sizeof(ud.respawn_monsters),1,fil); + dfwrite(&ud.respawn_items,sizeof(ud.respawn_items),1,fil); + dfwrite(&ud.respawn_inventory,sizeof(ud.respawn_inventory),1,fil); + dfwrite(&ud.god,sizeof(ud.god),1,fil); + dfwrite(&ud.auto_run,sizeof(ud.auto_run),1,fil); + dfwrite(&ud.crosshair,sizeof(ud.crosshair),1,fil); + dfwrite(&ud.monsters_off,sizeof(ud.monsters_off),1,fil); + dfwrite(&ud.last_level,sizeof(ud.last_level),1,fil); + dfwrite(&ud.eog,sizeof(ud.eog),1,fil); + dfwrite(&ud.coop,sizeof(ud.coop),1,fil); + dfwrite(&ud.marker,sizeof(ud.marker),1,fil); + dfwrite(&ud.ffire,sizeof(ud.ffire),1,fil); + dfwrite(&camsprite,sizeof(camsprite),1,fil); + dfwrite(&connecthead,sizeof(connecthead),1,fil); + dfwrite(connectpoint2,sizeof(connectpoint2),1,fil); + dfwrite(&numplayersprites,sizeof(numplayersprites),1,fil); + dfwrite((short *)&frags[0][0],sizeof(frags),1,fil); + + dfwrite(&randomseed,sizeof(randomseed),1,fil); + dfwrite(&global_random,sizeof(global_random),1,fil); + dfwrite(¶llaxyscale,sizeof(parallaxyscale),1,fil); + + fclose(fil); + + if(ud.multimode < 2) + { + strcpy(fta_quotes[122],"GAME SAVED"); + FTA(122,&ps[myconnectindex]); + } + + ready2send = 1; + + waitforeverybody(); + + ototalclock = totalclock; + + return(0); +} + +#define LMB (buttonstat&1) +#define RMB (buttonstat&2) + +ControlInfo minfo; + +long mi; + +static int probe_with_delete(int x,int y,int i,int n,int *hitdelete) +{ + short centre, s; + + s = 1+(CONTROL_GetMouseSensitivity()>>4); + + if( ControllerType == 1 && CONTROL_MousePresent ) + { + CONTROL_GetInput( &minfo ); + mi += minfo.dz; + } + + else minfo.dz = minfo.dyaw = 0; + + if( x == (320>>1) ) + centre = 320>>2; + else centre = 0; + + if(!buttonstat) + { + if( KB_KeyPressed( sc_UpArrow ) || KB_KeyPressed( sc_PgUp ) || KB_KeyPressed( sc_kpad_8 ) || + mi < -8192 ) + { + mi = 0; + KB_ClearKeyDown( sc_UpArrow ); + KB_ClearKeyDown( sc_kpad_8 ); + KB_ClearKeyDown( sc_PgUp ); + sound(KICK_HIT); + + probey--; + if(probey < 0) probey = n-1; + minfo.dz = 0; + } + if( KB_KeyPressed( sc_DownArrow ) || KB_KeyPressed( sc_PgDn ) || KB_KeyPressed( sc_kpad_2 ) + || mi > 8192 ) + { + mi = 0; + KB_ClearKeyDown( sc_DownArrow ); + KB_ClearKeyDown( sc_kpad_2 ); + KB_ClearKeyDown( sc_PgDn ); + sound(KICK_HIT); + probey++; + minfo.dz = 0; + } + } + + if(probey >= n) + probey = 0; + + if(centre) + { +// rotatesprite(((320>>1)+(centre)+54)<<16,(y+(probey*i)-4)<<16,65536L,0,SPINNINGNUKEICON+6-((6+(totalclock>>3))%7),sh,0,10,0,0,xdim-1,ydim-1); +// rotatesprite(((320>>1)-(centre)-54)<<16,(y+(probey*i)-4)<<16,65536L,0,SPINNINGNUKEICON+((totalclock>>3)%7),sh,0,10,0,0,xdim-1,ydim-1); + + rotatesprite(((320>>1)+(centre>>1)+70)<<16,(y+(probey*i)-4)<<16,65536L,0,SPINNINGNUKEICON+6-((6+(totalclock>>3))%7),sh,0,10,0,0,xdim-1,ydim-1); + rotatesprite(((320>>1)-(centre>>1)-70)<<16,(y+(probey*i)-4)<<16,65536L,0,SPINNINGNUKEICON+((totalclock>>3)%7),sh,0,10,0,0,xdim-1,ydim-1); + } + else + rotatesprite((x-tilesizx[BIGFNTCURSOR]-4)<<16,(y+(probey*i)-4)<<16,65536L,0,SPINNINGNUKEICON+(((totalclock>>3))%7),sh,0,10,0,0,xdim-1,ydim-1); + + if (hitdelete != NULL) + { + *hitdelete = ((KB_KeyPressed(sc_Delete)) || + (KB_KeyPressed(sc_BackSpace)) || + (KB_KeyPressed(sc_kpad_Period))); + + if (*hitdelete) + { + sound(KICK_HIT); + KB_ClearKeyDown(sc_Delete); + KB_ClearKeyDown(sc_BackSpace); + KB_ClearKeyDown(sc_kpad_Period); + return(probey); + } + } + + if( KB_KeyPressed(sc_Space) || KB_KeyPressed( sc_kpad_Enter ) || KB_KeyPressed( sc_Enter ) || (LMB && !onbar) ) + { + if(current_menu != 110) + sound(PISTOL_BODYHIT); + KB_ClearKeyDown( sc_Enter ); + KB_ClearKeyDown( sc_Space ); + KB_ClearKeyDown( sc_kpad_Enter ); + return(probey); + } + else if( KB_KeyPressed( sc_Escape ) || (RMB) ) + { + onbar = 0; + KB_ClearKeyDown( sc_Escape ); + sound(EXITMENUSOUND); + return(-1); + } + else + { + if(onbar == 0) return(-probey-2); + if ( KB_KeyPressed( sc_LeftArrow ) || KB_KeyPressed( sc_kpad_4 ) || ((buttonstat&1) && minfo.dyaw < -128 ) ) + return(probey); + else if ( KB_KeyPressed( sc_RightArrow ) || KB_KeyPressed( sc_kpad_6 ) || ((buttonstat&1) && minfo.dyaw > 128 ) ) + return(probey); + else return(-probey-2); + } +} + +int probe(int x,int y,int i,int n) +{ + return probe_with_delete(x,y,i,n,NULL); +} + +int menutext(int x,int y,short s,short p,char *t) +{ + short i, ac, centre; + + y -= 12; + + i = centre = 0; + + if( x == (320>>1) ) + { + while( *(t+i) ) + { + if(*(t+i) == ' ') + { + centre += 5; + i++; + continue; + } + ac = 0; + if(*(t+i) >= '0' && *(t+i) <= '9') + ac = *(t+i) - '0' + BIGALPHANUM-10; + else if(*(t+i) >= 'a' && *(t+i) <= 'z') + ac = toupper(*(t+i)) - 'A' + BIGALPHANUM; + else if(*(t+i) >= 'A' && *(t+i) <= 'Z') + ac = *(t+i) - 'A' + BIGALPHANUM; + else switch(*(t+i)) + { + case '-': + ac = BIGALPHANUM-11; + break; + case '.': + ac = BIGPERIOD; + break; + case '\'': + ac = BIGAPPOS; + break; + case ',': + ac = BIGCOMMA; + break; + case '!': + ac = BIGX; + break; + case '?': + ac = BIGQ; + break; + case ';': + ac = BIGSEMI; + break; + case ':': + ac = BIGSEMI; + break; + default: + centre += 5; + i++; + continue; + } + + centre += tilesizx[ac]-1; + i++; + } + } + + if(centre) + x = (320-centre-10)>>1; + + while(*t) + { + if(*t == ' ') {x+=5;t++;continue;} + ac = 0; + if(*t >= '0' && *t <= '9') + ac = *t - '0' + BIGALPHANUM-10; + else if(*t >= 'a' && *t <= 'z') + ac = toupper(*t) - 'A' + BIGALPHANUM; + else if(*t >= 'A' && *t <= 'Z') + ac = *t - 'A' + BIGALPHANUM; + else switch(*t) + { + case '-': + ac = BIGALPHANUM-11; + break; + case '.': + ac = BIGPERIOD; + break; + case ',': + ac = BIGCOMMA; + break; + case '!': + ac = BIGX; + break; + case '\'': + ac = BIGAPPOS; + break; + case '?': + ac = BIGQ; + break; + case ';': + ac = BIGSEMI; + break; + case ':': + ac = BIGCOLIN; + break; + default: + x += 5; + t++; + continue; + } + + rotatesprite(x<<16,y<<16,65536L,0,ac,s,p,10+16,0,0,xdim-1,ydim-1); + + x += tilesizx[ac]; + t++; + } + return (x); +} + + +int menutextc(int x,int y,short s,short p,char *t) +{ + short i, ac, centre; + + s += 8; + y -= 12; + + i = centre = 0; + +// if( x == (320>>1) ) + { + while( *(t+i) ) + { + if(*(t+i) == ' ') + { + centre += 5; + i++; + continue; + } + ac = 0; + if(*(t+i) >= '0' && *(t+i) <= '9') + ac = *(t+i) - '0' + BIGALPHANUM+26+26; + if(*(t+i) >= 'a' && *(t+i) <= 'z') + ac = *(t+i) - 'a' + BIGALPHANUM+26; + if(*(t+i) >= 'A' && *(t+i) <= 'Z') + ac = *(t+i) - 'A' + BIGALPHANUM; + + else switch(*t) + { + case '-': + ac = BIGALPHANUM-11; + break; + case '.': + ac = BIGPERIOD; + break; + case ',': + ac = BIGCOMMA; + break; + case '!': + ac = BIGX; + break; + case '?': + ac = BIGQ; + break; + case ';': + ac = BIGSEMI; + break; + case ':': + ac = BIGCOLIN; + break; + } + + centre += tilesizx[ac]-1; + i++; + } + } + + x -= centre>>1; + + while(*t) + { + if(*t == ' ') {x+=5;t++;continue;} + ac = 0; + if(*t >= '0' && *t <= '9') + ac = *t - '0' + BIGALPHANUM+26+26; + if(*t >= 'a' && *t <= 'z') + ac = *t - 'a' + BIGALPHANUM+26; + if(*t >= 'A' && *t <= 'Z') + ac = *t - 'A' + BIGALPHANUM; + switch(*t) + { + case '-': + ac = BIGALPHANUM-11; + break; + case '.': + ac = BIGPERIOD; + break; + case ',': + ac = BIGCOMMA; + break; + case '!': + ac = BIGX; + break; + case '?': + ac = BIGQ; + break; + case ';': + ac = BIGSEMI; + break; + case ':': + ac = BIGCOLIN; + break; + } + + rotatesprite(x<<16,y<<16,65536L,0,ac,s,p,10+16,0,0,xdim-1,ydim-1); + + x += tilesizx[ac]; + t++; + } + return (x); +} + + +void bar(int x,int y,short *p,short dainc,char damodify,short s, short pa) +{ + short xloc; + char rev; + + if(dainc < 0) { dainc = -dainc; rev = 1; } + else rev = 0; + y-=2; + + if(damodify) + { + if(rev == 0) + { + if( KB_KeyPressed( sc_LeftArrow ) || KB_KeyPressed( sc_kpad_4 ) || ((buttonstat&1) && minfo.dyaw < -256 ) ) // && onbar) ) + { + KB_ClearKeyDown( sc_LeftArrow ); + KB_ClearKeyDown( sc_kpad_4 ); + + *p -= dainc; + if(*p < 0) + *p = 0; + sound(KICK_HIT); + } + if( KB_KeyPressed( sc_RightArrow ) || KB_KeyPressed( sc_kpad_6 ) || ((buttonstat&1) && minfo.dyaw > 256 ) )//&& onbar) ) + { + KB_ClearKeyDown( sc_RightArrow ); + KB_ClearKeyDown( sc_kpad_6 ); + + *p += dainc; + if(*p > 63) + *p = 63; + sound(KICK_HIT); + } + } + else + { + if( KB_KeyPressed( sc_RightArrow ) || KB_KeyPressed( sc_kpad_6 ) || ((buttonstat&1) && minfo.dyaw > 256 ))//&& onbar )) + { + KB_ClearKeyDown( sc_RightArrow ); + KB_ClearKeyDown( sc_kpad_6 ); + + *p -= dainc; + if(*p < 0) + *p = 0; + sound(KICK_HIT); + } + if( KB_KeyPressed( sc_LeftArrow ) || KB_KeyPressed( sc_kpad_4 ) || ((buttonstat&1) && minfo.dyaw < -256 ))// && onbar) ) + { + KB_ClearKeyDown( sc_LeftArrow ); + KB_ClearKeyDown( sc_kpad_4 ); + + *p += dainc; + if(*p > 64) + *p = 64; + sound(KICK_HIT); + } + } + } + + xloc = *p; + + rotatesprite( (x+22)<<16,(y-3)<<16,65536L,0,SLIDEBAR,s,pa,10,0,0,xdim-1,ydim-1); + if(rev == 0) + rotatesprite( (x+xloc+1)<<16,(y+1)<<16,65536L,0,SLIDEBAR+1,s,pa,10,0,0,xdim-1,ydim-1); + else + rotatesprite( (x+(65-xloc) )<<16,(y+1)<<16,65536L,0,SLIDEBAR+1,s,pa,10,0,0,xdim-1,ydim-1); +} + +#define SHX(X) 0 +// ((x==X)*(-sh)) +#define PHX(X) 0 +// ((x==X)?1:2) +#define MWIN(X) rotatesprite( 320<<15,200<<15,X,0,MENUSCREEN,-16,0,10+64,0,0,xdim-1,ydim-1) +#define MWINXY(X,OX,OY) rotatesprite( ( 320+(OX) )<<15, ( 200+(OY) )<<15,X,0,MENUSCREEN,-16,0,10+64,0,0,xdim-1,ydim-1) + + +int32 volnum,levnum,plrskl,numplr; +short lastsavedpos = -1; + +void dispnames(void) +{ + short x, c = 160; + + c += 64; + for(x = 0;x <= 108;x += 12) + rotatesprite((c+91-64)<<16,(x+56)<<16,65536L,0,TEXTBOX,24,0,10,0,0,xdim-1,ydim-1); + + rotatesprite(22<<16,97<<16,65536L,0,WINDOWBORDER2,24,0,10,0,0,xdim-1,ydim-1); + rotatesprite(180<<16,97<<16,65536L,1024,WINDOWBORDER2,24,0,10,0,0,xdim-1,ydim-1); + rotatesprite(99<<16,50<<16,65536L,512,WINDOWBORDER1,24,0,10,0,0,xdim-1,ydim-1); + rotatesprite(103<<16,144<<16,65536L,1024+512,WINDOWBORDER1,24,0,10,0,0,xdim-1,ydim-1); + + minitext(c,48,ud.savegame[0],2,10+16); + minitext(c,48+12,ud.savegame[1],2,10+16); + minitext(c,48+12+12,ud.savegame[2],2,10+16); + minitext(c,48+12+12+12,ud.savegame[3],2,10+16); + minitext(c,48+12+12+12+12,ud.savegame[4],2,10+16); + minitext(c,48+12+12+12+12+12,ud.savegame[5],2,10+16); + minitext(c,48+12+12+12+12+12+12,ud.savegame[6],2,10+16); + minitext(c,48+12+12+12+12+12+12+12,ud.savegame[7],2,10+16); + minitext(c,48+12+12+12+12+12+12+12+12,ud.savegame[8],2,10+16); + minitext(c,48+12+12+12+12+12+12+12+12+12,ud.savegame[9],2,10+16); + +} + + +// This is the same thing as was in build.c ... +// We DO have a _dos_findfirst implementation now...maybe use that instead? +// --ryan. +#if ORIGINAL_DUKE3D_GETFILENAMES +int getfilenames(char kind[6]) +{ + short type; + struct find_t fileinfo; + + if (strcmp(kind,"SUBD") == 0) + { + strcpy(kind,"*.*"); + if (_dos_findfirst(kind,_A_SUBDIR,&fileinfo) != 0) + return(-1); + type = 1; + } + else + { + if (_dos_findfirst(kind,_A_NORMAL,&fileinfo) != 0) + return(-1); + type = 0; + } + do + { + if ((type == 0) || ((fileinfo.attrib&16) > 0)) + if ((fileinfo.name[0] != '.') || (fileinfo.name[1] != 0)) + { + strcpy(menuname[menunamecnt],fileinfo.name); + menuname[menunamecnt][16] = type; + menunamecnt++; + } + } + while (_dos_findnext(&fileinfo) == 0); + + return(0); +} + +#else + +int getfilenames(char kind[6]) +{ +/* !!! FIXME: Visual C? */ +#if (defined __WATCOMC__) + short type; + struct find_t fileinfo; + + if (strcmp(kind,"SUBD") == 0) + { + strcpy(kind,"*.*"); + if (_dos_findfirst(kind,_A_SUBDIR,&fileinfo) != 0) + return(-1); + type = 1; + } + else + { + if (_dos_findfirst(kind,_A_NORMAL,&fileinfo) != 0) + return(-1); + type = 0; + } + do + { + if ((type == 0) || ((fileinfo.attrib&16) > 0)) + if ((fileinfo.name[0] != '.') || (fileinfo.name[1] != 0)) + { + strcpy(menuname[menunamecnt],fileinfo.name); + menuname[menunamecnt][16] = type; + menunamecnt++; + } + } + while (_dos_findnext(&fileinfo) == 0); + +#elif (defined PLATFORM_UNIX) + + DIR *dir; + struct dirent *dent; + struct stat statbuf; + int add_this; + char *ptr = NULL; + int len = 0; + int subdirs = 0; + + if (strcmp(kind,"SUBD") == 0) + subdirs = 1; + + dir = opendir("."); + if (dir == NULL) + return(-1); + + do + { + add_this = 0; + dent = readdir(dir); + if (dent != NULL) + { +#ifndef DC + if (stat(dent->d_name, &statbuf) == 0) +#endif + { + if (subdirs) + { +#ifdef DC + if (dent->size==-1) +#else + if (S_ISDIR(statbuf.st_mode)) +#endif + add_this = 1; + } /* if */ + else + { + /* need to expand support if this assertion ever fails. */ + assert(stricmp(kind, "*.MAP") == 0); + len = strlen(dent->d_name); + if (len >= 5) + { + ptr = ((char *) dent->d_name) + len; + ptr += strlen(ptr) - 4; + if (stricmp(ptr, ".MAP") == 0) + add_this = 1; + } /* if */ + } /* else */ + + if (add_this) + { + strcpy(menuname[(int)menunamecnt],dent->d_name); + menuname[(int)menunamecnt][16] = subdirs; + menunamecnt++; + } /* if */ + } /* if */ + } /* if */ + } while (dent != NULL); + + closedir(dir); + +#endif + return(0); +} + +#endif + + +void sortfilenames() +{ + char sortbuffer[17]; + long i, j, k; + + for(i=1;i>1,15,0,0,name); + + rc = probe_with_delete(46,20+16,16,cnt,&hitdelete); + if (rc == -1) // escape + { + cmenu(prevmenu); + if (controlsstackedprobey >= 0) + { + probey = controlsstackedprobey; + controlsstackedprobey = -1; + } + } + else if (rc >= 0) // chose an option. + { + if (hitdelete) // clear this keybind. + { + char *fname = CONFIG_FunctionNumToName(keybinds[rc].which); + CONTROL_MapKey(keybinds[rc].which, 0, 0); + CONFIG_PutString("KeyDefinitions", fname, ""); + drawmenu = 1; + } + else // Go to the keybinder menu to select a new key. + { + prevbindmenu = current_menu; + currentbind = &keybinds[rc]; + keybindprobey = probey; + KB_FlushKeyboardQueue(); + KB_ClearKeysDown(); + cmenu(MENU_CONTROLS_KEYBINDER); + } + } + else // unknown option or none chosen, so draw menu. + { + drawmenu = 1; + } + + if (drawmenu) + { + for (i = 0; i < cnt; i++) + keybindtext(i, keybinds[i].name, keybinds[i].which); + } +} +#endif + +static void non3dr_menus(void) +{ + short c = (320>>1); + int rc; + + switch(current_menu) + { +#if CONTROLS_CONFIG_MENU + case MENU_CONTROLS_KEYBINDER: // binding a new key. + { + int bound = 0; + char *binding; + if (currentbind == NULL) // sanity check. + { + cmenu(prevbindmenu ? prevbindmenu : MENU_CONTROLS); + break; + } + + if (KB_KeyWaiting()) + { + kb_scancode sc = KB_GetLastScanCode(); + char *scstr = KB_ScanCodeToString(sc); + KB_FlushKeyboardQueue(); + KB_ClearKeysDown(); + + if (scstr == NULL) // make sure it maps. + sound(KICK_HIT); + else + { + if (sc == sc_Escape) // cancel request? + sound(EXITMENUSOUND); + else + { + char *fname = CONFIG_FunctionNumToName(currentbind->which); + sound(PISTOL_BODYHIT); + CONTROL_MapKey(currentbind->which, sc, 0); + CONFIG_PutString("KeyDefinitions", fname, scstr); + } + bound = 1; + } + } + + #if 0 // !!! FIXME...yuck. + else + { + int32 buttons = MOUSE_GetButtons(); + if (buttons) + { + int i; + int32 b = 1; + for (i = 0; i < MAXMOUSEBUTTONS; i++, b <<= 1) + { + if (b & buttons) + { + char *fname = CONFIG_FunctionNumToName(currentbind->which); + char buf[64]; + snprintf(buf, sizeof (buf), "MouseButton%d", i); + CONTROL_MapButton(currentbind->which, i, 0); + CONFIG_PutString("Controls", buf, fname); + break; + } + } + bound = ((b & buttons) != 0); + } + } + #endif + + if (bound) + { + cmenu(prevbindmenu ? prevbindmenu : MENU_CONTROLS); + prevbindmenu = 0; + currentbind = NULL; + probey = keybindprobey; + break; // we're done. + } + + // still waiting for valid user input...draw UI. + + rotatesprite(320<<15,10<<16,65536L,0,MENUBAR,16,0,10,0,0,xdim-1,ydim-1); + menutext(320>>1,15,0,0,currentbind->name); + + binding = (char *) CONTROL_GetMappingName(currentbind->which); + if (binding != NULL) + { + menutext(320>>1,15+30,0,0,"CURRENTLY BOUND TO:"); + menutext(320>>1,15+30+16,0,0,binding); + } + else + { + menutext(320>>1,15+30+16,0,0,"NOT CURRENTLY BOUND"); + } + + menutext(320>>1,15+30+16+30,0,0,"PRESS NEW KEY"); + menutext(320>>1,15+30+16+30+16,0,0,"OR"); + menutext(320>>1,15+30+16+30+16+16,0,0,"ESC TO LEAVE AS IS"); + + rotatesprite((320>>1)<<16,(15+30+16+30+16+16+20)<<16,65536L,0,SPINNINGNUKEICON+(((totalclock>>3))%7),sh,0,10,0,0,xdim-1,ydim-1); + + break; + } + + case MENU_CONTROLS: // main config menu. + { + rotatesprite(320<<15,10<<16,65536L,0,MENUBAR,16,0,10,0,0,xdim-1,ydim-1); + menutext(320>>1,15,0,0,"CONTROLS"); + + ignore_escape = 1; + rc = probe(320/4,20+16,16,6); // !!! FIXME: Move cursor to right more. + controlsstackedprobey = rc; + switch (rc) + { + case -1: // escape + cmenu(200); // options menu + ignore_escape = 0; + break; + case 0: // movement + cmenu(MENU_CONTROLS_MOVEMENT); + break; + case 1: // more movement + cmenu(MENU_CONTROLS_MOREMOVEMENT); + break; + case 2: // actions + cmenu(MENU_CONTROLS_ACTIONS); + break; + case 3: // weapons + cmenu(MENU_CONTROLS_WEAPONS); + break; + case 4: // items + cmenu(MENU_CONTROLS_ITEMS); + break; + case 5: // misc + cmenu(MENU_CONTROLS_MISC); + break; + default: + menutext(c,20+16,SHX(-1),PHX(-1),"MOVEMENT"); + menutext(c,20+16+16,SHX(-2),PHX(-2),"MORE MOVEMENT"); + menutext(c,20+16+16+16,SHX(-3),PHX(-3),"ACTIONS"); + menutext(c,20+16+16+16+16,SHX(-4),PHX(-4),"WEAPON SELECT"); + menutext(c,20+16+16+16+16+16,SHX(-5),PHX(-5),"INVENTORY"); + menutext(c,20+16+16+16+16+16+16,SHX(-6),PHX(-6),"MISCELLANEOUS"); + break; + } + break; + } + + case MENU_CONTROLS_MOVEMENT: // movement controls. + { + static KeyBinds keybinds[] = + { + { "MOVE FORWARD", gamefunc_Move_Forward }, + { "MOVE BACKWARD", gamefunc_Move_Backward }, + { "STRAFE LEFT", gamefunc_Strafe_Left }, + { "STRAFE RIGHT", gamefunc_Strafe_Right }, + { "TURN LEFT",gamefunc_Turn_Left }, + { "TURN RIGHT",gamefunc_Turn_Right }, + { "STRAFE", gamefunc_Strafe } + }; + + DoKeybindMenu("MOVEMENT", keybinds, ALEN(keybinds), MENU_CONTROLS); + break; + } + + case MENU_CONTROLS_MOREMOVEMENT: // more movement controls. + { + static KeyBinds keybinds[] = + { + { "JUMP", gamefunc_Jump }, + { "CROUCH", gamefunc_Crouch }, + { "RUN", gamefunc_Run }, + { "RUNLOCK", gamefunc_AutoRun }, + { "AIM UP", gamefunc_Aim_Up }, + { "AIM DOWN", gamefunc_Aim_Down }, + { "CENTER VIEW", gamefunc_Center_View }, + { "MOUSE AIM", gamefunc_Mouse_Aiming } + }; + + DoKeybindMenu("MORE MOVEMENT", keybinds, ALEN(keybinds), MENU_CONTROLS); + break; + } + + case MENU_CONTROLS_ACTIONS: // actions controls + { + static KeyBinds keybinds[] = + { + { "FIRE OR ATTACK", gamefunc_Fire }, + { "OPEN OR USE", gamefunc_Open }, + { "QUICK KICK", gamefunc_Quick_Kick }, + { "180 TURN", gamefunc_TurnAround }, + { "VIEW MAP", gamefunc_Map }, + { "HOLSTER WEAPON" ,gamefunc_Holster_Weapon }, + { "PREVIOUS WEAPON", gamefunc_Previous_Weapon }, + { "NEXT WEAPON", gamefunc_Next_Weapon } + }; + + DoKeybindMenu("ACTIONS", keybinds, ALEN(keybinds), MENU_CONTROLS); + break; + } + + case MENU_CONTROLS_WEAPONS: // weapon controls + { + static KeyBinds keybinds[] = + { + { "KICK", gamefunc_Weapon_1 }, + { "PISTOL", gamefunc_Weapon_2 }, + { "SHOTGUN", gamefunc_Weapon_3 }, + { "RIPPER", gamefunc_Weapon_4 }, + { "RPG", gamefunc_Weapon_5 }, + { "PIPEBOMB", gamefunc_Weapon_6 }, + { "SHRINK RAY", gamefunc_Weapon_7 }, + { "DEVASTATOR", gamefunc_Weapon_8 }, + { "TRIP BOMP", gamefunc_Weapon_9 }, + { "FREEZER", gamefunc_Weapon_10 } + }; + + DoKeybindMenu("WEAPON SELECT", keybinds, ALEN(keybinds), MENU_CONTROLS); + break; + } + + case MENU_CONTROLS_ITEMS: // item controls + { + static KeyBinds keybinds[] = + { + { "INVENTORY", gamefunc_Inventory }, + { "PREVIOUS ITEM", gamefunc_Inventory_Left }, + { "NEXT ITEM", gamefunc_Inventory_Right }, + { "USE HOLODUKE", gamefunc_Holo_Duke}, + { "USE JETPACK", gamefunc_Jetpack }, + { "USE NIGHTVISION", gamefunc_NightVision }, + { "USE MEDKIT", gamefunc_MedKit }, + { "USE STEROIDS", gamefunc_Steroids } + }; + + DoKeybindMenu("INVENTORY", keybinds, ALEN(keybinds), MENU_CONTROLS); + break; + } + + case MENU_CONTROLS_MISC: // misc controls + { + static KeyBinds keybinds[] = + { + { "SHRINK SCREEN", gamefunc_Shrink_Screen }, + { "ENLARGE SCREEN", gamefunc_Enlarge_Screen }, + { "SHOW WEAPONS", gamefunc_Show_Opponents_Weapon }, + { "MAP FOLLOW MODE", gamefunc_Map_Follow_Mode }, + { "SEE COOP VIEW", gamefunc_See_Coop_View }, + { "CHAT MESSAGE", gamefunc_SendMessage }, + { "TOGGLE CROSSHAIR", gamefunc_Toggle_Crosshair }, + }; + + DoKeybindMenu("MISCELLANEOUS", keybinds, ALEN(keybinds), MENU_CONTROLS); + break; + } +#endif + + default: + //gameexit("\nERROR: Unknown menu?!\n"); + cmenu(0); // main menu + } +} + + +void menus(void) +{ + int count; + short shorttmp = 0; + short c,x; + volatile long l; +// CTW - REMOVED +// int tenerr; +// CTW END - REMOVED + + getpackets(); + + if(ControllerType == 1 && CONTROL_MousePresent) + { + if(buttonstat != 0 && !onbar) + { + x = MOUSE_GetButtons()<<3; + if( x ) buttonstat = x<<3; + else buttonstat = 0; + } + else + buttonstat = MOUSE_GetButtons(); + } + else buttonstat = 0; + + if( (ps[myconnectindex].gm&MODE_MENU) == 0 ) + { + walock[MAXTILES-3] = 1; + return; + } + + ps[myconnectindex].gm &= (0xff-MODE_TYPE); + ps[myconnectindex].fta = 0; + + x = 0; + + sh = 4-(sintable[(totalclock<<4)&2047]>>11); + + if(!(current_menu >= 1000 && current_menu <= 2999 && current_menu >= 300 && current_menu <= 369)) + vscrn(); + + // icculus.org-added menus? + if (current_menu >= 30000) + non3dr_menus(); + else switch(current_menu) + { + case 25000: + gametext(160,90,"SELECT A SAVE SPOT BEFORE",0,2+8+16); + gametext(160,90+9,"YOU QUICK RESTORE.",0,2+8+16); + + x = probe(186,124,0,0); + if(x >= -1) + { + if(ud.multimode < 2 && ud.recstat != 2) + { + ready2send = 1; + totalclock = ototalclock; + } + ps[myconnectindex].gm &= ~MODE_MENU; + } + break; + + case 20000: + x = probe(326,190,0,0); + gametext(160,50-8,"YOU ARE PLAYING THE SHAREWARE",0,2+8+16); + gametext(160,59-8,"VERSION OF DUKE NUKEM 3D. WHILE",0,2+8+16); + gametext(160,68-8,"THIS VERSION IS REALLY COOL, YOU",0,2+8+16); + gametext(160,77-8,"ARE MISSING OVER 75% OF THE TOTAL",0,2+8+16); + gametext(160,86-8,"GAME, ALONG WITH OTHER GREAT EXTRAS",0,2+8+16); + gametext(160,95-8,"AND GAMES, WHICH YOU'LL GET WHEN",0,2+8+16); + gametext(160,104-8,"YOU ORDER THE COMPLETE VERSION AND",0,2+8+16); + gametext(160,113-8,"GET THE FINAL TWO EPISODES.",0,2+8+16); + + gametext(160,113+8,"PLEASE READ THE 'HOW TO ORDER' ITEM",0,2+8+16); + gametext(160,122+8,"ON THE MAIN MENU IF YOU WISH TO",0,2+8+16); + gametext(160,131+8,"UPGRADE TO THE FULL REGISTERED",0,2+8+16); + gametext(160,140+8,"VERSION OF DUKE NUKEM 3D.",0,2+8+16); + gametext(160,149+16,"PRESS ANY KEY...",0,2+8+16); + + if( x >= -1 ) cmenu(100); + break; +// CTW - REMOVED +/* case 20001: + x = probe(188,80+32+32,0,0); + gametext(160,86-8,"You must be in Windows 95 to",0,2+8+16); + gametext(160,86,"play on TEN",0,2+8+16); + gametext(160,86+32,"PRESS ANY KEY...",0,2+8+16); + if(x >= -1) cmenu(0); + break; + + case 20002: + x = probe(188,80+32+32+32,0,0); + gametext(160,86-8,"MISSING FILE: TENGAME.INI. PLEASE",0,2+8+16); + gametext(160,86,"CONNECT TO TEN BY LAUNCHING THE",0,2+8+16); + gametext(160,86+8,"CONNECT TO TEN SHORTCUT OR CONTACT",0,2+8+16); + gametext(160,86+8+8,"CUSTOMER SUPPORT AT 1-800-8040-TEN.",0,2+8+16); + gametext(160,86+8+8+32,"PRESS ANY KEY...",0,2+8+16); + if(x >= -1) cmenu(0); + break; + case 20003: + x = probe(188,80+32+32,0,0); + gametext(160,86-8,"BAD TEN INSTALL: PLEASE RE-INSTALL",0,2+8+16); + gametext(160,86,"BAD TEN INSTALL: PLEASE RE-INSTALL TEN",0,2+8+16); + gametext(160,86+32,"PRESS ANY KEY...",0,2+8+16); + if(x >= -1) cmenu(0); + break; + case 20005: + x = probe(188,80+32+32,0,0); + gametext(160,86-8,"GET THE LATEST TEN SOFTWARE AT",0,2+8+16); + gametext(160,86,"HTTP://WWW.TEN.NET",0,2+8+16); + gametext(160,86+32,"PRESS ANY KEY...",0,2+8+16); + if(x >= -1) cmenu(0); + break;*/ +// CTW END - REMOVED + + case 15001: + case 15000: + + gametext(160,90,"LOAD last game:",0,2+8+16); + + sprintf(tempbuf,"\"%s\"",ud.savegame[lastsavedpos]); + gametext(160,99,tempbuf,0,2+8+16); + + gametext(160,99+9,"(Y/N)",0,2+8+16); + + if( KB_KeyPressed(sc_Escape) || KB_KeyPressed(sc_N) || RMB) + { + if(sprite[ps[myconnectindex].i].extra <= 0) + { + enterlevel(MODE_GAME); + return; + } + + KB_ClearKeyDown(sc_N); + KB_ClearKeyDown(sc_Escape); + + ps[myconnectindex].gm &= ~MODE_MENU; + if(ud.multimode < 2 && ud.recstat != 2) + { + ready2send = 1; + totalclock = ototalclock; + } + } + + if( KB_KeyPressed(sc_Space) || KB_KeyPressed(sc_Enter) || KB_KeyPressed(sc_kpad_Enter) || KB_KeyPressed(sc_Y) || LMB ) + { + KB_FlushKeyboardQueue(); + FX_StopAllSounds(); + + if(ud.multimode > 1) + { + loadplayer(-1-lastsavedpos); + ps[myconnectindex].gm = MODE_GAME; + } + else + { + c = loadplayer(lastsavedpos); + if(c == 0) + ps[myconnectindex].gm = MODE_GAME; + } + } + + probe(186,124+9,0,0); + + break; + + case 10000: + case 10001: + + c = 60; + rotatesprite(160<<16,19<<16,65536L,0,MENUBAR,16,0,10,0,0,xdim-1,ydim-1); + menutext(160,24,0,0,"ADULT MODE"); + + x = probe(60,50+16,16,2); + if(x == -1) { cmenu(200); break; } + + menutext(c,50+16,SHX(-2),PHX(-2),"ADULT MODE"); + menutext(c,50+16+16,SHX(-3),PHX(-3),"ENTER PASSWORD"); + + if(ud.lockout) menutext(c+160+40,50+16,0,0,"OFF"); + else menutext(c+160+40,50+16,0,0,"ON"); + + if(current_menu == 10001) + { + gametext(160,50+16+16+16+16-12,"ENTER PASSWORD",0,2+8+16); + x = strget((320>>1),50+16+16+16+16,buf,19, 998); + + if( x ) + { + if(ud.pwlockout[0] == 0 || ud.lockout == 0 ) + strcpy(&ud.pwlockout[0],buf); + else if( strcmp(buf,&ud.pwlockout[0]) == 0 ) + { + ud.lockout = 0; + buf[0] = 0; + + for(x=0;x= 0 ) + wall[animwall[x].wallnum].picnum = wall[animwall[x].wallnum].extra; + + } + current_menu = 10000; + KB_ClearKeyDown(sc_Enter); + KB_ClearKeyDown(sc_kpad_Enter); + KB_FlushKeyboardQueue(); + } + } + else + { + if(x == 0) + { + if( ud.lockout == 1 ) + { + if(ud.pwlockout[0] == 0) + { + ud.lockout = 0; + for(x=0;x= 0 ) + wall[animwall[x].wallnum].picnum = wall[animwall[x].wallnum].extra; + } + else + { + buf[0] = 0; + current_menu = 10001; + inputloc = 0; + KB_FlushKeyboardQueue(); + } + } + else + { + ud.lockout = 1; + + for(x=0;x 1) + { + if( ps[myconnectindex].gm&MODE_GAME ) + { + loadplayer(-1-lastsavedpos); + ps[myconnectindex].gm = MODE_GAME; + } + else + { + tempbuf[0] = 126; + tempbuf[1] = lastsavedpos; + for(x=connecthead;x>=0;x=connectpoint2[x]) + if(x != myconnectindex) + sendpacket(x,tempbuf,2); + + getpackets(); + + loadplayer(lastsavedpos); + + multiflag = 0; + } + } + else + { + c = loadplayer(lastsavedpos); + if(c == 0) + ps[myconnectindex].gm = MODE_GAME; + } + + break; + } + if( KB_KeyPressed(sc_N) || KB_KeyPressed(sc_Escape) || RMB) + { + KB_ClearKeyDown(sc_N); + KB_ClearKeyDown(sc_Escape); + sound(EXITMENUSOUND); + if(ps[myconnectindex].gm&MODE_DEMO) cmenu(300); + else + { + ps[myconnectindex].gm &= ~MODE_MENU; + if(ud.multimode < 2 && ud.recstat != 2) + { + ready2send = 1; + totalclock = ototalclock; + } + } + } + + probe(186,124+9,0,0); + + break; + + case 1500: + + if( KB_KeyPressed(sc_Space) || KB_KeyPressed(sc_Enter) || KB_KeyPressed(sc_kpad_Enter) || KB_KeyPressed(sc_Y) || LMB ) + { + KB_FlushKeyboardQueue(); + cmenu(100); + } + if( KB_KeyPressed(sc_N) || KB_KeyPressed(sc_Escape) || RMB) + { + KB_ClearKeyDown(sc_N); + KB_ClearKeyDown(sc_Escape); + if(ud.multimode < 2 && ud.recstat != 2) + { + ready2send = 1; + totalclock = ototalclock; + } + ps[myconnectindex].gm &= ~MODE_MENU; + sound(EXITMENUSOUND); + break; + } + probe(186,124,0,0); + gametext(160,90,"ABORT this game?",0,2+8+16); + gametext(160,90+9,"(Y/N)",0,2+8+16); + + break; + + case 2000: + case 2001: + case 2002: + case 2003: + case 2004: + case 2005: + case 2006: + case 2007: + case 2008: + case 2009: + + rotatesprite(160<<16,200<<15,65536L,0,MENUSCREEN,16,0,10+64,0,0,xdim-1,ydim-1); + rotatesprite(160<<16,19<<16,65536L,0,MENUBAR,16,0,10,0,0,xdim-1,ydim-1); + menutext(160,24,0,0,"SAVE GAME"); + + rotatesprite(101<<16,97<<16,65536L,512,MAXTILES-3,-32,0,4+10+64,0,0,xdim-1,ydim-1); + sprintf(tempbuf,"PLAYERS: %-2ld ",ud.multimode); + gametext(160,158,tempbuf,0,2+8+16); + + sprintf(tempbuf,"EPISODE: %-2ld / LEVEL: %-2ld / SKILL: %-2ld",1+ud.volume_number,1+ud.level_number,ud.player_skill); + gametext(160,170,tempbuf,0,2+8+16); + + dispnames(); + + gametext(160,90,"OVERWRITE previous SAVED game?",0,2+8+16); + gametext(160,90+9,"(Y/N)",0,2+8+16); + + if( KB_KeyPressed(sc_Space) || KB_KeyPressed(sc_Enter) || KB_KeyPressed(sc_kpad_Enter) || KB_KeyPressed(sc_Y) || LMB ) + { + KB_FlushKeyboardQueue(); + inputloc = strlen(&ud.savegame[current_menu-2000][0]); + + cmenu(current_menu-2000+360); + + KB_FlushKeyboardQueue(); + break; + } + if( KB_KeyPressed(sc_N) || KB_KeyPressed(sc_Escape) || RMB) + { + KB_ClearKeyDown(sc_N); + KB_ClearKeyDown(sc_Escape); + cmenu(351); + sound(EXITMENUSOUND); + } + + probe(186,124,0,0); + + break; + + case 990: + case 991: + case 992: + case 993: + case 994: + case 995: + case 996: + case 997: + +// rotatesprite(c<<16,200<<15,65536L,0,MENUSCREEN,16,0,10+64,0,0,xdim-1,ydim-1); +// rotatesprite(c<<16,19<<16,65536L,0,MENUBAR,16,0,10,0,0,xdim-1,ydim-1); +// menutext(c,24,0,0,"CREDITS"); + + if(KB_KeyPressed(sc_Escape)) { cmenu(0); break; } + + if( KB_KeyPressed( sc_LeftArrow ) || + KB_KeyPressed( sc_kpad_4 ) || + KB_KeyPressed( sc_UpArrow ) || + KB_KeyPressed( sc_PgUp ) || + KB_KeyPressed( sc_kpad_8 ) ) + { + KB_ClearKeyDown(sc_LeftArrow); + KB_ClearKeyDown(sc_kpad_4); + KB_ClearKeyDown(sc_UpArrow); + KB_ClearKeyDown(sc_PgUp); + KB_ClearKeyDown(sc_kpad_8); + + sound(KICK_HIT); + current_menu--; + if(current_menu < 990) current_menu = 992; + } + else if( + KB_KeyPressed( sc_PgDn ) || + KB_KeyPressed( sc_Enter ) || + KB_KeyPressed( sc_Space ) || + KB_KeyPressed( sc_kpad_Enter ) || + KB_KeyPressed( sc_RightArrow ) || + KB_KeyPressed( sc_DownArrow ) || + KB_KeyPressed( sc_kpad_2 ) || + KB_KeyPressed( sc_kpad_9 ) || + KB_KeyPressed( sc_kpad_6 ) ) + { + KB_ClearKeyDown(sc_PgDn); + KB_ClearKeyDown(sc_Enter); + KB_ClearKeyDown(sc_RightArrow); + KB_ClearKeyDown(sc_kpad_Enter); + KB_ClearKeyDown(sc_kpad_6); + KB_ClearKeyDown(sc_kpad_9); + KB_ClearKeyDown(sc_kpad_2); + KB_ClearKeyDown(sc_DownArrow); + KB_ClearKeyDown(sc_Space); + sound(KICK_HIT); + current_menu++; + if(current_menu > 992) current_menu = 990; + } + + switch(current_menu) + { + case 990: + case 991: + case 992: + rotatesprite(160<<16,200<<15,65536L,0,2504+current_menu-990,0,0,10+64,0,0,xdim-1,ydim-1); + + break; + + } + break; + + case 0: + c = (320>>1); + rotatesprite(c<<16,(28<<16)-5,65536L,0,INGAMEDUKETHREEDEE,0,0,10,0,0,xdim-1,ydim-1); + rotatesprite((c+100)<<16,(36<<16)-5,65536L,0,PLUTOPAKSPRITE+2,(sintable[(totalclock<<4)&2047]>>11),0,2+8,0,0,xdim-1,ydim-1); +// CTW - MODIFICATION +// x = probe(c,67-3,16,7); + count = 6; +#if NET_MENU + count++; +#endif + x = probe(c,67-3,16,count); +// CTW END - MODIFICATION + if(x >= 0) + { + if( ud.multimode > 1 && x == 0 && ud.recstat != 2) + { + if( movesperpacket == 4 && myconnectindex != connecthead ) + break; + + last_zero = 0; + cmenu( 600 ); + } + else + { + last_zero = x; + switch(x) + { + case 0: + cmenu(100); + break; +// CTW - MODIFICATION +// Shifted the entire menu input results up one. +/* case 1: + if(movesperpacket == 4 || numplayers > 1) + break; + + tenBnSetExitRtn(dummyfunc); + setDebugMsgRoutine(dummymess); + tenerr = tenBnStart(); + + switch(tenerr) + { + case eTenBnNotInWindows: + cmenu(20001); + break; + case eTenBnBadGameIni: + cmenu(20002); + break; + case eTenBnBadTenIni: + cmenu(20003); + break; + case eTenBnBrowseCancel: + cmenu(20004); + break; + case eTenBnBadTenInst: + cmenu(20005); + break; + default: + playonten = 1; + gameexit(" "); + break; + } + break;*/ + case 1: cmenu(200);break; + case 2: + if(movesperpacket == 4 && connecthead != myconnectindex) + break; + cmenu(300); + break; + case 3: KB_FlushKeyboardQueue();cmenu(400);break; + case 4: cmenu(990);break; +#if NET_MENU + case 5: cmenu(30000);break; + case 6: cmenu(500);break; +#else + case 5: cmenu(500);break; +#endif + +// CTW END - MODIFICATION + } + } + } + + if(KB_KeyPressed(sc_Q)) cmenu(500); + + if(x == -1) + { + ps[myconnectindex].gm &= ~MODE_MENU; + if(ud.multimode < 2 && ud.recstat != 2) + { + ready2send = 1; + totalclock = ototalclock; + } + } + + if(movesperpacket == 4) + { + if( myconnectindex == connecthead ) + menutext(c,67-3,SHX(-2),PHX(-2),"NEW GAME"); + else + menutext(c,67-3,SHX(-2),1,"NEW GAME"); + } + else + menutext(c,67-3,SHX(-2),PHX(-2),"NEW GAME"); + +// CTW - REMOVED +/* if(movesperpacket != 4 && numplayers < 2) + menutext(c,67-3+16,SHX(-3),PHX(-3),"PLAY ON TEN"); + else + menutext(c,67-3+16,SHX(-3),1,"PLAY ON TEN");*/ +// CTW END - REMOVED + +// CTW - MODIFICATION - Not going to comment out the exact old code here. +// I shifted up every menu option by 16. +// I shifted up every menu result by 1. + menutext(c,67-3+16,SHX(-3),PHX(-3),"OPTIONS"); + + if(movesperpacket == 4 && connecthead != myconnectindex) + menutext(c,67-3+16+16,SHX(-4),1,"LOAD GAME"); + else menutext(c,67-3+16+16,SHX(-4),PHX(-4),"LOAD GAME"); + +#ifndef VOLUMEALL + menutext(c,67-3+16+16+16,SHX(-5),PHX(-5),"HOW TO ORDER"); +#else + menutext(c,67-3+16+16+16,SHX(-5),PHX(-5),"HELP"); +#endif + menutext(c,67-3+16+16+16+16,SHX(-6),PHX(-6),"CREDITS"); + +#if NET_MENU + menutext(c,67-3+16+16+16+16+16,SHX(-7),PHX(-7),"NETWORK GAME"); + menutext(c,67-3+16+16+16+16+16+16,SHX(-8),PHX(-8),"QUIT"); +#else + menutext(c,67-3+16+16+16+16+16,SHX(-7),PHX(-7),"QUIT"); +#endif + + break; +// CTW END - MODIFICATION + + case 50: + c = (320>>1); + rotatesprite(c<<16,32<<16,65536L,0,INGAMEDUKETHREEDEE,0,0,10,0,0,xdim-1,ydim-1); + rotatesprite((c+100)<<16,36<<16,65536L,0,PLUTOPAKSPRITE+2,(sintable[(totalclock<<4)&2047]>>11),0,2+8,0,0,xdim-1,ydim-1); + x = probe(c,67,16,7); + switch(x) + { + case 0: + if(movesperpacket == 4 && myconnectindex != connecthead) + break; + if(ud.multimode < 2 || ud.recstat == 2) + cmenu(1500); + else + { + cmenu(600); + last_fifty = 0; + } + break; + case 1: + if(movesperpacket == 4 && connecthead != myconnectindex) + break; + if(ud.recstat != 2) + { + last_fifty = 1; + cmenu(350); + setview(0,0,xdim-1,ydim-1); + } + break; + case 2: + if(movesperpacket == 4 && connecthead != myconnectindex) + break; + last_fifty = 2; + cmenu(300); + break; + case 3: + last_fifty = 3; + cmenu(200); + break; + case 4: + last_fifty = 4; + KB_FlushKeyboardQueue(); + cmenu(400); + break; + case 5: + if(numplayers < 2) + { + last_fifty = 5; + cmenu(501); + } + break; + case 6: + last_fifty = 6; + cmenu(500); + break; + case -1: + ps[myconnectindex].gm &= ~MODE_MENU; + if(ud.multimode < 2 && ud.recstat != 2) + { + ready2send = 1; + totalclock = ototalclock; + } + break; + } + + if( KB_KeyPressed(sc_Q) ) + cmenu(500); + + if(movesperpacket == 4 && connecthead != myconnectindex) + { + menutext(c,67 ,SHX(-2),1,"NEW GAME"); + menutext(c,67+16 ,SHX(-3),1,"SAVE GAME"); + menutext(c,67+16+16 ,SHX(-4),1,"LOAD GAME"); + } + else + { + menutext(c,67 ,SHX(-2),PHX(-2),"NEW GAME"); + menutext(c,67+16 ,SHX(-3),PHX(-3),"SAVE GAME"); + menutext(c,67+16+16 ,SHX(-4),PHX(-4),"LOAD GAME"); + } + + menutext(c,67+16+16+16 ,SHX(-5),PHX(-5),"OPTIONS"); +#ifndef VOLUMEALL + menutext(c,67+16+16+16+16 ,SHX(-6),PHX(-6),"HOW TO ORDER"); +#else + menutext(c,67+16+16+16+16 ,SHX(-6),PHX(-6)," HELP"); +#endif + if(numplayers > 1) + menutext(c,67+16+16+16+16+16 ,SHX(-7),1,"QUIT TO TITLE"); + else menutext(c,67+16+16+16+16+16 ,SHX(-7),PHX(-7),"QUIT TO TITLE"); + menutext(c,67+16+16+16+16+16+16,SHX(-8),PHX(-8),"QUIT GAME"); + break; + + case 100: + rotatesprite(160<<16,19<<16,65536L,0,MENUBAR,16,0,10,0,0,xdim-1,ydim-1); + menutext(160,24,0,0,"SELECT AN EPISODE"); +#ifdef PLUTOPAK + if(boardfilename[0]) + x = probe(160,60,20,5); + else x = probe(160,60,20,4); +#else + if(boardfilename[0]) + x = probe(160,60,20,4); + else x = probe(160,60,20,3); +#endif + if(x >= 0) + { +#ifdef VOLUMEONE + if(x > 0) + cmenu(20000); + else + { + ud.m_volume_number = x; + ud.m_level_number = 0; + cmenu(110); + } +#endif + +#ifndef VOLUMEONE +#ifndef PLUTOPAK + + if(x == 3 && boardfilename[0]) + { + ud.m_volume_number = 0; + ud.m_level_number = 7; + } +#else + if(x == 4 && boardfilename[0]) + { + ud.m_volume_number = 0; + ud.m_level_number = 7; + } +#endif + + else + { + ud.m_volume_number = x; + ud.m_level_number = 0; + } + cmenu(110); +#endif + } + else if(x == -1) + { + if(ps[myconnectindex].gm&MODE_GAME) cmenu(50); + else cmenu(0); + } + + menutext(160,60,SHX(-2),PHX(-2),volume_names[0]); + + c = 80; +#ifdef VOLUMEONE + menutext(160,60+20,SHX(-3),1,volume_names[1]); + menutext(160,60+20+20,SHX(-4),1,volume_names[2]); +#ifdef PLUTOPAK + menutext(160,60+20+20,SHX(-5),1,volume_names[3]); +#endif +#else + menutext(160,60+20,SHX(-3),PHX(-3),volume_names[1]); + menutext(160,60+20+20,SHX(-4),PHX(-4),volume_names[2]); +#ifdef PLUTOPAK + menutext(160,60+20+20+20,SHX(-5),PHX(-5),volume_names[3]); + if(boardfilename[0]) + { + + menutext(160,60+20+20+20+20,SHX(-6),PHX(-6),"USER MAP"); + gametextpal(160,60+20+20+20+20+3,boardfilename,16+(sintable[(totalclock<<4)&2047]>>11),2); + } +#else + if(boardfilename[0]) + { + menutext(160,60+20+20+20,SHX(-6),PHX(-6),"USER MAP"); + gametext(160,60+20+20+20+6,boardfilename,2,2+8+16); + } +#endif + +#endif + break; + + case 110: + c = (320>>1); + rotatesprite(c<<16,19<<16,65536L,0,MENUBAR,16,0,10,0,0,xdim-1,ydim-1); + menutext(c,24,0,0,"SELECT SKILL"); + x = probe(c,70,19,4); + if(x >= 0) + { + switch(x) + { + case 0: globalskillsound = JIBBED_ACTOR6;break; + case 1: globalskillsound = BONUS_SPEECH1;break; + case 2: globalskillsound = DUKE_GETWEAPON2;break; + case 3: globalskillsound = JIBBED_ACTOR5;break; + } + + sound(globalskillsound); + + ud.m_player_skill = x+1; + if(x == 3) ud.m_respawn_monsters = 1; + else ud.m_respawn_monsters = 0; + + ud.m_monsters_off = ud.monsters_off = 0; + + ud.m_respawn_items = 0; + ud.m_respawn_inventory = 0; + + ud.multimode = 1; + + if(ud.m_volume_number == 3) + { + flushperms(); + setview(0,0,xdim-1,ydim-1); + clearview(0L); + nextpage(); + } + + newgame(ud.m_volume_number,ud.m_level_number,ud.m_player_skill); + enterlevel(MODE_GAME); + } + else if(x == -1) + { + cmenu(100); + KB_FlushKeyboardQueue(); + } + + menutext(c,70,SHX(-2),PHX(-2),skill_names[0]); + menutext(c,70+19,SHX(-3),PHX(-3),skill_names[1]); + menutext(c,70+19+19,SHX(-4),PHX(-4),skill_names[2]); + menutext(c,70+19+19+19,SHX(-5),PHX(-5),skill_names[3]); + break; + + case 200: + + rotatesprite(320<<15,10<<16,65536L,0,MENUBAR,16,0,10,0,0,xdim-1,ydim-1); + menutext(320>>1,15,0,0,"OPTIONS"); + + c = (320>>1)-120; + + onbar = (probey == 3 || probey == 4 || probey == 5); + count = 10; +#if CONTROLS_CONFIG_MENU + count++; +#endif + x = probe(c+6,31,15,count); + + if(x == -1) + { if(ps[myconnectindex].gm&MODE_GAME) cmenu(50);else cmenu(0); } + + if(onbar == 0) switch(x) + { + case 0: + ud.detail = 1-ud.detail; + break; + case 1: + ud.shadows = 1-ud.shadows; + break; + case 2: + ud.screen_tilting = 1-ud.screen_tilting; + break; + case 6: + if ( ControllerType == controltype_keyboardandmouse ) + ud.mouseflip = 1-ud.mouseflip; + break; + case 7: + cmenu(700); + break; + case 8: +#ifndef AUSTRALIA + cmenu(10000); +#endif + break; + case 9: + if( (ps[myconnectindex].gm&MODE_GAME) ) + { + closedemowrite(); + break; + } + ud.m_recstat = !ud.m_recstat; + break; +#if CONTROLS_CONFIG_MENU + case 10: + cmenu(MENU_CONTROLS); + break; +#endif + } + + if(ud.detail) menutext(c+160+40,31,0,0,"HIGH"); + else menutext(c+160+40,31,0,0,"LOW"); + + if(ud.shadows) menutext(c+160+40,31+15,0,0,"ON"); + else menutext(c+160+40,31+15,0,0,"OFF"); + + switch(ud.screen_tilting) + { + case 0: menutext(c+160+40,31+15+15,0,0,"OFF");break; + case 1: menutext(c+160+40,31+15+15,0,0,"ON");break; + case 2: menutext(c+160+40,31+15+15,0,0,"FULL");break; + } + + menutext(c,31,SHX(-2),PHX(-2),"DETAIL"); + menutext(c,31+15,SHX(-3),PHX(-3),"SHADOWS"); + menutext(c,31+15+15,SHX(-4),PHX(-4),"SCREEN TILTING"); + menutext(c,31+15+15+15,SHX(-5),PHX(-5),"SCREEN SIZE"); + shorttmp = (short) ud.screen_size; + bar(c+167+40,31+15+15+15,(short *)&shorttmp,-4,x==3,SHX(-5),PHX(-5)); + ud.screen_size = (int32) shorttmp; + + menutext(c,31+15+15+15+15,SHX(-6),PHX(-6),"BRIGHTNESS"); + shorttmp = (short) ud.brightness; + bar(c+167+40,31+15+15+15+15,(short *)&shorttmp,8,x==4,SHX(-6),PHX(-6)); + ud.brightness = (int32) shorttmp; + if(x==4) setbrightness(ud.brightness>>2,&ps[myconnectindex].palette[0]); + + if ( ControllerType == controltype_keyboardandmouse ) + { + short sense; + sense = CONTROL_GetMouseSensitivity()>>10; + + menutext(c,31+15+15+15+15+15,SHX(-7),PHX(-7),"MOUSE SENSITIVITY"); + bar(c+167+40,31+15+15+15+15+15,&sense,4,x==5,SHX(-7),PHX(-7)); + CONTROL_SetMouseSensitivity( sense<<10 ); + menutext(c,31+15+15+15+15+15+15,SHX(-7),PHX(-7),"MOUSE AIMING FLIP"); + + if(ud.mouseflip) menutext(c+160+40,31+15+15+15+15+15+15,SHX(-7),PHX(-7),"ON"); + else menutext(c+160+40,31+15+15+15+15+15+15,SHX(-7),PHX(-7),"OFF"); + + } + else + { + short sense; + sense = CONTROL_GetMouseSensitivity()>>10; + + menutext(c,31+15+15+15+15+15,SHX(-7),1,"MOUSE SENSITIVITY"); + bar(c+167+40,31+15+15+15+15+15,&sense,4,x==99,SHX(-7),1); + menutext(c,31+15+15+15+15+15+15,SHX(-7),1,"MOUSE AIMING FLIP"); + + if(ud.mouseflip) menutext(c+160+40,31+15+15+15+15+15+15,SHX(-7),1,"ON"); + else menutext(c+160+40,31+15+15+15+15+15+15,SHX(-7),1,"OFF"); + } + + menutext(c,31+15+15+15+15+15+15+15,SHX(-8),PHX(-8),"SOUNDS"); +#ifndef AUSTRALIA + menutext(c,31+15+15+15+15+15+15+15+15,SHX(-9),PHX(-9),"PARENTAL LOCK"); +#else + menutext(c,31+15+15+15+15+15+15+15+15,SHX(-9),1,"PARENTAL LOCK"); +#endif + if( (ps[myconnectindex].gm&MODE_GAME) && ud.m_recstat != 1 ) + { + menutext(c,31+15+15+15+15+15+15+15+15+15,SHX(-10),1,"RECORD"); + menutext(c+160+40,31+15+15+15+15+15+15+15+15+15,SHX(-10),1,"OFF"); + } + else + { + menutext(c,31+15+15+15+15+15+15+15+15+15,SHX(-10),PHX(-10),"RECORD"); + + if(ud.m_recstat == 1) + menutext(c+160+40,31+15+15+15+15+15+15+15+15+15,SHX(-10),PHX(-10),"ON"); + else menutext(c+160+40,31+15+15+15+15+15+15+15+15+15,SHX(-10),PHX(-10),"OFF"); + } + +#if CONTROLS_CONFIG_MENU + menutext(c,31+15+15+15+15+15+15+15+15+15+15,SHX(-11),PHX(-11),"CONTROLS..."); +#endif + break; + + case 700: + c = (320>>1)-120; + rotatesprite(320<<15,19<<16,65536L,0,MENUBAR,16,0,10,0,0,xdim-1,ydim-1); + menutext(320>>1,24,0,0,"SOUNDS"); + onbar = ( probey == 2 || probey == 3 ); + + x = probe(c,50,16,7); + switch(x) + { + case -1: + if(ps[myconnectindex].gm&MODE_GAME) + { + ps[myconnectindex].gm &= ~MODE_MENU; + if(ud.multimode < 2 && ud.recstat != 2) + { + ready2send = 1; + totalclock = ototalclock; + } + } + + else cmenu(200); + break; + case 0: + if (FXDevice != NumSoundCards) + { + SoundToggle = 1-SoundToggle; + if( SoundToggle == 0 ) + { + FX_StopAllSounds(); + clearsoundlocks(); + } + onbar = 0; + } + break; + case 1: + + if(eightytwofifty == 0 || numplayers < 2) + if(MusicDevice != NumSoundCards) + { + MusicToggle = 1-MusicToggle; + if( MusicToggle == 0 ) MUSIC_Pause(); + else + { + if(ud.recstat != 2 && ps[myconnectindex].gm&MODE_GAME) + playmusic(&music_fn[0][(int)music_select][0]); + else playmusic(&env_music_fn[0][0]); + + MUSIC_Continue(); + } + } + onbar = 0; + + break; + case 4: + if(SoundToggle && (FXDevice != NumSoundCards)) VoiceToggle = 1-VoiceToggle; + onbar = 0; + break; + case 5: + if(SoundToggle && (FXDevice != NumSoundCards)) AmbienceToggle = 1-AmbienceToggle; + onbar = 0; + break; + case 6: + if(SoundToggle && (FXDevice != NumSoundCards)) + { + ReverseStereo = 1-ReverseStereo; + FX_SetReverseStereo(ReverseStereo); + } + onbar = 0; + break; + default: + onbar = 1; + break; + } + + if(SoundToggle && FXDevice != NumSoundCards) menutext(c+160+40,50,0,(FXDevice == NumSoundCards),"ON"); + else menutext(c+160+40,50,0,(FXDevice == NumSoundCards),"OFF"); + + if(MusicToggle && (MusicDevice != NumSoundCards) && (!eightytwofifty||numplayers<2)) + menutext(c+160+40,50+16,0,(MusicDevice == NumSoundCards),"ON"); + else menutext(c+160+40,50+16,0,(MusicDevice == NumSoundCards),"OFF"); + + menutext(c,50,SHX(-2),(FXDevice == NumSoundCards),"SOUND"); + menutext(c,50+16+16,SHX(-4),(FXDevice==NumSoundCards)||SoundToggle==0,"SOUND VOLUME"); + { + l = FXVolume; + FXVolume >>= 2; + shorttmp = (short) FXVolume; + bar(c+167+40,50+16+16,(short *)&shorttmp,4,(FXDevice!=NumSoundCards)&&x==2,SHX(-4),SoundToggle==0||(FXDevice==NumSoundCards)); + FXVolume = (int32) shorttmp; + if(l != FXVolume) + FXVolume <<= 2; + if(l != FXVolume) + FX_SetVolume( (short) FXVolume ); + } + menutext(c,50+16,SHX(-3),(MusicDevice==NumSoundCards),"MUSIC"); + menutext(c,50+16+16+16,SHX(-5),(MusicDevice==NumSoundCards)||(numplayers > 1 && eightytwofifty)||MusicToggle==0,"MUSIC VOLUME"); + { + l = MusicVolume; + MusicVolume >>= 2; + shorttmp = (short) MusicVolume; + bar(c+167+40,50+16+16+16, + &shorttmp,4, + (eightytwofifty==0||numplayers < 2) && (MusicDevice!=NumSoundCards) && x==3,SHX(-5), + (numplayers > 1 && eightytwofifty)||MusicToggle==0||(MusicDevice==NumSoundCards)); + MusicVolume = (int32) shorttmp; + MusicVolume <<= 2; + if(l != MusicVolume) + { + STUBBED("Check this"); + // !!! FIXME: Used to be Music_ not MUSIC_. --ryan. + MUSIC_SetVolume( (short) MusicVolume ); + } + } + menutext(c,50+16+16+16+16,SHX(-6),(FXDevice==NumSoundCards)||SoundToggle==0,"DUKE TALK"); + menutext(c,50+16+16+16+16+16,SHX(-7),(FXDevice==NumSoundCards)||SoundToggle==0,"AMBIENCE"); + + menutext(c,50+16+16+16+16+16+16,SHX(-8),(FXDevice==NumSoundCards)||SoundToggle==0,"FLIP STEREO"); + + if(VoiceToggle) menutext(c+160+40,50+16+16+16+16,0,(FXDevice==NumSoundCards)||SoundToggle==0,"ON"); + else menutext(c+160+40,50+16+16+16+16,0,(FXDevice==NumSoundCards)||SoundToggle==0,"OFF"); + + if(AmbienceToggle) menutext(c+160+40,50+16+16+16+16+16,0,(FXDevice==NumSoundCards)||SoundToggle==0,"ON"); + else menutext(c+160+40,50+16+16+16+16+16,0,(FXDevice==NumSoundCards)||SoundToggle==0,"OFF"); + + if(ReverseStereo) menutext(c+160+40,50+16+16+16+16+16+16,0,(FXDevice==NumSoundCards)||SoundToggle==0,"ON"); + else menutext(c+160+40,50+16+16+16+16+16+16,0,(FXDevice==NumSoundCards)||SoundToggle==0,"OFF"); + + + break; + + case 350: + cmenu(351); + screencapt = 1; + displayrooms(myconnectindex,65536); + savetemp("duke3d.tmp",waloff[MAXTILES-1],160*100); + screencapt = 0; + break; + + case 360: + case 361: + case 362: + case 363: + case 364: + case 365: + case 366: + case 367: + case 368: + case 369: + case 351: + case 300: + + c = 320>>1; + rotatesprite(c<<16,200<<15,65536L,0,MENUSCREEN,16,0,10+64,0,0,xdim-1,ydim-1); + rotatesprite(c<<16,19<<16,65536L,0,MENUBAR,16,0,10,0,0,xdim-1,ydim-1); + + if(current_menu == 300) menutext(c,24,0,0,"LOAD GAME"); + else menutext(c,24,0,0,"SAVE GAME"); + + if(current_menu >= 360 && current_menu <= 369 ) + { + sprintf(tempbuf,"PLAYERS: %-2ld ",ud.multimode); + gametext(160,158,tempbuf,0,2+8+16); + sprintf(tempbuf,"EPISODE: %-2ld / LEVEL: %-2ld / SKILL: %-2ld",1+ud.volume_number,1+ud.level_number,ud.player_skill); + gametext(160,170,tempbuf,0,2+8+16); + + x = strget((320>>1),184,&ud.savegame[current_menu-360][0],19, 999 ); + + if(x == -1) + { + // readsavenames(); + ps[myconnectindex].gm = MODE_GAME; + if(ud.multimode < 2 && ud.recstat != 2) + { + ready2send = 1; + totalclock = ototalclock; + } + goto DISPLAYNAMES; + } + + if( x == 1 ) + { + if( ud.savegame[current_menu-360][0] == 0 ) + { + KB_FlushKeyboardQueue(); + cmenu(351); + } + else + { + if(ud.multimode > 1) + saveplayer(-1-(current_menu-360)); + else saveplayer(current_menu-360); + lastsavedpos = current_menu-360; + ps[myconnectindex].gm = MODE_GAME; + + if(ud.multimode < 2 && ud.recstat != 2) + { + ready2send = 1; + totalclock = ototalclock; + } + KB_ClearKeyDown(sc_Escape); + sound(EXITMENUSOUND); + } + } + + rotatesprite(101<<16,97<<16,65536,512,MAXTILES-1,-32,0,2+4+8+64,0,0,xdim-1,ydim-1); + dispnames(); + rotatesprite((c+67+strlen(&ud.savegame[current_menu-360][0])*4)<<16,(50+12*probey)<<16,32768L-10240,0,SPINNINGNUKEICON+(((totalclock)>>3)%7),0,0,10,0,0,xdim-1,ydim-1); + break; + } + + last_threehundred = probey; + + x = probe(c+68,54,12,10); + + if(current_menu == 300) + { + if( ud.savegame[probey][0] ) + { + if( lastprobey != probey ) + { + loadpheader(probey,&volnum,&levnum,&plrskl,&numplr); + lastprobey = probey; + } + + rotatesprite(101<<16,97<<16,65536L,512,MAXTILES-3,-32,0,4+10+64,0,0,xdim-1,ydim-1); + sprintf(tempbuf,"PLAYERS: %-2ld ",numplr); + gametext(160,158,tempbuf,0,2+8+16); + sprintf(tempbuf,"EPISODE: %-2ld / LEVEL: %-2ld / SKILL: %-2ld",1+volnum,1+levnum,plrskl); + gametext(160,170,tempbuf,0,2+8+16); + } + else menutext(69,70,0,0,"EMPTY"); + } + else + { + if( ud.savegame[probey][0] ) + { + if(lastprobey != probey) + loadpheader(probey,&volnum,&levnum,&plrskl,&numplr); + lastprobey = probey; + rotatesprite(101<<16,97<<16,65536L,512,MAXTILES-3,-32,0,4+10+64,0,0,xdim-1,ydim-1); + } + else menutext(69,70,0,0,"EMPTY"); + sprintf(tempbuf,"PLAYERS: %-2ld ",ud.multimode); + gametext(160,158,tempbuf,0,2+8+16); + sprintf(tempbuf,"EPISODE: %-2ld / LEVEL: %-2ld / SKILL: %-2ld",1+ud.volume_number,1+ud.level_number,ud.player_skill); + gametext(160,170,tempbuf,0,2+8+16); + } + + switch( x ) + { + case -1: + if(current_menu == 300) + { + if( (ps[myconnectindex].gm&MODE_GAME) != MODE_GAME) + { + cmenu(0); + break; + } + else + ps[myconnectindex].gm &= ~MODE_MENU; + } + else + ps[myconnectindex].gm = MODE_GAME; + + if(ud.multimode < 2 && ud.recstat != 2) + { + ready2send = 1; + totalclock = ototalclock; + } + + break; + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 8: + case 9: + if( current_menu == 300) + { + if( ud.savegame[x][0] ) + current_menu = (1000+x); + } + else + { + if( ud.savegame[x][0] != 0) + current_menu = 2000+x; + else + { + KB_FlushKeyboardQueue(); + current_menu = (360+x); + ud.savegame[x][0] = 0; + inputloc = 0; + } + } + break; + } + + DISPLAYNAMES: + dispnames(); + break; + +#ifndef VOLUMEALL + case 400: + case 401: + case 402: + case 403: + + c = 320>>1; + + if( KB_KeyPressed( sc_LeftArrow ) || + KB_KeyPressed( sc_kpad_4 ) || + KB_KeyPressed( sc_UpArrow ) || + KB_KeyPressed( sc_PgUp ) || + KB_KeyPressed( sc_kpad_8 ) ) + { + KB_ClearKeyDown(sc_LeftArrow); + KB_ClearKeyDown(sc_kpad_4); + KB_ClearKeyDown(sc_UpArrow); + KB_ClearKeyDown(sc_PgUp); + KB_ClearKeyDown(sc_kpad_8); + + sound(KICK_HIT); + current_menu--; + if(current_menu < 400) current_menu = 403; + } + else if( + KB_KeyPressed( sc_PgDn ) || + KB_KeyPressed( sc_Enter ) || + KB_KeyPressed( sc_kpad_Enter ) || + KB_KeyPressed( sc_RightArrow ) || + KB_KeyPressed( sc_DownArrow ) || + KB_KeyPressed( sc_kpad_2 ) || + KB_KeyPressed( sc_kpad_9 ) || + KB_KeyPressed( sc_Space ) || + KB_KeyPressed( sc_kpad_6 ) ) + { + KB_ClearKeyDown(sc_PgDn); + KB_ClearKeyDown(sc_Enter); + KB_ClearKeyDown(sc_RightArrow); + KB_ClearKeyDown(sc_kpad_Enter); + KB_ClearKeyDown(sc_kpad_6); + KB_ClearKeyDown(sc_kpad_9); + KB_ClearKeyDown(sc_kpad_2); + KB_ClearKeyDown(sc_DownArrow); + KB_ClearKeyDown(sc_Space); + sound(KICK_HIT); + current_menu++; + if(current_menu > 403) current_menu = 400; + } + + if( KB_KeyPressed(sc_Escape) ) + { + if(ps[myconnectindex].gm&MODE_GAME) + cmenu(50); + else cmenu(0); + return; + } + + flushperms(); + rotatesprite(0,0,65536L,0,ORDERING+current_menu-400,0,0,10+16+64,0,0,xdim-1,ydim-1); + +#else + case 400: + case 401: + + c = 320>>1; + + if( KB_KeyPressed( sc_LeftArrow ) || + KB_KeyPressed( sc_kpad_4 ) || + KB_KeyPressed( sc_UpArrow ) || + KB_KeyPressed( sc_PgUp ) || + KB_KeyPressed( sc_kpad_8 ) ) + { + KB_ClearKeyDown(sc_LeftArrow); + KB_ClearKeyDown(sc_kpad_4); + KB_ClearKeyDown(sc_UpArrow); + KB_ClearKeyDown(sc_PgUp); + KB_ClearKeyDown(sc_kpad_8); + + sound(KICK_HIT); + current_menu--; + if(current_menu < 400) current_menu = 401; + } + else if( + KB_KeyPressed( sc_PgDn ) || + KB_KeyPressed( sc_Enter ) || + KB_KeyPressed( sc_kpad_Enter ) || + KB_KeyPressed( sc_RightArrow ) || + KB_KeyPressed( sc_DownArrow ) || + KB_KeyPressed( sc_kpad_2 ) || + KB_KeyPressed( sc_kpad_9 ) || + KB_KeyPressed( sc_Space ) || + KB_KeyPressed( sc_kpad_6 ) ) + { + KB_ClearKeyDown(sc_PgDn); + KB_ClearKeyDown(sc_Enter); + KB_ClearKeyDown(sc_RightArrow); + KB_ClearKeyDown(sc_kpad_Enter); + KB_ClearKeyDown(sc_kpad_6); + KB_ClearKeyDown(sc_kpad_9); + KB_ClearKeyDown(sc_kpad_2); + KB_ClearKeyDown(sc_DownArrow); + KB_ClearKeyDown(sc_Space); + sound(KICK_HIT); + current_menu++; + if(current_menu > 401) current_menu = 400; + } + + if( KB_KeyPressed(sc_Escape) ) + { + if(ps[myconnectindex].gm&MODE_GAME) + cmenu(50); + else cmenu(0); + return; + } + + flushperms(); + switch(current_menu) + { + case 400: + rotatesprite(0,0,65536L,0,TEXTSTORY,0,0,10+16+64, 0,0,xdim-1,ydim-1); + break; + case 401: + rotatesprite(0,0,65536L,0,F1HELP,0,0,10+16+64, 0,0,xdim-1,ydim-1); + break; + } + +#endif + + break; + + case 500: + c = 320>>1; + + gametext(c,90,"Are you sure you want to quit?",0,2+8+16); + gametext(c,99,"(Y/N)",0,2+8+16); + + if( KB_KeyPressed(sc_Space) || KB_KeyPressed(sc_Enter) || KB_KeyPressed(sc_kpad_Enter) || KB_KeyPressed(sc_Y) || LMB ) + { + KB_FlushKeyboardQueue(); + + if( gamequit == 0 && ( numplayers > 1 ) ) + { + if(ps[myconnectindex].gm&MODE_GAME) + { + gamequit = 1; + quittimer = totalclock+120; + } + else + { + sendlogoff(); + gameexit(" "); + } + } + else if( numplayers < 2 ) + gameexit(" "); + + if( ( totalclock > quittimer ) && ( gamequit == 1) ) + gameexit("Timed out."); + } + + x = probe(186,124,0,0); + if(x == -1 || KB_KeyPressed(sc_N) || RMB) + { + KB_ClearKeyDown(sc_N); + quittimer = 0; + if( ps[myconnectindex].gm&MODE_DEMO ) + ps[myconnectindex].gm = MODE_DEMO; + else + { + ps[myconnectindex].gm &= ~MODE_MENU; + if(ud.multimode < 2 && ud.recstat != 2) + { + ready2send = 1; + totalclock = ototalclock; + } + } + } + + break; + case 501: + c = 320>>1; + gametext(c,90,"Quit to Title?",0,2+8+16); + gametext(c,99,"(Y/N)",0,2+8+16); + + if( KB_KeyPressed(sc_Space) || KB_KeyPressed(sc_Enter) || KB_KeyPressed(sc_kpad_Enter) || KB_KeyPressed(sc_Y) || LMB ) + { + KB_FlushKeyboardQueue(); + ps[myconnectindex].gm = MODE_DEMO; + if(ud.recstat == 1) + closedemowrite(); + cmenu(0); + } + + x = probe(186,124,0,0); + + if(x == -1 || KB_KeyPressed(sc_N) || RMB) + { + ps[myconnectindex].gm &= ~MODE_MENU; + if(ud.multimode < 2 && ud.recstat != 2) + { + ready2send = 1; + totalclock = ototalclock; + } + } + + break; + + case 601: + displayfragbar(); + rotatesprite(160<<16,29<<16,65536L,0,MENUBAR,16,0,10,0,0,xdim-1,ydim-1); + menutext(320>>1,34,0,0,&ud.user_name[myconnectindex][0]); + + sprintf(tempbuf,"Waiting for master"); + gametext(160,50,tempbuf,0,2+8+16); + gametext(160,59,"to select level",0,2+8+16); + + if( KB_KeyPressed(sc_Escape) ) + { + KB_ClearKeyDown(sc_Escape); + sound(EXITMENUSOUND); + cmenu(0); + } + break; + + case 602: + if(menunamecnt == 0) + { + // getfilenames("SUBD"); + getfilenames("*.MAP"); + sortfilenames(); + if (menunamecnt == 0) + cmenu(600); + } + case 603: + c = (320>>1) - 120; + displayfragbar(); + rotatesprite(320>>1<<16,19<<16,65536L,0,MENUBAR,16,0,10,0,0,xdim-1,ydim-1); + menutext(320>>1,24,0,0,"USER MAPS"); + for(x=0;x 256 ) ) + { + KB_ClearKeyDown( sc_RightArrow ); + KB_ClearKeyDown( sc_kpad_6 ); + probey += 15; + if(probey >= menunamecnt) + probey -= 15; + else sound(KICK_HIT); + } + + onbar = 0; + x = probe(0,0,0,menunamecnt); + + if(x == -1) cmenu(600); + else if(x >= 0) + { + tempbuf[0] = 8; + tempbuf[1] = ud.m_level_number = 6; + tempbuf[2] = ud.m_volume_number = 0; + tempbuf[3] = ud.m_player_skill+1; + + if(ud.player_skill == 3) + ud.m_respawn_monsters = 1; + else ud.m_respawn_monsters = 0; + + if(ud.m_coop == 0) ud.m_respawn_items = 1; + else ud.m_respawn_items = 0; + + ud.m_respawn_inventory = 1; + + tempbuf[4] = ud.m_monsters_off; + tempbuf[5] = ud.m_respawn_monsters; + tempbuf[6] = ud.m_respawn_items; + tempbuf[7] = ud.m_respawn_inventory; + tempbuf[8] = ud.m_coop; + tempbuf[9] = ud.m_marker; + + x = strlen(menuname[probey]); + + copybufbyte(menuname[probey],tempbuf+10,x); + copybufbyte(menuname[probey],boardfilename,x+1); + + for(c=connecthead;c>=0;c=connectpoint2[c]) + if(c != myconnectindex) + sendpacket(c,tempbuf,x+10); + + newgame(ud.m_volume_number,ud.m_level_number,ud.m_player_skill+1); + enterlevel(MODE_GAME); + } + break; + + case 600: + c = (320>>1) - 120; + if((ps[myconnectindex].gm&MODE_GAME) != MODE_GAME) + displayfragbar(); + rotatesprite(160<<16,26<<16,65536L,0,MENUBAR,16,0,10,0,0,xdim-1,ydim-1); + menutext(160,31,0,0,&ud.user_name[myconnectindex][0]); + + x = probe(c,57-8,16,8); + + switch(x) + { + case -1: + ud.m_recstat = 0; + if(ps[myconnectindex].gm&MODE_GAME) cmenu(50); + else cmenu(0); + break; + case 0: + ud.m_coop++; + if(ud.m_coop == 3) ud.m_coop = 0; + break; + case 1: +#ifndef VOLUMEONE + ud.m_volume_number++; +#ifdef PLUTOPAK + if(ud.m_volume_number > 3) ud.m_volume_number = 0; +#else + if(ud.m_volume_number > 2) ud.m_volume_number = 0; +#endif + if(ud.m_volume_number == 0 && ud.m_level_number > 6) + ud.m_level_number = 0; + if(ud.m_level_number > 10) ud.m_level_number = 0; +#endif + break; + case 2: +#ifndef ONELEVELDEMO + ud.m_level_number++; +#ifndef VOLUMEONE + if(ud.m_volume_number == 0 && ud.m_level_number > 6) + ud.m_level_number = 0; +#else + if(ud.m_volume_number == 0 && ud.m_level_number > 5) + ud.m_level_number = 0; +#endif + if(ud.m_level_number > 10) ud.m_level_number = 0; +#endif + break; + case 3: + if(ud.m_monsters_off == 1 && ud.m_player_skill > 0) + ud.m_monsters_off = 0; + + if(ud.m_monsters_off == 0) + { + ud.m_player_skill++; + if(ud.m_player_skill > 3) + { + ud.m_player_skill = 0; + ud.m_monsters_off = 1; + } + } + else ud.m_monsters_off = 0; + + break; + + case 4: + if(ud.m_coop == 0) + ud.m_marker = !ud.m_marker; + break; + + case 5: + if(ud.m_coop == 1) + ud.m_ffire = !ud.m_ffire; + break; + + case 6: +#ifdef VOLUMEALL + if(boardfilename[0] == 0) break; + + tempbuf[0] = 5; + tempbuf[1] = ud.m_level_number = 7; + tempbuf[2] = ud.m_volume_number = 0; + tempbuf[3] = ud.m_player_skill+1; + + ud.level_number = ud.m_level_number; + ud.volume_number = ud.m_volume_number; + + if( ud.m_player_skill == 3 ) ud.m_respawn_monsters = 1; + else ud.m_respawn_monsters = 0; + + if(ud.m_coop == 0) ud.m_respawn_items = 1; + else ud.m_respawn_items = 0; + + ud.m_respawn_inventory = 1; + + tempbuf[4] = ud.m_monsters_off; + tempbuf[5] = ud.m_respawn_monsters; + tempbuf[6] = ud.m_respawn_items; + tempbuf[7] = ud.m_respawn_inventory; + tempbuf[8] = ud.m_coop; + tempbuf[9] = ud.m_marker; + tempbuf[10] = ud.m_ffire; + + for(c=connecthead;c>=0;c=connectpoint2[c]) + { + resetweapons(c); + resetinventory(c); + + if(c != myconnectindex) + sendpacket(c,tempbuf,11); + } + + newgame(ud.m_volume_number,ud.m_level_number,ud.m_player_skill+1); + enterlevel(MODE_GAME); + + return; +#endif + case 7: + + tempbuf[0] = 5; + tempbuf[1] = ud.m_level_number; + tempbuf[2] = ud.m_volume_number; + tempbuf[3] = ud.m_player_skill+1; + + if( ud.m_player_skill == 3 ) ud.m_respawn_monsters = 1; + else ud.m_respawn_monsters = 0; + + if(ud.m_coop == 0) ud.m_respawn_items = 1; + else ud.m_respawn_items = 0; + + ud.m_respawn_inventory = 1; + + tempbuf[4] = ud.m_monsters_off; + tempbuf[5] = ud.m_respawn_monsters; + tempbuf[6] = ud.m_respawn_items; + tempbuf[7] = ud.m_respawn_inventory; + tempbuf[8] = ud.m_coop; + tempbuf[9] = ud.m_marker; + tempbuf[10] = ud.m_ffire; + + for(c=connecthead;c>=0;c=connectpoint2[c]) + { + resetweapons(c); + resetinventory(c); + + if(c != myconnectindex) + sendpacket(c,tempbuf,11); + } + + newgame(ud.m_volume_number,ud.m_level_number,ud.m_player_skill+1); + enterlevel(MODE_GAME); + + return; + + } + + c += 40; + + if(ud.m_coop==1) gametext(c+70,57-7-9,"COOPERATIVE PLAY",0,2+8+16); + else if(ud.m_coop==2) gametext(c+70,57-7-9,"DUKEMATCH (NO SPAWN)",0,2+8+16); + else gametext(c+70,57-7-9,"DUKEMATCH (SPAWN)",0,2+8+16); + + #ifdef VOLUMEONE + gametext(c+70,57+16-7-9,volume_names[ud.m_volume_number],0,2+8+16); + #else + gametext(c+70,57+16-7-9,volume_names[ud.m_volume_number],0,2+8+16); + #endif + + gametext(c+70,57+16+16-7-9,&level_names[11*ud.m_volume_number+ud.m_level_number][0],0,2+8+16); + + if(ud.m_monsters_off == 0 || ud.m_player_skill > 0) + gametext(c+70,57+16+16+16-7-9,skill_names[ud.m_player_skill],0,2+8+16); + else gametext(c+70,57+16+16+16-7-9,"NONE",0,2+8+16); + + if(ud.m_coop == 0) + { + if(ud.m_marker) + gametext(c+70,57+16+16+16+16-7-9,"ON",0,2+8+16); + else gametext(c+70,57+16+16+16+16-7-9,"OFF",0,2+8+16); + } + + if(ud.m_coop == 1) + { + if(ud.m_ffire) + gametext(c+70,57+16+16+16+16+16-7-9,"ON",0,2+8+16); + else gametext(c+70,57+16+16+16+16+16-7-9,"OFF",0,2+8+16); + } + + c -= 44; + + menutext(c,57-9,SHX(-2),PHX(-2),"GAME TYPE"); + +#ifdef VOLUMEONE + sprintf(tempbuf,"EPISODE %ld",ud.m_volume_number+1); + menutext(c,57+16-9,SHX(-3),1,tempbuf); +#else + sprintf(tempbuf,"EPISODE %ld",ud.m_volume_number+1); + menutext(c,57+16-9,SHX(-3),PHX(-3),tempbuf); +#endif + +#ifndef ONELEVELDEMO + sprintf(tempbuf,"LEVEL %ld",ud.m_level_number+1); + menutext(c,57+16+16-9,SHX(-4),PHX(-4),tempbuf); +#else + sprintf(tempbuf,"LEVEL %ld",ud.m_level_number+1); + menutext(c,57+16+16-9,SHX(-4),1,tempbuf); +#endif + menutext(c,57+16+16+16-9,SHX(-5),PHX(-5),"MONSTERS"); + + if(ud.m_coop == 0) + menutext(c,57+16+16+16+16-9,SHX(-6),PHX(-6),"MARKERS"); + else + menutext(c,57+16+16+16+16-9,SHX(-6),1,"MARKERS"); + + if(ud.m_coop == 1) + menutext(c,57+16+16+16+16+16-9,SHX(-6),PHX(-6),"FR. FIRE"); + else menutext(c,57+16+16+16+16+16-9,SHX(-6),1,"FR. FIRE"); + +#ifdef VOLUMEALL + menutext(c,57+16+16+16+16+16+16-9,SHX(-7),boardfilename[0] == 0,"USER MAP"); + if( boardfilename[0] != 0 ) + gametext(c+70+44,57+16+16+16+16+16,boardfilename,0,2+8+16); +#else + menutext(c,57+16+16+16+16+16+16-9,SHX(-7),1,"USER MAP"); +#endif + + menutext(c,57+16+16+16+16+16+16+16-9,SHX(-8),PHX(-8),"START GAME"); + + break; + } + + if( (ps[myconnectindex].gm&MODE_MENU) != MODE_MENU) + { + vscrn(); + cameraclock = totalclock; + cameradist = 65536L; + } +} + +void palto(char r,char g,char b,long e) +{ + int i; + char temparray[768]; + + for(i=0;i<768;i+=3) + { + temparray[i ] = + ps[myconnectindex].palette[i+0]+((((long)r-(long)ps[myconnectindex].palette[i+0])*(long)(e&127))>>6); + temparray[i+1] = + ps[myconnectindex].palette[i+1]+((((long)g-(long)ps[myconnectindex].palette[i+1])*(long)(e&127))>>6); + temparray[i+2] = + ps[myconnectindex].palette[i+2]+((((long)b-(long)ps[myconnectindex].palette[i+2])*(long)(e&127))>>6); + } + +// CTW - MODIFICATION +/* if( (e&128) == 0 ) + if ((vidoption != 1) || (vgacompatible == 1)) limitrate();*/ + if( (e&128) == 0 ) + if ((ScreenMode != 1) || (vgacompatible == 1)) limitrate(); +// CTW END - MODIFICATION + + setbrightness(ud.brightness>>2,temparray); +} + + +void drawoverheadmap(long cposx, long cposy, long czoom, short cang) +{ + long i=0l, j=0l, k=0l, l=0l, x1=0l, y1=0l, x2=0l, y2=0l, x3=0l; + long y3=0l, x4=0l, y4=0l, ox=0l, oy=0l, xoff=0l, yoff=0l; + long dax=0l, day=0l, cosang=0l, sinang=0l, xspan=0l, yspan=0l, sprx=0l, spry=0l; + long xrepeat=0l, yrepeat=0l, z1=0l, z2=0l, startwall=0l, endwall=0l, tilenum=0l, daang=0l; + long xvect=0l, yvect=0l, xvect2=0l, yvect2=0l; + short p=0l; + char col; + walltype *wal, *wal2; + spritetype *spr; + + xvect = sintable[(-cang)&2047] * czoom; + yvect = sintable[(1536-cang)&2047] * czoom; + xvect2 = mulscale16(xvect,yxaspect); + yvect2 = mulscale16(yvect,yxaspect); + + //Draw red lines + for(i=0;i>3]&(1<<(i&7)))) continue; + + startwall = sector[i].wallptr; + endwall = sector[i].wallptr + sector[i].wallnum; + + z1 = sector[i].ceilingz; z2 = sector[i].floorz; + + for(j=startwall,wal=&wall[startwall];jnextwall; if (k < 0) continue; + + //if ((show2dwall[j>>3]&(1<<(j&7))) == 0) continue; + //if ((k > j) && ((show2dwall[k>>3]&(1<<(k&7))) > 0)) continue; + + if (sector[wal->nextsector].ceilingz == z1) + if (sector[wal->nextsector].floorz == z2) + if (((wal->cstat|wall[wal->nextwall].cstat)&(16+32)) == 0) continue; + + col = 139; //red + if ((wal->cstat|wall[wal->nextwall].cstat)&1) col = 234; //magenta + + if (!(show2dsector[wal->nextsector>>3]&(1<<(wal->nextsector&7)))) + col = 24; + else continue; + + ox = wal->x-cposx; oy = wal->y-cposy; + x1 = dmulscale16(ox,xvect,-oy,yvect)+(xdim<<11); + y1 = dmulscale16(oy,xvect2,ox,yvect2)+(ydim<<11); + + wal2 = &wall[wal->point2]; + ox = wal2->x-cposx; oy = wal2->y-cposy; + x2 = dmulscale16(ox,xvect,-oy,yvect)+(xdim<<11); + y2 = dmulscale16(oy,xvect2,ox,yvect2)+(ydim<<11); + + drawline256(x1,y1,x2,y2,col); + } + } + + //Draw sprites + k = ps[screenpeek].i; + for(i=0;i>3]&(1<<(i&7)))) continue; + for(j=headspritesect[i];j>=0;j=nextspritesect[j]) + //if ((show2dsprite[j>>3]&(1<<(j&7))) > 0) + { + spr = &sprite[j]; + + if (j == k || (spr->cstat&0x8000) || spr->cstat == 257 || spr->xrepeat == 0) continue; + + col = 71; //cyan + if (spr->cstat&1) col = 234; //magenta + + sprx = spr->x; + spry = spr->y; + + if( (spr->cstat&257) != 0) switch (spr->cstat&48) + { + case 0: break; + + ox = sprx-cposx; oy = spry-cposy; + x1 = dmulscale16(ox,xvect,-oy,yvect); + y1 = dmulscale16(oy,xvect2,ox,yvect2); + + ox = (sintable[(spr->ang+512)&2047]>>7); + oy = (sintable[(spr->ang)&2047]>>7); + x2 = dmulscale16(ox,xvect,-oy,yvect); + y2 = dmulscale16(oy,xvect,ox,yvect); + + x3 = mulscale16(x2,yxaspect); + y3 = mulscale16(y2,yxaspect); + + drawline256(x1-x2+(xdim<<11),y1-y3+(ydim<<11), + x1+x2+(xdim<<11),y1+y3+(ydim<<11),col); + drawline256(x1-y2+(xdim<<11),y1+x3+(ydim<<11), + x1+x2+(xdim<<11),y1+y3+(ydim<<11),col); + drawline256(x1+y2+(xdim<<11),y1-x3+(ydim<<11), + x1+x2+(xdim<<11),y1+y3+(ydim<<11),col); + break; + + case 16: + if( spr->picnum == LASERLINE ) + { + x1 = sprx; y1 = spry; + tilenum = spr->picnum; + xoff = (long)((signed char)((picanm[tilenum]>>8)&255))+((long)spr->xoffset); + if ((spr->cstat&4) > 0) xoff = -xoff; + k = spr->ang; l = spr->xrepeat; + dax = sintable[k&2047]*l; day = sintable[(k+1536)&2047]*l; + l = tilesizx[tilenum]; k = (l>>1)+xoff; + x1 -= mulscale16(dax,k); x2 = x1+mulscale16(dax,l); + y1 -= mulscale16(day,k); y2 = y1+mulscale16(day,l); + + ox = x1-cposx; oy = y1-cposy; + x1 = dmulscale16(ox,xvect,-oy,yvect); + y1 = dmulscale16(oy,xvect2,ox,yvect2); + + ox = x2-cposx; oy = y2-cposy; + x2 = dmulscale16(ox,xvect,-oy,yvect); + y2 = dmulscale16(oy,xvect2,ox,yvect2); + + drawline256(x1+(xdim<<11),y1+(ydim<<11), + x2+(xdim<<11),y2+(ydim<<11),col); + } + + break; + + case 32: + + tilenum = spr->picnum; + xoff = (long)((signed char)((picanm[tilenum]>>8)&255))+((long)spr->xoffset); + yoff = (long)((signed char)((picanm[tilenum]>>16)&255))+((long)spr->yoffset); + if ((spr->cstat&4) > 0) xoff = -xoff; + if ((spr->cstat&8) > 0) yoff = -yoff; + + k = spr->ang; + cosang = sintable[(k+512)&2047]; sinang = sintable[k]; + xspan = tilesizx[tilenum]; xrepeat = spr->xrepeat; + yspan = tilesizy[tilenum]; yrepeat = spr->yrepeat; + + dax = ((xspan>>1)+xoff)*xrepeat; day = ((yspan>>1)+yoff)*yrepeat; + x1 = sprx + dmulscale16(sinang,dax,cosang,day); + y1 = spry + dmulscale16(sinang,day,-cosang,dax); + l = xspan*xrepeat; + x2 = x1 - mulscale16(sinang,l); + y2 = y1 + mulscale16(cosang,l); + l = yspan*yrepeat; + k = -mulscale16(cosang,l); x3 = x2+k; x4 = x1+k; + k = -mulscale16(sinang,l); y3 = y2+k; y4 = y1+k; + + ox = x1-cposx; oy = y1-cposy; + x1 = dmulscale16(ox,xvect,-oy,yvect); + y1 = dmulscale16(oy,xvect2,ox,yvect2); + + ox = x2-cposx; oy = y2-cposy; + x2 = dmulscale16(ox,xvect,-oy,yvect); + y2 = dmulscale16(oy,xvect2,ox,yvect2); + + ox = x3-cposx; oy = y3-cposy; + x3 = dmulscale16(ox,xvect,-oy,yvect); + y3 = dmulscale16(oy,xvect2,ox,yvect2); + + ox = x4-cposx; oy = y4-cposy; + x4 = dmulscale16(ox,xvect,-oy,yvect); + y4 = dmulscale16(oy,xvect2,ox,yvect2); + + drawline256(x1+(xdim<<11),y1+(ydim<<11), + x2+(xdim<<11),y2+(ydim<<11),col); + + drawline256(x2+(xdim<<11),y2+(ydim<<11), + x3+(xdim<<11),y3+(ydim<<11),col); + + drawline256(x3+(xdim<<11),y3+(ydim<<11), + x4+(xdim<<11),y4+(ydim<<11),col); + + drawline256(x4+(xdim<<11),y4+(ydim<<11), + x1+(xdim<<11),y1+(ydim<<11),col); + + break; + } + } + } + + //Draw white lines + for(i=0;i>3]&(1<<(i&7)))) continue; + + startwall = sector[i].wallptr; + endwall = sector[i].wallptr + sector[i].wallnum; + + k = -1; + for(j=startwall,wal=&wall[startwall];jnextwall >= 0) continue; + + //if ((show2dwall[j>>3]&(1<<(j&7))) == 0) continue; + + if (tilesizx[wal->picnum] == 0) continue; + if (tilesizy[wal->picnum] == 0) continue; + + if (j == k) + { x1 = x2; y1 = y2; } + else + { + ox = wal->x-cposx; oy = wal->y-cposy; + x1 = dmulscale16(ox,xvect,-oy,yvect)+(xdim<<11); + y1 = dmulscale16(oy,xvect2,ox,yvect2)+(ydim<<11); + } + + k = wal->point2; wal2 = &wall[k]; + ox = wal2->x-cposx; oy = wal2->y-cposy; + x2 = dmulscale16(ox,xvect,-oy,yvect)+(xdim<<11); + y2 = dmulscale16(oy,xvect2,ox,yvect2)+(ydim<<11); + + drawline256(x1,y1,x2,y2,24); + } + } + + for(p=connecthead;p >= 0;p=connectpoint2[p]) + { + if(ud.scrollmode && p == screenpeek) continue; + + ox = sprite[ps[p].i].x-cposx; oy = sprite[ps[p].i].y-cposy; + daang = (sprite[ps[p].i].ang-cang)&2047; + if (p == screenpeek) { ox = 0; oy = 0; daang = 0; } + x1 = mulscale(ox,xvect,16) - mulscale(oy,yvect,16); + y1 = mulscale(oy,xvect2,16) + mulscale(ox,yvect2,16); + + if(p == screenpeek || ud.coop == 1 ) + { + if(sprite[ps[p].i].xvel > 16 && ps[p].on_ground) + i = APLAYERTOP+((totalclock>>4)&3); + else + i = APLAYERTOP; + + j = klabs(ps[p].truefz-ps[p].posz)>>8; + j = mulscale(czoom*(sprite[ps[p].i].yrepeat+j),yxaspect,16); + + if(j < 22000) j = 22000; + else if(j > (65536<<1)) j = (65536<<1); + + rotatesprite((x1<<4)+(xdim<<15),(y1<<4)+(ydim<<15),j, + daang,i,sprite[ps[p].i].shade,sprite[ps[p].i].pal, + (sprite[ps[p].i].cstat&2)>>1,windowx1,windowy1,windowx2,windowy2); + } + } +} + + + +void endanimsounds(long fr) +{ + switch(ud.volume_number) + { + case 0:break; + case 1: + switch(fr) + { + case 1: + sound(WIND_AMBIENCE); + break; + case 26: + sound(ENDSEQVOL2SND1); + break; + case 36: + sound(ENDSEQVOL2SND2); + break; + case 54: + sound(THUD); + break; + case 62: + sound(ENDSEQVOL2SND3); + break; + case 75: + sound(ENDSEQVOL2SND4); + break; + case 81: + sound(ENDSEQVOL2SND5); + break; + case 115: + sound(ENDSEQVOL2SND6); + break; + case 124: + sound(ENDSEQVOL2SND7); + break; + } + break; + case 2: + switch(fr) + { + case 1: + sound(WIND_REPEAT); + break; + case 98: + sound(DUKE_GRUNT); + break; + case 82+20: + sound(THUD); + sound(SQUISHED); + break; + case 104+20: + sound(ENDSEQVOL3SND3); + break; + case 114+20: + sound(ENDSEQVOL3SND2); + break; + case 158: + sound(PIPEBOMB_EXPLODE); + break; + } + break; + } +} + +void logoanimsounds(long fr) +{ + switch(fr) + { + case 1: + sound(FLY_BY); + break; + case 19: + sound(PIPEBOMB_EXPLODE); + break; + } +} + +void intro4animsounds(long fr) +{ + switch(fr) + { + case 1: + sound(INTRO4_B); + break; + case 12: + case 34: + sound(SHORT_CIRCUIT); + break; + case 18: + sound(INTRO4_5); + break; + } +} + +void first4animsounds(long fr) +{ + switch(fr) + { + case 1: + sound(INTRO4_1); + break; + case 12: + sound(INTRO4_2); + break; + case 7: + sound(INTRO4_3); + break; + case 26: + sound(INTRO4_4); + break; + } +} + +void intro42animsounds(long fr) +{ + switch(fr) + { + case 10: + sound(INTRO4_6); + break; + } +} + + + + +void endanimvol41(long fr) +{ + switch(fr) + { + case 3: + sound(DUKE_UNDERWATER); + break; + case 35: + sound(VOL4ENDSND1); + break; + } +} + +void endanimvol42(long fr) +{ + switch(fr) + { + case 11: + sound(DUKE_UNDERWATER); + break; + case 20: + sound(VOL4ENDSND1); + break; + case 39: + sound(VOL4ENDSND2); + break; + case 50: + FX_StopAllSounds(); + break; + } +} + +void endanimvol43(long fr) +{ + switch(fr) + { + case 1: + sound(BOSS4_DEADSPEECH); + break; + case 40: + sound(VOL4ENDSND1); + sound(DUKE_UNDERWATER); + break; + case 50: + sound(BIGBANG); + break; + } +} + + +long lastanimhack=0; +void playanm(char *fn,char t) +{ + char *animbuf, *palptr; + long i, j, k, length=0, numframes=0; + int32 handle=-1; + +// return; + + if(t != 7 && t != 9 && t != 10 && t != 11) + KB_FlushKeyboardQueue(); + + if( KB_KeyWaiting() ) + { + FX_StopAllSounds(); + goto ENDOFANIMLOOP; + } + + handle = kopen4load(fn,0); + if(handle == -1) return; + length = kfilelength(handle); + + walock[MAXTILES-3-t] = 219+t; + + if(anim == 0 || lastanimhack != (MAXTILES-3-t)) + allocache((long *)&anim,length+sizeof(anim_t),&walock[MAXTILES-3-t]); + + animbuf = (char *)(FP_OFF(anim)+sizeof(anim_t)); + + lastanimhack = (MAXTILES-3-t); + + tilesizx[MAXTILES-3-t] = 200; + tilesizy[MAXTILES-3-t] = 320; + + kread(handle,animbuf,length); + kclose(handle); + + ANIM_LoadAnim (animbuf); + numframes = ANIM_NumFrames(); + + palptr = ANIM_GetPalette(); + for(i=0;i<256;i++) + { + j = (i<<2); k = j-i; + tempbuf[j+0] = (palptr[k+2]>>2); + tempbuf[j+1] = (palptr[k+1]>>2); + tempbuf[j+2] = (palptr[k+0]>>2); + tempbuf[j+3] = 0; + } + + VBE_setPalette(0L,256L,tempbuf); + + ototalclock = totalclock + 10; + + for(i=1;iheat_on) p->palette = slimepal; + else switch(sector[p->cursectnum].ceilingpicnum) + { + case FLOORSLIME: + case FLOORSLIME+1: + case FLOORSLIME+2: + p->palette = slimepal; + break; + default: + if(sector[p->cursectnum].lotag == 2) p->palette = waterpal; + else p->palette = palette; + break; + } + restorepalette = 1; +} + +void incur_damage( struct player_struct *p ) +{ + long damage = 0L, shield_damage = 0L; + short i, damage_source; + + sprite[p->i].extra -= p->extra_extra8>>8; + + damage = sprite[p->i].extra - p->last_extra; + + if ( damage < 0 ) + { + p->extra_extra8 = 0; + + if ( p->shield_amount > 0 ) + { + shield_damage = damage * (20 + (TRAND%30)) / 100; + damage -= shield_damage; + + p->shield_amount += shield_damage; + + if ( p->shield_amount < 0 ) + { + damage += p->shield_amount; + p->shield_amount = 0; + } + } + + sprite[p->i].extra = p->last_extra + damage; + } +} + +void quickkill(struct player_struct *p) +{ + p->pals[0] = 48; + p->pals[1] = 48; + p->pals[2] = 48; + p->pals_time = 48; + + sprite[p->i].extra = 0; + sprite[p->i].cstat |= 32768; + if(ud.god == 0) guts(&sprite[p->i],JIBS6,8,myconnectindex); + return; +} + +void forceplayerangle(struct player_struct *p) +{ + short n; + + n = 128-(TRAND&255); + + p->horiz += 64; + p->return_to_center = 9; + p->look_ang = n>>1; + p->rotscrnang = n>>1; +} + +void tracers(long x1,long y1,long z1,long x2,long y2,long z2,long n) +{ + long i, xv, yv, zv; + short sect = -1; + + i = n+1; + xv = (x2-x1)/i; + yv = (y2-y1)/i; + zv = (z2-z1)/i; + + if( ( klabs(x1-x2)+klabs(y1-y2) ) < 3084 ) + return; + + for(i=n;i>0;i--) + { + x1 += xv; + y1 += yv; + z1 += zv; + updatesector(x1,y1,§); + if(sect >= 0) + { + if(sector[sect].lotag == 2) + EGS(sect,x1,y1,z1,WATERBUBBLE,-32,4+(TRAND&3),4+(TRAND&3),TRAND&2047,0,0,ps[0].i,5); + else + EGS(sect,x1,y1,z1,SMALLSMOKE,-32,14,14,0,0,0,ps[0].i,5); + } + } +} + +long hits(short i) +{ + long sx,sy,sz; + short sect,hw,hs; + long zoff; + + if(PN == APLAYER) zoff = (40<<8); + else zoff = 0; + + hitscan(SX,SY,SZ-zoff,SECT, + sintable[(SA+512)&2047], + sintable[SA&2047], + 0,§,&hw,&hs,&sx,&sy,&sz,CLIPMASK1); + + return ( FindDistance2D( sx-SX,sy-SY ) ); +} + +long hitasprite(short i,short *hitsp) +{ + long sx,sy,sz,zoff; + short sect,hw; + + if(badguy(&sprite[i]) ) + zoff = (42<<8); + else if(PN == APLAYER) zoff = (39<<8); + else zoff = 0; + + hitscan(SX,SY,SZ-zoff,SECT, + sintable[(SA+512)&2047], + sintable[SA&2047], + 0,§,&hw,hitsp,&sx,&sy,&sz,CLIPMASK1); + + if(hw >= 0 && (wall[hw].cstat&16) && badguy(&sprite[i]) ) + return((1<<30)); + + return ( FindDistance2D(sx-SX,sy-SY) ); +} + +/* +long hitaspriteandwall(short i,short *hitsp,short *hitw,short *x, short *y) +{ + long sz; + short sect; + + hitscan(SX,SY,SZ,SECT, + sintable[(SA+512)&2047], + sintable[SA&2047], + 0,§,hitw,hitsp,x,y,&sz,CLIPMASK1); + + return ( FindDistance2D(*x-SX,*y-SY) ); +} +*/ + + +long hitawall(struct player_struct *p,short *hitw) +{ + long sx,sy,sz; + short sect,hs; + + hitscan(p->posx,p->posy,p->posz,p->cursectnum, + sintable[(p->ang+512)&2047], + sintable[p->ang&2047], + 0,§,hitw,&hs,&sx,&sy,&sz,CLIPMASK0); + + return ( FindDistance2D(sx-p->posx,sy-p->posy) ); +} + +short aim(spritetype *s,short aang) +{ + char gotshrinker,gotfreezer; + short i, j, a, k, cans; + short aimstats[] = {10,13,1,2}; + long dx1, dy1, dx2, dy2, dx3, dy3, smax, sdist; + long xv, yv; + + a = s->ang; + + j = -1; +// if(s->picnum == APLAYER && ps[s->yvel].aim_mode) return -1; + + gotshrinker = s->picnum == APLAYER && ps[s->yvel].curr_weapon == SHRINKER_WEAPON; + gotfreezer = s->picnum == APLAYER && ps[s->yvel].curr_weapon == FREEZE_WEAPON; + + smax = 0x7fffffff; + + dx1 = sintable[(a+512-aang)&2047]; + dy1 = sintable[(a-aang)&2047]; + dx2 = sintable[(a+512+aang)&2047]; + dy2 = sintable[(a+aang)&2047]; + + dx3 = sintable[(a+512)&2047]; + dy3 = sintable[a&2047]; + + for(k=0;k<4;k++) + { + if( j >= 0 ) + break; + for(i=headspritestat[aimstats[k]];i >= 0;i=nextspritestat[i]) + if( sprite[i].xrepeat > 0 && sprite[i].extra >= 0 && (sprite[i].cstat&(257+32768)) == 257) + if( badguy(&sprite[i]) || k < 2 ) + { + if(badguy(&sprite[i]) || PN == APLAYER || PN == SHARK) + { + if( PN == APLAYER && +// ud.ffire == 0 && + ud.coop == 1 && + s->picnum == APLAYER && + s != &sprite[i]) + continue; + + if(gotshrinker && sprite[i].xrepeat < 30 ) + { + switch(PN) + { + case SHARK: + if(sprite[i].xrepeat < 20) continue; + continue; + case GREENSLIME: + case GREENSLIME+1: + case GREENSLIME+2: + case GREENSLIME+3: + case GREENSLIME+4: + case GREENSLIME+5: + case GREENSLIME+6: + case GREENSLIME+7: + break; + default: + continue; + } + } + if(gotfreezer && sprite[i].pal == 1) continue; + } + + xv = (SX-s->x); + yv = (SY-s->y); + + if( (dy1*xv) <= (dx1*yv) ) + if( ( dy2*xv ) >= (dx2*yv) ) + { + sdist = mulscale(dx3,xv,14) + mulscale(dy3,yv,14); + if( sdist > 512 && sdist < smax ) + { + if(s->picnum == APLAYER) + a = (klabs(scale(SZ-s->z,10,sdist)-(ps[s->yvel].horiz+ps[s->yvel].horizoff-100)) < 100); + else a = 1; + + if(PN == ORGANTIC || PN == ROTATEGUN ) + cans = cansee(SX,SY,SZ,SECT,s->x,s->y,s->z-(32<<8),s->sectnum); + else cans = cansee(SX,SY,SZ-(32<<8),SECT,s->x,s->y,s->z-(32<<8),s->sectnum); + + if( a && cans ) + { + smax = sdist; + j = i; + } + } + } + } + } + + return j; +} + + + + +void shoot(short i,short atwith) +{ + short sect, hitsect, hitspr, hitwall, l, sa, p, j, k, scount; + long sx, sy, sz, vel, zvel, hitx, hity, hitz, x, oldzvel, dal; + unsigned char sizx,sizy; + spritetype *s; + + s = &sprite[i]; + sect = s->sectnum; + zvel = 0; + + if( s->picnum == APLAYER ) + { + p = s->yvel; + + sx = ps[p].posx; + sy = ps[p].posy; + sz = ps[p].posz+ps[p].pyoff+(4<<8); + sa = ps[p].ang; + + ps[p].crack_time = 777; + + } + else + { + p = -1; + sa = s->ang; + sx = s->x; + sy = s->y; + sz = s->z-((s->yrepeat*tilesizy[s->picnum])<<1)+(4<<8); + if(s->picnum != ROTATEGUN) + { + sz -= (7<<8); + if(badguy(s) && PN != COMMANDER) + { + sx += (sintable[(sa+1024+96)&2047]>>7); + sy += (sintable[(sa+512+96)&2047]>>7); + } + } + } + + switch(atwith) + { + case BLOODSPLAT1: + case BLOODSPLAT2: + case BLOODSPLAT3: + case BLOODSPLAT4: + + if(p >= 0) + sa += 64 - (TRAND&127); + else sa += 1024 + 64 - (TRAND&127); + zvel = 1024-(TRAND&2047); + case KNEE: + if(atwith == KNEE ) + { + if(p >= 0) + { + zvel = (100-ps[p].horiz-ps[p].horizoff)<<5; + sz += (6<<8); + sa += 15; + } + else + { + j = ps[findplayer(s,&x)].i; + zvel = ( (sprite[j].z-sz)<<8 ) / (x+1); + sa = getangle(sprite[j].x-sx,sprite[j].y-sy); + } + } + +// writestring(sx,sy,sz,sect,sintable[(sa+512)&2047],sintable[sa&2047],zvel<<6); + + hitscan(sx,sy,sz,sect, + sintable[(sa+512)&2047], + sintable[sa&2047],zvel<<6, + &hitsect,&hitwall,&hitspr,&hitx,&hity,&hitz,CLIPMASK1); + + if( atwith == BLOODSPLAT1 || + atwith == BLOODSPLAT2 || + atwith == BLOODSPLAT3 || + atwith == BLOODSPLAT4 ) + { + if( FindDistance2D(sx-hitx,sy-hity) < 1024 ) + if( hitwall >= 0 && wall[hitwall].overpicnum != BIGFORCE ) + if( ( wall[hitwall].nextsector >= 0 && hitsect >= 0 && + sector[wall[hitwall].nextsector].lotag == 0 && + sector[hitsect].lotag == 0 && + sector[wall[hitwall].nextsector].lotag == 0 && + (sector[hitsect].floorz-sector[wall[hitwall].nextsector].floorz) > (16<<8) ) || + ( wall[hitwall].nextsector == -1 && sector[hitsect].lotag == 0 ) ) + if( (wall[hitwall].cstat&16) == 0) + { + if(wall[hitwall].nextsector >= 0) + { + k = headspritesect[wall[hitwall].nextsector]; + while(k >= 0) + { + if(sprite[k].statnum == 3 && sprite[k].lotag == 13) + return; + k = nextspritesect[k]; + } + } + + if( wall[hitwall].nextwall >= 0 && + wall[wall[hitwall].nextwall].hitag != 0 ) + return; + + if(wall[hitwall].hitag == 0) + { + k = spawn(i,atwith); + sprite[k].xvel = -12; + sprite[k].ang = getangle(wall[hitwall].x-wall[wall[hitwall].point2].x, + wall[hitwall].y-wall[wall[hitwall].point2].y)+512; + sprite[k].x = hitx; + sprite[k].y = hity; + sprite[k].z = hitz; + sprite[k].cstat |= (TRAND&4); + ssp(k,CLIPMASK0); + setsprite(k,sprite[k].x,sprite[k].y,sprite[k].z); + if( PN == OOZFILTER || PN == NEWBEAST ) + sprite[k].pal = 6; + } + } + return; + } + + if(hitsect < 0) break; + + if( ( klabs(sx-hitx)+klabs(sy-hity) ) < 1024 ) + { + if(hitwall >= 0 || hitspr >= 0) + { + j = EGS(hitsect,hitx,hity,hitz,KNEE,-15,0,0,sa,32,0,i,4); + sprite[j].extra += (TRAND&7); + if(p >= 0) + { + k = spawn(j,SMALLSMOKE); + sprite[k].z -= (8<<8); + spritesound(KICK_HIT,j); + } + + if ( p >= 0 && ps[p].steroids_amount > 0 && ps[p].steroids_amount < 400 ) + sprite[j].extra += (max_player_health>>2); + + if( hitspr >= 0 && sprite[hitspr].picnum != ACCESSSWITCH && sprite[hitspr].picnum != ACCESSSWITCH2 ) + { + checkhitsprite(hitspr,j); + if(p >= 0) checkhitswitch(p,hitspr,1); + } + + else if( hitwall >= 0 ) + { + if( wall[hitwall].cstat&2 ) + if(wall[hitwall].nextsector >= 0) + if(hitz >= (sector[wall[hitwall].nextsector].floorz) ) + hitwall = wall[hitwall].nextwall; + + if( hitwall >= 0 && wall[hitwall].picnum != ACCESSSWITCH && wall[hitwall].picnum != ACCESSSWITCH2 ) + { + checkhitwall(j,hitwall,hitx,hity,hitz,atwith); + if(p >= 0) checkhitswitch(p,hitwall,0); + } + } + } + else if(p >= 0 && zvel > 0 && sector[hitsect].lotag == 1) + { + j = spawn(ps[p].i,WATERSPLASH2); + sprite[j].x = hitx; + sprite[j].y = hity; + sprite[j].ang = ps[p].ang; // Total tweek + sprite[j].xvel = 32; + ssp(i,CLIPMASK0); + sprite[j].xvel = 0; + + } + } + + break; + + case SHOTSPARK1: + case SHOTGUN: + case CHAINGUN: + + if( s->extra >= 0 ) s->shade = -96; + + if(p >= 0) + { + j = aim( s, AUTO_AIM_ANGLE ); + if(j >= 0) + { + dal = ((sprite[j].xrepeat*tilesizy[sprite[j].picnum])<<1)+(5<<8); + switch(sprite[j].picnum) + { + case GREENSLIME: + case GREENSLIME+1: + case GREENSLIME+2: + case GREENSLIME+3: + case GREENSLIME+4: + case GREENSLIME+5: + case GREENSLIME+6: + case GREENSLIME+7: + case ROTATEGUN: + dal -= (8<<8); + break; + } + zvel = ( ( sprite[j].z-sz-dal )<<8 ) / ldist(&sprite[ps[p].i], &sprite[j]) ; + sa = getangle(sprite[j].x-sx,sprite[j].y-sy); + } + + if(atwith == SHOTSPARK1) + { + if(j == -1) + { + sa += 16-(TRAND&31); + zvel = (100-ps[p].horiz-ps[p].horizoff)<<5; + zvel += 128-(TRAND&255); + } + } + else + { + sa += 16-(TRAND&31); + if(j == -1) zvel = (100-ps[p].horiz-ps[p].horizoff)<<5; + zvel += 128-(TRAND&255); + } + sz -= (2<<8); + } + else + { + j = findplayer(s,&x); + sz -= (4<<8); + zvel = ( (ps[j].posz-sz) <<8 ) / (ldist(&sprite[ps[j].i], s ) ); + if(s->picnum != BOSS1) + { + zvel += 128-(TRAND&255); + sa += 32-(TRAND&63); + } + else + { + zvel += 128-(TRAND&255); + sa = getangle(ps[j].posx-sx,ps[j].posy-sy)+64-(TRAND&127); + } + } + + s->cstat &= ~257; + hitscan(sx,sy,sz,sect, + sintable[(sa+512)&2047], + sintable[sa&2047], + zvel<<6,&hitsect,&hitwall,&hitspr,&hitx,&hity,&hitz,CLIPMASK1); + s->cstat |= 257; + + if(hitsect < 0) return; + + if( (TRAND&15) == 0 && sector[hitsect].lotag == 2 ) + tracers(hitx,hity,hitz,sx,sy,sz,8-(ud.multimode>>1)); + + if(p >= 0) + { + k = EGS(hitsect,hitx,hity,hitz,SHOTSPARK1,-15,10,10,sa,0,0,i,4); + sprite[k].extra = *actorscrptr[atwith]; + sprite[k].extra += (TRAND%6); + + if( hitwall == -1 && hitspr == -1) + { + if( zvel < 0 ) + { + if( sector[hitsect].ceilingstat&1 ) + { + sprite[k].xrepeat = 0; + sprite[k].yrepeat = 0; + return; + } + else + checkhitceiling(hitsect); + } + spawn(k,SMALLSMOKE); + } + + if(hitspr >= 0) + { + checkhitsprite(hitspr,k); + if( sprite[hitspr].picnum == APLAYER && (ud.coop != 1 || ud.ffire == 1) ) + { + l = spawn(k,JIBS6); + sprite[k].xrepeat = sprite[k].yrepeat = 0; + sprite[l].z += (4<<8); + sprite[l].xvel = 16; + sprite[l].xrepeat = sprite[l].yrepeat = 24; + sprite[l].ang += 64-(TRAND&127); + } + else spawn(k,SMALLSMOKE); + + if(p >= 0 && ( + sprite[hitspr].picnum == DIPSWITCH || + sprite[hitspr].picnum == DIPSWITCH+1 || + sprite[hitspr].picnum == DIPSWITCH2 || + sprite[hitspr].picnum == DIPSWITCH2+1 || + sprite[hitspr].picnum == DIPSWITCH3 || + sprite[hitspr].picnum == DIPSWITCH3+1 || + sprite[hitspr].picnum == HANDSWITCH || + sprite[hitspr].picnum == HANDSWITCH+1) ) + { + checkhitswitch(p,hitspr,1); + return; + } + } + else if( hitwall >= 0 ) + { + spawn(k,SMALLSMOKE); + + if( isadoorwall(wall[hitwall].picnum) == 1 ) + goto SKIPBULLETHOLE; + if(p >= 0 && ( + wall[hitwall].picnum == DIPSWITCH || + wall[hitwall].picnum == DIPSWITCH+1 || + wall[hitwall].picnum == DIPSWITCH2 || + wall[hitwall].picnum == DIPSWITCH2+1 || + wall[hitwall].picnum == DIPSWITCH3 || + wall[hitwall].picnum == DIPSWITCH3+1 || + wall[hitwall].picnum == HANDSWITCH || + wall[hitwall].picnum == HANDSWITCH+1) ) + { + checkhitswitch(p,hitwall,0); + return; + } + + if(wall[hitwall].hitag != 0 || ( wall[hitwall].nextwall >= 0 && wall[wall[hitwall].nextwall].hitag != 0 ) ) + goto SKIPBULLETHOLE; + + if( hitsect >= 0 && sector[hitsect].lotag == 0 ) + if( wall[hitwall].overpicnum != BIGFORCE ) + if( (wall[hitwall].nextsector >= 0 && sector[wall[hitwall].nextsector].lotag == 0 ) || + ( wall[hitwall].nextsector == -1 && sector[hitsect].lotag == 0 ) ) + if( (wall[hitwall].cstat&16) == 0) + { + if(wall[hitwall].nextsector >= 0) + { + l = headspritesect[wall[hitwall].nextsector]; + while(l >= 0) + { + if(sprite[l].statnum == 3 && sprite[l].lotag == 13) + goto SKIPBULLETHOLE; + l = nextspritesect[l]; + } + } + + l = headspritestat[5]; + while(l >= 0) + { + if(sprite[l].picnum == BULLETHOLE) + if(dist(&sprite[l],&sprite[k]) < (12+(TRAND&7)) ) + goto SKIPBULLETHOLE; + l = nextspritestat[l]; + } + l = spawn(k,BULLETHOLE); + sprite[l].xvel = -1; + sprite[l].ang = getangle(wall[hitwall].x-wall[wall[hitwall].point2].x, + wall[hitwall].y-wall[wall[hitwall].point2].y)+512; + ssp(l,CLIPMASK0); + } + + SKIPBULLETHOLE: + + if( wall[hitwall].cstat&2 ) + if(wall[hitwall].nextsector >= 0) + if(hitz >= (sector[wall[hitwall].nextsector].floorz) ) + hitwall = wall[hitwall].nextwall; + + checkhitwall(k,hitwall,hitx,hity,hitz,SHOTSPARK1); + } + } + else + { + k = EGS(hitsect,hitx,hity,hitz,SHOTSPARK1,-15,24,24,sa,0,0,i,4); + sprite[k].extra = *actorscrptr[atwith]; + + if( hitspr >= 0 ) + { + checkhitsprite(hitspr,k); + if( sprite[hitspr].picnum != APLAYER ) + spawn(k,SMALLSMOKE); + else sprite[k].xrepeat = sprite[k].yrepeat = 0; + } + else if( hitwall >= 0 ) + checkhitwall(k,hitwall,hitx,hity,hitz,SHOTSPARK1); + } + + if( (TRAND&255) < 4 ) + xyzsound(PISTOL_RICOCHET,k,hitx,hity,hitz); + + return; + + case FIRELASER: + case SPIT: + case COOLEXPLOSION1: + + if( s->extra >= 0 ) s->shade = -96; + + scount = 1; + if(atwith == SPIT) vel = 292; + else + { + if(atwith == COOLEXPLOSION1) + { + if(s->picnum == BOSS2) vel = 644; + else vel = 348; + sz -= (4<<7); + } + else + { + vel = 840; + sz -= (4<<7); + } + } + + if(p >= 0) + { + j = aim( s, AUTO_AIM_ANGLE ); + + if(j >= 0) + { + dal = ((sprite[j].xrepeat*tilesizy[sprite[j].picnum])<<1)-(12<<8); + zvel = ((sprite[j].z-sz-dal)*vel ) / ldist(&sprite[ps[p].i], &sprite[j]) ; + sa = getangle(sprite[j].x-sx,sprite[j].y-sy); + } + else + zvel = (100-ps[p].horiz-ps[p].horizoff)*98; + } + else + { + j = findplayer(s,&x); +// sa = getangle(ps[j].oposx-sx,ps[j].oposy-sy); + sa += 16-(TRAND&31); + zvel = ( ( (ps[j].oposz - sz + (3<<8) ) )*vel ) / ldist(&sprite[ps[j].i],s); + } + + oldzvel = zvel; + + if(atwith == SPIT) { sizx = 18;sizy = 18,sz -= (10<<8); } + else + { + if( atwith == FIRELASER ) + { + if(p >= 0) + { + + sizx = 34; + sizy = 34; + } + else + { + sizx = 18; + sizy = 18; + } + } + else + { + sizx = 18; + sizy = 18; + } + } + + if(p >= 0) sizx = 7,sizy = 7; + + while(scount > 0) + { + j = EGS(sect,sx,sy,sz,atwith,-127,sizx,sizy,sa,vel,zvel,i,4); + sprite[j].extra += (TRAND&7); + + if(atwith == COOLEXPLOSION1) + { + sprite[j].shade = 0; + if(PN == BOSS2) + { + l = sprite[j].xvel; + sprite[j].xvel = 1024; + ssp(j,CLIPMASK0); + sprite[j].xvel = l; + sprite[j].ang += 128-(TRAND&255); + } + } + + sprite[j].cstat = 128; + sprite[j].clipdist = 4; + + sa = s->ang+32-(TRAND&63); + zvel = oldzvel+512-(TRAND&1023); + + scount--; + } + + return; + + case FREEZEBLAST: + sz += (3<<8); + case RPG: + + if( s->extra >= 0 ) s->shade = -96; + + scount = 1; + vel = 644; + + j = -1; + + if(p >= 0) + { + j = aim( s, 48 ); + if(j >= 0) + { + dal = ((sprite[j].xrepeat*tilesizy[sprite[j].picnum])<<1)+(8<<8); + zvel = ( (sprite[j].z-sz-dal)*vel ) / ldist(&sprite[ps[p].i], &sprite[j]); + if( sprite[j].picnum != RECON ) + sa = getangle(sprite[j].x-sx,sprite[j].y-sy); + } + else zvel = (100-ps[p].horiz-ps[p].horizoff)*81; + if(atwith == RPG) + spritesound(RPG_SHOOT,i); + + } + else + { + j = findplayer(s,&x); + sa = getangle(ps[j].oposx-sx,ps[j].oposy-sy); + if(PN == BOSS3) + sz -= (32<<8); + else if(PN == BOSS2) + { + vel += 128; + sz += 24<<8; + } + + l = ldist(&sprite[ps[j].i],s); + zvel = ( (ps[j].oposz-sz)*vel) / l; + + if( badguy(s) && (s->hitag&face_player_smart) ) + sa = s->ang+(TRAND&31)-16; + } + + if( p >= 0 && j >= 0) + l = j; + else l = -1; + + j = EGS(sect, + sx+(sintable[(348+sa+512)&2047]/448), + sy+(sintable[(sa+348)&2047]/448), + sz-(1<<8),atwith,0,14,14,sa,vel,zvel,i,4); + + sprite[j].extra += (TRAND&7); + if(atwith != FREEZEBLAST) + sprite[j].yvel = l; + else + { + sprite[j].yvel = numfreezebounces; + sprite[j].xrepeat >>= 1; + sprite[j].yrepeat >>= 1; + sprite[j].zvel -= (2<<4); + } + + if(p == -1) + { + if(PN == BOSS3) + { + if(TRAND&1) + { + sprite[j].x -= sintable[sa&2047]>>6; + sprite[j].y -= sintable[(sa+1024+512)&2047]>>6; + sprite[j].ang -= 8; + } + else + { + sprite[j].x += sintable[sa&2047]>>6; + sprite[j].y += sintable[(sa+1024+512)&2047]>>6; + sprite[j].ang += 4; + } + sprite[j].xrepeat = 42; + sprite[j].yrepeat = 42; + } + else if(PN == BOSS2) + { + sprite[j].x -= sintable[sa&2047]/56; + sprite[j].y -= sintable[(sa+1024+512)&2047]/56; + sprite[j].ang -= 8+(TRAND&255)-128; + sprite[j].xrepeat = 24; + sprite[j].yrepeat = 24; + } + else if(atwith != FREEZEBLAST) + { + sprite[j].xrepeat = 30; + sprite[j].yrepeat = 30; + sprite[j].extra >>= 2; + } + } + else if(ps[p].curr_weapon == DEVISTATOR_WEAPON) + { + sprite[j].extra >>= 2; + sprite[j].ang += 16-(TRAND&31); + sprite[j].zvel += 256-(TRAND&511); + + if( ps[p].hbomb_hold_delay ) + { + sprite[j].x -= sintable[sa&2047]/644; + sprite[j].y -= sintable[(sa+1024+512)&2047]/644; + } + else + { + sprite[j].x += sintable[sa&2047]>>8; + sprite[j].y += sintable[(sa+1024+512)&2047]>>8; + } + sprite[j].xrepeat >>= 1; + sprite[j].yrepeat >>= 1; + } + + sprite[j].cstat = 128; + if(atwith == RPG) + sprite[j].clipdist = 4; + else + sprite[j].clipdist = 40; + + break; + + case HANDHOLDINGLASER: + + if(p >= 0) + zvel = (100-ps[p].horiz-ps[p].horizoff)*32; + else zvel = 0; + + hitscan(sx,sy,sz-ps[p].pyoff,sect, + sintable[(sa+512)&2047], + sintable[sa&2047], + zvel<<6,&hitsect,&hitwall,&hitspr,&hitx,&hity,&hitz,CLIPMASK1); + + j = 0; + if(hitspr >= 0) break; + + if(hitwall >= 0 && hitsect >= 0) + if( ((hitx-sx)*(hitx-sx)+(hity-sy)*(hity-sy)) < (290*290) ) + { + if( wall[hitwall].nextsector >= 0) + { + if( sector[wall[hitwall].nextsector].lotag <= 2 && sector[hitsect].lotag <= 2 ) + j = 1; + } + else if( sector[hitsect].lotag <= 2 ) + j = 1; + } + + if(j == 1) + { + k = EGS(hitsect,hitx,hity,hitz,TRIPBOMB,-16,4,5,sa,0,0,i,6); + + sprite[k].hitag = k; + spritesound(LASERTRIP_ONWALL,k); + sprite[k].xvel = -20; + ssp(k,CLIPMASK0); + sprite[k].cstat = 16; + hittype[k].temp_data[5] = sprite[k].ang = getangle(wall[hitwall].x-wall[wall[hitwall].point2].x,wall[hitwall].y-wall[wall[hitwall].point2].y)-512; + + if(p >= 0) + ps[p].ammo_amount[TRIPBOMB_WEAPON]--; + + } + return; + + case BOUNCEMINE: + case MORTER: + + if( s->extra >= 0 ) s->shade = -96; + + j = ps[findplayer(s,&x)].i; + x = ldist(&sprite[j],s); + + zvel = -x>>1; + + if(zvel < -4096) + zvel = -2048; + vel = x>>4; + + EGS(sect, + sx+(sintable[(512+sa+512)&2047]>>8), + sy+(sintable[(sa+512)&2047]>>8), + sz+(6<<8),atwith,-64,32,32,sa,vel,zvel,i,1); + break; + + case GROWSPARK: + + if(p >= 0) + { + j = aim( s, AUTO_AIM_ANGLE ); + if(j >= 0) + { + dal = ((sprite[j].xrepeat*tilesizy[sprite[j].picnum])<<1)+(5<<8); + switch(sprite[j].picnum) + { + case GREENSLIME: + case GREENSLIME+1: + case GREENSLIME+2: + case GREENSLIME+3: + case GREENSLIME+4: + case GREENSLIME+5: + case GREENSLIME+6: + case GREENSLIME+7: + case ROTATEGUN: + dal -= (8<<8); + break; + } + zvel = ( ( sprite[j].z-sz-dal )<<8 ) / (ldist(&sprite[ps[p].i], &sprite[j]) ); + sa = getangle(sprite[j].x-sx,sprite[j].y-sy); + } + else + { + sa += 16-(TRAND&31); + zvel = (100-ps[p].horiz-ps[p].horizoff)<<5; + zvel += 128-(TRAND&255); + } + + sz -= (2<<8); + } + else + { + j = findplayer(s,&x); + sz -= (4<<8); + zvel = ( (ps[j].posz-sz) <<8 ) / (ldist(&sprite[ps[j].i], s ) ); + zvel += 128-(TRAND&255); + sa += 32-(TRAND&63); + } + + k = 0; + +// RESHOOTGROW: + + s->cstat &= ~257; + hitscan(sx,sy,sz,sect, + sintable[(sa+512)&2047], + sintable[sa&2047], + zvel<<6,&hitsect,&hitwall,&hitspr,&hitx,&hity,&hitz,CLIPMASK1); + + s->cstat |= 257; + + j = EGS(sect,hitx,hity,hitz,GROWSPARK,-16,28,28,sa,0,0,i,1); + + sprite[j].pal = 2; + sprite[j].cstat |= 130; + sprite[j].xrepeat = sprite[j].yrepeat = 1; + + if( hitwall == -1 && hitspr == -1 && hitsect >= 0) + { + if( zvel < 0 && (sector[hitsect].ceilingstat&1) == 0) + checkhitceiling(hitsect); + } + else if(hitspr >= 0) checkhitsprite(hitspr,j); + else if(hitwall >= 0 && wall[hitwall].picnum != ACCESSSWITCH && wall[hitwall].picnum != ACCESSSWITCH2 ) + { + /* if(wall[hitwall].overpicnum == MIRROR && k == 0) + { + l = getangle( + wall[wall[hitwall].point2].x-wall[hitwall].x, + wall[wall[hitwall].point2].y-wall[hitwall].y); + + sx = hitx; + sy = hity; + sz = hitz; + sect = hitsect; + sa = ((l<<1) - sa)&2047; + sx += sintable[(sa+512)&2047]>>12; + sy += sintable[sa&2047]>>12; + + k++; + goto RESHOOTGROW; + } + else */ + checkhitwall(j,hitwall,hitx,hity,hitz,atwith); + } + + break; + case SHRINKER: + if( s->extra >= 0 ) s->shade = -96; + if(p >= 0) + { + j = aim( s, AUTO_AIM_ANGLE ); + if(j >= 0) + { + dal = ((sprite[j].xrepeat*tilesizy[sprite[j].picnum])<<1); + zvel = ( (sprite[j].z-sz-dal-(4<<8))*768) / (ldist( &sprite[ps[p].i], &sprite[j])); + sa = getangle(sprite[j].x-sx,sprite[j].y-sy); + } + else zvel = (100-ps[p].horiz-ps[p].horizoff)*98; + } + else if(s->statnum != 3) + { + j = findplayer(s,&x); + l = ldist(&sprite[ps[j].i],s); + zvel = ( (ps[j].oposz-sz)*512) / l ; + } + else zvel = 0; + + j = EGS(sect, + sx+(sintable[(512+sa+512)&2047]>>12), + sy+(sintable[(sa+512)&2047]>>12), + sz+(2<<8),SHRINKSPARK,-16,28,28,sa,768,zvel,i,4); + + sprite[j].cstat = 128; + sprite[j].clipdist = 32; + + + return; + } + return; +} + + + +void displayloogie(short snum) +{ + long i, a, x, y, z; + + if(ps[snum].loogcnt == 0) return; + + y = (ps[snum].loogcnt<<2); + for(i=0;i>5; + z = 4096+((ps[snum].loogcnt+i)<<9); + x = (-sync[snum].avel)+(sintable[((ps[snum].loogcnt+i)<<6)&2047]>>10); + + rotatesprite( + (ps[snum].loogiex[i]+x)<<16,(200+ps[snum].loogiey[i]-y)<<16,z-(i<<8),256-a, + LOOGIE,0,0,2,0,0,xdim-1,ydim-1); + } +} + +char animatefist(short gs,short snum) +{ + short looking_arc,fisti,fistpal; + long fistzoom, fistz; + + fisti = ps[snum].fist_incs; + if(fisti > 32) fisti = 32; + if(fisti <= 0) return 0; + + looking_arc = klabs(ps[snum].look_ang)/9; + + fistzoom = 65536L - (sintable[(512+(fisti<<6))&2047]<<2); + if(fistzoom > 90612L) + fistzoom = 90612L; + if(fistzoom < 40920) + fistzoom = 40290; + fistz = 194 + (sintable[((6+fisti)<<7)&2047]>>9); + + if(sprite[ps[snum].i].pal == 1) + fistpal = 1; + else + fistpal = sector[ps[snum].cursectnum].floorpal; + + rotatesprite( + (-fisti+222+(sync[snum].avel>>4))<<16, + (looking_arc+fistz)<<16, + fistzoom,0,FIST,gs,fistpal,2,0,0,xdim-1,ydim-1); + + return 1; +} + +char animateknee(short gs,short snum) +{ + short knee_y[] = {0,-8,-16,-32,-64,-84,-108,-108,-108,-72,-32,-8}; + short looking_arc, pal; + + if(ps[snum].knee_incs > 11 || ps[snum].knee_incs == 0 || sprite[ps[snum].i].extra <= 0) return 0; + + looking_arc = knee_y[ps[snum].knee_incs] + klabs(ps[snum].look_ang)/9; + + looking_arc -= (ps[snum].hard_landing<<3); + + if(sprite[ps[snum].i].pal == 1) + pal = 1; + else + { + pal = sector[ps[snum].cursectnum].floorpal; + if(pal == 0) + pal = ps[snum].palookup; + } + + myospal(105+(sync[snum].avel>>4)-(ps[snum].look_ang>>1)+(knee_y[ps[snum].knee_incs]>>2),looking_arc+280-((ps[snum].horiz-ps[snum].horizoff)>>4),KNEE,gs,4,pal); + + return 1; +} + +char animateknuckles(short gs,short snum) +{ + short knuckle_frames[] = {0,1,2,2,3,3,3,2,2,1,0}; + short looking_arc, pal; + + if(ps[snum].knuckle_incs == 0 || sprite[ps[snum].i].extra <= 0) return 0; + + looking_arc = klabs(ps[snum].look_ang)/9; + + looking_arc -= (ps[snum].hard_landing<<3); + + if(sprite[ps[snum].i].pal == 1) + pal = 1; + else + pal = sector[ps[snum].cursectnum].floorpal; + + myospal(160+(sync[snum].avel>>4)-(ps[snum].look_ang>>1),looking_arc+180-((ps[snum].horiz-ps[snum].horizoff)>>4),CRACKKNUCKLES+knuckle_frames[ps[snum].knuckle_incs>>1],gs,4,pal); + + return 1; +} + + + +long lastvisinc; + +void displaymasks(short snum) +{ + short i, p; + + if(sprite[ps[snum].i].pal == 1) + p = 1; + else + p = sector[ps[snum].cursectnum].floorpal; + + if(ps[snum].scuba_on) + { + if(ud.screen_size > 4) + { +// rotatesprite(43<<16,(200-8-(tilesizy[SCUBAMASK])<<16),65536,0,SCUBAMASK,0,p,2+16,windowx1,windowy1,windowx2,windowy2); +// rotatesprite((320-43)<<16,(200-8-(tilesizy[SCUBAMASK])<<16),65536,1024,SCUBAMASK,0,p,2+4+16,windowx1,windowy1,windowx2,windowy2); + rotatesprite(43<<16,(200-8-tilesizy[SCUBAMASK])<<16,65536,0,SCUBAMASK,0,p,2+16,windowx1,windowy1,windowx2,windowy2); + rotatesprite((320-43)<<16,(200-8-tilesizy[SCUBAMASK])<<16,65536,1024,SCUBAMASK,0,p,2+4+16,windowx1,windowy1,windowx2,windowy2); + } + else + { +// rotatesprite(43<<16,(200-(tilesizy[SCUBAMASK])<<16),65536,0,SCUBAMASK,0,p,2+16,windowx1,windowy1,windowx2,windowy2); +// rotatesprite((320-43)<<16,(200-(tilesizy[SCUBAMASK])<<16),65536,1024,SCUBAMASK,0,p,2+4+16,windowx1,windowy1,windowx2,windowy2); + rotatesprite(43<<16,(200-tilesizy[SCUBAMASK])<<16,65536,0,SCUBAMASK,0,p,2+16,windowx1,windowy1,windowx2,windowy2); + rotatesprite((320-43)<<16,(200-tilesizy[SCUBAMASK])<<16,65536,1024,SCUBAMASK,0,p,2+4+16,windowx1,windowy1,windowx2,windowy2); + } + } +} + +char animatetip(short gs,short snum) +{ + short p,looking_arc; + short tip_y[] = {0,-8,-16,-32,-64,-84,-108,-108,-108,-108,-108,-108,-108,-108,-108,-108,-96,-72,-64,-32,-16}; + + if(ps[snum].tipincs == 0) return 0; + + looking_arc = klabs(ps[snum].look_ang)/9; + looking_arc -= (ps[snum].hard_landing<<3); + + if(sprite[ps[snum].i].pal == 1) + p = 1; + else + p = sector[ps[snum].cursectnum].floorpal; + +/* if(ps[snum].access_spritenum >= 0) + p = sprite[ps[snum].access_spritenum].pal; + else + p = wall[ps[snum].access_wallnum].pal; + */ + myospal(170+(sync[snum].avel>>4)-(ps[snum].look_ang>>1), + (tip_y[ps[snum].tipincs]>>1)+looking_arc+240-((ps[snum].horiz-ps[snum].horizoff)>>4),TIP+((26-ps[snum].tipincs)>>4),gs,0,p); + + return 1; +} + +char animateaccess(short gs,short snum) +{ + short access_y[] = {0,-8,-16,-32,-64,-84,-108,-108,-108,-108,-108,-108,-108,-108,-108,-108,-96,-72,-64,-32,-16}; + short looking_arc; + char p; + + if(ps[snum].access_incs == 0 || sprite[ps[snum].i].extra <= 0) return 0; + + looking_arc = access_y[ps[snum].access_incs] + klabs(ps[snum].look_ang)/9; + looking_arc -= (ps[snum].hard_landing<<3); + + if(ps[snum].access_spritenum >= 0) + p = sprite[ps[snum].access_spritenum].pal; + else p = 0; +// else +// p = wall[ps[snum].access_wallnum].pal; + + if((ps[snum].access_incs-3) > 0 && (ps[snum].access_incs-3)>>3) + myospal(170+(sync[snum].avel>>4)-(ps[snum].look_ang>>1)+(access_y[ps[snum].access_incs]>>2),looking_arc+266-((ps[snum].horiz-ps[snum].horizoff)>>4),HANDHOLDINGLASER+(ps[snum].access_incs>>3),gs,0,p); + else + myospal(170+(sync[snum].avel>>4)-(ps[snum].look_ang>>1)+(access_y[ps[snum].access_incs]>>2),looking_arc+266-((ps[snum].horiz-ps[snum].horizoff)>>4),HANDHOLDINGACCESS,gs,4,p); + + return 1; +} + +short fistsign; + +void displayweapon(short snum) +{ + long gun_pos, looking_arc, cw; + long weapon_xoffset, i, j, x1, y1, x2; + char o,pal; + signed char gs; + struct player_struct *p; + short *kb; + + p = &ps[snum]; + kb = &p->kickback_pic; + + o = 0; + + looking_arc = klabs(p->look_ang)/9; + + gs = sprite[p->i].shade; + if(gs > 24) gs = 24; + + if(p->newowner >= 0 || ud.camerasprite >= 0 || p->over_shoulder_on > 0 || (sprite[p->i].pal != 1 && sprite[p->i].extra <= 0) || animatefist(gs,snum) || animateknuckles(gs,snum) || animatetip(gs,snum) || animateaccess(gs,snum) ) + return; + + animateknee(gs,snum); + + gun_pos = 80-(p->weapon_pos*p->weapon_pos); + + weapon_xoffset = (160)-90; + weapon_xoffset -= (sintable[((p->weapon_sway>>1)+512)&2047]/(1024+512)); + weapon_xoffset -= 58 + p->weapon_ang; + if( sprite[p->i].xrepeat < 32 ) + gun_pos -= klabs(sintable[(p->weapon_sway<<2)&2047]>>9); + else gun_pos -= klabs(sintable[(p->weapon_sway>>1)&2047]>>10); + + gun_pos -= (p->hard_landing<<3); + + if(p->last_weapon >= 0) + cw = p->last_weapon; + else cw = p->curr_weapon; + + j = 14-p->quick_kick; + if(j != 14) + { + if(sprite[p->i].pal == 1) + pal = 1; + else + { + pal = sector[p->cursectnum].floorpal; + if(pal == 0) + pal = p->palookup; + } + + + if( j < 5 || j > 9 ) + myospal(weapon_xoffset+80-(p->look_ang>>1), + looking_arc+250-gun_pos,KNEE,gs,o|4,pal); + else myospal(weapon_xoffset+160-16-(p->look_ang>>1), + looking_arc+214-gun_pos,KNEE+1,gs,o|4,pal); + } + + if( sprite[p->i].xrepeat < 40 ) + { + if(p->jetpack_on == 0 ) + { + i = sprite[p->i].xvel; + looking_arc += 32-(i>>1); + fistsign += i>>1; + } + cw = weapon_xoffset; + weapon_xoffset += sintable[(fistsign)&2047]>>10; + myos(weapon_xoffset+250-(p->look_ang>>1), + looking_arc+258-(klabs(sintable[(fistsign)&2047]>>8)), + FIST,gs,o); + weapon_xoffset = cw; + weapon_xoffset -= sintable[(fistsign)&2047]>>10; + myos(weapon_xoffset+40-(p->look_ang>>1), + looking_arc+200+(klabs(sintable[(fistsign)&2047]>>8)), + FIST,gs,o|4); + } + else switch(cw) + { + case KNEE_WEAPON: + if( (*kb) > 0 ) + { + if(sprite[p->i].pal == 1) + pal = 1; + else + { + pal = sector[p->cursectnum].floorpal; + if(pal == 0) + pal = p->palookup; + } + + if( (*kb) < 5 || (*kb) > 9 ) + myospal(weapon_xoffset+220-(p->look_ang>>1), + looking_arc+250-gun_pos,KNEE,gs,o,pal); + else + myospal(weapon_xoffset+160-(p->look_ang>>1), + looking_arc+214-gun_pos,KNEE+1,gs,o,pal); + } + break; + + case TRIPBOMB_WEAPON: + if(sprite[p->i].pal == 1) + pal = 1; + else + pal = sector[p->cursectnum].floorpal; + + weapon_xoffset += 8; + gun_pos -= 10; + + if((*kb) > 6) + looking_arc += ((*kb)<<3); + else if((*kb) < 4) + myospal(weapon_xoffset+142-(p->look_ang>>1), + looking_arc+234-gun_pos,HANDHOLDINGLASER+3,gs,o,pal); + + myospal(weapon_xoffset+130-(p->look_ang>>1), + looking_arc+249-gun_pos, + HANDHOLDINGLASER+((*kb)>>2),gs,o,pal); + myospal(weapon_xoffset+152-(p->look_ang>>1), + looking_arc+249-gun_pos, + HANDHOLDINGLASER+((*kb)>>2),gs,o|4,pal); + + break; + + case RPG_WEAPON: + if(sprite[p->i].pal == 1) + pal = 1; + else pal = sector[p->cursectnum].floorpal; + + weapon_xoffset -= sintable[(768+((*kb)<<7))&2047]>>11; + gun_pos += sintable[(768+((*kb)<<7))&2047]>>11; + + if(*kb > 0) + { + if(*kb < 8) + { + myospal(weapon_xoffset+164,(looking_arc<<1)+176-gun_pos, + RPGGUN+((*kb)>>1),gs,o,pal); + } + } + + myospal(weapon_xoffset+164,(looking_arc<<1)+176-gun_pos, + RPGGUN,gs,o,pal); + + break; + + case SHOTGUN_WEAPON: + if(sprite[p->i].pal == 1) + pal = 1; + else + pal = sector[p->cursectnum].floorpal; + + weapon_xoffset -= 8; + + switch(*kb) + { + case 1: + case 2: + myospal(weapon_xoffset+168-(p->look_ang>>1),looking_arc+201-gun_pos, + SHOTGUN+2,-128,o,pal); + case 0: + case 6: + case 7: + case 8: + myospal(weapon_xoffset+146-(p->look_ang>>1),looking_arc+202-gun_pos, + SHOTGUN,gs,o,pal); + break; + case 3: + case 4: + case 5: + case 9: + case 10: + case 11: + case 12: + if( *kb > 1 && *kb < 5 ) + { + gun_pos -= 40; + weapon_xoffset += 20; + + myospal(weapon_xoffset+178-(p->look_ang>>1),looking_arc+194-gun_pos, + SHOTGUN+1+((*(kb)-1)>>1),-128,o,pal); + } + + myospal(weapon_xoffset+158-(p->look_ang>>1),looking_arc+220-gun_pos, + SHOTGUN+3,gs,o,pal); + + break; + case 13: + case 14: + case 15: + myospal(32+weapon_xoffset+166-(p->look_ang>>1),looking_arc+210-gun_pos, + SHOTGUN+4,gs,o,pal); + break; + case 16: + case 17: + case 18: + case 19: + myospal(64+weapon_xoffset+170-(p->look_ang>>1),looking_arc+196-gun_pos, + SHOTGUN+5,gs,o,pal); + break; + case 20: + case 21: + case 22: + case 23: + myospal(64+weapon_xoffset+176-(p->look_ang>>1),looking_arc+196-gun_pos, + SHOTGUN+6,gs,o,pal); + break; + case 24: + case 25: + case 26: + case 27: + myospal(64+weapon_xoffset+170-(p->look_ang>>1),looking_arc+196-gun_pos, + SHOTGUN+5,gs,o,pal); + break; + case 28: + case 29: + case 30: + myospal(32+weapon_xoffset+156-(p->look_ang>>1),looking_arc+206-gun_pos, + SHOTGUN+4,gs,o,pal); + break; + } + break; + + + + case CHAINGUN_WEAPON: + if(sprite[p->i].pal == 1) + pal = 1; + else + pal = sector[p->cursectnum].floorpal; + + if(*kb > 0) + gun_pos -= sintable[(*kb)<<7]>>12; + + if(*kb > 0 && sprite[p->i].pal != 1) weapon_xoffset += 1-(rand()&3); + + myospal(weapon_xoffset+168-(p->look_ang>>1),looking_arc+260-gun_pos, + CHAINGUN,gs,o,pal); + switch(*kb) + { + case 0: + myospal(weapon_xoffset+178-(p->look_ang>>1),looking_arc+233-gun_pos, + CHAINGUN+1,gs,o,pal); + break; + default: + if(*kb > 4 && *kb < 12) + { + i = 0; + if(sprite[p->i].pal != 1) i = rand()&7; + myospal(i+weapon_xoffset-4+140-(p->look_ang>>1),i+looking_arc-((*kb)>>1)+208-gun_pos, + CHAINGUN+5+((*kb-4)/5),gs,o,pal); + if(sprite[p->i].pal != 1) i = rand()&7; + myospal(i+weapon_xoffset-4+184-(p->look_ang>>1),i+looking_arc-((*kb)>>1)+208-gun_pos, + CHAINGUN+5+((*kb-4)/5),gs,o,pal); + } + if(*kb < 8) + { + i = rand()&7; + myospal(i+weapon_xoffset-4+162-(p->look_ang>>1),i+looking_arc-((*kb)>>1)+208-gun_pos, + CHAINGUN+5+((*kb-2)/5),gs,o,pal); + myospal(weapon_xoffset+178-(p->look_ang>>1),looking_arc+233-gun_pos, + CHAINGUN+1+((*kb)>>1),gs,o,pal); + } + else myospal(weapon_xoffset+178-(p->look_ang>>1),looking_arc+233-gun_pos, + CHAINGUN+1,gs,o,pal); + break; + } + break; + case PISTOL_WEAPON: + if(sprite[p->i].pal == 1) + pal = 1; + else + pal = sector[p->cursectnum].floorpal; + + if( (*kb) < 5) + { + short kb_frames[] = {0,1,2,0,0},l; + + l = 195-12+weapon_xoffset; + + if((*kb) == 2) + l -= 3; + myospal( + (l-(p->look_ang>>1)), + (looking_arc+244-gun_pos), + FIRSTGUN+kb_frames[*kb], + gs,2,pal); + } + else + { + if((*kb) < 10) + myospal(194-(p->look_ang>>1),looking_arc+230-gun_pos,FIRSTGUN+4,gs,o,pal); + else if((*kb) < 15) + { + myospal(244-((*kb)<<3)-(p->look_ang>>1),looking_arc+130-gun_pos+((*kb)<<4),FIRSTGUN+6,gs,o,pal); + myospal(224-(p->look_ang>>1),looking_arc+220-gun_pos,FIRSTGUN+5,gs,o,pal); + } + else if((*kb) < 20) + { + myospal(124+((*kb)<<1)-(p->look_ang>>1),looking_arc+430-gun_pos-((*kb)<<3),FIRSTGUN+6,gs,o,pal); + myospal(224-(p->look_ang>>1),looking_arc+220-gun_pos,FIRSTGUN+5,gs,o,pal); + } + else if((*kb) < 23) + { + myospal(184-(p->look_ang>>1),looking_arc+235-gun_pos,FIRSTGUN+8,gs,o,pal); + myospal(224-(p->look_ang>>1),looking_arc+210-gun_pos,FIRSTGUN+5,gs,o,pal); + } + else if((*kb) < 25) + { + myospal(164-(p->look_ang>>1),looking_arc+245-gun_pos,FIRSTGUN+8,gs,o,pal); + myospal(224-(p->look_ang>>1),looking_arc+220-gun_pos,FIRSTGUN+5,gs,o,pal); + } + else if((*kb) < 27) + myospal(194-(p->look_ang>>1),looking_arc+235-gun_pos,FIRSTGUN+5,gs,o,pal); + } + + break; + case HANDBOMB_WEAPON: + { + if(sprite[p->i].pal == 1) + pal = 1; + else + pal = sector[p->cursectnum].floorpal; + + if((*kb)) + { + char throw_frames[] + = {0,0,0,0,0,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2}; + + if((*kb) < 7) + gun_pos -= 10*(*kb); //D + else if((*kb) < 12) + gun_pos += 20*((*kb)-10); //U + else if((*kb) < 20) + gun_pos -= 9*((*kb)-14); //D + + myospal(weapon_xoffset+190-(p->look_ang>>1),looking_arc+250-gun_pos,HANDTHROW+throw_frames[(*kb)],gs,o,pal); + } + else + myospal(weapon_xoffset+190-(p->look_ang>>1),looking_arc+260-gun_pos,HANDTHROW,gs,o,pal); + } + break; + + case HANDREMOTE_WEAPON: + { + signed char remote_frames[] = {0,1,1,2,1,1,0,0,0,0,0}; + if(sprite[p->i].pal == 1) + pal = 1; + else + pal = sector[p->cursectnum].floorpal; + + weapon_xoffset = -48; + + if((*kb)) + myospal(weapon_xoffset+150-(p->look_ang>>1),looking_arc+258-gun_pos,HANDREMOTE+remote_frames[(*kb)],gs,o,pal); + else + myospal(weapon_xoffset+150-(p->look_ang>>1),looking_arc+258-gun_pos,HANDREMOTE,gs,o,pal); + } + break; + case DEVISTATOR_WEAPON: + if(sprite[p->i].pal == 1) + pal = 1; + else + pal = sector[p->cursectnum].floorpal; + + if((*kb)) + { + char cycloidy[] = {0,4,12,24,12,4,0}; + + i = sgn((*kb)>>2); + + if(p->hbomb_hold_delay) + { + myospal( (cycloidy[*kb]>>1)+weapon_xoffset+268-(p->look_ang>>1),cycloidy[*kb]+looking_arc+238-gun_pos,DEVISTATOR+i,-32,o,pal); + myospal(weapon_xoffset+30-(p->look_ang>>1),looking_arc+240-gun_pos,DEVISTATOR,gs,o|4,pal); + } + else + { + myospal( -(cycloidy[*kb]>>1)+weapon_xoffset+30-(p->look_ang>>1),cycloidy[*kb]+looking_arc+240-gun_pos,DEVISTATOR+i,-32,o|4,pal); + myospal(weapon_xoffset+268-(p->look_ang>>1),looking_arc+238-gun_pos,DEVISTATOR,gs,o,pal); + } + } + else + { + myospal(weapon_xoffset+268-(p->look_ang>>1),looking_arc+238-gun_pos,DEVISTATOR,gs,o,pal); + myospal(weapon_xoffset+30-(p->look_ang>>1),looking_arc+240-gun_pos,DEVISTATOR,gs,o|4,pal); + } + break; + + case FREEZE_WEAPON: + if(sprite[p->i].pal == 1) + pal = 1; + else + pal = sector[p->cursectnum].floorpal; + + if((*kb)) + { + char cat_frames[] = { 0,0,1,1,2,2 }; + + if(sprite[p->i].pal != 1) + { + weapon_xoffset += rand()&3; + looking_arc += rand()&3; + } + gun_pos -= 16; + myospal(weapon_xoffset+210-(p->look_ang>>1),looking_arc+261-gun_pos,FREEZE+2,-32,o,pal); + myospal(weapon_xoffset+210-(p->look_ang>>1),looking_arc+235-gun_pos,FREEZE+3+cat_frames[*kb%6],-32,o,pal); + } + else myospal(weapon_xoffset+210-(p->look_ang>>1),looking_arc+261-gun_pos,FREEZE,gs,o,pal); + + break; + + case SHRINKER_WEAPON: + case GROW_WEAPON: + weapon_xoffset += 28; + looking_arc += 18; + if(sprite[p->i].pal == 1) + pal = 1; + else + pal = sector[p->cursectnum].floorpal; + if((*kb) == 0) + { + if(cw == GROW_WEAPON) + { + myospal(weapon_xoffset+184-(p->look_ang>>1), + looking_arc+240-gun_pos,SHRINKER+2, + 16-(sintable[p->random_club_frame&2047]>>10), + o,2); + + myospal(weapon_xoffset+188-(p->look_ang>>1), + looking_arc+240-gun_pos,SHRINKER-2,gs,o,pal); + } + else + { + myospal(weapon_xoffset+184-(p->look_ang>>1), + looking_arc+240-gun_pos,SHRINKER+2, + 16-(sintable[p->random_club_frame&2047]>>10), + o,0); + + myospal(weapon_xoffset+188-(p->look_ang>>1), + looking_arc+240-gun_pos,SHRINKER,gs,o,pal); + } + } + else + { + if(sprite[p->i].pal != 1) + { + weapon_xoffset += rand()&3; + gun_pos += (rand()&3); + } + + if(cw == GROW_WEAPON) + { + myospal(weapon_xoffset+184-(p->look_ang>>1), + looking_arc+240-gun_pos,SHRINKER+3+((*kb)&3),-32, + o,2); + + myospal(weapon_xoffset+188-(p->look_ang>>1), + looking_arc+240-gun_pos,SHRINKER-1,gs,o,pal); + + } + else + { + myospal(weapon_xoffset+184-(p->look_ang>>1), + looking_arc+240-gun_pos,SHRINKER+3+((*kb)&3),-32, + o,0); + + myospal(weapon_xoffset+188-(p->look_ang>>1), + looking_arc+240-gun_pos,SHRINKER+1,gs,o,pal); + } + } + break; + } + + displayloogie(snum); + +} + +#define TURBOTURNTIME (TICRATE/8) // 7 +#define NORMALTURN 15 +#define PREAMBLETURN 5 +#define NORMALKEYMOVE 40 +#define MAXVEL ((NORMALKEYMOVE*2)+10) +#define MAXSVEL ((NORMALKEYMOVE*2)+10) +#define MAXANGVEL 127 +#define MAXHORIZ 127 + +long myaimmode = 0, myaimstat = 0, omyaimstat = 0; + +void getinput(short snum) +{ + + short j, daang; +// MED + ControlInfo info; + int32 tics; + boolean running; + int32 turnamount; + int32 keymove; + int32 momx,momy; + struct player_struct *p; + + momx = momy = 0; + p = &ps[snum]; + + CONTROL_GetInput( &info ); + + if( (p->gm&MODE_MENU) || (p->gm&MODE_TYPE) || (ud.pause_on && !KB_KeyPressed(sc_Pause)) ) + { + loc.fvel = vel = 0; + loc.svel = svel = 0; + loc.avel = angvel = 0; + loc.horz = horiz = 0; + loc.bits = (((long)gamequit)<<26); + info.dz = info.dyaw = 0; + return; + } + + tics = totalclock-lastcontroltime; + lastcontroltime = totalclock; + + if (MouseAiming) + myaimmode = BUTTON(gamefunc_Mouse_Aiming); + else + { + omyaimstat = myaimstat; myaimstat = BUTTON(gamefunc_Mouse_Aiming); + if (myaimstat > omyaimstat) + { + myaimmode ^= 1; + FTA(44+myaimmode,p); + } + } + + if(multiflag == 1) + { + loc.bits = 1<<17; + loc.bits |= multiwhat<<18; + loc.bits |= multipos<<19; + multiflag = 0; + return; + } + + loc.bits = BUTTON(gamefunc_Jump); + loc.bits |= BUTTON(gamefunc_Crouch)<<1; + loc.bits |= BUTTON(gamefunc_Fire)<<2; + loc.bits |= BUTTON(gamefunc_Aim_Up)<<3; + loc.bits |= BUTTON(gamefunc_Aim_Down)<<4; + loc.bits |= BUTTON(gamefunc_Run)<<5; + loc.bits |= BUTTON(gamefunc_Look_Left)<<6; + loc.bits |= BUTTON(gamefunc_Look_Right)<<7; + + j=0; + if (BUTTON(gamefunc_Weapon_1)) + j = 1; + if (BUTTON(gamefunc_Weapon_2)) + j = 2; + if (BUTTON(gamefunc_Weapon_3)) + j = 3; + if (BUTTON(gamefunc_Weapon_4)) + j = 4; + if (BUTTON(gamefunc_Weapon_5)) + j = 5; + if (BUTTON(gamefunc_Weapon_6)) + j = 6; + + if (BUTTON(gamefunc_Previous_Weapon)) + j = 11; + if (BUTTON(gamefunc_Next_Weapon)) + j = 12; + + #ifndef VOLUMEONE + if (BUTTON(gamefunc_Weapon_7)) + j = 7; + if (BUTTON(gamefunc_Weapon_8)) + j = 8; + if (BUTTON(gamefunc_Weapon_9)) + j = 9; + if (BUTTON(gamefunc_Weapon_10)) + j = 10; + #endif + + loc.bits |= j<<8; + loc.bits |= BUTTON(gamefunc_Steroids)<<12; + loc.bits |= BUTTON(gamefunc_Look_Up)<<13; + loc.bits |= BUTTON(gamefunc_Look_Down)<<14; + loc.bits |= BUTTON(gamefunc_NightVision)<<15; + loc.bits |= BUTTON(gamefunc_MedKit)<<16; + loc.bits |= BUTTON(gamefunc_Center_View)<<18; + loc.bits |= BUTTON(gamefunc_Holster_Weapon)<<19; + loc.bits |= BUTTON(gamefunc_Inventory_Left)<<20; + loc.bits |= KB_KeyPressed(sc_Pause)<<21; + loc.bits |= BUTTON(gamefunc_Quick_Kick)<<22; + loc.bits |= myaimmode<<23; + loc.bits |= BUTTON(gamefunc_Holo_Duke)<<24; + loc.bits |= BUTTON(gamefunc_Jetpack)<<25; + loc.bits |= (((long)gamequit)<<26); + loc.bits |= BUTTON(gamefunc_Inventory_Right)<<27; + loc.bits |= BUTTON(gamefunc_TurnAround)<<28; + loc.bits |= BUTTON(gamefunc_Open)<<29; + loc.bits |= BUTTON(gamefunc_Inventory)<<30; + loc.bits |= KB_KeyPressed(sc_Escape)<<31; + + running = BUTTON(gamefunc_Run)|ud.auto_run; + svel = vel = angvel = horiz = 0; + + if( CONTROL_JoystickEnabled ) + if ( running ) info.dz *= 2; + + if( BUTTON(gamefunc_Strafe) ) + svel = -info.dyaw/8; + else angvel = info.dyaw/64; + + // Account for which mode we're in. (1, 2 or 7) + switch(ControllerType) + { + case controltype_keyboardandjoystick: + case controltype_joystickandmouse: + { + if(CONTROL_JoystickEnabled) + { + // + if(ud.mouseflip) + { + horiz -= info.dpitch/(314-128); + } + else + { + horiz += info.dpitch/(314-128); + } + + info.dpitch = 0; + } + } + break; + default: + { + // If Mouse aim active + if( myaimmode ) + { + // + if(ud.mouseflip) + { + horiz -= info.dpitch/(314-128); + } + else + { + horiz += info.dpitch/(314-128); + } + + info.dpitch = 0; + } + } + break; + } + + /* + if( myaimmode ) + { + if(ud.mouseflip) + horiz -= info.dz/(314-128); + else horiz += info.dz/(314-128); + + info.dz = 0; + } + */ + + svel -= info.dx; + vel = -info.dz>>6; + + if (running) + { + turnamount = NORMALTURN<<1; + keymove = NORMALKEYMOVE<<1; + } + else + { + turnamount = NORMALTURN; + keymove = NORMALKEYMOVE; + } + + if (BUTTON(gamefunc_Strafe)) + { + if ( BUTTON(gamefunc_Turn_Left)) + { + svel -= -keymove; + } + if ( BUTTON(gamefunc_Turn_Right)) + { + svel -= keymove; + } + } + else + { + if ( BUTTON(gamefunc_Turn_Left)) + { + turnheldtime += tics; + if (turnheldtime>=TURBOTURNTIME) + { + angvel -= turnamount; + } + else + { + angvel -= PREAMBLETURN; + } + } + else if ( BUTTON(gamefunc_Turn_Right)) + { + turnheldtime += tics; + if (turnheldtime>=TURBOTURNTIME) + { + angvel += turnamount; + } + else + { + angvel += PREAMBLETURN; + } + } + else + { + turnheldtime=0; + } + } + + if ( BUTTON( gamefunc_Strafe_Left ) ) + svel += keymove; + + if ( BUTTON( gamefunc_Strafe_Right ) ) + svel += -keymove; + + if ( BUTTON(gamefunc_Move_Forward) ) + vel += keymove; + + if ( BUTTON(gamefunc_Move_Backward) ) + vel += -keymove; + + if(vel < -MAXVEL) vel = -MAXVEL; + if(vel > MAXVEL) vel = MAXVEL; + if(svel < -MAXSVEL) svel = -MAXSVEL; + if(svel > MAXSVEL) svel = MAXSVEL; + if(angvel < -MAXANGVEL) angvel = -MAXANGVEL; + if(angvel > MAXANGVEL) angvel = MAXANGVEL; + if(horiz < -MAXHORIZ) horiz = -MAXHORIZ; + if(horiz > MAXHORIZ) horiz = MAXHORIZ; + + if(ud.scrollmode && ud.overhead_on) + { + ud.folfvel = vel; + ud.folavel = angvel; + loc.fvel = 0; + loc.svel = 0; + loc.avel = 0; + loc.horz = 0; + return; + } + + if( numplayers > 1 ) + daang = myang; + else daang = p->ang; + + momx = mulscale9(vel,sintable[(daang+2560)&2047]); + momy = mulscale9(vel,sintable[(daang+2048)&2047]); + + momx += mulscale9(svel,sintable[(daang+2048)&2047]); + momy += mulscale9(svel,sintable[(daang+1536)&2047]); + + momx += fricxv; + momy += fricyv; + + loc.fvel = momx; + loc.svel = momy; + loc.avel = angvel; + loc.horz = horiz; +} + + +char doincrements(struct player_struct *p) +{ + long /*j,*/i,snum; + + snum = sprite[p->i].yvel; +// j = sync[snum].avel; +// p->weapon_ang = -(j/5); + + p->player_par++; + + if(p->invdisptime > 0) + p->invdisptime--; + + if(p->tipincs > 0) p->tipincs--; + + if(p->last_pissed_time > 0 ) + { + p->last_pissed_time--; + + if( p->last_pissed_time == (26*219) ) + { + spritesound(FLUSH_TOILET,p->i); + if(snum == screenpeek || ud.coop == 1) + spritesound(DUKE_PISSRELIEF,p->i); + } + + if( p->last_pissed_time == (26*218) ) + { + p->holster_weapon = 0; + p->weapon_pos = 10; + } + } + + if(p->crack_time > 0) + { + p->crack_time--; + if(p->crack_time == 0) + { + p->knuckle_incs = 1; + p->crack_time = 777; + } + } + + if( p->steroids_amount > 0 && p->steroids_amount < 400) + { + p->steroids_amount--; + if(p->steroids_amount == 0) + checkavailinven(p); + if( !(p->steroids_amount&7) ) + if(snum == screenpeek || ud.coop == 1) + spritesound(DUKE_HARTBEAT,p->i); + } + + if(p->heat_on && p->heat_amount > 0) + { + p->heat_amount--; + if( p->heat_amount == 0 ) + { + p->heat_on = 0; + checkavailinven(p); + spritesound(NITEVISION_ONOFF,p->i); + setpal(p); + } + } + + if( p->holoduke_on >= 0 ) + { + p->holoduke_amount--; + if(p->holoduke_amount <= 0) + { + spritesound(TELEPORTER,p->i); + p->holoduke_on = -1; + checkavailinven(p); + } + } + + if( p->jetpack_on && p->jetpack_amount > 0 ) + { + p->jetpack_amount--; + if(p->jetpack_amount <= 0) + { + p->jetpack_on = 0; + checkavailinven(p); + spritesound(DUKE_JETPACK_OFF,p->i); + stopsound(DUKE_JETPACK_IDLE); + stopsound(DUKE_JETPACK_ON); + } + } + + if(p->quick_kick > 0 && sprite[p->i].pal != 1) + { + p->quick_kick--; + if( p->quick_kick == 8 ) + shoot(p->i,KNEE); + } + + if(p->access_incs && sprite[p->i].pal != 1) + { + p->access_incs++; + if(sprite[p->i].extra <= 0) + p->access_incs = 12; + if(p->access_incs == 12) + { + if(p->access_spritenum >= 0) + { + checkhitswitch(snum,p->access_spritenum,1); + switch(sprite[p->access_spritenum].pal) + { + case 0:p->got_access &= (0xffff-0x1);break; + case 21:p->got_access &= (0xffff-0x2);break; + case 23:p->got_access &= (0xffff-0x4);break; + } + p->access_spritenum = -1; + } + else + { + checkhitswitch(snum,p->access_wallnum,0); + switch(wall[p->access_wallnum].pal) + { + case 0:p->got_access &= (0xffff-0x1);break; + case 21:p->got_access &= (0xffff-0x2);break; + case 23:p->got_access &= (0xffff-0x4);break; + } + } + } + + if(p->access_incs > 20) + { + p->access_incs = 0; + p->weapon_pos = 10; + p->kickback_pic = 0; + } + } + + if(p->scuba_on == 0 && sector[p->cursectnum].lotag == 2) + { + if(p->scuba_amount > 0) + { + p->scuba_on = 1; + p->inven_icon = 6; + FTA(76,p); + } + else + { + if(p->airleft > 0) + p->airleft--; + else + { + p->extra_extra8 += 32; + if(p->last_extra < (max_player_health>>1) && (p->last_extra&3) == 0) + spritesound(DUKE_LONGTERM_PAIN,p->i); + } + } + } + else if(p->scuba_amount > 0 && p->scuba_on) + { + p->scuba_amount--; + if(p->scuba_amount == 0) + { + p->scuba_on = 0; + checkavailinven(p); + } + } + + if(p->knuckle_incs) + { + p->knuckle_incs ++; + if(p->knuckle_incs==10) + { + if(totalclock > 1024) + if(snum == screenpeek || ud.coop == 1) + { + if(rand()&1) + spritesound(DUKE_CRACK,p->i); + else spritesound(DUKE_CRACK2,p->i); + } + spritesound(DUKE_CRACK_FIRST,p->i); + } + else if( p->knuckle_incs == 22 || (sync[snum].bits&(1<<2))) + p->knuckle_incs=0; + + return 1; + } + return 0; +} + +short weapon_sprites[MAX_WEAPONS] = { KNEE, FIRSTGUNSPRITE, SHOTGUNSPRITE, + CHAINGUNSPRITE, RPGSPRITE, HEAVYHBOMB, SHRINKERSPRITE, DEVISTATORSPRITE, + TRIPBOMBSPRITE, FREEZESPRITE, HEAVYHBOMB, SHRINKERSPRITE}; + +void checkweapons(struct player_struct *p) +{ + short j,cw; + + cw = p->curr_weapon; + + if(cw < 1 || cw >= MAX_WEAPONS) return; + + if(cw) + { + if(TRAND&1) + spawn(p->i,weapon_sprites[cw]); + else switch(cw) + { + case RPG_WEAPON: + case HANDBOMB_WEAPON: + spawn(p->i,EXPLOSION2); + break; + } + } +} + +void processinput(short snum) +{ + long j, i, k, doubvel, fz, cz, hz, lz, truefdist, x, y; + char shrunk; + unsigned long sb_snum; + short psect, psectlotag,*kb, tempsect, pi; + struct player_struct *p; + spritetype *s; + + p = &ps[snum]; + pi = p->i; + s = &sprite[pi]; + + kb = &p->kickback_pic; + + if(p->cheat_phase <= 0) sb_snum = sync[snum].bits; + else sb_snum = 0; + + psect = p->cursectnum; + if(psect == -1) + { + if(s->extra > 0 && ud.clipping == 0) + { + quickkill(p); + spritesound(SQUISHED,pi); + } + psect = 0; + } + + psectlotag = sector[psect].lotag; + p->spritebridge = 0; + + shrunk = (s->yrepeat < 32); + getzrange(p->posx,p->posy,p->posz,psect,&cz,&hz,&fz,&lz,163L,CLIPMASK0); + + j = getflorzofslope(psect,p->posx,p->posy); + + p->truefz = j; + p->truecz = getceilzofslope(psect,p->posx,p->posy); + + truefdist = klabs(p->posz-j); + if( (lz&49152) == 16384 && psectlotag == 1 && truefdist > PHEIGHT+(16<<8) ) + psectlotag = 0; + + hittype[pi].floorz = fz; + hittype[pi].ceilingz = cz; + + p->ohoriz = p->horiz; + p->ohorizoff = p->horizoff; + + if( p->aim_mode == 0 && p->on_ground && psectlotag != 2 && (sector[psect].floorstat&2) ) + { + x = p->posx+(sintable[(p->ang+512)&2047]>>5); + y = p->posy+(sintable[p->ang&2047]>>5); + tempsect = psect; + updatesector(x,y,&tempsect); + if (tempsect >= 0) + { + k = getflorzofslope(psect,x,y); + if (psect == tempsect) + p->horizoff += mulscale16(j-k,160); + else if (klabs(getflorzofslope(tempsect,x,y)-k) <= (4<<8)) + p->horizoff += mulscale16(j-k,160); + } + } + if (p->horizoff > 0) p->horizoff -= ((p->horizoff>>3)+1); + else if (p->horizoff < 0) p->horizoff += (((-p->horizoff)>>3)+1); + + if( hz >= 0 && (hz&49152) == 49152) + { + hz &= (MAXSPRITES-1); + + if(sprite[hz].statnum == 1 && sprite[hz].extra >= 0) + { + hz = 0; + cz = p->truecz; + } + } + + if(lz >= 0 && (lz&49152) == 49152) + { + j = lz&(MAXSPRITES-1); + + if( (sprite[j].cstat&33) == 33 ) + { + psectlotag = 0; + p->footprintcount = 0; + p->spritebridge = 1; + } + else if(badguy(&sprite[j]) && sprite[j].xrepeat > 24 && klabs(s->z-sprite[j].z) < (84<<8) ) + { + j = getangle(sprite[j].x-p->posx,sprite[j].y-p->posy); + p->posxv -= sintable[(j+512)&2047]<<4; + p->posyv -= sintable[j&2047]<<4; + } + } + + + if ( s->extra > 0 ) incur_damage( p ); + else + { + s->extra = 0; + p->shield_amount = 0; + } + + p->last_extra = s->extra; + + if(p->loogcnt > 0) p->loogcnt--; + else p->loogcnt = 0; + + if(p->fist_incs) + { + p->fist_incs++; + if(p->fist_incs == 28) + { + if(ud.recstat == 1) closedemowrite(); + sound(PIPEBOMB_EXPLODE); + p->pals[0] = 64; + p->pals[1] = 64; + p->pals[2] = 64; + p->pals_time = 48; + } + if(p->fist_incs > 42) + { + if(p->buttonpalette && ud.from_bonus == 0) + { + ud.from_bonus = ud.level_number+1; + if(ud.secretlevel > 0 && ud.secretlevel < 12) ud.level_number = ud.secretlevel-1; + ud.m_level_number = ud.level_number; + } + else + { + if(ud.from_bonus) + { + ud.level_number = ud.from_bonus; + ud.m_level_number = ud.level_number; + ud.from_bonus = 0; + } + else + { + if(ud.level_number == ud.secretlevel && ud.from_bonus > 0 ) + ud.level_number = ud.from_bonus; + else ud.level_number++; + + if(ud.level_number > 10) ud.level_number = 0; + ud.m_level_number = ud.level_number; + + } + } + for(i=connecthead;i>=0;i=connectpoint2[i]) + ps[i].gm = MODE_EOL; + p->fist_incs = 0; + + return; + } + } + + if(p->timebeforeexit > 1 && p->last_extra > 0) + { + p->timebeforeexit--; + if(p->timebeforeexit == 26*5) + { + FX_StopAllSounds(); + clearsoundlocks(); + if(p->customexitsound >= 0) + { + sound(p->customexitsound); + FTA(102,p); + } + } + else if(p->timebeforeexit == 1) + { + for(i=connecthead;i>=0;i=connectpoint2[i]) + ps[i].gm = MODE_EOL; + if(ud.from_bonus) + { + ud.level_number = ud.from_bonus; + ud.m_level_number = ud.level_number; + ud.from_bonus = 0; + } + else + { + ud.level_number++; + ud.m_level_number = ud.level_number; + } + return; + } + } +/* + if(p->select_dir) + { + if(psectlotag != 15 || (sb_snum&(1<<31)) ) + p->select_dir = 0; + else + { + if(sync[snum].fvel > 127) + { + p->select_dir = 0; + activatewarpelevators(pi,-1); + } + else if(sync[snum].fvel <= -127) + { + p->select_dir = 0; + activatewarpelevators(pi,1); + } + return; + } + } + */ + if(p->pals_time > 0) + p->pals_time--; + + if(p->fta > 0) + { + p->fta--; + if(p->fta == 0) + { + pub = NUMPAGES; + pus = NUMPAGES; + p->ftq = 0; + } + } + + if( s->extra <= 0 ) + { + if(p->dead_flag == 0) + { + if(s->pal != 1) + { + p->pals[0] = 63; + p->pals[1] = 0; + p->pals[2] = 0; + p->pals_time = 63; + p->posz -= (16<<8); + s->z -= (16<<8); + } + + if(ud.recstat == 1 && ud.multimode < 2) + closedemowrite(); + + if(s->pal != 1) + p->dead_flag = (512-((TRAND&1)<<10)+(TRAND&255)-512)&2047; + + p->jetpack_on = 0; + p->holoduke_on = -1; + + stopsound(DUKE_JETPACK_IDLE); + if(p->scream_voice > FX_Ok) + { + FX_StopSound(p->scream_voice); + testcallback(DUKE_SCREAM); + p->scream_voice = FX_Ok; + } + + if( s->pal != 1 && (s->cstat&32768) == 0) s->cstat = 0; + + if( ud.multimode > 1 && ( s->pal != 1 || (s->cstat&32768) ) ) + { + if(p->frag_ps != snum) + { + ps[p->frag_ps].frag++; + frags[p->frag_ps][snum]++; + + if( ud.user_name[p->frag_ps][0] != 0) + { + if(snum == screenpeek) + { + sprintf(&fta_quotes[115][0],"KILLED BY %s",&ud.user_name[p->frag_ps][0]); + FTA(115,p); + } + else + { + sprintf(&fta_quotes[116][0],"KILLED %s",&ud.user_name[snum][0]); + FTA(116,&ps[p->frag_ps]); + } + } + else + { + if(snum == screenpeek) + { + sprintf(&fta_quotes[115][0],"KILLED BY PLAYER %d",1+p->frag_ps); + FTA(115,p); + } + else + { + sprintf(&fta_quotes[116][0],"KILLED PLAYER %d",1+snum); + FTA(116,&ps[p->frag_ps]); + } + } + } + else p->fraggedself++; + + if(myconnectindex == connecthead) + { + sprintf(tempbuf,"frag %d killed %d\n",p->frag_ps+1,snum+1); + sendscore(tempbuf); +// printf(tempbuf); + } + + p->frag_ps = snum; + pus = NUMPAGES; + } + } + + if( psectlotag == 2 ) + { + if(p->on_warping_sector == 0) + { + if( klabs(p->posz-fz) > (PHEIGHT>>1)) + p->posz += 348; + } + else + { + s->z -= 512; + s->zvel = -348; + } + + clipmove(&p->posx,&p->posy, + &p->posz,&p->cursectnum, + 0,0,164L,(4L<<8),(4L<<8),CLIPMASK0); +// p->bobcounter += 32; + } + + p->oposx = p->posx; + p->oposy = p->posy; + p->oposz = p->posz; + p->oang = p->ang; + p->opyoff = p->pyoff; + + p->horiz = 100; + p->horizoff = 0; + + updatesector(p->posx,p->posy,&p->cursectnum); + + pushmove(&p->posx,&p->posy,&p->posz,&p->cursectnum,128L,(4L<<8),(20L<<8),CLIPMASK0); + + if( fz > cz+(16<<8) && s->pal != 1) + p->rotscrnang = (p->dead_flag + ( (fz+p->posz)>>7))&2047; + + p->on_warping_sector = 0; + + return; + } + + if(p->transporter_hold > 0) + { + p->transporter_hold--; + if(p->transporter_hold == 0 && p->on_warping_sector) + p->transporter_hold = 2; + } + if(p->transporter_hold < 0) + p->transporter_hold++; + + if(p->newowner >= 0) + { + i = p->newowner; + p->posx = SX; + p->posy = SY; + p->posz = SZ; + p->ang = SA; + p->posxv = p->posyv = s->xvel = 0; + p->look_ang = 0; + p->rotscrnang = 0; + + doincrements(p); + + if(p->curr_weapon == HANDREMOTE_WEAPON) goto SHOOTINCODE; + + return; + } + + doubvel = TICSPERFRAME; + + if (p->rotscrnang > 0) p->rotscrnang -= ((p->rotscrnang>>1)+1); + else if (p->rotscrnang < 0) p->rotscrnang += (((-p->rotscrnang)>>1)+1); + + p->look_ang -= (p->look_ang>>2); + + if( sb_snum&(1<<6) ) + { + p->look_ang -= 152; + p->rotscrnang += 24; + } + + if( sb_snum&(1<<7) ) + { + p->look_ang += 152; + p->rotscrnang -= 24; + } + + if(p->on_crane >= 0) + goto HORIZONLY; + + j = ksgn(sync[snum].avel); + /* + if( j && ud.screen_tilting == 2) + { + k = 4; + if(sb_snum&(1<<5)) k <<= 2; + p->rotscrnang -= k*j; + p->look_ang += k*j; + } + */ + + if( s->xvel < 32 || p->on_ground == 0 || p->bobcounter == 1024 ) + { + if( (p->weapon_sway&2047) > (1024+96) ) + p->weapon_sway -= 96; + else if( (p->weapon_sway&2047) < (1024-96) ) + p->weapon_sway += 96; + else p->weapon_sway = 1024; + } + else p->weapon_sway = p->bobcounter; + + s->xvel = + ksqrt( (p->posx-p->bobposx)*(p->posx-p->bobposx)+(p->posy-p->bobposy)*(p->posy-p->bobposy)); + if(p->on_ground) p->bobcounter += sprite[p->i].xvel>>1; + + if( ud.clipping == 0 && ( sector[p->cursectnum].floorpicnum == MIRROR || p->cursectnum < 0 || p->cursectnum >= MAXSECTORS) ) + { + p->posx = p->oposx; + p->posy = p->oposy; + } + else + { + p->oposx = p->posx; + p->oposy = p->posy; + } + + p->bobposx = p->posx; + p->bobposy = p->posy; + + p->oposz = p->posz; + p->opyoff = p->pyoff; + p->oang = p->ang; + + if(p->one_eighty_count < 0) + { + p->one_eighty_count += 128; + p->ang += 128; + } + + // Shrinking code + + i = 40; + + if( psectlotag == 2) + { + p->jumping_counter = 0; + + p->pycount += 32; + p->pycount &= 2047; + p->pyoff = sintable[p->pycount]>>7; + + if( Sound[DUKE_UNDERWATER].num == 0 ) + spritesound(DUKE_UNDERWATER,pi); + + if ( sb_snum&1 ) + { + if(p->poszv > 0) p->poszv = 0; + p->poszv -= 348; + if(p->poszv < -(256*6)) p->poszv = -(256*6); + } + else if (sb_snum&(1<<1)) + { + if(p->poszv < 0) p->poszv = 0; + p->poszv += 348; + if(p->poszv > (256*6)) p->poszv = (256*6); + } + else + { + if(p->poszv < 0) + { + p->poszv += 256; + if(p->poszv > 0) + p->poszv = 0; + } + if(p->poszv > 0) + { + p->poszv -= 256; + if(p->poszv < 0) + p->poszv = 0; + } + } + + if(p->poszv > 2048) + p->poszv >>= 1; + + p->posz += p->poszv; + + if(p->posz > (fz-(15<<8)) ) + p->posz += ((fz-(15<<8))-p->posz)>>1; + + if(p->posz < (cz+(4<<8)) ) + { + p->posz = cz+(4<<8); + p->poszv = 0; + } + + if( p->scuba_on && (TRAND&255) < 8 ) + { + j = spawn(pi,WATERBUBBLE); + sprite[j].x += + sintable[(p->ang+512+64-(global_random&128))&2047]>>6; + sprite[j].y += + sintable[(p->ang+64-(global_random&128))&2047]>>6; + sprite[j].xrepeat = 3; + sprite[j].yrepeat = 2; + sprite[j].z = p->posz+(8<<8); + } + } + + else if(p->jetpack_on) + { + p->on_ground = 0; + p->jumping_counter = 0; + p->hard_landing = 0; + p->falling_counter = 0; + + p->pycount += 32; + p->pycount &= 2047; + p->pyoff = sintable[p->pycount]>>7; + + if(p->jetpack_on < 11) + { + p->jetpack_on++; + p->posz -= (p->jetpack_on<<7); //Goin up + } + else if(p->jetpack_on == 11 && Sound[DUKE_JETPACK_IDLE].num < 1) + spritesound(DUKE_JETPACK_IDLE,pi); + + if(shrunk) j = 512; + else j = 2048; + + if ( sb_snum&1 ) //A (soar high) + { + p->posz -= j; + p->crack_time = 777; + } + + if (sb_snum&(1<<1)) //Z (soar low) + { + p->posz += j; + p->crack_time = 777; + } + + if( shrunk == 0 && (psectlotag == 0 || psectlotag == 2)) k = 32; + else k = 16; + + if( psectlotag != 2 && p->scuba_on == 1 ) + p->scuba_on = 0; + + if(p->posz > (fz-(k<<8)) ) + p->posz += ((fz-(k<<8))-p->posz)>>1; + if(p->posz < (hittype[pi].ceilingz+(18<<8)) ) + p->posz = hittype[pi].ceilingz+(18<<8); + + } + else if( psectlotag != 2 ) + { + if(p->airleft != 15*26) + p->airleft = 15*26; //Aprox twenty seconds. + + if(p->scuba_on == 1) + p->scuba_on = 0; + + if( psectlotag == 1 && p->spritebridge == 0) + { + if(shrunk == 0) + { + i = 34; + p->pycount += 32; + p->pycount &= 2047; + p->pyoff = sintable[p->pycount]>>6; + } + else i = 12; + + if(shrunk == 0 && truefdist <= PHEIGHT) + { + if(p->on_ground == 1) + { + if( p->dummyplayersprite == -1 ) + p->dummyplayersprite = + spawn(pi,PLAYERONWATER); + + p->footprintcount = 6; + if(sector[p->cursectnum].floorpicnum == FLOORSLIME) + p->footprintpal = 8; + else p->footprintpal = 0; + p->footprintshade = 0; + } + } + } + else + { + if(p->footprintcount > 0 && p->on_ground) + if( (sector[p->cursectnum].floorstat&2) != 2 ) + { + for(j=headspritesect[psect];j>=0;j=nextspritesect[j]) + if( sprite[j].picnum == FOOTPRINTS || sprite[j].picnum == FOOTPRINTS2 || sprite[j].picnum == FOOTPRINTS3 || sprite[j].picnum == FOOTPRINTS4 ) + if (klabs(sprite[j].x-p->posx) < 384) + if (klabs(sprite[j].y-p->posy) < 384) + break; + if(j < 0) + { + p->footprintcount--; + if( sector[p->cursectnum].lotag == 0 && sector[p->cursectnum].hitag == 0 ) + { + switch(TRAND&3) + { + case 0: j = spawn(pi,FOOTPRINTS); break; + case 1: j = spawn(pi,FOOTPRINTS2); break; + case 2: j = spawn(pi,FOOTPRINTS3); break; + default: j = spawn(pi,FOOTPRINTS4); break; + } + sprite[j].pal = p->footprintpal; + sprite[j].shade = p->footprintshade; + } + } + } + } + + if(p->posz < (fz-(i<<8)) ) //falling + { + if( (sb_snum&3) == 0 && p->on_ground && (sector[psect].floorstat&2) && p->posz >= (fz-(i<<8)-(16<<8) ) ) + p->posz = fz-(i<<8); + else + { + p->on_ground = 0; + p->poszv += (gc+80); // (TICSPERFRAME<<6); + if(p->poszv >= (4096+2048)) p->poszv = (4096+2048); + if(p->poszv > 2400 && p->falling_counter < 255) + { + p->falling_counter++; + if( p->falling_counter == 38 ) + p->scream_voice = spritesound(DUKE_SCREAM,pi); + } + + if( (p->posz+p->poszv) >= (fz-(i<<8)) ) // hit the ground + if(sector[p->cursectnum].lotag != 1) + { + if( p->falling_counter > 62 ) quickkill(p); + + else if( p->falling_counter > 9 ) + { + j = p->falling_counter; + s->extra -= j-(TRAND&3); + if(s->extra <= 0) + { + spritesound(SQUISHED,pi); + p->pals[0] = 63; + p->pals[1] = 0; + p->pals[2] = 0; + p->pals_time = 63; + } + else + { + spritesound(DUKE_LAND,pi); + spritesound(DUKE_LAND_HURT,pi); + } + + p->pals[0] = 16; + p->pals[1] = 0; + p->pals[2] = 0; + p->pals_time = 32; + } + else if(p->poszv > 2048) spritesound(DUKE_LAND,pi); + } + } + } + + else + { + p->falling_counter = 0; + if(p->scream_voice > FX_Ok) + { + FX_StopSound(p->scream_voice); + p->scream_voice = FX_Ok; + } + + if(psectlotag != 1 && psectlotag != 2 && p->on_ground == 0 && p->poszv > (6144>>1)) + p->hard_landing = p->poszv>>10; + + p->on_ground = 1; + + if( i==40 ) + { + //Smooth on the ground + + k = ((fz-(i<<8))-p->posz)>>1; + if( klabs(k) < 256 ) k = 0; + p->posz += k; + p->poszv -= 768; + if(p->poszv < 0) p->poszv = 0; + } + else if(p->jumping_counter == 0) + { + p->posz += ((fz-(i<<7))-p->posz)>>1; //Smooth on the water + if(p->on_warping_sector == 0 && p->posz > fz-(16<<8)) + { + p->posz = fz-(16<<8); + p->poszv >>= 1; + } + } + + p->on_warping_sector = 0; + + if( (sb_snum&2) ) + { + p->posz += (2048+768); + p->crack_time = 777; + } + + if( (sb_snum&1) == 0 && p->jumping_toggle == 1) + p->jumping_toggle = 0; + + else if( (sb_snum&1) && p->jumping_toggle == 0 ) + { + if( p->jumping_counter == 0 ) + if( (fz-cz) > (56<<8) ) + { + p->jumping_counter = 1; + p->jumping_toggle = 1; + } + } + + if( p->jumping_counter && (sb_snum&1) == 0 ) + p->jumping_toggle = 0; + } + + if(p->jumping_counter) + { + if( (sb_snum&1) == 0 && p->jumping_toggle == 1) + p->jumping_toggle = 0; + + if( p->jumping_counter < (1024+256) ) + { + if(psectlotag == 1 && p->jumping_counter > 768) + { + p->jumping_counter = 0; + p->poszv = -512; + } + else + { + p->poszv -= (sintable[(2048-128+p->jumping_counter)&2047])/12; + p->jumping_counter += 180; + p->on_ground = 0; + } + } + else + { + p->jumping_counter = 0; + p->poszv = 0; + } + } + + p->posz += p->poszv; + + if(p->posz < (cz+(4<<8))) + { + p->jumping_counter = 0; + if(p->poszv < 0) + p->posxv = p->posyv = 0; + p->poszv = 128; + p->posz = cz+(4<<8); + } + } + + //Do the quick lefts and rights + + if ( p->fist_incs || + p->transporter_hold > 2 || + p->hard_landing || + p->access_incs > 0 || + p->knee_incs > 0 || + (p->curr_weapon == TRIPBOMB_WEAPON && + *kb > 1 && + *kb < 4 ) ) + { + doubvel = 0; + p->posxv = 0; + p->posyv = 0; + } + else if ( sync[snum].avel ) //p->ang += syncangvel * constant + { //ENGINE calculates angvel for you + long tempang; + + tempang = sync[snum].avel<<1; + + if( psectlotag == 2 ) p->angvel =(tempang-(tempang>>3))*sgn(doubvel); + else p->angvel = tempang*sgn(doubvel); + + p->ang += p->angvel; + p->ang &= 2047; + p->crack_time = 777; + } + + if(p->spritebridge == 0) + { + j = sector[s->sectnum].floorpicnum; + + if( j == PURPLELAVA || sector[s->sectnum].ceilingpicnum == PURPLELAVA ) + { + if(p->boot_amount > 0) + { + p->boot_amount--; + p->inven_icon = 7; + if(p->boot_amount <= 0) + checkavailinven(p); + } + else + { + if(Sound[DUKE_LONGTERM_PAIN].num < 1) + spritesound(DUKE_LONGTERM_PAIN,pi); + p->pals[0] = 0; p->pals[1] = 8; p->pals[2] = 0; + p->pals_time = 32; + s->extra--; + } + } + + k = 0; + + if(p->on_ground && truefdist <= PHEIGHT+(16<<8)) + { + switch(j) + { + case HURTRAIL: + if( rnd(32) ) + { + if(p->boot_amount > 0) + k = 1; + else + { + if(Sound[DUKE_LONGTERM_PAIN].num < 1) + spritesound(DUKE_LONGTERM_PAIN,pi); + p->pals[0] = 64; p->pals[1] = 64; p->pals[2] = 64; + p->pals_time = 32; + s->extra -= 1+(TRAND&3); + if(Sound[SHORT_CIRCUIT].num < 1) + spritesound(SHORT_CIRCUIT,pi); + } + } + break; + case FLOORSLIME: + if( rnd(16) ) + { + if(p->boot_amount > 0) + k = 1; + else + { + if(Sound[DUKE_LONGTERM_PAIN].num < 1) + spritesound(DUKE_LONGTERM_PAIN,pi); + p->pals[0] = 0; p->pals[1] = 8; p->pals[2] = 0; + p->pals_time = 32; + s->extra -= 1+(TRAND&3); + } + } + break; + case FLOORPLASMA: + if( rnd(32) ) + { + if( p->boot_amount > 0 ) + k = 1; + else + { + if(Sound[DUKE_LONGTERM_PAIN].num < 1) + spritesound(DUKE_LONGTERM_PAIN,pi); + p->pals[0] = 8; p->pals[1] = 0; p->pals[2] = 0; + p->pals_time = 32; + s->extra -= 1+(TRAND&3); + } + } + break; + } + } + + if( k ) + { + FTA(75,p); + p->boot_amount -= 2; + if(p->boot_amount <= 0) + checkavailinven(p); + } + } + + if ( p->posxv || p->posyv || sync[snum].fvel || sync[snum].svel ) + { + p->crack_time = 777; + + k = sintable[p->bobcounter&2047]>>12; + + if(truefdist < PHEIGHT+(8<<8) ) + { + if( k == 1 || k == 3 ) + { + if(p->spritebridge == 0 && p->walking_snd_toggle == 0 && p->on_ground) + { + switch( psectlotag ) + { + case 0: + + if(lz >= 0 && (lz&(MAXSPRITES-1))==49152 ) + j = sprite[lz&(MAXSPRITES-1)].picnum; + else j = sector[psect].floorpicnum; + + switch(j) + { + case PANNEL1: + case PANNEL2: + spritesound(DUKE_WALKINDUCTS,pi); + p->walking_snd_toggle = 1; + break; + } + break; + case 1: + if((TRAND&1) == 0) + spritesound(DUKE_ONWATER,pi); + p->walking_snd_toggle = 1; + break; + } + } + } + } + else if(p->walking_snd_toggle > 0) + p->walking_snd_toggle --; + + if(p->jetpack_on == 0 && p->steroids_amount > 0 && p->steroids_amount < 400) + doubvel <<= 1; + + p->posxv += ((sync[snum].fvel*doubvel)<<6); + p->posyv += ((sync[snum].svel*doubvel)<<6); + + if( ( p->curr_weapon == KNEE_WEAPON && *kb > 10 && p->on_ground ) || ( p->on_ground && (sb_snum&2) ) ) + { + p->posxv = mulscale(p->posxv,dukefriction-0x2000,16); + p->posyv = mulscale(p->posyv,dukefriction-0x2000,16); + } + else + { + if(psectlotag == 2) + { + p->posxv = mulscale(p->posxv,dukefriction-0x1400,16); + p->posyv = mulscale(p->posyv,dukefriction-0x1400,16); + } + else + { + p->posxv = mulscale(p->posxv,dukefriction,16); + p->posyv = mulscale(p->posyv,dukefriction,16); + } + } + + if( abs(p->posxv) < 2048 && abs(p->posyv) < 2048 ) + p->posxv = p->posyv = 0; + + if( shrunk ) + { + p->posxv = + mulscale16(p->posxv,dukefriction-(dukefriction>>1)+(dukefriction>>2)); + p->posyv = + mulscale16(p->posyv,dukefriction-(dukefriction>>1)+(dukefriction>>2)); + } + } + + HORIZONLY: + + if(psectlotag == 1 || p->spritebridge == 1) i = (4L<<8); + else i = (20L<<8); + + if(sector[p->cursectnum].lotag == 2) k = 0; + else k = 1; + + if(ud.clipping) + { + j = 0; + p->posx += p->posxv>>14; + p->posy += p->posyv>>14; + updatesector(p->posx,p->posy,&p->cursectnum); + changespritesect(pi,p->cursectnum); + } + else + j = clipmove(&p->posx,&p->posy, + &p->posz,&p->cursectnum, + p->posxv,p->posyv,164L,(4L<<8),i,CLIPMASK0); + + if(p->jetpack_on == 0 && psectlotag != 2 && psectlotag != 1 && shrunk) + p->posz += 32<<8; + + if(j) + checkplayerhurt(p,j); + + if(p->jetpack_on == 0) + { + if( s->xvel > 16 ) + { + if( psectlotag != 1 && psectlotag != 2 && p->on_ground ) + { + p->pycount += 52; + p->pycount &= 2047; + p->pyoff = + klabs(s->xvel*sintable[p->pycount])/1596; + } + } + else if( psectlotag != 2 && psectlotag != 1 ) + p->pyoff = 0; + } + + // RBG*** + setsprite(pi,p->posx,p->posy,p->posz+PHEIGHT); + + if( psectlotag < 3 ) + { + psect = s->sectnum; + if( ud.clipping == 0 && sector[psect].lotag == 31) + { + if( sprite[sector[psect].hitag].xvel && hittype[sector[psect].hitag].temp_data[0] == 0) + { + quickkill(p); + return; + } + } + } + + if(truefdist < PHEIGHT && p->on_ground && psectlotag != 1 && shrunk == 0 && sector[p->cursectnum].lotag == 1) + if( Sound[DUKE_ONWATER].num == 0 ) + spritesound(DUKE_ONWATER,pi); + + if (p->cursectnum != s->sectnum) + changespritesect(pi,p->cursectnum); + + if(ud.clipping == 0) + j = ( pushmove(&p->posx,&p->posy,&p->posz,&p->cursectnum,164L,(4L<<8),(4L<<8),CLIPMASK0) < 0 && furthestangle(pi,8) < 512 ); + else j = 0; + + if(ud.clipping == 0) + { + if( klabs(hittype[pi].floorz-hittype[pi].ceilingz) < (48<<8) || j ) + { + if ( !(sector[s->sectnum].lotag&0x8000) && ( isanunderoperator(sector[s->sectnum].lotag) || + isanearoperator(sector[s->sectnum].lotag) ) ) + activatebysector(s->sectnum,pi); + if(j) + { + quickkill(p); + return; + } + } + else if( klabs(fz-cz) < (32<<8) && isanunderoperator(sector[psect].lotag) ) + activatebysector(psect,pi); + } + + if( sb_snum&(1<<18) || p->hard_landing) + p->return_to_center = 9; + + if( sb_snum&(1<<13) ) + { + p->return_to_center = 9; + if( sb_snum&(1<<5) ) p->horiz += 12; + p->horiz += 12; + } + + else if( sb_snum&(1<<14) ) + { + p->return_to_center = 9; + if( sb_snum&(1<<5) ) p->horiz -= 12; + p->horiz -= 12; + } + + else if( sb_snum&(1<<3) ) + { + if( sb_snum&(1<<5) ) p->horiz += 6; + p->horiz += 6; + } + + else if( sb_snum&(1<<4) ) + { + if( sb_snum&(1<<5) ) p->horiz -= 6; + p->horiz -= 6; + } + if(p->return_to_center > 0) + if( (sb_snum&(1<<13)) == 0 && (sb_snum&(1<<14)) == 0 ) + { + p->return_to_center--; + p->horiz += 33-(p->horiz/3); + } + + if(p->hard_landing > 0) + { + p->hard_landing--; + p->horiz -= (p->hard_landing<<4); + } + + if(p->aim_mode) + p->horiz += sync[snum].horz>>1; + else + { + if( p->horiz > 95 && p->horiz < 105) p->horiz = 100; + if( p->horizoff > -5 && p->horizoff < 5) p->horizoff = 0; + } + + if(p->horiz > 299) p->horiz = 299; + else if(p->horiz < -99) p->horiz = -99; + + //Shooting code/changes + + if( p->show_empty_weapon > 0) + { + p->show_empty_weapon--; + if(p->show_empty_weapon == 0) + { + if(p->last_full_weapon == GROW_WEAPON) + p->subweapon |= (1<last_full_weapon == SHRINKER_WEAPON) + p->subweapon &= ~(1<last_full_weapon ); + return; + } + } + + if(p->knee_incs > 0) + { + p->knee_incs++; + p->horiz -= 48; + p->return_to_center = 9; + if(p->knee_incs > 15) + { + p->knee_incs = 0; + p->holster_weapon = 0; + if(p->weapon_pos < 0) + p->weapon_pos = -p->weapon_pos; + if(p->actorsqu >= 0 && dist(&sprite[pi],&sprite[p->actorsqu]) < 1400 ) + { + guts(&sprite[p->actorsqu],JIBS6,7,myconnectindex); + spawn(p->actorsqu,BLOODPOOL); + spritesound(SQUISHED,p->actorsqu); + switch(sprite[p->actorsqu].picnum) + { + case FEM1: + case FEM2: + case FEM3: + case FEM4: + case FEM5: + case FEM6: + case FEM7: + case FEM8: + case FEM9: + case FEM10: + case PODFEM1: + case NAKED1: + case STATUE: + if(sprite[p->actorsqu].yvel) + operaterespawns(sprite[p->actorsqu].yvel); + break; + } + + if(sprite[p->actorsqu].picnum == APLAYER) + { + quickkill(&ps[sprite[p->actorsqu].yvel]); + ps[sprite[p->actorsqu].yvel].frag_ps = snum; + } + else if(badguy(&sprite[p->actorsqu])) + { + deletesprite(p->actorsqu); + p->actors_killed++; + } + else deletesprite(p->actorsqu); + } + p->actorsqu = -1; + } + else if(p->actorsqu >= 0) + p->ang += getincangle(p->ang,getangle(sprite[p->actorsqu].x-p->posx,sprite[p->actorsqu].y-p->posy))>>2; + } + + if( doincrements(p) ) return; + + if(p->weapon_pos != 0) + { + if(p->weapon_pos == -9) + { + if(p->last_weapon >= 0) + { + p->weapon_pos = 10; +// if(p->curr_weapon == KNEE_WEAPON) *kb = 1; + p->last_weapon = -1; + } + else if(p->holster_weapon == 0) + p->weapon_pos = 10; + } + else p->weapon_pos--; + } + + // HACKS + + SHOOTINCODE: + + if( p->curr_weapon == SHRINKER_WEAPON || p->curr_weapon == GROW_WEAPON ) + p->random_club_frame += 64; // Glowing + + if(p->rapid_fire_hold == 1) + { + if( sb_snum&(1<<2) ) return; + p->rapid_fire_hold = 0; + } + + if(shrunk || p->tipincs || p->access_incs) + sb_snum &= ~(1<<2); + else if ( shrunk == 0 && (sb_snum&(1<<2)) && (*kb) == 0 && p->fist_incs == 0 && + p->last_weapon == -1 && ( p->weapon_pos == 0 || p->holster_weapon == 1 ) ) + { + + p->crack_time = 777; + + if(p->holster_weapon == 1) + { + if( p->last_pissed_time <= (26*218) && p->weapon_pos == -9) + { + p->holster_weapon = 0; + p->weapon_pos = 10; + FTA(74,p); + } + } + else switch(p->curr_weapon) + { + case HANDBOMB_WEAPON: + p->hbomb_hold_delay = 0; + if( p->ammo_amount[HANDBOMB_WEAPON] > 0 ) + (*kb)=1; + break; + case HANDREMOTE_WEAPON: + p->hbomb_hold_delay = 0; + (*kb) = 1; + break; + + case PISTOL_WEAPON: + if( p->ammo_amount[PISTOL_WEAPON] > 0 ) + { + p->ammo_amount[PISTOL_WEAPON]--; + (*kb) = 1; + } + break; + + + case CHAINGUN_WEAPON: + if( p->ammo_amount[CHAINGUN_WEAPON] > 0 ) // && p->random_club_frame == 0) + (*kb)=1; + break; + + case SHOTGUN_WEAPON: + if( p->ammo_amount[SHOTGUN_WEAPON] > 0 && p->random_club_frame == 0 ) + (*kb)=1; + break; +#ifndef VOLUMEONE + case TRIPBOMB_WEAPON: + if ( p->ammo_amount[TRIPBOMB_WEAPON] > 0 ) + { + long sx,sy,sz; + short sect,hw,hitsp; + + hitscan( p->posx, p->posy, p->posz, + p->cursectnum, sintable[(p->ang+512)&2047], + sintable[p->ang&2047], (100-p->horiz-p->horizoff)*32, + §, &hw, &hitsp, &sx, &sy, &sz,CLIPMASK1); + + if(sect < 0 || hitsp >= 0) + break; + + if( hw >= 0 && sector[sect].lotag > 2 ) + break; + + if(hw >= 0 && wall[hw].overpicnum >= 0) + if(wall[hw].overpicnum == BIGFORCE) + break; + + j = headspritesect[sect]; + while(j >= 0) + { + if( sprite[j].picnum == TRIPBOMB && + klabs(sprite[j].z-sz) < (12<<8) && ((sprite[j].x-sx)*(sprite[j].x-sx)+(sprite[j].y-sy)*(sprite[j].y-sy)) < (290*290) ) + break; + j = nextspritesect[j]; + } + + if(j == -1 && hw >= 0 && (wall[hw].cstat&16) == 0 ) + if( ( wall[hw].nextsector >= 0 && sector[wall[hw].nextsector].lotag <= 2 ) || ( wall[hw].nextsector == -1 && sector[sect].lotag <= 2 ) ) + if( ( (sx-p->posx)*(sx-p->posx) + (sy-p->posy)*(sy-p->posy) ) < (290*290) ) + { + p->posz = p->oposz; + p->poszv = 0; + (*kb) = 1; + } + } + break; + + case SHRINKER_WEAPON: + case GROW_WEAPON: + if( p->curr_weapon == GROW_WEAPON ) + { + if( p->ammo_amount[GROW_WEAPON] > 0 ) + { + (*kb) = 1; + spritesound(EXPANDERSHOOT,pi); + } + } + else if( p->ammo_amount[SHRINKER_WEAPON] > 0) + { + (*kb) = 1; + spritesound(SHRINKER_FIRE,pi); + } + break; + + case FREEZE_WEAPON: + if( p->ammo_amount[FREEZE_WEAPON] > 0 ) + { + (*kb) = 1; + spritesound(CAT_FIRE,pi); + } + break; + case DEVISTATOR_WEAPON: + if( p->ammo_amount[DEVISTATOR_WEAPON] > 0 ) + { + (*kb) = 1; + p->hbomb_hold_delay = !p->hbomb_hold_delay; + spritesound(CAT_FIRE,pi); + } + break; + +#endif + case RPG_WEAPON: + if ( p->ammo_amount[RPG_WEAPON] > 0) + (*kb) = 1; + break; + + case KNEE_WEAPON: + if(p->quick_kick == 0) (*kb) = 1; + break; + } + } + else if((*kb)) + { + switch( p->curr_weapon ) + { + case HANDBOMB_WEAPON: + + if( (*kb) == 6 && (sb_snum&(1<<2)) ) + { + p->rapid_fire_hold = 1; + break; + } + (*kb)++; + if((*kb)==12) + { + p->ammo_amount[HANDBOMB_WEAPON]--; + + if(p->on_ground && (sb_snum&2) ) + { + k = 15; + i = ((p->horiz+p->horizoff-100)*20); + } + else + { + k = 140; + i = -512-((p->horiz+p->horizoff-100)*20); + } + + j = EGS(p->cursectnum, + p->posx+(sintable[(p->ang+512)&2047]>>6), + p->posy+(sintable[p->ang&2047]>>6), + p->posz,HEAVYHBOMB,-16,9,9, + p->ang,(k+(p->hbomb_hold_delay<<5)),i,pi,1); + + if(k == 15) + { + sprite[j].yvel = 3; + sprite[j].z += (8<<8); + } + + k = hits(pi); + if( k < 512 ) + { + sprite[j].ang += 1024; + sprite[j].zvel /= 3; + sprite[j].xvel /= 3; + } + + p->hbomb_on = 1; + + } + else if( (*kb) < 12 && (sb_snum&(1<<2)) ) + p->hbomb_hold_delay++; + else if( (*kb) > 19 ) + { + (*kb) = 0; + p->curr_weapon = HANDREMOTE_WEAPON; + p->last_weapon = -1; + p->weapon_pos = 10; + } + + break; + + + case HANDREMOTE_WEAPON: + + (*kb)++; + + if((*kb) == 2) + { + p->hbomb_on = 0; + } + + if((*kb) == 10) + { + (*kb) = 0; + if(p->ammo_amount[HANDBOMB_WEAPON] > 0) + addweapon(p,HANDBOMB_WEAPON); + else checkavailweapon(p); + } + break; + + case PISTOL_WEAPON: + if( (*kb)==1) + { + shoot(pi,SHOTSPARK1); + spritesound(PISTOL_FIRE,pi); + + lastvisinc = totalclock+32; + p->visibility = 0; + } + else if((*kb) == 2) + spawn(pi,SHELL); + + (*kb)++; + + if((*kb) >= 5) + { + if( p->ammo_amount[PISTOL_WEAPON] <= 0 || (p->ammo_amount[PISTOL_WEAPON]%12) ) + { + (*kb)=0; + checkavailweapon(p); + } + else + { + switch((*kb)) + { + case 5: + spritesound(EJECT_CLIP,pi); + break; + case 8: + spritesound(INSERT_CLIP,pi); + break; + } + } + } + + if((*kb) == 27) + { + (*kb) = 0; + checkavailweapon(p); + } + + break; + + case SHOTGUN_WEAPON: + + (*kb)++; + + if(*kb == 4) + { + shoot(pi,SHOTGUN); + shoot(pi,SHOTGUN); + shoot(pi,SHOTGUN); + shoot(pi,SHOTGUN); + shoot(pi,SHOTGUN); + shoot(pi,SHOTGUN); + shoot(pi,SHOTGUN); + + p->ammo_amount[SHOTGUN_WEAPON]--; + + spritesound(SHOTGUN_FIRE,pi); + + lastvisinc = totalclock+32; + p->visibility = 0; + } + + switch(*kb) + { + case 13: + checkavailweapon(p); + break; + case 15: + spritesound(SHOTGUN_COCK,pi); + break; + case 17: + case 20: + p->kickback_pic++; + break; + case 24: + j = spawn(pi,SHOTGUNSHELL); + sprite[j].ang += 1024; + ssp(j,CLIPMASK0); + sprite[j].ang += 1024; + p->kickback_pic++; + break; + case 31: + *kb = 0; + return; + } + break; + + case CHAINGUN_WEAPON: + + (*kb)++; + + if( *(kb) <= 12 ) + { + if( ((*(kb))%3) == 0 ) + { + p->ammo_amount[CHAINGUN_WEAPON]--; + + if( (*(kb)%3) == 0 ) + { + j = spawn(pi,SHELL); + + sprite[j].ang += 1024; + sprite[j].ang &= 2047; + sprite[j].xvel += 32; + sprite[j].z += (3<<8); + ssp(j,CLIPMASK0); + } + + spritesound(CHAINGUN_FIRE,pi); + shoot(pi,CHAINGUN); + lastvisinc = totalclock+32; + p->visibility = 0; + checkavailweapon(p); + + if( ( sb_snum&(1<<2) ) == 0 ) + { + *kb = 0; + break; + } + } + } + else if((*kb) > 10) + { + if( sb_snum&(1<<2) ) *kb = 1; + else *kb = 0; + } + + break; + + case SHRINKER_WEAPON: + case GROW_WEAPON: + + if(p->curr_weapon == GROW_WEAPON) + { + if((*kb) > 3) + { + *kb = 0; + if( screenpeek == snum ) pus = 1; + p->ammo_amount[GROW_WEAPON]--; + shoot(pi,GROWSPARK); + + p->visibility = 0; + lastvisinc = totalclock+32; + checkavailweapon(p); + } + else (*kb)++; + } + else + { + if( (*kb) > 10) + { + (*kb) = 0; + + p->ammo_amount[SHRINKER_WEAPON]--; + shoot(pi,SHRINKER); + + p->visibility = 0; + lastvisinc = totalclock+32; + checkavailweapon(p); + } + else (*kb)++; + } + break; + + case DEVISTATOR_WEAPON: + if(*kb) + { + (*kb)++; + + if( (*kb) & 1 ) + { + p->visibility = 0; + lastvisinc = totalclock+32; + shoot(pi,RPG); + p->ammo_amount[DEVISTATOR_WEAPON]--; + checkavailweapon(p); + } + if((*kb) > 5) (*kb) = 0; + } + break; + case FREEZE_WEAPON: + + if( (*kb) < 4 ) + { + (*kb)++; + if( (*kb) == 3 ) + { + p->ammo_amount[FREEZE_WEAPON]--; + p->visibility = 0; + lastvisinc = totalclock+32; + shoot(pi,FREEZEBLAST); + checkavailweapon(p); + } + if(s->xrepeat < 32) + { *kb = 0; break; } + } + else + { + if( sb_snum&(1<<2)) + { + *kb = 1; + spritesound(CAT_FIRE,pi); + } + else *kb = 0; + } + break; + + case TRIPBOMB_WEAPON: + if(*kb < 4) + { + p->posz = p->oposz; + p->poszv = 0; + if( (*kb) == 3 ) + shoot(pi,HANDHOLDINGLASER); + } + if((*kb) == 16) + { + (*kb) = 0; + checkavailweapon(p); + p->weapon_pos = -9; + } + else (*kb)++; + break; + case KNEE_WEAPON: + (*kb)++; + + if( (*kb) == 7) shoot(pi,KNEE); + else if( (*kb) == 14) + { + if( sb_snum&(1<<2) ) + *kb = 1+(TRAND&3); + else *kb = 0; + } + + if(p->wantweaponfire >= 0) + checkavailweapon(p); + break; + + case RPG_WEAPON: + (*kb)++; + if( (*kb) == 4 ) + { + p->ammo_amount[RPG_WEAPON]--; + lastvisinc = totalclock+32; + p->visibility = 0; + shoot(pi,RPG); + checkavailweapon(p); + } + else if( *kb == 20 ) + *kb = 0; + break; + } + } +} + + + +//UPDATE THIS FILE OVER THE OLD GETSPRITESCORE/COMPUTERGETINPUT FUNCTIONS +static int getspritescore(long snum, long dapicnum) +{ + switch(dapicnum) + { + case FIRSTGUNSPRITE: return(5); + case CHAINGUNSPRITE: return(50); + case RPGSPRITE: return(200); + case FREEZESPRITE: return(25); + case SHRINKERSPRITE: return(80); + case HEAVYHBOMB: return(60); + case TRIPBOMBSPRITE: return(50); + case SHOTGUNSPRITE: return(120); + case DEVISTATORSPRITE: return(120); + + case FREEZEAMMO: if (ps[snum].ammo_amount[FREEZE_WEAPON] < max_ammo_amount[FREEZE_WEAPON]) return(10); else return(0); + case AMMO: if (ps[snum].ammo_amount[SHOTGUN_WEAPON] < max_ammo_amount[SHOTGUN_WEAPON]) return(10); else return(0); + case BATTERYAMMO: if (ps[snum].ammo_amount[CHAINGUN_WEAPON] < max_ammo_amount[CHAINGUN_WEAPON]) return(20); else return(0); + case DEVISTATORAMMO: if (ps[snum].ammo_amount[DEVISTATOR_WEAPON] < max_ammo_amount[DEVISTATOR_WEAPON]) return(25); else return(0); + case RPGAMMO: if (ps[snum].ammo_amount[RPG_WEAPON] < max_ammo_amount[RPG_WEAPON]) return(50); else return(0); + case CRYSTALAMMO: if (ps[snum].ammo_amount[SHRINKER_WEAPON] < max_ammo_amount[SHRINKER_WEAPON]) return(10); else return(0); + case HBOMBAMMO: if (ps[snum].ammo_amount[HANDBOMB_WEAPON] < max_ammo_amount[HANDBOMB_WEAPON]) return(30); else return(0); + case SHOTGUNAMMO: if (ps[snum].ammo_amount[SHOTGUN_WEAPON] < max_ammo_amount[SHOTGUN_WEAPON]) return(25); else return(0); + + case COLA: if (sprite[ps[snum].i].extra < 100) return(10); else return(0); + case SIXPAK: if (sprite[ps[snum].i].extra < 100) return(30); else return(0); + case FIRSTAID: if (ps[snum].firstaid_amount < 100) return(100); else return(0); + case SHIELD: if (ps[snum].shield_amount < 100) return(50); else return(0); + case STEROIDS: if (ps[snum].steroids_amount < 400) return(30); else return(0); + case AIRTANK: if (ps[snum].scuba_amount < 6400) return(30); else return(0); + case JETPACK: if (ps[snum].jetpack_amount < 1600) return(100); else return(0); + case HEATSENSOR: if (ps[snum].heat_amount < 1200) return(10); else return(0); + case ACCESSCARD: return(1); + case BOOTS: if (ps[snum].boot_amount < 200) return(50); else return(0); + case ATOMICHEALTH: if (sprite[ps[snum].i].extra < max_player_health) return(50); else return(0); + case HOLODUKE: if (ps[snum].holoduke_amount < 2400) return(30); else return(0); + } + return(0); +} + +static long fdmatrix[12][12] = +{ + //KNEE PIST SHOT CHAIN RPG PIPE SHRI DEVI WALL FREE HAND EXPA + { 128, -1, -1, -1, 128, -1, -1, -1, 128, -1, 128, -1 }, //KNEE + { 1024,1024,1024,1024,2560, 128,2560,2560,1024,2560,2560,2560 }, //PIST + { 512, 512, 512, 512,2560, 128,2560,2560,1024,2560,2560,2560 }, //SHOT + { 512, 512, 512, 512,2560, 128,2560,2560,1024,2560,2560,2560 }, //CHAIN + { 2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560 }, //RPG + { 512, 512, 512, 512,2048, 512,2560,2560, 512,2560,2560,2560 }, //PIPE + { 128, 128, 128, 128,2560, 128,2560,2560, 128, 128, 128, 128 }, //SHRI + { 1536,1536,1536,1536,2560,1536,1536,1536,1536,1536,1536,1536 }, //DEVI + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, //WALL + { 128, 128, 128, 128,2560, 128,2560,2560, 128, 128, 128, 128 }, //FREE + { 2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560,2560 }, //HAND + { 128, 128, 128, 128,2560, 128,2560,2560, 128, 128, 128, 128 } //EXPA +}; + +static long goalx[MAXPLAYERS], goaly[MAXPLAYERS], goalz[MAXPLAYERS]; +static long goalsect[MAXPLAYERS], goalwall[MAXPLAYERS], goalsprite[MAXPLAYERS]; +static long goalplayer[MAXPLAYERS], clipmovecount[MAXPLAYERS]; +short searchsect[MAXSECTORS], searchparent[MAXSECTORS]; +char dashow2dsector[(MAXSECTORS+7)>>3]; +void computergetinput(long snum, input *syn) +{ + long i, j, k, l, x1, y1, z1, x2, y2, z2, x3, y3, z3, dx, dy; + long dist, daang, zang, fightdist, damyang, damysect; + long startsect, endsect, splc, send, startwall, endwall; + short dasect, dawall, daspr; + struct player_struct *p; + walltype *wal; + + p = &ps[snum]; + syn->fvel = 0; + syn->svel = 0; + syn->avel = 0; + syn->horz = 0; + syn->bits = 0; + + z2 = y2 = x2 = 0; + x1 = sprite[p->i].x; + y1 = sprite[p->i].y; + z1 = sprite[p->i].z; + damyang = sprite[p->i].ang; + damysect = sprite[p->i].sectnum; + if ((numplayers >= 2) && (snum == myconnectindex)) + { x1 = myx; y1 = myy; z1 = myz+PHEIGHT; damyang = myang; damysect = mycursectnum; } + + if (!(numframes&7)) + { + if (!cansee(x1,y1,z1-(48<<8),damysect,x2,y2,z2-(48<<8),sprite[ps[goalplayer[snum]].i].sectnum)) + goalplayer[snum] = snum; + } + + if ((goalplayer[snum] == snum) || (ps[goalplayer[snum]].dead_flag != 0)) + { + j = 0x7fffffff; + for(i=connecthead;i>=0;i=connectpoint2[i]) + if (i != snum) + { + dist = ksqrt((sprite[ps[i].i].x-x1)*(sprite[ps[i].i].x-x1)+(sprite[ps[i].i].y-y1)*(sprite[ps[i].i].y-y1)); + + x2 = sprite[ps[i].i].x; + y2 = sprite[ps[i].i].y; + z2 = sprite[ps[i].i].z; + if (!cansee(x1,y1,z1-(48<<8),damysect,x2,y2,z2-(48<<8),sprite[ps[i].i].sectnum)) + dist <<= 1; + + if (dist < j) { j = dist; goalplayer[snum] = i; } + } + } + + x2 = sprite[ps[goalplayer[snum]].i].x; + y2 = sprite[ps[goalplayer[snum]].i].y; + z2 = sprite[ps[goalplayer[snum]].i].z; + + if (p->dead_flag) syn->bits |= (1<<29); + if ((p->firstaid_amount > 0) && (p->last_extra < 100)) + syn->bits |= (1<<16); + + for(j=headspritestat[4];j>=0;j=nextspritestat[j]) + { + switch (sprite[j].picnum) + { + case TONGUE: k = 4; break; + case FREEZEBLAST: k = 4; break; + case SHRINKSPARK: k = 16; break; + case RPG: k = 16; break; + default: k = 0; break; + } + if (k) + { + x3 = sprite[j].x; + y3 = sprite[j].y; + z3 = sprite[j].z; + for(l=0;l<=8;l++) + { + if (tmulscale11(x3-x1,x3-x1,y3-y1,y3-y1,(z3-z1)>>4,(z3-z1)>>4) < 3072) + { + dx = sintable[(sprite[j].ang+512)&2047]; + dy = sintable[sprite[j].ang&2047]; + if ((x1-x3)*dy > (y1-y3)*dx) i = -k*512; else i = k*512; + syn->fvel -= mulscale17(dy,i); + syn->svel += mulscale17(dx,i); + } + if (l < 7) + { + x3 += (mulscale14(sprite[j].xvel,sintable[(sprite[j].ang+512)&2047])<<2); + y3 += (mulscale14(sprite[j].xvel,sintable[sprite[j].ang&2047])<<2); + z3 += (sprite[j].zvel<<2); + } + else + { + hitscan(sprite[j].x,sprite[j].y,sprite[j].z,sprite[j].sectnum, + mulscale14(sprite[j].xvel,sintable[(sprite[j].ang+512)&2047]), + mulscale14(sprite[j].xvel,sintable[sprite[j].ang&2047]), + (long)sprite[j].zvel, + &dasect,&dawall,&daspr,&x3,&y3,&z3,CLIPMASK1); + } + } + } + } + + if ((ps[goalplayer[snum]].dead_flag == 0) && + ((cansee(x1,y1,z1,damysect,x2,y2,z2,sprite[ps[goalplayer[snum]].i].sectnum)) || + (cansee(x1,y1,z1-(24<<8),damysect,x2,y2,z2-(24<<8),sprite[ps[goalplayer[snum]].i].sectnum)) || + (cansee(x1,y1,z1-(48<<8),damysect,x2,y2,z2-(48<<8),sprite[ps[goalplayer[snum]].i].sectnum)))) + { + syn->bits |= (1<<2); + + if ((p->curr_weapon == HANDBOMB_WEAPON) && (!(rand()&7))) + syn->bits &= ~(1<<2); + + if (p->curr_weapon == TRIPBOMB_WEAPON) + syn->bits |= ((rand()%MAX_WEAPONS)<<8); + + if (p->curr_weapon == RPG_WEAPON) + { + hitscan(x1,y1,z1-PHEIGHT,damysect,sintable[(damyang+512)&2047],sintable[damyang&2047], + (100-p->horiz-p->horizoff)*32,&dasect,&dawall,&daspr,&x3,&y3,&z3,CLIPMASK1); + if ((x3-x1)*(x3-x1)+(y3-y1)*(y3-y1) < 2560*2560) syn->bits &= ~(1<<2); + } + + + fightdist = fdmatrix[p->curr_weapon][ps[goalplayer[snum]].curr_weapon]; + if (fightdist < 128) fightdist = 128; + dist = ksqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)); if (dist == 0) dist = 1; + daang = getangle(x2+(ps[goalplayer[snum]].posxv>>14)-x1,y2+(ps[goalplayer[snum]].posyv>>14)-y1); + zang = 100-((z2-z1)*8)/dist; + fightdist = max(fightdist,(klabs(z2-z1)>>4)); + + if (sprite[ps[goalplayer[snum]].i].yrepeat < 32) + { fightdist = 0; syn->bits &= ~(1<<2); } + if (sprite[ps[goalplayer[snum]].i].pal == 1) + { fightdist = 0; syn->bits &= ~(1<<2); } + + if (dist < 256) syn->bits |= (1<<22); + + x3 = x2+((x1-x2)*fightdist/dist); + y3 = y2+((y1-y2)*fightdist/dist); + syn->fvel += (x3-x1)*2047/dist; + syn->svel += (y3-y1)*2047/dist; + + //Strafe attack + if (fightdist) + { + j = totalclock+snum*13468; + i = sintable[(j<<6)&2047]; + i += sintable[((j+4245)<<5)&2047]; + i += sintable[((j+6745)<<4)&2047]; + i += sintable[((j+15685)<<3)&2047]; + dx = sintable[(sprite[ps[goalplayer[snum]].i].ang+512)&2047]; + dy = sintable[sprite[ps[goalplayer[snum]].i].ang&2047]; + if ((x1-x2)*dy > (y1-y2)*dx) i += 8192; else i -= 8192; + syn->fvel += ((sintable[(daang+1024)&2047]*i)>>17); + syn->svel += ((sintable[(daang+512)&2047]*i)>>17); + } + + syn->avel = min(max((((daang+1024-damyang)&2047)-1024)>>1,-127),127); + syn->horz = min(max((zang-p->horiz)>>1,-MAXHORIZ),MAXHORIZ); + syn->bits |= (1<<23); + return; + } + + goalsect[snum] = -1; + if (goalsect[snum] < 0) + { + goalwall[snum] = -1; + startsect = sprite[p->i].sectnum; + endsect = sprite[ps[goalplayer[snum]].i].sectnum; + + clearbufbyte(dashow2dsector,(MAXSECTORS+7)>>3,0L); + searchsect[0] = startsect; + searchparent[0] = -1; + dashow2dsector[startsect>>3] |= (1<<(startsect&7)); + for(splc=0,send=1;splcnextsector; if (j < 0) continue; + + dx = ((wall[wal->point2].x+wal->x)>>1); + dy = ((wall[wal->point2].y+wal->y)>>1); + if ((getceilzofslope(j,dx,dy) > getflorzofslope(j,dx,dy)-(28<<8)) && ((sector[j].lotag < 15) || (sector[j].lotag > 22))) + continue; + if (getflorzofslope(j,dx,dy) < getflorzofslope(searchsect[splc],dx,dy)-(72<<8)) + continue; + if ((dashow2dsector[j>>3]&(1<<(j&7))) == 0) + { + dashow2dsector[j>>3] |= (1<<(j&7)); + searchsect[send] = (short)j; + searchparent[send] = (short)splc; + send++; + if (j == endsect) + { + clearbufbyte(dashow2dsector,(MAXSECTORS+7)>>3,0L); + for(k=send-1;k>=0;k=searchparent[k]) + dashow2dsector[searchsect[k]>>3] |= (1<<(searchsect[k]&7)); + + for(k=send-1;k>=0;k=searchparent[k]) + if (!searchparent[k]) break; + + goalsect[snum] = searchsect[k]; + startwall = sector[goalsect[snum]].wallptr; + endwall = startwall+sector[goalsect[snum]].wallnum; + x3 = y3 = 0; + for(i=startwall;i= dy*(x2-wall[i].x)) + if ((x3-x1)*(wall[i].y-y1) <= (y3-y1)*(wall[i].x-x1)) + if ((x3-x1)*(wall[wall[i].point2].y-y1) >= (y3-y1)*(wall[wall[i].point2].x-x1)) + { k = i; break; } + + dist = ksqrt(dx*dx+dy*dy); + if (dist > l) { l = dist; k = i; } + } + goalwall[snum] = k; + daang = ((getangle(wall[wall[k].point2].x-wall[k].x,wall[wall[k].point2].y-wall[k].y)+1536)&2047); + goalx[snum] = ((wall[k].x+wall[wall[k].point2].x)>>1)+(sintable[(daang+512)&2047]>>8); + goaly[snum] = ((wall[k].y+wall[wall[k].point2].y)>>1)+(sintable[daang&2047]>>8); + goalz[snum] = sector[goalsect[snum]].floorz-(32<<8); + break; + } + } + } + + for(i=headspritesect[searchsect[splc]];i>=0;i=nextspritesect[i]) + if (sprite[i].lotag == 7) + { + j = sprite[sprite[i].owner].sectnum; + if ((dashow2dsector[j>>3]&(1<<(j&7))) == 0) + { + dashow2dsector[j>>3] |= (1<<(j&7)); + searchsect[send] = (short)j; + searchparent[send] = (short)splc; + send++; + if (j == endsect) + { + clearbufbyte(dashow2dsector,(MAXSECTORS+7)>>3,0L); + for(k=send-1;k>=0;k=searchparent[k]) + dashow2dsector[searchsect[k]>>3] |= (1<<(searchsect[k]&7)); + + for(k=send-1;k>=0;k=searchparent[k]) + if (!searchparent[k]) break; + + goalsect[snum] = searchsect[k]; + startwall = sector[startsect].wallptr; + endwall = startwall+sector[startsect].wallnum; + l = 0; k = startwall; + for(i=startwall;i l)) + { l = dist; k = i; } + } + goalwall[snum] = k; + daang = ((getangle(wall[wall[k].point2].x-wall[k].x,wall[wall[k].point2].y-wall[k].y)+1536)&2047); + goalx[snum] = ((wall[k].x+wall[wall[k].point2].x)>>1)+(sintable[(daang+512)&2047]>>8); + goaly[snum] = ((wall[k].y+wall[wall[k].point2].y)>>1)+(sintable[daang&2047]>>8); + goalz[snum] = sector[goalsect[snum]].floorz-(32<<8); + break; + } + } + } + if (goalwall[snum] >= 0) break; + } + } + + if ((goalsect[snum] < 0) || (goalwall[snum] < 0)) + { + if (goalsprite[snum] < 0) + { + for(k=0;k<4;k++) + { + i = (rand()%numsectors); + for(j=headspritesect[i];j>=0;j=nextspritesect[j]) + { + if ((sprite[j].xrepeat <= 0) || (sprite[j].yrepeat <= 0)) continue; + if (getspritescore(snum,sprite[j].picnum) <= 0) continue; + if (cansee(x1,y1,z1-(32<<8),damysect,sprite[j].x,sprite[j].y,sprite[j].z-(4<<8),i)) + { goalx[snum] = sprite[j].x; goaly[snum] = sprite[j].y; goalz[snum] = sprite[j].z; goalsprite[snum] = j; break; } + } + } + } + x2 = goalx[snum]; + y2 = goaly[snum]; + dist = ksqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)); if (!dist) return; + daang = getangle(x2-x1,y2-y1); + syn->fvel += (x2-x1)*2047/dist; + syn->svel += (y2-y1)*2047/dist; + syn->avel = min(max((((daang+1024-damyang)&2047)-1024)>>3,-127),127); + } + else + goalsprite[snum] = -1; + + x3 = p->posx; y3 = p->posy; z3 = p->posz; dasect = p->cursectnum; + i = clipmove(&x3,&y3,&z3,&dasect,p->posxv,p->posyv,164L,4L<<8,4L<<8,CLIPMASK0); + if (!i) + { + x3 = p->posx; y3 = p->posy; z3 = p->posz+(24<<8); dasect = p->cursectnum; + i = clipmove(&x3,&y3,&z3,&dasect,p->posxv,p->posyv,164L,4L<<8,4L<<8,CLIPMASK0); + } + if (i) + { + clipmovecount[snum]++; + + j = 0; + if ((i&0xc000) == 32768) //Hit a wall (49152 for sprite) + if (wall[i&(MAXWALLS-1)].nextsector >= 0) + { + if (getflorzofslope(wall[i&(MAXWALLS-1)].nextsector,p->posx,p->posy) <= p->posz+(24<<8)) j |= 1; + if (getceilzofslope(wall[i&(MAXWALLS-1)].nextsector,p->posx,p->posy) >= p->posz-(24<<8)) j |= 2; + } + if ((i&0xc000) == 49152) j = 1; + if (j&1) if (clipmovecount[snum] == 4) syn->bits |= (1<<0); + if (j&2) syn->bits |= (1<<1); + + //Strafe attack + daang = getangle(x2-x1,y2-y1); + if ((i&0xc000) == 32768) + daang = getangle(wall[wall[i&(MAXWALLS-1)].point2].x-wall[i&(MAXWALLS-1)].x,wall[wall[i&(MAXWALLS-1)].point2].y-wall[i&(MAXWALLS-1)].y); + j = totalclock+snum*13468; + i = sintable[(j<<6)&2047]; + i += sintable[((j+4245)<<5)&2047]; + i += sintable[((j+6745)<<4)&2047]; + i += sintable[((j+15685)<<3)&2047]; + syn->fvel += ((sintable[(daang+1024)&2047]*i)>>17); + syn->svel += ((sintable[(daang+512)&2047]*i)>>17); + + if ((clipmovecount[snum]&31) == 2) syn->bits |= (1<<29); + if ((clipmovecount[snum]&31) == 17) syn->bits |= (1<<22); + if (clipmovecount[snum] > 32) { goalsect[snum] = -1; goalwall[snum] = -1; clipmovecount[snum] = 0; } + + goalsprite[snum] = -1; + } + else + clipmovecount[snum] = 0; + + if ((goalsect[snum] >= 0) && (goalwall[snum] >= 0)) + { + x2 = goalx[snum]; + y2 = goaly[snum]; + dist = ksqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)); if (!dist) return; + daang = getangle(x2-x1,y2-y1); + if ((goalwall[snum] >= 0) && (dist < 4096)) + daang = ((getangle(wall[wall[goalwall[snum]].point2].x-wall[goalwall[snum]].x,wall[wall[goalwall[snum]].point2].y-wall[goalwall[snum]].y)+1536)&2047); + syn->fvel += (x2-x1)*2047/dist; + syn->svel += (y2-y1)*2047/dist; + syn->avel = min(max((((daang+1024-damyang)&2047)-1024)>>3,-127),127); + } +} + diff --git a/premap.c b/premap.c new file mode 100755 index 0000000..da08662 --- /dev/null +++ b/premap.c @@ -0,0 +1,1569 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment + +This file is part of Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Original Source: 1996 - Todd Replogle +Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms +*/ +//------------------------------------------------------------------------- + +#include "duke3d.h" + +extern char everyothertime; +short which_palookup = 9; + + +static void tloadtile(short tilenume) +{ + gotpic[tilenume>>3] |= (1<<(tilenume&7)); +} + +void cachespritenum(short i) +{ + char maxc; + short j; + + if(ud.monsters_off && badguy(&sprite[i])) return; + + maxc = 1; + + switch(PN) + { + case HYDRENT: + tloadtile(BROKEFIREHYDRENT); + for(j = TOILETWATER; j < (TOILETWATER+4); j++) + if(waloff[j] == 0) tloadtile(j); + break; + case TOILET: + tloadtile(TOILETBROKE); + for(j = TOILETWATER; j < (TOILETWATER+4); j++) + if(waloff[j] == 0) tloadtile(j); + break; + case STALL: + tloadtile(STALLBROKE); + for(j = TOILETWATER; j < (TOILETWATER+4); j++) + if(waloff[j] == 0) tloadtile(j); + break; + case RUBBERCAN: + maxc = 2; + break; + case TOILETWATER: + maxc = 4; + break; + case FEMPIC1: + maxc = 44; + break; + case LIZTROOP: + case LIZTROOPRUNNING: + case LIZTROOPSHOOT: + case LIZTROOPJETPACK: + case LIZTROOPONTOILET: + case LIZTROOPDUCKING: + for(j = LIZTROOP; j < (LIZTROOP+72); j++) + if(waloff[j] == 0) + tloadtile(j); + for(j=HEADJIB1;j 1) + { + maxc = 5; + for(j = 1420;j < 1420+106; j++) + if(waloff[j] == -1) + tloadtile(j); + } + break; + case ATOMICHEALTH: + maxc = 14; + break; + case DRONE: + maxc = 10; + break; + case EXPLODINGBARREL: + case SEENINE: + case OOZFILTER: + maxc = 3; + break; + case NUKEBARREL: + case CAMERA1: + maxc = 5; + break; + } + + for(j = PN; j < (PN+maxc); j++) + if(waloff[j] == 0) + tloadtile(j); +} + +void cachegoodsprites(void) +{ + short i; + + if(ud.screen_size >= 8) + { + if(waloff[BOTTOMSTATUSBAR] == 0) + tloadtile(BOTTOMSTATUSBAR); + if( ud.multimode > 1) + { + if(waloff[FRAGBAR] == 0) + tloadtile(FRAGBAR); + for(i=MINIFONT;i= NUM_SOUNDS || SoundToggle == 0) return 0; + if (FXDevice == NumSoundCards) return 0; + + fp = kopen4load(sounds[num],loadfromgrouponly); + if(fp == -1) return 0; + + l = kfilelength( fp ); + soundsiz[num] = l; + + if( (ud.level_number == 0 && ud.volume_number == 0 && (num == 189 || num == 232 || num == 99 || num == 233 || num == 17 ) ) || + ( l < 12288 ) ) + { + Sound[num].lock = 2; + allocache((long *)&Sound[num].ptr,l,(unsigned char *)&Sound[num].lock); + if(Sound[num].ptr != NULL) + kread( fp, Sound[num].ptr , l); + } + kclose( fp ); + return 1; +} + +void precachenecessarysounds(void) +{ + short i, j; + + if (FXDevice == NumSoundCards) return; + j = 0; + + for(i=0;i= 0 && waloff[wall[i].overpicnum] == 0 ) + tloadtile(wall[i].overpicnum); + } + + for(i=0;i= 0) + { + if(sprite[j].xrepeat != 0 && sprite[j].yrepeat != 0 && (sprite[j].cstat&32768) == 0) + if(waloff[sprite[j].picnum] == 0) + cachespritenum(j); + j = nextspritesect[j]; + } + } + +} + +void docacheit(void) +{ + long i,j; + + j = 0; + + for(i=0;i>3]&(1<<(i&7))) && waloff[i] == 0) + { + loadtile((short)i); + j++; + if((j&7) == 0) getpackets(); + } + + clearbufbyte(gotpic,sizeof(gotpic),0L); + +} + + + +void xyzmirror(short i,short wn) +{ + if (waloff[wn] == 0) loadtile(wn); + setviewtotile(wn,tilesizy[wn],tilesizx[wn]); + + drawrooms(SX,SY,SZ,SA,100+sprite[i].shade,SECT); + display_mirror = 1; animatesprites(SX,SY,SA,65536L); display_mirror = 0; + drawmasks(); + + setviewback(); + squarerotatetile(wn); +} + +void vscrn(void) +{ + long i, j, ss, x1, x2, y1, y2; + + if(ud.screen_size < 0) ud.screen_size = 0; + else if(ud.screen_size > 63) ud.screen_size = 64; + + if(ud.screen_size == 0) flushperms(); + + ss = max(ud.screen_size-8,0); + + x1 = scale(ss,xdim,160); + x2 = xdim-x1; + + y1 = ss; y2 = 200; + if ( ud.screen_size > 0 && ud.coop != 1 && ud.multimode > 1) + { + j = 0; + for(i=connecthead;i>=0;i=connectpoint2[i]) + if(i > j) j = i; + + if (j >= 1) y1 += 8; + if (j >= 4) y1 += 8; + if (j >= 8) y1 += 8; + if (j >= 12) y1 += 8; + } + + if (ud.screen_size >= 8) y2 -= (ss+34); + + y1 = scale(y1,ydim,200); + y2 = scale(y2,ydim,200); + + setview(x1,y1,x2-1,y2-1); + + pub = NUMPAGES; + pus = NUMPAGES; +} + +void pickrandomspot(short snum) +{ + struct player_struct *p; + short i; + + p = &ps[snum]; + + if( ud.multimode > 1 && ud.coop != 1) + i = TRAND%numplayersprites; + else i = snum; + + p->bobposx = p->oposx = p->posx = po[i].ox; + p->bobposy = p->oposy = p->posy = po[i].oy; + p->oposz = p->posz = po[i].oz; + p->ang = po[i].oa; + p->cursectnum = po[i].os; +} + +void resetplayerstats(short snum) +{ + struct player_struct *p; + short i; + + p = &ps[snum]; + + ud.show_help = 0; + ud.showallmap = 0; + p->dead_flag = 0; + p->wackedbyactor = -1; + p->falling_counter = 0; + p->quick_kick = 0; + p->subweapon = 0; + p->last_full_weapon = 0; + p->ftq = 0; + p->fta = 0; + p->tipincs = 0; + p->buttonpalette = 0; + p->actorsqu =-1; + p->invdisptime = 0; + p->refresh_inventory= 0; + p->last_pissed_time = 0; + p->holster_weapon = 0; + p->pycount = 0; + p->pyoff = 0; + p->opyoff = 0; + p->loogcnt = 0; + p->angvel = 0; + p->weapon_sway = 0; +// p->select_dir = 0; + p->extra_extra8 = 0; + p->show_empty_weapon= 0; + p->dummyplayersprite=-1; + p->crack_time = 0; + p->hbomb_hold_delay = 0; + p->transporter_hold = 0; + p->wantweaponfire = -1; + p->hurt_delay = 0; + p->footprintcount = 0; + p->footprintpal = 0; + p->footprintshade = 0; + p->jumping_toggle = 0; + p->ohoriz = p->horiz= 140; + p->horizoff = 0; + p->bobcounter = 0; + p->on_ground = 0; + p->player_par = 0; + p->return_to_center = 9; + p->airleft = 15*26; + p->rapid_fire_hold = 0; + p->toggle_key_flag = 0; + p->access_spritenum = -1; + if(ud.multimode > 1 && ud.coop != 1 ) + p->got_access = 7; + else p->got_access = 0; + p->random_club_frame= 0; + pus = 1; + p->on_warping_sector = 0; + p->spritebridge = 0; + p->palette = (char *) &palette[0]; + + if(p->steroids_amount < 400 ) + { + p->steroids_amount = 0; + p->inven_icon = 0; + } + p->heat_on = 0; + p->jetpack_on = 0; + p->holoduke_on = -1; + + p->look_ang = 512 - ((ud.level_number&1)<<10); + + p->rotscrnang = 0; + p->newowner =-1; + p->jumping_counter = 0; + p->hard_landing = 0; + p->posxv = 0; + p->posyv = 0; + p->poszv = 0; + fricxv = 0; + fricyv = 0; + p->somethingonplayer =-1; + p->one_eighty_count = 0; + p->cheat_phase = 0; + + p->on_crane = -1; + + if(p->curr_weapon == PISTOL_WEAPON) + p->kickback_pic = 5; + else p->kickback_pic = 0; + + p->weapon_pos = 6; + p->walking_snd_toggle= 0; + p->weapon_ang = 0; + + p->knuckle_incs = 1; + p->fist_incs = 0; + p->knee_incs = 0; + p->jetpack_on = 0; + setpal(p); +} + + + +void resetweapons(short snum) +{ + short weapon; + struct player_struct *p; + + p = &ps[snum]; + + for ( weapon = PISTOL_WEAPON; weapon < MAX_WEAPONS; weapon++ ) + p->gotweapon[weapon] = 0; + for ( weapon = PISTOL_WEAPON; weapon < MAX_WEAPONS; weapon++ ) + p->ammo_amount[weapon] = 0; + + p->weapon_pos = 6; + p->kickback_pic = 5; + p->curr_weapon = PISTOL_WEAPON; + p->gotweapon[PISTOL_WEAPON] = 1; + p->gotweapon[KNEE_WEAPON] = 1; + p->ammo_amount[PISTOL_WEAPON] = 48; + p->gotweapon[HANDREMOTE_WEAPON] = 1; + p->last_weapon = -1; + + p->show_empty_weapon= 0; + p->last_pissed_time = 0; + p->holster_weapon = 0; +} + +void resetinventory(short snum) +{ + struct player_struct *p; + short i; + + p = &ps[snum]; + + p->inven_icon = 0; + p->boot_amount = 0; + p->scuba_on = 0;p->scuba_amount = 0; + p->heat_amount = 0;p->heat_on = 0; + p->jetpack_on = 0;p->jetpack_amount = 0; + p->shield_amount = max_armour_amount; + p->holoduke_on = -1; + p->holoduke_amount = 0; + p->firstaid_amount = 0; + p->steroids_amount = 0; + p->inven_icon = 0; +} + + +void resetprestat(short snum,char g) +{ + struct player_struct *p; + short i; + + p = &ps[snum]; + + spriteqloc = 0; + for(i=0;ihbomb_on = 0; + p->cheat_phase = 0; + p->pals_time = 0; + p->toggle_key_flag = 0; + p->secret_rooms = 0; + p->max_secret_rooms = 0; + p->actors_killed = 0; + p->max_actors_killed = 0; + p->lastrandomspot = 0; + p->weapon_pos = 6; + p->kickback_pic = 5; + p->last_weapon = -1; + p->weapreccnt = 0; + p->show_empty_weapon= 0; + p->holster_weapon = 0; + p->last_pissed_time = 0; + + p->one_parallax_sectnum = -1; + p->visibility = ud.const_visibility; + + screenpeek = myconnectindex; + numanimwalls = 0; + numcyclers = 0; + animatecnt = 0; + parallaxtype = 0; + randomseed = 17L; + ud.pause_on = 0; + ud.camerasprite =-1; + ud.eog = 0; + tempwallptr = 0; + camsprite =-1; + earthquaketime = 0; + + numinterpolations = 0; + startofdynamicinterpolations = 0; + + if( ( (g&MODE_EOL) != MODE_EOL && numplayers < 2) || (ud.coop != 1 && numplayers > 1) ) + { + resetweapons(snum); + resetinventory(snum); + } + else if(p->curr_weapon == HANDREMOTE_WEAPON) + { + p->ammo_amount[HANDBOMB_WEAPON]++; + p->curr_weapon = HANDBOMB_WEAPON; + } + + p->timebeforeexit = 0; + p->customexitsound = 0; + +} + +void setupbackdrop(short sky) +{ + short i; + + for(i=0;i sector[i].ceilingz) + sector[i].lotag |= 32768; + continue; + } + + if(sector[i].ceilingstat&1) + { + if(waloff[sector[i].ceilingpicnum] == 0) + { + if(sector[i].ceilingpicnum == LA) + for(j=0;j<5;j++) + if(waloff[sector[i].ceilingpicnum+j] == 0) + tloadtile(sector[i].ceilingpicnum+j); + } + setupbackdrop(sector[i].ceilingpicnum); + + if(sector[i].ceilingpicnum == CLOUDYSKIES && numclouds < 127) + clouds[numclouds++] = i; + + if(ps[0].one_parallax_sectnum == -1) + ps[0].one_parallax_sectnum = i; + } + + if(sector[i].lotag == 32767) //Found a secret room + { + ps[0].max_secret_rooms++; + continue; + } + + if(sector[i].lotag == -1) + { + ps[0].exitx = wall[sector[i].wallptr].x; + ps[0].exity = wall[sector[i].wallptr].y; + continue; + } + } + + i = headspritestat[0]; + while(i >= 0) + { + nexti = nextspritestat[i]; + + if(sprite[i].lotag == -1 && (sprite[i].cstat&16) ) + { + ps[0].exitx = SX; + ps[0].exity = SY; + } + else switch(PN) + { + case GPSPEED: + sector[SECT].extra = SLT; + deletesprite(i); + break; + + case CYCLER: + if(numcyclers >= MAXCYCLERS) + gameexit("\nToo many cycling sectors."); + cyclers[numcyclers][0] = SECT; + cyclers[numcyclers][1] = SLT; + cyclers[numcyclers][2] = SS; + cyclers[numcyclers][3] = sector[SECT].floorshade; + cyclers[numcyclers][4] = SHT; + cyclers[numcyclers][5] = (SA == 1536); + numcyclers++; + deletesprite(i); + break; + } + i = nexti; + } + + for(i=0;i < MAXSPRITES;i++) + { + if(sprite[i].statnum < MAXSTATUS) + { + if(PN == SECTOREFFECTOR && SLT == 14) + continue; + spawn(-1,i); + } + } + + for(i=0;i < MAXSPRITES;i++) + if(sprite[i].statnum < MAXSTATUS) + { + if( PN == SECTOREFFECTOR && SLT == 14 ) + spawn(-1,i); + } + + lotaglist = 0; + + i = headspritestat[0]; + while(i >= 0) + { + switch(PN) + { + case DIPSWITCH: + case DIPSWITCH2: + case ACCESSSWITCH: + case PULLSWITCH: + case HANDSWITCH: + case SLOTDOOR: + case LIGHTSWITCH: + case SPACELIGHTSWITCH: + case SPACEDOORSWITCH: + case FRANKENSTINESWITCH: + case LIGHTSWITCH2: + case POWERSWITCH1: + case LOCKSWITCH1: + case POWERSWITCH2: + break; + case DIPSWITCH+1: + case DIPSWITCH2+1: + case PULLSWITCH+1: + case HANDSWITCH+1: + case SLOTDOOR+1: + case LIGHTSWITCH+1: + case SPACELIGHTSWITCH+1: + case SPACEDOORSWITCH+1: + case FRANKENSTINESWITCH+1: + case LIGHTSWITCH2+1: + case POWERSWITCH1+1: + case LOCKSWITCH1+1: + case POWERSWITCH2+1: + for(j=0;j 64) + gameexit("\nToo many switches (64 max)."); + + j = headspritestat[3]; + while(j >= 0) + { + if(sprite[j].lotag == 12 && sprite[j].hitag == SLT) + hittype[j].temp_data[0] = 1; + j = nextspritestat[j]; + } + } + break; + } + i = nextspritestat[i]; + } + + mirrorcnt = 0; + + for( i = 0; i < numwalls; i++ ) + { + walltype *wal; + wal = &wall[i]; + + if(wal->overpicnum == MIRROR && (wal->cstat&32) != 0) + { + j = wal->nextsector; + + if(mirrorcnt > 63) + gameexit("\nToo many mirrors (64 max.)"); + if ( (j >= 0) && sector[j].ceilingpicnum != MIRROR ) + { + sector[j].ceilingpicnum = MIRROR; + sector[j].floorpicnum = MIRROR; + mirrorwall[mirrorcnt] = i; + mirrorsector[mirrorcnt] = j; + mirrorcnt++; + continue; + } + } + + if(numanimwalls >= MAXANIMWALLS) + gameexit("\nToo many 'anim' walls (max 512.)"); + + animwall[numanimwalls].tag = 0; + animwall[numanimwalls].wallnum = 0; + + switch(wal->overpicnum) + { + case FANSHADOW: + case FANSPRITE: + wall->cstat |= 65; + animwall[numanimwalls].wallnum = i; + numanimwalls++; + break; + + case W_FORCEFIELD: + if(waloff[W_FORCEFIELD] == 0) + for(j=0;j<3;j++) + tloadtile(W_FORCEFIELD+j); + case W_FORCEFIELD+1: + case W_FORCEFIELD+2: + if(wal->shade > 31) + wal->cstat = 0; + else wal->cstat |= 85+256; + + + if(wal->lotag && wal->nextwall >= 0) + wall[wal->nextwall].lotag = + wal->lotag; + + case BIGFORCE: + + animwall[numanimwalls].wallnum = i; + numanimwalls++; + + continue; + } + + wal->extra = -1; + + switch(wal->picnum) + { + case WATERTILE2: + for(j=0;j<3;j++) + if(waloff[wal->picnum+j] == 0) + tloadtile(wal->picnum+j); + break; + + case TECHLIGHT2: + case TECHLIGHT4: + if(waloff[wal->picnum] == 0) + tloadtile(wal->picnum); + break; + case W_TECHWALL1: + case W_TECHWALL2: + case W_TECHWALL3: + case W_TECHWALL4: + animwall[numanimwalls].wallnum = i; +// animwall[numanimwalls].tag = -1; + numanimwalls++; + break; + case SCREENBREAK6: + case SCREENBREAK7: + case SCREENBREAK8: + if(waloff[SCREENBREAK6] == 0) + for(j=SCREENBREAK6;jextra = wal->picnum; + animwall[numanimwalls].tag = -1; + if(ud.lockout) + { + if(wal->picnum == FEMPIC1) + wal->picnum = BLANKSCREEN; + else wal->picnum = SCREENBREAK6; + } + + animwall[numanimwalls].wallnum = i; + animwall[numanimwalls].tag = wal->picnum; + numanimwalls++; + break; + + case SCREENBREAK1: + case SCREENBREAK2: + case SCREENBREAK3: + case SCREENBREAK4: + case SCREENBREAK5: + + case SCREENBREAK9: + case SCREENBREAK10: + case SCREENBREAK11: + case SCREENBREAK12: + case SCREENBREAK13: + case SCREENBREAK14: + case SCREENBREAK15: + case SCREENBREAK16: + case SCREENBREAK17: + case SCREENBREAK18: + case SCREENBREAK19: + + animwall[numanimwalls].wallnum = i; + animwall[numanimwalls].tag = wal->picnum; + numanimwalls++; + break; + } + } + + //Invalidate textures in sector behind mirror + for(i=0;i= 0) + while(Sound[globalskillsound].lock>=200); + globalskillsound = -1; + + waitforeverybody(); + ready2send = 0; + + if( ud.m_recstat != 2 && ud.last_level >= 0 && ud.multimode > 1 && ud.coop != 1) + dobonus(1); + + if( ln == 0 && vn == 3 && ud.multimode < 2 && ud.lockout == 0) + { + playmusic(&env_music_fn[1][0]); + + flushperms(); + setview(0,0,xdim-1,ydim-1); + clearview(0L); + nextpage(); + + playanm("vol41a.anm",6); + clearview(0L); + nextpage(); + playanm("vol42a.anm",7); +// clearview(0L); + // nextpage(); + playanm("vol43a.anm",9); + clearview(0L); + nextpage(); + + FX_StopAllSounds(); + } + + show_shareware = 26*34; + + ud.level_number = ln; + ud.volume_number = vn; + ud.player_skill = sk; + ud.secretlevel = 0; + ud.from_bonus = 0; + parallaxyscale = 0; + + ud.last_level = -1; + lastsavedpos = -1; + p->zoom = 768; + p->gm = 0; + + if(ud.m_coop != 1) + { + p->curr_weapon = PISTOL_WEAPON; + p->gotweapon[PISTOL_WEAPON] = 1; + p->gotweapon[KNEE_WEAPON] = 1; + p->ammo_amount[PISTOL_WEAPON] = 48; + p->gotweapon[HANDREMOTE_WEAPON] = 1; + p->last_weapon = -1; + } + + display_mirror = 0; + + if(ud.multimode > 1 ) + { + if(numplayers < 2) + { + connecthead = 0; + for(i=0;i 1 && ud.coop == 1 && ud.last_level >= 0) + { + for(j=0;j 1 && ud.coop == 1 && ud.last_level >= 0) + { + for(j=0;j= 0) + { + nexti = nextspritestat[i]; + s = &sprite[i]; + + if( numplayersprites == MAXPLAYERS) + gameexit("\nToo many player sprites (max 16.)"); + + if(numplayersprites == 0) + { + firstx = ps[0].posx; + firsty = ps[0].posy; + } + + po[(int)numplayersprites].ox = s->x; + po[(int)numplayersprites].oy = s->y; + po[(int)numplayersprites].oz = s->z; + po[(int)numplayersprites].oa = s->ang; + po[(int)numplayersprites].os = s->sectnum; + + numplayersprites++; + if(j >= 0) + { + s->owner = i; + s->shade = 0; + s->xrepeat = 42; + s->yrepeat = 36; + s->cstat = 1+256; + s->xoffset = 0; + s->clipdist = 64; + + if( (g&MODE_EOL) != MODE_EOL || ps[j].last_extra == 0) + { + ps[j].last_extra = max_player_health; + s->extra = max_player_health; + } + else s->extra = ps[j].last_extra; + + s->yvel = j; + + if(s->pal == 0) + { + s->pal = ps[j].palookup = which_palookup; + which_palookup++; + if( which_palookup >= 17 ) which_palookup = 9; + } + else ps[j].palookup = s->pal; + + ps[j].i = i; + ps[j].frag_ps = j; + hittype[i].owner = i; + + hittype[i].bposx = ps[j].bobposx = ps[j].oposx = ps[j].posx = s->x; + hittype[i].bposy = ps[j].bobposy = ps[j].oposy = ps[j].posy = s->y; + hittype[i].bposz = ps[j].oposz = ps[j].posz = s->z; + ps[j].oang = ps[j].ang = s->ang; + + updatesector(s->x,s->y,&ps[j].cursectnum); + + j = connectpoint2[j]; + + } + else deletesprite(i); + i = nexti; + } +} + +void clearfrags(void) +{ + short i; + + for(i = 0;i=0;i=connectpoint2[i]) + { + if (i != myconnectindex) + sendpacket(i,packbuf,1); + } + + playerreadyflag[myconnectindex]++; + do + { + _idle(); /* let input queue run... */ + getpackets(); + for(i=connecthead;i>=0;i=connectpoint2[i]) + { + if (playerreadyflag[i] < playerreadyflag[myconnectindex]) + break; + } + } while (i >= 0); +} + +void dofrontscreens(void) +{ + long tincs,i,j; + + if(ud.recstat != 2) + { + ps[myconnectindex].palette = palette; + for(j=0;j<63;j+=7) palto(0,0,0,j); + i = ud.screen_size; + ud.screen_size = 0; + vscrn(); + clearview(0L); + + rotatesprite(320<<15,200<<15,65536L,0,LOADSCREEN,0,0,2+8+64,0,0,xdim-1,ydim-1); + + if( boardfilename[0] != 0 && ud.level_number == 7 && ud.volume_number == 0 ) + { + menutext(160,90,0,0,"ENTERING USER MAP"); + gametextpal(160,90+10,boardfilename,14,2); + } + else + { + menutext(160,90,0,0,"ENTERING"); + menutext(160,90+16+8,0,0,level_names[(ud.volume_number*11) + ud.level_number]); + } + + nextpage(); + + for(j=63;j>0;j-=7) palto(0,0,0,j); + + KB_FlushKeyboardQueue(); + ud.screen_size = i; + } + else + { + clearview(0L); + ps[myconnectindex].palette = palette; + palto(0,0,0,0); + rotatesprite(320<<15,200<<15,65536L,0,LOADSCREEN,0,0,2+8+64,0,0,xdim-1,ydim-1); + menutext(160,105,0,0,"LOADING..."); + nextpage(); + } +} + +void clearfifo(void) +{ + syncvaltail = 0L; + syncvaltottail = 0L; + syncstat = 0; + bufferjitter = 1; + mymaxlag = otherminlag = 0; + + movefifoplc = movefifosendplc = fakemovefifoplc = 0; + avgfvel = avgsvel = avgavel = avghorz = avgbits = 0; + otherminlag = mymaxlag = 0; + + clearbufbyte(myminlag,MAXPLAYERS<<2,0L); + clearbufbyte(&loc,sizeof(input),0L); + clearbufbyte(&sync[0],sizeof(sync),0L); + clearbufbyte(inputfifo,sizeof(input)*MOVEFIFOSIZ*MAXPLAYERS,0L); + + clearbuf(movefifoend,MAXPLAYERS,0L); + clearbuf(syncvalhead,MAXPLAYERS,0L); + clearbuf(myminlag,MAXPLAYERS,0L); + +// clearbufbyte(playerquitflag,MAXPLAYERS,0x01); +} + +void resetmys(void) +{ + myx = omyx = ps[myconnectindex].posx; + myy = omyy = ps[myconnectindex].posy; + myz = omyz = ps[myconnectindex].posz; + myxvel = myyvel = myzvel = 0; + myang = omyang = ps[myconnectindex].ang; + myhoriz = omyhoriz = ps[myconnectindex].horiz; + myhorizoff = omyhorizoff = ps[myconnectindex].horizoff; + mycursectnum = ps[myconnectindex].cursectnum; + myjumpingcounter = ps[myconnectindex].jumping_counter; + myjumpingtoggle = ps[myconnectindex].jumping_toggle; + myonground = ps[myconnectindex].on_ground; + myhardlanding = ps[myconnectindex].hard_landing; + myreturntocenter = ps[myconnectindex].return_to_center; +} + +void enterlevel(char g) +{ + short i,j; + long l; + char levname[256]; + + if( (g&MODE_DEMO) != MODE_DEMO ) ud.recstat = ud.m_recstat; + ud.respawn_monsters = ud.m_respawn_monsters; + ud.respawn_items = ud.m_respawn_items; + ud.respawn_inventory = ud.m_respawn_inventory; + ud.monsters_off = ud.m_monsters_off; + ud.coop = ud.m_coop; + ud.marker = ud.m_marker; + ud.ffire = ud.m_ffire; + + if( (g&MODE_DEMO) == 0 && ud.recstat == 2) + ud.recstat = 0; + + FX_StopAllSounds(); + clearsoundlocks(); + FX_SetReverb(0); + + i = ud.screen_size; + ud.screen_size = 0; + dofrontscreens(); + vscrn(); + ud.screen_size = i; + +#ifndef VOLUMEONE + + if( boardfilename[0] != 0 && ud.m_level_number == 7 && ud.m_volume_number == 0 ) + { + if ( loadboard( boardfilename,&ps[0].posx, &ps[0].posy, &ps[0].posz, &ps[0].ang,&ps[0].cursectnum ) == -1 ) + { + sprintf(tempbuf,"Map %s not found!",boardfilename); + gameexit(tempbuf); + } + } + else if ( loadboard( level_file_names[ (ud.volume_number*11)+ud.level_number],&ps[0].posx, &ps[0].posy, &ps[0].posz, &ps[0].ang,&ps[0].cursectnum ) == -1) + { + sprintf(tempbuf,"Map %s not found!",level_file_names[(ud.volume_number*11)+ud.level_number]); + gameexit(tempbuf); + } + +#else + + l = strlen(level_file_names[ (ud.volume_number*11)+ud.level_number]); + copybufbyte( level_file_names[ (ud.volume_number*11)+ud.level_number],&levname[0],l); + levname[l] = 255; + levname[l+1] = 0; + + if ( loadboard( levname,&ps[0].posx, &ps[0].posy, &ps[0].posz, &ps[0].ang,&ps[0].cursectnum ) == -1) + { + sprintf(tempbuf,"Map %s not found!",level_file_names[(ud.volume_number*11)+ud.level_number]); + gameexit(tempbuf); + } +#endif + + clearbufbyte(gotpic,sizeof(gotpic),0L); + + prelevel(g); + + allignwarpelevators(); + resetpspritevars(g); + + cachedebug = 0; + automapping = 0; + + if(ud.recstat != 2) MUSIC_StopSong(); + + cacheit(); + docacheit(); + + if(ud.recstat != 2) + { + music_select = (ud.volume_number*11) + ud.level_number; + playmusic(&music_fn[0][(int)music_select][0]); + } + + if( (g&MODE_GAME) || (g&MODE_EOL) ) + ps[myconnectindex].gm = MODE_GAME; + else if(g&MODE_RESTART) + { + if(ud.recstat == 2) + ps[myconnectindex].gm = MODE_DEMO; + else ps[myconnectindex].gm = MODE_GAME; + } + + if( (ud.recstat == 1) && (g&MODE_RESTART) != MODE_RESTART ) + opendemowrite(); + +#ifdef VOLUMEONE + if(ud.level_number == 0 && ud.recstat != 2) FTA(40,&ps[myconnectindex]); +#endif + + for(i=connecthead;i>=0;i=connectpoint2[i]) + switch(sector[sprite[ps[i].i].sectnum].floorpicnum) + { + case HURTRAIL: + case FLOORSLIME: + case FLOORPLASMA: + resetweapons(i); + resetinventory(i); + ps[i].gotweapon[PISTOL_WEAPON] = 0; + ps[i].ammo_amount[PISTOL_WEAPON] = 0; + ps[i].curr_weapon = KNEE_WEAPON; + ps[i].kickback_pic = 0; + break; + } + + //PREMAP.C - replace near the my's at the end of the file + + resetmys(); + + ps[myconnectindex].palette = palette; + palto(0,0,0,0); + + setpal(&ps[myconnectindex]); + flushperms(); + + everyothertime = 0; + global_random = 0; + + ud.last_level = ud.level_number+1; + + clearfifo(); + + for(i=numinterpolations-1;i>=0;i--) bakipos[i] = *curipos[i]; + + restorepalette = 1; + + flushpackets(); + waitforeverybody(); + + palto(0,0,0,0); + vscrn(); + clearview(0L); + drawbackground(); + + clearbufbyte(playerquitflag,MAXPLAYERS,0x01010101); + ps[myconnectindex].over_shoulder_on = 0; + + clearfrags(); + + resettimevars(); // Here we go + + +} + +/* +Duke Nukem V + +Layout: + + Settings: + Suburbs + Duke inflitrating neighborhoods inf. by aliens + Death Valley: + Sorta like a western. Bull-skulls halb buried in the sand + Military compound: Aliens take over nuke-missle silo, duke + must destroy. + Abondend Aircraft field + Vegas: + Blast anything bright! Alien lights camoflauged. + Alien Drug factory. The Blue Liquid + Mountainal Cave: + Interior cave battles. + Jungle: + Trees, canopee, animals, a mysterious hole in the earth + Penetencury: + Good use of spotlights: + Inventory: + Wood, + Metal, + Torch, + Rope, + Plastique, + Cloth, + Wiring, + Glue, + Cigars, + Food, + Duck Tape, + Nails, + Piping, + Petrol, + Uranium, + Gold, + Prism, + Power Cell, + + Hand spikes (Limited usage, they become dull) + Oxygent (Oxygen mixed with stimulant) + + + Player Skills: + R-Left,R-Right,Foward,Back + Strafe, Jump, Double Flip Jump for distance + Help, Escape + Fire/Use + Use Menu + +Programming: + Images: Polys + Actors: + Multi-Object sections for change (head,arms,legs,torsoe,all change) + Facial expressions. Pal lookup per poly? + + struct imagetype + { + int *itable; // AngX,AngY,AngZ,Xoff,Yoff,Zoff; + int *idata; + struct imagetype *prev, *next; + } + +*/ diff --git a/rts.c b/rts.c new file mode 100755 index 0000000..d92fb37 --- /dev/null +++ b/rts.c @@ -0,0 +1,239 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment + +This file is part of Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Original Source: 1996 - Todd Replogle +Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms +*/ +//------------------------------------------------------------------------- + +#include "duke3d.h" + +//============= +// STATICS +//============= + +int32 numlumps; +static void **lumpcache; +static lumpinfo_t *lumpinfo; // location of each lump on disk +static boolean RTS_Started = false; + +char lumplockbyte[11]; + +/* +============================================================================ + + LUMP BASED ROUTINES + +============================================================================ +*/ + +/* +==================== += += RTS_AddFile += += All files are optional, but at least one file must be found += Files with a .rts extension are wadlink files with multiple lumps += Other files are single lumps with the base filename for the lump name += +==================== +*/ + +void RTS_AddFile (char *filename) + { + wadinfo_t header; + lumpinfo_t *lump_p; + int32 i; + int32 handle, length; + int32 startlump; + filelump_t *fileinfo; + +// +// read the entire file in +// FIXME: shared opens + + handle = SafeOpenRead( filename, filetype_binary ); + + startlump = numlumps; + + // WAD file + printf(" Adding %s.\n",filename); + SafeRead( handle, &header, sizeof( header ) ); + if (strncmp(header.identification,"IWAD",4)) + Error ("RTS file %s doesn't have IWAD id\n",filename); + header.numlumps = IntelLong(header.numlumps); + header.infotableofs = IntelLong(header.infotableofs); + length = header.numlumps*sizeof(filelump_t); + fileinfo = alloca (length); + if (!fileinfo) + Error ("RTS file could not allocate header info on stack"); + lseek (handle, header.infotableofs, SEEK_SET); + SafeRead (handle, fileinfo, length); + numlumps += header.numlumps; + +// +// Fill in lumpinfo +// + SafeRealloc((void **)&lumpinfo,numlumps*sizeof(lumpinfo_t)); + lump_p = &lumpinfo[startlump]; + + for (i=startlump ; ihandle = handle; + lump_p->position = IntelLong(fileinfo->filepos); + lump_p->size = IntelLong(fileinfo->size); + strncpy (lump_p->name, fileinfo->name, 8); + } + } + +/* +==================== += += RTS_Init += += Files with a .rts extension are idlink files with multiple lumps += +==================== +*/ + +void RTS_Init (char *filename) + { + int32 length; + // + // open all the files, load headers, and count lumps + // + numlumps = 0; + lumpinfo = SafeMalloc(5); // will be realloced as lumps are added + + printf("RTS Manager Started.\n"); + if (SafeFileExists(filename)) + RTS_AddFile (filename); + + if (!numlumps) return; + + // + // set up caching + // + length = (numlumps) * sizeof( *lumpcache ); + lumpcache = SafeMalloc(length); + memset(lumpcache,0,length); + RTS_Started = true; + } + + +/* +==================== += += RTS_NumSounds += +==================== +*/ + +int32 RTS_NumSounds (void) + { + return numlumps-1; + } + +/* +==================== += += RTS_SoundLength += += Returns the buffer size needed to load the given lump += +==================== +*/ + +int32 RTS_SoundLength (int32 lump) + { + lump++; + if (lump >= numlumps) + Error ("RTS_SoundLength: %i >= numlumps",lump); + return lumpinfo[lump].size; + } + +/* +==================== += += RTS_GetSoundName += +==================== +*/ + +char * RTS_GetSoundName (int32 i) + { + i++; + if (i>=numlumps) + Error ("RTS_GetSoundName: %i >= numlumps",i); + return &(lumpinfo[i].name[0]); + } + +/* +==================== += += RTS_ReadLump += += Loads the lump into the given buffer, which must be >= RTS_SoundLength() += +==================== +*/ +void RTS_ReadLump (int32 lump, void *dest) + { + lumpinfo_t *l; + + if (lump >= numlumps) + Error ("RTS_ReadLump: %i >= numlumps",lump); + if (lump < 0) + Error ("RTS_ReadLump: %i < 0",lump); + l = lumpinfo+lump; + lseek (l->handle, l->position, SEEK_SET); + SafeRead(l->handle,dest,l->size); + } + +/* +==================== += += RTS_GetSound += +==================== +*/ +void *RTS_GetSound (int32 lump) +{ + lump++; + if (lump >= numlumps) + Error ("RTS_GetSound: %i >= %i\n",lump,numlumps); + + if (lumpcache[lump] == NULL) + { + lumplockbyte[lump] = 200; + allocache((long *)&lumpcache[lump],(long)RTS_SoundLength(lump-1),&lumplockbyte[lump]); + RTS_ReadLump(lump, lumpcache[lump]); + } + else + { + if (lumplockbyte[lump] < 200) + lumplockbyte[lump] = 200; + else + lumplockbyte[lump]++; + } + return lumpcache[lump]; +} + diff --git a/rts.h b/rts.h new file mode 100755 index 0000000..c4a1d3c --- /dev/null +++ b/rts.h @@ -0,0 +1,84 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment + +This file is part of Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Original Source: 1996 - Todd Replogle +Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms +*/ +//------------------------------------------------------------------------- + +//*************************************************************************** +// +// RTS.H +// +//*************************************************************************** + +#ifndef __rts_public__ +#define __rts_public__ + +/* +==================== += += RTS_Init += += Files with a .rts extension are idlink files with multiple lumps += +==================== +*/ + +void RTS_Init (char *filename); +/* +==================== += += RTS_NumSounds += +==================== +*/ + +int32 RTS_NumSounds (void); +/* +==================== += += RTS_SoundLength += += Returns the buffer size needed to load the given lump += +==================== +*/ + +int32 RTS_SoundLength (int32 lump); +/* +==================== += += RTS_GetSoundName += +==================== +*/ + +char * RTS_GetSoundName (int32 i); +/* +==================== += += RTS_GetSound += +==================== +*/ +void *RTS_GetSound (int32 lump); +#endif diff --git a/scriplib.c b/scriplib.c new file mode 100755 index 0000000..259cd65 --- /dev/null +++ b/scriplib.c @@ -0,0 +1,1017 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment + +This file is part of Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Original Source: 1996 - Todd Replogle +Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms +*/ +//------------------------------------------------------------------------- + +#include +#include +#include +#include +#include + +#include "duke3d.h" +#include "scriplib.h" + +//#define DEBUG_SCRIPLIB 1 + +#define MAX_SCRIPTS 5 + +typedef enum { + SCRIPTFLAG_UNKNOWN, + SCRIPTFLAG_CATEGORY, + SCRIPTFLAG_ONESTRING, + SCRIPTFLAG_TWOSTRING, + SCRIPTFLAG_HEX, + SCRIPTFLAG_DECIMAL, + SCRIPTFLAG_FLOAT +} scriptflag_t; + +typedef struct scriptnode_s { + struct scriptnode_s *child; + struct scriptnode_s *sibling; + char *key; + scriptflag_t type; + union { + char *string[2]; + int number; + float floatnumber; + } data; +} scriptnode_t; + +static int script_nexthandle = 0; +static int script_numscriptsopen = 0; + +static scriptnode_t *script_headnode[MAX_SCRIPTS]; + +/* Utility functions */ +static scriptnode_t *SCRIPT_constructnode (void) +{ + scriptnode_t *s; + + s = (scriptnode_t *) malloc (sizeof (scriptnode_t)); + if (s != NULL) + { + s->child = NULL; + s->sibling = NULL; + s->key = NULL; + s->data.string[0] = NULL; + s->data.string[1] = NULL; + s->type = SCRIPTFLAG_UNKNOWN; + } + return s; +} + +static void SCRIPT_freenode (scriptnode_t *node) +{ + assert (node != NULL); + + if (node->type == SCRIPTFLAG_ONESTRING) { + free (node->data.string[0]); + } else if (node->type == SCRIPTFLAG_TWOSTRING) { + free (node->data.string[0]); + free (node->data.string[1]); + } + + free (node->key); + free (node->sibling); + free (node->child); + free (node); +} + +static void SCRIPT_writenode (scriptnode_t *node, FILE *fp) +{ + switch (node->type) + { + case SCRIPTFLAG_UNKNOWN: + return; + break; + case SCRIPTFLAG_CATEGORY: + fprintf (fp, "\n[%s]\n", node->key); + break; + case SCRIPTFLAG_ONESTRING: + fprintf (fp, "%s = \"%s\"\n", node->key, node->data.string[0]); + break; + case SCRIPTFLAG_TWOSTRING: + fprintf (fp, "%s = \"%s\" \"%s\"\n", node->key, node->data.string[0], node->data.string[1]); + break; + case SCRIPTFLAG_HEX: + fprintf (fp, "%s = 0x%X\n", node->key, node->data.number); + break; + case SCRIPTFLAG_DECIMAL: + fprintf (fp, "%s = %d\n", node->key, (unsigned short)node->data.number); + break; + case SCRIPTFLAG_FLOAT: + fprintf (fp, "%s = %ff\n", node->key, node->data.floatnumber); + break; + } +} + +static void SCRIPT_recursivewrite (scriptnode_t *node, FILE *fp) +{ + if (node == NULL) return; + + SCRIPT_writenode (node, fp); + + /* Free dependant nodes first */ + if (node->child) { + SCRIPT_recursivewrite (node->child, fp); + } + + if (node->sibling) { + SCRIPT_recursivewrite (node->sibling, fp); + } +} + +static void SCRIPT_recursivefree (scriptnode_t *node) +{ + assert (node != NULL); + + /* Free dependant nodes first */ + if (node->child) { + SCRIPT_recursivefree (node->child); + node->child = NULL; + } + + if (node->sibling) { + SCRIPT_recursivefree (node->sibling); + node->sibling = NULL; + } + + SCRIPT_freenode (node); + node = NULL; +} + +static void SCRIPT_addsibling (scriptnode_t *node, scriptnode_t *sibling) +{ + assert (node != NULL); + assert (sibling != NULL); + + /* printf ("addsib: %p, %p, %p\n", node, node->sibling, sibling); */ + + if (node->sibling == NULL) { + node->sibling = sibling; + } else { + SCRIPT_addsibling (node->sibling, sibling); + } +} + +static void SCRIPT_addchild (scriptnode_t *parent, scriptnode_t *child) +{ + assert (parent != NULL); + assert (child != NULL); + + if (parent->child == NULL) { + parent->child = child; + } else { + SCRIPT_addsibling (parent->child, child); + } +} + +static char *SCRIPT_copystring (char * s) +{ + char *ret; + + ret = (char *) malloc (strlen (s)+1); + if (ret != NULL) + { + strcpy (ret, s); + } + return ret; +} + +static int SCRIPT_getnexttoken (char *buffer, char* token, int start) +{ + int iterator = start; + + if (buffer[start] == '\0') { + token[0] = '\0'; + return start; + } + + while (iterator < 128 && !isspace (buffer[iterator])) + { + token[iterator-start] = buffer[iterator]; + iterator++; + } + + token[iterator-start] = '\0'; + + /* Trim off any extra whitespace */ + while (iterator < 127 && isspace(buffer[iterator+1])) + iterator++; + + return ++iterator; +} + +/* Fills in a scriptnode with the interpreted contents of a line */ +static void SCRIPT_parseline (char *curline, scriptnode_t *node) +{ + char token[128]; + int i; + + /* Needs to handle 5 cases: */ + /* key = someint */ + /* key = 0xsomehexnum */ + /* key = ~ */ + /* key = "onestring" */ + /* key = "two" "strings" */ + + assert (node != NULL); + assert (curline != NULL); + + i = SCRIPT_getnexttoken (curline, token, 0); + node->key = SCRIPT_copystring (token); + + i = SCRIPT_getnexttoken (curline, token, i); + /* Sanity check... this token should be "=" */ + if (strcmp (token, "=")) { + /* Error state, free the memory allocated */ + SCRIPT_recursivefree (node); + return; + } + + /* This is where the real fun begins... */ + /* we can begin to determine which of the 5 */ + /* possibilities the node is now */ + i = SCRIPT_getnexttoken (curline, token, i); + + if (!strncmp (token, "0x", 2)) { + /* Found a hex digit! */ + node->type = SCRIPTFLAG_HEX; + node->data.number = strtol (token, NULL, 16); + } else if (isdigit (token[0]) || token[0] == '-') { + /* Found a number! */ + node->type = SCRIPTFLAG_DECIMAL; + node->data.number = atoi (token); + } else if (token[strlen(token) - 1] == 'f') { + /* Found a float */ + node->type = SCRIPTFLAG_FLOAT; + node->data.floatnumber = atof(token); + } else if (token[0] == '~') { + /* Found a ... who knows */ + node->type = SCRIPTFLAG_DECIMAL; + node->data.number = -1; + } else if (token[0] == '"') { + char workbuf[128]; + int r; + + /* Found one of possibly two strings */ + strcpy (workbuf, token); + while (token != NULL && workbuf[strlen(workbuf)-1] != '"') + { + i = SCRIPT_getnexttoken (curline, token, i); + strcat (workbuf, " "); + strcat (workbuf, token); + } + r = sscanf(workbuf, "\"%[^\"]\"", workbuf); + if (r == 0) workbuf[0] = '\0'; + + node->type = SCRIPTFLAG_ONESTRING; + node->data.string[0] = SCRIPT_copystring (workbuf); + /* Check for a second string */ + i = SCRIPT_getnexttoken (curline, token, i); + if (token[0] == '"') { + strcpy (workbuf, token); + while (token != NULL && workbuf[strlen(workbuf)-1] != '"') + { + i = SCRIPT_getnexttoken (curline, token, i); + strcat (workbuf, " "); + strcat (workbuf, token); + } + r = sscanf(workbuf, "\"%[^\"]\"", workbuf); + if (r == 0) workbuf[0] = '\0'; + + node->type = SCRIPTFLAG_TWOSTRING; + node->data.string[1] = SCRIPT_copystring (workbuf); + } + } else { + /* Error state! */ + SCRIPT_recursivefree (node); + } +} + +static scriptnode_t *SCRIPT_findinchildren (scriptnode_t *parent, char *s) +{ + scriptnode_t *cur = parent; + + if (cur == NULL) return NULL; + cur = cur->child; + if (cur == NULL) return NULL; + while (cur != NULL) + { + if (!strcmp(cur->key, s)) + break; + cur = cur->sibling; + } + + return cur; +} + +/* +============== += += SCRIPT_Init += +============== +*/ +int32 SCRIPT_Init( char * name ) +{ + STUBBED("Init"); + + return -1; +} + + +/* +============== += += SCRIPT_Free += +============== +*/ +void SCRIPT_Free( int32 scripthandle ) +{ + /* STUBBED("Free"); */ + if (scripthandle == -1) return; + + SCRIPT_recursivefree (script_headnode[scripthandle]); + script_numscriptsopen--; +} + + +/* +============== += += SCRIPT_Parse += +============== +*/ + +int32 SCRIPT_Parse ( char *data, int32 length, char * name ) +{ + STUBBED("Parse"); + + return -1; +} + + +/* +============== += += SCRIPT_Load += +============== +*/ + +int32 SCRIPT_Load ( char * filename ) +{ + FILE *fp; + char curline[128]; + scriptnode_t *headnode = NULL; + scriptnode_t *cur_subsection = NULL; + + if (script_numscriptsopen == MAX_SCRIPTS) return -1; + + /* The main program does not check for any sort of */ + /* error in loading, so each SCRIPT_ function needs */ + /* to check if the handle is -1 before doing anything */ + fp = fopen (filename, "r"); + + if (fp == NULL) return -1; + + /* Start loading the script */ + /* Loads and parse the entire file into a tree */ + script_numscriptsopen++; + + /* script_nexthandle is the current handle until we increment it */ + script_headnode[script_nexthandle] = SCRIPT_constructnode (); + headnode = script_headnode[script_nexthandle]; + + memset (curline, 0, 128); + while (fgets (curline, 128, fp)) + { + /* Skip comments */ + if (curline[0] == ';') continue; + + /* Parse line */ + /* We have two options... it starts with a [, making it */ + /* a new subsection (child of headnode) or it starts with */ + /* a letter, making it a child of a subsection. */ + if (curline[0] == '[') + { + scriptnode_t *node; + int i; + + /* Remove [] manually */ + for (i = 0; i < 127; i++) + curline[i] = curline[i+1]; + for (i = 127; i >= 0; i--) + { + if (curline[i] == ']') { + curline[i] = '\0'; + break; + } else { + curline[i] = '\0'; + } + } + + /* Insert into head */ + node = SCRIPT_constructnode (); + node->type = SCRIPTFLAG_CATEGORY; + node->key = SCRIPT_copystring (curline); + SCRIPT_addchild (headnode, node); + cur_subsection = node; + /* printf ("Working in section \"%s\"\n", node->key); */ + } else if (isalpha (curline[0])) { + scriptnode_t *node; + + /* Ignore if not under a subsection */ + if (cur_subsection == NULL) + continue; + + node = SCRIPT_constructnode (); + + /* TODO: Parse line here */ + SCRIPT_parseline (curline, node); + if (node != NULL) + { + /* printf ("Adding node with key \"%s\"\n", node->key); */ + SCRIPT_addchild (cur_subsection, node); + } + } + memset (curline, 0, 128); + } + + fclose (fp); + + return script_nexthandle++; /* postincrement is important here */ +} + +/* +============== += += SCRIPT_Save += +============== +*/ +void SCRIPT_Save (int32 scripthandle, char * filename) +{ + FILE *fp; + scriptnode_t *head; + + if(scripthandle >= MAX_SCRIPTS || scripthandle < 0) + return; + + fp = fopen (filename, "w"); + if (fp == NULL) return; + + head = script_headnode[scripthandle]; + SCRIPT_recursivewrite (head, fp); + + fclose (fp); + +} + + +/* +============== += += SCRIPT_NumberSections += +============== +*/ + +int32 SCRIPT_NumberSections( int32 scripthandle ) +{ + STUBBED("NumberSections"); + + return -1; +} + +/* +============== += += SCRIPT_Section += +============== +*/ + +char * SCRIPT_Section( int32 scripthandle, int32 which ) +{ + STUBBED("Section"); + + return NULL; +} + +/* +============== += += SCRIPT_NumberEntries += +============== +*/ + +int32 SCRIPT_NumberEntries( int32 scripthandle, char * sectionname ) +{ + scriptnode_t *node = NULL; + int32 entries = 0; + + if(scripthandle >= MAX_SCRIPTS || scripthandle < 0) + return 0; + + node = script_headnode[scripthandle]; + node = SCRIPT_findinchildren(node, sectionname); + if(!node) return 0; + + for(node=node->child; node ; node=node->sibling) + { + ++entries; + } + + return entries; +} + + +/* +============== += += SCRIPT_Entry += +============== +*/ +char * SCRIPT_Entry( int32 scripthandle, char * sectionname, int32 which ) +{ + scriptnode_t *node = NULL; + int32 entrynum = 0; + char* val = NULL; + + if(scripthandle >= MAX_SCRIPTS || scripthandle < 0) + return ""; + + node = script_headnode[scripthandle]; + node = SCRIPT_findinchildren(node,sectionname); + if(!node) return ""; + + for(node=node->child; node ; node=node->sibling, ++entrynum) + { + if(entrynum == which) + { + val = node->key; + break; + } + } + + return val; +} + + +/* +============== += += SCRIPT_GetRaw += +============== +*/ +char * SCRIPT_GetRaw(int32 scripthandle, char * sectionname, char * entryname) +{ + STUBBED("GetRaw"); + + return NULL; +} + +/* +============== += += SCRIPT_GetString += +============== +*/ +void SCRIPT_GetString + ( + int32 scripthandle, + char * sectionname, + char * entryname, + char * dest + ) +{ + scriptnode_t *cur; + + /* STUBBED("GetString"); */ + if (scripthandle == -1) return; + + cur = script_headnode[scripthandle]; + + cur = SCRIPT_findinchildren (cur, sectionname); + cur = SCRIPT_findinchildren (cur, entryname); + + if (cur != NULL && cur->type == SCRIPTFLAG_ONESTRING) + { + strcpy (dest, cur->data.string[0]); +#ifdef DEBUG_SCRIPLIB + printf ("GetString: value for %s:%s is %s\n", sectionname, entryname, dest); +#endif + } +} + +/* +============== += += SCRIPT_GetDoubleString += +============== +*/ +void SCRIPT_GetDoubleString + ( + int32 scripthandle, + char * sectionname, + char * entryname, + char * dest1, + char * dest2 + ) +{ + scriptnode_t *cur; + + /* STUBBED("GetDoubleString"); */ + if (scripthandle == -1) return; + + cur = script_headnode[scripthandle]; + + cur = SCRIPT_findinchildren (cur, sectionname); + cur = SCRIPT_findinchildren (cur, entryname); + + if (cur != NULL && cur->type == SCRIPTFLAG_TWOSTRING) + { + strcpy (dest1, cur->data.string[0]); + strcpy (dest2, cur->data.string[1]); +#ifdef DEBUG_SCRIPLIB + printf ("GetDoubleString: value for %s:%s is %s %s\n", sectionname, entryname, dest1, dest2); +#endif + } +} + +/* +============== += += SCRIPT_GetNumber += +============== +*/ +boolean SCRIPT_GetNumber + ( + int32 scripthandle, + char * sectionname, + char * entryname, + int32 * number + ) +{ + scriptnode_t *cur; + + if (scripthandle == -1) return false; + + cur = script_headnode[scripthandle]; + + cur = SCRIPT_findinchildren (cur, sectionname); + cur = SCRIPT_findinchildren (cur, entryname); + + if (cur != NULL && cur->type == SCRIPTFLAG_DECIMAL) + { + *number = cur->data.number; +#ifdef DEBUG_SCRIPLIB + printf ("GetNumber: value for %s:%s is %ld\n", sectionname, entryname, *number); +#endif + } + + return (cur != NULL) ? true : false; +} + +/* +============== += += SCRIPT_GetBoolean += +============== +*/ +void SCRIPT_GetBoolean + ( + int32 scripthandle, + char * sectionname, + char * entryname, + boolean * bool + ) +{ + STUBBED("GetBoolean"); +} + +/* +============== += += SCRIPT_GetFloat += +============== +*/ +boolean SCRIPT_GetFloat + ( + int32 scripthandle, + char * sectionname, + char * entryname, + float * floatnumber + ) +{ + scriptnode_t *cur; + + if (scripthandle == -1) return false; + + cur = script_headnode[scripthandle]; + + cur = SCRIPT_findinchildren (cur, sectionname); + cur = SCRIPT_findinchildren (cur, entryname); + + if (cur != NULL && cur->type == SCRIPTFLAG_FLOAT) + { + *floatnumber = cur->data.floatnumber; +#ifdef DEBUG_SCRIPLIB + printf ("GetFloat: value for %s:%s is %f\n", sectionname, entryname, *floatnumber); +#endif + } + + return (cur != NULL) ? true : false; +} + +/* ++============== ++= += SCRIPT_GetDouble += +============== +*/ + +void SCRIPT_GetDouble + ( + int32 scripthandle, + char * sectionname, + char * entryname, + double * number + ) +{ + STUBBED("GetDouble"); +} + + + +/* +============== += += SCRIPT_PutComment += +============== +*/ +void SCRIPT_PutComment( int32 scripthandle, char * sectionname, char * comment ) +{ + STUBBED("PutComment"); +} + +/* +============== += += SCRIPT_PutEOL += +============== +*/ +void SCRIPT_PutEOL( int32 scripthandle, char * sectionname ) +{ + STUBBED("PutEOL"); +} + +/* +============== += += SCRIPT_PutMultiComment += +============== +*/ +void SCRIPT_PutMultiComment + ( + int32 scripthandle, + char * sectionname, + char * comment, + ... + ) +{ + STUBBED("PutMultiComment"); +} + +/* +============== += += SCRIPT_PutSection += +============== +*/ +void SCRIPT_PutSection( int32 scripthandle, char * sectionname ) +{ + STUBBED("PutSection"); +} + +/* +============== += += SCRIPT_PutRaw += +============== +*/ +void SCRIPT_PutRaw + ( + int32 scripthandle, + char * sectionname, + char * entryname, + char * raw + ) +{ + STUBBED("PutRaw"); +} + +/* +============== += += SCRIPT_PutString += +============== +*/ +void SCRIPT_PutString + ( + int32 scripthandle, + char * sectionname, + char * entryname, + char * string + ) +{ + scriptnode_t *head; + scriptnode_t *section; + scriptnode_t *node; + + if(scripthandle >= MAX_SCRIPTS || scripthandle < 0) + return; + + head = script_headnode[scripthandle]; + + /* We're screwed if there's no head */ + if (head == NULL) return; + + section = SCRIPT_findinchildren (head, sectionname); + if (section == NULL) + { + /* Add the section if it does not exist */ + section = SCRIPT_constructnode (); + section->type = SCRIPTFLAG_CATEGORY; + section->key = SCRIPT_copystring (sectionname); + SCRIPT_addchild (head, section); + } + + node = SCRIPT_findinchildren (section, entryname); + if (node == NULL) + { + /* Add the section if it does not exist */ + node = SCRIPT_constructnode (); + node->type = SCRIPTFLAG_ONESTRING; + node->key = SCRIPT_copystring (entryname); + SCRIPT_addchild (section, node); + } else { + free (node->data.string[0]); + } + + node->data.string[0] = SCRIPT_copystring (string); +} + +/* +============== += += SCRIPT_PutDoubleString += +============== +*/ +void SCRIPT_PutDoubleString + ( + int32 scripthandle, + char * sectionname, + char * entryname, + char * string1, + char * string2 + ) +{ + STUBBED("PutDoubleString"); +} + +/* +============== += += SCRIPT_PutNumber += +============== +*/ +void SCRIPT_PutNumber + ( + int32 scripthandle, + char * sectionname, + char * entryname, + int32 number, + boolean hexadecimal, + boolean defaultvalue + ) +{ + /* DDOI - I don't know what "defaultvalue" is for so it's ignored */ + scriptnode_t *head; + scriptnode_t *section; + scriptnode_t *node; + + if(scripthandle >= MAX_SCRIPTS || scripthandle < 0) + return; + + head = script_headnode[scripthandle]; + + /* We're screwed if there's no head */ + if (head == NULL) return; + + section = SCRIPT_findinchildren (head, sectionname); + if (section == NULL) + { + /* Add the section if it does not exist */ + section = SCRIPT_constructnode (); + section->type = SCRIPTFLAG_CATEGORY; + section->key = SCRIPT_copystring (sectionname); + SCRIPT_addchild (head, section); + } + + node = SCRIPT_findinchildren (section, entryname); + if (node == NULL) + { + /* Add the section if it does not exist */ + node = SCRIPT_constructnode (); + node->key = SCRIPT_copystring (entryname); + SCRIPT_addchild (section, node); + } + + if (hexadecimal) + node->type = SCRIPTFLAG_HEX; + else + node->type = SCRIPTFLAG_DECIMAL; + node->data.number = number; +} + +/* +============== += += SCRIPT_PutBoolean += +============== +*/ +void SCRIPT_PutBoolean + ( + int32 scripthandle, + char * sectionname, + char * entryname, + boolean bool + ) +{ + STUBBED("PutBoolean"); +} + +/* +============== += += SCRIPT_PutDouble += +============== +*/ + +void SCRIPT_PutDouble + ( + int32 scripthandle, + char * sectionname, + char * entryname, + double number, + boolean defaultvalue + ) +{ + STUBBED("PutDouble"); +} diff --git a/scriplib.h b/scriplib.h new file mode 100755 index 0000000..fb7fc72 --- /dev/null +++ b/scriplib.h @@ -0,0 +1,371 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment + +This file is part of Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Original Source: 1996 - Todd Replogle +Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms +*/ +//------------------------------------------------------------------------- + +// scriplib.h + +#ifndef _scriplib_public +#define _scriplib_public +#ifdef __cplusplus +extern "C" { +#endif + +/* +============== += += SCRIPT_Init += +============== +*/ +int32 SCRIPT_Init( char * name ); + + +/* +============== += += SCRIPT_Free += +============== +*/ +void SCRIPT_Free( int32 scripthandle ); + +/* +============== += += SCRIPT_Parse += +============== +*/ + +int32 SCRIPT_Parse ( char *data, int32 length, char * name ); + + +/* +============== += += SCRIPT_Load += +============== +*/ + +int32 SCRIPT_Load ( char * filename ); + +/* +============== += += SCRIPT_Save += +============== +*/ +void SCRIPT_Save (int32 scripthandle, char * filename); + + +/* +============== += += SCRIPT_NumberSections += +============== +*/ + +int32 SCRIPT_NumberSections( int32 scripthandle ); + +/* +============== += += SCRIPT_Section += +============== +*/ + +char * SCRIPT_Section( int32 scripthandle, int32 which ); + +/* +============== += += SCRIPT_NumberEntries += +============== +*/ + +int32 SCRIPT_NumberEntries( int32 scripthandle, char * sectionname ); + +/* +============== += += SCRIPT_Entry += +============== +*/ + +char * SCRIPT_Entry( int32 scripthandle, char * sectionname, int32 which ); + + +/* +============== += += SCRIPT_GetRaw += +============== +*/ +char * SCRIPT_GetRaw(int32 scripthandle, char * sectionname, char * entryname); + +/* +============== += += SCRIPT_GetString += +============== +*/ +void SCRIPT_GetString + ( + int32 scripthandle, + char * sectionname, + char * entryname, + char * dest + ); + +/* +============== += += SCRIPT_GetDoubleString += +============== +*/ +void SCRIPT_GetDoubleString + ( + int32 scripthandle, + char * sectionname, + char * entryname, + char * dest1, + char * dest2 + ); + +/* +============== += += SCRIPT_GetNumber += +============== +*/ +boolean SCRIPT_GetNumber + ( + int32 scripthandle, + char * sectionname, + char * entryname, + int32 * number + ); + +/* +============== += += SCRIPT_GetBoolean += +============== +*/ +void SCRIPT_GetBoolean + ( + int32 scripthandle, + char * sectionname, + char * entryname, + boolean * bool + ); + +/* +============== += += SCRIPT_GetFloat += +============== +*/ + +boolean SCRIPT_GetFloat + ( + int32 scripthandle, + char * sectionname, + char * entryname, + float * floatnumber + ); + +/* ++============== ++= += SCRIPT_GetDouble += +============== +*/ + +void SCRIPT_GetDouble + ( + int32 scripthandle, + char * sectionname, + char * entryname, + double * number + ); + + + +/* +============== += += SCRIPT_PutComment += +============== +*/ +void SCRIPT_PutComment( int32 scripthandle, char * sectionname, char * comment ); + +/* +============== += += SCRIPT_PutEOL += +============== +*/ +void SCRIPT_PutEOL( int32 scripthandle, char * sectionname ); + +/* +============== += += SCRIPT_PutMultiComment += +============== +*/ +void SCRIPT_PutMultiComment + ( + int32 scripthandle, + char * sectionname, + char * comment, + ... + ); + +/* +============== += += SCRIPT_PutSection += +============== +*/ +void SCRIPT_PutSection( int32 scripthandle, char * sectionname ); + +/* +============== += += SCRIPT_PutRaw += +============== +*/ +void SCRIPT_PutRaw + ( + int32 scripthandle, + char * sectionname, + char * entryname, + char * raw + ); + +/* +============== += += SCRIPT_PutString += +============== +*/ +void SCRIPT_PutString + ( + int32 scripthandle, + char * sectionname, + char * entryname, + char * string + ); + +/* +============== += += SCRIPT_PutDoubleString += +============== +*/ +void SCRIPT_PutDoubleString + ( + int32 scripthandle, + char * sectionname, + char * entryname, + char * string1, + char * string2 + ); + +/* +============== += += SCRIPT_PutNumber += +============== +*/ +void SCRIPT_PutNumber + ( + int32 scripthandle, + char * sectionname, + char * entryname, + int32 number, + boolean hexadecimal, + boolean defaultvalue + ); + +/* +============== += += SCRIPT_PutBoolean += +============== +*/ +void SCRIPT_PutBoolean + ( + int32 scripthandle, + char * sectionname, + char * entryname, + boolean bool + ); + +/* +============== += += SCRIPT_PutDouble += +============== +*/ + +void SCRIPT_PutDouble + ( + int32 scripthandle, + char * sectionname, + char * entryname, + double number, + boolean defaultvalue + ); + + +#ifdef __cplusplus +}; +#endif +#endif diff --git a/sector.c b/sector.c new file mode 100755 index 0000000..b006824 --- /dev/null +++ b/sector.c @@ -0,0 +1,3224 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment + +This file is part of Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Original Source: 1996 - Todd Replogle +Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms +*/ +//------------------------------------------------------------------------- + +#include "duke3d.h" + +// PRIMITIVE + + +char haltsoundhack; +short callsound(short sn,short whatsprite) +{ + short i; + + if(haltsoundhack) + { + haltsoundhack = 0; + return -1; + } + + i = headspritesect[sn]; + while(i >= 0) + { + if( PN == MUSICANDSFX && SLT < 1000 ) + { + if(whatsprite == -1) whatsprite = i; + + if(T1 == 0) + { + if( (soundm[SLT]&16) == 0) + { + if(SLT) + { + spritesound(SLT,whatsprite); + if(SHT && SLT != SHT && SHT < NUM_SOUNDS) + stopsound(SHT); + } + + if( (sector[SECT].lotag&0xff) != 22) + T1 = 1; + } + } + else if(SHT < NUM_SOUNDS) + { + if(SHT) spritesound(SHT,whatsprite); + if( (soundm[SLT]&1) || ( SHT && SHT != SLT ) ) + stopsound(SLT); + T1 = 0; + } + return SLT; + } + i = nextspritesect[i]; + } + return -1; +} + + +short check_activator_motion( short lotag ) +{ + short i, j; + spritetype *s; + + i = headspritestat[8]; + while ( i >= 0 ) + { + if ( sprite[i].lotag == lotag ) + { + s = &sprite[i]; + + for ( j = animatecnt-1; j >= 0; j-- ) + if ( s->sectnum == animatesect[j] ) + return( 1 ); + + j = headspritestat[3]; + while ( j >= 0 ) + { + if(s->sectnum == sprite[j].sectnum) + switch(sprite[j].lotag) + { + case 11: + case 30: + if ( hittype[j].temp_data[4] ) + return( 1 ); + break; + case 20: + case 31: + case 32: + case 18: + if ( hittype[j].temp_data[0] ) + return( 1 ); + break; + } + + j = nextspritestat[j]; + } + } + i = nextspritestat[i]; + } + return( 0 ); +} + +char isadoorwall(short dapic) +{ + switch(dapic) + { + case DOORTILE1: + case DOORTILE2: + case DOORTILE3: + case DOORTILE4: + case DOORTILE5: + case DOORTILE6: + case DOORTILE7: + case DOORTILE8: + case DOORTILE9: + case DOORTILE10: + case DOORTILE11: + case DOORTILE12: + case DOORTILE14: + case DOORTILE15: + case DOORTILE16: + case DOORTILE17: + case DOORTILE18: + case DOORTILE19: + case DOORTILE20: + case DOORTILE21: + case DOORTILE22: + case DOORTILE23: + return 1; + } + return 0; +} + + +char isanunderoperator(short lotag) +{ + switch(lotag&0xff) + { + case 15: + case 16: + case 17: + case 18: + case 19: + case 22: + case 26: + return 1; + } + return 0; +} + +char isanearoperator(short lotag) +{ + switch(lotag&0xff) + { + case 9: + case 15: + case 16: + case 17: + case 18: + case 19: + case 20: + case 21: + case 22: + case 23: + case 25: + case 26: + case 29://Toothed door + return 1; + } + return 0; +} + +short checkcursectnums(short sect) +{ + short i; + for(i=connecthead;i>=0;i=connectpoint2[i]) + if( sprite[ps[i].i].sectnum == sect ) return i; + return -1; +} + +long ldist(spritetype *s1,spritetype *s2) +{ + long vx,vy; + vx = s1->x - s2->x; + vy = s1->y - s2->y; + return(FindDistance2D(vx,vy) + 1); +} + +long dist(spritetype *s1,spritetype *s2) +{ + long vx,vy,vz; + vx = s1->x - s2->x; + vy = s1->y - s2->y; + vz = s1->z - s2->z; + return(FindDistance3D(vx,vy,vz>>4)); +} + +short findplayer(spritetype *s,long *d) +{ + short j, closest_player; + long x, closest; + + if(ud.multimode < 2) + { + *d = klabs(ps[myconnectindex].oposx-s->x) + klabs(ps[myconnectindex].oposy-s->y) + ((klabs(ps[myconnectindex].oposz-s->z+(28<<8)))>>4); + return myconnectindex; + } + + closest = 0x7fffffff; + closest_player = 0; + + for(j=connecthead;j>=0;j=connectpoint2[j]) + { + x = klabs(ps[j].oposx-s->x) + klabs(ps[j].oposy-s->y) + ((klabs(ps[j].oposz-s->z+(28<<8)))>>4); + if( x < closest && sprite[ps[j].i].extra > 0 ) + { + closest_player = j; + closest = x; + } + } + + *d = closest; + return closest_player; +} + +short findotherplayer(short p,long *d) +{ + short j, closest_player; + long x, closest; + + closest = 0x7fffffff; + closest_player = p; + + for(j=connecthead;j>=0;j=connectpoint2[j]) + if(p != j && sprite[ps[j].i].extra > 0) + { + x = klabs(ps[j].oposx-ps[p].posx) + klabs(ps[j].oposy-ps[p].posy) + (klabs(ps[j].oposz-ps[p].posz)>>4); + + if( x < closest ) + { + closest_player = j; + closest = x; + } + } + + *d = closest; + return closest_player; +} + + + +void doanimations(void) +{ + long i, j, a, p, v, dasect; + + for(i=animatecnt-1;i>=0;i--) + { + a = *animateptr[i]; + v = animatevel[i]*TICSPERFRAME; + dasect = animatesect[i]; + + if (a == animategoal[i]) + { + stopinterpolation(animateptr[i]); + + animatecnt--; + animateptr[i] = animateptr[animatecnt]; + animategoal[i] = animategoal[animatecnt]; + animatevel[i] = animatevel[animatecnt]; + animatesect[i] = animatesect[animatecnt]; + if( sector[animatesect[i]].lotag == 18 || sector[animatesect[i]].lotag == 19 ) + if(animateptr[i] == §or[animatesect[i]].ceilingz) + continue; + + if( (sector[dasect].lotag&0xff) != 22 ) + callsound(dasect,-1); + + continue; + } + + if (v > 0) { a = min(a+v,animategoal[i]); } + else { a = max(a+v,animategoal[i]); } + + if( animateptr[i] == §or[animatesect[i]].floorz) + { + for(p=connecthead;p>=0;p=connectpoint2[p]) + if (ps[p].cursectnum == dasect) + if ((sector[dasect].floorz-ps[p].posz) < (64<<8)) + if (sprite[ps[p].i].owner >= 0) + { + ps[p].posz += v; + ps[p].poszv = 0; + if (p == myconnectindex) + { + myz += v; + myzvel = 0; + myzbak[((movefifoplc-1)&(MOVEFIFOSIZ-1))] = ps[p].posz; + } + } + + for(j=headspritesect[dasect];j>=0;j=nextspritesect[j]) + if (sprite[j].statnum != 3) + { + hittype[j].bposz = sprite[j].z; + sprite[j].z += v; + hittype[j].floorz = sector[dasect].floorz+v; + } + } + + *animateptr[i] = a; + } +} + +long getanimationgoal(long *animptr) +{ + long i, j; + + j = -1; + for(i=animatecnt-1;i>=0;i--) + if (animptr == (long *)animateptr[i]) + { + j = i; + break; + } + return(j); +} + +static long setanimation(short animsect,long *animptr, long thegoal, long thevel) +{ + long i, j; + + if (animatecnt >= MAXANIMATES-1) + return(-1); + + j = animatecnt; + for(i=0;i= *animptr) + animatevel[j] = thevel; + else + animatevel[j] = -thevel; + + if (j == animatecnt) animatecnt++; + + setinterpolation(animptr); + + return(j); +} + + + + +void animatecamsprite(void) +{ + short i; + + if(camsprite <= 0) return; + + i = camsprite; + + if(T1 >= 11) + { + T1 = 0; + + if(ps[screenpeek].newowner >= 0) + OW = ps[screenpeek].newowner; + + else if(OW >= 0 && dist(&sprite[ps[screenpeek].i],&sprite[i]) < 2048) + xyzmirror(OW,PN); + } + else T1++; +} + +void animatewalls(void) +{ + long i, j, p, t; + + for(p=0;p < numanimwalls ;p++) +// for(p=numanimwalls-1;p>=0;p--) + { + i = animwall[p].wallnum; + j = wall[i].picnum; + + switch(j) + { + case SCREENBREAK1: + case SCREENBREAK2: + case SCREENBREAK3: + case SCREENBREAK4: + case SCREENBREAK5: + + case SCREENBREAK9: + case SCREENBREAK10: + case SCREENBREAK11: + case SCREENBREAK12: + case SCREENBREAK13: + case SCREENBREAK14: + case SCREENBREAK15: + case SCREENBREAK16: + case SCREENBREAK17: + case SCREENBREAK18: + case SCREENBREAK19: + + if( (TRAND&255) < 16) + { + animwall[p].tag = wall[i].picnum; + wall[i].picnum = SCREENBREAK6; + } + + continue; + + case SCREENBREAK6: + case SCREENBREAK7: + case SCREENBREAK8: + + if(animwall[p].tag >= 0 && wall[i].extra != FEMPIC2 && wall[i].extra != FEMPIC3 ) + wall[i].picnum = animwall[p].tag; + else + { + wall[i].picnum++; + if(wall[i].picnum == (SCREENBREAK6+3) ) + wall[i].picnum = SCREENBREAK6; + } + continue; + + } + + if(wall[i].cstat&16) + switch(wall[i].overpicnum) + { + case W_FORCEFIELD: + case W_FORCEFIELD+1: + case W_FORCEFIELD+2: + + t = animwall[p].tag; + + if(wall[i].cstat&254) + { + wall[i].xpanning -= t>>10; // sintable[(t+512)&2047]>>12; + wall[i].ypanning -= t>>10; // sintable[t&2047]>>12; + + if(wall[i].extra == 1) + { + wall[i].extra = 0; + animwall[p].tag = 0; + } + else + animwall[p].tag+=128; + + if( animwall[p].tag < (128<<4) ) + { + if( animwall[p].tag&128 ) + wall[i].overpicnum = W_FORCEFIELD; + else wall[i].overpicnum = W_FORCEFIELD+1; + } + else + { + if( (TRAND&255) < 32 ) + animwall[p].tag = 128<<(TRAND&3); + else wall[i].overpicnum = W_FORCEFIELD+1; + } + } + + break; + } + } +} + +char activatewarpelevators(short s,short d) //Parm = sectoreffectornum +{ + short i, sn; + + sn = sprite[s].sectnum; + + // See if the sector exists + + i = headspritestat[3]; + while(i >= 0) + { + if( SLT == 17 ) + if( SHT == sprite[s].hitag ) + if( (klabs(sector[sn].floorz-hittype[s].temp_data[2]) > SP) || + (sector[SECT].hitag == (sector[sn].hitag-d) ) ) + break; + i = nextspritestat[i]; + } + + if(i==-1) + { + d = 0; + return 1; // No find + } + else + { + if(d == 0) + spritesound(ELEVATOR_OFF,s); + else spritesound(ELEVATOR_ON,s); + } + + + i = headspritestat[3]; + while(i >= 0) + { + if( SLT == 17 ) + if( SHT == sprite[s].hitag ) + { + T1 = d; + T2 = d; //Make all check warp + } + i = nextspritestat[i]; + } + return 0; +} + + + +void operatesectors(short sn,short ii) +{ + long j=0l, l=0l, q=0l, startwall=0l, endwall=0l; + short i=0; + char sect_error; + sectortype *sptr; + + sect_error = 0; + sptr = §or[sn]; + + switch(sptr->lotag&(0xffff-49152)) + { + + case 30: + j = sector[sn].hitag; + if( hittype[j].tempang == 0 || + hittype[j].tempang == 256) + callsound(sn,ii); + if(sprite[j].extra == 1) + sprite[j].extra = 3; + else sprite[j].extra = 1; + break; + + case 31: + + j = sector[sn].hitag; + if(hittype[j].temp_data[4] == 0) + hittype[j].temp_data[4] = 1; + + callsound(sn,ii); + break; + + case 26: //The split doors + i = getanimationgoal(&sptr->ceilingz); + if(i == -1) //if the door has stopped + { + haltsoundhack = 1; + sptr->lotag &= 0xff00; + sptr->lotag |= 22; + operatesectors(sn,ii); + sptr->lotag &= 0xff00; + sptr->lotag |= 9; + operatesectors(sn,ii); + sptr->lotag &= 0xff00; + sptr->lotag |= 26; + } + return; + + case 9: + { + long dax,day,dax2,day2,sp; + long wallfind[2]; + + startwall = sptr->wallptr; + endwall = startwall+sptr->wallnum-1; + + sp = sptr->extra>>4; + + //first find center point by averaging all points + dax = 0L, day = 0L; + for(i=startwall;i<=endwall;i++) + { + dax += wall[i].x; + day += wall[i].y; + } + dax /= (endwall-startwall+1); + day /= (endwall-startwall+1); + + //find any points with either same x or same y coordinate + // as center (dax, day) - should be 2 points found. + wallfind[0] = -1; + wallfind[1] = -1; + for(i=startwall;i<=endwall;i++) + if ((wall[i].x == dax) || (wall[i].y == day)) + { + if (wallfind[0] == -1) + wallfind[0] = i; + else wallfind[1] = i; + } + + for(j=0;j<2;j++) + { + if ((wall[wallfind[j]].x == dax) && (wall[wallfind[j]].y == day)) + { + //find what direction door should open by averaging the + // 2 neighboring points of wallfind[0] & wallfind[1]. + i = wallfind[j]-1; if (i < startwall) i = endwall; + dax2 = ((wall[i].x+wall[wall[wallfind[j]].point2].x)>>1)-wall[wallfind[j]].x; + day2 = ((wall[i].y+wall[wall[wallfind[j]].point2].y)>>1)-wall[wallfind[j]].y; + if (dax2 != 0) + { + dax2 = wall[wall[wall[wallfind[j]].point2].point2].x; + dax2 -= wall[wall[wallfind[j]].point2].x; + setanimation(sn,&wall[wallfind[j]].x,wall[wallfind[j]].x+dax2,sp); + setanimation(sn,&wall[i].x,wall[i].x+dax2,sp); + setanimation(sn,&wall[wall[wallfind[j]].point2].x,wall[wall[wallfind[j]].point2].x+dax2,sp); + callsound(sn,ii); + } + else if (day2 != 0) + { + day2 = wall[wall[wall[wallfind[j]].point2].point2].y; + day2 -= wall[wall[wallfind[j]].point2].y; + setanimation(sn,&wall[wallfind[j]].y,wall[wallfind[j]].y+day2,sp); + setanimation(sn,&wall[i].y,wall[i].y+day2,sp); + setanimation(sn,&wall[wall[wallfind[j]].point2].y,wall[wall[wallfind[j]].point2].y+day2,sp); + callsound(sn,ii); + } + } + else + { + i = wallfind[j]-1; if (i < startwall) i = endwall; + dax2 = ((wall[i].x+wall[wall[wallfind[j]].point2].x)>>1)-wall[wallfind[j]].x; + day2 = ((wall[i].y+wall[wall[wallfind[j]].point2].y)>>1)-wall[wallfind[j]].y; + if (dax2 != 0) + { + setanimation(sn,&wall[wallfind[j]].x,dax,sp); + setanimation(sn,&wall[i].x,dax+dax2,sp); + setanimation(sn,&wall[wall[wallfind[j]].point2].x,dax+dax2,sp); + callsound(sn,ii); + } + else if (day2 != 0) + { + setanimation(sn,&wall[wallfind[j]].y,day,sp); + setanimation(sn,&wall[i].y,day+day2,sp); + setanimation(sn,&wall[wall[wallfind[j]].point2].y,day+day2,sp); + callsound(sn,ii); + } + } + } + + } + return; + + case 15://Warping elevators + + if(sprite[ii].picnum != APLAYER) return; +// if(ps[sprite[ii].yvel].select_dir == 1) return; + + i = headspritesect[sn]; + while(i >= 0) + { + if(PN==SECTOREFFECTOR && SLT == 17 ) break; + i = nextspritesect[i]; + } + + if(sprite[ii].sectnum == sn) + { + if( activatewarpelevators(i,-1) ) + activatewarpelevators(i,1); + else if( activatewarpelevators(i,1) ) + activatewarpelevators(i,-1); + return; + } + else + { + if(sptr->floorz > SZ) + activatewarpelevators(i,-1); + else + activatewarpelevators(i,1); + } + + return; + + case 16: + case 17: + + i = getanimationgoal(&sptr->floorz); + + if(i == -1) + { + i = nextsectorneighborz(sn,sptr->floorz,1,1); + if( i == -1 ) + { + i = nextsectorneighborz(sn,sptr->floorz,1,-1); + if( i == -1 ) return; + j = sector[i].floorz; + setanimation(sn,&sptr->floorz,j,sptr->extra); + } + else + { + j = sector[i].floorz; + setanimation(sn,&sptr->floorz,j,sptr->extra); + } + callsound(sn,ii); + } + + return; + + case 18: + case 19: + + i = getanimationgoal(&sptr->floorz); + + if(i==-1) + { + i = nextsectorneighborz(sn,sptr->floorz,1,-1); + if(i==-1) i = nextsectorneighborz(sn,sptr->floorz,1,1); + if(i==-1) return; + j = sector[i].floorz; + q = sptr->extra; + l = sptr->ceilingz-sptr->floorz; + setanimation(sn,&sptr->floorz,j,q); + setanimation(sn,&sptr->ceilingz,j+l,q); + callsound(sn,ii); + } + return; + + case 29: + + if(sptr->lotag&0x8000) + j = sector[nextsectorneighborz(sn,sptr->ceilingz,1,1)].floorz; + else + j = sector[nextsectorneighborz(sn,sptr->ceilingz,-1,-1)].ceilingz; + + i = headspritestat[3]; //Effectors + while(i >= 0) + { + if( (SLT == 22) && + (SHT == sptr->hitag) ) + { + sector[SECT].extra = -sector[SECT].extra; + + T1 = sn; + T2 = 1; + } + i = nextspritestat[i]; + } + + sptr->lotag ^= 0x8000; + + setanimation(sn,&sptr->ceilingz,j,sptr->extra); + + callsound(sn,ii); + + return; + + case 20: + + REDODOOR: + + if(sptr->lotag&0x8000) + { + i = headspritesect[sn]; + while(i >= 0) + { + if(sprite[i].statnum == 3 && SLT==9) + { + j = SZ; + break; + } + i = nextspritesect[i]; + } + if(i==-1) + j = sptr->floorz; + } + else + { + j = nextsectorneighborz(sn,sptr->ceilingz,-1,-1); + + if(j >= 0) j = sector[j].ceilingz; + else + { + sptr->lotag |= 32768; + goto REDODOOR; + } + } + + sptr->lotag ^= 0x8000; + + setanimation(sn,&sptr->ceilingz,j,sptr->extra); + callsound(sn,ii); + + return; + + case 21: + i = getanimationgoal(&sptr->floorz); + if (i >= 0) + { + if (animategoal[sn] == sptr->ceilingz) + animategoal[i] = sector[nextsectorneighborz(sn,sptr->ceilingz,1,1)].floorz; + else animategoal[i] = sptr->ceilingz; + j = animategoal[i]; + } + else + { + if (sptr->ceilingz == sptr->floorz) + j = sector[nextsectorneighborz(sn,sptr->ceilingz,1,1)].floorz; + else j = sptr->ceilingz; + + sptr->lotag ^= 0x8000; + + if(setanimation(sn,&sptr->floorz,j,sptr->extra) >= 0) + callsound(sn,ii); + } + return; + + case 22: + + // REDODOOR22: + + if ( (sptr->lotag&0x8000) ) + { + q = (sptr->ceilingz+sptr->floorz)>>1; + j = setanimation(sn,&sptr->floorz,q,sptr->extra); + j = setanimation(sn,&sptr->ceilingz,q,sptr->extra); + } + else + { + q = sector[nextsectorneighborz(sn,sptr->floorz,1,1)].floorz; + j = setanimation(sn,&sptr->floorz,q,sptr->extra); + q = sector[nextsectorneighborz(sn,sptr->ceilingz,-1,-1)].ceilingz; + j = setanimation(sn,&sptr->ceilingz,q,sptr->extra); + } + + sptr->lotag ^= 0x8000; + + callsound(sn,ii); + + return; + + case 23: //Swingdoor + + j = -1; + q = 0; + + i = headspritestat[3]; + while(i >= 0) + { + if( SLT == 11 && SECT == sn && !T5) + { + j = i; + break; + } + i = nextspritestat[i]; + } + + l = sector[SECT].lotag&0x8000; + + if(j >= 0) + { + i = headspritestat[3]; + while(i >= 0) + { + if( l == (sector[SECT].lotag&0x8000) && SLT == 11 && sprite[j].hitag == SHT && !T5 ) + { + if(sector[SECT].lotag&0x8000) sector[SECT].lotag &= 0x7fff; + else sector[SECT].lotag |= 0x8000; + T5 = 1; + T4 = -T4; + if(q == 0) + { + callsound(sn,i); + q = 1; + } + } + i = nextspritestat[i]; + } + } + return; + + case 25: //Subway type sliding doors + + j = headspritestat[3]; + while(j >= 0)//Find the sprite + { + if( (sprite[j].lotag) == 15 && sprite[j].sectnum == sn ) + break; //Found the sectoreffector. + j = nextspritestat[j]; + } + + if(j < 0) + return; + + i = headspritestat[3]; + while(i >= 0) + { + if( SHT==sprite[j].hitag ) + { + if( SLT == 15 ) + { + sector[SECT].lotag ^= 0x8000; // Toggle the open or close + SA += 1024; + if(T5) callsound(SECT,i); + callsound(SECT,i); + if(sector[SECT].lotag&0x8000) T5 = 1; + else T5 = 2; + } + } + i = nextspritestat[i]; + } + return; + + case 27: //Extended bridge + + j = headspritestat[3]; + while(j >= 0) + { + if( (sprite[j].lotag&0xff)==20 && sprite[j].sectnum == sn) //Bridge + { + + sector[sn].lotag ^= 0x8000; + if(sector[sn].lotag&0x8000) //OPENING + hittype[j].temp_data[0] = 1; + else hittype[j].temp_data[0] = 2; + callsound(sn,ii); + break; + } + j = nextspritestat[j]; + } + return; + + + case 28: + //activate the rest of them + + j = headspritesect[sn]; + while(j >= 0) + { + if(sprite[j].statnum==3 && (sprite[j].lotag&0xff)==21) + break; //Found it + j = nextspritesect[j]; + } + + j = sprite[j].hitag; + + l = headspritestat[3]; + while(l >= 0) + { + if( (sprite[l].lotag&0xff)==21 && !hittype[l].temp_data[0] && + (sprite[l].hitag) == j ) + hittype[l].temp_data[0] = 1; + l = nextspritestat[l]; + } + callsound(sn,ii); + + return; + } +} + + + +void operaterespawns(short low) +{ + short i, j, nexti; + + i = headspritestat[11]; + while(i >= 0) + { + nexti = nextspritestat[i]; + if(SLT == low) switch(PN) + { + case RESPAWN: + if( badguypic(SHT) && ud.monsters_off ) break; + + j = spawn(i,TRANSPORTERSTAR); + sprite[j].z -= (32<<8); + + sprite[i].extra = 66-12; // Just a way to killit + break; + } + i = nexti; + } +} + +void operateactivators(short low,short snum) +{ + short i, j, k, *p, nexti; + walltype *wal; + + for(i=numcyclers-1;i>=0;i--) + { + p = &cyclers[i][0]; + + if(p[4] == low) + { + p[5] = !p[5]; + + sector[p[0]].floorshade = sector[p[0]].ceilingshade = p[3]; + wal = &wall[sector[p[0]].wallptr]; + for(j=sector[p[0]].wallnum;j > 0;j--,wal++) + wal->shade = p[3]; + } + } + + i = headspritestat[8]; + k = -1; + while(i >= 0) + { + if(sprite[i].lotag == low) + { + if( sprite[i].picnum == ACTIVATORLOCKED ) + { + if(sector[SECT].lotag&16384) + sector[SECT].lotag &= 65535-16384; + else + sector[SECT].lotag |= 16384; + + if(snum >= 0) + { + if(sector[SECT].lotag&16384) + FTA(4,&ps[snum]); + else FTA(8,&ps[snum]); + } + } + else + { + switch(SHT) + { + case 0: + break; + case 1: + if(sector[SECT].floorz != sector[SECT].ceilingz) + { + i = nextspritestat[i]; + continue; + } + break; + case 2: + if(sector[SECT].floorz == sector[SECT].ceilingz) + { + i = nextspritestat[i]; + continue; + } + break; + } + + if( sector[sprite[i].sectnum].lotag < 3 ) + { + j = headspritesect[sprite[i].sectnum]; + while(j >= 0) + { + if( sprite[j].statnum == 3 ) switch(sprite[j].lotag) + { + case 36: + case 31: + case 32: + case 18: + hittype[j].temp_data[0] = 1-hittype[j].temp_data[0]; + callsound(SECT,j); + break; + } + j = nextspritesect[j]; + } + } + + if( k == -1 && (sector[SECT].lotag&0xff) == 22 ) + k = callsound(SECT,i); + + operatesectors(SECT,i); + } + } + i = nextspritestat[i]; + } + + operaterespawns(low); +} + +void operatemasterswitches(short low) +{ + short i; + + i = headspritestat[6]; + while(i >= 0) + { + if( PN == MASTERSWITCH && SLT == low && SP == 0 ) + SP = 1; + i = nextspritestat[i]; + } +} + + + +void operateforcefields(short s, short low) +{ + short i, p; + + for(p=numanimwalls;p>=0;p--) + { + i = animwall[p].wallnum; + + if(low == wall[i].lotag || low == -1) + switch(wall[i].overpicnum) + { + case W_FORCEFIELD : + case W_FORCEFIELD+1: + case W_FORCEFIELD+2: + case BIGFORCE: + + animwall[p].tag = 0; + + if( wall[i].cstat ) + { + wall[i].cstat = 0; + + if( s >= 0 && sprite[s].picnum == SECTOREFFECTOR && + sprite[s].lotag == 30) + wall[i].lotag = 0; + } + else + wall[i].cstat = 85; + break; + } + } +} + + +char checkhitswitch(short snum,long w,char switchtype) +{ + char switchpal; + short i, x, lotag,hitag,picnum,correctdips,numdips; + long sx,sy; + + if(w < 0) return 0; + correctdips = 1; + numdips = 0; + + if(switchtype == 1) // A wall sprite + { + lotag = sprite[w].lotag; if(lotag == 0) return 0; + hitag = sprite[w].hitag; + sx = sprite[w].x; + sy = sprite[w].y; + picnum = sprite[w].picnum; + switchpal = sprite[w].pal; + } + else + { + lotag = wall[w].lotag; if(lotag == 0) return 0; + hitag = wall[w].hitag; + sx = wall[w].x; + sy = wall[w].y; + picnum = wall[w].picnum; + switchpal = wall[w].pal; + } + + switch(picnum) + { + case DIPSWITCH: + case DIPSWITCH+1: + case TECHSWITCH: + case TECHSWITCH+1: + case ALIENSWITCH: + case ALIENSWITCH+1: + break; + case ACCESSSWITCH: + case ACCESSSWITCH2: + if(ps[snum].access_incs == 0) + { + if( switchpal == 0 ) + { + if( (ps[snum].got_access&1) ) + ps[snum].access_incs = 1; + else FTA(70,&ps[snum]); + } + + else if( switchpal == 21 ) + { + if( ps[snum].got_access&2 ) + ps[snum].access_incs = 1; + else FTA(71,&ps[snum]); + } + + else if( switchpal == 23 ) + { + if( ps[snum].got_access&4 ) + ps[snum].access_incs = 1; + else FTA(72,&ps[snum]); + } + + if( ps[snum].access_incs == 1 ) + { + if(switchtype == 0) + ps[snum].access_wallnum = w; + else + ps[snum].access_spritenum = w; + } + + return 0; + } + case DIPSWITCH2: + case DIPSWITCH2+1: + case DIPSWITCH3: + case DIPSWITCH3+1: + case MULTISWITCH: + case MULTISWITCH+1: + case MULTISWITCH+2: + case MULTISWITCH+3: + case PULLSWITCH: + case PULLSWITCH+1: + case HANDSWITCH: + case HANDSWITCH+1: + case SLOTDOOR: + case SLOTDOOR+1: + case LIGHTSWITCH: + case LIGHTSWITCH+1: + case SPACELIGHTSWITCH: + case SPACELIGHTSWITCH+1: + case SPACEDOORSWITCH: + case SPACEDOORSWITCH+1: + case FRANKENSTINESWITCH: + case FRANKENSTINESWITCH+1: + case LIGHTSWITCH2: + case LIGHTSWITCH2+1: + case POWERSWITCH1: + case POWERSWITCH1+1: + case LOCKSWITCH1: + case LOCKSWITCH1+1: + case POWERSWITCH2: + case POWERSWITCH2+1: + if( check_activator_motion( lotag ) ) return 0; + break; + default: + if( isadoorwall(picnum) == 0 ) return 0; + break; + } + + i = headspritestat[0]; + while(i >= 0) + { + if( lotag == SLT ) switch(PN) + { + case DIPSWITCH: + case TECHSWITCH: + case ALIENSWITCH: + if( switchtype == 1 && w == i ) PN++; + else if( SHT == 0 ) correctdips++; + numdips++; + break; + case TECHSWITCH+1: + case DIPSWITCH+1: + case ALIENSWITCH+1: + if( switchtype == 1 && w == i ) PN--; + else if( SHT == 1 ) correctdips++; + numdips++; + break; + case MULTISWITCH: + case MULTISWITCH+1: + case MULTISWITCH+2: + case MULTISWITCH+3: + sprite[i].picnum++; + if( sprite[i].picnum > (MULTISWITCH+3) ) + sprite[i].picnum = MULTISWITCH; + break; + case ACCESSSWITCH: + case ACCESSSWITCH2: + case SLOTDOOR: + case LIGHTSWITCH: + case SPACELIGHTSWITCH: + case SPACEDOORSWITCH: + case FRANKENSTINESWITCH: + case LIGHTSWITCH2: + case POWERSWITCH1: + case LOCKSWITCH1: + case POWERSWITCH2: + case HANDSWITCH: + case PULLSWITCH: + case DIPSWITCH2: + case DIPSWITCH3: + sprite[i].picnum++; + break; + case PULLSWITCH+1: + case HANDSWITCH+1: + case LIGHTSWITCH2+1: + case POWERSWITCH1+1: + case LOCKSWITCH1+1: + case POWERSWITCH2+1: + case SLOTDOOR+1: + case LIGHTSWITCH+1: + case SPACELIGHTSWITCH+1: + case SPACEDOORSWITCH+1: + case FRANKENSTINESWITCH+1: + case DIPSWITCH2+1: + case DIPSWITCH3+1: + sprite[i].picnum--; + break; + } + i = nextspritestat[i]; + } + + for(i=0;i (MULTISWITCH+3) ) + wall[x].picnum = MULTISWITCH; + break; + case ACCESSSWITCH: + case ACCESSSWITCH2: + case SLOTDOOR: + case LIGHTSWITCH: + case SPACELIGHTSWITCH: + case SPACEDOORSWITCH: + case LIGHTSWITCH2: + case POWERSWITCH1: + case LOCKSWITCH1: + case POWERSWITCH2: + case PULLSWITCH: + case HANDSWITCH: + case DIPSWITCH2: + case DIPSWITCH3: + wall[x].picnum++; + break; + case HANDSWITCH+1: + case PULLSWITCH+1: + case LIGHTSWITCH2+1: + case POWERSWITCH1+1: + case LOCKSWITCH1+1: + case POWERSWITCH2+1: + case SLOTDOOR+1: + case LIGHTSWITCH+1: + case SPACELIGHTSWITCH+1: + case SPACEDOORSWITCH+1: + case DIPSWITCH2+1: + case DIPSWITCH3+1: + wall[x].picnum--; + break; + } + } + + if(lotag == (short) 65535) + { + ps[myconnectindex].gm = MODE_EOL; + if(ud.from_bonus) + { + ud.level_number = ud.from_bonus; + ud.m_level_number = ud.level_number; + ud.from_bonus = 0; + } + else + { + ud.level_number++; + if( (ud.volume_number && ud.level_number > 10 ) || ( ud.volume_number == 0 && ud.level_number > 5 ) ) + ud.level_number = 0; + ud.m_level_number = ud.level_number; + } + return 1; + } + + switch(picnum) + { + default: + if(isadoorwall(picnum) == 0) break; + case DIPSWITCH: + case DIPSWITCH+1: + case TECHSWITCH: + case TECHSWITCH+1: + case ALIENSWITCH: + case ALIENSWITCH+1: + if( picnum == DIPSWITCH || picnum == DIPSWITCH+1 || + picnum == ALIENSWITCH || picnum == ALIENSWITCH+1 || + picnum == TECHSWITCH || picnum == TECHSWITCH+1 ) + { + if( picnum == ALIENSWITCH || picnum == ALIENSWITCH+1) + { + if(switchtype == 1) + xyzsound(ALIEN_SWITCH1,w,sx,sy,ps[snum].posz); + else xyzsound(ALIEN_SWITCH1,ps[snum].i,sx,sy,ps[snum].posz); + } + else + { + if(switchtype == 1) + xyzsound(SWITCH_ON,w,sx,sy,ps[snum].posz); + else xyzsound(SWITCH_ON,ps[snum].i,sx,sy,ps[snum].posz); + } + if(numdips != correctdips) break; + xyzsound(END_OF_LEVEL_WARN,ps[snum].i,sx,sy,ps[snum].posz); + } + case DIPSWITCH2: + case DIPSWITCH2+1: + case DIPSWITCH3: + case DIPSWITCH3+1: + case MULTISWITCH: + case MULTISWITCH+1: + case MULTISWITCH+2: + case MULTISWITCH+3: + case ACCESSSWITCH: + case ACCESSSWITCH2: + case SLOTDOOR: + case SLOTDOOR+1: + case LIGHTSWITCH: + case LIGHTSWITCH+1: + case SPACELIGHTSWITCH: + case SPACELIGHTSWITCH+1: + case SPACEDOORSWITCH: + case SPACEDOORSWITCH+1: + case FRANKENSTINESWITCH: + case FRANKENSTINESWITCH+1: + case LIGHTSWITCH2: + case LIGHTSWITCH2+1: + case POWERSWITCH1: + case POWERSWITCH1+1: + case LOCKSWITCH1: + case LOCKSWITCH1+1: + case POWERSWITCH2: + case POWERSWITCH2+1: + case HANDSWITCH: + case HANDSWITCH+1: + case PULLSWITCH: + case PULLSWITCH+1: + + if( picnum == MULTISWITCH || picnum == (MULTISWITCH+1) || + picnum == (MULTISWITCH+2) || picnum == (MULTISWITCH+3) ) + lotag += picnum-MULTISWITCH; + + x = headspritestat[3]; + while(x >= 0) + { + if( ((sprite[x].hitag) == lotag) ) + { + switch(sprite[x].lotag) + { + case 12: + sector[sprite[x].sectnum].floorpal = 0; + hittype[x].temp_data[0]++; + if(hittype[x].temp_data[0] == 2) + hittype[x].temp_data[0]++; + + break; + case 24: + case 34: + case 25: + hittype[x].temp_data[4] = !hittype[x].temp_data[4]; + if(hittype[x].temp_data[4]) + FTA(15,&ps[snum]); + else FTA(2,&ps[snum]); + break; + case 21: + FTA(2,&ps[screenpeek]); + break; + } + } + x = nextspritestat[x]; + } + + operateactivators(lotag,snum); + operateforcefields(ps[snum].i,lotag); + operatemasterswitches(lotag); + + if( picnum == DIPSWITCH || picnum == DIPSWITCH+1 || + picnum == ALIENSWITCH || picnum == ALIENSWITCH+1 || + picnum == TECHSWITCH || picnum == TECHSWITCH+1 ) return 1; + + if( hitag == 0 && isadoorwall(picnum) == 0 ) + { + if(switchtype == 1) + xyzsound(SWITCH_ON,w,sx,sy,ps[snum].posz); + else xyzsound(SWITCH_ON,ps[snum].i,sx,sy,ps[snum].posz); + } + else if(hitag != 0) + { + if(switchtype == 1 && (soundm[hitag]&4) == 0) + xyzsound(hitag,w,sx,sy,ps[snum].posz); + else spritesound(hitag,ps[snum].i); + } + + return 1; + } + return 0; +} + + +void activatebysector(short sect,short j) +{ + short i,didit; + + didit = 0; + + i = headspritesect[sect]; + while(i >= 0) + { + if(PN == ACTIVATOR) + { + operateactivators(SLT,-1); + didit = 1; +// return; + } + i = nextspritesect[i]; + } + + if(didit == 0) + operatesectors(sect,j); +} + +void breakwall(short newpn,short spr,short dawallnum) +{ + wall[dawallnum].picnum = newpn; + spritesound(VENT_BUST,spr); + spritesound(GLASS_HEAVYBREAK,spr); + lotsofglass(spr,dawallnum,10); +} + +void checkhitwall(short spr,short dawallnum,long x,long y,long z,short atwith) +{ + short j, i, sn = -1, darkestwall; + signed char nfloors,nceilings; + short nextj; + walltype *wal; + spritetype *s; + + wal = &wall[dawallnum]; + + if(wal->overpicnum == MIRROR) + { + switch(atwith) + { + case HEAVYHBOMB: + case RADIUSEXPLOSION: + case RPG: + case HYDRENT: + case SEENINE: + case OOZFILTER: + case EXPLODINGBARREL: + lotsofglass(spr,dawallnum,70); + wal->cstat &= ~16; + wal->overpicnum = MIRRORBROKE; + spritesound(GLASS_HEAVYBREAK,spr); + return; + } + } + + if( ( (wal->cstat&16) || wal->overpicnum == BIGFORCE ) && wal->nextsector >= 0 ) + if( sector[wal->nextsector].floorz > z ) + if( sector[wal->nextsector].floorz-sector[wal->nextsector].ceilingz ) + switch(wal->overpicnum) + { + case W_FORCEFIELD: + case W_FORCEFIELD+1: + case W_FORCEFIELD+2: + wal->extra = 1; // tell the forces to animate + case BIGFORCE: + updatesector(x,y,&sn); + if( sn < 0 ) return; + + if(atwith == -1) + i = EGS(sn,x,y,z,FORCERIPPLE,-127,8,8,0,0,0,spr,5); + else + { + if(atwith == CHAINGUN) + i = EGS(sn,x,y,z,FORCERIPPLE,-127,16+sprite[spr].xrepeat,16+sprite[spr].yrepeat,0,0,0,spr,5); + else i = EGS(sn,x,y,z,FORCERIPPLE,-127,32,32,0,0,0,spr,5); + } + + CS |= 18+128; + SA = getangle(wal->x-wall[wal->point2].x, + wal->y-wall[wal->point2].y)-512; + + spritesound(SOMETHINGHITFORCE,i); + + return; + + case FANSPRITE: + wal->overpicnum = FANSPRITEBROKE; + wal->cstat &= 65535-65; + if(wal->nextwall >= 0) + { + wall[wal->nextwall].overpicnum = FANSPRITEBROKE; + wall[wal->nextwall].cstat &= 65535-65; + } + spritesound(VENT_BUST,spr); + spritesound(GLASS_BREAKING,spr); + return; + + case GLASS: + updatesector(x,y,&sn); if( sn < 0 ) return; + wal->overpicnum=GLASS2; + lotsofglass(spr,dawallnum,10); + wal->cstat = 0; + + if(wal->nextwall >= 0) + wall[wal->nextwall].cstat = 0; + + i = EGS(sn,x,y,z,SECTOREFFECTOR,0,0,0,ps[0].ang,0,0,spr,3); + SLT = 128; T2 = 5; T3 = dawallnum; + spritesound(GLASS_BREAKING,i); + return; + case STAINGLASS1: + updatesector(x,y,&sn); if( sn < 0 ) return; + lotsofcolourglass(spr,dawallnum,80); + wal->cstat = 0; + if(wal->nextwall >= 0) + wall[wal->nextwall].cstat = 0; + spritesound(VENT_BUST,spr); + spritesound(GLASS_BREAKING,spr); + return; + } + + switch(wal->picnum) + { + case COLAMACHINE: + case VENDMACHINE: + breakwall(wal->picnum+2,spr,dawallnum); + spritesound(VENT_BUST,spr); + return; + + case OJ: + case FEMPIC2: + case FEMPIC3: + + case SCREENBREAK6: + case SCREENBREAK7: + case SCREENBREAK8: + + case SCREENBREAK1: + case SCREENBREAK2: + case SCREENBREAK3: + case SCREENBREAK4: + case SCREENBREAK5: + + case SCREENBREAK9: + case SCREENBREAK10: + case SCREENBREAK11: + case SCREENBREAK12: + case SCREENBREAK13: + case SCREENBREAK14: + case SCREENBREAK15: + case SCREENBREAK16: + case SCREENBREAK17: + case SCREENBREAK18: + case SCREENBREAK19: + case BORNTOBEWILDSCREEN: + + lotsofglass(spr,dawallnum,30); + wal->picnum=W_SCREENBREAK+(TRAND%3); + spritesound(GLASS_HEAVYBREAK,spr); + return; + + case W_TECHWALL5: + case W_TECHWALL6: + case W_TECHWALL7: + case W_TECHWALL8: + case W_TECHWALL9: + breakwall(wal->picnum+1,spr,dawallnum); + return; + case W_MILKSHELF: + breakwall(W_MILKSHELFBROKE,spr,dawallnum); + return; + + case W_TECHWALL10: + breakwall(W_HITTECHWALL10,spr,dawallnum); + return; + + case W_TECHWALL1: + case W_TECHWALL11: + case W_TECHWALL12: + case W_TECHWALL13: + case W_TECHWALL14: + breakwall(W_HITTECHWALL1,spr,dawallnum); + return; + + case W_TECHWALL15: + breakwall(W_HITTECHWALL15,spr,dawallnum); + return; + + case W_TECHWALL16: + breakwall(W_HITTECHWALL16,spr,dawallnum); + return; + + case W_TECHWALL2: + breakwall(W_HITTECHWALL2,spr,dawallnum); + return; + + case W_TECHWALL3: + breakwall(W_HITTECHWALL3,spr,dawallnum); + return; + + case W_TECHWALL4: + breakwall(W_HITTECHWALL4,spr,dawallnum); + return; + + case ATM: + wal->picnum = ATMBROKE; + lotsofmoney(&sprite[spr],1+(TRAND&7)); + spritesound(GLASS_HEAVYBREAK,spr); + break; + + case WALLLIGHT1: + case WALLLIGHT2: + case WALLLIGHT3: + case WALLLIGHT4: + case TECHLIGHT2: + case TECHLIGHT4: + + if( rnd(128) ) + spritesound(GLASS_HEAVYBREAK,spr); + else spritesound(GLASS_BREAKING,spr); + lotsofglass(spr,dawallnum,30); + + if(wal->picnum == WALLLIGHT1) + wal->picnum = WALLLIGHTBUST1; + + if(wal->picnum == WALLLIGHT2) + wal->picnum = WALLLIGHTBUST2; + + if(wal->picnum == WALLLIGHT3) + wal->picnum = WALLLIGHTBUST3; + + if(wal->picnum == WALLLIGHT4) + wal->picnum = WALLLIGHTBUST4; + + if(wal->picnum == TECHLIGHT2) + wal->picnum = TECHLIGHTBUST2; + + if(wal->picnum == TECHLIGHT4) + wal->picnum = TECHLIGHTBUST4; + + if(!wal->lotag) return; + + sn = wal->nextsector; + if(sn < 0) return; + darkestwall = 0; + + wal = &wall[sector[sn].wallptr]; + for(i=sector[sn].wallnum;i > 0;i--,wal++) + if(wal->shade > darkestwall) + darkestwall=wal->shade; + + j = TRAND&1; + i= headspritestat[3]; + while(i >= 0) + { + if(SHT == wall[dawallnum].lotag && SLT == 3 ) + { + T3 = j; + T4 = darkestwall; + T5 = 1; + } + i = nextspritestat[i]; + } + break; + } +} + + +void checkplayerhurt(struct player_struct *p,short j) +{ + if( (j&49152) == 49152 ) + { + j &= (MAXSPRITES-1); + + switch(sprite[j].picnum) + { + case CACTUS: + if(p->hurt_delay < 8 ) + { + sprite[p->i].extra -= 5; + + p->hurt_delay = 16; + p->pals_time = 32; + p->pals[0] = 32; + p->pals[1] = 0; + p->pals[2] = 0; + spritesound(DUKE_LONGTERM_PAIN,p->i); + } + break; + } + return; + } + + if( (j&49152) != 32768) return; + j &= (MAXWALLS-1); + + if( p->hurt_delay > 0 ) p->hurt_delay--; + else if( wall[j].cstat&85 ) switch(wall[j].overpicnum) + { + case W_FORCEFIELD: + case W_FORCEFIELD+1: + case W_FORCEFIELD+2: + sprite[p->i].extra -= 5; + + p->hurt_delay = 16; + p->pals_time = 32; + p->pals[0] = 32; + p->pals[1] = 0; + p->pals[2] = 0; + + p->posxv = -(sintable[(p->ang+512)&2047]<<8); + p->posyv = -(sintable[(p->ang)&2047]<<8); + spritesound(DUKE_LONGTERM_PAIN,p->i); + + checkhitwall(p->i,j, + p->posx+(sintable[(p->ang+512)&2047]>>9), + p->posy+(sintable[p->ang&2047]>>9), + p->posz,-1); + + break; + + case BIGFORCE: + p->hurt_delay = 26; + checkhitwall(p->i,j, + p->posx+(sintable[(p->ang+512)&2047]>>9), + p->posy+(sintable[p->ang&2047]>>9), + p->posz,-1); + break; + + } +} + + +char checkhitceiling(short sn) +{ + short i, j, q, darkestwall, darkestceiling; + signed char nfloors,nceilings; + walltype *wal; + + switch(sector[sn].ceilingpicnum) + { + case WALLLIGHT1: + case WALLLIGHT2: + case WALLLIGHT3: + case WALLLIGHT4: + case TECHLIGHT2: + case TECHLIGHT4: + + ceilingglass(ps[myconnectindex].i,sn,10); + spritesound(GLASS_BREAKING,ps[screenpeek].i); + + if(sector[sn].ceilingpicnum == WALLLIGHT1) + sector[sn].ceilingpicnum = WALLLIGHTBUST1; + + if(sector[sn].ceilingpicnum == WALLLIGHT2) + sector[sn].ceilingpicnum = WALLLIGHTBUST2; + + if(sector[sn].ceilingpicnum == WALLLIGHT3) + sector[sn].ceilingpicnum = WALLLIGHTBUST3; + + if(sector[sn].ceilingpicnum == WALLLIGHT4) + sector[sn].ceilingpicnum = WALLLIGHTBUST4; + + if(sector[sn].ceilingpicnum == TECHLIGHT2) + sector[sn].ceilingpicnum = TECHLIGHTBUST2; + + if(sector[sn].ceilingpicnum == TECHLIGHT4) + sector[sn].ceilingpicnum = TECHLIGHTBUST4; + + + if(!sector[sn].hitag) + { + i = headspritesect[sn]; + while(i >= 0) + { + if( PN == SECTOREFFECTOR && SLT == 12 ) + { + j = headspritestat[3]; + while(j >= 0) + { + if( sprite[j].hitag == SHT ) + hittype[j].temp_data[3] = 1; + j = nextspritestat[j]; + } + break; + } + i = nextspritesect[i]; + } + } + + i = headspritestat[3]; + j = TRAND&1; + while(i >= 0) + { + if(SHT == (sector[sn].hitag) && SLT == 3 ) + { + T3 = j; + T5 = 1; + } + i = nextspritestat[i]; + } + + return 1; + } + + return 0; +} + +void checkhitsprite(short i,short sn) +{ + short j, k, l, nextj, p; + spritetype *s; + + i &= (MAXSPRITES-1); + + switch(PN) + { + case OCEANSPRITE1: + case OCEANSPRITE2: + case OCEANSPRITE3: + case OCEANSPRITE4: + case OCEANSPRITE5: + spawn(i,SMALLSMOKE); + deletesprite(i); + break; + case QUEBALL: + case STRIPEBALL: + if(sprite[sn].picnum == QUEBALL || sprite[sn].picnum == STRIPEBALL) + { + sprite[sn].xvel = (sprite[i].xvel>>1)+(sprite[i].xvel>>2); + sprite[sn].ang -= (SA<<1)+1024; + SA = getangle(SX-sprite[sn].x,SY-sprite[sn].y)-512; + if(Sound[POOLBALLHIT].num < 2) + spritesound(POOLBALLHIT,i); + } + else + { + if( TRAND&3 ) + { + sprite[i].xvel = 164; + sprite[i].ang = sprite[sn].ang; + } + else + { + lotsofglass(i,-1,3); + deletesprite(i); + } + } + break; + case TREE1: + case TREE2: + case TIRE: + case CONE: + case BOX: + switch(sprite[sn].picnum) + { + case RADIUSEXPLOSION: + case RPG: + case FIRELASER: + case HYDRENT: + case HEAVYHBOMB: + if(T1 == 0) + { + CS &= ~257; + T1 = 1; + spawn(i,BURNING); + } + break; + } + break; + case CACTUS: +// case CACTUSBROKE: + switch(sprite[sn].picnum) + { + case RADIUSEXPLOSION: + case RPG: + case FIRELASER: + case HYDRENT: + case HEAVYHBOMB: + for(k=0;k<64;k++) + { + j = EGS(SECT,SX,SY,SZ-(TRAND%(48<<8)),SCRAP3+(TRAND&3),-8,48,48,TRAND&2047,(TRAND&63)+64,-(TRAND&4095)-(sprite[i].zvel>>2),i,5); + sprite[j].pal = 8; + } + + if(PN == CACTUS) + PN = CACTUSBROKE; + CS &= ~257; + // else deletesprite(i); + break; + } + break; + + case HANGLIGHT: + case GENERICPOLE2: + for(k=0;k<6;k++) + EGS(SECT,SX,SY,SZ-(8<<8),SCRAP1+(TRAND&15),-8,48,48,TRAND&2047,(TRAND&63)+64,-(TRAND&4095)-(sprite[i].zvel>>2),i,5); + spritesound(GLASS_HEAVYBREAK,i); + deletesprite(i); + break; + + + case FANSPRITE: + PN = FANSPRITEBROKE; + CS &= (65535-257); + if( sector[SECT].floorpicnum == FANSHADOW ) + sector[SECT].floorpicnum = FANSHADOWBROKE; + + spritesound(GLASS_HEAVYBREAK,i); + s = &sprite[i]; + for(j=0;j<16;j++) RANDOMSCRAP; + + break; + case WATERFOUNTAIN: + case WATERFOUNTAIN+1: + case WATERFOUNTAIN+2: + case WATERFOUNTAIN+3: + PN = WATERFOUNTAINBROKE; + spawn(i,TOILETWATER); + break; + case SATELITE: + case FUELPOD: + case SOLARPANNEL: + case ANTENNA: + if(sprite[sn].extra != *actorscrptr[SHOTSPARK1] ) + { + for(j=0;j<15;j++) + EGS(SECT,SX,SY,sector[SECT].floorz-(12<<8)-(j<<9),SCRAP1+(TRAND&15),-8,64,64, + TRAND&2047,(TRAND&127)+64,-(TRAND&511)-256,i,5); + spawn(i,EXPLOSION2); + deletesprite(i); + } + break; + case BOTTLE1: + case BOTTLE2: + case BOTTLE3: + case BOTTLE4: + case BOTTLE5: + case BOTTLE6: + case BOTTLE8: + case BOTTLE10: + case BOTTLE11: + case BOTTLE12: + case BOTTLE13: + case BOTTLE14: + case BOTTLE15: + case BOTTLE16: + case BOTTLE17: + case BOTTLE18: + case BOTTLE19: + case WATERFOUNTAINBROKE: + case DOMELITE: + case SUSHIPLATE1: + case SUSHIPLATE2: + case SUSHIPLATE3: + case SUSHIPLATE4: + case SUSHIPLATE5: + case WAITTOBESEATED: + case VASE: + case STATUEFLASH: + case STATUE: + if(PN == BOTTLE10) + lotsofmoney(&sprite[i],4+(TRAND&3)); + else if(PN == STATUE || PN == STATUEFLASH) + { + lotsofcolourglass(i,-1,40); + spritesound(GLASS_HEAVYBREAK,i); + } + else if(PN == VASE) + lotsofglass(i,-1,40); + + spritesound(GLASS_BREAKING,i); + SA = TRAND&2047; + lotsofglass(i,-1,8); + deletesprite(i); + break; + case FETUS: + PN = FETUSBROKE; + spritesound(GLASS_BREAKING,i); + lotsofglass(i,-1,10); + break; + case FETUSBROKE: + for(j=0;j<48;j++) + { + shoot(i,BLOODSPLAT1); + SA += 333; + } + spritesound(GLASS_HEAVYBREAK,i); + spritesound(SQUISHED,i); + case BOTTLE7: + spritesound(GLASS_BREAKING,i); + lotsofglass(i,-1,10); + deletesprite(i); + break; + case HYDROPLANT: + PN = BROKEHYDROPLANT; + spritesound(GLASS_BREAKING,i); + lotsofglass(i,-1,10); + break; + + case FORCESPHERE: + sprite[i].xrepeat = 0; + hittype[OW].temp_data[0] = 32; + hittype[OW].temp_data[1] = !hittype[OW].temp_data[1]; + hittype[OW].temp_data[2] ++; + spawn(i,EXPLOSION2); + break; + + case BROKEHYDROPLANT: + if(CS&1) + { + spritesound(GLASS_BREAKING,i); + SZ += 16<<8; + CS = 0; + lotsofglass(i,-1,5); + } + break; + + case TOILET: + PN = TOILETBROKE; + CS |= (TRAND&1)<<2; + CS &= ~257; + spawn(i,TOILETWATER); + spritesound(GLASS_BREAKING,i); + break; + + case STALL: + PN = STALLBROKE; + CS |= (TRAND&1)<<2; + CS &= ~257; + spawn(i,TOILETWATER); + spritesound(GLASS_HEAVYBREAK,i); + break; + + case HYDRENT: + PN = BROKEFIREHYDRENT; + spawn(i,TOILETWATER); + +// for(k=0;k<5;k++) + // { + // j = EGS(SECT,SX,SY,SZ-(TRAND%(48<<8)),SCRAP3+(TRAND&3),-8,48,48,TRAND&2047,(TRAND&63)+64,-(TRAND&4095)-(sprite[i].zvel>>2),i,5); + // sprite[j].pal = 2; + // } + spritesound(GLASS_HEAVYBREAK,i); + break; + + case GRATE1: + PN = BGRATE1; + CS &= (65535-256-1); + spritesound(VENT_BUST,i); + break; + + case CIRCLEPANNEL: + PN = CIRCLEPANNELBROKE; + CS &= (65535-256-1); + spritesound(VENT_BUST,i); + break; + case PANNEL1: + case PANNEL2: + PN = BPANNEL1; + CS &= (65535-256-1); + spritesound(VENT_BUST,i); + break; + case PANNEL3: + PN = BPANNEL3; + CS &= (65535-256-1); + spritesound(VENT_BUST,i); + break; + case PIPE1: + case PIPE2: + case PIPE3: + case PIPE4: + case PIPE5: + case PIPE6: + switch(PN) + { + case PIPE1:PN=PIPE1B;break; + case PIPE2:PN=PIPE2B;break; + case PIPE3:PN=PIPE3B;break; + case PIPE4:PN=PIPE4B;break; + case PIPE5:PN=PIPE5B;break; + case PIPE6:PN=PIPE6B;break; + } + + j = spawn(i,STEAM); + sprite[j].z = sector[SECT].floorz-(32<<8); + break; + + case MONK: + case LUKE: + case INDY: + case JURYGUY: + spritesound(SLT,i); + spawn(i,SHT); + case SPACEMARINE: + sprite[i].extra -= sprite[sn].extra; + if(sprite[i].extra > 0) break; + SA = TRAND&2047; + shoot(i,BLOODSPLAT1); + SA = TRAND&2047; + shoot(i,BLOODSPLAT2); + SA = TRAND&2047; + shoot(i,BLOODSPLAT3); + SA = TRAND&2047; + shoot(i,BLOODSPLAT4); + SA = TRAND&2047; + shoot(i,BLOODSPLAT1); + SA = TRAND&2047; + shoot(i,BLOODSPLAT2); + SA = TRAND&2047; + shoot(i,BLOODSPLAT3); + SA = TRAND&2047; + shoot(i,BLOODSPLAT4); + guts(&sprite[i],JIBS1,1,myconnectindex); + guts(&sprite[i],JIBS2,2,myconnectindex); + guts(&sprite[i],JIBS3,3,myconnectindex); + guts(&sprite[i],JIBS4,4,myconnectindex); + guts(&sprite[i],JIBS5,1,myconnectindex); + guts(&sprite[i],JIBS3,6,myconnectindex); + sound(SQUISHED); + deletesprite(i); + break; + case CHAIR1: + case CHAIR2: + PN = BROKENCHAIR; + CS = 0; + break; + case CHAIR3: + case MOVIECAMERA: + case SCALE: + case VACUUM: + case CAMERALIGHT: + case IVUNIT: + case POT1: + case POT2: + case POT3: + case TRIPODCAMERA: + spritesound(GLASS_HEAVYBREAK,i); + s = &sprite[i]; + for(j=0;j<16;j++) RANDOMSCRAP; + deletesprite(i); + break; + case PLAYERONWATER: + i = OW; + default: + if( (sprite[i].cstat&16) && SHT == 0 && SLT == 0 && sprite[i].statnum == 0) + break; + + if( ( sprite[sn].picnum == FREEZEBLAST || sprite[sn].owner != i ) && sprite[i].statnum != 4) + { + if( badguy(&sprite[i]) == 1) + { + if(sprite[sn].picnum == RPG) sprite[sn].extra <<= 1; + + if( (PN != DRONE) && (PN != ROTATEGUN) && (PN != COMMANDER) && (PN < GREENSLIME || PN > GREENSLIME+7) ) + if(sprite[sn].picnum != FREEZEBLAST ) + if( actortype[PN] == 0 ) + { + j = spawn(sn,JIBS6); + if(sprite[sn].pal == 6) + sprite[j].pal = 6; + sprite[j].z += (4<<8); + sprite[j].xvel = 16; + sprite[j].xrepeat = sprite[j].yrepeat = 24; + sprite[j].ang += 32-(TRAND&63); + } + + j = sprite[sn].owner; + + if( j >= 0 && sprite[j].picnum == APLAYER && PN != ROTATEGUN && PN != DRONE ) + if( ps[sprite[j].yvel].curr_weapon == SHOTGUN_WEAPON ) + { + shoot(i,BLOODSPLAT3); + shoot(i,BLOODSPLAT1); + shoot(i,BLOODSPLAT2); + shoot(i,BLOODSPLAT4); + } + + if( PN != TANK && PN != BOSS1 && PN != BOSS4 && PN != BOSS2 && PN != BOSS3 && PN != RECON && PN != ROTATEGUN ) + { + if( (sprite[i].cstat&48) == 0 ) + SA = (sprite[sn].ang+1024)&2047; + sprite[i].xvel = -(sprite[sn].extra<<2); + j = SECT; + pushmove(&SX,&SY,&SZ,&j,128L,(4L<<8),(4L<<8),CLIPMASK0); + if(j != SECT && j >= 0 && j < MAXSECTORS) + changespritesect(i,j); + } + + if(sprite[i].statnum == 2) + { + changespritestat(i,1); + hittype[i].timetosleep = SLEEPTIME; + } + if( ( RX < 24 || PN == SHARK) && sprite[sn].picnum == SHRINKSPARK) return; + } + + if( sprite[i].statnum != 2 ) + { + if( sprite[sn].picnum == FREEZEBLAST && ( (PN == APLAYER && sprite[i].pal == 1 ) || ( freezerhurtowner == 0 && sprite[sn].owner == i ) ) ) + return; + + hittype[i].picnum = sprite[sn].picnum; + hittype[i].extra += sprite[sn].extra; + hittype[i].ang = sprite[sn].ang; + hittype[i].owner = sprite[sn].owner; + } + + if(sprite[i].statnum == 10) + { + p = sprite[i].yvel; + if(ps[p].newowner >= 0) + { + ps[p].newowner = -1; + ps[p].posx = ps[p].oposx; + ps[p].posy = ps[p].oposy; + ps[p].posz = ps[p].oposz; + ps[p].ang = ps[p].oang; + + updatesector(ps[p].posx,ps[p].posy,&ps[p].cursectnum); + setpal(&ps[p]); + + j = headspritestat[1]; + while(j >= 0) + { + if(sprite[j].picnum==CAMERA1) sprite[j].yvel = 0; + j = nextspritestat[j]; + } + } + + if( RX < 24 && sprite[sn].picnum == SHRINKSPARK) + return; + + if( sprite[hittype[i].owner].picnum != APLAYER) + if(ud.player_skill >= 3) + sprite[sn].extra += (sprite[sn].extra>>1); + } + + } + break; + } +} + + +void allignwarpelevators(void) +{ + short i, j; + + i = headspritestat[3]; + while(i >= 0) + { + if( SLT == 17 && SS > 16) + { + j = headspritestat[3]; + while(j >= 0) + { + if( (sprite[j].lotag) == 17 && i != j && + (SHT) == (sprite[j].hitag) ) + { + sector[sprite[j].sectnum].floorz = + sector[SECT].floorz; + sector[sprite[j].sectnum].ceilingz = + sector[SECT].ceilingz; + } + + j = nextspritestat[j]; + } + } + i = nextspritestat[i]; + } +} + + + + +void cheatkeys(short snum) +{ + short i, k; + char dainv; + unsigned long sb_snum; + long j; + struct player_struct *p; + + sb_snum = sync[snum].bits; + p = &ps[snum]; + + if(p->cheat_phase == 1) return; + + i = p->aim_mode; + p->aim_mode = (sb_snum>>23)&1; + if(p->aim_mode < i) + p->return_to_center = 9; + + if( (sb_snum&(1<<22)) && p->quick_kick == 0) + if( p->curr_weapon != KNEE_WEAPON || p->kickback_pic == 0 ) + { + p->quick_kick = 14; + FTA(80,p); + } + + if( !(sb_snum&((15<<8)|(1<<12)|(1<<15)|(1<<16)|(1<<22)|(1<<19)|(1<<20)|(1<<21)|(1<<24)|(1<<25)|(1<<27)|(1<<28)|(1<<29)|(1<<30)|(1<<31))) ) + p->interface_toggle_flag = 0; + else if(p->interface_toggle_flag == 0 && ( sb_snum&(1<<17) ) == 0) + { + p->interface_toggle_flag = 1; + + if( sb_snum&(1<<21) ) + { + KB_ClearKeyDown( sc_Pause ); + ud.pause_on = !ud.pause_on; + if( ud.pause_on == 1 && sb_snum&(1<<5) ) ud.pause_on = 2; + if(ud.pause_on) + { + MUSIC_Pause(); + FX_StopAllSounds(); + clearsoundlocks(); + } + else + { + if(MusicToggle) MUSIC_Continue(); + pub = NUMPAGES; + pus = NUMPAGES; + } + } + + if(ud.pause_on) return; + + if(sprite[p->i].extra <= 0) return; + + if( sb_snum&(1<<30) && p->newowner == -1 ) + { + switch(p->inven_icon) + { + case 4: sb_snum |= (1<<25);break; + case 3: sb_snum |= (1<<24);break; + case 5: sb_snum |= (1<<15);break; + case 1: sb_snum |= (1<<16);break; + case 2: sb_snum |= (1<<12);break; + } + } + + if( sb_snum&(1<<15) && p->heat_amount > 0 ) + { + p->heat_on = !p->heat_on; + setpal(p); + p->inven_icon = 5; + spritesound(NITEVISION_ONOFF,p->i); + FTA(106+(!p->heat_on),p); + } + + if( (sb_snum&(1<<12)) ) + { + if(p->steroids_amount == 400 ) + { + p->steroids_amount--; + spritesound(DUKE_TAKEPILLS,p->i); + p->inven_icon = 2; + FTA(12,p); + } + return; + } + + if(p->newowner == -1) + if( sb_snum&(1<<20) || sb_snum&(1<<27) || p->refresh_inventory) + { + p->invdisptime = 26*2; + + if( sb_snum&(1<<27) ) k = 1; + else k = 0; + + if(p->refresh_inventory) p->refresh_inventory = 0; + dainv = p->inven_icon; + + i = 0; + CHECKINV1: + + if(i < 9) + { + i++; + + switch(dainv) + { + case 4: + if(p->jetpack_amount > 0 && i > 1) + break; + if(k) dainv = 5; + else dainv = 3; + goto CHECKINV1; + case 6: + if(p->scuba_amount > 0 && i > 1) + break; + if(k) dainv = 7; + else dainv = 5; + goto CHECKINV1; + case 2: + if(p->steroids_amount > 0 && i > 1) + break; + if(k) dainv = 3; + else dainv = 1; + goto CHECKINV1; + case 3: + if(p->holoduke_amount > 0 && i > 1) + break; + if(k) dainv = 4; + else dainv = 2; + goto CHECKINV1; + case 0: + case 1: + if(p->firstaid_amount > 0 && i > 1) + break; + if(k) dainv = 2; + else dainv = 7; + goto CHECKINV1; + case 5: + if(p->heat_amount > 0 && i > 1) + break; + if(k) dainv = 6; + else dainv = 4; + goto CHECKINV1; + case 7: + if(p->boot_amount > 0 && i > 1) + break; + if(k) dainv = 1; + else dainv = 6; + goto CHECKINV1; + } + } + else dainv = 0; + p->inven_icon = dainv; + + switch(dainv) + { + case 1: FTA(3,p);break; + case 2: FTA(90,p);break; + case 3: FTA(91,p);break; + case 4: FTA(88,p);break; + case 5: FTA(101,p);break; + case 6: FTA(89,p);break; + case 7: FTA(6,p);break; + } + } + + j = ( (sb_snum&(15<<8))>>8 ) - 1; + + if( j > 0 && p->kickback_pic > 0) + p->wantweaponfire = j; + + if(p->last_pissed_time <= (26*218) && p->show_empty_weapon == 0 && p->kickback_pic == 0 && p->quick_kick == 0 && sprite[p->i].xrepeat > 32 && p->access_incs == 0 && p->knee_incs == 0 ) + { + if( ( p->weapon_pos == 0 || ( p->holster_weapon && p->weapon_pos == -9 ) ) ) + { + if(j == 10 || j == 11) + { + k = p->curr_weapon; + j = ( j == 10 ? -1 : 1 ); + i = 0; + + while( ( k >= 0 && k < 10 ) || ( k == GROW_WEAPON && (p->subweapon&(1<subweapon&(1<gotweapon[k] && p->ammo_amount[k] > 0 ) + { + if( k == SHRINKER_WEAPON && p->subweapon&(1<ammo_amount[GROW_WEAPON] == 0 && p->gotweapon[SHRINKER_WEAPON] && p->ammo_amount[SHRINKER_WEAPON] > 0) + { + j = SHRINKER_WEAPON; + p->subweapon &= ~(1<ammo_amount[SHRINKER_WEAPON] == 0 && p->gotweapon[SHRINKER_WEAPON] && p->ammo_amount[GROW_WEAPON] > 0) + { + j = GROW_WEAPON; + p->subweapon |= (1<ammo_amount[HANDBOMB_WEAPON] == 0 ) + { + k = headspritestat[1]; + while(k >= 0) + { + if( sprite[k].picnum == HEAVYHBOMB && sprite[k].owner == p->i ) + { + p->gotweapon[HANDBOMB_WEAPON] = 1; + j = HANDREMOTE_WEAPON; + break; + } + k = nextspritestat[k]; + } + } + + if(j == SHRINKER_WEAPON) + { + if(screenpeek == snum) pus = NUMPAGES; + + if( p->curr_weapon != GROW_WEAPON && p->curr_weapon != SHRINKER_WEAPON ) + { + if( p->ammo_amount[GROW_WEAPON] > 0 ) + { + if( (p->subweapon&(1<ammo_amount[SHRINKER_WEAPON] == 0) + { + j = GROW_WEAPON; + p->subweapon |= (1<ammo_amount[SHRINKER_WEAPON] > 0 ) + p->subweapon &= ~(1<curr_weapon == SHRINKER_WEAPON ) + { + p->subweapon |= (1<subweapon &= ~(1<holster_weapon) + { + sb_snum |= 1<<19; + p->weapon_pos = -9; + } + else if( p->gotweapon[j] && p->curr_weapon != j ) switch(j) + { + case KNEE_WEAPON: + addweapon( p, KNEE_WEAPON ); + break; + case PISTOL_WEAPON: + if ( p->ammo_amount[PISTOL_WEAPON] == 0 ) + if(p->show_empty_weapon == 0) + { + p->last_full_weapon = p->curr_weapon; + p->show_empty_weapon = 32; + } + addweapon( p, PISTOL_WEAPON ); + break; + case SHOTGUN_WEAPON: + if( p->ammo_amount[SHOTGUN_WEAPON] == 0 && p->show_empty_weapon == 0) + { + p->last_full_weapon = p->curr_weapon; + p->show_empty_weapon = 32; + } + addweapon( p, SHOTGUN_WEAPON); + break; + case CHAINGUN_WEAPON: + if( p->ammo_amount[CHAINGUN_WEAPON] == 0 && p->show_empty_weapon == 0) + { + p->last_full_weapon = p->curr_weapon; + p->show_empty_weapon = 32; + } + addweapon( p, CHAINGUN_WEAPON); + break; + case RPG_WEAPON: + if( p->ammo_amount[RPG_WEAPON] == 0 ) + if(p->show_empty_weapon == 0) + { + p->last_full_weapon = p->curr_weapon; + p->show_empty_weapon = 32; + } + addweapon( p, RPG_WEAPON ); + break; + case DEVISTATOR_WEAPON: + if( p->ammo_amount[DEVISTATOR_WEAPON] == 0 && p->show_empty_weapon == 0 ) + { + p->last_full_weapon = p->curr_weapon; + p->show_empty_weapon = 32; + } + addweapon( p, DEVISTATOR_WEAPON ); + break; + case FREEZE_WEAPON: + if( p->ammo_amount[FREEZE_WEAPON] == 0 && p->show_empty_weapon == 0) + { + p->last_full_weapon = p->curr_weapon; + p->show_empty_weapon = 32; + } + addweapon( p, FREEZE_WEAPON ); + break; + case GROW_WEAPON: + case SHRINKER_WEAPON: + + if( p->ammo_amount[j] == 0 && p->show_empty_weapon == 0) + { + p->show_empty_weapon = 32; + p->last_full_weapon = p->curr_weapon; + } + + addweapon(p, j); + break; + case HANDREMOTE_WEAPON: + if(k >= 0) // Found in list of [1]'s + { + p->curr_weapon = HANDREMOTE_WEAPON; + p->last_weapon = -1; + p->weapon_pos = 10; + } + break; + case HANDBOMB_WEAPON: + if( p->ammo_amount[HANDBOMB_WEAPON] > 0 && p->gotweapon[HANDBOMB_WEAPON] ) + addweapon( p, HANDBOMB_WEAPON ); + break; + case TRIPBOMB_WEAPON: + if( p->ammo_amount[TRIPBOMB_WEAPON] > 0 && p->gotweapon[TRIPBOMB_WEAPON] ) + addweapon( p, TRIPBOMB_WEAPON ); + break; + } + } + + if( sb_snum&(1<<19) ) + { + if( p->curr_weapon > KNEE_WEAPON ) + { + if(p->holster_weapon == 0 && p->weapon_pos == 0) + { + p->holster_weapon = 1; + p->weapon_pos = -1; + FTA(73,p); + } + else if(p->holster_weapon == 1 && p->weapon_pos == -9) + { + p->holster_weapon = 0; + p->weapon_pos = 10; + FTA(74,p); + } + } + } + } + + if( sb_snum&(1<<24) && p->newowner == -1 ) + { + if( p->holoduke_on == -1 ) + { + + if( p->holoduke_amount > 0 ) + { + p->inven_icon = 3; + + p->holoduke_on = i = + EGS(p->cursectnum, + p->posx, + p->posy, + p->posz+(30<<8),APLAYER,-64,0,0,p->ang,0,0,-1,10); + T4 = T5 = 0; + SP = snum; + sprite[i].extra = 0; + FTA(47,p); + } + else FTA(49,p); + spritesound(TELEPORTER,p->holoduke_on); + + } + else + { + spritesound(TELEPORTER,p->holoduke_on); + p->holoduke_on = -1; + FTA(48,p); + } + } + + if( sb_snum&(1<<16) ) + { + if( p->firstaid_amount > 0 && sprite[p->i].extra < max_player_health ) + { + j = max_player_health-sprite[p->i].extra; + + if(p->firstaid_amount > j) + { + p->firstaid_amount -= j; + sprite[p->i].extra = max_player_health; + p->inven_icon = 1; + } + else + { + sprite[p->i].extra += p->firstaid_amount; + p->firstaid_amount = 0; + checkavailinven(p); + } + spritesound(DUKE_USEMEDKIT,p->i); + } + } + + if( sb_snum&(1<<25) && p->newowner == -1) + { + if( p->jetpack_amount > 0 ) + { + p->jetpack_on = !p->jetpack_on; + if(p->jetpack_on) + { + p->inven_icon = 4; + if(p->scream_voice > FX_Ok) + { + FX_StopSound(p->scream_voice); + testcallback(DUKE_SCREAM); + p->scream_voice = FX_Ok; + } + + spritesound(DUKE_JETPACK_ON,p->i); + + FTA(52,p); + } + else + { + p->hard_landing = 0; + p->poszv = 0; + spritesound(DUKE_JETPACK_OFF,p->i); + stopsound(DUKE_JETPACK_IDLE); + stopsound(DUKE_JETPACK_ON); + FTA(53,p); + } + } + else FTA(50,p); + } + + if(sb_snum&(1<<28) && p->one_eighty_count == 0) + p->one_eighty_count = -1024; + } +} + +void checksectors(short snum) +{ + long i = -1,oldz; + struct player_struct *p; + short j,hitscanwall; + + p = &ps[snum]; + + switch(sector[p->cursectnum].lotag) + { + + case 32767: + sector[p->cursectnum].lotag = 0; + FTA(9,p); + p->secret_rooms++; + return; + case -1: + for(i=connecthead;i>=0;i=connectpoint2[i]) + ps[i].gm = MODE_EOL; + sector[p->cursectnum].lotag = 0; + if(ud.from_bonus) + { + ud.level_number = ud.from_bonus; + ud.m_level_number = ud.level_number; + ud.from_bonus = 0; + } + else + { + ud.level_number++; + if( (ud.volume_number && ud.level_number > 10 ) || ud.level_number > 5 ) + ud.level_number = 0; + ud.m_level_number = ud.level_number; + } + return; + case -2: + sector[p->cursectnum].lotag = 0; + p->timebeforeexit = 26*8; + p->customexitsound = sector[p->cursectnum].hitag; + return; + default: + if(sector[p->cursectnum].lotag >= 10000 && sector[p->cursectnum].lotag < 16383) + { + if(snum == screenpeek || ud.coop == 1 ) + spritesound(sector[p->cursectnum].lotag-10000,p->i); + sector[p->cursectnum].lotag = 0; + } + break; + + } + + //After this point the the player effects the map with space + + if(p->gm&MODE_TYPE || sprite[p->i].extra <= 0) return; + + if( ud.cashman && sync[snum].bits&(1<<29) ) + lotsofmoney(&sprite[p->i],2); + + if(p->newowner >= 0) + { + if( klabs(sync[snum].svel) > 768 || klabs(sync[snum].fvel) > 768 ) + { + i = -1; + goto CLEARCAMERAS; + } + } + + if( !(sync[snum].bits&(1<<29)) && !(sync[snum].bits&(1<<31))) + p->toggle_key_flag = 0; + + else if(!p->toggle_key_flag) + { + + if( (sync[snum].bits&(1<<31)) ) + { + if( p->newowner >= 0 ) + { + i = -1; + goto CLEARCAMERAS; + } + return; + } + + neartagsprite = -1; + p->toggle_key_flag = 1; + hitscanwall = -1; + + i = hitawall(p,&hitscanwall); + + if(i < 1280 && hitscanwall >= 0 && wall[hitscanwall].overpicnum == MIRROR) + if( wall[hitscanwall].lotag > 0 && Sound[wall[hitscanwall].lotag].num == 0 && snum == screenpeek) + { + spritesound(wall[hitscanwall].lotag,p->i); + return; + } + + if(hitscanwall >= 0 && (wall[hitscanwall].cstat&16) ) + switch(wall[hitscanwall].overpicnum) + { + default: + if(wall[hitscanwall].lotag) + return; + } + + if(p->newowner >= 0) + neartag(p->oposx,p->oposy,p->oposz,sprite[p->i].sectnum,p->oang,&neartagsector,&neartagwall,&neartagsprite,&neartaghitdist,1280L,1); + else + { + neartag(p->posx,p->posy,p->posz,sprite[p->i].sectnum,p->oang,&neartagsector,&neartagwall,&neartagsprite,&neartaghitdist,1280L,1); + if(neartagsprite == -1 && neartagwall == -1 && neartagsector == -1) + neartag(p->posx,p->posy,p->posz+(8<<8),sprite[p->i].sectnum,p->oang,&neartagsector,&neartagwall,&neartagsprite,&neartaghitdist,1280L,1); + if(neartagsprite == -1 && neartagwall == -1 && neartagsector == -1) + neartag(p->posx,p->posy,p->posz+(16<<8),sprite[p->i].sectnum,p->oang,&neartagsector,&neartagwall,&neartagsprite,&neartaghitdist,1280L,1); + if(neartagsprite == -1 && neartagwall == -1 && neartagsector == -1) + { + neartag(p->posx,p->posy,p->posz+(16<<8),sprite[p->i].sectnum,p->oang,&neartagsector,&neartagwall,&neartagsprite,&neartaghitdist,1280L,3); + if(neartagsprite >= 0) + { + switch(sprite[neartagsprite].picnum) + { + case FEM1: + case FEM2: + case FEM3: + case FEM4: + case FEM5: + case FEM6: + case FEM7: + case FEM8: + case FEM9: + case FEM10: + case PODFEM1: + case NAKED1: + case STATUE: + case TOUGHGAL: + return; + } + } + + neartagsprite = -1; + neartagwall = -1; + neartagsector = -1; + } + } + + if(p->newowner == -1 && neartagsprite == -1 && neartagsector == -1 && neartagwall == -1 ) + if( isanunderoperator(sector[sprite[p->i].sectnum].lotag) ) + neartagsector = sprite[p->i].sectnum; + + if( neartagsector >= 0 && (sector[neartagsector].lotag&16384) ) + return; + + if( neartagsprite == -1 && neartagwall == -1) + if(sector[p->cursectnum].lotag == 2 ) + { + oldz = hitasprite(p->i,&neartagsprite); + if(oldz > 1280) neartagsprite = -1; + } + + if(neartagsprite >= 0) + { + if( checkhitswitch(snum,neartagsprite,1) ) return; + + switch(sprite[neartagsprite].picnum) + { + case TOILET: + case STALL: + if(p->last_pissed_time == 0) + { + if(ud.lockout == 0) spritesound(DUKE_URINATE,p->i); + + p->last_pissed_time = 26*220; + p->transporter_hold = 29*2; + if(p->holster_weapon == 0) + { + p->holster_weapon = 1; + p->weapon_pos = -1; + } + if(sprite[p->i].extra <= (max_player_health-(max_player_health/10) ) ) + { + sprite[p->i].extra += max_player_health/10; + p->last_extra = sprite[p->i].extra; + } + else if(sprite[p->i].extra < max_player_health ) + sprite[p->i].extra = max_player_health; + } + else if(Sound[FLUSH_TOILET].num == 0) + spritesound(FLUSH_TOILET,p->i); + return; + + case NUKEBUTTON: + + hitawall(p,&j); + if(j >= 0 && wall[j].overpicnum == 0) + if(hittype[neartagsprite].temp_data[0] == 0) + { + hittype[neartagsprite].temp_data[0] = 1; + sprite[neartagsprite].owner = p->i; + p->buttonpalette = sprite[neartagsprite].pal; + if(p->buttonpalette) + ud.secretlevel = sprite[neartagsprite].lotag; + else ud.secretlevel = 0; + } + return; + case WATERFOUNTAIN: + if(hittype[neartagsprite].temp_data[0] != 1) + { + hittype[neartagsprite].temp_data[0] = 1; + sprite[neartagsprite].owner = p->i; + + if(sprite[p->i].extra < max_player_health) + { + sprite[p->i].extra++; + spritesound(DUKE_DRINKING,p->i); + } + } + return; + case PLUG: + spritesound(SHORT_CIRCUIT,p->i); + sprite[p->i].extra -= 2+(TRAND&3); + p->pals[0] = 48; + p->pals[1] = 48; + p->pals[2] = 64; + p->pals_time = 32; + break; + case VIEWSCREEN: + case VIEWSCREEN2: + { + i = headspritestat[1]; + + while(i >= 0) + { + if( PN == CAMERA1 && SP == 0 && sprite[neartagsprite].hitag == SLT ) + { + SP = 1; //Using this camera + spritesound(MONITOR_ACTIVE,neartagsprite); + + sprite[neartagsprite].owner = i; + sprite[neartagsprite].yvel = 1; + + + j = p->cursectnum; + p->cursectnum = SECT; + setpal(p); + p->cursectnum = j; + + // parallaxtype = 2; + p->newowner = i; + return; + } + i = nextspritestat[i]; + } + } + + CLEARCAMERAS: + + if(i < 0) + { + p->posx = p->oposx; + p->posy = p->oposy; + p->posz = p->oposz; + p->ang = p->oang; + p->newowner = -1; + + updatesector(p->posx,p->posy,&p->cursectnum); + setpal(p); + + + i = headspritestat[1]; + while(i >= 0) + { + if(PN==CAMERA1) SP = 0; + i = nextspritestat[i]; + } + } + else if(p->newowner >= 0) + p->newowner = -1; + + if( KB_KeyPressed(sc_Escape) ) + KB_ClearKeyDown(sc_Escape); + + return; + } + } + + if( (sync[snum].bits&(1<<29)) == 0 ) return; + else if(p->newowner >= 0) { i = -1; goto CLEARCAMERAS; } + + if(neartagwall == -1 && neartagsector == -1 && neartagsprite == -1) + if( klabs(hits(p->i)) < 512 ) + { + if( (TRAND&255) < 16 ) + spritesound(DUKE_SEARCH2,p->i); + else spritesound(DUKE_SEARCH,p->i); + return; + } + + if( neartagwall >= 0 ) + { + if( wall[neartagwall].lotag > 0 && isadoorwall(wall[neartagwall].picnum) ) + { + if(hitscanwall == neartagwall || hitscanwall == -1) + checkhitswitch(snum,neartagwall,0); + return; + } + else if(p->newowner >= 0) + { + i = -1; + goto CLEARCAMERAS; + } + } + + if( neartagsector >= 0 && (sector[neartagsector].lotag&16384) == 0 && isanearoperator(sector[neartagsector].lotag) ) + { + i = headspritesect[neartagsector]; + while(i >= 0) + { + if( PN == ACTIVATOR || PN == MASTERSWITCH ) + return; + i = nextspritesect[i]; + } + operatesectors(neartagsector,p->i); + } + else if( (sector[sprite[p->i].sectnum].lotag&16384) == 0 ) + { + if( isanunderoperator(sector[sprite[p->i].sectnum].lotag) ) + { + i = headspritesect[sprite[p->i].sectnum]; + while(i >= 0) + { + if(PN == ACTIVATOR || PN == MASTERSWITCH) return; + i = nextspritesect[i]; + } + operatesectors(sprite[p->i].sectnum,p->i); + } + else checkhitswitch(snum,neartagwall,0); + } + } +} + + + diff --git a/sndcards.h b/sndcards.h new file mode 100755 index 0000000..99f6435 --- /dev/null +++ b/sndcards.h @@ -0,0 +1,51 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment + +This file is part of Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Original Source: 1994 - Jim Dose +Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms +*/ +//------------------------------------------------------------------------- + +#ifndef __SNDCARDS_H +#define __SNDCARDS_H + +#define ASS_VERSION_STRING "1.1" + +typedef enum + { +// ASS_NoSound, + SoundBlaster, + ProAudioSpectrum, + SoundMan16, + Adlib, + GenMidi, + SoundCanvas, + Awe32, + WaveBlaster, + SoundScape, + UltraSound, + SoundSource, + TandySoundSource, + PC, + NumSoundCards + } soundcardnames; + +#endif diff --git a/soundefs.h b/soundefs.h new file mode 100755 index 0000000..aa76476 --- /dev/null +++ b/soundefs.h @@ -0,0 +1,1231 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment + +This file is part of Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Original Source: 1996 - Todd Replogle +Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms +*/ +//------------------------------------------------------------------------- + +#define SECTOREFFECTOR 1 +#define ACTIVATOR 2 +#define TOUCHPLATE 3 +#define ACTIVATORLOCKED 4 +#define MUSICANDSFX 5 +#define LOCATORS 6 +#define CYCLER 7 +#define MASTERSWITCH 8 +#define RESPAWN 9 +#define GPSPEED 10 +#define ARROW 20 +#define FIRSTGUNSPRITE 21 +#define CHAINGUNSPRITE 22 +#define RPGSPRITE 23 +#define FREEZESPRITE 24 +#define SHRINKERSPRITE 25 +#define HEAVYHBOMB 26 +#define TRIPBOMBSPRITE 27 +#define SHOTGUNSPRITE 28 +#define DEVISTATORSPRITE 29 +#define HEALTHBOX 30 +#define AMMOBOX 31 +#define INVENTORYBOX 33 +#define FREEZEAMMO 37 +#define AMMO 40 +#define BATTERYAMMO 41 +#define DEVISTATORAMMO 42 +#define RPGAMMO 44 +#define GROWAMMO 45 +#define CRYSTALAMMO 46 +#define HBOMBAMMO 47 +#define AMMOLOTS 48 +#define SHOTGUNAMMO 49 +#define COLA 51 +#define SIXPAK 52 +#define FIRSTAID 53 +#define SHIELD 54 +#define STEROIDS 55 +#define AIRTANK 56 +#define JETPACK 57 +#define HEATSENSOR 59 +#define ACCESSCARD 60 +#define BOOTS 61 +#define MIRRORBROKE 70 +#define CLOUDYOCEAN 78 +#define CLOUDYSKIES 79 +#define MOONSKY1 80 +#define MOONSKY2 81 +#define MOONSKY3 82 +#define MOONSKY4 83 +#define BIGORBIT1 84 +#define BIGORBIT2 85 +#define BIGORBIT3 86 +#define BIGORBIT4 87 +#define BIGORBIT5 88 +#define LA 89 +#define REDSKY1 98 +#define REDSKY2 99 +#define ATOMICHEALTH 100 +#define TECHLIGHT2 120 +#define TECHLIGHTBUST2 121 +#define TECHLIGHT4 122 +#define TECHLIGHTBUST4 123 +#define WALLLIGHT4 124 +#define WALLLIGHTBUST4 125 +#define ACCESSSWITCH 130 +#define SLOTDOOR 132 +#define LIGHTSWITCH 134 +#define SPACEDOORSWITCH 136 +#define SPACELIGHTSWITCH 138 +#define FRANKENSTINESWITCH 140 +#define NUKEBUTTON 142 +#define MULTISWITCH 146 +#define DOORTILE5 150 +#define DOORTILE6 151 +#define DOORTILE1 152 +#define DOORTILE2 153 +#define DOORTILE3 154 +#define DOORTILE4 155 +#define DOORTILE7 156 +#define DOORTILE8 157 +#define DOORTILE9 158 +#define DOORTILE10 159 +#define DOORSHOCK 160 +#define DIPSWITCH 162 +#define DIPSWITCH2 164 +#define TECHSWITCH 166 +#define DIPSWITCH3 168 +#define ACCESSSWITCH2 170 +#define REFLECTWATERTILE 180 +#define FLOORSLIME 200 +#define BIGFORCE 230 +#define EPISODE 247 +#define MASKWALL9 255 +#define W_LIGHT 260 +#define SCREENBREAK1 263 +#define SCREENBREAK2 264 +#define SCREENBREAK3 265 +#define SCREENBREAK4 266 +#define SCREENBREAK5 267 +#define SCREENBREAK6 268 +#define SCREENBREAK7 269 +#define SCREENBREAK8 270 +#define SCREENBREAK9 271 +#define SCREENBREAK10 272 +#define SCREENBREAK11 273 +#define SCREENBREAK12 274 +#define SCREENBREAK13 275 +#define MASKWALL1 285 +#define W_TECHWALL1 293 +#define W_TECHWALL2 297 +#define W_TECHWALL15 299 +#define W_TECHWALL3 301 +#define W_TECHWALL4 305 +#define W_TECHWALL10 306 +#define W_TECHWALL16 307 +#define WATERTILE2 336 +#define BPANNEL1 341 +#define PANNEL1 342 +#define PANNEL2 343 +#define WATERTILE 344 +#define STATIC 351 +#define W_SCREENBREAK 357 +#define W_HITTECHWALL3 360 +#define W_HITTECHWALL4 361 +#define W_HITTECHWALL2 362 +#define W_HITTECHWALL1 363 +#define MASKWALL10 387 +#define MASKWALL11 391 +#define DOORTILE22 395 +#define FANSPRITE 407 +#define FANSPRITEBROKE 411 +#define FANSHADOW 412 +#define FANSHADOWBROKE 416 +#define DOORTILE18 447 +#define DOORTILE19 448 +#define DOORTILE20 449 +// #define SPACESHUTTLE 487 +#define SATELLITE 489 +#define VIEWSCREEN2 499 +#define VIEWSCREENBROKE 501 +#define VIEWSCREEN 502 +#define GLASS 503 +#define GLASS2 504 +#define STAINGLASS1 510 +#define MASKWALL5 514 +#define SATELITE 516 +#define FUELPOD 517 +#define SLIMEPIPE 538 +#define CRACK1 546 +#define CRACK2 547 +#define CRACK3 548 +#define CRACK4 549 +#define FOOTPRINTS 550 +#define DOMELITE 551 +#define CAMERAPOLE 554 +#define CHAIR1 556 +#define CHAIR2 557 +#define BROKENCHAIR 559 +#define MIRROR 560 +#define WATERFOUNTAIN 563 +#define WATERFOUNTAINBROKE 567 +#define FEMMAG1 568 +#define TOILET 569 +#define STALL 571 +#define STALLBROKE 573 +#define FEMMAG2 577 +#define REACTOR2 578 +#define REACTOR2BURNT 579 +#define REACTOR2SPARK 580 +#define GRATE1 595 +#define BGRATE1 596 +#define SOLARPANNEL 602 +#define NAKED1 603 +#define ANTENNA 607 +#define MASKWALL12 609 +#define TOILETBROKE 615 +#define PIPE2 616 +#define PIPE1B 617 +#define PIPE3 618 +#define PIPE1 619 +#define CAMERA1 621 +#define BRICK 626 +#define SPLINTERWOOD 630 +#define PIPE2B 633 +#define BOLT1 634 +#define W_NUMBERS 640 +#define WATERDRIP 660 +#define WATERBUBBLE 661 +#define WATERBUBBLEMAKER 662 +#define W_FORCEFIELD 663 +#define VACUUM 669 +#define FOOTPRINTS2 672 +#define FOOTPRINTS3 673 +#define FOOTPRINTS4 674 +#define EGG 675 +#define SCALE 678 +#define CHAIR3 680 +#define CAMERALIGHT 685 +#define MOVIECAMERA 686 +#define IVUNIT 689 +#define POT1 694 +#define POT2 695 +#define POT3 697 +#define PIPE3B 700 +#define WALLLIGHT3 701 +#define WALLLIGHTBUST3 702 +#define WALLLIGHT1 703 +#define WALLLIGHTBUST1 704 +#define WALLLIGHT2 705 +#define WALLLIGHTBUST2 706 +#define LIGHTSWITCH2 712 +#define WAITTOBESEATED 716 +#define DOORTILE14 717 +#define STATUE 753 +#define MIKE 762 +#define VASE 765 +#define SUSHIPLATE1 768 +#define SUSHIPLATE2 769 +#define SUSHIPLATE3 774 +#define SUSHIPLATE4 779 +#define DOORTILE16 781 +#define SUSHIPLATE5 792 +#define OJ 806 +#define MASKWALL13 830 +#define HURTRAIL 859 +#define POWERSWITCH1 860 +#define LOCKSWITCH1 862 +#define POWERSWITCH2 864 +#define ATM 867 +#define STATUEFLASH 869 +#define ATMBROKE 888 +#define BIGHOLE2 893 +#define STRIPEBALL 901 +#define QUEBALL 902 +#define POCKET 903 +#define WOODENHORSE 904 +#define TREE1 908 +#define TREE2 910 +#define CACTUS 911 +#define MASKWALL2 913 +#define MASKWALL3 914 +#define MASKWALL4 915 +#define FIREEXT 916 +#define TOILETWATER 921 +#define NEON1 925 +#define NEON2 926 +#define CACTUSBROKE 939 +#define BOUNCEMINE 940 +#define BROKEFIREHYDRENT 950 +#define BOX 951 +#define BULLETHOLE 952 +#define BOTTLE1 954 +#define BOTTLE2 955 +#define BOTTLE3 956 +#define BOTTLE4 957 +#define FEMPIC5 963 +#define FEMPIC6 964 +#define FEMPIC7 965 +#define HYDROPLANT 969 +#define OCEANSPRITE1 971 +#define OCEANSPRITE2 972 +#define OCEANSPRITE3 973 +#define OCEANSPRITE4 974 +#define OCEANSPRITE5 975 +#define GENERICPOLE 977 +#define CONE 978 +#define HANGLIGHT 979 +#define HYDRENT 981 +#define MASKWALL14 988 +#define TIRE 990 +#define PIPE5 994 +#define PIPE6 995 +#define PIPE4 996 +#define PIPE4B 997 +#define BROKEHYDROPLANT 1003 +#define PIPE5B 1005 +#define NEON3 1007 +#define NEON4 1008 +#define NEON5 1009 +#define BOTTLE5 1012 +#define BOTTLE6 1013 +#define BOTTLE8 1014 +#define SPOTLITE 1020 +#define HANGOOZ 1022 +#define MASKWALL15 1024 +#define BOTTLE7 1025 +#define HORSEONSIDE 1026 +#define GLASSPIECES 1031 +#define HORSELITE 1034 +#define DONUTS 1045 +#define NEON6 1046 +#define MASKWALL6 1059 +#define CLOCK 1060 +#define RUBBERCAN 1062 +#define BROKENCLOCK 1067 +#define PLUG 1069 +#define OOZFILTER 1079 +#define FLOORPLASMA 1082 +#define REACTOR 1088 +#define REACTORSPARK 1092 +#define REACTORBURNT 1096 +#define DOORTILE15 1102 +#define HANDSWITCH 1111 +#define CIRCLEPANNEL 1113 +#define CIRCLEPANNELBROKE 1114 +#define PULLSWITCH 1122 +#define MASKWALL8 1124 +#define BIGHOLE 1141 +#define ALIENSWITCH 1142 +#define DOORTILE21 1144 +#define HANDPRINTSWITCH 1155 +#define BOTTLE10 1157 +#define BOTTLE11 1158 +#define BOTTLE12 1159 +#define BOTTLE13 1160 +#define BOTTLE14 1161 +#define BOTTLE15 1162 +#define BOTTLE16 1163 +#define BOTTLE17 1164 +#define BOTTLE18 1165 +#define BOTTLE19 1166 +#define DOORTILE17 1169 +#define MASKWALL7 1174 +#define JAILBARBREAK 1175 +#define DOORTILE11 1178 +#define DOORTILE12 1179 +#define VENDMACHINE 1212 +#define VENDMACHINEBROKE 1214 +#define COLAMACHINE 1215 +#define COLAMACHINEBROKE 1217 +#define CRANEPOLE 1221 +#define CRANE 1222 +#define BARBROKE 1225 +#define BLOODPOOL 1226 +#define NUKEBARREL 1227 +#define NUKEBARRELDENTED 1228 +#define NUKEBARRELLEAKED 1229 +#define CANWITHSOMETHING 1232 +#define MONEY 1233 +#define BANNER 1236 +#define EXPLODINGBARREL 1238 +#define EXPLODINGBARREL2 1239 +#define FIREBARREL 1240 +#define SEENINE 1247 +#define SEENINEDEAD 1248 +#define STEAM 1250 +#define CEILINGSTEAM 1255 +#define PIPE6B 1260 +#define TRANSPORTERBEAM 1261 +#define RAT 1267 +#define TRASH 1272 +#define FEMPIC1 1280 +#define FEMPIC2 1289 +#define BLANKSCREEN 1293 +#define PODFEM1 1294 +#define FEMPIC3 1298 +#define FEMPIC4 1306 +#define FEM1 1312 +#define FEM2 1317 +#define FEM3 1321 +#define FEM5 1323 +#define BLOODYPOLE 1324 +#define FEM4 1325 +#define FEM6 1334 +#define FEM6PAD 1335 +#define FEM8 1336 +#define HELECOPT 1346 +#define FETUSJIB 1347 +#define HOLODUKE 1348 +#define SPACEMARINE 1353 +#define INDY 1355 +#define FETUS 1358 +#define FETUSBROKE 1359 +#define MONK 1352 +#define LUKE 1354 +#define COOLEXPLOSION1 1360 +#define WATERSPLASH2 1380 +#define FIREVASE 1390 +#define SCRATCH 1393 +#define FEM7 1395 +#define APLAYERTOP 1400 +#define APLAYER 1405 +#define PLAYERONWATER 1420 +#define DUKELYINGDEAD 1518 +#define DUKETORSO 1520 +#define DUKEGUN 1528 +#define DUKELEG 1536 +#define SHARK 1550 +#define BLOOD 1620 +#define FIRELASER 1625 +#define TRANSPORTERSTAR 1630 +#define SPIT 1636 +#define LOOGIE 1637 +#define FIST 1640 +#define FREEZEBLAST 1641 +#define DEVISTATORBLAST 1642 +#define SHRINKSPARK 1646 +#define TONGUE 1647 +#define MORTER 1650 +#define SHRINKEREXPLOSION 1656 +#define RADIUSEXPLOSION 1670 +#define FORCERIPPLE 1671 +#define LIZTROOP 1680 +#define LIZTROOPRUNNING 1681 +#define LIZTROOPSTAYPUT 1682 +#define LIZTOP 1705 +#define LIZTROOPSHOOT 1715 +#define LIZTROOPJETPACK 1725 +#define LIZTROOPDSPRITE 1734 +#define LIZTROOPONTOILET 1741 +#define LIZTROOPJUSTSIT 1742 +#define LIZTROOPDUCKING 1744 +#define HEADJIB1 1768 +#define ARMJIB1 1772 +#define LEGJIB1 1776 +#define CANNONBALL 1817 +#define OCTABRAIN 1820 +#define OCTABRAINSTAYPUT 1821 +#define OCTATOP 1845 +#define OCTADEADSPRITE 1855 +#define INNERJAW 1860 +#define DRONE 1880 +#define EXPLOSION2 1890 +#define COMMANDER 1920 +#define COMMANDERSTAYPUT 1921 +#define RECON 1960 +#define TANK 1975 +#define PIGCOP 2000 +#define PIGCOPSTAYPUT 2001 +#define PIGCOPDIVE 2045 +#define PIGCOPDEADSPRITE 2060 +#define PIGTOP 2061 +#define LIZMAN 2120 +#define LIZMANSTAYPUT 2121 +#define LIZMANSPITTING 2150 +#define LIZMANFEEDING 2160 +#define LIZMANJUMP 2165 +#define LIZMANDEADSPRITE 2185 +#define FECES 2200 +#define LIZMANHEAD1 2201 +#define LIZMANARM1 2205 +#define LIZMANLEG1 2209 +#define EXPLOSION2BOT 2219 +#define USERWEAPON 2235 +#define HEADERBAR 2242 +#define JIBS1 2245 +#define JIBS2 2250 +#define JIBS3 2255 +#define JIBS4 2260 +#define JIBS5 2265 +#define BURNING 2270 +#define FIRE 2271 +#define JIBS6 2286 +#define BLOODSPLAT1 2296 +#define BLOODSPLAT3 2297 +#define BLOODSPLAT2 2298 +#define BLOODSPLAT4 2299 +#define OOZ 2300 +#define OOZ2 2309 +#define WALLBLOOD1 2301 +#define WALLBLOOD2 2302 +#define WALLBLOOD3 2303 +#define WALLBLOOD4 2304 +#define WALLBLOOD5 2305 +#define WALLBLOOD6 2306 +#define WALLBLOOD7 2307 +#define WALLBLOOD8 2308 +#define BURNING2 2310 +#define FIRE2 2311 +#define CRACKKNUCKLES 2324 +#define SMALLSMOKE 2329 +#define SMALLSMOKEMAKER 2330 +#define FLOORFLAME 2333 +#define ROTATEGUN 2360 +#define GREENSLIME 2370 +#define WATERDRIPSPLASH 2380 +#define SCRAP6 2390 +#define SCRAP1 2400 +#define SCRAP2 2404 +#define SCRAP3 2408 +#define SCRAP4 2412 +#define SCRAP5 2416 +#define ORGANTIC 2420 +#define BETAVERSION 2440 +#define PLAYERISHERE 2442 +#define PLAYERWASHERE 2443 +#define SELECTDIR 2444 +#define F1HELP 2445 +#define NOTCHON 2446 +#define NOTCHOFF 2447 +#define GROWSPARK 2448 +#define DUKEICON 2452 +#define BADGUYICON 2453 +#define FOODICON 2454 +#define GETICON 2455 +#define MENUSCREEN 2456 +#define MENUBAR 2457 +#define KILLSICON 2458 +#define FIRSTAID_ICON 2460 +#define HEAT_ICON 2461 +#define BOTTOMSTATUSBAR 2462 +#define BOOT_ICON 2463 +#define FRAGBAR 2465 +#define JETPACK_ICON 2467 +#define AIRTANK_ICON 2468 +#define STEROIDS_ICON 2469 +#define HOLODUKE_ICON 2470 +#define ACCESS_ICON 2471 +#define DIGITALNUM 2472 +#define DUKECAR 2491 +#define CAMCORNER 2482 +#define CAMLIGHT 2484 +#define LOGO 2485 +#define TITLE 2486 +#define NUKEWARNINGICON 2487 +#define MOUSECURSOR 2488 +#define SLIDEBAR 2489 +#define DREALMS 2492 +#define BETASCREEN 2493 +#define WINDOWBORDER1 2494 +#define TEXTBOX 2495 +#define WINDOWBORDER2 2496 +#define DUKENUKEM 2497 +#define THREEDEE 2498 +#define INGAMEDUKETHREEDEE 2499 +#define TENSCREEN 2500 +#define PLUTOPAKSPRITE 2501 +#define DEVISTATOR 2510 +#define KNEE 2521 +#define CROSSHAIR 2523 +#define FIRSTGUN 2524 +#define FIRSTGUNRELOAD 2528 +#define FALLINGCLIP 2530 +#define CLIPINHAND 2531 +#define HAND 2532 +#define SHELL 2533 +#define SHOTGUNSHELL 2535 +#define CHAINGUN 2536 +#define RPGGUN 2544 +#define RPGMUZZLEFLASH 2545 +#define FREEZE 2548 +#define CATLITE 2552 +#define SHRINKER 2556 +#define HANDHOLDINGLASER 2563 +#define TRIPBOMB 2566 +#define LASERLINE 2567 +#define HANDHOLDINGACCESS 2568 +#define HANDREMOTE 2570 +#define HANDTHROW 2573 +#define TIP 2576 +#define GLAIR 2578 +#define SCUBAMASK 2581 +#define SPACEMASK 2584 +#define FORCESPHERE 2590 +#define SHOTSPARK1 2595 +#define RPG 2605 +#define LASERSITE 2612 +#define SHOTGUN 2613 +#define BOSS1 2630 +#define BOSS1STAYPUT 2631 +#define BOSS1SHOOT 2660 +#define BOSS1LOB 2670 +#define BOSSTOP 2696 +#define BOSS2 2710 +#define BOSS3 2760 +#define SPINNINGNUKEICON 2813 +#define BIGFNTCURSOR 2820 +#define SMALLFNTCURSOR 2821 +#define STARTALPHANUM 2822 +#define ENDALPHANUM 2915 +#define BIGALPHANUM 2940 +#define BIGPERIOD 3002 +#define BIGCOMMA 3003 +#define BIGX 3004 +#define BIGQ 3005 +#define BIGSEMI 3006 +#define BIGCOLIN 3007 +#define THREEBYFIVE 3010 +#define BIGAPPOS 3022 +#define BLANK 3026 +#define MINIFONT 3072 +#define BUTTON1 3164 +#define GLASS3 3187 +#define RESPAWNMARKERRED 3190 +#define RESPAWNMARKERYELLOW 3200 +#define RESPAWNMARKERGREEN 3210 +#define BONUSSCREEN 3240 +#define VIEWBORDER 3250 +#define VICTORY1 3260 +#define ORDERING 3270 +#define TEXTSTORY 3280 +#define LOADSCREEN 3281 +#define BORNTOBEWILDSCREEN 3370 +#define BLIMP 3400 +#define FEM9 3450 +#define FOOTPRINT 3701 +#define POOP 4094 +#define FRAMEEFFECT1 4095 +#define PANNEL3 4099 +#define SCREENBREAK19 4125 +#define W_TECHWALL11 4130 +#define W_TECHWALL12 4131 +#define W_TECHWALL13 4132 +#define W_TECHWALL14 4133 +#define SCREENBREAK14 4120 +#define SCREENBREAK15 4123 +#define SCREENBREAK16 4127 +#define SCREENBREAK17 4128 +#define SCREENBREAK18 4129 +#define W_TECHWALL5 4134 +#define W_TECHWALL6 4136 +#define W_TECHWALL7 4138 +#define W_TECHWALL8 4140 +#define W_TECHWALL9 4142 +#define BPANNEL3 4100 +#define MIMON 4120 +#define W_HITTECHWALL16 4144 +#define W_HITTECHWALL10 4145 +#define W_HITTECHWALL15 4147 +#define W_MILKSHELF 4181 +#define W_MILKSHELFBROKE 4203 +#define PURPLELAVA 4240 +#define LAVABUBBLE 4340 +#define DUKECUTOUT 4352 +#define TARGET 4359 +#define GUNPOWDERBARREL 4360 +#define DUCK 4361 +#define HATRACK 4367 +#define DESKLAMP 4370 +#define COFFEEMACHINE 4372 +#define CUPS 4373 +#define GAVALS 4374 +#define GAVALS2 4375 +#define POLICELIGHTPOLE 4377 +#define FLOORBASKET 4388 +#define PUKE 4389 +#define DOORTILE23 4391 +#define TOPSECRET 4396 +#define SPEAKER 4397 +#define TEDDYBEAR 4400 +#define ROBOTDOG 4402 +#define ROBOTPIRATE 4404 +#define ROBOTMOUSE 4407 +#define MAIL 4410 +#define MAILBAG 4413 +#define HOTMEAT 4427 +#define COFFEEMUG 4438 +#define DONUTS2 4440 +#define TRIPODCAMERA 4444 +#define METER 4453 +#define DESKPHONE 4454 +#define GUMBALLMACHINE 4458 +#define GUMBALLMACHINEBROKE 4459 +#define PAPER 4460 +#define MACE 4464 +#define GENERICPOLE2 4465 +#define XXXSTACY 4470 +#define WETFLOOR 4495 +#define BROOM 4496 +#define MOP 4497 +#define PIRATE1A 4510 +#define PIRATE4A 4511 +#define PIRATE2A 4512 +#define PIRATE5A 4513 +#define PIRATE3A 4514 +#define PIRATE6A 4515 +#define PIRATEHALF 4516 +#define CHESTOFGOLD 4520 +#define SIDEBOLT1 4525 +#define FOODOBJECT1 4530 +#define FOODOBJECT2 4531 +#define FOODOBJECT3 4532 +#define FOODOBJECT4 4533 +#define FOODOBJECT5 4534 +#define FOODOBJECT6 4535 +#define FOODOBJECT7 4536 +#define FOODOBJECT8 4537 +#define FOODOBJECT9 4538 +#define FOODOBJECT10 4539 +#define FOODOBJECT11 4540 +#define FOODOBJECT12 4541 +#define FOODOBJECT13 4542 +#define FOODOBJECT14 4543 +#define FOODOBJECT15 4544 +#define FOODOBJECT16 4545 +#define FOODOBJECT17 4546 +#define FOODOBJECT18 4547 +#define FOODOBJECT19 4548 +#define FOODOBJECT20 4549 +#define HEADLAMP 4550 +#define TAMPON 4557 +#define SKINNEDCHICKEN 4554 +#define FEATHEREDCHICKEN 4555 +#define ROBOTDOG2 4560 +#define JOLLYMEAL 4569 +#define DUKEBURGER 4570 +#define SHOPPINGCART 4576 +#define CANWITHSOMETHING2 4580 +#define CANWITHSOMETHING3 4581 +#define CANWITHSOMETHING4 4582 +#define SNAKEP 4590 +#define DOLPHIN1 4591 +#define DOLPHIN2 4592 +#define NEWBEAST 4610 +#define NEWBEASTSTAYPUT 4611 +#define NEWBEASTJUMP 4690 +#define NEWBEASTHANG 4670 +#define NEWBEASTHANGDEAD 4671 +#define BOSS4 4740 +#define BOSS4STAYPUT 4741 +#define FEM10 4864 +#define TOUGHGAL 4866 +#define MAN 4871 +#define MAN2 4872 +#define WOMAN 4874 +#define PLEASEWAIT 4887 +#define NATURALLIGHTNING 4890 +#define WEATHERWARN 4893 +#define DUKETAG 4900 +#define SIGN1 4909 +#define SIGN2 4912 +#define JURYGUY 4943 + + + + +// These tile positions are reserved! +#define RESERVEDSLOT1 6132 +#define RESERVEDSLOT2 6133 +#define RESERVEDSLOT3 6134 +#define RESERVEDSLOT4 6135 +#define RESERVEDSLOT5 6136 +#define RESERVEDSLOT6 6137 +#define RESERVEDSLOT7 6138 +#define RESERVEDSLOT8 6139 +#define RESERVEDSLOT9 6140 +#define RESERVEDSLOT10 6141 +#define RESERVEDSLOT11 6142 +#define RESERVEDSLOT12 6143 + +// Defines weapon, not to be used with the 'shoot' keyword. + +#define KNEE_WEAPON 0 +#define PISTOL_WEAPON 1 +#define SHOTGUN_WEAPON 2 +#define CHAINGUN_WEAPON 3 +#define RPG_WEAPON 4 +#define HANDBOMB_WEAPON 5 +#define SHRINKER_WEAPON 6 +#define DEVISTATOR_WEAPON 7 +#define TRIPBOMB_WEAPON 8 +#define FREEZE_WEAPON 9 +#define HANDREMOTE_WEAPON 10 +#define GROW_WEAPON 11 + +// Defines the motion characteristics of an actor +#define faceplayer 1 +#define geth 2 +#define getv 4 +#define randomangle 8 +#define faceplayerslow 16 +#define spin 32 +#define faceplayersmart 64 +#define fleeenemy 128 +#define jumptoplayer 257 +#define seekplayer 512 +#define furthestdir 1024 +#define dodgebullet 4096 + +// Some misc #defines +#define NO 0 +#define YES 1 + +// Defines for 'useractor' keyword +#define notenemy 0 +#define enemy 1 +#define enemystayput 2 + +// Player Actions. +#define pstanding 1 +#define pwalking 2 +#define prunning 4 +#define pducking 8 +#define pfalling 16 +#define pjumping 32 +#define phigher 64 +#define pwalkingback 128 +#define prunningback 256 +#define pkicking 512 +#define pshrunk 1024 +#define pjetpack 2048 +#define ponsteroids 4096 +#define ponground 8192 +#define palive 16384 +#define pdead 32768 +#define pfacing 65536 + + +#define GET_STEROIDS 0 +#define GET_SHIELD 1 +#define GET_SCUBA 2 +#define GET_HOLODUKE 3 +#define GET_JETPACK 4 +#define GET_ACCESS 6 +#define GET_HEATS 7 +#define GET_FIRSTAID 9 +#define GET_BOOTS 10 + + +#define KICK_HIT 0 +#define PISTOL_RICOCHET 1 +#define PISTOL_BODYHIT 2 +#define PISTOL_FIRE 3 +#define EJECT_CLIP 4 +#define INSERT_CLIP 5 +#define CHAINGUN_FIRE 6 +#define RPG_SHOOT 7 +#define POOLBALLHIT 8 +#define RPG_EXPLODE 9 +#define CAT_FIRE 10 +#define SHRINKER_FIRE 11 +#define ACTOR_SHRINKING 12 +#define PIPEBOMB_BOUNCE 13 +#define PIPEBOMB_EXPLODE 14 +#define LASERTRIP_ONWALL 15 +#define LASERTRIP_ARMING 16 +#define LASERTRIP_EXPLODE 17 +#define VENT_BUST 18 +#define GLASS_BREAKING 19 +#define GLASS_HEAVYBREAK 20 +#define SHORT_CIRCUIT 21 +#define ITEM_SPLASH 22 +#define DUKE_BREATHING 23 +#define DUKE_EXHALING 24 +#define DUKE_GASP 25 +#define SLIM_RECOG 26 +// #define ENDSEQVOL3SND1 27 +#define DUKE_URINATE 28 +#define ENDSEQVOL3SND2 29 +#define ENDSEQVOL3SND3 30 +#define DUKE_PASSWIND 32 +#define DUKE_CRACK 33 +#define SLIM_ATTACK 34 +#define SOMETHINGHITFORCE 35 +#define DUKE_DRINKING 36 +#define DUKE_KILLED1 37 +#define DUKE_GRUNT 38 +#define DUKE_HARTBEAT 39 +#define DUKE_ONWATER 40 +#define DUKE_DEAD 41 +#define DUKE_LAND 42 +#define DUKE_WALKINDUCTS 43 +#define DUKE_GLAD 44 +#define DUKE_YES 45 +#define DUKE_HEHE 46 +#define DUKE_SHUCKS 47 +#define DUKE_UNDERWATER 48 +#define DUKE_JETPACK_ON 49 +#define DUKE_JETPACK_IDLE 50 +#define DUKE_JETPACK_OFF 51 +#define LIZTROOP_GROWL 52 +#define LIZTROOP_TALK1 53 +#define LIZTROOP_TALK2 54 +#define LIZTROOP_TALK3 55 +#define DUKETALKTOBOSS 56 +#define LIZCAPT_GROWL 57 +#define LIZCAPT_TALK1 58 +#define LIZCAPT_TALK2 59 +#define LIZCAPT_TALK3 60 +#define LIZARD_BEG 61 +#define LIZARD_PAIN 62 +#define LIZARD_DEATH 63 +#define LIZARD_SPIT 64 +#define DRONE1_HISSRATTLE 65 +#define DRONE1_HISSSCREECH 66 +#define DUKE_TIP2 67 +#define FLESH_BURNING 68 +#define SQUISHED 69 +#define TELEPORTER 70 +#define ELEVATOR_ON 71 +#define DUKE_KILLED3 72 +#define ELEVATOR_OFF 73 +#define DOOR_OPERATE1 74 +#define SUBWAY 75 +#define SWITCH_ON 76 +#define FAN 77 +#define DUKE_GETWEAPON3 78 +#define FLUSH_TOILET 79 +#define HOVER_CRAFT 80 +#define EARTHQUAKE 81 +#define INTRUDER_ALERT 82 +#define END_OF_LEVEL_WARN 83 +#define ENGINE_OPERATING 84 +#define REACTOR_ON 85 +#define COMPUTER_AMBIENCE 86 +#define GEARS_GRINDING 87 +#define BUBBLE_AMBIENCE 88 +#define MACHINE_AMBIENCE 89 +#define SEWER_AMBIENCE 90 +#define WIND_AMBIENCE 91 +#define SOMETHING_DRIPPING 92 +#define STEAM_HISSING 93 +#define THEATER_BREATH 94 +#define BAR_MUSIC 95 +#define BOS1_ROAM 96 +#define BOS1_RECOG 97 +#define BOS1_ATTACK1 98 +#define BOS1_PAIN 99 +#define BOS1_DYING 100 +#define BOS2_ROAM 101 +#define BOS2_RECOG 102 +#define BOS2_ATTACK 103 +#define BOS2_PAIN 104 +#define BOS2_DYING 105 +#define GETATOMICHEALTH 106 +#define DUKE_GETWEAPON2 107 +#define BOS3_DYING 108 +#define SHOTGUN_FIRE 109 +#define PRED_ROAM 110 +#define PRED_RECOG 111 +#define PRED_ATTACK 112 +#define PRED_PAIN 113 +#define PRED_DYING 114 +#define CAPT_ROAM 115 +#define CAPT_ATTACK 116 +#define CAPT_RECOG 117 +#define CAPT_PAIN 118 +#define CAPT_DYING 119 +#define PIG_ROAM 120 +#define PIG_RECOG 121 +#define PIG_ATTACK 122 +#define PIG_PAIN 123 +#define PIG_DYING 124 +#define RECO_ROAM 125 +#define RECO_RECOG 126 +#define RECO_ATTACK 127 +#define RECO_PAIN 128 +#define RECO_DYING 129 +#define DRON_ROAM 130 +#define DRON_RECOG 131 +#define DRON_ATTACK1 132 +#define DRON_PAIN 133 +#define DRON_DYING 134 +#define COMM_ROAM 135 +#define COMM_RECOG 136 +#define COMM_ATTACK 137 +#define COMM_PAIN 138 +#define COMM_DYING 139 +#define OCTA_ROAM 140 +#define OCTA_RECOG 141 +#define OCTA_ATTACK1 142 +#define OCTA_PAIN 143 +#define OCTA_DYING 144 +#define TURR_ROAM 145 +#define TURR_RECOG 146 +#define TURR_ATTACK 147 +#define DUMPSTER_MOVE 148 +#define SLIM_DYING 149 +#define BOS3_ROAM 150 +#define BOS3_RECOG 151 +#define BOS3_ATTACK1 152 +#define BOS3_PAIN 153 +#define BOS1_ATTACK2 154 +#define COMM_SPIN 155 +#define BOS1_WALK 156 +#define DRON_ATTACK2 157 +#define THUD 158 +#define OCTA_ATTACK2 159 +#define WIERDSHOT_FLY 160 +#define TURR_PAIN 161 +#define TURR_DYING 162 +#define SLIM_ROAM 163 +#define LADY_SCREAM 164 +#define DOOR_OPERATE2 165 +#define DOOR_OPERATE3 166 +#define DOOR_OPERATE4 167 +#define BORNTOBEWILDSND 168 +#define SHOTGUN_COCK 169 +#define GENERIC_AMBIENCE1 170 +#define GENERIC_AMBIENCE2 171 +#define GENERIC_AMBIENCE3 172 +#define GENERIC_AMBIENCE4 173 +#define GENERIC_AMBIENCE5 174 +#define GENERIC_AMBIENCE6 175 +#define BOS3_ATTACK2 176 +#define GENERIC_AMBIENCE17 177 +#define GENERIC_AMBIENCE18 178 +#define GENERIC_AMBIENCE19 179 +#define GENERIC_AMBIENCE20 180 +#define GENERIC_AMBIENCE21 181 +#define GENERIC_AMBIENCE22 182 +#define SECRETLEVELSND 183 +#define GENERIC_AMBIENCE8 184 +#define GENERIC_AMBIENCE9 185 +#define GENERIC_AMBIENCE10 186 +#define GENERIC_AMBIENCE11 187 +#define GENERIC_AMBIENCE12 188 +#define GENERIC_AMBIENCE13 189 +#define GENERIC_AMBIENCE14 190 +#define GENERIC_AMBIENCE15 192 +#define GENERIC_AMBIENCE16 193 +#define FIRE_CRACKLE 194 +#define BONUS_SPEECH1 195 +#define BONUS_SPEECH2 196 +#define BONUS_SPEECH3 197 +#define PIG_CAPTURE_DUKE 198 +#define BONUS_SPEECH4 199 +#define DUKE_LAND_HURT 200 +#define DUKE_HIT_STRIPPER1 201 +#define DUKE_TIP1 202 +#define DUKE_KILLED2 203 +#define PRED_ROAM2 204 +#define PIG_ROAM2 205 +#define DUKE_GETWEAPON1 206 +#define DUKE_SEARCH2 207 +#define DUKE_CRACK2 208 +#define DUKE_SEARCH 209 +#define DUKE_GET 210 +#define DUKE_LONGTERM_PAIN 211 +#define MONITOR_ACTIVE 212 +#define NITEVISION_ONOFF 213 +#define DUKE_HIT_STRIPPER2 214 +#define DUKE_CRACK_FIRST 215 +#define DUKE_USEMEDKIT 216 +#define DUKE_TAKEPILLS 217 +#define DUKE_PISSRELIEF 218 +#define SELECT_WEAPON 219 +#define WATER_GURGLE 220 +#define DUKE_GETWEAPON4 221 +#define JIBBED_ACTOR1 222 +#define JIBBED_ACTOR2 223 +#define JIBBED_ACTOR3 224 +#define JIBBED_ACTOR4 225 +#define JIBBED_ACTOR5 226 +#define JIBBED_ACTOR6 227 +#define JIBBED_ACTOR7 228 +#define DUKE_GOTHEALTHATLOW 229 +#define BOSSTALKTODUKE 230 +#define WAR_AMBIENCE1 231 +#define WAR_AMBIENCE2 232 +#define WAR_AMBIENCE3 233 +#define WAR_AMBIENCE4 234 +#define WAR_AMBIENCE5 235 +#define WAR_AMBIENCE6 236 +#define WAR_AMBIENCE7 237 +#define WAR_AMBIENCE8 238 +#define WAR_AMBIENCE9 239 +#define WAR_AMBIENCE10 240 +#define ALIEN_TALK1 241 +#define ALIEN_TALK2 242 +#define EXITMENUSOUND 243 +#define FLY_BY 244 +#define DUKE_SCREAM 245 +#define SHRINKER_HIT 246 +#define RATTY 247 +#define INTO_MENU 248 +#define BONUSMUSIC 249 +#define DUKE_BOOBY 250 +#define DUKE_TALKTOBOSSFALL 251 +#define DUKE_LOOKINTOMIRROR 252 +#define PIG_ROAM3 253 +#define KILLME 254 +#define DRON_JETSND 255 +#define SPACE_DOOR1 256 +#define SPACE_DOOR2 257 +#define SPACE_DOOR3 258 +#define SPACE_DOOR4 259 +#define SPACE_DOOR5 260 +#define ALIEN_ELEVATOR1 261 +#define VAULT_DOOR 262 +#define JIBBED_ACTOR13 263 +#define DUKE_GETWEAPON6 264 +#define JIBBED_ACTOR8 265 +#define JIBBED_ACTOR9 266 +#define JIBBED_ACTOR10 267 +#define JIBBED_ACTOR11 268 +#define JIBBED_ACTOR12 269 +#define DUKE_KILLED4 270 +#define DUKE_KILLED5 271 +#define ALIEN_SWITCH1 272 +#define DUKE_STEPONFECES 273 +#define DUKE_LONGTERM_PAIN2 274 +#define DUKE_LONGTERM_PAIN3 275 +#define DUKE_LONGTERM_PAIN4 276 +#define COMPANB2 277 +#define KTIT 278 +#define HELICOP_IDLE 279 +#define STEPNIT 280 +#define SPACE_AMBIENCE1 281 +#define SPACE_AMBIENCE2 282 +#define SLIM_HATCH 283 +#define RIPHEADNECK 284 +#define FOUNDJONES 285 +#define ALIEN_DOOR1 286 +#define ALIEN_DOOR2 287 +#define ENDSEQVOL3SND4 288 +#define ENDSEQVOL3SND5 289 +#define ENDSEQVOL3SND6 290 +#define ENDSEQVOL3SND7 291 +#define ENDSEQVOL3SND8 292 +#define ENDSEQVOL3SND9 293 +#define WHIPYOURASS 294 +#define ENDSEQVOL2SND1 295 +#define ENDSEQVOL2SND2 296 +#define ENDSEQVOL2SND3 297 +#define ENDSEQVOL2SND4 298 +#define ENDSEQVOL2SND5 299 +#define ENDSEQVOL2SND6 300 +#define ENDSEQVOL2SND7 301 +#define GENERIC_AMBIENCE23 302 +#define SOMETHINGFROZE 303 +#define DUKE_LONGTERM_PAIN5 304 +#define DUKE_LONGTERM_PAIN6 305 +#define DUKE_LONGTERM_PAIN7 306 +#define DUKE_LONGTERM_PAIN8 307 +#define WIND_REPEAT 308 +#define MYENEMY_ROAM 309 +#define MYENEMY_HURT 310 +#define MYENEMY_DEAD 311 +#define MYENEMY_SHOOT 312 +#define STORE_MUSIC 313 +#define STORE_MUSIC_BROKE 314 +#define ACTOR_GROWING 315 +#define NEWBEAST_ROAM 316 +#define NEWBEAST_RECOG 317 +#define NEWBEAST_ATTACK 318 +#define NEWBEAST_PAIN 319 +#define NEWBEAST_DYING 320 +#define NEWBEAST_SPIT 321 +#define VOL4_1 322 +#define SUPERMARKET 323 +#define MOUSEANNOY 324 +#define BOOKEM 325 +#define SUPERMARKETCRY 326 +#define DESTRUCT 327 +#define EATFOOD 328 +#define MAKEMYDAY 329 +#define WITNESSSTAND 330 +#define VACATIONSPEECH 331 +#define YIPPEE1 332 +#define YOHOO1 333 +#define YOHOO2 334 +#define DOLPHINSND 335 +#define TOUGHGALSND1 336 +#define TOUGHGALSND2 337 +#define TOUGHGALSND3 338 +#define TOUGHGALSND4 339 +#define TANK_ROAM 340 +#define BOS4_ROAM 341 +#define BOS4_RECOG 342 +#define BOS4_ATTACK 343 +#define BOS4_PAIN 344 +#define BOS4_DYING 345 +#define NEWBEAST_ATTACKMISS 346 +#define VOL4_2 347 +#define COOKINGDEEPFRIER 348 +#define WHINING_DOG 349 +#define DEAD_DOG 350 +#define LIGHTNING_SLAP 351 +#define THUNDER 352 +#define HAPPYMOUSESND1 353 +#define HAPPYMOUSESND2 354 +#define HAPPYMOUSESND3 355 +#define HAPPYMOUSESND4 356 +#define ALARM 357 +#define RAIN 358 +#define DTAG_GREENRUN 359 +#define DTAG_BROWNRUN 360 +#define DTAG_GREENSCORE 361 +#define DTAG_BROWNSCORE 362 +#define INTRO4_1 363 +#define INTRO4_2 364 +#define INTRO4_3 365 +#define INTRO4_4 366 +#define INTRO4_5 367 +#define INTRO4_6 368 +#define SCREECH 369 +#define BOSS4_DEADSPEECH 370 +#define BOSS4_FIRSTSEE 371 +#define PARTY_SPEECH 372 +#define POSTAL_SPEECH 373 +#define TGSPEECH 374 +#define DOGROOMSPEECH 375 +#define SMACKED 376 +#define MDEVSPEECH 377 +#define AREA51SPEECH 378 +#define JEEPSOUND 379 +#define BIGDOORSLAM 380 +#define BOS4_LAY 381 +#define WAVESOUND 382 +#define ILLBEBACK 383 +#define VOL4ENDSND1 384 +#define VOL4ENDSND2 385 +#define EXPANDERHIT 386 +#define SNAKESPEECH 387 +#define EXPANDERSHOOT 388 +#define GETBACKTOWORK 389 +#define JIBBED_ACTOR14 390 +#define JIBBED_ACTOR15 391 +#define INTRO4_B 392 +#define BIGBANG 393 +#define SMACKIT 394 +#define BELLSND 395 +// MAXIMUM NUMBER OF SOUNDS: 450 ( 0-449 ) diff --git a/sounds.c b/sounds.c new file mode 100755 index 0000000..daa5025 --- /dev/null +++ b/sounds.c @@ -0,0 +1,687 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment + +This file is part of Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Original Source: 1996 - Todd Replogle +Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms +*/ +//------------------------------------------------------------------------- + +#if PLATFORM_DOS +#include +#endif + +#include +#include +#include "types.h" +#include "sndcards.h" +#include "fx_man.h" +#include "music.h" +#include "util_lib.h" +#include "duke3d.h" + + +#define LOUDESTVOLUME 150 + +long backflag,numenvsnds; + +/* +=================== += += SoundStartup += +=================== +*/ + +void SoundStartup( void ) + { + int32 status; + + // if they chose None lets return + if (FXDevice == NumSoundCards) return; + + // Do special Sound Blaster, AWE32 stuff + if ( + ( FXDevice == SoundBlaster ) || + ( FXDevice == Awe32 ) + ) + { + int MaxVoices; + int MaxBits; + int MaxChannels; + + status = FX_SetupSoundBlaster + ( + BlasterConfig, (int *)&MaxVoices, (int *)&MaxBits, (int *)&MaxChannels + ); + } + else + { + status = FX_Ok; + } + + if ( status == FX_Ok ) + { + if ( eightytwofifty && numplayers > 1) + { + status = FX_Init( FXDevice, min( NumVoices,4 ), 1, 8, 8000 ); + } + else + { + status = FX_Init( FXDevice, NumVoices, NumChannels, NumBits, MixRate ); + } + if ( status == FX_Ok ) + { + + FX_SetVolume( FXVolume ); + if (ReverseStereo == 1) + { + FX_SetReverseStereo(!FX_GetReverseStereo()); + } + } + } + if ( status != FX_Ok ) + { + Error( FX_ErrorString( FX_Error )); + } + + status = FX_SetCallBack( testcallback ); + + if ( status != FX_Ok ) + { + Error( FX_ErrorString( FX_Error )); + } + } + +/* +=================== += += SoundShutdown += +=================== +*/ + +void SoundShutdown( void ) + { + int32 status; + + // if they chose None lets return + if (FXDevice == NumSoundCards) + return; + + status = FX_Shutdown(); + if ( status != FX_Ok ) + { + Error( FX_ErrorString( FX_Error )); + } + } + +/* +=================== += += MusicStartup += +=================== +*/ + +void MusicStartup( void ) + { + int32 status; + + // if they chose None lets return + /*if ((MusicDevice == NumSoundCards) || (eightytwofifty && numplayers > 1) ) + return; + + // satisfy AWE32 and WAVEBLASTER stuff + BlasterConfig.Midi = MidiPort; + + // Do special Sound Blaster, AWE32 stuff + if ( + ( FXDevice == SoundBlaster ) || + ( FXDevice == Awe32 ) + ) + { + int MaxVoices; + int MaxBits; + int MaxChannels; + + FX_SetupSoundBlaster + ( + BlasterConfig, (int *)&MaxVoices, (int *)&MaxBits, (int *)&MaxChannels + ); + }*/ + status = MUSIC_Init( MusicDevice, MidiPort ); + + if ( status == MUSIC_Ok ) + { + MUSIC_SetVolume( MusicVolume ); + } + else + { + puts("Couldn't find selected sound card, or, error w/ sound card itself."); + + SoundShutdown(); + uninittimer(); + uninitengine(); + CONTROL_Shutdown(); + CONFIG_WriteSetup(); + KB_Shutdown(); + uninitgroupfile(); + unlink("duke3d.tmp"); + exit(-1); + } +} + +/* +=================== += += MusicShutdown += +=================== +*/ + +void MusicShutdown( void ) + { + int32 status; + + // if they chose None lets return + if ((MusicDevice == NumSoundCards) || (eightytwofifty && numplayers > 1) ) + return; + + status = MUSIC_Shutdown(); + if ( status != MUSIC_Ok ) + { + Error( MUSIC_ErrorString( MUSIC_ErrorCode )); + } + } + +int USRHOOKS_GetMem(char **ptr, unsigned long size ) +{ + *ptr = malloc(size); + + if (*ptr == NULL) + return(USRHOOKS_Error); + + return( USRHOOKS_Ok); + +} + +int USRHOOKS_FreeMem(char *ptr) +{ + free(ptr); + return( USRHOOKS_Ok); +} + +void intomenusounds(void) +{ + static const short menusnds[] = + { + LASERTRIP_EXPLODE, + DUKE_GRUNT, + DUKE_LAND_HURT, + CHAINGUN_FIRE, + SQUISHED, + KICK_HIT, + PISTOL_RICOCHET, + PISTOL_BODYHIT, + PISTOL_FIRE, + SHOTGUN_FIRE, + BOS1_WALK, + RPG_EXPLODE, + PIPEBOMB_BOUNCE, + PIPEBOMB_EXPLODE, + NITEVISION_ONOFF, + RPG_SHOOT, + SELECT_WEAPON + }; + + static int menunum = 0; + + sound(menusnds[menunum++]); + menunum %= 17; +} + +void playmusic(char *fn) +{ +#if PLATFORM_DOS + short fp; + long l; + + if(MusicToggle == 0) return; + if(MusicDevice == NumSoundCards) return; + if(eightytwofifty && numplayers > 1) return; + + fp = kopen4load(fn,0); + + if(fp == -1) return; + + l = kfilelength( fp ); + if(l >= 72000) + { + kclose(fp); + return; + } + + kread( fp, MusicPtr, l); + kclose( fp ); + MUSIC_PlaySong( MusicPtr, MUSIC_LoopSong ); +#else + if(MusicToggle == 0) return; + if(MusicDevice == NumSoundCards) return; + + // the SDL_mixer version does more or less this same thing. --ryan. + PlayMusic(fn); +#endif +} + +char loadsound(unsigned short num) +{ + long fp, l; + + if(num >= NUM_SOUNDS || SoundToggle == 0) return 0; + if (FXDevice == NumSoundCards) return 0; + + fp = kopen4load(sounds[num],loadfromgrouponly); + if(fp == -1) + { + #if 0 // commented out, since game legitimately triggers it. + sprintf(&fta_quotes[113][0],"Sound %s(#%d) not found.",sounds[num],num); + FTA(113,&ps[myconnectindex]); + #endif + return 0; + } + + l = kfilelength( fp ); + soundsiz[num] = l; + + Sound[num].lock = 200; + + allocache((long *)&Sound[num].ptr,l,(unsigned char *)&Sound[num].lock); + kread( fp, Sound[num].ptr , l); + kclose( fp ); + return 1; +} + +int xyzsound(short num,short i,long x,long y,long z) +{ + long sndist, cx, cy, cz, j,k; + short pitche,pitchs,cs; + int voice, sndang, ca, pitch; + +// if(num != 358) return 0; + + if( num >= NUM_SOUNDS || + FXDevice == NumSoundCards || + ( (soundm[num]&8) && ud.lockout ) || + SoundToggle == 0 || + Sound[num].num > 3 || + FX_VoiceAvailable(soundpr[num]) == 0 || + (ps[myconnectindex].timebeforeexit > 0 && ps[myconnectindex].timebeforeexit <= 26*3) || + ps[myconnectindex].gm&MODE_MENU) return -1; + + if( soundm[num]&128 ) + { + sound(num); + return 0; + } + + if( soundm[num]&4 ) + { + if(VoiceToggle==0 || (ud.multimode > 1 && PN == APLAYER && sprite[i].yvel != screenpeek && ud.coop != 1) ) return -1; + + for(j=0;j 0) && (soundm[j]&4) ) + return -1; + } + + cx = ps[screenpeek].oposx; + cy = ps[screenpeek].oposy; + cz = ps[screenpeek].oposz; + cs = ps[screenpeek].cursectnum; + ca = ps[screenpeek].ang+ps[screenpeek].look_ang; + + sndist = FindDistance3D((cx-x),(cy-y),(cz-z)>>4); + + if( i >= 0 && (soundm[num]&16) == 0 && PN == MUSICANDSFX && SLT < 999 && (sector[SECT].lotag&0xff) < 9 ) + sndist = divscale14(sndist,(SHT+1)); + + pitchs = soundps[num]; + pitche = soundpe[num]; + cx = klabs(pitche-pitchs); + + if(cx) + { + if( pitchs < pitche ) + pitch = pitchs + ( rand()%cx ); + else pitch = pitche + ( rand()%cx ); + } + else pitch = pitchs; + + sndist += soundvo[num]; + if(sndist < 0) sndist = 0; + if( sndist && PN != MUSICANDSFX && !cansee(cx,cy,cz-(24<<8),cs,SX,SY,SZ-(24<<8),SECT) ) + sndist += sndist>>5; + + switch(num) + { + case PIPEBOMB_EXPLODE: + case LASERTRIP_EXPLODE: + case RPG_EXPLODE: + if(sndist > (6144) ) + sndist = 6144; + if(sector[ps[screenpeek].cursectnum].lotag == 2) + pitch -= 1024; + break; + default: + if(sector[ps[screenpeek].cursectnum].lotag == 2 && (soundm[num]&4) == 0) + pitch = -768; + if( sndist > 31444 && PN != MUSICANDSFX) + return -1; + break; + } + + + if( Sound[num].num > 0 && PN != MUSICANDSFX ) + { + if( SoundOwner[num][0].i == i ) stopsound(num); + else if( Sound[num].num > 1 ) stopsound(num); + else if( badguy(&sprite[i]) && sprite[i].extra <= 0 ) stopsound(num); + } + + if( PN == APLAYER && sprite[i].yvel == screenpeek ) + { + sndang = 0; + sndist = 0; + } + else + { + sndang = 2048 + ca - getangle(cx-x,cy-y); + sndang &= 2047; + } + + if(Sound[num].ptr == 0) { if( loadsound(num) == 0 ) return 0; } + else + { + if (Sound[num].lock < 200) + Sound[num].lock = 200; + else Sound[num].lock++; + } + + if( soundm[num]&16 ) sndist = 0; + + if(sndist < ((255-LOUDESTVOLUME)<<6) ) + sndist = ((255-LOUDESTVOLUME)<<6); + + if( soundm[num]&1 ) + { + unsigned short start; + + if(Sound[num].num > 0) return -1; + + start = *(unsigned short *)(Sound[num].ptr + 0x14); + start = BUILDSWAP_INTEL16(start); + + if(*Sound[num].ptr == 'C') + voice = FX_PlayLoopedVOC( Sound[num].ptr, start, start + soundsiz[num], + pitch,sndist>>6,sndist>>6,0,soundpr[num],num); + else + voice = FX_PlayLoopedWAV( Sound[num].ptr, start, start + soundsiz[num], + pitch,sndist>>6,sndist>>6,0,soundpr[num],num); + } + else + { + if( *Sound[num].ptr == 'C') + voice = FX_PlayVOC3D( Sound[ num ].ptr,pitch,sndang>>6,sndist>>6, soundpr[num], num ); + else voice = FX_PlayWAV3D( Sound[ num ].ptr,pitch,sndang>>6,sndist>>6, soundpr[num], num ); + } + + if ( voice > FX_Ok ) + { + SoundOwner[num][Sound[num].num].i = i; + SoundOwner[num][Sound[num].num].voice = voice; + Sound[num].num++; + } + else Sound[num].lock--; + return (voice); +} + +void sound(short num) +{ + short pitch,pitche,pitchs,cx; + int voice; + long start; + + if (FXDevice == NumSoundCards) return; + if(SoundToggle==0) return; + if(VoiceToggle==0 && (soundm[num]&4) ) return; + if( (soundm[num]&8) && ud.lockout ) return; + if(FX_VoiceAvailable(soundpr[num]) == 0) return; + + pitchs = soundps[num]; + pitche = soundpe[num]; + cx = klabs(pitche-pitchs); + + if(cx) + { + if( pitchs < pitche ) + pitch = pitchs + ( rand()%cx ); + else pitch = pitche + ( rand()%cx ); + } + else pitch = pitchs; + + if(Sound[num].ptr == 0) { if( loadsound(num) == 0 ) return; } + else + { + if (Sound[num].lock < 200) + Sound[num].lock = 200; + else Sound[num].lock++; + } + + if( soundm[num]&1 ) + { + if(*Sound[num].ptr == 'C') + { + start = (long)*(unsigned short *)(Sound[num].ptr + 0x14); + voice = FX_PlayLoopedVOC( Sound[num].ptr, start, start + soundsiz[num], + pitch,LOUDESTVOLUME,LOUDESTVOLUME,LOUDESTVOLUME,soundpr[num],num); + } + else + { + start = (long)*(unsigned short *)(Sound[num].ptr + 0x14); + voice = FX_PlayLoopedWAV( Sound[num].ptr, start, start + soundsiz[num], + pitch,LOUDESTVOLUME,LOUDESTVOLUME,LOUDESTVOLUME,soundpr[num],num); + } + } + else + { + if(*Sound[num].ptr == 'C') + voice = FX_PlayVOC3D( Sound[ num ].ptr, pitch,0,255-LOUDESTVOLUME,soundpr[num], num ); + else + voice = FX_PlayWAV3D( Sound[ num ].ptr, pitch,0,255-LOUDESTVOLUME,soundpr[num], num ); + } + + if(voice > FX_Ok) return; + Sound[num].lock--; +} + +int spritesound(unsigned short num, short i) +{ + if(num >= NUM_SOUNDS) return -1; + return xyzsound(num,i,SX,SY,SZ); +} + +void stopsound(short num) +{ + if(Sound[num].num > 0) + { + FX_StopSound(SoundOwner[num][Sound[num].num-1].voice); + testcallback(num); + } +} + +void stopenvsound(short num,short i) +{ + short j, k; + + if(Sound[num].num > 0) + { + k = Sound[num].num; + for(j=0;j>4); + if( i >= 0 && (soundm[j]&16) == 0 && PN == MUSICANDSFX && SLT < 999 && (sector[SECT].lotag&0xff) < 9 ) + sndist = divscale14(sndist,(SHT+1)); + } + + sndist += soundvo[j]; + if(sndist < 0) sndist = 0; + + if( sndist && PN != MUSICANDSFX && !cansee(cx,cy,cz-(24<<8),cs,sx,sy,sz-(24<<8),SECT) ) + sndist += sndist>>5; + + if(PN == MUSICANDSFX && SLT < 999) + numenvsnds++; + + switch(j) + { + case PIPEBOMB_EXPLODE: + case LASERTRIP_EXPLODE: + case RPG_EXPLODE: + if(sndist > (6144)) sndist = (6144); + break; + default: + if( sndist > 31444 && PN != MUSICANDSFX) + { + stopsound(j); + continue; + } + } + + if(Sound[j].ptr == 0 && loadsound(j) == 0 ) continue; + if( soundm[j]&16 ) sndist = 0; + + if(sndist < ((255-LOUDESTVOLUME)<<6) ) + sndist = ((255-LOUDESTVOLUME)<<6); + + FX_Pan3D(SoundOwner[j][k].voice,sndang>>6,sndist>>6); + } +} + +void testcallback(unsigned long _num) +{ + long num = (long) _num; + + short tempi,tempj,tempk; + + if(num < 0) + { + if(lumplockbyte[-num] >= 200) + lumplockbyte[-num]--; + return; + } + + tempk = Sound[num].num; + + if(tempk > 0) + { + if( (soundm[num]&16) == 0) + for(tempj=0;tempj= 200) + Sound[i].lock = 199; + + for(i=0;i<11;i++) + if(lumplockbyte[i] >= 200) + lumplockbyte[i] = 199; +} diff --git a/sounds.h b/sounds.h new file mode 100755 index 0000000..97697fc --- /dev/null +++ b/sounds.h @@ -0,0 +1,59 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment + +This file is part of Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Original Source: 1996 - Todd Replogle +Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms +*/ +//------------------------------------------------------------------------- + +//**************************************************************************** +// +// sounds.h +// +//**************************************************************************** + +#ifndef _sounds_public_ +#define _sounds_public_ + +extern int32 FXDevice; +extern int32 MusicDevice; +extern int32 FXVolume; +extern int32 MusicVolume; +extern fx_blaster_config BlasterConfig; +extern int32 NumVoices; +extern int32 NumChannels; +extern int32 NumBits; +extern int32 MixRate; +extern int32 MidiPort; +extern int32 ReverseStereo; + +void SoundStartup( void ); +void SoundShutdown( void ); +void MusicStartup( void ); +void MusicShutdown( void ); + +/* sounds.c */ +void clearsoundlocks(void); + +/* dunno where this came from; I added it. --ryan. */ +void testcallback(unsigned long num); + +#endif diff --git a/task_man.h b/task_man.h new file mode 100755 index 0000000..cba6f88 --- /dev/null +++ b/task_man.h @@ -0,0 +1,64 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment + +This file is part of Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Original Source: 1994 - Jim Dose +Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms +*/ +//------------------------------------------------------------------------- + +#ifndef __TASK_MAN_H +#define __TASK_MAN_H + +enum TASK_ERRORS + { + TASK_Warning = -2, + TASK_Error = -1, + TASK_Ok = 0 + }; + +typedef struct task +{ + struct task *next; + struct task *prev; + void ( *TaskService )( struct task * ); + void *data; + long rate; + volatile long count; + int priority; + int active; +} task; + +// TS_InInterrupt is TRUE during a taskman interrupt. +// Use this if you have code that may be used both outside +// and within interrupts. + +extern volatile int TS_InInterrupt; + +void TS_Shutdown( void ); +task *TS_ScheduleTask( void ( *Function )( task * ), int rate, + int priority, void *data ); +int TS_Terminate( task *ptr ); +void TS_Dispatch( void ); +void TS_SetTaskRate( task *Task, int rate ); +void TS_UnlockMemory( void ); +int TS_LockMemory( void ); + +#endif diff --git a/types.h b/types.h new file mode 100755 index 0000000..bfdcc77 --- /dev/null +++ b/types.h @@ -0,0 +1,105 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment + +This file is part of Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Original Source: 1996 - Todd Replogle +Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms +*/ +//------------------------------------------------------------------------- + +#ifndef _types_public +#define _types_public +#ifdef __cplusplus +extern "C" { +#endif + + +//*************************************************************************** +// +// Global Data Types (For portability) +// +//*************************************************************************** + +typedef unsigned char uint8; +typedef uint8 byte; +typedef signed char int8; + +typedef unsigned short int uint16; +typedef uint16 word; +typedef short int int16; + +typedef unsigned long uint32; +typedef long int32; +typedef uint32 dword; + +typedef int32 fixed; +typedef int32 boolean; +typedef float float32; +typedef double float64; + +// not used, spits out a compiler warning on MacOSX's gcc... --ryan.) +//typedef long double float128; + +typedef float64 appfloat; + +#define MAXINT32 0x7fffffff +#define MININT32 -0x80000000 +#define MAXUINT32 0xffffffff +#define MINUINT32 0 + +#define MAXINT16 0x7fff +#define MININT16 -0x8000 +#define MAXUINT16 0xffff +#define MINUINT16 0 + +//*************************************************************************** +// +// boolean values +// +//*************************************************************************** + +#define true ( 1 == 1 ) +#define false ( ! true ) + +//*************************************************************************** +// +// BYTE ACCESS MACROS +// +//*************************************************************************** + +// WORD macros +#define Int16_HighByte( x ) ( (uint8) ((x)>>8) ) +#define Int16_LowByte( x ) ( (uint8) ((x)&0xff) ) + +// DWORD macros +#define Int32_4Byte( x ) ( (uint8) ((x)>>24)&0xff ) +#define Int32_3Byte( x ) ( (uint8) (((x)>>16)&0xff) ) +#define Int32_2Byte( x ) ( (uint8) (((x)>>8)&0xff) ) +#define Int32_1Byte( x ) ( (uint8) ((x)&0xff) ) + +#ifdef __NeXT__ +#define stricmp strcasecmp +#define strcmpi strcasecmp +#endif + +#ifdef __cplusplus +}; +#endif +#endif diff --git a/util_lib.h b/util_lib.h new file mode 100755 index 0000000..c42ebfd --- /dev/null +++ b/util_lib.h @@ -0,0 +1,67 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 1996, 2003 - 3D Realms Entertainment + +This file is part of Duke Nukem 3D version 1.5 - Atomic Edition + +Duke Nukem 3D 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +Original Source: 1996 - Todd Replogle +Prepared for public release: 03/21/2003 - Charlie Wiederhold, 3D Realms +*/ +//------------------------------------------------------------------------- + +//*************************************************************************** +// +// UTIL_LIB.C - various utils +// +//*************************************************************************** + +#ifndef _util_lib_public +#define _util_lib_public +#ifdef __cplusplus +extern "C" { +#endif + +#if (defined(__MSDOS__) && !defined(__FLAT__)) +extern int16 _argc; +#else +extern int32 _argc; +#endif +extern char ** _argv; + +void RegisterShutdownFunction( void (* shutdown) (void) ); +void Error (char *error, ...); + +char CheckParm (char *check); + +void *SafeMalloc (int32 size); +int32 SafeMallocSize (void * ptr); +void SafeFree (void * ptr); +void SafeRealloc (void ** ptr, int32 newsize); +int32 ParseHex (char *hex); +int32 ParseNum (char *str); +int16 MotoShort (int16 l); +int16 IntelShort (int16 l); +int32 MotoLong (int32 l); +int32 IntelLong (int32 l); + +void HeapSort(char * base, int32 nel, int32 width, int32 (*compare)(), void (*switcher)()); + +#ifdef __cplusplus +}; +#endif +#endif