1
Fork 0
mirror of https://bitbucket.org/Ioncannon/project-meteor-server.git synced 2025-04-21 20:27:47 +00:00

Merge branch 'ioncannon/quest_system' of https://bitbucket.org/Ioncannon/project-meteor-server into Jorge/quest_system

This commit is contained in:
CuriousJorge 2022-02-06 14:49:31 -05:00
commit fb9d4026a5
9 changed files with 209 additions and 195 deletions

View file

@ -18,6 +18,7 @@ function onTrigger(player, argc, command, var1, var2, var3)
local sender = "[quest] "; local sender = "[quest] ";
local message = "Error"; local message = "Error";
print(tostring(argc));
if player then if player then
if argc == 2 then if argc == 2 then
if command == "add" or command == "give" or command == "+" then if command == "add" or command == "give" or command == "+" then
@ -57,19 +58,45 @@ function onTrigger(player, argc, command, var1, var2, var3)
else else
message = ("remove error: either incorrect ID or quest "..var1.." isn't active on character"); message = ("remove error: either incorrect ID or quest "..var1.." isn't active on character");
end end
end
elseif command == "info" then
if tonumber(var1) then
if player:HasQuest(tonumber(var1)) then
quest = player:GetQuest(tonumber(var1));
local flagStr = "";
for i=0,31,1 do
if (quest:GetFlag(i)) then
flagStr = flagStr .. "O";
else
flagStr = flagStr .. "X";
end
if (i == 15) then
flagStr = flagStr .. "\n";
end
end
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("Flags: \n%s\n", flagStr)
message = message .. string.format("Counters: %d,%d,%d,%d", quest:getCounter(1), quest:getCounter(2), quest:getCounter(3), quest:getCounter(4));
else
message = ("Quest not active: "..var1);
end
else
message = ("error: invalid parameters used");
end end
else else
message = ("error: command "..command.." not recognized"); message = ("error: command "..command.." not recognized");
end end
elseif argc == 3 then elseif argc == 3 then
if command == "phase" or command == "step" then if command == "seq" or command == "sequence" then
if (tonumber(var1) and tonumber(var2)) ~= nil then if (tonumber(var1) and tonumber(var2)) ~= nil then
if player:HasQuest(tonumber(var1)) == true then if player:HasQuest(tonumber(var1)) == true then
player:GetQuest(tonumber(var1)):NextPhase(tonumber(var2)); player:GetQuest(tonumber(var1)):StartSequence(tonumber(var2));
message = ("changing phase of quest "..var1.." to "..var2); message = ("changing sequence of quest "..var1.." to "..var2);
else else
message = ("phase error: either incorrect ID or quest "..var1.." isn't active on character"); message = ("sequence error: either incorrect ID or quest "..var1.." isn't active on character");
end end
else else
message = ("error: invalid parameters used"); message = ("error: invalid parameters used");
@ -85,13 +112,13 @@ function onTrigger(player, argc, command, var1, var2, var3)
flagvar = (tonumber(var2)); flagvar = (tonumber(var2));
boolvar = 0; boolvar = 0;
if var3 == "true" or var3 == "1" or var3 == "on" then if var3 == "true" or var3 == "1" or var3 == "on" or var3 == "O" then
boolvar = true; boolvar = true;
elseif var3 == "false" or var3 == "0" or var3 == "off" then elseif var3 == "false" or var3 == "0" or var3 == "off" or var3 == "X" then
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):GetQuestFlag(flagvar); boolvar = not player:GetQuest(questvar):GetFlag(flagvar);
end end
else else
message = ("error: flag: boolean not recognized"); message = ("error: flag: boolean not recognized");
@ -99,10 +126,15 @@ function onTrigger(player, argc, command, var1, var2, var3)
return; return;
end end
var4 = player:GetQuest(questvar):GetQuestFlag(flagvar); var4 = player:GetQuest(questvar):GetFlag(flagvar);
if var4 ~= boolvar then if var4 ~= boolvar then
player:GetQuest(questvar):SetQuestFlag(flagvar, boolvar); if (boolvar == true) then
player:GetQuest(questvar):SetFlag(flagvar);
else
player:GetQuest(questvar):ClearFlag(flagvar);
end
player:GetQuest(questvar):UpdateENPCs();
player:GetQuest(questvar):SaveData(); player:GetQuest(questvar):SaveData();
if boolvar == true then if boolvar == true then
message = ("changing flag "..tonumber(var2).." to true on quest "..questvar); message = ("changing flag "..tonumber(var2).." to true on quest "..questvar);
@ -114,6 +146,18 @@ function onTrigger(player, argc, command, var1, var2, var3)
end end
else else
message = ("error: command "..command.." not recognized"); message = ("error: command "..command.." not recognized");
end
elseif command == "counter" then
if tonumber(var1) and (tonumber(var2) >= 0 and tonumber(var2) <= 4) then
questvar = tonumber(var1);
index = (tonumber(var2));
player:GetQuest(questvar):SetCounter(index, tonumber(var3));
player:GetQuest(questvar):UpdateENPCs();
player:GetQuest(questvar):SaveData();
message = ("changing counter "..tonumber(var2).." to "..var3);
else
message = ("error: command "..command.." not recognized");
end end
end end
end end

View file

@ -161,8 +161,8 @@ ENPC_PROP_CAN_EMOTE = 3;
ENPC_PROP_CAN_NOTICE = 4; ENPC_PROP_CAN_NOTICE = 4;
QFLAG_NONE = 0; QFLAG_NONE = 0;
QFLAG_MAP = 1;
QFLAG_PLATE = 2; QFLAG_PLATE = 2;
QFLAG_MAP = 3;
-- MUSIC -- MUSIC
MUSIC_IMMEDIATE = 1; MUSIC_IMMEDIATE = 1;

View file

@ -63,9 +63,6 @@ function onFinish(player, quest)
end end
function onSequence(player, quest, sequence) function onSequence(player, quest, sequence)
quest:ClearENpcs();
quest:ClearData();
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;
@ -73,7 +70,7 @@ function onSequence(player, quest, sequence)
local babyfaceFlag = quest:GetFlag(FLAG_SEQ000_MINITUT3) and QFLAG_NONE or QFLAG_PLATE; local babyfaceFlag = quest:GetFlag(FLAG_SEQ000_MINITUT3) and QFLAG_NONE or QFLAG_PLATE;
local rostnsthalCanPush = not quest:GetFlag(FLAG_SEQ000_MINITUT0); local rostnsthalCanPush = not quest:GetFlag(FLAG_SEQ000_MINITUT0);
local exitCanPush = quest:GetFlags() == 0xF; local exitCanPush = quest:GetFlags() == 0xF;
local exitFlag = quest:GetFlags() == 0xF and QFLAG_PLATE or QFLAG_NONE; local exitFlag = quest:GetFlags() == 0xF and QFLAG_MAP or QFLAG_NONE;
quest:AddENpc(WELLTRAVELED_MERCHANT); quest:AddENpc(WELLTRAVELED_MERCHANT);
quest:AddENpc(TIPSY_ADVENTURER); quest:AddENpc(TIPSY_ADVENTURER);
@ -90,7 +87,7 @@ function onSequence(player, quest, sequence)
quest:AddENpc(LANKY_TRAVELER); quest:AddENpc(LANKY_TRAVELER);
quest:AddENpc(GRINNING_ADVENTURER); quest:AddENpc(GRINNING_ADVENTURER);
quest:AddENpc(ROSTNSTHAL, rostnsthalFlag, true, rostnsthalCanPush); quest:AddENpc(ROSTNSTHAL, rostnsthalFlag, true, rostnsthalCanPush);
quest:AddENpc(EXIT_TRIGGER, exitFlag, false, false, exitCanPush); quest:AddENpc(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:AddENpc(HOB);
@ -102,7 +99,7 @@ function onSequence(player, quest, sequence)
quest:AddENpc(WELLTRAVELED_MERCHANT); quest:AddENpc(WELLTRAVELED_MERCHANT);
quest:AddENpc(VOLUPTUOUS_VIXEN); quest:AddENpc(VOLUPTUOUS_VIXEN);
quest:AddENpc(LANKY_TRAVELER); quest:AddENpc(LANKY_TRAVELER);
quest:AddENpc(PRIVAREA_PAST_EXIT, QFLAG_NONE, false, false, true); quest:AddENpc(PRIVAREA_PAST_EXIT, QFLAG_NONE, false, true);
end end
end end
@ -115,6 +112,8 @@ function onTalk(player, quest, npc)
elseif (sequence == SEQ_010) then elseif (sequence == SEQ_010) then
seq010_onTalk(player, quest, npc, classId); seq010_onTalk(player, quest, npc, classId);
end end
quest:UpdateENPCs();
end end
function onPush(player, quest, npc) function onPush(player, quest, npc)
@ -138,6 +137,8 @@ function onPush(player, quest, npc)
end end
end end
end end
quest:UpdateENPCs();
end end
function onNotice(player, quest, target) function onNotice(player, quest, target)
@ -148,6 +149,7 @@ function onNotice(player, quest, target)
end end
player:EndEvent(); player:EndEvent();
quest:UpdateENPCs();
end end
function seq000_onTalk(player, quest, npc, classId) function seq000_onTalk(player, quest, npc, classId)
@ -162,7 +164,6 @@ function seq000_onTalk(player, quest, npc, classId)
elseif (classId == BABYFACED_ADVENTURER) then elseif (classId == BABYFACED_ADVENTURER) then
if (not quest:GetFlag(FLAG_SEQ000_MINITUT3)) then if (not quest:GetFlag(FLAG_SEQ000_MINITUT3)) then
callClientFunction(player, "delegateEvent", player, quest, "processTtrMini003"); callClientFunction(player, "delegateEvent", player, quest, "processTtrMini003");
quest:UpdateENpc(BABYFACED_ADVENTURER, ENPC_PROP_QFLAG, QFLAG_NONE);
quest:SetFlag(FLAG_SEQ000_MINITUT3); quest:SetFlag(FLAG_SEQ000_MINITUT3);
else else
callClientFunction(player, "delegateEvent", player, quest, "processEvent000_8"); callClientFunction(player, "delegateEvent", player, quest, "processEvent000_8");
@ -178,7 +179,6 @@ function seq000_onTalk(player, quest, npc, classId)
elseif (classId == VOLUPTUOUS_VIXEN) then elseif (classId == VOLUPTUOUS_VIXEN) then
if (not quest:GetFlag(FLAG_SEQ000_MINITUT2)) then if (not quest:GetFlag(FLAG_SEQ000_MINITUT2)) then
callClientFunction(player, "delegateEvent", player, quest, "processTtrMini002"); callClientFunction(player, "delegateEvent", player, quest, "processTtrMini002");
quest:UpdateENpc(VOLUPTUOUS_VIXEN, ENPC_PROP_QFLAG, QFLAG_NONE);
quest:SetFlag(FLAG_SEQ000_MINITUT2); quest:SetFlag(FLAG_SEQ000_MINITUT2);
else else
callClientFunction(player, "delegateEvent", player, quest, "processEvent000_13"); callClientFunction(player, "delegateEvent", player, quest, "processEvent000_13");
@ -196,24 +196,14 @@ function seq000_onTalk(player, quest, npc, classId)
if (not quest:GetFlag(FLAG_SEQ000_MINITUT0)) then if (not quest:GetFlag(FLAG_SEQ000_MINITUT0)) then
callClientFunction(player, "delegateEvent", player, quest, "processTtrNomal003"); callClientFunction(player, "delegateEvent", player, quest, "processTtrNomal003");
quest:SetFlag(FLAG_SEQ000_MINITUT0); quest:SetFlag(FLAG_SEQ000_MINITUT0);
quest:UpdateENpc(ROSTNSTHAL, ENPC_PROP_CAN_PUSH, false);
quest:UpdateENpc(ROSTNSTHAL, ENPC_PROP_QFLAG, QFLAG_PLATE);
quest:UpdateENpc(VOLUPTUOUS_VIXEN, ENPC_PROP_QFLAG, QFLAG_PLATE);
quest:UpdateENpc(BABYFACED_ADVENTURER, ENPC_PROP_QFLAG, QFLAG_PLATE);
else else
callClientFunction(player, "delegateEvent", player, quest, "processTtrMini001"); callClientFunction(player, "delegateEvent", player, quest, "processTtrMini001");
if (not quest:GetFlag(FLAG_SEQ000_MINITUT1)) then if (not quest:GetFlag(FLAG_SEQ000_MINITUT1)) then
quest:UpdateENpc(ROSTNSTHAL, ENPC_PROP_QFLAG, QFLAG_NONE);
quest:SetFlag(FLAG_SEQ000_MINITUT1); quest:SetFlag(FLAG_SEQ000_MINITUT1);
end end
end end
end end
if (quest:GetFlags() == 0xF) then
quest:UpdateENpc(EXIT_TRIGGER, ENPC_PROP_CAN_PUSH, true);
quest:UpdateENpc(EXIT_TRIGGER, ENPC_PROP_QFLAG, QFLAG_MAP);
end
player:EndEvent(); player:EndEvent();
end end
@ -233,7 +223,7 @@ function seq010_onTalk(player, quest, npc, classId)
elseif (classId == HOB) then elseif (classId == HOB) then
local choice = callClientFunction(player, "delegateEvent", player, quest, "processEvent020_9"); local choice = callClientFunction(player, "delegateEvent", player, quest, "processEvent020_9");
if (choice == 1) then if (choice == 1) then
quest:completeAndReplace(110002); player:ReplaceQuest(quest, "Man0l1");
return; return;
end end
elseif (classId == GERT) then elseif (classId == GERT) then

View file

@ -41,92 +41,20 @@ end
function onSequence(player, quest, sequence) function onSequence(player, quest, sequence)
quest:ClearENpcs(); quest:ClearENpcs();
if (sequence == SEQ_000) then
-- Setup states incase we loaded in.
local rostnsthalFlag = quest:GetFlag(FLAG_SEQ000_MINITUT1) and QFLAG_NONE or QFLAG_PLATE;
local vixenFlag = quest:GetFlag(FLAG_SEQ000_MINITUT2) and QFLAG_NONE or QFLAG_PLATE;
local babyfaceFlag = quest:GetFlag(FLAG_SEQ000_MINITUT3) and QFLAG_NONE or QFLAG_PLATE;
local rostnsthalCanPush = not quest:GetFlag(FLAG_SEQ000_MINITUT0);
local exitCanPush = quest:GetFlags() == 0xF;
local exitFlag = quest:GetFlags() == 0xF and QFLAG_PLATE or QFLAG_NONE;
quest:AddENpc(WELLTRAVELED_MERCHANT);
quest:AddENpc(TIPSY_ADVENTURER);
quest:AddENpc(CULTIVATED_TENDER);
quest:AddENpc(ANXIOUS_ADVENTURER);
quest:AddENpc(BABYFACED_ADVENTURER, babyfaceFlag);
quest:AddENpc(AUSTERE_ADVENTURER);
quest:AddENpc(UNDIGNIFIED_ADVENTURER);
quest:AddENpc(SHADOWY_TRAVELER);
quest:AddENpc(ASTUTE_MERCHANT);
quest:AddENpc(VOLUPTUOUS_VIXEN, vixenFlag);
quest:AddENpc(INDIFFERENT_PASSERBY);
quest:AddENpc(PRATTLING_ADVENTURER);
quest:AddENpc(LANKY_TRAVELER);
quest:AddENpc(GRINNING_ADVENTURER);
quest:AddENpc(ROSTNSTHAL, rostnsthalFlag, true, rostnsthalCanPush);
quest:AddENpc(EXIT_TRIGGER, exitFlag, false, false, exitCanPush);
elseif (sequence == SEQ_005) then
elseif (sequence == SEQ_010) then
quest:AddENpc(HOB);
quest:AddENpc(GERT);
quest:AddENpc(LORHZANT);
quest:AddENpc(MUSCLEBOUND_DECKHAND);
quest:AddENpc(PEARLYTOOTHED_PORTER);
quest:AddENpc(UNDIGNIFIED_ADVENTURER);
quest:AddENpc(WELLTRAVELED_MERCHANT);
quest:AddENpc(VOLUPTUOUS_VIXEN);
quest:AddENpc(LANKY_TRAVELER);
quest:AddENpc(PRIVAREA_PAST_EXIT, QFLAG_NONE, false, false, true);
end
end end
function onTalk(player, quest, npc) function onTalk(player, quest, npc)
local sequence = quest:getSequence(); local sequence = quest:getSequence();
local classId = npc:GetActorClassId(); local classId = npc:GetActorClassId();
if (sequence == SEQ_000) then
seq000_onTalk(player, quest, npc, classId);
elseif (sequence == SEQ_010) then
seq010_onTalk(player, quest, npc, classId);
end
end end
function onPush(player, quest, npc) function onPush(player, quest, npc)
local sequence = quest:getSequence(); local sequence = quest:getSequence();
local classId = npc:GetActorClassId(); local classId = npc:GetActorClassId();
if (sequence == SEQ_000) then
elseif (sequence == SEQ_010) then
end
end
function onNotice(player, quest, target)
local sequence = quest:getSequence();
if (sequence == SEQ_000) then
callClientFunction(player, "delegateEvent", player, quest, "processTtrNomal001withHQ");
end
end
function seq000_onTalk(player, quest, npc, classId)
if (classId == WELLTRAVELED_MERCHANT) then
callClientFunction(player, "delegateEvent", player, quest, "processEvent000_4");
elseif (classId == TIPSY_ADVENTURER) then
callClientFunction(player, "delegateEvent", player, quest, "processEvent000_5");
end
player:EndEvent();
end end
function getJournalMapMarkerList(player, quest) function getJournalMapMarkerList(player, quest)
local sequence = quest:getSequence(); local sequence = quest:getSequence();
if (sequence == SEQ_000) then
-- return MRKR_ROSTNSTHAL, MRKR_BABYFACED_ADVENTURER, MRKR_VOLUPTUOUS_VIXEN;
elseif (sequence == SEQ_010) then
-- return MRKR_HOB;
end
end end

View file

@ -1,22 +1,35 @@
/* -- --------------------------------------------------------
MySQL Data Transfer -- Host: 127.0.0.1
Source Host: localhost -- Server version: 5.6.17 - MySQL Community Server (GPL)
Source Database: ffxiv_server -- Server OS: Win64
Target Host: localhost -- HeidiSQL Version: 10.1.0.5464
Target Database: ffxiv_server -- --------------------------------------------------------
Date: 4/2/2017 2:27:54 PM
*/
SET FOREIGN_KEY_CHECKS=0; /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
-- ---------------------------- /*!40101 SET NAMES utf8 */;
-- Table structure for characters_quest_scenario /*!50503 SET NAMES utf8mb4 */;
-- ---------------------------- /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
CREATE TABLE `characters_quest_scenario` ( /*!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.characters_quest_scenario
CREATE TABLE IF NOT EXISTS `characters_quest_scenario` (
`characterId` int(10) unsigned NOT NULL, `characterId` int(10) unsigned NOT NULL,
`slot` smallint(5) unsigned NOT NULL, `slot` smallint(5) unsigned NOT NULL,
`questId` int(10) unsigned NOT NULL, `questId` int(10) unsigned NOT NULL,
`currentPhase` int(10) unsigned NOT NULL DEFAULT '0', `sequence` int(10) unsigned NOT NULL DEFAULT '0',
`questData` longtext, `flags` mediumint(8) unsigned NOT NULL DEFAULT '0',
`questFlags` int(10) unsigned NOT NULL DEFAULT '0', `counter1` smallint(5) unsigned NOT NULL DEFAULT '0',
`counter2` smallint(5) unsigned NOT NULL DEFAULT '0',
`counter3` smallint(5) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`characterId`,`slot`) PRIMARY KEY (`characterId`,`slot`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1; ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
-- Data exporting was unselected.
/*!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 */;

View file

@ -1558,24 +1558,21 @@ namespace Meteor.Map.Actors
} }
} }
public void ReplaceQuest(uint oldId, uint newId) public void ReplaceQuest(Quest oldQuest, string questCode)
{
if (HasQuest(oldId))
{ {
for (int i = 0; i < questScenario.Length; i++) for (int i = 0; i < questScenario.Length; i++)
{ {
if (questScenario[i] != null && questScenario[i].GetQuestId() == oldId) if (questScenario[i] != null && questScenario[i].Equals(oldQuest))
{ {
Quest baseQuest = (Quest) Server.GetStaticActors((0xA0F00000 | newId)); Quest baseQuest = (Quest) Server.GetStaticActors(questCode);
playerWork.questScenario[i] = (0xA0F00000 | newId);
questScenario[i] = new Quest(this, baseQuest); questScenario[i] = new Quest(this, baseQuest);
playerWork.questScenario[i] = questScenario[i].Id;
Database.SaveQuest(this, questScenario[i]); Database.SaveQuest(this, questScenario[i]);
SendQuestClientUpdate(i); SendQuestClientUpdate(i);
break; break;
} }
} }
} }
}
public bool CanAcceptQuest(string name) public bool CanAcceptQuest(string name)
{ {
@ -1646,6 +1643,11 @@ namespace Meteor.Map.Actors
return false; 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++)

View file

@ -46,7 +46,7 @@ namespace Meteor.Map.actors.director
private Coroutine currentCoroutine; private Coroutine currentCoroutine;
public Director(uint id, Area zone, string directorPath, bool hasContentGroup, params object[] args) public Director(uint id, Area zone, string directorPath, bool hasContentGroup, params object[] args)
: base((6 << 28 | zone.CurrentArea.ZoneId << 19 | (uint)id)) : base((6 << 28 | zone.ZoneId << 19 | (uint)id + 2))
{ {
directorId = id; directorId = id;
CurrentArea = zone; CurrentArea = zone;

View file

@ -51,6 +51,24 @@ namespace Meteor.Map.Actors
this.isEmoteEnabled = isEmoteEnabled; this.isEmoteEnabled = isEmoteEnabled;
this.isPushEnabled = isPushEnabled; 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 private struct QuestData
@ -73,59 +91,38 @@ namespace Meteor.Map.Actors
private Player Owner; private Player Owner;
private ushort currentSequence; private ushort currentSequence;
private QuestData data = new QuestData(); private QuestData data = new QuestData();
private Dictionary<uint, ENpcQuestInstance> ActiveENpcs = new Dictionary<uint, ENpcQuestInstance>(); private bool dataDirty = false;
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 isEmoteEnabled = false, bool isPushEnabled = false, bool isSpawned = false) public void AddENpc(uint classId, byte flagType = 0, bool isTalkEnabled = true, bool isPushEnabled = false, bool isEmoteEnabled = false, bool isSpawned = false)
{ {
if (ActiveENpcs.ContainsKey(classId)) ENpcQuestInstance instanceUpdated = null;
return;
ENpcQuestInstance instance = new ENpcQuestInstance(classId, flagType, isSpawned, isTalkEnabled, isEmoteEnabled, isPushEnabled); if (OldENPCs.ContainsKey(classId))
ActiveENpcs.Add(classId, instance); {
Owner.playerSession.UpdateQuestNpcInInstance(instance); if (OldENPCs[classId].IsChanged(flagType, isTalkEnabled, isPushEnabled, isEmoteEnabled, isSpawned))
{
instanceUpdated = OldENPCs[classId];
instanceUpdated.Update(flagType, isTalkEnabled, isPushEnabled, isEmoteEnabled, isSpawned);
CurrentENPCs.Add(classId, instanceUpdated);
}
OldENPCs.Remove(classId);
}
else
{
instanceUpdated = new ENpcQuestInstance(classId, flagType, isSpawned, isTalkEnabled, isEmoteEnabled, isPushEnabled);
CurrentENPCs.Add(classId, instanceUpdated);
} }
public void ClearENpcs() if (instanceUpdated != null)
{ Owner.playerSession.UpdateQuestNpcInInstance(instanceUpdated);
foreach (ENpcQuestInstance instance in ActiveENpcs.Values)
Owner.playerSession.UpdateQuestNpcInInstance(instance, true);
ActiveENpcs.Clear();
}
public void UpdateENpc(uint classId, ENpcProperty property, object value)
{
if (!ActiveENpcs.ContainsKey(classId))
return;
ENpcQuestInstance instance = ActiveENpcs[classId];
switch (property)
{
case ENpcProperty.QuestFlag:
if (value is double)
instance.questFlagType = (byte)(double)value;
else if (value is int)
instance.questFlagType = (byte)value;
break;
case ENpcProperty.CanTalk:
instance.isTalkEnabled = (bool)value;
break;
case ENpcProperty.CanPush:
instance.isPushEnabled = (bool)value;
break;
case ENpcProperty.CanEmote:
instance.isEmoteEnabled = (bool)value;
break;
}
Owner.playerSession.UpdateQuestNpcInInstance(instance, false);
} }
public ENpcQuestInstance GetENpcInstance(uint classId) public ENpcQuestInstance GetENpcInstance(uint classId)
{ {
if (ActiveENpcs.ContainsKey(classId)) if (CurrentENPCs.ContainsKey(classId))
return ActiveENpcs[classId]; return CurrentENPCs[classId];
return null; return null;
} }
@ -154,11 +151,25 @@ 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) public bool IsQuestENPC(Player caller, Npc npc)
{ {
List<LuaParam> returned = LuaEngine.GetInstance().CallLuaFunctionForReturn(caller, this, "IsQuestENPC", true, npc, this); List<LuaParam> returned = LuaEngine.GetInstance().CallLuaFunctionForReturn(caller, this, "IsQuestENPC", true, npc, this);
bool scriptReturned = returned != null && returned.Count != 0 && returned[0].typeID == 3; bool scriptReturned = returned != null && returned.Count != 0 && returned[0].typeID == 3;
return scriptReturned || ActiveENpcs.ContainsKey(npc.GetActorClassId()); return scriptReturned || CurrentENPCs.ContainsKey(npc.GetActorClassId());
} }
@ -195,7 +206,8 @@ namespace Meteor.Map.Actors
Owner.SendGameMessage(Server.GetWorldManager().GetActor(), 25116, 0x20, (object)GetQuestId()); Owner.SendGameMessage(Server.GetWorldManager().GetActor(), 25116, 0x20, (object)GetQuestId());
currentSequence = sequence; currentSequence = sequence;
LuaEngine.GetInstance().CallLuaFunction(Owner, this, "onSequence", false, currentSequence); dataDirty = true;
UpdateENPCs();
} }
public void ClearData() public void ClearData()
@ -206,70 +218,88 @@ namespace Meteor.Map.Actors
public void SetFlag(int index) public void SetFlag(int index)
{ {
if (index >= 0 && index < 32) if (index >= 0 && index < 32)
{
data.flags |= (uint)(1 << index); data.flags |= (uint)(1 << index);
dataDirty = true;
}
} }
public void ClearFlag(int index) public void ClearFlag(int index)
{ {
if (index >= 0 && index < 32) if (index >= 0 && index < 32)
{
data.flags &= (uint)~(1 << index); data.flags &= (uint)~(1 << index);
dataDirty = true;
}
} }
public void IncCounter(int num) public void IncCounter(int num)
{ {
dataDirty = true;
switch (num) switch (num)
{ {
case 0: case 0:
data.counter1++; data.counter1++;
break; return;
case 1: case 1:
data.counter2++; data.counter2++;
break; return;
case 2: case 2:
data.counter3++; data.counter3++;
break; return;
case 3: case 3:
data.counter4++; data.counter4++;
break; return;
} }
dataDirty = false;
} }
public void DecCounter(int num) public void DecCounter(int num)
{ {
dataDirty = true;
switch (num) switch (num)
{ {
case 0: case 0:
data.counter1--; data.counter1--;
break; return;
case 1: case 1:
data.counter2--; data.counter2--;
break; return;
case 2: case 2:
data.counter3--; data.counter3--;
break; return;
case 3: case 3:
data.counter4--; data.counter4--;
break; return;
} }
dataDirty = false;
} }
public void SetCounter(int num, ushort value) public void SetCounter(int num, ushort value)
{ {
dataDirty = true;
switch (num) switch (num)
{ {
case 0: case 0:
data.counter1 = value; data.counter1 = value;
break; return;
case 1: case 1:
data.counter2 = value; data.counter2 = value;
break; return;
case 2: case 2:
data.counter3 = value; data.counter3 = value;
break; return;
case 3: case 3:
data.counter4 = value; data.counter4 = value;
break; return;
} }
dataDirty = false;
} }
public bool GetFlag(int index) public bool GetFlag(int index)

View file

@ -39,6 +39,9 @@ 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.DataObjects;
using Meteor.Map.actors.chara.player; using Meteor.Map.actors.chara.player;
using Meteor.Map.Actors.Chara;
using Meteor.Map.dataobjects.chara;
using Meteor.Map.actors.chara;
namespace Meteor.Map.lua namespace Meteor.Map.lua
{ {
@ -69,12 +72,16 @@ namespace Meteor.Map.lua
UserData.RegisterType<LuaEngine>(); UserData.RegisterType<LuaEngine>();
UserData.RegisterType<Player>(); UserData.RegisterType<Player>();
UserData.RegisterType<CharaWork>();
UserData.RegisterType<ParameterSave>();
UserData.RegisterType<PlayerWork>();
UserData.RegisterType<Command>(); UserData.RegisterType<Command>();
UserData.RegisterType<Npc>(); UserData.RegisterType<Npc>();
UserData.RegisterType<Quest>(); UserData.RegisterType<Quest>();
UserData.RegisterType<Zone>(); UserData.RegisterType<Zone>();
UserData.RegisterType<InventoryItem>(); UserData.RegisterType<InventoryItem>();
UserData.RegisterType<ItemPackage>(); UserData.RegisterType<ItemPackage>();
UserData.RegisterType<ReferencedItemPackage>();
UserData.RegisterType<PrivateArea>(); UserData.RegisterType<PrivateArea>();
UserData.RegisterType<PrivateAreaContent>(); UserData.RegisterType<PrivateAreaContent>();
UserData.RegisterType<Director>(); UserData.RegisterType<Director>();