/* * ============================================================================ * * Zombie:Reloaded * * File: volclassedit.inc * Type: Module * Description: Class editor volumetric feature. * * Copyright (C) 2009-2013 Greyscale, Richard Helgeby * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * ============================================================================ */ #define VOL_CLASSNAME_SIZE 64 /** * Empty attribute structure with all settings set to be ignored. */ new VolEmptyAttributes[ClassEditableAttributes] = { -1, /** ModelSkinIndex */ -1, /** AlphaInitial */ -1, /** AlphaDamaged */ -1, /** AlphaDamage */ "nochange", /** OverlayPath */ -1, /** Nvgs */ -1, /** Fov */ -1, /** HasNapalm */ -1.0, /** NapalmTime */ Immunity_Invalid, /** ImmunityMode */ -1, /** ImmunityAmount */ -1, /** ImmunityCooldown */ -1, /** NoFallDamage */ -1.0, /** RegenInterval */ -1, /** RegenAmount */ -1, /** InfectGain */ -1, /** KillBonus */ -1.0, /** Speed */ ZR_CLASS_KNOCKBACK_IGNORE, /** KnockBack */ -1.0, /** JumpHeight */ -1.0, /** JumpDistance */ }; /** * List of class edit modes. */ enum VolClassEditMode { ClassEditMode_Name, /** Change whole player class. */ ClassEditMode_Attributes /** Override class attributes. */ } /** * Data structure for class editor. */ enum VolTypeClassEdit { bool:VolClassEdit_InUse, VolClassEditMode:VolClassEdit_Mode, String:VolClassEdit_ClassName[VOL_CLASSNAME_SIZE], VolClassEdit_ClassData[ClassEditableAttributes] } /** * Class editor data. */ new VolClassEditData[ZR_VOLUMES_MAX][VolTypeClassEdit]; /** * The player's selected class index. Used by volumes in "name" mode. */ new VolClassEditSelectedClass[MAXPLAYERS + 1]; /** * Checks if the specified index is in use. * * @param dataIndex Index to check. * @return True if in use, false otherwise. */ bool:VolClassEditInUse(dataIndex) { return VolClassEditData[dataIndex][VolClassEdit_InUse]; } /** * Gets the first free data index. * * @return Data index or -1 if failed. */ VolClassEditGetFreeIndex() { // Loop through all indexes. for (new dataindex = 0; dataindex < ZR_VOLUMES_MAX; dataindex++) { // Check if unused. if (!VolClassEditInUse(dataindex)) { // Mark as in use. VolClassEditData[dataindex][VolClassEdit_InUse] = true; // Unused index found. return dataindex; } } // Unused index not found. return -1; } VolClassEditReset(dataIndex) { VolClassEditData[dataIndex][VolClassEdit_InUse] = false; VolClassEditData[dataIndex][VolClassEdit_Mode] = ClassEditMode_Attributes; strcopy(VolClassEditData[dataIndex][VolClassEdit_ClassName], 64, ""); VolClassEditData[dataIndex][VolClassEdit_ClassData] = VolEmptyAttributes; } /** * Initialize class editor. */ VolClassEditInit() { for (new dataindex = 0; dataindex < ZR_VOLUMES_MAX; dataindex++) { VolClassEditReset(dataindex); } } /** * Sets class editor spesific attributes on a anticamp volume. * * @param dataIndex Local data index. * @param attribName Attribute to modify. * @param attribVlue Attribute value to set. * @return True if successfully set, false otherwise. */ VolClassEditSetAttribute(dataIndex, const String:attribName[], const String:attribValue[]) { // Validate index. if (!VolIsValidIndex(dataIndex)) { return false; } /* Class Editor Attributes */ if (StrEqual(attribName, "mode", false)) { if (VolClassEditSetMode(dataIndex, attribValue)) { return true; } } else if (StrEqual(attribName, "name", false)) { if (VolClassEditSetName(dataIndex, attribValue)) { return true; } } /* Model */ else if (StrEqual(attribName, "alpha_initial", false)) { if (VolClassEditSetAlphaInitial(dataIndex, attribValue)) { return true; } } else if (StrEqual(attribName, "alpha_damaged", false)) { if (VolClassEditSetAlphaDamaged(dataIndex, attribValue)) { return true; } } else if (StrEqual(attribName, "alpha_damage", false)) { if (VolClassEditSetAlphaDamage(dataIndex, attribValue)) { return true; } } /* Hud */ else if (StrEqual(attribName, "overlay_path", false)) { if (VolClassEditSetOverlayPath(dataIndex, attribValue)) { return true; } } else if (StrEqual(attribName, "nvgs", false)) { if (VolClassEditSetNvgs(dataIndex, attribValue)) { return true; } } else if (StrEqual(attribName, "fov", false)) { if (VolClassEditSetFov(dataIndex, attribValue)) { return true; } } /* Effects */ else if (StrEqual(attribName, "has_napalm", false)) { if (VolClassEditSetHasNapalm(dataIndex, attribValue)) { return true; } } else if (StrEqual(attribName, "napalm_time", false)) { if (VolClassEditSetNapalmTime(dataIndex, attribValue)) { return true; } } /* Player behavior */ else if (StrEqual(attribName, "immunity_mode", false)) { if (VolClassEditSetImmunityMode(dataIndex, attribValue)) { return true; } } else if (StrEqual(attribName, "immunity_amount", false)) { if (VolClassEditSetImmunityAmount(dataIndex, attribValue)) { return true; } } else if (StrEqual(attribName, "immunity_cooldown", false)) { if (VolClassEditSetImmunityCooldown(dataIndex, attribValue)) { return true; } } else if (StrEqual(attribName, "no_fall_damage", false)) { if (VolClassEditSetNoFallDamage(dataIndex, attribValue)) { return true; } } else if (StrEqual(attribName, "health_regen_interval", false)) { if (VolClassEditSetRegenInterval(dataIndex, attribValue)) { return true; } } else if (StrEqual(attribName, "health_regen_amount", false)) { if (VolClassEditSetRegenAmount(dataIndex, attribValue)) { return true; } } else if (StrEqual(attribName, "infect_gain", false)) { if (VolClassEditSetInfectGain(dataIndex, attribValue)) { return true; } } else if (StrEqual(attribName, "kill_bonus", false)) { if (VolClassEditSetKillBonus(dataIndex, attribValue)) { return true; } } else if (StrEqual(attribName, "speed", false)) { if (VolClassEditSetSpeed(dataIndex, attribValue)) { return true; } } else if (StrEqual(attribName, "knockback", false)) { if (VolClassEditSetKnockBack(dataIndex, attribValue)) { return true; } } else if (StrEqual(attribName, "jump_height", false)) { if (VolClassEditSetJumpHeight(dataIndex, attribValue)) { return true; } } else if (StrEqual(attribName, "jump_distance", false)) { if (VolClassEditSetJumpDistance(dataIndex, attribValue)) { return true; } } // Invalid attribute name or empty value. return false; } /** * Dumps data to be used by zr_vol_list command. * * @param dataIndex Index in anticamp data array. * @param buffer Destination string buffer. * @param maxlen Size of destination buffer. * @return Number of cells written. */ VolClassEditDumpData(dataIndex, String:buffer[], maxlen) { #define CLASSEDIT_DUMP_FORMAT "%-19s %s\n" decl String:linebuffer[128]; decl String:valuebuffer[256]; new cache[VolTypeClassEdit]; new cellswritten; // Validate index. if (!VolIsValidIndex(dataIndex)) { return 0; } // Initialize and clear buffer. buffer[0] = 0; // Cache data. cache = VolClassEditData[dataIndex]; VolClassEditModeToString(cache[VolClassEdit_Mode], valuebuffer, sizeof(valuebuffer)); Format(linebuffer, sizeof(linebuffer), CLASSEDIT_DUMP_FORMAT, "Mode:", valuebuffer); cellswritten += StrCat(buffer, maxlen, linebuffer); switch (cache[VolClassEdit_Mode]) { case ClassEditMode_Name: { Format(linebuffer, sizeof(linebuffer), CLASSEDIT_DUMP_FORMAT, "Class Name:", cache[VolClassEdit_ClassName]); cellswritten += StrCat(buffer, maxlen, linebuffer); } case ClassEditMode_Attributes: { VolClassEditIntToString(dataIndex, ClassEdit_AlphaInitial, valuebuffer, sizeof(valuebuffer)); Format(linebuffer, sizeof(linebuffer), CLASSEDIT_DUMP_FORMAT, "Alpha initial:", valuebuffer); cellswritten += StrCat(buffer, maxlen, linebuffer); VolClassEditIntToString(dataIndex, ClassEdit_AlphaDamaged, valuebuffer, sizeof(valuebuffer)); Format(linebuffer, sizeof(linebuffer), CLASSEDIT_DUMP_FORMAT, "Alpha damaged:", valuebuffer); cellswritten += StrCat(buffer, maxlen, linebuffer); VolClassEditIntToString(dataIndex, ClassEdit_AlphaDamage, valuebuffer, sizeof(valuebuffer)); Format(linebuffer, sizeof(linebuffer), CLASSEDIT_DUMP_FORMAT, "Alpha damage:", valuebuffer); cellswritten += StrCat(buffer, maxlen, linebuffer); VolClassEditStringToHumanStr(dataIndex, ClassEdit_OverlayPath, valuebuffer, sizeof(valuebuffer)); Format(linebuffer, sizeof(linebuffer), CLASSEDIT_DUMP_FORMAT, "Overlay path:", valuebuffer); cellswritten += StrCat(buffer, maxlen, linebuffer); VolClassEditIntToString(dataIndex, ClassEdit_Nvgs, valuebuffer, sizeof(valuebuffer)); Format(linebuffer, sizeof(linebuffer), CLASSEDIT_DUMP_FORMAT, "NVGs:", valuebuffer); cellswritten += StrCat(buffer, maxlen, linebuffer); VolClassEditIntToString(dataIndex, ClassEdit_Fov, valuebuffer, sizeof(valuebuffer)); Format(linebuffer, sizeof(linebuffer), CLASSEDIT_DUMP_FORMAT, "FOV:", valuebuffer); cellswritten += StrCat(buffer, maxlen, linebuffer); VolClassEditIntToString(dataIndex, ClassEdit_HasNapalm, valuebuffer, sizeof(valuebuffer)); Format(linebuffer, sizeof(linebuffer), CLASSEDIT_DUMP_FORMAT, "Has napalm:", valuebuffer); cellswritten += StrCat(buffer, maxlen, linebuffer); VolClassEditFloatToString(dataIndex, ClassEdit_NapalmTime, valuebuffer, sizeof(valuebuffer)); Format(linebuffer, sizeof(linebuffer), CLASSEDIT_DUMP_FORMAT, "Napalm time:", valuebuffer); cellswritten += StrCat(buffer, maxlen, linebuffer); ImmunityModeToString(VolClassEditData[dataIndex][ClassEdit_ImmunityMode], valuebuffer, sizeof(valuebuffer)); Format(linebuffer, sizeof(linebuffer), CLASSEDIT_DUMP_FORMAT, "Immunity mode:", valuebuffer); cellswritten += StrCat(buffer, maxlen, linebuffer); VolClassEditIntToString(dataIndex, ClassEdit_ImmunityAmount, valuebuffer, sizeof(valuebuffer)); Format(linebuffer, sizeof(linebuffer), CLASSEDIT_DUMP_FORMAT, "Immunity amount:", valuebuffer); cellswritten += StrCat(buffer, maxlen, linebuffer); VolClassEditIntToString(dataIndex, ClassEdit_ImmunityCooldown, valuebuffer, sizeof(valuebuffer)); Format(linebuffer, sizeof(linebuffer), CLASSEDIT_DUMP_FORMAT, "Immunity cooldown:", valuebuffer); cellswritten += StrCat(buffer, maxlen, linebuffer); VolClassEditIntToString(dataIndex, ClassEdit_NoFallDamage, valuebuffer, sizeof(valuebuffer)); Format(linebuffer, sizeof(linebuffer), CLASSEDIT_DUMP_FORMAT, "No fall damage:", valuebuffer); cellswritten += StrCat(buffer, maxlen, linebuffer); VolClassEditFloatToString(dataIndex, ClassEdit_RegenInterval, valuebuffer, sizeof(valuebuffer)); Format(linebuffer, sizeof(linebuffer), CLASSEDIT_DUMP_FORMAT, "Regen interval:", valuebuffer); cellswritten += StrCat(buffer, maxlen, linebuffer); VolClassEditIntToString(dataIndex, ClassEdit_RegenAmount, valuebuffer, sizeof(valuebuffer)); Format(linebuffer, sizeof(linebuffer), CLASSEDIT_DUMP_FORMAT, "Regen amount:", valuebuffer); cellswritten += StrCat(buffer, maxlen, linebuffer); VolClassEditIntToString(dataIndex, ClassEdit_InfectGain, valuebuffer, sizeof(valuebuffer)); Format(linebuffer, sizeof(linebuffer), CLASSEDIT_DUMP_FORMAT, "Infect gain:", valuebuffer); cellswritten += StrCat(buffer, maxlen, linebuffer); VolClassEditIntToString(dataIndex, ClassEdit_KillBonus, valuebuffer, sizeof(valuebuffer)); Format(linebuffer, sizeof(linebuffer), CLASSEDIT_DUMP_FORMAT, "Kill bonus:", valuebuffer); cellswritten += StrCat(buffer, maxlen, linebuffer); VolClassEditFloatToString(dataIndex, ClassEdit_Speed, valuebuffer, sizeof(valuebuffer)); Format(linebuffer, sizeof(linebuffer), CLASSEDIT_DUMP_FORMAT, "Speed:", valuebuffer); cellswritten += StrCat(buffer, maxlen, linebuffer); VolClassEditFloatToString(dataIndex, ClassEdit_KnockBack, valuebuffer, sizeof(valuebuffer), ZR_CLASS_KNOCKBACK_IGNORE); Format(linebuffer, sizeof(linebuffer), CLASSEDIT_DUMP_FORMAT, "Knock back:", valuebuffer); cellswritten += StrCat(buffer, maxlen, linebuffer); VolClassEditFloatToString(dataIndex, ClassEdit_JumpHeight, valuebuffer, sizeof(valuebuffer)); Format(linebuffer, sizeof(linebuffer), CLASSEDIT_DUMP_FORMAT, "Jump height:", valuebuffer); cellswritten += StrCat(buffer, maxlen, linebuffer); VolClassEditFloatToString(dataIndex, ClassEdit_JumpDistance, valuebuffer, sizeof(valuebuffer)); Format(linebuffer, sizeof(linebuffer), CLASSEDIT_DUMP_FORMAT, "Jump distance:", valuebuffer); cellswritten += StrCat(buffer, maxlen, linebuffer); } } return cellswritten; } /************************************** * * * EVENTS * * * **************************************/ /** * Applies new class attributes to the player. * * @param client The client index. * @param dataIndex Local data index. */ VolClassEditApply(client, dataIndex) { switch (VolClassEditData[dataIndex][VolClassEdit_Mode]) { case ClassEditMode_Name: { // Cache volume attributes. new classindex = ClassGetIndex(VolClassEditData[dataIndex][VolClassEdit_ClassName]); // Save player's selected class. VolClassEditSelectedClass[client] = ClassGetActiveIndex(client); // Update cache with new attributes. ClassReloadPlayerCache(client, classindex); } case ClassEditMode_Attributes: { // Update player's entire cache with attributes from the specified // class attributes. VolClassEditUpdateAttributes(client, VolClassEditData[dataIndex][VolClassEdit_ClassData]); } } LogEvent(_, LogType_Normal, LOG_DEBUG, LogModule_Volfeatures, "ClassEdit", "Applied class data on client %d.", client); // Apply the updated attributes. ClassApplyAttributes(client); } /** * Restores the player's regular class attributes (from modified cache). * * @param client The client index. */ VolClassEditRestore(client, dataIndex) { new classindex = ClassGetActiveIndex(client); switch (VolClassEditData[dataIndex][VolClassEdit_Mode]) { case ClassEditMode_Name: { // Restore player's entire cache with attributes from the selected // class. ClassReloadPlayerCache(client, VolClassEditSelectedClass[client]); } case ClassEditMode_Attributes: { // Restore individual attributes, if specified. VolClassEditRestoreAttributes(client, classindex, VolClassEditData[dataIndex][VolClassEdit_ClassData]); } } // Apply the restored attributes. if (ClassApplyAttributes(client)) { LogEvent(_, LogType_Normal, LOG_DEBUG, LogModule_Volfeatures, "ClassEdit", "Restored class data on client %d.", client); } } /** * Event callback. A player entered a class edit volume. * * @param client The client index. * @param volumeIndex The volume index. */ VolClassEditOnPlayerEnter(client, volumeIndex) { VolClassEditApply(client, Volumes[volumeIndex][Vol_DataIndex]); } /** * Event callback. A player left a class edit volume. * * @param client The client index. * @param volumeIndex The volume index. */ VolClassEditOnPlayerLeave(client, volumeIndex) { VolClassEditRestore(client, Volumes[volumeIndex][Vol_DataIndex]); } /** * Event callback. A class edit volume was enabled. * * @param volumeIndex The volume index. */ /*VolClassEditOnEnabled(volumeIndex) { }*/ /** * Event callback. A class edit volume was enabled. * * @param volumeIndex The volume index. */ VolClassEditOnDisabled(volumeIndex) { for (new client = 1; client < MaxClients; client++) { if (IsClientConnected(client) && IsClientInGame(client)) { // Only forward event if the player really is in the volume.. if (VolPlayerInVolume[client][volumeIndex] && VolClassEditSelectedClass[client] >= 0) { VolClassEditOnPlayerLeave(client, volumeIndex); } } } } /************************************** * * * ATTRIBUTE FUNCTIONS * * * **************************************/ /** * Converts the specified mode to a string. * * @param mode Mode to convert. * @param buffer Destination string buffer. * @param maxlen Size of buffer. * @return Number of cells written. */ VolClassEditModeToString(VolClassEditMode:mode, String:buffer[], maxlen) { switch (mode) { case ClassEditMode_Name: { return strcopy(buffer, maxlen, "Name"); } case ClassEditMode_Attributes: { return strcopy(buffer, maxlen, "Attributes"); } } return 0; } /** * Gets a integer attribute and converts it to a human readable string. * * Note: attribute is assumed to be a integer (cell) and is not type cheked! * * @param dataIndex Local data index. * @param attribute Attribute to convert. * @param buffer Destination string buffer. * @param maxlen Size of destination buffer. */ VolClassEditIntToString(dataIndex, ClassEditableAttributes:attribute, String:buffer[], maxlen) { new intVal; new String:strVal[8]; intVal = VolClassEditData[dataIndex][VolClassEdit_ClassData][attribute]; // Check if the attribute is marked as ignored. if (intVal == -1) { return strcopy(buffer, maxlen, "(no change)"); } else { IntToString(intVal, strVal, sizeof(strVal)); return strcopy(buffer, maxlen, strVal); } } /** * Gets a float attribute and converts it to a human readable string. * * Note: attribute is assumed to be a float and is not type cheked! * * @param dataIndex Local data index. * @param attribute Attribute to convert. * @param buffer Destination string buffer. * @param maxlen Size of destination buffer. */ VolClassEditFloatToString(dataIndex, ClassEditableAttributes:attribute, String:buffer[], maxlen, Float:minval = -1.0) { new Float:floatVal; new String:strVal[8]; floatVal = Float:VolClassEditData[dataIndex][VolClassEdit_ClassData][attribute]; // Check if the attribute is marked as ignored. if (floatVal == minval) { return strcopy(buffer, maxlen, "(no change)"); } else { FloatToString(floatVal, strVal, sizeof(strVal)); return strcopy(buffer, maxlen, strVal); } } /** * Gets a string attribute and converts it to a human readable string. * * Note: attribute is assumed to be a string and is not type cheked! * * @param dataIndex Local data index. * @param attribute Attribute to convert. * @param buffer Destination string buffer. * @param maxlen Size of destination buffer. */ VolClassEditStringToHumanStr(dataIndex, ClassEditableAttributes:attribute, String:buffer[], maxlen) { decl String:strVal[PLATFORM_MAX_PATH]; strcopy(strVal, sizeof(strVal), String:VolClassEditData[dataIndex][VolClassEdit_ClassData][attribute]); // Check if the attribute is marked as ignored. if (StrEqual(strVal, "nochange", false)) { return strcopy(buffer, maxlen, "(no change)"); } else { return strcopy(buffer, maxlen, strVal); } } /** * Sets the mode attribute. * * @param dataIndex Local data index. * @param value String value to set (converted to proper type by this * function). * @return True if set, false if empty. */ bool:VolClassEditSetMode(dataIndex, const String:value[]) { if (strlen(value) == 0) { return false; } if (StrEqual(value, "name", false)) { VolClassEditData[dataIndex][VolClassEdit_Mode] = ClassEditMode_Name; return true; } else if (StrEqual(value, "attributes", false)) { VolClassEditData[dataIndex][VolClassEdit_Mode] = ClassEditMode_Attributes; return true; } // No match. return false; } /** * Sets the class name attribute (name of the class to switch to). * * @param dataIndex Local data index. * @param value String value to set (converted to proper type by this * function). * @return True if set, false if empty. */ bool:VolClassEditSetName(dataIndex, const String:value[]) { if (strlen(value) == 0) { return false; } strcopy(VolClassEditData[dataIndex][VolClassEdit_ClassName], VOL_CLASSNAME_SIZE, value); // TODO: Validate name. return true; } /** * Sets the alpha initial attribute. * * Note: The value is not validated! * * @param dataIndex Local data index. * @param value String value to set (converted to proper type by this * function). * @return True if set, false if empty. */ bool:VolClassEditSetAlphaInitial(dataIndex, const String:value[]) { if (strlen(value) == 0) { return false; } VolClassEditData[dataIndex][VolClassEdit_ClassData][ClassEdit_AlphaInitial] = StringToInt(value); return true; } /** * Sets the alpha damaged attribute. * * Note: The value is not validated! * * @param dataIndex Local data index. * @param value String value to set (converted to proper type by this * function). * @return True if set, false if empty. */ bool:VolClassEditSetAlphaDamaged(dataIndex, const String:value[]) { if (strlen(value) == 0) { return false; } VolClassEditData[dataIndex][VolClassEdit_ClassData][ClassEdit_AlphaDamaged] = StringToInt(value); return true; } /** * Sets the alpha damage attribute. * * Note: The value is not validated! * * @param dataIndex Local data index. * @param value String value to set (converted to proper type by this * function). * @return True if set, false if empty. */ bool:VolClassEditSetAlphaDamage(dataIndex, const String:value[]) { if (strlen(value) == 0) { return false; } VolClassEditData[dataIndex][VolClassEdit_ClassData][ClassEdit_AlphaDamage] = StringToInt(value); return true; } /** * Sets the overlay path attribute. * * Note: The value is not validated! * * @param dataIndex Local data index. * @param value String value to set (converted to proper type by this * function). * @return True if set, false if empty. */ bool:VolClassEditSetOverlayPath(dataIndex, const String:value[]) { if (strlen(value) == 0) { return false; } strcopy(VolClassEditData[dataIndex][VolClassEdit_ClassData][ClassEdit_OverlayPath], PLATFORM_MAX_PATH, value); return true; } /** * Sets the nvgs attribute. * * Note: The value is not validated! * * @param dataIndex Local data index. * @param value String value to set (converted to proper type by this * function). * @return True if set, false if empty. */ bool:VolClassEditSetNvgs(dataIndex, const String:value[]) { if (strlen(value) == 0) { return false; } VolClassEditData[dataIndex][VolClassEdit_ClassData][ClassEdit_Nvgs] = StringToInt(value); return true; } /** * Sets the fov attribute. * * Note: The value is not validated! * * @param dataIndex Local data index. * @param value String value to set (converted to proper type by this * function). * @return True if set, false if empty. */ bool:VolClassEditSetFov(dataIndex, const String:value[]) { if (strlen(value) == 0) { return false; } VolClassEditData[dataIndex][VolClassEdit_ClassData][ClassEdit_Fov] = StringToInt(value); return true; } /** * Sets the has napalm attribute. * * Note: The value is not validated! * * @param dataIndex Local data index. * @param value String value to set (converted to proper type by this * function). * @return True if set, false if empty. */ bool:VolClassEditSetHasNapalm(dataIndex, const String:value[]) { if (strlen(value) == 0) { return false; } VolClassEditData[dataIndex][VolClassEdit_ClassData][ClassEdit_HasNapalm] = StringToInt(value); return true; } /** * Sets the napalm time attribute. * * Note: The value is not validated! * * @param dataIndex Local data index. * @param value String value to set (converted to proper type by this * function). * @return True if set, false if empty. */ bool:VolClassEditSetNapalmTime(dataIndex, const String:value[]) { if (strlen(value) == 0) { return false; } VolClassEditData[dataIndex][VolClassEdit_ClassData][ClassEdit_NapalmTime] = StringToFloat(value); return true; } /** * Sets the immunity mode attribute. * * Note: The value is not validated! * * @param dataIndex Local data index. * @param value String value to set (converted to proper type by this * function). * @return True if set, false if empty. */ bool:VolClassEditSetImmunityMode(dataIndex, const String:value[]) { if (strlen(value) == 0) { return false; } new ImmunityMode:mode = ImmunityStringToMode(value); VolClassEditData[dataIndex][VolClassEdit_ClassData][ClassEdit_ImmunityMode] = mode; return true; } /** * Sets the immunity amount attribute. * * Note: The value is not validated! * * @param dataIndex Local data index. * @param value String value to set (converted to proper type by this * function). * @return True if set, false if empty. */ bool:VolClassEditSetImmunityAmount(dataIndex, const String:value[]) { if (strlen(value) == 0) { return false; } VolClassEditData[dataIndex][VolClassEdit_ClassData][ClassEdit_ImmunityAmount] = StringToInt(value); return true; } /** * Sets the immunity cooldown attribute. * * Note: The value is not validated! * * @param dataIndex Local data index. * @param value String value to set (converted to proper type by this * function). * @return True if set, false if empty. */ bool:VolClassEditSetImmunityCooldown(dataIndex, const String:value[]) { if (strlen(value) == 0) { return false; } VolClassEditData[dataIndex][VolClassEdit_ClassData][ClassEdit_ImmunityCooldown] = StringToInt(value); return true; } /** * Sets the no fall damage attribute. * * Note: The value is not validated! * * @param dataIndex Local data index. * @param value String value to set (converted to proper type by this * function). * @return True if set, false if empty. */ bool:VolClassEditSetNoFallDamage(dataIndex, const String:value[]) { if (strlen(value) == 0) { return false; } VolClassEditData[dataIndex][VolClassEdit_ClassData][ClassEdit_NoFallDamage] = StringToInt(value); return true; } /** * Sets the health regen interval attribute. * * Note: The value is not validated! * * @param dataIndex Local data index. * @param value String value to set (converted to proper type by this * function). * @return True if set, false if empty. */ bool:VolClassEditSetRegenInterval(dataIndex, const String:value[]) { if (strlen(value) == 0) { return false; } VolClassEditData[dataIndex][VolClassEdit_ClassData][ClassEdit_RegenInterval] = StringToFloat(value); return true; } /** * Sets the health regen amount attribute. * * Note: The value is not validated! * * @param dataIndex Local data index. * @param value String value to set (converted to proper type by this * function). * @return True if set, false if empty. */ bool:VolClassEditSetRegenAmount(dataIndex, const String:value[]) { if (strlen(value) == 0) { return false; } VolClassEditData[dataIndex][VolClassEdit_ClassData][ClassEdit_RegenAmount] = StringToInt(value); return true; } /** * Sets the infect gain attribute. * * Note: The value is not validated! * * @param dataIndex Local data index. * @param value String value to set (converted to proper type by this * function). * @return True if set, false if empty. */ bool:VolClassEditSetInfectGain(dataIndex, const String:value[]) { if (strlen(value) == 0) { return false; } VolClassEditData[dataIndex][VolClassEdit_ClassData][ClassEdit_InfectGain] = StringToInt(value); return true; } /** * Sets the kill bonus attribute. * * Note: The value is not validated! * * @param dataIndex Local data index. * @param value String value to set (converted to proper type by this * function). * @return True if set, false if empty. */ bool:VolClassEditSetKillBonus(dataIndex, const String:value[]) { if (strlen(value) == 0) { return false; } VolClassEditData[dataIndex][VolClassEdit_ClassData][ClassEdit_KillBonus] = StringToInt(value); return true; } /** * Sets the speed attribute. * * Note: The value is not validated! * * @param dataIndex Local data index. * @param value String value to set (converted to proper type by this * function). * @return True if set, false if empty. */ bool:VolClassEditSetSpeed(dataIndex, const String:value[]) { if (strlen(value) == 0) { return false; } VolClassEditData[dataIndex][VolClassEdit_ClassData][ClassEdit_Speed] = StringToFloat(value); return true; } /** * Sets the knock back attribute. * * Note: The value is not validated! * * @param dataIndex Local data index. * @param value String value to set (converted to proper type by this * function). * @return True if set, false if empty. */ bool:VolClassEditSetKnockBack(dataIndex, const String:value[]) { if (strlen(value) == 0) { return false; } VolClassEditData[dataIndex][VolClassEdit_ClassData][ClassEdit_KnockBack] = StringToFloat(value); return true; } /** * Sets the jump heigt attribute. * * Note: The value is not validated! * * @param dataIndex Local data index. * @param value String value to set (converted to proper type by this * function). * @return True if set, false if empty. */ bool:VolClassEditSetJumpHeight(dataIndex, const String:value[]) { if (strlen(value) == 0) { return false; } VolClassEditData[dataIndex][VolClassEdit_ClassData][ClassEdit_JumpHeight] = StringToFloat(value); return true; } /** * Sets the jump distance attribute. * * Note: The value is not validated! * * @param dataIndex Local data index. * @param value String value to set (converted to proper type by this * function). * @return True if set, false if empty. */ bool:VolClassEditSetJumpDistance(dataIndex, const String:value[]) { if (strlen(value) == 0) { return false; } VolClassEditData[dataIndex][VolClassEdit_ClassData][ClassEdit_JumpDistance] = StringToFloat(value); return true; } /** * Updates a player's cache with the specified attribute set. Only active * attributes are applied. * * Note: These attributes are not validated! * * @param client The client index. * @param attributes Attribute set to apply (ClassEditableAttributes) * @return Number of attributes changed. */ VolClassEditUpdateAttributes(client, const attributes[]) { new numChanges; // Alpha initial. if (attributes[ClassEdit_AlphaInitial] > -1) { ClassPlayerCache[client][Class_AlphaInitial] = attributes[ClassEdit_AlphaInitial]; numChanges++; } // Alpha damaged. if (attributes[ClassEdit_AlphaDamaged] > -1) { ClassPlayerCache[client][Class_AlphaDamaged] = attributes[ClassEdit_AlphaDamaged]; numChanges++; } // Alpha damage. if (attributes[ClassEdit_AlphaDamage] > -1) { ClassPlayerCache[client][Class_AlphaDamage] = attributes[ClassEdit_AlphaDamage]; numChanges++; } // Overlay path. if (!StrEqual(attributes[ClassEdit_OverlayPath], "nochange")) { strcopy(ClassPlayerCache[client][Class_OverlayPath], PLATFORM_MAX_PATH, attributes[ClassEdit_OverlayPath]); numChanges++; } // Nvgs. if (attributes[ClassEdit_Nvgs] > -1) { ClassPlayerCache[client][Class_Nvgs] = bool:attributes[ClassEdit_Nvgs]; numChanges++; } // Napalm time. if (attributes[ClassEdit_NapalmTime] > -1.0) { ClassPlayerCache[client][Class_NapalmTime] = attributes[ClassEdit_NapalmTime]; numChanges++; } // Immunity mode. if (attributes[ClassEdit_ImmunityMode] != Immunity_Invalid) { ClassPlayerCache[client][Class_ImmunityMode] = attributes[ClassEdit_ImmunityMode]; numChanges++; } // Immunity amount. if (attributes[ClassEdit_ImmunityAmount] > -1) { ClassPlayerCache[client][Class_ImmunityAmount] = attributes[ClassEdit_ImmunityAmount]; numChanges++; } // Immunity cooldown. if (attributes[ClassEdit_ImmunityCooldown] > -1) { ClassPlayerCache[client][Class_ImmunityCooldown] = attributes[ClassEdit_ImmunityCooldown]; numChanges++; } // No fall damage. if (attributes[ClassEdit_NoFallDamage] > -1) { ClassPlayerCache[client][Class_NoFallDamage] = bool:attributes[ClassEdit_NoFallDamage]; numChanges++; } // Health regen interval. if (attributes[ClassEdit_RegenInterval] > -1.0) { ClassPlayerCache[client][Class_HealthRegenInterval] = attributes[ClassEdit_RegenInterval]; numChanges++; } // Health regen amount. if (attributes[ClassEdit_RegenAmount] > -1) { ClassPlayerCache[client][Class_HealthRegenAmount] = attributes[ClassEdit_RegenAmount]; numChanges++; } // Infect gain. if (attributes[ClassEdit_InfectGain] > -1) { ClassPlayerCache[client][Class_HealthInfectGain] = attributes[ClassEdit_InfectGain]; numChanges++; } // Kill bonus. if (attributes[ClassEdit_KillBonus] > -1) { ClassPlayerCache[client][Class_KillBonus] = attributes[ClassEdit_KillBonus]; numChanges++; } // Speed. if (attributes[ClassEdit_Speed] > -1.0) { ClassPlayerCache[client][Class_Speed] = attributes[ClassEdit_Speed]; numChanges++; } // Knock back. if (attributes[ClassEdit_KnockBack] > ZR_CLASS_KNOCKBACK_IGNORE) { ClassPlayerCache[client][Class_KnockBack] = attributes[ClassEdit_KnockBack]; numChanges++; } // Jump height. if (attributes[ClassEdit_JumpHeight] > -1.0) { ClassPlayerCache[client][Class_JumpHeight] = attributes[ClassEdit_JumpHeight]; numChanges++; } // Jump distance. if (attributes[ClassEdit_JumpDistance] > -1.0) { ClassPlayerCache[client][Class_JumpDistance] = attributes[ClassEdit_JumpDistance]; numChanges++; } LogEvent(_, LogType_Normal, LOG_DEBUG, LogModule_Volfeatures, "ClassEdit", "Applied %d attribute(s).", numChanges); return numChanges; } /** * Restores a player's cache to the original values (from modified cache). A * attribute set is used as a mask to determine what attributes to restore. * * @param client The client index. * @param classindex Index of class to restore. * @param attributes Attribute mask (ClassEditableAttributes). * @return Number of attributes changed. */ VolClassEditRestoreAttributes(client, classindex, const attributes[]) { new numChanges; // Alpha initial. if (attributes[ClassEdit_AlphaInitial] > -1) { ClassPlayerCache[client][Class_AlphaInitial] = ClassGetAlphaInitial(classindex, ZR_CLASS_CACHE_MODIFIED); numChanges++; } // Alpha damaged. if (attributes[ClassEdit_AlphaDamaged] > -1) { ClassPlayerCache[client][Class_AlphaDamaged] = ClassGetAlphaDamaged(classindex, ZR_CLASS_CACHE_MODIFIED); numChanges++; } // Alpha damage. if (attributes[ClassEdit_AlphaDamage] > -1) { ClassPlayerCache[client][Class_AlphaDamage] = ClassGetAlphaDamage(classindex, ZR_CLASS_CACHE_MODIFIED); numChanges++; } // Overlay path. if (!StrEqual(attributes[ClassEdit_OverlayPath], "nochange")) { decl String:path[PLATFORM_MAX_PATH]; ClassGetOverlayPath(classindex, path, sizeof(path), ZR_CLASS_CACHE_MODIFIED); strcopy(ClassPlayerCache[client][Class_OverlayPath], PLATFORM_MAX_PATH, path); numChanges++; } // Nvgs. if (attributes[ClassEdit_Nvgs] > -1) { ClassPlayerCache[client][Class_Nvgs] = ClassGetNvgs(classindex, ZR_CLASS_CACHE_MODIFIED); numChanges++; } // Napalm time. if (attributes[ClassEdit_NapalmTime] > -1.0) { ClassPlayerCache[client][Class_NapalmTime] = ClassGetNapalmTime(classindex, ZR_CLASS_CACHE_MODIFIED); numChanges++; } // Immunity mode. if (attributes[ClassEdit_ImmunityMode] != Immunity_Invalid) { ClassPlayerCache[client][Class_ImmunityMode] = ClassGetImmunityMode(classindex, ZR_CLASS_CACHE_MODIFIED); numChanges++; } // Immunity amount. if (attributes[ClassEdit_ImmunityAmount] > -1.0) { ClassPlayerCache[client][Class_ImmunityAmount] = ClassGetImmunityAmount(classindex, ZR_CLASS_CACHE_MODIFIED); numChanges++; } // No fall damage. if (attributes[ClassEdit_NoFallDamage] > -1) { ClassPlayerCache[client][Class_NoFallDamage] = ClassGetNoFallDamage(classindex, ZR_CLASS_CACHE_MODIFIED); numChanges++; } // Health regen interval. if (attributes[ClassEdit_RegenInterval] > -1.0) { ClassPlayerCache[client][Class_HealthRegenInterval] = ClassGetHealthRegenInterval(classindex, ZR_CLASS_CACHE_MODIFIED); numChanges++; } // Health regen amount. if (attributes[ClassEdit_RegenAmount] > -1) { ClassPlayerCache[client][Class_HealthRegenAmount] = ClassGetHealthRegenAmount(classindex, ZR_CLASS_CACHE_MODIFIED); numChanges++; } // Infect gain. if (attributes[ClassEdit_InfectGain] > -1) { ClassPlayerCache[client][Class_HealthInfectGain] = ClassGetHealthInfectGain(classindex, ZR_CLASS_CACHE_MODIFIED); numChanges++; } // Kill bonus. if (attributes[ClassEdit_KillBonus] > -1) { ClassPlayerCache[client][Class_KillBonus] = ClassGetKillBonus(classindex, ZR_CLASS_CACHE_MODIFIED); numChanges++; } // Speed. if (attributes[ClassEdit_Speed] > -1.0) { ClassPlayerCache[client][Class_Speed] = ClassGetSpeed(classindex, ZR_CLASS_CACHE_MODIFIED); numChanges++; } // Knock back. if (attributes[ClassEdit_KnockBack] > ZR_CLASS_KNOCKBACK_IGNORE) { ClassPlayerCache[client][Class_KnockBack] = ClassGetKnockback(classindex, ZR_CLASS_CACHE_MODIFIED); numChanges++; } // Jump height. if (attributes[ClassEdit_JumpHeight] > -1.0) { ClassPlayerCache[client][Class_JumpHeight] = ClassGetJumpHeight(classindex, ZR_CLASS_CACHE_MODIFIED); numChanges++; } // Jump distance. if (attributes[ClassEdit_JumpDistance] > -1.0) { ClassPlayerCache[client][Class_JumpDistance] = ClassGetJumpDistance(classindex, ZR_CLASS_CACHE_MODIFIED); numChanges++; } LogEvent(_, LogType_Normal, LOG_DEBUG, LogModule_Volfeatures, "ClassEdit", "Applied %d attribute(s).", numChanges); return numChanges; }