#include "colors_inc" #include "inc_helper_funcs" #include "inc_pc_functions" #include "inc_mysql_tables" #include "nwnx_structs" #include "zzdlg_main_inc" // Firearm Upgrade System Include File // Created by Zunath on July 23, 2011 /////////////// // VARIABLES // /////////////// // Name of the script which handles the FUSE menu const string FUS_WORKSHOP_MENU = "fus_menu"; // Keeps track of the firearm object being modified. const string FUS_FIREARM_OBJECT = "FUS_FIREARM_OBJECT"; // Keeps track of the firearm's current upgrade level for a specific statistic. const string FUS_FIREARM_UPGRADE_LEVEL = "FUS_FIREARM_UPGRADE_LEVEL"; // Keeps track of the upgrade confirmation button. const string FUS_CHAT_UPGRADE_CONFIRMATION = "FUS_CHAT_UPGRADE_CONFIRMATION"; // Keeps track of the chosen node ID const string FUS_CHAT_NODE_ID = "FUS_CHAT_NODE_ID"; // Stored on the firearm object. Tracks the current level of all upgrades. const string FUS_FIREARM_UPGRADES_LEVELS = "FUS_FIREARM_UPGRADES_LEVELS"; /////////////// // 2DA FILES // /////////////// // The magazine capacity 2DA file const string FUS_2DA_MAGAZINE_SIZE = "iprp_magcapcost"; // The firepower 2DA file const string FUS_2DA_FIREPOWER = "iprp_firepowcost"; ////////////////////// // SYSTEM CONSTANTS // ////////////////////// // Number of upgrade categories. If you add a new category of upgrades this number needs to be updated! const int FUS_NUMBER_OF_UPGRADE_CATEGORIES = 6; // These determine which information to grab for each upgrade page. const int FUS_UPGRADE_TYPE_FIREPOWER = 1; const int FUS_UPGRADE_TYPE_MAGAZINE_SIZE = 2; const int FUS_UPGRADE_TYPE_RELOAD_SPEED = 3; const int FUS_UPGRADE_TYPE_AMMO_TYPE = 4; const int FUS_UPGRADE_TYPE_FIRING_MODES = 5; const int FUS_UPGRADE_TYPE_CRITICAL_RATING = 6; ////////////////// // MYSQL TABLES // ////////////////// // Global table which tracks maximum upgrades for all firearms. const string FUS_MYSQL_GLOBAL = "fus_global"; // Lookup table for components const string FUS_MYSQL_COMPONENTS = "fus_components"; // Prefix used for individual firearm tables. These tables appear as FUS_MYSQL_PREFIX + Item Resref in the DBMS. const string FUS_MYSQL_PREFIX = "fus_"; ///////////// // STRUCTS // ///////////// struct FUS_UpgradeInfoStruct { int iUpgradeLevel; // Current upgrade level int iMaxLevel; // Maximum upgrade level int iGoldCost; // Amount of gold needed to make upgrade string sUpgradeName; // The name of the upgrade being done int iComponent1, iComponent2, iComponent3, iComponent4, iComponent5; // Component ID numbers string sFirearmName; // Name of the firearm string sDescription; // The upgrade's description. Details what the upgrade actually does. }; //////////////// // PROTOTYPES // //////////////// // Returns all information regarding a firearm's upgrade as a FUS_UpgradeInfoStruct // oFirearm = The firearm to retrieve information from // sUpgradeName = Optional field which allows you to pass the upgrade name in as a parameter struct FUS_UpgradeInfoStruct FUS_GetUpgradeInformation(object oFirearm, int iUpgradeType); // Returns a list of the components needed to upgrade an item. This is displayed in the upgrade menu. // stUpgradeInfo = The struct which holds upgrade information (FUS_UpgradeInfoStruct) string FUS_BuildComponentList(struct FUS_UpgradeInfoStruct stUpgradeInfo); // Call this on the OnDisturbed event of your workbench placeable. // When an item is added to its inventory, the item will be returned to the PC that put it inside. // Then a conversation will begin which will allow the player to perform upgrades to the item. // During this process the item in question will be cursed to prevent exploits. Once the upgrading is complete // it will return to normal. void FUS_OnWorkbenchDisturbed(); // Returns the upgrade data for a particular firearm's upgrade ID and level. // This data is used for a number of things depending on the upgrade type. // For example, firepower uses this to determine what to set the new value at. string FUS_GetUpgradeData(object oFirearm, int iLevel, int iUpgradeID); // Performs the upgrade to the firearm being modified. Checks are made to ensure the player has enough // gold and the appropriate materials. // oPC = The player object speaking // iUpgradeID = The upgrade ID void FUS_DoUpgrade(object oPC, int iUpgradeID, struct FUS_UpgradeInfoStruct stUpgradeInfo); // Removes all temporary variables that are temporarily stored on the PC void FUS_ClearTemporaryVariables(object oPC); // Returns the upgrade header for the menu. This header displays information regarding the firearm's current // upgrade stats, price to upgrade, components needed, and so on. // oPC = The player object // iUpgradeID = FUS_UPGRADE_TYPE_* string FUS_CreateUpgradePageHeader(object oPC, int iUpgradeID); // Returns the ID number of an item property's value from the lookup table. // iValue = The value of the item property // iUpgradeType = FUS_UPGRADE_TYPE_* // sValueInteger = If set TRUE, sValue is treated as an integer. If set FALSE, it's treated as a string. int FUS_GetItemPropertyID(string sValue, int iUpgradeType, int sValueInteger = FALSE); /////////////// // FUNCTIONS // /////////////// struct FUS_UpgradeInfoStruct FUS_GetUpgradeInformation(object oFirearm, int iUpgradeType) { struct FUS_UpgradeInfoStruct stUpgradeInfo; string sResref = GetResRef(oFirearm); string sUpgradeType, sUpgradeName; string sDescription; stUpgradeInfo.sFirearmName = GetName(oFirearm, TRUE); // Grab the name of the upgrade column switch(iUpgradeType) { case FUS_UPGRADE_TYPE_FIREPOWER: sUpgradeType = "Firepower"; sUpgradeName = "Firepower"; sDescription = "Increases firepower to "; break; case FUS_UPGRADE_TYPE_MAGAZINE_SIZE: sUpgradeType = "MagazineSize"; sUpgradeName = "Magazine Size"; sDescription = "Increases magazine size to "; break; case FUS_UPGRADE_TYPE_RELOAD_SPEED: sUpgradeType = "ReloadSpeed"; sUpgradeName = "Reload Speed"; sDescription = "Increases reload speed to "; break; case FUS_UPGRADE_TYPE_AMMO_TYPE: sUpgradeType = "AmmoType"; sUpgradeName = "Additional Ammo Types"; sDescription = "Enables firing of ammo type: "; break; case FUS_UPGRADE_TYPE_FIRING_MODES: sUpgradeType = "FiringModes"; sUpgradeName = "Additional Firing Modes"; sDescription = "Enables firing mode: "; break; case FUS_UPGRADE_TYPE_CRITICAL_RATING: sUpgradeType = "CriticalRate"; sUpgradeName = "Critical Rating"; sDescription = "Increases critical rating to "; break; } // Store upgrade name and maximum upgrade level possible string sSQL = "SELECT MAX(Level) FROM " + FUS_MYSQL_PREFIX + sResref + " WHERE UpgradeType='" + IntToString(iUpgradeType) + "';"; SQLExecDirect(sSQL); if(SQLFetch() == SQL_SUCCESS) { stUpgradeInfo.iMaxLevel = StringToInt(SQLGetData(1)); } // Store upgrade name stUpgradeInfo.sUpgradeName = sUpgradeName; // Store upgrade level stUpgradeInfo.iUpgradeLevel = GetLocalArrayInt(oFirearm, FUS_FIREARM_UPGRADES_LEVELS, iUpgradeType); // Store gold cost, component resrefs, and component names sSQL = "SELECT Gold, Component1, Component2, Component3, Component4, Component5 FROM " + FUS_MYSQL_PREFIX + sResref + " WHERE Level=" + IntToString(stUpgradeInfo.iUpgradeLevel+1) + " AND UpgradeType=" + IntToString(iUpgradeType); SQLExecDirect(sSQL); if(SQLFetch() == SQL_SUCCESS) { stUpgradeInfo.iGoldCost = StringToInt(SQLGetData(1)); stUpgradeInfo.iComponent1 = StringToInt(SQLGetData(2)); stUpgradeInfo.iComponent2 = StringToInt(SQLGetData(3)); stUpgradeInfo.iComponent3 = StringToInt(SQLGetData(4)); stUpgradeInfo.iComponent4 = StringToInt(SQLGetData(5)); stUpgradeInfo.iComponent5 = StringToInt(SQLGetData(6)); } // Store upgrade description (actual values are set when the menu header is built stUpgradeInfo.sDescription = sDescription; return stUpgradeInfo; } string FUS_BuildComponentList(struct FUS_UpgradeInfoStruct stUpgradeInfo) { int bRequiresComponents = FALSE; string sComponentList; string sSQL = "SELECT ID, ComponentName FROM `" + FUS_MYSQL_COMPONENTS + "` WHERE ID=" + IntToString(stUpgradeInfo.iComponent1) + " OR ID=" + IntToString(stUpgradeInfo.iComponent2) + " OR ID=" + IntToString(stUpgradeInfo.iComponent3) +" OR ID=" + IntToString(stUpgradeInfo.iComponent4) +" OR ID=" + IntToString(stUpgradeInfo.iComponent5) + " ORDER BY ID"; SQLExecDirect(sSQL); while(SQLFetch() == SQL_SUCCESS) { int iDBID = StringToInt(SQLGetData(1)); bRequiresComponents = TRUE; if(iDBID == stUpgradeInfo.iComponent1) { sComponentList += SQLGetData(2) + "\n"; } if(iDBID == stUpgradeInfo.iComponent2) { sComponentList += SQLGetData(2) + "\n"; } if(iDBID == stUpgradeInfo.iComponent3) { sComponentList += SQLGetData(2) + "\n"; } if(iDBID == stUpgradeInfo.iComponent4) { sComponentList += SQLGetData(2) + "\n"; } if(iDBID == stUpgradeInfo.iComponent5) { sComponentList += SQLGetData(2) + "\n"; } } // Only display the "Components Required" message if there's components actually needed. if(bRequiresComponents) { sComponentList = ColorTokenGreen() + "Components Required:\n\n" + ColorTokenEnd() + sComponentList; } return sComponentList; } void FUS_OnWorkbenchDisturbed() { object oPC = GetLastDisturbed(); object oWorkshop = OBJECT_SELF; object oItem = GetInventoryDisturbItem(); int iType = GetInventoryDisturbType(); string sName = GetName(oItem); string sResref = GetResRef(oItem); if(iType == INVENTORY_DISTURB_TYPE_ADDED) { object oCopy = CopyItemSafe(oItem, oPC, TRUE); DestroyObject(oItem); // Does the table exist? If so we can fire the upgrade menu. if(DoesMySQLTableExist(FUS_MYSQL_PREFIX + sResref)) { // Clean variables just in case FUS_ClearTemporaryVariables(oPC); SetLocalObject(oPC, FUS_FIREARM_OBJECT, oCopy); SetItemCursedFlag(oCopy, TRUE); _dlgStart(oPC, oWorkshop, FUS_WORKSHOP_MENU, 1, 1, 1); } // Otherwise the PC can't upgrade that firearm (or other item) else { FloatingTextStringOnCreature(ColorTokenRed() + "You cannot upgrade that item.", oPC, FALSE); } } } void FUS_ClearTemporaryVariables(object oPC) { DeleteLocalInt(oPC, FUS_CHAT_UPGRADE_CONFIRMATION); DeleteLocalObject(oPC, FUS_FIREARM_OBJECT); DeleteLocalInt(oPC, FUS_CHAT_NODE_ID); } string FUS_CreateUpgradePageHeader(object oPC, int iUpgradeID) { object oFirearm = GetLocalObject(oPC, FUS_FIREARM_OBJECT); struct FUS_UpgradeInfoStruct stUpgradeInfo = FUS_GetUpgradeInformation(oFirearm, iUpgradeID); string sGold; if(stUpgradeInfo.iUpgradeLevel >= stUpgradeInfo.iMaxLevel) { sGold = ColorTokenRed() + "N/A"; } else { sGold = IntToString(stUpgradeInfo.iGoldCost); } string sHeader = ColorTokenGreen() + "Firearm: " + ColorTokenEnd() + GetName(oFirearm, TRUE) + "\n"; sHeader += ColorTokenGreen() + "Upgrade: " + ColorTokenEnd() + stUpgradeInfo.sUpgradeName + "\n\n"; sHeader += ColorTokenGreen() + "Level: " + ColorTokenEnd() + IntToString(stUpgradeInfo.iUpgradeLevel) + " / " + ColorTokenRed() + IntToString(stUpgradeInfo.iMaxLevel) + ColorTokenEnd() + "\n"; sHeader += ColorTokenGreen() + "Price to Upgrade: " + ColorTokenEnd() + sGold + "\n"; sHeader += ColorTokenGreen() + "Money: " + ColorTokenWhite() + IntToString(GetGold(oPC)) + ColorTokenEnd() + "\n\n"; // Ensure the upgrade isn't at its max already - this prevents unnecessary calls to the database if(stUpgradeInfo.iUpgradeLevel < stUpgradeInfo.iMaxLevel) { // Show the description and component list only if the upgrade isn't maxed out yet if(stUpgradeInfo.iUpgradeLevel < stUpgradeInfo.iMaxLevel) { sHeader += ColorTokenGreen() + "Next Upgrade: " + ColorTokenEnd() + ColorTokenWhite() + stUpgradeInfo.sDescription + FUS_GetUpgradeData(oFirearm, stUpgradeInfo.iUpgradeLevel+1, iUpgradeID) + "\n\n" + ColorTokenEnd(); sHeader += FUS_BuildComponentList(stUpgradeInfo); } } return sHeader; } string FUS_GetUpgradeData(object oFirearm, int iLevel, int iUpgradeID) { string sResref = GetResRef(oFirearm); string sData; string sTable = FUS_MYSQL_PREFIX + sResref; string sSQL = "SELECT UpgradeInfo FROM " + sTable + " WHERE Level=" + IntToString(iLevel) + " AND UpgradeType=" + IntToString(iUpgradeID); SQLExecDirect(sSQL); if(SQLFetch() == SQL_SUCCESS) { sData = SQLGetData(1); } return sData; } int FUS_GetItemPropertyID(string sValue, int iUpgradeType, int sValueInteger = FALSE) { int iValue = StringToInt(sValue); string sColumn; if(iUpgradeType == FUS_UPGRADE_TYPE_FIREPOWER) sColumn = "Firepower"; else if(iUpgradeType == FUS_UPGRADE_TYPE_MAGAZINE_SIZE) sColumn = "MagazineSize"; else if(iUpgradeType == FUS_UPGRADE_TYPE_RELOAD_SPEED) sColumn = "ReloadSpeed"; else if(iUpgradeType == FUS_UPGRADE_TYPE_AMMO_TYPE) sColumn = "AmmoType"; else if(iUpgradeType == FUS_UPGRADE_TYPE_FIRING_MODES) sColumn = "FiringModes"; else if(iUpgradeType == FUS_UPGRADE_TYPE_CRITICAL_RATING) sColumn = "CriticalRating"; // Return -1 on error if(sColumn == "") return -1; if(sValueInteger) { return StringToInt(GetMySQLData(FUS_MYSQL_LOOKUP, "ID", iValue, sColumn)); } else { return StringToInt(GetMySQLDataKeyString(FUS_MYSQL_LOOKUP, "ID", sValue, sColumn)); } } void FUS_DoUpgrade(object oPC, int iUpgradeID, struct FUS_UpgradeInfoStruct stUpgradeInfo) { object oComponent1, oComponent2, oComponent3, oComponent4, oComponent5; string sComponentName1, sComponentName2, sComponentName3, sComponentName4, sComponentName5; string sComponentResref1, sComponentResref2, sComponentResref3, sComponentResref4, sComponentResref5; int iGold = GetGold(oPC); // Check their gold just in case they dropped it while the purchase option was available if(iGold < stUpgradeInfo.iGoldCost) { SendMessageToPC(oPC, ColorTokenRed() + "You do not have enough money to make that purchase." + ColorTokenEnd()); return; } // Check for required components in PC's inventory object oItem = GetFirstItemInInventory(oPC); int bComp1Found, bComp2Found, bComp3Found, bComp4Found, bComp5Found; // Grab the names and resrefs of the components needed. string sSQL = "SELECT ID, ComponentName, ComponentResref FROM `" + FUS_MYSQL_COMPONENTS + "` WHERE ID=" + IntToString(stUpgradeInfo.iComponent1) + " OR ID=" + IntToString(stUpgradeInfo.iComponent2) + " OR ID=" + IntToString(stUpgradeInfo.iComponent3) +" OR ID=" + IntToString(stUpgradeInfo.iComponent4) +" OR ID=" + IntToString(stUpgradeInfo.iComponent5) + " ORDER BY ID"; SQLExecDirect(sSQL); while(SQLFetch() == SQL_SUCCESS) { int iCompID = StringToInt(SQLGetData(1)); if(iCompID == stUpgradeInfo.iComponent1) { sComponentName1 = SQLGetData(2); sComponentResref1 = SQLGetData(3); } if(iCompID == stUpgradeInfo.iComponent2) { sComponentName2 = SQLGetData(2); sComponentResref2 = SQLGetData(3); } if(iCompID == stUpgradeInfo.iComponent3) { sComponentName3 = SQLGetData(2); sComponentResref3 = SQLGetData(3); } if(iCompID == stUpgradeInfo.iComponent4) { sComponentName4 = SQLGetData(2); sComponentResref4 = SQLGetData(3); } if(iCompID == stUpgradeInfo.iComponent5) { sComponentName5 = SQLGetData(2); sComponentResref5 = SQLGetData(3); } } while(GetIsObjectValid(oItem)) { string sResref = GetResRef(oItem); // First component if(sComponentResref1 == sResref && oComponent1 == OBJECT_INVALID && sComponentResref1 != "") { oComponent1 = oItem; bComp1Found = TRUE; } // Second component else if(sComponentResref2 == sResref && oComponent2 == OBJECT_INVALID && sComponentResref2 != "") { oComponent2 = oItem; bComp2Found = TRUE; } // Thid component else if(sComponentResref3 == sResref && oComponent3 == OBJECT_INVALID && sComponentResref3 != "") { oComponent3 = oItem; bComp3Found = TRUE; } // Fourth component else if(sComponentResref4 == sResref && oComponent4 == OBJECT_INVALID && sComponentResref4 != "") { oComponent4 = oItem; bComp4Found = TRUE; } // Fifth component else if(sComponentResref5 == sResref && oComponent5 == OBJECT_INVALID && sComponentResref5 != "") { oComponent5 = oItem; bComp5Found = TRUE; } oItem = GetNextItemInInventory(oPC); } // Remove the materials only if they are all found in the PC's inventory. Otherwise print out an error message int bAllComponentsFound = TRUE; if(sComponentResref1 != "" && bComp1Found == FALSE) bAllComponentsFound = FALSE; else if(sComponentResref2 != "" && bComp2Found == FALSE) bAllComponentsFound = FALSE; else if(sComponentResref3 != "" && bComp3Found == FALSE) bAllComponentsFound = FALSE; else if(sComponentResref4 != "" && bComp4Found == FALSE) bAllComponentsFound = FALSE; else if(sComponentResref5 != "" && bComp5Found == FALSE) bAllComponentsFound = FALSE; // Destroy all components since they were all found if(bAllComponentsFound) { if(GetIsObjectValid(oComponent1)) DestroyObject(oComponent1); if(GetIsObjectValid(oComponent2)) DestroyObject(oComponent2); if(GetIsObjectValid(oComponent3)) DestroyObject(oComponent3); if(GetIsObjectValid(oComponent4)) DestroyObject(oComponent4); if(GetIsObjectValid(oComponent5)) DestroyObject(oComponent5); } // Do nothing and print an error message detailing which components are missing else { string sError = ColorTokenRed() + "You are missing the following components:\n"; if(sComponentName1 != "" && !bComp1Found) sError += "\n" + sComponentName1; if(sComponentName2 != "" && !bComp2Found) sError += "\n" + sComponentName2; if(sComponentName3 != "" && !bComp3Found) sError += "\n" + sComponentName3; if(sComponentName4 != "" && !bComp4Found) sError += "\n" + sComponentName4; if(sComponentName5 != "" && !bComp5Found) sError += "\n" + sComponentName5; sError += ColorTokenEnd(); SendMessageToPC(oPC, sError); return; } // Remove the gold from the game AssignCommand(oPC, TakeGoldFromCreature(stUpgradeInfo.iGoldCost, oPC, TRUE)); object oFirearm = GetLocalObject(oPC, FUS_FIREARM_OBJECT); string sResref = GetResRef(oFirearm); int iUpgradeType = GetLocalInt(oPC, FUS_CHAT_NODE_ID); string sUpgradeData = FUS_GetUpgradeData(oFirearm, stUpgradeInfo.iUpgradeLevel + 1, iUpgradeType); stUpgradeInfo.iUpgradeLevel = stUpgradeInfo.iUpgradeLevel + 1; // Safety check to make sure the weapon doesn't go beyond its max level if(stUpgradeInfo.iUpgradeLevel > stUpgradeInfo.iMaxLevel) { SendMessageToPC(oPC, ColorTokenRed() + "You cannot upgrade that any further." + ColorTokenEnd()); return; } // Update the upgrade level SetLocalArrayInt(oFirearm, FUS_FIREARM_UPGRADES_LEVELS, iUpgradeID, stUpgradeInfo.iUpgradeLevel); // Different actions have to be taken depending on what's being upgraded on the firearm switch(iUpgradeID) { // Firepower - Check the lookup table for the new firepower value, and then set the // firepower item property on the firearm to the new value case FUS_UPGRADE_TYPE_FIREPOWER: { int iIPID = FUS_GetItemPropertyID(sUpgradeData, iUpgradeID, TRUE); itemproperty ipFirepower = ItemPropertyDirect(ITEM_PROPERTY_FIREARM_FIREPOWER, 0, 33, iIPID, 0, 0); IPSafeAddItemProperty(oFirearm, ipFirepower, 0.0f, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, TRUE); break; } // Magazine Size - Check the lookup table for the new magazine size value and then set the // magazine size item property on the firearm to the new value case FUS_UPGRADE_TYPE_MAGAZINE_SIZE: { int iIPID = FUS_GetItemPropertyID(sUpgradeData, iUpgradeID, TRUE); itemproperty ipMagazineSize = ItemPropertyDirect(ITEM_PROPERTY_FIREARM_MAGAZINE, 0, 28, iIPID, 0, 0); IPSafeAddItemProperty(oFirearm, ipMagazineSize, 0.0f, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, TRUE); break; } // Reload Speed - Check the lookup table for ID values. Codes are as follows: // VERY_SLOW: Very slow reload speed // SLOW: Slow reload speed // MEDIUM: Medium reload speed // FAST: Fast reload speed // VERY_FAST: Very fast reload speed case FUS_UPGRADE_TYPE_RELOAD_SPEED: { int iIPID = FUS_GetItemPropertyID(sUpgradeData, iUpgradeID, FALSE); itemproperty ipMagazineSize = ItemPropertyDirect(ITEM_PROPERTY_FIREARM_RELOAD_SPEED, iIPID, 0, 0, 0, 0); IPSafeAddItemProperty(oFirearm, ipMagazineSize, 0.0f, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, TRUE); break; } // Ammo Types - Check the lookup table for ID values. Codes are as follows: // ENHANCED: Ability to use enhanced ammo type // INCENDIARY: Ability to use incendiary ammo type case FUS_UPGRADE_TYPE_AMMO_TYPE: { int iIPID = FUS_GetItemPropertyID(sUpgradeData, iUpgradeID, FALSE); itemproperty ipBonusAmmoTypes = ItemPropertyDirect(ITEM_PROPERTY_FIREARM_ADDITIONAL_AMMO_CLASSES, iIPID, 0, 0, 0, 0); IPSafeAddItemProperty(oFirearm, ipBonusAmmoTypes, 0.0f, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, FALSE); break; } // Firing Modes - Check the lookup table for ID values. Codes are as follows: // THREE_ROUND_BURST: Ability to use three round burst firing mode case FUS_UPGRADE_TYPE_FIRING_MODES: { int iIPID = FUS_GetItemPropertyID(sUpgradeData, iUpgradeID, FALSE); itemproperty ipFiringMode = ItemPropertyDirect(ITEM_PROPERTY_FIREARM_RATE_OF_FIRE, iIPID, 0, 0, 0, 0); IPSafeAddItemProperty(oFirearm, ipFiringMode, 0.0f, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, TRUE); break; } // Critical Rating - Set the critical rating variable on the firearm to the new value. // Range is from 1-50 case FUS_UPGRADE_TYPE_CRITICAL_RATING: { int iIPID = FUS_GetItemPropertyID(sUpgradeData, iUpgradeID, TRUE); itemproperty ipCriticalRating = ItemPropertyDirect(ITEM_PROPERTY_FIREARM_CRITICAL_RATING, 0, 34, iIPID, 0, 0); IPSafeAddItemProperty(oFirearm, ipCriticalRating, 0.0f, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, TRUE); break; } } } // Error checking //void main(){}