#include #include #include #include "chargen.h" #include "character.h" unsigned long profs; unsigned long languages; char otherprofs[100]; char* background; char* race; char* class; char* classes[] = {"Barbarian", "Bard", "Cleric", "Druid", "Fighter", "Monk", "Paladin", "Ranger", "Rogue", "Sorcerer", "Warlock", "Wizard" }; char* races[] = { "Dragonborn", "Dwarf", "Elf", "Gnome", "Half-Elf", "Halfling", "Half-Orc", "Human", "Tiefling" }; char* backgrounds[] = { "Acolyte", "Charlatan", "Criminal", "Entertainer", "Folk Hero", "Guild Artisan", "Hermit", "Noble", "Outlander", "Sage", "Sailor", "Soldier", "Urchin" }; int stats[6]; int mods[6]; int hp; 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(1lu << arc4random_uniform(15)); } } void addProf(long prof){ if((prof & profs) == 0){ profs = profs + prof; }else{ addProf(1lu << 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(1lu << 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(1lu << arc4random_uniform(18)); addProf(1lu << arc4random_uniform(18)); addProf(1lu << 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(1lu << 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(1lu << arc4random_uniform(18)); addProf(1lu << arc4random_uniform(18)); addLanguage(1lu << 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(1lu << 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(1lu << arc4random_uniform(15)); addLanguage(1lu << 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(1lu << arc4random_uniform(15)); strlcat(otherprofs, "Artisan's Tools, ", sizeof(otherprofs)); break; case HERMIT: addProf(MEDICINE); addProf(RELIGION); addLanguage(1lu << arc4random_uniform(15)); strlcat(otherprofs, "Herbalism Kit, ", sizeof(otherprofs)); break; case NOBLE: addProf(HISTORY); addProf(PERSUASION); addLanguage(1lu << arc4random_uniform(15)); strlcat(otherprofs, "Gaming Set, ", sizeof(otherprofs)); break; case OUTLANDER: addProf(ATHLETICS); addProf(SURVIVAL); addLanguage(1lu << arc4random_uniform(15)); strlcat(otherprofs, "Musical Instrument, ", sizeof(otherprofs)); break; case SAGE: addProf(ARCANA); addProf(HISTORY); addLanguage(1lu << arc4random_uniform(15)); addLanguage(1lu << 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 */ } } size_t genChar(char* output, size_t maxlen){ 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] = (stats[i]/2)-5; } snprintf(output, maxlen, "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",maxlen); if((ATHLETICS & profs) != 0){ strlcat(output,"Athletics\r\n",maxlen); } if((ACROBATICS & profs) != 0){ strlcat(output,"Acrobatics\r\n",maxlen); } if((SLEIGHTOFHAND & profs) != 0){ strlcat(output,"Sleight of Hand\r\n",maxlen); } if((STEALTH & profs) != 0){ strlcat(output,"Stealth\r\n",maxlen); } if((ARCANA & profs) != 0){ strlcat(output,"Arcana\r\n",maxlen); } if((HISTORY & profs) != 0){ strlcat(output,"History\r\n",maxlen); } if((INVESTIGATION & profs) != 0){ strlcat(output,"Investigation\r\n",maxlen); } if((NATURE & profs) != 0){ strlcat(output,"Nature\r\n",maxlen); } if((RELIGION & profs) != 0){ strlcat(output,"Regligion\r\n",maxlen); } if((ANIMALHANDLING & profs) != 0){ strlcat(output,"Animal Handling\r\n",maxlen); } if((INSIGHT & profs) != 0){ strlcat(output,"Insight\r\n",maxlen); } if((MEDICINE & profs) != 0){ strlcat(output,"Medicine\r\n",maxlen); } if((PERCEPTION & profs) != 0){ strlcat(output,"Perception\r\n",maxlen); } if((SURVIVAL & profs) != 0){ strlcat(output,"Survival\r\n",maxlen); } if((DECEPTION & profs) != 0){ strlcat(output,"Deception\r\n",maxlen); } if((INTIMIDATION & profs) != 0){ strlcat(output,"Intimidation\r\n",maxlen); } if((PERFORMANCE & profs) != 0){ strlcat(output,"Performance\r\n",maxlen); } if((PERSUASION & profs) != 0){ strlcat(output,"Persuaion\r\n",maxlen); } strlcat(output,"\r\nLanguages:\r\nCommon\r\n",maxlen); if((ABYSSAL & languages) != 0){ strlcat(output,"Abyssal\r\n",maxlen); } if((CELESTIAL & languages) != 0){ strlcat(output,"Celestial\r\n",maxlen); } if((DRACONIC & languages) != 0){ strlcat(output,"Draconic\r\n",maxlen); } if((DEEPSPEECH & languages) != 0){ strlcat(output,"Deep Speech\r\n",maxlen); } if((INFERNAL & languages) != 0){ strlcat(output,"Infernal\r\n",maxlen); } if((PRIMORDIAL & languages) != 0){ strlcat(output,"Primordial\r\n",maxlen); } if((SYLVAN & languages) != 0){ strlcat(output,"Sylvan\r\n",maxlen); } if((UNDERCOMMON & languages) != 0){ strlcat(output,"Undercommon\r\n",maxlen); } if((DWARVISH & languages) != 0){ strlcat(output,"Dwarvish\r\n",maxlen); } if((ELVISH & languages) != 0){ strlcat(output,"Elvish\r\n",maxlen); } if((GIANT & languages) != 0){ strlcat(output,"Giant\r\n",maxlen); } if((GNOMISH & languages) != 0){ strlcat(output,"Gnome\r\n",maxlen); } if((GOBLIN & languages) != 0){ strlcat(output,"Goblin\r\n",maxlen); } if((HALFLISH & languages) != 0){ strlcat(output,"Halfling\r\n",maxlen); } if((ORC & languages) != 0){ strlcat(output,"Orcish\r\n",maxlen); } strlcat(output,"\r\nOther Profs: ",maxlen); strlcat(output,otherprofs,maxlen); strlcat(output,"\r\n",maxlen); return strlen(output); }