Rolling Dice in Tads3?

Hi; sorry if this has been covered elsewhere, but how do you program dice in Tads3?

In my current project, I’m trying to implement a D20 which, of course, when rolled would generate a number 1-20 which would then become a value to be applied to a number of things depending on context.

Currently, I have a do-nothing die:

class Die : Thing
vocabWords = 'die*dice'
dobjFor(Roll)
{
verify(){}
check(){}
action()
 {
  "{you/he} roll{s} a <<rand(20)>>. ";
  }
}
;

The problems with this are
a) I want to exclude zero as a possible outcome, which it currently is. Preferably, I’d like to have it randomly select numbers between a given min and max, but so far the literature doesn’t seem to say how to do that. :stuck_out_tongue:
Also,
b) It’s currently display only. What should I do so that I get a random value for computing purposes? Anonymous function? Script? Something else altogether?

Does anyone have any ideas?

ETA: Just updating to say that I worked out an awkward kludge for problem A,


class Die : Thing
vocabWords = 'die*dice'
dobjFor(Roll)
{
verify(){}
check(){}
action()
 {
  "{you/he} roll{s} a <<rand(gDobj.sides)>>. ";
  }
}
;

d20: Die 'd20' 'D20'
"It's a blue, nearly round die with sides numbered one through twenty. "
sides = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
;

But I keep thinking there has got to be a more effecient way to do these things. Is there?
Also, still working on B. :stuck_out_tongue:

TADS 3 doesn’t have a function that returns a random number in any given range. As you’ve noticed, rand(20) actually returns a random number from 0-19. If all of your ranges will be from 1 to some other number, then it’s easiest to use rand(max) + 1; in the case of your d20, you’d use rand(20) + 1.

It’s easy enough to create a function that returns a random number from a given range, though. This does the trick:

[code]function randBetween(num1, num2)
{
/* find out which of the given numbers is larger */
local maximum = max(num1, num2);
local minimum = min(num1, num2);

/* calculate the random number */
local tempMax = maximum - minimum + 1;
local randNum = rand(tempMax) + minimum;
return randNum;

}[/code]

rand() doesn’t print the number itself; it just returns it. (The number is being printed by the << >> brackets in your string.) So you can store the random number in a local variable or a property, just like any other number. For instance:

local roll = rand(20) + 1;

Thanks! :slight_smile:

Note the first: I know nothing about TADS, 3 or otherwise. But I do know a few things about die rollers.

First, as Emerald already said, rolling a die in your bog-standard coding language is easiest done by simply randomising and adding numbers to make the range fit. I’ll do this in metacode; hopefully the ideas will be lucid enough.

(single die, where x is the number of sides to the die) random(x-1)+1 // solves for a single die with 2 or more sides
Next, bonuses and penalties are applied.
(where y is the die bonus or penalty) random(x-1)+1+y // solves for any single die with 2 or more sides and a bonus or penalty, e.g. 1d8-5, 1d20+30, etc
So far, everything is simple enough. But what to do when you have multiple dice? Well, obviously, run the routine again. Best to put it in a function, of course, but that’s good practice anyway. For legibility, I tend to create functions that are called like this in languages like PhP:

dieRoll("3d6+1");

The function then chunks the input string and interprets it as needed, which is trivial enough.

But… what if we have notions such as “remove the lowest die”? What you do then is store each die rolled as a part of an array. Then you have the function iterate through the array and remove those dice that rolled the lowest, the highest, or whatever result you wanted. Then you add/subtract the final bonus or penalty.

But… what about Infinity dice? I speak of the good old mechanic in which you get to roll, for instance, 3d6, and in which every 6 means you don’t add the 6 but instead roll two new d6es, and so on and so forth? It’s a dead useful mechanic, providing a limited but sometimes dramatic uncertainty factor. But it also, if you’re not clever about things, will be a bitch to code: the first impulse of the modern coder is to do it recursively (that is that each result of 6 would call the die roller function twice from within the die roller function, and so on) leading to completely unnecessary hi-jinks.

Or we could do it with a For-Next loop, which would loop through every die. Each time you roll 1 to 5, you add it as normal to the tally. Whenever you roll 6, you don’t add it: you instead add 2 to the number of dice that must be rolled.

…I really must learn TADS3. Regrettably I can’t seem to get it to work on my system. All that aside, I hope someone will find something useful in the above post.

…Coool… :open_mouth:

And yes, you must learn Tads3. As it is, my experience with rpg die-roll systems is limited, and so I’m working with a combination of scant knowledge and guesswork; reinventing the wheel as it were. :stuck_out_tongue: All these things sound very useful to know.

TADS 3 does appear to have its good sides. I primarily enjoy Inform 7 at present because it’s forced me to go back to the basics and learn alternative ways of doing things. But broader knowledge is also a useful thing, so I’ve just installed TADS 3. I’ll give it a whirl one of these days.

One thing I have to stress regarding computer RPGs, a thing I think has yet to occur to perhaps ninety-eight percent of the more famous publishers of “computer RPG”, is what role playing as a concept is actually about. The reason we use dice in tabletop games isn’t because they’re dice and we love numbers; it was simply seen as the least cumbersome way to both randomise the action and let the player place bets.

That’s why I can’t really comprehend why hit points or overt number damage still exists in computer games today. If you hit a person with a sword, it will presumably cause some manner of setback. Fine, that’s okay. In a realistic setting, this might lead to bleeding, shock, broken bones or death; perhaps the person instead will be so charged with adrenaline that she will keep fighting and hardly feel it. In an unrealistic, heroic setting, the character might grunt, clutch a superficial cut on her cheek, raise her sword again, and continue; either that, or she will not be hit in the first place.

I have yet to see a story or TV show in which a hit from a sword resulted in “-15 hp” briefly floating above the head of a character. It’s useless, mechanics-bound information, and it will only serve to pull you out of mimesis. Once it was tolerated because the simplest pen-and-paper systems available used it for attrition, but then as now, there are so many other systems around that are frankly better. Said systems should be used instead of the tick-tick-boom method of “I’m just fine… crud, HP is 0! I’m dead!”

EDIT: So I guess what I’m saying is actually three things.

  1. Avoid adopting the Bioware school of doing things, i.e. bringing in everything but the dice themselves. It’s a popular method because some apparently hold this as the point of RPGs, but otherwise it is of limited utility.
  2. The presentation of violence as entertainment (or chases, or anything else we usually see in RPGs) will differ between genres. In Star Wars, a five-man group of plucky outsiders are perfectly expected to brave the unknown; we take it in stride; the action is spectacular and flamboyant and superlative. In Call of Cthulhu, “braving the unknown” is… well, pretty much what does tend to happen in a Lovecraft book, but it seldom ends well.
  3. Instead of presenting numbers, present what they mean in in-game terms.