Animatronic store

What it does

You click the placeable "container", the NPC comes over, says whateve speil you like and opens the store. The script also randomly generates the contents (5 types) and replenishes over time and if needed. It is compatible with regular merchants.


Scripts needed: 2

Items needed:

  • You need an NPC with the word "seller" in its tag and the second script in it's conversation.
  • You need 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"
  • a merchant placed near the placeable.

How it works

basically it 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.

Once the placeable is properly stocked, the nearest designated salesman is called over and his conversation starts. 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.

The Script, part 1

This goes in the container's on_use (note the container will not have an inventory!)

#include "nw_o2_coninclude"
// Generate treasure routine modified from guess where
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
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; }
//dbSpeak("Generate Treasure nSpecific = 0");
void main()
object oPC;
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;}
    oSeller = GetNearestObject( OBJECT_TYPE_CREATURE, oShelf, nNth );
// store 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
////////////adjust (GetCalendarYear()-##) ## should be your 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 );
// salesman comes over
AssignCommand( oSeller, ActionMoveToObject(oShelf,FALSE,5.0) );
AssignCommand( oSeller, ActionStartConversation(oPC,"basic_merchant",TRUE) );

The Script, Part 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.

void main()
object oPC = GetPCSpeaker();
object oStore = GetLocalObject( oPC, "Store_at" );
if ( GetDistanceToObject(oStore)<10.0 ) { OpenStore( oStore, oPC ); }


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.

Community content is available under CC-BY-SA unless otherwise noted.