├── .vscode └── settings.json ├── README.md ├── ashita ├── _ashita.lua ├── _enums.lua ├── ability.lua ├── chat.lua ├── item.lua ├── menu.lua ├── mob.lua ├── packets.lua ├── party.lua ├── player.lua ├── spell.lua └── weaponskill.lua ├── columns ├── !column.lua ├── accuracy.lua ├── attack_speed.lua ├── catalog.lua ├── damage.lua ├── defense.lua ├── general.lua ├── healing.lua ├── proc.lua ├── spell.lua ├── string.lua └── util.lua ├── commands.lua ├── database ├── _database.lua ├── _enum.lua ├── accuracy.lua ├── attack_speed.lua ├── catalog.lua ├── data.lua ├── dps.lua ├── lists.lua ├── pet_catalog.lua ├── pet_data.lua └── widgets.lua ├── file.lua ├── handlers ├── _handler.lua ├── abilities.lua ├── deaths.lua ├── items.lua ├── melee.lua ├── melee_def.lua ├── ranged.lua ├── spells.lua ├── spells_def.lua ├── tp_action.lua └── tp_action_def.lua ├── initialization.lua ├── metrics.lua ├── modules ├── battle log │ ├── _battle_log.lua │ ├── columns.lua │ ├── config.lua │ ├── entries.lua │ └── widgets.lua ├── config │ └── _config.lua ├── debug │ ├── !debug.lua │ ├── performance.lua │ ├── screens │ │ ├── data_viewer.lua │ │ ├── error_log.lua │ │ ├── mob_viewer.lua │ │ └── packet_viewer.lua │ └── unit_tests │ │ ├── _tests.lua │ │ ├── abilities.lua │ │ ├── defense.lua │ │ ├── melee.lua │ │ ├── ranged.lua │ │ ├── spells.lua │ │ └── tp_action.lua ├── exp │ ├── _exp.lua │ ├── chains.lua │ ├── columns.lua │ ├── config.lua │ ├── dedication.lua │ └── tracking.lua ├── focus │ ├── _focus.lua │ ├── abilities.lua │ ├── cataloged.lua │ ├── config.lua │ ├── defense.lua │ ├── magic.lua │ ├── melee.lua │ ├── overview.lua │ ├── pets.lua │ ├── ranged.lua │ └── weaponskills.lua ├── hub │ ├── !hub.lua │ └── config.lua ├── overview │ ├── _overview.lua │ ├── config.lua │ ├── focus.lua │ └── parse.lua ├── parse │ ├── _parse.lua │ ├── config.lua │ ├── display_full.lua │ ├── display_mini.lua │ ├── display_nano.lua │ ├── enum.lua │ └── widgets.lua └── report │ ├── _report.lua │ ├── config.lua │ ├── publishing.lua │ └── widgets.lua ├── packets ├── _bitreader.lua └── _parser.lua ├── resources ├── _resource.lua ├── abilities.lua ├── avatars.lua ├── buffs.lua ├── colors.lua ├── game.lua ├── items.lua ├── jobs.lua ├── monster_abilities.lua ├── monster_abilities_curated.lua ├── pets.lua ├── spells.lua ├── spells_curated.lua ├── themes.lua ├── weapon_skills.lua └── weapon_skills_curated.lua ├── throttling.lua ├── timers.lua └── windows ├── !manager.lua ├── !window.lua ├── config.lua ├── themes.lua └── widgets.lua /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Lua.diagnostics.globals": [ 3 | "windower", 4 | "_addon", 5 | "addon", 6 | "AshitaCore", 7 | "ashita", 8 | "ImGuiWindowFlags_NoDecoration", 9 | "ImGuiWindowFlags_AlwaysAutoResize", 10 | "ImGuiWindowFlags_NoSavedSettings", 11 | "ImGuiWindowFlags_NoFocusOnAppearing", 12 | "ImGuiWindowFlags_NoNav", 13 | "ImGuiTableFlags_SizingFixedFit", 14 | "ImGuiTableFlags_None", 15 | "ImGuiTableFlags_Borders", 16 | "bit", 17 | "ImGuiTableColumnFlags_WidthFixed", 18 | "ImGuiWindowFlags_None", 19 | "ImGuiTableFlags_SizingStretchProp", 20 | "ImGuiTableColumnFlags_None", 21 | "ImGuiCond_Always", 22 | "ImGuiStyleVar_CellPadding", 23 | "ImGuiTableFlags_PadOuterX", 24 | "ImGuiStyleVar_WindowPadding", 25 | "ImGuiTabBarFlags_None", 26 | "ImGuiComboFlags_None", 27 | "ImGuiTreeNodeFlags_None", 28 | "GetPlayerEntity", 29 | "ImGuiStyleVar_ItemSpacing", 30 | "ImGuiStyleVar_ItemInnerSpacing", 31 | "ImGuiStyleVar_Alpha", 32 | "ImGuiTableColumnFlags_WidthStretch", 33 | "ImGuiTableFlags_Resizable", 34 | "ImGuiTableFlags_SizingStretchSame", 35 | "ImGuiTableFlags_NoSavedSettings", 36 | "ImGuiWindowFlags_HorizontalScrollbar", 37 | "ImGuiCol_TableHeaderBg", 38 | "ImGuiSliderFlags_None", 39 | "ImGuiInputTextFlags_CharsDecimal", 40 | "ImGuiTableFlags_Reorderable", 41 | "ImGuiTableFlags_Sortable", 42 | "ImGuiTableColumnFlags_DefaultSort", 43 | "ImGuiTableFlags_ScrollY", 44 | "ImGuiStyleVar_IndentSpacing", 45 | "ImGuiTableFlags_NoHostExtendX", 46 | "T", 47 | "ImGuiCol_Text", 48 | "ImGuiCol_TextDisabled", 49 | "ImGuiCol_WindowBg", 50 | "ImGuiCol_ChildBg", 51 | "ImGuiCol_PopupBg", 52 | "ImGuiCol_Border", 53 | "ImGuiCol_BorderShadow", 54 | "ImGuiCol_FrameBg", 55 | "ImGuiCol_FrameBgHovered", 56 | "ImGuiCol_FrameBgActive", 57 | "ImGuiCol_TitleBg", 58 | "ImGuiCol_TitleBgActive", 59 | "ImGuiCol_TitleBgCollapsed", 60 | "ImGuiCol_MenuBarBg", 61 | "ImGuiCol_ScrollbarBg", 62 | "ImGuiCol_ScrollbarGrab", 63 | "ImGuiCol_ScrollbarGrabHovered", 64 | "ImGuiCol_ScrollbarGrabActive", 65 | "ImGuiCol_CheckMark", 66 | "ImGuiCol_SliderGrab", 67 | "ImGuiCol_SliderGrabActive", 68 | "ImGuiCol_Button", 69 | "ImGuiCol_ButtonHovered", 70 | "ImGuiCol_ButtonActive", 71 | "ImGuiCol_Header", 72 | "ImGuiCol_HeaderHovered", 73 | "ImGuiCol_HeaderActive", 74 | "ImGuiCol_Separator", 75 | "ImGuiCol_SeparatorHovered", 76 | "ImGuiCol_SeparatorActive", 77 | "ImGuiCol_ResizeGrip", 78 | "ImGuiCol_ResizeGripHovered", 79 | "ImGuiCol_ResizeGripActive", 80 | "ImGuiCol_Tab", 81 | "ImGuiCol_TabHovered", 82 | "ImGuiCol_TabActive", 83 | "ImGuiCol_TabUnfocused", 84 | "ImGuiCol_TabUnfocusedActive", 85 | "ImGuiCol_PlotLines", 86 | "ImGuiCol_PlotLinesHovered", 87 | "ImGuiCol_PlotHistogram", 88 | "ImGuiCol_PlotHistogramHovered", 89 | "ImGuiCol_TableBorderStrong", 90 | "ImGuiCol_TableBorderLight", 91 | "ImGuiCol_TableRowBg", 92 | "ImGuiCol_TableRowBgAlt", 93 | "ImGuiCol_TextSelectedBg", 94 | "ImGuiCol_DragDropTarget", 95 | "ImGuiCol_NavHighlight", 96 | "ImGuiCol_NavWindowingHighlight", 97 | "ImGuiCol_NavWindowingDimBg", 98 | "ImGuiCol_ModalWindowDimBg", 99 | "ImGuiTreeNodeFlags_SpanAvailWidth", 100 | "ImGuiWindowFlags_NoTitleBar", 101 | "breader", 102 | "switch", 103 | "GetEntity", 104 | "ImGuiTabItemFlags_SetSelected", 105 | "ImGuiWindowFlags_NoBackground", 106 | "ImGuiTableBgTarget_CellBg", 107 | "ImGuiTableBgTarget_RowBg0", 108 | "ImGuiCond_Once", 109 | "ImGuiTableFlags_RowBg", 110 | "ImGuiInputTextFlags_AutoSelectAll" 111 | ], 112 | "Lua.diagnostics.disable": [ 113 | "undefined-field" 114 | ] 115 | } -------------------------------------------------------------------------------- /ashita/_ashita.lua: -------------------------------------------------------------------------------- 1 | Ashita = T{} 2 | 3 | -- ------------------------------------------------------------------------------------------------------ 4 | -- https://github.com/AshitaXI/Ashita-v4beta/blob/main/plugins/sdk/Ashita.h 5 | -- Memory Manager Functions 6 | -- IAutoFollow* GetAutoFollow(void) 7 | -- ICastBar* GetCastBar(void) 8 | -- IEntity* GetEntity(void) 9 | -- IInventory* GetInventory(void) 10 | -- IParty* GetParty(void) 11 | -- IPlayer* GetPlayer(void) 12 | -- IRecast* GetRecast(void) 13 | -- ITarget* GetTarget(void) 14 | -- ------------------------------------------------------------------------------------------------------ 15 | -- TO DO 16 | -- 1. Finish the pet portion in a.Mob.Get_Mob_By_Target 17 | -- ------------------------------------------------------------------------------------------------------ 18 | 19 | Ashita.States = { 20 | Zoning = false, 21 | } 22 | 23 | require("ashita._enums") 24 | require("ashita.mob") -- Getting data related to mobs. 25 | require("ashita.player") -- Getting data related to the player. 26 | require("ashita.party") -- Getting data related to the party. 27 | require("ashita.ability") -- Getting data related to abilities. 28 | require("ashita.spell") -- Getting data related to spells. 29 | require("ashita.weaponskill") -- Getting data related to weaponskills. 30 | require("ashita.item") -- Getting data related to items. 31 | require("ashita.chat") -- Chat functions. 32 | require("ashita.packets") -- Packet functions. 33 | require("ashita.menu") -- Memory and Menus. -------------------------------------------------------------------------------- /ashita/_enums.lua: -------------------------------------------------------------------------------- 1 | Ashita.Enum = T{} 2 | 3 | Ashita.Enum.Chat = T{ 4 | PARTY = 1, 5 | LINKSHELL = 2, 6 | LINKSHELL2 = 3, 7 | SAY = 4, 8 | } 9 | 10 | Ashita.Enum.Player_Attributes = T{ 11 | TP = "TP", 12 | PET_TP = "Pet TP", 13 | ISZONING = "IsZoning", 14 | } 15 | 16 | Ashita.Enum.Targets = T{ 17 | ME = "me", 18 | TARGET = "t", 19 | PET = "pet", 20 | } 21 | 22 | Ashita.Enum.Spawn_Flags = T{ 23 | MAINPLAYER = 525, 24 | OTHERPLAYER = 1, 25 | NPC = 2, 26 | IN_PARTY = 13, 27 | IN_ALLIANCE = 9, 28 | MOB = 16, 29 | TRUST = 4366, 30 | PET = 258, 31 | } 32 | 33 | Ashita.Enum.Ability = T{ 34 | NORMAL = 1, -- Type: Normal Ability 35 | PETLOGISTICS = 2, -- Type: Fight, Heel, Stay, etc. 36 | BLOODPACTRAGE = 6, -- Type: 37 | BLOODPACTWARD = 10, -- Type: 38 | PETABILITY = 18, -- Type: Offensive BST/SMN ability. 39 | } 40 | 41 | -- Animation IDs from incoming packet 0x028 (Action Packet). 42 | Ashita.Enum.Animation = T{ 43 | MELEE_MAIN = 0, 44 | MELEE_OFFHAND = 1, 45 | MELEE_KICK = 2, 46 | MELEE_KICK2 = 3, 47 | DAKEN = 4, 48 | } 49 | 50 | Ashita.Enum.Reaction = T{ 51 | GUARD = 2, 52 | SHIELD_BLOCK = 4, 53 | } 54 | 55 | Ashita.Enum.Effect_Animation = T{ 56 | FIRE = 1, 57 | ICE = 2, 58 | WIND = 3, 59 | EARTH = 4, 60 | THUNDER = 5, 61 | WATER = 6, 62 | LIGHT = 7, 63 | DARK = 8, 64 | SLEEP = 9, 65 | POISON = 10, 66 | PARALYZE = 11, 67 | BLIND = 12, 68 | SILENCE = 13, 69 | STUN = 16, 70 | CURSE = 17, 71 | DEF_DOWN = 18, 72 | DRAIN = 21, 73 | ASPIR = 22, 74 | HASTE = 23, 75 | } 76 | 77 | -- Message IDs from incoming packet 0x029 (Action Message). 78 | Ashita.Enum.Message = T{ 79 | HIT = 1, 80 | MOBHEAL3 = 3, 81 | MOB_KILL = 6, 82 | MOBHEAL373 = 373, 83 | MISS = 15, 84 | DEATH_FALL = 20, 85 | SHADOWS = 31, 86 | DODGE = 32, 87 | COUNTER = 33, 88 | SPIKE_DMG = 44, 89 | CRIT = 67, 90 | PARRY = 70, 91 | NO_EFFECT = 75, 92 | RESIST = 85, 93 | DEATH = 97, 94 | EFFECT_FAIL = 114, 95 | ENDEBUFF = 160, 96 | ENDRAIN = 161, 97 | ENASPIR = 162, 98 | ENDAMAGE = 163, 99 | RANGEPUP = 185, 100 | MISS_TP = 188, 101 | ENSPELL = 229, 102 | ENF_LAND = 236, 103 | ENF_LAND_2 = 237, 104 | BURST = 252, 105 | ENF_BURST = 271, 106 | RESIST_2 = 284, 107 | ABSORB_STR = 329, 108 | ABSORB_DEX = 330, 109 | ABSORB_VIT = 331, 110 | ABSORB_AGI = 332, 111 | ABSORB_INT = 333, 112 | ABSORB_MND = 334, 113 | ABSORB_CHR = 335, 114 | MAGIC_ERASE = 341, 115 | RANGEHIT = 352, 116 | RANGECRIT = 353, 117 | RANGEMISS = 354, 118 | COR_BUST = 426, 119 | ABSORB_TP = 454, 120 | ABSORB_ACC = 533, 121 | SQUARE = 576, 122 | TRUE = 577, 123 | COMP_RESIST = 655, 124 | OVERLOAD = 799, 125 | } -------------------------------------------------------------------------------- /ashita/ability.lua: -------------------------------------------------------------------------------- 1 | Ashita.Ability = T{} 2 | 3 | -- ------------------------------------------------------------------------------------------------------ 4 | -- Get ability data. 5 | -- https://wiki.ashitaxi.com/doku.php?id=addons:adk:iresourcemanager 6 | -- Type 1 = Special Ability (2-hour), Third Eye, 7 | -- Type 6 = SMN using BloodPactRage 8 | -- Type 10 = BloodPactWard 9 | -- Type 18 = BloodPactRage 10 | -- Offsets 11 | -- WS have zero offset. 12 | -- Abilities have 512 offset. 13 | -- ------------------------------------------------------------------------------------------------------ 14 | ---@param id number 15 | ---@return table 16 | -- ------------------------------------------------------------------------------------------------------ 17 | Ashita.Ability.Get_By_ID = function(id) 18 | return AshitaCore:GetResourceManager():GetAbilityById(id) 19 | end 20 | 21 | -- ------------------------------------------------------------------------------------------------------ 22 | -- Get the name of an ability. 23 | -- If we already have the ability data then we don't need to get it again. 24 | -- ------------------------------------------------------------------------------------------------------ 25 | ---@param id number ability ID. 26 | ---@param data? table ability table if we already have it. 27 | ---@return string 28 | -- ------------------------------------------------------------------------------------------------------ 29 | Ashita.Ability.Name = function(id, data) 30 | local ability = data 31 | if not ability then 32 | ability = Ashita.Ability.Get_By_ID(id) 33 | end 34 | if not ability then return "Error" end 35 | return ability.Name[1] 36 | end 37 | 38 | -- ------------------------------------------------------------------------------------------------------ 39 | -- Get the current recast time for an ability by the abilities ID. 40 | -- ------------------------------------------------------------------------------------------------------ 41 | ---@param id number ability ID. 42 | ---@return number 43 | -- ------------------------------------------------------------------------------------------------------ 44 | Ashita.Ability.Recast_ID = function(id) 45 | local ability_id 46 | local recast = 0 47 | local found = false 48 | for i = 0, 31 do 49 | if not found then 50 | ability_id = AshitaCore:GetMemoryManager():GetRecast():GetAbilityTimerId(i) 51 | if ability_id == id then 52 | recast = math.floor(AshitaCore:GetMemoryManager():GetRecast():GetAbilityTimer(i) / 60) 53 | found = true 54 | end 55 | end 56 | end 57 | return recast 58 | end -------------------------------------------------------------------------------- /ashita/chat.lua: -------------------------------------------------------------------------------- 1 | Ashita.Chat = T{} 2 | 3 | Ashita.Chat.Selection = T{ 4 | Title = "Chat Mode", 5 | Width = 150, 6 | } 7 | 8 | Ashita.Chat.Modes = { 9 | [1] = {Name = "Party", Prefix = "/p"}, 10 | [2] = {Name = "Linkshell 1", Prefix = "/l"}, 11 | [3] = {Name = "Linkshell 2", Prefix = "/l2"}, 12 | [4] = {Name = "Say", Prefix = "/s"}, 13 | } 14 | 15 | -- ------------------------------------------------------------------------------------------------------ 16 | -- Adds a message in game chat. Doesn't actually send anything to other people. 17 | -- ------------------------------------------------------------------------------------------------------ 18 | ---@param message string 19 | -- ------------------------------------------------------------------------------------------------------ 20 | Ashita.Chat.Message = function(message) 21 | print("METRICS: " .. message) 22 | end 23 | 24 | -- ------------------------------------------------------------------------------------------------------ 25 | -- Adds a message in game chat. This is meant to be viewed by other people. 26 | -- ------------------------------------------------------------------------------------------------------ 27 | ---@param message string 28 | -- ------------------------------------------------------------------------------------------------------ 29 | Ashita.Chat.Add_To_Chat = function(type, message) 30 | AshitaCore:GetChatManager():QueueCommand(1, tostring(type) .. " " .. tostring(message)) 31 | end -------------------------------------------------------------------------------- /ashita/item.lua: -------------------------------------------------------------------------------- 1 | Ashita.Item = T{} 2 | 3 | -- ------------------------------------------------------------------------------------------------------ 4 | -- Checks a piece of gear's level. 5 | -- ------------------------------------------------------------------------------------------------------ 6 | ---@param item_name string 7 | ---@return number 8 | -- ------------------------------------------------------------------------------------------------------ 9 | Ashita.Item.Get_Item_Level = function(item_name) 10 | local item = AshitaCore:GetResourceManager():GetItemByName(item_name, 0) 11 | local item_level = item.Level 12 | if not item_level then return 0 end 13 | return item_level 14 | end -------------------------------------------------------------------------------- /ashita/menu.lua: -------------------------------------------------------------------------------- 1 | Ashita.Menu = T{} 2 | 3 | Ashita.Menu.Module = "FFXiMain.dll" 4 | Ashita.Menu.Pattern = "8B480C85C974??8B510885D274??3B05" 5 | 6 | Ashita.Menu.Types = T{ 7 | fulllog = true, -- Expanded chat log 8 | equip = true, -- Equipment menu 9 | inventor = true, -- Inventory 10 | mnstorag = true, -- Equip inventory selection 11 | iuse = true, -- Use item 12 | map0 = true, -- Regular map 13 | maplist = true, -- Selecting a map from within the regular map 14 | mapframe = true, -- Temporary map state while transitioning between maps 15 | scanlist = true, -- Widescan 16 | cnqframe = true, -- Conquest, Beseiged, Campaign, etc. map 17 | conf2win = true, -- Gameplay 18 | cfilter = true, -- Chat Filters 19 | textcol1 = true, -- Font Colors -> Chat, For Self, For Others, System 20 | confyn = true, -- Font Colors -> Default 21 | conf5m = true, -- Windows 22 | conf5win = true, -- Windows -> Shared 23 | conf5w1 = true, -- Windows -> Window 1 24 | conf5w2 = true, -- Windows -> Window 2 25 | conf11m = true, -- Log 26 | conf11l = true, -- Log -> Window 1/2 27 | conf11s = true, -- Log -> Window 1/2 -> Chat, For Self, For Others, System 28 | conf3win = true, -- Misc 29 | conf6win = true, -- Misc 2 30 | conf12wi = true, -- Misc 3 31 | conf13wi = true, -- Misc 4 32 | fxfilter = true, -- Effects 33 | conf7 = true, -- Mouse/Cam 34 | conf4 = true, -- Global 35 | link5 = true, -- Linkshell 36 | link12 = true, -- Linkshell list 37 | link13 = true, -- Linkshell -> Unequiped linkshell 38 | link3 = true, -- Linkshell -> Equipped linkshell 39 | scresult = true, -- Search results 40 | evitem = true, -- Curencies 41 | statcom2 = true, -- Combat skills 42 | auc1 = true, -- AH Bid/Sell 43 | moneyctr = true, -- AH Window 44 | shopsell = true, -- Sell prompt 45 | comyn = true, -- AH confirm sell 46 | auclist = true, -- AH Sales Status 47 | auchisto = true, -- AH History 48 | auc4 = true, -- AH Stop Sale 49 | post1 = true, -- Delivery Box 50 | post2 = true, -- Delivery Box Confirm 51 | stringdl = true, -- Delivery Box Send Recipient 52 | delivery = true, -- Delivery Box Sending 53 | mcr1edlo = true, -- Macro editing row 1 54 | mcr2edlo = true, -- Macro editing row 2 55 | mcrbedit = true, -- Hitting + to edit macros 56 | mcresed = true, -- Equipset editing 57 | bank = true, -- Mog Satchel 58 | handover = true, -- Trade Menu 59 | itmsortw = true, -- Item Sort Menu 60 | sortyn = true, -- Item Sort Yes/No 61 | itemctrl = true, -- Choosing the number of items to select for transfer in inventory 62 | loot = true, -- Treasure Pool 63 | lootope = true, -- Cast Lot 64 | meritcat = true, -- Merit Categories 65 | merit1 = true, -- Merit Categories/Mode Switch 66 | merit2 = true, -- Merit EXP/Limit Points 67 | merit3 = true, -- Merit Raise/Lower 68 | merityn = true, -- Yes/No on the merit upgrades 69 | shop = true, -- Setting bazaar prices 70 | automato = true, -- Automaton equipment menu 71 | bluinven = true, -- Automaton equipment selection 72 | bluequip = true, -- BLU magic spell equip menu 73 | quest00 = true, -- Quest menu 74 | quest01 = true, -- Quest selection menu 75 | miss00 = true, -- Mission submenu 76 | faqsub = true, -- Help Desk 77 | cmbhlst = true, -- Synthesis History 78 | } 79 | 80 | -- ------------------------------------------------------------------------------------------------------ 81 | -- Gets the name of the upper most menu. 82 | -- Copied from PetMe which got it from XITools. 83 | -- https://github.com/mousseng/xitools 84 | -- https://github.com/m4thmatic/PetMe 85 | -- ------------------------------------------------------------------------------------------------------ 86 | ---@return string, integer 87 | -- ------------------------------------------------------------------------------------------------------ 88 | function Ashita.Menu.Get_Menu_Name() 89 | local menu = ashita.memory.find(Ashita.Menu.Module, 0, Ashita.Menu.Pattern, 16, 0) 90 | local pointer = ashita.memory.read_uint32(menu) 91 | local pointer_value = ashita.memory.read_uint32(pointer) 92 | if pointer_value == 0 then return "", 0 end 93 | local menu_header = ashita.memory.read_uint32(pointer_value + 4) 94 | local menu_name = ashita.memory.read_string(menu_header + 0x46, 16) 95 | return string.gsub(menu_name, "\x00", "") 96 | end 97 | 98 | -- ------------------------------------------------------------------------------------------------------ 99 | -- Checks whether a menu is up that we should hide Metrics for. 100 | -- ------------------------------------------------------------------------------------------------------ 101 | ---@return boolean 102 | -- ------------------------------------------------------------------------------------------------------ 103 | function Ashita.Menu.Hide() 104 | local menu_name = Ashita.Menu.Get_Menu_Name() 105 | if not menu_name then return true end 106 | 107 | -- Get rid of prefix junk and clip off trailing spaces. 108 | menu_name = string.sub(menu_name, 9) 109 | menu_name = string.gsub(menu_name, " ", "") 110 | 111 | return Ashita.Menu.Types[menu_name] 112 | end -------------------------------------------------------------------------------- /ashita/spell.lua: -------------------------------------------------------------------------------- 1 | Ashita.Spell = T{} 2 | 3 | -- ------------------------------------------------------------------------------------------------------ 4 | -- Get spell data. 5 | -- https://wiki.ashitaxi.com/doku.php?id=addons:adk:iresourcemanager 6 | -- ------------------------------------------------------------------------------------------------------ 7 | ---@param id number spell ID. 8 | ---@return table 9 | -- ------------------------------------------------------------------------------------------------------ 10 | Ashita.Spell.Get_By_ID = function(id) 11 | return AshitaCore:GetResourceManager():GetSpellById(id) 12 | end 13 | 14 | -- ------------------------------------------------------------------------------------------------------ 15 | -- Get the name of a spell. 16 | -- If we already have the spell data then we don't need to get it again. 17 | -- ------------------------------------------------------------------------------------------------------ 18 | ---@param id number spell ID. 19 | ---@param data? table spell table if we already have it. 20 | ---@return string 21 | -- ------------------------------------------------------------------------------------------------------ 22 | Ashita.Spell.Name = function(id, data) 23 | local spell = data 24 | if not spell then 25 | spell = Ashita.Spell.Get_By_ID(id) 26 | end 27 | if not spell then return "Error" end 28 | return spell.Name[1] 29 | end 30 | 31 | -- ------------------------------------------------------------------------------------------------------ 32 | -- Get the MP cost of a spell. 33 | -- If we already have the spell data then we don't need to get it again. 34 | -- ------------------------------------------------------------------------------------------------------ 35 | ---@param id number spell ID. 36 | ---@param data? table spell table if we already have it. 37 | ---@return number 38 | -- ------------------------------------------------------------------------------------------------------ 39 | Ashita.Spell.MP = function(id, data) 40 | local spell = data 41 | if not spell then 42 | spell = Ashita.Spell.Get_By_ID(id) 43 | end 44 | if not spell then return 0 end 45 | return spell.ManaCost 46 | end -------------------------------------------------------------------------------- /ashita/weaponskill.lua: -------------------------------------------------------------------------------- 1 | Ashita.WS = T{} 2 | 3 | -- ------------------------------------------------------------------------------------------------------ 4 | -- Gets properties for a WS. 5 | -- The resource file used to do this is from Windower. 6 | -- Some things are treated as weaponskills, but aren't actually. Those can be missing from the WS file. 7 | -- For those I keep track of them in Missing_WS define in the lists.lua 8 | -- ------------------------------------------------------------------------------------------------------ 9 | ---@param id number weaponskill ID. 10 | ---@return table 11 | -- ------------------------------------------------------------------------------------------------------ 12 | Ashita.WS.Get_By_ID = function(id) 13 | local ws = Res.WS.Get_Full_List(id) 14 | if not ws then ws = Res.WS.Get_Missing(id) end 15 | return ws 16 | end -------------------------------------------------------------------------------- /columns/!column.lua: -------------------------------------------------------------------------------- 1 | Column = T{} 2 | 3 | Column.Flags = T{ 4 | None = bit.bor(ImGuiTableColumnFlags_None), 5 | Expandable = bit.bor(ImGuiTableColumnFlags_WidthStretch), 6 | } 7 | 8 | Column.Widths = T{ 9 | Name = 150, 10 | Parse = 60, 11 | Percent = 60, 12 | Single = 40, 13 | Standard = 75, 14 | Settings = 175, 15 | Report = 110, 16 | Catalog = 65, 17 | } 18 | 19 | Column.Mode = DB.Enum.Mode 20 | Column.Trackable = DB.Enum.Trackable 21 | Column.Metric = DB.Enum.Metric 22 | 23 | -- Load dependencies 24 | require("columns.string") 25 | require("columns.damage") 26 | require("columns.attack_speed") 27 | require("columns.defense") 28 | require("columns.healing") 29 | require("columns.accuracy") 30 | require("columns.proc") 31 | require("columns.spell") 32 | require("columns.catalog") 33 | require("columns.util") 34 | require("columns.general") -------------------------------------------------------------------------------- /columns/accuracy.lua: -------------------------------------------------------------------------------- 1 | Column.Acc = T{} 2 | 3 | ------------------------------------------------------------------------------------------------------ 4 | -- Grabs an entities accuracy for a specific trackable. 5 | -- Accuracy can be broken up into type--like melee and ranged--or melee and ranged combined. 6 | ------------------------------------------------------------------------------------------------------ 7 | ---@param player_name string 8 | ---@param acc_type string a trackable from the model. 9 | ---@param justify? boolean whether or not to right justify the text 10 | ---@param count_type? string used for getting ranged square and truestrike rates. 11 | ---@param raw? boolean true: just output the raw value; false: output a column to a table. 12 | ---@return string 13 | ------------------------------------------------------------------------------------------------------ 14 | Column.Acc.By_Type = function(player_name, acc_type, justify, count_type, raw) 15 | local hits, attempts 16 | if not count_type then count_type = Column.Metric.HIT_COUNT end 17 | if acc_type == DB.Enum.Values.COMBINED then 18 | local melee_hits = DB.Data.Get(player_name, Column.Trackable.MELEE, Column.Metric.HIT_COUNT) 19 | local melee_attempts = DB.Data.Get(player_name, Column.Trackable.MELEE, Column.Metric.COUNT) 20 | local ranged_hits = DB.Data.Get(player_name, Column.Trackable.RANGED, Column.Metric.HIT_COUNT) 21 | local ranged_attempts = DB.Data.Get(player_name, Column.Trackable.RANGED, Column.Metric.COUNT) 22 | hits = melee_hits + ranged_hits 23 | attempts = melee_attempts + ranged_attempts 24 | else 25 | hits = DB.Data.Get(player_name, acc_type, count_type) 26 | attempts = DB.Data.Get(player_name, acc_type, Column.Metric.COUNT) 27 | end 28 | 29 | local color = Res.Colors.Basic.WHITE 30 | local percent = Column.String.Raw_Percent(hits, attempts) 31 | if percent == 0 then 32 | color = Res.Colors.Basic.DIM 33 | elseif percent <= DB.Settings.Accuracy_Warning then 34 | color = Res.Colors.Basic.RED 35 | end 36 | 37 | if raw then return Column.String.Format_Percent(hits, attempts) end 38 | return UI.TextColored(color, Column.String.Format_Percent(hits, attempts, justify)) 39 | end 40 | 41 | ------------------------------------------------------------------------------------------------------ 42 | -- Grabs the accuracy of a certain trackable that the entity's pet has done. 43 | ------------------------------------------------------------------------------------------------------ 44 | ---@param player_name string the entity that owns the pet. 45 | ---@param pet_name string the pet that we want the damage for. 46 | ---@param acc_type string a trackable from the model. 47 | ---@param justify? boolean whether or not to right justify the text 48 | ---@param count_type? string used for getting ranged square and truestrike rates. 49 | ---@return string 50 | ------------------------------------------------------------------------------------------------------ 51 | Column.Acc.Pet_By_Type = function(player_name, pet_name, acc_type, justify, count_type) 52 | if not count_type then count_type = Column.Metric.HIT_COUNT end 53 | local hits = DB.Pet_Data.Get(player_name, pet_name, acc_type, count_type) 54 | local attempts = DB.Pet_Data.Get(player_name, pet_name, acc_type, Column.Metric.COUNT) 55 | 56 | local color = Res.Colors.Basic.WHITE 57 | local percent = Column.String.Raw_Percent(hits, attempts) 58 | if percent == 0 then 59 | color = Res.Colors.Basic.DIM 60 | elseif percent <= DB.Settings.Accuracy_Warning then 61 | color = Res.Colors.Basic.RED 62 | end 63 | 64 | return UI.TextColored(color, Column.String.Format_Percent(hits, attempts, justify)) 65 | end 66 | 67 | 68 | ------------------------------------------------------------------------------------------------------ 69 | -- Grabs an entity's accuracy for last {X} amount of attempts. Includes melee and ranged combined. 70 | -- {X} is defined in the model's settings. 71 | ------------------------------------------------------------------------------------------------------ 72 | ---@param player_name string 73 | ---@param justify? boolean 74 | ---@return string 75 | ------------------------------------------------------------------------------------------------------ 76 | Column.Acc.Running = function(player_name, justify) 77 | local accuracy = DB.Accuracy.Get(player_name) 78 | local color = Res.Colors.Basic.WHITE 79 | local percent = Column.String.Raw_Percent(accuracy[1], accuracy[2]) 80 | 81 | if percent == 0 then 82 | color = Res.Colors.Basic.DIM 83 | elseif percent <= DB.Settings.Accuracy_Warning then 84 | color = Res.Colors.Basic.RED 85 | end 86 | 87 | return UI.TextColored(color, Column.String.Format_Percent(accuracy[1], accuracy[2], justify)) 88 | end -------------------------------------------------------------------------------- /columns/attack_speed.lua: -------------------------------------------------------------------------------- 1 | Column.Attack_Speed = T{} 2 | 3 | ------------------------------------------------------------------------------------------------------ 4 | -- Gets a player's attack speed. 5 | ------------------------------------------------------------------------------------------------------ 6 | ---@param player_name string 7 | ---@param justify? boolean whether or not to right justify the text 8 | ---@param raw? boolean true: just output the raw value; false: output a column to a table. 9 | ---@return string 10 | ------------------------------------------------------------------------------------------------------ 11 | Column.Attack_Speed.Get = function(player_name, justify, raw) 12 | local speed = DB.Attack_Speed.Get(player_name) 13 | 14 | local color = Res.Colors.Basic.WHITE 15 | if speed == 0 then color = Res.Colors.Basic.DIM end 16 | 17 | if raw then return Column.String.Format_Decimal(speed, justify) end 18 | return UI.TextColored(color, Column.String.Format_Decimal(speed, justify)) 19 | end -------------------------------------------------------------------------------- /columns/defense.lua: -------------------------------------------------------------------------------- 1 | Column.Defense = T{} 2 | 3 | ------------------------------------------------------------------------------------------------------ 4 | -- Grabs the damage of a certain trackable that the entity has taken. 5 | ------------------------------------------------------------------------------------------------------ 6 | ---@param player_name string 7 | ---@param damage_type string a trackable from the model. 8 | ---@param percent? boolean whether or not the damage should be raw or percent. 9 | ---@param justify? boolean whether or not to right justify the text 10 | ---@param raw? boolean true: just output the raw value; false: output a column to a table. 11 | ---@return string 12 | ------------------------------------------------------------------------------------------------------ 13 | Column.Defense.Damage_Taken_By_Type = function(player_name, damage_type, percent, justify, raw) 14 | local total = DB.Data.Get(player_name, damage_type, Column.Metric.TOTAL) 15 | local color = Column.String.Color_Zero(total) 16 | if percent then 17 | local total_damage = DB.Data.Get(player_name, Column.Trackable.DAMAGE_TAKEN_TOTAL, Column.Metric.TOTAL) 18 | if raw then return Column.String.Format_Percent(total, total_damage) end 19 | return UI.TextColored(color, Column.String.Format_Percent(total, total_damage, justify)) 20 | end 21 | if raw then return Column.String.Format_Number(total) end 22 | return UI.TextColored(color, Column.String.Format_Number(total, justify)) 23 | end 24 | 25 | ------------------------------------------------------------------------------------------------------ 26 | -- Grabs the proc rate of certain defensive actions. 27 | ------------------------------------------------------------------------------------------------------ 28 | ---@param player_name string 29 | ---@param damage_type string a trackable from the model. 30 | ---@param justify? boolean whether or not to right justify the text 31 | ---@param raw? boolean true: just output the raw value; false: output a column to a table. 32 | ---@return string 33 | ------------------------------------------------------------------------------------------------------ 34 | Column.Defense.Proc_Rate_By_Type = function(player_name, damage_type, justify, raw) 35 | local proc_count = DB.Data.Get(player_name, damage_type, Column.Metric.HIT_COUNT) 36 | local color = Column.String.Color_Zero(proc_count) 37 | local attack_count = DB.Data.Get(player_name, damage_type, Column.Metric.COUNT) 38 | if raw then return Column.String.Format_Percent(proc_count, attack_count) end 39 | return UI.TextColored(color, Column.String.Format_Percent(proc_count, attack_count, justify)) 40 | end 41 | 42 | ------------------------------------------------------------------------------------------------------ 43 | -- Approximates how much damage has been potentially mitigated by the given mitigation type. 44 | ------------------------------------------------------------------------------------------------------ 45 | ---@param player_name string 46 | ---@param mitigation_type string a trackable from the model. 47 | ---@param justify? boolean whether or not to right justify the text 48 | ---@return string 49 | ------------------------------------------------------------------------------------------------------ 50 | Column.Defense.Damage_Mitigation = function(player_name, mitigation_type, justify) 51 | local mitigation_proc = DB.Data.Get(player_name, mitigation_type, Column.Metric.HIT_COUNT) 52 | local color = Column.String.Color_Zero(mitigation_proc) 53 | if mitigation_proc == 0 then return UI.TextColored(color, Column.String.Format_Number(mitigation_proc)) end 54 | 55 | local average_melee = Column.Defense.Average_Damage_By_Type(player_name, Column.Trackable.DEF_UNMITIGATED, false, true) 56 | color = Column.String.Color_Zero(average_melee) 57 | if average_melee == 0 then return UI.TextColored(color, "...") end 58 | 59 | local average_reduced_damage = Column.Defense.Average_Damage_By_Type(player_name, mitigation_type, false, true) 60 | if mitigation_type == DB.Enum.Trackable.DEF_COUNTER then average_reduced_damage = 0 end -- Counter reduces damage 100%, but stores counter damage done. 61 | local damage_mitigated = mitigation_proc * (average_melee - average_reduced_damage) 62 | if damage_mitigated < 0 then damage_mitigated = 0 end 63 | color = Column.String.Color_Zero(damage_mitigated) 64 | return UI.TextColored(color, Column.String.Format_Number(damage_mitigated, justify)) 65 | end 66 | 67 | ------------------------------------------------------------------------------------------------------ 68 | -- Gets the average amount of damage taken per damage type. 69 | ------------------------------------------------------------------------------------------------------ 70 | ---@param player_name string 71 | ---@param damage_type string a trackable from the model. 72 | ---@param justify? boolean whether or not to right justify the text 73 | ---@param raw? boolean true: just output the raw value; false: output a column to a table. 74 | ---@return integer 75 | ------------------------------------------------------------------------------------------------------ 76 | Column.Defense.Average_Damage_By_Type = function(player_name, damage_type, justify, raw) 77 | local count = DB.Data.Get(player_name, damage_type, Column.Metric.HIT_COUNT) 78 | local color = Column.String.Color_Zero(count) 79 | if count == 0 then 80 | if raw then return 0 end 81 | return UI.TextColored(color, "...", justify) 82 | end 83 | 84 | local damage = DB.Data.Get(player_name, damage_type, Column.Metric.TOTAL) 85 | color = Column.String.Color_Zero(damage) 86 | local average_damage = math.floor(damage / count) 87 | if raw then return average_damage end 88 | return UI.TextColored(color, Column.String.Format_Percent(damage, count, justify, true)) 89 | end 90 | 91 | ------------------------------------------------------------------------------------------------------ 92 | -- Calculates how what the DT% is for a given mitigation type. 93 | ------------------------------------------------------------------------------------------------------ 94 | ---@param player_name string 95 | ---@param mitigation_type string a trackable from the model. 96 | ---@param justify? boolean whether or not to right justify the text 97 | ---@return string 98 | ------------------------------------------------------------------------------------------------------ 99 | Column.Defense.Damage_Reduction = function(player_name, mitigation_type, justify) 100 | local average_melee = Column.Defense.Average_Damage_By_Type(player_name, Column.Trackable.DEF_UNMITIGATED, false, true) 101 | local color = Column.String.Color_Zero(average_melee) 102 | if average_melee == 0 then return UI.TextColored(color, "...") end 103 | 104 | local average_reduced_damage = Column.Defense.Average_Damage_By_Type(player_name, mitigation_type, false, true) 105 | color = Column.String.Color_Zero(average_reduced_damage) 106 | 107 | return UI.TextColored(color, Column.String.Format_Percent(average_melee - average_reduced_damage, average_melee, justify)) 108 | end -------------------------------------------------------------------------------- /columns/general.lua: -------------------------------------------------------------------------------- 1 | Column.General = T{} 2 | 3 | ------------------------------------------------------------------------------------------------------ 4 | -- Takes one metric and divides it by another metric. 5 | ------------------------------------------------------------------------------------------------------ 6 | ---@param player_name string 7 | ---@param trackable string a trackable from the model. 8 | ---@param metric_numerator string a metric from the model. 9 | ---@param metric_denominator string metric from the model to be used as a denominator in a percent calculation. 10 | ---@param justify? boolean whether or not to right justify the text 11 | ---@param raw? boolean true: just output the raw value; false: output a column to a table. 12 | ---@param no_scaling? boolean do not scale the fraction by 100. 13 | ---@return string 14 | ------------------------------------------------------------------------------------------------------ 15 | Column.General.Fraction = function(player_name, trackable, metric_numerator, metric_denominator, justify, raw, no_scaling) 16 | local numerator = DB.Data.Get(player_name, trackable, metric_numerator) 17 | local color = Column.String.Color_Zero(numerator) 18 | local denominator = DB.Data.Get(player_name, trackable, metric_denominator) 19 | if not denominator or denominator <= 0 then return UI.TextColored(color, Column.String.Format_Percent(0, 0, justify)) end 20 | if raw then return Column.String.Format_Percent(numerator, denominator) end 21 | return UI.TextColored(color, Column.String.Format_Percent(numerator, denominator, justify, no_scaling)) 22 | end 23 | 24 | ------------------------------------------------------------------------------------------------------ 25 | -- Takes the total metric from a trackable and divides by how much of the trackable the party has done. 26 | ------------------------------------------------------------------------------------------------------ 27 | ---@param player_name string 28 | ---@param trackable string a trackable from the model. 29 | ---@param justify? boolean whether or not to right justify the text 30 | ---@param raw? boolean true: just output the raw value; false: output a column to a table. 31 | ---@return string 32 | ------------------------------------------------------------------------------------------------------ 33 | Column.General.Percent_Party_Total = function(player_name, trackable, justify, raw) 34 | local player_total = DB.Data.Get(player_name, trackable, Column.Metric.TOTAL) 35 | local color = Column.String.Color_Zero(player_total) 36 | local party_total = 0 37 | for name, _ in pairs(DB.Tracking.Initialized_Players) do 38 | party_total = party_total + DB.Data.Get(name, trackable, Column.Metric.TOTAL) 39 | end 40 | if raw then return Column.String.Format_Percent(player_total, party_total) end 41 | return UI.TextColored(color, Column.String.Format_Percent(player_total, party_total, justify)) 42 | end 43 | 44 | ------------------------------------------------------------------------------------------------------ 45 | -- This is for cataloged actions. 46 | -- Grabs the total amount of damage a cataloged action has done for a given trackable and metric. 47 | ------------------------------------------------------------------------------------------------------ 48 | ---@param player_name string 49 | ---@param action_name string 50 | ---@param trackable string a trackable from the model. 51 | ---@param raw? boolean true: just output the raw value; false: output a column to a table. 52 | ---@return string 53 | ------------------------------------------------------------------------------------------------------ 54 | Column.General.Percent_Party_Total_Action = function(player_name, action_name, trackable, raw) 55 | local action_total = DB.Catalog.Get(player_name, trackable, action_name, Column.Metric.TOTAL) 56 | local color = Column.String.Color_Zero(action_total) 57 | local party_total = 0 58 | for name, _ in pairs(DB.Tracking.Initialized_Players) do 59 | party_total = party_total + DB.Data.Get(name, trackable, Column.Metric.TOTAL) 60 | end 61 | if raw then return Column.String.Format_Percent(action_total, party_total) end 62 | return UI.TextColored(color, Column.String.Format_Percent(action_total, party_total)) 63 | end 64 | 65 | ------------------------------------------------------------------------------------------------------ 66 | -- Takes the total metric from a pet specific trackable and divides by how much of the trackable the party has done. 67 | ------------------------------------------------------------------------------------------------------ 68 | ---@param player_name string 69 | ---@param pet_name string 70 | ---@param trackable string a trackable from the model. 71 | ---@param justify? boolean whether or not to right justify the text 72 | ---@param raw? boolean true: just output the raw value; false: output a column to a table. 73 | ---@return string 74 | ------------------------------------------------------------------------------------------------------ 75 | Column.General.Percent_Party_Total_Pet = function(player_name, pet_name, trackable, justify, raw) 76 | local pet_total = DB.Pet_Data.Get(player_name, pet_name, trackable, Column.Metric.TOTAL) 77 | local color = Column.String.Color_Zero(pet_total) 78 | local party_total = 0 79 | for name, _ in pairs(DB.Tracking.Initialized_Players) do 80 | party_total = party_total + DB.Data.Get(name, trackable, Column.Metric.TOTAL) 81 | end 82 | if raw then return Column.String.Format_Percent(pet_total, party_total) end 83 | return UI.TextColored(color, Column.String.Format_Percent(pet_total, party_total, justify)) 84 | end 85 | -------------------------------------------------------------------------------- /columns/healing.lua: -------------------------------------------------------------------------------- 1 | Column.Healing = T{} 2 | 3 | ------------------------------------------------------------------------------------------------------ 4 | -- Grabs the damage of a certain trackable that the entity has done. 5 | ------------------------------------------------------------------------------------------------------ 6 | ---@param player_name string 7 | ---@param percent? boolean whether or not the damage should be raw or percent. 8 | ---@param justify? boolean whether or not to right justify the text 9 | ---@param raw? boolean true: just output the raw value; false: output a column to a table. 10 | ---@return string 11 | ------------------------------------------------------------------------------------------------------ 12 | Column.Healing.Total = function(player_name, percent, justify, raw) 13 | local spell_healing = DB.Data.Get(player_name, DB.Enum.Trackable.HEALING, Column.Metric.TOTAL) 14 | local ability_healing = DB.Data.Get(player_name, DB.Enum.Trackable.ABILITY_HEALING, Column.Metric.TOTAL) 15 | local total_healing = spell_healing + ability_healing 16 | local color = Column.String.Color_Zero(total_healing) 17 | if percent then 18 | local total_damage = Column.Damage.Raw_Total_Player_Damage(player_name) 19 | if raw then return Column.String.Format_Percent(total_healing, total_damage) end 20 | return UI.TextColored(color, Column.String.Format_Percent(total_healing, total_damage, justify)) 21 | end 22 | if raw then return Column.String.Format_Number(total_healing) end 23 | return UI.TextColored(color, Column.String.Format_Number(total_healing, justify)) 24 | end 25 | 26 | ------------------------------------------------------------------------------------------------------ 27 | -- Grabs the overcure amount for the player. 28 | ------------------------------------------------------------------------------------------------------ 29 | ---@param player_name string 30 | ---@param justify? boolean whether or not to right justify the text 31 | ---@return string 32 | ------------------------------------------------------------------------------------------------------ 33 | Column.Healing.Overcure = function(player_name, justify) 34 | local overcure = DB.Data.Get(player_name, Column.Trackable.HEALING, Column.Metric.OVERCURE) 35 | local color = Column.String.Color_Zero(overcure) 36 | return UI.TextColored(color, Column.String.Format_Number(overcure, justify)) 37 | end -------------------------------------------------------------------------------- /columns/spell.lua: -------------------------------------------------------------------------------- 1 | Column.Spell = T{} 2 | 3 | ------------------------------------------------------------------------------------------------------ 4 | -- Shows MP a player has used. 5 | ------------------------------------------------------------------------------------------------------ 6 | ---@param player_name string 7 | ---@param magic_type string 8 | ---@param justify? boolean whether or not to right justify the text 9 | ---@return string 10 | ------------------------------------------------------------------------------------------------------ 11 | Column.Spell.MP = function(player_name, magic_type, justify) 12 | if not magic_type then magic_type = Column.Trackable.MAGIC end 13 | local mp = 0 14 | if magic_type == "Other" then 15 | local total = DB.Data.Get(player_name, Column.Trackable.MAGIC, Column.Metric.MP_SPENT) 16 | local healing = DB.Data.Get(player_name, Column.Trackable.HEALING, Column.Metric.MP_SPENT) 17 | local nuke = DB.Data.Get(player_name, Column.Trackable.NUKE, Column.Metric.MP_SPENT) 18 | local enfeeble = DB.Data.Get(player_name, Column.Trackable.ENFEEBLE, Column.Metric.MP_SPENT) 19 | local enspell = DB.Data.Get(player_name, Column.Trackable.ENSPELL, Column.Metric.MP_SPENT) 20 | local mp_drain = DB.Data.Get(player_name, Column.Trackable.MP_DRAIN, Column.Metric.MP_SPENT) 21 | mp = total - healing - nuke - enfeeble - enspell - mp_drain 22 | else 23 | mp = DB.Data.Get(player_name, magic_type, Column.Metric.MP_SPENT) 24 | end 25 | local color = Column.String.Color_Zero(mp) 26 | return UI.TextColored(color, Column.String.Format_Number(mp, justify)) 27 | end 28 | 29 | ------------------------------------------------------------------------------------------------------ 30 | -- Shows many much MP is used per damage or healing done. 31 | ------------------------------------------------------------------------------------------------------ 32 | ---@param player_name string 33 | ---@param magic_type string 34 | ---@return string 35 | ------------------------------------------------------------------------------------------------------ 36 | Column.Spell.Unit_Per_MP = function(player_name, magic_type) 37 | local mp = DB.Data.Get(player_name, magic_type, Column.Metric.MP_SPENT) 38 | local unit = DB.Data.Get(player_name, magic_type, Column.Metric.TOTAL) 39 | local color = Column.String.Color_Zero(unit) 40 | return UI.TextColored(color, Column.String.Format_Percent(unit, mp, false, true)) 41 | end -------------------------------------------------------------------------------- /columns/util.lua: -------------------------------------------------------------------------------- 1 | Column.Util = T{} 2 | 3 | ------------------------------------------------------------------------------------------------------ 4 | -- Switches to a player in the player filter based on partial matching. 5 | ------------------------------------------------------------------------------------------------------ 6 | ---@param player_name string 7 | ------------------------------------------------------------------------------------------------------ 8 | Column.Util.Focus = function(player_name) 9 | if not player_name then return nil end 10 | local focus_check = player_name 11 | player_name = string.lower(player_name) 12 | UI.PushID(player_name) 13 | if UI.SmallButton(" F ") then 14 | -- Default to the Overview tab when jumping from this column. 15 | Focus.Tabs.Switch[Focus.Tabs.Names.OVERVIEW] = ImGuiTabItemFlags_SetSelected 16 | 17 | -- If in multi-window mode toggle open and closing if the focus is already the given player. 18 | -- Always jump to Focus if in non-Window mode. 19 | if focus_check ~= DB.Widgets.Util.Get_Player_Focus() or not Metrics.Window.Multi_Window then 20 | DB.Widgets.Util.Player_Switch(player_name) 21 | Window_Manager.Switch_Module(Focus.Name) 22 | Focus.Window.Show() 23 | else 24 | Focus.Window.Toggle_Visibility() 25 | end 26 | end 27 | UI.PopID() 28 | end -------------------------------------------------------------------------------- /commands.lua: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------------------------------ 2 | -- Subscribe to addon commands. 3 | -- Influenced by HXUI: https://github.com/tirem/HXUI 4 | ------------------------------------------------------------------------------------------------------ 5 | ashita.events.register('command', 'command_cb', function (e) 6 | local command_args = e.command:lower():args() 7 | ---@diagnostic disable-next-line: undefined-field 8 | if table.contains({"/metrics"}, command_args[1]) or table.contains({"/met"}, command_args[1]) then 9 | local arg = command_args[2] 10 | local sub_command = command_args[3] 11 | 12 | -- Help Text 13 | if not arg then 14 | if Config.Settings_Mode ~= Config.Enum.File.CONFIG and Config.Window.Is_Visible() then 15 | Config.Settings_Mode = Config.Enum.File.CONFIG 16 | elseif Config.Settings_Mode ~= Config.Enum.File.CONFIG and not Config.Window.Is_Visible() then 17 | Config.Settings_Mode = Config.Enum.File.CONFIG 18 | Config.Window.Show() 19 | elseif Config.Settings_Mode == Config.Enum.File.CONFIG then 20 | Config.Window.Toggle_Visibility() 21 | end 22 | 23 | -- General Settings 24 | elseif arg == "show" or arg == "s" then 25 | Window_Manager.Toggle_Mask() 26 | elseif arg == "hub" then 27 | Hub.Window.Toggle_Visibility() 28 | elseif arg == "debug" then 29 | Debug.Toggle() 30 | elseif arg == "nano" or arg == "n" then 31 | Parse.Nano.Toggle() 32 | elseif arg == "mini" or arg == "m" then 33 | Parse.Mini.Toggle() 34 | elseif arg == "reset" or arg == "r" then 35 | DB.Initialize(true) 36 | elseif arg == "full" or arg == "f" then 37 | Parse.Full.Enable() 38 | elseif (arg == "pet" or arg == "p") then 39 | Parse.Config.Toggle_Pet() 40 | elseif arg == "clock" or arg == "c" then 41 | Parse.Config.Toggle_Clock() 42 | elseif arg == "percent" then 43 | Focus.Config.Percent_Toggle() 44 | elseif arg == "dps" then 45 | Metrics.Parse.DPS = not Metrics.Parse.DPS 46 | Parse.Util.Calculate_Column_Flags() 47 | elseif arg == "speed" then 48 | Metrics.Parse.Attack_Speed = not Metrics.Parse.Attack_Speed 49 | Parse.Util.Calculate_Column_Flags() 50 | elseif arg == "throttle" then 51 | Throttle.Toggle() 52 | elseif arg == "lurk" then 53 | Metrics.Parse.Lurk_Mode = not Metrics.Parse.Lurk_Mode 54 | elseif arg == "mouse" then 55 | Window_Manager.Toggle_Mouse() 56 | 57 | -- XP 58 | elseif arg == "xp" and sub_command then 59 | if sub_command == "mini" then 60 | Metrics.XP.XP_Mini = not Metrics.XP.XP_Mini 61 | end 62 | 63 | -- General reports. 64 | elseif arg == "report" or arg == "rep" then 65 | local report_type = command_args[3] 66 | if report_type == "total" then 67 | Report.Publishing.Total_Damage() 68 | elseif report_type == "acc" then 69 | Report.Publishing.Accuracy() 70 | elseif report_type == "melee" then 71 | Report.Publishing.Damage_By_Type(DB.Enum.Trackable.MELEE) 72 | elseif report_type == "ws" then 73 | Report.Publishing.Damage_By_Type(DB.Enum.Trackable.WS) 74 | elseif report_type == "healing" then 75 | Report.Publishing.Damage_By_Type(DB.Enum.Trackable.HEALING) 76 | end 77 | 78 | -- Primary module switching. 79 | elseif arg == "team" or arg == "parse" then Parse.Window.Make_Active() 80 | elseif arg == "focus" then Focus.Window.Make_Active() 81 | elseif arg == "log" or arg == "bl" then Blog.Window.Make_Active() 82 | elseif arg == "xp" then XP.Window.Make_Active() 83 | elseif arg == "report" or arg == "rep" then Report.Window.Make_Active() 84 | 85 | -- Player selection 86 | elseif arg == "player" or arg == "pl" then 87 | local player_string = command_args[3] 88 | Debug.Error.Add("Metrics Command: " .. tostring(arg) .. " " .. tostring(command_args[3])) 89 | if player_string then 90 | DB.Widgets.Util.Player_Switch(player_string) 91 | end 92 | 93 | -- Focus tab switching. 94 | elseif arg == "melee" then 95 | Focus.Tabs.Switch[Focus.Tabs.Names.MELEE] = ImGuiTabItemFlags_SetSelected 96 | elseif arg == "ranged" then 97 | Focus.Tabs.Switch[Focus.Tabs.Names.RANGED] = ImGuiTabItemFlags_SetSelected 98 | elseif arg == "ws" or arg == "weaponskill" then 99 | Focus.Tabs.Switch[Focus.Tabs.Names.WS] = ImGuiTabItemFlags_SetSelected 100 | elseif arg == "magic" then 101 | Focus.Tabs.Switch[Focus.Tabs.Names.MAGIC] = ImGuiTabItemFlags_SetSelected 102 | elseif arg == "ability" or arg == "abil" then 103 | Focus.Tabs.Switch[Focus.Tabs.Names.ABILITIES] = ImGuiTabItemFlags_SetSelected 104 | elseif (arg == "pet" or arg == "p") and Window_Manager.Tabs.Active == Focus.Name then 105 | Focus.Tabs.Switch[Focus.Tabs.Names.PETS] = ImGuiTabItemFlags_SetSelected 106 | elseif arg == "defense" or arg == "def" then 107 | Focus.Tabs.Switch[Focus.Tabs.Names.DEFENSE] = ImGuiTabItemFlags_SetSelected 108 | end 109 | end 110 | end) -------------------------------------------------------------------------------- /database/_database.lua: -------------------------------------------------------------------------------- 1 | DB = T{} 2 | 3 | -- Primary Database 4 | DB.Parse = T{} -- [index][trackable][metric] 5 | -- [index][trackable][m.Enum.Node.CATALOG][action_name][metric] 6 | DB.Pet_Parse = T{} -- [index][pet][trackable][metric] 7 | -- [index][pet][trackable][m.Enum.Node.CATALOG][action_name][metric] 8 | 9 | -- Secondary Tracking Tables 10 | DB.Tracking = T{} 11 | DB.Tracking.Trackable = T{} -- [trackable][player_name] 12 | DB.Tracking.Pet_Trackable = T{} -- [trackable][player_name][pet_name] 13 | DB.Tracking.Initialized_Players = T{} -- [player_name] 14 | DB.Tracking.Initialized_Pets = T{} -- [player_name][pet_name] 15 | DB.Tracking.Initialized_Mobs = T{} -- [mob_name] 16 | DB.Tracking.Running_Accuracy = T{} -- [player_name] 17 | DB.Tracking.Running_Attack_Speed = T{} -- [player_name] 18 | DB.Tracking.Running_Damage = T{} -- [player_name] 19 | DB.Tracking.Multi_Attack = T{} -- [player_name][multi-rank] 20 | DB.Tracking.Defeated_Mobs = T{} -- [mob_name] 21 | 22 | -- Used to hold column data for performance improvements. 23 | DB.Cache = T{} -- [player_name][trackable][metric] 24 | 25 | DB.Settings = T{} 26 | DB.Settings.Accuracy_Warning = 0.80 27 | 28 | -- These are used for user saved settings. 29 | DB.Defaults = T{ 30 | Running_Accuracy_Limit = 25 31 | } 32 | 33 | require("database._enum") 34 | require("database.accuracy") 35 | require("database.dps") 36 | require("database.attack_speed") 37 | require("database.catalog") 38 | require("database.data") 39 | require("database.lists") 40 | require("database.pet_catalog") 41 | require("database.pet_data") 42 | require("database.widgets") 43 | 44 | ------------------------------------------------------------------------------------------------------ 45 | -- Resets the parsing data and clears the battle log. 46 | ------------------------------------------------------------------------------------------------------ 47 | ---@param reset? boolean true: manual reset; false: normal initialization 48 | ------------------------------------------------------------------------------------------------------ 49 | DB.Initialize = function(reset) 50 | if Metrics.Report.Auto_Save and reset then 51 | File.Save_Data() 52 | File.Save_Catalog() 53 | File.Save_Battlelog() 54 | end 55 | 56 | DB.Parse = T{} 57 | DB.Pet_Parse = T{} 58 | 59 | DB.Tracking.Trackable = T{} 60 | DB.Tracking.Pet_Trackable = T{} 61 | DB.Tracking.Initialized_Players = T{} 62 | DB.Tracking.Initialized_Pets = T{} 63 | DB.Tracking.Initialized_Mobs = T{[DB.Widgets.Dropdown.Enum.NONE] = true} 64 | DB.Tracking.Running_Accuracy = T{} 65 | DB.Tracking.Running_Damage = T{} 66 | DB.Tracking.Multi_Attack = T{} 67 | DB.Tracking.Defeated_Mobs = T{} 68 | 69 | DB.Sorted.Players = T{[1] = DB.Widgets.Dropdown.Enum.NONE} 70 | DB.Sorted.Mobs = T{[1] = DB.Widgets.Dropdown.Enum.NONE} 71 | DB.Sorted.Total_Damage = T{} 72 | DB.Sorted.Catalog_Damage = T{} 73 | 74 | DB.Healing_Max = {} 75 | DB.Widgets.Dropdown.Player.Focus = DB.Widgets.Dropdown.Enum.NONE 76 | DB.Widgets.Dropdown.Player.Index = 1 77 | DB.Widgets.Dropdown.Mob.Focus = DB.Widgets.Dropdown.Enum.NONE 78 | DB.Widgets.Dropdown.Mob.Index = 1 79 | for spell, threshold in pairs(DB.Enum.HEALING) do 80 | DB.Healing_Max[spell] = threshold 81 | end 82 | Blog.Reset_Log() 83 | DB.Attack_Speed.Reset() 84 | Timers.Reset(Timers.Enum.Names.PARSE) 85 | end 86 | 87 | ------------------------------------------------------------------------------------------------------ 88 | -- Calculates the total damage from everyone currently on the Parse display. 89 | ------------------------------------------------------------------------------------------------------ 90 | ---@return number 91 | ------------------------------------------------------------------------------------------------------ 92 | DB.Team_Damage = function() 93 | local total = 0 94 | DB.Lists.Sort.Total_Damage() 95 | for _, data in ipairs(DB.Sorted.Total_Damage) do 96 | local player_name = data[1] 97 | if Parse.Config.Include_SC_Damage() then 98 | total = total + DB.Data.Get(player_name, DB.Enum.Trackable.TOTAL, DB.Enum.Metric.TOTAL) 99 | else 100 | total = total + DB.Data.Get(player_name, DB.Enum.Trackable.TOTAL_NO_SC, DB.Enum.Metric.TOTAL) 101 | end 102 | end 103 | return total 104 | end 105 | 106 | ------------------------------------------------------------------------------------------------------ 107 | -- Calculates the total damage by type from everyone currently on the Parse display. 108 | ------------------------------------------------------------------------------------------------------ 109 | ---@return number 110 | ------------------------------------------------------------------------------------------------------ 111 | DB.Team_Damage_By_Type = function(damage_type) 112 | local total = 0 113 | DB.Lists.Sort.Total_Damage() 114 | for rank, data in ipairs(DB.Sorted.Total_Damage) do 115 | if rank <= Parse.Config.Rank_Cutoff() then 116 | local player_name = data[1] 117 | total = total + DB.Data.Get(player_name, damage_type, DB.Enum.Metric.TOTAL) 118 | end 119 | end 120 | return total 121 | end 122 | 123 | ------------------------------------------------------------------------------------------------------ 124 | -- Keeps track of how many mobs have been defeated. 125 | ------------------------------------------------------------------------------------------------------ 126 | ---@param mob_name string 127 | ------------------------------------------------------------------------------------------------------ 128 | DB.Defeated_Mob = function(mob_name) 129 | if not DB.Tracking.Defeated_Mobs[mob_name] then DB.Tracking.Defeated_Mobs[mob_name] = 0 end 130 | DB.Tracking.Defeated_Mobs[mob_name] = DB.Tracking.Defeated_Mobs[mob_name] + 1 131 | end -------------------------------------------------------------------------------- /database/_enum.lua: -------------------------------------------------------------------------------- 1 | DB.Enum = T{} 2 | 3 | DB.Enum.Mode = T{ 4 | INC = "inc", 5 | SET = "set", 6 | } 7 | 8 | DB.Enum.Trackable = T{ 9 | TOTAL = "Total", 10 | TOTAL_NO_SC = "No SC Total", 11 | MELEE = "Melee", -- Melee 12 | MELEE_MAIN = "Melee Mainhand", 13 | MELEE_OFFHAND = "Melee Offhand", 14 | MELEE_KICK = "Melee Kicks", 15 | PET_MELEE = "Pet Melee", 16 | PET_MELEE_DISCRETE = "Pet Melee Discrete", 17 | MELEE_COUNTERED = "Countered", 18 | RANGED = "Ranged", -- Ranged 19 | RANGED_SQUARE = "Ranged Square Hit", 20 | RANGED_TRUE = "Ranged True Strike", 21 | PET_RANGED = "Pet Ranged", 22 | THROWING = "Throwing", 23 | WS = "Weaponskills", -- TP Action 24 | PET_WS = "Pet Weaponskills", 25 | SC = "Skillchains", 26 | ABILITY = "Abilities", -- Ability 27 | ABILITY_DAMAGING = "Damaging Abilities", 28 | ABILITY_HEALING = "Healing Abilities", 29 | ABILITY_MP_RECOVERY = "MP Recovery Abilities", 30 | ABILITY_GENERAL = "General Ability", 31 | MANEUVER = "Maneuver", 32 | PHANTOM_ROLL = "Corsair Roll", 33 | PET = "Pet", -- Pets 34 | PET_ABILITY = "Pet Ability", 35 | PET_HEAL = "Pet Healing", 36 | PET_NUKE = "Pet Nuking", 37 | PET_ENFEEBLING = "Pet Enfeebling", 38 | PET_MP_DRAIN = "Pet MP Drain", 39 | PET_MAGIC = "Pet Magic", 40 | MAGIC = "Spells", -- Magic 41 | ENSPELL = "Enspell", 42 | ENDAMAGE = "Melee Endamage", 43 | ENDAMAGE_R = "Ranged Endamage", 44 | ENDRAIN = "Melee Endrain", 45 | ENDRAIN_R = "Ranged Endrain", 46 | ENASPIR = "Melee Enaspir", 47 | ENASPIR_R = "Ranged Enaspir", 48 | ENDEBUFF = "Melee Debuff", 49 | ENDEBUFF_R = "Ranged Debuff", 50 | NUKE = "Nuking", 51 | HEALING = "Healing", 52 | ALL_HEAL = "Combined Healing", 53 | ENFEEBLE = "Enfeebling", 54 | BUFF_SONG = "BRD Buff Song", 55 | DEBUFF_REMOVAL = "Debuff Removal", 56 | BUFF_SPELL = "Buff Spell", 57 | MP_DRAIN = "MP Drain", 58 | OUTGOING_SPIKE_DMG = "Outgoing Spike Damage", 59 | HEALING_RECEIVED = "Healing Received", 60 | DAMAGE_TAKEN_TOTAL = "Total Damage Taken", -- Defense 61 | DMG_TAKEN_TOTAL_PET = "Total Pet Damage Taken", 62 | MELEE_DMG_TAKEN = "Melee Damage Taken", 63 | MELEE_PET_DMG_TAKEN = "Melee Pet Damage Taken", 64 | DEF_EVASION = "Evasion", 65 | DEF_PARRY = "Parry", 66 | DEF_SHADOWS = "Shadow Absorption", 67 | DEF_COUNTER = "Counter", 68 | DEF_GUARD = "Guard", 69 | DEF_BLOCK = "Shield Block", 70 | DEF_CRIT = "Crits Taken", 71 | DEF_UNMITIGATED = "Unmitigated Melee Damage Taken", 72 | INCOMING_SPIKE_DMG = "Incoming Spike Damage", 73 | SPELL_DMG_TAKEN = "Spell Damage Taken", 74 | SPELL_PET_DMG_TAKEN = "Spell Pet Damage Taken", 75 | DEF_NO_DMG_SPELLS = "No Damage Spells", 76 | DEF_MP_DRAIN = "Player MP Drained", 77 | DEF_ENFEEBLE = "Player Enfeebled", 78 | -- SPELL_ENF_RESIST = "Enfeeble Resist" 79 | TP_DMG_TAKEN = "TP Move Damage Taken", 80 | PET_TP_DMG_TAKEN = "Pet TP Move Damage Taken", 81 | DEATH = "Death", -- Misc 82 | DEFAULT = "Default", 83 | } 84 | 85 | DB.Enum.Metric = T{ 86 | TOTAL = "Total", 87 | COUNT = "Attempts", 88 | AOE_COUNT = "AOE Targets Hit", 89 | CYCLE = "Melee Cycles", -- How many times a melee cycle occurred. 90 | ROUNDS = "Attack Rounds", -- Used in multi-attacks 91 | MULTI_TOTAL = "Multi-Attack", 92 | MULT_ATK_1 = "Single", 93 | MULT_ATK_2 = "Double", 94 | MULT_ATK_3 = "Triple", 95 | MULT_ATK_4 = "Quad", 96 | MULT_ATK_5 = "Mult. V", 97 | MULT_ATK_6 = "Mult. VI", 98 | MULT_ATK_7 = "Mult. VII", 99 | MULT_ATK_8 = "Mult. VIII", 100 | GUARD = "Guard", 101 | HIT_COUNT = "Hits", 102 | SHOT_DISTANCE = "Shot Distance", 103 | CRIT_COUNT = "Crit Count", 104 | CRIT_DAMAGE = "Crit Damage", 105 | SHADOWS = "Shadow Absorption", 106 | MOB_HEAL = "Mob Heal", 107 | MIN = "Min", 108 | MAX = "Max", 109 | BURST_COUNT = "Burst Count", 110 | BURST_DAMAGE = "Burst Damage", 111 | OVERCURE = "Overcure", 112 | MP_SPENT = "MP Spent", 113 | TP_SPENT = "TP Spent", 114 | SC_OPENED = "Skillchains Opened", 115 | SC_CLOSED = "Skillchains Closed", 116 | OVERLOAD = "Maneuver Overload", 117 | PHANTOM_ROLL_FIRST_ROLL = "Phantom Roll First Rolls", 118 | PHANTOM_ROLL_REROLL = "Phantom Roll Rerolls", 119 | BUST_COUNT = "COR Roll Bust Count", 120 | LUCKY_COUNT = "COR Roll Lucky Count", 121 | UNLUCKY_COUNT = "COR Roll Unlucky Count", 122 | LUCKY_11_COUNT = "COR Roll Lucky 11 Count", 123 | } 124 | 125 | DB.Enum.Pet_Single_Trackable = T{ 126 | PET_WS = DB.Enum.Trackable.PET_WS, 127 | PET_ABILITY = DB.Enum.Trackable.PET_ABILITY, 128 | PET_HEAL = DB.Enum.Trackable.PET_HEAL, 129 | PET_NUKE = DB.Enum.Trackable.PET_NUKE, 130 | PET_ENFEEBLING = DB.Enum.Trackable.PET_ENFEEBLING, 131 | PET_MP_DRAIN = DB.Enum.Trackable.PET_MP_DRAIN, 132 | PET_MAGIC = DB.Enum.Trackable.PET_MAGIC, 133 | } 134 | 135 | DB.Enum.Values = T{ 136 | CATALOG = "catalog", 137 | PET_CATALOG = "pet_catalog", 138 | DEBUG = "Debug", 139 | IGNORE = 'ignore', 140 | COMBINED = 'combined', 141 | MAX_DAMAGE = 100000, 142 | } 143 | 144 | DB.Enum.HEALING = T{ 145 | ["Cure"] = 50, -- 35 146 | ["Cure II"] = 150, -- 102 147 | ["Cure III"] = 250, -- 212 148 | ["Cure IV"] = 500, -- 430 149 | ["Cure V"] = 1300, 150 | ["Cure VI"] = 1500, 151 | ["Curaga"] = 150, -- 102 152 | ["Curaga II"] = 300, -- 213 153 | ["Curaga III"] = 400, 154 | ["Curaga IV"] = 500, 155 | ["Curaga V"] = 800, 156 | } 157 | 158 | DB.Healing_Max = T{ 159 | ["Cure"] = 50, 160 | ["Cure II"] = 150, 161 | ["Cure III"] = 250, 162 | ["Cure IV"] = 500, 163 | ["Cure V"] = 1300, 164 | ["Cure VI"] = 1500, 165 | ["Curaga"] = 150, 166 | ["Curaga II"] = 300, 167 | ["Curaga III"] = 400, 168 | ["Curaga IV"] = 500, 169 | ["Curaga V"] = 800, 170 | } -------------------------------------------------------------------------------- /database/accuracy.lua: -------------------------------------------------------------------------------- 1 | DB.Accuracy = T{} 2 | 3 | ------------------------------------------------------------------------------------------------------ 4 | -- Keeps a tally of the last running accuracy limit amount of hit attempts. 5 | -- This is called by the action handling functions. 6 | ------------------------------------------------------------------------------------------------------ 7 | ---@param player_name string primary index for the Running_Accuracy_Data table 8 | ---@param hit boolean if true then there was a hit; miss otherwise 9 | ---@return boolean 10 | ------------------------------------------------------------------------------------------------------ 11 | DB.Accuracy.Update = function(player_name, hit) 12 | if not DB.Tracking.Running_Accuracy[player_name] then 13 | Debug.Error.Add("Update.Running_Accuracy: {" .. tostring(player_name) .. "} is missing in Data.Running_Accuracy.") 14 | return false 15 | end 16 | local max = #DB.Tracking.Running_Accuracy[player_name] 17 | if max >= Metrics.Model.Running_Accuracy_Limit then table.remove(DB.Tracking.Running_Accuracy[player_name], Metrics.Model.Running_Accuracy_Limit) end 18 | table.insert(DB.Tracking.Running_Accuracy[player_name], 1, hit) 19 | return true 20 | end 21 | 22 | ------------------------------------------------------------------------------------------------------ 23 | -- Returns the players accuracy for the last running accuracy limit amount of attempts. 24 | ------------------------------------------------------------------------------------------------------ 25 | ---@param player_name string primary index for the Running_Accuracy_Data table 26 | ---@return table {hits, count} 27 | ------------------------------------------------------------------------------------------------------ 28 | DB.Accuracy.Get = function(player_name) 29 | -- This error can occur in mini mode when trying to load data before the player has been initialized. Not a big deal. 30 | if not DB.Tracking.Running_Accuracy[player_name] then 31 | Debug.Error.Add("Get.Running_Accuracy: Attempt to get {" .. tostring(player_name) .. "} running accuracy, but it didn't exist.") 32 | return {0, 0} 33 | end 34 | local hits = 0 35 | local count = 0 36 | 37 | -- Tally how hits the player had in the last {running accuracy limit} amount of attempts. 38 | for _, value in pairs(DB.Tracking.Running_Accuracy[player_name]) do 39 | if value then hits = hits + 1 end 40 | count = count + 1 41 | end 42 | 43 | return {hits, count} 44 | end -------------------------------------------------------------------------------- /database/attack_speed.lua: -------------------------------------------------------------------------------- 1 | DB.Attack_Speed = T{} 2 | 3 | DB.Attack_Speed.Players = T{} 4 | DB.Attack_Speed.Timestamp = T{} 5 | DB.Attack_Speed.Max_Windows = 3 6 | DB.Attack_Speed.Timeout = 15 -- Treshold in seconds to throw away a value (in between pulls or something). 7 | 8 | ------------------------------------------------------------------------------------------------------ 9 | -- Resets the attack speed globals. 10 | ------------------------------------------------------------------------------------------------------ 11 | DB.Attack_Speed.Reset = function() 12 | DB.Attack_Speed.Players = T{} 13 | DB.Attack_Speed.Timestamp = T{} 14 | end 15 | 16 | ------------------------------------------------------------------------------------------------------ 17 | -- Keeps a tally of the player's attack speed. 18 | ------------------------------------------------------------------------------------------------------ 19 | ---@param player_name string 20 | ------------------------------------------------------------------------------------------------------ 21 | DB.Attack_Speed.Update = function(player_name) 22 | if not DB.Tracking.Running_Attack_Speed[player_name] then 23 | Debug.Error.Add("Attack_Speed.Update: {" .. tostring(player_name) .. "} is missing in Tracking.Attack_Speed.") 24 | return false 25 | end 26 | 27 | -- Capture the rate. 28 | local rate = 0 29 | local skip = false 30 | local timestamp = DB.Attack_Speed.Timestamp[player_name] 31 | if timestamp then 32 | rate = Socket.gettime() - timestamp 33 | if rate > DB.Attack_Speed.Timeout then skip = true end 34 | else 35 | skip = true 36 | end 37 | timestamp = Socket.gettime() 38 | DB.Attack_Speed.Timestamp[player_name] = timestamp 39 | if skip then return false end 40 | 41 | -- Add the new speed to the attack speed tracking buckets. 42 | local size = #DB.Tracking.Running_Attack_Speed[player_name] 43 | if size >= DB.Attack_Speed.Max_Windows then table.remove(DB.Tracking.Running_Attack_Speed[player_name], DB.Attack_Speed.Max_Windows) end 44 | table.insert(DB.Tracking.Running_Attack_Speed[player_name], 1, rate) 45 | local new_size = #DB.Tracking.Running_Attack_Speed[player_name] 46 | 47 | -- Average the attack speed. 48 | local total = 0 49 | for _, attack_speed in pairs(DB.Tracking.Running_Attack_Speed[player_name]) do 50 | total = total + attack_speed 51 | end 52 | local average = total / new_size 53 | DB.Attack_Speed.Players[player_name] = average 54 | 55 | return true 56 | end 57 | 58 | ------------------------------------------------------------------------------------------------------ 59 | -- Retrieves a player's attack speed. 60 | ------------------------------------------------------------------------------------------------------ 61 | ---@param player_name string 62 | ------------------------------------------------------------------------------------------------------ 63 | DB.Attack_Speed.Get = function(player_name) 64 | local speed = DB.Attack_Speed.Players[player_name] 65 | if not speed then speed = 0 end 66 | return speed 67 | end -------------------------------------------------------------------------------- /database/pet_data.lua: -------------------------------------------------------------------------------- 1 | DB.Pet_Data = T{} 2 | 3 | ------------------------------------------------------------------------------------------------------ 4 | -- Initializes an [actor:target][pet_name] combination in the primary data node and catalog nodes. 5 | -- Also initializes separate tracking globals for Running Accuracy. 6 | -- If the "actor:target" combo has already been initialized then this will quit out early. 7 | -- CALLED BY: Init.Data 8 | ------------------------------------------------------------------------------------------------------ 9 | ---@param index string "actor_name:target_name" 10 | ---@param player_name? string used for maintaining various player indexed tables. In the case of pets this will be the owner. 11 | ---@param pet_name string used for maintaining various pet indexed tables. 12 | ------------------------------------------------------------------------------------------------------ 13 | DB.Pet_Data.Init = function(index, player_name, pet_name) 14 | if not index or not pet_name then 15 | Debug.Error.Add("Pet_Data.Init: {" .. tostring(player_name) .. " {" .. tostring(pet_name) .. "} nil index passed in." ) 16 | return false 17 | end 18 | 19 | if not DB.Pet_Parse[index] then DB.Pet_Parse[index] = {} end 20 | if DB.Pet_Parse[index][pet_name] then return false end 21 | 22 | DB.Pet_Parse[index][pet_name] = {} 23 | 24 | -- Initialize data nodes 25 | for _, trackable in pairs(DB.Enum.Trackable) do 26 | DB.Pet_Parse[index][pet_name][trackable] = {} 27 | DB.Pet_Parse[index][pet_name][trackable][DB.Enum.Values.CATALOG] = {} 28 | for _, metric in pairs(DB.Enum.Metric) do 29 | DB.Pet_Data.Set(0, index, pet_name, trackable, metric) 30 | end 31 | end 32 | 33 | -- Need to set minimum high manually to capture accurate minimums. 34 | DB.Pet_Data.Set(DB.Enum.Values.MAX_DAMAGE, index, pet_name, DB.Enum.Trackable.PET_WS, DB.Enum.Metric.MIN) 35 | DB.Pet_Data.Set(DB.Enum.Values.MAX_DAMAGE, index, pet_name, DB.Enum.Trackable.PET_ABILITY, DB.Enum.Metric.MIN) 36 | DB.Pet_Data.Set(DB.Enum.Values.MAX_DAMAGE, index, pet_name, DB.Enum.Trackable.PET_HEAL, DB.Enum.Metric.MIN) 37 | DB.Pet_Data.Set(DB.Enum.Values.MAX_DAMAGE, index, pet_name, DB.Enum.Trackable.PET_NUKE, DB.Enum.Metric.MIN) 38 | DB.Pet_Data.Set(DB.Enum.Values.MAX_DAMAGE, index, pet_name, DB.Enum.Trackable.MELEE_PET_DMG_TAKEN, DB.Enum.Metric.MIN) 39 | DB.Pet_Data.Set(DB.Enum.Values.MAX_DAMAGE, index, pet_name, DB.Enum.Trackable.SPELL_PET_DMG_TAKEN, DB.Enum.Metric.MIN) 40 | DB.Pet_Data.Set(DB.Enum.Values.MAX_DAMAGE, index, pet_name, DB.Enum.Trackable.PET_TP_DMG_TAKEN, DB.Enum.Metric.MIN) 41 | 42 | -- Initialize pet tracking tables. 43 | if player_name and not DB.Tracking.Initialized_Pets[player_name] then 44 | DB.Tracking.Initialized_Pets[player_name] = {} 45 | end 46 | if player_name and not DB.Tracking.Initialized_Pets[player_name][pet_name] then 47 | DB.Tracking.Initialized_Pets[player_name][pet_name] = true 48 | end 49 | end 50 | 51 | ------------------------------------------------------------------------------------------------------ 52 | -- Directly sets a pet's trackables metric to a specified value. 53 | ------------------------------------------------------------------------------------------------------ 54 | ---@param value number the value to set the node to. 55 | ---@param index string "actor_name:target_name". 56 | ---@param pet_name string 57 | ---@param trackable string a tracked item from the trackable list. 58 | ---@param metric string a trackable's metric from the metric 59 | ---@return boolean 60 | ------------------------------------------------------------------------------------------------------ 61 | DB.Pet_Data.Set = function(value, index, pet_name, trackable, metric) 62 | if not value or not index or not pet_name or not trackable or not metric then 63 | Debug.Error.Add("Set.Pet_Data: {" .. tostring(index) .. "} {" .. tostring(trackable) .. "} nil required parameter passed in." ) 64 | return false 65 | end 66 | DB.Pet_Parse[index][pet_name][trackable][metric] = value 67 | return true 68 | end 69 | 70 | ------------------------------------------------------------------------------------------------------ 71 | -- Increments a pet's trackables metric by a specified amount. 72 | ------------------------------------------------------------------------------------------------------ 73 | ---@param value number the value to increment the node by. 74 | ---@param index string "player_name:mob_name" 75 | ---@param pet_name string 76 | ---@param trackable string a tracked item from the trackable list. 77 | ---@param metric string a trackable's metric from the metric list. 78 | ---@return boolean 79 | ------------------------------------------------------------------------------------------------------ 80 | DB.Pet_Data.Inc = function(value, index, pet_name, trackable, metric) 81 | if not value or not index or not pet_name or not trackable or not metric then 82 | Debug.Error.Add("Inc.Pet_Data: {" .. tostring(index) .. "} {" .. tostring(pet_name) .. "} {" .. tostring(trackable) .. "} nil required parameter passed in." ) 83 | return false 84 | end 85 | DB.Pet_Parse[index][pet_name][trackable][metric] = DB.Pet_Parse[index][pet_name][trackable][metric] + value 86 | return true 87 | end 88 | 89 | ------------------------------------------------------------------------------------------------------ 90 | -- Gets data from a pet's trackable metric. 91 | -- If the mob filter is set then only actions towards that mob are counted. 92 | -- Consider that not every player:mob index will have a pet node. 93 | ------------------------------------------------------------------------------------------------------ 94 | ---@param player_name string the player or entity name to search data for. 95 | ---@param pet_name string 96 | ---@param trackable string a tracked item from the trackable list. 97 | ---@param metric string a trackable's metric from the metric list. 98 | ---@return number 99 | ------------------------------------------------------------------------------------------------------ 100 | DB.Pet_Data.Get = function(player_name, pet_name, trackable, metric) 101 | local total = 0 102 | local mob_focus = DB.Widgets.Util.Get_Mob_Focus() 103 | for index, _ in pairs(DB.Pet_Parse) do 104 | if mob_focus == DB.Widgets.Dropdown.Enum.NONE then 105 | if string.find(index, player_name .. ":") then 106 | if DB.Pet_Parse[index][pet_name] then 107 | total = total + DB.Pet_Parse[index][pet_name][trackable][metric] 108 | end 109 | end 110 | else 111 | if string.find(index, player_name .. ":" .. mob_focus) then 112 | if DB.Pet_Parse[index][pet_name] then 113 | total = total + DB.Pet_Parse[index][pet_name][trackable][metric] 114 | end 115 | end 116 | end 117 | end 118 | return total 119 | end -------------------------------------------------------------------------------- /database/widgets.lua: -------------------------------------------------------------------------------- 1 | DB.Widgets = T{} 2 | 3 | DB.Widgets.Util = T{} 4 | 5 | DB.Widgets.Dropdown = T{} 6 | DB.Widgets.Dropdown.Enum = T{ 7 | MOB = "Mob Filter", 8 | FOCUS = "Player", 9 | NONE = "!NONE", 10 | } 11 | DB.Widgets.Dropdown.Width = 150 12 | DB.Widgets.Dropdown.Flags = ImGuiComboFlags_None 13 | DB.Widgets.Dropdown.Player = T{} 14 | DB.Widgets.Dropdown.Player.Focus = DB.Widgets.Dropdown.Enum.NONE 15 | DB.Widgets.Dropdown.Player.Index = 1 16 | DB.Widgets.Dropdown.Mob = T{} 17 | DB.Widgets.Dropdown.Mob.Focus = DB.Widgets.Dropdown.Enum.NONE 18 | DB.Widgets.Dropdown.Mob.Index = 1 19 | 20 | ------------------------------------------------------------------------------------------------------ 21 | -- Creates a dropdown menu to show only damage done to a certain mob. 22 | ------------------------------------------------------------------------------------------------------ 23 | DB.Widgets.Mob_Filter = function() 24 | local list = DB.Lists.Get.Mob() 25 | local flags = DB.Widgets.Dropdown.Flags 26 | if list[1] then 27 | UI.SetNextItemWidth(DB.Widgets.Dropdown.Width) 28 | if UI.BeginCombo(DB.Widgets.Dropdown.Enum.MOB, list[DB.Widgets.Dropdown.Mob.Index], flags) then 29 | for n = 1, #list, 1 do 30 | local is_selected = DB.Widgets.Dropdown.Mob.Index == n 31 | if UI.Selectable(list[n], is_selected) then 32 | DB.Widgets.Dropdown.Mob.Index = n 33 | DB.Widgets.Dropdown.Mob.Focus = list[n] 34 | end 35 | if is_selected then 36 | UI.SetItemDefaultFocus() 37 | end 38 | end 39 | UI.EndCombo() 40 | end 41 | else 42 | if UI.BeginCombo(DB.Widgets.Dropdown.Enum.MOB, DB.Widgets.Dropdown.Enum.NONE, flags) then 43 | UI.EndCombo() 44 | end 45 | end 46 | DB.Widgets.Mob_Filter_Help_Text() 47 | end 48 | 49 | ------------------------------------------------------------------------------------------------------ 50 | -- Shows the help text for the mob filter. 51 | ------------------------------------------------------------------------------------------------------ 52 | DB.Widgets.Mob_Filter_Help_Text = function() 53 | UI.SameLine() Window_Manager.Widgets.HelpMarker("You can filter to show only data for actions taken against mobs with a specific name.\n" 54 | .. "Notes:\n" 55 | .. "1. The filter may not be for individual mobs. It is for mobs with that name collectively.\n" 56 | .. "2. If the mob has a unique name (like an NM) then the data will be mob specific.\n" 57 | .. "3. The filter only affects actions taken against mobs with that name.\n" 58 | .. "4. The filter does not work for healing because those actions are taken on other players.\n" 59 | .. "5. The filter does not work for abilities that are used on yourself or other players.\n") 60 | end 61 | 62 | ------------------------------------------------------------------------------------------------------ 63 | -- Utility function for accessing the name of the currently focused mob. 64 | ------------------------------------------------------------------------------------------------------ 65 | DB.Widgets.Util.Get_Mob_Focus = function() 66 | return DB.Widgets.Dropdown.Mob.Focus 67 | end 68 | 69 | ------------------------------------------------------------------------------------------------------ 70 | -- Creates a dropdown menu to show only damage done by a certain entity. 71 | ------------------------------------------------------------------------------------------------------ 72 | DB.Widgets.Player_Filter = function() 73 | local list = DB.Lists.Get.Players() 74 | local flags = DB.Widgets.Dropdown.Flags 75 | if list[1] then 76 | UI.SetNextItemWidth(DB.Widgets.Dropdown.Width) 77 | if UI.BeginCombo(DB.Widgets.Dropdown.Enum.FOCUS, list[DB.Widgets.Dropdown.Player.Index], flags) then 78 | for n = 1, #list, 1 do 79 | local is_selected = DB.Widgets.Dropdown.Player.Index == n 80 | if UI.Selectable(list[n], is_selected) then 81 | DB.Widgets.Dropdown.Player.Index = n 82 | DB.Widgets.Dropdown.Player.Focus = list[n] 83 | end 84 | if is_selected then 85 | UI.SetItemDefaultFocus() 86 | end 87 | end 88 | UI.EndCombo() 89 | end 90 | else 91 | if UI.BeginCombo(DB.Widgets.Dropdown.Enum.FOCUS, DB.Widgets.Dropdown.Enum.NONE, flags) then 92 | UI.EndCombo() 93 | end 94 | end 95 | DB.Widgets.Player_Filter_Help_Text() 96 | end 97 | 98 | ------------------------------------------------------------------------------------------------------ 99 | -- Shows the help text for the player filter. 100 | ------------------------------------------------------------------------------------------------------ 101 | DB.Widgets.Player_Filter_Help_Text = function() 102 | UI.SameLine() Window_Manager.Widgets.HelpMarker("Pick a player that you would like to see more detailed stats for.\n") 103 | end 104 | 105 | ------------------------------------------------------------------------------------------------------ 106 | -- Utility function for accessing the name of the currently focused entity. 107 | ------------------------------------------------------------------------------------------------------ 108 | DB.Widgets.Util.Get_Player_Focus = function() 109 | return DB.Widgets.Dropdown.Player.Focus 110 | end 111 | 112 | ------------------------------------------------------------------------------------------------------ 113 | -- Switches to a player in the player filter based on partial matching. 114 | ------------------------------------------------------------------------------------------------------ 115 | ---@param player_string string 116 | ------------------------------------------------------------------------------------------------------ 117 | DB.Widgets.Util.Player_Switch = function(player_string) 118 | local list = DB.Lists.Get.Players() 119 | local found = false 120 | for n, player_name in pairs(list) do 121 | if not found then 122 | if string.find(string.lower(player_name), player_string) then 123 | DB.Widgets.Dropdown.Player.Index = n 124 | DB.Widgets.Dropdown.Player.Focus = list[n] 125 | found = true 126 | end 127 | end 128 | end 129 | end -------------------------------------------------------------------------------- /handlers/_handler.lua: -------------------------------------------------------------------------------- 1 | H = {} 2 | 3 | H.Mode = DB.Enum.Mode 4 | H.Trackable = DB.Enum.Trackable 5 | H.Metric = DB.Enum.Metric 6 | 7 | H.Enum = {} 8 | 9 | H.Enum.Flags = { 10 | IGNORE = "ignore", 11 | } 12 | 13 | H.Enum.Offsets = { 14 | ABILITY = 512, 15 | PET = 512, 16 | } 17 | 18 | H.Enum.Text = { 19 | BLANK = "", 20 | } 21 | 22 | require("handlers.melee") 23 | require("handlers.melee_def") 24 | require("handlers.ranged") 25 | require("handlers.tp_action") 26 | require("handlers.tp_action_def") 27 | require("handlers.abilities") 28 | require("handlers.spells") 29 | require("handlers.spells_def") 30 | require("handlers.deaths") 31 | require("handlers.items") -------------------------------------------------------------------------------- /handlers/deaths.lua: -------------------------------------------------------------------------------- 1 | H.Death = {} 2 | 3 | ------------------------------------------------------------------------------------------------------ 4 | -- Parse the player death message. 5 | ------------------------------------------------------------------------------------------------------ 6 | ---@param actor_mob table mob id of the entity performing the action 7 | ---@param target_mob table mob id of the entity receiving the action (this is the person dying) 8 | ------------------------------------------------------------------------------------------------------ 9 | H.Death.Action = function(actor_mob, target_mob) 10 | if not actor_mob or not target_mob then return nil end 11 | 12 | local audits = { 13 | player_name = target_mob.name, 14 | target_name = actor_mob.name, 15 | } 16 | 17 | DB.Data.Update(H.Mode.INC, 1, audits, H.Trackable.DEATH, H.Metric.COUNT) 18 | DB.Data.Update(H.Mode.INC, 1, audits, H.Trackable.DEATH, H.Metric.TOTAL) 19 | Blog.Add(target_mob.name, nil, Blog.Enum.Types.DEATH, Blog.Enum.Text.PLAYER_DEATH, nil, actor_mob.name, DB.Enum.Trackable.DEATH) 20 | end 21 | -------------------------------------------------------------------------------- /handlers/items.lua: -------------------------------------------------------------------------------- 1 | H.Item = T{} 2 | 3 | -- ------------------------------------------------------------------------------------------------------ 4 | -- Parse the finish item use packet. 5 | -- ------------------------------------------------------------------------------------------------------ 6 | ---@param action table action packet data. 7 | ---@param actor_mob table 8 | -- ------------------------------------------------------------------------------------------------------ 9 | H.Item.Action = function(action, actor_mob) 10 | if not action then return nil end 11 | if not actor_mob then return nil end 12 | if not Ashita.Mob.Is_Me(actor_mob.name) then return nil end 13 | local item_id = action.param 14 | local dedication_item = Res.Items.Get_Dedication(item_id) 15 | if dedication_item then XP.Dedication.Set(dedication_item, true) end 16 | end -------------------------------------------------------------------------------- /modules/battle log/columns.lua: -------------------------------------------------------------------------------- 1 | Blog.Columns = T{} 2 | 3 | ------------------------------------------------------------------------------------------------------ 4 | -- Creates a name string for display in the battle log. 5 | ------------------------------------------------------------------------------------------------------ 6 | ---@param player_name string 7 | ---@param pet_name string 8 | ---@return string 9 | ------------------------------------------------------------------------------------------------------ 10 | Blog.Columns.Name = function(player_name, pet_name) 11 | if Metrics.Parse.Hide_Name then player_name = Blog.Columns.Job(player_name) end 12 | if pet_name ~= Blog.Enum.Text.NO_PET then 13 | local combined_string = player_name .. " (" .. pet_name .. ")" 14 | if string.len(combined_string) > Blog.Settings.Truncate_Length then 15 | local truncated_pet = Column.String.Truncate(pet_name, Blog.Settings.Pet_Name_Truncate_Length, true) 16 | local truncated_player = Column.String.Truncate(player_name, Blog.Settings.Player_Name_Truncate_Length) 17 | combined_string = truncated_player .. " (" .. truncated_pet .. ")" 18 | end 19 | return Column.String.Set_Length(combined_string, Blog.Settings.Truncate_Length) 20 | end 21 | player_name = Column.String.Set_Length(player_name, Blog.Settings.Truncate_Length) 22 | return player_name 23 | end 24 | 25 | ------------------------------------------------------------------------------------------------------ 26 | -- Gets the player's job for name masking. 27 | -- Don't need the color because it gets saved when the entry is saved. 28 | ------------------------------------------------------------------------------------------------------ 29 | ---@param player_name string 30 | ---@return string 31 | ------------------------------------------------------------------------------------------------------ 32 | Blog.Columns.Job = function(player_name) 33 | local anon_string = "NON0/NON0" 34 | local hide_subjob = Metrics.Parse.Hide_Subjob 35 | if hide_subjob then anon_string = "NON0" end 36 | if not player_name or not Ashita.Party.Jobs[player_name] then return anon_string end 37 | 38 | local main = Res.Jobs.Get_Job(Ashita.Party.Jobs[player_name].main) 39 | local main_level = Ashita.Party.Jobs[player_name].main_level 40 | if not main then main = Res.Jobs.List[0] end 41 | local main_string = string.format("%s%02d", main.ens, main_level) 42 | 43 | local sub_string = "" 44 | if not hide_subjob then 45 | local sub = Res.Jobs.Get_Job(Ashita.Party.Jobs[player_name].sub) 46 | local sub_level = Ashita.Party.Jobs[player_name].sub_level 47 | if not sub then sub = Res.Jobs.List[0] end 48 | sub_string = "/" .. string.format("%s%02d", sub.ens, sub_level) 49 | end 50 | 51 | return main_string .. sub_string 52 | end 53 | 54 | ------------------------------------------------------------------------------------------------------ 55 | -- Formats the damage string. 56 | ------------------------------------------------------------------------------------------------------ 57 | ---@param damage string 58 | ---@return string 59 | ------------------------------------------------------------------------------------------------------ 60 | Blog.Columns.Damage = function(damage) 61 | return Column.String.Set_Length(damage, Blog.Settings.Damage_Truncate_Length) 62 | end 63 | 64 | ------------------------------------------------------------------------------------------------------ 65 | -- Formats the action name. 66 | ------------------------------------------------------------------------------------------------------ 67 | ---@param action_name string 68 | ---@return string 69 | ------------------------------------------------------------------------------------------------------ 70 | Blog.Columns.Action = function(action_name) 71 | action_name = Column.String.Truncate(action_name, Blog.Settings.Action_Truncate_Length) 72 | action_name = Column.String.Set_Length(action_name, Blog.Settings.Action_Truncate_Length) 73 | return action_name 74 | end 75 | 76 | ------------------------------------------------------------------------------------------------------ 77 | -- Formats the note. 78 | ------------------------------------------------------------------------------------------------------ 79 | ---@param note string 80 | ---@return string 81 | ------------------------------------------------------------------------------------------------------ 82 | Blog.Columns.Notes = function(note) 83 | note = Column.String.Truncate(note, Blog.Settings.Action_Truncate_Length) 84 | note = Column.String.Set_Length(note, Blog.Settings.Action_Truncate_Length) 85 | return note 86 | end 87 | -------------------------------------------------------------------------------- /modules/battle log/entries.lua: -------------------------------------------------------------------------------- 1 | Blog.Entries = T{} 2 | 3 | ------------------------------------------------------------------------------------------------------ 4 | -- Format the player name component of the battle log. 5 | ------------------------------------------------------------------------------------------------------ 6 | ---@param player_name string 7 | ---@param is_mob? boolean 8 | ---@return table {Name, Color} 9 | ------------------------------------------------------------------------------------------------------ 10 | Blog.Entries.Name = function(player_name, is_mob) 11 | local color = Res.Colors.Basic.WHITE 12 | if is_mob then 13 | color = Res.Colors.Basic.MOB 14 | elseif Metrics.Parse.Name_Colors and Ashita.Party.Jobs[player_name] then 15 | local job = Res.Jobs.Get_Job(Ashita.Party.Jobs[player_name].main) 16 | if not job then job = Res.Jobs.List[0] end 17 | color = Res.Colors.Get_Job(job.id) 18 | end 19 | return {Value = tostring(player_name), Color = color} 20 | end 21 | 22 | ------------------------------------------------------------------------------------------------------ 23 | -- Format the pet name component of the battle log. 24 | ------------------------------------------------------------------------------------------------------ 25 | ---@param pet_name string 26 | ---@return table {Name, Color} 27 | ------------------------------------------------------------------------------------------------------ 28 | Blog.Entries.Pet_Name = function(pet_name) 29 | local color = Res.Colors.Basic.WHITE 30 | if not pet_name then pet_name = Blog.Enum.Text.NO_PET end 31 | return {Value = pet_name, Color = color} 32 | end 33 | 34 | ------------------------------------------------------------------------------------------------------ 35 | -- Format the damage component of the battle log. 36 | ------------------------------------------------------------------------------------------------------ 37 | ---@param damage? number 38 | ---@param action_type? string a trackable from the data model. 39 | ---@param color? table 40 | ---@param is_mob? boolean 41 | ---@return table {Damage, Color} 42 | ------------------------------------------------------------------------------------------------------ 43 | Blog.Entries.Damage = function(damage, action_type, color, is_mob) 44 | if action_type == Blog.Enum.Flags.IGNORE then return {Value = Blog.Enum.Text.NA, Color = Res.Colors.Basic.WHITE} end 45 | 46 | local default_color = Res.Colors.Basic.WHITE 47 | if color then default_color = color end 48 | 49 | -- Change the color of the text if the damage is over a certain threshold. 50 | local threshold = Blog.Entries.Damage_Threshold(action_type) 51 | 52 | -- Generate damage string. 53 | if not damage then 54 | return {Value = Blog.Enum.Text.NA, Color = Res.Colors.Basic.DIM} 55 | elseif is_mob then 56 | return {Value = Column.String.Format_Number(damage), Color = Res.Colors.Basic.MOB} 57 | elseif damage < 0 then -- Enfeeble 58 | return {Value = Blog.Enum.Text.NA, Color = Res.Colors.Basic.DIM} 59 | elseif damage == 0 then 60 | return {Value = Column.String.Format_Number(0), Color = default_color, Note = Blog.Enum.Text.MISS} 61 | elseif damage >= threshold then 62 | return {Value = Column.String.Format_Number(damage), Color = default_color, Note = Blog.Enum.Text.HIGH_DAMAGE} 63 | end 64 | return {Value = Column.String.Format_Number(damage), Color = default_color} 65 | end 66 | 67 | ------------------------------------------------------------------------------------------------------ 68 | -- Helper function for calculating a damage threshold for highlighting. 69 | ------------------------------------------------------------------------------------------------------ 70 | ---@param action_type? string a trackable from the data model. 71 | ---@return number 72 | ------------------------------------------------------------------------------------------------------ 73 | Blog.Entries.Damage_Threshold = function(action_type) 74 | local threshold = DB.Enum.Values.MAX_DAMAGE 75 | if not action_type then 76 | return threshold 77 | elseif action_type == DB.Enum.Trackable.WS then 78 | return Metrics.Blog.WS_THRESHOLD 79 | elseif action_type == DB.Enum.Trackable.MAGIC then 80 | return Metrics.Blog.MAGIC_THRESHOLD 81 | else 82 | return threshold 83 | end 84 | end 85 | 86 | ------------------------------------------------------------------------------------------------------ 87 | -- Format the action component of the battle log. 88 | ------------------------------------------------------------------------------------------------------ 89 | ---@param action_name string 90 | ---@param color table 91 | ---@param is_mob? boolean 92 | ---@return table {Name, Color} 93 | ------------------------------------------------------------------------------------------------------ 94 | Blog.Entries.Action = function(action_name, color, is_mob) 95 | if is_mob then color = Res.Colors.Basic.MOB end 96 | return {Value = action_name, Color = color} 97 | end 98 | 99 | ------------------------------------------------------------------------------------------------------ 100 | -- Format the TP component of the battle log. 101 | -- Will also show if a spell cast is a magic burst. 102 | ------------------------------------------------------------------------------------------------------ 103 | ---@param note? string|number how much TP was used by the weaponskill 104 | ---@param action_type? string a trackable from the data model. 105 | ---@param is_mob? boolean 106 | ---@return table 107 | ------------------------------------------------------------------------------------------------------ 108 | Blog.Entries.Notes = function(note, action_type, is_mob) 109 | local color = Res.Colors.Basic.WHITE 110 | if is_mob then color = Res.Colors.Basic.MOB end 111 | 112 | local final_note = {Value = " ", Color = color} 113 | if not note or note == "" then return final_note end 114 | 115 | -- A note should be passed in with these actions. Just use that. 116 | if action_type == DB.Enum.Trackable.MAGIC or action_type == DB.Enum.Trackable.HEALING 117 | or action_type == DB.Enum.Trackable.TP_DMG_TAKEN or action_type == Blog.Enum.Flags.IGNORE 118 | or action_type == DB.Enum.Trackable.ENFEEBLE or action_type == DB.Enum.Trackable.BUFF_SONG 119 | or action_type == DB.Enum.Trackable.PET_ABILITY or action_type == DB.Enum.Trackable.PHANTOM_ROLL 120 | or action_type == DB.Enum.Trackable.DEBUFF_REMOVAL or action_type == DB.Enum.Trackable.DEATH then 121 | final_note.Value = tostring(note) 122 | 123 | -- If the player died then show who killed them. 124 | elseif action_type == DB.Enum.Trackable.DEATH then 125 | if note then final_note.Value = "by " .. tostring(note) end 126 | 127 | -- Show the TP of the weaponskill. 128 | elseif action_type == DB.Enum.Trackable.WS then 129 | ---@diagnostic disable-next-line: param-type-mismatch 130 | if note then final_note.Value = "TP: " .. Column.String.Format_Number(note) .. " " end 131 | 132 | -- We passed in a note, but didn't handle it above. 133 | else 134 | Debug.Error.Add("Entries.Notes: Unhandled battle log note. Note: {" .. tostring(note) .. "} Type: {" .. tostring(action_type) .. "} Mob {" .. tostring(is_mob) .. "}.") 135 | final_note.Value = " " 136 | end 137 | 138 | return final_note 139 | end -------------------------------------------------------------------------------- /modules/debug/!debug.lua: -------------------------------------------------------------------------------- 1 | Debug = {} 2 | Debug.Enabled = false 3 | Debug.Show_Demo = false 4 | 5 | Debug.Name = "Debug" 6 | Debug.Title = "Metrics - Debug" 7 | Debug.Module = "Debug" 8 | Debug.Window = Window:New({ 9 | Name = Debug.Name, 10 | Title = Debug.Title, 11 | Module = Debug.Module, 12 | Visible = {false}, 13 | Show_Title = true, 14 | }) 15 | 16 | Debug.Modes = T{ 17 | MOB_VIEWER = "Mob Viewer ", 18 | ACTION_PACKET = "Action Packet ", 19 | MESSAGE_PACKET = "Message Packet", 20 | ERROR_LOG = "Error Log ", 21 | DATA_VIEWER = "Data Viewer ", 22 | JOB_COLORS = "Job Colors ", 23 | UNIT_TESTS = "Unit Tests ", 24 | DEMO = "Demo Window ", 25 | } 26 | Debug.Active_Mode = Debug.Modes.MOB_VIEWER 27 | 28 | require("modules.debug.performance") 29 | require("modules.debug.screens.mob_viewer") 30 | require("modules.debug.screens.packet_viewer") 31 | require("modules.debug.screens.error_log") 32 | require("modules.debug.screens.data_viewer") 33 | require("modules.debug.unit_tests._tests") 34 | require("modules.debug.unit_tests.melee") 35 | require("modules.debug.unit_tests.ranged") 36 | require("modules.debug.unit_tests.tp_action") 37 | require("modules.debug.unit_tests.abilities") 38 | require("modules.debug.unit_tests.spells") 39 | require("modules.debug.unit_tests.defense") 40 | 41 | ------------------------------------------------------------------------------------------------------ 42 | -- Is debug mode enabled. 43 | ------------------------------------------------------------------------------------------------------ 44 | ---@return boolean 45 | ------------------------------------------------------------------------------------------------------ 46 | Debug.Is_Enabled = function() 47 | return Debug.Enabled 48 | end 49 | 50 | ------------------------------------------------------------------------------------------------------ 51 | -- Toggles debug mode. 52 | ------------------------------------------------------------------------------------------------------ 53 | Debug.Toggle = function() 54 | Debug.Enabled = not Debug.Enabled 55 | if Debug.Enabled then Debug.Window.Show() else Debug.Window.Hide() end 56 | end 57 | 58 | -- ------------------------------------------------------------------------------------------------------ 59 | -- Adds a message in game chat if the debug mode is enabled. 60 | -- ------------------------------------------------------------------------------------------------------ 61 | ---@param message string 62 | -- ------------------------------------------------------------------------------------------------------ 63 | Debug.Message = function(message) 64 | if Debug.Enabled then print("METRICS DEBUG: " .. message) end 65 | end 66 | 67 | ------------------------------------------------------------------------------------------------------ 68 | -- Poplates the debug screen to show debug tools. 69 | ------------------------------------------------------------------------------------------------------ 70 | Debug.Content = function() 71 | local col_flags = Column.Flags.None 72 | local width = 150 73 | 74 | if UI.BeginTable("Debug Functions", 3, Window_Manager.Table.Flags.None) then 75 | UI.TableSetupColumn("Col 1", col_flags, width) 76 | UI.TableSetupColumn("Col 2", col_flags, width) 77 | UI.TableSetupColumn("Col 3", col_flags, width) 78 | 79 | UI.TableNextColumn() if UI.Button(Debug.Modes.MOB_VIEWER) then Debug.Active_Mode = Debug.Modes.MOB_VIEWER end 80 | UI.TableNextColumn() if UI.Button(Debug.Modes.ACTION_PACKET) then Debug.Active_Mode = Debug.Modes.ACTION_PACKET end 81 | UI.TableNextColumn() if UI.Button(Debug.Modes.MESSAGE_PACKET) then Debug.Active_Mode = Debug.Modes.MESSAGE_PACKET end 82 | UI.TableNextColumn() if UI.Button(Debug.Modes.ERROR_LOG) then Debug.Active_Mode = Debug.Modes.ERROR_LOG end 83 | UI.TableNextColumn() if UI.Button(Debug.Modes.DATA_VIEWER) then Debug.Active_Mode = Debug.Modes.DATA_VIEWER end 84 | UI.TableNextColumn() if UI.Button(Debug.Modes.JOB_COLORS) then Debug.Active_Mode = Debug.Modes.JOB_COLORS end 85 | UI.TableNextColumn() if UI.Button(Debug.Modes.UNIT_TESTS) then 86 | Debug.Active_Mode = Debug.Modes.UNIT_TESTS 87 | Debug.Unit.Results = T{} 88 | Debug.Unit.Run_Tests() 89 | end 90 | UI.TableNextColumn() if UI.Button(Debug.Modes.DEMO) then Debug.Show_Demo = not Debug.Show_Demo end 91 | 92 | UI.EndTable() 93 | end 94 | 95 | if Debug.Active_Mode == Debug.Modes.MOB_VIEWER then Debug.Mob.Populate(Ashita.Mob.Get_Mob_By_Target(Ashita.Enum.Targets.TARGET)) 96 | elseif Debug.Active_Mode == Debug.Modes.ACTION_PACKET then Debug.Packet.Populate_Action() 97 | elseif Debug.Active_Mode == Debug.Modes.MESSAGE_PACKET then Debug.Packet.Populate_Message() 98 | elseif Debug.Active_Mode == Debug.Modes.ERROR_LOG then Debug.Error.Populate() 99 | elseif Debug.Active_Mode == Debug.Modes.DATA_VIEWER then Debug.Data_View.Populate() 100 | elseif Debug.Active_Mode == Debug.Modes.JOB_COLORS then 101 | UI.TextColored(Res.Colors.Get_Job(1), "Warrior") 102 | UI.TextColored(Res.Colors.Get_Job(2), "Monk") 103 | UI.TextColored(Res.Colors.Get_Job(3), "White Mage") 104 | UI.TextColored(Res.Colors.Get_Job(4), "Black Mage") 105 | UI.TextColored(Res.Colors.Get_Job(5), "Red Mage") 106 | UI.TextColored(Res.Colors.Get_Job(6), "Thief") 107 | UI.TextColored(Res.Colors.Get_Job(7), "Paladin") 108 | UI.TextColored(Res.Colors.Get_Job(8), "Dark Knight") 109 | UI.TextColored(Res.Colors.Get_Job(9), "Beastmaster") 110 | UI.TextColored(Res.Colors.Get_Job(10), "Bard") 111 | UI.TextColored(Res.Colors.Get_Job(11), "Ranger") 112 | UI.TextColored(Res.Colors.Get_Job(12), "Samurai") 113 | UI.TextColored(Res.Colors.Get_Job(13), "Ninja") 114 | UI.TextColored(Res.Colors.Get_Job(14), "Dragoon") 115 | UI.TextColored(Res.Colors.Get_Job(15), "Summoner") 116 | UI.TextColored(Res.Colors.Get_Job(16), "Blue Mage") 117 | UI.TextColored(Res.Colors.Get_Job(17), "Corsair") 118 | UI.TextColored(Res.Colors.Get_Job(18), "Puppetmaster") 119 | elseif Debug.Active_Mode == Debug.Modes.UNIT_TESTS then 120 | Debug.Unit.Populate() 121 | else 122 | UI.Text("Select a tool.") 123 | end 124 | end -------------------------------------------------------------------------------- /modules/debug/performance.lua: -------------------------------------------------------------------------------- 1 | Debug.Perf = T{} 2 | 3 | Debug.Perf.Players = T{ 4 | "Player1", 5 | "Player2", 6 | "Player3", 7 | "Player4", 8 | "Player5", 9 | "Player6", 10 | "Player7", 11 | "Player8", 12 | "Player9", 13 | "Player10", 14 | "Player11", 15 | "Player12", 16 | "Player13", 17 | "Player14", 18 | "Player15", 19 | "Player16", 20 | "Player17", 21 | "Player18", 22 | } 23 | 24 | Debug.Perf.Mobs = T{ 25 | "Mob1", 26 | "Mob2", 27 | "Mob3", 28 | "Mob4", 29 | "Mob5", 30 | "Mob6", 31 | "Mob7", 32 | "Mob8", 33 | "Mob9", 34 | "Mob10", 35 | "Mob11", 36 | "Mob12", 37 | "Mob13", 38 | } 39 | 40 | ------------------------------------------------------------------------------------------------------ 41 | -- Adds a lot of players and mobs that need to be sorted through to test performance. 42 | ------------------------------------------------------------------------------------------------------ 43 | Debug.Perf.Add_Load = function() 44 | for _, player in pairs(Debug.Perf.Players) do 45 | for _, mob in pairs(Debug.Perf.Mobs) do 46 | DB.Data.Update("inc", 25, {player_name = player, target_name = mob}, "No SC Total", "Total") 47 | end 48 | end 49 | end -------------------------------------------------------------------------------- /modules/debug/screens/data_viewer.lua: -------------------------------------------------------------------------------- 1 | Debug.Data_View = {} 2 | 3 | ------------------------------------------------------------------------------------------------------ 4 | -- Populates the data viewer tab. 5 | ------------------------------------------------------------------------------------------------------ 6 | Debug.Data_View.Populate = function() 7 | local stack = T{} 8 | if UI.TreeNode("Model.Data") then 9 | for index, value in pairs(DB.Parse) do 10 | if UI.TreeNode(tostring(index)) then 11 | Debug.Data_View.Node(stack, value) 12 | UI.TreePop() 13 | end 14 | end 15 | UI.TreePop() 16 | end 17 | 18 | if UI.TreeNode("Party List") then 19 | for player_name, party_number in pairs(Ashita.Party.List) do 20 | UI.Text(tostring(player_name) .. ": " .. tostring(party_number)) 21 | end 22 | UI.TreePop() 23 | end 24 | end 25 | 26 | ------------------------------------------------------------------------------------------------------ 27 | -- Recursively go through the data nodes. 28 | ------------------------------------------------------------------------------------------------------ 29 | ---@param stack table 30 | ---@param data table 31 | ------------------------------------------------------------------------------------------------------ 32 | Debug.Data_View.Node = function(stack, data) 33 | for index, value in pairs(data) do 34 | if type(value) == "table" then 35 | if index ~= DB.Enum.Values.CATALOG then 36 | table.insert(stack, index) 37 | Debug.Data_View.Node(stack, value) 38 | table.remove(stack) 39 | end 40 | else 41 | if value and value > 0 then 42 | if not (index == DB.Enum.Metric.MIN and value == DB.Enum.Values.MAX_DAMAGE) then 43 | for _, v in ipairs(stack) do UI.Text(tostring(v)) UI.SameLine() UI.Text(" ") UI.SameLine() end 44 | UI.Text(tostring(index) .. ": " .. tostring(value)) 45 | end 46 | end 47 | end 48 | end 49 | end -------------------------------------------------------------------------------- /modules/debug/screens/error_log.lua: -------------------------------------------------------------------------------- 1 | Debug.Error = {} 2 | Debug.Error.Log = {} -- Error, Count 3 | Debug.Error.Count = 0 4 | Debug.Error.Util = {} 5 | 6 | ------------------------------------------------------------------------------------------------------ 7 | -- Adds an entry to the error log. 8 | -- Example Call: _Debug.Error.Add("Function: Error") 9 | ------------------------------------------------------------------------------------------------------ 10 | ---@param error string error string and index to the error log. 11 | ---@return boolean whether or not this is a new error. 12 | ------------------------------------------------------------------------------------------------------ 13 | Debug.Error.Add = function(error) 14 | Debug.Error.Count = Debug.Error.Count + 1 15 | if not Debug.Error.Log[error] then 16 | Debug.Error.Log[error] = { 17 | Error = error, 18 | Count = 1, 19 | } 20 | return true 21 | end 22 | Debug.Error.Log[error].Count = Debug.Error.Log[error].Count + 1 23 | return false 24 | end 25 | 26 | ------------------------------------------------------------------------------------------------------ 27 | -- Resets the error log. 28 | ------------------------------------------------------------------------------------------------------ 29 | Debug.Error.Reset = function() 30 | Debug.Error.Log = {} 31 | Debug.Error.Count = 0 32 | end 33 | 34 | ------------------------------------------------------------------------------------------------------ 35 | -- Populates the error log tab. 36 | ------------------------------------------------------------------------------------------------------ 37 | Debug.Error.Populate = function() 38 | if UI.BeginTable("Error Log", 2, Window_Manager.Table.Flags.Borders) then 39 | Debug.Error.Headers() 40 | for _, data in pairs(Debug.Error.Log) do 41 | Debug.Error.Rows(data) 42 | end 43 | UI.EndTable() 44 | end 45 | end 46 | 47 | ------------------------------------------------------------------------------------------------------ 48 | -- Handles setting up the headers for the error log. 49 | ------------------------------------------------------------------------------------------------------ 50 | Debug.Error.Headers = function() 51 | local flags = Column.Flags.None 52 | UI.TableSetupColumn("Count", flags) 53 | UI.TableSetupColumn("Error", flags) 54 | UI.TableHeadersRow() 55 | end 56 | 57 | ------------------------------------------------------------------------------------------------------ 58 | -- Creates the rows of the error log. 59 | ------------------------------------------------------------------------------------------------------ 60 | ---@param entry table 61 | ------------------------------------------------------------------------------------------------------ 62 | Debug.Error.Rows = function(entry) 63 | UI.TableNextRow() 64 | UI.TableNextColumn() UI.Text(tostring(entry.Count)) 65 | UI.TableNextColumn() UI.Text(tostring(entry.Error)) 66 | end 67 | 68 | ------------------------------------------------------------------------------------------------------ 69 | -- Returns how many errors are currently in the error log. 70 | ------------------------------------------------------------------------------------------------------ 71 | Debug.Error.Util.Error_Count = function() 72 | return Debug.Error.Count 73 | end -------------------------------------------------------------------------------- /modules/debug/screens/mob_viewer.lua: -------------------------------------------------------------------------------- 1 | Debug.Mob = {} 2 | 3 | ------------------------------------------------------------------------------------------------------ 4 | -- Populates the Mob Viewer tab. 5 | ------------------------------------------------------------------------------------------------------ 6 | Debug.Mob.Populate = function(mob) 7 | if mob then 8 | if UI.BeginTable("table1", 2, Window_Manager.Table.Flags.Team) then 9 | Debug.Mob.Headers() 10 | Debug.Mob.Rows(mob) 11 | UI.EndTable() 12 | end 13 | end 14 | end 15 | 16 | ------------------------------------------------------------------------------------------------------ 17 | -- Handles setting up the headers for the mob viewer. 18 | ------------------------------------------------------------------------------------------------------ 19 | Debug.Mob.Headers = function() 20 | local flags = Column.Flags.None 21 | UI.TableSetupColumn("Flag", flags) 22 | UI.TableSetupColumn("Data", flags) 23 | UI.TableHeadersRow() 24 | end 25 | 26 | ------------------------------------------------------------------------------------------------------ 27 | -- Creates the rows of the mob viewer. 28 | ------------------------------------------------------------------------------------------------------ 29 | Debug.Mob.Rows = function(mob) 30 | UI.TableNextRow() 31 | UI.TableNextColumn() UI.Text("name") 32 | UI.TableNextColumn() UI.Text(tostring(mob.name)) 33 | UI.TableNextRow() 34 | UI.TableNextColumn() UI.Text("id") 35 | UI.TableNextColumn() UI.Text(tostring(mob.id_num)) 36 | UI.TableNextRow() 37 | UI.TableNextColumn() UI.Text("index") 38 | UI.TableNextColumn() UI.Text(tostring(mob.index)) 39 | UI.TableNextRow() 40 | UI.TableNextColumn() UI.Text("entity_type") 41 | UI.TableNextColumn() UI.Text(tostring(mob.entity_type)) 42 | UI.TableNextRow() 43 | UI.TableNextColumn() UI.Text("status") 44 | UI.TableNextColumn() UI.Text(tostring(mob.status)) 45 | UI.TableNextRow() 46 | UI.TableNextColumn() UI.Text("distance") 47 | UI.TableNextColumn() UI.Text(string.format("%.1f",(Ashita.Mob.Distance(Ashita.Mob.Get_Mob_By_Target(Ashita.Enum.Targets.ME), mob)))) 48 | UI.TableNextRow() 49 | UI.TableNextColumn() UI.Text("hpp") 50 | UI.TableNextColumn() UI.Text(tostring(mob.hpp)) 51 | UI.TableNextRow() 52 | UI.TableNextColumn() UI.Text("x") 53 | UI.TableNextColumn() UI.Text(Column.String.Format_Number(mob.x)) 54 | UI.TableNextRow() 55 | UI.TableNextColumn() UI.Text("y") 56 | UI.TableNextColumn() UI.Text(Column.String.Format_Number(mob.y)) 57 | UI.TableNextRow() 58 | UI.TableNextColumn() UI.Text("z") 59 | UI.TableNextColumn() UI.Text(Column.String.Format_Number(mob.z)) 60 | UI.TableNextRow() 61 | UI.TableNextColumn() UI.Text("target_index") 62 | UI.TableNextColumn() UI.Text(tostring(mob.target_index)) 63 | UI.TableNextRow() 64 | UI.TableNextColumn() UI.Text("pet_index") 65 | UI.TableNextColumn() UI.Text(tostring(mob.pet_index)) 66 | UI.TableNextRow() 67 | UI.TableNextColumn() UI.Text("claim_id") 68 | UI.TableNextColumn() UI.Text(tostring(mob.claim_id)) 69 | UI.TableNextRow() 70 | UI.TableNextColumn() UI.Text("spawn_flags") 71 | UI.TableNextColumn() UI.Text(tostring(mob.spawn_flags)) 72 | UI.TableNextRow() 73 | UI.TableNextColumn() UI.Text("in_party") 74 | UI.TableNextColumn() UI.Text(tostring(mob.in_party)) 75 | UI.TableNextRow() 76 | UI.TableNextColumn() UI.Text("in_alliance") 77 | UI.TableNextColumn() UI.Text(tostring(mob.in_alliance)) 78 | end -------------------------------------------------------------------------------- /modules/exp/chains.lua: -------------------------------------------------------------------------------- 1 | XP.Chains = T{} 2 | 3 | -- Adapted from Points and ASB. 4 | -- https://github.com/Shinzaku/Points 5 | XP.Chains.Max_Times = T{ 6 | {level=10, maxtime={80, 80, 60, 40, 30, 15}}, 7 | {level=20, maxtime={130, 130, 110, 80, 60, 25}}, 8 | {level=30, maxtime={160, 150, 120, 90, 60, 30}}, 9 | {level=40, maxtime={200, 200, 170, 130, 80, 40}}, 10 | {level=50, maxtime={290, 290, 230, 170, 110, 50}}, 11 | {level=99, maxtime={300, 300, 240, 180, 120, 60}}, 12 | } 13 | 14 | XP.Chains.Is_Active = false 15 | XP.Chains.Start_Time = 0 16 | XP.Chains.Duration = 0 17 | XP.Chains.Current = -1 18 | XP.Chains.Max = 0 19 | 20 | -- ------------------------------------------------------------------------------------------------------ 21 | -- Sets appropriate data for the start or continuation of a chain. 22 | -- ------------------------------------------------------------------------------------------------------ 23 | ---@param chain integer 24 | -- ------------------------------------------------------------------------------------------------------ 25 | XP.Chains.Start = function(chain) 26 | if chain > XP.Chains.Current then 27 | XP.Chains.Is_Active = true 28 | XP.Chains.Start_Time = os.time() 29 | XP.Chains.Metrics(chain) 30 | XP.Chains.Set_Duration() 31 | end 32 | end 33 | 34 | -- ------------------------------------------------------------------------------------------------------ 35 | -- Ends the chain. 36 | -- ------------------------------------------------------------------------------------------------------ 37 | XP.Chains.End = function() 38 | XP.Chains.Current = -1 39 | XP.Chains.Duration = 999 40 | XP.Chains.Start_Time = 0 41 | XP.Chains.Is_Active = false 42 | end 43 | 44 | -- ------------------------------------------------------------------------------------------------------ 45 | -- Handles chain metrics. 46 | -- ------------------------------------------------------------------------------------------------------ 47 | ---@param chain integer 48 | -- ------------------------------------------------------------------------------------------------------ 49 | XP.Chains.Metrics = function(chain) 50 | if not chain then chain = 0 end 51 | if chain > XP.Metric.Max_Chain then XP.Metric.Max_Chain = chain end 52 | XP.Chains.Current = chain 53 | end 54 | 55 | -- ------------------------------------------------------------------------------------------------------ 56 | -- Gets the amount of time left in the current chain. 57 | -- ------------------------------------------------------------------------------------------------------ 58 | XP.Chains.Set_Duration = function() 59 | local player = Ashita.Player.Get() 60 | if not player then return nil end 61 | local level = player:GetMainJobLevel() 62 | local chain = XP.Chains.Current 63 | if not chain or chain <= 0 then XP.Chains.Duration = 999 end 64 | chain = chain + 1 -- Chain we are going for is the next chain. 65 | if chain > 6 then chain = 6 end 66 | for _, bucket in ipairs(XP.Chains.Max_Times) do 67 | if level <= bucket.level then 68 | if bucket.maxtime[chain] then 69 | XP.Chains.Duration = bucket.maxtime[chain] 70 | break 71 | end 72 | end 73 | end 74 | end 75 | 76 | -- ------------------------------------------------------------------------------------------------------ 77 | -- Handles the chain countdown. 78 | -- ------------------------------------------------------------------------------------------------------ 79 | XP.Chains.Timer = function() 80 | local color = Res.Colors.Basic.WHITE 81 | if not XP.Chains.Is_Active then return UI.TextColored(color, "--:--") end 82 | local now = os.time() 83 | local elapsed_time = now - XP.Chains.Start_Time 84 | local time_remaining = XP.Chains.Duration - elapsed_time 85 | if time_remaining <=0 then 86 | color = Res.Colors.Basic.RED 87 | XP.Chains.End() 88 | elseif time_remaining <= 10 then 89 | color = Res.Colors.Basic.RED 90 | elseif time_remaining <= 30 then 91 | color = Res.Colors.Basic.YELLOW 92 | else 93 | color = Res.Colors.Basic.WHITE 94 | end 95 | UI.TextColored(color, Timers.Format(time_remaining, true)) 96 | end -------------------------------------------------------------------------------- /modules/exp/dedication.lua: -------------------------------------------------------------------------------- 1 | XP.Dedication = T{} 2 | 3 | XP.Dedication.Is_Active = true 4 | XP.Dedication.Need_Defaulting = false 5 | XP.Dedication.Need_Clear = false 6 | XP.Dedication.Zone_Delay = 10 7 | 8 | -- ------------------------------------------------------------------------------------------------------ 9 | -- Checks if dedication is active. 10 | -- ------------------------------------------------------------------------------------------------------ 11 | XP.Dedication.Check = function() 12 | XP.Dedication.Is_Active = Ashita.Player.Has_Buff(Ashita.Player.Buffs.DEDICATION) 13 | 14 | if not XP.Dedication.Is_Active and not Ashita.States.Zoning and XP.Dedication.Need_Clear 15 | and Timers.Get_Duration(Timers.Enum.Names.ZONE) > XP.Dedication.Zone_Delay then 16 | XP.Dedication.Clear() 17 | 18 | elseif XP.Dedication.Is_Active and XP.Dedication.Need_Defaulting then 19 | local default_item = Res.Items.Get_Dedication(0) 20 | if Metrics.XP.Boost_Default then 21 | local default_item_id = Res.Items.Get_Dedication_ID_From_Name(Metrics.XP.Boost_Item_Default_Name) 22 | default_item = Res.Items.Get_Dedication(default_item_id) 23 | end 24 | XP.Dedication.Set(default_item) 25 | 26 | elseif XP.Dedication.Is_Active then 27 | XP.Dedication.Need_Clear = true 28 | 29 | end 30 | end 31 | 32 | -- ------------------------------------------------------------------------------------------------------ 33 | -- Checks dedication progress. 34 | -- ------------------------------------------------------------------------------------------------------ 35 | ---@return number 36 | -- ------------------------------------------------------------------------------------------------------ 37 | XP.Dedication.Progress = function() 38 | if not XP.Dedication.Is_Active then return 0 end 39 | local bonus_xp = Metrics.XP.Boost_EXP 40 | local max_xp = Metrics.XP.Boost_Item_Max 41 | if not max_xp or max_xp == 0 then max_xp = 1 end 42 | return bonus_xp / max_xp 43 | end 44 | 45 | -- ------------------------------------------------------------------------------------------------------ 46 | -- Sets dedication flags. 47 | -- ------------------------------------------------------------------------------------------------------ 48 | ---@param item? table 49 | ---@param from_packet? boolean if the call comes from a packet then a real item was used. 50 | -- ------------------------------------------------------------------------------------------------------ 51 | XP.Dedication.Set = function(item, from_packet) 52 | if item and item.name then 53 | XP.Dedication.Is_Active = true -- Need to set manually when item is used. 54 | Metrics.XP.Boost_Item_Name = item.name 55 | Metrics.XP.Boost_Item_Rate = item.boost 56 | Metrics.XP.Boost_Item_Max = item.max 57 | if from_packet then XP.Dedication.Need_Defaulting = false end 58 | end 59 | end 60 | 61 | -- ------------------------------------------------------------------------------------------------------ 62 | -- Clears dedication flags. 63 | -- ------------------------------------------------------------------------------------------------------ 64 | XP.Dedication.Clear = function() 65 | Metrics.XP.Boost_Item_Name = "None" 66 | Metrics.XP.Boost_Item_Rate = 0 67 | Metrics.XP.Boost_Item_Max = 0 68 | Metrics.XP.Boost_EXP = 0 69 | XP.Dedication.Need_Defaulting = true 70 | XP.Dedication.Need_Clear = false 71 | Window_Manager.Set_Bar_Delay() 72 | end -------------------------------------------------------------------------------- /modules/focus/abilities.lua: -------------------------------------------------------------------------------- 1 | Focus.Abilities = T{} 2 | 3 | ------------------------------------------------------------------------------------------------------ 4 | -- Loads data to the ability drop down inside the focus window. 5 | ------------------------------------------------------------------------------------------------------ 6 | ---@param player_name string 7 | ---@param hide_publish? boolean 8 | ------------------------------------------------------------------------------------------------------ 9 | Focus.Abilities.Display = function(player_name, hide_publish) 10 | local ability_total = DB.Data.Get(player_name, DB.Enum.Trackable.ABILITY_DAMAGING, DB.Enum.Metric.COUNT) 11 | local healing_total = DB.Data.Get(player_name, DB.Enum.Trackable.ABILITY_HEALING, DB.Enum.Metric.COUNT) 12 | local mp_recovery = DB.Data.Get(player_name, DB.Enum.Trackable.ABILITY_MP_RECOVERY, DB.Enum.Metric.COUNT) 13 | local maneuvers = DB.Data.Get(player_name, DB.Enum.Trackable.MANEUVER, DB.Enum.Metric.COUNT) 14 | local rolls = DB.Data.Get(player_name, DB.Enum.Trackable.PHANTOM_ROLL, DB.Enum.Metric.COUNT) 15 | local misc_count = DB.Data.Get(player_name, DB.Enum.Trackable.ABILITY, DB.Enum.Metric.COUNT) 16 | 17 | Focus.Abilities.Total(player_name) 18 | UI.Separator() 19 | 20 | if rolls > 0 then Focus.Overview.Phantom_Roll(player_name, true) end 21 | if maneuvers > 0 then 22 | Focus.Overview.Overload(player_name) 23 | Focus.Overview.Maneuvers(player_name) 24 | end 25 | if ability_total > 0 then Focus.Catalog.Abilities(player_name, DB.Enum.Trackable.ABILITY_DAMAGING, "Damaging") end 26 | if healing_total > 0 then Focus.Catalog.Abilities(player_name, DB.Enum.Trackable.ABILITY_HEALING, "Healing") end 27 | if mp_recovery > 0 then Focus.Catalog.Abilities(player_name, DB.Enum.Trackable.ABILITY_MP_RECOVERY, "MP Recover") end 28 | if misc_count > 0 and Metrics.Focus.Show_Misc_Actions then Focus.Catalog.Abilities_General(player_name) end 29 | 30 | if not hide_publish then Focus.Abilities.Publish(player_name, ability_total, healing_total) end 31 | end 32 | 33 | ------------------------------------------------------------------------------------------------------ 34 | -- Loads data to the ability table inside the focus window. 35 | ------------------------------------------------------------------------------------------------------ 36 | ---@param player_name string 37 | ------------------------------------------------------------------------------------------------------ 38 | Focus.Abilities.Total = function(player_name) 39 | local col_flags = Focus.Column_Flags 40 | local table_flags = Focus.Table_Flags 41 | local name_width = Column.Widths.Name 42 | local width = Column.Widths.Standard 43 | 44 | local row = 1 45 | if UI.BeginTable("Ability", 2, table_flags) then 46 | UI.TableSetupColumn("Type", col_flags, name_width) 47 | UI.TableSetupColumn("Total", col_flags, width) 48 | UI.TableHeadersRow() 49 | 50 | UI.TableNextRow() 51 | UI.TableNextColumn() UI.Text("Damaging") 52 | UI.TableNextColumn() Column.Damage.By_Type(player_name, DB.Enum.Trackable.ABILITY_DAMAGING) 53 | Window_Manager.Table_Row_Color(row) 54 | row = row + 1 55 | 56 | UI.TableNextRow() 57 | UI.TableNextColumn()UI.Text("Healing") 58 | UI.TableNextColumn() Column.Damage.By_Type(player_name, DB.Enum.Trackable.ABILITY_HEALING) 59 | Window_Manager.Table_Row_Color(row) 60 | row = row + 1 61 | 62 | UI.TableNextRow() 63 | UI.TableNextColumn()UI.Text("MP Recovery") 64 | UI.TableNextColumn() Column.Damage.By_Type(player_name, DB.Enum.Trackable.ABILITY_MP_RECOVERY) 65 | Window_Manager.Table_Row_Color(row) 66 | row = row + 1 67 | 68 | UI.EndTable() 69 | end 70 | end 71 | 72 | ------------------------------------------------------------------------------------------------------ 73 | -- Sets up ability publishing buttons from within the focus window. 74 | ------------------------------------------------------------------------------------------------------ 75 | ---@param player_name string 76 | ---@param ability_total number 77 | ---@param healing_total number 78 | ------------------------------------------------------------------------------------------------------ 79 | Focus.Abilities.Publish = function(player_name, ability_total, healing_total) 80 | if ability_total > 0 then 81 | Report.Widgets.Button(player_name, DB.Enum.Trackable.ABILITY_DAMAGING, "Publish Abilities") 82 | end 83 | if healing_total > 0 then 84 | if ability_total > 0 then UI.SameLine() UI.Text(" ") UI.SameLine() end 85 | Report.Widgets.Button(player_name, DB.Enum.Trackable.ABILITY_HEALING, "Publish Healing") 86 | end 87 | end -------------------------------------------------------------------------------- /modules/focus/config.lua: -------------------------------------------------------------------------------- 1 | Focus.Config = T{} 2 | 3 | Focus.Config.Defaults = T{ 4 | X = 100, 5 | Y = 100, 6 | Visible = {true}, 7 | Show_Mitigation_Details = false, 8 | Show_Misc_Actions = false, 9 | } 10 | 11 | Focus.Config.Show_Percent_Details = false 12 | Focus.Config.Column_Flags = Column.Flags.None 13 | Focus.Config.Column_Width = Column.Widths.Settings 14 | 15 | ------------------------------------------------------------------------------------------------------ 16 | -- Shows settings that affect the focus screens. 17 | ------------------------------------------------------------------------------------------------------ 18 | Focus.Config.Display = function() 19 | local col_flags = Focus.Config.Column_Flags 20 | 21 | if UI.BeginTable("Focus General", 2) then 22 | UI.TableSetupColumn("Col 1", col_flags) 23 | UI.TableSetupColumn("Col 2", col_flags) 24 | 25 | -- Row 1 26 | UI.TableNextColumn() 27 | if UI.Checkbox("Misc Actions", {Metrics.Focus.Show_Misc_Actions}) then 28 | Metrics.Focus.Show_Misc_Actions = not Metrics.Focus.Show_Misc_Actions 29 | end 30 | UI.SameLine() Window_Manager.Widgets.HelpMarker("Shows uncategorized actions in the catalog lists. " 31 | .."Sometimes these lists can get quite long and take up a lot of space. " 32 | .."Turn this off if you aren't interested in seeing those.") 33 | 34 | UI.EndTable() 35 | end 36 | end 37 | 38 | ------------------------------------------------------------------------------------------------------ 39 | -- Toggles the settings showing for the battle log. 40 | ------------------------------------------------------------------------------------------------------ 41 | Focus.Config.Settings_Button = function() 42 | if UI.SmallButton("Settings") then 43 | Config.Button_Toggle(Config.Enum.File.FOCUS) 44 | end 45 | end 46 | 47 | ------------------------------------------------------------------------------------------------------ 48 | -- Shows percent details checkbox. 49 | ------------------------------------------------------------------------------------------------------ 50 | Focus.Config.Percent_Details = function() 51 | if UI.SmallButton("% Details") then 52 | Focus.Config.Percent_Toggle() 53 | end 54 | end 55 | 56 | ------------------------------------------------------------------------------------------------------ 57 | -- Toggles the percent details setting. 58 | ------------------------------------------------------------------------------------------------------ 59 | Focus.Config.Percent_Toggle = function() 60 | Focus.Config.Show_Percent_Details = not Focus.Config.Show_Percent_Details 61 | end -------------------------------------------------------------------------------- /modules/focus/weaponskills.lua: -------------------------------------------------------------------------------- 1 | Focus.WS = T{} 2 | 3 | ------------------------------------------------------------------------------------------------------ 4 | -- Loads data to the weaponskill and skillchain drop down inside the focus window. 5 | ------------------------------------------------------------------------------------------------------ 6 | ---@param player_name string 7 | ---@param hide_publish? boolean 8 | ------------------------------------------------------------------------------------------------------ 9 | Focus.WS.Display = function(player_name, hide_publish) 10 | local col_flags = Column.Flags.None 11 | local table_flags = Window_Manager.Table.Flags.Fixed_Borders 12 | local name_width = Column.Widths.Name 13 | local width = Column.Widths.Standard 14 | 15 | local trackable_ws = DB.Enum.Trackable.WS 16 | local trackable_sc = DB.Enum.Trackable.SC 17 | 18 | local row = 1 19 | if UI.BeginTable("WS and SC", 7, table_flags) then 20 | UI.TableSetupColumn("Type", col_flags, name_width) 21 | UI.TableSetupColumn("Damage", col_flags, width) 22 | UI.TableSetupColumn("%Player", col_flags, width) 23 | UI.TableSetupColumn("Average", col_flags, width) 24 | UI.TableSetupColumn("Accuracy", col_flags, width) 25 | UI.TableSetupColumn("~TP", col_flags, width) 26 | UI.TableSetupColumn("DMG/TP", col_flags, width) 27 | UI.TableHeadersRow() 28 | 29 | UI.TableNextRow() 30 | UI.TableNextColumn() UI.Text("Weaponskills") 31 | UI.TableNextColumn() Column.Damage.By_Type(player_name, trackable_ws) 32 | UI.TableNextColumn() Column.Damage.By_Type(player_name, trackable_ws, true) 33 | UI.TableNextColumn() Column.Damage.Average_By_Type(player_name, trackable_ws) 34 | UI.TableNextColumn() Column.Acc.By_Type(player_name, trackable_ws) 35 | UI.TableNextColumn() Column.Damage.Average_TP(player_name) 36 | UI.TableNextColumn() Column.General.Fraction(player_name, trackable_ws, DB.Enum.Metric.TOTAL, DB.Enum.Metric.TP_SPENT, false, false, true) 37 | Window_Manager.Table_Row_Color(row) 38 | row = row + 1 39 | 40 | UI.TableNextRow() 41 | UI.TableNextColumn() UI.Text("Skillchains") 42 | UI.TableNextColumn() Column.Damage.By_Type(player_name, trackable_sc) 43 | UI.TableNextColumn() Column.Damage.By_Type(player_name, trackable_sc, true) 44 | UI.TableNextColumn() Column.Damage.Average_By_Type(player_name, trackable_sc) 45 | UI.TableNextColumn() UI.TextColored(Res.Colors.Basic.DIM, "---") 46 | UI.TableNextColumn() UI.TextColored(Res.Colors.Basic.DIM, "---") 47 | UI.TableNextColumn() UI.TextColored(Res.Colors.Basic.DIM, "---") 48 | Window_Manager.Table_Row_Color(row) 49 | row = row + 1 50 | 51 | UI.EndTable() 52 | end 53 | 54 | Focus.Overview.Skillchains(player_name) 55 | 56 | -- Cataloged data 57 | local show_ws_publish = false 58 | local show_sc_publish = false 59 | if DB.Tracking.Trackable[DB.Enum.Trackable.WS] and DB.Tracking.Trackable[DB.Enum.Trackable.WS][player_name] then 60 | Focus.Catalog.Weaponskill(player_name, DB.Enum.Trackable.WS) 61 | show_ws_publish = true 62 | end 63 | 64 | if DB.Tracking.Trackable[DB.Enum.Trackable.SC] and DB.Tracking.Trackable[DB.Enum.Trackable.SC][player_name] then 65 | Focus.Catalog.Skillchains(player_name, DB.Enum.Trackable.SC) 66 | show_sc_publish = true 67 | end 68 | 69 | -- Publish buttons 70 | if not hide_publish then 71 | if show_ws_publish then 72 | Report.Widgets.Button(player_name, trackable_ws, "Publish Weaponskills") 73 | end 74 | if show_sc_publish then 75 | UI.SameLine() UI.Text(" ") UI.SameLine() 76 | Report.Widgets.Button(player_name, trackable_sc, "Publish Skillchains") 77 | end 78 | end 79 | end -------------------------------------------------------------------------------- /modules/hub/config.lua: -------------------------------------------------------------------------------- 1 | Hub.Config = T{} 2 | 3 | Hub.Config.Defaults = T{ 4 | X = 100, 5 | Y = 100, 6 | Visible = {true}, 7 | } -------------------------------------------------------------------------------- /modules/overview/_overview.lua: -------------------------------------------------------------------------------- 1 | Overview = T{} 2 | 3 | Overview.Name = "Overview" 4 | Overview.Title = "Metrics - Overview" 5 | Overview.Module = "Overview" 6 | Overview.Window = Window:New({ 7 | Name = Overview.Name, 8 | Title = Overview.Title, 9 | Module = Overview.Module, 10 | Visible = {false}, 11 | Show_Title = true, 12 | }) 13 | 14 | Overview.Modes = T{ 15 | PARSE = "Parse", 16 | FOCUS = "Focus", 17 | BLOG = "Battle Log", 18 | } 19 | Overview.Mode = Overview.Modes.PARSE 20 | 21 | require("modules.overview.config") 22 | require("modules.overview.parse") 23 | require("modules.overview.focus") 24 | 25 | ------------------------------------------------------------------------------------------------------ 26 | -- Opens a new window to show all tabs as a vertical column. 27 | ------------------------------------------------------------------------------------------------------ 28 | Overview.Content = function() 29 | if Overview.Mode == Overview.Modes.PARSE then 30 | Overview.Parse.Content() 31 | elseif Overview.Mode == Overview.Modes.FOCUS then 32 | local player_name = DB.Widgets.Util.Get_Player_Focus() 33 | if player_name == DB.Widgets.Dropdown.Enum.NONE then 34 | Focus.Screenshot_Mode[1] = false 35 | return nil 36 | end 37 | Overview.Focus.Content(player_name) 38 | else 39 | UI.Text("No content.") 40 | end 41 | end 42 | 43 | ------------------------------------------------------------------------------------------------------ 44 | -- Button that opens the overview window with focus content. 45 | ------------------------------------------------------------------------------------------------------ 46 | Overview.Screenshot_Button = function() 47 | if UI.SmallButton("Screenshot") then 48 | if Overview.Mode == Overview.Modes.FOCUS then 49 | Overview.Window.Toggle_Visibility() 50 | else 51 | Overview.Window.Show() 52 | Overview.Mode = Overview.Modes.FOCUS 53 | end 54 | end 55 | end 56 | 57 | ------------------------------------------------------------------------------------------------------ 58 | -- Button that opens the overview window with parse content. 59 | ------------------------------------------------------------------------------------------------------ 60 | Overview.Overview_Button = function() 61 | if UI.SmallButton("Overview") then 62 | if Overview.Mode == Overview.Modes.PARSE then 63 | Overview.Window.Toggle_Visibility() 64 | else 65 | Overview.Window.Show() 66 | Overview.Mode = Overview.Modes.PARSE 67 | end 68 | end 69 | end -------------------------------------------------------------------------------- /modules/overview/config.lua: -------------------------------------------------------------------------------- 1 | Overview.Config = T{} 2 | 3 | Overview.Config.Defaults = T{ 4 | X = 100, 5 | Y = 100, 6 | Visible = {false}, 7 | Timer = true, 8 | Melee = false, 9 | Ranged = false, 10 | WS = false, 11 | Nuke = false, 12 | Pets = false, 13 | Healing = false, 14 | Defense = false, 15 | Mobs_Defeated = false, 16 | } -------------------------------------------------------------------------------- /modules/overview/focus.lua: -------------------------------------------------------------------------------- 1 | Overview.Focus = T{} 2 | 3 | ------------------------------------------------------------------------------------------------------ 4 | -- Content for the Focus screenshot window. 5 | ------------------------------------------------------------------------------------------------------ 6 | ---@param player_name string 7 | ------------------------------------------------------------------------------------------------------ 8 | Overview.Focus.Content = function(player_name) 9 | UI.Text("Overall") Focus.Overall(player_name) 10 | UI.Separator() UI.Text("Melee") Focus.Melee.Display(player_name) 11 | UI.Separator() UI.Text("Ranged") Focus.Ranged.Display(player_name) 12 | UI.Separator() UI.Text("Weaponskills") Focus.WS.Display(player_name, true) 13 | UI.Separator() UI.Text("Magic") Focus.Magic.Display(player_name, true) 14 | UI.Separator() UI.Text("Abilities") Focus.Abilities.Display(player_name, true) 15 | UI.Separator() UI.Text("Pets") Focus.Pets.Display(player_name) 16 | UI.Separator() UI.Text("Defense") Focus.Defense.Display(player_name) 17 | end -------------------------------------------------------------------------------- /modules/parse/_parse.lua: -------------------------------------------------------------------------------- 1 | Parse = T{} 2 | 3 | Parse.Name = "Parse" 4 | Parse.Title = "Metrics - Parse" 5 | Parse.Module = "Parse" 6 | Parse.Window = Window:New({ 7 | Name = Parse.Name, 8 | Title = Parse.Title, 9 | Module = Parse.Module, 10 | }) 11 | 12 | -- Used to house general functions that I don't want immediately exposed. 13 | Parse.Util = {} 14 | 15 | -- Keeps track of how many columns should be shown on the screen in full mode. 16 | Parse.Columns = { 17 | Base = 3, -- Name, Total, %T 18 | Current = 5, 19 | Max = 32, 20 | } 21 | 22 | Parse.Confirmation = false 23 | 24 | -- Load dependencies 25 | require("modules.parse.enum") 26 | require("modules.parse.config") 27 | require("modules.parse.display_full") 28 | require("modules.parse.display_mini") 29 | require("modules.parse.display_nano") 30 | require("modules.parse.widgets") 31 | 32 | ------------------------------------------------------------------------------------------------------ 33 | -- Initializes the Parse screen. 34 | ------------------------------------------------------------------------------------------------------ 35 | Parse.Initialize = function() 36 | Parse.Util.Calculate_Column_Flags() 37 | end 38 | 39 | ------------------------------------------------------------------------------------------------------ 40 | -- Parse window content. 41 | ------------------------------------------------------------------------------------------------------ 42 | Parse.Content = function() 43 | if Parse.Nano.Is_Enabled() then 44 | Parse.Nano.Populate() 45 | elseif Parse.Mini.Is_Enabled() then 46 | Parse.Mini.Populate() 47 | else 48 | Parse.Full.Populate() 49 | end 50 | end 51 | 52 | ------------------------------------------------------------------------------------------------------ 53 | -- Calculates how many columns should be shown on the Parse table based on column visibility flags. 54 | ------------------------------------------------------------------------------------------------------ 55 | Parse.Util.Calculate_Column_Flags = function() 56 | local added_columns = 0 57 | if Metrics.Parse.Focus then added_columns = added_columns + 1 end 58 | if Metrics.Parse.Jobs then added_columns = added_columns + 1 end 59 | if Metrics.Parse.Attack_Speed then added_columns = added_columns + 1 end 60 | if Metrics.Parse.DPS then added_columns = added_columns + 1 end 61 | if Metrics.Parse.Running_Acc then added_columns = added_columns + 1 end 62 | if Metrics.Parse.Total_Acc then added_columns = added_columns + 1 end 63 | if Metrics.Parse.Crit then added_columns = added_columns + 1 end 64 | if Metrics.Parse.Melee then added_columns = added_columns + 1 end 65 | if Metrics.Parse.Melee_Acc then added_columns = added_columns + 1 end 66 | if Metrics.Parse.Melee_Crit then added_columns = added_columns + 1 end 67 | if Metrics.Parse.Weaponskill then added_columns = added_columns + 1 end 68 | if Metrics.Parse.Average_WS then added_columns = added_columns + 1 end 69 | if Metrics.Parse.WS_TP then added_columns = added_columns + 1 end 70 | if Metrics.Parse.WS_Accuracy then added_columns = added_columns + 1 end 71 | if Parse.Config.Include_SC_Damage() then added_columns = added_columns + 1 end 72 | if Metrics.Parse.Ranged then added_columns = added_columns + 1 end 73 | if Metrics.Parse.Ranged_Acc then added_columns = added_columns + 1 end 74 | if Metrics.Parse.Ranged_Crit then added_columns = added_columns + 1 end 75 | if Metrics.Parse.Ranged_Dist then added_columns = added_columns + 1 end 76 | if Metrics.Parse.Magic then added_columns = added_columns + 1 end 77 | if Metrics.Parse.Ability then added_columns = added_columns + 1 end 78 | if Metrics.Parse.Pet_Acc then added_columns = added_columns + 1 end 79 | if Metrics.Parse.Pet_Melee then added_columns = added_columns + 1 end 80 | if Metrics.Parse.Pet_Ranged then added_columns = added_columns + 1 end 81 | if Metrics.Parse.Pet_WS then added_columns = added_columns + 1 end 82 | if Metrics.Parse.Pet_Ability then added_columns = added_columns + 1 end 83 | if Metrics.Parse.Healing then added_columns = added_columns + 1 end 84 | if Metrics.Parse.Damage_Taken then added_columns = added_columns + 1 end 85 | if Metrics.Parse.Deaths then added_columns = added_columns + 1 end 86 | 87 | -- Apply new column count. 88 | Parse.Columns.Current = Parse.Columns.Base + added_columns 89 | if Parse.Columns.Current > Parse.Columns.Max then Parse.Columns.Current = Parse.Columns.Max end 90 | end -------------------------------------------------------------------------------- /modules/parse/display_mini.lua: -------------------------------------------------------------------------------- 1 | Parse.Mini = T{} 2 | 3 | Parse.Mini.Column_Flags = Column.Flags.None 4 | Parse.Mini.Table_Flags = bit.bor(ImGuiTableFlags_Borders) 5 | 6 | ------------------------------------------------------------------------------------------------------ 7 | -- Loads shows just the Team tab with just the player. 8 | ------------------------------------------------------------------------------------------------------ 9 | Parse.Mini.Populate = function() 10 | local columns = 3 11 | if Parse.Config.Is_Pet_Column_Enabled() then columns = columns + 2 end 12 | if Metrics.Parse.Attack_Speed then columns = columns + 1 end 13 | if Metrics.Parse.DPS then columns = columns + 1 end 14 | if Metrics.Parse.Running_Acc then columns = columns + 1 end 15 | if Metrics.Parse.Lurk_Mode then UI.Text("Lurking...") end 16 | if UI.BeginTable("Team Mini", columns, Parse.Mini.Table_Flags) then 17 | Parse.Mini.Headers() 18 | 19 | local player = Ashita.Player.My_Mob() 20 | if not player then return nil end 21 | 22 | local player_name = "Debug" 23 | DB.Lists.Sort.Total_Damage() 24 | for rank, data in ipairs(DB.Sorted.Total_Damage) do 25 | if rank <= Parse.Config.Rank_Cutoff() then 26 | player_name = data[1] 27 | Parse.Mini.Rows(player_name) 28 | elseif data[1] == player.name then 29 | Parse.Mini.Rows(player.name) 30 | end 31 | end 32 | if Metrics.Parse.Grand_Totals and #DB.Sorted.Total_Damage > 0 then Parse.Mini.Total_Row() end 33 | 34 | UI.EndTable() 35 | end 36 | end 37 | 38 | ------------------------------------------------------------------------------------------------------ 39 | -- Populate table headers for mini mode. 40 | ------------------------------------------------------------------------------------------------------ 41 | Parse.Mini.Headers = function() 42 | local flags = Parse.Mini.Column_Flags 43 | 44 | UI.TableSetupColumn("Name", flags) 45 | UI.TableSetupColumn("Total", flags) 46 | UI.TableSetupColumn("%T", flags) 47 | if Metrics.Parse.Attack_Speed then UI.TableSetupColumn("Speed", flags) end 48 | if Metrics.Parse.DPS then UI.TableSetupColumn(DB.DPS.Column_Header(), flags) end 49 | if Metrics.Parse.Running_Acc then UI.TableSetupColumn("%A-" .. Metrics.Model.Running_Accuracy_Limit, flags) end 50 | if Parse.Config.Is_Pet_Column_Enabled() then 51 | UI.TableSetupColumn("Pet D.", flags) 52 | UI.TableSetupColumn("Pet A.", flags) 53 | end 54 | UI.TableHeadersRow() 55 | end 56 | 57 | ------------------------------------------------------------------------------------------------------ 58 | -- Populate table rows for mini mode. 59 | ------------------------------------------------------------------------------------------------------ 60 | ---@param player_name string 61 | ------------------------------------------------------------------------------------------------------ 62 | Parse.Mini.Rows = function(player_name) 63 | UI.TableNextRow() 64 | UI.TableNextColumn() Column.String.Format_Name(player_name) 65 | UI.TableNextColumn() Column.Damage.Total(player_name, false, true) 66 | UI.TableNextColumn() Column.Damage.Total(player_name, true, true) 67 | if Metrics.Parse.Attack_Speed then UI.TableNextColumn() Column.Attack_Speed.Get(player_name, true) end 68 | if Metrics.Parse.DPS then UI.TableNextColumn() Column.Damage.DPS(player_name, true) end 69 | if Metrics.Parse.Running_Acc then UI.TableNextColumn() Column.Acc.Running(player_name, true) end 70 | if Parse.Config.Is_Pet_Column_Enabled() then 71 | UI.TableNextColumn() Column.Damage.By_Type(player_name, DB.Enum.Trackable.PET) 72 | UI.TableNextColumn() Column.Acc.By_Type(player_name, DB.Enum.Trackable.PET_MELEE_DISCRETE) 73 | end 74 | end 75 | 76 | ------------------------------------------------------------------------------------------------------ 77 | -- Shows totals for each column. 78 | ------------------------------------------------------------------------------------------------------ 79 | Parse.Mini.Total_Row = function() 80 | UI.TableNextRow() 81 | local x, y, z, w = UI.GetStyleColorVec4(ImGuiCol_TableHeaderBg) 82 | local row_bg_color = UI.GetColorU32({x, y, z, w}) 83 | UI.TableSetBgColor(ImGuiTableBgTarget_RowBg0, row_bg_color) 84 | 85 | UI.TableNextColumn() UI.Text("Total") 86 | UI.TableNextColumn() Column.Damage.Parse_Total(true) 87 | if Metrics.Parse.Attack_Speed then UI.TableNextColumn() UI.Text(" ") end 88 | if Metrics.Parse.DPS then UI.TableNextColumn() Column.Damage.Parse_DPS(true) end 89 | if Metrics.Parse.Running_Acc then UI.TableNextColumn() UI.Text(" ") end 90 | UI.TableNextColumn() UI.Text(" ") 91 | if Parse.Config.Is_Pet_Column_Enabled() then 92 | UI.TableNextColumn() UI.Text(" ") 93 | UI.TableNextColumn() Column.Damage.Trackable_Total(DB.Enum.Trackable.PET, true) 94 | UI.TableNextColumn() UI.Text(" ") 95 | end 96 | end 97 | 98 | ------------------------------------------------------------------------------------------------------ 99 | -- Returns whether mini mode is enabled. 100 | ------------------------------------------------------------------------------------------------------ 101 | Parse.Mini.Is_Enabled = function() 102 | return Metrics.Parse.Display_Mode == Parse.Enum.Display_Mode.MINI 103 | end 104 | 105 | ------------------------------------------------------------------------------------------------------ 106 | -- Toggles mini mode. 107 | ------------------------------------------------------------------------------------------------------ 108 | Parse.Mini.Toggle = function() 109 | Metrics.Parse.Display_Mode = Parse.Enum.Display_Mode.MINI 110 | end 111 | -------------------------------------------------------------------------------- /modules/parse/display_nano.lua: -------------------------------------------------------------------------------- 1 | Parse.Nano = T{} 2 | 3 | Parse.Nano.Table_Flags = bit.bor(ImGuiTableFlags_Borders) 4 | 5 | ------------------------------------------------------------------------------------------------------ 6 | -- Loads shows just the Team tab with just the player. 7 | ------------------------------------------------------------------------------------------------------ 8 | Parse.Nano.Populate = function() 9 | local flags = Column.Flags.None 10 | local player = Ashita.Mob.Get_Mob_By_Target(Ashita.Enum.Targets.ME) 11 | if not player then return nil end 12 | local player_name = player.name 13 | 14 | local columns = 1 15 | if Metrics.Parse.DPS then columns = columns + 1 end 16 | if Metrics.Parse.Running_Acc then columns = columns + 1 end 17 | 18 | if UI.BeginTable("Team Nano", columns, Parse.Nano.Table_Flags) then 19 | UI.TableSetupColumn("Total", flags) 20 | if Metrics.Parse.DPS then UI.TableSetupColumn(DB.DPS.Column_Header(), flags) end 21 | if Metrics.Parse.Running_Acc then UI.TableSetupColumn("%A-" .. Metrics.Model.Running_Accuracy_Limit, flags) end 22 | UI.TableHeadersRow() 23 | 24 | UI.TableNextRow() 25 | UI.TableNextColumn() Column.Damage.Total(player_name, false, true) 26 | if Metrics.Parse.DPS then UI.TableNextColumn() Column.Damage.DPS(player_name, true) end 27 | if Metrics.Parse.Running_Acc then UI.TableNextColumn() Column.Acc.Running(player_name, true) end 28 | 29 | UI.EndTable() 30 | end 31 | end 32 | 33 | ------------------------------------------------------------------------------------------------------ 34 | -- Returns whether nano mode is enabled. 35 | ------------------------------------------------------------------------------------------------------ 36 | Parse.Nano.Is_Enabled = function() 37 | return Metrics.Parse.Display_Mode == Parse.Enum.Display_Mode.NANO 38 | end 39 | 40 | ------------------------------------------------------------------------------------------------------ 41 | -- Toggles nano mode. 42 | ------------------------------------------------------------------------------------------------------ 43 | Parse.Nano.Toggle = function() 44 | Metrics.Parse.Display_Mode = Parse.Enum.Display_Mode.NANO 45 | end -------------------------------------------------------------------------------- /modules/parse/enum.lua: -------------------------------------------------------------------------------- 1 | Parse.Enum = T{} 2 | 3 | Parse.Enum.Display_Mode = T{ 4 | FULL = 1, 5 | MINI = 2, 6 | NANO = 3, 7 | } -------------------------------------------------------------------------------- /modules/report/_report.lua: -------------------------------------------------------------------------------- 1 | Report = T{} 2 | 3 | Report.Name = "Report" 4 | Report.Title = "Metrics - Reporting" 5 | Report.Module = "Report" 6 | Report.Window = Window:New({ 7 | Name = Report.Name, 8 | Title = Report.Title, 9 | Module = Report.Module, 10 | }) 11 | 12 | Report.Section = T{} 13 | 14 | -- Load dependencies 15 | require("modules.report.config") 16 | require("modules.report.publishing") 17 | require("modules.report.widgets") 18 | 19 | ------------------------------------------------------------------------------------------------------ 20 | -- Creates some buttons to publish various party metrics to chat. 21 | ------------------------------------------------------------------------------------------------------ 22 | Report.Content = function() 23 | Report.Widgets.Settings_Button() 24 | UI.Separator() Report.Section.Chat_Reports() 25 | UI.Separator() Report.Section.File() 26 | end 27 | 28 | ------------------------------------------------------------------------------------------------------ 29 | -- Builds the chat report section. 30 | ------------------------------------------------------------------------------------------------------ 31 | Report.Section.Chat_Reports = function() 32 | local col_flags = Column.Flags.None 33 | local width = Column.Widths.Report 34 | UI.Text("Chat Reports") 35 | Report.Widgets.Chat_Mode() 36 | if UI.BeginTable("Chat Reports", 4, Window_Manager.Table.Flags.None) then 37 | UI.TableSetupColumn("Col 1", col_flags, width) 38 | UI.TableSetupColumn("Col 2", col_flags, width) 39 | UI.TableSetupColumn("Col 3", col_flags, width) 40 | UI.TableSetupColumn("Col 4", col_flags, width) 41 | 42 | UI.TableNextRow() 43 | UI.TableNextColumn() 44 | if UI.Button("Total Damage") then 45 | Report.Publishing.Total_Damage() 46 | return nil 47 | end 48 | UI.TableNextColumn() 49 | if UI.Button("Accuracy ") then 50 | Report.Publishing.Accuracy() 51 | return nil 52 | end 53 | UI.TableNextColumn() 54 | UI.TableNextColumn() 55 | -- 56 | UI.TableNextColumn() 57 | if UI.Button("Melee ") then 58 | Report.Publishing.Damage_By_Type(DB.Enum.Trackable.MELEE) 59 | return nil 60 | end 61 | UI.TableNextColumn() 62 | if UI.Button("Weaponskills") then 63 | Report.Publishing.Damage_By_Type(DB.Enum.Trackable.WS) 64 | return nil 65 | end 66 | UI.TableNextColumn() 67 | if UI.Button("Magic ") then 68 | Report.Publishing.Damage_By_Type(DB.Enum.Trackable.MAGIC) 69 | return nil 70 | end 71 | UI.TableNextColumn() 72 | if UI.Button("Pet ") then 73 | Report.Publishing.Damage_By_Type(DB.Enum.Trackable.PET) 74 | return nil 75 | end 76 | -- 77 | UI.TableNextColumn() 78 | if UI.Button("Abilities ") then 79 | Report.Publishing.Damage_By_Type(DB.Enum.Trackable.ABILITY_DAMAGING) 80 | return nil 81 | end 82 | UI.TableNextColumn() 83 | if UI.Button("Healing ") then 84 | Report.Publishing.Damage_By_Type(DB.Enum.Trackable.ALL_HEAL) 85 | return nil 86 | end 87 | UI.EndTable() 88 | end 89 | end 90 | 91 | ------------------------------------------------------------------------------------------------------ 92 | -- Builds the file section. 93 | ------------------------------------------------------------------------------------------------------ 94 | Report.Section.File = function() 95 | local col_flags = Column.Flags.None 96 | local width = Column.Widths.Report 97 | UI.Text("Create CSV File") 98 | UI.Text("Files can be found in: /config/Metrics/") 99 | 100 | local blog_length = #Blog.Log 101 | if blog_length >= 50000 then 102 | UI.Text("NOTICE: There are " .. tostring(blog_length) .. " entries in the battle log.") 103 | UI.Text(" You may notice a stagger when saving it.") 104 | end 105 | 106 | if UI.BeginTable("Save File", 4, Window_Manager.Table.Flags.None) then 107 | UI.TableSetupColumn("Col 1", col_flags, width) 108 | UI.TableSetupColumn("Col 2", col_flags, width) 109 | UI.TableSetupColumn("Col 3", col_flags, width) 110 | UI.TableSetupColumn("Col 3", col_flags, width) 111 | 112 | UI.TableNextRow() 113 | UI.TableNextColumn() 114 | if UI.Button("Database ") then 115 | File.Save_Data() 116 | File.Save_Catalog() 117 | return nil 118 | end 119 | UI.TableNextColumn() 120 | if UI.Button("Battle Log ") then 121 | File.Save_Battlelog() 122 | return nil 123 | end 124 | UI.EndTable() 125 | end 126 | end -------------------------------------------------------------------------------- /modules/report/config.lua: -------------------------------------------------------------------------------- 1 | Report.Config = T{} 2 | 3 | Report.Config.Defaults = T{ 4 | X = 100, 5 | Y = 100, 6 | Visible = {true}, 7 | Damage_Threshold = 5, -- Controls what damage percent is needed for showing up in a cross-player chat report. 8 | Auto_Save = false, 9 | } 10 | 11 | Report.Config.Slider_Width = 100 12 | 13 | ------------------------------------------------------------------------------------------------------ 14 | -- Resets report settings. 15 | ------------------------------------------------------------------------------------------------------ 16 | Report.Config.Reset = function() 17 | for setting, value in pairs(Report.Config.Defaults) do 18 | Metrics.Report[setting] = value 19 | end 20 | end 21 | 22 | ------------------------------------------------------------------------------------------------------ 23 | -- Shows settings that affect the Report tab. 24 | ------------------------------------------------------------------------------------------------------ 25 | Report.Config.Display = function() 26 | if UI.Checkbox("Auto Save", {Metrics.Report.Auto_Save}) then 27 | Metrics.Report.Auto_Save = not Metrics.Report.Auto_Save 28 | end 29 | UI.SameLine() Window_Manager.Widgets.HelpMarker("Automatically save an export of the database as a CSV whenver you " 30 | .."reset the database or re/unload the addon (like shutting down).") 31 | UI.Separator() 32 | local damage_threshold = {[1] = Metrics.Report.Damage_Threshold} 33 | UI.Text("This does not affect the Publish button on the focus tab.") 34 | UI.SetNextItemWidth(Report.Config.Slider_Width) 35 | if UI.DragInt("Chat Report % Threshold", damage_threshold, 0.1, 0, 50, "%d", ImGuiSliderFlags_None) then 36 | Metrics.Report.Damage_Threshold = damage_threshold[1] 37 | end 38 | end -------------------------------------------------------------------------------- /modules/report/widgets.lua: -------------------------------------------------------------------------------- 1 | Report.Widgets = T{} 2 | 3 | ------------------------------------------------------------------------------------------------------ 4 | -- Toggles the settings showing for the battle log. 5 | ------------------------------------------------------------------------------------------------------ 6 | Report.Widgets.Settings_Button = function() 7 | if UI.SmallButton("Settings") then 8 | Config.Button_Toggle(Config.Enum.File.REPORT) 9 | end 10 | end 11 | 12 | ------------------------------------------------------------------------------------------------------ 13 | -- Creates a button to publish certain cataloged actions to the screen. 14 | ------------------------------------------------------------------------------------------------------ 15 | ---@param player_name string 16 | ---@param focus_type string 17 | ---@param caption? string 18 | ------------------------------------------------------------------------------------------------------ 19 | Report.Widgets.Button = function(player_name, focus_type, caption) 20 | if not caption then caption = "Publish" end 21 | if UI.Button(caption) then 22 | Report.Publishing.Catalog(player_name, focus_type) 23 | end 24 | end 25 | 26 | ------------------------------------------------------------------------------------------------------ 27 | -- Creates a dropdown menu to chat mode options for publishing. 28 | ------------------------------------------------------------------------------------------------------ 29 | Report.Widgets.Chat_Mode = function() 30 | local list = Ashita.Chat.Modes 31 | local flags = DB.Widgets.Dropdown.Flags 32 | if list[1] then 33 | UI.SetNextItemWidth(Ashita.Chat.Selection.Width) 34 | if UI.BeginCombo(Ashita.Chat.Selection.Title, list[Report.Publishing.Chat_Index].Name, flags) then 35 | for n = 1, #list, 1 do 36 | local is_selected = Ashita.Chat.Selection.Index == n 37 | if UI.Selectable(list[n].Name, is_selected) then 38 | Report.Publishing.Chat_Index = n 39 | Report.Publishing.Chat_Mode = list[n] 40 | end 41 | if is_selected then 42 | UI.SetItemDefaultFocus() 43 | end 44 | end 45 | UI.EndCombo() 46 | end 47 | else 48 | if UI.BeginCombo(Ashita.Chat.Selection.Title, Ashita.Enum.Chat.PARTY, flags) then 49 | UI.EndCombo() 50 | end 51 | end 52 | end -------------------------------------------------------------------------------- /packets/_bitreader.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | * Addons - Copyright (c) 2023 Ashita Development Team 3 | * Contact: https://www.ashitaxi.com/ 4 | * Contact: https://discord.gg/Ashita 5 | * 6 | * This file is part of Ashita. 7 | * 8 | * Ashita is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * Ashita is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with Ashita. If not, see . 20 | --]] 21 | 22 | require('common'); 23 | 24 | local bitreader = T{ 25 | data = nil, 26 | bit = 0, 27 | pos = 0, 28 | }; 29 | 30 | --[[ 31 | * Creates and returns a new bit reader instance. 32 | * 33 | * @param {table} o - The default object table, if provided. 34 | * @return {table} The bit reader instance. 35 | --]] 36 | function bitreader:new(o) 37 | o = o or T{}; 38 | 39 | setmetatable(o, self); 40 | self.__index = self; 41 | 42 | return o; 43 | end 44 | 45 | 46 | --[[ 47 | * Sets the current reader data. 48 | * 49 | * @param {string|table} data - The data to use with the reader. (Strings are converted to a byte table automatically.) 50 | --]] 51 | function bitreader:set_data(data) 52 | self.bit = 0; 53 | self.data = T{}; 54 | self.pos = 0; 55 | 56 | switch(type(data), T{ 57 | ['string'] = function () 58 | data:tohex():replace(' ', ''):gsub('(%x%x)', function (x) 59 | return table.insert(self.data, tonumber(x, 16)); 60 | end); 61 | end, 62 | ['table'] = function () 63 | self.data = data; 64 | end, 65 | [switch.default] = function () 66 | error('[BitReader] Invalid data type: ' .. type(data)); 67 | end, 68 | }); 69 | end 70 | 71 | --[[ 72 | * Sets the current reader position. 73 | * 74 | * @param {number} pos - The byte position to set the reader to. (Resets the bit position.) 75 | --]] 76 | function bitreader:set_pos(pos) 77 | self.bit = 0; 78 | self.pos = pos; 79 | end 80 | 81 | --[[ 82 | * Reads a packed value from the current data. 83 | * 84 | * @param {number} bits - The number of bits to read. 85 | * @return {number} The read value. 86 | --]] 87 | function bitreader:read(bits) 88 | local ret = 0; 89 | 90 | if (self.data == nil) then 91 | return ret; 92 | end 93 | 94 | for x = 0, bits - 1 do 95 | local val = bit.lshift(bit.band(self.data[self.pos + 1], 1), x); 96 | self.data[self.pos + 1] = bit.rshift(self.data[self.pos + 1], 1); 97 | ret = bit.bor(ret, val); 98 | 99 | self.bit = self.bit + 1; 100 | if (self.bit == 8) then 101 | self.bit = 0; 102 | self.pos = self.pos + 1; 103 | end 104 | end 105 | 106 | return ret; 107 | end 108 | 109 | -- Return the BitReader table.. 110 | return bitreader; -------------------------------------------------------------------------------- /packets/_parser.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | * Addons - Copyright (c) 2023 Ashita Development Team 3 | * Contact: https://www.ashitaxi.com/ 4 | * Contact: https://discord.gg/Ashita 5 | * 6 | * This file is part of Ashita. 7 | * 8 | * Ashita is free software: you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, either version 3 of the License, or 11 | * (at your option) any later version. 12 | * 13 | * Ashita is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | * GNU General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU General Public License 19 | * along with Ashita. If not, see . 20 | --]] 21 | 22 | require('common'); 23 | local breader = require('packets._bitreader'); 24 | 25 | -- Action parser table.. 26 | local parser = T{}; 27 | 28 | --[[ 29 | * Locates and returns the name of the actor of the given server id. 30 | * 31 | * @param {number} id - The server id of the actor to locate. 32 | * @return {string} The actor name. 33 | --]] 34 | local function get_actor_name(id) 35 | local ret = 'Unknown'; 36 | for x = 0, 2302 do 37 | local e = GetEntity(x); 38 | if (e and e.ServerId == id) then 39 | return e.Name; 40 | end 41 | end 42 | return ret; 43 | end 44 | 45 | --[[ 46 | * Parses the given action packet. 47 | * 48 | * @param {string} packet - The packet string to parse. 49 | * @return {table} The parsed action packet. 50 | --]] 51 | parser.parse = function (packet) 52 | local reader = breader:new(); 53 | reader:set_data(packet); 54 | reader:set_pos(5); 55 | 56 | local action = T{}; 57 | action.m_uID = reader:read(32); 58 | action.caster_name = get_actor_name(action.m_uID); 59 | action.trg_sum = reader:read(6); 60 | action.res_sum = reader:read(4); 61 | action.cmd_no = reader:read(4); 62 | action.cmd_arg = reader:read(32); 63 | action.info = reader:read(32); 64 | action.target = T{}; 65 | 66 | for _ = 0, action.trg_sum - 1 do 67 | local target = T{}; 68 | target.m_uID = reader:read(32); 69 | target.target_name = get_actor_name(target.m_uID); 70 | target.result_sum = reader:read(4); 71 | target.result = T{}; 72 | 73 | for _ = 0, target.result_sum - 1 do 74 | local result = T{}; 75 | result.miss = reader:read(3); 76 | result.kind = reader:read(2); 77 | result.sub_kind = reader:read(12); 78 | result.info = reader:read(5); 79 | result.scale = reader:read(5); 80 | result.value = reader:read(17); 81 | result.message = reader:read(10); 82 | result.bit = reader:read(31); 83 | 84 | if (reader:read(1) > 0) then 85 | result.has_proc = true; 86 | result.proc_kind = reader:read(6); 87 | result.proc_info = reader:read(4); 88 | result.proc_value = reader:read(17); 89 | result.proc_message = reader:read(10); 90 | else 91 | result.has_proc = false; 92 | result.proc_kind = 0; 93 | result.proc_info = 0; 94 | result.proc_value = 0; 95 | result.proc_message = 0; 96 | end 97 | 98 | if (reader:read(1) > 0) then 99 | result.has_react = true; 100 | result.react_kind = reader:read(6); 101 | result.react_info = reader:read(4); 102 | result.react_value = reader:read(14); 103 | result.react_message= reader:read(10); 104 | else 105 | result.has_react = false; 106 | result.react_kind = 0; 107 | result.react_info = 0; 108 | result.react_value = 0; 109 | result.react_message= 0; 110 | end 111 | 112 | table.insert(target.result, result); 113 | end 114 | 115 | table.insert(action.target, target); 116 | end 117 | 118 | return action; 119 | end 120 | 121 | --[[ 122 | * Returns the name of the given action command number. 123 | * 124 | * @param {number} cmd_no - The action command number. 125 | * @return {string} The command name. 126 | *--]] 127 | parser.get_action_name = function (cmd_no) 128 | return switch(cmd_no, T{ 129 | [ 0] = function () return 'None'; end, -- None. 130 | [ 1] = function () return 'Attack'; end, -- Basic Attack 131 | [ 2] = function () return 'R.Attack (F)'; end, -- Finish: Ranged Attack 132 | [ 3] = function () return 'WeaponSkill (F)'; end, -- Finish: Player Weapon Skills (Some job abilities use this such as Mug.) 133 | [ 4] = function () return 'Magic (F)'; end, -- Finish: Player and Monster Magic Casts 134 | [ 5] = function () return 'Item (F)'; end, -- Finish: Item Use 135 | [ 6] = function () return 'JobAbility (F)'; end, -- Finish: Player Job Abilities, DNC Reverse Flourish 136 | [ 7] = function () return 'Mon/WepSkill (S)'; end, -- Start: Monster Skill, Weapon Skill 137 | [ 8] = function () return 'Magic (S)'; end, -- Start: Player and Monster Magic Casts 138 | [ 9] = function () return 'Item (S)'; end, -- Start: Item Use 139 | [10] = function () return 'JobAbility (S)'; end, -- Start: Job Ability 140 | [11] = function () return 'MonSkill (F)'; end, -- Finish: Monster Skill 141 | [12] = function () return 'R.Attack (S)'; end, -- Start: Ranged Attack 142 | [14] = function () return 'Dancer'; end, -- Dancer Flourish, Samba, Step, Waltz 143 | [15] = function () return 'RuneFencer'; end, -- Rune Fencer Effusion, Ward 144 | [switch.default] = function() 145 | return ('%d:Unknown'):fmt(cmd_no); 146 | end, 147 | }); 148 | end 149 | 150 | --[[ 151 | * Returns the name of the given miss id. 152 | * 153 | * @param {number} id - The miss id. 154 | * @return {string} The miss name. 155 | *--]] 156 | parser.get_miss_name = function (id) 157 | return switch(id, T{ 158 | [0] = function () return 'hit'; end, -- Hit 159 | [1] = function () return 'miss'; end, -- Miss 160 | [2] = function () return 'guard'; end, -- Guard 161 | [3] = function () return 'parry'; end, -- Parry 162 | [4] = function () return 'block'; end, -- Block 163 | [9] = function () return 'evade'; end, -- Evade 164 | [switch.default] = function() 165 | return ('%d:unknown'):fmt(id); 166 | end, 167 | }); 168 | end 169 | 170 | -- Return the action parser table.. 171 | return parser; -------------------------------------------------------------------------------- /resources/avatars.lua: -------------------------------------------------------------------------------- 1 | Res.Avatar = T{} 2 | 3 | -- Based off of monster_abilities.lua from Windower. 4 | Res.Avatar.Rage = T{ 5 | -- Fenrir 6 | [831] = {id=831,en="Moonlit Charge",ja="ムーンリットチャージ"}, 7 | [832] = {id=832,en="Crescent Fang",ja="クレセントファング"}, 8 | [836] = {id=836,en="Eclipse Bite",ja="エクリプスバイト"}, 9 | [838] = {id=838,en="Howling Moon",ja="(ハウリングムーン)",skillchain_a="Darkness",skillchain_b="Distortion",skillchain_c=""}, 10 | [839] = {id=839,en="Howling Moon",ja="ハウリングムーン",skillchain_a="Darkness",skillchain_b="Distortion",skillchain_c=""}, 11 | -- Ifrit 12 | [840] = {id=840,en="Punch",ja="パンチ"}, 13 | [841] = {id=841,en="Fire II",ja="ファイアII"}, 14 | [842] = {id=842,en="Burning Strike",ja="バーニングストライク"}, 15 | [843] = {id=843,en="Double Punch",ja="ダブルパンチ"}, 16 | [845] = {id=845,en="Fire IV",ja="ファイアIV"}, 17 | [846] = {id=846,en="Flaming Crush",ja="フレイムクラッシュ"}, 18 | [847] = {id=847,en="Meteor Strike",ja="メテオストライク"}, 19 | [848] = {id=848,en="Inferno",ja="インフェルノ"}, 20 | -- Titan 21 | [849] = {id=849,en="Rock Throw",ja="ロックスロー"}, 22 | [850] = {id=850,en="Stone II",ja="ストーンII"}, 23 | [851] = {id=851,en="Rock Buster",ja="ロックバスター"}, 24 | [852] = {id=852,en="Megalith Throw",ja="メガリススロー"}, 25 | [854] = {id=854,en="Stone IV",ja="ストーンIV"}, 26 | [855] = {id=855,en="Mountain Buster",ja="マウンテンバスター"}, 27 | [856] = {id=856,en="Geocrush",ja="ジオクラッシュ"}, 28 | [857] = {id=857,en="Earthen Fury",ja="アースフューリー"}, 29 | -- Leviathan 30 | [858] = {id=858,en="Barracuda Dive",ja="バラクーダダイブ"}, 31 | [859] = {id=859,en="Water II",ja="ウォータII"}, 32 | [860] = {id=860,en="Tail Whip",ja="テールウィップ"}, 33 | [863] = {id=863,en="Water IV",ja="ウォータIV"}, 34 | [864] = {id=864,en="Spinning Dive",ja="スピニングダイブ"}, 35 | [865] = {id=865,en="Grand Fall",ja="グランドフォール"}, 36 | [866] = {id=866,en="Tidal Wave",ja="タイダルウェイブ"}, 37 | -- Garuda 38 | [867] = {id=867,en="Claw",ja="クロー"}, 39 | [868] = {id=868,en="Aero II",ja="エアロII"}, 40 | [872] = {id=872,en="Aero IV",ja="エアロIV"}, 41 | [873] = {id=873,en="Predator Claws",ja="プレデタークロー"}, 42 | [874] = {id=874,en="Wind Blade",ja="ウインドブレード"}, 43 | [875] = {id=875,en="Aerial Blast",ja="エリアルブラスト"}, 44 | -- Shiva 45 | [876] = {id=876,en="Axe Kick",ja="アクスキック"}, 46 | [877] = {id=877,en="Blizzard II",ja="ブリザドII"}, 47 | [880] = {id=880,en="Double Slap",ja="ダブルスラップ"}, 48 | [881] = {id=881,en="Blizzard IV",ja="ブリザドIV"}, 49 | [882] = {id=882,en="Rush",ja="ラッシュ"}, 50 | [883] = {id=883,en="Heavenly Strike",ja="ヘヴンリーストライク"}, 51 | [884] = {id=884,en="Diamond Dust",ja="ダイヤモンドダスト"}, 52 | -- Ramuh 53 | [885] = {id=885,en="Shock Strike",ja="ショックストライク"}, 54 | [886] = {id=886,en="Thunder II",ja="サンダーII"}, 55 | [888] = {id=888,en="Thunderspark",ja="サンダースパーク"}, 56 | [890] = {id=890,en="Thunder IV",ja="サンダーIV"}, 57 | [891] = {id=891,en="Chaotic Strike",ja="カオスストライク"}, 58 | [892] = {id=892,en="Thunderstorm",ja="サンダーストーム"}, 59 | [893] = {id=893,en="Judgment Bolt",ja="ジャッジボルト"}, 60 | -- Carbuncle 61 | [907] = {id=907,en="Poison Nails",ja="ポイズンネイル"}, 62 | [910] = {id=910,en="Meteorite",ja="プチメテオ"}, 63 | [912] = {id=912,en="Searing Light",ja="シアリングライト"}, 64 | -- Diabolos 65 | [1903] = {id=1903,en="Camisado",ja="カミサドー"}, 66 | [1904] = {id=1904,en="Somnolence",ja="ソムノレンス"}, 67 | [1909] = {id=1909,en="Cacodemonia",ja="カコデモニア"}, 68 | [1910] = {id=1910,en="Nether Blast",ja="ネザーブラスト"}, 69 | [1911] = {id=1911,en="Ruinous Omen",ja="ルイナスオーメン"}, 70 | [3554] = {id=3554,en="Night Terror",ja="ナイトテラー"}, 71 | [3555] = {id=3555,en="Ruinous Omen",ja="ルイナスオーメン"}, 72 | } 73 | 74 | -- Based off of monster_abilities.lua from Windower. 75 | Res.Avatar.Ward = T{ 76 | -- Fenrir 77 | [833] = {id=833,en="Lunar Cry",ja="ルナークライ"}, 78 | [834] = {id=834,en="Ecliptic Growl",ja="上弦の唸り"}, 79 | [835] = {id=835,en="Lunar Roar",ja="ルナーロア"}, 80 | [837] = {id=837,en="Ecliptic Howl",ja="下弦の咆哮"}, 81 | -- Ifrit 82 | [844] = {id=844,en="Crimson Roar",ja="紅蓮の咆哮"}, 83 | -- Titan 84 | [853] = {id=853,en="Earthen Ward",ja="大地の守り"}, 85 | -- Leviathan (Spring Water is Refresh on Horizon) 86 | [861] = {id=861,en="Spring Water",ja="湧水"}, 87 | [862] = {id=862,en="Slowga",ja="スロウガ"}, 88 | -- Garuda 89 | [869] = {id=869,en="Whispering Wind",ja="風の囁き"}, 90 | [870] = {id=870,en="Hastega",ja="ヘイスガ"}, 91 | [871] = {id=871,en="Aerial Armor",ja="真空の鎧"}, 92 | -- Shiva 93 | [878] = {id=878,en="Frost Armor",ja="凍てつく鎧"}, 94 | [879] = {id=879,en="Sleepga",ja="スリプガ"}, 95 | -- Ramuh 96 | [887] = {id=887,en="Rolling Thunder",ja="雷鼓"}, 97 | [889] = {id=889,en="Lightning Armor",ja="雷電の鎧"}, 98 | -- Carbuncle 99 | [906] = {id=906,en="Healing Ruby",ja="ルビーの癒し"}, 100 | [908] = {id=908,en="Shining Ruby",ja="ルビーの輝き"}, 101 | [909] = {id=909,en="Glittering Ruby",ja="ルビーの煌き"}, 102 | [911] = {id=911,en="Healing Ruby II",ja="ルビーの癒しII"}, 103 | -- Diabolos 104 | [1905] = {id=1905,en="Noctoshield",ja="ノクトシールド"}, 105 | [1906] = {id=1906,en="Ultimate Terror",ja="アルティメットテラー"}, 106 | [1907] = {id=1907,en="Dream Shroud",ja="ドリームシュラウド"}, 107 | [1908] = {id=1908,en="Nightmare",ja="ナイトメア"}, 108 | } 109 | 110 | -- Based off of monster_abilities.lua from Windower. 111 | Res.Avatar.Healing = T{ 112 | -- Garuda 113 | [869] = {id=869,en="Whispering Wind",ja="風の囁き"}, 114 | -- Carbuncle 115 | [906] = {id=906,en="Healing Ruby",ja="ルビーの癒し"}, 116 | [911] = {id=911,en="Healing Ruby II",ja="ルビーの癒しII"}, 117 | } 118 | -------------------------------------------------------------------------------- /resources/colors.lua: -------------------------------------------------------------------------------- 1 | Res.Colors = T{} 2 | 3 | Res.Colors.Basic = { 4 | -- Base Colors 5 | WHITE = {1.00, 1.00, 1.00, 1.0}, 6 | RED = {1.00, 0.00, 0.00, 1.0}, 7 | GREEN = {0.00, 1.00, 0.00, 1.0}, 8 | BLUE = {0.00, 0.00, 1.00, 1.0}, 9 | ORANGE = {0.90, 0.60, 0.00, 1.0}, 10 | YELLOW = {0.90, 1.00, 0.00, 1.0}, 11 | BR_GREEN = {0.20, 1.00, 0.00, 1.0}, 12 | PURPLE = {0.70, 0.20, 1.00, 1.0}, 13 | DIM = {0.50, 0.50, 0.50, 1.0}, 14 | INACTIVE = {0.14, 0.14, 0.14, 1.0}, 15 | MOB = {0.60, 0.60, 0.60, 1.0}, 16 | -- Elements 17 | LIGHT = {1.0, 1.0, 1.0, 1.0}, 18 | DARK = {0.9, 0.0, 1.0, 1.0}, 19 | FIRE = {1.0, 0.0, 0.0, 1.0}, 20 | ICE = {0.0, 0.7, 1.0, 1.0}, 21 | WIND = {0.0, 1.0, 0.0, 1.0}, 22 | EARTH = {0.7, 0.5, 0.0, 1.0}, 23 | THUNDER = {0.7, 0.2, 1.0, 1.0}, 24 | WATER = {0.3, 0.5, 0.8, 1.0}, 25 | } 26 | 27 | Res.Colors.Elements = { 28 | [0] = Res.Colors.Basic.FIRE, 29 | [1] = Res.Colors.Basic.ICE, 30 | [2] = Res.Colors.Basic.WIND, 31 | [3] = Res.Colors.Basic.EARTH, 32 | [4] = Res.Colors.Basic.THUNDER, 33 | [5] = Res.Colors.Basic.WATER, 34 | [6] = Res.Colors.Basic.LIGHT, 35 | [7] = Res.Colors.Basic.DARK, 36 | } 37 | 38 | Res.Colors.Avatars = { 39 | Carbuncle = Res.Colors.Basic.LIGHT, 40 | Fenrir = Res.Colors.Basic.DARK, 41 | Diabolos = Res.Colors.Basic.DARK, 42 | Ifrit = Res.Colors.Basic.FIRE, 43 | Shiva = Res.Colors.Basic.ICE, 44 | Garuda = Res.Colors.Basic.WIND, 45 | Titan = Res.Colors.Basic.EARTH, 46 | Ramuh = Res.Colors.Basic.THUNDER, 47 | Leviathan = Res.Colors.Basic.WATER, 48 | } 49 | 50 | Res.Colors.Jobs = T{ 51 | [0] = {0.40, 0.40, 0.40, 1.0}, -- NON 52 | [1] = {0.90, 0.00, 0.00, 1.0}, -- WAR 53 | [2] = {0.96, 0.77, 0.01, 1.0}, -- MNK 54 | [3] = {1.00, 1.00, 1.00, 1.0}, -- WHM 55 | [4] = {0.65, 0.52, 0.74, 1.0}, -- BLM 56 | [5] = {0.91, 0.39, 0.40, 1.0}, -- RDM 57 | [6] = {0.03, 0.76, 0.11, 1.0}, -- THF 58 | [7] = {0.90, 0.98, 0.09, 1.0}, -- PLD 59 | [8] = {0.90, 0.00, 1.00, 1.0}, -- DRK 60 | [9] = {0.80, 0.73, 0.47, 1.0}, -- BST 61 | [10] = {0.97, 0.64, 0.91, 1.0}, -- BRD 62 | [11] = {0.43, 0.77, 0.35, 1.0}, -- RNG 63 | [12] = {0.99, 0.43, 0.01, 1.0}, -- SAM 64 | [13] = {0.96, 0.19, 0.00, 1.0}, -- NIN 65 | [14] = {0.70, 0.29, 0.98, 1.0}, -- DRG 66 | [15] = {0.44, 0.99, 0.71, 1.0}, -- SMN 67 | [16] = {0.30, 0.56, 0.83, 1.0}, -- BLU 68 | [17] = {0.79, 0.46, 0.34, 1.0}, -- COR 69 | [18] = {0.51, 0.48, 0.67, 1.0}, -- PUP 70 | [19] = {0.00, 0.00, 0.00, 1.0}, -- DNC 71 | [20] = {0.00, 0.00, 0.00, 1.0}, -- SCH 72 | [21] = {0.00, 0.00, 0.00, 1.0}, -- GEO 73 | [22] = {0.00, 0.00, 0.00, 1.0}, -- RUN 74 | } 75 | 76 | Res.Colors.XP = T{ 77 | [1] = {0.83, 0.65, 0.31, 1.0}, -- Experience 78 | [2] = {0.30, 0.56, 0.83, 1.0}, -- Limit 79 | } -------------------------------------------------------------------------------- /resources/game.lua: -------------------------------------------------------------------------------- 1 | Res.Game = T{} 2 | 3 | Res.Game.Effect_Animation = T{ 4 | [1] = "Fire", 5 | [2] = "Ice", 6 | [3] = "Wind", 7 | [4] = "Earth", 8 | [5] = "Lightning", 9 | [6] = "Water", 10 | [7] = "Light", 11 | [8] = "Dark", 12 | [9] = "Sleep", 13 | [10] = "Poison", 14 | [11] = "Paralyze", 15 | [12] = "Blind", 16 | [13] = "Silence", 17 | [16] = "Stun", 18 | [17] = "Curse", 19 | [18] = "Stat Down", 20 | [21] = "Drain", 21 | [22] = "Aspir", 22 | [23] = "Haste", 23 | } -------------------------------------------------------------------------------- /resources/items.lua: -------------------------------------------------------------------------------- 1 | Res.Items = T{} 2 | 3 | Res.Items.Dedication = T{ 4 | [0] = {name = "Unknown", boost = -1, max = -1}, 5 | [8191] = {name = "Wandering Heroes", boost = 75, max = 10000}, 6 | [15793] = {name = "Anniversary Ring", boost = 100, max = 3000}, 7 | [15763] = {name = "Emperor Band", boost = 75, max = 2250}, 8 | [15762] = {name = "Empress Band", boost = 50, max = 1000}, 9 | [15761] = {name = "Chariot Band", boost = 100, max = 4000}, 10 | } 11 | 12 | -- Used for item dropdown selection. 13 | Res.Items.Dedication_Selection = T{ 14 | [1] = "Chariot Band", -- 15761 15 | [2] = "Emperor Band", -- 15763 16 | [3] = "Empress Band", -- 15762 17 | [4] = "Wandering Heroes", -- 8191 18 | [5] = "Anniversary Ring", -- 15793 19 | } 20 | 21 | Res.Items.Dedication_Name_To_ID = T{ 22 | ["Chariot Band"] = 15761, 23 | ["Emperor Band"] = 15763, 24 | ["Empress Band"] = 15762, 25 | ["Wandering Heroes"] = 8191, 26 | ["Anniversary Ring"] = 15793, 27 | } -------------------------------------------------------------------------------- /resources/jobs.lua: -------------------------------------------------------------------------------- 1 | Res.Jobs = T{} 2 | 3 | Res.Jobs.List = T{ 4 | [0] = {id=0,en="None",ja="なし",ens="NON",jas=""}, 5 | [1] = {id=1,en="Warrior",ja="戦士",ens="WAR",jas="戦"}, 6 | [2] = {id=2,en="Monk",ja="モンク",ens="MNK",jas="モ"}, 7 | [3] = {id=3,en="White Mage",ja="白魔道士",ens="WHM",jas="白"}, 8 | [4] = {id=4,en="Black Mage",ja="黒魔道士",ens="BLM",jas="黒"}, 9 | [5] = {id=5,en="Red Mage",ja="赤魔道士",ens="RDM",jas="赤"}, 10 | [6] = {id=6,en="Thief",ja="シーフ",ens="THF",jas="シ"}, 11 | [7] = {id=7,en="Paladin",ja="ナイト",ens="PLD",jas="ナ"}, 12 | [8] = {id=8,en="Dark Knight",ja="暗黒騎士",ens="DRK",jas="暗"}, 13 | [9] = {id=9,en="Beastmaster",ja="獣使い",ens="BST",jas="獣"}, 14 | [10] = {id=10,en="Bard",ja="吟遊詩人",ens="BRD",jas="詩"}, 15 | [11] = {id=11,en="Ranger",ja="狩人",ens="RNG",jas="狩"}, 16 | [12] = {id=12,en="Samurai",ja="侍",ens="SAM",jas="侍"}, 17 | [13] = {id=13,en="Ninja",ja="忍者",ens="NIN",jas="忍"}, 18 | [14] = {id=14,en="Dragoon",ja="竜騎士",ens="DRG",jas="竜"}, 19 | [15] = {id=15,en="Summoner",ja="召喚士",ens="SMN",jas="召"}, 20 | [16] = {id=16,en="Blue Mage",ja="青魔道士",ens="BLU",jas="青"}, 21 | [17] = {id=17,en="Corsair",ja="コルセア",ens="COR",jas="コ"}, 22 | [18] = {id=18,en="Puppetmaster",ja="からくり士",ens="PUP",jas="か"}, 23 | [19] = {id=19,en="Dancer",ja="踊り子",ens="DNC",jas="踊"}, 24 | [20] = {id=20,en="Scholar",ja="学者",ens="SCH",jas="学"}, 25 | [21] = {id=21,en="Geomancer",ja="風水士",ens="GEO",jas="風"}, 26 | [22] = {id=22,en="Rune Fencer",ja="魔導剣士",ens="RUN",jas="剣"}, 27 | [23] = {id=23,en="Monipulator",ja="モンストロス",ens="MON",jas="MON"}, 28 | } 29 | 30 | --[[ 31 | Copyright © 2013-2023, Windower 32 | All rights reserved. 33 | 34 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 35 | 36 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 37 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 38 | * Neither the name of Windower nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 39 | 40 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Windower BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 41 | ]] 42 | -------------------------------------------------------------------------------- /resources/pets.lua: -------------------------------------------------------------------------------- 1 | Res.Pets = T{} 2 | 3 | -- Based off of monster_abilities.lua from Windower. 4 | Res.Pets.Damaging_Wyvern_Breath = T{ 5 | [646] = {id=900,en="Flame Breath",ja="フレイムブレス"}, 6 | [647] = {id=901,en="Frost Breath",ja="フロストブレス"}, 7 | [648] = {id=902,en="Gust Breath",ja="ガストブレス"}, 8 | [649] = {id=903,en="Sand Breath",ja="サンドブレス"}, 9 | [650] = {id=904,en="Lightning Breath",ja="ライトニングブレス"}, 10 | [651] = {id=905,en="Hydro Breath",ja="ハイドロブレス"}, 11 | } 12 | 13 | Res.Pets.Healing_Wyvern_Breath = T{ 14 | [639] = {id=639,en="Healing Breath IV"}, 15 | [640] = {id=894,en="Healing Breath",ja="ヒールブレス"}, 16 | [641] = {id=895,en="Healing Breath II",ja="ヒールブレスII"}, 17 | [642] = {id=896,en="Healing Breath III",ja="ヒールブレスIII"}, 18 | } -------------------------------------------------------------------------------- /resources/themes.lua: -------------------------------------------------------------------------------- 1 | local themes = {} 2 | 3 | themes.Elements = { 4 | ImGuiCol_Text = 0; 5 | ImGuiCol_TextDisabled = 1; 6 | ImGuiCol_WindowBg = 2; -- Background of normal windows 7 | ImGuiCol_ChildBg = 3; -- Background of child windows 8 | ImGuiCol_PopupBg = 4; -- Background of popups, menus, tooltips windows 9 | ImGuiCol_Border = 5; 10 | ImGuiCol_BorderShadow = 6; 11 | ImGuiCol_FrameBg = 7; -- Background of checkbox, radio button, plot, slider, text input 12 | ImGuiCol_FrameBgHovered = 8; 13 | ImGuiCol_FrameBgActive = 9; 14 | ImGuiCol_TitleBg = 10; 15 | ImGuiCol_TitleBgActive = 11; 16 | ImGuiCol_TitleBgCollapsed = 12; 17 | ImGuiCol_MenuBarBg = 13; 18 | ImGuiCol_ScrollbarBg = 14; 19 | ImGuiCol_ScrollbarGrab = 15; 20 | ImGuiCol_ScrollbarGrabHovered = 16; 21 | ImGuiCol_ScrollbarGrabActive = 17; 22 | ImGuiCol_CheckMark = 18; 23 | ImGuiCol_SliderGrab = 19; 24 | ImGuiCol_SliderGrabActive = 20; 25 | ImGuiCol_Button = 21; 26 | ImGuiCol_ButtonHovered = 22; 27 | ImGuiCol_ButtonActive = 23; 28 | ImGuiCol_Header = 24; -- Header* colors are used for CollapsingHeader, TreeNode, Selectable, MenuItem 29 | ImGuiCol_HeaderHovered = 25; 30 | ImGuiCol_HeaderActive = 26; 31 | ImGuiCol_Separator = 27; 32 | ImGuiCol_SeparatorHovered = 28; 33 | ImGuiCol_SeparatorActive = 29; 34 | ImGuiCol_ResizeGrip = 30; 35 | ImGuiCol_ResizeGripHovered = 31; 36 | ImGuiCol_ResizeGripActive = 32; 37 | ImGuiCol_Tab = 33; 38 | ImGuiCol_TabHovered = 34; 39 | ImGuiCol_TabActive = 35; 40 | ImGuiCol_TabUnfocused = 36; 41 | ImGuiCol_TabUnfocusedActive = 37; 42 | ImGuiCol_PlotLines = 38; 43 | ImGuiCol_PlotLinesHovered = 39; 44 | ImGuiCol_PlotHistogram = 40; 45 | ImGuiCol_PlotHistogramHovered = 41; 46 | ImGuiCol_TableHeaderBg = 42; -- Table header background 47 | ImGuiCol_TableBorderStrong = 43; -- Table outer and header borders (prefer using Alpha=1.0 here) 48 | ImGuiCol_TableBorderLight = 44; -- Table inner borders (prefer using Alpha=1.0 here) 49 | ImGuiCol_TableRowBg = 45; -- Table row background (even rows) 50 | ImGuiCol_TableRowBgAlt = 46; -- Table row background (odd rows) 51 | ImGuiCol_TextSelectedBg = 47; 52 | ImGuiCol_DragDropTarget = 48; 53 | ImGuiCol_NavHighlight = 49; -- Gamepad/keyboard: current highlighted item 54 | ImGuiCol_NavWindowingHighlight = 50; -- Highlight window when using CTRL+TAB 55 | ImGuiCol_NavWindowingDimBg = 51; -- Darken/colorize entire screen behind the CTRL+TAB window list, when active 56 | ImGuiCol_ModalWindowDimBg = 52; -- Darken/colorize entire screen behind a modal window, when one is active 57 | } 58 | 59 | themes.Default = { 60 | ImGuiCol_Text = {0.94, 0.94, 0.94, 1.00}, 61 | ImGuiCol_TextDisabled = {0.94, 0.94, 0.94, 0.29}, 62 | ImGuiCol_WindowBg = {0.18, 0.20, 0.23, 0.96}, 63 | ImGuiCol_ChildBg = {0.22, 0.24, 0.27, 0.96}, 64 | ImGuiCol_PopupBg = {0.05, 0.05, 0.10, 0.90}, 65 | ImGuiCol_Border = {0.05, 0.05, 0.10, 0.80}, 66 | ImGuiCol_BorderShadow = {0.00, 0.00, 0.00, 0.00}, 67 | ImGuiCol_FrameBg = {0.16, 0.17, 0.20, 1.00}, 68 | ImGuiCol_FrameBgHovered = {0.14, 0.14, 0.14, 0.78}, 69 | ImGuiCol_FrameBgActive = {0.12, 0.12, 0.12, 1.00}, 70 | ImGuiCol_TitleBg = {0.83, 0.33, 0.28, 0.69}, 71 | ImGuiCol_TitleBgActive = {0.83, 0.33, 0.28, 1.00}, 72 | ImGuiCol_TitleBgCollapsed = {0.83, 0.33, 0.28, 0.50}, 73 | ImGuiCol_MenuBarBg = {0.12, 0.13, 0.17, 1.00}, 74 | ImGuiCol_ScrollbarBg = {0.12, 0.13, 0.17, 1.00}, 75 | ImGuiCol_ScrollbarGrab = {0.83, 0.33, 0.28, 0.69}, 76 | ImGuiCol_ScrollbarGrabHovered = {0.83, 0.33, 0.28, 1.00}, 77 | ImGuiCol_ScrollbarGrabActive = {0.83, 0.33, 0.28, 1.00}, 78 | ImGuiCol_CheckMark = {0.83, 0.33, 0.28, 1.00}, 79 | ImGuiCol_SliderGrab = {0.83, 0.33, 0.28, 0.69}, 80 | ImGuiCol_SliderGrabActive = {0.83, 0.33, 0.28, 1.00}, 81 | ImGuiCol_Button = {0.83, 0.33, 0.28, 0.78}, 82 | ImGuiCol_ButtonHovered = {0.83, 0.33, 0.28, 1.00}, 83 | ImGuiCol_ButtonActive = {0.83, 0.33, 0.28, 1.00}, 84 | ImGuiCol_Header = {0.83, 0.33, 0.28, 0.78}, 85 | ImGuiCol_HeaderHovered = {0.83, 0.33, 0.28, 1.00}, 86 | ImGuiCol_HeaderActive = {0.83, 0.33, 0.28, 1.00}, 87 | ImGuiCol_Separator = {0.43, 0.43, 0.50, 0.50}, 88 | ImGuiCol_SeparatorHovered = {0.10, 0.40, 0.75, 0.78}, 89 | ImGuiCol_SeparatorActive = {0.10, 0.40, 0.75, 1.00}, 90 | ImGuiCol_ResizeGrip = {0.05, 0.05, 0.05, 0.69}, 91 | ImGuiCol_ResizeGripHovered = {0.83, 0.33, 0.28, 1.00}, 92 | ImGuiCol_ResizeGripActive = {0.83, 0.33, 0.28, 1.00}, 93 | ImGuiCol_Tab = {0.05, 0.05, 0.05, 0.69}, 94 | ImGuiCol_TabHovered = {0.83, 0.33, 0.28, 1.00}, 95 | ImGuiCol_TabActive = {0.83, 0.33, 0.28, 1.00}, 96 | ImGuiCol_TabUnfocused = {0.07, 0.10, 0.15, 0.97}, 97 | ImGuiCol_TabUnfocusedActive = {0.14, 0.26, 0.42, 1.00}, 98 | ImGuiCol_PlotLines = {0.83, 0.33, 0.28, 1.00}, 99 | ImGuiCol_PlotLinesHovered = {0.81, 0.81, 0.81, 1.00}, 100 | ImGuiCol_PlotHistogram = {0.83, 0.33, 0.28, 1.00}, 101 | ImGuiCol_PlotHistogramHovered = {0.81, 0.81, 0.81, 1.00}, 102 | ImGuiCol_TableHeaderBg = {0.05, 0.05, 0.05, 0.69}, 103 | ImGuiCol_TableBorderStrong = {0.10, 0.10, 0.10, 1.00}, 104 | ImGuiCol_TableBorderLight = {0.15, 0.15, 0.15, 1.00}, 105 | ImGuiCol_TableRowBg = {0.00, 0.00, 0.00, 0.00}, 106 | ImGuiCol_TableRowBgAlt = {1.00, 1.00, 1.00, 0.06}, 107 | ImGuiCol_TextSelectedBg = {0.83, 0.33, 0.28, 0.50}, 108 | ImGuiCol_DragDropTarget = {1.00, 1.00, 0.00, 0.90}, 109 | ImGuiCol_NavHighlight = {1.00, 1.00, 0.00, 1.00}, 110 | ImGuiCol_NavWindowingHighlight = {0.83, 0.33, 0.28, 1.00}, 111 | ImGuiCol_NavWindowingDimBg = {0.00, 0.00, 0.00, 0.60}, 112 | ImGuiCol_ModalWindowDimBg = {0.05, 0.05, 0.05, 0.78}, 113 | } 114 | 115 | return themes -------------------------------------------------------------------------------- /resources/weapon_skills_curated.lua: -------------------------------------------------------------------------------- 1 | Res.WS = T{} 2 | 3 | -- Based off of weapons_skills.lua from Windower. 4 | Res.WS.Missing = T{ 5 | [260] = {id = 260, english = "Spirit Jump"}, 6 | [293] = {id = 293, english = "Soul Jump"}, 7 | [329] = {id = 329, english = "Intervene"}, 8 | [3502] = {id = 3502, english = "Nott"} 9 | } 10 | 11 | -- Based off of weapons_skills.lua from Windower. 12 | Res.WS.Abilities = T{ 13 | [26] = {id = 26, english = "Eagle Eye Shot"}, 14 | [41] = {id = 41, english = "Steal"}, 15 | [45] = {id = 45, english = "Mug"}, 16 | [46] = {id = 46, english = "Shield Bash"}, 17 | [57] = {id = 57, english = "Shadowbind"}, 18 | [66] = {id = 66, english = "Jump"}, 19 | [67] = {id = 67, english = "High Jump"}, 20 | [68] = {id = 68, english = "Super Jump"}, 21 | [77] = {id = 77, english = "Weapon Bash"}, 22 | [228] = {id = 228, english = "Despoil"}, 23 | [260] = {id = 260, english = "Spirit Jump"}, 24 | [293] = {id = 293, english = "Soul Jump"}, 25 | [329] = {id = 329, english = "Intervene"}, 26 | } 27 | 28 | -- Based off of weapons_skills.lua from Windower. 29 | Res.WS.MP_Drain = T{ 30 | [21] = {id=21,en="Energy Steal",ja="エナジースティール",element=7,icon_id=596,prefix="/weaponskill",range=2,skill=2,skillchain_a="",skillchain_b="",skillchain_c="",targets=32}, 31 | -- [22] = {id=22,en="Energy Drain",ja="エナジードレイン",element=7,icon_id=596,prefix="/weaponskill",range=2,skill=2,skillchain_a="",skillchain_b="",skillchain_c="",targets=32}, 32 | [163] = {id=163,en="Starlight",ja="スターライト",element=6,icon_id=628,prefix="/weaponskill",range=2,skill=11,skillchain_a="",skillchain_b="",skillchain_c="",targets=1}, 33 | [164] = {id=164,en="Moonlight",ja="ムーンライト",element=6,icon_id=628,prefix="/weaponskill",range=2,skill=11,skillchain_a="",skillchain_b="",skillchain_c="",targets=1}, 34 | [183] = {id=183,en="Spirit Taker",ja="スピリットテーカー",element=6,icon_id=631,prefix="/weaponskill",range=2,skill=12,skillchain_a="",skillchain_b="",skillchain_c="",targets=32}, 35 | } 36 | 37 | Res.WS.Skillchains = T{ 38 | [229] = 'DRG Jump Effect', 39 | [288] = 'Light', [289] = 'Darkness', 40 | [290] = 'Gravitation', [291] = 'Fragmentation', [292] = 'Distortion', [293] = 'Fusion', 41 | [294] = 'Compression', [295] = 'Liquefaction', [296] = 'Induration', [297] = 'Reverberation', 42 | [298] = 'Transfixion', [299] = 'Scission', [300] = 'Detonation', [301] = 'Impaction', 43 | [385] = 'Light', [386] = 'Darkness', 44 | [767] = 'Radiance', [768] = 'Umbra' 45 | } -------------------------------------------------------------------------------- /throttling.lua: -------------------------------------------------------------------------------- 1 | Throttle = T{} 2 | Throttle.Enabled = true 3 | Throttle.Mod = 10 4 | Throttle.Tick = 0 5 | Throttle.Need_Refresh = true 6 | 7 | ------------------------------------------------------------------------------------------------------ 8 | -- Provides a gate to throttle performance intensive calculations. 9 | ------------------------------------------------------------------------------------------------------ 10 | Throttle.Throttle = function() 11 | Throttle.Tick = (Throttle.Tick + 1) % Throttle.Mod 12 | if Throttle.Tick == 0 then Throttle.Need_Refresh = true end 13 | end 14 | 15 | ------------------------------------------------------------------------------------------------------ 16 | -- Returns whether throttling is enabled or not. 17 | ------------------------------------------------------------------------------------------------------ 18 | ---@return boolean 19 | ------------------------------------------------------------------------------------------------------ 20 | Throttle.Is_Enabled = function() 21 | return Throttle.Enabled 22 | end 23 | 24 | ------------------------------------------------------------------------------------------------------ 25 | -- Toggle whether throttling is turned on or off. 26 | ------------------------------------------------------------------------------------------------------ 27 | Throttle.Toggle = function() 28 | Throttle.Enabled = not Throttle.Enabled 29 | end 30 | 31 | ------------------------------------------------------------------------------------------------------ 32 | -- Returns whether the caller is permitted to perform its calculation or not. 33 | ------------------------------------------------------------------------------------------------------ 34 | ---@return boolean 35 | ------------------------------------------------------------------------------------------------------ 36 | Throttle.Allow_Calculation = function() 37 | return Throttle.Need_Refresh 38 | end 39 | 40 | ------------------------------------------------------------------------------------------------------ 41 | -- Blocks calculation until the next throttle window opens up. 42 | ------------------------------------------------------------------------------------------------------ 43 | Throttle.Block = function() 44 | Throttle.Need_Refresh = false 45 | end -------------------------------------------------------------------------------- /timers.lua: -------------------------------------------------------------------------------- 1 | local timers = T{} 2 | 3 | timers.Timers = T{} 4 | 5 | timers.Enum = T{} 6 | timers.Enum.Names = T{ 7 | METRICS = "Total Runtime", 8 | PARSE = "Active Time", 9 | AUTOPAUSE = "Auto-Pause", 10 | AUTOSAVE = "Auto-Save", 11 | DPS = "DPS", 12 | EXP = "EXP", 13 | CHAIN = "Chain", 14 | ZONE = "Zone", 15 | } 16 | 17 | timers.Tresholds = T{ 18 | AUTOPAUSE = 5, 19 | } 20 | 21 | ------------------------------------------------------------------------------------------------------ 22 | -- Start the timer. 23 | ------------------------------------------------------------------------------------------------------ 24 | ---@param name string name of the timer to check. 25 | ------------------------------------------------------------------------------------------------------ 26 | timers.Start = function(name) 27 | if not name then name = "Default" end 28 | if not timers.Timers[name] then 29 | timers.Timers[name] = T{ 30 | Start = os.time(), 31 | Duration = 0, 32 | Paused = false 33 | } 34 | end 35 | end 36 | 37 | ------------------------------------------------------------------------------------------------------ 38 | -- Pause the timer. 39 | ------------------------------------------------------------------------------------------------------ 40 | ---@param name string name of the timer to check. 41 | ------------------------------------------------------------------------------------------------------ 42 | timers.Pause = function(name) 43 | if timers.Timers[name] then 44 | if not timers.Timers[name].Paused then 45 | local new_duration = os.time() - timers.Timers[name].Start 46 | timers.Timers[name].Paused = true 47 | timers.Timers[name].Duration = timers.Timers[name].Duration + new_duration 48 | end 49 | end 50 | end 51 | 52 | ------------------------------------------------------------------------------------------------------ 53 | -- Unpause the timer. 54 | ------------------------------------------------------------------------------------------------------ 55 | ---@param name string name of the timer to check. 56 | ------------------------------------------------------------------------------------------------------ 57 | timers.Unpause = function(name) 58 | if timers.Timers[name] then 59 | if timers.Timers[name].Paused then 60 | timers.Timers[name].Start = os.time() 61 | timers.Timers[name].Paused = false 62 | end 63 | end 64 | end 65 | 66 | ------------------------------------------------------------------------------------------------------ 67 | -- Checks if a timer is paused. 68 | ------------------------------------------------------------------------------------------------------ 69 | ---@param name string name of the timer to check. 70 | ---@return boolean 71 | ------------------------------------------------------------------------------------------------------ 72 | timers.Is_Paused = function(name) 73 | if timers.Timers[name] then 74 | return timers.Timers[name].Paused 75 | end 76 | return false 77 | end 78 | 79 | ------------------------------------------------------------------------------------------------------ 80 | -- Resets the timer. 81 | ------------------------------------------------------------------------------------------------------ 82 | ---@param name string name of the timer to check. 83 | ------------------------------------------------------------------------------------------------------ 84 | timers.Reset = function(name) 85 | timers.Timers[name] = nil 86 | timers.Start(name) 87 | end 88 | 89 | ------------------------------------------------------------------------------------------------------ 90 | -- Gets the duration for a timer. 91 | ------------------------------------------------------------------------------------------------------ 92 | ---@param name string name of the timer to check. 93 | ---@return number 94 | ------------------------------------------------------------------------------------------------------ 95 | timers.Get_Duration = function(name) 96 | local duration = 0 97 | if timers.Timers[name] then 98 | duration = timers.Timers[name].Duration 99 | if not timers.Timers[name].Paused then 100 | local start = timers.Timers[name].Start 101 | local now = os.time() 102 | duration = duration + (now - start) 103 | end 104 | end 105 | return duration 106 | end 107 | 108 | ------------------------------------------------------------------------------------------------------ 109 | -- Check the timer. 110 | ------------------------------------------------------------------------------------------------------ 111 | ---@param name string name of the timer to check. 112 | ---@param countdown? boolean true: count down; false: count up 113 | ---@return string 114 | ------------------------------------------------------------------------------------------------------ 115 | timers.Check = function(name, countdown) 116 | if timers.Timers[name] then 117 | local duration = timers.Get_Duration(name) 118 | if countdown then 119 | return timers.Format((countdown * 60) - duration) 120 | else 121 | return timers.Format(duration) 122 | end 123 | end 124 | return timers.Format() 125 | end 126 | 127 | ------------------------------------------------------------------------------------------------------ 128 | -- Take an action when a timer passes its threshold. 129 | ------------------------------------------------------------------------------------------------------ 130 | ---@param name string name of the timer to check. 131 | ------------------------------------------------------------------------------------------------------ 132 | timers.Cycle = function(name) 133 | local duration = timers.Get_Duration(name) 134 | if name == Timers.Enum.Names.AUTOPAUSE then 135 | if duration > timers.Tresholds.AUTOPAUSE then 136 | timers.Pause(timers.Enum.Names.PARSE) 137 | end 138 | elseif name == Timers.Enum.Names.DPS then 139 | if duration > DB.DPS.Snapshot_Time then 140 | DB.DPS.Create_Snapshot() 141 | timers.Reset(Timers.Enum.Names.DPS) 142 | end 143 | elseif name == Timers.Enum.Names.EXP then 144 | if duration > XP.Local.Bucket_Length then 145 | XP.Local.Cycle_Window() 146 | timers.Reset(Timers.Enum.Names.EXP) 147 | end 148 | end 149 | end 150 | 151 | ------------------------------------------------------------------------------------------------------ 152 | -- Formats the display timer. 153 | ------------------------------------------------------------------------------------------------------ 154 | ---@param time? number duration in seconds. 155 | ---@param hide_hour? boolean 156 | ---@return string 157 | ------------------------------------------------------------------------------------------------------ 158 | timers.Format = function(time, hide_hour) 159 | if not time then return '00:00' end 160 | local hour, minute, second 161 | hour = string.format("%02.f", math.floor(time / 3600)) 162 | minute = string.format("%02.f", math.floor((time / 60) - (hour * 60))) 163 | second = string.format("%02.f", math.floor(time % 60)) 164 | local formatted_time = minute .. ":" .. second 165 | if not hide_hour then formatted_time = hour .. ":" .. formatted_time end 166 | return formatted_time 167 | end 168 | 169 | return timers -------------------------------------------------------------------------------- /windows/!window.lua: -------------------------------------------------------------------------------- 1 | Window = T{} 2 | 3 | function Window:New(settings) 4 | 5 | local self = T{} 6 | settings = settings or T{} 7 | 8 | local name = settings.Name or "Default" 9 | local title = settings.Title or "Default Title" 10 | local module = settings.Module or "Default" 11 | local x = settings.X or 100 12 | local y = settings.Y or 100 13 | local show_title = settings.Show_Title or false 14 | local show_bg = true 15 | 16 | local need_position_reset = true 17 | local scaling_set = false 18 | local visible = {false} 19 | 20 | local flags_default = bit.bor( 21 | ImGuiWindowFlags_AlwaysAutoResize, -- This prevents manual resizing, but without it things look messed up. 22 | ImGuiWindowFlags_NoSavedSettings, 23 | ImGuiWindowFlags_NoNav 24 | ) 25 | 26 | ------------------------------------------------------------------------------------------------------ 27 | -- Populates the window. 28 | ------------------------------------------------------------------------------------------------------ 29 | ---@param content? function 30 | ------------------------------------------------------------------------------------------------------ 31 | self.Populate = function(content) 32 | visible[1] = Window_Manager.Get_Visibility(module) 33 | if Ashita.Player.Is_Zoning() or not visible[1] then return nil end 34 | 35 | UI.PushStyleVar(ImGuiStyleVar_Alpha, Metrics.Window.Alpha) 36 | UI.PushStyleVar(ImGuiStyleVar_CellPadding, {10, 1}) 37 | UI.PushStyleVar(ImGuiStyleVar_WindowPadding, {7, 3}) 38 | UI.PushStyleVar(ImGuiStyleVar_ItemSpacing, {0, 5}) 39 | UI.PushStyleVar(ImGuiStyleVar_ItemInnerSpacing, {5, 0}) 40 | 41 | local flags = flags_default 42 | if not Metrics.Window.Show_Title and not show_title then flags = bit.bor(flags, ImGuiWindowFlags_NoTitleBar) end 43 | if not show_bg then flags = bit.bor(flags, ImGuiWindowFlags_NoBackground) end 44 | self.Check_Position() 45 | 46 | if UI.Begin(title, visible, flags) then 47 | self.Update_Settings() 48 | self.Set_Scaling() 49 | Window_Manager.Theme.Set() 50 | if content then content() end 51 | UI.End() 52 | end 53 | 54 | UI.PopStyleVar(5) 55 | end 56 | 57 | ------------------------------------------------------------------------------------------------------ 58 | -- Checks if the position of the window needs to be reset ex: switching characters. 59 | ------------------------------------------------------------------------------------------------------ 60 | self.Check_Position = function() 61 | if need_position_reset then 62 | UI.SetNextWindowPos(Window_Manager.Get_Position(module), ImGuiCond_Always) 63 | need_position_reset = false 64 | end 65 | end 66 | 67 | ------------------------------------------------------------------------------------------------------ 68 | -- Updates the window position for the settings file. 69 | ------------------------------------------------------------------------------------------------------ 70 | self.Update_Settings = function() 71 | x, y = UI.GetWindowPos() 72 | Window_Manager.Save_Position(module, x, y) 73 | Window_Manager.Save_Visibility(module, visible[1]) 74 | end 75 | 76 | ------------------------------------------------------------------------------------------------------ 77 | -- Checks whether the window is currently visible. 78 | ------------------------------------------------------------------------------------------------------ 79 | self.Is_Visible = function() 80 | return visible[1] 81 | end 82 | 83 | ------------------------------------------------------------------------------------------------------ 84 | -- Toggles window visibility. 85 | ------------------------------------------------------------------------------------------------------ 86 | self.Toggle_Visibility = function() 87 | visible[1] = not visible[1] 88 | Window_Manager.Save_Visibility(module, visible[1]) 89 | end 90 | 91 | ------------------------------------------------------------------------------------------------------ 92 | -- Makes the window visible. 93 | ------------------------------------------------------------------------------------------------------ 94 | self.Show = function() 95 | visible[1] = true 96 | Window_Manager.Save_Visibility(module, true) 97 | end 98 | 99 | ------------------------------------------------------------------------------------------------------ 100 | -- Makes the window invisible. 101 | ------------------------------------------------------------------------------------------------------ 102 | self.Hide = function() 103 | visible[1] = false 104 | Window_Manager.Save_Visibility(module, false) 105 | end 106 | 107 | ------------------------------------------------------------------------------------------------------ 108 | -- Makes the window active either by switching to the tab or by toggling the window. 109 | ------------------------------------------------------------------------------------------------------ 110 | self.Make_Active = function() 111 | Window_Manager.Switch_Module(name) 112 | self.Toggle_Visibility() 113 | end 114 | 115 | ------------------------------------------------------------------------------------------------------ 116 | -- Forces the position to need a reset for cases like character switch. 117 | ------------------------------------------------------------------------------------------------------ 118 | self.Settings_Reset = function() 119 | need_position_reset = true 120 | scaling_set = false 121 | end 122 | 123 | ------------------------------------------------------------------------------------------------------ 124 | -- Sets the window scaling. 125 | ------------------------------------------------------------------------------------------------------ 126 | self.Set_Scaling = function() 127 | if not scaling_set then 128 | UI.SetWindowFontScale(Window_Manager.Get_Scaling()) 129 | scaling_set = true 130 | end 131 | end 132 | 133 | ------------------------------------------------------------------------------------------------------ 134 | -- Forces the scaling flag to reset after toggling the scaling setting. 135 | ------------------------------------------------------------------------------------------------------ 136 | self.Force_Scaling_Reset = function() 137 | scaling_set = false 138 | end 139 | 140 | ------------------------------------------------------------------------------------------------------ 141 | -- Forces the scaling flag to reset after toggling the scaling setting. 142 | ------------------------------------------------------------------------------------------------------ 143 | ---@param background boolean 144 | ------------------------------------------------------------------------------------------------------ 145 | self.Set_Background = function(background) 146 | show_bg = background 147 | end 148 | 149 | Window_Manager.Add_Window(module, module, self) 150 | return self 151 | end 152 | -------------------------------------------------------------------------------- /windows/config.lua: -------------------------------------------------------------------------------- 1 | Window_Manager.Config = T{} 2 | 3 | Window_Manager.Config.Defaults = T{ 4 | Alpha = 1.0, 5 | Window_Scaling = 1.0, 6 | Style = 0, 7 | X_Pos = 100, 8 | Y_Pos = 100, 9 | Show_Title = false, 10 | Show_Mouse = false, 11 | Multi_Window = false, 12 | Active_Window = "Parse", 13 | Hub_X = 100, 14 | Hub_Y = 100, 15 | Screenshot_X = 100, 16 | Screenshot_Y = 100, 17 | Config_Window_Visible = {false}, 18 | Config_X = 100, 19 | Config_Y = 100, 20 | } 21 | 22 | ------------------------------------------------------------------------------------------------------ 23 | -- Resets visual settings in the window. 24 | ------------------------------------------------------------------------------------------------------ 25 | Window_Manager.Config.Reset = function() 26 | Metrics.Window.Alpha = Window_Manager.Defaults.Alpha 27 | Metrics.Window.Window_Scaling = Window_Manager.Defaults.Window_Scaling 28 | Metrics.Window.Show_Title = Window_Manager.Defaults.Show_Title 29 | end 30 | 31 | ------------------------------------------------------------------------------------------------------ 32 | -- Shows settings that affect the GUI. 33 | ------------------------------------------------------------------------------------------------------ 34 | Window_Manager.Config.Display = function() 35 | if UI.BeginTable("GUI Setings", 2) then 36 | UI.TableNextColumn() 37 | if UI.Checkbox("Show Title Bar", {Metrics.Window.Show_Title}) then 38 | Metrics.Window.Show_Title = not Metrics.Window.Show_Title 39 | end 40 | UI.SameLine() Window_Manager.Widgets.HelpMarker("Enables a window header that allows you to collapse the window.") 41 | 42 | UI.TableNextColumn() 43 | if UI.Checkbox("Show Mouse", {Metrics.Window.Show_Mouse}) then 44 | Window_Manager.Toggle_Mouse() 45 | end 46 | UI.SameLine() Window_Manager.Widgets.HelpMarker("There are a lot of click targets in Metrics. If you can't see your mouse when hovering over " .. 47 | "the windows of ImGui based addons and would like to then give this a try. It will show your regular " .. 48 | "Windows mouse on top of your regular in game cursor.") 49 | 50 | UI.TableNextColumn() 51 | if UI.Checkbox("Multi Window", {Metrics.Window.Multi_Window}) then 52 | Metrics.Window.Multi_Window = not Metrics.Window.Multi_Window 53 | if Metrics.Window.Multi_Window then 54 | Metrics.Window.Active_Window = nil 55 | Config.Window.Show() 56 | else 57 | Metrics.Window.Active_Window = Config.Name 58 | Config.Window.Hide() 59 | end 60 | end 61 | UI.SameLine() Window_Manager.Widgets.HelpMarker("Have mutliple tabs open at once by enabling multiple windows. Be cautious running at " .. 62 | "higher FPS with multiple windows open. It may affect performance.") 63 | UI.EndTable() 64 | end 65 | 66 | UI.Separator() Window_Manager.Theme.Choose() 67 | UI.Separator() Window_Manager.Widgets.Alpha() 68 | Window_Manager.Widgets.Window_Scale() 69 | end -------------------------------------------------------------------------------- /windows/themes.lua: -------------------------------------------------------------------------------- 1 | Window_Manager.Theme = T{} 2 | 3 | Window_Manager.Theme.Is_Set = false 4 | Window_Manager.Theme.Table_Row_Bg = {0.00, 0.00, 0.00, 0.00} 5 | 6 | ------------------------------------------------------------------------------------------------------ 7 | -- Change the window themes. 8 | -- Modeled from the ImGui demo. 9 | -- https://github.com/ocornut/imgui/blob/master/imgui_demo.cpp 10 | ------------------------------------------------------------------------------------------------------ 11 | Window_Manager.Theme.Choose = function() 12 | UI.Text("Theme (will affect other ImGui based addons)") 13 | if UI.RadioButton("Default ", {Metrics.Window.Style}, 0) then 14 | Metrics.Window.Style = 0 15 | Window_Manager.Theme.Is_Set = false 16 | end 17 | UI.SameLine() 18 | if UI.RadioButton("Dark ", {Metrics.Window.Style}, 1) then 19 | Metrics.Window.Style = 1 20 | Window_Manager.Theme.Is_Set = false 21 | end 22 | UI.SameLine() 23 | if UI.RadioButton("Classic ", {Metrics.Window.Style}, 3) then 24 | Metrics.Window.Style = 3 25 | Window_Manager.Theme.Is_Set = false 26 | end 27 | Window_Manager.Theme.Set() 28 | end 29 | 30 | ------------------------------------------------------------------------------------------------------ 31 | -- Change the window themes. 32 | -- Modeled from the ImGui demo. 33 | -- https://github.com/ocornut/imgui/blob/master/imgui_demo.cpp 34 | ------------------------------------------------------------------------------------------------------ 35 | Window_Manager.Theme.Set = function() 36 | if not Window_Manager.Theme.Is_Set then 37 | if Metrics.Window.Style == 0 then 38 | Window_Manager.Theme.Apply_Custom(Themes.Default) 39 | Window_Manager.Theme.Table_Row_Bg = {0.18, 0.20, 0.23, 1.00} 40 | elseif Metrics.Window.Style == 1 then 41 | UI.StyleColorsDark() 42 | Window_Manager.Theme.Table_Row_Bg = {0.06, 0.06, 0.06, 1.00} 43 | elseif Metrics.Window.Style == 2 then 44 | UI.StyleColorsLight() 45 | elseif Metrics.Window.Style == 3 then 46 | UI.StyleColorsClassic() 47 | Window_Manager.Theme.Table_Row_Bg = {0.00, 0.00, 0.00, 1.00} 48 | else 49 | Window_Manager.Theme.Apply_Custom(Themes.Default) 50 | end 51 | Window_Manager.Theme.Is_Set = true 52 | end 53 | end 54 | 55 | ------------------------------------------------------------------------------------------------------ 56 | -- Applies a custom theme. 57 | ------------------------------------------------------------------------------------------------------ 58 | ---@param theme table defined in resources.themes. 59 | ------------------------------------------------------------------------------------------------------ 60 | Window_Manager.Theme.Apply_Custom = function(theme) 61 | for flag_name, flag_value in pairs(Themes.Elements) do 62 | if theme[flag_name] then 63 | UI.PushStyleColor(flag_value, theme[flag_name]) 64 | end 65 | end 66 | end -------------------------------------------------------------------------------- /windows/widgets.lua: -------------------------------------------------------------------------------- 1 | Window_Manager.Widgets = T{} 2 | 3 | Window_Manager.Widgets.Slider_Width = 100 4 | 5 | ------------------------------------------------------------------------------------------------------ 6 | -- Creates a help text marker. 7 | ------------------------------------------------------------------------------------------------------ 8 | Window_Manager.Widgets.HelpMarker = function(text) 9 | UI.TextDisabled("(?)") 10 | if UI.IsItemHovered() then 11 | UI.BeginTooltip() 12 | UI.PushTextWrapPos(UI.GetFontSize() * 25) 13 | UI.TextUnformatted(text) 14 | UI.PopTextWrapPos() 15 | UI.EndTooltip() 16 | end 17 | end 18 | 19 | ------------------------------------------------------------------------------------------------------ 20 | -- Sets screen alpha. 21 | ------------------------------------------------------------------------------------------------------ 22 | Window_Manager.Widgets.Alpha = function() 23 | local alpha = {[1] = Metrics.Window.Alpha} 24 | UI.SetNextItemWidth(Window_Manager.Widgets.Slider_Width) 25 | if UI.DragFloat("Window Transparency", alpha, 0.005, 0.2, 1, "%.2f", ImGuiSliderFlags_None) then 26 | if alpha[1] < 0.2 then alpha[1] = 0.2 27 | elseif alpha[1] > 1 then alpha[1] = 1 end 28 | Metrics.Window.Alpha = alpha[1] 29 | end 30 | UI.SameLine() Window_Manager.Widgets.HelpMarker("Window transparency.") 31 | end 32 | 33 | ------------------------------------------------------------------------------------------------------ 34 | -- Sets window scaling. 35 | ------------------------------------------------------------------------------------------------------ 36 | Window_Manager.Widgets.Window_Scale = function() 37 | local window_scale = {[1] = Metrics.Window.Window_Scaling} 38 | UI.SetNextItemWidth(Window_Manager.Widgets.Slider_Width) 39 | if UI.DragFloat("Window Scaling", window_scale, 0.005, 0.7, 3, "%.2f", ImGuiSliderFlags_None) then 40 | if window_scale[1] < 0.7 then window_scale[1] = 0.7 41 | elseif window_scale[1] > 3 then window_scale[1] = 3 end 42 | Metrics.Window.Window_Scaling = window_scale[1] 43 | Window_Manager.Reset_Scaling_Flags() 44 | end 45 | UI.SameLine() Window_Manager.Widgets.HelpMarker("Adjust window element size.") 46 | end --------------------------------------------------------------------------------