diff --git a/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj b/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj
index 5ff268f7..c0dd50c5 100644
--- a/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj
+++ b/FFXIVClassic Map Server/FFXIVClassic Map Server.csproj
@@ -265,6 +265,9 @@
+
+
+
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