Initial upload
Initial upload
This commit is contained in:
202
_module/nss/tab_containregen.nss
Normal file
202
_module/nss/tab_containregen.nss
Normal file
@@ -0,0 +1,202 @@
|
||||
/**
|
||||
* Generic OnOpen and OnDeath handler for respawning containers.
|
||||
* To use this script:
|
||||
* <ol>
|
||||
* <li>Create a new invisible plot object to act as the respawner. Note its
|
||||
* resref, as we'll be using it later.</li>
|
||||
* <li>Create a container and set this script as its OnOpen and OnDeath
|
||||
* handler.</li>
|
||||
* <li>Create a custom OnUserDefined script for the container.</li>
|
||||
* <li>In that script, #include "dmc_inc_contgen"</li>
|
||||
* <li>In that script, handle the UE_SET_RESPAWN_VARIABLES event. In it,
|
||||
* set the following local variables:
|
||||
* <ul>
|
||||
* <li>float RESPAWN_DURATION_TAG: the number of seconds to wait between
|
||||
* respawns. (REQUIRED)</li>
|
||||
* <li>string RESPAWNER_RESREF_TAG: the blueprint resref of the
|
||||
* respawner blueprint created above. (REQUIRED)</li>
|
||||
* <li>int CONTAINER_STORE_INVENTORY_TAG: TRUE if you want the
|
||||
* container's original contents to be respawned. Defaults to
|
||||
* FALSE.</li>
|
||||
* </ul>
|
||||
* Once you've finished setting these variables, call
|
||||
* callbackSetRespawnVariables.</li>
|
||||
* <li>In that script, optionally handle the UE_GENERATE_TREASURE event. In it,
|
||||
* generate treasure for the container. You can use the treasure generation
|
||||
* system from the original campaign (found in NW_O2_CONINCLUDE), the
|
||||
* treasure generation system from Shadows of Undrentide (found in
|
||||
* X0_I0_TREASURE), or your own treasure generation system. Prior to the
|
||||
* event being signalled, the CONTAINER_ACTOR_TAG local object is set to
|
||||
* the object that triggered the event (whoever opened or destroyed the
|
||||
* container).</li>
|
||||
* <li>In that script, optionally handle the UE_CONTAINER_DESTRUCTION event. In
|
||||
* it, perform any operations needed when the container is destroyed, such
|
||||
* as destroying fragile treasure. This is signalled AFTER the
|
||||
* UE_GENERATE_TREASURE event. Prior to the event being signalled, the
|
||||
* CONTAINER_ACTOR_TAG local object is set to the object that triggered the
|
||||
* event (whoever destroyed the container).</li>
|
||||
*
|
||||
* Feel free to use or modify this script freely, with the exception that this
|
||||
* paragraph must remain unchanged. Please leave some mention of the original
|
||||
* authors in the comments of the script, and if you have an area in your module
|
||||
* where you give credit to the developers/contributors, please be sure to
|
||||
* include us.
|
||||
*
|
||||
* @author <a href="mailto:david@carr.name">David Carr</a>
|
||||
* @author <a href="http://nwvault.ign.com/Files/scripts/data/1046937481401.shtml">
|
||||
* R.Lowe
|
||||
* </a>
|
||||
* @version 0.3
|
||||
*/
|
||||
|
||||
#include "dmc_inc_contgen"
|
||||
|
||||
/**
|
||||
* PRIVATE: Returns the value of GetLastOpenedBy() if set, otherwise the value
|
||||
* of GetLastKiller() if set, otherwise OBJECT_INVALID.
|
||||
*/
|
||||
object GetLastOpenerOrKiller() {
|
||||
object oLastOpenedBy = GetLastOpenedBy();
|
||||
object oLastKiller = GetLastKiller();
|
||||
if(GetIsObjectValid(oLastOpenedBy)) {
|
||||
return oLastOpenedBy;
|
||||
} else if(GetIsObjectValid(oLastKiller)){
|
||||
return oLastKiller;
|
||||
} else {
|
||||
return OBJECT_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* PRIVATE: Returns if the specified object was killed
|
||||
*/
|
||||
int ObjectWasKilled() {
|
||||
return GetIsObjectValid(GetLastKiller());
|
||||
}
|
||||
|
||||
/**
|
||||
* PRIVATE: Alert nearby creatures when a container is disturbed.
|
||||
* Based on code in NW_O2_CONINCLUDE.
|
||||
*/
|
||||
void ShoutDisturbed() {
|
||||
object oContainer = OBJECT_SELF;
|
||||
location lLoc = GetLocation(oContainer);
|
||||
object oAttacker = GetLastOpenerOrKiller();
|
||||
object oTarget = GetFirstObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, lLoc,
|
||||
TRUE, OBJECT_TYPE_CREATURE);
|
||||
//Cycle through the targets within the spell shape until an
|
||||
//invalid object is captured.
|
||||
while(GetIsObjectValid(oTarget)) {
|
||||
if(GetFactionEqual(oTarget, oContainer)) {
|
||||
//Make anyone who is a member of my faction hostile if I am violated
|
||||
SetIsTemporaryEnemy(oAttacker, oTarget);
|
||||
AssignCommand(oTarget, ActionAttack(oAttacker));
|
||||
}
|
||||
oTarget = GetNextObjectInShape(SHAPE_SPHERE, RADIUS_SIZE_LARGE, lLoc, TRUE,
|
||||
OBJECT_TYPE_CREATURE);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* PRIVATE: Returns true if it's okay to generate treasure now
|
||||
*/
|
||||
int respawnTimerHasExpired(object oContainer) {
|
||||
return !GetLocalInt(oContainer, RESPAWN_TIMER_TAG);
|
||||
}
|
||||
|
||||
/**
|
||||
* PRIVATE: Puts a hold on treasure generation until clearRespawnTimer is called
|
||||
*/
|
||||
void setRespawnTimer(object oContainer) {
|
||||
SetLocalInt(oContainer, RESPAWN_TIMER_TAG, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* PRIVATE: Removes the association between the spawner and a container
|
||||
*/
|
||||
void clearInstance(object oSpawner) {
|
||||
DeleteLocalObject(oSpawner, INSTANCE_TAG);
|
||||
}
|
||||
|
||||
/**
|
||||
* PRIVATE: Returns the respawner object associated with a container, or
|
||||
* OBJECT_INVALID if one doesn't exist
|
||||
*/
|
||||
object getRespawner(object oContainer) {
|
||||
return GetLocalObject(oContainer, RESPAWNER_TAG);
|
||||
}
|
||||
|
||||
/**
|
||||
* PRIVATE: Signals the container to set its variables, such as respawn duration
|
||||
* and whether to store the inventory. No arguments are passed.
|
||||
*/
|
||||
void signalSetRespawnVariables(object oContainer) {
|
||||
SignalEvent(oContainer, EventUserDefined(UE_SET_RESPAWN_VARIABLES));
|
||||
}
|
||||
|
||||
/**
|
||||
* PRIVATE: Signals the treasure generation event for the container. One
|
||||
* argument is passed, the "actor" who triggered the event.
|
||||
*/
|
||||
void signalTreasureGeneration(object oContainer, object oActor) {
|
||||
//Set the actor on the container so that it can be accessed from user events
|
||||
SetLocalObject(oContainer, CONTAINER_ACTOR_TAG, oActor);
|
||||
SignalEvent(oContainer, EventUserDefined(UE_GENERATE_TREASURE));
|
||||
}
|
||||
|
||||
/**
|
||||
* PRIVATE: Signals the container destruction event for the container. One
|
||||
* argument is passed, the "actor" who triggered the event.
|
||||
*/
|
||||
void signalContainerDestruction(object oContainer, object oActor) {
|
||||
//Set the actor on the container so that it can be accessed from user events
|
||||
SetLocalObject(oContainer, CONTAINER_ACTOR_TAG, oActor);
|
||||
SignalEvent(oContainer, EventUserDefined(UE_CONTAINER_DESTRUCTION));
|
||||
}
|
||||
|
||||
/**
|
||||
* PRIVATE: If a respawner for the specified container doesn't exist, create
|
||||
* one. If it's a new respawner or the instance was destroyed, update the stored
|
||||
* instance. Then, queue a command to respawn the treasure/container.
|
||||
*/
|
||||
void scheduleRespawn(object oContainer) {
|
||||
if(!GetIsObjectValid(oContainer) || !GetHasInventory(oContainer)) {
|
||||
logError("invalid object passed to scheduleRespawn");
|
||||
return;
|
||||
}
|
||||
object oSpawner = getRespawner(oContainer);
|
||||
if(!GetIsObjectValid(oSpawner)) {//If there isn't a spawner already
|
||||
signalSetRespawnVariables(oContainer);
|
||||
} else {
|
||||
addRespawnToEventQueue(oSpawner);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* PRIVATE: First, determine whether the container was opened or destroyed.
|
||||
* Then, if it has been destroyed or it is time to generate treasure, set a
|
||||
* timer for a respawn. Then, generate the treasure if appropriate. If the
|
||||
* chest was destroyed, potions may be shattered. Also, alert any nearby
|
||||
* creatures.
|
||||
*/
|
||||
void main() {
|
||||
object oContainer = OBJECT_SELF;
|
||||
object oActor = GetLastOpenerOrKiller();
|
||||
int bWasKilled = ObjectWasKilled();
|
||||
if(!GetIsObjectValid(oActor)) {
|
||||
logError("object was neither opened nor destroyed");
|
||||
return;
|
||||
}
|
||||
if(respawnTimerHasExpired(oContainer)) {
|
||||
setRespawnTimer(oContainer);
|
||||
scheduleRespawn(oContainer);
|
||||
signalTreasureGeneration(oContainer, oActor);
|
||||
} else if(bWasKilled) {
|
||||
//clear the instance so that the respawn event knows to make a new container
|
||||
clearInstance(getRespawner(oContainer));
|
||||
}
|
||||
if(bWasKilled) {
|
||||
signalContainerDestruction(oContainer, oActor);
|
||||
}
|
||||
ShoutDisturbed();
|
||||
}
|
||||
Reference in New Issue
Block a user