rockbox/apps/plugins/doom/rockdoom.c
Karl Kurbjun b47a43aa28 Doom for the Gigabeat and some code reduction
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@12051 a1c6a512-1295-4272-9138-f99709370657
2007-01-17 18:52:24 +00:00

764 lines
17 KiB
C

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
*
* Copyright (C) 2005 Karl Kurbjun
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* H300 Port by Karl Kurbjun
* IPod port by Dave Chapman and Paul Louden
* Additional code contributed by Thom Johansen
* Based off work by: Digita Doom, IDoom, Prboom, lSDLDoom, LxDoom,
* MBF, Boom, DosDoom,
* and of course Original Doom by ID Software
* See: http://prboom.sourceforge.net/about.html for the history
*
*
****************************************************************************/
#include "d_main.h"
#include "doomdef.h"
#include "settings.h"
#include "m_fixed.h"
#include "m_argv.h"
#include "m_misc.h"
#include "g_game.h"
#include "rockmacros.h"
#include "doomstat.h"
#include "i_system.h"
#include "hu_stuff.h"
#include "st_stuff.h"
PLUGIN_HEADER
PLUGIN_IRAM_DECLARE
extern boolean timingdemo, singledemo, demoplayback, fastdemo; // killough
int filearray[9];
int fpoint=1; // save 0 for closing
int fileexists(const char * fname)
{
int fd;
fd = open(fname,O_RDONLY);
if (fd>=0)
{
close(fd);
return 0;
}
return -1;
}
#ifndef SIMULATOR
int my_open(const char *file, int flags)
{
if(fpoint==8)
return -1;
#undef open
filearray[fpoint]=rb->open(file, flags);
if(filearray[fpoint]<0)
return filearray[fpoint];
fpoint++;
return filearray[fpoint-1];
}
int my_close(int id)
{
int i=0;
if(id<0)
return id;
while(filearray[i]!=id && i<8)
i++;
if(i==8)
{
printf("A requested FID did not exist!!!!");
return -9;
}
#undef close
rb->close(id);
for(; i<fpoint-1; i++)
filearray[i]=filearray[i+1];
fpoint--;
return 0;
}
#endif
struct plugin_api* rb;
#define MAXARGVS 100
bool noprintf=0; // Variable disables printf lcd updates to protect grayscale lib/direct lcd updates
// Here is a hacked up printf command to get the output from the game.
int printf(const char *fmt, ...)
{
static int p_xtpt;
char p_buf[50];
bool ok;
rb->yield();
va_list ap;
va_start(ap, fmt);
ok = vsnprintf(p_buf,sizeof(p_buf), fmt, ap);
va_end(ap);
rb->lcd_putsxy(1,p_xtpt, (unsigned char *)p_buf);
if (!noprintf)
rb->lcd_update();
p_xtpt+=8;
if(p_xtpt>LCD_HEIGHT-8)
{
p_xtpt=0;
if (!noprintf)
rb->lcd_clear_display();
}
return 1;
}
char *my_strtok( char * s, const char * delim )
{
register char *spanp;
register int c, sc;
char *tok;
static char *lasts;
if (s == NULL && (s = lasts) == NULL)
return (NULL);
/*
* Skip (span) leading delimiters (s += strspn(s, delim), sort of).
*/
cont:
c = *s++;
for (spanp = (char *)delim; (sc = *spanp++) != 0;) {
if (c == sc)
goto cont;
}
if (c == 0) { /* no non-delimiter characters */
lasts = NULL;
return (NULL);
}
tok = s - 1;
/*
* Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
* Note that delim must have one NUL; we stop if we see that, too.
*/
for (;;) {
c = *s++;
spanp = (char *)delim;
do {
if ((sc = *spanp++) == c) {
if (c == 0)
s = NULL;
else
s[-1] = 0;
lasts = s;
return (tok);
}
} while (sc != 0);
}
/* NOTREACHED */
}
inline void* memcpy(void* dst, const void* src, size_t size)
{
return rb->memcpy(dst, src, size);
}
struct argvlist
{
int timedemo; // 1 says there's a timedemo
int demonum;
int addonnum;
} argvlist;
const unsigned char versions_builtin[7][20] =
{
"Doom Shareware",
"Doom Registered",
"Ultimate Doom",
"Doom 2",
"Doom 2 French",
"Plutonia",
"TNT"
};
const unsigned char wads_builtin[7][30] =
{
GAMEBASE"doom1.wad",
GAMEBASE"doom.wad",
GAMEBASE"doomu.wad",
GAMEBASE"doom2.wad",
GAMEBASE"doom2f.wad",
GAMEBASE"plutonia.wad",
GAMEBASE"tnt.wad"
};
int namemap[7];
static struct menu_item *addons;
static struct menu_item *demolmp;
char addon[200];
// This sets up the base game and builds up myargv/c
bool Dhandle_ver (int dver)
{
switch (dver) {
case 0: /* Doom Shareware */
gamemode = shareware;
gamemission = doom;
D_AddFile(wads_builtin[0],source_iwad);
break;
case 1: /* Doom registered */
gamemode = registered;
gamemission = doom;
D_AddFile(wads_builtin[1],source_iwad);
break;
case 2: /* Ultimate Doom */
gamemode = retail;
gamemission = doom;
D_AddFile(wads_builtin[2],source_iwad);
break;
case 3: /* Doom2 */
gamemode = commercial;
gamemission = doom2;
D_AddFile(wads_builtin[3],source_iwad);
break;
case 4: /* Doom2f */
gamemode = commercial;
gamemission = doom2;
D_AddFile(wads_builtin[4],source_iwad);
break;
case 5: /* Plutonia */
gamemode = commercial;
gamemission = pack_plut;
D_AddFile(wads_builtin[5],source_iwad);
break;
case 6: /* TNT */
gamemode = commercial;
gamemission = pack_tnt;
D_AddFile(wads_builtin[6],source_iwad);
break;
default:
gamemission = none;
return 0;
}
// Start adding to myargv
if(argvlist.timedemo && (gamemode == shareware))
{
singletics = true;
timingdemo = true; // show stats after quit
G_DeferedPlayDemo("demo3");
singledemo = true; // quit after one demo
}
if(argvlist.addonnum)
{
snprintf(addon,sizeof(addon),"%s%s", GAMEBASE"addons/", addons[argvlist.addonnum].desc);
D_AddFile(addon,source_pwad);
modifiedgame = true;
}
if(argvlist.demonum)
{
snprintf(addon, sizeof(addon),"%s%s", GAMEBASE"demos/", demolmp[argvlist.demonum].desc);
D_AddFile(addon, source_lmp);
G_DeferedPlayDemo(addon);
singledemo = true; // quit after one demo
}
return 1;
}
// This function builds up the basegame list for use in the options selection
// it also sets the defaults for the argvlist
// Now checking for rcokdoom.wad based on prboom.wad
int Dbuild_base (struct opt_items *names)
{
if ( fileexists(GAMEBASE"rockdoom.wad") )
return 0;
D_AddFile (GAMEBASE"rockdoom.wad", source_pwad);
int i=0, j;
/* Doom Shareware */
/* Doom registered */
/* Ultimate Doom */
/* Doom2 */
/* Doom2f */
/* Plutonia */
/* TNT */
for(j=0;j<7;j++)
if ( !fileexists (wads_builtin[j]) )
{
names[i].string=versions_builtin[j];
names[i].voice_id=0;
namemap[i]=j;
i++;
}
// Set argvlist defaults
argvlist.timedemo=0;
return i;
}
// This is a general function that takes in a menu_item structure and makes a list
// of files within it based on matching the string stringmatch to the files.
int Dbuild_filelistm(struct menu_item **names, char *firstentry, char *directory, char *stringmatch)
{
int i=0;
DIR *filedir;
struct dirent *dptr;
char *startpt;
struct menu_item *temp;
filedir=opendir(directory);
if(filedir==NULL)
{
temp=malloc(sizeof(struct opt_items));
temp[0].desc=firstentry;
temp[0].function=0;
*names=temp;
return 1;
}
// Get the total number of entries
while((dptr=rb->readdir(filedir)))
i++;
// Reset the directory
closedir(filedir);
filedir=opendir(directory);
i++;
temp=malloc(i*sizeof(struct opt_items));
temp[0].desc=firstentry;
temp[0].function=0;
i=1;
while((dptr=rb->readdir(filedir)))
{
if(rb->strcasestr(dptr->d_name, stringmatch))
{
startpt=malloc(strlen(dptr->d_name)*sizeof(char));
strcpy(startpt,dptr->d_name);
temp[i].desc=startpt;
temp[i].function=0;
i++;
}
}
closedir(filedir);
*names=temp;
return i;
}
static int translatekey(int key) __attribute__ ((noinline));
// This key configuration code is not the cleanest or the most efficient, but it works
static int translatekey(int key)
{
if (key<31)
{
switch(key)
{
case 0:
return 0;
case 1:
return KEY_RIGHTARROW;
case 2:
return KEY_LEFTARROW;
case 3:
return KEY_UPARROW;
case 4:
return KEY_DOWNARROW;
case 5:
return KEY_ENTER;
case 6:
return KEY_RCTRL;
case 7:
return ' ';
case 8:
return KEY_ESCAPE;
case 9:
return 'w';
case 10:
return KEY_TAB;
default:
return 0;
}
}
else
{
switch(key)
{
case 0:
return 0;
case KEY_RIGHTARROW:
return 1;
case KEY_LEFTARROW:
return 2;
case KEY_UPARROW:
return 3;
case KEY_DOWNARROW:
return 4;
case KEY_ENTER:
return 5;
case KEY_RCTRL:
return 6;
case ' ':
return 7;
case KEY_ESCAPE:
return 8;
case 'w':
return 9;
case KEY_TAB:
return 10;
default:
return 0;
}
}
}
// I havn't added configurable keys for enter or escape because this requires some modification to
// m_menu.c which hasn't been done yet.
int Oset_keys()
{
int m, result;
int menuquit=0;
static const struct opt_items doomkeys[] = {
{ "Unmapped", NULL },
{ "Key Right", NULL },
{ "Key Left", NULL },
{ "Key Up", NULL },
{ "Key Down", NULL },
{ "Key Select", NULL },
#if defined(TOSHIBA_GIGABEAT_F)
{ "Key A", NULL },
{ "Key Menu", NULL },
{ "Key Power", NULL },
{ "Key Volume Down", NULL },
{ "Key Volume Up", NULL },
#else
{ "Key Record", NULL },
{ "Key Mode", NULL },
{ "Key Off", NULL },
{ "Key On", NULL },
#endif
};
int *keys[]={
&key_right,
&key_left,
&key_up,
&key_down,
&key_fire,
&key_use,
&key_strafe,
&key_weapon,
&key_map
};
int numdoomkeys=sizeof(doomkeys) / sizeof(*doomkeys);
static const struct menu_item items[] = {
{ "Game Right", NULL },
{ "Game Left", NULL },
{ "Game Up", NULL },
{ "Game Down", NULL },
{ "Game Shoot", NULL },
{ "Game Open", NULL },
{ "Game Strafe", NULL },
{ "Game Weapon", NULL },
{ "Game Automap", NULL },
};
m = rb->menu_init(items, sizeof(items) / sizeof(*items),
NULL, NULL, NULL, NULL);
while(!menuquit)
{
result=rb->menu_show(m);
if(result<0)
menuquit=1;
else
{
*keys[result]=translatekey(*keys[result]);
rb->set_option(items[result].desc, keys[result], INT, doomkeys, numdoomkeys, NULL );
*keys[result]=translatekey(*keys[result]);
}
}
rb->menu_exit(m);
return (1);
}
extern int fake_contrast;
static bool Doptions()
{
static const struct opt_items onoff[2] = {
{ "Off", NULL },
{ "On", NULL },
};
int m, result;
int menuquit=0;
static const struct menu_item items[] = {
{ "Set Keys", NULL },
{ "Sound", NULL },
{ "Timedemo", NULL },
{ "Player Bobbing", NULL },
{ "Weapon Recoil", NULL },
{ "Translucency", NULL },
{ "Fake Contrast", NULL },
{ "Always Run", NULL },
{ "Headsup Display", NULL },
{ "Statusbar Always Red", NULL },
#if(LCD_HEIGHT>LCD_WIDTH)
{ "Rotate Screen 90 deg", NULL },
#endif
};
void *options[]={
&enable_sound,
&argvlist.timedemo,
&default_player_bobbing,
&default_weapon_recoil,
&default_translucency,
&fake_contrast,
&autorun,
&hud_displayed,
&sts_always_red,
#if(LCD_HEIGHT>LCD_WIDTH)
&rotate_screen,
#endif
};
m = rb->menu_init(items, sizeof(items) / sizeof(*items),
NULL, NULL, NULL, NULL);
while(!menuquit)
{
result=rb->menu_show(m);
if(result==0)
Oset_keys();
else if (result > 0)
rb->set_option(items[result].desc, options[result-1], INT, onoff, 2, NULL );
else
menuquit=1;
}
rb->menu_exit(m);
return (1);
}
int menuchoice(struct menu_item *menu, int items)
{
int m, result;
m = rb->menu_init(menu, items,NULL, NULL, NULL, NULL);
result= rb->menu_show(m);
rb->menu_exit(m);
if(result<items && result>=0)
return result;
return 0;
}
//
// Doom Menu
//
int doom_menu()
{
int m;
int result;
int status;
int gamever;
bool menuquit=0;
static struct opt_items names[7];
static const struct menu_item items[] = {
{ "Game", NULL },
{ "Addons", NULL },
{ "Demos", NULL },
{ "Options", NULL },
{ "Play Game", NULL },
{ "Quit", NULL },
};
if( (status=Dbuild_base(names)) == 0 ) // Build up the base wad files (select last added file)
{
rb->splash(HZ*2, true, "Missing Base WAD!");
return -2;
}
int numadd=Dbuild_filelistm(&addons, "No Addon", GAMEBASE"addons/", ".WAD" );
int numdemos=Dbuild_filelistm(&demolmp, "No Demo", GAMEBASE"demos/", ".LMP" );
argvlist.demonum=0;
argvlist.addonnum=0;
gamever=status-1;
/* Clean out the button Queue */
while (rb->button_get(false) != BUTTON_NONE)
rb->yield();
m = rb->menu_init(items, sizeof(items) / sizeof(*items),
NULL, NULL, NULL, NULL);
while(!menuquit)
{
result=rb->menu_show(m);
switch (result) {
case 0: /* Game picker */
rb->set_option("Game WAD", &gamever, INT, names, status, NULL );
break;
case 1: /* Addon picker */
argvlist.addonnum=menuchoice(addons,numadd);
break;
case 2: /* Demos */
argvlist.demonum=menuchoice(demolmp,numdemos);
break;
case 3: /* Options */
Doptions();
break;
case 4: /* Play Game */
menuquit=1;
break;
case 5: /* Quit */
menuquit=1;
gamever=-1;
break;
default:
break;
}
}
rb->menu_exit(m);
return (gamever);
}
extern int systemvol;
/* this is the plugin entry point */
enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
{
PLUGIN_IRAM_INIT(api)
rb = api;
(void)parameter;
doomexit=0;
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
rb->cpu_boost(true);
#endif
rb->lcd_setfont(0);
// We're using doom's memory management since it implements a proper free (and re-uses the memory)
// and now with prboom's code: realloc and calloc
printf ("Z_Init: Init zone memory allocation daemon.\n");
Z_Init ();
printf ("M_LoadDefaults: Load system defaults.\n");
M_LoadDefaults (); // load before initing other systems
rb->splash(HZ*2, true, "Welcome to RockDoom");
myargv =0;
myargc=0;
rb->lcd_clear_display();
int result = doom_menu();
if (result < 0)
{
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
rb->cpu_boost(false);
#endif
if( result == -1 ) return PLUGIN_OK; // Quit was selected
else if( result == -2 ) return PLUGIN_ERROR; // Missing base wads
}
#if(LCD_HEIGHT>LCD_WIDTH)
if(rotate_screen)
{
SCREENHEIGHT=LCD_WIDTH;
SCREENWIDTH=LCD_HEIGHT;
}
else
{
SCREENHEIGHT=LCD_HEIGHT;
SCREENWIDTH=LCD_WIDTH;
}
#endif
Dhandle_ver( namemap[ result ] );
rb->lcd_setfont(0);
rb->lcd_clear_display();
systemvol= rb->global_settings->volume-rb->global_settings->volume%((rb->sound_max(SOUND_VOLUME)-rb->sound_min(SOUND_VOLUME))/15);
general_translucency = default_translucency; // phares
#ifdef RB_PROFILE
rb->profile_thread();
#endif
rb->lcd_set_backdrop(NULL);
D_DoomMain ();
#ifdef RB_PROFILE
rb->profstop();
#endif
M_SaveDefaults ();
I_Quit(); // Make SURE everything was closed out right
printf("There were still: %d files open\n", fpoint);
while(fpoint>0)
{
rb->close(filearray[fpoint]);
fpoint--;
}
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
rb->cpu_boost(false);
#endif
return PLUGIN_OK;
}