diff --git a/FFXIVClassic Map Server/actors/chara/player/Inventory.cs b/FFXIVClassic Map Server/actors/chara/player/Inventory.cs index 6770643f..a8fa7458 100644 --- a/FFXIVClassic Map Server/actors/chara/player/Inventory.cs +++ b/FFXIVClassic Map Server/actors/chara/player/Inventory.cs @@ -94,7 +94,30 @@ namespace FFXIVClassic_Map_Server.actors.chara.player return null; } - public INV_ERROR AddItem(uint itemId) + + public int GetItemQuantity(uint itemId) + { + return GetItemQuantity(itemId, 1); + } + + public int GetItemQuantity(uint itemId, uint quality) + { + int count = 0; + + for (int i = endOfListIndex - 1; i >= 0; i--) + { + InventoryItem item = list[i]; + + if (item.itemId == itemId && item.quality == quality) + count += item.quantity; + + } + + return count; + } + + + public int AddItem(uint itemId) { return AddItem(itemId, 1, 1); } @@ -105,22 +128,22 @@ namespace FFXIVClassic_Map_Server.actors.chara.player AddItem(itemId[i]); } - public INV_ERROR AddItem(uint itemId, int quantity) + public int AddItem(uint itemId, int quantity) { return AddItem(itemId, quantity, 1); } - public INV_ERROR AddItem(uint itemId, int quantity, byte quality) + public int AddItem(uint itemId, int quantity, byte quality) { if (!IsSpaceForAdd(itemId, quantity, quality)) - return INV_ERROR.INVENTORY_FULL; + return (int)INV_ERROR.INVENTORY_FULL; ItemData gItem = Server.GetItemGamedata(itemId); if (gItem == null) { Program.Log.Error("Inventory.AddItem: unable to find item %u", itemId); - return INV_ERROR.SYSTEM_ERROR; + return (int)INV_ERROR.SYSTEM_ERROR; } //Check if item id exists @@ -146,8 +169,8 @@ namespace FFXIVClassic_Map_Server.actors.chara.player } //If it's unique, abort - if (quantityCount > 0 && gItem.isExclusive) - return INV_ERROR.ALREADY_HAS_UNIQUE; + if (HasItem(itemId) && gItem.isRare) + return (int)INV_ERROR.ALREADY_HAS_UNIQUE; //New item that spilled over while (quantityCount > 0) @@ -161,9 +184,9 @@ namespace FFXIVClassic_Map_Server.actors.chara.player DoDatabaseAdd(addedItem); } - SendUpdatePackets(); - - return INV_ERROR.SUCCESS; + SendUpdatePackets(); + + return (int)INV_ERROR.SUCCESS; } public void RemoveItem(uint itemId) diff --git a/data/scripts/base/chara/npc/populace/PopulaceBlackMarketeer.lua b/data/scripts/base/chara/npc/populace/PopulaceBlackMarketeer.lua index 9a3a30db..cc506739 100644 --- a/data/scripts/base/chara/npc/populace/PopulaceBlackMarketeer.lua +++ b/data/scripts/base/chara/npc/populace/PopulaceBlackMarketeer.lua @@ -25,6 +25,7 @@ Actorclass Id - 1500295 : Lalaroon, Ul'dah --]] require ("global") +require ("shop") shopInfo = { -- [ index ] = { itemId, gilPrice, sealPrice, city, itemCategory } [1001] = {3020202, 100, 10000, 1, 1}, @@ -121,7 +122,7 @@ function processGilShop(player) location = INVENTORY_NORMAL; end - purchaseItem(player, shopInfo[buyResult][1], 1, 1, shopInfo[buyResult][3], gilCurrency, location); + purchaseItem(player, location, shopInfo[buyResult][1], 1, 1, shopInfo[buyResult][3], gilCurrency); end end end @@ -150,44 +151,9 @@ function processSealShop(player) location = INVENTORY_NORMAL; end - purchaseItem(player, shopInfo[buyResult][1], 1, 1, shopInfo[buyResult][2], playerGCSeal, location); + purchaseItem(player, location, shopInfo[buyResult][1], 1, 1, shopInfo[buyResult][2], playerGCSeal); end end end end -function purchaseItem(player, itemId, quantity, quality, price, currency, location) - - local worldMaster = GetWorldMaster(); - local cost = quantity * price; - local gItemData = GetItemGamedata(itemId); - local isUnique = gItemData.isRare; - - if player:GetInventory(location):HasItem(itemId) and isUnique then - -- You cannot have more than one in your possession at any given time. - player:SendGameMessage(player, worldMaster, 40279, MESSAGE_TYPE_SYSTEM, itemId, quality); - return; - end - - if (not player:GetInventory(location):IsFull() or player:GetInventory(location):IsSpaceForAdd(itemId, quantity)) then - if player:GetInventory(INVENTORY_CURRENCY):HasItem(currency, cost) then - player:GetInventory(INVENTORY_CURRENCY):removeItem(currency, cost) - player:GetInventory(location):AddItem(itemId, quantity, quality); - if currency == 1000001 then - -- You purchase for gil. - player:SendGameMessage(player, worldMaster, 25061, MESSAGE_TYPE_SYSTEM, itemId, quality, quantity, cost); - elseif currency == 1000201 or currency == 1000202 or currency == 1000203 then - -- You exchange for . - player:SendGameMessage(player, GetWorldMaster(), 25275, MESSAGE_TYPE_SYSTEM, itemId, quality, quantity, price, player.gcCurrent); - - end - else - -- You do not have enough gil. (Should never see this aside from packet injection, since client prevents buying if not enough currency) - player:SendGameMessage(player, worldMaster, 25065, MESSAGE_TYPE_SYSTEM); - end - else - -- Your inventory is full. - player:SendGameMessage(player, worldMaster, 60022, MESSAGE_TYPE_SYSTEM); - end - return -end \ No newline at end of file diff --git a/data/scripts/base/chara/npc/populace/PopulaceCompanyBuffer.lua b/data/scripts/base/chara/npc/populace/PopulaceCompanyBuffer.lua new file mode 100644 index 00000000..63ed7364 --- /dev/null +++ b/data/scripts/base/chara/npc/populace/PopulaceCompanyBuffer.lua @@ -0,0 +1,43 @@ +--[[ + +PopulaceCompanyBuffer Script + +Functions: + +eventTalkWelcome(player, boolean) - Welcome dialog. Boolean seems to be related to rank? +eventTalkBufEffect() - Dialog for applying Sanction +eventTalkBufEffectAfter(player) - Dialog after applying Sanction +eventTalkStepBreak() - Returns to NPC's neutral state + +--]] + +require ("global") + +function init(npc) + return false, false, 0, 0; +end + +local gcRep = { + [1500388] = 1, -- Maelstrom Representative + [1500389] = 2, -- Adder Representative + [1500390] = 3, -- Flame Representative +} + +function onEventStarted(player, npc, triggerName) + local playerGC = player.gcCurrent; + local playerGCRanks = {player.gcRankLimsa, player.gcRankGridania, player.gcRankUldah}; + + local choice = callClientFunction(player, "eventTalkWelcome", player, true); + + if (choice == 1 and playerGCRanks[playerGC] > 10 and playerGCRanks[playerGC] < 112) then + callClientFunction(player, "eventTalkBufEffect"); + callClientFunction(player, "eventTalkBufEffectAfter", player); + -- TODO: Add Sanction buff + else + player:SendMessage(0x20, "", "Quit hex editing your memory."); + end + + callClientFunction(player, "eventTalkStepBreak"); + player:endEvent(); +end + diff --git a/data/scripts/base/chara/npc/populace/PopulaceCompanyGLPublisher.lua b/data/scripts/base/chara/npc/populace/PopulaceCompanyGLPublisher.lua new file mode 100644 index 00000000..68bb71be --- /dev/null +++ b/data/scripts/base/chara/npc/populace/PopulaceCompanyGLPublisher.lua @@ -0,0 +1,66 @@ +--[[ + +PopulaceCompanyGLPublisher Script + +xtx_gcRank for GC Rank values + +Functions: + +talkOutsider() - Dialog for no affiliated with GC. Seems to always read Maelstrom? +talkOfferWelcome(unk1) - Errors +askCompanyLeve() - Errors +askLeveDetail(unk1, unk2, unk3, unk4, unk5, unk6, unk7, unk8) - Errors + +eventGLDifficulty() - Difficulty window, returns player choice +eventGLStart(leveName, difficulty, unk1) - leveName from xtx_guildleve + +talkAfterOffer() +talkOfferLimit() + +finishTalkTurn() - Resets NPC target/facing + +eventGLPlay(leveName, guardianFavor, favorCost, difficulty) - Menu for active levequest +eventGLShinpu(guardianFavor, favorCost) - Menu to accept favor buff. evenGLPlay() calls it +eventGLThanks() - Errors + +eventGLReward( -- Leve reward screen + guildleveId, + clearTime, + missionBonus, + difficultyBonus, + factionNumber, + factionBonus, + factionCredit, + glRewardItem, + glRewardNumber, + glRewardSubItem, + glRewardSubNumber, + difficulty +) + + +--]] + +require ("global") + +function init(npc) + return false, false, 0, 0; +end + +gcOfficer = { +[1500222] = 1, -- Storm Sergeant Hammil +[1500223] = 1, -- Storm Sergeant Sternn +[1500224] = 2, -- Serpent Sergeant Cordwyk +[1500225] = 2, -- Serpent Sergeant Lodall +[1500226] = 3, -- Flame Sergeant Byrne +[1500227] = 3, -- Flame Sergeant Dalvag +} + +function onEventStarted(player, npc, triggerName) + + callClientFunction(player, "talkOutsider"); + + callClientFunction(player, "finishTalkTurn"); + player:endEvent(); +end + diff --git a/data/scripts/base/chara/npc/populace/PopulaceCompanyGuide.lua b/data/scripts/base/chara/npc/populace/PopulaceCompanyGuide.lua new file mode 100644 index 00000000..044f5fc1 --- /dev/null +++ b/data/scripts/base/chara/npc/populace/PopulaceCompanyGuide.lua @@ -0,0 +1,45 @@ +--[[ + +PopulaceCompanyGuide Script + +Functions: + +eventTalkWelcome() - Dialog for new recruits +eventTalkProvisional() - Message for when rank isn't high enough? +eventTalkExclusive() - Message for wrong GC. +eventTalkComMember(nil, npc, isFoundationDay) - Information menus for various GC related activities +eventTalkStepBreak() - Returns to NPC's neutral state + +--]] + +require ("global") + +function init(npc) + return false, false, 0, 0; +end + +local gcRep = { + [1001737] = 1, -- Maelstrom Representative + [1001738] = 2, -- Adder Representative + [1001739] = 3, -- Flame Representative +} + +function onEventStarted(player, npc, triggerName) + local playerGC = player.gcCurrent; + local playerGCRanks = {player.gcRankLimsa, player.gcRankGridania, player.gcRankUldah}; + local npcGC = gcRep[npc:GetActorClassId()]; + + if (playerGC ~= npcGC and playerGCRanks[playerGC] == 127) then + callClientFunction(player, "eventTalkWelcome"); + elseif (playerGC == npcGC and playerGCRanks[playerGC] == 127) then + callClientFunction(player, "eventTalkProvisional"); + elseif (playerGC ~= npcGC and playerGCRanks[playerGC] ~= 127) then + callClientFunction(player, "eventTalkExclusive"); + elseif (playerGC == npcGC and playerGCRanks[playerGC] > 10 and playerGCRanks[playerGC] < 112) then + callClientFunction(player, "eventTalkComMember", nil, npc, true); + end + + callClientFunction(player, "eventTalkStepBreak"); + player:endEvent(); +end + diff --git a/data/scripts/base/chara/npc/populace/PopulaceCompanyShop.lua b/data/scripts/base/chara/npc/populace/PopulaceCompanyShop.lua index d82765c4..7f6dd5a2 100644 --- a/data/scripts/base/chara/npc/populace/PopulaceCompanyShop.lua +++ b/data/scripts/base/chara/npc/populace/PopulaceCompanyShop.lua @@ -33,6 +33,7 @@ eventTalkStepBreak() -- Returns NPC to their starting direction --]] require ("global") +require ("shop") function init(npc) return false, false, 0, 0; @@ -44,7 +45,7 @@ gcOfficer = { [1500201] = 3, -- Flame Shop } -shopInfo = { -- [index] = { itemID, itemQuality, itemQuantity, itemCost gcRank, city, special, itemCategory } +shopInfo = { -- [index] = { itemID, itemQuality, itemQuantity, itemCost, gcRank, city, special, itemCategory } [100001] = {3010403, 1, 10, 20, 0, 1, 0, 1}, [100002] = {3010402, 1, 10, 30, 0, 1, 0, 1}, [100003] = {3020202, 1, 1, 50, 0, 1, 0, 1}, @@ -450,7 +451,7 @@ shopInfo = { -- [index] = { itemID, itemQuality, itemQuantity, itemCost gcRank, } function onEventStarted(player, npc, triggerName) - skipGCcheck = 1; -- 0 No, 1 Yes + skipGCcheck = 0; -- 0 No, 1 Yes playerGC = player.gcCurrent; playerGCSeal = 1000200 + playerGC; playerCurrentRank = 13; @@ -470,7 +471,7 @@ function onEventStarted(player, npc, triggerName) --player:SendMessage(0x20, "", "eventShopMenuOpen: " .. tostring(t1) .. ", ".. tostring(t2) .. ", ".. tostring(t3)); while (true) do - -- TODO: ADD RANK CHECK, CITY CHECK, AND RANGE CHECK + -- TODO: ADD RANK CHECK, CITY CHECK, AND ITEM-RANGE CHECK buyResult, buyIndex = callClientFunction(player, "eventShopMenuAsk"); @@ -486,7 +487,7 @@ function onEventStarted(player, npc, triggerName) end end - purchaseItem(player, shopInfo[buyIndex][1], shopInfo[buyIndex][3], shopInfo[buyIndex][2], shopInfo[buyIndex][4], playerGCSeal, location); + purchaseItem(player, location, shopInfo[buyIndex][1], shopInfo[buyIndex][3], shopInfo[buyIndex][2], shopInfo[buyIndex][4], playerGCSeal); end --player:SendMessage(0x20, "", "Player picked an item at gcSealShopIndex " .. tostring(buyResult) .. ", ".. tostring(buyIndex)); @@ -503,43 +504,6 @@ function onEventStarted(player, npc, triggerName) end -function purchaseItem(player, itemId, quantity, quality, price, currency, location) - - local worldMaster = GetWorldMaster(); - local cost = quantity * price; - local gItemData = GetItemGamedata(itemId); - local isUnique = gItemData.isRare; - - if player:GetInventory(location):HasItem(itemId) and isUnique then - -- You cannot have more than one in your possession at any given time. - player:SendGameMessage(player, worldMaster, 40279, MESSAGE_TYPE_SYSTEM, itemId, quality); - return; - end - - if (not player:GetInventory(location):IsFull() or player:GetInventory(location):IsSpaceForAdd(itemId, quantity)) then - if player:GetInventory(INVENTORY_CURRENCY):HasItem(currency, cost) then - player:GetInventory(INVENTORY_CURRENCY):removeItem(currency, cost) - player:GetInventory(location):AddItem(itemId, quantity, quality); - if currency == 1000001 then - -- You purchase for gil. - player:SendGameMessage(player, worldMaster, 25061, MESSAGE_TYPE_SYSTEM, itemId, quality, quantity, cost); - elseif currency == 1000201 or currency == 1000202 or currency == 1000203 then - -- You exchange for . - player:SendGameMessage(player, GetWorldMaster(), 25275, MESSAGE_TYPE_SYSTEM, itemId, quality, quantity, price, player.gcCurrent); - - end - else - -- You do not have enough gil. (Should never see this aside from packet injection, since client prevents buying if not enough currency) - player:SendGameMessage(player, worldMaster, 25065, MESSAGE_TYPE_SYSTEM); - end - else - -- Your inventory is full. - player:SendGameMessage(player, worldMaster, 60022, MESSAGE_TYPE_SYSTEM); - end - return -end - - diff --git a/data/scripts/base/chara/npc/populace/PopulaceCompanySupply.lua b/data/scripts/base/chara/npc/populace/PopulaceCompanySupply.lua new file mode 100644 index 00000000..92076990 --- /dev/null +++ b/data/scripts/base/chara/npc/populace/PopulaceCompanySupply.lua @@ -0,0 +1,464 @@ +--[[ + +PopulaceCompanySupply Script + +This class handles the menus for player's delivering specific items in exchange for grand company seals. +The supply/provision schedule runs on a weekly rotation, which resets Monday at 12AM JST, with eight rotations total to cycle through. +Each desired item has a server-wide max that it can be turned in, and when that is fulfilled, it moves to the next item in that week's list to work on. + +NPCs involved in the script use the Noc001 script for dialog and menu interactions. + + +Functions: + +eventTalkPreJoin() - Dialog when you're not affiliated +eventTalkExclusive() - Dialog when you're part of a GC but not the one of the actor? +eventTalkJoined() - Salutes then softlocks the client due to removed dialog strings. Obsolete function. + +eventQuestItemMenuOpen(itemId, itemPrice, itemPriceHq, supplyType) - supplyType: 1 = Supply, 2 = Provisioning, 3 = Totorak, 4 = Dzmael, 5 = Primal, 6 = NM drops +eventQuestItemMenuSelect(quantity, quality, unk) - Brings up the shop-style menu for viewing item detail and confirming item delivery. Args appear to do nothing on client? +eventQuestItemMenuClose() - Closes menu + +eventQuestSupplyItemActor(unk1) -- Client calls this automatically for setting up Expeditionary window in some manner +eventQuestSupplyItemID(unk1, unk2) -- eventQuestSupplyItemActor() calls this to sets item ranges based on category + +getEventQuestSupplyMode() - Returns current supply mode set by eventQuestItemMenuOpen() +eventTalkStepBreak() - Resets actor engage state + + +Noc001 Functions: + +pENPCAskSupplyWelcome(npcGC) -- Welcome dialog +pENPCAskSupply(npcGC) -- Brings up the delivery selection menu +eventQuestAskExWelcome(npcGC) -- Dialog when you pick Expeditionary +eventQuestAskExArea(npcGC) -- Brings up the Expeditionary selection menu +pENPCAskNowTalk(npcGC) -- Dialog for picking Delivery Status from pENPCAskSupply() + +nowSup(itemId1, current1, max1, itemId2, current2, max2, itemId3, current3, max3) -- Says current 3 items and current amount delivered vs. max it'll take +nowSupAddItem(itemId, current, max) -- Lists bonus item +pItem(itemId1, unk1, itemId2, unk2, itemId3, unk3, itemId4, unk4) -- Lists which item(s) you want to delivery. Fourth item is the bonus, set 0 for hidden. + +showSupplyLimit(minutes, seconds, current, required) -- Shows time remaining to finish delivery, shows current/required amount +eventShowPrizeMessage(npcGC) -- Reward dialog for handing something in? + +pELimitErr() -- Error msg for GC no longer accepting items. +pETradeErr() -- Transaction error. Inventory error? +pETradeErrLimit(minutes, seconds, current, required) -- Transaction error. Shows time remaining and current/required amount +pESuppylMaxErrKeyWait(isShowLimit, minutes, seconds, current, required) -- Error msg for delivery quota already filled. Optional timer/amount display +pESuppylSealMaxErr() -- Error msg for capped on GC seals, transaction incomplete + +eventQuestCantEx(npcGC) -- Dialog explaining you need to be Private Second Class to do Expeditionary missions +--]] + +require ("global") +require ("shop") + +function init(npc) + return false, false, 0, 0; +end + +local gcRep = { + [1500210] = 1, -- Maelstrom Representative + [1500211] = 2, -- Adder Representative + [1500212] = 3, -- Flame Representative +} + +local gcItems = { -- Debug purposes. Static item list with seal value and max turn-in. + [111] = {id = 10002015, seals = 8, cap = 1900}, + [112] = {id = 8031419, seals = 68, cap = 300}, + [113] = {id = 3010011, seals = 3, cap = 5000}, + [114] = {id = 8011108, seals = 89, cap = 400}, + + [115] = {id = 10004001, seals = 5, cap = 3000}, + [116] = {id = 10008109, seals = 3, cap = 5000}, + [117] = {id = 12000180, seals = 5, cap = 3000}, + [118] = {id = 10004026, seals = 9, cap = 3400}, + + [121] = {id = 10008211, seals = 5, cap = 3000}, + [122] = {id = 3020407, seals = 5, cap = 2500}, + [123] = {id = 8030220, seals = 92, cap = 200}, + [124] = {id = 8030922, seals = 99, cap = 400}, + + [125] = {id = 10001014, seals = 3, cap = 5000}, + [126] = {id = 10008007, seals = 5, cap = 3000}, + [127] = {id = 3011217, seals = 3, cap = 5000}, + [128] = {id = 3011207, seals = 3, cap = 6000}, + + [131] = {id = 4030204, seals = 69, cap = 300}, + [132] = {id = 10004103, seals = 9, cap = 1700}, + [133] = {id = 10009208, seals = 6, cap = 3000}, + [134] = {id = 1, seals = 1, cap = 1}, -- Unknown + + [135] = {id = 10004008, seals = 9, cap = 1700}, + [136] = {id = 10008007, seals = 5, cap = 3000}, + [137] = {id = 3011201, seals = 5, cap = 3000}, + [138] = {id = 10009401, seals = 6, cap = 6000}, + + [211] = {id = 10002012, seals = 5, cap = 3000}, + [212] = {id = 4100007, seals = 51, cap = 300}, + [213] = {id = 3010108, seals = 2, cap = 3000}, + [214] = {id = 8080825, seals = 42, cap = 800}, + + [215] = {id = 10004003, seals = 5, cap = 3000}, + [216] = {id = 10002012, seals = 3, cap = 5000}, + [217] = {id = 3011104, seals = 2, cap = 3000}, + [218] = {id = 3011107, seals = 3, cap = 6000}, + +} + + +local gcWeek = { -- Debug purposes. Static weekly item lists. [week] = { [city] = {[category] = { info } } } + [1] = { + [1] = { -- Limsa + [1] = { -- Supply + gcItems[111], + gcItems[112], + gcItems[113], + gcItems[114], + }, + [2] = { -- Provision + gcItems[115], + gcItems[116], + gcItems[117], + gcItems[118], + } + }, + [2] = { -- Gridania + [1] = { -- Supply + gcItems[121], + gcItems[122], + gcItems[123], + gcItems[124], + }, + [2] = { -- Provision + gcItems[125], + gcItems[126], + gcItems[127], + gcItems[128], + } + }, + [3] = { -- Ul'dah + [1] = { -- Supply + gcItems[131], + gcItems[132], + gcItems[133], + gcItems[134], + }, + [2] = { -- Provision + gcItems[135], + gcItems[136], + gcItems[137], + gcItems[138], + } + } + }, + + [2] = { + [1] = { -- Limsa + [1] = { -- Supply + gcItems[211], + gcItems[212], + gcItems[213], + gcItems[214], + }, + [2] = { -- Provision + gcItems[215], + gcItems[216], + gcItems[217], + gcItems[218], + } + } + } + +} + +local gcDelivery = { -- Debug purposes. Holds values for current turned in amount and 4th item bonus status. + week = 1, + currentCount = { + { + {49, 81, 5000, 5}, {2402, 4779, 589, 2} -- Limsa Supply/Provision + }, + { + {1, 2, 3, 4}, {5, 6, 7, 8} -- Gridania Supply/Provision + }, + { + {10, 32, 9, 18}, {23, 49, 9, 300} -- Ul'dah Supply/Provision + } + }, + bonus = { {1, 1}, {0,1}, {0,1} }; -- City -> {Supply, Provision} + timeRemainingMinutes = 99, + timeRemainingSeconds = 59, +} + +local supplyQuest = GetStaticActor("Noc001"); +local skipGCcheck = false; -- Debug +local skipRankCheck = false; -- Debug +local gcCheckProceed = false; -- Debug + + + + +function onEventStarted(player, npc, triggerName) + local playerGC = player.gcCurrent; + local limsaRank = player.gcRankLimsa; + local gridaniaRank = player.gcRankGridania; + local uldahRank = player.gcRankUldah; + local playerGCSeal = 1000200 + playerGC; + + local npcId = npc:GetActorClassId(); + local npcGC = gcRep[npcId]; + + if (skipGCcheck == true) then + gcCheckProceed = true; + end + + if ((playerGC ~= npcGC) and skipGCcheck == false) then + if (playerGC == 0) then + callClientFunction(player, "eventTalkPreJoin"); + else + callClientFunction(player, "eventTalkExclusive"); + end + else + gcCheckProceed = true; + end + + if gcCheckProceed then + callClientFunction(player, "delegateEvent", player, supplyQuest, "pENPCAskSupplyWelcome", gcRep[npcId]); + while (true) do + + local choice = callClientFunction(player, "delegateEvent", player, supplyQuest, "pENPCAskSupply", gcRep[npcId]); + + if (choice == 2) then -- Supply + deliveryMenuInfo(player, npcGC, 1); + + elseif (choice == 3) then -- Provision + deliveryMenuInfo(player, npcGC, 2); + + elseif (choice == 4) then -- Expeditionary + local proceed = false; + + if (skipRankCheck == true) then + proceed = true; + else + if (playerGC == 1 and limsaRank >= 13 and limsaRank <= 111) + or (playerGC == 2 and gridaniaRank >= 13 and gridaniaRank <= 111) + or (playerGC == 3 and uldahRank >= 13 and uldahRank <= 111) then + proceed = true + end + end + + if proceed == true then + callClientFunction(player, "delegateEvent", player, supplyQuest, "eventQuestAskExWelcome", gcRep[npcId]); + while (true) do + local exChoice = callClientFunction(player, "delegateEvent", player, supplyQuest, "eventQuestAskExArea", gcRep[npcId]); + + if (exChoice >= 3) then + deliveryMenuOpen(player, npc, 0,0,0, exChoice); + else + break; + end + end + else + callClientFunction(player, "delegateEvent", player, supplyQuest, "eventQuestCantEx",gcRep[npcId]); + end + + elseif (choice == 5) then -- Requested item + deliveryStatus(player, npcGC); + else + break; + end + + wait(1); + end + end + + callClientFunction(player, "eventTalkStepBreak"); + player:endEvent() + +end + + +function deliveryMenuInfo(player, city, category) + + local gcContents = getWeeklyItems(city, category); + local gcCurrent = getCurrentCount(city, category); + local supplyChoice = 0; + + while (true) do + + if gcDelivery.bonus[city][category] == 1 then -- Show fourth item if condition is met, otherwise show three. + + supplyChoice = callClientFunction + ( + player, + "delegateEvent", + player, + supplyQuest, + "pItem", + gcContents[1].id, + 1, + gcContents[2].id, + 1, + gcContents[3].id, + 1, + gcContents[4].id, + 1 + ); + else + supplyChoice = callClientFunction + ( + player, + "delegateEvent", + player, + supplyQuest, + "pItem", + gcContents[1].id, + 1, + gcContents[2].id, + 1, + gcContents[3].id, + 1, + 0, + 0 + ); + end + + if supplyChoice >= 2 then + + if gcCurrent[supplyChoice-1] < gcContents[supplyChoice-1].cap then + local hqPrice = math.ceil(gcContents[supplyChoice-1].seals * 1.5); + + deliveryMenuOpen + ( + player, + npc, + gcContents[supplyChoice-1].id, + gcContents[supplyChoice-1].seals, + hqPrice, + category + ); + + else + callClientFunction(player, "delegateEvent", player, supplyQuest, "pESuppylMaxErrKeyWait"); + end + elseif supplyChoice == 1 then + break; + end + wait(1); + end +end + + +function deliveryMenuOpen(player, npc, itemId, price, hqPrice, supplyType) + + callClientFunction(player, "eventQuestItemMenuOpen", itemId, price, hqPrice, supplyType); + + while (true) do + + local choice, quantity, quality, itemSlot, Type7Param = callClientFunction(player, "eventQuestItemMenuSelect"); + + if choice == false then + callClientFunction(player, "eventQuestItemMenuClose"); + break; + end + + --[[ + player:SendMessage(0x20, "", "Choice: " .. tostring(choice)); + player:SendMessage(0x20, "", "Quantity: " .. tostring(quantity)); + player:SendMessage(0x20, "", "Quality: " .. tostring(quality)); + player:SendMessage(0x20, "", "Slot: " .. tostring(itemSlot)); -- Broke at some point, always return 0, investigate sometime + player:SendMessage(0x20, "", "Type7Param: " .. tostring(Type7Param.slot)); + --]] + + pickedItem = GetItemGamedata(player:GetInventory(INVENTORY_NORMAL):GetItemAtSlot(Type7Param.slot).itemId).name; + player:SendMessage(0x20, "", "Player tried to deliver " .. quantity .. " " .. pickedItem); + + -- TODO: Add error handling for capped seals, no-long-available-to-deliver, etc + wait(1); + end +end + + + +function deliveryStatus(player, city) + local gcContents = getWeeklyItems(city, 1); + local gcCurrent = getCurrentCount(city, 1); + + callClientFunction(player, "delegateEvent", player, supplyQuest, "pENPCAskNowTalk", gcRep[npcId]); + callClientFunction + ( + player, + "delegateEvent", + player, + supplyQuest, + "nowSup", + gcContents[1].id, + gcCurrent[1], + gcContents[1].cap, + gcContents[2].id, + gcCurrent[2], + gcContents[2].cap, + gcContents[3].id, + gcCurrent[3], + gcContents[3].cap + ); + if gcDelivery.bonus[city][1] == 1 then + callClientFunction + ( + player, + "delegateEvent", + player, + supplyQuest, + "nowSupAddItem", + gcContents[4].id, + gcCurrent[4], + gcContents[4].cap + ); + end; + + gcContents = getWeeklyItems(city, 2); + gcCurrent = getCurrentCount(city, 2); + + callClientFunction + ( + player, + "delegateEvent", + player, + supplyQuest, + "nowSup", + gcContents[1].id, + gcCurrent[1], + gcContents[1].cap, + gcContents[2].id, + gcCurrent[2], + gcContents[2].cap, + gcContents[3].id, + gcCurrent[3], + gcContents[3].cap + ); + if gcDelivery.bonus[city][2] == 1 then + callClientFunction + ( + player, + "delegateEvent", + player, + supplyQuest, + "nowSupAddItem", + gcContents[4].id, + gcCurrent[4], + gcContents[4].cap + ); + end; + + callClientFunction(player, "delegateEvent", player, supplyQuest, "showSupplyLimit", gcDelivery.timeRemainingMinutes, gcDelivery.timeRemainingSeconds, 2, 8); +end + + +function getWeeklyItems(city, category) + return gcWeek[gcDelivery.week][city][category] +end + +function getCurrentCount(city, category) + return gcDelivery.currentCount[city][category]; +end + diff --git a/data/scripts/base/chara/npc/populace/shop/PopulaceGuildShop.lua b/data/scripts/base/chara/npc/populace/shop/PopulaceGuildShop.lua index 72348129..ed6466b6 100644 --- a/data/scripts/base/chara/npc/populace/shop/PopulaceGuildShop.lua +++ b/data/scripts/base/chara/npc/populace/shop/PopulaceGuildShop.lua @@ -1,63 +1,108 @@ +--[[ + +PopulaceGuildShop Script + +In 1.20, the devs removed Guild Marks as acquirable. In 1.21, this class was set up to allow exchanging them for +a variety of materia/crystals/gil, as well as refunding traits purchased with marks. Traits used to be purchased +to slot in, where-as with late-XIV they are just automatically unlocked once the appropriate level is met. + +Functions: + +cashbackTalkCommand(arg1 through arg10) -- Dialog for refunding purchased skills prior to Job update. Args are xtx_command values for command names. +cashbackTalk(nil, refundAmount, arg3 through arg10) -- Dialog for refunding treaties to guild marks. Arg3 through 10 use xtx_itemName values. +selectMode(nil, npcId, isShowExchange, guildCurrency, unk) -- Menus for exchanging leftover marks, undoing class points, and learning about guild. Unk seems related to point resetting + +maskShopListIndex(shopPack?, isSomething) -- Presumably hides an item in the shop list. Needs to be called after openShopBuy or errors client. +guildExplain(npcId, player) -- Guild Mark tutorial dialog. selectMode calls this on its own + +--]] + + require ("global") +require ("shop") function init(npc) - return false, false, 0, 0; + return false, false, 0, 0; end +guildShopInfo = { -- [actor id] = { saySheetId, guildmarkCurrency } +[1000157] = {9, 1000103}, -- Marauder, S'raemha +[1000158] = {24, 1000120}, -- Culinarian, Noline +[1000162] = {18, 1000114}, -- Blacksmith, Qhas Chalahko +[1000164] = {16, 1000123}, -- Fishermen, Faucillien +[1000459] = {21, 1000117}, -- Leatherworker, Gallia +[1000460] = {13, 1000111}, -- Conjurer, Hetzkin +[1000461] = {15, 1000122}, -- Botanist, Kipopo +[1000462] = {11, 1000107}, -- Lancer, Clarembald +[1000464] = {10, 1000106}, -- Archer, Cassandra +[1000466] = {17, 1000113}, -- Carpenter, Frances +[1000631] = {8, 1000102}, -- Gladiator, Coynach +[1000632] = {7, 1000101}, -- Pugilist, Moruith +[1000633] = {12, 1000110}, -- Thaumaturge, Nyunoeya +[1000634] = {23, 1000119}, -- Alchemist, Kylene +[1000635] = {20, 1000116}, -- Goldsmith, Hnaufrid +[1000636] = {22, 1000118}, -- Weaver, Lafla Morfla +[1000637] = {14, 1000121}, -- Miner, Shilgen +[1001461] = {19, 1000115}, -- Armorer, Notrelchamps +} + + + function onEventStarted(player, npc) - saySheetId = 1; + local npcId = npc:GetActorClassId(); + local saySheetId = guildShopInfo[npcId][1]; + local shopCurrency = guildShopInfo[npcId][2]; + local gilCurrency = 1000001; + local keepersHymn = 3020410; + local shopPack = 0; + + callClientFunction(player, "welcomeTalk", nil, saySheetId, player); - if (npc:GetActorClassId() == 1000157) then - saySheetId = 9; - elseif (npc:GetActorClassId() == 1000158) then - saySheetId = 24; - elseif (npc:GetActorClassId() == 1000162) then - saySheetId = 18; - elseif (npc:GetActorClassId() == 1000164) then - saySheetId = 16; - elseif (npc:GetActorClassId() == 1000459) then - saySheetId = 21; - elseif (npc:GetActorClassId() == 1000460) then - saySheetId = 13; - elseif (npc:GetActorClassId() == 1000461) then - saySheetId = 15; - elseif (npc:GetActorClassId() == 1000462) then - saySheetId = 11; - elseif (npc:GetActorClassId() == 1000464) then - saySheetId = 10; - elseif (npc:GetActorClassId() == 1000466) then - saySheetId = 17; - elseif (npc:GetActorClassId() == 1000631) then - saySheetId = 8; - elseif (npc:GetActorClassId() == 1000632) then - saySheetId = 7; - elseif (npc:GetActorClassId() == 1000633) then - saySheetId = 12; - elseif (npc:GetActorClassId() == 1000634) then - saySheetId = 23; - elseif (npc:GetActorClassId() == 1000635) then - saySheetId = 20; - elseif (npc:GetActorClassId() == 1000636) then - saySheetId = 22; - elseif (npc:GetActorClassId() == 1000637) then - saySheetId = 14; - elseif (npc:GetActorClassId() == 1001461) then - saySheetId = 19; - end + while (true) do + local choice = callClientFunction(player, "selectMode", nil, npcId, true, shopCurrency, 100); - callClientFunction(player, "welcomeTalk", nil, saySheetId, player); - - while (true) do - choice = callClientFunction(player, "selectMode", nil, npc:GetActorClassId(), false, 1000001); --Step 2, state your business - - if (choice == 3) then - - elseif (choice == 4) then - player:EndEvent(); - break; - end - - end - -end \ No newline at end of file + if (choice == 3) then -- Undo Point Allotment + -- TODO: Add point reset handling + elseif (choice == 4) then -- Leave menu selected + player:EndEvent(); + break; + elseif (choice == nil) then -- Escape key hit to leave menu + player:EndEvent(); + break + elseif (choice >= 102 and choice <= 120) then -- Exchange marks for Materia + shopPack = choice + 18; -- Index offset + if (choice == 119) then + shopPack = shopPack + 1; + elseif (choice == 120) then -- Exchange marks for Crystals + shopPack = 144; + end; + processGuildShop(player, shopPack, shopCurrency); + elseif (choice == 121) then -- Exchange marks for Gil. 1 mark = 4 gil + local markAmount = player:GetInventory(INVENTORY_CURRENCY):GetItemQuantity(shopCurrency); + purchaseItem(player, INVENTORY_CURRENCY, gilCurrency, markAmount*4, 1, markAmount, shopCurrency); + + end + end + + player:EndEvent() +end + + + +function processGuildShop(player, choice, currency) + + callClientFunction(player, "openShopBuy", player, choice, currency); + --callClientFunction(player, "maskShopListIndex", 137, true); + + while (true) do + buyResult, quantity = callClientFunction(player, "selectShopBuy", player); + + if (buyResult == 0) then + callClientFunction(player, "closeShopBuy", player); + break; + else + player:SendMessage(0x20, "", string.format("Player purchased %s item(s) at index %s in shopPack %s.", quantity, buyResult, choice)); + end + end +end diff --git a/data/scripts/base/chara/npc/populace/shop/PopulaceShopSalesman.lua b/data/scripts/base/chara/npc/populace/shop/PopulaceShopSalesman.lua index 20e2f789..26039572 100644 --- a/data/scripts/base/chara/npc/populace/shop/PopulaceShopSalesman.lua +++ b/data/scripts/base/chara/npc/populace/shop/PopulaceShopSalesman.lua @@ -18,6 +18,8 @@ openShopSell(player) - Call this to open sell window selectShopSell(player) - Call after openShopSell() closeShopSell(player) - Closes the sell window +confirmSellingItem(itemId, quality, quantity, gil) - Simple Sell confirmation window + selectFacility(?, sheetId, 3) - Opens the facility chooser. confirmUseFacility(player, cost) - Facility cost confirm @@ -30,139 +32,259 @@ finishTalkTurn() - Done at the end. --]] require ("global") +require ("shop") + +shopInfo = { -- [actorclass id] = { welcomeText, shopMode, shopPack{s} } +[1000159] = {34, 0, 1016}, +[1000163] = {49, 0, 1017}, +[1000165] = {74, 0, 1019}, +[1001458] = {44, 0, 1018}, +[1500405] = {320, 0, 1013}, +[1500407] = {321, 0, 1012}, +[1500411] = {322, 0, 2017}, +[1500414] = {324, 0, 1012}, +[1500419] = {327, 0, 1012}, +[1500422] = {332, 0, 1013}, +[1500423] = {331, 0, 2017}, +[1500429] = {328, 0, 2017}, +[1500430] = {281, 0, 5121}, +[1600001] = {6, 0, 1006}, +[1600002] = {7, 0, 1007}, +[1600003] = {8, 0, 1008}, +[1600004] = {9, 0, 1009}, +[1600005] = {10, 0, 1010}, +[1600006] = {11, 0, 1011}, +[1600007] = {12, 0, 1012}, +[1600008] = {13, 0, 1013}, +[1600009] = {14, 0, 1014}, +[1600010] = {15, 0, 1015}, +[1600011] = {1, 0, 1001}, +[1600012] = {2, 0, 1002}, +[1600013] = {3, 0, 1003}, +[1600014] = {4, 0, 1004}, +[1600016] = {5, 0, 1005}, +[1600017] = {39, 0, 2020}, +[1600018] = {59, 0, 2021}, +[1600019] = {75, 0, 2022}, +[1600020] = {77, 0, 2010}, +[1600021] = {78, 0, 2011}, +[1600022] = {79, 0, 2012}, +[1600023] = {80, 0, 2013}, +[1600024] = {81, 0, 2014}, +[1600025] = {82, 0, 2015}, +[1600026] = {83, 0, 2016}, +[1600027] = {84, 0, 2017}, +[1600028] = {85, 0, 2018}, +[1600029] = {86, 0, 2019}, +[1600030] = {87, 0, 2001}, +[1600031] = {88, 0, 2003}, +[1600032] = {89, 0, 2002}, +[1600033] = {90, 0, 2004}, +[1600034] = {91, 0, 2005}, +[1600035] = {92, 0, 2006}, +[1600036] = {93, 0, 2007}, +[1600037] = {94, 0, 2008}, +[1600039] = {69, 0, 3020}, +[1600040] = {54, 0, 3019}, +[1600041] = {64, 0, 3021}, +[1600042] = {76, 0, 3022}, +[1600043] = {96, 0, 3009}, +[1600044] = {97, 0, 3010}, +[1600045] = {98, 0, 3011}, +[1600046] = {99, 0, 3012}, +[1600047] = {100, 0, 3013}, +[1600048] = {101, 0, 3014}, +[1600049] = {102, 0, 3016}, +[1600050] = {103, 0, 3015}, +[1600051] = {104, 0, 3017}, +[1600052] = {105, 0, 3004}, +[1600053] = {106, 0, 3007}, +[1600054] = {107, 0, 3018}, +[1600055] = {108, 0, 3006}, +[1600056] = {109, 0, 3005}, +[1600057] = {110, 0, 3002}, +[1600058] = {111, 0, 3003}, +[1600059] = {112, 0, 3001}, +[1600064] = {235, 0, 2023}, +[1600066] = {237, 0, 3023}, +[1600075] = {245, 1, {5021,5022,5023,5024,5025,5026} }, +[1600076] = {247, 1, {5027,5028,5029,5030,5031,5032} }, +[1600077] = {248, 1, {5033,5034,5035,5036,5037,5038} }, +[1600080] = {251, 1, {5051,5052,5053,5054,5055,5056} }, +[1600081] = {255, 1, {5075,5076,5077,5078,5079,5080} }, +[1600089] = {260, 1, {5105,5106,5107,5108,5109,5110} }, +[1600092] = {263, 0, 2024}, +[1600094] = {265, 0, 3024}, +[1600100] = {281, 2, {5001, 5002, 5007, 5008} }, +} + function init(npc) - return false, false, 0, 0; + return false, false, 0, 0; end function onEventStarted(player, npc, triggerName) - require("/unique/".. npc.zone.zoneName .."/PopulaceShopSalesman/" .. npc:GetUniqueId()) - - if (shopInfo.shopCurrancy == nil) then - shopInfo.shopCurrancy = 1000001; - end - - callClientFunction(player, "welcomeTalk", shopInfo.welcomeText, player); - - while (true) do - - tutorialId = -8; - - if (shopInfo.tutorialId ~= nil) then - tutorialAskMode = shopInfo.tutorialId; - end - - if (shopInfo.selectMode == nil or shopInfo.selectMode == 0) then - choice = callClientFunction(player, "selectMode", tutorialId); - elseif (shopInfo.selectMode == 1) then - choice = callClientFunction(player, "selectModeOfClassVendor"); - elseif (shopInfo.selectMode == 2) then - choice = callClientFunction(player, "selectModeOfMultiWeaponVendor", tutorialId); - elseif (shopInfo.selectMode == 3) then - choice = callClientFunction(player, "selectModeOfMultiArmorVendor", tutorialId); - end - - if (choice == nil) then - break; - end - - if (shopInfo.selectMode == nil or shopInfo.selectMode == 0) then - processNormalShop(player, choice); - elseif (shopInfo.selectMode == 1) then - processNormalShop(player, choice); - elseif (shopInfo.selectMode == 2) then - processMultiShop(player, choice); - elseif (shopInfo.selectMode == 3) then - processMultiShop(player, choice); - end - - end - - callClientFunction(player, "finishTalkTurn", player); - player:EndEvent(); - + -- require("/unique/".. npc.zone.zoneName .."/PopulaceShopSalesman/" .. npc:GetUniqueId()) + npcId = npc:GetActorClassId(); + + if shopInfo[npcId] == nil then + errorMsg = string.format("This PopulaceShopSalesman actor has no shop set. Actor Class Id: %s", npcId); + player:SendMessage(MESSAGE_TYPE_SYSTEM_ERROR, "", errorMsg ); + player:EndEvent(); + return; + end; + + shopCurrancy = 1000001; + callClientFunction(player, "welcomeTalk", shopInfo[npcId][1], player); + + if npcId == 1000159 then -- DoH Guild NPCs with Facility menu + tutorialId = 36; + elseif npcId == 1000163 then + tutorialId = 31; + elseif npcId == 1001458 then + tutorialId = 30; + elseif npcId == 1600017 then + tutorialId = 29; + elseif npcId == 1600018 then + tutorialId = 33; + elseif npcId == 1600039 then + tutorialId = 35; + elseif npcId == 1600040 then + tutorialId = 32; + elseif npcId == 1600041 then + tutorialId = 34; + else + tutorialId = -8; + end + + + + while (true) do + + if (shopInfo[npcId][2] == 0) then + choice = callClientFunction(player, "selectMode", tutorialId); + elseif (shopInfo[npcId][2] == 1) then + choice = callClientFunction(player, "selectModeOfClassVendor"); + elseif (shopInfo[npcId][2] == 2) then + choice = callClientFunction(player, "selectModeOfMultiWeaponVendor", tutorialId); + elseif (shopInfo[npcId][2] == 3) then + choice = callClientFunction(player, "selectModeOfMultiArmorVendor", tutorialId); + end + + if (choice == nil or choice == -3) then + break; + end + + if (shopInfo[npcId][2] == 0) then + processNormalShop(player, choice); + elseif (shopInfo[npcId][2] == 1) then + processMultiShop(player, choice); + elseif (shopInfo[npcId][2] == 2) then + processMultiShop(player, choice); + elseif (shopInfo[npcId][2] == 3) then + processMultiShop(player, choice); + end + + end + + callClientFunction(player, "finishTalkTurn", player); + player:EndEvent(); + end function processNormalShop(player, choice) - if (choice == 1) then - callClientFunction(player, "openShopBuy", player, shopInfo.shopPack, shopInfo.shopCurrancy); - - while (true) do - buyResult, index, quantity = callClientFunction(player, "selectShopBuy", player); - - player:GetInventory(location):AddItem(3020308, 1); - if (buyResult == 0) then - callClientFunction(player, "closeShopBuy", player); - break; - else - player:SendMessage(0x20, "", "Player bought a thing at slot " .. tostring(buyResult).. " with quantity "..tostring(index).."."); - end - - end - elseif (choice == 2) then - callClientFunction(player, "openShopSell", player); - - while (true) do - sellResult = callClientFunction(player, "selectShopSell", player); - - if (sellResult == nil) then - callClientFunction(player, "closeShopSell", player); - break; - else - player:SendMessage(0x20, "", "Player sold a thing at slot " .. tostring(sellResult).."."); - - itemToSell = player:GetInventory(0x00):GetItemAtSlot(sellResult.slot); - gItemTOSell = GetItemGamedata(itemToSell.itemId); - - player:GetInventory(0x63):AddItem(shopInfo.shopCurrancy, gItemTOSell.sellPrice); - player:GetInventory(0x00):RemoveItemAtSlot(sellResult.slot); - end - - end - elseif (choice == 3) then - callClientFunction(player, "selectFacility", 2, 35, 3); - callClientFunction(player, "confirmUseFacility", player, 35); - elseif (choice == 4) then - callClientFunction(player, "startTutorial", nil, shopInfo.classAskMode); - end + if (choice == 1) then + callClientFunction(player, "openShopBuy", player, shopInfo[npcId][3], shopCurrancy); + + while (true) do + buyResult, quantity = callClientFunction(player, "selectShopBuy", player); + + if (buyResult == 0) then + callClientFunction(player, "closeShopBuy", player); + break; + else + -- purchaseItem(player, shopInfo.shopContents[buyResult].id, quantity, shopInfo.shopContents[buyResult].hq, shopInfo.shopContents[buyResult].gil, shopInfo.shopCurrancy); + end + end + elseif (choice == 2) then + openSellMenu(player); + elseif (choice == 3) then + local classFacility = (shopInfo[npcId][1] + 1) or 35; + facilityChoice = callClientFunction(player, "selectFacility", nil, classFacility, 3); + + if facilityChoice == 1 then + callClientFunction(player, "confirmUseFacility", player, 200); + elseif facilityChoice == 2 then + callClientFunction(player, "confirmUseFacility", player, 400); + elseif facilityChoice == 3 then + callClientFunction(player, "confirmUseFacility", player, 1000); + end + + elseif (choice == 4) then + callClientFunction(player, "startTutorial", nil, tutorialId); + end end function processMultiShop(player, choice, sellType) - if (choice >= 1 and choice <= 4) then - callClientFunction(player, "openShopBuy", player, shopInfo.shopPack[choice], shopInfo.shopCurrancy); - - while (true) do - buyResult, index, quantity = callClientFunction(player, "selectShopBuy", player); - player:GetInventory(location):AddItem(3020308, 1); - if (buyResult == 0) then - callClientFunction(player, "closeShopBuy", player); - break; - else - player:SendMessage(0x20, "", "Player bought a thing at slot " .. tostring(buyResult).."."); - end - - end - elseif (choice == 0) then - callClientFunction(player, "openShopSell", player); + if (choice >= 1 and choice <= 6) then + callClientFunction(player, "openShopBuy", player, shopInfo[npcId][3][choice], shopCurrancy); + + while (true) do + buyResult, quantity = callClientFunction(player, "selectShopBuy", player); + + if (buyResult == 0) then + callClientFunction(player, "closeShopBuy", player); + break; + else + -- purchaseItem(player, shopInfo.shopContents[choice][buyResult].id, quantity, shopInfo.shopContents[choice][buyResult].hq, shopInfo.shopContents[choice][buyResult].gil, shopInfo.shopCurrancy); + end + end + elseif (choice == 0) then + openSellMenu(player); + elseif (choice == 6) then + callClientFunction(player, "selectFacility", 2, 35, 3); + callClientFunction(player, "confirmUseFacility", player, 35); + elseif (choice == 7) then + callClientFunction(player, "startTutorial", nil, tutorialId); + end + +end + + +function openSellMenu(player) + callClientFunction(player, "openShopSell", player); + + while (true) do + sellResult, sellQuantity, sellState, unknown, sellItemSlot = callClientFunction(player, "selectShopSell", player); + + if (sellResult == nil) then + callClientFunction(player, "closeShopSell", player); + break; + else + if sellState == 1 then + itemToSell = player:GetInventory(INVENTORY_NORMAL):GetItemAtSlot(sellItemSlot-1); + gItemSellId = itemToSell.itemId; + gItemQuality = itemToSell.quality; + gItemPrice = GetItemGamedata(gItemSellId); + gItemPrice = gItemPrice.sellPrice; + + + if gItemQuality == 2 then -- +1 + gItemPrice = (math.floor(gItemPrice * 1.10)); + elseif gItemQuality == 3 then -- +2 + gItemPrice = (math.floor(gItemPrice * 1.25)); + elseif gItemQuality == 4 then -- +3 + gItemPrice = (math.floor(gItemPrice * 1.50)); + end + + callClientFunction(player, "informSellPrice", 1, sellItemSlot, gItemPrice); + + elseif sellState == nil then + sellItem(player, gItemSellId, sellQuantity, gItemQuality, gItemPrice, sellItemSlot-1, shopCurrancy); + end + end + end +end - while (true) do - sellResult = callClientFunction(player, "selectShopSell", player); - - if (sellResult == nil) then - callClientFunction(player, "closeShopSell", player); - break; - else - player:SendMessage(0x20, "", "Player sold a thing at slot " .. tostring(sellResult).."."); - end - - end - elseif (choice == 6) then - callClientFunction(player, "selectFacility", 2, 35, 3); - callClientFunction(player, "confirmUseFacility", player, 35); - elseif (choice == 7) then - callClientFunction(player, "startTutorial", nil, shopInfo.classAskMode); - end - -end \ No newline at end of file diff --git a/data/scripts/commands/DiceCommand.lua b/data/scripts/commands/DiceCommand.lua index 9f9bd110..d16557aa 100644 --- a/data/scripts/commands/DiceCommand.lua +++ b/data/scripts/commands/DiceCommand.lua @@ -6,8 +6,8 @@ DiceCommand Script function onEventStarted(player, actor, triggerName, maxNumber) - if (maxNumber == nil) then - maxNumber = 999; + if (maxNumber == nil or maxNumber > 1000 or maxNumber < 1) then + maxNumber = 100; end result = math.random(0, maxNumber); diff --git a/data/scripts/commands/EmoteStandardCommand.lua b/data/scripts/commands/EmoteStandardCommand.lua index 5b5f762b..a4a9c867 100644 --- a/data/scripts/commands/EmoteStandardCommand.lua +++ b/data/scripts/commands/EmoteStandardCommand.lua @@ -69,7 +69,7 @@ function onEventStarted(player, actor, triggerName, emoteId, unknownArg1, arg2, targetId = 0; end - if (player:GetState() == 0) then + if (player:GetState() == 0 or player:GetState() == 11 or player:GetState() == 13) then emote = emoteTable[emoteId]; if (emote ~= nil) then player:doEmote(targetId, emote.animId, emote.descId); diff --git a/data/scripts/commands/gm/givecurrency.lua b/data/scripts/commands/gm/givecurrency.lua index 564dd73d..9f1b6622 100644 --- a/data/scripts/commands/gm/givecurrency.lua +++ b/data/scripts/commands/gm/givecurrency.lua @@ -6,14 +6,100 @@ properties = { description = [[ Adds currency to player or -!addcurrency | -!addcurrency | +Defaults to gil if no item entered +!givecurrency | +!givecurrency | ]], } -function onTrigger(player, argc, currency, qty, name, lastName) +currencyItems = { +["GIL"] = 1000001, +["FIRE_SHARD"] = 1000003, +["ICE_SHARD"] = 1000004, +["WIND_SHARD"] = 1000005, +["EARTH_SHARD"] = 1000006, +["LIGHTNING_SHARD"] = 1000007, +["WATER_SHARD"] = 1000008, +["FIRE_CRYSTAL"] = 1000009, +["ICE_CRYSTAL"] = 1000010, +["WIND_CRYSTAL"] = 1000011, +["EARTH_CRYSTAL"] = 1000012, +["LIGHTNING_CRYSTAL"] = 1000013, +["WATER_CRYSTAL"] = 1000014, +["FIRE_CLUSTER"] = 1000015, +["ICE_CLUSTER"] = 1000016, +["WIND_CLUSTER"] = 1000017, +["EARTH_CLUSTER"] = 1000018, +["LIGHTNING_CLUSTER"] = 1000019, +["WATER_CLUSTER"] = 1000020, +["PUGILISTS_GUILD_MARK"] = 1000101, +["GLADIATORS_GUILD_MARK"] = 1000102, +["MARAUDERS_GUILD_MARK"] = 1000103, +["ARCHERS_GUILD_MARK"] = 1000106, +["LANCERS_GUILD_MARK"] = 1000107, +["THAUMATURGES_GUILD_MARK"] = 1000110, +["CONJURERS_GUILD_MARK"] = 1000111, +["CARPENTERS_GUILD_MARK"] = 1000113, +["BLACKSMITHS_GUILD_MARK"] = 1000114, +["ARMORERS_GUILD_MARK"] = 1000115, +["GOLDSMITHS_GUILD_MARK"] = 1000116, +["LEATHERWORKERS_GUILD_MARK"] = 1000117, +["WEAVERS_GUILD_MARK"] = 1000118, +["ALCHEMISTS_GUILD_MARK"] = 1000119, +["CULINARIANS_GUILD_MARK"] = 1000120, +["MINERS_GUILD_MARK"] = 1000121, +["BOTANISTS_GUILD_MARK"] = 1000122, +["FISHERMENS_GUILD_MARK"] = 1000123, +["STORM_SEAL"] = 1000201, +["SERPENT_SEAL"] = 1000202, +["FLAME_SEAL"] = 1000203, + +["FIRESHARD"] = 1000003, +["ICESHARD"] = 1000004, +["WINDSHARD"] = 1000005, +["EARTHSHARD"] = 1000006, +["LIGHTNINGSHARD"] = 1000007, +["WATERSHARD"] = 1000008, +["FIRECRYSTAL"] = 1000009, +["ICECRYSTAL"] = 1000010, +["WINDCRYSTAL"] = 1000011, +["EARTHCRYSTAL"] = 1000012, +["LIGHTNINGCRYSTAL"] = 1000013, +["WATERCRYSTAL"] = 1000014, +["FIRECLUSTER"] = 1000015, +["ICECLUSTER"] = 1000016, +["WINDCLUSTER"] = 1000017, +["EARTHCLUSTER"] = 1000018, +["LIGHTNINGCLUSTER"] = 1000019, +["WATERCLUSTER"] = 1000020, +["PUGILISTSGUILDMARK"] = 1000101, +["GLADIATORSGUILDMARK"] = 1000102, +["MARAUDERSGUILDMARK"] = 1000103, +["ARCHERSGUILDMARK"] = 1000106, +["LANCERSGUILDMARK"] = 1000107, +["THAUMATURGESGUILDMARK"] = 1000110, +["CONJURERSGUILDMARK"] = 1000111, +["CARPENTERSGUILDMARK"] = 1000113, +["BLACKSMITHSGUILDMARK"] = 1000114, +["ARMORERSGUILDMARK"] = 1000115, +["GOLDSMITHSGUILDMARK"] = 1000116, +["LEATHERWORKERSGUILDMARK"] = 1000117, +["WEAVERSGUILDMARK"] = 1000118, +["ALCHEMISTSGUILDMARK"] = 1000119, +["CULINARIANSGUILDMARK"] = 1000120, +["MINERSGUILDMARK"] = 1000121, +["BOTANISTSGUILDMARK"] = 1000122, +["FISHERMENSGUILDMARK"] = 1000123, +["STORMSEAL"] = 1000201, +["SERPENTSEAL"] = 1000202, +["FLAMESEAL"] = 1000203, +} + +function onTrigger(player, argc, item, qty, name, lastName) local sender = "[givecurrency] "; - + local messageID = MESSAGE_TYPE_SYSTEM_ERROR; + local worldMaster = GetWorldMaster(); + if name then if lastName then player = GetWorldManager():GetPCInWorld(name.." "..lastName) or nil; @@ -23,20 +109,30 @@ function onTrigger(player, argc, currency, qty, name, lastName) end; if player then - currency = tonumber(currency) or nil; + if not currencyItems[string.upper(item)] then + player:SendMessage(messageID, sender, "Invalid parameter for item."); + return; + else + item = currencyItems[string.upper(item)]; + end + qty = tonumber(qty) or 1; location = INVENTORY_CURRENCY; + + local invCheck = player:getInventory(location):AddItem(item, qty, 1); - local added = player:GetInventory(location):AddItem(currency, qty, 1); - local messageID = MESSAGE_TYPE_SYSTEM_ERROR; - local message = "unable to add currency"; - - if currency and added then - message = string.format("added currency %u to %s", currency, player:GetName()); + if (invCheck == INV_ERROR_FULL) then + -- Your inventory is full. + player:SendGameMessage(player, worldMaster, 60022, messageID); + elseif (invCheck == INV_ERROR_ALREADY_HAS_UNIQUE) then + -- You cannot have more than one in your possession at any given time. + player:SendGameMessage(player, worldMaster, 40279, messageID, item, 1); + elseif (invCheck == INV_ERROR_SYSTEM_ERROR) then + player:SendMessage(MESSAGE_TYPE_SYSTEM, "", "[DEBUG] Server Error on adding item."); + elseif (invCheck == INV_ERROR_SUCCESS) then + message = string.format("Added item %s to location %s to %s", item, location, player:GetName()); + player:SendMessage(MESSAGE_TYPE_SYSTEM, "", message); + player:SendGameMessage(player, worldMaster, 25246, messageID, item, qty); end - player:SendMessage(messageID, sender, message); - print(message); - else - print(sender.."unable to add currency, ensure player name is valid."); - end; + end end; \ No newline at end of file diff --git a/data/scripts/commands/gm/giveitem.lua b/data/scripts/commands/gm/giveitem.lua index 0b16b329..79d01ff5 100644 --- a/data/scripts/commands/gm/giveitem.lua +++ b/data/scripts/commands/gm/giveitem.lua @@ -15,7 +15,7 @@ Adds to for player or . function onTrigger(player, argc, item, qty, location, name, lastName) local sender = "[giveitem] "; local messageID = MESSAGE_TYPE_SYSTEM_ERROR; - local message = string.format("Unable to add item %u", item); + local worldMaster = GetWorldMaster(); if name then if lastName then @@ -27,10 +27,16 @@ function onTrigger(player, argc, item, qty, location, name, lastName) if player then item = tonumber(item) or nil; + + if not item then + player:SendMessage(messageID, sender, "Invalid parameter for item."); + return; + end + qty = tonumber(qty) or 1; if location then - location = tonumber(location) or _G[string.upper(location)]; + location = _G[string.upper(location)]; if not location then player:SendMessage(messageID, sender, "Unknown item location."); @@ -40,16 +46,22 @@ function onTrigger(player, argc, item, qty, location, name, lastName) location = INVENTORY_NORMAL; end; - local added = player:getInventory(location):addItem(item, qty, 1); - if added then - message = string.format("Added item %u of kind %u to %s", item, location, player:GetName()); - end; - else - print(sender.."[giveitem] Unable to add item, ensure player name is valid."); - return; - end; - - player:SendMessage(messageID, sender, message); - print(message); + local invCheck = player:getInventory(location):AddItem(item, qty, 1); + + if (invCheck == INV_ERROR_FULL) then + -- Your inventory is full. + player:SendGameMessage(player, worldMaster, 60022, messageID); + elseif (invCheck == INV_ERROR_ALREADY_HAS_UNIQUE) then + -- You cannot have more than one in your possession at any given time. + player:SendGameMessage(player, worldMaster, 40279, messageID, item, 1); + elseif (invCheck == INV_ERROR_SYSTEM_ERROR) then + player:SendMessage(MESSAGE_TYPE_SYSTEM, "", "[DEBUG] Server Error on adding item."); + elseif (invCheck == INV_ERROR_SUCCESS) then + message = string.format("Added item %s to location %s to %s", item, location, player:GetName()); + player:SendMessage(MESSAGE_TYPE_SYSTEM, "", message); + player:SendGameMessage(player, worldMaster, 25246, messageID, item, qty); + 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 932ed372..65b79140 100644 --- a/data/scripts/commands/gm/nudge.lua +++ b/data/scripts/commands/gm/nudge.lua @@ -13,7 +13,18 @@ Positions your character forward a set , defaults to 5 yalms. } -function onTrigger(player, argc, distance, vertical) +vertical = { +["UP"] = 1, +["U"] = 1, +["+"] = 1, +["ASCEND"] = 1, +["DOWN"] = -1, +["D"] = -1, +["-"] = -1, +["DESCEND"] = -1, +} + +function onTrigger(player, argc, arg1, arg2) local pos = player:GetPos(); local x = pos[0]; local y = pos[1]; @@ -21,37 +32,69 @@ function onTrigger(player, argc, distance, vertical) local rot = pos[3]; local zone = pos[4]; local angle = rot + (math.pi/2); + + local worldManager = GetWorldManager(); local messageID = MESSAGE_TYPE_SYSTEM_ERROR; local sender = "[nudge] "; - - if distance == nil then - distance = 5 - end; - - local px = x - distance * math.cos(angle); - local pz = z + distance * math.sin(angle); - local message = string.format("Positioning forward %u yalms.", distance); - local worldManager = GetWorldManager(); + local distance = 5; + local direction = 0; + + local checkArg1 = tonumber(arg1); + local checkArg2 = tonumber(arg2); if argc == 1 then - worldManager:DoPlayerMoveInZone(player, px, y, pz, rot, 0x0); - player:SendMessage(messageID, sender, message); - elseif argc == 2 then - if vertical == "up" or vertical == "u" or vertical == "+" then - y = y + distance; - message = string.format("Positioning up %u yalms.", distance); - worldManager:DoPlayerMoveInZone(player, x, y, z, rot, 0x0); - player:SendMessage(messageID, sender, message); - elseif vertical == "down" or vertical == "d" or vertical == "-" then - y = y - distance; - message = string.format("Positioning down %u yalms.", distance); - worldManager:DoPlayerMoveInZone(player, x, y, z, rot, 0x0); - player:SendMessage(messageID, sender, message); - else - player:SendMessage(messageID, sender, "Unknown parameters! Usage: \n"..properties.description); - end; + 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, otherwise throw param error + direction = vertical[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 + direction = vertical[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 + + + + local message = string.format("Positioning forward %s yalms.", distance); + + if direction == 1 then + y = y + distance; + message = string.format("Positioning up %s yalms.", distance); + worldManager:DoPlayerMoveInZone(player, x, y, z, rot, 0x0); + elseif direction == -1 then + y = y - distance; + message = string.format("Positioning down %s yalms.", distance); + worldManager:DoPlayerMoveInZone(player, x, y, z, rot, 0x0); else - worldManager:DoPlayerMoveInZone(player, px, y, pz, rot, 0x0); - player:SendMessage(messageID, sender, message); + local px = x - distance * math.cos(angle); + local pz = z + distance * math.sin(angle); + if distance < 1 then + message = string.format("Positioning back %s yalms.", distance); + end + worldManager:DoPlayerMoveInZone(player, px, y, pz, rot, 0x0); end; + + player:SendMessage(messageID, sender, message); + end; diff --git a/data/scripts/commands/gm/quest.lua b/data/scripts/commands/gm/quest.lua new file mode 100644 index 00000000..6814338e --- /dev/null +++ b/data/scripts/commands/gm/quest.lua @@ -0,0 +1,124 @@ +require("global"); + +properties = { + permissions = 0, + parameters = "ssss", + description = +[[ +Add/Remove Quests, modify and . +!quest add/remove | +!quest phase | +!quest flag true/false | +]], +} + +function onTrigger(player, argc, command, var1, var2, var3) + + local messageID = MESSAGE_TYPE_SYSTEM_ERROR; + local sender = "[quest] "; + local message = "Error"; + + if player then + if argc == 2 then + if command == "add" or command == "give" or command == "+" then + if tonumber(var1) then + if player:HasQuest(tonumber(var1)) == false then + player:AddQuest(tonumber(var1)); + message = ("adding quest "..var1); + else + message = ("already have quest "..var1); + end + else + if player:HasQuest(var1) == false then + player:AddQuest(var1); + message = ("adding quest "..var1); + else + message = ("already have quest "..var1); + end + end + + elseif command == "remove" or command == "delete" or command == "-" then + if tonumber(var1) and player:HasQuest(tonumber(var1)) == true then + player:RemoveQuestByQuestId(tonumber(var1)); + message = ("removing quest "..var1); + else + if player:HasQuest(var1) == true then + q2 = GetStaticActor(var1); + + if q2 ~= nil then + q3 = q2.actorId; + message = ("removing quest "..var1); + printf(q3); + q4 = bit32.band(q3, 0xA0F00000); + printf(q4); + + --player:RemoveQuest(quest.actorName); + end + else + message = ("remove error: either incorrect ID or quest "..var1.." isn't active on character"); + end + end + else + message = ("error: command "..command.." not recognized"); + end + + elseif argc == 3 then + if command == "phase" or command == "step" then + if (tonumber(var1) and tonumber(var2)) ~= nil then + if player:HasQuest(tonumber(var1)) == true then + player:GetQuest(tonumber(var1)):NextPhase(tonumber(var2)); + message = ("changing phase of quest "..var1.." to "..var2); + else + message = ("phase error: either incorrect ID or quest "..var1.." isn't active on character"); + end + else + message = ("error: invalid parameters used"); + end + else + message = ("error: command "..command.." not recognized"); + end; + + elseif argc == 4 then + if command == "flag" then + if tonumber(var1) and (tonumber(var2) >= 0 and tonumber(var2) <= 32) then + questvar = tonumber(var1); + flagvar = (tonumber(var2)); + boolvar = 0; + + if var3 == "true" or var3 == "1" or var3 == "on" then + boolvar = true; + elseif var3 == "false" or var3 == "0" or var3 == "off" then + boolvar = false; + elseif var3 == "flip" or var3 == "toggle" then + if player:HasQuest(questvar) == true then + boolvar = not player:GetQuest(questvar):GetQuestFlag(flagvar); + end + else + message = ("error: flag: boolean not recognized"); + print(sender..message); + return; + end + + var4 = player:GetQuest(questvar):GetQuestFlag(flagvar); + + if var4 ~= boolvar then + player:GetQuest(questvar):SetQuestFlag(flagvar, boolvar); + player:GetQuest(questvar):SaveData(); + if boolvar == true then + message = ("changing flag "..tonumber(var2).." to true on quest "..questvar); + else + message = ("changing flag "..tonumber(var2).." to false on quest "..questvar); + end + else + message = ("error: flag "..flagvar.." is already set to that state on quest "..questvar); + end + else + message = ("error: command "..command.." not recognized"); + end + end + end + end + + player:SendMessage(messageID, sender, message); + print(sender..message); +end \ No newline at end of file diff --git a/data/scripts/commands/gm/speed.lua b/data/scripts/commands/gm/speed.lua index 1008eb2b..8c1e5018 100644 --- a/data/scripts/commands/gm/speed.lua +++ b/data/scripts/commands/gm/speed.lua @@ -13,24 +13,20 @@ Set movement speed for player. Enter no value to reset to default. } function onTrigger(player, argc, stop, walk, run) - - if argc == 1 then - s = 0; - w = (tonumber(stop) / 2); - r = tonumber(stop); - player:ChangeSpeed(s, w, r); - player:SendMessage(MESSAGE_TYPE_SYSTEM_ERROR, "[speed]", string.format("Speed set to 0/%u/%u", w,r)); - elseif argc == 3 then - stop = tonumber(stop) or 0; - walk = tonumber(walk) or 2; - run = tonumber(run) or 5; - if argc == 3 then - player:ChangeSpeed(stop, walk, run, run); - elseif argc == 1 then - player:ChangeSpeed(0, stop/2, stop, stop); - else - player:ChangeSpeed(0,2,5,5); - end - end - + local s = tonumber(stop) or 0; + local w = tonumber(walk) or 2; + local r = tonumber(run) or 5; + + if argc == 1 and tonumber(stop) then + w = (tonumber(stop) / 2); + player:ChangeSpeed(0, w, s, s); + player:SendMessage(MESSAGE_TYPE_SYSTEM_ERROR, "", string.format("[speed] Speed set to 0/%s/%s", w,s)); + elseif argc == 3 then + player:ChangeSpeed(s, w, r, r); + player:SendMessage(MESSAGE_TYPE_SYSTEM_ERROR, "", string.format("[speed] Speed set to %s/%s/%s", s,w,r)); + else + player:ChangeSpeed(0, 2, 5, 5); + player:SendMessage(MESSAGE_TYPE_SYSTEM_ERROR, "", "[speed] Speed values set to default"); + end + end \ No newline at end of file diff --git a/data/scripts/commands/gm/warpid.lua b/data/scripts/commands/gm/warpid.lua new file mode 100644 index 00000000..66301140 --- /dev/null +++ b/data/scripts/commands/gm/warpid.lua @@ -0,0 +1,39 @@ +require("global"); + +properties = { + permissions = 0, + parameters = "s", + description = "Teleports to Actor uniqueId's position", +} + +function onTrigger(player, argc, uID) + local messageID = MESSAGE_TYPE_SYSTEM_ERROR; + local sender = "[warpid] "; + local message = "unable to find actor"; + local worldManager = GetWorldManager(); + + if not player then + printf("[Command] [warpid] Player not found!"); + return; + end; + + actor = GetWorldManager():GetActorInWorldByUniqueId(uID); + + if (actor ~= nil) then + local actorPos = actor:GetPos(); + local playerPos = player:GetPos(); + + if actorPos[4] == playerPos[4] then + worldManager:DoPlayerMoveInZone(player, actorPos[0], actorPos[1], actorPos[2], actorPos[3], 0x00); + else + worldManager:DoZoneChange(player, actorPos[4], nil, 0, 0x02, actorPos[0], actorPos[1], actorPos[2], actorPos[3]); + end + + message = string.format("Moving to %s 's coordinates @ zone %s, %.3f %.3f %.3f ", uID, actorPos[4], actorPos[0], actorPos[1], actorPos[2]); + end ; + + player:SendMessage(messageID, sender, message); + +end + + \ No newline at end of file diff --git a/data/scripts/commands/gm/warpplayer.lua b/data/scripts/commands/gm/warpplayer.lua new file mode 100644 index 00000000..297c9250 --- /dev/null +++ b/data/scripts/commands/gm/warpplayer.lua @@ -0,0 +1,63 @@ +require("global"); + +properties = { + permissions = 0, + parameters = "ssss", + description = +[[ +Warps to name of player, or warps first player to second player + | +<1st target name> <2nd target name> +]], +} + +function onTrigger(player, argc, name, lastName, name2, lastName2) + + local messageID = MESSAGE_TYPE_SYSTEM_ERROR; + local sender = "[warpplayer] "; + + if name and lastName then + p1 = GetWorldManager():GetPCInWorld(name.." "..lastName) or nil; + end; + + if name2 and lastName2 then + p2 = GetWorldManager():GetPCInWorld(name2.." "..lastName2) or nil; + end; + + if not player then + printf("[Command] [warpplayer] Error! No target or player specified!"); + return; + end; + + local worldManager = GetWorldManager(); + + if argc == 2 then + if not p1 then + printf("[Command] [warpplayer] Error! Invalid player specified!"); + player:SendMessage(messageID, sender, "Error! Invalid player specified!"); + return; + else + local pos = p1:GetPos(); + worldManager:DoZoneChange(player, pos[4], nil, 0, 0x02, pos[0], pos[1], pos[2], pos[3]); + player:SendMessage(messageID, sender, string.format("Moving to %s %s 's coordinates.", name, lastName)); + end; + elseif argc == 4 then; + if not p1 or not p2 then + printf("[Command] [warpplayer] Error! Invalid player specified!"); + player:SendMessage(messageID, sender, "Error! Invalid player specified!"); + return; + else + local pos = p1:GetPos(); + local pos2 = p2:GetPos(); + + worldManager:DoZoneChange(p1, pos2[4], nil, 0, 0x02, pos2[0], pos2[1], pos2[2], pos2[3]); + player:SendMessage(messageID, sender, string.format("Moving %s %s to %s %s 's coordinates.", name, lastName, name2, lastName2)); + p1:SendMessage(messageID, sender, string.format("You are being moved to %s %s 's coordinates.", name2, lastName2)); + end; + else + if player then + player:SendMessage(messageID, sender, "Unknown parameters! Usage: "..properties.description); + end; + return; + end; +end; diff --git a/data/scripts/global.lua b/data/scripts/global.lua index af933ad2..107307f7 100644 --- a/data/scripts/global.lua +++ b/data/scripts/global.lua @@ -51,6 +51,12 @@ INVENTORY_KEYITEMS = 0x0064; --Max 0x500 INVENTORY_EQUIPMENT = 0x00FE; --Max 0x23 INVENTORY_EQUIPMENT_OTHERPLAYER = 0x00F9; --Max 0x23 +-- INVENTORY ERRORS +INV_ERROR_SUCCESS = 0; +INV_ERROR_FULL = 1; +INV_ERROR_ALREADY_HAS_UNIQUE = 2; +INV_ERROR_SYSTEM_ERROR = 3; + -- CHOCOBO APPEARANCE CHOCOBO_NORMAL = 0; diff --git a/data/scripts/shop.lua b/data/scripts/shop.lua new file mode 100644 index 00000000..acaf3f93 --- /dev/null +++ b/data/scripts/shop.lua @@ -0,0 +1,55 @@ +--[[ + +Shop Buy/Sell Functions + +--]] + +function purchaseItem(player, location, itemId, quantity, quality, price, currency) + + local worldMaster = GetWorldMaster(); + local invCheck = -1; + + if (player:GetInventory(INVENTORY_CURRENCY):HasItem(currency, price)) then + invCheck = player:GetInventory(location):AddItem(itemId, quantity, quality); + + if (invCheck == INV_ERROR_FULL) then + -- Your inventory is full. + player:SendGameMessage(player, worldMaster, 60022, MESSAGE_TYPE_SYSTEM); + elseif (invCheck == INV_ERROR_ALREADY_HAS_UNIQUE) then + -- You cannot have more than one in your possession at any given time. + player:SendGameMessage(player, worldMaster, 40279, MESSAGE_TYPE_SYSTEM, itemId, quality); + elseif (invCheck == INV_ERROR_SYSTEM_ERROR) then + player:SendMessage(0x20, "", "[DEBUG] Server Error on adding item."); + elseif (invCheck == INV_ERROR_SUCCESS) then + player:GetInventory(INVENTORY_CURRENCY):removeItem(currency, price); + + if (currency == 1000001) then -- If Gil + -- You purchase for gil. + player:SendGameMessage(player, worldMaster, 25061, MESSAGE_TYPE_SYSTEM, itemId, quality, quantity, price); + + elseif (currency == 1000201 or currency == 1000202 or currency == 1000203) then -- If Grand Company seal + -- You exchange for . + player:SendGameMessage(player, worldMaster, 25275, MESSAGE_TYPE_SYSTEM, itemId, quality, quantity, price, player.gcCurrent); + + elseif (currency >= 1000101 and currency <= 1000123) then -- If Guild mark + -- You trade for . + player:SendGameMessage(player, GetWorldMaster(), 25071, MESSAGE_TYPE_SYSTEM, currency, 1, itemId, 1, price, quantity); + end + end + else + -- You do not have enough gil. (Should never see this) + player:SendGameMessage(player, worldMaster, 25065, MESSAGE_TYPE_SYSTEM); + end + return +end + + +function sellItem(player, itemId, quantity, quality, itemPrice, slot, currency) + local worldMaster = GetWorldMaster(); + local cost = quantity * itemPrice; + + player:GetInventory(INVENTORY_CURRENCY):AddItem(currency, cost); + player:GetInventory(INVENTORY_NORMAL):RemoveItemAtSlot(slot, quantity); + -- You sell for gil. + player:SendGameMessage(player, worldMaster, 25075, MESSAGE_TYPE_SYSTEM, itemId, quality, quantity, cost); +end \ No newline at end of file