In-game Shops In this tutorial, we will create a fully functional in-game shop, where
the player can use his loot to purchase items. This tutorial is for Thief
2 only. This tutorial assumes that you've already set up a mission, with a working player start, and that Convict and Gen have been loaded. Before we begin, let's consider what we'll need to do set up a working
in-game shop system.
- Counting The Loot - We'll start by creating a system to count the player's gold, as it is gained and spent, in order to keep a running total. This total will be kept in a quest variable, so the first thing to do is to create one. Enter the following line into DromEd's console: quest_create_mis Loot,0 This will create a local (current mission only) quest variable named Loot, and set it to zero. A special Act/React Stimulus will be used to count the loot as it comes into and leaves the player's inventory, so the next thing to do is to create this stim, which should be named 'LootStim'. In order to get the new stim to work, you need to save the gamesys (and set it using the set_gamesys command, if you haven't already), and then save and reload the mission. Next, we need to add the counting system to the loot archetypes. In
a real mission, you would need to apply the system to every single type
of loot, but for this tutorial we will just set up three example items:
Purse (-2609), GoldCoinStack
(-2956), and Tiara (-1976). Now, create a metaproperty under M-LootTypes,
named 'M-Loot025'. This metaproperty will
be given to any piece of loot which is worth 25.
When the player frobs a piece of loot which has this metaproperty, he will be hit by an intensity 25 LootStim. Next, create two more metaproperties under M-LootTypes, and name these 'M-Loot100' and 'M-Loot125'. Give both of them the same properties you added to 'M-Loot025', but change the value of the Dark Gamesys->Loot property, and the intensity of the stimulus, so that they both have appropriate values (that is, 100 and 125, respectively). Make sure that you leave everything inside Dark Gamesys->Loot other than Gold at 0. If you wanted to set up every single type of loot, you would need to create a lot more metaproperties, but these three will serve us for this tutorial. Now to apply these new metaproperties to the loot types. Find Tiara
(-1976) and open its properties. Notice the value of the Dark
Gamesys->Loot property: Gold: 75,
Gems: 50, Art: 0.
Later on, when the player buys something and we need to take some of his
money away, there's no easy way of knowing if the player is carrying Gold,
Gems, or Art, so the simplest thing to do is
to just change all the loot to have its value in Gold only. You also need to add the appropriate metaproperties to the other two
loot items. Give Purse (-2609) M-Loot100
and GoldCoinStack (-2956) M-Loot025.
Don't forget to remove the Dark Gamesys->Loot
property if you see it. The next thing to do is to make something happen when the player is hit
by a LootStim.
Obviously enough, if you want to set things up for every single piece of loot, you would need to add more Receptrons here, but these three are enough for this tutorial. You should now have a working system to count the amount of loot the player is carrying (assuming that the level only contains the three types of loot which we've set up), but you have no way of knowing if it actually works. To find out, create a new archetype under slidy_door
(-1262), and name it BlueRoomDoor.
You'll need it later, anyway.
Now would probably be a good time to save the gamesys. Create a long blue room,
maybe around 12x32x16 in size. Now, create a QuestVarTrigger (-4370) in the blue room (of course, you may want to give some item of furniture elsewhere in the mission the TrigQVar script instead, to save objects...). Add the Trap>Quest Var property, and type in >399:Loot Create a ControlDevice link from the
QuestVarTrigger to the BlueRoomDoor.
Save everything and go into Game Mode. Assuming everything went according to plan, you should now have a working loot-counting system, even if it only works with three types of loot.
- Buying Things Costs You Money - Now, we can move on to the shop itself.
Head over to the place where you want to build your shop, and create
three noisemakers, or rather Noise (-129),
three RopeArrow (-2603), and three water
arrows (not crystals) from the archetype Water (-128). Eventually, we're going to need another new stim, and now would be a
good time to create it. Open the Act/React Stimuli section of the Object
Hierarchy and create a new entry; MiscStim. Now, flip over to the Metaproperties section . To keep things orderly,
create a new one named Shop-Related-M and
move M-LootTypes into it. Open the properties for ForSale-M, and add Engine Features->FrobInfo. Set the World Action to Move, Script. Now, move on to ForSale-M-050, and add the following Act/React Source:
And also add this Act/React Receptron:
Set up the other two metaproperties the same way; hitting anyone who
frobs them with a negative LootStim of the
intensity their name suggests, and removing themselves when they are hit
with an intensity 1 MiscStim. Once you've finished with those three metaproperties, go back to the
Archetypes section of the Object Hierarchy, find Swag
(-1708), and create a new archetype under it named Receipts.
These will be pieces loot with a negative value, forced into the
player's inventory when he purchases objects.
...and this Act/React Receptron:
As soon as one of these Receipts is created, it will be frobbed. This should force it into the player's inventory, although there are some problems with this that will be addressed later. Create three more archetypes under Receipts, and name them Receipt-050, Receipt-200, and Receipt-250. Give each of them a negative Gold value in Dark Gamesys->Loot, as appropriate to their names; Receipt-050 is worth -50 Gold, etc. Also, add these Act/React Receptrons:
Using Add with a negative amount may seem a bit unusual, but please bear
in mind that there is no Subtract option, and also no real need for one. And now, finally, go back to the Metaproperties section and find M-LootReciever. Add three new Act/React Receptrons.
As you can see, any object that gives the player a negative LootStim will be hit with an intensity 2 MiscStim, removing its ForSale-M metaproperty. Other negative intensities of LootStim create the appropriate receipt, thus reducing the player's gold by the cost of the item. More receptrons can be added for additional Receipts, if you need them. And now there are only two things left to do to complete the second part
of the tutorial.
Finally, create a Swag (-1708), and give
it the Dark Gamesys->Loot property. Set
everything inside to 0.
- You Don't Have Enough Gold - Of course, the player shouldn't be able to buy anything when he
doesn't have any money! To make sure that the player can't take objects which are above his price range, we will disallow the player from frobbing them entirely. Create a new metaproperty under Shop-Related-M
and name it CannotBuy-M. Open its properties
and add Engine Features->FrobInfo, leaving
everything set to [None].
You'll also need to give ForSale-M this Receptron:
These stims will be used later to add and remove this metaproperty as the player gains and looses money. Notice how I've given CannotBuy-M an Abort receptron - this is to make sure that it cannot be added to an object more than once, which would make it a nightmare to remove again. At the start of the game, the player shouldn't have any money, and therefore none of the items should be frobbable. Add CannotBuy-M to all nine of the 'for sale' objects. The next thing to do is to set up a system where a projectile fired from
an EmitterTrap hits a different object depending
on how much loot the player is carrying. Arrange these new objects as follows, where the X, Y, and Z values are offsets from the centre of the blue room that contains the objects.
Also, create a Button (-448), name it 'CheckLoot', and give it a ControlDevice link to LootCheckEmit. Having done all of that, find the QuestVarTrigger you created earlier, rename it LootCheck050, and change the Trap>Quest Var property to >49:Loot Now, create two more QuestVarTriggers. Having done all that, one door should open when you have more than 50
loot, another when you have more than 200, and the third when you have
more than 250. Now, open the Object Hierarchy and find Projectile
(-59).
Close the Object Hierarchy, and open the properties for LootCheckEmit. Head back over to the Metaproperties section of the Object Hierarchy, and find M-LootReciever, which now needs one new Receptron:
Assuming that everything went according to plan, a BlueProjectile
should be fired from LootCheckEmit every time the player gains or looses
money (or at least those types of money that have been set up to be counted). We still need to set things up so that the CannotBuy-M metaproperties is added or removed from the items depending on which door or banner is hit. The easiest way to do this involves the creation of a few more metaproperties, so open the appropriate section of the Object Hierarchy. Create a new metaproperty under Shop-Related-M named 'Loot-MoreThan-050', and give it some Act/React Receptrons:
As we have given CannotBuy-M a Receptron to remove itself when it receives an intensity 3 MiscStim, this basically removes that metaproperty from all the water arrows when it gets hit by a BlueProjectile. Now, we need to create another metaproperty under Loot-MoreThan-050, named 'Loot-MoreThan-200'. Give it these receptrons:
And one more metaproperty under that, named 'Loot-MoreThan-250'. This time, the receptrons should stimulate the three 'for sale' noisemaker arrows. You could easily create more metaproperties for items worth different amounts, so long as you keep them in the correct order, each one inheriting from the next cheapest. That way, when a BlueProjectile hits the deepest nested metaproperty, therefore removing CannotBuy-M from the most expensive items in the shop, it will also trigger all the receptrons for the cheaper items, and remove CannotBuy-M from them, too. And now, it's time to add these new metaproperties to the BlueRoomDoors. Save everything and go into game mode. As they become affordable, the 'for sale' items will become frobbable. However, they do not become infrobbable again when the player can no longer afford them, which rather defeats the whole purpose. To fix it, go back to the Metaproperties section of the Object Hierarchy, and create a new metaproperty under Shop-Related-M. Name it 'Loot-LessThan-250', and give it some Act/React Receptrons:
Next, create another metaproperty under it and name this one 'Loot-LessThan-200', giving it the following receptrons:
As you've probably guessed, a final metaproperty, 'Loot-LessThan-050',
should inherit from Loot-LessThan-200, and
its set of receptrons should hit the three
'for sale' water arrows with an intensity 4 MiscStim. Head back to the BlueRoomDoors and give Loot-LessThan-050 to LootDoor-050, Loot-LessThan-200 to LootDoor-200, and Loot-LessThan-250 to LootDoor-250. You should now have a working in-game shop!
- Fixing The Problem - There is still one problem with this system. To find it, go into game
mode and pick up 50 worth of loot. You should end up with two water arrows, and -50 gold in your inventory.
This happens because it takes a few moments for the BlueProjectile
to travel down the blue room,
which means that you can frob a second item before it hits the BlueRoomDoors
and adds CannotBuy-M to the stuff you can't
afford. Find ForSale-M and give it some new Act/React Receptrons:
And now, we need to create a new metaproperty named under Shop-Related-M named M-PatientLootReciever. Drag M-LootReciever inside it, and add this stack of Act/React Receptrons:
Every time the player gets hit by a LootStim,
all the items in the shop should get zapped by an intensity 5 MiscStim,
which should change set all of their Engine Features->FrobInfo
properties so that they cannot be frobbed. One final note: hitting the shop's supply of water arrows with a fire arrow will destroy them, so it would be a really good idea to add give ForSale-M an Abort receptron for FireStim, and you might as well add some more for WaterStim, and WeaponStim, too.
Once again, I have a small mission which demonstrates an in-game shop in action, which you can download here. There are, however, a few minor problems that should be looked into, although they are not essential to the running of the shop. These have been addressed in the following section.
- Belts and Boxes - When we created the loot earlier in this tutorial, I never specified
where to put it, so you probably just dumped it on the floor. But first, we should take a look at the second problem. When the player frobs a box containing a piece of loot, the object is put in his inventory, but, seeing as the player hasn't actually frobbed the item, the LootStim is never sent. What this means is that, while the amount of money the player thinks he has increases, the loot counter does not, and so the money can't be used to buy things. Again, you could just avoid placing loot inside containers, but that's hardly a proper solution. To fix both of these problems, we'll need a new stim named PermeateStim (save gamesys, save mission, reload mission). Next, create a Reciepts somewhere that the
player can never reach it, and name it 'PlusLoot'.
Find Treasure (-224) in the Object Hierarchy
and create a new archetype under it named ContainedLoot.
Now, head over to the Garrett (-2099) archetype and add this receptron:
Create a new metaproperty under Shop-Related-M
named 'M-ContainedLootTypes', and create
another metaproperty under that for each 'contained loot' value you wish
to use - for example, M-'ContainedLoot100',
'M-ContainedLoot125', etc.
Next, you need to decide how much this piece of loot is supposed to
be worth, give it the appropriate meteproperty, for example ContainedLoot125.
(Replace the Intensity with an amount that matches the Loot value of the object.) If you find it a bit repetitve to add this source to every single ContainedLoot, you can create some more archetypes under ContainedLoot for certain oft-used values, but they won't do much good unless you only plan to attach them to someone's belt. Every time the player gets hit by a PermeateStim,
it gets sent to every single item in his inventory. Any pieces of ContainedLoot
in there will recieve the stim and create a special type of loot (based
on PlusLoot) that gets forced into the player's inventory. Unfortunately, there's still a major problem with this this system; if you knock out an AI and then try to pick him up while the 'Auto-search bodies' option is enabled, the ContainedLoot will be put into the player's inventory, but will not hit the player with a PermeateStim. I can only think of two solutions to this problem, one of which is to simply give the Garrett archetype the following Act/React Source:
There are, however, two problems with that solution; firstly, the repeatedly firing stim will slow the whole game down slightly, and secondly, auto-searching a body and then grabbing another piece of loot with a differint value will cause the system to break. Hopefully no one will manage to do that in 500ms... The other method is much more complicated, and requires GayleSaver's
custom scripts to work. stim="PermeateStim";intensity=1.00 Finally, create two links; a ScriptParams link from the ContainedLoot archetype to ContainedLootFixDelay (with a Data of 'InvSelect'), and a ControlDevice link from ContainedLootFix to your starting point. Each time the player grabs some ContainedLoot, the TrapSMTrans will send a ControlDevice 'on' signal to ContainedLootFixDelay, which will wait 10 miliseconds and then activate the TrapStim, which, in turn, will hit the player with a PermeateStim. For some reason, everything goes wrong if you don't put in the 10ms delay... If you added the source described in the first solution to the Garrett archetype, you can remove it again if you use the second method. As you can see, this makes it a lot more hassle to put loot on people's belts and inside containers, but no one said creating an ingame shop was easy... And now, assuming everything went according to plan, you should now have a fully working shop which accepts loot found inside containers, just like this one I made earlier. Well done! |