2026/03/28
Added default level up package for Warblade. Moment of Prescience should be an instant action. Truespeak should be a class skill for Factotum. Added Armor Enhancement, Lesser infusion. Added Armor Enhancement infusion. Added Armor Enhancement, Greater infusion Added Resistance Item infusion. Added Weapon Augmentation, Personal infusion. Added Weapon Augmentation infusion. Added Weapon Augmentation, Lesser infusion.
This commit is contained in:
849
nwn/nwnprc/trunk/newspellbook/inf_armor_enh.nss
Normal file
849
nwn/nwnprc/trunk/newspellbook/inf_armor_enh.nss
Normal file
@@ -0,0 +1,849 @@
|
||||
// inf_armor_enh.nss
|
||||
/*
|
||||
Armor Enhancement, Lesser
|
||||
Transmutation
|
||||
Level: Artificer 1
|
||||
Components: S, M
|
||||
Casting Time: 1 minute
|
||||
Range: Touch
|
||||
Target: Armor or shield touched
|
||||
Duration: 10 min./level
|
||||
Saving Throw: None (object)
|
||||
Spell Resistance: No (object)
|
||||
|
||||
The armor or shield you touch temporarily gains a special ability
|
||||
commonly found on magic armor or shields.
|
||||
You can choose any special ability whose market price is equivalent to
|
||||
a +1 bonus or up to 5,000 gp, such as light fortification or shadow.
|
||||
The armor or shield does not need to have an existing enhancement
|
||||
bonus, nor does it gain one when you imbue it with this infusion.
|
||||
Material Component: An ointment made from rare spices and minerals,
|
||||
costing 10 gp.
|
||||
|
||||
Armor Enhancement
|
||||
Transmutation
|
||||
Level: Artificer 2
|
||||
|
||||
As lesser armor enhancement, but you can choose any special ability
|
||||
whose market price is equivalent to a bonus of up to +3 or up to
|
||||
35,000 gp, such as ghost touch or acid resistance.
|
||||
Material Component: An ointment costing 50 gp.
|
||||
|
||||
Armor Enhancement, Greater
|
||||
Transmutation
|
||||
Level: Artificer 3
|
||||
|
||||
As lesser armor enhancement, but you can choose any special ability
|
||||
whose market price is equivalent to a bonus of up to +5 or up to
|
||||
100,000 gp, such as etherealness or greater fire resistance.
|
||||
Material Component: An ointment costing 100 gp.
|
||||
*/
|
||||
|
||||
#include "inc_debug"
|
||||
#include "prc_craft_inc"
|
||||
#include "inc_dynconv"
|
||||
|
||||
// Placeholder magic numbers for spell IDs
|
||||
const int ARMOR_ENH_LESS = 5001;
|
||||
const int ARMOR_ENH = 5002;
|
||||
const int ARMOR_ENH_GREATER = 5003;
|
||||
|
||||
// Dynamic conversation stages
|
||||
const int STAGE_PROPERTY_SELECTION = 0;
|
||||
const int STAGE_CONFIRMATION = 1;
|
||||
|
||||
|
||||
void HandleConversation(object oPC, object oArmor, int nMaxEnhancement, int nMaxCost, string sLocalVar, int nSpellID, int nCasterLevel)
|
||||
{
|
||||
int nValue = GetLocalInt(oPC, DYNCONV_VARIABLE);
|
||||
int nStage = GetStage(oPC);
|
||||
|
||||
if(nValue == 0) return;
|
||||
|
||||
if(nValue == DYNCONV_SETUP_STAGE)
|
||||
{
|
||||
if(!GetIsStageSetUp(nStage, oPC))
|
||||
{
|
||||
if(nStage == STAGE_PROPERTY_SELECTION)
|
||||
{
|
||||
// Set header first
|
||||
SetHeader("Select an armor enhancement:");
|
||||
|
||||
// Initialize default tokens BEFORE adding choices
|
||||
SetDefaultTokens();
|
||||
|
||||
// Read directly from craft_armour.2da
|
||||
int nFileEnd = PRCGetFileEnd("craft_armour");
|
||||
int nChoice = 1;
|
||||
int i;
|
||||
|
||||
for(i = 0; i <= nFileEnd; i++)
|
||||
{
|
||||
// Get enhancement and cost for this specific line
|
||||
int nEnhancement = StringToInt(Get2DACache("craft_armour", "Enhancement", i));
|
||||
int nAdditionalCost = StringToInt(Get2DACache("craft_armour", "AdditionalCost", i));
|
||||
string sName = GetStringByStrRef(StringToInt(Get2DACache("craft_armour", "Name", i)));
|
||||
|
||||
// Debug output
|
||||
SendMessageToPC(oPC, "Line " + IntToString(i) + ": " + sName + " (Enh:" + IntToString(nEnhancement) + ", Cost:" + IntToString(nAdditionalCost) + ")");
|
||||
|
||||
// Check if this property is within limits
|
||||
if(nEnhancement <= nMaxEnhancement && nAdditionalCost <= nMaxCost)
|
||||
{
|
||||
AddChoice(sName, i, oPC);
|
||||
nChoice++;
|
||||
}
|
||||
}
|
||||
|
||||
MarkStageSetUp(STAGE_PROPERTY_SELECTION, oPC);
|
||||
}
|
||||
else if(nStage == STAGE_CONFIRMATION)
|
||||
{
|
||||
int nPropertyLine = GetLocalInt(oPC, "ArmorEnh_SelectedProperty");
|
||||
string sName = GetStringByStrRef(StringToInt(Get2DACache("craft_armour", "Name", nPropertyLine)));
|
||||
|
||||
SetHeader("Apply " + sName + " to the armor?");
|
||||
|
||||
AddChoice("Yes", TRUE, oPC);
|
||||
AddChoice("No", FALSE, oPC);
|
||||
|
||||
MarkStageSetUp(STAGE_CONFIRMATION, oPC);
|
||||
}
|
||||
}
|
||||
|
||||
SetupTokens();
|
||||
}
|
||||
else if(nValue == DYNCONV_EXITED)
|
||||
{
|
||||
// Cleanup
|
||||
DeleteLocalInt(oPC, "ArmorEnh_ConvMode");
|
||||
DeleteLocalObject(oPC, "ARMOR_ENH_TARGET");
|
||||
DeleteLocalInt(oPC, "ArmorEnh_SelectedProperty");
|
||||
}
|
||||
else if(nValue == DYNCONV_ABORTED)
|
||||
{
|
||||
// Cleanup
|
||||
DeleteLocalInt(oPC, "ArmorEnh_ConvMode");
|
||||
DeleteLocalObject(oPC, "ARMOR_ENH_TARGET");
|
||||
DeleteLocalInt(oPC, "ArmorEnh_SelectedProperty");
|
||||
}
|
||||
else
|
||||
{
|
||||
int nChoice = GetChoice(oPC);
|
||||
|
||||
if(nStage == STAGE_PROPERTY_SELECTION)
|
||||
{
|
||||
// Store selection and go to confirmation
|
||||
SetLocalInt(oPC, "ArmorEnh_SelectedProperty", nChoice);
|
||||
nStage = STAGE_CONFIRMATION;
|
||||
MarkStageNotSetUp(STAGE_PROPERTY_SELECTION, oPC);
|
||||
}
|
||||
else if(nStage == STAGE_CONFIRMATION)
|
||||
{
|
||||
if(nChoice == TRUE) // User confirmed
|
||||
{
|
||||
// Apply the property
|
||||
object oArmor = GetLocalObject(oPC, "ARMOR_ENH_TARGET");
|
||||
int nPropertyLine = GetLocalInt(oPC, "ArmorEnh_SelectedProperty");
|
||||
int nCasterLevel = GetLocalInt(oPC, "ArmorEnh_CasterLevel");
|
||||
|
||||
float fDuration = TurnsToSeconds(nCasterLevel * 10);
|
||||
int nMetaMagic = PRCGetMetaMagicFeat();
|
||||
if(nMetaMagic & METAMAGIC_EXTEND)
|
||||
fDuration *= 2;
|
||||
|
||||
// Debug output
|
||||
SendMessageToPC(oPC, "Duration: " + FloatToString(fDuration) + " seconds");
|
||||
|
||||
// Add fallback for very small durations
|
||||
if (fDuration <= 1.0) fDuration = 30.0f;
|
||||
|
||||
SendMessageToPC(oPC, "Fallback Duration: " + FloatToString(fDuration) + " seconds");
|
||||
|
||||
// Create property directly
|
||||
itemproperty ip;
|
||||
/* if(nPropertyLine == 0)
|
||||
{
|
||||
// +1 Enhancement
|
||||
ip = ConstructIP(ITEM_PROPERTY_AC_BONUS, 0, 1, 0);
|
||||
}
|
||||
else
|
||||
{ */
|
||||
// Read property data from 2DA and construct
|
||||
string sIPData = Get2DACache("craft_armour", "IP1", nPropertyLine);
|
||||
struct ipstruct iptemp = GetIpStructFromString(sIPData);
|
||||
ip = ConstructIP(iptemp.type, iptemp.subtype, iptemp.costtablevalue, iptemp.param1value);
|
||||
//}
|
||||
|
||||
// Apply with proper duration
|
||||
ip = TagItemProperty(ip, "ArmorEnhInfusion");
|
||||
IPSafeAddItemProperty(oArmor, ip, fDuration, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, TRUE);
|
||||
|
||||
// Clean up and exit
|
||||
DeleteLocalInt(oPC, "ArmorEnh_ConvMode");
|
||||
DeleteLocalObject(oPC, "ARMOR_ENH_TARGET");
|
||||
DeleteLocalInt(oPC, "ArmorEnh_SelectedProperty");
|
||||
|
||||
AllowExit(DYNCONV_EXIT_FORCE_EXIT);
|
||||
}
|
||||
else // User cancelled
|
||||
{
|
||||
// Go back to property selection
|
||||
nStage = STAGE_PROPERTY_SELECTION;
|
||||
MarkStageNotSetUp(STAGE_CONFIRMATION, oPC);
|
||||
}
|
||||
}
|
||||
|
||||
SetStage(nStage, oPC);
|
||||
}
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
object oPC = GetPCSpeaker();
|
||||
if(!GetIsObjectValid(oPC)) oPC = OBJECT_SELF;
|
||||
|
||||
// Check if we're in conversation mode
|
||||
if(GetLocalInt(oPC, "ArmorEnh_ConvMode"))
|
||||
{
|
||||
// Retrieve parameters for conversation
|
||||
object oArmor = GetLocalObject(oPC, "ARMOR_ENH_TARGET");
|
||||
int nMaxEnhancement = GetLocalInt(oPC, "ArmorEnh_MaxEnh");
|
||||
int nMaxCost = GetLocalInt(oPC, "ArmorEnh_MaxCost");
|
||||
string sLocalVar = GetLocalString(oPC, "ArmorEnh_LocalVar");
|
||||
int nSpellID = GetLocalInt(oPC, "ArmorEnh_SpellID");
|
||||
int nCasterLevel = GetLocalInt(oPC, "ArmorEnh_CasterLevel");
|
||||
|
||||
HandleConversation(oPC, oArmor, nMaxEnhancement, nMaxCost, sLocalVar, nSpellID, nCasterLevel);
|
||||
return;
|
||||
}
|
||||
|
||||
// Normal spell execution
|
||||
PRCSetSchool(SPELL_SCHOOL_TRANSMUTATION);
|
||||
if (!X2PreSpellCastCode()) return;
|
||||
|
||||
object oCaster = OBJECT_SELF;
|
||||
object oTarget = PRCGetSpellTargetObject();
|
||||
int nCasterLevel = PRCGetCasterLevel(oCaster);
|
||||
int nSpellID = PRCGetSpellId();
|
||||
|
||||
// Declare variables
|
||||
int nGoldCost, nMaxEnhancement, nMaxCost;
|
||||
string sLocalVar;
|
||||
|
||||
// Set parameters based on spell level
|
||||
switch(nSpellID)
|
||||
{
|
||||
case ARMOR_ENH_LESS:
|
||||
nGoldCost = 10;
|
||||
nMaxEnhancement = 1;
|
||||
nMaxCost = 5000;
|
||||
sLocalVar = "ARMOR_ENH_LESS_PROPERTY";
|
||||
break;
|
||||
case ARMOR_ENH:
|
||||
nGoldCost = 50;
|
||||
nMaxEnhancement = 3;
|
||||
nMaxCost = 35000;
|
||||
sLocalVar = "ARMOR_ENH_PROPERTY";
|
||||
break;
|
||||
case ARMOR_ENH_GREATER:
|
||||
nGoldCost = 100;
|
||||
nMaxEnhancement = 5;
|
||||
nMaxCost = 100000;
|
||||
sLocalVar = "ARMOR_ENH_GREATER_PROPERTY";
|
||||
break;
|
||||
default:
|
||||
// Default to lesser version for testing
|
||||
nGoldCost = 10;
|
||||
nMaxEnhancement = 1;
|
||||
nMaxCost = 5000;
|
||||
sLocalVar = "ARMOR_ENH_LESS_PROPERTY";
|
||||
break;
|
||||
}
|
||||
|
||||
// Check material component
|
||||
if(GetGold(oCaster) < nGoldCost)
|
||||
{
|
||||
FloatingTextStringOnCreature("You need " + IntToString(nGoldCost) + "gp worth of rare spices and minerals.", oCaster, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get targeted armor or shield
|
||||
object oArmor = GetItemInSlot(INVENTORY_SLOT_CHEST, oCaster);
|
||||
//object oArmor = IPGetTargetedOrEquippedArmor(TRUE); <- don't delete
|
||||
if(!GetIsObjectValid(oArmor))
|
||||
{
|
||||
FloatingTextStrRefOnCreature(83826, oCaster, FALSE); // "Invalid target"
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if returning from conversation with a selection
|
||||
int nPropertyLine = GetLocalInt(oCaster, sLocalVar);
|
||||
if(nPropertyLine > 0)
|
||||
{
|
||||
// Apply the property
|
||||
float fDuration = TurnsToSeconds(nCasterLevel * 10);
|
||||
int nMetaMagic = PRCGetMetaMagicFeat();
|
||||
if(nMetaMagic & METAMAGIC_EXTEND)
|
||||
fDuration *= 2;
|
||||
|
||||
if (fDuration <= 1.0) fDuration = 30.0f;
|
||||
|
||||
// Create property directly
|
||||
itemproperty ip;
|
||||
|
||||
// Read property data from 2DA and construct
|
||||
string sIPData = Get2DACache("craft_armour", "IP1", nPropertyLine);
|
||||
struct ipstruct iptemp = GetIpStructFromString(sIPData);
|
||||
ip = ConstructIP(iptemp.type, iptemp.subtype, iptemp.costtablevalue, iptemp.param1value);
|
||||
|
||||
// Apply with proper duration
|
||||
ip = TagItemProperty(ip, "ArmorEnhInfusion");
|
||||
IPSafeAddItemProperty(oArmor, ip, fDuration, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, TRUE);
|
||||
|
||||
DeleteLocalInt(oCaster, sLocalVar);
|
||||
return;
|
||||
}
|
||||
|
||||
// Store parameters for conversation and start it
|
||||
SetLocalInt(oPC, "ArmorEnh_ConvMode", 1);
|
||||
SetLocalObject(oPC, "ARMOR_ENH_TARGET", oArmor);
|
||||
SetLocalInt(oPC, "ArmorEnh_MaxEnh", nMaxEnhancement);
|
||||
SetLocalInt(oPC, "ArmorEnh_MaxCost", nMaxCost);
|
||||
SetLocalString(oPC, "ArmorEnh_LocalVar", sLocalVar);
|
||||
SetLocalInt(oPC, "ArmorEnh_SpellID", nSpellID);
|
||||
SetLocalInt(oPC, "ArmorEnh_CasterLevel", nCasterLevel);
|
||||
|
||||
// Start the dynamic conversation using this same script
|
||||
StartDynamicConversation("inf_armor_enh", oPC, 0, FALSE, TRUE);
|
||||
}
|
||||
|
||||
|
||||
/* void HandleConversation(object oPC, object oArmor, int nMaxEnhancement, int nMaxCost, string sLocalVar, int nSpellID, int nCasterLevel)
|
||||
{
|
||||
int nValue = GetLocalInt(oPC, DYNCONV_VARIABLE);
|
||||
int nStage = GetStage(oPC);
|
||||
|
||||
if(nValue == 0) return;
|
||||
|
||||
if(nValue == DYNCONV_SETUP_STAGE)
|
||||
{
|
||||
if(!GetIsStageSetUp(nStage, oPC))
|
||||
{
|
||||
if(nStage == STAGE_PROPERTY_SELECTION)
|
||||
{
|
||||
// Set header first
|
||||
SetHeader("Select an armor enhancement:");
|
||||
|
||||
// Initialize default tokens BEFORE adding choices
|
||||
SetDefaultTokens();
|
||||
|
||||
// Read directly from craft_armour.2da
|
||||
int nFileEnd = PRCGetFileEnd("craft_armour");
|
||||
int nChoice = 1;
|
||||
int i;
|
||||
|
||||
for(i = 0; i <= nFileEnd; i++)
|
||||
{
|
||||
// Get enhancement and cost for this specific line
|
||||
int nEnhancement = StringToInt(Get2DACache("craft_armour", "Enhancement", i));
|
||||
int nAdditionalCost = StringToInt(Get2DACache("craft_armour", "AdditionalCost", i));
|
||||
string sName = GetStringByStrRef(StringToInt(Get2DACache("craft_armour", "Name", i)));
|
||||
|
||||
// Debug output
|
||||
SendMessageToPC(oPC, "Line " + IntToString(i) + ": " + sName + " (Enh:" + IntToString(nEnhancement) + ", Cost:" + IntToString(nAdditionalCost) + ")");
|
||||
|
||||
// Check if this property is within limits
|
||||
if(nEnhancement <= nMaxEnhancement && nAdditionalCost <= nMaxCost)
|
||||
{
|
||||
AddChoice(sName, i, oPC);
|
||||
nChoice++;
|
||||
}
|
||||
}
|
||||
|
||||
MarkStageSetUp(STAGE_PROPERTY_SELECTION, oPC);
|
||||
}
|
||||
else if(nStage == STAGE_CONFIRMATION)
|
||||
{
|
||||
int nPropertyLine = GetLocalInt(oPC, "ArmorEnh_SelectedProperty");
|
||||
|
||||
string sName = GetStringByStrRef(StringToInt(Get2DACache("craft_armour", "Name", nPropertyLine)));
|
||||
|
||||
SetHeader("Apply " + sName + " to the armor?");
|
||||
|
||||
AddChoice("Yes", TRUE, oPC);
|
||||
AddChoice("No", FALSE, oPC);
|
||||
|
||||
MarkStageSetUp(STAGE_CONFIRMATION, oPC);
|
||||
}
|
||||
}
|
||||
|
||||
SetupTokens();
|
||||
}
|
||||
else if(nValue == DYNCONV_EXITED)
|
||||
{
|
||||
// Cleanup
|
||||
DeleteLocalInt(oPC, "ArmorEnh_ConvMode");
|
||||
DeleteLocalObject(oPC, "ARMOR_ENH_TARGET");
|
||||
DeleteLocalInt(oPC, "ArmorEnh_SelectedProperty");
|
||||
}
|
||||
else if(nValue == DYNCONV_ABORTED)
|
||||
{
|
||||
// Cleanup
|
||||
DeleteLocalInt(oPC, "ArmorEnh_ConvMode");
|
||||
DeleteLocalObject(oPC, "ARMOR_ENH_TARGET");
|
||||
DeleteLocalInt(oPC, "ArmorEnh_SelectedProperty");
|
||||
}
|
||||
else
|
||||
{
|
||||
int nChoice = GetChoice(oPC);
|
||||
|
||||
if(nStage == STAGE_PROPERTY_SELECTION)
|
||||
{
|
||||
// Store selection and go to confirmation
|
||||
SetLocalInt(oPC, "ArmorEnh_SelectedProperty", nChoice);
|
||||
nStage = STAGE_CONFIRMATION;
|
||||
MarkStageNotSetUp(STAGE_PROPERTY_SELECTION, oPC);
|
||||
}
|
||||
else if(nStage == STAGE_CONFIRMATION)
|
||||
{
|
||||
if(nChoice == TRUE) // User confirmed
|
||||
{
|
||||
// Apply the property
|
||||
object oArmor = GetLocalObject(oPC, "ARMOR_ENH_TARGET");
|
||||
int nPropertyLine = GetLocalInt(oPC, "ArmorEnh_SelectedProperty");
|
||||
int nCasterLevel = GetLocalInt(oPC, "ArmorEnh_CasterLevel");
|
||||
|
||||
float fDuration = TurnsToSeconds(nCasterLevel * 10);
|
||||
int nMetaMagic = PRCGetMetaMagicFeat();
|
||||
if(nMetaMagic & METAMAGIC_EXTEND)
|
||||
fDuration *= 2;
|
||||
|
||||
// Debug output
|
||||
SendMessageToPC(oPC, "Duration: " + FloatToString(fDuration) + " seconds");
|
||||
|
||||
// Add fallback for very small durations
|
||||
if (fDuration <= 1.0) fDuration = 30.0f;
|
||||
|
||||
// Create property directly
|
||||
itemproperty ip;
|
||||
if(nPropertyLine == 0)
|
||||
{
|
||||
// +1 Enhancement
|
||||
ip = ConstructIP(ITEM_PROPERTY_AC_BONUS, 0, 1, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Read property data from 2DA and construct
|
||||
string sIPData = Get2DACache("craft_armour", "IP1", nPropertyLine);
|
||||
struct ipstruct iptemp = GetIpStructFromString(sIPData);
|
||||
ip = ConstructIP(iptemp.type, iptemp.subtype, iptemp.costtablevalue, iptemp.param1value);
|
||||
}
|
||||
|
||||
// Apply with proper duration
|
||||
ip = TagItemProperty(ip, "ArmorEnhInfusion");
|
||||
IPSafeAddItemProperty(oArmor, ip, fDuration, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, TRUE);
|
||||
|
||||
// Clean up and exit
|
||||
DeleteLocalInt(oPC, "ArmorEnh_ConvMode");
|
||||
DeleteLocalObject(oPC, "ARMOR_ENH_TARGET");
|
||||
DeleteLocalInt(oPC, "ArmorEnh_SelectedProperty");
|
||||
|
||||
AllowExit(DYNCONV_EXIT_FORCE_EXIT);
|
||||
return;
|
||||
}
|
||||
else // User cancelled
|
||||
{
|
||||
// Go back to property selection
|
||||
nStage = STAGE_PROPERTY_SELECTION;
|
||||
MarkStageNotSetUp(STAGE_CONFIRMATION, oPC);
|
||||
}
|
||||
}
|
||||
|
||||
SetStage(nStage, oPC);
|
||||
}
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
object oPC = GetPCSpeaker();
|
||||
if(!GetIsObjectValid(oPC)) oPC = OBJECT_SELF;
|
||||
|
||||
// Check if we're in conversation mode
|
||||
if(GetLocalInt(oPC, "ArmorEnh_ConvMode"))
|
||||
{
|
||||
// Retrieve parameters for conversation
|
||||
object oArmor = GetLocalObject(oPC, "ARMOR_ENH_TARGET");
|
||||
int nMaxEnhancement = GetLocalInt(oPC, "ArmorEnh_MaxEnh");
|
||||
int nMaxCost = GetLocalInt(oPC, "ArmorEnh_MaxCost");
|
||||
string sLocalVar = GetLocalString(oPC, "ArmorEnh_LocalVar");
|
||||
int nSpellID = GetLocalInt(oPC, "ArmorEnh_SpellID");
|
||||
int nCasterLevel = GetLocalInt(oPC, "ArmorEnh_CasterLevel");
|
||||
|
||||
HandleConversation(oPC, oArmor, nMaxEnhancement, nMaxCost, sLocalVar, nSpellID, nCasterLevel);
|
||||
return;
|
||||
}
|
||||
|
||||
// Normal spell execution
|
||||
PRCSetSchool(SPELL_SCHOOL_TRANSMUTATION);
|
||||
if (!X2PreSpellCastCode()) return;
|
||||
|
||||
object oCaster = OBJECT_SELF;
|
||||
object oTarget = PRCGetSpellTargetObject();
|
||||
int nCasterLevel = PRCGetCasterLevel(oCaster);
|
||||
//int nSpellID = PRCGetSpellId();
|
||||
int nSpellID = ARMOR_ENH_GREATER;
|
||||
|
||||
// Declare variables
|
||||
int nGoldCost, nMaxEnhancement, nMaxCost;
|
||||
string sLocalVar;
|
||||
|
||||
// Set parameters based on spell level
|
||||
switch(nSpellID)
|
||||
{
|
||||
case ARMOR_ENH_LESS:
|
||||
nGoldCost = 10;
|
||||
nMaxEnhancement = 1;
|
||||
nMaxCost = 5000;
|
||||
sLocalVar = "ARMOR_ENH_LESS_PROPERTY";
|
||||
break;
|
||||
case ARMOR_ENH:
|
||||
nGoldCost = 50;
|
||||
nMaxEnhancement = 3;
|
||||
nMaxCost = 35000;
|
||||
sLocalVar = "ARMOR_ENH_PROPERTY";
|
||||
break;
|
||||
case ARMOR_ENH_GREATER:
|
||||
nGoldCost = 100;
|
||||
nMaxEnhancement = 5;
|
||||
nMaxCost = 100000;
|
||||
sLocalVar = "ARMOR_ENH_GREATER_PROPERTY";
|
||||
break;
|
||||
default:
|
||||
// Default to lesser version for testing
|
||||
nGoldCost = 10;
|
||||
nMaxEnhancement = 1;
|
||||
nMaxCost = 5000;
|
||||
sLocalVar = "ARMOR_ENH_LESS_PROPERTY";
|
||||
break;
|
||||
}
|
||||
|
||||
// Check material component
|
||||
if(GetGold(oCaster) < nGoldCost)
|
||||
{
|
||||
FloatingTextStringOnCreature("You need " + IntToString(nGoldCost) + "gp worth of rare spices and minerals.", oCaster, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get targeted armor or shield
|
||||
object oArmor = GetItemInSlot(INVENTORY_SLOT_CHEST, oCaster);
|
||||
if(!GetIsObjectValid(oArmor))
|
||||
{
|
||||
FloatingTextStrRefOnCreature(83826, oCaster, FALSE); // "Invalid target"
|
||||
return;
|
||||
}
|
||||
|
||||
// Store parameters for conversation and start it
|
||||
SetLocalInt(oPC, "ArmorEnh_ConvMode", 1);
|
||||
SetLocalObject(oPC, "ARMOR_ENH_TARGET", oArmor);
|
||||
SetLocalInt(oPC, "ArmorEnh_MaxEnh", nMaxEnhancement);
|
||||
SetLocalInt(oPC, "ArmorEnh_MaxCost", nMaxCost);
|
||||
SetLocalString(oPC, "ArmorEnh_LocalVar", sLocalVar);
|
||||
SetLocalInt(oPC, "ArmorEnh_SpellID", nSpellID);
|
||||
SetLocalInt(oPC, "ArmorEnh_CasterLevel", nCasterLevel);
|
||||
|
||||
// Start the dynamic conversation using this same script
|
||||
DelayCommand(0.1f, StartDynamicConversation("inf_armor_enh", oPC, 0, FALSE, TRUE));
|
||||
} */
|
||||
|
||||
|
||||
|
||||
/* void HandleConversation(object oPC, object oArmor, int nMaxEnhancement, int nMaxCost, string sLocalVar, int nSpellID, int nCasterLevel)
|
||||
{
|
||||
int nValue = GetLocalInt(oPC, DYNCONV_VARIABLE);
|
||||
int nStage = GetStage(oPC);
|
||||
|
||||
if(nValue == 0) return;
|
||||
|
||||
if(nValue == DYNCONV_SETUP_STAGE)
|
||||
{
|
||||
if(!GetIsStageSetUp(nStage, oPC))
|
||||
{
|
||||
if(nStage == STAGE_PROPERTY_SELECTION)
|
||||
{
|
||||
// Set header first
|
||||
SetHeader("Select an armor enhancement:");
|
||||
|
||||
// Initialize default tokens BEFORE adding choices
|
||||
SetDefaultTokens();
|
||||
|
||||
// Read directly from craft_armour.2da
|
||||
int nFileEnd = PRCGetFileEnd("craft_armour");
|
||||
int nChoice = 1;
|
||||
int i;
|
||||
|
||||
AddChoice("Enhancement +1", 0, oPC);
|
||||
|
||||
for(i = 1; i <= nFileEnd; i++)
|
||||
{
|
||||
// Get enhancement and cost for this specific line
|
||||
int nEnhancement = StringToInt(Get2DACache("craft_armour", "Enhancement", i));
|
||||
int nAdditionalCost = StringToInt(Get2DACache("craft_armour", "AdditionalCost", i));
|
||||
string sName = GetStringByStrRef(StringToInt(Get2DACache("craft_armour", "Name", i)));
|
||||
|
||||
// Debug output
|
||||
SendMessageToPC(oPC, "Line " + IntToString(i) + ": " + sName + " (Enh:" + IntToString(nEnhancement) + ", Cost:" + IntToString(nAdditionalCost) + ")");
|
||||
|
||||
// Check if this property is within limits
|
||||
if(nEnhancement <= nMaxEnhancement && nAdditionalCost <= nMaxCost)
|
||||
{
|
||||
AddChoice(sName, i, oPC);
|
||||
nChoice++;
|
||||
}
|
||||
}
|
||||
|
||||
MarkStageSetUp(STAGE_PROPERTY_SELECTION, oPC);
|
||||
}
|
||||
else if(nStage == STAGE_CONFIRMATION)
|
||||
{
|
||||
int nPropertyLine = GetLocalInt(oPC, "ArmorEnh_SelectedProperty");
|
||||
string sName;
|
||||
|
||||
if(nPropertyLine == 0)
|
||||
sName = "Enhancement +1";
|
||||
else
|
||||
sName = GetStringByStrRef(StringToInt(Get2DACache("craft_armour", "Name", nPropertyLine)));
|
||||
|
||||
SetHeader("Apply " + sName + " to the armor?");
|
||||
|
||||
AddChoice("Yes", TRUE, oPC);
|
||||
AddChoice("No", FALSE, oPC);
|
||||
|
||||
MarkStageSetUp(STAGE_CONFIRMATION, oPC);
|
||||
}
|
||||
}
|
||||
|
||||
SetupTokens();
|
||||
}
|
||||
else if(nValue == DYNCONV_EXITED)
|
||||
{
|
||||
// Cleanup
|
||||
DeleteLocalInt(oPC, "ArmorEnh_ConvMode");
|
||||
DeleteLocalObject(oPC, "ARMOR_ENH_TARGET");
|
||||
DeleteLocalInt(oPC, "ArmorEnh_SelectedProperty");
|
||||
}
|
||||
else if(nValue == DYNCONV_ABORTED)
|
||||
{
|
||||
// Cleanup
|
||||
DeleteLocalInt(oPC, "ArmorEnh_ConvMode");
|
||||
DeleteLocalObject(oPC, "ARMOR_ENH_TARGET");
|
||||
DeleteLocalInt(oPC, "ArmorEnh_SelectedProperty");
|
||||
}
|
||||
else
|
||||
{
|
||||
int nChoice = GetChoice(oPC);
|
||||
|
||||
if(nStage == STAGE_PROPERTY_SELECTION)
|
||||
{
|
||||
// Store selection and go to confirmation
|
||||
SetLocalInt(oPC, "ArmorEnh_SelectedProperty", nChoice);
|
||||
nStage = STAGE_CONFIRMATION;
|
||||
MarkStageNotSetUp(STAGE_PROPERTY_SELECTION, oPC);
|
||||
}
|
||||
else if(nStage == STAGE_CONFIRMATION)
|
||||
{
|
||||
if(nChoice == TRUE) // User confirmed
|
||||
{
|
||||
// Apply the property
|
||||
object oArmor = GetLocalObject(oPC, "ARMOR_ENH_TARGET");
|
||||
int nPropertyLine = GetLocalInt(oPC, "ArmorEnh_SelectedProperty");
|
||||
int nCasterLevel = GetLocalInt(oPC, "ArmorEnh_CasterLevel");
|
||||
|
||||
float fDuration = TurnsToSeconds(nCasterLevel * 10);
|
||||
int nMetaMagic = PRCGetMetaMagicFeat();
|
||||
if(nMetaMagic & METAMAGIC_EXTEND)
|
||||
fDuration *= 2;
|
||||
|
||||
// Debug output
|
||||
SendMessageToPC(oPC, "Duration: " + FloatToString(fDuration) + " seconds");
|
||||
|
||||
// Add fallback for very small durations
|
||||
if (fDuration <= 1.0) fDuration = 30.0f;
|
||||
|
||||
// Create property directly
|
||||
itemproperty ip;
|
||||
if(nPropertyLine == 0)
|
||||
{
|
||||
// +1 Enhancement
|
||||
ip = ConstructIP(ITEM_PROPERTY_AC_BONUS, 0, 1, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Read property data from 2DA and construct
|
||||
string sIPData = Get2DACache("craft_armour", "IP1", nPropertyLine);
|
||||
struct ipstruct iptemp = GetIpStructFromString(sIPData);
|
||||
ip = ConstructIP(iptemp.type, iptemp.subtype, iptemp.costtablevalue, iptemp.param1value);
|
||||
}
|
||||
|
||||
// Apply with proper duration
|
||||
ip = TagItemProperty(ip, "ArmorEnhInfusion");
|
||||
IPSafeAddItemProperty(oArmor, ip, fDuration, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, TRUE);
|
||||
|
||||
// Clean up and exit
|
||||
DeleteLocalInt(oPC, "ArmorEnh_ConvMode");
|
||||
DeleteLocalObject(oPC, "ARMOR_ENH_TARGET");
|
||||
DeleteLocalInt(oPC, "ArmorEnh_SelectedProperty");
|
||||
|
||||
AllowExit(DYNCONV_EXIT_FORCE_EXIT);
|
||||
}
|
||||
else // User cancelled
|
||||
{
|
||||
// Go back to property selection
|
||||
nStage = STAGE_PROPERTY_SELECTION;
|
||||
MarkStageNotSetUp(STAGE_CONFIRMATION, oPC);
|
||||
}
|
||||
}
|
||||
|
||||
SetStage(nStage, oPC);
|
||||
}
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
object oPC = GetPCSpeaker();
|
||||
if(!GetIsObjectValid(oPC)) oPC = OBJECT_SELF;
|
||||
|
||||
// Check if we're in conversation mode
|
||||
if(GetLocalInt(oPC, "ArmorEnh_ConvMode"))
|
||||
{
|
||||
// Retrieve parameters for conversation
|
||||
object oArmor = GetLocalObject(oPC, "ARMOR_ENH_TARGET");
|
||||
int nMaxEnhancement = GetLocalInt(oPC, "ArmorEnh_MaxEnh");
|
||||
int nMaxCost = GetLocalInt(oPC, "ArmorEnh_MaxCost");
|
||||
string sLocalVar = GetLocalString(oPC, "ArmorEnh_LocalVar");
|
||||
int nSpellID = GetLocalInt(oPC, "ArmorEnh_SpellID");
|
||||
int nCasterLevel = GetLocalInt(oPC, "ArmorEnh_CasterLevel");
|
||||
|
||||
HandleConversation(oPC, oArmor, nMaxEnhancement, nMaxCost, sLocalVar, nSpellID, nCasterLevel);
|
||||
return;
|
||||
}
|
||||
|
||||
// Normal spell execution
|
||||
PRCSetSchool(SPELL_SCHOOL_TRANSMUTATION);
|
||||
if (!X2PreSpellCastCode()) return;
|
||||
|
||||
object oCaster = OBJECT_SELF;
|
||||
object oTarget = PRCGetSpellTargetObject();
|
||||
int nCasterLevel = PRCGetCasterLevel(oCaster);
|
||||
int nSpellID = PRCGetSpellId();
|
||||
|
||||
// Declare variables
|
||||
int nGoldCost, nMaxEnhancement, nMaxCost;
|
||||
string sLocalVar;
|
||||
|
||||
// Set parameters based on spell level
|
||||
switch(nSpellID)
|
||||
{
|
||||
case ARMOR_ENH_LESS:
|
||||
nGoldCost = 10;
|
||||
nMaxEnhancement = 1;
|
||||
nMaxCost = 5000;
|
||||
sLocalVar = "ARMOR_ENH_LESS_PROPERTY";
|
||||
break;
|
||||
case ARMOR_ENH:
|
||||
nGoldCost = 50;
|
||||
nMaxEnhancement = 3;
|
||||
nMaxCost = 35000;
|
||||
sLocalVar = "ARMOR_ENH_PROPERTY";
|
||||
break;
|
||||
case ARMOR_ENH_GREATER:
|
||||
nGoldCost = 100;
|
||||
nMaxEnhancement = 5;
|
||||
nMaxCost = 100000;
|
||||
sLocalVar = "ARMOR_ENH_GREATER_PROPERTY";
|
||||
break;
|
||||
default:
|
||||
// Default to lesser version for testing
|
||||
nGoldCost = 10;
|
||||
nMaxEnhancement = 1;
|
||||
nMaxCost = 5000;
|
||||
sLocalVar = "ARMOR_ENH_LESS_PROPERTY";
|
||||
break;
|
||||
}
|
||||
|
||||
// Check material component
|
||||
if(GetGold(oCaster) < nGoldCost)
|
||||
{
|
||||
FloatingTextStringOnCreature("You need " + IntToString(nGoldCost) + "gp worth of rare spices and minerals.", oCaster, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get targeted armor or shield
|
||||
object oArmor = GetItemInSlot(INVENTORY_SLOT_CHEST, oCaster);
|
||||
if(!GetIsObjectValid(oArmor))
|
||||
{
|
||||
FloatingTextStrRefOnCreature(83826, oCaster, FALSE); // "Invalid target"
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if item already has an infusion
|
||||
itemproperty ipExisting = GetFirstItemProperty(oArmor);
|
||||
while(GetIsItemPropertyValid(ipExisting))
|
||||
{
|
||||
if(GetItemPropertyTag(ipExisting) == "ArmorEnhInfusion")
|
||||
{
|
||||
FloatingTextStringOnCreature("This armor already has an armor enhancement infusion.", oCaster, FALSE);
|
||||
return;
|
||||
}
|
||||
ipExisting = GetNextItemProperty(oArmor);
|
||||
}
|
||||
|
||||
// Check if returning from conversation with a selection
|
||||
int nPropertyLine = GetLocalInt(oCaster, sLocalVar);
|
||||
if(nPropertyLine > 0)
|
||||
{
|
||||
// Apply the property
|
||||
float fDuration = TurnsToSeconds(nCasterLevel * 10);
|
||||
int nMetaMagic = PRCGetMetaMagicFeat();
|
||||
if(nMetaMagic & METAMAGIC_EXTEND)
|
||||
fDuration *= 2;
|
||||
|
||||
if (fDuration <= 1.0) fDuration = 30.0f;
|
||||
|
||||
// Create property directly
|
||||
itemproperty ip;
|
||||
if(nPropertyLine == 0)
|
||||
{
|
||||
// +1 Enhancement
|
||||
ip = ConstructIP(ITEM_PROPERTY_AC_BONUS, 0, 1, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Read property data from 2DA and construct
|
||||
string sIPData = Get2DACache("craft_armour", "IP1", nPropertyLine);
|
||||
struct ipstruct iptemp = GetIpStructFromString(sIPData);
|
||||
ip = ConstructIP(iptemp.type, iptemp.subtype, iptemp.costtablevalue, iptemp.param1value);
|
||||
}
|
||||
|
||||
// Apply with proper duration
|
||||
ip = TagItemProperty(ip, "ArmorEnhInfusion");
|
||||
IPSafeAddItemProperty(oArmor, ip, fDuration, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, TRUE);
|
||||
|
||||
DeleteLocalInt(oCaster, sLocalVar);
|
||||
return;
|
||||
}
|
||||
|
||||
// Store parameters for conversation and start it
|
||||
SetLocalInt(oPC, "ArmorEnh_ConvMode", 1);
|
||||
SetLocalObject(oPC, "ARMOR_ENH_TARGET", oArmor);
|
||||
SetLocalInt(oPC, "ArmorEnh_MaxEnh", nMaxEnhancement);
|
||||
SetLocalInt(oPC, "ArmorEnh_MaxCost", nMaxCost);
|
||||
SetLocalString(oPC, "ArmorEnh_LocalVar", sLocalVar);
|
||||
SetLocalInt(oPC, "ArmorEnh_SpellID", nSpellID);
|
||||
SetLocalInt(oPC, "ArmorEnh_CasterLevel", nCasterLevel);
|
||||
|
||||
// Start the dynamic conversation using this same script
|
||||
StartDynamicConversation("inf_armor_enh", oPC, 0, FALSE, TRUE);
|
||||
}
|
||||
|
||||
*/
|
||||
158
nwn/nwnprc/trunk/newspellbook/inf_energy_alt.nss
Normal file
158
nwn/nwnprc/trunk/newspellbook/inf_energy_alt.nss
Normal file
@@ -0,0 +1,158 @@
|
||||
// inf_energy_alt.nss
|
||||
#include "prc_sp_func"
|
||||
#include "prc_inc_spells"
|
||||
#include "psi_inc_enrgypow"
|
||||
#include "prc_craft_inc" // Add this for item property serialization
|
||||
|
||||
const int SPELL_ENERGY_ALTERATION_COLD = 9000;
|
||||
const int SPELL_ENERGY_ALTERATION_ELEC = 9001;
|
||||
const int SPELL_ENERGY_ALTERATION_FIRE = 9002;
|
||||
const int SPELL_ENERGY_ALTERATION_SONIC = 9003;
|
||||
|
||||
// Forward declarations
|
||||
void StoreOriginalProperties(object oItem);
|
||||
void RestoreOriginalProperties(object oItem);
|
||||
int ConvertDamageTypeToIPConst(int nDamageType);
|
||||
|
||||
// Convert DAMAGE_TYPE_* to IP_CONST_DAMAGETYPE_*
|
||||
int ConvertDamageTypeToIPConst(int nDamageType)
|
||||
{
|
||||
switch(nDamageType)
|
||||
{
|
||||
case DAMAGE_TYPE_ACID: return IP_CONST_DAMAGETYPE_ACID;
|
||||
case DAMAGE_TYPE_COLD: return IP_CONST_DAMAGETYPE_COLD;
|
||||
case DAMAGE_TYPE_ELECTRICAL: return IP_CONST_DAMAGETYPE_ELECTRICAL;
|
||||
case DAMAGE_TYPE_FIRE: return IP_CONST_DAMAGETYPE_FIRE;
|
||||
case DAMAGE_TYPE_SONIC: return IP_CONST_DAMAGETYPE_SONIC;
|
||||
default: return IP_CONST_DAMAGETYPE_ACID;
|
||||
}
|
||||
return IP_CONST_DAMAGETYPE_ACID; // Add explicit return for compiler
|
||||
}
|
||||
|
||||
void ApplyEnergyAlteration(object oItem, int nSpellID, int nCasterLvl)
|
||||
{
|
||||
struct energy_adjustments enAdj = EvaluateEnergy(
|
||||
nSpellID,
|
||||
SPELL_ENERGY_ALTERATION_COLD,
|
||||
SPELL_ENERGY_ALTERATION_ELEC,
|
||||
SPELL_ENERGY_ALTERATION_FIRE,
|
||||
SPELL_ENERGY_ALTERATION_SONIC
|
||||
);
|
||||
|
||||
// Modify existing energy properties
|
||||
itemproperty ip = GetFirstItemProperty(oItem);
|
||||
while(GetIsItemPropertyValid(ip))
|
||||
{
|
||||
int nType = GetItemPropertyType(ip);
|
||||
|
||||
// Replace damage bonus properties
|
||||
if(nType == ITEM_PROPERTY_DAMAGE_BONUS)
|
||||
{
|
||||
int nDamageType = GetItemPropertySubType(ip);
|
||||
if(nDamageType == DAMAGE_TYPE_ACID || nDamageType == DAMAGE_TYPE_COLD ||
|
||||
nDamageType == DAMAGE_TYPE_ELECTRICAL || nDamageType == DAMAGE_TYPE_FIRE ||
|
||||
nDamageType == DAMAGE_TYPE_SONIC)
|
||||
{
|
||||
RemoveItemProperty(oItem, ip);
|
||||
itemproperty ipNew = ItemPropertyDamageBonus(enAdj.nDamageType, GetItemPropertyCostTableValue(ip));
|
||||
AddItemProperty(DURATION_TYPE_TEMPORARY, ipNew, oItem, RoundsToSeconds(nCasterLvl * 10));
|
||||
SetLocalInt(oItem, "EnergyAlter_Temp_" + IntToString(ITEM_PROPERTY_DAMAGE_BONUS), TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
// Replace resistance properties
|
||||
if(nType == ITEM_PROPERTY_DAMAGE_RESISTANCE)
|
||||
{
|
||||
int nResistType = GetItemPropertySubType(ip);
|
||||
if(nResistType == IP_CONST_DAMAGETYPE_ACID || nResistType == IP_CONST_DAMAGETYPE_COLD ||
|
||||
nResistType == IP_CONST_DAMAGETYPE_ELECTRICAL || nResistType == IP_CONST_DAMAGETYPE_FIRE ||
|
||||
nResistType == IP_CONST_DAMAGETYPE_SONIC)
|
||||
{
|
||||
RemoveItemProperty(oItem, ip);
|
||||
int nNewType = ConvertDamageTypeToIPConst(enAdj.nDamageType);
|
||||
itemproperty ipNew = ItemPropertyDamageResistance(nNewType, GetItemPropertyCostTableValue(ip));
|
||||
AddItemProperty(DURATION_TYPE_TEMPORARY, ipNew, oItem, RoundsToSeconds(nCasterLvl * 10));
|
||||
SetLocalInt(oItem, "EnergyAlter_Temp_" + IntToString(ITEM_PROPERTY_DAMAGE_RESISTANCE), TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
ip = GetNextItemProperty(oItem);
|
||||
}
|
||||
|
||||
// Schedule restoration
|
||||
DelayCommand(RoundsToSeconds(nCasterLvl * 10), RestoreOriginalProperties(oItem));
|
||||
}
|
||||
|
||||
// Store original properties with PRC persistent backup
|
||||
void StoreOriginalProperties(object oItem)
|
||||
{
|
||||
string sItemID = GetObjectUUID(oItem);
|
||||
itemproperty ip = GetFirstItemProperty(oItem);
|
||||
|
||||
while(GetIsItemPropertyValid(ip))
|
||||
{
|
||||
string sPropData = GetItemPropertyString(ip); // Use PRC's function
|
||||
SetLocalString(oItem, "EnergyAlter_Original_" + IntToString(GetItemPropertyType(ip)), sPropData);
|
||||
|
||||
// PRC persistence for crash recovery
|
||||
SetPersistantLocalString(oItem, "EnergyAlter_" + sItemID + "_" + IntToString(GetItemPropertyType(ip)), sPropData);
|
||||
ip = GetNextItemProperty(oItem);
|
||||
}
|
||||
|
||||
SetLocalInt(oItem, "EnergyAlter_Active", TRUE);
|
||||
SetLocalString(oItem, "EnergyAlter_ItemID", sItemID);
|
||||
}
|
||||
|
||||
// Restore properties with cleanup
|
||||
void RestoreOriginalProperties(object oItem)
|
||||
{
|
||||
string sItemID = GetLocalString(oItem, "EnergyAlter_ItemID");
|
||||
|
||||
// Remove temporary properties
|
||||
itemproperty ip = GetFirstItemProperty(oItem);
|
||||
while(GetIsItemPropertyValid(ip))
|
||||
{
|
||||
if(GetLocalInt(oItem, "EnergyAlter_Temp_" + IntToString(GetItemPropertyType(ip))))
|
||||
RemoveItemProperty(oItem, ip);
|
||||
ip = GetNextItemProperty(oItem);
|
||||
}
|
||||
|
||||
// Restore original properties
|
||||
int nType;
|
||||
for(nType = 0; nType < 100; nType++)
|
||||
{
|
||||
string sPropData = GetPersistantLocalString(oItem, "EnergyAlter_" + sItemID + "_" + IntToString(nType));
|
||||
if(sPropData != "")
|
||||
{
|
||||
struct ipstruct ipData = GetIpStructFromString(sPropData);
|
||||
itemproperty ipOriginal = ConstructIP(ipData.type, ipData.subtype, ipData.costtablevalue, ipData.param1value);
|
||||
AddItemProperty(DURATION_TYPE_PERMANENT, ipOriginal, oItem);
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup - clear PRC persistent variables
|
||||
DeletePersistantLocalString(oItem, "EnergyAlter_" + sItemID);
|
||||
DeleteLocalInt(oItem, "EnergyAlter_Active");
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
if(!X2PreSpellCastCode()) return;
|
||||
|
||||
object oCaster = OBJECT_SELF;
|
||||
object oTarget = PRCGetSpellTargetObject();
|
||||
int nSpellID = PRCGetSpellId();
|
||||
int nCasterLvl = PRCGetCasterLevel(oCaster);
|
||||
|
||||
// Material component validation (remove for testing)
|
||||
// if(!GetIsObjectValid(GetItemPossessedBy(oCaster, "energy_alter_ointment")))
|
||||
// {
|
||||
// FloatingTextStringOnCreature("You need an alchemical ointment (50 gp) to cast this spell.", oCaster, FALSE);
|
||||
// return;
|
||||
// }
|
||||
// DestroyObject(GetItemPossessedBy(oCaster, "energy_alter_ointment"));
|
||||
|
||||
// Store original properties and apply alteration
|
||||
StoreOriginalProperties(oTarget);
|
||||
ApplyEnergyAlteration(oTarget, nSpellID, nCasterLvl);
|
||||
}
|
||||
213
nwn/nwnprc/trunk/newspellbook/inf_resist_item.nss
Normal file
213
nwn/nwnprc/trunk/newspellbook/inf_resist_item.nss
Normal file
@@ -0,0 +1,213 @@
|
||||
// inf_resist_item.nss
|
||||
|
||||
/*
|
||||
Resistance Item
|
||||
Abjuration
|
||||
Level: Artificer 1
|
||||
Components: S, M
|
||||
Casting Time: 1 round
|
||||
Range: Touch
|
||||
Target: Item touched
|
||||
Duration: 10 min./level
|
||||
Saving Throw: None
|
||||
Spell Resistance: No
|
||||
|
||||
A nonmagical item imbued with this infusion grants a + 1 resistance
|
||||
bonus on saving throws to a character who wears or wields it. This
|
||||
bonus increases by 1 for every four caster levels (to +2 at 4th level,
|
||||
+3 at 8th level, +4 at 12th level, and so forth).
|
||||
Material Component: Oil mixed with various spices and minerals.
|
||||
*/
|
||||
|
||||
#include "prc_craft_inc"
|
||||
#include "inc_dynconv"
|
||||
|
||||
// Spell constants for subradials
|
||||
const int RESISTANCE_ITEM_FORTITUDE = 6001;
|
||||
const int RESISTANCE_ITEM_REFLEX = 6002;
|
||||
const int RESISTANCE_ITEM_WILL = 6003;
|
||||
|
||||
// Check if item is magical
|
||||
int GetIsItemMagical(object oItem)
|
||||
{
|
||||
if(!GetIsObjectValid(oItem)) return FALSE;
|
||||
|
||||
// Skip plot items
|
||||
if(GetPlotFlag(oItem)) return TRUE;
|
||||
|
||||
int bIsMagical = FALSE;
|
||||
itemproperty ipCheck = GetFirstItemProperty(oItem);
|
||||
while (GetIsItemPropertyValid(ipCheck))
|
||||
{
|
||||
string sTag = GetItemPropertyTag(ipCheck);
|
||||
int nType = GetItemPropertyType(ipCheck);
|
||||
|
||||
// Check for protected properties
|
||||
if(sTag == "Tag_PRC_OnHitKeeper" ||
|
||||
sTag == "Quality_Masterwork" ||
|
||||
sTag == "Material_Mithral" ||
|
||||
sTag == "Material_Adamantine" ||
|
||||
sTag == "Material_Darkwood" ||
|
||||
sTag == "Material_ColdIron" ||
|
||||
sTag == "Material_MundaneCrystal" ||
|
||||
sTag == "Material_DeepCrystal" ||
|
||||
nType == ITEM_PROPERTY_MATERIAL) // All material properties
|
||||
{
|
||||
// Protected property - skip, don't set bIsMagical
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check for helmet carveout: +1 Concentration only
|
||||
if(GetBaseItemType(oItem) == BASE_ITEM_HELMET &&
|
||||
GetItemPropertyType(ipCheck) == ITEM_PROPERTY_SKILL_BONUS &&
|
||||
GetItemPropertySubType(ipCheck) == SKILL_CONCENTRATION &&
|
||||
GetItemPropertyCostTableValue(ipCheck) == 1)
|
||||
{
|
||||
// This is a +1 Concentration helmet with no other properties, allow it
|
||||
bIsMagical = FALSE;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
bIsMagical = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ipCheck = GetNextItemProperty(oItem);
|
||||
}
|
||||
|
||||
return bIsMagical;
|
||||
}
|
||||
|
||||
// Find first non-magical item on creature
|
||||
object GetFirstNonMagicalItem(object oCreature)
|
||||
{
|
||||
// Check equipped items first
|
||||
int nSlot;
|
||||
for(nSlot = 0; nSlot < NUM_INVENTORY_SLOTS; nSlot++)
|
||||
{
|
||||
object oItem = GetItemInSlot(nSlot, oCreature);
|
||||
if(GetIsObjectValid(oItem) && !GetIsItemMagical(oItem))
|
||||
return oItem;
|
||||
}
|
||||
|
||||
// Check inventory
|
||||
object oItem = GetFirstItemInInventory(oCreature);
|
||||
while(GetIsObjectValid(oItem))
|
||||
{
|
||||
if(!GetIsItemMagical(oItem))
|
||||
return oItem;
|
||||
oItem = GetNextItemInInventory(oCreature);
|
||||
}
|
||||
|
||||
return OBJECT_INVALID;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
PRCSetSchool(SPELL_SCHOOL_ABJURATION);
|
||||
if (!X2PreSpellCastCode()) return;
|
||||
|
||||
object oCaster = OBJECT_SELF;
|
||||
//object oTarget = PRCGetSpellTargetObject();
|
||||
object oTarget = OBJECT_SELF; //:: for testing
|
||||
|
||||
int nCasterLevel = PRCGetCasterLevel(oCaster);
|
||||
//int nSpellID = PRCGetSpellId();
|
||||
int nSpellID = RESISTANCE_ITEM_FORTITUDE;
|
||||
|
||||
// Calculate resistance bonus: +1 +1 per 4 caster levels
|
||||
int nBonus = 1 + (nCasterLevel / 4);
|
||||
|
||||
// Calculate duration: 10 minutes per level
|
||||
float fDuration = TurnsToSeconds(nCasterLevel * 10);
|
||||
int nMetaMagic = PRCGetMetaMagicFeat();
|
||||
if(nMetaMagic & METAMAGIC_EXTEND)
|
||||
fDuration *= 2;
|
||||
|
||||
// Add fallback for very small durations
|
||||
if (fDuration <= 1.0) fDuration = 30.0f; // 30 seconds is fine for testing
|
||||
|
||||
// Determine save type based on infusion spellID
|
||||
int nSaveType;
|
||||
string sSaveName;
|
||||
|
||||
switch(nSpellID)
|
||||
{
|
||||
case RESISTANCE_ITEM_FORTITUDE:
|
||||
nSaveType = SAVING_THROW_FORT;
|
||||
sSaveName = "Fortitude";
|
||||
break;
|
||||
case RESISTANCE_ITEM_REFLEX:
|
||||
nSaveType = SAVING_THROW_REFLEX;
|
||||
sSaveName = "Reflex";
|
||||
break;
|
||||
case RESISTANCE_ITEM_WILL:
|
||||
nSaveType = SAVING_THROW_WILL;
|
||||
sSaveName = "Will";
|
||||
break;
|
||||
default:
|
||||
FloatingTextStringOnCreature("Invalid resistance spell type.", oCaster, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
object oItem;
|
||||
|
||||
// Handle targeting
|
||||
if(GetObjectType(oTarget) == OBJECT_TYPE_ITEM)
|
||||
{
|
||||
oItem = oTarget;
|
||||
}
|
||||
else if(GetObjectType(oTarget) == OBJECT_TYPE_CREATURE)
|
||||
{
|
||||
oItem = GetFirstNonMagicalItem(oTarget);
|
||||
if(!GetIsObjectValid(oItem))
|
||||
{
|
||||
FloatingTextStringOnCreature(GetName(oTarget) + " has no non-magical items to infuse.", oCaster, FALSE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FloatingTextStringOnCreature("Invalid target. Must target an item or creature.", oCaster, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate item
|
||||
if(!GetIsObjectValid(oItem))
|
||||
{
|
||||
FloatingTextStringOnCreature("Invalid item target.", oCaster, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
if(GetPlotFlag(oItem))
|
||||
{
|
||||
FloatingTextStringOnCreature("Cannot infuse plot items.", oCaster, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
if(GetIsItemMagical(oItem))
|
||||
{
|
||||
FloatingTextStringOnCreature(GetName(oItem) + " is already magical. Can only infuse non-magical items.", oCaster, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for existing resistance infusion to prevent stacking
|
||||
itemproperty ipExisting = GetFirstItemProperty(oItem);
|
||||
while(GetIsItemPropertyValid(ipExisting))
|
||||
{
|
||||
if(GetItemPropertyTag(ipExisting) == "ResistanceInfusion")
|
||||
{
|
||||
FloatingTextStringOnCreature(GetName(oItem) + " already has a resistance infusion.", oCaster, FALSE);
|
||||
return;
|
||||
}
|
||||
ipExisting = GetNextItemProperty(oItem);
|
||||
}
|
||||
|
||||
// Create and apply the resistance bonus property
|
||||
itemproperty ip = ItemPropertyBonusSavingThrow(nSaveType, nBonus);
|
||||
ip = TagItemProperty(ip, "ResistanceInfusion");
|
||||
IPSafeAddItemProperty(oItem, ip, fDuration, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, TRUE);
|
||||
|
||||
FloatingTextStringOnCreature(sSaveName + " resistance +" + IntToString(nBonus) + " applied to " + GetName(oItem) + ".", oCaster, FALSE);
|
||||
}
|
||||
709
nwn/nwnprc/trunk/newspellbook/inf_weapon_aug.nss
Normal file
709
nwn/nwnprc/trunk/newspellbook/inf_weapon_aug.nss
Normal file
@@ -0,0 +1,709 @@
|
||||
// inf_weapon_aug.nss
|
||||
/*
|
||||
Weapon Augmentation, Personal
|
||||
Transmutation
|
||||
Level: Artificer 1
|
||||
Components: S, M
|
||||
Casting Time: 1 minute
|
||||
Range: Touch
|
||||
Target: Weapon touched
|
||||
Duration: 10 min./level
|
||||
Saving Throw: None (object)
|
||||
Spell Resistance: No (object)
|
||||
|
||||
The weapon you touch temporarily gains a special ability commonly
|
||||
found on magic weapons. You can choose any special ability whose
|
||||
market price is equivalent to a +1 bonus or up to 10,000 gp, such as
|
||||
flaming or keen. The weapon does not have to have an existing
|
||||
enhancement bonus, nor does it gain one when you imbue it with this
|
||||
infusion. The weapon gains the benefit of the infusion only if you
|
||||
wield, throw, or fire it.
|
||||
|
||||
Material Component: A patch of rabbit's fur.
|
||||
|
||||
Weapon Augmentation, Lesser
|
||||
Transmutation
|
||||
Level: Artificer 2
|
||||
Duration: 10 min./level
|
||||
|
||||
Target: One weapon or fifty projectiles, all of which must be in
|
||||
contact with each other at the time of casting As personal weapon
|
||||
augmentation, but any character can wield the weapon you augment.
|
||||
Alternatively, you can affect as many as fifty arrows, bolts, or
|
||||
bullets. The projectiles must be of the same kind, and they have to be
|
||||
together (in the same quiver or other container). Projectiles, but
|
||||
not thrown weapons, lose their transmutation when used. (Treat
|
||||
shuriken as projectiles rather than thrown weapons for the purpose of
|
||||
this spell.)
|
||||
|
||||
Material Component: An ointment made from rare spices and minerals, costing 20 gp.
|
||||
|
||||
|
||||
|
||||
Weapon Augmentation
|
||||
Transmutation
|
||||
Level: Artificer 4
|
||||
|
||||
As lesser weapon augmentation, but you can choose any special ability
|
||||
whose market price is equivalent to a bonus of up to +3 or up to
|
||||
70,000 gp, such as speed.
|
||||
|
||||
Material Component: An ointment costing 100 gp.
|
||||
|
||||
*/
|
||||
#include "inc_debug"
|
||||
#include "prc_craft_inc"
|
||||
#include "inc_dynconv"
|
||||
|
||||
// Placeholder magic numbers for spell IDs
|
||||
const int WEAPON_AUG_PER = 6001;
|
||||
const int WEAPON_AUG_LESS = 6002;
|
||||
const int WEAPON_AUG = 6003;
|
||||
const int WEAPON_AUG_GREATER = 6004;
|
||||
|
||||
// Define constants (these are standard in the crafting system)
|
||||
const int CHOICE_BACK = -1;
|
||||
|
||||
// Dynamic conversation stages
|
||||
const int STAGE_PROPERTY_SELECTION = 0;
|
||||
const int STAGE_BANE = 1; // Match crafting system naming
|
||||
const int STAGE_CONFIRMATION = 2;
|
||||
|
||||
// Helper functions for sorted lists
|
||||
void AddToTempList(object oPC, string sChoice, int nChoice)
|
||||
{
|
||||
// Simple implementation - just add directly
|
||||
AddChoice(sChoice, nChoice, oPC);
|
||||
}
|
||||
|
||||
void TransferTempList(object oPC)
|
||||
{
|
||||
// No-op for simple implementation
|
||||
}
|
||||
|
||||
//Adds names to a list based on sTable (2da), delayed recursion to avoid TMI
|
||||
void PopulateList(object oPC, int MaxValue, int bSort, string sTable, int i = 0)
|
||||
{
|
||||
if(GetLocalInt(oPC, "DynConv_Waiting") == FALSE)
|
||||
return;
|
||||
|
||||
if(i <= MaxValue)
|
||||
{
|
||||
string sTemp = Get2DACache(sTable, "Name", i);
|
||||
if(sTemp != "")
|
||||
{
|
||||
if(bSort)
|
||||
AddToTempList(oPC, ActionString(GetStringByStrRef(StringToInt(sTemp))), i);
|
||||
else
|
||||
AddChoice(ActionString(GetStringByStrRef(StringToInt(sTemp))), i, oPC);
|
||||
}
|
||||
|
||||
if(!(i % 100) && i) //i != 0, i % 100 == 0
|
||||
FloatingTextStringOnCreature("*Tick*", oPC, FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(bSort) TransferTempList(oPC);
|
||||
DeleteLocalInt(oPC, "DynConv_Waiting");
|
||||
FloatingTextStringOnCreature("*Done*", oPC, FALSE);
|
||||
return;
|
||||
}
|
||||
DelayCommand(0.01, PopulateList(oPC, MaxValue, bSort, sTable, i + 1));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void HandleConversation(object oPC, object oWeapon, int nMaxEnhancement, int nMaxCost, string sLocalVar, int nSpellID, int nCasterLevel)
|
||||
{
|
||||
int nValue = GetLocalInt(oPC, DYNCONV_VARIABLE);
|
||||
int nStage = GetStage(oPC);
|
||||
|
||||
if(nValue == 0) return;
|
||||
|
||||
if(nValue == DYNCONV_SETUP_STAGE)
|
||||
{
|
||||
if(!GetIsStageSetUp(nStage, oPC))
|
||||
{
|
||||
if(nStage == STAGE_PROPERTY_SELECTION)
|
||||
{
|
||||
// Set header first
|
||||
SetHeader("Select a weapon augmentation:");
|
||||
|
||||
// Initialize default tokens BEFORE adding choices
|
||||
SetDefaultTokens();
|
||||
|
||||
int nFileEnd = PRCGetFileEnd("craft_weapon");
|
||||
int nChoice = 1;
|
||||
int i;
|
||||
|
||||
for(i = 0; i <= nFileEnd; i++)
|
||||
{
|
||||
// Get enhancement and cost for this specific line
|
||||
int nEnhancement = StringToInt(Get2DACache("craft_weapon", "Enhancement", i));
|
||||
int nAdditionalCost = StringToInt(Get2DACache("craft_weapon", "AdditionalCost", i));
|
||||
string sName = GetStringByStrRef(StringToInt(Get2DACache("craft_weapon", "Name", i)));
|
||||
|
||||
// Debug output
|
||||
SendMessageToPC(oPC, "Line " + IntToString(i) + ": " + sName + " (Enh:" + IntToString(nEnhancement) + ", Cost:" + IntToString(nAdditionalCost) + ")");
|
||||
|
||||
// Check if this property is within limits
|
||||
if(nEnhancement <= nMaxEnhancement && nAdditionalCost <= nMaxCost)
|
||||
{
|
||||
AddChoice(sName, i, oPC);
|
||||
nChoice++;
|
||||
}
|
||||
}
|
||||
|
||||
MarkStageSetUp(STAGE_PROPERTY_SELECTION, oPC);
|
||||
}
|
||||
else if(nStage == STAGE_BANE)
|
||||
{
|
||||
// Exact copy from crafting system
|
||||
SetHeader("Select a racial type.");
|
||||
AllowExit(DYNCONV_EXIT_NOT_ALLOWED, FALSE, oPC);
|
||||
AddChoice(ActionString("Back"), CHOICE_BACK, oPC);
|
||||
SetLocalInt(oPC, "DynConv_Waiting", TRUE);
|
||||
PopulateList(oPC, PRCGetFileEnd("racialtypes"), TRUE, "racialtypes");
|
||||
MarkStageSetUp(nStage);
|
||||
}
|
||||
else if(nStage == STAGE_CONFIRMATION)
|
||||
{
|
||||
int nPropertyLine = GetLocalInt(oPC, "WeaponAug_SelectedProperty");
|
||||
string sName = GetStringByStrRef(StringToInt(Get2DACache("craft_weapon", "Name", nPropertyLine)));
|
||||
|
||||
SetHeader("Apply " + sName + " to the weapon?");
|
||||
|
||||
AddChoice("Yes", TRUE, oPC);
|
||||
AddChoice("No", FALSE, oPC);
|
||||
|
||||
MarkStageSetUp(STAGE_CONFIRMATION, oPC);
|
||||
}
|
||||
}
|
||||
|
||||
SetupTokens();
|
||||
}
|
||||
else if(nValue == DYNCONV_EXITED)
|
||||
{
|
||||
// Cleanup
|
||||
DeleteLocalInt(oPC, "WeaponAug_ConvMode");
|
||||
DeleteLocalObject(oPC, "WEAPON_AUG_TARGET");
|
||||
DeleteLocalInt(oPC, "WeaponAug_SelectedProperty");
|
||||
DeleteLocalInt(oPC, PRC_CRAFT_SPECIAL_BANE_RACE);
|
||||
}
|
||||
else if(nValue == DYNCONV_ABORTED)
|
||||
{
|
||||
// Cleanup
|
||||
DeleteLocalInt(oPC, "WeaponAug_ConvMode");
|
||||
DeleteLocalObject(oPC, "WEAPON_AUG_TARGET");
|
||||
DeleteLocalInt(oPC, "WeaponAug_SelectedProperty");
|
||||
DeleteLocalInt(oPC, PRC_CRAFT_SPECIAL_BANE_RACE);
|
||||
}
|
||||
else
|
||||
{
|
||||
int nChoice = GetChoice(oPC);
|
||||
|
||||
if(nStage == STAGE_PROPERTY_SELECTION)
|
||||
{
|
||||
// Store selection and check if Bane/Dread
|
||||
SetLocalInt(oPC, "WeaponAug_SelectedProperty", nChoice);
|
||||
if(nChoice == 26 || nChoice == 27) // Bane or Dread
|
||||
{
|
||||
nStage = STAGE_BANE;
|
||||
}
|
||||
else
|
||||
{
|
||||
nStage = STAGE_CONFIRMATION;
|
||||
}
|
||||
MarkStageNotSetUp(STAGE_PROPERTY_SELECTION, oPC);
|
||||
}
|
||||
else if(nStage == STAGE_BANE)
|
||||
{
|
||||
// Exact copy from crafting system logic
|
||||
if(nChoice == CHOICE_BACK)
|
||||
nStage = STAGE_PROPERTY_SELECTION;
|
||||
else
|
||||
{
|
||||
nStage = STAGE_CONFIRMATION;
|
||||
SetLocalInt(oPC, PRC_CRAFT_SPECIAL_BANE_RACE, nChoice);
|
||||
}
|
||||
MarkStageNotSetUp(nStage, oPC);
|
||||
}
|
||||
else if(nStage == STAGE_CONFIRMATION)
|
||||
{
|
||||
if(nChoice == TRUE) // User confirmed
|
||||
{
|
||||
// Apply the property
|
||||
object oWeapon = GetLocalObject(oPC, "WEAPON_AUG_TARGET");
|
||||
int nPropertyLine = GetLocalInt(oPC, "WeaponAug_SelectedProperty");
|
||||
int nCasterLevel = GetLocalInt(oPC, "WeaponAug_CasterLevel");
|
||||
|
||||
float fDuration = TurnsToSeconds(nCasterLevel * 10);
|
||||
int nMetaMagic = PRCGetMetaMagicFeat();
|
||||
if(nMetaMagic & METAMAGIC_EXTEND)
|
||||
fDuration *= 2;
|
||||
|
||||
// Debug output
|
||||
SendMessageToPC(oPC, "Duration: " + FloatToString(fDuration) + " seconds");
|
||||
|
||||
// Add fallback for very small durations
|
||||
if (fDuration <= 1.0) fDuration = 30.0f;
|
||||
|
||||
SendMessageToPC(oPC, "Fallback Duration: " + FloatToString(fDuration) + " seconds");
|
||||
|
||||
// Create property with special handling for Bane/Dread
|
||||
itemproperty ip;
|
||||
if(nPropertyLine == 26 || nPropertyLine == 27) // Bane or Dread
|
||||
{
|
||||
// Use the special handling function from the crafting system
|
||||
ip = PropSpecialHandling(oWeapon, "craft_weapon", nPropertyLine, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Standard property construction
|
||||
string sIPData = Get2DACache("craft_weapon", "IP1", nPropertyLine);
|
||||
struct ipstruct iptemp = GetIpStructFromString(sIPData);
|
||||
ip = ConstructIP(iptemp.type, iptemp.subtype, iptemp.costtablevalue, iptemp.param1value);
|
||||
}
|
||||
|
||||
// Apply with proper duration
|
||||
ip = TagItemProperty(ip, "WeaponAugInfusion");
|
||||
IPSafeAddItemProperty(oWeapon, ip, fDuration, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, TRUE);
|
||||
|
||||
// Clean up and exit
|
||||
DeleteLocalInt(oPC, "WeaponAug_ConvMode");
|
||||
DeleteLocalObject(oPC, "WEAPON_AUG_TARGET");
|
||||
DeleteLocalInt(oPC, "WeaponAug_SelectedProperty");
|
||||
DeleteLocalInt(oPC, PRC_CRAFT_SPECIAL_BANE_RACE);
|
||||
|
||||
AllowExit(DYNCONV_EXIT_FORCE_EXIT);
|
||||
}
|
||||
else // User cancelled
|
||||
{
|
||||
// Go back to property selection or BANE stage
|
||||
if(GetLocalInt(oPC, PRC_CRAFT_SPECIAL_BANE_RACE))
|
||||
{
|
||||
nStage = STAGE_BANE;
|
||||
DeleteLocalInt(oPC, PRC_CRAFT_SPECIAL_BANE_RACE);
|
||||
}
|
||||
else
|
||||
{
|
||||
nStage = STAGE_PROPERTY_SELECTION;
|
||||
}
|
||||
MarkStageNotSetUp(STAGE_CONFIRMATION, oPC);
|
||||
}
|
||||
}
|
||||
|
||||
SetStage(nStage, oPC);
|
||||
}
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
object oPC = GetPCSpeaker();
|
||||
if(!GetIsObjectValid(oPC)) oPC = OBJECT_SELF;
|
||||
|
||||
// Check if we're in conversation mode
|
||||
if(GetLocalInt(oPC, "WeaponAug_ConvMode"))
|
||||
{
|
||||
// Retrieve parameters for conversation
|
||||
object oWeapon = GetLocalObject(oPC, "WEAPON_AUG_TARGET");
|
||||
int nMaxEnhancement = GetLocalInt(oPC, "WeaponAug_MaxEnh");
|
||||
int nMaxCost = GetLocalInt(oPC, "WeaponAug_MaxCost");
|
||||
string sLocalVar = GetLocalString(oPC, "WeaponAug_LocalVar");
|
||||
int nSpellID = GetLocalInt(oPC, "WeaponAug_SpellID");
|
||||
int nCasterLevel = GetLocalInt(oPC, "WeaponAug_CasterLevel");
|
||||
|
||||
HandleConversation(oPC, oWeapon, nMaxEnhancement, nMaxCost, sLocalVar, nSpellID, nCasterLevel);
|
||||
return;
|
||||
}
|
||||
|
||||
// Normal spell execution
|
||||
PRCSetSchool(SPELL_SCHOOL_TRANSMUTATION);
|
||||
if (!X2PreSpellCastCode()) return;
|
||||
|
||||
object oCaster = OBJECT_SELF;
|
||||
object oTarget = PRCGetSpellTargetObject();
|
||||
int nCasterLevel = PRCGetCasterLevel(oCaster);
|
||||
int nSpellID = PRCGetSpellId();
|
||||
|
||||
// Declare variables
|
||||
int nGoldCost, nMaxEnhancement, nMaxCost;
|
||||
string sLocalVar;
|
||||
|
||||
// Set parameters based on spell level
|
||||
switch(nSpellID)
|
||||
{
|
||||
case WEAPON_AUG_PER:
|
||||
nGoldCost = 0;
|
||||
nMaxEnhancement = 1;
|
||||
nMaxCost = 10000;
|
||||
sLocalVar = "WEAPON_AUG_PER_PROPERTY";
|
||||
break;
|
||||
case WEAPON_AUG_LESS:
|
||||
nGoldCost = 20;
|
||||
nMaxEnhancement = 1;
|
||||
nMaxCost = 10000;
|
||||
sLocalVar = "WEAPON_AUG_LESS_PROPERTY";
|
||||
break;
|
||||
case WEAPON_AUG:
|
||||
nGoldCost = 100;
|
||||
nMaxEnhancement = 3;
|
||||
nMaxCost = 70000;
|
||||
sLocalVar = "WEAPON_AUG_PROPERTY";
|
||||
break;
|
||||
case WEAPON_AUG_GREATER:
|
||||
nGoldCost = 200;
|
||||
nMaxEnhancement = 5;
|
||||
nMaxCost = 200000;
|
||||
sLocalVar = "WEAPON_AUG_GREATER_PROPERTY";
|
||||
break;
|
||||
default:
|
||||
// Default to lesser version for testing
|
||||
nGoldCost = 20;
|
||||
nMaxEnhancement = 1;
|
||||
nMaxCost = 10000;
|
||||
sLocalVar = "WEAPON_AUG_LESS_PROPERTY";
|
||||
break;
|
||||
}
|
||||
|
||||
// Check material component
|
||||
if(GetGold(oCaster) < nGoldCost)
|
||||
{
|
||||
FloatingTextStringOnCreature("You need " + IntToString(nGoldCost) + "gp worth of rare ointments.", oCaster, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get targeted weapon
|
||||
object oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oCaster);
|
||||
//object oWeapon = IPGetTargetedOrEquippedArmor(TRUE); <- don't delete
|
||||
if(!GetIsObjectValid(oWeapon))
|
||||
{
|
||||
FloatingTextStrRefOnCreature(83826, oCaster, FALSE); // "Invalid target"
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if returning from conversation with a selection
|
||||
int nPropertyLine = GetLocalInt(oCaster, sLocalVar);
|
||||
if(nPropertyLine > 0)
|
||||
{
|
||||
// Apply the property
|
||||
float fDuration = TurnsToSeconds(nCasterLevel * 10);
|
||||
int nMetaMagic = PRCGetMetaMagicFeat();
|
||||
if(nMetaMagic & METAMAGIC_EXTEND)
|
||||
fDuration *= 2;
|
||||
|
||||
if (fDuration <= 1.0) fDuration = 30.0f;
|
||||
|
||||
// Read property data from 2DA and construct
|
||||
string sIPData = Get2DACache("craft_weapon", "IP1", nPropertyLine);
|
||||
struct ipstruct iptemp = GetIpStructFromString(sIPData);
|
||||
itemproperty ip = ConstructIP(iptemp.type, iptemp.subtype, iptemp.costtablevalue, iptemp.param1value);
|
||||
|
||||
|
||||
// Apply with proper duration
|
||||
ip = TagItemProperty(ip, "WeaponAugInfusion");
|
||||
IPSafeAddItemProperty(oWeapon, ip, fDuration, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, TRUE);
|
||||
|
||||
DeleteLocalInt(oCaster, sLocalVar);
|
||||
return;
|
||||
}
|
||||
|
||||
// Store parameters for conversation and start it
|
||||
SetLocalInt(oPC, "WeaponAug_ConvMode", 1);
|
||||
SetLocalObject(oPC, "WEAPON_AUG_TARGET", oWeapon);
|
||||
SetLocalInt(oPC, "WeaponAug_MaxEnh", nMaxEnhancement);
|
||||
SetLocalInt(oPC, "WeaponAugh_MaxCost", nMaxCost);
|
||||
SetLocalString(oPC, "WeaponAug_LocalVar", sLocalVar);
|
||||
SetLocalInt(oPC, "WeaponAug_SpellID", nSpellID);
|
||||
SetLocalInt(oPC, "WeaponAug_CasterLevel", nCasterLevel);
|
||||
|
||||
// Start the dynamic conversation using this same script
|
||||
StartDynamicConversation("inf_weapon_aug", oPC, 0, FALSE, TRUE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* #include "inc_debug"
|
||||
#include "prc_craft_inc"
|
||||
#include "inc_dynconv"
|
||||
|
||||
// Placeholder magic numbers for spell IDs
|
||||
const int WEAPON_AUG_PER = 6001;
|
||||
const int WEAPON_AUG_LESS = 6002;
|
||||
const int WEAPON_AUG = 6003;
|
||||
const int WEAPON_AUG_GREATER = 6004;
|
||||
|
||||
|
||||
// Dynamic conversation stages
|
||||
const int STAGE_PROPERTY_SELECTION = 0;
|
||||
const int STAGE_CONFIRMATION = 1;
|
||||
|
||||
|
||||
void HandleConversation(object oPC, object oWeapon, int nMaxEnhancement, int nMaxCost, string sLocalVar, int nSpellID, int nCasterLevel)
|
||||
{
|
||||
int nValue = GetLocalInt(oPC, DYNCONV_VARIABLE);
|
||||
int nStage = GetStage(oPC);
|
||||
|
||||
if(nValue == 0) return;
|
||||
|
||||
if(nValue == DYNCONV_SETUP_STAGE)
|
||||
{
|
||||
if(!GetIsStageSetUp(nStage, oPC))
|
||||
{
|
||||
if(nStage == STAGE_PROPERTY_SELECTION)
|
||||
{
|
||||
// Set header first
|
||||
SetHeader("Select a weapon augmentation:");
|
||||
|
||||
// Initialize default tokens BEFORE adding choices
|
||||
SetDefaultTokens();
|
||||
|
||||
int nFileEnd = PRCGetFileEnd("craft_weapon");
|
||||
int nChoice = 1;
|
||||
int i;
|
||||
|
||||
for(i = 0; i <= nFileEnd; i++)
|
||||
{
|
||||
// Get enhancement and cost for this specific line
|
||||
int nEnhancement = StringToInt(Get2DACache("craft_weapon", "Enhancement", i));
|
||||
int nAdditionalCost = StringToInt(Get2DACache("craft_weapon", "AdditionalCost", i));
|
||||
string sName = GetStringByStrRef(StringToInt(Get2DACache("craft_weapon", "Name", i)));
|
||||
|
||||
// Debug output
|
||||
SendMessageToPC(oPC, "Line " + IntToString(i) + ": " + sName + " (Enh:" + IntToString(nEnhancement) + ", Cost:" + IntToString(nAdditionalCost) + ")");
|
||||
|
||||
// Check if this property is within limits
|
||||
if(nEnhancement <= nMaxEnhancement && nAdditionalCost <= nMaxCost)
|
||||
{
|
||||
AddChoice(sName, i, oPC);
|
||||
nChoice++;
|
||||
}
|
||||
}
|
||||
|
||||
MarkStageSetUp(STAGE_PROPERTY_SELECTION, oPC);
|
||||
}
|
||||
else if(nStage == STAGE_CONFIRMATION)
|
||||
{
|
||||
int nPropertyLine = GetLocalInt(oPC, "WeaponAug_SelectedProperty");
|
||||
string sName = GetStringByStrRef(StringToInt(Get2DACache("craft_weapon", "Name", nPropertyLine)));
|
||||
|
||||
SetHeader("Apply " + sName + " to the weapon?");
|
||||
|
||||
AddChoice("Yes", TRUE, oPC);
|
||||
AddChoice("No", FALSE, oPC);
|
||||
|
||||
MarkStageSetUp(STAGE_CONFIRMATION, oPC);
|
||||
}
|
||||
}
|
||||
|
||||
SetupTokens();
|
||||
}
|
||||
else if(nValue == DYNCONV_EXITED)
|
||||
{
|
||||
// Cleanup
|
||||
DeleteLocalInt(oPC, "WeaponAug_ConvMode");
|
||||
DeleteLocalObject(oPC, "WEAPON_AUG_TARGET");
|
||||
DeleteLocalInt(oPC, "WeaponAug_SelectedProperty");
|
||||
}
|
||||
else if(nValue == DYNCONV_ABORTED)
|
||||
{
|
||||
// Cleanup
|
||||
DeleteLocalInt(oPC, "WeaponAug_ConvMode");
|
||||
DeleteLocalObject(oPC, "WEAPON_AUG_TARGET");
|
||||
DeleteLocalInt(oPC, "WeaponAug_SelectedProperty");
|
||||
}
|
||||
else
|
||||
{
|
||||
int nChoice = GetChoice(oPC);
|
||||
|
||||
if(nStage == STAGE_PROPERTY_SELECTION)
|
||||
{
|
||||
// Store selection and go to confirmation
|
||||
SetLocalInt(oPC, "WeaponAug_SelectedProperty", nChoice);
|
||||
nStage = STAGE_CONFIRMATION;
|
||||
MarkStageNotSetUp(STAGE_PROPERTY_SELECTION, oPC);
|
||||
}
|
||||
else if(nStage == STAGE_CONFIRMATION)
|
||||
{
|
||||
if(nChoice == TRUE) // User confirmed
|
||||
{
|
||||
// Apply the property
|
||||
object oWeapon = GetLocalObject(oPC, "WEAPON_AUG_TARGET");
|
||||
int nPropertyLine = GetLocalInt(oPC, "WeaponAug_SelectedProperty");
|
||||
int nCasterLevel = GetLocalInt(oPC, "WeaponAug_CasterLevel");
|
||||
|
||||
float fDuration = TurnsToSeconds(nCasterLevel * 10);
|
||||
int nMetaMagic = PRCGetMetaMagicFeat();
|
||||
if(nMetaMagic & METAMAGIC_EXTEND)
|
||||
fDuration *= 2;
|
||||
|
||||
// Debug output
|
||||
SendMessageToPC(oPC, "Duration: " + FloatToString(fDuration) + " seconds");
|
||||
|
||||
// Add fallback for very small durations
|
||||
if (fDuration <= 1.0) fDuration = 30.0f;
|
||||
|
||||
SendMessageToPC(oPC, "Fallback Duration: " + FloatToString(fDuration) + " seconds");
|
||||
|
||||
// Create property directly
|
||||
itemproperty ip;
|
||||
// Read property data from 2DA and construct
|
||||
string sIPData = Get2DACache("craft_weapon", "IP1", nPropertyLine);
|
||||
struct ipstruct iptemp = GetIpStructFromString(sIPData);
|
||||
ip = ConstructIP(iptemp.type, iptemp.subtype, iptemp.costtablevalue, iptemp.param1value);
|
||||
|
||||
// Apply with proper duration
|
||||
ip = TagItemProperty(ip, "WeaponAugInfusion");
|
||||
IPSafeAddItemProperty(oWeapon, ip, fDuration, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, TRUE);
|
||||
|
||||
// Clean up and exit
|
||||
DeleteLocalInt(oPC, "WeaponAug_ConvMode");
|
||||
DeleteLocalObject(oPC, "WEAPON_AUG_TARGET");
|
||||
DeleteLocalInt(oPC, "WeaponAug_SelectedProperty");
|
||||
|
||||
AllowExit(DYNCONV_EXIT_FORCE_EXIT);
|
||||
}
|
||||
else // User cancelled
|
||||
{
|
||||
// Go back to property selection
|
||||
nStage = STAGE_PROPERTY_SELECTION;
|
||||
MarkStageNotSetUp(STAGE_CONFIRMATION, oPC);
|
||||
}
|
||||
}
|
||||
|
||||
SetStage(nStage, oPC);
|
||||
}
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
object oPC = GetPCSpeaker();
|
||||
if(!GetIsObjectValid(oPC)) oPC = OBJECT_SELF;
|
||||
|
||||
// Check if we're in conversation mode
|
||||
if(GetLocalInt(oPC, "WeaponAug_ConvMode"))
|
||||
{
|
||||
// Retrieve parameters for conversation
|
||||
object oWeapon = GetLocalObject(oPC, "WEAPON_AUG_TARGET");
|
||||
int nMaxEnhancement = GetLocalInt(oPC, "WeaponAug_MaxEnh");
|
||||
int nMaxCost = GetLocalInt(oPC, "WeaponAug_MaxCost");
|
||||
string sLocalVar = GetLocalString(oPC, "WeaponAug_LocalVar");
|
||||
int nSpellID = GetLocalInt(oPC, "WeaponAug_SpellID");
|
||||
int nCasterLevel = GetLocalInt(oPC, "WeaponAug_CasterLevel");
|
||||
|
||||
HandleConversation(oPC, oWeapon, nMaxEnhancement, nMaxCost, sLocalVar, nSpellID, nCasterLevel);
|
||||
return;
|
||||
}
|
||||
|
||||
// Normal spell execution
|
||||
PRCSetSchool(SPELL_SCHOOL_TRANSMUTATION);
|
||||
if (!X2PreSpellCastCode()) return;
|
||||
|
||||
object oCaster = OBJECT_SELF;
|
||||
object oTarget = PRCGetSpellTargetObject();
|
||||
int nCasterLevel = PRCGetCasterLevel(oCaster);
|
||||
int nSpellID = PRCGetSpellId();
|
||||
|
||||
// Declare variables
|
||||
int nGoldCost, nMaxEnhancement, nMaxCost;
|
||||
string sLocalVar;
|
||||
|
||||
// Set parameters based on spell level
|
||||
switch(nSpellID)
|
||||
{
|
||||
case WEAPON_AUG_PER:
|
||||
nGoldCost = 0;
|
||||
nMaxEnhancement = 1;
|
||||
nMaxCost = 10000;
|
||||
sLocalVar = "WEAPON_AUG_PER_PROPERTY";
|
||||
break;
|
||||
case WEAPON_AUG_LESS:
|
||||
nGoldCost = 20;
|
||||
nMaxEnhancement = 1;
|
||||
nMaxCost = 10000;
|
||||
sLocalVar = "WEAPON_AUG_LESS_PROPERTY";
|
||||
break;
|
||||
case WEAPON_AUG:
|
||||
nGoldCost = 100;
|
||||
nMaxEnhancement = 3;
|
||||
nMaxCost = 70000;
|
||||
sLocalVar = "WEAPON_AUG_PROPERTY";
|
||||
break;
|
||||
case WEAPON_AUG_GREATER:
|
||||
nGoldCost = 200;
|
||||
nMaxEnhancement = 5;
|
||||
nMaxCost = 200000;
|
||||
sLocalVar = "WEAPON_AUG_GREATER_PROPERTY";
|
||||
break;
|
||||
default:
|
||||
// Default to lesser version for testing
|
||||
nGoldCost = 20;
|
||||
nMaxEnhancement = 1;
|
||||
nMaxCost = 10000;
|
||||
sLocalVar = "WEAPON_AUG_LESS_PROPERTY";
|
||||
break;
|
||||
}
|
||||
|
||||
// Check material component
|
||||
if(GetGold(oCaster) < nGoldCost)
|
||||
{
|
||||
FloatingTextStringOnCreature("You need " + IntToString(nGoldCost) + "gp worth of rare ointments.", oCaster, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get targeted weapon
|
||||
object oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oCaster);
|
||||
//object oWeapon = IPGetTargetedOrEquippedArmor(TRUE); <- don't delete
|
||||
if(!GetIsObjectValid(oWeapon))
|
||||
{
|
||||
FloatingTextStrRefOnCreature(83826, oCaster, FALSE); // "Invalid target"
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if returning from conversation with a selection
|
||||
int nPropertyLine = GetLocalInt(oCaster, sLocalVar);
|
||||
if(nPropertyLine > 0)
|
||||
{
|
||||
// Apply the property
|
||||
float fDuration = TurnsToSeconds(nCasterLevel * 10);
|
||||
int nMetaMagic = PRCGetMetaMagicFeat();
|
||||
if(nMetaMagic & METAMAGIC_EXTEND)
|
||||
fDuration *= 2;
|
||||
|
||||
if (fDuration <= 1.0) fDuration = 30.0f;
|
||||
|
||||
// Read property data from 2DA and construct
|
||||
string sIPData = Get2DACache("craft_weapon", "IP1", nPropertyLine);
|
||||
struct ipstruct iptemp = GetIpStructFromString(sIPData);
|
||||
itemproperty ip = ConstructIP(iptemp.type, iptemp.subtype, iptemp.costtablevalue, iptemp.param1value);
|
||||
|
||||
|
||||
// Apply with proper duration
|
||||
ip = TagItemProperty(ip, "WeaponAugInfusion");
|
||||
IPSafeAddItemProperty(oWeapon, ip, fDuration, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, TRUE);
|
||||
|
||||
DeleteLocalInt(oCaster, sLocalVar);
|
||||
return;
|
||||
}
|
||||
|
||||
// Store parameters for conversation and start it
|
||||
SetLocalInt(oPC, "WeaponAug_ConvMode", 1);
|
||||
SetLocalObject(oPC, "WEAPON_AUG_TARGET", oWeapon);
|
||||
SetLocalInt(oPC, "WeaponAug_MaxEnh", nMaxEnhancement);
|
||||
SetLocalInt(oPC, "WeaponAugh_MaxCost", nMaxCost);
|
||||
SetLocalString(oPC, "WeaponAug_LocalVar", sLocalVar);
|
||||
SetLocalInt(oPC, "WeaponAug_SpellID", nSpellID);
|
||||
SetLocalInt(oPC, "WeaponAug_CasterLevel", nCasterLevel);
|
||||
|
||||
// Start the dynamic conversation using this same script
|
||||
StartDynamicConversation("inf_weapon_aug", oPC, 0, FALSE, TRUE);
|
||||
} */
|
||||
Reference in New Issue
Block a user