forked from silverwizard/CharGen
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
445 lines
12 KiB
445 lines
12 KiB
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
|
|
#include "chargen.h"
|
|
#include "character.h"
|
|
|
|
int dieroll(int num,int sides){
|
|
int total = 0;
|
|
for(num;num>0;num--){
|
|
total = total + arc4random_uniform(sides)+1;
|
|
}
|
|
return total;
|
|
}
|
|
|
|
void addLanguage(long lang){
|
|
if((lang & languages ) == 0){
|
|
languages = languages + lang;
|
|
}else{
|
|
addLanguage(exp2l(arc4random_uniform(15)));
|
|
}
|
|
}
|
|
|
|
void addProf(long prof){
|
|
if((prof & profs) == 0){
|
|
profs = profs + prof;
|
|
}else{
|
|
addProf(exp2l(arc4random_uniform(18)));
|
|
}
|
|
}
|
|
|
|
void classProfs(unsigned long* classprofs, int count, int num){
|
|
//Remove existing profs from the array
|
|
for(int i=0; i<=count;i++){
|
|
if((classprofs[i] & profs) != 0){
|
|
classprofs[i] = classprofs[count];
|
|
count--;
|
|
i = 0;
|
|
}
|
|
}
|
|
//Shuffle the array
|
|
for(int i=0; i<=count;i++){
|
|
int newpos = i + arc4random_uniform(count - i);
|
|
unsigned long local = classprofs[newpos];
|
|
classprofs[newpos] = classprofs[i];
|
|
classprofs[i]=local;
|
|
}
|
|
//Grab the first N elements, based on the class's value, but first, if we have more profs than available profs, get some random ones
|
|
if(num > count){
|
|
for(count;num > count;count--){
|
|
addProf(exp2l(arc4random_uniform(18)));
|
|
}
|
|
}
|
|
for(int i=0;i<=num;i++){
|
|
addProf(classprofs[num]);
|
|
}
|
|
}
|
|
|
|
void genClass(){
|
|
int c = arc4random_uniform(sizeof(classes)/sizeof(classes[0]));
|
|
class = classes[c];
|
|
switch(c){
|
|
case BARBARIAN:;
|
|
unsigned long barbskills[6] = {ANIMALHANDLING, ATHLETICS, INTIMIDATION, NATURE, PERCEPTION, SURVIVAL};
|
|
hp = 12 + mods[CON];
|
|
classProfs(barbskills, 6, 2);
|
|
break;
|
|
case BARD:;
|
|
addProf(exp2l(arc4random_uniform(18)));
|
|
addProf(exp2l(arc4random_uniform(18)));
|
|
addProf(exp2l(arc4random_uniform(18)));
|
|
strlcat(otherprofs, "Three Musical Instruments, ", sizeof(otherprofs));
|
|
hp = 8 + mods[CON];
|
|
break;
|
|
case CLERIC:;
|
|
unsigned long clericskills[5]= {HISTORY, INSIGHT, MEDICINE, PERSUASION, RELIGION};
|
|
classProfs(clericskills, 5, 2);
|
|
hp = 8 + mods[CON];
|
|
break;
|
|
case DRUID:;
|
|
unsigned long druidskills[8] = {ARCANA, ANIMALHANDLING, INSIGHT, MEDICINE, NATURE, PERCEPTION, RELIGION, SURVIVAL};
|
|
classProfs(druidskills, 8, 2);
|
|
strlcat(otherprofs, "Herbalism Kit, ", sizeof(otherprofs));
|
|
hp = 8 + mods[CON];
|
|
break;
|
|
case FIGHTER:;
|
|
unsigned long fighterskills[8] = {ACROBATICS, ANIMALHANDLING, ATHLETICS, HISTORY, INSIGHT, INTIMIDATION, PERCEPTION, SURVIVAL};
|
|
classProfs(fighterskills, 8, 2);
|
|
hp = 10 + mods[CON];
|
|
break;
|
|
case MONK:;
|
|
unsigned long monkskills[6] = {ACROBATICS, ATHLETICS, HISTORY, INSIGHT, RELIGION, STEALTH};
|
|
classProfs(monkskills, 6, 2);
|
|
strlcat(otherprofs, "Artisan Tool or Musical Instrument, ", sizeof(otherprofs));
|
|
hp = 8 + mods[CON];
|
|
break;
|
|
case PALADIN:;
|
|
unsigned long paladinskills[6] = {ATHLETICS, INSIGHT, INTIMIDATION, MEDICINE, PERSUASION, RELIGION};
|
|
classProfs(paladinskills, 6, 2);
|
|
hp = 10 + mods[CON];
|
|
break;
|
|
case RANGER:;
|
|
unsigned long rangerskills[8] = {ANIMALHANDLING, ATHLETICS, INSIGHT, INVESTIGATION, NATURE, PERCEPTION, STEALTH, SURVIVAL};
|
|
classProfs(rangerskills, 8, 3);
|
|
hp = 10 + mods[CON];
|
|
break;
|
|
case ROGUE:;
|
|
unsigned long rogueskills[11] = {ACROBATICS, ATHLETICS, DECEPTION, INSIGHT, INTIMIDATION, INVESTIGATION, PERCEPTION, PERFORMANCE, PERSUASION, SLEIGHTOFHAND, STEALTH};
|
|
classProfs(rogueskills, 11, 4);
|
|
strlcat(otherprofs, "Thieves tools, ", sizeof(otherprofs));
|
|
hp = 8 + mods[CON];
|
|
break;
|
|
case SORCERER:;
|
|
unsigned long sorcererskills[6] = {ARCANA, DECEPTION, INSIGHT, INTIMIDATION, PERSUASION, RELIGION};
|
|
classProfs(sorcererskills, 6, 2);
|
|
hp = 6 + mods[CON];
|
|
break;
|
|
case WARLOCK:;
|
|
unsigned long warlockskills[7] = {ARCANA, DECEPTION, HISTORY, INTIMIDATION, INVESTIGATION, NATURE, RELIGION};
|
|
classProfs(warlockskills, 7, 2);
|
|
hp = 8 + mods[CON];
|
|
break;
|
|
case WIZARD:;
|
|
unsigned long wizardskills[5] = {ARCANA, HISTORY, INVESTIGATION, MEDICINE, RELIGION};
|
|
classProfs(wizardskills, 5, 2);
|
|
hp = 6 + mods[CON];
|
|
break;
|
|
default:
|
|
fprintf(stderr, "Incorrect class was generated for some reason");
|
|
/* This should never happen */
|
|
}
|
|
}
|
|
|
|
void genRace(){
|
|
int r = arc4random_uniform(sizeof(races)/sizeof(races[0]));
|
|
race = races[r];
|
|
int subrace;
|
|
switch (r){
|
|
case DRAGONBORN:
|
|
addLanguage(DRACONIC);
|
|
stats[STR]+=2;
|
|
stats[CHA]+=1;
|
|
break;
|
|
case DWARF:
|
|
addLanguage(DWARVISH);
|
|
stats[CON]+=2;
|
|
subrace = arc4random_uniform(2);
|
|
if(subrace == 0){
|
|
race = "Hill Dwarf";
|
|
stats[WIS]+=1;
|
|
}else{
|
|
race = "Mountain Dwarf";
|
|
stats[STR]+=2;
|
|
}
|
|
break;
|
|
case ELF:
|
|
addLanguage(ELVISH);
|
|
addProf(PERCEPTION);
|
|
stats[DEX]+=2;
|
|
subrace = arc4random_uniform(3);
|
|
if(subrace == 0){
|
|
race = "High Elf";
|
|
stats[INT]+=1;
|
|
addLanguage(exp2l(arc4random_uniform(15)));
|
|
}else if(subrace == 1){
|
|
race = "Wood Elf";
|
|
stats[WIS]+=1;
|
|
}else{
|
|
race = "Drow";
|
|
stats[CHA]+=1;
|
|
}
|
|
break;
|
|
case GNOME:
|
|
subrace = arc4random_uniform(2);
|
|
stats[INT]+=2;
|
|
addLanguage(GNOMISH);
|
|
if(subrace == 0){
|
|
race = "Forest Gnome";
|
|
stats[DEX]+=1;
|
|
}else{
|
|
race = "Rock Gnome";
|
|
stats[CON]+=1;
|
|
strlcat(otherprofs, "Artisan Tools, ", sizeof(otherprofs));
|
|
}
|
|
break;
|
|
case HALFELF:
|
|
stats[CHA]+=2;
|
|
stats[arc4random_uniform(4)]+=1;
|
|
stats[arc4random_uniform(4)]+=1;
|
|
addProf(exp2l(arc4random_uniform(18)));
|
|
addProf(exp2l(arc4random_uniform(18)));
|
|
addLanguage(exp2l(arc4random_uniform(15)));
|
|
addLanguage(ELVISH);
|
|
break;
|
|
case HALFLING:
|
|
addLanguage(HALFLISH);
|
|
stats[DEX]+=2;
|
|
subrace = arc4random_uniform(2);
|
|
if(subrace == 0){
|
|
race = "Lightfoot Halfling";
|
|
stats[CHA]+=1;
|
|
}else{
|
|
race = "Stout Halfling";
|
|
stats[INT]+=1;
|
|
}
|
|
break;
|
|
case HALFORC:
|
|
addLanguage(ORC);
|
|
stats[STR]+=2;
|
|
stats[CON]+=1;
|
|
addProf(INTIMIDATION);
|
|
break;
|
|
case HUMAN:
|
|
stats[STR]+=1;
|
|
stats[DEX]+=1;
|
|
stats[CON]+=1;
|
|
stats[INT]+=1;
|
|
stats[WIS]+=1;
|
|
stats[CHA]+=1;
|
|
addLanguage(exp2l(arc4random_uniform(15)));
|
|
break;
|
|
case TIEFLING:
|
|
stats[INT]+=1;
|
|
stats[CHA]+=2;
|
|
addLanguage(INFERNAL);
|
|
break;
|
|
default:
|
|
fprintf(stderr, "Something went wrong in race selection");
|
|
/*Hopefully should never happen*/
|
|
}
|
|
}
|
|
|
|
void genBackground(){
|
|
int b = arc4random_uniform(sizeof(backgrounds)/sizeof(backgrounds[0]));
|
|
background = backgrounds[b];
|
|
switch (b){
|
|
case ACOLYTE:
|
|
addProf(INSIGHT);
|
|
addProf(RELIGION);
|
|
addLanguage(exp2l(arc4random_uniform(15)));
|
|
addLanguage(exp2l(arc4random_uniform(15)));
|
|
break;
|
|
case CHARLATAN:
|
|
addProf(DECEPTION);
|
|
addProf(SLEIGHTOFHAND);
|
|
strlcat(otherprofs, "Disguise Kit, ", sizeof(otherprofs));
|
|
strlcat(otherprofs, "Forgery Kit, ", sizeof(otherprofs));
|
|
break;
|
|
case CRIMINAL:
|
|
addProf(DECEPTION);
|
|
addProf(STEALTH);
|
|
strlcat(otherprofs, "Gaming Set, ", sizeof(otherprofs));
|
|
strlcat(otherprofs, "Theives Tools, ", sizeof(otherprofs));
|
|
break;
|
|
case ENTERTAINER:
|
|
addProf(ACROBATICS);
|
|
addProf(PERFORMANCE);
|
|
strlcat(otherprofs, "Disguise Kit, ", sizeof(otherprofs));
|
|
strlcat(otherprofs, "Musical Instrument, ", sizeof(otherprofs));
|
|
break;
|
|
case FOLKHERO:
|
|
addProf(ANIMALHANDLING);
|
|
addProf(SURVIVAL);
|
|
strlcat(otherprofs, "Artisan's Tools, ", sizeof(otherprofs));
|
|
strlcat(otherprofs, "Land Vehicles, ", sizeof(otherprofs));
|
|
break;
|
|
case GUILDARTISAN:
|
|
addProf(INSIGHT);
|
|
addProf(PERSUASION);
|
|
addLanguage(exp2l(arc4random_uniform(15)));
|
|
strlcat(otherprofs, "Artisan's Tools, ", sizeof(otherprofs));
|
|
break;
|
|
case HERMIT:
|
|
addProf(MEDICINE);
|
|
addProf(RELIGION);
|
|
addLanguage(exp2l(arc4random_uniform(15)));
|
|
strlcat(otherprofs, "Herbalism Kit, ", sizeof(otherprofs));
|
|
break;
|
|
case NOBLE:
|
|
addProf(HISTORY);
|
|
addProf(PERSUASION);
|
|
addLanguage(exp2l(arc4random_uniform(15)));
|
|
strlcat(otherprofs, "Gaming Set, ", sizeof(otherprofs));
|
|
break;
|
|
case OUTLANDER:
|
|
addProf(ATHLETICS);
|
|
addProf(SURVIVAL);
|
|
addLanguage(exp2l(arc4random_uniform(15)));
|
|
strlcat(otherprofs, "Musical Instrument, ", sizeof(otherprofs));
|
|
break;
|
|
case SAGE:
|
|
addProf(ARCANA);
|
|
addProf(HISTORY);
|
|
addLanguage(exp2l(arc4random_uniform(15)));
|
|
addLanguage(exp2l(arc4random_uniform(15)));
|
|
break;
|
|
case SAILOR:
|
|
addProf(ATHLETICS);
|
|
addProf(PERCEPTION);
|
|
strlcat(otherprofs, "Navigator's Tools, ", sizeof(otherprofs));
|
|
strlcat(otherprofs, "Water Vehicles, ", sizeof(otherprofs));
|
|
break;
|
|
case SOLDIER:
|
|
addProf(ATHLETICS);
|
|
addProf(INTIMIDATION);
|
|
strlcat(otherprofs, "Gaming Set, ", sizeof(otherprofs));
|
|
strlcat(otherprofs, "Land Vehicles, ", sizeof(otherprofs));
|
|
break;
|
|
case URCHIN:
|
|
addProf(SLEIGHTOFHAND);
|
|
addProf(STEALTH);
|
|
strlcat(otherprofs, "Theives Tools, ", sizeof(otherprofs));
|
|
strlcat(otherprofs, "Disguise Kit, ", sizeof(otherprofs));
|
|
break;
|
|
default:
|
|
fprintf(stderr, "Bad background was generated!");
|
|
/* Ideally not reached */
|
|
}
|
|
}
|
|
|
|
char * genChar(char* output){
|
|
profs = 0;
|
|
languages = 0;
|
|
for(int i = 0; i <= 100; i++){
|
|
otherprofs[i] = '\0';
|
|
}
|
|
int i;
|
|
genRace();
|
|
genClass();
|
|
genBackground();
|
|
for(i=0; i < 6; i++){
|
|
stats[i] = dieroll(3,6);
|
|
mods[i] = floor((stats[i]/2)-5);
|
|
}
|
|
snprintf(output, 512, "Race = %s\r\nBackground = %s\r\nClass = %s\r\nStr = %d %d\r\nDex = %d %d\r\nCon = %d %d\r\nInt = %d %d\r\nWis = %d %d\r\nCha = %d %d\r\n\r\nHP: %d\r\n", race, background, class, stats[STR], mods[STR], stats[DEX], mods[DEX], stats[CON], mods[CON], stats[INT], mods[INT], stats[WIS], mods[WIS], stats[CHA], mods[CHA], hp);
|
|
|
|
|
|
strlcat(output,"Proficiences:\r\n",512);
|
|
if((ATHLETICS & profs) != 0){
|
|
strlcat(output,"Athletics\r\n",512);
|
|
}
|
|
if((ACROBATICS & profs) != 0){
|
|
strlcat(output,"Acrobatics\r\n",512);
|
|
}
|
|
if((SLEIGHTOFHAND & profs) != 0){
|
|
strlcat(output,"Sleight of Hand\r\n",512);
|
|
}
|
|
if((STEALTH & profs) != 0){
|
|
strlcat(output,"Stealth\r\n",512);
|
|
}
|
|
if((ARCANA & profs) != 0){
|
|
strlcat(output,"Arcana\r\n",512);
|
|
}
|
|
if((HISTORY & profs) != 0){
|
|
strlcat(output,"History\r\n",512);
|
|
}
|
|
if((INVESTIGATION & profs) != 0){
|
|
strlcat(output,"Investigation\r\n",512);
|
|
}
|
|
if((NATURE & profs) != 0){
|
|
strlcat(output,"Nature\r\n",512);
|
|
}
|
|
if((RELIGION & profs) != 0){
|
|
strlcat(output,"Regligion\r\n",512);
|
|
}
|
|
if((ANIMALHANDLING & profs) != 0){
|
|
strlcat(output,"Animal Handling\r\n",512);
|
|
}
|
|
if((INSIGHT & profs) != 0){
|
|
strlcat(output,"Insight\r\n",512);
|
|
}
|
|
if((MEDICINE & profs) != 0){
|
|
strlcat(output,"Medicine\r\n",512);
|
|
}
|
|
if((PERCEPTION & profs) != 0){
|
|
strlcat(output,"Perception\r\n",512);
|
|
}
|
|
if((SURVIVAL & profs) != 0){
|
|
strlcat(output,"Survival\r\n",512);
|
|
}
|
|
if((DECEPTION & profs) != 0){
|
|
strlcat(output,"Deception\r\n",512);
|
|
}
|
|
if((INTIMIDATION & profs) != 0){
|
|
strlcat(output,"Intimidation\r\n",512);
|
|
}
|
|
if((PERFORMANCE & profs) != 0){
|
|
strlcat(output,"Performance\r\n",512);
|
|
}
|
|
if((PERSUASION & profs) != 0){
|
|
strlcat(output,"Persuaion\r\n",512);
|
|
}
|
|
|
|
strlcat(output,"\r\nLanguages:\r\nCommon\r\n",512);
|
|
if((ABYSSAL & languages) != 0){
|
|
strlcat(output,"Abyssal\r\n",512);
|
|
}
|
|
if((CELESTIAL & languages) != 0){
|
|
strlcat(output,"Celestial\r\n",512);
|
|
}
|
|
if((DRACONIC & languages) != 0){
|
|
strlcat(output,"Draconic\r\n",512);
|
|
}
|
|
if((DEEPSPEECH & languages) != 0){
|
|
strlcat(output,"Deep Speech\r\n",512);
|
|
}
|
|
if((INFERNAL & languages) != 0){
|
|
strlcat(output,"Infernal\r\n",512);
|
|
}
|
|
if((PRIMORDIAL & languages) != 0){
|
|
strlcat(output,"Primordial\r\n",512);
|
|
}
|
|
if((SYLVAN & languages) != 0){
|
|
strlcat(output,"Sylvan\r\n",512);
|
|
}
|
|
if((UNDERCOMMON & languages) != 0){
|
|
strlcat(output,"Undercommon\r\n",512);
|
|
}
|
|
if((DWARVISH & languages) != 0){
|
|
strlcat(output,"Dwarvish\r\n",512);
|
|
}
|
|
if((ELVISH & languages) != 0){
|
|
strlcat(output,"Elvish\r\n",512);
|
|
}
|
|
if((GIANT & languages) != 0){
|
|
strlcat(output,"Giant\r\n",512);
|
|
}
|
|
if((GNOMISH & languages) != 0){
|
|
strlcat(output,"Gnome\r\n",512);
|
|
}
|
|
if((GOBLIN & languages) != 0){
|
|
strlcat(output,"Goblin\r\n",512);
|
|
}
|
|
if((HALFLISH & languages) != 0){
|
|
strlcat(output,"Halfling\r\n",512);
|
|
}
|
|
if((ORC & languages) != 0){
|
|
strlcat(output,"Orcish\r\n",512);
|
|
}
|
|
strlcat(output,"\r\nOther Profs: ",512);
|
|
strlcat(output,otherprofs,512);
|
|
strlcat(output,"\r\n",512);
|
|
return output;
|
|
}
|
|
|