Added Mine & Caverns raise & lower functionality
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.
This commit is contained in:
13
_module/nss/at_give_coins.nss
Normal file
13
_module/nss/at_give_coins.nss
Normal file
@@ -0,0 +1,13 @@
|
||||
void main()
|
||||
{
|
||||
// Get the PC who is in this conversation.
|
||||
object oPC = GetPCSpeaker();
|
||||
object oSelf = OBJECT_SELF;
|
||||
|
||||
string sTag = GetTag(oSelf);
|
||||
|
||||
|
||||
// Give 2-8 gold to the PC.
|
||||
GiveGoldToCreature(oPC, d6(1)+2);
|
||||
SetLocalInt(oPC, "FoundCoins"+sTag, 1);
|
||||
}
|
24
_module/nss/at_spn_grn_slime.nss
Normal file
24
_module/nss/at_spn_grn_slime.nss
Normal file
@@ -0,0 +1,24 @@
|
||||
//:: at_spn_grn_slime
|
||||
//::
|
||||
//:: Spawns a small green slime
|
||||
|
||||
#include "nw_i0_generic"
|
||||
|
||||
void main()
|
||||
{
|
||||
object oSpawn;
|
||||
effect eVFX;
|
||||
object oSelf = OBJECT_SELF;
|
||||
|
||||
// Get the PC who is in this conversation.
|
||||
object oPC = GetPCSpeaker();
|
||||
string sName = GetName(oPC);
|
||||
string sTag = GetTag(oSelf);
|
||||
|
||||
// Spawn Small Green Slime.
|
||||
eVFX = EffectVisualEffect(VFX_COM_BLOOD_CRT_GREEN);
|
||||
oSpawn = CreateObject(OBJECT_TYPE_CREATURE, "zep_greenslimes", GetLocation(oSelf));
|
||||
AssignCommand(oSpawn, DetermineCombatRound(oPC));
|
||||
DelayCommand(0.3f, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVFX, oSpawn));
|
||||
SetLocalInt(oPC, "FoundSlime"+sTag, 1);
|
||||
}
|
51
_module/nss/cavein_retex.nss
Normal file
51
_module/nss/cavein_retex.nss
Normal file
@@ -0,0 +1,51 @@
|
||||
void main()
|
||||
{
|
||||
//:: Get the placeable object that triggers the script.
|
||||
object oPlaceable = OBJECT_SELF;
|
||||
|
||||
string sTexture;
|
||||
|
||||
//:: Check if a custom local variable has been set to indicate that the script has run.
|
||||
int bHasRun = GetLocalInt(oPlaceable, "HasRun");
|
||||
|
||||
if (!bHasRun)
|
||||
{
|
||||
switch (d4(1))
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
sTexture = "tdm01_rock01";
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
sTexture = "tdm01_rock02";
|
||||
break;
|
||||
}
|
||||
|
||||
case 3:
|
||||
{
|
||||
sTexture = "tdm01_rock03";
|
||||
break;
|
||||
}
|
||||
|
||||
case 4:
|
||||
{
|
||||
sTexture = "tdm01_rock04";
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ReplaceObjectTexture(oPlaceable, "tx_rough_006g", sTexture);
|
||||
|
||||
//:: Set the local variable to indicate that the script has run.
|
||||
SetLocalInt(oPlaceable, "HasRun", 1);
|
||||
|
||||
//:: Removed HB script from event to save resources
|
||||
SetEventScript(oPlaceable, EVENT_SCRIPT_PLACEABLE_ON_HEARTBEAT, "");
|
||||
|
||||
}
|
||||
}
|
||||
|
27
_module/nss/lvl01_bone_src10.nss
Normal file
27
_module/nss/lvl01_bone_src10.nss
Normal file
@@ -0,0 +1,27 @@
|
||||
//:: Returns true if PC passes a DC 10 search check
|
||||
|
||||
int StartingConditional()
|
||||
{
|
||||
//:: Declare major variables
|
||||
object oPC = GetPCSpeaker();
|
||||
object oSelf = OBJECT_SELF;
|
||||
|
||||
string sTag =GetTag(oSelf);
|
||||
|
||||
if (GetLocalInt(oPC, "FoundCoins"+sTag) == TRUE)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Check if the player's search skill check is successful against DC 10
|
||||
if (GetIsSkillSuccessful(oPC, SKILL_SEARCH, 10))
|
||||
{
|
||||
//:: Player passed the search check
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
//:: Player failed the search check
|
||||
return FALSE;
|
||||
}
|
||||
}
|
27
_module/nss/lvl01_bone_srch5.nss
Normal file
27
_module/nss/lvl01_bone_srch5.nss
Normal file
@@ -0,0 +1,27 @@
|
||||
//:: Returns true if PC passes a DC 5 search check
|
||||
|
||||
int StartingConditional()
|
||||
{
|
||||
//:: Declare major variables
|
||||
object oPC = GetPCSpeaker();
|
||||
object oSelf = OBJECT_SELF;
|
||||
|
||||
string sTag =GetTag(oSelf);
|
||||
|
||||
if (GetLocalInt(oPC, "FoundSlime"+sTag) == TRUE)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Check if the player's search skill check is successful against DC 5
|
||||
if (GetIsSkillSuccessful(oPC, SKILL_SEARCH, 5))
|
||||
{
|
||||
//:: Player passed the search check
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
//:: Player failed the search check
|
||||
return FALSE;
|
||||
}
|
||||
}
|
67
_module/nss/lw_trap_ondisarm.nss
Normal file
67
_module/nss/lw_trap_ondisarm.nss
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
OnDisarm
|
||||
|
||||
Awards XP for disarming traps
|
||||
|
||||
For nonmagical harmless traps set the trap type to "minor entangle trap"
|
||||
For magical traps, use the local int TRAP_DAMAGE_OVERRIDE
|
||||
*/
|
||||
|
||||
void main()
|
||||
{
|
||||
object oPC = GetLastDisarmed();
|
||||
|
||||
if (GetIsPC(oPC) )
|
||||
{
|
||||
int nTrapCR = 0;
|
||||
int nDisarmDC = GetTrapDisarmDC(OBJECT_SELF);
|
||||
int nDetectDC = GetTrapDetectDC(OBJECT_SELF);
|
||||
int nRow, nDam, nDamOvr;
|
||||
|
||||
// Modify the CR based on the Disarm DC
|
||||
if (nDisarmDC > 30)
|
||||
{
|
||||
nTrapCR = nTrapCR + 2;
|
||||
}
|
||||
else if (nDisarmDC > 15)
|
||||
{
|
||||
nTrapCR = nTrapCR + 1;
|
||||
}
|
||||
|
||||
// Modify the CR based on the Detect DC
|
||||
if (nDetectDC > 30)
|
||||
{
|
||||
nTrapCR = nTrapCR + 2;
|
||||
}
|
||||
else if (nDetectDC > 15)
|
||||
{
|
||||
nTrapCR = nTrapCR + 1;
|
||||
}
|
||||
|
||||
// Determine the average amount of damage to use in the final CR calculation
|
||||
nDamOvr = GetLocalInt(OBJECT_SELF, "TRAP_DAMAGE_OVERRIDE");
|
||||
if (!nDamOvr)
|
||||
{
|
||||
nRow = GetTrapBaseType(OBJECT_SELF);
|
||||
nDam = StringToInt(Get2DAString("traps.2da", "MedianDamage", nRow));
|
||||
}
|
||||
else
|
||||
{
|
||||
nDam = nDamOvr;
|
||||
}
|
||||
|
||||
// Calculate the total Trap CR
|
||||
nTrapCR = nTrapCR + (nDam /7);
|
||||
|
||||
// Calculate the final award - PC only
|
||||
int nLevel = GetHitDice(oPC);
|
||||
int nXPScale = GetModuleXPScale();
|
||||
float fAward = (300.00 / IntToFloat(nXPScale)) * IntToFloat(nLevel) * pow(2.0, (IntToFloat(nTrapCR)-IntToFloat(nLevel)) * 0.5);
|
||||
|
||||
// Award some XP
|
||||
if (fAward > 0.0)
|
||||
{
|
||||
GiveXPToCreature(oPC, FloatToInt(fAward));
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,43 +0,0 @@
|
||||
/// ----------------------------------------------------------------------------
|
||||
/// @file nui_i_library.nss
|
||||
/// @author Ed Burke (tinygiant98) <af.hog.pilot@gmail.com>
|
||||
/// @brief Boilerplate code for creating a library dispatcher. Should only be
|
||||
/// included in library scripts as it implements main().
|
||||
/// ----------------------------------------------------------------------------
|
||||
|
||||
#include "nui_i_main"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Function Protoypes
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void DefineForm();
|
||||
void BindForm();
|
||||
void HandleNUIEvents();
|
||||
void HandleModuleEvents();
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Function Implementations
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// These are dummy implementations to prevent nwnsc from complaining that they
|
||||
// do not exist. If you want to compile in the toolset rather than using nwnsc,
|
||||
// comment these lines out.
|
||||
//#pragma default_function(DefineForm)
|
||||
//#pragma default_function(BindForm)
|
||||
//#pragma default_function(HandleNUIEvents)
|
||||
//#pragma default_function(HandleModuleEvents)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Library Dispatch
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void main()
|
||||
{
|
||||
string sOperation = GetScriptParam("NUI_FUNCTION");
|
||||
|
||||
if (sOperation == NUI_DEFINE) DefineForm();
|
||||
else if (sOperation == NUI_BIND) BindForm();
|
||||
else if (sOperation == NUI_EVENT_NUI) HandleNUIEvents();
|
||||
else HandleModuleEvents();
|
||||
}
|
89
_module/nss/ra_lvl01_onenter.nss
Normal file
89
_module/nss/ra_lvl01_onenter.nss
Normal file
@@ -0,0 +1,89 @@
|
||||
//::////////////////////////////////////////////////////////////////////////////
|
||||
/*//
|
||||
|
||||
Level 1: The Lair of the Dung Beast
|
||||
onEnter script
|
||||
ra_lvl01_onenter.nss
|
||||
|
||||
Wandering Monsters: Check once per 30 minutes on 1d20
|
||||
|
||||
Detections: Faint evil from the whole place; slightly more to the south east.
|
||||
|
||||
Continuous Effects: The stench of this level requires all characters to make
|
||||
a Fortitude save (DC 10) upon entering the level and every 30 minutes
|
||||
thereafter or all rolls are at –2 morale penalty due to the distraction
|
||||
caused by the overpowering smell.
|
||||
|
||||
*///
|
||||
//::////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "spawn_functions"
|
||||
#include "tgdc_explore_inc"
|
||||
|
||||
void StenchMessage(object oPC = OBJECT_SELF)
|
||||
{
|
||||
//:: Only fire for (real) PCs.
|
||||
if ( !GetIsPC(oPC) || GetIsDMPossessed(oPC) )
|
||||
return;
|
||||
|
||||
//:: Have text appear over the PC's head.
|
||||
FloatingTextStringOnCreature("As you enter this area, a terrible, overpowering stench assaults your senses.", oPC, FALSE);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
//:: Get the entering object (usually a PC)
|
||||
object oPC = GetEnteringObject();
|
||||
|
||||
//:: Only fire once per PC.
|
||||
if (!GetLocalInt(oPC, "DO_ONCE__" + GetTag(OBJECT_SELF)) )
|
||||
{
|
||||
StenchMessage(oPC);
|
||||
|
||||
SetLocalInt(oPC, "DO_ONCE__" + GetTag(OBJECT_SELF), TRUE);
|
||||
}
|
||||
|
||||
/*
|
||||
Spawn_OnAreaEnter() can take three arguments - the name of the heartbeat
|
||||
script to execute, the heartbeat duration, and a delay for the first
|
||||
heartbeat. They default to spawn_sample_hb, 6.0, and 0.0 respectively; as
|
||||
if it were called like: Spawn_OnAreaEnter( "spawn_sample_hb", 6.0, 0.0 );
|
||||
*/
|
||||
|
||||
if ( GetIsAreaAboveGround( OBJECT_SELF ) && ! GetIsAreaNatural( OBJECT_SELF ) )
|
||||
{
|
||||
//:: Indoors - no delay on the first HB
|
||||
Spawn_OnAreaEnter( "spawn_sample_hb", 6.0, 0.0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
//:: Outdoors or underground - do a 3 second delay on the first HB
|
||||
Spawn_OnAreaEnter( "spawn_sample_hb", 6.0, 3.0 );
|
||||
}
|
||||
|
||||
//:: Records that the PC has entered Rappan Athuk at least once.
|
||||
SetLocalInt(oPC, "bEnteredDungeon", 1);
|
||||
SetLocalInt(oPC, "bEnteredLevelOne", 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
51
_module/nss/ra_lvl01_onexit.nss
Normal file
51
_module/nss/ra_lvl01_onexit.nss
Normal file
@@ -0,0 +1,51 @@
|
||||
//::////////////////////////////////////////////////////////////////////////////
|
||||
/*//
|
||||
|
||||
Level 1: The Lair of the Dung Beast
|
||||
onExit script
|
||||
ra_lvl01_onexit.nss
|
||||
|
||||
Wandering Monsters: Check once per 30 minutes on 1d20
|
||||
|
||||
Detections: Faint evil from the whole place; slightly more to the south east.
|
||||
|
||||
Continuous Effects: The stench of this level requires all characters to make
|
||||
a Fortitude save (DC 10) upon entering the level and every 30 minutes
|
||||
thereafter or all rolls are at –2 morale penalty due to the distraction
|
||||
caused by the overpowering smell.
|
||||
|
||||
*///
|
||||
//::////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
//:: Get the entering object (usually a PC)
|
||||
object oPC = GetExitingObject();
|
||||
|
||||
//:: Clears Level 1 stench message int var,
|
||||
//:: so it will show up again next time they enter
|
||||
DelayCommand(0.0f,DeleteLocalInt(oPC, "DO_ONCE__" + GetTag(OBJECT_SELF)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
107
_module/nss/ra_lvl01_onhb.nss
Normal file
107
_module/nss/ra_lvl01_onhb.nss
Normal file
@@ -0,0 +1,107 @@
|
||||
//::////////////////////////////////////////////////////////////////////////////
|
||||
/*//
|
||||
|
||||
Level 1: The Lair of the Dung Beast
|
||||
onHeartbeat script
|
||||
ra_lvl01_onhb.nss
|
||||
|
||||
Wandering Monsters: Check once per 30 minutes on 1d20.
|
||||
|
||||
Detections: Faint evil from the whole place; slightly more to the south east.
|
||||
|
||||
Continuous Effects: The stench of this level requires all characters to make
|
||||
a Fortitude save (DC 10) upon entering the level and every 30 minutes
|
||||
thereafter or all rolls are at –2 morale penalty due to the distraction
|
||||
caused by the overpowering smell.
|
||||
|
||||
*///
|
||||
//::////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
//:: Function to process the stench penalty
|
||||
void ApplyStench(object oPC)
|
||||
{
|
||||
int RA_DEBUG = 0;
|
||||
|
||||
//:: Check for exising variable on player
|
||||
int oldTime = GetLocalInt(oPC, "StenchFortSaveTime");
|
||||
|
||||
// Get the current system time in seconds
|
||||
int newTime = (GetTimeHour()*60*60)+(GetTimeMinute()*60)+GetTimeSecond();
|
||||
|
||||
// Calculate the time difference in seconds
|
||||
int timeDifference = newTime - oldTime;
|
||||
|
||||
if (RA_DEBUG)
|
||||
{
|
||||
SendMessageToPC(oPC, "oldTime = " + IntToString(oldTime));
|
||||
SendMessageToPC(oPC, "newTime = " + IntToString(newTime));
|
||||
SendMessageToPC(oPC, "timeDifference = " + IntToString(timeDifference));
|
||||
}
|
||||
|
||||
//:: Check if the character hasn't made a Fortitude save in the last 3 minutes
|
||||
if (oldTime == 0 || timeDifference >= 180) // 180 seconds = 3 real-time minutes
|
||||
{
|
||||
//:: Check if the character failed the save
|
||||
if (!FortitudeSave(oPC, 10))
|
||||
{
|
||||
//:: Apply a -2 morale penalty to all rolls
|
||||
effect eMoralePenalty = EffectAttackDecrease(2);
|
||||
effect eVFX = EffectVisualEffect(VFX_DUR_CESSATE_NEGATIVE);
|
||||
effect eLink = EffectLinkEffects(eMoralePenalty, eVFX);
|
||||
|
||||
eLink = SupernaturalEffect(eLink);
|
||||
eLink = TagEffect(eLink, "LvlOneStench");
|
||||
|
||||
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eLink, oPC, 180.0f); // 180 seconds = 3 real-time minutes & .5 hours in-game.
|
||||
|
||||
//:: Store the current time on player
|
||||
SetLocalInt(oPC, "StenchFortSaveTime", newTime);
|
||||
|
||||
if (RA_DEBUG)
|
||||
{
|
||||
SendMessageToPC(oPC, "Failed StenchFortSave");
|
||||
SendMessageToPC(oPC, "Setting StenchFortSaveTime as " + IntToString(newTime));
|
||||
}
|
||||
|
||||
// Send a message to the player
|
||||
SendMessageToPC(oPC, "The overpowering stench is distracting you.");
|
||||
}
|
||||
|
||||
//:: Store the current time on player
|
||||
SetLocalInt(oPC, "StenchFortSaveTime", newTime);
|
||||
|
||||
if (RA_DEBUG)
|
||||
{
|
||||
SendMessageToPC(oPC, "Passed StenchFortSave");
|
||||
SendMessageToPC(oPC, "Setting StenchFortSaveTime as " + IntToString(newTime));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
int RA_DEBUG = 0;
|
||||
|
||||
//:: Declare major variables
|
||||
object oArea = OBJECT_SELF;
|
||||
object oPC = GetFirstObjectInArea(oArea, OBJECT_TYPE_CREATURE);
|
||||
|
||||
while (GetIsObjectValid(oPC))
|
||||
{
|
||||
if (GetIsPC(oPC) || (GetMaster(oPC) != OBJECT_INVALID && GetIsPC(GetMaster(oPC))))
|
||||
{
|
||||
if (RA_DEBUG)
|
||||
{
|
||||
SendMessageToPC(oPC, "Running Level 1 Area HB");
|
||||
}
|
||||
|
||||
//:: Apply the stench
|
||||
ApplyStench(oPC);
|
||||
}
|
||||
|
||||
// Get the next object in the area
|
||||
oPC = GetNextObjectInArea(oArea);
|
||||
}
|
||||
}
|
||||
|
83
_module/nss/sc_search_dc10.nss
Normal file
83
_module/nss/sc_search_dc10.nss
Normal file
@@ -0,0 +1,83 @@
|
||||
#include "x0_i0_partywide"
|
||||
|
||||
//:: Returns true if PC passes a DC 10 search check.
|
||||
//:: Only allows one chance to search
|
||||
|
||||
int StartingConditional()
|
||||
{
|
||||
object oPC = GetPCSpeaker();
|
||||
string sPlacableTag = GetTag(OBJECT_SELF);
|
||||
int nPartySearched = GetLocalInt(oPC, "PartySearched_" + sPlacableTag); // Unique flag for each placable
|
||||
|
||||
// Check if the party has already successfully searched at this placable
|
||||
if (nPartySearched == 1)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Check if the player's search skill check is successful against DC 10
|
||||
if (GetIsSkillSuccessful(oPC, SKILL_SEARCH, 10))
|
||||
{
|
||||
// Set the flag on every member of the party to ensure it's only run once per party
|
||||
SetLocalIntOnAll(oPC, "PartySearched_" + sPlacableTag, 1);
|
||||
|
||||
return TRUE; // Condition met, continue with the conversation
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//:: Returns true if PC passes a DC 10 search check
|
||||
|
||||
/*int StartingConditional()
|
||||
{
|
||||
//:: Declare major variables
|
||||
object oPC = GetPCSpeaker();
|
||||
|
||||
// Check if the player's search skill check is successful against DC 10
|
||||
if (GetIsSkillSuccessful(oPC, SKILL_SEARCH, 10))
|
||||
{
|
||||
//:: Player passed the search check
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
//:: Player failed the search check
|
||||
return FALSE;
|
||||
}
|
||||
} */
|
19
_module/nss/sc_search_dc5.nss
Normal file
19
_module/nss/sc_search_dc5.nss
Normal file
@@ -0,0 +1,19 @@
|
||||
//:: Returns true if PC passes a DC 5 search check
|
||||
|
||||
int StartingConditional()
|
||||
{
|
||||
//:: Declare major variables
|
||||
object oPC = GetPCSpeaker();
|
||||
|
||||
// Check if the player's search skill check is successful against DC 5
|
||||
if (GetIsSkillSuccessful(oPC, SKILL_SEARCH, 5))
|
||||
{
|
||||
//:: Player passed the search check
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
//:: Player failed the search check
|
||||
return FALSE;
|
||||
}
|
||||
}
|
44
_module/nss/stench_onenter.nss
Normal file
44
_module/nss/stench_onenter.nss
Normal file
@@ -0,0 +1,44 @@
|
||||
// Stench Area OnEnter Script - stench_onenter.nss
|
||||
|
||||
// Function to apply the stench penalty
|
||||
void ApplyStenchPenalty(object oPC)
|
||||
{
|
||||
// Calculate the current time in minutes
|
||||
int currentTime = GetTimeHour() * 60 + GetTimeMinute();
|
||||
|
||||
// Check if the character hasn't made a Fortitude save in the last 30 minutes
|
||||
if (!GetLocalInt(oPC, "FortitudeSaveTime") || currentTime >= GetLocalInt(oPC, "FortitudeSaveTime") + 30)
|
||||
{
|
||||
// Roll a Fortitude save (DC 10)
|
||||
int fortitudeSaveResult = FortitudeSave(oPC, 10, SAVING_THROW_TYPE_NONE, OBJECT_SELF);
|
||||
|
||||
// Check if the character failed the save
|
||||
if (fortitudeSaveResult < 1)
|
||||
{
|
||||
// Apply a -2 morale penalty to all rolls
|
||||
effect eMoralePenalty = EffectAttackDecrease(2, ATTACK_BONUS_MISC);
|
||||
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eMoralePenalty, oPC, 90.0f); // 90 seconds = 3 real time minutes & .5 hours in game.
|
||||
|
||||
// Store the current time as the last Fortitude save time
|
||||
SetLocalInt(oPC, "FortitudeSaveTime", currentTime);
|
||||
|
||||
// Send a message to the player
|
||||
SendMessageToPC(oPC, "The overpowering stench distracts you, imposing a -2 morale penalty to your rolls for the next 30 minutes.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
// Get the entering object (usually a PC)
|
||||
object oPC = GetEnteringObject();
|
||||
|
||||
// Check if the entering object is a valid creature and is a player character
|
||||
if (GetIsObjectValid(oPC) && GetObjectType(oPC) == OBJECT_TYPE_CREATURE && GetIsPC(oPC))
|
||||
{
|
||||
// Start the periodic script to apply the stench penalty
|
||||
ApplyStenchPenalty(oPC);
|
||||
}
|
||||
|
||||
DelayCommand(90.0f, ExecuteScript("stench_onenter"));
|
||||
}
|
72
_module/nss/trap_footcatch.nss
Normal file
72
_module/nss/trap_footcatch.nss
Normal file
@@ -0,0 +1,72 @@
|
||||
//::///////////////////////////////////////////////
|
||||
//:: Footcatcher Trap
|
||||
//:: trap_footcatch
|
||||
//:: Copyright (c) 2023 Project RATDOG
|
||||
//:://////////////////////////////////////////////
|
||||
/*
|
||||
|
||||
*/
|
||||
//:://////////////////////////////////////////////
|
||||
|
||||
#include "prc_inc_spells"
|
||||
#include "NW_I0_SPELLS"
|
||||
|
||||
void CreateObject2(int nObjectType, string sTemplate, location lLocation, int bUseAppearAnimation=FALSE);
|
||||
|
||||
void main()
|
||||
{
|
||||
//Declare major variables
|
||||
int nDuration = 4;
|
||||
int nDamage = d3(1);
|
||||
|
||||
object oTarget = GetEnteringObject();
|
||||
|
||||
location lTarget = GetLocation(oTarget);
|
||||
|
||||
effect eStopped = EffectCutsceneImmobilize();
|
||||
eStopped = ExtraordinaryEffect(eStopped);
|
||||
|
||||
effect eDamage = EffectDamage(nDamage);
|
||||
effect eVis1 = EffectVisualEffect(VFX_DUR_ENTANGLE);
|
||||
effect eVis2 = EffectVisualEffect(VFX_IMP_POISON_S);
|
||||
|
||||
effect ePoison = EffectPoison(POISON_LARGE_SCORPION_VENOM);
|
||||
ePoison = ExtraordinaryEffect(ePoison);
|
||||
|
||||
effect eLink1 = EffectLinkEffects(eVis1, eDamage);
|
||||
eLink1 = ExtraordinaryEffect(eLink1);
|
||||
|
||||
//Find first target in the size
|
||||
oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_SMALL, lTarget);
|
||||
//Cycle through the objects in the radius
|
||||
while (GetIsObjectValid(oTarget))
|
||||
{
|
||||
if(!MySavingThrow(SAVING_THROW_REFLEX, oTarget, 20, SAVING_THROW_TYPE_NONE))
|
||||
{
|
||||
//:: Apply damage & hold effect
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT, eLink1, oTarget);
|
||||
ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eStopped, oTarget, RoundsToSeconds(nDuration));
|
||||
SendMessageToPC(oTarget, "You've stepped thru a false floor, into a spiked trap.");
|
||||
|
||||
if(!MySavingThrow(SAVING_THROW_FORT, oTarget, 18, SAVING_THROW_TYPE_POISON))
|
||||
{
|
||||
//:: Apply poison
|
||||
ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis2, oTarget);
|
||||
ApplyEffectToObject(DURATION_TYPE_PERMANENT, ePoison, oTarget, RoundsToSeconds(nDuration));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
//Get next target in the shape.
|
||||
oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_SMALL, lTarget);
|
||||
}
|
||||
//respawn trap
|
||||
DelayCommand(598.0, CreateObject2(GetObjectType(OBJECT_SELF), GetResRef(OBJECT_SELF), GetLocation(OBJECT_SELF)));
|
||||
DelayCommand(600.0, DestroyObject(OBJECT_SELF));
|
||||
}
|
||||
|
||||
void CreateObject2(int nObjectType, string sTemplate, location lLocation, int bUseAppearAnimation=FALSE)
|
||||
{
|
||||
CreateObject(nObjectType, sTemplate, lLocation, bUseAppearAnimation);
|
||||
return;
|
||||
}
|
174
_module/nss/underwater_hb.nss
Normal file
174
_module/nss/underwater_hb.nss
Normal file
@@ -0,0 +1,174 @@
|
||||
//::////////////////////////////////////////////////////////////////////////////
|
||||
//::
|
||||
// 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);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user