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.
471 lines
17 KiB
Plaintext
471 lines
17 KiB
Plaintext
void DoNaturalWeaponHB(object oPC = OBJECT_SELF);
|
|
|
|
#include "prc_inc_combat"
|
|
#include "prc_inc_template"
|
|
|
|
object GetProperTarget(object oPC, object oTarget)
|
|
{
|
|
location lTarget = GetLocation(oPC);
|
|
// Use the function to get the closest creature as a target
|
|
object oAreaTarget = MyFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_MEDIUM, lTarget, TRUE, OBJECT_TYPE_CREATURE);
|
|
while(GetIsObjectValid(oAreaTarget))
|
|
{
|
|
if(oAreaTarget != oPC && // Not you.
|
|
GetIsEnemy(oPC, oAreaTarget) && // Enemies only, please
|
|
GetIsInMeleeRange(oPC, oAreaTarget)) // They must be in melee range
|
|
{
|
|
return oAreaTarget;
|
|
}
|
|
//Select the next target within the spell shape.
|
|
oAreaTarget = MyNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_MEDIUM, lTarget, TRUE, OBJECT_TYPE_CREATURE);
|
|
}
|
|
|
|
return oTarget;
|
|
}
|
|
|
|
void DoNaturalAttack(object oWeapon)
|
|
{
|
|
//if weapon is not valid, abort
|
|
if(!GetIsObjectValid(oWeapon))
|
|
return;
|
|
|
|
// object oTarget = GetAttackTarget();
|
|
object oTarget = GetAttemptedAttackTarget();
|
|
|
|
// motu99: The following checks should be made by PerformAttack(), so they are somewhat redundant
|
|
|
|
/*
|
|
//no point attacking plot
|
|
if(GetPlotFlag(oTarget))
|
|
return;
|
|
*/
|
|
if (DEBUG) DoDebug("DoNaturalAttack oTarget1 "+GetName(oTarget));
|
|
object oPC = OBJECT_SELF;
|
|
|
|
// Make sure you don't hit yourself. Some idiot didn't check that.
|
|
if (GetIsFriend(oPC, oTarget) || oPC == oTarget)
|
|
oTarget = GetProperTarget(oPC, oTarget);
|
|
|
|
if (DEBUG) DoDebug("DoNaturalAttack oTarget2 "+GetName(oTarget));
|
|
|
|
// if not melee/ranged fighting, abort
|
|
if (!GetIsObjectValid(oTarget))
|
|
return;
|
|
|
|
// natural attacks are (usually) not ranged attacks, so PerformAttack() will move to a target, if it is out of melee range
|
|
// However, we do not want to run to the target if we are in the midst of doing ranged attacks, e.g. if we have a ranged
|
|
// weapon equipped (and are still out of melee range, so we can effectively do ranged attacks)
|
|
// so check for a ranged weapon in the right hand slot and abort if we have one and are out of melee range
|
|
object oWeaponR = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC);
|
|
if(GetIsObjectValid(oWeaponR)
|
|
&& GetIsRangedWeaponType(GetBaseItemType(oWeaponR))
|
|
&& !GetIsInMeleeRange(oTarget, oPC))
|
|
return;
|
|
/*
|
|
//if not fighting, abort
|
|
// motu99: PRCGetIsFighting() not only checks. whether GetAttemptedAttackTarget() (relevant for melee attacks) returns a valid object
|
|
// it also checks whether we have attempted to attack a valid target with a spell
|
|
// but spell attacks don't make sense for natural attacks (which are pure melee), so commented out
|
|
if(!PRCGetIsFighting(oPC))
|
|
{
|
|
DoDebug(COLOR_WHITE + "DoNaturalAttack(): not fighting any more - aborting");
|
|
return;
|
|
}
|
|
*/
|
|
|
|
//null effect
|
|
effect eInvalid;
|
|
string sMessageSuccess;
|
|
string sMessageFailure;
|
|
if(DEBUG)
|
|
{
|
|
sMessageSuccess += GetName(oWeapon);
|
|
//add attack
|
|
sMessageSuccess += " natural attack";
|
|
//copy it to failure
|
|
sMessageFailure = sMessageSuccess;
|
|
//add hit/miss
|
|
sMessageSuccess += " hit";
|
|
sMessageFailure += " miss";
|
|
//add stars around messages
|
|
sMessageSuccess = "*"+sMessageSuccess+"*";
|
|
sMessageFailure = "*"+sMessageFailure+"*";
|
|
}
|
|
|
|
//secondary attacks are -5 to hit
|
|
int nAttackMod = -5;
|
|
if (GetHasTemplate(TEMPLATE_GRAVETOUCHED_GHOUL, oPC)) nAttackMod = -2; // This is a standin for multiattack
|
|
/*
|
|
//check for (Improved) Multiattack
|
|
if(GetHasFeat(FEAT_IMPROVED_MULTIATTACK, oPC))
|
|
nAttackMod = 0;
|
|
else if(GetHasFeat(FEAT_MULTIATTACK, oPC))
|
|
nAttackMod = -2;
|
|
*/
|
|
//secondary attacks are half strength (we use offhand for this)
|
|
|
|
// set the prc combat mode
|
|
int bCombatMode = PRC_COMBATMODE_HB & PRC_COMBATMODE_ALLOW_TARGETSWITCH & PRC_COMBATMODE_ABORT_WHEN_OUT_OF_RANGE;
|
|
|
|
int nEssentia = GetEssentiaInvested(oPC, MELD_GIRALLON_ARMS);
|
|
if (nEssentia) IPSafeAddItemProperty(oWeapon, ItemPropertyEnhancementBonus(nEssentia), 9999.0, X2_IP_ADDPROP_POLICY_REPLACE_EXISTING, FALSE, TRUE);
|
|
int nStrHalf = GetAbilityModifier(ABILITY_STRENGTH, oPC)/2;
|
|
nStrHalf = nStrHalf * -1;
|
|
|
|
if(DEBUG) DoDebug(PRC_TEXT_WHITE + "initiating a secondary natural attack with "+GetName(oWeapon)+", attack mod " + IntToString(nAttackMod) + ", nStrHalf " + IntToString(nStrHalf));
|
|
|
|
PerformAttack(oTarget,
|
|
oPC, //
|
|
eInvalid, //effect eSpecialEffect,
|
|
0.0, //float eDuration = 0.0
|
|
nAttackMod, //int iAttackBonusMod = 0
|
|
nStrHalf, //int iDamageModifier = Half strength
|
|
DAMAGE_TYPE_SLASHING, //int iDamageType = DAMAGE_TYPE_SLASHING, otherwise it uses magical damage.
|
|
sMessageSuccess, //sMessageSuccess
|
|
sMessageFailure, //sMessageFailure
|
|
FALSE, //int iTouchAttackType = FALSE
|
|
oWeaponR, // we should have something in the right hand (might need it for some calculations)
|
|
oWeapon, // we put the creature weapon in the left hand slot
|
|
FALSE, //offhand override (for half strength)
|
|
bCombatMode // prc scripted combat mode
|
|
);
|
|
}
|
|
|
|
void DoOffhandAttack(int nAttackMod)
|
|
{
|
|
object oPC = OBJECT_SELF;
|
|
object oWeapon = GetItemInSlot(INVENTORY_SLOT_LEFTHAND, oPC);
|
|
|
|
|
|
// check for offhand or double sided weapon, if not - return
|
|
if (!GetIsOffhandWeapon(oWeapon))
|
|
{
|
|
object oWeaponR = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC);
|
|
if (!GetIsDoubleSidedWeapon(oWeaponR))
|
|
return;
|
|
oWeapon = oWeaponR;
|
|
}
|
|
|
|
// object oTarget = GetAttackTarget();
|
|
object oTarget = GetAttemptedAttackTarget();
|
|
|
|
// motu99: The following checks should be made by PerformAttack(), so they are somewhat redundant
|
|
/*
|
|
//no point attacking plot
|
|
if(GetPlotFlag(oTarget))
|
|
return;
|
|
*/
|
|
// Make sure you don't hit yourself. Some idiot didn't check that.
|
|
if (GetIsFriend(oPC, oTarget) || oPC == oTarget)
|
|
oTarget = GetProperTarget(oPC, oTarget);
|
|
|
|
// if not melee fighting, abort
|
|
if (!GetIsObjectValid(oTarget))
|
|
return;
|
|
|
|
/*
|
|
//if not fighting, abort
|
|
if(!PRCGetIsFighting(oPC))
|
|
{
|
|
DoDebug(COLOR_WHITE + "DoOffhandAttack(): not fighting any more - aborting");
|
|
return;
|
|
}
|
|
*/
|
|
string sMessageSuccess;
|
|
string sMessageFailure;
|
|
if (DEBUG)
|
|
{
|
|
sMessageSuccess += GetName(oWeapon);
|
|
//add attack
|
|
sMessageSuccess += " scripted offhand";
|
|
//copy it to failure
|
|
sMessageFailure = sMessageSuccess;
|
|
//add hit/miss
|
|
sMessageSuccess += " hit";
|
|
sMessageFailure += " miss";
|
|
//add stars around messages
|
|
sMessageSuccess = "*"+sMessageSuccess+"*";
|
|
sMessageFailure = "*"+sMessageFailure+"*";
|
|
}
|
|
|
|
//null effect
|
|
effect eInvalid;
|
|
|
|
// set the prc combat mode
|
|
int bCombatMode = PRC_COMBATMODE_HB & PRC_COMBATMODE_ALLOW_TARGETSWITCH & PRC_COMBATMODE_ABORT_WHEN_OUT_OF_RANGE;
|
|
|
|
if (DEBUG) DoDebug(PRC_TEXT_WHITE + "initiating an overflow offhand attack with "+GetName(oWeapon)+" and attack mod "+IntToString(nAttackMod));
|
|
|
|
PerformAttack(oTarget,
|
|
oPC, //
|
|
eInvalid, //effect eSpecialEffect,
|
|
0.0, //float eDuration = 0.0
|
|
nAttackMod, //int iAttackBonusMod = 0
|
|
0, //int iDamageModifier = 0
|
|
DAMAGE_TYPE_SLASHING, //int iDamageType = DAMAGE_TYPE_SLASHING, otherwise it uses magical damage.
|
|
sMessageSuccess, //sMessageSuccess, //string sMessageSuccess = ""
|
|
sMessageFailure, //sMessageFailure, //string sMessageFailure = ""
|
|
FALSE, //int iTouchAttackType = FALSE
|
|
oWeapon, //object oRightHandOverride = OBJECT_INVALID,
|
|
oWeapon, //object oLeftHandOverride = OBJECT_INVALID,
|
|
1, // offhand attack
|
|
bCombatMode // prc combat mode
|
|
);
|
|
}
|
|
|
|
void DoOverflowOnhandAttack(int nAttackMod)
|
|
{
|
|
object oPC = OBJECT_SELF;
|
|
object oWeapon = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND, oPC);
|
|
|
|
//if weapon is not valid, abort
|
|
if(!GetIsObjectValid(oWeapon))
|
|
return;
|
|
|
|
// object oTarget = GetAttackTarget();
|
|
object oTarget = GetAttemptedAttackTarget();
|
|
|
|
// motu99: The following checks should be made by PerformAttack(), so they are somewhat redundant
|
|
/*
|
|
//no point attacking plot
|
|
if(GetPlotFlag(oTarget))
|
|
return;
|
|
*/
|
|
// Make sure you don't hit yourself. Some idiot didn't check that.
|
|
if (GetIsFriend(oPC, oTarget) || oPC == oTarget)
|
|
oTarget = GetProperTarget(oPC, oTarget);
|
|
|
|
// if not melee fighting, abort
|
|
if (!GetIsObjectValid(oTarget))
|
|
return;
|
|
|
|
/*
|
|
//if not fighting, abort
|
|
if(!PRCGetIsFighting(oPC))
|
|
{
|
|
DoDebug(COLOR_WHITE + "DoOverflowOnhandAttack(): not fighting any more - aborting");
|
|
return;
|
|
}
|
|
*/
|
|
string sMessageSuccess;
|
|
string sMessageFailure;
|
|
if (DEBUG)
|
|
{
|
|
sMessageSuccess += GetName(oWeapon);
|
|
//add attack
|
|
sMessageSuccess += " scripted overflow";
|
|
//copy it to failure
|
|
sMessageFailure = sMessageSuccess;
|
|
//add hit/miss
|
|
sMessageSuccess += " hit";
|
|
sMessageFailure += " miss";
|
|
//add stars around messages
|
|
sMessageSuccess = "*"+sMessageSuccess+"*";
|
|
sMessageFailure = "*"+sMessageFailure+"*";
|
|
}
|
|
|
|
//null effect
|
|
effect eInvalid;
|
|
|
|
// set the prc combat mode
|
|
int bCombatMode = PRC_COMBATMODE_HB & PRC_COMBATMODE_ALLOW_TARGETSWITCH & PRC_COMBATMODE_ABORT_WHEN_OUT_OF_RANGE;
|
|
|
|
if (DEBUG) DoDebug(PRC_TEXT_WHITE+"initiating an overflow onhand attack with "+GetName(oWeapon)+" and attack mod "+IntToString(nAttackMod));
|
|
|
|
PerformAttack(oTarget,
|
|
oPC, //
|
|
eInvalid, //effect eSpecialEffect,
|
|
0.0, //float eDuration = 0.0
|
|
nAttackMod, //int iAttackBonusMod = 0
|
|
0, //int iDamageModifier = 0
|
|
DAMAGE_TYPE_SLASHING, //int iDamageType = DAMAGE_TYPE_SLASHING, otherwise it uses magical damage.
|
|
sMessageSuccess,//sMessageSuccess, //string sMessageSuccess = ""
|
|
sMessageFailure,//sMessageFailure, //string sMessageFailure = ""
|
|
FALSE, //int iTouchAttackType = FALSE
|
|
oWeapon, //object oRightHandOverride = OBJECT_INVALID,
|
|
OBJECT_INVALID, //object oLeftHandOverride = OBJECT_INVALID
|
|
0,
|
|
bCombatMode
|
|
);
|
|
}
|
|
|
|
void DoNaturalWeaponHB(object oPC = OBJECT_SELF)
|
|
{
|
|
//not in combat, abort
|
|
if(!GetIsInCombat(oPC))
|
|
return;
|
|
|
|
// if(DEBUG) DoDebug("entered DoNaturalWeaponHB");
|
|
|
|
float fDelay = 0.1 + IntToFloat(Random(10))/100.0;
|
|
|
|
//no natural weapons, abort
|
|
//in a different form, abort for now fix it later
|
|
if(array_exists(oPC, ARRAY_NAT_SEC_WEAP_RESREF)
|
|
&& !GetIsPolyMorphedOrShifted(oPC))
|
|
{
|
|
// DoDebug("DoNaturalWeaponHB: creature has natural secondary weapons");
|
|
UpdateSecondaryWeaponSizes(oPC);
|
|
int i;
|
|
while(i < array_get_size(oPC, ARRAY_NAT_SEC_WEAP_RESREF))
|
|
{
|
|
//get the resref to use
|
|
string sResRef = array_get_string(oPC, ARRAY_NAT_SEC_WEAP_RESREF, i);
|
|
//if null, move to next
|
|
if(sResRef != "")
|
|
{
|
|
//get the created item
|
|
object oWeapon = GetObjectByTag(sResRef);
|
|
if(!GetIsObjectValid(oWeapon))
|
|
{
|
|
object oLimbo = GetObjectByTag("HEARTOFCHAOS");
|
|
location lLimbo = GetLocation(oLimbo);
|
|
if(!GetIsObjectValid(oLimbo))
|
|
lLimbo = GetStartingLocation();
|
|
oWeapon = CreateObject(OBJECT_TYPE_ITEM, sResRef, lLimbo);
|
|
}
|
|
|
|
// DoDebug(COLOR_WHITE + "DoNaturalWeaponHB: scheduling a secondary natural attack with "+GetName(oWeapon)+" at delay "+FloatToString(fDelay));
|
|
//do the attack within a delay
|
|
/*
|
|
// motu99: commented this out; AssignCommand ist not needed, because OBJECT_SELF is oPC - using AssignCommand will only degrade performance
|
|
AssignCommand(oPC, DelayCommand(fDelay, DoNaturalAttack(oWeapon)));
|
|
*/
|
|
|
|
DelayCommand(fDelay, DoNaturalAttack(oWeapon));
|
|
|
|
//calculate the delay to use next time
|
|
fDelay += 2.05;
|
|
if(fDelay > 6.0)
|
|
fDelay -= 6.0;
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
|
|
int iMod = 5; // motu99: added check for monk weapon
|
|
if(GetHasMonkWeaponEquipped(oPC)) iMod = 3;
|
|
|
|
// check for overflow (main hand) attacks
|
|
int nOverflowAttackCount = GetLocalInt(oPC, "OverflowBaseAttackCount");
|
|
if(nOverflowAttackCount)
|
|
{
|
|
int i;
|
|
// the first overflow attack would be the seventh main hand attack, at an AB of -30
|
|
int nAttackPenalty = -6 * iMod; // -30 for normal bab, -18 for monks
|
|
// DoDebug("DoNaturalWeaponHB(): number of scripted overflow attacks: "+IntToString(nOverflowAttackCount));
|
|
for(i = 0; i < nOverflowAttackCount; i++)
|
|
{
|
|
// DoDebug(COLOR_WHITE + "DoNaturalWeaponHB(): scheduling a scripted overflow attack with attack mod "+IntToString(nAttackPenalty)+" at delay "+FloatToString(fDelay));
|
|
/*
|
|
// motu99: see comment above why this is commented out
|
|
AssignCommand(oPC, DelayCommand(fDelay, DoOverflowOnhandAttack(nAttackPenalty)));
|
|
*/
|
|
DelayCommand(fDelay, DoOverflowOnhandAttack(nAttackPenalty));
|
|
|
|
//calculate the delay to use
|
|
fDelay += 2.05;
|
|
if(fDelay > 6.0)
|
|
fDelay -= 6.0;
|
|
//calculate new attack penalty
|
|
nAttackPenalty -= iMod; // motu99: usually -5, for monks -3 (unarmed or kama)
|
|
}
|
|
}
|
|
|
|
// motu99: this is only here for debugging in order to test PerformAttackRound()
|
|
// must be deleted after debugging!!!
|
|
//if (GetPRCSwitch(PRC_PNP_TRUESEEING)) DelayCommand(0.01, DoOffhandAttackRound());
|
|
|
|
|
|
// check for overflow offhand attacks
|
|
int nOffhandAttackCount = GetLocalInt(oPC, "OffhandOverflowAttackCount");
|
|
// if (DEBUG) DoDebug("DoNaturalWeaponHB: number of scripted offhand attacks = "+IntToString(nOffhandAttackCount));
|
|
if(nOffhandAttackCount)
|
|
{
|
|
int i;
|
|
int nAttackPenalty = -2 * iMod; // offhand attacks always come at -5 per additional attack (but for monks we assume -3)
|
|
for(i = 0; i < nOffhandAttackCount; i++)
|
|
{
|
|
// DoDebug(COLOR_WHITE + "DoNaturalWeaponHB(): scheduling a scripted offhand attack with attack mod "+IntToString(nAttackPenalty)+" at delay "+FloatToString(fDelay));
|
|
|
|
DelayCommand(fDelay, DoOffhandAttack(nAttackPenalty));
|
|
|
|
//calculate the delay to use
|
|
fDelay += 2.05;
|
|
if(fDelay > 6.0)
|
|
fDelay -= 6.0;
|
|
//calculate new attack penalty
|
|
nAttackPenalty -= iMod;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* motu99's test functions. Not actually used by PRC scripts
|
|
*/
|
|
|
|
// motu99: This is only for test purposes (in order to test PerformAttackRound())
|
|
void DoOffhandAttackRound(object oPC = OBJECT_SELF)
|
|
{
|
|
// object oTarget = GetAttackTarget();
|
|
object oTarget = GetAttemptedAttackTarget();
|
|
|
|
// motu99: The following checks should be made by PerformAttack(), so they are somewhat redundant
|
|
/*
|
|
//no point attacking plot
|
|
if(GetPlotFlag(oTarget))
|
|
return;
|
|
*/
|
|
// if not melee fighting, abort
|
|
if (!GetIsObjectValid(oTarget))
|
|
return;
|
|
/*
|
|
//if not fighting, abort
|
|
if(!PRCGetIsFighting(oPC))
|
|
{
|
|
DoDebug(COLOR_WHITE + "DoOffhandAttack(): not fighting any more - aborting");
|
|
return;
|
|
}
|
|
*/
|
|
string sMessageSuccess;
|
|
string sMessageFailure;
|
|
if (DEBUG)
|
|
{
|
|
// sMessageSuccess += GetName(oWeapon);
|
|
//add attack
|
|
// sMessageSuccess += " scripted offhand";
|
|
//copy it to failure
|
|
// sMessageFailure = sMessageSuccess;
|
|
//add hit/miss
|
|
sMessageSuccess += "s hit";
|
|
sMessageFailure += "s miss";
|
|
//add stars around messages
|
|
sMessageSuccess = "*"+sMessageSuccess+"*";
|
|
sMessageFailure = "*"+sMessageFailure+"*";
|
|
}
|
|
|
|
//null effect
|
|
effect eInvalid;
|
|
|
|
// set the prc combat mode
|
|
int bCombatMode = PRC_COMBATMODE_HB & PRC_COMBATMODE_ALLOW_TARGETSWITCH & PRC_COMBATMODE_ABORT_WHEN_OUT_OF_RANGE;
|
|
|
|
DoDebug(PRC_TEXT_WHITE + "initiating an overflow offhand attack round");
|
|
|
|
PerformAttackRound(oTarget, // object oDefender
|
|
oPC, // object oAttacker,
|
|
eInvalid, // effect eSpecialEffect,
|
|
0.0, // float eDuration = 0.0,
|
|
0, // int iAttackBonusMod = 0,
|
|
0, // int iDamageModifier = 0,
|
|
0, // int iDamageType = 0,
|
|
TRUE, // int bEffectAllAttacks = FALSE,
|
|
sMessageSuccess, // string sMessageSuccess = "",
|
|
sMessageFailure, // string sMessageFailure = "",
|
|
0, // int bApplyTouchToAll = FALSE,
|
|
0, // int iTouchAttackType = FALSE,
|
|
0, //int bInstantAttack = FALSE);
|
|
bCombatMode // CombatMode
|
|
);
|
|
}
|