static public Animal BuildAnimal(Dice dice, string terrainType, string animalClassName = null, int evolutionRolls = 0) { //Options var selectedTerrainType = TerrainTypeList.Single(x => x.Name == terrainType); var terrainPenalty = 0; if (animalClassName == null) { var animalClassNotes = dice.ChooseWithOdds(selectedTerrainType.AnimalClasses); animalClassName = animalClassNotes.AnimalClass; terrainPenalty = animalClassNotes.Penalty; } else { var animalClassNotes = selectedTerrainType.AnimalClasses.SingleOrDefault(ac => ac.AnimalClass == animalClassName); if (animalClassNotes == null) { terrainPenalty = -5; //What is it doing here? } else { terrainPenalty = animalClassNotes.Penalty; } } var animalClass = AnimalClassList.Single(x => x.Name == animalClassName); //Type var result = new Animal() { TerrainType = selectedTerrainType.Name, AnimalClass = animalClassName, EvolutionRolls = evolutionRolls }; var movement = dice.ChooseByRoll(selectedTerrainType.MovementChart, "D6"); result.Movement = !string.IsNullOrWhiteSpace(animalClass.Movement) ? animalClass.Movement : movement.Movement; result.InitiativeDM += animalClass.InitiativeDM; //Starting Skills foreach (var skill in animalClass.Skills) { if (skill.ScoreSpecified) { result.Skills.Add(skill.Name, skill.Score); } else { result.Skills.Increase(skill.Name, skill.Bonus); } } //Class features if (animalClass.Features != null) { foreach (var feature in animalClass.Features) { result.Features.Add(feature.Text); } } //Diet var diet = dice.ChooseWithOdds(animalClass.Diets); result.Diet = diet.Diet; if (diet.Skills != null) { foreach (var skill in diet.Skills) { if (skill.ScoreSpecified) { result.Skills.Add(skill.Name, skill.Score); } else { result.Skills.Increase(skill.Name, skill.Bonus); } } } foreach (var att in diet.Attribute) { result.Increase(att.Name, dice.D(att.Bonus)); } var weaponDM = 0; switch (result.Diet) { case "Carnivore": result.InitiativeDM += 1; weaponDM = 8; break; case "Omnivore": weaponDM = 4; break; case "Herbivore": result.InitiativeDM += -1; weaponDM = -6; break; } //Behavior var behaviorMeta = dice.ChooseByRoll(diet.Behaviors, "1D"); var behavior = BehaviorList.Single(x => x.Name == behaviorMeta.Behavior); result.Behavior = behaviorMeta.Behavior; result.Attack = behavior.Attack.ToIntOrNull(); result.Flee = behavior.Flee.ToIntOrNull(); result.InitiativeDM += behavior.InitiativeDM; if (result.BehaviorCount == 1) {//subtract the reaction to make it act like a DM result.Attack -= behaviorMeta.Reaction; result.Flee -= behaviorMeta.Reaction; } else { var shortList = diet.Behaviors.Where(x => x.Behavior != behaviorMeta.Behavior).ToList(); var behaviorMeta2 = dice.ChooseByRoll(shortList, "1D5"); result.SecondaryBehavior = behaviorMeta2.Behavior; } AddBehavior(result, behavior, dice); result.QuirkRolls += dice.D("D6") == 6 ? 1 : 0; //We do this in a loop because each chart can add rolls to other charts while (result.QuirkRolls > 0 || result.EvolutionRolls > 0 || result.PhysicalSkills > 0 || result.SocialSkills > 0 || result.EvolutionSkills > 0) { //Evolution Rolls while (result.EvolutionRolls > 0) { result.EvolutionRolls -= 1; if (dice.D(2) == 0) { RollOnChart(result, animalClass.Chart.Single(x => x.Name == "AdditionalSkills"), dice, $"1D6+{result.EvolutionDM}"); } else { RollOnChart(result, animalClass.Chart.Single(x => x.Name == "OtherBenefits"), dice, $"1D6+{result.EvolutionDM}"); } } //Skill Rolls while (result.PhysicalSkills > 0) { result.PhysicalSkills -= 1; RollOnChart(result, animalClass.Chart.Single(x => x.Name == "PhysicalSkills"), dice); } while (result.SocialSkills > 0) { result.SocialSkills -= 1; RollOnChart(result, animalClass.Chart.Single(x => x.Name == "SocialSkills"), dice); } while (result.EvolutionSkills > 0) { result.EvolutionSkills -= 1; RollOnChart(result, animalClass.Chart.Single(x => x.Name == "EvolutionSkills"), dice); } //Quirk Rolls while (result.QuirkRolls > 0) { result.QuirkRolls -= 1; RollOnChart(result, animalClass.Chart.Single(x => x.Name == "Quirks"), dice, "2D"); } } //Size var sizeRoll = (dice.D(selectedTerrainType.SizeDM) + dice.D(movement.SizeDM) + dice.D(2, 6)).Limit(1, 13); var size = s_Templates.SizeTable.Single(sizeRoll); result.Size = sizeRoll; result.WeightKG = size.WeightKG; //Attributes result.Strength += dice.D(size.Strength) + terrainPenalty; result.Dexterity += dice.D(size.Dexterity) + terrainPenalty; result.Endurance += dice.D(size.Endurance) + terrainPenalty; result.Pack += dice.D(2, 6) + terrainPenalty; result.Instinct += dice.D(2, 6) + terrainPenalty; if (dice.D(6) + terrainPenalty >= 5) { result.Intelligence += 1; } //Weapons var baseDamage = s_Templates.DamageTable.Last(x => result.Strength >= x.MinValue).Damage; var weapon = s_Templates.WeaponTable.Single((dice.D("2D6") + weaponDM).Limit(1, 20)); if (weapon.Weapon != "None") { result.Weapons.Add(new Weapon() { Name = weapon.Weapon, Damage = (baseDamage + weapon.Bonus) + "d6" }); } if (result.Weapons.Count > 0) { result.Skills.Add("Melee"); //always have melee if you have any weapons. Page 23 } //Armor result.Armor += s_Templates.ArmorTable.Single(dice.D(2, 6)).Armor; //Bonus skills if (result.Skills.Count > 0) { var bonusSkills = dice.D(1, 6); dice.Choose(result.Skills).Level += 1; } //Run post-scripts foreach (var script in result.PostScripts) { RunScript(result, dice, script); } result.PostScripts.Clear(); //Finishing touches result.NumberEncountered = s_Templates.NumberTable.Last(x => result.Pack.Limit(0, 15) >= x.MinValue).Number; result.Strength = Math.Max(result.Strength, 0); result.Dexterity = Math.Max(result.Dexterity, 0); result.Endurance = Math.Max(result.Endurance, 0); result.Pack = Math.Max(result.Pack, 0); result.Instinct = Math.Max(result.Instinct, 0); result.Intelligence = Math.Max(result.Intelligence, 0); result.Armor = Math.Max(result.Armor, 0); return(result); }
static public Animal BuildAnimal(string terrainType, string animalType) { var dice = new Dice(); var selectedTerrainType = TerrainTypeList.Single(x => x.Name == terrainType); var selectedAnimalType = AnimalTypeList.Single(x => x.Name == animalType); //Type var result = new Animal() { TerrainType = selectedTerrainType.Name, AnimalType = selectedAnimalType.Name }; var behaviorName = (selectedAnimalType.Option.Single((dice.D(selectedTerrainType.TypeDM) + dice.D(2, 6)).Limit(1, 13))).Behavior; var behavior = selectedAnimalType.Behavior.Single(x => x.Name == behaviorName); result.Behavior = behaviorName; var movement = selectedTerrainType.Option.Single(dice.D(6)); //Size var sizeRoll = (dice.D(selectedTerrainType.SizeDM) + dice.D(movement.SizeDM) + dice.D(2, 6)).Limit(1, 13); var size = s_Templates.SizeTable.Single(sizeRoll); result.Size = sizeRoll; result.Movement = movement.Movement; result.WeightKG = size.WeightKG; //Attributes result.Strength = dice.D(size.Strength); result.Dexterity = dice.D(size.Dexterity); result.Endurance = dice.D(size.Endurance); result.Pack = dice.D(2, 6); result.Instinct = dice.D(2, 6); if (behaviorName == "Killer") { if (dice.D(2) == 1) { result.Strength += 4; } else { result.Dexterity += 4; } } var intOdds = dice.D(100); //Each point of instinct gives a 10% change of intelligence 1 and a 1% chance of intelligence 2 if (result.Instinct >= intOdds) { result.Intelligence = 2; } else if ((result.Instinct * 10) >= intOdds) { result.Intelligence = 1; } if (behavior.Attribute != null) { foreach (var item in behavior.Attribute) { int bonus = item.Add; switch (item.Name) { case "Strength": result.Strength += bonus; break; case "Dexterity": result.Dexterity += bonus; break; case "Endurance": result.Endurance += bonus; break; case "Intelligence": result.Intelligence += bonus; break; case "Instinct": result.Instinct += bonus; break; case "Pack": result.Pack += bonus; break; default: throw new System.Exception("Unkonw attribute " + item.Name); } } } //Skills var basicTraining = new List <string>() { "Survival", "Recon", "Athletics", "Melee" }; if (behavior.Skill != null) { foreach (var item in behavior.Skill) { basicTraining.Add(item.Name); } } var skillPicks = dice.D(6) + result.InstinctDM; for (int i = 0; i < skillPicks; i++) { result.Skills.Increase(dice.Choose(basicTraining), 1); } //Base skills added at level 0 if you don't already have them result.Skills.Add("Survival"); result.Skills.Add("Recon"); result.Skills.Add("Athletics"); //Weapons var baseDamage = (int)s_Templates.DamageTable.Last(x => result.Strength >= x.MinValue).Damage; var weapon = s_Templates.WeaponTable.Single((dice.D(2, 6) + (int)selectedAnimalType.WeaponDM).Limit(1, 13)); if (weapon.Weapon != "None") { result.Weapons.Add(new Weapon() { Name = weapon.Weapon, Damage = (baseDamage + int.Parse(weapon.Bonus)) + "d6" }); } if (selectedAnimalType.Name == "Scavenger" && !(result.Weapons.Any(x => x.Name.Contains("Teeth")))) { result.Weapons.Add(new Weapon() { Name = "Teeth", Damage = baseDamage + "d6" }); } result.NumberEncountered = s_Templates.NumberTable.Last(x => result.Pack.Limit(0, 15) >= x.MinValue).Number; result.Attack = behavior.Attack; result.Flee = behavior.Flee; //Armor result.Armor = s_Templates.ArmorTable.Single(dice.D(2, 6)).Armor; return(result); }