/// <summary> /// Returns a random quest ID from QuestIdSkillRankList, /// based on the current Erinn day and the player's blacksmithing /// PTJ level/skill rank (via <paramref name="npc"/>). /// </summary> /// <param name="npc"></param> /// <returns> /// Will always return a quest ID of the given <paramref name="level"/>. /// However, if no job of the matching rank can be found, /// a job of next-highest rank will be returned. /// </returns> /// <remarks> /// As there are (at the time of writing) only jobs of rank F, C, B, and A, /// the ranks that are supplied to and returned from this method are as follows: /// <list type="table"> /// <listheader> <term>Supplied Rank</term> <term>Returned Rank</term> </listheader> /// <item> <term>(Unlearned)</term> <term>rF</term> </item> /// <item> <term>rN ~ rD</term> <term>rF</term> </item> /// <item> <term>rC ~ rA</term> <term>[Same as supplied]</term></item> /// <item> <term>r9 and up</term> <term>rA</term> </item> /// </list> /// /// See also: http://wiki.mabinogiworld.com/view/Thread:Talk:Edern/Part-time_job_requests /// </remarks> public int RandomPtj(NpcScript npc) { // Determine player's Blacksmithing skill level var playerSkills = npc.Player.Skills; var skillRank = playerSkills.Has(SkillId.Blacksmithing) ? playerSkills.Get(SkillId.Blacksmithing).Info.Rank : SkillRank.RF; // Default to RF jobs if player does not know Blacksmithing. var ptjQuestLevel = npc.GetPtjQuestLevel(JobType); Func <SkillRank, IEnumerable <int> > GetSameRankQuests = r => QuestIdSkillRankList .Where(pair => pair.Item2 == r) // Filter on skill rank .Select(pair => pair.Item1); // Get resulting quest IDs Func <IEnumerable <int>, int> GetRandomIdOfTheDay = ids => ids.ElementAt(new Random(ErinnTime.Now.DateTimeStamp).Next(ids.Count())); var rankProbe = skillRank; var sameLevelQuestIds = npc.GetLevelMatchingQuestIds(JobType, QuestIdSkillRankList.Select(pair => pair.Item1).ToArray()); IEnumerable <int> matchingQuestIds; // Clamp on rank A, the most difficult job available. if (rankProbe > SkillRank.RA) { rankProbe = SkillRank.RA; } // Filter on skill rank, retrying on a lower rank if no results. while (rankProbe >= SkillRank.RC) { // Merge with filter on sameLevelQuestIds. matchingQuestIds = GetSameRankQuests(rankProbe).Where(id => sameLevelQuestIds.Contains(id)); if (matchingQuestIds.Any()) { return(GetRandomIdOfTheDay(matchingQuestIds)); } else { --rankProbe; // Retry on lower rank. } } // Else no matching jobs at A, B, or C. // Try rank F jobs? matchingQuestIds = GetSameRankQuests(SkillRank.RF).Where(id => sameLevelQuestIds.Contains(id)); if (matchingQuestIds.Any()) { return(GetRandomIdOfTheDay(matchingQuestIds)); } // Else no matching jobs at F. // If this point is reached, // we were not able to find a quest for the player. throw new Exception(string.Format("EdernPtjScript.RandomPtj: Unable to provide a quest for level:{0}, rank:{1}", ptjQuestLevel, skillRank)); }