430 lines
12 KiB
SourcePawn
430 lines
12 KiB
SourcePawn
/**
|
|
* Checks for clients near AoE Towers
|
|
*
|
|
* @param hTimer Timer Handle
|
|
* @param iTower The tower
|
|
* @noreturn
|
|
*/
|
|
public Action Timer_ClientNearAoETower(Handle hTimer) {
|
|
for (int iClient = 1; iClient <= MaxClients; iClient++) {
|
|
if (IsClientInGame(iClient) && IsPlayerAlive(iClient)) {
|
|
if (IsTower(iClient)) {
|
|
int iTower = iClient;
|
|
TDTowerId iTowerId = GetTowerId(iTower);
|
|
|
|
if (iTowerId == TDTower_AoE_Engineer) {
|
|
float fAreaScale = 80.0 * Tower_GetAreaScale(GetTowerId(iTower));
|
|
CreateBeamBoxAroundClient(iTower, fAreaScale, true, 0.2, { 231, 76, 60, 25 });
|
|
Tower_ObjectNearAoEEngineer(iTower, iClient);
|
|
}
|
|
if (iTowerId == TDTower_Medic) {
|
|
float fAreaScale = 160.0 * Tower_GetAreaScale(GetTowerId(iTower));
|
|
CreateBeamBoxAroundClient(iTower, fAreaScale, true, 0.2, { 46, 204, 113, 25 });
|
|
Tower_ObjectNearAoEMedic(iTower);
|
|
}
|
|
if (iTowerId == TDTower_Kritz_Medic) {
|
|
float fAreaScale = 60.0 * Tower_GetAreaScale(GetTowerId(iTower));
|
|
CreateBeamBoxAroundClient(iTower, fAreaScale, true, 0.2, { 41, 128, 185, 25 });
|
|
Tower_ObjectNearKritzMedic(iTower);
|
|
}
|
|
if (iTowerId == TDTower_Slow_Spy) {
|
|
float fAreaScale = 100.0 * Tower_GetAreaScale(GetTowerId(iTower));
|
|
CreateBeamBoxAroundClient(iTower, fAreaScale, false, 0.2, { 44, 62, 80, 25 });
|
|
Tower_ObjectNearAoESpy(iTower);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return Plugin_Continue;
|
|
}
|
|
|
|
/**
|
|
* Player is close to AoEMedic
|
|
*
|
|
* @param iTower The tower
|
|
* @param iClient The player
|
|
* @noreturn
|
|
*/
|
|
public void Tower_ObjectNearAoEMedic(int iTower) {
|
|
for (int iClient = 1; iClient <= MaxClients; iClient++) {
|
|
if (IsDefender(iClient) && IsClientInZone(iClient, g_fBeamPoints[iTower])) {
|
|
Player_AddHealth(iClient, 5);
|
|
|
|
// Check if there is no Beam
|
|
if (g_iHealBeamIndex[iClient][0] == 0 && g_iHealBeamIndex[iClient][1] == 0) {
|
|
AttachHealBeam(iTower, iClient);
|
|
}
|
|
|
|
} else {
|
|
Tower_ObjectNotNearAoEMedic(iClient);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Player isn't close to AoEMedic
|
|
*
|
|
* @param iTower The tower
|
|
* @param iClient The player
|
|
* @noreturn
|
|
*/
|
|
public void Tower_ObjectNotNearAoEMedic(int iClient) {
|
|
// Remove Beam if there is one
|
|
if (g_iHealBeamIndex[iClient][0] != 0) {
|
|
if (IsValidEdict(g_iHealBeamIndex[iClient][0])) {
|
|
RemoveEdict(g_iHealBeamIndex[iClient][0]);
|
|
g_iHealBeamIndex[iClient][0] = 0;
|
|
}
|
|
}
|
|
|
|
if (g_iHealBeamIndex[iClient][1] != 0) {
|
|
if (IsValidEdict(g_iHealBeamIndex[iClient][1])) {
|
|
RemoveEdict(g_iHealBeamIndex[iClient][1]);
|
|
g_iHealBeamIndex[iClient][1] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Player is close to AoEEngineer
|
|
*
|
|
* @param iTower The tower
|
|
* @param iClient The player
|
|
* @noreturn
|
|
*/
|
|
public void Tower_ObjectNearAoEEngineer(int iTower, int iClient) {
|
|
if (iAoEEngineerTimer < 3 && !IsTowerAttached(iTower)) {
|
|
iAoEEngineerTimer++;
|
|
return;
|
|
} else if (!IsTowerAttached(iTower)) {
|
|
iAoEEngineerTimer = 0;
|
|
}
|
|
int iSentry = -1, iDispenser = -1;
|
|
float fLocation[3];
|
|
|
|
// Sentries
|
|
while ((iSentry = FindEntityByClassname(iSentry, "obj_sentrygun")) != -1) {
|
|
if (!IsValidEntity(iSentry)) {
|
|
continue;
|
|
}
|
|
|
|
GetEntPropVector(iSentry, Prop_Send, "m_vecOrigin", fLocation);
|
|
fLocation[2] += 20.0;
|
|
|
|
if (IsPointInZone(fLocation, g_fBeamPoints[iTower])) {
|
|
int iShellsMax, iHealthMax, iRocketsMax, iMetalMax;
|
|
|
|
if (IsMiniSentry(iSentry)) {
|
|
iShellsMax = 150;
|
|
iHealthMax = 150;
|
|
iRocketsMax = 0;
|
|
iMetalMax = 0;
|
|
} else {
|
|
switch (GetBuildingLevel(iSentry)) {
|
|
case 1: {
|
|
iShellsMax = 150;
|
|
iHealthMax = 150;
|
|
iRocketsMax = 0;
|
|
iMetalMax = 1000;
|
|
}
|
|
|
|
case 2: {
|
|
iShellsMax = 200;
|
|
iHealthMax = 180;
|
|
iRocketsMax = 0;
|
|
iMetalMax = 1000;
|
|
}
|
|
|
|
case 3: {
|
|
iShellsMax = 200;
|
|
iHealthMax = 216;
|
|
iRocketsMax = 20;
|
|
iMetalMax = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
int iState = GetEntProp(iSentry, Prop_Send, "m_iState");
|
|
|
|
// If is not building up
|
|
if (iState != 0) {
|
|
int iShells = GetEntProp(iSentry, Prop_Send, "m_iAmmoShells");
|
|
int iHealth = GetEntProp(iSentry, Prop_Send, "m_iHealth");
|
|
int iRockets = GetEntProp(iSentry, Prop_Send, "m_iAmmoRockets");
|
|
int iMetal = GetEntProp(iSentry, Prop_Send, "m_iUpgradeMetal");
|
|
|
|
if (IsMiniSentry(iSentry)) {
|
|
int iShellsPerHit = 20; // Default: 40
|
|
|
|
if (iShells + iShellsPerHit < iShellsMax) {
|
|
SetEntProp(iSentry, Prop_Send, "m_iAmmoShells", iShells + iShellsPerHit);
|
|
} else if (iShells < iShellsMax) {
|
|
SetEntProp(iSentry, Prop_Send, "m_iAmmoShells", iShellsMax);
|
|
}
|
|
} else {
|
|
int iMetalPerHit = 10; // Default: 25
|
|
int iHealthPerHit = 50; // Default: 105
|
|
int iShellsPerHit = 20; // Default: 40
|
|
int iRocketsPerHit = 4; // Default: 8
|
|
|
|
if (iMetal < iMetalMax) {
|
|
SetEntProp(iSentry, Prop_Send, "m_iUpgradeMetal", iMetal + iMetalPerHit);
|
|
|
|
// Upgrade to the next level
|
|
} else if (iMetalMax != 0 && !g_bAoEEngineerAttack) {
|
|
float fLocationTower[3];
|
|
GetClientAbsOrigin(iTower, fLocationTower);
|
|
|
|
TeleportEntity(iTower, fLocation, NULL_VECTOR, NULL_VECTOR);
|
|
|
|
g_bAoEEngineerAttack = true;
|
|
|
|
DataPack hPack = new DataPack();
|
|
hPack.WriteFloat(float(iTower));
|
|
hPack.WriteFloat(fLocationTower[0]);
|
|
hPack.WriteFloat(fLocationTower[1]);
|
|
hPack.WriteFloat(fLocationTower[2]);
|
|
|
|
CreateTimer(0.2, Timer_TeleportAoEEngineerBack, hPack, _);
|
|
}
|
|
|
|
if (iHealth + iHealthPerHit < iHealthMax) {
|
|
SetEntProp(iSentry, Prop_Send, "m_iHealth", iHealth + iHealthPerHit);
|
|
} else if (iHealth < iHealthMax) {
|
|
SetEntProp(iSentry, Prop_Send, "m_iHealth", iHealthMax);
|
|
}
|
|
|
|
if (iShells + iShellsPerHit < iShellsMax) {
|
|
SetEntProp(iSentry, Prop_Send, "m_iAmmoShells", iShells + iShellsPerHit);
|
|
} else if (iShells < iShellsMax) {
|
|
SetEntProp(iSentry, Prop_Send, "m_iAmmoShells", iShellsMax);
|
|
}
|
|
if (iRockets + iRocketsPerHit < iRocketsMax) {
|
|
SetEntProp(iSentry, Prop_Send, "m_iAmmoRockets", iRockets + iRocketsPerHit);
|
|
} else if (iRockets < iRocketsMax) {
|
|
SetEntProp(iSentry, Prop_Send, "m_iAmmoRockets", iRocketsMax);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Dispensers
|
|
while ((iDispenser = FindEntityByClassname(iDispenser, "obj_dispenser")) != -1) {
|
|
if (!IsValidEntity(iDispenser)) {
|
|
continue;
|
|
}
|
|
|
|
GetEntPropVector(iDispenser, Prop_Send, "m_vecOrigin", fLocation);
|
|
|
|
fLocation[2] += 20.0;
|
|
|
|
if (IsPointInZone(fLocation, g_fBeamPoints[iTower])) {
|
|
int iHealthMax, iMetalMax;
|
|
|
|
switch (GetBuildingLevel(iDispenser)) {
|
|
case 1: {
|
|
iHealthMax = 150;
|
|
iMetalMax = 500;
|
|
}
|
|
|
|
case 2: {
|
|
iHealthMax = 180;
|
|
iMetalMax = 500;
|
|
}
|
|
|
|
case 3: {
|
|
iHealthMax = 216;
|
|
iMetalMax = 0;
|
|
}
|
|
}
|
|
|
|
int iBuildingUp = GetEntProp(iDispenser, Prop_Send, "m_bBuilding");
|
|
if (iBuildingUp != 1) { // Is not building up
|
|
int iHealth = GetEntProp(iDispenser, Prop_Send, "m_iHealth");
|
|
int iMetal = GetEntProp(iDispenser, Prop_Send, "m_iUpgradeMetal");
|
|
int iMetalPerHit = 10; // Default: 25
|
|
int iHealthPerHit = 50; // Default: 105
|
|
|
|
if (iMetal < iMetalMax) {
|
|
SetEntProp(iDispenser, Prop_Send, "m_iUpgradeMetal", iMetal + iMetalPerHit);
|
|
} else if (iMetalMax != 0 && !g_bAoEEngineerAttack) { // Upgrade to the next level
|
|
float fLocationTower[3];
|
|
GetClientAbsOrigin(iTower, fLocationTower);
|
|
|
|
TeleportEntity(iTower, fLocation, NULL_VECTOR, NULL_VECTOR);
|
|
|
|
g_bAoEEngineerAttack = true;
|
|
|
|
DataPack hPack = new DataPack();
|
|
hPack.WriteFloat(float(iTower));
|
|
hPack.WriteFloat(fLocationTower[0]);
|
|
hPack.WriteFloat(fLocationTower[1]);
|
|
hPack.WriteFloat(fLocationTower[2]);
|
|
|
|
CreateTimer(0.5, Timer_TeleportAoEEngineerBack, hPack, _);
|
|
}
|
|
|
|
if (iHealth + iHealthPerHit < iHealthMax) {
|
|
SetEntProp(iDispenser, Prop_Send, "m_iHealth", iHealth + iHealthPerHit);
|
|
} else if (iHealth < iHealthMax) {
|
|
SetEntProp(iDispenser, Prop_Send, "m_iHealth", iHealthMax);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public Action Timer_TeleportAoEEngineerBack(Handle hTimer, DataPack hPack) {
|
|
hPack.Reset();
|
|
|
|
g_bAoEEngineerAttack = false;
|
|
int iTower = RoundToZero(ReadPackFloat(hPack));
|
|
float fLocation[3];
|
|
fLocation[0] = hPack.ReadFloat();
|
|
fLocation[1] = hPack.ReadFloat();
|
|
fLocation[2] = hPack.ReadFloat();
|
|
TeleportEntity(iTower, fLocation, NULL_VECTOR, NULL_VECTOR);
|
|
return Plugin_Continue;
|
|
}
|
|
|
|
/**
|
|
* Player is close to KritzMedic
|
|
*
|
|
* @param iTower The tower
|
|
* @noreturn
|
|
*/
|
|
public void Tower_ObjectNearKritzMedic(int iTower) {
|
|
// If Kritz Time is up
|
|
if (TF2_GetUberLevel(iTower) <= 0.0)
|
|
g_bKritzMedicCharged = false;
|
|
|
|
// If Bot is fully charged, charge player
|
|
if (g_bKritzMedicCharged && TF2_GetUberLevel(iTower) > 0.0) {
|
|
TF2_SetUberLevel(iTower, TF2_GetUberLevel(iTower) - 0.02);
|
|
for (int iClient = 1; iClient <= MaxClients; iClient++) {
|
|
if (IsValidClient(iClient))
|
|
TF2_AddCondition(iClient, TFCond_Kritzkrieged, 0.3);
|
|
}
|
|
// If Bot is fully charged
|
|
} else if (TF2_GetUberLevel(iTower) >= 1.0) {
|
|
g_bKritzMedicCharged = true;
|
|
} else if (iAoEKritzMedicTimer < 3 && !IsTowerAttached(iTower)) {
|
|
iAoEKritzMedicTimer++;
|
|
return;
|
|
} else if (!IsTowerAttached(iTower)) {
|
|
iAoEKritzMedicTimer = 0;
|
|
}
|
|
for (int iClient = 1; iClient <= MaxClients; iClient++) {
|
|
if (IsDefender(iClient) && IsClientInZone(iClient, g_fBeamPoints[iTower])) {
|
|
float fUberLevel = TF2_GetUberLevel(iTower);
|
|
TF2_SetUberLevel(iTower, fUberLevel + 0.01);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Player is close to AoESpy
|
|
*
|
|
* @param iTower The tower
|
|
* @param iClient The player
|
|
* @noreturn
|
|
*/
|
|
public void Tower_ObjectNearAoESpy(int iTower) {
|
|
for (int iClient = 1; iClient <= MaxClients; iClient++) {
|
|
if (IsAttacker(iClient) && IsClientInZone(iClient, g_fBeamPoints[iTower]) && !g_iSlowAttacker[iClient])
|
|
g_iSlowAttacker[iClient] = true;
|
|
else if (g_iSlowAttacker[iClient] && IsClientInZone(iClient, g_fBeamPoints[iTower]))
|
|
TF2_AddCondition(iClient, TFCond_TeleportedGlow, 1.0);
|
|
else if (g_iSlowAttacker[iClient])
|
|
g_iSlowAttacker[iClient] = false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets the level of an building.
|
|
*
|
|
* @param iEntity The buildings entity index.
|
|
* @return The buildings level.
|
|
*/
|
|
public int GetBuildingLevel(int iEntity) {
|
|
return GetEntProp(iEntity, Prop_Send, "m_iUpgradeLevel");
|
|
}
|
|
|
|
/**
|
|
* Checks wheter a sentry is a Mini-Sentry or not.
|
|
*
|
|
* @param iSentry The sentries entity index.
|
|
* @return True if mini, false otherwise.
|
|
*/
|
|
public bool IsMiniSentry(int iSentry) {
|
|
return ((GetEntProp(iSentry, Prop_Send, "m_bMiniBuilding") == 0) ? false : true);
|
|
}
|
|
|
|
/**
|
|
* Attach a beam between two entities
|
|
*
|
|
* @param iEntity The start point
|
|
* @param iTarget The target
|
|
* @noreturn
|
|
*/
|
|
stock void AttachHealBeam(int iEntity, int iTarget) {
|
|
int iParticleIndex1 = CreateEntityByName("info_particle_system");
|
|
int iParticleIndex2 = CreateEntityByName("info_particle_system");
|
|
|
|
if (IsValidEdict(iParticleIndex1)) {
|
|
char sEntityName[128];
|
|
Format(sEntityName, sizeof(sEntityName), "target%i", iEntity);
|
|
DispatchKeyValue(iEntity, "targetname", sEntityName);
|
|
|
|
char sTargetName1[128];
|
|
Format(sTargetName1, sizeof(sTargetName1), "target%i", iTarget);
|
|
DispatchKeyValue(iTarget, "targetname", sTargetName1);
|
|
|
|
char sTargetName2[128];
|
|
Format(sTargetName2, sizeof(sTargetName2), "tf2particle%i", iTarget);
|
|
|
|
DispatchKeyValue(iParticleIndex2, "targetname", sTargetName2);
|
|
DispatchKeyValue(iParticleIndex2, "parentname", sTargetName1);
|
|
|
|
SetVariantString(sTargetName1);
|
|
AcceptEntityInput(iParticleIndex2, "SetParent");
|
|
|
|
SetVariantString("flag");
|
|
AcceptEntityInput(iParticleIndex2, "SetParentAttachment");
|
|
|
|
DispatchKeyValue(iParticleIndex1, "targetname", "tf2particle");
|
|
DispatchKeyValue(iParticleIndex1, "parentname", sEntityName);
|
|
DispatchKeyValue(iParticleIndex1, "effect_name", "dispenser_heal_blue");
|
|
DispatchKeyValue(iParticleIndex1, "cpoint1", sTargetName2);
|
|
|
|
DispatchSpawn(iParticleIndex1);
|
|
|
|
SetVariantString(sEntityName);
|
|
AcceptEntityInput(iParticleIndex1, "SetParent");
|
|
|
|
SetVariantString("flag");
|
|
AcceptEntityInput(iParticleIndex1, "SetParentAttachment");
|
|
|
|
ActivateEntity(iParticleIndex1);
|
|
AcceptEntityInput(iParticleIndex1, "start");
|
|
|
|
g_iHealBeamIndex[iTarget][0] = iParticleIndex1;
|
|
g_iHealBeamIndex[iTarget][1] = iParticleIndex2;
|
|
}
|
|
}
|
|
|
|
stock float TF2_GetUberLevel(int iClient) {
|
|
int iIndex = GetPlayerWeaponSlot(iClient, 1);
|
|
if (iIndex > 0)
|
|
return GetEntPropFloat(iIndex, Prop_Send, "m_flChargeLevel");
|
|
else
|
|
return 0.0;
|
|
}
|
|
|
|
stock void TF2_SetUberLevel(int iClient, float fUberLevel) {
|
|
int iIndex = GetPlayerWeaponSlot(iClient, 1);
|
|
if (iIndex > 0)
|
|
SetEntPropFloat(iIndex, Prop_Send, "m_flChargeLevel", fUberLevel);
|
|
}
|