#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 2 (of 2)."
# Contents:  mkchar.c
# Wrapped by hgb@catalina on Thu Jan 23 13:11:35 1997
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'mkchar.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'mkchar.c'\"
else
echo shar: Extracting \"'mkchar.c'\" \(31582 characters\)
sed "s/^X//" >'mkchar.c' <<'END_OF_FILE'
X/*	mkchar.c
X
X	--Albedo character generator version 1.2.1--
X
X	You may use the mkchar program and modify the source code
X	for your own purposes given that the following conditions
X	are met:
X
X	1.) This notice must remain in the source code
X	2.) You may not sell the program or source code
X
X	Albedo and its associated tables are Copyright 1993, Steve Gallacci
X	and Paul Kidd, Thoughts & Images. This program is offered with the
X	understanding that it will be used to assist in the Albedo RolePlaying
X	Game.
X
X	I would appreciate any new versions you make based on this code.
X
X	Version 1.0	 4-Jan-95	hgb@catalina.opt-sci.arizona.edu
X	Version 1.1	 7-Jan-95	Limited career choices - Admin, Starship
X					Ground, 
X	Version 1.1.1	14-Feb-95	Added default skills for Expertise -
X					which all characters have.
X	Version 1.1.2	20-Dec-95	Changed rules for generating PCs. 
X	Version 1.1.3	20-Dec-95	Broke out Engineering choices.
X	Version 1.2.0	24-Dec-95	Added Career Selection
X	Version 1.2.1	23-Aug-96	HTML and PC code by corps@ts.umu.se
X	Version 1.3	23-Jan-96	Generates a PostScript file
X*/
X
X#include <stdio.h>
X#include <stdlib.h>
X#ifdef MSC
X#include <string.h>
X#endif
X#ifdef SYSV
X#include <string.h>
X#endif
X#ifdef BSD
X#include <strings.h>
X#endif
X#include <time.h>
X#include "albedo.h"
X
X/*#define SPACING		1 */
X/*#define SPACING1		1 */
X
Xint Html	= 0;		/* Do NOT generate HTML-code as default */
Xint PC		= 0;		/* Generate an NPC as default           */
X
Xint main(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	time_t t;
X	int i, k, offset, numchar;
X	int Done;
X	int HaveSpecies;
X	int HaveCareer;
X	char token[40];
X	int new_spe_num, cur_spe_num;  
X	int new_career, cur_career;
X	int Species_find(), Career_find();
X	extern int NoCareers;
X	extern int CareerType;
X	extern int NoSkills;
X	extern int NoEngineeringSkills;
X	extern Career_List Careers[];
X/*
X	Check for a usage request.
X*/
X	if (argc == 1 ) {
X		usage();
X		exit(1);
X	}
X/*
X	Initialize the randomizer and other variables
X*/
X	srand((unsigned) time(&t));
X	cur_spe_num = -1;
X	new_spe_num = -1;
X	cur_career = -1;
X	new_career = -1;
X	CareerType = 0;
X	HaveSpecies = 0;
X	HaveCareer = 0;
X	offset = 0;
X	Done = 1;
X/*
X	Count the number of careers at the moment - this is used in the
X	random career chooser.
X*/
X	for( NoCareers = 0; Careers[NoCareers].C_name[0] != '\0'; NoCareers++) ;
X	for( NoSkills = 0; Skills[NoSkills].skill_name[0] != '\0'; NoSkills++) ;
X	for( NoEngineeringSkills = 0;
X		EngineeringSkills[NoEngineeringSkills].skill_name[0] != '\0';
X		NoEngineeringSkills++) ;
X/*
X	Parse the command line. We assume that numbers will follow the Species
X	token. If any numbers appear without a new Species being set, we will
X	use the previous Species. Should no Species be set initially, we 
X	generate a Species. There is also the chance of a career choice.
X*/
X	for( argc--, argv++; argc > 0; argc--, argv++) {
X		strncpy( token, argv[0], 40);
X		if( token[0] == '-') {
X			if( islower( token[1])) token[1] = toupper( token[1]);
X			if(( strcmp( token, "-P")) == 0)
X				PC = 1;
X			if(( strcmp( token, "-H")) == 0)
X				Html = 1;
X			if(( strcmp( token, "-Admin")) == 0)
X				CareerType = ADMIN;
X			if(( strcmp( token, "-Starship")) == 0)
X				CareerType = MIL_SPACE;
X			if(( strcmp( token, "-Ground")) == 0)
X				CareerType = MIL_GROUND;
X			continue;
X		}
X		if(( numchar = atoi( token)) != 0) {
X/*
X	The numchar is not a species - take it as the number of characters to
X	create and do it. Flag that we've finished with the currect pair. We
X	don't care if there is a species or not as we'll just generate it if
X	needed.
X*/
X			if( Done == 1) {
X			  for( k = 0; k < numchar; k++) {
X				Gen_Albedo_Char( cur_career, cur_spe_num, 1);
X			  }
X			} else {
X			  Gen_Albedo_Char( cur_career, cur_spe_num, numchar);
X			}
X			HaveSpecies = 0;
X			HaveCareer = 0;
X			Done = 1;
X		} else {
X/*
X	Token is a Species or Career name. First, search the tables and try
X	to match the name.  Check what we already have and if necessary,
X	force a character generation - if we have a species and a new species,
X	for example. Assume that numchar is 1 and do it. Ordinarily, we'd
X	wait for the number, but ...
X*/
X			if( islower( token[0])) token[0] = toupper( token[0]);
X			new_spe_num = Species_find( token);
X			if( new_spe_num == -1) {
X				new_career = Career_find( token,
X					&offset, argc, argv);
X				if( offset == 1) {
X					argc--; 
X					argv++;
X				}
X				if( offset == 2) {
X					argc--; argc--;
X					argv++; argv++;
X				}
X			} else new_career = -1;
X			if( new_spe_num != -1 && HaveSpecies) {
X			  numchar = 1;
X			  Gen_Albedo_Char( cur_career, cur_spe_num, numchar);
X			  HaveSpecies = 0;
X			  HaveCareer = 0;
X			  Done = 1;
X			}
X			if( new_career != -1 && HaveCareer) {
X			  numchar = 1;
X			  Gen_Albedo_Char( cur_career, cur_spe_num, numchar);
X			  HaveSpecies = 0;
X			  HaveCareer = 0;
X			  Done = 1;
X			}
X/*
X	That takes care of the things undone. Flag that we've got a species
X	name on the list - and are looking for a number.
X*/
X			if( new_spe_num != -1) {
X				cur_spe_num = new_spe_num;
X				HaveSpecies = 1;
X				Done = 0;
X			}
X			if( new_career != -1) {
X				cur_career = new_career;
X				HaveCareer = 1;
X				Done = 0;
X			}
X/*
X	No such things in the list. Make the user aware and cross it off the
X	list.
X*/
X			if( new_spe_num == -1 && new_career == -1) {
X			  printf("'%s' couldn't be found.\n", token);
X			  printf("Check the spelling and try again.\n");
X			  continue;
X			}
X		} 
X	}
X/*
X	Check if there's anything leftover - a species name, for example. Do it.
X*/
X	if( HaveSpecies || HaveCareer ) {
X		Gen_Albedo_Char( cur_career, cur_spe_num, 1);
X	}
X	return(0);
X}
X/*
X	Gen_Albedo_Char
X
X	This routine creates an Albedo character, based on the species requested.
X	It is almost completely random and arbitary. 
X
X	Version 1.0	 4-Jan-95	hgb@catalina.opt-sci.arizona.edu
X					Creates only characteristics.
X					And base skills
X	Version 1.1	20-Dec-95	hgb@catalina.opt-sci.arizona.edu
X					Save the first character in a file
X					for printing.
X	Version 1.2	22-Dec-95	Hooks for career specification.
X*/
XGen_Albedo_Char( cur_career, cur_spe_num, numchar)
Xint cur_career;
Xint cur_spe_num;
Xint numchar;
X{
X	extern Character MyChar;
X	extern int CareerType;
X	int i;
X	int career_index, Gen_Career();
X	int spe_num, Gen_Albedo_Species();
X	void Skill_Set();
X	FILE *fopen(), *fp;
X
X	for( i = 0; i < numchar; i++) {
X		if( cur_spe_num == -1) {
X			spe_num = Gen_Albedo_Species();
X		} else {
X			spe_num = cur_spe_num;
X		}
X		strcpy( MyChar.c_species, Species[spe_num].spe_name);
X		strcpy( MyChar.c_frame, Species[spe_num].spe_frame);
X		Gen_Albedo_Stats( spe_num);
X		Gen_Dispositions();
X		Skill_Set();
X		Gen_Basic_Skills();
X		career_index = Gen_Career( CareerType, cur_career);
X		Gen_Extra_Skills( career_index, EXTRA_POINTS );
X		PrintChar(stdout);
X		DumpSkill(stdout);
X		if( i == 0) {
X			fp = fopen( "albedo.cha", "w");
X			if( fp != NULL) {
X				PrintChar( fp);
X				DumpSkill( fp);
X				fclose( fp);
X			}
X			pspage( "albedo.ps");
X		}
X	}
X}
X/*
X	Gen_Albedo_Stats
X
X	This routine creates the Albedo stats, based on the species requested.
X	It tries for a best fit, generating the stats randomly and adding the
X	costs. Exceeding or being under the limits causes it to re-try another
X	set. MAX_POINTS and MIN_POINTS are defined to produce characters 
X	around 40 points - this may be redefined.
X
X	Version 1.0	4-Jan-95	hgb@catalina.opt-sci.arizona.edu
X					Creates only characteristics.
X	Version 1.1	4-Jan-95	Generate large D6 roll and divide
X					down to center the curve.
X*/
XGen_Albedo_Stats( n)
Xint n;		/* The number into the Species table */
X{
X	extern Character MyChar;
X	extern CharCosts[8][7];
X	int Stats[8];
X	int StatCosts[8];
X	int total;
X	int level;
X	int i, die, k;
X	int die_total;
X	int try;
X
X	try = 0;
X	while(1) {
X		if( ++try > 50) {
X			printf(" Unable to find a set of stats in 50 tries\n");
X			exit(0);
X		}
X		total = 0;
X		for( i = 0; i < 8; i++) {
X			die = D7();
X			switch(i) {
X				case	0:	
X					level = Species[n].spe_str; break;
X				case	1:
X					level = Species[n].spe_sta; break;
X				case	2:
X					level = Species[n].spe_mdex; break;
X				case	3:
X					level = Species[n].spe_crd; break;
X				case	4:
X					level = Species[n].spe_rea; break;
X				case	5:
X					level = Species[n].spe_int; break;
X				case	6:
X					level = Species[n].spe_driv; break;
X				case	7:
X					level = Species[n].spe_stab; break;
X			}
X			total += CharCosts[0][die];
X			StatCosts[i] = CharCosts[0][die];
X			Stats[i] = CharCosts[level][die];
X			if( total > MAX_POINTS) break; 
X		}
X		if( total <= MAX_POINTS && total >= MIN_POINTS ) break; 
X		
X	}
X/*
X	We have a good character. Now, begin to fill the character structure.
X*/
X	MyChar.c_str = Stats[0];
X	MyChar.c_sta = Stats[1];
X	MyChar.c_mdex = Stats[2];
X	MyChar.c_crd = Stats[3];
X	MyChar.c_rea = Stats[4];
X	MyChar.c_int = Stats[5];
X	MyChar.c_driv = Stats[6];
X	MyChar.c_stab = Stats[7];
X/*
X	Computed stats
X*/
X	if( MyChar.c_str <= 4)	MyChar.recoil_number = 1; 
X	else if( MyChar.c_str >= 5 && MyChar.c_str <= 7)
X			MyChar.recoil_number = 2;
X	else if( MyChar.c_str >= 8 && MyChar.c_str <= 11)
X			MyChar.recoil_number = 3;
X	else if( MyChar.c_str >= 12 && MyChar.c_str <= 13)
X			MyChar.recoil_number = 4;
X	else MyChar.recoil_number = 5;
X/* */
X	MyChar.max_fatigue = MyChar.c_sta * 3;
X	MyChar.cur_fatigue = MyChar.c_sta * 3;
X/* */
X	MyChar.dam_mods = 2;	/* Small */
X	if( strcmp( MyChar.c_frame, "Light") == 0 ) MyChar.dam_mods = 1;
X	if( strcmp( MyChar.c_frame, "Average") == 0 ) MyChar.dam_mods = 0;
X	if( strcmp( MyChar.c_frame, "Solid") ==  0) MyChar.dam_mods = -1;
X	if( strcmp( MyChar.c_frame, "Huge") == 0 ) MyChar.dam_mods = -2;
X/* */
X	MyChar.str_mods = -4;
X	if( MyChar.c_str >= 5 && MyChar.c_str <= 9) MyChar.str_mods = -2;
X	if( MyChar.c_str >= 10 && MyChar.c_str <= 14) MyChar.str_mods = 0;
X	if( MyChar.c_str >= 15) MyChar.str_mods = 2;
X/* */
X	if( MyChar.c_crd < 3)	MyChar.actions_turn = 1; 
X	else if( MyChar.c_crd == 3 && MyChar.c_crd == 4) MyChar.actions_turn = 2;
X	else if( MyChar.c_crd >= 5 && MyChar.c_crd <= 8) MyChar.actions_turn = 3;
X	else if( MyChar.c_crd >= 9 && MyChar.c_crd <= 12)MyChar.actions_turn = 4;
X	else MyChar.actions_turn = 5;
X/* */
X	k = ((MyChar.c_int + MyChar.c_rea + MyChar.c_driv)* 10 )/10;
X	MyChar.SPI = ((double) k) / 10.0;
X/*
X	Determine the initiative dice
X*/
X	level = MyChar.c_int;
X	if( level < 8)  { strcpy( MyChar.init_dice, "1D6-1");
X	} else if( level < 11) { strcpy( MyChar.init_dice, "1D6");
X	} else if( level < 13) { strcpy( MyChar.init_dice, "1D6+1");
X	} else { strcpy( MyChar.init_dice, "3D3"); }
X	MyChar.self_im_low = MyChar.c_driv / 2;
X	MyChar.self_im_high = MyChar.c_driv + MyChar.self_im_low;
X	MyChar.self_im_cur = MyChar.c_driv;
X	MyChar.Mil = 1;
X}
X/*
X	Gen_Albedo_Species
X
X	This routine generates a random Species for the new character, using
X	a table originally printed in the first edition Albedo referee book.
X
X	Version 1.0	4-Jan-95	hgb@catalina.opt-sci.arizona.edu
X				
X	Version 1.1	22-Dec-95	Don't need Species name returned.
X*/
Xint Gen_Albedo_Species()
X{
X	int i;
X	int die;
X	char species[20];
X
X	die = rand() % 100 + 1;
X	i = 0;
X	while( die > RandSpe[i].next_percent ) i++;
X	strcpy( species, RandSpe[i].ran_species);
X	for( i = 0; Species[i].spe_name[0] != '\0'; i++) {
X		if( strcmp( Species[i].spe_name, species) == 0) {
X			return(i);
X		}
X	}
X/*
X	Default case - if there is an error. Fox, I think.
X*/
X	return(11);
X}
X/*
X
X	Generate the character's Core and Inclination Dispositions. Adjust
X	the character's SPI if needed. Mark EDF_OK if there is a disorder.
X
X*/
XGen_Dispositions( )
X{
X	int Core, Incl;
X
X	Core = D20();
X	Incl = D20();
X	if (PC)
X	{
X		Core /= 2;
X		Incl /= 2;
X		if( Core == Incl) Core++;
X	}
X
X/*
X	If this happens, the character has an Disorder. Find the Disorder
X	and remove the flag that allows EDF and Homeguard service.
X*/
X	if( Core == Incl)  {		
X		if(( rand() % 2 + 1) == 1) {
X			Incl = D20() + 20;
X		} else {
X			Core = D20() + 20;
X		}
X		MyChar.SPI = MyChar.SPI - 0.8;
X		MyChar.Mil = 0;
X	}
X	if( Core >= 10 && Core <= 19) MyChar.SPI = MyChar.SPI - 0.2;
X	if( Incl >= 10 && Incl <= 19) MyChar.SPI = MyChar.SPI - 0.2;
X	strcpy( MyChar.disposition_core, Disposition[Core]);
X	strcpy( MyChar.disposition_incl, Disposition[Incl]);
X}
X/*
X *
X *	Skills handling - a seperate part of mkchar, a table of skills is
X *	filled out. Chosen skills can be printed out if needed.
X */
X
X/*
X	The Generic skills that every character begins with. No SPI credits
X	or costs are evaluated.
X*/
XGen_Basic_Skills()
X{
X	double SPindex;
X	int costs;
X	int Skill_up();
X	extern Character MyChar;
X	int die, i;
X/*
X	These are really the default skills
X*/
X	costs = Skill_up( "Literacy", 20, &SPindex);
X	costs = Skill_up( "Melee (Armed)", 20, &SPindex);
X	costs = Skill_up( "Melee (Unarmed)", 20, &SPindex);
X	costs = Skill_up( "Sm Ground Vehicle Driver", 20, &SPindex);
X	costs = Skill_up( "Sneaking", 20, &SPindex);
X/*
X	This is not according to the book - but in a game where combat
X	may occur, characters SHOULD have at least one ranged combat skill.
X	Comment out if you wish characters generated as per the book.
X*/
X	costs = Skill_up( "Handguns", 20, &SPindex);
X/*
X	Now, we must choose between 3 family backgrounds
X*/
X	die = rand() % 3 + 1;
X	switch( die) {
X		case 1:
X			strcpy( MyChar.background, "Military");
X			costs = Skill_up( "Current Affairs", 20, &SPindex);
X			costs = Skill_up( "Law", 20, &SPindex);
X			costs = Skill_up( "Political Science", 20, &SPindex);
X			break;
X		case 2:
X			strcpy( MyChar.background, "Institutional");
X			costs = Skill_up( "Literacy", 20, &SPindex);
X			costs = Skill_up( "Higher Mathematics", 20, &SPindex);
X			costs = Skill_up( "Research", 20, &SPindex);
X			break;
X		case 3:
X			strcpy( MyChar.background, "Clan/Family");
X			costs = Skill_up( "Literacy", 20, &SPindex);
X			if( D6()/3 == 1)
X				costs = Skill_up( "Current Affairs",20,&SPindex);
X			else
X				costs = Skill_up( "Socio-History",20,&SPindex);
X			if( D6()/3 == 1)
X				costs = Skill_up( "Art",20,&SPindex);
X			else
X				costs = Skill_up( "Musician",20,&SPindex);
X			break;
X	}
X/*
X	Finally, we must choose 3 skills from the SOCIAL and MOVE_PERCEP
X	lists.
X*/
X	for( i = 0; i < 3; i++) {
X		die = D6();
X		switch( die) {
X			case 1:
X				costs = Skill_up( "Art",20,&SPindex);
X				if( costs == 0) i--;
X				break;
X			case 2:
X				costs = Skill_up( "Current Affairs",20,&SPindex);
X				if( costs == 0) i--;
X				break;
X			case 3:
X				costs = Skill_up( "Leadership",20,&SPindex);
X				if( costs == 0) i--;
X				break;
X			case 4:
X				costs = Skill_up( "Literacy",20,&SPindex);
X				if( costs == 0) i--;
X				break;
X			case 5:
X				costs = Skill_up( "Musician",20,&SPindex);
X				if( costs == 0) i--;
X				break;
X			case 6:
X				costs = Skill_up( "Dancing",20,&SPindex);
X				if( costs == 0) i--;
X				break;
X		}
X	}
X	for( i = 0; i < 3; i++) {
X		die = rand() % 5 + 1;
X		switch( die) {
X			case 1:
X				costs = Skill_up( "Climbing",20,&SPindex);
X				if( costs == 0) i--;
X				break;
X			case 2:
X				costs = Skill_up( "Coolness under Fire",20,
X					&SPindex);
X				if( costs == 0) i--;
X				break;
X			case 3:
X				costs = Skill_up( "Sneaking",20,&SPindex);
X				if( costs == 0) i--;
X				break;
X			case 4:
X				costs = Skill_up( "Swimming",20,&SPindex);
X				if( costs == 0) i--;
X				break;
X			case 5:
X				costs = Skill_up( "Zero-G Movement",20,&SPindex);
X				if( costs == 0) i--;
X				break;
X		}
X	}
X}
X/*
X	Find a career for the new character. Note, this does not reflect the
X	number of animals with this career in the Albedo universe - the 
X	program may generate mostly Diplomats if you're unlucky.
X
X	If cur_career is not -1, then we'll create one randomly.
X
X	It returns the index for the list of skills that can be bought
X	with the 20 or 40 or 60 experience points.
X*/
Xint
XGen_Career(Cr_Type, cur_career)
Xint Cr_Type;
Xint cur_career;
X{
X	extern int NoCareer;
X	extern Career_List Careers[];
X	extern Character MyChar;
X	extern Skill_list Skills[];
X	int i, k;
X	int costs;
X	int thiskind;
X	double theSPI;
X/*
X	If no career has been selected, generate one
X*/
X	if( cur_career == -1) {
X		i = rand() % NoCareers;
X/*
X	Check if the chosen career is the right one. Ignore SPI checks.
X*/
X		if( Cr_Type != 0) {
X			thiskind = Careers[i].Other_list;
X			while( thiskind != Cr_Type) {
X				i = rand() % NoCareers;
X				thiskind = Careers[i].Other_list;
X			}
X/*
X	Check if the character is allowed this career - check SPI!
X*/
X		 } else {
X			theSPI = Careers[i].minSPI;
X			while( theSPI > MyChar.SPI) {
X				i = rand() % NoCareers;
X				theSPI = Careers[i].minSPI;
X			}
X		}
X/*
X	If it is specified, ignore all those tests and just do it
X*/
X	} else {
X		i = cur_career;
X	}
X/*
X	OK, the character can have this career. Now, note it and do the
X	Skill up's. Note: Advanced Education is a bit different - see
X	the second part of the function. We need to pick 3 random KNOWLEDGE
X	skills from the list.
X*/
X	strcpy( MyChar.career, Careers[i].C_name);
X	if( strcmp( Careers[i].C_pskill, "Knowledge") != 0) {
X		costs = Skill_up( Careers[i].C_pskill, 20, &theSPI);
X		MyChar.SPI = MyChar.SPI + theSPI;
X		costs = Skill_up( Careers[i].C_pskill, 20, &theSPI);
X		MyChar.SPI = MyChar.SPI + theSPI;
X		costs = Skill_up( Careers[i].C_1skill, 20, &theSPI);
X		MyChar.SPI = MyChar.SPI + theSPI;
X		costs = Skill_up( Careers[i].C_2skill, 20, &theSPI);
X		MyChar.SPI = MyChar.SPI + theSPI;
X	} else {
X		k = rand() % NoSkills;
X		while( Skills[k].skill_type != KNOWLEDGE) {
X			k = rand() % NoSkills;
X		}	
X		costs = Skill_up( Skills[k].skill_name, 20, &theSPI);
X		MyChar.SPI = MyChar.SPI + theSPI;
X		costs = Skill_up( Skills[k].skill_name, 20, &theSPI);
X		MyChar.SPI = MyChar.SPI + theSPI;
X
X/*
X	That is the primary knowledge skill. Now, for the two secondary skills.
X*/
X		k = rand() % NoSkills;
X		while( Skills[k].skill_type != KNOWLEDGE) {
X			k = rand() % NoSkills;
X		}	
X		costs = Skill_up( Skills[k].skill_name, 20, &theSPI);
X		MyChar.SPI = MyChar.SPI + theSPI;
X		k = rand() % NoSkills;
X		while( Skills[k].skill_type != KNOWLEDGE) {
X			k = rand() % NoSkills;
X		}	
X		costs = Skill_up( Skills[k].skill_name, 20, &theSPI);
X		MyChar.SPI = MyChar.SPI + theSPI;
X	}
X	return( Careers[i].Other_list);
X}
X/*
X
X	Generate the extra skills bought through the 'points' experience
X	points. Each career has a pool of available skills indexed by
X	the parameter index. If there are not enough points to buy the
X	skill, go on to the next. Skill_up if there are enough points.
X*/
XGen_Extra_Skills( index, points)
Xint index;
Xint points;
X{
X	int costs, i,  Skill_up();
X	double theSPI;
X	extern char Admin[ADMIN_CHOICE][S_LEN];
X	extern char Research[RESEARCH_CHOICE][S_LEN];
X	extern char Mil_Space[MIL_SPACE_CHOICE][S_LEN];
X	extern char Mil_Ground[MIL_GROUND_CHOICE][S_LEN];
X	extern char Tech[TECH_CHOICE][S_LEN];
X	extern char Other[OTHER_CHOICE][S_LEN];
X
X	while( points > 0) {
X		costs = 0;
X		theSPI = 0.0;
X		switch( index) {
X		case ADMIN:	
X				i = rand() % ADMIN_CHOICE;
X				costs = Skill_up( Admin[i], points, &theSPI);
X				break;
X		case RESEARCH:	
X				i = rand() % RESEARCH_CHOICE;
X				costs = Skill_up( Research[i], points, &theSPI);
X				break;
X		case MIL_SPACE:	
X				i = rand() % MIL_SPACE_CHOICE;
X				costs = Skill_up( Mil_Space[i], points, &theSPI);
X				break;
X		case MIL_GROUND:
X				i = rand() % MIL_GROUND_CHOICE;
X				costs = Skill_up( Mil_Ground[i], points, &theSPI);
X				break;
X		case TECH:
X				i = rand() % TECH_CHOICE;
X				costs = Skill_up( Tech[i], points, &theSPI);
X				break;
X		case OTHER:
X				i = rand() % OTHER_CHOICE;
X				costs = Skill_up( Other[i], points, &theSPI);
X				break;
X		}
X		if( costs != 0) {
X			points = points - costs;
X			MyChar.SPI = MyChar.SPI + theSPI;
X		}
X	}
X}
X/*
X	Career_find
X
X	Look through the career list and try to match what the user
X	asked for. Once a name matches, return the index into the table.
X	If nothing matches, return a -1 error.
X*/
Xint Career_find( token, offset, argc, argv)
Xchar *token;
Xint *offset;
Xint argc;
Xchar **argv;
X{
X	int i;
X	char dtok[40];
X	char ttok[40];
X	
X	dtok[0] = '\0';
X	ttok[0] = '\0';	
X	*offset = 0;
X	for( i = 0; Careers[i].C_1st_match[0] != '\0'; i++) {
X		if( strcmp( Careers[i].C_1st_match, token) == 0) {
X		   if( Careers[i].C_2nd_match[0] != '\0') {
X			if( argc > 1) strncpy( dtok, *(argv+1), 40);
X			if( islower( dtok[0])) dtok[0] = toupper( dtok[0]);
X			if( strcmp( Careers[i].C_2nd_match, dtok) == 0) {
X			   if( Careers[i].C_3rd_match[0] != '\0') {
X		    		if( argc > 2) strncpy( ttok, *(argv+2), 40);
X				if( islower( ttok[0]))
X					ttok[0] = toupper( ttok[0]);
X				if( strcmp( Careers[i].C_3rd_match, ttok)== 0){
X					*offset = 2;
X					return(i);
X				}			/* no match 3rd part */
X				continue;
X			  } else { 			/* null 3rd part */
X				*offset = 1;
X				return(i);
X			  }
X			}				/* no match 2nd part */
X			continue;
X		} else {				/* null 2nd part */
X			*offset = 0;
X			return(i);
X		}
X	    }						/* no match 1st part */
X	}
X	return(-1);
X}
X/*
X	Species_find
X
X	Look through the species list and try to match what the user
X	asked for. Once a name matches, return the index into the table.
X	If nothing matches, return a -1 error.
X*/
Xint Species_find( token)
Xchar *token;
X{
X	int i;
X
X	for( i = 0; Species[i].spe_name[0] != '\0'; i++) {
X		  if( strcmp( Species[i].spe_name, token) == 0) return(i);
X	}
X	return(-1);
X}
X/*
X	Given a name of a skill, it returns the index. A -1 means it 
X	could not be found in the table.
X*/
Xint
XSkill_find( skill)
Xchar skill[S_LEN];
X{
X
X	extern Skill_list Skills[];
X	int i;
X
X	for( i = 0; Skills[i].skill_name[0] != '\0'; i++ ) {
X		if( strcmp( Skills[i].skill_name, skill) == 0)
X			return(i);
X	}
X	printf(" Looked for %s - could not find\n", skill);
X	return( -1);
X}
X/*
X	Given a skill and the number of points still available, try to up
X	the skill level. It can go up to 3 (Master level). A cost of zero
X	is returned if the program cannot up the skill. Note - points must
X	be adjusted in the calling routine. The spi adjustments are returned
X	through a pointer. If the SPI is to be adjusted, it also must be
X	adjusted in the calling routine.
X
X	Modified for the Systems Engineering special case - one of a set
X	of specialities must be picked.
X*/
Xint
XSkill_up( skill, points, spi)
Xchar skill[S_LEN];
Xint points;
Xdouble *spi;
X{
X	extern Skill_list Skills[];
X	extern Skill_list EngineeringSkills[];
X	int cost;
X	int i;
X	int k;
X	int Skill_find();
X
X	cost = 0;
X	*spi = 0.0;
X	if( strcmp( skill, "Systems Engineering") == 0) {
X		i = rand() % NoEngineeringSkills;
X		strcpy( skill, EngineeringSkills[i].skill_name);
X	}
X	if(( i =  Skill_find( skill)) == -1) return(cost);
X/*
X	Skillful/ Expertise
X*/
X	if( Skills[i].skill_chosen == 0) {
X		cost = ( Skills[i].skill_type == EXPERTISE)? 1 : 2;
X		if( (points - cost ) > 0) {
X			Skills[i].skill_chosen = 1;
X			*spi = 0.1;
X			if( Skills[i].skill_type == EXPERTISE)
X				Skills[i].skill_value = Skills[i].skill_value + 2;
X		}
X		return( cost);
X/*
X	Adept / Great Expertise
X*/
X	} else if( Skills[i].skill_chosen == 1) {
X		cost = ( Skills[i].skill_type == EXPERTISE)? 3 : 5;
X		if( (points - cost ) > 0) {
X			Skills[i].skill_chosen = 2;
X			*spi = 0.2;
X			Skills[i].skill_value = Skills[i].skill_value + 5;
X		}
X		return( cost);
X/*
X	Master / Exceptional Expertise
X*/
X	} else if( Skills[i].skill_chosen == 2) {
X		cost = ( Skills[i].skill_type == EXPERTISE)? 10 : 15;
X		if( (points - cost ) > 0) {
X			Skills[i].skill_chosen = 3;
X			*spi = 0.3;
X			Skills[i].skill_value = Skills[i].skill_value + 5;
X		}
X		return( cost);
X	} else return(0);
X}
X/*
X	Set all the values in the skill list to their default values. This
X	means computing the various sets of attributes and then inserting
X	them into the table. It assumes that MyChar's attributes have already
X	been defined.
X*/
Xvoid
XSkill_Set()
X{
X	int i, k;
X	int Attr[16];
X	extern Character MyChar;
X	extern Skill_list Skills[];
X/*
X	Start with the set of attributes.
X*/
X	Attr[STR] = MyChar.c_str;
X	Attr[STA] = MyChar.c_sta;
X	Attr[MDEX] = MyChar.c_mdex;
X	Attr[CRD] = MyChar.c_crd;
X	Attr[REA] = MyChar.c_rea;
X	Attr[INTU] = MyChar.c_int;
X	Attr[STAB] = MyChar.c_stab;
X	Attr[DRIV] = MyChar.c_driv;
X	Attr[SELF] = MyChar.self_im_cur;
X	Attr[INTU_MDEX] = (MyChar.c_int + MyChar.c_mdex) /2;
X	Attr[INTU_CRD] = (MyChar.c_int + MyChar.c_crd) /2;
X	Attr[INTU_REA] = (MyChar.c_int + MyChar.c_rea) /2;
X	Attr[INTU_DRIV] = (MyChar.c_int + MyChar.c_driv) /2;
X	Attr[STR_CRD] = (MyChar.c_str + MyChar.c_crd) /2;
X	Attr[REA_MDEX] = (MyChar.c_rea + MyChar.c_mdex) /2;
X	Attr[REA_DRIV] = (MyChar.c_rea + MyChar.c_driv) /2;
X
X	for( i = 0; Skills[i].skill_name[0] != '\0'; i++ ) {
X		k = Skills[i].skill_attr;
X		Skills[i].skill_value = Attr[k];
X		Skills[i].skill_chosen = 0;
X	}
X}
X/*
X	Return a dice roll (D6) - this is the dice used almost all of the
X	time in Albedo.
X*/
Xint D6()
X{
X	int die;
X	die = rand() % 6 + 1;
X	return die;
X}
X/*
X	Return a dice roll (D7 - 1) - this creates entries in the 
X	character costs table to generate stats.
X*/
Xint D7()
X{
X	int die;
X	die = rand() % 7; 
X	return die;
X}
X/*
X	Return a dice roll (D20) - this is used to determine both Core
X	Disposition and Inclination Dispostion.
X*/
Xint D20()
X{
X	int die;
X	die = rand() % 20;
X	return die;
X}
XDumpSkill(fp)
XFILE *fp;
X{
X	extern Character MyChar;
X	extern Skill_list Skills[];
X	char buf[41], fmt[41];
X	static int char_count = 0;
X	int fold;
X	int i;
X	int j;
X	int k;
X
X	fmt[39] = '\0';
X	for( i = 0, fold = 0; Skills[i].skill_name[0] != '\0'; i++ ) {
X	  switch( Skills[i].skill_chosen) {
X	  case 0:
X		if( Skills[i].skill_type == EXPERTISE) {
X			sprintf(buf,"%s %d", Skills[i].skill_name,
X				Skills[i].skill_value);
X			if( PC &&  fp != stdout)
X				Skills[i].skill_chosen = 10;
X		}
X		break;
X	  case 1:
X		sprintf(buf,"%s %d", Skills[i].skill_name,
X			Skills[i].skill_value);
X		break;
X	  case 2:
X		sprintf(buf,"%s (Adept) %d", Skills[i].skill_name,
X			Skills[i].skill_value);
X		break;
X	  case 3:
X		sprintf(buf,"%s (Master) %d", Skills[i].skill_name,
X			Skills[i].skill_value);
X		break;
X	  }
X/*
X	Format the strings into 40 character strings. Then fold them
X	into 2 columns.
X*/
X	  if( Skills[i].skill_chosen != 0) {
X		if (!Html)
X		{
X			k = strlen( buf);
X			for( j = 0; j < k; j++) fmt[j] = buf[j];
X			for( j = k; j < 39; j++) fmt[j] = ' ';
X			if( fold == 0) {
X				fprintf( fp, "%s", fmt); fold = 1;
X			} else {
X				fprintf( fp, "%s\n", fmt); fold = 0;
X			}
X			if( Skills[i].skill_chosen == 10)
X				Skills[i].skill_chosen = 0;
X	  	}
X		else
X		{
X			if (fold == 0) {
X				fprintf(fp, "<tr><td colspan=2>%s</td>", buf);
X				fold = 1;
X			} else {
X				fprintf(fp, "<td colspan=8>%s</td></tr>\n",
X					buf);
X				fold = 0;
X			}
X		}
X	  }
X	}
X	if (!Html) {
X		if( fold == 1) fprintf(fp, "\n");
X	} else {
X		fprintf(fp, "</table>\n<br><br>\n");
X	}
X#ifdef SPACING
X	fprintf(fp, "\014");
X#endif
X#ifdef SPACING1
X	char_count++;
X	if((char_count % 2) == 0)  {
X		fprintf(fp, "\014");
X	} else {
X		fprintf(fp, "\n\n\n\n\n\n\n\n\n");
X	}
X#endif
X	
X}	
XPrintChar(fp)
XFILE *fp;
X{
X	extern Character MyChar;
X	int i;
X	double max_ftiles;
X
X	if (!Html)
X	{
X		fprintf(fp, "\n");
X		fprintf(fp, "%-20s", MyChar.c_species);
X		fprintf(fp, "\t\t  Str  Sta  MDex Crd  Reas Intu Driv Stab\n");
X		fprintf(fp, "\t\t\t\t %4d %4d %4d %4d %4d %4d %4d %4d\n", 
X		  MyChar.c_str, MyChar.c_sta, MyChar.c_mdex, MyChar.c_crd,
X		  MyChar.c_rea, MyChar.c_int, MyChar.c_driv, MyChar.c_stab);
X		fprintf(fp, "%s, %s\n", MyChar.disposition_core,
X			MyChar.disposition_incl);
X		fprintf(fp, "Frame: %s", MyChar.c_frame);
X		fprintf(fp, "\t\tStr. Mods: %+2d", MyChar.str_mods);
X		fprintf(fp, "\t\tInjury Penalty: %+2d\n", MyChar.dam_mods);
X		fprintf(fp, "(%s)\t %s\t\tSPI: %3.1f\n",
X			 MyChar.background, MyChar.career, MyChar.SPI);
X		fprintf(fp, "Acts on Phase:");
X		switch( MyChar.actions_turn) {
X		case 1:		fprintf(fp, " 4\t\t\t\t"); break;
X		case 2:		fprintf(fp, " 3, 5\t\t"); break;
X		case 3:		fprintf(fp, " 2, 4, 6\t"); break;
X		case 4:		fprintf(fp, " 1, 3, 5, 6"); break;
X		case 5:		fprintf(fp, " 1, 2, 4, 5, 6"); break;
X		}
X		fprintf(fp, "\t\t\tInitiative Dice: %s\n", MyChar.init_dice);
X		max_ftiles = (double) (MyChar.max_fatigue)/6.0;
X		fprintf(fp, "Fatigue Levels:");
X		for( i = 6; i >= 1; i--) {
X			fprintf(fp, " %d", (int) (max_ftiles * (double) i));
X			if( i != 1) fprintf(fp, ",");
X		}
X		fprintf(fp, "\t\tMaximum Recoil: %d\n", MyChar.recoil_number);
X		fprintf(fp, "\n");
X	}
X	else
X	{
X		fprintf(fp, "<table border=1 width=100%%>\n");
X		fprintf(fp, "<tr><th>Race:</th><td width=50%%>%s</td>\n",
X			MyChar.c_species);
X		fprintf(fp, "<th width = 6%%>Str</th>");
X		fprintf(fp, "<th width = 6%%>Sta</th>\n");
X		fprintf(fp, "<th width = 6%%>MDex</th>");
X		fprintf(fp, "<th width = 6%%>Crd</th>\n");
X		fprintf(fp, "<th width = 6%%>Reas</th>");
X		fprintf(fp, "<th width = 6%%>Intu</th>\n");
X		fprintf(fp, "<th width = 6%%>Driv</th>");
X		fprintf(fp, "<th width = 6%%>Stab</th></tr>\n");
X		fprintf(fp, "<tr><th>Name:</th><td width=50%%><br></td>\n");
X		fprintf(fp, "<td width = 6%%>%d</td><td width = 6%%>%d</td>\n",
X			MyChar.c_str, MyChar.c_sta);
X		fprintf(fp, "<td width = 6%%>%d</td><td width = 6%%>%d</td>\n",
X			MyChar.c_mdex, MyChar.c_crd);
X		fprintf(fp, "<td width = 6%%>%d</td><td width = 6%%>%d</td>\n",
X			MyChar.c_rea, MyChar.c_int);
X		fprintf(fp, "<td width = 6%%>%d</td>",
X			MyChar.c_driv);
X		fprintf(fp, "<td width = 6%%>%d</td></tr>\n",
X			MyChar.c_stab);
X		fprintf(fp, "<tr><th>Disposition:</th>");
X		fprintf(fp, "<td colspan=9>%s, %s</td></tr>\n",
X			MyChar.disposition_core, MyChar.disposition_incl);
X		fprintf(fp, "<tr><th>Frame:</th><td>%s</td>\n",
X			MyChar.c_frame);
X		fprintf(fp, "<th colspan=4>Current Fatigue:</th>");
X		fprintf(fp, "<td colspan=4>%d</td></tr>\n",
X			MyChar.cur_fatigue);
X		fprintf(fp, "<tr><th>Str. Mods:</th><td>%+2d</td>\n",
X			MyChar.str_mods);
X		fprintf(fp, "<th colspan=4>Injury Penalty:</th>");
X		fprintf(fp, "<td colspan=4>%+2d</td></tr>\n",
X			MyChar.dam_mods);
X		fprintf(fp, "<tr><td>(%s)</td><td colspan = 7>%s</td>\n",
X			MyChar.background, MyChar.career);
X		fprintf(fp, "<th>SPI:</th><td>%3.1f</td></tr>\n",
X			MyChar.SPI);
X		fprintf(fp, "<tr><th colspan=10><hr></th></tr>\n");
X		fprintf(fp, "<tr><th>Acts on Phase:</th><td>");
X		switch( MyChar.actions_turn) {
X		case 1:         fprintf(fp, " 4"); break;
X		case 2:         fprintf(fp, " 3, 5"); break;
X		case 3:         fprintf(fp, " 2, 4, 6"); break;
X		case 4:         fprintf(fp, " 1, 3, 5, 6"); break;
X		case 5:         fprintf(fp, " 1, 2, 4, 5, 6"); break;
X		}
X		fprintf(fp, "</td><th colspan=4>Initiative Dice:</th>\n");
X		fprintf(fp, "<td colspan=4>%s</td></tr>\n", MyChar.init_dice);
X		fprintf(fp, "<tr><th colspan=10><hr></th></tr>\n");
X		fprintf(fp, "<tr><th>Maximum Recoil:</th><td>%d</td>\n",
X			MyChar.recoil_number);
X		max_ftiles = (double) (MyChar.max_fatigue)/6.0;
X		fprintf(fp, "<th colspan=4>Fatigue Levels:</th><td colspan=4>");
X		for( i = 6; i >= 1; i--) {
X			fprintf(fp, " %d", (int) (max_ftiles * (double) i));
X			if( i != 1) fprintf(fp, ",");
X		}
X		fprintf(fp, "</td></tr>\n");
X		fprintf(fp, "<tr><th colspan=10><hr></th></tr>\n");
X	}
X}
X/*
X*/
Xint usage()
X{
X  printf("\n\nmkchar [-H][-P][-Admin|-Starship|-Ground][Species][Career][n]\n\n");
X  printf("(V1.3.0)	Creates characters for the Albedo Role-Playing Game.\n");
X  printf("-H		Create HTML-type output\n");
X  printf("-P		Create characters that can be used as Player");
X	printf(" Characters\n");
X  printf("-Admin		The character will have an Administration");
X	printf(" career\n");
X  printf("-Starship	The character will have a Starship career\n");
X  printf("-Ground		The character will have a Military/Ground");
X	printf(" career\n");
X  printf(" Species -	The Species of the characters to be created.\n");
X  printf(" Career -	The Career of the characters to be created.\n");
X  printf(" n -		The number of characters to be generated.\n\n");
X  printf(" The default is 1 character; species and career are randomly");
X	printf(" determined.\n");
X  printf(" Two files are created - 'albedo.cha' saves the first character\n");
X  printf(" in ASCII format and - 'albedo.ps' saves the first character as\n");
X  printf(" a PostScript-formated character sheet.\n");
X}
X
END_OF_FILE
if test 31582 -ne `wc -c <'mkchar.c'`; then
    echo shar: \"'mkchar.c'\" unpacked with wrong size!
fi
# end of 'mkchar.c'
fi
echo shar: End of archive 2 \(of 2\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked both archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
