public double UseVis(Ability visType, double amount) { if (!MagicArts.IsArt(visType)) { throw new ArgumentException("Only magic arts have vis!"); } if (_visStock[visType] + (Covenant == null ? 0 : Covenant.GetVis(visType)) < amount) { throw new ArgumentException("Insufficient vis available!"); } double covVis = Covenant == null ? 0 : Covenant.GetVis(visType); if (covVis >= amount) { Covenant.RemoveVis(visType, amount); } else { if (Covenant != null) { amount -= covVis; Covenant.RemoveVis(visType, covVis); } _visStock[visType] -= amount; } return(_visStock[visType]); }
public ApprenticeGoal(Character character, uint?dueDate, double desire) : base(character, dueDate, desire) { foreach (Ability ability in MagicArts.GetEnumerator()) { Conditions.Add(new AbilityScoreCondition(character, dueDate == null ? 200 : (uint)(dueDate - 1), desire, ability, 5)); } }
public override void AddActionPreferencesToList(ConsideredActions alreadyConsidered, IList <string> log) { _currentTotal = GetTotal(); if (!ConditionFulfilled) { // the basic structure is (portion of necessary gain action provides) * (desire / time left until needed) foreach (Ability ability in Abilities) { if (!MagicArts.IsArt(ability)) { AddPracticeToActionList(ability, alreadyConsidered, log); } else if (Character.GetType() == typeof(Magus)) { AddVisUseToActionList(ability, alreadyConsidered, log); } var topicalBooks = Character.ReadableBooks.Where(b => b.Topic == ability); if (topicalBooks.Any()) { AddReadingToActionList(topicalBooks, ability, alreadyConsidered, log); } } } }
public virtual void ModifyActionList(Character character, ConsideredActions alreadyConsidered, IList <string> log) { if (BaseDueDate != null && BaseDueDate == 0) { return; } IEnumerable <IBook> readableBooks = character.ReadableBooks; foreach (Ability ability in _abilities) { // Handle Reading CharacterAbilityBase charAbility = character.GetAbility(ability); var topicalBooks = readableBooks.Where(b => b.Topic == ability); HandleReading(character, alreadyConsidered, topicalBooks); // Handle Practice if (!MagicArts.IsArt(ability)) { HandlePractice(character, alreadyConsidered, log, ability); } else if (character.GetType() == typeof(Magus)) { Magus mage = (Magus)character; HandleVisUse(mage, charAbility, alreadyConsidered, log); } // TODO: Learning By Training // TODO: Learning by Teaching } }
public double GetVis(Ability visType) { if (!MagicArts.IsArt(visType)) { throw new ArgumentException("Only magic arts have vis!"); } return(_visStock.ContainsKey(visType) ? _visStock[visType] : 0); }
/// <summary> /// Determines the value of an experience gain in terms of practice seasons /// </summary> /// <param name="ability"></param> /// <param name="gain"></param> /// <returns>the season equivalence of this gain</returns> public virtual double RateSeasonalExperienceGain(Ability ability, double gain) { if (MagicArts.IsArt(ability)) { return(0); } return(gain / 4); }
public ArtPair(Ability technique, Ability form) { if (!MagicArts.IsTechnique(technique) || !MagicArts.IsForm(form)) { throw new ArgumentException("one of the arts used to initialize this pair is invalid!"); } Technique = technique; Form = form; }
public VisStudying(Ability art, double desire) { if (!MagicArts.IsArt(art)) { throw new ArgumentException("Only magic arts have vis associated with them!"); } Art = art; Desire = desire; Action = Activity.StudyVis; }
/// <summary> /// Looks at the giver and receiver vis desires, and sees what combination of vis can meet the desires /// </summary> /// <param name="price">the agreed upon price, in Vim vis</param> /// <param name="giverVisDesires"></param> /// <param name="receiverVisDesires"></param> /// <returns></returns> private IEnumerable <VisOffer> GenerateVisOffer(double price, VisDesire[] giverVisDesires, VisDesire[] receiverVisDesires) { double remainingPrice = price; List <VisOffer> offerSegments = new List <VisOffer>(); // order the receiver's desires from largest to smallest foreach (VisDesire desire in receiverVisDesires.Where(d => d.Quantity > 0).OrderByDescending(d => d.Quantity)) { var giverArt = giverVisDesires.First(d => d.Art == desire.Art); // see if the giver can supply this type of vis if (giverArt.Quantity < 0) { // they have some to trade double maxNeed = remainingPrice; if (MagicArts.IsTechnique(desire.Art)) { maxNeed /= 4.0; if (giverArt.Quantity * -1 >= maxNeed) { offerSegments.Add(new VisOffer(desire.Art, maxNeed)); remainingPrice = 0; break; } else { // we're going to need more than this, so use all of this vis and move on offerSegments.Add(new VisOffer(desire.Art, giverArt.Quantity * -1)); remainingPrice -= giverArt.Quantity * -4; } } else if (desire.Art != MagicArts.Vim) { maxNeed /= 2.0; if (giverArt.Quantity * -1 >= maxNeed) { offerSegments.Add(new VisOffer(desire.Art, maxNeed)); remainingPrice = 0; break; } else { // we're going to need more than this, so use all of this vis and move on offerSegments.Add(new VisOffer(desire.Art, giverArt.Quantity * -1)); remainingPrice -= giverArt.Quantity * -2; } } } } if (remainingPrice > 0) { return(null); } return(offerSegments); }
public override CharacterAbilityBase GetAbility(Ability ability) { if (MagicArts.IsArt(ability)) { return(Arts.GetAbility(ability)); } else { return(base.GetAbility(ability)); } }
public double AddVis(Ability visType, double amount) { if (MagicArts.IsArt(visType)) { if (_visStock.ContainsKey(visType)) { _visStock[visType] += amount; } else { _visStock[visType] = amount; } return(_visStock[visType]); } return(0); }
public double GainVis(Ability visType, double amount) { if (!MagicArts.IsArt(visType)) { throw new ArgumentException("Only magic arts have vis!"); } if (_visStock.ContainsKey(visType)) { _visStock[visType] += amount; } else { _visStock[visType] = amount; } return(_visStock[visType]); }
public double RemoveVis(Ability visType, double amount) { if (amount <= 0) { return(_visStock.ContainsKey(visType) ? _visStock[visType] : 0); } if (!MagicArts.IsArt(visType)) { throw new ArgumentException("Only magic arts have vis!"); } if (!_visStock.ContainsKey(visType) || _visStock[visType] < amount) { throw new ArgumentException("Insufficient vis available!"); } _visStock[visType] -= amount; return(_visStock[visType]); }
public override void ModifyVisDesires(VisDesire[] desires) { foreach (Ability ability in this.Abilities) { if (MagicArts.IsArt(ability)) { double visNeed = 0.5 + (this.Character.GetAbility(ability).Value / 10.0); foreach (VisDesire visDesire in desires) { if (visDesire.Art == ability) { visDesire.Quantity += visNeed; break; } } } } }
/// <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); }
private double CalculateVisValue() { double total = 0; foreach (VisOffer offer in VisOffers) { if (MagicArts.IsTechnique(offer.Art)) { total += offer.Quantity * 4.0; } else if (offer.Art != MagicArts.Vim) { total += offer.Quantity * 2.0; } else { total += offer.Quantity; } } return(total); }
public WorldGenerator() { ImmutableMultiton <int, Ability> .Initialize(MagicArts.GetEnumerator()); ImmutableMultiton <int, Ability> .Initialize(Abilities.GetEnumerator()); // read out values in multiton foreach (int i in ImmutableMultiton <int, Ability> .GetKeys()) { Ability ability = ImmutableMultiton <int, Ability> .GetInstance(i); if (ability.AbilityName == "Latin") { _latin = ability; } else if (ability.AbilityName == "Magic Theory") { _magicTheory = ability; } else if (ability.AbilityName == "Artes Liberales") { _artLib = ability; } else if (ability.AbilityName == "Area Lore") { _areaLore = ability; } } InitializeComponent(); foreach (Magus founder in Founders.GetEnumerator()) { _magusArray[_magusCount] = founder; _magusCount++; } lstMembers.DataSource = _magusArray.Take(_magusCount).ToList(); _log = new List <string>(); lstAdvance.DataSource = _log; }
public Magus(Ability magicAbility, Ability writingLanguage, Ability writingAbility, Ability areaAbility, uint baseAge = 20) : base(writingLanguage, writingAbility, areaAbility, baseAge) { _magicAbility = magicAbility; Arts = new Arts(); Covenant = null; Laboratory = null; _visStock = new Dictionary <Ability, double>(); SpellList = new List <Spell>(); //_tractatusGoals = new List<TractatusGoal>(); //_summaGoals = new List<SummaGoal>(); _partialSpell = null; _partialSpellProgress = 0; VisStudyRate = 6.75; House = Houses.Apprentice; foreach (Ability art in MagicArts.GetEnumerator()) { _visStock[art] = 0; } InitializeGoals(); }
/// <summary> /// Determines the value of an experience gain in terms of the value of vis, /// and the amount of time it would take the character to produce and learn from /// that amount of vis /// </summary> /// <param name="ability"></param> /// <param name="gain"></param> /// <returns>the vis equivalence (vis savings) of this gain relative to vis study</returns> public override double RateSeasonalExperienceGain(Ability ability, double gain) { if (!MagicArts.IsArt(ability)) { return(base.RateSeasonalExperienceGain(ability, gain)); } double baseDistillVisRate = GetVisDistillationRate(); double distillVisRate = baseDistillVisRate; if (MagicArts.IsTechnique(ability)) { distillVisRate /= 4.0; } else if (ability != MagicArts.Vim) { distillVisRate /= 2.0; } CharacterAbilityBase charAbility = GetAbility(ability); double visUsedPerStudySeason = 0.5 + ((charAbility.Value + (charAbility.GetValueGain(gain) / 2)) / 10.0); // the gain per season depends on how the character views vis double studySeasons = gain / VisStudyRate; double visNeeded = studySeasons * visUsedPerStudySeason; // compare to the number of seasons we would need to extract the vis // plus the number of seasons we would need to study the extracted vis double extractTime = visNeeded / distillVisRate; double totalVisEquivalent = (extractTime + studySeasons) * baseDistillVisRate; // credit back the value of the exposure gained in the process of distilling double exposureGained = 2.0 * extractTime; double exposureSeasonsOfVis = exposureGained / VisStudyRate; CharacterAbilityBase vim = GetAbility(MagicArts.Vim); CharacterAbilityBase creo = GetAbility(MagicArts.Creo); CharacterAbilityBase exposureAbility = creo.Value < vim.Value ? creo : vim; double visValueOfExposure = 0.5 + ((exposureAbility.Value + (exposureAbility.GetValueGain(exposureGained) / 2)) / 10.0) * exposureSeasonsOfVis; return(totalVisEquivalent - visValueOfExposure); }
public override void Advance() { // harvest vis foreach (Aura aura in KnownAuras) { foreach (VisSource source in aura.VisSources) { if ((CurrentSeason & source.Seasons) == CurrentSeason) { _visStock[source.Art] += source.Amount; } } } Log.Add("VIS STOCK"); foreach (Ability art in MagicArts.GetEnumerator()) { if (_visStock[art] > 0) { Log.Add(art.AbilityName + ": " + _visStock[art].ToString("0.00")); } } base.Advance(); }
protected IEnumerable <BookForTrade> EvaluateBookValuesAsSeller(IEnumerable <IBook> books) { List <BookForTrade> list = new List <BookForTrade>(); double distillRate = GetVisDistillationRate(); foreach (IBook book in books) { if (book.Level == 1000) { list.Add(new BookForTrade(book, distillRate)); } else { double writeRate = GetAbility(_writingLanguage).Value + _attributes[(int)AttributeType.Communication].Value; double seasons = book.Level / writeRate; if (!MagicArts.IsArt(book.Topic)) { seasons *= 5; } list.Add(new BookForTrade(book, distillRate * seasons)); } } return(list); }
public double GetWritingPointsNeeded() { return(MagicArts.IsArt(Topic) ? Level : Level * 5); }
private void DisplayAbilities() { dgvAbilities.AutoGenerateColumns = false; dgvAbilities.DataSource = _character.GetAbilities().Where(a => !MagicArts.IsArt(a.Ability)).OrderBy(a => a.Ability.AbilityName).ToList(); }
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); }