Updated Release Archive. Fixed Mage-killer prereqs. Removed old LETO & ConvoCC related files. Added organized spell scroll store. Fixed Gloura spellbook. Various TLK fixes. Reorganized Repo. Removed invalid user folders. Added DocGen back in.
307 lines
17 KiB
Plaintext
307 lines
17 KiB
Plaintext
//::///////////////////////////////////////////////
|
|
//:: Soulknife: Manifest Mindblade
|
|
//:: psi_sk_manifmbld
|
|
//::///////////////////////////////////////////////
|
|
/** @file Soulknife: Manifest Mindblade
|
|
Handles creation of mindblades.
|
|
|
|
|
|
@author Ornedan
|
|
@date Created - 07.04.2005
|
|
@date Modified - 01.09.2005
|
|
*/
|
|
//:://////////////////////////////////////////////
|
|
//:://////////////////////////////////////////////
|
|
|
|
#include "prc_inc_combat"
|
|
#include "psi_inc_soulkn"
|
|
|
|
int LOCAL_DEBUG = DEBUG;
|
|
|
|
//////////////////////////////////////////////////
|
|
/* Function prototypes */
|
|
//////////////////////////////////////////////////
|
|
|
|
// Handles adding in the enhancement bonuses and specials
|
|
// ======================================================
|
|
// oMbld mindblade item
|
|
void BuildMindblade(object oPC, object oMbld, int nMbldType);
|
|
|
|
|
|
void main()
|
|
{
|
|
if(LOCAL_DEBUG) DoDebug("Starting psi_sk_manifmbld");
|
|
object oPC = OBJECT_SELF;
|
|
object oMbld;
|
|
int nMbldType = GetPersistantLocalInt(oPC, MBLADE_SHAPE);
|
|
int nHand = GetPersistantLocalInt(oPC, MBLADE_HAND);
|
|
|
|
// If this is the very first time a PC is manifesting a mindblade, initialise the hand to be main hand
|
|
if(!nHand)
|
|
{
|
|
nHand = INVENTORY_SLOT_RIGHTHAND;
|
|
SetPersistantLocalInt(oPC, MBLADE_HAND, INVENTORY_SLOT_RIGHTHAND);
|
|
}
|
|
|
|
// Generate the item based on type selection
|
|
switch(nMbldType)
|
|
{
|
|
case MBLADE_SHAPE_DUAL_SHORTSWORDS:
|
|
//SendMessageToPC(oPC, "psi_sk_manifmbld: First of dual shortswords - ");
|
|
// The first of dual mindblades always goes to mainhand
|
|
nHand = INVENTORY_SLOT_RIGHTHAND;
|
|
case MBLADE_SHAPE_SHORTSWORD:
|
|
//SendMessageToPC(oPC, "psi_sk_manifmbld: Created shortsword");
|
|
oMbld = CreateItemOnObject("prc_sk_mblade_ss", oPC);
|
|
break;
|
|
case MBLADE_SHAPE_LONGSWORD:
|
|
//SendMessageToPC(oPC, "psi_sk_manifmbld: Created longsword");
|
|
oMbld = CreateItemOnObject("prc_sk_mblade_ls", oPC);
|
|
break;
|
|
case MBLADE_SHAPE_BASTARDSWORD:
|
|
//SendMessageToPC(oPC, "psi_sk_manifmbld: Created bastardsword");
|
|
oMbld = CreateItemOnObject("prc_sk_mblade_bs", oPC);
|
|
break;
|
|
case MBLADE_SHAPE_RANGED:
|
|
//SendMessageToPC(oPC, "psi_sk_manifmbld: Created throwing mindblade");
|
|
// Create one more mindblade than needed in order to bypass the BW bug of the last thrown weapon in a stack no longer being a valid object in the OnHitCast script
|
|
oMbld = CreateItemOnObject("prc_sk_mblade_th", oPC, (GetHasFeat(FEAT_MULTIPLE_THROW, oPC) ? GetMainHandAttacks(oPC) : 1) + 1);
|
|
break;
|
|
|
|
default:
|
|
WriteTimestampedLogEntry("Invalid value in MBLADE_SHAPE for " + GetName(oPC) + ": " + IntToString(nMbldType));
|
|
return;
|
|
}
|
|
|
|
// Construct the bonuses
|
|
/*DelayCommand(0.25f, */BuildMindblade(oPC, oMbld, nMbldType)/*)*/;
|
|
|
|
// check for existing one before equipping and destroy
|
|
if(GetStringLeft(GetTag(GetItemInSlot(nHand, oPC)), 14) == "prc_sk_mblade_")
|
|
MyDestroyObject(GetItemInSlot(nHand, oPC));
|
|
// Force equip
|
|
AssignCommand(oPC, ActionEquipItem(oMbld, nHand));
|
|
|
|
// Hook the mindblade into OnHit event
|
|
AddEventScript(oMbld, EVENT_ITEM_ONHIT, "psi_sk_onhit", TRUE, FALSE);
|
|
|
|
// Make even more sure the mindblade cannot be dropped
|
|
SetDroppableFlag(oMbld, FALSE);
|
|
SetItemCursedFlag(oMbld, TRUE);
|
|
|
|
// Generate the second mindblade if set to dual shortswords
|
|
if(nMbldType == MBLADE_SHAPE_DUAL_SHORTSWORDS)
|
|
{
|
|
oMbld = CreateItemOnObject("prc_sk_mblade_ss", oPC);
|
|
|
|
//SendMessageToPC(oPC, "psi_sk_manifmbld: Created second mindblade - is valid: " + (GetIsObjectValid(oMbld) ? "TRUE":"FALSE"));
|
|
|
|
DelayCommand(0.5f, BuildMindblade(oPC, oMbld, nMbldType)); // Delay a bit to prevent a lag spike
|
|
//BuildMindblade(oPC, oMbld, nMbldType);
|
|
AssignCommand(oPC, ActionDoCommand(ActionEquipItem(oMbld, INVENTORY_SLOT_LEFTHAND)));
|
|
//AssignCommand(oPC, ActionEquipItem(oMbld, INVENTORY_SLOT_LEFTHAND));
|
|
AddEventScript(oMbld, EVENT_ITEM_ONHIT, "psi_sk_onhit", TRUE, FALSE);
|
|
|
|
SetDroppableFlag(oMbld, FALSE);
|
|
SetItemCursedFlag(oMbld, TRUE);
|
|
}
|
|
// Not dual-wielding, so delete the second mindblade if they have such
|
|
else
|
|
{
|
|
// Get the other hand
|
|
int nOtherHand;
|
|
if(nHand == INVENTORY_SLOT_RIGHTHAND)
|
|
nOtherHand = INVENTORY_SLOT_LEFTHAND;
|
|
else
|
|
nOtherHand = INVENTORY_SLOT_RIGHTHAND;
|
|
// Check it's contents and take action if necessary
|
|
if(GetStringLeft(GetTag(GetItemInSlot(nOtherHand, oPC)), 14) == "prc_sk_mblade_")
|
|
MyDestroyObject(GetItemInSlot(nOtherHand, oPC));
|
|
}
|
|
|
|
/* Now in their own script - psi_sk_clseval
|
|
// Hook psi_sk_event to the mindblade-related events it handles
|
|
AddEventScript(oPC, EVENT_ONPLAYEREQUIPITEM, "psi_sk_event", TRUE, FALSE);
|
|
AddEventScript(oPC, EVENT_ONPLAYERUNEQUIPITEM, "psi_sk_event", TRUE, FALSE);
|
|
AddEventScript(oPC, EVENT_ONUNAQUIREITEM, "psi_sk_event", TRUE, FALSE);
|
|
AddEventScript(oPC, EVENT_ONPLAYERDEATH, "psi_sk_event", TRUE, FALSE);
|
|
AddEventScript(oPC, EVENT_ONPLAYERLEVELDOWN, "psi_sk_event", TRUE, FALSE);
|
|
*/
|
|
if(LOCAL_DEBUG) DelayCommand(0.01f, DoDebug("Finished psi_sk_manifmbld")); // Wrap in delaycommand so that the game clock gets to update for the purposes of WriteTimestampedLogEntry
|
|
}
|
|
|
|
|
|
void BuildMindblade(object oPC, object oMbld, int nMbldType)
|
|
{
|
|
/* Add normal stuff and VFX */
|
|
/// Add enhancement bonus
|
|
int nSKLevel = GetLevelByClass(CLASS_TYPE_SOULKNIFE, oPC);
|
|
int nEnh;
|
|
// The first actual enhancement bonus is gained at L4, but the mindblade needs to
|
|
// have enhancement right from the beginning to pierce DR as per being magical
|
|
if(nSKLevel < 4)
|
|
{
|
|
nEnh = 1;
|
|
// The mindblade being magical should grant no benefits to attack or damage
|
|
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyAttackPenalty(1), oMbld);
|
|
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyDamagePenalty(1), oMbld);
|
|
}
|
|
else
|
|
{
|
|
nEnh = nSKLevel <= 20 ?
|
|
nSKLevel / 4: // Boni are granget +1 / 4 levels pre-epic
|
|
(nSKLevel - 20) / 5 + 5; // Boni are granted +1 / 5 levels epic
|
|
// Dual mindblades have one lower bonus
|
|
nEnh -= nMbldType == MBLADE_SHAPE_DUAL_SHORTSWORDS ? 1 : 0;
|
|
}
|
|
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyEnhancementBonus(nEnh), oMbld);
|
|
// In case of bastard sword, store the enhancement bonus for later for use in the 2-h handling code
|
|
if(nMbldType == MBLADE_SHAPE_BASTARDSWORD)
|
|
SetLocalInt(oMbld, "PRC_SK_BSwd_EnhBonus", nEnh);
|
|
|
|
// Handle Greater Weapon Focus (mindblade) here. It grants +1 to attack with any shape of mindblade.
|
|
// Because of stacking issues, the actual value granted is enhancement bonus + 1.
|
|
if(GetHasFeat(FEAT_GREATER_WEAPON_FOCUS_MINDBLADE, oPC))
|
|
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyAttackBonus(nEnh + 1), oMbld);
|
|
|
|
/// Add in VFX
|
|
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyVisualEffect(GetAlignmentGoodEvil(oPC) == ALIGNMENT_GOOD ? ITEM_VISUAL_HOLY :
|
|
GetAlignmentGoodEvil(oPC) == ALIGNMENT_EVIL ? ITEM_VISUAL_EVIL :
|
|
ITEM_VISUAL_SONIC
|
|
), oMbld);
|
|
|
|
/* Add in common feats */
|
|
//string sTag = GetTag(oMbld);
|
|
// For the purposes of the rest of this function, dual shortswords is the same as single shortsword
|
|
if(nMbldType == MBLADE_SHAPE_DUAL_SHORTSWORDS) nMbldType = MBLADE_SHAPE_SHORTSWORD;
|
|
|
|
// Weapon Focus
|
|
/* Every soulknife has this, so it's automatically on the weapons now. Uncomment if for some reason another class with the mindblade class feature is added
|
|
if(GetHasFeat(FEAT_WEAPON_FOCUS_MINDBLADE, oPC))
|
|
AddItemProperty(DURATION_TYPE_PERMANENT, PRCItemPropertyBonusFeat(nMbldType == MBLADE_SHAPE_SHORTSWORD ? IP_CONST_FEAT_WEAPON_FOCUS_SHORT_SWORD :
|
|
nMbldType == MBLADE_SHAPE_LONGSWORD ? IP_CONST_FEAT_WEAPON_FOCUS_LONG_SWORD :
|
|
nMbldType == MBLADE_SHAPE_BASTARDSWORD ? IP_CONST_FEAT_WEAPON_FOCUS_BASTARD_SWORD :
|
|
IP_CONST_FEAT_WEAPON_FOCUS_THROWING_AXE
|
|
), oMbld);*/
|
|
// Improved Critical
|
|
if(GetHasFeat(FEAT_IMPROVED_CRITICAL_MINDBLADE, oPC))
|
|
AddItemProperty(DURATION_TYPE_PERMANENT, PRCItemPropertyBonusFeat(nMbldType == MBLADE_SHAPE_SHORTSWORD ? IP_CONST_FEAT_IMPROVED_CRITICAL_SHORT_SWORD :
|
|
nMbldType == MBLADE_SHAPE_LONGSWORD ? IP_CONST_FEAT_IMPROVED_CRITICAL_LONG_SWORD :
|
|
nMbldType == MBLADE_SHAPE_BASTARDSWORD ? IP_CONST_FEAT_IMPROVED_CRITICAL_BASTARD_SWORD :
|
|
IP_CONST_FEAT_IMPROVED_CRITICAL_THROWING_AXE
|
|
), oMbld);
|
|
// Overwhelming Critical
|
|
if(GetHasFeat(FEAT_OVERWHELMING_CRITICAL_MINDBLADE, oPC))
|
|
AddItemProperty(DURATION_TYPE_PERMANENT, PRCItemPropertyBonusFeat(nMbldType == MBLADE_SHAPE_SHORTSWORD ? IP_CONST_FEAT_EPIC_OVERWHELMING_CRITICAL_SHORTSWORD :
|
|
nMbldType == MBLADE_SHAPE_LONGSWORD ? IP_CONST_FEAT_EPIC_OVERWHELMING_CRITICAL_LONGSWORD :
|
|
nMbldType == MBLADE_SHAPE_BASTARDSWORD ? IP_CONST_FEAT_EPIC_OVERWHELMING_CRITICAL_BASTARDSWORD :
|
|
IP_CONST_FEAT_EPIC_OVERWHELMING_CRITICAL_THROWINGAXE
|
|
), oMbld);
|
|
// Devastating Critical
|
|
if(GetHasFeat(FEAT_DEVASTATING_CRITICAL_MINDBLADE, oPC))
|
|
AddItemProperty(DURATION_TYPE_PERMANENT, PRCItemPropertyBonusFeat(nMbldType == MBLADE_SHAPE_SHORTSWORD ? IP_CONST_FEAT_EPIC_DEVASTATING_CRITICAL_SHORTSWORD :
|
|
nMbldType == MBLADE_SHAPE_LONGSWORD ? IP_CONST_FEAT_EPIC_DEVASTATING_CRITICAL_LONGSWORD :
|
|
nMbldType == MBLADE_SHAPE_BASTARDSWORD ? IP_CONST_FEAT_EPIC_DEVASTATING_CRITICAL_BASTARDSWORD :
|
|
IP_CONST_FEAT_EPIC_DEVASTATING_CRITICAL_THROWINGAXE
|
|
), oMbld);
|
|
// Weapon Specialization
|
|
if(GetHasFeat(FEAT_WEAPON_SPECIALIZATION_MINDBLADE, oPC))
|
|
AddItemProperty(DURATION_TYPE_PERMANENT, PRCItemPropertyBonusFeat(nMbldType == MBLADE_SHAPE_SHORTSWORD ? IP_CONST_FEAT_WEAPON_SPECIALIZATION_SHORT_SWORD :
|
|
nMbldType == MBLADE_SHAPE_LONGSWORD ? IP_CONST_FEAT_WEAPON_SPECIALIZATION_LONG_SWORD :
|
|
nMbldType == MBLADE_SHAPE_BASTARDSWORD ? IP_CONST_FEAT_WEAPON_SPECIALIZATION_BASTARD_SWORD :
|
|
IP_CONST_FEAT_WEAPON_SPECIALIZATION_THROWING_AXE
|
|
), oMbld);
|
|
// Epic Weapon Focus
|
|
if(GetHasFeat(FEAT_EPIC_WEAPON_FOCUS_MINDBLADE, oPC))
|
|
AddItemProperty(DURATION_TYPE_PERMANENT, PRCItemPropertyBonusFeat(nMbldType == MBLADE_SHAPE_SHORTSWORD ? IP_CONST_FEAT_EPIC_WEAPON_FOCUS_SHORT_SWORD :
|
|
nMbldType == MBLADE_SHAPE_LONGSWORD ? IP_CONST_FEAT_EPIC_WEAPON_FOCUS_LONG_SWORD :
|
|
nMbldType == MBLADE_SHAPE_BASTARDSWORD ? IP_CONST_FEAT_EPIC_WEAPON_FOCUS_BASTARD_SWORD :
|
|
IP_CONST_FEAT_EPIC_WEAPON_FOCUS_THROWING_AXE
|
|
), oMbld);
|
|
// Epic Weapon Specialization
|
|
if(GetHasFeat(FEAT_EPIC_WEAPON_SPECIALIZATION_MINDBLADE, oPC))
|
|
AddItemProperty(DURATION_TYPE_PERMANENT, PRCItemPropertyBonusFeat(nMbldType == MBLADE_SHAPE_SHORTSWORD ? IP_CONST_FEAT_EPIC_WEAPON_SPECIALIZATION_SHORT_SWORD :
|
|
nMbldType == MBLADE_SHAPE_LONGSWORD ? IP_CONST_FEAT_EPIC_WEAPON_SPECIALIZATION_LONG_SWORD :
|
|
nMbldType == MBLADE_SHAPE_BASTARDSWORD ? IP_CONST_FEAT_EPIC_WEAPON_SPECIALIZATION_BASTARD_SWORD :
|
|
IP_CONST_FEAT_EPIC_WEAPON_SPECIALIZATION_THROWING_AXE
|
|
), oMbld);
|
|
// Weapon of Choice
|
|
if(GetHasFeat(FEAT_WEAPON_OF_CHOICE_MINDBLADE, oPC) && nMbldType != MBLADE_SHAPE_RANGED)
|
|
AddItemProperty(DURATION_TYPE_PERMANENT, PRCItemPropertyBonusFeat(nMbldType == MBLADE_SHAPE_SHORTSWORD ? IP_CONST_FEAT_WEAPON_OF_CHOICE_SHORTSWORD :
|
|
nMbldType == MBLADE_SHAPE_LONGSWORD ? IP_CONST_FEAT_WEAPON_OF_CHOICE_LONGSWORD :
|
|
nMbldType == MBLADE_SHAPE_BASTARDSWORD ? IP_CONST_FEAT_WEAPON_OF_CHOICE_BASTARDSWORD :
|
|
-1 // This shouldn't ever be reached
|
|
), oMbld);
|
|
// Bladewind: Due to some moron @ BioWare, calls to DoWhirlwindAttack() do not do anything if one
|
|
// does not have the feat. Therefore, we need to grant it as a bonus feat on the blade.
|
|
if(GetHasFeat(FEAT_BLADEWIND, oPC))
|
|
AddItemProperty(DURATION_TYPE_PERMANENT, PRCItemPropertyBonusFeat(IP_CONST_FEAT_WHIRLWIND), oMbld);
|
|
|
|
|
|
/* Apply the enhancements */
|
|
int nFlags = GetPersistantLocalInt(oPC, MBLADE_FLAGS);
|
|
int bLight = FALSE;
|
|
|
|
if(nFlags & MBLADE_FLAG_LUCKY)
|
|
{
|
|
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyCastSpell(IP_CONST_CASTSPELL_MINDBLADE_LUCKY, IP_CONST_CASTSPELL_NUMUSES_1_USE_PER_DAY), oMbld);
|
|
}
|
|
if(nFlags & MBLADE_FLAG_DEFENDING)
|
|
{
|
|
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyACBonus(2), oMbld);
|
|
}
|
|
if(nFlags & MBLADE_FLAG_KEEN)
|
|
{
|
|
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyKeen(), oMbld);
|
|
}
|
|
/*if(nFlags & MBLADE_FLAG_VICIOUS)
|
|
{ OnHit
|
|
}*/
|
|
if(nFlags & MBLADE_FLAG_PSYCHOKINETIC && !(nFlags & MBLADE_FLAG_PSYCHOKINETICBURST)) // Only Psychokinetic
|
|
{
|
|
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyDamageBonus(IP_CONST_DAMAGETYPE_MAGICAL, IP_CONST_DAMAGEBONUS_1d4), oMbld);
|
|
bLight = TRUE;
|
|
}
|
|
if(nFlags & MBLADE_FLAG_MIGHTYCLEAVING)
|
|
{
|
|
if(GetHasFeat(FEAT_CLEAVE, oPC))
|
|
AddItemProperty(DURATION_TYPE_PERMANENT, PRCItemPropertyBonusFeat(IP_CONST_FEAT_GREAT_CLEAVE), oMbld);
|
|
else
|
|
AddItemProperty(DURATION_TYPE_PERMANENT, PRCItemPropertyBonusFeat(IP_CONST_FEAT_CLEAVE), oMbld);
|
|
}
|
|
if(nFlags & MBLADE_FLAG_COLLISION)
|
|
{
|
|
if(LOCAL_DEBUG) DoDebug("Added Collision damage", oPC);
|
|
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyDamageBonus(IP_CONST_DAMAGETYPE_BLUDGEONING, IP_CONST_DAMAGEBONUS_5), oMbld);
|
|
}
|
|
/*if(nFlags & MBLADE_FLAG_MINDCRUSHER )
|
|
{ OnHit
|
|
}*/
|
|
if(nFlags & MBLADE_FLAG_PSYCHOKINETICBURST && !(nFlags & MBLADE_FLAG_PSYCHOKINETIC)) // Only Psychokinetic Burst
|
|
{
|
|
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyDamageBonus(IP_CONST_DAMAGETYPE_MAGICAL, IP_CONST_DAMAGEBONUS_1d4), oMbld);
|
|
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyMassiveCritical(IP_CONST_DAMAGEBONUS_1d6), oMbld);
|
|
bLight = TRUE;
|
|
}
|
|
/*if(nFlags & MBLADE_FLAG_SUPPRESSION)
|
|
{ OnHit
|
|
}*/
|
|
/*if(nFlags & MBLADE_FLAG_WOUNDING)
|
|
{ OnHit
|
|
}*/
|
|
/*if(nFlags & MBLADE_FLAG_DISRUPTING)
|
|
{ OnHit
|
|
}
|
|
if(nFlags & MBLADE_FLAG_SOULBREAKER)
|
|
{
|
|
}*/
|
|
if((nFlags & MBLADE_FLAG_PSYCHOKINETICBURST) && (nFlags & MBLADE_FLAG_PSYCHOKINETIC)) // Both Psychokinetic and Psychokinetic Burst
|
|
{
|
|
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyDamageBonus(IP_CONST_DAMAGETYPE_MAGICAL, IP_CONST_DAMAGEBONUS_2d4), oMbld);
|
|
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyMassiveCritical(IP_CONST_DAMAGEBONUS_1d6), oMbld);
|
|
bLight = TRUE;
|
|
}
|
|
|
|
if(bLight)
|
|
AddItemProperty(DURATION_TYPE_PERMANENT, ItemPropertyLight(IP_CONST_LIGHTBRIGHTNESS_NORMAL, IP_CONST_LIGHTCOLOR_WHITE), oMbld);
|
|
} |