//::///////////////////////////////////////////////
//:: Greater Wild Shape, Humanoid Shape
//:: x2_s2_gwildshp
//:: Copyright (c) 2003 Bioware Corp.
//:://////////////////////////////////////////////
/*
Allows the character to shift into one of these
forms, gaining special abilities
Credits must be given to mr_bumpkin from the NWN
community who had the idea of merging item properties
from weapon and armor to the creatures new forms.
*/
//:://////////////////////////////////////////////
//:: Created By: Georg Zoeller
//:: Created On: 2003-07-02
//:://////////////////////////////////////////////
//:: Modified By: Iznoghoud
/*
What this script changes:
- Tower shields now carry over their properties just like Small and Large
shields. (Which has been a bug I believe since the original script had 2 checks
for SMALLSHIELD in it, one probably should have been TOWERSHIELD)
- Melee Weapon properties now carry over to the unarmed forms' claws and bite
attacks.
- My last (and most complicated) changes:
1) Now, items with an AC bonus (or penalty) carry over to the shifted form as
the correct type. This means if you wear an amulet of natural armor +4, and a
cloak of protection +5, and you shift to a form that gets all item properties
carried over, you will have the +4 natural armor bonus from the ammy, as well as
the +5 deflection bonus from the cloak. No longer will the highest one override
all the other AC bonuses even if they are a different type. Note that some
forms, such as the dragon, get an inherent natural AC bonus, which may still
override your amulet of natural armor, if the inherent bonus is better.
2) Other "stackable" item properties, like ability bonuses, skill bonuses and
saving throw bonuses, now correctly add up in shifted form. This means if you
have a ring that gives +2 strength, and a ring with +3 strength, and you shift
into a drow warrior, you get +5 strength in shifted form, where you used to get
only +3. (the highest)
-- Modified by StoneDK 2003.12.21
Added saving of old equip to allow items to be applied without going
through normal shape, should now get item effects even when changing
directly from wyrm to kobold shape.
Added message to player about which items are merged.
-- Modified by Iznoghoud 2003-12-26
Added storing of Polymorph ID on the player for letting exportallchars() scripts
reapply polymorphing effects when saving
-- Modified by Iznoghoud 2003-12-27
Added regeneration as a stacking property, bracers now stored correctly for re-shifting,
Added constants for easy configuration.
-- Modified by Iznoghoud January 13 2004
The bulk of the handling of stacking item properties, as well as the constants
for configuration, are now in ws_inc_shifter, which is included
by this file, and the two druid polymorphing scripts, nw_s2_elemshape and nw_s2_wildshape.
Made the message about which items are merged more explicit.
*/
//:://////////////////////////////////////////////
#include "ws_inc_shifter"
// Main function of the script
void main()
{
if(GetLocalInt(GetArea(OBJECT_SELF), "NOCAST")==2 && !GetIsDM(OBJECT_SELF))
{
FloatingTextStringOnCreature("All spells fizzle in town.", OBJECT_SELF);
return;
}
//--------------------------------------------------------------------------
// Declare major variables
//--------------------------------------------------------------------------
object oPC = OBJECT_SELF;
int nSpell = GetSpellId();
object oTarget = GetSpellTargetObject();
effect eVis = EffectVisualEffect(VFX_IMP_POLYMORPH);
int nShifter = GetLevelByClass(CLASS_TYPE_SHIFTER);
effect ePoly;
int nPoly;
//--------------------------------------------------------------------------
// Determine which form to use based on spell id, gender and level
//--------------------------------------------------------------------------
switch (nSpell)
{
//-----------------------------------------------------------------------
// Greater Wildshape I - Wyrmling Shape
//-----------------------------------------------------------------------
case 658: nPoly = POLYMORPH_TYPE_WYRMLING_RED; break;
case 659: nPoly = POLYMORPH_TYPE_WYRMLING_BLUE; break;
case 660: nPoly = POLYMORPH_TYPE_WYRMLING_BLACK; break;
case 661: nPoly = POLYMORPH_TYPE_WYRMLING_WHITE; break;
case 662: nPoly = POLYMORPH_TYPE_WYRMLING_GREEN; break;
//-----------------------------------------------------------------------
// Greater Wildshape II - Minotaur, Gargoyle, Harpy
//-----------------------------------------------------------------------
case 672: if (nShifter < X2_GW2_EPIC_THRESHOLD)
nPoly = POLYMORPH_TYPE_HARPY;
else
nPoly = 97;
break;
case 678: if (nShifter < X2_GW2_EPIC_THRESHOLD)
nPoly = POLYMORPH_TYPE_GARGOYLE;
else
nPoly = 98;
break;
case 680: if (nShifter < X2_GW2_EPIC_THRESHOLD)
nPoly = POLYMORPH_TYPE_MINOTAUR;
else
nPoly = 96;
break;
//-----------------------------------------------------------------------
// Greater Wildshape III - Drider, Basilisk, Manticore
//-----------------------------------------------------------------------
case 670: if (nShifter < X2_GW3_EPIC_THRESHOLD)
nPoly = POLYMORPH_TYPE_BASILISK;
else
nPoly = 99;
break;
case 673: if (nShifter < X2_GW3_EPIC_THRESHOLD)
nPoly = POLYMORPH_TYPE_DRIDER;
else
nPoly = 100;
break;
case 674: if (nShifter < X2_GW3_EPIC_THRESHOLD)
nPoly = POLYMORPH_TYPE_MANTICORE;
else
nPoly = 101;
break;
//-----------------------------------------------------------------------
// Greater Wildshape IV - Dire Tiger, Medusa, MindFlayer
//-----------------------------------------------------------------------
case 679: nPoly = POLYMORPH_TYPE_MEDUSA; break;
case 691: nPoly = 68; break; // Mindflayer
case 694: nPoly = 69; break; // DireTiger
//-----------------------------------------------------------------------
// Humanoid Shape - Kobold Commando, Drow, Lizard Crossbow Specialist
//-----------------------------------------------------------------------
case 682:
if(nShifter< 17)
{
if (GetGender(OBJECT_SELF) == GENDER_MALE) //drow
nPoly = 59;
else
nPoly = 70;
}
else
{
if (GetGender(OBJECT_SELF) == GENDER_MALE) //drow
nPoly = 105;
else
nPoly = 106;
}
break;
case 683:
if(nShifter< 17)
{
nPoly = 82; break; // Lizard
}
else
{
nPoly =104; break; // Epic Lizard
}
case 684: if(nShifter< 17)
{
nPoly = 83; break; // Kobold Commando
}
else
{
nPoly = 103; break; // Kobold Commando
}
//-----------------------------------------------------------------------
// Undead Shape - Spectre, Risen Lord, Vampire
//-----------------------------------------------------------------------
case 704: nPoly = 75; break; // Risen lord
case 705: if (GetGender(OBJECT_SELF) == GENDER_MALE) // vampire
nPoly = 74;
else
nPoly = 77;
break;
case 706: nPoly = 76; break; /// spectre
//-----------------------------------------------------------------------
// Dragon Shape - Red Blue and Green Dragons
//-----------------------------------------------------------------------
case 707: nPoly = 72; break; // Ancient Red Dragon
case 708: nPoly = 71; break; // Ancient Blue Dragon
case 709: nPoly = 73; break; // Ancient Green Dragon
//-----------------------------------------------------------------------
// Outsider Shape - Rakshasa, Azer Chieftain, Black Slaad
//-----------------------------------------------------------------------
case 733: if (GetGender(OBJECT_SELF) == GENDER_MALE) //azer
nPoly = 85;
else // anything else is female
nPoly = 86;
break;
case 734: if (GetGender(OBJECT_SELF) == GENDER_MALE) //rakshasa
nPoly = 88;
else // anything else is female
nPoly = 89;
break;
case 735: nPoly =87; break; // slaad
//-----------------------------------------------------------------------
// Construct Shape - Stone Golem, Iron Golem, Demonflesh Golem
//-----------------------------------------------------------------------
case 738: nPoly =91; break; // stone golem
case 739: nPoly =92; break; // demonflesh golem
case 740: nPoly =90; break; // iron golem
}
//--------------------------------------------------------------------------
// Determine which items get their item properties merged onto the shifters
// new form.
//--------------------------------------------------------------------------
int bWeapon;
int bArmor;
int bItems;
int bCopyGlovesToClaws = FALSE;
bWeapon = ShifterMergeWeapon(nPoly);
if ( GW_ALWAYS_COPY_ARMOR_PROPS )
bArmor = TRUE;
else
bArmor = ShifterMergeArmor(nPoly);
if ( GW_ALWAYS_COPY_ITEM_PROPS )
bItems = TRUE;
else
bItems = ShifterMergeItems(nPoly);
// Send message to PC about which items get merged to this form
string sMerge;
sMerge = "Merged: "; // : This is a color code that makes the text behind it sort of light blue.
if(bArmor) sMerge += "Armor, Helmet, Shield";
if(bItems) sMerge += ", Rings, Amulet, Cloak, Boots, Belt, Bracers";
if( bWeapon || GW_COPY_WEAPON_PROPS_TO_UNARMED == 1 )
sMerge += ", Weapon";
else if ( GW_COPY_WEAPON_PROPS_TO_UNARMED == 2 )
sMerge += ", Gloves to unarmed attacks";
else if (GW_COPY_WEAPON_PROPS_TO_UNARMED == 3 )
sMerge += ", Weapon (if you had one equipped) or gloves to unarmed attacks";
else
sMerge += ", No weapon or gloves to unarmed attacks";
SendMessageToPC(oTarget,sMerge + ".");
// Store which items should transfer to this polymorph type. (For exportallchar scripts)
SetLocalInt(oTarget, "GW_PolyID", nPoly);
SetLocalInt(oTarget, "GW_bWeapon", bWeapon );
SetLocalInt(oTarget, "GW_bArmor", bArmor );
SetLocalInt(oTarget, "GW_bItems", bItems );
//--------------------------------------------------------------------------
// Store the old objects so we can access them after the character has
// changed into his new form
//--------------------------------------------------------------------------
object oWeaponOld;
object oArmorOld;
object oRing1Old ;
object oRing2Old;
object oAmuletOld;
object oCloakOld ;
object oBootsOld ;
object oBeltOld ;
object oHelmetOld;
object oShield ;
object oBracerOld;
object oHideOld;
//Assume the normal shape doesn't have a creature skin object.
//If using a subracesystem or something else that places a skin on the normal shape
//another condition is needed to decide whether or not to store current items.
//One way could be to scan all effects to see whether one is a polymorph effect.
int nPolyed = GetIsObjectValid(GetItemInSlot(INVENTORY_SLOT_CARMOUR,OBJECT_SELF));
// If there is a creature armor see if it is a creature hide put
// on the unpolymorphed player by scanning for a polymorph effect.
if ( nPolyed )
nPolyed = ( ScanForPolymorphEffect(OBJECT_SELF) != -2 );
if(! nPolyed)
{
//if not polymorphed get items worn and store on player.
oWeaponOld = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,OBJECT_SELF);
oArmorOld = GetItemInSlot(INVENTORY_SLOT_CHEST,OBJECT_SELF);
oRing1Old = GetItemInSlot(INVENTORY_SLOT_LEFTRING,OBJECT_SELF);
oRing2Old = GetItemInSlot(INVENTORY_SLOT_RIGHTRING,OBJECT_SELF);
oAmuletOld = GetItemInSlot(INVENTORY_SLOT_NECK,OBJECT_SELF);
oCloakOld = GetItemInSlot(INVENTORY_SLOT_CLOAK,OBJECT_SELF);
oBootsOld = GetItemInSlot(INVENTORY_SLOT_BOOTS,OBJECT_SELF);
oBeltOld = GetItemInSlot(INVENTORY_SLOT_BELT,OBJECT_SELF);
oHelmetOld = GetItemInSlot(INVENTORY_SLOT_HEAD,OBJECT_SELF);
oShield = GetItemInSlot(INVENTORY_SLOT_LEFTHAND,OBJECT_SELF);
oBracerOld = GetItemInSlot(INVENTORY_SLOT_ARMS,OBJECT_SELF);
oHideOld = GetItemInSlot(INVENTORY_SLOT_CARMOUR,OBJECT_SELF);
SetLocalObject(OBJECT_SELF,"GW_OldWeapon",oWeaponOld);
SetLocalObject(OBJECT_SELF,"GW_OldArmor",oArmorOld);
SetLocalObject(OBJECT_SELF,"GW_OldRing1",oRing1Old);
SetLocalObject(OBJECT_SELF,"GW_OldRing2",oRing2Old);
SetLocalObject(OBJECT_SELF,"GW_OldAmulet",oAmuletOld);
SetLocalObject(OBJECT_SELF,"GW_OldCloak",oCloakOld);
SetLocalObject(OBJECT_SELF,"GW_OldBoots",oBootsOld);
SetLocalObject(OBJECT_SELF,"GW_OldBelt",oBeltOld);
SetLocalObject(OBJECT_SELF,"GW_OldHelmet",oHelmetOld);
SetLocalObject(OBJECT_SELF,"GW_OldBracer",oBracerOld);
SetLocalObject(OBJECT_SELF,"GW_OldHide",oHideOld);
if (GetIsObjectValid(oShield))
{
if (GetBaseItemType(oShield) !=BASE_ITEM_LARGESHIELD &&
GetBaseItemType(oShield) !=BASE_ITEM_SMALLSHIELD &&
GetBaseItemType(oShield) !=BASE_ITEM_TOWERSHIELD)
{
oShield = OBJECT_INVALID;
}
}
SetLocalObject(OBJECT_SELF,"GW_OldShield",oShield);
}
else
{
//if already polymorphed use items stored earlier.
oWeaponOld = GetLocalObject(OBJECT_SELF,"GW_OldWeapon");
oArmorOld = GetLocalObject(OBJECT_SELF,"GW_OldArmor");
oRing1Old = GetLocalObject(OBJECT_SELF,"GW_OldRing1");
oRing2Old = GetLocalObject(OBJECT_SELF,"GW_OldRing2");
oAmuletOld = GetLocalObject(OBJECT_SELF,"GW_OldAmulet");
oCloakOld = GetLocalObject(OBJECT_SELF,"GW_OldCloak");
oBootsOld = GetLocalObject(OBJECT_SELF,"GW_OldBoots");
oBeltOld = GetLocalObject(OBJECT_SELF,"GW_OldBelt");
oHelmetOld = GetLocalObject(OBJECT_SELF,"GW_OldHelmet");
oShield = GetLocalObject(OBJECT_SELF,"GW_OldShield");
oBracerOld = GetLocalObject(OBJECT_SELF,"GW_OldBracer");
oHideOld = GetLocalObject(OBJECT_SELF,"GW_OldHide");
}
//--------------------------------------------------------------------------
// Here the actual polymorphing is done
//--------------------------------------------------------------------------
ePoly = EffectPolymorph(nPoly);
//--------------------------------------------------------------------------
// Iznoghoud: Link the stackable properties as permanent bonuses to the
// Polymorph effect, instead of putting them on the creature hide. They will
// properly disappear as soon as the polymorph is ended.
//--------------------------------------------------------------------------
ePoly = AddStackablePropertiesToPoly ( oPC, ePoly, bWeapon, bItems, bArmor, oArmorOld, oRing1Old, oRing2Old, oAmuletOld, oCloakOld, oBracerOld, oBootsOld, oBeltOld, oHelmetOld, oShield, oWeaponOld, oHideOld);
ePoly = ExtraordinaryEffect(ePoly);
ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, OBJECT_SELF);
ApplyEffectToObject(DURATION_TYPE_PERMANENT, ePoly, OBJECT_SELF);
SignalEvent(oTarget, EventSpellCastAt(OBJECT_SELF, GetSpellId(), FALSE));
//--------------------------------------------------------------------------
// This code handles the merging of item properties
//--------------------------------------------------------------------------
object oWeaponNew = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND,OBJECT_SELF);
object oArmorNew = GetItemInSlot(INVENTORY_SLOT_CARMOUR,OBJECT_SELF);
object oClawLeft = GetItemInSlot(INVENTORY_SLOT_CWEAPON_L,OBJECT_SELF);
object oClawRight = GetItemInSlot(INVENTORY_SLOT_CWEAPON_R,OBJECT_SELF);
object oBite = GetItemInSlot(INVENTORY_SLOT_CWEAPON_B,OBJECT_SELF);
//--------------------------------------------------------------------------
// ...Weapons
//--------------------------------------------------------------------------
if (bWeapon)
{
//----------------------------------------------------------------------
// GZ: 2003-10-20
// Sorry, but I was forced to take that out, it was confusing people
// and there were problems with updating the stats sheet.
//----------------------------------------------------------------------
/* if (!GetIsObjectValid(oWeaponOld))
{
//------------------------------------------------------------------
// If we had no weapon equipped before, remove the old weapon
// to allow monks to change into unarmed forms by not equipping any
// weapon before polymorphing
//------------------------------------------------------------------
DestroyObject(oWeaponNew);
}
else*/
{
//------------------------------------------------------------------
// Merge item properties...
//------------------------------------------------------------------
WildshapeCopyWeaponProperties(oTarget, oWeaponOld,oWeaponNew);
}
}
else {
switch ( GW_COPY_WEAPON_PROPS_TO_UNARMED )
{
case 1: // Copy over weapon properties to claws/bite
WildshapeCopyNonStackProperties(oWeaponOld,oClawLeft, TRUE);
WildshapeCopyNonStackProperties(oWeaponOld,oClawRight, TRUE);
WildshapeCopyNonStackProperties(oWeaponOld,oBite, TRUE);
break;
case 2: // Copy over glove properties to claws/bite
WildshapeCopyNonStackProperties(oBracerOld,oClawLeft, FALSE);
WildshapeCopyNonStackProperties(oBracerOld,oClawRight, FALSE);
WildshapeCopyNonStackProperties(oBracerOld,oBite, FALSE);
bCopyGlovesToClaws = TRUE;
break;
case 3: // Copy over weapon properties to claws/bite if wearing a weapon, otherwise copy gloves
if ( GetIsObjectValid(oWeaponOld) )
{
WildshapeCopyNonStackProperties(oWeaponOld,oClawLeft, TRUE);
WildshapeCopyNonStackProperties(oWeaponOld,oClawRight, TRUE);
WildshapeCopyNonStackProperties(oWeaponOld,oBite, TRUE);
}
else
{
WildshapeCopyNonStackProperties(oBracerOld,oClawLeft, FALSE);
WildshapeCopyNonStackProperties(oBracerOld,oClawRight, FALSE);
WildshapeCopyNonStackProperties(oBracerOld,oBite, FALSE);
bCopyGlovesToClaws = TRUE;
}
break;
default: // Do not copy over anything
break;
};
}
//--------------------------------------------------------------------------
// ...Armor
//--------------------------------------------------------------------------
if (bArmor)
{
//----------------------------------------------------------------------
// Merge item properties from armor and helmet...
//----------------------------------------------------------------------
WildshapeCopyNonStackProperties(oArmorOld,oArmorNew);
WildshapeCopyNonStackProperties(oHelmetOld,oArmorNew);
WildshapeCopyNonStackProperties(oShield,oArmorNew);
WildshapeCopyNonStackProperties(oHideOld,oArmorNew);
}
//--------------------------------------------------------------------------
// ...Magic Items
//--------------------------------------------------------------------------
if (bItems)
{
//----------------------------------------------------------------------
// Merge item properties from from rings, amulets, cloak, boots, belt
// Iz: And bracers, in case oBracerOld gets set to a valid object.
//----------------------------------------------------------------------
WildshapeCopyNonStackProperties(oRing1Old,oArmorNew);
WildshapeCopyNonStackProperties(oRing2Old,oArmorNew);
WildshapeCopyNonStackProperties(oAmuletOld,oArmorNew);
WildshapeCopyNonStackProperties(oCloakOld,oArmorNew);
WildshapeCopyNonStackProperties(oBootsOld,oArmorNew);
WildshapeCopyNonStackProperties(oBeltOld,oArmorNew);
// Because Bracers can have On Hit Cast Spell type properties we should
// avoid copying the bracers twice. Otherwise the player can get that On
// Hit effect both when hitting, and getting hit.
if ( bCopyGlovesToClaws == FALSE )
WildshapeCopyNonStackProperties(oBracerOld,oArmorNew);
}
//--------------------------------------------------------------------------
// Set artificial usage limits for special ability spells to work around
// the engine limitation of not being able to set a number of uses for
// spells in the polymorph radial
//--------------------------------------------------------------------------
ShifterSetGWildshapeSpellLimits(nSpell);
}