2024-06-20 15:47:42 -04:00

557 lines
22 KiB
Plaintext

// ****************************************************************************
// CONFIGURATION
// ****************************************************************************
// The COTW_INCREASE_* constants specify the rate of player levels per increase.
// A value of 4.0 would specify the effect will increase every 4 player levels.
// A value of 0.0 would specify the effect will never increase.
const float COTW_INCREASE_HEAL_TYPE = 4.0;
const float COTW_INCREASE_ATTACK_BONUS = 4.0;
const float COTW_INCREASE_ARMOR_CLASS = 1.5;
const float COTW_INCREASE_REGEN = 4.0;
const float COTW_INCREASE_NUM_ATTACK = 6.0;
const float COTW_INCREASE_DAMAGE = 3.0;
const float COTW_INCREASE_CON = 3.0;
const float COTW_INCREASE_STR = 3.0;
const float COTW_INCREASE_LISTEN_SPOT = 1.5;
// How much should the movement speed increase per level? (Maximum movement speed is 150)
const float COTW_MOVEMENT_SPEED = 2.5;
// How many seconds should pass between regenerating HP?
const float COTW_REGEN_TIMER = 6.0;
// While in wolf state the player can have random bad effects.
const int COTW_USE_BAD_EFFECTS = TRUE;
// Chance that the player will become confused while in the werewolf state and
// they are in combat.
const int COTW_USE_BLOODLUST = TRUE;
// Set how often to time the bloodlust/bad effect checks (increase time to
// reduce CPU usage)
const float COTW_TIMER = 120.0f;
// ****************************************************************************
// CONSTANTS
// ****************************************************************************
const string COTW_ITEM_STOP_WOLF = "cotw_on_activate_stop";
const string COTW_ITEM_START_WOLF = "cotw_on_activate_start";
const string COTW_ITEM_STOP_RESREF = "cotw_on_act_stop";
const string COTW_ITEM_START_RESREF = "cotw_on_act_star";
const string COTW_ITEM_DM_WIDGET = "cotw_on_activate_dm";
const string COTW_CACHED_ITEM = "cotw_cached_item";
const string COTW_STATE_MACHINE = "cotw_state_machine";
const string COTW_HEALED = "cotw_healed";
const int COTW_STATE_INACTIVE = 0;
const int COTW_STATE_WOLF = 1;
const int COTW_STATE_NORMAL = 2;
// ****************************************************************************
// FUNCTION DECLARATIONS/PROTOTYPES
// ****************************************************************************
// COTWGetBAB
// Calculates the basic attack bonus based on the classes that oTarget possesses.
// object oTarget - the target to get the basic attack bonus of.
// Returns the basic attack bonus.
int COTWGetBAB (object oTarget);
// COTWRemoveWolfEffects
// Removes the werewolf effect from OBJECT_SELF.
void COTWRemoveWolfEffect();
// COTWDebug
// Modify this function if you want to enable debugging messages for this script.
void COTWDebug(string sMsg);
// COTWWolfGetDmgBonus
// int iDmg - a value between 1 to 7.
// Returns a DAMAGE_BONUS_* constant based on the value supplied.
int COTWWolfGetDmgBonus (int iDmg);
// COTWWolfGetHealType
// int iHeal - a value between 1 to 6.
// Returns a cure wounds SPELL_* constant based on the value supplied.
int COTWWolfGetHealType (int iHeal);
// COTWCreateWolfEffect
// Creates the werewolf effect from OBJECT_SELF.
// int bInstant - setting this to true will skip the healing and transformation
// visuals.
void COTWCreateWolfEffect(int bInstant = FALSE);
// COTWStartWolf
// Creates the werewolf effect and changes the activated item.
// object oPC - player to make into a werewolf.
// object oActivatedItem - item
void COTWStartWolf (object oPC, object oActivatedItem);
// COTWStopWolf
// Removes the werewolf effect and changes the activated item.
// object oPC - player to make normal.
// object oActivatedItem - item
void COTWStopWolf (object oPC, object oActivatedItem);
// COTWTimer
// Timer that runs on the player while they are in the werewolf state.
void COTWTimer ();
// COTWOnActivateItem
// OnActivateItem event handler. Returns TRUE if it could handle activating
// the item.
// object oUser - person activating the item
// object oTarget - target of the item
// object oItem - the activated item
int COTWOnActivateItem (object oUser, object oTarget, object oItem);
// COTWOnUnAcquiredItem
// OnUnAcquiredItem event handler. Returns TRUE if it could handle activating
// the item.
// object oPC - person dropping the item
// object oItem - the lost item
int COTWOnUnAcquiredItem (object oPC, object oItem);
// COTWOnPlayerDeath
// OnPlayerDeath event handler. Returns TRUE if the player lost the werewolf
// effect from death.
// object oPC - person who died
int COTWOnPlayerDeath (object oPC);
// COTWOnClientEnter
// OnClientEnter event handler. Applies the werewolf effect if the player
// has the item that signifies being a werewolf.
// object oPC - person who entered the module
void COTWOnClientEnter (object oPC);
// ****************************************************************************
// FUNCTIONS
// ****************************************************************************
int COTWGetBAB (object oTarget)
{
// Original function by Jasperre posted on the bioboards at 19 May 2003
// oTarget - the creature to find the BAB for.
// Returns: Base Attack Bonus (strictly by class, no ability/item modifiers)
if (!GetIsObjectValid(oTarget)) return 0;
int nBAB1 = GetLevelByClass(CLASS_TYPE_RANGER, oTarget)
+ GetLevelByClass(CLASS_TYPE_FIGHTER, oTarget)
+ GetLevelByClass(CLASS_TYPE_PALADIN, oTarget)
+ GetLevelByClass(CLASS_TYPE_BARBARIAN, oTarget)
+ GetLevelByClass(CLASS_TYPE_DRAGON, oTarget)
+ GetLevelByClass(CLASS_TYPE_OUTSIDER, oTarget)
+ GetLevelByClass(CLASS_TYPE_MONSTROUS, oTarget)
+ GetLevelByClass(CLASS_TYPE_ARCANE_ARCHER, oTarget)
+ GetLevelByClass(CLASS_TYPE_BLACKGUARD, oTarget);
int nBAB2 = GetLevelByClass(CLASS_TYPE_ABERRATION, oTarget)
+ GetLevelByClass(CLASS_TYPE_ANIMAL, oTarget)
+ GetLevelByClass(CLASS_TYPE_BARD, oTarget)
+ GetLevelByClass(CLASS_TYPE_BEAST, oTarget)
+ GetLevelByClass(CLASS_TYPE_CLERIC, oTarget)
+ GetLevelByClass(CLASS_TYPE_CONSTRUCT, oTarget)
+ GetLevelByClass(CLASS_TYPE_DRUID, oTarget)
+ GetLevelByClass(CLASS_TYPE_ELEMENTAL, oTarget)
+ GetLevelByClass(CLASS_TYPE_GIANT, oTarget)
+ GetLevelByClass(CLASS_TYPE_HUMANOID, oTarget)
+ GetLevelByClass(CLASS_TYPE_MAGICAL_BEAST, oTarget)
+ GetLevelByClass(CLASS_TYPE_MONK, oTarget)
+ GetLevelByClass(CLASS_TYPE_ROGUE, oTarget)
+ GetLevelByClass(CLASS_TYPE_SHAPECHANGER, oTarget)
+ GetLevelByClass(CLASS_TYPE_VERMIN, oTarget)
+ GetLevelByClass(CLASS_TYPE_ASSASSIN, oTarget)
+ GetLevelByClass(CLASS_TYPE_HARPER, oTarget)
+ GetLevelByClass(CLASS_TYPE_SHADOWDANCER, oTarget);
int nBAB3 = GetLevelByClass(CLASS_TYPE_COMMONER, oTarget)
+ GetLevelByClass(CLASS_TYPE_FEY, oTarget)
+ GetLevelByClass(CLASS_TYPE_UNDEAD, oTarget)
+ GetLevelByClass(CLASS_TYPE_SORCERER, oTarget)
+ GetLevelByClass(CLASS_TYPE_WIZARD, oTarget);
int nBaseBAB = nBAB1 + (nBAB2 * 3 / 4) + (nBAB3 / 2);
return nBaseBAB;
}
// ****************************************************************************
void COTWRemoveWolfEffect()
{
// We can't just add more spell effects because they will stack.
// We have to remove any existing spell effects first.
effect eEffect = GetFirstEffect(OBJECT_SELF);
while (GetIsEffectValid(eEffect))
{
if (GetEffectType(eEffect) == EFFECT_TYPE_POLYMORPH)
{
// Is the effect extraordinary?
if (GetEffectSubType(eEffect) == SUBTYPE_SUPERNATURAL)
{
RemoveEffect(OBJECT_SELF, eEffect);
}
}
eEffect = GetNextEffect(OBJECT_SELF);
}
SetLocalInt(OBJECT_SELF, COTW_STATE_MACHINE, COTW_STATE_NORMAL);
}
// ****************************************************************************
void COTWDebug(string sMsg)
{
//SendMessageToPC(OBJECT_SELF, sMsg);
SendMessageToAllDMs(sMsg);
}
// ****************************************************************************
int COTWWolfGetDmgBonus (int iDmg)
{
// Return a damage bonus constant.
switch (iDmg)
{
case 1: return DAMAGE_BONUS_2;
case 2: return DAMAGE_BONUS_1d4;
case 3: return DAMAGE_BONUS_1d6;
case 4: return DAMAGE_BONUS_1d8;
case 5: return DAMAGE_BONUS_1d10;
case 6: return DAMAGE_BONUS_2d6;
case 7: return DAMAGE_BONUS_2d6;
}
return DAMAGE_BONUS_1;
}
// ****************************************************************************
int COTWWolfGetHealType (int iHeal)
{
// Return a cure wounds spell.
switch (iHeal)
{
case 1: return SPELL_CURE_MINOR_WOUNDS;
case 2: return SPELL_CURE_LIGHT_WOUNDS;
case 3: return SPELL_CURE_MODERATE_WOUNDS;
case 4: return SPELL_CURE_SERIOUS_WOUNDS;
case 5: return SPELL_CURE_CRITICAL_WOUNDS;
case 6: return SPELL_HEAL;
}
return SPELL_HEAL;
}
// ****************************************************************************
void COTWCreateWolfEffect(int bInstant = FALSE)
{
// Create the werewolf effect.
// Check if they are already under the effect of the timer.
if (GetLocalInt(OBJECT_SELF, COTW_STATE_MACHINE) == COTW_STATE_WOLF)
{
COTWRemoveWolfEffect();
} else {
if ((COTW_USE_BAD_EFFECTS || COTW_USE_BLOODLUST) && COTW_TIMER > 0.0)
DelayCommand(COTW_TIMER, COTWTimer());
}
// Find the character level
int iCharLevel = GetHitDice(OBJECT_SELF);
// If the effect isn't being instantly created, then creating the wolf effect
// heals the character.
if (COTW_INCREASE_HEAL_TYPE > 0.0)
{
if ((!bInstant) && (GetLocalInt(OBJECT_SELF, COTW_HEALED) == 0))
{
// Prevent the player from repeatedly changing shape for the free heals.
DelayCommand(480.0, DeleteLocalInt(OBJECT_SELF, COTW_HEALED));
SetLocalInt(OBJECT_SELF, COTW_HEALED, 1);
int iSpellID = COTWWolfGetHealType(FloatToInt(iCharLevel / COTW_INCREASE_HEAL_TYPE)+1);
ActionCastSpellAtObject(iSpellID, OBJECT_SELF, METAMAGIC_EMPOWER, TRUE, 0, PROJECTILE_PATH_TYPE_DEFAULT, TRUE);
}
}
// Start building up the wolf effect.
effect eWolf = EffectPolymorph(POLYMORPH_TYPE_WEREWOLF);
if (COTW_INCREASE_ATTACK_BONUS > 0.0)
{
// Increase attack bonus.
int iABInc = iCharLevel - COTWGetBAB(OBJECT_SELF) + FloatToInt(iCharLevel / COTW_INCREASE_ATTACK_BONUS);
eWolf = EffectLinkEffects (EffectAttackIncrease(iABInc, ATTACK_BONUS_MISC), eWolf);
COTWDebug("Wolf: Increasing AB by: "+IntToString(iABInc));
}
if (COTW_INCREASE_ARMOR_CLASS > 0.0)
{
// Increase armor class.
int iACInc = FloatToInt(iCharLevel / COTW_INCREASE_ARMOR_CLASS);
eWolf = EffectLinkEffects (EffectACIncrease(iACInc), eWolf);
COTWDebug("Wolf: Increasing AC by: "+IntToString(iACInc));
}
if (COTW_INCREASE_REGEN > 0.0)
{
// Increase regeneration.
int iRegen = FloatToInt(iCharLevel / COTW_INCREASE_REGEN);
eWolf = EffectLinkEffects (EffectRegenerate(iRegen, COTW_REGEN_TIMER), eWolf);
COTWDebug("Wolf: Increasing Regen by: "+IntToString(iRegen));
}
if (COTW_INCREASE_NUM_ATTACK > 0.0)
{
// Increase number of attacks.
int iAttacks = FloatToInt(iCharLevel / COTW_INCREASE_NUM_ATTACK);
eWolf = EffectLinkEffects (EffectModifyAttacks(iAttacks), eWolf);
COTWDebug("Wolf: Increasing number of attacks by: "+IntToString(iAttacks));
}
if (COTW_MOVEMENT_SPEED > 0.0)
{
// Increase movement speed.
int iSpeed = FloatToInt(iCharLevel * COTW_MOVEMENT_SPEED);
eWolf = EffectLinkEffects (EffectMovementSpeedIncrease(iSpeed), eWolf);
COTWDebug("Wolf: movement speed by: "+IntToString(iSpeed));
}
if (COTW_INCREASE_DAMAGE > 0.0)
{
// Increase unarmed damage.
int iDmg = COTWWolfGetDmgBonus(FloatToInt(iCharLevel / COTW_INCREASE_DAMAGE));
eWolf = EffectLinkEffects (EffectDamageIncrease(iDmg), eWolf);
COTWDebug("Wolf: Damage by: "+IntToString(iDmg));
}
if (COTW_INCREASE_CON > 0.0)
{
// Increase constitution.
int iCon = FloatToInt(iCharLevel / COTW_INCREASE_CON);
eWolf = EffectLinkEffects (EffectAbilityIncrease(ABILITY_CONSTITUTION, iCon), eWolf);
COTWDebug("Wolf: Increase constitution by: "+IntToString(iCon));
}
if (COTW_INCREASE_STR > 0.0)
{
// Increase strength.
int iStr = FloatToInt(iCharLevel / COTW_INCREASE_STR);
eWolf = EffectLinkEffects (EffectAbilityIncrease(ABILITY_STRENGTH, iStr), eWolf);
COTWDebug("Wolf: Increase constitution by: "+IntToString(iStr));
}
if (COTW_INCREASE_LISTEN_SPOT > 0.0)
{
// Increase Spot and Listen skills
int iSkill = FloatToInt(iCharLevel / COTW_INCREASE_LISTEN_SPOT);
eWolf = EffectLinkEffects (EffectSkillIncrease(SKILL_LISTEN, iSkill), eWolf);
eWolf = EffectLinkEffects (EffectSkillIncrease(SKILL_SPOT, iSkill), eWolf);
COTWDebug("Wolf: Increased listen/spot by: "+IntToString(iSkill));
}
if (!bInstant)
{
FloatingTextStringOnCreature("You feel as if your bones are shifting under your skin.", OBJECT_SELF, FALSE);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_DUR_PROT_SHADOW_ARMOR), OBJECT_SELF, 7.0);
DelayCommand(3.0f, PlaySound ("as_an_wolveshwl1"));
DelayCommand(6.0f, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_IMP_POLYMORPH), OBJECT_SELF, 9.0));
DelayCommand(6.0f, ApplyEffectToObject(DURATION_TYPE_PERMANENT, SupernaturalEffect(eWolf), OBJECT_SELF));
} else {
ApplyEffectToObject(DURATION_TYPE_PERMANENT, SupernaturalEffect(eWolf), OBJECT_SELF);
}
SetLocalInt(OBJECT_SELF, COTW_STATE_MACHINE, COTW_STATE_WOLF);
}
// ****************************************************************************
void COTWStartWolf (object oPC, object oActivatedItem)
{
// Turn them into a wolf.
FloatingTextStringOnCreature(GetName(oPC)+" starts to change shape.", oPC);
AssignCommand(oPC, COTWCreateWolfEffect());
// Destroy the activating item.
if (GetIsObjectValid(oActivatedItem)) { SetPlotFlag(oActivatedItem, FALSE); DestroyObject(oActivatedItem); }
// Check where the player's last item went.
oActivatedItem = GetLocalObject(oPC, COTW_CACHED_ITEM);
if (GetIsObjectValid(oActivatedItem)) { SetPlotFlag(oActivatedItem, FALSE); DestroyObject(oActivatedItem); }
// Check that the player doesn't have additional items through a bug.
oActivatedItem = GetItemPossessedBy(oPC, COTW_ITEM_START_WOLF);
if (GetIsObjectValid(oActivatedItem)) { SetPlotFlag(oActivatedItem, FALSE); DestroyObject(oActivatedItem); }
// Create a new item.
oActivatedItem = CreateItemOnObject(COTW_ITEM_STOP_RESREF, oPC);
// Cache the item to prevent duplication.
SetLocalObject(oPC, COTW_CACHED_ITEM, oActivatedItem);
FloatingTextStringOnCreature("OOC: Drop the 'Stop Werewolf Form' item to regain your true shape.", oPC, FALSE);
}
// ****************************************************************************
void COTWStopWolf (object oTarget, object oActivatedItem)
{
// Remove the wolf effects.
FloatingTextStringOnCreature(GetName(oTarget)+" starts to return to normal.", oTarget);
AssignCommand(oTarget, COTWRemoveWolfEffect());
// Destroy the activating item.
if (GetIsObjectValid(oActivatedItem)) { SetPlotFlag(oActivatedItem, FALSE); DestroyObject(oActivatedItem); }
// Check where the player's last item went.
oActivatedItem = GetLocalObject(oTarget, COTW_CACHED_ITEM);
if (GetIsObjectValid(oActivatedItem)) { SetPlotFlag(oActivatedItem, FALSE); DestroyObject(oActivatedItem); }
// Check that the player doesn't have additional items through a bug.
oActivatedItem = GetItemPossessedBy(oTarget, COTW_ITEM_STOP_WOLF);
if (GetIsObjectValid(oActivatedItem)) { SetPlotFlag(oActivatedItem, FALSE); DestroyObject(oActivatedItem); }
// Create a new item.
oActivatedItem = CreateItemOnObject(COTW_ITEM_START_RESREF, oTarget);
// Cache the item to prevent duplication.
SetLocalObject(oTarget, COTW_CACHED_ITEM, oActivatedItem);
}
// ****************************************************************************
void COTWTimer ()
{
if (GetLocalInt(OBJECT_SELF, COTW_STATE_MACHINE) != COTW_STATE_WOLF)
{
return;
}
// Reassign the timer as the first action so that the timer isn't lost in
// a lag situation.
AssignCommand(OBJECT_SELF, DelayCommand(COTW_TIMER, COTWTimer()));
if (COTW_USE_BLOODLUST && GetIsInCombat())
{
// The creature is in combat, check if they go into bloodlust.
if (Random(10) == 9)
{
FloatingTextStringOnCreature("The smell of blood is too much...", OBJECT_SELF);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectConfused(), OBJECT_SELF, d6()*6.0);
}
}
else if (COTW_USE_BAD_EFFECTS)
{
switch (Random(36)+1)
{
case 1:
case 2:
case 3:
FloatingTextStringOnCreature("You feel hungry.", OBJECT_SELF);
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d4()), OBJECT_SELF);
break;
case 4:
case 5:
case 6:
FloatingTextStringOnCreature("Your increased hearing overwhelms your ears.", OBJECT_SELF);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectDeaf(), OBJECT_SELF, d4()*6.0);
break;
case 7:
case 8:
FloatingTextStringOnCreature("Your sight swims with visions of bloody meat.", OBJECT_SELF);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectBlindness(), OBJECT_SELF, d2()*6.0);
break;
case 9:
case 10:
case 11:
FloatingTextStringOnCreature("The need to kill is rising.", OBJECT_SELF);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectMissChance(3*d20()), OBJECT_SELF, d6()*6.0);
break;
case 12:
case 13:
FloatingTextStringOnCreature(GetName(GetNearestObject())+" looks tasty.", OBJECT_SELF);
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDamage(d8()), OBJECT_SELF);
break;
case 14:
FloatingTextStringOnCreature("Your increased metabolism needs more food.", OBJECT_SELF);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectSlow(), OBJECT_SELF, d3()*6.0);
break;
case 15:
case 16:
FloatingTextStringOnCreature("The hunger is keeping you from doing anything else.", OBJECT_SELF);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectDazed(), OBJECT_SELF, d3()*6.0);
break;
case 17:
FloatingTextStringOnCreature("The changes in your body overwhelm you.", OBJECT_SELF);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectStunned(), OBJECT_SELF, d2()*6.0);
break;
case 18:
FloatingTextStringOnCreature("You feel the animal within take control.", OBJECT_SELF);
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectFrightened(), OBJECT_SELF, d2()*6.0);
break;
default:
// do nothing
break;
}
}
}
// ****************************************************************************
int COTWOnActivateItem (object oUser, object oTarget, object oItem)
{
// OnActivateItem event handler.
string sTag = GetTag(oItem);
if (sTag == COTW_ITEM_STOP_WOLF)
{
COTWStopWolf(oTarget, oItem);
return TRUE;
}
if (sTag == COTW_ITEM_START_WOLF)
{
COTWStartWolf(oTarget, oItem);
return TRUE;
}
if (sTag == COTW_ITEM_DM_WIDGET)
{
if (!GetIsDM(oUser) && !GetIsDM(GetMaster(oUser)))
{
FloatingTextStringOnCreature("You cannot use a DM item.", oUser, FALSE);
SetPlotFlag(oItem, FALSE);
DestroyObject(oItem);
return TRUE;
}
if (GetLocalInt(oTarget, COTW_STATE_MACHINE) == COTW_STATE_WOLF)
{
AssignCommand(oTarget, COTWRemoveWolfEffect());
return TRUE;
}
else
{
AssignCommand(oTarget, COTWCreateWolfEffect());
return TRUE;
}
}
return FALSE;
}
// ****************************************************************************
int COTWOnUnAcquiredItem (object oPC, object oItem)
{
// OnUnAcquiredItem event handler.
string sTag = GetTag(oItem);
// Dropping actives the item. This is because polymorphed
// creatures can't use items.
if (sTag == COTW_ITEM_STOP_WOLF)
{
COTWStopWolf(oPC, oItem);
return TRUE;
}
if (sTag == COTW_ITEM_START_WOLF)
{
COTWStartWolf(oPC, oItem);
return TRUE;
}
return FALSE;
}
// ****************************************************************************
int COTWOnPlayerDeath (object oPC)
{
// OnPlayerDeath event handler.
if (GetLocalInt(oPC, COTW_STATE_MACHINE) == COTW_STATE_WOLF)
{
object oItem = GetItemPossessedBy(oPC, COTW_ITEM_STOP_WOLF);
if (GetIsObjectValid(oItem)) COTWStopWolf(oPC, oItem);
else AssignCommand(oPC, COTWRemoveWolfEffect());
return TRUE;
}
return FALSE;
}
// ****************************************************************************
void COTWOnClientEnter (object oPC)
{
// OnClientEneter event handler.
object oItem = GetItemPossessedBy(oPC, COTW_ITEM_STOP_WOLF);
if (GetIsObjectValid(oItem))
{
FloatingTextStringOnCreature("OOC: Reapplying lycanthropy effect.", oPC, FALSE);
AssignCommand(oPC, COTWCreateWolfEffect(TRUE));
return;
}
}
//void main(){}