diff --git a/cstrike/addons/sourcemod/translations/zombiereloaded.phrases.txt b/cstrike/addons/sourcemod/translations/zombiereloaded.phrases.txt index 78cff2f..119664a 100644 --- a/cstrike/addons/sourcemod/translations/zombiereloaded.phrases.txt +++ b/cstrike/addons/sourcemod/translations/zombiereloaded.phrases.txt @@ -1104,6 +1104,12 @@ "Vol Slay" { "#format" "{1:s},{2:d}" - "en" "Player \"{1}\" has been slayed for camping in a restricted area (ID: {2})." + "en" "Slayed player \"{1}\" for camping in a restricted area (ID: {2})." } -} \ No newline at end of file + + "Vol Ignite" + { + "#format" "{1:s},{2:d}" + "en" "Ignited player \"{1}\" for camping in a restricted area (ID: {2})." + } +} diff --git a/src/zr/event.inc b/src/zr/event.inc index ed93272..05f9325 100644 --- a/src/zr/event.inc +++ b/src/zr/event.inc @@ -282,6 +282,7 @@ public Action:EventPlayerDeath(Handle:event, const String:name[], bool:dontBroad ZSpawnOnClientDeath(index); ZTeleOnClientDeath(index); ZHPOnClientDeath(index); + VolOnPlayerDeath(index); } /** diff --git a/src/zr/volfeatures/volanticamp.inc b/src/zr/volfeatures/volanticamp.inc index d99fe98..e8f6dd4 100644 --- a/src/zr/volfeatures/volanticamp.inc +++ b/src/zr/volfeatures/volanticamp.inc @@ -77,6 +77,7 @@ new AnticampData[ZR_VOLUMES_MAX][VolTypeAnticamp]; VolAnticampEnable(volumeIndex) { new Float:interval; + new Handle:timer; // Validate index. if (!VolIsValidIndex(volumeIndex)) @@ -96,20 +97,27 @@ VolAnticampEnable(volumeIndex) // Check if in use. if (AnticampData[dataindex][Anticamp_InUse]) { - // Start timer if not running. - if (AnticampData[dataindex][Anticamp_Timer] == INVALID_HANDLE) + // Kill timer if it exist. + timer = AnticampData[dataindex][Anticamp_Timer]; + if (timer != INVALID_HANDLE) { - // Get interval. - interval = AnticampData[dataindex][Anticamp_Interval]; - - // Validate interval. - if (interval > 0.0) - { - AnticampData[dataindex][Anticamp_Timer] = CreateTimer(interval, Event_VolAnticampTrigger, _, TIMER_REPEAT); - } + KillTimer(timer); + AnticampData[dataindex][Anticamp_Timer] = INVALID_HANDLE; } - LogEvent(_, LogType_Normal, LOG_DEBUG, LogModule_Volfeatures, "Vol state", "Enabled anticamp volume %d.", volumeIndex); + // Get interval. + interval = AnticampData[dataindex][Anticamp_Interval]; + + // Validate interval. + if (interval > 0.0) + { + AnticampData[dataindex][Anticamp_Timer] = CreateTimer(interval, Event_VolAnticampTrigger, volumeIndex, TIMER_REPEAT); + LogEvent(_, LogType_Normal, LOG_DEBUG, LogModule_Volfeatures, "Vol state", "Enabled anticamp volume %d.", volumeIndex); + } + else + { + LogEvent(_, LogType_Error, LOG_CORE_EVENTS, LogModule_Volfeatures, "Config Validation", "Warning: Invalid interval %.2f in anticamp volume %d.", interval, volumeIndex); + } } } @@ -119,24 +127,44 @@ VolAnticampEnable(volumeIndex) stock VolAnticampEnableAll() { new Float:interval; + new dataindex; // Loop through all volumes. - for (new dataindex = 0; dataindex < ZR_VOLUMES_MAX; dataindex++) + for (new volumeindex = 0; volumeindex < ZR_VOLUMES_MAX; volumeindex++) { - // Check if in use. - if (AnticampData[dataindex][Anticamp_InUse]) + // Check if unused. + if (!VolInUse(volumeindex)) { - // Start timer if not running. - if (AnticampData[dataindex][Anticamp_Timer] == INVALID_HANDLE) + // Volume not in use, skip it. + continue; + } + + // Check if it's a anticamp volume. + if (VolIsType(volumeindex, VolFeature_Anticamp)) + { + // Get data index. + dataindex = Volumes[volumeindex][Vol_DataIndex]; + + // Kill timer if it exist. + timer = AnticampData[dataindex][Anticamp_Timer]; + if (timer != INVALID_HANDLE) { - // Get interval. - interval = AnticampData[dataindex][Anticamp_Interval]; - - // Validate interval. - if (interval > 0.0) - { - AnticampData[dataindex][Anticamp_Timer] = CreateTimer(interval, Event_VolAnticampTrigger, _, TIMER_REPEAT); - } + KillTimer(timer); + AnticampData[dataindex][Anticamp_Timer] = INVALID_HANDLE; + } + + // Get interval. + interval = AnticampData[dataindex][Anticamp_Interval]; + + // Validate interval. + if (interval > 0.0) + { + AnticampData[dataindex][Anticamp_Timer] = CreateTimer(interval, Event_VolAnticampTrigger, volumeindex, TIMER_REPEAT); + LogEvent(_, LogType_Normal, LOG_DEBUG, LogModule_Volfeatures, "Vol state", "Enabled anticamp volume %d.", volumeIndex); + } + else + { + LogEvent(_, LogType_Error, LOG_CORE_EVENTS, LogModule_Volfeatures, "Config Validation", "Warning: Invalid interval %.2f in anticamp volume %d.", interval, volumeIndex); } } } @@ -242,23 +270,37 @@ VolAnticampInit() /** * Timer callback for anticamp volumes. Applies actions on players in volumes. */ -public Action:Event_VolAnticampTrigger(Handle:timer) +public Action:Event_VolAnticampTrigger(Handle:timer, any:volumeIndex) { // Loop through all players. for (new client = 1; client <= MaxClients; client++) { - // Loop through all volumes. - for (new volumeindex = 0; volumeindex < ZR_VOLUMES_MAX; volumeindex++) + // Validate client's connection state. + if (!IsClientConnected(client) || !IsClientInGame(client) || !IsPlayerAlive(client)) { - // Check if the volume is enabled and in use. - if (VolIsEnabled(volumeindex) && VolInUse(volumeindex)) + continue; + } + + // Check if the volume is unused. + if (!VolInUse(volumeIndex)) + { + continue; + } + + // Check if the volume is disabled. + if (!VolIsEnabled(volumeIndex)) + { + continue; + } + + // Check if it's a anticamp volume. + if (VolIsType(volumeIndex, VolFeature_Anticamp)) + { + // Check if player is in the volume. + if (VolPlayerInVolume[client][volumeIndex]) { - // Check if player is in a anticamp volume. - if (VolPlayerInVolume[client][volumeindex] && Volumes[volumeindex][Vol_Type] == VolFeature_Anticamp) - { - // Apply action. - VolAnticampApplyAction(client, Volumes[volumeindex][Vol_DataIndex], volumeindex); - } + // Apply action. + VolAnticampApplyAction(client, Volumes[volumeIndex][Vol_DataIndex], volumeIndex); } } } @@ -275,6 +317,13 @@ VolAnticampApplyAction(client, dataIndex, volumeIndex) { new Float:amount = AnticampData[dataIndex][Anticamp_Amount]; + // Set client language. + SetGlobalTransTarget(client); + + // Get player name. + decl String:name[64]; + GetClientName(client, name, sizeof(name)); + // Send warning message. VolAnticampWarnPlayer(client, dataIndex); @@ -286,11 +335,9 @@ VolAnticampApplyAction(client, dataIndex, volumeIndex) } case Anticamp_Damage: { - // Give damage to player. Kill if zero HP. + // Give damage to player. Kill if zero HP or below. new damage = RoundToNearest(amount); new health = GetClientHealth(client) - damage; - decl String:name[64]; - decl String:buffer[256]; if (health > 0) { @@ -302,29 +349,32 @@ VolAnticampApplyAction(client, dataIndex, volumeIndex) ForcePlayerSuicide(client); // Log event. - GetClientName(client, name, sizeof(name)); - SetGlobalTransTarget(client); - Format(buffer, sizeof(buffer), "%t", "Vol Slay", name, volumeIndex); - - /*if (LogFlagCheck(LOG_GAME_EVENTS, LOG_MODULE_ANTICAMP)) ZR_LogMessageFormatted(client, "anticamp", "kill", "%s", true, buffer); - if (anticamp_echo) - { - FormatTextString(buffer, sizeof(buffer)); - ZR_PrintToAdminChat(buffer); - }*/ + LogEvent(false, LogType_Normal, LOG_GAME_EVENTS, LogModule_Volfeatures, "Anti-camp", "%t", "Vol Slay", name, volumeIndex); } } case Anticamp_Slay: { + // Instantly kill the player. + ForcePlayerSuicide(client); + // Log event. + LogEvent(false, LogType_Normal, LOG_GAME_EVENTS, LogModule_Volfeatures, "Anti-camp", "%t", "Vol Slay", name, volumeIndex); } case Anticamp_Drug: { - + // TODO: Trigger sm_drug on client some how. } case Anticamp_Ignite: { - + // Validate amount. + if (amount > 0.0) + { + // Ignite player for "amount" seconds. + IgniteEntity(client, amount); + + // Log event. + LogEvent(false, LogType_Normal, LOG_GAME_EVENTS, LogModule_Volfeatures, "Anti-camp", "%t", "Vol Ignite", name, volumeIndex); + } } } } @@ -351,7 +401,7 @@ VolAnticampWarnPlayer(client, dataIndex) } else { - // Use message in translations file. + // Use default anticamp message in translations file. Format(buffer, sizeof(buffer), "%t", "Vol Anticamp Message"); } @@ -415,6 +465,10 @@ VolAnticampGetFreeIndex() // Check if it's free. if (!AnticampData[dataindex][Anticamp_InUse]) { + // Mark as in use. + AnticampData[dataindex][Anticamp_InUse] = true; + + // Return the new index. return dataindex; } } diff --git a/src/zr/volfeatures/volcommands.inc b/src/zr/volfeatures/volcommands.inc index 4488ba8..9e1c535 100644 --- a/src/zr/volfeatures/volcommands.inc +++ b/src/zr/volfeatures/volcommands.inc @@ -223,7 +223,6 @@ public Action:VolAddVolumeCommand(client, argc) // Set attributes. paramcount = VolSetAttributes(volindex, params); - LogEvent(_, LogType_Normal, LOG_DEBUG, LogModule_Volfeatures, "Add volume", "Parsing parameter string. Param count = \"%d\". String = \"%s\"", paramcount, params); } else { @@ -240,6 +239,9 @@ public Action:VolAddVolumeCommand(client, argc) Format(buffer, sizeof(buffer), "Additional attributes set: %d", paramcount); } + // Send enable event to volume. + VolOnEnabled(volindex); + ReplyToCommand(client, "Added volume at index %d. %s", volindex, buffer); return Plugin_Handled; } diff --git a/src/zr/volfeatures/volevents.inc b/src/zr/volfeatures/volevents.inc index 33f1398..eed16d2 100644 --- a/src/zr/volfeatures/volevents.inc +++ b/src/zr/volfeatures/volevents.inc @@ -85,6 +85,38 @@ VolOnPlayerSpawn(client) VolUpdatePlayerLocation(client); } +/** + * Called when a player died. + * + * @param client The client index. + */ +VolOnPlayerDeath(client) +{ + // Send player left volume event to all volumes the player was in. + for (new volindex = 0; volindex < ZR_VOLUMES_MAX; volindex++) + { + // Check if volume is unused. + if (!Volumes[volindex][Vol_InUse]) + { + continue; + } + + // Check if volume is disabled. + if (!Volumes[volindex][Vol_Enabled]) + { + continue; + } + + // Check if player is inside the volume. + if (VolPlayerInVolume[client][volindex]) + { + // Mark as not in the volume and trigger event. + VolPlayerInVolume[client][volindex] = false; + VolOnPlayerLeave(client, volindex); + } + } +} + /** * Called when a player disconnects. * @@ -94,6 +126,9 @@ VolOnPlayerDisconnect(client) { // Disable trigger delay counters. VolResetCountDown(client); + + // Trigger death event to clean up. + VolOnPlayerDeath(client); } /** @@ -133,6 +168,13 @@ VolOnRoundEnd() */ VolOnDisabled(volumeIndex) { + // Check if volumetric features is enabled. + if (!VolEnabled) + { + // Volumetric features disabled. + return; + } + new VolumeFeatureTypes:voltype = Volumes[volumeIndex][Vol_Type]; // Forward stop event to features. @@ -151,6 +193,13 @@ VolOnDisabled(volumeIndex) */ VolOnEnabled(volumeIndex) { + // Check if volumetric features is enabled. + if (!VolEnabled) + { + // Volumetric features disabled. + return; + } + new VolumeFeatureTypes:voltype = Volumes[volumeIndex][Vol_Type]; // Forward stop event to features. diff --git a/src/zr/volfeatures/volfeatures.inc b/src/zr/volfeatures/volfeatures.inc index 1f67dfd..9f13f83 100644 --- a/src/zr/volfeatures/volfeatures.inc +++ b/src/zr/volfeatures/volfeatures.inc @@ -195,6 +195,28 @@ VolDisableVolumes() { if (Volumes[volindex][Vol_InUse] && Volumes[volindex][Vol_Enabled]) { + // Mark as disabled. + Volumes[volindex][Vol_Enabled] = false; + + // Trigger player left volume event if inside a volume. + for (new client = 1; client <= MaxClients; client++) + { + // Validate client's connection state. + if (!IsClientConnected(client) || !IsClientInGame(client)) + { + continue; + } + + // Check if player is inside the volume. + if (VolPlayerInVolume[client][volindex]) + { + // Mark as not in the volume and trigger event. + VolPlayerInVolume[client][volindex] = false; + VolOnPlayerLeave(client, volindex); + } + } + + // Trigger disabled event. VolOnDisabled(volindex); } } @@ -210,6 +232,7 @@ VolEnableVolumes() { if (Volumes[volindex][Vol_InUse] && !Volumes[volindex][Vol_Enabled]) { + Volumes[volindex][Vol_Enabled] = true; VolOnEnabled(volindex); } } @@ -367,10 +390,10 @@ VolUpdatePlayerLocation(client = -1) { for (client = 1; client <= MaxClients; client++) { - // Check if client is in game and alive. + // Validate client's connection state. if (!IsClientConnected(client) || !IsClientInGame(client) || !IsPlayerAlive(client)) { - return; + continue; } // Save location in array. @@ -396,7 +419,7 @@ VolUpdatePlayerChanges() // Loop through all players. for (new client = 1; client <= MaxClients; client++) { - // Check if client is in game and alive. + // Validate client's connection state. if (!IsClientConnected(client) || !IsClientInGame(client) || !IsPlayerAlive(client)) { // Skip client. @@ -467,11 +490,17 @@ VolUpdatePlayerChanges() // Make sure count down value is reset. VolPlayerCountDown[client][volumeIndex] = -1.0; - // Update cache. - VolPlayerInVolume[client][volumeIndex] = false; - - // Trigger event. - VolOnPlayerLeave(client, volumeIndex); + // Only trigger left volume event if player already is in the + // volume, so volumes with trigger delay won't get a left event + // before the enter event. + if (VolPlayerInVolume[client][volumeIndex]) + { + // Update cache. + VolPlayerInVolume[client][volumeIndex] = false; + + // Trigger event. + VolOnPlayerLeave(client, volumeIndex); + } } } } @@ -641,6 +670,18 @@ bool:VolTeamFilterMatch(client, volumeIndex) return false; } +/** + * Checs if a volume is a certain type. + * + * @param volumeIndex Volume to check. + * @param volType Type to match. + * @return True if the types match, false otherwise. + */ +bool:VolIsType(volumeIndex, VolumeFeatureTypes:volType) +{ + return Volumes[volumeIndex][Vol_Type] == volType; +} + /** * Gets wether a client is within volumes or not. Result is stored in a boolean * array.