// Created by Zunath #include "inc_mysql_tables" #include "inc_system_const" #include "inc_pc_functions" #include "colors_inc" #include "char_stats" #include "nwnx_funcs_l" ///////////////////// // SYSTEM SETTINGS // ///////////////////// // This determines the max level players can reach. // Reminder: Levels don't do anything by themselves. They only give 10 SP per level. const int ADV_LEVEL_CAP = 50; // Number of SP earned on every level up - this is the base amount which increases as // players enter new level ranges. // DEFAULT: // Levels 1 - 20: 10SP / Level // Levels 21 - 40: 20SP / Level // Levels 41 - 50: 30SP / Level const int ADV_SP_EARNED_ON_LEVEL_UP = 10; // Amount of gold it takes to purchase a skill point reset. // Default: 2000 const int ADV_SP_RESET_INITIAL_COST = 2000; // Amount of gold to add on to the initial cost for each SP reset performed previously. // Default: 500 const int ADV_SP_RESET_ADDITIONAL_COST = 500; // The number of seconds before a player can do another SP reset. // Default: 259200 (72 Hours) const int ADV_SP_RESET_COOLDOWN_UNIXTIME = 259200; // If set to TRUE, the first time a player resets his or her SP allocation is free const int ADV_SP_RESET_FIRST_TIME_FREE = TRUE; ///////////////////////////////////////////// // SKILL POINT ALLOCATION SYSTEM VARIABLES // ///////////////////////////////////////////// // IMPORTANT - If you add or remove ANY upgrade categories, make sure this value is set correctly. // Determines the highest ID number of the list of upgrades. const int ADV_NUMBER_OF_UPGRADE_CATEGORIES = 20; // Number of SP available for use const string ADV_UNALLOCATED_SP = "ADV_UNALLOCATED_SP"; // Total number of SP that has been allocated const string ADV_ALLOCATED_SP = "ADV_ALLOCATED_SP"; // Level of the player const string ADV_PLAYER_LEVEL = "ADV_PLAYER_LEVEL"; // Current experience of the player const string ADV_PLAYER_EXPERIENCE = "ADV_PLAYER_EXPERIENCE"; // This is the base value of EXP which is used in the EXP to next level calculation // Default: 20 - DO NOT CHANGE ONCE SERVER GOES LIVE const int ADV_BASE_EXP = 5; // Array which keeps track of the upgrades that have been made const string ARRAY_UPGRADE_LIST = "ADV_ARRAY_UPGRADE_LIST"; // Array which keeps track of the upgrades that have had their soft caps increased const string ARRAY_SOFT_CAP_UPGRADE_LIST = "ADV_SOFT_CAP_UPGRADE_LIST"; // Max number of "skill requirement" columns in the ADV_TABLE_EQUIPMENT table. // If you need more skill requirement categories, add them to the table in MySQL and then // increase this number to reflect the new number const int ADV_MYSQL_REQUIREMENTS_MAX = 10; // Name of the variable which tracks a player's SP reset cooldown. // Once this date has passed, the player is free to do another reset. const string ADV_SP_RESET_COOLDOWN = "SP_RESET_ALLOCATION_COOLDOWN"; // Name of the variable which tracks the number of times a player has reset their SP const string ADV_SP_RESET_COUNT = "ADV_RESET_SP_COUNT"; // Name of the variable which tracks whether or not a player has used his or her free SP reset const string ADV_SP_RESET_FIRST_TIME_USED = "ADV_SP_RESET_FIRST_TIME_USED"; //////////////////////////// // ADVANCEMENT CATEGORIES // //////////////////////////// const int ADV_CATEGORY_INVALID = 0; const int ADV_CATEGORY_STATISTIC = 1; const int ADV_CATEGORY_PROFICIENCIES = 2; const int ADV_CATEGORY_UTILITY = 3; const int ADV_CATEGORY_ABILITIES = 4; ///////////////////////////// // ADVANCEMENT UPGRADES ID // ///////////////////////////// const int ADV_ID_INVALID = 0; const int ADV_ID_HP = 1; const int ADV_ID_INVENTORY_SPACE = 2; const int ADV_ID_ARMOR = 3; const int ADV_ID_HANDGUN_PROFICIENCY = 4; const int ADV_ID_SHOTGUN_PROFICIENCY = 5; const int ADV_ID_RIFLE_PROFICIENCY = 6; const int ADV_ID_SMG_PROFICIENCY = 7; const int ADV_ID_MAGNUM_PROFICIENCY = 8; const int ADV_ID_MELEE = 9; const int ADV_ID_SEARCH = 10; const int ADV_ID_HIDE = 11; const int ADV_ID_MOVE_SILENTLY = 12; const int ADV_ID_FIRST_AID = 13; const int ADV_ID_LOCKPICKING = 14; const int ADV_ID_MIXING = 15; const int ADV_ID_SPRING_ATTACK = 16; const int ADV_ID_POWER_ATTACK = 17; const int ADV_ID_AMBIDEXTERITY = 18; const int ADV_ID_TWO_WEAPON_FIGHTING = 19; const int ADV_ID_ITEM_REPAIR = 20; /////////////////////// // CUSTOM ITEM TYPES // /////////////////////// const int ADV_ITEM_TYPE_INVALID = 0; const int ADV_ITEM_TYPE_ARMOR = 1; const int ADV_ITEM_TYPE_SHIELD = 2; const int ADV_ITEM_TYPE_HANDGUN = 3; const int ADV_ITEM_TYPE_SHOTGUN = 4; const int ADV_ITEM_TYPE_SMG = 5; const int ADV_ITEM_TYPE_RIFLE = 6; const int ADV_ITEM_TYPE_THROWING = 7; const int ADV_ITEM_TYPE_AMMO = 8; const int ADV_ITEM_TYPE_RING = 9; const int ADV_ITEM_TYPE_BOOTS = 10; ////////////////////////////////// // ADVANCEMENT SYSTEM FUNCTIONS // ////////////////////////////////// // Sets all ability scores to 10, sets all skills to 0, and removes all // feats and skills granted by the PC's NWN class. Then gives the // appropriate feats to use all items. // iResetFeats = If set TRUE, player's feats will be removed and basic feats will be given. // If set FALSE, feats will remain as-is void ADV_InitializePC(object oPC, int iResetFeats = TRUE); // Get the number of skill points oPC has available for use. int ADV_GetUnallocatedSkillPoints(object oPC); // Get the number of skill points that have been used to // oPC's attributes. int ADV_GetAllocatedSkillPoints(object oPC); // Sets the number of SP oPC has allocated into upgrades void ADV_SetAllocatedSP(object oPC, int iAmount); // Sets the number of SP oPC has not allocated yet. This is the number of SP // he or she has available to them to make upgrades. void ADV_SetUnallocatedSP(object oPC, int iAmount); // Get the PC's current level under the advancement system // Note that level is just a reference. Levels only grant the player with // more SP, nothing else. int ADV_GetLevel(object oPC); // Sets a PC's level to iLevel. This does not grant any SP. It merely changes their level. void ADV_SetLevel(object oPC, int iLevel); // Get the PC's current EXP amount int ADV_GetCurrentExperience(object oPC); // Creates the message that appears when oPC chooses the // "View Character Data" option in rest menu string ADV_CreateCharacterInfoMessage(object oPC); // Returns data from a MySQL table string ADV_GetMySQLData(string sTable, string sColumn, int iID); // Returns the max number of times a player can increase the rank of an upgrade. // iUpgradeID = ADV_ID_* int ADV_GetMaxUpgrades(int iUpgradeID); // Returns the maximum times a PC can upgrade a stat before he or she hits the "soft cap". // In other words, when the soft cap is reached the PC must complete a quest or do something // in order to increase the soft cap. // iUpgradeID = ADV_ID_* int ADV_GetSoftCap(int iUpgradeID); // Sets the number of times an upgrade has been increased // oPC must be a valid player // iUpgradeID = ADV_ID_* // iLevel = Number of increases void ADV_SetUpgradeLevel(object oPC, int iUpgradeID, int iLevel); // Returns the number of time an upgrade has been increased // oPC must be a valid player // iUpgradeID = ADV_ID_* int ADV_GetUpgradeLevel(object oPC, int iUpgradeID); // Get the number of SP required to upgrade a category to iLevel // iLevel should be one step up from a PC's current level. int ADV_GetUpgradeCost(int iUpgradeID, int iLevel); // Return the name of the upgrade at row iUpgradeID string ADV_GetUpgradeName(int iUpgradeID); // Grants iAmount of experience to oPC. // Each level grants 10 SP (Skill Points) void ADV_GiveExperienceToPC(object oPC, int iAmount); // Increases an upgrade category one level. Required SP is taken from oPC's // unallocated SP pool and the bonus is made. void ADV_DoUpgrade(object oPC, int iUpgradeID); // Returns the description for an upgrade category. // To be used in the SP allocation menu // iUpgradeID = ADV_ID_* string ADV_GetUpgradeDescription(int iUpgradeID); ///////////////////////// // EQUIPMENT FUNCTIONS // ///////////////////////// // Checks to see if oPC can equip oItem. If he or she cannot, // messages will be sent to notify them. Keep in mind that // players cannot equip an item if it isn't in the equipment // list (ADV_EQUIPMENT MySQL table) // If bShowMessage is TRUE, a message will be sent to the PC in the event that he or she // fails to equip the item due to lack of skill int ADV_CanItemBeEquipped(object oPC, object oItem, int bShowMessage = TRUE); // Returns the type of item found on row iID of ADV_EQUIPMENT MySQL table // Return value: ADV_ITEM_TYPE_* int ADV_GetItemType(string sResref); // Sets the value of a soft cap to a particular number. Keep in mind this is // the MULTIPLE of the soft cap range. So if the soft cap has to be increased // every 10 levels, the PC's new cap will be iNewLimit * 10. // oPC = The player object // iUpgradeID = ADV_ID_* // iNewLimit = The new multiple value void ADV_SetPCSoftCap(object oPC, int iUpgradeID, int iNewLimit); // Returns the soft cap multiple for a particular upgrade ID. // Refer to ADV_SetPCSoftCap for more information // oPC = The player object // iUpgradeID = ADV_ID_* int ADV_GetPCSoftCap(object oPC, int iUpgradeID); // Creates a header for the SP allocation menu which displays // important information for the player string ADV_CreateUpgradeHeader(object oPC, int iIDNumber); void ADV_InitializePC(object oPC, int iResetFeats = TRUE) { if(!GetIsPC(oPC)){return;} if(iResetFeats) { // Remove feats, spells, and abilites granted from the NWN class // and give the basic feats that all characters have if(ADV_USING_LINUX) { int iNumFeats = GetTotalKnownFeats(oPC); int iCurFeat; for(iCurFeat = 1; iCurFeat <= iNumFeats; iCurFeat++) { SetKnownFeat (oPC, iCurFeat, -1); } AddKnownFeat(oPC, FEAT_ARMOR_PROFICIENCY_LIGHT); AddKnownFeat(oPC, FEAT_ARMOR_PROFICIENCY_MEDIUM); AddKnownFeat(oPC, FEAT_ARMOR_PROFICIENCY_HEAVY); AddKnownFeat(oPC, FEAT_SHIELD_PROFICIENCY); AddKnownFeat(oPC, FEAT_WEAPON_PROFICIENCY_EXOTIC); AddKnownFeat(oPC, FEAT_WEAPON_PROFICIENCY_MARTIAL); AddKnownFeat(oPC, FEAT_WEAPON_PROFICIENCY_SIMPLE); AddKnownFeat(oPC, 1116); // Reload feat } else { NWNXFuncs_RemoveAllFeats(oPC); NWNXFuncs_AddFeat(oPC, FEAT_ARMOR_PROFICIENCY_LIGHT); NWNXFuncs_AddFeat(oPC, FEAT_ARMOR_PROFICIENCY_MEDIUM); NWNXFuncs_AddFeat(oPC, FEAT_ARMOR_PROFICIENCY_HEAVY); NWNXFuncs_AddFeat(oPC, FEAT_SHIELD_PROFICIENCY); NWNXFuncs_AddFeat(oPC, FEAT_WEAPON_PROFICIENCY_EXOTIC); NWNXFuncs_AddFeat(oPC, FEAT_WEAPON_PROFICIENCY_MARTIAL); NWNXFuncs_AddFeat(oPC, FEAT_WEAPON_PROFICIENCY_SIMPLE); NWNXFuncs_AddFeat(oPC, 1116); // Reload feat } } // Change player's class selection to fighter. if(ADV_USING_LINUX) { // Currently unable to do this under Linux } else { NWNXFuncs_SetClassByPosition(oPC, 1, CLASS_TYPE_FIGHTER); } // Initialize all stats if(ADV_USING_LINUX) { SetAbilityScore(oPC, ABILITY_STRENGTH, PC_BASE_STR); SetAbilityScore(oPC, ABILITY_DEXTERITY, PC_BASE_DEX); SetAbilityScore(oPC, ABILITY_CONSTITUTION, PC_BASE_CON); SetAbilityScore(oPC, ABILITY_WISDOM, PC_BASE_WIS); SetAbilityScore(oPC, ABILITY_CHARISMA, PC_BASE_CHA); SetAbilityScore(oPC, ABILITY_INTELLIGENCE, PC_BASE_INT); SetMaxHitPointsByLevel(oPC, 1, PC_BASE_HP); SetCurrentHitPoints(oPC, GetMaxHitPoints(oPC)); int iCurSkill; for(iCurSkill = 1; iCurSkill <= 27; iCurSkill++) { SetSkillRank(oPC, iCurSkill, 0); } SetSavingThrowBonus(oPC, SAVING_THROW_FORT, 0); SetSavingThrowBonus(oPC, SAVING_THROW_REFLEX, 0); SetSavingThrowBonus(oPC, SAVING_THROW_WILL, 0); } else { NWNXFuncs_SetAbilityScore(oPC, ABILITY_STRENGTH, PC_BASE_STR); NWNXFuncs_SetAbilityScore(oPC, ABILITY_DEXTERITY, PC_BASE_DEX); NWNXFuncs_SetAbilityScore(oPC, ABILITY_CONSTITUTION, PC_BASE_CON); NWNXFuncs_SetAbilityScore(oPC, ABILITY_WISDOM, PC_BASE_WIS); NWNXFuncs_SetAbilityScore(oPC, ABILITY_CHARISMA, PC_BASE_CHA); NWNXFuncs_SetAbilityScore(oPC, ABILITY_INTELLIGENCE, PC_BASE_INT); NWNXFuncs_SetHitPointsByLevel(oPC, PC_BASE_HP, 1); NWNXFuncs_SetCurrentHitPoints(oPC, GetMaxHitPoints(oPC)); NWNXFuncs_SetAllSkillsToZero(oPC); // Reset fortitude, reflex, and will saving throws NWNXFuncs_SetSavingThrowBonus(oPC, SAVING_THROW_FORT, 0); NWNXFuncs_SetSavingThrowBonus(oPC, SAVING_THROW_REFLEX, 0); NWNXFuncs_SetSavingThrowBonus(oPC, SAVING_THROW_WILL, 0); } // Give the PC an item properties skin object oSkin = GetItemInSlot(INVENTORY_SLOT_CARMOUR, oPC); if(!GetIsObjectValid(oSkin)) { oSkin = CreateItemOnObject("soo_pc_skin", oPC); AssignCommand(oPC, ActionEquipItem(oSkin, INVENTORY_SLOT_CARMOUR)); } // AP System Initialization int iLevel = ADV_GetLevel(oPC); if(iLevel <= 0) { ADV_SetLevel(oPC, 1); iLevel = 1; } // 9/27/2011 - Levels 21 - 40 give 2x the number of SP // Levels 41 - 60 give 3x the number of SP int iSP; int iCurLevel; for(iCurLevel = 1; iCurLevel <= iLevel; iCurLevel++) { if(iCurLevel <= 20) iSP = iSP + ADV_SP_EARNED_ON_LEVEL_UP; else if(iCurLevel <= 40) iSP = iSP + (ADV_SP_EARNED_ON_LEVEL_UP * 2); else if(iCurLevel <= 60) iSP = iSP + (ADV_SP_EARNED_ON_LEVEL_UP * 3); } ADV_SetUnallocatedSP(oPC, iSP); ADV_SetAllocatedSP(oPC, 0); int iLoop; // Set all upgrade categories to zero for(iLoop = 1; iLoop <= ADV_NUMBER_OF_UPGRADE_CATEGORIES; iLoop++) { ADV_SetUpgradeLevel(oPC, iLoop, 0); } // Initialize all HP regeneration variables object oDatabase = GetItemPossessedBy(oPC, PC_DATABASE); SetLocalInt(oDatabase, REGEN_RATE, PC_BASE_HP_REGEN_RATE); SetLocalInt(oDatabase, REGEN_AMOUNT, PC_BASE_HP_REGEN_AMOUNT); // Initialize inventory bonus space DeleteLocalInt(oDatabase, INV_INVENTORY_BONUS); } int ADV_GetUnallocatedSkillPoints(object oPC) { object oDatabase = GetItemPossessedBy(oPC, PC_DATABASE); return GetLocalInt(oDatabase, ADV_UNALLOCATED_SP); } int ADV_GetAllocatedSkillPoints(object oPC) { object oDatabase = GetItemPossessedBy(oPC, PC_DATABASE); return GetLocalInt(oDatabase, ADV_ALLOCATED_SP); } int ADV_GetLevel(object oPC) { object oDatabase = GetItemPossessedBy(oPC, PC_DATABASE); return GetLocalInt(oDatabase, ADV_PLAYER_LEVEL); } int ADV_GetRequiredExperience(object oPC) { // Section removed because we're going with the "100 EXP per level" concept object oDatabase = GetItemPossessedBy(oPC, PC_DATABASE); int iLevel = ADV_GetLevel(oPC); return StringToInt(GetMySQLData(ADV_EXP_CHART, "Experience", iLevel, "Level")); } int ADV_GetCurrentExperience(object oPC) { object oDatabase = GetItemPossessedBy(oPC, PC_DATABASE); return GetLocalInt(oDatabase, ADV_PLAYER_EXPERIENCE); } string ADV_CreateCharacterInfoMessage(object oPC) { object oDatabase = GetItemPossessedBy(oPC, PC_DATABASE); int iHungerLevel = GetLocalInt(oDatabase, FOOD_CURRENT_HUNGER); int iHungerMaxLevel = GetLocalInt(oDatabase, FOOD_MAX_HUNGER); int iInfectionLevel = GetLocalInt(oDatabase, DISEASE_PC_DISEASE_LEVEL); int iInfectionMaxLevel = GetLocalInt(oDatabase, DISEASE_PC_DISEASE_CAP); int iLevel = ADV_GetLevel(oPC); int iEXP = ADV_GetCurrentExperience(oPC); int iAllocatedSP = ADV_GetAllocatedSkillPoints(oPC); int iUnallocatedSP = ADV_GetUnallocatedSkillPoints(oPC); string sMessage = ColorTokenGreen() + "Name: " + ColorTokenEnd() + GetName(oPC) + "\n\n" + ColorTokenGreen() + "Level: " + ColorTokenEnd() + IntToString(iLevel) + " / " + IntToString(ADV_LEVEL_CAP) + "\n" + ColorTokenGreen() + "EXP: " + ColorTokenEnd() + IntToString(iEXP) + " / " + IntToString(ADV_GetRequiredExperience(oPC)) + "\n\n" + //ColorTokenGreen() + "Allocated Skill Points: " + ColorTokenEnd() + IntToString(iAllocatedSP) + "\n" + ColorTokenGreen() + "Skill Points: " + ColorTokenEnd() + IntToString(iUnallocatedSP) + "\n"; //ColorTokenGreen() + "Hunger Level: " + ColorTokenEnd() + IntToString(iHungerLevel) + "% / " + ColorTokenRed() + IntToString(iHungerMaxLevel) + "%" + ColorTokenEnd() + "\n" + //ColorTokenGreen() + "Infection Level: " + ColorTokenEnd() + IntToString(iInfectionLevel) + "% / " + ColorTokenRed() + IntToString(iInfectionMaxLevel) + "%" + ColorTokenEnd() + "\n"; return sMessage; } string ADV_GetMySQLData(string sTable, string sColumn, int iID) { string sSQL = "SELECT " + sColumn + " FROM " + sTable + " WHERE ID=" + IntToString(iID); SQLExecDirect(sSQL); SQLFetch(); return SQLGetData(1); } int ADV_GetMaxUpgrades(int iUpgradeID) { return StringToInt(ADV_GetMySQLData(ADV_MAX_UPGRADES, "MaxUpgrades", iUpgradeID)); } int ADV_GetSoftCap(int iUpgradeID) { return StringToInt(ADV_GetMySQLData(ADV_MAX_UPGRADES, "SoftCap", iUpgradeID)); } void ADV_SetLevel(object oPC, int iLevel) { object oDatabase = GetItemPossessedBy(oPC, PC_DATABASE); SetLocalInt(oDatabase, ADV_PLAYER_LEVEL, iLevel); } void ADV_SetUnallocatedSP(object oPC, int iAmount) { object oDatabase = GetItemPossessedBy(oPC, PC_DATABASE); SetLocalInt(oDatabase, ADV_UNALLOCATED_SP, iAmount); } void ADV_SetAllocatedSP(object oPC, int iAmount) { object oDatabase = GetItemPossessedBy(oPC, PC_DATABASE); SetLocalInt(oDatabase, ADV_ALLOCATED_SP, iAmount); } void ADV_SetUpgradeLevel(object oPC, int iUpgradeID, int iLevel) { object oDatabase = GetItemPossessedBy(oPC, PC_DATABASE); SetLocalArrayInt(oDatabase, ARRAY_UPGRADE_LIST, iUpgradeID, iLevel); } int ADV_GetUpgradeLevel(object oPC, int iUpgradeID) { object oDatabase = GetItemPossessedBy(oPC, PC_DATABASE); return GetLocalArrayInt(oDatabase, ARRAY_UPGRADE_LIST, iUpgradeID); } int ADV_GetUpgradeCost(int iUpgradeID, int iLevel) { iLevel = iLevel - 1; if(iLevel < 0) iLevel = 0; int iCost = StringToInt(ADV_GetMySQLData(ADV_MAX_UPGRADES, "InitialCost", iUpgradeID)); iCost = iCost + iLevel; return iCost; } string ADV_GetUpgradeName(int iUpgradeID) { return ADV_GetMySQLData(ADV_MAX_UPGRADES, "Name", iUpgradeID); } void ADV_GiveExperienceToPC(object oPC, int iAmount) { // Safety check - no need to give zero XP nor should DMs get XP if(iAmount <= 0 || GetIsDM(oPC)) return; object oDatabase = GetItemPossessedBy(oPC, PC_DATABASE); int iExp = ADV_GetCurrentExperience(oPC) + iAmount; int iLevel = ADV_GetLevel(oPC); int iSP = ADV_GetUnallocatedSkillPoints(oPC); int iReqExp = ADV_GetRequiredExperience(oPC); FloatingTextStringOnCreature("You earned " + ColorTokenWhite() + IntToString(iAmount) + ColorTokenEnd() + " experience points.", oPC, FALSE); // Added for ROTD - EXP given beyond the level cap will be reset to EXP TNL - 1 if(iLevel >= ADV_LEVEL_CAP && iExp >= iReqExp) { iExp = iReqExp - 1; } // As long as current EXP has reached or passed the EXP cap, // grant the player another level. while(iExp >= iReqExp) { int iSPMultiplier = 1; iExp = iExp - iReqExp; iLevel = iLevel + 1; // 9/27/2011 - Players receive more SP as they level up. Ranges are as follows: // // Levels 1-20 : 1x normal // Levels 21-40: 2x normal // Levels 41-60: 3x normal if(iLevel >= 21 && iLevel <= 40) iSPMultiplier = 2; else if(iLevel >= 41 && iLevel <= 60) iSPMultiplier = 3; iSP = iSP + (ADV_SP_EARNED_ON_LEVEL_UP * iSPMultiplier); SetLocalInt(oDatabase, ADV_UNALLOCATED_SP, iSP); SetLocalInt(oDatabase, ADV_PLAYER_LEVEL, iLevel); SetLocalInt(oDatabase, "ADV_REQUIRED_EXP", ADV_GetRequiredExperience(oPC)); ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_HEALING_G), oPC); SendMessageToPC(oPC, "You have attained level " + ColorTokenGreen() + IntToString(iLevel) + ColorTokenEnd() + " !"); iReqExp = ADV_GetRequiredExperience(oPC); } SetLocalInt(oDatabase, ADV_PLAYER_EXPERIENCE, iExp); } void ADV_DoUpgrade(object oPC, int iUpgradeID) { object oDatabase = GetItemPossessedBy(oPC, PC_DATABASE); int iLevel = ADV_GetUpgradeLevel(oPC, iUpgradeID) + 1; int iAvailableSP = ADV_GetUnallocatedSkillPoints(oPC); int iSPCost = ADV_GetUpgradeCost(iUpgradeID, iLevel); int iAllocatedSP = ADV_GetAllocatedSkillPoints(oPC); int iMaxUpgrades = ADV_GetMaxUpgrades(iUpgradeID); int iSoftCap = ADV_GetSoftCap(iUpgradeID); int iPCSoftCap = ADV_GetPCSoftCap(oPC, iUpgradeID); iSoftCap = iSoftCap + (iSoftCap * iPCSoftCap); if(iSoftCap < iMaxUpgrades) iMaxUpgrades = iSoftCap; // Safety check to prevent PC from upgrading too high if(iLevel > iMaxUpgrades) { SendMessageToPC(oPC, ColorTokenRed() + "You cannot increase that upgrade's level any further."); return; } // Another safety check to prevent PC from upgrading without necessary SP if(iAvailableSP < iSPCost) { SendMessageToPC(oPC, ColorTokenRed() + "You do not have enough SP to make that upgrade."); return; } // Everything checks out. Make the upgrade. ADV_SetUpgradeLevel(oPC, iUpgradeID, iLevel); // Reduce unallocated SP iAvailableSP = iAvailableSP - iSPCost; ADV_SetUnallocatedSP(oPC, iAvailableSP); // Increase allocated SP iAllocatedSP = iAllocatedSP + iSPCost; ADV_SetAllocatedSP(oPC, iAllocatedSP); // Change character's stats, depending on which upgrade was chosen switch(iUpgradeID) { case ADV_ID_HP: { if(ADV_USING_LINUX) { SetMaxHitPointsByLevel(oPC, 1, GetMaxHitPoints(oPC) + 1); } else { NWNXFuncs_ModHitPointsByLevel(oPC, 1, 1); } break; } case ADV_ID_INVENTORY_SPACE: { SetLocalInt(oDatabase, INV_INVENTORY_BONUS, GetLocalInt(oDatabase, INV_INVENTORY_BONUS) + 1); break; } case ADV_ID_SEARCH: { if(ADV_USING_LINUX) { SetSkillRank(oPC, SKILL_SEARCH, GetSkillRank(SKILL_SEARCH, oPC, FALSE) + 1); } else { NWNXFuncs_ModSkill(oPC, SKILL_SEARCH, 1); } break; } case ADV_ID_HIDE: { if(ADV_USING_LINUX) { SetSkillRank(oPC, SKILL_HIDE, GetSkillRank(SKILL_HIDE, oPC, FALSE) + 1); } else { NWNXFuncs_ModSkill(oPC, SKILL_HIDE, 1); } break; } case ADV_ID_MOVE_SILENTLY: { if(ADV_USING_LINUX) { SetSkillRank(oPC, SKILL_MOVE_SILENTLY, GetSkillRank(SKILL_MOVE_SILENTLY, oPC, FALSE) + 1); } else { NWNXFuncs_ModSkill(oPC, SKILL_MOVE_SILENTLY, 1); } break; } case ADV_ID_SPRING_ATTACK: { if(ADV_USING_LINUX) { AddKnownFeat(oPC, FEAT_SPRING_ATTACK, 0); } else { NWNXFuncs_AddFeat(oPC, FEAT_SPRING_ATTACK, 0); } break; } case ADV_ID_POWER_ATTACK: { if(ADV_USING_LINUX) { AddKnownFeat(oPC, FEAT_POWER_ATTACK, 0); } else { NWNXFuncs_AddFeat(oPC, FEAT_POWER_ATTACK, 0); } break; } case ADV_ID_AMBIDEXTERITY: { if(ADV_USING_LINUX) { AddKnownFeat(oPC, FEAT_AMBIDEXTERITY, 0); } else { NWNXFuncs_AddFeat(oPC, FEAT_AMBIDEXTERITY, 0); } break; } case ADV_ID_TWO_WEAPON_FIGHTING: { if(ADV_USING_LINUX) { AddKnownFeat(oPC, FEAT_TWO_WEAPON_FIGHTING, 0); } else { NWNXFuncs_AddFeat(oPC, FEAT_TWO_WEAPON_FIGHTING, 0); } break; } } } string ADV_GetUpgradeDescription(int iUpgradeID) { return ADV_GetMySQLData(ADV_MAX_UPGRADES, "Description", iUpgradeID); } // (Private Function - Gets information from the MySQL table "ADV_EQUIPMENT") // sLookFor should be the column name. Remember to convert to different data type // if you need ints, floats, etc. string ADV_GetMySQLInfo(string sResref, string sLookFor) { string sSQL = "SELECT " + sLookFor + " FROM " + ADV_EQUIPMENT + " WHERE Resref='" + sResref + "';"; SQLExecDirect(sSQL); SQLFetch(); return SQLGetData(1); } int ADV_CanItemBeEquipped(object oPC, object oItem, int bShowMessage = TRUE) { object oDatabase = GetItemPossessedBy(oPC, PC_DATABASE); string sResref = GetResRef(oItem); int iLoop; int bPass = TRUE; // Item isn't listed in item database or resref is invalid. Cannot be equipped. if(ADV_GetMySQLInfo(sResref, "Resref") == "") { SendMessageToPC(oPC, ColorTokenRed() + "The item you tried to equip is not in the database. Please inform a DM of this issue. ( ResRef: " + sResref + " )"); return FALSE; } // Cycle through each required skill and check it against the PC's skill level for(iLoop = 1; iLoop <= ADV_MYSQL_REQUIREMENTS_MAX; iLoop++) { int iSkillID = StringToInt(GetMySQLDataKeyString(ADV_EQUIPMENT, "SkillReq" + IntToString(iLoop), sResref)); if(iSkillID <= 0) break; int iReq = StringToInt(GetMySQLDataKeyString(ADV_EQUIPMENT, "SkillReq" + IntToString(iLoop) + "Level", sResref)); int iSkillLevel = ADV_GetUpgradeLevel(oPC, iSkillID); if(iReq > iSkillLevel) { // Show the message if bShowMessage is TRUE if(bShowMessage) { SendMessageToPC(oPC, ColorTokenRed() + "You lack the necessary " + ADV_GetUpgradeName(iSkillID) + " skill to equip that item. (Required: " + IntToString(iReq) + ")"); } bPass = FALSE; } } return bPass; } int ADV_GetItemType(string sResref) { if(sResref == "") return ADV_ITEM_TYPE_INVALID; return StringToInt(ADV_GetMySQLInfo(sResref, "Type")); } void ADV_SetPCSoftCap(object oPC, int iUpgradeID, int iNewLimit) { object oDatabase = GetItemPossessedBy(oPC, PC_DATABASE); SetLocalArrayInt(oDatabase, ARRAY_SOFT_CAP_UPGRADE_LIST, iUpgradeID, iNewLimit); } int ADV_GetPCSoftCap(object oPC, int iUpgradeID) { object oDatabase = GetItemPossessedBy(oPC, PC_DATABASE); return GetLocalArrayInt(oDatabase, ARRAY_SOFT_CAP_UPGRADE_LIST, iUpgradeID); } string ADV_CreateUpgradeHeader(object oPC, int iID) { object oDatabase = GetItemPossessedBy(oPC, PC_DATABASE); // Tracks whether or not the max cap has been reached. int bAbsoluteCapReached = FALSE; // Max number of times the category can be upgraded int iMaxUpgrades = ADV_GetMaxUpgrades(iID); // Soft cap - PC cannot increase the stat until prerequisite quest is completed // This number is the specified point at which the soft cap takes effect. So if // this number is set to '10' then that means every 10 levels the soft cap has to be // increased. int iSoftCap = ADV_GetSoftCap(iID); // Number of times the soft cap has been increased int iPlayerSoftCap = ADV_GetPCSoftCap(oPC, iID); iSoftCap = iSoftCap + (iPlayerSoftCap * iSoftCap); if(iSoftCap > iMaxUpgrades) { iSoftCap = iMaxUpgrades; bAbsoluteCapReached = TRUE; } // Current number of time the category has been upgraded int iCurrentUpgrade = ADV_GetUpgradeLevel(oPC, iID); // Change the max upgrade color depending on if max cap has been reached string sUpgradeCap = IntToString(iSoftCap); if(iSoftCap == iMaxUpgrades) sUpgradeCap = ColorTokenRed() + sUpgradeCap + ColorTokenEnd(); else sUpgradeCap = ColorTokenYellow() + sUpgradeCap + ColorTokenEnd(); // Name of the upgrade string sName = Get2DAString(ADV_MAX_UPGRADES, "Name", iID); string sPrompt = ColorTokenGreen() + "Currently Selected Upgrade: " + ColorTokenEnd() + sName + ColorTokenEnd() + "\n"; sPrompt = sPrompt + ColorTokenGreen() + "Upgrade Level: " + ColorTokenEnd() + IntToString(iCurrentUpgrade) + " / " + sUpgradeCap + "\n\n"; iCurrentUpgrade = iCurrentUpgrade + 1; sPrompt = sPrompt + ColorTokenGreen() + "Available SP: " + ColorTokenEnd() + IntToString(ADV_GetUnallocatedSkillPoints(oPC)) + ColorTokenEnd() + "\n"; sPrompt = sPrompt + ColorTokenGreen() + "Next Upgrade: " + ColorTokenEnd(); // Display the SP requirement for upgrading, if applicable. if(iCurrentUpgrade > iMaxUpgrades) { sPrompt = sPrompt + ColorTokenRed() + "MAX" + ColorTokenEnd(); } else { // Get the SP requirement for next level iCurrentUpgrade = ADV_GetUpgradeCost(iID, iCurrentUpgrade); // Show in RED if PC doesn't have enough SP to make the upgrade if(iCurrentUpgrade > ADV_GetUnallocatedSkillPoints(oPC)) { sPrompt = sPrompt + ColorTokenRed() + IntToString(iCurrentUpgrade) + "SP" + ColorTokenEnd(); } // Show in GREEN if PC does have enough SP to make the upgrade else { sPrompt = sPrompt + IntToString(iCurrentUpgrade) + "SP"; } } // Add a description of the upgrade sPrompt = sPrompt + ColorTokenGreen() + "\n\nDescription: " + ColorTokenEnd() + ADV_GetUpgradeDescription(iID); return sPrompt; } // Error checking //void main(){}