Added Mine & Caverns raise & lower functionality. Revamped Level 1 events to match PnP. Updated Level 1: Core. Added new Footcatcher trap type. Added Underwater heartbeat to Glop Lake Underwater. Full compile.
174 lines
5.8 KiB
Plaintext
174 lines
5.8 KiB
Plaintext
//::////////////////////////////////////////////////////////////////////////////
|
|
//::
|
|
// underwater_hb.nss
|
|
/*
|
|
Handles being underwater.
|
|
|
|
*/
|
|
//
|
|
//::
|
|
//::////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "prc_inc_spells"
|
|
#include "x0_i0_match"
|
|
|
|
|
|
//:: Checks if a creature is Aquatic for underwater related scripting
|
|
int GetIsAquatic(object oCreature)
|
|
{
|
|
//:: Check if the provided object is valid
|
|
if (!GetIsObjectValid(oCreature))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//:: Get the subrace field of the creature or player, set to lowercase
|
|
string sSubrace = GetStringLowerCase(GetSubRace(oCreature));
|
|
|
|
if (FindSubString(sSubrace, "aquatic") != -1)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
//:: Check for aquatic or amphibious appearance
|
|
int nAppearance = GetAppearanceType(oCreature);
|
|
switch(nAppearance)
|
|
{
|
|
case APPEARANCE_TYPE_SHARK_GOBLIN:
|
|
case APPEARANCE_TYPE_SHARK_HAMMERHEAD:
|
|
case APPEARANCE_TYPE_SHARK_MAKO:
|
|
case APPEARANCE_TYPE_MEPHIT_OOZE:
|
|
case APPEARANCE_TYPE_MEPHIT_WATER:
|
|
case APPEARANCE_TYPE_SEA_HAG:
|
|
|
|
//:: CEP appearances follow
|
|
case 872: //:: Leviathan
|
|
case 990: //:: Troll, Scrag
|
|
case 1427: //:: Crab: Blue: Giant* (Eligio Sacateca)
|
|
case 1428: //:: Crab: Blue: Small* (Eligio Sacateca)
|
|
case 1429: //:: Crab: Red: Giant 1* (Eligio Sacateca)
|
|
case 1430: //:: Crab: Red: Small 1* (Eligio Sacateca)
|
|
case 3053: //:: Bullywug: Brown-Green* (baba yaga)
|
|
case 3054: //:: Bullywug: Green* (baba yaga)
|
|
case 3055: //:: Bullywug: Brown* (baba yaga)
|
|
case 3538: //:: Fish: Pike* (JFK)
|
|
case 3539: //:: Fish: Pike, Giant* (JFK)
|
|
case 3889: //:: Hag: Sea 2* (Hardpoints)
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//:: If you made it this far, return false.
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//:: Can't breathe in water
|
|
void ApplySuffocationEffect(object oCreature)
|
|
{
|
|
int iConstitution = GetAbilityScore(oCreature, ABILITY_CONSTITUTION);
|
|
int iBreathRounds = iConstitution * 2;
|
|
int iSuffocationDC = 10; // Starting suffocation DC
|
|
|
|
int iCurrentRound = GetLocalInt(oCreature, "SuffocationRound");
|
|
|
|
if (iCurrentRound <= iBreathRounds)
|
|
{
|
|
if (GetResRef(OBJECT_SELF) != "mepooze001" &&
|
|
GetResRef(OBJECT_SELF) != "tarmephit001" &&
|
|
!GetHasFeat(FEAT_WATER_BREATHING, oCreature) &&
|
|
!GetHasFeat(FEAT_BREATHLESS, oCreature) &&
|
|
!GetHasSpellEffect(SPELL_WATER_BREATHING, oCreature) &&
|
|
(MyPRCGetRacialType(oCreature) != RACIAL_TYPE_UNDEAD) &&
|
|
(MyPRCGetRacialType(oCreature) != RACIAL_TYPE_ELEMENTAL) &&
|
|
(MyPRCGetRacialType(oCreature) != RACIAL_TYPE_CONSTRUCT))
|
|
{
|
|
SendMessageToPC(oCreature, "You are struggling to breathe in the water!");
|
|
|
|
if (d20() + GetFortitudeSavingThrow(oCreature) >= iSuffocationDC)
|
|
{
|
|
SendMessageToPC(oCreature, "You manage to hold your breath and avoid suffocation for now.");
|
|
}
|
|
else
|
|
{
|
|
SendMessageToPC(oCreature, "You are drowning!");
|
|
|
|
if (iCurrentRound == 1)
|
|
{
|
|
AssignCommand(oCreature, ActionPlayAnimation(ANIMATION_LOOPING_SPASM, 0.5f, 6.0f));
|
|
SetCurrentHitPoints(oCreature, 1);
|
|
}
|
|
else if (iCurrentRound == 2)
|
|
{
|
|
SetCurrentHitPoints(oCreature, 0);
|
|
}
|
|
else if (iCurrentRound == 3)
|
|
{
|
|
ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_DEATH), oCreature);
|
|
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectDeath(), oCreature);
|
|
}
|
|
|
|
iCurrentRound++;
|
|
}
|
|
}
|
|
|
|
// Store the updated round counter back in the creature's local variables
|
|
SetLocalInt(oCreature, "SuffocationRound", iCurrentRound);
|
|
}
|
|
}
|
|
|
|
|
|
//:: Water slows non-aquatic to 1/2 speed
|
|
//:: unless they are under the effect of Freedom of Movement
|
|
void ApplySlowEffect(object oCreature)
|
|
{
|
|
if (GetIsAquatic(oCreature) == FALSE &&
|
|
GetResRef(OBJECT_SELF) != "mepooze001" &&
|
|
GetResRef(OBJECT_SELF) != "tarmephit001" &&
|
|
!GetHasSpellEffect(SPELL_FREEDOM_OF_MOVEMENT, oCreature) ||
|
|
GetHasEffect(IMMUNITY_TYPE_MOVEMENT_SPEED_DECREASE, oCreature))
|
|
{
|
|
// Object has either Freedom of Movement spell effect or IMMUNITY_TYPE_MOVEMENT_SPEED_DECREASE effect
|
|
SendMessageToPC(GetFirstPC(), "This object has Freedom of Movement or immunity to movement speed decrease!");
|
|
}
|
|
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectMovementSpeedDecrease(50), oCreature, 6.0f);
|
|
}
|
|
|
|
void main()
|
|
{
|
|
object oArea = GetArea(OBJECT_SELF);
|
|
object oCreature = GetFirstObjectInArea(oArea, OBJECT_TYPE_CREATURE);
|
|
|
|
string sResref = GetResRef(oCreature);
|
|
|
|
while (GetIsObjectValid(oCreature))
|
|
{
|
|
//:: Calculate the armor penalty
|
|
int iArmorPenalty = 0;
|
|
object oArmor = GetItemInSlot(INVENTORY_SLOT_CHEST, oCreature);
|
|
if (GetIsObjectValid(oArmor))
|
|
{
|
|
iArmorPenalty = GetItemACValue(oArmor);
|
|
}
|
|
|
|
//:: Calculate the DC for the Strength check
|
|
int iStrengthDC = 15 + iArmorPenalty;
|
|
|
|
//:: Be an Ooze Mephit or roll a Strength check against the DC
|
|
if (GetIsAquatic(oCreature) == FALSE &&
|
|
GetResRef(OBJECT_SELF) != "mepooze001" &&
|
|
GetResRef(OBJECT_SELF) != "tarmephit001" ||
|
|
GetAppearanceType(oCreature) != APPEARANCE_TYPE_MEPHIT_OOZE ||
|
|
d20() + GetAbilityModifier(ABILITY_STRENGTH, oCreature) < iStrengthDC)
|
|
{
|
|
//:: Apply the other effects since the Strength check failed
|
|
SendMessageToPC(oCreature, "You are floundering in the water!");
|
|
ApplySuffocationEffect(oCreature);
|
|
}
|
|
|
|
//:: Tar is always hot & slowing
|
|
ApplySlowEffect(oCreature);
|
|
|
|
oCreature = GetNextObjectInArea(oArea, OBJECT_TYPE_CREATURE);
|
|
}
|
|
} |