public Character GenerateCharacter() { var dice = new Dice(); var result = new Character(); result.Rank = SelectedRank.Name; result.IsWildCard = WildCard; //Add all possible skills (except ones created by edges) foreach (var item in Skills) result.Skills.Add(new Skill(item.Name, item.Attribute) { Trait = 0 }); ApplyArchetype(result); ApplyRace(result); //Add the rank result.UnusedAdvances = SelectedRank.UnusedAdvances; result.Experience = SelectedRank.Experience; //Main loop for random picks while (result.UnusedAttributes > 0 || result.UnusedSkills > 0 || result.UnusedSmartSkills > 0 || result.UnusedAdvances > 0 || result.UnusedEdges > 0 || result.UnusedHindrances > 0) { //tight loop to apply current hindrances while (result.UnusedHindrances > 0) PickHindrance(result, dice); if (result.UnusedAttributes > 0) PickAttribute(result, dice); if (result.UnusedSmartSkills > 0) PickSkill(result, dice, "Smarts"); if (result.UnusedSkills > 0) PickSkill(result, dice); if (result.UnusedEdges > 0) PickEdge(result, dice); //only apply an advance when everything else has been used if (result.UnusedAdvances > 0 && result.UnusedAttributes <= 0 && result.UnusedSkills <= 0 && result.UnusedEdges <= 0 && result.UnusedSmartSkills <= 0) { PickAdvancement(result, dice); } //Out of advancements. Do we need a hindrance? if (result.UnusedAdvances == 0) { if (result.UnusedAttributes < 0) { result.UnusedHindrances += -2 * result.UnusedAttributes; result.UnusedAttributes = 0; } if (result.UnusedSmartSkills < 0) { result.UnusedSkills += result.UnusedSmartSkills; result.UnusedSmartSkills = 0; } if (result.UnusedSkills < 0) { result.UnusedHindrances += -1 * result.UnusedSkills; result.UnusedSkills = 0; } if (result.UnusedEdges < 0) { result.UnusedHindrances += -2 * result.UnusedEdges; result.UnusedEdges = 0; } } } //Remove the skills that were not chosen foreach (var item in result.Skills.Where(s => s.Trait == 0).ToList()) result.Skills.Remove(item); return result; }
void ApplyHindrance(Character result, SettingHindrance hindrance, int level) { result.Hindrances.Add(new Hindrance() { Name = hindrance.Name, Description = hindrance.Description, Level = level }); if (hindrance.Trait != null) foreach (var item in hindrance.Trait) result.Increment(item.Name, item.Bonus); if (hindrance.Features != null) foreach (var item in hindrance.Features) result.Features.Add(item.Name); if (hindrance.Skill != null) foreach (var item in hindrance.Skill) { var skill = result.Skills.FirstOrDefault(s => s.Name == item.Name); if (skill == null) result.Skills.Add(new Skill(item.Name, item.Attribute) { Trait = item.Level }); else if (skill.Trait < item.Level) skill.Trait = item.Level; } }
void ApplyRace(Character result) { //Add the race result.Race = SelectedRace.Name; if (SelectedRace.Edges != null) foreach (var item in SelectedRace.Edges) { //Lookup the edge defintion. If not found, assume this edge is custom for the race. var edge = Edges.SingleOrDefault(e => e.Name == item.Name) ?? item; ApplyEdge(result, edge); } if (SelectedRace.Skills != null) foreach (var item in SelectedRace.Skills) { var skill = result.Skills[item.Name]; if (skill != null) skill.Trait = Math.Max(skill.Trait.Score, item.Level); else result.Skills.Add(new Skill(item.Name, item.Attribute) { Trait = item.Level }); } if (SelectedRace.Traits != null) foreach (var item in SelectedRace.Traits) result.Increment(item.Name, item.Bonus); }
void ApplyArchetype(Character result) { //Add the archetype result.Archetype = SelectedArchetype.Name; result.UnusedAttributes = SelectedArchetype.UnusedAttributes; result.UnusedSkills = SelectedArchetype.UnusedSkills; result.Agility = SelectedArchetype.Agility; result.Smarts = SelectedArchetype.Smarts; result.Spirit = SelectedArchetype.Spirit; result.Strength = SelectedArchetype.Strength; result.Vigor = SelectedArchetype.Vigor; //edges first because they can create new skills if (SelectedArchetype.Edges != null) foreach (var item in SelectedArchetype.Edges) { //Lookup the edge defintion. If not found, assume this edge is custom for the archetype. var edge = Edges.SingleOrDefault(e => e.Name == item.Name) ?? item; ApplyEdge(result, edge); } if (SelectedArchetype.Skills != null) foreach (var item in SelectedArchetype.Skills) { var skill = result.Skills[item.Name]; if (skill != null) skill.Trait = Math.Max(skill.Trait.Score, item.Level); else result.Skills.Add(new Skill(item.Name, item.Attribute) { Trait = item.Level }); } if (SelectedArchetype.Traits != null) foreach (var item in SelectedArchetype.Traits) result.Increment(item.Name, item.Bonus); }
static void PickSkill(Character result, Dice dice, string attributeFilter = null) { bool allowHigh = result.UnusedSkills >= 2 && result.UnusedAttributes == 0; //don't buy expensive skills until all of the attributes are picked var table = new Table<Skill>(); foreach (var item in result.Skills.Where(s => attributeFilter == null || s.Attribute == attributeFilter)) { if (item.Trait == 0) table.Add(item, result.GetAttribute(item.Attribute).Score - 3); //favor skills that match your attributes else if (item.Trait < result.GetAttribute(item.Attribute)) //favor improving what you know table.Add(item, result.GetAttribute(item.Attribute).Score - 3 + item.Trait.Score); else if (allowHigh && item.Trait < 12) table.Add(item, item.Trait.Score); //Raising skills above the controlling attribute is relatively rare } var skill = table.RandomChoose(dice); if (skill.Trait == 0) { result.UnusedSkills -= 1; skill.Trait = 4; } else if (skill.Trait < result.GetAttribute(skill.Attribute)) { result.UnusedSkills -= 1; skill.Trait += 1; } else { result.UnusedSkills -= 2; skill.Trait += 1; } }
static void PickAttribute(Character result, Dice dice) { //Attributes are likely to stack rather than spread evenly var table = new Table<string>(); if (result.Vigor < 12) table.Add("Vigor", result.Vigor.Score); if (result.Smarts < 12) table.Add("Smarts", result.Smarts.Score); if (result.Agility < 12) table.Add("Agility", result.Agility.Score); if (result.Strength < 12) table.Add("Strength", result.Strength.Score); if (result.Spirit < 12) table.Add("Spirit", result.Spirit.Score); result.Increment(table.RandomChoose(dice)); result.UnusedAttributes -= 1; }
static void PickAdvancement(Character result, Dice dice) { result.UnusedAdvances -= 1; if (result.UnusedEdges < 0) result.UnusedEdges += 1; else if (result.UnusedSkills < 0) result.UnusedSkills += 2; //pay back the skill point loan else if (result.UnusedSmartSkills < 0) result.UnusedSmartSkills += 2; //pay back the skill point loan else { switch (dice.Next(5)) { case 0: result.UnusedEdges += 1; break; case 1: //increase a high skill { var table = new Table<Skill>(); foreach (var skill in result.Skills) { if (skill.Trait >= result.GetAttribute(skill.Attribute) && skill.Trait < 12) table.Add(skill, skill.Trait.Score); } if (table.Count == 0) goto case 2; table.RandomChoose(dice).Trait += 1; break; } case 2: //increase a low skill { var table = new Table<Skill>(); foreach (var skill in result.Skills) { if (skill.Trait < result.GetAttribute(skill.Attribute) && skill.Trait < 12) table.Add(skill, skill.Trait.Score); } if (table.Count >= 2) goto case 3; table.RandomPick(dice).Trait += 1; table.RandomPick(dice).Trait += 1; //use Pick so we get 2 different skills break; } case 3: //add a new skill { var table = new Table<Skill>(); foreach (var skill in result.Skills) { if (skill.Trait == 0) table.Add(skill, result.GetAttribute(skill.Attribute).Score); } if (table.Count == 0) break; //really? table.RandomChoose(dice).Trait = 4; break; } case 4: result.UnusedAttributes += 1; break; } } }
static void ApplyEdge(Character result, SettingEdge edge) { result.Edges.Add(new Edge() { Name = edge.Name, Description = edge.Description, UniqueGroup = edge.UniqueGroup }); if (edge.Traits != null) foreach (var item in edge.Traits) result.Increment(item.Name, item.Bonus); if (edge.Features != null) foreach (var item in edge.Features) result.Features.Add(item.Name); if (edge.Skills != null) foreach (var item in edge.Skills) { var skill = result.Skills.FirstOrDefault(s => s.Name == item.Name); if (skill == null) { result.Skills.Add(new Skill(item.Name, item.Attribute) { Trait = item.Level }); } else if (skill.Trait < item.Level) { skill.Trait = item.Level; } } }