From 1523ae200bc763400de2b186ee18defba834327c Mon Sep 17 00:00:00 2001 From: Filip Maj Date: Wed, 16 Feb 2022 15:32:54 -0500 Subject: [PATCH] Finished quest state system idea --- Common Class Lib/Bitstream.cs | 150 +++++++++++++++ Common Class Lib/Common Class Lib.csproj | 1 + .../chara/npc/populace/PopulaceStandard.lua | 6 +- Data/scripts/quests/etc/etc3g0.lua | 34 ++-- Data/scripts/quests/etc/etc5g0.lua | 10 +- Data/scripts/quests/man/man0l0.lua | 54 +++--- Data/scripts/quests/man/man0l1.lua | 64 +++---- Data/scripts/quests/man/man0u0.lua | 50 ++--- Data/scripts/quests/man/man0u1.lua | 10 +- Data/scripts/quests/man/man2l0.lua | 2 +- Data/scripts/quests/trl/Trl0g1.lua | 29 --- Data/scripts/quests/trl/Trl0l1.lua | 29 --- Data/scripts/quests/trl/Trl0u1.lua | 29 --- Map Server/Actors/Quest/Quest.cs | 181 +++++++----------- Map Server/Actors/Quest/QuestState.cs | 112 +++++++++++ Map Server/Actors/Quest/QuestStateManager.cs | 108 +++++++++++ Map Server/Database.cs | 52 ++++- Map Server/Map Server.csproj | 3 + Map Server/PacketProcessor.cs | 2 +- Map Server/Server.cs | 165 ++++++++++------ Map Server/WorldManager.cs | 2 +- 21 files changed, 720 insertions(+), 373 deletions(-) create mode 100644 Common Class Lib/Bitstream.cs delete mode 100644 Data/scripts/quests/trl/Trl0g1.lua delete mode 100644 Data/scripts/quests/trl/Trl0l1.lua delete mode 100644 Data/scripts/quests/trl/Trl0u1.lua create mode 100644 Map Server/Actors/Quest/QuestState.cs create mode 100644 Map Server/Actors/Quest/QuestStateManager.cs diff --git a/Common Class Lib/Bitstream.cs b/Common Class Lib/Bitstream.cs new file mode 100644 index 00000000..a543a75c --- /dev/null +++ b/Common Class Lib/Bitstream.cs @@ -0,0 +1,150 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Meteor.Common +{ + public class Bitstream + { + private readonly byte[] Data; + + public Bitstream(uint numBits, bool setAllTrue = false) + { + Debug.Assert(numBits % 8 == 0); + Debug.Assert(numBits % 4 == 0); + Data = new byte[numBits / 8]; + + if (setAllTrue) + SetAll(true); + } + + public Bitstream(bool[] boolArray) + { + Data = Utils.ConvertBoolArrayToBinaryStream(boolArray); + } + + private Bitstream(byte[] byteArray) + { + Data = byteArray; + } + + public void SetAll(bool to) + { + for (int i = 0; i < Data.Length; i += 4) + { + Data[i] = Data[i + 1] = Data[i + 2] = Data[i + 3] = (byte)(to ? 0xFF : 0x00); + } + } + + public void SetTo(Bitstream result) + { + Debug.Assert(Data.Length == result.Data.Length); + for (int i = 0; i < result.Data.Length; i += 4) + { + Data[i] = result.Data[i]; + Data[i + 1] = result.Data[i + 1]; + Data[i + 2] = result.Data[i + 2]; + Data[i + 3] = result.Data[i + 3]; + } + } + + public bool Get(uint at) + { + return Get((int)at); + } + + public bool Get(int at) + { + int bytePos = at / 8; + int bitPos = at % 8; + return (Data[bytePos] & (1 << bitPos)) != 0; + } + + public void Set(uint at) + { + Set((int)at); + } + + public void Set(int at) + { + int bytePos = at / 8; + int bitPos = at % 8; + Data[bytePos] |= (byte)(1 << bitPos); + } + + public void Clear(uint at) + { + Clear((int)at); + } + + public void Clear(int at) + { + int bytePos = at / 8; + int bitPos = at % 8; + Data[bytePos] &= (byte)~(1 << bitPos); + } + + public void NOT() + { + for (int i = 0; i < Data.Length; i += 4) + { + Data[i] = (byte)~Data[i]; + Data[i + 1] = (byte)~Data[i + 1]; + Data[i + 2] = (byte)~Data[i + 2]; + Data[i + 3] = (byte)~Data[i + 3]; + } + } + + public void OR(Bitstream other) + { + Debug.Assert(Data.Length == other.Data.Length); + for (int i = 0; i < Data.Length; i += 4) + { + Data[i] |= other.Data[i]; + Data[i + 1] |= other.Data[i + 1]; + Data[i + 2] |= other.Data[i + 2]; + Data[i + 3] |= other.Data[i + 3]; + } + } + + public void AND(Bitstream other) + { + Debug.Assert(Data.Length == other.Data.Length); + for (int i = 0; i < Data.Length; i += 4) + { + Data[i] &= other.Data[i]; + Data[i + 1] &= other.Data[i + 1]; + Data[i + 2] &= other.Data[i + 2]; + Data[i + 3] &= other.Data[i + 3]; + } + } + + public void XOR(Bitstream other) + { + Debug.Assert(Data.Length == other.Data.Length); + for (int i = 0; i < Data.Length; i += 4) + { + Data[i] ^= other.Data[i]; + Data[i + 1] ^= other.Data[i + 1]; + Data[i + 2] ^= other.Data[i + 2]; + Data[i + 3] ^= other.Data[i + 3]; + } + } + + public Bitstream Copy() + { + byte[] copy = new byte[Data.Length]; + Array.Copy(Data, copy, Data.Length); + return new Bitstream(copy); + } + + public byte[] GetBytes() + { + return Data; + } + + } +} diff --git a/Common Class Lib/Common Class Lib.csproj b/Common Class Lib/Common Class Lib.csproj index 1462cb50..5c60a839 100644 --- a/Common Class Lib/Common Class Lib.csproj +++ b/Common Class Lib/Common Class Lib.csproj @@ -87,6 +87,7 @@ + diff --git a/Data/scripts/base/chara/npc/populace/PopulaceStandard.lua b/Data/scripts/base/chara/npc/populace/PopulaceStandard.lua index f69ad19b..77635106 100644 --- a/Data/scripts/base/chara/npc/populace/PopulaceStandard.lua +++ b/Data/scripts/base/chara/npc/populace/PopulaceStandard.lua @@ -23,7 +23,8 @@ end function onEventStarted(player, npc, eventType, eventName) local defaultTalk = player:GetDefaultTalkQuest(npc); - local tutorialTalk = player:GetTutorialQuest(npc); + local tutorialTalk = player:GetTutorialQuest(npc); + local journalQuests = player:GetJournalQuestsForNpc(npc); local activeQuests = player:GetQuestsForNpc(npc); local possibleQuests = {}; @@ -34,6 +35,9 @@ function onEventStarted(player, npc, eventType, eventName) if (tutorialTalk ~= nil and eventType == ETYPE_TALK) then table.insert(possibleQuests, tutorialTalk); end + if (journalQuests ~= nil) then + table.insert(possibleQuests, unpack(journalQuests)); + end if (activeQuests ~= nil) then table.insert(possibleQuests, unpack(activeQuests)); end diff --git a/Data/scripts/quests/etc/etc3g0.lua b/Data/scripts/quests/etc/etc3g0.lua index a8f95077..d5f326b5 100644 --- a/Data/scripts/quests/etc/etc3g0.lua +++ b/Data/scripts/quests/etc/etc3g0.lua @@ -41,8 +41,6 @@ FLAG_TALKED_LEFWYNE = 4; -- Quest Counters COUNTER_TALKED = 0; ---offerQuestResult = callClientFunction(player, "delegateEvent", player, quest, "processEventOffersStart"); - function onStart(player, quest) quest:StartSequence(SEQ_000); end @@ -50,25 +48,39 @@ end function onFinish(player, quest) end -function onSequence(player, quest, sequence) +function onStateChange(player, quest, sequence) + if (sequence == 65536) then + quest:SetENpc(KINNISON, QFLAG_PLATE); + end + if (sequence == SEQ_000) then - quest:AddENpc(KINNISON); - quest:AddENpc(SYBELL, (not quest:GetFlag(FLAG_TALKED_SYBELL) and QFLAG_PLATE or QFLAG_NONE)); - quest:AddENpc(KHUMA_MOSHROCA, (not quest:GetFlag(FLAG_TALKED_KHUMA_MOSHROCA) and QFLAG_PLATE or QFLAG_NONE)); - quest:AddENpc(NELLAURE, (not quest:GetFlag(FLAG_TALKED_NELLAURE) and QFLAG_PLATE or QFLAG_NONE)); - quest:AddENpc(MESTONNAUX, (not quest:GetFlag(FLAG_TALKED_MESTONNAUX) and QFLAG_PLATE or QFLAG_NONE)); - quest:AddENpc(LEFWYNE, (not quest:GetFlag(FLAG_TALKED_LEFWYNE) and QFLAG_PLATE or QFLAG_NONE)); + quest:SetENpc(KINNISON); + quest:SetENpc(SYBELL, (not quest:GetFlag(FLAG_TALKED_SYBELL) and QFLAG_PLATE or QFLAG_NONE)); + quest:SetENpc(KHUMA_MOSHROCA, (not quest:GetFlag(FLAG_TALKED_KHUMA_MOSHROCA) and QFLAG_PLATE or QFLAG_NONE)); + quest:SetENpc(NELLAURE, (not quest:GetFlag(FLAG_TALKED_NELLAURE) and QFLAG_PLATE or QFLAG_NONE)); + quest:SetENpc(MESTONNAUX, (not quest:GetFlag(FLAG_TALKED_MESTONNAUX) and QFLAG_PLATE or QFLAG_NONE)); + quest:SetENpc(LEFWYNE, (not quest:GetFlag(FLAG_TALKED_LEFWYNE) and QFLAG_PLATE or QFLAG_NONE)); elseif (sequence == SEQ_001) then - quest:AddENpc(KINNISON, QFLAG_PLATE); + quest:SetENpc(KINNISON, QFLAG_PLATE); end end - function onTalk(player, quest, npc, eventName) local npcClassId = npc.GetActorClassId(); local seq = quest:GetSequence(); local incCounter = false; + -- Offer the quest + if (npcClassId == KINNISON and not player:HasQuest(quest)) then + local questAccepted = callClientFunction(player, "delegateEvent", player, quest, "processEventOffersStart"); + if (questAccepted) then + player:AddQuest(quest); + end + player:EndEvent(); + return; + end + + -- Quest Progress if (seq == SEQ_000) then if (npcClassId == KINNISON) then callClientFunction(player, "delegateEvent", player, quest, "processEventOffersAfter"); diff --git a/Data/scripts/quests/etc/etc5g0.lua b/Data/scripts/quests/etc/etc5g0.lua index 4c82338f..08893374 100644 --- a/Data/scripts/quests/etc/etc5g0.lua +++ b/Data/scripts/quests/etc/etc5g0.lua @@ -40,13 +40,13 @@ end -function onSequence(player, quest, sequence) +function onStateChange(player, quest, sequence) if (sequence == SEQ_000) then - quest:AddENpc(VKOROLON); - quest:AddENpc(PFARAHR, QFLAG_PLATE); + quest:SetENpc(VKOROLON); + quest:SetENpc(PFARAHR, QFLAG_PLATE); elseif (sequence == SEQ_001) then - quest:AddENpc(VKOROLON, QFLAG_PLATE); - quest:AddENpc(PFARAHR); + quest:SetENpc(VKOROLON, QFLAG_PLATE); + quest:SetENpc(PFARAHR); end end diff --git a/Data/scripts/quests/man/man0l0.lua b/Data/scripts/quests/man/man0l0.lua index 8e6e7d0a..47217e3b 100644 --- a/Data/scripts/quests/man/man0l0.lua +++ b/Data/scripts/quests/man/man0l0.lua @@ -62,7 +62,7 @@ end function onFinish(player, quest) end -function onSequence(player, quest, sequence) +function onStateChange(player, quest, sequence) if (sequence == SEQ_000) then -- Setup states incase we loaded in. local rostnsthalFlag = quest:GetFlag(FLAG_SEQ000_MINITUT1) and QFLAG_NONE or QFLAG_PLATE; @@ -72,34 +72,34 @@ function onSequence(player, quest, sequence) local exitCanPush = quest:GetFlags() == 0xF; local exitFlag = quest:GetFlags() == 0xF and QFLAG_MAP or QFLAG_NONE; - quest:AddENpc(WELLTRAVELED_MERCHANT); - quest:AddENpc(TIPSY_ADVENTURER); - quest:AddENpc(CULTIVATED_TENDER); - quest:AddENpc(ANXIOUS_ADVENTURER); - quest:AddENpc(BABYFACED_ADVENTURER, babyfaceFlag); - quest:AddENpc(AUSTERE_ADVENTURER); - quest:AddENpc(UNDIGNIFIED_ADVENTURER); - quest:AddENpc(SHADOWY_TRAVELER); - quest:AddENpc(ASTUTE_MERCHANT); - quest:AddENpc(VOLUPTUOUS_VIXEN, vixenFlag); - quest:AddENpc(INDIFFERENT_PASSERBY); - quest:AddENpc(PRATTLING_ADVENTURER); - quest:AddENpc(LANKY_TRAVELER); - quest:AddENpc(GRINNING_ADVENTURER); - quest:AddENpc(ROSTNSTHAL, rostnsthalFlag, true, rostnsthalCanPush); - quest:AddENpc(EXIT_TRIGGER, exitFlag, false, exitCanPush); + quest:SetENpc(WELLTRAVELED_MERCHANT); + quest:SetENpc(TIPSY_ADVENTURER); + quest:SetENpc(CULTIVATED_TENDER); + quest:SetENpc(ANXIOUS_ADVENTURER); + quest:SetENpc(BABYFACED_ADVENTURER, babyfaceFlag); + quest:SetENpc(AUSTERE_ADVENTURER); + quest:SetENpc(UNDIGNIFIED_ADVENTURER); + quest:SetENpc(SHADOWY_TRAVELER); + quest:SetENpc(ASTUTE_MERCHANT); + quest:SetENpc(VOLUPTUOUS_VIXEN, vixenFlag); + quest:SetENpc(INDIFFERENT_PASSERBY); + quest:SetENpc(PRATTLING_ADVENTURER); + quest:SetENpc(LANKY_TRAVELER); + quest:SetENpc(GRINNING_ADVENTURER); + quest:SetENpc(ROSTNSTHAL, rostnsthalFlag, true, rostnsthalCanPush); + quest:SetENpc(EXIT_TRIGGER, exitFlag, false, exitCanPush); elseif (sequence == SEQ_005) then elseif (sequence == SEQ_010) then - quest:AddENpc(HOB); - quest:AddENpc(GERT); - quest:AddENpc(LORHZANT); - quest:AddENpc(MUSCLEBOUND_DECKHAND); - quest:AddENpc(PEARLYTOOTHED_PORTER); - quest:AddENpc(UNDIGNIFIED_ADVENTURER); - quest:AddENpc(WELLTRAVELED_MERCHANT); - quest:AddENpc(VOLUPTUOUS_VIXEN); - quest:AddENpc(LANKY_TRAVELER); - quest:AddENpc(PRIVAREA_PAST_EXIT, QFLAG_NONE, false, true); + quest:SetENpc(HOB); + quest:SetENpc(GERT); + quest:SetENpc(LORHZANT); + quest:SetENpc(MUSCLEBOUND_DECKHAND); + quest:SetENpc(PEARLYTOOTHED_PORTER); + quest:SetENpc(UNDIGNIFIED_ADVENTURER); + quest:SetENpc(WELLTRAVELED_MERCHANT); + quest:SetENpc(VOLUPTUOUS_VIXEN); + quest:SetENpc(LANKY_TRAVELER); + quest:SetENpc(PRIVAREA_PAST_EXIT, QFLAG_NONE, false, true); end end diff --git a/Data/scripts/quests/man/man0l1.lua b/Data/scripts/quests/man/man0l1.lua index 9ced680f..e0a38b1d 100644 --- a/Data/scripts/quests/man/man0l1.lua +++ b/Data/scripts/quests/man/man0l1.lua @@ -85,56 +85,56 @@ end function onFinish(player, quest) end -function onSequence(player, quest, sequence) +function onStateChange(player, quest, sequence) if (sequence == SEQ_000) then - quest:AddENpc(YSHTOLA); - quest:AddENpc(CRAPULOUS_ADVENTURER); - quest:AddENpc(DUPLICITOUS_TRADER); - quest:AddENpc(DEBONAIR_PIRATE); - quest:AddENpc(ONYXHAIRED_ADVENTURER); - quest:AddENpc(SKITTISH_ADVENTURER); - quest:AddENpc(RELAXING_ADVENTURER); - quest:AddENpc(BADERON, QFLAG_PLATE); - quest:AddENpc(MYTESYN); - quest:AddENpc(COCKAHOOP_COCKSWAIN); - quest:AddENpc(SENTENIOUS_SELLSWORD); - quest:AddENpc(SOLICITOUS_SELLSWORD); + quest:SetENpc(YSHTOLA); + quest:SetENpc(CRAPULOUS_ADVENTURER); + quest:SetENpc(DUPLICITOUS_TRADER); + quest:SetENpc(DEBONAIR_PIRATE); + quest:SetENpc(ONYXHAIRED_ADVENTURER); + quest:SetENpc(SKITTISH_ADVENTURER); + quest:SetENpc(RELAXING_ADVENTURER); + quest:SetENpc(BADERON, QFLAG_PLATE); + quest:SetENpc(MYTESYN); + quest:SetENpc(COCKAHOOP_COCKSWAIN); + quest:SetENpc(SENTENIOUS_SELLSWORD); + quest:SetENpc(SOLICITOUS_SELLSWORD); elseif (sequence == SEQ_003) then - quest:AddENpc(BADERON); + quest:SetENpc(BADERON); elseif (sequence == SEQ_005) then - quest:AddENpc(BADERON, QFLAG_PLATE); + quest:SetENpc(BADERON, QFLAG_PLATE); elseif (sequence == SEQ_006) then - quest:AddENpc(BADERON, QFLAG_PLATE); + quest:SetENpc(BADERON, QFLAG_PLATE); elseif (sequence == SEQ_007) then local subseqCUL = quest:GetCounter(CNTR_SEQ7_CUL); local subseqMRD = quest:GetCounter(CNTR_SEQ7_MRD); -- Always active in this seqence - quest:AddENpc(BADERON); - quest:AddENpc(CHARLYS, subseqCUL == 0 and QFLAG_PLATE or QFLAG_NONE); + quest:SetENpc(BADERON); + quest:SetENpc(CHARLYS, subseqCUL == 0 and QFLAG_PLATE or QFLAG_NONE); -- Down and Up the MSK guild - quest:AddENpc(ISANDOREL, (subseqMRD == 0 or subseqMRD == 2) and QFLAG_PLATE or QFLAG_NONE); + quest:SetENpc(ISANDOREL, (subseqMRD == 0 or subseqMRD == 2) and QFLAG_PLATE or QFLAG_NONE); if (subseqMRD == 1) then - quest:AddENpc(MSK_TRIGGER, QFLAG_MAP, false, true); + quest:SetENpc(MSK_TRIGGER, QFLAG_MAP, false, true); elseif (subseqMRD == 2) then - quest:AddENpc(MERLZIRN); + quest:SetENpc(MERLZIRN); end -- In Echo - quest:AddENpc(NERVOUS_BARRACUDA); - quest:AddENpc(INTIMIDATING_BARRACUDA); - quest:AddENpc(OVEREAGER_BARRACUDA); - quest:AddENpc(SOPHISTICATED_BARRACUDA); - quest:AddENpc(SMIRKING_BARRACUDA); - quest:AddENpc(MANNSKOEN); - quest:AddENpc(TOTORUTO); - quest:AddENpc(ADVENTURER1); - quest:AddENpc(ADVENTURER2); - quest:AddENpc(ADVENTURER3); - quest:AddENpc(ECHO_EXIT_TRIGGER, subseqMRD == 3 and QFLAG_MAP or QFLAG_NONE, false, subseqMRD == 3); + quest:SetENpc(NERVOUS_BARRACUDA); + quest:SetENpc(INTIMIDATING_BARRACUDA); + quest:SetENpc(OVEREAGER_BARRACUDA); + quest:SetENpc(SOPHISTICATED_BARRACUDA); + quest:SetENpc(SMIRKING_BARRACUDA); + quest:SetENpc(MANNSKOEN); + quest:SetENpc(TOTORUTO); + quest:SetENpc(ADVENTURER1); + quest:SetENpc(ADVENTURER2); + quest:SetENpc(ADVENTURER3); + quest:SetENpc(ECHO_EXIT_TRIGGER, subseqMRD == 3 and QFLAG_MAP or QFLAG_NONE, false, subseqMRD == 3); if (subseqCUL == 1 and subseqMRD == 4) then player:SetNpcLS(1, 1); diff --git a/Data/scripts/quests/man/man0u0.lua b/Data/scripts/quests/man/man0u0.lua index a8f8e70c..4eab0227 100644 --- a/Data/scripts/quests/man/man0u0.lua +++ b/Data/scripts/quests/man/man0u0.lua @@ -103,7 +103,7 @@ end function onFinish(player, quest) end -function onSequence(player, quest, sequence) +function onStateChange(player, quest, sequence) if (sequence == SEQ_000) then -- Setup states incase we loaded in. @@ -119,34 +119,34 @@ function onSequence(player, quest, sequence) gildiggingmistressFlag = QFLAG_NONE; end - --AddENpc(classId, byte flagType=0,isTalkEnabled, isPushEnabled, isEmoteEnabled, isSpawned) - quest:AddENpc(ASCILIA, asciliaFlag, true, asciliaCanPush); - quest:AddENpc(WARBURTON); - quest:AddENpc(RURURAJI); - quest:AddENpc(BIG_BELLIED_BARKER); - quest:AddENpc(FRETFUL_FARMHAND, fretfulfarmhandFlag); - quest:AddENpc(DEBAUCHED_DEMONESS); - quest:AddENpc(DAPPER_DAN); - quest:AddENpc(LOUTISH_LAD); - quest:AddENpc(GIL_DIGGING_MISTRESS, gildiggingmistressFlag); - quest:AddENpc(TWITTERING_TOMBOY); - quest:AddENpc(STOCKY_STRANGER); - quest:AddENpc(EXIT_TRIGGER, exitFlag, false, true); - quest:AddENpc(OPENING_STOPER_ULDAH, QFLAG_NONE, false, false, true); + --SetENpc(classId, byte flagType=0,isTalkEnabled, isPushEnabled, isEmoteEnabled, isSpawned) + quest:SetENpc(ASCILIA, asciliaFlag, true, asciliaCanPush); + quest:SetENpc(WARBURTON); + quest:SetENpc(RURURAJI); + quest:SetENpc(BIG_BELLIED_BARKER); + quest:SetENpc(FRETFUL_FARMHAND, fretfulfarmhandFlag); + quest:SetENpc(DEBAUCHED_DEMONESS); + quest:SetENpc(DAPPER_DAN); + quest:SetENpc(LOUTISH_LAD); + quest:SetENpc(GIL_DIGGING_MISTRESS, gildiggingmistressFlag); + quest:SetENpc(TWITTERING_TOMBOY); + quest:SetENpc(STOCKY_STRANGER); + quest:SetENpc(EXIT_TRIGGER, exitFlag, false, true); + quest:SetENpc(OPENING_STOPER_ULDAH, QFLAG_NONE, false, false, true); elseif (sequence == SEQ_010) then local yayatokiFlag = quest:GetFlag(FLAG_SEQ010_TALK0) and QFLAG_NONE or QFLAG_PLATE; local uldahopeningexitFlag = QFLAG_MAP; - quest:AddENpc(KEEN_EYED_MERCHANT); - quest:AddENpc(HIGH_SPIRITED_FELLOW); - quest:AddENpc(DISREPUTABLE_MIDLANDER); - quest:AddENpc(LONG_LEGGED_LADY); - quest:AddENpc(LARGE_LUNGED_LABORER); - quest:AddENpc(TOOTH_GRINDING_TRAVELER); - quest:AddENpc(FULL_LIPPED_FILLE); - quest:AddENpc(YAYATOKI, yayatokiFlag); - quest:AddENpc(BLOCKER, QFLAG_NONE, false, true); - quest:AddENpc(ULDAH_OPENING_EXIT, uldahopeningexitFlag, false, true); + quest:SetENpc(KEEN_EYED_MERCHANT); + quest:SetENpc(HIGH_SPIRITED_FELLOW); + quest:SetENpc(DISREPUTABLE_MIDLANDER); + quest:SetENpc(LONG_LEGGED_LADY); + quest:SetENpc(LARGE_LUNGED_LABORER); + quest:SetENpc(TOOTH_GRINDING_TRAVELER); + quest:SetENpc(FULL_LIPPED_FILLE); + quest:SetENpc(YAYATOKI, yayatokiFlag); + quest:SetENpc(BLOCKER, QFLAG_NONE, false, true); + quest:SetENpc(ULDAH_OPENING_EXIT, uldahopeningexitFlag, false, true); end end diff --git a/Data/scripts/quests/man/man0u1.lua b/Data/scripts/quests/man/man0u1.lua index 1de8bf9d..6fc8a6ad 100644 --- a/Data/scripts/quests/man/man0u1.lua +++ b/Data/scripts/quests/man/man0u1.lua @@ -127,17 +127,17 @@ end function onFinish(player, quest) end -function onSequence(player, quest, sequence) +function onStateChange(player, quest, sequence) if (sequence == SEQ_000) then -- Setup states incase we loaded in. - --AddENpc(classId, byte flagType=0,isTalkEnabled, isPushEnabled, isEmoteEnabled, isSpawned) - quest:AddENpc(MOMODI, QFLAG_PLATE); - quest:AddENpc(OTOPA_POTTOPA); + --SetENpc(classId, byte flagType=0,isTalkEnabled, isPushEnabled, isEmoteEnabled, isSpawned) + quest:SetENpc(MOMODI, QFLAG_PLATE); + quest:SetENpc(OTOPA_POTTOPA); elseif (sequence == SEQ_005) then - quest:AddENpc(MOMODI); + quest:SetENpc(MOMODI); end end diff --git a/Data/scripts/quests/man/man2l0.lua b/Data/scripts/quests/man/man2l0.lua index cffda573..b5788ee7 100644 --- a/Data/scripts/quests/man/man2l0.lua +++ b/Data/scripts/quests/man/man2l0.lua @@ -7,7 +7,7 @@ end function onFinish(player, quest) end -function onSequence(player, quest, seqNum) +function onStateChange(player, quest, seqNum) quest:ClearENpcs(); end diff --git a/Data/scripts/quests/trl/Trl0g1.lua b/Data/scripts/quests/trl/Trl0g1.lua deleted file mode 100644 index e07ec868..00000000 --- a/Data/scripts/quests/trl/Trl0g1.lua +++ /dev/null @@ -1,29 +0,0 @@ -require ("global") - ---[[ - -Quest Script - -Name: Getting Started (Mother Miounne) -Code: Trl0g1 -Id: 110141 - -Enables the "Getting Started" option on Miounne. -* NOTE: This quest is active for all players at all times. -]] - -function onTalk(player, quest, npc, eventName) - local choice = callClientFunction(player, "delegateEvent", player, quest, "processEventMiounneStart"); - - if (choice == 1) then - callClientFunction(player, "delegateEvent", player, quest, "processEvent225"); - elseif (choice == 2) then - callClientFunction(player, "delegateEvent", player, quest, "processEvent230"); - end - - player:EndEvent(); -end - -function IsQuestENPC(player, quest, npc) - return npc:GetActorClassId()] == 1000230; -end \ No newline at end of file diff --git a/Data/scripts/quests/trl/Trl0l1.lua b/Data/scripts/quests/trl/Trl0l1.lua deleted file mode 100644 index 6e8ac0f5..00000000 --- a/Data/scripts/quests/trl/Trl0l1.lua +++ /dev/null @@ -1,29 +0,0 @@ -require ("global") - ---[[ - -Quest Script - -Name: Getting Started (Baderon) -Code: Trl0l1 -Id: 110140 - -Enables the "Getting Started" option on Baderon. -* NOTE: This quest is active for all players at all times. -]] - -function onTalk(player, quest, npc, eventName) - local choice = callClientFunction(player, "delegateEvent", player, quest, "processEventBaderonStart"); - - if (choice == 1) then - callClientFunction(player, "delegateEvent", player, quest, "processEvent640"); - elseif (choice == 2) then - callClientFunction(player, "delegateEvent", player, quest, "processEvent650"); - end - - player:EndEvent(); -end - -function IsQuestENPC(player, quest, npc) - return npc:GetActorClassId()] == 1000137; -end \ No newline at end of file diff --git a/Data/scripts/quests/trl/Trl0u1.lua b/Data/scripts/quests/trl/Trl0u1.lua deleted file mode 100644 index bf5734d0..00000000 --- a/Data/scripts/quests/trl/Trl0u1.lua +++ /dev/null @@ -1,29 +0,0 @@ -require ("global") - ---[[ - -Quest Script - -Name: Getting Started (Momodi) -Code: Trl0u1 -Id: 110142 - -Enables the "Getting Started" option on Momodi. -* NOTE: This quest is active for all players at all times. -]] - -function onTalk(player, quest, npc, eventName) - local choice = callClientFunction(player, "delegateEvent", player, quest, "processEventMomodiStart"); - - if (choice == 1) then - callClientFunction(player, "delegateEvent", player, quest, "processEvent235"); - elseif (choice == 2) then - callClientFunction(player, "delegateEvent", player, quest, "processEvent240"); - end - - player:EndEvent(); -end - -function IsQuestENPC(player, quest, npc) - return npc:GetActorClassId() == 1000841; -end \ No newline at end of file diff --git a/Map Server/Actors/Quest/Quest.cs b/Map Server/Actors/Quest/Quest.cs index 7cd6e3e5..67d246df 100644 --- a/Map Server/Actors/Quest/Quest.cs +++ b/Map Server/Actors/Quest/Quest.cs @@ -28,48 +28,8 @@ namespace Meteor.Map.Actors { class Quest : Actor { - public const ushort SEQ_NOT_STARTED = ushort.MaxValue; - - public enum QuestFlag { None = 0, Map = 1, Plate = 2 } - public enum ENpcProperty { QuestFlag = 0, CanTalk = 1, CanPush = 2, CanEmote = 3, CanNotice = 4} - - public class ENpcQuestInstance - { - public readonly uint actorClassId; - public byte questFlagType { set; get; } - public bool isSpawned { set; get; } - public bool isTalkEnabled { set; get; } - public bool isEmoteEnabled { set; get; } - public bool isPushEnabled { set; get; } - - public ENpcQuestInstance(uint actorClassId, byte questFlagType, bool isSpawned, bool isTalkEnabled, bool isEmoteEnabled, bool isPushEnabled) - { - this.actorClassId = actorClassId; - this.questFlagType = questFlagType; - this.isSpawned = isSpawned; - this.isTalkEnabled = isTalkEnabled; - this.isEmoteEnabled = isEmoteEnabled; - this.isPushEnabled = isPushEnabled; - } - - public bool IsChanged(byte flagType, bool isTalkEnabled, bool isPushEnabled, bool isEmoteEnabled, bool isSpawned) - { - return flagType != this.questFlagType - || isTalkEnabled != this.isTalkEnabled - || isPushEnabled != this.isPushEnabled - || isEmoteEnabled != this.isEmoteEnabled - || isSpawned != this.isSpawned; - } - - public void Update(byte flagType, bool isTalkEnabled, bool isPushEnabled, bool isEmoteEnabled, bool isSpawned) - { - this.questFlagType = flagType; - this.isSpawned = isSpawned; - this.isTalkEnabled = isTalkEnabled; - this.isEmoteEnabled = isEmoteEnabled; - this.isPushEnabled = isPushEnabled; - } - } + public const ushort SEQ_NOT_STARTED = 65535; + public const ushort SEQ_COMPLETED = 65534; private struct QuestData { @@ -88,43 +48,37 @@ namespace Meteor.Map.Actors } } + // This is only set on instance quests (non static) private Player Owner; private ushort currentSequence; - private QuestData data = new QuestData(); + private QuestState QuestState; + private QuestData Data; private bool dataDirty = false; - private Dictionary CurrentENPCs = new Dictionary(); - private Dictionary OldENPCs = new Dictionary(); - public void AddENpc(uint classId, byte flagType = 0, bool isTalkEnabled = true, bool isPushEnabled = false, bool isEmoteEnabled = false, bool isSpawned = false) + public void SetENpc(uint classId, byte flagType = 0, bool isTalkEnabled = true, bool isPushEnabled = false, bool isEmoteEnabled = false, bool isSpawned = false) { - ENpcQuestInstance instanceUpdated = null; - - if (OldENPCs.ContainsKey(classId)) - { - if (OldENPCs[classId].IsChanged(flagType, isTalkEnabled, isPushEnabled, isEmoteEnabled, isSpawned)) - { - OldENPCs[classId].Update(flagType, isTalkEnabled, isPushEnabled, isEmoteEnabled, isSpawned); - instanceUpdated = OldENPCs[classId]; - } - - CurrentENPCs.Add(classId, OldENPCs[classId]); - OldENPCs.Remove(classId); - } - else - { - instanceUpdated = new ENpcQuestInstance(classId, flagType, isSpawned, isTalkEnabled, isEmoteEnabled, isPushEnabled); - CurrentENPCs.Add(classId, instanceUpdated); - } - - if (instanceUpdated != null) - Owner.playerSession.UpdateQuestNpcInInstance(instanceUpdated); + if (QuestState != null) + QuestState.AddENpc(classId, flagType, isTalkEnabled, isPushEnabled, isEmoteEnabled, isSpawned); } - - public ENpcQuestInstance GetENpcInstance(uint classId) + + public void UpdateENPCs() { - if (CurrentENPCs.ContainsKey(classId)) - return CurrentENPCs[classId]; - return null; + if (dataDirty) + { + if (QuestState != null) + QuestState.UpdateState(); + dataDirty = false; + } + } + + public QuestState GetQuestState() + { + return QuestState; + } + + public bool IsInstance() + { + return Owner != null; } public void OnTalk(Player caller, Npc npc) @@ -152,25 +106,11 @@ namespace Meteor.Map.Actors LuaEngine.GetInstance().CallLuaFunction(caller, this, "onNpcLS", true, npcLSId); } - public void UpdateENPCs() - { - if (dataDirty) - { - OldENPCs = CurrentENPCs; - CurrentENPCs = new Dictionary(); - LuaEngine.GetInstance().CallLuaFunctionForReturn(Owner, this, "onSequence", false, currentSequence); - foreach (var enpc in OldENPCs) - Owner.playerSession.UpdateQuestNpcInInstance(enpc.Value); - OldENPCs = null; - dataDirty = false; - } - } - public bool IsQuestENPC(Player caller, Npc npc) { List returned = LuaEngine.GetInstance().CallLuaFunctionForReturn(caller, this, "IsQuestENPC", true, npc, this); bool scriptReturned = returned != null && returned.Count != 0 && returned[0].typeID == 3; - return scriptReturned || CurrentENPCs.ContainsKey(npc.GetActorClassId()); + return scriptReturned || QuestState.HasENpc(npc.GetActorClassId()); } @@ -213,14 +153,14 @@ namespace Meteor.Map.Actors public void ClearData() { - data.flags = data.counter1 = data.counter2 = data.counter3 = data.counter4 = 0; + Data.flags = Data.counter1 = Data.counter2 = Data.counter3 = Data.counter4 = 0; } public void SetFlag(int index) { if (index >= 0 && index < 32) { - data.flags |= (uint)(1 << index); + Data.flags |= (uint)(1 << index); dataDirty = true; } } @@ -229,7 +169,7 @@ namespace Meteor.Map.Actors { if (index >= 0 && index < 32) { - data.flags &= (uint)~(1 << index); + Data.flags &= (uint)~(1 << index); dataDirty = true; } } @@ -241,16 +181,16 @@ namespace Meteor.Map.Actors switch (num) { case 0: - data.counter1++; + Data.counter1++; return; case 1: - data.counter2++; + Data.counter2++; return; case 2: - data.counter3++; + Data.counter3++; return; case 3: - data.counter4++; + Data.counter4++; return; } @@ -264,16 +204,16 @@ namespace Meteor.Map.Actors switch (num) { case 0: - data.counter1--; + Data.counter1--; return; case 1: - data.counter2--; + Data.counter2--; return; case 2: - data.counter3--; + Data.counter3--; return; case 3: - data.counter4--; + Data.counter4--; return; } @@ -287,16 +227,16 @@ namespace Meteor.Map.Actors switch (num) { case 0: - data.counter1 = value; + Data.counter1 = value; return; case 1: - data.counter2 = value; + Data.counter2 = value; return; case 2: - data.counter3 = value; + Data.counter3 = value; return; case 3: - data.counter4 = value; + Data.counter4 = value; return; } @@ -306,13 +246,13 @@ namespace Meteor.Map.Actors public bool GetFlag(int index) { if (index >= 0 && index < 32) - return (data.flags & (uint) (1 << index)) != 0; + return (Data.flags & (uint) (1 << index)) != 0; return false; } public uint GetFlags() { - return data.flags; + return Data.flags; } public ushort GetCounter(int num) @@ -320,13 +260,13 @@ namespace Meteor.Map.Actors switch (num) { case 0: - return data.counter1; + return Data.counter1; case 1: - return data.counter2; + return Data.counter2; case 2: - return data.counter3; + return Data.counter3; case 3: - return data.counter4; + return Data.counter4; } return 0; @@ -354,12 +294,8 @@ namespace Meteor.Map.Actors className = baseQuest.className; classPath = baseQuest.classPath; currentSequence = sequence; - data = new QuestData(flags, counter1, counter2, counter3); - - if (currentSequence == SEQ_NOT_STARTED) - LuaEngine.GetInstance().CallLuaFunction(Owner, this, "onStart", false); - else - StartSequence(currentSequence); + QuestState = new QuestState(owner, this); + Data = new QuestData(flags, counter1, counter2, counter3); } public uint GetQuestId() @@ -367,17 +303,34 @@ namespace Meteor.Map.Actors return Id & 0xFFFFF; } + public void DoAccept() + { + if (currentSequence == SEQ_NOT_STARTED) + LuaEngine.GetInstance().CallLuaFunction(Owner, this, "onStart", false); + else + StartSequence(currentSequence); + } + public void DoComplete() { LuaEngine.GetInstance().CallLuaFunctionForReturn(Owner, this, "onFinish", true); Owner.SendDataPacket("attention", Server.GetWorldManager().GetActor(), "", 25225, (object)GetQuestId()); Owner.SendGameMessage(Server.GetWorldManager().GetActor(), 25225, 0x20, (object)GetQuestId()); + currentSequence = SEQ_COMPLETED; } public void DoAbandon() { LuaEngine.GetInstance().CallLuaFunctionForReturn(Owner, this, "onFinish", false); Owner.SendGameMessage(Owner, Server.GetWorldManager().GetActor(), 25236, 0x20, (object)GetQuestId()); + currentSequence = SEQ_NOT_STARTED; + } + + public override bool Equals(object obj) + { + if (obj is Quest quest) + return quest.Id == this.Id; + return false; } } } diff --git a/Map Server/Actors/Quest/QuestState.cs b/Map Server/Actors/Quest/QuestState.cs new file mode 100644 index 00000000..068083cd --- /dev/null +++ b/Map Server/Actors/Quest/QuestState.cs @@ -0,0 +1,112 @@ +using Meteor.Map.lua; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Meteor.Map.Actors +{ + class QuestState + { + public enum QuestFlag { None = 0, Map = 1, Plate = 2 } + + public class QuestENpc + { + public readonly uint actorClassId; + public byte questFlagType { set; get; } + public bool isSpawned { set; get; } + public bool isTalkEnabled { set; get; } + public bool isEmoteEnabled { set; get; } + public bool isPushEnabled { set; get; } + + public QuestENpc(uint actorClassId, byte questFlagType, bool isSpawned, bool isTalkEnabled, bool isEmoteEnabled, bool isPushEnabled) + { + this.actorClassId = actorClassId; + this.questFlagType = questFlagType; + this.isSpawned = isSpawned; + this.isTalkEnabled = isTalkEnabled; + this.isEmoteEnabled = isEmoteEnabled; + this.isPushEnabled = isPushEnabled; + } + + public bool IsChanged(byte flagType, bool isTalkEnabled, bool isPushEnabled, bool isEmoteEnabled, bool isSpawned) + { + return flagType != this.questFlagType + || isTalkEnabled != this.isTalkEnabled + || isPushEnabled != this.isPushEnabled + || isEmoteEnabled != this.isEmoteEnabled + || isSpawned != this.isSpawned; + } + + public void Update(byte flagType, bool isTalkEnabled, bool isPushEnabled, bool isEmoteEnabled, bool isSpawned) + { + this.questFlagType = flagType; + this.isSpawned = isSpawned; + this.isTalkEnabled = isTalkEnabled; + this.isEmoteEnabled = isEmoteEnabled; + this.isPushEnabled = isPushEnabled; + } + } + + private Player Owner; + private Quest Parent; + private Dictionary CurrentENPCs = new Dictionary(); + private Dictionary OldENPCs = new Dictionary(); + + public QuestState(Player owner, Quest parent) + { + Owner = owner; + Parent = parent; + UpdateState(); + } + + public void AddENpc(uint classId, byte flagType = 0, bool isTalkEnabled = true, bool isPushEnabled = false, bool isEmoteEnabled = false, bool isSpawned = false) + { + QuestENpc instanceUpdated = null; + + if (OldENPCs.ContainsKey(classId)) + { + if (OldENPCs[classId].IsChanged(flagType, isTalkEnabled, isPushEnabled, isEmoteEnabled, isSpawned)) + { + OldENPCs[classId].Update(flagType, isTalkEnabled, isPushEnabled, isEmoteEnabled, isSpawned); + instanceUpdated = OldENPCs[classId]; + } + + CurrentENPCs.Add(classId, OldENPCs[classId]); + OldENPCs.Remove(classId); + } + else + { + instanceUpdated = new QuestENpc(classId, flagType, isSpawned, isTalkEnabled, isEmoteEnabled, isPushEnabled); + CurrentENPCs.Add(classId, instanceUpdated); + } + + if (instanceUpdated != null) + Owner.playerSession.UpdateQuestNpcInInstance(instanceUpdated); + } + + public QuestENpc GetENpc(uint classId) + { + if (CurrentENPCs.ContainsKey(classId)) + return CurrentENPCs[classId]; + return null; + } + + public bool HasENpc(uint classId) + { + return CurrentENPCs.ContainsKey(classId); + } + + public void UpdateState() + { + ushort currentSeq = Parent.GetSequence(); + OldENPCs = CurrentENPCs; + CurrentENPCs = new Dictionary(); + LuaEngine.GetInstance().CallLuaFunctionForReturn(Owner, Parent, "onStateChange", false, currentSeq); + foreach (var enpc in OldENPCs) + Owner.playerSession.UpdateQuestNpcInInstance(enpc.Value); + OldENPCs = null; + } + } +} diff --git a/Map Server/Actors/Quest/QuestStateManager.cs b/Map Server/Actors/Quest/QuestStateManager.cs new file mode 100644 index 00000000..e2e2bf7d --- /dev/null +++ b/Map Server/Actors/Quest/QuestStateManager.cs @@ -0,0 +1,108 @@ +using Meteor.Common; +using Meteor.Map.DataObjects; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Meteor.Map.Actors +{ + class QuestStateManager + { + private const int SCENARIO_START = 110001; + private const int SCENARIO_MAX = 2048; + + private readonly Player player; + private readonly Bitstream AvailableQuestsBitfield = new Bitstream(SCENARIO_MAX); + private readonly Bitstream MinLevelBitfield = new Bitstream(SCENARIO_MAX); + private readonly Bitstream PrereqBitfield = new Bitstream(SCENARIO_MAX, true); + private readonly Bitstream GCRankBitfield = new Bitstream(SCENARIO_MAX, true); + + private List ActiveQuests = new List(); + + public QuestStateManager(Player player) + { + this.player = player; + } + + public void Init() + { + // Init MinLv + QuestData[] minLvl = Server.GetQuestGamedataByMaxLvl(player.GetHighestLevel(), true); + foreach (var questData in minLvl) + MinLevelBitfield.Set(questData.Id - SCENARIO_START); + + // Init Prereq + Bitstream completed = new Bitstream(player.playerWork.questScenarioComplete); + foreach (var questData in Server.GetQuestGamedataAllPrerequisite()) + { + if (completed.Get(((Quest)Server.GetStaticActors(0xA0F00000 | questData.PrerequisiteQuest)).GetQuestId() - SCENARIO_START)) + PrereqBitfield.Set(questData.Id - SCENARIO_START); + else + PrereqBitfield.Clear(questData.Id - SCENARIO_START); + } + ComputeAvailable(); + } + + public void UpdateLevel(int level) + { + QuestData[] updated = Server.GetQuestGamedataByMaxLvl(level); + foreach (var questData in updated) + MinLevelBitfield.Set(questData.Id - SCENARIO_START); + ComputeAvailable(); + } + + public void UpdateQuestComplete(Quest quest) + { + QuestData[] updated = Server.GetQuestGamedataByPrerequisite(quest.GetQuestId()); + foreach (var questData in updated) + PrereqBitfield.Set(questData.Id - SCENARIO_START); + ComputeAvailable(); + } + + public void QuestAdded(Quest quest) + { + ActiveQuests.Remove(quest); + } + + private void ComputeAvailable() + { + Bitstream result = new Bitstream(player.playerWork.questScenarioComplete); + result.NOT(); + result.AND(MinLevelBitfield); + result.AND(PrereqBitfield); + result.AND(GCRankBitfield); + + Bitstream difference = AvailableQuestsBitfield.Copy(); + difference.XOR(result); + byte[] diffBytes = difference.GetBytes(); + + for (int i = 0; i < diffBytes.Length; i++) + { + if (diffBytes[i] == 0) + continue; + for (int shift = 0; shift < 8; shift++) + { + if ((diffBytes[i] >> shift & 1) == 1) + { + int index = i * 8 + shift; + Quest quest = (Quest)Server.GetStaticActors(0xA0F00000 | (SCENARIO_START + (uint)index)); + if (!AvailableQuestsBitfield.Get(index)) + ActiveQuests.Add(new Quest(player, quest)); + else + ActiveQuests.Remove(quest); + } + } + } + + AvailableQuestsBitfield.SetTo(result); + } + + public Quest[] GetQuestsForNpc(Npc npc) + { + return ActiveQuests.FindAll(quest => quest.IsQuestENPC(player, npc)).ToArray(); + } + } +} diff --git a/Map Server/Database.cs b/Map Server/Database.cs index ecf7eec0..129062ba 100644 --- a/Map Server/Database.cs +++ b/Map Server/Database.cs @@ -26,7 +26,7 @@ using Meteor.Common; using Meteor.Map.utils; using Meteor.Map.packets.send.player; -using Meteor.Map.dataobjects; +using Meteor.Map.DataObjects; using Meteor.Map.Actors; using Meteor.Map.actors.chara.player; using Meteor.Map.packets.receive.supportdesk; @@ -72,6 +72,56 @@ namespace Meteor.Map return id; } + public static Dictionary GetQuestGamedata() + { + using (var conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD))) + { + Dictionary gamedataQuests = new Dictionary(); + + try + { + conn.Open(); + + string query = @" + SELECT + id, + className, + questName, + prerequisite, + minLevel, + minGCRank + FROM gamedata_quests + "; + + MySqlCommand cmd = new MySqlCommand(query, conn); + + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + uint questId = reader.GetUInt32("id"); + string code = reader.GetString("className"); + string name = reader.GetString("questName"); + uint prerequisite = reader.GetUInt32("prerequisite"); + ushort minLevel = reader.GetUInt16("minLevel"); + ushort minRank = reader.GetUInt16("minGCRank"); + gamedataQuests.Add(questId, new QuestData(questId, code, name, prerequisite, minLevel, minRank)); + } + } + } + catch (MySqlException e) + { + Program.Log.Error(e.ToString()); + } + finally + { + conn.Dispose(); + } + + return gamedataQuests; + } + } + public static Dictionary GetItemGamedata() { using (var conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD))) diff --git a/Map Server/Map Server.csproj b/Map Server/Map Server.csproj index 8c6639a5..8d421cd9 100644 --- a/Map Server/Map Server.csproj +++ b/Map Server/Map Server.csproj @@ -180,9 +180,12 @@ + + + diff --git a/Map Server/PacketProcessor.cs b/Map Server/PacketProcessor.cs index 6e6619d5..c36f761a 100644 --- a/Map Server/PacketProcessor.cs +++ b/Map Server/PacketProcessor.cs @@ -22,7 +22,7 @@ along with Project Meteor Server. If not, see . using Meteor.Common; using System; -using Meteor.Map.dataobjects; +using Meteor.Map.DataObjects; using Meteor.Map.packets.receive; using Meteor.Map.packets.send; using Meteor.Map.packets.send.login; diff --git a/Map Server/Server.cs b/Map Server/Server.cs index 8bb8f1c9..af4724bf 100644 --- a/Map Server/Server.cs +++ b/Map Server/Server.cs @@ -23,10 +23,11 @@ using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; -using Meteor.Map.dataobjects; +using Meteor.Map.DataObjects; using Meteor.Common; using Meteor.Map.Actors; +using System.Linq; namespace Meteor.Map { @@ -38,52 +39,56 @@ namespace Meteor.Map public const string STATIC_ACTORS_PATH = "./staticactors.bin"; - private static Server mSelf; + private static Server _Self; - private Socket mServerSocket; + private Socket ServerSocket; - private Dictionary mSessionList = new Dictionary(); + private Dictionary SessionList = new Dictionary(); - private static CommandProcessor mCommandProcessor = new CommandProcessor(); - private static ZoneConnection mWorldConnection = new ZoneConnection(); - private static WorldManager mWorldManager; - private static Dictionary mGamedataItems; - private static Dictionary mGamedataGuildleves; - private static StaticActors mStaticActors; + private static CommandProcessor CommandProcessor = new CommandProcessor(); + private static ZoneConnection WorldConnection = new ZoneConnection(); + private static WorldManager WorldManager; + private static Dictionary GamedataItems; + private static Dictionary GamedataGuildleves; + private static Dictionary GamedataQuests; + private static StaticActors StaticActors; private PacketProcessor mProcessor; public Server() { - mSelf = this; + _Self = this; } public bool StartServer() { - mStaticActors = new StaticActors(STATIC_ACTORS_PATH); + StaticActors = new StaticActors(STATIC_ACTORS_PATH); - mGamedataItems = Database.GetItemGamedata(); - Program.Log.Info("Loaded {0} items.", mGamedataItems.Count); - mGamedataGuildleves = Database.GetGuildleveGamedata(); - Program.Log.Info("Loaded {0} guildleves.", mGamedataGuildleves.Count); + Program.Log.Info("Loading gamedata..."); + GamedataItems = Database.GetItemGamedata(); + Program.Log.Info("Loaded {0} items.", GamedataItems.Count); + GamedataGuildleves = Database.GetGuildleveGamedata(); + Program.Log.Info("Loaded {0} guildleves.", GamedataGuildleves.Count); + GamedataQuests = Database.GetQuestGamedata(); + Program.Log.Info("Loaded {0} quests.", GamedataQuests.Count); - mWorldManager = new WorldManager(this); - mWorldManager.LoadZoneList(); - mWorldManager.LoadSeamlessBoundryList(); - mWorldManager.LoadActorClasses(); - mWorldManager.LoadENPCs(); - mWorldManager.LoadBattleNpcs(); - mWorldManager.LoadStatusEffects(); - mWorldManager.LoadBattleCommands(); - mWorldManager.LoadBattleTraits(); - mWorldManager.SpawnAllActors(); - mWorldManager.StartZoneThread(); + WorldManager = new WorldManager(this); + WorldManager.LoadZoneList(); + WorldManager.LoadSeamlessBoundryList(); + WorldManager.LoadActorClasses(); + WorldManager.LoadENPCs(); + WorldManager.LoadBattleNpcs(); + WorldManager.LoadStatusEffects(); + WorldManager.LoadBattleCommands(); + WorldManager.LoadBattleTraits(); + WorldManager.SpawnAllActors(); + WorldManager.StartZoneThread(); IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse(ConfigConstants.OPTIONS_BINDIP), int.Parse(ConfigConstants.OPTIONS_PORT)); try { - mServerSocket = new Socket(serverEndPoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + ServerSocket = new Socket(serverEndPoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp); } catch (Exception e) { @@ -91,8 +96,8 @@ namespace Meteor.Map } try { - mServerSocket.Bind(serverEndPoint); - mServerSocket.Listen(BACKLOG); + ServerSocket.Bind(serverEndPoint); + ServerSocket.Listen(BACKLOG); } catch (Exception e) { @@ -100,7 +105,7 @@ namespace Meteor.Map } try { - mServerSocket.BeginAccept(new AsyncCallback(AcceptCallback), mServerSocket); + ServerSocket.BeginAccept(new AsyncCallback(AcceptCallback), ServerSocket); } catch (Exception e) { @@ -108,7 +113,7 @@ namespace Meteor.Map } Console.ForegroundColor = ConsoleColor.White; - Program.Log.Info("Map Server has started @ {0}:{1}", (mServerSocket.LocalEndPoint as IPEndPoint).Address, (mServerSocket.LocalEndPoint as IPEndPoint).Port); + Program.Log.Info("Map Server has started @ {0}:{1}", (ServerSocket.LocalEndPoint as IPEndPoint).Address, (ServerSocket.LocalEndPoint as IPEndPoint).Port); Console.ForegroundColor = ConsoleColor.Gray; mProcessor = new PacketProcessor(this); @@ -122,36 +127,36 @@ namespace Meteor.Map public Session AddSession(uint id) { - if (mSessionList.ContainsKey(id)) + if (SessionList.ContainsKey(id)) { - mSessionList[id].ClearInstance(); - return mSessionList[id]; + SessionList[id].ClearInstance(); + return SessionList[id]; } Session session = new Session(id); - mSessionList.Add(id, session); + SessionList.Add(id, session); return session; } public void RemoveSession(uint id) { - if (mSessionList.ContainsKey(id)) + if (SessionList.ContainsKey(id)) { - mSessionList.Remove(id); + SessionList.Remove(id); } } public Session GetSession(uint id) { - if (mSessionList.ContainsKey(id)) - return mSessionList[id]; + if (SessionList.ContainsKey(id)) + return SessionList[id]; else return null; } public Session GetSession(string name) { - foreach (Session s in mSessionList.Values) + foreach (Session s in SessionList.Values) { if (s.GetActor().DisplayName.ToLower().Equals(name.ToLower())) return s; @@ -161,7 +166,7 @@ namespace Meteor.Map public Dictionary GetSessionList() { - return mSessionList; + return SessionList; } #endregion @@ -179,29 +184,29 @@ namespace Meteor.Map conn.socket = socket.EndAccept(result); conn.buffer = new byte[BUFFER_SIZE]; - mWorldConnection = conn; + WorldConnection = conn; Program.Log.Info("Connection {0}:{1} has connected.", (conn.socket.RemoteEndPoint as IPEndPoint).Address, (conn.socket.RemoteEndPoint as IPEndPoint).Port); //Queue recieving of data from the connection conn.socket.BeginReceive(conn.buffer, 0, conn.buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), conn); //Queue the accept of the next incomming connection - mServerSocket.BeginAccept(new AsyncCallback(AcceptCallback), mServerSocket); + ServerSocket.BeginAccept(new AsyncCallback(AcceptCallback), ServerSocket); } catch (SocketException) { if (conn != null) { - mWorldConnection = null; + WorldConnection = null; } - mServerSocket.BeginAccept(new AsyncCallback(AcceptCallback), mServerSocket); + ServerSocket.BeginAccept(new AsyncCallback(AcceptCallback), ServerSocket); } catch (Exception) { if (conn != null) { - mWorldConnection = null; + WorldConnection = null; } - mServerSocket.BeginAccept(new AsyncCallback(AcceptCallback), mServerSocket); + ServerSocket.BeginAccept(new AsyncCallback(AcceptCallback), ServerSocket); } } @@ -216,7 +221,7 @@ namespace Meteor.Map //Check if disconnected if ((conn.socket.Poll(1, SelectMode.SelectRead) && conn.socket.Available == 0)) { - mWorldConnection = null; + WorldConnection = null; Program.Log.Info("Disconnected from world server!"); } @@ -260,7 +265,7 @@ namespace Meteor.Map } else { - mWorldConnection = null; + WorldConnection = null; Program.Log.Info("Disconnected from world server!"); } } @@ -268,7 +273,7 @@ namespace Meteor.Map { if (conn.socket != null) { - mWorldConnection = null; + WorldConnection = null; Program.Log.Info("Disconnected from world server!"); } } @@ -278,54 +283,90 @@ namespace Meteor.Map public static ZoneConnection GetWorldConnection() { - return mWorldConnection; + return WorldConnection; } public static Server GetServer() { - return mSelf; + return _Self; } public static CommandProcessor GetCommandProcessor() { - return mCommandProcessor; + return CommandProcessor; } public static WorldManager GetWorldManager() { - return mWorldManager; + return WorldManager; } public static Dictionary GetGamedataItems() { - return mGamedataItems; + return GamedataItems; } public static Actor GetStaticActors(uint id) { - return mStaticActors.GetActor(id); + return StaticActors.GetActor(id); } public static Actor GetStaticActors(string name) { - return mStaticActors.FindStaticActor(name); + return StaticActors.FindStaticActor(name); } public static ItemData GetItemGamedata(uint id) { - if (mGamedataItems.ContainsKey(id)) - return mGamedataItems[id]; + if (GamedataItems.ContainsKey(id)) + return GamedataItems[id]; else return null; } public static GuildleveData GetGuildleveGamedata(uint id) { - if (mGamedataGuildleves.ContainsKey(id)) - return mGamedataGuildleves[id]; + if (GamedataGuildleves.ContainsKey(id)) + return GamedataGuildleves[id]; else return null; } + public static QuestData GetQuestGamedata(uint id) + { + if (GamedataQuests.ContainsKey(id)) + return GamedataQuests[id]; + else + return null; + } + + + public static QuestData[] GetQuestGamedataByMaxLvl(int lvl, bool all = false) + { + if (all) + return GamedataQuests.Values.Where(quest => quest.MinLevel > 0 && quest.MinLevel <= lvl).ToArray(); + else + return GamedataQuests.Values.Where(quest => quest.MinLevel > 0 && quest.MinLevel == lvl).ToArray(); + } + + public static QuestData[] GetQuestGamedataByPrerequisite(uint questId) + { + return GamedataQuests.Values.Where(quest => quest.PrerequisiteQuest == questId).ToArray(); + } + + public static QuestData[] GetQuestGamedataAllPrerequisite() + { + return GamedataQuests.Values.Where(quest => quest.PrerequisiteQuest != 0).ToArray(); + } + + public static QuestData[] GetQuestGamedataAllGCRanked() + { + return GamedataQuests.Values.Where(quest => quest.MinGCRank != 0).ToArray(); + } + + //public static QuestData[] GetQuestGamedataByGCRank(int gc, int rank, bool all = false) + //{ + // return GamedataQuests.Values.Where(quest => all ? quest.MinLevel == lvl : quest.MinLevel <= lvl).ToArray(); + //} } } diff --git a/Map Server/WorldManager.cs b/Map Server/WorldManager.cs index 85ec220a..d1723e2e 100644 --- a/Map Server/WorldManager.cs +++ b/Map Server/WorldManager.cs @@ -23,7 +23,7 @@ using Meteor.Common; using Meteor.Map.actors.area; using Meteor.Map.actors.chara.npc; using Meteor.Map.Actors; -using Meteor.Map.dataobjects; +using Meteor.Map.DataObjects; using Meteor.Map.lua; using Meteor.Map.packets.send; using Meteor.Map.packets.send.actor;