FANDOM


m (capitalization)
(Script 1: linking to event handler)
 
(3 intermediate revisions by one user not shown)
Line 1: Line 1:
== What it does ==
+
'''Animatronic store''' is a [[script]] that causes a [[non-player character|NPC]] to approach a [[player character|PC]], say something, then open a [[store]] whenever the PC uses (clicks on) a special [[placeable]]. The contents of the store are randomly generated and replenished over time.
'''Animatronic Store''': You click the [[placeable]] "[[container]]", the [[NPC]] comes over, says whatever [[conversation|speil]] you like and opens the store.
 
   
The script also randomly generates the contents (5 types) and replenishes over time, if needed. It is compatible with regular merchants.
+
== Configuration ==
+
The elements a [[module]] needs in order to make use of this script are
== Setting up the script ==
+
* a [[conversation]] called "basic_merchant",
Scripts needed: 2
+
* an NPC to initiate the dialog,
+
* a placeable for PCs to click, and
Items needed:
+
* a merchant object to be opened.
* an NPC with the word "seller" in its [[tag]] and the second [[script]] in its conversation,
+
To make the script work, some guidelines must be followed. The NPC must have the word "seller" in its [[tag]], and the placeable should have one of six keywords in its tag ("CLASS", "ARCANE", "DIVINE", "AMMO", "POTION", or "KIT"). In addition, the placeable must be useable with no inventory, and probably should be flagged as [[plot]]. The dialog does not need to be assigned to the NPC in the [[Toolset]], but should end with a line like "Do you want to see these?", for which the second script below is the "Actions Taken" script. Finally, the merchant object needs to be placed near the placeable.
* a placeable set to plot and useable with no [[inventory]], that should have one of 5 words in its tag (see script),
 
* a script with the [[ResRef]] "basic_merchant", and
 
* a merchant placed near the placeable.
 
   
 
== How it works ==
 
== How it works ==
Basically, the script uses the tag of the placeable to determine how to stock the nearest store. Since it uses the standard [[NWN]] treasure charts the [[class]] and [[level]] of the seller also affect stocking.
+
The script stocks the nearest store using the standard (non-expansion) treasure system included in NWN, based on the keyword in the placeable's tag. This treasure system often factors a character's [[class]] and [[character level|level]] into which items are created; for this script, it is the NPC's class and level that affect the items. Next, the NPC moves to the PC and starts the "basic_merchant" conversation, which ends with the newly-stocked store being opened.
   
Once the placeable is properly stocked, the nearest designated salesman is called over and his conversation starts.
+
== Script 1 ==
I found that I had to add an option in his conversation to ask him to back up, otherwise s/he tends to trap characters in corners.
+
This script is to be the container's [[OnUsed event]] [[event handler|handler]].
 
== The Script, part 1 ==
 
This goes in the container's on_use (note the container will not have an inventory!)
 
   
 
<pre>
 
<pre>
 
#include "nw_o2_coninclude"
 
#include "nw_o2_coninclude"
  +
 
// Generate treasure routine modified from guess where
 
// Generate treasure routine modified from guess where
 
void GenerateStock(int nNumberItems, object oSeller, object oStore)
 
void GenerateStock(int nNumberItems, object oSeller, object oStore)
 
{
 
{
// there are 5 basic types of store. The tag should include one of the 5 words below
+
// There are 6 basic types of stores.
int nType = 0; // defaults to class (personal items)
+
// The tag should include one of the 6 words below.
if ( FindSubString( GetTag(oStore), "CLASS") >= 0 ) { nType=0; }
+
int nType = 0; // defaults to class (personal items)
else if (FindSubString( GetTag(oStore),"ARCANE")>=0) {nType=1;}
+
if ( FindSubString( GetTag(oStore), "CLASS") >= 0 )
else if (FindSubString(GetTag(oStore),"DIVINE")>=0) {nType=2;}
+
nType = 0;
else if (FindSubString(GetTag(oStore),"AMMO")>=0) {nType=3;}
+
else if ( FindSubString(GetTag(oStore), "ARCANE") >= 0 )
else if (FindSubString(GetTag(oStore),"POTION")>=0) {nType=4;}
+
nType=1;
else if (FindSubString(GetTag(oStore),"KIT")>=0) {nType=5;}
+
else if ( FindSubString(GetTag(oStore), "DIVINE") >= 0 )
int i = 0;
+
nType=2;
for (i = 1; i <= nNumberItems; i++) {
+
else if ( FindSubString(GetTag(oStore), "AMMO") >= 0 )
switch(nType) {
+
nType=3;
case 0: {CreateTable2Item(oStore, oSeller, 0); break; }
+
else if ( FindSubString(GetTag(oStore), "POTION") >= 0 )
case 1: {CreateArcaneScroll(oStore, oSeller); break; }
+
nType=4;
case 2: {CreateDivineScroll(oStore, oSeller); break; }
+
else if ( FindSubString(GetTag(oStore), "KIT") >= 0 )
case 3: {CreateAmmo(oStore, oSeller); break; }
+
nType=5;
case 4: {CreatePotion(oStore, oSeller); break; }
+
case 5: {CreateKit(oStore, oSeller); break; }
+
int i = 0;
  +
for ( i = 1; i <= nNumberItems; i++)
  +
{
  +
switch(nType)
  +
{
  +
case 0: CreateTable2Item(oStore, oSeller, 0); break;
  +
case 1: CreateArcaneScroll(oStore, oSeller); break;
  +
case 2: CreateDivineScroll(oStore, oSeller); break;
  +
case 3: CreateAmmo(oStore, oSeller); break;
  +
case 4: CreatePotion(oStore, oSeller); break;
  +
case 5: CreateKit(oStore, oSeller); break;
 
}
 
}
 
}
 
}
//dbSpeak("Generate Treasure nSpecific = 0");
 
 
}
 
}
  +
  +
 
void main()
 
void main()
 
{
 
{
object oPC;
+
object oPC = GetLastUsedBy();
oPC = GetLastUsedBy();
+
if ( !GetIsObjectValid(oPC) )
if (!GetIsObjectValid(oPC)) { oPC = GetLastOpenedBy(); }
+
oPC = GetLastOpenedBy();
object oShelf = OBJECT_SELF;
+
object oStore = GetNearestObject( OBJECT_TYPE_STORE, oShelf, 1 );
+
object oShelf = OBJECT_SELF;
int nNth=1;
+
object oStore = GetNearestObject(OBJECT_TYPE_STORE, oShelf, 1);
object oSeller = GetNearestObject( OBJECT_TYPE_CREATURE, oShelf, nNth );
+
while ( GetIsObjectValid(oSeller) ) {
+
int nNth = 1;
if ( !GetIsPC(oSeller) ) {break;}
+
object oSeller = GetNearestObject(OBJECT_TYPE_CREATURE, oShelf, nNth);
nNth++;
+
while ( GetIsObjectValid(oSeller) )
oSeller = GetNearestObject( OBJECT_TYPE_CREATURE, oShelf, nNth );
+
{
  +
if ( !GetIsPC(oSeller) )
  +
break;
  +
nNth++;
  +
oSeller = GetNearestObject(OBJECT_TYPE_CREATURE, oShelf, nNth);
 
}
 
}
// store merchant object
+
SetLocalObject( oPC, "Store_at", oStore );
+
// Store the merchant object.
// * RESTOCK THE STORE (Simulates trade and over-ordering)
+
SetLocalObject(oPC, "Store_at", oStore);
// add lots if store has never been used before
+
if ( GetLocalInt(oStore, "LastStocked") ==0 )
+
// Restock the store. (Simulates trade and over-ordering.)
{ GenerateStock( d10(1)+10, oSeller, oStore); }
+
// Add lots if store has never been used before.
// get what day it is
+
if ( GetLocalInt(oStore, "LastStocked") == 0 )
////////////adjust (GetCalendarYear()-##) ## should be your module's starting year
+
GenerateStock(d10(1)+10, oSeller, oStore);
int nTime = (GetCalendarYear()-65)*365 + GetCalendarMonth()*31 + GetCalendarDay();
+
// Get what day it is.
// restock fastest if low inventory
+
///Adjustment needed: In "(GetCalendarYear()-##)", the "##" should be the module's starting year.
nNth = 0;
+
int nTime = (GetCalendarYear()-65)*365 + GetCalendarMonth()*31 + GetCalendarDay();
object oItem = GetFirstItemInInventory(oStore);
+
// restock fastest if low inventory
while ( GetIsObjectValid(oItem) ) { nNth++; oItem = GetNextItemInInventory(oStore); }
+
nNth = 0;
nTime = nTime + 5 / nNth;
+
object oItem = GetFirstItemInInventory(oStore);
// add some stock every week or so
+
while ( GetIsObjectValid(oItem) )
if ( GetLocalInt(oStore, "LastStocked") < nTime-10 )
+
{
{ GenerateStock( d4(1), oSeller, oStore); }
+
nNth++;
// add some more stock every few days
+
oItem = GetNextItemInInventory(oStore);
if ( GetLocalInt(oStore, "LastStocked") < nTime- 5) {
 
GenerateStock( d4(1), oSeller, oStore);
 
SetLocalInt( oStore, "LastStocked", nTime );
 
 
}
 
}
// END RESTOCKING *
+
nTime = nTime + 5 / nNth;
// salesman comes over
+
// Add some stock every week or so.
AssignCommand( oSeller, ActionMoveToObject(oShelf,FALSE,5.0) );
+
if ( GetLocalInt(oStore, "LastStocked") < nTime-10 )
AssignCommand( oSeller, ActionStartConversation(oPC,"basic_merchant",TRUE) );
+
GenerateStock(d4(1), oSeller, oStore);
  +
// Add some more stock every few days.
  +
if ( GetLocalInt(oStore, "LastStocked") < nTime- 5)
  +
{
  +
GenerateStock(d4(1), oSeller, oStore);
  +
SetLocalInt(oStore, "LastStocked", nTime);
  +
}
  +
// END Restocking.
  +
  +
// Salesman comes over.
  +
AssignCommand(oSeller, ActionMoveToObject(oShelf, FALSE, 5.0));
  +
AssignCommand(oSeller, ActionStartConversation(oPC, "basic_merchant", TRUE));
 
}
 
}
 
</pre>
 
</pre>
   
== The Script, Part 2 ==
+
== Script 2 ==
This goes in the conversation script. Note that the previous script will start the conversation. It is set up for a ResRef "basic_merchant" for the conversation.
+
This script is an "Actions Taken" script for the last line in the dialog named "basic_merchant".
   
 
<pre>
 
<pre>
 
void main()
 
void main()
 
{
 
{
object oPC = GetPCSpeaker();
+
object oPC = GetPCSpeaker();
object oStore = GetLocalObject( oPC, "Store_at" );
+
object oStore = GetLocalObject(oPC, "Store_at");
if ( GetDistanceToObject(oStore)<10.0 ) { OpenStore( oStore, oPC ); }
 
}
 
   
  +
if ( GetDistanceToObject(oStore) < 10.0 )
  +
OpenStore(oStore, oPC);
  +
}
 
</pre>
 
</pre>
   
 
== Notes ==
 
== Notes ==
*I should also mention that the merchant conversation this script uses isn't necessarily (and probably isn't) the conversation the Seller uses when you click on it. It's simply a script that says something like "Do you want to see these?" or some such generic store opening question. After using it awhile I'm sonsidering have it be a one-liner and use OpenStore immediately.
+
* It is possible to merge the two scripts, eliminating the "basic_merchat" conversation. (Instead of a full-fledged conversation, the NPC would be made to speak a one-liner.)
  +
* The original version of this script is by WyrmSoul, and was posted in the BioWare fourms [http://nwn.bioware.com/forums/viewpost.html?topic=116828&post=1194053&forum=63 here].
   
[[category:Script_directory:Merchants]]
+
[[category:Script directory:Merchants]]

Latest revision as of 23:34, December 15, 2011

Animatronic store is a script that causes a NPC to approach a PC, say something, then open a store whenever the PC uses (clicks on) a special placeable. The contents of the store are randomly generated and replenished over time.

Configuration Edit

The elements a module needs in order to make use of this script are

  • a conversation called "basic_merchant",
  • an NPC to initiate the dialog,
  • a placeable for PCs to click, and
  • a merchant object to be opened.

To make the script work, some guidelines must be followed. The NPC must have the word "seller" in its tag, and the placeable should have one of six keywords in its tag ("CLASS", "ARCANE", "DIVINE", "AMMO", "POTION", or "KIT"). In addition, the placeable must be useable with no inventory, and probably should be flagged as plot. The dialog does not need to be assigned to the NPC in the Toolset, but should end with a line like "Do you want to see these?", for which the second script below is the "Actions Taken" script. Finally, the merchant object needs to be placed near the placeable.

How it works Edit

The script stocks the nearest store using the standard (non-expansion) treasure system included in NWN, based on the keyword in the placeable's tag. This treasure system often factors a character's class and level into which items are created; for this script, it is the NPC's class and level that affect the items. Next, the NPC moves to the PC and starts the "basic_merchant" conversation, which ends with the newly-stocked store being opened.

Script 1 Edit

This script is to be the container's OnUsed event handler.

#include "nw_o2_coninclude"

// Generate treasure routine modified from guess where
void GenerateStock(int nNumberItems, object oSeller, object oStore)
{
    // There are 6 basic types of stores.
    // The tag should include one of the 6 words below.
    int nType = 0; // defaults to class (personal items)
    if ( FindSubString( GetTag(oStore), "CLASS") >= 0 )
        nType = 0;
    else if ( FindSubString(GetTag(oStore), "ARCANE") >= 0 )
        nType=1;
    else if ( FindSubString(GetTag(oStore), "DIVINE") >= 0 )
        nType=2;
    else if ( FindSubString(GetTag(oStore), "AMMO") >= 0 )
        nType=3;
    else if ( FindSubString(GetTag(oStore), "POTION") >= 0 )
        nType=4;
    else if ( FindSubString(GetTag(oStore), "KIT") >= 0 )
        nType=5;

    int i = 0;
    for ( i = 1; i <= nNumberItems; i++)
    {
        switch(nType)
        {
            case 0:  CreateTable2Item(oStore, oSeller, 0);  break;
            case 1:  CreateArcaneScroll(oStore, oSeller);   break;
            case 2:  CreateDivineScroll(oStore, oSeller);   break;
            case 3:  CreateAmmo(oStore, oSeller);           break;
            case 4:  CreatePotion(oStore, oSeller);         break;
            case 5:  CreateKit(oStore, oSeller);            break;
        }
   }
}


void main()
{
    object oPC = GetLastUsedBy();
    if ( !GetIsObjectValid(oPC) )
        oPC = GetLastOpenedBy();

    object oShelf = OBJECT_SELF;
    object oStore = GetNearestObject(OBJECT_TYPE_STORE, oShelf, 1);

    int nNth = 1;
    object oSeller = GetNearestObject(OBJECT_TYPE_CREATURE, oShelf, nNth);
    while ( GetIsObjectValid(oSeller) )
    {
        if ( !GetIsPC(oSeller) )
            break;
        nNth++;
        oSeller = GetNearestObject(OBJECT_TYPE_CREATURE, oShelf, nNth);
    }

    // Store the merchant object.
    SetLocalObject(oPC, "Store_at", oStore);

    // Restock the store. (Simulates trade and over-ordering.)
    // Add lots if store has never been used before.
    if ( GetLocalInt(oStore, "LastStocked") == 0 )
        GenerateStock(d10(1)+10, oSeller, oStore);
    // Get what day it is.
    ///Adjustment needed: In "(GetCalendarYear()-##)", the "##" should be the module's starting year.
    int nTime = (GetCalendarYear()-65)*365 + GetCalendarMonth()*31 + GetCalendarDay();
    // restock fastest if low inventory
    nNth = 0;
    object oItem = GetFirstItemInInventory(oStore);
    while ( GetIsObjectValid(oItem) )
    {
        nNth++;
        oItem = GetNextItemInInventory(oStore);
    }
    nTime = nTime + 5 / nNth;
    // Add some stock every week or so.
    if ( GetLocalInt(oStore, "LastStocked") < nTime-10 )
        GenerateStock(d4(1), oSeller, oStore);
    // Add some more stock every few days.
    if ( GetLocalInt(oStore, "LastStocked") < nTime- 5)
    {
        GenerateStock(d4(1), oSeller, oStore);
        SetLocalInt(oStore, "LastStocked", nTime);
    }
    // END Restocking.

    // Salesman comes over.
    AssignCommand(oSeller, ActionMoveToObject(oShelf, FALSE, 5.0));
    AssignCommand(oSeller, ActionStartConversation(oPC, "basic_merchant", TRUE));
}

Script 2 Edit

This script is an "Actions Taken" script for the last line in the dialog named "basic_merchant".

void main()
{
    object oPC = GetPCSpeaker();
    object oStore = GetLocalObject(oPC, "Store_at");

    if ( GetDistanceToObject(oStore) < 10.0 )
        OpenStore(oStore, oPC);
}

Notes Edit

  • It is possible to merge the two scripts, eliminating the "basic_merchat" conversation. (Instead of a full-fledged conversation, the NPC would be made to speak a one-liner.)
  • The original version of this script is by WyrmSoul, and was posted in the BioWare fourms here.
Community content is available under CC-BY-SA unless otherwise noted.