PDA

View Full Version : Script: Shop system


Skyld
08-21-2006, 11:11 PM
Once again in the interest of education, here's my shop system. It's broken into several parts, so make sure to read the instructions carefully!

Now, of course you can modify the script to make it match your own setup, however, here's how it works in my configuration. It also works using gralats by default; you'll have to change it in order to use custom money.

You'll need to update the shop weapon so that it adds the item to the player matching your own system. Also, you'll want to make sure that the seteffect fade doesn't interfere with your daynight, and finally, note that the weapon has a "Debit" option. This was for my setup on Rudora so that you could pay straight from your bank account. Either match it to your own bank system or just rip it out.

The system will depend upon three database NPCs, two classes and one weapon. Start by making the Database NPCs;

DB_Items; this is where we will store information about the items which you will sell
DB_Shops; this is where we will store the names of the shops, funds received from shop sales, etc
DB_Prices; this is where we will store the prices of items


You'll need to populate the NPCs with some data. Let's start with DB_Items; put the following script in DB_Items:
function onCreated()
{
/*
Format:
this.item_id = {Name, Internalname, Image, ActionWeapon, Canbedropped};
*/

this.item_100 = {"Block", "block", "block.png", "-No Item", 1};
}

Next, in DB_Prices, put the following:
function onCreated()
{
// Format:
// this.item_id = price

this.item_100 = 3; // 3 gralats in this case
}

Next, you'll need to set up the levels with the classes. It shouldn't really matter what you name the classes, but for this example, we'll use 'shopcontrol' and 'shopitem'.

Each shop level requires one shopcontrol class. This puts the level's base name into a level variable, and displays the shop's funds and name. Put this somewhere nice-looking. Just do something like this:
this.join("shopcontrol");

Now, for each item that you want to sell in the shop, place a shopitem. You must specify additional data for shopitem classes, such as the item you want to sell. Here's an example:
this.item = 100; // this is item ID 100 from DB_Items
this.customimage = false; // use the image set in DB_Items
this.join("shopitem");

Finally, add the shop interface weapon into a weapon called "-Shop", and make sure that it is added to any players using the shop. Hell, you could just add it to all players on logon.

That's about it, really. Once you upload the shop, it should work. You should also be able to specify a name for the shop inside DB_Shops' flag list once it's uploaded.

Enjoy.

Shop item class:
function onCreated()
{
onTimeout();
}

function onTimeout()
{
this.okay = 0;

if (this.item == NULL)
{
temp.data = "-unavailable-";
}

if (DB_Items.("item_" @ this.item) == NULL)
{
temp.data = "-unavailable-";
}

if (DB_Prices.("item_" @ this.item) == NULL)
{
temp.data = "-unavailable-";
}

this.itemdata = DB_Items.("item_" @ this.item);
this.price = DB_Prices.("item_" @ this.item);

this.setShape(1, 32, 32);

if (temp.data == "-unavailable-")
{
this.setimg(""); // <- image for unavailable item here
}
else
{
if (this.customimage != TRUE ||
this.customimage == 0)
{
this.setimg(this.itemdata[2]);
}
}

if (temp.data == NULL)
{
temp.data = this.itemdata[0];
this.okay = 1;
}

showimg(1, "@Tahoma@bc@" @ temp.data, this.x + 1, this.y - 0.5);
changeimgzoom(1, 0.5);

setTimer(2);
}

function onActionleftmouse()
{
if (this.okay == 1)
{
player.triggerclient("-Shop", "purchaseItem", this.item, this.itemdata, this.price);
}
}

Shop control class:
function onCreated()
{
level.creditor = extractfilebase(this.level.name);

onTimeout();
}

function onTimeout()
{
level.shopname = (!(DB_Shops.(level.creditor @ "_name")) ?
"Unnamed Shop" : DB_Shops.(level.creditor @ "_name"));

showimg(1, format("@Tahoma@bc@%s", level.shopname), x - 1.5, y - 1);
changeimgvis(1, 2);
changeimgzoom(1, 0.8);

showimg(2, format("@Tahoma@bc@Shop Funds: %ig", DB_Shops.(level.creditor @ "_funds")), x - 1.5, y);
changeimgvis(2, 2);
changeimgzoom(2, 0.5);

setTimer(2);
}

-Shop weapon:
function onActionserverside()
{
if (params[0] == "purchaseItem")
{
if (params[1] == NULL)
{
player.say2("An error occured. 1" @ params[1]);
return;
}

if (DB_Prices.("item_" @ params[1]) == NULL)
{
player.say2("An error occured. 2");
return;
}

temp.price = DB_Prices.("item_" @ params[1]);
temp.item = params[1];
temp.creditor = (!level.creditor ? "unknown" : level.creditor);

if (params[2] == false)
{
if (player.rupees >= temp.price)
{
player.rupees -= temp.price;
// ADD THE ITEM TO THE PLAYER HERE
DB_Shops.(temp.creditor @ "_funds") += temp.price;

player.say2("Thank you.");
}
else
{
player.say2("You do not have enough money!");
}
}
else
{
if (player.bankBalance() >= temp.price)
{
temp.res = player.bankDebit(temp.price, temp.creditor);
if (temp.res == 0)
{
// ADD THE ITEM TO THE PLAYER HERE
DB_Shops.(temp.creditor @ "_funds") += temp.price;

player.say2(format("Thank you.\nDebited: %dg.\nNew bank balance: %dg.", temp.price, player.bankBalance()));
}
else
{
player.say2(format("Bank debit failed!\n%s.", temp.res));
}
}
else
{
player.say2("You do not have enough money!");
}
}
}
}

//#CLIENTSIDE

function onPlayerEnters()
{
client.menus.remove("shop");
hideimgs(200, 201);

Shop_Purchase.visible = false;
Shop_Cancel.visible = false;
Shop_Debit.visible = false;
}

function onActionclientside(temp.actionname, temp.itemid, temp.itemdata, temp.itemprice)
{
switch (temp.actionname)
{
case "purchaseItem":
{
if ("shop" in client.menus)
{
return;
}

client.menus.add("shop");
this.sellitem = temp.itemid;

for (temp.i = 0; temp.i <= 0.7; temp.i += 0.1)
{
seteffect(0, 0, 0, temp.i);
sleep(0.05);
}

showimg(200, "@Tahoma@cb@Purchase " @ temp.itemdata[0], screenwidth / 2, (screenheight / 2) - 150);
changeimgvis(200, 5);

showimg(201, "@Tahoma@cb@Price: " @ temp.itemprice @ "g", screenwidth / 2, (screenheight / 2) - 120);
changeimgzoom(201, 0.6);
changeimgvis(201, 5);

new GuiCheckBoxCtrl(Shop_Debit)
{
profile = "GuiBlueCheckBoxProfile";

position = {(screenwidth / 2) - 64, (screenheight / 2) - 110};
extent = {136, 16};

visible = true;

text = "Debit from bank account";
}

new GuiButtonCtrl(Shop_Purchase)
{
profile = "GuiGreenButtonProfile";

position = {(screenwidth / 2) - 72, (screenheight / 2) - 90};
extent = {64, 24};

visible = true;

text = "Purchase";

thiso.catchEvent(this, "onAction", "onPurchase");
}

new GuiButtonCtrl(Shop_Cancel)
{
profile = "GuiBlueButtonProfile";

position = {(screenwidth / 2) + 12, (screenheight / 2) - 90};
extent = {64, 24};

visible = true;

text = "Cancel";

thiso.catchEvent(this, "onAction", "onCancelPurchase");
}

break;
}

default:
{
echo("Invalid shop data received!");
}
}
}

function onPurchase()
{
triggeraction(0, 0, "serverside", "-Rudora-Shop", "purchaseItem", this.sellitem, Shop_Debit.checked);
onCancelPurchase();
}

function onCancelPurchase()
{
if (!("shop" in client.menus))
{
return;
}

hideimgs(200, 201);

Shop_Purchase.destroy();
Shop_Cancel.destroy();
Shop_Debit.destroy();

for (temp.i = 0.7; temp.i >= 0; temp.i -= 0.1)
{
seteffect(0, 0, 0, temp.i);
sleep(0.05);
}

client.menus.remove("shop");
}

Angel_Light
08-24-2006, 01:25 AM
Sexy ;o

coreys
08-24-2006, 02:11 AM
such a simple script to come from you, skyld! ;)

helpful though, way to go ;o

KuJi
08-24-2006, 02:16 AM
Nifty..

Angel_Light
10-09-2006, 02:51 AM
What do you mean by ActionWeapon? in DB_Items? And what exactly do I put in DB_Shops?

Inverness
10-12-2006, 12:20 AM
ActionWeapon is most likely the actual Weapon the item uses to execute stuff.
I myself prefer to make certain public functions that are always executed in the weapon by the Mudlib.
(mud_onPickUp(), mud_onEquip(), mud_onActivate(), mud_onUnEquip(), mud_onDrop())

It works nicely and Oblivion is a good source of ideas.

Angel_Light
10-17-2006, 02:27 AM
I'm entirely sure but okay, still having problems with it though.

sssssssssss
11-07-2009, 11:23 PM
Resurrecting an old post. This is a good resource for some of us still, but Angel_Light's old question is mine.

So ActionWeapon is the -Shop weapon?
and how do you set up DB_Shops?

cbk1994
11-07-2009, 11:50 PM
Resurrecting an old post. This is a good resource for some of us still, but Angel_Light's old question is mine.

So ActionWeapon is the -Shop weapon?
The "ActionWeapon" looks like it's the weapon that goes along with the item, e.g. "Swords/Super Sword" might be the weapon name for a "supersword" item.
and how do you set up DB_Shops?

It looks like it's all there, do you mean how do you add the database NPC itself? Just click Scripts > NPCs (or the NPC button if using the graphical RC), then Add (name it DB_Shops, and put it in an existing level).

sssssssssss
11-08-2009, 02:35 AM
Well on here it just says make a DB called DB_Shops, and add a shop name in the flags.
doesnt tell what format, var to use if any, how to name the shops, nothing that i saw.

the block.png sample item isnt even showing up for me either, and i followed all the directions.

LoneAngelIbesu
11-08-2009, 03:18 AM
Well on here it just says make a DB called DB_Shops, and add a shop name in the flags.
doesnt tell what format, var to use if any, how to name the shops, nothing that i saw.

It does, but you have to actually read the code.

level.shopname = (!(DB_Shops.(level.creditor @ "_name")) ?
"Unnamed Shop" : DB_Shops.(level.creditor @ "_name"));

In DB_Shops, the format for naming shops is this.mylevel_name = "My Shop Name".

sssssssssss
11-08-2009, 05:16 AM
in the flags i have

this.armageddon-shop1.nw_name = "SHOP 1"
also tried w/o .nw in the level name, w/o _name although its obviously required.

its not showing up.

can't buy anything either. Was also wondering, how would you add it to add player.bombs instead of a weapon? is typing that in where the ActionWeapon is sufficient?

LoneAngelIbesu
11-08-2009, 07:04 PM
in the flags i have

this.armageddon-shop1.nw_name = "SHOP 1"
also tried w/o .nw in the level name, w/o _name although its obviously required.

its not showing up.
Then you're doing something else wrong.

can't buy anything either. Was also wondering, how would you add it to add player.bombs instead of a weapon? is typing that in where the ActionWeapon is sufficient?

You have to script adding the item yourself.

sssssssssss
11-09-2009, 07:12 AM
Then you're doing something else wrong.


Did everything that it said to do.

sssssssssss
11-13-2009, 02:38 AM
In DB_Shops, the format for naming shops is this.mylevel_name = "My Shop Name".

Just to clarify, its actually just
mylevel_name = "My Shop Name"

no this.var at all, and no .nw either.

So for all to come, add DB_Shops, and put that in it for each shop.

Ex:
armageddon-shop1_name="Lystra Shop"
for the level armageddon-shop1.nw

coreys
11-13-2009, 03:10 AM
Just a note, if you're using the - character in a variable name, it will only work in instances like this:

this.(@"foo-bar") = "baz";

not this:

this.foo-bar = "baz";


- and other reserved characters are not valid in variable names, but GS2 will compensate for this when using (@"variable-name").