mirror of
https://git.do.srb2.org/KartKrew/Kart-Public.git
synced 2025-01-13 05:11:01 +00:00
Merge branch 'map-by-name' of https://git.do.srb2.org/KartKrew/Kart into internal16fixes
This commit is contained in:
commit
60b8916a96
10 changed files with 596 additions and 99 deletions
|
@ -353,6 +353,40 @@ size_t COM_CheckParm(const char *check)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/** \brief COM_CheckParm, but checks only the start of each argument.
|
||||
* E.g. checking for "-no" would match "-noerror" too.
|
||||
*/
|
||||
size_t COM_CheckPartialParm(const char *check)
|
||||
{
|
||||
int len;
|
||||
size_t i;
|
||||
|
||||
len = strlen(check);
|
||||
|
||||
for (i = 1; i < com_argc; i++)
|
||||
{
|
||||
if (strncasecmp(check, com_argv[i], len) == 0)
|
||||
return i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Find the first argument that starts with a hyphen (-).
|
||||
* \return The index of the argument, or 0
|
||||
* if there are no such arguments.
|
||||
*/
|
||||
size_t COM_FirstOption(void)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 1; i < com_argc; i++)
|
||||
{
|
||||
if (com_argv[i][0] == '-')/* options start with a hyphen */
|
||||
return i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Parses a string into command-line tokens.
|
||||
*
|
||||
* \param ptext A null-terminated string. Does not need to be
|
||||
|
|
|
@ -37,6 +37,8 @@ size_t COM_Argc(void);
|
|||
const char *COM_Argv(size_t arg); // if argv > argc, returns empty string
|
||||
char *COM_Args(void);
|
||||
size_t COM_CheckParm(const char *check); // like M_CheckParm :)
|
||||
size_t COM_CheckPartialParm(const char *check);
|
||||
size_t COM_FirstOption(void);
|
||||
|
||||
// match existing command or NULL
|
||||
const char *COM_CompleteCommand(const char *partial, INT32 skips);
|
||||
|
|
37
src/d_main.c
37
src/d_main.c
|
@ -1247,26 +1247,6 @@ void D_SRB2Main(void)
|
|||
if (M_CheckParm("-server") || dedicated)
|
||||
netgame = server = true;
|
||||
|
||||
if (M_CheckParm("-warp") && M_IsNextParm())
|
||||
{
|
||||
const char *word = M_GetNextParm();
|
||||
char ch; // use this with sscanf to catch non-digits with
|
||||
if (fastncmp(word, "MAP", 3)) // MAPxx name
|
||||
pstartmap = M_MapNumber(word[3], word[4]);
|
||||
else if (sscanf(word, "%d%c", &pstartmap, &ch) != 1) // a plain number
|
||||
I_Error("Cannot warp to map %s (invalid map name)\n", word);
|
||||
// Don't check if lump exists just yet because the wads haven't been loaded!
|
||||
// Just do a basic range check here.
|
||||
if (pstartmap < 1 || pstartmap > NUMMAPS)
|
||||
I_Error("Cannot warp to map %d (out of range)\n", pstartmap);
|
||||
else
|
||||
{
|
||||
if (!M_CheckParm("-server"))
|
||||
G_SetGameModified(true, true);
|
||||
autostart = true;
|
||||
}
|
||||
}
|
||||
|
||||
CONS_Printf("Z_Init(): Init zone memory allocation daemon. \n");
|
||||
Z_Init();
|
||||
|
||||
|
@ -1446,6 +1426,23 @@ void D_SRB2Main(void)
|
|||
|
||||
//------------------------------------------------ COMMAND LINE PARAMS
|
||||
|
||||
// this must be done after loading gamedata,
|
||||
// to avoid setting off the corrupted gamedata code in G_LoadGameData if a SOC with custom gamedata is added
|
||||
// -- Monster Iestyn 20/02/20
|
||||
if (M_CheckParm("-warp") && M_IsNextParm())
|
||||
{
|
||||
const char *word = M_GetNextParm();
|
||||
pstartmap = G_FindMapByNameOrCode(word, 0);
|
||||
if (! pstartmap)
|
||||
I_Error("Cannot find a map remotely named '%s'\n", word);
|
||||
else
|
||||
{
|
||||
if (!M_CheckParm("-server"))
|
||||
G_SetGameModified(true, true);
|
||||
autostart = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize CD-Audio
|
||||
if (M_CheckParm("-usecd") && !dedicated)
|
||||
I_InitCD();
|
||||
|
|
244
src/d_netcmd.c
244
src/d_netcmd.c
|
@ -2519,27 +2519,67 @@ void D_PickVote(void)
|
|||
SendNetXCmd(XD_PICKVOTE, &buf, 2);
|
||||
}
|
||||
|
||||
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.
|
||||
// Called either from map <mapname> console command, or idclev cheat.
|
||||
//
|
||||
// Largely rewritten by James.
|
||||
//
|
||||
static void Command_Map_f(void)
|
||||
{
|
||||
const char *mapname;
|
||||
size_t i;
|
||||
INT32 newmapnum;
|
||||
boolean newresetplayers, newencoremode;
|
||||
INT32 newgametype = gametype;
|
||||
size_t first_option;
|
||||
size_t option_force;
|
||||
size_t option_gametype;
|
||||
size_t option_encore;
|
||||
const char *gametypename;
|
||||
boolean newresetplayers;
|
||||
|
||||
// max length of command: map map03 -gametype race -noresetplayers -force -encore
|
||||
// 1 2 3 4 5 6 7
|
||||
// = 8 arg max
|
||||
// i don't know whether this is intrinsic to the system or just someone being weird but
|
||||
// "noresetplayers" is pretty useless for kart if it turns out this is too close to the limit
|
||||
if (COM_Argc() < 2 || COM_Argc() > 8)
|
||||
{
|
||||
CONS_Printf(M_GetText("map <mapname> [-gametype <type> [-force]: warp to map\n"));
|
||||
return;
|
||||
}
|
||||
boolean mustmodifygame;
|
||||
|
||||
INT32 newmapnum;
|
||||
|
||||
char * mapname;
|
||||
char *realmapname = NULL;
|
||||
|
||||
INT32 newgametype = gametype;
|
||||
boolean newencoremode = cv_kartencore.value;
|
||||
|
||||
INT32 d;
|
||||
|
||||
if (client && !IsPlayerAdmin(consoleplayer))
|
||||
{
|
||||
|
@ -2547,99 +2587,129 @@ static void Command_Map_f(void)
|
|||
return;
|
||||
}
|
||||
|
||||
// internal wad lump always: map command doesn't support external files as in doom legacy
|
||||
if (W_CheckNumForName(COM_Argv(1)) == LUMPERROR)
|
||||
option_force = COM_CheckPartialParm("-f");
|
||||
option_gametype = COM_CheckPartialParm("-g");
|
||||
option_encore = COM_CheckPartialParm("-e");
|
||||
newresetplayers = ! COM_CheckParm("-noresetplayers");
|
||||
|
||||
mustmodifygame = !( netgame || multiplayer || majormods );
|
||||
|
||||
if (mustmodifygame && !option_force)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
if (!(netgame || multiplayer) && !majormods)
|
||||
{
|
||||
if (COM_CheckParm("-force"))
|
||||
{
|
||||
G_SetGameModified(false, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
CONS_Printf(M_GetText("Sorry, level change disabled in single player.\n"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
newresetplayers = !COM_CheckParm("-noresetplayers");
|
||||
|
||||
if (!newresetplayers && !cv_debug)
|
||||
{
|
||||
CONS_Printf(M_GetText("DEVMODE must be enabled.\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
mapname = COM_Argv(1);
|
||||
if (strlen(mapname) != 5
|
||||
|| (newmapnum = M_MapNumber(mapname[3], mapname[4])) == 0)
|
||||
if (option_gametype)
|
||||
{
|
||||
CONS_Alert(CONS_ERROR, M_GetText("Invalid level name %s\n"), mapname);
|
||||
if (!multiplayer)
|
||||
{
|
||||
CONS_Printf(M_GetText(
|
||||
"You can't switch gametypes in single player!\n"));
|
||||
return;
|
||||
}
|
||||
else if (COM_Argc() < option_gametype + 2)/* no argument after? */
|
||||
{
|
||||
CONS_Alert(CONS_ERROR,
|
||||
"No gametype name follows parameter '%s'.\n",
|
||||
COM_Argv(option_gametype));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!( first_option = COM_FirstOption() ))
|
||||
first_option = COM_Argc();
|
||||
|
||||
if (first_option < 2)
|
||||
{
|
||||
/* I'm going over the fucking lines and I DON'T CAREEEEE */
|
||||
CONS_Printf("map <name / [MAP]code / number> [-gametype <type>] [-encore] [-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 and may be abbreviated.\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
mapname = ConcatCommandArgv(1, first_option);
|
||||
|
||||
newmapnum = G_FindMapByNameOrCode(mapname, &realmapname);
|
||||
|
||||
if (newmapnum == 0)
|
||||
{
|
||||
CONS_Alert(CONS_ERROR, M_GetText("Could not find any map described as '%s'.\n"), mapname);
|
||||
Z_Free(mapname);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mustmodifygame && option_force)
|
||||
{
|
||||
G_SetGameModified(false, true);
|
||||
}
|
||||
|
||||
// new gametype value
|
||||
// use current one by default
|
||||
i = COM_CheckParm("-gametype");
|
||||
if (i)
|
||||
if (option_gametype)
|
||||
{
|
||||
if (!multiplayer)
|
||||
{
|
||||
CONS_Printf(M_GetText("You can't switch gametypes in single player!\n"));
|
||||
return;
|
||||
}
|
||||
gametypename = COM_Argv(option_gametype + 1);
|
||||
|
||||
newgametype = G_GetGametypeByName(gametypename);
|
||||
|
||||
newgametype = G_GetGametypeByName(COM_Argv(i+1));
|
||||
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
|
||||
if (j >= 0 && j < NUMGAMETYPES)
|
||||
newgametype = (INT16)j;
|
||||
/* Did they give us a gametype number? That's okay too! */
|
||||
if (isdigit(gametypename[0]))
|
||||
{
|
||||
d = atoi(gametypename);
|
||||
if (d >= 0 && d < NUMGAMETYPES)
|
||||
newgametype = d;
|
||||
else
|
||||
{
|
||||
CONS_Alert(CONS_ERROR,
|
||||
"Gametype number %d is out of range. Use a number between"
|
||||
" 0 and %d inclusive. ...Or just use the name. :v\n",
|
||||
d,
|
||||
NUMGAMETYPES-1);
|
||||
Z_Free(realmapname);
|
||||
Z_Free(mapname);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CONS_Alert(CONS_ERROR,
|
||||
"'%s' is not a gametype.\n",
|
||||
gametypename);
|
||||
Z_Free(realmapname);
|
||||
Z_Free(mapname);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// new encoremode value
|
||||
// use cvar by default
|
||||
|
||||
newencoremode = (boolean)cv_kartencore.value;
|
||||
|
||||
if (COM_CheckParm("-encore"))
|
||||
{
|
||||
if (!M_SecretUnlocked(SECRET_ENCORE) && !newencoremode)
|
||||
{
|
||||
CONS_Alert(CONS_NOTICE, M_GetText("You haven't unlocked Encore Mode yet!\n"));
|
||||
return;
|
||||
}
|
||||
newencoremode = !newencoremode;
|
||||
}
|
||||
|
||||
if (!(i = COM_CheckParm("-force")) && newgametype == gametype) // SRB2Kart
|
||||
if (!option_force && newgametype == gametype) // SRB2Kart
|
||||
newresetplayers = false; // if not forcing and gametypes is the same
|
||||
|
||||
// don't use a gametype the map doesn't support
|
||||
if (cv_debug || i || cv_skipmapcheck.value)
|
||||
; // The player wants us to trek on anyway. Do so.
|
||||
if (cv_debug || option_force || 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
|
||||
// Alternatively, bail if the map header is completely missing anyway.
|
||||
else if (!mapheaderinfo[newmapnum-1]
|
||||
|| !(mapheaderinfo[newmapnum-1]->typeoflevel & G_TOLFlag(newgametype)))
|
||||
else
|
||||
{
|
||||
char gametypestring[32] = "Single Player";
|
||||
|
||||
if (multiplayer)
|
||||
if (!(mapheaderinfo[newmapnum-1]->typeoflevel & G_TOLFlag(newgametype)))
|
||||
{
|
||||
if (newgametype >= 0 && newgametype < NUMGAMETYPES
|
||||
&& Gametype_Names[newgametype])
|
||||
strcpy(gametypestring, Gametype_Names[newgametype]);
|
||||
CONS_Alert(CONS_WARNING, M_GetText("Course %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;
|
||||
}
|
||||
|
||||
CONS_Alert(CONS_WARNING, M_GetText("%s doesn't support %s mode!\n(Use -force to override)\n"), mapname, gametypestring);
|
||||
return;
|
||||
}
|
||||
|
||||
// Prevent warping to locked levels
|
||||
|
@ -2649,11 +2719,25 @@ static void Command_Map_f(void)
|
|||
if (!dedicated && M_MapLocked(newmapnum))
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
if (option_encore)
|
||||
{
|
||||
newencoremode = ! newencoremode;
|
||||
if (! M_SecretUnlocked(SECRET_ENCORE) && newencoremode)
|
||||
{
|
||||
CONS_Alert(CONS_NOTICE, M_GetText("You haven't unlocked Encore Mode yet!\n"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fromlevelselect = false;
|
||||
D_MapChange(newmapnum, newgametype, newencoremode, newresetplayers, 0, false, false);
|
||||
|
||||
Z_Free(realmapname);
|
||||
}
|
||||
|
||||
/** Receives a map command and changes the map.
|
||||
|
@ -2702,7 +2786,9 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum)
|
|||
lastgametype = gametype;
|
||||
gametype = READUINT8(*cp);
|
||||
|
||||
if (gametype != lastgametype)
|
||||
if (gametype < 0 || gametype >= NUMGAMETYPES)
|
||||
gametype = lastgametype;
|
||||
else if (gametype != lastgametype)
|
||||
D_GameTypeChanged(lastgametype); // emulate consvar_t behavior for gametype
|
||||
|
||||
if (!G_RaceGametype())
|
||||
|
|
|
@ -532,6 +532,7 @@ extern boolean capslock;
|
|||
|
||||
// if we ever make our alloc stuff...
|
||||
#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
|
||||
INT32 I_GetKey(void);
|
||||
|
|
|
@ -139,6 +139,9 @@ typedef long ssize_t;
|
|||
#define strlwr _strlwr
|
||||
#endif
|
||||
|
||||
char *strcasestr(const char *in, const char *what);
|
||||
#define stristr strcasestr
|
||||
|
||||
#if defined (macintosh) //|| defined (__APPLE__) //skip all boolean/Boolean crap
|
||||
#define true 1
|
||||
#define false 0
|
||||
|
|
236
src/g_game.c
236
src/g_game.c
|
@ -4866,6 +4866,242 @@ char *G_BuildMapTitle(INT32 mapnum)
|
|||
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);
|
||||
}
|
||||
|
||||
INT32 G_FindMapByNameOrCode(const char *mapname, char **realmapnamep)
|
||||
{
|
||||
boolean usemapcode = false;
|
||||
|
||||
INT32 newmapnum;
|
||||
|
||||
size_t mapnamelen;
|
||||
|
||||
char *p;
|
||||
|
||||
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]) ))
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
usemapcode = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
newmapnum = G_FindMap(mapname, realmapnamep, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (usemapcode)
|
||||
{
|
||||
/* we can't check mapheaderinfo for this hahahaha */
|
||||
if (W_CheckNumForName(G_BuildMapName(newmapnum)) == LUMPERROR)
|
||||
return 0;
|
||||
|
||||
if (realmapnamep)
|
||||
(*realmapnamep) = G_BuildMapTitle(newmapnum);
|
||||
}
|
||||
|
||||
return newmapnum;
|
||||
}
|
||||
|
||||
//
|
||||
// DEMO RECORDING
|
||||
//
|
||||
|
|
24
src/g_game.h
24
src/g_game.h
|
@ -173,6 +173,30 @@ void G_InitNew(UINT8 pencoremode, const char *mapname, boolean resetplayer,
|
|||
boolean skipprecutscene);
|
||||
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);
|
||||
|
||||
/* Match map name by search + 2 digit map code or map number. */
|
||||
INT32 G_FindMapByNameOrCode(const char *query, char **foundmapnamep);
|
||||
|
||||
// XMOD spawning
|
||||
mapthing_t *G_FindCTFStart(INT32 playernum);
|
||||
mapthing_t *G_FindMatchStart(INT32 playernum);
|
||||
|
|
111
src/strcasestr.c
Normal file
111
src/strcasestr.c
Normal file
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
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)
|
||||
{
|
||||
char **pp;
|
||||
char *p;
|
||||
|
||||
pp = *ppap;
|
||||
*ppap = *ppbp;
|
||||
*ppbp = pp;
|
||||
|
||||
p = *cpap;
|
||||
*cpap = *cpbp;
|
||||
*cpbp = p;
|
||||
}
|
||||
|
||||
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 && 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-2018 by Sonic Team Junior.
|
||||
// Copyright (C) 2019 by James R.
|
||||
//
|
||||
// This program is free software distributed under the
|
||||
// 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
|
||||
|
||||
#include "strcasestr.c"
|
||||
|
|
Loading…
Reference in a new issue