Creating a steal function (Solved, i think)

// feels a bit like an idoit, somehow my command function had been classified as an object rather than a command pattern)
I'm sure this has been tried many times before, but I'd like to make a steal command, the basic premise is to move items from an NPC to the players inventory

There are two major problems I have run across, the first is having the item that are stealable on the NPC's object makes them impossible to see, The two ways I see of solving this logically(If not narritvly) are using a function to list the contents of the npc, or making the npcs a transparent container.
An aside to this is I'd rather have the items appear JUST when the npc is looked at rather than be put in the places and things section of the room

The second problem I come across is actually moving the object from one to another dynamically, I've thought of putting a script on as an attribute on the npc similarly to a search function, with passing it giving the player the items . Is this the best way to do it?

I think i'm messing up the Steal command... it doesn't' seem to register, not even getting the debug text line.
(Command) Steal from #object#

The script its supposed to run
msg ("Steal enable")
if (HasScript(object "steal")) {
  do (object, "steal")
}


Why don't you just explain what the NPC is carrying in the narrative? You don't have to reply on the auto-generated objects and exits.

The best way to move object is to use the move script.


You could make it easy and create a "Global Command" and a "Function" if you want. A global command so the action can be called upon anytime, and the function so that as your game grows you can add to the function and call upon it without having to update every npc.

NPC
Attribute Add
steal
set to boolean False or True

Command Pattern
steal;thief;pillage;gank etc
Name: Stealing
Script

if (obj.steal=True) {
StealFunction
}
else {
msg ("You cannot steal from this NPC") 
}

StealFunction
Return Type: None
Parameters: Leave Blank
Script

if (RandomChance(50)) {
msg ("You tried to steal something but unfortunately you didn't! Oh noes! Egads!")
}
else {
if (RandomChance(25)) {
  msg ("You stole insert item here")
  MoveObject (precious diamond, player)
  }
else if (RandomChance(25)) {
  msg ("You swiped some gold!")
  player.gold = player.gold + 5
  }
 else {
 msg ("You tried to steal something but failed this time.")
  }
}

I'm not 100% sure this will work, but it should give you a good start. A good programmer could correct any mistakes I've made :)

Hope it helps!

Anonynn.


Why do you have a fail for both the first condition, and the last? If you don't fail (randomchance 50) then all the else statements should be success of some sort.


I think it works properly (though it could probably be done a bit more concisely/efficiently in terms of code design):

if (RandomChance(50)) {
  msg ("You tried to steal something but unfortunately you didn't! Oh noes! Egads!")
} else {
  if (RandomChance(25)) {
    msg ("You stole insert item here")
    MoveObject (precious diamond, player)
  } else if (RandomChance(25)) {
    msg ("You swiped some gold!")
    player.gold = player.gold + 5
  } else {
    msg ("You tried to steal something but failed this time.")
  }
}

HK edit: this is incorrect ---> slightly more concise/efficient, I think:

HK edit: err.. I'm having trouble (as you can see below, my code isn't any better) ... or maybe there's just no way to reduce it to a single 'fail' message, meh... lol

if (RandomChance(50)) {
  if (RandomChance(25)) {
    msg ("You stole insert item here")
    MoveObject (precious diamond, player)
  } else if (RandomChance(25)) {
    msg ("You swiped some gold!")
    player.gold = player.gold + 5
  } else {
    msg ("You tried to steal something but unfortunately you didn't! Oh noes! Egads!")
  }
} else {
  msg ("You tried to steal something but unfortunately you didn't! Oh noes! Egads!")
}

not sure if this is actually better...

(actually, this is VERY DIFFERENT... my bad)

if (RandomChance(50) and RandomChance(25)) {
  msg ("You stole insert item here")
  MoveObject (precious diamond, player)
} else if (RandomChance(50) and RandomChance(25)) {
  msg ("You swiped some gold!")
  player.gold = player.gold + 5
} else {
  msg ("You tried to steal something but unfortunately you didn't! Oh noes! Egads!")
}

maybe this way, lol:

(I'm sure this is more concise, but not sure in terms of its actual efficiency/performance/operations, but if there's a way to make it so, this is it, as far as I can deduce, lol)

boolean_variable = RandomChance (50)
if (boolean_variable and RandomChance(25)) {
  msg ("You stole insert item here")
  MoveObject (precious diamond, player)
} else if (boolean_variable and RandomChance(25)) {
  msg ("You swiped some gold!")
  player.gold = player.gold + 5
} else {
  msg ("You tried to steal something but unfortunately you didn't! Oh noes! Egads!")
}

Don't use boolean in this code. that's an on/off switch.

This:

if (RandomChance(50))
{
}
else msg ("You didn't get anything.")

is your frame. It says check a random percentage and if it's 50 percent or lower, then you succeed, otherwise send the player a fail message. So if we only want there to be a 50 percent chance the gold can be stolen, and the number if 0 - 50, the functions inside the {} will run. If it's 51 or more, the fail message will display.

In between those {} put your various success calls:
if (RandonChance(10)) msg ("You got gold.")
If (RandomChance(20)) msg ("You got a diamond.")
If (RandomChance(30)) msg ("You got splinters! Ouch.")
If (RandomChance(50)) msg ("A mousetrap snaps on your fingers.")
else msg ("Your target is broke. You got air.")


hmm... looked at my code again...

HK edit: this is NOT true ----> this is definately the most concise/efficient you can make it!

if (RandomChance (50)) {
  msg ("You tried to steal something but unfortunately you didn't! Oh noes! Egads!")
} else if (RandomChance(25)) {
  msg ("You stole insert item here")
  MoveObject (precious diamond, player)
} else if (RandomChance(25)) {
  msg ("You swiped some gold!")
  player.gold = player.gold + 5
}
// we (STILL-ARGH) need a fail prompting here, so this code doesn't even work (in terms of being better)... DOH!

HK Edit: NOOOOOOOOOO, this fails.... ARGH! I was wrong... as this doesn't even work (again a missing prompt of failure with this bad/failed design of mine). My previous post is the best you can make it, I think (though not sure about actual efficiency/operations, meh)


this is the most concise design possible (whether it's actually more efficient/operations, is another matter):

boolean_variable = RandomChance (50)
if (boolean_variable and RandomChance(25)) {
  msg ("You stole insert item here")
  MoveObject (precious diamond, player)
} else if (boolean_variable and RandomChance(25)) {
  msg ("You swiped some gold!")
  player.gold = player.gold + 5
} else {
  msg ("You tried to steal something but unfortunately you didn't! Oh noes! Egads!")
}

we could do this, but it's NOT the same (not the same mechanics/equation/formula algorithm design):

if (RandomChance(25)) {
  msg ("You stole insert item here")
  MoveObject (precious diamond, player)
} else if (RandomChance(25)) {
  msg ("You swiped some gold!")
  player.gold = player.gold + 5
} else {
  msg ("You tried to steal something but unfortunately you didn't! Oh noes! Egads!")
}

This explains the algorithms/designs (axioms):

as there's a big difference between the mechanics/formula/equation/math/odds of them:

odds: 50% (or fail prompt) -> 25% -> 25% (or fail prompt)
odds: (0.5, or fail prompt) -> (0.5 * 0.25) -> (0.5 * 0.25 * 0.25, or fail prompt)
odds: (1/2, or 1/2 for fail prompt) -> (1/8 for item) -> (1/32 for gold, or 31/32 for fail prompt)
VS
odds: 25% -> 25% (or fail prompt)
odds: (0.25) -> (0.25 * 0.25, or fail prompt)
odds: (1/4 for item) -> (1/16 for gold, or 15/16 for fail prompt)

// shouldn't the item (precious diamond) be more rare to get than gold? lol (maybe gold is much more valuable... meh --- I'm just joking around, though with this algorithm, you can see that you probably do want to switch the gold and precious diamond, so that the precious diamond is the more rare thing to get, than gold is)


so again, this (at the very bottom of this post) is the most concise design possible for Anonynn's algorithm/design (axiom) of:

odds: 50% (or fail prompt) -> 25% -> 25% (or fail prompt)
odds: (0.5, or fail prompt) -> (0.5 * 0.25) -> (0.5 * 0.25 * 0.25, or fail prompt)
odds: (1/2, or 1/2 for fail prompt) -> (1/8 for item) -> (1/32 for gold, or 31/32 for fail prompt)

EQUALS:

// Anonynn's original code:

if (RandomChance(50)) {
  msg ("You tried to steal something but unfortunately you didn't! Oh noes! Egads!")
} else {
  if (RandomChance(25)) {
    msg ("You stole insert item here")
    MoveObject (precious diamond, player)
  } else if (RandomChance(25)) {
    msg ("You swiped some gold!")
    player.gold = player.gold + 5
  } else {
    msg ("You tried to steal something but failed this time.")
  }
}

most concise code design possible using Anonynn's axiom (aka her original code directly above):

boolean_variable = RandomChance (50)
if (boolean_variable and RandomChance(25)) {
  msg ("You stole insert item here")
  MoveObject (precious diamond, player)
} else if (boolean_variable and RandomChance(25)) {
  msg ("You swiped some gold!")
  player.gold = player.gold + 5
} else {
  msg ("You tried to steal something but unfortunately you didn't! Oh noes! Egads!")
}

you're overthinking again.

  1. don't use boolean. it's not necessary. think yes/no when you think of boolean.

All you need is an if/else statement with some if/else statement nested inside it.

If/else is automatically yes/no

Psudeo code:

If (this) do this
else do this

If randomchance is 50 (or less) = yes
else = randomchane wasn't 50 or less so that = an automatic no

So the starting frame is:

if (RandomChance(50))
     {
              {
              insert success messages here
              }
 else 
        {
        msg ("You tried to steal something but failed this time.")
       }
}

Now we create the messages that the player will get if attempt is successful:

if (RandomChance (10)) 
      {
       msg ("")
      }
 else if (RandomChance (20))
      {
       msg (" ")
       }
 else if (RandomChance (30))
       {
       msg (" ")
       }
else if (RandomChance (40))
      {
       msg (" ")
      }
else
      {
      msg (" ")
       }

Now we put those all together:

if (RandomChance(50))
      {
            {
               if (RandomChance (10)) 
                      {
                      msg ("")
                       }
                else if (RandomChance (20))
                        {
                 msg (" ")
                       }
                     else if (RandomChance (30))
                        {
                         msg (" ")
                          }
                   else if (RandomChance (40))
                          {
                    msg (" ")
                       }
                  else
                        {
                  msg (" ")
                         }
               }
 else 
          {
          msg ("You tried to steal something but failed this time.")
          }
}

when this runs, the game will check the chance. If it is 50% or less, it'll go through the nested if/else statements for success and return one of them. If it is NOT 50%, it'll ignore all of them and just display the failure message

Obviously, you'll also need to have it do stuff like adding gold or whatever is appropriate for each success message. Those functions will be added right after the message, or right before it, in the set of curly braces the message resides in.

Also, notice the logic of the random amounts. Start with the lowest chance, then the next highest, and next highest and so on. This lets you keep YOU organizes. you put the rarest thing first, and go on up to the most common thing. You do that every time you code something like this and then down the road you don't have to try to translate what you were doing.


crystalwizard, I've been puzzling over the multiple calls to GetRandomChance with the increasing values. I did notice that you had noted this in your answer as "a good thing", but I wondered what the probabilities actually were. So I worked out the probabilities, and it ended up being strange.

Ignoring the 50% chance thing up front, we can compute the probability of hitting each branch for a given pass through the code.

For the first item, you have a 10% chance. That's simple enough.

For the second item, you have a 90% chance from the first roll, and then a 20% from the second, which gives you an overall probability of 18%.

For the third, it's similar: 90% * 80% * 30%, which gives 21.6%.

So far so good. Now the next one gets weird.

For the fourth, you have 90% * 80% * 70% * 40%... which gives 20.16%. Less than the one above.

And your final branch has probability of 90% * 80% * 70% * 60% or 30.24%.

I've added these probabilities up (10 + 18 + 21.6 + 20.16 + 30.24) and gotten 100, so that leads me to believe I didn't make an error.

If you had proceeded further with another item (at 50%), then that probability would have been around 17%, which is less again from the previous. I'm wondering if it's approximating more a bell curve than a strict increase... (I can do many math things, but there's also a lot of theoretical math I'm simply not set up for. I'm sure someone out there would have a definitive answer as to why it behaves this way.) It could also be just that you're taking a larger and larger percent of a rapidly diminishing probability.

Anyway, just wanted to mention that, as your code doesn't seem to be doing quite what you implied you thought it was doing. :)

When I was working on my response library, I allowed choosing randomly from a list of choices, where each choice could have a weight. The algorithm was to sum up the various weights and then use that total as a divisor for the various individual weights when selecting using a probability from a single roll. That works especially well if items can come and go within the list. I think cascading probabilities is going to give you grief, unless it is broad branches like the "50% chance you might get something" one above.


I wasn't trying for a bell curve, just a set of "if you succeeded, did you get this, did you get that, did you get, ..." Which can be all over the place, really. You could even give every item the same random chance... -> You have a 50% chance to get something if you steal. You succeeded with that, so... now we check to see what you got:

  1. you have a 50% chance to have gotten a ring. Nope.
  2. Okay, you have a 50% chance to have gotten gold. Nope.
  3. Okay, you have a 50% chance to have gotten pocket lint. Nope.
  4. Okay....

Until finally you run out of stuff you might have gotten, didn't get any of them, and get the message that your target was broke and all you got was air. That actually makes it far more realistic, as you always face a schrodinger's cat situation when trying to steal something you can't see - Does it exist or not till you try to take it? And what might it be.

The reason for the rising percentages in my illustration to start is that well, if you didn't get this (and you had a slim chance), maybe you got this - not much better chance, but something of a better chance. You didn't get that, maybe you got this, an even better chance.... and so on. The percents don't have to be rising, they can be in any order, it just keeps it easier to organize from a programing perspective (not that I commented my code as I should have).

Personally, coming from an AD&D background, I'd prefer a table of objects, and to roll a dice to see what object is acquired if success == yes. But that requires Quest to have the ability to store a global table, and then read it when needed.


I know you weren't trying for a bell curve. (It may not even be one.) Which is why I brought it up to begin with. Perhaps I misunderstood this: "Also, notice the logic of the random amounts. Start with the lowest chance then the next highest, and next highest and so on." To me that implied the chances of you getting an item was increasing, which wasn't the case. I was simply pointing that out, in case you thought it was working a different way than what you intended. Since you had specifically mentioned "the logic of the random amounts" increasing, I assumed "the logic" was what you stated afterwards.

Also keep in mind that even with a 50% scheme, the probabilities for each item drop off wildly (well, exponentially) the more you have. So if you had four items, they will have probabilities 1/2 for the first, 1/4 for the second, then 1/8 and 1/16, as you go along your "if"s. If you're willing for the last one to end up selected so infrequently (only one time in sixteen), then it's an acceptable scheme. If you had 10 items, the last item would only be selected 1 in 1024 times. So you can see the problem as you scale.

And it effectively comes down to the opposite of what you had said: with cascading "if"s, apart from mucking about with the probabilities to artificially boost things (which you can only do so far), you will end up typically with the first item having the highest chance, not the rarest, since the probabilities do drop off so quickly the more random numbers you choose.

But basically, as long as it's working the way you want, then great! :)


Why do you have a fail for both the first condition, and the last? If you don't fail (randomchance 50) then all the else statements should be success of some sort.

I set it up that way because I prefer a balanced way of doing things. I would want the odds of successfully pick-pocketing to be lower than the success, that way it would be exciting to the player, or a more meaningful success when they actually do rob someone. Hell, you could even make it that instead of a second fail, they actually get caught and attacked. :)

You could also do...

chance = GetRandomInt(0, 100)
if (chance <=50) {
 //do this
}
else {
  if (15 < chance >=30) {
  //do this
  else if (31 <chance>=50) {
  //do this
  } 
  else {
  //do this
}
}

And so on :)


This topic is now closed. Topics are closed after 60 days of inactivity.

Support

Forums