Random Stuff Generator
Captain Coredump
mjranum at gouldsd.UUCP
Wed Oct 29 05:16:57 AEST 1986
Here it is, since I am tired of sending individual copies around.
Take it or leave it.... So far it runs on BSD UNIX and on IBM PCs under
Lattice 3.0 (with stack modifications).
Live Free
mjr
the following files are in this bundle: (Use them wisely)
Makefile README food nationality pirate possesions rnd.c rnd.nro skill weapon
cut here --------------------------------------------------
# To unbundle - sh this file
echo unbundling Makefile
if [ -f Makefile ] ; then
echo cannot unbundle Makefile - file exists already
exit 1
fi
cat >Makefile <<'End of Makefile'
CFLAGS= -O
CC= /bin/cc
STD= rnd
DOC= README
all: ${STD} ${DOC}
${STD}: rnd.c
${CC} ${CFLAGS} -o $@ $@.c
${DOC}: rnd.nro
nroff -man rnd.nro >> README
End of Makefile
echo unbundling README
if [ -f README ] ; then
echo cannot unbundle README - file exists already
exit 1
fi
cat >README <<'End of README'
rrrrnnnndddd((((1111)))) rrrrnnnndddd((((1111))))
rrrrnnnndddd ---- RRRRaaaannnnddddoooommmm ssssttttuuuuffffffff ggggeeeennnneeeerrrraaaattttoooorrrr ((((MMMMJJJJRRRR))))
SSSSYYYYNNNNTTTTAAAAXXXX
rrrrnnnndddd file1 file2, etc...
OOOOPPPPTTTTIIIIOOOONNNNSSSS
Each file must be a 'table' file.
DDDDEEEESSSSCCCCRRRRIIIIPPPPTTTTIIIIOOOONNNN
_R_n_d reads a file and writes generated data to the standard
output. If more than one file is specified, the files are
used as descriptions in sequence and merged output is written
to the standard output. Two types of files are recognized;
table files, and subtable files. A table file can contain
several types of information:
o+ Text-formats and text: these are simply text that will be
included in the output. There are, however, a few
simple rules. Any text string ending in a ':' (no
space afterwards) will NOT have a newline appended
after it. This is to allow a user to have the output
from a subtable placed after a text string. Other
text that does not have a ':' as the last character
before a newline is printed as is.
o+ Tabs and Formfeeds: to insert tabs and formfeeds, a "\t" (tab)
or a "\l" (formfeed ^L) is placed as the ONLY thing
on that line. There must be no other blank spaces,
etc. This is inelegant, but allows the program to
run reasonably fast. If a tab is coded, the program
does NOT automatically generate a newline after it.
This is to allow a user to separate stats with tabs
reasonably easily.
o+ Stat commands: a stat command goes at the beginning of an
otherwise empty line, in the format
"stat <char string WITHOUT spaces> <# of dice> <type of dice>"
Rnd will then roll the appropriate number of N-sided
dice, and print the stat on the standard output.
o+ Subtable commands: a subtable command goes at the beginning of
an otherwise empty line, in the format
UTX/32 User's
Reference Manual -1- Commands
rrrrnnnndddd((((1111)))) rrrrnnnndddd((((1111))))
"subtable <filename> <# of dice> <type of dice>"
Rnd will then roll the appropriate number of N-sided
dice, and open the subtable file. A subtable file is
constructed as follows:
<#upper limit> <text string>
<#upper limit> <text string>
Subtable files may not contain any extraneous text
(unlike table files) and all the entries must be in
order, with the highest numerical entry as the last
line in the file, and the lowest numerical entry as
the first. Each line must contain a number value
and a text string, or the results may be unusual.
o+ Table commands: a table can contain a list of tables as well as
stats, format commands, text, and subtables. Each
table is randomized recursively, until your stack
overflows, or it returns, whichever comes first.
Stacking tables deeply is usually not necessary,
since several tables can be called on the command
line, and that is much safer. When a table command
is invoked, it must be followed by two numbers so
that the semi-braindead parser recognizes it as a
command.
table <filename> <bogus #><bogus #>
Each table can contain its own list of subtables and
stats, as well as text and format commands. This is
lots of fun, since it allows the discerning DM to
make a variety of layered tables and gives excellent
control over how much is generated. For example if
you determine that an encounter consists of
monsters, booty, and terrain, you could have a table
that invoked the monster table, then the terrain
one, then the booty. In this way, you would still
have a perfectly usable set of tables for any time
you wanted just a monster, or just terrain. The
possibilities as far as maintaining standard
libraries are considerable, obviously. The primary
limitation is your machine's stack and disk space.
EEEEXXXXAAAAMMMMPPPPLLLLEEEESSSS
$ rrrrnnnndddd ppppiiiirrrraaaatttteeeessss
rrrrnnnndddd reads the table named ppppiiiirrrraaaatttteeeessss and executes all the stats,
subtables, and tables contained therein.
UTX/32 User's
Reference Manual -2- Commands
rrrrnnnndddd((((1111)))) rrrrnnnndddd((((1111))))
((((TTTThhhheeee ccccoooonnnntttteeeennnnttttssss ooooffff ffffiiiilllleeee """"ppppiiiirrrraaaatttteeeessss""""....))))
--------------------------------------
A sample pirate -----
stat strength 3 6
\t
stat brains 3 6
possesions:
subtable possesions 1 100
table anothertable 0 0
---------------------------------------
\l
This would generate a pirate with 3d6 strength and
brains, and would make a 1d100 roll on the possessions table.
The table "anothertable" is then opened and treated as a new
list of commands. Note that there are 2 numbers provided with
the table command. This is MANDATORY, and due only to lazy
programming. Live with it. Appropriate tabs and a formfeed
are generated.
((((ccccoooonnnntttteeeennnnttttssss ooooffff ffffiiiilllleeee """"ppppoooosssssssseeeessssiiiioooonnnnssss""""))))
10 Cutlass
20 Fists
30 Bucket of Grog
40 Belaying Pin
90 Just his clothes
100 Fancy clothes
In this example, when the subtable was called, a 1d100 was
rolled (be sure to specify that right!) 0-10 yields a Cutlass,
11-20 Fists, etc.
SSSSPPPPEEEECCCCIIIIAAAALLLL CCCCOOOONNNNSSSSIIIIDDDDEEEERRRRAAAATTTTIIIIOOOONNNNSSSS
o+ This program is machine dependent to the degree that your
machine likes recursion.
o+ A random seed is requested for portability's sake. Those
of you on UNIX systems are urged to use something like:
srand((unsigned)getpid());
instead. Any random stirrer is appropriate.
UTX/32 User's
Reference Manual -3- Commands
rrrrnnnndddd((((1111)))) rrrrnnnndddd((((1111))))
o+ This program has run on Gould Powernode 9080, Sun
workstations, and my IBM compatible clone (lattice 3.0).
On the PCs, usually some provision will have to be made to
increase the stack size. On lattice this is done by
declaring a global "int _stack = 6000;" or about 6
kilobytes. You decide. No guarantees are made for other
compilers/machines, but anything that is not braindead can
handle it.
o+ Capturing the output:: This program is designed for
systems with I/O redirection. If you don't have it, I
suggest you frob the code slightly by changing all printfs
to fprintf, etc. For you with I/O redirection, the initial
text, etc, is returned on the standard error, so it will
not kluge up your characters as they are generated. Pipe
the output through your favorite formatter, editor,
printer, or null device.
SSSSEEEEEEEE AAAALLLLSSSSOOOO
no references
AAAAuuuutttthhhhoooorrrr:::: Marcus J Ranum, Gould Inc. All rights reserved. Don't use
this to make money, or sell. Otherwise it may be freely copied,
deleted, and hacked. Give me credit for the idea, if not the
code.
UTX/32 User's
Reference Manual -4- Commands
End of README
echo unbundling food
if [ -f food ] ; then
echo cannot unbundle food - file exists already
exit 1
fi
cat >food <<'End of food'
10 Sushi
20 Salad
30 Wiskey
40 Sandwitches
50 Port
60 Scotch
70 Vodka
80 Caviar
90 Gum
100 Beer
End of food
echo unbundling nationality
if [ -f nationality ] ; then
echo cannot unbundle nationality - file exists already
exit 1
fi
cat >nationality <<'End of nationality'
10 Spanish
20 French
30 English
40 Japanese
50 Dutch
60 Portugese
70 Italian
80 Russian
90 German
100 Other
End of nationality
echo unbundling pirate
if [ -f pirate ] ; then
echo cannot unbundle pirate - file exists already
exit 1
fi
cat >pirate <<'End of pirate'
--------------------------------------------------------------
Sample Pirate
-------------
stat strength 3 6
\t
\t
stat intelligence 3 6
\t
\t
stat seamanship 3 6
stat swordplay 3 6
\t
\t
stat looks 3 6
\t
\t
stat education 1 10
nationality:
subtable nationality 1 100
Possessions:
table possesions 0 0
End of pirate
echo unbundling possesions
if [ -f possesions ] ; then
echo cannot unbundle possesions - file exists already
exit 1
fi
cat >possesions <<'End of possesions'
Weapons:
subtable weapon 1 100
Food:
subtable food 1 100
subtable food 1 100
stat cash 3 30
Skills:
subtable skill 1 100
\t
subtable skill 1 100
\t
subtable skill 1 100
End of possesions
echo unbundling rnd.c
if [ -f rnd.c ] ; then
echo cannot unbundle rnd.c - file exists already
exit 1
fi
cat >rnd.c <<'End of rnd.c'
#include "stdio.h"
/* rnd.c :
written by Marcus J Ranum.
All rights reserved. You may freely copy, modify, distribute,
and delete this program, but any use that will cause you to
gain money is prohibited unless we work out a deal, or you
ask me nicely. Any nifty ideas/modifications, please let me
know.
-mjr
*/
main(argc,argv)
int argc;
char *argv[];
{
int a;
char seed[100];
char word[200];
int iterations;
fprintf(stderr,"Please enter a random # and press <return>: ");
srand((unsigned)atoi(gets(seed)));
fprintf(stderr,"How many runs do you want and press <return>: ");
iterations=atoi(gets(word));
while(iterations--) {
for(a=1 ; a < argc; a++) {
dotable(argv[a]);
}
}
}
/* roll a <sides> sided die <num> times */
roll(num,sides)
int num;
int sides;
{
int a=0;
while (num-- >0)
a += rnd(sides);
return(a);
}
/* roll a <die> sided die once */
rnd(die)
register die;
{
return(((rand()>>3) % die)+1);
}
/* reads a table. calls doparse for every line in the table.
note, if doparse hits another table name, this will
be recursively called. max recursions seems to be
around 10....
*/
dotable(table)
char table[];
{
FILE *file;
char junk[BUFSIZ];
if((file = fopen(table,"r")) ==NULL) {
fprintf(stderr,"can't open %s\n",table);
exit(1);
}
while((fgets(junk,BUFSIZ-3,file)) !=NULL){
doparse(junk);
}
if(fclose(file) == EOF) {
fprintf(stderr,"unusual file-close error!\n");
exit(1);
}
}
/* reads a subtable, and looks for a numbered entry that matches the
given selection criterion. <stat> is the table name, <num> is
the number of dice, and <die> is the number of sides on the
die. the subtables must be in the form of
<#> entry (text string terminated with newline)
*/
dosubtable(stat,num,die)
char stat[];
int num;
int die;
{
FILE *tbl;
char junk[BUFSIZ];
char word[100];
int old;
int new;
int pick;
old=0;
if((tbl=fopen(stat,"r")) == NULL){
fprintf(stderr,"can't open subtable %s\n",stat);
} else {
pick = roll(num,die);
while((fgets(junk,BUFSIZ-3,tbl)) != NULL){
if(sscanf(junk,"%d",&new)) {
if( pick > old && pick <= new) {
if (sscanf(junk,"%s",word)==0) {
fprintf(stderr, "invalid format\n");
exit(1);
}
junk[strlen(junk)-1] = ' ';
dohack(junk);
break;
}
old = new;
}
}
}
if(fclose(tbl)== EOF) {
fprintf(stderr,"unusual file-close error\n");
exit(1);
}
}
/* prints a stat <stat> is statname, <num> is number of dice, and
<die> is how many sides the die has. */
dostat(stat,num,die)
char stat[];
int num;
int die;
{
printf("%s:_______ \b\b\b\b\b\b\b%d",stat,roll(num,die));
}
/* doparse looks for the magic words "table" "subtable" "\t" or "\l"
and does the appropriate thing if it encounters them. if it
does not, it dumps it as text */
doparse(junk)
char junk[];
{
char stat[200];
char word[200];
int die;
int num;
if( junk[0] == '\\') {
switch(junk[1]) {
case 'l':
putchar(12);
break;
case 't':
printf("\t");
break;
}
} else {
if((sscanf(junk,"%s %s %d %d",
word,stat,&num,&die))!= 4) {
dotext(junk);
} else {
if(!strcmp(word,"subtable"))
dosubtable(stat,num,die);
else if(!strcmp(word,"stat"))
dostat(stat,num,die);
else if(!strcmp(word,"table"))
dotable(stat);
else
dotext(junk);
}
}
}
/* dohack takes a string and dumps all of it except the FIRST word.
this is basically useful for printing subtable entries.
while there are more elegant ways of doing this in C,
my Lattice compiler dies when I try it. */
dohack(string)
char string[BUFSIZ];
{
int a = 0;
int b = 0;
while(b == 0)
if(string[a++] == ' ')
b++;
for(b = a; b < strlen(string); b++)
putchar(string[b]);
}
/* dotext basically dumps a text string.
if the 2nd to last char (newline is last) is a ":"
it does NOT put a newline on. this is to allow you to
have items from subtables appear after a : */
dotext(string)
char string[BUFSIZ];
{
int c;
c = (strlen(string)-2);
if (string[c] == ':')
string[++c] = ' ';
printf("%s",string);
}
End of rnd.c
echo unbundling rnd.nro
if [ -f rnd.nro ] ; then
echo cannot unbundle rnd.nro - file exists already
exit 1
fi
cat >rnd.nro <<'End of rnd.nro'
.EV
.T1 rnd 1 2/14/84
.SH "rnd \- Random stuff generator" (MJR)
.SY
.B rnd
file1 file2, etc...
.OP
Each file must be a 'table' file.
.DS
.I Rnd
reads a file and writes generated data to the standard output.
If more than one file is specified, the files are used as descriptions
in sequence and merged output is written to the standard output.
Two types of files are recognized; table files, and subtable files.
A table file can contain several types of information:
.TP 8
\(bu Text-formats and text: these are simply text that will be
included in the output. There are, however, a few simple rules.
Any text string ending in a ':' (no space afterwards) will NOT
have a newline appended after it. This is to allow a user to
have the output from a subtable placed after a text string.
Other text that does not have a ':' as the last character before
a newline is printed as is.
.TP
\(bu Tabs and Formfeeds: to insert tabs and formfeeds, a "\\t" (tab)
or a "\\l" (formfeed ^L) is placed as the ONLY thing on that line.
There must be no other blank spaces, etc. This is inelegant, but
allows the program to run reasonably fast. If a tab is coded, the
program does NOT automatically generate a newline after it. This
is to allow a user to separate stats with tabs reasonably easily.
.TP
\(bu Stat commands: a stat command goes at the beginning of an
otherwise empty line, in the format
.nf
.na
"stat <char string WITHOUT spaces> <# of dice> <type of dice>"
.fi
.ad
Rnd will then roll the appropriate number of N-sided dice, and
print the stat on the standard output.
.TP
\(bu Subtable commands: a subtable command goes at the beginning of
an otherwise empty line, in the format
.nf
.na
"subtable <filename> <# of dice> <type of dice>"
.fi
.ad
Rnd will then roll the appropriate number of N-sided dice, and
open the subtable file. A subtable file is constructed as follows:
.nf
.na
<#upper limit> <text string>
<#upper limit> <text string>
... etc.
.fi
.ad
Subtable files may not contain any extraneous text (unlike table files)
and all the entries must be in order, with the highest numerical entry as the
last line in the file, and the lowest numerical entry as the first.
Each line must contain a number value and a text string, or the results
may be unusual.
.TP
\(bu Table commands: a table can contain a list of tables as well as
stats, format commands, text, and subtables. Each table is randomized
recursively, until your stack overflows, or it returns, whichever comes
first. Stacking tables deeply is usually not necessary, since several
tables can be called on the command line, and that is much safer.
When a table command is invoked, it must be followed by two numbers
so that the semi-braindead parser recognizes it as a command.
.nf
.na
table <filename> <bogus #><bogus #>
.fi
.ad
Each table can contain its own list of subtables and stats, as well as text
and format commands. This is lots of fun, since it allows the discerning
DM to make a variety of layered tables and gives excellent control
over how much is generated. For example if you determine that an encounter
consists of monsters, booty, and terrain, you could have a table that
invoked the monster table, then the terrain one, then the booty. In
this way, you would still have a perfectly usable set of tables for
any time you wanted just a monster, or just terrain. The possibilities
as far as maintaining standard libraries are considerable, obviously.
The primary limitation is your machine's stack and disk space.
.EX
$ \fBrnd pirates\fR
.EE
.B rnd
reads the table named
.B pirates
and executes all the stats, subtables, and tables contained therein.
.E2
.sp
.sp
.sp
.sp
\fB(The contents of file "pirates".)\fR
.EE
.nf
.na
--------------------------------------
A sample pirate -----
stat strength 3 6
\\t
stat brains 3 6
possesions:
subtable possesions 1 100
table anothertable 0 0
---------------------------------------
\\l
.fi
.ad
This would generate a pirate with 3d6 strength and brains, and
would make a 1d100 roll on the possessions table.
The table "anothertable" is then opened and treated as a new list of
commands. Note that there are 2 numbers provided with the table command.
This is MANDATORY, and due only to lazy programming. Live with it.
Appropriate tabs and
a formfeed are generated.
.E2
\fB(contents of file "possesions")\fP
.EE
.nf
.na
10 Cutlass
20 Fists
30 Bucket of Grog
40 Belaying Pin
90 Just his clothes
100 Fancy clothes
.fi
.ad
In this example, when the subtable was called, a 1d100 was rolled (be
sure to specify that right!) 0-10 yields a Cutlass, 11-20 Fists, etc.
.SC
.TP 2
\(bu
This program is machine dependent to the degree that your machine likes
recursion.
.TP
\(bu
A random seed is requested for portability's sake. Those of you on
UNIX systems are urged to use something like:
.nf
.na
srand((unsigned)getpid());
.fi
.ad
instead. Any random stirrer is appropriate.
.TP
\(bu
This program has run on Gould Powernode 9080, Sun workstations, and
my IBM compatible clone (lattice 3.0). On the PCs, usually some provision
will have to be made to increase the stack size. On lattice this is
done by declaring a global "int _stack = 6000;" or about 6 kilobytes.
You decide. No guarantees are made for other compilers/machines, but
anything that is not braindead can handle it.
.TP
\(bu
Capturing the output:: This program is designed for systems with I/O
redirection. If you don't have it, I suggest you frob the code slightly
by changing all printfs to fprintf, etc. For you with I/O redirection,
the initial text, etc, is returned on the standard error, so it will
not kluge up your characters as they are generated. Pipe the output
through your favorite formatter, editor, printer, or null device.
.IN
no references
.I0
Author:
Marcus J Ranum, Gould Inc. All rights reserved. Don't use this to make
money, or sell. Otherwise it may be freely copied, deleted, and hacked.
Give me credit for the idea, if not the code.
End of rnd.nro
echo unbundling skill
if [ -f skill ] ; then
echo cannot unbundle skill - file exists already
exit 1
fi
cat >skill <<'End of skill'
5 pickpocketing
10 torture
30 basic seamanship
35 zymurgy
40 gunnery
45 rope-tying
50 liguistics
55 reading/writing
60 bookeeping
65 farming
70 gunsmithing
72 metalsmithing
80 woodworking
85 whaling
90 shipbuilding
95 navigation
97 storytelling/music
100 cartography
End of skill
echo unbundling weapon
if [ -f weapon ] ; then
echo cannot unbundle weapon - file exists already
exit 1
fi
cat >weapon <<'End of weapon'
10 Bad Breath
20 Musket
30 Cutlass
40 Belaying Pin.
50 Cane
60 Bottle
100 Fists
End of weapon
More information about the Comp.sources.unix
mailing list