964 lines
23 KiB
C++
964 lines
23 KiB
C++
|
#include "g_local.h"
|
||
|
#include "Module.h"
|
||
|
#include "Tokenizer.h"
|
||
|
|
||
|
// **** STUFF FOR TOKENIZER ****
|
||
|
|
||
|
extern keywordArray_t Keywords[];
|
||
|
extern keywordArray_t Symbols[];
|
||
|
|
||
|
enum
|
||
|
{
|
||
|
// Keywords
|
||
|
TK_MONSTERS = TK_USERDEF,
|
||
|
TK_MONSTER,
|
||
|
TK_LOCATION,
|
||
|
TK_NAME,
|
||
|
TK_CLASS,
|
||
|
TK_ENEMY_GRUNT,
|
||
|
TK_ENEMY_LEADER,
|
||
|
TK_ENEMY_ANIMAL,
|
||
|
TK_ENEMY_BOSS,
|
||
|
TK_NPC,
|
||
|
TK_NPC_ANIMAL,
|
||
|
TK_SPECIAL,
|
||
|
|
||
|
// SYMBOLS
|
||
|
TK_LBRACE,
|
||
|
TK_RBRACE,
|
||
|
TK_UNDERSCORE,
|
||
|
};
|
||
|
|
||
|
keywordArray_t Keywords[] =
|
||
|
{
|
||
|
"monsters", TK_MONSTERS,
|
||
|
"monster", TK_MONSTER,
|
||
|
"location", TK_LOCATION,
|
||
|
"name", TK_NAME,
|
||
|
"class", TK_CLASS,
|
||
|
"ENEMY_GRUNT", TK_ENEMY_GRUNT,
|
||
|
"ENEMY_LEADER", TK_ENEMY_LEADER,
|
||
|
"ENEMY_ANIMAL", TK_ENEMY_ANIMAL,
|
||
|
"ENEMY_BOSS", TK_ENEMY_BOSS,
|
||
|
"NPC", TK_NPC,
|
||
|
"NPC_ANIMAL", TK_NPC_ANIMAL,
|
||
|
"SPECIAL", TK_SPECIAL,
|
||
|
|
||
|
NULL, TK_EOF,
|
||
|
};
|
||
|
|
||
|
keywordArray_t Symbols[] =
|
||
|
{
|
||
|
"{", TK_LBRACE,
|
||
|
"}", TK_RBRACE,
|
||
|
"_", TK_UNDERSCORE,
|
||
|
NULL, TK_EOF,
|
||
|
};
|
||
|
|
||
|
|
||
|
// **** END OF TOKENIZER STUFF ****
|
||
|
|
||
|
// ====== CMonsterStats Functions ====================
|
||
|
|
||
|
CMonsterStats::CMonsterStats(edict_t *Monster, int KilledValue, int SurvivalValue, monsterclass myClass)
|
||
|
{
|
||
|
if (!Monster)
|
||
|
{
|
||
|
delete this;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
m_KilledValue = KilledValue;
|
||
|
m_SurvivalValue = SurvivalValue;
|
||
|
m_MonsterClass = myClass;
|
||
|
m_MonsterID = Monster->s.number;
|
||
|
}
|
||
|
|
||
|
void CMonsterStats::Delete ()
|
||
|
{
|
||
|
delete this;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
bool CMonsterStats::MatchMonsterID(edict_t *ent)
|
||
|
{
|
||
|
if (m_MonsterID == ent->s.number )
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// ====== CPlayerStats Functions =====================
|
||
|
|
||
|
void CPlayerStats::Init(long CashInBank, long CashOnHand)
|
||
|
{
|
||
|
m_CashToBeAwarded = 0;
|
||
|
m_CashInBank = CashInBank;
|
||
|
m_CashOnHand = CashOnHand;
|
||
|
}
|
||
|
|
||
|
// ============== CNonPlayer functions ===========================
|
||
|
|
||
|
CNonPlayer::CNonPlayer(void)
|
||
|
{
|
||
|
m_MonsterName = NULL;
|
||
|
m_KilledValue = 0;
|
||
|
m_SurvivalValue = 0;
|
||
|
m_MonsterClass = ENEMY_GRUNT;
|
||
|
}
|
||
|
|
||
|
CNonPlayer::CNonPlayer(const char* name)
|
||
|
{
|
||
|
m_MonsterName = (char*)malloc(strlen(name) + 1);
|
||
|
strcpy(m_MonsterName, name);
|
||
|
m_KilledValue = 0;
|
||
|
m_SurvivalValue = 0;
|
||
|
m_MonsterClass = ENEMY_GRUNT;
|
||
|
}
|
||
|
|
||
|
void CNonPlayer::Delete()
|
||
|
{
|
||
|
free(m_MonsterName);
|
||
|
m_MonsterName = NULL;
|
||
|
|
||
|
delete this;
|
||
|
}
|
||
|
|
||
|
bool CNonPlayer::ParseNonPlayerData(CTokenizer* Tokenizer)
|
||
|
{
|
||
|
CToken* Token;
|
||
|
|
||
|
// Put these lines in once we have different missions <--- now difficulty levels
|
||
|
/* if (game.GameStats->MissionNumber)
|
||
|
{
|
||
|
for(int count = 0; count < ((game.GameStats->MissionNumber)*2); count++)
|
||
|
{
|
||
|
Token = Tokenizer->GetToken();
|
||
|
if (Token->GetType() != TK_INT)
|
||
|
{
|
||
|
Tokenizer->Error("Warning: Strange Values found while scanning for killed value");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
*/
|
||
|
Token = Tokenizer->GetToken();
|
||
|
if (Token->GetType() != TK_INT)
|
||
|
{
|
||
|
Tokenizer->Error("Killed value not found after monster name");
|
||
|
Tokenizer->PutBackToken(Token);
|
||
|
return false;
|
||
|
}
|
||
|
m_KilledValue = Token->GetIntValue();
|
||
|
Token->Delete();
|
||
|
Token = Tokenizer->GetToken();
|
||
|
if (Token->GetType() != TK_INT)
|
||
|
{
|
||
|
Tokenizer->Error("Survival value not found after Killed Value");
|
||
|
Tokenizer->PutBackToken(Token);
|
||
|
return false;
|
||
|
}
|
||
|
m_SurvivalValue = Token->GetIntValue();
|
||
|
Token->Delete();
|
||
|
Token = Tokenizer->GetToken();
|
||
|
while (Token->GetType() != TK_CLASS)
|
||
|
{
|
||
|
if (Token->GetType() != TK_INT)
|
||
|
{
|
||
|
Tokenizer->Error("Unable to find monster class!");
|
||
|
Tokenizer->PutBackToken (Token);
|
||
|
return false;
|
||
|
}
|
||
|
Token->Delete();
|
||
|
Token = Tokenizer->GetToken();
|
||
|
}
|
||
|
Token->Delete();
|
||
|
Token = Tokenizer->GetToken();
|
||
|
switch (Token->GetType())
|
||
|
{
|
||
|
case TK_ENEMY_GRUNT:
|
||
|
m_MonsterClass = ENEMY_GRUNT;
|
||
|
break;
|
||
|
case TK_ENEMY_LEADER:
|
||
|
m_MonsterClass = ENEMY_LEADER;
|
||
|
break;
|
||
|
case TK_ENEMY_ANIMAL:
|
||
|
m_MonsterClass = ENEMY_ANIMAL;
|
||
|
break;
|
||
|
case TK_ENEMY_BOSS:
|
||
|
m_MonsterClass = ENEMY_BOSS;
|
||
|
break;
|
||
|
case TK_NPC:
|
||
|
m_MonsterClass = NPC;
|
||
|
break;
|
||
|
case TK_NPC_ANIMAL:
|
||
|
m_MonsterClass = NPC_ANIMAL;
|
||
|
break;
|
||
|
case TK_SPECIAL:
|
||
|
m_MonsterClass = SPECIAL;
|
||
|
break;
|
||
|
default:
|
||
|
Tokenizer->Error("Invalid monster class found!");
|
||
|
Tokenizer->PutBackToken (Token);
|
||
|
return false;
|
||
|
}
|
||
|
Token->Delete ();
|
||
|
return true; //Yay!
|
||
|
}
|
||
|
|
||
|
// ============== CLocation functions ============================
|
||
|
|
||
|
CLocation::CLocation(void)
|
||
|
{
|
||
|
m_LocationName = NULL;
|
||
|
}
|
||
|
|
||
|
CLocation::CLocation(const char* name)
|
||
|
{
|
||
|
m_LocationName = (char*)malloc(strlen(name) + 1);
|
||
|
strcpy(m_LocationName,name);
|
||
|
}
|
||
|
|
||
|
void CLocation::Delete()
|
||
|
{
|
||
|
free(m_LocationName);
|
||
|
m_LocationName = NULL;
|
||
|
|
||
|
List<CNonPlayer*>::Iter NPIter;
|
||
|
|
||
|
for (NPIter = m_NonPlayerList.Begin(); NPIter!=m_NonPlayerList.End(); NPIter++)
|
||
|
{
|
||
|
(*NPIter)->Delete();
|
||
|
}
|
||
|
|
||
|
delete this;
|
||
|
}
|
||
|
|
||
|
bool CLocation::RegisterNonPlayers(CTokenizer* Tokenizer)
|
||
|
{
|
||
|
CToken* Token = Tokenizer->GetToken();
|
||
|
if (Token->GetType() != TK_LBRACE)
|
||
|
{
|
||
|
Tokenizer->Error("Left Brace Expected After location Name");
|
||
|
Tokenizer->PutBackToken(Token);
|
||
|
return false;
|
||
|
}
|
||
|
Token->Delete();
|
||
|
Token = Tokenizer->GetToken();
|
||
|
if (Token->GetType() != TK_NAME)
|
||
|
{
|
||
|
Tokenizer->Error ("'name' expected after left brace following location");
|
||
|
Tokenizer->PutBackToken(Token);
|
||
|
return false;
|
||
|
}
|
||
|
while (Token->GetType() == TK_NAME)
|
||
|
{
|
||
|
Token->Delete();
|
||
|
Token = Tokenizer->GetToken();
|
||
|
if (Token->GetType() != TK_STRING)
|
||
|
{
|
||
|
Tokenizer->PutBackToken(Token);
|
||
|
Tokenizer->Error ("No monster name found after keyword 'name'");
|
||
|
if (m_NonPlayerList.Begin() != m_NonPlayerList.End())
|
||
|
{
|
||
|
return true; // some locations were successful, so we should keep them
|
||
|
}
|
||
|
return false; // no successful locations yet, kill 'em all!
|
||
|
}
|
||
|
LPCTSTR name = Token->GetStringValue();
|
||
|
CNonPlayer* NonPlayer = new CNonPlayer(name);
|
||
|
Token->Delete();
|
||
|
|
||
|
bool success = NonPlayer->ParseNonPlayerData(Tokenizer);
|
||
|
if (success)
|
||
|
{
|
||
|
m_NonPlayerList.PushBack(NonPlayer);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
NonPlayer->Delete();
|
||
|
}
|
||
|
Token = Tokenizer->GetToken();
|
||
|
}
|
||
|
if (Token->GetType() != TK_RBRACE)
|
||
|
{
|
||
|
Tokenizer->Error("No closing brace found after name lists!");
|
||
|
Tokenizer->PutBackToken(Token);
|
||
|
return true; // keep what we've got
|
||
|
}
|
||
|
Token->Delete();
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
int CLocation::GetDefaultKilledValue(CTokenizer* Tokenizer)
|
||
|
{
|
||
|
CToken *Token;
|
||
|
List<CNonPlayer*>::Iter NPIter;
|
||
|
int killedValue = DEFAULT_KILLED_VALUE;
|
||
|
|
||
|
Token = Tokenizer->GetToken();
|
||
|
if (Token->GetType() != TK_UNDERSCORE)
|
||
|
{
|
||
|
Tokenizer->Error("Underscore expected after location!");
|
||
|
Token->Delete();
|
||
|
return killedValue;
|
||
|
}
|
||
|
Token->Delete();
|
||
|
Token = Tokenizer->GetToken((UINT)0, TKF_NOUNDERSCOREINIDENTIFIER);
|
||
|
for (NPIter = m_NonPlayerList.Begin(); NPIter!=m_NonPlayerList.End(); NPIter++)
|
||
|
{
|
||
|
if (!(stricmp((*NPIter)->GetMonsterName(), Token->GetStringValue())))
|
||
|
{
|
||
|
killedValue = (*NPIter)->GetKilledValue();
|
||
|
Token->Delete();
|
||
|
return killedValue;
|
||
|
}
|
||
|
}
|
||
|
Tokenizer->Error("Economy.dat does not contain a monster entity name!");
|
||
|
Token->Delete();
|
||
|
return killedValue;
|
||
|
}
|
||
|
|
||
|
int CLocation::GetDefaultSurvivalValue(CTokenizer* Tokenizer)
|
||
|
{
|
||
|
CToken *Token = 0;
|
||
|
List<CNonPlayer*>::Iter NPIter;
|
||
|
int SurvivalValue = DEFAULT_SURVIVAL_VALUE;
|
||
|
|
||
|
Token = Tokenizer->GetToken();
|
||
|
if (Token->GetType() != TK_UNDERSCORE)
|
||
|
{
|
||
|
Tokenizer->Error("Underscore expected after location!");
|
||
|
Token->Delete();
|
||
|
return SurvivalValue;
|
||
|
}
|
||
|
Token->Delete();
|
||
|
Token = Tokenizer->GetToken((UINT)0, TKF_NOUNDERSCOREINIDENTIFIER);
|
||
|
for (NPIter = m_NonPlayerList.Begin(); NPIter!=m_NonPlayerList.End(); NPIter++)
|
||
|
{
|
||
|
if (!(stricmp((*NPIter)->GetMonsterName(), Token->GetStringValue())))
|
||
|
{
|
||
|
SurvivalValue = (*NPIter)->GetSurvivalValue();
|
||
|
Token->Delete();
|
||
|
return SurvivalValue;
|
||
|
}
|
||
|
}
|
||
|
Tokenizer->Error("Economy.dat does not contain a monster entity name!");
|
||
|
Token->Delete();
|
||
|
return SurvivalValue;
|
||
|
}
|
||
|
|
||
|
monsterclass CLocation::GetDefaultMonsterClass(CTokenizer* Tokenizer)
|
||
|
{
|
||
|
CToken *Token = 0;
|
||
|
List<CNonPlayer*>::Iter NPIter;
|
||
|
monsterclass MonsterClass = DEFAULT_MONSTER_CLASS;
|
||
|
|
||
|
Token = Tokenizer->GetToken();
|
||
|
if (Token->GetType() != TK_UNDERSCORE)
|
||
|
{
|
||
|
Tokenizer->Error("Underscore expected after location!");
|
||
|
Token->Delete();
|
||
|
return MonsterClass;
|
||
|
}
|
||
|
Token->Delete();
|
||
|
Token = Tokenizer->GetToken((UINT)0, TKF_NOUNDERSCOREINIDENTIFIER);
|
||
|
for (NPIter = m_NonPlayerList.Begin(); NPIter!=m_NonPlayerList.End(); NPIter++)
|
||
|
{
|
||
|
if (!(stricmp((*NPIter)->GetMonsterName(), Token->GetStringValue())))
|
||
|
{
|
||
|
MonsterClass = (*NPIter)->GetMonsterClass();
|
||
|
Token->Delete();
|
||
|
return MonsterClass;
|
||
|
}
|
||
|
}
|
||
|
Tokenizer->Error("Economy.dat does not contain a monster entity name!");
|
||
|
Token->Delete();
|
||
|
return MonsterClass;
|
||
|
}
|
||
|
|
||
|
// ============== CMonsterList functions =========================
|
||
|
|
||
|
CMonsterList::CMonsterList()
|
||
|
{
|
||
|
// m_LocationList = NULL;
|
||
|
}
|
||
|
|
||
|
void CMonsterList::Delete()
|
||
|
{
|
||
|
List<CLocation*>::Iter LocIter;
|
||
|
|
||
|
for (LocIter = m_LocationList.Begin(); LocIter!=m_LocationList.End(); LocIter++)
|
||
|
{
|
||
|
(*LocIter)->Delete();
|
||
|
}
|
||
|
|
||
|
delete this;
|
||
|
}
|
||
|
|
||
|
bool CMonsterList::RegisterLocations (CTokenizer* Tokenizer)
|
||
|
{
|
||
|
CToken* Token = Tokenizer->GetToken();
|
||
|
if (Token->GetType() != TK_LBRACE)
|
||
|
{
|
||
|
Tokenizer->Error("Left Brace Expected After 'monsters' keyword");
|
||
|
Tokenizer->PutBackToken(Token);
|
||
|
return false;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Token->Delete();
|
||
|
Token = Tokenizer->GetToken();
|
||
|
if (Token->GetType() != TK_LOCATION)
|
||
|
{
|
||
|
Tokenizer->Error ("'location' expected after left brace");
|
||
|
Tokenizer->PutBackToken(Token);
|
||
|
return false;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
while (Token->GetType() == TK_LOCATION)
|
||
|
{
|
||
|
Token->Delete();
|
||
|
Token = Tokenizer->GetToken();
|
||
|
if (Token->GetType() != TK_STRING)
|
||
|
{
|
||
|
Tokenizer->PutBackToken(Token);
|
||
|
Tokenizer->Error ("No name found after keyword 'location'");
|
||
|
if (m_LocationList.Begin() != m_LocationList.End())
|
||
|
{
|
||
|
return true; // some locations were successful, so we should keep them
|
||
|
}
|
||
|
return false; // no successful locations yet, kill 'em all!
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LPCTSTR name = Token->GetStringValue();
|
||
|
CLocation* Location = new CLocation(name);
|
||
|
bool success = Location->RegisterNonPlayers(Tokenizer);
|
||
|
if (success)
|
||
|
{
|
||
|
m_LocationList.PushBack(Location);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Location->Delete();
|
||
|
}
|
||
|
}
|
||
|
Token->Delete();
|
||
|
Token = Tokenizer->GetToken();
|
||
|
}
|
||
|
}
|
||
|
if (Token->GetType() != TK_RBRACE)
|
||
|
{
|
||
|
Tokenizer->Error("No closing brace found after location lists!");
|
||
|
Tokenizer->PutBackToken(Token);
|
||
|
return true; // keep what we've got
|
||
|
}
|
||
|
|
||
|
}
|
||
|
Token->Delete();
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
int CMonsterList::GetDefaultKilledValue(CTokenizer* Tokenizer)
|
||
|
{
|
||
|
CToken *Token;
|
||
|
List<CLocation*>::Iter LocIter;
|
||
|
int killedValue = DEFAULT_KILLED_VALUE;
|
||
|
|
||
|
Token = Tokenizer->GetToken();
|
||
|
if (Token->GetType() != TK_UNDERSCORE)
|
||
|
{
|
||
|
Tokenizer->Error("Underscore expected after monster!");
|
||
|
Token->Delete();
|
||
|
return killedValue;
|
||
|
}
|
||
|
Token->Delete();
|
||
|
Token = Tokenizer->GetToken();
|
||
|
for (LocIter = m_LocationList.Begin(); LocIter!=m_LocationList.End(); LocIter++)
|
||
|
{
|
||
|
if (!(stricmp((*LocIter)->GetLocationName(), Token->GetStringValue())))
|
||
|
{
|
||
|
killedValue = (*LocIter)->GetDefaultKilledValue(Tokenizer);
|
||
|
Token->Delete();
|
||
|
return killedValue;
|
||
|
}
|
||
|
}
|
||
|
Tokenizer->Error("Economy.dat does not contain a location specified in a monster name!");
|
||
|
Token->Delete();
|
||
|
return killedValue;
|
||
|
}
|
||
|
|
||
|
int CMonsterList::GetDefaultSurvivalValue(CTokenizer* Tokenizer)
|
||
|
{
|
||
|
CToken *Token;
|
||
|
List<CLocation*>::Iter LocIter;
|
||
|
int SurvivalValue = DEFAULT_SURVIVAL_VALUE;
|
||
|
|
||
|
Token = Tokenizer->GetToken();
|
||
|
if (Token->GetType() != TK_UNDERSCORE)
|
||
|
{
|
||
|
Tokenizer->Error("Underscore expected after monster!");
|
||
|
Token->Delete();
|
||
|
return SurvivalValue;
|
||
|
}
|
||
|
Token->Delete();
|
||
|
Token = Tokenizer->GetToken();
|
||
|
for (LocIter = m_LocationList.Begin(); LocIter!=m_LocationList.End(); LocIter++)
|
||
|
{
|
||
|
if (!(stricmp((*LocIter)->GetLocationName(), Token->GetStringValue())))
|
||
|
{
|
||
|
SurvivalValue = (*LocIter)->GetDefaultSurvivalValue(Tokenizer);
|
||
|
Token->Delete();
|
||
|
return SurvivalValue;
|
||
|
}
|
||
|
}
|
||
|
Tokenizer->Error("Economy.dat does not contain a location specified in a monster name!");
|
||
|
Token->Delete();
|
||
|
return SurvivalValue;
|
||
|
}
|
||
|
|
||
|
monsterclass CMonsterList::GetDefaultMonsterClass(CTokenizer* Tokenizer)
|
||
|
{
|
||
|
CToken *Token;
|
||
|
List<CLocation*>::Iter LocIter;
|
||
|
monsterclass MonsterClass = DEFAULT_MONSTER_CLASS;
|
||
|
|
||
|
Token = Tokenizer->GetToken();
|
||
|
if (Token->GetType() != TK_UNDERSCORE)
|
||
|
{
|
||
|
Tokenizer->Error("Underscore expected after monster!");
|
||
|
Token->Delete();
|
||
|
return MonsterClass;
|
||
|
}
|
||
|
Token->Delete();
|
||
|
Token = Tokenizer->GetToken();
|
||
|
for (LocIter = m_LocationList.Begin(); LocIter!=m_LocationList.End(); LocIter++)
|
||
|
{
|
||
|
if (!(stricmp((*LocIter)->GetLocationName(), Token->GetStringValue())))
|
||
|
{
|
||
|
MonsterClass = (*LocIter)->GetDefaultMonsterClass(Tokenizer);
|
||
|
Token->Delete();
|
||
|
return MonsterClass;
|
||
|
}
|
||
|
}
|
||
|
Tokenizer->Error("Economy.dat does not contain a location specified in a monster name!");
|
||
|
Token->Delete();
|
||
|
return MonsterClass;
|
||
|
}
|
||
|
// ============== CEconomyRegistry functions =====================
|
||
|
|
||
|
void CEconomyRegistry::RegisterMonsters(CTokenizer* Tokenizer)
|
||
|
{
|
||
|
CToken* Token;
|
||
|
Tokenizer->ScanUntilToken(TK_MONSTERS);
|
||
|
Token = Tokenizer->GetToken();
|
||
|
if (Token->GetType() == TK_EOF)
|
||
|
{
|
||
|
Tokenizer->Error("No Monsters to Register for Economy!");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_MonsterList = new CMonsterList();
|
||
|
bool success = m_MonsterList->RegisterLocations(Tokenizer);
|
||
|
if (!success)
|
||
|
{
|
||
|
m_MonsterList->Delete();
|
||
|
}
|
||
|
}
|
||
|
Token->Delete();
|
||
|
}
|
||
|
|
||
|
int CEconomyRegistry::GetDefaultKilledValue(edict_t *ent)
|
||
|
{
|
||
|
int killedValue = DEFAULT_KILLED_VALUE;
|
||
|
|
||
|
CTokenizer* Tokenizer = CTokenizer::Create(TKF_NOUNDERSCOREINIDENTIFIER);
|
||
|
|
||
|
Tokenizer->SetKeywords(Keywords);
|
||
|
Tokenizer->SetSymbols(Symbols);
|
||
|
Tokenizer->AddParseStream((unsigned char *)ent->classname, strlen(ent->classname));
|
||
|
|
||
|
CToken* Token = Tokenizer->GetToken();
|
||
|
switch(Token->GetType())
|
||
|
{
|
||
|
case TK_MONSTER:
|
||
|
killedValue = m_MonsterList->GetDefaultKilledValue(Tokenizer);
|
||
|
break;
|
||
|
default:
|
||
|
Tokenizer->Error("Invalid entity category in economy.dat!");
|
||
|
break;
|
||
|
}
|
||
|
Token->Delete();
|
||
|
Tokenizer->Delete();
|
||
|
return killedValue;
|
||
|
}
|
||
|
|
||
|
int CEconomyRegistry::GetDefaultSurvivalValue(edict_t *ent)
|
||
|
{
|
||
|
int SurvivalValue = DEFAULT_SURVIVAL_VALUE;
|
||
|
|
||
|
CTokenizer* Tokenizer = CTokenizer::Create(TKF_NOUNDERSCOREINIDENTIFIER);
|
||
|
|
||
|
Tokenizer->SetKeywords(Keywords);
|
||
|
Tokenizer->SetSymbols(Symbols);
|
||
|
Tokenizer->AddParseStream((unsigned char *)ent->classname, strlen(ent->classname));
|
||
|
|
||
|
CToken* Token = Tokenizer->GetToken();
|
||
|
switch(Token->GetType())
|
||
|
{
|
||
|
case TK_MONSTER:
|
||
|
SurvivalValue = m_MonsterList->GetDefaultSurvivalValue(Tokenizer);
|
||
|
break;
|
||
|
default:
|
||
|
Tokenizer->Error("Invalid entity category in economy.dat!");
|
||
|
break;
|
||
|
}
|
||
|
Token->Delete();
|
||
|
Tokenizer->Delete();
|
||
|
return SurvivalValue;
|
||
|
}
|
||
|
|
||
|
monsterclass CEconomyRegistry::GetDefaultMonsterClass(edict_t *ent)
|
||
|
{
|
||
|
monsterclass MonsterClass = DEFAULT_MONSTER_CLASS;
|
||
|
|
||
|
CTokenizer* Tokenizer = CTokenizer::Create(TKF_NOUNDERSCOREINIDENTIFIER);
|
||
|
|
||
|
Tokenizer->SetKeywords(Keywords);
|
||
|
Tokenizer->SetSymbols(Symbols);
|
||
|
Tokenizer->AddParseStream((unsigned char *)ent->classname, strlen(ent->classname));
|
||
|
|
||
|
CToken* Token = Tokenizer->GetToken();
|
||
|
switch(Token->GetType())
|
||
|
{
|
||
|
case TK_MONSTER:
|
||
|
MonsterClass = m_MonsterList->GetDefaultMonsterClass(Tokenizer);
|
||
|
break;
|
||
|
default:
|
||
|
Tokenizer->Error("Invalid entity category in economy.dat!");
|
||
|
break;
|
||
|
}
|
||
|
Token->Delete();
|
||
|
Tokenizer->Delete();
|
||
|
return MonsterClass;
|
||
|
}
|
||
|
|
||
|
CEconomyRegistry::CEconomyRegistry()
|
||
|
{
|
||
|
// do parsing of economy.dat here
|
||
|
byte* econInfo;
|
||
|
UINT flags = 0x00;
|
||
|
int flength;
|
||
|
|
||
|
|
||
|
flength = gi.FS_LoadFile ("economy.dat", (void**)&econInfo);
|
||
|
|
||
|
CTokenizer* Tokenizer = CTokenizer::Create();
|
||
|
|
||
|
if (flength <= 0)
|
||
|
{
|
||
|
Tokenizer->Error("Error trying to open file economy.dat in base directory!");
|
||
|
Tokenizer->Delete();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
Tokenizer->SetKeywords(Keywords);
|
||
|
Tokenizer->SetSymbols(Symbols);
|
||
|
Tokenizer->AddParseStream(econInfo, flength);
|
||
|
|
||
|
m_MonsterList = NULL;
|
||
|
RegisterMonsters(Tokenizer);
|
||
|
// RegisterObjects, etc...
|
||
|
|
||
|
Tokenizer->Delete();
|
||
|
|
||
|
gi.FS_FreeFile(econInfo);
|
||
|
}
|
||
|
|
||
|
void CEconomyRegistry::Delete()
|
||
|
{
|
||
|
if (m_MonsterList)
|
||
|
{
|
||
|
m_MonsterList->Delete();
|
||
|
m_MonsterList = NULL;
|
||
|
}
|
||
|
|
||
|
delete this;
|
||
|
}
|
||
|
|
||
|
// ============== CGameStats functions ===========================
|
||
|
|
||
|
CGameStats::CGameStats()
|
||
|
{
|
||
|
m_EconomyRegistry = new CEconomyRegistry();
|
||
|
}
|
||
|
|
||
|
void CGameStats::Delete ()
|
||
|
{
|
||
|
if (m_EconomyRegistry)
|
||
|
{
|
||
|
m_EconomyRegistry->Delete();
|
||
|
m_EconomyRegistry = NULL;
|
||
|
}
|
||
|
|
||
|
List<CMonsterStats*>::Iter MSIter;
|
||
|
|
||
|
for (MSIter = m_MonsterStats.Begin(); MSIter!=m_MonsterStats.End(); MSIter++)
|
||
|
{
|
||
|
(*MSIter)->Delete();
|
||
|
}
|
||
|
|
||
|
m_MonsterStats.Erase(m_MonsterStats.Begin(),m_MonsterStats.End());
|
||
|
|
||
|
delete this;
|
||
|
}
|
||
|
|
||
|
int CGameStats::GetDefaultKilledValue(edict_t *ent)
|
||
|
{
|
||
|
int KilledValue = m_EconomyRegistry->GetDefaultKilledValue(ent);
|
||
|
return KilledValue;
|
||
|
}
|
||
|
|
||
|
int CGameStats::GetDefaultSurvivalValue(edict_t *ent)
|
||
|
{
|
||
|
int SurvivalValue = m_EconomyRegistry->GetDefaultSurvivalValue(ent);
|
||
|
return SurvivalValue;
|
||
|
}
|
||
|
|
||
|
monsterclass CGameStats::GetDefaultMonsterClass(edict_t *ent)
|
||
|
{
|
||
|
monsterclass MonsterClass = m_EconomyRegistry->GetDefaultMonsterClass(ent);
|
||
|
return MonsterClass;
|
||
|
}
|
||
|
|
||
|
void CGameStats::AddMonsterToStatsList (edict_t *ent, float killedValue, float survivalValue)
|
||
|
{
|
||
|
|
||
|
if (killedValue == 12345678)
|
||
|
{
|
||
|
killedValue = GetDefaultKilledValue(ent);
|
||
|
}
|
||
|
|
||
|
if (survivalValue == 12345678)
|
||
|
{
|
||
|
survivalValue = GetDefaultSurvivalValue(ent);
|
||
|
}
|
||
|
|
||
|
monsterclass myClass = GetDefaultMonsterClass(ent);
|
||
|
|
||
|
|
||
|
CMonsterStats *NewMonsterStats = new CMonsterStats(ent, killedValue, survivalValue, myClass);
|
||
|
|
||
|
m_MonsterStats.PushBack(NewMonsterStats);
|
||
|
|
||
|
}
|
||
|
|
||
|
CMonsterStats* CGameStats::GetMonsterStats(edict_t *ent)
|
||
|
{
|
||
|
List<CMonsterStats *>::Iter MSIter;
|
||
|
|
||
|
for(MSIter = m_MonsterStats.Begin(); MSIter != m_MonsterStats.End(); MSIter++)
|
||
|
{
|
||
|
if ((*MSIter)->MatchMonsterID(ent))
|
||
|
{
|
||
|
return (*MSIter);
|
||
|
}
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
bool CGameStats::CanBuy(edict_t *ent)
|
||
|
{
|
||
|
// if the ent is a client, he can buy.
|
||
|
|
||
|
//sorry to butt into this code, but this test was returning some monsters as able to buy...--ss
|
||
|
// return ((ent-g_edicts-1<MAX_CLIENTS) && (ent>g_edicts));
|
||
|
return (ent->client != NULL);
|
||
|
}
|
||
|
|
||
|
void CGameStats::BuyModeImpulse(edict_t *ent, int impulse)
|
||
|
{
|
||
|
if (!CanBuy(ent))
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
CPlayerStats *PlayerStats = GetPlayerStats(ent);
|
||
|
if (!PlayerStats->GetBuyModeOnOff())
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
switch(impulse)
|
||
|
{
|
||
|
case 133:
|
||
|
ExitBuyMode(ent);
|
||
|
break;
|
||
|
case 134:
|
||
|
if(PlayerStats->GetCashInBank() < 1)
|
||
|
{
|
||
|
gi.centerprintf(ent,"not enough cash!\n");
|
||
|
return;
|
||
|
}
|
||
|
PlayerStats->AdjustCashInBank(-1); // -1 is hardcoded price... hacked in for now - FIXME
|
||
|
//everyone better have a client at this point...
|
||
|
ent->client->inv->addWeaponType(SFW_AUTOSHOTGUN, 1);
|
||
|
break;
|
||
|
case 135:
|
||
|
if(PlayerStats->GetCashInBank() < 10)
|
||
|
{
|
||
|
gi.centerprintf(ent,"not enough cash!\n");
|
||
|
return;
|
||
|
}
|
||
|
PlayerStats->AdjustCashInBank(-10);
|
||
|
ent->client->inv->addWeaponType(SFW_MACHINEGUN, 1);
|
||
|
break;
|
||
|
case 136:
|
||
|
if(PlayerStats->GetCashInBank() < 6000)
|
||
|
{
|
||
|
gi.centerprintf(ent,"not enough cash!\n");
|
||
|
return;
|
||
|
}
|
||
|
break;
|
||
|
case 164:
|
||
|
if(PlayerStats->GetCashInBank() < 10)
|
||
|
{
|
||
|
gi.centerprintf(ent,"not enough cash!\n");
|
||
|
return;
|
||
|
}
|
||
|
PlayerStats->AdjustCashInBank(-10);
|
||
|
ent->client->inv->addAmmoType(AMMO_9MM, 100);
|
||
|
break;
|
||
|
case 165:
|
||
|
if(PlayerStats->GetCashInBank() < 100)
|
||
|
{
|
||
|
gi.centerprintf(ent,"not enough cash!\n");
|
||
|
return;
|
||
|
}
|
||
|
PlayerStats->AdjustCashInBank(-100);
|
||
|
// ent->client->inv->addAmmoType(AMMO_GRENADE, 20);
|
||
|
break;
|
||
|
case 166:
|
||
|
if(PlayerStats->GetCashInBank() < 500)
|
||
|
{
|
||
|
gi.centerprintf(ent,"not enough cash!\n");
|
||
|
return;
|
||
|
}
|
||
|
PlayerStats->AdjustCashInBank(-500);
|
||
|
ent->client->inv->addAmmoType(AMMO_ROCKET, 20);
|
||
|
break;
|
||
|
case 194:
|
||
|
if(PlayerStats->GetCashInBank() < 30)
|
||
|
{
|
||
|
gi.centerprintf(ent,"not enough cash!\n");
|
||
|
return;
|
||
|
}
|
||
|
PlayerStats->AdjustCashInBank(-30);
|
||
|
ent->client->inv->addItem(SFE_FLASHPACK, 3);
|
||
|
break;
|
||
|
case 195:
|
||
|
if(PlayerStats->GetCashInBank() < 40)
|
||
|
{
|
||
|
gi.centerprintf(ent,"not enough cash!\n");
|
||
|
return;
|
||
|
}
|
||
|
PlayerStats->AdjustCashInBank(-40);
|
||
|
ent->client->inv->addItem(SFE_C4, 3);
|
||
|
break;
|
||
|
case 196:
|
||
|
if(PlayerStats->GetCashInBank() < 40)
|
||
|
{
|
||
|
gi.centerprintf(ent,"not enough cash!\n");
|
||
|
return;
|
||
|
}
|
||
|
PlayerStats->AdjustCashInBank(-40);
|
||
|
ent->client->inv->addItem(SFE_NEURAL_GRENADE, 3);
|
||
|
break;
|
||
|
case 197:
|
||
|
if(PlayerStats->GetCashInBank() < 40)
|
||
|
{
|
||
|
gi.centerprintf(ent,"not enough cash!\n");
|
||
|
return;
|
||
|
}
|
||
|
break;
|
||
|
case 198:
|
||
|
if(PlayerStats->GetCashInBank() < 40)
|
||
|
{
|
||
|
gi.centerprintf(ent,"not enough cash!\n");
|
||
|
return;
|
||
|
}
|
||
|
PlayerStats->AdjustCashInBank(-40);
|
||
|
ent->client->inv->addItem(SFE_LIGHT_GOGGLES, 1);
|
||
|
break;
|
||
|
case 199:
|
||
|
if(PlayerStats->GetCashInBank() < 40)
|
||
|
{
|
||
|
gi.centerprintf(ent,"not enough cash!\n");
|
||
|
return;
|
||
|
}
|
||
|
PlayerStats->AdjustCashInBank(-40);
|
||
|
ent->client->inv->addArmor(100);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CGameStats::EnterBuyMode(edict_t *ent)
|
||
|
{
|
||
|
CPlayerStats *PlayerStats;
|
||
|
|
||
|
if (!CanBuy(ent))
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
PlayerStats = GetPlayerStats(ent);
|
||
|
PlayerStats->SetBuyModeOnOff (true);
|
||
|
|
||
|
|
||
|
gi.WriteByte(svc_equip);
|
||
|
gi.WriteByte(1);//equip code
|
||
|
gi.WriteByte(3);//how many weapons to offer for sale
|
||
|
gi.WriteString("jackhammer");//weap name
|
||
|
gi.WriteLong(1);//weap price
|
||
|
gi.WriteString("minimi");//weap name
|
||
|
gi.WriteLong(10);//weap price
|
||
|
gi.WriteString("m305a1");//weap name
|
||
|
gi.WriteLong(6000);//weap price
|
||
|
gi.WriteByte(3);//dif't ammo types for sale
|
||
|
gi.WriteString("9mm");//weap name
|
||
|
gi.WriteLong(10);//weap price
|
||
|
gi.WriteString("grenades");//weap name
|
||
|
gi.WriteLong(100);//weap price
|
||
|
gi.WriteString("rockets");//weap name
|
||
|
gi.WriteLong(500);//weap price
|
||
|
gi.WriteByte(6);//dif't items for sale
|
||
|
gi.WriteString("flashpacks");//weap name
|
||
|
gi.WriteLong(30);//weap price
|
||
|
gi.WriteString("c4 explosive");//weap name
|
||
|
gi.WriteLong(40);//weap price
|
||
|
gi.WriteString("neural grenades");//weap name
|
||
|
gi.WriteLong(40);//weap price
|
||
|
gi.WriteString("robot grenades");//weap name
|
||
|
gi.WriteLong(40);//weap price
|
||
|
gi.WriteString("light goggles");//weap name
|
||
|
gi.WriteLong(200);//weap price
|
||
|
gi.WriteString("armor");//weap name
|
||
|
gi.WriteLong(40);//weap price
|
||
|
gi.unicast (ent, true);
|
||
|
}
|
||
|
|
||
|
void CGameStats::ExitBuyMode(edict_t *ent)
|
||
|
{
|
||
|
if (!CanBuy(ent))
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
CPlayerStats *PlayerStats = GetPlayerStats(ent);
|
||
|
|
||
|
PlayerStats->SetBuyModeOnOff(false);
|
||
|
gi.WriteByte(svc_equip);
|
||
|
gi.WriteByte(0);
|
||
|
gi.unicast (ent, true);
|
||
|
}
|