362 lines
11 KiB
SourcePawn
362 lines
11 KiB
SourcePawn
#pragma semicolon 1
|
|
|
|
#include <sourcemod>
|
|
|
|
#if defined INFO_INCLUDES
|
|
#include "../info/constants.sp"
|
|
#include "../info/enums.sp"
|
|
#include "../info/variables.sp"
|
|
#endif
|
|
|
|
/**
|
|
* Initializes the server.
|
|
*
|
|
* @noreturn
|
|
*/
|
|
|
|
stock void Server_Initialize() {
|
|
Log(TDLogLevel_Debug, "Initializing server");
|
|
|
|
StripConVarFlag("sv_cheats", FCVAR_NOTIFY);
|
|
StripConVarFlag("sv_tags", FCVAR_NOTIFY);
|
|
StripConVarFlag("tf_bot_count", FCVAR_NOTIFY);
|
|
StripConVarFlag("sv_password", FCVAR_NOTIFY);
|
|
|
|
HookButtons();
|
|
Server_Reset();
|
|
|
|
int iServerIp[4];
|
|
SteamWorks_GetPublicIP(iServerIp);
|
|
Format(g_sServerIp, sizeof(g_sServerIp), "%d.%d.%d.%d", iServerIp[0], iServerIp[1], iServerIp[2], iServerIp[3]);
|
|
|
|
char sServerPort[6];
|
|
GetConVarString(FindConVar("hostport"), sServerPort, sizeof(sServerPort));
|
|
g_iServerPort = StringToInt(sServerPort);
|
|
|
|
if (StrEqual(g_sServerIp, "0.0.0.0")) {
|
|
Log(TDLogLevel_Error, "ServerIP: %s", g_sServerIp);
|
|
Log(TDLogLevel_Error, "Vac enabled?: %b", SteamWorks_IsVACEnabled());
|
|
Log(TDLogLevel_Error, "Is connected to Steam?: %b", SteamWorks_IsConnected());
|
|
Log(TDLogLevel_Error, "This can be caused by using GSLT with an expired Token. https://steamcommunity.com/dev/managegameservers");
|
|
Log(TDLogLevel_Error, "The server will loop indefinetly if it can't connect to Steam");
|
|
|
|
Log(TDLogLevel_Info, "Server has been restarted completely, reloading map for initializing");
|
|
ReloadMap();
|
|
} else {
|
|
Database_CheckServer(); // Calls Database_OnServerChecked() when finished
|
|
}
|
|
}
|
|
|
|
stock void Database_OnServerChecked() {
|
|
Log(TDLogLevel_Trace, "Database_OnServerChecked");
|
|
|
|
Database_LoadData(); // Calls Database_OnDataLoaded() when finished
|
|
}
|
|
|
|
stock void Database_OnDataLoaded() {
|
|
Log(TDLogLevel_Debug, "Successfully initialized server");
|
|
|
|
PrintToHudAll("WELCOME TO TF2 TOWER DEFENSE");
|
|
|
|
g_bServerInitialized = true;
|
|
}
|
|
|
|
/**
|
|
* Resets the server.
|
|
*
|
|
* @noreturn
|
|
*/
|
|
|
|
stock void Server_Reset() {
|
|
g_bEnabled = g_hEnabled.BoolValue && g_bTowerDefenseMap && g_bSteamWorks && g_bTF2Attributes;
|
|
g_bMapRunning = true;
|
|
|
|
UpdateGameDescription();
|
|
|
|
if (!g_bEnabled) {
|
|
if (!g_bTowerDefenseMap) {
|
|
char sCurrentMap[PLATFORM_MAX_PATH];
|
|
GetCurrentMap(sCurrentMap, sizeof(sCurrentMap));
|
|
|
|
Log(TDLogLevel_Info, "Map \"%s\" is not supported, thus Tower Defense has been disabled.", sCurrentMap);
|
|
} else {
|
|
Log(TDLogLevel_Info, "Tower Defense is disabled.");
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
g_iBuildingLimit[TDBuilding_Sentry] = 1;
|
|
g_iBuildingLimit[TDBuilding_Dispenser] = 0;
|
|
g_iBuildingLimit[TDBuilding_TeleporterEntry] = 1;
|
|
g_iBuildingLimit[TDBuilding_TeleporterExit] = 1;
|
|
|
|
// Reset Hint Timer
|
|
if (hHintTimer != null) {
|
|
CloseHandle(hHintTimer);
|
|
hHintTimer = null;
|
|
}
|
|
|
|
for (int iClient = 1; iClient <= MaxClients; iClient++) {
|
|
// Reset carry Towers/Sentry
|
|
if (IsTower(g_iAttachedTower[iClient])) {
|
|
TF2Attrib_RemoveByName(iClient, "cannot pick up buildings");
|
|
g_iLastMover[g_iAttachedTower[iClient]] = 0;
|
|
g_bCarryingObject[iClient] = false;
|
|
g_iAttachedTower[iClient] = 0;
|
|
}
|
|
// Reset bought Towers
|
|
if (IsTower(iClient)) {
|
|
TDTowerId iTowerId = GetTowerId(iClient);
|
|
// tf_bot_quota > 0 breaks this here
|
|
if (iTowerId != TDTower_Invalid) {
|
|
g_bTowerBought[view_as<int>(iTowerId)] = false;
|
|
}
|
|
}
|
|
if (IsAttacker(iClient) && g_iSlowAttacker[iClient]) {
|
|
g_iSlowAttacker[iClient] = false;
|
|
}
|
|
if (IsDefender(iClient)) {
|
|
g_bCarryingObject[iClient] = false;
|
|
// 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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Reset Multipliers
|
|
for (int i = 1; i <= iMaxMultiplierTypes; i++) {
|
|
fMultiplier[i] = 0.0;
|
|
}
|
|
g_iTime = GetTime();
|
|
g_iMetalPackCount = 0;
|
|
|
|
g_bTowersLocked = false;
|
|
g_bAoEEngineerAttack = false;
|
|
|
|
g_bStartWaveEarly = false;
|
|
g_iBotsToSpawn = 0;
|
|
g_iTotalBotsLeft = 0;
|
|
|
|
g_iCurrentWave = 0;
|
|
g_iNextWaveType = 0;
|
|
|
|
iAoEEngineerTimer = 0;
|
|
iAoEKritzMedicTimer = 0;
|
|
|
|
g_iHealthBar = GetHealthBar();
|
|
|
|
g_bLockable = true;
|
|
g_bCanGetUnlocks = true;
|
|
|
|
// Reset AoE Timer
|
|
if (hAoETimer != null) {
|
|
CloseHandle(hAoETimer);
|
|
hAoETimer = null;
|
|
}
|
|
|
|
// Get map max clients
|
|
g_iMaxClients = PLAYER_LIMIT;
|
|
|
|
char sQuery[256];
|
|
char sCurrentMap[PLATFORM_MAX_PATH];
|
|
GetCurrentMap(sCurrentMap, sizeof(sCurrentMap));
|
|
|
|
g_hDatabase.Format(sQuery, sizeof(sQuery),
|
|
"SELECT `player_limit` " ...
|
|
"FROM `map` " ...
|
|
"WHERE `name` = '%s' " ...
|
|
"LIMIT 1",
|
|
sCurrentMap);
|
|
|
|
DBResultSet queryResult = SQL_Query(g_hDatabase, sQuery);
|
|
|
|
if (queryResult == null) {
|
|
char error[255];
|
|
SQL_GetError(g_hDatabase, error, sizeof(error));
|
|
LogType(TDLogLevel_Error, TDLogType_FileAndConsole, "Failed to query (error: %s)", error);
|
|
} else {
|
|
if (queryResult.HasResults && queryResult.FetchRow()) {
|
|
int iResult = queryResult.FetchInt(0);
|
|
if (iResult > 0) {
|
|
g_iMaxClients = iResult;
|
|
LogType(TDLogLevel_Debug, TDLogType_FileAndConsole, "Max clients for map %s is %d", sCurrentMap, g_iMaxClients);
|
|
} else {
|
|
LogType(TDLogLevel_Error, TDLogType_FileAndConsole, "Max clients for map %s is %d. This isnt supported; Please check the database entries. Setting max clients to default %d", sCurrentMap, iResult, g_iMaxClients);
|
|
}
|
|
} else {
|
|
LogType(TDLogLevel_Debug, TDLogType_FileAndConsole, "Couldn't find entry for map '%s'. Setting max clients to default %d", sCurrentMap, g_iMaxClients);
|
|
}
|
|
delete queryResult;
|
|
}
|
|
|
|
int clients = (g_iMaxClients + g_hMaxBotsOnField.IntValue) - MaxClients;
|
|
|
|
if (clients > 0) {
|
|
char cvarName[32];
|
|
g_hMaxBotsOnField.GetName(cvarName, sizeof(cvarName));
|
|
LogType(TDLogLevel_Warning, TDLogType_FileAndConsole, "ConVar '%s' value + the allowed max clients '%d' (database) is higher than the server maxplayers '%d'. Shrinking convar value by '%d'", cvarName, g_iMaxClients, MaxClients, clients);
|
|
g_hMaxBotsOnField.IntValue = g_hMaxBotsOnField.IntValue - clients;
|
|
}
|
|
|
|
Format(g_sPassword, sizeof(g_sPassword), "");
|
|
|
|
SetPassword(g_sPassword, false); // Change upon release
|
|
}
|
|
|
|
/**
|
|
* Called when a servers data was set.
|
|
*
|
|
* @param iServerId The server id (unique for every server).
|
|
* @param sKey The set key.
|
|
* @param iDataType The datatype of the set data.
|
|
* @param iValue The value if the set data is an integer, -1 otherwise.
|
|
* @param bValue The value if the set data is a boolean, false otherwise.
|
|
* @param fValue The value if the set data is a float, -1.0 otherwise.
|
|
* @param sValue The value if the set data is a string, empty string ("") otherwise.
|
|
* @noreturn
|
|
*/
|
|
|
|
stock void Server_OnDataSet(int iServerId, const char[] sKey, TDDataType iDataType, int iValue, int bValue, float fValue, const char[] sValue) {
|
|
switch (iDataType) {
|
|
case TDDataType_Integer: {
|
|
Log(TDLogLevel_Trace, "Server_OnDataSet: iServerId=%d, sKey=%s, iDataType=TDDataType_Integer, iValue=%d", iServerId, sKey, iValue);
|
|
}
|
|
|
|
case TDDataType_Boolean: {
|
|
Log(TDLogLevel_Trace, "Server_OnDataSet: iServerId=%d, sKey=%s, iDataType=TDDataType_Boolean, bValue=%s", iServerId, sKey, (bValue ? "true" : "false"));
|
|
}
|
|
|
|
case TDDataType_Float: {
|
|
Log(TDLogLevel_Trace, "Server_OnDataSet: iServerId=%d, sKey=%s, iDataType=TDDataType_Float, fValue=%f", iServerId, sKey, fValue);
|
|
}
|
|
|
|
case TDDataType_String: {
|
|
Log(TDLogLevel_Trace, "Server_OnDataSet: iServerId=%d, sKey=%s, iDataType=TDDataType_String, sValue=%s", iServerId, sKey, sValue);
|
|
}
|
|
}
|
|
}
|
|
|
|
stock void Server_UAddValue(int iServerId, const char[] sKey, int iValue) {
|
|
char sServerIdKey[128];
|
|
int iOldValue;
|
|
Server_UGetValue(iServerId, sKey, iOldValue);
|
|
if (iOldValue != -1)
|
|
iValue = iValue + iOldValue;
|
|
|
|
Format(sServerIdKey, sizeof(sServerIdKey), "%d_%s", iServerId, sKey);
|
|
|
|
Server_OnDataSet(iServerId, sKey, TDDataType_Integer, iValue, false, -1.0, "");
|
|
|
|
SetTrieValue(g_hServerData, sServerIdKey, iValue);
|
|
}
|
|
|
|
stock void Server_USetValue(int iServerId, const char[] sKey, int iValue) {
|
|
char sServerIdKey[128];
|
|
Format(sServerIdKey, sizeof(sServerIdKey), "%d_%s", iServerId, sKey);
|
|
|
|
Server_OnDataSet(iServerId, sKey, TDDataType_Integer, iValue, false, -1.0, "");
|
|
|
|
SetTrieValue(g_hServerData, sServerIdKey, iValue);
|
|
}
|
|
|
|
stock bool Server_UGetValue(int iServerId, const char[] sKey, int &iValue) {
|
|
char sServerIdKey[128];
|
|
Format(sServerIdKey, sizeof(sServerIdKey), "%d_%s", iServerId, sKey);
|
|
|
|
Log(TDLogLevel_Trace, "Server_UGetValue: iServerId=%d, sKey=%s", iServerId, sKey);
|
|
|
|
if (!GetTrieValue(g_hServerData, sServerIdKey, iValue)) {
|
|
iValue = -1;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
stock void Server_USetBool(int iServerId, const char[] sKey, bool bValue) {
|
|
char sServerIdKey[128];
|
|
Format(sServerIdKey, sizeof(sServerIdKey), "%d_%s", iServerId, sKey);
|
|
|
|
Server_OnDataSet(iServerId, sKey, TDDataType_Integer, -1, bValue, -1.0, "");
|
|
|
|
SetTrieValue(g_hServerData, sServerIdKey, (bValue ? 1 : 0));
|
|
}
|
|
|
|
stock bool Server_UGetBool(int iServerId, const char[] sKey) {
|
|
char sServerIdKey[128];
|
|
Format(sServerIdKey, sizeof(sServerIdKey), "%d_%s", iServerId, sKey);
|
|
|
|
Log(TDLogLevel_Trace, "Server_UGetBool: iServerId=%d, sKey=%s", iServerId, sKey);
|
|
|
|
int iValue = 0;
|
|
GetTrieValue(g_hServerData, sServerIdKey, iValue);
|
|
|
|
return (iValue != 0);
|
|
}
|
|
|
|
stock void Server_USetFloat(int iServerId, const char[] sKey, float fValue) {
|
|
char sServerIdKey[128];
|
|
Format(sServerIdKey, sizeof(sServerIdKey), "%d_%s", iServerId, sKey);
|
|
|
|
char sValue[64];
|
|
FloatToString(fValue, sValue, sizeof(sValue));
|
|
|
|
Server_OnDataSet(iServerId, sKey, TDDataType_Integer, -1, false, fValue, "");
|
|
|
|
SetTrieString(g_hServerData, sServerIdKey, sValue);
|
|
}
|
|
|
|
stock bool Server_UGetFloat(int iServerId, const char[] sKey, float &fValue) {
|
|
char sServerIdKey[128];
|
|
Format(sServerIdKey, sizeof(sServerIdKey), "%d_%s", iServerId, sKey);
|
|
|
|
Log(TDLogLevel_Trace, "Server_UGetFloat: iServerId=%d, sKey=%s", iServerId, sKey);
|
|
|
|
char sValue[64];
|
|
if (!GetTrieString(g_hServerData, sServerIdKey, sValue, sizeof(sValue))) {
|
|
fValue = -1.0;
|
|
return false;
|
|
}
|
|
|
|
fValue = StringToFloat(sValue);
|
|
return true;
|
|
}
|
|
|
|
stock void Server_USetString(int iServerId, const char[] sKey, const char[] sValue, any...) {
|
|
char sServerIdKey[128];
|
|
Format(sServerIdKey, sizeof(sServerIdKey), "%d_%s", iServerId, sKey);
|
|
|
|
char sFormattedValue[256];
|
|
VFormat(sFormattedValue, sizeof(sFormattedValue), sValue, 4);
|
|
|
|
Server_OnDataSet(iServerId, sKey, TDDataType_String, -1, false, -1.0, sValue);
|
|
|
|
SetTrieString(g_hServerData, sServerIdKey, sFormattedValue);
|
|
}
|
|
|
|
stock bool Server_UGetString(int iServerId, const char[] sKey, char[] sValue, int iMaxLength) {
|
|
char sServerIdKey[128];
|
|
Format(sServerIdKey, sizeof(sServerIdKey), "%d_%s", iServerId, sKey);
|
|
|
|
Log(TDLogLevel_Trace, "Server_UGetString: iServerId=%d, sKey=%s, iMaxLength=%d", iServerId, sKey, iMaxLength);
|
|
|
|
if (!GetTrieString(g_hServerData, sServerIdKey, sValue, iMaxLength)) {
|
|
Format(sValue, iMaxLength, "");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|