/*	AD&D gem rolling program,
 *        written August, 1992, by Ken Jenks, 
 *        kjenks@gothamcity.jsc.nasa.gov
 *
 *	This program randomly determines the properties of non-magical
 *      gems.
 *
 *	Compile and run with no command line options to see 'usage.'
 */

#include <ctype.h>
#include <math.h>
#include <stdio.h>

static int
bv_table[13][2] = {
  { 25,     10.0},
  { 50,     50.0},
  { 70,    100.0},
  { 90,    500.0},
  { 99,   1000.0},
  {100,   5000.0},
  {  0,  10000.0},
  {  0,  25000.0},
  {  0,  50000.0},
  {  0, 100000.0},
  {  0, 250000.0},
  {  0, 500000.0},
  {  0,1000000.0}};

static float
decreased_bv_table[6] = {5.0, 1.0, 0.5, 0.25, 0.05};

static char *
descriptions[6] = {
  "Ornamental Stones",        /*   10 */
  "Semi-precious Stones",     /*   50 */
  "Fancy Stones",             /*  100 */
  "Fancy Stones (Precious)",  /*  500 */
  "Gem Stones",               /* 1000 */
  "Gem Stones (Jewels)"};     /* 5000 */

static char *
properties[6][14][3] = {

  {  /* Ornamental Stones, base value 10 GP */
/* 1*/    {"azurite","opaque","mottled deep blue"},
/* 2*/    {"banded agate","transparent","striped brown and blue and white and reddish"},
/* 3*/    {"blue quartz","transparent","pale blue"},
/* 4*/    {"eye agate","transluscent","circles of gray, white, brown, blue and/or green"},
/* 5*/    {"hematite","opaque","gray-black"},
/* 6*/    {"lapis lazuli","opaque","light and dark blue with yellow flecks"},
/* 7*/    {"malachite","opaque","striated light and dark green"},
/* 8*/    {"moss agate","transluscent","pink or white with grayish or greenish 'moss markings'"},
/* 9*/    {"obsidian","opaque","black"},
/*10*/    {"rhodochrosite","opaque","light pink"},
/*11*/    {"tiger eye","transluscent","rich brown with golden center under-hue"},
/*12*/    {"turquiose","opaque","light blue-green"},
/*13*/    {"","",""},
/*14*/    {"","",""}},

  {  /* Semi-precious Stones, base value 50 GP */
/* 1*/    {"amber","opaque","watery gold to rich gold"},
/* 2*/    {"carnelian","opaque","orange to reddish brown (also called Sard)"},
/* 3*/    {"chalcedony","opaque","white"},
/* 4*/    {"chrysoprase","transluscent","apple green to emerald green"},
/* 5*/    {"citrine","transparent","pale yellow brown"},
/* 6*/    {"jasper","opaque","blue, black to brown"},
/* 7*/    {"moonstone","transluscent","white with pale blue glow"},
/* 8*/    {"onyx","opaque","bands of black and white or pure black and white"},
/* 9*/    {"rock crystal","transparent","clear"},
/*10*/    {"sardonyx","opaque","bands of sard (red) and onyx (white) or sard"},
/*11*/    {"smoky quartz","transparent","gray, yellow, or blue (Cairngorm), all light"},
/*12*/    {"star rose quartz","transluscent","rosy stone with white 'star' center"},
/*13*/    {"zircon","transparent","clear pale blue-green"},
/*14*/    {"","",""}},

  {  /* Fancy Stones, base value 100 GP */
/* 1*/    {"amber","transparent","watery gold to rich gold"},
/* 2*/    {"alexandrite","transparent","dark green"},
/* 3*/    {"amethyst","transparent","deep purple"},
/* 4*/    {"","",""},
/* 5*/    {"chrysoberyl","transparent","yellow green to green"},
/* 6*/    {"coral","opaque","crimson"},
/* 7*/    {"garnet","transparent","red, brown-green, or violet (the most prized)"},
/* 8*/    {"jade","translucent","light green, deep green, green and white, white"},
/* 9*/    {"jet","opaque","deep black"},
/*10*/    {"pearl","transparent","lustrous white, yellowish, pinkish, etc. to pure black (the most prized)"},
/*11*/    {"","",""},
/*12*/    {"spinel","transparent","red, red-brown, deep green, or very deep blue (the most prized)"},
/*13*/    {"","",""},
/*14*/    {"tourmaline","transparent","green pale, blue pale, brown pale, or reddish pale"}},

  {  /* Fancy Stones, base value 500 GP */
/* 1*/    {"","",""},
/* 2*/    {"","",""},
/* 3*/    {"","",""},
/* 4*/    {"aquamarine","transparent","pale blue green"},
/* 5*/    {"","",""},
/* 6*/    {"","",""},
/* 7*/    {"garnet","transparent","red, brown-green, or violet (the most prized)"},
/* 8*/    {"","",""},
/* 9*/    {"","",""},
/*10*/    {"pearl","opaque","lustrous white, yellowish, pinkish, etc. to pure black (the most prized)"},
/*11*/    {"peridot","transparent","rich olive green (Chrysolite)"},
/*12*/    {"spinel","transparent","red, red-brown, deep green, or very deep blue (the most prized)"},
/*13*/    {"topaz","transparent","golden yellow"},
/*14*/    {"","",""}},

  {  /* Gem Stones, base value 1000 GP */
/* 1*/    {"black opal","translucent","dark green with black mottling and golden flakes"},
/* 2*/    {"","",""},
/* 3*/    {"","",""},
/* 4*/    {"emerald","transparent","deep bright green"},
/* 5*/    {"fire opal","translucent","fiery red"},
/* 6*/    {"","",""},
/* 7*/    {"opal","translucent","pale blue with green and golden mottling"},
/* 8*/    {"oriental amethyst","transparent","rich purple (Corundum)"},
/* 9*/    {"","",""},
/*10*/    {"oriental topaz","transparent","fiery yellow (Corundum)"},
/*11*/    {"","",""},
/*12*/    {"sapphire","transparent","clear to medium blue (Corundum)"},
/*13*/    {"star ruby","translucent","translucent ruby with white 'star' center"},
/*14*/    {"star sapphire","translucent","translucent sapphire with white 'star' center"}},

  {  /* Gem Stones, base value 5000 GP */
/* 1*/    {"black opal","translucent","dark green with black mottling and golden flakes"},
/* 2*/    {"black sapphire","translucent","lustrous black with glowing highlights"},
/* 3*/    {"diamond","transparent","clear blue-white with lesser stones clear whote or pale tints"},
/* 4*/    {"emerald","transparent","deep bright green"},
/* 5*/    {"fire opal","translucent","fiery red"},
/* 6*/    {"jacinth","transparent","fiery orange (Corundum)"},
/* 7*/    {"opal","translucent","pale blue with green and golden mottling"},
/* 8*/    {"oriental amethyst","transparent","rich purple (Corundum)"},
/* 9*/    {"oriental emerald","transparent","clear bright green (Corundum)"},
/*10*/    {"oriental topaz","transparent","fiery yellow (Corundum)"},
/*11*/    {"ruby","transparent","clear red to deep crimsom (Corundum)"},
/*12*/    {"sapphire","transparent","clear to medium blue (Corundum)"},
/*13*/    {"star ruby","translucent","translucent ruby with white 'star' center"},
/*14*/    {"star sapphire","translucent","translucent sapphire with white 'star' center"}}
  };

/************************************************************************
* die_roll() - simple function to roll one die of the given size
************************************************************************/

int die_roll(size)
int size;
{
   return ((rand() % size) + 1);
}

/************************************************************************
* random_gems() - randomly determine gems
*
************************************************************************/

void
random_gems(num_gems, base_value, outfile)
int num_gems, base_value;
FILE *outfile;
{
  int i;
  float bv, total = 0;
  int bv_die;
  int orig_base_value_place, current_base_value_place;
  int ignore_results_below_2 = 0;
  int inc_or_dec_die;
  int prop;

  fprintf(outfile,"%i gem%s, ",num_gems,
    (num_gems!=1)?"s":"");

  if(base_value)
    fprintf(outfile,"base value %i\n\n",base_value);
  else
    fprintf(outfile,"random base values\n\n");

  for (i=1; i<=num_gems; i++) {

    if(base_value) {
      bv = base_value;
      /* Calculate orig_base_value_place for later, since no gem may *
       * increase more than 7 places beyond its original base value  */
      orig_base_value_place=0;
      while ((orig_base_value_place<12)
        && (base_value > bv_table[orig_base_value_place][1]))
        ++orig_base_value_place;
      if(orig_base_value_place >= 6)
        orig_base_value_place = 5;

    } else {
      bv_die = die_roll(100);
      orig_base_value_place=0;
      while((orig_base_value_place<5)
        && (bv_die >= bv_table[orig_base_value_place][0]))
        orig_base_value_place++;

      bv = bv_table[orig_base_value_place][1];
#ifdef DEBUG
  fprintf(stderr,"Found bv=%f, base value place: %i\n",bv,orig_base_value_place);
#endif;
      /* Remember orig_base_value_place for later, since no gem may increase *
       * more than 7 places beyond its original base value              */
    }
    current_base_value_place = orig_base_value_place;

#ifdef DEBUG
  fprintf(stderr,"\nGem #%i, base value: %f\n\n",i,bv);
  fprintf(stderr,"  Base value place: %i\n",orig_base_value_place);
  fprintf(stderr,"  Calculating increase or decrease beyond base value...\n");
#endif

    ignore_results_below_2 = 0; /* Later, if we roll a 10, we ignore 1's */

inc_or_dec:
    inc_or_dec_die = die_roll(10);

#ifdef DEBUG
  fprintf(stderr,"  Inc/Dec die: %i\n",inc_or_dec_die);
#endif

    switch(inc_or_dec_die) {
      case 1: if((current_base_value_place <= 12) 
              && (current_base_value_place <= orig_base_value_place +6)
              && !ignore_results_below_2)
                bv = bv_table[++current_base_value_place][1];
#ifdef DEBUG
  fprintf(stderr,"    Value increases one place to %f; roll again.\n",bv);
#endif
              goto inc_or_dec;

      case 2: bv = 2.0*bv;
#ifdef DEBUG
  fprintf(stderr,"    Value doubles to %f\n",bv);
#endif
              break;

      case 3: bv = bv * (1.0 + (((float) die_roll(6))/10.0));
#ifdef DEBUG
  fprintf(stderr,"    Value increases by 10-60 percent to %f\n",bv);
#endif
              break;

      case 4: 
      case 5: 
      case 6: 
      case 7: 
      case 8: 
#ifdef DEBUG
  fprintf(stderr,"    No change in value\n");
#endif
              break;

      case 9: bv = bv * (1.0 - (((float) die_roll(4))/10.0));
#ifdef DEBUG
  fprintf(stderr,"    Value decreases by 10-40 percent to %f\n",bv);
#endif
              break;

      case 10: ignore_results_below_2 = 1;
              if(current_base_value_place >= orig_base_value_place -4) {
                if(current_base_value_place > 0)
                  bv = bv_table[--current_base_value_place][1];
                else
                  bv = decreased_bv_table[-1-(--current_base_value_place)];
#ifdef DEBUG
  fprintf(stderr,"    Place decreases one place to %i (started at %i)\n",
                        current_base_value_place, orig_base_value_place);
  fprintf(stderr,"    Value decreases one place to %f; roll again.\n",bv);
#endif
                goto inc_or_dec; 
              }

    } /* end switch */;

try_again:
    prop = die_roll(14)-1;
    if(strlen(properties[orig_base_value_place][prop][0]) == 0)
      goto try_again;
#ifdef DEBUG
  fprintf(stderr,"  Prop = %i\n",prop);
#endif

    fprintf(outfile,"%3i  %6.0f  %s\n",
      i,
      bv, 
      properties[orig_base_value_place][prop][0]);

    total = total + bv;

  } /* end for i */
  fprintf(outfile,"\nTotal: %f\n",total);

}; /* end proc random_gems */

main(argc,argv)
int argc;
char **argv;
{
  int num_gems;
  int base_value;

  if((argc != 2) && (argc != 3)) {
    fprintf(stderr,"Randomly determines the properties of gems.\n");
    fprintf(stderr,"\n");
    fprintf(stderr," usage: %s number [base-value]\n",argv[0]);
    fprintf(stderr,"   where 'number' is the number of gems desired\n");
    fprintf(stderr,"         'base-value' is [optional] base value in GP\n");
    fprintf(stderr,"           (default base-value is random)\n",
             '%','%');
    fprintf(stderr,"\n  Examples: %s 318      (generates 318 random gems)\n",
             argv[0]);
    fprintf(stderr,"            %s 12 100   (generates 12 gems, base 100 GPV)\n",argv[0]);
    exit(0);
  }

  num_gems = atoi(argv[1]);

  if(argc==3)
    base_value = atoi(argv[2]);
  else
    base_value = 0;

  /* seed random generator, may require system dependant command if
   * time(0) does not work, or might need to use a scanf to get seed */
  srand(time(0));

  random_gems(num_gems, base_value, stdout);

} /* end main */
