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