From 1c5fd48d032011e868cfac61d088c163bc8d5c7f Mon Sep 17 00:00:00 2001 From: PW Anon Date: Mon, 13 Apr 2020 20:49:38 +0000 Subject: [PATCH 1/4] Merged in Resharc/project-meteor-server/issue-25 (pull request #68) Fix to incorrect skill being given upon changing to a new class for the first time. * Ported over changes from resharc/ffxiv-classic-server and merged into new branch. * Changed EquipAbilitiesAtLevel(...) to use the level supplied, instead of GetLevel(), which should fix issue 25. * Revert "Ported over changes from resharc/ffxiv-classic-server and merged into new branch." This reverts commit fce3fb5b899c6150230245d73f25255ae2b93549. Approved-by: Filip Maj --- Map Server/Actors/Chara/Player/Player.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Map Server/Actors/Chara/Player/Player.cs b/Map Server/Actors/Chara/Player/Player.cs index 32d124da..361111f2 100644 --- a/Map Server/Actors/Chara/Player/Player.cs +++ b/Map Server/Actors/Chara/Player/Player.cs @@ -2618,7 +2618,7 @@ namespace Meteor.Map.Actors private void EquipAbilitiesAtLevel(byte classId, short level, List actionList = null) { //If there's any abilites that unlocks at this level, equip them. - List commandIds = Server.GetWorldManager().GetBattleCommandIdByLevel(classId, GetLevel()); + List commandIds = Server.GetWorldManager().GetBattleCommandIdByLevel(classId, level); foreach (ushort commandId in commandIds) { EquipAbilityInFirstOpenSlot(classId, commandId, false); From 48d996bd4f6e83a01744af988d43060342433ccb Mon Sep 17 00:00:00 2001 From: CuriousJorge Date: Fri, 25 Sep 2020 18:15:54 -0400 Subject: [PATCH 2/4] SetPushEventConditionWithTriggerBox & EventList.cs - Made changes to PushBoxEventCondition so it can function ingame if provided the correct parameters in the eventConditions in the gamedata_actor_class SQL. These are used for the Market Wards entrances in each city MarketEntrance.lua - Script mostly laid out and documented. Some debugging info left in while various warp locations and PrivateAreas still need finishing up. CraftCommand.lua - WIP on crafting menu + minigame. Menu flow worked out for the most part, it's just a matter of plugging in various data for them to replace the debugging values I set currently. DummyCommand.lua - WIP on Mining minigame. Still lots missing but it's a start. Cannot use mining nodes ingame currently without modifying KickEventPacket.cs Removed orphaned individual ShopSalesman scripts since their info was tabled into a single script awhile back. --- .../base/chara/npc/object/MarketEntrance.lua | 138 +++++- Data/scripts/commands/CraftCommand.lua | 452 ++++++++++++++++++ Data/scripts/commands/DummyCommand.lua | 427 +++++++++++++++-- .../PopulaceShopSalesman/jossy.lua | 6 - .../PopulaceShopSalesman/jemimi.lua | 6 - .../PopulaceShopSalesman/norbettaux.lua | 6 - .../PopulaceShopSalesman/nortmoen.lua | 6 - .../PopulaceShopSalesman/pamisolaux.lua | 6 - .../PopulaceShopSalesman/waeksatz.lua | 5 - .../PopulaceShopSalesman/wnhalki.lua | 5 - .../PopulaceShopSalesman/zagylswerd.lua | 5 - Map Server/Actors/EventList.cs | 4 +- .../SetPushEventConditionWithTriggerBox.cs | 18 +- 13 files changed, 989 insertions(+), 95 deletions(-) create mode 100644 Data/scripts/commands/CraftCommand.lua delete mode 100644 Data/scripts/unique/sea0Town01a/PopulaceShopSalesman/jossy.lua delete mode 100644 Data/scripts/unique/wil0Town01a/PopulaceShopSalesman/jemimi.lua delete mode 100644 Data/scripts/unique/wil0Town01a/PopulaceShopSalesman/norbettaux.lua delete mode 100644 Data/scripts/unique/wil0Town01a/PopulaceShopSalesman/nortmoen.lua delete mode 100644 Data/scripts/unique/wil0Town01a/PopulaceShopSalesman/pamisolaux.lua delete mode 100644 Data/scripts/unique/wil0Town01a/PopulaceShopSalesman/waeksatz.lua delete mode 100644 Data/scripts/unique/wil0Town01a/PopulaceShopSalesman/wnhalki.lua delete mode 100644 Data/scripts/unique/wil0Town01a/PopulaceShopSalesman/zagylswerd.lua diff --git a/Data/scripts/base/chara/npc/object/MarketEntrance.lua b/Data/scripts/base/chara/npc/object/MarketEntrance.lua index 5c0269b6..d09309cd 100644 --- a/Data/scripts/base/chara/npc/object/MarketEntrance.lua +++ b/Data/scripts/base/chara/npc/object/MarketEntrance.lua @@ -4,20 +4,148 @@ MarketEntrance Script Functions: -eventPushChoiceAreaOrQuest(gcLeaderPlaceName[Fronds, etc], showMarketWards/Houses (must be 0xc1a), gcHQPlaceName, anotherPlaceName, showItemSearchCounter, stopSearchingItemId) - -eventPushStepPrvMarket(?, ?, ?) - +Parameters mostly rely on the xtx_placeName sheet for its strings. + +eventPushChoiceAreaOrQuest( + exitPlaceName[Fronds, etc], - Retail only showed it when inside a Market Ward/Office Set to 0 to hide the menu. + showMarketWards/Houses - If > 0, client script adds nation-specific Mercentile Houses as well. + gcHQPlaceName, - Set to the placeName id for the Grand Company office of that city + questAreaName, - Set to the placeName id of applicable quest instance, ex. Sailors Ward. + showItemSearchCounter, - If true, shows the Item Search menu + itemSearchId - If > 0 & showItemSearchCounter = true, displays the item name with a "Stop Searching" +) +eventPushStepPrvMarket( + staringWard, - Sets the starting placeName id + wardCount, - Valid number 1-20. Sets the amount of market ward entries. Client continues sequentially from startingWard id. + excludeWard - Hides the ward in the list that matches the id. Use on the ward you're currently in. +) + + +MarketEntrance City TriggerBox details +Limsa - !warp 230 -416.5 40 446 + bgObj Id - [0xB3B] 2875 + Layout Id - [0x79 ] 121 (0x29d90001) + Condition - in + reactName - dwti - Not a typo compared to the other cities +Gridania - !warp 206 -192.57 23.48 -1407.58 + bgObj Id - [0xCFA] 3322 + Layout Id - [0x141] 321 (0x29b00001) + Condition - in + reactName - dtwi +Ul'dah - !warp 175 -235 189 50.5 + bgObj Id - [0x102F] 4143 + Layout Id - [0x1A5] 421 (0x615a0001) + Condition - in + reactName - dtwi --]] require ("global") -local MARKETWARD_ENTRANCE = {-201.0, 0.0, -160.0, 1.5}; - function init(npc) return false, false, 0, 0; end + +CITY_INFO = { -- wardPlaceName, exitPlaceName, gcHQPlaceName, questAreaName, wardListStart, wardListCount + {1093, 1087, 1512, 1091, 1261, 20}, -- Limsa + {2099, 2091, 2526, 2095, 2261, 20}, -- Gridania + {3098, 3091, 3514, 3095, 3261, 20}, -- Ul'dah +} + +-- TO-DO: Add some X/Z pos jitter to Entrances/Exits when called +MARKETWARD_ENTRANCE = { + {134, 160, 0, 135}, -- Limsa Market + {160, 160, 0, 138}, -- Gridania Market + {180, 160, 0, 185} -- Ul'dah Market +} + +MARKETWARD_EXIT = { + {230, -420, 41, 435, -3.14}, -- Educated guess for Limsa, need video reference to confirm + {206, -180, 22, -1408, 1.5}, + {175, -210, 190, 25, 0.65} +} + +GC_ENTRANCE = { + [1512] = {232, 160, 0, -155}, -- Maelstrom Command + [2526] = {234, 160, 0, -155}, -- Adders' Nest + [3514] = {233, 160, 0, -155} -- Hall of Flames +} + +city = { + [1090238] = 1, -- Limsa Market Ward Entrance + [1090264] = 2, -- Gridania Market Ward Entrance + [1090265] = 3, -- Ul'dah Market Ward Entrance + [1500392] = 1, -- Limsa : M'septha + [1500393] = 2, -- Gridania : Torsefers + [1500394] = 3, -- Ul'dah : Edine +} + + + function onEventStarted(player, npc, triggerName) - callClientFunction(player, "eventPushChoiceAreaOrQuest", 0xc13, 0xc1a, 0xdba, 0, true, 1); + + local npcCity = city[npc:GetActorClassId()] or 1; + local wardPlaceName = CITY_INFO[npcCity][1]; -- Market Wards category name. Identical in all languages except Japanese + local exitPlaceName = CITY_INFO[npcCity][2]; -- Central Limsa Lominsa / Heartstream / The Fronds + local gcHQPlaceName = CITY_INFO[npcCity][3]; -- Maelstrom Command / Adders' Nest / Hall of Flames + local questAreaName = 0; --CITY_INFO[npcCity][4]; -- Sailors Ward / Peasants Ward / Merchants Ward + local wardListStart = CITY_INFO[npcCity][5]; -- Starting id for the market wards + local wardListCount = CITY_INFO[npcCity][6]; -- Amount of wards in the list + local showItemSearchCounter = false; + local itemSearchId = 11000125; + + local worldMaster = GetWorldMaster(); + local pos = player:GetPos(); + local currZone = pos[4]; + + if (currZone == 133 or currZone == 230 or currZone == 155 or currZone == 206 or currZone == 175 or currZone == 209) then + exitPlaceName = 0; -- If in city, hide city menu option + elseif (currZone == 232 or currZone == 234 or currZone == 233) then + gcHQPlaceName = 0; -- If in GC Office, hide office menu option + end + + choice = callClientFunction(player, "eventPushChoiceAreaOrQuest", exitPlaceName, wardPlaceName, gcHQPlaceName, questAreaName, showItemSearchCounter, itemSearchId); + + while (true) do + + if choice == wardPlaceName then -- Market Wards + wardSelect = callClientFunction(player, "eventPushStepPrvMarket", wardListStart, wardListCount, 0); + + if wardSelect and (wardSelect >= wardListStart and wardSelect <= (wardListStart+wardListCount)) then + player:SendGameMessage(player, worldMaster, 60004, 0x20, wardSelect); + warp = MARKETWARD_ENTRANCE[npcCity]; + playerRot = math.random(-3.14, 3.14); + wait(1); + GetWorldManager():DoZoneChange(player, warp[1], nil, 0, 0x02, warp[2], warp[3], warp[4], playerRot); + player:SendDataPacket("attention", worldMaster, "", 60003, wardSelect); + -- Temp: Pop-up display after Ward zone-in. Client should automate this with PrivateArea's properly setup + + break; + end + + elseif (choice == 1519 or choice == 2534 or choice == 3533) then -- Mercentile Wards + player:SendMessage(0x20, "", "[MarketEntrance] DEBUG: "..choice); + elseif (choice == 1512 or choice == 2526 or choice == 3514) then -- GC Office + warp = GC_ENTRANCE[choice]; + player:SendGameMessage(player, worldMaster, 60004, 0x20, choice); + wait(1); + GetWorldManager():DoZoneChange(player, warp[1], nil, 0, 0x02, warp[2], warp[3], warp[4], math.pi); + break; + elseif (choice == 1087 or choice == 2091 or choice == 3091) then -- Exiting to City + player:SendGameMessage(player, worldMaster, 60004, 0x20, choice); + warp = MARKETWARD_EXIT[npcCity]; + wait(1); + GetWorldManager():DoZoneChange(player, warp[1], nil, 0, 0x02, warp[2], warp[3], warp[4], warp[5]); + break; + elseif (choice == 0 or choice == -3) then -- Menu Closed + break; + end + + choice = callClientFunction(player, "eventPushChoiceAreaOrQuest", exitPlaceName, wardPlaceName, gcHQPlaceName, questAreaName, showItemSearchCounter, itemSearchId); + + end + player:EndEvent(); + end \ No newline at end of file diff --git a/Data/scripts/commands/CraftCommand.lua b/Data/scripts/commands/CraftCommand.lua new file mode 100644 index 00000000..05b87286 --- /dev/null +++ b/Data/scripts/commands/CraftCommand.lua @@ -0,0 +1,452 @@ +--[[ + +CraftJudge + +Operates the Crafting system. + +Functions: + +loadTextData() + Desc: Loads all gamesheets needed and instantiates a CraftJudge. + Params: None + +start(facility, requestsMode, material1, material2, material3, material4, material5, material6, material7, material8) + Desc: Opens the Craft Start widget, with any preloaded materials. Widget has two modes; one for normal synthesis and another + for local leve "requested items" mode. + Params: * facility/widgetMode - The current facility id buff the player may have. After opening a recipe tab, start() has to be called with this + set to -1. After the player chooses a recipe, start() has to be called with this set to -2. + * requestMode - If true, switches the UI to Requested Items mode otherwise it opens Normal Synthesis mode. + * material1-8 - ItemID for each of the 8 material slots. If empty, they must be set to 0 or the client will crash. + +closeCraftStartWidget() + Desc: Closes the Craft Start widget. + Params: None + +selectRcp(item1, item2, item3, item4, item5, item6, item7, item8) + Desc: Opens a recipe selection window. If one recipe is provided, automatically selects that recipe. + Params: * itemId1-8 - The itemIDs to show in the list. If only one provided, select it. + +confirmRcp(craftedItem, quantity, crystalItem1, crystalQuantity1, crystalQuantity1, crystalItem2, crystalQuantity2, recommendedSkill, recommendedFacility) + Desc: Opens the confirmation window, detailing what is needed and the item that will be created. Requires a selectRcp() call first. + Params: * craftedItem - The itemID of the item to be crafted. + * quantity - Quantity of crafted items. + * crystalItem1 - The first required crystal itemID for crafting. + * crystalQuantity1 - Quantity of the first crystal. + * crystalItem2 - The second required crystal itemID for crafting. + * crystalQuantity2 - Quantity of the second crystal. + * recommendedSkill - Which itemID to display under the "Recommended Skill" panel. + * recommendedFacility - Which facility to display under the "Recommended Facility" panel. + +selectCraftQuest() + Desc: Opens the journal to select the local leve that the player would like to do. + Params: None + +confirmLeve() + Desc: Opens the summery page for the local leve. + Params: * localLeveID - + * craftedItem - + * ? + * ? + * itemsCompleted - + * remainingMaterials - + * ? + * ? + +askContinueLocalLeve(localLeveID, craftedItem, itemsCompleted, craftTotal, attempts) + Desc: Opens the dialog to continue crafting for a local leve after an item was completed. + Params: * localLeveID - The id of the current leve in progress. + * craftedItem - The current crafted item id. + * itemsCompleted - Number of items crafted so far. + * craftTotal - Number of items to be crafted in total. + * attempts - The number of attempts left. + +askRetryLocalleve(localLeveID, allowanceCount) + Desc: Opens the dialog to retry the local leve (at the expense of an allowance) if the player had failed it. + Params: * localLeveID - The failed level id. + * allowanceCount - How many allowances the player has. + +openCraftProgressWidget(durability, quality, hqChance) + Desc: Opens the crafting minigame, sets starting values. + Params: * durability - Durability of the current item. + * quality - Starting quality of the current item. + * hqChance - Starting chance to get a HQ item. + +craftCommandUI(classID, hasWait, command1, command2, command3, command4, command5) + Desc: Sets the available command list and waits for the player to select a command. + Params: + * classID - The current crafting class. Must be set properly to show the three synthesis commands. + * hasWait - If true, adds the wait command. + * command1-5 - Five possible crafting commands (crafting skills). + +craftTuningUI(command1, command2, command3, command4, command5, command6, command7, command8) + Desc: Displays a full list of commands for the legacy "Tuning" phase that happens after crafting. Deprecated in 1.23b. + Params: * command1-8 - The list of commands available. + +updateInfo(progress, durability, quality, tuningItem, tuningItemQuality, tuningItemQuantity, hqChance) + Desc: Updates the progress UI components and text boxes. + Params: * progress - The current crafting progress percentage. Value is from 0 to 100. + * durability - The current durability of the crafted item. + * quality - The current quality of the crafted item. + * tuningItem - The crafted item to show in the Tuning UI. Nil if crafting. Deprecated in 1.23b. + * tuningItemQuality - The quality of the item to show in the Tuning UI. Nil if crafting. Deprecated in 1.23b. + * tuningItemQuantity - The amount of the item to show in the Tuning UI. Nil if crafting. Deprecated in 1.23b. + * hqChance - The current chance of an HQ craft. + +closeCraftProgressWidget() + Desc: Closes the crafting minigame widget. + Params: None + +cfmQst() + Desc: Quest confirmation window for when starting a crafting quest from the journal. + Params: + +startRepair(craftMode, item, quality, durability, hasMateria, spiritbind) + Desc: Opens the repair item widget. + Params: * craftMode - Either 0 or 1. Anything else crashes. + * item - ItemID of the item to be repaired. + * quality - Quality of the item to be repaired. + * durability - Durability of the item to be repaired. + * hasMateria - Shows an icon if the item to be repaired has materia attached. + * spiritbind - Spiritbind of the item to be repaired. + +askJoinMateria() +displayRate() + +askJoinResult(isSuccess, item, itemQuality, materia, materiaNumber, isSpiritBound) + Desc: Opens the result widget after materia melding is done. + Params: * isSuccess - True if the meld was successful. + * item - Item ID of the melded item. + * quality - Quality of the melded item. + * materia - Item ID of the materia being melded. + * materiaNumber - Total count of materia on the item. + * isSpiritBound - True if the item is spiritbound. Causes icon to appear. + +Notes: + +Class ID + Starting skill + 29 CRP = 22550 + 30 BSM = 22556 + 31 ARM = 22562 + 32 GSM = 22568 + 33 LTW = 22574 + 34 WVR = 22580 + 35 ALC = 22586 + 36 CUL = 22592 + + +--]] + +require ("global") + + +skillAnim = { + [22553] = 0x10002000; + [22554] = 0x10001000; + [22555] = 0x10003000; + [29531] = 0x10009002; +} + + +materialSlots = {0,0,0,0,0,0,0,0}; -- The 8 slots +recentRecipe = {10008205, 4030706, 4070009} -- Recent Recipe list +awardedRecipe = {7020105, 7030011} -- Awarded Recipe list + +materialRecipe = { -- Always 8 params because we can't have any nils here for "start" command + [6071007] = {4070402, 4070309,0,0,0,0,0,0}, + [10008205] = {10008005,10008005,0,0,0,0,0,0}, + [10009617] = {4040009, 4040010, 4040011,0,0,0,0,0}, + [4070009] = {4070006, 10005401, 10008203,0,0,0,0,0}, + [4070010] = {10008204,10008106,10005302,0,0,0,0,0} +} + +materialQuest = { -- What a quest or leve will preload slots with, in addition to any extras the player does manual + [0] = {0,0,0,0,0,0,0,0}, + [1] = {0,0,0,0,0,0,0,0}, + [110442] = {11000075, 11000074, 0, 0, 0, 0, 0, 0} +} + + +function onEventStarted(player, commandactor, triggerName, arg1, arg2, arg3, arg4, checkedActorId) + + MENU_CANCEL, MENU_MAINHAND, MENU_OFFHAND, MENU_REQUEST = 0, 1, 2, 3; + MENU_RECIPE, MENU_AWARDED, MENU_RECIPE_DETAILED, MENU_AWARDED_DETAILED = 7, 8, 9, 10; + + debugMessage = false; + + isRecipeRecentSent = false; + isRecipeAwardSent = false; + detailWindow = true; + isRequested = false; -- False = The default state. True = User picked a quest recipe/local leve + facilityId = 0; + chosenQuest = 0; -- Use this to store any chosen recipe/local leve + recipeDetail = 0; + detailWindowState = 0; + + craftJudge = GetStaticActor("CraftJudge"); + callClientFunction(player, "delegateCommand", craftJudge, "loadTextData", commandactor); + + chosenOperation = -1; + + + while chosenOperation ~= 0 do + + player:ChangeState(30); + + if debugMessage then player:SendMessage(0x20, "", "[DEBUG] Menu ID: "..tostring(chosenOperation).." Recipe : "..tostring(recipeMode).." Quest : "..chosenQuest); end + + + if materialQuest[chosenQuest] then + if debugMessage then player:SendMessage(0x20, "", "Key is valid: "..chosenQuest); end + materialSlots = materialQuest[chosenQuest]; + else + if debugMessage then player:SendMessage(0x20, "", "Key is not valid: "..chosenQuest); end + end + + + if isRecipeRecentSent == false then -- If Recipe button not hit, aka default state. + chosenOperation, recipeMode = callClientFunction(player, "delegateCommand", craftJudge, "start", commandactor, facilityId, isRequested, unpack(materialSlots)); -- Initial window + + elseif isRecipeRecentSent == true and recipeMode == 0 then -- If recipe window/award tab was hit + chosenOperation, recipeMode = callClientFunction(player, "delegateCommand", craftJudge, "start", commandactor, -1, isRequested, unpack(materialSlots)); -- Keep window going + + elseif isRecipeRecentSent == true and recipeMode > 0 then -- If recipe item picked + if recipeDetail then + chosenOperation, recipeMode = callClientFunction(player, "delegateCommand", craftJudge, "start", commandactor, -2, isRequested, unpack(recipeDetail)); -- Item mat(s) for picked item. + else + chosenOperation, recipeMode = callClientFunction(player, "delegateCommand", craftJudge, "start", commandactor, -2, isRequested, 10009617,0,0,0,0,0,0,0); -- Show dummy info for unfilled item + end + end + + + if chosenOperation == MENU_CANCEL then + callClientFunction(player, "delegateCommand", craftJudge, "closeCraftStartWidget", commandactor); + + + elseif (chosenOperation == MENU_MAINHAND or chosenOperation == MENU_OFFHAND) then + + if isRequested == true then + recipeResult = callClientFunction(player, "delegateCommand", craftJudge, "selectRcp", commandactor, 10009617); + else + recipeResult = callClientFunction(player, "delegateCommand", craftJudge, "selectRcp", commandactor, 10009617,6071007,5030112,5030007,10009617,6071007,5030112,5030007); + end + + if recipeResult == 0 then -- Closed/Return hit. + callClientFunction(player, "delegateCommand", craftJudge, "closeCraftStartWidget", commandactor); + currentlyCrafting = -1; + + elseif (recipeResult >= 1 or recipeResult <= 8) then + --item yld, xstal1, qty, xstal2, qty + recipeConfirmed = callClientFunction(player, "delegateCommand", craftJudge, "confirmRcp", commandactor, 10009617, 1, 0xF4247, 1, 0xf4245, 1, 0, 0); + + if recipeConfirmed then + callClientFunction(player, "delegateCommand", craftJudge, "closeCraftStartWidget", commandactor); + isRecipeRecentSent = false; + isRecipeAwardSent = false; + currentlyCrafting = startCrafting(player, chosenOperation, isRequested, 80, 100, 50); + end + end + + elseif chosenOperation == MENU_REQUEST then -- Conditional button label based on isRequested + if isRequested == false then -- "Request Items" hit, close Start and open up the Quest select + callClientFunction(player, "delegateCommand", craftJudge, "closeCraftStartWidget", commandactor); + isRecipeRecentSent = false; + isRecipeAwardSent = false; + + local questConfirmed, returnedQuest = GetCraftQuest(player, craftjudge, commandactor); + chosenQuest = tonumber(returnedQuest); + + if debugMessage then player:SendMessage(0x20, "", "[DEBUG] Chosen Quest: "..tostring(chosenQuest)); end + + if questConfirmed then + isRequested = true; + end + + + elseif isRequested == true then -- "Normal Synthesis" button hit + isRequested = false; + chosenQuest = 0; + callClientFunction(player, "delegateCommand", craftJudge, "closeCraftStartWidget", commandactor); + + end + + elseif chosenOperation == MENU_RECIPE then -- "Recipes" button hit + if isRecipeRecentSent == false then + callClientFunction(player, "delegateCommand", craftJudge, "selectRcp", commandactor, unpack(recentRecipe)); -- Load up recipe list + isRecipeRecentSent = true; + end + + recipeDetail = materialRecipe[recentRecipe[recipeMode]]; + + elseif chosenOperation == MENU_AWARDED then -- "Awarded Recipes" tab hit + if isRecipeAwardSent == false then + callClientFunction(player, "delegateCommand", craftJudge, "selectRcp", commandactor, unpack(awardedRecipe)); -- Load up Award list + isRecipeAwardSent = true; + end + + recipeDetail = materialRecipe[awardedRecipe[recipeMode]]; + + elseif (chosenOperation == MENU_RECIPE_DETAILED or chosenOperation == MENU_AWARDED_DETAILED) and recipeMode > 0 then -- Pop-up for an item's stats/craft mats + detailWindowState = callClientFunction(player, "delegateCommand", craftJudge, "confirmRcp", commandactor, 10009617, 1, 0xF4247, 1, 0xf4245, 1, 0, 0); + + else + break; + end + end + + player:ChangeMusic(51); + player:ChangeState(0); + player:EndEvent(); + +end + + + +-- Handles the menus to pick a crafter quest or local leve quest that run separate widgets from the Start command. +-- Returns whether a quest was selected, and what id the quest is. +function GetCraftQuest(player, craftjudge, commandactor); + + local questOffset = 0xA0F00000; + local questId = 0; + local requestState = false; + local requestedMenuChoice = callClientFunction(player, "delegateCommand", craftJudge, "selectCraftQuest", commandactor); + + if requestedMenuChoice then + questId = requestedMenuChoice - questOffset; + + if isCraftQuest(questId) then + confirm = callClientFunction(player, "delegateCommand", craftJudge, "cfmQst", commandactor, questId, 20, 1, 1, 1, 0, 0, ""); + + if confirm == true then + requestState = true; + player:SendGameMessage(craftJudge, 21, 0x20); + end + + elseif isLocalLeve(questId) then + confirm = callClientFunction(player, "delegateCommand", craftJudge, "confirmLeve", commandactor, questId, 0, 8030421, 5, 50, 0, 0); + + if confirm == true then + requestState = true; + itemSlots = { unpack(materialRecipe[4070010])}; + end + + elseif isScenarioQuest(questId) == true then + -- TEMP for now. Cannot find source for what happens if you confirm a non-craft quest. + player:SendGameMessage(GetWorldMaster(), 40209, 0x20); + end + end + + return requestState, questId; +end + + +function isScenarioQuest(id) + + if (id >= 110001 and id <= 120026) then + return true; + else + return false; + end +end + + +function isCraftQuest(id) + if (id >= 110300 and id <= 110505) then + return true; + else + return false; + end +end + + +function isLocalLeve(id) + + if (id >= 120001 and id <= 120452) then + return true; + else + return false; + end +end + + +-- No real logic in this function. Just smoke and mirrors to 'see' the minigame in action at the minimum level. +function startCrafting(player, hand, quest, startDur, startQly, startHQ) + + local worldMaster = GetWorldMaster(); + local proggers = 0; + local attempts = 5; + local craftedCount = 0; + local craftTotal = 2; + local itemId = 10009617; + + player:ChangeState(30+hand); -- Craft kneeling w/ appropriate tool out + player:ChangeMusic(73); + callClientFunction(player, "delegateCommand", craftJudge, "openCraftProgressWidget", commandactor, startDur, startQly, startHQ); + + while true do + + local progDiff = math.random(25,25); + local duraDiff = math.random(1,3); + local qltyDiff = math.random(0,2); + + if proggers >= 100 then + + testChoice2 = callClientFunction(player, "delegateCommand", craftJudge, "updateInfo", commandactor, 100, 10, 20, 5020111, 69, 70, 75); + + testChoice = callClientFunction(player, "delegateCommand", craftJudge, "craftTuningUI", commandactor, 22503, 23033); + + player:SendGameMessage(GetWorldMaster(), 40111, 0x20, player, itemId, 3, 8); -- "You create <#3 quantity> <#1 item> <#2 quality>." + callClientFunction(player, "delegateCommand", craftJudge, "closeCraftProgressWidget", commandactor); + + if quest then + continueLeve = callClientFunction(player, "delegateCommand", craftJudge, "askContinueLocalLeve", 120001, itemId, craftedCount, craftTotal, attempts); + + if continueLeve == true then + proggers = 0; + callClientFunction(player, "delegateCommand", craftJudge, "openCraftProgressWidget", commandactor, startDur, startQly, startHQ); + else + break; + end + else + break; + end + end + + choice = callClientFunction(player, "delegateCommand", craftJudge, "craftCommandUI", commandactor, 29, 2, 29530,29531,29532,29533,29534); + --player:SendMessage(0x20, "", "[DEBUG] Command id selected: "..choice); + + + + if choice then + + if skillAnim[choice] then + player:PlayAnimation(skillAnim[choice]); + end + + wait(3); + + player:SendGameMessage(worldMaster, 40108, 0x20, choice,2); + + if choice ~= 29531 then + proggers = proggers + progDiff; + + if proggers >= 100 then + proggers = 100; + end + + startDur = startDur - duraDiff; + startQly = startQly + qltyDiff; + + player:SendGameMessage(worldMaster, 40102, 0x20, progDiff); + player:SendGameMessage(worldMaster, 40103, 0x20, duraDiff); + player:SendGameMessage(worldMaster, 40104, 0x20, qltyDiff); + end + --prg dur qly, ???, ???, ???, HQ + callClientFunction(player, "delegateCommand", craftJudge, "updateInfo", commandactor, proggers, startDur, startQly, nil, nil, nil, nil, nil); + + end + end + + return -1; +end + + diff --git a/Data/scripts/commands/DummyCommand.lua b/Data/scripts/commands/DummyCommand.lua index ca26f9ce..77d37df3 100644 --- a/Data/scripts/commands/DummyCommand.lua +++ b/Data/scripts/commands/DummyCommand.lua @@ -6,51 +6,406 @@ Operates the harvesting system for mining, logging, and fishing. Functions: -loadTextData(commandActor): Loads all gamesheets needed and instantiates a HarvestJudge. -targetCancel(commandActor): Cancels the player's target. -turnToTarget(commandActor, harvestType, direction): Turns to a direction (name's a lie, angle must be computed lol) -openInputWidget(commandActor, harvestType, nodeGrade): Inits the widget system (call first). -orderInputWidget(commandActor, nodeHP [max 100], ?, harvestType): Updates the node HP. -textInputWidget(commandActor, harvestType, ?, textId, ?, ?, ?): Sets the result text after a minigame is performed. -askInputWidget(commandActor, harvestType, inputPageNumber, showTutorial, showFishWait, showFishWaitAndJig, updateFishHP, showRareCatalystEffect): Gets user input after opening a ask widget. -closeInputWidget(commandActor, harvestType): Closes the widget system (call last). -rangeInputWidget(harvestType, inputPageNumber, goodMin, goodMax, bool): Unknown, currently crashing... +loadTextData() + Desc: Loads all gamesheets needed and instantiates a HarvestJudge. + Params: None + +targetCancel() + Desc: Cancels the player's target. + Params: None + +turnToTarget() + Desc: Turns to a direction + Params: * harvestType - Harvest command used. Client script has a _waitForTurning() for Quarry/Harvest/Spearfishing + * direction - The pi radian to turn the character towards, server has to calculate the vector between the actors. + +openInputWidget() + Desc: Inits the widget system (call first). + Params: * harvestType - Determines which text strings to load based on the harvestType + * nodeGrade - The grade of the node. Retail went up to grade 5. +orderInputWidget() + Desc: Updates the node HP. + Params: * nodeRemainder - Range goes from 0-100 + * unk1 - + * harvestType - Doesn't appear to visually do anything? Script checks against harvest command id + +textInputWidget() + Desc: Sets the result text after a minigame is performed. + Params: * harvestType - The harvest command + * unk1 - Actor to grab text from? Set to the harvestJudge so the rest of params function, otherwise widget prints whatever is set here. + * textId - Id from the harvestJudge sheet. + * textIdParam1 - Used to fill in textId details if the sheet requires it, Eg. textId #25 requires an itemId, HQ quality, and yield filled in. + * textIdParam2 + * textIdParam3 + * commandId - If textId = nil, client script sets it to 64 and this parameter is assigned to Param1 + - Why does this exist? Setting textId to 64 and using commandId as textIdParam1 does the same job. + +askInputWidget() + Desc: Gets user input after opening a ask widget. Returns two values, one being the id of the chosen command, and the "currentPower" of the minigame. + Params: * harvestType - The harvest command + * phase - The current minigame window to show. Valid ids 1 & 2. + * showTutorial - Shows Tutorial menu option in the window if not = 0. + * showFishWait - + * showFishWaitAndJig - + * updateFishHP - + * showRareCatalystEffect- + +closeInputWidget() + Desc: Closes the widget system (call last). + Params: * harvestType - The harvest command + +rangeInputWidget() + Desc: Unknown, currently errors the client... + Params: * harvestType + * phase + * goodMin + * goodMax + * bool + + Notes: - -HarvestType Ids: - -20002: Mine -20003: Log -20004: Fish - + * Aim = Where on the aim gauge the player chose. + * Remainder = How many attempts you get on the section portion of the minigame + * Sweetspot = Where you hit on the second portion of the minigame --]] +minerAnim = {0x14001000, 0x14002000, 0x14003000}; + +--[[ Mooglebox - Aim ++5 +4 +3 +2 +1 0 -1 -2 -3 -4 -5 + 0 10 20 30 40 50 60 70 80 90 100 + +Sweetspots 1=10 2=30 3=70 4=100 for Mining +Remainder A=40 B=60 C=70 D=80 +--]] + + +harvestNodeContainer = { -- nodeGrade, harvestAttempts, #ofItemsBecauseICantIntoIpairs, Item1, Item2, etc + [1001] = {2, 2, 3, 1, 2, 3}, + [1002] = {2, 4, 5, 3005, 3003, 3002, 3001, 3004} +} + +harvestNodeItems = { + --itemId, remainder, aim, sweetspot, max yield + [1] = {10009104, 70, 30, 30, 4}, -- Rock Salt + [2] = {10006001, 80, 10, 30, 4}, -- Bone Chip + [3] = {10001006, 80, 20, 30, 3}, -- Copper Ore + [3001] = {10001003, 80, 50, 30, 3}, + [3002] = {10001006, 70, 70, 10, 4}, + [3003] = {10001005, 80, 90, 70, 1}, + [3004] = {10009104, 40, 10, 100, 2}, + [3005] = {10001007, 40, 0, 30, 1} + +} + + require ("global") -function onEventStarted(player, commandactor, triggerName, arg1, arg2, arg3, arg4, checkedActorId) +function onEventStarted(player, commandActor, triggerName, arg1, arg2, arg3, arg4, checkedActorId) - harvestJudge = GetStaticActor("HarvestJudge"); - callClientFunction(player, "delegateCommand", harvestJudge, "loadTextData", commandactor); - callClientFunction(player, "delegateCommand", harvestJudge, "targetCancel", commandactor); - callClientFunction(player, "delegateCommand", harvestJudge, "turnToTarget", commandactor, 0x55F2, 2); + debugMsg = false; + + powerCurrent = 0; + powerLast = 0; + powerRange = 10; -- 'Feels' look a good amount compared to vids/ARR's minigame. + + showTutorial = 0; + + commandMine = 22002; + commandLog = 22003; + commandFish = 22004; + + harvestNodeId = 1001; -- What the server should send eventually + harvestNode = BuildHarvestNode(player, harvestNodeId); -- [1-11] = {itemId, remainder, sweetspot, maxYield} + harvestGrade = harvestNodeContainer[harvestNodeId][1] or 0; + harvestAttempts = harvestNodeContainer[harvestNodeId][2] or 0; + nodeRemainder = 0; + + + + harvestType = commandMine; + + worldMaster = GetWorldMaster(); + harvestJudge = GetStaticActor("HarvestJudge"); + callClientFunction(player, "delegateCommand", harvestJudge, "loadTextData", commandActor); + --callClientFunction(player, "delegateCommand", harvestJudge, "targetCancel", commandActor); + --callClientFunction(player, "delegateCommand", harvestJudge, "turnToTarget", commandActor, harvestType, nodeGrade); + + player:ChangeState(50); - player:ChangeState(50); - - callClientFunction(player, "delegateCommand", harvestJudge, "openInputWidget", commandactor, 0x55F2, 2); - callClientFunction(player, "delegateCommand", harvestJudge, "orderInputWidget", commandactor, 3, false, 0x55f2); - callClientFunction(player, "delegateCommand", harvestJudge, "textInputWidget", commandactor, 0x55f2, harvestJudge, nil, nil, nil, nil, 0); - callClientFunction(player, "delegateCommand", harvestJudge, "askInputWidget", commandactor, 0x55f2, 1, 0, false, false, nil, false); - - callClientFunction(player, "delegateCommand", harvestJudge, "textInputWidget", commandactor, 0x55f2, harvestJudge, 60, nil, nil, nil, 0); - callClientFunction(player, "delegateCommand", harvestJudge, "askInputWidget", commandactor, 0x55f2, 2, 0, false, false, nil, false); - - callClientFunction(player, "delegateCommand", harvestJudge, "textInputWidget", commandactor, 0x55f2, harvestJudge, 46,0, 0, 0, 0); - callClientFunction(player, "delegateCommand", harvestJudge, "askInputWidget", commandactor, 0x55f2, 2, 0, false, false, nil, false); - - - player:ChangeState(0); + + + if harvestType == commandMine then + player:SendGameMessage(harvestJudge, 26, MESSAGE_TYPE_SYSTEM, 1, harvestGrade); + + callClientFunction(player, "delegateCommand", harvestJudge, "openInputWidget", commandActor, harvestType, harvestGrade); + callClientFunction(player, "delegateCommand", harvestJudge, "orderInputWidget", commandActor, nodeRemainder, nil, harvestType); + callClientFunction(player, "delegateCommand", harvestJudge, "textInputWidget", commandActor, harvestType, harvestJudge, nil, 0, 0, 0, 0); + + + + while harvestAttempts > 0 do + + -- "Aim", 0 = Top of bar, 100 = Bottom. + menuResult, sliderPhase, unk3 = callClientFunction(player, "delegateCommand", harvestJudge, "askInputWidget", commandActor, harvestType, 1, showTutorial, false, false, nil, false); + if debugMsg then player:SendMessage(0x20, "", "menuResult: "..tostring(menuResult).." sliderPhase: "..tostring(sliderPhase).." Unk: "..tostring(unk3)); end + + if menuResult == 22701 then -- Begin. + + local aimSlot = (sliderPhase/10)+1; -- Thanks LUA index = 1 + + local nodeDetails = harvestNode[aimSlot]; + local nodeItem = nodeDetails[1]; + local nodeRemainder = nodeDetails[2]; + local nodeSweetspot = nodeDetails[3]; + local nodeYield = nodeDetails[4]; + local isFirstSwing = true; + + local sweetspotDifference; + local sweetspotDifferencePrevious; + + if debugMsg then + player:SendMessage(0x20, "", "aimSlot: "..(aimSlot).." itemId:"..tostring(nodeDetails[1]).." remainder: "..tostring(nodeDetails[2])); + end + + + player:SendGameMessage(harvestJudge, 36, MESSAGE_TYPE_SYSTEM); -- "You set your sights on an area." + + + + callClientFunction(player, "delegateCommand", harvestJudge, "orderInputWidget", commandActor, nodeRemainder, nil, harvestType); + + while true do + callClientFunction(player, "delegateCommand", harvestJudge, "textInputWidget", commandActor, harvestType, harvestJudge, nil, 0, 0, 0, 0); + + -- "Strike" 0 = Empty, 100 = Filled. Mooglebox sweespots are 1=10, 2=30, 3=70, 4=100 for Mining + chosenCommand, powerCurrent = callClientFunction(player, "delegateCommand", harvestJudge, "askInputWidget", commandActor, harvestType, 2, showTutorial, false, false, nil, false); -- Strike + + if debugMsg then player:SendMessage(0x20, "", tostring(chosenCommand).." Power: "..tostring(powerCurrent)); end + + + if chosenCommand == 22702 then -- Cancel. + harvestAttempts = harvestAttempts - 1; + + if harvestAttempts > 0 then + -- You can make # more gathering attempts. + player:SendGameMessage(player, worldMaster, 40344, 0x20, harvestAttempts); + else + -- There is nothing left to gather at this location. + player:SendGameMessage(player, worldMaster, 40339, 0x20, harvestAttempts); + end + break; + + elseif chosenCommand == 22703 then -- Strike. + + + nodeRemainder = nodeRemainder - 20; + if nodeRemainder < 0 then + nodeRemainder = 0; + end + + callClientFunction(player, "delegateCommand", harvestJudge, "textInputWidget", commandActor, harvestType, harvestJudge, nil, 0, 0, 0, 0); + + player:PlayAnimation(minerAnim[math.random(1,3)]); + wait(2); + sweetspotDifference = math.abs(powerCurrent - nodeSweetspot); + + + if powerRange >= sweetspotDifference then + callClientFunction(player, "delegateCommand", harvestJudge, "orderInputWidget", commandActor, nodeRemainder, false, harvestType); + + -- "You obtain " + callClientFunction(player, "delegateCommand", harvestJudge, "textInputWidget", commandActor, harvestType, harvestJudge, 25, nodeItem, 0, nodeYield, 0); + + player:SendGameMessage(player, worldMaster, 40301, MESSAGE_TYPE_SYSTEM, player, nodeItem, nodeYield); -- TODO: Refer to caps to see wtf is going on here + + + HarvestReward(player, nodeItem, nodeYield); + nodeRemainder = 0; + else + if isFirstSwing then + if sweetspotDifference < 19 then -- TODO: TWEAK THESE, likely need to be larger + callClientFunction(player, "delegateCommand", harvestJudge, "textInputWidget", commandActor, harvestType, harvestJudge, 45); + player:SendGameMessage(harvestJudge, 45, MESSAGE_TYPE_SYSTEM); -- "You feel something promising." + elseif sweetspotDifference > 20 then + callClientFunction(player, "delegateCommand", harvestJudge, "textInputWidget", commandActor, harvestType, harvestJudge, 42); + player:SendGameMessage(harvestJudge, 42, MESSAGE_TYPE_SYSTEM); -- "You feel nothing promising." + end + else + if sweetspotDifference > sweetspotDifferencePrevious then + callClientFunction(player, "delegateCommand", harvestJudge, "textInputWidget", commandActor, harvestType, harvestJudge, 43); + player:SendGameMessage(harvestJudge, 43, MESSAGE_TYPE_SYSTEM); -- "You are getting farther from the mark." + + elseif sweetspotDifference < sweetspotDifferencePrevious then + callClientFunction(player, "delegateCommand", harvestJudge, "textInputWidget", commandActor, harvestType, harvestJudge, 44); + player:SendGameMessage(harvestJudge, 44, MESSAGE_TYPE_SYSTEM); -- "You are getting closer to the mark." + else + callClientFunction(player, "delegateCommand", harvestJudge, "textInputWidget", commandActor, harvestType, harvestJudge, 42); + player:SendGameMessage(harvestJudge, 42, MESSAGE_TYPE_SYSTEM); -- "You feel nothing promising." + end + end + end + + if not isFirstSwing then + powerLast = powerCurrent; + end; + + callClientFunction(player, "delegateCommand", harvestJudge, "orderInputWidget", commandActor, nodeRemainder, false, harvestType); + + + if nodeRemainder == 0 then + harvestAttempts = harvestAttempts - 1; + + if harvestAttempts > 0 then + -- You can make # more gathering attempts. + player:SendGameMessage(player, worldMaster, 40344, 0x20, harvestAttempts); + else + -- There is nothing left to gather at this location. + player:ChangeMusic(101); + player:SendGameMessage(player, worldMaster, 40339, 0x20, harvestAttempts); + end + + wait(2); + break; + end + + + if isFirstSwing and debugMsg then player:SendMessage(0x20, "", "First swing"); end + + isFirstSwing = false; + sweetspotDifferencePrevious = sweetspotDifference; + + elseif chosenCommand == 22710 then -- "Strike" Tutorial. + SendTutorial(player, harvestJudge, 2); + end + + end + + elseif menuResult == 22702 then -- Cancel. + break; + elseif menuResult == 22710 then -- "Aim" Tutorial. + SendTutorial(player, harvestJudge, 1); + end + end + + elseif harvestType == commandLog then + + elseif harvestType == commandFish then + + end + + player:SendGameMessage(harvestJudge, 31, MESSAGE_TYPE_SYSTEM); + + + if harvestAttempts == 0 then + player:SendGameMessage(player, worldMaster, 40310, 0x20); -- "The deposit has been exhausted." + --TO:DO Despawn node + whatever logic to respawn an exsiting expired node in the area. + end + + callClientFunction(player, "delegateCommand", harvestJudge, "closeInputWidget", commandActor, harvestType); + + player:ChangeState(0); player:EndEvent(); end + + + +-- Returns a table in the following format: nodeTable = { [1-11] = {itemId, remainder, sweetspot, maxYield} } +function BuildHarvestNode(player, sentNode) + + if harvestNodeContainer[sentNode] then + local node = harvestNodeContainer[sentNode]; + local nodeTable = {}; + local nodeItems = {}; + local nodeItemCount = node[3]; + + local grade = node[1]; + local attempts = node[2]; + + + -- Load up nodeItems[] with the harvestNodeItems{} key and Aim point + for i=1, nodeItemCount do + local nodeItemKey = node[3+i]; + local item = harvestNodeItems[ node[3+i] ] + + nodeItems[i] = { nodeItemKey, ((item[3] / 10)+1) }; + + if debugMsg then player:SendMessage(0x20, "", "nodeItems: "..nodeItems[i][1].." "..nodeItems[i][2]); end + end + + -- Iterate through the 11 Aim spots + for i=1,11,1 do + local hasItem = false; + + -- See if there's a nodeItems[] that has an Aim spot that matches the current loop + -- TODO: Just set nodeItems[] keys to the actual slots to skip this loop inside a loop + for j=1, nodeItemCount do + if nodeItems[j][2] == i then + hasItem = j; + break; + end + end + + if hasItem then + local item = harvestNodeItems[ nodeItems[hasItem][1] ]; + + -- Assign itemId, remainder, sweetspot, yield to this slot + nodeTable[i] = {item[1], item[2], item[4], item[5] }; + + if debugMsg then + player:SendMessage(0x20, "", "nodeTable: "..i.." "..nodeTable[i][1].." "..nodeTable[i][2].." "..nodeTable[i][3].." "..nodeTable[i][3]); + end + + else + nodeTable[i] = {0,0,0,0}; + if debugMsg then player:SendMessage(0x20, "", "nodeTable: "..i); end + end + end + + return nodeTable + end + +end + + + +function SendTutorial(player, harvestJudge, id) + + if id == 1 then + player:SendGameMessage(harvestJudge, 1, MESSAGE_TYPE_SYSTEM); + wait(3); + player:SendGameMessage(harvestJudge, 4, MESSAGE_TYPE_SYSTEM); + elseif id == 2 then + player:SendGameMessage(harvestJudge, 7, MESSAGE_TYPE_SYSTEM); + wait(3); + player:SendGameMessage(harvestJudge, 10, MESSAGE_TYPE_SYSTEM); + wait(3); + player:SendGameMessage(harvestJudge, 13, MESSAGE_TYPE_SYSTEM); + wait(3); + player:SendGameMessage(harvestJudge, 16, MESSAGE_TYPE_SYSTEM); + end + +end + +function HarvestReward(player, item, qty) -- Really should get a helper function for this + + local worldMaster = GetWorldMaster(); + local location = INVENTORY_NORMAL; + local invCheck = player:getItemPackage(location):addItem(item, qty, 1); + + if (invCheck == INV_ERROR_FULL) then + -- Your inventory is full. + player:SendGameMessage(player, worldMaster, 60022, MESSAGE_TYPE_SYSTEM_ERROR); + 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_ERROR, item, 1); + elseif (invCheck == INV_ERROR_SYSTEM_ERROR) then + player:SendMessage(MESSAGE_TYPE_SYSTEM_ERROR, "", "[DEBUG] Server Error on adding item."); + elseif (invCheck == INV_ERROR_SUCCESS) then + --player:SendMessage(MESSAGE_TYPE_SYSTEM, "", message); + player:SendGameMessage(player, worldMaster, 25246, MESSAGE_TYPE_SYSTEM, item, qty); + end +end \ No newline at end of file diff --git a/Data/scripts/unique/sea0Town01a/PopulaceShopSalesman/jossy.lua b/Data/scripts/unique/sea0Town01a/PopulaceShopSalesman/jossy.lua deleted file mode 100644 index b0781436..00000000 --- a/Data/scripts/unique/sea0Town01a/PopulaceShopSalesman/jossy.lua +++ /dev/null @@ -1,6 +0,0 @@ - -shopInfo = { -welcomeText = 94, -shopPack = 0x67, -shopCurrancy = nil -} \ No newline at end of file diff --git a/Data/scripts/unique/wil0Town01a/PopulaceShopSalesman/jemimi.lua b/Data/scripts/unique/wil0Town01a/PopulaceShopSalesman/jemimi.lua deleted file mode 100644 index ba2cb149..00000000 --- a/Data/scripts/unique/wil0Town01a/PopulaceShopSalesman/jemimi.lua +++ /dev/null @@ -1,6 +0,0 @@ - -shopInfo = { -welcomeText = 69, -shopPack = 3020, -tutorialId = 35 -} \ No newline at end of file diff --git a/Data/scripts/unique/wil0Town01a/PopulaceShopSalesman/norbettaux.lua b/Data/scripts/unique/wil0Town01a/PopulaceShopSalesman/norbettaux.lua deleted file mode 100644 index 50d75a8f..00000000 --- a/Data/scripts/unique/wil0Town01a/PopulaceShopSalesman/norbettaux.lua +++ /dev/null @@ -1,6 +0,0 @@ - -shopInfo = { -welcomeText = 64, -shopPack = 3021, -tutorialId = 34 -} \ No newline at end of file diff --git a/Data/scripts/unique/wil0Town01a/PopulaceShopSalesman/nortmoen.lua b/Data/scripts/unique/wil0Town01a/PopulaceShopSalesman/nortmoen.lua deleted file mode 100644 index 118e0824..00000000 --- a/Data/scripts/unique/wil0Town01a/PopulaceShopSalesman/nortmoen.lua +++ /dev/null @@ -1,6 +0,0 @@ - -shopInfo = { -welcomeText = 76, -shopPack = 3022, -tutorialId = 39 -} \ No newline at end of file diff --git a/Data/scripts/unique/wil0Town01a/PopulaceShopSalesman/pamisolaux.lua b/Data/scripts/unique/wil0Town01a/PopulaceShopSalesman/pamisolaux.lua deleted file mode 100644 index eac22408..00000000 --- a/Data/scripts/unique/wil0Town01a/PopulaceShopSalesman/pamisolaux.lua +++ /dev/null @@ -1,6 +0,0 @@ - -shopInfo = { -welcomeText = 54, -shopPack = 3019, -tutorialId = 32 -} \ No newline at end of file diff --git a/Data/scripts/unique/wil0Town01a/PopulaceShopSalesman/waeksatz.lua b/Data/scripts/unique/wil0Town01a/PopulaceShopSalesman/waeksatz.lua deleted file mode 100644 index d83094e0..00000000 --- a/Data/scripts/unique/wil0Town01a/PopulaceShopSalesman/waeksatz.lua +++ /dev/null @@ -1,5 +0,0 @@ - -shopInfo = { -welcomeText = 265, -shopPack = 3024 -} \ No newline at end of file diff --git a/Data/scripts/unique/wil0Town01a/PopulaceShopSalesman/wnhalki.lua b/Data/scripts/unique/wil0Town01a/PopulaceShopSalesman/wnhalki.lua deleted file mode 100644 index a5842c11..00000000 --- a/Data/scripts/unique/wil0Town01a/PopulaceShopSalesman/wnhalki.lua +++ /dev/null @@ -1,5 +0,0 @@ - -shopInfo = { -welcomeText = 111, -shopPack = 3003 -} \ No newline at end of file diff --git a/Data/scripts/unique/wil0Town01a/PopulaceShopSalesman/zagylswerd.lua b/Data/scripts/unique/wil0Town01a/PopulaceShopSalesman/zagylswerd.lua deleted file mode 100644 index f03d0eb1..00000000 --- a/Data/scripts/unique/wil0Town01a/PopulaceShopSalesman/zagylswerd.lua +++ /dev/null @@ -1,5 +0,0 @@ - -shopInfo = { -welcomeText = 110, -shopPack = 3002 -} \ No newline at end of file diff --git a/Map Server/Actors/EventList.cs b/Map Server/Actors/EventList.cs index 041ee53f..e654f779 100644 --- a/Map Server/Actors/EventList.cs +++ b/Map Server/Actors/EventList.cs @@ -79,8 +79,10 @@ namespace Meteor.Map.actors public class PushBoxEventCondition { + public uint bgObj; + public uint layout; public string conditionName = ""; - public float size = 30.0f; + public string reactName = ""; public bool outwards = false; public bool silent = true; } diff --git a/Map Server/Packets/Send/Actor/Events/SetPushEventConditionWithTriggerBox.cs b/Map Server/Packets/Send/Actor/Events/SetPushEventConditionWithTriggerBox.cs index 96b07236..f0644d21 100644 --- a/Map Server/Packets/Send/Actor/Events/SetPushEventConditionWithTriggerBox.cs +++ b/Map Server/Packets/Send/Actor/Events/SetPushEventConditionWithTriggerBox.cs @@ -26,7 +26,7 @@ using System.Text; using Meteor.Common; -namespace Meteor.Map.packets.send.actor.events +namespace Meteor.Map.packets.send.actor.events { class SetPushEventConditionWithTriggerBox { @@ -41,18 +41,20 @@ namespace Meteor.Map.packets.send.actor.events { using (BinaryWriter binWriter = new BinaryWriter(mem)) { - binWriter.Write((UInt32)condition.size); - binWriter.Write((UInt32)0x1A5); - binWriter.Write((UInt32)4); - binWriter.Seek(8, SeekOrigin.Current); + binWriter.Write((UInt32)condition.bgObj); // bgObj + binWriter.Write((UInt32)condition.layout); // Layout + binWriter.Write((UInt32)4); // Actor? Always 4 in 1.23 + binWriter.Seek(8, SeekOrigin.Current); // Unknowns binWriter.Write((Byte)(condition.outwards ? 0x11 : 0x0)); //If == 0x10, Inverted Bounding Box binWriter.Write((Byte)3); binWriter.Write((Byte)(condition.silent ? 0x1 : 0x0)); //Silent Trigger; - binWriter.Write(Encoding.ASCII.GetBytes(condition.conditionName), 0, Encoding.ASCII.GetByteCount(condition.conditionName) >= 0x24 ? 0x24 : Encoding.ASCII.GetByteCount(condition.conditionName)); + binWriter.Write(Encoding.ASCII.GetBytes(condition.conditionName), 0, Encoding.ASCII.GetByteCount(condition.conditionName) >= 0x20 ? 0x20 : Encoding.ASCII.GetByteCount(condition.conditionName)); + binWriter.Seek(55, SeekOrigin.Begin); + binWriter.Write((Byte)0); // Unknown + binWriter.Write(Encoding.ASCII.GetBytes(condition.reactName), 0, Encoding.ASCII.GetByteCount(condition.reactName) >= 0x04 ? 0x04 : Encoding.ASCII.GetByteCount(condition.reactName)); } } - return new SubPacket(OPCODE, sourceActorId, data); } } -} +} \ No newline at end of file From bbf49123b63d2dbabb2318090340e7c44e597376 Mon Sep 17 00:00:00 2001 From: CuriousJorge Date: Fri, 25 Sep 2020 18:23:09 -0400 Subject: [PATCH 3/4] Follow-up to prior commit with script changes I forgot to commit. --- .../base/chara/npc/object/MarketEntrance.lua | 7 +++--- Data/scripts/commands/CraftCommand.lua | 24 ++++++++++--------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/Data/scripts/base/chara/npc/object/MarketEntrance.lua b/Data/scripts/base/chara/npc/object/MarketEntrance.lua index d09309cd..e157a777 100644 --- a/Data/scripts/base/chara/npc/object/MarketEntrance.lua +++ b/Data/scripts/base/chara/npc/object/MarketEntrance.lua @@ -22,17 +22,18 @@ eventPushStepPrvMarket( MarketEntrance City TriggerBox details -Limsa - !warp 230 -416.5 40 446 +Limsa - !warp 230 -416.5 40 446 ActorClass Id = 1090238 bgObj Id - [0xB3B] 2875 Layout Id - [0x79 ] 121 (0x29d90001) Condition - in reactName - dwti - Not a typo compared to the other cities -Gridania - !warp 206 -192.57 23.48 -1407.58 +Gridania - !warp 206 -192.57 23.48 -1407.58 ActorClass Id = 1090264 + bgObj Id - [0xCFA] 3322 Layout Id - [0x141] 321 (0x29b00001) Condition - in reactName - dtwi -Ul'dah - !warp 175 -235 189 50.5 +Ul'dah - !warp 175 -235 189 50.5 ActorClass Id = 1500394 bgObj Id - [0x102F] 4143 Layout Id - [0x1A5] 421 (0x615a0001) Condition - in diff --git a/Data/scripts/commands/CraftCommand.lua b/Data/scripts/commands/CraftCommand.lua index 05b87286..fba7fef5 100644 --- a/Data/scripts/commands/CraftCommand.lua +++ b/Data/scripts/commands/CraftCommand.lua @@ -79,7 +79,7 @@ craftCommandUI(classID, hasWait, command1, command2, command3, command4, command * command1-5 - Five possible crafting commands (crafting skills). craftTuningUI(command1, command2, command3, command4, command5, command6, command7, command8) - Desc: Displays a full list of commands for the legacy "Tuning" phase that happens after crafting. Deprecated in 1.23b. + Desc: Displays only the provided commands for the "Double Down" phase that happens after crafting. Params: * command1-8 - The list of commands available. updateInfo(progress, durability, quality, tuningItem, tuningItemQuality, tuningItemQuantity, hqChance) @@ -293,7 +293,7 @@ function onEventStarted(player, commandactor, triggerName, arg1, arg2, arg3, arg end end - player:ChangeMusic(51); + player:ChangeMusic(7); -- Need way to reset music back to the zone's default player:ChangeState(0); player:EndEvent(); @@ -372,7 +372,7 @@ end function startCrafting(player, hand, quest, startDur, startQly, startHQ) local worldMaster = GetWorldMaster(); - local proggers = 0; + local craftProg = 0; local attempts = 5; local craftedCount = 0; local craftTotal = 2; @@ -388,11 +388,13 @@ function startCrafting(player, hand, quest, startDur, startQly, startHQ) local duraDiff = math.random(1,3); local qltyDiff = math.random(0,2); - if proggers >= 100 then + if craftProg >= 100 then testChoice2 = callClientFunction(player, "delegateCommand", craftJudge, "updateInfo", commandactor, 100, 10, 20, 5020111, 69, 70, 75); - - testChoice = callClientFunction(player, "delegateCommand", craftJudge, "craftTuningUI", commandactor, 22503, 23033); + + -- From Lodestone: If the HQ odds are 1% or better, players will have the option of selecting either Finish or Double Down. + -- By electing to double down, the player takes a chance on creating an HQ item at the risk of losing the completed item if the attempt fails + testChoice = callClientFunction(player, "delegateCommand", craftJudge, "craftTuningUI", commandactor, 22503, 22504); player:SendGameMessage(GetWorldMaster(), 40111, 0x20, player, itemId, 3, 8); -- "You create <#3 quantity> <#1 item> <#2 quality>." callClientFunction(player, "delegateCommand", craftJudge, "closeCraftProgressWidget", commandactor); @@ -401,7 +403,7 @@ function startCrafting(player, hand, quest, startDur, startQly, startHQ) continueLeve = callClientFunction(player, "delegateCommand", craftJudge, "askContinueLocalLeve", 120001, itemId, craftedCount, craftTotal, attempts); if continueLeve == true then - proggers = 0; + craftProg = 0; callClientFunction(player, "delegateCommand", craftJudge, "openCraftProgressWidget", commandactor, startDur, startQly, startHQ); else break; @@ -427,10 +429,10 @@ function startCrafting(player, hand, quest, startDur, startQly, startHQ) player:SendGameMessage(worldMaster, 40108, 0x20, choice,2); if choice ~= 29531 then - proggers = proggers + progDiff; + craftProg = craftProg + progDiff; - if proggers >= 100 then - proggers = 100; + if craftProg >= 100 then + craftProg = 100; end startDur = startDur - duraDiff; @@ -441,7 +443,7 @@ function startCrafting(player, hand, quest, startDur, startQly, startHQ) player:SendGameMessage(worldMaster, 40104, 0x20, qltyDiff); end --prg dur qly, ???, ???, ???, HQ - callClientFunction(player, "delegateCommand", craftJudge, "updateInfo", commandactor, proggers, startDur, startQly, nil, nil, nil, nil, nil); + callClientFunction(player, "delegateCommand", craftJudge, "updateInfo", commandactor, craftProg, startDur, startQly, nil, nil, nil, nil, nil); end end From df49eefadbf6825413fa9c3b4fbcf1712cc952c7 Mon Sep 17 00:00:00 2001 From: Filip Maj Date: Tue, 23 Feb 2021 15:39:46 -0500 Subject: [PATCH 4/4] Added recipe resolver --- Data/sql/gamedata_recipes.sql | 51 +++++++++++++ Map Server/DataObjects/Recipe.cs | 24 ++++++ Map Server/DataObjects/RecipeResolver.cs | 69 +++++++++++++++++ Map Server/Database.cs | 97 +++++++++++++++++++++++- Map Server/Lua/LuaEngine.cs | 2 + Map Server/Map Server.csproj | 2 + 6 files changed, 244 insertions(+), 1 deletion(-) create mode 100644 Data/sql/gamedata_recipes.sql create mode 100644 Map Server/DataObjects/Recipe.cs create mode 100644 Map Server/DataObjects/RecipeResolver.cs diff --git a/Data/sql/gamedata_recipes.sql b/Data/sql/gamedata_recipes.sql new file mode 100644 index 00000000..4af0035f --- /dev/null +++ b/Data/sql/gamedata_recipes.sql @@ -0,0 +1,51 @@ +-- -------------------------------------------------------- +-- Host: 127.0.0.1 +-- Server version: 5.6.17 - MySQL Community Server (GPL) +-- Server OS: Win64 +-- HeidiSQL Version: 10.1.0.5464 +-- -------------------------------------------------------- + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET NAMES utf8 */; +/*!50503 SET NAMES utf8mb4 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; + + +-- Dumping database structure for ffxiv_server +CREATE DATABASE IF NOT EXISTS `ffxiv_server` /*!40100 DEFAULT CHARACTER SET latin1 */; +USE `ffxiv_server`; + +-- Dumping structure for table ffxiv_server.gamedata_recipes +CREATE TABLE IF NOT EXISTS `gamedata_recipes` ( + `id` int(4) NOT NULL AUTO_INCREMENT, + `craftedItem` int(11) NOT NULL, + `craftedQuantity` int(11) NOT NULL, + `job` char(4) NOT NULL COMMENT 'A=CRP,B=BSM,C=ARM,D=GSM,E=LTW,F=WVR,G=ALC,H=CUL', + `level` tinyint(1) NOT NULL, + `dated` tinyint(1) DEFAULT NULL, + `kind` varchar(2) NOT NULL COMMENT 'AA=Material,BB=Parts,CC=Finished', + `crystal0ID` int(11) NOT NULL DEFAULT '0', + `crystal0Quantity` int(11) NOT NULL DEFAULT '0', + `crystal1ID` int(11) NOT NULL DEFAULT '0', + `crystal1Quantity` int(11) NOT NULL DEFAULT '0', + `facilities` int(11) DEFAULT NULL, + `material0` int(11) NOT NULL DEFAULT '0', + `material1` int(11) NOT NULL DEFAULT '0', + `material2` int(11) NOT NULL DEFAULT '0', + `material3` int(11) NOT NULL DEFAULT '0', + `material4` int(11) NOT NULL DEFAULT '0', + `material5` int(11) NOT NULL DEFAULT '0', + `material6` int(11) NOT NULL DEFAULT '0', + `material7` int(11) NOT NULL DEFAULT '0', + `subSkill0Job` int(11) DEFAULT NULL, + `subSkill0Level` varchar(5) DEFAULT NULL, + `subSkill1Job` int(11) DEFAULT NULL, + `subSkill1Level` varchar(5) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC; + +-- Data exporting was unselected. +/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */; +/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; diff --git a/Map Server/DataObjects/Recipe.cs b/Map Server/DataObjects/Recipe.cs new file mode 100644 index 00000000..67d3474a --- /dev/null +++ b/Map Server/DataObjects/Recipe.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Meteor.Map.DataObjects +{ + class Recipe + { + public readonly uint resultItemID; + public readonly uint resultQuantity; + public readonly byte[] allowedCrafters; + public readonly byte tier; + + public Recipe(uint resultItemID, uint resultQuantity, byte[] allowedCrafters, byte tier) + { + this.resultItemID = resultItemID; + this.resultQuantity = resultQuantity; + this.allowedCrafters = allowedCrafters; + this.tier = tier; + } + } +} diff --git a/Map Server/DataObjects/RecipeResolver.cs b/Map Server/DataObjects/RecipeResolver.cs new file mode 100644 index 00000000..ed8a42f4 --- /dev/null +++ b/Map Server/DataObjects/RecipeResolver.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using System.Security.Cryptography; + +namespace Meteor.Map.DataObjects +{ + class RecipeResolver + { + Dictionary recipeList; + Dictionary> matsToRecipes; + + private RecipeResolver(Dictionary recipeList, Dictionary> matsToRecipes) + { + this.recipeList = recipeList; + this.matsToRecipes = matsToRecipes; + } + + public static RecipeResolver Init() + { + var recipeList = new Dictionary(); + var matToRecipes = new Dictionary>(); + + Database.GetRecipeGamedata(recipeList, matToRecipes); + + return new RecipeResolver(recipeList, matToRecipes); + } + + public List GetRecipeFromMats(uint mat1 = 0, uint mat2 = 0, uint mat3 = 0, uint mat4 = 0, uint mat5 = 0, uint mat6 = 0, uint mat7 = 0, uint mat8 = 0) + { + uint[] mats = new uint[8]; + mats[0] = mat1; + mats[1] = mat2; + mats[2] = mat3; + mats[3] = mat4; + mats[4] = mat5; + mats[5] = mat6; + mats[6] = mat7; + mats[7] = mat8; + + Array.Sort(mats); + + byte[] result = new byte[8 * sizeof(int)]; + Buffer.BlockCopy(mats, 0, result, 0, result.Length); + string hash; + using (MD5 md5 = MD5.Create()) + { + hash = BitConverter.ToString(md5.ComputeHash(result)); + } + + if (matsToRecipes.ContainsKey(hash)) + return matsToRecipes[hash]; + else + return null; + } + + public Recipe GetMatsForRecipe(uint recipeID) + { + if (recipeList.ContainsKey(recipeID)) + return recipeList[recipeID]; + else + return null; + } + + public int GetNumRecipes() + { + return recipeList.Count; + } + } +} diff --git a/Map Server/Database.cs b/Map Server/Database.cs index 75508b70..5e571deb 100644 --- a/Map Server/Database.cs +++ b/Map Server/Database.cs @@ -33,6 +33,8 @@ using Meteor.Map.packets.receive.supportdesk; using Meteor.Map.actors.chara.npc; using Meteor.Map.actors.chara.ai; using Meteor.Map.packets.send.actor.battle; +using Meteor.Map.DataObjects; +using System.Security.Cryptography; namespace Meteor.Map { @@ -168,6 +170,99 @@ namespace Meteor.Map } } + public static bool GetRecipeGamedata(Dictionary recipeList, Dictionary> matToRecipe) + { + using (var conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD))) + { + try + { + conn.Open(); + + string query = @" + SELECT + id, + craftedItem, + craftedQuantity, + + crystal0ID, + crystal0Quantity, + crystal1ID, + crystal1Quantity, + + material0, + material1, + material2, + material3, + material4, + material5, + material6, + material7 + FROM gamedata_recipes + ORDER BY craftedItem ASC + "; + + MySqlCommand cmd = new MySqlCommand(query, conn); + + using (MySqlDataReader reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + uint recipeID = reader.GetUInt32("id"); + + uint craftedItem = reader.GetUInt32("craftedItem"); + uint craftedQuantity = reader.GetUInt32("craftedQuantity"); + + uint crystal0ID = reader.GetUInt32("crystal0ID"); + uint crystal0Quantity = reader.GetUInt32("crystal0Quantity"); + uint crystal1ID = reader.GetUInt32("crystal1ID"); + uint crystal1Quantity = reader.GetUInt32("crystal1Quantity"); + + uint[] mats = new uint[8]; + mats[0] = reader.GetUInt32("material0"); + mats[1] = reader.GetUInt32("material1"); + mats[2] = reader.GetUInt32("material2"); + mats[3] = reader.GetUInt32("material3"); + mats[4] = reader.GetUInt32("material4"); + mats[5] = reader.GetUInt32("material5"); + mats[6] = reader.GetUInt32("material6"); + mats[7] = reader.GetUInt32("material7"); + + Array.Sort(mats); + + Recipe recipe = new Recipe(craftedItem, craftedQuantity, new byte[] { }, 1); + + //Hash for the Mat -> Recipe Dictionary + byte[] result = new byte[8 * sizeof(int)]; + Buffer.BlockCopy(mats, 0, result, 0, result.Length); + string hash; + using (MD5 md5 = MD5.Create()) + { + hash = BitConverter.ToString(md5.ComputeHash(result)); + } + + if (!matToRecipe.ContainsKey(hash)) + matToRecipe.Add(hash, new List()); + + //Add to both Dictionaries + recipeList.Add(recipeID, new Recipe(craftedItem, craftedQuantity, new byte[] { }, 1)); + matToRecipe[hash].Add(new Recipe(craftedItem, craftedQuantity, new byte[] { }, 1)); + } + } + } + catch (MySqlException e) + { + Program.Log.Error(e.ToString()); + return false; + } + finally + { + conn.Dispose(); + } + + return true; + } + } + public static void SavePlayerAppearance(Player player) { string query; @@ -2777,6 +2872,6 @@ namespace Meteor.Map } } } - + } } diff --git a/Map Server/Lua/LuaEngine.cs b/Map Server/Lua/LuaEngine.cs index 236e4830..247eb440 100644 --- a/Map Server/Lua/LuaEngine.cs +++ b/Map Server/Lua/LuaEngine.cs @@ -37,6 +37,7 @@ using Meteor.Map.actors.area; using System.Threading; using Meteor.Map.actors.chara.ai; using Meteor.Map.actors.chara.ai.controllers; +using Meteor.Map.DataObjects; namespace Meteor.Map.lua { @@ -850,6 +851,7 @@ namespace Meteor.Map.lua script.Globals["GetWorldMaster"] = (Func)Server.GetWorldManager().GetActor; script.Globals["GetItemGamedata"] = (Func)Server.GetItemGamedata; script.Globals["GetGuildleveGamedata"] = (Func)Server.GetGuildleveGamedata; + script.Globals["GetRecipeResolver"] = (Func)Server.ResolveRecipe; script.Globals["GetLuaInstance"] = (Func)LuaEngine.GetInstance; script.Options.DebugPrint = s => { Program.Log.Debug(s); }; diff --git a/Map Server/Map Server.csproj b/Map Server/Map Server.csproj index 8ab70f72..5dcd478d 100644 --- a/Map Server/Map Server.csproj +++ b/Map Server/Map Server.csproj @@ -168,6 +168,8 @@ + +