EFUPW Forums

Main Forums => Suggestions => Player Workshop => Topic started by: Kotenku on November 17, 2015, 07:44:10 AM

Title: Sanctuary Stock Exchange, Dynamic crafting pricing system.
Post by: Kotenku on November 17, 2015, 07:44:10 AM
The way potion brewing works in EFU is that potions have a fixed price determined by a bit of code in game. Prices can be manually adjusted up or down by DMs as needed, but have been more or less static for the last ten years. That's fair enough, the DMs have it balanced to what they feel is the sweet spot for cost/reward.

I don't think there's anything inherently wrong with the way it works right now, however, I propose that potion brewing, which is a reasonably stable and (let's face it) boring source of income for so-inclined-characters, could be implemented in a better way, which could add meaningfully to the setting's narrative, introduce a more dynamic economy, and allow the DMs to just as easily (or more easily) adjust the balance as they desire.

What I'm proposing boils down to a fluctuating economy, where brewed potions will fluctuate in price according to the following equation. If any of this is unclear, just be patient, I'll provide examples afterward.

CurrentPrice + kPS(sin(Q)) where:
k is some constant value determined by the DMs reflecting the amplitude of fluctuation
S is the level of the spell being brewed into a potion
P is a secret floating point variable which represents the stability of the market. A value of zero means that prices will remain fixed at their base rate, a value of 1 means they will fluctuate by as much as K at each adjustment.
Q is the random seed of the equation, and would typically be some function of the server's internal clock at a particular moment in time when prices are recalculated.

Outside the equation there are some further important elements to consider:

1) Maximum and Minimum boundaries for potion prices. These would be expressed as base price plus or minus some nkS where n is an integer multiplier, applied to the constant factor and spell level of a given potion.

2) The minimum interval before prices are recalculated again. Potion prices would (I think!) necessarily have to be calculated when the module loads. This could be hourly or daily (meaning in practice, every time the server resets), or every few days, or every few weeks, or months. It could even be just whenever a DM decides to let the prices adjust. I think every ten days would probably be the best bet, but that number is completely arbitrary.

---

As an example, I generated the following graph with the following data:

Base Cost = 60gp
Spell level = 2
P = 1.1 ( economy should fluctuate slightly more than normally )
n = 1.2 ( Constant multiplier to determine minimum and maximum prices )
k = 5 ( Constant to determine absolute value of variance of prices )
Q = a set of pseudo random values between 0 and 100


Effectively, these numbers mean that a Potion of Blur (which is brewed at 60gp before cost of bottles and experience) will be brewed for between 48 and 72 GP.

[ATTACH=CONFIG]n649302[/ATTACH]

in the graph, the orange line represents actual prices in game with boundaries in effect. What you'll see is that when prices dip too high or low, the line will flatten out until the 'hidden' price starts adjusting back in the other direction.

Now, these numbers certainly shouldn't represent a final product. The formula definitely needs work, as the variance in price on a third level potion would be even greater. It would be reasonable to express concern over potions of blur being brewed for 48 GP. It would be very straightforward to have the minimum and maximum boundaries be adjusted separately. For example, if the minimum boundary were at (.5 * nkS) and the maximum boundary at (2*nkS), you would instead have a minimum cost of 54GP and a maximum cost of 84GP. This would raise the average cost of the potion, and isn't particularly recommended.

---

There are a few other ways this could be implemented, and I'll endeavour to list the advantages and disadvantages of each.

* As written above, the implementation would require the scripter to use a NWNX database to store the current price of each potion, as this is what the next price of each potion will be based on.

* Instead of setting the price of a potion based on historical values, the prices could be determined from only the base price. With this implementation, prices would necessarily have to be adjusted every time the module loads, would be more random, and would make the prediction of prices impossible. This would effectively defeat the purpose of the system, which hopes to create a "realistic" economy that could give rise to new avenues of financial roleplay and manipulation, such as speculation and investment (buying or brewing potions when they're cheap, selling them when they're expensive, undercutting rival merchants, etc...)
The upshot is that this would be a lot easier to implement, and would not require that much extra work for somebody who knows their way around NWNX and EFU's database back-end to alter into the above-outlined implementation.

---

There are some important considerations that whoever implements this system would have to decide:

1) Will all potions be priced individually, or will potion prices be adjusted up or down by some constant factor? (eg potions of blur and strength both costing 60+13 gp to brew, vs potions of blur at 60+15gp and potions of strength at 60-2gp)

2) What would be the most reasonable minimum and maximum boundaries for brewing cost?

3) Should this pricing system be extended to other crafting systems (ie Wands and Scrolls)?

4) How frequently should prices be updated?

5) What other features should be implemented to make this more user friendly? An IG tool to adjust values on the fly? Handlers for Alchemical items or perks which flatly decrese (or increase!) the cost of brewing?

---

What I envision for this system is for it to create a new dynamic marketplace, where effort corresponds to reward, - compare the diligent brewer who adjusts her prices every week with the lazy one who sets a constant price and never adjusts. A market place where the only people who can know for sure what a fair price for a potion is are those capable of brewing them. (Fighters no longer able to dicker down the price by saying "I know it only costs you 60GP to brew that, sell it to me cheaper").

I've generated an Excel Spreadsheet in which interested people can toy around with the numbers to see if they can come up with a set of parameters that create an ideal distribution of prices. Keeping in mind that prices SHOULD be random, and that going below the current base price is desirable, as long as prices over the long term average out to be approximately the same as base costs are now.

If you're interested, you can grab it from the attachment below. (I solemnly swear it isn't a virus. <3)

I can't say that I will have the time in the near future to script this system. However, when free time returns to me, if there's enough interest in the system I've described here, I may be willing to put it together. In the meantime, please let me know what you think, request features, make suggestions, criticize my maths, forecast doom or point out some potential problems and solutions. The key here is constructive criticism.

Thanks :)
Title:
Post by: Random_White_Guy on November 17, 2015, 08:08:11 AM
Doing god's work you mad bastard. Potion cost driven down by people demanding lowest prices through dickering has always been irksome.
Title:
Post by: Pentaxius on November 17, 2015, 01:22:56 PM
Excellent.

I would add the two following additions :

A scaling variable D which captures the PC's commercial acumen (based on appraise) and will influence his own costs of brewing to a slight degree.
A noise parameter F on a per PC basis, to allow for slight fluctuations in prices between PCs on top of the barter modifier.

from an RP perspective, consider D to be the brewer's skill in acquiring components at a reasonable price, and F to be the brewer's luck in finding the right suppliers at the right time given market prices.
Title:
Post by: Hound on November 17, 2015, 02:17:46 PM
I think appraise should be incorporated as a value reducing the expense of any given potion by a percentage equal to the appraise check. Or perhaps half the check, since that could be too powerful. 0.5% reduction to each appraise point? This would mean that wizards and bards take an advantage in their brewing costs - clerics and druids don't have appraise as a class skill, and don't usually have the skill points spare to dump into it as CC either. This boon will mostly benefit bards, who often tend to have a higher supply expenditure than the other brewing classes anyway.
Title:
Post by: Kotenku on December 19, 2015, 01:06:27 PM
I've formalized and re-written the original proposal for a class project, and updated the spreadsheet I used to create simulations. I've attached them both here, and I mean to start working on this some time in the next week or so, holidays permitting..


https://www.dropbox.com/s/dl85ttq4068zcrj/NWN%20Stock%20Market.pdf?dl=0 <-- PDF of formalized proposal

https://www.dropbox.com/s/dl85ttq4068zcrj/NWN%20Stock%20Market.pdf?dl=0 <-- .,xlsx file for running simulations.

 
Title:
Post by: Howlando on March 21, 2016, 07:01:55 PM
For the record, if anyone is interested in actually implementing this I would not mind.
Title:
Post by: Rocinante on March 23, 2016, 06:51:21 AM
Definitely sounds very cool for sure
Title:
Post by: Kotenku on May 16, 2016, 05:17:17 AM
Summer is here and I've started work on this.  If anybody can provide me with a list of brewable potions associated with their base (or max) crafting costs, that would be extremely handy.

Thanks!
Title:
Post by: VanillaPudding on May 16, 2016, 05:34:01 AM
FOIG
Title:
Post by: Rocinante on May 18, 2016, 12:16:54 AM
I think in the case of an OOC project FOIG isn't necessary.
Title:
Post by: EventHorizon on August 25, 2016, 07:25:03 AM
I'm glad Howlando digs this. And holy hell, nice work, Kotenku. Do you want to make this a ssuuuuuuuuuuper RP opportunity, and RP a character revolutionizing potionsbrewing, or would you prefer to dive fully into the academic, RL experiment potential for this? If the former, I'd say FOIG! If the latter, I'd say nothing because I don't really have the authority or knowledge, other than that's admirable as all hell.
Title:
Post by: Kotenku on October 11, 2016, 01:47:07 AM
To perhaps no one's surprise, it's unlikely that I will ever finish this. In the hopes that some other naive soul takes up the mantle, I bequeath until you all the work I completed before other responsibilities got in the way.

This work is based on the Avilis Persistence System. The database calls are non-functional, but should be straightforward to fix for somebody with the know-how.

Code: [Select]
#include "aps_include"
#include "kot_market"
// This is a function intended to be called by an object in the game world, which will print out
// the first and last DB entries to plain text for debugging. As the database end never worked,
// this bit was never proven to work either.

void main()
{
    SQLExecDirect("SELECT * FROM market_potions WHERE id = 1");
    SQLFetch();
    SpeakString("nCurrPrice of Aid = " + SQLGetData(4));

    SQLExecDirect("SELECT * FROM market_potions WHERE id = 882");
    SQLFetch();
    SpeakString("nCurrPrice of Whispering_Wind = " + SQLGetData(4));

}

[code]
import java.io.*;
import java.util.*;
import java.io.IOException;
import java.text.*;

public class main {
    public static void main(String args[]) throws IOException{
       
            Scanner scan = new Scanner (new FileReader("brews.txt"));
           
            while(scan.hasNextLine()) {
                String ID = scan.next();
                String name = scan.next();
                scan.nextLine();


//The Generator for 'InitializeMarket', uncomment to use.
/*                System.out.print("nID = " + ID + ";        // " + name  + "\n    "
                        + "sLabel = Get2DAString(\"spells.2da\", \"Label\", nID);\n  "
                        + "  nInnate = StringToInt(Get2DAString(\"spells.2da\