RPG Maker MV Shops with unique items (Javascript)

RPG Maker MV Shops with unique items (Javascript) 1 - steamsplay.com
RPG Maker MV Shops with unique items (Javascript) 1 - steamsplay.com

Did you ever want to have the player be able to buy an item from a shop only once? With this newbie-friendly guide we will learn how to make this possible. Not only will the player be unable to buy the same item twice, the item will not even show in the shop anymore!
 
 

Introduction

If you’re like me, sometimes you want to have single-use items in your shops. For example, a book the player can buy, but only once. However, to do that with the pseudocode, you would require to check if the player has the item, and then make a new shop without that item. Or you would do it by choices, but again, it’s just not the same as a shop…
 
 
Well you’re at the right place. In this guide we will create a single shop which will contain both single-use items and multiple-use items, and have the player only be able to buy the single-use items once, and even make them disappear the next time the shop opens up.
 
 
We will have to dig into the JS files for this, but I will make it as simple as possible for newbies too.
 
 
 

How will this work exactly?

Before we start working, we should note how exactly this is going to work: what’s the logic behind it.
 
 
1. In the beginning of the game, we will make an empty list and store it.
 
2. When setting up an item in the database, we will add a “<single use>” note.
 
3. When the player buys the item, if that item is “<single use>” its ID will be added in that list.
 
4. If that item is “<single use>” the max possible items will be 1.
 
5. If that item is “<single use>” and its ID is inside that list, it means we have already bought it, so don’t add it when opening up the shop.
 
 
That’s pretty much it!
 
 
 

1. Make an empty list and store it

So, for all people who have some coding experience, when I say “list” I mean, in fact, an array. However, we will need to make that array somewhere that will get stored between saves.
 
 
A quick glance at rpg_managers.js will reveal to us the DataManager.makaSaveContents function, which is responsible for, well, making the contents of a saved game. From that, we can see that the object $gamePlayer gets saved and loaded from saved games. Therefore, we are going to use that one.
 
 
Most of you are already starting the game with an Autorun event, which is used to initialize all game-related variables and switches. If you aren’t, then add an Autorun event in the first screen, add a “set self-switch A to ON” command, and then another page whose condition is that self-switch A, and the trigger condition is “action”. This way we have added an event that will only run once.
 
 
Inside this event, add a script command and type this.
 
 

$gamePlayer.singleUseItemIDs = [];

 
 
That’s it, we’ve created our empty list. This list will now remain forever and all its changes will follow between saves too.
 
 
 

2. Setup items in the database, setup first shop

This will work by utilizing the notes from the items in the database. This is really simple, as we can make an item, and then just add “<single use>” in its note.
 
 
So go ahead, change the healing potion’s price to 0 so we can easily buy it, and add “<single use>” in its note. Now make an event that opens up a shop that contains this item, along with any other items, to test it out.
 
 
You can do this with as many items as you want, wherever they are in the database.
 
 
So test that the shop opens up and contains those items. At the moment that note does nothing, but we will make it do something in the next steps.
 
 
 

3. Add ids to our list

Now we have to get into JS. Open up rpg_scenes.js, located in gameFolder/js
 
 
Inside it, find the function
 

Scene_Shop.prototype.doBuy

 
 
You will notice that this function goes as so:
 
 

Scene_Shop.prototype.doBuy = function(number) {
 $gameParty.loseGold(number * this.buyingPrice());
 $gameParty.gainItem(this._item, number);
};

 
 
Now, let’s make it add the item’s id in the list!
 
 

Scene_Shop.prototype.doBuy = function(number) {
 $gameParty.loseGold(number * this.buyingPrice());
 $gameParty.gainItem(this._item, number);
 //edit starts
 $gamePlayer.singleUseItemIDs.push(this._item.id);
 //edit ends
};

 
 
Note that I added
 

//edit

 
starts and ends to show a point that I have edited. My advice is to always do that, so you always know what you have edited.
 
 
Ok, so we did that, what does that do? This will add the ID of any bought item to our ID list. But we only want the “<single use>” items to be added, right? So let’s add a condition then:
 
 

Scene_Shop.prototype.doBuy = function(number) {
 $gameParty.loseGold(number * this.buyingPrice());
 $gameParty.gainItem(this._item, number);
 //edit starts
 if(this._item.note.indexOf('<single use>') > -1) {
 $gamePlayer.singleUseItemIDs.push(this._item.id);
 }
 //edit ends
};

 
 
To explain this a bit more, “this._item” is the item object, “this._item.note” is its note. Therefore, this._item.note.indexOf(‘<single use>’) will return -1 if that precise phrase is not found in its note, and its index if it’s found. Its index will be a number above -1. So in this way, we are checking if the item’s note contains that phrase, and then add its id in our list if it does.
 
 
So now our list will contain the ID of a bought item if that item is single use!
 
 
 

4. If that item is “<single use>” the max possible items will be 1.

In the rpg_scenes.js file we can see the function
 

Scene_Shop.prototype.maxBuy

 
. In this function, we will notice the line
 

var max = $gameParty.maxItems(this._item) - $gameParty.numItems(this._item);

 
 
Therefore, we will need to find this $gameParty.maxItems function. Let’s open up the file rpg_objects.js next.
 
 
Locate the function
 

 Game_Party.prototype.maxItems 

 
, it should look like this:
 
 

Game_Party.prototype.maxItems = function (item) {
 return 99;
};

 
 
So as we can see it takes an item as an argument. We want to see if that item is a single use item right? So let’s do as we did before:
 
 

Game_Party.prototype.maxItems = function (item) {
 if (item.note.indexOf('<single use>') > -1) return 1;
 else return 99;
 };

 
 
Now let’s test our test shop. You should be able to only buy one healing potion – in general only one item of any item that has the “<single use>” note. However, we’re not done yet. We also want to make sure that this item will never appear in that shop again. So onto our next step!
 
 
 

5. Remove a bought “<single use>” item from the shop

Since the player has bought the item already, it means that this item’s id has been added to our list. Therefore we only have to check if our list has that id when the shop opens up. But where is that function?
 
 
Last step, I promise. Open up rpg_windows.js
 
 
Here, we can locate “Window_ShopBuy”, which is the window that shows the items that you can buy. It also has other functionalities, but we only care about that. Do you see the point where it initializes?
 
 


Window_ShopBuy.prototype.initialize = function(x, y, height, shopGoods) {
var width = this.windowWidth();
Window_Selectable.prototype.initialize.call(this, x, y, width, height);
this._shopGoods = shopGoods;
this._money = 0;
this.refresh();
this.select(0);
};

 
 
You see that “shopGoods” ? That’s what contains the information of the items that will be shown in the shop. This is a list of arrays, and the second place of each array ([1]) holds the id of the item! Since we can get that id, then we can easily see if that’s contained in our list and remove it from the shop!
 
 
To do this, we will have to check that entire array. Let’s create a for loop to do just that:
 
 



for (let i = 0; i < shopGoods.length; i++) {
let id = shopGoods[i][1];
}

 
 
So now we have that id. In order to check if that id is in our list of ids, we can do:
 
 


for (let i = 0; i < shopGoods.length; i++) {
let id = shopGoods[i][1];
if($gamePlayer.singleUseItemIDs.includes(id)) {}
}

 
 
and now we’re checking if that id is in our list. So what’s next, is to remove that item from the shop, by removing that entry from that list.
 
 


for (let i = 0; i < shopGoods.length; i++) {
let id = shopGoods[i][1];
if($gamePlayer.singleUseItemIDs.includes(id)) {
shopGoods.splice(i, 1);
}
}

 
 
With the “splice” function, we are removing 1 entry from position i (which is the position that it found that entry). However, now the array we’re checking is 1 element smaller, therefore it’s as if we “jumped” one element ahead. We can fix that by moving the index backwards once:
 
 


for (let i = 0; i < shopGoods.length; i++) {
let id = shopGoods[i][1];
if($gamePlayer.singleUseItemIDs.includes(id)) {
shopGoods.splice(i, 1);
i--;
}
}

 
 
And there you have it! Now let’s add this in the function:
 
 


Window_ShopBuy.prototype.initialize = function(x, y, height, shopGoods) {
var width = this.windowWidth();
Window_Selectable.prototype.initialize.call(this, x, y, width, height);
// EDIT START
for (let i = 0; i < shopGoods.length; i++) {
let id = shopGoods[i][1];
if($gamePlayer.singleUseItemIDs.includes(id)) {
shopGoods.splice(i, 1);
i--;
}
}
// EDIT END
this._shopGoods = shopGoods;
this._money = 0;
this.refresh();
this.select(0);
};

 
 
Now let’s test our shop. Buy a single use item, test that you can only buy one of them. Then go back and see if it still exists in there. Then use that item, and go back to the shop and check if it’s there now.
 
 
If these tests are passed, then we’re done. Now you can create any single use item and include it in your shops without worrying with the pseudocode. Just add the “<single use>” note, and add that item in any shop you want!
 
 
 

TL;DR (Quick Reference)

1 – > Add Autorun event
 
Turn self-switch A ON
 
Script:
 

$gamePlayer.singleUseItemIDs = [];

 
Second page of event, empty, conditions – > self-switch A, trigger: action
 
 
2 – > Add “<single use>” note to “Healing Potion”
 
 
3 – > Make a shop with “Healing Potion” (and any other items)
 
 
4 – > Open up rpg_scenes.js
 
Edit function
 

 Scene_Shop.prototype.doBuy 

 
 
to this:
 

Scene_Shop.prototype.doBuy = function(number) {
 $gameParty.loseGold(number * this.buyingPrice());
 $gameParty.gainItem(this._item, number);
 if (this._item.note.indexOf('<single use>') > -1) {
 $gamePlayer.singleUseItemIDs.push(this._item.id);
 }
};

 
 
5 – > Open up rpg_objects.js
 
Edit function
 

Game_Party.prototype.maxItems 

 
 
to this:
 

Game_Party.prototype.maxItems = function(item) {
 if (item.note.indexOf('<single use>') > -1) return 1;
 else return 99;
};

 
 
6 – > Open up rpg_windows.js
 
Edit function
 

Window_ShopBuy.prototype.initialize 

 
 
to this:
 


Window_ShopBuy.prototype.initialize = function(x, y, height, shopGoods) {
var width = this.windowWidth();
Window_Selectable.prototype.initialize.call(this, x, y, width, height);
// EDIT START
for (let i = 0; i < shopGoods.length; i++) {
let id = shopGoods[i][1];
if ($gamePlayer.singleUseItemIDs.includes(id)) {
shopGoods.splice(i, 1);
i--;
}
}
// EDIT END
this._shopGoods = shopGoods;
this._money = 0;
this.refresh();
this.select(0);

};

 
 
7 – > Test
 
 
 

Final Thoughts

I made this guide a bit hastily, but I did test everything I said in here in a new project, and it all worked for me. Even between saves and even when the item is consumed.
 
 
For Weapons and Armors you would perhaps need to dig in a bit more, since this is specific for Items.
 
 
Note that this might clash with other plugins that alter these functions. It might not work if the functions are being written over, without their previous versions being called. To fix that, you can go into that plugin that re-writes them, and add the necessary commands in there.
 
 
Have fun!
 
 
PS: I will see if I have written anything silly when I come back, because I have to go now. Let me hear your thoughts!
 
 

Written by MAKAIROSI

 
 
Hope you enjoy the post for RPG Maker MV Shops with unique items (Javascript), If you think we should update the post or something is wrong please let us know via comment and we will fix it how fast as possible! Thank you and have a great day!
 


Be the first to comment

Leave a Reply

Your email address will not be published.


*