mirror of
https://github.com/blendogames/thirtyflightsofloving.git
synced 2024-11-14 16:40:57 +00:00
495 lines
No EOL
12 KiB
C
495 lines
No EOL
12 KiB
C
/*
|
|
===========================================================================
|
|
Copyright (C) 1997-2001 Id Software, Inc.
|
|
|
|
This file is part of Quake 2 source code.
|
|
|
|
Quake 2 source code 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.
|
|
|
|
Quake 2 source code 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 Quake 2 source code; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
===========================================================================
|
|
*/
|
|
|
|
/*
|
|
NoCheat LOC support by NiceAss
|
|
Edited and Fixed by Xile and FourthX
|
|
*/
|
|
|
|
#include "client.h"
|
|
|
|
#ifdef LOC_SUPPORT
|
|
|
|
typedef struct {
|
|
vec3_t origin;
|
|
char name[64];
|
|
qboolean used;
|
|
} loc_t;
|
|
|
|
#define MAX_LOCATIONS 768
|
|
|
|
loc_t locations[MAX_LOCATIONS];
|
|
|
|
|
|
/*
|
|
=================
|
|
CL_FreeLoc
|
|
=================
|
|
*/
|
|
int CL_FreeLoc (void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < MAX_LOCATIONS; i++)
|
|
{
|
|
if (locations[i].used == false)
|
|
return i;
|
|
}
|
|
|
|
// just keep overwriting the last one....
|
|
return MAX_LOCATIONS - 1;
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
CL_LoadLoc
|
|
=================
|
|
*/
|
|
void CL_LoadLoc (void)
|
|
{
|
|
char mapname[MAX_QPATH];
|
|
char filename[MAX_OSPATH];
|
|
char *buf, *line, *nl, *cr, *tok;
|
|
char *token1, *token2, *token3, *token4;
|
|
int fSize, nLines, index;
|
|
qboolean isCommentLine, fpFormat = false;
|
|
// FILE *f;
|
|
|
|
memset(locations, 0, sizeof(loc_t) * MAX_LOCATIONS);
|
|
|
|
// format map pathname
|
|
Q_strncpyz (mapname, sizeof(mapname), cl.configstrings[CS_MODELS + 1] + 5); // skip "maps/"
|
|
mapname[strlen(mapname) - 4] = 0; // remove ".bsp"
|
|
Com_sprintf (filename, sizeof(filename), "locs/%s.loc", mapname);
|
|
|
|
// load file and check buffer and size
|
|
fSize = FS_LoadFile (filename, &buf);
|
|
if (!buf) {
|
|
Com_DPrintf("CL_LoadLoc: Couldn't load %s\n", filename);
|
|
return;
|
|
}
|
|
if (fSize < 7) {
|
|
Com_Printf(S_COLOR_YELLOW"CL_LoadLoc: Loc file %s is too small: %d\n", filename, fSize);
|
|
FS_FreeFile (buf);
|
|
return;
|
|
}
|
|
|
|
// check if it's in floating-point format
|
|
if ( strstr(buf, ".000") || strstr(buf, ".125") || strstr(buf, ".250") || strstr(buf, ".375")
|
|
|| strstr(buf, ".500") || strstr(buf, ".625") || strstr(buf, ".750") || strstr(buf, ".875") ) {
|
|
// Com_DPrintf("CL_LoadLoc: %s is in floating-point format.\n", filename);
|
|
fpFormat = true;
|
|
}
|
|
|
|
line = buf;
|
|
nLines = 0;
|
|
while ( *line && (line < buf + fSize) )
|
|
{
|
|
// overwrite new line characters with null
|
|
nl = strchr(line, '\n');
|
|
if (nl)
|
|
*nl = '\0';
|
|
// nullify the carriage return too!
|
|
cr = strchr(line, '\r');
|
|
if (cr)
|
|
*cr = '\0';
|
|
nLines++;
|
|
|
|
// skip comments
|
|
isCommentLine = (line[0] == ':' || line[0] == ';' || line[0] == '/');
|
|
if (!isCommentLine)
|
|
{
|
|
// break the line up into 4 tokens
|
|
token1 = line;
|
|
token2 = strchr(token1, ' ');
|
|
if (token2 == NULL) {
|
|
Com_Printf(S_COLOR_YELLOW"CL_LoadLoc: Line %d is incomplete in %s\n", nLines, filename);
|
|
continue;
|
|
}
|
|
*token2 = '\0';
|
|
token2++;
|
|
|
|
token3 = strchr(token2, ' ');
|
|
if (token3 == NULL) {
|
|
Com_Printf(S_COLOR_YELLOW"CL_LoadLoc: Line %d is incomplete in %s\n", nLines, filename);
|
|
continue;
|
|
}
|
|
*token3 = '\0';
|
|
token3++;
|
|
|
|
token4 = strchr(token3, ' ');
|
|
if (token4 == NULL) {
|
|
Com_Printf(S_COLOR_YELLOW"CL_LoadLoc: Line %d is incomplete in %s\n", nLines, filename);
|
|
continue;
|
|
}
|
|
*token4 = '\0';
|
|
token4++;
|
|
|
|
// floating-point format has a ':' between coords and label
|
|
if (fpFormat) {
|
|
tok = token4;
|
|
token4 = strchr(tok, ' ');
|
|
if (token4 == NULL) {
|
|
Com_Printf(S_COLOR_YELLOW"CL_LoadLoc: Line %d is incomplete in %s\n", nLines, filename);
|
|
continue;
|
|
}
|
|
*token4 = '\0';
|
|
token4++;
|
|
}
|
|
|
|
// Com_DPrintf("%s %s %s %s\n", token1, token2, token3, token4);
|
|
|
|
// copy the data to the struct
|
|
index = CL_FreeLoc();
|
|
if (fpFormat) {
|
|
locations[index].origin[0] = atof(token1);
|
|
locations[index].origin[1] = atof(token2);
|
|
locations[index].origin[2] = atof(token3);
|
|
}
|
|
else
|
|
{
|
|
locations[index].origin[0] = atof(token1) * 0.125f;
|
|
locations[index].origin[1] = atof(token2) * 0.125f;
|
|
locations[index].origin[2] = atof(token3) * 0.125f;
|
|
}
|
|
Q_strncpyz (locations[index].name, sizeof(locations[index].name), token4);
|
|
locations[index].used = true;
|
|
|
|
// Com_DPrintf("%.3f %.3f %.3f\n", locations[index].origin[0], locations[index].origin[1], locations[index].origin[2]);
|
|
}
|
|
|
|
if (!nl) break;
|
|
|
|
line = nl + 1;
|
|
}
|
|
|
|
FS_FreeFile (buf);
|
|
|
|
Com_Printf("CL_LoadLoc: Loaded %d locations from %s.\n", nLines, filename);
|
|
|
|
/* Com_sprintf (filename, sizeof(filename), "%s/locs/%s.loc", FS_Savegamedir(), mapname); // was FS_Gamedir()
|
|
if (!(f = fopen(filename, "r"))) {
|
|
Com_DPrintf("CL_LoadLoc: Couldn't load locs/%s.loc\n", mapname);
|
|
return;
|
|
}
|
|
|
|
while (!feof(f))
|
|
{
|
|
char *token1, *token2, *token3, *token4;
|
|
char line[128], *nl;
|
|
int index;
|
|
|
|
// read a line
|
|
fgets(line, sizeof(line), f);
|
|
|
|
// skip comments
|
|
if (line[0] == ':' || line[0] == ';' || line[0] == '/')
|
|
continue;
|
|
|
|
// overwrite new line characters with null
|
|
nl = strchr(line, '\n');
|
|
if (nl)
|
|
*nl = '\0';
|
|
|
|
// break the line up into 4 tokens
|
|
token1 = line;
|
|
|
|
token2 = strchr(token1, ' ');
|
|
if (token2 == NULL)
|
|
continue;
|
|
*token2 = '\0';
|
|
token2++;
|
|
|
|
token3 = strchr(token2, ' ');
|
|
if (token3 == NULL)
|
|
continue;
|
|
*token3 = '\0';
|
|
token3++;
|
|
|
|
token4 = strchr(token3, ' ');
|
|
if (token4 == NULL)
|
|
continue;
|
|
*token4 = '\0';
|
|
token4++;
|
|
|
|
// copy the data to the structure
|
|
index = CL_FreeLoc();
|
|
locations[index].origin[0] = atof(token1) * 0.125f;
|
|
locations[index].origin[1] = atof(token2) * 0.125f;
|
|
locations[index].origin[2] = atof(token3) * 0.125f;
|
|
Q_strncpyz (locations[index].name, sizeof(locations[index].name), token4);
|
|
locations[index].used = true;
|
|
}
|
|
fclose(f);
|
|
|
|
Com_Printf("Loaded location data from locs/%s.loc.\n", mapname);
|
|
*/
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
CL_LocIndex
|
|
=================
|
|
*/
|
|
int CL_LocIndex (vec3_t origin)
|
|
{
|
|
vec3_t diff; // FourthX fix
|
|
float minDist = -1;
|
|
int locIndex = -1;
|
|
int i;
|
|
|
|
for (i = 0; i < MAX_LOCATIONS; i++)
|
|
{
|
|
float dist;
|
|
|
|
if (!locations[i].used)
|
|
continue;
|
|
|
|
VectorSubtract(origin, locations[i].origin, diff);
|
|
|
|
//dist = sqrt(diff[0]*diff[0] + diff[1]*diff[1] + diff[2]*diff[2]); // FourthX fix, wtf was this other guy thinking?!?
|
|
dist = diff[0]*diff[0] + diff[1]*diff[1] + diff[2]*diff[2]; // jit - small optimization
|
|
// (sqrt unnecessary w/relative distances: if dist1 < dist2 then dist1^2 < dist2^2)
|
|
|
|
if (dist < minDist || minDist == -1)
|
|
{
|
|
minDist = dist;
|
|
locIndex = i;
|
|
}
|
|
}
|
|
|
|
return locIndex;
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
CL_LocDelete
|
|
=================
|
|
*/
|
|
void CL_LocDelete (void)
|
|
{
|
|
vec3_t point;
|
|
int index;
|
|
|
|
point[0] = cl.frame.playerstate.pmove.origin[0] * 0.125f;
|
|
point[1] = cl.frame.playerstate.pmove.origin[1] * 0.125f;
|
|
point[2] = cl.frame.playerstate.pmove.origin[2] * 0.125f;
|
|
index = CL_LocIndex(point);
|
|
|
|
if (index != -1)
|
|
{
|
|
locations[index].used = false;
|
|
Com_Printf("Location '%s' deleted.\n", locations[index].name); // Xile reworked.
|
|
}
|
|
else
|
|
{
|
|
Com_Printf("Warning: No location to delete!\n");
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
CL_LocAdd
|
|
=================
|
|
*/
|
|
void CL_LocAdd (char *name)
|
|
{
|
|
int index = CL_FreeLoc();
|
|
|
|
locations[index].origin[0] = cl.frame.playerstate.pmove.origin[0] * 0.125f;
|
|
locations[index].origin[1] = cl.frame.playerstate.pmove.origin[1] * 0.125f;
|
|
locations[index].origin[2] = cl.frame.playerstate.pmove.origin[2] * 0.125f;
|
|
Q_strncpyz (locations[index].name, sizeof(locations[index].name), name);
|
|
locations[index].used = true;
|
|
|
|
Com_Printf("Location '%s' added at (%.3f %.3f %.3f). Loc #%d.\n", locations[index].name,
|
|
locations[index].origin[0],
|
|
locations[index].origin[1],
|
|
locations[index].origin[2],
|
|
index);
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
CL_LocWrite
|
|
=================
|
|
*/
|
|
void CL_LocWrite (void)
|
|
{
|
|
char mapname[MAX_QPATH];
|
|
char filename[MAX_OSPATH];
|
|
int i;
|
|
FILE *f;
|
|
|
|
// format map pathname
|
|
// strncpy(mapname, cl.configstrings[CS_MODELS + 1] + 5); // Xile; lets just keep saving em to one file mmmkay?
|
|
Q_strncpyz (mapname, sizeof(mapname), cl.configstrings[CS_MODELS + 1] + 5);
|
|
mapname[strlen(mapname) - 4] = 0;
|
|
Com_sprintf (filename, sizeof(filename), "%s/locs/%s.loc", FS_Savegamedir(), mapname); // was FS_Gamedir()
|
|
|
|
// Sys_Mkdir("locs");
|
|
FS_CreatePath (filename);
|
|
|
|
// if (!(f = fopen(va("locs/%s.loc", mapname), "w")))
|
|
if (!(f = fopen(filename, "w")))
|
|
{
|
|
Com_Printf(S_COLOR_YELLOW"Unable to open locs/%s.loc for writing.\n", mapname);
|
|
return;
|
|
}
|
|
|
|
fprintf(f, "// This location file is generated by KMQuake2, edit at your own risk.\n");
|
|
|
|
for (i = 0; i < MAX_LOCATIONS; i++)
|
|
{
|
|
if (!locations[i].used)
|
|
continue;
|
|
|
|
fprintf(f, "%d %d %d %s\n",
|
|
(int)(locations[i].origin[0] * 8),
|
|
(int)(locations[i].origin[1] * 8),
|
|
(int)(locations[i].origin[2] * 8),
|
|
locations[i].name);
|
|
}
|
|
|
|
fclose(f);
|
|
|
|
Com_Printf("Saved location data to locs/%s.loc.\n", mapname);
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
CL_LocPlace
|
|
=================
|
|
*/
|
|
void CL_LocPlace (void)
|
|
{
|
|
trace_t tr;
|
|
vec3_t point, end;
|
|
// int there[3];
|
|
int index1, index2 = -1;
|
|
|
|
point[0] = cl.frame.playerstate.pmove.origin[0] * 0.125f;
|
|
point[1] = cl.frame.playerstate.pmove.origin[1] * 0.125f;
|
|
point[2] = cl.frame.playerstate.pmove.origin[2] * 0.125f;
|
|
index1 = CL_LocIndex(point);
|
|
|
|
VectorMA(cl.predicted_origin, WORLD_SIZE, cl.v_forward, end); // was 8192
|
|
tr = CM_BoxTrace(cl.predicted_origin, end, vec3_origin, vec3_origin, 0, MASK_PLAYERSOLID);
|
|
// there[0] = tr.endpos[0] * 8;
|
|
// there[1] = tr.endpos[1] * 8;
|
|
// there[2] = tr.endpos[2] * 8;
|
|
index2 = CL_LocIndex(tr.endpos);
|
|
|
|
if (index1 != -1)
|
|
Cvar_ForceSet("loc_here", locations[index1].name);
|
|
else
|
|
Cvar_ForceSet("loc_here", "");
|
|
|
|
if (index2 != -1)
|
|
Cvar_ForceSet("loc_there", locations[index2].name);
|
|
else
|
|
Cvar_ForceSet("loc_there", "");
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
CL_AddViewLocs
|
|
=================
|
|
*/
|
|
void CL_AddViewLocs (void)
|
|
{
|
|
vec3_t point;
|
|
int i, index, num = 0;
|
|
|
|
// if (!cl_drawlocs->value)
|
|
if (!cl_drawlocs->integer)
|
|
return;
|
|
|
|
point[0] = cl.frame.playerstate.pmove.origin[0] * 0.125f;
|
|
point[1] = cl.frame.playerstate.pmove.origin[1] * 0.125f;
|
|
point[2] = cl.frame.playerstate.pmove.origin[2] * 0.125f;
|
|
index = CL_LocIndex(point);
|
|
|
|
for (i = 0; i < MAX_LOCATIONS; i++)
|
|
{
|
|
float dist;
|
|
entity_t ent;
|
|
|
|
if (locations[i].used == false)
|
|
continue;
|
|
|
|
dist = ((float)cl.frame.playerstate.pmove.origin[0] * 0.125f - locations[i].origin[0]) *
|
|
((float)cl.frame.playerstate.pmove.origin[0] * 0.125f - locations[i].origin[0]) +
|
|
((float)cl.frame.playerstate.pmove.origin[1] * 0.125f - locations[i].origin[1]) *
|
|
((float)cl.frame.playerstate.pmove.origin[1] * 0.125f - locations[i].origin[1]) +
|
|
((float)cl.frame.playerstate.pmove.origin[2] * 0.125f - locations[i].origin[2]) *
|
|
((float)cl.frame.playerstate.pmove.origin[2] * 0.125f - locations[i].origin[2]);
|
|
|
|
if (dist > 4000 * 4000)
|
|
continue;
|
|
|
|
memset(&ent, 0, sizeof(entity_t));
|
|
ent.origin[0] = locations[i].origin[0];
|
|
ent.origin[1] = locations[i].origin[1];
|
|
ent.origin[2] = locations[i].origin[2];
|
|
ent.skinnum = 0;
|
|
ent.skin = NULL;
|
|
// memset(ent.skins, 0, sizeof(ent.skins));
|
|
ent.model = NULL;
|
|
|
|
if (i == index)
|
|
ent.origin[2] += sin(cl.time * 0.01f) * 10.0f;
|
|
|
|
V_AddEntity(&ent);
|
|
num++;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
CL_LocHelp_f
|
|
=================
|
|
*/
|
|
void CL_LocHelp_f (void)
|
|
{
|
|
// Xile/jitspoe - simple help cmd for reference
|
|
Com_Printf(
|
|
"Loc Commands:\n"
|
|
"-------------\n"
|
|
"loc_add <label/description>\n"
|
|
"loc_del\n"
|
|
"loc_save\n"
|
|
"cl_drawlocs\n"
|
|
"say_team $loc_here\n"
|
|
"say_team $loc_there\n"
|
|
"-------------\n");
|
|
}
|
|
|
|
#endif // LOC_SUPPORT
|