Portable Half-Life SDK. GoldSource and Xash3D. Crossplatform.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

410 lines
9.9 KiB

//++ 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; 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,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