Merge branch 'map-by-name' into 'master'
New map command See merge request STJr/SRB2Internal!424
This commit is contained in:
commit
510f36fbdf
329
src/d_netcmd.c
329
src/d_netcmd.c
|
@ -1736,25 +1736,151 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pultmode, boolean rese
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
MAP_COMMAND_FORCE_OPTION,
|
||||||
|
MAP_COMMAND_GAMETYPE_OPTION,
|
||||||
|
MAP_COMMAND_NORESETPLAYERS_OPTION,
|
||||||
|
|
||||||
|
NUM_MAP_COMMAND_OPTIONS
|
||||||
|
};
|
||||||
|
|
||||||
|
static size_t CheckOptions(
|
||||||
|
int num_options,
|
||||||
|
size_t *first_argumentp,
|
||||||
|
size_t *user_options,
|
||||||
|
const char ***option_names,
|
||||||
|
int *option_num_arguments
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int arguments_used;
|
||||||
|
size_t first_argument;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
const char **pp;
|
||||||
|
const char *name;
|
||||||
|
size_t n;
|
||||||
|
|
||||||
|
arguments_used = 0;
|
||||||
|
first_argument = COM_Argc();
|
||||||
|
|
||||||
|
for (i = 0; i < num_options; ++i)
|
||||||
|
{
|
||||||
|
pp = option_names[i];
|
||||||
|
name = *pp;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (( n = COM_CheckParm(name) ))
|
||||||
|
{
|
||||||
|
user_options[i] = n;
|
||||||
|
arguments_used += 1 + option_num_arguments[i];
|
||||||
|
if (n < first_argument)
|
||||||
|
first_argument = n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (( name = *++pp )) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*first_argumentp) = first_argument;
|
||||||
|
|
||||||
|
return arguments_used;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
ConcatCommandArgv (int start, int end)
|
||||||
|
{
|
||||||
|
char *final;
|
||||||
|
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
size = 0;
|
||||||
|
|
||||||
|
for (i = start; i < end; ++i)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
one space after each argument, but terminating
|
||||||
|
character on final argument
|
||||||
|
*/
|
||||||
|
size += strlen(COM_Argv(i)) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
final = ZZ_Alloc(size);
|
||||||
|
p = final;
|
||||||
|
|
||||||
|
--end;/* handle the final argument separately */
|
||||||
|
for (i = start; i < end; ++i)
|
||||||
|
{
|
||||||
|
p += sprintf(p, "%s ", COM_Argv(i));
|
||||||
|
}
|
||||||
|
/* at this point "end" is actually the last argument's position */
|
||||||
|
strcpy(p, COM_Argv(end));
|
||||||
|
|
||||||
|
return final;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
// Warp to map code.
|
// Warp to map code.
|
||||||
// Called either from map <mapname> console command, or idclev cheat.
|
// Called either from map <mapname> console command, or idclev cheat.
|
||||||
//
|
//
|
||||||
|
// Largely rewritten by James.
|
||||||
|
//
|
||||||
static void Command_Map_f(void)
|
static void Command_Map_f(void)
|
||||||
{
|
{
|
||||||
const char *mapname;
|
const char *force_option_names[] =
|
||||||
size_t i;
|
{
|
||||||
INT32 newmapnum;
|
"-force",
|
||||||
|
"-f",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
const char *gametype_option_names[] =
|
||||||
|
{
|
||||||
|
"-gametype",
|
||||||
|
"-g",
|
||||||
|
"-gt",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
const char *noresetplayers_option_names[] =
|
||||||
|
{
|
||||||
|
"-noresetplayers",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
const char **option_names[] =
|
||||||
|
{
|
||||||
|
force_option_names,
|
||||||
|
gametype_option_names,
|
||||||
|
noresetplayers_option_names,
|
||||||
|
};
|
||||||
|
int option_num_arguments[] =
|
||||||
|
{
|
||||||
|
0,/* -force */
|
||||||
|
1,/* -gametype */
|
||||||
|
0,/* -noresetplayers */
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t acceptableargc;/* (this includes the command name itself!) */
|
||||||
|
size_t first_argument;
|
||||||
|
|
||||||
|
size_t user_options [NUM_MAP_COMMAND_OPTIONS] = {0};
|
||||||
|
|
||||||
|
const char *arg_gametype;
|
||||||
boolean newresetplayers;
|
boolean newresetplayers;
|
||||||
|
|
||||||
|
boolean mustmodifygame;
|
||||||
|
boolean usemapcode = false;
|
||||||
|
|
||||||
|
INT32 newmapnum;
|
||||||
|
|
||||||
|
char * mapname;
|
||||||
|
size_t mapnamelen;
|
||||||
|
char *realmapname = NULL;
|
||||||
|
|
||||||
INT32 newgametype = gametype;
|
INT32 newgametype = gametype;
|
||||||
|
|
||||||
// max length of command: map map03 -gametype coop -noresetplayers -force
|
INT32 d;
|
||||||
// 1 2 3 4 5 6
|
char *p;
|
||||||
// = 8 arg max
|
|
||||||
if (COM_Argc() < 2 || COM_Argc() > 8)
|
|
||||||
{
|
|
||||||
CONS_Printf(M_GetText("map <mapname> [-gametype <type> [-force]: warp to map\n"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (client && !IsPlayerAdmin(consoleplayer))
|
if (client && !IsPlayerAdmin(consoleplayer))
|
||||||
{
|
{
|
||||||
|
@ -1762,62 +1888,145 @@ static void Command_Map_f(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// internal wad lump always: map command doesn't support external files as in doom legacy
|
/* map name + options */
|
||||||
if (W_CheckNumForName(COM_Argv(1)) == LUMPERROR)
|
acceptableargc = 2 + CheckOptions(NUM_MAP_COMMAND_OPTIONS,
|
||||||
|
&first_argument,
|
||||||
|
user_options, option_names, option_num_arguments);
|
||||||
|
|
||||||
|
newresetplayers = !user_options[MAP_COMMAND_NORESETPLAYERS_OPTION];
|
||||||
|
|
||||||
|
mustmodifygame =
|
||||||
|
!( netgame || multiplayer ) &&
|
||||||
|
(!modifiedgame || savemoddata );
|
||||||
|
|
||||||
|
if (mustmodifygame && !user_options[MAP_COMMAND_FORCE_OPTION])
|
||||||
{
|
{
|
||||||
CONS_Alert(CONS_ERROR, M_GetText("Internal game level '%s' not found\n"), COM_Argv(1));
|
/* May want to be more descriptive? */
|
||||||
|
CONS_Printf(M_GetText("Sorry, level change disabled in single player.\n"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(netgame || multiplayer) && (!modifiedgame || savemoddata))
|
|
||||||
{
|
|
||||||
if (COM_CheckParm("-force"))
|
|
||||||
G_SetGameModified(false);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
CONS_Printf(M_GetText("Sorry, level change disabled in single player.\n"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
newresetplayers = !COM_CheckParm("-noresetplayers");
|
|
||||||
|
|
||||||
if (!newresetplayers && !cv_debug)
|
if (!newresetplayers && !cv_debug)
|
||||||
{
|
{
|
||||||
CONS_Printf(M_GetText("DEVMODE must be enabled.\n"));
|
CONS_Printf(M_GetText("DEVMODE must be enabled.\n"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mapname = COM_Argv(1);
|
if (user_options[MAP_COMMAND_GAMETYPE_OPTION] && !multiplayer)
|
||||||
if (strlen(mapname) != 5
|
|
||||||
|| (newmapnum = M_MapNumber(mapname[3], mapname[4])) == 0)
|
|
||||||
{
|
{
|
||||||
CONS_Alert(CONS_ERROR, M_GetText("Invalid level name %s\n"), mapname);
|
CONS_Printf(M_GetText("You can't switch gametypes in single player!\n"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ultimate Mode only in SP via menu
|
/* If the first argument is an option, you fucked up. */
|
||||||
if (netgame || multiplayer)
|
if (COM_Argc() < acceptableargc || first_argument == 1)
|
||||||
ultimatemode = false;
|
{
|
||||||
|
/* I'm going over the fucking lines and I DON'T CAREEEEE */
|
||||||
|
CONS_Printf("map <name / [MAP]code / number> [-gametype <type>] [-force]:\n");
|
||||||
|
CONS_Printf(M_GetText(
|
||||||
|
"Warp to a map, by its name, two character code, with optional \"MAP\" prefix, or by its number (though why would you).\n"
|
||||||
|
"All parameters are case-insensitive.\n"
|
||||||
|
"* \"-force\" may be shortened to \"-f\".\n"
|
||||||
|
"* \"-gametype\" may be shortened to \"-g\" or \"-gt\".\n"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mapname = ConcatCommandArgv(1, first_argument);
|
||||||
|
mapnamelen = strlen(mapname);
|
||||||
|
|
||||||
|
if (mapnamelen == 2)/* maybe two digit code */
|
||||||
|
{
|
||||||
|
if (( newmapnum = M_MapNumber(mapname[0], mapname[1]) ))
|
||||||
|
usemapcode = true;
|
||||||
|
}
|
||||||
|
else if (mapnamelen == 5 && strnicmp(mapname, "MAP", 3) == 0)
|
||||||
|
{
|
||||||
|
if (( newmapnum = M_MapNumber(mapname[3], mapname[4]) ) == 0)
|
||||||
|
{
|
||||||
|
CONS_Alert(CONS_ERROR, M_GetText("Invalid map code '%s'.\n"), mapname);
|
||||||
|
Z_Free(mapname);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
usemapcode = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!usemapcode)
|
||||||
|
{
|
||||||
|
/* Now detect map number in base 10, which no one asked for. */
|
||||||
|
newmapnum = strtol(mapname, &p, 10);
|
||||||
|
if (*p == '\0')/* we got it */
|
||||||
|
{
|
||||||
|
if (newmapnum < 1 || newmapnum > NUMMAPS)
|
||||||
|
{
|
||||||
|
CONS_Alert(CONS_ERROR, M_GetText("Invalid map number %d.\n"), newmapnum);
|
||||||
|
Z_Free(mapname);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
usemapcode = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
newmapnum = G_FindMap(mapname, &realmapname, NULL, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newmapnum == 0 || !mapheaderinfo[newmapnum-1])
|
||||||
|
{
|
||||||
|
CONS_Alert(CONS_ERROR, M_GetText("Could not find any map described as '%s'.\n"), mapname);
|
||||||
|
Z_Free(mapname);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (usemapcode)
|
||||||
|
{
|
||||||
|
realmapname = G_BuildMapTitle(newmapnum);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mustmodifygame && user_options[MAP_COMMAND_FORCE_OPTION])
|
||||||
|
{
|
||||||
|
G_SetGameModified(false);
|
||||||
|
}
|
||||||
|
|
||||||
// new gametype value
|
// new gametype value
|
||||||
// use current one by default
|
// use current one by default
|
||||||
i = COM_CheckParm("-gametype");
|
if (user_options[MAP_COMMAND_GAMETYPE_OPTION])
|
||||||
if (i)
|
|
||||||
{
|
{
|
||||||
if (!multiplayer)
|
arg_gametype = COM_Argv(user_options[MAP_COMMAND_GAMETYPE_OPTION] + 1);
|
||||||
{
|
|
||||||
CONS_Printf(M_GetText("You can't switch gametypes in single player!\n"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
newgametype = G_GetGametypeByName(COM_Argv(i+1));
|
newgametype = G_GetGametypeByName(arg_gametype);
|
||||||
|
|
||||||
if (newgametype == -1) // reached end of the list with no match
|
if (newgametype == -1) // reached end of the list with no match
|
||||||
{
|
{
|
||||||
INT32 j = atoi(COM_Argv(i+1)); // assume they gave us a gametype number, which is okay too
|
d = atoi(arg_gametype);
|
||||||
if (j >= 0 && j < NUMGAMETYPES)
|
// assume they gave us a gametype number, which is okay too
|
||||||
newgametype = (INT16)j;
|
if (d >= 0 && d < NUMGAMETYPES)
|
||||||
|
newgametype = d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't use a gametype the map doesn't support
|
||||||
|
if (cv_debug || user_options[MAP_COMMAND_FORCE_OPTION] || cv_skipmapcheck.value)
|
||||||
|
fromlevelselect = false; // The player wants us to trek on anyway. Do so.
|
||||||
|
// G_TOLFlag handles both multiplayer gametype and ignores it for !multiplayer
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!(
|
||||||
|
mapheaderinfo[newmapnum-1] &&
|
||||||
|
mapheaderinfo[newmapnum-1]->typeoflevel & G_TOLFlag(newgametype)
|
||||||
|
))
|
||||||
|
{
|
||||||
|
CONS_Alert(CONS_WARNING, M_GetText("%s (%s) doesn't support %s mode!\n(Use -force to override)\n"), realmapname, G_BuildMapName(newmapnum),
|
||||||
|
(multiplayer ? gametype_cons_t[newgametype].strvalue : "Single Player"));
|
||||||
|
Z_Free(realmapname);
|
||||||
|
Z_Free(mapname);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fromlevelselect =
|
||||||
|
( netgame || multiplayer ) &&
|
||||||
|
newgametype == gametype &&
|
||||||
|
newgametype == GT_COOP;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1828,31 +2037,14 @@ static void Command_Map_f(void)
|
||||||
if (!dedicated && M_MapLocked(newmapnum))
|
if (!dedicated && M_MapLocked(newmapnum))
|
||||||
{
|
{
|
||||||
CONS_Alert(CONS_NOTICE, M_GetText("You need to unlock this level before you can warp to it!\n"));
|
CONS_Alert(CONS_NOTICE, M_GetText("You need to unlock this level before you can warp to it!\n"));
|
||||||
|
Z_Free(realmapname);
|
||||||
|
Z_Free(mapname);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't use a gametype the map doesn't support
|
// Ultimate Mode only in SP via menu
|
||||||
if (cv_debug || COM_CheckParm("-force") || cv_skipmapcheck.value)
|
if (netgame || multiplayer)
|
||||||
fromlevelselect = false; // The player wants us to trek on anyway. Do so.
|
ultimatemode = false;
|
||||||
// G_TOLFlag handles both multiplayer gametype and ignores it for !multiplayer
|
|
||||||
// Alternatively, bail if the map header is completely missing anyway.
|
|
||||||
else if (!mapheaderinfo[newmapnum-1]
|
|
||||||
|| !(mapheaderinfo[newmapnum-1]->typeoflevel & G_TOLFlag(newgametype)))
|
|
||||||
{
|
|
||||||
char gametypestring[32] = "Single Player";
|
|
||||||
|
|
||||||
if (multiplayer)
|
|
||||||
{
|
|
||||||
if (newgametype >= 0 && newgametype < NUMGAMETYPES
|
|
||||||
&& Gametype_Names[newgametype])
|
|
||||||
strcpy(gametypestring, Gametype_Names[newgametype]);
|
|
||||||
}
|
|
||||||
|
|
||||||
CONS_Alert(CONS_WARNING, M_GetText("%s doesn't support %s mode!\n(Use -force to override)\n"), mapname, gametypestring);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
fromlevelselect = ((netgame || multiplayer) && ((gametype == newgametype) && (newgametype == GT_COOP)));
|
|
||||||
|
|
||||||
if (tutorialmode && tutorialgcs)
|
if (tutorialmode && tutorialgcs)
|
||||||
{
|
{
|
||||||
|
@ -1865,7 +2057,10 @@ static void Command_Map_f(void)
|
||||||
tutorialmode = false; // warping takes us out of tutorial mode
|
tutorialmode = false; // warping takes us out of tutorial mode
|
||||||
|
|
||||||
D_MapChange(newmapnum, newgametype, false, newresetplayers, 0, false, fromlevelselect);
|
D_MapChange(newmapnum, newgametype, false, newresetplayers, 0, false, fromlevelselect);
|
||||||
|
|
||||||
|
Z_Free(realmapname);
|
||||||
}
|
}
|
||||||
|
#undef CHECKPARM
|
||||||
|
|
||||||
/** Receives a map command and changes the map.
|
/** Receives a map command and changes the map.
|
||||||
*
|
*
|
||||||
|
|
|
@ -495,6 +495,7 @@ extern boolean capslock;
|
||||||
|
|
||||||
// if we ever make our alloc stuff...
|
// if we ever make our alloc stuff...
|
||||||
#define ZZ_Alloc(x) Z_Malloc(x, PU_STATIC, NULL)
|
#define ZZ_Alloc(x) Z_Malloc(x, PU_STATIC, NULL)
|
||||||
|
#define ZZ_Calloc(x) Z_Calloc(x, PU_STATIC, NULL)
|
||||||
|
|
||||||
// i_system.c, replace getchar() once the keyboard has been appropriated
|
// i_system.c, replace getchar() once the keyboard has been appropriated
|
||||||
INT32 I_GetKey(void);
|
INT32 I_GetKey(void);
|
||||||
|
|
|
@ -115,6 +115,9 @@ typedef long ssize_t;
|
||||||
#define strnicmp(x,y,n) strncasecmp(x,y,n)
|
#define strnicmp(x,y,n) strncasecmp(x,y,n)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
char *strcasestr(const char *in, const char *what);
|
||||||
|
#define stristr strcasestr
|
||||||
|
|
||||||
#if defined (macintosh) //|| defined (__APPLE__) //skip all boolean/Boolean crap
|
#if defined (macintosh) //|| defined (__APPLE__) //skip all boolean/Boolean crap
|
||||||
#define true 1
|
#define true 1
|
||||||
#define false 0
|
#define false 0
|
||||||
|
|
181
src/g_game.c
181
src/g_game.c
|
@ -4047,6 +4047,187 @@ char *G_BuildMapTitle(INT32 mapnum)
|
||||||
return title;
|
return title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void measurekeywords(mapsearchfreq_t *fr,
|
||||||
|
struct searchdim **dimp, UINT8 *cuntp,
|
||||||
|
const char *s, const char *q, boolean wanttable)
|
||||||
|
{
|
||||||
|
char *qp;
|
||||||
|
char *sp;
|
||||||
|
if (wanttable)
|
||||||
|
(*dimp) = Z_Realloc((*dimp), 255 * sizeof (struct searchdim),
|
||||||
|
PU_STATIC, NULL);
|
||||||
|
for (qp = strtok(va("%s", q), " ");
|
||||||
|
qp && fr->total < 255;
|
||||||
|
qp = strtok(0, " "))
|
||||||
|
{
|
||||||
|
if (( sp = strcasestr(s, qp) ))
|
||||||
|
{
|
||||||
|
if (wanttable)
|
||||||
|
{
|
||||||
|
(*dimp)[(*cuntp)].pos = sp - s;
|
||||||
|
(*dimp)[(*cuntp)].siz = strlen(qp);
|
||||||
|
}
|
||||||
|
(*cuntp)++;
|
||||||
|
fr->total++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (wanttable)
|
||||||
|
(*dimp) = Z_Realloc((*dimp), (*cuntp) * sizeof (struct searchdim),
|
||||||
|
PU_STATIC, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void writesimplefreq(mapsearchfreq_t *fr, INT32 *frc,
|
||||||
|
INT32 mapnum, UINT8 pos, UINT8 siz)
|
||||||
|
{
|
||||||
|
fr[(*frc)].mapnum = mapnum;
|
||||||
|
fr[(*frc)].matchd = ZZ_Alloc(sizeof (struct searchdim));
|
||||||
|
fr[(*frc)].matchd[0].pos = pos;
|
||||||
|
fr[(*frc)].matchd[0].siz = siz;
|
||||||
|
fr[(*frc)].matchc = 1;
|
||||||
|
fr[(*frc)].total = 1;
|
||||||
|
(*frc)++;
|
||||||
|
}
|
||||||
|
|
||||||
|
INT32 G_FindMap(const char *mapname, char **foundmapnamep,
|
||||||
|
mapsearchfreq_t **freqp, INT32 *freqcp)
|
||||||
|
{
|
||||||
|
INT32 newmapnum = 0;
|
||||||
|
INT32 mapnum;
|
||||||
|
INT32 apromapnum = 0;
|
||||||
|
|
||||||
|
size_t mapnamelen;
|
||||||
|
char *realmapname = NULL;
|
||||||
|
char *newmapname = NULL;
|
||||||
|
char *apromapname = NULL;
|
||||||
|
char *aprop = NULL;
|
||||||
|
|
||||||
|
mapsearchfreq_t *freq;
|
||||||
|
boolean wanttable;
|
||||||
|
INT32 freqc;
|
||||||
|
UINT8 frequ;
|
||||||
|
|
||||||
|
INT32 i;
|
||||||
|
|
||||||
|
mapnamelen = strlen(mapname);
|
||||||
|
|
||||||
|
/* Count available maps; how ugly. */
|
||||||
|
for (i = 0, freqc = 0; i < NUMMAPS; ++i)
|
||||||
|
{
|
||||||
|
if (mapheaderinfo[i])
|
||||||
|
freqc++;
|
||||||
|
}
|
||||||
|
|
||||||
|
freq = ZZ_Calloc(freqc * sizeof (mapsearchfreq_t));
|
||||||
|
|
||||||
|
wanttable = !!( freqp );
|
||||||
|
|
||||||
|
freqc = 0;
|
||||||
|
for (i = 0, mapnum = 1; i < NUMMAPS; ++i, ++mapnum)
|
||||||
|
if (mapheaderinfo[i])
|
||||||
|
{
|
||||||
|
if (!( realmapname = G_BuildMapTitle(mapnum) ))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
aprop = realmapname;
|
||||||
|
|
||||||
|
/* Now that we found a perfect match no need to fucking guess. */
|
||||||
|
if (strnicmp(realmapname, mapname, mapnamelen) == 0)
|
||||||
|
{
|
||||||
|
if (wanttable)
|
||||||
|
{
|
||||||
|
writesimplefreq(freq, &freqc, mapnum, 0, mapnamelen);
|
||||||
|
}
|
||||||
|
if (newmapnum == 0)
|
||||||
|
{
|
||||||
|
newmapnum = mapnum;
|
||||||
|
newmapname = realmapname;
|
||||||
|
realmapname = 0;
|
||||||
|
Z_Free(apromapname);
|
||||||
|
if (!wanttable)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (apromapnum == 0 || wanttable)
|
||||||
|
{
|
||||||
|
/* LEVEL 1--match keywords verbatim */
|
||||||
|
if (( aprop = strcasestr(realmapname, mapname) ))
|
||||||
|
{
|
||||||
|
if (wanttable)
|
||||||
|
{
|
||||||
|
writesimplefreq(freq, &freqc,
|
||||||
|
mapnum, aprop - realmapname, mapnamelen);
|
||||||
|
}
|
||||||
|
if (apromapnum == 0)
|
||||||
|
{
|
||||||
|
apromapnum = mapnum;
|
||||||
|
apromapname = realmapname;
|
||||||
|
realmapname = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else/* ...match individual keywords */
|
||||||
|
{
|
||||||
|
freq[freqc].mapnum = mapnum;
|
||||||
|
measurekeywords(&freq[freqc],
|
||||||
|
&freq[freqc].matchd, &freq[freqc].matchc,
|
||||||
|
realmapname, mapname, wanttable);
|
||||||
|
if (freq[freqc].total)
|
||||||
|
freqc++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Z_Free(realmapname);/* leftover old name */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newmapnum == 0)/* no perfect match--try a substring */
|
||||||
|
{
|
||||||
|
newmapnum = apromapnum;
|
||||||
|
newmapname = apromapname;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newmapnum == 0)/* calculate most queries met! */
|
||||||
|
{
|
||||||
|
frequ = 0;
|
||||||
|
for (i = 0; i < freqc; ++i)
|
||||||
|
{
|
||||||
|
if (freq[i].total > frequ)
|
||||||
|
{
|
||||||
|
frequ = freq[i].total;
|
||||||
|
newmapnum = freq[i].mapnum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (newmapnum)
|
||||||
|
{
|
||||||
|
newmapname = G_BuildMapTitle(newmapnum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (freqp)
|
||||||
|
(*freqp) = freq;
|
||||||
|
else
|
||||||
|
Z_Free(freq);
|
||||||
|
|
||||||
|
if (freqcp)
|
||||||
|
(*freqcp) = freqc;
|
||||||
|
|
||||||
|
if (foundmapnamep)
|
||||||
|
(*foundmapnamep) = newmapname;
|
||||||
|
else
|
||||||
|
Z_Free(newmapname);
|
||||||
|
|
||||||
|
return newmapnum;
|
||||||
|
}
|
||||||
|
|
||||||
|
void G_FreeMapSearch(mapsearchfreq_t *freq, INT32 freqc)
|
||||||
|
{
|
||||||
|
INT32 i;
|
||||||
|
for (i = 0; i < freqc; ++i)
|
||||||
|
{
|
||||||
|
Z_Free(freq[i].matchd);
|
||||||
|
}
|
||||||
|
Z_Free(freq);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// DEMO RECORDING
|
// DEMO RECORDING
|
||||||
//
|
//
|
||||||
|
|
21
src/g_game.h
21
src/g_game.h
|
@ -108,6 +108,27 @@ void G_InitNew(UINT8 pultmode, const char *mapname, boolean resetplayer,
|
||||||
boolean skipprecutscene, boolean FLS);
|
boolean skipprecutscene, boolean FLS);
|
||||||
char *G_BuildMapTitle(INT32 mapnum);
|
char *G_BuildMapTitle(INT32 mapnum);
|
||||||
|
|
||||||
|
struct searchdim
|
||||||
|
{
|
||||||
|
UINT8 pos;
|
||||||
|
UINT8 siz;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
INT16 mapnum;
|
||||||
|
UINT8 matchc;
|
||||||
|
struct searchdim *matchd;/* offset that a pattern was matched */
|
||||||
|
UINT8 keywhc;
|
||||||
|
struct searchdim *keywhd;/* ...in KEYWORD */
|
||||||
|
UINT8 total;/* total hits */
|
||||||
|
}
|
||||||
|
mapsearchfreq_t;
|
||||||
|
|
||||||
|
INT32 G_FindMap(const char *query, char **foundmapnamep,
|
||||||
|
mapsearchfreq_t **freqp, INT32 *freqc);
|
||||||
|
void G_FreeMapSearch(mapsearchfreq_t *freq, INT32 freqc);
|
||||||
|
|
||||||
// XMOD spawning
|
// XMOD spawning
|
||||||
mapthing_t *G_FindCTFStart(INT32 playernum);
|
mapthing_t *G_FindCTFStart(INT32 playernum);
|
||||||
mapthing_t *G_FindMatchStart(INT32 playernum);
|
mapthing_t *G_FindMatchStart(INT32 playernum);
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
/*
|
||||||
|
strcasestr -- case insensitive substring searching function.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
Copyright 2019 James R.
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source forms, with or without modification, is
|
||||||
|
permitted provided that the following condition is met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
condition and the following disclaimer.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||||
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SWAP( a, b ) \
|
||||||
|
(\
|
||||||
|
(a) ^= (b),\
|
||||||
|
(b) ^= (a),\
|
||||||
|
(a) ^= (b)\
|
||||||
|
)
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
trycmp (char **pp, char *cp,
|
||||||
|
const char *q, size_t qn)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
p = (*pp);
|
||||||
|
if (strncasecmp(p, q, qn) == 0)
|
||||||
|
return 0;
|
||||||
|
(*pp) = strchr(&p[1], (*cp));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
swapp (char ***ppap, char ***ppbp, char **cpap, char **cpbp)
|
||||||
|
{
|
||||||
|
SWAP(*(intptr_t *)ppap, *(intptr_t *)ppbp);
|
||||||
|
SWAP(*(intptr_t *)cpap, *(intptr_t *)cpbp);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
strcasestr (const char *s, const char *q)
|
||||||
|
{
|
||||||
|
size_t qn;
|
||||||
|
|
||||||
|
char uc;
|
||||||
|
char lc;
|
||||||
|
|
||||||
|
char *up;
|
||||||
|
char *lp;
|
||||||
|
|
||||||
|
char **ppa;
|
||||||
|
char **ppb;
|
||||||
|
|
||||||
|
char *cpa;
|
||||||
|
char *cpb;
|
||||||
|
|
||||||
|
uc = toupper(*q);
|
||||||
|
lc = tolower(*q);
|
||||||
|
|
||||||
|
up = strchr(s, uc);
|
||||||
|
lp = strchr(s, lc);
|
||||||
|
|
||||||
|
if (!( (intptr_t)up|(intptr_t)lp ))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!lp || up < lp)
|
||||||
|
{
|
||||||
|
ppa = &up;
|
||||||
|
ppb = &lp;
|
||||||
|
|
||||||
|
cpa = &uc;
|
||||||
|
cpb = &lc;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ppa = &lp;
|
||||||
|
ppb = &up;
|
||||||
|
|
||||||
|
cpa = &lc;
|
||||||
|
cpb = &uc;
|
||||||
|
}
|
||||||
|
|
||||||
|
qn = strlen(q);
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
if (trycmp(ppa, cpa, q, qn) == 0)
|
||||||
|
return (*ppa);
|
||||||
|
|
||||||
|
if (!( (intptr_t)up|(intptr_t)lp ))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!(*ppa) || ( (*ppb) && (*ppb) < (*ppa) ))
|
||||||
|
swapp(&ppa, &ppb, &cpa, &cpb);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Copyright (C) 2006 by Graue.
|
// Copyright (C) 2006 by Graue.
|
||||||
// Copyright (C) 2006-2018 by Sonic Team Junior.
|
// Copyright (C) 2006-2018 by Sonic Team Junior.
|
||||||
|
// Copyright (C) 2019 by James R.
|
||||||
//
|
//
|
||||||
// This program is free software distributed under the
|
// This program is free software distributed under the
|
||||||
// terms of the GNU General Public License, version 2.
|
// terms of the GNU General Public License, version 2.
|
||||||
|
@ -50,3 +51,5 @@ size_t strlcpy(char *dst, const char *src, size_t siz)
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "strcasestr.c"
|
||||||
|
|
Loading…
Reference in New Issue