/* Version 1.3

Added the MSnn switch. A destination with this switch attached, sends a message to the PC when they arrive at the destination. The messages are defined in the dds_ModInit function at the end of the script. */




//NWScript:
/*#############
# Dynamic Door System v1.3
# by Karthal <kar_of_albion@hotmail.com>
#####
# DESCRIPTION:
#
# This is intend to be a complete system to create dynamic doors which transfer
# players to different locations based on a number of factors. Features:
#
# * Script can be placed on a doorway OnAreaTransitionClick event to replace
# the normal transition.
# * Script can be placed on the OnUsed event of any placeable, the OnEnter
# event of a trigger or the OnAreaTransitionClick of an area transition.
# * Each door can have up to 99 possible destinations (1-99)
# * Multiple doors can be linked to the same set of destinations
# * Access to particular destinations can be changed based on whether it is
# nighttime, daytime, dusk or dawn (DT, NT, DUT, DWT switches).
# * Access based on the sex of the PC (PF, PM).
# * Access based on the minimum (and maximum) level for a player. Based on
# total levels across all classes (hit dice). (PLnnTyy)
# * Particular destinations can be "weighted" so that they are more frequently
# chosen when the script has multiple possible destinations. For instance if
# one door was weighted with a value of 9. It would be 9 times more likely
# to be chosen then other doors in the set (WTnn).
# * Access to a particular destination contigent on the presence of an
# item in the inventory of the PC. There is a list of items in the function
# dds_ModInit. You can have up to 99 items in the list (PInn, PInnD).
# * Access to a particular destination is denied if a particular item is in
# the inventory of the PC. (PInnX).
#####
# INSTALATION
#
# 1. Create a door. Give it a custom tag. The tag can be anything. Let's say
# you use the tag "custom".
# 2. On the area transition of the door, enter a dummy tag as the destination.
# This is so the area transition is highlighted when the PC puts the cursor
# over it.
# 3. Click on the scripts tag. Put this script on the "OnAreaTransitionClick"
# event.
# 4. Start making waypoints. Make sure the name of each waypoint begins with
# "DDS". Make the tags of the waypoints sequential using the tag of the
# corresponding door as the base. For instance, if the tag of the door is
# "custom" then the waypoints would be tagged "custom_01", "custom_02",
# "custom_03", etc. They must begin with 01 and there cannot be any gaps
# in the sequence.
# 5. Add switches to the name of the waypoints. Each waypoint can have
# numerous switches attached to it.
#####
# SIMPLE EXAMPLES:
#
# 1. You want a door to lead to one location during the day, another at night.
#
# a. Create a door and give it a custom tag, e.g. "custom". Add a fake tag
# in the Area Transition tab so that the area transition shows up.
# b. Place a waypoint at the place where you want the player to go during
# the day. Give it the tag "custom_01" and the name "DDS_DT".
# c. Place another waypoint at the place where you want the player to go at
# night. Give it the tag "custom_02" and the name "DDS_NT".
# d. Add this script to the OnAreaTransitionClick event on the door
# properties.
#
# 2. You want to create a door which leads to one of four locations randomly.
#
# a. Create a door and give it a custom tag, e.g. "random". Add a fake tag
# in the Area Transition tab so that the area transition shows up.
# b. Place four waypoints and give them these tags: "random_01", "random_02"
# "random_03" and "random_04". All of them should have the name "DDS"
# c. Add this script to the OnAreaTransitionClick event on the door
# properties.
#
# 3. You want to create a door which leads to one place for male characters
# and another for female characters.
#
# a. Create a door and give it a custom tag, e.g. "gender". Add a fake tag
# in the Area Transition tab so that the area transition shows up.
# b. Place two waypoints with tags: "gender_01" and "gender_02".
# c. On the waypoint you want to be female only, put the name, "DDS_PF".
# On the waypoint you want to be male only, put the name, "DDS_PM".
# d. Add this script to the OnAreaTransitionClick event on the door
# properties.
#
# 4. You want to create a door which leads to different places depending on the
# level of the character.
#
# a. Create a door and give it a custom tag, e.g. "level". Add a fake tag
# in the Area Transition tab so that the area transition shows up.
# b. Place several waypoints with tags: "level_01", "level_02", etc..
# c. For each waypoint, give it a name like this:
# "DDS_PL05" - PC's must be at least level 5 go to this destination.
# "DDS_PL06T08 - PC's must be between level 6 and 8 to go to this
# destination.
# d. Add this script to the OnAreaTransitionClick event on the door
# properties.
#
# 5. You want to create a door which leads to one place if a character has a
# specific item or another destination if they don't.
#
# a. Create a door and give it a custom tag, e.g. "item". Add a fake tag
# in the Area Transition tab so that the area transition shows up.
# b. Place two waypoints with tags: "item_01", "item_02"
# c. Use this name for the waypoint where you want to send them if they
# have the item: "DDS_PI01"
# d. Use this name for the any other waypoint: "DDS_PI01X"
# e. Add this script to the OnAreaTransitionClick event on the door
# properties.
#####
# UPDATES:
#
# VERSION 1.3
# _MSnn A message is sent to the PC when they arrive at the
# destination. There can be up to 99 messages defined in the
# dds_ModInit function.
#
# VERSION 1.2
# Name Name of the script changed to "Dynamic Door System"
# Changed the prefix of scripts to dds_ instead of sds_
# _WTnn Weighted - you can specify one waypoint to have a greater
# chance than others to be chosen. For instance, if you have one
# waypoint with no WT switch and another with a WT10 switch, the
# one with the WT10 switch will be 10 times more likely to
# chosen as the random destination than the other waypoint.
# _PInn Access granted to this destination if a particular item
# is in the player's inventory.
# _PInnD Access granted to this destination if a particular item
# is in the player's inventory. And the item is destroyed.
# _PInnX Access denied to this destination if a particular item
# is in the player's inventory.
#
# VERSION 1.1
# _PLnn Player level - checks for minimum player level. Uses hit dice.
# _PLnnTyy Player level range - checks for a player level range between
# nn and yy. Uses hit dice.
#
# VERSION 1.0
#
# _DT Daytime - valid destination during the day.
# _NT Nighttime - valid destination during the night.
# _DWT Dawn - valid destination at dawn.
# _DUT Dusk - valid destination at dusk.
#
# _PF Player female - valid destination for females only. Cannot be
# used with the PM switch. Leave them both off to make it work for
# both genders.
# _PM Player male - valid destination for females only. Cannot be used
# with the PF switch. Leave them both off to make it work for both
# genders.
#
#############*/
int iDebug = FALSE;
void dds_MoveCreature( object oCreature, object oWaypoint );
void dds_InitializeWaypoint( object oWaypoint, object oPC );
int dds_CheckValid( object oWaypoint, object oPC );
int dds_GetNumber( string sName, string sSwitch, int iSecond=FALSE );
int dds_CheckInventory( string sTag, object oPC );
string dds_ValueToString( int iValue, int iDigits=2 );
void dds_ModInit();
void main()
{
// Define variables
object oCreature = GetEnteringObject();
object oWaypoint;
string sDoorTag = GetTag( OBJECT_SELF );
string sWPTag;
string sWPName;
int iCount = 0;
int iValid = 0;
int iCheck = 0;
object oPC;
int iWayPoint;
// Setup Item vars
if ( !GetLocalInt( OBJECT_SELF, "ModInit" ) )
dds_ModInit();
// Check to see that the entering object is a PC.
if ( GetIsPC( oCreature ) )
oPC = oCreature;
else
return;
// This loop counts the number of valid destinations.
// Get the first waypoint object. It should be "sDoorTag01"
oWaypoint = GetWaypointByTag( sDoorTag + dds_ValueToString( ++iCount ) );
while ( oWaypoint != OBJECT_INVALID )
{
// Debug
if ( iDebug == TRUE )
SendMessageToPC( oPC, "Checking waypoint: " + IntToString( iCount ) );
// Initialize the local variables on this waypoint.
dds_InitializeWaypoint( oWaypoint, oPC );
// Checks to see if this waypoint is valid for this oPC, and increments
// the counter which keeps track of the total number of valid
// destinations.
iValid = iValid + dds_CheckValid( oWaypoint, oPC );
// Debug
if ( iDebug == TRUE )
SendMessageToPC( oPC, "iValid: " + IntToString( iValid ) );
// Gets the next waypoint
oWaypoint = GetWaypointByTag( sDoorTag + dds_ValueToString( ++iCount ) );
}
// Choose a random waypoint and reset the counters.
iWayPoint = Random( iValid ) + 1;
iCount = 0;
iValid = 0;
// This loop goes through the waypoints again and stops at the chosen
// destination waypoint. For instance if there are 3 valid waypoints and
// the random function chose waypoint 2, it would loop through all of the
// waypoints until it finds the 2nd valid one.
// Get the first waypoint object. It should be "sDoorTag_01"
oWaypoint = GetWaypointByTag( sDoorTag + dds_ValueToString( ++iCount ) );
while ( oWaypoint != OBJECT_INVALID )
{
// Debug
if ( iDebug == TRUE )
SendMessageToPC( oPC, "Choosing waypoint: " + IntToString( iCount ) );
// Checks to see if this waypoint is valid for this oPC, and increments
// the counter which keeps track of the total number of valid
// destinations.
iValid = iValid + dds_CheckValid( oWaypoint, oPC );
// If this is chosen destination waypoint, the move creature function is called.
if ( iValid >= iWayPoint )
{
dds_MoveCreature( oPC, oWaypoint );
break;
}
// Get next waypoint
oWaypoint = GetWaypointByTag( sDoorTag + dds_ValueToString( ++iCount ) );
}
}
// dds_ValueToString converts a integer into a string value and adds leading 0s.
string dds_ValueToString( int iValue, int iDigits=2 )
{
if ( iDigits < 2 || iDigits > 3 || iValue < 0 || iValue > 999 || ( iValue > 99 && iDigits == 2 ) )
{
if ( iDebug == TRUE )
SendMessageToAllDMs( "Problem in dds_ValueToString. iDigits = " + IntToString( iDigits ) + " / iValue = " + IntToString( iValue ) );
return "";
}
string sValue = IntToString( iValue );
if ( iValue < 10 )
sValue = "0" + sValue;
if ( iValue < 100 && iDigits == 3 )
sValue = "0" + sValue;
sValue = "_" + sValue;
return sValue;
}
// dds_MoveCreature moves a creature object to a new destination. If it has a
// henchman, familiar, summoned or dominated, they are moved too. Much of this
// function was taken from a post by Ojus.
void dds_MoveCreature( object oPC, object oWaypoint )
{
object oHench = GetAssociate (ASSOCIATE_TYPE_HENCHMAN, oPC);
object oFam = GetAssociate (ASSOCIATE_TYPE_FAMILIAR, oPC);
object oSumm = GetAssociate (ASSOCIATE_TYPE_SUMMONED, oPC);
object oDom = GetAssociate (ASSOCIATE_TYPE_DOMINATED, oPC);
float fFace = GetFacing( oWaypoint );
// Debug
if ( iDebug == TRUE )
{
SendMessageToPC( oPC, "Checking waypoint: " + GetTag( oWaypoint ) + " / " + GetName( oWaypoint) );
SendMessageToPC( oPC, "Daytime DT switch = " + IntToString( GetLocalInt( oWaypoint, "dds_Daytime" ) ) );
SendMessageToPC( oPC, "Nighttime NT switch = " + IntToString( GetLocalInt( oWaypoint, "dds_Nighttime" ) ) );
SendMessageToPC( oPC, "Dawn DWT switch = " + IntToString( GetLocalInt( oWaypoint, "dds_Dawn" ) ) );
SendMessageToPC( oPC, "Dusk DUT switch = " + IntToString( GetLocalInt( oWaypoint, "dds_Dusk" ) ) );
SendMessageToPC( oPC, "Player Female PF switch = " + IntToString( GetLocalInt( oWaypoint, "dds_Female" ) ) );
SendMessageToPC( oPC, "Player Male PM switch = " + IntToString( GetLocalInt( oWaypoint, "dds_Male" ) ) );
SendMessageToPC( oPC, "Player Level Min PLnn switch = " + IntToString( GetLocalInt( oWaypoint, "dds_PlayerLevelMin" ) ) );
SendMessageToPC( oPC, "Player Level Max PLnnTyy switch = " + IntToString( GetLocalInt( oWaypoint, "dds_PlayerLevelMax" ) ) );
SendMessageToPC( oPC, "Weighted = " + IntToString( GetLocalInt( oWaypoint, "dds_Weighted" ) ) );
SendMessageToPC( oPC, "Player Item = " + IntToString( GetLocalInt( oWaypoint, "dds_PlayerItem" ) ) );
SendMessageToPC( oPC, "Not Player Item = " + IntToString( GetLocalInt( oWaypoint, "dds_NotPlayerItem" ) ) );
SendMessageToPC( oPC, "Message = " + IntToString( GetLocalInt( oWaypoint, "dds_Message" ) ) );
}
AssignCommand (oPC, SetCameraFacing ( fFace ) );
AssignCommand (oPC, ActionJumpToObject (oWaypoint, FALSE));
AssignCommand (oHench, ClearAllActions());
AssignCommand (oHench, ActionJumpToObject (oWaypoint, FALSE));
AssignCommand (oHench, ActionForceFollowObject (oPC, 5.0));
AssignCommand (oFam, ClearAllActions());
AssignCommand (oFam, ActionJumpToObject (oWaypoint, FALSE));
AssignCommand (oFam, ActionForceFollowObject (oPC, 5.0));
AssignCommand (oSumm, ClearAllActions());
AssignCommand (oSumm, ActionJumpToObject (oWaypoint, FALSE));
AssignCommand (oSumm, ActionForceFollowObject (oPC, 5.0));
AssignCommand (oDom, ClearAllActions());
AssignCommand (oDom, ActionJumpToObject (oWaypoint, FALSE));
AssignCommand (oDom, ActionForceFollowObject (oPC, 5.0));
if ( GetLocalInt( oWaypoint, "dds_TakePlayerItem" ) == TRUE )
{
DestroyObject( GetItemPossessedBy( oPC, GetLocalString( OBJECT_SELF, "item" + dds_ValueToString ( GetLocalInt( oWaypoint, "dds_PlayerItem" ) ) ) ) );
}
if ( GetLocalInt( oWaypoint, "dds_Message" ) > 0 )
{
SendMessageToPC( oPC, GetLocalString( OBJECT_SELF, "message" + dds_ValueToString ( GetLocalInt( oWaypoint, "dds_Message" ) ) ) );
PlaySound( "gui_journaladd" );
}
}
// Initialize the Values on the waypoint
void dds_InitializeWaypoint( object oWaypoint, object oPC )
{
if ( GetLocalInt( oWaypoint, "dds_Initialized" ) == TRUE )
return;
// Get name of waypoint
string oWPName = GetName( oWaypoint );
// Set Initialized to TRUE
SetLocalInt( oWaypoint, "dds_Initialized", TRUE );
// Check for DDS switch - Is a valid Smart Door Destination.
// It only checks for "DS". If it checked for "DDS" it would get a 0
// even if it was there.
SetLocalInt( oWaypoint, "dds_IsSmartDoor", FindSubString( oWPName, "DS" ) );
// Check for DT switch - Daytime
SetLocalInt( oWaypoint, "dds_Daytime", FindSubString( oWPName, "_DT" ) );
// Check for NT switch - Nighttime
SetLocalInt( oWaypoint, "dds_Nighttime", FindSubString( oWPName, "_NT" ) );
// Check for DWT switch - Dawn
SetLocalInt( oWaypoint, "dds_Dawn", FindSubString( oWPName, "_DWT" ) );
// Check for DUT switch - Dusk
SetLocalInt( oWaypoint, "dds_Dusk", FindSubString( oWPName, "_DUT" ) );
// Check for PF switch - Player Female
SetLocalInt( oWaypoint, "dds_Female", FindSubString( oWPName, "_PF" ) );
// Check for PF switch - Player Male
SetLocalInt( oWaypoint, "dds_Male", FindSubString( oWPName, "_PM" ) );
// Check for PL switch - Player Level
SetLocalInt( oWaypoint, "dds_PlayerLevelMin", FindSubString( oWPName, "_PL" ) );
if ( GetLocalInt( oWaypoint, "dds_PlayerLevelMin" ) > 0 )
{
SetLocalInt( oWaypoint, "dds_PlayerLevelMin", dds_GetNumber( oWPName, "_PL" ) );
SetLocalInt( oWaypoint, "dds_PlayerLevelMax", dds_GetNumber( oWPName, "_PL", TRUE ) );
}
// Check for WT switch - Weighted value
SetLocalInt( oWaypoint, "dds_Weighted", FindSubString( oWPName, "_WT" ) );
if ( GetLocalInt( oWaypoint, "dds_Weighted" ) > 0 )
SetLocalInt( oWaypoint, "dds_Weighted", dds_GetNumber( oWPName, "_WT" ) );
else
SetLocalInt( oWaypoint, "dds_Weighted", 1 );
// Check for PI switch - Player Item
SetLocalInt( oWaypoint, "dds_PlayerItem", FindSubString( oWPName, "_PI" ) );
if ( GetLocalInt( oWaypoint, "dds_PlayerItem" ) > 0 )
{
if ( GetSubString ( GetName( oWaypoint ), GetLocalInt( oWaypoint, "dds_PlayerItem" ) + 5, 1 ) == "X" )
SetLocalInt( oWaypoint, "dds_NotPlayerItem", TRUE );
if ( GetSubString ( GetName( oWaypoint ), GetLocalInt( oWaypoint, "dds_PlayerItem" ) + 5, 1 ) == "D" )
SetLocalInt( oWaypoint, "dds_TakePlayerItem", TRUE );
SetLocalInt( oWaypoint, "dds_PlayerItem", dds_GetNumber( oWPName, "_PI" ) );
}
// Check for MS switch - Message
SetLocalInt( oWaypoint, "dds_Message", FindSubString( oWPName, "_MS" ) );
if ( GetLocalInt( oWaypoint, "dds_Message" ) > 0 )
SetLocalInt( oWaypoint, "dds_Message", dds_GetNumber( oWPName, "_MS" ) );
return;
}
// Checks to see if a particular waypoint is valid or not for this PC.
int dds_CheckValid( object oWaypoint, object oPC )
{
string sItem;
// Debug
if ( iDebug == TRUE )
{
SendMessageToPC( oPC, "Checking waypoint: " + GetTag( oWaypoint ) + " / " + GetName( oWaypoint) );
SendMessageToPC( oPC, "Daytime DT switch = " + IntToString( GetLocalInt( oWaypoint, "dds_Daytime" ) ) );
SendMessageToPC( oPC, "Nighttime NT switch = " + IntToString( GetLocalInt( oWaypoint, "dds_Nighttime" ) ) );
SendMessageToPC( oPC, "Dawn DWT switch = " + IntToString( GetLocalInt( oWaypoint, "dds_Dawn" ) ) );
SendMessageToPC( oPC, "Dusk DUT switch = " + IntToString( GetLocalInt( oWaypoint, "dds_Dusk" ) ) );
SendMessageToPC( oPC, "Player Female PF switch = " + IntToString( GetLocalInt( oWaypoint, "dds_Female" ) ) );
SendMessageToPC( oPC, "Player Male PM switch = " + IntToString( GetLocalInt( oWaypoint, "dds_Male" ) ) );
SendMessageToPC( oPC, "Player Level Min PLnn switch = " + IntToString( GetLocalInt( oWaypoint, "dds_PlayerLevelMin" ) ) );
SendMessageToPC( oPC, "Player Level Max PLnnTyy switch = " + IntToString( GetLocalInt( oWaypoint, "dds_PlayerLevelMax" ) ) );
SendMessageToPC( oPC, "Weighted = " + IntToString( GetLocalInt( oWaypoint, "dds_Weighted" ) ) );
SendMessageToPC( oPC, "Player Item = " + IntToString( GetLocalInt( oWaypoint, "dds_PlayerItem" ) ) );
SendMessageToPC( oPC, "Not Player Item = " + IntToString( GetLocalInt( oWaypoint, "dds_NotPlayerItem" ) ) );
SendMessageToPC( oPC, "Take Player Item = " + IntToString( GetLocalInt( oWaypoint, "dds_TakePlayerItem" ) ) );
}
// If the waypoint doesn't have "DDS" in the name, it's not considered valid
if ( !GetLocalInt( oWaypoint, "dds_IsSmartDoor" ) )
return FALSE;
// If the waypoint has any of the time of day switches set, it checks to
// make sure the current time of day
if ( GetLocalInt( oWaypoint, "dds_Daytime" ) > 0 ||
GetLocalInt( oWaypoint, "dds_Nighttime" ) > 0 ||
GetLocalInt( oWaypoint, "dds_Dawn" ) > 0 ||
GetLocalInt( oWaypoint, "dds_Dusk" ) > 0 )
{
if ( GetIsDay() && GetLocalInt( oWaypoint, "dds_Daytime" ) < 0 )
return FALSE;
else if ( GetIsNight() && GetLocalInt( oWaypoint, "dds_Nighttime" ) < 0 )
return FALSE;
else if ( GetIsDawn() && GetLocalInt( oWaypoint, "dds_Dawn" ) < 0 )
return FALSE;
else if ( GetIsDusk() && GetLocalInt( oWaypoint, "dds_Dusk" ) < 0 )
return FALSE;
}
// Checks to see gender if either the PF or PM switch is set:
if ( GetLocalInt( oWaypoint, "dds_Female" ) > 0 && GetGender( oPC ) == GENDER_MALE )
return FALSE;
if ( GetLocalInt( oWaypoint, "dds_Male" ) > 0 && GetGender( oPC ) == GENDER_FEMALE )
return FALSE;
// Checks to see if player level maximum is set:
if ( GetLocalInt( oWaypoint, "dds_PlayerLevelMax" ) > 0 )
{
if ( GetHitDice( oPC ) > GetLocalInt( oWaypoint, "dds_PlayerLevelMax" ) )
return FALSE;
}
// Checks to see if player level minimum is set:
if ( GetLocalInt( oWaypoint, "dds_PlayerLevelMin" ) > 0 )
{
if ( GetHitDice( oPC ) < GetLocalInt( oWaypoint, "dds_PlayerLevelMin" ) )
return FALSE;
}
// Checks for the absence of a particular item
if ( GetLocalInt( oWaypoint, "dds_NotPlayerItem" ) > 0 )
{
sItem = "item" + dds_ValueToString ( GetLocalInt( oWaypoint, "dds_PlayerItem" ) );
sItem = GetLocalString( OBJECT_SELF, sItem );
if ( dds_CheckInventory( sItem, oPC ) )
{
return FALSE;
}
}
// Checks for a particular item in the players inventory
if ( GetLocalInt( oWaypoint, "dds_PlayerItem" ) > 0 &&
GetLocalInt( oWaypoint, "dds_NotPlayerItem" ) == 0 )
{
sItem = "item" + dds_ValueToString ( GetLocalInt( oWaypoint, "dds_PlayerItem" ) );
sItem = GetLocalString( OBJECT_SELF, sItem );
if ( !dds_CheckInventory( sItem, oPC ) )
return FALSE;
}
// Returns the "weight" of the waypoint. If this is not specified, then the
// weight of a particular waypoint is 1. If it is specified, then that
// waypoint is X times more likely to be chosen.
return GetLocalInt( oWaypoint, "dds_Weighted" );
}
// Extracts the number attached to a switch
int dds_GetNumber( string sName, string sSwitch, int iSecond=FALSE )
{
int iStart = FindSubString( sName, sSwitch );
if ( iStart < 0 )
return -1;
iStart = iStart + GetStringLength( sSwitch );
if ( iSecond )
iStart = iStart + 3;
int iValue = StringToInt( GetSubString( sName, iStart, 2 ) );
return iValue;
}
// Checks to see if an item is in the inventory of a player
int dds_CheckInventory( string sTag, object oPC )
{
object oItem = GetFirstItemInInventory( oPC );
string sItemTag;
while ( oItem != OBJECT_INVALID )
{
sItemTag = GetTag( oItem );
if ( sItemTag == sTag )
return TRUE;
oItem = GetNextItemInInventory( oPC );
}
return FALSE;
}
// ModInit sets up local variables used
void dds_ModInit()
{
// Single Items
SetLocalString(OBJECT_SELF, "item_01", "dds_key");
// Messages
SetLocalString(OBJECT_SELF, "message_01", "You have finally arrived at the destination you sought.");
// Has run already?
SetLocalInt(OBJECT_SELF, "ModInit", 1);
}