/// <summary> /// Inserts a new quests into the questlist. /// </summary> public static void InsertQuest(uint cid, uint QID, byte slot) { QuestBase oldQuest; QuestBase newQuest; Character Character; if (LifeCycle.TryGetById(cid, out Character)) { newQuest = Character.QuestObjectives[QID]; if (newQuest == null) if (Singleton.Quests.TryFindQuests(QID, out newQuest)) { if (slot == 1) { oldQuest = Character.QuestObjectives.OfficialQuest; Character.QuestObjectives.OfficialQuest = newQuest; newQuest.questtype = slot; } else if (slot == 2) { oldQuest = Character.QuestObjectives.PersonalQuest; Character.QuestObjectives.PersonalQuest = newQuest; newQuest.questtype = slot; } List<Saga.Quests.Objectives.ObjectiveList.StepInfo> Steps2 = QuestBase.GetSteps(Character, QID); if (Steps2.Count == 0) { newQuest.OnStart(Character.id); } if (Steps2.Count > 0) { newQuest.isnew = true; Steps2[0].State = 1; } SMSG_QUESTREMOVE spkt4 = Character.Tag as SMSG_QUESTREMOVE; if (spkt4 != null) { Character.client.Send((byte[])spkt4); Character.Tag = null; } // Send new Quest list SMSG_QUESTINFO spkt3 = new SMSG_QUESTINFO(); spkt3.SessionId = Character.id; foreach (QuestBase Quest in Character.QuestObjectives) { List<Saga.Quests.Objectives.ObjectiveList.StepInfo> Steps = QuestBase.GetSteps(Character, Quest.QuestId); spkt3.AddQuest(Quest.QuestId, (byte)Steps.Count); for (int i = 0; i < Steps.Count; i++) { Saga.Quests.Objectives.ObjectiveList.StepInfo currentStep = Steps[i]; uint nextstep = (i + 1 < Steps.Count) ? Steps[i + 1].StepId : 0; spkt3.AddQuestStep(currentStep.StepId, currentStep.State, nextstep, Quest.isnew); if (Quest.isnew == true) Quest.isnew = false; } } Character.client.Send((byte[])spkt3); newQuest.CheckQuest(Character); /* // Send waypoint contruction SMSG_SENDNAVIGATIONPOINT spkt2 = new SMSG_SENDNAVIGATIONPOINT(); spkt2.SessionId = Character.id; spkt2.QuestID = QID; foreach (Saga.Quests.Objectives.ObjectiveList.Waypoint waypoint in QuestBase.UserGetWaypoints(Character, QID)) { //Predicate to search the npc Predicate<MapObject> IsNpc = delegate(MapObject match) { return match.ModelId == waypoint.NpcId; }; MapObject myObject = Character.currentzone.Regiontree.SearchActor(IsNpc, SearchFlags.Npcs); if ( myObject != null ) { spkt2.AddPosition(waypoint.NpcId, myObject.Position.x, myObject.Position.y, myObject.Position.z); if ( Point.IsInSightRangeByRadius(Character.Position, myObject.Position)) { BaseMob temp = (BaseMob)myObject; Common.Actions.UpdateIcon(Character, temp); } } } Character.client.Send((byte[])spkt2);*/ } else { Console.WriteLine("Quest not found"); } } else { Trace.TraceError("Character not found"); } }
/// <remarks> /// Cancels only the QuestBase of it can be canceled. /// This is not yet implamented in any QuestBase of kro2, but most likely /// in the future there are going to be certain QuestBases that supports that. /// /// For example a chain of QuestBase events. /// </remarks> /// <param name="cpkt"></param> private void CM_QUESTCONFIRMCANCEL(CMSG_QUESTCONFIRMCANCEL cpkt) { if (QuestBaseID > 0) { try { QuestBase myQuestBase = this.character.QuestObjectives[QuestBaseID]; if (myQuestBase != null) { //Removes the quest this.character.QuestObjectives[QuestBaseID] = null; //Invalidates all stepinfo QuestBase.InvalidateQuest(myQuestBase, this.character); //Send over new quest list SMSG_QUESTINFO spkt3 = new SMSG_QUESTINFO(); spkt3.SessionId = this.character.id; foreach (QuestBase Quest in this.character.QuestObjectives) { List<Saga.Quests.Objectives.ObjectiveList.StepInfo> Steps = QuestBase.GetSteps(this.character, Quest.QuestId); spkt3.AddQuest(Quest.QuestId, (byte)Steps.Count); for (int i = 0; i < Steps.Count; i++) { Saga.Quests.Objectives.ObjectiveList.StepInfo currentStep = Steps[i]; uint nextstep = (i + 1 < Steps.Count) ? Steps[i + 1].StepId : 0; spkt3.AddQuestStep(currentStep.StepId, currentStep.State, nextstep, Quest.isnew); } } this.Send((byte[])spkt3); //Remove all waypoints SMSG_REMOVENAVIGATIONPOINT spkt = new SMSG_REMOVENAVIGATIONPOINT(); spkt.QuestID = QuestBaseID; spkt.SessionId = this.character.id; this.Send((byte[])spkt); //Updates all new icons CommonFunctions.RefreshPersonalRequests(this.character); CommonFunctions.UpdateNpcIcons(this.character); } } finally { //Reset our Quest Base Id QuestBaseID = 0; } } else { QuestBaseID = cpkt.QuestID; } }
/// <summary> /// Notifies the client to load start sending all pre-cached and yet to be /// processed packets. /// /// See the above method /// </summary> /// <remarks> /// Due the nature of this method we'll be invoking a notification on /// our "assumed" to be pending LoadMap method. We'll process all Moveable /// objects in the sightrange here. /// /// We cannot do this when we're precaching because suppose the client takes /// 10 minutes to load, all the moveable monsters and characters can be gone /// already. And thus sending outdated information. /// </remarks> private void CM_CHARACTER_MAPLOADED() { try { #region Internal //Register on the new map this.character.currentzone.Regiontree.Subscribe(this.character); //GET NEW Z-POS float z = character.Position.z + 100; //Refresh Personal Requests CommonFunctions.RefreshPersonalRequests(this.character); Regiontree.UpdateRegion(this.character); isloaded = false; #endregion Internal #region Actor infromation { /* * Send actor information * * This packet makes a actor appear on the screen. Just like character information * It defines automaticly which actor is your actor. */ SMSG_ACTORINFO spkt = new SMSG_ACTORINFO(); spkt.ActorID = this.character.id; spkt.X = this.character.Position.x; spkt.Y = this.character.Position.y; spkt.Z = this.character.Position.z; spkt.race = this.character.race; spkt.face = this.character.FaceDetails; spkt.ActiveWeaponIndex = (byte)this.character.weapons.ActiveWeaponIndex; spkt.InventoryContainerSize = (byte)this.character.container.Capacity; spkt.StorageContainerSize = (byte)this.character.STORAGE.Capacity; spkt.UnlockedWeaponCount = this.character.weapons.UnlockedWeaponSlots; spkt.Unknown = 0; spkt.PrimaryWeaponByIndex = this.character.weapons.PrimaryWeaponIndex; spkt.SeccondairyWeaponByIndex = this.character.weapons.SeconairyWeaponIndex; spkt.Name = this.character.Name; spkt.SessionId = this.character.id; this.Send((byte[])spkt); } #endregion Actor infromation #region Battle Stats { CommonFunctions.SendBattleStatus(this.character); } #endregion Battle Stats #region Extend Stats { /* * Sends over the status points attributes * */ SMSG_EXTSTATS spkt2 = new SMSG_EXTSTATS(); spkt2.base_stats_1 = character.stats.BASE; spkt2.base_stats_2 = character.stats.CHARACTER; spkt2.base_stats_jobs = character.stats.EQUIPMENT; spkt2.base_stats_bonus = character.stats.ENCHANTMENT; spkt2.statpoints = character.stats.REMAINING; spkt2.SessionId = character.id; this.Send((byte[])spkt2); } #endregion Extend Stats if (IsFirstTimeLoad) { #if THREADING WaitCallback FireTimeLoginCallback = delegate(object a) { #else { #endif #region Equipment List { /* * Sends a list of all Equiped Equipment */ SMSG_EQUIPMENTLIST spkt = new SMSG_EQUIPMENTLIST(); for (int i = 0; i < 16; i++) { Rag2Item item = this.character.Equipment[i]; if (item != null) spkt.AddItem(item, item.active, i); } spkt.SessionId = this.character.id; this.Send((byte[])spkt); } #endregion Equipment List #region Weaponary List { /* * Sends a list of all weapons */ SMSG_WEAPONLIST spkt = new SMSG_WEAPONLIST(); spkt.SessionId = this.character.id; for (int i = 0; i < 5; i++) { Weapon current = this.character.weapons[i]; spkt.AddWeapon(current); } this.Send((byte[])spkt); } #endregion Weaponary List #region Unlock Weaponary { /* * This packet unlocks the selected slots */ SMSG_ADDITIONLIST spkt = new SMSG_ADDITIONLIST(); spkt.SessionId = this.character.id; this.Send((byte[])spkt); } #endregion Unlock Weaponary #region Character Status { /* * Send Character status * * This updates the characters status, this defines which job you're using * the experience you have. The experience is expressed in absolute values * so it doesn't represent a relative value for exp required. * * It also contains the definitions of how many LC, LP, HP, SP you have. * Note: LC represents the amount of breath capacity. */ SMSG_CHARSTATUS spkt = new SMSG_CHARSTATUS(); spkt.Job = this.character.job; spkt.Exp = this.character.Cexp; spkt.JobExp = this.character.Jexp; spkt.LC = this.character._status.CurrentOxygen; spkt.MaxLC = this.character._status.MaximumOxygen; spkt.HP = this.character.HP; spkt.MaxHP = this.character.HPMAX; spkt.SP = this.character.SP; spkt.MaxSP = this.character.SPMAX; spkt.LP = this.character._status.CurrentLp; spkt.MaxLP = 7; spkt.FieldOfSight = 0; spkt.SessionId = this.character.id; this.Send((byte[])spkt); } #endregion Character Status #region Battle Skills { /* * Region Send all battle skills * * Also known as all active skills, heals, buffs included */ List<Skill> list = this.character.learnedskills; SMSG_BATTLESKILL battleskills = new SMSG_BATTLESKILL(list.Count); foreach (Skill skill in list) battleskills.AddSkill(skill.Id, skill.Experience); battleskills.SessionId = this.character.id; this.Send((byte[])battleskills); } #endregion Battle Skills #region Special Skills { /* * Sends over an list of special skills * */ SMSG_LISTSPECIALSKILLS spkt = new SMSG_LISTSPECIALSKILLS(); for (int i = 0; i < 16; i++) { Skill skill = character.SpecialSkills[i]; if (skill != null) { spkt.AddSkill(skill.info.skillid, skill.Experience, (byte)i); } } spkt.SessionId = this.character.id; this.Send((byte[])spkt); } #endregion Special Skills #region Update Zeny { /* * Send Money * * This sets the money of a player to a absolute value. For instance if you * say 500, it would mean the player gets 500 rufi. There are no relative * values for TakeMoney or GiveMoney. */ SMSG_SENDZENY spkt = new SMSG_SENDZENY(); spkt.Zeny = this.character.ZENY; spkt.SessionId = this.character.id; this.Send((byte[])spkt); } #endregion Update Zeny #region Send Quest List { SMSG_QUESTINFO spkt3 = new SMSG_QUESTINFO(); spkt3.SessionId = this.character.id; foreach (QuestBase Quest in this.character.QuestObjectives) { List<Saga.Quests.Objectives.ObjectiveList.StepInfo> Steps = QuestBase.GetSteps(this.character, Quest.QuestId); spkt3.AddQuest(Quest.QuestId, (byte)Steps.Count); for (int i = 0; i < Steps.Count; i++) { Saga.Quests.Objectives.ObjectiveList.StepInfo currentStep = Steps[i]; uint nextstep = (i + 1 < Steps.Count) ? Steps[i + 1].StepId : 0; spkt3.AddQuestStep(currentStep.StepId, currentStep.State, nextstep, Quest.isnew); } } this.Send((byte[])spkt3); foreach (QuestBase Quest in this.character.QuestObjectives) { List<Saga.Quests.Objectives.ObjectiveList.StepInfo> Steps = QuestBase.GetSteps(this.character, Quest.QuestId); for (int i = 0; i < Steps.Count; i++) { Saga.Quests.Objectives.ObjectiveList.StepInfo currentStep = Steps[i]; if (currentStep.State == 1) { Predicate<Saga.Quests.Objectives.ObjectiveList.SubStep> Findsubstep = delegate(Saga.Quests.Objectives.ObjectiveList.SubStep objective) { return objective.Quest == Quest.QuestId && objective.StepId == currentStep.StepId; }; List<Quests.Objectives.ObjectiveList.SubStep> Substeps = this.character.QuestObjectives.Substeps.FindAll(Findsubstep); foreach (Saga.Quests.Objectives.ObjectiveList.SubStep substep in Substeps) { if (substep.current > 0) { SMSG_QUESTSUBSTEPUPDATE spkt = new SMSG_QUESTSUBSTEPUPDATE(); spkt.Unknown = 1; spkt.SubStep = (byte)substep.SubStepId; spkt.StepID = substep.StepId; spkt.QuestID = substep.Quest; spkt.Amount = (byte)substep.current; spkt.SessionId = this.character.id; this.Send((byte[])spkt); } } break; } } } } #endregion Send Quest List #region Send Way Points { foreach (QuestBase Quest in this.character.QuestObjectives) { SMSG_SENDNAVIGATIONPOINT spkt2 = new SMSG_SENDNAVIGATIONPOINT(); spkt2.SessionId = this.character.id; spkt2.QuestID = Quest.QuestId; foreach (Saga.Quests.Objectives.ObjectiveList.Waypoint waypoint in QuestBase.UserGetWaypoints(this.character, Quest.QuestId)) { Predicate<MapObject> IsNpc = delegate(MapObject match) { return match.ModelId == waypoint.NpcId; }; MapObject myObject = this.character.currentzone.Regiontree.SearchActor(IsNpc, SearchFlags.Npcs); if (myObject != null) { spkt2.AddPosition(waypoint.NpcId, myObject.Position.x, myObject.Position.y, myObject.Position.z); } } this.Send((byte[])spkt2); } } #endregion Send Way Points #region Addition List { SMSG_ADDITIONLIST spkt = new SMSG_ADDITIONLIST(); spkt.SessionId = this.character.id; foreach (AdditionState state in character._additions) { if (state.CanExpire) { spkt.Add(state.Addition, state.Lifetime); } else { spkt.Add(state.Addition, 0); } } this.Send((byte[])spkt); } #endregion Addition List #region Scenario { QuestBase scenarioQuest = this.character.QuestObjectives.Quests[3]; if (scenarioQuest != null) { SMSG_INITIALIZESCENARIO spkt = new SMSG_INITIALIZESCENARIO(); spkt.Scenario1 = scenarioQuest.QuestId; List<Saga.Quests.Objectives.ObjectiveList.StepInfo> list; if (this.character.QuestObjectives.ScenarioSteps.TryGetValue(scenarioQuest.QuestId, out list)) if (list.Count > 0) { spkt.Scenario2 = list[0].StepId; spkt.StepStatus = 1; spkt.Enabled = 0; } spkt.SessionId = this.character.id; this.Send((byte[])spkt); } else { QuestBase qbase; if (Singleton.Quests.TryFindScenarioQuest(1, out qbase)) { qbase.OnStart(character.id); } } } #endregion Scenario #region Mail { int count = Singleton.Database.GetInboxUncheckedCount(this.character.Name); SMSG_MAILARRIVED spkt = new SMSG_MAILARRIVED(); spkt.Amount = (uint)count; spkt.SessionId = this.character.id; this.Send((byte[])spkt); } #endregion Mail #region Inventory List { SMSG_INVENTORYLIST spkt5 = new SMSG_INVENTORYLIST((byte)this.character.container.Count); spkt5.SessionId = this.character.id; foreach (Rag2Item c in this.character.container) spkt5.AddItem(c); this.Send((byte[])spkt5); } #endregion Inventory List #region Friendlist { WaitCallback FriendlistLogin = delegate(object state) { //Look through all friends lists of logged on players and if they are friends then // notify them that the user logged on. SMSG_FRIENDSLIST_NOTIFYLOGIN spkt = new SMSG_FRIENDSLIST_NOTIFYLOGIN(); spkt.name = this.character.Name; foreach (Character characterTarget in LifeCycle.Characters) { lock (characterTarget) { if (characterTarget.id != this.character.id) if (character._friendlist.Contains(this.character.Name)) { spkt.SessionId = characterTarget.id; characterTarget.client.Send((byte[])spkt); } } } }; ThreadPool.QueueUserWorkItem(FriendlistLogin); } #endregion Friendlist #if THREADING }; ThreadPool.QueueUserWorkItem(FireTimeLoginCallback); #else } #endif } else { //Always ubsubcribe from the respawn manager in case //we forget to do it. Tasks.Respawns.Unsubscribe(this.character); } #region Dynamic Objects { try { Regiontree tree = this.character.currentzone.Regiontree; #if THREADING WaitCallback FindCharactersActors = delegate(object a) { #else { #endif foreach (Character regionObject in tree.SearchActors(this.character, SearchFlags.Characters)) { try { if (Point.IsInSightRangeByRadius(this.character.Position, regionObject.Position)) { regionObject.ShowObject(this.character); if (this.character.id != regionObject.id) { this.character.ShowObject(regionObject); } regionObject.Appears(this.character); } } catch (SocketException) { Trace.WriteLine("Network eror"); } catch (Exception e) { Trace.WriteLine(e.Message); } } #if THREADING }; #else } #endif #if THREADING WaitCallback FindNpcActors = delegate(object a) { #else { #endif foreach (MapObject regionObject in tree.SearchActors(this.character, SearchFlags.MapItems | SearchFlags.Npcs)) { try { if (Point.IsInSightRangeByRadius(this.character.Position, regionObject.Position)) { regionObject.ShowObject(this.character); regionObject.Appears(this.character); } } catch (SocketException) { Trace.WriteLine("Network eror"); } catch (Exception e) { Trace.WriteLine(e.Message); } } #if THREADING }; #else } #endif #if THREADING ThreadPool.QueueUserWorkItem(FindCharactersActors); ThreadPool.QueueUserWorkItem(FindNpcActors); #endif } catch (Exception e) { Trace.WriteLine(e.Message); } } #endregion Dynamic Objects #region Time Weather CommonFunctions.UpdateTimeWeather(this.character); #endregion Time Weather #region Map Info { SMSG_SHOWMAPINFO spkt2 = new SMSG_SHOWMAPINFO(); spkt2.SessionId = this.character.id; spkt2.ZoneInfo = this.character.ZoneInformation; this.Send((byte[])spkt2); } #endregion Map Info #region Return Points { /* * Send Resturn points * Return points define which map you'll be send to when you * use your promise stone or die */ WorldCoordinate lpos = this.character.lastlocation.map > 0 ? this.character.lastlocation : this.character.savelocation; WorldCoordinate spos = this.character.savelocation; if (spos.map == this.character.currentzone.Map) { this.character.stance = (byte)StancePosition.Stand; SMSG_RETURNMAPLIST spkt = new SMSG_RETURNMAPLIST(); spkt.ToMap = lpos.map; spkt.FromMap = this.character.currentzone.CathelayaLocation.map; spkt.IsSaveLocationSet = (lpos.map > 0) ? (byte)1 : (byte)0; spkt.SessionId = this.character.id; this.Send((byte[])spkt); } else { this.character.stance = (byte)StancePosition.Stand; SMSG_RETURNMAPLIST spkt = new SMSG_RETURNMAPLIST(); spkt.ToMap = spos.map; spkt.FromMap = this.character.currentzone.CathelayaLocation.map; spkt.IsSaveLocationSet = (spos.map > 0) ? (byte)1 : (byte)0; spkt.SessionId = this.character.id; this.Send((byte[])spkt); } } #endregion Return Points #region Job Levels { SMSG_JOBLEVELS spkt2 = new SMSG_JOBLEVELS(); spkt2.SessionId = this.character.id; spkt2.jobslevels = this.character.CharacterJobLevel; this.Send((byte[])spkt2); } #endregion Job Levels #region Change Actors state { /* * Change the actors state * * This is used to change the actors state to a non-active-battle position. * Note we will not warp the player back on their x and y coords if they were dead. * This would result in double loading a map. This should be handeld before processing * the character. */ this.character.stance = (byte)StancePosition.Reborn; this.character.ISONBATTLE = false; SMSG_ACTORCHANGESTATE spkt = new SMSG_ACTORCHANGESTATE(); spkt.ActorID = this.character.id; spkt.SessionId = this.character.id; spkt.Stance = this.character.stance; spkt.State = (this.character.ISONBATTLE) ? (byte)1 : (byte)0; this.Send((byte[])spkt); } #endregion Change Actors state #region Party Update if (this.character.sessionParty != null) { foreach (Character partyTarget in this.character.sessionParty._Characters) { //Only process if we're on the same map if (partyTarget.id != this.character.id) if (partyTarget.map == this.character.map) { //Retrieve positions people that are loaded SMSG_PARTYMEMBERLOCATION spkt2 = new SMSG_PARTYMEMBERLOCATION(); spkt2.Index = 1; spkt2.ActorId = partyTarget.id; spkt2.SessionId = this.character.id; spkt2.X = (partyTarget.Position.x / 1000); spkt2.Y = (partyTarget.Position.y / 1000); this.Send((byte[])spkt2); //Update the position of myself to loaded characters SMSG_PARTYMEMBERLOCATION spkt3 = new SMSG_PARTYMEMBERLOCATION(); spkt3.Index = 1; spkt3.ActorId = this.character.id; spkt3.SessionId = partyTarget.id; spkt3.X = (this.character.Position.x / 1000); spkt3.Y = (this.character.Position.y / 1000); partyTarget.client.Send((byte[])spkt3); } } } #endregion Party Update #region Static Objects try { //SEND OVER ALL CHARACTERS THAT ARE ALWAYS VISIBLE foreach (MapObject regionObject in this.character.currentzone.Regiontree.SearchActors(SearchFlags.StaticObjects)) { Console.WriteLine("Show object: {0}", regionObject.ToString()); regionObject.ShowObject(this.character); regionObject.Appears(this.character); } } catch (Exception) { //Do nothing } #endregion Static Objects } catch (Exception e) { Console.WriteLine(e); this.Close(); } finally { this.character.ISONBATTLE = false; isloaded = true; IsFirstTimeLoad = false; this.character.LastPositionTick = Environment.TickCount; } }