public IBook WriteBook(Ability topic, string name, Ability exposureAbility, double desiredLevel = 0) { // grant exposure experience List <Ability> abilityList = new List <Ability>(_writingAbilities); abilityList.Add(topic); GetAbility(exposureAbility).AddExperience(2); // TODO: When should books moved from the owned list to the covenant library? if (desiredLevel == 1000) { Tractatus t = WriteTractatus(topic, name); _booksOwned.Add(t); return(t); } else { Summa s = WriteSumma(topic, name, desiredLevel); if (s != null) { _booksOwned.Add(s); } return(s); } }
public override bool Equals(object obj) { if (obj.GetType() != typeof(Summa)) { return(false); } Summa otherBook = (Summa)obj; return (this.Author == otherBook.Author && this.Level == otherBook.Level && this.Quality == otherBook.Quality && this.Title == otherBook.Title && this.Topic == otherBook.Topic); }
/// <summary> /// Works on a summa on the given topic. /// If the work invested is not enough to finish a book on that topic, /// the incomplete work is added to the list /// </summary> /// <param name="topic"></param> /// <param name="desiredLevel"></param> /// <returns>the summa if it is completed, null otherwise</returns> protected Summa WriteSumma(Ability topic, string name, double desiredLevel) { Summa s; CharacterAbilityBase ability = GetAbility(topic); Summa previousWork = _incompleteBooks.Where(b => b.Title == name).FirstOrDefault(); if (previousWork == null) { double difference = (ability.Value / 2) - desiredLevel; if (difference < 0) { throw new ArgumentOutOfRangeException(); } s = new Summa() { Author = this, Level = desiredLevel, Topic = topic, Title = name, Quality = MagicArts.IsArt(ability.Ability) ? this.GetAttribute(AttributeType.Communication).Value + difference + 6 : this.GetAttribute(AttributeType.Communication).Value + (difference * 3) + 6 }; } else { s = previousWork; } s.PointsComplete += this.GetAttribute(AttributeType.Communication).Value + GetAbility(_writingLanguage).Value; if (s.PointsComplete >= s.GetWritingPointsNeeded()) { _booksWritten.Add(s); if (previousWork != null) { _incompleteBooks.Remove(previousWork); } return(s); } return(null); }
/// <summary> /// Works on a summa on the given topic. /// If the work invested is not enough to finish a book on that topic, /// the incomplete work is added to the list /// </summary> /// <param name="topic"></param> /// <param name="desiredLevel"></param> /// <returns>the summa if it is completed, null otherwise</returns> protected Summa WriteSumma(Ability topic, string name, double desiredLevel) { Summa s; CharacterAbilityBase ability = GetAbility(topic); Summa previousWork = _incompleteBooks.Where(b => b.Title == name).FirstOrDefault(); if (previousWork == null) { double difference = (ability.Value / 2) - desiredLevel; if (difference < 0) { throw new ArgumentOutOfRangeException(); } s = new Summa() { Author = this, Level = desiredLevel, Topic = topic, Title = name, Quality = MagicArts.IsArt(ability.Ability) ? this.GetAttribute(AttributeType.Communication).Value + difference + 6 : this.GetAttribute(AttributeType.Communication).Value + (difference * 3) + 6 }; } else { s = previousWork; } s.PointsComplete += this.GetAttribute(AttributeType.Communication).Value + GetAbility(_writingLanguage).Value; if (s.PointsComplete >= s.GetWritingPointsNeeded()) { _booksWritten.Add(s); if (previousWork != null) { _incompleteBooks.Remove(previousWork); } return s; } return null; }
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); }