ID:152470
 
I'm trying to come up with an algorithm for a reputation system, that will affect the shop prices in-game.

The way I want it like the following:

0 rep = Double shop prices.

5,000 rep = Normal shop prices.

20,000 rep = Half shop prices.


The only way I could do this is in chunks, however I would prefer a formula for it.

I appreciate any help, Comz.
Use a proc. I don't think you could use an equation for dat. D:

mob/proc/Rep2Price(reputation, item)
switch(reputation)
if(0 to 4999)
return item.highcost

else if(5000 to 19999)
return item.normalcost

else if(20000 to 30**30) // 20000 to infinite >.>
return item.lowcost

In response to DivineO'peanut
Eww, no no no, no 'else' in switch statements (not even 'else if') unless the else will end that switch().. otherwise the switch() will think that where 'else' shows up is the last choice (if you don't believe me, try playing with the following code)
mob/verb/Try_This()
var/n=input("Pick a number") in list(1,2,3)
switch(n)
if(1) world<<"You picked 1. Congrats!"
else if(2) world<<"You picked 2.[n==2?"":" Actually you didn't, see what 'else if' did? If you didn't, try taking the 'else' out of 'else if' on the switch #2 line. Else, even in else if, ends the switch choices, meaning that all the choices before happens but after the else doesn't"]"
else if(3) world<<"You picked 3... this really should be 'else'..."


Besides, wouldn't it be easier to have something like this on the purchase proc (if you don''t have a Generalized Buying/Selling proc/system, I recommand you do one):
value*=rep<5000 ? 2 : rep>20000 ? 0.5 : 1


Expression ? IfTrue : IfFalse (basically a compacted if(Expression) {IfTrue}else{IfFalse};

rep<5000 ? 2 <-- if rep < 5000, price is doubles (value*2)
: <- else
rep>20000 ? 0.5 <-- if rep > 20k, price is cut in half (value * 0.5)
:
1 <-- if rep 5k-20k, price stays at normal value (value*1)

mob/verb/Try_This()
var/val=1,rrep=input("Pick a number") as num
val*=rrep<5000 ? 2 : rrep>20000 ? 0.5 : 1
world<<val
(This will show the multiplcation of the value according to the rrep you entered (val->value, rrep=rep).

- GhostAnime - >_>'

Example of a REALLY small general selling system:
mob/proc/Buy(obj/I)
if(!I) CRASH("No item has been defined!")
if(!I.value||I.value<0) src<<"Sorry but I can't sell this to you, It's priceless" //!I.value checks if I.value is FALSE (such as 0) and for safety purposes, also checks if it's less than 0.. for the heck of it
var/val=I.value //temp. stores the value of the item.
val*=rep<5000?2:rep>20000?0.5:1 //does the lil' reputation thing you wanted
if((input("Do you want to buy [I.name] for [val]?") as null|anything in list("Yes","No"))!="Yes")return //stops code if choice is not Yes
if(src.money<val){src<<"You can not afford this!";return}//reason why this is here is if the usr drops the money during the input, this would catch it... safety check, ya know.
src.money-=val
new I.type(src)//eh I forgot if 'new I.type' would directly like this...
In response to GhostAnime
GhostAnime wrote:
Eww, no no no, no 'else' in switch statements (not even 'else if') unless the else will end that switch().. otherwise the switch() will think that where 'else' shows up is the last choice (if you don't believe me, try playing with the following code)
mob/verb/Try_This()
> var/n=input("Pick a number") in list(1,2,3)
> switch(n)
> if(1) world<<"You picked 1. Congrats!"
> else if(2) world<<"You picked 2.[n==2?"":" Actually you didn't, see what 'else if' did? If you didn't, try taking the 'else' out of 'else if' on the switch #2 line. Else, even in else if, ends the switch choices, meaning that all the choices before happens but after the else doesn't"]"
> else if(3) world<<"You picked 3... this really should be 'else'..."


Sometimes I feel dum. =(
Thanks for the fix!

Besides, wouldn't it be easier to have something like this on the purchase proc (if you don''t have a Generalized Buying/Selling proc/system, I recommand you do one): (...)

The ? method is very un-readable and hard to edit.
In response to DivineO'peanut
Hn, well that's true about hard to understand at first, but once you're used to it ... anyways, there's no one way for a person to code, it was all part of an example... meaning that the person could make it in a totally different way. There's no set way to do something... most of the time. Anyways, I will translate that piece of part to something a bit more readable >_>

Translation from:
val*=rrep<5000 ? 2 : rrep>20000 ? 0.5 : 1

is:
if(rrep < 5000) //rrep<5000 ? 
val*=2 //value is multiplied by two - that's what the 2 was there
else // :
if(rrep > 20000)//rrep>20000 ?
val*=0.5 // 0.5
else // :
val*=// 1


And don't worry about the else if thing in your post, I didn't know about it until something didn't worked right in one of my old projects. In other words, you are not (totally) dumb <_<

- GhostAnime - Learned something new today? ;)
In response to GhostAnime
I don't think any of you quite understand what he wants. From what I can gather, he would like a formula that will work for any amount of reputation. For example:-

Reputation Value
5000 100
5054 99
4900 110
3561 135
2124 139
10000 75
20000 50

Basicly, the amount will be incremental, and not adjusted at a set amount of reputation such as 4000 to 5000. A small difference in reputation would have a proportional effect on the value. I hope this is clear and understand this, as with regards to the actuall formula, I have no idea.

(Supaz)
In response to Supanova
This should probably be in the Developer how to section, as it's not really code you are looking for

it sound like you want at 0 rep the cost to be 150%, at 5000 rep the cost to be 100%, and at 20000 rep the cost to be 50%. You make it tougher since the spread is uneven. It would be easier if the middle mark was 10000 rep.

you'll need 2 equations. one for from 0 to 5000 rep. the other for 5001 to 20000 rep.

the first half you'd need to break down 150% - 100% (or 50) across 5000. this means for each point of rep (up to 5000) you increase the price by 0.01% (50/5000)
price += price * (rep * 0.01)

for the second half (or 5001 to 20000) you have to break down 100%-50% (or 50) across 14999 (5001 - 20000). This means for each point of rep you decrease the price by 0.0033 (50/15000 [forget that 1 extra point])
price -= price * (rep * 0.0033)

you will need to do you own if's for over or under rep of 5000

[EDIT] - made a bit of a mistake... With the 0-5000 rep, you need to reverse the equation a bit...

price += price * ((5000 - rep)*0.01)

This way at 0 rep, you'll get the 150% markup, and at 5000 rep you'll get 0% markup.
In response to Supanova
If he wanted that, he would have stated that. I think he said that those are the exact guidelines and proportions to popularity he wants.
I'm not sure if i can come up with a formula that hits those marks precisely off the bat, but it looks like you want a formula where the gains drop off the more the value increases - that is, going from 20 000 to 30 000 doesn't get you paying as much less as going from 10 000 to 20 000 did.

Something like 2/(f(n)) (Where f(n) is some linear function of n, your reputation) fits the bill, I think. It can be tweaked so that the function decreases appropriately with increasing reputation, it never hits zero, and it can be set up so that negative reputations are possible.

With the numbers you've handed out, f(n)=(n/5000)+1 would hit the 5000 rep and 0 rep values, although negative reputation should be disallowed in that case. Unfortunately, it also puts 'half shop prices' at 15000 rep, not 20000. It might be able to be tweaked in such a way that you can hit all your targets - probably by making f(n) some sort of exponential formula - but it's probably easier to just change your targets.

Of course, the problem with that is that shop prices can be decreased indefinitely. And while the value will never hit 0, rounding errors will soon have shopkeepers selling items to the most reputable characters for free. I'd suggest limiting the gains from reputation so that that can't happen. Also, you have to be careful about the lower limit of reputation - it absolutely needs to be enforced. If you took my example and gave someone a reputation of -10001, shopkeepers would sell them items for -lots of money, and I'm sure you don't want players getting ridiculous amounts of money for buying stuff off of shopkeepers.
In response to CaptFalcon33035
If he wanted that, he would have stated that.

You mean like this?:

"The only way I could do this is in chunks, however I would prefer a formula for it."

;)
In response to Jp
Yeah, but that could mean several different things. I was wrong to post what I did, about the possibility of supernova being wrong. I did not read that last part of text, but he could have been. He could also just want a formula giving you one of the three prices. Otherwise, why would he list them?
In response to Jp
From the numbers he's given us, his sequence is quadratic.

For any quadratic sequence, A + d(n-1) + 1/2c(n-1)(n-2) is the nth term.

Where A is the first term, d is the first difference and c is the second difference.

Terms - 0, 5000, 20000
First differences - 5000, 15000
Second differences - 10000

A = 0 (from 0, 5000, 20000)
d = 5000 (5000-0)
c = 10000

nth term = 0 + 5000(n-1) + 1/2*10000(n-1)(n-2)
= 5000n - 5000 + 5000(n^2 - 3n + 2)
= 5000n^2 - 15000n + 5000n + 10000 - 5000
= 5000n^2 - 10000n + 5000

I don't know what use this will be though.
In response to CaptFalcon33035
CaptFalcon33035 wrote:
If he wanted that, he would have stated that. I think he said that those are the exact guidelines and proportions to popularity he wants.

Well, first off, it was me who asked dice if he knew of a way to do this.

Secondly, if you read my post properly, the 3 original numbers are in there, after reading a few posts, it was clear that there was insufficient information to the problem, so I had to post more numbers to give a better idea of what was needed. The reason for those 3 numbers being used originally were the way we were hoping to have the formula work.

Trying to do this in 1 formula, isn't impossible but certianly a lot more difficult than if it were done with 2, and Jik's response is simple and effective. Obviously negative rep and rep over 20000 is easy to stop, so as not to have huge prices, or even having free items.

Sorry for not having made things clear.

(Supaz)

It sounds to me like what you really want a logarithmic system, one where neutral reputation is 0 and it can go positive or negative from there.

First you need some kind of function to convert your reputation to a range of -1 to 1. The further you get from 0, the closer you'll approach this limit.

x2 = 2 ** (x/k)
z = (x2 - 1) / (1 + x2)

Now, z will be close to 1 when you have high positive reputation, close to -1 when it's very negative.

price = base_price / 2**z

Of course, chances are price differences based on reputation would come out more in haggling, and in shopkeepers not letting known troublemakers in their stores.

Lummox JR
Ok, I have it figured out now. After a while of racking my brain I got it. So here it is:

    if(usr.rep<=4999)               //For reps below 5000
var/f = 5000-usr.rep
var/g = f*0.02
var/h = round((orig_cost/100)*g)
var/i = orig_cost+h
usr<< "The new cost due to your rep is [i]"
return


if(usr.rep==5000) //Bang on 5000
usr<< "The new cost due to your rep is [orig_cost]"
return


if(usr.rep>=5001) //Over 5000
var/f = 5000-usr.rep
var/g = f*0.003333
var/h = round((orig_cost/100)*g)
var/i = orig_cost+h
usr<< "The new cost due to your rep is [i]"
return


The code above is taken from a small demo I made to test it out.

Now, let me explain what it does a bit more clearly. You start off with 5000 rep, thus paying normal shop prices. Depending on what you do your rep will change after that.

If your rep is under 5000 items will cost more, when it hits 0 you pay double. If your rep is over 5000 items will cost less, when it hits 20000 you pay half.

After testing I seen that it works fine, apart from the odd extra point being added with high numbers due to the round()proc.

So what do you think? Decent enough?