|
|
|
//++ BulliT
|
|
|
|
|
|
|
|
#include "hud.h"
|
|
|
|
#include "cl_util.h"
|
|
|
|
#include "const.h"
|
|
|
|
#include "entity_state.h"
|
|
|
|
#include "cl_entity.h"
|
|
|
|
#include "parsemsg.h"
|
|
|
|
#include "agglobal.h"
|
|
|
|
#include "aghudlocation.h"
|
|
|
|
|
|
|
|
|
|
|
|
DECLARE_MESSAGE(m_Location, Location );
|
|
|
|
DECLARE_MESSAGE(m_Location, InitLoc );
|
|
|
|
DECLARE_COMMAND(m_Location, OpenLocation );
|
|
|
|
DECLARE_COMMAND(m_Location, CloseLocation );
|
|
|
|
DECLARE_COMMAND(m_Location, AddLocation );
|
|
|
|
DECLARE_COMMAND(m_Location, DeleteLocation );
|
|
|
|
DECLARE_COMMAND(m_Location, ShowLocations );
|
|
|
|
|
|
|
|
Vector vPlayerLocations[MAX_PLAYERS+1];
|
|
|
|
|
|
|
|
int AgHudLocation::Init(void)
|
|
|
|
{
|
|
|
|
m_fAt = 0;
|
|
|
|
m_fNear = 0;
|
|
|
|
m_iFlags = 0;
|
|
|
|
m_szMap[0] = '\0';
|
|
|
|
|
|
|
|
for (int i = 1; i < MAX_PLAYERS + 1; i++)
|
|
|
|
vPlayerLocations[i] = Vector(0,0,0);
|
|
|
|
|
|
|
|
gHUD.AddHudElem(this);
|
|
|
|
|
|
|
|
HOOK_MESSAGE( Location );
|
|
|
|
HOOK_MESSAGE( InitLoc );
|
|
|
|
#ifdef _DEBUG
|
|
|
|
HOOK_COMMAND("+location",OpenLocation);
|
|
|
|
HOOK_COMMAND("-location",CloseLocation);
|
|
|
|
#endif
|
|
|
|
HOOK_COMMAND("agaddloc",AddLocation);
|
|
|
|
HOOK_COMMAND("agdelloc",DeleteLocation);
|
|
|
|
HOOK_COMMAND("aglistloc",ShowLocations);
|
|
|
|
return 1;
|
|
|
|
};
|
|
|
|
|
|
|
|
AgHudLocation::~AgHudLocation()
|
|
|
|
{
|
|
|
|
//Delete all.
|
|
|
|
for (AgLocationList::iterator itrLocations = m_lstLocations.begin() ;itrLocations != m_lstLocations.end(); ++itrLocations)
|
|
|
|
delete *itrLocations;
|
|
|
|
m_lstLocations.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
int AgHudLocation::VidInit(void)
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
};
|
|
|
|
|
|
|
|
void AgHudLocation::Reset(void)
|
|
|
|
{
|
|
|
|
m_iFlags &= ~HUD_ACTIVE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int AgHudLocation::Draw(float fTime)
|
|
|
|
{
|
|
|
|
cl_entity_t* pPlayer = gEngfuncs.GetLocalPlayer(); // Get the local player's index
|
|
|
|
int r, g, b;
|
|
|
|
UnpackRGB(r,g,b, RGB_GREENISH);
|
|
|
|
int iPos = 5;
|
|
|
|
for (int i = 1; i < gEngfuncs.GetMaxClients(); i++ )
|
|
|
|
{
|
|
|
|
if (i == pPlayer->index)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if ('\0' != g_PlayerExtraInfo[i].teamname[0] &&
|
|
|
|
'\0' != g_PlayerExtraInfo[i].teamname[pPlayer->index] &&
|
|
|
|
0 == stricmp(g_PlayerExtraInfo[i].teamname, g_PlayerExtraInfo[pPlayer->index].teamname))
|
|
|
|
{
|
|
|
|
//Show his location - it's a team m8.
|
|
|
|
char szText[128];
|
|
|
|
sprintf(szText,"%s [%s]",g_PlayerInfoList[i].name,Location(vPlayerLocations[i]).c_str());
|
|
|
|
gHUD.DrawHudString(ScreenWidth/20, ScreenHeight/8 + gHUD.m_scrinfo.iCharHeight*iPos,ScreenWidth,szText,r,g,b);
|
|
|
|
iPos++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 5 != iPos;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AgHudLocation::UserCmd_OpenLocation()
|
|
|
|
{
|
|
|
|
m_iFlags |= HUD_ACTIVE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AgHudLocation::UserCmd_CloseLocation()
|
|
|
|
{
|
|
|
|
m_iFlags &= ~HUD_ACTIVE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AgHudLocation::UserCmd_AddLocation()
|
|
|
|
{
|
|
|
|
if (2 == gEngfuncs.Cmd_Argc())
|
|
|
|
{
|
|
|
|
AgString sLocation = gEngfuncs.Cmd_Argv(1);
|
|
|
|
if (0 == sLocation.size())
|
|
|
|
return;
|
|
|
|
|
|
|
|
AgLocation* pLocation = new AgLocation;
|
|
|
|
pLocation->m_sLocation = sLocation;
|
|
|
|
//pLocation->m_vPosition = vPlayerLocations[gEngfuncs.GetLocalPlayer()->index];
|
|
|
|
pLocation->m_vPosition = gEngfuncs.GetLocalPlayer()->attachment[0];
|
|
|
|
|
|
|
|
m_lstLocations.push_back(pLocation);
|
|
|
|
pLocation->Show();
|
|
|
|
|
|
|
|
Save();
|
|
|
|
|
|
|
|
char szMsg[128];
|
|
|
|
sprintf(szMsg,"Added Location %s.\n",(const char*)sLocation.c_str());
|
|
|
|
ConsolePrint(szMsg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AgHudLocation::UserCmd_DeleteLocation()
|
|
|
|
{
|
|
|
|
if (2 == gEngfuncs.Cmd_Argc())
|
|
|
|
{
|
|
|
|
AgString sLocation = gEngfuncs.Cmd_Argv(1);
|
|
|
|
if (0 == sLocation.size())
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (AgLocationList::iterator itrLocations = m_lstLocations.begin() ;itrLocations != m_lstLocations.end(); ++itrLocations)
|
|
|
|
{
|
|
|
|
if (0 == stricmp((*itrLocations)->m_sLocation.c_str(),sLocation.c_str()))
|
|
|
|
{
|
|
|
|
char szMsg[128];
|
|
|
|
sprintf(szMsg,"Deleted Location %s.\n",(const char*)sLocation.c_str());
|
|
|
|
ConsolePrint(szMsg);
|
|
|
|
|
|
|
|
AgLocation* pLocation = *itrLocations;
|
|
|
|
m_lstLocations.erase(itrLocations);
|
|
|
|
delete pLocation;
|
|
|
|
Save();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void AgHudLocation::UserCmd_ShowLocations()
|
|
|
|
{
|
|
|
|
for (AgLocationList::iterator itrLocations = m_lstLocations.begin() ;itrLocations != m_lstLocations.end(); ++itrLocations)
|
|
|
|
{
|
|
|
|
char szMsg[128];
|
|
|
|
sprintf(szMsg,"%s\n",(const char*)(*itrLocations)->m_sLocation.c_str());
|
|
|
|
ConsolePrint(szMsg);
|
|
|
|
(*itrLocations)->Show();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AgHudLocation::InitDistances()
|
|
|
|
{
|
|
|
|
if (2 > m_lstLocations.size())
|
|
|
|
return; //No use.
|
|
|
|
|
|
|
|
float fMinDistance = -1;
|
|
|
|
float fMaxdistance = 0;
|
|
|
|
|
|
|
|
//Calculate max/min distance between all locations.
|
|
|
|
for (AgLocationList::iterator itrLocations = m_lstLocations.begin() ;itrLocations != m_lstLocations.end(); ++itrLocations)
|
|
|
|
{
|
|
|
|
for (AgLocationList::iterator itr = m_lstLocations.begin() ;itr != m_lstLocations.end(); ++itr)
|
|
|
|
{
|
|
|
|
if (*itrLocations != *itr)
|
|
|
|
{
|
|
|
|
float fDistance = ((*itr)->m_vPosition - (*itrLocations)->m_vPosition).Length();
|
|
|
|
|
|
|
|
if (fDistance < fMinDistance || -1 == fMinDistance)
|
|
|
|
fMinDistance = fDistance;
|
|
|
|
|
|
|
|
if (fDistance > fMaxdistance)
|
|
|
|
fMaxdistance = fDistance;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//Now calculate when you are at/near a location or at atleast when its closest.
|
|
|
|
m_fAt = fMinDistance / 2; //You are at a location if you are one fourth between to locations.
|
|
|
|
m_fNear = fMinDistance / 1.1; //Over halfway of the mindistance you are at the "side".
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AgHudLocation::NearestLocation(const Vector& vPosition, AgLocation*& pLocation, float& fNearestdistance)
|
|
|
|
{
|
|
|
|
fNearestdistance = -1;
|
|
|
|
pLocation = NULL;
|
|
|
|
|
|
|
|
for (AgLocationList::iterator itrLocations = m_lstLocations.begin() ;itrLocations != m_lstLocations.end(); ++itrLocations)
|
|
|
|
{
|
|
|
|
float fDistance = (vPosition - (*itrLocations)->m_vPosition).Length();
|
|
|
|
|
|
|
|
if (fDistance < fNearestdistance || -1 == fNearestdistance)
|
|
|
|
{
|
|
|
|
fNearestdistance = fDistance;
|
|
|
|
pLocation = *itrLocations;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL != pLocation;
|
|
|
|
}
|
|
|
|
|
|
|
|
extern cvar_t* g_pcl_location_keywords;
|
|
|
|
|
|
|
|
AgString AgHudLocation::Location(const Vector& vLocation)
|
|
|
|
{
|
|
|
|
AgString sLocation;
|
|
|
|
if (2 > m_lstLocations.size())
|
|
|
|
return sLocation;
|
|
|
|
|
|
|
|
AgLocation* pLocation = NULL;
|
|
|
|
float fNearestDistance = 0;
|
|
|
|
|
|
|
|
if (NearestLocation(vLocation, pLocation, fNearestDistance))
|
|
|
|
{
|
|
|
|
if (pLocation)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
#ifdef _DEBUG
|
|
|
|
pLocation->Show();
|
|
|
|
#endif
|
|
|
|
*/
|
|
|
|
if (fNearestDistance < m_fAt || g_pcl_location_keywords->value < 1)
|
|
|
|
{
|
|
|
|
sLocation = pLocation->m_sLocation;
|
|
|
|
}
|
|
|
|
else if (fNearestDistance < m_fNear)
|
|
|
|
{
|
|
|
|
sLocation.append("Near ");
|
|
|
|
sLocation.append(pLocation->m_sLocation);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sLocation.append(pLocation->m_sLocation);
|
|
|
|
sLocation.append(" Side");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return sLocation;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AgHudLocation::Load()
|
|
|
|
{
|
|
|
|
for (AgLocationList::iterator itrLocations = m_lstLocations.begin() ;itrLocations != m_lstLocations.end(); ++itrLocations)
|
|
|
|
delete *itrLocations;
|
|
|
|
m_lstLocations.clear();
|
|
|
|
|
|
|
|
char szData[8196];
|
|
|
|
|
|
|
|
char szFile[MAX_PATH];
|
|
|
|
sprintf(szFile,"%s/locs/%s.loc",AgGetDirectory(),m_szMap);
|
|
|
|
FILE* pFile = fopen(szFile,"r");
|
|
|
|
if (!pFile)
|
|
|
|
{
|
|
|
|
// file error
|
|
|
|
char szMsg[128];
|
|
|
|
sprintf(szMsg,"Couldn't open location file %s.\n",szFile);
|
|
|
|
ConsolePrint(szMsg);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
enum enumParseState { Location, X, Y, Z };
|
|
|
|
enumParseState ParseState = Location;
|
|
|
|
AgLocation* pLocation = new AgLocation;
|
|
|
|
int iRead = fread(szData,sizeof(char),sizeof(szData)-2,pFile);
|
|
|
|
if (0 >= iRead)
|
|
|
|
return;
|
|
|
|
szData[iRead] = '\0';
|
|
|
|
|
|
|
|
char* pszParse = NULL;
|
|
|
|
pszParse = strtok(szData, "#");
|
|
|
|
if (pszParse)
|
|
|
|
{
|
|
|
|
while (pszParse)
|
|
|
|
{
|
|
|
|
if (Location == ParseState)
|
|
|
|
{
|
|
|
|
pLocation->m_sLocation = pszParse;
|
|
|
|
ParseState = X;
|
|
|
|
}
|
|
|
|
else if (X == ParseState)
|
|
|
|
{
|
|
|
|
pLocation->m_vPosition.x = atof(pszParse);
|
|
|
|
ParseState = Y;
|
|
|
|
}
|
|
|
|
else if (Y == ParseState)
|
|
|
|
{
|
|
|
|
pLocation->m_vPosition.y = atof(pszParse);
|
|
|
|
ParseState = Z;
|
|
|
|
}
|
|
|
|
else if (Z == ParseState)
|
|
|
|
{
|
|
|
|
pLocation->m_vPosition.z = atof(pszParse);
|
|
|
|
m_lstLocations.push_back(pLocation);
|
|
|
|
pLocation = new AgLocation;
|
|
|
|
ParseState = Location;
|
|
|
|
}
|
|
|
|
pszParse = strtok(NULL, "#");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
delete pLocation;
|
|
|
|
|
|
|
|
fclose(pFile);
|
|
|
|
|
|
|
|
InitDistances();
|
|
|
|
}
|
|
|
|
|
|
|
|
void AgHudLocation::Save()
|
|
|
|
{
|
|
|
|
InitDistances();
|
|
|
|
|
|
|
|
if (0 == m_lstLocations.size())
|
|
|
|
return;
|
|
|
|
|
|
|
|
char szFile[MAX_PATH];
|
|
|
|
sprintf(szFile,"%s/locs/%s.loc",AgGetDirectory(),m_szMap);
|
|
|
|
FILE* pFile = fopen(szFile,"wb");
|
|
|
|
if (!pFile)
|
|
|
|
{
|
|
|
|
// file error
|
|
|
|
char szMsg[128];
|
|
|
|
sprintf(szMsg,"Couldn't create/save location file %s.\n",szFile);
|
|
|
|
ConsolePrint(szMsg);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Loop and write the file.
|
|
|
|
for (AgLocationList::iterator itrLocations = m_lstLocations.begin() ;itrLocations != m_lstLocations.end(); ++itrLocations)
|
|
|
|
{
|
|
|
|
//Append.
|
|
|
|
AgLocation* pLocation = *itrLocations;
|
|
|
|
fprintf(pFile,"%s#%f#%f#%f#",(const char*)pLocation->m_sLocation.c_str(),pLocation->m_vPosition.x,pLocation->m_vPosition.y,pLocation->m_vPosition.z);
|
|
|
|
}
|
|
|
|
|
|
|
|
fflush(pFile);
|
|
|
|
fclose(pFile);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void AgHudLocation::ParseAndEditSayString(char* pszSay, int iPlayer)
|
|
|
|
{
|
|
|
|
//Make backup
|
|
|
|
char* pszText = (char*)malloc(strlen(pszSay)+1);
|
|
|
|
char* pszSayTemp = pszText;
|
|
|
|
strcpy(pszText,pszSay);
|
|
|
|
//Now parse for %L and edit it.
|
|
|
|
|
|
|
|
while (*pszSayTemp) //Dont overflow the string. Stop when its 200 chars.
|
|
|
|
{
|
|
|
|
if ('%' == *pszSayTemp)
|
|
|
|
{
|
|
|
|
pszSayTemp++;
|
|
|
|
if ('l' == *pszSayTemp || 'L' == *pszSayTemp || 'd' == *pszSayTemp || 'D' == *pszSayTemp )
|
|
|
|
{
|
|
|
|
//Location files.
|
|
|
|
pszSay = pszSay + sprintf(pszSay, "%s", Location(vPlayerLocations[iPlayer]).c_str());
|
|
|
|
pszSayTemp++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pszSay[0] = '%';
|
|
|
|
pszSay++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*pszSay = *pszSayTemp;
|
|
|
|
pszSay++;
|
|
|
|
pszSayTemp++;
|
|
|
|
}
|
|
|
|
*pszSay = '\0';
|
|
|
|
|
|
|
|
free(pszText);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int AgHudLocation::MsgFunc_Location(const char *pszName, int iSize, void *pbuf)
|
|
|
|
{
|
|
|
|
BEGIN_READ( pbuf, iSize );
|
|
|
|
vec3_t origin;
|
|
|
|
int iPlayer = READ_BYTE();
|
|
|
|
for ( int i = 0 ; i < 3 ; i++)
|
|
|
|
vPlayerLocations[iPlayer][i] = READ_COORD();
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int AgHudLocation::MsgFunc_InitLoc(const char *pszName, int iSize, void *pbuf)
|
|
|
|
{
|
|
|
|
BEGIN_READ( pbuf, iSize );
|
|
|
|
strcpy(m_szMap,READ_STRING());
|
|
|
|
Load();
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
//-- Martin Webrant
|