mirror of
https://bitbucket.org/Ioncannon/project-meteor-server.git
synced 2025-04-25 14:17:46 +00:00
Merge remote-tracking branch 'origin/ioncannon/quest_system' into Jorge/quest_system
This commit is contained in:
commit
594e08f990
84 changed files with 2660 additions and 1279 deletions
204
Common Class Lib/Bitstream.cs
Normal file
204
Common Class Lib/Bitstream.cs
Normal file
|
@ -0,0 +1,204 @@
|
||||||
|
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 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 void SetTo(bool[] result)
|
||||||
|
{
|
||||||
|
Debug.Assert(Data.Length == result.Length / 8);
|
||||||
|
Data = Utils.ConvertBoolArrayToBinaryStream(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] GetSlice(ushort from, ushort to)
|
||||||
|
{
|
||||||
|
int remainder = ((to - from) % 8 != 0) ? 1 : 0;
|
||||||
|
byte[] toReturn = new byte[((to - from) / 8) + remainder + 1];
|
||||||
|
toReturn[toReturn.Length - 1] = 0x3;
|
||||||
|
|
||||||
|
|
||||||
|
byte curByte = 0;
|
||||||
|
|
||||||
|
int destByteIndx = 0;
|
||||||
|
int destShiftIndx = 0;
|
||||||
|
int srcByteIndx = from / 8;
|
||||||
|
int srcShiftIndx = from % 8;
|
||||||
|
|
||||||
|
for (int i = from; i <= to; i++)
|
||||||
|
{
|
||||||
|
// Skip Zeros
|
||||||
|
if (Data[srcByteIndx] == 0)
|
||||||
|
{
|
||||||
|
srcByteIndx++;
|
||||||
|
srcShiftIndx = 0;
|
||||||
|
destByteIndx++;
|
||||||
|
i += 8;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool val = (Data[srcByteIndx] & (1 << srcShiftIndx++)) != 0;
|
||||||
|
|
||||||
|
curByte |= (byte)((val ? 1 : 0) << destShiftIndx++);
|
||||||
|
if (srcShiftIndx == 8)
|
||||||
|
{
|
||||||
|
srcShiftIndx = 0;
|
||||||
|
srcByteIndx++;
|
||||||
|
}
|
||||||
|
if (destShiftIndx == 8)
|
||||||
|
{
|
||||||
|
toReturn[destByteIndx++] = curByte;
|
||||||
|
destShiftIndx = 0;
|
||||||
|
curByte = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (destByteIndx == toReturn.Length - 2)
|
||||||
|
toReturn[destByteIndx] = curByte;
|
||||||
|
|
||||||
|
return toReturn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -87,6 +87,7 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="BasePacket.cs" />
|
<Compile Include="BasePacket.cs" />
|
||||||
<Compile Include="Bitfield.cs" />
|
<Compile Include="Bitfield.cs" />
|
||||||
|
<Compile Include="Bitstream.cs" />
|
||||||
<Compile Include="Blowfish.cs" />
|
<Compile Include="Blowfish.cs" />
|
||||||
<Compile Include="EfficientHashTables.cs" />
|
<Compile Include="EfficientHashTables.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
|
|
@ -245,7 +245,7 @@ namespace Meteor.Common
|
||||||
{
|
{
|
||||||
for (var bitCount = 0; bitCount < 8; bitCount++)
|
for (var bitCount = 0; bitCount < 8; bitCount++)
|
||||||
{
|
{
|
||||||
if (i + bitCount >= array.Length)
|
if (i + bitCount >= array.Length - 1)
|
||||||
break;
|
break;
|
||||||
data[dataCounter] = (byte)(((array[i + bitCount] ? 1 : 0) << 7 - bitCount) | data[dataCounter]);
|
data[dataCounter] = (byte)(((array[i + bitCount] ? 1 : 0) << 7 - bitCount) | data[dataCounter]);
|
||||||
}
|
}
|
||||||
|
@ -255,6 +255,26 @@ namespace Meteor.Common
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool[] ConvertBinaryStreamToBoolArray(byte[] bytes)
|
||||||
|
{
|
||||||
|
bool[] data = new bool[bytes.Length * 8];
|
||||||
|
|
||||||
|
int boolCounter = 0;
|
||||||
|
for (int i = 0; i < bytes.Length; i ++)
|
||||||
|
{
|
||||||
|
if (bytes[i] == 0)
|
||||||
|
{
|
||||||
|
boolCounter += 8;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int bitCount = 0; bitCount < 8; bitCount++)
|
||||||
|
data[boolCounter++] = (bytes[i] >> bitCount & 1) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
public static string ToStringBase63(int number)
|
public static string ToStringBase63(int number)
|
||||||
{
|
{
|
||||||
var lookup = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
var lookup = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
|
|
58
Data/scripts/commands/gm/completedQuest.lua
Normal file
58
Data/scripts/commands/gm/completedQuest.lua
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
require("global");
|
||||||
|
|
||||||
|
properties = {
|
||||||
|
permissions = 0,
|
||||||
|
parameters = "dd",
|
||||||
|
description =
|
||||||
|
[[
|
||||||
|
Sets if a quest is completed.
|
||||||
|
!completedQuest <questId> true/false
|
||||||
|
]],
|
||||||
|
}
|
||||||
|
|
||||||
|
function onTrigger(player, argc, questId, flag)
|
||||||
|
|
||||||
|
print("HEY");
|
||||||
|
local messageID = MESSAGE_TYPE_SYSTEM_ERROR;
|
||||||
|
local sender = "[completedQuest] ";
|
||||||
|
local message = "Error";
|
||||||
|
|
||||||
|
if (argc < 1) then
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
local questId = tonumber(questId);
|
||||||
|
local flag = flag or nil;
|
||||||
|
|
||||||
|
-- Fail if not valid questId
|
||||||
|
if (questId < 110001 or questId > 110001 + 2048) then
|
||||||
|
player:SendMessage(messageID, sender, "Invalid questId entered");
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Getting
|
||||||
|
if (arc == 1) then
|
||||||
|
player:SendMessage(messageID, sender, string.format("Quest %d completion is set to: %s", questId, tostring(player:IsQuestCompleted(questId))));
|
||||||
|
return;
|
||||||
|
-- Setting
|
||||||
|
else
|
||||||
|
-- Fail if not valid flag
|
||||||
|
if (not flag == nil) then
|
||||||
|
player:SendMessage(messageID, sender, "Invalid flag entered");
|
||||||
|
else
|
||||||
|
local boolFlag = false;
|
||||||
|
|
||||||
|
if (flag == "true" or flag == "1" or flag == "on" or flag == "O") then
|
||||||
|
boolFlag = true;
|
||||||
|
elseif (flag == "false" or flag == "0" or flag == "off" or flag == "X") then
|
||||||
|
boolFlag = false;
|
||||||
|
elseif flag == "flip" or flag == "toggle" then
|
||||||
|
boolFlag = not player:IsQuestCompleted(questId);
|
||||||
|
end
|
||||||
|
|
||||||
|
player:SetQuestComplete(questId, boolFlag);
|
||||||
|
player:SendMessage(messageID, sender, string.format("Quest %d completion set to: %s", questId, tostring(player:IsQuestCompleted(questId))));
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -66,7 +66,7 @@ function onTrigger(player, argc, command, var1, var2, var3)
|
||||||
|
|
||||||
local flagStr = "";
|
local flagStr = "";
|
||||||
for i=0,31,1 do
|
for i=0,31,1 do
|
||||||
if (quest:GetFlag(i)) then
|
if (quest:GetData():GetFlag(i)) then
|
||||||
flagStr = flagStr .. "O";
|
flagStr = flagStr .. "O";
|
||||||
else
|
else
|
||||||
flagStr = flagStr .. "X";
|
flagStr = flagStr .. "X";
|
||||||
|
@ -76,10 +76,12 @@ function onTrigger(player, argc, command, var1, var2, var3)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local data = quest:GetData();
|
||||||
|
|
||||||
message = string.format("\nInfo for quest %s [%d]\n", quest.Name, quest:GetQuestId());
|
message = string.format("\nInfo for quest %s [%d]\n", quest.Name, quest:GetQuestId());
|
||||||
message = message .. string.format("Current Sequence: %d\n", quest:getSequence());
|
message = message .. string.format("Current Sequence: %d\n", quest:getSequence());
|
||||||
message = message .. string.format("Flags: \n%s\n", flagStr)
|
message = message .. string.format("Flags: \n%s\n", flagStr)
|
||||||
message = message .. string.format("Counters: %d,%d,%d,%d", quest:getCounter(0), quest:getCounter(1), quest:getCounter(2), quest:getCounter(3));
|
message = message .. string.format("Counters: %d,%d,%d,%d", data:getCounter(0), data:getCounter(1), data:getCounter(2), data:getCounter(3));
|
||||||
else
|
else
|
||||||
message = ("Quest not active: "..var1);
|
message = ("Quest not active: "..var1);
|
||||||
end
|
end
|
||||||
|
@ -118,7 +120,7 @@ function onTrigger(player, argc, command, var1, var2, var3)
|
||||||
boolvar = false;
|
boolvar = false;
|
||||||
elseif var3 == "flip" or var3 == "toggle" then
|
elseif var3 == "flip" or var3 == "toggle" then
|
||||||
if player:HasQuest(questvar) == true then
|
if player:HasQuest(questvar) == true then
|
||||||
boolvar = not player:GetQuest(questvar):GetFlag(flagvar);
|
boolvar = not player:GetQuest(questvar):GetData():GetFlag(flagvar);
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
message = ("error: flag: boolean not recognized");
|
message = ("error: flag: boolean not recognized");
|
||||||
|
@ -126,13 +128,13 @@ function onTrigger(player, argc, command, var1, var2, var3)
|
||||||
return;
|
return;
|
||||||
end
|
end
|
||||||
|
|
||||||
var4 = player:GetQuest(questvar):GetFlag(flagvar);
|
var4 = player:GetQuest(questvar):GetData():GetFlag(flagvar);
|
||||||
|
|
||||||
if var4 ~= boolvar then
|
if var4 ~= boolvar then
|
||||||
if (boolvar == true) then
|
if (boolvar == true) then
|
||||||
player:GetQuest(questvar):SetFlag(flagvar);
|
player:GetQuest(questvar):GetData():SetFlag(flagvar);
|
||||||
else
|
else
|
||||||
player:GetQuest(questvar):ClearFlag(flagvar);
|
player:GetQuest(questvar):GetData():ClearFlag(flagvar);
|
||||||
end
|
end
|
||||||
player:GetQuest(questvar):UpdateENPCs();
|
player:GetQuest(questvar):UpdateENPCs();
|
||||||
player:GetQuest(questvar):SaveData();
|
player:GetQuest(questvar):SaveData();
|
||||||
|
@ -152,7 +154,7 @@ function onTrigger(player, argc, command, var1, var2, var3)
|
||||||
questvar = tonumber(var1);
|
questvar = tonumber(var1);
|
||||||
index = (tonumber(var2));
|
index = (tonumber(var2));
|
||||||
|
|
||||||
player:GetQuest(questvar):SetCounter(index, tonumber(var3));
|
player:GetQuest(questvar):GetData():SetCounter(index, tonumber(var3));
|
||||||
player:GetQuest(questvar):UpdateENPCs();
|
player:GetQuest(questvar):UpdateENPCs();
|
||||||
player:GetQuest(questvar):SaveData();
|
player:GetQuest(questvar):SaveData();
|
||||||
message = ("changing counter "..tonumber(var2).." to "..var3);
|
message = ("changing counter "..tonumber(var2).." to "..var3);
|
||||||
|
|
|
@ -41,8 +41,6 @@ FLAG_TALKED_LEFWYNE = 4;
|
||||||
-- Quest Counters
|
-- Quest Counters
|
||||||
COUNTER_TALKED = 0;
|
COUNTER_TALKED = 0;
|
||||||
|
|
||||||
--offerQuestResult = callClientFunction(player, "delegateEvent", player, quest, "processEventOffersStart");
|
|
||||||
|
|
||||||
function onStart(player, quest)
|
function onStart(player, quest)
|
||||||
quest:StartSequence(SEQ_000);
|
quest:StartSequence(SEQ_000);
|
||||||
end
|
end
|
||||||
|
@ -50,79 +48,93 @@ end
|
||||||
function onFinish(player, quest)
|
function onFinish(player, quest)
|
||||||
end
|
end
|
||||||
|
|
||||||
function onSequence(player, quest, sequence)
|
function onStateChange(player, quest, sequence)
|
||||||
|
if (sequence == 65535) then
|
||||||
|
quest:SetENpc(KINNISON, QFLAG_PLATE);
|
||||||
|
end
|
||||||
|
|
||||||
|
local data = quest:GetData();
|
||||||
if (sequence == SEQ_000) then
|
if (sequence == SEQ_000) then
|
||||||
quest:AddENpc(KINNISON);
|
quest:SetENpc(KINNISON);
|
||||||
quest:AddENpc(SYBELL, (not quest:GetFlag(FLAG_TALKED_SYBELL) and QFLAG_PLATE or QFLAG_NONE));
|
quest:SetENpc(SYBELL, (not data: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:SetENpc(KHUMA_MOSHROCA, (not data: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:SetENpc(NELLAURE, (not data: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:SetENpc(MESTONNAUX, (not data: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(LEFWYNE, (not data:GetFlag(FLAG_TALKED_LEFWYNE) and QFLAG_PLATE or QFLAG_NONE));
|
||||||
elseif (sequence == SEQ_001) then
|
elseif (sequence == SEQ_001) then
|
||||||
quest:AddENpc(KINNISON, QFLAG_PLATE);
|
quest:SetENpc(KINNISON, QFLAG_PLATE);
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function onTalk(player, quest, npc, eventName)
|
function onTalk(player, quest, npc, eventName)
|
||||||
local npcClassId = npc.GetActorClassId();
|
local npcClassId = npc.GetActorClassId();
|
||||||
local seq = quest:GetSequence();
|
local seq = quest:GetSequence();
|
||||||
local incCounter = false;
|
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 == 1) then
|
||||||
|
player:AcceptQuest(quest);
|
||||||
|
end
|
||||||
|
player:EndEvent();
|
||||||
|
return;
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Quest Progress
|
||||||
|
local data = quest:GetData();
|
||||||
if (seq == SEQ_000) then
|
if (seq == SEQ_000) then
|
||||||
if (npcClassId == KINNISON) then
|
if (npcClassId == KINNISON) then
|
||||||
callClientFunction(player, "delegateEvent", player, quest, "processEventOffersAfter");
|
callClientFunction(player, "delegateEvent", player, quest, "processEventOffersAfter");
|
||||||
elseif (npcClassId == SYBELL) then
|
elseif (npcClassId == SYBELL) then
|
||||||
if (not quest:GetFlag(FLAG_TALKED_SYBELL)) then
|
if (not data:GetFlag(FLAG_TALKED_SYBELL)) then
|
||||||
callClientFunction(player, "delegateEvent", player, quest, "processEventSybellSpeak");
|
callClientFunction(player, "delegateEvent", player, quest, "processEventSybellSpeak");
|
||||||
quest:SetFlag(FLAG_TALKED_SYBELL);
|
data:SetFlag(FLAG_TALKED_SYBELL);
|
||||||
incCounter = true;
|
incCounter = true;
|
||||||
else
|
else
|
||||||
callClientFunction(player, "delegateEvent", player, quest, "processEventSybellSpeakAfter");
|
callClientFunction(player, "delegateEvent", player, quest, "processEventSybellSpeakAfter");
|
||||||
end
|
end
|
||||||
elseif (npcClassId == KHUMA_MOSHROCA) then
|
elseif (npcClassId == KHUMA_MOSHROCA) then
|
||||||
if (not quest:GetFlag(FLAG_TALKED_KHUMA_MOSHROCA)) then
|
if (not data:GetFlag(FLAG_TALKED_KHUMA_MOSHROCA)) then
|
||||||
callClientFunction(player, "delegateEvent", player, quest, "processEventKhumaSpeak");
|
callClientFunction(player, "delegateEvent", player, quest, "processEventKhumaSpeak");
|
||||||
quest:SetFlag(FLAG_TALKED_KHUMA_MOSHROCA);
|
data:SetFlag(FLAG_TALKED_KHUMA_MOSHROCA);
|
||||||
incCounter = true;
|
incCounter = true;
|
||||||
else
|
else
|
||||||
callClientFunction(player, "delegateEvent", player, quest, "processEventKhumaSpeakAfter");
|
callClientFunction(player, "delegateEvent", player, quest, "processEventKhumaSpeakAfter");
|
||||||
end
|
end
|
||||||
elseif (npcClassId == NELLAURE) then
|
elseif (npcClassId == NELLAURE) then
|
||||||
if (not quest:GetFlag(FLAG_TALKED_NELLAURE)) then
|
if (not data:GetFlag(FLAG_TALKED_NELLAURE)) then
|
||||||
callClientFunction(player, "delegateEvent", player, quest, "processEventNellaureSpeak");
|
callClientFunction(player, "delegateEvent", player, quest, "processEventNellaureSpeak");
|
||||||
quest:SetFlag(FLAG_TALKED_NELLAURE);
|
data:SetFlag(FLAG_TALKED_NELLAURE);
|
||||||
incCounter = true;
|
incCounter = true;
|
||||||
else
|
else
|
||||||
callClientFunction(player, "delegateEvent", player, quest, "processEventNellaureSpeakAfter");
|
callClientFunction(player, "delegateEvent", player, quest, "processEventNellaureSpeakAfter");
|
||||||
end
|
end
|
||||||
elseif (npcClassId == MESTONNAUX) then
|
elseif (npcClassId == MESTONNAUX) then
|
||||||
if (not quest:GetFlag(FLAG_TALKED_MESTONNAUX)) then
|
if (not data:GetFlag(FLAG_TALKED_MESTONNAUX)) then
|
||||||
callClientFunction(player, "delegateEvent", player, quest, "processEventMestonnauxSpeak");
|
callClientFunction(player, "delegateEvent", player, quest, "processEventMestonnauxSpeak");
|
||||||
quest:SetFlag(FLAG_TALKED_MESTONNAUX);
|
data:SetFlag(FLAG_TALKED_MESTONNAUX);
|
||||||
incCounter = true;
|
incCounter = true;
|
||||||
else
|
else
|
||||||
callClientFunction(player, "delegateEvent", player, quest, "processEventMestonnauxSpeakAfter");
|
callClientFunction(player, "delegateEvent", player, quest, "processEventMestonnauxSpeakAfter");
|
||||||
end
|
end
|
||||||
elseif (npcClassId == LEFWYNE) then
|
elseif (npcClassId == LEFWYNE) then
|
||||||
if (not quest:GetFlag(FLAG_TALKED_LEFWYNE)) then
|
if (not data:GetFlag(FLAG_TALKED_LEFWYNE)) then
|
||||||
callClientFunction(player, "delegateEvent", player, quest, "processEventLefwyneSpeak");
|
callClientFunction(player, "delegateEvent", player, quest, "processEventLefwyneSpeak");
|
||||||
quest:SetFlag(FLAG_TALKED_LEFWYNE);
|
data:SetFlag(FLAG_TALKED_LEFWYNE);
|
||||||
incCounter = true;
|
incCounter = true;
|
||||||
else
|
else
|
||||||
callClientFunction(player, "delegateEvent", player, quest, "processEventLefwyneSpeakAfter");
|
callClientFunction(player, "delegateEvent", player, quest, "processEventLefwyneSpeakAfter");
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Increase objective counter & play relevant messages
|
-- Increase objective counter & play relevant messages
|
||||||
if (incCounter == true) then
|
if (incCounter == true) then
|
||||||
quest:IncCounter(COUNTER_TALKED);
|
local counterAmount = data:IncCounter(COUNTER_TALKED);
|
||||||
local counterAmount = quest:GetCounter(COUNTER_TALKED);
|
|
||||||
|
|
||||||
attentionMessage(player, 51061, 0, counterAmount, 5); -- You have heard word of the Seedseers. (... of 5)
|
attentionMessage(player, 51061, 0, counterAmount, 5); -- You have heard word of the Seedseers. (... of 5)
|
||||||
|
|
||||||
if (seq000_checkCondition(quest)) then -- All Seers spoken to
|
if (seq000_checkCondition(data)) then -- All Seers spoken to
|
||||||
attentionMessage(player, 25225, 110674); -- "Seeing the Seers" objectives complete!
|
attentionMessage(player, 25225, 110674); -- "Seeing the Seers" objectives complete!
|
||||||
quest:UpdateENPCs(); -- Band-aid for a QFLAG_PLATE issue
|
quest:UpdateENPCs(); -- Band-aid for a QFLAG_PLATE issue
|
||||||
quest:StartSequence(SEQ_001);
|
quest:StartSequence(SEQ_001);
|
||||||
|
@ -134,7 +146,7 @@ function onTalk(player, quest, npc, eventName)
|
||||||
if (npcClassId == KINNISON) then
|
if (npcClassId == KINNISON) then
|
||||||
callClientFunction(player, "delegateEvent", player, quest, "processEventClear");
|
callClientFunction(player, "delegateEvent", player, quest, "processEventClear");
|
||||||
callClientFunction(player, "delegateEvent", player, quest, "sqrwa", 200, 1, 1, 9);
|
callClientFunction(player, "delegateEvent", player, quest, "sqrwa", 200, 1, 1, 9);
|
||||||
player:CompleteQuest(quest:GetQuestId());
|
player:CompleteQuest(quest);
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
quest:UpdateENPCs();
|
quest:UpdateENPCs();
|
||||||
|
@ -143,12 +155,12 @@ end
|
||||||
|
|
||||||
|
|
||||||
-- Check if all seers are talked to
|
-- Check if all seers are talked to
|
||||||
function seq000_checkCondition(quest)
|
function seq000_checkCondition(data)
|
||||||
return (quest:GetFlag(FLAG_TALKED_SYBELL) and
|
return (data:GetFlag(FLAG_TALKED_SYBELL) and
|
||||||
quest:GetFlag(FLAG_TALKED_KHUMA_MOSHROCA) and
|
data:GetFlag(FLAG_TALKED_KHUMA_MOSHROCA) and
|
||||||
quest:GetFlag(FLAG_TALKED_NELLAURE) and
|
data:GetFlag(FLAG_TALKED_NELLAURE) and
|
||||||
quest:GetFlag(FLAG_TALKED_MESTONNAUX) and
|
data:GetFlag(FLAG_TALKED_MESTONNAUX) and
|
||||||
quest:GetFlag(FLAG_TALKED_LEFWYNE));
|
data:GetFlag(FLAG_TALKED_LEFWYNE));
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -157,11 +169,11 @@ function getJournalMapMarkerList(player, quest)
|
||||||
local possibleMarkers = {};
|
local possibleMarkers = {};
|
||||||
|
|
||||||
if (sequence == SEQ_000) then
|
if (sequence == SEQ_000) then
|
||||||
if (not quest:GetFlag(FLAG_TALKED_SYBELL)) then table.insert(possibleMarkers, MRKR_SYBELL); end
|
if (not data:GetFlag(FLAG_TALKED_SYBELL)) then table.insert(possibleMarkers, MRKR_SYBELL); end
|
||||||
if (not quest:GetFlag(FLAG_TALKED_KHUMA_MOSHROCA)) then table.insert(possibleMarkers, MRKR_KHUMA_MOSHROCA); end
|
if (not data:GetFlag(FLAG_TALKED_KHUMA_MOSHROCA)) then table.insert(possibleMarkers, MRKR_KHUMA_MOSHROCA); end
|
||||||
if (not quest:GetFlag(FLAG_TALKED_NELLAURE)) then table.insert(possibleMarkers, MRKR_NELLAURE); end
|
if (not data:GetFlag(FLAG_TALKED_NELLAURE)) then table.insert(possibleMarkers, MRKR_NELLAURE); end
|
||||||
if (not quest:GetFlag(FLAG_TALKED_MESTONNAUX)) then table.insert(possibleMarkers, MRKR_MESTONNAUX); end
|
if (not data:GetFlag(FLAG_TALKED_MESTONNAUX)) then table.insert(possibleMarkers, MRKR_MESTONNAUX); end
|
||||||
if (not quest:GetFlag(FLAG_TALKED_LEFWYNE)) then table.insert(possibleMarkers, MRKR_LEFWYNE); end
|
if (not data:GetFlag(FLAG_TALKED_LEFWYNE)) then table.insert(possibleMarkers, MRKR_LEFWYNE); end
|
||||||
elseif (sequence == SEQ_001) then
|
elseif (sequence == SEQ_001) then
|
||||||
table.insert(possibleMarkers, MRKR_KINNISON);
|
table.insert(possibleMarkers, MRKR_KINNISON);
|
||||||
end
|
end
|
||||||
|
|
|
@ -40,13 +40,13 @@ end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function onSequence(player, quest, sequence)
|
function onStateChange(player, quest, sequence)
|
||||||
if (sequence == SEQ_000) then
|
if (sequence == SEQ_000) then
|
||||||
quest:AddENpc(VKOROLON);
|
quest:SetENpc(VKOROLON);
|
||||||
quest:AddENpc(PFARAHR, QFLAG_PLATE);
|
quest:SetENpc(PFARAHR, QFLAG_PLATE);
|
||||||
elseif (sequence == SEQ_001) then
|
elseif (sequence == SEQ_001) then
|
||||||
quest:AddENpc(VKOROLON, QFLAG_PLATE);
|
quest:SetENpc(VKOROLON, QFLAG_PLATE);
|
||||||
quest:AddENpc(PFARAHR);
|
quest:SetENpc(PFARAHR);
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,7 @@ end
|
||||||
function onFinish(player, quest)
|
function onFinish(player, quest)
|
||||||
end
|
end
|
||||||
|
|
||||||
function onSequence(player, quest, sequence)
|
function onStateChange(player, quest, sequence)
|
||||||
if (sequence == SEQ_000) then
|
if (sequence == SEQ_000) then
|
||||||
-- Setup states incase we loaded in.
|
-- Setup states incase we loaded in.
|
||||||
local rostnsthalFlag = quest:GetFlag(FLAG_SEQ000_MINITUT1) and QFLAG_NONE or QFLAG_PLATE;
|
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 exitCanPush = quest:GetFlags() == 0xF;
|
||||||
local exitFlag = quest:GetFlags() == 0xF and QFLAG_MAP or QFLAG_NONE;
|
local exitFlag = quest:GetFlags() == 0xF and QFLAG_MAP or QFLAG_NONE;
|
||||||
|
|
||||||
quest:AddENpc(WELLTRAVELED_MERCHANT);
|
quest:SetENpc(WELLTRAVELED_MERCHANT);
|
||||||
quest:AddENpc(TIPSY_ADVENTURER);
|
quest:SetENpc(TIPSY_ADVENTURER);
|
||||||
quest:AddENpc(CULTIVATED_TENDER);
|
quest:SetENpc(CULTIVATED_TENDER);
|
||||||
quest:AddENpc(ANXIOUS_ADVENTURER);
|
quest:SetENpc(ANXIOUS_ADVENTURER);
|
||||||
quest:AddENpc(BABYFACED_ADVENTURER, babyfaceFlag);
|
quest:SetENpc(BABYFACED_ADVENTURER, babyfaceFlag);
|
||||||
quest:AddENpc(AUSTERE_ADVENTURER);
|
quest:SetENpc(AUSTERE_ADVENTURER);
|
||||||
quest:AddENpc(UNDIGNIFIED_ADVENTURER);
|
quest:SetENpc(UNDIGNIFIED_ADVENTURER);
|
||||||
quest:AddENpc(SHADOWY_TRAVELER);
|
quest:SetENpc(SHADOWY_TRAVELER);
|
||||||
quest:AddENpc(ASTUTE_MERCHANT);
|
quest:SetENpc(ASTUTE_MERCHANT);
|
||||||
quest:AddENpc(VOLUPTUOUS_VIXEN, vixenFlag);
|
quest:SetENpc(VOLUPTUOUS_VIXEN, vixenFlag);
|
||||||
quest:AddENpc(INDIFFERENT_PASSERBY);
|
quest:SetENpc(INDIFFERENT_PASSERBY);
|
||||||
quest:AddENpc(PRATTLING_ADVENTURER);
|
quest:SetENpc(PRATTLING_ADVENTURER);
|
||||||
quest:AddENpc(LANKY_TRAVELER);
|
quest:SetENpc(LANKY_TRAVELER);
|
||||||
quest:AddENpc(GRINNING_ADVENTURER);
|
quest:SetENpc(GRINNING_ADVENTURER);
|
||||||
quest:AddENpc(ROSTNSTHAL, rostnsthalFlag, true, rostnsthalCanPush);
|
quest:SetENpc(ROSTNSTHAL, rostnsthalFlag, true, rostnsthalCanPush);
|
||||||
quest:AddENpc(EXIT_TRIGGER, exitFlag, false, exitCanPush);
|
quest:SetENpc(EXIT_TRIGGER, exitFlag, false, exitCanPush);
|
||||||
elseif (sequence == SEQ_005) then
|
elseif (sequence == SEQ_005) then
|
||||||
elseif (sequence == SEQ_010) then
|
elseif (sequence == SEQ_010) then
|
||||||
quest:AddENpc(HOB);
|
quest:SetENpc(HOB);
|
||||||
quest:AddENpc(GERT);
|
quest:SetENpc(GERT);
|
||||||
quest:AddENpc(LORHZANT);
|
quest:SetENpc(LORHZANT);
|
||||||
quest:AddENpc(MUSCLEBOUND_DECKHAND);
|
quest:SetENpc(MUSCLEBOUND_DECKHAND);
|
||||||
quest:AddENpc(PEARLYTOOTHED_PORTER);
|
quest:SetENpc(PEARLYTOOTHED_PORTER);
|
||||||
quest:AddENpc(UNDIGNIFIED_ADVENTURER);
|
quest:SetENpc(UNDIGNIFIED_ADVENTURER);
|
||||||
quest:AddENpc(WELLTRAVELED_MERCHANT);
|
quest:SetENpc(WELLTRAVELED_MERCHANT);
|
||||||
quest:AddENpc(VOLUPTUOUS_VIXEN);
|
quest:SetENpc(VOLUPTUOUS_VIXEN);
|
||||||
quest:AddENpc(LANKY_TRAVELER);
|
quest:SetENpc(LANKY_TRAVELER);
|
||||||
quest:AddENpc(PRIVAREA_PAST_EXIT, QFLAG_NONE, false, true);
|
quest:SetENpc(PRIVAREA_PAST_EXIT, QFLAG_NONE, false, true);
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -85,56 +85,56 @@ end
|
||||||
function onFinish(player, quest)
|
function onFinish(player, quest)
|
||||||
end
|
end
|
||||||
|
|
||||||
function onSequence(player, quest, sequence)
|
function onStateChange(player, quest, sequence)
|
||||||
|
|
||||||
if (sequence == SEQ_000) then
|
if (sequence == SEQ_000) then
|
||||||
quest:AddENpc(YSHTOLA);
|
quest:SetENpc(YSHTOLA);
|
||||||
quest:AddENpc(CRAPULOUS_ADVENTURER);
|
quest:SetENpc(CRAPULOUS_ADVENTURER);
|
||||||
quest:AddENpc(DUPLICITOUS_TRADER);
|
quest:SetENpc(DUPLICITOUS_TRADER);
|
||||||
quest:AddENpc(DEBONAIR_PIRATE);
|
quest:SetENpc(DEBONAIR_PIRATE);
|
||||||
quest:AddENpc(ONYXHAIRED_ADVENTURER);
|
quest:SetENpc(ONYXHAIRED_ADVENTURER);
|
||||||
quest:AddENpc(SKITTISH_ADVENTURER);
|
quest:SetENpc(SKITTISH_ADVENTURER);
|
||||||
quest:AddENpc(RELAXING_ADVENTURER);
|
quest:SetENpc(RELAXING_ADVENTURER);
|
||||||
quest:AddENpc(BADERON, QFLAG_PLATE);
|
quest:SetENpc(BADERON, QFLAG_PLATE);
|
||||||
quest:AddENpc(MYTESYN);
|
quest:SetENpc(MYTESYN);
|
||||||
quest:AddENpc(COCKAHOOP_COCKSWAIN);
|
quest:SetENpc(COCKAHOOP_COCKSWAIN);
|
||||||
quest:AddENpc(SENTENIOUS_SELLSWORD);
|
quest:SetENpc(SENTENIOUS_SELLSWORD);
|
||||||
quest:AddENpc(SOLICITOUS_SELLSWORD);
|
quest:SetENpc(SOLICITOUS_SELLSWORD);
|
||||||
elseif (sequence == SEQ_003) then
|
elseif (sequence == SEQ_003) then
|
||||||
quest:AddENpc(BADERON);
|
quest:SetENpc(BADERON);
|
||||||
elseif (sequence == SEQ_005) then
|
elseif (sequence == SEQ_005) then
|
||||||
quest:AddENpc(BADERON, QFLAG_PLATE);
|
quest:SetENpc(BADERON, QFLAG_PLATE);
|
||||||
elseif (sequence == SEQ_006) then
|
elseif (sequence == SEQ_006) then
|
||||||
quest:AddENpc(BADERON, QFLAG_PLATE);
|
quest:SetENpc(BADERON, QFLAG_PLATE);
|
||||||
elseif (sequence == SEQ_007) then
|
elseif (sequence == SEQ_007) then
|
||||||
local subseqCUL = quest:GetCounter(CNTR_SEQ7_CUL);
|
local subseqCUL = quest:GetCounter(CNTR_SEQ7_CUL);
|
||||||
local subseqMRD = quest:GetCounter(CNTR_SEQ7_MRD);
|
local subseqMRD = quest:GetCounter(CNTR_SEQ7_MRD);
|
||||||
|
|
||||||
-- Always active in this seqence
|
-- Always active in this seqence
|
||||||
quest:AddENpc(BADERON);
|
quest:SetENpc(BADERON);
|
||||||
quest:AddENpc(CHARLYS, subseqCUL == 0 and QFLAG_PLATE or QFLAG_NONE);
|
quest:SetENpc(CHARLYS, subseqCUL == 0 and QFLAG_PLATE or QFLAG_NONE);
|
||||||
|
|
||||||
-- Down and Up the MSK guild
|
-- 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
|
if (subseqMRD == 1) then
|
||||||
quest:AddENpc(MSK_TRIGGER, QFLAG_MAP, false, true);
|
quest:SetENpc(MSK_TRIGGER, QFLAG_MAP, false, true);
|
||||||
elseif (subseqMRD == 2) then
|
elseif (subseqMRD == 2) then
|
||||||
quest:AddENpc(MERLZIRN);
|
quest:SetENpc(MERLZIRN);
|
||||||
end
|
end
|
||||||
|
|
||||||
-- In Echo
|
-- In Echo
|
||||||
quest:AddENpc(NERVOUS_BARRACUDA);
|
quest:SetENpc(NERVOUS_BARRACUDA);
|
||||||
quest:AddENpc(INTIMIDATING_BARRACUDA);
|
quest:SetENpc(INTIMIDATING_BARRACUDA);
|
||||||
quest:AddENpc(OVEREAGER_BARRACUDA);
|
quest:SetENpc(OVEREAGER_BARRACUDA);
|
||||||
quest:AddENpc(SOPHISTICATED_BARRACUDA);
|
quest:SetENpc(SOPHISTICATED_BARRACUDA);
|
||||||
quest:AddENpc(SMIRKING_BARRACUDA);
|
quest:SetENpc(SMIRKING_BARRACUDA);
|
||||||
quest:AddENpc(MANNSKOEN);
|
quest:SetENpc(MANNSKOEN);
|
||||||
quest:AddENpc(TOTORUTO);
|
quest:SetENpc(TOTORUTO);
|
||||||
quest:AddENpc(ADVENTURER1);
|
quest:SetENpc(ADVENTURER1);
|
||||||
quest:AddENpc(ADVENTURER2);
|
quest:SetENpc(ADVENTURER2);
|
||||||
quest:AddENpc(ADVENTURER3);
|
quest:SetENpc(ADVENTURER3);
|
||||||
quest:AddENpc(ECHO_EXIT_TRIGGER, subseqMRD == 3 and QFLAG_MAP or QFLAG_NONE, false, subseqMRD == 3);
|
quest:SetENpc(ECHO_EXIT_TRIGGER, subseqMRD == 3 and QFLAG_MAP or QFLAG_NONE, false, subseqMRD == 3);
|
||||||
|
|
||||||
if (subseqCUL == 1 and subseqMRD == 4) then
|
if (subseqCUL == 1 and subseqMRD == 4) then
|
||||||
player:SetNpcLS(1, 1);
|
player:SetNpcLS(1, 1);
|
||||||
|
|
|
@ -103,7 +103,7 @@ end
|
||||||
function onFinish(player, quest)
|
function onFinish(player, quest)
|
||||||
end
|
end
|
||||||
|
|
||||||
function onSequence(player, quest, sequence)
|
function onStateChange(player, quest, sequence)
|
||||||
|
|
||||||
if (sequence == SEQ_000) then
|
if (sequence == SEQ_000) then
|
||||||
-- Setup states incase we loaded in.
|
-- Setup states incase we loaded in.
|
||||||
|
@ -119,34 +119,34 @@ function onSequence(player, quest, sequence)
|
||||||
gildiggingmistressFlag = QFLAG_NONE;
|
gildiggingmistressFlag = QFLAG_NONE;
|
||||||
end
|
end
|
||||||
|
|
||||||
--AddENpc(classId, byte flagType=0,isTalkEnabled, isPushEnabled, isEmoteEnabled, isSpawned)
|
--SetENpc(classId, byte flagType=0,isTalkEnabled, isPushEnabled, isEmoteEnabled, isSpawned)
|
||||||
quest:AddENpc(ASCILIA, asciliaFlag, true, asciliaCanPush);
|
quest:SetENpc(ASCILIA, asciliaFlag, true, asciliaCanPush);
|
||||||
quest:AddENpc(WARBURTON);
|
quest:SetENpc(WARBURTON);
|
||||||
quest:AddENpc(RURURAJI);
|
quest:SetENpc(RURURAJI);
|
||||||
quest:AddENpc(BIG_BELLIED_BARKER);
|
quest:SetENpc(BIG_BELLIED_BARKER);
|
||||||
quest:AddENpc(FRETFUL_FARMHAND, fretfulfarmhandFlag);
|
quest:SetENpc(FRETFUL_FARMHAND, fretfulfarmhandFlag);
|
||||||
quest:AddENpc(DEBAUCHED_DEMONESS);
|
quest:SetENpc(DEBAUCHED_DEMONESS);
|
||||||
quest:AddENpc(DAPPER_DAN);
|
quest:SetENpc(DAPPER_DAN);
|
||||||
quest:AddENpc(LOUTISH_LAD);
|
quest:SetENpc(LOUTISH_LAD);
|
||||||
quest:AddENpc(GIL_DIGGING_MISTRESS, gildiggingmistressFlag);
|
quest:SetENpc(GIL_DIGGING_MISTRESS, gildiggingmistressFlag);
|
||||||
quest:AddENpc(TWITTERING_TOMBOY);
|
quest:SetENpc(TWITTERING_TOMBOY);
|
||||||
quest:AddENpc(STOCKY_STRANGER);
|
quest:SetENpc(STOCKY_STRANGER);
|
||||||
quest:AddENpc(EXIT_TRIGGER, exitFlag, false, true);
|
quest:SetENpc(EXIT_TRIGGER, exitFlag, false, true);
|
||||||
quest:AddENpc(OPENING_STOPER_ULDAH, QFLAG_NONE, false, false, true);
|
quest:SetENpc(OPENING_STOPER_ULDAH, QFLAG_NONE, false, false, true);
|
||||||
|
|
||||||
elseif (sequence == SEQ_010) then
|
elseif (sequence == SEQ_010) then
|
||||||
local yayatokiFlag = quest:GetFlag(FLAG_SEQ010_TALK0) and QFLAG_NONE or QFLAG_PLATE;
|
local yayatokiFlag = quest:GetFlag(FLAG_SEQ010_TALK0) and QFLAG_NONE or QFLAG_PLATE;
|
||||||
local uldahopeningexitFlag = QFLAG_MAP;
|
local uldahopeningexitFlag = QFLAG_MAP;
|
||||||
quest:AddENpc(KEEN_EYED_MERCHANT);
|
quest:SetENpc(KEEN_EYED_MERCHANT);
|
||||||
quest:AddENpc(HIGH_SPIRITED_FELLOW);
|
quest:SetENpc(HIGH_SPIRITED_FELLOW);
|
||||||
quest:AddENpc(DISREPUTABLE_MIDLANDER);
|
quest:SetENpc(DISREPUTABLE_MIDLANDER);
|
||||||
quest:AddENpc(LONG_LEGGED_LADY);
|
quest:SetENpc(LONG_LEGGED_LADY);
|
||||||
quest:AddENpc(LARGE_LUNGED_LABORER);
|
quest:SetENpc(LARGE_LUNGED_LABORER);
|
||||||
quest:AddENpc(TOOTH_GRINDING_TRAVELER);
|
quest:SetENpc(TOOTH_GRINDING_TRAVELER);
|
||||||
quest:AddENpc(FULL_LIPPED_FILLE);
|
quest:SetENpc(FULL_LIPPED_FILLE);
|
||||||
quest:AddENpc(YAYATOKI, yayatokiFlag);
|
quest:SetENpc(YAYATOKI, yayatokiFlag);
|
||||||
quest:AddENpc(BLOCKER, QFLAG_NONE, false, true);
|
quest:SetENpc(BLOCKER, QFLAG_NONE, false, true);
|
||||||
quest:AddENpc(ULDAH_OPENING_EXIT, uldahopeningexitFlag, false, true);
|
quest:SetENpc(ULDAH_OPENING_EXIT, uldahopeningexitFlag, false, true);
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -127,17 +127,17 @@ end
|
||||||
function onFinish(player, quest)
|
function onFinish(player, quest)
|
||||||
end
|
end
|
||||||
|
|
||||||
function onSequence(player, quest, sequence)
|
function onStateChange(player, quest, sequence)
|
||||||
|
|
||||||
if (sequence == SEQ_000) then
|
if (sequence == SEQ_000) then
|
||||||
-- Setup states incase we loaded in.
|
-- Setup states incase we loaded in.
|
||||||
|
|
||||||
--AddENpc(classId, byte flagType=0,isTalkEnabled, isPushEnabled, isEmoteEnabled, isSpawned)
|
--SetENpc(classId, byte flagType=0,isTalkEnabled, isPushEnabled, isEmoteEnabled, isSpawned)
|
||||||
quest:AddENpc(MOMODI, QFLAG_PLATE);
|
quest:SetENpc(MOMODI, QFLAG_PLATE);
|
||||||
quest:AddENpc(OTOPA_POTTOPA);
|
quest:SetENpc(OTOPA_POTTOPA);
|
||||||
|
|
||||||
elseif (sequence == SEQ_005) then
|
elseif (sequence == SEQ_005) then
|
||||||
quest:AddENpc(MOMODI);
|
quest:SetENpc(MOMODI);
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ end
|
||||||
function onFinish(player, quest)
|
function onFinish(player, quest)
|
||||||
end
|
end
|
||||||
|
|
||||||
function onSequence(player, quest, seqNum)
|
function onStateChange(player, quest, seqNum)
|
||||||
quest:ClearENpcs();
|
quest:ClearENpcs();
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -1,51 +1,29 @@
|
||||||
-- MySQL dump 10.13 Distrib 5.7.10, for Win64 (x86_64)
|
-- --------------------------------------------------------
|
||||||
--
|
-- Host: 127.0.0.1
|
||||||
-- Host: localhost Database: ffxiv_database
|
-- Server version: 5.6.17 - MySQL Community Server (GPL)
|
||||||
-- ------------------------------------------------------
|
-- Server OS: Win64
|
||||||
-- Server version 5.7.10-log
|
-- HeidiSQL Version: 10.1.0.5464
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||||
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
|
||||||
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
|
||||||
/*!40101 SET NAMES utf8 */;
|
/*!40101 SET NAMES utf8 */;
|
||||||
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
|
/*!50503 SET NAMES utf8mb4 */;
|
||||||
/*!40103 SET TIME_ZONE='+00:00' */;
|
|
||||||
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
|
|
||||||
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
|
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
|
||||||
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
|
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
|
||||||
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
|
|
||||||
|
|
||||||
--
|
|
||||||
-- Table structure for table `characters_quest_completed`
|
|
||||||
--
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS `characters_quest_completed`;
|
-- Dumping database structure for ffxiv_server
|
||||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
CREATE DATABASE IF NOT EXISTS `ffxiv_server` /*!40100 DEFAULT CHARACTER SET latin1 */;
|
||||||
/*!40101 SET character_set_client = utf8 */;
|
USE `ffxiv_server`;
|
||||||
CREATE TABLE `characters_quest_completed` (
|
|
||||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
-- Dumping structure for table ffxiv_server.characters_quest_completed
|
||||||
|
CREATE TABLE IF NOT EXISTS `characters_quest_completed` (
|
||||||
`characterId` int(10) unsigned NOT NULL,
|
`characterId` int(10) unsigned NOT NULL,
|
||||||
`questId` int(10) unsigned NOT NULL,
|
`completedQuests` varbinary(2048) DEFAULT NULL,
|
||||||
PRIMARY KEY (`id`)
|
PRIMARY KEY (`characterId`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
|
||||||
|
|
||||||
--
|
-- Data exporting was unselected.
|
||||||
-- Dumping data for table `characters_quest_completed`
|
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
|
||||||
--
|
/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */;
|
||||||
|
|
||||||
LOCK TABLES `characters_quest_completed` WRITE;
|
|
||||||
/*!40000 ALTER TABLE `characters_quest_completed` DISABLE KEYS */;
|
|
||||||
/*!40000 ALTER TABLE `characters_quest_completed` ENABLE KEYS */;
|
|
||||||
UNLOCK TABLES;
|
|
||||||
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
|
|
||||||
|
|
||||||
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
|
||||||
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
|
|
||||||
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
|
|
||||||
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||||
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
|
||||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
|
||||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
|
||||||
|
|
||||||
-- Dump completed on 2016-06-07 22:54:47
|
|
||||||
|
|
560
Data/sql/gamedata_quests.sql
Normal file
560
Data/sql/gamedata_quests.sql
Normal file
|
@ -0,0 +1,560 @@
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
-- Host: 127.0.0.1
|
||||||
|
-- Server version: 5.6.17 - MySQL Community Server (GPL)
|
||||||
|
-- Server OS: Win64
|
||||||
|
-- HeidiSQL Version: 10.1.0.5464
|
||||||
|
-- --------------------------------------------------------
|
||||||
|
|
||||||
|
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||||
|
/*!40101 SET NAMES utf8 */;
|
||||||
|
/*!50503 SET NAMES utf8mb4 */;
|
||||||
|
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
|
||||||
|
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
|
||||||
|
|
||||||
|
|
||||||
|
-- Dumping database structure for ffxiv_server
|
||||||
|
CREATE DATABASE IF NOT EXISTS `ffxiv_server` /*!40100 DEFAULT CHARACTER SET latin1 */;
|
||||||
|
USE `ffxiv_server`;
|
||||||
|
|
||||||
|
-- Dumping structure for table ffxiv_server.gamedata_quests
|
||||||
|
DROP TABLE IF EXISTS `gamedata_quests`;
|
||||||
|
CREATE TABLE IF NOT EXISTS `gamedata_quests` (
|
||||||
|
`id` int(11) unsigned NOT NULL,
|
||||||
|
`questName` varchar(50) NOT NULL,
|
||||||
|
`className` varchar(10) NOT NULL,
|
||||||
|
`prerequisite` int(11) unsigned NOT NULL,
|
||||||
|
`minLevel` smallint(5) unsigned NOT NULL
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||||
|
|
||||||
|
-- Dumping data for table ffxiv_server.gamedata_quests: ~524 rows (approximately)
|
||||||
|
/*!40000 ALTER TABLE `gamedata_quests` DISABLE KEYS */;
|
||||||
|
REPLACE INTO `gamedata_quests` (`id`, `questName`, `className`, `prerequisite`, `minLevel`) VALUES
|
||||||
|
(110001, 'Shapeless Melody', 'Man0l0', 0, 1),
|
||||||
|
(110002, 'Treasures of the Main', 'Man0l1', 0, 1),
|
||||||
|
(110003, 'Legends Adrift', 'Man1l0', 0, 8),
|
||||||
|
(110004, 'Never the Twain Shall Meet', 'Man2l0', 0, 13),
|
||||||
|
(110005, 'Sundered Skies', 'Man0g0', 0, 1),
|
||||||
|
(110006, 'Souls Gone Wild', 'Man0g1', 0, 1),
|
||||||
|
(110007, 'Whispers in the Wood', 'Man1g0', 0, 8),
|
||||||
|
(110008, 'Beckon of the Elementals', 'Man2g0', 0, 13),
|
||||||
|
(110009, 'Flowers for All', 'Man0u0', 0, 1),
|
||||||
|
(110010, 'Court in the Sands', 'Man0u1', 0, 1),
|
||||||
|
(110011, 'Golden Sacrifices', 'Man1u0', 0, 8),
|
||||||
|
(110012, 'Calamity Cometh', 'Man2u0', 0, 13),
|
||||||
|
(110013, 'Fade to White', 'Man200', 0, 18),
|
||||||
|
(110014, 'Together We Stand', 'Man206', 0, 22),
|
||||||
|
(110015, 'Toll of the Warden', 'Man300', 0, 30),
|
||||||
|
(110016, 'Forever Taken', 'Man304', 0, 34),
|
||||||
|
(110017, 'Lord Errant', 'Man308', 0, 38),
|
||||||
|
(110018, 'Of Men They Sing', 'Man402', 0, 42),
|
||||||
|
(110019, 'Futures Perfect', 'Man406', 0, 46),
|
||||||
|
(110020, '[en]', 'Man502', 0, 52),
|
||||||
|
(110021, '[en]', 'Man504', 0, 54),
|
||||||
|
(110060, 'The House Always Wins', 'Pgl200', 0, 20),
|
||||||
|
(110061, 'Here There Be Pirates', 'Pgl300', 0, 30),
|
||||||
|
(110062, 'Two Sides to Every Chip', 'Pgl306', 0, 36),
|
||||||
|
(110063, '[en]', 'Pgl400', 0, 40),
|
||||||
|
(110080, 'All Bark and No Bite', 'Gla200', 0, 20),
|
||||||
|
(110081, 'Unalienable Rights', 'Gla300', 0, 30),
|
||||||
|
(110082, 'Thrill of the Fight', 'Gla306', 0, 36),
|
||||||
|
(110083, '[en]', 'Gla400', 0, 40),
|
||||||
|
(110100, 'Bloody Baptism', 'Exc200', 0, 20),
|
||||||
|
(110101, 'Two-man Crew', 'Exc300', 0, 30),
|
||||||
|
(110102, 'Captain\'s Orders', 'Exc306', 0, 36),
|
||||||
|
(110103, '[en]', 'Exc400', 0, 40),
|
||||||
|
(110104, '[en]', 'Exc500', 0, 50),
|
||||||
|
(110105, '[en]', 'Exc506', 0, 56),
|
||||||
|
(110140, 'Getting Started', 'Trl0l1', 0, 20),
|
||||||
|
(110141, 'Getting Started', 'Trl0g1', 0, 30),
|
||||||
|
(110142, '[en]', 'Trl0u1', 0, 36),
|
||||||
|
(110143, '[en]', 'Trl0l2', 0, 20),
|
||||||
|
(110144, 'Selecting a Different Path Companion', 'Trl0l3', 0, 50),
|
||||||
|
(110145, '[en]', 'Trl0l4', 0, 56),
|
||||||
|
(110160, 'Filling the Quiver', 'Arc200', 0, 20),
|
||||||
|
(110161, 'The Foreboding Forest', 'Arc300', 110160, 30),
|
||||||
|
(110162, 'There Can Be Only One', 'Arc306', 110161, 36),
|
||||||
|
(110163, '[en]', 'Arc400', 0, 40),
|
||||||
|
(110164, '[en]', 'Arc500', 0, 50),
|
||||||
|
(110165, '[en]', 'Arc506', 0, 56),
|
||||||
|
(110180, 'A Wailing Welcome', 'Lnc200', 0, 20),
|
||||||
|
(110181, 'Culture Shock', 'Lnc300', 110180, 30),
|
||||||
|
(110182, 'Necessary Evils', 'Lnc306', 110181, 36),
|
||||||
|
(110183, '[en]', 'Lnc400', 0, 40),
|
||||||
|
(110184, '[en]', 'Lnc500', 0, 50),
|
||||||
|
(110185, '[en]', 'Lnc506', 0, 56),
|
||||||
|
(110240, 'The Big Payback', 'Thm200', 0, 20),
|
||||||
|
(110241, 'Revelry in Rivalry', 'Thm300', 0, 30),
|
||||||
|
(110242, 'Law and the Order', 'Thm306', 0, 36),
|
||||||
|
(110243, '[en]', 'Thm400', 0, 40),
|
||||||
|
(110260, 'Dendrological Duties', 'Cnj200', 0, 20),
|
||||||
|
(110261, 'Good Knight, Sweet Dreams', 'Cnj300', 110260, 30),
|
||||||
|
(110262, 'The Call of Nature', 'Cnj306', 110261, 36),
|
||||||
|
(110263, '[en]', 'Cnj400', 0, 40),
|
||||||
|
(110264, '[en]', 'Cnj500', 0, 50),
|
||||||
|
(110265, '[en]', 'Cnj506', 0, 56),
|
||||||
|
(110280, '[en]', 'Acn200', 0, 20),
|
||||||
|
(110281, '[en]', 'Acn300', 0, 30),
|
||||||
|
(110282, '[en]', 'Acn306', 0, 36),
|
||||||
|
(110283, '[en]', 'Acn400', 0, 40),
|
||||||
|
(110284, '[en]', 'Acn500', 0, 50),
|
||||||
|
(110285, '[en]', 'Acn506', 0, 56),
|
||||||
|
(110300, 'The Mouths of Babes', 'Wdk200', 0, 20),
|
||||||
|
(110301, 'Hide and Seek Shenanigans', 'Wdk300', 110300, 30),
|
||||||
|
(110302, 'Spanning the Spectrum', 'Wdk306', 110301, 36),
|
||||||
|
(110303, '[en]', 'Wdk400', 0, 40),
|
||||||
|
(110304, '[en]', 'Wdk500', 0, 50),
|
||||||
|
(110305, '[en]', 'Wdk506', 0, 56),
|
||||||
|
(110320, 'An Ear for Quality', 'Bsm200', 0, 20),
|
||||||
|
(110321, 'Song of the Sirens', 'Bsm300', 0, 30),
|
||||||
|
(110322, 'The Sound of Silence', 'Bsm306', 0, 36),
|
||||||
|
(110323, '[en]', 'Bsm400', 0, 40),
|
||||||
|
(110324, '[en]', 'Bsm500', 0, 50),
|
||||||
|
(110325, '[en]', 'Bsm506', 0, 56),
|
||||||
|
(110360, 'She Walks in Beauty', 'Gld200', 0, 20),
|
||||||
|
(110361, 'F\'lhaminn\'s Flower', 'Gld300', 0, 30),
|
||||||
|
(110362, 'Struck Through the Heart', 'Gld306', 0, 36),
|
||||||
|
(110363, '[en]', 'Gld400', 0, 40),
|
||||||
|
(110364, '[en]', 'Gld500', 0, 50),
|
||||||
|
(110365, '[en]', 'Gld506', 0, 56),
|
||||||
|
(110380, 'The Silent Partners', 'Tan200', 0, 20),
|
||||||
|
(110381, 'Design Imposters', 'Tan300', 110380, 30),
|
||||||
|
(110382, 'Head of the Class', 'Tan306', 110381, 36),
|
||||||
|
(110383, '[en]', 'Tan400', 0, 40),
|
||||||
|
(110384, '[en]', 'Tan500', 0, 50),
|
||||||
|
(110385, '[en]', 'Tan506', 0, 56),
|
||||||
|
(110400, 'Hoodwinked', 'Wvr200', 0, 20),
|
||||||
|
(110401, 'Dance the Night Away', 'Wvr300', 0, 30),
|
||||||
|
(110402, 'A Fruitful Murder', 'Wvr306', 0, 36),
|
||||||
|
(110403, '[en]', 'Wvr400', 0, 40),
|
||||||
|
(110404, '[en]', 'Wvr500', 0, 50),
|
||||||
|
(110405, '[en]', 'Wvr506', 0, 56),
|
||||||
|
(110420, 'Sleep, Cousin of Death', 'Alc200', 0, 20),
|
||||||
|
(110421, 'The Boy and the Dragon Gay', 'Alc300', 110420, 30),
|
||||||
|
(110422, 'Dream On, Dream Away', 'Alc306', 110421, 36),
|
||||||
|
(110423, '[en]', 'Alc400', 0, 40),
|
||||||
|
(110424, '[en]', 'Alc500', 0, 50),
|
||||||
|
(110425, '[en]', 'Alc506', 0, 56),
|
||||||
|
(110440, 'Showdown', 'Cul200', 0, 20),
|
||||||
|
(110441, 'Mystery of the Gastronome Gone Home', 'Cul300', 0, 30),
|
||||||
|
(110442, 'Something in the Soup', 'Cul306', 0, 36),
|
||||||
|
(110443, '[en]', 'Cul400', 0, 40),
|
||||||
|
(110444, '[en]', 'Cul500', 0, 50),
|
||||||
|
(110445, '[en]', 'Cul506', 0, 56),
|
||||||
|
(110460, 'A Piece of History', 'Min200', 0, 20),
|
||||||
|
(110461, 'Little Saboteurs', 'Min300', 0, 30),
|
||||||
|
(110462, 'Runaway Little Girl', 'Min306', 0, 36),
|
||||||
|
(110463, '[en]', 'Min400', 0, 40),
|
||||||
|
(110464, '[en]', 'Min500', 0, 50),
|
||||||
|
(110465, '[en]', 'Min506', 0, 56),
|
||||||
|
(110480, 'Gridanian Roots', 'Hrv200', 0, 20),
|
||||||
|
(110481, 'The Grass is Always Greener', 'Hrv300', 110480, 30),
|
||||||
|
(110482, 'A Moogle Bouquet', 'Hrv306', 110481, 36),
|
||||||
|
(110483, '[en]', 'Hrv400', 0, 40),
|
||||||
|
(110484, '[en]', 'Hrv500', 0, 50),
|
||||||
|
(110485, '[en]', 'Hrv506', 0, 56),
|
||||||
|
(110500, 'To Fight a Fishback', 'Fsh200', 0, 20),
|
||||||
|
(110501, 'The Beast of the Barrel', 'Fsh300', 0, 30),
|
||||||
|
(110502, 'Polishing the Mast', 'Fsh306', 0, 36),
|
||||||
|
(110503, '[en]', 'Fsh400', 0, 40),
|
||||||
|
(110504, '[en]', 'Fsh500', 0, 50),
|
||||||
|
(110505, '[en]', 'Fsh506', 0, 56),
|
||||||
|
(110540, 'Small Talk', 'Dftsea', 0, 0),
|
||||||
|
(110541, 'Small Talk', 'Dftfst', 0, 0),
|
||||||
|
(110542, 'Small Talk', 'Dftroc', 0, 0),
|
||||||
|
(110543, 'Small Talk', 'Dftwil', 0, 0),
|
||||||
|
(110544, 'Small Talk', 'Dftsrt', 0, 0),
|
||||||
|
(110545, 'Small Talk', 'Dftlak', 0, 0),
|
||||||
|
(110600, '[en]', 'Etc0l1', 0, 0),
|
||||||
|
(110601, '[en]', 'Etc0l2', 0, 0),
|
||||||
|
(110602, '[en]', 'Etc0l3', 0, 0),
|
||||||
|
(110603, '[en]', 'Etc0l4', 0, 0),
|
||||||
|
(110604, '[en]', 'Etc0l5', 0, 0),
|
||||||
|
(110605, '[en]', 'Etc0l6', 0, 0),
|
||||||
|
(110606, '[en]', 'Etc0l7', 0, 0),
|
||||||
|
(110607, '[en]', 'Etc0l8', 0, 0),
|
||||||
|
(110608, '[en]', 'Etc0l9', 0, 0),
|
||||||
|
(110609, '[en]', 'Etc0g1', 0, 0),
|
||||||
|
(110610, '[en]', 'Etc0g2', 0, 0),
|
||||||
|
(110611, '[en]', 'Etc0g3', 0, 0),
|
||||||
|
(110612, '[en]', 'Etc0g4', 0, 0),
|
||||||
|
(110613, '[en]', 'Etc0g5', 0, 0),
|
||||||
|
(110614, '[en]', 'Etc0g6', 0, 0),
|
||||||
|
(110615, '[en]', 'Etc0g7', 0, 0),
|
||||||
|
(110616, '[en]', 'Etc0g8', 0, 0),
|
||||||
|
(110617, '[en]', 'Etc0g9', 0, 0),
|
||||||
|
(110618, '[en]', 'Etc0u1', 0, 0),
|
||||||
|
(110619, '[en]', 'Etc0u2', 0, 0),
|
||||||
|
(110620, '[en]', 'Etc0u3', 0, 0),
|
||||||
|
(110621, '[en]', 'Etc0u4', 0, 0),
|
||||||
|
(110622, '[en]', 'Etc0u5', 0, 0),
|
||||||
|
(110623, '[en]', 'Etc0u6', 0, 0),
|
||||||
|
(110624, '[en]', 'Etc0u7', 0, 0),
|
||||||
|
(110625, '[en]', 'Etc0u8', 0, 0),
|
||||||
|
(110626, '[en]', 'Etc0u9', 0, 0),
|
||||||
|
(110627, 'Ifrit Bleeds, We Can Kill It', 'Sum6a0', 0, 45),
|
||||||
|
(110628, '[en]', 'Sum7l0', 0, 0),
|
||||||
|
(110629, '[en]', 'Sum7t0', 0, 0),
|
||||||
|
(110630, '[en]', 'Sum8a0', 0, 0),
|
||||||
|
(110631, '[en]', 'Sum8l0', 0, 0),
|
||||||
|
(110632, '[en]', 'Sum8t0', 0, 0),
|
||||||
|
(110633, 'Assessing the Damage', 'Etc1l0', 0, 20),
|
||||||
|
(110634, 'Bridging the Gap', 'Etc1l1', 0, 10),
|
||||||
|
(110635, '[en]', 'Etc1l2', 0, 0),
|
||||||
|
(110636, 'Revenge on the Reavers', 'Etc1l3', 0, 45),
|
||||||
|
(110637, '[en]', 'Etc1l4', 0, 0),
|
||||||
|
(110638, 'Till Death Do Us Part', 'Etc1l5', 0, 20),
|
||||||
|
(110639, 'Beryl Overboard', 'Etc1l6', 110638, 20),
|
||||||
|
(110640, 'Have You Seen My Son', 'Etc1l7', 0, 30),
|
||||||
|
(110641, 'Food for Thought', 'Etc1l8', 0, 20),
|
||||||
|
(110642, 'Seashells by the Seashore', 'Etc1l9', 0, 20),
|
||||||
|
(110643, 'Fishing for Answers', 'Etc2l0', 0, 25),
|
||||||
|
(110644, 'Moonstruck', 'Etc2l1', 0, 20),
|
||||||
|
(110645, '[en]', 'Etc2l2', 0, 0),
|
||||||
|
(110646, 'A Misty Past', 'Etc2l3', 0, 17),
|
||||||
|
(110647, '[en]', 'Etc2l4', 0, 0),
|
||||||
|
(110648, 'Carving a Name', 'Etc2l5', 0, 47),
|
||||||
|
(110649, '[en]', 'Etc2l6', 0, 0),
|
||||||
|
(110650, '[en]', 'Etc2l7', 0, 0),
|
||||||
|
(110651, '[en]', 'Etc2l8', 0, 0),
|
||||||
|
(110652, '[en]', 'Etc2l9', 0, 0),
|
||||||
|
(110653, 'The Tug of the Whorl', 'Etc3l0', 0, 5),
|
||||||
|
(110654, 'Proceed with Caution', 'Etc1g0', 0, 10),
|
||||||
|
(110655, 'Playing with Fire', 'Etc1g1', 0, 15),
|
||||||
|
(110656, 'A Well-Balanced Diet', 'Etc1g2', 0, 25),
|
||||||
|
(110657, '[en]', 'Etc1g3', 0, 0),
|
||||||
|
(110658, 'The Penultimate Prank', 'Etc1g4', 0, 30),
|
||||||
|
(110659, 'The Search for Sicksa', 'Etc1g5', 0, 10),
|
||||||
|
(110660, 'The Ultimate Prank', 'Etc1g6', 110658, 35),
|
||||||
|
(110661, '[en]', 'Etc1g7', 0, 0),
|
||||||
|
(110662, 'Say it with Wolf Tails', 'Etc1g8', 110640, 30),
|
||||||
|
(110663, 'Embarrassing Excerpts', 'Etc1g9', 0, 30),
|
||||||
|
(110664, 'A Forbidden Love', 'Etc2g0', 110663, 30),
|
||||||
|
(110665, 'Last Respects', 'Etc2g1', 0, 40),
|
||||||
|
(110666, 'Stone Deaf', 'Etc2g2', 0, 18),
|
||||||
|
(110667, 'Hunting the Hunters', 'Etc2g3', 0, 24),
|
||||||
|
(110668, 'To Deskunk A Beer', 'Etc2g4', 0, 31),
|
||||||
|
(110669, 'Losing One\'s Thread', 'Etc2g5', 0, 25),
|
||||||
|
(110670, '[en]', 'Etc2g6', 0, 0),
|
||||||
|
(110671, '[en]', 'Etc2g7', 0, 0),
|
||||||
|
(110672, '[en]', 'Etc2g8', 0, 0),
|
||||||
|
(110673, '[en]', 'Etc2g9', 0, 0),
|
||||||
|
(110674, 'Seeing the Seers', 'Etc3g0', 0, 5),
|
||||||
|
(110675, 'A Knock in the Night', 'Etc1u0', 0, 35),
|
||||||
|
(110676, 'Sleepless in Eorzea', 'Etc1u1', 0, 10),
|
||||||
|
(110677, 'Dressed to Be Killed', 'Etc1u2', 0, 45),
|
||||||
|
(110678, '[en]', 'Etc1u3', 0, 0),
|
||||||
|
(110679, 'The Customer Comes First', 'Etc1u4', 0, 30),
|
||||||
|
(110680, 'An Inconvenient Dodo', 'Etc1u5', 0, 15),
|
||||||
|
(110681, 'Besmitten and Besmirched', 'Etc1u6', 0, 15),
|
||||||
|
(110682, 'Clasping to Hope', 'Etc1u7', 0, 34),
|
||||||
|
(110683, 'Traumaturgy', 'Etc1u8', 110682, 36),
|
||||||
|
(110684, 'Best Flower Ever', 'Etc1u9', 0, 10),
|
||||||
|
(110685, 'The Unheard Horizon', 'Etc2u0', 0, 20),
|
||||||
|
(110686, 'Freedom Isn\'t Free', 'Etc2u1', 0, 32),
|
||||||
|
(110687, 'Ore for an Ore', 'Etc2u2', 0, 28),
|
||||||
|
(110688, '[en]', 'Etc2u3', 0, 0),
|
||||||
|
(110689, '[en]', 'Etc2u4', 0, 0),
|
||||||
|
(110690, 'No Other Dodo Will Do', 'Etc2u5', 0, 15),
|
||||||
|
(110691, '[en]', 'Etc2u6', 0, 0),
|
||||||
|
(110692, '[en]', 'Etc2u7', 0, 0),
|
||||||
|
(110693, '[en]', 'Etc2u8', 0, 0),
|
||||||
|
(110694, '[en]', 'Etc2u9', 0, 0),
|
||||||
|
(110695, 'A Call to Arms', 'Etc3u0', 0, 5),
|
||||||
|
(110696, '[en]', 'Etc1i0', 0, 0),
|
||||||
|
(110697, '[en]', 'Etc1i1', 0, 0),
|
||||||
|
(110698, '[en]', 'Etc1i2', 0, 0),
|
||||||
|
(110699, '[en]', 'Etc1i3', 0, 0),
|
||||||
|
(110700, '[en]', 'Etc1i4', 0, 0),
|
||||||
|
(110701, '[en]', 'Etc1i5', 0, 0),
|
||||||
|
(110702, '[en]', 'Etc1i6', 0, 0),
|
||||||
|
(110703, '[en]', 'Etc1i7', 0, 0),
|
||||||
|
(110704, '[en]', 'Etc1i8', 0, 0),
|
||||||
|
(110705, '[en]', 'Etc1i9', 0, 0),
|
||||||
|
(110706, 'Counting Sheep', 'Etc2i0', 0, 25),
|
||||||
|
(110707, 'A Hypocritical Oath', 'Etc2i1', 0, 25),
|
||||||
|
(110708, 'Blood Price', 'Etc2i2', 0, 45),
|
||||||
|
(110709, '[en]', 'Etc2i3', 0, 0),
|
||||||
|
(110710, '[en]', 'Etc2i4', 0, 0),
|
||||||
|
(110711, '[en]', 'Etc2i5', 0, 0),
|
||||||
|
(110712, '[en]', 'Etc2i6', 0, 0),
|
||||||
|
(110713, '[en]', 'Etc2i7', 0, 0),
|
||||||
|
(110714, '[en]', 'Etc2i8', 0, 0),
|
||||||
|
(110715, '[en]', 'Etc2i9', 0, 0),
|
||||||
|
(110716, '[en]', 'Etc3i0', 0, 0),
|
||||||
|
(110717, '[en]', 'Etc3i1', 0, 0),
|
||||||
|
(110718, '[en]', 'Etc3i2', 0, 0),
|
||||||
|
(110719, '[en]', 'Etc3i3', 0, 0),
|
||||||
|
(110720, '[en]', 'Etc3i4', 0, 0),
|
||||||
|
(110721, '[en]', 'Etc3i5', 0, 0),
|
||||||
|
(110722, '[en]', 'Etc3i6', 0, 0),
|
||||||
|
(110723, '[en]', 'Etc3i7', 0, 0),
|
||||||
|
(110724, '[en]', 'Etc3i8', 0, 0),
|
||||||
|
(110725, '[en]', 'Etc3i9', 0, 0),
|
||||||
|
(110726, 'Quid Pro Quo', 'Etc3u1', 0, 15),
|
||||||
|
(110727, 'There Might Be Blood', 'Etc3u2', 0, 21),
|
||||||
|
(110728, 'Cutthroat Prices', 'Etc3u3', 0, 15),
|
||||||
|
(110729, '[en]', 'Etc3u4', 0, 0),
|
||||||
|
(110730, '[en]', 'Etc3u5', 0, 0),
|
||||||
|
(110731, '[en]', 'Etc3u6', 0, 0),
|
||||||
|
(110732, '[en]', 'Etc3u7', 0, 0),
|
||||||
|
(110733, '[en]', 'Etc3u8', 0, 0),
|
||||||
|
(110734, 'Monster of Maw Most Massive', 'Etc3u9', 0, 45),
|
||||||
|
(110735, 'Scrubbing the Soul', 'Etc3g1', 0, 15),
|
||||||
|
(110736, 'Disorganized Crime', 'Etc3g2', 0, 21),
|
||||||
|
(110737, 'A Slippery Stone', 'Etc3g3', 0, 15),
|
||||||
|
(110738, '[en]', 'Etc3g4', 0, 0),
|
||||||
|
(110739, '[en]', 'Etc3g5', 0, 0),
|
||||||
|
(110740, '[en]', 'Etc3g6', 0, 0),
|
||||||
|
(110741, '[en]', 'Etc3g7', 0, 0),
|
||||||
|
(110742, '[en]', 'Etc3g8', 0, 0),
|
||||||
|
(110743, '[en]', 'Etc3g9', 0, 0),
|
||||||
|
(110744, 'Winds of Change', 'Etc3l1', 0, 15),
|
||||||
|
(110745, 'Shot Through the Heart', 'Etc3l2', 0, 21),
|
||||||
|
(110746, 'What a Pirate Wants', 'Etc3l3', 0, 15),
|
||||||
|
(110747, '[en]', 'Etc3l4', 0, 0),
|
||||||
|
(110748, '[en]', 'Etc3l5', 0, 0),
|
||||||
|
(110749, '[en]', 'Etc3l6', 0, 0),
|
||||||
|
(110750, '[en]', 'Etc3l7', 0, 0),
|
||||||
|
(110751, '[en]', 'Etc3l8', 0, 0),
|
||||||
|
(110752, '[en]', 'Etc3l9', 0, 0),
|
||||||
|
(110753, 'Of Archons and Muses', 'Wld0u1', 0, 10),
|
||||||
|
(110754, 'Sanguine Studies', 'Wld0u2', 0, 27),
|
||||||
|
(110755, 'Secrets Unearthed', 'Wld0u3', 0, 17),
|
||||||
|
(110756, 'Rustproof', 'Wld0u4', 0, 28),
|
||||||
|
(110757, '[en]', 'Wld0u5', 0, 0),
|
||||||
|
(110758, '[en]', 'Wld0u6', 0, 0),
|
||||||
|
(110759, '[en]', 'Wld0u7', 0, 0),
|
||||||
|
(110760, '[en]', 'Wld0u8', 0, 0),
|
||||||
|
(110761, '[en]', 'Wld0u9', 0, 0),
|
||||||
|
(110762, 'In the Name of Science', 'Wld0g1', 0, 10),
|
||||||
|
(110763, 'Hearing Confession', 'Wld0g2', 0, 10),
|
||||||
|
(110764, 'A Bitter Oil to Swallow', 'Wld0g3', 0, 17),
|
||||||
|
(110765, 'Spores on the Brain', 'Wld0g4', 110762, 11),
|
||||||
|
(110766, '[en]', 'Wld0g5', 0, 0),
|
||||||
|
(110767, '[en]', 'Wld0g6', 0, 0),
|
||||||
|
(110768, '[en]', 'Wld0g7', 0, 0),
|
||||||
|
(110769, '[en]', 'Wld0g8', 0, 0),
|
||||||
|
(110770, '[en]', 'Wld0g9', 0, 0),
|
||||||
|
(110771, 'Trading Tongueflaps', 'Wld0l1', 0, 5),
|
||||||
|
(110772, 'Letting Out Orion\'s Belt', 'Wld0l2', 0, 10),
|
||||||
|
(110773, 'Sour Grapes', 'Wld0l3', 0, 17),
|
||||||
|
(110774, 'Sniffing Out a Profit', 'Wld0l4', 0, 37),
|
||||||
|
(110775, '[en]', 'Wld0l5', 0, 0),
|
||||||
|
(110776, '[en]', 'Wld0l6', 0, 0),
|
||||||
|
(110777, '[en]', 'Wld0l7', 0, 0),
|
||||||
|
(110778, '[en]', 'Wld0l8', 0, 0),
|
||||||
|
(110779, '[en]', 'Wld0l9', 0, 0),
|
||||||
|
(110780, '[en]', 'Wld0i1', 0, 0),
|
||||||
|
(110781, '[en]', 'Wld0i2', 0, 0),
|
||||||
|
(110782, '[en]', 'Wld0i3', 0, 0),
|
||||||
|
(110783, '[en]', 'Wld0i4', 0, 0),
|
||||||
|
(110784, '[en]', 'Wld0i5', 0, 0),
|
||||||
|
(110785, '[en]', 'Wld0i6', 0, 0),
|
||||||
|
(110786, '[en]', 'Wld0i7', 0, 0),
|
||||||
|
(110787, '[en]', 'Wld0i8', 0, 0),
|
||||||
|
(110788, '[en]', 'Wld0i9', 0, 0),
|
||||||
|
(110789, 'The Dreamer\'s Gospel (Ul\'dah)', 'Spl0u1', 0, 5),
|
||||||
|
(110790, 'The Dreamer\'s Dilemma (Ul\'dah)', 'Spl0u2', 0, 5),
|
||||||
|
(110791, '[en]', 'Spl0u3', 0, 0),
|
||||||
|
(110792, '[en]', 'Spl0u4', 0, 0),
|
||||||
|
(110793, '[en]', 'Spl0u5', 0, 0),
|
||||||
|
(110794, 'The Dreamer\'s Gospel (Gridania)', 'Spl0g1', 0, 5),
|
||||||
|
(110795, 'The Dreamer\'s Dilemma (Gridania)', 'Spl0g2', 0, 5),
|
||||||
|
(110796, '[en]', 'Spl0g3', 0, 0),
|
||||||
|
(110797, '[en]', 'Spl0g4', 0, 0),
|
||||||
|
(110798, '[en]', 'Spl0g5', 0, 0),
|
||||||
|
(110799, 'The Heat Is On', 'Spl0i1', 0, 1),
|
||||||
|
(110800, 'Impish Impositions', 'Spl0i2', 0, 1),
|
||||||
|
(110801, 'Winter Is Not Coming', 'Spl0i3', 0, 1),
|
||||||
|
(110802, 'Gone with the Snow', 'Spl0i4', 0, 1),
|
||||||
|
(110803, '[en]', 'Spl0i5', 0, 0),
|
||||||
|
(110804, 'The Dreamer\'s Gospel (Limsa Lominsa)', 'Spl0l1', 0, 5),
|
||||||
|
(110805, 'The Dreamer\'s Dilemma (Limsa Lominsa)', 'Spl0l2', 0, 5),
|
||||||
|
(110806, '[en]', 'Spl0l3', 0, 0),
|
||||||
|
(110807, '[en]', 'Spl0l4', 0, 0),
|
||||||
|
(110808, '[en]', 'Spl0l5', 0, 0),
|
||||||
|
(110809, 'Guild Tasks', 'Noc000', 0, 0),
|
||||||
|
(110810, 'Call of Booty', 'Etc303', 110737, 15),
|
||||||
|
(110811, 'Risky Business', 'Etc101', 0, 18),
|
||||||
|
(110812, 'Forging the Spirit', 'Etc102', 0, 18),
|
||||||
|
(110813, 'Joining the Spirit', 'Etc103', 0, 18),
|
||||||
|
(110814, 'Waking the Spirit', 'Etc104', 0, 18),
|
||||||
|
(110815, '[en]', 'Etc105', 0, 0),
|
||||||
|
(110816, 'A Feast of Fools', 'Sum6m0', 0, 45),
|
||||||
|
(110817, 'Provisioning & Supply Missions', 'Noc001', 0, 0),
|
||||||
|
(110818, 'A Light in the Dark', 'Etc200', 0, 45),
|
||||||
|
(110819, 'What Glitters Always Isn\'t Gold', 'Etc201', 0, 45),
|
||||||
|
(110820, '[en]', 'Etc202', 0, 1),
|
||||||
|
(110821, 'the Thousand Maws of Toto’Rak', 'Etc202', 0, 1),
|
||||||
|
(110822, 'Dzemael Darkhold', 'Etc202', 0, 1),
|
||||||
|
(110823, 'Aurum Vale', 'Etc202', 0, 1),
|
||||||
|
(110824, 'Cutter\'s Cry', 'Etc202', 0, 1),
|
||||||
|
(110828, 'Waste Not Want Not', 'Etc5g0', 110006, 1),
|
||||||
|
(110829, 'In Plain Sight', 'Etc5g1', 0, 15),
|
||||||
|
(110838, 'The Ink Thief', 'Etc5l0', 110002, 1),
|
||||||
|
(110839, 'Private Eyes', 'Etc5l1', 0, 15),
|
||||||
|
(110840, 'Mysteries of the Red Moon', 'Etc5l2', 110839, 20),
|
||||||
|
(110841, 'Prophecy Inspection', 'Etc5l3', 110840, 20),
|
||||||
|
(110848, 'Ring of Deceit', 'Etc5u0', 110010, 1),
|
||||||
|
(110849, 'The Usual Suspect', 'Etc5u1', 0, 15),
|
||||||
|
(110850, '[en]', 'Etc5u2', 0, 1),
|
||||||
|
(110851, '[en]', 'Etc5u3', 0, 1),
|
||||||
|
(110858, 'Seasonal Event', 'Spl000', 0, 1),
|
||||||
|
(110859, 'Scrambled Eggs', 'Spl101', 0, 1),
|
||||||
|
(110860, 'Bombard Backlash', 'Spl102', 0, 1),
|
||||||
|
(110861, 'Seasonal Event (All City-states)', 'Spl103', 0, 1),
|
||||||
|
(110862, 'Hamlet Defense', 'Noc002', 0, 1),
|
||||||
|
(110863, 'Class is in Session', 'Noc003', 0, 1),
|
||||||
|
(110867, 'Taming the Tempest', 'Sum6g0', 0, 45),
|
||||||
|
(110868, 'A Relic Reborn', 'Etc106', 0, 50),
|
||||||
|
(110869, 'Living on a Prayer', 'Etc304', 0, 45),
|
||||||
|
(110870, 'The Raven, Nevermore', 'Sum6w0', 0, 45),
|
||||||
|
(111201, 'Pride and Duty (Will Take You from the Mountain)', 'War0j1', 0, 15),
|
||||||
|
(111202, 'Embracing the Beast', 'War0j2', 0, 15),
|
||||||
|
(111203, 'Curious Gorge Goes to the Bazaar', 'War0j3', 0, 15),
|
||||||
|
(111204, 'Looking the Part', 'War0j4', 0, 15),
|
||||||
|
(111205, 'Proof is in the Pudding', 'War0j5', 0, 15),
|
||||||
|
(111206, 'How to Quit You', 'War0j6', 0, 15),
|
||||||
|
(111221, 'Brother from Another Mother', 'Mnk0j1', 0, 15),
|
||||||
|
(111222, 'Insulted Intelligence', 'Mnk0j2', 0, 15),
|
||||||
|
(111223, 'The Pursuit of Power', 'Mnk0j3', 0, 15),
|
||||||
|
(111224, 'Good Vibrations', 'Mnk0j4', 0, 15),
|
||||||
|
(111225, 'Five Easy Pieces', 'Mnk0j5', 0, 15),
|
||||||
|
(111226, 'Return of the King...of Ruin', 'Mnk0j6', 0, 15),
|
||||||
|
(111241, 'Seeds of Initiative', 'Whm0j1', 0, 15),
|
||||||
|
(111242, 'When Sheep Attack', 'Whm0j2', 0, 15),
|
||||||
|
(111243, 'Lost in Rage', 'Whm0j3', 0, 15),
|
||||||
|
(111244, 'The Wheel of Disaster', 'Whm0j4', 0, 15),
|
||||||
|
(111245, 'In Search of Succor', 'Whm0j5', 0, 15),
|
||||||
|
(111246, 'The Chorus of Cataclysm', 'Whm0j6', 0, 15),
|
||||||
|
(111261, 'Hearing Voices', 'Blm0j1', 0, 15),
|
||||||
|
(111262, 'A Time to Kill', 'Blm0j2', 0, 15),
|
||||||
|
(111263, 'International Relations', 'Blm0j3', 0, 15),
|
||||||
|
(111264, 'The Voidgate Breathes Gloomy', 'Blm0j4', 0, 15),
|
||||||
|
(111265, 'Gearing Up', 'Blm0j5', 0, 15),
|
||||||
|
(111266, 'Always Bet on Black', 'Blm0j6', 0, 15),
|
||||||
|
(111281, 'Paladin\'s Pledge', 'Pld0j1', 0, 15),
|
||||||
|
(111282, 'Honor Lost', 'Pld0j2', 0, 15),
|
||||||
|
(111283, 'Power Struggles', 'Pld0j3', 0, 15),
|
||||||
|
(111284, 'Poisoned Hearts', 'Pld0j4', 0, 15),
|
||||||
|
(111285, 'Parley on High Ground', 'Pld0j5', 0, 15),
|
||||||
|
(111286, 'Keeping the Oath', 'Pld0j6', 0, 15),
|
||||||
|
(111301, 'A Song of Bards and Bowmen', 'Brd0j1', 0, 15),
|
||||||
|
(111302, 'The Archer\'s Anthem', 'Brd0j2', 0, 15),
|
||||||
|
(111303, 'Bard\'s-Eye View', 'Brd0j3', 0, 15),
|
||||||
|
(111304, 'Doing It the Bard Way', 'Brd0j4', 0, 15),
|
||||||
|
(111305, 'Pieces of the Past', 'Brd0j5', 0, 15),
|
||||||
|
(111306, 'Requiem for the Fallen', 'Brd0j6', 0, 15),
|
||||||
|
(111321, 'Eye of the Dragon', 'Drg0j1', 0, 15),
|
||||||
|
(111322, 'Lance of Fury', 'Drg0j2', 0, 15),
|
||||||
|
(111323, 'Unfading Scars', 'Drg0j3', 0, 15),
|
||||||
|
(111324, 'Double Dragoon', 'Drg0j4', 0, 15),
|
||||||
|
(111325, 'Fatal Seduction', 'Drg0j5', 0, 15),
|
||||||
|
(111326, 'Into the Dragon\'s Maw', 'Drg0j6', 0, 15),
|
||||||
|
(111401, 'The Price of Integrity', 'Com0l1', 0, 22),
|
||||||
|
(111402, 'Testing the Waters', 'Com0l2', 0, 22),
|
||||||
|
(111403, 'Seals for the Whorl', 'Com0l3', 0, 22),
|
||||||
|
(111404, 'Engineering Victory', 'Com0l4', 0, 22),
|
||||||
|
(111405, 'An Officer and a Wise Man', 'Com0l5', 0, 25),
|
||||||
|
(111406, 'Ceruleum Shock', 'Com0l6', 0, 25),
|
||||||
|
(111407, 'Till Sea Swallows All', 'Com0l7', 0, 25),
|
||||||
|
(111408, '[en]', 'Com0l8', 0, 0),
|
||||||
|
(111409, '[en]', 'Com0l9', 0, 0),
|
||||||
|
(111410, 'Imperial Devices (Limsa Lominsa)', 'Com5l0', 0, 25),
|
||||||
|
(111411, 'Into the Dark (Limsa Lominsa)', 'Com5l1', 0, 45),
|
||||||
|
(111412, '[en]', 'Com5l2', 0, 0),
|
||||||
|
(111413, '[en]', 'Com5l3', 0, 0),
|
||||||
|
(111414, '[en]', 'Com5l4', 0, 0),
|
||||||
|
(111415, '[en]', 'Com5l5', 0, 0),
|
||||||
|
(111416, 'It Kills with Fire (Limsa Lominsa)', 'Gcl101', 0, 30),
|
||||||
|
(111417, 'The Cove', 'Gcl301', 0, 25),
|
||||||
|
(111418, 'Saving the Stead Instead', 'Gcl302', 0, 25),
|
||||||
|
(111419, 'It\'s a Piece of Cake to Bake a Poison Cake', 'Gcl303', 0, 40),
|
||||||
|
(111420, 'Kobold and the Beautiful', 'Gcl304', 0, 45),
|
||||||
|
(111421, '[en]', 'Gcl501', 0, 0),
|
||||||
|
(111422, '[en]', 'Gcl502', 0, 0),
|
||||||
|
(111423, '[en]', 'Gcl601', 0, 0),
|
||||||
|
(111424, '[en]', 'Gcl602', 0, 0),
|
||||||
|
(111425, '[en]', 'Gcl603', 0, 0),
|
||||||
|
(111426, 'Oil Crisis', 'Gcl305', 0, 50),
|
||||||
|
(111427, 'Alive', 'Gcl102', 0, 40),
|
||||||
|
(111428, 'The Weakest Link', 'Gcl701', 0, 45),
|
||||||
|
(111429, 'Deus ex Machina', 'Gcl103', 0, 45),
|
||||||
|
(111430, 'In for Garuda Wakening (Limsa Lominsa)', 'Gcl104', 0, 45),
|
||||||
|
(111431, 'Don\'t Hate the Messenger (Limsa Lominsa)', 'Gcl105', 0, 45),
|
||||||
|
(111432, 'United We Stand (Limsa Lominsa)', 'Gcl106', 0, 45),
|
||||||
|
(111433, 'To Kill a Raven (Limsa Lominsa)', 'Gcl107', 0, 45),
|
||||||
|
(111434, 'Patrol, Interrupted', 'Gcl702', 0, 50),
|
||||||
|
(111601, 'Breaking the Seals', 'Com0g1', 0, 22),
|
||||||
|
(111602, 'Why Did It Have to Be Snakes', 'Com0g2', 0, 22),
|
||||||
|
(111603, 'Adder\'s Nest Egg', 'Com0g3', 0, 22),
|
||||||
|
(111604, 'The Mail Must Get Through', 'Com0g4', 0, 22),
|
||||||
|
(111605, 'Their Finest Hour', 'Com0g5', 0, 25),
|
||||||
|
(111606, 'Appetite for Destruction', 'Com0g6', 0, 25),
|
||||||
|
(111607, 'Serenity, Purity, Sanctity', 'Com0g7', 0, 25),
|
||||||
|
(111608, '[en]', 'Com0g8', 0, 0),
|
||||||
|
(111609, '[en]', 'Com0g9', 0, 0),
|
||||||
|
(111610, 'Imperial Devices (Gridania)', 'Com5g0', 0, 25),
|
||||||
|
(111611, 'Into the Dark (Gridania)', 'Com5g1', 0, 45),
|
||||||
|
(111612, '[en]', 'Com5g2', 0, 0),
|
||||||
|
(111613, '[en]', 'Com5g3', 0, 0),
|
||||||
|
(111614, '[en]', 'Com5g4', 0, 0),
|
||||||
|
(111615, '[en]', 'Com5g5', 0, 0),
|
||||||
|
(111616, 'It Kills with Fire (Gridania)', 'Gcg101', 0, 30),
|
||||||
|
(111617, 'Eternal Recurrence', 'Gcg301', 0, 25),
|
||||||
|
(111618, 'The Pen Is Mightier Than the Spear', 'Gcg302', 0, 25),
|
||||||
|
(111619, 'Woes of the Botanist', 'Gcg303', 0, 40),
|
||||||
|
(111620, 'Gone with the Wind', 'Gcg304', 0, 45),
|
||||||
|
(111621, '[en]', 'Gcg501', 0, 0),
|
||||||
|
(111622, '[en]', 'Gcg502', 0, 0),
|
||||||
|
(111623, '[en]', 'Gcg601', 0, 0),
|
||||||
|
(111624, '[en]', 'Gcg602', 0, 0),
|
||||||
|
(111625, '[en]', 'Gcg603', 0, 0),
|
||||||
|
(111626, 'A Taste for Death', 'Gcg305', 0, 50),
|
||||||
|
(111627, 'Two Vans are Better than One', 'Gcg102', 0, 40),
|
||||||
|
(111628, 'You Don\'t Have the Rite', 'Gcg701', 0, 45),
|
||||||
|
(111629, 'Shadow of the Raven', 'Gcg103', 0, 45),
|
||||||
|
(111630, 'In for Garuda Wakening (Gridania)', 'Gcg104', 0, 45),
|
||||||
|
(111631, 'Don\'t Hate the Messenger (Gridania)', 'Gcg105', 0, 45),
|
||||||
|
(111632, 'United We Stand (Gridania)', 'Gcg106', 0, 45),
|
||||||
|
(111633, 'To Kill a Raven (Gridania)', 'Gcg107', 0, 45),
|
||||||
|
(111634, 'Cure for the Common Pox', 'Gcg702', 0, 50),
|
||||||
|
(111801, 'Career Opportunities', 'Com0u1', 0, 22),
|
||||||
|
(111802, 'Kindling a Flame', 'Com0u2', 0, 22),
|
||||||
|
(111803, 'Burning a Hole in One\'s Pocket', 'Com0u3', 0, 22),
|
||||||
|
(111804, 'Arms Race', 'Com0u4', 0, 22),
|
||||||
|
(111805, 'Burning Man', 'Com0u5', 0, 25),
|
||||||
|
(111806, 'Know Your Enemy', 'Com0u6', 0, 25),
|
||||||
|
(111807, 'By Fire Reborn', 'Com0u7', 0, 25),
|
||||||
|
(111808, '[en]', 'Com0u8', 0, 0),
|
||||||
|
(111809, '[en]', 'Com0u9', 0, 0),
|
||||||
|
(111810, 'Imperial Devices (Ul\'dah)', 'Com5u0', 0, 25),
|
||||||
|
(111811, 'Into the Dark (Ul\'dah)', 'Com5u1', 0, 45),
|
||||||
|
(111812, '[en]', 'Com5u2', 0, 0),
|
||||||
|
(111813, '[en]', 'Com5u3', 0, 0),
|
||||||
|
(111814, '[en]', 'Com5u4', 0, 0),
|
||||||
|
(111815, '[en]', 'Com5u5', 0, 0),
|
||||||
|
(111816, 'It Kills with Fire (Ul\'dah)', 'Gcu101', 0, 30),
|
||||||
|
(111817, 'Prying Eyes', 'Gcu301', 0, 25),
|
||||||
|
(111818, 'Different Strokes', 'Gcu302', 0, 25),
|
||||||
|
(111819, 'A Weaver and a Mummer', 'Gcu303', 0, 40),
|
||||||
|
(111820, 'When Alchemists Cry', 'Gcu304', 0, 45),
|
||||||
|
(111821, '[en]', 'Gcu501', 0, 0),
|
||||||
|
(111822, '[en]', 'Gcu502', 0, 0),
|
||||||
|
(111823, '[en]', 'Gcu601', 0, 0),
|
||||||
|
(111824, '[en]', 'Gcu602', 0, 0),
|
||||||
|
(111825, '[en]', 'Gcu603', 0, 0),
|
||||||
|
(111826, 'Challenge Accepted', 'Gcu305', 0, 50),
|
||||||
|
(111827, 'Like Father, Like Son', 'Gcu102', 0, 40),
|
||||||
|
(111828, 'Gore a Lizard, Hurry', 'Gcu701', 0, 45),
|
||||||
|
(111829, 'Careless Whispers', 'Gcu103', 0, 45),
|
||||||
|
(111830, 'In for Garuda Wakening (Ul\'dah)', 'Gcu104', 0, 45),
|
||||||
|
(111831, 'Don\'t Hate the Messenger (Ul\'dah)', 'Gcu105', 0, 45),
|
||||||
|
(111832, 'United We Stand (Ul\'dah)', 'Gcu106', 0, 45),
|
||||||
|
(111833, 'To Kill a Raven (Ul\'dah)', 'Gcu107', 0, 45),
|
||||||
|
(111834, 'Mess with the Goat, Get the Horns', 'Gcu702', 0, 50);
|
||||||
|
/*!40000 ALTER TABLE `gamedata_quests` ENABLE KEYS */;
|
||||||
|
|
||||||
|
/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */;
|
||||||
|
/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */;
|
||||||
|
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
|
@ -20,7 +20,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using Meteor.Map.Actors;
|
using Meteor.Map.Actors;
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
|
|
||||||
namespace Meteor.Map.actors.chara.ai.state
|
namespace Meteor.Map.actors.chara.ai.state
|
||||||
{
|
{
|
||||||
|
|
|
@ -24,7 +24,7 @@ using Meteor.Common;
|
||||||
using Meteor.Map.actors.chara.player;
|
using Meteor.Map.actors.chara.player;
|
||||||
using Meteor.Map.actors.group;
|
using Meteor.Map.actors.group;
|
||||||
using Meteor.Map.Actors.Chara;
|
using Meteor.Map.Actors.Chara;
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using Meteor.Map.packets.send.actor;
|
using Meteor.Map.packets.send.actor;
|
||||||
using Meteor.Map.packets.send.actor.inventory;
|
using Meteor.Map.packets.send.actor.inventory;
|
||||||
using Meteor.Map.utils;
|
using Meteor.Map.utils;
|
||||||
|
|
|
@ -22,7 +22,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
using Meteor.Common;
|
using Meteor.Common;
|
||||||
using Meteor.Map.actors.chara.npc;
|
using Meteor.Map.actors.chara.npc;
|
||||||
using Meteor.Map.Actors;
|
using Meteor.Map.Actors;
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using Meteor.Map.packets.send.actor.inventory;
|
using Meteor.Map.packets.send.actor.inventory;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
|
@ -23,8 +23,8 @@ using Meteor.Common;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using MoonSharp.Interpreter;
|
using MoonSharp.Interpreter;
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using Meteor.Map.dataobjects.chara;
|
using Meteor.Map.DataObjects.chara;
|
||||||
using Meteor.Map.lua;
|
using Meteor.Map.lua;
|
||||||
using Meteor.Map.packets.WorldPackets.Send.Group;
|
using Meteor.Map.packets.WorldPackets.Send.Group;
|
||||||
using Meteor.Map.utils;
|
using Meteor.Map.utils;
|
||||||
|
@ -37,6 +37,7 @@ using Meteor.Map.actors.chara.ai.controllers;
|
||||||
using Meteor.Map.actors.chara.ai.utils;
|
using Meteor.Map.actors.chara.ai.utils;
|
||||||
using Meteor.Map.actors.chara.ai.state;
|
using Meteor.Map.actors.chara.ai.state;
|
||||||
using Meteor.Map.actors.chara;
|
using Meteor.Map.actors.chara;
|
||||||
|
using Meteor.Map.Actors.QuestNS;
|
||||||
using Meteor.Map.packets.send;
|
using Meteor.Map.packets.send;
|
||||||
using Meteor.Map.packets.send.actor;
|
using Meteor.Map.packets.send.actor;
|
||||||
using Meteor.Map.packets.send.events;
|
using Meteor.Map.packets.send.events;
|
||||||
|
@ -46,6 +47,7 @@ using Meteor.Map.packets.send.actor.battle;
|
||||||
using Meteor.Map.packets.receive.events;
|
using Meteor.Map.packets.receive.events;
|
||||||
using static Meteor.Map.LuaUtils;
|
using static Meteor.Map.LuaUtils;
|
||||||
using Meteor.Map.packets.send.actor.events;
|
using Meteor.Map.packets.send.actor.events;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace Meteor.Map.Actors
|
namespace Meteor.Map.Actors
|
||||||
{
|
{
|
||||||
|
@ -147,6 +149,7 @@ namespace Meteor.Map.Actors
|
||||||
//Quest Actors (MUST MATCH playerWork.questScenario/questGuildleve)
|
//Quest Actors (MUST MATCH playerWork.questScenario/questGuildleve)
|
||||||
public Quest[] questScenario = new Quest[16];
|
public Quest[] questScenario = new Quest[16];
|
||||||
public uint[] questGuildleve = new uint[8];
|
public uint[] questGuildleve = new uint[8];
|
||||||
|
public QuestStateManager questStateManager;
|
||||||
|
|
||||||
//Aetheryte
|
//Aetheryte
|
||||||
public uint homepoint = 0;
|
public uint homepoint = 0;
|
||||||
|
@ -242,7 +245,6 @@ namespace Meteor.Map.Actors
|
||||||
|
|
||||||
charaWork.commandAcquired[27150 - 26000] = true;
|
charaWork.commandAcquired[27150 - 26000] = true;
|
||||||
|
|
||||||
playerWork.questScenarioComplete[110001 - 110001] = true;
|
|
||||||
playerWork.questGuildleveComplete[120050 - 120001] = true;
|
playerWork.questGuildleveComplete[120050 - 120001] = true;
|
||||||
|
|
||||||
for (int i = 0; i < charaWork.additionalCommandAcquired.Length; i++ )
|
for (int i = 0; i < charaWork.additionalCommandAcquired.Length; i++ )
|
||||||
|
@ -274,6 +276,9 @@ namespace Meteor.Map.Actors
|
||||||
this.aiContainer = new AIContainer(this, new PlayerController(this), null, new TargetFind(this));
|
this.aiContainer = new AIContainer(this, new PlayerController(this), null, new TargetFind(this));
|
||||||
allegiance = CharacterTargetingAllegiance.Player;
|
allegiance = CharacterTargetingAllegiance.Player;
|
||||||
CalculateBaseStats();
|
CalculateBaseStats();
|
||||||
|
|
||||||
|
questStateManager = new QuestStateManager(this);
|
||||||
|
questStateManager.Init(questScenario, playerWork.questScenarioComplete);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<SubPacket> Create0x132Packets()
|
public List<SubPacket> Create0x132Packets()
|
||||||
|
@ -400,9 +405,10 @@ namespace Meteor.Map.Actors
|
||||||
if (CurrentArea.isInn)
|
if (CurrentArea.isInn)
|
||||||
{
|
{
|
||||||
SetCutsceneBookPacket cutsceneBookPacket = new SetCutsceneBookPacket();
|
SetCutsceneBookPacket cutsceneBookPacket = new SetCutsceneBookPacket();
|
||||||
|
bool[] testComplete = new bool[2048]; //TODO: Change to playerwork.scenarioComplete
|
||||||
for (int i = 0; i < 2048; i++)
|
for (int i = 0; i < 2048; i++)
|
||||||
cutsceneBookPacket.cutsceneFlags[i] = true;
|
testComplete[i] = true;
|
||||||
QueuePacket(cutsceneBookPacket.BuildPacket(Id, "<Path Companion>", 11, 1, 1));
|
QueuePacket(cutsceneBookPacket.BuildPacket(Id, "<Path Companion>", 11, 1, 1, testComplete));
|
||||||
QueuePacket(SetPlayerDreamPacket.BuildPacket(Id, 0x16, GetInnCode()));
|
QueuePacket(SetPlayerDreamPacket.BuildPacket(Id, 0x16, GetInnCode()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -801,7 +807,7 @@ namespace Meteor.Map.Actors
|
||||||
foreach (Quest quest in questScenario)
|
foreach (Quest quest in questScenario)
|
||||||
{
|
{
|
||||||
if (quest != null)
|
if (quest != null)
|
||||||
quest.SaveData();
|
quest.GetData().Save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1151,6 +1157,42 @@ namespace Meteor.Map.Actors
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SendAchievedAetheryte(ushort from, ushort to)
|
||||||
|
{
|
||||||
|
Bitstream fakeAetheryte = new Bitstream(512, true);
|
||||||
|
|
||||||
|
SetActorPropetyPacket completedQuestWorkUpdate = new SetActorPropetyPacket(from, to, "work/achieveAetheryte");
|
||||||
|
completedQuestWorkUpdate.AddBitfield(Utils.MurmurHash2("work.event_achieve_aetheryte", 0), fakeAetheryte.GetSlice(from, to));
|
||||||
|
completedQuestWorkUpdate.AddTarget();
|
||||||
|
QueuePacket(completedQuestWorkUpdate.BuildPacket(Id));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SendCompletedQuests(ushort from, ushort to)
|
||||||
|
{
|
||||||
|
byte[] data = questStateManager.GetCompletionSliceBytes(from, to);
|
||||||
|
|
||||||
|
SetActorPropetyPacket completedQuestWorkUpdate = new SetActorPropetyPacket(from, to, "playerWork/journal");
|
||||||
|
completedQuestWorkUpdate.AddBitfield(Utils.MurmurHash2("playerWork.questScenarioComplete", 0), data);
|
||||||
|
completedQuestWorkUpdate.AddTarget();
|
||||||
|
QueuePacket(completedQuestWorkUpdate.BuildPacket(Id));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnWorkSyncRequest(string propertyName, ushort from = 0, ushort to = 0)
|
||||||
|
{
|
||||||
|
switch (propertyName)
|
||||||
|
{
|
||||||
|
case "charaWork/exp":
|
||||||
|
SendCharaExpInfo();
|
||||||
|
break;
|
||||||
|
case "work/achieveAetheryte":
|
||||||
|
SendAchievedAetheryte(from, to);
|
||||||
|
break;
|
||||||
|
case "playerWork/questCompleteS":
|
||||||
|
SendCompletedQuests(from, to);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public int GetHighestLevel()
|
public int GetHighestLevel()
|
||||||
{
|
{
|
||||||
int max = 0;
|
int max = 0;
|
||||||
|
@ -1413,33 +1455,276 @@ namespace Meteor.Map.Actors
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
//For Lua calls, cause MoonSharp goes retard with uint
|
#region Quests - Script Related
|
||||||
public void AddQuest(int id, bool isSilent = false)
|
// Add quest from an active quest in the player's quest state. Quest scripts will use this to add a quest.
|
||||||
|
public bool AcceptQuest(Quest instance, bool isSilent = false)
|
||||||
{
|
{
|
||||||
AddQuest((uint)id, isSilent);
|
if (instance == null)
|
||||||
}
|
return false;
|
||||||
public void CompleteQuest(int id)
|
|
||||||
{
|
|
||||||
CompleteQuest((uint)id);
|
|
||||||
}
|
|
||||||
public bool HasQuest(int id)
|
|
||||||
{
|
|
||||||
return HasQuest((uint)id);
|
|
||||||
}
|
|
||||||
public Quest GetQuest(int id)
|
|
||||||
{
|
|
||||||
return GetQuest((uint)id);
|
|
||||||
}
|
|
||||||
public bool IsQuestCompleted(int id)
|
|
||||||
{
|
|
||||||
return IsQuestCompleted((uint)id);
|
|
||||||
}
|
|
||||||
public bool CanAcceptQuest(int id)
|
|
||||||
{
|
|
||||||
return CanAcceptQuest((uint)id);
|
|
||||||
}
|
|
||||||
//For Lua calls, cause MoonSharp goes retard with uint
|
|
||||||
|
|
||||||
|
int freeSlot = GetFreeQuestSlot();
|
||||||
|
|
||||||
|
if (freeSlot == -1)
|
||||||
|
{
|
||||||
|
SendGameMessage(Server.GetWorldManager().GetActor(), 25234, 0x20); // "You cannot accept any more quests at this time."
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
playerWork.questScenario[freeSlot] = instance.Id;
|
||||||
|
questScenario[freeSlot] = instance;
|
||||||
|
SendQuestClientUpdate(freeSlot);
|
||||||
|
|
||||||
|
if (!isSilent)
|
||||||
|
{
|
||||||
|
SendGameMessage(Server.GetWorldManager().GetActor(), 25224, 0x20, (object)questScenario[freeSlot].GetQuestId()); // "<Quest> accepted."
|
||||||
|
}
|
||||||
|
|
||||||
|
instance.OnAccept();
|
||||||
|
|
||||||
|
Database.SaveQuest(this, questScenario[freeSlot], freeSlot);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace a quest with another quest in the player's quest state.
|
||||||
|
public void ReplaceQuest(Quest oldQuestInstance, Quest newQuestInstance)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < questScenario.Length; i++)
|
||||||
|
{
|
||||||
|
if (questScenario[i] != null && questScenario[i].Equals(oldQuestInstance))
|
||||||
|
{
|
||||||
|
questScenario[i] = newQuestInstance;
|
||||||
|
playerWork.questScenario[i] = questScenario[i].Id;
|
||||||
|
SendQuestClientUpdate(i);
|
||||||
|
oldQuestInstance.OnComplete();
|
||||||
|
questStateManager.UpdateQuestCompleted(oldQuestInstance);
|
||||||
|
newQuestInstance.OnAccept();
|
||||||
|
Database.SaveQuest(this, questScenario[i], i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CompleteQuest(Quest completed)
|
||||||
|
{
|
||||||
|
int slot = GetQuestSlot(completed);
|
||||||
|
if (slot >= 0)
|
||||||
|
{
|
||||||
|
// Remove the quest from the DB and update client work values
|
||||||
|
playerWork.questScenarioComplete[completed.GetQuestId() - 110001] = true;
|
||||||
|
questScenario[slot] = null;
|
||||||
|
playerWork.questScenario[slot] = 0;
|
||||||
|
SendQuestClientUpdate(slot);
|
||||||
|
|
||||||
|
// Reset active quest and quest state
|
||||||
|
completed.OnComplete();
|
||||||
|
Database.SaveCompletedQuests(playerSession.GetActor());
|
||||||
|
Database.RemoveQuest(this, completed.Id);
|
||||||
|
questStateManager.UpdateQuestCompleted(completed);
|
||||||
|
|
||||||
|
// Msg Player
|
||||||
|
SendGameMessage(Server.GetWorldManager().GetActor(), 25086, 0x20, (object)completed.GetQuestId()); // "<Quest> complete!"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool AbandonQuest(uint questId)
|
||||||
|
{
|
||||||
|
// Check if in an instance
|
||||||
|
if (CurrentArea.IsPrivate())
|
||||||
|
{
|
||||||
|
SendGameMessage(Server.GetWorldManager().GetActor(), 25235, 0x20); // "Quests cannot be abandoned while from within an instance."
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the quest object
|
||||||
|
int slot = GetQuestSlot(questId);
|
||||||
|
Quest abandoned = questScenario[slot];
|
||||||
|
|
||||||
|
if (abandoned == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Check if Main Scenario
|
||||||
|
if (abandoned.IsMainScenario())
|
||||||
|
{
|
||||||
|
SendGameMessage(Server.GetWorldManager().GetActor(), 25233, 0x20); // "Main scenario quests cannot be abandoned."
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the quest from the DB and update client work values
|
||||||
|
questScenario[slot] = null;
|
||||||
|
playerWork.questScenario[slot] = 0;
|
||||||
|
SendQuestClientUpdate(slot);
|
||||||
|
|
||||||
|
// Reset active quest and quest state
|
||||||
|
abandoned.OnAbandon();
|
||||||
|
Database.RemoveQuest(this, abandoned.Id);
|
||||||
|
questStateManager.UpdateQuestAbandoned();
|
||||||
|
|
||||||
|
// Msg Player
|
||||||
|
SendGameMessage(this, Server.GetWorldManager().GetActor(), 25236, 0x20, (object)abandoned.GetQuestId()); // "<Quest> abandoned."
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool HasQuest(Quest questInstance)
|
||||||
|
{
|
||||||
|
return GetQuestSlot(questInstance) != -1;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Quests - Debug/Misc Related
|
||||||
|
// Force-Add a quest by Id. Called be debug scripts.
|
||||||
|
public void AddQuest(uint id, bool isSilent = false)
|
||||||
|
{
|
||||||
|
Actor actor = Server.GetStaticActors((0xA0F00000 | id));
|
||||||
|
AddQuest(actor.Name, isSilent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Force-Add a quest by Name. Called be debug scripts. Will try to use an active quest, otherwise adds a new instance.
|
||||||
|
public void AddQuest(string name, bool isSilent = false)
|
||||||
|
{
|
||||||
|
Quest baseQuest = (Quest)Server.GetStaticActors(name);
|
||||||
|
Quest activeQuest = questStateManager.GetActiveQuest(baseQuest.GetQuestId());
|
||||||
|
|
||||||
|
int freeSlot = GetFreeQuestSlot();
|
||||||
|
|
||||||
|
if (freeSlot == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
playerWork.questScenario[freeSlot] = baseQuest.Id;
|
||||||
|
questScenario[freeSlot] = activeQuest ?? new Quest(this, baseQuest);
|
||||||
|
|
||||||
|
if (activeQuest == null)
|
||||||
|
questStateManager.ForceAddActiveQuest(questScenario[freeSlot]);
|
||||||
|
|
||||||
|
Database.SaveQuest(this, questScenario[freeSlot], freeSlot);
|
||||||
|
SendQuestClientUpdate(freeSlot);
|
||||||
|
|
||||||
|
if (!isSilent)
|
||||||
|
{
|
||||||
|
SendGameMessage(Server.GetWorldManager().GetActor(), 25224, 0x20, (object)questScenario[freeSlot].GetQuestId());
|
||||||
|
}
|
||||||
|
|
||||||
|
questScenario[freeSlot].OnAccept();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveQuest(uint id)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < questScenario.Length; i++)
|
||||||
|
{
|
||||||
|
if (questScenario[i] != null && questScenario[i].Id == (0xA0F00000 | id))
|
||||||
|
{
|
||||||
|
Database.RemoveQuest(this, questScenario[i].Id);
|
||||||
|
questScenario[i] = null;
|
||||||
|
playerWork.questScenario[i] = 0;
|
||||||
|
SendQuestClientUpdate(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveQuest(string name)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < questScenario.Length; i++)
|
||||||
|
{
|
||||||
|
if (questScenario[i] != null && questScenario[i].Name.ToLower().Equals(name.ToLower()))
|
||||||
|
{
|
||||||
|
Database.RemoveQuest(this, questScenario[i].Id);
|
||||||
|
questScenario[i] = null;
|
||||||
|
playerWork.questScenario[i] = 0;
|
||||||
|
SendQuestClientUpdate(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool HasQuest(string name)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < questScenario.Length; i++)
|
||||||
|
{
|
||||||
|
if (questScenario[i] != null && questScenario[i].Name.ToLower().Equals(name.ToLower()))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool HasQuest(uint id)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < questScenario.Length; i++)
|
||||||
|
{
|
||||||
|
if (questScenario[i] != null && questScenario[i].Id == (0xA0F00000 | id))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsQuestCompleted(uint id)
|
||||||
|
{
|
||||||
|
return questStateManager.IsQuestComplete(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetQuestComplete(uint id, bool flag)
|
||||||
|
{
|
||||||
|
if (flag)
|
||||||
|
{
|
||||||
|
Quest currentQuest = GetQuest(id);
|
||||||
|
if (currentQuest != null)
|
||||||
|
{
|
||||||
|
CompleteQuest(currentQuest);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
questStateManager.ForceQuestCompleteFlag(id, flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Quest GetQuest(uint id)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < questScenario.Length; i++)
|
||||||
|
{
|
||||||
|
if (questScenario[i] != null && questScenario[i].Id == (0xA0F00000 | id))
|
||||||
|
return questScenario[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Quest GetQuest(string name)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < questScenario.Length; i++)
|
||||||
|
{
|
||||||
|
if (questScenario[i] != null && questScenario[i].Name.ToLower().Equals(name.ToLower()))
|
||||||
|
return questScenario[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetQuestSlot(Quest quest)
|
||||||
|
{
|
||||||
|
for (int slot = 0; slot < questScenario.Length; slot++)
|
||||||
|
{
|
||||||
|
if (questScenario[slot] != null && questScenario[slot].Id == quest.Id)
|
||||||
|
return slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetQuestSlot(uint id)
|
||||||
|
{
|
||||||
|
for (int slot = 0; slot < questScenario.Length; slot++)
|
||||||
|
{
|
||||||
|
if (questScenario[slot] != null && questScenario[slot].GetQuestId() == id)
|
||||||
|
return slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Guildleves
|
||||||
public void AddGuildleve(uint id)
|
public void AddGuildleve(uint id)
|
||||||
{
|
{
|
||||||
int freeSlot = GetFreeGuildleveSlot();
|
int freeSlot = GetFreeGuildleveSlot();
|
||||||
|
@ -1486,178 +1771,6 @@ namespace Meteor.Map.Actors
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddQuest(uint id, bool isSilent = false)
|
|
||||||
{
|
|
||||||
Actor actor = Server.GetStaticActors((0xA0F00000 | id));
|
|
||||||
AddQuest(actor.Name, isSilent);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddQuest(string name, bool isSilent = false)
|
|
||||||
{
|
|
||||||
Quest baseQuest = (Quest) Server.GetStaticActors(name);
|
|
||||||
|
|
||||||
if (baseQuest == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
int freeSlot = GetFreeQuestSlot();
|
|
||||||
|
|
||||||
if (freeSlot == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
playerWork.questScenario[freeSlot] = baseQuest.Id;
|
|
||||||
questScenario[freeSlot] = new Quest(this, baseQuest);
|
|
||||||
Database.SaveQuest(this, questScenario[freeSlot]);
|
|
||||||
SendQuestClientUpdate(freeSlot);
|
|
||||||
|
|
||||||
if (!isSilent)
|
|
||||||
{
|
|
||||||
SendGameMessage(Server.GetWorldManager().GetActor(), 25224, 0x20, (object)questScenario[freeSlot].GetQuestId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CompleteQuest(uint id)
|
|
||||||
{
|
|
||||||
Actor actor = Server.GetStaticActors((0xA0F00000 | id));
|
|
||||||
CompleteQuest(actor.Name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CompleteQuest(string name)
|
|
||||||
{
|
|
||||||
Actor actor = Server.GetStaticActors(name);
|
|
||||||
|
|
||||||
if (actor == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
uint id = actor.Id;
|
|
||||||
if (HasQuest(id))
|
|
||||||
{
|
|
||||||
Database.CompleteQuest(playerSession.GetActor(), id);
|
|
||||||
SendGameMessage(Server.GetWorldManager().GetActor(), 25086, 0x20, (object)GetQuest(id).GetQuestId());
|
|
||||||
RemoveQuest(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: Add checks for you being in an instance or main scenario
|
|
||||||
public void AbandonQuest(uint id)
|
|
||||||
{
|
|
||||||
Quest quest = GetQuest(id);
|
|
||||||
RemoveQuestByQuestId(id);
|
|
||||||
quest.DoAbandon();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveQuestByQuestId(uint id)
|
|
||||||
{
|
|
||||||
RemoveQuest((0xA0F00000 | id));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveQuest(uint id)
|
|
||||||
{
|
|
||||||
if (HasQuest(id))
|
|
||||||
{
|
|
||||||
for (int i = 0; i < questScenario.Length; i++)
|
|
||||||
{
|
|
||||||
if (questScenario[i] != null && questScenario[i].Id == id)
|
|
||||||
{
|
|
||||||
Database.RemoveQuest(this, questScenario[i].Id);
|
|
||||||
questScenario[i] = null;
|
|
||||||
playerWork.questScenario[i] = 0;
|
|
||||||
SendQuestClientUpdate(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ReplaceQuest(Quest oldQuest, string questCode)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < questScenario.Length; i++)
|
|
||||||
{
|
|
||||||
if (questScenario[i] != null && questScenario[i].Equals(oldQuest))
|
|
||||||
{
|
|
||||||
Quest baseQuest = (Quest) Server.GetStaticActors(questCode);
|
|
||||||
questScenario[i] = new Quest(this, baseQuest);
|
|
||||||
playerWork.questScenario[i] = questScenario[i].Id;
|
|
||||||
Database.SaveQuest(this, questScenario[i]);
|
|
||||||
SendQuestClientUpdate(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool CanAcceptQuest(string name)
|
|
||||||
{
|
|
||||||
if (!IsQuestCompleted(name) && !HasQuest(name))
|
|
||||||
return true;
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool CanAcceptQuest(uint id)
|
|
||||||
{
|
|
||||||
Actor actor = Server.GetStaticActors((0xA0F00000 | id));
|
|
||||||
return CanAcceptQuest(actor.Name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsQuestCompleted(string questName)
|
|
||||||
{
|
|
||||||
Actor actor = Server.GetStaticActors(questName);
|
|
||||||
return IsQuestCompleted(actor.Id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsQuestCompleted(uint questId)
|
|
||||||
{
|
|
||||||
return Database.IsQuestCompleted(this, 0xFFFFF & questId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Quest GetQuest(uint id)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < questScenario.Length; i++)
|
|
||||||
{
|
|
||||||
if (questScenario[i] != null && questScenario[i].Id == (0xA0F00000 | id))
|
|
||||||
return questScenario[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Quest GetQuest(string name)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < questScenario.Length; i++)
|
|
||||||
{
|
|
||||||
if (questScenario[i] != null && questScenario[i].Name.ToLower().Equals(name.ToLower()))
|
|
||||||
return questScenario[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool HasQuest(string name)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < questScenario.Length; i++)
|
|
||||||
{
|
|
||||||
if (questScenario[i] != null && questScenario[i].Name.ToLower().Equals(name.ToLower()))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool HasQuest(uint id)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < questScenario.Length; i++)
|
|
||||||
{
|
|
||||||
if (questScenario[i] != null && questScenario[i].Id == (0xA0F00000 | id))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool HasQuest(Quest quest)
|
|
||||||
{
|
|
||||||
return HasQuest(quest.className);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool HasGuildleve(uint id)
|
public bool HasGuildleve(uint id)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < work.guildleveId.Length; i++)
|
for (int i = 0; i < work.guildleveId.Length; i++)
|
||||||
|
@ -1668,17 +1781,7 @@ namespace Meteor.Map.Actors
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
public int GetQuestSlot(uint id)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < questScenario.Length; i++)
|
|
||||||
{
|
|
||||||
if (questScenario[i] != null && questScenario[i].Id == (0xA0F00000 | id))
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Quest GetDefaultTalkQuest(Npc npc)
|
public Quest GetDefaultTalkQuest(Npc npc)
|
||||||
{
|
{
|
||||||
|
@ -1732,7 +1835,9 @@ namespace Meteor.Map.Actors
|
||||||
|
|
||||||
public Quest[] GetQuestsForNpc(Npc npc)
|
public Quest[] GetQuestsForNpc(Npc npc)
|
||||||
{
|
{
|
||||||
return Array.FindAll(questScenario, e => e != null && e.IsQuestENPC(this, npc));
|
Quest[] quests = questStateManager.GetQuestsForNpc(npc);
|
||||||
|
Array.Sort(quests, (q1, q2) => (q1.HasData() ? 1 : 0) - (q2.HasData() ? 1 : 0));
|
||||||
|
return quests;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void HandleNpcLS(uint id)
|
public void HandleNpcLS(uint id)
|
||||||
|
@ -2755,6 +2860,7 @@ namespace Meteor.Map.Actors
|
||||||
actionList.Add(new CommandResult(Id, 33909, 0, (ushort)charaWork.battleSave.skillLevel[classId - 1]));
|
actionList.Add(new CommandResult(Id, 33909, 0, (ushort)charaWork.battleSave.skillLevel[classId - 1]));
|
||||||
|
|
||||||
EquipAbilitiesAtLevel(classId, GetLevel(), actionList);
|
EquipAbilitiesAtLevel(classId, GetLevel(), actionList);
|
||||||
|
questStateManager.UpdateLevel(GetHighestLevel());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
===========================================================================
|
===========================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Meteor.Map.dataobjects.chara
|
namespace Meteor.Map.DataObjects.chara
|
||||||
{
|
{
|
||||||
class PlayerWork
|
class PlayerWork
|
||||||
{
|
{
|
||||||
|
|
|
@ -21,7 +21,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
|
|
||||||
using Meteor.Map.actors.chara.player;
|
using Meteor.Map.actors.chara.player;
|
||||||
using Meteor.Map.Actors;
|
using Meteor.Map.Actors;
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using Meteor.Map.packets.send.actor.inventory;
|
using Meteor.Map.packets.send.actor.inventory;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|
|
@ -22,7 +22,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
using Meteor.Common;
|
using Meteor.Common;
|
||||||
using Meteor.Map.actors.director.Work;
|
using Meteor.Map.actors.director.Work;
|
||||||
using Meteor.Map.Actors;
|
using Meteor.Map.Actors;
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using Meteor.Map.utils;
|
using Meteor.Map.utils;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
|
@ -23,7 +23,7 @@ using Meteor.Common;
|
||||||
using Meteor.Map.actors.director;
|
using Meteor.Map.actors.director;
|
||||||
using Meteor.Map.actors.group.Work;
|
using Meteor.Map.actors.group.Work;
|
||||||
using Meteor.Map.Actors;
|
using Meteor.Map.Actors;
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using Meteor.Map.packets.send.group;
|
using Meteor.Map.packets.send.group;
|
||||||
using Meteor.Map.packets.send.groups;
|
using Meteor.Map.packets.send.groups;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
|
@ -20,7 +20,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using Meteor.Common;
|
using Meteor.Common;
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using Meteor.Map.packets.send.group;
|
using Meteor.Map.packets.send.group;
|
||||||
using Meteor.Map.packets.send.groups;
|
using Meteor.Map.packets.send.groups;
|
||||||
using System;
|
using System;
|
||||||
|
|
|
@ -20,7 +20,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using Meteor.Common;
|
using Meteor.Common;
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using Meteor.Map.packets.send.group;
|
using Meteor.Map.packets.send.group;
|
||||||
using Meteor.Map.packets.send.groups;
|
using Meteor.Map.packets.send.groups;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
|
@ -21,7 +21,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
|
|
||||||
using Meteor.Common;
|
using Meteor.Common;
|
||||||
using Meteor.Map.actors.group.Work;
|
using Meteor.Map.actors.group.Work;
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using Meteor.Map.packets.send.group;
|
using Meteor.Map.packets.send.group;
|
||||||
using Meteor.Map.packets.send.groups;
|
using Meteor.Map.packets.send.groups;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
|
@ -22,7 +22,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
using Meteor.Common;
|
using Meteor.Common;
|
||||||
using Meteor.Map.actors.chara.npc;
|
using Meteor.Map.actors.chara.npc;
|
||||||
using Meteor.Map.Actors;
|
using Meteor.Map.Actors;
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using Meteor.Map.packets.send.group;
|
using Meteor.Map.packets.send.group;
|
||||||
using Meteor.Map.packets.send.groups;
|
using Meteor.Map.packets.send.groups;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
|
@ -21,7 +21,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
|
|
||||||
using Meteor.Common;
|
using Meteor.Common;
|
||||||
using Meteor.Map.actors.group.Work;
|
using Meteor.Map.actors.group.Work;
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using Meteor.Map.packets.send.group;
|
using Meteor.Map.packets.send.group;
|
||||||
using Meteor.Map.packets.send.groups;
|
using Meteor.Map.packets.send.groups;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
|
@ -20,113 +20,124 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using Meteor.Map.lua;
|
using Meteor.Map.lua;
|
||||||
using Newtonsoft.Json;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Meteor.Map.Actors
|
namespace Meteor.Map.Actors.QuestNS
|
||||||
{
|
{
|
||||||
class Quest : Actor
|
class Quest : Actor
|
||||||
{
|
{
|
||||||
public const ushort SEQ_NOT_STARTED = ushort.MaxValue;
|
public const ushort SEQ_NOT_STARTED = 65535;
|
||||||
|
public const ushort SEQ_COMPLETED = 65534;
|
||||||
|
|
||||||
public enum QuestFlag { None = 0, Map = 1, Plate = 2 }
|
private Player owner;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private struct QuestData
|
|
||||||
{
|
|
||||||
public UInt32 flags;
|
|
||||||
public UInt16 counter1;
|
|
||||||
public UInt16 counter2;
|
|
||||||
public UInt16 counter3;
|
|
||||||
public UInt16 counter4;
|
|
||||||
|
|
||||||
public QuestData(uint flags, ushort counter1, ushort counter2, ushort counter3) : this()
|
|
||||||
{
|
|
||||||
this.flags = flags;
|
|
||||||
this.counter1 = counter1;
|
|
||||||
this.counter2 = counter2;
|
|
||||||
this.counter3 = counter3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Player Owner;
|
|
||||||
private ushort currentSequence;
|
private ushort currentSequence;
|
||||||
private QuestData data = new QuestData();
|
private QuestState questState = null;
|
||||||
private bool dataDirty = false;
|
private QuestData data = null;
|
||||||
private Dictionary<uint, ENpcQuestInstance> CurrentENPCs = new Dictionary<uint, ENpcQuestInstance>();
|
|
||||||
private Dictionary<uint, ENpcQuestInstance> OldENPCs = new Dictionary<uint, ENpcQuestInstance>();
|
|
||||||
|
|
||||||
public void AddENpc(uint classId, byte flagType = 0, bool isTalkEnabled = true, bool isPushEnabled = false, bool isEmoteEnabled = false, bool isSpawned = false)
|
// Creates a Static Quest for the StaticActors list.
|
||||||
|
public Quest(uint actorID, string className, string classPath)
|
||||||
|
: base(actorID)
|
||||||
{
|
{
|
||||||
ENpcQuestInstance instanceUpdated = null;
|
Name = className;
|
||||||
|
this.className = className;
|
||||||
if (OldENPCs.ContainsKey(classId))
|
this.classPath = classPath;
|
||||||
{
|
|
||||||
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]);
|
// Creates a Static Quest from another Static Quest
|
||||||
OldENPCs.Remove(classId);
|
public Quest(Quest staticQuest)
|
||||||
}
|
: this(staticQuest.Id, staticQuest.Name, staticQuest.classPath)
|
||||||
else
|
{ }
|
||||||
|
|
||||||
|
// Creates a Instance Quest that has been started.
|
||||||
|
public Quest(Player owner, Quest staticQuest, ushort sequence) : this(staticQuest)
|
||||||
{
|
{
|
||||||
instanceUpdated = new ENpcQuestInstance(classId, flagType, isSpawned, isTalkEnabled, isEmoteEnabled, isPushEnabled);
|
this.owner = owner;
|
||||||
CurrentENPCs.Add(classId, instanceUpdated);
|
currentSequence = sequence;
|
||||||
|
questState = new QuestState(owner, this);
|
||||||
|
questState.UpdateState();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (instanceUpdated != null)
|
// Creates a Instance Quest that has not been started.
|
||||||
Owner.playerSession.UpdateQuestNpcInInstance(instanceUpdated);
|
public Quest(Player owner, Quest staticQuest) : this(owner, staticQuest, SEQ_NOT_STARTED)
|
||||||
}
|
{ }
|
||||||
|
|
||||||
public ENpcQuestInstance GetENpcInstance(uint classId)
|
#region Getters
|
||||||
|
public uint GetQuestId()
|
||||||
{
|
{
|
||||||
if (CurrentENPCs.ContainsKey(classId))
|
return Id & 0xFFFFF;
|
||||||
return CurrentENPCs[classId];
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
if (obj != null && obj is Quest quest)
|
||||||
|
return quest.Id == this.Id;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return base.GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsInstance()
|
||||||
|
{
|
||||||
|
return questState != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsMainScenario()
|
||||||
|
{
|
||||||
|
uint id = GetQuestId();
|
||||||
|
return id >= 110001 && id <= 110021;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ushort GetSequence()
|
||||||
|
{
|
||||||
|
return currentSequence;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Quest Data
|
||||||
|
public void SetData(uint flags, ushort counter1, ushort counter2, ushort counter3, ushort counter4)
|
||||||
|
{
|
||||||
|
data = new QuestData(owner, this, flags, counter1, counter2, counter3, counter4);
|
||||||
|
}
|
||||||
|
|
||||||
|
public QuestData GetData()
|
||||||
|
{
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool HasData()
|
||||||
|
{
|
||||||
|
return data != null;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Quest State
|
||||||
|
public void SetENpc(uint classId, byte flagType = 0, bool isTalkEnabled = true, bool isPushEnabled = false, bool isEmoteEnabled = false, bool isSpawned = false)
|
||||||
|
{
|
||||||
|
if (questState != null)
|
||||||
|
questState.AddENpc(classId, flagType, isTalkEnabled, isPushEnabled, isEmoteEnabled, isSpawned);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateENPCs()
|
||||||
|
{
|
||||||
|
if (data.Dirty)
|
||||||
|
{
|
||||||
|
if (questState != null)
|
||||||
|
questState.UpdateState();
|
||||||
|
data.ClearDirty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public QuestState GetQuestState()
|
||||||
|
{
|
||||||
|
return questState;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Script Callbacks
|
||||||
public void OnTalk(Player caller, Npc npc)
|
public void OnTalk(Player caller, Npc npc)
|
||||||
{
|
{
|
||||||
LuaEngine.GetInstance().CallLuaFunction(caller, this, "onTalk", true, npc);
|
LuaEngine.GetInstance().CallLuaFunction(caller, this, "onTalk", true, npc);
|
||||||
|
@ -152,31 +163,9 @@ namespace Meteor.Map.Actors
|
||||||
LuaEngine.GetInstance().CallLuaFunction(caller, this, "onNpcLS", true, npcLSId);
|
LuaEngine.GetInstance().CallLuaFunction(caller, this, "onNpcLS", true, npcLSId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateENPCs()
|
|
||||||
{
|
|
||||||
if (dataDirty)
|
|
||||||
{
|
|
||||||
OldENPCs = CurrentENPCs;
|
|
||||||
CurrentENPCs = new Dictionary<uint, ENpcQuestInstance>();
|
|
||||||
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<LuaParam> 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());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public object[] GetJournalInformation()
|
public object[] GetJournalInformation()
|
||||||
{
|
{
|
||||||
List<LuaParam> returned = LuaEngine.GetInstance().CallLuaFunctionForReturn(Owner, this, "getJournalInformation", true);
|
List<LuaParam> returned = LuaEngine.GetInstance().CallLuaFunctionForReturn(owner, this, "getJournalInformation", true);
|
||||||
if (returned != null && returned.Count != 0)
|
if (returned != null && returned.Count != 0)
|
||||||
return LuaUtils.CreateLuaParamObjectList(returned);
|
return LuaUtils.CreateLuaParamObjectList(returned);
|
||||||
else
|
else
|
||||||
|
@ -185,16 +174,19 @@ namespace Meteor.Map.Actors
|
||||||
|
|
||||||
public object[] GetJournalMapMarkerList()
|
public object[] GetJournalMapMarkerList()
|
||||||
{
|
{
|
||||||
List<LuaParam> returned = LuaEngine.GetInstance().CallLuaFunctionForReturn(Owner, this, "getJournalMapMarkerList", true);
|
List<LuaParam> returned = LuaEngine.GetInstance().CallLuaFunctionForReturn(owner, this, "getJournalMapMarkerList", true);
|
||||||
if (returned != null && returned.Count != 0)
|
if (returned != null && returned.Count != 0)
|
||||||
return LuaUtils.CreateLuaParamObjectList(returned);
|
return LuaUtils.CreateLuaParamObjectList(returned);
|
||||||
else
|
else
|
||||||
return new object[0];
|
return new object[0];
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
public ushort GetSequence()
|
public bool IsQuestENPC(Player caller, Npc npc)
|
||||||
{
|
{
|
||||||
return currentSequence;
|
List<LuaParam> returned = LuaEngine.GetInstance().CallLuaFunctionForReturn(caller, this, "IsQuestENPC", true, npc, this);
|
||||||
|
bool scriptReturned = returned != null && returned.Count != 0 && returned[0].typeID == 3;
|
||||||
|
return scriptReturned || questState.HasENpc(npc.GetActorClassId());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StartSequence(ushort sequence)
|
public void StartSequence(ushort sequence)
|
||||||
|
@ -204,180 +196,36 @@ namespace Meteor.Map.Actors
|
||||||
|
|
||||||
// Send the message that the journal has been updated
|
// Send the message that the journal has been updated
|
||||||
if (currentSequence != SEQ_NOT_STARTED)
|
if (currentSequence != SEQ_NOT_STARTED)
|
||||||
Owner.SendGameMessage(Server.GetWorldManager().GetActor(), 25116, 0x20, (object)GetQuestId());
|
owner.SendGameMessage(Server.GetWorldManager().GetActor(), 25116, 0x20, (object)GetQuestId());
|
||||||
|
|
||||||
currentSequence = sequence;
|
currentSequence = sequence;
|
||||||
dataDirty = true;
|
questState.UpdateState();
|
||||||
UpdateENPCs();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ClearData()
|
public void OnAccept()
|
||||||
{
|
{
|
||||||
data.flags = data.counter1 = data.counter2 = data.counter3 = data.counter4 = 0;
|
data = new QuestData(owner, this);
|
||||||
}
|
|
||||||
|
|
||||||
public void SetFlag(int index)
|
|
||||||
{
|
|
||||||
if (index >= 0 && index < 32)
|
|
||||||
{
|
|
||||||
data.flags |= (uint)(1 << index);
|
|
||||||
dataDirty = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ClearFlag(int index)
|
|
||||||
{
|
|
||||||
if (index >= 0 && index < 32)
|
|
||||||
{
|
|
||||||
data.flags &= (uint)~(1 << index);
|
|
||||||
dataDirty = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void IncCounter(int num)
|
|
||||||
{
|
|
||||||
dataDirty = true;
|
|
||||||
|
|
||||||
switch (num)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
data.counter1++;
|
|
||||||
return;
|
|
||||||
case 1:
|
|
||||||
data.counter2++;
|
|
||||||
return;
|
|
||||||
case 2:
|
|
||||||
data.counter3++;
|
|
||||||
return;
|
|
||||||
case 3:
|
|
||||||
data.counter4++;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dataDirty = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DecCounter(int num)
|
|
||||||
{
|
|
||||||
dataDirty = true;
|
|
||||||
|
|
||||||
switch (num)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
data.counter1--;
|
|
||||||
return;
|
|
||||||
case 1:
|
|
||||||
data.counter2--;
|
|
||||||
return;
|
|
||||||
case 2:
|
|
||||||
data.counter3--;
|
|
||||||
return;
|
|
||||||
case 3:
|
|
||||||
data.counter4--;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dataDirty = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetCounter(int num, ushort value)
|
|
||||||
{
|
|
||||||
dataDirty = true;
|
|
||||||
|
|
||||||
switch (num)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
data.counter1 = value;
|
|
||||||
return;
|
|
||||||
case 1:
|
|
||||||
data.counter2 = value;
|
|
||||||
return;
|
|
||||||
case 2:
|
|
||||||
data.counter3 = value;
|
|
||||||
return;
|
|
||||||
case 3:
|
|
||||||
data.counter4 = value;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
dataDirty = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool GetFlag(int index)
|
|
||||||
{
|
|
||||||
if (index >= 0 && index < 32)
|
|
||||||
return (data.flags & (uint) (1 << index)) != 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public uint GetFlags()
|
|
||||||
{
|
|
||||||
return data.flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ushort GetCounter(int num)
|
|
||||||
{
|
|
||||||
switch (num)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
return data.counter1;
|
|
||||||
case 1:
|
|
||||||
return data.counter2;
|
|
||||||
case 2:
|
|
||||||
return data.counter3;
|
|
||||||
case 3:
|
|
||||||
return data.counter4;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SaveData()
|
|
||||||
{
|
|
||||||
Database.SaveQuest(Owner, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Quest(uint actorID, string name)
|
|
||||||
: base(actorID)
|
|
||||||
{
|
|
||||||
Name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Quest(Player owner, Quest baseQuest): this(owner, baseQuest, SEQ_NOT_STARTED, 0, 0, 0, 0)
|
|
||||||
{}
|
|
||||||
|
|
||||||
public Quest(Player owner, Quest baseQuest, ushort sequence, uint flags, ushort counter1, ushort counter2, ushort counter3)
|
|
||||||
: base(baseQuest.Id)
|
|
||||||
{
|
|
||||||
Owner = owner;
|
|
||||||
Name = baseQuest.Name;
|
|
||||||
className = baseQuest.className;
|
|
||||||
classPath = baseQuest.classPath;
|
|
||||||
currentSequence = sequence;
|
|
||||||
data = new QuestData(flags, counter1, counter2, counter3);
|
|
||||||
|
|
||||||
if (currentSequence == SEQ_NOT_STARTED)
|
if (currentSequence == SEQ_NOT_STARTED)
|
||||||
LuaEngine.GetInstance().CallLuaFunction(Owner, this, "onStart", false);
|
LuaEngine.GetInstance().CallLuaFunction(owner, this, "onStart", false);
|
||||||
else
|
else
|
||||||
StartSequence(currentSequence);
|
StartSequence(currentSequence);
|
||||||
}
|
}
|
||||||
|
|
||||||
public uint GetQuestId()
|
public void OnComplete()
|
||||||
{
|
{
|
||||||
return Id & 0xFFFFF;
|
LuaEngine.GetInstance().CallLuaFunctionForReturn(owner, this, "onFinish", true);
|
||||||
|
currentSequence = SEQ_COMPLETED;
|
||||||
|
data = null;
|
||||||
|
questState.UpdateState();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DoComplete()
|
public void OnAbandon()
|
||||||
{
|
{
|
||||||
LuaEngine.GetInstance().CallLuaFunctionForReturn(Owner, this, "onFinish", true);
|
LuaEngine.GetInstance().CallLuaFunctionForReturn(owner, this, "onFinish", false);
|
||||||
Owner.SendDataPacket("attention", Server.GetWorldManager().GetActor(), "", 25225, (object)GetQuestId());
|
currentSequence = SEQ_NOT_STARTED;
|
||||||
Owner.SendGameMessage(Server.GetWorldManager().GetActor(), 25225, 0x20, (object)GetQuestId());
|
data = null;
|
||||||
|
questState.UpdateState();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DoAbandon()
|
|
||||||
{
|
|
||||||
LuaEngine.GetInstance().CallLuaFunctionForReturn(Owner, this, "onFinish", false);
|
|
||||||
Owner.SendGameMessage(Owner, Server.GetWorldManager().GetActor(), 25236, 0x20, (object)GetQuestId());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
173
Map Server/Actors/Quest/QuestData.cs
Normal file
173
Map Server/Actors/Quest/QuestData.cs
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Meteor.Map.Actors.QuestNS
|
||||||
|
{
|
||||||
|
class QuestData
|
||||||
|
{
|
||||||
|
private Player owner;
|
||||||
|
private Quest parent;
|
||||||
|
|
||||||
|
private uint flags;
|
||||||
|
private ushort counter1;
|
||||||
|
private ushort counter2;
|
||||||
|
private ushort counter3;
|
||||||
|
private ushort counter4;
|
||||||
|
|
||||||
|
public bool Dirty { get; private set; } = false;
|
||||||
|
|
||||||
|
public QuestData(Player owner, Quest parent, uint flags, ushort counter1, ushort counter2, ushort counter3, ushort counter4)
|
||||||
|
{
|
||||||
|
this.owner = owner;
|
||||||
|
this.parent = parent;
|
||||||
|
this.flags = flags;
|
||||||
|
this.counter1 = counter1;
|
||||||
|
this.counter2 = counter2;
|
||||||
|
this.counter3 = counter3;
|
||||||
|
this.counter4 = counter4;
|
||||||
|
}
|
||||||
|
|
||||||
|
public QuestData(Player owner, Quest parent)
|
||||||
|
{
|
||||||
|
this.owner = owner;
|
||||||
|
this.parent = parent;
|
||||||
|
flags = counter1 = counter2 = counter3 = counter4 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearData()
|
||||||
|
{
|
||||||
|
flags = counter1 = counter2 = counter3 = counter4 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetFlag(int index)
|
||||||
|
{
|
||||||
|
if (index >= 0 && index < 32)
|
||||||
|
{
|
||||||
|
flags |= (uint)(1 << index);
|
||||||
|
Dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearFlag(int index)
|
||||||
|
{
|
||||||
|
if (index >= 0 && index < 32)
|
||||||
|
{
|
||||||
|
flags &= (uint)~(1 << index);
|
||||||
|
Dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ushort IncCounter(int num)
|
||||||
|
{
|
||||||
|
Dirty = true;
|
||||||
|
|
||||||
|
switch (num)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
counter1++;
|
||||||
|
return counter1;
|
||||||
|
case 1:
|
||||||
|
counter2++;
|
||||||
|
return counter2;
|
||||||
|
case 2:
|
||||||
|
counter3++;
|
||||||
|
return counter3;
|
||||||
|
case 3:
|
||||||
|
counter4++;
|
||||||
|
return counter4;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dirty = false;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ushort DecCounter(int num)
|
||||||
|
{
|
||||||
|
Dirty = true;
|
||||||
|
|
||||||
|
switch (num)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
counter1--;
|
||||||
|
return counter1;
|
||||||
|
case 1:
|
||||||
|
counter2--;
|
||||||
|
return counter2;
|
||||||
|
case 2:
|
||||||
|
counter3--;
|
||||||
|
return counter3;
|
||||||
|
case 3:
|
||||||
|
counter4--;
|
||||||
|
return counter4;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dirty = false;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetCounter(int num, ushort value)
|
||||||
|
{
|
||||||
|
Dirty = true;
|
||||||
|
|
||||||
|
switch (num)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
counter1 = value;
|
||||||
|
return;
|
||||||
|
case 1:
|
||||||
|
counter2 = value;
|
||||||
|
return;
|
||||||
|
case 2:
|
||||||
|
counter3 = value;
|
||||||
|
return;
|
||||||
|
case 3:
|
||||||
|
counter4 = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool GetFlag(int index)
|
||||||
|
{
|
||||||
|
if (index >= 0 && index < 32)
|
||||||
|
return (flags & (uint)(1 << index)) != 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint GetFlags()
|
||||||
|
{
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ushort GetCounter(int num)
|
||||||
|
{
|
||||||
|
switch (num)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return counter1;
|
||||||
|
case 1:
|
||||||
|
return counter2;
|
||||||
|
case 2:
|
||||||
|
return counter3;
|
||||||
|
case 3:
|
||||||
|
return counter4;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearDirty()
|
||||||
|
{
|
||||||
|
Dirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Save()
|
||||||
|
{
|
||||||
|
Database.UpdateQuest(owner, parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
118
Map Server/Actors/Quest/QuestState.cs
Normal file
118
Map Server/Actors/Quest/QuestState.cs
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
using Meteor.Map.lua;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Meteor.Map.Actors.QuestNS
|
||||||
|
{
|
||||||
|
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 readonly Player Owner;
|
||||||
|
private readonly Quest Parent;
|
||||||
|
private Dictionary<uint, QuestENpc> CurrentENPCs = new Dictionary<uint, QuestENpc>();
|
||||||
|
private Dictionary<uint, QuestENpc> OldENPCs = new Dictionary<uint, QuestENpc>();
|
||||||
|
|
||||||
|
public QuestState(Player owner, Quest parent)
|
||||||
|
{
|
||||||
|
Owner = owner;
|
||||||
|
Parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
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<uint, QuestENpc>();
|
||||||
|
LuaEngine.GetInstance().CallLuaFunctionForReturn(Owner, Parent, "onStateChange", false, currentSeq);
|
||||||
|
foreach (var enpc in OldENPCs)
|
||||||
|
Owner.playerSession.UpdateQuestNpcInInstance(enpc.Value, true);
|
||||||
|
OldENPCs = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeleteState()
|
||||||
|
{
|
||||||
|
foreach (var enpc in CurrentENPCs)
|
||||||
|
Owner.playerSession.UpdateQuestNpcInInstance(enpc.Value, true);
|
||||||
|
CurrentENPCs.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
178
Map Server/Actors/Quest/QuestStateManager.cs
Normal file
178
Map Server/Actors/Quest/QuestStateManager.cs
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
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.QuestNS
|
||||||
|
{
|
||||||
|
class QuestStateManager
|
||||||
|
{
|
||||||
|
private const int SCENARIO_START = 110001;
|
||||||
|
private const int SCENARIO_MAX = 2048;
|
||||||
|
|
||||||
|
private readonly Player player;
|
||||||
|
private readonly Bitstream CompletedQuestsBitfield = new Bitstream(SCENARIO_MAX);
|
||||||
|
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<Quest> ActiveQuests = new List<Quest>();
|
||||||
|
private Dictionary<uint, QuestState> QuestStateTable = new Dictionary<uint, QuestState>();
|
||||||
|
|
||||||
|
public QuestStateManager(Player player)
|
||||||
|
{
|
||||||
|
this.player = player;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Init(Quest[] journalQuests, bool[] completedQuests)
|
||||||
|
{
|
||||||
|
// Preload any quests that the player loaded
|
||||||
|
if (journalQuests != null)
|
||||||
|
{
|
||||||
|
foreach (var quest in journalQuests)
|
||||||
|
{
|
||||||
|
if (quest != null)
|
||||||
|
{
|
||||||
|
ActiveQuests.Add(quest);
|
||||||
|
AvailableQuestsBitfield.Set(quest.GetQuestId() - SCENARIO_START);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init MinLv
|
||||||
|
QuestGameData[] minLvl = Server.GetQuestGamedataByMaxLvl(player.GetHighestLevel(), true);
|
||||||
|
foreach (var questData in minLvl)
|
||||||
|
MinLevelBitfield.Set(questData.Id - SCENARIO_START);
|
||||||
|
|
||||||
|
// Init Prereq
|
||||||
|
CompletedQuestsBitfield.SetTo(completedQuests);
|
||||||
|
foreach (var questData in Server.GetQuestGamedataAllPrerequisite())
|
||||||
|
{
|
||||||
|
if (CompletedQuestsBitfield.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)
|
||||||
|
{
|
||||||
|
QuestGameData[] updated = Server.GetQuestGamedataByMaxLvl(level);
|
||||||
|
foreach (var questData in updated)
|
||||||
|
MinLevelBitfield.Set(questData.Id - SCENARIO_START);
|
||||||
|
ComputeAvailable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateQuestCompleted(Quest quest)
|
||||||
|
{
|
||||||
|
CompletedQuestsBitfield.Set(quest.Id - SCENARIO_START);
|
||||||
|
QuestGameData[] updated = Server.GetQuestGamedataByPrerequisite(quest.GetQuestId());
|
||||||
|
foreach (var questData in updated)
|
||||||
|
PrereqBitfield.Set(questData.Id - SCENARIO_START);
|
||||||
|
ComputeAvailable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateQuestAbandoned()
|
||||||
|
{
|
||||||
|
ComputeAvailable();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ComputeAvailable()
|
||||||
|
{
|
||||||
|
Bitstream result = new Bitstream(SCENARIO_MAX);
|
||||||
|
result.OR(CompletedQuestsBitfield);
|
||||||
|
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))
|
||||||
|
AddActiveQuest(quest);
|
||||||
|
else
|
||||||
|
RemoveActiveQuest(quest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AvailableQuestsBitfield.SetTo(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ForceAddActiveQuest(Quest questInstance)
|
||||||
|
{
|
||||||
|
ActiveQuests.Add(questInstance);
|
||||||
|
QuestStateTable.Add(questInstance.Id, questInstance.GetQuestState());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddActiveQuest(Quest staticQuest)
|
||||||
|
{
|
||||||
|
Quest instance = new Quest(player, staticQuest);
|
||||||
|
ActiveQuests.Add(instance);
|
||||||
|
QuestStateTable.Add(staticQuest.Id, instance.GetQuestState());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoveActiveQuest(Quest staticQuest)
|
||||||
|
{
|
||||||
|
// Do not remove quests in the player's journal
|
||||||
|
if (player.HasQuest(staticQuest.GetQuestId()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ActiveQuests.Remove(staticQuest);
|
||||||
|
|
||||||
|
if (QuestStateTable.ContainsKey(staticQuest.Id))
|
||||||
|
{
|
||||||
|
QuestStateTable[staticQuest.Id].DeleteState();
|
||||||
|
QuestStateTable.Remove(staticQuest.Id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Quest GetActiveQuest(uint id)
|
||||||
|
{
|
||||||
|
return ActiveQuests.Find(quest => quest.GetQuestId() == id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Quest[] GetQuestsForNpc(Npc npc)
|
||||||
|
{
|
||||||
|
return ActiveQuests.FindAll(quest => quest.IsQuestENPC(player, npc)).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] GetCompletionSliceBytes(ushort from, ushort to)
|
||||||
|
{
|
||||||
|
return CompletedQuestsBitfield.GetSlice(from, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsQuestComplete(uint questId)
|
||||||
|
{
|
||||||
|
return CompletedQuestsBitfield.Get(questId - SCENARIO_START);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ForceQuestCompleteFlag(uint questId, bool flag)
|
||||||
|
{
|
||||||
|
if (flag)
|
||||||
|
CompletedQuestsBitfield.Set(questId - SCENARIO_START);
|
||||||
|
else
|
||||||
|
CompletedQuestsBitfield.Clear(questId - SCENARIO_START);
|
||||||
|
ComputeAvailable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,6 +20,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using Meteor.Common;
|
using Meteor.Common;
|
||||||
|
using Meteor.Map.Actors.QuestNS;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
@ -98,7 +99,7 @@ namespace Meteor.Map.Actors
|
||||||
if (actorType.Equals("Command"))
|
if (actorType.Equals("Command"))
|
||||||
actor = new Command(id, actorName);
|
actor = new Command(id, actorName);
|
||||||
else if (actorType.Equals("Quest"))
|
else if (actorType.Equals("Quest"))
|
||||||
actor = new Quest(id, actorName);
|
actor = new Quest(id, actorName, output);
|
||||||
//else if (actorType.Equals("Status"))
|
//else if (actorType.Equals("Status"))
|
||||||
//mStaticActors.Add(id, new Status(id, actorName));
|
//mStaticActors.Add(id, new Status(id, actorName));
|
||||||
else if (actorType.Equals("Judge"))
|
else if (actorType.Equals("Judge"))
|
||||||
|
|
|
@ -22,7 +22,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Meteor.Map.packets.send;
|
using Meteor.Map.packets.send;
|
||||||
|
|
|
@ -21,7 +21,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
|
|
||||||
using MySql.Data.MySqlClient;
|
using MySql.Data.MySqlClient;
|
||||||
|
|
||||||
namespace Meteor.Map.dataobjects
|
namespace Meteor.Map.DataObjects
|
||||||
{
|
{
|
||||||
class GuildleveData
|
class GuildleveData
|
||||||
{
|
{
|
||||||
|
|
|
@ -25,7 +25,7 @@ using MySql.Data.MySqlClient;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace Meteor.Map.dataobjects
|
namespace Meteor.Map.DataObjects
|
||||||
{
|
{
|
||||||
class InventoryItem
|
class InventoryItem
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,7 +22,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
using MySql.Data.MySqlClient;
|
using MySql.Data.MySqlClient;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Meteor.Map.dataobjects
|
namespace Meteor.Map.DataObjects
|
||||||
{
|
{
|
||||||
class ItemData
|
class ItemData
|
||||||
{
|
{
|
||||||
|
|
28
Map Server/DataObjects/QuestGameData.cs
Normal file
28
Map Server/DataObjects/QuestGameData.cs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Meteor.Map.DataObjects
|
||||||
|
{
|
||||||
|
class QuestGameData
|
||||||
|
{
|
||||||
|
public uint Id { get; }
|
||||||
|
public string ClassName { get; }
|
||||||
|
public string Name { get; }
|
||||||
|
public uint PrerequisiteQuest { get; }
|
||||||
|
public int MinLevel { get; }
|
||||||
|
public int MinGCRank { get; }
|
||||||
|
|
||||||
|
public QuestGameData(uint id, string className, string name, uint prereq, int minLv, int minGcRank)
|
||||||
|
{
|
||||||
|
Id = id;
|
||||||
|
ClassName = className;
|
||||||
|
Name = Name;
|
||||||
|
PrerequisiteQuest = prereq;
|
||||||
|
MinLevel = minLv;
|
||||||
|
MinGCRank = minGcRank;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,7 +19,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
===========================================================================
|
===========================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Meteor.Map.dataobjects
|
namespace Meteor.Map.DataObjects
|
||||||
{
|
{
|
||||||
class RecruitmentDetails
|
class RecruitmentDetails
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,7 +19,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
===========================================================================
|
===========================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Meteor.Map.dataobjects
|
namespace Meteor.Map.DataObjects
|
||||||
{
|
{
|
||||||
class SeamlessBoundry
|
class SeamlessBoundry
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,7 +23,7 @@ using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Meteor.Map.dataobjects
|
namespace Meteor.Map.DataObjects
|
||||||
{
|
{
|
||||||
class SearchEntry
|
class SearchEntry
|
||||||
{
|
{
|
||||||
|
|
|
@ -25,9 +25,10 @@ using Meteor.Map.Actors;
|
||||||
using Meteor.Map.packets.send.actor;
|
using Meteor.Map.packets.send.actor;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Meteor.Map.actors.chara.npc;
|
using Meteor.Map.actors.chara.npc;
|
||||||
using static Meteor.Map.Actors.Quest;
|
using Meteor.Map.Actors.QuestNS;
|
||||||
|
using static Meteor.Map.Actors.QuestNS.QuestState;
|
||||||
|
|
||||||
namespace Meteor.Map.dataobjects
|
namespace Meteor.Map.DataObjects
|
||||||
{
|
{
|
||||||
class Session
|
class Session
|
||||||
{
|
{
|
||||||
|
@ -167,7 +168,7 @@ namespace Meteor.Map.dataobjects
|
||||||
Quest[] quests = playerActor.GetQuestsForNpc(npc);
|
Quest[] quests = playerActor.GetQuestsForNpc(npc);
|
||||||
if (quests.Length != 0)
|
if (quests.Length != 0)
|
||||||
{
|
{
|
||||||
ENpcQuestInstance questInstance = quests[0].GetENpcInstance(npc.GetActorClassId());
|
QuestENpc questInstance = quests[0].GetQuestState().GetENpc(npc.GetActorClassId());
|
||||||
QueuePacket(npc.GetSetEventStatusPackets());
|
QueuePacket(npc.GetSetEventStatusPackets());
|
||||||
QueuePacket(SetActorQuestGraphicPacket.BuildPacket(npc.Id, questInstance.questFlagType));
|
QueuePacket(SetActorQuestGraphicPacket.BuildPacket(npc.Id, questInstance.questFlagType));
|
||||||
}
|
}
|
||||||
|
@ -179,7 +180,7 @@ namespace Meteor.Map.dataobjects
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateQuestNpcInInstance(ENpcQuestInstance questInstance, bool clearInstance = false)
|
public void UpdateQuestNpcInInstance(QuestENpc questInstance, bool clearInstance = false)
|
||||||
{
|
{
|
||||||
LockUpdates(true);
|
LockUpdates(true);
|
||||||
Actor actor = actorInstanceList.Find(x => x is Npc npc && npc.GetActorClassId().Equals(questInstance.actorClassId));
|
Actor actor = actorInstanceList.Find(x => x is Npc npc && npc.GetActorClassId().Equals(questInstance.actorClassId));
|
||||||
|
|
|
@ -19,6 +19,6 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
===========================================================================
|
===========================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Meteor.Map.dataobjects
|
namespace Meteor.Map.DataObjects
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ using System.Collections.Concurrent;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using Meteor.Map.packets.WorldPackets.Send;
|
using Meteor.Map.packets.WorldPackets.Send;
|
||||||
|
|
||||||
namespace Meteor.Map.dataobjects
|
namespace Meteor.Map.DataObjects
|
||||||
{
|
{
|
||||||
class ZoneConnection
|
class ZoneConnection
|
||||||
{
|
{
|
||||||
|
|
|
@ -26,14 +26,15 @@ using Meteor.Common;
|
||||||
using Meteor.Map.utils;
|
using Meteor.Map.utils;
|
||||||
|
|
||||||
using Meteor.Map.packets.send.player;
|
using Meteor.Map.packets.send.player;
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using Meteor.Map.Actors;
|
using Meteor.Map.Actors;
|
||||||
|
using Meteor.Map.Actors.QuestNS;
|
||||||
using Meteor.Map.actors.chara.player;
|
using Meteor.Map.actors.chara.player;
|
||||||
using Meteor.Map.packets.receive.supportdesk;
|
using Meteor.Map.packets.receive.supportdesk;
|
||||||
using Meteor.Map.actors.chara.npc;
|
using Meteor.Map.actors.chara.npc;
|
||||||
using Meteor.Map.actors.chara.ai;
|
using Meteor.Map.actors.chara.ai;
|
||||||
using Meteor.Map.packets.send.actor.battle;
|
using Meteor.Map.packets.send.actor.battle;
|
||||||
using Meteor.Map.DataObjects;
|
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
namespace Meteor.Map
|
namespace Meteor.Map
|
||||||
|
@ -72,6 +73,55 @@ namespace Meteor.Map
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Dictionary<uint, QuestGameData> 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<uint, QuestGameData> gamedataQuests = new Dictionary<uint, QuestGameData>();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
conn.Open();
|
||||||
|
|
||||||
|
string query = @"
|
||||||
|
SELECT
|
||||||
|
id,
|
||||||
|
className,
|
||||||
|
questName,
|
||||||
|
prerequisite,
|
||||||
|
minLevel
|
||||||
|
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 QuestGameData(questId, code, name, prerequisite, minLevel, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (MySqlException e)
|
||||||
|
{
|
||||||
|
Program.Log.Error(e.ToString());
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
conn.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
return gamedataQuests;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static Dictionary<uint, ItemData> GetItemGamedata()
|
public static Dictionary<uint, ItemData> 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)))
|
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)))
|
||||||
|
@ -477,23 +527,13 @@ namespace Meteor.Map
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SaveQuest(Player player, Quest quest)
|
|
||||||
{
|
|
||||||
int slot = player.GetQuestSlot(quest.Id);
|
|
||||||
if (slot == -1)
|
|
||||||
{
|
|
||||||
Program.Log.Error("Tried saving quest player didn't have: Player: {0:x}, QuestId: {0:x}", player.Id, quest.Id);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
SaveQuest(player, quest, slot);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SaveQuest(Player player, Quest quest, int slot)
|
public static void SaveQuest(Player player, Quest quest, int slot)
|
||||||
{
|
{
|
||||||
string query;
|
string query;
|
||||||
MySqlCommand cmd;
|
MySqlCommand cmd;
|
||||||
|
|
||||||
|
QuestData qData = quest.GetData();
|
||||||
|
|
||||||
using (MySqlConnection 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)))
|
using (MySqlConnection 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)))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -514,10 +554,59 @@ namespace Meteor.Map
|
||||||
cmd.Parameters.AddWithValue("@slot", slot);
|
cmd.Parameters.AddWithValue("@slot", slot);
|
||||||
cmd.Parameters.AddWithValue("@questId", 0xFFFFF & quest.Id);
|
cmd.Parameters.AddWithValue("@questId", 0xFFFFF & quest.Id);
|
||||||
cmd.Parameters.AddWithValue("@sequence", quest.GetSequence());
|
cmd.Parameters.AddWithValue("@sequence", quest.GetSequence());
|
||||||
cmd.Parameters.AddWithValue("@flags", quest.GetFlags());
|
|
||||||
cmd.Parameters.AddWithValue("@counter1", quest.GetCounter(1));
|
if (qData != null)
|
||||||
cmd.Parameters.AddWithValue("@counter2", quest.GetCounter(2));
|
{
|
||||||
cmd.Parameters.AddWithValue("@counter3", quest.GetCounter(3));
|
cmd.Parameters.AddWithValue("@flags", qData.GetFlags());
|
||||||
|
cmd.Parameters.AddWithValue("@counter1", qData.GetCounter(1));
|
||||||
|
cmd.Parameters.AddWithValue("@counter2", qData.GetCounter(2));
|
||||||
|
cmd.Parameters.AddWithValue("@counter3", qData.GetCounter(3));
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.ExecuteNonQuery();
|
||||||
|
}
|
||||||
|
catch (MySqlException e)
|
||||||
|
{
|
||||||
|
Program.Log.Error(e.ToString());
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
conn.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void UpdateQuest(Player player, Quest quest)
|
||||||
|
{
|
||||||
|
string query;
|
||||||
|
MySqlCommand cmd;
|
||||||
|
|
||||||
|
QuestData qData = quest.GetData();
|
||||||
|
|
||||||
|
using (MySqlConnection 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)))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
conn.Open();
|
||||||
|
|
||||||
|
query = @"
|
||||||
|
UPDATE characters_quest_scenario
|
||||||
|
SET sequence = @sequence, flags = @flags, counter1 = @counter1, counter2 = @counter2, counter3 = @counter3
|
||||||
|
WHERE characterId = @charaId and questId = @questId
|
||||||
|
";
|
||||||
|
|
||||||
|
cmd = new MySqlCommand(query, conn);
|
||||||
|
cmd.Parameters.AddWithValue("@charaId", player.Id);
|
||||||
|
cmd.Parameters.AddWithValue("@questId", 0xFFFFF & quest.Id);
|
||||||
|
cmd.Parameters.AddWithValue("@sequence", quest.GetSequence());
|
||||||
|
|
||||||
|
if (qData != null)
|
||||||
|
{
|
||||||
|
cmd.Parameters.AddWithValue("@flags", qData.GetFlags());
|
||||||
|
cmd.Parameters.AddWithValue("@counter1", qData.GetCounter(1));
|
||||||
|
cmd.Parameters.AddWithValue("@counter2", qData.GetCounter(2));
|
||||||
|
cmd.Parameters.AddWithValue("@counter3", qData.GetCounter(3));
|
||||||
|
}
|
||||||
|
|
||||||
cmd.ExecuteNonQuery();
|
cmd.ExecuteNonQuery();
|
||||||
}
|
}
|
||||||
|
@ -674,7 +763,7 @@ namespace Meteor.Map
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void CompleteQuest(Player player, uint questId)
|
public static void SaveCompletedQuests(Player player)
|
||||||
{
|
{
|
||||||
string query;
|
string query;
|
||||||
MySqlCommand cmd;
|
MySqlCommand cmd;
|
||||||
|
@ -687,15 +776,15 @@ namespace Meteor.Map
|
||||||
|
|
||||||
query = @"
|
query = @"
|
||||||
INSERT INTO characters_quest_completed
|
INSERT INTO characters_quest_completed
|
||||||
(characterId, questId)
|
(characterId, completedQuests)
|
||||||
VALUES
|
VALUES
|
||||||
(@charaId, @questId)
|
(@charaId, @completedQuests)
|
||||||
ON DUPLICATE KEY UPDATE characterId=characterId
|
ON DUPLICATE KEY UPDATE completedQuests=completedQuests
|
||||||
";
|
";
|
||||||
|
|
||||||
cmd = new MySqlCommand(query, conn);
|
cmd = new MySqlCommand(query, conn);
|
||||||
cmd.Parameters.AddWithValue("@charaId", player.Id);
|
cmd.Parameters.AddWithValue("@charaId", player.Id);
|
||||||
cmd.Parameters.AddWithValue("@questId", 0xFFFFF & questId);
|
cmd.Parameters.AddWithValue("@completedQuests", Utils.ConvertBoolArrayToBinaryStream(player.playerWork.questScenarioComplete));
|
||||||
|
|
||||||
cmd.ExecuteNonQuery();
|
cmd.ExecuteNonQuery();
|
||||||
}
|
}
|
||||||
|
@ -710,31 +799,6 @@ namespace Meteor.Map
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsQuestCompleted(Player player, uint questId)
|
|
||||||
{
|
|
||||||
bool isCompleted = false;
|
|
||||||
using (MySqlConnection 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)))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
conn.Open();
|
|
||||||
MySqlCommand cmd = new MySqlCommand("SELECT * FROM characters_quest_completed WHERE characterId = @charaId and questId = @questId", conn);
|
|
||||||
cmd.Parameters.AddWithValue("@charaId", player.Id);
|
|
||||||
cmd.Parameters.AddWithValue("@questId", questId);
|
|
||||||
isCompleted = cmd.ExecuteScalar() != null;
|
|
||||||
}
|
|
||||||
catch (MySqlException e)
|
|
||||||
{
|
|
||||||
Program.Log.Error(e.ToString());
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
conn.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return isCompleted;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void LoadPlayerCharacter(Player player)
|
public static void LoadPlayerCharacter(Player player)
|
||||||
{
|
{
|
||||||
string query;
|
string query;
|
||||||
|
@ -1168,11 +1232,32 @@ namespace Meteor.Map
|
||||||
ushort counter1 = reader.GetUInt16("counter1");
|
ushort counter1 = reader.GetUInt16("counter1");
|
||||||
ushort counter2 = reader.GetUInt16("counter2");
|
ushort counter2 = reader.GetUInt16("counter2");
|
||||||
ushort counter3 = reader.GetUInt16("counter3");
|
ushort counter3 = reader.GetUInt16("counter3");
|
||||||
|
//ushort counter4 = reader.GetUInt16("counter4");
|
||||||
|
|
||||||
Quest baseQuest = (Quest) Server.GetStaticActors(questId);
|
Quest baseQuest = (Quest) Server.GetStaticActors(questId);
|
||||||
|
|
||||||
player.playerWork.questScenario[index] = questId;
|
player.playerWork.questScenario[index] = questId;
|
||||||
player.questScenario[index] = new Quest(player, baseQuest, sequence, flags, counter1, counter2, counter3);
|
player.questScenario[index] = new Quest(player, baseQuest, sequence);
|
||||||
|
player.questScenario[index].SetData(flags, counter1, counter2, counter3, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Load Completed Quests bitstream
|
||||||
|
query = @"
|
||||||
|
SELECT
|
||||||
|
completedQuests
|
||||||
|
FROM characters_quest_completed WHERE characterId = @charaId";
|
||||||
|
|
||||||
|
cmd = new MySqlCommand(query, conn);
|
||||||
|
cmd.Parameters.AddWithValue("@charaId", player.Id);
|
||||||
|
using (MySqlDataReader reader = cmd.ExecuteReader())
|
||||||
|
{
|
||||||
|
// Replace the bool stream or use the default empty one.
|
||||||
|
if (reader.Read())
|
||||||
|
{
|
||||||
|
byte[] bytes = new byte[256];
|
||||||
|
reader.GetBytes(reader.GetOrdinal("completedQuests"), 0, bytes, 0, 256);
|
||||||
|
player.playerWork.questScenarioComplete = Utils.ConvertBinaryStreamToBoolArray(bytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,12 +22,11 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
|
|
||||||
using Meteor.Map.actors.director;
|
using Meteor.Map.actors.director;
|
||||||
using Meteor.Map.Actors;
|
using Meteor.Map.Actors;
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using Meteor.Map.packets.receive.events;
|
using Meteor.Map.packets.receive.events;
|
||||||
using Meteor.Map.packets.send;
|
using Meteor.Map.packets.send;
|
||||||
using Meteor.Map.packets.send.events;
|
using Meteor.Map.packets.send.events;
|
||||||
using MoonSharp.Interpreter;
|
using MoonSharp.Interpreter;
|
||||||
using MoonSharp.Interpreter.Interop;
|
|
||||||
using MoonSharp.Interpreter.Loaders;
|
using MoonSharp.Interpreter.Loaders;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
@ -37,11 +36,11 @@ using Meteor.Map.actors.area;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Meteor.Map.actors.chara.ai;
|
using Meteor.Map.actors.chara.ai;
|
||||||
using Meteor.Map.actors.chara.ai.controllers;
|
using Meteor.Map.actors.chara.ai.controllers;
|
||||||
using Meteor.Map.DataObjects;
|
|
||||||
using Meteor.Map.actors.chara.player;
|
using Meteor.Map.actors.chara.player;
|
||||||
using Meteor.Map.Actors.Chara;
|
using Meteor.Map.Actors.Chara;
|
||||||
using Meteor.Map.dataobjects.chara;
|
using Meteor.Map.DataObjects.chara;
|
||||||
using Meteor.Map.actors.chara;
|
using Meteor.Map.actors.chara;
|
||||||
|
using Meteor.Map.Actors.QuestNS;
|
||||||
|
|
||||||
namespace Meteor.Map.lua
|
namespace Meteor.Map.lua
|
||||||
{
|
{
|
||||||
|
@ -78,6 +77,7 @@ namespace Meteor.Map.lua
|
||||||
UserData.RegisterType<Command>();
|
UserData.RegisterType<Command>();
|
||||||
UserData.RegisterType<Npc>();
|
UserData.RegisterType<Npc>();
|
||||||
UserData.RegisterType<Quest>();
|
UserData.RegisterType<Quest>();
|
||||||
|
UserData.RegisterType<QuestData>();
|
||||||
UserData.RegisterType<Zone>();
|
UserData.RegisterType<Zone>();
|
||||||
UserData.RegisterType<InventoryItem>();
|
UserData.RegisterType<InventoryItem>();
|
||||||
UserData.RegisterType<ItemPackage>();
|
UserData.RegisterType<ItemPackage>();
|
||||||
|
|
|
@ -180,9 +180,13 @@
|
||||||
<Compile Include="Actors\Group\Work\RelationWork.cs" />
|
<Compile Include="Actors\Group\Work\RelationWork.cs" />
|
||||||
<Compile Include="Actors\Judge\Judge.cs" />
|
<Compile Include="Actors\Judge\Judge.cs" />
|
||||||
<Compile Include="Actors\Quest\Quest.cs" />
|
<Compile Include="Actors\Quest\Quest.cs" />
|
||||||
|
<Compile Include="Actors\Quest\QuestData.cs" />
|
||||||
|
<Compile Include="Actors\Quest\QuestState.cs" />
|
||||||
|
<Compile Include="Actors\Quest\QuestStateManager.cs" />
|
||||||
<Compile Include="Actors\StaticActors.cs" />
|
<Compile Include="Actors\StaticActors.cs" />
|
||||||
<Compile Include="Actors\World\WorldMaster.cs" />
|
<Compile Include="Actors\World\WorldMaster.cs" />
|
||||||
<Compile Include="DataObjects\GuildleveData.cs" />
|
<Compile Include="DataObjects\GuildleveData.cs" />
|
||||||
|
<Compile Include="DataObjects\QuestGameData.cs" />
|
||||||
<Compile Include="DataObjects\Recipe.cs" />
|
<Compile Include="DataObjects\Recipe.cs" />
|
||||||
<Compile Include="DataObjects\RecipeResolver.cs" />
|
<Compile Include="DataObjects\RecipeResolver.cs" />
|
||||||
<Compile Include="DataObjects\TradeTransaction.cs" />
|
<Compile Include="DataObjects\TradeTransaction.cs" />
|
||||||
|
@ -223,7 +227,7 @@
|
||||||
<Compile Include="Packets\Receive\CountdownRequestPacket.cs" />
|
<Compile Include="Packets\Receive\CountdownRequestPacket.cs" />
|
||||||
<Compile Include="Packets\Receive\LangaugeCodePacket.cs" />
|
<Compile Include="Packets\Receive\LangaugeCodePacket.cs" />
|
||||||
<Compile Include="Packets\Receive\UpdateItemPackagePacket.cs" />
|
<Compile Include="Packets\Receive\UpdateItemPackagePacket.cs" />
|
||||||
<Compile Include="Packets\Receive\ParameterDataRequestPacket.cs" />
|
<Compile Include="Packets\Receive\WorkSyncRequestPacket.cs" />
|
||||||
<Compile Include="Packets\Receive\Recruitment\RecruitmentDetailsRequestPacket.cs" />
|
<Compile Include="Packets\Receive\Recruitment\RecruitmentDetailsRequestPacket.cs" />
|
||||||
<Compile Include="Packets\Receive\Recruitment\RecruitmentSearchRequestPacket.cs" />
|
<Compile Include="Packets\Receive\Recruitment\RecruitmentSearchRequestPacket.cs" />
|
||||||
<Compile Include="Packets\Receive\Recruitment\StartRecruitingRequestPacket.cs" />
|
<Compile Include="Packets\Receive\Recruitment\StartRecruitingRequestPacket.cs" />
|
||||||
|
|
|
@ -22,7 +22,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
using Meteor.Common;
|
using Meteor.Common;
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using Meteor.Map.packets.receive;
|
using Meteor.Map.packets.receive;
|
||||||
using Meteor.Map.packets.send;
|
using Meteor.Map.packets.send;
|
||||||
using Meteor.Map.packets.send.login;
|
using Meteor.Map.packets.send.login;
|
||||||
|
@ -39,6 +39,7 @@ using Meteor.Map.Actors;
|
||||||
using Meteor.Map.packets.WorldPackets.Send;
|
using Meteor.Map.packets.WorldPackets.Send;
|
||||||
using Meteor.Map.packets.WorldPackets.Receive;
|
using Meteor.Map.packets.WorldPackets.Receive;
|
||||||
using Meteor.Map.actors.director;
|
using Meteor.Map.actors.director;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace Meteor.Map
|
namespace Meteor.Map
|
||||||
{
|
{
|
||||||
|
@ -260,9 +261,8 @@ namespace Meteor.Map
|
||||||
break;
|
break;
|
||||||
case 0x012F:
|
case 0x012F:
|
||||||
subpacket.DebugPrintSubPacket();
|
subpacket.DebugPrintSubPacket();
|
||||||
ParameterDataRequestPacket paramRequest = new ParameterDataRequestPacket(subpacket.data);
|
WorkSyncRequestPacket workSyncRequest = new WorkSyncRequestPacket(subpacket.data);
|
||||||
if (paramRequest.paramName.Equals("charaWork/exp"))
|
session.GetActor().OnWorkSyncRequest(workSyncRequest.propertyName, workSyncRequest.from, workSyncRequest.to);
|
||||||
session.GetActor().SendCharaExpInfo();
|
|
||||||
break;
|
break;
|
||||||
//Item Package Request
|
//Item Package Request
|
||||||
case 0x0131:
|
case 0x0131:
|
||||||
|
|
|
@ -26,7 +26,7 @@ using System.Text;
|
||||||
|
|
||||||
namespace Meteor.Map.packets.receive
|
namespace Meteor.Map.packets.receive
|
||||||
{
|
{
|
||||||
class ParameterDataRequestPacket
|
class WorkSyncRequestPacket
|
||||||
{
|
{
|
||||||
public const ushort OPCODE = 0x012F;
|
public const ushort OPCODE = 0x012F;
|
||||||
public const uint PACKET_SIZE = 0x48;
|
public const uint PACKET_SIZE = 0x48;
|
||||||
|
@ -34,9 +34,11 @@ namespace Meteor.Map.packets.receive
|
||||||
public bool invalidPacket = false;
|
public bool invalidPacket = false;
|
||||||
|
|
||||||
public uint actorID;
|
public uint actorID;
|
||||||
public string paramName;
|
public string propertyName;
|
||||||
|
public ushort from, to;
|
||||||
|
public bool requestingBitfield = false;
|
||||||
|
|
||||||
public ParameterDataRequestPacket(byte[] data)
|
public WorkSyncRequestPacket(byte[] data)
|
||||||
{
|
{
|
||||||
using (MemoryStream mem = new MemoryStream(data))
|
using (MemoryStream mem = new MemoryStream(data))
|
||||||
{
|
{
|
||||||
|
@ -44,13 +46,22 @@ namespace Meteor.Map.packets.receive
|
||||||
{
|
{
|
||||||
try{
|
try{
|
||||||
actorID = binReader.ReadUInt32();
|
actorID = binReader.ReadUInt32();
|
||||||
List<byte> strList = new List<byte>();
|
if (binReader.PeekChar() == 9)
|
||||||
byte curByte;
|
|
||||||
while ((curByte = binReader.ReadByte()) != 0 && strList.Count<=0x20)
|
|
||||||
{
|
{
|
||||||
strList.Add(curByte);
|
binReader.ReadByte();
|
||||||
|
from = binReader.ReadUInt16();
|
||||||
|
to = binReader.ReadUInt16();
|
||||||
}
|
}
|
||||||
paramName = Encoding.ASCII.GetString(strList.ToArray());
|
|
||||||
|
byte currentByte;
|
||||||
|
int size = 0;
|
||||||
|
long strPos = binReader.BaseStream.Position;
|
||||||
|
while ((currentByte = binReader.ReadByte()) != 0 && size <= 0x20)
|
||||||
|
size++;
|
||||||
|
|
||||||
|
binReader.BaseStream.Seek(strPos, SeekOrigin.Begin);
|
||||||
|
byte[] str = binReader.ReadBytes(size);
|
||||||
|
propertyName = Encoding.ASCII.GetString(str);
|
||||||
}
|
}
|
||||||
catch (Exception){
|
catch (Exception){
|
||||||
invalidPacket = true;
|
invalidPacket = true;
|
|
@ -19,7 +19,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
===========================================================================
|
===========================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
===========================================================================
|
===========================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
===========================================================================
|
===========================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
using Meteor.Common;
|
using Meteor.Common;
|
||||||
|
|
|
@ -19,7 +19,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
===========================================================================
|
===========================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
|
@ -19,7 +19,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
===========================================================================
|
===========================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
===========================================================================
|
===========================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
===========================================================================
|
===========================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
using Meteor.Common;
|
using Meteor.Common;
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
|
|
||||||
namespace Meteor.Map.packets.send.actor.inventory
|
namespace Meteor.Map.packets.send.actor.inventory
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,7 +19,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
===========================================================================
|
===========================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
|
@ -19,7 +19,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
===========================================================================
|
===========================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
|
@ -19,7 +19,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
===========================================================================
|
===========================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
|
@ -19,7 +19,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
===========================================================================
|
===========================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
|
@ -44,6 +44,10 @@ namespace Meteor.Map.packets.send.actor
|
||||||
|
|
||||||
string currentTarget;
|
string currentTarget;
|
||||||
|
|
||||||
|
bool isBitfield = false;
|
||||||
|
ushort from;
|
||||||
|
ushort to;
|
||||||
|
|
||||||
private MemoryStream mem;
|
private MemoryStream mem;
|
||||||
private BinaryWriter binWriter;
|
private BinaryWriter binWriter;
|
||||||
|
|
||||||
|
@ -54,6 +58,16 @@ namespace Meteor.Map.packets.send.actor
|
||||||
binWriter.Seek(1, SeekOrigin.Begin);
|
binWriter.Seek(1, SeekOrigin.Begin);
|
||||||
currentTarget = startingTarget;
|
currentTarget = startingTarget;
|
||||||
}
|
}
|
||||||
|
public SetActorPropetyPacket(ushort from, ushort to, string startingTarget)
|
||||||
|
{
|
||||||
|
mem = new MemoryStream(data);
|
||||||
|
binWriter = new BinaryWriter(mem);
|
||||||
|
binWriter.Seek(1, SeekOrigin.Begin);
|
||||||
|
currentTarget = startingTarget;
|
||||||
|
this.from = from;
|
||||||
|
this.to = to;
|
||||||
|
isBitfield = true;
|
||||||
|
}
|
||||||
|
|
||||||
public void CloseStreams()
|
public void CloseStreams()
|
||||||
{
|
{
|
||||||
|
@ -100,6 +114,19 @@ namespace Meteor.Map.packets.send.actor
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool AddBitfield(uint id, byte[] data)
|
||||||
|
{
|
||||||
|
if (runningByteTotal + 5 + data.Length + 1 + (1 + 5 + Encoding.ASCII.GetByteCount(currentTarget)) > MAXBYTES)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
binWriter.Write((byte) (data.Length));
|
||||||
|
binWriter.Write((UInt32)id);
|
||||||
|
binWriter.Write(data);
|
||||||
|
runningByteTotal += (ushort)(5 + data.Length);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public bool AddBuffer(uint id, byte[] buffer)
|
public bool AddBuffer(uint id, byte[] buffer)
|
||||||
{
|
{
|
||||||
if (runningByteTotal + 5 + buffer.Length + (1 + Encoding.ASCII.GetByteCount(currentTarget)) > MAXBYTES)
|
if (runningByteTotal + 5 + buffer.Length + (1 + Encoding.ASCII.GetByteCount(currentTarget)) > MAXBYTES)
|
||||||
|
@ -208,10 +235,22 @@ namespace Meteor.Map.packets.send.actor
|
||||||
public void SetTarget(string target)
|
public void SetTarget(string target)
|
||||||
{
|
{
|
||||||
currentTarget = target;
|
currentTarget = target;
|
||||||
|
isBitfield = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddTarget()
|
public void AddTarget()
|
||||||
{
|
{
|
||||||
|
if (isBitfield)
|
||||||
|
{
|
||||||
|
binWriter.Write((byte)(isMore ? 0x60 + currentTarget.Length + 5 : 0x82 + currentTarget.Length + 5));
|
||||||
|
binWriter.Write((byte)9);
|
||||||
|
binWriter.Write(from);
|
||||||
|
binWriter.Write(to);
|
||||||
|
binWriter.Write(Encoding.ASCII.GetBytes(currentTarget));
|
||||||
|
runningByteTotal += (ushort)(6 + Encoding.ASCII.GetByteCount(currentTarget));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (isArrayMode)
|
if (isArrayMode)
|
||||||
binWriter.Write((byte)(0xA4 + currentTarget.Length));
|
binWriter.Write((byte)(0xA4 + currentTarget.Length));
|
||||||
else
|
else
|
||||||
|
@ -236,6 +275,7 @@ namespace Meteor.Map.packets.send.actor
|
||||||
CloseStreams();
|
CloseStreams();
|
||||||
|
|
||||||
SubPacket packet = new SubPacket(OPCODE, sourceActorId, data);
|
SubPacket packet = new SubPacket(OPCODE, sourceActorId, data);
|
||||||
|
packet.DebugPrintSubPacket();
|
||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -79,9 +79,7 @@ namespace Meteor.Map.packets.send.player
|
||||||
public const ushort OPCODE = 0x01A3;
|
public const ushort OPCODE = 0x01A3;
|
||||||
public const uint PACKET_SIZE = 0x150;
|
public const uint PACKET_SIZE = 0x150;
|
||||||
|
|
||||||
public bool[] cutsceneFlags = new bool[2048];
|
public SubPacket BuildPacket(uint sourceActorId, string sNpcName, short sNpcActorIdOffset, byte sNpcSkin, byte sNpcPersonality, bool[] completedQuests)
|
||||||
|
|
||||||
public SubPacket BuildPacket(uint sourceActorId, string sNpcName, short sNpcActorIdOffset, byte sNpcSkin, byte sNpcPersonality)
|
|
||||||
{
|
{
|
||||||
byte[] data = new byte[PACKET_SIZE - 0x20];
|
byte[] data = new byte[PACKET_SIZE - 0x20];
|
||||||
|
|
||||||
|
@ -89,7 +87,7 @@ namespace Meteor.Map.packets.send.player
|
||||||
{
|
{
|
||||||
using (BinaryWriter binWriter = new BinaryWriter(mem))
|
using (BinaryWriter binWriter = new BinaryWriter(mem))
|
||||||
{
|
{
|
||||||
byte[] binStream = Utils.ConvertBoolArrayToBinaryStream(cutsceneFlags);
|
byte[] binStream = Utils.ConvertBoolArrayToBinaryStream(completedQuests);
|
||||||
|
|
||||||
//Temp Path Companion SNPC Stuff
|
//Temp Path Companion SNPC Stuff
|
||||||
binWriter.Seek(0x01 ,SeekOrigin.Begin);
|
binWriter.Seek(0x01 ,SeekOrigin.Begin);
|
||||||
|
|
|
@ -19,7 +19,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
===========================================================================
|
===========================================================================
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
|
@ -20,7 +20,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using Meteor.Common;
|
using Meteor.Common;
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
|
@ -20,7 +20,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using Meteor.Common;
|
using Meteor.Common;
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using Meteor.Common;
|
using Meteor.Common;
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using Meteor.Common;
|
using Meteor.Common;
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using Meteor.Common;
|
using Meteor.Common;
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
|
|
||||||
namespace Meteor.Map.packets.WorldPackets.Send.Group
|
namespace Meteor.Map.packets.WorldPackets.Send.Group
|
||||||
{
|
{
|
||||||
|
|
|
@ -20,7 +20,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using Meteor.Common;
|
using Meteor.Common;
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
|
@ -20,7 +20,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using Meteor.Common;
|
using Meteor.Common;
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
|
@ -20,7 +20,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using Meteor.Common;
|
using Meteor.Common;
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
|
@ -20,7 +20,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using Meteor.Common;
|
using Meteor.Common;
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
|
@ -20,7 +20,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using Meteor.Common;
|
using Meteor.Common;
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
|
@ -20,7 +20,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using Meteor.Common;
|
using Meteor.Common;
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using Meteor.Common;
|
using Meteor.Common;
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
|
@ -20,7 +20,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using Meteor.Common;
|
using Meteor.Common;
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using Meteor.Common;
|
using Meteor.Common;
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ along with Project Meteor Server. If not, see <https:www.gnu.org/licenses/>.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using Meteor.Common;
|
||||||
using MySql.Data.MySqlClient;
|
using MySql.Data.MySqlClient;
|
||||||
using NLog;
|
using NLog;
|
||||||
|
|
||||||
|
|
|
@ -23,10 +23,11 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
|
|
||||||
using Meteor.Common;
|
using Meteor.Common;
|
||||||
using Meteor.Map.Actors;
|
using Meteor.Map.Actors;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Meteor.Map
|
namespace Meteor.Map
|
||||||
{
|
{
|
||||||
|
@ -38,52 +39,56 @@ namespace Meteor.Map
|
||||||
|
|
||||||
public const string STATIC_ACTORS_PATH = "./staticactors.bin";
|
public const string STATIC_ACTORS_PATH = "./staticactors.bin";
|
||||||
|
|
||||||
private static Server mSelf;
|
private static Server _Self;
|
||||||
|
|
||||||
private Socket mServerSocket;
|
private Socket ServerSocket;
|
||||||
|
|
||||||
private Dictionary<uint, Session> mSessionList = new Dictionary<uint, Session>();
|
private Dictionary<uint, Session> SessionList = new Dictionary<uint, Session>();
|
||||||
|
|
||||||
private static CommandProcessor mCommandProcessor = new CommandProcessor();
|
private static CommandProcessor CommandProcessor = new CommandProcessor();
|
||||||
private static ZoneConnection mWorldConnection = new ZoneConnection();
|
private static ZoneConnection WorldConnection = new ZoneConnection();
|
||||||
private static WorldManager mWorldManager;
|
private static WorldManager WorldManager;
|
||||||
private static Dictionary<uint, ItemData> mGamedataItems;
|
private static Dictionary<uint, ItemData> GamedataItems;
|
||||||
private static Dictionary<uint, GuildleveData> mGamedataGuildleves;
|
private static Dictionary<uint, GuildleveData> GamedataGuildleves;
|
||||||
private static StaticActors mStaticActors;
|
private static Dictionary<uint, QuestGameData> GamedataQuests;
|
||||||
|
private static StaticActors StaticActors;
|
||||||
|
|
||||||
private PacketProcessor mProcessor;
|
private PacketProcessor mProcessor;
|
||||||
|
|
||||||
public Server()
|
public Server()
|
||||||
{
|
{
|
||||||
mSelf = this;
|
_Self = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool StartServer()
|
public bool StartServer()
|
||||||
{
|
{
|
||||||
mStaticActors = new StaticActors(STATIC_ACTORS_PATH);
|
StaticActors = new StaticActors(STATIC_ACTORS_PATH);
|
||||||
|
|
||||||
mGamedataItems = Database.GetItemGamedata();
|
Program.Log.Info("Loading gamedata...");
|
||||||
Program.Log.Info("Loaded {0} items.", mGamedataItems.Count);
|
GamedataItems = Database.GetItemGamedata();
|
||||||
mGamedataGuildleves = Database.GetGuildleveGamedata();
|
Program.Log.Info("Loaded {0} items.", GamedataItems.Count);
|
||||||
Program.Log.Info("Loaded {0} guildleves.", mGamedataGuildleves.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);
|
WorldManager = new WorldManager(this);
|
||||||
mWorldManager.LoadZoneList();
|
WorldManager.LoadZoneList();
|
||||||
mWorldManager.LoadSeamlessBoundryList();
|
WorldManager.LoadSeamlessBoundryList();
|
||||||
mWorldManager.LoadActorClasses();
|
WorldManager.LoadActorClasses();
|
||||||
mWorldManager.LoadENPCs();
|
WorldManager.LoadENPCs();
|
||||||
mWorldManager.LoadBattleNpcs();
|
WorldManager.LoadBattleNpcs();
|
||||||
mWorldManager.LoadStatusEffects();
|
WorldManager.LoadStatusEffects();
|
||||||
mWorldManager.LoadBattleCommands();
|
WorldManager.LoadBattleCommands();
|
||||||
mWorldManager.LoadBattleTraits();
|
WorldManager.LoadBattleTraits();
|
||||||
mWorldManager.SpawnAllActors();
|
WorldManager.SpawnAllActors();
|
||||||
mWorldManager.StartZoneThread();
|
WorldManager.StartZoneThread();
|
||||||
|
|
||||||
IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse(ConfigConstants.OPTIONS_BINDIP), int.Parse(ConfigConstants.OPTIONS_PORT));
|
IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse(ConfigConstants.OPTIONS_BINDIP), int.Parse(ConfigConstants.OPTIONS_PORT));
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
mServerSocket = new Socket(serverEndPoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
ServerSocket = new Socket(serverEndPoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -91,8 +96,8 @@ namespace Meteor.Map
|
||||||
}
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
mServerSocket.Bind(serverEndPoint);
|
ServerSocket.Bind(serverEndPoint);
|
||||||
mServerSocket.Listen(BACKLOG);
|
ServerSocket.Listen(BACKLOG);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -100,7 +105,7 @@ namespace Meteor.Map
|
||||||
}
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
mServerSocket.BeginAccept(new AsyncCallback(AcceptCallback), mServerSocket);
|
ServerSocket.BeginAccept(new AsyncCallback(AcceptCallback), ServerSocket);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -108,7 +113,7 @@ namespace Meteor.Map
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.ForegroundColor = ConsoleColor.White;
|
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;
|
Console.ForegroundColor = ConsoleColor.Gray;
|
||||||
|
|
||||||
mProcessor = new PacketProcessor(this);
|
mProcessor = new PacketProcessor(this);
|
||||||
|
@ -122,36 +127,36 @@ namespace Meteor.Map
|
||||||
|
|
||||||
public Session AddSession(uint id)
|
public Session AddSession(uint id)
|
||||||
{
|
{
|
||||||
if (mSessionList.ContainsKey(id))
|
if (SessionList.ContainsKey(id))
|
||||||
{
|
{
|
||||||
mSessionList[id].ClearInstance();
|
SessionList[id].ClearInstance();
|
||||||
return mSessionList[id];
|
return SessionList[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
Session session = new Session(id);
|
Session session = new Session(id);
|
||||||
mSessionList.Add(id, session);
|
SessionList.Add(id, session);
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveSession(uint id)
|
public void RemoveSession(uint id)
|
||||||
{
|
{
|
||||||
if (mSessionList.ContainsKey(id))
|
if (SessionList.ContainsKey(id))
|
||||||
{
|
{
|
||||||
mSessionList.Remove(id);
|
SessionList.Remove(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Session GetSession(uint id)
|
public Session GetSession(uint id)
|
||||||
{
|
{
|
||||||
if (mSessionList.ContainsKey(id))
|
if (SessionList.ContainsKey(id))
|
||||||
return mSessionList[id];
|
return SessionList[id];
|
||||||
else
|
else
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Session GetSession(string name)
|
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()))
|
if (s.GetActor().DisplayName.ToLower().Equals(name.ToLower()))
|
||||||
return s;
|
return s;
|
||||||
|
@ -161,7 +166,7 @@ namespace Meteor.Map
|
||||||
|
|
||||||
public Dictionary<uint, Session> GetSessionList()
|
public Dictionary<uint, Session> GetSessionList()
|
||||||
{
|
{
|
||||||
return mSessionList;
|
return SessionList;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -179,29 +184,29 @@ namespace Meteor.Map
|
||||||
conn.socket = socket.EndAccept(result);
|
conn.socket = socket.EndAccept(result);
|
||||||
conn.buffer = new byte[BUFFER_SIZE];
|
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);
|
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
|
//Queue recieving of data from the connection
|
||||||
conn.socket.BeginReceive(conn.buffer, 0, conn.buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), conn);
|
conn.socket.BeginReceive(conn.buffer, 0, conn.buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), conn);
|
||||||
//Queue the accept of the next incomming connection
|
//Queue the accept of the next incomming connection
|
||||||
mServerSocket.BeginAccept(new AsyncCallback(AcceptCallback), mServerSocket);
|
ServerSocket.BeginAccept(new AsyncCallback(AcceptCallback), ServerSocket);
|
||||||
}
|
}
|
||||||
catch (SocketException)
|
catch (SocketException)
|
||||||
{
|
{
|
||||||
if (conn != null)
|
if (conn != null)
|
||||||
{
|
{
|
||||||
mWorldConnection = null;
|
WorldConnection = null;
|
||||||
}
|
}
|
||||||
mServerSocket.BeginAccept(new AsyncCallback(AcceptCallback), mServerSocket);
|
ServerSocket.BeginAccept(new AsyncCallback(AcceptCallback), ServerSocket);
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
if (conn != null)
|
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
|
//Check if disconnected
|
||||||
if ((conn.socket.Poll(1, SelectMode.SelectRead) && conn.socket.Available == 0))
|
if ((conn.socket.Poll(1, SelectMode.SelectRead) && conn.socket.Available == 0))
|
||||||
{
|
{
|
||||||
mWorldConnection = null;
|
WorldConnection = null;
|
||||||
Program.Log.Info("Disconnected from world server!");
|
Program.Log.Info("Disconnected from world server!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,7 +265,7 @@ namespace Meteor.Map
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mWorldConnection = null;
|
WorldConnection = null;
|
||||||
Program.Log.Info("Disconnected from world server!");
|
Program.Log.Info("Disconnected from world server!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -268,7 +273,7 @@ namespace Meteor.Map
|
||||||
{
|
{
|
||||||
if (conn.socket != null)
|
if (conn.socket != null)
|
||||||
{
|
{
|
||||||
mWorldConnection = null;
|
WorldConnection = null;
|
||||||
Program.Log.Info("Disconnected from world server!");
|
Program.Log.Info("Disconnected from world server!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -278,54 +283,90 @@ namespace Meteor.Map
|
||||||
|
|
||||||
public static ZoneConnection GetWorldConnection()
|
public static ZoneConnection GetWorldConnection()
|
||||||
{
|
{
|
||||||
return mWorldConnection;
|
return WorldConnection;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Server GetServer()
|
public static Server GetServer()
|
||||||
{
|
{
|
||||||
return mSelf;
|
return _Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CommandProcessor GetCommandProcessor()
|
public static CommandProcessor GetCommandProcessor()
|
||||||
{
|
{
|
||||||
return mCommandProcessor;
|
return CommandProcessor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static WorldManager GetWorldManager()
|
public static WorldManager GetWorldManager()
|
||||||
{
|
{
|
||||||
return mWorldManager;
|
return WorldManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Dictionary<uint, ItemData> GetGamedataItems()
|
public static Dictionary<uint, ItemData> GetGamedataItems()
|
||||||
{
|
{
|
||||||
return mGamedataItems;
|
return GamedataItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Actor GetStaticActors(uint id)
|
public static Actor GetStaticActors(uint id)
|
||||||
{
|
{
|
||||||
return mStaticActors.GetActor(id);
|
return StaticActors.GetActor(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Actor GetStaticActors(string name)
|
public static Actor GetStaticActors(string name)
|
||||||
{
|
{
|
||||||
return mStaticActors.FindStaticActor(name);
|
return StaticActors.FindStaticActor(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ItemData GetItemGamedata(uint id)
|
public static ItemData GetItemGamedata(uint id)
|
||||||
{
|
{
|
||||||
if (mGamedataItems.ContainsKey(id))
|
if (GamedataItems.ContainsKey(id))
|
||||||
return mGamedataItems[id];
|
return GamedataItems[id];
|
||||||
else
|
else
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GuildleveData GetGuildleveGamedata(uint id)
|
public static GuildleveData GetGuildleveGamedata(uint id)
|
||||||
{
|
{
|
||||||
if (mGamedataGuildleves.ContainsKey(id))
|
if (GamedataGuildleves.ContainsKey(id))
|
||||||
return mGamedataGuildleves[id];
|
return GamedataGuildleves[id];
|
||||||
else
|
else
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static QuestGameData GetQuestGamedata(uint id)
|
||||||
|
{
|
||||||
|
if (GamedataQuests.ContainsKey(id))
|
||||||
|
return GamedataQuests[id];
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static QuestGameData[] 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 QuestGameData[] GetQuestGamedataByPrerequisite(uint questId)
|
||||||
|
{
|
||||||
|
return GamedataQuests.Values.Where(quest => quest.PrerequisiteQuest == questId).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static QuestGameData[] GetQuestGamedataAllPrerequisite()
|
||||||
|
{
|
||||||
|
return GamedataQuests.Values.Where(quest => quest.PrerequisiteQuest != 0).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static QuestGameData[] 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();
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ using Meteor.Common;
|
||||||
using Meteor.Map.actors.area;
|
using Meteor.Map.actors.area;
|
||||||
using Meteor.Map.actors.chara.npc;
|
using Meteor.Map.actors.chara.npc;
|
||||||
using Meteor.Map.Actors;
|
using Meteor.Map.Actors;
|
||||||
using Meteor.Map.dataobjects;
|
using Meteor.Map.DataObjects;
|
||||||
using Meteor.Map.lua;
|
using Meteor.Map.lua;
|
||||||
using Meteor.Map.packets.send;
|
using Meteor.Map.packets.send;
|
||||||
using Meteor.Map.packets.send.actor;
|
using Meteor.Map.packets.send.actor;
|
||||||
|
|
Loading…
Add table
Reference in a new issue