ns/releases/3.03/source/mod/AvHCombat.cpp

708 lines
24 KiB
C++
Raw Normal View History

#include "build.h"
#include "types.h"
#include "mod/AvHPlayer.h"
#include "mod/AvHPlayerUpgrade.h"
#include "mod/AvHServerUtil.h"
#include "mod/AvHGamerules.h"
#include "mod/AvHMarineEquipment.h"
#include "mod/AvHSharedUtil.h"
extern int gLevelUpEventID;
bool AvHPlayer::GiveCombatModeUpgrade(AvHMessageID inMessageID, bool inInstantaneous)
{
bool theSuccess = false;
bool theEffectivePlayerClassChanged = false;
// Process every upgrade here
AvHUser3 theUser3 = (AvHUser3)this->pev->iuser3;
int thePlayerLevel = this->GetExperienceLevel();
float theHealthPercentage = this->pev->health/AvHPlayerUpgrade::GetMaxHealth(this->pev->iuser4, theUser3, thePlayerLevel);
float theArmorPercentage = this->pev->armorvalue/AvHPlayerUpgrade::GetMaxArmorLevel(this->pev->iuser4, theUser3);
bool thePreserveHealthArmorPercentage = true;
CBasePlayerItem* theCreatedItem = NULL;
// Marine upgrades
if(this->GetIsMarine())
{
Vector thePlayerMinSize, thePlayerMaxSize;
this->GetSize(thePlayerMinSize, thePlayerMaxSize);
Vector thePlayersFeet = this->pev->origin;
thePlayersFeet.z += thePlayerMinSize.z;
switch(inMessageID)
{
case BUILD_SHOTGUN:
case BUILD_GRENADE_GUN:
case BUILD_HMG:
case BUILD_WELDER:
case BUILD_MINES:
case BUILD_JETPACK:
case BUILD_HEAVY:
//voogru: spawn the weapon in the middle of nowhere to prevent anyone else from getting it.
theCreatedItem = dynamic_cast<CBasePlayerItem*>(AvHSUBuildTechForPlayer(inMessageID, Vector(9999,9999,9999), this));
ASSERT(theCreatedItem);
if((inMessageID == BUILD_JETPACK) || (inMessageID == BUILD_HEAVY))
{
theEffectivePlayerClassChanged = true;
}
theSuccess = true;
break;
case BUILD_SCAN:
AvHSUBuildTechForPlayer(inMessageID, thePlayersFeet, this);
theSuccess = true;
break;
// case RESEARCH_DISTRESSBEACON:
// AvHSUResearchStarted(this, inMessageID);
// AvHSUResearchComplete(this, inMessageID);
// theSuccess = true;
// break;
// Give upgrades
case RESEARCH_ARMOR_ONE:
this->GiveTeamUpgrade(RESEARCH_ARMOR_ONE);
theSuccess = true;
break;
case RESEARCH_ARMOR_TWO:
this->GiveTeamUpgrade(RESEARCH_ARMOR_ONE);
this->GiveTeamUpgrade(RESEARCH_ARMOR_TWO);
theSuccess = true;
break;
case RESEARCH_ARMOR_THREE:
this->GiveTeamUpgrade(RESEARCH_ARMOR_ONE);
this->GiveTeamUpgrade(RESEARCH_ARMOR_TWO);
this->GiveTeamUpgrade(RESEARCH_ARMOR_THREE);
theSuccess = true;
break;
case RESEARCH_WEAPONS_ONE:
this->GiveTeamUpgrade(RESEARCH_WEAPONS_ONE);
theSuccess = true;
break;
case RESEARCH_WEAPONS_TWO:
this->GiveTeamUpgrade(RESEARCH_WEAPONS_ONE);
this->GiveTeamUpgrade(RESEARCH_WEAPONS_TWO);
theSuccess = true;
break;
case RESEARCH_WEAPONS_THREE:
this->GiveTeamUpgrade(RESEARCH_WEAPONS_ONE);
this->GiveTeamUpgrade(RESEARCH_WEAPONS_TWO);
this->GiveTeamUpgrade(RESEARCH_WEAPONS_THREE);
theSuccess = true;
break;
case RESEARCH_GRENADES:
this->GiveNamedItem(kwsGrenade);
// NOTE: Fall through below
case RESEARCH_MOTIONTRACK:
this->GiveTeamUpgrade(inMessageID);
theSuccess = true;
break;
//case BUILD_AMMO:
//case BUILD_HEALTH:
case BUILD_RESUPPLY:
// Find all friendly players nearby (right now this just resupplies current player)
// Give them health and ammo, equal to # of current level
AvHSUResupplyFriendliesInRange(1, this);
thePreserveHealthArmorPercentage = false;
theSuccess = true;
// Add new tech node to allow us to buy it again
//AvHTechNode theTechNode(BUILD_RESUPPLY, TECH_FOUR_LEVEL_TWO, TECH_FOUR_LEVEL_TWO, TECH_NULL, 0, 0, true);
//this->mCombatNodes.AddTechNode(theTechNode);
break;
case BUILD_CAT:
// Don't give out cat-packs every time
AvHCatalyst::GiveCatalyst(this);
theSuccess = true;
break;
}
}
else if(this->GetIsAlien())
{
theSuccess = this->ExecuteAlienMorphMessage(inMessageID, inInstantaneous);
thePreserveHealthArmorPercentage = false;
}
if(thePreserveHealthArmorPercentage)
{
this->pev->health = theHealthPercentage*AvHPlayerUpgrade::GetMaxHealth(this->pev->iuser4, theUser3, thePlayerLevel);
this->pev->armorvalue = theArmorPercentage*AvHPlayerUpgrade::GetMaxArmorLevel(this->pev->iuser4, theUser3);
}
if(theEffectivePlayerClassChanged)
{
this->EffectivePlayerClassChanged();
}
return theSuccess;
}
float AvHPlayer::GetExperience() const
{
return this->mExperience;
}
int AvHPlayer::GetExperienceLevelsSpent() const
{
return this->mExperienceLevelsSpent;
}
void AvHPlayer::SetExperienceLevelsSpent(int inSpentLevels)
{
this->mExperienceLevelsSpent = inSpentLevels;
}
void AvHPlayer::AwardExperienceForObjective(float inHealthChange, AvHMessageID inMessageID)
{
bool theAwardExperience = false;
if(GetGameRules()->GetIsCombatMode())
{
switch(inMessageID)
{
case ALIEN_BUILD_HIVE:
case BUILD_COMMANDSTATION:
theAwardExperience = true;
break;
}
}
if(theAwardExperience)
{
int theMaxHealth = GetGameRules()->GetBaseHealthForMessageID(inMessageID);
float thePercentageOfHealth = inHealthChange/theMaxHealth;
int theCombatObjectiveExperienceScalar = BALANCE_IVAR(kCombatObjectiveExperienceScalar);
float theExperienceGained = thePercentageOfHealth*theCombatObjectiveExperienceScalar;
this->SetExperience(this->GetExperience() + theExperienceGained);
}
}
void AvHPlayer::SetExperience(float inExperience)
{
if(GetGameRules()->GetIsCombatMode())
{
int theCurrentLevel = AvHPlayerUpgrade::GetPlayerLevel(this->GetExperience());
this->mExperience = inExperience;
// Update server player data in case we get disconnected
AvHTeam* theTeam = this->GetTeamPointer();
if(theTeam)
{
AvHServerPlayerData* theServerPlayerData = this->GetServerPlayerData();
if(theServerPlayerData)
{
theServerPlayerData->SetExperience(this->mExperience);
}
}
int theNewLevel = AvHPlayerUpgrade::GetPlayerLevel(this->GetExperience());
if(theCurrentLevel != theNewLevel)
{
int theIsMarine = this->GetIsMarine();
PLAYBACK_EVENT_FULL(0, this->edict(), gLevelUpEventID, 0, this->pev->origin, (float *)&g_vecZero, 0.0, 0.0, theIsMarine, 0, 0, 0 );
// Give player health and armor back on level-up, to allow more soloing, heroics, and reduce dependence on hives/resupply
AvHUser3 theUser3 = AvHUser3(this->pev->iuser3);
float theMaxHealth = AvHPlayerUpgrade::GetMaxHealth(this->pev->iuser4, theUser3, theCurrentLevel);
float theHealthPercentage = this->pev->health/theMaxHealth;
float theLevelUpHealthPercentage = BALANCE_IVAR(kCombatLevelupHealthIncreasePercent)/100.0f;
theHealthPercentage = min(theHealthPercentage + theLevelUpHealthPercentage, 1.0f);
this->pev->health = theHealthPercentage*theMaxHealth;
float theMaxArmor = AvHPlayerUpgrade::GetMaxArmorLevel(this->pev->iuser4, theUser3);
float theArmorPercentage = this->pev->armorvalue/theMaxArmor;
float theLevelUpArmorPercentage = BALANCE_IVAR(kCombatLevelupArmorIncreasePercent)/100.0f;
theArmorPercentage = min(theArmorPercentage + theLevelUpArmorPercentage, 1.0f);
this->pev->armorvalue = theArmorPercentage*theMaxArmor;
// Unlock tiers as player levels up
// if(theNewLevel >= 4)
// {
// this->mCombatNodes.SetResearchDone(COMBAT_TIER2_UNLOCK);
// }
// if(theNewLevel >= 7)
// {
// this->mCombatNodes.SetResearchDone(COMBAT_TIER3_UNLOCK);
// }
}
}
}
int AvHPlayer::GetExperienceLevel() const
{
int theLevel = 1;
if(GetGameRules()->GetIsCombatMode())
{
theLevel = AvHPlayerUpgrade::GetPlayerLevel(this->GetExperience());
}
return theLevel;
}
AvHTechNodes& AvHPlayer::GetCombatNodes()
{
return this->mCombatNodes;
}
MessageIDListType& AvHPlayer::GetPurchasedCombatUpgrades()
{
return this->mPurchasedCombatUpgrades;
}
void AvHPlayer::SetCombatNodes(const AvHTechNodes& inTechNodes)
{
this->mCombatNodes = inTechNodes;
}
void AvHPlayer::GiveCombatUpgradesOnSpawn()
{
// Save off previously-spent upgrades and respend them
MessageIDListType theUpgrades = this->mGiveCombatUpgrades;
// Need to run through these in order
for(MessageIDListType::iterator theIter = theUpgrades.begin(); theIter != theUpgrades.end(); theIter++)
{
AvHMessageID theCurrentCombatUpgrade = *theIter;
if(theCurrentCombatUpgrade != MESSAGE_NULL)
{
this->GiveCombatModeUpgrade(theCurrentCombatUpgrade, true);
}
}
}
void AvHPlayer::PurchaseCombatUpgrade(AvHMessageID inMessageID)
{
this->mPurchasedCombatUpgrades.push_back(inMessageID);
//this->mExperienceLevelsSpent++;
// Remove any upgrades that this prempts
bool theOneShot = false;
switch(inMessageID)
{
case BUILD_AMMO:
case BUILD_HEALTH:
case BUILD_RESUPPLY:
case BUILD_CAT:
case BUILD_SCAN:
//case BUILD_MINES:
//case RESEARCH_DISTRESSBEACON:
theOneShot = true;
break;
}
// Don't add it as a permanent upgrade to get every time we spawn
if(!theOneShot)
{
this->mGiveCombatUpgrades.push_back(inMessageID);
}
this->RemoveCombatUpgradesPremptedBy(inMessageID);
}
void AvHPlayer::RemoveCombatUpgrade(AvHMessageID inMessageID)
{
MessageIDListType::iterator theIter = std::find(this->mGiveCombatUpgrades.begin(), this->mGiveCombatUpgrades.end(), inMessageID);
if(theIter != this->mGiveCombatUpgrades.end())
{
this->mGiveCombatUpgrades.erase(theIter);
// Take away the upgrade
this->GiveTeamUpgrade(inMessageID, false);
}
}
void AvHPlayer::RemoveCombatUpgradesPremptedBy(AvHMessageID inMessageID)
{
switch(inMessageID)
{
case BUILD_JETPACK:
this->RemoveCombatUpgrade(BUILD_HEAVY);
break;
case BUILD_HEAVY:
this->RemoveCombatUpgrade(BUILD_JETPACK);
break;
case BUILD_HMG:
this->RemoveCombatUpgrade(BUILD_SHOTGUN);
this->RemoveCombatUpgrade(BUILD_GRENADE_GUN);
break;
case BUILD_GRENADE_GUN:
this->RemoveCombatUpgrade(BUILD_SHOTGUN);
this->RemoveCombatUpgrade(BUILD_HMG);
break;
case ALIEN_LIFEFORM_TWO:
this->RemoveCombatUpgrade(ALIEN_LIFEFORM_ONE);
break;
case ALIEN_LIFEFORM_THREE:
this->RemoveCombatUpgrade(ALIEN_LIFEFORM_TWO);
break;
case ALIEN_LIFEFORM_FOUR:
this->RemoveCombatUpgrade(ALIEN_LIFEFORM_THREE);
break;
case ALIEN_LIFEFORM_FIVE:
this->RemoveCombatUpgrade(ALIEN_LIFEFORM_FOUR);
break;
//case BUILD_WELDER
// this->RemoveCombatUpgrade(BUILD_MINES);
// break;
//case BUILD_MINES:
// this->RemoveCombatUpgrade(BUILD_WELDER);
// break;
}
}
void AvHPlayer::ProcessCombatDeath()
{
// Unspend lifeform (return to skulk, but get the levels spent on lifeform back)
if(this->GetIsAlien())
{
AvHMessageID theLifeformID = MESSAGE_NULL;
AvHUser3 theUser3 = this->GetUser3(false);
if(theUser3 == AVH_USER3_ALIEN_EMBRYO)
{
// Use the last lifeform we were, unless we're evolving into a new one (assumes only one lifeform change per life)
theUser3 = this->GetPreviousUser3(false);
switch(this->mEvolution)
{
case ALIEN_LIFEFORM_TWO:
theUser3 = AVH_USER3_ALIEN_PLAYER2;
break;
case ALIEN_LIFEFORM_THREE:
theUser3 = AVH_USER3_ALIEN_PLAYER3;
break;
case ALIEN_LIFEFORM_FOUR:
theUser3 = AVH_USER3_ALIEN_PLAYER4;
break;
case ALIEN_LIFEFORM_FIVE:
theUser3 = AVH_USER3_ALIEN_PLAYER5;
break;
}
}
AvHSHUUser3ToMessageID(theUser3, theLifeformID);
ASSERT(theLifeformID != MESSAGE_NULL);
int theLifeformCost = GetGameRules()->GetCostForMessageID(theLifeformID);
this->SetExperienceLevelsSpent(this->GetExperienceLevelsSpent() - theLifeformCost);
this->RemoveCombatUpgrade(theLifeformID);
// Make all lifeforms chooseable again
this->SetLifeformCombatNodesAvailable(true);
}
}
void AvHPlayer::SetLifeformCombatNodesAvailable(bool inAvailable)
{
MessageIDListType theLifeformList;
theLifeformList.push_back(ALIEN_LIFEFORM_ONE);
theLifeformList.push_back(ALIEN_LIFEFORM_TWO);
theLifeformList.push_back(ALIEN_LIFEFORM_THREE);
theLifeformList.push_back(ALIEN_LIFEFORM_FOUR);
theLifeformList.push_back(ALIEN_LIFEFORM_FIVE);
for(MessageIDListType::iterator theIter = theLifeformList.begin(); theIter != theLifeformList.end(); theIter++)
{
AvHMessageID theLifeformID = *theIter;
this->mCombatNodes.SetIsResearchable(theLifeformID, inAvailable);
this->mCombatNodes.SetResearchDone(theLifeformID, !inAvailable);
}
}
bool AvHPlayer::ExecuteCombatMessage(AvHMessageID inMessageID, bool& outIsAvailable, bool inForce)
{
bool theMessageExecuted = false;
// Only explicitly deny messages in the tech tree, let the others fall back to NS-mode handling
if(this->mCombatNodes.GetIsMessageInTechTree(inMessageID))
{
if(this->mCombatNodes.GetIsMessageAvailable(inMessageID) || inForce)
{
if(this->GiveCombatModeUpgrade(inMessageID))
{
theMessageExecuted = true;
}
}
else
{
// Explicitly deny
outIsAvailable = false;
}
}
return theMessageExecuted;
}
bool AvHPlayer::GetHasCombatModeUpgrade(AvHMessageID inMessageID) const
{
bool theHasUpgrade = false;
MessageIDListType::const_iterator theIter = std::find(this->mPurchasedCombatUpgrades.begin(), this->mPurchasedCombatUpgrades.end(), inMessageID);
if(theIter != this->mPurchasedCombatUpgrades.end())
{
theHasUpgrade = true;
}
return theHasUpgrade;
}
void AvHPlayer::InternalCombatThink()
{
// Only update every so often
if(GetGameRules()->GetIsCombatMode())
{
// Save our data in case we get kicked off
AvHServerPlayerData* theServerPlayerData = this->GetServerPlayerData();
if(theServerPlayerData)
{
theServerPlayerData->SetCombatNodes(this->mCombatNodes);
theServerPlayerData->SetPurchasedCombatUpgrades(this->mPurchasedCombatUpgrades);
theServerPlayerData->SetExperienceLevelsSpent(this->mExperienceLevelsSpent);
}
// If it's time for an update
float theCurrentTime = gpGlobals->time;
const float theCombatThinkInterval = BALANCE_FVAR(kCombatThinkInterval);
// Give support from a fake commander
if(this->GetIsMarine() && this->GetIsRelevant() && !this->GetIsBeingDigested())
{
if(this->mTimeOfLastCombatThink == 0 || (theCurrentTime > (this->mTimeOfLastCombatThink + theCombatThinkInterval)))
{
// Only allow one upgrade per think
bool theSuccess = false;
// Does player have resupply upgrade?
if(this->GetHasCombatModeUpgrade(BUILD_RESUPPLY))
{
// Do they need it?
float theHealthPercentage = this->pev->health/AvHPlayerUpgrade::GetMaxHealth(this->pev->iuser4, (AvHUser3)this->pev->iuser3, this->GetExperienceLevel());
// float theAmmoPercentage = this->GetCurrentWeaponAmmoPercentage(); // changed to fix #542
bool theAmmoResupply = this->GetShouldResupplyAmmo();
if((theHealthPercentage < BALANCE_FVAR(kCombatResupplyHealthPercentage)) || theAmmoResupply) //(theAmmoPercentage < BALANCE_FVAR(kCombatResupplyAmmoPercentage)))
{
// Resupply player
this->GiveCombatModeUpgrade(BUILD_RESUPPLY);
theSuccess = true;
}
}
// Does player have resupply upgrade?
if(this->GetHasCombatModeUpgrade(BUILD_CAT))
{
// Catalyst player after he gets a kill
if(this->pev->frags > this->mSavedCombatFrags)
{
//if(RANDOM_LONG(0, 1) == 0)
//{
AvHCatalyst::GiveCatalyst(this);
theSuccess = true;
//}
}
}
this->mSavedCombatFrags = this->pev->frags;
// Does player have scan upgrade?
if(!theSuccess && this->GetHasCombatModeUpgrade(BUILD_SCAN) && !this->GetIsBeingDigested())
{
// Needed if there is a cloaked enemy nearby
bool theCloakedEnemyNearby = false;
// Look in sphere for cloakables
CBaseEntity* theSphereEntity = NULL;
while ((theSphereEntity = UTIL_FindEntityInSphere(theSphereEntity, this->pev->origin, BALANCE_IVAR(kScanRadius))) != NULL)
{
if(!AvHSUGetIsExternalClassName(STRING(theSphereEntity->pev->classname)))
{
AvHCloakable* theCloakable = dynamic_cast<AvHCloakable*>(theSphereEntity);
if(theCloakable && theCloakable->GetIsPartiallyCloaked() && (theSphereEntity->pev->team != this->pev->team))
{
//if(this->GetIsEntityInSight(theSphereEntity))
//{
theCloakedEnemyNearby = true;
break;
//}
}
}
}
// Lucky enough to receive?
if(theCloakedEnemyNearby /*&& (RANDOM_LONG(0, 1) == 0)*/)
{
// Scan
this->GiveCombatModeUpgrade(BUILD_SCAN);
theSuccess = true;
}
}
// // Does player have distress beacon?
// if(!theSuccess && this->GetHasCombatModeUpgrade(RESEARCH_DISTRESSBEACON))
// {
// // Needed?
// int theNumTeammatesWaitingToSpawn = 0;
// FOR_ALL_ENTITIES(kAvHPlayerClassName, AvHPlayer*);
// if(theEntity->GetTeam() == this->GetTeam())
// {
// if(theEntity->GetPlayMode() == PLAYMODE_AWAITINGREINFORCEMENT)
// {
// theNumTeammatesWaitingToSpawn++;
// }
// }
// END_FOR_ALL_ENTITIES(kAvHPlayerClassName);
//
// // Lucky enough?
// int theNumPlayersOnTeam = 0;
// AvHTeam* theTeamPointer = this->GetTeamPointer();
// if(theTeamPointer)
// {
// theNumPlayersOnTeam = theTeamPointer->GetPlayerCount();
// }
//
// float theDeadPercentage = (float)theNumTeammatesWaitingToSpawn/theNumPlayersOnTeam;
// if(theDeadPercentage > BALANCE_FVAR(kCombatDistressBeaconDeadPercentage))
// {
// // Distress!
// this->GiveCombatModeUpgrade(RESEARCH_DISTRESSBEACON);
// theSuccess = true;
// }
// }
// Update time
this->mTimeOfLastCombatThink = theCurrentTime;
}
}
else if(this->GetIsAlien() && this->GetIsRelevant())
{
// Give aliens experience slowly over time
if(this->mTimeOfLastCombatThink == 0 || (theCurrentTime > (this->mTimeOfLastCombatThink + theCombatThinkInterval)))
{
float theExperienceRate = BALANCE_FVAR(kCombatExperienceAlienGrowthRate);
float theExperienceGained = theCombatThinkInterval*theExperienceRate;
this->SetExperience(this->GetExperience() + theExperienceGained);
// Update time
this->mTimeOfLastCombatThink = theCurrentTime;
}
}
}
}
void AvHTeam::InitializeCombatTechNodes()
{
// If team is marine
if(this->mTeamType == AVH_CLASS_TYPE_MARINE)
{
this->AddTechNode(RESEARCH_WEAPONS_ONE, TECH_ONE_LEVEL_ONE, TECH_NULL, TECH_NULL, false);
this->AddTechNode(RESEARCH_WEAPONS_TWO, TECH_ONE_LEVEL_TWO, TECH_ONE_LEVEL_ONE, TECH_NULL, false);
this->AddTechNode(RESEARCH_WEAPONS_THREE, TECH_NULL, TECH_ONE_LEVEL_TWO, TECH_NULL, false);
this->AddTechNode(BUILD_SHOTGUN, TECH_ONE_LEVEL_THREE, TECH_ONE_LEVEL_ONE, TECH_NULL, false);
this->AddTechNode(BUILD_GRENADE_GUN, TECH_NULL, TECH_ONE_LEVEL_THREE, TECH_NULL, false);
this->AddTechNode(BUILD_HMG, TECH_NULL, TECH_ONE_LEVEL_THREE, TECH_NULL, false);
this->AddTechNode(RESEARCH_ARMOR_ONE, TECH_TWO_LEVEL_ONE, TECH_NULL, TECH_NULL, false);
this->AddTechNode(RESEARCH_ARMOR_TWO, TECH_TWO_LEVEL_TWO, TECH_TWO_LEVEL_ONE, TECH_NULL, false);
this->AddTechNode(RESEARCH_ARMOR_THREE, TECH_NULL, TECH_TWO_LEVEL_TWO, TECH_NULL, false);
this->AddTechNode(BUILD_JETPACK, TECH_NULL, TECH_TWO_LEVEL_TWO, TECH_NULL, false);
this->AddTechNode(BUILD_HEAVY, TECH_NULL, TECH_TWO_LEVEL_TWO, TECH_NULL, false);
this->AddTechNode(BUILD_SCAN, TECH_THREE_LEVEL_ONE, TECH_NULL, TECH_NULL, false, false);
this->AddTechNode(RESEARCH_MOTIONTRACK, TECH_THREE_LEVEL_ONE, TECH_NULL, TECH_NULL, false);
//this->AddTechNode(RESEARCH_DISTRESSBEACON, TECH_THREE_LEVEL_ONE, TECH_NULL, TECH_NULL, true, false);
this->AddTechNode(BUILD_RESUPPLY, TECH_THREE_LEVEL_ONE, TECH_NULL, TECH_NULL, false, false);
this->AddTechNode(BUILD_CAT, TECH_THREE_LEVEL_ONE, TECH_NULL, TECH_NULL, false, false);
this->AddTechNode(BUILD_WELDER, TECH_THREE_LEVEL_ONE, TECH_NULL, TECH_NULL, false, false);
this->AddTechNode(BUILD_MINES, TECH_THREE_LEVEL_ONE, TECH_NULL, TECH_NULL, false, false);
this->AddTechNode(RESEARCH_GRENADES, TECH_THREE_LEVEL_ONE, TECH_NULL, TECH_NULL, false, false);
}
else
{
// Deny skulks so that player can't "re-evolve" to skulks.
this->AddTechNode(ALIEN_LIFEFORM_ONE, TECH_NULL, TECH_PLAYER_UNAVAILABLE, TECH_NULL, false);
this->AddTechNode(ALIEN_LIFEFORM_TWO, TECH_ONE_LEVEL_ONE, TECH_NULL, TECH_NULL, false);
this->AddTechNode(ALIEN_LIFEFORM_THREE, TECH_ONE_LEVEL_TWO, TECH_NULL, TECH_NULL, false);
this->AddTechNode(ALIEN_LIFEFORM_FOUR, TECH_ONE_LEVEL_THREE, TECH_NULL, TECH_NULL, false);
this->AddTechNode(ALIEN_LIFEFORM_FIVE, TECH_ONE_LEVEL_FOUR, TECH_NULL, TECH_NULL, false);
this->AddTechNode(ALIEN_HIVE_TWO_UNLOCK, TECH_TWO_LEVEL_ONE, TECH_NULL, TECH_NULL, false);
this->AddTechNode(ALIEN_HIVE_THREE_UNLOCK, TECH_THREE_LEVEL_TWO, TECH_TWO_LEVEL_ONE, TECH_NULL, false);
this->AddTechNode(ALIEN_EVOLUTION_ONE, TECH_THREE_LEVEL_ONE, TECH_NULL, TECH_NULL, false);
this->AddTechNode(ALIEN_EVOLUTION_TWO, TECH_THREE_LEVEL_ONE, TECH_NULL, TECH_NULL, false);
this->AddTechNode(ALIEN_EVOLUTION_THREE, TECH_THREE_LEVEL_ONE, TECH_NULL, TECH_NULL, false);
this->AddTechNode(ALIEN_EVOLUTION_TEN, TECH_FOUR_LEVEL_ONE, TECH_NULL, TECH_NULL, false);
this->AddTechNode(ALIEN_EVOLUTION_TWELVE, TECH_FOUR_LEVEL_ONE, TECH_NULL, TECH_NULL, false);
this->AddTechNode(ALIEN_EVOLUTION_ELEVEN, TECH_FOUR_LEVEL_ONE, TECH_NULL, TECH_NULL, false);
this->AddTechNode(ALIEN_EVOLUTION_SEVEN, TECH_FIVE_LEVEL_ONE, TECH_NULL, TECH_NULL, false);
this->AddTechNode(ALIEN_EVOLUTION_EIGHT, TECH_FIVE_LEVEL_ONE, TECH_NULL, TECH_NULL, false);
this->AddTechNode(ALIEN_EVOLUTION_NINE, TECH_FIVE_LEVEL_ONE, TECH_NULL, TECH_NULL, false);
}
}
void AvHGamerules::AwardExperience(AvHPlayer* inPlayer, int inTargetLevel, bool inAwardFriendliesInRange)
{
PlayerListType thePlayerList;
thePlayerList.push_back(inPlayer);
if(inAwardFriendliesInRange)
{
// Award experience to player, and any other players nearby
int theExperienceRadius = BALANCE_IVAR(kCombatFriendlyNearbyRange);
// Make list of players to split it between. If a player is at full experience, extra is wasted.
CBaseEntity* theEntity = NULL;
while ((theEntity = UTIL_FindEntityInSphere(theEntity, inPlayer->pev->origin, theExperienceRadius)) != NULL)
{
const char* theClassName = STRING(theEntity->pev->classname);
if(!AvHSUGetIsExternalClassName(theClassName))
{
AvHPlayer* thePlayer = dynamic_cast<AvHPlayer*>(theEntity);
if(thePlayer && (thePlayer != inPlayer) && (thePlayer->pev->team == inPlayer->pev->team) && thePlayer->GetIsRelevant() && !thePlayer->GetIsBeingDigested())
{
thePlayerList.push_back(thePlayer);
}
}
}
}
ASSERT(thePlayerList.size() > 0);
float theExperienceFactor = GetGameRules()->GetIsIronMan() ? BALANCE_FVAR(kCombatIronManExperienceScalar) : 1.0f;
int theExperienceToAward = BALANCE_IVAR(kCombatExperienceBaseAward) + inTargetLevel*BALANCE_IVAR(kCombatExperienceLevelAward);
float theExperienceForEach = (theExperienceToAward/(float)thePlayerList.size() + BALANCE_IVAR(kCombatExperienceCrowdAward))*theExperienceFactor;
for(PlayerListType::iterator thePlayerIter = thePlayerList.begin(); thePlayerIter != thePlayerList.end(); thePlayerIter++)
{
AvHPlayer* theCurrentPlayer = (*thePlayerIter);
theCurrentPlayer->SetExperience(theCurrentPlayer->GetExperience() + theExperienceForEach);
}
}