/// <summary> /// Sends NewQuest to creature's client. /// </summary> /// <param name="character"></param> /// <param name="quest"></param> public static void NewQuest(Creature character, Quest quest) { var packet = new Packet(Op.NewQuest, character.EntityId); packet.AddQuest(quest); character.Client.Send(packet); }
/// <summary> /// Broadcasts QuestUpdate in party. /// </summary> /// <param name="creature"></param> /// <param name="quest"></param> public static void QuestUpdate(Party party, Quest quest) { var packet = new Packet(Op.QuestUpdate, 0); packet.AddQuestUpdate(quest); party.Broadcast(packet, true); }
/// <summary> /// Sends QuestUpdate to creature's client. /// </summary> /// <param name="creature"></param> /// <param name="quest"></param> public static void QuestUpdate(Creature creature, Quest quest) { var packet = new Packet(Op.QuestUpdate, creature.EntityId); packet.AddQuestUpdate(quest); creature.Client.Send(packet); }
/// <summary> /// Adds quest to manager and informs the client about it. /// </summary> /// <param name="quest"></param> public void Add(Quest quest) { // Check quest item if (quest.QuestItem == null) throw new InvalidOperationException("Quest item can't be null."); if (!_creature.Inventory.Has(quest.QuestItem)) throw new InvalidOperationException("The quest item needs to be in the creature's inventory first."); this.AddSilent(quest); // Quest info Send.NewQuest(_creature, quest); // Start PTJ clock if (quest.Data.Type == QuestType.Deliver) Send.QuestStartPtj(_creature, quest.UniqueId); // Initial objective check, for things like collect and reach rank, // that may be done already. quest.Data.CheckCurrentObjective(_creature); // Give item to deliver for first deliver objective var deliverObjective = quest.Data.Objectives[quest.CurrentObjectiveOrLast.Ident] as QuestObjectiveDeliver; if (deliverObjective != null) { var item = new Item(deliverObjective.ItemId); item.Amount = Math.Min(1, deliverObjective.Amount); _creature.Inventory.Add(item, true); } }
/// <summary> /// Completes and removes quest, if it exists. /// </summary> /// <param name="questId"></param> public bool Complete(Quest quest) { var success = this.Complete(quest, true); if (success) { quest.State = QuestState.Complete; ChannelServer.Instance.Events.OnPlayerCompletesQuest(_creature, quest.Id); } return success; }
/// <summary> /// Adds quest to manager and informs the client about it. /// </summary> /// <param name="quest"></param> public void Add(Quest quest) { // Check quest item if (quest.QuestItem == null) throw new InvalidOperationException("Quest item can't be null."); if (!_creature.Inventory.Has(quest.QuestItem)) throw new InvalidOperationException("The quest item needs to be in the creature's inventory first."); this.AddSilent(quest); // Quest info Send.NewQuest(_creature, quest); // Start PTJ clock if (quest.Data.Type == QuestType.Deliver) Send.QuestStartPtj(_creature, quest.UniqueId); // Initial objective check, for things like collect and reach rank, // that may be done already. quest.Data.CheckCurrentObjective(_creature); }
/// <summary> /// Adds quest to manager and informs the client about it. /// </summary> /// <param name="quest"></param> public void Add(Quest quest) { // Check quest item if (quest.QuestItem == null) throw new InvalidOperationException("Quest item can't be null."); if (!_creature.Inventory.Has(quest.QuestItem)) throw new InvalidOperationException("The quest item needs to be in the creature's inventory first."); this.AddSilent(quest); // Quest info Send.NewQuest(_creature, quest); // Start PTJ clock if (quest.Data.Type == QuestType.Deliver) Send.QuestStartPtj(_creature, quest.UniqueId); // Initial objective check, for things like collect and reach rank, // that may be done already. quest.Data.CheckCurrentObjective(_creature); // Give item to deliver for first deliver objective var deliverObjective = quest.Data.Objectives[quest.CurrentObjectiveOrLast.Ident] as QuestObjectiveDeliver; if (deliverObjective != null) { var item = new Item(deliverObjective.ItemId); item.Amount = Math.Min(1, deliverObjective.Amount); _creature.Inventory.Add(item, true); } // Receive event // XXX: Could be used for the deliver objectives above as well? // It would make more sense to always give delvier items // automatically though, not only on start. quest.Data.OnReceive(_creature); }
/// <summary> /// Sends QuestUpdate to creature's client. /// </summary> /// <param name="creature"></param> /// <param name="quest"></param> public static void QuestUpdate(Creature creature, Quest quest) { var progress = quest.GetList(); var packet = new Packet(Op.QuestUpdate, creature.EntityId); packet.PutLong(quest.UniqueId); packet.PutByte(1); packet.PutInt(progress.Count); foreach (var p in progress) { packet.PutInt(p.Count); // [180600, NA187 (25.06.2014)] ? { packet.PutFloat(0); } packet.PutByte(p.Done); packet.PutByte(p.Unlocked); } packet.PutByte(0); packet.PutByte(0); creature.Client.Send(packet); }
/// <summary> /// Creates quest scroll for the given quest id. /// </summary> /// <remarks> /// During the creation, a quest is created and included with the item. /// </remarks> /// <param name="questId"></param> /// <returns></returns> public static Item CreateQuestScroll(int questId) { // Get quest information var questScript = ChannelServer.Instance.ScriptManager.QuestScripts.Get(questId); if (questScript == null) throw new ArgumentException("Quest '" + questId + "' not found."); var quest = new Quest(questId); var item = new Item(questScript.ScrollId); item.MetaData1.Parse(quest.Data.MetaData.ToString()); item.Quest = quest; quest.QuestItem = item; return item; }
public override void Reward(Creature creature, Quest quest) { creature.Inventory.Add(this.ItemId, this.Amount); Send.AcquireItemInfo(creature, this.ItemId, this.Amount); }
/// <summary> /// Completes and removes quest without rewards, if it exists. /// </summary> /// <param name="quest"></param> /// <returns></returns> public bool GiveUp(Quest quest) { if (!this.Has(quest)) throw new ArgumentException("Quest not found in this manager."); var success = this.EndQuest(quest, -1, false); // Remove quest item on success, which will also remove the // quest from the manager. if (success) _creature.Inventory.Remove(quest.QuestItem); return success; }
/// <summary> /// Sets party quest, removing previous ones and updating all members. /// </summary> /// <param name="quest"></param> public void SetPartyQuest(Quest quest) { if (this.Quest != null) this.UnsetPartyQuest(); this.Quest = quest; // Give quest to other members lock (_sync) { foreach (var member in _members.Where(a => a != this.Leader)) { member.Quests.AddSilent(quest); Send.NewQuest(member, quest); } } Send.PartySetActiveQuest(this, quest.UniqueId); }
/// <summary> /// Unsets party quest, removes it from all normal member's managers, /// and updates the clients. Returns false if no party quest was set. /// </summary> /// <param name="quest"></param> public bool UnsetPartyQuest() { var quest = this.Quest; if (quest == null) return false; this.Quest = null; // Remove quest from other members lock (_sync) { foreach (var member in _members.Where(a => a != this.Leader)) member.Quests.Remove(quest); } Send.PartyUnsetActiveQuest(this, quest.UniqueId); return true; }
/// <summary> /// Completes and removes quest, if it exists, giving the rewards /// in the process, if warranted. /// </summary> /// <param name="quest"></param> /// <param name="rewardGroup">Reward group to use, set to -1 for no rewards.</param> /// <param name="owl">Show owl delivering the rewards?</param> /// <returns></returns> private bool EndQuest(Quest quest, int rewardGroup, bool owl) { var result = quest.GetResult(); // Increase PTJ done/success if (quest.Data.Type == QuestType.Deliver) this.ModifyPtjTrackRecord(quest.Data.PtjType, +1, (result == QuestResult.Perfect ? +1 : 0)); // Rewards if (rewardGroup != -1) { var rewards = quest.Data.GetRewards(rewardGroup, result); if (rewards.Count == 0) Log.Warning("CreatureQuests.EndQuest: No rewards for group '{0}' at result '{1}' in quest '{2}'.", rewardGroup, result, quest.Id); else this.GiveRewards(quest, rewards, owl); } // Remove from quest log. Send.QuestClear(_creature, quest.UniqueId); // Update PTJ stuff and stop clock if (quest.Data.Type == QuestType.Deliver) { var record = this.GetPtjTrackRecord(quest.Data.PtjType); Send.QuestUpdatePtj(_creature, quest.Data.PtjType, record.Done, record.Success); Send.QuestEndPtj(_creature); } return true; }
public static void AddQuestUpdate(this Packet packet, Quest quest) { var progress = quest.GetList(); packet.PutLong(quest.UniqueId); packet.PutByte(1); packet.PutInt(progress.Count); foreach (var p in progress) { packet.PutInt(p.Count); // [180600, NA187 (25.06.2014)] ? { packet.PutFloat(0); } packet.PutByte(p.Done); packet.PutByte(p.Unlocked); } packet.PutByte(0); packet.PutByte(0); }
public override void Reward(Creature creature, Quest quest) { creature.Inventory.AddGold(this.Amount); Send.AcquireInfo(creature, "gold", this.Amount); }
public override void Reward(Creature creature, Quest quest) { creature.GiveAp(this.Amount); Send.AcquireInfo(creature, "ap", this.Amount); }
public override void Reward(Creature creature, Quest quest) { creature.Inventory.Add(Item.CreateQuestScroll(this.QuestId), true); }
public override void Reward(Creature creature, Quest quest) { creature.AcquireItem(Item.Create(this.ItemId, this.Amount)); }
/// <summary> /// Returns true if creature has the given quest. /// </summary> /// <param name="quest"></param> /// <returns></returns> public bool Has(Quest quest) { lock (_quests) return _quests.Contains(quest); }
/// <summary> /// Gives quest rewards to creature. /// </summary> /// <param name="quest">Quest the rewards come from.</param> /// <param name="rewards">Rewards to give to the creature.</param> /// <param name="owl">Show owl delivering the rewards?</param> private void GiveRewards(Quest quest, ICollection<QuestReward> rewards, bool owl) { if (rewards.Count == 0) return; if (owl) Send.QuestOwlComplete(_creature, quest.UniqueId); foreach (var reward in rewards) { try { reward.Reward(_creature, quest); } catch (NotImplementedException) { Log.Unimplemented("Quest.Complete: Reward '{0}'.", reward.Type); } } }
/// <summary> /// Adds quest to manager, does not update client, send owl, /// or anything else. /// </summary> /// <remarks> /// This method is for initialization, use Give during run-time. /// </remarks> /// <param name="quest"></param> public void AddSilent(Quest quest) { lock (_quests) _quests.Add(quest); }
public override void Reward(Creature creature, Quest quest) { creature.AcquireItem(Item.CreateEnchant(OptionSetId)); }
/// <summary> /// Starts PTJ quest. /// </summary> /// <param name="questId"></param> public void StartPtj(int questId) { try { var quest = new Quest(questId); quest.MetaData.SetByte("QMRTCT", (byte)quest.Data.RewardGroups.Count); quest.MetaData.SetInt("QMRTBF", 0x4321); // (specifies which groups to display at which position, 1 group per hex char) quest.MetaData.SetString("QRQSTR", this.NPC.Name); quest.MetaData.SetBool("QMMABF", false); // Calculate deadline, based on current time and quest data var now = ErinnTime.Now; var diffHours = Math.Max(0, quest.Data.DeadlineHour - now.Hour - 1); var diffMins = Math.Max(0, 60 - now.Minute); var deadline = DateTime.Now.AddTicks(diffHours * ErinnTime.TicksPerHour + diffMins * ErinnTime.TicksPerMinute); quest.Deadline = deadline; this.Player.Quests.Start(quest, false); } catch (Exception ex) { Log.Exception(ex, "NpcScript.StartPtj: Quest '{0}'", questId); this.Msg("(Error)"); } }
public override void Reward(Creature creature, Quest quest) { // Only give skill if char doesn't have it or rank is lower. if (creature.Skills.Has(this.SkillId, this.Rank)) return; creature.Skills.Give(this.SkillId, this.Rank); if (this.Training != 0) creature.Skills.Train(this.SkillId, this.Rank, this.Training); }
/// <summary> /// Updates quest on client(s), depending on its type. /// </summary> /// <param name="creature"></param> /// <param name="quest"></param> private void UpdateQuest(Creature creature, Quest quest) { if (!this.IsPartyQuest) Send.QuestUpdate(creature, quest); else Send.QuestUpdate(creature.Party, quest); }
public override void Reward(Creature creature, Quest quest) { throw new NotImplementedException(); }
/// <summary> /// Returns true if creature can make progress on this quest. /// </summary> /// <remarks> /// Used from objective event handlers, to see if the quest should /// receive the progress. /// </remarks> /// <param name="creature"></param> /// <param name="quest"></param> /// <returns></returns> private bool CanMakeProgress(Creature creature, Quest quest) { // Party quests can only make progress if they're active if (this.IsPartyQuest) return (creature.IsInParty && creature.Party.Quest == quest); // TODO: Guild quests, outside, delay return true; }
/// <summary> /// Gives reward to creature. /// </summary> /// <param name="creature"></param> /// <param name="quest"></param> public abstract void Reward(Creature creature, Quest quest);
public static void AddQuest(this Packet packet, Quest quest) { if (quest.Data == null) throw new Exception("AddQuest: Missing quest data for '" + quest.Id.ToString() + "'."); packet.PutLong(quest.UniqueId); packet.PutByte(0); packet.PutLong(quest.QuestItem.EntityId); packet.PutByte((byte)quest.Data.Type); // 0 = blue icon, 2 = normal, 4 = exploration, 7 = shadow (changes structure slightly) // Client values that might make sense: // Delivery: 1? (id == 506401?) // Event: 1? ((this + 80) == 18?) // Homework: 1? ((this + 80) >= 10000?) // Exploration: 4|5 // Escort: 6 // Shadow: 7|8 // Bingo: 9 // GameQuest: 2|4|5 // GuildQuest: 0 (id >= 110001 < 120000?) // PartyQuest: 0 (id >= 100000 < 110000?), blue icon with party symbol, turns yellow if active packet.PutInt(quest.Id); // Range is important for the tabs. // 201000~201999 : event // 202000~209999 : normal // 210000~239999 : goddess // 240000~289999 : normal // 290000~290599 : alchemist // 290600~291999 : normal // 292000~292599 : alchemist // 292600~292999 : normal // 293000~293599 : alchemist // 293600~293999 : shakespear (default) // 294000~294599 : shakespear (hamlet) // 294600~294999 : shakespear (default) // 295000~295599 : shakespear (romeo and juliet) // 295600~295999 : shakespear (default) // 296000~296599 : shakespear (merchant) // 296600~296999 : shakespear (default) // 297000~297599 : shakespear (macbeth) // 297600~______ : normal packet.PutString(quest.Data.Name); packet.PutString(quest.Data.Description); packet.PutString(quest.Data.AdditionalInfo); packet.PutInt(1); packet.PutInt(quest.QuestItem.Info.Id); packet.PutByte(quest.Data.Cancelable); packet.PutByte(0); packet.PutByte(0); // 1 = blue icon packet.PutByte(0); // [180300, NA166 (18.09.2013)] ? { packet.PutByte(0); packet.PutByte(0); packet.PutByte(0); } // [190200, NA203 (22.04.2015)] ? { packet.PutByte(0); } packet.PutString(""); // data\gfx\image\gui_temporary_quest.dds packet.PutInt(0); // 4, x y ? packet.PutInt(0); packet.PutString(""); // <xml soundset="4" npc="GUI_NPCportrait_Lanier"/> packet.PutString(quest.MetaData.ToString()); switch (quest.Data.Type) { case QuestType.Deliver: packet.PutInt((int)quest.Data.PtjType); packet.PutInt(quest.Data.StartHour); packet.PutInt(quest.Data.ReportHour); packet.PutInt(quest.Data.DeadlineHour); packet.PutLong(quest.Deadline); break; default: packet.PutInt(0); packet.PutInt(0); break; } packet.PutInt(quest.Data.Objectives.Count); foreach (var objectiveData in quest.Data.Objectives) { var objective = objectiveData.Value; var progress = quest.GetProgress(objectiveData.Key); // Objective packet.PutByte((byte)objective.Type); packet.PutString(objective.Description); packet.PutString(objective.MetaData.ToString()); // 3 - TARGECHAR:s:shamala;TARGETCOUNT:4:1; - Ask Shamala about collecting transformations // 14 - TARGETITEM:4:40183;TARGETCOUNT:4:1; - Break a nearby tree // 1 - TGTSID:s:/brownphysisfoxkid/;TARGETCOUNT:4:10;TGTCLS:2:0; - Hunt 10 Young Brown Physis Foxes // 9 - TGTSKL:2:23002;TGTLVL:2:1;TARGETCOUNT:4:1; - Combat Mastery rank F reached // 19 - TGTCLS:2:3906;TARGETCOUNT:4:1; - Win at least one match in the preliminaries or the finals of the Jousting Tournament. // 18 - TGTCLS:2:3502;TARGETCOUNT:4:1; - Read the Author's Notebook. // 4 - TARGECHAR:s:duncan;TARGETITEM:4:75473;TARGETCOUNT:4:1; - Deliver the Author's Notebook to Duncan. // 15 - TGTLVL:2:15;TARGETCOUNT:4:1; - Reach Lv. 15 // 2 - TARGETITEM:4:52027;TARGETCOUNT:4:10;QO_FLAG:4:1; - Harvest 10 Bundles of Wheat // 22 - TGTSID:s:/ski/start/;TARGETITEM:4:0;EXCNT:4:0;TGITM2:4:0;EXCNT2:4:0;TARGETCOUNT:4:1; - Click on the Start Flag. // 47 - TARGETCOUNT:4:1;TGTCLS:4:730205; - Clear the Monkey Mash Mission. // 52 - QO_FLAG:b:true;TARGETCOUNT:4:1; - Collect for the Transformation Diary // 50 - TARGETRACE:4:9;TARGETCOUNT:4:1; - Transform into a Kiwi. // 54 - TARGETRACE:4:9;TARGETCOUNT:4:1; - Collect Frail Green Kiwi perfectly. // 31 - TARGETCOUNT:4:1;TGTSID:s:/Gathering_Knife/; - Equip Gathering Knife // 32 - TARGETCOUNT:4:5;TARGETITEM:4:60009;TGTSID:s:/Gathering_Knife/; - Sheared 5 Sheep // 13 - TARGETCOUNT:4:1;TGTCLS:s:TirCho_Ciar_Low_Dungeon; - Clear Ciar Basic Dungeon // Type theory: // 1 : Kill x of y // 2 : Collect x of y // 3 : Talk to x // 4 : Bring x to y // 9 : Reach rank x on skill y // 13 : Clear dungeon // 14 : ? // 15 : Reach lvl x // 18 : Do something with item x ? // 19 : Clear something, like jousting or a dungeon? // 31 : Equip item, matching tag X // 32 : Gather item x, gather equipment doesn't seem to matter // Progress packet.PutInt(progress.Count); // [180600, NA187 (25.06.2014)] ? { packet.PutFloat(0); } packet.PutByte(progress.Done); packet.PutByte(progress.Unlocked); // Target location packet.PutByte(objective.RegionId > 0); if (objective.RegionId > 0) { packet.PutInt(objective.RegionId); packet.PutInt(objective.X); packet.PutInt(objective.Y); } } // Rewards packet.PutByte((byte)quest.Data.RewardGroups.Count); foreach (var group in quest.Data.RewardGroups.Values.OrderBy(a => a.Id)) { // Group id has to be !0 for client to display rewards for PTJs packet.PutByte((byte)group.Id); packet.PutByte((byte)group.Type); packet.PutByte(group.PerfectOnly); packet.PutByte((byte)group.Rewards.Count); foreach (var reward in group.Rewards) { packet.PutByte((byte)reward.Type); packet.PutString(reward.ToString()); packet.PutByte((byte)reward.Result); packet.PutByte(reward.Visible); // If false, displays "(시간초과시)" (timeout) after the // reward. Probably not used anymore, maybe players could // still get certain rewards after a timeout at some // point? packet.PutByte(true); } } packet.PutByte(0); }