diff --git a/Data/scripts/base/chara/npc/object/PrivateAreaPastExit.lua b/Data/scripts/base/chara/npc/object/PrivateAreaPastExit.lua index 6149b464..446fd05d 100644 --- a/Data/scripts/base/chara/npc/object/PrivateAreaPastExit.lua +++ b/Data/scripts/base/chara/npc/object/PrivateAreaPastExit.lua @@ -1,17 +1,37 @@ -function init(npc) +require("global"); + +--[[ + +PrivateAreaPastExit + +This object contains the player inside a PrivateAreaPast, stopping them from escaping it's bounds. It is the +object that generates the circle graphic on the minimap. This object always has two push triggers, an inner +and outer inverted circle. The inner one is named "caution" and the outer one is named "exit". When the player +leaves the inner circle a warning is shown and when they leave the outer circle they either leave the instance +or get warped back to the center. + +]] + +function init(privAreaExit) return false, false, 0, 0; end -function onEventStarted(player, npc, eventType, eventName) +function onEventStarted(player, privAreaExit, eventType, eventName) player:EndEvent(); if (eventName == "caution") then - player:SendGameMessage(player, GetWorldMaster(), 34109, 0x20); + player:SendGameMessage(player, GetWorldMaster(), 34109, MESSAGE_TYPE_SYSTEM); -- You are about to leave the instance. elseif (eventName == "exit") then - local activeQuests = player:GetQuestsForNpc(npc); - print(tostring(#activeQuests)); - if (#activeQuests >= 1) then - activeQuests[1]:OnPush(player, npc, eventName); + local area = privAreaExit.CurrentArea; + if (area.IsPrivate()) then + -- If you can leave, warp to public zone and show message. + if (area.CanExitPrivateArea()) then + player:SendGameMessage(player, GetWorldMaster(), 34110, MESSAGE_TYPE_SYSTEM); -- You have left the instance. + GetWorldManager():WarpToPublicArea(player); + -- Otherwise warp back to the center of the zone. + else + GetWorldManager():WarpToCharaPosition(player, privAreaExit); + end end end end \ No newline at end of file diff --git a/Data/scripts/commands/gm/nudge.lua b/Data/scripts/commands/gm/nudge.lua index bb3ceb50..573eb92b 100644 --- a/Data/scripts/commands/gm/nudge.lua +++ b/Data/scripts/commands/gm/nudge.lua @@ -24,6 +24,21 @@ vertical = { ["DESCEND"] = -1, } +horizontal = { +["RIGHT"] = 2, +["R"] = 2, +["+"] = 2, +["LEFT"] = -2, +["L"] = -2, +["0"] = -2 +} + +rotation = { +["ROTATE"] = 3, +["ORIENTATION"] = 3, +["O"] = 3 +} + function onTrigger(player, argc, arg1, arg2) local pos = player:GetPos(); local x = pos[1]; @@ -54,16 +69,24 @@ function onTrigger(player, argc, arg1, arg2) distance = checkArg1; elseif checkArg1 and not checkArg2 then -- If first is number and second is string distance = checkArg1; - if vertical[string.upper(arg2)] then -- Check vertical direction on string, otherwise throw param error + if vertical[string.upper(arg2)] then -- Check vertical direction on string direction = vertical[string.upper(arg2)]; + elseif horizontal[string.upper(arg2)] then -- Check horizontal direction on string + direction = horizontal[string.upper(arg2)]; + elseif rotation[string.upper(arg2)] then -- Check rotation on string, otherwise throw param error + direction = rotation[string.upper(arg2)]; else player:SendMessage(messageID, sender, "Unknown parameters! Usage: \n"..properties.description); return; end elseif (not checkArg1) and checkArg2 then -- If first is string and second is number distance = checkArg2; - if vertical[string.upper(arg1)] then -- Check vertical direction on string, otherwise throw param error + if vertical[string.upper(arg1)] then -- Check vertical direction on string direction = vertical[string.upper(arg1)]; + elseif horizontal[string.upper(arg1)] then -- Check horizontal direction on string + direction = horizontal[string.upper(arg1)]; + elseif rotation[string.upper(arg1)] then -- Check rotation on string, otherwise throw param error + direction = rotation[string.upper(arg1)]; else player:SendMessage(messageID, sender, "Unknown parameters! Usage: \n"..properties.description); return; @@ -86,6 +109,19 @@ function onTrigger(player, argc, arg1, arg2) y = y - distance; message = string.format("Positioning down %s yalms.", distance); worldManager:DoPlayerMoveInZone(player, x, y, z, rot, 0x0); + elseif direction == 2 then + local px = x - distance * math.cos(angle - math.pi/2); + local pz = z + distance * math.sin(angle - math.pi/2); + message = string.format("Positioning right %s yalms.", distance); + worldManager:DoPlayerMoveInZone(player, px, y, pz, rot, 0x0); + elseif direction == -2 then + local px = x - distance * math.cos(angle + math.pi/2); + local pz = z + distance * math.sin(angle + math.pi/2); + message = string.format("Positioning left %s yalms.", distance); + worldManager:DoPlayerMoveInZone(player, px, y, pz, rot, 0x0); + elseif direction == 3 then + message = string.format("ROTATE down %s yalms.", distance); + worldManager:DoPlayerMoveInZone(player, x, y, z, distance, 0x0); else local px = x - distance * math.cos(angle); local pz = z + distance * math.sin(angle); diff --git a/Data/scripts/commands/gm/nudgenpc.lua b/Data/scripts/commands/gm/nudgenpc.lua new file mode 100644 index 00000000..e1719e5f --- /dev/null +++ b/Data/scripts/commands/gm/nudgenpc.lua @@ -0,0 +1,140 @@ +require("global"); + +properties = { + permissions = 0, + parameters = "ss", + description = +[[ +Positions a targeted npc by some , defaults to 5 yalms. +!nudge | +!nudge | +!nudge | +!nudge | +!nudge | +]], + +} + +vertical = { +["UP"] = 1, +["U"] = 1, +["+"] = 1, +["ASCEND"] = 1, +["DOWN"] = -1, +["D"] = -1, +["-"] = -1, +["DESCEND"] = -1, +} + +horizontal = { +["RIGHT"] = 2, +["R"] = 2, +["+"] = 2, +["LEFT"] = -2, +["L"] = -2, +["0"] = -2 +} + +rotation = { +["ROTATE"] = 3, +["ORIENTATION"] = 3, +["O"] = 3 +} + +function onTrigger(player, argc, arg1, arg2) + local messageID = MESSAGE_TYPE_SYSTEM; + local sender = "[nudge] "; + + local targetActor = player.CurrentArea.FindActorInArea(player.currentTarget) or nil; + + + if (targetActor == nil) then + player:SendMessage(MESSAGE_TYPE_SYSTEM, sender, "No target was selected.\n"); + return; + end + + local pos = targetActor:GetPos(); + local x = pos[1]; + local y = pos[2]; + local z = pos[3]; + local rot = pos[4]; + local zone = pos[5]; + local angle = rot + (math.pi/2); + + local worldManager = GetWorldManager(); + local distance = 5; + local direction = 0; + + local checkArg1 = tonumber(arg1); + local checkArg2 = tonumber(arg2); + + if argc == 1 then + if checkArg1 then + distance = checkArg1; + else + player:SendMessage(messageID, sender, "Unknown parameters! Usage: \n"..properties.description); + return; + end + elseif argc == 2 then + if checkArg1 and checkArg2 then -- If both are numbers, just ignore second argument + distance = checkArg1; + elseif checkArg1 and not checkArg2 then -- If first is number and second is string + distance = checkArg1; + if vertical[string.upper(arg2)] then -- Check vertical direction on string + direction = vertical[string.upper(arg2)]; + elseif horizontal[string.upper(arg2)] then -- Check horizontal direction on string + direction = horizontal[string.upper(arg2)]; + elseif rotation[string.upper(arg2)] then -- Check rotation on string, otherwise throw param error + direction = rotation[string.upper(arg2)]; + else + player:SendMessage(messageID, sender, "Unknown parameters! Usage: \n"..properties.description); + return; + end + elseif (not checkArg1) and checkArg2 then -- If first is string and second is number + distance = checkArg2; + if vertical[string.upper(arg1)] then -- Check vertical direction on string + direction = vertical[string.upper(arg1)]; + elseif horizontal[string.upper(arg1)] then -- Check horizontal direction on string + direction = horizontal[string.upper(arg1)]; + elseif rotation[string.upper(arg1)] then -- Check rotation on string, otherwise throw param error + direction = rotation[string.upper(arg1)]; + else + player:SendMessage(messageID, sender, "Unknown parameters! Usage: \n"..properties.description); + return; + end + else + player:SendMessage(messageID, sender, "Unknown parameters! Usage: \n"..properties.description); + return; + end + end + + if direction == 1 then + y = y + distance; + targetActor:SetPos(x,y,z,rot,true, player); + message = string.format("Moved %s @ %f, %f, %f, %f", targetActor:GetUniqueId(), x, y, z, rot); + elseif direction == -1 then + y = y - distance; + targetActor:SetPos(x,y,z,rot,true, player); + message = string.format("Moved %s @ %f, %f, %f, %f", targetActor:GetUniqueId(), x, y, z, rot); + elseif direction == 2 then + local px = x - distance * math.cos(angle - math.pi/2); + local pz = z + distance * math.sin(angle - math.pi/2); + targetActor:SetPos(px, y, pz, rot, true, player); + message = string.format("Moved %s @ %f, %f, %f, %f", targetActor:GetUniqueId(), px, y, pz, rot); + elseif direction == -2 then + local px = x - distance * math.cos(angle + math.pi/2); + local pz = z + distance * math.sin(angle + math.pi/2); + targetActor:SetPos(px, y, pz, rot, true, player); + message = string.format("Moved %s @ %f, %f, %f, %f", targetActor:GetUniqueId(), px, y, pz, rot); + elseif direction == 3 then + targetActor:SetPos(x, y, z, distance, true, player); + message = string.format("Moved %s @ %f, %f, %f, %f", targetActor:GetUniqueId(), x, y, z, distance); + else + local px = x - distance * math.cos(angle); + local pz = z + distance * math.sin(angle); + targetActor:SetPos(px, y, pz, rot, true, player); + message = string.format("Moved %s @ %f, %f, %f, %f", targetActor:GetUniqueId(), px, y, pz, rot); + end + + player:SendMessage(messageID, sender, message); +end diff --git a/Data/scripts/commands/gm/testbnpckill b/Data/scripts/commands/gm/testbnpckill new file mode 100644 index 00000000..5f70394e --- /dev/null +++ b/Data/scripts/commands/gm/testbnpckill @@ -0,0 +1,16 @@ +require("global"); + +properties = { + permissions = 0, + parameters = "d", + description = "Simulates killing a bnpc. Used for quest testing.", +} + +function onTrigger(player, argc, actorClassId) + if (argc == 1) then + player:HandleBNpcKill(actorClassId); + player:SendMessage(0x20, "", "Simulating BNpc kill for actor class id: " .. tostring(actorClassId)); + else + player:SendMessage(0x20, "", "No actor class id provided."); + end +end \ No newline at end of file diff --git a/Data/scripts/quests/man/man0l1.lua b/Data/scripts/quests/man/man0l1.lua index b9b991b2..0a33d345 100644 --- a/Data/scripts/quests/man/man0l1.lua +++ b/Data/scripts/quests/man/man0l1.lua @@ -28,7 +28,7 @@ SEQ_065 = 65; -- Return to FSH Guild SEQ_070 = 70; -- Contact Baderon on LS SEQ_075 = 75; -- Go to the ARM and BSM Guilds. Talk to Bodenolf. SEQ_080 = 80; -- Speak with H'naanza -SEQ_085 = 85; -- Speak with Bodenolf +SEQ_085 = 85; -- Walk into push trigger SEQ_090 = 90; -- Contact Baderon on LS SEQ_092 = 92; -- Return to Baderon. @@ -91,7 +91,7 @@ JOELLAUT = 1000163; WERNER = 1000247; HIHINE = 1000267; TRINNE = 1000268; -ECHO_EXIT_TRIGGER2 = 1090001; +ECHO_EXIT_TRIGGER2 = 1090007; -- Quest Markers diff --git a/Data/scripts/quests/man/man1l0.lua b/Data/scripts/quests/man/man1l0.lua new file mode 100644 index 00000000..2dd98fa8 --- /dev/null +++ b/Data/scripts/quests/man/man1l0.lua @@ -0,0 +1,398 @@ +require("global"); + +--[[ + +Quest Script + +Name: Legends Adrift +Code: Man1l0 +Id: 110003 +Prereq: Treasures of the Main (Man0l1 - 110002) + +]] + +-- Sequence Numbers +SEQ_000 = 0; -- Echo intance with Y'shtola, Baderon, Etc. Talk to Y'shtola. +SEQ_010 = 10; -- Echo instance, talk with Baderon. +SEQ_020 = 20; -- Head to MRD guild and talk to Waekbyrt. +SEQ_030 = 30; -- Head down the Astalicia to the push trigger. +SEQ_040 = 40; -- Head up the Astalicia to the push trigger. +SEQ_050 = 50; -- Contact Baderon on the Link Pearl. +SEQ_060 = 60; -- Head to the FSH guild and push the trigger. +SEQ_070 = 70; -- Head to a spot in Lower La Noscea. +SEQ_080 = 80; -- Contact Baderon on the Link Pearl. +SEQ_090 = 90; -- Speak to P'tahjha at the ACN guild. +SEQ_100 = 100; -- Echo instance, head downstairs to push a trigger and cutscene. +SEQ_110 = 110; -- Echo instance still, head upstairs to trigger a cutscene. +SEQ_120 = 120; -- Contact Baderon on the Link Pearl. +SEQ_122 = 122; -- Head back to Baderon to finish the quest. + +-- Quest Actors +BADERON = 1000137; +YSHTOLA = 1000001; + +-- ADV Guild Echo +ADVENTURER = 1000101; +WHISPERING_ADVENTURER = 1000102; +UNAPPROACHABLE_ADVENTURER = 1000103; +FISH_SMELLING_ADVENTURER = 1000104; +SPEAR_WIELDING_ADVENTURER = 1000105; +TRIGGER_ADVGUILD = 1090080; + +-- MRD Guild Echo +WAEKBYRT = 1000003; +HULKING_CUDA_KNIGHT = 1000182; +SOPHISTICATED_CUDA_KNIGHT = 1000108; +FRIGHTENED_CUDA_KNIGHT = 1000110; +ZEALOUS_PIRATE = 1000112; +ENRAGED_PIRATE = 1000113; +TRIGGER_MRD = 1090081; + +-- MRD Guild Echo 2 +DISGRUNTLED_PIRATE = 1000087; +PINE_SCENTED_PIRATE = 1000088; +BARITONE_PIRATE = 1000089; +BAYARD = 1000190; + +-- FSH Guild Sequences +NNMULIKA = 1000153; +SISIPU = 1000156; +TRIGGER_FSH = 1090006; +TRIGGER_SEAFLD = 1090082; + +-- ACN Guild Echo +ASSESSOR = 1000121; +PTAHJHA = 1000150; +HALDBERK = 1000160; +LILINA = 1000178; +DODOROBA = 1000196; +IVAN = 1000197; +MERODAULYN = 1000008; +COQUETTISH_PIRATE = 1000868; +VOLUPTUOUS_PIRATE = 1000115; +PEACOCKISH_PIRATE = 1000118; +TRIGGER_ACN_LOWER = 1090083; +TRIGGER_ACN_UPPER = 1090084; + +-- Quest Markers +MRKR_TRIGGER_FSH = 11000306; +MRKR_TRIGGER_SEAFLD = 11000307; +MRKR_TRIGGER_ANC_LOWER = 11000308; + +-- Msg packs for the Npc LS +NPCLS_MSGS = { + {57, 58, 59}, -- SEQ_050 + {92, 93, 94}, -- SEQ_070 + {140, 141} -- SEQ_120 +}; + +function onStart(player, quest) + quest:StartSequence(SEQ_000); + GetWorldManager():WarpToPrivateArea(player, "PrivateAreaMasterPast", 3, -430.55, 40.2, 185.41, 1.89); +end + +function onFinish(player, quest) +end + +function onStateChange(player, quest, sequence) + local data = quest:GetData(); + if (sequence == SEQ_ACCEPT) then + quest:SetENpc(BADERON, QFLAG_PLATE); + elseif (sequence == SEQ_000) then + quest:SetENpc(BADERON); + quest:SetENpc(ADVENTURER); + quest:SetENpc(WHISPERING_ADVENTURER); + quest:SetENpc(UNAPPROACHABLE_ADVENTURER); + quest:SetENpc(FISH_SMELLING_ADVENTURER); + quest:SetENpc(SPEAR_WIELDING_ADVENTURER); + quest:SetENpc(TRIGGER_ADVGUILD, QFLAG_MAP, false, true); + elseif (sequence == SEQ_010) then + quest:SetENpc(BADERON, QFLAG_PLATE); + quest:SetENpc(ADVENTURER); + quest:SetENpc(WHISPERING_ADVENTURER); + quest:SetENpc(UNAPPROACHABLE_ADVENTURER); + quest:SetENpc(FISH_SMELLING_ADVENTURER); + quest:SetENpc(SPEAR_WIELDING_ADVENTURER); + quest:SetENpc(YSHTOLA); + elseif (sequence == SEQ_020) then + quest:SetENpc(WAEKBYRT, QFLAG_PLATE); + quest:SetENpc(BADERON); + elseif (sequence == SEQ_030) then + quest:SetENpc(TRIGGER_MRD, QFLAG_MAP, false, true); + quest:SetENpc(HULKING_CUDA_KNIGHT); + quest:SetENpc(SOPHISTICATED_CUDA_KNIGHT); + quest:SetENpc(FRIGHTENED_CUDA_KNIGHT); + quest:SetENpc(ZEALOUS_PIRATE); + quest:SetENpc(ENRAGED_PIRATE); + quest:SetENpc(WAEKBYRT); + elseif (sequence == SEQ_040) then + quest:SetENpc(TRIGGER_MRD, QFLAG_MAP, false, true); + quest:SetENpc(PINE_SCENTED_PIRATE); + quest:SetENpc(BARITONE_PIRATE); + quest:SetENpc(BAYARD); + quest:SetENpc(DISGRUNTLED_PIRATE); + elseif (sequence == SEQ_060) then + quest:SetENpc(TRIGGER_FSH, QFLAG_MAP, false, true); + quest:SetENpc(BADERON); + elseif (sequence == SEQ_070) then + quest:SetENpc(TRIGGER_SEAFLD, QFLAG_MAP, false, true); + quest:SetENpc(NNMULIKA); + elseif (sequence == SEQ_090) then + quest:SetENpc(PTAHJHA, QFLAG_PLATE); + elseif (sequence == SEQ_100) then + quest:SetENpc(TRIGGER_ACN_LOWER, QFLAG_MAP, false, true); + quest:SetENpc(ASSESSOR); + quest:SetENpc(HALDBERK); + quest:SetENpc(LILINA); + quest:SetENpc(VOLUPTUOUS_PIRATE); + quest:SetENpc(PEACOCKISH_PIRATE); + quest:SetENpc(MERODAULYN); + quest:SetENpc(COQUETTISH_PIRATE); + quest:SetENpc(IVAN); + elseif (sequence == SEQ_110) then + quest:SetENpc(TRIGGER_ACN_UPPER, QFLAG_MAP, false, true); + elseif (sequence == SEQ_122) then + quest:SetENpc(BADERON, QFLAG_REWARD); + end + +end + +function onTalk(player, quest, npc) + local sequence = quest:getSequence(); + local classId = npc:GetActorClassId(); + + if (sequence == SEQ_ACCEPT) then + if (classId == BADERON) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent200"); + player:EndEvent(); + player:AcceptQuest(quest, true); + return; + end + elseif (sequence == SEQ_000) then + seq000_010_onTalk(player, quest, npc, classId); + elseif (sequence == SEQ_010) then + if (classId == BADERON) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent215"); + player:EndEvent(); + quest:StartSequence(SEQ_020); + GetWorldManager():WarpToPublicArea(player); + return; + elseif (classId == YSHTOLA) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent200_8"); + else + seq000_010_onTalk(player, quest, npc, classId); + end + elseif (sequence == SEQ_020) then + if (classId == WAEKBYRT) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent400"); + quest:StartSequence(SEQ_030); + player:EndEvent(); + GetWorldManager():WarpToPrivateArea(player, "PrivateAreaMasterPast", 6, -754.03, 7.352, 382.872, 3.133); + return; + elseif (classId == BADERON) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent215_2"); + end + elseif (sequence == SEQ_030 or sequence == SEQ_040) then + seq000_030_040_onTalk(player, quest, npc, classId) + elseif (sequence == SEQ_060) then + if (classId == NNMULIKA) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent600"); + elseif (classId == BADERON) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent420_2"); + end + elseif (sequence == SEQ_070) then + if (classId == NNMULIKA) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent600_2"); + end + elseif (sequence == SEQ_090) then + if (classId == PTAHJHA) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent2000"); + quest:StartSequence(SEQ_100); + player:EndEvent(); + GetWorldManager():WarpToPrivateArea(player, "PrivateAreaMasterPast", 7); + elseif (classId == BADERON) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent610_2"); + end + elseif (sequence == SEQ_100) then + seq000_100_onTalk(player, quest, npc, classId) + elseif (sequence == SEQ_110) then + elseif (sequence == SEQ_122) then + if (classId == BADERON) then + callClientFunction(player, "delegateEvent", player, quest, "processEventComplete"); + callClientFunction(player, "delegateEvent", player, quest, "sqrwa", 300, 1, 1, 2); + player:EndEvent(); + player:CompleteQuest(quest); + return; + end + end + + player:EndEvent(); + quest:UpdateENPCs(); +end + +function seq000_010_onTalk(player, quest, npc, classId) + if (classId == ADVENTURER) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent200_2"); + elseif (classId == WHISPERING_ADVENTURER) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent200_3"); + elseif (classId == UNAPPROACHABLE_ADVENTURER) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent200_4"); + elseif (classId == FISH_SMELLING_ADVENTURER) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent200_5"); + elseif (classId == SPEAR_WIELDING_ADVENTURER) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent200_6"); + elseif (classId == BADERON) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent200_7"); + end +end + +function seq000_030_040_onTalk(player, quest, npc, classId) + if (classId == HULKING_CUDA_KNIGHT) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent400_2"); + elseif (classId == SOPHISTICATED_CUDA_KNIGHT) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent400_3"); + elseif (classId == FRIGHTENED_CUDA_KNIGHT) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent400_4"); + elseif (classId == ZEALOUS_PIRATE) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent400_5"); + elseif (classId == ENRAGED_PIRATE) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent400_6"); + elseif (classId == WAEKBYRT) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent400_7"); + elseif (classId == PINE_SCENTED_PIRATE) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent410_2"); + elseif (classId == BARITONE_PIRATE) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent410_3"); + elseif (classId == BAYARD) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent410_4"); + elseif (classId == DISGRUNTLED_PIRATE) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent410_5"); + end +end + +function seq000_100_onTalk(player, quest, npc, classId) + if (classId == ASSESSOR) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent2000_2"); + elseif (classId == 0) then -- !!!MISSING DIALOG OWNER!!! + callClientFunction(player, "delegateEvent", player, quest, "processEvent2000_3"); + elseif (classId == HALDBERK) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent2000_4"); + elseif (classId == LILINA) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent2000_5"); + elseif (classId == VOLUPTUOUS_PIRATE) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent2000_6"); + elseif (classId == PEACOCKISH_PIRATE) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent2000_7"); + elseif (classId == MERODAULYN) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent2000_8"); + elseif (classId == COQUETTISH_PIRATE) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent2000_9"); + elseif (classId == 0) then -- !!!MISSING DIALOG OWNER!!! + callClientFunction(player, "delegateEvent", player, quest, "processEvent2000_10"); + elseif (classId == 0) then -- !!!MISSING DIALOG OWNER!!! + callClientFunction(player, "delegateEvent", player, quest, "processEvent2000_11"); + elseif (classId == IVAN) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent2000_12"); + end +end + +function onPush(player, quest, npc) + local data = quest:GetData(); + local sequence = quest:getSequence(); + local classId = npc:GetActorClassId(); + + if (sequence == SEQ_000) then + if (classId == TRIGGER_ADVGUILD) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent210"); + quest:StartSequence(SEQ_010); + end + elseif (sequence == SEQ_030) then + if (classId == TRIGGER_MRD) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent410"); + quest:StartSequence(SEQ_040); + player:EndEvent(); + GetWorldManager():WarpToPosition(player, -764.519, -3.146, 384.154, 1.575); + return; + end + elseif (sequence == SEQ_040) then + if (classId == TRIGGER_MRD) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent420"); + quest:NewNpcLsMsg(1); + quest:StartSequence(SEQ_050); + player:EndEvent(); + GetWorldManager():WarpToPublicArea(player); + return; + end + elseif (sequence == SEQ_060) then + if (classId == TRIGGER_FSH) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent600"); + quest:StartSequence(SEQ_070); + end + elseif (sequence == SEQ_070) then + if (classId == TRIGGER_SEAFLD) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent610"); + quest:NewNpcLsMsg(1); + quest:StartSequence(SEQ_080); + end + elseif (sequence == SEQ_100) then + if (classId == TRIGGER_ACN_LOWER) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent2001"); + quest:StartSequence(SEQ_110); + player:EndEvent(); + GetWorldManager():WarpToPosition(player, -785.938, -0.62, 189.044, 3.09); + return; + end + elseif (sequence == SEQ_110) then + if (classId == TRIGGER_ACN_UPPER) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent2002"); + quest:NewNpcLsMsg(1); + quest:StartSequence(SEQ_120); + player:EndEvent(); + GetWorldManager():WarpToPublicArea(player); + return; + end + end + + player:EndEvent(); + quest:UpdateENPCs(); +end + +function onNpcLS(player, quest, from, msgStep) + local sequence = quest:getSequence(); + local msgPack; + + if (from == 1) then + -- Get the right msg pack + if (sequence == SEQ_050 or sequence == SEQ_060) then + msgPack = 1; + elseif (sequence == SEQ_080 or sequence == SEQ_090) then + msgPack = 2; + elseif (sequence == SEQ_120 or sequence == SEQ_122) then + msgPack = 3; + end + + -- Quick way to handle all msgs nicely. + player:SendGameMessageLocalizedDisplayName(quest, NPCLS_MSGS[msgPack][msgStep], MESSAGE_TYPE_NPC_LINKSHELL, 1000015); + if (msgStep >= #NPCLS_MSGS[msgPack]) then + quest:EndOfNpcLsMsgs(); + else + quest:ReadNpcLsMsg(); + end + + -- Handle anything else + if (sequence == SEQ_050) then + quest:StartSequenceForNpcLs(SEQ_060); + elseif (sequence == SEQ_080) then + quest:StartSequenceForNpcLs(SEQ_090); + elseif (sequence == SEQ_120) then + quest:StartSequenceForNpcLs(SEQ_122); + end + end + + player:EndEvent(); +end + +function getJournalMapMarkerList(player, quest) + local sequence = quest:getSequence(); + +end \ No newline at end of file diff --git a/Data/scripts/quests/man/man2l0.lua b/Data/scripts/quests/man/man2l0.lua index f7eee0e1..d8d0b50b 100644 --- a/Data/scripts/quests/man/man2l0.lua +++ b/Data/scripts/quests/man/man2l0.lua @@ -1,4 +1,52 @@ -require("global") +require("global"); + +--[[ + +Quest Script + +Name: Never the Twain Shall Meet +Code: Man2l0 +Id: 110004 +Prereq: Legends Adrift (Man1l0 - 110003) + +]] + +-- Sequence Numbers +SEQ_000 = 0; -- Talk to Captain Hob. +SEQ_010 = 10; -- Ship instance, enter the hold. +SEQ_015 = 15; -- Exit the hold, go back upstairs. +SEQ_020 = 20; -- Duty, fight Emerick and Merodaulyn +SEQ_035 = 35; -- Head to Baderon and chat. +SEQ_037 = 37; -- Head to outcrop in La Noscea. +SEQ_040 = 40; -- Talk to Baderon on the Link Pearl +SEQ_042 = 42; -- Enter and push at the MSK guild. +SEQ_045 = 45; -- Talk to Isaudorel +SEQ_050 = 50; -- Head to God's Grip push, talk with Blackburn. +SEQ_055 = 55; -- Continue to the other push with Y'shtola in the subecho. +SEQ_060 = 60; -- Unused? Talks about spying Stahlmann, Emerick, and Merod scheming. +SEQ_065 = 65; -- Unused? Talks about the meteor shower and the Ascian stealing the key. +SEQ_070 = 70; -- Unused? Talks about heading to Ul'dah + +-- Quest Actors +BADERON = 1000137; +YSHTOLA = 1000001; +HOB = 1000151; +ISAUDOREL = 1000152; +BARRACUDA_KNIGHT1 = 1000183; +BARRACUDA_KNIGHT2 = 1000184; +TRIGGER_SHIP1 = 1090003; +TRIGGER_SHIP2 = 1090003; +TRIGGER_MSK = 1090003; +TRIGGER_SEAFLD1 = 1090003; +TRIGGER_SEAFLD2 = 1090003; +TRIGGER_SEAFLD3 = 1090003; + +-- Quest Markers + +-- Msg packs for the Npc LS +NPCLS_MSGS = { + {40, 41} -- SEQ_040 +}; function onStart(player, quest) quest:StartSequence(SEQ_000); @@ -7,29 +55,169 @@ end function onFinish(player, quest) end -function onStateChange(player, quest, seqNum) +function onStateChange(player, quest, sequence) + local data = quest:GetData(); + + if (sequence == SEQ_ACCEPT) then + quest:SetENpc(BADERON, QFLAG_PLATE); + elseif (sequence == SEQ_000) then + quest:SetENpc(HOB, QFLAG_PLATE); + quest:SetENpc(BADERON); + elseif (sequence == SEQ_010) then + quest:SetENpc(HOB); + quest:SetENpc(BARRACUDA_KNIGHT1); + quest:SetENpc(BARRACUDA_KNIGHT2); + elseif (sequence == SEQ_015) then + quest:SetENpc(HOB); + quest:SetENpc(BARRACUDA_KNIGHT1); + quest:SetENpc(BARRACUDA_KNIGHT2); + elseif (sequence == SEQ_020) then + -- DUTY HAPPENS HERE + elseif (sequence == SEQ_035) then + quest:SetENpc(BADERON, QFLAG_PLATE); + elseif (sequence == SEQ_037) then + quest:SetENpc(BADERON); + elseif (sequence == SEQ_040) then + elseif (sequence == SEQ_042) then + quest:SetENpc(BADERON); + elseif (sequence == SEQ_045) then + quest:SetENpc(ISAUDOREL, QFLAG_PLATE); + elseif (sequence == SEQ_050) then + elseif (sequence == SEQ_055) then + quest:SetENpc(YSHTOLA); + end + end function onTalk(player, quest, npc) local sequence = quest:getSequence(); local classId = npc:GetActorClassId(); - - -end -function onEmote(player, quest, npc, emote) + if (sequence == SEQ_ACCEPT) then + if (classId == BADERON) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent000"); + end + elseif (sequence == SEQ_000) then + if (classId == HOB) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent010"); + quest:StartSequence(SEQ_010); + elseif (classId == BADERON) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent000_2"); + end + elseif (sequence == SEQ_010) then + if (classId == HOB) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent011_2"); + elseif (classId == BARRACUDA_KNIGHT1) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent011_3"); + elseif (classId == BARRACUDA_KNIGHT2) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent011_4"); + end + elseif (sequence == SEQ_015) then + if (classId == HOB) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent011_2"); + elseif (classId == BARRACUDA_KNIGHT1) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent011_3"); + elseif (classId == BARRACUDA_KNIGHT2) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent011_4"); + end + elseif (sequence == SEQ_035) then + if (classId == BADERON) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent050"); + quest:StartSequence(SEQ_037); + end + elseif (sequence == SEQ_037) then + if (classId == BADERON) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent050_2"); + end + elseif (sequence == SEQ_042) then + if (classId == BADERON) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent060_2"); + end + elseif (sequence == SEQ_045) then + if (classId == ISAUDOREL) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent075"); + quest:StartSequence(SEQ_050); + end + elseif (sequence == SEQ_055) then + if (classId == YSHTOLA) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent080_2"); + end + end + + player:EndEvent(); + quest:UpdateENPCs(); end function onPush(player, quest, npc) + local data = quest:GetData(); + local sequence = quest:getSequence(); + local classId = npc:GetActorClassId(); + + if (sequence == SEQ_037) then + if (classId == TRIGGER_SEAFLD1) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent060"); + quest:StartSequence(SEQ_040); + end + elseif (sequence == SEQ_042) then + if (classId == TRIGGER_MSK) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent070"); + quest:StartSequence(SEQ_045); + end + elseif (sequence == SEQ_050) then + if (classId == TRIGGER_SEAFLD2) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent080"); + quest:StartSequence(SEQ_055); + end + elseif (sequence == SEQ_055) then + if (classId == TRIGGER_SEAFLD3) then + callClientFunction(player, "delegateEvent", player, quest, "processEvent081"); + end + end + + player:EndEvent(); + quest:UpdateENPCs(); end -function onNotice(player, quest, npc) +function onNotice(player, quest, target) + callClientFunction(player, "delegateEvent", player, quest, "sqrwa", 300, 1, 1, 2); + player:CompleteQuest(quest); + callClientFunction(player, "delegateEvent", player, quest, "processEvent081_2", 1); + player:EndEvent(); + quest:UpdateENPCs(); +end + +function onNpcLS(player, quest, from, msgStep) + local sequence = quest:getSequence(); + local msgPack; + + if (from == 1) then + -- Get the right msg pack + if (sequence == SEQ_040 or sequence == SEQ_042) then + msgPack = 1; + end + + -- Quick way to handle all msgs nicely. + player:SendGameMessageLocalizedDisplayName(quest, NPCLS_MSGS[msgPack][msgStep], MESSAGE_TYPE_NPC_LINKSHELL, 1000015); + if (msgStep >= #NPCLS_MSGS[msgPack]) then + quest:EndOfNpcLsMsgs(); + else + quest:ReadNpcLsMsg(); + end + + -- Handle anything else + if (sequence == SEQ_040) then + quest:StartSequenceForNpcLs(SEQ_042); + end + end + + player:EndEvent(); end function getJournalInformation(player, quest) - return {}; + return 40, 40, 40; end function getJournalMapMarkerList(player, quest) - return 11000105, 11000106; + local sequence = quest:getSequence(); + end \ No newline at end of file diff --git a/Map Server/Actors/Actor.cs b/Map Server/Actors/Actor.cs index b2550bf0..8ddb41bf 100644 --- a/Map Server/Actors/Actor.cs +++ b/Map Server/Actors/Actor.cs @@ -642,7 +642,7 @@ namespace Meteor.Map.Actors return new Vector3(positionX, positionY, positionZ); } - public void SetPos(float x, float y, float z, float rot = 0, bool instant = false) + public void SetPos(float x, float y, float z, float rot = 0, bool instant = false, Player player = null) { oldPositionX = positionX; oldPositionY = positionY; @@ -657,8 +657,9 @@ namespace Meteor.Map.Actors // todo: handle zone? if (instant) { - CurrentArea.BroadcastPacketAroundPoint(oldPositionX, oldPositionY, CreateSpawnTeleportPacket(0)); - CurrentArea.BroadcastPacketAroundPoint(positionX, positionY, CreateSpawnTeleportPacket(0)); + player.QueuePacket(CreateSpawnTeleportPacket(0)); + //CurrentArea.BroadcastPacketAroundPoint(oldPositionX, oldPositionY, CreateSpawnTeleportPacket(0)); + //CurrentArea.BroadcastPacketAroundPoint(positionX, positionY, CreateSpawnTeleportPacket(0)); } else CurrentArea.BroadcastPacketAroundActor(this, MoveActorToPositionPacket.BuildPacket(Id, x, y, z, rot, moveState)); diff --git a/Map Server/Actors/Area/PrivateArea.cs b/Map Server/Actors/Area/PrivateArea.cs index 2155229f..ddf42ce2 100644 --- a/Map Server/Actors/Area/PrivateArea.cs +++ b/Map Server/Actors/Area/PrivateArea.cs @@ -33,9 +33,10 @@ namespace Meteor.Map.actors.area private readonly Zone ParentZone; private readonly string PrivateAreaName; private readonly int PrivateAreaType; + private readonly bool CanExitArea; - public PrivateArea(Zone parent, string classPath, string privateAreaName, int privateAreaType, ushort bgmDay, ushort bgmNight, ushort bgmBattle) - : base(parent.ZoneId, parent.ZoneName, parent.RegionId, classPath, bgmDay, bgmNight, bgmBattle, parent.isIsolated, parent.isInn, parent.canRideChocobo, parent.canStealth, true) + public PrivateArea(Zone parent, string classPath, string privateAreaName, int privateAreaType, bool canExitArea, ushort music) + : base(parent.ZoneId, parent.ZoneName, parent.RegionId, classPath, music, music, music, parent.isIsolated, parent.isInn, parent.canRideChocobo, parent.canStealth, true) { this.ParentZone = parent; this.PrivateAreaName = privateAreaName; @@ -52,6 +53,11 @@ namespace Meteor.Map.actors.area return PrivateAreaType; } + public bool CanExitPrivateArea() + { + return CanExitArea; + } + public override bool IsPublic() { return false; diff --git a/Map Server/Actors/Area/PrivateAreaContent.cs b/Map Server/Actors/Area/PrivateAreaContent.cs index 8639d6d1..38d930fc 100644 --- a/Map Server/Actors/Area/PrivateAreaContent.cs +++ b/Map Server/Actors/Area/PrivateAreaContent.cs @@ -38,7 +38,7 @@ namespace Meteor.Map.actors.area } public PrivateAreaContent(Zone parent, string classPath, string privateAreaName, int privateAreaType, Director director, Player contentStarter) //TODO: Make it a list - : base(parent, classPath, privateAreaName, privateAreaType, 0, 0, 0) + : base(parent, classPath, privateAreaName, privateAreaType, false, 0) { currentDirector = director; LuaEngine.GetInstance().CallLuaFunction(contentStarter, this, "onCreate", false, currentDirector); diff --git a/Map Server/Actors/Chara/Player/Player.cs b/Map Server/Actors/Chara/Player/Player.cs index 2f0b74ad..b0359bd4 100644 --- a/Map Server/Actors/Chara/Player/Player.cs +++ b/Map Server/Actors/Chara/Player/Player.cs @@ -1840,18 +1840,27 @@ namespace Meteor.Map.Actors public Quest[] GetQuestsForNpc(Npc npc) { - Quest[] quests = questStateManager.GetQuestsForNpc(npc); + Quest[] quests = questStateManager.GetQuestsForNpc(npc, CurrentArea.IsPrivate()); Array.Sort(quests, (q1, q2) => (q1.HasData() ? 1 : 0) - (q2.HasData() ? 1 : 0)); return quests; } + public void HandleBNpcKill(uint bnpcClassId) + { + foreach (Quest quest in questScenario) + { + if (quest != null) + quest.OnKillBNpc(this, bnpcClassId); + } + } + public bool HandleNpcLs(uint id) { foreach (Quest quest in questScenario) { if (quest != null && quest.HasNpcLsMsgs(id)) { - quest.OnNpcLS(this); + quest.OnNpcLs(this); return true; } } diff --git a/Map Server/Actors/Quest/Quest.cs b/Map Server/Actors/Quest/Quest.cs index a9a9884d..a69a0741 100644 --- a/Map Server/Actors/Quest/Quest.cs +++ b/Map Server/Actors/Quest/Quest.cs @@ -194,7 +194,12 @@ namespace Meteor.Map.Actors.QuestNS LuaEngine.GetInstance().CallLuaFunction(caller, this, "onNotice", true, triggerName); } - public void OnNpcLS(Player caller) + public void OnKillBNpc(Player caller, uint classId) + { + LuaEngine.GetInstance().CallLuaFunction(caller, this, "onKillBNpc", true, classId); + } + + public void OnNpcLs(Player caller) { LuaEngine.GetInstance().CallLuaFunction(caller, this, "onNpcLS", true, data.GetNpcLsFrom(), data.GetMsgStep()); } diff --git a/Map Server/Actors/Quest/QuestStateManager.cs b/Map Server/Actors/Quest/QuestStateManager.cs index 8dd2b8c3..1aa337da 100644 --- a/Map Server/Actors/Quest/QuestStateManager.cs +++ b/Map Server/Actors/Quest/QuestStateManager.cs @@ -151,9 +151,12 @@ namespace Meteor.Map.Actors.QuestNS return ActiveQuests.Find(quest => quest.GetQuestId() == id); } - public Quest[] GetQuestsForNpc(Npc npc) + public Quest[] GetQuestsForNpc(Npc npc, bool isPrivateArea) { - return ActiveQuests.FindAll(quest => quest.IsQuestENPC(player, npc)).ToArray(); + if (isPrivateArea) + return ActiveQuests.FindAll(quest => quest.IsQuestENPC(player, npc) && quest.GetSequence() != Quest.SEQ_NOT_STARTED).ToArray(); + else + return ActiveQuests.FindAll(quest => quest.IsQuestENPC(player, npc)).ToArray(); } public byte[] GetCompletionSliceBytes(ushort from, ushort to) diff --git a/Map Server/WorldManager.cs b/Map Server/WorldManager.cs index 70444f01..872fcd72 100644 --- a/Map Server/WorldManager.cs +++ b/Map Server/WorldManager.cs @@ -144,9 +144,8 @@ namespace Meteor.Map privateAreaName, privateAreaType, className, - dayMusic, - nightMusic, - battleMusic + canExitArea, + music FROM server_zones_privateareas WHERE privateAreaName IS NOT NULL"; @@ -161,7 +160,7 @@ namespace Meteor.Map if (zoneList.ContainsKey(parentZoneId)) { Zone parent = zoneList[parentZoneId]; - PrivateArea privArea = new PrivateArea(parent, reader.GetString("className"), reader.GetString("privateAreaName"), reader.GetInt32("privateAreaType"), reader.GetUInt16("dayMusic"), reader.GetUInt16("nightMusic"), reader.GetUInt16("battleMusic")); + PrivateArea privArea = new PrivateArea(parent, reader.GetString("className"), reader.GetString("privateAreaName"), reader.GetInt32("privateAreaType"), reader.GetBoolean("canExitArea"), reader.GetUInt16("music")); parent.AddPrivateArea(privArea); } else @@ -939,7 +938,7 @@ namespace Meteor.Map DoZoneChange(player, player.CurrentArea.ZoneId, null, 0, 15, x, y, z, rotation); } - public void WarpToPosition(Player player, float x, float y, float z, float rotation) + public void WarpToPosition(Player player, float x, float y, float z, float rotation, bool debugInstant = false) { //Remove player from currentZone if transfer else it's login if (player.CurrentArea != null) @@ -956,13 +955,18 @@ namespace Meteor.Map //Send packets player.playerSession.QueuePacket(_0xE2Packet.BuildPacket(player.Id, 0x10)); - player.playerSession.QueuePacket(player.CreateSpawnTeleportPacket(0)); + player.playerSession.QueuePacket(player.CreateSpawnTeleportPacket(debugInstant ? (ushort) 0x0 : (ushort) 0xF)); player.playerSession.LockUpdates(false); player.SendInstanceUpdate(); } } - + + public void WarpToCharaPosition(Player player, Character target) + { + WarpToPosition(player, target.positionX, target.positionY, target.positionZ, target.rotation); + } + //Moves actor to new zone, and sends packets to spawn at the given coords. public void DoZoneChangeContent(Player player, PrivateAreaContent contentArea, float spawnX, float spawnY, float spawnZ, float spawnRotation, ushort spawnType = SetActorPositionPacket.SPAWNTYPE_WARP_DUTY) {