public override CharacterAbilityBase MakeCopy() { CharacterAbility retVal = new CharacterAbility(this.Ability); retVal.Experience = this.Experience; retVal.IsAffinity = this.IsAffinity; retVal.IsPuissant = this.IsPuissant; return(retVal); }
public Character(Ability writingLanguage, Ability writingAbility, Ability areaAbility, uint baseSeasonableAge = 20) { Die die = new Die(); _attributes[(short)AttributeType.Strength] = new Attribute(die.RollNormal()); _attributes[(short)AttributeType.Stamina] = new Attribute(die.RollNormal()); _attributes[(short)AttributeType.Dexterity] = new Attribute(die.RollNormal()); _attributes[(short)AttributeType.Quickness] = new Attribute(die.RollNormal()); _attributes[(short)AttributeType.Intelligence] = new Attribute(die.RollNormal()); _attributes[(short)AttributeType.Communication] = new Attribute(die.RollNormal()); _attributes[(short)AttributeType.Perception] = new Attribute(die.RollNormal()); _attributes[(short)AttributeType.Presence] = new Attribute(die.RollNormal()); Decrepitude = 0; CurrentSeason = Season.Spring; KnownAuras = new List <Aura>(); IsCollaborating = false; WantsToFollow = true; _noAgingSeasons = 0; _baseAge = baseSeasonableAge; _mandatoryAction = null; _abilityList = new Dictionary <int, CharacterAbilityBase>(); _seasonList = new List <IAction>(); _booksRead = new List <IBook>(); _booksWritten = new List <IBook>(); _booksOwned = new List <IBook>(); _areaAbility = areaAbility; _writingAbility = writingAbility; _writingLanguage = writingLanguage; _writingAbilities = new List <Ability>(); _writingAbilities.Add(_writingAbility); _writingAbilities.Add(_writingLanguage); _incompleteBooks = new List <Summa>(); _goals = new List <IGoal>(); Log = new List <string>(); Warping = new CharacterAbility(Abilities.Warping); }
public override IBook GetBestBookToWrite() { double currentBestBookValue = 0; IBook bestBook = null; HashSet <int> consideredTopics = new HashSet <int>(); // since the value of a tractatus is independent of topic, // calculate the value of writing a tractatus now, so that we don't have to keep doing it double tractatusValue = (6 + GetAttributeValue(AttributeType.Communication)) * GlobalEconomy.GlobalTractatusValue / 6; double writingRate = GetAttributeValue(AttributeType.Communication) + GetAbility(_writingLanguage).Value; var unneededBookTopics = GetUnneededBooksFromCollection().Select(b => b.Topic).Distinct(); foreach (BookDesire bookDesire in GlobalEconomy.DesiredBooksList) { // if we already have a suitable book for this topic, let's not try to write another if (unneededBookTopics.Contains(bookDesire.Ability)) { continue; } // check to see if we could even write a summa of a level that would meet this desire if (GetAbility(bookDesire.Ability).Value > bookDesire.CurrentLevel * 2) { CharacterAbility buyerAbility = new CharacterAbility(bookDesire.Ability); buyerAbility.Experience = buyerAbility.GetExperienceUntilLevel(bookDesire.CurrentLevel); // see if we have started a summa on this topic var relatedIncompleteBooks = _incompleteBooks.Where(b => b.Topic == bookDesire.Ability && b.Level > bookDesire.CurrentLevel); if (relatedIncompleteBooks.Any()) { foreach (Summa incompleteBook in relatedIncompleteBooks) { // the effective value is based on time to finish, not time already invested double experienceValue = buyerAbility.GetExperienceUntilLevel(incompleteBook.Level); double seasonsOfStudy = Math.Ceiling(experienceValue / incompleteBook.Quality); double effectiveQuality = experienceValue / seasonsOfStudy; // at a minimum, the book is worth the vis it would take, on average, to gain that experience double visUsedPerStudySeason = 0.5 + ((buyerAbility.Value + (buyerAbility.GetValueGain(experienceValue) / 2)) / 10.0); double studySeasons = experienceValue / VisStudyRate; double visNeeded = studySeasons * visUsedPerStudySeason; // scale visNeeded according to vis type if (MagicArts.IsTechnique(bookDesire.Ability)) { visNeeded *= 4; } else if (MagicArts.IsArt(bookDesire.Ability) && bookDesire.Ability != MagicArts.Vim) { visNeeded *= 2; } // for now, scale vis according to quality of book vs. quality of vis study visNeeded *= incompleteBook.Quality / VisStudyRate; // divide this visNeed valuation by how many seasons are left for writing double writingNeeded = incompleteBook.GetWritingPointsNeeded() - incompleteBook.PointsComplete; double seasonsLeft = Math.Ceiling(writingNeeded / writingRate); double writingValue = visNeeded / seasonsLeft; if (writingValue > currentBestBookValue) { // continue writing this summa bestBook = incompleteBook; } } } else { // NOTE: this could lead us down a strange rabbit hole of starting a bunch of // summae on a subject of varying levels, but I think that's unlikely enough // to not try and protect from for now double maxLevel = GetAbility(bookDesire.Ability).Value / 2.0; for (double l = maxLevel; l > bookDesire.CurrentLevel; l--) { double q = 6 + maxLevel - l; // the effective value is based on time to finish, not time already invested double experienceValue = buyerAbility.GetExperienceUntilLevel(l); double seasonsOfStudy = Math.Ceiling(experienceValue / q); double effectiveQuality = experienceValue / seasonsOfStudy; // at a minimum, the book is worth the vis it would take, on average, to gain that experience double visUsedPerStudySeason = 0.5 + ((buyerAbility.Value + (buyerAbility.GetValueGain(experienceValue) / 2)) / 10.0); double studySeasons = experienceValue / VisStudyRate; double visNeeded = studySeasons * visUsedPerStudySeason; // scale visNeeded according to vis type if (MagicArts.IsTechnique(bookDesire.Ability)) { visNeeded *= 4; } else if (MagicArts.IsArt(bookDesire.Ability) && bookDesire.Ability != MagicArts.Vim) { visNeeded *= 2; } // for now, scale vis according to quality of book vs. quality of vis study visNeeded *= q / VisStudyRate; // divide this visNeed valuation by how many seasons are left for writing double seasonsLeft = Math.Ceiling(l / writingRate); double writingValue = visNeeded / seasonsLeft; if (writingValue > currentBestBookValue) { // write this summa bestBook = new Summa { Quality = q, Level = l, Topic = bookDesire.Ability, Title = bookDesire.Ability.AbilityName + " Summa for Dummies by " + Name, Value = writingValue }; currentBestBookValue = writingValue; } } } } // consider the value of writing a tractatus var charAbility = GetAbility(bookDesire.Ability); if (!consideredTopics.Contains(bookDesire.Ability.AbilityId) && tractatusValue > currentBestBookValue && CanWriteTractatus(charAbility)) { ushort previouslyWrittenCount = GetTractatiiWrittenOnTopic(bookDesire.Ability); string name = Name + " " + bookDesire.Ability.AbilityName + " T" + previouslyWrittenCount.ToString(); bestBook = new Tractatus { Topic = bookDesire.Ability, Title = name, Value = tractatusValue }; currentBestBookValue = tractatusValue; } consideredTopics.Add(bookDesire.Ability.AbilityId); } return(bestBook); }