PRC8/nwn/nwnprc/trunk/psionics/psi_sk_manifmbld.nss
Jaysyn904 6ec137a24e Updated AMS marker feats
Updated AMS marker feats.  Removed arcane & divine marker feats.  Updated Dread Necromancer for epic progression. Updated weapon baseitem models.  Updated new weapons for crafting & npc equip.
 Updated prefix.  Updated release archive.
2024-02-11 14:01:05 -05:00

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);
}