| 1 | --[[ ***** see Iris2 COPYING for license info ***** ]]-- |
|---|
| 2 | --[[ \brief |
|---|
| 3 | handles macro list |
|---|
| 4 | ]]-- |
|---|
| 5 | |
|---|
| 6 | gMacroList = {} |
|---|
| 7 | |
|---|
| 8 | gMacroOpenCommands = {} |
|---|
| 9 | gMacroOpenCommands.Status = function() ToggleStatusAos() end |
|---|
| 10 | gMacroOpenCommands.Skill = function() ToggleSkill() end |
|---|
| 11 | gMacroOpenCommands.Journal = function() ToggleJournal() end |
|---|
| 12 | gMacroOpenCommands.Backpack = function() TogglePlayerBackpack() end |
|---|
| 13 | gMacroOpenCommands.Paperdoll = function() TogglePlayerPaperdoll() end |
|---|
| 14 | gMacroOpenCommands.Compass = function() ToggleCompass() end |
|---|
| 15 | gMacroOpenCommands.Logo = function() ToggleLogo() end |
|---|
| 16 | gMacroOpenCommands.PartyList = function() TogglePartyList() end |
|---|
| 17 | |
|---|
| 18 | gMacroItemSlots = {} |
|---|
| 19 | gMacroReadMobileStats = {} |
|---|
| 20 | gMacroReadMobileStats.curHits = true |
|---|
| 21 | gMacroReadMobileStats.maxHits = true |
|---|
| 22 | gMacroReadMobileStats.curMana = true |
|---|
| 23 | gMacroReadMobileStats.maxMana = true |
|---|
| 24 | gMacroReadMobileStats.curStamina = true |
|---|
| 25 | gMacroReadMobileStats.maxStamina = true |
|---|
| 26 | gMacroReadMobileStats.curWeight = true |
|---|
| 27 | gMacroReadMobileStats.maxWeight = true |
|---|
| 28 | gMacroReadMobileStats.maxPet = true |
|---|
| 29 | gMacroReadMobileStats.curPet = true |
|---|
| 30 | gMacroReadMobileStats.tithing = true |
|---|
| 31 | |
|---|
| 32 | function GetMobileStat(mobile,statname) return mobile and mobile.stats and mobile.stats[statname] or 0 end |
|---|
| 33 | function GetMobileRelHP(serial) local mobile = GetMobile(serial) return mobile and mobile:GetRelHP() end |
|---|
| 34 | |
|---|
| 35 | function GetPlayerManaCur() return GetMobileStat(GetPlayerMobile(),"curMana") end |
|---|
| 36 | function GetPlayerManaMax() return GetMobileStat(GetPlayerMobile(),"maxMana") end |
|---|
| 37 | function GetPlayerStamCur() return GetMobileStat(GetPlayerMobile(),"curStamina") end |
|---|
| 38 | function GetPlayerStamMax() return GetMobileStat(GetPlayerMobile(),"maxStamina") end |
|---|
| 39 | function GetPlayerHitsCur() return GetMobileStat(GetPlayerMobile(),"curHits") end |
|---|
| 40 | function GetPlayerHitsMax() return GetMobileStat(GetPlayerMobile(),"maxHits") end |
|---|
| 41 | function GetPlayerPetsCur() return GetMobileStat(GetPlayerMobile(),"curPet") end -- follower slots |
|---|
| 42 | function GetPlayerPetsMax() return GetMobileStat(GetPlayerMobile(),"maxPet") end |
|---|
| 43 | function GetPlayerTithingPoints() return GetMobileStat(GetPlayerMobile(),"tithing") end |
|---|
| 44 | function IsPlayerHidden() local mobile = GetPlayerMobile() return mobile and mobile.flag_hidden end |
|---|
| 45 | |
|---|
| 46 | function MacroCmd_MobilePoisoned (mobile) return mobile and IsMobilePoisoned(mobile) end |
|---|
| 47 | function MacroCmd_MobileMortaled (mobile) return mobile and IsMobileMortaled(mobile) end |
|---|
| 48 | |
|---|
| 49 | function MacroCmd_MiniHealCureSelf () |
|---|
| 50 | if (not GetPlayerMobile()) then return end |
|---|
| 51 | if (MacroCmd_MobilePoisoned(GetPlayerMobile())) then |
|---|
| 52 | MacroCmd_Spell("Cure" ,GetPlayerSerial()) |
|---|
| 53 | else |
|---|
| 54 | MacroCmd_Spell("Heal" ,GetPlayerSerial()) |
|---|
| 55 | end |
|---|
| 56 | end |
|---|
| 57 | |
|---|
| 58 | kSmartSpellHealSmall = 4 |
|---|
| 59 | kSmartSpellHealBig = 29 |
|---|
| 60 | kSmartSpellCureSmall = 11 |
|---|
| 61 | kSmartSpellCureBig = 25 |
|---|
| 62 | -- returns serial,bIsFriendly |
|---|
| 63 | function MacroCmd_GetSmartTargetForLastSpell () -- smart targets for friendly spells (heal,cure) |
|---|
| 64 | if (gSmartLastSpellID) then |
|---|
| 65 | if (gSmartLastSpellID == kSmartSpellHealSmall or gSmartLastSpellID == kSmartSpellHealBig) then |
|---|
| 66 | local target = MobileList_GetWeakestFromList(MobileList_HealablePartyMembers(true)) |
|---|
| 67 | --~ print("healtarget",target) |
|---|
| 68 | return target and target.serial or GetPlayerSerial(),true |
|---|
| 69 | end |
|---|
| 70 | if (gSmartLastSpellID == kSmartSpellCureSmall or gSmartLastSpellID == kSmartSpellCureBig) then |
|---|
| 71 | local target = MobileList_GetWeakestFromList(MobileList_CurablePartyMembers(true)) |
|---|
| 72 | --~ print("curetarget",target) |
|---|
| 73 | return target and target.serial or GetPlayerSerial(),true |
|---|
| 74 | end |
|---|
| 75 | end |
|---|
| 76 | -- gLastSpellID |
|---|
| 77 | return MobListGetMainTargetSerial() |
|---|
| 78 | end |
|---|
| 79 | |
|---|
| 80 | function MobileList_GetWeakestFromList (list) |
|---|
| 81 | local found |
|---|
| 82 | local foundhp |
|---|
| 83 | for k,mobile in pairs(list) do |
|---|
| 84 | local curhp = mobile:GetRelHP() or 1 |
|---|
| 85 | --~ print("MobileList_GetWeakestFromList",curhp) |
|---|
| 86 | if ((not foundhp) or foundhp > curhp) then foundhp = curhp found = mobile end |
|---|
| 87 | end |
|---|
| 88 | return found |
|---|
| 89 | end |
|---|
| 90 | |
|---|
| 91 | -- checking if a mob has equip helps detecting humans/players |
|---|
| 92 | function MobileHasEquip (mobile) |
|---|
| 93 | for index,layer in pairs(gLayerOrder) do |
|---|
| 94 | -- slime has kLayer_Backpack , dog not |
|---|
| 95 | if (layer ~= kLayer_Backpack and mobile:GetEquipmentAtLayer(layer)) then return true end |
|---|
| 96 | end |
|---|
| 97 | return false |
|---|
| 98 | end |
|---|
| 99 | function MobileIsHuman (mobile) |
|---|
| 100 | return mobile and |
|---|
| 101 | mobile.artid == 400 or mobile.artid == 401 or |
|---|
| 102 | mobile.artid == 744 or mobile.artid == 745 or MobileHasEquip(mobile) |
|---|
| 103 | end |
|---|
| 104 | |
|---|
| 105 | function MobileList_GetByFilter (fun) |
|---|
| 106 | local res = {} |
|---|
| 107 | for k,mobile in pairs(GetMobileList()) do if (fun(mobile)) then table.insert(res,mobile) end end |
|---|
| 108 | return res |
|---|
| 109 | end |
|---|
| 110 | |
|---|
| 111 | |
|---|
| 112 | function MobileList_HealablePartyMembers (bFriendsAlso) |
|---|
| 113 | return MobileList_GetByFilter(function (mobile) return GetUODistToPlayer(mobile.xloc,mobile.yloc) <= gSpellCastRange and |
|---|
| 114 | (not MacroCmd_MobilePoisoned(mobile)) and (not MacroCmd_MobileMortaled(mobile)) and |
|---|
| 115 | (IsMobileInParty(mobile.serial) or (bFriendsAlso and mobile.notoriety == kNotoriety_Friend and MobileIsHuman(mobile))) and |
|---|
| 116 | (mobile:GetRelHP() or 0) < 1 and |
|---|
| 117 | (mobile:GetRelHP() or 0) > 0 end) -- not dead |
|---|
| 118 | end |
|---|
| 119 | function MobileList_CurablePartyMembers (bFriendsAlso) |
|---|
| 120 | return MobileList_GetByFilter(function (mobile) return GetUODistToPlayer(mobile.xloc,mobile.yloc) <= gSpellCastRange and |
|---|
| 121 | (MacroCmd_MobilePoisoned(mobile)) and |
|---|
| 122 | (IsMobileInParty(mobile.serial) or (bFriendsAlso and mobile.notoriety == kNotoriety_Friend and MobileIsHuman(mobile))) and |
|---|
| 123 | (mobile:GetRelHP() or 0) < 1 end) |
|---|
| 124 | end |
|---|
| 125 | |
|---|
| 126 | -- GetPlayerMobile |
|---|
| 127 | function MacroRead_PlayerStat (statname) return MacroReadAux_MobileStat(GetPlayerMobile(),statname,"MacroRead_PlayerStat") end |
|---|
| 128 | function MacroRead_TargetStat (statname) return MacroReadAux_MobileStat(GetMobile(giSelectedMobile),statname,"MacroRead_TargetStat") end |
|---|
| 129 | |
|---|
| 130 | function MacroRead_SkillDataPart (skillname,partname) -- internal, used by the others |
|---|
| 131 | for skillid,name in pairs(glSkillNames) do |
|---|
| 132 | if skillname == name then return gPlayerSkills and gPlayerSkills[skillid] and gPlayerSkills[skillid][partname] end |
|---|
| 133 | end |
|---|
| 134 | end |
|---|
| 135 | function MacroRead_SkillBaseSum () |
|---|
| 136 | local c = 0 |
|---|
| 137 | for skillid,name in pairs(glSkillNames) do c = c + MacroRead_SkillBase(name) end |
|---|
| 138 | return c |
|---|
| 139 | end |
|---|
| 140 | function MacroRead_SkillBase (skillname) return (MacroRead_SkillDataPart(skillname,"base_value") or -1) * 0.1 end |
|---|
| 141 | function MacroRead_SkillCap (skillname) return (MacroRead_SkillDataPart(skillname,"skill_cap") or -1) * 0.1 end |
|---|
| 142 | function MacroRead_SkillValue (skillname) return (MacroRead_SkillDataPart(skillname,"value") or -1) * 0.1 end |
|---|
| 143 | function MacroRead_SkillLockState (skillname) return MacroRead_SkillDataPart(skillname,"lockstate") end -- 0=up, 1=down, 2=lock |
|---|
| 144 | function MacroCmd_SetSkillLockState (skillname,lockstate) |
|---|
| 145 | for skillid,name in pairs(glSkillNames) do |
|---|
| 146 | if skillname == name then Send_SkillLockState(skillid-1,tonumber(lockstate) or 0) return true end |
|---|
| 147 | end |
|---|
| 148 | end -- 0=up, 1=down, 2=lock |
|---|
| 149 | |
|---|
| 150 | |
|---|
| 151 | |
|---|
| 152 | function MacroRead_BuffActive (buffname) |
|---|
| 153 | for id,v in pairs(gBuffIcons) do |
|---|
| 154 | if buffname == v.name then |
|---|
| 155 | return gBuffs[id] or false |
|---|
| 156 | end |
|---|
| 157 | end |
|---|
| 158 | return false |
|---|
| 159 | end |
|---|
| 160 | |
|---|
| 161 | function MacroCmd_Say (text) if (gInGameStarted) then SendChat(text) end end |
|---|
| 162 | function MacroCmd_NextCamMode () gCurrentRenderer:ChangeCamMode() end |
|---|
| 163 | function MacroCmd_BandageSelf () SendBandageSelf() end |
|---|
| 164 | function MacroCmd_Quit () Terminate() end |
|---|
| 165 | function MacroCmd_RepeatLastChat () if (gInGameStarted) then IrisChatLine_RepeatLast() end end |
|---|
| 166 | function MacroCmd_RepeatLastDoubleClick () if (gInGameStarted) then RepeatLastDoubleClick() end end |
|---|
| 167 | function MacroCmd_SelectNearestMobile () if (gInGameStarted) then SelectNearestMobile() end end |
|---|
| 168 | function MacroCmd_SelectNextMobile () if (gInGameStarted) then SelectNextMobile() end end |
|---|
| 169 | function MacroCmd_AttackSelectedMobile () if (gInGameStarted) then if giSelectedMobile then AttackMobile(giSelectedMobile) end end end |
|---|
| 170 | function MacroCmd_ToggleWarmode () if (gInGameStarted) then Send_CombatMode(IsWarModeActive() and gWarmode_Normal or gWarmode_Combat) end end |
|---|
| 171 | function MacroCmd_OpenDoors () Send_OpenDoors() end |
|---|
| 172 | function MacroCmd_Open (dialogtype) |
|---|
| 173 | if (not gInGameStarted) then return end |
|---|
| 174 | local f = gMacroOpenCommands[dialogtype] |
|---|
| 175 | if (not f) then return MacroErrorNameMismatch("MacroCmd_Open",dialogtype,gMacroOpenCommands) end |
|---|
| 176 | f() |
|---|
| 177 | end |
|---|
| 178 | |
|---|
| 179 | function MacroCmd_UseNearbyGate () local gate = MacroCmd_Item_FindFirstNearByArtID(kMoongateGateArtID,nil,1) MacroCmd_Item_Use(gate) return gate ~= nil end |
|---|
| 180 | |
|---|
| 181 | function MacroCmd_ToggleHideGUI () GuiToggleHide() Client_RenderOneFrame() end |
|---|
| 182 | |
|---|
| 183 | |
|---|
| 184 | function MacroCmd_PopupCommandByTag (serial,tag,timeout) |
|---|
| 185 | local timeout_endt = Client_GetTicks() + (timeout or 1000) |
|---|
| 186 | Send_PopupRequest(serial) |
|---|
| 187 | Send_PopupAnswer(serial,tag) |
|---|
| 188 | RegisterListener("Hook_OpenPopupMenu",function (popupmenu) |
|---|
| 189 | if (popupmenu.serial == serial or Client_GetTicks() < timeout_endt) then ClosePopUpMenu() end |
|---|
| 190 | return true |
|---|
| 191 | end) |
|---|
| 192 | end |
|---|
| 193 | |
|---|
| 194 | function MacroCmd_PopupCommandByName (serial,name,timeout) |
|---|
| 195 | if (not serial) then return end |
|---|
| 196 | if (type(serial) ~= "number") then return end |
|---|
| 197 | local timeout_endt = Client_GetTicks() + (timeout or 1000) |
|---|
| 198 | ClosePopUpMenu() -- close old |
|---|
| 199 | Send_PopupRequest(serial) |
|---|
| 200 | RegisterListener("Hook_OpenPopupMenu",function (popupmenu) |
|---|
| 201 | if (popupmenu.serial == serial or Client_GetTicks() < timeout_endt) then |
|---|
| 202 | for k,entry in pairs(popupmenu.entries) do |
|---|
| 203 | print("MacroCmd_PopupCommandByName",">"..entry.text.."<") |
|---|
| 204 | if (StringContains(entry.text,name)) then Send_PopupAnswer(popupmenu.serial,entry.tag) break end |
|---|
| 205 | end |
|---|
| 206 | ClosePopUpMenu() |
|---|
| 207 | end |
|---|
| 208 | return true |
|---|
| 209 | end) |
|---|
| 210 | end |
|---|
| 211 | |
|---|
| 212 | function MacroCmd_SendTargetSerial (serial,maxrange) |
|---|
| 213 | local mobile = GetMobile(serial) |
|---|
| 214 | if mobile then return CompleteTargetMode({ hittype = kMousePickHitType_Mobile, mobile = mobile },maxrange) end |
|---|
| 215 | local dynamic = GetDynamic(serial) |
|---|
| 216 | if dynamic then return CompleteTargetMode({ hittype = kMousePickHitType_Dynamic, dynamic = dynamic },maxrange) end |
|---|
| 217 | end |
|---|
| 218 | |
|---|
| 219 | -- timeout : in ms |
|---|
| 220 | -- bFailBySpellInterrupt : if true, then it will be aborted if a message indicating spell interruption is received |
|---|
| 221 | function MacroCmd_QueueTargetSerial (serial,timeout,callback,bFailBySpellInterrupt) |
|---|
| 222 | gMacroQueuedTarget_Serial = serial |
|---|
| 223 | gMacroQueuedTarget_Timeout = Client_GetTicks() + timeout |
|---|
| 224 | gMacroQueuedTarget_CallBack = callback |
|---|
| 225 | gMacroQueuedTarget_FailBySpellInterrupt = bFailBySpellInterrupt |
|---|
| 226 | if (IsTargetModeActive()) then |
|---|
| 227 | MacroCmd_SendTargetSerial(serial) |
|---|
| 228 | MacroCmd_QueuedTargetEnd(true) |
|---|
| 229 | end |
|---|
| 230 | end |
|---|
| 231 | function MacroCmd_QueuedTargetEnd (bSuccess,sFailureReason) |
|---|
| 232 | if (gMacroQueuedTarget_CallBack) then gMacroQueuedTarget_CallBack(bSuccess,sFailureReason) end |
|---|
| 233 | gMacroQueuedTarget_CallBack = nil |
|---|
| 234 | gMacroQueuedTarget_Serial = nil |
|---|
| 235 | gMacroQueuedTarget_Timeout = nil |
|---|
| 236 | gMacroQueuedTarget_FailBySpellInterrupt = nil |
|---|
| 237 | end |
|---|
| 238 | |
|---|
| 239 | RegisterStepper(function () |
|---|
| 240 | local t = Client_GetTicks() |
|---|
| 241 | if (gMacroQueuedTarget_Timeout and t > gMacroQueuedTarget_Timeout) then MacroCmd_QueuedTargetEnd(false,"timeout") end |
|---|
| 242 | for data,v in pairs(gMacroGumpWaiters) do |
|---|
| 243 | if (t > data.timeout) then data.callback() gMacroGumpWaiters[data] = nil end |
|---|
| 244 | end |
|---|
| 245 | end) |
|---|
| 246 | RegisterListener("Hook_Spell_Interrupt", function () |
|---|
| 247 | if (gMacroQueuedTarget_FailBySpellInterrupt) then MacroCmd_QueuedTargetEnd(false,"spell-interrupt") end |
|---|
| 248 | end) |
|---|
| 249 | gMacroJobsWaitingForTarget = {} |
|---|
| 250 | function MacroCmd_JobWaitForTarget(timeout) -- returns true if IsTargetModeActive |
|---|
| 251 | if (IsTargetModeActive()) then return true end |
|---|
| 252 | gMacroJobsWaitingForTarget[job.running_id()] = true |
|---|
| 253 | job.wait(timeout or 30000) |
|---|
| 254 | gMacroJobsWaitingForTarget[job.running_id()] = nil |
|---|
| 255 | return IsTargetModeActive() |
|---|
| 256 | end |
|---|
| 257 | RegisterListener("Hook_TargetMode_Start", function () |
|---|
| 258 | if (gMacroQueuedTarget_Serial) then MacroCmd_SendTargetSerial(gMacroQueuedTarget_Serial) MacroCmd_QueuedTargetEnd(true) end |
|---|
| 259 | for jobid,v in pairs(gMacroJobsWaitingForTarget) do job.wakeup(jobid,true) end gMacroJobsWaitingForTarget = {} |
|---|
| 260 | end) |
|---|
| 261 | RegisterListener("Hook_TargetMode_Start", function () |
|---|
| 262 | if (gMacroQueuedTarget_Serial) then MacroCmd_SendTargetSerial(gMacroQueuedTarget_Serial) MacroCmd_QueuedTargetEnd(true) end |
|---|
| 263 | end) |
|---|
| 264 | |
|---|
| 265 | gMacroJobsWaitingForGump = {} |
|---|
| 266 | function MacroCmd_JobWaitForGump(callback,timeout) -- callback(dialog,playerid,dialogId) should return true for the gump that it waited for |
|---|
| 267 | gMacroJobsWaitingForGump[job.running_id()] = callback |
|---|
| 268 | job.wait(timeout or 30000) |
|---|
| 269 | gMacroJobsWaitingForGump[job.running_id()] = nil |
|---|
| 270 | end |
|---|
| 271 | function MacroCmd_JobWaitForGumpWithKeyword(keyword,timeout) |
|---|
| 272 | local dialog = MacroCmd_FindGumpByKeyword(keyword) |
|---|
| 273 | if (dialog) then return dialog end |
|---|
| 274 | MacroCmd_JobWaitForGump(function(dialog) return dialog:Search(keyword) end,timeout) |
|---|
| 275 | return MacroCmd_FindGumpByKeyword(keyword) |
|---|
| 276 | end |
|---|
| 277 | function MacroCmd_FindGumpByKeyword(keyword) |
|---|
| 278 | for k,dialog in pairs(gServerSideGump) do |
|---|
| 279 | if (dialog:Search(keyword)) then return dialog end |
|---|
| 280 | end |
|---|
| 281 | end |
|---|
| 282 | |
|---|
| 283 | RegisterListener("Hook_OpenServersideGump", function (dialog,playerid,dialogId,Length_Data) |
|---|
| 284 | for data,v in pairs(gMacroGumpWaiters) do |
|---|
| 285 | if ((not data.search) or dialog:Search(data.search)) then data.callback(dialog) gMacroGumpWaiters[data] = nil end |
|---|
| 286 | end |
|---|
| 287 | |
|---|
| 288 | for jobid,callback in pairs(gMacroJobsWaitingForGump) do |
|---|
| 289 | if ((not callback) or callback(dialog,playerid,dialogId)) then |
|---|
| 290 | job.wakeup(jobid,true) |
|---|
| 291 | gMacroJobsWaitingForGump[jobid] = nil |
|---|
| 292 | end |
|---|
| 293 | end |
|---|
| 294 | end) |
|---|
| 295 | |
|---|
| 296 | gMacroGumpWaiters = {} |
|---|
| 297 | -- callback(dialog) or callback(nil) for timeout |
|---|
| 298 | function MacroCmd_NextGumpContaining (search,timeout,callback) |
|---|
| 299 | if (not callback) then return end |
|---|
| 300 | gMacroGumpWaiters[{search=search,timeout=Client_GetTicks()+(timeout or 1000),callback=callback}] = true |
|---|
| 301 | end |
|---|
| 302 | |
|---|
| 303 | |
|---|
| 304 | gMacroJobsWaitingForShop = {} |
|---|
| 305 | function MacroCmd_JobWaitForShop(timeout) |
|---|
| 306 | gMacroJobsWaitingForShop[job.running_id()] = true |
|---|
| 307 | job.wait(timeout or 30000) |
|---|
| 308 | gMacroJobsWaitingForShop[job.running_id()] = nil |
|---|
| 309 | end |
|---|
| 310 | RegisterListener("Hook_Open_Shop_Dialog", function (shop) |
|---|
| 311 | for jobid,callback in pairs(gMacroJobsWaitingForShop) do |
|---|
| 312 | gMacroJobsWaitingForShop[jobid] = nil |
|---|
| 313 | job.wakeup(jobid,true) |
|---|
| 314 | end |
|---|
| 315 | end) |
|---|
| 316 | |
|---|
| 317 | |
|---|
| 318 | -- method: nil=recall "gate"=gate "use"=runebookcharge |
|---|
| 319 | function MacroCmd_UseRuneBookPreAOS (runebookid,runeidx,method,timeout) -- for pre-aos (uogamers) runeidx:0-15 |
|---|
| 320 | Send_DoubleClick(runebookid) |
|---|
| 321 | MacroCmd_NextGumpContaining("Charges",timeout or 1000,function (dialog) |
|---|
| 322 | if (dialog) then |
|---|
| 323 | dialog:ShowPage(floor(runeidx/2)+2) |
|---|
| 324 | local side = (runeidx%2) |
|---|
| 325 | if (method == "gate") then |
|---|
| 326 | dialog:SendClick((side == 0) and 230 or 390,160) -- gate travel |
|---|
| 327 | elseif (method == "use") then |
|---|
| 328 | dialog:SendClick((side == 0) and 135 or 295,70) -- runebook charge |
|---|
| 329 | else |
|---|
| 330 | dialog:SendClick((side == 0) and 160 or 320,160) -- recall |
|---|
| 331 | end |
|---|
| 332 | end |
|---|
| 333 | end) |
|---|
| 334 | end |
|---|
| 335 | |
|---|
| 336 | -- method: nil=recall "gate"=gate "chivalry"=sacred-journey "use"=runebookcharge "default":set as runebook default |
|---|
| 337 | function MacroCmd_UseRuneBookPostAOS (runebookid,runeidx,method,timeout,forcew,forceh) -- for post-aos (vetus-mundus) runeidx:0-15 |
|---|
| 338 | Send_DoubleClick(runebookid) |
|---|
| 339 | MacroCmd_NextGumpContaining("Charges",timeout or 1000,function (dialog) |
|---|
| 340 | if (dialog) then |
|---|
| 341 | dialog:ShowPage(floor(runeidx/2)+2) |
|---|
| 342 | local side = (runeidx%2) |
|---|
| 343 | if (method == "use") then |
|---|
| 344 | dialog:SendClick((side == 0) and 135 or 295,70,forcew,forceh) -- runebook charge |
|---|
| 345 | elseif (method == "gate") then |
|---|
| 346 | dialog:SendClick((side == 0) and 140 or 300,160,forcew,forceh) -- gate travel |
|---|
| 347 | elseif (method == "chivalry") then |
|---|
| 348 | dialog:SendClick((side == 0) and 140 or 300,180,forcew,forceh) -- chivalry : sacred journey |
|---|
| 349 | elseif (method == "default") then |
|---|
| 350 | dialog:SendClick((side == 0) and 165 or 305,25,forcew,forceh) -- recall |
|---|
| 351 | else |
|---|
| 352 | dialog:SendClick((side == 0) and 140 or 300,145,forcew,forceh) -- recall |
|---|
| 353 | end |
|---|
| 354 | end |
|---|
| 355 | end) |
|---|
| 356 | end |
|---|
| 357 | |
|---|
| 358 | gMacroLastTargetMemory = nil |
|---|
| 359 | gMacroTargetLastRunning = false |
|---|
| 360 | function MacroRememberTarget (hitobject) |
|---|
| 361 | gMacroLastTargetMemory = {} |
|---|
| 362 | for k,v in pairs(hitobject) do gMacroLastTargetMemory[k] = v end |
|---|
| 363 | end |
|---|
| 364 | function MacroSetLastTarget (serial) |
|---|
| 365 | local mobile = GetMobile(serial) |
|---|
| 366 | if (mobile) then gMacroLastTargetMemory = { hittype=kMousePickHitType_Mobile, mobile=mobile } return end |
|---|
| 367 | local dynamic = GetDynamic(serial) |
|---|
| 368 | if (dynamic) then gMacroLastTargetMemory = { hittype=kMousePickHitType_Dynamic, dynamic=mobile } return end |
|---|
| 369 | end |
|---|
| 370 | |
|---|
| 371 | function MacroGetLastTargetSerial () |
|---|
| 372 | if (not gMacroLastTargetMemory) then return 0 end |
|---|
| 373 | if (gMacroLastTargetMemory.hittype == kMousePickHitType_Mobile) then return gMacroLastTargetMemory.mobile.serial end |
|---|
| 374 | if (gMacroLastTargetMemory.hittype == kMousePickHitType_Dynamic) then return gMacroLastTargetMemory.dynamic.serial end |
|---|
| 375 | end |
|---|
| 376 | |
|---|
| 377 | function MacroCmd_LastTargetVisible () |
|---|
| 378 | if (not gMacroLastTargetMemory) then return end |
|---|
| 379 | if (gMacroLastTargetMemory.hittype == kMousePickHitType_Mobile) then |
|---|
| 380 | local mobile = GetMobile(gMacroLastTargetMemory.mobile.serial) |
|---|
| 381 | return mobile ~= nil |
|---|
| 382 | end |
|---|
| 383 | if (gMacroLastTargetMemory.hittype == kMousePickHitType_Dynamic) then |
|---|
| 384 | local dynamic = GetDynamic(gMacroLastTargetMemory.dynamic.serial) |
|---|
| 385 | return dynamic ~= nil |
|---|
| 386 | end |
|---|
| 387 | end |
|---|
| 388 | |
|---|
| 389 | |
|---|
| 390 | function MacroCmd_TargetLastNow () if (gMacroLastTargetMemory) then CompleteTargetMode(gMacroLastTargetMemory) end end |
|---|
| 391 | function MacroCmd_TargetSelfNow () CompleteTargetModeWithTargetMobile(GetPlayerMobile()) end |
|---|
| 392 | |
|---|
| 393 | function MacroCmd_WeaponAbilityPrimary () local a,b = GetWeaponSpecialsForMobile(GetPlayerMobile()) Send_AOSCommand_WeaponAbility(a) end |
|---|
| 394 | function MacroCmd_WeaponAbilitySecondary () local a,b = GetWeaponSpecialsForMobile(GetPlayerMobile()) Send_AOSCommand_WeaponAbility(b) end |
|---|
| 395 | |
|---|
| 396 | -- timeout in ms, defaults to 30 seconds |
|---|
| 397 | gMacroTargetLastRunningNextIndex = 1 |
|---|
| 398 | function MacroCmd_TargetLast (completefun,timeout) -- repeat the last target |
|---|
| 399 | timeout = timeout or 30000 |
|---|
| 400 | if (gMacroTargetLastRunning) then return end |
|---|
| 401 | if (not gMacroLastTargetMemory) then return end |
|---|
| 402 | |
|---|
| 403 | if (IsTargetModeActive()) then |
|---|
| 404 | MacroCmd_TargetLastNow() |
|---|
| 405 | if (completefun) then completefun() end |
|---|
| 406 | return |
|---|
| 407 | end |
|---|
| 408 | |
|---|
| 409 | local myindex = gMacroTargetLastRunningNextIndex |
|---|
| 410 | gMacroTargetLastRunningNextIndex = gMacroTargetLastRunningNextIndex + 1 |
|---|
| 411 | gMacroTargetLastRunning = myindex |
|---|
| 412 | local listener = RegisterListener("Hook_TargetMode_Start",function () |
|---|
| 413 | if (myindex ~= gMacroTargetLastRunning) then return true end -- timeout was reached, or other targetlast started |
|---|
| 414 | MacroCmd_TargetLastNow() |
|---|
| 415 | gMacroTargetLastRunning = false |
|---|
| 416 | if (completefun) then completefun() end |
|---|
| 417 | return true |
|---|
| 418 | end) |
|---|
| 419 | if (timeout) then |
|---|
| 420 | InvokeLater(timeout,function () |
|---|
| 421 | if (not gMacroTargetLastRunning) then return end |
|---|
| 422 | UnregisterListener("Hook_TargetMode_Start",listener) |
|---|
| 423 | gMacroTargetLastRunning = false |
|---|
| 424 | print("MacroCmd_TargetLast timeout") |
|---|
| 425 | end) |
|---|
| 426 | end |
|---|
| 427 | end |
|---|
| 428 | |
|---|
| 429 | function MacroCmd_TargetGround (xloc,yloc,zloc_or_nil, completefun) |
|---|
| 430 | if (gMacroWaitForTargetActive) then return end |
|---|
| 431 | gMacroWaitForTargetActive = true |
|---|
| 432 | RegisterListener("Hook_TargetMode_Start",function () |
|---|
| 433 | print("MacroCmd_TargetGround hook triggered") |
|---|
| 434 | MacroCmd_TargetGroundNow(xloc,yloc,zloc_or_nil) |
|---|
| 435 | gMacroWaitForTargetActive = false |
|---|
| 436 | if (completefun) then completefun() end |
|---|
| 437 | return true |
|---|
| 438 | end) |
|---|
| 439 | end |
|---|
| 440 | |
|---|
| 441 | -- zloc_or_nil : determined automatically if nil |
|---|
| 442 | function MacroCmd_TargetGroundNow (xloc,yloc,zloc_or_nil) |
|---|
| 443 | if (xloc and yloc) then |
|---|
| 444 | local zloc = zloc_or_nil or GetGroundZAtAbsPos(xloc,yloc) or 0 |
|---|
| 445 | CompleteTargetMode({hittype=kMousePickHitType_Ground,x=xloc,y=yloc,z=zloc}) |
|---|
| 446 | end |
|---|
| 447 | end |
|---|
| 448 | |
|---|
| 449 | function MacroCmd_TargetSelf (completefun) -- target self |
|---|
| 450 | if (gMacroWaitForTargetActive) then return end |
|---|
| 451 | gMacroWaitForTargetActive = true |
|---|
| 452 | RegisterListener("Hook_TargetMode_Start",function () |
|---|
| 453 | local playermobile = GetPlayerMobile() |
|---|
| 454 | print("MacroCmd_TargetSelf hook triggered") |
|---|
| 455 | if (playermobile) then |
|---|
| 456 | print("#",playermobile.serial) |
|---|
| 457 | CompleteTargetMode({hittype=kMousePickHitType_Mobile,mobile=playermobile}) |
|---|
| 458 | end |
|---|
| 459 | gMacroWaitForTargetActive = false |
|---|
| 460 | if (completefun) then completefun() end |
|---|
| 461 | return true |
|---|
| 462 | end) |
|---|
| 463 | end |
|---|
| 464 | |
|---|
| 465 | -- currently broken |
|---|
| 466 | --~ function MacroCmd_ShowFallBackTool () if (gInGameStarted) then ShowFallBackTool() end end |
|---|
| 467 | function MacroCmd_ShowDevTool () if (gInGameStarted) then ShowDevTool() end end |
|---|
| 468 | function MacroCmd_ZoomCompass (zoomfactor) if (gInGameStarted) then ZoomCompass(zoomfactor) end end |
|---|
| 469 | function MacroCmd_ActivateNextRenderer () if (gInGameStarted) then ActivateNextRenderer() end end |
|---|
| 470 | function MacroCmd_CamChangeZoom (zoomadd) if (gInGameStarted) then gCurrentRenderer:CamChangeZoom(zoomadd) end end |
|---|
| 471 | function MacroCmd_Screenshot () Client_TakeScreenshot(gScreenshotDir) end |
|---|
| 472 | function MacroCmd_GridScreenshot () |
|---|
| 473 | if (not gInGameStarted) then return end |
|---|
| 474 | ToggleCompass() |
|---|
| 475 | Client_TakeGridScreenshot(gScreenshotDir) |
|---|
| 476 | ToggleCompass() |
|---|
| 477 | end |
|---|
| 478 | |
|---|
| 479 | function MacroCmd_ReloadMap () |
|---|
| 480 | if (not gInGameStarted) then return end |
|---|
| 481 | local mapindex = gMapIndex |
|---|
| 482 | UnloadOldMap(true) -- do not clear objects |
|---|
| 483 | LoadMap(gMapIndex) |
|---|
| 484 | end |
|---|
| 485 | |
|---|
| 486 | function MacroCmd_Dress (dresslist) |
|---|
| 487 | for k,serial in pairs(dresslist) do |
|---|
| 488 | if (MacroCmd_EquipItem(serial)) then return true end |
|---|
| 489 | end |
|---|
| 490 | end |
|---|
| 491 | |
|---|
| 492 | function MacroCmd_EquipItem (serial,bOkIfNotInBackPack) |
|---|
| 493 | if (type(serial) == "table") then |
|---|
| 494 | local cmd,param = unpack(serial) |
|---|
| 495 | if (cmd == "use") then Send_DoubleClick(param) end |
|---|
| 496 | return |
|---|
| 497 | end |
|---|
| 498 | local item = GetDynamic(serial) |
|---|
| 499 | if (not item) then item = MacroCmd_Item_FindFirstByArtID(serial) end |
|---|
| 500 | if (not item) then return end |
|---|
| 501 | if (item.iContainerSerial == GetPlayerSerial()) then return end -- already equipped |
|---|
| 502 | if (item.iContainerSerial ~= GetPlayerBackPackSerial() and (not bOkIfNotInBackPack)) then return end -- not in backpack, other char? |
|---|
| 503 | local layer = GetPaperdollLayerFromTileType(item.artid) |
|---|
| 504 | if (not layer) then return end -- unknown layer |
|---|
| 505 | if (MacroCmd_GetPlayerEquipment(layer)) then return end -- something else already equipped there |
|---|
| 506 | print("MacroCmd_EquipItem",serial,item.amount,layer) |
|---|
| 507 | Send_Take_Object(item.serial,item.amount) |
|---|
| 508 | Send_Equip_Item_Request(item.serial,layer,GetPlayerSerial()) |
|---|
| 509 | return true |
|---|
| 510 | end |
|---|
| 511 | |
|---|
| 512 | |
|---|
| 513 | |
|---|
| 514 | function MacroCmd_RiseText (r,g,b,text,serial) |
|---|
| 515 | serial = serial or GetPlayerSerial() |
|---|
| 516 | if (SpellBarRiseTextOnMob) then SpellBarRiseTextOnMob(serial,r,g,b,text) end |
|---|
| 517 | end |
|---|
| 518 | |
|---|
| 519 | function MacroCmd_Item_Use (item) if (item) then Send_DoubleClick(item.serial) return item end end |
|---|
| 520 | |
|---|
| 521 | function MacroCmd_Item_UseByName (itemnamepart) return MacroCmd_Item_Use(MacroCmd_Item_FindFirstByName(itemnamepart)) end |
|---|
| 522 | function MacroCmd_Item_UseByArtID (artid,hue) return MacroCmd_Item_Use(MacroCmd_Item_FindFirstByArtID(artid,hue)) end |
|---|
| 523 | |
|---|
| 524 | function MacroCmd_Item_FindFirstByName (itemnamepart,container) local list = MacroCmd_Item_FindByName(itemnamepart,container) return list[1] end |
|---|
| 525 | function MacroCmd_Item_FindFirstByArtID (artid,hue,container) local list = MacroCmd_Item_FindByArtID(artid,hue,container) return list[1] end |
|---|
| 526 | function MacroCmd_Item_FindFirstNearByArtID (artid,hue,dist) local list = MacroCmd_Item_FindNearByArtID(artid,hue,dist) return list[1] end |
|---|
| 527 | |
|---|
| 528 | function MacroCmd_GetPlayerEquipment (layer) |
|---|
| 529 | local playermobile = GetPlayerMobile() |
|---|
| 530 | return playermobile and GetMobileEquipmentItem(playermobile,layer) |
|---|
| 531 | end |
|---|
| 532 | function MacroCmd_GetItemInHand () return MacroCmd_GetPlayerEquipment(kLayer_OneHanded) end |
|---|
| 533 | function MacroCmd_IsMounted () return MacroCmd_GetPlayerEquipment(kLayer_Mount) ~= nil end |
|---|
| 534 | function MacroCmd_Dismount () |
|---|
| 535 | if (MacroCmd_IsMounted()) then Send_DoubleClick(GetPlayerSerial()) return true end -- todo : check if mounted |
|---|
| 536 | end |
|---|
| 537 | |
|---|
| 538 | function MacroCmd_DragAndEquip (takeserial,mobileserial) |
|---|
| 539 | local item = GetDynamic(takeserial) |
|---|
| 540 | local layer = item and GetPaperdollLayerFromTileType(item.artid) |
|---|
| 541 | if (not layer) then print("MacroCmd_DragEquip not wearable or item not found, artid=",item.artid) return end |
|---|
| 542 | Send_Take_Object(takeserial,1) |
|---|
| 543 | Send_Equip_Item_Request(takeserial,layer,mobileserial or GetPlayerSerial()) |
|---|
| 544 | end |
|---|
| 545 | function MacroCmd_DragDrop (takeserial,amount,dropcontainerserial) |
|---|
| 546 | Send_Take_Object(takeserial,amount) |
|---|
| 547 | Send_Drop_Object_AutoStack(takeserial,dropcontainerserial or GetPlayerBackPackSerial()) |
|---|
| 548 | end |
|---|
| 549 | |
|---|
| 550 | function MacroCmd_DragDropToGround (takeserial,amount,xloc,yloc,zloc) |
|---|
| 551 | if (not takeserial) then print("MacroCmd_DragDropToGround:no takeserial") return end |
|---|
| 552 | local o = GetDynamic(takeserial) |
|---|
| 553 | amount = amount or (o and o.amount) |
|---|
| 554 | if (not amount) then print("MacroCmd_DragDropToGround:no amount") return end |
|---|
| 555 | xloc = xloc or gPlayerXLoc |
|---|
| 556 | yloc = yloc or gPlayerYLoc |
|---|
| 557 | zloc = zloc or gPlayerZLoc |
|---|
| 558 | job.create(function () |
|---|
| 559 | Send_Take_Object(takeserial,amount) |
|---|
| 560 | job.wait(math.random(200,300)) |
|---|
| 561 | Send_Drop_Object(takeserial,xloc,yloc,zloc,0xFFFFFFFF) |
|---|
| 562 | end) |
|---|
| 563 | end |
|---|
| 564 | |
|---|
| 565 | -- 0x0c9e : ohii tree not hackable |
|---|
| 566 | function MacroCmd_IsHackableTrees (artid) return 0x0c9e ~= artid and StringContains(string.lower(GetStaticTileTypeName(artid)),"tree") end |
|---|
| 567 | function MacroCmd_FindNearbyTrees (r) return MacroCmd_FindNearbyStatics(r,"tree",{0x0c9e}) end -- ohii tree not hackable |
|---|
| 568 | function MacroCmd_FindNearbyStatics (r,namepart,skipartidlist) |
|---|
| 569 | local res = {} |
|---|
| 570 | r = r or 2 |
|---|
| 571 | for ax = -r,r do |
|---|
| 572 | for ay = -r,r do |
|---|
| 573 | for k,item in pairs(MapGetStatics(gPlayerXLoc+ax,gPlayerYLoc+ay)) do |
|---|
| 574 | --~ print("MacroCmd_FindNearbyStatics",GetStaticTileTypeName(item.artid)) |
|---|
| 575 | if (StringContains(string.lower(GetStaticTileTypeName(item.artid)),namepart) and |
|---|
| 576 | ((not skipartidlist) or (not in_array(item.artid,skipartidlist)))) then |
|---|
| 577 | table.insert(res,item) |
|---|
| 578 | end |
|---|
| 579 | end |
|---|
| 580 | end |
|---|
| 581 | end |
|---|
| 582 | return res |
|---|
| 583 | end |
|---|
| 584 | |
|---|
| 585 | -- doesn't sum stack-amount |
|---|
| 586 | function MacroCmd_Item_CountByArtID (artid,hue,container) local list = MacroCmd_Item_FindByArtID(artid,hue,container) return list and #list or 0 end |
|---|
| 587 | function MacroCmd_Item_SumByArtID (artid,hue,container) -- does sum stack |
|---|
| 588 | local list = MacroCmd_Item_FindByArtID(artid,hue,container) |
|---|
| 589 | if (not list) then return 0 end |
|---|
| 590 | local c = 0 |
|---|
| 591 | for k,item in pairs(list) do c = c + item.amount end |
|---|
| 592 | return c |
|---|
| 593 | end |
|---|
| 594 | |
|---|
| 595 | -- container defaults to player-backpack |
|---|
| 596 | function MacroCmd_Item_FindByName (itemnamepart,container) |
|---|
| 597 | container = container or GetPlayerBackPackContainer() |
|---|
| 598 | if (not container) then return end |
|---|
| 599 | local res = {} |
|---|
| 600 | for k,item in pairs(container:GetContent()) do |
|---|
| 601 | local name = AosToolTip_GetText(item.serial) or GetStaticTileTypeName(item.artid) |
|---|
| 602 | if (name and string.find(name,itemnamepart)) then |
|---|
| 603 | table.insert(res,item) |
|---|
| 604 | end |
|---|
| 605 | end |
|---|
| 606 | return res |
|---|
| 607 | end |
|---|
| 608 | |
|---|
| 609 | function MacroCmd_HideAllCorpses () |
|---|
| 610 | for k,item in pairs(GetDynamicList()) do |
|---|
| 611 | if (item.artid_base == kCorpseDynamicArtID and (not Renderer2D:MobileHasVisibleEquip(item.amount))) then item:Destroy() end |
|---|
| 612 | end |
|---|
| 613 | end |
|---|
| 614 | |
|---|
| 615 | function MacroCmd_AutoClickItems () |
|---|
| 616 | for k,item in pairs(GetDynamicList()) do |
|---|
| 617 | if (DynamicIsInWorld(item) and (not gItemAutoClickSent[item.serial])) then |
|---|
| 618 | gItemAutoClickSent[item.serial] = true |
|---|
| 619 | if ((not GetItemTooltipOrLabel(item.serial)) and (gDynamicAutoClickByArtID[item.artid] or gContainerArtIDs[item.artid])) then |
|---|
| 620 | Send_SingleClick(item.serial,true) |
|---|
| 621 | end |
|---|
| 622 | end |
|---|
| 623 | end |
|---|
| 624 | end |
|---|
| 625 | |
|---|
| 626 | function MacroCmd_Item_FindNearByArtList (artlist,dist) |
|---|
| 627 | local res = {} |
|---|
| 628 | for k,item in pairs(GetDynamicList()) do |
|---|
| 629 | if (DynamicIsInWorld(item) and |
|---|
| 630 | (dist == nil or item:GetUODistToPlayer() <= dist) and in_array(item.artid,artlist)) then |
|---|
| 631 | table.insert(res,item) |
|---|
| 632 | end |
|---|
| 633 | end |
|---|
| 634 | return res |
|---|
| 635 | end |
|---|
| 636 | |
|---|
| 637 | function MacroCmd_Item_FindNearByArtID (artid,hue,dist) -- equals easyuo type |
|---|
| 638 | local res = {} |
|---|
| 639 | local artidlist = (type(artid) == "number") and {artid} or artid |
|---|
| 640 | for k,item in pairs(GetDynamicList()) do |
|---|
| 641 | if (in_array(item.artid,artidlist) and (hue == nil or hue == item.hue) and DynamicIsInWorld(item) and |
|---|
| 642 | (dist == nil or item:GetUODistToPlayer() <= dist) ) then |
|---|
| 643 | table.insert(res,item) |
|---|
| 644 | end |
|---|
| 645 | end |
|---|
| 646 | return res |
|---|
| 647 | end |
|---|
| 648 | |
|---|
| 649 | function MacroCmd_Item_FindNearCorpses (dist,corpsetype) |
|---|
| 650 | local res = {} |
|---|
| 651 | for k,item in pairs(GetDynamicList()) do |
|---|
| 652 | if (DynamicIsInWorld(item) and IsCorpseArtID(item.artid) and ((not corpsetype) or (item.amount == corpsetype)) and |
|---|
| 653 | (dist == nil or item:GetUODistToPlayer() <= dist) ) then |
|---|
| 654 | table.insert(res,item) |
|---|
| 655 | end |
|---|
| 656 | end |
|---|
| 657 | return res |
|---|
| 658 | end |
|---|
| 659 | |
|---|
| 660 | function MacroCmd_IsItemInContainer (serial,container) |
|---|
| 661 | if (type(container) == "number") then container = GetContainer(container) end -- resolve serial |
|---|
| 662 | container = container or GetPlayerBackPackContainer() |
|---|
| 663 | return container and serial and container.content[serial] |
|---|
| 664 | end |
|---|
| 665 | |
|---|
| 666 | -- container defaults to player-backpack |
|---|
| 667 | -- hue can be nil for any |
|---|
| 668 | function MacroCmd_Item_FindByArtID (artid,hue,container) -- equals easyuo type |
|---|
| 669 | if (type(container) == "number") then container = GetContainer(container) end -- resolve serial |
|---|
| 670 | container = container or GetPlayerBackPackContainer() |
|---|
| 671 | if (not container) then return end |
|---|
| 672 | local res = {} |
|---|
| 673 | local artidlist = (type(artid) == "number") and {artid} or artid |
|---|
| 674 | for k,item in pairs(container:GetContent()) do |
|---|
| 675 | if (in_array(item.artid,artidlist) and (hue == nil or hue == item.hue)) then |
|---|
| 676 | table.insert(res,item) |
|---|
| 677 | end |
|---|
| 678 | end |
|---|
| 679 | return res |
|---|
| 680 | end |
|---|
| 681 | |
|---|
| 682 | function MacroCmd_FindNearestMobByName (namepart) |
|---|
| 683 | local founddist,foundmob |
|---|
| 684 | local xloc,yloc = GetPlayerPos() |
|---|
| 685 | for k,mobile in pairs(GetMobileList()) do |
|---|
| 686 | local dist = dist2(xloc,yloc,mobile.xloc,mobile.yloc) |
|---|
| 687 | if (((not founddist) or dist < founddist) and (not IsPlayerMobile(mobile))) then |
|---|
| 688 | if ((not namepart) or StringContains(AosToolTip_GetText(mobile.serial) or mobile.name or "",namepart)) then |
|---|
| 689 | founddist = dist |
|---|
| 690 | foundmob = mobile |
|---|
| 691 | end |
|---|
| 692 | end |
|---|
| 693 | end |
|---|
| 694 | return foundmob |
|---|
| 695 | end |
|---|
| 696 | |
|---|
| 697 | function MacroCmd_FindNearestMobByArtID (artid) |
|---|
| 698 | local founddist,foundmob |
|---|
| 699 | local xloc,yloc = GetPlayerPos() |
|---|
| 700 | for k,mobile in pairs(GetMobileList()) do |
|---|
| 701 | local dist = dist2(xloc,yloc,mobile.xloc,mobile.yloc) |
|---|
| 702 | if (((not founddist) or dist < founddist) and (not IsPlayerMobile(mobile))) then |
|---|
| 703 | if ((not artid) or mobile.artid == artid) then |
|---|
| 704 | founddist = dist |
|---|
| 705 | foundmob = mobile |
|---|
| 706 | end |
|---|
| 707 | end |
|---|
| 708 | end |
|---|
| 709 | return foundmob |
|---|
| 710 | end |
|---|
| 711 | |
|---|
| 712 | function MacroCmd_GetNearestMobFromList (list) |
|---|
| 713 | local founddist,foundmob |
|---|
| 714 | local xloc,yloc = GetPlayerPos() |
|---|
| 715 | for k,mobile in pairs(list) do |
|---|
| 716 | local dist = dist2(xloc,yloc,mobile.xloc,mobile.yloc) |
|---|
| 717 | if ((not founddist) or dist < founddist) then |
|---|
| 718 | founddist = dist |
|---|
| 719 | foundmob = mobile |
|---|
| 720 | end |
|---|
| 721 | end |
|---|
| 722 | return foundmob |
|---|
| 723 | end |
|---|
| 724 | |
|---|
| 725 | function MacroCmd_ListNonFriendlyPlayers () |
|---|
| 726 | local res = {} |
|---|
| 727 | for k,mobile in pairs(GetMobileList()) do |
|---|
| 728 | if ((mobile.artid == 400 or mobile.artid == 401) and |
|---|
| 729 | (not IsMobileInParty(mobile.serial)) and |
|---|
| 730 | (not IsPlayerMobile(mobile))) then |
|---|
| 731 | |
|---|
| 732 | local labelhue = GetItemLabelHue(mobile.serial) |
|---|
| 733 | if (labelhue ~= kPlayerVendorLabelHue) then res[mobile.serial] = mobile end |
|---|
| 734 | end |
|---|
| 735 | end |
|---|
| 736 | return res |
|---|
| 737 | end |
|---|
| 738 | |
|---|
| 739 | function MacroCmd_FindNearestNonFriendlyPlayer () return MacroCmd_GetNearestMobFromList(MacroCmd_ListNonFriendlyPlayers()) end |
|---|
| 740 | |
|---|
| 741 | function MacroCmd_ListMobilesInRange (filterfun,maxdist) |
|---|
| 742 | local res = {} |
|---|
| 743 | for k,mobile in pairs(GetMobileList()) do |
|---|
| 744 | if (GetUODistToPlayer(mobile.xloc,mobile.yloc) <= maxdist and filterfun(mobile)) then table.insert(res,mobile) end |
|---|
| 745 | end |
|---|
| 746 | return res |
|---|
| 747 | end |
|---|
| 748 | |
|---|
| 749 | function MacroCmd_ListMobiles (filterfun) |
|---|
| 750 | local res = {} |
|---|
| 751 | for k,mobile in pairs(GetMobileList()) do if (filterfun(mobile)) then table.insert(res,mobile) end end |
|---|
| 752 | return res |
|---|
| 753 | end |
|---|
| 754 | |
|---|
| 755 | function MacroCmd_FindNearestMob () return MacroCmd_FindNearestMobByName() end |
|---|
| 756 | |
|---|
| 757 | -- set itemserial = 0 to clear |
|---|
| 758 | -- itemserial defaults to the serial of the item currently under the mouse |
|---|
| 759 | function MacroCmd_ItemSlot_Set (slotnumber,itemserial) |
|---|
| 760 | if (not gInGameStarted) then return end |
|---|
| 761 | if (not itemserial) then itemserial = GetMouseHitSerial() end -- itemserial_under_mouse |
|---|
| 762 | if (itemserial == 0) then itemserial = nil end -- set 0 to clear |
|---|
| 763 | print("MacroCmd_ItemSlot_Set",slotnumber,itemserial) |
|---|
| 764 | local item = itemserial and GetObjectBySerial(itemserial) |
|---|
| 765 | local itemname = item and GetStaticTileTypeName(item.artid) or "empty" |
|---|
| 766 | GuiAddChatLine("ItemSlot "..tostring(slotnumber).." set to "..tostring(itemname)) |
|---|
| 767 | gMacroItemSlots[slotnumber] = itemserial |
|---|
| 768 | end |
|---|
| 769 | |
|---|
| 770 | function MacroCmd_ItemSlot_Use (slotnumber) |
|---|
| 771 | local itemserial = gMacroItemSlots[slotnumber] |
|---|
| 772 | if (not itemserial) then return MacroError("MacroCmd_ItemSlot_Use : no item in slot "..tostring(slotnumber)) end |
|---|
| 773 | print("MacroCmd_ItemSlot_Use",slotnumber,itemserial) |
|---|
| 774 | Send_DoubleClick(itemserial) |
|---|
| 775 | end |
|---|
| 776 | |
|---|
| 777 | function MacroCmd_Skill (skillname) |
|---|
| 778 | if (not gInGameStarted) then return end |
|---|
| 779 | local skillid = gCharCreateSkillIDs[skillname] -- zero based |
|---|
| 780 | if (not skillid) then return MacroErrorNameMismatch("MacroCmd_Skill",skillname,gCharCreateSkillIDs) end |
|---|
| 781 | skillid = skillid + 1 -- one based needed below |
|---|
| 782 | if (glSkillActive[skillid] ~= 1) then return MacroError("MacroCmd_Skill : skill is passive : "..tostring(skillname)) end |
|---|
| 783 | Send_Request_SkillUse(skillid) |
|---|
| 784 | end |
|---|
| 785 | |
|---|
| 786 | function MacroCmd_RepeatLastSpell () |
|---|
| 787 | if (gLastSpellID) then Send_Spell(gLastSpellID) end |
|---|
| 788 | end |
|---|
| 789 | function MacroCmd_Spell (spellname,targetserial,targetcallback,targetwaitadd) |
|---|
| 790 | if (not gInGameStarted) then return end |
|---|
| 791 | local spellid = GetSpellIDByName(spellname) |
|---|
| 792 | if (not spellid) then return MacroErrorNameMismatch("MacroCmd_Spell",spellname,gSpellIDByName) end |
|---|
| 793 | Send_Spell(spellid) |
|---|
| 794 | |
|---|
| 795 | if (targetserial) then |
|---|
| 796 | local timeout = GetSpellCastTimeForPlayer(spellid) + kSpellTimeLatency + (targetwaitadd or 1000) |
|---|
| 797 | MacroCmd_QueueTargetSerial(targetserial,timeout,targetcallback,true) |
|---|
| 798 | end |
|---|
| 799 | end |
|---|
| 800 | |
|---|
| 801 | |
|---|
| 802 | -- searches the journal for text |
|---|
| 803 | -- if timestamp is not nil, only entries since timestamp are searched |
|---|
| 804 | -- if the text is found it returns the complete line otherwise nil |
|---|
| 805 | function MacroJournal_FindLineContainingSince (text, timestamp) |
|---|
| 806 | for k,v in pairs(gJournalExtendedEntries) do |
|---|
| 807 | if timestamp == nil or v.time >= timestamp then |
|---|
| 808 | if string.find(v.line, text) then |
|---|
| 809 | return v.line |
|---|
| 810 | end |
|---|
| 811 | end |
|---|
| 812 | end |
|---|
| 813 | |
|---|
| 814 | return nil |
|---|
| 815 | end |
|---|
| 816 | |
|---|
| 817 | -- waits until a given text appears, list = {text=returnvalue, text=returnvalue, ...} |
|---|
| 818 | function MacroJournal_WaitForText (list,timeout) |
|---|
| 819 | if not list then return end |
|---|
| 820 | |
|---|
| 821 | local lastcheck = Client_GetTicks() |
|---|
| 822 | local endtime = timeout and lastcheck+timeout or nil |
|---|
| 823 | |
|---|
| 824 | while true do |
|---|
| 825 | for k,v in pairs(list) do |
|---|
| 826 | if MacroJournal_FindLineContainingSince(k, lastcheck) then |
|---|
| 827 | return v |
|---|
| 828 | end |
|---|
| 829 | end |
|---|
| 830 | lastcheck = Client_GetTicks() |
|---|
| 831 | |
|---|
| 832 | -- timeout check |
|---|
| 833 | if endtime and lastcheck > endtime then |
|---|
| 834 | print("TIMEOUT") |
|---|
| 835 | return nil |
|---|
| 836 | end |
|---|
| 837 | |
|---|
| 838 | job.wait(100) |
|---|
| 839 | end |
|---|
| 840 | end |
|---|
| 841 | |
|---|
| 842 | function MacroRead_GetPlayerPosition () |
|---|
| 843 | local sx,sy,sz |
|---|
| 844 | local mobile = GetPlayerMobile() |
|---|
| 845 | if mobile then |
|---|
| 846 | sx,sy,sz = mobile.xloc,mobile.yloc,mobile.zloc * 0.1 |
|---|
| 847 | else |
|---|
| 848 | sx,sy,sz = gCurrentRenderer:GetExactLocalPos() |
|---|
| 849 | end |
|---|
| 850 | return sx,sy,sz |
|---|
| 851 | end |
|---|
| 852 | |
|---|
| 853 | |
|---|
| 854 | function MacroReadAux_MobileStat (mobile,statname,errormsg_funname) |
|---|
| 855 | if (not gInGameStarted) then return 0 end |
|---|
| 856 | if (not gMacroReadMobileStats[statname]) then |
|---|
| 857 | return MacroErrorNameMismatch("MacroRead_PlayerStat",statname,gMacroReadMobileStats) |
|---|
| 858 | end |
|---|
| 859 | local mobile = GetPlayerMobile() |
|---|
| 860 | return mobile and mobile.stats and mobile.stats[statname] or 0 |
|---|
| 861 | end |
|---|
| 862 | |
|---|
| 863 | function MacroErrorNameMismatch (cmd,name,list_by_key) |
|---|
| 864 | local infotext = cmd.." : unknown name "..tostring(name).." available names:\n" |
|---|
| 865 | for k,v in pairs(list_by_key) do infotext = infotext..k.."\n" end |
|---|
| 866 | MacroError(infotext) |
|---|
| 867 | end |
|---|
| 868 | |
|---|
| 869 | function MacroError (infotext) |
|---|
| 870 | print(infotext) |
|---|
| 871 | PlainMessageBox(infotext,gGuiDefaultStyleSet,gGuiDefaultStyleSet) |
|---|
| 872 | end |
|---|
| 873 | |
|---|
| 874 | function GetMacroKeyComboName (keycode,char,bCtrl,bAlt,bShift) |
|---|
| 875 | local text = (keycode > 0) and GetKeyName(keycode) or ("0"..char) |
|---|
| 876 | if (bCtrl ) then text = "ctrl+"..text end |
|---|
| 877 | if (bAlt ) then text = "alt+"..text end |
|---|
| 878 | if (bShift ) then text = "shift+"..text end |
|---|
| 879 | return text |
|---|
| 880 | end |
|---|
| 881 | |
|---|
| 882 | function ClearAllMacros () gMacroList = {} end |
|---|
| 883 | |
|---|
| 884 | function SetMacro (keycomboname,fun) gMacroList[string.gsub(string.lower(keycomboname)," ","")] = fun end |
|---|
| 885 | |
|---|
| 886 | function TriggerMacros (keycode,char) |
|---|
| 887 | local bCtrl = gKeyPressed[key_lcontrol] or gKeyPressed[key_rcontrol] |
|---|
| 888 | local bAlt = gKeyPressed[key_lalt] or gKeyPressed[key_ralt] |
|---|
| 889 | local bShift = gKeyPressed[key_lshift] or gKeyPressed[key_rshift] |
|---|
| 890 | local name = GetMacroKeyComboName(keycode,char,bCtrl,bAlt,bShift) |
|---|
| 891 | local macrofun = gMacroList[name] |
|---|
| 892 | if (gMacroPrintAllKeyCombos) then print('to use this macro keycombo : SetMacro("'..name..'",function() MacroCmd_Say("test") end)') end |
|---|
| 893 | if (not macrofun) then return end -- no macro mapped to this keycode |
|---|
| 894 | |
|---|
| 895 | -- protected macro call |
|---|
| 896 | local success,errormsg_or_result = lugrepcall(macrofun) |
|---|
| 897 | if (not success) then |
|---|
| 898 | local myErrorText = "ERROR executing MACRO for keycombo "..name.." :\n"..tostring(errormsg_or_result) |
|---|
| 899 | print(myErrorText) |
|---|
| 900 | PlainMessageBox(myErrorText,gGuiDefaultStyleSet,gGuiDefaultStyleSet) |
|---|
| 901 | end |
|---|
| 902 | end |
|---|
| 903 | |
|---|
| 904 | RegisterListener("keydown",function (keycode,char,bConsumed) |
|---|
| 905 | if (not bConsumed) then TriggerMacros(keycode,char) end |
|---|
| 906 | end) |
|---|
| 907 | |
|---|
| 908 | --[[ |
|---|
| 909 | gMacroActionDescriptions = {} |
|---|
| 910 | gMacroActionDescriptions.Say = "Open a text window where you can enter a line of dialog that your character will speak when the Macro is used." |
|---|
| 911 | gMacroActionDescriptions.Emote = "As Say, but may be a different text color than normal speech (see \"Change Emote Color\" above). Also, any Emote text will be placed between two asterisks, for example *grin* or *Broods darkly*. The traditional function of emote text is to convey actions, attitudes, or emotions rather than simple speech." |
|---|
| 912 | gMacroActionDescriptions.Whisper = "As Say, but whispered text (e.g., \"Psst, wanna buy a chicken?\") can only be \"heard\" by characters immediately adjacent to you." |
|---|
| 913 | gMacroActionDescriptions.Yell = "As Say, but yelled text (e.g., \"HELP!\") can be \"heard\" by any character up to a screen and a half away." |
|---|
| 914 | gMacroActionDescriptions.Walk = "Opens a menu of compass directions from which you choose one. Using this menu causes your character to face and take a step in the selected direction." |
|---|
| 915 | gMacroActionDescriptions.War_Peace = "Toggles you between War mode and Peace mode." |
|---|
| 916 | gMacroActionDescriptions.Paste = "Pastes text from your Windows clipboard into a book or speech. Text length is limited. Speech can be only a few words, while books can receive a few sentences." |
|---|
| 917 | gMacroActionDescriptions.Open = "Opens one of your informational windows. Selecting this option will present you with a list of windows from which to select. Your Character Window is listed as \"Paperdoll\" and your Options screen as \"Configuration\"." |
|---|
| 918 | gMacroActionDescriptions.Close = "Closes the window you specify." |
|---|
| 919 | gMacroActionDescriptions.Minimize = "Minimizes all open windows." |
|---|
| 920 | gMacroActionDescriptions.Maximize = "Fully opens all minimized windows on screen." |
|---|
| 921 | gMacroActionDescriptions.Open_Door = "Opens any door within reach." |
|---|
| 922 | gMacroActionDescriptions.Use_Skill = "Presents you with a list of all applicable skills, from which to select the specific skill you want to try to Use when you trigger this Macro. This command can only be used to initiate those skills which are normally begun from the skill list in your Character Window. It does not apply to skills initiated by using a specific item or taking a certain action." |
|---|
| 923 | gMacroActionDescriptions.Last_Skill = "Attempts to again Use the last skill you Used." |
|---|
| 924 | gMacroActionDescriptions.Cast_Spell = "Presents you with a list of all the spells in the game, from which you must select the specific spell you want to cast. It's up to you to ensure the spell you select is, in fact, one that you actually know how to cast." |
|---|
| 925 | gMacroActionDescriptions.Last_Spell = "Attempts to recast the last spell you cast." |
|---|
| 926 | gMacroActionDescriptions.Last_Object = "Attempt to again use the last item you Used." |
|---|
| 927 | gMacroActionDescriptions.Bow = "Your character will bow from the waist." |
|---|
| 928 | gMacroActionDescriptions.Salute = "Your character will perform a military salute." |
|---|
| 929 | gMacroActionDescriptions.Quit_Game = "Disconnects you and closes the game." |
|---|
| 930 | gMacroActionDescriptions.Allnames = "Displays the names of every creature and character currently on screen." |
|---|
| 931 | gMacroActionDescriptions.LastTarget = "Automatically target the last object, creature, or player that you clicked on with the targeting cursor." |
|---|
| 932 | gMacroActionDescriptions.TargetSelf = "Targets you. Used in conjunction with other macros." |
|---|
| 933 | gMacroActionDescriptions.Arm_Disarm = "Arms or Disarms your current or chosen weapon. You must specify an arm (right or left)." |
|---|
| 934 | gMacroActionDescriptions.Wait_for_Target = "Waits for the target cursor to become available." |
|---|
| 935 | gMacroActionDescriptions.Target_Next = "Moves your target cursor to the next available target." |
|---|
| 936 | gMacroActionDescriptions.Attack_Last = "Attacks the creature or player your last targeted." |
|---|
| 937 | gMacroActionDescriptions.Delay = "Allows you to set a \"wait\" delay with a complex macro." |
|---|
| 938 | gMacroActionDescriptions.CircleTrans = "Allows you to toggle Circle Transparency with a macro." |
|---|
| 939 | gMacroActionDescriptions.CloseGumps = "Closes all open pop-up messages." |
|---|
| 940 | gMacroActionDescriptions.AlwaysRun = "Toggles the Always Run setting, which makes you always run whenever you move." |
|---|
| 941 | gMacroActionDescriptions.SaveDesktop = "" |
|---|
| 942 | gMacroActionDescriptions.KillGumpOpen = "" |
|---|
| 943 | gMacroActionDescriptions.PrimaryAbility = "Activates your weapon's primary special ability." |
|---|
| 944 | gMacroActionDescriptions.SecondaryAbility = "Activates your weapon's secondary special ability." |
|---|
| 945 | gMacroActionDescriptions.EquipLastWeapon = "Allows you to quickly switch between two weapons. Click here for more information." |
|---|
| 946 | gMacroActionDescriptions.SetUpdateRange = "" |
|---|
| 947 | gMacroActionDescriptions.ModifyUpdateRange = "" |
|---|
| 948 | gMacroActionDescriptions.IncreaseUpdateRange = "" |
|---|
| 949 | gMacroActionDescriptions.DecreaseUpdateRange = "" |
|---|
| 950 | gMacroActionDescriptions.MaxUpdateRange = "" |
|---|
| 951 | gMacroActionDescriptions.MinUpdateRange = "" |
|---|
| 952 | gMacroActionDescriptions.DefaultUpdateRange = "" |
|---|
| 953 | gMacroActionDescriptions.UpdateRangeInfo = "" |
|---|
| 954 | gMacroActionDescriptions.EnableRangeColor = "" |
|---|
| 955 | gMacroActionDescriptions.DisableRangeColor = "" |
|---|
| 956 | gMacroActionDescriptions.ToggleRangeColor = "" |
|---|
| 957 | gMacroActionDescriptions.InvokeVirtue = "Allows you to specify a virtue to be activated." |
|---|
| 958 | ]]-- |
|---|
| 959 | |
|---|
| 960 | |
|---|
| 961 | -- obsolete... |
|---|
| 962 | gMacroListDialog = nil |
|---|
| 963 | function ToggleMacroList () end |
|---|
| 964 | function ToggleMacroList_OLD () |
|---|
| 965 | if (gMacroListDialog) then CloseMacroListDialog() return end |
|---|
| 966 | |
|---|
| 967 | local rows = { |
|---|
| 968 | { {"MacroList"} }, |
|---|
| 969 | { {type="EditText",controlname="note",w=400,h=24} }, |
|---|
| 970 | { {"Apply",function () |
|---|
| 971 | local mytext = gMacroListDialog.controls["note"]:GetText() or "" |
|---|
| 972 | -- todo.... |
|---|
| 973 | end}, |
|---|
| 974 | {"Close",function () CloseMacroListDialog() end}, |
|---|
| 975 | }, |
|---|
| 976 | } |
|---|
| 977 | gMacroListDialog = guimaker.MakeTableDlg(rows,100,100,false,true) |
|---|
| 978 | end |
|---|
| 979 | |
|---|
| 980 | -- obsolete... |
|---|
| 981 | function CloseMacroListDialog_OLD () |
|---|
| 982 | if (gMacroListDialog) then gMacroListDialog:Destroy() gMacroListDialog = nil end |
|---|
| 983 | end |
|---|
| 984 | |
|---|
| 985 | function MacroCmd_WalkInDir (iDir,bRunFlag) ExecWalkRequestIfPossible(iDir,bRunFlag) end |
|---|
| 986 | |
|---|
| 987 | -- run from a job (uses wait) !!!! |
|---|
| 988 | -- timeout : stop walking if the target wasn't reached after this time. 0 to walk until target is reached |
|---|
| 989 | |
|---|
| 990 | function MacroCmd_PathFindTo (xloc,yloc,tolerance,timeout,bNoLog) |
|---|
| 991 | tolerance = tolerance or 0 |
|---|
| 992 | local bLog = not bNoLog |
|---|
| 993 | if (bLog) then print("MacroCmd_PathFindTo : start",xloc,yloc,tolerance,timeout) end |
|---|
| 994 | if (GetUODistToPlayer(xloc,yloc) <= tolerance) then |
|---|
| 995 | if (bLog) then print("MacroCmd_PathFindTo : already there") end |
|---|
| 996 | return true |
|---|
| 997 | end |
|---|
| 998 | local iJobWaitInterval = 50 |
|---|
| 999 | timeout = timeout or 0 |
|---|
| 1000 | local endt = (timeout > 0) and (Client_GetTicks() + timeout) |
|---|
| 1001 | repeat -- repeat the pathfinding calc every few seconds in case dynamics show up |
|---|
| 1002 | local t = Client_GetTicks() |
|---|
| 1003 | local res = cPathFind2:CalcRouteFromPlayerToPos(xloc,yloc,tolerance,iJobWaitInterval,endt and (endt-t)) |
|---|
| 1004 | local t2 = Client_GetTicks() |
|---|
| 1005 | local nextstept = t2 + 1000 |
|---|
| 1006 | local dt = t2-t |
|---|
| 1007 | if (bLog) then print("MacroCmd_PathFindTo: calc took ",dt,"ms",res and ("numsteps:"..#res) or "failed","curpos:"..table.concat({GetPlayerPos()},",")) end |
|---|
| 1008 | if (not res) then if (bLog) then print("MacroCmd_PathFindTo : failed, no path") end return end |
|---|
| 1009 | local bRunFlag = true |
|---|
| 1010 | local bTrySides = true |
|---|
| 1011 | for k,pos in ipairs(res) do |
|---|
| 1012 | local xloc,yloc,zloc = unpack(pos) |
|---|
| 1013 | repeat |
|---|
| 1014 | job.wait(max(10,Walk_GetTimeUntilNextStep())) |
|---|
| 1015 | WalkStep_WalkToPosSimple(xloc,yloc,bRunFlag,bTrySides) |
|---|
| 1016 | if (endt and gMyTicks > endt) then |
|---|
| 1017 | if (bLog) then print("MacroCmd_PathFindTo : failed, timeout") end |
|---|
| 1018 | return |
|---|
| 1019 | end |
|---|
| 1020 | if (gMyTicks > nextstept) then break end |
|---|
| 1021 | until GetUODistToPlayer(xloc,yloc) <= 0 -- repeat (turn,walk) until this next tile reached |
|---|
| 1022 | if (gMyTicks > nextstept) then break end |
|---|
| 1023 | end |
|---|
| 1024 | if (gMyTicks <= nextstept) then |
|---|
| 1025 | if (bLog) then print("MacroCmd_PathFindTo : success, finished") end |
|---|
| 1026 | return true -- final destination reached |
|---|
| 1027 | end |
|---|
| 1028 | until false |
|---|
| 1029 | end |
|---|
| 1030 | |
|---|
| 1031 | function MacroCmd_WalkToMouse () |
|---|
| 1032 | MainMousePick() |
|---|
| 1033 | local x,y,z = GetMouseHitTileCoords() |
|---|
| 1034 | SetAutoWalkTo(x,y) |
|---|
| 1035 | end |
|---|
| 1036 | |
|---|
| 1037 | |
|---|
| 1038 | gAttackRunning = false |
|---|
| 1039 | function StopAttack () |
|---|
| 1040 | gAttackRunning = false |
|---|
| 1041 | end |
|---|
| 1042 | |
|---|
| 1043 | gAttackMobile = nil |
|---|
| 1044 | function AttackMobile (mobileserial) |
|---|
| 1045 | gAttackMobile = mobileserial |
|---|
| 1046 | if gAttackRunning then return end |
|---|
| 1047 | gAttackRunning = true |
|---|
| 1048 | |
|---|
| 1049 | job.create(function() |
|---|
| 1050 | --~ print("START ATTACK") |
|---|
| 1051 | local reqsend = false |
|---|
| 1052 | while gAttackRunning and gAttackMobile do |
|---|
| 1053 | local mobile = gMobiles[gAttackMobile] |
|---|
| 1054 | if not mobile then |
|---|
| 1055 | gAttackRunning = false |
|---|
| 1056 | else |
|---|
| 1057 | local tx,ty,tz = mobile.xloc,mobile.yloc,mobile.zloc |
|---|
| 1058 | local px,py,pz = GetPlayerTilePosition() |
|---|
| 1059 | local dx,dy,dz = Vector.sub(px,py,pz, tx,ty,tz) |
|---|
| 1060 | dx,dy,dz = Vector.normalise_to_len(dx,dy,dz, 1) |
|---|
| 1061 | gCurrentRenderer:SetViewDir(dx,dy) |
|---|
| 1062 | |
|---|
| 1063 | --[[ |
|---|
| 1064 | autowalk is not good here, because of distance attacks |
|---|
| 1065 | dx,dy,dz = Vector.add(tx,ty,tz, dx,dy,dz) |
|---|
| 1066 | dx = round(dx) |
|---|
| 1067 | dy = round(dy) |
|---|
| 1068 | SetAutoWalkTo(dx,dy) |
|---|
| 1069 | ]] |
|---|
| 1070 | |
|---|
| 1071 | if (IsWarModeActive()) then |
|---|
| 1072 | if not reqsend then |
|---|
| 1073 | --~ print("REQUEST SEND") |
|---|
| 1074 | Send_AttackReq(gAttackMobile) |
|---|
| 1075 | reqsend = true |
|---|
| 1076 | end |
|---|
| 1077 | else |
|---|
| 1078 | reqsend = false |
|---|
| 1079 | end |
|---|
| 1080 | |
|---|
| 1081 | job.wait(500) |
|---|
| 1082 | end |
|---|
| 1083 | end |
|---|
| 1084 | --~ print("STOP ATTACK") |
|---|
| 1085 | end) |
|---|
| 1086 | end |
|---|
| 1087 | |
|---|
| 1088 | function MacroGoto(x,y,slow) |
|---|
| 1089 | SetAutoWalkTo(x,y,slow) |
|---|
| 1090 | while gWalkPathToGo do |
|---|
| 1091 | job.wait(500) |
|---|
| 1092 | end |
|---|
| 1093 | end |
|---|
| 1094 | |
|---|
| 1095 | function MacroGetItemFromBackpackByName(itemnamepart) |
|---|
| 1096 | local backpack_container = GetPlayerBackPackContainer() |
|---|
| 1097 | if backpack_container then return MacroGetItemFromContainerByName(itemnamepart, backpack_container.serial) end |
|---|
| 1098 | return nil |
|---|
| 1099 | end |
|---|
| 1100 | |
|---|
| 1101 | function MacroGetItemFromContainerByArtidHue(artid, hue, container_serial) |
|---|
| 1102 | MacroEnsureContainerIsOpen(container_serial) |
|---|
| 1103 | |
|---|
| 1104 | local container = GetContainer(container_serial) |
|---|
| 1105 | if (not container) then return nil end |
|---|
| 1106 | for k,item in pairs(container:GetContent()) do |
|---|
| 1107 | if item.artid == artid and (not hue or item.hue == hue) then |
|---|
| 1108 | return item |
|---|
| 1109 | end |
|---|
| 1110 | end |
|---|
| 1111 | |
|---|
| 1112 | return nil |
|---|
| 1113 | end |
|---|
| 1114 | |
|---|
| 1115 | function MacroGetItemFromContainerByName(itemnamepart, container_serial) |
|---|
| 1116 | MacroEnsureContainerIsOpen(container_serial) |
|---|
| 1117 | |
|---|
| 1118 | local container = GetContainer(container_serial) |
|---|
| 1119 | if (not container) then return nil end |
|---|
| 1120 | for k,item in pairs(container:GetContent()) do |
|---|
| 1121 | local name = GetStaticTileTypeName(item.artid) |
|---|
| 1122 | if (name and string.find(name,itemnamepart)) then |
|---|
| 1123 | return item |
|---|
| 1124 | end |
|---|
| 1125 | end |
|---|
| 1126 | |
|---|
| 1127 | return nil |
|---|
| 1128 | end |
|---|
| 1129 | |
|---|
| 1130 | function MacroDropItemIntoContainer(dropitem, container_serial, x,y) |
|---|
| 1131 | x = x or 50 |
|---|
| 1132 | y = y or 50 |
|---|
| 1133 | |
|---|
| 1134 | MacroEnsureContainerIsOpen(container_serial) |
|---|
| 1135 | |
|---|
| 1136 | local amount = dropitem.amount or 1 |
|---|
| 1137 | local target = container_serial |
|---|
| 1138 | |
|---|
| 1139 | local container = GetContainer(container_serial) |
|---|
| 1140 | if (not container) then return nil end |
|---|
| 1141 | for k,item in pairs(container:GetContent()) do |
|---|
| 1142 | if item.serial ~= dropitem.serial and item.artid == dropitem.artid and (not dropitem.hue or item.hue == dropitem.hue) then |
|---|
| 1143 | target = item.serial |
|---|
| 1144 | end |
|---|
| 1145 | end |
|---|
| 1146 | |
|---|
| 1147 | Send_Take_Object(dropitem.serial,amount) |
|---|
| 1148 | job.wait(400) |
|---|
| 1149 | Send_Drop_Object(dropitem.serial,x,y,0,target) |
|---|
| 1150 | job.wait(400) |
|---|
| 1151 | end |
|---|
| 1152 | |
|---|
| 1153 | function MacroDropAllIntoContainer(itemnamepart, container_serial, x,y) |
|---|
| 1154 | MacroEnsureContainerIsOpen(container_serial) |
|---|
| 1155 | |
|---|
| 1156 | x = x or 50 |
|---|
| 1157 | y = y or 50 |
|---|
| 1158 | local item = MacroGetItemFromBackpackByName(itemnamepart) |
|---|
| 1159 | local lastserial = nil |
|---|
| 1160 | while item do |
|---|
| 1161 | MacroDropItemIntoContainer(item, container_serial, x,y) |
|---|
| 1162 | lastserial = item.serial |
|---|
| 1163 | item = MacroGetItemFromBackpackByName(itemnamepart) |
|---|
| 1164 | -- something went wrong so stop |
|---|
| 1165 | if item and lastserial and item.serial == lastserial then return end |
|---|
| 1166 | end |
|---|
| 1167 | end |
|---|
| 1168 | |
|---|
| 1169 | function MacroEnsureContainerIsOpen (container_serial) |
|---|
| 1170 | if not IsContainerAlreadyOpen(container_serial) then |
|---|
| 1171 | Send_DoubleClick(container_serial) |
|---|
| 1172 | end |
|---|
| 1173 | while not IsContainerAlreadyOpen(container_serial) do |
|---|
| 1174 | job.wait(100) |
|---|
| 1175 | end |
|---|
| 1176 | end |
|---|
| 1177 | |
|---|
| 1178 | function MacroStackEverytingInContainer (container_serial) |
|---|
| 1179 | MacroEnsureContainerIsOpen(container_serial) |
|---|
| 1180 | |
|---|
| 1181 | local sx = 20 |
|---|
| 1182 | local sy = 20 |
|---|
| 1183 | local dx = 2 |
|---|
| 1184 | local dy = 2 |
|---|
| 1185 | local x = sx |
|---|
| 1186 | local y = sy |
|---|
| 1187 | local limit = 150 |
|---|
| 1188 | |
|---|
| 1189 | local rowh = 0 |
|---|
| 1190 | |
|---|
| 1191 | local container = GetContainer(container_serial) |
|---|
| 1192 | if (not container) then return nil end |
|---|
| 1193 | |
|---|
| 1194 | |
|---|
| 1195 | local l = {} |
|---|
| 1196 | |
|---|
| 1197 | -- sort content by height |
|---|
| 1198 | for k,v in pairs(container:GetContent()) do table.insert(l,v) end |
|---|
| 1199 | table.sort(l, function(a,b) |
|---|
| 1200 | local minx,miny,maxx,maxy = GetArtVisibleAABB(a.artid + 0x4000) |
|---|
| 1201 | local ha = maxy-miny |
|---|
| 1202 | minx,miny,maxx,maxy = GetArtVisibleAABB(b.artid + 0x4000) |
|---|
| 1203 | local hb = maxy-miny |
|---|
| 1204 | return ha < hb |
|---|
| 1205 | end) |
|---|
| 1206 | |
|---|
| 1207 | for k,item in ipairs(l) do |
|---|
| 1208 | -- print("DROP AT",x,y) |
|---|
| 1209 | |
|---|
| 1210 | local minx,miny,maxx,maxy = GetArtVisibleAABB(item.artid + 0x4000) |
|---|
| 1211 | -- print("AABB",minx,miny,maxx,maxy) |
|---|
| 1212 | --local w,h = GetArtSize(item.artid + 0x4000) |
|---|
| 1213 | local w,h = maxx-minx,maxy-miny |
|---|
| 1214 | |
|---|
| 1215 | rowh = math.max(h, rowh) |
|---|
| 1216 | |
|---|
| 1217 | -- print("w,h,rowh",w,h,rowh,x,y) |
|---|
| 1218 | |
|---|
| 1219 | MacroDropItemIntoContainer(item, container_serial, x-minx,y-miny) |
|---|
| 1220 | |
|---|
| 1221 | -- goto next position |
|---|
| 1222 | x = x + w + dx |
|---|
| 1223 | if x > limit then |
|---|
| 1224 | x = sx |
|---|
| 1225 | y = y + rowh + dy |
|---|
| 1226 | end |
|---|
| 1227 | end |
|---|
| 1228 | end |
|---|
| 1229 | |
|---|
| 1230 | function MacroGetSerialUnderMouse () |
|---|
| 1231 | return GetMouseHitSerial(true) |
|---|
| 1232 | end |
|---|
| 1233 | |
|---|
| 1234 | |
|---|
| 1235 | -- color is #000000 format, timeout in ms |
|---|
| 1236 | function Macro_ShowTimeout (x,y,w,h,text,color,timeout) |
|---|
| 1237 | if timeout > 0 then |
|---|
| 1238 | local params = { |
|---|
| 1239 | gfxparam_bar = MakeSpritePanelParam_BorderPartMatrix(GetPlainTextureGUIMat("ray_border.png"),32,32, 0,0, 0,0, 1,30,1, 1,30,1, 32,32, 1,1, false, false), |
|---|
| 1240 | gfxparam_background = MakeSpritePanelParam_BorderPartMatrix(GetPlainTextureGUIMat("ray_border_black.png"),32,32, 0,0, 0,0, 1,30,1, 1,30,1, 32,32, 1,1, false, false), |
|---|
| 1241 | } |
|---|
| 1242 | |
|---|
| 1243 | local progress = GetDesktopWidget():CreateChild("Bar",params) |
|---|
| 1244 | progress:SetLeftTop(x,y) |
|---|
| 1245 | progress:SetSize(w,h) |
|---|
| 1246 | progress:SetProgress(0) |
|---|
| 1247 | progress:CreateContentChild("UOText",{text="<BASEFONT COLOR="..color..">"..text.."</BASEFONT>",x=5,y=-2,width=w,height=h,background=0,scrollbar=0,bold=false,crop=false,html=true}) |
|---|
| 1248 | |
|---|
| 1249 | local startt = Client_GetTicks() |
|---|
| 1250 | |
|---|
| 1251 | job.create(function() |
|---|
| 1252 | local p = 0 |
|---|
| 1253 | repeat |
|---|
| 1254 | p = Clamp((Client_GetTicks() - startt) / timeout, 0, 1) |
|---|
| 1255 | progress:SetProgress(p) |
|---|
| 1256 | job.wait(10) |
|---|
| 1257 | until p == 1 |
|---|
| 1258 | progress:Destroy() |
|---|
| 1259 | end) |
|---|
| 1260 | end |
|---|
| 1261 | end |
|---|
| 1262 | |
|---|
| 1263 | |
|---|
| 1264 | -- disconnect from server + login with a different char/acc (experimental, no error handling) |
|---|
| 1265 | function MacroCmd_ReLogin (shardname,user,pass,charidx) |
|---|
| 1266 | print("MacroCmd_Relog",shardname,user,charidx) |
|---|
| 1267 | NetDisconnect() |
|---|
| 1268 | gHuffmanDecode = false |
|---|
| 1269 | gInGameStarted = false |
|---|
| 1270 | |
|---|
| 1271 | -- close healthbars |
|---|
| 1272 | for serial,dialog in pairs(gHealthbarDialogs) do dialog:Destroy() end gHealthbarDialogs = {} |
|---|
| 1273 | |
|---|
| 1274 | for k,dynamic in pairs(GetDynamicList()) do if (DynamicIsInWorld(dynamic)) then dynamic:Destroy() end end |
|---|
| 1275 | for k,mobile in pairs(GetMobileList()) do mobile:Destroy() end |
|---|
| 1276 | |
|---|
| 1277 | -- ClearDynamicsAndMobiles : not really needed since dynamics and mobiles are destroyed above |
|---|
| 1278 | if (gCurrentRenderer.ClearDynamicsAndMobiles) then |
|---|
| 1279 | gCurrentRenderer:ClearDynamicsAndMobiles() |
|---|
| 1280 | else |
|---|
| 1281 | gCurrentRenderer:DeInit() |
|---|
| 1282 | end |
|---|
| 1283 | |
|---|
| 1284 | local shard = gShardList[shardname] assert(shard) |
|---|
| 1285 | gShardName = shardname |
|---|
| 1286 | LoadShardfilter(shard.gCustomArtFilterFilePath) -- todo : revert on error or back-button ? |
|---|
| 1287 | |
|---|
| 1288 | -- load global config from shard |
|---|
| 1289 | for k,v in pairs(shard) do _G[k] = v end |
|---|
| 1290 | |
|---|
| 1291 | gLoginname = user |
|---|
| 1292 | gPassword = pass -- MainMenu_GetStoredPassword(shard.gLoginServerIP,shard.gLoginServerPort,gLoginname) |
|---|
| 1293 | |
|---|
| 1294 | -- init net |
|---|
| 1295 | gNet_State = NetConnectWithKey(gLoginServerIP,gLoginServerPort,gServerSeed) |
|---|
| 1296 | assert(gNet_State) |
|---|
| 1297 | |
|---|
| 1298 | gAutoLoginCharID = nil |
|---|
| 1299 | gAutoLoginCharName = nil |
|---|
| 1300 | gAutoLoginCharID = charidx |
|---|
| 1301 | Send_Account_Login_Request(user,pass) -- 0x80 kPacket_Account_Login_Request |
|---|
| 1302 | end |
|---|