#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(AvHSUBuildTechForPlayer(inMessageID, Vector(9999,9999,9999), this)); ASSERT(theCreatedItem); if((inMessageID == BUILD_JETPACK) || (inMessageID == BUILD_HEAVY) || (inMessageID == BUILD_HMG) || (inMessageID == BUILD_SHOTGUN) || (inMessageID == BUILD_GRENADE_GUN)) { 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_VAR(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 ); this->EffectivePlayerClassChanged(); // 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_VAR(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_VAR(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; } AvHTechTree& AvHPlayer::GetCombatNodes() { return this->mCombatNodes; } MessageIDListType& AvHPlayer::GetPurchasedCombatUpgrades() { return this->mPurchasedCombatUpgrades; } void AvHPlayer::SetCombatNodes(const AvHTechTree& 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_VAR(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_VAR(kCombatResupplyHealthPercentage)) || theAmmoResupply) //(theAmmoPercentage < BALANCE_VAR(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_VAR(kScanRadius))) != NULL) { if(!AvHSUGetIsExternalClassName(STRING(theSphereEntity->pev->classname))) { AvHCloakable* theCloakable = dynamic_cast(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_VAR(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_VAR(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_VAR(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(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_VAR(kCombatIronManExperienceScalar) : 1.0f; int theExperienceToAward = BALANCE_VAR(kCombatExperienceBaseAward) + inTargetLevel*BALANCE_VAR(kCombatExperienceLevelAward); float theExperienceForEach = (theExperienceToAward/(float)thePlayerList.size() + BALANCE_VAR(kCombatExperienceCrowdAward))*theExperienceFactor; for(PlayerListType::iterator thePlayerIter = thePlayerList.begin(); thePlayerIter != thePlayerList.end(); thePlayerIter++) { AvHPlayer* theCurrentPlayer = (*thePlayerIter); theCurrentPlayer->SetExperience(theCurrentPlayer->GetExperience() + theExperienceForEach); } }