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.
409 lines
9.9 KiB
409 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 + 1; i++) |
|
vPlayerLocations[i] = Vector(0,0,0); |
|
|
|
gHUD.AddHudElem(this); |
|
|
|
HOOK_MESSAGE( Location ); |
|
HOOK_MESSAGE( InitLoc ); |
|
#if _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.1f; //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) |
|
{ |
|
/* |
|
#if _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(), (double)pLocation->m_vPosition.x, (double)pLocation->m_vPosition.y, (double)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
|
|
|