forked from kc8pnd/MobInfo2
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMobInfo2.lua
2199 lines (1911 loc) · 83.7 KB
/
MobInfo2.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
--
-- MobInfo2.lua
--
-- Main module of MobInfo-2 AddOn
-- Version: 2.98
--
-- MobInfo-2 is a World of Warcraft AddOn that provides you with useful
-- additional information about Mobs (ie. opponents/monsters). It adds
-- new information to the game's Tooltip when you hover with your mouse
-- over a mob. It also adds a numeric display of the Mobs health
-- and mana (current and max) to the Mob target frame.
--
-- MobInfo-2 is the continuation of the original "MobInfo" by Dizzarian,
-- combined with the original "MobHealth2" by Wyv. Both Dizzarian and
-- Wyv sadly no longer play WoW and stopped maintaining their AddOns.
-- I have "inhereted" MobInfo from Dizzarian and MobHealth-2 from Wyv
-- and now continue to update and improve the united result.
--
-- global vars
MI2_Debug = 0 -- 0=no debug info, 1=minimal debug info, 2=extensive debug info, 3=more extensive+event info
MI2_DebugItems = 0 -- 0=no item debug info, 1=show item ID and item value in tooltip
MI2_DB_VERSION = 6
MI2_IMPORT_DB_VERSION = 6
-- default initialization for all MobInfo database tables
-- this automatically gets overwritten by the database contents loaded from file
MobInfoDB = { ["DatabaseVersion:0"] = { ver = MI2_DB_VERSION } }
MI2_CharTable = { charCount = 0 }
MI2_ZoneTable = { cnt = 0 }
MI2_ItemNameTable = {}
MobHealthPlayerDB = {}
MobHealthDB = { }
local MI2_CurrentTargets = {}
local MI2_RecentCorpses = {}
local MI2_NewCorpseIdx = 0
local MI2_CurrentCorpseIndex = nil
local MI2_LootFrameOpen = false
-- skinning loot table using localization independant item IDs:
-- Ruined Leather Scraps, Light Leather, Medium Leather, Heavy Leather, Thick Leather, Rugged Leather
-- Chimera Leather, Devilsaur Leather, Frostsaber Leather, Warbear Leather,
-- Light Hide, Medium Hide, Heavy Hide, Thick Hide, Rugged Hide, Shadowcat Hide, Thick Wolfhide
-- Scorpid Scale, Shiny Fish Scales, Red Whelp Scales, Turtle Scales, Black Whelp Scales, Brilliant Chromatic Scale
-- Black Dragonscale, Blue Dragonscale, Red Dragonscale, Green Dragonscale, Worn Dragonscale, Heavy Scorpid Scale
local miSkinLoot = { [2934]=1, [2318]=1, [2319]=1, [4234]=1, [4304]=1, [8170]=1,
[15423]=1,[15417]=1,[15422]=1,[15419]=1,
[783]=1, [4232]=1, [4235]=1, [8169]=1, [8171]=1, [7428]=1, [8368]=1,
[8154]=1,[17057]=1, [7287]=1, [8167]=1, [7286]=1,[12607]=1,
[15416]=1,[15415]=1,[15414]=1,[15412]=1, [8165]=1,[15408]=1, }
-- cloth loot table using localization independant item IDs
-- Linen Cloth, Wool Cloth, Silk Cloth, Mageweave Cloth, Felcloth, Runecloth, Mooncloth
local miClothLoot = { [2589]=1, [2592]=1, [4306]=1, [4338]=1, [14256]=1, [14047]=1, [14342]=1 };
local MI2_ItemCollapseList = { [2725]=2725, [2728]=2725, [2730]=2725, [2732]=2725,
[2734]=2725, [2735]=2725, [2738]=2725, [2740]=2725,[2742]=2725,
[2745]=2725, [2748]=2725, [2749]=2725, [2750]=2725, [2751]=2725 }
-- global MobInfo color constansts
mifontBlue = "|cff0000ff"
mifontItemBlue = "|cff2060ff"
mifontLightBlue = "|cff00e0ff"
mifontGreen = "|cff00ff00"
mifontRed = "|cffff0000"
mifontLightRed = "|cffff8080"
mifontGold = "|cffffcc00"
mifontGray = "|cff888888"
mifontWhite = "|cffffffff"
mifontSubWhite = "|cffbbbbbb"
mifontMageta = "|cffe040ff" -- old magenta: "|cffff00ff"
mifontYellow = "|cffffff00"
mifontCyan = "|cff00ffff"
mifontOrange = "|cffff7000"
MI2_QualityColor = { [1]=mifontGray, [2]=mifontWhite, [3]=mifontGreen, [4]=mifontItemBlue, [5]=mifontMageta, [6]=mifontOrange, [7]=mifontRed }
-----------------------------------------------------------------------------
-- MI2_GetMobData( mobName, mobLevel [, unitId] )
--
-- Get and return all the data that MobInfo knows about a given mob.
-- This is an externally available interface function that can be
-- called by other AddOns to access MobInfo data. It should be fast,
-- efficient, and easy to use
--
-- The data describing a Mob is returned in table form as described below.
--
-- To identify the mob you must supply its name and level. You can
-- optionally supply a "unitId" to get additional info:
-- mobName : name of mob, eg. "Forest Lurker"
-- mobLevel : mob level as integer number
-- unitId : optional WoW unit identification, should be either
-- "target" or "mouseover"
--
-- Examples:
-- A. mobData = MI2_GetMobData( "Forest Lurker", 10 )
-- B. mobData = MI2_GetMobData( "Forest Lurker", 10, "target" )
--
-- Return Value:
-- The return value is a LUA table with one table entry for each value that
-- MobInfo can know about a Mob. Note that table entries exist ONLY if the
-- corresponding value has actually been collected for the given Mob.
-- Unrecorded values do NOT exist in the table and thus evaluate to a NIL
-- expression.
--
-- Values you can get without "unitId" (as per Example A above):
-- mobData.healthMax : health maximum
-- mobData.xp : experience value
-- mobData.kills : number of times current player has killed this mob
-- mobData.minDamage : minimum damage done by mob
-- mobData.maxDamage : maximum damage done by mob
-- mobData.dps : dps of Mon against current player
-- mobData.loots : number of times this mob has been looted
-- mobData.emptyLoots : number of times this mob gave empty loot
-- mobData.clothCount : number of times this mob gave cloth loot
-- mobData.copper : total money loot of this mob as copper amount
-- mobData.itemValue : total item value loot of this mob as copper amount
-- mobData.mobType : mob type for special mobs: 1=normal, 2=rare/elite, 3=boss
-- mobData.r1 : number of rarity 1 loot items (grey)
-- mobData.r2 : number of rarity 2 loot items (white)
-- mobData.r3 : number of rarity 3 loot items (green)
-- mobData.r4 : number of rarity 4 loot items (blue)
-- mobData.r5 : number of rarity 5 loot items (purple)
-- mobData.itemList : table that lists all recorded items looted from this mob
-- table entry index gives WoW item ID,
-- table entry value gives item amount
--
-- Additional values you will get with "unitId" (as per Example B above):
-- mobData.class : class of mob as localized text
-- mobData.healthCur : current health of given unit
-- mobData.manaCur : current mana of given unit
-- mobData.manaMax : maximum mana for given unit
--
-- Code Example:
--
-- local mobData = MI2_GetMobData( "Forest Lurker", 10 )
--
-- if mobData.xp then
-- DEFAULT_CHAT_FRAME:AddMessage( "XP = "..mobData.xp )
-- end
--
-- if mobData.copper and mobData.loots then
-- local avgLoot = mobData.copper / mobData.loots
-- DEFAULT_CHAT_FRAME:AddMessage( "average loot = "..avgLoot )
-- end
-----------------------------------------------------------------------------
function MI2_GetMobData( mobName, mobLevel, unitId )
local mobData = {}
local mobIndex = mobName..":"..mobLevel
-- get mobs PPP and calculate max health
local mobPPP = MobHealth_PPP(mobIndex)
if mobPPP <= 0 then mobPPP = 1 end
mobData.healthMax = floor(mobPPP * 100 + 0.5)
if MI2_Debug > 2 then chattext( "M2DBG: MI2_GetMobData: name=["..mobName.."], level="..mobLevel..", exists: "..tostring(MobInfoDB[mobIndex] ~= nil) ) end
-- obtain unit specific values if unitId is given
if unitId then
mobData.class = UnitClass(unitId)
if UnitHealthMax(unitId) == 100 then
mobData.healthCur = floor(mobPPP * UnitHealth(unitId) + 0.5)
else
mobData.healthCur = UnitHealth(unitId)
end
mobData.manaCur = UnitMana( unitId )
mobData.manaMax = UnitManaMax( unitId )
mobData.armor = UnitResistance(unitId, 0)
mobData.holyResist = UnitResistance(unitId, 1)
mobData.fireResist = UnitResistance(unitId, 2)
mobData.natureResist = UnitResistance(unitId, 3)
mobData.frostResist = UnitResistance(unitId, 4)
mobData.shadowResist = UnitResistance(unitId, 5)
mobData.arcaneResist = UnitResistance(unitId, 6)
end
-- decode basic mob info
-- exit here if mob does not exist in DB, set color only if mob exists
local mobInfo = MobInfoDB[mobIndex]
if not mobInfo then return mobData end
mobData.color = GetDifficultyColor( mobLevel )
MI2_GetMobDataFromMobInfo( mobInfo, mobData )
return mobData
end -- MI2_GetMobData()
-----------------------------------------------------------------------------
-- MI2_GetMobDataFromMobInfo()
--
-- Extract all data describing a specific mob from a given mob database
-- record (called "mobInfo"). The various different fields within the
-- record get decoded and the resulting data is returned in a convenient
-- format that allows for easy further processing of the data. The return
-- format for the decoded data is called "mobData". The resulting "mobData"
-- structure is returned.
-----------------------------------------------------------------------------
function MI2_GetMobDataFromMobInfo( mobInfo, mobData )
MI2_DecodeBasicMobData( mobInfo, mobData )
MI2_DecodePlayerSpecificData( mobInfo, mobData, MI2_PlayerName )
MI2_DecodeQualityOverview( mobInfo, mobData )
MI2_DecodeMobLocation( mobInfo, mobData )
MI2_DecodeItemList( mobInfo, mobData )
end -- MI2_GetMobDataFromMobInfo()
-----------------------------------------------------------------------------
-- MI2_DecodeBasicMobData()
--
-- Decode the basic mob data. This function is used by the public
-- "MI2_GetMobData()" and also by the Mob search routines.
-----------------------------------------------------------------------------
function MI2_DecodeBasicMobData( mobInfo, mobData, mobIndex )
if mobIndex then
mobInfo = MobInfoDB[mobIndex]
if not mobInfo then
-- unknown mob is being looted
mobData.loots = 1
return
end
end
-- decode mob basic info: loots, empty loots, experience, cloth count, money looted, item value looted, mob type
mobData.mobType = 1
if mobInfo.bi then
local a,b,lt,el,cp,iv,cc,xp,mt,sc = string.find( mobInfo.bi, "(%d*)/(%d*)/(%d*)/(%d*)/(%d*)/(%d*)/(%d*)/(%d*)")
mobData.loots = tonumber(lt)
mobData.emptyLoots = tonumber(el)
mobData.xp = tonumber(xp)
mobData.clothCount = tonumber(cc)
mobData.copper = tonumber(cp)
mobData.itemValue = tonumber(iv)
mobData.mobType = tonumber(mt) or 1
mobData.skinCount = tonumber(sc)
end
end -- MI2_DecodeBasicMobData()
-----------------------------------------------------------------------------
-- MI2_DecodeMobLocation()
--
-- Decode mob location info, skip invalid location data
-- The location is encoded in the mob record entry "ml".
-- The decoded data is stored in the given "mobData" structure.
-----------------------------------------------------------------------------
function MI2_DecodeMobLocation( mobInfo, mobData, mobIndex )
if mobIndex then
mobInfo = MobInfoDB[mobIndex]
end
if mobInfo.ml then
local a,b,x1,y1,x2,y2,c,z = string.find( mobInfo.ml, "(%d*)/(%d*)/(%d*)/(%d*)/(%d*)/(%d*)")
mobData.location = {}
mobData.location.x1 = tonumber(x1)
mobData.location.y1 = tonumber(y1)
mobData.location.x2 = tonumber(x2)
mobData.location.y2 = tonumber(y2)
mobData.location.c = tonumber(c)
mobData.location.z = (tonumber(z) or 0)
if not mobData.location.x1 or not mobData.location.x2 or
not mobData.location.y1 or not mobData.location.y2 or
not mobData.location.c or mobData.location.z == 0 then
mobData.location = nil
end
end
end -- MI2_DecodeMobLocation()
-----------------------------------------------------------------------------
-- MI2_DecodeQualityOverview()
--
-- Decode item quality data: loot count per item rarity category
-- The loot items quality overview is encoded in the mob record entry "qi".
-- The decoded data is stored in the given "mobData" structure.
-----------------------------------------------------------------------------
function MI2_DecodeQualityOverview( mobInfo, mobData, mobIndex )
if mobIndex then
mobInfo = MobInfoDB[mobIndex]
end
if mobInfo.qi then
local a,b,r1,r2,r3,r4,r5 = string.find( mobInfo.qi, "(%d*)/(%d*)/(%d*)/(%d*)/(%d*)")
mobData.r1 = tonumber(r1)
mobData.r2 = tonumber(r2)
mobData.r3 = tonumber(r3)
mobData.r4 = tonumber(r4)
mobData.r5 = tonumber(r5)
end
end -- MI2_DecodeQualityOverview
-----------------------------------------------------------------------------
-- MI2_DecodePlayerSpecificData()
--
-- Decode player specific data: number of kills, min damage, max damage, dps
-- Player specific data is encoded in mob record entries starting with
-- the lowercase letter "c" plus a player name index number, eg. "c7",
-- this is called the player ID code. The playerName parameter must give
-- the player ID code for the player data to decode.
-- The decoded data is stored in the given "mobData" structure.
-----------------------------------------------------------------------------
function MI2_DecodePlayerSpecificData( mobInfo, mobData, playerName, mobIndex )
if mobIndex then
mobInfo = MobInfoDB[mobIndex]
end
if mobInfo[playerName] then
local a,b,kl,mind,maxd,dps = string.find( mobInfo[playerName], "(%d*)/(%d*)/(%d*)/(%d*)")
mobData.kills = tonumber(kl)
mobData.minDamage = tonumber(mind)
mobData.maxDamage = tonumber(maxd)
mobData.dps = tonumber(dps)
end
end
-----------------------------------------------------------------------------
-- MI2_DecodeItemList()
--
-- Decode the item list encoded in the "il" string of a mobInfo database
-- record. The result is stored in the given mobData record as a new
-- record field called "itemList".
-----------------------------------------------------------------------------
function MI2_DecodeItemList( mobInfo, mobData, mobIndex )
if mobIndex then
mobInfo = MobInfoDB[mobIndex]
end
if mobInfo.il then
local lootItems = mobInfo.il
local s,e, item, amount = string.find( lootItems, "(%d+)[:]?(%d*)" )
if e then mobData.itemList = {} end
while e do
mobData.itemList[tonumber(item)] = tonumber(amount) or 1
s,e, item, amount = string.find( lootItems, "/(%d+)[:]?(%d*)", e+1 )
end
end
end -- MI2_DecodeItemList()
-----------------------------------------------------------------------------
-- MI2_StoreMobData()
--
-- Store the contents of a given "mobData" structure (ie. the data describing
-- a mob) in the mob database. The "mobData" must be compatible to what is
-- returned by the "MI2_GetMobData()" function.
-----------------------------------------------------------------------------
function MI2x_StoreMobData( mobData, mobName, mobLevel, playerName, mobIndex )
if not mobIndex then
mobIndex = mobName..":"..mobLevel
end
-- create the mob basic info (".bi") string
if mobData.mobType == 1 then mobData.mobType = "" end
local basicInfo = (mobData.loots or "").."/"..(mobData.emptyLoots or "").."/"..(mobData.copper or "").."/"..(mobData.itemValue or "").."/"..
(mobData.clothCount or "").."/"..(mobData.xp or "").."/"..(mobData.mobType or "").."/"..(mobData.skinCount or "")
-- create the mob quality info (".qi") string
local qualityInfo = (mobData.r1 or "").."/"..(mobData.r2 or "").."/"..(mobData.r3 or "").."/"..(mobData.r4 or "").."/"..(mobData.r5 or "")
-- create the mob player specific info, which is stored using the players name
local playerInfo = (mobData.kills or "").."/"..(mobData.minDamage or "").."/"..(mobData.maxDamage or "").."/"..(mobData.dps or "")
-- create the mob location data
-- note: a copy of this code can be found in MI2_AdaptImportLocation()
local loc = mobData.location or {}
local locationInfo = (loc.x1 or "").."/"..(loc.y1 or "").."/"..(loc.x2 or "").."/"..(loc.y2 or "").."/"..(loc.c or "").."/"..(loc.z or "")
-- create loot item list string for database
local itemList = ""
if mobData.itemList then
local prefix = ""
for itemID, amount in mobData.itemList do
itemList = itemList..prefix..itemID
if amount > 1 then
itemList = itemList..":"..amount
end
prefix = "/"
end
end
-- only enter non empty data into database record
local mobInfo = {}
local recordNotEmpty = false
if MobInfoConfig.SaveBasicInfo == 1 and basicInfo ~= "///////" then
mobInfo.bi = basicInfo
recordNotEmpty = true
end
if MobInfoConfig.SaveBasicInfo == 1 and qualityInfo ~= "////" then
mobInfo.qi = qualityInfo
recordNotEmpty = true
end
if MobInfoConfig.SaveCharData == 1 and playerInfo ~= "///" then
mobInfo[playerName] = playerInfo
recordNotEmpty = true
end
if MobInfoConfig.SaveItems == 1 and itemList ~= "" then
mobInfo.il = itemList
recordNotEmpty = true
end
if MobInfoConfig.SaveBasicInfo == 1 and locationInfo ~= "/////" then
mobInfo.ml = locationInfo
recordNotEmpty = true
end
-- do not store empty records in database
if recordNotEmpty then
MobInfoDB[mobIndex] = mobInfo
end
end -- MI2_StoreMobData()
-----------------------------------------------------------------------------
-- MI2_RemoveCharData()
--
-- Remove all char specific data from the given Mob database record.
-----------------------------------------------------------------------------
function MI2_RemoveCharData( mobInfo )
for entryName, entryData in mobInfo do
if entryName ~= "bi" and entryName ~= "qi" and entryName ~= "il" and entryName ~= "ml" and entryName ~= "ver" then
mobInfo[entryName] = nil
end
end
end -- MI2_StoreMobData()
-----------------------------------------------------------------------------
-- MI2_PrepareForImport()
--
-- Prepare for importing external MobInfo databases into the main database.
-----------------------------------------------------------------------------
function MI2_PrepareForImport()
local mobDbSize, healthDbSize, itemDbSize = 0, 0, 0
-- external database version number check
local version = MobInfoDB["DatabaseVersion:0"].ver
if version and version < MI2_IMPORT_DB_VERSION then
MI2_Import_Status = "BADVER"
return
end
-- calculate Mob database size and import signature
local levelSum, nameSum = 0, 0
for index in MobInfoDB do
mobDbSize = mobDbSize + 1
local mobName, mobLevel = MI2_GetIndexComponents( index )
levelSum = levelSum + mobLevel
nameSum = nameSum + string.len( mobName )
end
for index in MobHealthDB do healthDbSize = healthDbSize + 1 end
for index in MI2_ItemNameTable do itemDbSize = itemDbSize + 1 end
MI2_Import_Signature = mobDbSize.."_"..healthDbSize.."_"..itemDbSize.."_"..levelSum.."_"..nameSum
-- store copy of databases to be imported and calculate import status
MobInfoDB["DatabaseVersion:0"] = nil
MobInfoDB_Import = MobInfoDB
MI2_ItemNameTable_Import = MI2_ItemNameTable
MI2_ZoneTable_Import = MI2_ZoneTable
MobHealthDB_Import = MobHealthDB
if mobDbSize > 1 then
MI2_Import_Status = (mobDbSize-1).." Mobs"
end
if healthDbSize > 0 then
if MI2_Import_Status then
MI2_Import_Status = MI2_Import_Status.." & "
end
MI2_Import_Status = (MI2_Import_Status or "")..healthDbSize.." HP values"
end
MobInfoDB = { ["DatabaseVersion:0"] = { ver = MI2_DB_VERSION } }
MI2_CharTable = { charCount = 0 }
MI2_ZoneTable = { cnt = 0 }
MI2_ItemNameTable = {}
MobHealthDB = { }
end -- MI2_PrepareForImport()
-----------------------------------------------------------------------------
-- MI2_DeleteMobData()
--
-- Delete data for a specific Mob from database and current target table.
-----------------------------------------------------------------------------
function MI2_DeleteMobData( mobIndex, deleteHealth )
if mobIndex then
MobInfoDB[mobIndex] = nil
MI2_CurrentTargets[mobIndex] = nil
if deleteHealth then
MobHealthDB[mobIndex] = nil
end
if mobIndex == MI2_Target.mobIndex then
MI2_Target = {}
MobHealth_Display()
end
end
end -- MI2_DeleteMobData()
-----------------------------------------------------------------------------
-- chattext()
--
-- spits out msg to the chat channel. used in debuging
-----------------------------------------------------------------------------
function chattext(txt)
if( DEFAULT_CHAT_FRAME ) then
DEFAULT_CHAT_FRAME:AddMessage(txt)
end
end -- chattext()
-----------------------------------------------------------------------------
-- MI2_InitOptions()
--
-- initialize MobInfo configuration options
-- this takes into account new options that have been added to MobInfo
-- in the course of developement
-----------------------------------------------------------------------------
function MI2_InitOptions()
-- initialize MobInfoConfig
if not MobInfoConfig or not MobInfoConfig.ShowLoots then
MobInfoConfig = { }
MI2_SlashAction_Default()
end
-- initial defaults for all config options
if not MobInfoConfig.ShowBlankLines then MobInfoConfig.ShowBlankLines = 1 end
if not MobInfoConfig.TargetFontSize then MobInfoConfig.TargetFontSize = 10 end
if not MobInfoConfig.DisableMobInfo then MobInfoConfig.DisableMobInfo = 0 end
if not MobInfoConfig.ShowDamage then MobInfoConfig.ShowDamage = 1 end
if not MobInfoConfig.ShowMana then MobInfoConfig.ShowMana = 1 end
if not MobInfoConfig.ShowEmpty then MobInfoConfig.ShowEmpty = 0 end
if not MobInfoConfig.CombinedMode then MobInfoConfig.CombinedMode = 0 end
if not MobInfoConfig.ShowCombined then MobInfoConfig.ShowCombined = 1 end
if not MobInfoConfig.KeypressMode then MobInfoConfig.KeypressMode = 0 end
if not MobInfoConfig.StableMax then MobInfoConfig.StableMax = 0 end
if not MobInfoConfig.TargetHealth then MobInfoConfig.TargetHealth = 1 end
if not MobInfoConfig.TargetMana then MobInfoConfig.TargetMana = 1 end
if not MobInfoConfig.HealthPercent then MobInfoConfig.HealthPercent = 1 end
if not MobInfoConfig.ManaPercent then MobInfoConfig.ManaPercent = 1 end
if not MobInfoConfig.HealthPosX then MobInfoConfig.HealthPosX = -7 end
if not MobInfoConfig.HealthPosY then MobInfoConfig.HealthPosY = 11 end
if not MobInfoConfig.ManaPosX then MobInfoConfig.ManaPosX = -7 end
if not MobInfoConfig.ManaPosY then MobInfoConfig.ManaPosY = 11 end
if not MobInfoConfig.TargetFont then MobInfoConfig.TargetFont = 2 end
if not MobInfoConfig.SavePlayerHp then MobInfoConfig.SavePlayerHp = 0 end
if not MobInfoConfig.CompactMode then MobInfoConfig.CompactMode = 1 end
if not MobInfoConfig.ShowItems then MobInfoConfig.ShowItems = 1 end
if not MobInfoConfig.SaveItems then MobInfoConfig.SaveItems = 1 end
if not MobInfoConfig.SaveCharData then MobInfoConfig.SaveCharData = 1 end
if not MobInfoConfig.ItemsQuality then MobInfoConfig.ItemsQuality = 2 end
if not MobInfoConfig.SaveBasicInfo then MobInfoConfig.SaveBasicInfo = 1 end
if not MobInfoConfig.ItemTooltip then MobInfoConfig.ItemTooltip = 1 end
if not MobInfoConfig.ItemFilter then MobInfoConfig.ItemFilter = "" end
if not MobInfoConfig.ShowLocation then MobInfoConfig.ShowLocation = 1 end
if not MobInfoConfig.SaveLocation then MobInfoConfig.SaveLocation = 1 end
if not MobInfoConfig.ShowClothSkin then MobInfoConfig.ShowClothSkin = 1 end
if not MobInfoConfig.ImportOnlyNew then MobInfoConfig.ImportOnlyNew = 0 end
-- former option "HealthOff" has been renamed to "DisableHealth"
if not MobInfoConfig.DisableHealth then
MobInfoConfig.DisableHealth = (MobInfoConfig.HealthOff or 0)
end
-- config values that no longer exist
if MobInfoConfig.HealthOff then MobInfoConfig.HealthOff = nil end
if MobInfoConfig.ManaDistance then MobInfoConfig.ManaDistance = nil end
if MobInfoConfig.ShowPercent then MobInfoConfig.ShowPercent = nil end
if MobInfoConfig.CustomTracks then MobInfoConfig.CustomTracks = nil end
if MobInfoConfig.SaveAllValues then MobInfoConfig.SaveAllValues = nil end
if MobInfoConfig.MobDbVersion then MobInfoConfig.MobDbVersion = nil end
if MobInfoConfig.MobDbVersion then MobInfoConfig.MobDbVersion = nil end
if MobInfoConfig.ClearOnExit then MobInfoConfig.ClearOnExit = nil end
if MobInfoConfig.SaveGoodItems then MobInfoConfig.SaveGoodItems = nil end
if MobInfoConfig.SaveQualityData then MobInfoConfig.SaveQualityData = nil end
end -- MI2_InitOptions()
-----------------------------------------------------------------------------
-- MI2_IndexComponents()
--
-- Return the component parts of a mob index: mob name, mob level
-----------------------------------------------------------------------------
function MI2_GetIndexComponents( mobIndex )
local a, b, mobName, mobLevel = string.find(mobIndex, "(.+):(.+)$")
mobLevel = tonumber(mobLevel)
return mobName, mobLevel
end -- MI2_IndexComponents()
-----------------------------------------------------------------------------
-- MI2_CleanupDatabases()
--
-- Cleanup for MobInfo database. This function corrects bugs in the
-- MobInfo database and applies some changes that have been made to
-- the format of the actual database entires.
--
-- With "DatabaseVersion" 3 the database storage format has changed completely,
-- which means that a complex conversion must be applied to convert the
-- old into the new database format.
--
-- increased DB version to 4 to enforce a cleanup run for everyone installing
-- the newest MobInfo release (2.64 and above)
-----------------------------------------------------------------------------
function MI2_CleanupDatabases()
-- local startTime = GetTime()
local mobIndex, mobInfo
if MobInfoDB.DatabaseVersion then MobInfoDB.DatabaseVersion = nil end
-- attempt to automatically fix invalid database entries where the index is bugged
for mobIndex, mobInfo in MobInfoDB do
local mobName, mobLevel = MI2_GetIndexComponents( mobIndex )
if not mobName or not mobLevel or mobName == "" then
MobInfoDB[mobIndex] = nil
end
end
-- update database to the most recent version
-- this will convert old databases into the new DB format and will attempt
-- to fix any invalid database entries
if not MobInfoDB["DatabaseVersion:0"] or MobInfoDB["DatabaseVersion:0"].ver < MI2_DB_VERSION then
if MI2_Debug > 0 then chattext( "M2DBG: running DB cleanup for ver=[nil]" ) end
MobInfoDB["DatabaseVersion:0"] = nil
-- loop through all Mobs in the database
for mobIndex, mobInfo in MobInfoDB do
-- build new "basic info" entry from old separate entries
if (mobInfo.lt or mobInfo.el or mobInfo.cp or mobInfo.iv or mobInfo.cc or mobInfo.xp) and not mobInfo.bi then
if mobInfo.lt and mobInfo.lt <= 0 then mobInfo.lt = nil end
if mobInfo.cp and mobInfo.cp <= 0 then mobInfo.cp = nil end
if mobInfo.iv and mobInfo.iv <= 0 then mobInfo.iv = nil end
if mobInfo.el and mobInfo.el <= 0 then mobInfo.el = nil end
if mobInfo.cc and mobInfo.cc <= 0 then mobInfo.cc = nil end
mobInfo.bi = (mobInfo.lt or "").."/"..(mobInfo.el or "").."/"..(mobInfo.cp or "").."/"..(mobInfo.iv or "").."/"..(mobInfo.cc or "").."/"..(mobInfo.xp or "").."/"..(mobInfo.mt or "")
end
local s, slashCount = string.gsub( (mobInfo.bi or ""), "/", "@" )
if slashCount == 6 then mobInfo.bi = mobInfo.bi.."/"; slashCount = slashCount + 1 end
if mobInfo.bi == "///////" then mobInfo.bi = nil end
if mobInfo.bi and slashCount ~= 7 then mobInfo.bi = nil end
-- build new "quality info" entry from old separate entries
if (mobInfo.r0 or mobInfo.r1 or mobInfo.r2 or mobInfo.r3 or mobInfo.r4) and not mobInfo.qi then
if mobInfo.r0 and mobInfo.r0 <= 0 then mobInfo.r0 = nil end
if mobInfo.r1 and mobInfo.r1 <= 0 then mobInfo.r1 = nil end
if mobInfo.r2 and mobInfo.r2 <= 0 then mobInfo.r2 = nil end
if mobInfo.r3 and mobInfo.r3 <= 0 then mobInfo.r3 = nil end
if mobInfo.r4 and mobInfo.r4 <= 0 then mobInfo.r4 = nil end
mobInfo.qi = (mobInfo.r0 or "").."/"..(mobInfo.r1 or "").."/"..(mobInfo.r2 or "").."/"..(mobInfo.r3 or "").."/"..(mobInfo.r4 or "")
end
if mobInfo.qi == "////" then mobInfo.qi = nil end
-- loop through all Mob database record entries
-- process char specific data and remove all invalid entries from database record
for entryName, entryData in mobInfo do
if type(entryData) == "table" then
-- char specific data in table form found: convert it to new DB format
local dl = entryData.dl
local du = entryData.du
local dd = entryData.dd
if (dl or du) and not dd then
dd = dl.."/"..du.."/"..0
end
mobInfo[entryName] = (entryData.kl or "").."/"..(dd or "")
else
local isCharEntry = type(entryData) == "string" and (string.find(entryName,":") ~= nil or MI2_CharTable[entryName]) and string.find(entryData,"/") ~= nil
isCharEntry = isCharEntry or type(entryData) == "string"
if isCharEntry then
if mobInfo[entryName] == "///" then
mobInfo[entryName] = nil
end
elseif entryName ~= "bi" and entryName ~= "qi" and entryName ~= "il" and entryName ~= "ml" then
mobInfo[entryName] = nil
end
end
end -- for
end -- for
-- loop through all Mobs in the database and convert char name into char index
-- delete all empty mob records
for mobIndex, mobInfo in MobInfoDB do
local entryCount = 0
for entryName, entryData in mobInfo do
entryCount = entryCount + 1
local isCharEntry = type(entryData) == "string" and string.find(entryName,":") ~= nil and string.find(entryData,"/") ~= nil
if isCharEntry then
if not MI2_CharTable[entryName] then
MI2_CharTable.charCount = MI2_CharTable.charCount + 1
MI2_CharTable[entryName] = "c"..MI2_CharTable.charCount
end
mobInfo[MI2_CharTable[entryName]] = entryData
mobInfo[entryName] = nil
end
end -- for
if entryCount == 0 then
MobInfoDB[mobIndex] = nil
end
end
MobInfoDB["DatabaseVersion:0"] = { ver = MI2_DB_VERSION }
end
-- chattext( "<MobInfo> database conversion time = "..(GetTime()-startTime).." seconds" )
end -- MI2_CleanupDatabases()
-----------------------------------------------------------------------------
-- MI2_ImportLocationsFromMI2B()
--
-- Import the Mob locations that have been recorded by the MI2_Browser
-- AddOn into the MobInfo2 Mob database. Only import correct location
-- data for Mobs that do not yet have a location.
-----------------------------------------------------------------------------
function MI2_ImportLocationsFromMI2B()
-- import TipBuddy Mob location data into the MobInfo database
if MobInfoDB_B and not MobInfoDB_B.converted then
for idx, val in MobInfoDB_B do
if MobInfoDB[idx] and not MobInfoDB[idx].ml and val.loc and val.loc.l and val.loc.x and val.loc.y then
local x = floor( val.loc.x * 100.0 )
local y = floor( val.loc.y * 100.0 )
local _, _, continent, zone = string.find( (tostring(val.loc.l)), MI2B_LOCPATTERN )
if continent and zone and x > 0 and y > 0 then
local locationInfo = (x or "").."/"..(y or "").."/"..(x or "").."/"..(y or "").."/"..(continent or "").."/"..(zone or "")
MobInfoDB[idx].ml = locationInfo
end
end
end
MobInfoDB_B.converted = 1
end
end
-----------------------------------------------------------------------------
-- MI2_AddItemToXRefTable()
--
-- build the cross reference table for fast item lookup
-- The table is indexed by item name and lists all Mobs that drop the item
-----------------------------------------------------------------------------
local function MI2_AddItemToXRefTable( mobIndex, itemName, itemAmount )
if not MI2_XRefItemTable[itemName] then
MI2_XRefItemTable[itemName] = {}
end
local oldAmount = MI2_XRefItemTable[itemName][mobIndex]
MI2_XRefItemTable[itemName][mobIndex] = (oldAmount or 0) + itemAmount
--chattext("DBG: XRefItemTable: item=["..itemName.."], mob=["..mobIndex.."], val="..MI2_XRefItemTable[itemName][mobIndex] )
end -- MI2_AddItemToXRefTable()
-----------------------------------------------------------------------------
-- MI2_BuildXRefItemTable()
--
-- build the cross reference table for fast item lookup
-- The table is indexed by item name and lists all Mobs that drop the item.
-- It is needed for quickly generating the "Dropped By" list in item tooltips.
-----------------------------------------------------------------------------
function MI2_BuildXRefItemTable()
MI2_XRefItemTable = {}
for mobIndex, mobInfo in MobInfoDB do
local mobData = {}
MI2_DecodeItemList( mobInfo, mobData )
if mobData.itemList then
for itemID, amount in mobData.itemList do
local itemText = MI2_ItemNameTable[itemID]
if itemText then
itemText = string.sub( itemText, 1, -3 )
MI2_AddItemToXRefTable( mobIndex, itemText, amount )
end
end
end
end
end -- MI2_BuildXRefItemTable()
-----------------------------------------------------------------------------
-- MI2_NewMobTarget()
--
-- Add a Mob to the list of current targets. MobInfo tracks all current
-- targets to collect data on the Mobs and for advanced kill counting.
-----------------------------------------------------------------------------
function MI2_NewMobTarget( index )
if not MI2_CurrentTargets[index] then
MI2_CurrentTargets[index] = {}
end
local mobData = MI2_CurrentTargets[index]
mobData.time = GetTime()
mobData.killed = nil
-- obtain and store mob type
local mobType = UnitClassification( "target" )
if mobType and mobType ~= "normal" then
if mobType == "rare" or mobType == "elite" then
mobData.mobType = 2
else
mobData.mobType = 3
end
end
return mobData
end -- MI2_NewMobTarget()
-----------------------------------------------------------------------------
-- MI2_RecordDamage()
--
-- record damage value for a mob
-----------------------------------------------------------------------------
function MI2_RecordDamage( index, damage )
local mobData = MI2_CurrentTargets[index]
if MI2_Debug > 1 then chattext( "M2DBG: damage reported: mob=["..index.."], dmg="..damage ) end
-- update minimum and/or maximum damage for mob
if mobData and damage > 0 then
if not mobData.minDamage or mobData.minDamage <= 0 then
mobData.minDamage, mobData.maxDamage = damage, damage
elseif damage < mobData.minDamage then
if MI2_Debug > 0 then chattext( "M2DBG: recording new MIN dmg "..damage.." for ["..index.."] (old="..mobData.minDamage..")" ) end
mobData.minDamage = damage
elseif damage > mobData.maxDamage then
if MI2_Debug > 0 then chattext( "M2DBG: recording new MAX dmg "..damage.." for ["..index.."] (old="..mobData.maxDamage..")" ) end
mobData.maxDamage = damage
end
end
end -- MI2_RecordDamage()
-----------------------------------------------------------------------------
-- MI2_RecordDps()
--
-- record a new dps (damage per second) value for a specific mob
-- dps gets calculated from damage done within a given time
-----------------------------------------------------------------------------
function MI2_RecordDps( index, deltaTime, damage )
local mobData = MI2_CurrentTargets[index]
-- only store dps for fights longer then 4 seconds
if mobData and deltaTime > 4 then
-- calculate DPS value
local newDps = damage / deltaTime
if not mobData.dps then mobData.dps = newDps end
mobData.dps = floor( ((2.0 * mobData.dps) + newDps) / 3.0 )
-- update the dd (damage data) entry for this mob
if MI2_Debug > 0 then chattext( "M2DBG: recording new dps: idx="..index..", new dps="..mobData.dps ) end
end
end -- MI2_RecordDps()
-----------------------------------------------------------------------------
-- MI2_RecordKill()
--
-- record a kill and optionally the xp you got for the kill for the given mob
-----------------------------------------------------------------------------
local function MI2_RecordKill( index, xp )
local mobData = MI2_CurrentTargets[index]
if mobData then
if not mobData.killed then
mobData.kills = (mobData.kills or 0) + 1
end
mobData.killed = 1
if xp > 0 then
mobData.xp = xp
end
mobData.time = GetTime()
end
if MI2_Debug > 0 then chattext( "M2DBG: recording kill "..(mobData.kills or "<nil>").." and XP "..xp.." for mob ["..index.."]" ) end
end -- MI2_RecordKill()
-----------------------------------------------------------------------------
-- MI2_RecordLocation()
--
-- record the current location of the player as the location of the Mob
-- he is fighting
-----------------------------------------------------------------------------
local function MI2_RecordLocation( index )
local mobData = MI2_CurrentTargets[index]
if mobData and not mobData.location then
local x, y = GetPlayerMapPosition("player")
x = floor( x * 100.0 )
y = floor( y * 100.0 )
mobData.location = { x1=x, x2=x, y1=y, y2=y, c=MI2_CurContinent, z=MI2_CurZone }
end
end -- MI2_RecordLocation()
-----------------------------------------------------------------------------
-- MI2_RecordLootData()
--
-- Record the data for one loot item. This function is called in turn for
-- each loot item in the loot window.
-----------------------------------------------------------------------------
local function MI2_RecordLootData( mobData, itemID, money, itemValue, quality, isSkinningLoot )
mobData.clothCount = (mobData.clothCount or 0) + (miClothLoot[itemID] or 0 )
mobData.copper = (mobData.copper or 0) + money
if isSkinningLoot then
mobData.skinCount = (mobData.skinCount or 0) + 1
else
-- count item value only for non skinning loot
mobData.itemValue = (mobData.itemValue or 0) + itemValue
end
-- decide whether item should be counted in quality overview
if itemValue < 1 and quality == 2 or isSkinningLoot then
quality = -1
end
-- record loot item quality (if enabled)
if quality == 1 then
mobData.r1 = (mobData.r1 or 0) + 1
elseif quality == 2 then
mobData.r2 = (mobData.r2 or 0) + 1
elseif quality == 3 then
mobData.r3 = (mobData.r3 or 0) + 1
elseif quality == 4 then
mobData.r4 = (mobData.r4 or 0) + 1
elseif quality == 5 then
mobData.r5 = (mobData.r5 or 0) + 1
end
end -- MI2_RecordLootData()
-----------------------------------------------------------------------------
-- MI2_AddTwoMobs()
--
-- add the data for two mobs,
-- the data of the second mob (mobData2) is added to the data of the first
-- mob (mobData1). The result is returned in "mobData1".
-----------------------------------------------------------------------------
function MI2_AddTwoMobs( mobData1, mobData2 )
mobData1.loots = (mobData1.loots or 0) + (mobData2.loots or 0)
mobData1.kills = (mobData1.kills or 0) + (mobData2.kills or 0)
mobData1.emptyLoots = (mobData1.emptyLoots or 0) + (mobData2.emptyLoots or 0)
mobData1.clothCount = (mobData1.clothCount or 0) + (mobData2.clothCount or 0)
mobData1.copper = (mobData1.copper or 0) + (mobData2.copper or 0)
mobData1.itemValue = (mobData1.itemValue or 0) + (mobData2.itemValue or 0)
mobData1.skinCount = (mobData1.skinCount or 0) + (mobData2.skinCount or 0)
mobData1.r1 = (mobData1.r1 or 0) + (mobData2.r1 or 0)
mobData1.r2 = (mobData1.r2 or 0) + (mobData2.r2 or 0)
mobData1.r3 = (mobData1.r3 or 0) + (mobData2.r3 or 0)
mobData1.r4 = (mobData1.r4 or 0) + (mobData2.r4 or 0)
mobData1.r5 = (mobData1.r5 or 0) + (mobData2.r5 or 0)
if mobData2.mobType then mobData1.mobType = mobData2.mobType end
if mobData2.xp then mobData1.xp = mobData2.xp end
-- combine locations
if mobData1.location or mobData2.location then
if not mobData1.location then
mobData1.location = mobData2.location
elseif mobData2.location then
if mobData2.location.x1 < mobData1.location.x1 then
mobData1.location.x1 = mobData2.location.x1
end
if mobData2.location.x2 > mobData1.location.x2 then
mobData1.location.x2 = mobData2.location.x2
end
if mobData2.location.y1 < mobData1.location.y1 then
mobData1.location.y1 = mobData2.location.y1
end
if mobData2.location.y2 > mobData1.location.y2 then
mobData1.location.y2 = mobData2.location.y2
end
if mobData1.location.c == 0 then
mobData1.location.c = mobData2.location.c
end
end
end
-- combine DPS od two mobs
if not mobData1.dps then
mobData1.dps = mobData2.dps
else
if mobData2.dps then
mobData1.dps = floor( ((2.0 * mobData1.dps) + mobData2.dps) / 3.0 )
end
end
-- combine minimum and maximum damage
if (mobData2.minDamage or 99999) < (mobData1.minDamage or 99999) then
mobData1.minDamage = mobData2.minDamage
end
if (mobData2.maxDamage or 0) > (mobData1.maxDamage or 0) then
mobData1.maxDamage = mobData2.maxDamage
end
-- add loot item tables of the two mobs
if mobData2.itemList then
if not mobData1.itemList then mobData1.itemList = {} end
for itemID, amount in mobData2.itemList do
mobData1.itemList[itemID] = (mobData1.itemList[itemID] or 0) + mobData2.itemList[itemID]
end
end
if mobData1.loots == 0 then mobData1.loots = nil end