NWNWiki
Register
NWNWiki
3,718
pages
Edit Page
Warning: You are not logged in. Your IP address will be publicly visible if you make any edits. If you log in or create an account, your edits will be attributed to your username, along with other benefits.

The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then publish the changes below to finish undoing the edit.

Latest revision Your text
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.
 
  +
* You need an NPC with the word "seller" in its [[tag]] and the second [[script]] in it's 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.
 
  +
* 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 ==
 
== 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 6 basic types of stores.
+
// 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)
// 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)
 
if ( FindSubString( GetTag(oStore), "CLASS") >= 0 )
+
else if (FindSubString( GetTag(oStore),"ARCANE")>=0) {nType=1;}
  +
else if (FindSubString(GetTag(oStore),"DIVINE")>=0) {nType=2;}
nType = 0;
 
else if ( FindSubString(GetTag(oStore), "ARCANE") >= 0 )
+
else if (FindSubString(GetTag(oStore),"AMMO")>=0) {nType=3;}
  +
else if (FindSubString(GetTag(oStore),"POTION")>=0) {nType=4;}
nType=1;
 
else if ( FindSubString(GetTag(oStore), "DIVINE") >= 0 )
+
else if (FindSubString(GetTag(oStore),"KIT")>=0) {nType=5;}
 
int i = 0;
nType=2;
 
 
for (i = 1; i <= nNumberItems; i++) {
else if ( FindSubString(GetTag(oStore), "AMMO") >= 0 )
 
 
switch(nType) {
nType=3;
 
else if ( FindSubString(GetTag(oStore), "POTION") >= 0 )
+
case 0: {CreateTable2Item(oStore, oSeller, 0); break; }
 
case 1: {CreateArcaneScroll(oStore, oSeller); break; }
nType=4;
 
else if ( FindSubString(GetTag(oStore), "KIT") >= 0 )
+
case 2: {CreateDivineScroll(oStore, oSeller); break; }
 
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 = GetLastUsedBy();
+
object oPC;
  +
oPC = GetLastUsedBy();
if ( !GetIsObjectValid(oPC) )
 
oPC = GetLastOpenedBy();
+
if (!GetIsObjectValid(oPC)) { 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>
   
== Script 2 ==
+
== The Script, Part 2 ==
This script is an "Actions Taken" script for the last line in the dialog named "basic_merchant".
+
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.
   
 
<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]]
Please note that all contributions to the NWNWiki are considered to be released under the CC-BY-SA
Cancel Editing help (opens in new window)