REO-EE/_module/nss/reo_combine.nss
Jaysyn904 f82740bbbd Initial commit
Initial commit
2024-02-22 13:22:03 -05:00

264 lines
10 KiB
Plaintext

#include "adv_include"
#include "nwnx_events"
#include "inc_helper_funcs"
// Item combination script
//
// This is fired when a player uses the "Combine" spell on an item to target another item in their inventory.
// When another object is targeted, a combination will be looked up in the database to see if there's a match.
// If a match is found, it will destroy both the used item and the target item and create the new item in the player's inventory.
// For example:
// Player combines a Green Herb with a Red Herb. Both of those herbs are destroyed and a new item named "Mixed Herb" is created in their inventory.
//
// If no match is found, the combination will fail and nothing will happen.
//
// Created by Zunath on July 19, 2011
/////////////////////
// SYSTEM MESSAGES //
/////////////////////
// The message that displays when a combination fails.
const string COMBINE_MESSAGE_FAILED = "Combination failed.";
// The message that displays when a player has too low skill
const string COMBINE_MESSAGE_LOW_SKILL = "Your mixing skill is too low to combine those items.";
//////////////////////
// SYSTEM CONSTANTS //
//////////////////////
// Name of the MySQL table which holds all valid combinations
const string COMBINE_MYSQL_TABLE = "combine_chart";
///////////////////////
// SYSTEM PROTOTYPES //
///////////////////////
// Handles creation of new item and destruction of the two items used to create it.
// oPC = The player creating the item
// oItemA = Object #1
// oItemB = Object #2
// sOutput = The resref of the item to be created
// iQuantity = The number of items to create
// sHQOutput = The resref of the "high quality" item
// iHQQuantity = The number of "high quality" items to create
// iMixingSkill = oPC's mixing skill level. This is used to determine if HQ items can be made
// bItemAInfinite = If TRUE, item A will not be destroyed during combination
// bItemBInfinite = If TRUE, item B will not be destroyed during combination
//
// SPECIAL CODES:
// Quantity:
// SA: Quantity and HQ quantity become the size of item A (listed in the database)
// SB: Quantity and HQ quantity become the size of item B (listed in the database)
void COMBINE_CombineItemProcess(object oPC, object oItemA, object oItemB, string sOutput, string sQuantity, string sHQOutput = "", string sHQQuantity = "", int iMixingSkill = 0, string sDatabaseItemA = "", string sDatabaseItemB = "", int bItemAInfinite = FALSE, int bItemBInfinite = FALSE);
//////////////////////
// SYSTEM FUNCTIONS //
//////////////////////
void COMBINE_CombineItemProcess(object oPC, object oItemA, object oItemB, string sOutput, string sQuantity, string sHQOutput = "", string sHQQuantity = "", int iMixingSkill = 0, string sDatabaseItemA = "", string sDatabaseItemB = "", int bItemAInfinite = FALSE, int bItemBInfinite = FALSE)
{
int iQuantity;
int iHQQuantity = StringToInt(sHQQuantity);
string sResrefA = GetResRef(oItemA);
string sResrefB = GetResRef(oItemB);
// Special quantity codes functionality:
// SA: Quantity is the stack size of ItemA
// SB: Quantity is the stack size of ItemB
if(sQuantity == "SA")
{
if(sResrefB == sDatabaseItemA) iQuantity = GetItemStackSize(oItemB);
if(sResrefA == sDatabaseItemA) iQuantity = GetItemStackSize(oItemA);
iHQQuantity = iQuantity;
}
else if(sQuantity == "SB")
{
if(sResrefB == sDatabaseItemB) iQuantity = GetItemStackSize(oItemB);
if(sResrefA == sDatabaseItemB) iQuantity = GetItemStackSize(oItemA);
iHQQuantity = iQuantity;
}
// Otherwise use the specified quantities and HQ quantities
else iQuantity = StringToInt(sQuantity);
// Safety check
if(iQuantity < 1) iQuantity = 1;
if(!bItemAInfinite)
{
if(sResrefB == sDatabaseItemA)
DestroyObject(oItemB);
if(sResrefA == sDatabaseItemA)
DestroyObject(oItemA);
}
if(!bItemBInfinite)
{
if(sResrefB == sDatabaseItemB)
DestroyObject(oItemB);
if(sResrefA == sDatabaseItemB)
DestroyObject(oItemA);
}
string sOutputResref = sOutput;
int bHQMade = FALSE;
// Check to see if this is an HQ creation
if(sHQOutput != "" && iHQQuantity > 0 && iMixingSkill > 0)
{
// 50% chance to HQ at max mixing level (Level 20)
int iChance = FloatToInt(iMixingSkill * 2.5);
if(d100(1) <= iChance)
{
sOutputResref = sHQOutput;
iQuantity = iHQQuantity;
bHQMade = TRUE;
}
}
// Mixing skill also allows players to make more of an item than normal, if they aren't making an HQ item already
// The quantity made increases at a rate of an additional 2.5% per level of mixing.
if(!bHQMade && iQuantity > 1)
{
iQuantity = FloatToInt(((1 + (0.025 * iMixingSkill)) * iQuantity));
}
object oOutput = CreateItemOnObjectSafe(sOutputResref, oPC, iQuantity);
int iStackSize = GetItemStackSize(oOutput);
// Some items aren't stackable. If that's the case then we need to loop through and create each item
if(iStackSize == 1)
{
iQuantity --;
int iCurrentItem;
for(iCurrentItem = 1; iCurrentItem <= iQuantity; iCurrentItem++)
{
CreateItemOnObjectSafe(sOutputResref, oPC, iQuantity);
}
}
// Sometimes the item's stack size will be reached. If that's the case then we need to continue spawning
// items until all of them have been created
else if(iStackSize < iQuantity)
{
// We've already created the first stack, so remove that from the quantity
iQuantity = iQuantity - iStackSize;
while(iQuantity > 0)
{
// Still at least as large as the max stack size - create the new stack and reduce quantity
if(iQuantity >= iStackSize)
{
CreateItemOnObjectSafe(sOutputResref, oPC, iStackSize);
iQuantity = iQuantity - iStackSize;
}
// There's no more to create after this stack - create the new stack and set quantity to 0
else if(iQuantity < iStackSize)
{
CreateItemOnObjectSafe(sOutputResref, oPC, iQuantity);
iQuantity = 0;
}
}
}
}
void main()
{
object oPC = OBJECT_SELF;
object oItemA;
object oItemB;
if(ADV_USING_LINUX)
{
oItemA = GetEventItem();
oItemB = GetEventTarget();
}
else
{
oItemA = GetSpellTargetObject();
oItemB = GetSpellCastItem();
}
string sItemAResref = GetResRef(oItemA);
string sItemBResref = GetResRef(oItemB);
// Player's skill in mixing
int iMixingSkill = ADV_GetUpgradeLevel(oPC, ADV_ID_MIXING);
// You can't combine items that aren't in your inventory.
// You also can't if both of the items are the exact same.
if(GetItemPossessor(oItemA) != oPC || GetItemPossessor(oItemB) != oPC || oItemA == oItemB)
{
SendMessageToPC(oPC, ColorTokenRed() + COMBINE_MESSAGE_FAILED + ColorTokenEnd());
return;
}
string sSQL = "SELECT ItemA, ItemB, ItemAInfinite, ItemBInfinite, Output, Quantity, HQOutput, HQQuantity, MixingRequired FROM " + COMBINE_MYSQL_TABLE + " WHERE ItemA='" + sItemAResref + "' AND ItemB='" + sItemBResref +"'";
SQLExecDirect(sSQL);
// Combination is valid - create the new item and destroy the old ones.
if(SQLFetch() == SQL_SUCCESS)
{
string sDatabaseItemA = SQLGetData(1);
string sDatabaseItemB = SQLGetData(2);
int bItemAInfinite = StringToInt(SQLGetData(3));
int bItemBInfinite = StringToInt(SQLGetData(4));
string sOutput = SQLGetData(5);
string sQuantity = SQLGetData(6);
string sHQOutput = SQLGetData(7);
string sHQQuantity = SQLGetData(8);
int iMixingRequired = StringToInt(SQLGetData(9));
if(iMixingSkill >= iMixingRequired)
{
COMBINE_CombineItemProcess(oPC, oItemA, oItemB, sOutput, sQuantity, sHQOutput, sHQQuantity, iMixingSkill, sDatabaseItemA, sDatabaseItemB, bItemAInfinite, bItemBInfinite);
}
else
{
SendMessageToPC(oPC, ColorTokenRed() + COMBINE_MESSAGE_LOW_SKILL + " (Required: " + IntToString(iMixingRequired) + ")" + ColorTokenEnd());
}
return;
}
// Combination not valid - Try the alternative ordering. Note that IgnoreOrder field must be TRUE in order for this to work.
else
{
sSQL = "SELECT ItemA, ItemB, ItemAInfinite, ItemBInfinite, Output, Quantity, HQOutput, HQQuantity, MixingRequired, IgnoreOrder FROM " + COMBINE_MYSQL_TABLE + " WHERE ItemB='" + sItemAResref + "' AND ItemA='" + sItemBResref +"'";
SQLExecDirect(sSQL);
if(SQLFetch() == SQL_SUCCESS)
{
string sDatabaseItemA = SQLGetData(1);
string sDatabaseItemB = SQLGetData(2);
int bItemAInfinite = StringToInt(SQLGetData(3));
int bItemBInfinite = StringToInt(SQLGetData(4));
string sOutput = SQLGetData(5);
string sQuantity = SQLGetData(6);
string sHQOutput = SQLGetData(7);
string sHQQuantity = SQLGetData(8);
int iMixingRequired = StringToInt(SQLGetData(9));
int bIgnoreOrder = StringToInt(SQLGetData(10));
// IgnoreOrder field must be true in order for this to work.
if(bIgnoreOrder)
{
if(iMixingSkill >= iMixingRequired)
{
COMBINE_CombineItemProcess(oPC, oItemA, oItemB, sOutput, sQuantity, sHQOutput, sHQQuantity, iMixingSkill, sDatabaseItemA, sDatabaseItemB, bItemAInfinite, bItemBInfinite);
}
else
{
SendMessageToPC(oPC, ColorTokenRed() + COMBINE_MESSAGE_LOW_SKILL + ColorTokenEnd());
}
return;
}
}
}
// If we reach this point, then the combination has failed.
SendMessageToPC(oPC, ColorTokenRed() + COMBINE_MESSAGE_FAILED + ColorTokenEnd());
}