diff --git a/README.md b/README.md
index d383279f1b..34f55c95c8 100644
--- a/README.md
+++ b/README.md
@@ -514,12 +514,10 @@ https://github.com/mehah/otclient/blob/main/data/setup.otml#L21
|----------------------- |----------------------------------- |------ |
| Android compatibility |  | [Branch](https://github.com/mehah/otclient/tree/mobile-working) |
| Familiar outfit |  | [#39](https://github.com/Nottinghster/otclient/pull/39) |
-| Cyclopedia |  | [#47](https://github.com/Nottinghster/otclient/pull/47) |
-| Blessing |  | [#825](https://github.com/mehah/otclient/pull/825) |
| wheel_of_destiny |  | None |
+| Forge |  | None |
| Analyzer |  | [#802](https://github.com/mehah/otclient/pull/802) |
| fix Extended view new-layout |  | None |
-| Quickloot |  | None |
| Sound tibia 13 |  | None |
## 💯 Support Protocol
@@ -537,7 +535,7 @@ https://github.com/mehah/otclient/blob/main/data/setup.otml#L21
| TFS 1.6
(13.10) | Main repo
otland (2024) | [See wiki](https://github.com/mehah/otclient/wiki/Tutorial-to-Use-OTC-in-TFS-main) | ✅ |
| Canary 13.21 | OpenTibiaBr | [Assets , Enable HTTP login and port 80](https://docs.opentibiabr.com/opentibiabr/projects/otclient-redemption#how-to-connect-on-canary-with-otclient-redemption) | ✅ |
| Canary 13.32 | OpenTibiaBr | [Assets , Enable HTTP login and port 80](https://docs.opentibiabr.com/opentibiabr/projects/otclient-redemption#how-to-connect-on-canary-with-otclient-redemption) | ✅ |
-| Canary 13.40 | OpenTibiaBr | | 〰️ |
+| Canary 13.40 | OpenTibiaBr | | ✅ |
diff --git a/data/images/game/cyclopedia/bestiary_off.png b/data/images/game/cyclopedia/bestiary_off.png
new file mode 100644
index 0000000000..b62a5f8a4c
Binary files /dev/null and b/data/images/game/cyclopedia/bestiary_off.png differ
diff --git a/data/images/game/cyclopedia/bestiary_on.png b/data/images/game/cyclopedia/bestiary_on.png
new file mode 100644
index 0000000000..a936cc1280
Binary files /dev/null and b/data/images/game/cyclopedia/bestiary_on.png differ
diff --git a/data/images/game/cyclopedia/bossSlot_off.png b/data/images/game/cyclopedia/bossSlot_off.png
new file mode 100644
index 0000000000..02f9847c94
Binary files /dev/null and b/data/images/game/cyclopedia/bossSlot_off.png differ
diff --git a/data/images/game/cyclopedia/bossSlot_on.png b/data/images/game/cyclopedia/bossSlot_on.png
new file mode 100644
index 0000000000..cc6973ffb7
Binary files /dev/null and b/data/images/game/cyclopedia/bossSlot_on.png differ
diff --git a/data/images/game/cyclopedia/bosstiary_off.png b/data/images/game/cyclopedia/bosstiary_off.png
new file mode 100644
index 0000000000..c7a864ca06
Binary files /dev/null and b/data/images/game/cyclopedia/bosstiary_off.png differ
diff --git a/data/images/game/cyclopedia/bosstiary_on.png b/data/images/game/cyclopedia/bosstiary_on.png
new file mode 100644
index 0000000000..0d180f53dc
Binary files /dev/null and b/data/images/game/cyclopedia/bosstiary_on.png differ
diff --git a/data/images/game/cyclopedia/character_off.png b/data/images/game/cyclopedia/character_off.png
new file mode 100644
index 0000000000..eb3ce4c21a
Binary files /dev/null and b/data/images/game/cyclopedia/character_off.png differ
diff --git a/data/images/game/cyclopedia/character_on.png b/data/images/game/cyclopedia/character_on.png
new file mode 100644
index 0000000000..ec13d60389
Binary files /dev/null and b/data/images/game/cyclopedia/character_on.png differ
diff --git a/data/images/game/cyclopedia/charms_off.png b/data/images/game/cyclopedia/charms_off.png
new file mode 100644
index 0000000000..4d584ea432
Binary files /dev/null and b/data/images/game/cyclopedia/charms_off.png differ
diff --git a/data/images/game/cyclopedia/charms_on.png b/data/images/game/cyclopedia/charms_on.png
new file mode 100644
index 0000000000..ab4aa91cf1
Binary files /dev/null and b/data/images/game/cyclopedia/charms_on.png differ
diff --git a/data/images/game/cyclopedia/houses_off.png b/data/images/game/cyclopedia/houses_off.png
new file mode 100644
index 0000000000..a69605b03e
Binary files /dev/null and b/data/images/game/cyclopedia/houses_off.png differ
diff --git a/data/images/game/cyclopedia/houses_on.png b/data/images/game/cyclopedia/houses_on.png
new file mode 100644
index 0000000000..1bde4c8f6d
Binary files /dev/null and b/data/images/game/cyclopedia/houses_on.png differ
diff --git a/data/images/game/cyclopedia/items_off.png b/data/images/game/cyclopedia/items_off.png
new file mode 100644
index 0000000000..e4f7506dff
Binary files /dev/null and b/data/images/game/cyclopedia/items_off.png differ
diff --git a/data/images/game/cyclopedia/items_on.png b/data/images/game/cyclopedia/items_on.png
new file mode 100644
index 0000000000..9cf56260f8
Binary files /dev/null and b/data/images/game/cyclopedia/items_on.png differ
diff --git a/data/images/game/cyclopedia/map_off.png b/data/images/game/cyclopedia/map_off.png
new file mode 100644
index 0000000000..5a0d9d7161
Binary files /dev/null and b/data/images/game/cyclopedia/map_off.png differ
diff --git a/data/images/game/cyclopedia/map_on.png b/data/images/game/cyclopedia/map_on.png
new file mode 100644
index 0000000000..e3dce516d4
Binary files /dev/null and b/data/images/game/cyclopedia/map_on.png differ
diff --git a/data/images/game/cyclopedia/off.psd b/data/images/game/cyclopedia/off.psd
new file mode 100644
index 0000000000..7e59fd932a
Binary files /dev/null and b/data/images/game/cyclopedia/off.psd differ
diff --git a/data/images/game/cyclopedia/on.psd b/data/images/game/cyclopedia/on.psd
new file mode 100644
index 0000000000..b5d26577ea
Binary files /dev/null and b/data/images/game/cyclopedia/on.psd differ
diff --git a/data/images/game/slots/inventory-back.png b/data/images/game/slots/inventory-back.png
new file mode 100644
index 0000000000..30b8cf298c
Binary files /dev/null and b/data/images/game/slots/inventory-back.png differ
diff --git a/data/images/game/slots/inventory-feet.png b/data/images/game/slots/inventory-feet.png
new file mode 100644
index 0000000000..348e9b0a01
Binary files /dev/null and b/data/images/game/slots/inventory-feet.png differ
diff --git a/data/images/game/slots/inventory-finger.png b/data/images/game/slots/inventory-finger.png
new file mode 100644
index 0000000000..3dd65d8ccd
Binary files /dev/null and b/data/images/game/slots/inventory-finger.png differ
diff --git a/data/images/game/slots/inventory-head.png b/data/images/game/slots/inventory-head.png
new file mode 100644
index 0000000000..3b246f8589
Binary files /dev/null and b/data/images/game/slots/inventory-head.png differ
diff --git a/data/images/game/slots/inventory-hip.png b/data/images/game/slots/inventory-hip.png
new file mode 100644
index 0000000000..7be6547c7b
Binary files /dev/null and b/data/images/game/slots/inventory-hip.png differ
diff --git a/data/images/game/slots/inventory-left-hand.png b/data/images/game/slots/inventory-left-hand.png
new file mode 100644
index 0000000000..4bdfb1a654
Binary files /dev/null and b/data/images/game/slots/inventory-left-hand.png differ
diff --git a/data/images/game/slots/inventory-legs.png b/data/images/game/slots/inventory-legs.png
new file mode 100644
index 0000000000..1fc8835cb3
Binary files /dev/null and b/data/images/game/slots/inventory-legs.png differ
diff --git a/data/images/game/slots/inventory-neck.png b/data/images/game/slots/inventory-neck.png
new file mode 100644
index 0000000000..4e19f4d52b
Binary files /dev/null and b/data/images/game/slots/inventory-neck.png differ
diff --git a/data/images/game/slots/inventory-right-hand.png b/data/images/game/slots/inventory-right-hand.png
new file mode 100644
index 0000000000..df7dc95dba
Binary files /dev/null and b/data/images/game/slots/inventory-right-hand.png differ
diff --git a/data/images/game/slots/inventory-torso.png b/data/images/game/slots/inventory-torso.png
new file mode 100644
index 0000000000..dfc98aca96
Binary files /dev/null and b/data/images/game/slots/inventory-torso.png differ
diff --git a/data/images/options/ButtonBossSlot.png b/data/images/options/ButtonBossSlot.png
new file mode 100644
index 0000000000..80262bc181
Binary files /dev/null and b/data/images/options/ButtonBossSlot.png differ
diff --git a/data/images/options/ButtonBosstiary.png b/data/images/options/ButtonBosstiary.png
new file mode 100644
index 0000000000..e161a3c726
Binary files /dev/null and b/data/images/options/ButtonBosstiary.png differ
diff --git a/data/images/options/bestiaryTracker.png b/data/images/options/bestiaryTracker.png
new file mode 100644
index 0000000000..93e7858cc2
Binary files /dev/null and b/data/images/options/bestiaryTracker.png differ
diff --git a/data/images/options/bosstiaryTracker.png b/data/images/options/bosstiaryTracker.png
new file mode 100644
index 0000000000..1fd58020fa
Binary files /dev/null and b/data/images/options/bosstiaryTracker.png differ
diff --git a/data/images/topbuttons/bestiaryTracker.png b/data/images/topbuttons/bestiaryTracker.png
new file mode 100644
index 0000000000..ddaab2a010
Binary files /dev/null and b/data/images/topbuttons/bestiaryTracker.png differ
diff --git a/data/images/ui/backdrop-dark-grey.png b/data/images/ui/backdrop-dark-grey.png
new file mode 100644
index 0000000000..a8ad6ff6b3
Binary files /dev/null and b/data/images/ui/backdrop-dark-grey.png differ
diff --git a/data/images/ui/button-9grid-idle.png b/data/images/ui/button-9grid-idle.png
new file mode 100644
index 0000000000..bb5a869689
Binary files /dev/null and b/data/images/ui/button-9grid-idle.png differ
diff --git a/data/images/ui/button-9grid-pressed.png b/data/images/ui/button-9grid-pressed.png
new file mode 100644
index 0000000000..b0935c59b9
Binary files /dev/null and b/data/images/ui/button-9grid-pressed.png differ
diff --git a/data/images/ui/button-clear-18x18-down.png b/data/images/ui/button-clear-18x18-down.png
new file mode 100644
index 0000000000..a24de421f4
Binary files /dev/null and b/data/images/ui/button-clear-18x18-down.png differ
diff --git a/data/images/ui/button-clear-18x18-up.png b/data/images/ui/button-clear-18x18-up.png
new file mode 100644
index 0000000000..08ebd932f8
Binary files /dev/null and b/data/images/ui/button-clear-18x18-up.png differ
diff --git a/data/images/ui/button-storexp-pressed.png b/data/images/ui/button-storexp-pressed.png
new file mode 100644
index 0000000000..793637cd83
Binary files /dev/null and b/data/images/ui/button-storexp-pressed.png differ
diff --git a/data/images/ui/button-storexp.png b/data/images/ui/button-storexp.png
new file mode 100644
index 0000000000..6bc36d142c
Binary files /dev/null and b/data/images/ui/button-storexp.png differ
diff --git a/data/images/ui/character/ammo.png b/data/images/ui/character/ammo.png
new file mode 100644
index 0000000000..db66a8eb96
Binary files /dev/null and b/data/images/ui/character/ammo.png differ
diff --git a/data/images/ui/character/ammo2.png b/data/images/ui/character/ammo2.png
new file mode 100644
index 0000000000..2b426ec7f8
Binary files /dev/null and b/data/images/ui/character/ammo2.png differ
diff --git a/data/images/ui/character/amulet.png b/data/images/ui/character/amulet.png
new file mode 100644
index 0000000000..25e40ad346
Binary files /dev/null and b/data/images/ui/character/amulet.png differ
diff --git a/data/images/ui/character/amulet2.png b/data/images/ui/character/amulet2.png
new file mode 100644
index 0000000000..2010752cd2
Binary files /dev/null and b/data/images/ui/character/amulet2.png differ
diff --git a/data/images/ui/character/armor.png b/data/images/ui/character/armor.png
new file mode 100644
index 0000000000..56ff9f70af
Binary files /dev/null and b/data/images/ui/character/armor.png differ
diff --git a/data/images/ui/character/armor2.png b/data/images/ui/character/armor2.png
new file mode 100644
index 0000000000..6183f10c5b
Binary files /dev/null and b/data/images/ui/character/armor2.png differ
diff --git a/data/images/ui/character/artifact.png b/data/images/ui/character/artifact.png
new file mode 100644
index 0000000000..8fecd99233
Binary files /dev/null and b/data/images/ui/character/artifact.png differ
diff --git a/data/images/ui/character/artifact2.png b/data/images/ui/character/artifact2.png
new file mode 100644
index 0000000000..2029c92bf5
Binary files /dev/null and b/data/images/ui/character/artifact2.png differ
diff --git a/data/images/ui/character/backpack.png b/data/images/ui/character/backpack.png
new file mode 100644
index 0000000000..1fadbf4a6a
Binary files /dev/null and b/data/images/ui/character/backpack.png differ
diff --git a/data/images/ui/character/backpack2.png b/data/images/ui/character/backpack2.png
new file mode 100644
index 0000000000..bfe60b5aa9
Binary files /dev/null and b/data/images/ui/character/backpack2.png differ
diff --git a/data/images/ui/character/blank.png b/data/images/ui/character/blank.png
new file mode 100644
index 0000000000..30235d80a7
Binary files /dev/null and b/data/images/ui/character/blank.png differ
diff --git a/data/images/ui/character/boots.png b/data/images/ui/character/boots.png
new file mode 100644
index 0000000000..e222854002
Binary files /dev/null and b/data/images/ui/character/boots.png differ
diff --git a/data/images/ui/character/boots2.png b/data/images/ui/character/boots2.png
new file mode 100644
index 0000000000..0380494d13
Binary files /dev/null and b/data/images/ui/character/boots2.png differ
diff --git a/data/images/ui/character/helmet.png b/data/images/ui/character/helmet.png
new file mode 100644
index 0000000000..16130d4ccb
Binary files /dev/null and b/data/images/ui/character/helmet.png differ
diff --git a/data/images/ui/character/helmet2.png b/data/images/ui/character/helmet2.png
new file mode 100644
index 0000000000..1c1b002d23
Binary files /dev/null and b/data/images/ui/character/helmet2.png differ
diff --git a/data/images/ui/character/icon.png b/data/images/ui/character/icon.png
new file mode 100644
index 0000000000..76781e5db7
Binary files /dev/null and b/data/images/ui/character/icon.png differ
diff --git a/data/images/ui/character/legs.png b/data/images/ui/character/legs.png
new file mode 100644
index 0000000000..333a751930
Binary files /dev/null and b/data/images/ui/character/legs.png differ
diff --git a/data/images/ui/character/legs2.png b/data/images/ui/character/legs2.png
new file mode 100644
index 0000000000..7d34d27f4c
Binary files /dev/null and b/data/images/ui/character/legs2.png differ
diff --git a/data/images/ui/character/mainhand.png b/data/images/ui/character/mainhand.png
new file mode 100644
index 0000000000..bf5b2c6809
Binary files /dev/null and b/data/images/ui/character/mainhand.png differ
diff --git a/data/images/ui/character/mainhand2.png b/data/images/ui/character/mainhand2.png
new file mode 100644
index 0000000000..2ce1f516d9
Binary files /dev/null and b/data/images/ui/character/mainhand2.png differ
diff --git a/data/images/ui/character/offhand.png b/data/images/ui/character/offhand.png
new file mode 100644
index 0000000000..20512bc3c4
Binary files /dev/null and b/data/images/ui/character/offhand.png differ
diff --git a/data/images/ui/character/offhand2.png b/data/images/ui/character/offhand2.png
new file mode 100644
index 0000000000..0e85afca0b
Binary files /dev/null and b/data/images/ui/character/offhand2.png differ
diff --git a/data/images/ui/character/primary_backpack.png b/data/images/ui/character/primary_backpack.png
new file mode 100644
index 0000000000..19599c03ea
Binary files /dev/null and b/data/images/ui/character/primary_backpack.png differ
diff --git a/data/images/ui/character/ring.png b/data/images/ui/character/ring.png
new file mode 100644
index 0000000000..be90959873
Binary files /dev/null and b/data/images/ui/character/ring.png differ
diff --git a/data/images/ui/character/ring2.png b/data/images/ui/character/ring2.png
new file mode 100644
index 0000000000..039998c809
Binary files /dev/null and b/data/images/ui/character/ring2.png differ
diff --git a/data/images/ui/character/rune.png b/data/images/ui/character/rune.png
new file mode 100644
index 0000000000..5dffba1f88
Binary files /dev/null and b/data/images/ui/character/rune.png differ
diff --git a/data/images/ui/character/rune2.png b/data/images/ui/character/rune2.png
new file mode 100644
index 0000000000..ef94251c4d
Binary files /dev/null and b/data/images/ui/character/rune2.png differ
diff --git a/data/images/ui/character/secondary_backpack.png b/data/images/ui/character/secondary_backpack.png
new file mode 100644
index 0000000000..a150550bef
Binary files /dev/null and b/data/images/ui/character/secondary_backpack.png differ
diff --git a/data/images/ui/character/slot.png b/data/images/ui/character/slot.png
new file mode 100644
index 0000000000..3f33686dd8
Binary files /dev/null and b/data/images/ui/character/slot.png differ
diff --git a/data/images/ui/ditherpattern.png b/data/images/ui/ditherpattern.png
new file mode 100644
index 0000000000..6620529f9b
Binary files /dev/null and b/data/images/ui/ditherpattern.png differ
diff --git a/data/images/ui/miniwindow_buttons.png b/data/images/ui/miniwindow_buttons.png
index 8d19e30c65..5de3abd310 100644
Binary files a/data/images/ui/miniwindow_buttons.png and b/data/images/ui/miniwindow_buttons.png differ
diff --git a/data/images/ui/progress-separator.png b/data/images/ui/progress-separator.png
new file mode 100644
index 0000000000..00c545d5ae
Binary files /dev/null and b/data/images/ui/progress-separator.png differ
diff --git a/data/images/ui/rarity_blue.png b/data/images/ui/rarity_blue.png
index 13220bd287..2740796fd5 100644
Binary files a/data/images/ui/rarity_blue.png and b/data/images/ui/rarity_blue.png differ
diff --git a/data/images/ui/rarity_green.png b/data/images/ui/rarity_green.png
index b452b0fd16..8dd64a49f2 100644
Binary files a/data/images/ui/rarity_green.png and b/data/images/ui/rarity_green.png differ
diff --git a/data/images/ui/rarity_grey.png b/data/images/ui/rarity_grey.png
new file mode 100644
index 0000000000..d8aaaad4a0
Binary files /dev/null and b/data/images/ui/rarity_grey.png differ
diff --git a/data/images/ui/rarity_purple.png b/data/images/ui/rarity_purple.png
index 05faf5b18e..f060d41073 100644
Binary files a/data/images/ui/rarity_purple.png and b/data/images/ui/rarity_purple.png differ
diff --git a/data/images/ui/rarity_white.png b/data/images/ui/rarity_white.png
index 9984f9c732..fb19f85378 100644
Binary files a/data/images/ui/rarity_white.png and b/data/images/ui/rarity_white.png differ
diff --git a/data/images/ui/rarity_yellow.png b/data/images/ui/rarity_yellow.png
new file mode 100644
index 0000000000..0b02660792
Binary files /dev/null and b/data/images/ui/rarity_yellow.png differ
diff --git a/data/images/ui/undefined_item.png b/data/images/ui/undefined_item.png
new file mode 100644
index 0000000000..8514b74680
Binary files /dev/null and b/data/images/ui/undefined_item.png differ
diff --git a/data/images/ui/widget-borderimage.png b/data/images/ui/widget-borderimage.png
new file mode 100644
index 0000000000..36b45c5f5a
Binary files /dev/null and b/data/images/ui/widget-borderimage.png differ
diff --git a/data/styles/10-checkboxes.otui b/data/styles/10-checkboxes.otui
index 194ac1d52d..56975b7c58 100644
--- a/data/styles/10-checkboxes.otui
+++ b/data/styles/10-checkboxes.otui
@@ -104,3 +104,33 @@ QtCheckBox < UICheckBox
$checked disabled:
image-clip: 0 26 14 14
+
+fakeCheckBox < UICheckBox
+ font: cipsoftFont
+ size: 106 23
+ image-source: /images/ui/button
+ image-clip: 0 0 22 23
+ image-border: 3
+ padding: 5 10 5 10
+ opacity: 1.0
+ color: #b9b9b9ff
+
+ $hover !disabled:
+ color: #ffffff
+
+ $!checked:
+ image-clip: 0 0 22 23
+
+ $hover !checked:
+ image-clip: 0 0 22 23
+
+ $checked:
+ image-clip: 0 46 22 23
+
+ $hover checked:
+ image-clip: 0 46 22 23
+
+ $disabled:
+ image-color: #dfdfdf88
+ color: #dfdfdf88
+ opacity: 0.8
diff --git a/modules/corelib/ui/uimessagebox.lua b/modules/corelib/ui/uimessagebox.lua
index 92eeba8bd8..280641e766 100644
--- a/modules/corelib/ui/uimessagebox.lua
+++ b/modules/corelib/ui/uimessagebox.lua
@@ -11,11 +11,10 @@ function UIMessageBox.create(title, okCallback, cancelCallback)
return calendar
end
-
function UIMessageBox.display(title, message, buttons, onEnterCallback, onEscapeCallback)
local staticSizes = {
width = {
- max = 616,
+ max = 916,
min = 116
},
height = {
diff --git a/modules/game_containers/containers.lua b/modules/game_containers/containers.lua
index 5cb598b14b..fc0354b057 100644
--- a/modules/game_containers/containers.lua
+++ b/modules/game_containers/containers.lua
@@ -137,6 +137,7 @@ function onContainerOpen(container, previousContainer)
local itemWidget = g_ui.createWidget('Item', containerPanel)
itemWidget:setId('item' .. slot)
itemWidget:setItem(container:getItem(slot))
+ ItemsDatabase.setRarityItem(itemWidget, container:getItem(slot))
itemWidget:setMargin(0)
itemWidget.position = container:getSlotPosition(slot)
diff --git a/modules/game_cooldown/cooldown.lua b/modules/game_cooldown/cooldown.lua
index b3fda07688..933b2915bc 100644
--- a/modules/game_cooldown/cooldown.lua
+++ b/modules/game_cooldown/cooldown.lua
@@ -4,7 +4,7 @@ local ProgressCallback = {
}
cooldownWindow = nil
-cooldownButton = nil
+
contentsPanel = nil
cooldownPanel = nil
lastPlayer = nil
@@ -20,23 +20,13 @@ function init()
onSpellCooldown = onSpellCooldown
})
- cooldownButton = modules.game_mainpanel.addToggleButton('cooldownButton', tr('Cooldowns'),
- '/images/options/cooldowns', toggle, false, 5)
-
if modules.client_options.getOption('showSpellGroupCooldowns') then
- cooldownButton:setOn(true)
modules.client_options.setOption('showSpellGroupCooldowns', true)
else
- cooldownButton:setOn(false)
modules.client_options.setOption('showSpellGroupCooldowns', false)
end
- cooldownButton:hide()
-
cooldownWindow = g_ui.loadUI('cooldown', modules.game_interface.getBottomPanel())
-
-
-
contentsPanel = cooldownWindow:getChildById('contentsPanel2')
cooldownPanel = contentsPanel:getChildById('cooldownPanel')
@@ -59,7 +49,6 @@ function terminate()
})
cooldownWindow:destroy()
- cooldownButton:destroy()
end
@@ -98,39 +87,21 @@ function loadIcon(iconId)
end
function onMiniWindowOpen()
- cooldownButton:setOn(true)
modules.client_options.setOption('showSpellGroupCooldowns', true)
end
function onMiniWindowClose()
- cooldownButton:setOn(false)
modules.client_options.setOption('showSpellGroupCooldowns', false)
end
-function toggle()
- local console = modules.game_console.consolePanel
- if cooldownButton:isOn() then
- modules.client_options.setOption('showSpellGroupCooldowns', false)
- cooldownButton:setOn(false)
- else
- modules.client_options.setOption('showSpellGroupCooldowns', true)
- cooldownButton:setOn(true)
- end
-end
-
function online()
local console = modules.game_console.consolePanel
if console then
console:addAnchor(AnchorTop, cooldownWindow:getId(), AnchorBottom)
end
- if g_game.getFeature(GameSpellList) then
- cooldownButton:show()
- cooldownButton:setOn(true)
- modules.client_options.setOption('showSpellGroupCooldowns', true)
- else
- cooldownButton:hide()
- cooldownButton:setOn(false)
+ if not g_game.getFeature(GameSpellList) then
modules.client_options.setOption('showSpellGroupCooldowns', false)
+ return
end
if not lastPlayer or lastPlayer ~= g_game.getCharacterName() then
@@ -277,11 +248,6 @@ function onSpellGroupCooldown(groupId, duration)
end
function setSpellGroupCooldownsVisible(visible)
- if not g_game.getFeature(GameSpellList) then
- cooldownWindow:hide()
- cooldownWindow:setHeight(10)
- return
- end
if visible then
cooldownWindow:setHeight(30)
cooldownWindow:show()
@@ -289,6 +255,4 @@ function setSpellGroupCooldownsVisible(visible)
cooldownWindow:hide()
cooldownWindow:setHeight(10)
end
-
- cooldownButton:setOn(visible)
end
\ No newline at end of file
diff --git a/modules/game_cyclopedia/cyclopedia_pages.otui b/modules/game_cyclopedia/cyclopedia_pages.otui
new file mode 100644
index 0000000000..40b488086a
--- /dev/null
+++ b/modules/game_cyclopedia/cyclopedia_pages.otui
@@ -0,0 +1 @@
+CyclopediaPages < UIWidget
diff --git a/modules/game_cyclopedia/cyclopedia_widgets.otui b/modules/game_cyclopedia/cyclopedia_widgets.otui
new file mode 100644
index 0000000000..8ce07b2079
--- /dev/null
+++ b/modules/game_cyclopedia/cyclopedia_widgets.otui
@@ -0,0 +1,1446 @@
+HouseIcon < UIWidget
+ //image-source: /game_cyclopedia/images/house-owner-icon
+ margin-left: 1
+HouseBidArea < UIWidget
+ height: 100
+ margin-top: 2
+ Label
+ !text: tr('Set bid limit:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: parent.top
+ anchors.left: parent.left
+ margin-top: 2
+ TextEdit
+ id: textEdit
+ size: 100 16
+ text-align: right
+ anchors.top: parent.top
+ anchors.left: prev.right
+ padding-top: 1
+ margin-top: 1
+ margin-left: 5
+ UIWidget
+ image-source: /game_cyclopedia/images/icon_gold
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-top: 3
+ margin-left: 5
+ UIWidget
+ anchors.right: parent.right
+ anchors.top: prev.top
+ image-source: /images/icons/show_gui_help_grey
+ Label
+ id: information
+ color: #C0C0C0
+ text-auto-resize: true
+ text-wrap: true
+ anchors.top: parent.top
+ anchors.left: parent.left
+ margin-top: 25
+House < UICheckBox
+ text-align: top
+ text-offset: 0 1
+ color: #909090
+ image-source: /images/ui/widget-borderimage
+ image-border: 5
+ padding: 5
+ padding-top: 18
+ $checked:
+ border: 2 white
+ $!checked:
+ border: 0 white
+ Label
+ id: size
+ size: 100 15
+ !text: tr('Size: 17sqm')
+ color: #909090
+ anchors.top: parent.top
+ anchors.left: parent.left
+ Label
+ id: status
+ !text: tr('Status: auctioned (no bid yet)')
+ text-auto-resize: true
+ color: #909090
+ anchors.top: size.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ Label
+ id: beds
+ size: 95 15
+ !text: tr('Max. Beds: 1')
+ color: #909090
+ anchors.top: size.top
+ anchors.left: size.right
+ Label
+ text-auto-resize: true
+ !text: tr('Rent: ')
+ color: #909090
+ anchors.top: beds.top
+ anchors.left: beds.right
+ Label
+ id: rent
+ text-auto-resize: true
+ color: #C0C0C0
+ anchors.top: prev.top
+ anchors.left: prev.right
+ UIWidget
+ anchors.left: rent.right
+ anchors.verticalCenter: rent.verticalCenter
+ margin-left: 3
+ image-source: /game_cyclopedia/images/icon_gold
+ Panel
+ id: icons
+ height: 12
+ anchors.verticalCenter: prev.verticalCenter
+ anchors.left: prev.right
+ anchors.right: parent.right
+ layout:
+ type: horizontalBox
+ align-right: true
+ flow: true
+ UIWidget
+ id: description
+ //image-source: /game_cyclopedia/images/house-description
+ anchors.top: sold.top
+ anchors.left: sold.left
+ visible: false
+
+CharacterBadge < UIWidget
+ image-source: /game_cyclopedia/images/character_icons/friend-badge-icons
+
+CharacterAppearance < UIWidget
+ image-source: /images/ui/button-9grid-idle
+ image-border: 5
+ $pressed:
+ image-source: /images/ui/button-9grid-pressed
+ UICreature
+ id: creature
+ size: 64 64
+ anchors.centerIn: parent
+ phantom: true
+ margin-right: 5
+ margin-bottom: 10
+ Label
+ id: name
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.top: creature.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+ phantom: true
+CharacterGridItem < UIWidget
+ UIWidget
+ size: 32 32
+ id: ItemBackground
+ anchors.left: parent.left
+ anchors.verticalCenter: parent.verticalCenter
+ image-source: /images/ui/item
+ UIWidget
+ id: rarity
+ margin: 1
+ anchors.fill: ItemBackground
+ UIItem
+ id: item
+ anchors.fill: ItemBackground
+ Label
+ id: amount
+ !text: tr('0')
+ color: #C0C0C0
+ font: verdana-11px-rounded
+ text-auto-resize: true
+ anchors.bottom: parent.bottom
+ anchors.right: parent.right
+ margin-right: 2
+CharacterListItem < UIWidget
+ size: 480 36
+ UIWidget
+ size: 32 32
+ id: ItemBackground
+ anchors.left: parent.left
+ anchors.verticalCenter: parent.verticalCenter
+ image-source: /images/ui/item
+ margin-left: 2
+ UIWidget
+ id: rarity
+ margin: 1
+ anchors.fill: ItemBackground
+ UIItem
+ id: item
+ anchors.fill: ItemBackground
+ Label
+ id: name
+ !text: tr('Boots')
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.verticalCenter: item.verticalCenter
+ anchors.left: item.right
+ margin-left: 5
+ VerticalSeparator
+ id: separator
+ anchors.top: parent.top
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ margin-top: -1
+ margin-bottom: -1
+ margin-right: 135
+ Label
+ id: amount
+ !text: tr('1')
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.verticalCenter: item.verticalCenter
+ anchors.left: separator.left
+ margin-left: 5
+Achievement < UICheckBox
+ image-source: /images/ui/outfits/minipanel
+ image-border: 5
+ color: #C0C0C0
+ text-auto-resize: true
+ text-wrap: true
+ text-offset: 10 25
+ padding-bottom: 5
+ margin: 5
+ margin-bottom: 1
+ UIWidget
+ id: title
+ text-auto-resize: true
+ color: #909090
+ anchors.top: parent.top
+ margin-top: 2
+ anchors.horizontalCenter: parent.horizontalCenter
+ UIWidget
+ id: icon
+ image-source: /game_cyclopedia/images/icon-achievement
+ image-repeated: true
+ width: 22
+ anchors.top: title.top
+ anchors.left: parent.left
+ margin-left: 2
+ margin-top: 2
+CharacterDeath < UICheckBox
+ size: 450 17
+ Label
+ id: date
+ text-auto-resize: true
+ anchors.top: parent.top
+ anchors.left: parent.left
+ margin-left: 2
+ $on:
+ color: #F4F4F4
+ $!on:
+ color: #C0C0C0
+ VerticalSeparator
+ id: separator
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.bottom: parent.bottom
+ margin-top: -1
+ margin-bottom: -1
+ margin-left: 155
+ Label
+ id: cause
+ text-auto-resize: true
+ anchors.top: parent.top
+ anchors.left: separator.left
+ margin-left: 5
+ $on:
+ color: #F4F4F4
+ $!on:
+ color: #C0C0C0
+CharacterKill < UICheckBox
+ size: 450 17
+ Label
+ id: date
+ text-auto-resize: true
+ anchors.top: parent.top
+ anchors.left: parent.left
+ margin-left: 2
+ $on:
+ color: #F4F4F4
+ $!on:
+ color: #C0C0C0
+ VerticalSeparator
+ id: separator
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.bottom: parent.bottom
+ margin-top: -1
+ margin-bottom: -1
+ margin-left: 155
+ Label
+ id: description
+ text-auto-resize: true
+ anchors.top: parent.top
+ anchors.left: separator.left
+ margin-left: 5
+ $on:
+ color: #F4F4F4
+ $!on:
+ color: #C0C0C0
+ VerticalSeparator
+ id: separatorTwo
+ anchors.top: parent.top
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ margin-top: -1
+ margin-bottom: -1
+ margin-right: 84
+ Label
+ id: status
+ text-auto-resize: true
+ anchors.top: parent.top
+ anchors.left: separatorTwo.left
+ margin-left: 5
+ $on:
+ color: #F4F4F4
+ $!on:
+ color: #C0C0C0
+CharacterElementReduction < UIWidget
+ height: 20
+ Label
+ id: name
+ !text: tr('Physical')
+ text-auto-resize: true
+ anchors.top: parent.top
+ anchors.left: parent.left
+ color: #C0C0C0
+ Label
+ id: value
+ !text: ('+5%')
+ color: #44AD25
+ text-auto-resize: true
+ anchors.top: parent.top
+ anchors.right: parent.right
+ margin-right: 20
+ UIWidget
+ id: icon
+ size: 9 9
+ image-source: /images/icons/icons-skills
+
+ anchors.top: parent.top
+ anchors.left: value.right
+ margin-left: 5
+ margin-top: 2
+SkillCharacterIcon < UIWidget
+ id: icon
+ size: 9 9
+ anchors.top: parent.top
+ margin-top: 13
+ image-source: /images/icons/icons-skills
+CharacterSkillBase < UIWidget
+ height: 20
+ margin-left: 5
+ margin-right: 5
+ margin-top: 5
+SkillCharacterPercentPanel < ProgressBar
+ id: percent
+ background-color: green
+ height: 5
+ margin-top: 13
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.top: parent.top
+ phantom: false
+SelectBossBossSlots < UICheckBox
+ image-source: /images/ui/outfits/minipanel
+ text-offset: 0 3
+ text-align: top
+ image-border: 5
+ !text: tr('?')
+ color: #BEBEBE
+ border: 0 white
+ @onClick: modules.game_cyclopedia.Cyclopedia.bossSlotSelectBoss(self)
+ $checked:
+ border: 1 white
+ $!checked:
+ border: 0 white
+ UICreature
+ id: Sprite
+ size: 64 64
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ margin-bottom: 10
+ margin-right: 5
+ phantom: true
+ UIWidget
+ id: TypeIcon
+ anchors.right: Sprite.left
+ anchors.top: Sprite.top
+ image-source: images/boss/icon_bane
+SlotBossSlots < UIWidget
+ size: 222 360
+ image-source: /images/ui/outfits/minipanel
+ image-border: 20
+ color: #929292
+ text-offset: 0 3
+ text-align: top
+ Label
+ id: LockLabel
+ anchors.centerIn: parent
+ text-auto-resize: true
+ !text: tr('Unlocks if you reach the\nProwess level for any boss')
+ text-align: center
+ visible: true
+ UIWidget
+ id: SelectBoss
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ margin: 3
+ margin-top: 20
+ visible: false
+ BorderBox
+ id: ListBase
+ size: 212 281
+ anchors.top: parent.top
+ anchors.left: parent.left
+ margin-top: 5
+ margin-left: 2
+ UIScrollArea
+ id: List
+ vertical-scrollbar: ListScrollbar
+ anchors.fill: parent
+ padding-left: 6
+ padding-top: 6
+ padding-bottom: 4
+ layout:
+ type: grid
+ cell-size: 88 103
+ cell-spacing: 4
+ flow: true
+ VerticalScrollBar
+ id: ListScrollbar
+ anchors.top: List.top
+ anchors.right: List.right
+ anchors.bottom: List.bottom
+ step: 80
+ pixel-scroll: true
+ TextEdit
+ id: SearchEdit
+ height: 20
+ anchors.top: ListBase.bottom
+ anchors.right: ListBase.right
+ anchors.left: ListBase.left
+ margin-top: 6
+ padding-top: 2
+ padding-right: 15
+ placeholder: Type to search
+ placeholder-color: #6E706F
+ @onTextChange: modules.game_cyclopedia.Cyclopedia.SelectBossSearchText(self:getText())
+ UIWidget
+ id: SearchClearButton
+ anchors.right: SearchEdit.right
+ anchors.top: SearchEdit.top
+ margin-top: 1
+ margin-right: 1
+ image-source: /images/ui/button-clear-18x18-up
+ @onClick: modules.game_cyclopedia.Cyclopedia.SelectBossSearchText("", true, self)
+ $pressed:
+ image-source: /images/ui/button-clear-18x18-down
+ Button
+ id: SelectButton
+ size: 43 20
+ anchors.bottom: parent.bottom
+ anchors.right: parent.right
+ !text: tr('Select')
+ //font: verdana-bold-8px-antialiased
+ text-offset: 0 -1
+ color: #C0C0C0
+ enabled: false
+ margin-bottom: 2
+ margin-right: 2
+ UIWidget
+ id: ActivedBoss
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ margin: 3
+ margin-top: 20
+ visible: false
+ UICreature
+ id: Sprite
+ size: 64 64
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.top: parent.top
+ margin-top: 10
+ UIWidget
+ id: TypeIcon
+ anchors.right: Sprite.left
+ anchors.top: Sprite.top
+ image-source: images/boss/icon_bane
+ BossSlotProgress
+ id: Progress
+ anchors.top: Sprite.bottom
+ anchors.horizontalCenter: Sprite.horizontalCenter
+ margin-top: 34
+ Label
+ anchors.horizontalCenter: Progress.horizontalCenter
+ anchors.bottom: Progress.top
+ margin-bottom: 3
+ text-auto-resize: true
+ !text: tr('Total Kills')
+ color: #BEBEBE
+ Label
+ id: EquipmentLabel
+ anchors.horizontalCenter: Progress.horizontalCenter
+ anchors.top: Progress.bottom
+ text-auto-resize: true
+ !text: ('Equipment loot bonus: 118%')
+ text-align: center
+ margin-top: 18
+ ProgressBackground
+ id: ValueBackground
+ size: 128 20
+ anchors.bottom: parent.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+ margin-bottom: 5
+ Label
+ id: Value
+ anchors.centerIn: prev
+ text-auto-resize: true
+ !text: ('0')
+ text-align: center
+ UIWidget
+ image-source: /game_cyclopedia/images/icon_gold
+ anchors.left: Value.right
+ anchors.verticalCenter: Value.verticalCenter
+ margin-left: 2
+ margin-top: 1
+ Button
+ id: RemoveButton
+ height: 20
+ anchors.bottom: ValueBackground.bottom
+ anchors.right: ValueBackground.right
+ anchors.left: ValueBackground.left
+ margin-bottom: 25
+ !text: tr('Remove')
+ //font: verdana-bold-8px-antialiased
+ text-offset: 0 -1
+ color: #C0C0C0
+BossSlotProgress < UIWidget
+ size: 140 35
+ ProgressBackground
+ id: ProgressBorder2
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottom: parent.bottom
+ margin-bottom: 20
+ size: 42 14
+ ProgressBackground
+ id: ProgressBorder1
+ anchors.right: ProgressBorder2.left
+ anchors.bottom: ProgressBorder2.bottom
+ margin-right: 2
+ size: 42 14
+ ProgressBackground
+ id: ProgressBorder3
+ anchors.left: ProgressBorder2.right
+ anchors.bottom: ProgressBorder2.bottom
+ margin-left: 2
+ size: 42 14
+ UIWidget
+ id: ProgressBack
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ margin-bottom: 21
+ margin-right: 7
+ margin-left: 7
+ height: 13
+ image-border: 10
+ phantom: true
+ UIWidget
+ id: fill
+ anchors.fill: ProgressBack
+ image-source: /game_cyclopedia/images/boss/fill
+ margin-top: 1
+ phantom: true
+ UIWidget
+ anchors.left: ProgressBorder1.right
+ anchors.top: ProgressBorder1.top
+ image-source: /images/ui/progress-separator
+ margin-right: 4
+ phantom: true
+ UIWidget
+ anchors.left: ProgressBorder2.right
+ anchors.top: ProgressBorder1.top
+ image-source: /images/ui/progress-separator
+ phantom: true
+ UIWidget
+ id: bronzeStar
+ anchors.top: ProgressBorder1.bottom
+ anchors.horizontalCenter: ProgressBorder1.horizontalCenter
+ margin-top: 3
+ image-source: images/boss/icon_star_dark
+ UIWidget
+ id: silverStar
+ anchors.top: ProgressBorder2.bottom
+ anchors.horizontalCenter: ProgressBorder2.horizontalCenter
+ margin-top: 3
+ image-source: images/boss/icon_star_dark
+ image-repeated: true
+ width: 18
+ UIWidget
+ id: goldStar
+ anchors.top: ProgressBorder3.bottom
+ anchors.horizontalCenter: ProgressBorder3.horizontalCenter
+ margin-top: 3
+ image-source: images/boss/icon_star_dark
+ image-repeated: true
+ width: 27
+ Label
+ id: ProgressValue
+ anchors.centerIn: ProgressBorder2
+ text-auto-resize: true
+ !text: tr('0')
+ProgressBackground < UIWidget
+ image-source: /images/game/actionbar/1pixel-down-frame
+ image-border: 5
+ padding: 1
+ UIWidget
+ image-source: /images/ui/backdrop-dark-grey
+ image-border: 5
+ anchors.fill: parent
+ phantom: true
+CheckBoxButton < UICheckBox
+ size: 106 23
+ image-source: /images/ui/button-9grid-idle
+ image-border: 3
+ text-align: center
+ padding: 5 10 5 10
+ change-cursor-image: true
+ cursor: pointer
+ color: #BDBDBD
+ $checked:
+ image-source: /images/ui/button-9grid-pressed
+ text-offset: 1 1
+ $!checked:
+ text-offset: 0 0
+ $disabled:
+ color: #dfdfdf88
+ opacity: 0.8
+ change-cursor-image: false
+BorderBox < UIWidget
+ border-width-top: 1
+ border-color-top: black
+ border-width-left: 1
+ border-color-left: black
+ border-width-bottom: 1
+ border-color-bottom: #747474
+ border-width-right: 1
+ border-color-right: #747474
+SubPanel < UIWidget
+ image-source: /images/ui/outfits/minipanel
+ image-border: 3
+ image-border-top: 22
+ color: #929292
+ text-offset: 0 3
+ text-align: top
+ItemCategory < UIWidget
+ color: #C0C0C0
+ text-align: left
+ @onCheckChange: modules.game_cyclopedia.Cyclopedia.onCategoryChange(self)
+ $checked:
+ color: #F6F6F6
+ItemsListBaseItem < UIWidget
+ UIWidget
+ size: 32 32
+ id: ItemBackground
+ anchors.left: parent.left
+ anchors.verticalCenter: parent.verticalCenter
+ image-source: /images/ui/item
+ margin-left: 1
+ UIWidget
+ id: Rarity
+ anchors.fill: ItemBackground
+ UIItem
+ id: Sprite
+ anchors.fill: ItemBackground
+ Label
+ id: Name
+ anchors.left: ItemBackground.right
+ anchors.verticalCenter: ItemBackground.verticalCenter
+ margin-left: 5
+ text-auto-resize: true
+ !text: tr('Item Name')
+ color: #C0C0C0
+ItemBasicDetail < UIWidget
+ UIWidget
+ id: background
+ anchors.fill: parent
+ UIWidget
+ id: separator
+ anchors.centerIn: parent
+ margin-right: 40
+ text: :
+ text-auto-resize: true
+ color: #BDBDBD
+ Label
+ id: name
+ anchors.right: separator.left
+ anchors.verticalCenter: parent.verticalCenter
+ margin-right: 3
+ !text: tr('Name')
+ text-auto-resize: true
+ color: #BDBDBD
+ Label
+ id: value
+ anchors.left: separator.right
+ anchors.verticalCenter: parent.verticalCenter
+ margin-left: 10
+ !text: tr('0')
+ text-auto-resize: true
+ color: #BDBDBD
+CharmItem < UICheckBox
+ !text: tr('Title')
+ image-source: /images/ui/outfits/minipanel
+ image-border: 3
+ image-border-top: 22
+ color: #929292
+ text-offset: 0 3
+ text-align: top
+ border: 0 white
+ @onClick: modules.game_cyclopedia.Cyclopedia.selectCharm(self, self:isChecked())
+ $checked:
+ border: 2 white
+ $!checked:
+ border: 0 white
+ BorderBox
+ id: InfoBase
+ anchors.bottom: parent.bottom
+ anchors.right: parent.right
+ margin-bottom: 5
+ margin-right: 5
+ image-source: /images/ui/panel_flat
+ image-border: 10
+ size: 66 66
+ phantom: true
+ UICreature
+ size: 64 64
+ id: Sprite
+ anchors.centerIn: parent
+ phantom: true
+ UIWidget
+ id: PriceBase
+ size: 73 20
+ anchors.left: parent.left
+ anchors.bottom: InfoBase.bottom
+ margin-left: 8
+ image-source: /images/ui/item
+ image-border: 10
+ phantom: true
+ Label
+ id: Value
+ anchors.centerIn: parent
+ !text: tr('0')
+ text-auto-resize: true
+ margin-right: 3
+ UIWidget
+ id: Charm
+ anchors.left: Value.right
+ anchors.verticalCenter: parent.verticalCenter
+ margin-left: 2
+ image-source: /game_cyclopedia/images/icon_charms
+ UIWidget
+ id: Gold
+ anchors.left: Value.right
+ anchors.verticalCenter: parent.verticalCenter
+ margin-left: 2
+ image-source: /game_cyclopedia/images/icon_gold
+ visible: false
+ BorderBox
+ id: charmBase
+ anchors.bottom: PriceBase.top
+ anchors.horizontalCenter: PriceBase.horizontalCenter
+ margin-bottom: 7
+ image-source: /images/ui/panel_flat
+ image-border: 10
+ size: 37 37
+ phantom: true
+ UIWidget
+ size: 32 32
+ id: image
+ anchors.centerIn: parent
+ phantom: true
+ UIWidget
+ id: lockedMask
+ size: 35 35
+ anchors.centerIn: parent
+ image-source: /images/ui/ditherpattern
+ phantom: true
+MarkListItem < ButtonBox
+ icon-size: 11 11
+ icon-offset: 3 3
+CharacterCategoryItem < UIWidget
+ size: 150 22
+ image-source: /images/game/actionbar/1pixel-down-frame
+ image-border: 5
+ UIWidget
+ id: Button
+ size: 148 20
+ anchors.top: parent.top
+ anchors.left: parent.left
+ margin-left: 1
+ margin-top: 1
+ image-source: /images/ui/button-grey-up
+ image-border: 5
+ opacity: 1.0
+ $pressed:
+ image-source: /images/ui/button-grey-down
+ $checked:
+ image-source: /images/ui/button-grey-down
+ UIWidget
+ id: Icon
+ size: 13 13
+ anchors.left: parent.left
+ anchors.verticalCenter: parent.verticalCenter
+ margin-left: 10
+ phantom: true
+ $checked:
+ margin-left: 11
+ margin-top: 1
+ $!checked:
+ margin-left: 10
+ margin-top: 0
+ Label
+ id: Title
+ anchors.left: Icon.right
+ anchors.verticalCenter: Icon.verticalCenter
+ margin-left: 10
+ text-auto-resize: true
+ !text: tr('General Stats')
+ //font: verdana-bold-8px-antialiased
+ color: #C0C0C0
+ $checked:
+ text-offset 10 10
+ $!checked:
+ text-offset 0 0
+ UIWidget
+ id: Arrow
+ size: 7 7
+ anchors.right: parent.right
+ anchors.verticalCenter: parent.verticalCenter
+ margin-right: 5
+ phantom: true
+ image-source: images/icon-arrow7x7-down
+ visible: false
+BestiaryCategory < UIWidget
+ image-source: /images/ui/outfits/minipanel
+ image-border: 20
+ !text: tr('Name')
+ text-align: top
+ text-offset: 0 4
+ color: #909090
+ UIWidget
+ id: ClassBase
+ anchors.top: parent.top
+ anchors.horizontalCenter: parent.horizontalCenter
+ margin-top: 22
+ size: 64 64
+ image-source: /images/ui/2pixel_up_frame_borderimage
+ image-border: 10
+ $pressed:
+ image-source: /images/ui/2pixel_up_frame_borderimage_dark_reversed
+ UIWidget
+ id: ClassIcon
+ anchors.centerIn: ClassBase
+ phantom: true
+ Label
+ id: KnownValue
+ anchors.bottom: parent.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+ margin-bottom: 5
+ !text: tr('Known: ') .. '00'
+ color: #C2C2C2
+ Label
+ id: TotalValue
+ anchors.bottom: KnownValue.top
+ anchors.horizontalCenter: parent.horizontalCenter
+ margin-bottom: 0
+ !text: tr('Total: ') .. '00'
+ color: #C2C2C2
+BosstiaryItem < UIWidget
+ image-source: /images/ui/outfits/minipanel
+ image-border: 20
+ !text: tr('?')
+ text-align: top
+ text-offset: 0 4
+ color: #919191
+ UIWidget
+ id: TypeIcon
+ anchors.left: parent.left
+ anchors.top: parent.top
+ margin-left: 7
+ margin-top: 22
+ image-source: images/boss/icon_bane
+ ProgressBackground
+ id: ProgressBorder2
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottom: parent.bottom
+ margin-bottom: 20
+ size: 47 14
+ ProgressBackground
+ id: ProgressBorder1
+ anchors.right: ProgressBorder2.left
+ anchors.bottom: ProgressBorder2.bottom
+ margin-right: 2
+ size: 47 14
+ ProgressBackground
+ id: ProgressBorder3
+ anchors.left: ProgressBorder2.right
+ anchors.bottom: ProgressBorder2.bottom
+ margin-left: 2
+ size: 47 14
+ UIWidget
+ id: ProgressBack
+ anchors.left: ProgressBorder1.left
+ anchors.bottom: ProgressBorder2.bottom
+ height: 12
+ phantom: true
+ image-source: /game_cyclopedia/images/bestiary/fill
+ UIWidget
+ id: ProgressBack33
+ anchors.left: ProgressBorder2.left
+ anchors.bottom: ProgressBorder2.bottom
+ height: 12
+ phantom: true
+ image-source: /game_cyclopedia/images/bestiary/fill
+ UIWidget
+ id: ProgressBack55
+ anchors.left: ProgressBorder3.left
+ anchors.bottom: ProgressBorder2.bottom
+ height: 12
+ phantom: true
+ image-source: /game_cyclopedia/images/bestiary/fill
+ UIWidget
+ anchors.left: ProgressBorder1.right
+ anchors.top: ProgressBorder1.top
+ image-source: /images/ui/progress-separator
+ phantom: true
+ UIWidget
+ anchors.left: ProgressBorder2.right
+ anchors.top: ProgressBorder1.top
+ image-source: /images/ui/progress-separator
+ phantom: true
+ Label
+ id: ProgressValue
+ anchors.centerIn: ProgressBorder2
+ text-auto-resize: true
+ !text: tr('0')
+ UIWidget
+ id: bronzeStar
+ anchors.top: ProgressBorder1.bottom
+ anchors.horizontalCenter: ProgressBorder1.horizontalCenter
+ margin-top: 3
+ image-source: images/boss/icon_star_dark
+ UIWidget
+ id: silverStar
+ anchors.top: ProgressBorder2.bottom
+ anchors.horizontalCenter: ProgressBorder2.horizontalCenter
+ margin-top: 3
+ margin-right: 5
+ image-source: images/boss/icon_star_dark
+ image-repeated: true
+ width: 18
+ UIWidget
+ id: goldStar
+ anchors.top: ProgressBorder3.bottom
+ anchors.horizontalCenter: ProgressBorder3.horizontalCenter
+ margin-top: 3
+ image-source: images/boss/icon_star_dark
+ image-repeated: true
+ width: 27
+ Label
+ id: KillsLabel
+ anchors.left: ProgressBorder1.left
+ anchors.bottom: ProgressBorder1.top
+ margin-bottom: 5
+ !text: tr('Total Kills')
+ text-auto-resize: true
+ color: #C1C1C1
+ CheckBox
+ id: TrackCheck
+ anchors.right: ProgressBorder3.right
+ anchors.bottom: ProgressBorder1.top
+ margin-bottom: 5
+ !text: tr('Track')
+ text-auto-resize: true
+ color: #C1C1C1
+ @onCheckChange: |
+ g_game.sendStatusTrackerBestiary(self:getParent():getId(),self:isChecked())
+ UICreature
+ id: Sprite
+ anchors.bottom: TrackCheck.top
+ anchors.horizontalCenter: parent.horizontalCenter
+ margin-bottom: 5
+ size: 64 64
+BestiaryCreature < UIWidget
+ image-source: /images/ui/outfits/minipanel
+ image-border: 20
+ Label
+ id: Name
+ height: 20
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.right: parent.right
+ margin-left: 2
+ margin-right: 2
+ text-align: center
+ text-offset: 0 3
+ color: #919191
+ UIWidget
+ id: ClassBase
+ anchors.top: parent.top
+ anchors.horizontalCenter: parent.horizontalCenter
+ margin-top: 22
+ size: 64 64
+ image-source: /images/ui/2pixel_up_frame_borderimage
+ image-border: 10
+ $pressed:
+ image-source: /images/ui/2pixel_up_frame_borderimage_dark_reversed
+ UICreature
+ id: Sprite
+ anchors.fill: ClassBase
+ phantom: true
+ UIWidget
+ id: AnimusMastery
+ anchors.top: prev.top
+ anchors.left: prev.left
+ image-source: /game_cyclopedia/images/indicator_soulcore
+ UIWidget
+ id: Finalized
+ image-source: images/checkmark-icon
+ anchors.horizontalCenter: ClassBase.horizontalCenter
+ anchors.top: ClassBase.bottom
+ margin-top: 5
+ visible: false
+ Label
+ id: KillsLabel
+ anchors.horizontalCenter: ClassBase.horizontalCenter
+ anchors.top: ClassBase.bottom
+ margin-top: 5
+ !text: tr('?')
+ text-auto-resize: true
+ color: #C1C1C1
+ UIWidget
+ id: CompleteIcon
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottom: parent.bottom
+ margin-bottom: 15
+ image-source: images/checkmark-icon
+ visible: false
+BestiaryResistProgress < UIWidget
+ image-source: /game_cyclopedia/images/bestiary/barra
+ UIWidget
+ id: Fill
+ anchors.fill: parent
+ background-color: red
+ margin-left: 1
+ margin-bottom: 2
+ margin-top: 2
+ margin-right: 1
+ phantom: true
+ UIWidget
+ id: Border
+ anchors.fill: parent
+ image-source: /game_cyclopedia/images/bestiary/barra
+ phantom: true
+BestiaryItem < UIItem
+ image-source: /images/ui/2pixel_up_frame_borderimage
+ image-border: 10
+ size: 34 34
+ anchors.verticalCenter: parent.verticalCenter
+ padding: 1
+ $checked:
+ image-source: /images/ui/panel_flat
+ $first:
+ anchors.left: parent.left
+ $!first:
+ anchors.left: prev.right
+ margin-left: 2
+ UIWidget
+ id: undefinedItem
+ image-source: /images/ui/undefined_item
+ anchors.fill: parent
+ visible: false
+ Label
+ id: Stackable
+ text-auto-resize: true
+ font: verdana-11px-rounded
+ anchors.bottom: parent.bottom
+ anchors.right: parent.right
+ color: #BFBFBF
+ margin-bottom: -1
+ UIWidget
+ id: Rarity
+ image-border: 5
+ padding: 1
+ anchors.fill: parent
+BestiaryItemGroup < UIWidget
+ height: 45
+ UIWidget
+ id: Items
+ anchors.fill: parent
+ margin-left: 108
+ Label
+ id: Title
+ anchors.left: parent.left
+ anchors.verticalCenter: parent.verticalCenter
+ margin-left: 5
+ !text: tr('Common') .. ':'
+ text-auto-resize: true
+CharmCreatureName < UICheckBox
+ color: #C0C0C0
+ background-color: #484848
+ @onClick: modules.game_cyclopedia.Cyclopedia.selectCreatureCharm(self, self:isChecked())
+ $checked:
+ background-color: #585858
+
+InventoryItemCyclopedia < Item
+HeadSlot < InventoryItemCyclopedia
+ id: slot1
+
+ &position: {x=65535, y=1, z=0}
+
+BodySlot < InventoryItemCyclopedia
+ id: slot4
+
+ &position: {x=65535, y=4, z=0}
+
+LegSlot < InventoryItemCyclopedia
+ id: slot7
+
+ &position: {x=65535, y=7, z=0}
+
+FeetSlot < InventoryItemCyclopedia
+ id: slot8
+
+ &position: {x=65535, y=8, z=0}
+
+NeckSlot < InventoryItemCyclopedia
+ id: slot2
+
+ &position: {x=65535, y=2, z=0}
+
+LeftSlot < InventoryItemCyclopedia
+ id: slot6
+
+ &position: {x=65535, y=6, z=0}
+
+FingerSlot < InventoryItemCyclopedia
+ id: slot9
+
+ &position: {x=65535, y=9, z=0}
+
+BackSlot < InventoryItemCyclopedia
+ id: slot3
+
+ &position: {x=65535, y=3, z=0}
+
+RightSlot < InventoryItemCyclopedia
+ id: slot5
+
+ &position: {x=65535, y=5, z=0}
+
+AmmoSlot < InventoryItemCyclopedia
+ id: slot10
+
+ &position: {x=65535, y=10, z=0}
+
+BackSlot2 < InventoryItemCyclopedia
+ id: slot12
+ image-source: /images/ui/character/secondary_backpack
+ &position: {x=65535, y=12, z=0}
+
+BackSlot3 < InventoryItemCyclopedia
+ id: slot13
+ image-source: /images/ui/character/secondary_backpack
+ &position: {x=65535, y=13, z=0}
+
+BackSlot4 < InventoryItemCyclopedia
+ id: slot14
+
+ &position: {x=65535, y=14, z=0}
+
+BackSlot5 < InventoryItemCyclopedia
+ id: slot15
+
+ &position: {x=65535, y=15, z=0}
+
+ArtifactSlot < InventoryItemCyclopedia
+ id: slot16
+
+ &position: {x=65535, y=16, z=0}
+
+RuneSlot < InventoryItemCyclopedia
+ id: slot18
+
+ &position: {x=65535, y=18, z=0}
+
+RoundCheckBox < CheckBox
+ image-source: /images/ui/outfits/checkbox_round
+
+ $first:
+ margin-top: 2
+
+ $!first:
+ margin-top: 5
+
+TrackerButton < Panel
+ height: 34
+ margin-bottom: 5
+ phantom: false
+ border-width: 1
+ border-color: alpha
+ padding: 1
+
+ $hover:
+ border-color: white
+
+ UICreature
+ id: creature
+ size: 16 16
+ anchors.left: parent.left
+ anchors.top: parent.top
+ phantom: true
+
+ UIWidget
+ id: spacer
+ width: 3
+ anchors.left: creature.right
+ anchors.top: creature.top
+
+ Label
+ id: label
+ anchors.left: spacer.right
+ anchors.top: creature.top
+ text-auto-resize: true
+ color: #888888
+ margin-left: 2
+
+ Label
+ id: kills
+ anchors.right: parent.right
+ anchors.top: creature.top
+ text-align: right
+ text-auto-resize: true
+ color: #888888
+ margin-left: 2
+
+ LifeProgressBar
+ id: killsBar
+ height: 8
+ anchors.left: spacer.right
+ anchors.right: parent.right
+ anchors.top: label.bottom
+ margin-top: 2
+ phantom: true
+ visible: false
+
+ ProgressBackground
+ id: ProgressBorder2
+ anchors.left: spacer.right
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.top: creature.bottom
+ margin-top: 2
+ size: 54 15
+ ProgressBackground
+ id: ProgressBorder1
+ anchors.right: ProgressBorder2.left
+ anchors.top: creature.bottom
+ margin-right: 2
+ margin-top: 2
+ size: 54 15
+ ProgressBackground
+ id: ProgressBorder3
+ anchors.left: ProgressBorder2.right
+ anchors.top: creature.bottom
+ margin-top: 2
+ margin-left: 2
+ size: 54 15
+ UIWidget
+ id: killsBar2
+ anchors.left: ProgressBorder1.left
+ anchors.top: creature.bottom
+ height: 12
+ phantom: true
+ margin-top: 3
+
+ UIWidget
+ id: ProgressBack33
+ anchors.left: ProgressBorder2.left
+ anchors.top: creature.bottom
+ height: 12
+ phantom: true
+ margin-top: 3
+
+ UIWidget
+ id: ProgressBack55
+ anchors.left: ProgressBorder3.left
+ anchors.top: creature.bottom
+ height: 12
+ phantom: true
+ margin-top: 3
+
+
+BestiaryTracker < MiniWindow
+ id: BestiaryTracker
+ !text: tr('Bestiary Tracker')
+ icon: /images/topbuttons/bestiaryTracker
+ icon-offset: 4 2
+ icon-size: 12 12
+ @onClose: modules.game_cyclopedia.Cyclopedia.onTrackerClose(self:getText())
+
+ UIButton
+ id: menuButton
+ anchors.top: prev.top
+ anchors.right: prev.left
+ margin-right: 2
+ size: 14 14
+ image-source: /images/ui/miniwindow_buttons
+ image-clip: 112 0 14 14
+
+ $hover:
+ image-clip: 112 14 14 14
+
+ $pressed:
+ image-clip: 112 28 14 14
+
+ $on:
+ image-clip: 112 0 14 14
+
+ UIButton
+ id: cyclopediaButton
+ anchors.top: prev.top
+ anchors.right: prev.left
+ margin-right: 2
+ size: 14 14
+ image-source: /images/ui/miniwindow_buttons
+ image-clip: 126 0 14 14
+
+ $hover:
+ image-clip: 126 14 14 14
+
+ $pressed:
+ image-clip: 126 28 14 14
+
+ $on:
+ image-clip: 126 0 14 14
+
+ MiniWindowContents
+ id: contentsPanel
+ padding-left: 5
+ padding-right: 5
+ padding-bottom: 3
+ layout: verticalBox
+
+
+bestiaryTrackerMenu < PopupMenu
+ id: imbuementTrackerMenu
+ width: 304
+
+ ImbuementTrackerMenuOption
+ id: sortByName
+ !text: tr('sort by name')
+
+ ImbuementTrackerMenuOption
+ id: ShortByPercentage
+ !text: tr('Short by completion percentage')
+
+ ImbuementTrackerMenuOption
+ id: sortByKills
+ !text: tr('sort by remaining kills')
+
+ HorizontalSeparator
+
+ ImbuementTrackerMenuOption
+ id: sortByAscending
+ !text: tr('sort by ascending')
+
+ ImbuementTrackerMenuOption
+ id: sortByDescending
+ !text: tr('sort by descending')
+StoreFlatPanel < UIWidget
+ phantom: true
+ auto-focus: first
+ image-source: /game_store/images/panel
+ image-border: 3
+Box < UIWidget
+ border-width-top: 1
+ border-color-top: black
+ border-width-left: 1
+ border-color-left: black
+ border-width-bottom: 1
+ border-color-bottom: gray
+ border-width-right: 1
+ border-color-right: gray
+ image-smooth: true
+ image-fixed-ratio: false
+RowStore2 < UIWidget
+ height: 78
+ margin: 2
+ border: 0 white
+
+ $focus:
+ border: 2 white
+
+ Box
+ id: image
+ size: 64 64
+ anchors.top: parent.top
+ anchors.left: parent.left
+ margin: 5 0 0 5
+
+ Label
+ id: lblName
+ anchors.top: parent.top
+ anchors.left: prev.right
+ anchors.right: parent.right
+ margin: 8 0 0 8
+ text-auto-resize: true
+ text-wrap: true
+ Label
+ id: count
+ anchors.bottom: parent.bottom
+ anchors.left: image.right
+ margin: 0 5 5 0
+ margin-left:22
+ text-align: center
+
+ StoreFlatPanel
+ id: lblPrice
+ size: 104 20
+ anchors.bottom: parent.bottom
+ anchors.right: parent.right
+ margin: 0 5 5 0
+ text-align: center
+ text-offset: 15 0
+ image-color: #1111118c
+ icon: images/tibiaCoin
+ icon-align: right
+ icon-offset: -2 0
+
+BlessCreate < UIWidget
+ background-color: alpha
+ text-offset: 35 1
+ focusable: true
+ font: verdana-11px-rounded
+ text-align: left
+
+ Label
+ id: text2
+ anchors.left: parent.left
+ anchors.verticalCenter: parent.verticalCenter
+ width: 15
+ height: 15
+ margin-top: 2
+ margin-left: 3
+
+ Label
+ id: text1
+ margin-left: 8
+ anchors.left: prev.right
+ anchors.verticalCenter: parent.verticalCenter
+ focusable: false
\ No newline at end of file
diff --git a/modules/game_cyclopedia/game_cyclopedia.lua b/modules/game_cyclopedia/game_cyclopedia.lua
new file mode 100644
index 0000000000..43efe44546
--- /dev/null
+++ b/modules/game_cyclopedia/game_cyclopedia.lua
@@ -0,0 +1,295 @@
+Cyclopedia = {}
+
+trackerButton = nil
+trackerMiniWindow = nil
+trackerButtonBosstiary = nil
+trackerMiniWindowBosstiary = nil
+contentContainer = nil
+
+local buttonSelection = nil
+local items = nil
+local bestiary = nil
+local charms = nil
+local map = nil
+local houses = nil
+local character = nil
+local CyclopediaButton = nil
+local bosstiary = nil
+local bossSlot = nil
+local ButtonBossSlot = nil
+local ButtonBestiary = nil
+
+function toggle()
+ if not controllerCyclopedia.ui then
+ return
+ end
+ if controllerCyclopedia.ui:isVisible() then
+ return hide()
+ end
+ show()
+end
+
+controllerCyclopedia = Controller:new()
+controllerCyclopedia:setUI('game_cyclopedia')
+
+function controllerCyclopedia:onInit()
+
+end
+
+function controllerCyclopedia:onGameStart()
+ if g_game.getClientVersion() >= 1332 then
+ CyclopediaButton = modules.game_mainpanel.addToggleButton('CyclopediaButton', tr('Cyclopedia'),
+ '/images/options/cooldowns', toggle, false, 7)
+ ButtonBossSlot = modules.game_mainpanel.addToggleButton("bossSlot", tr("Open Boss Slots dialog"),
+ "/images/options/ButtonBossSlot", getBossSlot, false, 20)
+ CyclopediaButton:setOn(false)
+ ButtonBestiary = modules.game_mainpanel.addToggleButton("bosstiary", tr("Open Bosstiary dialog"),
+ "/images/options/ButtonBosstiary", getBosstiary, false, 17)
+
+ contentContainer = controllerCyclopedia.ui:recursiveGetChildById('contentContainer')
+ buttonSelection = controllerCyclopedia.ui:recursiveGetChildById('buttonSelection')
+ items = buttonSelection:recursiveGetChildById('items')
+ bestiary = buttonSelection:recursiveGetChildById('bestiary')
+ charms = buttonSelection:recursiveGetChildById('charms')
+ map = buttonSelection:recursiveGetChildById('map')
+ houses = buttonSelection:recursiveGetChildById('houses')
+ character = buttonSelection:recursiveGetChildById('character')
+ bosstiary = buttonSelection:recursiveGetChildById('bosstiary')
+ bossSlot = buttonSelection:recursiveGetChildById('bossSlot')
+
+ g_ui.importStyle("cyclopedia_widgets")
+ g_ui.importStyle("cyclopedia_pages")
+
+ controllerCyclopedia:registerEvents(g_game, {
+ -- bestiary
+ onParseBestiaryRaces = Cyclopedia.LoadBestiaryCategories,
+ onParseBestiaryOverview = Cyclopedia.onParseBestiaryOverview,
+ onUpdateBestiaryMonsterData = Cyclopedia.loadBestiarySelectedCreature,
+ -- bosstiary // bestiary
+ onParseCyclopediaTracker = Cyclopedia.onParseCyclopediaTracker,
+ -- bosstiary
+ onParseSendBosstiary = Cyclopedia.LoadBoostiaryCreatures,
+ -- boss_slot
+ onParseBosstiarySlots = Cyclopedia.loadBossSlots,
+ -- character
+ onParseCyclopediaCharacterGeneralStats = Cyclopedia.loadCharacterGeneralStats,
+ onParseCyclopediaCharacterCombatStats = Cyclopedia.loadCharacterCombatStats,
+ onParseCyclopediaCharacterBadges = Cyclopedia.loadCharacterBadges,
+ onCyclopediaCharacterRecentDeaths = Cyclopedia.loadCharacterRecentDeaths,
+ onCyclopediaCharacterRecentKills = Cyclopedia.loadCharacterRecentKills,
+ onUpdateCyclopediaCharacterItemSummary = Cyclopedia.loadCharacterItems,
+ onParseCyclopediaCharacterAppearances = Cyclopedia.loadCharacterAppearances,
+ onParseCyclopediaStoreSummary = Cyclopedia.onParseCyclopediaStoreSummary,
+ -- charms
+ onUpdateBestiaryCharmsData = Cyclopedia.loadCharms,
+ -- items
+ onParseItemDetail = Cyclopedia.onParseItemDetail
+ })
+
+ --[[===================================================
+ = Tracker Bestiary =
+ =================================================== ]] --
+
+ trackerButton = modules.game_mainpanel.addToggleButton("trackerButton", tr("Bestiary Tracker"),
+ "/images/options/bestiaryTracker", Cyclopedia.toggleBestiaryTracker, false, 17)
+
+ trackerButton:setOn(false)
+ trackerMiniWindow = g_ui.createWidget('BestiaryTracker', modules.game_interface.getRightPanel())
+
+ trackerMiniWindow.menuButton.onClick = function(widget, mousePos, mouseButton)
+ local menu = g_ui.createWidget('bestiaryTrackerMenu')
+ menu:setGameMenu(true)
+ local shortCreature = UIRadioGroup.create()
+ local shortAlphabets = UIRadioGroup.create()
+
+ for i, choice in ipairs(menu:getChildren()) do
+ if i >= 1 and i <= 3 then
+ shortCreature:addWidget(choice)
+ elseif i == 5 or i == 6 then
+ shortAlphabets:addWidget(choice)
+ end
+ end
+
+ menu:display(mousePos)
+ return true
+ end
+
+ trackerMiniWindow.cyclopediaButton.onClick = function(widget, mousePos, mouseButton)
+ toggle()
+ SelectWindow("bestiary")
+ return true
+ end
+
+ trackerMiniWindow:moveChildToIndex(trackerMiniWindow.menuButton, 4)
+ trackerMiniWindow:moveChildToIndex(trackerMiniWindow.cyclopediaButton, 5)
+ trackerMiniWindow:setup()
+ trackerMiniWindow:hide()
+
+ --[[===================================================
+ = Tracker Bosstiary =
+ =================================================== ]] --
+
+ trackerButtonBosstiary = modules.game_mainpanel.addToggleButton("bosstiarytrackerButton",
+ tr("bosstiary Tracker"), "/images/options/bosstiaryTracker", Cyclopedia.toggleBosstiaryTracker, false, 17)
+
+ trackerButtonBosstiary:setOn(false)
+ trackerMiniWindowBosstiary = g_ui.createWidget('BestiaryTracker', modules.game_interface.getRightPanel())
+ trackerMiniWindowBosstiary:setText("Boosteary Tracker")
+
+ trackerMiniWindowBosstiary.menuButton.onClick = function(widget, mousePos, mouseButton)
+ local menu = g_ui.createWidget('bestiaryTrackerMenu')
+ menu:setGameMenu(true)
+ local shortCreature = UIRadioGroup.create()
+ local shortAlphabets = UIRadioGroup.create()
+
+ for i, choice in ipairs(menu:getChildren()) do
+ if i >= 1 and i <= 3 then
+ shortCreature:addWidget(choice)
+ elseif i == 5 or i == 6 then
+ shortAlphabets:addWidget(choice)
+ end
+ end
+
+ menu:display(mousePos)
+ return true
+ end
+
+ trackerMiniWindowBosstiary.cyclopediaButton.onClick =
+ function(widget, mousePos, mouseButton)
+ toggle()
+ SelectWindow("bosstiary")
+ return true
+ end
+
+ trackerMiniWindowBosstiary:moveChildToIndex(trackerMiniWindowBosstiary.menuButton, 4)
+ trackerMiniWindowBosstiary:moveChildToIndex(trackerMiniWindowBosstiary.cyclopediaButton, 5)
+ trackerMiniWindowBosstiary:setup()
+ trackerMiniWindowBosstiary:hide()
+ trackerMiniWindow:setupOnStart()
+ loadFilters()
+ Cyclopedia.BossSlots.UnlockBosses = {}
+ end
+
+end
+
+
+function controllerCyclopedia:onGameEnd()
+ if trackerMiniWindow then
+ trackerMiniWindow.contentsPanel:destroyChildren()
+ end
+ hide()
+ saveFilters()
+end
+
+function controllerCyclopedia:onTerminate()
+ if trackerButton then
+ trackerButton:destroy()
+ trackerButton = nil
+ end
+
+ if trackerMiniWindow then
+ trackerMiniWindow:destroy()
+ trackerMiniWindow = nil
+ end
+
+ if trackerButtonBosstiary then
+ trackerButtonBosstiary:destroy()
+ trackerButtonBosstiary = nil
+ end
+
+ if trackerMiniWindowBosstiary then
+ trackerMiniWindowBosstiary:destroy()
+ trackerMiniWindowBosstiary = nil
+ end
+
+ if focusCategoryList then
+ disconnect(focusCategoryList, {
+ onChildFocusChange = function(self, focusedChild)
+ if focusedChild == nil then
+ return
+ end
+ focusedChild:onClick()
+ end
+ })
+ end
+end
+
+function hide()
+ if not controllerCyclopedia.ui then
+ return
+ end
+ controllerCyclopedia.ui:hide()
+ if focusCategoryList then
+ disconnect(focusCategoryList, {
+ onChildFocusChange = function(self, focusedChild)
+ if focusedChild == nil then
+ return
+ end
+ focusedChild:onClick()
+ end
+ })
+ end
+end
+
+function show()
+ if not controllerCyclopedia.ui or not CyclopediaButton then
+ return
+ end
+
+ controllerCyclopedia.ui:show()
+ controllerCyclopedia.ui:raise()
+ controllerCyclopedia.ui:focus()
+ SelectWindow("items")
+ controllerCyclopedia.ui.GoldBase.Value:setText(Cyclopedia.formatGold(g_game.getLocalPlayer():getResourceBalance(1)))
+end
+
+function SelectWindow(type)
+ local windowTypes = {
+ items = { obj = items, func = showItems },
+ bestiary = { obj = bestiary, func = showBestiary },
+ charms = { obj = charms, func = showCharms },
+ map = { obj = map, func = showMap },
+ houses = { obj = houses, func = showHouse },
+ character = { obj = character, func = showCharacter },
+ bosstiary = { obj = bosstiary, func = showBosstiary },
+ bossSlot = { obj = bossSlot, func = showBossSlot }
+ }
+
+ if previousType then
+ previousType.obj:enable()
+ previousType.obj:setOn(false)
+ end
+ contentContainer:destroyChildren()
+
+ local window = windowTypes[type]
+ if window then
+ window.obj:setOn(true)
+ window.obj:disable()
+ previousType = window
+ if window.func then
+ window.func(contentContainer)
+ end
+ end
+end
+
+function getBosstiary()
+ if not controllerCyclopedia.ui then
+ return
+ end
+ if controllerCyclopedia.ui:isVisible() then
+ return hide()
+ end
+ show()
+ SelectWindow("bosstiary")
+end
+
+function getBossSlot()
+ if not controllerCyclopedia.ui then
+ return
+ end
+ if controllerCyclopedia.ui:isVisible() then
+ return hide()
+ end
+ show()
+ SelectWindow("bossSlot")
+end
diff --git a/modules/game_cyclopedia/game_cyclopedia.otmod b/modules/game_cyclopedia/game_cyclopedia.otmod
new file mode 100644
index 0000000000..818fb0abc5
--- /dev/null
+++ b/modules/game_cyclopedia/game_cyclopedia.otmod
@@ -0,0 +1,7 @@
+Module
+ name: game_cyclopedia
+ description: game_cyclopedia
+ scripts: [ game_cyclopedia, Tab/*, utils]
+ sandboxed: true
+ @onLoad: controllerCyclopedia:init()
+ @onUnload: controllerCyclopedia:terminate()
diff --git a/modules/game_cyclopedia/game_cyclopedia.otui b/modules/game_cyclopedia/game_cyclopedia.otui
new file mode 100644
index 0000000000..0fda1e705f
--- /dev/null
+++ b/modules/game_cyclopedia/game_cyclopedia.otui
@@ -0,0 +1,288 @@
+
+MainWindow
+ size: 700 560
+ !text: tr('Cyclopedia')
+ visible: false
+ @onEscape: toggle()
+
+ UIWidget
+ id: buttonSelection
+ anchors.top: parent.top
+ anchors.left: parent.left
+ size: 668 36
+ background-color: #404040
+ border-width-top: 1
+ border-color-top: black
+ border-width-left: 1
+ border-color-left: black
+ border-width-bottom: 1
+ border-color-bottom: #747474
+ border-width-right: 1
+ border-color-right: #747474
+
+ UIButton
+ id: items
+ anchors.top: parent.top
+ anchors.left: parent.left
+ margin-left: 1
+ size: 668 36
+ @onClick: SelectWindow("items")
+
+ $on:
+ size: 150 34
+ image-clip: 0 0 150 34
+ image-source: /images/game/cyclopedia/items_on
+
+ $!on:
+ size: 34 34
+ image-clip: 0 0 34 34
+ image-source: /images/game/cyclopedia/items_off
+
+ $pressed:
+ size: 34 34
+ image-clip: 0 34 34 34
+ image-source: /images/game/cyclopedia/items_off
+
+ UIButton
+ id: bestiary
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 1
+ @onClick: SelectWindow("bestiary")
+
+ $on:
+ size: 150 34
+ image-clip: 0 0 150 34
+ image-source: /images/game/cyclopedia/bestiary_on
+
+ $!on:
+ size: 34 34
+ image-clip: 0 0 34 34
+ image-source: /images/game/cyclopedia/bestiary_off
+
+ $pressed:
+ size: 34 34
+ image-clip: 0 34 34 34
+ image-source: /images/game/cyclopedia/bestiary_off
+
+ UIButton
+ id: charms
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 1
+ @onClick: SelectWindow("charms")
+
+ $on:
+ size: 150 34
+ image-clip: 0 0 150 34
+ image-source: /images/game/cyclopedia/charms_on
+
+ $!on:
+ size: 34 34
+ image-clip: 0 0 34 34
+ image-source: /images/game/cyclopedia/charms_off
+
+ $pressed:
+ size: 34 34
+ image-clip: 0 34 34 34
+ image-source: /images/game/cyclopedia/charms_off
+
+ UIButton
+ id: map
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 1
+ @onClick: SelectWindow("map")
+
+ $on:
+ size: 150 34
+ image-clip: 0 0 150 34
+ image-source: /images/game/cyclopedia/map_on
+
+ $!on:
+ size: 34 34
+ image-clip: 0 0 34 34
+ image-source: /images/game/cyclopedia/map_off
+
+ $pressed:
+ size: 34 34
+ image-clip: 0 34 34 34
+ image-source: /images/game/cyclopedia/map_off
+
+ UIButton
+ id: houses
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 1
+ @onClick: SelectWindow("houses")
+
+ $on:
+ size: 150 34
+ image-clip: 0 0 150 34
+ image-source: /images/game/cyclopedia/houses_on
+
+ $!on:
+ size: 34 34
+ image-clip: 0 0 34 34
+ image-source: /images/game/cyclopedia/houses_off
+
+ $pressed:
+ size: 34 34
+ image-clip: 0 34 34 34
+ image-source: /images/game/cyclopedia/houses_off
+
+ UIButton
+ id: character
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 1
+ @onClick: SelectWindow("character")
+
+ $on:
+ size: 150 34
+ image-clip: 0 0 150 34
+ image-source: /images/game/cyclopedia/character_on
+
+ $!on:
+ size: 34 34
+ image-clip: 0 0 34 34
+ image-source: /images/game/cyclopedia/character_off
+
+ $pressed:
+ size: 34 34
+ image-clip: 0 34 34 34
+ image-source: /images/game/cyclopedia/character_off
+
+ UIButton
+ id: bosstiary
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 1
+ @onClick: SelectWindow("bosstiary")
+
+ $on:
+ size: 150 34
+ image-clip: 0 0 150 34
+ image-source: /images/game/cyclopedia/bosstiary_on
+
+ $!on:
+ size: 34 34
+ image-clip: 0 0 34 34
+ image-source: /images/game/cyclopedia/bosstiary_off
+
+ $pressed:
+ size: 34 34
+ image-clip: 0 34 34 34
+ image-source: /images/game/cyclopedia/bosstiary_off
+
+ UIButton
+ id: bossSlot
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 1
+ @onClick: SelectWindow("bossSlot")
+
+ $on:
+ size: 150 34
+ image-clip: 0 0 150 34
+ image-source: /images/game/cyclopedia/bossSlot_on
+
+ $!on:
+ size: 34 34
+ image-clip: 0 0 34 34
+ image-source: /images/game/cyclopedia/bossSlot_off
+
+ $pressed:
+ size: 34 34
+ image-clip: 0 34 34 34
+ image-source: /images/game/cyclopedia/bossSlot_off
+
+ UIWidget
+ id: contentContainer
+ anchors.top: prev.bottom
+ anchors.bottom: parent.bottom
+ anchors.left: parent.left
+ anchors.right: parent.right
+ margin-top: 5
+
+
+ Button
+ id: CloseButton
+ size: 40 20
+ anchors.bottom: parent.bottom
+ anchors.right: parent.right
+ !text: tr('Close')
+ //font: verdana-bold-8px-antialiased
+ text-offset: 0 -1
+ color: #C0C0C0
+ @onClick: toggle()
+ Button
+ id: BackButton
+ size: 40 20
+ anchors.bottom: parent.bottom
+ anchors.right: CloseButton.left
+ margin-right: 10
+ !text: tr('Back')
+ //font: verdana-bold-8px-antialiased
+ text-offset: 0 -1
+ color: #C0C0C0
+ HorizontalSeparator
+ id: BottomSep
+ anchors.bottom: CloseButton.top
+ anchors.left: parent.left
+ anchors.right: parent.right
+ margin-bottom: 10
+ UIWidget
+ id: GoldBase
+ anchors.bottom: parent.bottom
+ anchors.left: parent.left
+ image-source: /images/ui/item
+ image-border: 10
+ size: 131 20
+ UIWidget
+ id: Icon
+ anchors.right: parent.right
+ anchors.verticalCenter: parent.verticalCenter
+ margin-right: 4
+ image-source: /game_cyclopedia/images/icon_gold
+ Label
+ id: Value
+ anchors.right: Icon.left
+ anchors.verticalCenter: parent.verticalCenter
+ margin-right: 4
+ !text: tr('0')
+ text-auto-resize: true
+ color: #BDBDBD
+ UIWidget
+ id: CharmsBase
+ anchors.bottom: parent.bottom
+ anchors.left: GoldBase.right
+ margin-left: 5
+ image-source: /images/ui/item
+ image-border: 10
+ size: 100 20
+ UIWidget
+ id: Icon
+ anchors.right: parent.right
+ anchors.verticalCenter: parent.verticalCenter
+ margin-right: 4
+ image-source: /game_cyclopedia/images/icon_charms
+ Label
+ id: Value
+ anchors.right: Icon.left
+ anchors.verticalCenter: parent.verticalCenter
+ margin-right: 4
+ !text: tr('0')
+ text-auto-resize: true
+ color: #BDBDBD
+ Button
+ id: BestiaryTrackerButton
+ size: 90 20
+ anchors.bottom: parent.bottom
+ anchors.left: CharmsBase.right
+ margin-left: 5
+ !text: tr('Bestiary Tracker')
+ font: small-9px
+ @onClick: modules.game_cyclopedia.Cyclopedia.toggleBestiaryTracker()
+ text-offset: 0 -1
+ color: #C0C0C0
\ No newline at end of file
diff --git a/modules/game_cyclopedia/images/Icon_Charms.png b/modules/game_cyclopedia/images/Icon_Charms.png
new file mode 100644
index 0000000000..4be40b529b
Binary files /dev/null and b/modules/game_cyclopedia/images/Icon_Charms.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/armor.png b/modules/game_cyclopedia/images/bestiary/armor.png
new file mode 100644
index 0000000000..9f15c289aa
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/armor.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/barra.png b/modules/game_cyclopedia/images/bestiary/barra.png
new file mode 100644
index 0000000000..cd8c99f6bb
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/barra.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/bestiaryContainer.png b/modules/game_cyclopedia/images/bestiary/bestiaryContainer.png
new file mode 100644
index 0000000000..72876856c8
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/bestiaryContainer.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/bestiaryContainerBorder.png b/modules/game_cyclopedia/images/bestiary/bestiaryContainerBorder.png
new file mode 100644
index 0000000000..1b9925992d
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/bestiaryContainerBorder.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/charm.png b/modules/game_cyclopedia/images/bestiary/charm.png
new file mode 100644
index 0000000000..4210a03776
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/charm.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/creatureCheck.png b/modules/game_cyclopedia/images/bestiary/creatureCheck.png
new file mode 100644
index 0000000000..43aa21a002
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/creatureCheck.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/creatures/-.---.png b/modules/game_cyclopedia/images/bestiary/creatures/-.---.png
new file mode 100644
index 0000000000..f99eefe556
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/creatures/-.---.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/creatures/Construct.png b/modules/game_cyclopedia/images/bestiary/creatures/Construct.png
new file mode 100644
index 0000000000..2519867e3c
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/creatures/Construct.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/creatures/Demon.png b/modules/game_cyclopedia/images/bestiary/creatures/Demon.png
new file mode 100644
index 0000000000..ba3c710baf
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/creatures/Demon.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/creatures/Dragon.png b/modules/game_cyclopedia/images/bestiary/creatures/Dragon.png
new file mode 100644
index 0000000000..aed5fcc058
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/creatures/Dragon.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/creatures/Extra_Dimensional.png b/modules/game_cyclopedia/images/bestiary/creatures/Extra_Dimensional.png
new file mode 100644
index 0000000000..2875528c2e
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/creatures/Extra_Dimensional.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/creatures/Fey.png b/modules/game_cyclopedia/images/bestiary/creatures/Fey.png
new file mode 100644
index 0000000000..7dace79266
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/creatures/Fey.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/creatures/Giant.png b/modules/game_cyclopedia/images/bestiary/creatures/Giant.png
new file mode 100644
index 0000000000..3cb47b7dfa
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/creatures/Giant.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/creatures/Human.png b/modules/game_cyclopedia/images/bestiary/creatures/Human.png
new file mode 100644
index 0000000000..6071e33a49
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/creatures/Human.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/creatures/Humanoid.png b/modules/game_cyclopedia/images/bestiary/creatures/Humanoid.png
new file mode 100644
index 0000000000..e48b82ff09
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/creatures/Humanoid.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/creatures/Lycanthrope.png b/modules/game_cyclopedia/images/bestiary/creatures/Lycanthrope.png
new file mode 100644
index 0000000000..1da895143e
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/creatures/Lycanthrope.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/creatures/Magical.png b/modules/game_cyclopedia/images/bestiary/creatures/Magical.png
new file mode 100644
index 0000000000..211f9b43d6
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/creatures/Magical.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/creatures/Mammal.png b/modules/game_cyclopedia/images/bestiary/creatures/Mammal.png
new file mode 100644
index 0000000000..8e89444377
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/creatures/Mammal.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/creatures/Plant.png b/modules/game_cyclopedia/images/bestiary/creatures/Plant.png
new file mode 100644
index 0000000000..072e61f5f9
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/creatures/Plant.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/creatures/Reptile.png b/modules/game_cyclopedia/images/bestiary/creatures/Reptile.png
new file mode 100644
index 0000000000..11d9ea56a8
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/creatures/Reptile.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/creatures/Slime.png b/modules/game_cyclopedia/images/bestiary/creatures/Slime.png
new file mode 100644
index 0000000000..07660cbfed
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/creatures/Slime.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/creatures/Undead.png b/modules/game_cyclopedia/images/bestiary/creatures/Undead.png
new file mode 100644
index 0000000000..eacd22836f
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/creatures/Undead.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/creatures/Vermin.png b/modules/game_cyclopedia/images/bestiary/creatures/Vermin.png
new file mode 100644
index 0000000000..5d681acd1f
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/creatures/Vermin.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/creatures/amphibic.png b/modules/game_cyclopedia/images/bestiary/creatures/amphibic.png
new file mode 100644
index 0000000000..9b2490f723
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/creatures/amphibic.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/creatures/aquatic.png b/modules/game_cyclopedia/images/bestiary/creatures/aquatic.png
new file mode 100644
index 0000000000..389ae46de6
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/creatures/aquatic.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/creatures/bird.png b/modules/game_cyclopedia/images/bestiary/creatures/bird.png
new file mode 100644
index 0000000000..cf07eabf87
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/creatures/bird.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/creatures/elemental.png b/modules/game_cyclopedia/images/bestiary/creatures/elemental.png
new file mode 100644
index 0000000000..14651ea47f
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/creatures/elemental.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/death.png b/modules/game_cyclopedia/images/bestiary/death.png
new file mode 100644
index 0000000000..c74fc4ea9c
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/death.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/difficulty.png b/modules/game_cyclopedia/images/bestiary/difficulty.png
new file mode 100644
index 0000000000..2679f4de02
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/difficulty.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/difficulty_disabled.png b/modules/game_cyclopedia/images/bestiary/difficulty_disabled.png
new file mode 100644
index 0000000000..fcbc69e7dd
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/difficulty_disabled.png differ
diff --git a/data/images/ui/rarity_gold.png b/modules/game_cyclopedia/images/bestiary/drown.png
similarity index 84%
rename from data/images/ui/rarity_gold.png
rename to modules/game_cyclopedia/images/bestiary/drown.png
index e38503eee7..db783edd56 100644
Binary files a/data/images/ui/rarity_gold.png and b/modules/game_cyclopedia/images/bestiary/drown.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/durability_fill.png b/modules/game_cyclopedia/images/bestiary/durability_fill.png
new file mode 100644
index 0000000000..4db38c4379
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/durability_fill.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/earth.png b/modules/game_cyclopedia/images/bestiary/earth.png
new file mode 100644
index 0000000000..04f1da2935
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/earth.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/elementContainer.png b/modules/game_cyclopedia/images/bestiary/elementContainer.png
new file mode 100644
index 0000000000..cd8c99f6bb
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/elementContainer.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/empty.png b/modules/game_cyclopedia/images/bestiary/empty.png
new file mode 100644
index 0000000000..ccdd660cf9
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/empty.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/energy.png b/modules/game_cyclopedia/images/bestiary/energy.png
new file mode 100644
index 0000000000..9cea5378af
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/energy.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/exp.png b/modules/game_cyclopedia/images/bestiary/exp.png
new file mode 100644
index 0000000000..8434cdbde9
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/exp.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/fill.png b/modules/game_cyclopedia/images/bestiary/fill.png
new file mode 100644
index 0000000000..aa1edd368a
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/fill.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/fill_completed.png b/modules/game_cyclopedia/images/bestiary/fill_completed.png
new file mode 100644
index 0000000000..c78380a5f2
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/fill_completed.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/fire.png b/modules/game_cyclopedia/images/bestiary/fire.png
new file mode 100644
index 0000000000..d798168d4a
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/fire.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/haste.png b/modules/game_cyclopedia/images/bestiary/haste.png
new file mode 100644
index 0000000000..a3f466eaca
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/haste.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/healing.png b/modules/game_cyclopedia/images/bestiary/healing.png
new file mode 100644
index 0000000000..db783edd56
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/healing.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/health.png b/modules/game_cyclopedia/images/bestiary/health.png
new file mode 100644
index 0000000000..4fdcff71a4
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/health.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/holy.png b/modules/game_cyclopedia/images/bestiary/holy.png
new file mode 100644
index 0000000000..937330b7a3
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/holy.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/ice.png b/modules/game_cyclopedia/images/bestiary/ice.png
new file mode 100644
index 0000000000..132482af47
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/ice.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/icons/monster-icon-agony-resist.png b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-agony-resist.png
new file mode 100644
index 0000000000..af60dda82d
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-agony-resist.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/icons/monster-icon-armor.png b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-armor.png
new file mode 100644
index 0000000000..9d3686adf6
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-armor.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/icons/monster-icon-bonuspoints.png b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-bonuspoints.png
new file mode 100644
index 0000000000..416a573313
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-bonuspoints.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/icons/monster-icon-death-resist.png b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-death-resist.png
new file mode 100644
index 0000000000..20b26cf579
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-death-resist.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/icons/monster-icon-diamond-active.png b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-diamond-active.png
new file mode 100644
index 0000000000..49432d3f9b
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-diamond-active.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/icons/monster-icon-diamond-inactive.png b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-diamond-inactive.png
new file mode 100644
index 0000000000..204d1fc311
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-diamond-inactive.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/icons/monster-icon-drowning-resist.png b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-drowning-resist.png
new file mode 100644
index 0000000000..b6bd89e3f3
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-drowning-resist.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/icons/monster-icon-earth-resist.png b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-earth-resist.png
new file mode 100644
index 0000000000..0de184559b
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-earth-resist.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/icons/monster-icon-energy-resist.png b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-energy-resist.png
new file mode 100644
index 0000000000..3ad36cbe2f
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-energy-resist.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/icons/monster-icon-experience.png b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-experience.png
new file mode 100644
index 0000000000..02384a46e2
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-experience.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/icons/monster-icon-fire-resist.png b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-fire-resist.png
new file mode 100644
index 0000000000..ec28ad4263
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-fire-resist.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/icons/monster-icon-healing-resist.png b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-healing-resist.png
new file mode 100644
index 0000000000..7dd24b0c27
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-healing-resist.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/icons/monster-icon-hitpoints.png b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-hitpoints.png
new file mode 100644
index 0000000000..62467e8da3
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-hitpoints.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/icons/monster-icon-holy-resist.png b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-holy-resist.png
new file mode 100644
index 0000000000..cbc65a4055
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-holy-resist.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/icons/monster-icon-ice-resist.png b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-ice-resist.png
new file mode 100644
index 0000000000..645c103678
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-ice-resist.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/icons/monster-icon-lifedrain-resist.png b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-lifedrain-resist.png
new file mode 100644
index 0000000000..8ac0160df0
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-lifedrain-resist.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/icons/monster-icon-manadrain-resist.png b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-manadrain-resist.png
new file mode 100644
index 0000000000..6a630b85d1
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-manadrain-resist.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/icons/monster-icon-melee.png b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-melee.png
new file mode 100644
index 0000000000..b4bbcf89aa
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-melee.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/icons/monster-icon-mitigation.png b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-mitigation.png
new file mode 100644
index 0000000000..161c7d1e08
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-mitigation.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/icons/monster-icon-noattack.png b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-noattack.png
new file mode 100644
index 0000000000..638466fb67
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-noattack.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/icons/monster-icon-physical-resist.png b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-physical-resist.png
new file mode 100644
index 0000000000..d75a003e69
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-physical-resist.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/icons/monster-icon-ranged.png b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-ranged.png
new file mode 100644
index 0000000000..476c78339f
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-ranged.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/icons/monster-icon-speed.png b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-speed.png
new file mode 100644
index 0000000000..f4a75f2459
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-speed.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/icons/monster-icon-spellcaster.png b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-spellcaster.png
new file mode 100644
index 0000000000..aa8ad70034
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/icons/monster-icon-spellcaster.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/lifedrain.png b/modules/game_cyclopedia/images/bestiary/lifedrain.png
new file mode 100644
index 0000000000..db783edd56
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/lifedrain.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/lockedCreature.png b/modules/game_cyclopedia/images/bestiary/lockedCreature.png
new file mode 100644
index 0000000000..2c38c872a4
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/lockedCreature.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/manadrain.png b/modules/game_cyclopedia/images/bestiary/manadrain.png
new file mode 100644
index 0000000000..db783edd56
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/manadrain.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/ocurrence.png b/modules/game_cyclopedia/images/bestiary/ocurrence.png
new file mode 100644
index 0000000000..058a9e93e9
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/ocurrence.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/ocurrence_disabled.png b/modules/game_cyclopedia/images/bestiary/ocurrence_disabled.png
new file mode 100644
index 0000000000..476f74a6e8
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/ocurrence_disabled.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/panel_texture2.png b/modules/game_cyclopedia/images/bestiary/panel_texture2.png
new file mode 100644
index 0000000000..50e4eb270e
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/panel_texture2.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/physical.png b/modules/game_cyclopedia/images/bestiary/physical.png
new file mode 100644
index 0000000000..3416927221
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/physical.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/plus.png b/modules/game_cyclopedia/images/bestiary/plus.png
new file mode 100644
index 0000000000..b72fd894dd
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/plus.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/poison.png b/modules/game_cyclopedia/images/bestiary/poison.png
new file mode 100644
index 0000000000..de6f7c4fee
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/poison.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/progress_bar.png b/modules/game_cyclopedia/images/bestiary/progress_bar.png
new file mode 100644
index 0000000000..96978a8ee0
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/progress_bar.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/undefined_item.png b/modules/game_cyclopedia/images/bestiary/undefined_item.png
new file mode 100644
index 0000000000..8514b74680
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/undefined_item.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/underfined.png b/modules/game_cyclopedia/images/bestiary/underfined.png
new file mode 100644
index 0000000000..db783edd56
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/underfined.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/undiscoveredSlot.png b/modules/game_cyclopedia/images/bestiary/undiscoveredSlot.png
new file mode 100644
index 0000000000..8514b74680
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/undiscoveredSlot.png differ
diff --git a/modules/game_cyclopedia/images/bestiary/window.png b/modules/game_cyclopedia/images/bestiary/window.png
new file mode 100644
index 0000000000..d418dfe6f4
Binary files /dev/null and b/modules/game_cyclopedia/images/bestiary/window.png differ
diff --git a/modules/game_cyclopedia/images/boss/boss_base.png b/modules/game_cyclopedia/images/boss/boss_base.png
new file mode 100644
index 0000000000..756993cc81
Binary files /dev/null and b/modules/game_cyclopedia/images/boss/boss_base.png differ
diff --git a/modules/game_cyclopedia/images/boss/fill.png b/modules/game_cyclopedia/images/boss/fill.png
new file mode 100644
index 0000000000..e5791578d2
Binary files /dev/null and b/modules/game_cyclopedia/images/boss/fill.png differ
diff --git a/modules/game_cyclopedia/images/boss/icon_archfoe.png b/modules/game_cyclopedia/images/boss/icon_archfoe.png
new file mode 100644
index 0000000000..34f8823298
Binary files /dev/null and b/modules/game_cyclopedia/images/boss/icon_archfoe.png differ
diff --git a/modules/game_cyclopedia/images/boss/icon_bane.png b/modules/game_cyclopedia/images/boss/icon_bane.png
new file mode 100644
index 0000000000..aeac6ebc8c
Binary files /dev/null and b/modules/game_cyclopedia/images/boss/icon_bane.png differ
diff --git a/modules/game_cyclopedia/images/boss/icon_nemesis.png b/modules/game_cyclopedia/images/boss/icon_nemesis.png
new file mode 100644
index 0000000000..ae83d1ee19
Binary files /dev/null and b/modules/game_cyclopedia/images/boss/icon_nemesis.png differ
diff --git a/modules/game_cyclopedia/images/boss/icon_star.png b/modules/game_cyclopedia/images/boss/icon_star.png
new file mode 100644
index 0000000000..bd37936872
Binary files /dev/null and b/modules/game_cyclopedia/images/boss/icon_star.png differ
diff --git a/modules/game_cyclopedia/images/boss/icon_star_active.png b/modules/game_cyclopedia/images/boss/icon_star_active.png
new file mode 100644
index 0000000000..ef30ccc64f
Binary files /dev/null and b/modules/game_cyclopedia/images/boss/icon_star_active.png differ
diff --git a/modules/game_cyclopedia/images/boss/icon_star_bronze.png b/modules/game_cyclopedia/images/boss/icon_star_bronze.png
new file mode 100644
index 0000000000..411849143a
Binary files /dev/null and b/modules/game_cyclopedia/images/boss/icon_star_bronze.png differ
diff --git a/modules/game_cyclopedia/images/boss/icon_star_dark.png b/modules/game_cyclopedia/images/boss/icon_star_dark.png
new file mode 100644
index 0000000000..9d68b0d4ad
Binary files /dev/null and b/modules/game_cyclopedia/images/boss/icon_star_dark.png differ
diff --git a/modules/game_cyclopedia/images/boss/icon_star_gold.png b/modules/game_cyclopedia/images/boss/icon_star_gold.png
new file mode 100644
index 0000000000..ef30ccc64f
Binary files /dev/null and b/modules/game_cyclopedia/images/boss/icon_star_gold.png differ
diff --git a/modules/game_cyclopedia/images/boss/icon_star_inactive.png b/modules/game_cyclopedia/images/boss/icon_star_inactive.png
new file mode 100644
index 0000000000..326547d265
Binary files /dev/null and b/modules/game_cyclopedia/images/boss/icon_star_inactive.png differ
diff --git a/modules/game_cyclopedia/images/boss/icon_star_silver.png b/modules/game_cyclopedia/images/boss/icon_star_silver.png
new file mode 100644
index 0000000000..f8aa9e51b2
Binary files /dev/null and b/modules/game_cyclopedia/images/boss/icon_star_silver.png differ
diff --git a/modules/game_cyclopedia/images/button_back.png b/modules/game_cyclopedia/images/button_back.png
new file mode 100644
index 0000000000..12f86bb352
Binary files /dev/null and b/modules/game_cyclopedia/images/button_back.png differ
diff --git a/modules/game_cyclopedia/images/button_back_disabled.png b/modules/game_cyclopedia/images/button_back_disabled.png
new file mode 100644
index 0000000000..775b25ce6a
Binary files /dev/null and b/modules/game_cyclopedia/images/button_back_disabled.png differ
diff --git a/modules/game_cyclopedia/images/button_back_pressed.png b/modules/game_cyclopedia/images/button_back_pressed.png
new file mode 100644
index 0000000000..88ee7e2308
Binary files /dev/null and b/modules/game_cyclopedia/images/button_back_pressed.png differ
diff --git a/modules/game_cyclopedia/images/button_clear_search.png b/modules/game_cyclopedia/images/button_clear_search.png
new file mode 100644
index 0000000000..abdc2240e6
Binary files /dev/null and b/modules/game_cyclopedia/images/button_clear_search.png differ
diff --git a/modules/game_cyclopedia/images/button_store.png b/modules/game_cyclopedia/images/button_store.png
new file mode 100644
index 0000000000..28411d8734
Binary files /dev/null and b/modules/game_cyclopedia/images/button_store.png differ
diff --git a/modules/game_cyclopedia/images/button_wheel.png b/modules/game_cyclopedia/images/button_wheel.png
new file mode 100644
index 0000000000..10958a082b
Binary files /dev/null and b/modules/game_cyclopedia/images/button_wheel.png differ
diff --git a/modules/game_cyclopedia/images/character_icons/friend-badge-icons.png b/modules/game_cyclopedia/images/character_icons/friend-badge-icons.png
new file mode 100644
index 0000000000..df98940767
Binary files /dev/null and b/modules/game_cyclopedia/images/character_icons/friend-badge-icons.png differ
diff --git a/modules/game_cyclopedia/images/character_icons/icon-character-battleresults-recentdeaths.png b/modules/game_cyclopedia/images/character_icons/icon-character-battleresults-recentdeaths.png
new file mode 100644
index 0000000000..64595ac6a7
Binary files /dev/null and b/modules/game_cyclopedia/images/character_icons/icon-character-battleresults-recentdeaths.png differ
diff --git a/modules/game_cyclopedia/images/character_icons/icon-character-battleresults-recentpvpkills.png b/modules/game_cyclopedia/images/character_icons/icon-character-battleresults-recentpvpkills.png
new file mode 100644
index 0000000000..e3626c5def
Binary files /dev/null and b/modules/game_cyclopedia/images/character_icons/icon-character-battleresults-recentpvpkills.png differ
diff --git a/modules/game_cyclopedia/images/character_icons/icon-character-battleresults.png b/modules/game_cyclopedia/images/character_icons/icon-character-battleresults.png
new file mode 100644
index 0000000000..ade94fe938
Binary files /dev/null and b/modules/game_cyclopedia/images/character_icons/icon-character-battleresults.png differ
diff --git a/modules/game_cyclopedia/images/character_icons/icon-character-generalstats-combatstats.png b/modules/game_cyclopedia/images/character_icons/icon-character-generalstats-combatstats.png
new file mode 100644
index 0000000000..a23b899ada
Binary files /dev/null and b/modules/game_cyclopedia/images/character_icons/icon-character-generalstats-combatstats.png differ
diff --git a/modules/game_cyclopedia/images/character_icons/icon-character-generalstats-overview.png b/modules/game_cyclopedia/images/character_icons/icon-character-generalstats-overview.png
new file mode 100644
index 0000000000..c14414a21a
Binary files /dev/null and b/modules/game_cyclopedia/images/character_icons/icon-character-generalstats-overview.png differ
diff --git a/modules/game_cyclopedia/images/character_icons/icon-character-store.png b/modules/game_cyclopedia/images/character_icons/icon-character-store.png
new file mode 100644
index 0000000000..e0279bea6b
Binary files /dev/null and b/modules/game_cyclopedia/images/character_icons/icon-character-store.png differ
diff --git a/modules/game_cyclopedia/images/character_icons/icon-character-titles.png b/modules/game_cyclopedia/images/character_icons/icon-character-titles.png
new file mode 100644
index 0000000000..2dd5dc980b
Binary files /dev/null and b/modules/game_cyclopedia/images/character_icons/icon-character-titles.png differ
diff --git a/modules/game_cyclopedia/images/character_icons/icon-charactertrade.png b/modules/game_cyclopedia/images/character_icons/icon-charactertrade.png
new file mode 100644
index 0000000000..50ab405a01
Binary files /dev/null and b/modules/game_cyclopedia/images/character_icons/icon-charactertrade.png differ
diff --git a/modules/game_cyclopedia/images/character_icons/icon_achievement.png b/modules/game_cyclopedia/images/character_icons/icon_achievement.png
new file mode 100644
index 0000000000..5f3eeba1b4
Binary files /dev/null and b/modules/game_cyclopedia/images/character_icons/icon_achievement.png differ
diff --git a/modules/game_cyclopedia/images/character_icons/icon_battleresults.png b/modules/game_cyclopedia/images/character_icons/icon_battleresults.png
new file mode 100644
index 0000000000..64595ac6a7
Binary files /dev/null and b/modules/game_cyclopedia/images/character_icons/icon_battleresults.png differ
diff --git a/modules/game_cyclopedia/images/character_icons/icon_generalstats.png b/modules/game_cyclopedia/images/character_icons/icon_generalstats.png
new file mode 100644
index 0000000000..73b56a6d0c
Binary files /dev/null and b/modules/game_cyclopedia/images/character_icons/icon_generalstats.png differ
diff --git a/modules/game_cyclopedia/images/character_icons/icon_items.png b/modules/game_cyclopedia/images/character_icons/icon_items.png
new file mode 100644
index 0000000000..1f510415da
Binary files /dev/null and b/modules/game_cyclopedia/images/character_icons/icon_items.png differ
diff --git a/modules/game_cyclopedia/images/character_icons/icon_outfitsmounts.png b/modules/game_cyclopedia/images/character_icons/icon_outfitsmounts.png
new file mode 100644
index 0000000000..3dee4e1216
Binary files /dev/null and b/modules/game_cyclopedia/images/character_icons/icon_outfitsmounts.png differ
diff --git a/modules/game_cyclopedia/images/charms/0.png b/modules/game_cyclopedia/images/charms/0.png
new file mode 100644
index 0000000000..e24c2c2b53
Binary files /dev/null and b/modules/game_cyclopedia/images/charms/0.png differ
diff --git a/modules/game_cyclopedia/images/charms/1.png b/modules/game_cyclopedia/images/charms/1.png
new file mode 100644
index 0000000000..942be1e978
Binary files /dev/null and b/modules/game_cyclopedia/images/charms/1.png differ
diff --git a/modules/game_cyclopedia/images/charms/10.png b/modules/game_cyclopedia/images/charms/10.png
new file mode 100644
index 0000000000..7f0e3f4896
Binary files /dev/null and b/modules/game_cyclopedia/images/charms/10.png differ
diff --git a/modules/game_cyclopedia/images/charms/11.png b/modules/game_cyclopedia/images/charms/11.png
new file mode 100644
index 0000000000..1355863cc9
Binary files /dev/null and b/modules/game_cyclopedia/images/charms/11.png differ
diff --git a/modules/game_cyclopedia/images/charms/12.png b/modules/game_cyclopedia/images/charms/12.png
new file mode 100644
index 0000000000..66b2dc50df
Binary files /dev/null and b/modules/game_cyclopedia/images/charms/12.png differ
diff --git a/modules/game_cyclopedia/images/charms/13.png b/modules/game_cyclopedia/images/charms/13.png
new file mode 100644
index 0000000000..aecba95ad1
Binary files /dev/null and b/modules/game_cyclopedia/images/charms/13.png differ
diff --git a/modules/game_cyclopedia/images/charms/14.png b/modules/game_cyclopedia/images/charms/14.png
new file mode 100644
index 0000000000..2ab52539e0
Binary files /dev/null and b/modules/game_cyclopedia/images/charms/14.png differ
diff --git a/modules/game_cyclopedia/images/charms/15.png b/modules/game_cyclopedia/images/charms/15.png
new file mode 100644
index 0000000000..b08a03dd08
Binary files /dev/null and b/modules/game_cyclopedia/images/charms/15.png differ
diff --git a/modules/game_cyclopedia/images/charms/16.png b/modules/game_cyclopedia/images/charms/16.png
new file mode 100644
index 0000000000..a6ccdd6741
Binary files /dev/null and b/modules/game_cyclopedia/images/charms/16.png differ
diff --git a/modules/game_cyclopedia/images/charms/17.png b/modules/game_cyclopedia/images/charms/17.png
new file mode 100644
index 0000000000..f1dc200331
Binary files /dev/null and b/modules/game_cyclopedia/images/charms/17.png differ
diff --git a/modules/game_cyclopedia/images/charms/18.png b/modules/game_cyclopedia/images/charms/18.png
new file mode 100644
index 0000000000..6f00013b2e
Binary files /dev/null and b/modules/game_cyclopedia/images/charms/18.png differ
diff --git a/modules/game_cyclopedia/images/charms/19.png b/modules/game_cyclopedia/images/charms/19.png
new file mode 100644
index 0000000000..6f00013b2e
Binary files /dev/null and b/modules/game_cyclopedia/images/charms/19.png differ
diff --git a/modules/game_cyclopedia/images/charms/2.png b/modules/game_cyclopedia/images/charms/2.png
new file mode 100644
index 0000000000..511c801f70
Binary files /dev/null and b/modules/game_cyclopedia/images/charms/2.png differ
diff --git a/modules/game_cyclopedia/images/charms/3.png b/modules/game_cyclopedia/images/charms/3.png
new file mode 100644
index 0000000000..2d22ff3ee2
Binary files /dev/null and b/modules/game_cyclopedia/images/charms/3.png differ
diff --git a/modules/game_cyclopedia/images/charms/4.png b/modules/game_cyclopedia/images/charms/4.png
new file mode 100644
index 0000000000..e188f84266
Binary files /dev/null and b/modules/game_cyclopedia/images/charms/4.png differ
diff --git a/modules/game_cyclopedia/images/charms/5.png b/modules/game_cyclopedia/images/charms/5.png
new file mode 100644
index 0000000000..f054aac439
Binary files /dev/null and b/modules/game_cyclopedia/images/charms/5.png differ
diff --git a/modules/game_cyclopedia/images/charms/6.png b/modules/game_cyclopedia/images/charms/6.png
new file mode 100644
index 0000000000..2b5d649be2
Binary files /dev/null and b/modules/game_cyclopedia/images/charms/6.png differ
diff --git a/modules/game_cyclopedia/images/charms/7.png b/modules/game_cyclopedia/images/charms/7.png
new file mode 100644
index 0000000000..3be5f38fde
Binary files /dev/null and b/modules/game_cyclopedia/images/charms/7.png differ
diff --git a/modules/game_cyclopedia/images/charms/8.png b/modules/game_cyclopedia/images/charms/8.png
new file mode 100644
index 0000000000..d5f32bcece
Binary files /dev/null and b/modules/game_cyclopedia/images/charms/8.png differ
diff --git a/modules/game_cyclopedia/images/charms/9.png b/modules/game_cyclopedia/images/charms/9.png
new file mode 100644
index 0000000000..9d57bcb226
Binary files /dev/null and b/modules/game_cyclopedia/images/charms/9.png differ
diff --git a/modules/game_cyclopedia/images/checkmark-icon.png b/modules/game_cyclopedia/images/checkmark-icon.png
new file mode 100644
index 0000000000..43aa21a002
Binary files /dev/null and b/modules/game_cyclopedia/images/checkmark-icon.png differ
diff --git a/modules/game_cyclopedia/images/houses/1001.png b/modules/game_cyclopedia/images/houses/1001.png
new file mode 100644
index 0000000000..76aed291e1
Binary files /dev/null and b/modules/game_cyclopedia/images/houses/1001.png differ
diff --git a/modules/game_cyclopedia/images/houses/1002.png b/modules/game_cyclopedia/images/houses/1002.png
new file mode 100644
index 0000000000..13da1817c6
Binary files /dev/null and b/modules/game_cyclopedia/images/houses/1002.png differ
diff --git a/modules/game_cyclopedia/images/icon-achievement.png b/modules/game_cyclopedia/images/icon-achievement.png
new file mode 100644
index 0000000000..4e01ed9c00
Binary files /dev/null and b/modules/game_cyclopedia/images/icon-achievement.png differ
diff --git a/modules/game_cyclopedia/images/icon-arrow7x7-down.png b/modules/game_cyclopedia/images/icon-arrow7x7-down.png
new file mode 100644
index 0000000000..859cec5175
Binary files /dev/null and b/modules/game_cyclopedia/images/icon-arrow7x7-down.png differ
diff --git a/modules/game_cyclopedia/images/icon-arrow7x7-right.png b/modules/game_cyclopedia/images/icon-arrow7x7-right.png
new file mode 100644
index 0000000000..4238a43ccb
Binary files /dev/null and b/modules/game_cyclopedia/images/icon-arrow7x7-right.png differ
diff --git a/modules/game_cyclopedia/images/icon-downarrow-disabled.png b/modules/game_cyclopedia/images/icon-downarrow-disabled.png
new file mode 100644
index 0000000000..cb1b7c2f72
Binary files /dev/null and b/modules/game_cyclopedia/images/icon-downarrow-disabled.png differ
diff --git a/modules/game_cyclopedia/images/icon-equipmentdetails.png b/modules/game_cyclopedia/images/icon-equipmentdetails.png
new file mode 100644
index 0000000000..63e260ac04
Binary files /dev/null and b/modules/game_cyclopedia/images/icon-equipmentdetails.png differ
diff --git a/modules/game_cyclopedia/images/icon-goldcoin.png b/modules/game_cyclopedia/images/icon-goldcoin.png
new file mode 100644
index 0000000000..39fca159f1
Binary files /dev/null and b/modules/game_cyclopedia/images/icon-goldcoin.png differ
diff --git a/modules/game_cyclopedia/images/icon-left-arrow-disabled.png b/modules/game_cyclopedia/images/icon-left-arrow-disabled.png
new file mode 100644
index 0000000000..d581aebeed
Binary files /dev/null and b/modules/game_cyclopedia/images/icon-left-arrow-disabled.png differ
diff --git a/modules/game_cyclopedia/images/icon-left-arrow.png b/modules/game_cyclopedia/images/icon-left-arrow.png
new file mode 100644
index 0000000000..2b467e4fc2
Binary files /dev/null and b/modules/game_cyclopedia/images/icon-left-arrow.png differ
diff --git a/modules/game_cyclopedia/images/icon-map-house-status.png b/modules/game_cyclopedia/images/icon-map-house-status.png
new file mode 100644
index 0000000000..8e22dbe31a
Binary files /dev/null and b/modules/game_cyclopedia/images/icon-map-house-status.png differ
diff --git a/modules/game_cyclopedia/images/icon-map-house.png b/modules/game_cyclopedia/images/icon-map-house.png
new file mode 100644
index 0000000000..00b702c662
Binary files /dev/null and b/modules/game_cyclopedia/images/icon-map-house.png differ
diff --git a/modules/game_cyclopedia/images/icon-map-improvedrespawn.png b/modules/game_cyclopedia/images/icon-map-improvedrespawn.png
new file mode 100644
index 0000000000..ad7a6a6dac
Binary files /dev/null and b/modules/game_cyclopedia/images/icon-map-improvedrespawn.png differ
diff --git a/modules/game_cyclopedia/images/icon-map-npc.png b/modules/game_cyclopedia/images/icon-map-npc.png
new file mode 100644
index 0000000000..f260f7f297
Binary files /dev/null and b/modules/game_cyclopedia/images/icon-map-npc.png differ
diff --git a/modules/game_cyclopedia/images/icon-map-passage-idle.png b/modules/game_cyclopedia/images/icon-map-passage-idle.png
new file mode 100644
index 0000000000..ae08323f73
Binary files /dev/null and b/modules/game_cyclopedia/images/icon-map-passage-idle.png differ
diff --git a/modules/game_cyclopedia/images/icon-map-passage-selected.png b/modules/game_cyclopedia/images/icon-map-passage-selected.png
new file mode 100644
index 0000000000..65ca064f96
Binary files /dev/null and b/modules/game_cyclopedia/images/icon-map-passage-selected.png differ
diff --git a/modules/game_cyclopedia/images/icon-map-player.png b/modules/game_cyclopedia/images/icon-map-player.png
new file mode 100644
index 0000000000..7db077d281
Binary files /dev/null and b/modules/game_cyclopedia/images/icon-map-player.png differ
diff --git a/modules/game_cyclopedia/images/icon-map-pointofinterest.png b/modules/game_cyclopedia/images/icon-map-pointofinterest.png
new file mode 100644
index 0000000000..8c04afd695
Binary files /dev/null and b/modules/game_cyclopedia/images/icon-map-pointofinterest.png differ
diff --git a/modules/game_cyclopedia/images/icon-playerdetails.png b/modules/game_cyclopedia/images/icon-playerdetails.png
new file mode 100644
index 0000000000..0d3eeafd26
Binary files /dev/null and b/modules/game_cyclopedia/images/icon-playerdetails.png differ
diff --git a/modules/game_cyclopedia/images/icon-refresh.png b/modules/game_cyclopedia/images/icon-refresh.png
new file mode 100644
index 0000000000..194750f8ae
Binary files /dev/null and b/modules/game_cyclopedia/images/icon-refresh.png differ
diff --git a/modules/game_cyclopedia/images/icon-right-arrow-disabled.png b/modules/game_cyclopedia/images/icon-right-arrow-disabled.png
new file mode 100644
index 0000000000..ecb892d96c
Binary files /dev/null and b/modules/game_cyclopedia/images/icon-right-arrow-disabled.png differ
diff --git a/modules/game_cyclopedia/images/icon-right-arrow.png b/modules/game_cyclopedia/images/icon-right-arrow.png
new file mode 100644
index 0000000000..4238a43ccb
Binary files /dev/null and b/modules/game_cyclopedia/images/icon-right-arrow.png differ
diff --git a/modules/game_cyclopedia/images/icon-uparrow-disabled.png b/modules/game_cyclopedia/images/icon-uparrow-disabled.png
new file mode 100644
index 0000000000..e1d50c676d
Binary files /dev/null and b/modules/game_cyclopedia/images/icon-uparrow-disabled.png differ
diff --git a/modules/game_cyclopedia/images/icon_gold.png b/modules/game_cyclopedia/images/icon_gold.png
new file mode 100644
index 0000000000..39fca159f1
Binary files /dev/null and b/modules/game_cyclopedia/images/icon_gold.png differ
diff --git a/modules/game_cyclopedia/images/indicator_soulcore.png b/modules/game_cyclopedia/images/indicator_soulcore.png
new file mode 100644
index 0000000000..2ffc168063
Binary files /dev/null and b/modules/game_cyclopedia/images/indicator_soulcore.png differ
diff --git a/modules/game_cyclopedia/images/markers.png b/modules/game_cyclopedia/images/markers.png
new file mode 100644
index 0000000000..6c5a92f985
Binary files /dev/null and b/modules/game_cyclopedia/images/markers.png differ
diff --git a/modules/game_cyclopedia/images/panel_flat.png b/modules/game_cyclopedia/images/panel_flat.png
new file mode 100644
index 0000000000..2da41ddefd
Binary files /dev/null and b/modules/game_cyclopedia/images/panel_flat.png differ
diff --git a/modules/game_cyclopedia/tab/bestiary/bestiary.lua b/modules/game_cyclopedia/tab/bestiary/bestiary.lua
new file mode 100644
index 0000000000..5b34d7ddea
--- /dev/null
+++ b/modules/game_cyclopedia/tab/bestiary/bestiary.lua
@@ -0,0 +1,826 @@
+local UI = nil
+
+local STAGES = {
+ CREATURES = 2,
+ SEARCH = 4,
+ CATEGORY = 1,
+ CREATURE = 3
+}
+
+local storedRaceIDs = {}
+local animusMasteryPoints = 0
+
+function Cyclopedia.loadBestiaryOverview(name, creatures, animusMasteryPoints)
+ if name == "Result" then
+ Cyclopedia.loadBestiarySearchCreatures(creatures)
+ else
+ Cyclopedia.loadBestiaryCreatures(creatures)
+ end
+
+ if animusMasteryPoints and animusMasteryPoints > 0 then
+ animusMasteryPoints = animusMasteryPoints
+ end
+end
+
+function showBestiary()
+ UI = g_ui.loadUI("bestiary", contentContainer)
+ UI:show()
+
+ UI.ListBase.CategoryList:setVisible(true)
+ UI.ListBase.CreatureList:setVisible(false)
+ UI.ListBase.CreatureInfo:setVisible(false)
+
+ Cyclopedia.Bestiary.Stage = STAGES.CATEGORY
+ controllerCyclopedia.ui.CharmsBase:setVisible(true)
+ controllerCyclopedia.ui.GoldBase:setVisible(true)
+ controllerCyclopedia.ui.BestiaryTrackerButton:setVisible(true)
+ g_game.requestBestiary()
+end
+
+Cyclopedia.Bestiary = {}
+Cyclopedia.Bestiary.Stage = STAGES.CATEGORY
+
+function Cyclopedia.SetBestiaryProgress(fit, firstBar, secondBar, thirdBar, killCount, firstGoal, secondGoal, thirdGoal)
+ local function calculateWidth(value, max)
+ return math.min(math.floor((value / max) * fit), fit)
+ end
+
+ local function setBarVisibility(bar, isVisible, width)
+ bar:setVisible(isVisible)
+ if isVisible then
+ bar:setImageRect({
+ height = 12,
+ x = 0,
+ y = 0,
+ width = width
+ })
+ bar:setImageSource("/game_cyclopedia/images/bestiary/fill")
+ end
+ end
+
+ local firstWidth = calculateWidth(math.min(killCount, firstGoal), firstGoal)
+ setBarVisibility(firstBar, killCount > 0, firstWidth)
+
+ local secondWidth = 0
+ if killCount > firstGoal then
+ secondWidth = calculateWidth(math.min(killCount - firstGoal, secondGoal - firstGoal), secondGoal - firstGoal)
+ end
+ setBarVisibility(secondBar, killCount > firstGoal, secondWidth)
+
+ local thirdWidth = 0
+ if killCount > secondGoal then
+ thirdWidth = calculateWidth(math.min(killCount - secondGoal, thirdGoal - secondGoal), thirdGoal - secondGoal)
+ end
+ setBarVisibility(thirdBar, killCount > secondGoal, thirdWidth)
+end
+
+function Cyclopedia.SetBestiaryStars(value)
+ UI.ListBase.CreatureInfo.StarFill:setWidth(value * 9)
+end
+
+function Cyclopedia.SetBestiaryDiamonds(value)
+ UI.ListBase.CreatureInfo.DiamondFill:setWidth(value * 9)
+end
+
+function Cyclopedia.CreateCreatureItems(data)
+ UI.ListBase.CreatureInfo.ItemsBase.Itemlist:destroyChildren()
+
+ for index, _ in pairs(data) do
+ local widget = g_ui.createWidget("BestiaryItemGroup", UI.ListBase.CreatureInfo.ItemsBase.Itemlist)
+ widget:setId(index)
+
+ if index == 0 then
+ widget.Title:setText(tr("Common") .. ":")
+ elseif index == 1 then
+ widget.Title:setText(tr("Uncommon") .. ":")
+ elseif index == 2 then
+ widget.Title:setText(tr("Semi-Rare") .. ":")
+ elseif index == 3 then
+ widget.Title:setText(tr("Rare") .. ":")
+ else
+ widget.Title:setText(tr("Very Rare") .. ":")
+ end
+
+ for i = 1, 15 do
+ local item = g_ui.createWidget("BestiaryItem", widget.Items)
+ item:setId(i)
+ end
+
+ for itemIndex, itemData in ipairs(data[index]) do
+ local thing = g_things.getThingType(itemData.id, ThingCategoryItem)
+ local itemWidget = UI.ListBase.CreatureInfo.ItemsBase.Itemlist[index].Items[itemIndex]
+ itemWidget:setItemId(itemData.id)
+ itemWidget.id = itemData.id
+ itemWidget.classification = thing:getClassification()
+
+ if itemData.id == 0 then
+ itemWidget.undefinedItem:setVisible(true)
+ end
+
+ if itemData.id > 0 then
+ if itemData.stackable then
+ itemWidget.Stackable:setText("1+")
+ else
+ itemWidget.Stackable:setText("1")
+ end
+ end
+
+ local price, rarity = ItemsDatabase.getSellValueAndColor(itemWidget.id)
+ if price > 0 then
+ itemWidget:setImageSource("/images/ui/rarity_" .. rarity)
+ end
+
+ itemWidget.onMouseRelease = onAddLootClick
+ end
+ end
+end
+
+function Cyclopedia.loadBestiarySelectedCreature(data)
+ local occurence = {
+ [0] = 1,
+ 2,
+ 3,
+ 4
+ }
+
+ local formattedName = "BUSCAR__" .. data.id
+ local outfit = 22
+ if RACE[data.id] then
+ formattedName = RACE[data.id].name:gsub("(%l)(%w*)", function(first, rest)
+ return first:upper() .. rest
+ end)
+ outfit = RACE[data.id].type
+ end
+
+ UI.ListBase.CreatureInfo:setText(formattedName)
+ Cyclopedia.SetBestiaryDiamonds(occurence[data.ocorrence])
+ Cyclopedia.SetBestiaryStars(data.difficulty)
+ UI.ListBase.CreatureInfo.LeftBase.Sprite:setOutfit({
+ type = outfit
+ })
+ UI.ListBase.CreatureInfo.LeftBase.Sprite:getCreature():setStaticWalking(1000)
+
+ Cyclopedia.SetBestiaryProgress(60, UI.ListBase.CreatureInfo.ProgressBack, UI.ListBase.CreatureInfo.ProgressBack33,
+ UI.ListBase.CreatureInfo.ProgressBack55, data.killCounter, data.thirdDifficulty, data.secondUnlock,
+ data.lastProgressKillCount)
+
+ UI.ListBase.CreatureInfo.ProgressValue:setText(data.killCounter)
+
+ local fullText = ""
+ if data.killCounter >= data.lastProgressKillCount then
+ fullText = "(fully unlocked)"
+ end
+
+ UI.ListBase.CreatureInfo.ProgressBorder1:setTooltip(string.format(" %d / %d %s", data.killCounter,
+ data.thirdDifficulty, fullText))
+ UI.ListBase.CreatureInfo.ProgressBorder2:setTooltip(string.format(" %d / %d %s", data.killCounter,
+ data.secondUnlock, fullText))
+ UI.ListBase.CreatureInfo.ProgressBorder3:setTooltip(string.format(" %d / %d %s", data.killCounter,
+ data.lastProgressKillCount, fullText))
+ UI.ListBase.CreatureInfo.LeftBase.TrackCheck.raceId = data.id
+
+ -- TODO investigate when it can be track-- idk when
+ --[[ if data.currentLevel == 1 then
+ UI.ListBase.CreatureInfo.LeftBase.TrackCheck:enable()
+ else
+ UI.ListBase.CreatureInfo.LeftBase.TrackCheck:disable()
+ end ]]
+
+ if table.find(storedRaceIDs, data.id) then
+ UI.ListBase.CreatureInfo.LeftBase.TrackCheck:setChecked(true)
+ else
+ UI.ListBase.CreatureInfo.LeftBase.TrackCheck:setChecked(false)
+ end
+
+ if data.currentLevel > 1 then
+ UI.ListBase.CreatureInfo.Value1:setText(data.maxHealth)
+ UI.ListBase.CreatureInfo.Value2:setText(data.experience)
+ UI.ListBase.CreatureInfo.Value3:setText(data.speed)
+ UI.ListBase.CreatureInfo.Value4:setText(data.armor)
+ UI.ListBase.CreatureInfo.Value5:setText(data.mitigation .. "%")
+ UI.ListBase.CreatureInfo.BonusValue:setText(data.charmValue)
+ else
+ UI.ListBase.CreatureInfo.Value1:setText("?")
+ UI.ListBase.CreatureInfo.Value2:setText("?")
+ UI.ListBase.CreatureInfo.Value3:setText("?")
+ UI.ListBase.CreatureInfo.Value4:setText("?")
+ UI.ListBase.CreatureInfo.Value5:setText("?")
+ UI.ListBase.CreatureInfo.BonusValue:setText("?")
+ end
+
+ if data.attackMode == 1 then
+ local rect = {
+ height = 9,
+ x = 18,
+ y = 0,
+ width = 18
+ }
+
+ UI.ListBase.CreatureInfo.SubTextLabel:setImageSource("/images/icons/icons-skills")
+ UI.ListBase.CreatureInfo.SubTextLabel:setImageClip(rect)
+ UI.ListBase.CreatureInfo.SubTextLabel:setSize("18 9")
+ else
+ local rect = {
+ height = 9,
+ x = 0,
+ y = 0,
+ width = 18
+ }
+ UI.ListBase.CreatureInfo.SubTextLabel:setImageSource("/images/icons/icons-skills")
+ UI.ListBase.CreatureInfo.SubTextLabel:setImageClip(rect)
+ UI.ListBase.CreatureInfo.SubTextLabel:setSize("18 9")
+ end
+
+ local resists = {"PhysicalProgress", "FireProgress", "EarthProgress", "EnergyProgress", "IceProgress",
+ "HolyProgress", "DeathProgress", "HealingProgress"}
+
+ if not table.empty(data.combat) then
+ for i = 1, 8 do
+ local combat = Cyclopedia.calculateCombatValues(data.combat[i])
+ UI.ListBase.CreatureInfo[resists[i]].Fill:setMarginRight(combat.margin)
+ UI.ListBase.CreatureInfo[resists[i]].Fill:setBackgroundColor(combat.color)
+ UI.ListBase.CreatureInfo[resists[i]]:setTooltip(string.format("Sensitive to %s : %s", string.gsub(
+ resists[i], "Progress", ""):lower(), combat.tooltip))
+ end
+ else
+ for i = 1, 8 do
+ UI.ListBase.CreatureInfo[resists[i]].Fill:setMarginRight(65)
+ end
+ end
+
+ local lootData = {}
+ for _, value in ipairs(data.loot) do
+ local loot = {
+ name = value.name,
+ id = value.itemId,
+ type = value.type,
+ difficulty = value.diffculty,
+ stackable = value.stackable == 1 and true or false
+ }
+
+ if not lootData[value.diffculty] then
+ lootData[value.diffculty] = {}
+ end
+
+ table.insert(lootData[value.diffculty], loot)
+ end
+
+ Cyclopedia.CreateCreatureItems(lootData)
+ UI.ListBase.CreatureInfo.LocationField.Textlist.Text:setText(data.location)
+
+ if data.AnimusMasteryPoints and data.AnimusMasteryPoints > 1 then
+ UI.ListBase.CreatureInfo.AnimusMastery:setTooltip("The Animus Mastery for this creature is unlocked.\nIt yields "..(data.AnimusMasteryBonus / 10).."% bonus experience points, plus an additional 0.1% for every 10 Animus Masteries unlocked, up to a maximum of 4%.\nYou currently benefit from "..(data.AnimusMasteryBonus / 10).."% bonus experience points due to having unlocked ".. data.AnimusMasteryPoints .." Animus Masteries.")
+ UI.ListBase.CreatureInfo.AnimusMastery:setVisible(true)
+ else
+ UI.ListBase.CreatureInfo.AnimusMastery:removeTooltip()
+ UI.ListBase.CreatureInfo.AnimusMastery:setVisible(false)
+ end
+end
+
+function Cyclopedia.ShowBestiaryCreature()
+ Cyclopedia.Bestiary.Stage = STAGES.CREATURE
+ Cyclopedia.onStageChange()
+end
+
+function Cyclopedia.ShowBestiaryCreatures(Category)
+ UI.ListBase.CreatureList:destroyChildren()
+ UI.ListBase.CategoryList:setVisible(false)
+ UI.ListBase.CreatureInfo:setVisible(false)
+ UI.ListBase.CreatureList:setVisible(true)
+ g_game.requestBestiaryOverview(Category)
+end
+
+function Cyclopedia.CreateBestiaryCategoryItem(Data)
+ UI.BackPageButton:setEnabled(false)
+
+ local widget = g_ui.createWidget("BestiaryCategory", UI.ListBase.CategoryList)
+ widget:setText(Data.name)
+ widget.ClassIcon:setImageSource("/game_cyclopedia/images/bestiary/creatures/" .. Data.name:lower():gsub(" ", "_"))
+ widget.Category = Data.name
+ widget:setColor("#C0C0C0")
+ widget.TotalValue:setText(string.format("Total: %d", Data.amount))
+ widget.KnownValue:setText(string.format("Known: %d", Data.know))
+
+ function widget.ClassBase:onClick()
+ UI.BackPageButton:setEnabled(true)
+ Cyclopedia.ShowBestiaryCreatures(self:getParent().Category)
+ Cyclopedia.Bestiary.Stage = STAGES.CREATURES
+ Cyclopedia.onStageChange()
+ end
+end
+
+function Cyclopedia.loadBestiarySearchCreatures(data)
+ UI.ListBase.CategoryList:setVisible(false)
+ UI.ListBase.CreatureInfo:setVisible(false)
+ UI.ListBase.CreatureList:setVisible(true)
+ UI.BackPageButton:setEnabled(true)
+
+ Cyclopedia.Bestiary.Stage = STAGES.SEARCH
+ Cyclopedia.onStageChange()
+ Cyclopedia.Bestiary.Search = {}
+ Cyclopedia.Bestiary.Page = 1
+
+ local maxCategoriesPerPage = 15
+ Cyclopedia.Bestiary.TotalSearchPages = math.ceil(#data / maxCategoriesPerPage)
+
+ UI.PageValue:setText(string.format("%d / %d", Cyclopedia.Bestiary.Page, Cyclopedia.Bestiary.TotalSearchPages))
+
+ local page = 1
+ Cyclopedia.Bestiary.Search[page] = {}
+
+ for i = 0, #data do
+ if i % maxCategoriesPerPage == 0 and i > 0 then
+ page = page + 1
+ Cyclopedia.Bestiary.Search[page] = {}
+ end
+ local creature = {
+ id = data[i].id,
+ currentLevel = data[i].currentLevel,
+ AnimusMasteryBonus = data[i].AnimusMasteryBonus,
+
+ }
+
+ table.insert(Cyclopedia.Bestiary.Search[page], creature)
+ end
+
+ Cyclopedia.Bestiary.Stage = STAGES.SEARCH
+ Cyclopedia.loadBestiaryCreature(Cyclopedia.Bestiary.Page, true)
+ Cyclopedia.verifyBestiaryButtons()
+end
+
+function Cyclopedia.loadBestiaryCreatures(data)
+ Cyclopedia.Bestiary.Creatures = {}
+ Cyclopedia.Bestiary.Page = 1
+
+ local maxCategoriesPerPage = 15
+ Cyclopedia.Bestiary.TotalCreaturesPages = math.ceil(#data / maxCategoriesPerPage)
+
+ UI.PageValue:setText(string.format("%d / %d", Cyclopedia.Bestiary.Page, Cyclopedia.Bestiary.TotalCreaturesPages))
+
+ local page = 1
+ Cyclopedia.Bestiary.Creatures[page] = {}
+
+ for i = 1, #data do
+ if (i - 1) % maxCategoriesPerPage == 0 and i > 1 then
+ page = page + 1
+ Cyclopedia.Bestiary.Creatures[page] = {}
+ end
+
+ local creature = {
+ id = data[i].id,
+ currentLevel = data[i].currentLevel,
+ AnimusMasteryBonus = data[i].creatureAnimusMasteryBonus,
+
+ }
+
+ table.insert(Cyclopedia.Bestiary.Creatures[page], creature)
+ end
+
+ Cyclopedia.loadBestiaryCreature(Cyclopedia.Bestiary.Page, false)
+ Cyclopedia.verifyBestiaryButtons()
+end
+
+function Cyclopedia.BestiarySearch()
+ local text = UI.SearchEdit:getText()
+ local creatures = {}
+
+ for id, data in pairs(RACE) do
+ if string.find(data.name, text) then
+ table.insert(creatures, id)
+ end
+ end
+
+ g_game.requestBestiarySearch(creatures)
+ UI.SearchEdit:setText("")
+end
+
+function Cyclopedia.BestiarySearchText(text)
+ if text ~= "" then
+ UI.SearchButton:enable(true)
+ else
+ UI.SearchButton:disable(false)
+ end
+end
+
+function Cyclopedia.CreateBestiaryCreaturesItem(data)
+ if not RACE[data.id] then
+ g_logger.warning(string.format("Race id: %d not found. add in ./modules/game_cyclopedia/utils.lua", data.id))
+ end
+
+ local function verify(name)
+ if #name > 18 then
+ return name:sub(1, 15) .. "..."
+ else
+ return name
+ end
+ end
+
+ local widget = g_ui.createWidget("BestiaryCreature", UI.ListBase.CreatureList)
+ widget:setId(data.id)
+
+ local formattedName = "search__" .. data.id
+ if RACE[data.id] then
+ formattedName = RACE[data.id].name:gsub("(%l)(%w*)", function(first, rest)
+ return first:upper() .. rest
+ end)
+ end
+
+ widget.Name:setText(verify(formattedName))
+ widget.Sprite:setOutfit({
+ type = Cyclopedia.safeOutfit(RACE[data.id] and RACE[data.id].type or nil)
+ })
+ widget.Sprite:getCreature():setStaticWalking(1000)
+
+ if data.AnimusMasteryBonus > 0 then
+ widget.AnimusMastery:setTooltip("The Animus Mastery for this creature is unlocked.\nIt yields ".. data.AnimusMasteryBonus.. "% bonus experience points, plus an additional 0.1% for every 10 Animus Masteries unlocked, up to a maximum of 4%.\nYou currently benefit from ".. data.AnimusMasteryBonus.. "% bonus experience points due to having unlocked ".. animusMasteryPoints.." Animus Masteries.")
+ widget.AnimusMastery:setVisible(true)
+ else
+ widget.AnimusMastery:removeTooltip()
+ widget.AnimusMastery:setVisible(false)
+ end
+
+ if data.currentLevel >= 3 then
+ widget.Finalized:setVisible(true)
+ widget.KillsLabel:setVisible(false)
+ widget.Sprite:getCreature():setShader("")
+ else
+ if data.currentLevel < 1 then
+ widget.KillsLabel:setText("?")
+ widget.Sprite:getCreature():setShader("Outfit - cyclopedia-black")
+ widget.Name:setText("Unknown")
+ widget.AnimusMastery:setVisible(false)
+ else
+ widget.KillsLabel:setText(string.format("%d / 3", data.currentLevel - 1))
+ end
+
+ end
+
+ function widget.ClassBase:onClick()
+ if data.currentLevel < 1 then
+ return
+ end
+
+ UI.BackPageButton:setEnabled(true)
+ g_game.requestBestiarySearch(widget:getId())
+ Cyclopedia.ShowBestiaryCreature()
+ end
+end
+
+function Cyclopedia.loadBestiaryCreature(page, search)
+ local state = "Creatures"
+ if search then
+ state = "Search"
+ end
+
+ if not Cyclopedia.Bestiary[state][page] then
+ return
+ end
+
+ UI.ListBase.CreatureList:destroyChildren()
+
+ for _, data in ipairs(Cyclopedia.Bestiary[state][page]) do
+ Cyclopedia.CreateBestiaryCreaturesItem(data)
+ end
+end
+
+function Cyclopedia.loadBestiaryCategories(data)
+ Cyclopedia.Bestiary.Categories = {}
+ Cyclopedia.Bestiary.Page = 1
+
+ local maxCategoriesPerPage = 15
+ Cyclopedia.Bestiary.TotalCategoriesPages = math.ceil(#data / maxCategoriesPerPage)
+
+ if UI == nil or UI.PageValue == nil then -- I know, don't change it
+ return
+ end
+
+ UI.PageValue:setText(string.format("%d / %d", Cyclopedia.Bestiary.Page, Cyclopedia.Bestiary.TotalCategoriesPages))
+
+ local page = 1
+ Cyclopedia.Bestiary.Categories[page] = {}
+
+ for i = 1, #data do
+ if (i - 1) % maxCategoriesPerPage == 0 and i > 1 then
+ page = page + 1
+ Cyclopedia.Bestiary.Categories[page] = {}
+ end
+
+ local category = {
+ name = data[i].bestClass,
+ amount = data[i].count,
+ know = data[i].unlockedCount,
+ AnimusMasteryBonus = data[i].AnimusMasteryBonus,
+ }
+
+ table.insert(Cyclopedia.Bestiary.Categories[page], category)
+ end
+
+ Cyclopedia.loadBestiaryCategory(Cyclopedia.Bestiary.Page)
+ Cyclopedia.verifyBestiaryButtons()
+end
+
+function Cyclopedia.loadBestiaryCategory(page)
+ if not Cyclopedia.Bestiary.Categories[page] then
+ return
+ end
+
+ UI.ListBase.CategoryList:destroyChildren()
+
+ for _, data in ipairs(Cyclopedia.Bestiary.Categories[page]) do
+ Cyclopedia.CreateBestiaryCategoryItem(data)
+ end
+end
+
+function Cyclopedia.onStageChange()
+ Cyclopedia.Bestiary.Page = 1
+
+ if Cyclopedia.Bestiary.Stage == STAGES.CATEGORY then
+ UI.BackPageButton:setEnabled(false)
+ UI.ListBase.CategoryList:setVisible(true)
+ UI.ListBase.CreatureList:setVisible(false)
+ UI.ListBase.CreatureInfo:setVisible(false)
+ end
+
+ if Cyclopedia.Bestiary.Stage == STAGES.CREATURES then
+ UI.BackPageButton:setEnabled(true)
+ UI.ListBase.CategoryList:setVisible(false)
+ UI.ListBase.CreatureList:setVisible(true)
+ UI.ListBase.CreatureInfo:setVisible(false)
+
+ function UI.BackPageButton.onClick()
+ Cyclopedia.Bestiary.Stage = STAGES.CATEGORY
+ Cyclopedia.onStageChange()
+ end
+ end
+
+ if Cyclopedia.Bestiary.Stage == STAGES.SEARCH then
+ UI.BackPageButton:setEnabled(true)
+ UI.ListBase.CategoryList:setVisible(false)
+ UI.ListBase.CreatureList:setVisible(true)
+ UI.ListBase.CreatureInfo:setVisible(false)
+
+ function UI.BackPageButton.onClick()
+ Cyclopedia.Bestiary.Stage = STAGES.CATEGORY
+ Cyclopedia.onStageChange()
+ end
+ end
+
+ if Cyclopedia.Bestiary.Stage == STAGES.CREATURE then
+ UI.BackPageButton:setEnabled(true)
+ UI.ListBase.CategoryList:setVisible(false)
+ UI.ListBase.CreatureList:setVisible(false)
+ UI.ListBase.CreatureInfo:setVisible(true)
+
+ function UI.BackPageButton.onClick()
+ Cyclopedia.Bestiary.Stage = STAGES.CREATURES
+ Cyclopedia.onStageChange()
+ end
+ end
+
+ Cyclopedia.verifyBestiaryButtons()
+end
+
+function Cyclopedia.changeBestiaryPage(prev, next)
+ if next then
+ Cyclopedia.Bestiary.Page = Cyclopedia.Bestiary.Page + 1
+ end
+
+ if prev then
+ Cyclopedia.Bestiary.Page = Cyclopedia.Bestiary.Page - 1
+ end
+
+ local stage = Cyclopedia.Bestiary.Stage
+ if stage == STAGES.CATEGORY then
+ Cyclopedia.loadBestiaryCategory(Cyclopedia.Bestiary.Page)
+ elseif stage == STAGES.CREATURES then
+ Cyclopedia.loadBestiaryCreature(Cyclopedia.Bestiary.Page, false)
+ elseif stage == STAGES.SEARCH then
+ Cyclopedia.loadBestiaryCreature(Cyclopedia.Bestiary.Page, true)
+ end
+
+ Cyclopedia.verifyBestiaryButtons()
+end
+
+function Cyclopedia.verifyBestiaryButtons()
+ local function updateButtonState(button, condition)
+ if condition then
+ button:enable()
+ else
+ button:disable()
+ end
+ end
+
+ local function updatePageValue(currentPage, totalPages)
+ UI.PageValue:setText(string.format("%d / %d", currentPage, totalPages))
+ end
+
+ updateButtonState(UI.SearchButton, UI.SearchEdit:getText() ~= "")
+
+ local stage = Cyclopedia.Bestiary.Stage
+ local totalSearchPages = Cyclopedia.Bestiary.TotalSearchPages
+ local page = Cyclopedia.Bestiary.Page
+ if stage == STAGES.SEARCH and totalSearchPages then
+ local totalPages = totalSearchPages
+ updateButtonState(UI.PrevPageButton, page > 1)
+ updateButtonState(UI.NextPageButton, page < totalPages)
+ updatePageValue(page, totalPages)
+ return
+ end
+
+ if stage == STAGES.CREATURE then
+ UI.PrevPageButton:disable()
+ UI.NextPageButton:disable()
+ updatePageValue(1, 1)
+ return
+ end
+
+ local totalCategoriesPages = Cyclopedia.Bestiary.TotalCategoriesPages
+ local totalCreaturesPages = Cyclopedia.Bestiary.TotalCreaturesPages
+ if stage == STAGES.CATEGORY and totalCategoriesPages or stage == STAGES.CREATURES and totalCreaturesPages then
+ local totalPages = stage == STAGES.CATEGORY and totalCategoriesPages or totalCreaturesPages
+ updateButtonState(UI.PrevPageButton, page > 1)
+ updateButtonState(UI.NextPageButton, page < totalPages)
+ updatePageValue(page, totalPages)
+ end
+end
+
+--[[
+===================================================
+= Tracker =
+===================================================
+]]
+
+function Cyclopedia.toggleBestiaryTracker()
+ if not trackerMiniWindow then
+ return
+ end
+
+ if trackerButton:isOn() then
+ trackerMiniWindow:close()
+ trackerButton:setOn(false)
+ else
+ if not trackerMiniWindow:getParent() then
+ local panel = modules.game_interface.findContentPanelAvailable(trackerMiniWindow,
+ trackerMiniWindow:getMinimumHeight())
+ if not panel then
+ return
+ end
+ panel:addChild(trackerMiniWindow)
+ end
+ trackerMiniWindow:open()
+ trackerButton:setOn(true)
+ end
+end
+
+function Cyclopedia.toggleBosstiaryTracker()
+ if not trackerMiniWindowBosstiary then
+ return
+ end
+
+ if trackerButtonBosstiary:isOn() then
+ trackerMiniWindowBosstiary:close()
+ trackerButtonBosstiary:setOn(false)
+ else
+ if not trackerMiniWindowBosstiary:getParent() then
+ local panel = modules.game_interface.findContentPanelAvailable(trackerMiniWindowBosstiary,
+ trackerMiniWindowBosstiary:getMinimumHeight())
+ if not panel then
+ return
+ end
+ panel:addChild(trackerMiniWindowBosstiary)
+ end
+ trackerMiniWindowBosstiary:open()
+ trackerButtonBosstiary:setOn(true)
+ end
+end
+
+function Cyclopedia.onTrackerClose(temp)
+ if temp == "Boosteary Tracker" then
+ trackerButtonBosstiary:setOn(false)
+ else
+ trackerButton:setOn(false)
+ end
+end
+
+function Cyclopedia.setBarPercent(widget, percent)
+ if percent > 92 then
+ widget.killsBar:setBackgroundColor("#00BC00")
+ elseif percent > 60 then
+ widget.killsBar:setBackgroundColor("#50A150")
+ elseif percent > 30 then
+ widget.killsBar:setBackgroundColor("#A1A100")
+ elseif percent > 8 then
+ widget.killsBar:setBackgroundColor("#BF0A0A")
+ elseif percent > 3 then
+ widget.killsBar:setBackgroundColor("#910F0F")
+ else
+ widget.killsBar:setBackgroundColor("#850C0C")
+ end
+
+ widget.killsBar:setPercent(percent)
+end
+
+function Cyclopedia.onParseCyclopediaTracker(trackerType, data)
+ if not data then
+ return
+ end
+
+ local isBoss = trackerType == 1
+ local window = isBoss and trackerMiniWindowBosstiary or trackerMiniWindow
+ local raceData = isBoss and RACE_Bosstiary or RACE
+
+ window.contentsPanel:destroyChildren()
+ storedRaceIDs = {}
+
+ for _, entry in ipairs(data) do
+ local raceId, kills, uno, dos, maxKills = unpack(entry)
+ table.insert(storedRaceIDs, raceId)
+ local raceInfo = raceData[raceId]
+ local name = raceInfo.name
+
+ local widget = g_ui.createWidget("TrackerButton", window.contentsPanel)
+ widget:setId(raceId)
+ widget.creature:setOutfit({
+ type = raceInfo.type
+ })
+ widget.label:setText(name:len() > 12 and name:sub(1, 9) .. "..." or name)
+ widget.kills:setText(kills .. "/" .. maxKills)
+ widget.onMouseRelease = onTrackerClick
+
+ Cyclopedia.SetBestiaryProgress(54,widget.killsBar2, widget.ProgressBack33, widget.ProgressBack55, kills, uno, dos, maxKills)
+ end
+end
+
+local BESTIATYTRACKER_FILTERS = {
+ ["sortByName"] = true,
+ ["ShortByPercentage"] = false,
+ ["sortByKills"] = false,
+ ["sortByAscending"] = false,
+ ["sortByDescending"] = false
+}
+
+function loadFilters()
+ local settings = g_settings.getNode("bestiaryTracker")
+ if not settings or not settings['filters'] then
+ return BESTIATYTRACKER_FILTERS
+ end
+ return settings['filters']
+end
+
+function saveFilters()
+ g_settings.mergeNode('bestiaryTracker', {
+ ['filters'] = loadFilters()
+ })
+end
+
+function getFilter(filter)
+ return loadFilters()[filter] or false
+end
+
+function setFilter(filter)
+ local filters = loadFilters()
+ local value = filters[filter]
+ if value == nil then
+ return false
+ end
+
+ filters[filter] = not value
+ g_settings.mergeNode('bestiaryTracker', {
+ ['filters'] = filters
+ })
+end
+
+-- trackerMiniWindow.contentsPanel:moveChildToIndex(battleButton, index)
+-- TODO Add sort by name, kills, percentage, ascending, descending
+function test(index)
+ trackerMiniWindow.contentsPanel:moveChildToIndex(trackerMiniWindow.contentsPanel:getLastChild(), index)
+end
+
+function onTrackerClick(widget, mousePosition, mouseButton)
+ local taskId = tonumber(widget:getId())
+ local menu = g_ui.createWidget("PopupMenu")
+
+ menu:setGameMenu(true)
+ menu:addOption("stop Tracking " .. widget.label:getText(), function()
+ g_game.sendStatusTrackerBestiary(taskId, false)
+ end)
+ menu:display(menuPosition)
+
+ return true
+end
+
+function onAddLootClick(widget, mousePosition, mouseButton)
+ local taskId = tonumber(widget:getId())
+ local menu = g_ui.createWidget("PopupMenu")
+
+ menu:setGameMenu(true)
+ --if true then -- is in loot list ?
+ menu:addOption("Add to Loot List", function() print("future") end)
+ --else
+ --menu:addOption("Remove from Loot List", function() print("future") end)
+ --end
+
+ menu:display(menuPosition)
+
+ return true
+end
diff --git a/modules/game_cyclopedia/tab/bestiary/bestiary.otui b/modules/game_cyclopedia/tab/bestiary/bestiary.otui
new file mode 100644
index 0000000000..7b1345c3e6
--- /dev/null
+++ b/modules/game_cyclopedia/tab/bestiary/bestiary.otui
@@ -0,0 +1,588 @@
+UIWidget
+ id: Cat2
+ anchors.fill: parent
+ visible: false
+
+ Button
+ id: SearchButton
+ size: 40 20
+ anchors.bottom: parent.bottom
+ anchors.right: parent.right
+ margin-bottom: 35
+ !text: tr('Search')
+ font: small-9px
+ text-offset: 0 -1
+ color: #C0C0C0
+ @onClick: modules.game_cyclopedia.Cyclopedia.BestiarySearch(self:getText())
+ TextEdit
+ id: SearchEdit
+ size: 130 17
+ anchors.right: SearchButton.left
+ anchors.bottom: SearchButton.bottom
+ margin-bottom: 1
+ placeholder: Type to search
+ placeholder-color: #6E706F
+ font: verdana-11px-monochrome
+ color: #C0C0C0
+ padding-top: 1
+ shader: Map - Party
+ @onTextChange: modules.game_cyclopedia.Cyclopedia.BestiarySearchText(self:getText())
+ UIWidget
+ id: PageValue
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottom: parent.bottom
+ margin-bottom: 34
+ size: 50 20
+ text-align: center
+ !text: tr('1 / 1')
+ color: #C2C2C2
+ Button
+ id: NextPageButton
+ size: 20 20
+ anchors.left: PageValue.right
+ anchors.bottom: PageValue.bottom
+ icon-source: /game_cyclopedia/images/icon-right-arrow
+ @onClick: modules.game_cyclopedia.Cyclopedia.changeBestiaryPage(false, true)
+ $pressed:
+ icon-source: /game_cyclopedia/images/icon-right-arrow
+ $disabled:
+ icon-source: /game_cyclopedia/images/icon-right-arrow-disabled
+ Button
+ id: PrevPageButton
+ size: 20 20
+ anchors.right: PageValue.left
+ anchors.bottom: PageValue.bottom
+ icon-source: /game_cyclopedia/images/icon-left-arrow
+ @onClick: modules.game_cyclopedia.Cyclopedia.changeBestiaryPage(true, false)
+ $pressed:
+ icon-source: /game_cyclopedia/images/icon-left-arrow-disabled
+ $disabled:
+ icon-source: /game_cyclopedia/images/icon-left-arrow-disabled
+ UIWidget
+ id: BackPageButton
+ size: 20 20
+ anchors.right: PrevPageButton.left
+ anchors.bottom: PageValue.bottom
+ margin-right: 10
+
+
+ image-source: /game_cyclopedia/images/button_back
+ $pressed:
+ image-source: /game_cyclopedia/images/button_back_pressed
+ $disabled:
+ image-source: /game_cyclopedia/images/button_back_disabled
+ Panel
+ id: ListBase
+ anchors.bottom: SearchButton.top
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.right: parent.right
+ margin-top: 10
+ margin-bottom: 5
+ UIScrollArea
+ id: CategoryList
+ anchors.fill: parent
+ padding-left: 5
+ padding-top: 5
+ layout:
+ type: grid
+ cell-size: 127 120
+ cell-spacing: 5
+ flow: true
+ UIScrollArea
+ id: CreatureList
+ anchors.fill: parent
+ padding-left: 5
+ padding-top: 5
+ visible: false
+ layout:
+ type: grid
+ cell-size: 127 120
+ cell-spacing: 5
+ flow: true
+ UIWidget
+ id: CreatureInfo
+ anchors.fill: parent
+ image-source: /images/ui/outfits/minipanel
+ image-border: 20
+ visible: false
+ !text: tr('Creature Name')
+ text-align: top
+ text-offset: 0 4
+ color: #919191
+ UIWidget
+ id: AnimusMastery
+ anchors.top: parent.top
+ anchors.left: parent.left
+
+ margin-top: 18
+ margin-left: 3
+ image-source: /game_cyclopedia/images/indicator_soulcore
+ UIWidget
+ id: LeftBase
+ anchors.left: parent.left
+ anchors.top: parent.top
+ anchors.bottom: parent.verticalCenter
+ margin-top: 20
+ margin-left: 5
+ width: 125
+ phantom: true
+ CheckBox
+ id: TrackCheck
+ anchors.bottom: parent.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+ !text: tr('Track Kills')
+ text-auto-resize: true
+ color: #C7C7C7
+ @onCheckChange: |
+ g_game.sendStatusTrackerBestiary(self.raceId,self:isChecked())
+ UICreature
+ id: Sprite
+ anchors.top: parent.top
+ anchors.horizontalCenter: parent.horizontalCenter
+ margin-top: 30
+ size: 96 96
+ ProgressBackground
+ id: ProgressBorder2
+ anchors.left: LeftBase.right
+ anchors.top: parent.top
+ margin-top: 40
+ margin-left: 80
+ size: 60 14
+ ProgressBackground
+ id: ProgressBorder1
+ anchors.right: ProgressBorder2.left
+ anchors.bottom: ProgressBorder2.bottom
+ margin-right: 2
+ size: 60 14
+ ProgressBackground
+ id: ProgressBorder3
+ anchors.left: ProgressBorder2.right
+ anchors.bottom: ProgressBorder2.bottom
+ margin-left: 2
+ size: 60 14
+ UIWidget
+ id: ProgressBack
+ anchors.left: ProgressBorder1.left
+ anchors.bottom: ProgressBorder2.bottom
+ height: 12
+
+ phantom: true
+
+ image-source: /game_cyclopedia/images/bestiary/fill
+ UIWidget
+ id: ProgressBack33
+ anchors.left: ProgressBorder2.left
+ anchors.bottom: ProgressBorder2.bottom
+ height: 12
+
+ phantom: true
+
+ image-source: /game_cyclopedia/images/bestiary/fill
+ UIWidget
+ id: ProgressBack55
+ anchors.left: ProgressBorder3.left
+ anchors.bottom: ProgressBorder2.bottom
+ height: 12
+
+ phantom: true
+
+ image-source: /game_cyclopedia/images/bestiary/fill
+ UIWidget
+
+ anchors.left: ProgressBorder1.right
+ anchors.top: ProgressBorder1.top
+ image-source: /images/ui/progress-separator
+
+ phantom: true
+ UIWidget
+
+ anchors.left: ProgressBorder2.right
+ anchors.top: ProgressBorder1.top
+ image-source: /images/ui/progress-separator
+ phantom: true
+ Label
+ id: ProgressValue
+ anchors.centerIn: ProgressBorder2
+
+ text-auto-resize: true
+ !text: tr('0')
+ Label
+ id: TotalLabel
+ anchors.bottom: ProgressBorder2.top
+ anchors.left: ProgressBorder1.right
+
+ margin-bottom: 2
+ !text: tr('Total Kills')
+ color: #C7C7C7
+ UIWidget
+ id: StarBase
+ anchors.left: ProgressBorder1.left
+ anchors.top: ProgressBorder2.bottom
+ margin-top: 4
+ image-source: /game_cyclopedia/images/boss/icon_star
+ image-repeated: true
+ width: 45
+ UIWidget
+ id: StarFill
+ anchors.left: ProgressBorder1.left
+ anchors.top: StarBase.top
+ image-source: /game_cyclopedia/images/boss/icon_star_active
+ image-repeated: true
+ width: 45
+ UIWidget
+ id: DiamondBase
+ anchors.left: ProgressBorder1.left
+ anchors.top: StarFill.bottom
+ margin-top: 5
+ image-source: /game_cyclopedia/images/bestiary/icons/monster-icon-diamond-inactive
+ image-repeated: true
+ width: 36
+ UIWidget
+ id: DiamondFill
+ anchors.left: ProgressBorder1.left
+ anchors.top: DiamondBase.top
+ image-source: /game_cyclopedia/images/bestiary/icons/monster-icon-diamond-active
+ image-repeated: true
+ width: 36
+ UIWidget
+ id: SubTextLabel
+ anchors.top: DiamondBase.bottom
+ anchors.left: DiamondBase.left
+ margin-top: 5
+ text-auto-resize: true
+
+ UIWidget
+ id: BonusIcon
+ anchors.top: SubTextLabel.bottom
+ anchors.left: SubTextLabel.left
+ margin-top: 5
+ image-source: /game_cyclopedia/images/bestiary/icons/monster-icon-bonuspoints
+ Label
+ id: BonusValue
+ anchors.verticalCenter: BonusIcon.verticalCenter
+ anchors.left: BonusIcon.right
+ margin-left: 5
+ text-auto-resize: true
+ !text: tr('?')
+ color: #C7C7C7
+ UIWidget
+ id: CharmBase
+ anchors.bottom: LeftBase.bottom
+ anchors.left: BonusIcon.left
+ image-source: /images/ui/panel_flat
+ image-border: 10
+ size: 45 45
+ Button
+ id: SelectButton
+ size: 70 20
+ anchors.left: CharmBase.right
+ anchors.bottom: CharmBase.bottom
+ margin-left: 5
+ !text: tr('Select')
+ //font: verdana-bold-8px-antialiased
+ text-offset: 0 -1
+ color: #C0C0C0
+ ComboBox
+ id: CharmSelector
+ anchors.left: SelectButton.left
+ anchors.right: ProgressBorder3.right
+ anchors.top: CharmBase.top
+ text-align: center
+ enabled: false
+ @onSetup: |
+ self:addOption("?")
+ UIWidget
+ id: BalanceBase
+ anchors.right: CharmSelector.right
+ anchors.left: SelectButton.right
+ anchors.bottom: SelectButton.bottom
+ height: 20
+ margin-left: 5
+ image-source: /images/ui/item
+ image-border: 10
+ UIWidget
+ id: GoldIcon
+ anchors.right: parent.right
+ anchors.verticalCenter: parent.verticalCenter
+ margin-right: 5
+ image-source: /game_cyclopedia/images/icon_gold
+ Label
+ id: GoldBalance
+ anchors.right: GoldIcon.left
+ anchors.verticalCenter: parent.verticalCenter
+ margin-right: 5
+ text-align: right
+ !text: '?'
+ Label
+ id: CharmLabel
+ anchors.bottom: CharmBase.top
+ anchors.left: CharmBase.left
+ margin-bottom: 3
+ text-auto-resize: true
+ !text: tr('Charm Selection:')
+ color: #C7C7C7
+ VerticalSeparator
+ id: IconsSep
+ anchors.horizontalCenter: ProgressBorder2.horizontalCenter
+ anchors.top: ProgressBorder2.bottom
+ anchors.bottom: CharmLabel.top
+ margin-top: 3
+ margin-left: 20
+ UIWidget
+ id: Icon1
+ anchors.top: IconsSep.top
+ anchors.left: IconsSep.right
+ margin-top: 2
+ margin-left: 5
+ image-source: /game_cyclopedia/images/bestiary/icons/monster-icon-hitpoints
+ Label
+ id: Value1
+ anchors.verticalCenter: Icon1.verticalCenter
+ anchors.left: Icon1.right
+ margin-left: 5
+ margin-bottom: 1
+ text-auto-resize: true
+ !text: tr('?')
+ color: #C7C7C7
+ UIWidget
+ id: Icon2
+ anchors.top: Icon1.bottom
+ anchors.left: IconsSep.right
+ margin-top: 7
+ margin-left: 5
+ image-source: /game_cyclopedia/images/bestiary/icons/monster-icon-experience
+ Label
+ id: Value2
+ anchors.verticalCenter: Icon2.verticalCenter
+ anchors.left: Icon2.right
+ margin-left: 5
+ margin-bottom: 1
+ text-auto-resize: true
+ !text: tr('?')
+ color: #C7C7C7
+ UIWidget
+ id: Icon3
+ anchors.top: Icon2.bottom
+ anchors.left: IconsSep.right
+ margin-top: 7
+ margin-left: 5
+ image-source: /game_cyclopedia/images/bestiary/icons/monster-icon-speed
+ Label
+ id: Value3
+ anchors.verticalCenter: Icon3.verticalCenter
+ anchors.left: Icon3.right
+ margin-left: 5
+ margin-bottom: 1
+ text-auto-resize: true
+ !text: tr('?')
+ color: #C7C7C7
+ UIWidget
+ id: Icon4
+ anchors.top: Icon3.bottom
+ anchors.left: IconsSep.right
+ margin-top: 7
+ margin-left: 5
+ image-source: /game_cyclopedia/images/bestiary/icons/monster-icon-armor
+ Label
+ id: Value4
+ anchors.verticalCenter: Icon4.verticalCenter
+ anchors.left: Icon4.right
+ margin-left: 5
+ margin-bottom: 1
+ text-auto-resize: true
+ !text: tr('?')
+ color: #C7C7C7
+ UIWidget
+ id: Icon5
+ anchors.top: Icon4.bottom
+ anchors.left: IconsSep.right
+ margin-top: 7
+ margin-left: 5
+ image-source: /game_cyclopedia/images/bestiary/icons/monster-icon-mitigation
+ Label
+ id: Value5
+ anchors.verticalCenter: Icon5.verticalCenter
+ anchors.left: Icon5.right
+ margin-left: 5
+ margin-bottom: 1
+ text-auto-resize: true
+ !text: tr('?')
+ color: #C7C7C7
+ UIWidget
+ id: LocationField
+ anchors.left: BalanceBase.right
+ anchors.bottom: BalanceBase.bottom
+ anchors.right: parent.right
+ height: 100
+ image-source: /images/ui/textedit
+ image-border: 10
+ margin-left: 10
+ margin-right: 5
+ ScrollablePanel
+ id: Textlist
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ anchors.left: parent.left
+ anchors.right: parent.right
+ margin-top: 5
+ margin-bottom: 5
+ margin-left: 5
+ margin-right: 20
+ padding-left: 1
+ vertical-scrollbar: TextlistScrollBar
+ layout: verticalBox
+ UIWidget
+ id: Text
+ text-auto-resize: true
+ text-align: left
+ text-wrap: true
+ !text: '?'
+ color: #C7C7C7
+ VerticalScrollBar
+ id: TextlistScrollBar
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ anchors.right: parent.right
+ margin-right: 2
+ margin-top: 2
+ margin-bottom: 2
+ step: 37
+ pixels-scroll: true
+ Label
+ id: LocationLabel
+ anchors.left: LocationField.left
+ anchors.bottom: LocationField.top
+ margin-bottom: 3
+ text-auto-resize: true
+ !text: tr('Location(s)') .. ':'
+ color: #C7C7C7
+ UIWidget
+ id: PhysicalResist
+ image-source: /game_cyclopedia/images/bestiary/icons/monster-icon-physical-resist
+ anchors.left: ProgressBorder3.right
+ anchors.top: parent.top
+ margin-top: 35
+ margin-left: 10
+ BestiaryResistProgress
+ id: PhysicalProgress
+ anchors.left: PhysicalResist.right
+ anchors.bottom: PhysicalResist.bottom
+ margin-left: 5
+ UIWidget
+ id: EarthResist
+ image-source: /game_cyclopedia/images/bestiary/icons/monster-icon-earth-resist
+ anchors.left: PhysicalProgress.right
+ anchors.top: PhysicalResist.top
+ margin-left: 5
+ BestiaryResistProgress
+ id: EarthProgress
+ anchors.left: EarthResist.right
+ anchors.bottom: EarthResist.bottom
+ margin-left: 5
+ UIWidget
+ id: FireResist
+ image-source: /game_cyclopedia/images/bestiary/icons/monster-icon-fire-resist
+ anchors.left: EarthProgress.right
+ anchors.top: PhysicalResist.top
+ margin-left: 5
+ BestiaryResistProgress
+ id: FireProgress
+ anchors.left: FireResist.right
+ anchors.bottom: FireResist.bottom
+ margin-left: 5
+ UIWidget
+ id: DeathResist
+ image-source: /game_cyclopedia/images/bestiary/icons/monster-icon-death-resist
+ anchors.left: FireProgress.right
+ anchors.top: PhysicalResist.top
+ margin-left: 5
+ BestiaryResistProgress
+ id: DeathProgress
+ anchors.left: DeathResist.right
+ anchors.bottom: DeathResist.bottom
+ margin-left: 5
+ UIWidget
+ id: EnergyResist
+ image-source: /game_cyclopedia/images/bestiary/icons/monster-icon-energy-resist
+ anchors.left: ProgressBorder3.right
+ anchors.top: PhysicalResist.bottom
+ margin-top: 10
+ margin-left: 10
+ BestiaryResistProgress
+ id: EnergyProgress
+ anchors.left: EnergyResist.right
+ anchors.bottom: EnergyResist.bottom
+ margin-left: 5
+
+
+ UIWidget
+ id: HolyResist
+ image-source: /game_cyclopedia/images/bestiary/icons/monster-icon-holy-resist
+ anchors.left: EnergyProgress.right
+ anchors.top: EnergyResist.top
+ margin-left: 5
+ BestiaryResistProgress
+ id: HolyProgress
+ anchors.left: HolyResist.right
+ anchors.bottom: HolyResist.bottom
+ margin-left: 5
+ UIWidget
+ id: IceResist
+ image-source: /game_cyclopedia/images/bestiary/icons/monster-icon-ice-resist
+ anchors.left: HolyProgress.right
+ anchors.top: EnergyResist.top
+ margin-left: 5
+ BestiaryResistProgress
+ id: IceProgress
+ anchors.left: IceResist.right
+ anchors.bottom: IceResist.bottom
+ margin-left: 5
+ UIWidget
+ id: HealingResist
+ image-source: /game_cyclopedia/images/bestiary/icons/monster-icon-healing-resist
+ anchors.left: IceProgress.right
+ anchors.top: EnergyResist.top
+ margin-left: 5
+ BestiaryResistProgress
+ id: HealingProgress
+ anchors.left: HealingResist.right
+ anchors.bottom: HealingResist.bottom
+ margin-left: 5
+ UIWidget
+ id: ItemsBase
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.top: LeftBase.bottom
+ anchors.bottom: parent.bottom
+ margin-top: 5
+ margin-bottom: 5
+ margin-left: 5
+ margin-right: 5
+ image-source: /game_cyclopedia/images/panel_flat
+ image-border: 10
+ UIScrollArea
+ id: Itemlist
+ anchors.fill: parent
+ margin-bottom: 5
+ margin-left: 5
+ margin-right: 20
+ padding-top: 5
+ auto-focus: first
+ vertical-scrollbar: ItemlistScrollBar
+ layout: verticalBox
+ VerticalScrollBar
+ id: ItemlistScrollBar
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ anchors.right: parent.right
+ margin-right: 2
+ margin-top: 2
+ margin-bottom: 2
+ step: 37
+ pixels-scroll: true
+
+
+
+
+
diff --git a/modules/game_cyclopedia/tab/boss_slots/boss_slots.lua b/modules/game_cyclopedia/tab/boss_slots/boss_slots.lua
new file mode 100644
index 0000000000..10bd8d68c8
--- /dev/null
+++ b/modules/game_cyclopedia/tab/boss_slots/boss_slots.lua
@@ -0,0 +1,431 @@
+local UI = nil
+
+function showBossSlot()
+ UI = g_ui.loadUI("boss_slots", contentContainer)
+ UI:show()
+ UI.RightBase.LockLabel:setText("Unlocks at 1500 Boss Points")
+ g_game.requestBossSlootInfo()
+ controllerCyclopedia.ui.CharmsBase:setVisible(false)
+ controllerCyclopedia.ui.GoldBase:setVisible(true)
+ controllerCyclopedia.ui.BestiaryTrackerButton:setVisible(false)
+ Cyclopedia.BossSlots.UnlockBosses = {}
+end
+
+local CATEGORY = {
+ BANE = 0,
+ NEMESIS = 2,
+ ARCHFOE = 1
+}
+
+local SLOT_STATE = {
+ EMPTY = 1,
+ LOCKED = 0,
+ ACTIVE = 2
+}
+
+local ICONS = {
+ [CATEGORY.BANE] = "/game_cyclopedia/images/boss/icon_bane",
+ [CATEGORY.ARCHFOE] = "/game_cyclopedia/images/boss/icon_archfoe",
+ [CATEGORY.NEMESIS] = "/game_cyclopedia/images/boss/icon_nemesis"
+}
+
+local SLOTS = {
+ [1] = "LeftBase",
+ [2] = "RightBase"
+}
+
+local CONFIG = {
+ [0] = {
+ EXPERTISE = 100,
+ PROWESS = 25,
+ MASTERY = 300
+ },
+ {
+ EXPERTISE = 20,
+ PROWESS = 5,
+ MASTERY = 60
+ },
+ {
+ EXPERTISE = 3,
+ PROWESS = 1,
+ MASTERY = 5
+ }
+}
+
+Cyclopedia.BossSlots = {}
+
+function Cyclopedia.loadBossSlots(data)
+ if not UI or not UI.Sprite then
+ return
+ end
+
+ if not RACE_Bosstiary[data.boostedBossId] then
+ g_logger.warning(string.format("Race id: %d not found. add in ./modules/game_cyclopedia/utils.lua", data.id))
+ end
+
+ local raceData = RACE_Bosstiary[data.boostedBossId]
+ UI.Sprite:setOutfit({
+ type = Cyclopedia.safeOutfit(raceData and raceData.type or 22)
+ })
+
+ UI.Sprite:getCreature():setStaticWalking(1000)
+ UI.TopBase.InfoLabel:setText(string.format("Equipment Loot Bonus: %d%% Next: %d%%", data.currentBonus,
+ data.nextBonus))
+
+ local fullText = ""
+ if data.playerPoints >= CONFIG[data.todaySlotData.bossRace].MASTERY then
+ fullText = "(fully unlocked)"
+ end
+
+ local progress = UI.BoostedProgress
+ progress.ProgressBorder1:setTooltip(string.format(" %d / %d %s", data.playerPoints,
+ CONFIG[data.todaySlotData.bossRace].PROWESS, fullText))
+ progress.ProgressBorder2:setTooltip(string.format(" %d / %d %s", data.playerPoints,
+ CONFIG[data.todaySlotData.bossRace].EXPERTISE, fullText))
+ progress.ProgressBorder3:setTooltip(string.format(" %d / %d %s", data.playerPoints,
+ CONFIG[data.todaySlotData.bossRace].MASTERY, fullText))
+
+ if data.playerPoints >= CONFIG[data.todaySlotData.bossRace].PROWESS then
+ progress.bronzeStar:setImageSource("/game_cyclopedia/images/boss/icon_star_bronze")
+ else
+ progress.bronzeStar:setImageSource("/game_cyclopedia/images/boss/icon_star_dark")
+ end
+
+ if data.playerPoints >= CONFIG[data.todaySlotData.bossRace].EXPERTISE then
+ progress.silverStar:setImageSource("/game_cyclopedia/images/boss/icon_star_silver")
+ else
+ progress.silverStar:setImageSource("/game_cyclopedia/images/boss/icon_star_dark")
+ end
+
+ if data.playerPoints >= CONFIG[data.todaySlotData.bossRace].MASTERY then
+ progress.goldStar:setImageSource("/game_cyclopedia/images/boss/icon_star_gold")
+ else
+ progress.goldStar:setImageSource("/game_cyclopedia/images/boss/icon_star_dark")
+ end
+
+ UI.MainLabel:setText(string.format("Equipment loot bonus: %d%%\nKill bonus: %dx", data.todaySlotData.lootBonus,
+ data.todaySlotData.killBonus))
+
+ Cyclopedia.setBosstiarySlotsProgress(data.playerPoints, data.totalPointsNextBonus)
+
+ local function format(string)
+ if #string > 18 then
+ return string:sub(1, 15) .. "..."
+ else
+ return string
+ end
+ end
+
+ local unlockedBosses = data.bossIdSlotTwo
+
+ UI.MidTitle:setText(string.format("Boosted Boss: %s", format(RACE_Bosstiary[data.boostedBossId].name)))
+ Cyclopedia.setBosstiarySlotsBossProgress(UI.BoostedProgress, data.todaySlotData.killCount,
+ CONFIG[data.todaySlotData.bossRace].MASTERY)
+ UI.TypeIcon:setImageSource(ICONS[data.todaySlotData.bossRace])
+
+ local tooltip =
+ "Bane\n\nFor unlocking a level, you will receive the following boss points:\nProwess: 5\nExpertise: 15\nMastery: 30"
+
+ tooltip = data.todaySlotData.bossRace == CATEGORY.ARCHFOE and
+ "Archfoe\n\nFor unlocking a level, you will receive the following boss points:\nProwess: 10\nExpertise: 30\nMastery: 60" or
+ "Nemesis\n\nFor unlocking a level, you will receive the following boss points:\nProwess: 10\nExpertise: 30\nMastery: 60"
+
+ UI.TypeIcon:setTooltip(tooltip)
+ -- UI.TypeIcon:setTooltipAlign(AlignTopLeft)
+
+ for i, unlockData in ipairs(data.bossesUnlockedData) do
+ if not unlockData then
+ break
+ end
+
+ local raceData = RACE_Bosstiary[unlockData.bossId]
+ if raceData then
+ local data_t = {
+ visible = true,
+ bossId = unlockData.bossId,
+ category = unlockData.bossRace,
+ name = raceData.name
+ }
+
+ table.insert(Cyclopedia.BossSlots.UnlockBosses, data_t)
+ end
+ end
+
+ if Cyclopedia.BossSlots.UnlockBosses then
+ table.sort(Cyclopedia.BossSlots.UnlockBosses, function(a, b)
+ return a.name < b.name
+ end)
+
+ if data.isSlotOneUnlocked or data.isSlotTwoUnlocked then
+ Cyclopedia.BossSlotChangeSlot(data, unlockedBosses)
+ end
+ end
+end
+
+function Cyclopedia.BossSlotChangeSlot(data, unlockedBosses)
+ local slots = {{
+ isUnlocked = data.isSlotOneUnlocked,
+ slotNumber = 1,
+ slotData = data.slotOneData,
+ bossId = data.bossIdSlotOne
+ }, {
+ isUnlocked = data.isSlotTwoUnlocked,
+ slotNumber = 2,
+ slotData = data.slotTwoData,
+ bossId = data.bossIdSlotTwo
+ }}
+
+ for _, slotInfo in ipairs(slots) do
+ if slotInfo.isUnlocked then
+ local widget = UI[SLOTS[slotInfo.slotNumber]]
+
+ if slotInfo.slotData then
+ Cyclopedia.setActiveSlot(widget, slotInfo.slotNumber, slotInfo.slotData, data, slotInfo.bossId)
+ elseif data.bossesUnlocked and #data.bossesUnlockedData > 0 then
+ Cyclopedia.setLockedSlot(widget, slotInfo.slotNumber, unlockedBosses)
+ else
+ Cyclopedia.setEmptySlot(widget, slotInfo.slotNumber, slotInfo.bossId)
+ end
+ end
+ end
+end
+
+function Cyclopedia.setEmptySlot(widget, slot, bossIdSlotTwo)
+ widget.LockLabel:setVisible(true)
+ widget.SelectBoss:setVisible(false)
+ widget.ActivedBoss:setVisible(false)
+ widget:setText(string.format("Slot %d: Locked", slot))
+ widget.LockLabel:setText(string.format("Unlocks at %d Boss Points", bossIdSlotTwo))
+end
+
+function Cyclopedia.setLockedSlot(widget, slot, unlockedBosses)
+ widget.LockLabel:setVisible(false)
+ widget.SelectBoss:setVisible(true)
+ widget.ActivedBoss:setVisible(false)
+ widget:setText(string.format("Slot %d: Select Boss", slot))
+ widget.SelectBoss.ListBase.List:destroyChildren()
+
+ local function format(string)
+ if #string > 12 then
+ return string:sub(1, 9) .. "..."
+ else
+ return string
+ end
+ end
+
+ for _, internalData in ipairs(Cyclopedia.BossSlots.UnlockBosses) do
+ local internalWidget = g_ui.createWidget("SelectBossBossSlots", widget.SelectBoss.ListBase.List)
+ internalWidget:setId(internalData.bossId)
+ internalWidget.Sprite:setOutfit({
+ type = Cyclopedia.safeOutfit(RACE_Bosstiary[internalData.bossId] and RACE_Bosstiary[internalData.bossId].type or 22)
+ })
+ internalWidget:setText(format(RACE_Bosstiary[internalData.bossId].name))
+ internalWidget.Sprite:getCreature():setStaticWalking(1000)
+ internalWidget.TypeIcon:setImageSource(ICONS[internalData.category])
+
+ local tooltip = internalData.category == CATEGORY.ARCHFOE and
+ "Archfoe\n\nFor unlocking a level, you will receive the following boss points:\nProwess: 10\nExpertise: 30\nMastery: 60" or
+ "Nemesis\n\nFor unlocking a level, you will receive the following boss points:\nProwess: 10\nExpertise: 30\nMastery: 60"
+
+ if internalData.category ~= CATEGORY.ARCHFOE then
+ tooltip =
+ "Bane\n\nFor unlocking a level, you will receive the following boss points:\nProwess: 5\nExpertise: 15\nMastery: 30"
+ end
+
+ internalWidget.TypeIcon:setTooltip(tooltip)
+ end
+
+ widget.SelectBoss.SelectButton:setEnabled(false)
+ widget.SelectBoss.SelectButton.onClick = function()
+ g_game.requestBossSlotAction(slot, Cyclopedia.BossSlots.lastSelected:getId())
+ Cyclopedia.BossSlots.UnlockBosses = {}
+ end
+end
+
+function Cyclopedia.setActiveSlot(widget, slot, slotData, data, bossId)
+ widget.LockLabel:setVisible(false)
+ widget.SelectBoss:setVisible(false)
+ widget.ActivedBoss:setVisible(true)
+ widget:setText(string.format("Slot %d: %s", slot, RACE_Bosstiary[bossId].name))
+ widget.ActivedBoss.TypeIcon:setImageSource(ICONS[slotData.bossRace])
+
+ Cyclopedia.setBosstiarySlotsBossProgress(widget.ActivedBoss.Progress, slotData.killBonus,
+ CONFIG[slotData.bossRace].MASTERY)
+
+ local tooltip = slotData.bossRace == CATEGORY.ARCHFOE and
+ "Archfoe\n\nFor unlocking a level, you will receive the following boss points:\nProwess: 10\nExpertise: 30\nMastery: 60" or
+ "Nemesis\n\nFor unlocking a level, you will receive the following boss points:\nProwess: 10\nExpertise: 30\nMastery: 60"
+
+ if slotData.bossRace ~= CATEGORY.ARCHFOE then
+ tooltip =
+ "Bane\n\nFor unlocking a level, you will receive the following boss points:\nProwess: 5\nExpertise: 15\nMastery: 30"
+ end
+
+ widget.ActivedBoss.TypeIcon:setTooltip(tooltip)
+ widget.ActivedBoss.Progress.ProgressBorder1:setTooltip()
+
+ local fullText = slotData.killBonus >= CONFIG[slotData.bossRace].MASTERY and "(fully unlocked)" or ""
+
+ local progress = widget.ActivedBoss.Progress
+ progress.ProgressBorder1:setTooltip(string.format(" %d / %d %s", slotData.killBonus,
+ CONFIG[slotData.bossRace].PROWESS, fullText))
+ progress.ProgressBorder2:setTooltip(string.format(" %d / %d %s", slotData.killBonus,
+ CONFIG[slotData.bossRace].EXPERTISE, fullText))
+ progress.ProgressBorder3:setTooltip(string.format(" %d / %d %s", slotData.killBonus,
+ CONFIG[slotData.bossRace].MASTERY, fullText))
+
+ progress.bronzeStar:setImageSource(slotData.killBonus >= CONFIG[slotData.bossRace].PROWESS and
+ "/game_cyclopedia/images/boss/icon_star_bronze" or
+ "/game_cyclopedia/images/boss/icon_star_dark")
+ progress.silverStar:setImageSource(slotData.killBonus >= CONFIG[slotData.bossRace].EXPERTISE and
+ "/game_cyclopedia/images/boss/icon_star_silver" or
+ "/game_cyclopedia/images/boss/icon_star_dark")
+ progress.goldStar:setImageSource(slotData.killBonus >= CONFIG[slotData.bossRace].MASTERY and
+ "/game_cyclopedia/images/boss/icon_star_gold" or
+ "/game_cyclopedia/images/boss/icon_star_dark")
+
+ widget.ActivedBoss.Sprite:setOutfit({
+ type = Cyclopedia.safeOutfit(RACE_Bosstiary[bossId] and RACE_Bosstiary[bossId].type or 22)
+ })
+ widget.ActivedBoss.Sprite:getCreature():setStaticWalking(1000)
+ widget.ActivedBoss.EquipmentLabel:setText(string.format("Equipment loot bonus: %d%%", slotData.lootBonus))
+ widget.ActivedBoss.Value:setText(comma_value(slotData.removePrice))
+
+ if g_game.getLocalPlayer():getResourceBalance(1) ~= nil then
+ if slotData.removePrice > g_game.getLocalPlayer():getResourceBalance(1) then
+ widget.ActivedBoss.Value:setColor("#D33C3C")
+ widget.ActivedBoss.RemoveButton:setEnabled(false)
+ else
+ widget.ActivedBoss.Value:setColor("#C0C0C0")
+ widget.ActivedBoss.RemoveButton:setEnabled(true)
+ end
+ end
+
+ widget.ActivedBoss.RemoveButton.onClick = function()
+ g_game.requestBossSlotAction(slot, 0)
+ end
+
+ widget.ActivedBoss.RemoveButton:setTooltip(string.format(
+ "It will cost you %s gold to remove the currently selected boss from this slot.",
+ comma_value(slotData.removePrice)))
+end
+
+function Cyclopedia.setBosstiarySlotsProgress(value, maxValue)
+ local rect = {
+ height = 18,
+ x = 0,
+ y = 0,
+ width = (maxValue < value and maxValue or value) / maxValue * 278
+ }
+
+ if value >= 0 and rect.width < 1 then
+ rect.width = 1
+ end
+
+ UI.TopBase.PointsBar.fill:setImageRect(rect)
+ UI.TopBase.PointsBar.Value:setText(string.format("%d/%d", value, maxValue))
+end
+
+function Cyclopedia.setBosstiarySlotsBossProgress(object, value, maxValue)
+ local rect = {
+ height = 12,
+ x = 0,
+ y = 0,
+ width = (maxValue < value and maxValue or value) / maxValue * 126
+ }
+
+ if value >= 0 and rect.width < 1 then
+ object.fill:setVisible(false)
+ else
+ object.fill:setVisible(true)
+ end
+
+ object.fill:setImageRect(rect)
+ object.ProgressValue:setText(value)
+
+ if maxValue <= value then
+ object.fill:setImageSource("/game_cyclopedia/images/bestiary/fill")
+ end
+end
+
+function Cyclopedia.bossSlotSelectBoss(widget)
+ local button = widget:getParent():getParent():getParent().SelectButton
+
+ for i = 1, widget:getParent():getChildCount() do
+ local child = widget:getParent():getChildByIndex(i)
+ child:setChecked(false)
+ end
+
+ widget:setChecked(true)
+ Cyclopedia.BossSlots.lastSelected = widget
+ button:setEnabled(true)
+end
+
+function Cyclopedia.readjustSelectBoss()
+ local slot = 1
+ if not UI.LeftBase.SelectBoss:isVisible() then
+ slot = 2
+ end
+
+ local icons = {
+ [CATEGORY.BANE] = "/game_cyclopedia/images/boss/icon_bane",
+ [CATEGORY.ARCHFOE] = "/game_cyclopedia/images/boss/icon_archfoe",
+ [CATEGORY.NEMESIS] = "/game_cyclopedia/images/boss/icon_nemesis"
+ }
+
+ local function format(string)
+ if #string > 12 then
+ return string:sub(1, 9) .. "..."
+ else
+ return string
+ end
+ end
+
+ local widget = UI[SLOTS[slot]]
+ widget.SelectBoss.ListBase.List:destroyChildren()
+
+ for _, internalData in ipairs(Cyclopedia.BossSlots.UnlockBosses) do
+ if internalData.visible then
+ local internalWidget = g_ui.createWidget("SelectBossBossSlots", widget.SelectBoss.ListBase.List)
+ internalWidget.Sprite:setOutfit({
+ type = Cyclopedia.safeOutfit(RACE_Bosstiary[internalData.bossId] and RACE_Bosstiary[internalData.bossId].type or 22)
+ })
+ internalWidget:setText(format(RACE_Bosstiary[internalData.bossId].name))
+ internalWidget.Sprite:getCreature():setStaticWalking(1000)
+ internalWidget.TypeIcon:setImageSource(icons[internalData.category])
+
+ local tooltip =
+ "Bane\n\nFor unlocking a level, you will receive the following boss points:\nProwess: 5\nExpertise: 15\nMastery: 30"
+
+ tooltip = internalData.category == CATEGORY.ARCHFOE and
+ "Archfoe\n\nFor unlocking a level, you will receive the following boss points:\nProwess: 10\nExpertise: 30\nMastery: 60" or
+ "Nemesis\n\nFor unlocking a level, you will receive the following boss points:\nProwess: 10\nExpertise: 30\nMastery: 60"
+
+ internalWidget.TypeIcon:setTooltip(tooltip)
+ end
+ end
+
+ widget.SelectBoss.SelectButton:setEnabled(false)
+end
+
+function Cyclopedia.SelectBossSearchText(text, clear, widget)
+ if clear then
+ widget:getParent().SearchEdit:setText("")
+ end
+
+ if text ~= "" then
+ for _, creature in ipairs(Cyclopedia.BossSlots.UnlockBosses) do
+ if string.find(creature.name:lower(), text:lower()) == nil then
+ creature.visible = false
+ else
+ creature.visible = true
+ end
+ end
+ else
+ for _, creature in ipairs(Cyclopedia.BossSlots.UnlockBosses) do
+ creature.visible = true
+ end
+ end
+
+ Cyclopedia.readjustSelectBoss()
+end
diff --git a/modules/game_cyclopedia/tab/boss_slots/boss_slots.otui b/modules/game_cyclopedia/tab/boss_slots/boss_slots.otui
new file mode 100644
index 0000000000..1cbd539aa5
--- /dev/null
+++ b/modules/game_cyclopedia/tab/boss_slots/boss_slots.otui
@@ -0,0 +1,121 @@
+UIWidget
+ id: Cat8
+ anchors.fill: parent
+ visible: false
+ UIWidget
+ id: TopBase
+ anchors.left: parent.left
+ anchors.top: parent.top
+ anchors.right: parent.right
+ margin-top: 10
+ height: 50
+ image-source: /images/ui/window_new
+ image-border: 10
+ color: #929292
+ text-offset: 0 3
+ text-align: top
+ !text: tr('Progress')
+ Label
+ id: PointsLabel
+ anchors.left: parent.left
+ anchors.bottom: parent.bottom
+ margin-left: 10
+ margin-bottom: 10
+ !text: tr('Boss Points')
+ color: #C0C0C0
+ text-auto-resize: true
+ ProgressBackground
+ id: PointsBar
+ size: 278 20
+ anchors.left: PointsLabel.right
+ anchors.verticalCenter: PointsLabel.verticalCenter
+ margin-left: 10
+ image-border: 5
+ UIWidget
+ id: fill
+ anchors.left: parent.left
+ anchors.top: parent.top
+ image-border: 5
+ image-source: /game_cyclopedia/images/boss/fill
+ Label
+ id: Value
+ anchors.centerIn: parent
+ text-auto-resize: true
+ !text: tr('0 / 0')
+ UIWidget
+ id: InfoIcon
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ margin-right: 10
+ margin-bottom: 10
+ image-source:/images/icons/show_gui_help_grey
+ !tooltip: ('Whenever you defat a creature, it drops a set of loot with a\ncertain chance. The equipment loot bonus shows your chance to\nget a second set of loot, but limited to equipment.')
+ Label
+ id: InfoLabel
+ anchors.right: InfoIcon.left
+ anchors.bottom: parent.bottom
+ margin-right: 35
+ margin-bottom: 9
+ text-auto-resize: true
+ !text: tr('')
+ SlotBossSlots
+ id: LeftBase
+ !text: tr('Slot 1: Locked')
+ anchors.left: parent.left
+ anchors.top: TopBase.bottom
+ margin-top: 10
+ margin-bottom: 10
+ SlotBossSlots
+ id: RightBase
+ anchors.right: parent.right
+ anchors.top: TopBase.bottom
+ margin-top: 10
+ margin-bottom: 10
+ !text: tr('Slot 2: Locked')
+ Label
+ id: MidTitle
+ anchors.left: LeftBase.right
+ anchors.right: RightBase.left
+ anchors.top: RightBase.top
+ !text: tr('Boosted Boss: The Source Of Co...')
+ color: #C0C0C0
+ margin-left: 5
+ UIWidget
+ id: PedestalBase
+ anchors.top: parent.top
+ anchors.horizontalCenter: parent.horizontalCenter
+ margin-top: 100
+ image-source: /game_cyclopedia/images/boss/boss_base
+ UICreature
+ id: Sprite
+ size: 64 64
+ anchors.centerIn: PedestalBase
+ margin-bottom: 15
+ margin-right: 15
+ UIWidget
+ id: TypeIcon
+ anchors.top: PedestalBase.top
+ anchors.right: PedestalBase.left
+ margin-right: 25
+ margin-top: 2
+ image-source: /game_cyclopedia/images/boss/icon_archfoe
+ BossSlotProgress
+ id: BoostedProgress
+ anchors.top: PedestalBase.bottom
+ anchors.horizontalCenter: PedestalBase.horizontalCenter
+ margin-top: 25
+ Label
+ anchors.horizontalCenter: BoostedProgress.horizontalCenter
+ anchors.bottom: BoostedProgress.top
+ margin-bottom: 3
+ text-auto-resize: true
+ !text: tr('Total Kills')
+ color: #BEBEBE
+ Label
+ id: MainLabel
+ anchors.centerIn: parent
+ margin-top: 45
+ text-auto-resize: true
+ text-align: center
+ !text: tr('')
+ color: #C2C2C2
diff --git a/modules/game_cyclopedia/tab/bosstiary/bosstiary.lua b/modules/game_cyclopedia/tab/bosstiary/bosstiary.lua
new file mode 100644
index 0000000000..cd51e198a2
--- /dev/null
+++ b/modules/game_cyclopedia/tab/bosstiary/bosstiary.lua
@@ -0,0 +1,443 @@
+local UI = nil
+function showBosstiary()
+ UI = g_ui.loadUI("bosstiary", contentContainer)
+ UI:show()
+ g_game.requestBosstiaryInfo()
+ UI.FilterBase.BaneIcon:setTooltip(
+ "Bane\n\nFor unlocking a level, you will receive the following boss points:\nProwess: 5\nExpertise: 15\nMastery: 30")
+ -- UI.FilterBase.BaneIcon:setTooltipAlign(AlignTopLeft)
+ UI.FilterBase.ArchfoeIcon:setTooltip(
+ "Archfoe\n\nFor unlocking a level, you will receive the following boss points:\nProwess: 10\nExpertise: 30\nMastery: 60")
+ -- UI.FilterBase.ArchfoeIcon:setTooltipAlign(AlignTopLeft)
+ UI.FilterBase.NemesisIcon:setTooltip(
+ "Nemesis\n\nFor unlocking a level, you will receive the following boss points:\nProwess: 10\nExpertise: 30\nMastery: 60")
+ -- UI.FilterBase.NemesisIcon:setTooltipAlign(AlignTopLeft)
+ UI.StarBase.Info1:setTooltip("Once you have reached the Prowess level, you can assign the boss\nto a boss slot.")
+ -- UI.StarBase.Info1:setTooltipAlign(AlignTopLeft)
+ UI.StarBase.Info2:setTooltip(
+ "Once you have reached the Expertise Level, you can display the\nboss on a Podium of Vigour.")
+ -- UI.StarBase.Info2:setTooltipAlign(AlignTopLeft)
+ UI.StarBase.Info3:setTooltip(
+ "Once you have reached the Mastery Level, youl will receive an\nadditional 25% loot bonus when the boss is assigned to a boss slot.")
+ -- UI.StarBase.Info3:setTooltipAlign(AlignTopLeft)
+ controllerCyclopedia.ui.CharmsBase:setVisible(false)
+ controllerCyclopedia.ui.GoldBase:setVisible(false)
+ controllerCyclopedia.ui.BestiaryTrackerButton:setVisible(false)
+end
+
+Cyclopedia.Bosstiary = {}
+
+local CATEGORY = {
+ BANE = 0,
+ NEMESIS = 2,
+ ARCHFOE = 1
+}
+local CONFIG = {
+ [0] = {
+ EXPERTISE = 100,
+ PROWESS = 25,
+ MASTERY = 300
+ },
+ {
+ EXPERTISE = 20,
+ PROWESS = 5,
+ MASTERY = 60
+ },
+ {
+ EXPERTISE = 3,
+ PROWESS = 1,
+ MASTERY = 5
+ }
+}
+
+--[[ function Cyclopedia.SetBosstiaryProgress(object, value, maxValue)
+ local rect = {
+ height = 12,
+ x = 0,
+ y = 0,
+ width = (maxValue < value and maxValue or value) / maxValue * 141
+ }
+
+ if value >= 0 and rect.width < 1 then
+ object.fill:setVisible(false)
+ else
+ object.fill:setVisible(true)
+ end
+
+ object.fill:setImageRect(rect)
+ object.ProgressValue:setText(value)
+ object.fill:setImageSource("/game_cyclopedia/images/bestiary/fill")
+
+end ]]
+
+function Cyclopedia.CreateBosstiaryCreature(data)
+ if not data.visible then
+ return
+ end
+
+ local widget = g_ui.createWidget("BosstiaryItem", UI.ListBase.BossList)
+ widget:setId(data.raceId)
+ local raceData = RACE_Bosstiary[data.raceId]
+ local icons = {
+ [CATEGORY.BANE] = "/game_cyclopedia/images/boss/icon_bane",
+ [CATEGORY.ARCHFOE] = "/game_cyclopedia/images/boss/icon_archfoe",
+ [CATEGORY.NEMESIS] = "/game_cyclopedia/images/boss/icon_nemesis"
+ }
+
+ local function format(string)
+ if #string > 19 then
+ return string:sub(1, 16) .. "..."
+ else
+ return string
+ end
+ end
+
+ local fullText = ""
+
+ if data.kills >= CONFIG[data.category].MASTERY then
+ fullText = "(fully unlocked)"
+ end
+
+ widget.ProgressBorder1:setTooltip(string.format(" %d / %d %s", data.kills, CONFIG[data.category].PROWESS, fullText))
+ widget.ProgressBorder2:setTooltip(
+ string.format(" %d / %d %s", data.kills, CONFIG[data.category].EXPERTISE, fullText))
+ widget.ProgressBorder3:setTooltip(string.format(" %d / %d %s", data.kills, CONFIG[data.category].MASTERY, fullText))
+
+ if data.kills >= CONFIG[data.category].PROWESS then
+ widget.bronzeStar:setImageSource("/game_cyclopedia/images/boss/icon_star_bronze")
+ else
+ widget.silverStar:setImageSource("/game_cyclopedia/images/boss/icon_star_dark")
+ end
+
+ if data.kills >= CONFIG[data.category].EXPERTISE then
+ widget.silverStar:setImageSource("/game_cyclopedia/images/boss/icon_star_silver")
+ else
+ widget.silverStar:setImageSource("/game_cyclopedia/images/boss/icon_star_dark")
+ end
+
+ if data.kills >= CONFIG[data.category].MASTERY then
+ widget.goldStar:setImageSource("/game_cyclopedia/images/boss/icon_star_gold")
+ else
+ widget.goldStar:setImageSource("/game_cyclopedia/images/boss/icon_star_dark")
+ end
+
+ widget.TypeIcon:setImageSource(icons[data.category])
+
+ if data.category == CATEGORY.BANE then
+ widget.TypeIcon:setTooltip(
+ "Bane\n\nFor unlocking a level, you will receive the following boss points:\nProwess: 5\nExpertise: 15\nMastery: 30")
+ -- widget.TypeIcon:setTooltipAlign(AlignTopLeft)
+ elseif data.category == CATEGORY.ARCHFOE then
+ widget.TypeIcon:setTooltip(
+ "Archfoe\n\nFor unlocking a level, you will receive the following boss points:\nProwess: 10\nExpertise: 30\nMastery: 60")
+ -- widget.TypeIcon:setTooltipAlign(AlignTopLeft)
+ elseif data.category == CATEGORY.NEMESIS then
+ widget.TypeIcon:setTooltip(
+ "Nemesis\n\nFor unlocking a level, you will receive the following boss points:\nProwess: 10\nExpertise: 30\nMastery: 60")
+ -- widget.TypeIcon:setTooltipAlign(AlignTopLeft)
+ end
+ widget.ProgressValue:setText(data.kills)
+
+ Cyclopedia.SetBestiaryProgress(46,widget.ProgressBack, widget.ProgressBack33, widget.ProgressBack55, data.kills, CONFIG[data.category].PROWESS, CONFIG[data.category].EXPERTISE, CONFIG[data.category].MASTERY)
+
+ if raceData then
+ widget.Sprite:setOutfit({
+ type = Cyclopedia.safeOutfit(raceData.type)
+ })
+ widget.Sprite:getCreature():setStaticWalking(1000)
+ if data.unlocked then
+ widget.Sprite:getCreature():setShader("")
+ widget:setText(format(data.name))
+ widget.TrackCheck:enable()
+ if data.isTrackerActived == 1 then
+ widget.TrackCheck:setChecked(true)
+ else
+ widget.TrackCheck:setChecked(false)
+ end
+ else
+ widget.Sprite:getCreature():setShader("Outfit - cyclopedia-black")
+ widget.TrackCheck:disable()
+
+ end
+
+ end
+
+end
+
+function Cyclopedia.LoadBoostiaryCreatures(data)
+ if not UI then
+ return
+ end
+ local maxCategoriesPerPage = 8
+
+ Cyclopedia.Bosstiary.Creatures = {}
+ Cyclopedia.Bosstiary.NotVisibleCreatures = {}
+ Cyclopedia.Bosstiary.Page = 1
+ Cyclopedia.Bosstiary.TotalPages = math.ceil(#data / maxCategoriesPerPage)
+
+ UI.PageValue:setText(string.format("%d / %d", Cyclopedia.Bosstiary.Page, Cyclopedia.Bosstiary.TotalPages))
+
+ local page = 1
+
+ Cyclopedia.Bosstiary.Creatures[page] = {}
+
+ local validCreatures = {}
+ local invalidCreatures = {}
+
+ for i, dataEntry in ipairs(data) do
+ local raceData = RACE_Bosstiary[dataEntry.raceId]
+ local creature = {
+ visible = true,
+ raceId = dataEntry.raceId,
+ name = raceData and raceData.name or "?",
+ kills = dataEntry.kills,
+ category = dataEntry.category,
+ isTrackerActived = dataEntry.isTrackerActived,
+ unlocked = dataEntry.kills > 0 and true or false
+ }
+
+ if raceData then
+ table.insert(validCreatures, creature)
+ else
+ table.insert(invalidCreatures, creature)
+ end
+ end
+
+ for _, value in pairs(invalidCreatures) do
+ table.insert(validCreatures, value)
+ end
+
+ table.sort(validCreatures, function(a, b)
+ if a.name == "?" and b.name ~= "?" then
+ return false
+ elseif a.name ~= "?" and b.name == "?" then
+ return true
+ elseif a.unlocked and not b.unlocked then
+ return true
+ elseif not a.unlocked and b.unlocked then
+ return false
+ else
+ return a.name < b.name
+ end
+ end)
+
+ for i = 1, #validCreatures do
+ local creature = validCreatures[i]
+
+ if creature.visible then
+ table.insert(Cyclopedia.Bosstiary.Creatures[page], creature)
+ else
+ table.insert(Cyclopedia.Bosstiary.NotVisibleCreatures[page], creature)
+ end
+
+ if i % maxCategoriesPerPage == 0 and i < #validCreatures then
+ page = page + 1
+ Cyclopedia.Bosstiary.Creatures[page] = {}
+ end
+ end
+
+ Cyclopedia.LoadBoostiaryCreature(Cyclopedia.Bosstiary.Page)
+ Cyclopedia.verifyBosstiaryButtons()
+end
+
+function Cyclopedia.LoadBoostiaryCreature(page)
+ if not Cyclopedia.Bosstiary.Creatures[page] then
+ return
+ end
+
+ UI.ListBase.BossList:destroyChildren()
+
+ for _, data in ipairs(Cyclopedia.Bosstiary.Creatures[page]) do
+ Cyclopedia.CreateBosstiaryCreature(data)
+ end
+end
+
+function Cyclopedia.verifyBosstiaryButtons()
+ local page = Cyclopedia.Bosstiary.Page
+ local totalPages = Cyclopedia.Bosstiary.TotalPages
+
+ local function updateButtonState(button, condition)
+ if condition then
+ button:enable()
+ else
+ button:disable()
+ end
+ end
+
+ local function updatePageValue(currentPage, maxPages)
+ UI.PageValue:setText(string.format("%d / %d", currentPage, maxPages))
+ end
+
+ updateButtonState(UI.PrevPageButton, page > 1)
+ updateButtonState(UI.NextPageButton, page < totalPages)
+ updatePageValue(page, totalPages)
+end
+
+function Cyclopedia.changeBosstiaryPage(prev, next)
+ if next then
+ Cyclopedia.Bosstiary.Page = Cyclopedia.Bosstiary.Page + 1
+ end
+
+ if prev then
+ Cyclopedia.Bosstiary.Page = Cyclopedia.Bosstiary.Page - 1
+ end
+
+ Cyclopedia.LoadBoostiaryCreature(Cyclopedia.Bosstiary.Page)
+ Cyclopedia.verifyBosstiaryButtons()
+end
+
+function Cyclopedia.BosstiarySearchText(text, clear)
+ local allCreatures = {}
+
+ if clear then
+ UI.SearchEdit:setText("")
+ end
+
+ for _, creatures in ipairs(Cyclopedia.Bosstiary.Creatures) do
+ for _, creature in ipairs(creatures) do
+ table.insert(allCreatures, creature)
+ end
+ end
+
+ for _, creature in ipairs(Cyclopedia.Bosstiary.NotVisibleCreatures) do
+ table.insert(allCreatures, creature)
+ end
+
+ if text ~= "" then
+ for _, creature in ipairs(allCreatures) do
+ if not creature.unlocked then
+ creature.visible = false
+ elseif string.find(creature.name:lower(), text:lower()) == nil then
+ creature.visible = false
+ else
+ creature.visible = true
+ end
+ end
+ else
+ for _, creature in ipairs(allCreatures) do
+ creature.visible = true
+ end
+ end
+
+ Cyclopedia.ReadjustPages()
+end
+
+function Cyclopedia.changeBosstiaryFilter(widget, isCheck)
+ widget:setChecked(not isCheck)
+
+ local id = widget:getId()
+ local allCreatures = {}
+
+ for _, creatures in ipairs(Cyclopedia.Bosstiary.Creatures) do
+ for _, creature in ipairs(creatures) do
+ table.insert(allCreatures, creature)
+ end
+ end
+
+ for _, creature in ipairs(Cyclopedia.Bosstiary.NotVisibleCreatures) do
+ table.insert(allCreatures, creature)
+ end
+
+ for _, creature in ipairs(allCreatures) do
+ if id == "BaneCheck" then
+ if creature.category == CATEGORY.BANE then
+ creature.visible = widget:isChecked()
+ end
+ elseif id == "ArchfoeCheck" then
+ if creature.category == CATEGORY.ARCHFOE then
+ creature.visible = widget:isChecked()
+ end
+ elseif id == "NemesisCheck" then
+ if creature.category == CATEGORY.NEMESIS then
+ creature.visible = widget:isChecked()
+ end
+ elseif id == "NoKillsCheck" then
+ if creature.kills < 1 then
+ creature.visible = widget:isChecked()
+ end
+ elseif id == "FewKillsCheck" then
+ if creature.kills ~= 0 and creature.kills < CONFIG[creature.category].PROWESS then
+ creature.visible = widget:isChecked()
+ end
+ elseif id == "ProwessCheck" then
+ if creature.kills ~= 0 and creature.kills >= CONFIG[creature.category].PROWESS and creature.kills <=
+ CONFIG[creature.category].EXPERTISE then
+ creature.visible = widget:isChecked()
+ end
+ elseif id == "ExpertiseCheck" then
+ if creature.kills ~= 0 and creature.kills >= CONFIG[creature.category].EXPERTISE and creature.kills <=
+ CONFIG[creature.category].MASTERY then
+ creature.visible = widget:isChecked()
+ end
+ elseif id == "MasteryCheck" and creature.kills ~= 0 and creature.kills >= CONFIG[creature.category].MASTERY then
+ creature.visible = widget:isChecked()
+ end
+ end
+
+ Cyclopedia.ReadjustPages()
+end
+
+function Cyclopedia.ReadjustPages()
+ local maxCategoriesPerPage = 8
+ local allCreatures = {}
+
+ for _, creatures in ipairs(Cyclopedia.Bosstiary.Creatures) do
+ for _, creature in ipairs(creatures) do
+ table.insert(allCreatures, creature)
+ end
+ end
+
+ for _, creature in ipairs(Cyclopedia.Bosstiary.NotVisibleCreatures) do
+ table.insert(allCreatures, creature)
+ end
+
+ table.sort(allCreatures, function(a, b)
+ if a.name == "?" and b.name ~= "?" then
+ return false
+ elseif a.name ~= "?" and b.name == "?" then
+ return true
+ elseif a.unlocked and not b.unlocked then
+ return true
+ elseif not a.unlocked and b.unlocked then
+ return false
+ else
+ return a.name < b.name
+ end
+ end)
+
+ Cyclopedia.Bosstiary.Creatures = {}
+ Cyclopedia.Bosstiary.NotVisibleCreatures = {}
+
+ local page = 1
+
+ Cyclopedia.Bosstiary.Creatures[page] = {}
+
+ for i, creature in ipairs(allCreatures) do
+ if creature.visible then
+ table.insert(Cyclopedia.Bosstiary.Creatures[page], creature)
+
+ if #Cyclopedia.Bosstiary.Creatures[page] == maxCategoriesPerPage then
+ page = page + 1
+ Cyclopedia.Bosstiary.Creatures[page] = {}
+ end
+ else
+ table.insert(Cyclopedia.Bosstiary.NotVisibleCreatures, creature)
+ end
+ end
+
+ local totalVisible = 0
+
+ for _, pageCreatures in ipairs(Cyclopedia.Bosstiary.Creatures) do
+ totalVisible = totalVisible + #pageCreatures
+ end
+
+ Cyclopedia.Bosstiary.TotalPages = math.ceil(totalVisible / maxCategoriesPerPage)
+
+ if Cyclopedia.Bosstiary.Page > Cyclopedia.Bosstiary.TotalPages then
+ Cyclopedia.Bosstiary.Page = 1
+ end
+
+ UI.PageValue:setText(string.format("%d / %d", Cyclopedia.Bosstiary.Page, Cyclopedia.Bosstiary.TotalPages))
+ Cyclopedia.LoadBoostiaryCreature(Cyclopedia.Bosstiary.Page)
+ Cyclopedia.verifyBosstiaryButtons()
+end
diff --git a/modules/game_cyclopedia/tab/bosstiary/bosstiary.otui b/modules/game_cyclopedia/tab/bosstiary/bosstiary.otui
new file mode 100644
index 0000000000..d71cc4f18e
--- /dev/null
+++ b/modules/game_cyclopedia/tab/bosstiary/bosstiary.otui
@@ -0,0 +1,275 @@
+UIWidget
+ id: Cat7
+ anchors.fill: parent
+ visible: false
+ margin-bottom:30
+ UIWidget
+ id: StarBase
+ anchors.top: parent.top
+ anchors.left: parent.left
+ margin-top: 10
+ size: 164 70
+ image-source: /images/game/actionbar/2pixel-up-frame-borderimage
+ image-border: 10
+ UIWidget
+ id: Info2
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.right: parent.right
+ margin-right: 18
+ image-source: /images/icons/show_gui_help_grey
+ UIWidget
+ id: Info1
+ anchors.right: Info2.right
+ anchors.bottom: Info2.top
+ margin-bottom: 10
+ image-source: /images/icons/show_gui_help_grey
+ UIWidget
+ id: Info3
+ anchors.right: Info2.right
+ anchors.top: Info2.bottom
+ margin-top: 10
+ image-source: /images/icons/show_gui_help_grey
+ UIWidget
+ id: Star1_1
+ anchors.bottom: Info1.bottom
+ anchors.left: parent.left
+ margin-left: 50
+ image-source: /game_cyclopedia/images/boss/icon_star_bronze
+ UIWidget
+ id: Star2_1
+ anchors.bottom: Info2.bottom
+ anchors.left: parent.left
+ margin-left: 50
+ image-source: /game_cyclopedia/images/boss/icon_star_silver
+ UIWidget
+ id: Star2_2
+ anchors.bottom: Info2.bottom
+ anchors.right: Star2_1.left
+ margin-right: 5
+ image-source: /game_cyclopedia/images/boss/icon_star_silver
+ UIWidget
+ id: Star3_1
+ anchors.bottom: Info3.bottom
+ anchors.left: parent.left
+ margin-left: 50
+ image-source: /game_cyclopedia/images/boss/icon_star_gold
+ UIWidget
+ id: Star3_2
+ anchors.bottom: Info3.bottom
+ anchors.right: Star3_1.left
+ margin-right: 5
+ image-source: /game_cyclopedia/images/boss/icon_star_gold
+ UIWidget
+ id: Star3_3
+ anchors.bottom: Info3.bottom
+ anchors.right: Star3_2.left
+ margin-right: 5
+ image-source: /game_cyclopedia/images/boss/icon_star_gold
+ Label
+ id: Text1
+ anchors.top: Info1.top
+ anchors.left: Star1_1.right
+ margin-left: 5
+ text-auto-resize: true
+ !text: tr('Prowess')
+ color: #BCBCBC
+ Label
+ id: Text2
+ anchors.top: Info2.top
+ anchors.left: Star2_1.right
+ margin-left: 5
+ text-auto-resize: true
+ !text: tr('Expertise')
+ color: #BCBCBC
+ Label
+ id: Text3
+ anchors.top: Info3.top
+ anchors.left: Star3_1.right
+ margin-left: 5
+ text-auto-resize: true
+ !text: tr('Mastery')
+ color: #BCBCBC
+ UIWidget
+ id: FilterBase
+ anchors.left: StarBase.right
+ anchors.right: parent.right
+ anchors.top: parent.top
+ margin-top: 10
+ margin-left: 10
+ image-source: /images/ui/window_new
+ image-border: 10
+ height: 70
+ !text: tr('Filter')
+ text-align: top
+ text-offset: 0 4
+ color: #919191
+ CheckBox
+ id: BaneCheck
+ anchors.top: parent.top
+ anchors.left: parent.left
+ margin-top: 25
+ margin-left: 10
+ !text: tr('Bane')
+ text-auto-resize: true
+ text-offset: 30 -1
+ checked: true
+ @onClick: modules.game_cyclopedia.Cyclopedia.changeBosstiaryFilter(self, self:isChecked())
+ UIWidget
+ id: BaneIcon
+ anchors.left: BaneCheck.left
+ anchors.verticalCenter: BaneCheck.verticalCenter
+ image-source: /game_cyclopedia/images/boss/icon_bane
+ margin-left: 15
+ CheckBox
+ id: ArchfoeCheck
+ anchors.top: BaneCheck.top
+ anchors.left: BaneCheck.right
+ margin-left: 30
+ !text: tr('Archfoe')
+ text-auto-resize: true
+ text-offset: 30 -1
+ checked: true
+ @onClick: modules.game_cyclopedia.Cyclopedia.changeBosstiaryFilter(self, self:isChecked())
+ UIWidget
+ id: ArchfoeIcon
+ anchors.left: ArchfoeCheck.left
+ anchors.verticalCenter: ArchfoeCheck.verticalCenter
+ image-source: /game_cyclopedia/images/boss/icon_archfoe
+ margin-left: 15
+ CheckBox
+ id: NemesisCheck
+ anchors.top: ArchfoeCheck.top
+ anchors.left: ArchfoeCheck.right
+ margin-left: 30
+ !text: tr('Nemesis')
+ text-auto-resize: true
+ text-offset: 30 -1
+ checked: true
+ @onClick: modules.game_cyclopedia.Cyclopedia.changeBosstiaryFilter(self, self:isChecked())
+ UIWidget
+ id: NemesisIcon
+ anchors.left: NemesisCheck.left
+ anchors.verticalCenter: NemesisCheck.verticalCenter
+ image-source: /game_cyclopedia/images/boss/icon_nemesis
+ margin-left: 15
+ CheckBox
+ id: NoKillsCheck
+ anchors.top: BaneCheck.bottom
+ anchors.left: parent.left
+ margin-top: 10
+ margin-left: 10
+ !text: tr('No Kills')
+ text-auto-resize: true
+ checked: true
+ @onClick: modules.game_cyclopedia.Cyclopedia.changeBosstiaryFilter(self, self:isChecked())
+ CheckBox
+ id: FewKillsCheck
+ anchors.top: BaneCheck.bottom
+ anchors.left: ArchfoeCheck.left
+ margin-top: 10
+ !text: tr('Few Kills')
+ text-auto-resize: true
+ checked: true
+ @onClick: modules.game_cyclopedia.Cyclopedia.changeBosstiaryFilter(self, self:isChecked())
+ CheckBox
+ id: ProwessCheck
+ anchors.top: BaneCheck.bottom
+ anchors.left: NemesisCheck.left
+ margin-top: 10
+ !text: tr('Prowess')
+ text-auto-resize: true
+ checked: true
+ @onClick: modules.game_cyclopedia.Cyclopedia.changeBosstiaryFilter(self, self:isChecked())
+ CheckBox
+ id: ExpertiseCheck
+ anchors.top: BaneCheck.bottom
+ anchors.left: ProwessCheck.right
+ margin-top: 10
+ margin-left: 30
+ !text: tr('Expertise')
+ text-auto-resize: true
+ checked: true
+ @onClick: modules.game_cyclopedia.Cyclopedia.changeBosstiaryFilter(self, self:isChecked())
+ CheckBox
+ id: MasteryCheck
+ anchors.top: BaneCheck.bottom
+ anchors.left: ExpertiseCheck.right
+ margin-top: 10
+ margin-left: 30
+ !text: tr('Mastery')
+ text-auto-resize: true
+ checked: true
+ @onClick: modules.game_cyclopedia.Cyclopedia.changeBosstiaryFilter(self, self:isChecked())
+ UIWidget
+ id: ListBase
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.top: FilterBase.bottom
+ anchors.bottom: parent.bottom
+ margin-bottom: 30
+ margin-top: 10
+ image-source: /images/ui/panel_flat
+ image-border: 10
+ UIScrollArea
+ id: BossList
+ anchors.fill: parent
+ padding-left: 4
+ padding-top: 4
+ margin-left: 3
+ layout:
+ type: grid
+ cell-size: 159 151
+ cell-spacing: 5
+ flow: true
+ TextEdit
+ id: SearchEdit
+ anchors.bottom: parent.bottom
+ anchors.right: parent.right
+ padding-top: 2
+ padding-right: 15
+ margin-bottom: 5
+ size: 150 20
+ placeholder: Type to search
+ placeholder-color: #6E706F
+ @onTextChange: modules.game_cyclopedia.Cyclopedia.BosstiarySearchText(self:getText())
+ UIWidget
+ id: SearchClearButton
+ anchors.right: SearchEdit.right
+ anchors.top: SearchEdit.top
+ margin-top: 1
+ margin-right: 1
+ image-source: /images/ui/button-clear-18x18-up
+ @onClick: modules.game_cyclopedia.Cyclopedia.BosstiarySearchText("", true)
+ $pressed:
+ image-source: /images/ui/button-clear-18x18-down
+ UIWidget
+ id: PageValue
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottom: parent.bottom
+ margin-bottom: 5
+ size: 60 20
+ text-align: center
+ !text: tr('1 / 1')
+ color: #C2C2C2
+ Button
+ id: NextPageButton
+ anchors.left: PageValue.right
+ anchors.bottom: PageValue.bottom
+ size: 20 20
+ icon-source: /game_cyclopedia/images/icon-right-arrow
+ @onClick: modules.game_cyclopedia.Cyclopedia.changeBosstiaryPage(false, true)
+ $pressed:
+ icon-source: /game_cyclopedia/images/icon-right-arrow
+ $disabled:
+ icon-source: /game_cyclopedia/images/icon-right-arrow-disabled
+ Button
+ id: PrevPageButton
+ anchors.right: PageValue.left
+ anchors.bottom: PageValue.bottom
+ size: 20 20
+ icon-source: /game_cyclopedia/images/icon-left-arrow
+ @onClick: modules.game_cyclopedia.Cyclopedia.changeBosstiaryPage(true, false)
+ $pressed:
+ icon-source: /game_cyclopedia/images/icon-left-arrow-disabled
+ $disabled:
+ icon-source: /game_cyclopedia/images/icon-left-arrow-disabled
diff --git a/modules/game_cyclopedia/tab/character/character.lua b/modules/game_cyclopedia/tab/character/character.lua
new file mode 100644
index 0000000000..484fabf3c3
--- /dev/null
+++ b/modules/game_cyclopedia/tab/character/character.lua
@@ -0,0 +1,1263 @@
+local characterPanel = nil
+local UI = nil
+
+local function close(parent)
+ if table.empty(parent.subCategories) then
+ return
+ end
+
+ for subId, _ in ipairs(parent.subCategories) do
+ local subWidget = parent:getChildById(subId)
+
+ if subWidget then
+ subWidget:setVisible(false)
+ end
+ end
+
+ parent:setHeight(parent.closedSize)
+ parent.opened = false
+ parent.Button.Arrow:setVisible(true)
+end
+
+local function reset()
+ characterPanel.InfoBase.inventoryPanel:setVisible(true)
+ characterPanel.InfoBase.outfitPanel:setVisible(false)
+
+ if characterPanel.InfoBase.CharacterButton.state ~= 1 then
+ Cyclopedia.characterButton(characterPanel.InfoBase.CharacterButton)
+ end
+
+ Cyclopedia.selectCharacterPage()
+ characterPanel.openedCategory = nil
+end
+
+local function open(parent)
+ local oldOpen = UI.openedCategory
+
+ for subId, _ in ipairs(parent.subCategories) do
+ local subWidget = parent:getChildById(subId)
+
+ if subWidget then
+ if tonumber(subWidget:getId()) == 1 then
+ subWidget.Button.onClick(subWidget)
+ end
+
+ subWidget:setVisible(true)
+ end
+ end
+
+ if oldOpen ~= nil and oldOpen ~= parent then
+ close(oldOpen)
+ end
+
+ parent:setHeight(parent.openedSize)
+ parent.opened = true
+ parent.Button.Arrow:setVisible(false)
+
+ UI.openedCategory = parent
+end
+
+function showCharacter()
+ characterPanel = g_ui.loadUI("character", contentContainer)
+ UI = characterPanel
+ characterPanel:show()
+ UI.selectedOption = "InfoBase"
+
+ if g_game.isOnline() then
+ local player = g_game.getLocalPlayer()
+ UI.CharacterBase:setText(player:getName())
+ UI.CharacterBase.InfoLabel:setText(string.format("Level: %d\n%s", player:getLevel(), player:getVocationNameByClientId()))
+ UI.CharacterBase.Outfit:setOutfit(player:getOutfit())
+
+ UI.InfoBase.outfitPanel.Sprite:setOutfit(player:getOutfit())
+ UI.InfoBase.InspectLabel:setText(tr("You are inspecting") .. ": " .. player:getName())
+
+ for i = InventorySlotFirst, InventorySlotPurse do
+ local item = player:getInventoryItem(i)
+ local itemWidget = UI.InfoBase.inventoryPanel["slot" .. i]
+ if itemWidget then
+ if item then
+ itemWidget:setStyle("InventoryItemCyclopedia")
+ itemWidget:setItem(item)
+ itemWidget:setIcon("")
+ else
+ itemWidget:setStyle(Cyclopedia.InventorySlotStyles[i].name)
+ itemWidget:setIcon(Cyclopedia.InventorySlotStyles[i].icon)
+ itemWidget:setItem(nil)
+ end
+ end
+ end
+
+ if g_game.isOnline() then
+ Cyclopedia.createCharacterDescription()
+ Cyclopedia.configureCharacterCategories()
+ end
+ end
+
+ reset()
+ controllerCyclopedia.ui.CharmsBase:setVisible(true)
+ controllerCyclopedia.ui.GoldBase:setVisible(true)
+ controllerCyclopedia.ui.BestiaryTrackerButton:setVisible(false)
+end
+
+Cyclopedia.Character = {}
+Cyclopedia.Character.Achievements = {}
+Cyclopedia.InventorySlotStyles = {
+ [InventorySlotHead] = {
+ icon = "/images/game/slots/inventory-head",
+ name = "HeadSlot"
+ },
+ [InventorySlotNeck] = {
+ icon = "/images/game/slots/inventory-neck",
+ name = "NeckSlot"
+ },
+ [InventorySlotBack] = {
+ icon = "/images/game/slots/inventory-back",
+ name = "BackSlot"
+ },
+ [InventorySlotBody] = {
+ icon = "/images/game/slots/inventory-torso",
+ name = "BodySlot"
+ },
+ [InventorySlotRight] = {
+ icon = "/images/game/slots/inventory-right-hand",
+ name = "RightSlot"
+ },
+ [InventorySlotLeft] = {
+ icon = "/images/game/slots/inventory-left-hand",
+ name = "LeftSlot"
+ },
+ [InventorySlotLeg] = {
+ icon = "/images/game/slots/inventory-legs",
+ name = "LegSlot"
+ },
+ [InventorySlotFeet] = {
+ icon = "/images/game/slots/inventory-feet",
+ name = "FeetSlot"
+ },
+ [InventorySlotFinger] = {
+ icon = "/images/game/slots/inventory-finger",
+ name = "FingerSlot"
+ },
+ [InventorySlotAmmo] = {
+ icon = "/images/game/slots/inventory-hip",
+ name = "AmmoSlot"
+ }
+}
+
+function Cyclopedia.characterAppearancesFilter(widget)
+ local parent = widget:getParent()
+ for i = 1, parent:getChildCount() do
+ local child = parent:getChildByIndex(i)
+ if child:getId() ~= "show" then
+ child:setChecked(false)
+ end
+ end
+
+ widget:setChecked(true)
+
+ for _, data in ipairs(Cyclopedia.Character.Appearances) do
+ if data.type == widget:getId() then
+ data.visible = true
+ else
+ data.visible = false
+ end
+ end
+
+ Cyclopedia.reloadCharacterAppearances()
+end
+
+function Cyclopedia.reloadCharacterAppearances()
+ UI.CharacterAppearances.ListBase.list:destroyChildren()
+
+ for _, data in ipairs(Cyclopedia.Character.Appearances) do
+ if data.visible then
+ local widget = g_ui.createWidget("CharacterAppearance", UI.CharacterAppearances.ListBase.list)
+ widget.name:setText(data.name)
+ widget.creature:setOutfit(data.outfit)
+ widget.creature:getCreature():setStaticWalking(1000)
+ end
+ end
+end
+
+function Cyclopedia.loadCharacterAppearances(color, outfits, mounts, familiars)
+ local data = {}
+
+ local function insert(value, type)
+ local lookData = value.lookType
+ if type == "mounts" then
+ lookData = value.mountId
+ end
+
+ local data_t = {
+ visible = false,
+ name = value.name,
+ type = type,
+ outfit = {
+ auxType = 0,
+ type = lookData,
+ head = color.lookHead,
+ body = color.lookBody,
+ legs = color.lookLegs,
+ feet = color.lookFeet,
+ addon = outfits.addons and outfits.addons or 0
+ }
+ }
+
+ table.insert(data, data_t)
+ end
+
+ local function process(container, containerType)
+ for i = 0, #container do
+ local value = container[i]
+ if value then
+ insert(value, containerType)
+ end
+ end
+ end
+
+ process(outfits, "outfits")
+ process(mounts, "mounts")
+ process(familiars, "familiars")
+
+ Cyclopedia.Character.Appearances = data
+ Cyclopedia.characterAppearancesFilter(UI.CharacterAppearances.listFilter.outfits)
+end
+
+function Cyclopedia.characterItemsSearch(text)
+ local filter = UI.CharacterItems.filters
+ local activeFilters = {}
+
+ for i = 1, filter:getChildCount() do
+ local child = filter:getChildByIndex(i)
+ if child:isChecked() then
+ table.insert(activeFilters, child:getId())
+ end
+ end
+
+ for _, item in ipairs(Cyclopedia.Character.Items) do
+ local data = item.data
+ local name = data.name:lower()
+ local meetsSearchCriteria = text == "" or string.find(name, text:lower()) ~= nil
+ local meetsFilterCriteria = #activeFilters == 0 or table.contains(activeFilters, data.type)
+ data.visible = meetsSearchCriteria and meetsFilterCriteria
+ end
+
+ Cyclopedia.reloadCharacterItems()
+end
+
+function Cyclopedia.characterItemsFilter(widget, force)
+ if force then
+ widget:setChecked(true)
+ end
+
+ local id = widget:getId()
+
+ for _, item in ipairs(Cyclopedia.Character.Items) do
+ local data = item.data
+ if data.type == id then
+ data.visible = widget:isChecked()
+ end
+ end
+
+ Cyclopedia.reloadCharacterItems()
+end
+
+function Cyclopedia.reloadCharacterItems()
+ UI.CharacterItems.ListBase.list:destroyChildren()
+ UI.CharacterItems.gridBase.grid:destroyChildren()
+
+ local colors = {"#484848", "#414141"}
+ local colorIndex = 1
+
+ for _, item in ipairs(Cyclopedia.Character.Items) do
+ local itemId, data = item.itemId, item.data
+
+ if data.visible then
+ local listItem = g_ui.createWidget("CharacterListItem", UI.CharacterItems.ListBase.list)
+ -- local frame = g_game.getItemFrame(data.value)
+ listItem.item:setItemId(itemId)
+ listItem.name:setText(data.name)
+ listItem.amount:setText(data.amount)
+ listItem:setBackgroundColor(colors[colorIndex])
+
+ local gridItem = g_ui.createWidget("CharacterGridItem", UI.CharacterItems.gridBase.grid)
+ gridItem.item:setItemId(itemId)
+ gridItem.amount:setText(data.amount)
+
+ --[[
+ if frame > 0 then
+ listItem.rarity:setImageSource("/images/ui/frames")
+ listItem.rarity:setImageClip(torect(g_game.getRectFrame(frame)))
+ gridItem.rarity:setImageSource("/images/ui/frames")
+ gridItem.rarity:setImageClip(torect(g_game.getRectFrame(frame)))
+ else
+ listItem.rarity:setImageSource("")
+ gridItem.rarity:setImageSource("")
+ end
+ ]]--
+
+ colorIndex = 3 - colorIndex
+ end
+ end
+end
+
+function Cyclopedia.loadCharacterItems(data)
+ local inventory = data.inventory
+ local store = data.store
+ local stash = data.stash
+ local depot = data.depot
+ local inbox = data.inbox
+ Cyclopedia.Character.Items = {}
+
+ local function insert(data, type)
+ if not data then
+ return
+ end
+
+ local thing = g_things.getThingType(data.itemId, ThingCategoryItem)
+ local name = thing:getMarketData().name:lower()
+ name = name ~= "" and name or "?"
+
+ local data_t = {
+ visible = false,
+ name = name,
+ amount = data.amount,
+ type = type
+ -- value = thing:getResultingValue()
+ }
+
+ local insertedItem = Cyclopedia.Character.Items[data.itemId]
+ if insertedItem then
+ insertedItem.amount = insertedItem.amount + data.amount
+ else
+ Cyclopedia.Character.Items[data.itemId] = data_t
+ end
+ end
+
+ local function processContainer(container, containerType)
+ for i = 0, #container do
+ local data = container[i]
+ if data then
+ insert(data, containerType)
+ end
+ end
+ end
+
+ processContainer(inventory, "inventory")
+ processContainer(store, "store")
+ processContainer(stash, "stash")
+ processContainer(depot, "depot")
+ processContainer(inbox, "inbox")
+
+ local sortedItems = {}
+
+ for itemId, data in pairs(Cyclopedia.Character.Items) do
+ table.insert(sortedItems, {
+ itemId = itemId,
+ data = data
+ })
+ end
+
+ local function compareByName(a, b)
+ local nameA = a.data.name:lower()
+ local nameB = b.data.name:lower()
+
+ if nameA ~= "?" and nameB == "?" then
+ return true
+ elseif nameA == "?" and nameB ~= "?" then
+ return false
+ else
+ return nameA < nameB
+ end
+ end
+
+ table.sort(sortedItems, compareByName)
+ Cyclopedia.Character.Items = sortedItems
+ Cyclopedia.characterItemsFilter(UI.CharacterItems.filters.inventory, true)
+end
+
+function Cyclopedia.loadCharacterAchievements()
+ if not Cyclopedia.Character.Achievements.Loaded then
+ UI.CharacterAchievements.sort:addOption("Alphabetically", 1, true)
+ UI.CharacterAchievements.sort:addOption("By Grade", 2, true)
+ UI.CharacterAchievements.sort:addOption("By Unlock Date", 3, true)
+ Cyclopedia.achievementFilter(UI.CharacterAchievements.filters.accomplished)
+ Cyclopedia.Character.Achievements.Loaded = true
+ end
+end
+
+function Cyclopedia.characterItemListFilter(widget)
+ local parent = widget:getParent()
+ for i = 1, parent:getChildCount() do
+ local child = parent:getChildByIndex(i)
+ if child then
+ child:setChecked(false)
+ end
+ end
+
+ widget:setChecked(true)
+
+ if widget:getId() == "list" then
+ UI.CharacterItems.ListBase:setVisible(true)
+ UI.CharacterItems.gridBase:setVisible(false)
+ else
+ UI.CharacterItems.ListBase:setVisible(false)
+ UI.CharacterItems.gridBase:setVisible(true)
+ end
+end
+
+function Cyclopedia.achievementFilter(widget)
+ local parent = widget:getParent()
+ for i = 1, parent:getChildCount() do
+ local child = parent:getChildByIndex(i)
+ if child then
+ child:setChecked(false)
+ end
+ end
+
+ if widget:getId() ~= "accomplished" then
+ local last = Cyclopedia.Character.Achievements.lastSort
+ last = last or 1
+ Cyclopedia.achievementSort(last)
+ else
+ UI.CharacterAchievements.ListBase.List:destroyChildren()
+ end
+
+ widget:setChecked(not widget:isChecked())
+end
+
+function Cyclopedia.achievementSort(option)
+ local tempTable = {}
+
+ for id, data in pairs(ACHIEVEMENTS) do
+ local tempData = {
+ id = id,
+ name = data.name,
+ description = data.description,
+ grade = data.grade
+ }
+
+ table.insert(tempTable, tempData)
+ end
+
+ if option == 1 then
+ table.sort(tempTable, function(a, b)
+ return a.name < b.name
+ end)
+ elseif option == 2 then
+ table.sort(tempTable, function(a, b)
+ return a.grade > b.grade
+ end)
+ end
+
+ UI.CharacterAchievements.ListBase.List:destroyChildren()
+
+ for _, data in pairs(tempTable) do
+ local widget = g_ui.createWidget("Achievement", UI.CharacterAchievements.ListBase.List)
+ widget:setId(data.id)
+ widget.title:setText(data.name)
+ widget.title = data.name
+ widget:setText(data.description)
+ widget.icon:setWidth(11 * data.grade)
+ widget.grade = data.grade
+ end
+
+ Cyclopedia.Character.Achievements.lastSort = option
+end
+
+function Cyclopedia.loadCharacterRecentKills(data)
+ UI.RecentKills.ListBase.List:destroyChildren()
+
+ if not table.empty(data) then
+ local color = "#484848"
+
+ for i = 1, #data do
+ local entry = data[i]
+ local time = entry.timestamp
+ local description = entry.description
+ local status = entry.status
+ local widget = g_ui.createWidget("CharacterKill", UI.RecentKills.ListBase.List)
+
+ widget:setId(i)
+ widget.date:setText(os.date("%Y-%m-%d, %H:%M:%S", time))
+ widget.description:setText(description)
+ widget.status:setText(status)
+ widget.color = color
+ widget:setBackgroundColor(color)
+
+ color = color == "#484848" and "#414141" or "#484848"
+
+ function widget:onClick()
+ local parent = widget:getParent()
+ for y = 1, parent:getChildCount() do
+ local child = parent:getChildByIndex(y)
+ child:setChecked(false)
+ child.date:setOn(false)
+ child.description:setOn(false)
+ child.status:setOn(false)
+ end
+
+ self:setChecked(not self:isChecked())
+ end
+
+ function widget:onCheckChange()
+ if self:isChecked() then
+ self:setBackgroundColor("#585858")
+ else
+ self:setBackgroundColor(self.color)
+ end
+
+ self.date:setOn(not self:isOn())
+ self.description:setOn(not self:isOn())
+ self.status:setOn(not self:isOn())
+ end
+
+ if i == 1 then
+ widget:setChecked(true)
+ end
+ end
+ end
+end
+
+function Cyclopedia.loadCharacterRecentDeaths(data)
+
+ UI.RecentDeaths.ListBase.List:destroyChildren()
+
+ if not table.empty(data) then
+ local color = "#484848"
+
+ for i = 1, #data do
+ local entry = data[i]
+ local widget = g_ui.createWidget("CharacterDeath", UI.RecentDeaths.ListBase.List)
+
+ widget:setId(i)
+ widget.date:setText(os.date("%Y-%m-%d, %H:%M:%S", entry.timestamp))
+ widget.cause:setText(entry.cause)
+ widget.color = color
+ widget:setBackgroundColor(color)
+ color = color == "#484848" and "#414141" or "#484848"
+
+ function widget:onClick()
+ local parent = widget:getParent()
+ for y = 1, parent:getChildCount() do
+ local child = parent:getChildByIndex(y)
+ child:setChecked(false)
+ child.cause:setOn(false)
+ child.date:setOn(false)
+ end
+
+ self:setChecked(not self:isChecked())
+ end
+
+ function widget:onCheckChange()
+ if self:isChecked() then
+ self:setBackgroundColor("#585858")
+ else
+ self:setBackgroundColor(self.color)
+ end
+
+ self.cause:setOn(not self:isOn())
+ self.date:setOn(not self:isOn())
+ end
+
+ if i == 1 then
+ widget:setChecked(true)
+ end
+ end
+ end
+end
+
+function Cyclopedia.loadCharacterCombatStats(data, mitigation, additionalSkillsArray, forgeSkillsArray,
+ perfectShotDamageRanges, combatsArray, concoctionsArray)
+ UI.CombatStats.attack.icon:setImageSource(Icons[data.weaponElement+1].icon)
+ UI.CombatStats.attack.icon:setImageClip(Icons[data.weaponElement+1].clip)
+ UI.CombatStats.attack.value:setText(data.weaponMaxHitChance)
+
+ if data.weaponElementDamage > 0 then
+ UI.CombatStats.converted.none:setVisible(false)
+ UI.CombatStats.converted.value:setVisible(true)
+ UI.CombatStats.converted.icon:setVisible(true)
+ UI.CombatStats.converted.icon:setImageSource(Icons[data.weaponElementType+1].icon)
+ UI.CombatStats.converted.icon:setImageClip(Icons[data.weaponElementType+1].clip)
+ UI.CombatStats.converted.value:setText(data.weaponElementDamage .. "%")
+ else
+ UI.CombatStats.converted.none:setVisible(true)
+ UI.CombatStats.converted.value:setVisible(false)
+ UI.CombatStats.converted.icon:setVisible(false)
+ end
+
+ UI.CombatStats.defence.value:setText(data.defense)
+ UI.CombatStats.armor.value:setText(data.armor)
+ UI.CombatStats.mitigation.value:setText(string.format("%.2f%%", mitigation))
+ UI.CombatStats.blessings.value:setText(string.format("%d/8", data.haveBlessings))
+
+ for i = 0, 6 do
+ local id = "reduction_" .. i
+ if UI.CombatStats[id] then
+ UI.CombatStats[id]:destroy()
+ end
+ end
+ UI.CombatStats.reductionNone:destroyChildren()
+
+ if (next(combatsArray) == nil) then
+ UI.CombatStats.reductionNone:setVisible(true)
+ else
+ UI.CombatStats.reductionNone:setVisible(true)
+ for i = 1, #combatsArray do
+ local widget = g_ui.createWidget("CharacterElementReduction", UI.CombatStats.reductionNone)
+ widget:setId("reduction_" .. i)
+
+ local element = Cyclopedia.clientCombat[combatsArray[i][1]]
+
+ if element then
+ widget.icon:setImageSource(element.path)
+ widget.icon:setImageSize({
+ width = 9,
+ height = 9
+ })
+ else
+ print(string.format("WARNING: Element not found for combat array index %d with key %s.", i, tostring(combatsArray[i][1])))
+ end
+ local valor = combatsArray[i][2]
+ local porcentaje = valor / 100
+ local diferencia = 65535 - valor
+ local porcentaje_negativo = diferencia / 100
+ local resultado
+ if porcentaje <= porcentaje_negativo then
+ resultado = string.format("+%.2f%%", porcentaje)
+ widget.value:setColor("green")
+ else
+ resultado = string.format("-%.2f%%", porcentaje_negativo)
+ widget.value:setColor("red")
+ end
+ widget.value:setText(resultado)
+ if element then
+ widget.name:setText(element.id)
+ end
+ widget:setMarginLeft(13)
+ end
+ end
+
+ local skillsIndexes = {
+ [Skill.CriticalChance] = 1,
+ [Skill.CriticalDamage] = 2,
+ [Skill.LifeLeechAmount] = 3,
+ [Skill.ManaLeechAmount] = 4
+ }
+
+ -- Critical Chance
+ local skillIndex = skillsIndexes[Skill.CriticalChance]
+ local skill = additionalSkillsArray[skillIndex][2]
+ UI.CombatStats.criticalChance.value:setText(skill .. "%")
+ if skill > 0 then
+ UI.CombatStats.criticalChance.value:setColor("#44AD25")
+ else
+ UI.CombatStats.criticalChance.value:setColor("#C0C0C0")
+ end
+
+ -- Critical Damage
+ skillIndex = skillsIndexes[Skill.CriticalDamage]
+ skill = additionalSkillsArray[skillIndex][2]
+ UI.CombatStats.criticalDamage.value:setText(skill .. "%")
+ if skill > 0 then
+ UI.CombatStats.criticalDamage.value:setColor("#44AD25")
+ else
+ UI.CombatStats.criticalDamage.value:setColor("#C0C0C0")
+ end
+
+ -- Life Leech Amount
+ skillIndex = skillsIndexes[Skill.LifeLeechAmount]
+ skill = additionalSkillsArray[skillIndex][2]
+ if skill > 0 then
+ UI.CombatStats.lifeLeech.value:setColor("#44AD25")
+ UI.CombatStats.lifeLeech.value:setText(string.format("%.2f%%", skill / 100))
+ else
+ UI.CombatStats.lifeLeech.value:setColor("#C0C0C0")
+ UI.CombatStats.lifeLeech.value:setText(string.format("%d%%", skill))
+ end
+
+ -- Mana Leech Amount
+ skillIndex = skillsIndexes[Skill.ManaLeechAmount]
+ skill = additionalSkillsArray[skillIndex][2]
+ if skill > 0 then
+ UI.CombatStats.manaLeech.value:setColor("#44AD25")
+ UI.CombatStats.manaLeech.value:setText(string.format("%.2f%%", skill / 100))
+ else
+ UI.CombatStats.manaLeech.value:setColor("#C0C0C0")
+ UI.CombatStats.manaLeech.value:setText(string.format("%d%%", skill))
+ end
+
+ for i = 1, #forgeSkillsArray do
+ local skillId = forgeSkillsArray[i][1]
+ local id = "special_" .. skillId
+ if UI.CombatStats[id] then
+ UI.CombatStats[id]:destroy()
+ end
+ end
+
+ local firstSpecial = true
+
+ for i = 1, #forgeSkillsArray do
+ local skillId = forgeSkillsArray[i][1]
+ local percent = forgeSkillsArray[i][2]
+
+ if percent > 0 then
+ local widget = g_ui.createWidget("CharacterSkillBase", UI.CombatStats)
+ widget:setId("special_" .. skillId)
+
+ local specialName = {
+ [13] = "Onslaught",
+ [14] = "Ruse",
+ [15] = "Momentum",
+ [16] = "Transcendence"
+ }
+
+ if firstSpecial then
+ widget:addAnchor(AnchorTop, "manaLeech", AnchorBottom)
+ widget:addAnchor(AnchorLeft, "criticalHit", AnchorLeft)
+ widget:addAnchor(AnchorRight, "parent", AnchorRight)
+ widget:setMarginTop(5)
+ else
+ widget:addAnchor(AnchorTop, "prev", AnchorBottom)
+ widget:addAnchor(AnchorLeft, "criticalHit", AnchorLeft)
+ widget:addAnchor(AnchorRight, "parent", AnchorRight)
+ widget:setMarginTop(0)
+ end
+
+ widget:setMarginLeft(0)
+
+ local name = g_ui.createWidget("SkillNameLabel", widget)
+ name:setText(specialName[skillId])
+ name:setColor("#C0C0C0")
+
+ local value = g_ui.createWidget("SkillValueLabel", widget)
+ value:setText(string.format("%.2f%%", percent / 100))
+ value:setColor("#C0C0C0")
+ value:setMarginRight(2)
+
+ if percent > 0 then
+ value:setColor("#44AD25")
+ else
+ value:setColor("#C0C0C0")
+ end
+
+ firstSpecial = firstSpecial and false
+ end
+ end
+end
+
+function Cyclopedia.loadCharacterGeneralStats(data, skills)
+ local player = g_game.getLocalPlayer()
+ if not player then
+ return
+ end
+
+ local function format(value)
+ local totalMinutes = value / 60
+ local hours = math.floor(totalMinutes / 60)
+ local minutes = math.floor(totalMinutes % 60)
+
+ if hours < 10 then
+ hours = "0" .. hours
+ end
+
+ if minutes < 10 then
+ minutes = "0" .. minutes
+ end
+
+ return hours .. ":" .. minutes
+ end
+
+ Cyclopedia.setCharacterSkillValue("level", comma_value(data.level))
+
+ local text = tr("You have %s percent to go ", 100 - data.levelPercent)
+ Cyclopedia.setCharacterSkillPercent("level", data.levelPercent, text)
+ Cyclopedia.setCharacterSkillValue("experience", comma_value(player:getExperience()))
+
+ local expGainRate = data.baseExpGain + data.XpBoostPercent
+ local hasStoreExpBonus = data.XpBoostPercent > 0
+ local hasStaminaBonus = data.staminaMinutes / 60 >= 3
+
+ expGainRate = hasStaminaBonus and expGainRate * 1.5 or expGainRate
+
+ local staminaBonusTime = string.format("%02d:%02d", math.floor(math.min(data.staminaMinutes, 180) / 60),
+ math.min(data.staminaMinutes, 180) % 60)
+ local storeExpBonusTime = format(data.XpBoostBonusRemainingTime)
+ local expGainRateTooltip = string.format(
+ "Your current XP gain rate amounts to %d%%.\nYour XP gain rate is calculated as follows:\n- Base XP gain rate: %d%%",
+ expGainRate, data.baseExpGain)
+
+ expGainRateTooltip = hasStoreExpBonus and expGainRateTooltip ..
+ string.format("\n- XP boost: %d%% (%s h remaining).", data.XpBoostPercent,
+ storeExpBonusTime) or expGainRateTooltip
+ expGainRateTooltip = hasStaminaBonus and expGainRateTooltip ..
+ string.format("\n- Stamina bonus: x1.5 (%s h remaining).", staminaBonusTime) or
+ expGainRateTooltip
+
+ UI.CharacterStats.expGainRate:setTooltip(expGainRateTooltip)
+ -- UI.CharacterStats.expGainRate:setTooltipAlign(AlignTopLeft)
+ Cyclopedia.setCharacterSkillValue("expGainRate", comma_value(expGainRate) .. "%")
+ Cyclopedia.setCharacterSkillValue("health", comma_value(data.maxHealth))
+ Cyclopedia.setCharacterSkillValue("mana", comma_value(data.mana))
+ Cyclopedia.setCharacterSkillValue("soul", data.soul)
+ Cyclopedia.setCharacterSkillValue("capacity", comma_value(math.floor(player:getFreeCapacity())))
+
+ if data.speed > 0 then
+ UI.CharacterStats.speed.value:setColor("#44AD25")
+ else
+ UI.CharacterStats.speed.value:setColor("#C0C0C0")
+ end
+
+ Cyclopedia.setCharacterSkillValue("speed", comma_value(math.floor(data.speed)))
+ Cyclopedia.setCharacterSkillValue("food", format(data.regenerationCondition))
+
+ local function formatTime(time)
+ local hours = math.floor(time / 60)
+ local minutes = time % 60
+ if minutes < 10 then
+ minutes = "0" .. minutes
+ end
+ return hours, minutes
+ end
+
+ local staminaPercent = math.floor(100 * data.staminaMinutes / 2520)
+ local staminaHours, staminaMinutes = formatTime(data.staminaMinutes)
+
+ Cyclopedia.setCharacterSkillValue("stamina", staminaHours .. ":" .. staminaMinutes)
+
+ if data.staminaMinutes > 2400 and g_game.getClientVersion() >= 1038 and player:isPremium() then
+ local text = tr("You have %s hours and %s minutes left", staminaHours, staminaMinutes) .. "\n" ..
+ tr("Now you will gain 50%% more experience")
+
+ Cyclopedia.setCharacterSkillPercent("stamina", staminaPercent, text, "green")
+ elseif data.staminaMinutes > 2400 and g_game.getClientVersion() >= 1038 and not player:isPremium() then
+ local text = tr("You have %s hours and %s minutes left", staminaHours, staminaMinutes) .. "\n" ..
+ tr(
+ "You will not gain 50%% more experience because you aren't premium player, now you receive only 1x experience points")
+
+ Cyclopedia.setCharacterSkillPercent("stamina", staminaPercent, text, "#89F013")
+ elseif data.staminaMinutes <= 840 and data.staminaMinutes > 0 then
+ local text = tr("You have %s hours and %s minutes left", staminaHours, staminaMinutes) .. "\n" ..
+ tr("You gain only 50%% experience and you don't may gain loot from monsters")
+
+ Cyclopedia.setCharacterSkillPercent("stamina", staminaPercent, text, "red")
+ elseif data.staminaMinutes == 0 then
+ local text = tr("You have %s hours and %s minutes left", staminaHours, staminaMinutes) .. "\n" ..
+ tr("You don't may receive experience and loot from monsters")
+
+ Cyclopedia.setCharacterSkillPercent("stamina", staminaPercent, text, "black")
+ end
+
+ local trainerHours, trainerMinutes = formatTime(data.offlineTrainingTime)
+ local trainerPercent = 100 * data.offlineTrainingTime / 720
+
+ Cyclopedia.setCharacterSkillValue("trainer", trainerHours .. ":" .. trainerMinutes)
+ Cyclopedia.setCharacterSkillPercent("trainer", trainerPercent, tr("You have %s percent", trainerPercent))
+ Cyclopedia.setCharacterSkillValue("magiclevel", data.magicLevel)
+ Cyclopedia.setCharacterSkillPercent("magiclevel", data.magicLevelPercent / 100,
+ tr("You have %s percent to go", 100 - data.magicLevelPercent / 100))
+ Cyclopedia.setCharacterSkillBase("magiclevel", data.magicLevel, data.baseMagicLevel)
+
+ for i = Skill.Fist + 1, Skill.Fishing + 1 do
+ local skillLevel = skills[i][1]
+ local baseSkill = skills[i][2]
+ local skillPercent = skills[i][3]
+ Cyclopedia.onSkillChange(player, i - 1, skillLevel, skillPercent)
+ Cyclopedia.onBaseCharacterSkillChange(player, i - 1, baseSkill)
+ end
+end
+
+function Cyclopedia.setCharacterSkillValue(id, value, color)
+ local skill = UI.CharacterStats:recursiveGetChildById(id)
+ local widget = skill:getChildById("value")
+ widget:setText(value)
+ widget:setColor(color)
+end
+
+function Cyclopedia.setCharacterSkillPercent(id, percent, tooltip, color)
+ local skill = UI.CharacterStats:recursiveGetChildById(id)
+ local widget = skill:getChildById("percent")
+ if widget then
+ widget:setPercent(math.floor(percent))
+
+ if tooltip then
+ widget:setTooltip(tooltip)
+ end
+
+ if color then
+ widget:setBackgroundColor(color)
+ end
+ end
+end
+
+function Cyclopedia.setCharacterSkillBase(id, value, baseValue)
+ if baseValue <= 0 or value < 0 then
+ return
+ end
+
+ local skill = UI.CharacterStats:recursiveGetChildById(id)
+ local widget = skill:getChildById("value")
+
+ if baseValue < value then
+ widget:setColor("#44AD25")
+ skill:setTooltip(baseValue .. " +" .. value - baseValue)
+ elseif value < baseValue then
+ widget:setColor("#b22222")
+ skill:setTooltip(baseValue .. " " .. value - baseValue)
+ else
+ widget:setColor("#bbbbbb")
+ skill:removeTooltip()
+ end
+end
+
+function Cyclopedia.onBaseCharacterSkillChange(localPlayer, id, baseLevel)
+ Cyclopedia.setCharacterSkillBase("skillId" .. id, localPlayer:getSkillLevel(id), baseLevel)
+end
+
+function Cyclopedia.onSkillChange(localPlayer, id, level, percent)
+ Cyclopedia.setCharacterSkillValue("skillId" .. id, level)
+ Cyclopedia.setCharacterSkillPercent("skillId" .. id, percent, tr("You have %s percent to go", 100 - percent))
+ Cyclopedia.onBaseCharacterSkillChange(localPlayer, id, localPlayer:getSkillBaseLevel(id))
+end
+
+function Cyclopedia.selectCharacterPage()
+ local selectedOption = UI.selectedOption
+ UI[selectedOption]:setVisible(false)
+ UI.InfoBase:setVisible(true)
+ Cyclopedia.closeCharacterButtons()
+
+ local oldOpen = UI.openedCategory
+ if oldOpen ~= nil then
+ close(oldOpen)
+ end
+
+ UI.selectedOption = "InfoBase"
+end
+
+function Cyclopedia.closeCharacterButtons()
+ local size = UI.OptionsBase:getChildCount()
+ for i = 1, size do
+ local widget = UI.OptionsBase:getChildByIndex(i)
+ if widget then
+ if widget.subCategories ~= nil then
+ for subId, _ in ipairs(widget.subCategories) do
+ local subWidget = widget:getChildById(subId)
+
+ if subWidget then
+ subWidget.Button:setChecked(false)
+ subWidget.Button.Arrow:setVisible(false)
+ subWidget.Button.Icon:setChecked(false)
+ end
+ end
+ else
+ widget.Button:setChecked(false)
+ widget.Button.Arrow:setVisible(false)
+ widget.Button.Icon:setChecked(false)
+ end
+ end
+ end
+end
+
+function Cyclopedia.configureCharacterCategories()
+ UI.OptionsBase:destroyChildren()
+
+ local buttons = {
+ {
+ text = "General Stats",
+ icon = "/game_cyclopedia/images/character_icons/icon_generalstats",
+ subCategories = {
+ {
+ text = "Character Stats",
+ icon = "/game_cyclopedia/images/character_icons/icon-character-generalstats-overview",
+ open = "CharacterStats"
+ },
+ {
+ text = "Combat Stats",
+ icon = "/game_cyclopedia/images/character_icons/icon-character-generalstats-combatstats",
+ open = "CombatStats"
+ }
+ }
+ },
+ {
+ text = "Battle Results",
+ icon = "/game_cyclopedia/images/character_icons/icon_battleresults",
+ subCategories = {
+ {
+ text = "Recent Deaths",
+ icon = "/game_cyclopedia/images/character_icons/icon-character-battleresults-recentdeaths",
+ open = "RecentDeaths"
+ },
+ {
+ text = "Recent PvP Kills",
+ icon = "/game_cyclopedia/images/character_icons/icon-character-battleresults-recentpvpkills",
+ open = "RecentKills"
+ }
+ }
+ },
+ {
+ text = "Achievements",
+ icon = "/game_cyclopedia/images/character_icons/icon_achievement",
+ open = "CharacterAchievements"
+ },
+ {
+ text = "Item Summary",
+ icon = "/game_cyclopedia/images/character_icons/icon_items",
+ open = "CharacterItems"
+ },
+ {
+ text = "Appearances",
+ icon = "/game_cyclopedia/images/character_icons/icon_outfitsmounts",
+ open = "CharacterAppearances"
+ },
+ {
+ text = "Store Summary",
+ icon = "/game_cyclopedia/images/character_icons/icon-character-store",
+ open = "StoreSummary"
+ },
+ {
+ text = "Character Titles",
+ icon = "/game_cyclopedia/images/character_icons/icon-character-titles",
+ open = "CharacterTitles"
+ }
+ }
+
+ for id, button in ipairs(buttons) do
+ local widget = g_ui.createWidget("CharacterCategoryItem", UI.OptionsBase)
+ widget:setId(id)
+ widget.Button.Icon:setIcon(button.icon)
+ widget.Button.Title:setText(button.text)
+
+ if button.open ~= nil then
+ widget.open = button.open
+ end
+
+ if button.subCategories ~= nil then
+ widget.subCategories = button.subCategories
+ widget.subCategoriesSize = #button.subCategories
+ widget.Button.Arrow:setVisible(true)
+
+ for subId, subButton in ipairs(button.subCategories) do
+ local subWidget = g_ui.createWidget("CharacterCategoryItem", widget)
+ subWidget:setId(subId)
+ subWidget.Button.Icon:setIcon(subButton.icon)
+ subWidget.Button.Title:setText(subButton.text)
+ subWidget:setVisible(false)
+ subWidget.open = subButton.open
+
+ function subWidget.Button:onClick(test)
+ local selectedOption = UI.selectedOption
+ Cyclopedia.closeCharacterButtons()
+ subWidget.Button:setChecked(true)
+ subWidget.Button.Arrow:setVisible(true)
+ subWidget.Button.Arrow:setImageSource("/game_cyclopedia/images/icon-arrow7x7-right")
+ subWidget.Button.Icon:setChecked(true)
+ UI[selectedOption]:setVisible(false)
+ UI[subWidget.open]:setVisible(true)
+
+ if subWidget.open == "CharacterStats" then
+ g_game.requestCharacterInfo(0, CyclopediaCharacterInfoTypes.GeneralStats)
+ g_game.requestCharacterInfo(0, CyclopediaCharacterInfoTypes.Badges)
+ elseif subWidget.open == "CombatStats" then
+ g_game.requestCharacterInfo(0, CyclopediaCharacterInfoTypes.CombatStats)
+ elseif subWidget.open == "RecentDeaths" then
+ g_game.requestCharacterInfo(0, CyclopediaCharacterInfoTypes.RecentDeaths, 23, 1)
+ elseif subWidget.open == "RecentKills" then
+ g_game.requestCharacterInfo(0, CyclopediaCharacterInfoTypes.RecentPVPKills, 23, 1)
+ end
+
+ UI.selectedOption = subWidget.open
+ end
+
+ if subId == 1 then
+ subWidget:addAnchor(AnchorTop, "parent", AnchorTop)
+ subWidget:addAnchor(AnchorHorizontalCenter, "parent", AnchorHorizontalCenter)
+ subWidget:setMarginTop(20)
+ else
+ subWidget:addAnchor(AnchorTop, "prev", AnchorBottom)
+ subWidget:addAnchor(AnchorHorizontalCenter, "parent", AnchorHorizontalCenter)
+ subWidget:setMarginTop(-1)
+ end
+ end
+ end
+
+ if id == 1 then
+ widget:addAnchor(AnchorTop, "parent", AnchorTop)
+ widget:addAnchor(AnchorHorizontalCenter, "parent", AnchorHorizontalCenter)
+ widget:setMarginTop(10)
+ else
+ widget:addAnchor(AnchorTop, "prev", AnchorBottom)
+ widget:addAnchor(AnchorHorizontalCenter, "parent", AnchorHorizontalCenter)
+ widget:setMarginTop(10)
+ end
+
+ function widget.Button.onClick(this)
+ if widget.open == "CharacterAchievements" then
+ Cyclopedia.loadCharacterAchievements()
+ elseif widget.open == "CharacterItems" then
+ g_game.requestCharacterInfo(0, CyclopediaCharacterInfoTypes.ItemSummary)
+ Cyclopedia.characterItemListFilter(UI.CharacterItems.listFilter.list)
+ elseif widget.open == "CharacterAppearances" then
+ g_game.requestCharacterInfo(0, CyclopediaCharacterInfoTypes.OutfitsAndMounts)
+ elseif widget.open == "StoreSummary" then
+ g_game.requestCharacterInfo(0, CyclopediaCharacterInfoTypes.StoreSummary)
+ end
+
+ local parent = this:getParent()
+ if parent.subCategoriesSize ~= nil then
+ if parent.closedSize == nil then
+ parent.closedSize = parent:getHeight() / (parent.subCategoriesSize + 1) + 15
+ end
+
+ if parent.openedSize == nil then
+ parent.openedSize = parent:getHeight() * (parent.subCategoriesSize + 1) - 6
+ end
+
+ open(parent)
+ else
+ local oldOpen = UI.openedCategory
+ local selectedOption = UI.selectedOption
+
+ Cyclopedia.closeCharacterButtons()
+ this.Arrow:setImageSource("/game_cyclopedia/images/icon-arrow7x7-right")
+ this.Arrow:setVisible(true)
+
+ if oldOpen ~= nil and oldOpen ~= parent then
+ close(oldOpen)
+ end
+
+ this:setChecked(true)
+ this.Icon:setChecked(true)
+ UI[selectedOption]:setVisible(false)
+ UI[parent.open]:setVisible(true)
+ UI.selectedOption = parent.open
+ end
+ end
+ end
+end
+
+function Cyclopedia.createCharacterDescription()
+ UI.InfoBase.DetailsBase.List:destroyChildren()
+
+ local player = g_game.getLocalPlayer()
+ local descriptions = {
+ { Level = player:getLevel() },
+ { Vocation = player:getVocationNameByClientId() },
+ { loyaltyTitle = "?" },
+ { Prey = "?" },
+ { Outfit = "?" },
+ { }
+ }
+
+ for _, description in ipairs(descriptions) do
+ local widget = g_ui.createWidget("UIWidget", UI.InfoBase.DetailsBase.List)
+ for key, value in pairs(description) do
+ widget:setText(key .. ": " .. value)
+ widget:setColor("#C0C0C0")
+ end
+ widget:setTextWrap(true)
+ end
+end
+
+function Cyclopedia.characterButton(widget)
+ if widget.state == 1 then
+ widget.state = 2
+ widget:setIcon("/game_cyclopedia/images/icon-equipmentdetails")
+ UI.InfoBase.inventoryPanel:setVisible(false)
+ UI.InfoBase.outfitPanel:setVisible(true)
+ else
+ widget.state = 1
+ widget:setIcon("/game_cyclopedia/images/icon-playerdetails")
+ UI.InfoBase.inventoryPanel:setVisible(true)
+ UI.InfoBase.outfitPanel:setVisible(false)
+ end
+end
+
+function Cyclopedia.loadCharacterBadges(showAccountInformation, playerOnline, playerPremium, loyaltyTitle, badgesVector)
+ UI.CharacterStats.ListBadge:destroyChildren()
+
+ local playerOnlineStatus = "Offline"
+ local playerOnlineStatusColor = "#ff0000"
+ if playerOnline == 1 then
+ playerOnlineStatus = "Online"
+ playerOnlineStatusColor = "#00ff00"
+ end
+
+ local accountStatus = "Free"
+ local accountStatusColor = "#ff0000"
+ if playerPremium == 1 then
+ accountStatus = "Premium"
+ accountStatusColor = "#00ff00"
+ end
+
+ if not loyaltyTitle or loyaltyTitle == "" then
+ loyaltyTitle = "None"
+ end
+
+ Cyclopedia.setCharacterSkillValue("accountStatus", accountStatus, accountStatusColor)
+ Cyclopedia.setCharacterSkillValue("accountOnline", playerOnlineStatus, playerOnlineStatusColor)
+ Cyclopedia.setCharacterSkillValue("loyaltyTitle", loyaltyTitle)
+
+ for _, badge in ipairs(badgesVector) do
+ local cell = g_ui.createWidget("CharacterBadge", UI.CharacterStats.ListBadge)
+ if cell then
+ cell:setImageClip(getImageClip(badge[1]))
+ cell:setTooltip(badge[2])
+ end
+ end
+end
+
+function getImageClip(elementIndex)
+ local elementSize = 64
+ local elementsPerRow = 21
+ local y = 0
+ local x = (elementIndex - 1) * elementSize
+ local imageClip = string.format("%d %d %d %d", x, y, elementSize, elementSize)
+ return imageClip
+end
+
+function Cyclopedia.onParseCyclopediaStoreSummary(xpBoostTime, dailyRewardXpBoostTime, blessings, preySlotsUnlocked,
+ preyWildcards, instantRewards, hasCharmExpansion, hirelingsObtained, hirelingSkills, houseItems)
+
+ UI.StoreSummary.ListBase.List.XPBoosts.RemainingStoreXPBoostTimeValue:setText(string.format("%02d:%02d",
+ math.floor(xpBoostTime / 3600), math.floor((xpBoostTime % 3600) / 60)))
+ UI.StoreSummary.ListBase.List.XPBoosts.RemainingDailyRewardXPBoostTimeValue:setText(string.format("%02d:%02d",
+ math.floor(dailyRewardXpBoostTime / 3600), math.floor((dailyRewardXpBoostTime % 3600) / 60)))
+
+ local panel = UI.StoreSummary.ListBase.List.Blessings.PurchasedHouseItems
+ for _, blessing in ipairs(blessings) do
+ local row = g_ui.createWidget('BlessCreate', panel)
+ row.text1:setText(blessing[1])
+ row.text2:setText("x" .. blessing[2])
+
+ end
+
+ UI.StoreSummary.ListBase.List.preyPanel.PermanentPreySlotsValue:setText(preySlotsUnlocked)
+ UI.StoreSummary.ListBase.List.preyPanel.PreyWildcardsValue:setText(preyWildcards)
+ UI.StoreSummary.ListBase.List.dailyReward.InstantRewardAccessValue:setText(instantRewards)
+
+ if hasCharmExpansion then
+ UI.StoreSummary.ListBase.List.CharmPanel.CharmExpansionValue:setText("Yes")
+ else
+ UI.StoreSummary.ListBase.List.CharmPanel.CharmExpansionValue:setText("No")
+ end
+
+ UI.StoreSummary.ListBase.List.hirelings.PurchasedHirelingsValue:setText(hirelingsObtained)
+
+ local rowHeight = 130
+ local maxVisibleRows = 1.6
+ local itemCount = #houseItems
+ UI.StoreSummary.ListBase.List.houseItems:setHeight(math.min(itemCount, maxVisibleRows) * rowHeight)
+ for _, item in ipairs(houseItems) do
+ local row = g_ui.createWidget('RowStore2', UI.StoreSummary.ListBase.List.houseItems.PurchasedHouseItems)
+ local nameLabel = row:getChildById('lblName')
+ nameLabel:setText(item[2])
+ nameLabel:setTextAlign(AlignCenter)
+ nameLabel:setMarginRight(10)
+ row:getChildById('lblPrice'):setText(item[3])
+ local itemWidget = g_ui.createWidget('Item', row:getChildById('image'))
+ itemWidget:setId(item[1])
+ itemWidget:setItemId(item[1])
+ itemWidget:fill('parent')
+ end
+end
diff --git a/modules/game_cyclopedia/tab/character/character.otui b/modules/game_cyclopedia/tab/character/character.otui
new file mode 100644
index 0000000000..cb0cd82b56
--- /dev/null
+++ b/modules/game_cyclopedia/tab/character/character.otui
@@ -0,0 +1,1773 @@
+UIWidget
+ id: Cat6
+ anchors.fill: parent
+ visible: false
+ UIWidget
+ id: CharacterBase
+ anchors.left: parent.left
+ anchors.top: parent.top
+ margin-top: 10
+ image-source: /images/ui/outfits/minipanel
+ image-border: 20
+ size: 170 130
+ color: #929292
+ text-offset: 0 3
+ text-align: top
+ !text: tr('Player Name')
+ change-cursor-image: true
+ cursor: pointer
+ @onClick: modules.game_cyclopedia.Cyclopedia.selectCharacterPage()
+ Label
+ id: InfoLabel
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottom: parent.bottom
+ margin-bottom: 5
+ !text: tr('Level: 1\nKnight')
+ text-auto-resize: true
+ text-align: center
+ color: #C1C1C1
+ UICreature
+ id: Outfit
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottom: InfoLabel.top
+ margin-bottom: 5
+ size: 64 64
+ phantom: true
+ UIWidget
+ id: OptionsBase
+ anchors.left: CharacterBase.left
+ anchors.top: CharacterBase.bottom
+ anchors.bottom: parent.bottom
+ margin-top: 10
+ margin-bottom: 30
+ image-source: /images/ui/2pixel_up_frame_borderimage_dark
+ image-size: 170 270
+ image-border: 10
+
+ width: 170
+
+ BorderBox
+ id: InfoBase
+ anchors.top: CharacterBase.top
+ anchors.left: CharacterBase.right
+ anchors.bottom: OptionsBase.bottom
+ anchors.right: parent.right
+ margin-left: 10
+ Panel
+ id: outfitPanel
+ margin-left: -10
+ margin-top: 10
+ anchors.left: parent.left
+ anchors.top: parent.top
+ size: 140 140
+ visible: false
+ UICreature
+ id: Sprite
+ anchors.fill: parent
+ Panel
+ id: inventoryPanel
+ margin-left: -10
+ margin-top: 10
+ anchors.left: parent.left
+ anchors.top: parent.top
+ size: 140 140
+ HeadSlot
+ anchors.top: parent.top
+ anchors.horizontalCenter: parent.horizontalCenter
+ margin-top: 3
+ BodySlot
+ anchors.top: prev.bottom
+ anchors.horizontalCenter: prev.horizontalCenter
+ margin-top: 3
+ LegSlot
+ anchors.top: prev.bottom
+ anchors.horizontalCenter: prev.horizontalCenter
+ margin-top: 3
+ FeetSlot
+ anchors.top: prev.bottom
+ anchors.horizontalCenter: prev.horizontalCenter
+ margin-top: 3
+ NeckSlot
+ anchors.top: slot1.top
+ anchors.right: slot1.left
+ margin-top: 13
+ margin-right: 5
+ LeftSlot
+ anchors.top: prev.bottom
+ anchors.horizontalCenter: prev.horizontalCenter
+ margin-top: 3
+ FingerSlot
+ anchors.top: prev.bottom
+ anchors.horizontalCenter: prev.horizontalCenter
+ margin-top: 3
+ BackSlot
+ anchors.top: slot1.top
+ anchors.left: slot1.right
+ margin-top: 13
+ margin-left: 5
+ RightSlot
+ anchors.top: prev.bottom
+ anchors.horizontalCenter: prev.horizontalCenter
+ margin-top: 3
+ AmmoSlot
+ anchors.top: prev.bottom
+ anchors.horizontalCenter: prev.horizontalCenter
+ margin-top: 3
+ Button
+ id: CharacterButton
+ anchors.left: inventoryPanel.right
+ anchors.top: parent.top
+ margin-top: 10
+ margin-left: -5
+ size: 34 34
+ icon-source: /game_cyclopedia/images/icon-playerdetails
+ &state: 1
+ @onClick: modules.game_cyclopedia.Cyclopedia.characterButton(self)
+ Button
+ id: WheelButton
+ anchors.left: CharacterButton.right
+ anchors.top: CharacterButton.top
+ margin-left: 5
+ size: 34 34
+ icon-source: /game_cyclopedia/images/button_wheel
+ BorderBox
+ id: DetailsBase
+ anchors.top: inventoryPanel.bottom
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ margin-top: 30
+ margin-left: 5
+ margin-right: 5
+ margin-bottom: 5
+ height: 140
+ background-color: #363636
+ UIScrollArea
+ id: List
+ vertical-scrollbar: ListScrollbar
+ anchors.fill: parent
+ size: 200 60
+ padding-left: 2
+ padding-top: 2
+ padding-bottom: 2
+ layout:
+ type: grid
+ cell-size: 325 22
+ cell-spacing: 2
+ flow: true
+ UIWidget
+ !text: tr('Status: Loading, please wait...')
+ color: #BEBEBE
+ VerticalScrollBar
+ id: ListScrollbar
+ anchors.top: List.top
+ anchors.right: List.right
+ anchors.bottom: List.bottom
+ step: 80
+ pixel-scroll: true
+ Label
+ id: InspectLabel
+ anchors.bottom: DetailsBase.top
+ anchors.left: DetailsBase.left
+ margin-bottom: 5
+ text-auto-resize: true
+ !text: tr('You are inspecting') .. ": " .. "Player Name"
+ color: #BEBEBE
+ BorderBox
+ id: CharacterStats
+ anchors.top: CharacterBase.top
+ anchors.left: CharacterBase.right
+ anchors.bottom: OptionsBase.bottom
+ anchors.right: parent.right
+ margin-left: 10
+ visible: false
+ VerticalSeparator
+ id: separator
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ margin-top: 5
+ margin-bottom: 5
+ CharacterSkillBase
+ id: level
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.right: separator.right
+ SkillNameLabel
+ !text: tr('Level')
+ color: #C0C0C0
+ SkillValueLabel
+ color: #C0C0C0
+ SkillCharacterPercentPanel
+ background-color: #C00000
+ CharacterSkillBase
+ id: experience
+ anchors.top: level.bottom
+ anchors.left: parent.left
+ anchors.right: separator.right
+ margin-top: 10
+ SkillNameLabel
+ !text: tr('Experience')
+ color: #C0C0C0
+ SkillValueLabel
+ color: #C0C0C0
+ CharacterSkillBase
+ id: expGainRate
+ anchors.top: experience.bottom
+ anchors.left: parent.left
+ anchors.right: separator.right
+ margin-top: 1
+ SkillNameLabel
+ !text: tr('XP Gain Rate')
+ color: #C0C0C0
+ SkillValueLabel
+ color: #44AD25
+ UIWidget
+ id: xpBoostButton
+ image-source: /images/ui/button-storexp
+ anchors.horizontalCenter: level.horizontalCenter
+ anchors.top: expGainRate.bottom
+ @onClick: modules.game_shop.toggle()
+ $pressed:
+ image-source: /images/ui/button-storexp-pressed
+ HorizontalSeparator
+ id: leftSeparator
+ anchors.top: expGainRate.bottom
+ anchors.left: parent.left
+ anchors.right: xpBoostButton.left
+ margin-top: 5
+ margin-left: 5
+ HorizontalSeparator
+ id: rightSeparator
+ anchors.top: leftSeparator.top
+ anchors.left: xpBoostButton.right
+ anchors.right: separator.right
+ margin-left: 1
+ margin-right: 5
+ CharacterSkillBase
+ id: health
+ anchors.top: xpBoostButton.bottom
+ anchors.left: parent.left
+ anchors.right: separator.right
+ margin-top: 10
+ SkillNameLabel
+ !text: tr('Hit Points')
+ color: #C0C0C0
+ SkillValueLabel
+ color: #C0C0C0
+ CharacterSkillBase
+ id: mana
+ anchors.top: health.bottom
+ anchors.left: parent.left
+ anchors.right: separator.right
+ margin-top: 1
+ SkillNameLabel
+ !text: tr('Mana')
+ color: #C0C0C0
+ SkillValueLabel
+ color: #C0C0C0
+ CharacterSkillBase
+ id: soul
+ anchors.top: mana.bottom
+ anchors.left: parent.left
+ anchors.right: separator.right
+ margin-top: 1
+ SkillNameLabel
+ !text: tr('Soul Points')
+ color: #C0C0C0
+ SkillValueLabel
+ color: #C0C0C0
+ CharacterSkillBase
+ id: capacity
+ anchors.top: soul.bottom
+ anchors.left: parent.left
+ anchors.right: separator.right
+ margin-top: 1
+ SkillNameLabel
+ !text: tr('Capacity')
+ color: #C0C0C0
+ SkillValueLabel
+ color: #C0C0C0
+ CharacterSkillBase
+ id: speed
+ anchors.top: capacity.bottom
+ anchors.left: parent.left
+ anchors.right: separator.right
+ margin-top: 1
+ SkillNameLabel
+ !text: tr('Speed')
+ color: #C0C0C0
+ SkillValueLabel
+ color: #C0C0C0
+ CharacterSkillBase
+ id: food
+ anchors.top: speed.bottom
+ anchors.left: parent.left
+ anchors.right: separator.right
+ margin-top: 1
+ SkillNameLabel
+ !text: tr('Food')
+ color: #C0C0C0
+ SkillValueLabel
+ color: #C0C0C0
+ CharacterSkillBase
+ id: stamina
+ anchors.top: food.bottom
+ anchors.left: parent.left
+ anchors.right: separator.right
+ margin-top: 1
+ SkillNameLabel
+ !text: tr('Stamina')
+ color: #C0C0C0
+ SkillValueLabel
+ color: #C0C0C0
+ SkillCharacterPercentPanel
+ background-color: green
+ CharacterSkillBase
+ id: trainer
+ anchors.top: stamina.bottom
+ anchors.left: parent.left
+ anchors.right: separator.right
+ margin-top: 5
+ SkillNameLabel
+ !text: tr('Offline Training')
+ color: #C0C0C0
+ SkillValueLabel
+ color: #C0C0C0
+ SkillCharacterPercentPanel
+ background-color: #C00000
+
+ HorizontalSeparator
+ id: leftSeparator2
+ anchors.top: trainer.bottom
+ anchors.left: parent.left
+ anchors.right: separator.right
+ margin-top: 5
+ margin-left: 5
+
+ CharacterSkillBase
+ id: accountStatus
+ anchors.top: leftSeparator2.bottom
+ anchors.left: parent.left
+ anchors.right: separator.right
+ margin-top: 10
+ SkillNameLabel
+ !text: tr('Account Status')
+ color: #C0C0C0
+ SkillValueLabel
+ !text: tr('33')
+ color: #C0C0C0
+ CharacterSkillBase
+ id: accountOnline
+ anchors.top: accountStatus.bottom
+ anchors.left: parent.left
+ anchors.right: separator.right
+ margin-top: 5
+ SkillNameLabel
+ !text: tr('Account Premium')
+ color: #C0C0C0
+ SkillValueLabel
+ !text: tr('33')
+ color: #C0C0C0
+ CharacterSkillBase
+ id: loyaltyTitle
+ anchors.top: accountOnline.bottom
+ anchors.left: parent.left
+ anchors.right: separator.right
+ margin-top: 5
+ SkillNameLabel
+ !text: tr('Loyalty Title')
+ color: #C0C0C0
+ SkillValueLabel
+ !text: tr('33')
+ color: #C0C0C0
+
+ Label
+ id: skillsLabel
+ !text: tr('Skills')
+ color: #C0C0C0
+ anchors.top: level.top
+ anchors.horizontalCenter: parent.horizontalCenter
+ margin-left: 125
+ CharacterSkillBase
+ id: magiclevel
+ anchors.top: skillsLabel.bottom
+ anchors.left: separator.left
+ anchors.right: parent.right
+ margin-top: 10
+ SkillNameLabel
+ !text: tr('Magic')
+ color: #C0C0C0
+ SkillValueLabel
+ SkillCharacterIcon
+ anchors.left: parent.left
+ image-clip: 27 0 9 9
+ SkillCharacterPercentPanel
+ anchors.left: icon.right
+ margin-top: 15
+ margin-left: 5
+ background-color: #00C000
+ CharacterSkillBase
+ id: skillId0
+ anchors.top: magiclevel.bottom
+ anchors.left: separator.left
+ anchors.right: parent.right
+ margin-top: 13
+ SkillNameLabel
+ !text: tr('Fist')
+ color: #C0C0C0
+ SkillValueLabel
+ SkillCharacterIcon
+ anchors.left: parent.left
+ image-clip: 0 0 9 9
+ SkillCharacterPercentPanel
+ anchors.left: icon.right
+ margin-top: 15
+ margin-left: 5
+ background-color: #00C000
+ CharacterSkillBase
+ id: skillId1
+ anchors.top: skillId0.bottom
+ anchors.left: separator.left
+ anchors.right: parent.right
+ margin-top: 13
+ SkillNameLabel
+ !text: tr('Club')
+ color: #C0C0C0
+ SkillValueLabel
+ SkillCharacterIcon
+ anchors.left: parent.left
+ image-clip: 45 0 9 9
+ SkillCharacterPercentPanel
+ anchors.left: icon.right
+ margin-top: 15
+ margin-left: 5
+ background-color: #00C000
+ CharacterSkillBase
+ id: skillId2
+ anchors.top: skillId1.bottom
+ anchors.left: separator.left
+ anchors.right: parent.right
+ margin-top: 13
+ SkillNameLabel
+ !text: tr('Sword')
+ color: #C0C0C0
+ SkillValueLabel
+ SkillCharacterIcon
+ anchors.left: parent.left
+ image-clip: 36 0 9 9
+ SkillCharacterPercentPanel
+ anchors.left: icon.right
+ margin-top: 15
+ margin-left: 5
+ background-color: #00C000
+ CharacterSkillBase
+ id: skillId3
+ anchors.top: skillId2.bottom
+ anchors.left: separator.left
+ anchors.right: parent.right
+ margin-top: 13
+ SkillNameLabel
+ !text: tr('Axe')
+ color: #C0C0C0
+ SkillValueLabel
+ SkillCharacterIcon
+ anchors.left: parent.left
+ image-clip: 54 0 9 9
+ SkillCharacterPercentPanel
+ anchors.left: icon.right
+ margin-top: 15
+ margin-left: 5
+ background-color: #00C000
+ CharacterSkillBase
+ id: skillId4
+ anchors.top: skillId3.bottom
+ anchors.left: separator.left
+ anchors.right: parent.right
+ margin-top: 13
+ SkillNameLabel
+ !text: tr('Distance')
+ color: #C0C0C0
+ SkillValueLabel
+ SkillCharacterIcon
+ anchors.left: parent.left
+ image-clip: 18 0 9 9
+ SkillCharacterPercentPanel
+ anchors.left: icon.right
+ margin-top: 15
+ margin-left: 5
+ background-color: #00C000
+ CharacterSkillBase
+ id: skillId5
+ anchors.top: skillId4.bottom
+ anchors.left: separator.left
+ anchors.right: parent.right
+ margin-top: 13
+ SkillNameLabel
+ !text: tr('Shielding')
+ color: #C0C0C0
+ SkillValueLabel
+ SkillCharacterIcon
+ anchors.left: parent.left
+ image-clip: 63 0 9 9
+ SkillCharacterPercentPanel
+ anchors.left: icon.right
+ margin-top: 15
+ margin-left: 5
+ background-color: #00C000
+ CharacterSkillBase
+ id: skillId6
+ anchors.top: skillId5.bottom
+ anchors.left: separator.left
+ anchors.right: parent.right
+ margin-top: 13
+ SkillNameLabel
+ !text: tr('Fishing')
+ color: #C0C0C0
+ SkillValueLabel
+ SkillCharacterIcon
+ anchors.left: parent.left
+ image-clip: 72 0 9 9
+ SkillCharacterPercentPanel
+ anchors.left: icon.right
+ margin-top: 15
+ margin-left: 5
+ background-color: #00C000
+ Label
+ !text: tr('Account Badges')
+ margin-top: 12
+ anchors.top: skillId6.bottom
+ anchors.left: separator.left
+ anchors.right: parent.right
+ margin-left: 75
+
+ UIScrollArea
+ id: ListBadge
+ vertical-scrollbar: ListBadgeScrollbar
+ anchors.top: prev.bottom
+ anchors.left: separator.left
+ anchors.right: parent.right
+ height: 140
+ border-width: 1
+ border-color: #00000077
+ background-color: #ffffff11
+ layout:
+ type: grid
+ cell-size: 64 64
+ cell-spacing: 5
+ flow: true
+ fit-children: false
+ padding-left: 20
+
+
+ VerticalScrollBar
+ id: ListBadgeScrollbar
+ anchors.top: ListBadge.top
+ anchors.right: ListBadge.right
+ anchors.bottom: ListBadge.bottom
+ margin: 1
+ margin-bottom: 10
+
+ step: 5
+ pixel-scroll: true
+
+ BorderBox
+ id: CombatStats
+ anchors.top: CharacterBase.top
+ anchors.left: CharacterBase.right
+ anchors.bottom: OptionsBase.bottom
+ anchors.right: parent.right
+ margin-left: 10
+ visible: false
+
+ VerticalSeparator
+ id: separator
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ margin-top: 5
+ margin-bottom: 5
+ CharacterSkillBase
+ id: attack
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.right: separator.right
+ margin-top: 5
+ margin-left: 5
+ SkillNameLabel
+ !text: tr('Attack Value:')
+ color: #C0C0C0
+ SkillValueLabel
+ color: #C0C0C0
+ anchors.right: next.left
+ margin-right: 8
+ !text: ('100')
+ SkillCharacterIcon
+ margin-top: 2
+ anchors.right: parent.right
+ CharacterSkillBase
+ id: converted
+ anchors.top: attack.bottom
+ anchors.left: parent.left
+ anchors.right: separator.right
+ margin-top: 0
+ SkillNameLabel
+ !text: tr('Converted Damage:')
+ color: #C0C0C0
+ SkillValueLabel
+ id: none
+ color: #C0C0C0
+ !text: tr('None')
+ margin-right: 2
+ visible: false
+ SkillValueLabel
+ color: #C0C0C0
+ anchors.right: next.left
+ margin-right: 8
+ !text: ('100')
+ SkillCharacterIcon
+ margin-top: 2
+ anchors.right: parent.right
+ CharacterSkillBase
+ id: defence
+ anchors.top: converted.bottom
+ anchors.left: parent.left
+ anchors.right: separator.right
+ margin-top: 0
+ SkillNameLabel
+ !text: tr('Defence Value:')
+ color: #C0C0C0
+ SkillValueLabel
+ color: #C0C0C0
+ margin-right: 2
+ CharacterSkillBase
+ id: armor
+ anchors.top: defence.bottom
+ anchors.left: parent.left
+ anchors.right: separator.right
+ margin-top: 1
+ SkillNameLabel
+ !text: tr('Armor Value:')
+ color: #C0C0C0
+ SkillValueLabel
+ color: #C0C0C0
+ margin-right: 2
+ CharacterSkillBase
+ id: mitigation
+ anchors.top: armor.bottom
+ anchors.left: parent.left
+ anchors.right: separator.right
+ margin-top: 0
+ SkillNameLabel
+ !text: tr('Mitigation:')
+ color: #C0C0C0
+ SkillValueLabel
+ color: #C0C0C0
+ margin-right: 2
+ CharacterSkillBase
+ id: blessings
+ anchors.top: mitigation.bottom
+ anchors.left: parent.left
+ anchors.right: separator.right
+ margin-top: 1
+ SkillNameLabel
+ !text: tr('Blessings:')
+ color: #C0C0C0
+ SkillValueLabel
+ color: #C0C0C0
+ margin-right: 20
+ UIButton
+ id: blessButton
+ size: 12 12
+ anchors.top: parent.top
+ anchors.right: parent.right
+ margin-top: 1
+ margin-right: 3
+ image-clip: 0 0 12 12
+ image-source: /images/inventory/button_blessings_grey
+ @onClick: modules.game_blessing.toggle()
+ $pressed:
+ image-source: /images/inventory/button_blessings_grey
+ image-clip: 12 0 12 12
+ $on:
+ image-source: /images/inventory/button_blessings_grey
+ image-clip: 12 0 12 12
+ $on pressed:
+ image-source: /images/inventory/button_blessings_grey
+ image-clip: 12 0 12 12
+ CharacterSkillBase
+ id: reduction
+ anchors.top: blessings.bottom
+ anchors.left: parent.left
+ anchors.right: separator.right
+ margin-top: 1
+ SkillNameLabel
+ !text: tr('Damage Reduction:')
+ color: #C0C0C0
+ Panel
+ id: reductionNone
+ anchors.top: reduction.bottom
+ anchors.left: reduction.left
+ anchors.right: separator.right
+
+ color: #f00303
+ background-color: #355d89
+ shader: Map - Party
+ margin-left: 10
+ margin-top: 10
+ size: 232 233
+ layout:
+ type: verticalBox
+ fit-children: true
+
+ CharacterSkillBase
+ id: criticalHit
+ anchors.top: attack.top
+ anchors.left: separator.left
+ anchors.right: parent.right
+ margin-top: 1
+ SkillNameLabel
+ !text: tr('Critical Hit:')
+ color: #C0C0C0
+ CharacterSkillBase
+ id: criticalChance
+ anchors.top: criticalHit.bottom
+ anchors.left: separator.left
+ anchors.right: parent.right
+ margin-left: 15
+ margin-top: 0
+ SkillNameLabel
+ !text: tr('Chance')
+ color: #C0C0C0
+ SkillValueLabel
+ color: #C0C0C0
+ margin-right: 2
+ CharacterSkillBase
+ id: criticalDamage
+ anchors.top: criticalChance.bottom
+ anchors.left: prev.left
+ anchors.right: parent.right
+ margin-left: 0
+ margin-top: 0
+ SkillNameLabel
+ !text: tr('Extra Damage')
+ color: #C0C0C0
+ SkillValueLabel
+ color: #C0C0C0
+ margin-right: 2
+ CharacterSkillBase
+ id: lifeLeech
+ anchors.top: criticalDamage.bottom
+ anchors.left: criticalHit.left
+ anchors.right: parent.right
+ margin-left: 0
+ margin-top: 0
+ SkillNameLabel
+ !text: tr('Life Leech:')
+ color: #C0C0C0
+ SkillValueLabel
+ color: #C0C0C0
+ margin-right: 2
+ CharacterSkillBase
+ id: manaLeech
+ anchors.top: lifeLeech.bottom
+ anchors.left: criticalHit.left
+ anchors.right: parent.right
+ margin-left: 0
+ margin-top: 0
+ SkillNameLabel
+ !text: tr('Mana Leech:')
+ color: #C0C0C0
+ SkillValueLabel
+ color: #C0C0C0
+ margin-right: 2
+ UIWidget
+ id: RecentDeaths
+ anchors.top: CharacterBase.top
+ anchors.left: CharacterBase.right
+ anchors.bottom: OptionsBase.bottom
+ anchors.right: parent.right
+ margin-left: 10
+ visible: false
+ BorderBox
+ id: ListBase
+ size: 494 380
+ anchors.top: parent.top
+ anchors.left: parent.left
+ UIWidget
+ height: 16
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.top: parent.top
+ image-source: /images/game/actionbar/1pixel-down-frame
+ image-border: 5
+ UIWidget
+ anchors.fill: parent
+ margin: 1
+ background-color: #363636
+ Label
+ !text: tr('Data and Time')
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ anchors.left: parent.left
+ margin-left: 3
+ margin-top: 1
+ color: #C0C0C0
+ width: 154
+ VerticalSeparator
+ id: separator
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ anchors.left: prev.right
+ Label
+ !text: tr('Cause of Death')
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ anchors.left: separator.left
+ anchors.right: parent.right
+ margin-left: 5
+ margin-top: 1
+ color: #C0C0C0
+ UIScrollArea
+ id: List
+ vertical-scrollbar: ListScrollbar
+ anchors.fill: parent
+ margin: 1
+ margin-top: 16
+ padding-right: 15
+ background-color: #404040
+ layout:
+ type: verticalBox
+ spacing: 3
+ VerticalScrollBar
+ id: ListScrollbar
+ anchors.top: List.top
+ anchors.right: List.right
+ anchors.bottom: List.bottom
+ margin: 1
+ margin-top: -15
+ step: 80
+ pixel-scroll: true
+ Button
+ id: previous
+ size: 86 20
+ !text: tr('Previous')
+ //font: verdana-bold-8px-antialiased
+ anchors.top: ListBase.bottom
+ anchors.left: parent.left
+ margin-top: 7
+ text-offset: 0 -1
+ color: #C0C0C0
+ enabled: false
+ Button
+ id: next
+ size: 86 20
+ !text: tr('Next')
+ //font: verdana-bold-8px-antialiased
+ anchors.top: ListBase.bottom
+ anchors.right: parent.right
+ margin-right: -5
+ margin-top: 7
+ text-offset: 0 -1
+ color: #C0C0C0
+ enabled: false
+ Label
+ id: pages
+ !text: tr('Page 1 / 1')
+ color: #C0C0C0
+ anchors.verticalCenter: previous.verticalCenter
+ anchors.horizontalCenter: parent.horizontalCenter
+ UIWidget
+ id: RecentKills
+ anchors.top: CharacterBase.top
+ anchors.left: CharacterBase.right
+ anchors.bottom: OptionsBase.bottom
+ anchors.right: parent.right
+ margin-left: 10
+ visible: false
+ BorderBox
+ id: ListBase
+ size: 494 380
+ anchors.top: parent.top
+ anchors.left: parent.left
+ UIWidget
+ height: 16
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.top: parent.top
+ image-source: /images/game/actionbar/1pixel-down-frame
+ image-border: 5
+ UIWidget
+ anchors.fill: parent
+ margin: 1
+ background-color: #363636
+ Label
+ !text: tr('Data and Time')
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ anchors.left: parent.left
+ margin-left: 3
+ margin-top: 1
+ color: #C0C0C0
+ width: 154
+ VerticalSeparator
+ id: separator
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ anchors.left: prev.right
+ Label
+ !text: tr('Description')
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ anchors.left: separator.left
+ anchors.right: parent.right
+ margin-left: 5
+ margin-top: 1
+ color: #C0C0C0
+ VerticalSeparator
+ id: separatorTwo
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ anchors.right: parent.right
+ margin-right: 100
+ Label
+ !text: tr('Status')
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ anchors.left: separatorTwo.left
+ anchors.right: parent.right
+ margin-left: 5
+ margin-top: 1
+ color: #C0C0C0
+ UIScrollArea
+ id: List
+ vertical-scrollbar: ListScrollbar
+ anchors.fill: parent
+ margin: 1
+ margin-top: 16
+ padding-right: 15
+ background-color: #404040
+ layout:
+ type: verticalBox
+ spacing: -1
+ VerticalScrollBar
+ id: ListScrollbar
+ anchors.top: List.top
+ anchors.right: List.right
+ anchors.bottom: List.bottom
+ margin: 1
+ margin-top: -15
+ step: 80
+ pixel-scroll: true
+ Button
+ id: previous
+ size: 86 20
+ !text: tr('Previous')
+ //font: verdana-bold-8px-antialiased
+ anchors.top: ListBase.bottom
+ anchors.left: parent.left
+ margin-top: 7
+ text-offset: 0 -1
+ color: #C0C0C0
+ enabled: false
+ Button
+ id: next
+ size: 86 20
+ !text: tr('Next')
+ //font: verdana-bold-8px-antialiased
+ anchors.top: ListBase.bottom
+ anchors.right: parent.right
+ margin-right: -5
+ margin-top: 7
+ text-offset: 0 -1
+ color: #C0C0C0
+ enabled: false
+ Label
+ id: pages
+ !text: tr('Page 1 / 1')
+ color: #C0C0C0
+ anchors.verticalCenter: previous.verticalCenter
+ anchors.horizontalCenter: parent.horizontalCenter
+ UIWidget
+ id: CharacterAchievements
+ anchors.top: CharacterBase.top
+ anchors.left: CharacterBase.right
+ anchors.bottom: OptionsBase.bottom
+ anchors.right: parent.right
+ margin-left: 10
+ visible: false
+ UIWidget
+ id: achievements
+ width: 150
+ anchors.top: parent.top
+ anchors.bottom: ListBase.top
+ anchors.left: parent.left
+ Label
+ id: Points
+ text-auto-resize: true
+ !text: tr('Achievements Points: ') .. 0
+ color: #C0C0C0
+ anchors.top: parent.top
+ anchors.left: parent.left
+ Label
+ id: gradeOne
+ text-auto-resize: true
+ !text: tr('Grade 1: ') .. 0
+ color: #C0C0C0
+ anchors.top: prev.bottom
+ anchors.right: parent.right
+ margin-right: 14
+ UIWidget
+ image-source: /game_cyclopedia/images/icon-achievement
+ anchors.top: gradeOne.top
+ anchors.right: gradeOne.left
+ margin-top: 2
+ margin-right: 5
+ Label
+ id: gradeTwo
+ text-auto-resize: true
+ !text: tr('Grade 2: ') .. 0
+ color: #C0C0C0
+ anchors.top: gradeOne.bottom
+ anchors.right: gradeOne.right
+ UIWidget
+ image-source: /game_cyclopedia/images/icon-achievement
+ image-repeated: true
+ width: 22
+ anchors.top: gradeTwo.top
+ anchors.right: gradeTwo.left
+ margin-top: 2
+ margin-right: 4
+ Label
+ id: gradeThree
+ text-auto-resize: true
+ !text: tr('Grade 3: ') .. 0
+ color: #C0C0C0
+ anchors.top: gradeTwo.bottom
+ anchors.right: gradeTwo.right
+ UIWidget
+ image-source: /game_cyclopedia/images/icon-achievement
+ image-repeated: true
+ width: 33
+ anchors.top: gradeThree.top
+ anchors.right: gradeThree.left
+ margin-top: 2
+ margin-right: 4
+ Label
+ id: gradeFour
+ text-auto-resize: true
+ !text: tr('Grade 4: ') .. 0
+ color: #C0C0C0
+ anchors.top: gradeThree.bottom
+ anchors.right: gradeThree.right
+ UIWidget
+ image-source: /game_cyclopedia/images/icon-achievement
+ image-repeated: true
+ width: 44
+ anchors.top: gradeFour.top
+ anchors.right: gradeFour.left
+ margin-top: 2
+ margin-right: 4
+ UIWidget
+ id: filters
+ width: 114
+ image-source: /images/game/actionbar/1pixel-down-frame
+ image-border: 5
+ anchors.top: achievements.top
+ anchors.bottom: ListBase.top
+ anchors.left: achievements.right
+ margin-bottom: 6
+ margin-left: 10
+ RoundCheckBox
+ id: all
+ width: 85
+ text: All
+ color: #C0C0C0
+ text-offset: 15 0
+ anchors.top: parent.top
+ anchors.left: parent.left
+ margin-left: 5
+ margin-top: 10
+ @onClick: modules.game_cyclopedia.Cyclopedia.achievementFilter(self)
+ RoundCheckBox
+ id: locked
+ width: 85
+ text: Locked
+ color: #C0C0C0
+ text-offset: 15 0
+ anchors.top: all.bottom
+ anchors.left: all.left
+ margin-top: 5
+ @onClick: modules.game_cyclopedia.Cyclopedia.achievementFilter(self)
+ RoundCheckBox
+ id: accomplished
+ width: 100
+ text: Accomplished
+ color: #C0C0C0
+ text-offset: 15 0
+ anchors.top: locked.bottom
+ anchors.left: locked.left
+ margin-top: 5
+ checked: true
+ @onClick: modules.game_cyclopedia.Cyclopedia.achievementFilter(self)
+ ComboBox
+ id: sort
+ size: 145 20
+ anchors.top: parent.top
+ anchors.right: parent.right
+ margin-top: -5
+ @onOptionChange: modules.game_cyclopedia.Cyclopedia.achievementSort(self:getCurrentOption().data)
+ Label
+ !text: ('Sort')
+ anchors.top: sort.top
+ anchors.right: sort.left
+ margin-right: 5
+ margin-top: 4
+ UIWidget
+ id: regular
+ height: 20
+ image-source: /images/game/actionbar/1pixel-down-frame
+ image-border: 5
+ anchors.top: sort.bottom
+ anchors.left: sort.left
+ anchors.right: sort.right
+ margin-top: 5
+ UIWidget
+ anchors.fill: parent
+ image-source: /images/ui/backdrop-dark-grey
+ image-border: 5
+ margin: 1
+ Label
+ id: value
+ text-auto-resize: true
+ !text: ('0/329')
+ anchors.centerIn: parent
+ Label
+ !text: ('Regular')
+ anchors.top: regular.top
+ anchors.right: regular.left
+ margin-right: 5
+ margin-top: 3
+ UIWidget
+ id: secret
+ height: 20
+ image-source: /images/game/actionbar/1pixel-down-frame
+ image-border: 5
+ anchors.top: regular.bottom
+ anchors.left: regular.left
+ anchors.right: regular.right
+ margin-top: 5
+ UIWidget
+ anchors.fill: parent
+ image-source: /images/ui/backdrop-dark-grey
+ image-border: 5
+ margin: 1
+ Label
+ id: value
+ text-auto-resize: true
+ !text: ('0/0')
+ anchors.centerIn: parent
+ Label
+ !text: ('Secret')
+ anchors.top: secret.top
+ anchors.right: secret.left
+ margin-right: 5
+ margin-top: 3
+ BorderBox
+ id: ListBase
+ size: 494 335
+ anchors.bottom: parent.bottom
+ anchors.left: parent.left
+ margin-bottom: 10
+ UIScrollArea
+ id: List
+ vertical-scrollbar: ListScrollbar
+ anchors.fill: parent
+ margin: 1
+ margin-right: 15
+ layout:
+ type: verticalBox
+ VerticalScrollBar
+ id: ListScrollbar
+ anchors.top: List.top
+ anchors.right: List.right
+ anchors.bottom: List.bottom
+ margin: 1
+ margin-right: -13
+ step: 80
+ pixel-scroll: true
+ UIWidget
+ id: CharacterItems
+ anchors.top: CharacterBase.top
+ anchors.left: CharacterBase.right
+ anchors.bottom: OptionsBase.bottom
+ anchors.right: parent.right
+ margin-left: 10
+ visible: false
+ UIWidget
+ id: gridBase
+ size: 494 340
+ anchors.bottom: parent.bottom
+ anchors.left: parentl.left
+ visible: false
+ UIScrollArea
+ id: grid
+ vertical-scrollbar: gridScrollbar
+ anchors.fill: parent
+ margin-right: 15
+ layout:
+ type: grid
+ cell-size: 34 34
+ cell-spacing: 3
+ flow: true
+ VerticalScrollBar
+ id: gridScrollbar
+ anchors.top: grid.top
+ anchors.right: grid.right
+ anchors.bottom: grid.bottom
+ margin: 1
+ margin-right: -13
+ margin-top: 0
+ step: 80
+ pixel-scroll: true
+ BorderBox
+ id: ListBase
+ size: 494 340
+ anchors.bottom: parent.bottom
+ anchors.left: parentl.left
+ UIWidget
+ id: listTop
+ height: 16
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.top: parent.top
+ image-source: /images/game/actionbar/1pixel-down-frame
+ image-border: 5
+ UIWidget
+ anchors.fill: parent
+ margin: 1
+ background-color: #363636
+ Label
+ !text: tr('Name')
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ anchors.left: parent.left
+ margin-left: 3
+ margin-top: 1
+ color: #C0C0C0
+ width: 154
+ VerticalSeparator
+ id: separator
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ anchors.right: parent.right
+ margin-right: 150
+ Label
+ !text: tr('Amount')
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ anchors.left: separator.left
+ anchors.right: parent.right
+ margin-left: 5
+ margin-top: 1
+ color: #C0C0C0
+ UIScrollArea
+ id: list
+ vertical-scrollbar: listScrollbar
+ anchors.fill: parent
+ margin: 1
+ margin-right: 15
+ margin-top: 16
+ background-color: #404040
+ layout:
+ type: verticalBox
+ spacing: 0
+ VerticalScrollBar
+ id: listScrollbar
+ anchors.top: list.top
+ anchors.right: list.right
+ anchors.bottom: list.bottom
+ margin: 1
+ margin-right: -13
+ margin-top: -15
+ step: 80
+ pixel-scroll: true
+ UIWidget
+ id: filters
+ height: 55
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.right: ListBase.right
+ image-source: /images/game/actionbar/2pixel-up-frame-borderimage
+ image-border: 5
+ CheckBox
+ id: inventory
+ width: 85
+ text: Inventory
+ color: #C0C0C0
+ text-offset: 15 0
+ anchors.top: parent.top
+ anchors.left: parent.left
+ margin-left: 8
+ margin-top: 8
+ @onCheckChange: modules.game_cyclopedia.Cyclopedia.characterItemsFilter(self)
+ CheckBox
+ id: depot
+ width: 85
+ text: Depot
+ color: #C0C0C0
+ text-offset: 15 0
+ anchors.top: inventory.top
+ anchors.left: inventory.right
+ margin-left: 10
+ @onCheckChange: modules.game_cyclopedia.Cyclopedia.characterItemsFilter(self)
+ CheckBox
+ id: stash
+ width: 100
+ text: Supply Stash
+ color: #C0C0C0
+ text-offset: 15 0
+ anchors.top: depot.bottom
+ anchors.left: depot.left
+ margin-top: 8
+ @onCheckChange: modules.game_cyclopedia.Cyclopedia.characterItemsFilter(self)
+ CheckBox
+ id: inbox
+ width: 100
+ text: Inbox
+ color: #C0C0C0
+ text-offset: 15 0
+ anchors.top: depot.top
+ anchors.left: depot.right
+ margin-left: 30
+ @onCheckChange: modules.game_cyclopedia.Cyclopedia.characterItemsFilter(self)
+ CheckBox
+ id: store
+ width: 100
+ text: Store Inbox
+ color: #C0C0C0
+ text-offset: 15 0
+ anchors.top: inbox.bottom
+ anchors.left: inbox.left
+ margin-top: 8
+ @onCheckChange: modules.game_cyclopedia.Cyclopedia.characterItemsFilter(self)
+ TextEdit
+ id: SearchEdit
+ size: 120 16
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.right: parent.right
+ margin-right: 7
+ padding-top: 2
+ padding-right: 15
+ padding-bottom: 0
+ placeholder: Type to search
+ placeholder-color: #6E706F
+ @onTextChange: modules.game_cyclopedia.Cyclopedia.characterItemsSearch(self:getText())
+ UIWidget
+ id: listFilter
+ height: 20
+ anchors.top: filters.bottom
+ anchors.left: parent.left
+ anchors.right: filters.right
+ image-source: /images/game/actionbar/2pixel-up-frame-borderimage
+ image-border: 5
+ margin-top: 5
+ RoundCheckBox
+ id: list
+ width: 85
+ text: show as list
+ color: #C0C0C0
+ text-offset: 15 0
+ anchors.centerIn: parent
+ margin-right: 70
+ @onClick: modules.game_cyclopedia.Cyclopedia.characterItemListFilter(self)
+ RoundCheckBox
+ id: grid
+ width: 100
+ text: show as grid
+ color: #C0C0C0
+ text-offset: 15 0
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.left: list.right
+ margin-left: 20
+ margin-bottom: 3
+ @onClick: modules.game_cyclopedia.Cyclopedia.characterItemListFilter(self)
+ UIWidget
+ id: CharacterAppearances
+ anchors.top: CharacterBase.top
+ anchors.left: CharacterBase.right
+ anchors.bottom: OptionsBase.bottom
+ anchors.right: parent.right
+ margin-left: 10
+ visible: false
+ UIWidget
+ id: listFilter
+ height: 34
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.right: parent.right
+ image-source: /images/game/actionbar/2pixel-up-frame-borderimage
+ image-border: 5
+ RoundCheckBox
+ id: outfits
+ width: 85
+ text: Outfits
+ color: #C0C0C0
+ text-offset: 15 0
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.left: parent.left
+ margin-left: 10
+ @onClick: modules.game_cyclopedia.Cyclopedia.characterAppearancesFilter(self)
+ RoundCheckBox
+ id: mounts
+ width: 85
+ text: Mounts
+ color: #C0C0C0
+ text-offset: 15 0
+ margin-bottom: 3
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.left: outfits.right
+ @onClick: modules.game_cyclopedia.Cyclopedia.characterAppearancesFilter(self)
+ RoundCheckBox
+ id: familiars
+ width: 85
+ text: Familiars
+ color: #C0C0C0
+ text-offset: 15 0
+ anchors.verticalCenter: parent.verticalCenter
+ margin-bottom: 3
+ anchors.left: mounts.right
+ @onClick: modules.game_cyclopedia.Cyclopedia.characterAppearancesFilter(self)
+ ComboBox
+ id: show
+ size: 222 20
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.left: familiars.right
+
+ @onSetup: |
+ self:addOption("Show All")
+ self:addOption("Show Standard Outfits")
+ self:addOption("Show Quest Outfits")
+ self:addOption("Show Store Outfits")
+ BorderBox
+ id: ListBase
+ size: 489 376
+ anchors.bottom: parent.bottom
+ anchors.left: parent.left
+ UIScrollArea
+ id: list
+ vertical-scrollbar: listScrollbar
+ anchors.fill: parent
+ margin: 5
+ margin-right: 10
+ layout:
+ type: grid
+ cell-size: 152 110
+ cell-spacing: 5
+ flow: true
+ VerticalScrollBar
+ id: listScrollbar
+ anchors.top: list.top
+ anchors.right: list.right
+ anchors.bottom: list.bottom
+ margin: 1
+ margin-right: -13
+ margin-top: 0
+ step: 80
+ pixel-scroll: true
+ UIWidget
+ id: StoreSummary
+ anchors.top: CharacterBase.top
+ anchors.left: CharacterBase.right
+ anchors.bottom: OptionsBase.bottom
+ anchors.right: parent.right
+ margin-left: 10
+ visible: false
+ BorderBox
+ id: ListBase
+ size: 494 380
+ anchors.top: parent.top
+ anchors.left: parent.left
+ UIScrollArea
+ id: List
+ vertical-scrollbar: ListScrollbarStoreSummary
+ anchors.fill: parent
+ margin: 1
+
+ padding-right: 15
+ background-color: #404040
+ layout:
+ type: verticalBox
+ spacing: 3
+
+ MiniPanel
+ id:XPBoosts
+ image-source: /images/ui/outfits/minipanel
+ image-border: 5
+ color: #C0C0C0
+ height: 66
+ padding-bottom: 5
+ margin: 5
+ margin-bottom: 1
+ text: XP Boosts
+
+ Label
+ id: RemainingStoreXPBoostTime
+ text-auto-resize: true
+ color: #909090
+ anchors.top: parent.top
+ anchors.left: parent.left
+ margin-top: 2
+ text: Remaining Store XP Boost Time:
+
+ Label
+ id: RemainingStoreXPBoostTimeValue
+ anchors.top: parent.top
+ anchors.left: parent.right
+ margin-left: -32
+ margin-top: 2
+ text: 00:00222222222
+
+ Label
+ id: RemainingDailyRewardXPBoostTime
+ text-auto-resize: true
+ color: #909090
+ anchors.top: RemainingStoreXPBoostTime.bottom
+ anchors.left: RemainingStoreXPBoostTime.left
+ margin-top: 2
+ text: Remaining Daily Reward XP Boost Time:
+
+ Label
+ id: RemainingDailyRewardXPBoostTimeValue
+ anchors.top: RemainingStoreXPBoostTimeValue.bottom
+ anchors.left: parent.right
+ margin-left: -30
+ margin-top: 2
+ text: 00:00222222222
+
+ MiniPanel
+ id:Blessings
+ image-source: /images/ui/outfits/minipanel
+ image-border: 5
+ color: #C0C0C0
+ padding-bottom: 5
+ margin: 5
+ margin-bottom: 1
+ text: Blessings
+ size: 225 135
+
+ Label
+ id: AvailableBlessings
+ text-auto-resize: true
+ color: #909090
+ anchors.top: parent.top
+ anchors.left: parent.left
+ margin-top: 2
+ text: Available Blessings:
+
+ Panel
+ id: PurchasedHouseItems
+ size: 225 100
+ margin-top: 15
+ anchors.fill: parent
+ image-border: 3
+ layout:
+ type: grid
+ cell-size: 224 20
+ flow: true
+
+
+ MiniPanel
+ id: preyPanel
+ image-source: /images/ui/outfits/minipanel
+ image-border: 5
+ color: #C0C0C0
+ height: 66
+ padding-bottom: 5
+ margin: 5
+ margin-bottom: 1
+ text: Prey
+
+ Label
+ id: PermanentPreySlots
+ text-auto-resize: true
+ color: #909090
+ anchors.top: parent.top
+ anchors.left: parent.left
+ margin-top: 2
+ text: Permanent Prey Slots:
+
+ Label
+ id: PermanentPreySlotsValue
+ anchors.top: parent.top
+ anchors.left: parent.right
+ margin-left: -30
+ margin-top: 2
+ text: 1x
+
+ Label
+ id: PreyWildcards
+ text-auto-resize: true
+ color: #909090
+ anchors.top: PermanentPreySlots.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ text: Prey Wildcards:
+
+ Label
+ id: PreyWildcardsValue
+ anchors.top: PermanentPreySlotsValue.bottom
+ anchors.left: parent.right
+ margin-left: -30
+ margin-top: 2
+ text: 20x
+
+ MiniPanel
+ id: dailyReward
+ image-source: /images/ui/outfits/minipanel
+ image-border: 5
+ color: #C0C0C0
+ height: 66
+ padding-bottom: 5
+ margin: 5
+ margin-bottom: 1
+ text: Daily Reward
+
+ Label
+ id: InstantRewardAccess
+ text-auto-resize: true
+ color: #909090
+ anchors.top: parent.top
+ anchors.left: parent.left
+ margin-top: 2
+ text: Instant Reward Access:
+
+ Label
+ id: InstantRewardAccessValue
+ anchors.top: parent.top
+ anchors.left: parent.right
+ margin-left: -30
+ text: 0x
+
+ MiniPanel
+ id: CharmPanel
+ image-source: /images/ui/outfits/minipanel
+ image-border: 5
+ color: #C0C0C0
+ height: 66
+ padding-bottom: 5
+ margin: 5
+ margin-bottom: 1
+ text: Charm
+
+ Label
+ id: CharmExpansion
+ text-auto-resize: true
+ color: #909090
+ anchors.top: parent.top
+ anchors.left: parent.left
+ margin-top: 2
+ text: Charm Expansion:
+
+ Label
+ id: CharmExpansionValue
+ anchors.top: parent.top
+ anchors.left: parent.right
+ margin-left: -30
+ text: Nooooo
+
+ MiniPanel
+ id: hirelings
+ image-source: /images/ui/outfits/minipanel
+ image-border: 5
+ color: #C0C0C0
+
+ padding-bottom: 5
+ margin: 5
+ margin-bottom: 1
+ text: hirelings
+
+ Label
+ id: PurchasedHireLings
+ text-auto-resize: true
+ color: #909090
+ anchors.top: parent.top
+ anchors.left: parent.left
+ margin-top: 2
+ text: Purchased Hirelngs:
+
+ Label
+ id: PurchasedHirelingsValue
+ anchors.top: parent.top
+ anchors.left: parent.right
+ margin-left: -30
+ text: 0x
+
+
+ Label
+ id: hirelingjobs
+ text-auto-resize: true
+ color: #909090
+ anchors.top: PurchasedHireLings.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ text: hireling jobs:
+
+ Label
+ id: hirelingOutfits
+ text-auto-resize: true
+ color: #909090
+ anchors.top: prev.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ text: hirelingOutfits:
+
+ MiniPanel
+ id: houseItems
+ image-source: /images/ui/outfits/minipanel
+ image-border: 5
+ color: #C0C0C0
+ height: 66
+ padding-bottom: 5
+ margin: 5
+ margin-bottom: 1
+ size: 530 407
+ text: Purchased House Items
+
+ Panel
+ id: PurchasedHouseItems
+ size: 225 74
+ anchors.fill: parent
+
+ image-border: 3
+ layout:
+ type: grid
+ cell-size: 224 74
+ flow: true
+ VerticalScrollBar
+ id: ListScrollbarStoreSummary
+ anchors.top: List.top
+ anchors.right: List.right
+ anchors.bottom: List.bottom
+ margin: 1
+
+ step: 80
+ pixel-scroll: true
+ UIWidget
+ id: CharacterTitles
+ anchors.top: CharacterBase.top
+ anchors.left: CharacterBase.right
+ anchors.bottom: OptionsBase.bottom
+ anchors.right: parent.right
+ margin-left: 10
+ visible: false
+
+ VerticalScrollBar
+ id: ListScrollbar
+ anchors.top: List.top
+ anchors.right: List.right
+ anchors.bottom: List.bottom
+ margin: 1
+
+ step: 80
+ pixel-scroll: true
\ No newline at end of file
diff --git a/modules/game_cyclopedia/tab/charms/charms.lua b/modules/game_cyclopedia/tab/charms/charms.lua
new file mode 100644
index 0000000000..5616136a54
--- /dev/null
+++ b/modules/game_cyclopedia/tab/charms/charms.lua
@@ -0,0 +1,482 @@
+local UI = nil
+
+function showCharms()
+ UI = g_ui.loadUI("charms", contentContainer)
+ UI:show()
+ g_game.requestBestiary()
+ controllerCyclopedia.ui.CharmsBase:setVisible(true)
+ controllerCyclopedia.ui.GoldBase:setVisible(true)
+ controllerCyclopedia.ui.BestiaryTrackerButton:setVisible(false)
+end
+
+Cyclopedia.Charms = {}
+
+local CHARMS = {
+ { ID = 9, IMAGE = "/game_cyclopedia/images/charms/9", TYPE = 1 },
+ { ID = 11, IMAGE = "/game_cyclopedia/images/charms/11", TYPE = 2 },
+ { ID = 10, IMAGE = "/game_cyclopedia/images/charms/10", TYPE = 3 },
+ { ID = 6, IMAGE = "/game_cyclopedia/images/charms/6", TYPE = 2 },
+ { ID = 8, IMAGE = "/game_cyclopedia/images/charms/8", TYPE = 2 },
+ { ID = 7, IMAGE = "/game_cyclopedia/images/charms/7", TYPE = 3 },
+ { ID = 5, IMAGE = "/game_cyclopedia/images/charms/5", TYPE = 4 },
+ { ID = 1, IMAGE = "/game_cyclopedia/images/charms/1", TYPE = 4 },
+ { ID = 3, IMAGE = "/game_cyclopedia/images/charms/3", TYPE = 4 },
+ { ID = 2, IMAGE = "/game_cyclopedia/images/charms/2", TYPE = 4 },
+ { ID = 0, IMAGE = "/game_cyclopedia/images/charms/0", TYPE = 4 },
+ { ID = 4, IMAGE = "/game_cyclopedia/images/charms/4", TYPE = 4 },
+ { ID = 16, IMAGE = "/game_cyclopedia/images/charms/16", TYPE = 5 },
+ { ID = 15, IMAGE = "/game_cyclopedia/images/charms/15", TYPE = 6 },
+ { ID = 17, IMAGE = "/game_cyclopedia/images/charms/17", TYPE = 6 },
+ { ID = 13, IMAGE = "/game_cyclopedia/images/charms/13", TYPE = 6 },
+ { ID = 12, IMAGE = "/game_cyclopedia/images/charms/12", TYPE = 6 },
+ { ID = 14, IMAGE = "/game_cyclopedia/images/charms/14", TYPE = 6 },
+ { ID = 18, IMAGE = "/game_cyclopedia/images/charms/18", TYPE = 6 },
+}
+
+function Cyclopedia.UpdateCharmsBalance(Value)
+ for i, child in pairs(UI.Bottombase:getChildren()) do
+ if child.CharmsBase then
+ child.CharmsBase.Value:setText(Value)
+ end
+ end
+end
+
+function Cyclopedia.CreateCharmItem(data)
+ local widget = g_ui.createWidget("CharmItem", UI.CharmList)
+ local value = widget.PriceBase.Value
+
+ widget:setId(data.id)
+
+ if data.id ~= nil then
+ widget.charmBase.image:setImageSource("/game_cyclopedia/images/charms/" .. data.id)
+ else
+ print("Error: CHARMS[" .. tostring(data.id) .. "] is nil")
+ return
+ end
+
+ widget:setText(data.name)
+ widget.data = data
+
+ if data.asignedStatus then
+ if data.raceId and RACE[data.raceId] then
+ widget.InfoBase.Sprite:setOutfit({
+ type = Cyclopedia.safeOutfit(RACE[data.raceId] and RACE[data.raceId].type or 22)
+ })
+
+ widget.InfoBase.Sprite:getCreature():setStaticWalking(1000)
+ else
+ print("Error: RACE[" .. tostring(data.raceId) .. "] es nil")
+ end
+ end
+
+ if data.unlocked then
+ widget.PriceBase.Charm:setVisible(false)
+ widget.PriceBase.Gold:setVisible(true)
+ widget.charmBase.lockedMask:setVisible(false)
+ widget.icon = 1
+ if data.asignedStatus then
+ widget.PriceBase.Value:setText(comma_value(data.removeRuneCost))
+ else
+ widget.PriceBase.Value:setText(0)
+ end
+ else
+ widget.PriceBase.Charm:setVisible(true)
+ widget.PriceBase.Gold:setVisible(false)
+ widget.charmBase.lockedMask:setVisible(true)
+ widget.PriceBase.Value:setText(comma_value(data.unlockPrice))
+ widget.icon = 0
+ end
+
+ if widget.icon == 1 and g_game.getLocalPlayer():getResourceBalance(1) then
+ if data.removeRuneCost > g_game.getLocalPlayer():getResourceBalance(1) then
+ value:setColor("#D33C3C")
+ else
+ value:setColor("#C0C0C0")
+ end
+ end
+
+ if widget.icon == 0 then
+ if data.unlockPrice > UI.CharmsPoints then
+ value:setColor("#D33C3C")
+ else
+ value:setColor("#C0C0C0")
+ end
+ end
+end
+
+function Cyclopedia.loadCharms(charmsData)
+ controllerCyclopedia.ui.CharmsBase.Value:setText(Cyclopedia.formatGold(charmsData.points))
+
+ if UI == nil or UI.CharmList == nil then -- I know, don't change it
+ return
+ end
+
+ UI.CharmsPoints = charmsData.points
+
+ local raceIdNamePairs = {}
+
+ for _, raceId in ipairs(charmsData.finishedMonsters) do
+ table.insert(raceIdNamePairs, {
+ raceId = raceId,
+ name = RACE and RACE.name or "buscar_" .. raceId
+ })
+ end
+
+ local function compareByName(a, b)
+ return a.name:lower() < b.name:lower()
+ end
+
+ table.sort(raceIdNamePairs, compareByName)
+
+ Cyclopedia.Charms.Monsters = {}
+
+ for _, pair in ipairs(raceIdNamePairs) do
+ table.insert(Cyclopedia.Charms.Monsters, pair.raceId)
+ end
+
+ UI.CharmList:destroyChildren()
+
+ local formatedData = {}
+
+ for _, charmData in pairs(charmsData.charms) do
+ local internalId = (charmData.id)
+ if internalId then
+ charmData.internalId = internalId
+ charmData.typePriority = CHARMS[internalId + 1].TYPE
+ table.insert(formatedData, charmData)
+ end
+ end
+
+ table.sort(formatedData, function(a, b)
+ if a.unlocked == b.unlocked then
+ if a.typePriority == b.typePriority then
+ return a.name < b.name
+ else
+ return a.typePriority < b.typePriority
+ end
+ else
+ return a.unlocked and not b.unlocked
+ end
+ end)
+
+ for _, value in ipairs(formatedData) do
+ Cyclopedia.CreateCharmItem(value)
+ end
+
+ if Cyclopedia.Charms.redirect then
+ Cyclopedia.selectCharm(UI.CharmList:getChildById(Cyclopedia.Charms.redirect),
+ UI.CharmList:getChildById(Cyclopedia.Charms.redirect):isChecked())
+ Cyclopedia.Charms.redirect = nil
+ else
+ Cyclopedia.selectCharm(UI.CharmList:getChildByIndex(1), UI.CharmList:getChildByIndex(1):isChecked())
+ end
+end
+
+function Cyclopedia.selectCharm(widget, isChecked)
+ UI.InformationBase.CreaturesBase.CreatureList:destroyChildren()
+
+ local parent = widget:getParent()
+ local button = UI.InformationBase.UnlockButton
+ local value = UI.InformationBase.PriceBase.Value
+
+ UI.InformationBase.data = widget.data
+
+ local function format(text)
+ local capitalizedText = text:gsub("(%l)(%w*)", function(first, rest)
+ return first:upper() .. rest
+ end)
+
+ if #capitalizedText > 19 then
+ return capitalizedText:sub(1, 16) .. "..."
+ else
+ return capitalizedText
+ end
+ end
+
+ for i = 1, parent:getChildCount() do
+ local internalWidget = parent:getChildByIndex(i)
+
+ if internalWidget:isChecked() and widget:getId() ~= internalWidget:getId() then
+ internalWidget:setChecked(false)
+ end
+ end
+
+ if not isChecked then
+ widget:setChecked(true)
+ end
+
+ UI.InformationBase.TextBase:setText(widget.data.description)
+ UI.InformationBase.ItemBase.image:setImageSource(widget.charmBase.image:getImageSource())
+
+ if widget.data.asignedStatus then
+ UI.InformationBase.InfoBase.sprite:setVisible(true)
+ UI.InformationBase.InfoBase.sprite:setOutfit({
+ type = Cyclopedia.safeOutfit(RACE[widget.data.raceId] and RACE[widget.data.raceId].type or 22)
+ })
+ UI.InformationBase.InfoBase.sprite:getCreature():setStaticWalking(1000)
+ UI.InformationBase.InfoBase.sprite:setOpacity(1)
+ else
+ UI.InformationBase.InfoBase.sprite:setVisible(false)
+ end
+
+ if widget.icon == 1 then
+ UI.InformationBase.PriceBase.Gold:setVisible(true)
+ UI.InformationBase.PriceBase.Charm:setVisible(false)
+ else
+ UI.InformationBase.PriceBase.Gold:setVisible(false)
+ UI.InformationBase.PriceBase.Charm:setVisible(true)
+ end
+
+ if widget.icon == 1 and g_game.getLocalPlayer():getResourceBalance(1) then
+ if widget.data.removeRuneCost > g_game.getLocalPlayer():getResourceBalance(1) then
+ value:setColor("#D33C3C")
+ button:setEnabled(false)
+ else
+ value:setColor("#C0C0C0")
+ button:setEnabled(true)
+ end
+
+ if widget.data.unlocked and not widget.data.asignedStatus then
+ value:setText(0)
+ else
+ value:setText(comma_value(widget.data.removeRuneCost))
+ end
+ end
+
+ if widget.icon == 0 then
+ if widget.data.unlockPrice > UI.CharmsPoints then
+ value:setColor("#D33C3C")
+ button:setEnabled(false)
+ else
+ value:setColor("#C0C0C0")
+ button:setEnabled(true)
+ end
+
+ value:setText(widget.data.unlockPrice)
+ end
+
+ if widget.data.unlocked and not widget.data.asignedStatus then
+ button:setText("Select")
+
+ local color = "#484848"
+
+ for index, raceId in ipairs(Cyclopedia.Charms.Monsters) do
+ local internalWidget = g_ui.createWidget("CharmCreatureName", UI.InformationBase.CreaturesBase.CreatureList)
+ internalWidget:setId(index)
+ internalWidget:setText(format(RACE[raceId].name))
+ internalWidget.raceId = raceId
+ internalWidget:setBackgroundColor(color)
+ internalWidget.color = color
+ color = color == "#484848" and "#414141" or "#484848"
+ end
+
+ button:setEnabled(false)
+ UI.InformationBase.SearchEdit:setEnabled(true)
+ UI.InformationBase.SearchLabel:setEnabled(true)
+ UI.InformationBase.CreaturesLabel:setEnabled(true)
+ end
+
+ if widget.data.asignedStatus then
+ button:setText("Remove")
+
+ local internalWidget = g_ui.createWidget("CharmCreatureName", UI.InformationBase.CreaturesBase.CreatureList)
+ internalWidget:setText(format(RACE[widget.data.raceId].name))
+ internalWidget:setEnabled(false)
+ internalWidget:setColor("#707070")
+ UI.InformationBase.SearchEdit:setEnabled(false)
+ UI.InformationBase.SearchLabel:setEnabled(false)
+ UI.InformationBase.CreaturesLabel:setEnabled(false)
+ end
+
+ if not widget.data.unlocked then
+ button:setText("Unlock")
+ UI.InformationBase.SearchEdit:setEnabled(false)
+ UI.InformationBase.SearchLabel:setEnabled(false)
+ UI.InformationBase.CreaturesLabel:setEnabled(false)
+ end
+end
+
+function Cyclopedia.selectCreatureCharm(widget, isChecked)
+ local parent = widget:getParent()
+
+ for i = 1, parent:getChildCount() do
+ local internalWidget = parent:getChildByIndex(i)
+
+ if internalWidget:isChecked() and widget:getId() ~= internalWidget:getId() then
+ internalWidget:setChecked(false)
+ internalWidget:setBackgroundColor(internalWidget.color)
+ end
+ end
+
+ if not isChecked then
+ widget:setChecked(true)
+ end
+
+ UI.InformationBase.InfoBase.sprite:setVisible(true)
+ UI.InformationBase.InfoBase.sprite:setOutfit({
+ type = Cyclopedia.safeOutfit(RACE[widget.raceId] and RACE[widget.raceId].type or 22)
+ })
+ UI.InformationBase.InfoBase.sprite:getCreature():setStaticWalking(1000)
+ UI.InformationBase.InfoBase.sprite:setOpacity(0.5)
+ UI.InformationBase.UnlockButton:setEnabled(true)
+
+ Cyclopedia.Charms.SelectedCreature = widget.raceId
+end
+
+function Cyclopedia.searchCharmMonster(text)
+ UI.InformationBase.CreaturesBase.CreatureList:destroyChildren()
+
+ local function format(string)
+ local capitalizedText = string:gsub("(%l)(%w*)", function(first, rest)
+ return first:upper() .. rest
+ end)
+
+ if #capitalizedText > 19 then
+ return capitalizedText:sub(1, 16) .. "..."
+ else
+ return capitalizedText
+ end
+ end
+
+ local function getColor(currentColor)
+ return currentColor == "#484848" and "#414141" or "#484848"
+ end
+
+ local searchedMonsters = {}
+
+ if text ~= "" then
+ for _, raceId in ipairs(Cyclopedia.Charms.Monsters) do
+ local name = RACE[raceId].name
+ if string.find(name:lower(), text:lower()) then
+ table.insert(searchedMonsters, raceId)
+ end
+ end
+ else
+ searchedMonsters = Cyclopedia.Charms.Monsters
+ end
+
+ local color = "#484848"
+
+ for _, raceId in ipairs(searchedMonsters) do
+ local internalWidget = g_ui.createWidget("CharmCreatureName", UI.InformationBase.CreaturesBase.CreatureList)
+ internalWidget:setId(raceId)
+ internalWidget:setText(format(RACE[raceId].name))
+ internalWidget.raceId = raceId
+ internalWidget:setBackgroundColor(color)
+ internalWidget.color = color
+ color = getColor(color)
+ end
+end
+
+function Cyclopedia.actionCharmButton(widget)
+ local confirmWindow
+ local type = widget:getText()
+ local data = widget:getParent().data
+
+ if type == "Unlock" then
+ local function yesCallback()
+ g_game.BuyCharmRune(data.id)
+ if confirmWindow then
+ confirmWindow:destroy()
+ confirmWindow = nil
+ -- Cyclopedia.Toggle(true, false, 3)
+ end
+
+ Cyclopedia.Charms.redirect = data.id
+ end
+
+ local function noCallback()
+ if confirmWindow then
+ confirmWindow:destroy()
+ confirmWindow = nil
+ end
+ end
+
+ if not confirmWindow then
+ confirmWindow = displayGeneralBox(tr("Confirm Unlocking of Charm"), tr(
+ "Do you want to unlock the Charm %s? This will cost you %d Charm Points?", data.name, data.unlockPrice),
+ {
+ {
+ text = tr("Yes"),
+ callback = yesCallback
+ },
+ {
+ text = tr("No"),
+ callback = noCallback
+ },
+ anchor = AnchorHorizontalCenter
+ }, yesCallback, noCallback
+ )
+ end
+ end
+
+ if type == "Select" then
+ local function yesCallback()
+ g_game.BuyCharmRune(data.id, 1, Cyclopedia.Charms.SelectedCreature)
+ if confirmWindow then
+ confirmWindow:destroy()
+ confirmWindow = nil
+ end
+ Cyclopedia.Charms.redirect = data.id
+ end
+
+ local function noCallback()
+ if confirmWindow then
+ confirmWindow:destroy()
+ confirmWindow = nil
+ end
+ end
+
+ if not confirmWindow then
+ confirmWindow = displayGeneralBox(tr("Confirm Selected Charm"),
+ tr("Do you want to use the Charm %s for this creature?", data.name), {
+ {
+ text = tr("Yes"),
+ callback = yesCallback
+ },
+ {
+ text = tr("No"),
+ callback = noCallback
+ },
+ anchor = AnchorHorizontalCenter
+ }, yesCallback, noCallback
+ )
+ end
+ end
+
+ if type == "Remove" then
+ local function yesCallback()
+ g_game.BuyCharmRune(data.id, 2)
+ if confirmWindow then
+ confirmWindow:destroy()
+ confirmWindow = nil
+ end
+
+ Cyclopedia.Charms.redirect = data.id
+ end
+
+ local function noCallback()
+ if confirmWindow then
+ confirmWindow:destroy()
+ confirmWindow = nil
+ end
+ end
+
+ if not confirmWindow then
+ confirmWindow = displayGeneralBox(tr("Confirm Charm Removal"),
+ tr("Do you want to remove the Charm %s from this creature? This will cost you %s gold pieces.",
+ data.name, comma_value(data.removeRuneCost)), {
+ {
+ text = tr("Yes"),
+ callback = yesCallback
+ },
+ {
+ text = tr("No"),
+ callback = noCallback
+ },
+ anchor = AnchorHorizontalCenter
+ }, yesCallback, noCallback
+ )
+ end
+ end
+end
diff --git a/modules/game_cyclopedia/tab/charms/charms.otui b/modules/game_cyclopedia/tab/charms/charms.otui
new file mode 100644
index 0000000000..f8fabf220d
--- /dev/null
+++ b/modules/game_cyclopedia/tab/charms/charms.otui
@@ -0,0 +1,200 @@
+UIWidget
+ id: Cat3
+ anchors.fill: parent
+ visible: false
+ SubPanel
+ id: InformationBase
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.bottom: parent.bottom
+ margin-bottom: 30
+ margin-top: 10
+ width: 163
+ !text: tr('Information')
+ UIWidget
+ id: TextBase
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.right: parent.right
+ margin: 20 5 5 5
+ height: 110
+ text-align: topLeft
+ text-wrap: true
+ color: #C1C1C1
+ margin-top: 25
+ BorderBox
+ id: InfoBase
+ anchors.top: parent.top
+ anchors.right: parent.right
+ margin-top: 140
+ margin-right: 7
+ image-source: /images/ui/panel_flat
+ image-border: 10
+ size: 66 66
+ phantom: true
+ UICreature
+ id: sprite
+ anchors.centerIn: parent
+ size: 64 64
+ Button
+ id: UnlockButton
+ size: 75 20
+ anchors.bottom: InfoBase.bottom
+ anchors.left: parent.left
+ margin-left: 10
+ margin-right: 10
+ !text: tr('Unlock')
+ //font: verdana-bold-8px-antialiased
+ text-offset: 0 -1
+ color: #C0C0C0
+ enabled: false
+ @onClick: modules.game_cyclopedia.Cyclopedia.actionCharmButton(self)
+ BorderBox
+ id: ItemBase
+ anchors.top: InfoBase.top
+ anchors.horizontalCenter: UnlockButton.horizontalCenter
+ image-source: /images/ui/panel_flat
+ image-border: 10
+ size: 37 37
+ phantom: true
+ UIWidget
+ size: 32 32
+ id: image
+ anchors.centerIn: parent
+ phantom: true
+ UIWidget
+ id: PriceBase
+ anchors.left: UnlockButton.left
+ anchors.right: UnlockButton.right
+ anchors.top: UnlockButton.bottom
+ margin-top: 5
+ height: 20
+ image-source: /images/ui/item
+ image-border: 10
+ phantom: true
+ Label
+ id: Value
+ anchors.centerIn: parent
+ !text: tr('0')
+ text-auto-resize: true
+ UIWidget
+ id: Charm
+ anchors.left: Value.right
+ anchors.verticalCenter: parent.verticalCenter
+ margin-left: 2
+ image-source: /game_cyclopedia/images/icon_charms
+ UIWidget
+ id: Gold
+ anchors.left: Value.right
+ anchors.verticalCenter: parent.verticalCenter
+ margin-left: 2
+ image-source: /game_cyclopedia/images/icon_gold
+ visible: false
+ UIWidget
+ id: StoreButton
+ anchors.right: InfoBase.right
+ anchors.top: PriceBase.top
+ margin-top: -2
+ size: 26 20
+ image-source: /game_cyclopedia/images/button_store
+ image-clip: 0 0 26 20
+ $pressed:
+ image-source: /game_cyclopedia/images/button_store
+ image-clip: 0 20 26 20
+ UIWidget
+ id: InfoButton
+ anchors.right: StoreButton.left
+ anchors.verticalCenter: StoreButton.verticalCenter
+ margin-right: 5
+ image-source: /images/icons/show_gui_help_grey
+ !tooltip: ('You can assign 4 more Charms to creatures.\nBuy a "Charm Expansion" to assign your unlocked Charms to\ncreatures nearly unlimitedly and to get a 25% discount whenever\nyou are removing a Charm.')
+ TextEdit
+ id: SearchEdit
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.bottom: parent.bottom
+ margin-bottom: 10
+ color: #C0C0C0
+ placeholder: Type to search
+ placeholder-color: #6E706F
+ padding-top: 1
+ size: 140 17
+ @onTextChange: modules.game_cyclopedia.Cyclopedia.searchCharmMonster(self:getText())
+ Label
+ id: SearchLabel
+ anchors.left: SearchEdit.left
+ anchors.bottom: SearchEdit.top
+ margin-bottom: 5
+ color: #C0C0C0
+ !text: tr('Search') .. ':'
+ BorderBox
+ id: CreaturesBase
+ anchors.bottom: SearchEdit.top
+ anchors.right: SearchEdit.right
+ anchors.left: SearchEdit.left
+ margin-bottom: 30
+ image-source: /images/ui/panel_flat
+ image-border: 10
+ height: 105
+ phantom: true
+ UIScrollArea
+ id: CreatureList
+ vertical-scrollbar: CreatureListScrollbar
+ anchors.fill: parent
+ margin-right: 13
+ padding-left: 3
+ padding-top: 3
+ padding-bottom: 2
+ layout:
+ type: grid
+ cell-size: 125 15
+ cell-spacing: 2
+ flow: true
+ CharmCreatureName
+ background-color: #484848
+ CharmCreatureName
+ background-color: #414141
+ VerticalScrollBar
+ id: CreatureListScrollbar
+ anchors.top: parent.top
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ step: 80
+ pixel-scroll: true
+ Label
+ id: CreaturesLabel
+ anchors.left: CreaturesBase.left
+ anchors.bottom: CreaturesBase.top
+ margin-bottom: 5
+ color: #C0C0C0
+ !text: tr('Select Creature') .. ':'
+ BorderBox
+ id: ListBase
+ anchors.bottom: InformationBase.bottom
+ anchors.top: parent.top
+ anchors.left: InformationBase.right
+ anchors.right: parent.right
+ margin-top: 10
+ margin-left: 10
+ UIScrollArea
+ id: CharmList
+ vertical-scrollbar: CharmListScrollbar
+ anchors.fill: ListBase
+ margin-right: 13
+
+ padding-left: 3
+ padding-right: 2
+ padding-top: 5
+ padding-bottom: 2
+ layout:
+ type: grid
+ cell-size: 158 94
+ cell-spacing: 2
+ flow: true
+ VerticalScrollBar
+ id: CharmListScrollbar
+ anchors.top: ListBase.top
+ anchors.right: ListBase.right
+ anchors.bottom: ListBase.bottom
+ step: 80
+
+ pixel-scroll: true
diff --git a/modules/game_cyclopedia/tab/house/house.lua b/modules/game_cyclopedia/tab/house/house.lua
new file mode 100644
index 0000000000..dba48199d4
--- /dev/null
+++ b/modules/game_cyclopedia/tab/house/house.lua
@@ -0,0 +1,1460 @@
+local UI = nil
+
+function showHouse()
+ UI = g_ui.loadUI("house", contentContainer)
+ UI:show()
+ UI.LateralBase.LayerScrollbar.decrementButton:setVisible(false)
+ UI.LateralBase.LayerScrollbar.incrementButton:setVisible(false)
+ UI.LateralBase.LayerScrollbar.sliderButton:setImageSource("")
+ --[[
+ g_ui.createWidget("MapLayerSelector", UI.LateralBase.LayerScrollbar.sliderButton)
+ function UI.LateralBase.LayerScrollbar:onValueChange(value)
+ local rect = {
+ width = 14,
+ height = 67,
+ y = 0,
+ x = Cyclopedia.ConvertLayer(value) * 14
+ }
+
+ UI.LateralBase.LayerIndicator:setImageClip(rect)
+ end
+ ]]--
+
+ UI.LateralBase.LayerScrollbar:setValue(150)
+
+ controllerCyclopedia.ui.CharmsBase:setVisible(false)
+ controllerCyclopedia.ui.GoldBase:setVisible(true)
+ controllerCyclopedia.ui.BestiaryTrackerButton:setVisible(false)
+
+ -- Cyclopedia.House.Data = json_data
+
+ if not Cyclopedia.House.Loaded then
+ for i = 1, #Cyclopedia.StateList do
+ UI.TopBase.StatesOption:addOption(Cyclopedia.StateList[i].Title, i)
+ UI.TopBase.StatesOption.onOptionChange = Cyclopedia.houseChangeState
+ end
+
+ for i = 0, #Cyclopedia.CityList do
+ UI.TopBase.CityOption:addOption(Cyclopedia.CityList[i].Title, i)
+ UI.TopBase.CityOption.onOptionChange = Cyclopedia.selectTown
+ end
+
+ for i = 1, #Cyclopedia.SortList do
+ UI.TopBase.SortOption:addOption(Cyclopedia.SortList[i].Title, i)
+ UI.TopBase.SortOption.onOptionChange = Cyclopedia.houseSort
+ end
+
+ Cyclopedia.House.Loaded = true
+ Cyclopedia.houseFilter(UI.TopBase.HousesCheck)
+ end
+
+ UI.bidArea:setVisible(false)
+ UI.ListBase:setVisible(true)
+ Cyclopedia.selectTown({
+ data = 0
+ })
+ UI.TopBase.StatesOption:setOption("All States", true)
+ UI.TopBase.CityOption:setOption("Own Houses", true)
+ UI.TopBase.SortOption:setOption("Sort by name", true)
+
+ Cyclopedia.House.lastTown = nil
+end
+
+Cyclopedia.House = {}
+Cyclopedia.StateList = {
+ { Title = "All States" },
+ { Title = "Auctioned" },
+ { Title = "Rented" }
+}
+
+Cyclopedia.CityList = {
+ [0] = { Title = "Own Houses" },
+ { Title = "Ab'Dendriel" },
+ { Title = "Ankrahmun" },
+ { Title = "Carlin" },
+ { Title = "Darashia" },
+ { Title = "Edron" },
+ { Title = "Farmine" },
+ { Title = "Gray Beach" },
+ { Title = "Issavi" },
+ { Title = "Kazordoon" },
+ { Title = "Liberty Bay" },
+ { Title = "Moonfall" },
+ { Title = "Port Hope" },
+ { Title = "Rathleton" },
+ { Title = "Silvertides" },
+ { Title = "Svargrond" },
+ { Title = "Thais" },
+ { Title = "Venore" },
+ { Title = "Yalahar" }
+}
+
+Cyclopedia.SortList = {
+ { Title = "Sort by name" },
+ { Title = "Sort by size" },
+ { Title = "Sort by rent" },
+ { Title = "Sort by bid" },
+ { Title = "Sort by auction end" }
+}
+
+local function resetButtons()
+ if UI.LateralBase:getChildById("bidButton") then
+ UI.LateralBase:getChildById("bidButton"):destroy()
+ end
+
+ if UI.LateralBase:getChildById("transferButton") then
+ UI.LateralBase:getChildById("transferButton"):destroy()
+ end
+
+ if UI.LateralBase:getChildById("moveOutButton") then
+ UI.LateralBase:getChildById("moveOutButton"):destroy()
+ end
+
+ if UI.LateralBase:getChildById("cancelTransfer") then
+ UI.LateralBase:getChildById("cancelTransfer"):destroy()
+ end
+
+ if UI.LateralBase:getChildById("acceptTransfer") then
+ UI.LateralBase:getChildById("acceptTransfer"):destroy()
+ end
+
+ if UI.LateralBase:getChildById("rejectTransfer") then
+ UI.LateralBase:getChildById("rejectTransfer"):destroy()
+ end
+end
+
+local function resetSelectedInfo()
+ UI.LateralBase.yourLimitBidGold:setVisible(false)
+ UI.LateralBase.yourLimitBid:setVisible(false)
+ UI.LateralBase.yourLimitLabel:setVisible(false)
+ UI.LateralBase.highestBid:setVisible(false)
+ UI.LateralBase.highestBidGold:setVisible(false)
+ UI.LateralBase.subAuctionLabel:setVisible(false)
+ UI.LateralBase.subAuctionText:setVisible(false)
+ UI.LateralBase.transferLabel:setVisible(false)
+ UI.LateralBase.transferValue:setVisible(false)
+ UI.LateralBase.transferGold:setVisible(false)
+end
+
+function Cyclopedia.houseChangeState(widget)
+ if Cyclopedia.House.Data then
+ local onlyGuildHall = UI.TopBase.GuildhallsCheck:isChecked()
+ local type = widget:getCurrentOption().data
+ for _, data in ipairs(Cyclopedia.House.Data) do
+ if onlyGuildHall then
+ data.visible = data.gh
+ elseif type == 3 then
+ data.visible = data.rented or data.inTransfer
+ elseif type == 2 then
+ data.visible = not data.rented
+ else
+ data.visible = true
+ end
+ end
+
+ Cyclopedia.reloadHouseList()
+ Cyclopedia.House.lastChangeState = widget
+ end
+end
+
+function Cyclopedia.houseMessage(houseId, type, message)
+ local confirmWindow
+ local function yesCallback()
+ if confirmWindow then
+ confirmWindow:destroy()
+ confirmWindow = nil
+ Cyclopedia.Toggle(true, false, 5)
+ end
+ end
+
+ if type == 1 then
+ if message == 0 then
+ if not confirmWindow then
+ confirmWindow = displayGeneralBox(tr("Summary"), tr(
+ "Your bid was successfull. You are currently holding the highest bid."), {
+ {
+ text = tr("Ok"),
+ callback = yesCallback
+ },
+ anchor = AnchorHorizontalCenter
+ }, yesCallback)
+
+ UI.ListBase:setVisible(true)
+ UI.bidArea:setVisible(false)
+ Cyclopedia.Toggle(true, false)
+ end
+ elseif message == 17 then
+ confirmWindow = displayGeneralBox(tr("Summary"), tr(
+ "Bid failed.\nYour character's bank acocunt balance is too low to pay the bid and the rent for the first month."),
+ {
+ {
+ text = tr("Ok"),
+ callback = yesCallback
+ },
+ anchor = AnchorHorizontalCenter
+ }, yesCallback)
+
+ UI.ListBase:setVisible(true)
+ UI.bidArea:setVisible(false)
+ Cyclopedia.Toggle(true, false)
+ end
+ elseif type == 2 then
+ if message == 0 then
+ confirmWindow = displayGeneralBox(tr("Summary"), tr("You have sucessfully iniated your move out."), {
+ {
+ text = tr("Ok"),
+ callback = yesCallback
+ },
+ anchor = AnchorHorizontalCenter
+ }, yesCallback)
+
+ UI.moveOutArea:setVisible(false)
+ UI.ListBase:setVisible(true)
+ Cyclopedia.Toggle(true, false)
+ end
+ elseif type == 3 then
+ if message == 0 then
+ confirmWindow = displayGeneralBox(tr("Summary"),
+ tr("You have sucessfully initiated the transfer of your house."), {
+ {
+ text = tr("Ok"),
+ callback = yesCallback
+ },
+ anchor = AnchorHorizontalCenter
+ }, yesCallback)
+
+ UI.transferArea:setVisible(false)
+ UI.ListBase:setVisible(true)
+ Cyclopedia.Toggle(true, false)
+ elseif message == 4 then
+ confirmWindow = displayGeneralBox(tr("Summary"), tr(
+ "Setting up a house transfer failed.\nA character with this name does not exist."), {
+ {
+ text = tr("Ok"),
+ callback = yesCallback
+ },
+ anchor = AnchorHorizontalCenter
+ }, yesCallback)
+
+ UI.transferArea:setVisible(false)
+ UI.ListBase:setVisible(true)
+ Cyclopedia.Toggle(true, false)
+ end
+ elseif type == 5 then
+ if message == 0 then
+ confirmWindow = displayGeneralBox(tr("Summary"), tr(
+ "You have sucessfully cancelled the transfer. You will keep the house."), {
+ {
+ text = tr("Ok"),
+ callback = yesCallback
+ },
+ anchor = AnchorHorizontalCenter
+ }, yesCallback)
+
+ UI.cancelHouseTransferArea:setVisible(false)
+ UI.ListBase:setVisible(true)
+ Cyclopedia.Toggle(true, false)
+ end
+ elseif type == 6 then
+ if message == 0 then
+ confirmWindow = displayGeneralBox(tr("Summary"), tr("You have sucessfully accepted the transfer."), {
+ {
+ text = tr("Ok"),
+ callback = yesCallback
+ },
+ anchor = AnchorHorizontalCenter
+ }, yesCallback)
+
+ UI.acceptTransferHouse:setVisible(false)
+ UI.ListBase:setVisible(true)
+ Cyclopedia.Toggle(true, false)
+ end
+ elseif type == 7 and message == 0 then
+ confirmWindow = displayGeneralBox(tr("Summary"), tr(
+ "You jected the house transfer sucessfully. The old owner will keep the house."), {
+ {
+ text = tr("Ok"),
+ callback = yesCallback
+ },
+ anchor = AnchorHorizontalCenter
+ }, yesCallback)
+
+ UI.rejectTransferHouse:setVisible(false)
+ UI.ListBase:setVisible(true)
+ Cyclopedia.Toggle(true, false)
+ end
+end
+
+function Cyclopedia.rejectTransfer()
+ UI.ListBase:setVisible(false)
+ UI.rejectTransferHouse:setVisible(true)
+
+ local house = Cyclopedia.House.lastSelectedHouse.data
+ local time = os.date("%Y-%m-%d, %H:%M CET", house.paidUntil)
+ local transferTime = os.date("%Y-%m-%d, %H:%M CET", house.transferTime)
+
+ function UI.rejectTransferHouse.cancel.onClick()
+ UI.rejectTransferHouse:setVisible(false)
+ UI.ListBase:setVisible(true)
+ end
+
+ function UI.rejectTransferHouse.transfer:onClick()
+ local confirmWindow
+ local function yesCallback()
+ if confirmWindow then
+ confirmWindow:destroy()
+ confirmWindow = nil
+ Cyclopedia.Toggle(true, false, 5)
+ end
+
+ g_game.requestRejectHouseTransfer(house.id)
+
+ Cyclopedia.House.ignore = true
+ --[[
+ if Cyclopedia.House.lastTown then
+ g_game.requestShowHouses(Cyclopedia.House.lastTown)
+ else
+ g_game.requestShowHouses("")
+ end
+ ]]--
+
+ UI.TopBase.StatesOption:setOption("All States", true)
+ UI.TopBase.SortOption:setOption("Sort by name", true)
+ end
+
+ local function noCallback()
+ if confirmWindow then
+ confirmWindow:destroy()
+ confirmWindow = nil
+ Cyclopedia.Toggle(true, false, 5)
+ end
+ end
+
+ if not confirmWindow then
+ confirmWindow = displayGeneralBox(tr("Confirm House Action"), tr(
+ "Do you really want to reject the transfer for the house '%s' offered by %s?\nYou will not get the house. %s will keep the house and can set up a new transfer anytime.",
+ house.name, house.owner, house.owner), {
+ {
+ text = tr("Yes"),
+ callback = yesCallback
+ },
+ {
+ text = tr("No"),
+ callback = noCallback
+ },
+ anchor = AnchorHorizontalCenter
+ }, yesCallback, noCallback)
+
+ Cyclopedia.Toggle(true, false)
+ end
+ end
+
+ UI.rejectTransferHouse.name:setText(house.name .. "asdasd")
+ UI.rejectTransferHouse.size:setText(house.sqm .. " sqm")
+ UI.rejectTransferHouse.beds:setText(house.beds)
+ UI.rejectTransferHouse.rent:setText((house.rent))
+ UI.rejectTransferHouse.paid:setText(time)
+ UI.rejectTransferHouse.owner:setText(house.transferName)
+ UI.rejectTransferHouse.transferDate:setText(transferTime)
+ UI.rejectTransferHouse.transferPrice:setText(comma_value(house.transferValue))
+end
+
+function Cyclopedia.acceptTransfer()
+ UI.ListBase:setVisible(false)
+ UI.acceptTransferHouse:setVisible(true)
+
+ local house = Cyclopedia.House.lastSelectedHouse.data
+ local time = os.date("%Y-%m-%d, %H:%M CET", house.paidUntil)
+ local transferTime = os.date("%Y-%m-%d, %H:%M CET", house.transferTime)
+
+ function UI.acceptTransferHouse.cancel.onClick()
+ UI.acceptTransferHouse:setVisible(false)
+ UI.ListBase:setVisible(true)
+ end
+
+ function UI.acceptTransferHouse.transfer:onClick()
+ local confirmWindow
+
+ local function yesCallback()
+ if confirmWindow then
+ confirmWindow:destroy()
+ confirmWindow = nil
+ Cyclopedia.Toggle(true, false, 5)
+ end
+
+ g_game.requestAcceptHouseTransfer(house.id)
+ Cyclopedia.House.ignore = true
+
+ -- g_game.requestShowHouses("")
+ UI.TopBase.StatesOption:setOption("All States", true)
+ UI.TopBase.SortOption:setOption("Sort by name", true)
+ end
+
+ local function noCallback()
+ if confirmWindow then
+ confirmWindow:destroy()
+ confirmWindow = nil
+ Cyclopedia.Toggle(true, false, 5)
+ end
+ end
+
+ if not confirmWindow then
+ confirmWindow = displayGeneralBox(tr("Confirm House Action"), tr(
+ "Do you want to accept the house transfer offered by %s for the property '%s'?\nThe transfer is scheduled for %s.\nThe transfer price was set to %s.\n\nMake sure to have enough gold in your bank account to pay the costs for this house transfer and the next rent.\nRemember to edit the door rights as only the guest list will be reset after the transfer!",
+ house.owner, house.name, transferTime, comma_value(house.transferValue)), {
+ {
+ text = tr("Yes"),
+ callback = yesCallback
+ },
+ {
+ text = tr("No"),
+ callback = noCallback
+ },
+ anchor = AnchorHorizontalCenter
+ }, yesCallback, noCallback)
+
+ Cyclopedia.Toggle(true, false)
+ end
+ end
+
+ UI.acceptTransferHouse.name:setText(house.name .. "22222")
+ UI.acceptTransferHouse.size:setText(house.sqm .. " sqm")
+ UI.acceptTransferHouse.beds:setText(house.beds)
+ UI.acceptTransferHouse.rent:setText((house.rent))
+ UI.acceptTransferHouse.paid:setText(time)
+ UI.acceptTransferHouse.owner:setText(house.transferName)
+ UI.acceptTransferHouse.transferDate:setText(transferTime)
+ UI.acceptTransferHouse.transferPrice:setText(comma_value(house.transferValue))
+end
+
+function Cyclopedia.cancelTransfer()
+ UI.ListBase:setVisible(false)
+ UI.cancelHouseTransferArea:setVisible(true)
+
+ local house = Cyclopedia.House.lastSelectedHouse.data
+ local time = os.date("%Y-%m-%d, %H:%M CET", house.paidUntil)
+ local transferTime = os.date("%Y-%m-%d, %H:%M CET", house.transferTime)
+
+ function UI.cancelHouseTransferArea.cancel.onClick()
+ UI.cancelHouseTransferArea:setVisible(false)
+ UI.ListBase:setVisible(true)
+ end
+
+ function UI.cancelHouseTransferArea.transfer:onClick()
+ local confirmWindow
+
+ local function yesCallback()
+ if confirmWindow then
+ confirmWindow:destroy()
+ confirmWindow = nil
+ Cyclopedia.Toggle(true, false, 5)
+ end
+
+ g_game.requestCancelHouseTransfer(house.id)
+
+ Cyclopedia.House.ignore = true
+ --[[
+ if Cyclopedia.House.lastTown then
+ g_game.requestShowHouses(Cyclopedia.House.lastTown)
+ else
+ g_game.requestShowHouses("")
+ end
+ ]]--
+
+ UI.TopBase.StatesOption:setOption("All States", true)
+ UI.TopBase.SortOption:setOption("Sort by name", true)
+ end
+
+ local function noCallback()
+ if confirmWindow then
+ confirmWindow:destroy()
+ confirmWindow = nil
+ Cyclopedia.Toggle(true, false, 5)
+ end
+ end
+
+ if not confirmWindow then
+ confirmWindow = displayGeneralBox(tr("Confirm House Action"),
+ tr("Do you really want to keep your house '%s'?\nYou will no longer transfer the house to %s on %s.",
+ house.name, house.transferName, transferTime), {
+ {
+ text = tr("Yes"),
+ callback = yesCallback
+ },
+ {
+ text = tr("No"),
+ callback = noCallback
+ },
+ anchor = AnchorHorizontalCenter
+ }, yesCallback, noCallback)
+
+ Cyclopedia.Toggle(true, false)
+ end
+ end
+
+ UI.cancelHouseTransferArea.name:setText(house.name .. "888")
+ UI.cancelHouseTransferArea.size:setText(house.sqm .. " sqm")
+ UI.cancelHouseTransferArea.beds:setText(house.beds)
+ UI.cancelHouseTransferArea.rent:setText((house.rent))
+ UI.cancelHouseTransferArea.paid:setText(time)
+ UI.cancelHouseTransferArea.owner:setText(house.transferName)
+ UI.cancelHouseTransferArea.transferDate:setText(transferTime)
+ UI.cancelHouseTransferArea.transferPrice:setText(comma_value(house.transferValue))
+end
+
+function Cyclopedia.transferHouse()
+ if UI.moveOutArea:isVisible() then
+ UI.moveOutArea:setVisible(false)
+ end
+
+ local house = Cyclopedia.House.lastSelectedHouse.data
+ local time = os.date("%Y-%m-%d, %H:%M CET", house.paidUntil)
+
+ local function verify(widget, text, type)
+ local timestemp = os.time({
+ year = UI.transferArea.year:getCurrentOption().text,
+ month = UI.transferArea.month:getCurrentOption().text,
+ day = UI.transferArea.day:getCurrentOption().text
+ })
+
+ if timestemp < os.time(os.date("!*t")) then
+ UI.transferArea.move:setEnabled(false)
+ UI.transferArea.error:setVisible(true)
+ else
+ UI.transferArea.move:setEnabled(true)
+ UI.transferArea.error:setVisible(false)
+ end
+ end
+
+ local function verifyName(widget, text, oldText)
+ if text ~= "" then
+ UI.transferArea.errorName:setVisible(false)
+ UI.transferArea.transfer:setEnabled(false)
+ else
+ UI.transferArea.transfer:setEnabled(true)
+ UI.transferArea.errorName:setVisible(true)
+ end
+ end
+
+ UI.ListBase:setVisible(false)
+ UI.transferArea:setVisible(true)
+
+ function UI.transferArea.cancel.onClick()
+ UI.transferArea:setVisible(false)
+ UI.ListBase:setVisible(true)
+ end
+
+ function UI.transferArea.transfer:onClick()
+ local confirmWindow
+ local transfer = UI.transferArea.owner:getText()
+ local value = UI.transferArea.price:getText()
+ local timestemp = os.time({
+ year = UI.transferArea.year:getCurrentOption().text,
+ month = UI.transferArea.month:getCurrentOption().text,
+ day = UI.transferArea.day:getCurrentOption().text
+ })
+
+ local function yesCallback()
+ if confirmWindow then
+ confirmWindow:destroy()
+ confirmWindow = nil
+ Cyclopedia.Toggle(true, false, 5)
+ end
+
+ g_game.requestTransferHouse(house.id, transfer, tonumber(value))
+
+ Cyclopedia.House.ignore = true
+ --[[
+ if Cyclopedia.House.lastTown then
+ g_game.requestShowHouses(Cyclopedia.House.lastTown)
+ else
+ g_game.requestShowHouses("")
+ end
+ ]]--
+
+ UI.TopBase.StatesOption:setOption("All States", true)
+ UI.TopBase.SortOption:setOption("Sort by name", true)
+ end
+
+ local function noCallback()
+ if confirmWindow then
+ confirmWindow:destroy()
+ confirmWindow = nil
+ Cyclopedia.Toggle(true, false, 5)
+ end
+ end
+
+ if not confirmWindow then
+ confirmWindow = displayGeneralBox(tr("Confirm House Action"), tr(
+ "Do you really want to transfer your house '%s', to %s?\nThe transfer is scheduled for %s.\nYou have set the transfer price to %s.\n\nThe transfer will only take place if %s accepts it!.\n\nPlease take all your personal belongings out of the house before the daily server save on the day you move\nout. Everything that remains in the house becomes the property of the new owner after the transfer. The only\nexception are items which have been purchased in the Store. They will be wrapped back up and sent to your\ninbox.",
+ house.name, transfer, os.date("%Y-%m-%d, %H:%M CET", timestemp), comma_value(value), transfer), {
+ {
+ text = tr("Yes"),
+ callback = yesCallback
+ },
+ {
+ text = tr("No"),
+ callback = noCallback
+ },
+ anchor = AnchorHorizontalCenter
+ }, yesCallback, noCallback)
+
+ Cyclopedia.Toggle(true, false)
+ end
+ end
+
+ UI.transferArea.name:setText(house.name .. "44444")
+ UI.transferArea.size:setText(house.sqm .. " sqm")
+ UI.transferArea.beds:setText(house.beds)
+ UI.transferArea.rent:setText((house.rent))
+ UI.transferArea.paid:setText(time)
+ UI.transferArea.year:clearOptions()
+ UI.transferArea.year.onOptionChange = verify
+
+ local yearNumber = tonumber(os.date("%Y"))
+
+ UI.transferArea.year:addOption(yearNumber, 1, true)
+ UI.transferArea.year:addOption(yearNumber + 1, 2, true)
+ UI.transferArea.month:clearOptions()
+ UI.transferArea.month.onOptionChange = verify
+
+ for i = 1, 12 do
+ UI.transferArea.month:addOption(i, i, true)
+ end
+
+ UI.transferArea.day:clearOptions()
+ UI.transferArea.day.onOptionChange = verify
+
+ local days = tonumber(os.date("%d", os.time({
+ day = 0,
+ year = yearNumber,
+ month = os.date("%m") + 1
+ })))
+
+ for i = 1, days do
+ UI.transferArea.day:addOption(i, i, true)
+ end
+
+ UI.transferArea.month:setOption(tonumber(os.date("%m")), true)
+ UI.transferArea.day:setOption(tonumber(os.date("%d") + 1), true)
+ UI.transferArea.owner.onTextChange = verifyName
+ UI.transferArea.owner:setText("")
+ verifyName(UI.transferArea.owner, "", "")
+ UI.transferArea.price:setText(0)
+
+ function UI.transferArea.price:onTextChange(text, oldText)
+ local convertedText = tonumber(text)
+ if text ~= "" and type(convertedText) ~= "number" then
+ self:setText(oldText)
+ end
+
+ if text == "" then
+ UI.transferArea.transfer:setEnabled(false)
+ elseif convertedText then
+ UI.transferArea.transfer:setEnabled(true)
+ end
+ end
+end
+
+function Cyclopedia.moveOutHouse()
+ if UI.transferArea:isVisible() then
+ UI.transferArea:setVisible(false)
+ end
+
+ local house = Cyclopedia.House.lastSelectedHouse.data
+ local time = os.date("%Y-%m-%d, %H:%M CET", house.paidUntil)
+
+ local function verify(widget, text, type)
+ local timestemp = os.time({
+ year = UI.moveOutArea.year:getCurrentOption().text,
+ month = UI.moveOutArea.month:getCurrentOption().text,
+ day = UI.moveOutArea.day:getCurrentOption().text
+ })
+
+ if timestemp < os.time(os.date("!*t")) then
+ UI.moveOutArea.move:setEnabled(false)
+ UI.moveOutArea.error:setVisible(true)
+ else
+ UI.moveOutArea.move:setEnabled(true)
+ UI.moveOutArea.error:setVisible(false)
+ end
+ end
+
+ UI.ListBase:setVisible(false)
+ UI.moveOutArea:setVisible(true)
+
+ function UI.moveOutArea.cancel.onClick()
+ UI.moveOutArea:setVisible(false)
+ UI.ListBase:setVisible(true)
+ end
+
+ function UI.moveOutArea.move:onClick()
+ local confirmWindow
+ local timestemp = os.time({
+ year = UI.moveOutArea.year:getCurrentOption().text,
+ month = UI.moveOutArea.month:getCurrentOption().text,
+ day = UI.moveOutArea.day:getCurrentOption().text
+ })
+
+ local function yesCallback()
+ if confirmWindow then
+ confirmWindow:destroy()
+ confirmWindow = nil
+ Cyclopedia.Toggle(true, false, 5)
+ end
+
+ g_game.requestMoveOutHouse(house.id)
+ end
+
+ local function noCallback()
+ if confirmWindow then
+ confirmWindow:destroy()
+ confirmWindow = nil
+ Cyclopedia.Toggle(true, false, 5)
+ end
+ end
+
+ if not confirmWindow then
+ confirmWindow = displayGeneralBox(tr("Confirm House Action"),
+ tr("Do you really want to move out of the house '%s'?\nClick on 'Yes' to move out on %s.", house.name,
+ os.date("%Y-%m-%d, %H:%M CET", timestemp)), {
+ {
+ text = tr("Yes"),
+ callback = yesCallback
+ },
+ {
+ text = tr("No"),
+ callback = noCallback
+ },
+ anchor = AnchorHorizontalCenter
+ }, yesCallback, noCallback)
+
+ Cyclopedia.Toggle(true, false)
+ end
+ end
+
+ UI.moveOutArea.name:setText(house.name .. "9999")
+ UI.moveOutArea.size:setText(house.sqm .. " sqm")
+ UI.moveOutArea.beds:setText(house.beds)
+ UI.moveOutArea.rent:setText((house.rent))
+ UI.moveOutArea.paid:setText(time)
+ UI.moveOutArea.year:clearOptions()
+ UI.moveOutArea.year.onOptionChange = verify
+
+ local yearNumber = tonumber(os.date("%Y"))
+ UI.moveOutArea.year:addOption(yearNumber, 1, true)
+ UI.moveOutArea.year:addOption(yearNumber + 1, 2, true)
+ UI.moveOutArea.month:clearOptions()
+ UI.moveOutArea.month.onOptionChange = verify
+
+ for i = 1, 12 do
+ UI.moveOutArea.month:addOption(i, i, true)
+ end
+
+ UI.moveOutArea.day:clearOptions()
+ UI.moveOutArea.day.onOptionChange = verify
+
+ local days = tonumber(os.date("%d", os.time({
+ day = 0,
+ year = yearNumber,
+ month = os.date("%m") + 1
+ })))
+
+ for i = 1, days do
+ UI.moveOutArea.day:addOption(i, i, true)
+ end
+
+ UI.moveOutArea.month:setOption(tonumber(os.date("%m")), true)
+ UI.moveOutArea.day:setOption(tonumber(os.date("%d") + 1), true)
+end
+
+function Cyclopedia.bidHouse(widget)
+ if UI.transferArea:isVisible() then
+ UI.transferArea:setVisible(false)
+ end
+
+ if UI.moveOutArea:isVisible() then
+ UI.moveOutArea:setVisible(false)
+ end
+
+ local house = Cyclopedia.House.lastSelectedHouse.data
+ local time = os.date("%Y-%m-%d, %H:%M CET", house.bidEnd)
+
+ UI.ListBase:setVisible(false)
+ UI.bidArea:setVisible(true)
+ UI.bidArea.name:setText(house.name .. "99889")
+ UI.bidArea.size:setText(house.sqm .. " sqm")
+ UI.bidArea.beds:setText(house.beds)
+ UI.bidArea.rent:setText((house.rent))
+
+ local labels = {{
+ id = "hightestBidder",
+ name = "Highest Bidder: ",
+ value = house.bidName
+ }, {
+ id = "endTime",
+ name = "End Time: ",
+ value = time
+ }, {
+ id = "highestBid",
+ name = "Highest Bid: ",
+ value = house.hightestBid
+ }}
+
+ for _, value in ipairs(labels) do
+ local child = UI.bidArea:getChildById(value.id)
+ if child then
+ child:destroy()
+ UI.bidArea:getChildById(value.id .. "_value"):destroy()
+
+ if UI.bidArea:getChildById("highestBid_gold") then
+ UI.bidArea:getChildById("highestBid_gold"):destroy()
+ end
+ end
+ end
+
+ if UI.bidArea:getChildById("yourLimit") then
+ UI.bidArea:getChildById("yourLimit"):destroy()
+ UI.bidArea:getChildById("yourLimit_value"):destroy()
+ UI.bidArea:getChildById("yourLimit_gold"):destroy()
+ end
+
+ if house.hasBid then
+ for index, data in ipairs(labels) do
+ local label = g_ui.createWidget("Label", UI.bidArea)
+ label:setId(data.id)
+ label:setText(data.name .. "44242")
+ label:setColor("#909090")
+ label:setWidth(90)
+ label:setHeight(15)
+ label:setTextAlign(AlignRight)
+ label:setMarginTop(2)
+
+ if index == 1 then
+ label:addAnchor(AnchorTop, "prev", AnchorBottom)
+ label:addAnchor(AnchorLeft, "parent", AnchorLeft)
+ else
+ label:addAnchor(AnchorTop, labels[index - 1].id, AnchorBottom)
+ label:addAnchor(AnchorLeft, "parent", AnchorLeft)
+ end
+
+ label:setMarginLeft(4)
+
+ local value = g_ui.createWidget("Label", UI.bidArea)
+ value:setId(data.id .. "_value")
+ value:setText(data.value)
+ value:setColor("#C0C0C0")
+ value:addAnchor(AnchorTop, "prev", AnchorTop)
+ value:addAnchor(AnchorLeft, "prev", AnchorRight)
+ value:setMarginLeft(5)
+
+ if data.id == "highestBid" then
+ value:setWidth(90)
+ value:setHeight(15)
+ value:setMarginLeft(7)
+ value:setTextAlign(AlignRight)
+
+ local gold = g_ui.createWidget("UIWidget", UI.bidArea)
+ gold:setId("highestBid_gold")
+ gold:setImageSource("/game_cyclopedia/images/icon_gold")
+ gold:addAnchor(AnchorTop, "prev", AnchorTop)
+ gold:addAnchor(AnchorLeft, "prev", AnchorRight)
+ gold:setMarginTop(2)
+ gold:setMarginLeft(9)
+ end
+ end
+
+ if house.bidHolderLimit then
+ local label = g_ui.createWidget("Label", UI.bidArea)
+ label:setId("yourLimit")
+ label:setText("Your Limit: ")
+ label:setColor("#909090")
+ label:setWidth(90)
+ label:setHeight(15)
+ label:setTextAlign(AlignRight)
+ label:setMarginTop(2)
+ label:addAnchor(AnchorTop, "highestBid", AnchorBottom)
+ label:addAnchor(AnchorLeft, "parent", AnchorLeft)
+
+ local value = g_ui.createWidget("Label", UI.bidArea)
+ value:setWidth(90)
+ value:setHeight(15)
+ value:setId("yourLimit_value")
+ value:setText(comma_value(house.bidHolderLimit))
+ value:setColor("#C0C0C0")
+ value:addAnchor(AnchorTop, "prev", AnchorTop)
+ value:addAnchor(AnchorLeft, "prev", AnchorRight)
+ value:setMarginLeft(13)
+ value:setTextAlign(AlignRight)
+
+ local gold = g_ui.createWidget("UIWidget", UI.bidArea)
+ gold:setId("yourLimit_gold")
+ gold:setImageSource("/game_cyclopedia/images/icon_gold")
+ gold:addAnchor(AnchorTop, "prev", AnchorTop)
+ gold:addAnchor(AnchorLeft, "prev", AnchorRight)
+ gold:setMarginTop(2)
+ gold:setMarginLeft(7)
+ end
+ else
+ if UI.bidArea:getChildById("soFar") then
+ UI.bidArea:getChildById("soFar"):destroy()
+ end
+
+ local label = g_ui.createWidget("Label", UI.bidArea)
+ label:setId("soFar")
+ label:setText("There is not bid so far.")
+ label:setColor("#C0C0C0")
+ label:addAnchor(AnchorTop, "prev", AnchorBottom)
+ label:addAnchor(AnchorLeft, "parent", AnchorLeft)
+ label:setMarginTop(2)
+ end
+
+ if UI.bidArea:getChildById("bidArea") then
+ UI.bidArea:getChildById("bidArea"):destroy()
+ end
+
+ local bidArea = g_ui.createWidget("HouseBidArea", UI.bidArea)
+ bidArea:setId("bidArea")
+ bidArea:addAnchor(AnchorTop, "prev", AnchorBottom)
+ bidArea:addAnchor(AnchorLeft, "parent", AnchorLeft)
+ bidArea:addAnchor(AnchorRight, "parent", AnchorRight)
+ bidArea:setMarginTop(5)
+
+ if house.bidHolderLimit then
+ bidArea.textEdit:setText(house.bidHolderLimit)
+ else
+ bidArea.textEdit:setText(0)
+ end
+
+ function bidArea.textEdit:onTextChange(text, oldText)
+ local convertedText = tonumber(text)
+ if text ~= "" and type(convertedText) ~= "number" then
+ self:setText(oldText)
+ end
+
+ if text == "" then
+ UI.bidArea.bid:setEnabled(false)
+ elseif convertedText then
+ UI.bidArea.bid:setEnabled(true)
+ end
+ end
+
+ if house.hasBid then
+ bidArea.information:setText(string.format(
+ "When the auction ends at %s the\nwinning bid plus the rent for the first month ( %s) will\nbe debited to your bank account.",
+ time, (house.rent)))
+ else
+ bidArea.information:setText("When the auction ends, the winning bid plus the rent for\nthe first month( " ..
+ (house.rent) .. ") will de debited yo your bank account.")
+ end
+
+ function UI.bidArea.cancel.onClick()
+ UI.bidArea:setVisible(false)
+ UI.ListBase:setVisible(true)
+ end
+
+ function UI.bidArea.bid:onClick()
+ local value = tonumber(bidArea.textEdit:getText())
+ if not value or value <= 0 then
+ return
+ end
+
+ local confirmWindow
+ local function yesCallback()
+ if confirmWindow then
+ confirmWindow:destroy()
+ confirmWindow = nil
+ Cyclopedia.Toggle(true, false, 5)
+ end
+
+ g_game.requestBidHouse(house.id, value)
+ end
+
+ local function noCallback()
+ if confirmWindow then
+ confirmWindow:destroy()
+ confirmWindow = nil
+ Cyclopedia.Toggle(true, false, 5)
+ end
+ end
+
+ if not confirmWindow then
+ confirmWindow = displayGeneralBox(tr("Confirm House Action"), tr(
+ "Do you really want to bid on the house '%s'?\nYour have set your bid limit to %s.\nWhen the auction ends, the winning bid plus the rent of %sfor the first month will be debited from your\nbank account.",
+ house.name, comma_value(value), (house.rent)), {
+ {
+ text = tr("Yes"),
+ callback = yesCallback
+ },
+ {
+ text = tr("No"),
+ callback = noCallback
+ },
+ anchor = AnchorHorizontalCenter
+ }, yesCallback, noCallback)
+
+ Cyclopedia.Toggle(true, false)
+ end
+ end
+end
+
+function Cyclopedia.houseRefresh()
+ if Cyclopedia.House.lastTown then
+ -- g_game.requestShowHouses(Cyclopedia.House.lastTown)
+
+ if Cyclopedia.House.lastChangeState then
+ if Cyclopedia.House.refreshEvent then
+ return
+ end
+
+ Cyclopedia.House.refreshEvent = scheduleEvent(function()
+ Cyclopedia.houseChangeState(Cyclopedia.House.lastChangeState)
+ Cyclopedia.House.refreshEvent = nil
+ end, 100)
+ end
+ end
+end
+
+function Cyclopedia.houseSort(widget, text, type)
+ if Cyclopedia.House.Data then
+ if type == 1 then
+ table.sort(Cyclopedia.House.Data, function(a, b)
+ return a.name < b.name
+ end)
+ elseif type == 2 then
+ table.sort(Cyclopedia.House.Data, function(a, b)
+ return a.sqm < b.sqm
+ end)
+ elseif type == 3 then
+ -- block empty
+ elseif type == 4 then
+ table.sort(Cyclopedia.House.Data, function(a, b)
+ if a.hasBid and not b.hasBid then
+ return true
+ elseif not a.hasBid and b.hasBid then
+ return false
+ else
+ return false
+ end
+ end)
+ elseif type == 5 then
+ table.sort(Cyclopedia.House.Data, function(a, b)
+ if a.hasBid and not b.hasBid then
+ return true
+ elseif not a.hasBid and b.hasBid then
+ return false
+ else
+ return false
+ end
+ end)
+ end
+
+ Cyclopedia.reloadHouseList()
+ end
+end
+
+function Cyclopedia.houseFilter(widget)
+ local id = widget:getId()
+ local brother
+
+ if id == "HousesCheck" then
+ brother = UI.TopBase.GuildhallsCheck
+ else
+ brother = UI.TopBase.HousesCheck
+ end
+
+ brother:setChecked(false)
+ widget:setChecked(true)
+
+ if not table.empty(Cyclopedia.House.Data) then
+ local onlyGuildHall = UI.TopBase.GuildhallsCheck:isChecked()
+ for _, data in ipairs(Cyclopedia.House.Data) do
+ if onlyGuildHall then
+ data.visible = data.gh
+ else
+ data.visible = not data.gh
+ end
+ end
+
+ Cyclopedia.reloadHouseList()
+ end
+end
+
+function Cyclopedia.reloadHouseList()
+ if not table.empty(Cyclopedia.House.Data) then
+ UI.LateralBase.MapViewbase.noHouse:setVisible(false)
+ UI.LateralBase.MapViewbase.houseImage:setVisible(false)
+ UI.LateralBase.MapViewbase.reload:setVisible(true)
+ UI.LateralBase.AuctionLabel:setVisible(true)
+ UI.LateralBase.AuctionText:setVisible(true)
+ UI.ListBase.AuctionList:destroyChildren()
+
+ for _, data in ipairs(Cyclopedia.House.Data) do
+ if data.visible then
+ local widget = g_ui.createWidget("House", UI.ListBase.AuctionList)
+ widget.data = data
+ widget:setId(data.id)
+ widget:setText(data.name)
+ widget.size:setColoredText("{Size: , #909090}" .. data.sqm .. " sqm")
+ widget.beds:setColoredText("{Max. Beds: ,#909090} " .. data.beds)
+ widget.rent:setColoredText(data.rent)
+
+ if data.description ~= "" then
+ local icon = g_ui.createWidget("HouseIcon", widget.icons)
+ -- icon:setImageSource("/game_cyclopedia/images/house-description")
+ icon:setTooltip(data.description)
+ end
+
+ if data.state == 0 then
+ if data.hasBid then
+ local function format(timestamp)
+ local difference = timestamp - os.time()
+ local hour = math.floor(difference / 3600)
+ local minutes = math.floor(difference % 3600 / 60)
+ return string.format("%02dh %02dmin", hour, minutes)
+ end
+
+ widget.status:setColoredText("{Status: , #909090}{auctioned, #00F000} (Bid: " ..
+ data.hightestBid .. " Ends in: " .. format(data.bidEnd) .. ")")
+ else
+ widget.status:setColoredText("{Status: , #909090}{auctioned, #00F000} (no bid yet)")
+ end
+ elseif data.state == 2 then
+ widget.status:setColoredText("{Status: , #909090}rented by " .. data.owner)
+ end
+
+ widget.onClick = Cyclopedia.selectHouse
+
+ if data.isYourOwner then
+ local icon = g_ui.createWidget("HouseIcon", widget.icons)
+ -- icon:setImageSource("/game_cyclopedia/images/house-owner-icon")
+ end
+
+ if widget.data.isTransferOwner then
+ local icon = g_ui.createWidget("HouseIcon", widget.icons)
+ icon:setImageSource("/game_cyclopedia/images/pending-transfer-house")
+ end
+
+ if data.isYourOwner and data.inTransfer then
+ local icon = g_ui.createWidget("HouseIcon", widget.icons)
+ icon:setImageSource("/game_cyclopedia/images/transfer-house")
+ end
+
+ if data.shop then
+ local icon = g_ui.createWidget("HouseIcon", widget.icons)
+ -- icon:setImageSource("/game_cyclopedia/images/house-shop")
+ icon:setTooltip("This house is a shop.")
+ end
+ end
+ end
+
+ if Cyclopedia.House.lastSelectedHouse then
+ local last = UI.ListBase.AuctionList:getChildById(Cyclopedia.House.lastSelectedHouse:getId())
+ last = last or UI.ListBase.AuctionList:getChildByIndex(1)
+ Cyclopedia.selectHouse(last)
+ else
+ Cyclopedia.selectHouse(UI.ListBase.AuctionList:getChildByIndex(1))
+ end
+ else
+ UI.LateralBase.MapViewbase.noHouse:setVisible(true)
+ UI.LateralBase.MapViewbase.reload:setVisible(false)
+ UI.LateralBase.MapViewbase.houseImage:setVisible(false)
+ UI.LateralBase.AuctionLabel:setVisible(false)
+ UI.LateralBase.AuctionText:setVisible(false)
+ UI.LateralBase.icons:destroyChildren()
+ UI.LateralBase.yourLimitBidGold:setVisible(false)
+ UI.LateralBase.yourLimitBid:setVisible(false)
+ UI.LateralBase.yourLimitLabel:setVisible(false)
+ UI.LateralBase.highestBid:setVisible(false)
+ UI.LateralBase.highestBidGold:setVisible(false)
+ UI.LateralBase.subAuctionLabel:setVisible(false)
+ UI.LateralBase.subAuctionText:setVisible(false)
+ UI.LateralBase.transferLabel:setVisible(false)
+ UI.LateralBase.transferValue:setVisible(false)
+ UI.LateralBase.transferGold:setVisible(false)
+ resetButtons()
+ end
+end
+
+function Cyclopedia.loadHouseList(data, other)
+ if Cyclopedia.House.ignore then
+ Cyclopedia.House.ignore = false
+ return
+ end
+
+ local houses = {}
+
+ if not table.empty(data) then
+ for i = 0, #data do
+ local value = data[i]
+ local house = HOUSE[value.houseId]
+ if house then
+ local isGuildHall = house.GH > 0 and true or false
+ local data_t = {
+ id = value.houseId,
+ name = house.name,
+ description = house.description,
+ rent = house.rent,
+ beds = house.beds,
+ sqm = house.sqm,
+ gh = isGuildHall,
+ shop = house.shop > 0 and true or false,
+ visible = not isGuildHall,
+ state = value.state,
+ owner = other[i].owner and other[i].owner or "?",
+ isYourBid = data[i].bidHolderLimit and data[i].bidHolderLimit > 0 and true or false,
+ hasBid = data[i].bidEnd and data[i].bidEnd > 0 and true or false,
+ bidEnd = data[i].bidEnd and data[i].bidEnd or nil,
+ hightestBid = data[i].hightestBid and data[i].hightestBid or nil,
+ bidName = other[i].bidName and other[i].bidName or nil,
+ bidHolderLimit = data[i].bidHolderLimit and data[i].bidHolderLimit or nil,
+ canBid = data[i].selfCanBid,
+ rented = data[i].state == 2 and true or false,
+ paidUntil = data[i].paidUntil and data[i].paidUntil or nil,
+ isYourOwner = other[i].owner and other[i].owner:lower() == g_game.getLocalPlayer():getName():lower() and
+ true or false,
+ inTransfer = data[i].state == 3 and true or false,
+ transferName = other[i].transferPlayer and other[i].transferPlayer or nil,
+ transferTime = data[i].time and data[i].time or 0,
+ transferValue = data[i].transferValue and data[i].transferValue or 0,
+ isTransferOwner = data[i].hasTransferOwner and data[i].hasTransferOwner > 0 and true or false,
+ canAcceptTransfer = data[i].canAcceptTransfer and data[i].canAcceptTransfer or 0
+ }
+
+ table.insert(houses, data_t)
+ end
+ end
+ else
+ UI.ListBase.AuctionList:destroyChildren()
+ end
+
+ table.sort(houses, function(a, b)
+ return a.name < b.name
+ end)
+
+ Cyclopedia.House.Data = houses
+ Cyclopedia.reloadHouseList()
+end
+
+function Cyclopedia.selectTown(widget, text, type)
+ local name = text
+ if type ~= 0 then
+ -- g_game.requestShowHouses(name)
+ Cyclopedia.House.lastTown = name
+ else
+ -- g_game.requestShowHouses("")
+ Cyclopedia.House.lastTown = ""
+ end
+end
+
+function Cyclopedia.selectHouse(widget)
+ if not widget then
+ return
+ end
+
+ local parent = widget:getParent()
+ for i = 1, parent:getChildCount() do
+ local child = parent:getChildByIndex(i)
+ child:setChecked(false)
+ end
+
+ UI.LateralBase.icons:destroyChildren()
+
+ if widget.data.isYourOwner then
+ local icon = g_ui.createWidget("HouseIcon", UI.LateralBase.icons)
+ -- icon:setImageSource("/game_cyclopedia/images/house-owner-icon")
+ end
+
+ if widget.data.isYourOwner and widget.data.inTransfer then
+ local icon = g_ui.createWidget("HouseIcon", UI.LateralBase.icons)
+ icon:setImageSource("/game_cyclopedia/images/transfer-house")
+ end
+
+ if widget.data.isTransferOwner then
+ local icon = g_ui.createWidget("HouseIcon", UI.LateralBase.icons)
+ icon:setImageSource("/game_cyclopedia/images/pending-transfer-house")
+ end
+
+ if widget.data.shop then
+ local icon = g_ui.createWidget("HouseIcon", UI.LateralBase.icons)
+ -- icon:setImageSource("/game_cyclopedia/images/house-shop")
+ icon:setTooltip("This house is a shop.")
+ end
+
+ if widget.data.description ~= "" then
+ local icon = g_ui.createWidget("HouseIcon", UI.LateralBase.icons)
+ -- icon:setImageSource("/game_cyclopedia/images/house-description")
+ icon:setTooltip(widget.data.description)
+ end
+
+ resetButtons()
+ resetSelectedInfo()
+
+ if widget.data.hasBid then
+ UI.LateralBase.AuctionLabel:setText("Auction")
+
+ local formattedDate = os.date("%b %d, %H:%M", widget.data.bidEnd)
+ local date = string.format("%s %s", formattedDate, "CET")
+
+ UI.LateralBase.AuctionText:setColoredText("{Hightest Bidder: , #909090}" .. widget.data.bidName ..
+ "\n{ End Time: , #909090}" .. date ..
+ "\n{ Highest Bid: , #909090}")
+ UI.LateralBase.highestBid:setVisible(true)
+ UI.LateralBase.highestBidGold:setVisible(true)
+ UI.LateralBase.highestBid:setText(comma_value(widget.data.hightestBid))
+
+ if widget.data.isYourBid then
+ UI.LateralBase.yourLimitLabel:setVisible(true)
+ UI.LateralBase.yourLimitBid:setVisible(true)
+ UI.LateralBase.yourLimitBid:setText(comma_value(widget.data.bidHolderLimit))
+ UI.LateralBase.yourLimitBidGold:setVisible(true)
+ end
+ elseif widget.data.rented or widget.data.inTransfer then
+ local formattedDate = os.date("%b %d, %H:%M", widget.data.paidUntil)
+ local date = string.format("%s %s", formattedDate, "CET")
+
+ UI.LateralBase.AuctionLabel:setText("Rental Details")
+ UI.LateralBase.AuctionText:setColoredText("{ Tenant: , #909090}" .. widget.data.owner ..
+ "\n{ Paid Until: , #909090}" .. date)
+
+ if widget.data.inTransfer then
+ formattedDate = os.date("%b %d, %H:%M", widget.data.transferTime)
+ date = string.format("%s %s", formattedDate, "CET")
+
+ UI.LateralBase.subAuctionLabel:setVisible(true)
+ UI.LateralBase.subAuctionText:setVisible(true)
+ UI.LateralBase.subAuctionText:setColoredText("{ New Owner: , #909090}" .. widget.data.transferName ..
+ "\n{ Date: , #909090}" .. date)
+ UI.LateralBase.transferLabel:setVisible(true)
+ UI.LateralBase.transferValue:setVisible(true)
+ UI.LateralBase.transferGold:setVisible(true)
+ UI.LateralBase.transferValue:setText(comma_value(widget.data.transferValue))
+ end
+ else
+ UI.LateralBase.AuctionLabel:setText("Auction")
+ UI.LateralBase.AuctionText:setText("There is no bid so far.\nBe the first to bid on this house.")
+ end
+
+ if widget.data.rented then
+ if widget.data.isYourOwner then
+ local button = g_ui.createWidget("Button", UI.LateralBase)
+ button:setId("transferButton")
+ button:setText("Transfer")
+ button:setColor("#C0C0C0")
+ -- button:setFont("verdana-bold-8px-antialiased")
+ button:setWidth(64)
+ button:setHeight(20)
+ button:addAnchor(AnchorBottom, "parent", AnchorBottom)
+ button:addAnchor(AnchorRight, "parent", AnchorRight)
+ button:setMarginRight(7)
+ button:setMarginBottom(7)
+ button.onClick = Cyclopedia.transferHouse
+ button = g_ui.createWidget("Button", UI.LateralBase)
+ button:setId("moveOutButton")
+ button:setText("Move Out")
+ button:setColor("#C0C0C0")
+ -- button:setFont("verdana-bold-8px-antialiased")
+ button:setWidth(64)
+ button:setHeight(20)
+ button:addAnchor(AnchorTop, "prev", AnchorTop)
+ button:addAnchor(AnchorRight, "prev", AnchorLeft)
+ button:setMarginRight(5)
+ button.onClick = Cyclopedia.moveOutHouse
+ end
+ elseif widget.data.inTransfer and not widget.data.isTransferOwner then
+ local button = g_ui.createWidget("Button", UI.LateralBase)
+ button:setId("cancelTransfer")
+ button:setText("Cancel Transfer")
+ button:setColor("#C0C0C0")
+ -- button:setFont("verdana-bold-8px-antialiased")
+ button:setWidth(86)
+ button:setHeight(20)
+ button:addAnchor(AnchorBottom, "parent", AnchorBottom)
+ button:addAnchor(AnchorRight, "parent", AnchorRight)
+ button:setMarginRight(7)
+ button:setMarginBottom(7)
+ button.onClick = Cyclopedia.cancelTransfer
+ elseif widget.data.isTransferOwner then
+ local button = g_ui.createWidget("Button", UI.LateralBase)
+ button:setId("rejectTransfer")
+ button:setText("Reject Transfer")
+ button:setColor("#C0C0C0")
+ -- button:setFont("verdana-bold-8px-antialiased")
+ button:setWidth(86)
+ button:setHeight(20)
+ button:addAnchor(AnchorBottom, "parent", AnchorBottom)
+ button:addAnchor(AnchorRight, "parent", AnchorRight)
+ button:setMarginRight(7)
+ button:setMarginBottom(7)
+ button:setTextOffset(topoint(0 .. " " .. 0))
+ button.onClick = Cyclopedia.rejectTransfer
+
+ local transferButton = g_ui.createWidget("Button", UI.LateralBase)
+ transferButton:setId("acceptTransfer")
+ transferButton:setText("Accept Transfer")
+ transferButton:setColor("#C0C0C0")
+ -- transferButton:setFont("verdana-bold-8px-antialiased")
+ transferButton:setWidth(86)
+ transferButton:setHeight(20)
+ transferButton:addAnchor(AnchorTop, "prev", AnchorTop)
+ transferButton:addAnchor(AnchorRight, "prev", AnchorLeft)
+ transferButton:setMarginRight(5)
+ transferButton:setTextOffset(topoint(0 .. " " .. 0))
+ transferButton.onClick = Cyclopedia.acceptTransfer
+
+ if widget.data.canAcceptTransfer ~= 0 then
+ transferButton:setEnabled(false)
+ else
+ transferButton:setEnabled(true)
+ end
+ else
+ local button = g_ui.createWidget("Button", UI.LateralBase)
+ button:setId("bidButton")
+ button:setText("Bid")
+ button:setColor("#C0C0C0")
+ -- button:setFont("verdana-bold-8px-antialiased")
+ button:setWidth(64)
+ button:setHeight(20)
+ button:addAnchor(AnchorBottom, "parent", AnchorBottom)
+ button:addAnchor(AnchorRight, "parent", AnchorRight)
+ button:setMarginRight(7)
+ button:setMarginBottom(7)
+ button.onClick = Cyclopedia.bidHouse
+
+ if widget.data.canBid == 0 then
+ button:setEnabled(true)
+ button:setTooltip("")
+ elseif widget.data.canBid == 11 then
+ button:setTooltip(
+ "A character of your account already holds the highest bid for \nanother house. You may olny bid for one house at the same time.")
+ button:setTooltipAlign(AlignTopLeft)
+ button:setEnabled(false)
+ else
+ button:setEnabled(false)
+ button:setTooltip("")
+ end
+ end
+
+ widget:setChecked(true)
+ UI.LateralBase.MapViewbase.noHouse:setVisible(false)
+ UI.LateralBase.MapViewbase.reload:setVisible(true)
+ UI.LateralBase.MapViewbase.houseImage:setVisible(false)
+
+ local imagePath = string.format("/game_cyclopedia/images/houses/%s.png", widget.data.id)
+ if g_resources.fileExists(imagePath) then
+ UI.LateralBase.MapViewbase.noHouse:setVisible(false)
+ UI.LateralBase.MapViewbase.reload:setVisible(false)
+ UI.LateralBase.MapViewbase.houseImage:setVisible(true)
+ UI.LateralBase.MapViewbase.houseImage:setImageSource(imagePath)
+ end
+
+ --[[
+ UI.LateralBase.MapViewbase.houseImage:setVisible(true)
+ HTTP.downloadImage("https://next-stage.pl/images/houses/A%20Horse%20farm.jpeg", function(path, err)
+ if err then g_logger.warning("HTTP error: " .. err .. " - ") return end
+ UI.LateralBase.MapViewbase.houseImage:setImageSource(path)
+ end)
+ ]]--
+
+ Cyclopedia.House.lastSelectedHouse = widget
+end
diff --git a/modules/game_cyclopedia/tab/house/house.otui b/modules/game_cyclopedia/tab/house/house.otui
new file mode 100644
index 0000000000..15034a48d5
--- /dev/null
+++ b/modules/game_cyclopedia/tab/house/house.otui
@@ -0,0 +1,1422 @@
+UIWidget
+ id: Cat5
+ anchors.fill: parent
+ visible: false
+ UIWidget
+ id: TopBase
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.right: parent.right
+ image-source: /images/game/actionbar/2pixel-up-frame-borderimage
+ image-border: 5
+ height: 52
+ margin-top: 5
+ ComboBox
+ id: StatesOption
+ size: 214 20
+ color: #C0C0C0
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.top: parent.top
+ margin-top: 7
+ text-align: center
+ ComboBox
+ id: CityOption
+ size: 215 20
+ color: #C0C0C0
+ anchors.right: StatesOption.left
+ anchors.top: StatesOption.top
+ margin-right: 5
+ text-align: center
+ ComboBox
+ id: SortOption
+ size: 215 20
+ color: #C0C0C0
+ anchors.left: StatesOption.right
+ anchors.top: StatesOption.top
+ margin-left: 5
+ text-align: center
+ CheckBox
+ id: GuildhallsCheck
+ anchors.bottom: parent.bottom
+ anchors.left: parent.horizontalCenter
+ margin-bottom: 5
+ margin-left: 20
+ image-source: /images/ui/outfits/checkbox_round
+ text-offset: 15 0
+ !text: tr('Guildhalls')
+ color: #C0C0C0
+ text-auto-resize: true
+ @onClick: modules.game_cyclopedia.Cyclopedia.houseFilter(self)
+ CheckBox
+ id: HousesCheck
+ anchors.bottom: GuildhallsCheck.bottom
+ anchors.right: GuildhallsCheck.left
+ margin-right: 20
+ image-source: /images/ui/outfits/checkbox_round
+ text-offset: 15 0
+ !text: tr('Houses and Flats')
+ color: #C0C0C0
+ text-auto-resize: true
+ @onClick: modules.game_cyclopedia.Cyclopedia.houseFilter(self)
+ UIWidget
+ id: LateralBase
+ size: 250 358
+ anchors.top: TopBase.bottom
+ anchors.left: parent.left
+ image-source: /images/game/actionbar/2pixel-up-frame-borderimage
+ image-border: 5
+ margin-top: 8
+ margin-bottom: 8
+ UIWidget
+ //MapRose
+ id: MapBorder
+ anchors.top: parent.top
+ anchors.right: parent.right
+ //image-source: /game_cyclopedia/images/map_borders/automap-rose-idle
+ margin-right: 10
+ margin-top: 50
+ visible: false
+ UIWidget
+ id: LayerIndicator
+ anchors.right: MapBorder.right
+ anchors.top: MapBorder.bottom
+ margin-top: 5
+ margin-right: 5
+ size: 14 67
+ //image-source: /game_cyclopedia/images/map_layers
+ image-rect: 0 0 14 67
+ image-clip: 112 0 14 67
+ visible: false
+ VerticalSeparator
+ id: LayerLine
+ anchors.top: LayerIndicator.top
+ anchors.bottom: LayerIndicator.bottom
+ anchors.left: LayerIndicator.right
+ margin-left: 5
+ visible: false
+ VerticalScrollBar
+ id: LayerScrollbar
+ anchors.top: LayerIndicator.top
+ anchors.bottom: LayerIndicator.bottom
+ anchors.left: LayerIndicator.right
+ margin-left: -1
+ margin-top: -16
+ margin-bottom: -16
+ step: 1
+ minimum: 1
+ maximum: 300
+ image-source:
+ visible: false
+ UIWidget
+ id: MapViewbase
+ size: 188 212
+ anchors.top: parent.top
+ anchors.left: parent.left
+ margin-top: 8
+ margin-left: 8
+ margin-right: 5
+ image-source: /images/ui/panel_flat
+ image-border: 10
+ UIWidget
+ id: reload
+ anchors.centerIn: parent
+ image-source: /game_cyclopedia/images/icon-refresh
+ opacity: 1.0
+ visible: false
+ $pressed:
+ opacity: 0.5
+ UIWidget
+ id: noHouse
+ anchors.fill: parent
+ margin: 1
+ background-color: black
+ Label
+ !text: tr('No house selected')
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.centerIn: parent
+ UIWidget
+ id: houseImage
+ anchors.fill: parent
+ margin: 1
+ visible: false
+ UIWidget
+ id: ZoomOutButton
+ anchors.left: MapBorder.left
+ anchors.top: MapBorder.bottom
+ margin-left: 3
+ margin-top: 11
+ //image-source: /game_cyclopedia/images/button_zoommin
+ visible: false
+ $pressed:
+ //image-source: /game_cyclopedia/images/button_zoommin_pressed
+ UIWidget
+ id: ZoomInButton
+ anchors.left: ZoomOutButton.left
+ anchors.top: ZoomOutButton.bottom
+ margin-top: 2
+ //image-source: /game_cyclopedia/images/button_zoomout
+ visible: false
+ $pressed:
+ //image-source: /game_cyclopedia/images/button_zoomout_pressed
+ UIWidget
+ id: MapButton
+ anchors.left: ZoomInButton.left
+ anchors.top: ZoomInButton.bottom
+ margin-top: 2
+ //image-source: /game_cyclopedia/images/button_cyclopediamap
+ visible: false
+ $pressed:
+ //image-source: /game_cyclopedia/images/button_cyclopediamap_pressed
+ Label
+ id: AuctionLabel
+ anchors.left: MapViewbase.left
+ anchors.top: MapViewbase.bottom
+ margin-top: 5
+ !text: tr('Auction')
+ color: #F7F7F7
+ text-auto-resize: true
+ Label
+ id: AuctionText
+ color: #C0C0C0
+ anchors.left: MapViewbase.left
+ anchors.top: AuctionLabel.bottom
+ margin-top: 3
+ !text: tr('There is no bid so far.\nBe the first to bid on this house.')
+ text-auto-resize: true
+ Label
+ id: subAuctionLabel
+ anchors.left: MapViewbase.left
+ anchors.top: AuctionText.bottom
+ margin-top: 5
+ !text: tr('Pending Transfer')
+ color: #F7F7F7
+ text-auto-resize: true
+ visible: false
+ Label
+ id: subAuctionText
+ color: #C0C0C0
+ anchors.left: MapViewbase.left
+ anchors.top: subAuctionLabel.bottom
+ margin-top: 3
+ text-auto-resize: true
+ visible: false
+ Label
+ id: highestBid
+ size: 100 15
+ text-align: right
+ color: #C0C0C0
+ anchors.right: parent.right
+ anchors.bottom: AuctionText.bottom
+ margin-right: 57
+ margin-top: 3
+ visible: false
+ UIWidget
+ id: highestBidGold
+ anchors.left: highestBid.right
+ anchors.verticalCenter: highestBid.verticalCenter
+ margin-left: 5
+ image-source: /game_cyclopedia/images/icon_gold
+ visible: false
+ Label
+ id: yourLimitLabel
+ !text: tr('Your Limit:')
+ color: #909090
+ anchors.left: AuctionText.left
+ anchors.top: AuctionText.bottom
+ margin-left: 15
+ visible: false
+ Label
+ id: yourLimitBid
+ size: 100 15
+ text-align: right
+ color: #C0C0C0
+ anchors.right: highestBid.right
+ anchors.top: highestBid.bottom
+ visible: false
+ UIWidget
+ id: yourLimitBidGold
+ anchors.left: yourLimitBid.right
+ anchors.verticalCenter: yourLimitBid.verticalCenter
+ margin-left: 5
+ image-source: /game_cyclopedia/images/icon_gold
+ visible: false
+ Label
+ id: transferLabel
+ !text: tr('Price:')
+ color: #909090
+ anchors.left: subAuctionText.left
+ anchors.top: subAuctionText.bottom
+ margin-left: 64
+ visible: false
+ Label
+ id: transferValue
+ text-auto-resize: true
+ color: #C0C0C0
+ anchors.left: transferLabel.right
+ anchors.top: transferLabel.top
+ visible: false
+ margin-left: 5
+ UIWidget
+ id: transferGold
+ anchors.left: transferValue.right
+ anchors.verticalCenter: transferValue.verticalCenter
+ margin-left: 5
+ image-source: /game_cyclopedia/images/icon_gold
+ visible: false
+ Panel
+ id: icons
+ height: 12
+ anchors.verticalCenter: AuctionLabel.verticalCenter
+ anchors.left: AuctionLabel.right
+ anchors.right: parent.right
+ margin-left: 5
+ margin-right: 5
+ layout:
+ type: horizontalBox
+ align-right: true
+ flow: true
+ UIWidget
+ id: description
+ //image-source: /game_cyclopedia/images/house-description
+ anchors.top: icons.top
+ anchors.left: icons.left
+ visible: false
+ UIWidget
+ id: bidArea
+ !text: tr('Place Your Bid')
+ text-align: top
+ text-offset: 0 1
+ color: #909090
+ size: 413 358
+ anchors.top: LateralBase.top
+ anchors.left: LateralBase.right
+ //image-source: /images/ui/widget-borderimage
+ image-border: 15
+ margin-left: 5
+ visible: false
+ padding: 15
+ Button
+ id: cancel
+ size: 43 20
+ !text: tr('Cancel')
+ color: #C0C0C0
+ anchors.bottom: parent.bottom
+ anchors.right: parent.right
+ //font: verdana-bold-8px-antialiased
+ text-offset: 0 -1
+ change-cursor-image: false
+ Button
+ id: bid
+ size: 64 20
+ !text: tr('Bid')
+ color: #C0C0C0
+ anchors.top: cancel.top
+ anchors.right: cancel.left
+ margin-right: 7
+ //font: verdana-bold-8px-antialiased
+ text-offset: 0 -1
+ change-cursor-image: false
+ Label
+ !text: tr('House Information')
+ anchors.top: parent.top
+ anchors.left: parent.left
+ margin-top: 10
+ color: #F7F7F7
+ Label
+ !text: tr('Name:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: prev.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ Label
+ id: name
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 8
+ Label
+ !text: tr('Size:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: name.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ Label
+ id: size
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 8
+ Label
+ !text: tr('Max. Beds:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: size.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ Label
+ id: beds
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 8
+ Label
+ !text: tr('Rent:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: beds.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ Label
+ id: rent
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 8
+ UIWidget
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-top: 3
+ image-source: /game_cyclopedia/images/icon_gold
+ Label
+ !text: tr('Auction Information')
+ anchors.top: prev.bottom
+ anchors.left: parent.left
+ margin-top: 5
+ color: #F7F7F7
+ UIWidget
+ id: moveOutArea
+ !text: tr('Select Move Date')
+ text-align: top
+ text-offset: 0 1
+ color: #909090
+ size: 413 358
+ anchors.top: LateralBase.top
+ anchors.left: LateralBase.right
+ image-source: /images/ui/widget-borderimage
+ image-border: 15
+ margin-left: 5
+ visible: false
+ padding: 15
+ Button
+ id: cancel
+ size: 43 20
+ !text: tr('Cancel')
+ color: #C0C0C0
+ anchors.bottom: parent.bottom
+ anchors.right: parent.right
+ //font: verdana-bold-8px-antialiased
+ text-offset: 0 -1
+ change-cursor-image: false
+ Button
+ id: move
+ size: 64 20
+ !text: tr('Move Out')
+ color: #C0C0C0
+ anchors.top: cancel.top
+ anchors.right: cancel.left
+ margin-right: 7
+ //font: verdana-bold-8px-antialiased
+ text-offset: 0 -1
+ change-cursor-image: false
+ Label
+ !text: tr('House Information')
+ anchors.top: parent.top
+ anchors.left: parent.left
+ margin-top: 10
+ color: #F7F7F7
+ Label
+ !text: tr('Name:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: prev.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ Label
+ id: name
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 8
+ Label
+ !text: tr('Size:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: name.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ Label
+ id: size
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 8
+ Label
+ !text: tr('Max. Beds:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: size.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ Label
+ id: beds
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 8
+ Label
+ !text: tr('Rent:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: beds.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ Label
+ id: rent
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 8
+ UIWidget
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-top: 3
+ image-source: /game_cyclopedia/images/icon_gold
+ Label
+ !text: tr('Move Information')
+ anchors.top: prev.bottom
+ anchors.left: parent.left
+ margin-top: 5
+ color: #F7F7F7
+ Label
+ !text: tr('Paid until:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: prev.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ Label
+ id: paid
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 8
+ Label
+ !text: tr('Move Date:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: paid.bottom
+ anchors.left: parent.left
+ margin-top: 8
+ ComboBox
+ id: year
+ size: 70 20
+ color: #C0C0C0
+ anchors.left: prev.right
+ anchors.top: prev.top
+ margin-left: 5
+ text-offset: 15 1
+ margin-top: -3
+ Label
+ !text: tr('-')
+ color: #C0C0C0
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 3
+ margin-top: 2
+ ComboBox
+ id: month
+ size: 51 20
+ color: #C0C0C0
+ text-offset: 20 1
+ anchors.left: prev.right
+ anchors.top: year.top
+ margin-left: 5
+ Label
+ !text: tr('-')
+ color: #C0C0C0
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 3
+ margin-top: 2
+ ComboBox
+ id: day
+ size: 50 20
+ color: #C0C0C0
+ text-offset: 15 1
+ anchors.left: prev.right
+ anchors.top: year.top
+ margin-left: 5
+ UIWidget
+ id: error
+ !tooltip: tr('Select a date in the future!')
+ anchors.left: prev.right
+ anchors.verticalCenter: month.verticalCenter
+ //image-source: /game_cyclopedia/images/icon-info-error
+ margin-left: 5
+ visible: false
+ UIWidget
+ !tooltip: tr('You will move out at the daily server save of the selected day.')
+ anchors.right: parent.right
+ anchors.verticalCenter: month.verticalCenter
+ //image-source: /images/icons/show_gui_help_grey
+ Label
+ !text: tr('All items you have left in the house will be automatically\nsent to your inbox.')
+ text-auto-resize: true
+ anchors.top: prev.bottom
+ anchors.left: parent.left
+ margin-top: 10
+ color: #C0C0C0
+ UIWidget
+ id: transferArea
+ !text: tr('Configure House Transfer')
+ text-align: top
+ text-offset: 0 1
+ color: #909090
+ size: 413 358
+ anchors.top: LateralBase.top
+ anchors.left: LateralBase.right
+ image-source: /images/ui/widget-borderimage
+ image-border: 15
+ margin-left: 5
+ visible: false
+ padding: 15
+ Button
+ id: cancel
+ size: 43 20
+ !text: tr('Cancel')
+ color: #C0C0C0
+ anchors.bottom: parent.bottom
+ anchors.right: parent.right
+ //font: verdana-bold-8px-antialiased
+ text-offset: 0 -1
+ change-cursor-image: false
+ Button
+ id: transfer
+ size: 64 20
+ !text: tr('Transfer')
+ color: #C0C0C0
+ anchors.top: cancel.top
+ anchors.right: cancel.left
+ margin-right: 7
+ //font: verdana-bold-8px-antialiased
+ text-offset: 0 -1
+ change-cursor-image: false
+ Label
+ !text: tr('House Information')
+ anchors.top: parent.top
+ anchors.left: parent.left
+ margin-top: 10
+ color: #F7F7F7
+ Label
+ !text: tr('Name:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: prev.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ Label
+ id: name
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 8
+ Label
+ !text: tr('Size:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: name.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ Label
+ id: size
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 8
+ Label
+ !text: tr('Max. Beds:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: size.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ Label
+ id: beds
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 8
+ Label
+ !text: tr('Rent:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: beds.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ Label
+ id: rent
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 8
+ UIWidget
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-top: 3
+ image-source: /game_cyclopedia/images/icon_gold
+ Label
+ !text: tr('Transfer Information')
+ anchors.top: prev.bottom
+ anchors.left: parent.left
+ margin-top: 5
+ color: #F7F7F7
+ Label
+ !text: tr('Paid until:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: prev.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ Label
+ id: paid
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 8
+ Label
+ !text: tr('Transfer Date:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: paid.bottom
+ anchors.left: parent.left
+ margin-top: 8
+ ComboBox
+ id: year
+ size: 70 20
+ color: #C0C0C0
+ anchors.left: prev.right
+ anchors.top: prev.top
+ margin-left: 5
+ text-offset: 15 1
+ margin-top: -3
+ Label
+ !text: tr('-')
+ color: #C0C0C0
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 3
+ margin-top: 2
+ ComboBox
+ id: month
+ size: 51 20
+ color: #C0C0C0
+ text-offset: 20 1
+ anchors.left: prev.right
+ anchors.top: year.top
+ margin-left: 5
+ Label
+ !text: tr('-')
+ color: #C0C0C0
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 3
+ margin-top: 2
+ ComboBox
+ id: day
+ size: 50 20
+ color: #C0C0C0
+ text-offset: 15 1
+ anchors.left: prev.right
+ anchors.top: year.top
+ margin-left: 5
+ UIWidget
+ id: error
+ !tooltip: tr('Select a date in the future!')
+ anchors.left: prev.right
+ anchors.verticalCenter: month.verticalCenter
+ //image-source: /game_cyclopedia/images/icon-info-error
+ margin-left: 5
+ visible: false
+ UIWidget
+ !tooltip: tr('You will move out at the daily server save of the selected day.')
+ anchors.right: parent.right
+ anchors.verticalCenter: month.verticalCenter
+ image-source: /images/icons/show_gui_help_grey
+ Label
+ !text: tr('New Owner:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: year.bottom
+ anchors.left: parent.left
+ margin-top: 3
+ TextEdit
+ id: owner
+ size: 193 16
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 5
+ padding-top: 1
+ placeholder: Name of new owner
+ placeholder-color: #6E706F
+ UIWidget
+ id: errorName
+ !tooltip: tr('Field must be completed.')
+ anchors.left: prev.right
+ anchors.verticalCenter: owner.verticalCenter
+ // image-source: /game_cyclopedia/images/icon-info-error
+ margin-left: 5
+ visible: false
+ UIWidget
+ !tooltip: tr('Note that the new owner has to accept the transfer.')
+ anchors.right: parent.right
+ anchors.verticalCenter: owner.verticalCenter
+ image-source: /images/icons/show_gui_help_grey
+ Label
+ !text: tr('Transfer Price:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: owner.bottom
+ anchors.left: parent.left
+ margin-top: 3
+ TextEdit
+ id: price
+ size: 100 16
+ text-align: right
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 5
+ padding-top: 1
+ UIWidget
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-top: 3
+ margin-left: 5
+ image-source: /game_cyclopedia/images/icon_gold
+ Label
+ !text: tr('Please remeber to take your personal belongings out of\nthe house before you move out. Items remaining in the\nhouse become the property of the new owner after the transfer.\nThe only exception are items which have been purchased\nin the Store. They will be sent yo your inbox.')
+ text-auto-resize: true
+ anchors.top: prev.bottom
+ anchors.left: parent.left
+ margin-top: 10
+ color: #C0C0C0
+ UIWidget
+ id: cancelHouseTransferArea
+ !text: tr('Cancel House Transfer')
+ text-align: top
+ text-offset: 0 1
+ color: #909090
+ size: 413 358
+ anchors.top: LateralBase.top
+ anchors.left: LateralBase.right
+ image-source: /images/ui/widget-borderimage
+ image-border: 15
+ margin-left: 5
+ visible: false
+ padding: 15
+ Button
+ id: cancel
+ size: 43 20
+ !text: tr('Cancel')
+ color: #C0C0C0
+ anchors.bottom: parent.bottom
+ anchors.right: parent.right
+ //font: verdana-bold-8px-antialiased
+ text-offset: 0 -1
+ change-cursor-image: false
+ Button
+ id: transfer
+ size: 86 20
+ !text: tr('Cancel Transfer')
+ color: #C0C0C0
+ anchors.top: cancel.top
+ anchors.right: cancel.left
+ margin-right: 7
+ //font: verdana-bold-8px-antialiased
+ text-offset: 0 -1
+ change-cursor-image: false
+ Label
+ !text: tr('House Information')
+ anchors.top: parent.top
+ anchors.left: parent.left
+ margin-top: 10
+ color: #F7F7F7
+ Label
+ !text: tr('Name:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: prev.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ Label
+ id: name
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 8
+ Label
+ !text: tr('Size:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: name.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ Label
+ id: size
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 8
+ Label
+ !text: tr('Max. Beds:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: size.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ Label
+ id: beds
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 8
+ Label
+ !text: tr('Rent:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: beds.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ Label
+ id: rent
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 8
+ UIWidget
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-top: 3
+ image-source: /game_cyclopedia/images/icon_gold
+ Label
+ !text: tr('Transfer Information')
+ anchors.top: prev.bottom
+ anchors.left: parent.left
+ margin-top: 5
+ color: #F7F7F7
+ Label
+ !text: tr('Paid until:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: prev.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ Label
+ id: paid
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 8
+ Label
+ !text: tr('New Owner:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: prev.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ Label
+ id: owner
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 8
+ Label
+ !text: tr('Transfer Date:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: prev.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ Label
+ id: transferDate
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 8
+ Label
+ !text: tr('Price:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: prev.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ Label
+ id: transferPrice
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 8
+ UIWidget
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-top: 3
+ margin-left: 5
+ image-source: /game_cyclopedia/images/icon_gold
+ Label
+ !text: tr('If you want to keep this house. click on "Cancel Transfer".')
+ text-auto-resize: true
+ anchors.top: prev.bottom
+ anchors.left: parent.left
+ margin-top: 10
+ color: #C0C0C0
+ UIWidget
+ id: acceptTransferHouse
+ !text: tr('Accept House Transfer')
+ text-align: top
+ text-offset: 0 1
+ color: #909090
+ size: 413 358
+ anchors.top: LateralBase.top
+ anchors.left: LateralBase.right
+ image-source: /images/ui/widget-borderimage
+ image-border: 15
+ margin-left: 5
+ visible: false
+ padding: 15
+ Button
+ id: cancel
+ size: 43 20
+ !text: tr('Cancel')
+ color: #C0C0C0
+ anchors.bottom: parent.bottom
+ anchors.right: parent.right
+ //font: verdana-bold-8px-antialiased
+ text-offset: 0 -1
+ change-cursor-image: false
+ Button
+ id: transfer
+ size: 86 20
+ !text: tr('Accept Transfer')
+ color: #C0C0C0
+ anchors.top: cancel.top
+ anchors.right: cancel.left
+ margin-right: 7
+ //font: verdana-bold-8px-antialiased
+ text-offset: 0 -1
+ change-cursor-image: false
+ Label
+ !text: tr('House Information')
+ anchors.top: parent.top
+ anchors.left: parent.left
+ margin-top: 10
+ color: #F7F7F7
+ Label
+ !text: tr('Name:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: prev.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ Label
+ id: name
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 8
+ Label
+ !text: tr('Size:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: name.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ Label
+ id: size
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 8
+ Label
+ !text: tr('Max. Beds:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: size.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ Label
+ id: beds
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 8
+ Label
+ !text: tr('Rent:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: beds.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ Label
+ id: rent
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 8
+ UIWidget
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-top: 3
+ image-source: /game_cyclopedia/images/icon_gold
+ Label
+ !text: tr('Transfer Information')
+ anchors.top: prev.bottom
+ anchors.left: parent.left
+ margin-top: 5
+ color: #F7F7F7
+ Label
+ !text: tr('Paid until:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: prev.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ Label
+ id: paid
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 8
+ Label
+ !text: tr('New Owner:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: prev.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ Label
+ id: owner
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 8
+ Label
+ !text: tr('Transfer Date:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: prev.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ Label
+ id: transferDate
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 8
+ Label
+ !text: tr('Price:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: prev.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ Label
+ id: transferPrice
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 8
+ UIWidget
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-top: 3
+ margin-left: 5
+ image-source: /game_cyclopedia/images/icon_gold
+ Label
+ !text: tr('Make sure to have enough gold in your bank account to\npay the costs for this house transfer and the next rent.\nRemember to edit the door rights as only the guest list\nwill be reset after the transfer!')
+ text-auto-resize: true
+ anchors.top: prev.bottom
+ anchors.left: parent.left
+ margin-top: 10
+ color: #C0C0C0
+ UIWidget
+ id: rejectTransferHouse
+ !text: tr('Reject House Transfer')
+ text-align: top
+ text-offset: 0 1
+ color: #909090
+ size: 413 358
+ anchors.top: LateralBase.top
+ anchors.left: LateralBase.right
+ image-source: /images/ui/widget-borderimage
+ image-border: 15
+ margin-left: 5
+ visible: false
+ padding: 15
+ Button
+ id: cancel
+ size: 43 20
+ !text: tr('Cancel')
+ color: #C0C0C0
+ anchors.bottom: parent.bottom
+ anchors.right: parent.right
+ //font: verdana-bold-8px-antialiased
+ text-offset: 0 -1
+ change-cursor-image: false
+ Button
+ id: transfer
+ size: 86 20
+ !text: tr('Reject Transfer')
+ color: #C0C0C0
+ anchors.top: cancel.top
+ anchors.right: cancel.left
+ margin-right: 7
+ //font: verdana-bold-8px-antialiased
+ text-offset: 0 -1
+ change-cursor-image: false
+ Label
+ !text: tr('House Information')
+ anchors.top: parent.top
+ anchors.left: parent.left
+ margin-top: 10
+ color: #F7F7F7
+ Label
+ !text: tr('Name:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: prev.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ Label
+ id: name
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 8
+ Label
+ !text: tr('Size:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: name.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ Label
+ id: size
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 8
+ Label
+ !text: tr('Max. Beds:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: size.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ Label
+ id: beds
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 8
+ Label
+ !text: tr('Rent:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: beds.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ Label
+ id: rent
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 8
+ UIWidget
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-top: 3
+ image-source: /game_cyclopedia/images/icon_gold
+ Label
+ !text: tr('Transfer Information')
+ anchors.top: prev.bottom
+ anchors.left: parent.left
+ margin-top: 5
+ color: #F7F7F7
+ Label
+ !text: tr('Paid until:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: prev.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ Label
+ id: paid
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 8
+ Label
+ !text: tr('New Owner:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: prev.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ Label
+ id: owner
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 8
+ Label
+ !text: tr('Transfer Date:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: prev.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ Label
+ id: transferDate
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 8
+ Label
+ !text: tr('Price:')
+ color: #909090
+ text-align: right
+ size: 90 15
+ anchors.top: prev.bottom
+ anchors.left: parent.left
+ margin-top: 2
+ Label
+ id: transferPrice
+ color: #C0C0C0
+ text-auto-resize: true
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-left: 8
+ UIWidget
+ anchors.top: prev.top
+ anchors.left: prev.right
+ margin-top: 3
+ margin-left: 5
+ image-source: /game_cyclopedia/images/icon_gold
+ Label
+ !text: tr('Reject the transfer if you do not want the house\ntransferred to you.')
+ text-auto-resize: true
+ anchors.top: prev.bottom
+ anchors.left: parent.left
+ margin-top: 10
+ color: #C0C0C0
+ UIWidget
+ id: ListBase
+ size: 413 358
+ anchors.top: LateralBase.top
+ anchors.left: LateralBase.right
+ image-source: /images/ui/panel_flat
+ image-border: 10
+ margin-left: 5
+ UIScrollArea
+ id: AuctionList
+ vertical-scrollbar: AuctionListScrollbar
+ anchors.fill: parent
+ margin-right: 13
+ padding-left: 3
+ padding-top: 3
+ padding-bottom: 2
+ layout:
+ type: grid
+ cell-size: 391 56
+ cell-spacing: 5
+ flow: true
+ VerticalScrollBar
+ id: AuctionListScrollbar
+ anchors.top: parent.top
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ margin-right: 3
+ margin-top: 3
+ margin-bottom: 3
+ step: 80
+ pixel-scroll: true
diff --git a/modules/game_cyclopedia/tab/items/items.lua b/modules/game_cyclopedia/tab/items/items.lua
new file mode 100644
index 0000000000..a0af80ac99
--- /dev/null
+++ b/modules/game_cyclopedia/tab/items/items.lua
@@ -0,0 +1,483 @@
+Cyclopedia.Items = {}
+Cyclopedia.CategoryItems = {
+ { id = 1, name = "Armors" },
+ { id = 2, name = "Amulets" },
+ { id = 3, name = "Boots" },
+ { id = 4, name = "Containers" },
+ { id = 24, name = "Creature Products" },
+ { id = 5, name = "Decoration" },
+ { id = 6, name = "Food" },
+ { id = 30, name = "Gold" },
+ { id = 7, name = "Helmets and Hats" },
+ { id = 8, name = "Legs" },
+ { id = 9, name = "Others" },
+ { id = 10, name = "Potions" },
+ { id = 25, name = "Quivers" },
+ { id = 11, name = "Rings" },
+ { id = 12, name = "Runes" },
+ { id = 13, name = "Shields" },
+ { id = 26, name = "Soul Cores" },
+ { id = 14, name = "Tools" },
+ { id = 31, name = "Unsorted" },
+ { id = 15, name = "Valuables" },
+ { id = 16, name = "Weapons: Ammo" },
+ { id = 17, name = "Weapons: Axe" },
+ { id = 18, name = "Weapons: Clubs" },
+ { id = 19, name = "Weapons: Distance" },
+ { id = 20, name = "Weapons: Swords" },
+ { id = 21, name = "Weapons: Wands" },
+ { id = 1000, name = "Weapons: All" }
+}
+
+local UI = nil
+
+focusCategoryList = nil
+
+function Cyclopedia.ResetItemCategorySelection(list)
+ for i, child in pairs(list:getChildren()) do
+ child:setChecked(false)
+ child:setBackgroundColor(child.BaseColor)
+ end
+end
+
+function showItems()
+ UI = g_ui.loadUI("items", contentContainer)
+ UI:show()
+ UI.VocFilter = false
+ UI.LevelFilter = false
+ UI.h1Filter = false
+ UI.h2Filter = false
+ UI.ClassificationFilter = 0
+ UI.SelectedCategory = nil
+ UI.LootValue.NpcBuyCheck.onClick = Cyclopedia.onChangeLootValue
+ UI.LootValue.MarketCheck.onClick = Cyclopedia.onChangeLootValue
+ UI.EmptyLabel:setVisible(true)
+ UI.InfoBase:setVisible(false)
+ UI.LootValue:setVisible(false)
+ UI.H1Button:disable()
+ UI.H2Button:disable()
+ UI.ItemFilter:disable()
+ controllerCyclopedia.ui.CharmsBase:setVisible(false)
+ controllerCyclopedia.ui.GoldBase:setVisible(false)
+ controllerCyclopedia.ui.BestiaryTrackerButton:setVisible(false)
+
+ local CategoryColor = "#484848"
+
+ for _, data in ipairs(Cyclopedia.CategoryItems) do
+ local ItemCat = g_ui.createWidget("ItemCategory", UI.CategoryList)
+
+ ItemCat:setId(data.id)
+ ItemCat:setText(data.name)
+ ItemCat:setBackgroundColor(CategoryColor)
+ ItemCat:setPhantom(false)
+ ItemCat.BaseColor = CategoryColor
+
+ function ItemCat:onClick()
+ Cyclopedia.ResetItemCategorySelection(UI.CategoryList)
+ self:setChecked(true)
+ self:setBackgroundColor("#585858")
+ end
+
+ CategoryColor = CategoryColor == "#484848" and "#414141" or "#484848"
+ end
+
+ Cyclopedia.ItemList = {}
+ Cyclopedia.AllItemList = {}
+ Cyclopedia.loadItemsCategories()
+
+ focusCategoryList = UI.CategoryList
+
+ g_keyboard.bindKeyPress('Down', function()
+ focusCategoryList:focusNextChild(KeyboardFocusReason)
+ end, focusCategoryList:getParent())
+
+ g_keyboard.bindKeyPress('Up', function()
+ focusCategoryList:focusPreviousChild(KeyboardFocusReason)
+ end, focusCategoryList:getParent())
+
+ connect(focusCategoryList, {
+ onChildFocusChange = function(self, focusedChild)
+ if focusedChild == nil then
+ return
+ end
+ focusedChild:onClick()
+ end
+ })
+end
+
+function Cyclopedia.onCategoryChange(widget)
+ if widget:isChecked() then
+ Cyclopedia.selectItemCategory(tonumber(widget:getId()))
+ UI.selectedCategory = widget
+ end
+end
+
+function Cyclopedia.vocationFilter(value)
+ UI.ItemListBase.List:destroyChildren()
+ Cyclopedia.Items.VocFilter = value
+ Cyclopedia.applyFilters()
+end
+
+function Cyclopedia.levelFilter(value)
+ UI.ItemListBase.List:destroyChildren()
+ Cyclopedia.Items.LevelFilter = value
+ Cyclopedia.applyFilters()
+end
+
+function Cyclopedia.h1Filter(value)
+ UI.ItemListBase.List:destroyChildren()
+
+ local brother = UI.H2Button
+
+ Cyclopedia.Items.h1Filter = value
+ Cyclopedia.applyFilters()
+
+ if value and brother:isChecked() then
+ brother:setChecked(false)
+ Cyclopedia.Items.h2Filter = false
+ end
+end
+
+function Cyclopedia.h2Filter(value)
+ UI.ItemListBase.List:destroyChildren()
+
+ local brother = UI.H1Button
+ Cyclopedia.Items.h2Filter = value
+ Cyclopedia.applyFilters()
+
+ if value and brother:isChecked() then
+ brother:setChecked(false)
+ Cyclopedia.Items.h1Filter = false
+ end
+end
+
+function Cyclopedia.classificationFilter(data)
+ UI.ItemListBase.List:destroyChildren()
+ Cyclopedia.Items.ClassificationFilter = tonumber(data)
+ Cyclopedia.applyFilters()
+end
+
+function Cyclopedia.applyFilters()
+ local isSearching = UI.SearchEdit:getText() ~= ""
+ if not isSearching then
+ if UI.selectedCategory then
+ local id = tonumber(UI.selectedCategory:getId())
+ end
+
+ if Cyclopedia.ItemList[id] then
+ for _, data in pairs(Cyclopedia.ItemList[id]) do
+ local item = Cyclopedia.internalCreateItem(data)
+ end
+ end
+ else
+ Cyclopedia.ItemSearch(UI.SearchEdit:getText(), false)
+ end
+end
+
+function Cyclopedia.internalCreateItem(data)
+ -- temp fix 13.40
+ if data:getId() > 47381 and data:getId() < 80909 then
+ return
+ end
+
+ local player = g_game.getLocalPlayer()
+ local vocation = player:getVocation()
+ local level = player:getLevel()
+ local classification = data:getClassification()
+ local marketData = data:getMarketData()
+ local vocFilter = Cyclopedia.Items.VocFilter
+ local levelFilter = Cyclopedia.Items.LevelFilter
+ local h1Filter = Cyclopedia.Items.h1Filter
+ local h2Filter = Cyclopedia.Items.h2Filter
+ local classificationFilter = Cyclopedia.Items.ClassificationFilter
+
+ if vocFilter and tonumber(marketData.restrictVocation) ~= tonumber(vocation) then
+ return
+ end
+
+ if levelFilter and level < marketData.requiredLevel then
+ return
+ end
+
+ if h1Filter and data:getClothSlot() ~= 6 then
+ return
+ end
+
+ if h2Filter and data:getClothSlot() ~= 0 then
+ return
+ end
+
+ if classificationFilter == -1 and classification ~= 0 then
+ return
+ elseif classificationFilter == 1 and classification ~= 1 then
+ return
+ elseif classificationFilter == 2 and classification ~= 2 then
+ return
+ elseif classificationFilter == 3 and classification ~= 3 then
+ return
+ elseif classificationFilter == 4 and classification ~= 4 then
+ return
+ end
+
+ local item = g_ui.createWidget("ItemsListBaseItem", UI.ItemListBase.List)
+
+ item:setId(data:getId())
+ item.Sprite:setItemId(data:getId())
+ item.Name:setText(marketData.name)
+
+ local price, rarity = ItemsDatabase.getSellValueAndColor(data:getId())
+ item.Value = price
+ item.Vocation = marketData.restrictVocation
+
+ if price > 0 then
+ item.Rarity:setImageSource("/images/ui/rarity_" .. rarity)
+ end
+
+ ItemsDatabase.setRarityItem(item.Sprite, item)
+
+ function item.onClick(widget)
+ UI.InfoBase.SellBase.List:destroyChildren()
+ UI.InfoBase.BuyBase.List:destroyChildren()
+
+ local oldSelected = UI.selectItem
+ local lootValue = UI.LootValue
+ local itemId = tonumber(widget:getId())
+ local internalData = g_things.getThingType(itemId, ThingCategoryItem)
+
+ if oldSelected then
+ oldSelected:setBackgroundColor("#00000000")
+ end
+
+ g_game.inspectionObject(3, itemId)
+
+ if not lootValue:isVisible() then
+ lootValue:setVisible(true)
+ end
+
+ UI.EmptyLabel:setVisible(false)
+ UI.InfoBase:setVisible(true)
+ UI.InfoBase.ResultGoldBase.Value:setText(Cyclopedia.formatGold(item.Value))
+ UI.SelectedItem.Sprite:setItemId(data:getId())
+
+ if price > 0 then
+ UI.InfoBase.ResultGoldBase.Rarity:setImageSource("/images/ui/rarity_" .. rarity)
+ UI.SelectedItem.Rarity:setImageSource("/images/ui/rarity_" .. rarity)
+ else
+ UI.InfoBase.ResultGoldBase.Rarity:setImageSource("")
+ UI.SelectedItem.Rarity:setImageSource("")
+ end
+ widget:setBackgroundColor("#585858")
+
+ UI.InfoBase.SkipQuickLootCheck.onCheckChange = function(self, checked)
+ UI.InfoBase.SkipQuickLootCheck:setChecked(modules.game_quickloot.QuickLoot.lootExists(data:getId(), 1))
+ if checked then
+ modules.game_quickloot.QuickLoot.addLootList(data:getId(), 1)
+ else
+ modules.game_quickloot.QuickLoot.removeLootList(data:getId(), 1)
+ end
+ end
+
+ --[[ local buy, sell = Cyclopedia.formatSaleData(internalData:getNpcSaleData())
+ local sellColor = "#484848"
+
+ for index, value in ipairs(sell) do
+ local t_widget = g_ui.createWidget("UIWidget", UI.InfoBase.SellBase.List)
+
+ t_widget:setId(index)
+ t_widget:setText(value)
+ t_widget:setTextAlign(AlignLeft)
+ t_widget:setBackgroundColor(sellColor)
+
+ t_widget.BaseColor = sellColor
+
+ function t_widget:onClick()
+ Cyclopedia.ResetItemCategorySelection(UI.InfoBase.SellBase.List)
+ self:setChecked(true)
+ self:setBackgroundColor("#585858")
+ end
+
+ sellColor = sellColor == "#484848" and "#414141" or "#484848"
+ end
+
+ local buyColor = "#484848"
+
+ for index, value in ipairs(buy) do
+ local t_widget = g_ui.createWidget("UIWidget", UI.InfoBase.BuyBase.List)
+
+ t_widget:setId(index)
+ t_widget:setText(value)
+ t_widget:setTextAlign(AlignLeft)
+ t_widget:setBackgroundColor(buyColor)
+
+ t_widget.BaseColor = buyColor
+
+ function t_widget:onClick()
+ Cyclopedia.ResetItemCategorySelection(UI.InfoBase.BuyBase.List)
+ self:setChecked(true)
+ self:setBackgroundColor("#585858")
+ end
+
+ buyColor = buyColor == "#484848" and "#414141" or "#484848"
+ end ]]
+
+ UI.selectItem = widget
+ end
+
+ return item
+end
+
+function Cyclopedia.ItemSearch(text, clearTextEdit)
+ UI.ItemListBase.List:destroyChildren()
+ if text ~= "" then
+ UI.SelectedItem.Sprite:setItemId(0)
+ UI.SelectedItem.Rarity:setImageSource("")
+
+ local searchedItems = {}
+
+ local oldSelected = UI.selectedCategory
+ if oldSelected then
+ oldSelected:setBackgroundColor(oldSelected.BaseColor)
+ oldSelected:setChecked(false)
+ end
+
+ local searchTermLower = string.lower(text)
+
+ for _, data in pairs(Cyclopedia.AllItemList) do
+ local marketData = data:getMarketData()
+ local itemNameLower = string.lower(marketData.name)
+ local _, endIndex = itemNameLower:find(searchTermLower, 1, true)
+
+ if endIndex and (itemNameLower:sub(endIndex + 1, endIndex + 1) == " " or endIndex == #itemNameLower) then
+ table.insert(searchedItems, data)
+ end
+ end
+
+ for _, data in ipairs(searchedItems) do
+ local item = Cyclopedia.internalCreateItem(data)
+ end
+ else
+ UI.SelectedItem.Sprite:setItemId(0)
+ UI.SelectedItem.Rarity:setImageSource("")
+ end
+
+ if clearTextEdit then
+ UI.SearchEdit:setText("")
+ end
+end
+
+function Cyclopedia.selectItemCategory(id)
+ if UI.SearchEdit:getText() ~= "" then
+ Cyclopedia.ItemSearch("", true)
+ end
+
+ UI.ItemListBase.List:destroyChildren()
+
+ if Cyclopedia.hasClassificationFilter(id) then
+ UI.ItemFilter:clearOptions()
+ UI.ItemFilter:addOption("All", 0, true)
+ UI.ItemFilter:addOption("None", -1, true)
+
+ for class = 1, 4 do
+ UI.ItemFilter:addOption("Class " .. class, class, true)
+ end
+
+ UI.ItemFilter:enable()
+ else
+ UI.ItemFilter:clearOptions()
+ Cyclopedia.Items.ClassificationFilter = 0
+ end
+
+ local idsToProcess = {}
+
+ if id == 1000 then
+ idsToProcess = {16, 17, 18, 19, 20, 21}
+ else
+ idsToProcess = {id}
+ end
+
+ for _, idToProcess in pairs(idsToProcess) do
+ if not table.empty(Cyclopedia.ItemList[idToProcess]) then
+ for _, data in pairs(Cyclopedia.ItemList[idToProcess]) do
+ local item = Cyclopedia.internalCreateItem(data)
+ end
+ end
+ end
+
+ if Cyclopedia.hasHandedFilter(id) then
+ UI.H1Button:enable()
+ UI.H2Button:enable()
+ else
+ UI.H1Button:disable()
+ UI.H2Button:disable()
+ end
+end
+
+function Cyclopedia.loadItemsCategories()
+ local types = g_things.findThingTypeByAttr(ThingAttrMarket, 0)
+ local tempItemList = {}
+
+ for _, data in pairs(types) do
+ local marketData = data:getMarketData()
+ if not tempItemList[marketData.category] then
+ tempItemList[marketData.category] = {}
+ end
+
+ if marketData then
+ table.insert(Cyclopedia.AllItemList, data)
+ end
+
+ table.insert(tempItemList[marketData.category], data)
+ end
+
+ for category, itemList in pairs(tempItemList) do
+ table.sort(itemList, Cyclopedia.compareItems)
+ Cyclopedia.ItemList[category] = itemList
+ end
+end
+
+function Cyclopedia.FillItemList()
+ local types = g_things.findThingTypeByAttr(ThingAttrMarket, 0)
+
+ for i = 1, #types do
+ local itemType = types[i]
+ local item = Item.create(itemType:getId())
+ if item then
+ local marketData = itemType:getMarketData()
+ if not table.empty(marketData) then
+ item:setId(marketData.showAs)
+
+ local marketItem = {
+ displayItem = item,
+ thingType = itemType,
+ marketData = marketData
+ }
+
+ if Cyclopedia.ItemList[marketData.category] ~= nil then
+ table.insert(Cyclopedia.ItemList[marketData.category], marketItem)
+ end
+ end
+ end
+ end
+end
+
+function Cyclopedia.loadItemDetail(itemId, descriptions)
+ UI.InfoBase.DetailsBase.List:destroyChildren()
+
+ local internalData = g_things.getThingType(itemId, ThingCategoryItem)
+ local classification = internalData:getClassification()
+
+ for _, description in ipairs(descriptions) do
+ local widget = g_ui.createWidget("UIWidget", UI.InfoBase.DetailsBase.List)
+ local key = description[1]
+ local value = description[2]
+ widget:setText(key .. ": " .. value)
+ widget:setColor("#C0C0C0")
+ widget:setTextWrap(true)
+ end
+
+ if classification > 0 then
+ local widget = g_ui.createWidget("UIWidget", UI.InfoBase.DetailsBase.List)
+ widget:setText("Classification: " .. classification)
+ widget:setColor("#C0C0C0")
+ end
+end
diff --git a/modules/game_cyclopedia/tab/items/items.otui b/modules/game_cyclopedia/tab/items/items.otui
new file mode 100644
index 0000000000..8123e295b9
--- /dev/null
+++ b/modules/game_cyclopedia/tab/items/items.otui
@@ -0,0 +1,447 @@
+
+UIWidget
+ id: Cat1
+ anchors.fill: parent
+ visible: false
+ UILabel
+ id: Categorylabel
+ anchors.top: parent.top
+ anchors.left: parent.left
+ margin-top: 10
+ !text: tr('Categories') .. ':'
+ text-auto-resize: true
+ color: #BDBDBD
+ TextList
+ id: CategoryList
+ vertical-scrollbar: CategoryScrollbar
+ anchors.left: parent.left
+ anchors.top: parent.top
+ margin-top: 30
+ image-source: /images/ui/panel_flat
+ image-border: 10
+ size: 200 60
+ padding-left: 2
+ padding-top: 2
+ padding-bottom: 2
+ focusable: false
+
+ VerticalScrollBar
+ id: CategoryScrollbar
+ anchors.top: CategoryList.top
+ anchors.right: CategoryList.right
+ anchors.bottom: CategoryList.bottom
+ step: 10
+ pixels-scroll: true
+ VerticalSeparator
+ id: MidSep
+ anchors.left: parent.left
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ margin-top: 10
+ margin-bottom:30
+ margin-left: 210
+ fakeCheckBox
+ id: LevelButton
+ size: 47 20
+ anchors.left: parent.left
+ anchors.top: CategoryList.bottom
+ margin-top: 40
+ !text: tr("Level")
+ //font: verdana-bold-8px-antialiased
+ text-offset: 13 6
+ color: #C0C0C0
+ @onCheckChange: modules.game_cyclopedia.Cyclopedia.levelFilter(self:isChecked())
+ fakeCheckBox
+ id: VocationButton
+ size: 47 20
+ anchors.left: LevelButton.right
+ anchors.top: LevelButton.top
+ margin-left: 5
+ !text: tr("Voc.")
+ //font: verdana-bold-8px-antialiased
+ text-offset: 13 6
+ color: #C0C0C0
+ @onCheckChange: modules.game_cyclopedia.Cyclopedia.vocationFilter(self:isChecked())
+ fakeCheckBox
+ id: H1Button
+ size: 47 20
+ anchors.left: VocationButton.right
+ anchors.top: LevelButton.top
+ margin-left: 5
+ text-offset: 13 6
+ !text: tr("1H")
+ //font: verdana-bold-8px-antialiased
+ color: #C0C0C0
+ @onCheckChange: modules.game_cyclopedia.Cyclopedia.h1Filter(self:isChecked())
+ fakeCheckBox
+ id: H2Button
+ size: 47 20
+ anchors.left: H1Button.right
+ anchors.top: LevelButton.top
+ margin-left: 5
+ !text: tr("2H")
+
+ //font: verdana-bold-8px-antialiased
+ text-offset: 13 6
+ color: #C0C0C0
+ @onCheckChange: modules.game_cyclopedia.Cyclopedia.h2Filter(self:isChecked())
+ ComboBox
+ id: ItemFilter
+ size: 77 20
+ anchors.top: LevelButton.bottom
+ anchors.left: parent.left
+ margin-top: 6
+ @onOptionChange: modules.game_cyclopedia.Cyclopedia.classificationFilter(self:getCurrentOption().data)
+ Label
+ id: ItemsLabel
+ anchors.top: ItemFilter.bottom
+ anchors.left: parent.left
+ margin-top: 5
+ !text: tr("Items") .. ':'
+ text-auto-resize: true
+ color: #BDBDBD
+ Panel
+ id: ItemListBase
+ anchors.left: parent.left
+ anchors.top: ItemsLabel.bottom
+ margin-top: 5
+ size: 200 120
+ background-color: #363636
+ UIScrollArea
+ id: List
+ anchors.fill: ItemListBase
+ vertical-scrollbar: ListScrollbar
+ margin-top: 5
+ size: 200 120
+ image-border: 10
+ padding-top: 1
+ padding-bottom: 1
+ layout:
+ type: grid
+ cell-size: 200 35
+ flow: true
+ VerticalScrollBar
+ id: ListScrollbar
+ anchors.top: List.top
+ anchors.right: List.right
+ anchors.bottom: List.bottom
+ step: 30
+ pixel-scroll: true
+ UIWidget
+ size: 32 32
+ id: SelectedItem
+ anchors.left: parent.left
+ anchors.top: ItemListBase.bottom
+ image-source: /images/ui/item
+ margin-top: 10
+ UIWidget
+ id: Rarity
+ anchors.fill: parent
+ UIItem
+ id: Sprite
+ anchors.fill: parent
+ Label
+ id: SearchLabel
+ anchors.left: SelectedItem.right
+ anchors.top: SelectedItem.top
+ margin-left: 5
+ !text: tr('Search') .. ':'
+ text-auto-resize: true
+ color: #BDBDBD
+ TextEdit
+ id: SearchEdit
+ anchors.bottom: SelectedItem.bottom
+ anchors.left: SelectedItem.right
+ anchors.right: ItemListBase.right
+ //font: verdana-10px-antialiased
+ padding-top: 2
+ padding-right: 15
+ margin-left: 5
+ height: 17
+ placeholder: Type to search
+ placeholder-color: #6E706F
+ @onTextChange: modules.game_cyclopedia.Cyclopedia.ItemSearch(self:getText())
+ UIWidget
+ id: SearchClearButton
+ anchors.right: SearchEdit.right
+ anchors.top: SearchEdit.top
+ margin-top: 1
+ margin-right: 2
+ image-source: /game_cyclopedia/images/button_clear_search
+ image-color: white
+ opacity: 0.8
+ @onClick: modules.game_cyclopedia.Cyclopedia.ItemSearch("", true)
+ $hover:
+ opacity: 1.0
+ image-color: white
+ $pressed:
+ opacity: 1.0
+ image-color: gray
+ UIWidget
+ id: LootValue
+ height: 64
+ anchors.left: parent.left
+ anchors.right: SearchClearButton.right
+ anchors.top: SelectedItem.bottom
+ Label
+ id: LootValueLabel
+ anchors.left: parent.left
+ anchors.top: parent.top
+ margin-top: 15
+ margin-left: 25
+ !text: tr('Loot Value Source') .. ':'
+ text-auto-resize: true
+ color: #BDBDBD
+ CheckBox
+ id: NpcBuyCheck
+ anchors.top: LootValueLabel.bottom
+ anchors.left: LootValueLabel.left
+ margin-top: 4
+
+ text-offset: 15 0
+ !text: tr('NPC Buy Value')
+ width: 130
+ checked: true
+ CheckBox
+ id: MarketCheck
+ anchors.top: NpcBuyCheck.bottom
+ anchors.left: LootValueLabel.left
+ margin-top: 4
+
+ text-offset: 15 0
+ !text: tr('Market Average Value')
+ width: 150
+ Label
+ id: EmptyLabel
+ anchors.top: parent.top
+ anchors.left: MidSep.right
+ margin-top: 10
+ margin-left: 10
+ !text: tr('Please select an item from the list to see its details here.')
+ color: #C0C0C0
+ text-auto-resize: true
+ UIWidget
+ id: InfoBase
+ anchors.left: MidSep.right
+ anchors.top: parent.top
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ visible: false
+ Label
+ id: BasicDetailsLabel
+ anchors.left: parent.left
+ anchors.top: parent.top
+ margin-left: 15
+ margin-top: 15
+ !text: tr('Basic Item Details') .. ':'
+ text-auto-resize: true
+ color: #BEBEBE
+ Panel
+ id: DetailsBase
+ anchors.left: BasicDetailsLabel.left
+ anchors.top: BasicDetailsLabel.bottom
+ anchors.right: parent.right
+ margin-top: 5
+ height: 140
+ background-color: #363636
+ UIScrollArea
+ id: List
+ vertical-scrollbar: ListScrollbar
+ anchors.fill: parent
+ size: 200 60
+ padding-left: 2
+ padding-top: 2
+ padding-bottom: 2
+ layout:
+ type: grid
+ cell-size: 425 22
+ cell-spacing: 2
+ flow: true
+ UIWidget
+ !text: tr('Status: Loading, please wait...')
+ VerticalScrollBar
+ id: ListScrollbar
+ anchors.top: List.top
+ anchors.right: List.right
+ anchors.bottom: List.bottom
+ step: 80
+ pixel-scroll: true
+ Panel
+ id: SellBase
+ anchors.left: DetailsBase.left
+ anchors.top: DetailsBase.bottom
+ anchors.right: parent.horizontalCenter
+ margin-top: 35
+ margin-right: -5
+ height: 100
+ background-color: #404040
+ UIScrollArea
+ id: List
+ vertical-scrollbar: ListScrollbar
+ anchors.fill: parent
+ size: 200 60
+ padding-left: 5
+ padding-top: 5
+ padding-bottom: 5
+ layout:
+ type: grid
+ cell-size: 210 30
+ cell-spacing: 0
+ flow: true
+ VerticalScrollBar
+ id: ListScrollbar
+ anchors.top: List.top
+ anchors.right: List.right
+ anchors.bottom: List.bottom
+ step: 80
+ pixel-scroll: true
+ Label
+ id: SellLabel
+ anchors.bottom: SellBase.top
+ anchors.left: SellBase.left
+ margin-bottom: 4
+ !text: tr('Sell To') .. ':'
+ text-auto-resize: true
+ color: #BEBEBE
+ Panel
+ id: BuyBase
+ anchors.left: parent.horizontalCenter
+ anchors.top: SellBase.top
+ anchors.right: parent.right
+ margin-left: 13
+ height: 100
+ background-color: #404040
+ UIScrollArea
+ id: List
+ vertical-scrollbar: ListScrollbar
+ anchors.fill: parent
+ size: 200 60
+ padding-left: 5
+ padding-top: 5
+ padding-bottom: 5
+ layout:
+ type: grid
+ cell-size: 210 30
+ cell-spacing: 0
+ flow: true
+ VerticalScrollBar
+ id: ListScrollbar
+ anchors.top: List.top
+ anchors.right: List.right
+ anchors.bottom: List.bottom
+ step: 80
+ pixel-scroll: true
+ Label
+ id: BuyLabel
+ anchors.bottom: BuyBase.top
+ anchors.left: BuyBase.left
+ margin-bottom: 4
+ !text: tr('Buy From') .. ':'
+ text-auto-resize: true
+ color: #BEBEBE
+ UIWidget
+ id: MarketGoldPriceBase
+ anchors.top: BuyBase.bottom
+ anchors.right: parent.right
+ margin-top: 25
+ image-source: /images/ui/item
+ image-border: 10
+ size: 100 22
+ UIWidget
+ id: Icon
+ anchors.right: parent.right
+ anchors.verticalCenter: parent.verticalCenter
+ margin-right: 4
+ image-source: /game_cyclopedia/images/icon-goldcoin
+ Label
+ id: Value
+ anchors.right: Icon.left
+ anchors.verticalCenter: parent.verticalCenter
+ margin-right: 4
+ !text: tr('0')
+ text-auto-resize: true
+ color: #BDBDBD
+ Label
+ id: MarketPriceLabel
+ anchors.left: SellBase.left
+ anchors.bottom: MarketGoldPriceBase.bottom
+ !text: tr('Average Market Price') .. ':'
+ text-auto-resize: true
+ color: #BEBEBE
+ TextEdit
+ id: OwnValueEdit
+ anchors.top: MarketGoldPriceBase.bottom
+ anchors.right: parent.right
+ anchors.left: MarketGoldPriceBase.left
+ margin-top: 2
+ placeholder: Type to set
+ placeholder-color: #6E706F
+ Label
+ id: OwnLootLabel
+ anchors.left: SellBase.left
+ anchors.bottom: OwnValueEdit.bottom
+ !text: tr('Prefer Own Loot Value') .. ':'
+ text-auto-resize: true
+ color: #BEBEBE
+ UIWidget
+ id: ResultGoldBase
+ anchors.top: OwnValueEdit.bottom
+ anchors.right: parent.right
+ margin-top: 2
+ image-source: /images/ui/item
+ image-border: 10
+ size: 100 22
+ UIWidget
+ id: Rarity
+ anchors.fill: parent
+ image-border: 5
+ margin: 1
+ UIWidget
+ id: Icon
+ anchors.right: parent.right
+ anchors.verticalCenter: parent.verticalCenter
+ margin-right: 4
+ image-source: /game_cyclopedia/images/icon-goldcoin
+ Label
+ id: Value
+ anchors.right: Icon.left
+ anchors.verticalCenter: parent.verticalCenter
+ margin-right: 4
+ !text: tr('0')
+ text-auto-resize: true
+ color: #BDBDBD
+ Label
+ id: ResultLabel
+ anchors.left: SellBase.left
+ anchors.bottom: ResultGoldBase.bottom
+ !text: tr('Resulting Value') .. ':'
+ text-auto-resize: true
+ color: #BEBEBE
+ CheckBox
+ id: TrackCheck
+ anchors.left: SellBase.left
+ anchors.bottom: parent.bottom
+ margin-bottom: 35
+ !text: tr('Track drops of this item')
+ text-auto-resize: true
+ CheckBox
+ id: SkipQuickLootCheck
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ margin-bottom: 35
+ !text: tr('Skip when Quick Looting')
+
+ text-auto-resize: true
+
+ Button
+ id: ManageButton
+ size: 120 20
+ anchors.left: parent.left
+ anchors.bottom: parent.bottom
+ !text: tr('Manage Containers')
+ //font: verdana-bold-8px-antialiased
+ text-offset: 0 -1
+ color: #C0C0C0
+ @onClick: |
+ modules.game_cyclopedia.toggle()
+ modules.game_quickloot.QuickLoot.toggle()
diff --git a/modules/game_cyclopedia/tab/map/map.lua b/modules/game_cyclopedia/tab/map/map.lua
new file mode 100644
index 0000000000..93344cb589
--- /dev/null
+++ b/modules/game_cyclopedia/tab/map/map.lua
@@ -0,0 +1,200 @@
+local UI = nil
+local virtualFloor = 7
+
+function showMap()
+ UI = g_ui.loadUI("map", contentContainer)
+ UI:show()
+ controllerCyclopedia:registerEvents(LocalPlayer, {
+ onPositionChange = Cyclopedia.onUpdateCameraPosition
+ }):execute()
+
+ Cyclopedia.prevFloor = 7
+ Cyclopedia.loadMap()
+
+ controllerCyclopedia.ui.CharmsBase:setVisible(false)
+ controllerCyclopedia.ui.GoldBase:setVisible(true)
+ controllerCyclopedia.ui.BestiaryTrackerButton:setVisible(false)
+end
+
+function Cyclopedia.loadMap()
+ local clientVersion = g_game.getClientVersion()
+ local minimapWidget = UI.MapBase.minimap
+
+ g_minimap.clean()
+
+ local loaded = false
+ local minimapFile = "/minimap.otmm"
+ local dataMinimapFile = "/data" .. minimapFile
+ local versionedMinimapFile = "/minimap" .. clientVersion .. ".otmm"
+
+ if g_resources.fileExists(dataMinimapFile) then
+ loaded = g_minimap.loadOtmm(dataMinimapFile)
+ end
+
+ if not loaded and g_resources.fileExists(versionedMinimapFile) then
+ loaded = g_minimap.loadOtmm(versionedMinimapFile)
+ end
+
+ if not loaded and g_resources.fileExists(minimapFile) then
+ loaded = g_minimap.loadOtmm(minimapFile)
+ end
+
+ if not loaded then
+ print("Minimap couldn't be loaded, file missing?")
+ end
+
+ minimapWidget:load()
+ -- minimapWidget:hideFlags()
+end
+
+function Cyclopedia.CreateMarkItem(Data)
+ local MarkItem = g_ui.createWidget("MarkListItem", UI.InformationBase.InternalBase.DisplayBase.MarkList)
+ MarkItem:setIcon("/images/game/minimap/flag" .. Data.flagId)
+end
+
+function Cyclopedia.toggleMapFlag(widget, checked)
+ -- UI.MapBase.minimap:filterFlag(widget:getId(), checked)
+end
+
+function Cyclopedia.showAllFlags(checked)
+ local size = UI.InformationBase.InternalBase.DisplayBase.MarkList:getChildCount()
+ if checked then
+ for i = 0, size do
+ local flag = UI.InformationBase.InternalBase.DisplayBase.MarkList[i]
+ if flag then
+ flag:setChecked(true)
+ end
+ end
+ else
+ for i = 0, size do
+ local flag = UI.InformationBase.InternalBase.DisplayBase.MarkList[i]
+ if flag then
+ flag:setChecked(false)
+ end
+ end
+ end
+end
+
+function Cyclopedia.moveMap(widget)
+ local distance = 5
+ local direction = widget:getId()
+ if direction == "n" then
+ UI.MapBase.minimap:move(0, distance)
+ elseif direction == "ne" then
+ UI.MapBase.minimap:move(-distance, distance)
+ elseif direction == "e" then
+ UI.MapBase.minimap:move(-distance, 0)
+ elseif direction == "se" then
+ UI.MapBase.minimap:move(-distance, -distance)
+ elseif direction == "s" then
+ UI.MapBase.minimap:move(0, -distance)
+ elseif direction == "sw" then
+ UI.MapBase.minimap:move(distance, -distance)
+ elseif direction == "w" then
+ UI.MapBase.minimap:move(distance, 0)
+ elseif direction == "nw" then
+ UI.MapBase.minimap:move(distance, distance)
+ end
+end
+
+function Cyclopedia.floorScrollBar(oldValue, value)
+ if value < oldValue then
+ UI.MapBase.minimap:floorUp()
+ elseif oldValue < value then
+ UI.MapBase.minimap:floorDown()
+ end
+
+ if value < 0 then
+ value = 0
+ elseif value > 15 then
+ value = 15
+ end
+end
+
+function ConvertLayer(Value)
+ if Value == 150 then
+ return 7
+ elseif Value == 300 then
+ return 15
+ elseif Value >= 1 and Value <= 300 then
+ return math.floor((Value - 1) / 20)
+ else
+ return 0
+ end
+end
+
+function Cyclopedia.onUpdateCameraPosition()
+ local player = g_game.getLocalPlayer()
+ if not player then
+ return
+ end
+
+ local pos = player:getPosition()
+ if not pos then
+ return
+ end
+
+ local minimapWidget = UI.MapBase.minimap
+ if not minimapWidget:isDragging() then
+ if not fullmapView then
+ minimapWidget:setCameraPosition(player:getPosition())
+ end
+
+ minimapWidget:setCrossPosition(player:getPosition(), true)
+ end
+
+ virtualFloor = pos.z
+end
+
+function Cyclopedia.onClickRoseButton(dir)
+ if dir == 'north' then
+ UI.MapBase.minimap:move(0, 1)
+ elseif dir == 'north-east' then
+ UI.MapBase.minimap:move(-1, 1)
+ elseif dir == 'east' then
+ UI.MapBase.minimap:move(-1, 0)
+ elseif dir == 'south-east' then
+ UI.MapBase.minimap:move(-1, -1)
+ elseif dir == 'south' then
+ UI.MapBase.minimap:move(0, -1)
+ elseif dir == 'south-west' then
+ UI.MapBase.minimap:move(1, -1)
+ elseif dir == 'west' then
+ UI.MapBase.minimap:move(1, 0)
+ elseif dir == 'north-west' then
+ UI.MapBase.minimap:move(1, 1)
+ end
+end
+
+function Cyclopedia.setZooom(zoom)
+ if zoom then
+ UI.MapBase.minimap:zoomIn()
+ else
+ UI.MapBase.minimap:zoomOut()
+ end
+end
+
+local function refreshVirtualFloors()
+ UI.InformationBase.InternalBase.NavigationBase.layersMark:setMarginTop(((virtualFloor + 1) * 4) - 3)
+ UI.InformationBase.InternalBase.NavigationBase.automapLayers:setImageClip((virtualFloor * 14) .. ' 0 14 67')
+end
+
+function Cyclopedia.downLayer()
+ if virtualFloor == 15 then
+ return
+ end
+
+ UI.MapBase.minimap:floorDown(1)
+ virtualFloor = virtualFloor + 1
+ refreshVirtualFloors()
+end
+
+function Cyclopedia.upLayer()
+ if virtualFloor == 0 then
+ return
+ end
+
+ UI.MapBase.minimap:floorUp(1)
+ virtualFloor = virtualFloor - 1
+ refreshVirtualFloors()
+end
diff --git a/modules/game_cyclopedia/tab/map/map.otui b/modules/game_cyclopedia/tab/map/map.otui
new file mode 100644
index 0000000000..47cfe3dad7
--- /dev/null
+++ b/modules/game_cyclopedia/tab/map/map.otui
@@ -0,0 +1,531 @@
+UIWidget
+ id: Cat4
+ anchors.fill: parent
+ visible: false
+ UIWidget
+ id: InformationBase
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.bottom: parent.bottom
+ margin-bottom: 8
+ margin-top: 10
+ width: 180
+
+
+ UIScrollArea
+ id: InternalBase
+ anchors.fill: parent
+ margin: 5 5 5 5
+ image-source: /images/ui/panel_flat
+ image-border: 10
+ padding-right: 16
+ margin-bottom: 25
+ vertical-scrollbar: FilterListScrollBar
+ layout: verticalBox
+ UIWidget
+ id: DisplayBase
+ height: 170
+ image-source: /images/ui/window
+ image-border: 20
+ color: #929292
+ text-offset: 0 3
+ text-align: top
+ !text: tr('Display')
+ UIScrollArea
+ id: MarkList
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.top: parent.top
+ margin-left: 10
+ margin-right: 10
+ margin-top: 40
+ height: 110
+ image-source: /images/ui/panel_flat
+ image-border: 10
+ padding-left: 5
+ padding-top: 5
+ layout:
+ type: grid
+ cell-size: 17 17
+ cell-spacing: 4
+ flow: true
+ CheckBoxButton
+ id: 0
+ icon: /game_cyclopedia/images/markers
+ icon-clip: 0 0 11 11
+ @onCheckChange: modules.game_cyclopedia.Cyclopedia.toggleMapFlag(self, self:isChecked())
+ CheckBoxButton
+ id: 1
+ icon: /game_cyclopedia/images/markers
+ icon-clip: 11 0 11 11
+ @onCheckChange: modules.game_cyclopedia.Cyclopedia.toggleMapFlag(self, self:isChecked())
+ CheckBoxButton
+ id: 2
+ icon: /game_cyclopedia/images/markers
+ icon-clip: 22 0 11 11
+ @onCheckChange: modules.game_cyclopedia.Cyclopedia.toggleMapFlag(self, self:isChecked())
+ CheckBoxButton
+ id: 3
+ icon: /game_cyclopedia/images/markers
+ icon-clip: 33 0 11 11
+ @onCheckChange: modules.game_cyclopedia.Cyclopedia.toggleMapFlag(self, self:isChecked())
+ CheckBoxButton
+ id: 4
+ icon: /game_cyclopedia/images/markers
+ icon-clip: 44 0 11 11
+ @onCheckChange: modules.game_cyclopedia.Cyclopedia.toggleMapFlag(self, self:isChecked())
+ CheckBoxButton
+ id: 20
+ icon: /game_cyclopedia/images/icon-map-npc
+ icon-offset: 4 4
+ CheckBoxButton
+ id: 5
+ icon: /game_cyclopedia/images/markers
+ icon-clip: 55 0 11 11
+ @onCheckChange: modules.game_cyclopedia.Cyclopedia.toggleMapFlag(self, self:isChecked())
+ CheckBoxButton
+ id: 6
+ icon: /game_cyclopedia/images/markers
+ icon-clip: 66 0 11 11
+ @onCheckChange: modules.game_cyclopedia.Cyclopedia.toggleMapFlag(self, self:isChecked())
+ CheckBoxButton
+ id: 7
+ icon: /game_cyclopedia/images/markers
+ icon-clip: 77 0 11 11
+ @onCheckChange: modules.game_cyclopedia.Cyclopedia.toggleMapFlag(self, self:isChecked())
+ CheckBoxButton
+ id: 8
+ icon: /game_cyclopedia/images/markers
+ icon-clip: 88 0 11 11
+ @onCheckChange: modules.game_cyclopedia.Cyclopedia.toggleMapFlag(self, self:isChecked())
+ CheckBoxButton
+ id: 9
+ icon: /game_cyclopedia/images/markers
+ icon-clip: 99 0 11 11
+ @onCheckChange: modules.game_cyclopedia.Cyclopedia.toggleMapFlag(self, self:isChecked())
+ CheckBoxButton
+ id: 12
+ icon: /game_cyclopedia/images/icon-map-passage-idle
+ CheckBoxButton
+ id: 10
+ icon: /game_cyclopedia/images/markers
+ icon-clip: 110 0 11 11
+ @onCheckChange: modules.game_cyclopedia.Cyclopedia.toggleMapFlag(self, self:isChecked())
+ CheckBoxButton
+ id: 11
+ icon: /game_cyclopedia/images/markers
+ icon-clip: 121 0 11 11
+ @onCheckChange: modules.game_cyclopedia.Cyclopedia.toggleMapFlag(self, self:isChecked())
+ CheckBoxButton
+ id: 12
+ icon: /game_cyclopedia/images/markers
+ icon-clip: 132 0 11 11
+ @onCheckChange: modules.game_cyclopedia.Cyclopedia.toggleMapFlag(self, self:isChecked())
+ CheckBoxButton
+ id: 13
+ icon: /game_cyclopedia/images/markers
+ icon-clip: 143 0 11 11
+ @onCheckChange: modules.game_cyclopedia.Cyclopedia.toggleMapFlag(self, self:isChecked())
+ CheckBoxButton
+ id: 14
+ icon: /game_cyclopedia/images/markers
+ icon-clip: 154 0 11 11
+ @onCheckChange: modules.game_cyclopedia.Cyclopedia.toggleMapFlag(self, self:isChecked())
+ CheckBoxButton
+ id: 21
+ icon: /game_cyclopedia/images/icon-map-house
+ CheckBoxButton
+ id: 15
+ icon: /game_cyclopedia/images/markers
+ icon-clip: 165 0 11 11
+ @onCheckChange: modules.game_cyclopedia.Cyclopedia.toggleMapFlag(self, self:isChecked())
+ CheckBoxButton
+ id: 16
+ icon: /game_cyclopedia/images/markers
+ icon-clip: 176 0 11 11
+ @onCheckChange: modules.game_cyclopedia.Cyclopedia.toggleMapFlag(self, self:isChecked())
+ CheckBoxButton
+ id: 17
+ icon: /game_cyclopedia/images/markers
+ icon-clip: 187 0 11 11
+ @onCheckChange: modules.game_cyclopedia.Cyclopedia.toggleMapFlag(self, self:isChecked())
+ CheckBoxButton
+ id: 18
+ icon: /game_cyclopedia/images/markers
+ icon-clip: 198 0 11 11
+ @onCheckChange: modules.game_cyclopedia.Cyclopedia.toggleMapFlag(self, self:isChecked())
+ CheckBoxButton
+ id: 19
+ icon: /game_cyclopedia/images/markers
+ icon-clip: 209 0 11 11
+ @onCheckChange: modules.game_cyclopedia.Cyclopedia.toggleMapFlag(self, self:isChecked())
+ CheckBox
+ id: ShowAllBox
+ anchors.left: MarkList.left
+ anchors.bottom: MarkList.bottom
+ margin-left: 5
+ margin-bottom: 5
+ text-auto-resize: true
+ !text: tr('Show All')
+ @onCheckChange: modules.game_cyclopedia.Cyclopedia.showAllFlags(self:isChecked())
+ Label
+ id: MarkLabel
+ anchors.bottom: MarkList.top
+ anchors.horizontalCenter: MarkList.horizontalCenter
+ margin-bottom: 5
+ text-auto-resize: true
+ color: #BEBEBE
+ !text: tr('Filter Marks')
+ UIWidget
+ id: ViewBase1
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ margin-left: 10
+ margin-right: 10
+ margin-bottom: 10
+ height: 85
+ image-source: /images/ui/panel_flat
+ image-border: 10
+ visible: false
+ CheckBox
+ id: SurfaceCheck
+ anchors.top: parent.top
+ anchors.left: parent.left
+ margin-top: 7
+ margin-left: 7
+ image-source: /images/ui/outfits/checkbox_round
+ text-offset: 15 0
+ !text: tr('Surface View')
+ text-auto-resize: true
+ CheckBox
+ id: MapCheck
+ anchors.top: SurfaceCheck.bottom
+ anchors.left: SurfaceCheck.left
+ margin-top: 7
+ image-source: /images/ui/outfits/checkbox_round
+ text-offset: 15 0
+ !text: tr('Map View')
+ text-auto-resize: true
+ HorizontalScrollBar
+ id: SeparatorScroll
+ anchors.left: MapCheck.left
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ margin-right: 7
+ margin-bottom: 5
+ enabled: false
+ Label
+ id: SeparatorLabel
+ anchors.left: SeparatorScroll.left
+ anchors.bottom: SeparatorScroll.top
+ margin-bottom: 6
+ !text: tr('Level separator')
+ color: #767676
+ $checked:
+ color: #BFBFBF
+ Label
+ id: ViewBaseLabel
+ anchors.bottom: ViewBase1.top
+ anchors.horizontalCenter: ViewBase1.horizontalCenter
+ margin-bottom: 5
+ text-auto-resize: true
+ color: #BEBEBE
+ !text: tr('Filter Marks')
+ visible: false
+ UIWidget
+ id: NavigationBase
+ height: 108
+ image-source: /images/ui/window
+ image-border: 20
+ color: #929292
+ text-offset: 0 3
+ text-align: top
+ !text: tr('Navigation')
+ UIWidget
+ id: rosePanel
+ anchors.top: parent.top
+ anchors.horizontalCenter: parent.horizontalCenter
+ size: 43 43
+ margin-top: 30
+ margin-left: -20
+
+ UIWidget
+ id: ambients
+ anchors.centerIn: parent
+ size: 31 31
+
+ UIWidget
+ id: main
+ image-source: /images/automap/timedisplay_scroll
+ anchors.left: parent.left
+ anchors.top: parent.top
+ image-clip: 100 0 24 31
+ size: 24 31
+ phantom: true
+
+ UIWidget
+ id: secondary
+ image-source: /images/automap/timedisplay_scroll
+ anchors.left: main.right
+ anchors.top: parent.top
+ image-clip: 0 0 7 31
+ size: 7 31
+ phantom: true
+
+
+ UIWidget
+ id: rose
+ anchors.fill: parent
+ image-source: /images/automap/automap_rose
+ image-clip: 0 0 43 43
+ phantom: true
+
+ Button
+ image-source: /images/automap/automap_rose
+ image-clip: 14 0 15 8
+ anchors.left: parent.left
+ anchors.top: parent.top
+ margin-left: 14
+ size: 15 8
+ @onClick: |
+ modules.game_cyclopedia.Cyclopedia.onClickRoseButton('north')
+
+ $pressed !disabled:
+ image-clip: 57 0 15 8
+
+ Button
+ image-source: /images/automap/automap_rose
+ image-clip: 28 0 15 15
+ anchors.left: parent.left
+ anchors.top: parent.top
+ margin-left: 28
+ size: 15 15
+ @onClick: |
+ modules.game_cyclopedia.Cyclopedia.onClickRoseButton('north-east')
+
+ $pressed !disabled:
+ image-clip: 114 0 15 15
+
+ Button
+ image-source: /images/automap/automap_rose
+ image-clip: 35 14 8 15
+ anchors.left: parent.left
+ anchors.top: parent.top
+ margin-left: 35
+ margin-top: 14
+ size: 8 15
+ @onClick: |
+ modules.game_cyclopedia.Cyclopedia.onClickRoseButton('east')
+
+ $pressed !disabled:
+ image-clip: 164 14 8 15
+
+ Button
+ image-source: /images/automap/automap_rose
+ image-clip: 28 28 15 15
+ anchors.left: parent.left
+ anchors.top: parent.top
+ margin-left: 28
+ margin-top: 28
+ size: 15 15
+ @onClick: |
+ modules.game_cyclopedia.Cyclopedia.onClickRoseButton('south-east')
+
+ $pressed !disabled:
+ image-clip: 200 28 15 15
+
+ Button
+ image-source: /images/automap/automap_rose
+ image-clip: 14 35 15 8
+ anchors.left: parent.left
+ anchors.top: parent.top
+ margin-left: 14
+ margin-top: 35
+ size: 15 8
+ @onClick: |
+ modules.game_cyclopedia.Cyclopedia.onClickRoseButton('south')
+
+ $pressed !disabled:
+ image-clip: 229 35 15 8
+
+ Button
+ image-source: /images/automap/automap_rose
+ image-clip: 0 28 15 15
+ anchors.left: parent.left
+ anchors.top: parent.top
+ margin-top: 28
+ size: 15 15
+ @onClick: |
+ modules.game_cyclopedia.Cyclopedia.onClickRoseButton('south-west')
+
+ $pressed !disabled:
+ image-clip: 258 28 15 15
+
+ Button
+ image-source: /images/automap/automap_rose
+ image-clip: 0 14 8 15
+ anchors.left: parent.left
+ anchors.top: parent.top
+ margin-top: 14
+ size: 8 15
+ @onClick: |
+ modules.game_cyclopedia.Cyclopedia.onClickRoseButton('west')
+
+ $pressed !disabled:
+ image-clip: 301 14 8 15
+
+ Button
+ image-source: /images/automap/automap_rose
+ image-clip: 0 0 15 15
+ anchors.left: parent.left
+ anchors.top: parent.top
+ size: 15 15
+ @onClick: |
+ modules.game_cyclopedia.Cyclopedia.onClickRoseButton('north-west')
+
+ $pressed !disabled:
+ image-clip: 344 0 15 15
+
+
+ UIWidget
+ id: ZoomOutButton
+ anchors.left: rosePanel.left
+ anchors.top: rosePanel.bottom
+ margin-top: 5
+ image-source: /images/automap/automap_buttons
+ image-clip: 0 20 20 20
+ size: 20 20
+ @onClick: modules.game_cyclopedia.Cyclopedia.setZooom(false)
+ $pressed:
+ image-clip: 20 20 20 20
+ UIWidget
+ id: ZoomInButton
+ size: 20 20
+ anchors.right: rosePanel.right
+ anchors.top: rosePanel.bottom
+ margin-top: 5
+ image-source: /images/automap/automap_buttons
+ image-clip: 0 40 20 20
+ @onClick: modules.game_cyclopedia.Cyclopedia.setZooom(true)
+ $pressed:
+ image-clip: 20 40 20 20
+
+ UIWidget
+ id: automapLayers
+ image-source: /images/automap/automap_indicator_maplayers
+ anchors.left: rosePanel.right
+ anchors.top: rosePanel.top
+ image-clip: 98 0 14 67
+ size: 14 67
+ margin-left: 22
+
+ UIWidget
+ image-source: /images/ui/vertical_line_dark
+ margin-left: 2
+ margin-top: 22
+ margin-bottom: 4
+ anchors.left: automapLayers.right
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ width: 1
+
+ UIWidget
+ id: layersMark
+ anchors.left: prev.right
+ anchors.top: automapLayers.top
+ image-source: /images/automap/automap_indicator_slider_left
+ margin-top: 28
+
+ Button
+ image-source: /images/automap/automap_phantom
+ anchors.left: automapLayers.left
+ anchors.right: automapLayers.right
+ anchors.top: automapLayers.top
+ anchors.bottom: automapLayers.verticalCenter
+ @onClick: modules.game_cyclopedia.Cyclopedia.upLayer()
+
+ Button
+ image-source: /images/automap/automap_phantom
+ anchors.left: automapLayers.left
+ anchors.right: automapLayers.right
+ anchors.top: automapLayers.verticalCenter
+ anchors.bottom: automapLayers.bottom
+ @onClick: modules.game_cyclopedia.Cyclopedia.downLayer()
+ VerticalScrollBar
+ id: FilterListScrollBar
+ anchors.top: InternalBase.top
+ anchors.right: InternalBase.right
+ anchors.bottom: InternalBase.bottom
+ margin-right: 2
+ margin-top: 2
+ margin-bottom: 2
+ step: 80
+ pixel-scroll: true
+ UIWidget
+ id: MapBase
+ anchors.top: InformationBase.top
+ anchors.left: InformationBase.right
+ anchors.right: parent.right
+ anchors.bottom: InformationBase.bottom
+ margin-left: 10
+ margin-bottom: 25
+ image-source: /images/ui/panel_flat
+ image-border: 10
+ UIMinimap
+ id: minimap
+ anchors.fill: parent
+ draggable: true
+ focusable: false
+ cross: true
+ color: black
+
+
+MapLayerSelector < UIWidget
+ UIWidget
+ id: layersPanel
+ size: 20 68
+ anchors.bottom: parent.bottom
+ anchors.right: parent.right
+ margin-right: 7
+
+ UIWidget
+ id: automapLayers
+ image-source: /images/automap/automap_indicator_maplayers
+ anchors.left: parent.left
+ anchors.bottom: parent.bottom
+ image-clip: 98 0 14 67
+ size: 14 67
+
+ UIWidget
+ image-source: /images/ui/vertical_line_dark
+ margin-left: 2
+ margin-top: 4
+ margin-bottom: 4
+ anchors.left: automapLayers.right
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ width: 1
+
+ UIWidget
+ id: layersMark
+ anchors.left: prev.right
+ anchors.top: automapLayers.top
+ image-source: /images/automap/automap_indicator_slider_left
+ margin-top: 28
+
+ Button
+ image-source: /images/automap/automap_phantom
+ anchors.left: automapLayers.left
+ anchors.right: automapLayers.right
+ anchors.top: automapLayers.top
+ anchors.bottom: automapLayers.verticalCenter
+ @onClick: modules.game_cyclopedia.Cyclopedia.upLayer()
+
+ Button
+ image-source: /images/automap/automap_phantom
+ anchors.left: automapLayers.left
+ anchors.right: automapLayers.right
+ anchors.top: automapLayers.verticalCenter
+ anchors.bottom: automapLayers.bottom
+ @onClick: modules.game_cyclopedia.Cyclopedia.downLayer()
diff --git a/modules/game_cyclopedia/utils.lua b/modules/game_cyclopedia/utils.lua
new file mode 100644
index 0000000000..a81c37e671
--- /dev/null
+++ b/modules/game_cyclopedia/utils.lua
@@ -0,0 +1,1653 @@
+RACE = {
+ [-1] = {name = "unknow", type = 2},
+ [0] = {name = "unknow", type = 2},
+ [1] = {name = "unknow", type = 2},
+ [2] = {name = "orc warlord", type = 2},
+ [3] = {name = "war wolf", type = 3},
+ [4] = {name = "orc rider", type = 4},
+ [5] = {name = "orc", type = 5},
+ [6] = {name = "orc shaman", type = 6},
+ [7] = {name = "orc warrior", type = 7},
+ [8] = {name = "orc berserker", type = 8},
+ [9] = {name = "necromancer", type = 9},
+ [10] = {name = "warlock", type = 130},
+ [11] = {name = "hunter", type = 129},
+ [12] = {name = "valkyrie", type = 139},
+ [13] = {name = "black sheep", type = 13},
+ [14] = {name = "sheep", type = 14},
+ [15] = {name = "troll", type = 15},
+ [16] = {name = "bear", type = 16},
+ [17] = {name = "bonelord", type = 17},
+ [18] = {name = "ghoul", type = 18},
+ [19] = {name = "slime", type = 19},
+ [20] = {name = "squidgy slime", type = 19},
+ [21] = {name = "rat", type = 21},
+ [22] = {name = "cyclops", type = 22},
+ [23] = {name = "minotaur mage", type = 23},
+ [24] = {name = "minotaur archer", type = 24},
+ [25] = {name = "minotaur", type = 25},
+ [26] = {name = "rotworm", type = 26},
+ [27] = {name = "wolf", type = 27},
+ [28] = {name = "snake", type = 28},
+ [29] = {name = "minotaur guard", type = 29},
+ [30] = {name = "spider", type = 30},
+ [31] = {name = "deer", type = 31},
+ [32] = {name = "dog", type = 32},
+ [33] = {name = "skeleton", type = 33},
+ [34] = {name = "dragon", type = 34},
+ [35] = {name = "demon", type = 35},
+ [36] = {name = "poison spider", type = 36},
+ [37] = {name = "demon skeleton", type = 37},
+ [38] = {name = "giant spider", type = 38},
+ [39] = {name = "dragon lord", type = 39},
+ [40] = {name = "fire devil", type = 40},
+ [41] = {name = "lion", type = 41},
+ [42] = {name = "polar bear", type = 42},
+ [43] = {name = "scorpion", type = 43},
+ [44] = {name = "wasp", type = 44},
+ [45] = {name = "bug", type = 45},
+ [47] = {name = "wild warrior", type = 131},
+ [48] = {name = "ghost", type = 48},
+ [49] = {name = "fire elemental", type = 49},
+ [50] = {name = "orc spearman", type = 50},
+ [51] = {name = "green djinn", type = 51},
+ [52] = {name = "winter wolf", type = 52},
+ [53] = {name = "frost troll", type = 53},
+ [54] = {name = "witch", type = 54},
+ [55] = {name = "behemoth", type = 55},
+ [56] = {name = "cave rat", type = 56},
+ [57] = {name = "monk", type = 57},
+ [58] = {name = "priestess", type = 58},
+ [59] = {name = "orc leader", type = 59},
+ [60] = {name = "pig", type = 60},
+ [61] = {name = "goblin", type = 61},
+ [62] = {name = "elf", type = 62},
+ [63] = {name = "elf arcanist", type = 63},
+ [64] = {name = "elf scout", type = 64},
+ [65] = {name = "mummy", type = 65},
+ [66] = {name = "dwarf geomancer", type = 66},
+ [67] = {name = "stone golem", type = 67},
+ [68] = {name = "vampire", type = 68},
+ [69] = {name = "dwarf", type = 69},
+ [70] = {name = "dwarf guard", type = 70},
+ [71] = {name = "dwarf soldier", type = 71},
+ [72] = {name = "stalker", type = 128},
+ [73] = {name = "hero", type = 73},
+ [74] = {name = "rabbit", type = 74},
+ [76] = {name = "swamp troll", type = 76},
+ [77] = {name = "amazon", type = 137},
+ [78] = {name = "banshee", type = 78},
+ [79] = {name = "ancient scarab", type = 79},
+ [80] = {name = "blue djinn", type = 80},
+ [81] = {name = "cobra", type = 81},
+ [82] = {name = "larva", type = 82},
+ [83] = {name = "scarab", type = 83},
+ [94] = {name = "hyaena", type = 94},
+ [95] = {name = "gargoyle", type = 95},
+ [99] = {name = "lich", type = 99},
+ [100] = {name = "crypt shambler", type = 100},
+ [101] = {name = "bonebeast", type = 101},
+ [103] = {name = "efreet", type = 103},
+ [104] = {name = "marid", type = 104},
+ [105] = {name = "badger", type = 105},
+ [106] = {name = "skunk", type = 106},
+ [108] = {name = "elder bonelord", type = 108},
+ [109] = {name = "gazer", type = 109},
+ [110] = {name = "yeti", type = 110},
+ [111] = {name = "chicken", type = 111},
+ [112] = {name = "crab", type = 112},
+ [113] = {name = "lizard templar", type = 113},
+ [114] = {name = "lizard sentinel", type = 114},
+ [115] = {name = "lizard snakecharmer", type = 115},
+ [116] = {name = "kongra", type = 116},
+ [117] = {name = "merlkin", type = 117},
+ [118] = {name = "sibang", type = 118},
+ [119] = {name = "crocodile", type = 119},
+ [120] = {name = "carniphila", type = 120},
+ [121] = {name = "hydra", type = 121},
+ [122] = {name = "bat", type = 122},
+ [123] = {name = "panda", type = 123},
+ [124] = {name = "centipede", type = 124},
+ [125] = {name = "tiger", type = 125},
+ [211] = {name = "elephant", type = 211},
+ [212] = {name = "flamingo", type = 212},
+ [213] = {name = "butterfly", type = 227},
+ [214] = {name = "dworc voodoomaster", type = 214},
+ [215] = {name = "dworc fleshhunter", type = 215},
+ [216] = {name = "dworc venomsniper", type = 216},
+ [217] = {name = "parrot", type = 217},
+ [218] = {name = "terror bird", type = 218},
+ [219] = {name = "tarantula", type = 219},
+ [220] = {name = "serpent spawn", type = 220},
+ [221] = {name = "spit nettle", type = 221},
+ [222] = {name = "smuggler", type = 134},
+ [223] = {name = "bandit", type = 129},
+ [224] = {name = "assassin", type = 152},
+ [225] = {name = "dark monk", type = 225},
+ [227] = {name = "yellow butterfly", type = 10},
+ [228] = {name = "red butterfly", type = 228},
+ [236] = {name = "water elemental", type = 286},
+ [237] = {name = "quara predator", type = 20},
+ [238] = {name = "quara predator scout", type = 20},
+ [239] = {name = "quara constrictor", type = 46},
+ [240] = {name = "quara constrictor scout", type = 46},
+ [241] = {name = "quara mantassin", type = 72},
+ [242] = {name = "quara mantassin scout", type = 72},
+ [243] = {name = "quara hydromancer", type = 47},
+ [244] = {name = "quara hydromancer scout", type = 47},
+ [245] = {name = "quara pincher", type = 77},
+ [246] = {name = "quara pincher scout", type = 77},
+ [247] = {name = "pirate marauder", type = 93},
+ [248] = {name = "pirate cutthroat", type = 96},
+ [249] = {name = "pirate buccaneer", type = 97},
+ [250] = {name = "pirate corsair", type = 98},
+ [251] = {name = "carrion worm", type = 192},
+ [252] = {name = "enlightened of the cult", type = 193},
+ [253] = {name = "acolyte of the cult", type = 194},
+ [254] = {name = "adept of the cult", type = 194},
+ [255] = {name = "novice of the cult", type = 133},
+ [256] = {name = "pirate skeleton", type = 195},
+ [257] = {name = "pirate ghost", type = 196},
+ [258] = {name = "tortoise", type = 197},
+ [259] = {name = "thornback tortoise", type = 198},
+ [260] = {name = "mammoth", type = 199},
+ [261] = {name = "blood crab", type = 200},
+ [262] = {name = "toad", type = 222},
+ [264] = {name = "seagull", type = 223},
+ [265] = {name = "son of verminor", type = 19},
+ [267] = {name = "green frog", type = 224},
+ [268] = {name = "azure frog", type = 226},
+ [269] = {name = "coral frog", type = 226},
+ [270] = {name = "crimson frog", type = 226},
+ [271] = {name = "orchid frog", type = 226},
+ [277] = {name = "island troll", type = 282},
+ [279] = {name = "massive water elemental", type = 11},
+ [281] = {name = "hand of cursed fate", type = 230},
+ [282] = {name = "undead dragon", type = 231},
+ [283] = {name = "lost soul", type = 232},
+ [284] = {name = "betrayed wraith", type = 233},
+ [285] = {name = "dark torturer", type = 234},
+ [286] = {name = "spectre", type = 235},
+ [287] = {name = "destroyer", type = 236},
+ [288] = {name = "diabolic imp", type = 237},
+ [289] = {name = "defiler", type = 238},
+ [290] = {name = "wyvern", type = 239},
+ [291] = {name = "fury", type = 149},
+ [292] = {name = "phantasm", type = 241},
+ [294] = {name = "hellhound", type = 240},
+ [295] = {name = "hellfire fighter", type = 243},
+ [296] = {name = "juggernaut", type = 244},
+ [298] = {name = "blightwalker", type = 246},
+ [299] = {name = "nightmare", type = 245},
+ [310] = {name = "nomad", type = 146},
+ [313] = {name = "massive fire elemental", type = 242},
+ [314] = {name = "plaguesmith", type = 247},
+ [317] = {name = "frost dragon", type = 248},
+ [318] = {name = "penguin", type = 250},
+ [319] = {name = "chakoya tribewarden", type = 249},
+ [321] = {name = "braindeath", type = 256},
+ [322] = {name = "barbarian skullhunter", type = 254},
+ [323] = {name = "barbarian bloodwalker", type = 255},
+ [324] = {name = "frost giant", type = 257},
+ [325] = {name = "husky", type = 258},
+ [326] = {name = "ice golem", type = 261},
+ [327] = {name = "silver rabbit", type = 262},
+ [328] = {name = "chakoya toolshaper", type = 259},
+ [329] = {name = "chakoya windcaller", type = 260},
+ [330] = {name = "crystal spider", type = 263},
+ [331] = {name = "ice witch", type = 149},
+ [332] = {name = "barbarian brutetamer", type = 264},
+ [333] = {name = "barbarian headsplitter", type = 253},
+ [334] = {name = "frost giantess", type = 265},
+ [335] = {name = "dire penguin", type = 250},
+ [371] = {name = "dark magician", type = 133},
+ [372] = {name = "dark apprentice", type = 133},
+ [376] = {name = "poacher", type = 129},
+ [377] = {name = "goblin leader", type = 61},
+ [379] = {name = "dwarf henchman", type = 160},
+ [383] = {name = "dryad", type = 137},
+ [384] = {name = "squirrel", type = 274},
+ [385] = {name = "dragon hatchling", type = 271},
+ [386] = {name = "dragon lord hatchling", type = 272},
+ [387] = {name = "cat", type = 276},
+ [389] = {name = "cyclops smith", type = 277},
+ [391] = {name = "cyclops drone", type = 280},
+ [392] = {name = "troll champion", type = 281},
+ [393] = {name = "grynch clan goblin", type = 61},
+ [402] = {name = "frost dragon hatchling", type = 283},
+ [437] = {name = "deepsea blood crab", type = 200},
+ [438] = {name = "sea serpent", type = 275},
+ [439] = {name = "young sea serpent", type = 317},
+ [446] = {name = "skeleton warrior", type = 298},
+ [455] = {name = "massive earth elemental", type = 285},
+ [456] = {name = "massive energy elemental", type = 290},
+ [457] = {name = "energy elemental", type = 293},
+ [458] = {name = "earth elemental", type = 301},
+ [460] = {name = "bog raider", type = 299},
+ [461] = {name = "wyrm", type = 291},
+ [462] = {name = "wisp", type = 294},
+ [463] = {name = "goblin assassin", type = 296},
+ [464] = {name = "goblin scavenger", type = 297},
+ [465] = {name = "grim reaper", type = 300},
+ [483] = {name = "vampire bride", type = 312},
+ [502] = {name = "mutated rat", type = 305},
+ [503] = {name = "worker golem", type = 304},
+ [508] = {name = "undead gladiator", type = 306},
+ [509] = {name = "mutated bat", type = 307},
+ [510] = {name = "werewolf", type = 308},
+ [511] = {name = "haunted treeling", type = 310},
+ [512] = {name = "zombie", type = 311},
+ [513] = {name = "acid blob", type = 314},
+ [514] = {name = "death blob", type = 315},
+ [515] = {name = "mercury blob", type = 316},
+ [516] = {name = "mutated tiger", type = 318},
+ [518] = {name = "nightmare scion", type = 321},
+ [519] = {name = "hellspawn", type = 322},
+ [520] = {name = "nightstalker", type = 320},
+ [521] = {name = "mutated human", type = 323},
+ [523] = {name = "gozzler", type = 313},
+ [524] = {name = "damaged worker golem", type = 304},
+ [525] = {name = "crazed beggar", type = 153},
+ [526] = {name = "gang member", type = 151},
+ [527] = {name = "gladiator", type = 131},
+ [528] = {name = "mad scientist", type = 133},
+ [529] = {name = "infernalist", type = 130},
+ [533] = {name = "war golem", type = 326},
+ [540] = {name = "furious troll", type = 281},
+ [541] = {name = "troll legionnaire", type = 53},
+ [555] = {name = "evil sheep", type = 14},
+ [556] = {name = "evil sheep lord", type = 13},
+ [557] = {name = "hot dog", type = 32},
+ [558] = {name = "vampire pig", type = 60},
+ [559] = {name = "doom deer", type = 31},
+ [560] = {name = "killer rabbit", type = 74},
+ [561] = {name = "berserker chicken", type = 111},
+ [562] = {name = "demon parrot", type = 217},
+ [563] = {name = "infernal frog", type = 224},
+ [570] = {name = "medusa", type = 330},
+ [578] = {name = "acolyte of darkness", type = 9},
+ [580] = {name = "bane of light", type = 68},
+ [581] = {name = "duskbringer", type = 300},
+ [582] = {name = "shadow hound", type = 322},
+ [584] = {name = "midnight spawn", type = 315},
+ [586] = {name = "herald of gloom", type = 320},
+ [594] = {name = "undead mine worker", type = 33},
+ [595] = {name = "undead prospector", type = 18},
+ [614] = {name = "orc marauder", type = 342},
+ [615] = {name = "eternal guardian", type = 345},
+ [616] = {name = "lizard zaogun", type = 343},
+ [617] = {name = "draken warmaster", type = 334},
+ [618] = {name = "draken spellweaver", type = 340},
+ [620] = {name = "lizard chosen", type = 344},
+ [621] = {name = "insect swarm", type = 349},
+ [623] = {name = "lizard dragon priest", type = 339},
+ [624] = {name = "lizard legionnaire", type = 338},
+ [625] = {name = "lizard high guard", type = 337},
+ [627] = {name = "killer caiman", type = 358},
+ [630] = {name = "gnarlhound", type = 341},
+ [631] = {name = "terramite", type = 346},
+ [632] = {name = "wailing widow", type = 347},
+ [633] = {name = "lancer beetle", type = 348},
+ [641] = {name = "sandcrawler", type = 350},
+ [643] = {name = "ghastly dragon", type = 351},
+ [655] = {name = "lizard magistratus", type = 115},
+ [656] = {name = "lizard noble", type = 115},
+ [672] = {name = "draken elite", type = 362},
+ [673] = {name = "draken abomination", type = 357},
+ [674] = {name = "brimstone bug", type = 352},
+ [675] = {name = "souleater", type = 355},
+ [679] = {name = "bane bringer", type = 310},
+ [693] = {name = "boar", type = 380},
+ [694] = {name = "stampor", type = 381},
+ [695] = {name = "draptor", type = 382},
+ [696] = {name = "undead cavebear", type = 384},
+ [697] = {name = "crustacea gigantica", type = 383},
+ [698] = {name = "midnight panther", type = 385},
+ [700] = {name = "iron servant", type = 395},
+ [701] = {name = "golden servant", type = 396},
+ [702] = {name = "diamond servant", type = 397},
+ [704] = {name = "ghoulish hyaena", type = 94},
+ [705] = {name = "sandstone scorpion", type = 398},
+ [706] = {name = "clay guardian", type = 333},
+ [707] = {name = "grave guard", type = 234},
+ [708] = {name = "tomb servant", type = 100},
+ [709] = {name = "sacred spider", type = 219},
+ [710] = {name = "death priest", type = 99},
+ [711] = {name = "elder mummy", type = 65},
+ [712] = {name = "honour guard", type = 298},
+ [717] = {name = "yielothax", type = 408},
+ [719] = {name = "feverish citizen", type = 425},
+ [720] = {name = "white deer", type = 400},
+ [723] = {name = "starving wolf", type = 27},
+ [724] = {name = "shaburak demon", type = 417},
+ [725] = {name = "shaburak lord", type = 409},
+ [726] = {name = "shaburak prince", type = 418},
+ [727] = {name = "askarak demon", type = 420},
+ [728] = {name = "askarak lord", type = 410},
+ [729] = {name = "askarak prince", type = 419},
+ [730] = {name = "wild horse", type = 393},
+ [731] = {name = "slug", type = 407},
+ [732] = {name = "insectoid scout", type = 403},
+ [733] = {name = "dromedary", type = 404},
+ [734] = {name = "deepling scout", type = 413},
+ [735] = {name = "filth toad", type = 222},
+ [737] = {name = "firestarter", type = 159},
+ [738] = {name = "bog frog", type = 412},
+ [739] = {name = "thornfire wolf", type = 414},
+ [740] = {name = "crystal wolf", type = 391},
+ [741] = {name = "elf overseer", type = 159},
+ [745] = {name = "troll guard", type = 281},
+ [750] = {name = "horse", type = 435},
+ [751] = {name = "grey horse", type = 434},
+ [752] = {name = "brown horse", type = 436},
+ [769] = {name = "deepling warrior", type = 441},
+ [770] = {name = "deepling guard", type = 442},
+ [771] = {name = "terrified elephant", type = 211},
+ [772] = {name = "deepling spellsinger", type = 443},
+ [776] = {name = "nomad blue", type = 146},
+ [777] = {name = "nomad female", type = 150},
+ [778] = {name = "ladybug", type = 448},
+ [779] = {name = "manta ray", type = 449},
+ [780] = {name = "calamary", type = 451},
+ [781] = {name = "jellyfish", type = 452},
+ [782] = {name = "shark", type = 453},
+ [783] = {name = "northern pike", type = 454},
+ [784] = {name = "fish", type = 455},
+ [786] = {name = "crawler", type = 456},
+ [787] = {name = "spidris", type = 457},
+ [788] = {name = "kollos", type = 458},
+ [790] = {name = "swarmer", type = 460},
+ [791] = {name = "spitter", type = 461},
+ [792] = {name = "waspoid", type = 462},
+ [795] = {name = "deepling worker", type = 470},
+ [796] = {name = "insectoid worker", type = 403},
+ [797] = {name = "spidris elite", type = 457},
+ [801] = {name = "hive overseer", type = 458},
+ [859] = {name = "deepling brawler", type = 470},
+ [860] = {name = "deepling master librarian", type = 443},
+ [861] = {name = "deepling tyrant", type = 442},
+ [862] = {name = "deepling elite", type = 441},
+ [867] = {name = "grave robber", type = 146},
+ [868] = {name = "crypt defiler", type = 146},
+ [869] = {name = "crystalcrusher", type = 511},
+ [870] = {name = "mushroom sniffer", type = 60},
+ [872] = {name = "water buffalo", type = 523},
+ [873] = {name = "enraged crystal golem", type = 508},
+ [874] = {name = "damaged crystal golem", type = 508},
+ [877] = {name = "modified gnarlhound", type = 515},
+ [878] = {name = "drillworm", type = 527},
+ [879] = {name = "stone devourer", type = 486},
+ [880] = {name = "armadile", type = 487},
+ [881] = {name = "humongous fungus", type = 488},
+ [882] = {name = "weeper", type = 489},
+ [883] = {name = "orewalker", type = 490},
+ [884] = {name = "lava golem", type = 491},
+ [885] = {name = "magma crawler", type = 492},
+ [886] = {name = "enslaved dwarf", type = 494},
+ [888] = {name = "lost berserker", type = 496},
+ [889] = {name = "cliff strider", type = 497},
+ [890] = {name = "ironblight", type = 498},
+ [891] = {name = "hideous fungus", type = 499},
+ [894] = {name = "dragonling", type = 505},
+ [897] = {name = "infected weeper", type = 489},
+ [898] = {name = "vulcongra", type = 509},
+ [899] = {name = "wiggler", type = 510},
+ [912] = {name = "emerald damselfly", type = 528},
+ [913] = {name = "salamander", type = 529},
+ [914] = {name = "marsh stalker", type = 530},
+ [915] = {name = "pigeon", type = 531},
+ [916] = {name = "corym charlatan", type = 532},
+ [917] = {name = "corym skirmisher", type = 533},
+ [918] = {name = "corym vanguard", type = 534},
+ [919] = {name = "swampling", type = 535},
+ [920] = {name = "little corym charlatan", type = 532},
+ [922] = {name = "adventurer", type = 129},
+ [924] = {name = "lost husher", type = 537},
+ [925] = {name = "lost basher", type = 538},
+ [926] = {name = "lost thrower", type = 539},
+ [958] = {name = "vampire viscount", type = 555},
+ [959] = {name = "vicious manbat", type = 554},
+ [960] = {name = "shadow pupil", type = 551},
+ [961] = {name = "blood priest", type = 553},
+ [962] = {name = "white shade", type = 560},
+ [963] = {name = "elder wyrm", type = 561},
+ [973] = {name = "nightfiend", type = 556},
+ [974] = {name = "blood hand", type = 552},
+ [975] = {name = "gravedigger", type = 558},
+ [976] = {name = "tarnished spirit", type = 566},
+ [978] = {name = "rorc", type = 550},
+ [979] = {name = "leaf golem", type = 567},
+ [980] = {name = "forest fury", type = 569},
+ [981] = {name = "roaring lion", type = 570},
+ [982] = {name = "wilting leaf golem", type = 573},
+ [1004] = {name = "shock head", type = 579},
+ [1012] = {name = "sight of surrender", type = 583},
+ [1013] = {name = "guzzlemaw", type = 584},
+ [1014] = {name = "silencer", type = 585},
+ [1015] = {name = "choking fear", type = 586},
+ [1016] = {name = "terrorsleep", type = 587},
+ [1018] = {name = "retching horror", type = 588},
+ [1019] = {name = "demon outcast", type = 590},
+ [1021] = {name = "feversleep", type = 593},
+ [1022] = {name = "frazzlemaw", type = 594},
+ [1038] = {name = "glooth golem", type = 600},
+ [1039] = {name = "metal gargoyle", type = 601},
+ [1040] = {name = "blood beast", type = 602},
+ [1041] = {name = "rustheap golem", type = 603},
+ [1042] = {name = "glooth anemone", type = 604},
+ [1043] = {name = "walker", type = 605},
+ [1044] = {name = "moohtant", type = 607},
+ [1045] = {name = "minotaur amazon", type = 608},
+ [1046] = {name = "execowtioner", type = 609},
+ [1051] = {name = "mooh'tah warrior", type = 611},
+ [1052] = {name = "minotaur hunter", type = 612},
+ [1053] = {name = "worm priestess", type = 613},
+ [1054] = {name = "glooth blob", type = 614},
+ [1055] = {name = "rot elemental", type = 615},
+ [1056] = {name = "devourer", type = 617},
+ [1096] = {name = "seacrest serpent", type = 675},
+ [1097] = {name = "renegade quara constrictor", type = 46},
+ [1098] = {name = "renegade quara hydromancer", type = 47},
+ [1099] = {name = "renegade quara mantassin", type = 72},
+ [1100] = {name = "renegade quara pincher", type = 77},
+ [1101] = {name = "renegade quara predator", type = 20},
+ [1105] = {name = "abyssal calamary", type = 451},
+ [1109] = {name = "minotaur invader", type = 29},
+ [1116] = {name = "high voltage elemental", type = 293},
+ [1118] = {name = "noble lion", type = 570},
+ [1119] = {name = "glooth bandit", type = 129},
+ [1120] = {name = "glooth brigand", type = 137},
+ [1121] = {name = "raging fire", type = 242},
+ [1134] = {name = "dawnfire asura", type = 150},
+ [1135] = {name = "midnight asura", type = 150},
+ [1137] = {name = "tainted soul", type = 712},
+ [1138] = {name = "redeemed soul", type = 714},
+ [1139] = {name = "gloom wolf", type = 716},
+ [1141] = {name = "omnivora", type = 717},
+ [1142] = {name = "werebear", type = 720},
+ [1143] = {name = "wereboar", type = 721},
+ [1144] = {name = "werebadger", type = 729},
+ [1145] = {name = "vicious squire", type = 131},
+ [1146] = {name = "renegade knight", type = 268},
+ [1147] = {name = "vile grandmaster", type = 268},
+ [1148] = {name = "ghost wolf", type = 730},
+ [1161] = {name = "ogre brute", type = 857},
+ [1162] = {name = "ogre savage", type = 858},
+ [1163] = {name = "ogre shaman", type = 859},
+ [1174] = {name = "clomp", type = 860},
+ [1196] = {name = "grimeleech", type = 855},
+ [1197] = {name = "vexclaw", type = 854},
+ [1198] = {name = "hellflayer", type = 856},
+ [1224] = {name = "reality reaver", type = 879},
+ [1234] = {name = "sparkion", type = 877},
+ [1235] = {name = "breach brood", type = 878},
+ [1260] = {name = "dread intruder", type = 882},
+ [1264] = {name = "instable sparkion", type = 877},
+ [1265] = {name = "instable breach brood", type = 878},
+ [1266] = {name = "stabilizing reality reaver", type = 879},
+ [1267] = {name = "stabilizing dread intruder", type = 882},
+ [1307] = {name = "cave parrot", type = 217},
+ [1314] = {name = "orclops doomhauler", type = 934},
+ [1320] = {name = "orclops ravager", type = 935},
+ [1321] = {name = "broken shaper", type = 932},
+ [1322] = {name = "twisted shaper", type = 932},
+ [1325] = {name = "iron servant replica", type = 395},
+ [1326] = {name = "diamond servant replica", type = 397},
+ [1327] = {name = "golden servant replica", type = 396},
+ [1376] = {name = "haunted dragon", type = 231},
+ [1380] = {name = "ice dragon", type = 947},
+ [1394] = {name = "shaper matriarch", type = 933},
+ [1395] = {name = "stone rhino", type = 936},
+ [1412] = {name = "misguided bully", type = 159},
+ [1413] = {name = "misguided thief", type = 684},
+ [1415] = {name = "putrid mummy", type = 976},
+ [1434] = {name = "faun", type = 980},
+ [1435] = {name = "pooka", type = 977},
+ [1436] = {name = "twisted pooka", type = 978},
+ [1437] = {name = "swan maiden", type = 138},
+ [1438] = {name = "pixie", type = 982},
+ [1439] = {name = "boogy", type = 981},
+ [1442] = {name = "weakened frazzlemaw", type = 594},
+ [1443] = {name = "enfeebled silencer", type = 585},
+ [1481] = {name = "goldhanded cultist", type = 132},
+ [1485] = {name = "nymph", type = 989},
+ [1486] = {name = "barkless devotee", type = 990},
+ [1488] = {name = "barkless fanatic", type = 990},
+ [1496] = {name = "dark faun", type = 980},
+ [1503] = {name = "orc cultist", type = 7},
+ [1504] = {name = "orc cult priest", type = 6},
+ [1505] = {name = "orc cult inquisitor", type = 8},
+ [1506] = {name = "orc cult fanatic", type = 59},
+ [1507] = {name = "orc cult minion", type = 50},
+ [1508] = {name = "minotaur cult follower", type = 25},
+ [1509] = {name = "minotaur cult prophet", type = 23},
+ [1510] = {name = "minotaur cult zealot", type = 29},
+ [1512] = {name = "cult believer", type = 132},
+ [1513] = {name = "cult enforcer", type = 134},
+ [1514] = {name = "cult scholar", type = 145},
+ [1525] = {name = "stonerefiner", type = 1032},
+ [1529] = {name = "lost exile", type = 537},
+ [1531] = {name = "deepworm", type = 1033},
+ [1532] = {name = "diremaw", type = 1034},
+ [1544] = {name = "cave devourer", type = 1036},
+ [1545] = {name = "tunnel tyrant", type = 1035},
+ [1546] = {name = "chasm spawn", type = 1037},
+ [1548] = {name = "fox", type = 1029},
+ [1549] = {name = "werefox", type = 1030},
+ [1563] = {name = "lava lurker", type = 1041},
+ [1569] = {name = "ravenous lava lurker", type = 1041},
+ [1570] = {name = "mole", type = 1048},
+ [1619] = {name = "frost flower asura", type = 150},
+ [1620] = {name = "true dawnfire asura", type = 1068},
+ [1621] = {name = "true midnight asura", type = 1068},
+ [1622] = {name = "true frost flower asura", type = 1068},
+ [1626] = {name = "arctic faun", type = 980},
+ [1637] = {name = "floating savant", type = 1063},
+ [1646] = {name = "falcon knight", type = 1071},
+ [1647] = {name = "falcon paladin", type = 1071},
+ [1653] = {name = "brain squid", type = 1059},
+ [1654] = {name = "flying book", type = 1060},
+ [1655] = {name = "cursed book", type = 1061},
+ [1656] = {name = "biting book", type = 1066},
+ [1658] = {name = "ink blob", type = 1064},
+ [1659] = {name = "guardian of tales", type = 1063},
+ [1663] = {name = "burning book", type = 1061},
+ [1664] = {name = "icecold book", type = 1061},
+ [1665] = {name = "energetic book", type = 1061},
+ [1666] = {name = "energuardian of tales", type = 1063},
+ [1667] = {name = "deathling scout", type = 1073},
+ [1668] = {name = "rage squid", type = 1059},
+ [1669] = {name = "squid warden", type = 1059},
+ [1670] = {name = "knowledge elemental", type = 1065},
+ [1671] = {name = "animated feather", type = 1058},
+ [1674] = {name = "skeleton elite warrior", type = 298},
+ [1675] = {name = "undead elite gladiator", type = 306},
+ [1677] = {name = "deathling spellsinger", type = 1088},
+ [1721] = {name = "lumbering carnivor", type = 1133},
+ [1722] = {name = "spiky carnivor", type = 1139},
+ [1723] = {name = "menacing carnivor", type = 1138},
+ [1724] = {name = "ripper spectre", type = 1122},
+ [1725] = {name = "gazer spectre", type = 1122},
+ [1726] = {name = "burster spectre", type = 1122},
+ [1728] = {name = "thanatursus", type = 1134},
+ [1729] = {name = "arachnophobica", type = 1135},
+ [1730] = {name = "crazed winter vanguard", type = 1137},
+ [1731] = {name = "crazed winter rearguard", type = 1136},
+ [1732] = {name = "crazed summer vanguard", type = 1137},
+ [1733] = {name = "crazed summer rearguard", type = 1136},
+ [1734] = {name = "soul-broken harbinger", type = 1137},
+ [1735] = {name = "insane siren", type = 1136},
+ [1736] = {name = "lacewing moth", type = 1148},
+ [1737] = {name = "hibernal moth", type = 1149},
+ [1740] = {name = "percht", type = 1161},
+ [1741] = {name = "schiach", type = 1162},
+ [1742] = {name = "baleful bunny", type = 1157},
+ [1751] = {name = "animated snowman", type = 1159},
+ [1775] = {name = "cobra assassin", type = 1217},
+ [1776] = {name = "cobra scout", type = 1217},
+ [1798] = {name = "burning gladiator", type = 541},
+ [1799] = {name = "priestess of the wild sun", type = 1199},
+ [1800] = {name = "black sphinx acolyte", type = 1200},
+ [1805] = {name = "crypt warden", type = 1190},
+ [1806] = {name = "lamassu", type = 1190},
+ [1807] = {name = "feral sphinx", type = 1188},
+ [1808] = {name = "sphinx", type = 1188},
+ [1816] = {name = "manticore", type = 1189},
+ [1817] = {name = "young goanna", type = 1196},
+ [1818] = {name = "adult goanna", type = 1195},
+ [1819] = {name = "gryphon", type = 1220},
+ [1820] = {name = "ogre ruffian", type = 1212},
+ [1821] = {name = "ogre rowdy", type = 1213},
+ [1822] = {name = "ogre sage", type = 1214},
+ [1824] = {name = "cobra vizier", type = 1217},
+ [1864] = {name = "flimsy lost soul", type = 1268},
+ [1865] = {name = "mean lost soul", type = 1268},
+ [1866] = {name = "freakish lost soul", type = 1268},
+ [1880] = {name = "cursed prospector", type = 1268},
+ [1885] = {name = "evil prospector", type = 1268},
+ [1926] = {name = "bony sea devil", type = 1294},
+ [1927] = {name = "many faces", type = 1296},
+ [1928] = {name = "cloak of terror", type = 1295},
+ [1929] = {name = "vibrant phantom", type = 1298},
+ [1930] = {name = "brachiodemon", type = 1299},
+ [1931] = {name = "branchy crawler", type = 1297},
+ [1932] = {name = "capricious phantom", type = 1298},
+ [1933] = {name = "infernal phantom", type = 1298},
+ [1938] = {name = "infernal demon", type = 1313},
+ [1939] = {name = "rotten golem", type = 1312},
+ [1940] = {name = "turbulent elemental", type = 1314},
+ [1941] = {name = "courage leech", type = 1315},
+ [1945] = {name = "mould phantom", type = 1298},
+ [1946] = {name = "druid's apparition", type = 148},
+ [1947] = {name = "knight's apparition", type = 131},
+ [1948] = {name = "paladin's apparition", type = 129},
+ [1949] = {name = "sorcerer's apparition", type = 138},
+ [1962] = {name = "distorted phantom", type = 1298},
+ [1963] = {name = "werehyaena", type = 1300},
+ [1964] = {name = "werehyaena shaman", type = 1300},
+ [1965] = {name = "werelion", type = 1301},
+ [1966] = {name = "werelioness", type = 1301},
+ [1967] = {name = "white lion", type = 1290},
+ [1972] = {name = "usurper knight", type = 1316},
+ [1973] = {name = "usurper archer", type = 1316},
+ [1974] = {name = "usurper warlock", type = 1316},
+ [1979] = {name = "agrestic chicken", type = 111},
+ [2024] = {name = "exotic cave spider", type = 1344},
+ [2036] = {name = "pirat cutthroat", type = 1346},
+ [2037] = {name = "pirat scoundrel", type = 1346},
+ [2038] = {name = "pirat bombardier", type = 1346},
+ [2039] = {name = "pirat mate", type = 1346},
+ [2051] = {name = "exotic bat", type = 1373},
+ [2088] = {name = "lavaworm", type = 1394},
+ [2089] = {name = "tremendous tyrant", type = 1396},
+ [2090] = {name = "varnished diremaw", type = 1397},
+ [2091] = {name = "streaked devourer", type = 1398},
+ [2092] = {name = "eyeless devourer", type = 1399},
+ [2093] = {name = "blemished spawn", type = 1401},
+ [2094] = {name = "afflicted strider", type = 1403},
+ [2095] = {name = "lavafungus", type = 1405},
+ [2096] = {name = "cave chimera", type = 1406},
+ [2098] = {name = "venerable girtablilu", type = 1407},
+ [2099] = {name = "girtablilu warrior", type = 1407},
+ [2100] = {name = "bashmu", type = 1408},
+ [2101] = {name = "juvenile bashmu", type = 1408},
+ [2107] = {name = "hulking carnisylvan", type = 1418},
+ [2108] = {name = "poisonous carnisylvan", type = 1418},
+ [2109] = {name = "dark carnisylvan", type = 1418},
+ [2256] = {name = "parder", type = 1533},
+ [2257] = {name = "jungle moa", type = 1534},
+ [2258] = {name = "two-headed turtle", type = 1535},
+ [2259] = {name = "foam stalker", type = 1562},
+ [2260] = {name = "naga archer", type = 1537},
+ [2261] = {name = "naga warrior", type = 1539},
+ [2262] = {name = "makara", type = 1565},
+ [2264] = {name = "sulphider", type = 1546},
+ [2265] = {name = "sulphur spouter", type = 1547},
+ [2266] = {name = "gore horn", type = 1548},
+ [2267] = {name = "sabretooth", type = 1549},
+ [2268] = {name = "emerald tortoise", type = 1550},
+ [2269] = {name = "undertaker", type = 1551},
+ [2270] = {name = "nighthunter", type = 1552},
+ [2271] = {name = "hulking prehemoth", type = 1553},
+ [2272] = {name = "stalking stalk", type = 1554},
+ [2274] = {name = "mantosaurus", type = 1556},
+ [2275] = {name = "headpecker", type = 1557},
+ [2276] = {name = "noxious ripptor", type = 1558},
+ [2277] = {name = "gorerilla", type = 1559},
+ [2278] = {name = "shrieking cry-stal", type = 1560},
+ [2279] = {name = "mercurial menace", type = 1561},
+ [2337] = {name = "crape man", type = 1601},
+ [2338] = {name = "liodile", type = 1602},
+ [2339] = {name = "boar man", type = 1603},
+ [2340] = {name = "harpy", type = 1604},
+ [2341] = {name = "carnivostrich", type = 1605},
+ [2342] = {name = "rhindeer", type = 1606},
+ [2343] = {name = "iks pututu", type = 1589},
+ [2344] = {name = "iks aucar", type = 1587},
+ [2345] = {name = "iks chuka", type = 1588},
+ [2347] = {name = "cursed ape", type = 1592},
+ [2349] = {name = "iks ahpututu", type = 1590},
+ [2350] = {name = "iks churrascan", type = 1587},
+ [2386] = {name = "weretiger", type = 1646},
+ [2387] = {name = "white weretiger", type = 1646},
+ [2389] = {name = "feral werecrocodile", type = 1647},
+ [2390] = {name = "werepanther", type = 1648},
+ [2391] = {name = "white tiger", type = 1649},
+ [2403] = {name = "werecrocodile", type = 1647},
+}
+
+RACE_Bosstiary = {
+ [46] = {name = "black knight", type = 131},
+ [84] = {name = "morguthis", type = 84},
+ [85] = {name = "vashresamun", type = 85},
+ [86] = {name = "mahrdis", type = 86},
+ [87] = {name = "dipthrah", type = 87},
+ [88] = {name = "rahemos", type = 88},
+ [89] = {name = "thalas", type = 89},
+ [90] = {name = "omruc", type = 90},
+ [91] = {name = "ashmunrah", type = 91},
+ [201] = {name = "orshabaal", type = 201},
+ [203] = {name = "dharalion", type = 203},
+ [205] = {name = "grorlam", type = 205},
+ [207] = {name = "general murius", type = 611},
+ [210] = {name = "the evil eye", type = 210},
+ [229] = {name = "morgaroth", type = 12},
+ [231] = {name = "ferumbras", type = 229},
+ [300] = {name = "the plasmother", type = 238},
+ [301] = {name = "the handmaiden", type = 230},
+ [302] = {name = "dracola", type = 231},
+ [303] = {name = "mr. punish", type = 234},
+ [304] = {name = "the imperor", type = 237},
+ [305] = {name = "massacre", type = 244},
+ [306] = {name = "countess sorrow", type = 241},
+ [312] = {name = "ghazbaran", type = 12},
+ [336] = {name = "yakchal", type = 149},
+ [338] = {name = "man in the cave", type = 128},
+ [373] = {name = "the abomination", type = 1393},
+ [403] = {name = "hellgorak", type = 12},
+ [414] = {name = "madareth", type = 12},
+ [415] = {name = "ushuriel", type = 12},
+ [416] = {name = "golgordan", type = 12},
+ [417] = {name = "latrivan", type = 12},
+ [418] = {name = "annihilon", type = 12},
+ [419] = {name = "warlord ruzad", type = 2},
+ [420] = {name = "the frog prince", type = 224},
+ [421] = {name = "zarabustor", type = 130},
+ [424] = {name = "foreman kneebiter", type = 70},
+ [425] = {name = "hairman the huge", type = 116},
+ [426] = {name = "gravelord oshuran", type = 99},
+ [427] = {name = "yaga the crone", type = 54},
+ [428] = {name = "xenia", type = 137},
+ [430] = {name = "captain jones", type = 196},
+ [431] = {name = "grandfather tridian", type = 193},
+ [432] = {name = "big boss trolliver", type = 281},
+ [434] = {name = "zugurosh", type = 12},
+ [435] = {name = "rukor zad", type = 152},
+ [436] = {name = "smuggler baron silvertoe", type = 134},
+ [440] = {name = "barbaria", type = 264},
+ [454] = {name = "lord of the elements", type = 243},
+ [459] = {name = "rotworm queen", type = 295},
+ [466] = {name = "the mutated pumpkin", type = 292},
+ [475] = {name = "zevelon duskbringer", type = 287},
+ [476] = {name = "sir valorcrest", type = 287},
+ [477] = {name = "diblis the fair", type = 287},
+ [478] = {name = "arachir the ancient one", type = 287},
+ [484] = {name = "diseased fred", type = 299},
+ [485] = {name = "diseased bill", type = 299},
+ [486] = {name = "diseased dan", type = 299},
+ [564] = {name = "doctor perhaps", type = 133},
+ [565] = {name = "dirtbeard", type = 98},
+ [566] = {name = "mephiles", type = 237},
+ [567] = {name = "boogey", type = 300},
+ [568] = {name = "monstor", type = 244},
+ [569] = {name = "evil mastermind", type = 256},
+ [628] = {name = "zulazza the corruptor", type = 334},
+ [629] = {name = "chizzoron the distorter", type = 340},
+ [635] = {name = "battlemaster zunzu", type = 343},
+ [636] = {name = "the voice of ruin", type = 344},
+ [638] = {name = "the blightfather", type = 348},
+ [639] = {name = "dreadmaw", type = 358},
+ [640] = {name = "fleabringer", type = 341},
+ [642] = {name = "grand mother foulscale", type = 34},
+ [647] = {name = "chikhaton", type = 361},
+ [670] = {name = "glitterscale", type = 34},
+ [671] = {name = "heoni", type = 239},
+ [703] = {name = "mad mage", type = 394},
+ [713] = {name = "horestis", type = 91},
+ [718] = {name = "raging mage", type = 416},
+ [736] = {name = "groam", type = 413},
+ [763] = {name = "jesse the wicked", type = 134},
+ [764] = {name = "robby the reckless", type = 129},
+ [765] = {name = "mornenion", type = 64},
+ [766] = {name = "elvira hammerthrust", type = 70},
+ [773] = {name = "jaul", type = 444},
+ [774] = {name = "obujos", type = 445},
+ [775] = {name = "tanjis", type = 446},
+ [858] = {name = "fleshslicer", type = 457},
+ [887] = {name = "abyssador", type = 495},
+ [892] = {name = "deathstrike", type = 500},
+ [893] = {name = "gnomevil", type = 504},
+ [900] = {name = "bibby bloodbath", type = 2},
+ [955] = {name = "willi wasp", type = 44},
+ [956] = {name = "zomba", type = 570},
+ [964] = {name = "the welter", type = 563},
+ [965] = {name = "white pale", type = 564},
+ [966] = {name = "tyrn", type = 562},
+ [967] = {name = "hirintror", type = 261},
+ [969] = {name = "zushuka", type = 149},
+ [970] = {name = "ocyakao", type = 259},
+ [972] = {name = "the pale count", type = 557},
+ [987] = {name = "furyosa", type = 149},
+ [1003] = {name = "gaz'haragoth", type = 591},
+ [1011] = {name = "omrafir", type = 12},
+ [1028] = {name = "mawhawk", type = 595},
+ [1035] = {name = "the ravager", type = 91},
+ [1047] = {name = "death priest shargon", type = 278},
+ [1058] = {name = "glooth fairy", type = 600},
+ [1059] = {name = "lisa", type = 604},
+ [1060] = {name = "bullwark", type = 607},
+ [1087] = {name = "deep terror", type = 676},
+ [1093] = {name = "professor maxxen", type = 679},
+ [1140] = {name = "ekatrix", type = 54},
+ [1149] = {name = "feroxa", type = 158},
+ [1165] = {name = "the shatterer", type = 842},
+ [1177] = {name = "razzagorn", type = 842},
+ [1179] = {name = "the lord of the lice", type = 305},
+ [1180] = {name = "ragiaz", type = 862},
+ [1181] = {name = "zamulosh", type = 862},
+ [1186] = {name = "mazoran", type = 842},
+ [1188] = {name = "tarbaz", type = 842},
+ [1191] = {name = "shulgrax", type = 842},
+ [1199] = {name = "plagirath", type = 862},
+ [1204] = {name = "ferumbras mortal shell", type = 229},
+ [1218] = {name = "realityquake", type = 0},
+ [1219] = {name = "anomaly", type = 876},
+ [1225] = {name = "rupture", type = 875},
+ [1226] = {name = "eradicator", type = 875},
+ [1227] = {name = "outburst", type = 876},
+ [1228] = {name = "world devourer", type = 875},
+ [1289] = {name = "soul of dragonking zyrtarch", type = 938},
+ [1290] = {name = "the time guardian", type = 945},
+ [1297] = {name = "the enraged thorn knight", type = 512},
+ [1304] = {name = "the last lore keeper", type = 939},
+ [1315] = {name = "lady tenebris", type = 433},
+ [1329] = {name = "lloyd", type = 940},
+ [1336] = {name = "melting frozen horror", type = 261},
+ [1368] = {name = "the first dragon", type = 947},
+ [1375] = {name = "zorvorax", type = 928},
+ [1379] = {name = "gelidrazah the frozen", type = 947},
+ [1389] = {name = "kalyassa", type = 947},
+ [1390] = {name = "tazhadur", type = 947},
+ [1406] = {name = "the unarmored voidborn", type = 987},
+ [1409] = {name = "the false god", type = 984},
+ [1422] = {name = "the souldespoiler", type = 875},
+ [1427] = {name = "ravenous hunger", type = 556},
+ [1444] = {name = "the sandking", type = 1013},
+ [1487] = {name = "essence of malice", type = 351},
+ [1500] = {name = "the source of corruption", type = 979},
+ [1515] = {name = "kroazur", type = 842},
+ [1518] = {name = "the baron from below", type = 1045},
+ [1519] = {name = "the count of the core", type = 1046},
+ [1520] = {name = "the duke of the depths", type = 1047},
+ [1551] = {name = "ancient spawn of morgathla", type = 1055},
+ [1558] = {name = "darkfang", type = 308},
+ [1559] = {name = "black vixen", type = 1038},
+ [1560] = {name = "bloodback", type = 1039},
+ [1561] = {name = "shadowpelt", type = 1040},
+ [1562] = {name = "sharpclaw", type = 1031},
+ [1574] = {name = "lokathmor", type = 1062},
+ [1576] = {name = "grand master oberon", type = 1072},
+ [1577] = {name = "jailer", type = 298},
+ [1578] = {name = "dazed leaf golem", type = 573},
+ [1579] = {name = "grand chaplain gaunder", type = 1071},
+ [1582] = {name = "grand commander soeren", type = 1071},
+ [1583] = {name = "preceptor lazare", type = 1078},
+ [1584] = {name = "grand canon dominus", type = 1071},
+ [1585] = {name = "thawing dragon lord", type = 1077},
+ [1591] = {name = "gorzindel", type = 1062},
+ [1598] = {name = "the diamond blossom", type = 1068},
+ [1600] = {name = "the blazing rose", type = 1068},
+ [1602] = {name = "the lily of night", type = 1068},
+ [1605] = {name = "mazzinor", type = 1062},
+ [1608] = {name = "ghulosh", type = 1062},
+ [1624] = {name = "raxias", type = 980},
+ [1642] = {name = "the scourge of oblivion", type = 875},
+ [1645] = {name = "brokul", type = 1076},
+ [1695] = {name = "plagueroot", type = 1121},
+ [1696] = {name = "malofur mangrinder", type = 1120},
+ [1697] = {name = "maxxenius", type = 1142},
+ [1698] = {name = "alptramun", type = 1143},
+ [1699] = {name = "izcandar the banished", type = 1137},
+ [1718] = {name = "the nightmare beast", type = 1144},
+ [1727] = {name = "faceless bane", type = 1119},
+ [1744] = {name = "the percht queen", type = 0},
+ [1753] = {name = "count vlarkorth", type = 1221},
+ [1754] = {name = "sir nictros", type = 1222},
+ [1755] = {name = "sir baeloc", type = 1222},
+ [1756] = {name = "lord azaram", type = 1223},
+ [1757] = {name = "earl osam", type = 1223},
+ [1758] = {name = "duke krule", type = 1221},
+ [1770] = {name = "custodian", type = 1217},
+ [1778] = {name = "gaffir", type = 1217},
+ [1784] = {name = "king zelos", type = 1224},
+ [1791] = {name = "guard captain quaid", type = 1217},
+ [1804] = {name = "scarlett etzel", type = 1201},
+ [1811] = {name = "wisdom of urmahlullu", type = 1200},
+ [1827] = {name = "xogixath", type = 842},
+ [1828] = {name = "bragrumol", type = 856},
+ [1829] = {name = "mozradek", type = 240},
+ [1862] = {name = "brain head", type = 0},
+ [1868] = {name = "the unwelcome", type = 1277},
+ [1872] = {name = "the dread maiden", type = 1278},
+ [1873] = {name = "the fear feaster", type = 1276},
+ [1881] = {name = "the pale worm", type = 1272},
+ [1890] = {name = "irgix the flimsy", type = 1268},
+ [1891] = {name = "unaz the mean", type = 1268},
+ [1892] = {name = "vok the freakish", type = 1268},
+ [1901] = {name = "goshnar's malice", type = 1306},
+ [1902] = {name = "goshnar's cruelty", type = 1303},
+ [1903] = {name = "goshnar's spite", type = 1305},
+ [1904] = {name = "goshnar's hatred", type = 1307},
+ [1905] = {name = "goshnar's greed", type = 1304},
+ [1957] = {name = "drume", type = 1317},
+ [1969] = {name = "goshnar's megalomania", type = 1308},
+ [1981] = {name = "katex blood tongue", type = 1300},
+ [1982] = {name = "yirkas blue scales", type = 1196},
+ [1983] = {name = "srezz yellow eyes", type = 220},
+ [1984] = {name = "utua stone sting", type = 398},
+ [2006] = {name = "ratmiral blackwhiskers", type = 1377},
+ [2055] = {name = "the brainstealer", type = 1412},
+ [2103] = {name = "amenef the burning", type = 541},
+ [2104] = {name = "sister hetai", type = 1199},
+ [2105] = {name = "neferi the spy", type = 149},
+ [2114] = {name = "megasylvan yselda", type = 0},
+ [2118] = {name = "morshabaal", type = 1468},
+ [2238] = {name = "tentugly's head", type = 0},
+ [2242] = {name = "magma bubble", type = 1413},
+ [2250] = {name = "timira the many-headed", type = 1542},
+ [2299] = {name = "the monster", type = 1600},
+ [2346] = {name = "ahau", type = 1591},
+}
+
+ACHIEVEMENTS = {
+ [1] = { name = "Castlemania", grade = 2, points = 5, secret = true, description = "You have an eye for suspicious places and love to read other people's diaries, especially those with vampire stories in it. You're also a dedicated token collector and explorer. Respect!" },
+ [2] = { name = "Chorister", grade = 1, points = 1, description = "Lalalala... you now know the cult's hymn sung in Liberty Bay by heart. Not that hard, considering that it mainly consists of two notes and repetitive lyrics." },
+ [3] = { name = "The Milkman", grade = 1, points = 2, description = "Who's the milkman? You are!" },
+ [4] = { name = "Vive la Resistance", grade = 1, points = 2, description = "You've always been a rebel - admit it! Supplying prisoners, caring for outcasts, stealing from the rich and giving to the poor - no wait, that was another story." },
+ [5] = { name = "Culinary Master", grade = 2, points = 4, description = "Simple hams and bread merely make you laugh. You're the master of the extra-ordinaire, melter of cheese, fryer of bat wings and shaker of shakes. Delicious!" },
+ [6] = { name = "Shell Seeker", grade = 1, points = 3, secret = true, description = "You found a hundred beautiful pearls in large sea shells. By now that necklace should be finished - and hopefully you didn't get your fingers squeezed too often during the process." },
+ [7] = { name = "Backpack Tourist", grade = 1, points = 1, secret = true, description = "If someone lost a random thing in a random place, you're probably a good person to ask and go find it, even if you don't know what and where." },
+ [8] = { name = "Dread Lord", grade = 3, points = 8, secret = true, description = "You don't care for rules that others set up and shape the world to your liking. Having left behind meaningless conventions and morals, you prize only the power you wield. You're a master of your fate and battle to cleanse the world." },
+ [9] = { name = "Lord Protector", grade = 3, points = 8, secret = true, description = "You proved yourself - not only in your dreams - and possess a strong and spiritual mind. Your valorous fight against demons and the undead plague has granted you the highest and most respected rank among the Nightmare Knights." },
+ [10] = { name = "Nightmare Knight", grade = 1, points = 1, description = "You follow the path of dreams and that of responsibility without self-centered power. Free from greed and selfishness, you help others without expecting a reward." },
+ [11] = { name = "Bone Brother", grade = 1, points = 1, description = "You've joined the undead bone brothers - making death your enemy and your weapon as well. Devouring what's weak and leaving space for what's strong is your primary goal." },
+ [12] = { name = "Blessed!", grade = 1, points = 2, description = "You travelled the world for an almost meaningless prayer - but at least you don't have to do that again and can get a new blessed stake in the blink of an eye." },
+ [13] = { name = "Recognised Trader", grade = 1, points = 3, description = "You're a talented merchant who's able to handle wares with care, finds good offers and digs up rares every now and then. Never late to complete an order, you're a reliable trader - at least in Rashid's eyes." },
+ [14] = { name = "Fountain of Life", grade = 1, points = 1, secret = true, description = "You found and took a sip from the Fountain of Life. Thought it didn't grant you eternal life, you feel changed and somehow at peace." },
+ [15] = { name = "Lord of the Elements", grade = 2, points = 5, description = "You travelled the surreal realm of the elemental spheres, summoned and slayed the Lord of the Elements, all in order to retrieve neutral matter. And as brave as you were, you couldn't have done it without your team!" },
+ [16] = { name = "Beach Tamer", grade = 1, points = 2, description = "You re-enacted the Taming of the Shrew on a beach setting and proved that you can handle capricious girls quite well. With or without fish tails." },
+ [17] = { name = "Follower of Azerus", grade = 2, points = 4, description = "When you do something, you do it right. You have an opinion and you stand by it - and no one will be able to convince you otherwise. On a sidenote, you're a bit on the brutal and war-oriented side, but that's not a bad thing, is it?" },
+ [18] = { name = "Follower of Palimuth", grade = 2, points = 4, description = "You're a peacekeeper and listen to what the small people have to say. You've made up your mind and know who to help and for which reasons - and you do it consistently. Your war is fought with reason rather than weapons." },
+ [19] = { name = "Elite Hunter", grade = 2, points = 5, description = "You jump at every opportunity for a hunting challenge that's offered to you and carry out those tasks with deadly precision. You're a hunter at heart and a valuable member of the Paw & Fur Society." },
+ [20] = { name = "Huntsman", grade = 1, points = 2, description = "You're familiar with hunting tasks and have carried out quite a few already. A bright career as hunter for the Paw & Fur society lies ahead!" },
+ [21] = { name = "Passionate Kisser", grade = 1, points = 3, description = "For you, a kiss is more than a simple touch of lips. You kiss maidens and deadbeats alike with unmatched affection and faced death and rebirth through the kiss of the banshee queen. Lucky are those who get to share such an intimate moment with you!" },
+ [22] = { name = "Top AVIN Agent", grade = 2, points = 4, description = "You've proven yourself as a worthy member of the 'family' and successfully carried out numerous spy missions for your 'uncle' to support the Venorean traders and their goals." },
+ [23] = { name = "Top CGB Agent", grade = 2, points = 4, description = "Girl power! Whether you're female or not, you've proven absolute loyalty and the willingness to put your life at stake for the girls brigade of Carlin." },
+ [24] = { name = "Top TBI Agent", grade = 2, points = 4, description = "Conspiracies and open secrets are your daily bread. You've shown loyalty to the Thaian crown through your courage when facing enemies and completing spy missions. You're an excellent field agent of the TBI." },
+ [25] = { name = "Secret Agent", grade = 1, points = 1, description = "Pack your spy gear and get ready for some dangerous missions in service of a secret agency. You've shown you want to - but can you really do it? Time will tell." },
+ [26] = { name = "Golem in the Gears", grade = 2, points = 4, description = "You're an aspiring mago-mechanic. Science and magic work well together in your eyes - and even though you probably delivered countless wrong charges while working for Telas, you might just have enough knowledge to build your own golem now." },
+ [27] = { name = "Poet Laureate", grade = 1, points = 2, secret = true, description = "Poems, verses, songs and rhymes you've recited many times. You have passed the cryptic door, raconteur of ancient lore. Even elves you've left impressed, so it seems you're truly blessed." },
+ [28] = { name = "Minstrel", grade = 1, points = 2, secret = true, description = "You can handle any music instrument you're given - and actually manage to produce a pleasant sound with it. You're a welcome guest and entertainer in most taverns." },
+ [29] = { name = "Friend of the Apes", grade = 2, points = 4, description = "You know Banuta like the back of your hand and are good at destroying caskets and urns. The sight of giant footprints doesn't keep you from exploring unknown areas either." },
+ [30] = { name = "Territorial", grade = 1, points = 1, secret = true, description = "Your map is your friend — always in your back pocket and covered with countless marks of interesting and useful locations. One could say that you might be lost without it — but luckily there's no way to take it from you." },
+ [31] = { name = "Marid Ally", grade = 1, points = 3, description = "You've proven to be a valuable ally to the Marid, and Gabel welcomed you to trade with Haroun and Nah'Bob whenever you want to. Though the Djinn war has still not ended, the Marid can't fail with you on their side." },
+ [32] = { name = "Efreet Ally", grade = 1, points = 3, description = 'Even though the Efreet welcomed you only reluctantly and viewed you as "only a human" for quite some time, you managed to impress Malor and gained his respect and trade options with the green djinns.' },
+ [33] = { name = "Lucid Dreamer", grade = 1, points = 2, description = "Dreams - are your reality? Strange visions, ticking clocks, going to bed and waking up somewhere completely else - that was some trip, but you're almost sure you actually did enjoy it." },
+ [34] = { name = "Explorer", grade = 2, points = 4, description = "You've been to places most people don't even know the names of. Collecting botanic, zoologic and ectoplasmic samples is your daily business and you're always prepared to discover new horizons." },
+ [35] = { name = "Sea Scout", grade = 1, points = 2, description = "Not even the hostile underwater environment stops you from doing your duty for the Explorer Society. Scouting the Quara realm is a piece of cake for you." },
+ [36] = { name = "Unlikely Pathfinder", grade = 1, points = 2, secret = true, description = "Wow - what was that? You don't know how you ended up here, but somehow you did. How to get from Beregar to Kazordoon in a jiffy - that's something those dwarves would love to know, but you're not quite sure how to reproduce it." },
+ [37] = { name = "Bearhugger", grade = 1, points = 1, description = "Warm, furry and cuddly - though that same bear you just hugged would probably rip you into pieces if he had been conscious, he reminded you of that old teddy bear which always slept in your bed when you were still small." },
+ [38] = { name = "Ghostwhisperer", grade = 1, points = 3, description = "You don't hunt them, you talk to them. You know that ghosts might keep secrets that have been long lost among the living, and you're skilled at talking them into revealing them to you." },
+ [39] = { name = "Animal Activist", grade = 1, points = 2, description = "You have a soft spot for little, weak animals, and you do everything in your power to protect them - even if you probably eat dragons for breakfast." },
+ [40] = { name = "Honorary Barbarian", grade = 1, points = 1, description = "You've hugged bears, pushed mammoths and proved your drinking skills. And even though you have a slight hangover, a partially fractured rib and some greasy hair on your tongue, you're quite proud to call yourself a honorary barbarian from now on." },
+ [41] = { name = "High Inquisitor", grade = 2, points = 5, description = "You're the one who poses the questions around here, and you know how to get the answers you want to hear. Besides, you're a famous exorcist and slay a few vampires and demons here and there. You and your stake are a perfect team." },
+ [42] = { name = "Worm Whacker", grade = 1, points = 1, secret = true, description = "Weehee! Whack those worms! You sure know how to handle a big hammer." },
+ [43] = { name = "King Tibianus Fan", grade = 1, points = 3, description = "You're not sure what it is, but you feel drawn to royalty. Your knees are always a bit grazed from crawling around in front of thrones and you love hanging out in castles. Maybe you should consider applying as a guard?" },
+ [44] = { name = "Just in Time", grade = 1, points = 1, description = "You're a fast runner and are good at delivering wares which are bound to decay just in the nick of time, even if you can't use any means of transportation or if your hands get cold or smelly in the process." },
+ [45] = { name = "Perfect Fool", grade = 1, points = 3, description = "You love playing jokes on others and tricking them into looking a little silly. Wagging tongues say that the moment of realisation in your victims' eyes is the reward you feed on, but you're probably just kidding and having fun with them... right??" },
+ [46] = { name = "Mathemagician", grade = 1, points = 1, description = "Sometimes the biggest secrets of life can have a simple solution." },
+ [47] = { name = "Archpostman", grade = 1, points = 3, description = "Delivering letters and parcels has always been a secret passion of yours, and now you can officially put on your blue hat, blow your post horn and do what you like to do most. Beware of dogs!" },
+ [48] = { name = "Matchmaker", grade = 1, points = 1, description = "You don't believe in romance to be a coincidence or in love at first sight. In fact - love potions, bouquets of flowers and cheesy poems do the trick much better than ever could. Keep those hormones flowing!" },
+ [49] = { name = "His True Face", grade = 1, points = 3, secret = true, description = "You're one of the few Tibians who Armenius chose to actually show his true face to - and he made you fight him. Either that means you're very lucky or very unlucky, but one thing's for sure - it's extremely rare." },
+ [50] = { name = "Razing!", grade = 3, points = 7, secret = true, description = "People with sharp canine teeth better beware of you, especially at nighttime, or they might find a stake between their ribs. You're a merciless vampire hunter and have gathered numerous tokens as proof." },
+ [51] = { name = "Master Thief", grade = 2, points = 4, description = "Robbing, inviting yourself to VIP parties, faking contracts and pretending to be someone else - you're a jack of all trades when it comes to illegal activities. You take no prisoners, except for the occasional goldfish now and then." },
+ [52] = { name = "Amateur Actor", grade = 1, points = 2, description = "You helped bringing Princess Buttercup, Doctor Dumbness and Lucky the Wonder Dog to life - and will probably dream of them tonight, since you memorised your lines perfectly. What a .. special piece of.. screenplay." },
+ [53] = { name = "Scrapper", grade = 1, points = 3, description = "You put out the Spirit of Fire's flames in the arena of Svargrond. Arena fights are for you - fair, square, with simple rules and one-on-one battles." },
+ [54] = { name = "Greenhorn", grade = 1, points = 2, description = "You wiped out Orcus the Cruel in the Arena of Svargrond. You're still a bit green behind the ears, but there's some great potential." },
+ [55] = { name = "Warlord of Svargrond", grade = 2, points = 5, description = "You sent the Obliverator into oblivion in the arena of Svargrond and defeated nine other dangerous enemies on the way. All hail the Warlord of Svargrond!" },
+ [56] = { name = "Herbicide", grade = 3, points = 8, secret = true, description = "You're one of the brave heroes to face and defeat the mysterious demon oak and all the critters it threw in your face. Wielding your blessed axe no tree dares stand in your way - demonic or not." },
+ [57] = { name = "Annihilator", grade = 2, points = 5, description = "You've daringly jumped into the infamous Annihilator and survived - taking home fame, glory and your reward." },
+ [58] = { name = "Master of the Nexus", grade = 2, points = 6, description = "You were able to fight your way through the countless hordes in the Demon Forge. Once more you proved that nothing is impossible." },
+ [59] = { name = "Talented Dancer", grade = 1, points = 1, description = "You're a lord or lady of the dance - and not afraid to use your skills to impress tribal gods. One step to the left, one jump to the right, twist and shout!" },
+ [60] = { name = "Allow Cookies?", grade = 1, points = 2, description = "With a perfectly harmless smile, you tricked all the funny guys into eating your exploding cookies. Next time you pull this prank, consider wearing a Boy Scout outfit to make it even better." },
+ [61] = { name = "Ruthless", grade = 2, points = 5, description = "You've touched all thrones of the Ruthless Seven and absorbed some of their evil spirit. It may have changed you forever." },
+ [62] = { name = "Champion of Chazorai", grade = 2, points = 4, description = "You won the merciless 2 vs. 2 team tournament on the Isle of Strife and wiped out wave after wave of fearsome opponents. Death or victory - you certainly chose the latter." },
+ [63] = { name = "Wayfarer", grade = 1, points = 3, secret = true, description = "Dragon dreams are golden." },
+ [64] = { name = "Waverider", grade = 1, points = 2, secret = true, description = "One thing's for sure: You definitely love swimming. Hanging out on the beach with your friends, having ice cream and playing beach ball is splashingly good fun!" },
+ [65] = { name = "Rockstar", grade = 1, points = 3, secret = true, description = "Music just comes to you naturally. You feel comfortable on any stage, at any time, and secretly hope that someday you will be able to defeat your foes by playing music only. Rock on!" },
+ [66] = { name = "Allowance Collector", grade = 1, points = 2, secret = true, description = "You certainly have your ways when it comes to acquiring money. Many of them are pink and paved with broken fragments of porcelain." },
+ [67] = { name = "High-Flyer", grade = 2, points = 4, secret = true, description = "The breeze in your hair, your fingers clutching the rim of your carpet - that's how you like to travel. Faster! Higher! And a looping every now and then." },
+ [68] = { name = "Clay Fighter", grade = 1, points = 3, secret = true, description = "You love getting your hands wet and dirty - and covered with clay. Your perfect sculpture of Brog, the raging Titan is your true masterpiece." },
+ [69] = { name = "Masquerader", grade = 1, points = 3, secret = true, description = "You probably don't know anymore how you really look like - usually when you look into a mirror, some kind of monster stares back at you. On the other hand - maybe that's an improvement?" },
+ [70] = { name = "Deep Sea Diver", grade = 2, points = 4, secret = true, description = "Under the sea - might not be your natural living space, but you're feeling quite comfortable on the ocean floor. Quara don't scare you anymore and sometimes you sleep with your helmet of the deep still equipped." },
+ [71] = { name = "Firewalker", grade = 2, points = 4, secret = true, description = "Running barefoot across ember is not for you! You do it the elegant way. Yet, you're kind of drawn to fire and warm surroundings in general - you like it hot!" },
+ [72] = { name = "Here, Fishy Fishy!", grade = 1, points = 1, secret = true, description = "Ah, the smell of the sea! Standing at the shore and casting a line is one of your favourite activities. For you, fishing is relaxing - and at the same time, providing easy food. Perfect!" },
+ [73] = { name = "Green Thumb", grade = 2, points = 4, secret = true, description = "If someone gives you seeds, you usually grow a beautiful plant from it within a few days. You like your house green and decorated with flowers. Probably you also talk to them." },
+ [74] = { name = "Potion Addict", grade = 2, points = 4, secret = true, description = "Your local magic trader considers you one of his best customers - you usually buy large stocks of potions so you won't wake up in the middle of the night craving for more. Yet, you always seem to run out of them too fast. Cheers!" },
+ [75] = { name = "Ice Sculptor", grade = 1, points = 3, secret = true, description = "You love to hang out in cold surroundings and consider ice the best material to be shaped. What a waste to use ice cubes for drinks when you can create a beautiful mammoth statue from it!" },
+ [76] = { name = "Interior Decorator", grade = 2, points = 4, secret = true, description = "Your home is your castle - and the furniture in it is just as important. Your friends ask for your advice when decorating their houses and your probably own every statue, rack and bed there is." },
+ [77] = { name = "Jinx", grade = 1, points = 2, secret = true, description = "Sometimes you feel there's a gremlin in there. So many lottery tickets, so many blanks? That's just not fair! Share your misery with the world." },
+ [78] = { name = "Lucky Devil", grade = 2, points = 4, secret = true, description = "That's almost too much luck for one person. If something's really, really rare - it probably falls into your lap sooner or later. Congratulations!" },
+ [79] = { name = "Marblelous", grade = 1, points = 3, secret = true, description = "You're an aspiring marble sculptor with promising skills - proven by the perfect little Tibiasula statue you shaped. One day you'll be really famous!" },
+ [80] = { name = "Party Animal", grade = 1, points = 1, secret = true, description = "Oh my god, it's a paaaaaaaaaaaarty! You're always in for fun, friends and booze and love being the center of attention. There's endless reasons to celebrate! Woohoo!" },
+ [81] = { name = "Fireworks in the Sky", grade = 1, points = 2, secret = true, description = "You love the moment right before your rocket takes off and explodes into beautiful colours - not only on new year's eve!" },
+ [82] = { name = "Quick as a Turtle", grade = 1, points = 2, secret = true, description = "There... is... simply... no... better... way - than to travel on the back of a turtle. At least you get to enjoy the beautiful surroundings of Laguna." },
+ [83] = { name = "Polisher", grade = 2, points = 4, secret = true, description = "If you see a rusty item, you can't resist polishing it. There's always a little flask of rust remover in your inventory – who knows, there might be a golden armor beneath all that dirt!" },
+ [84] = { name = "Ship's Kobold", grade = 2, points = 4, secret = true, description = "You’ve probably never gotten seasick in your life — you love spending your free time on the ocean and covered quite a lot of miles with ships. Aren’t you glad you didn’t have to swim all that?" },
+ [85] = { name = "Steampunked", grade = 1, points = 2, secret = true, description = "Travelling with the dwarven steamboats through the underground rivers is your preferred way of crossing the lands. No pesky seagulls, and good beer on board!" },
+ [86] = { name = "Vanity", grade = 1, points = 3, secret = true, description = "Aren't you just perfectly, wonderfully, beautifully gorgeous? You can't pass a mirror without admiring your looks. Or maybe doing a quick check whether something's stuck in your teeth, perhaps?" },
+ [87] = { name = "Superstitious", grade = 1, points = 2, secret = true, description = "Fortune tellers and horoscopes guide you through your life. And you probably wouldn't dare going on a big game hunt without your trusty voodoo skull giving you his approval for the day." },
+ [88] = { name = "Turncoat", grade = 2, points = 4, secret = true, description = "You served Yalahar - but you didn't seem so sure whom to believe on the way. Both Azerus and Palimuth had good reasons for their actions, and thus you followed your gut instinct in the end, even if you helped either of them. May Yalahar prosper!" },
+ [89] = { name = "Marble Madness", grade = 2, points = 6, secret = true, description = "Your little statues of Tibiasula have become quite famous around Tibia and there's few people with similar skills when it comes to shaping marble." },
+ [90] = { name = "Clay to Fame", grade = 2, points = 6, secret = true, description = "Sculpting Brog, the raging Titan, is your secret passion. Numerous perfect little clay statues with your name on them can be found everywhere around Tibia." },
+ [91] = { name = "Cold as Ice", grade = 2, points = 6, secret = true, description = "Take an ice cube and an obsidian knife and you'll very likely shape something really pretty from it. Mostly cute little mammoths, which are a hit with all the girls." },
+ [92] = { name = "Exquisite Taste", grade = 1, points = 2, secret = true, description = "You love fish - but preferably those caught in the cold north. Even though they're hard to come by you never get tired of picking holes in ice sheets and hanging your fishing rod in." },
+ [93] = { name = "Jamjam", grade = 2, points = 5, secret = true, description = "When it comes to interracial understanding, you're an expert. You've mastered the language of the Chakoya and made someone really happy with your generosity. Achuq!" },
+ [94] = { name = "I Did My Part", grade = 1, points = 2, secret = true, description = "Your world is lucky to have you! You don't hesitate to jump in and help when brave heroes are called to save the world." },
+ [95] = { name = "Notorious Worldsaver", grade = 3, points = 8, secret = true, description = "You're in the front line when it comes to saving your world or taking part in social events. Whether you do it noticed or unnoticed by the people, your world can rely on you to dutifully do your part to make it a better place for everyone." },
+ [96] = { name = "Teamplayer", grade = 1, points = 2, secret = true, description = "You don't consider yourself too good to do the dirty work while someone else might win the laurels for killing Devovorga. They couldn't do it without you!" },
+ [97] = { name = "Daring Trespasser", grade = 1, points = 3, secret = true, description = "You've entered the lair of Devovorga and joined the crew trying to take her down - whether crowned with success or not doesn't matter, but they can't blame you for not trying!" },
+ [98] = { name = "Slayer of Anmothra", grade = 1, points = 2, secret = true, description = "Souls are like butterflies. The black soul of a living weapon yearning to strike lies shattered beneath your feet." },
+ [99] = { name = "Slayer of Chikhaton", grade = 1, points = 2, secret = true, description = "Power lies in the will of her who commands it. You fought it with full force - and were stronger." },
+ [100] = { name = "Slayer of Irahsae", grade = 1, points = 2, secret = true, description = "Few things equal the wild fury of a trapped and riven creature. You were a worthy opponent." },
+ [101] = { name = "Slayer of Phrodomo", grade = 1, points = 2, secret = true, description = "Blind hatred took physical form, violently rebelling against the injustice it was born into. You were not able to bring justice - but at least temporary peace." },
+ [102] = { name = "Slayer of Teneshpar", grade = 1, points = 2, secret = true, description = "The forbidden knowledge of aeons was never meant to invade this world. You silenced its voice before it could be made heard." },
+ [103] = { name = "Cocoon of Doom", grade = 1, points = 3, secret = true, description = "You helped bringing Devovorga's dangerous tentacles and her humongous cocoon down - not stopping her transformation, but ultimately completing a crucial step to her death." },
+ [104] = { name = "Devovorga's Nemesis", grade = 2, points = 5, secret = true, description = "One special hero among many. This year - it was you. Devovorga withdrew in a darker realm because she could not withstand your power - and that of your comrades. Time will tell if the choice you made was good - but for now, it saved your world." },
+ [105] = { name = "Mister Sandman", grade = 1, points = 2, secret = true, description = "Tired... so tired... curling up in a warm and cosy bed seems like the perfect thing to do right now. Sweet dreams!" },
+ [106] = { name = "Rock Me to Sleep", grade = 1, points = 1, secret = true, description = "Sleeping - you do it with style. You're chilling in your hammock, listening to the sound of the birds and crickets as you slowly drift away into the realm of dreams." },
+ [107] = { name = "Modest Guest", grade = 1, points = 1, secret = true, description = "You don't need much to sleep comfortably. A pile of straw and a roof over your head - with the latter being completely optional - is quite enough to relax. You don't even mind the rats nibbling on your toes." },
+ [108] = { name = "Joke's on You", grade = 1, points = 1, secret = true, description = "Well - the contents of that present weren't quite what you expected. With friends like these, who needs enemies?" },
+ [109] = { name = "Oops", grade = 1, points = 2, secret = true, description = "So much for your feathered little friend! Maybe standing in front of the birdcage, squeezing its neck and shouting 'Sing! Sing! Sing!' was a little too much for it?!" },
+ [110] = { name = "Bluebarian", grade = 1, points = 2, secret = true, description = "You live the life of hunters and gatherers. Well, especially that of a gatherer, and especially of one who gathers lots of blueberries. Have you checked the colour of your tongue lately?" },
+ [111] = { name = "Demonic Barkeeper", grade = 1, points = 3, description = "Thick, red - shaken, not stirred - and with a straw in it: that's the way you prefer your demon blood. Served with an onion ring, the subtle metallic aftertaste is almost not noticeable. Beneficial effects on health or mana are welcome." },
+ [112] = { name = "The Snowman", grade = 1, points = 1, secret = true, description = "You love the winter. Fully equipped with scarf and gloves, you like to have fun outside while building lots of snowmen with your friends. Snowball fight, anyone?" },
+ [113] = { name = "Number of the Beast", grade = 1, points = 2, description = "Six. Six. Six." },
+ [114] = { name = "I Need a Hug", grade = 1, points = 2, description = "You and your stuffed furry friends are inseparable, and you're not ashamed to take them to bed with you - who knows when you will wake up in the middle of the night in dire need of a cuddle?" },
+ [115] = { name = "Slim Chance", grade = 1, points = 1, description = "Okay, let's face it - as long as you believe it could potentially lead you to the biggest treasure ever, you won't let go of that map, however fishy it might look. There must be a secret behind all of this!" },
+ [116] = { name = "Rocket in Pocket", grade = 1, points = 1, secret = true, description = "Either you are not a fast learner or you find some pleasure in setting yourself on fire. Or you're just looking for a fancy title. In any case, you should know that passing gas during your little donkey experiments is not recommended." },
+ [117] = { name = "Make a Wish", grade = 1, points = 1, secret = true, description = "But close your eyes and don't tell anyone what you wished for, or it won't come true!" },
+ [118] = { name = "Santa's Li'l Helper", grade = 1, points = 2, secret = true, description = "Christmas is your favourite time of the year, and boy, do you love presents. Buy some nice things for your friends, hide them away until - well, until you decide to actually unwrap them rather yourself." },
+ [119] = { name = "Cursed!", grade = 1, points = 3, secret = true, description = "The wrath of the Noxious Spawn - you accidentally managed to incur it. Your days are counted and your death inevitable. Sometime. Someplace." },
+ [120] = { name = "Free Items!", grade = 1, points = 3, secret = true, description = "Yay! Finders keepers, losers weepers! Who cares where all that stuff came from and if you had to crawl through garbage piles to get it? It's FREE!" },
+ [121] = { name = "Rollercoaster", grade = 1, points = 1, description = "Up and down and up and down... and then the big looping! Wait - they don't build loopings in Kazordoon. But ore wagon rides are still fun!" },
+ [122] = { name = "Transmutator", grade = 2, points = 5, secret = true, description = "You, Sir or Lady, are a true alchemist. Conducting transmutating experiments to find every possible combination has been your secret passion since years and the results of your research are incredible. Science has just taken a leap thanks to you!" },
+ [123] = { name = "Berserker", grade = 1, points = 3, description = "RAWR! Strength running through your body, your heart racing faster and adrenaline fueling your every weapon swing. All in a little bottle. No refund for destroyed furniture. For further questions consult your healer or potion dealer." },
+ [124] = { name = "Mastermind", grade = 1, points = 3, description = "You feel you could solve the hardest riddles within a minute or so. Plus, there's a nice boost on your spell damage. All in a little bottle. Aftereffects - feeling slightly stupid. For further questions consult your healer or potion dealer." },
+ [125] = { name = "Sharpshooter", grade = 1, points = 3, description = "Improved eyesight, arrows and bolts flying at the speed of light and pinning your enemies with extra damage. All in a little bottle. No consumption of carrots required. For further questions consult your healer or potion dealer." },
+ [126] = { name = "Do Not Disturb", grade = 1, points = 1, secret = true, description = "Urgh! Close the windows! Shut out the sun rearing its ugly yellow head, shut out the earsplitting laughter of your neighbour's corpulent children. Ahhh. Embrace sweet darkness and silence." },
+ [127] = { name = "Let the Sunshine In", grade = 1, points = 1, secret = true, description = "Rise and shine! It's a beautiful new day - open your windows, feel the warm sunlight, watch the birds singing on your windowsill and care for your plants. What reason is there not to be happy?" },
+ [128] = { name = "Bad Timing", grade = 1, points = 2, secret = true, description = "Argh! Not now! How is it that those multifunctional tools never fail when you're using them for something completely trivial like squeezing juice, but mess up when you desperately need to climb up a rope spot with a fire-breathing dragon chasing you?" },
+ [129] = { name = "Nothing Can Stop Me", grade = 1, points = 1, secret = true, description = "You laugh at unprepared adventurers stuck in high grass or rush wood. Or maybe you actually do help them out. They call you... 'Machete'." },
+ [130] = { name = "Happy Farmer", grade = 1, points = 1, secret = true, description = "Scythe swung over your shoulder, sun burning down on your back - you are a farmer at heart and love working in the fields. Or then again maybe you just create fancy crop circles to scare your fellow men." },
+ [131] = { name = "Natural Sweetener", grade = 1, points = 1, secret = true, description = "Liberty Bay is the perfect hangout for you and harvesting sugar cane quite a relaxing leisure activity. Would you like some tea with your sugar, hon?" },
+ [132] = { name = "Homebrewed", grade = 1, points = 1, secret = true, description = "Yo-ho-ho and a bottle of rum - homebrewed, of course, made from handpicked and personally harvested sugar cane plants. Now, let it age in an oak barrel and enjoy it in about 10 years. Or for the impatient ones: Let's have a paaaarty right now!" },
+ [133] = { name = "Gold Digger", grade = 2, points = 4, secret = true, description = "Hidden treasures below the sand dunes of the desert - you have a nose for finding them and you know where to dig. They might not make you filthy rich, but they're shiny and pretty anyhow." },
+ [134] = { name = "The Undertaker", grade = 1, points = 2, secret = true, description = "You and your shovel - a match made in heaven. Or hell, for that matter. Somewhere down below in any case. You're magically attracted by stone piles and love to open them up and see where those holes lead you. Good biceps as well." },
+ [135] = { name = "Cookie Monster", grade = 1, points = 1, secret = true, description = "You can easily be found by anyone if they just follow the cookie crumb trail. And for you, true love means to give away your last cookie." },
+ [136] = { name = "The Cake's the Truth", grade = 1, points = 1, secret = true, description = "And anyone claiming otherwise is a liar." },
+ [137] = { name = "Sweet Tooth", grade = 1, points = 2, secret = true, description = "The famous 'Ode to a Molten Chocolate Cake' was probably written by you. Spending a rainy afternoon in front of the chimney, wrapped in a blanket while indulging in cocoa delights sounds just like something you'd do. Enjoy!" },
+ [138] = { name = "With a Cherry on Top", grade = 1, points = 1, secret = true, description = "You like your cake soft, with fruity bits and a nice sugar icing. And you prefer to make them by yourself. Have you ever considered opening a bakery? You must be really good by now!" },
+ [139] = { name = "Mutated Presents", grade = 1, points = 1, secret = true, description = "Muahahaha it's a... mutated pumpkin! After helping to take it down - you DID help, didn't you? - you claimed your reward and got a more or less weird present. Happy Halloween!" },
+ [140] = { name = "Keeper of the Flame", grade = 1, points = 2, secret = true, description = "One of the Lightbearers. One of those who helped to keep the basins burning and worked together against the darkness. The demonic whispers behind the thin veil between the worlds - they were silenced again thanks to your help." },
+ [141] = { name = "True Lightbearer", grade = 2, points = 5, secret = true, description = "You're one of the most dedicated Lightbearers - without you, the demons would have torn the veil between the worlds for sure. You've lit each and every basin, travelling high and low, pushing back the otherworldly forces. Let there be light!" },
+ [142] = { name = "Godslayer", grade = 2, points = 4, description = "You have defeated the Snake God's incarnations and, with a final powerful swing of the snake sceptre, cut off his life force supply. The story of power, deceit and corruption has come to an end - or... not?" },
+ [143] = { name = "The Day After", grade = 1, points = 2, secret = true, description = "Uhm... who's that person who you just woke up beside? Broken cocktail glasses on the floor, flowers all over the room, and why the heck are you wearing a ring? Yesterday must have been a long, weird day..." },
+ [144] = { name = "Commitment Phobic", grade = 1, points = 2, secret = true, description = "Longterm relationships are just not for you. And each time you think you're in love, you're proven wrong shortly afterwards. Or maybe you just end up with the wrong lover each time - exploited and betrayed. Staying single might just be better." },
+ [145] = { name = "Heartbreaker", grade = 1, points = 1, secret = true, description = "Trust? Love? Faithfulness? Pah! Antiquated sentiments. As long as you have fun, you do not mind stepping on lots of hearts. Preferably while wearing combat boots." },
+ [146] = { name = "Swift Death", grade = 2, points = 6, description = "Stealth kills and backstabbing are you specialty. Your numerous victims are usually unaware of their imminent death, which you bring to them silently and swiftly. Everything is permitted." },
+ [147] = { name = "Brutal Politeness", grade = 2, points = 6, description = "What is best in life? To crush your enemies. To see them driven before you. And to maybe have a nice cup of tea afterwards." },
+ [148] = { name = "Life on the Streets", grade = 2, points = 4, description = "You're a beggar, homeless, wearing filthy and ragged clothes. But that doesn't mean you have to beg anyone for stuff - and you still kept your pride. Fine feathers do not necessarily make fine birds - what's under them is more important." },
+ [149] = { name = "Skull and Bones", grade = 2, points = 6, description = "Wearing the insignia and dark robes of the Brotherhood of Bones you roam the lands spreading fear and pain, creating new soldiers for the necromantic army which is about to rise soon. Hail the Brotherhood." },
+ [150] = { name = "Nightmare Walker", grade = 2, points = 6, description = "You do not fear nightmares, you travel in them - facing countless horrors and fighting the fate they're about to bring. Few believe the dark prophecies you bring back from those dreams, but those who do fight alongside you as Nightmare Knights." },
+ [151] = { name = "Exemplary Citizen", grade = 2, points = 4, description = "Every city should be proud to call someone like you its inhabitant. You're keeping the streets clean and help settling the usual disputes in front of the depot. Also, you probably own a cat and like hiking." },
+ [152] = { name = "Demonbane", grade = 2, points = 6, description = "You don't carry that stake just for decoration - you're prepared to use it. Usually you're seen hightailing through the deepest dungeons leaving a trail of slain demons. Whoever dares stand in your way should prepare to die." },
+ [153] = { name = "Of Wolves and Bears", grade = 2, points = 6, description = "One with nature, one with wildlife. Raw and animalistic power, sharpened senses, howling on the highest cliffs and roaring in the thickest forests - that's you." },
+ [154] = { name = "Hunting with Style", grade = 2, points = 6, description = "At daytime you can be found camouflaged in the woods laying traps or chasing big game, at night you're sitting by the campfire and sharing your hunting stories. You eat what you hunted and wear what you skinned. Life could go on like that forever." },
+ [155] = { name = "Fool at Heart", grade = 1, points = 3, description = "And remember: Never try to teach a pig to sing. It wastes your time and annoys the pig." },
+ [156] = { name = "In Shining Armor", grade = 2, points = 6, description = "With edged blade and fully equipped in a sturdy full plate armor, you charge at your enemies with both strength and valour. There's always a maiden to save and a dragon to slay for you." },
+ [157] = { name = "Aristocrat", grade = 2, points = 4, description = "You begin your day by bathing in your pot of gold and you don't mind showing off your wealth while strolling the streets in your best clothes - after all it's your hard-earned money! You prefer to be addressed with 'Your Highness'." },
+ [158] = { name = "Out in the Snowstorm", grade = 2, points = 4, description = "Snow heaps and hailstorms can't keep you from where you want to go. You're perfectly equipped for any expedition into the perpetual ice and know how to keep your feet warm. If you're a woman, that's quite an accomplishment, too." },
+ [159] = { name = "One Thousand and One", grade = 2, points = 6, description = "You feel at home under the hot desert sun with sand between your toes, and your favourite means of travel is a flying carpet. Also, you can probably do that head isolation dance move." },
+ [160] = { name = "Swashbuckler", grade = 2, points = 6, description = "Ye be a gentleman o' fortune, fightin' and carousin' on the high seas, out fer booty and lassies! Ye no be answerin' to no man or blasted monarchy and yer life ain't fer the lily-livered. Aye, matey!" },
+ [161] = { name = "Way of the Shaman", grade = 2, points = 6, description = "Shaking your rattle and dancing around the fire to jungle drums sounds like something you like doing. Besides, dreadlocks are a convenient way to wear your hair - no combing required!" },
+ [162] = { name = "Ritualist", grade = 2, points = 6, description = "You could be the author of the magnum opus 'How to Summon the Ultimate Beast from the Infernal Depths, Volume I'. Or, if your mind and heart are pure, you rather summon beings to help others. Or maybe just a little cat to have someone to cuddle." },
+ [163] = { name = "Master of War", grade = 2, points = 6, description = "You're not afraid to show your colours in the heat of battle. Enemies fear your lethal lance and impenetrable armor. The list of the wars you've won is impressive. Hail and kill!" },
+ [164] = { name = "Wild Warrior", grade = 2, points = 6, description = "Valour is for weaklings - it doesn't matter how you win the battle, as long as you're victorious. Thick armor would just hinder your movements, thus you keep it light and rely on speed and skill instead of hiding in an uncomfortable shell." },
+ [165] = { name = "Peazzekeeper", grade = 2, points = 6, description = "You're a humble warrior who doesn't need wealth or specialised equipment for travelling and fighting. You feel at home in the northern lands of Zao and did your part in fighting its corruption." },
+ [166] = { name = "Yalahari of Wisdom", grade = 1, points = 3, description = "Your deeds for Yalahar are usually characterised by deep insight and thoughtful actions. Thanks to you, Yalahar might have a chance to grow peacefully and with happy people living in it." },
+ [167] = { name = "Yalahari of Power", grade = 1, points = 3, description = "You defend Yalahar with brute force and are ready to lead it into a glorious battle, if necessary. Thanks to you, Yalahar will be powerful enough to stand up against any enemy." },
+ [168] = { name = "Piece of Cake", grade = 1, points = 1, description = "Life can be so easy with the right cake at the right time - and you mastered baking many different ones, so you should be prepared for almost everything life decides to throw at you." },
+ [169] = { name = "Alumni", grade = 2, points = 6, description = "You're considered a first-rate graduate of the Magic Academy in Edron due to your pioneering discoveries and successful studies in the field of experimental magic and spell development. Ever considered teaching the Armageddon spell?" },
+ [170] = { name = "Warlock", grade = 2, points = 6, description = "You're proficient in the darker ways of magic and are usually found sitting inside a circle of candles and skulls muttering unspeakable words. Don't carry things too far or the demons might come get you." },
+ [171] = { name = "Bunny Slipped", grade = 1, points = 2, secret = true, description = "Indeed, you have a soft spot for rabbits. Maybe the rabbits you saved today will be the rabbits that will save you tomorrow. When you are really hungry." },
+ [172] = { name = "Guinea Pig", grade = 1, points = 2, description = "True scientists know their equipment. Testing new inventions is essential daily work for any hard working researcher. You showed no fear and took all the new equipment from Spectulus and Sinclair for a spin." },
+ [173] = { name = "Merry Adventures", grade = 1, points = 2, description = "You went into the forest, met Rottin Wood and the Married Men and helped them out in their camp. Oh, and don't worry about those merchants. They won't dare mentioning the strangely large sums of gold they actually possessed which are missing now." },
+ [174] = { name = "Afraid of no Ghost!", grade = 1, points = 2, description = "You passed their test and helped the Spirithunters testing equipment, researching the supernatural and catching ghosts - it's you they're gonna call." },
+ [175] = { name = "Extreme Degustation", grade = 1, points = 2, secret = true, description = "Almost all the plants you tested for Chartan in Zao where inedible - you tasted them all, yet you're still standing! You should really get some fresh air now, though." },
+ [176] = { name = "Cake Conqueror", grade = 1, points = 1, secret = true, description = "You have bravely stepped onto the cake isle. Is there any more beautiful, tasty place to be in the whole world?" },
+ [177] = { name = "Baby Sitter", grade = 1, points = 1, secret = true, description = "You have cheered up a demon baby and returned it to its mother. A quick count of your fingers will reveal if you made it through unharmed." },
+ [178] = { name = "Nanny from Hell", grade = 1, points = 3, secret = true, description = "You have cheered up a bunch of demon babies and returned them to their mother. Don't bother the burn marks, don't bother the strains of grey hair, don't bother the nights you wake up screaming. It was worth it ... probably ... somehow." },
+ [179] = { name = "Ghost Sailor", grade = 1, points = 1, secret = true, description = "You have sailed the nether seas with the Ghost Captain. Despite the perils, you and your fellow crewmen have braved the challenge." },
+ [180] = { name = "Spectral Traveller", grade = 1, points = 2, secret = true, description = "You have sailed the nether seas with the Ghost Captain several times. The dangers of the nether have become familiar to you and unexperienced travelers turn to you for advice." },
+ [181] = { name = "Nether Pirate", grade = 1, points = 3, secret = true, description = "Not fearing death or ghosts you have traveled with the ghost captain several times and are a seasoned traveler of the netherworld. The dead and the living whisper about your exploits with appreciation." },
+ [182] = { name = "Scourge of Death", grade = 2, points = 5, secret = true, description = "You are a master of the nether sea and have traveled with the ghost captain so many times that you know his ship and the perils of the nether sea inside out. You laugh in the face of death and may return as a ghost pirate yourself in the afterlife!" },
+ [183] = { name = "Fire Lighter", grade = 1, points = 1, secret = true, description = "You have helped to keep the witches fire burning. Just watch your fingers, it's hot!" },
+ [184] = { name = "Witches Lil' Helper", grade = 1, points = 1, secret = true, description = "You sacrificed ingredients to create the protective brew of the witches." },
+ [185] = { name = "Banebringers' Bane", grade = 1, points = 2, secret = true, description = "You sacrificed a lot of ingredients to create the protective brew of the witches and played a significant part in the efforts to repel the dreaded banebringers. The drawback is that even the banebringers may take notice of you ..." },
+ [186] = { name = "Fire Devil", grade = 1, points = 3, secret = true, description = "To keep the witches' fire burning, you trashed a lot of the wood the bane bringers animated. Some might find your fascination for fire ... disturbing." },
+ [187] = { name = "Pyromaniac", grade = 2, points = 4, secret = true, description = "Love ... fire! So ... shiny! Must ... buuuurrrn!" },
+ [188] = { name = "Honorary Witch", grade = 2, points = 4, secret = true, description = "Your efforts in fighting back the banebringers has not gone unnoticed. You are a legend amongst the witches and your name is whispered with awe and admiration." },
+ [189] = { name = "Natural Born Cowboy", grade = 1, points = 1, secret = true, description = "Oh, the joy of riding! You've just got your very first own mount. Conveniently enough you don't even need stables, but can summon it any time you like." },
+ [190] = { name = "Petrologist", grade = 1, points = 2, secret = true, description = "Stones have always fascinated you. So has the chance of finding something really precious inside one of them. Statistically you should've discovered a few nice treasures by now. But then again, most statistics are overriden by Mother Disfortune." },
+ [191] = { name = "Hidden Powers", grade = 1, points = 2, description = "You've discovered the Ancients' hidden powers - from now on, they will aid you in your adventures." },
+ [192] = { name = "I Like it Fancy", grade = 1, points = 1, secret = true, description = "You definitely know how to bring out the best in your furniture and decoration pieces. Beautiful." },
+ [193] = { name = "Skin-Deep", grade = 2, points = 4, secret = true, description = "You always carry your obsidian knife with you and won't hesitate to use it. You've skinned countless little - and bigger - critters and yeah: they usually don't get any more beautiful on the inside. It's rather blood and gore and all that..." },
+ [194] = { name = "Ashes to Dust", grade = 2, points = 4, secret = true, description = "Staking vampires and demons has almost turned into your profession. You make sure to gather even the tiniest amount of evil dust particles. Beware of silicosis." },
+ -- [195] = Unknown/non-existent
+ [196] = { name = "Safely Stored Away", grade = 1, points = 2, secret = true, description = "Don't worry, no one will be able to take it from you. Probably." },
+ [197] = { name = "Something's in There", grade = 1, points = 1, secret = true, description = "By the gods! What was that?" },
+ [198] = { name = "Silent Pet", grade = 1, points = 1, secret = true, description = "Awww. Your very own little goldfish friend - he's cute, he's shiny and he can't complain should you forget to feed him. He'll definitely brighten up your day!" },
+ [199] = { name = "Snowbunny", grade = 1, points = 2, secret = true, description = "Hopping, hopping through the snow - that's the funnest way to go! Making footprints in a flurry - it's more fun the more you hurry! Licking icicles all day - Winter, never go away!" },
+ [200] = { name = "Dark Voodoo Priest", grade = 1, points = 2, secret = true, description = "Sinister curses, evil magic - you don't shy away from punishing others by questionable means. Someone just gave you a strange look - now where's that needle again?" },
+ [201] = { name = "Nomad Soul", grade = 1, points = 2, secret = true, description = "Home is where your current favourite hunting ground is, and though you might hold certain places more dear than others you never feel attached enough to really stay in one city for long. Pack all your stuff - it's time to move on again." },
+ [202] = { name = "Truth Be Told", grade = 1, points = 2, secret = true, description = "You told Jack the truth by explaining you and Spectulus made a mistake when trying to convince him of being a completely different person." },
+ [203] = { name = "You Don't Know Jack", grade = 1, points = 2, secret = true, description = "You did not tell Jack the truth about the mistake you and Spectulus made when trying to convince him about being a completely different person. He will live in doubt until the end of his existence." },
+ [204] = { name = "Berry Picker", grade = 2, points = 4, secret = true, description = "The Combined Magical Winterberry Society hereby honours continued selfless dedication and extraordinary efforts in the Annual Autumn Vintage." },
+ [205] = { name = "True Colours", grade = 1, points = 3, secret = true, description = "You and your friends showed the three wizards your loyalty three times - I am sure at least one of them is probably eternally thankful and exceedingly proud of you." },
+ [206] = { name = "Master Shapeshifter", grade = 1, points = 2, secret = true, description = "You have mastered Kuriks challenge in all possible shapes." },
+ [207] = { name = "Slimer", grade = 1, points = 1, secret = true, description = "With the assistance of your friendly little helper, you gobbled more than 500 chunks of slime. Well done, Slimer." },
+ [208] = { name = "Mageslayer", grade = 1, points = 1, secret = true, description = "You killed the raging mage in his tower south of Zao. Again. But this one just keeps coming back. The dimensional portal collapsed once more and you know he will eventually return but hey - a raging mage, it's like asking for it..." },
+ [209] = { name = "Biodegradable", grade = 1, points = 1, secret = true, description = "You caught fifty rare shimmer swimmers. Getting rid of all those corpses by dumping them into the lake really was worth it, wasn't it? Wait, didn't something move in the water just now...?" },
+ [210] = { name = "Eye of the Deep", grade = 1, points = 1, secret = true, description = "You didn't look into it - at least not for too long... but Groam did. And you relieved him. Just don't tell his friend Dronk." },
+ [211] = { name = "Invader of the Deep", grade = 1, points = 2, secret = true, description = "Many creatures of the deep have lost their lives by your hand. Three hundred have entered the depths of eternity. You should probably fear the revenge of the Eyes of the Deep." },
+ [212] = { name = "Firefighter", grade = 1, points = 2, secret = true, description = "You extinguished 500 thornfires! You were there when the Firestarters took over Shadowthorn. You saved the day - and the home of some elves which will try to kill you nonetheless. Isn't it nice to see everything restored just as it was before..?" },
+ [213] = { name = "Deer Hunt", grade = 1, points = 1, secret = true, description = "You managed to kill more than four hundred white deer - it looks like you are one of the main reasons they will soon be considered extinct, way to go!" },
+ [214] = { name = "Askarak Nemesis", grade = 1, points = 1, secret = true, description = "You are now the royal archfiend of the Askarak, prince slayer." },
+ [215] = { name = "Shaburak Nemesis", grade = 1, points = 1, secret = true, description = "You are now the public archenemy of the Shaburak, prince slayer." },
+ [216] = { name = "Fearless", grade = 1, points = 1, secret = true, description = 'You broke the jar of Horestis - fifty times. Either you know no fear or simply ignore it. Whatever the case, you are "fearless" indeed.' },
+ [217] = { name = "Doctor! Doctor!", grade = 1, points = 2, secret = true, description = "Did someone call a doctor? You delivered 100 medicine bags to Ottokar of the Venore poor house in times of dire need, well done!" },
+ [218] = { name = "Beak Doctor", grade = 2, points = 4, description = "You significantly helped the afflicted citizens of Venore in times of dire need. Somehow you still feel close to the victims of the fever outbreak. Your clothes make you one of them, one poor soul amongst the countless afflicted." },
+ [219] = { name = "Mystic Fabric Magic", grade = 2, points = 4, description = "You vanquished the mad mage, you subdued the raging mage - no spellweaving self-exposer can stand in your way. Yet you are quite absorbed in magical studies yourself. This very fabric reflects this personal approval of the magic arts." },
+ -- [220] = Unknown/non-existent
+ [221] = { name = "Arachnoise", grade = 1, points = 1, description = "You've shattered each of Bloodweb's eight frozen legs. As they say: break a leg, and then some more." },
+ [222] = { name = "Rootless Behaviour", grade = 1, points = 1, description = "You've descended into the swampy depths of Deathbine's lair and made quick work of it." },
+ [223] = { name = "Twisted Mutation", grade = 1, points = 1, description = "You've slain Esmeralda, the most hideous and aggressive of the mutated rats. No one will know that you almost lost a finger in the process." },
+ [224] = { name = "Beautiful Agony", grade = 1, points = 2, description = "Ethershreck's cry of agony kept ringing in your ear for hours after he had dissolved into thin air. He probably moved to another plane of existence... for a while." },
+ [225] = { name = "Scorched Flames", grade = 1, points = 1, description = "A mighty blaze went out today. It's Flameborn's turn to wait for his rebirth in the eternal cycle of life and death." },
+ [226] = { name = "Crawling Death", grade = 1, points = 1, description = "You ripped the ancient scarab Fleshcrawler apart and made sure he didn't get under your skin." },
+ [227] = { name = "The Serpent's Bride", grade = 1, points = 2, description = "You made a knot with Gorgo's living curls and took her scalp. You couldn't save her countless petrified victims, but at least you didn't become one." },
+ [228] = { name = "No More Hiding", grade = 1, points = 1, description = "You've found a well-hidden spider queen and caught her off guard in the middle of her meal." },
+ [229] = { name = "The Gates of Hell", grade = 1, points = 2, description = "It seems the gates to the underworld have to remain unprotected for a while. Kerberos, the mighty hellhound, lost his head. All three of them." },
+ [230] = { name = "The Drowned Sea God", grade = 1, points = 2, description = "As the killer of Leviathan, the giant sea serpent, his underwater kingdom is now under your reign." },
+ [231] = { name = "Spareribs for Dinner", grade = 1, points = 1, description = "Ribstride is striding no more. He had quite a few ribs to spare though." },
+ [232] = { name = "Breaking the Ice", grade = 1, points = 1, description = "You almost made friends with Shardhead... before he died. Poor guy only seems to attract violence with his frosty attitude." },
+ [233] = { name = "Just Cracked Me Up!", grade = 1, points = 2, description = "Stonecracker's head was much softer than the stones he threw at you." },
+ [234] = { name = "Something Smells", grade = 1, points = 1, description = "You've exinguished the Sulphur Scuttler's gas clouds and made the air in his cave a little better... at least for a while." },
+ [235] = { name = "Meat Skewer", grade = 1, points = 1, description = "You've impaled the big mammoth Bloodtusk with his own tusks." },
+ [236] = { name = "One Less", grade = 1, points = 2, description = "The Many is no more, but how many more are there? One can never know." },
+ [237] = { name = "Hissing Downfall", grade = 1, points = 2, description = "You've vanquished the Noxious Spawn and his serpentine heart." },
+ [238] = { name = "Choking on Her Venom", grade = 1, points = 1, description = "The Old Widow fell prey to your supreme hunting skills." },
+ [239] = { name = "Blood-Red Snapper", grade = 1, points = 1, description = "You've tainted the jungle floor with the Snapper's crimson blood." },
+ [240] = { name = "Back into the Abyss", grade = 1, points = 1, description = "You've cut off a whole lot of tentacles today. Thul was driven back to where he belongs." },
+ [241] = { name = "Pwned a Lot of Fur", grade = 3, points = 8, secret = true, description = "You've faced and defeated a lot of the mighty bosses the Paw and Fur society sent you out to kill. All by yourself. What a hunt!" },
+ [242] = { name = "Honest Finder", grade = 1, points = 1, description = "You've stopped the bank robber and returned the bag full of gold. Good to know there are still lawful Tibians like you around." },
+ [243] = { name = "Goldhunter", grade = 1, points = 2, secret = true, description = "If it wasn't for you, several banks in Tibia would've gotten bankrupt by now. Keep on chasing bank robbers and no one will have to worry about the Tibian economy!" },
+ [244] = { name = "Trail of the Ape God", grade = 1, points = 1, secret = true, description = "You've discovered a trail of giant footprints and terrified elephants running everywhere. Could it be that the mysterious ape god is rambling in the jungle?" },
+ [245] = { name = "Someone's Bored", grade = 1, points = 1, secret = true, description = "That was NOT a giant spider. There's some witchcraft at work here." },
+ [246] = { name = "Whistle-Blower", grade = 1, points = 1, secret = true, description = "You can't keep a secret, can you? Then again, you're just fulfilling your duty to the Queen of Carlin as a lawful citizen. That's a good thing, isn't it...?" },
+ [247] = { name = "Torn Treasures", grade = 1, points = 1, secret = true, description = "Wyda seems to be really, really bored. You also found out that she doesn't really need all those blood herbs that adventurers brought her. Still, she was nice enough to take one from you and gave you something quite cool in exchange." },
+ [248] = { name = "Loyal Subject", grade = 1, points = 1, secret = true, description = "You joined the Kingsday festivities and payed King Tibianus your respects. Now, off to party!" },
+ [249] = { name = "Desert Fisher", grade = 1, points = 1, description = "You managed to catch a fish in a surrounding that usually doesn't even carry water. Everything is subject to change, probably..." },
+ -- [250] = Unknown/non-existent
+ [251] = { name = "Dog Sitter", grade = 1, points = 1, description = "You showed Noodles the way home. How long will it take this time until he's on the loose again? That dog must be really bored in the throne room by now." },
+ [252] = { name = "Ice Harvester", grade = 1, points = 1, description = "You witnessed the thawing of Svargrond and harvested rare seeds from some strange icy plants. They must be good for something." },
+ [253] = { name = "Preservationist", grade = 1, points = 1, secret = true, description = "You are a pretty smart thinker and managed to create everlasting flowers. They might become a big hit with all the people who aren't blessed with a green thumb or just forgetful." },
+ [254] = { name = "Chest Robber", grade = 1, points = 1, description = "You've discovered three nomad camps and stole their supplies. Well, you can probably use them better then they can." },
+ [255] = { name = "Down the Drain", grade = 1, points = 2, description = "You've found a secret dungeon in the flooded plains and killed several of its inhabitants. And now you have wet feet." },
+ [256] = { name = "Fire from the Earth", grade = 1, points = 2, description = "You've survived the Hellgorge eruption and found a way through the flames and lava. You've even managed to kill a few fireborn on the way." },
+ [257] = { name = "Minor Disturbance", grade = 1, points = 2, description = "Your actions start to make a difference. You have blinded the antennae of the hive often enough to become an annoyance to it." },
+ [258] = { name = "Dazzler", grade = 1, points = 3, description = "In the war against the hive, your efforts in blinding it begin to pay off. Your actions have blinded the hive severely and the entity seems to become aware that something dangerous is happening." },
+ [259] = { name = "Hive Blinder", grade = 2, points = 4, description = "You have put a lot of time and energy into keeping the hive unaware of what is happening on Quirefang. The hive learnt to fear your actions. It would surely crush you with all its might ... if it could only find you!" },
+ [260] = { name = "Hickup", grade = 1, points = 2, description = "You have grown accustomed to frequenting the hive's stomach system. Your actions have caused the hive some first digestion problems." },
+ [261] = { name = "Heartburn", grade = 1, points = 3, description = "Never-tiring, you attack the inner organs of the mighty hive. Your attacks on the hive's digestion system begin to cause some trouble." },
+ [262] = { name = "Stomach Ulcer", grade = 2, points = 4, description = "You severely disrupted the digestion of the hive. The hive should for sure see a doctor. It seems you proved to be more than it can swallow." },
+ [263] = { name = "Planter", grade = 1, points = 2, description = "The hive has to be fought with might and main, hampering its soldiers is only the first step. You diligently stopped the pores of the hive to spread its warriors." },
+ [264] = { name = "Pimple", grade = 1, points = 3, description = "You are getting more and more experienced in destroying the supply of the enemy's forces. Your actions caused the hive some severe skin problems." },
+ [265] = { name = "Suppressor", grade = 2, points = 4, description = "A war is won by those who have the best supply of troops. The hive's troops have been dealt a significant blow by your actions. You interrupted the hive's replenishment of troops lastingly and severely." },
+ [266] = { name = "Gatherer", grade = 1, points = 2, description = "By killing creatures of the hive and gaining weapons for further missions, you started a quite effective way of war. You gathered a lot of dissolved chitin to resupply the war effort." },
+ [267] = { name = "Supplier", grade = 1, points = 3, description = "The need for supplies often decides over loss or victory. Your tireless efforts to resupply the resources keeps the war against the hive going." },
+ [268] = { name = "Chitin Bane", grade = 2, points = 4, description = "You have become competent and efficient in gathering the substance that is needed to fight the hive. You almost smell like dissolved chitin and the Hive Born would tell their children scary stories about you if they could speak." },
+ [269] = { name = "Guard Killer", grade = 1, points = 2, description = "You have proven that you can beat the best of the hive. You have caused first promising breaches in the defence of the hive" },
+ [270] = { name = "Hive Infiltrator", grade = 1, points = 3, description = "The most powerful warriors of the hive were killed by you by the dozens. The hive is not safe anymore because of your actions." },
+ [271] = { name = "Exterminator", grade = 2, points = 4, description = "Efficient and lethal, you have gained significant experience in fighting the elite forces of the hive. Almost single-handed, you have slain the best of the Hive Born and live to tell the tale." },
+ [272] = { name = "Headache", grade = 1, points = 2, description = "Even in the deepest structures of the hive, you began to strike against the mighty foe. Your actions probably already gave the hive a headache." },
+ [273] = { name = "Confusion", grade = 1, points = 3, description = "The destruction you have caused by now can be felt throughout the whole hive. The mayhem that follows your step caused significant confusion in the consciousness of the hive." },
+ [274] = { name = "Manic", grade = 2, points = 4, description = "You have destroyed a significant amount of the hive's vital nerve centers and caused massive destruction to the hive's awareness. You are probably causing the hive horrible nightmares." },
+ -- [275] = Unknown/non-existent
+ [276] = { name = "Navigational Error", grade = 2, points = 5, secret = true, description = "You confronted the Navigator." },
+ [277] = { name = "Si, Ariki!", grade = 1, points = 1, description = "You've found the oriental traveller Yasir and were able to trade with him - even if you didn't really understand his language." },
+ [278] = { name = "Guardian Downfall", grade = 2, points = 4, description = "You ended the life of over three hundred Deepling Guards. Not quite the guardian of the Deeplings, are you?" },
+ [279] = { name = "Death Song", grade = 1, points = 3, description = "You hushed the songs of war in the black depths by sliencing more than three hundred Deepling Spellsingers." },
+ [280] = { name = "Depth Dwellers", grade = 1, points = 3, description = "By eliminating at least three hundred Deepling Warriors you delivered quite a blow to the amassing armies of the deep." },
+ [281] = { name = "Gem Cutter", grade = 1, points = 1, secret = true, description = 'You cut your first gem - and it bears your own name! Now that would be a nice gift! This does not make it a "true" Heart of the Sea, however...' },
+ [282] = { name = "Spolium Profundis", grade = 2, points = 4, description = "You travelled the depths of this very world. You entered the blackness of the deep sea to conquer the realm of the Deeplings. May this suit remind you of the strange beauty below." },
+ [283] = { name = "Bane of the Hive", grade = 1, points = 2, description = "Countless fights and never tiring effort in the war against the hive grant you the experience to finish your outfit with the last remaining part. Your chitin outfit is a testament of your skills and dedication for the cause." },
+ -- [284] = Unknown/non-existent
+ [285] = { name = "Hive War Veteran", grade = 1, points = 1, description = "Your invaluable experience in fighting the hive allows you to add another piece of armor to your chitin outfit to prove your dedication for the cause." },
+ [286] = { name = "Hive Fighter", grade = 1, points = 1, description = "You have participated that much in the hive war, that you are able to create some makeshift armor from the remains of dead hive born that can be found in the major hive, to show of your skill." },
+ [287] = { name = "Howly Silence", grade = 1, points = 1, description = "You muted the everlasting howling of Hemming." },
+ [288] = { name = "Dream's Over", grade = 1, points = 1, description = "No more fear and bad dreams. You stabbed Tormentor to death with its scythe leg." },
+ [289] = { name = "Zzztill Zzztanding!", grade = 1, points = 1, description = "You wiped Fazzrah away - zzeemzz like now you're the captain." },
+ [290] = { name = "Stepped on a Big Toe", grade = 1, points = 1, description = "This time you knocked out the big one." },
+ [291] = { name = "Kapow!", grade = 1, points = 1, description = "No joke, you murdered the bat." },
+ [292] = { name = "Enter zze Draken!", grade = 1, points = 2, description = "You gave zzze draken a tazte of your finizzzing move." },
+ [293] = { name = "King of the Ring", grade = 1, points = 2, description = "Bretzecutioner's body just got slammed away. You are a true king of the ring!" },
+ [294] = { name = "Back from the Dead", grade = 1, points = 2, description = "You overcame the undead Zanakeph and sent him back into the darkness that spawned him." },
+ [295] = { name = "Pwned All Fur", grade = 3, points = 8, secret = true, description = "You've faced and defeated each of the mighty bosses the Paw and Fur society sent you out to kill. All by yourself. What a hunt!" },
+ -- [296] = Unknown/non-existent
+ [297] = { name = "Bibby's Bloodbath", grade = 1, points = 1, secret = true, description = "You lend a helping hand in defeating invading Orcs by destroying their warcamp along with their leader. Bibby's personal bloodbath..." },
+ [298] = { name = "Nestling", grade = 1, points = 1, description = "You cleansed the land from an eight legged nuisance by defeating Mamma Longlegs three times. She won't be back soon... or will she?" },
+ [299] = { name = "Becoming a Bigfoot", grade = 1, points = 1, description = "You did it! You convinced the reclusive gnomes to accept you as one of their Bigfoots. Now you are ready to help them. With big feet big missions seen to come." },
+ [300] = { name = "Gnome Little Helper", grade = 1, points = 1, description = "You think the gnomes start to like you. A little step for a Bigfoot but a big step for humanity." },
+ [301] = { name = "Gnome Friend", grade = 1, points = 2, description = "The gnomes are warming up to you. One or two of them might actually bother to remember your name. You're allowed to access their gnomebase alpha. You are prepared to boldly put your big feet into areas few humans have walked before." },
+ [302] = { name = "Gnomelike", grade = 1, points = 3, description = "You have become a household name in gnomish society! Your name is mentioned by gnomes more than once. Of course usually by gnomish mothers whose children refuse to eat their mushroom soup, but you are certainly making some tremendous progress." },
+ [303] = { name = "Honorary Gnome", grade = 2, points = 4, description = "You accomplished what few humans ever will: you truly impressed the gnomes. This might not change their outlook on humanity as a whole, but at least you can bathe in gnomish respect! And don't forget you're now allowed to enter the warzones!" },
+ [304] = { name = "Crystals in Love", grade = 1, points = 1, description = "You brought two loving crystals together. Perhaps they might even name one of their children after you. Too bad you forgot to leave your calling card." },
+ [305] = { name = "Substitute Tinker", grade = 1, points = 1, description = "Ring-a-ding! You have visited the golem workshop and lent a hand in repairing them. To know those golems are safe is worth all the bruises, isn't it?" },
+ [306] = { name = "Spore Hunter", grade = 1, points = 1, description = "After hunting for the correct mushrooms and their spores you're starting to feel like a mushroom yourself. A few times more and you might start thinking like a mushroom, who knows?" },
+ [307] = { name = "Grinding Again", grade = 1, points = 1, description = "Burnt fingers and itching lungs are a small price for bringing those gnomes some lousy stone and getting almost killed! Your mother warned you to better become a farmer." },
+ [308] = { name = "Dungeon Cleaner", grade = 1, points = 3, secret = true, description = "Seen it all. Done it all. Your unstoppable force swept through the dungeons and you vanquished their masters. Not to forget the precious loot you took! Now stop reading this and continue hunting! Time is money after all!" },
+ [309] = { name = "Crystal Keeper", grade = 1, points = 1, description = "So you repaired the light of some crystals for those gnomes. What's next? Sitting a week in a mushroom bed as a temporary mushroom?" },
+ [310] = { name = "Call Me Sparky", grade = 1, points = 1, description = "Admittedly you enjoyed the killing as usual. But the part with the sparks still gives you shivers ... or is it that there is some charge left on you?" },
+ [311] = { name = "One Foot Vs. Many", grade = 1, points = 1, description = "One Bigfoot won over thousands of tiny feet. Perhaps the gnomes are wrong and size matters?" },
+ [312] = { name = "The Picky Pig", grade = 1, points = 1, description = "The gnomes decided their pigs need some exclusive diet and you had to do all the dirty work - but wasn't the piglet adorable?" },
+ [313] = { name = "Diplomatic Immunity", grade = 2, points = 4, secret = true, description = "You killed the ambassador of the abyss that often that they might consider sending another one. Perhaps that will one day stop further intrusions." },
+ [314] = { name = "Fall of the Fallen", grade = 2, points = 4, secret = true, description = "Have you ever wondered how he reappears again and again? You only care for the loot, do you? Gotcha!" },
+ [315] = { name = "Death on Strike", grade = 2, points = 4, secret = true, description = "Again and again Deathstrike has fallen to your prowess. Perhaps it's time for people calling YOU Deathstrike from now on." },
+ [316] = { name = "Death from Below", grade = 1, points = 2, secret = true, description = "The face of the enemy is unmasked. You have encountered one of 'those below' and survived. More than that, you managed to kill the beast and prove once and for all that the enemy can be beaten." },
+ [317] = { name = "Gnomebane's Bane", grade = 1, points = 2, secret = true, description = "The fallen gnome is dead and justice served. But what was it that the gnome whispered with his last breath? He's your father???" },
+ [318] = { name = "Final Strike", grade = 1, points = 2, secret = true, description = "The mighty Deathstrike is dead! One legend is dead and you're on your way to become one yourself." },
+ [319] = { name = "Goo Goo Dancer", grade = 1, points = 1, secret = true, description = "Seeing a mucus plug makes your heart dance and you can't resist to see what it hides. Goo goo away!" },
+ [320] = { name = "Funghitastic", grade = 1, points = 3, description = "Finally your dream to become a walking mushroom has come true ... No, wait a minute!" },
+ [321] = { name = "Crystal Clear", grade = 1, points = 3, description = "If the gnomes had told you that crystal armor is see-through you had probably changed your underwear in time." },
+ [322] = { name = "Gnomish Art Of War", grade = 1, points = 3, description = "You have unleashed your inner gnome and slain some of the most fearsome threats that gnomekind has ever faced. Now you can come and go to the warzones as it pleases you. The enemies of gnomekind will never be safe again." },
+ -- [323] = Unknown/non-existent
+ [324] = { name = "True Dedication", grade = 2, points = 5, secret = true, description = "You conquered the demon challenge and prevailed... now show off your success in style!" },
+ [325] = { name = "Task Manager", grade = 1, points = 2, secret = true, description = "Helping a poor, stupid goblin to feed his starving children and wifes feels good ... if you'd only get rid of the strange feeling that you're missing something." },
+ [326] = { name = "Gravedigger", grade = 1, points = 3, description = "Assisting Omrabas' sick plan to resurrect made you dig your way through the blood-soaked halls of Drefia. Maybe better he failed!" },
+ [327] = { name = "Repenter", grade = 1, points = 1, secret = true, description = "You cleansed your soul in serving the Repenter enclave and purified thine self in completing all tasks in a single day of labour." },
+ [328] = { name = "Umbral Swordsman", grade = 2, points = 6, description = "You managed to transform, improve and sacrify your blade into a master state and have proven yourself worthy in a nightmarish world." },
+ -- [329] = Unknown/non-existent
+ -- [330] = Unknown/non-existent
+ [331] = { name = "Cave Completionist", grade = 1, points = 2, description = "You have helped the gnomes of the spike in securing the caves and explored enough of the lightles depths to earn you a complete cave explorers outfit. Well done!" },
+ [332] = { name = "Umbral Bladelord", grade = 2, points = 6, description = "You managed to transform, improve and sacrify your slayer into a master state and have proven yourself worthy in a nightmarish world." },
+ [333] = { name = "Umbral Headsman", grade = 2, points = 6, description = "You managed to transform, improve and sacrify your axe into a master state and have proven yourself worthy in a nightmarish world." },
+ [334] = { name = "Umbral Executioner", grade = 2, points = 6, description = "You managed to transform, improve and sacrify your chopper into a master state and have proven yourself worthy in a nightmarish world." },
+ [335] = { name = "Umbral Brawler", grade = 2, points = 6, description = "You managed to transform, improve and sacrify your mace into a master state and have proven yourself worthy in a nightmarish world." },
+ [336] = { name = "Umbral Berserker", grade = 2, points = 6, description = "You managed to transform, improve and sacrify your hammer into a master state and have proven yourself worthy in a nightmarish world." },
+ [337] = { name = "Umbral Archer", grade = 2, points = 6, description = "You managed to transform, improve and sacrify your bow into a master state and have proven yourself worthy in a nightmarish world." },
+ [338] = { name = "Umbral Marksman", grade = 2, points = 6, description = "You managed to transform, improve and sacrify your crossbow into a master state and have proven yourself worthy in a nightmarish world." },
+ [339] = { name = "Umbral Harbinger", grade = 2, points = 6, description = "You managed to transform, improve and sacrify your spellbook into a master state and have proven yourself worthy in a nightmarish world." },
+ [340] = { name = "Umbral Master", grade = 3, points = 8, description = "You managed to transform, improve and sacrify all kinds of weapons into a master state and have proven yourself worthy in a nightmarish world. Respect!" },
+ [341] = { name = "Nevermending Story", grade = 1, points = 3, secret = true, description = "You collected all of the mysterious bottle messages around the island of Roshamuul and located the remains of the first mate. Time will tell if his tale of mending an evil ring holds true." },
+ [342] = { name = "Luring Silence", grade = 1, points = 2, description = "What a scientific discovery - they really DO communicate! Using their own communication habits against them, you lured a large pack of silencers away from the walls of Roshamuul." },
+ [343] = { name = "Never Surrender", grade = 1, points = 3, description = "You did not show any signs of surrender to any sight of... you get the picture. Even a hundred of them did not pose a threat to you." },
+ [344] = { name = "Dream Wright", grade = 1, points = 1, description = "You have mended many a broken dream and so, the dream of Roshamuul is safely being told over and over again." },
+ [345] = { name = "Ending the Horror", grade = 1, points = 2, description = "You have cleansed the lands of many retching horrors. You sure know how to end a bad dream: forcefully, that's how!" },
+ [346] = { name = "Sleepwalking", grade = 1, points = 1, description = "You know your way, in dream and waking. And how to make tea that transcends the boundaries of conscience." },
+ [347] = { name = "Dream Warden", grade = 2, points = 5, description = "It doesn't matter what noise you would hear... dream, nightmare, illusion - there is nothing you can't vanquish. You are a true Dream Warden." },
+ [348] = { name = "Prison Break", grade = 3, points = 8, description = "Gaz'haragoth... a day to remember! Your world accomplished something really big - and you have been part of it!" },
+ [349] = { name = "Noblesse Obliterated", grade = 2, points = 6, description = "After a battle like this you know who your friends are." },
+ [350] = { name = "Elementary, My Dear", grade = 1, points = 1, description = "Through the spirit of science and exploration, you have discovered how to enter the secret hideout of the renowned Dr Merlay." },
+ [351] = { name = "Rathleton Commoner", grade = 1, points = 1, description = "By having rendered numerous services to the city of Rathleton you have been promoted to the rank of Commoner." },
+ [352] = { name = "Rathleton Inhabitant", grade = 1, points = 1, description = "By having rendered numerous services to the city of Rathleton you have been promoted to the rank of Inhabitant." },
+ [353] = { name = "Rathleton Citizen", grade = 1, points = 1, description = "By having rendered numerous services to the city of Rathleton you have been promoted to the rank of Citizen." },
+ [354] = { name = "Combo Master", grade = 1, points = 1, secret = true, description = "You accomplished 10 or more consecutive chains in a row! That's killing at least 39 creatures in the correct order - now that's combinatorics!" },
+ [355] = { name = "Glooth Engineer", grade = 2, points = 5, description = "Though you might have averted a dire threat for Rathleton, this relative peace may only hold for a while. At least you've scavenged an outfit from some of the poor fellows that have fallen prey to death priest Shagron." },
+ [356] = { name = "Lion's Den Explorer", grade = 1, points = 1, secret = true, description = "You discovered the Lion's Rock, passed the tests to enter the inner sanctum and finally revealed the secrets of the buried temple. You literally put your head in the lion's mouth and survived." },
+ [357] = { name = "Seasoned Adventurer", grade = 1, points = 1, description = "Adventure is your middle name. You spent much time in dangerous lands and have seen things others only dream of. You know your way around in Tibia - you are a seasoned adventurer now. And your journey has only just begun!" },
+ [358] = { name = "Mind the Step!", grade = 1, points = 1, description = "You've got a mind ready to draw strange conclusions that defy the laws of logic and sidestep reality. Or maybe it's just a lucky guess - or adventurous recklessness?" },
+ [359] = { name = "Rathleton Squire", grade = 1, points = 1, description = "By having rendered numerous services to the city of Rathleton you have been promoted to the rank of Squire." },
+ [360] = { name = "The Professor's Nut", grade = 1, points = 3, description = "He seriously stored away a wallnut? That was a nutty professor indeed." },
+ [361] = { name = "Plant vs. Minos", grade = 2, points = 4, secret = true, description = "You have defeated the wallbreaker and saved the glooth plant." },
+ [362] = { name = "Rumble in the Plant", grade = 2, points = 4, secret = true, description = "You have defeated the tremor worm - and wonder what kind of fish you'd be able to catch with such a bait." },
+ [363] = { name = "Robo Chop", grade = 2, points = 4, secret = true, description = "You have defeated the glooth bomb and chopped down a lot of metal monsters on your way." },
+ [364] = { name = "Go with da Lava Flow", grade = 1, points = 1, secret = true, description = "You escaped the glowing hot lava death trap, Professor Maxxen has set for you - Captain Caveworm is indeed proud!" },
+ [365] = { name = "Wail of the Banshee", grade = 1, points = 1, secret = true, description = "You saw the Crystal Gardens with all their stunning beauty and survived the equally impressive monsters there. In the end you discovered a great evil and destroyed it with the help of a banshee who was not even aware of her support." },
+ [366] = { name = "Publicity", grade = 1, points = 1, description = "You are a man of the public. Or of good publicity at least. Through your efforts in advertising the airtight cloth, Zeronex might yet be redeemed - and Rathleton might yet see its first working Gloud Ship." },
+ [367] = { name = "Snake Charmer", grade = 1, points = 1, description = "By restoring the Everhungry Altar, you charmed the Fire-Feathered Sea Serpent back into its fitful sleep, twenty miles beneath the sea." },
+ [368] = { name = "Hoard of the Dragon", grade = 1, points = 1, secret = true, description = "Your adventurous way through countless dragon lairs earned you a pretty treasure - and surely the enmity of many a dragon." },
+ -- [369] = Unknown/non-existent
+ [370] = { name = "Little Ball of Wool", grade = 1, points = 1, description = "You found a lost sheep and thus a steady source of black wool. But careful: don't get entangled." },
+ [371] = { name = "Luminous Kitty", grade = 1, points = 3, description = "You made some efforts to bring a little more light into the world. And what a nice present you got in return!" },
+ [372] = { name = "The Right Tone", grade = 1, points = 1, description = "By setting the right tone you convinced a crystal wolf to accompany you. Remember it is made of crystal, though, so be careful in a banshee's presence." },
+ [373] = { name = "Loyal Lad", grade = 1, points = 1, description = "Having a loyal friend alongside is comforting to every adventurer. If only this lad was not so stubborn..." },
+ [374] = { name = "Dragon Mimicry", grade = 1, points = 2, description = "It's not really a dragon, but rather a kind of chimera. Nonetheless a decent mount to impress any passer-by." },
+ [375] = { name = "Scales and Tail", grade = 1, points = 2, description = "The Muggy Plains are a dangerous place, often raided by dragons. But that was your luck: thus you found this scaly little guy." },
+ [376] = { name = "Fata Morgana", grade = 1, points = 2, description = "There are many delusions and phantasms in the desert. You saw a false oasis with fruit-bearing palm trees. Instead of water and refreshment, however, you found a dromedary in the end. What a useful Fata Morgana!" },
+ [377] = { name = "Fabled Construction", grade = 1, points = 3, description = "Finding all the pieces to this complicated vehicle was one kind of a challenge. However, what you built in the end is rather a fabled than a feeble construction." },
+ [378] = { name = "Mind the Dog!", grade = 1, points = 2, description = "Barking dogs never bite, as the saying goes. But this one clearly tried. In the end, however, you were able to walk the dog - ahem, gnarlhound." },
+ [379] = { name = "Magnetised", grade = 1, points = 2, description = "This magnetic beast attracted you in a very literal way. Or was it attracted by your metal equipment? Anyway, you seem to be stuck together now." },
+ [380] = { name = "Golden Sands", grade = 1, points = 3, description = "Counting ten thousand grains of sand could not have been harder than gaining this impressive mount." },
+ [381] = { name = "Friend of Elves", grade = 1, points = 1, description = "Kingly deer mostly prefer elves as friends and familiars. This one, however, decided to favour you as a confidant and rider. Well done!" },
+ [382] = { name = "Lovely Dots", grade = 1, points = 3, description = "Finding a four-leaved clover is always a sign of luck. And as luck would have it, you even baited a lovely dotted ladybug. Lucky you!" },
+ [383] = { name = "Way to Hell", grade = 1, points = 2, description = "This fiery beast really tried to give you hell. But not even a magma crawler can resist a mug of spicy, hot glow wine. Skol!" },
+ [384] = { name = "Beneath the Sea", grade = 1, points = 3, description = "Not really twenty thousand miles, but you had to dive a fair way beneath the sea to find your personal Manta Ray." },
+ [385] = { name = "Starless Night", grade = 1, points = 3, description = "By many it is considered a myth like the Yeti. But you came, saw and tamed it. Now you're the proud rider of a midnight panther, black as a starless night." },
+ [386] = { name = "Lion King", grade = 1, points = 1, description = "By mastering the secrets of Lion's Rock, you proved yourself worthy to face the mighty lions there. One of them even chose to accompany you." },
+ [387] = { name = "Pecking Order", grade = 1, points = 1, description = "Ah, the old carrot-on-a-stick trick. Well done! You've made the racing bird accept you as a rider and provider. Just don't feed it your fingers." },
+ [388] = { name = "Pig-Headed", grade = 1, points = 2, description = "Whoa, sow long! This boar is like a force of nature, breaking through the undergrowth of all the Tibian forests and all records of speed. Hang on!" },
+ [389] = { name = "Personal Nightmare", grade = 1, points = 3, description = "It might come as a shock to you, but this is the mount of your dreams. Not exactly the white steed of Prince Charming, but maybe the ladies will still scream and faint at the sight of you." },
+ [390] = { name = "Thick-Skinned", grade = 1, points = 2, description = "It's unstoppable! Walls? Fortresses? Obstacles? Objections? Pah! Nothing will stand before the stampor. Arrows and spears bounce off its hide, enemies are trampled by the dozen. Just don't go for the subtle approach or a date on this thing." },
+ [391] = { name = "Chequered Teddy", grade = 1, points = 1, description = "Don't let its fluffy appearance deceive you. The panda is a creature of the wild. It will take you to the most distant regions of Tibia, always in hopes of a little bamboo to nibble on or to check on a possible mate." },
+ [392] = { name = "Blacknailed", grade = 1, points = 1, description = "Well, you can rest your nailcase now. This gravedigger's fingernails are nice and clean. Though after the next hellride, you might not want to let it hand any food to you." },
+ [393] = { name = "Slugging Around", grade = 1, points = 2, description = "Drugging a snail can have some beneficial side effects. You're now the proud owner of a snarling, speed-crazy slug. Maybe it'll purr if you stroke it. Anyway, life should be one slick ride from now on." },
+ [394] = { name = "Knock on Wood", grade = 1, points = 3, description = "It's a wound-up wooden lizard! Well, stranger things have happened, or so you're told. Just hop on and let this wood-and-tin contraption take you anywhere you want to wind down a bit. And hope you don't get hit by lightning underway." },
+ [395] = { name = "Fried Shrimp", grade = 1, points = 2, description = "This must be underwater love - this enormous crustacean now does thy bidding. Or maybe it's just in it for a little more of that shrimp barbecue, as that's a little hard to come by in the sea." },
+ [396] = { name = "Out of the Stone Age", grade = 1, points = 3, description = "What a blast from the past! This thankful patient thinks you missed your dentist vocation. It's now ready to take a bite of the future and to carry you to your next adventure, or your next patient." },
+ [397] = { name = "Stuntman", grade = 1, points = 3, description = "A drop of oil and you're good to go. This unique mount will roll merrily in and out of any strange place you want to visit. If you see no exit, you probably ended up in a circus ring. Ah well, the show must go on!" },
+ [398] = { name = "Gear Up", grade = 1, points = 3, description = "Installing that control unit was a no-brainer. Now you're in control to make it walk this way or that, or to change tack at any moment if required. Your faithful walker mount obeys your every command." },
+ [399] = { name = "Bearbaiting", grade = 1, points = 1, description = "Hunter's greeting! Your skillful use of the slingshot actually stunned a large bear. The creature is slightly dazed, but seems susceptible to your commands. Let's declare open season on all our foes!" },
+ [400] = { name = "Lucky Horseshoe", grade = 1, points = 1, description = "'Sweets for my steed' could be your motto. An impressive horse is eating out of your hand. Saddle up and be ready to find adventure, new friends, and maybe someone to shoe your horse now and then." },
+ [401] = { name = "Swamp Beast", grade = 1, points = 1, description = "By cleverly using a leech to cool that raging bull's blood, you managed not to get swamped or trampled in a water buffalo stampede. The creature is now docile and follows your every command." },
+ [402] = { name = "Spin-Off", grade = 1, points = 1, description = "Seems like this spider has got a sweet tooth. As a result, eight hairy legs are now at your disposal to crawl and weave at your whim, and strike fear into the hearts of men." },
+ [403] = { name = "Icy Glare", grade = 1, points = 1, description = "Here's looking at you, kid. This ancient creature seems to size you up with its brilliant eyes and barely tolerates you riding it. Maybe it thinks you're the defrosted snack, after all?" },
+ [404] = { name = "Cartography 101", grade = 1, points = 2, description = "You succeeded in finding and charting several previously unexplored landmarks and locations for the Adventurer's Guild, you probably never need to ask anyone for the way - do you?" },
+ [405] = { name = "Lost Palace Raider", grade = 1, points = 2, secret = true, description = "Lifting the secrets of a fabulous palace and defeating a beautiful demon princess was a thrilling experience indeed. This site's marvels nearly matched its terrors. Nearly." },
+ [406] = { name = "The More the Merrier", grade = 1, points = 0, secret = true, description = "It's dangerous to go alone... Take ten friends." },
+ -- [407] = Unknown/non-existent
+ [408] = { name = "Rift Warrior", grade = 1, points = 3, description = "You went through hell. Seven times. You defeated the demons. Countless times. You put an end to Ferumbras claims to ascendancy. Once and for all." },
+ -- [409] = Unknown/non-existent
+ [410] = { name = "Hat Hunter", grade = 2, points = 5, description = "You sucessfully fought against all odds to protect your world from an ascending god! – You weren't there for the hat only after all?" },
+ [411] = { name = "Ogre Chef", grade = 1, points = 1, description = "You didn't manage to become an ogre chief. But at least you are, beyond doubt, a worthy ogre chef." },
+ [412] = { name = "The Call of the Wild", grade = 1, points = 2, description = "You opposed man-eating ogres and clumsy clomps. You grappled with hungry chieftains, desperate goblins and angry spirits. So you truly overcame the wild vastness of Krailos." },
+ [413] = { name = "Ender of the End", grade = 2, points = 5, description = "You have entered the heart of destruction and valiantly defeated the world devourer. By your actions you have postponed the end of the world — at least for a while." },
+ [414] = { name = "Vortex Tamer", grade = 2, points = 5, description = "After a long journey and dedication you were favoured by fortune and have tamed all three elusive beasts of the vortex. Unless the Vortexion decides you're a tasty morsel you can enjoy your small stable of ravaging beasts from beyond." },
+ [415] = { name = "Rhino Rider", grade = 1, points = 1, description = "Don't forget, even your rhino sometimes needs a hug. A careful one in this case." },
+ [416] = { name = "Forbidden Fruit", grade = 1, points = 1, secret = true, description = "You could not resist the taste of the forbidden fruit. Since you don't feel changed at all, it couldn't have been that bad after all. Or could it?" },
+ [417] = { name = "Forbidden Knowledge", grade = 1, points = 1, secret = true, description = "Perhaps with so much acquired knowledge, never meant for you, you know even when to stop! Time will tell whether this knowledge will do more harm or good." },
+ [418] = { name = "Treasure Hunter", grade = 1, points = 3, secret = true, description = "You wandered the world of Tibia in search of the ancient dragons' hoards. You are sure, you found them all." },
+ [419] = { name = "Reason to Celebrate", grade = 1, points = 1, description = "You met the legendary First Dragon and survived. That's a reason to celebrate for sure." },
+ [420] = { name = "Toothfairy Assistant", grade = 1, points = 1, description = "You assisted a very prominent fae and you fought tooth and nail to earn this title." },
+ [421] = { name = "Fairy Teasing", grade = 1, points = 1, secret = true, description = "Teasing fairies is fun. They leave behind such pretty clouds of glittering dust when chased. Just hope they don't get you back for it." },
+ [422] = { name = "Corruption Contained", grade = 2, points = 5, description = "You have managed to stall the worst incursion of corruption. Still this is just one battle won in an all out war for your world." },
+ -- [423] = Unknown/non-existent
+ -- [424] = Unknown/non-existent
+ -- [425] = Unknown/non-existent
+ -- [426] = Unknown/non-existent
+ -- [427] = Unknown/non-existent
+ -- [428] = Unknown/non-existent
+ -- [429] = Unknown/non-existent
+ [430] = { name = "Little Adventure", grade = 1, points = 1, description = "You have fully unlocked 10 easy monsters in the cyclopedia." },
+ [431] = { name = "Little Big Adventure", grade = 1, points = 2, secret = true, description = "You have fully unlocked 100 easy monsters in the cyclopedia." },
+ [432] = { name = "Contender", grade = 1, points = 3, description = "You have fully unlocked 10 medium monsters in the cyclopedia." },
+ [433] = { name = "Serious Contender", grade = 2, points = 4, secret = true, description = "You have fully unlocked 100 medium monsters in the cyclopedia." },
+ [434] = { name = "Skilled Hunter", grade = 2, points = 5, description = "You have fully unlocked 10 hard monsters in the cyclopedia." },
+ [435] = { name = "Master Hunter", grade = 2, points = 6, secret = true, description = "You have fully unlocked 100 hard monsters in the cyclopedia." },
+ [436] = { name = "Hunting Permit", grade = 1, points = 1, description = "You have fully unlocked your very first monster in the cyclopedia." },
+ [437] = { name = "Over the Moon", grade = 2, points = 5, description = "The Curse of the Full Moon transforms harmless citizens into feral beasts. But with your help, Edron and Cormaya are safe - fairly." },
+ [438] = { name = "His Days are Counted", grade = 1, points = 1, description = "You defeated the Count of the Core and destroyed his lava pump!" },
+ [439] = { name = "Duked It Out", grade = 1, points = 1, description = "You defeated the Duke of the Depths and destroyed his lava pump!" },
+ [440] = { name = "Buried the Baron", grade = 1, points = 1, description = "You defeated the Baron from Below and destroyed his lava pump!" },
+ [441] = { name = "Death in the Depths", grade = 1, points = 2, description = "The Baron from Below, Duke of the Depths and the Count of the Core are no more!" },
+ [442] = { name = "Scourge of Scarabs", grade = 1, points = 3, description = "You took the heat and defeated the Ancient Spawn of Morgathla!" },
+ [443] = { name = "Cobbled and Patched", grade = 2, points = 6, description = "Exploring the depths of Tibia can be a dangerous task. Surprisingly, some crude wood planks, rusty nails and a tinged pot can offer a sufficient protection against the creatures lurking in the deep." },
+ [444] = { name = "Up the Molehill", grade = 1, points = 3, description = "Putting this candle stump on your new mount was kind of a waiting game. You're even tempted to call it whack-a-mole. But in the end you found a loyal companion for your journeys into the depths." },
+ [445] = { name = "Master Debater", grade = 1, points = 1, secret = true, description = "You truly are the grand master of verbal debate! Now going forth and putting this wisdom to good use in everyday life... is probably debatable." },
+ [446] = { name = "High and Dry", grade = 1, points = 2, secret = true, description = "You asked Captain Charles to take a shortcut quite a few times. Now you are all too familiar with desert islands all over Tibia." },
+ [447] = { name = "Elven Woods", grade = 1, points = 1, description = "Tall trees, deep forests and and the beauty of Ab'Dendriel - you really know every corner of the elven lands now." },
+ [448] = { name = "Long Live the Queen", grade = 1, points = 1, description = "Ancient battlefields, amazons and the glory of Carlin - you really know every corner of Queen Eloise's realm now." },
+ [449] = { name = "Stronghold of Edron", grade = 1, points = 1, description = "Strong fortresses, sprawling woods and ivory towers - you really know every corner of Edron now." },
+ [450] = { name = "Dwarven Mines", grade = 1, points = 1, description = "Vast mines, an orc fortress and the magnificence of Kazordoon - you really know every corner of North-Eastern Mainland now." },
+ [451] = { name = "All Hail the King", grade = 1, points = 1, description = "Old temples, a meadowy countryside and the splendour of Thais - you really know every corner of King Tibianus' realm now." },
+ [452] = { name = "Jewel in the Swamp", grade = 1, points = 1, description = "Damp swamps, a dry desert and the opulence of Venore - you really know every corner of Eastern Mainland now." },
+ [453] = { name = "The Ogre Steppe", grade = 1, points = 1, description = "A vast steppe, voracious ogres and dried out salt seas - you really know every corner of Krailos now." },
+ [454] = { name = "Realms of Dreams", grade = 1, points = 1, description = "Lush meadows, colourful fairies and sentient stones - you really know every corner of Feyrist now." },
+ [455] = { name = "Mummy's Dearest", grade = 1, points = 1, description = "You have combed the desert and searched the pyramid city of Ankrahmun." },
+ [456] = { name = "Daraman's Footsteps", grade = 1, points = 1, description = "You journeyed through Darashia and the sea of sand around it, while fighting the perils of the desert." },
+ [457] = { name = "King of the Jungle", grade = 1, points = 1, description = "You have searched Port Hope and the jungle that thoroughly, that you are up to adoption by a friendly ape family." },
+ [458] = { name = "Ancient Splendor", grade = 1, points = 1, description = "You've braved the perils of Yalahar and learned of its gloomy shadows of long gone greatness." },
+ [459] = { name = "Liberty Bay Watch", grade = 1, points = 1, description = "A pirate's haven and a burglar's hideout. You found your way around Liberty Bay and its surroundings - land, ho!" },
+ [460] = { name = "Race to the Pole", grade = 1, points = 1, description = "You have expelled the fog of the unknown from the islands of Svargrond. Maybe not as first, but that's not what matters in the end." },
+ [461] = { name = "Lizard Kingdom", grade = 1, points = 1, description = "From the southern steppe through the Dragonblaze Mountains and the Muggy Plains to the forbidden city of Razachai - you really know every corner of Zao now." },
+ [462] = { name = "Trip to the Beach", grade = 1, points = 1, description = "Braving a hive full of unimaginable proportions and its grotesque creatures on the surface is only one side of Gray Beach. Your full trip of the island also included a dive into the black nothingness of the deep sea, facing the wrath of the Njey." },
+ [463] = { name = "Glooth Punk", grade = 1, points = 1, description = "Glooth is the substance that powers a whole continent and all its weird inhabitants, workshops and factories. You travelled this strange smorgasbord of curiosities in its entirety - just in time for tea." },
+ [464] = { name = "Twisted Dreams", grade = 1, points = 1, description = "A journey through a dreamscape of evil is no small feat. Yet you traversed the nightmarish lands of Roshamuul and live to tell the tale. Don't fall asleep now..." },
+ [465] = { name = "Library Liberator", grade = 1, points = 3, description = "Though you couldn't prevent the theft of the godbreaker knowledge, you still managed to fight off the invasion of the library and to kill the scourge of oblivion, a powerful servant of the enemy." },
+ [466] = { name = "Spectulation", grade = 1, points = 1, secret = true, description = "You checked out a strange temple deep in the jungles of Tiquanda. Spectulus was right, it was indeed overrun by strange fish-men you now call Deathlings." },
+ [467] = { name = "Millennial Falcon", grade = 1, points = 3, secret = true, description = "You defeated Grand Master Oberon and the remnants of the Order of the Falcon, no matter the odds." },
+ [468] = { name = "Bibliomaniac", grade = 1, points = 3, description = "You passion for reading was somewhat diminished by biting books and aggressive quills. But this flying specimen proved to be a loyal companion. Never judge a book by its cover!" },
+ [469] = { name = "Battle Mage", grade = 2, points = 6, description = "Wielding dangerous knowledge as well as the sword is your expertise. You have proven yourself versatile in all manner of situations." },
+ [470] = { name = "Widely Travelled", grade = 3, points = 7, description = "As a true globetrotter you can now show your colours proudly with this extraordinary outfit." },
+ [471] = { name = "Running the Rift", grade = 1, points = 3, description = "You don't just have a permission to ride a rift runner, you literally went through hell and earned it!" },
+ -- [472] = Unknown/non-existent
+ [473] = { name = "Exalted Battle Mage", grade = 1, points = 2, description = "Not only did you master the battlefield as a mage, you were also induced to the most inner secrets of the art of magical warfare and prevailed." },
+ [474] = { name = "Areas of Effect", grade = 1, points = 3, secret = true, description = "Wisely contributing your resources to areas, you pushed creatures to maximum effect, allowing improved respawn for everyone! Well done!" },
+ [475] = { name = "Tied the Knot", grade = 1, points = 1, secret = true, description = "You figured out the right order of spells in the buried cathedral, how enchanting!" },
+ [476] = { name = "Keeper of the 7 Keys", grade = 1, points = 2, description = "You found the Seven Keys to unlock ... no, not the seven seas. But at least seven doors in the realm of dreams." },
+ [477] = { name = "Dream Warrior", grade = 2, points = 6, description = "You became an acquaintance of the courts of dreams and acquired the right to display your new status and title of 'dream warrior'." },
+ [478] = { name = "Moth Whisperer", grade = 1, points = 3, description = "Your lantern was too bewitching for a hibernal moth. It couldn't withstand and follows you, the bearer of the lantern, now." },
+ [479] = { name = "Lacewing Catcher", grade = 1, points = 3, description = "You caught a lacewing moth with your lantern. It will follow you in companionship as the bearer of the lantern will be its guide through the darkness now." },
+ [480] = { name = "No Horse Open Sleigh", grade = 1, points = 3, description = "This sleigh is not driven by magic but pushed by a percht. Hopefully you two get along well together...!" },
+ [481] = { name = "Raider in the Dark", grade = 2, points = 6, description = "But can you truly be one of them?" },
+ [482] = { name = "Dream Catcher", grade = 1, points = 3, description = "You are the slayer of the ancient nightmare beast and prevented the nightmare to spread its madness." },
+ [483] = { name = "Champion of Summer", grade = 1, points = 2, secret = true, description = "You have vanquished numerous arena champions in the name of the Summer Court." },
+ [484] = { name = "Champion of Winter", grade = 1, points = 2, secret = true, description = "You have vanquished numerous arena champions in the name of the Winter Court." },
+ -- [485] = Unknown/non-existent
+ [486] = { name = "Bewitcher", grade = 2, points = 5, secret = true, description = "You literally put everything in that cauldron except lilac and gooseberries." },
+ [487] = { name = "Gryphon Rider", grade = 1, points = 3, description = "Unmasking spies, killing demons, discovering omens, solving puzzles and fighting ogres, manticores and feral sphinxes. - Nobody said it was easy to become a gryphon rider." },
+ [488] = { name = "Sculptor Apprentice", grade = 1, points = 2, secret = true, description = "Granted, you didn't carve those lifelike animal figurines yourself. But helping a medusa to find proper objects and even watching her using her petrifying gaze is almost as rewarding." },
+ [489] = { name = "Sun and Sea", grade = 2, points = 5, description = "You made sure that the balance of sun and sea is preserved in Kilmaresh. The Golden City of Issavi won't forget your favour." },
+ [490] = { name = "A Study in Scarlett", grade = 1, points = 3, secret = true, description = "You ended the regn of Scarlett Etzel. All-seeing yet blind, ever powerful yet ultimately helpless, she never got a second chance to truly see. Or has she..." },
+ [491] = { name = "Avid Spectral Reader", grade = 1, points = 1, secret = true, description = "What draws things to other dimensions, one wonders. You read the almanac at just the right spot to end up... where, of all places? That is the problem with dimensional travel: you will never know. Or you have always known. And everything in between." },
+ [492] = { name = "Hippofoddermus", grade = 1, points = 1, secret = true, description = "You did the hippo population of Kilmaresh a great favour. A well-fed hippo is a happy hippo." },
+ [493] = { name = "Inquisition's Hand", grade = 1, points = 3, description = "You defeated the Lich Knights and became the hand of the Inquisition, allowed to wear their special garb." },
+ [494] = { name = "The Empire's Glory", grade = 1, points = 1, description = "Mythical creatures, forgotten catacombs and the Golden City - you really know every corner of Kilmaresh now." },
+ [495] = { name = "Inquisition's Arm", grade = 1, points = 2, description = "Your special garb, solely awarded to a dedicated Hand of the Inquisition, is now complete." },
+ [496] = { name = "Traditionalist", grade = 2, points = 6, description = "You proudly wear the traditional Orcsoberfest garb, same as it ever was and as it always will be." },
+ [497] = { name = "Do a Barrel Roll!", grade = 1, points = 3, description = "Riding a traditional beer barrel from the Orcsoberfest is a once-in-a-lifetime experience. Beer sold separately." },
+ -- [498] = Unknown/non-existent
+ [499] = { name = "Orcsoberfest Welcome", grade = 1, points = 3, secret = true, description = 'The Orcsoberfest is not only known for its traditional food, beer and customs but also fun events and excitement! You took part in all of that and can now truly say: "I survived!"' },
+ [500] = { name = "Prospectre", grade = 1, points = 1, secret = true, description = "You made acquaintance with the Thaian. A strange contemporary with a dark history. No man but a derivate of greed and obsession." },
+ [501] = { name = "Nothing but Hot Air", grade = 1, points = 3, description = "You have tamed the ghostly mists to do your bidding. For now ..." },
+ [502] = { name = "Verminbane", grade = 1, points = 1, description = "And so it begins!" },
+ [503] = { name = "Monsterhunter", grade = 1, points = 2, description = "Fear me, monsters! There is some more slaying to come!" },
+ [504] = { name = "Taskmaster", grade = 1, points = 3, description = "Having hunted and bested them all, you live for the thrill of the hunt!" },
+ [505] = { name = "Mainstreet Nightmare", grade = 1, points = 2, description = "Now you are able to wander around Tibia wearing an angst-inducing vestment." },
+ [506] = { name = "Falconer", grade = 1, points = 2, description = "A true beastmaster learns the language of his animal companions. Now you as well can bolster your unique bond with nature and help preserve the balance of life as a proud falconer." },
+ [507] = { name = "Steppe Elegance", grade = 1, points = 3, description = "Champion of the wildlands, a swift strider among the creatures of the wild. The elegant nature of the gallop, this envoy of speed has mastered, indicates the precise understanding of its terrain and environment." },
+ [508] = { name = "Beyonder", grade = 1, points = 3, description = "Adventurous beyond death, you travelled the Netherworld. Although you had just the ghost of a chance you survived and even came back from the realm of the dead." },
+ -- [509] = Unknown/non-existent
+ [510] = { name = "Drama in Darama", grade = 1, points = 3, description = "If a pride of lions and a pack of hyaenas feud, it is not called a catfight but a ... whatsoever. For sure, it caused a lot of drama in the Darama Desert." },
+ [511] = { name = "Malefitz", grade = 1, points = 1, secret = true, description = "Made acquaintance with three brothers Fitz." },
+ [512] = { name = "Lionheart", grade = 1, points = 3, description = "You bested the maleficent duo Drume and Fugue and restored order to the besieged town of Bounac. You conquered the exotic stronghold of the Order of the Cobra and bested the undead knights of the Order of the Falcon. A true knight in heart and mind." },
+ [513] = { name = "Soul Mender", grade = 4, points = 10, description = "Brought back to the realm of the living this magnificent creature will carry you through death and everything that lays beyond." },
+ [514] = { name = "You Got Horse Power", grade = 3, points = 8, description = "Brought back to the realm of the living this magnificent creature will carry you through death and everything that lays beyond." },
+ [515] = { name = "Unleash the Beast", grade = 3, points = 8, description = "You defeated the manifestation of Goshnar's evil traits by fighting your way through beasts you didn't even want to imagine. It transformed you and now you can also look the part." },
+ [516] = { name = "Well Roared, Lion!", grade = 1, points = 1, description = "You helped Domizian and thus proved yourself worthy to enter the werelion sanctum underneath Lion's Rock. You faced the mighty werelions there and one of the rare white lions even chose to accompany you." },
+ -- [517] = Unknown/non-existent
+ [518] = { name = "Honorary Rascoohan", grade = 1, points = 2, description = "When in Rascacoon, do as the Rascoohans do!" },
+ [519] = { name = "Release the Kraken", grade = 1, points = 3, description = "Riding around on this squishy companion gives you the feeling of flying through the air... uhm... swimming through the seven seas!" },
+ -- [520] = Unknown/non-existent
+ [521] = { name = "Pied Piper", grade = 1, points = 3, secret = true, description = "You are not exactly the Pied Piper of Hamelin but at least you managed to fend off a decent amount of pirats and helped to keep them out of the cities." },
+ [522] = { name = "Woodcarver", grade = 1, points = 3, secret = true, description = "You defeated Megasylvan Yselda in the wake of the sleeping carnisylvan menace deep under Bounac." },
+ [523] = { name = "Bounacean Chivalry", grade = 1, points = 2, secret = true, description = "Yselda forever stands watch against the carnisylvan menace. Ever awake, waiting in the dark, her heart longs to be united with her king once again. Deep empathy let a hero to bring her Kesar's tulip as a token of his love. That hero was you." },
+ [524] = { name = "Knowledge Raider", grade = 1, points = 3, description = "Your thirst for knowledge is insatiable. In the task of helping your gnomish friends, flawless execution is just the icing on the cake." },
+ [525] = { name = "Citizen of Issavi", grade = 1, points = 2, description = "It was not the first time that you helped the Sapphire Blade or the Midnight Flame with a difficult task. You may now wear the Kilmareshian robes as well as the tagralt blade and the eye-embroidered veil of the seers as a sign of Issavi's gratitude." },
+ [526] = { name = "King's Council", grade = 1, points = 0, description = "Your continued efforts in keeping Bounac and the people of Kesar the Younger safe, earned you a permanent place at the royal court as an advisor to the king." },
+ [527] = { name = "Hot on the Trail", grade = 1, points = 3, description = "Since it is fireproof, this flaming creature feels right at home in raging infernos. But remember: just because it doesn't burn, you still do!" },
+ [528] = { name = "Shell We Take a Ride", grade = 1, points = 3, description = "Equipped with the shell of a tortoise and claws of a lobster this insect like companion will help you through every hardship." },
+ [529] = { name = "Phantastic!", grade = 1, points = 3, description = "This mighty pachyderm will march into battle as if just taking its Sunday stroll. The cost of friendship was only a few drome points!" },
+ [530] = { name = "Some Like It Hot", grade = 1, points = 2, description = "You have braved the searing heat in the tunnels deep below Kazordoon and vanquished the Brainstealer. The voices inside your head are finally silenced." },
+ [531] = { name = "First Achievement", grade = 1, points = 1, secret = true, description = "Congratulations to your very first achievement! ... Well, not really. But imagine, it is. Because at this point during your journey into Tibia's past, achievements have been introduced." },
+ [532] = { name = "Sharp Dressed", grade = 1, points = 2, description = "Just everyone will be crazy about you if you are wearing this formal dress. They will come running, promise!" },
+ [533] = { name = "Engine Driver", grade = 1, points = 3, description = "This glooth-driven locomotive will bring you to any party in the blink of an eye." },
+ [534] = { name = "Friendly Fire", grade = 1, points = 2, description = "You mastered the fire and tamed a supervulcano!" },
+ [535] = { name = "Wedding Planner", grade = 1, points = 3, description = "Alas! What could be more beautiful and satisfying than bringing two loving hearts together? So romantic!" },
+ [536] = { name = "Beaver Away", grade = 1, points = 1, description = "You really were as busy as a beaver in order to help the nagas. Enjoy some eager company!" },
+ [537] = { name = "Snake Pit", grade = 1, points = 1, description = "Mysterious nagas, a vibrant jungle and a sinking island - you really know every corner of Marapur now." },
+ [538] = { name = "Royalty of Hazard", grade = 1, points = 1, description = "For some it can't be hazardous enough." },
+ [539] = { name = "Measuring the World", grade = 1, points = 2, description = "Step by step you discovered many of the secrets hidden in the world, thus gaining the right to wear the Discoverer outfit and hat. Made-to-measure for a brave traveller of the Tibian wilds." },
+ [540] = { name = "Ripp-Ripp Hooray!", grade = 1, points = 3, description = "Don't get carried away by your success. Get carried away by your Ripptor." },
+ [541] = { name = "Warrior of the Iks", grade = 1, points = 2, description = "Combining unabating courage in combat and respect for the traditions and culture of the ancient Iks earned you the honours of true Aucar." },
+ [542] = { name = "Mutagenius", grade = 1, points = 2, description = "You accomplished the impossible and created 16 mutagens of corresponding colours." },
+ [543] = { name = "Strangest Thing", grade = 1, points = 3, description = "Only its rider can love this abomination of a mount." },
+ [544] = { name = "Fully Decayed", grade = 1, points = 2, description = "You defeated the embodiments of decay and live to tell the tale, wear the rotting attire of the unfaltering defender proudly." },
+ [545] = { name = "Like Fox and Mouse", grade = 1, points = 3, description = "Sly as a fox, quiet as a mouse - the perfect mount for a stealthy foray." },
+ [546] = { name = "The Spirit of Purity", grade = 1, points = 3, description = "Withstanding both filth and desolation of the rotten darkness that corrupted the very core of this world, you embodied the weapon of purity and light to defy all that was tainted. This spirit will continue guide you on all future paths." },
+ [547] = { name = "Museum Goer", grade = 1, points = 2, description = "You unveiled the secret plot of the Mitmah who stole away an entire civilisation for their own entertainment. Let the death of their outpost vanguard be an eternal lesson to them." },
+ [548] = { name = "Mystic Predator", grade = 1, points = 3, description = "Proving your true worth to a mystic creature like the jaguar, king of the hunt, granted you not only respect but also its heart." },
+ [549] = { name = "The Rule of Raccool", grade = 1, points = 2, description = "You almost feel as cool as a raccoon. Now, where's the trash?" },
+}
+
+function Cyclopedia.formatGold(value)
+ local number = tostring(value)
+ number = string.reverse(number)
+ number = string.gsub(number, "(%d%d%d)", "%1,")
+ number = string.reverse(number)
+
+ if string.sub(number, 1, 1) == "," then
+ number = string.sub(number, 2)
+ end
+
+ return number
+end
+
+function Cyclopedia.calculateCombatValues(percent)
+ local values = {}
+ if percent == 0 then
+ values.color = "#AE0F0F"
+ values.tooltip = "0% (immune)"
+ elseif percent < 100 then
+ values.color = "#E4C00A"
+ values.tooltip = percent .. "% (strong)"
+ elseif percent == 100 then
+ values.color = "#FFFFFF"
+ values.tooltip = "100% (neutral)"
+ else
+ values.color = "#18CE18"
+ values.tooltip = percent .. "% (weak)"
+ end
+
+ if percent > 100 then
+ values.margin = 15 + (125 - percent) * 0.28
+ else
+ values.margin = 22 + (100 - percent) * 0.21
+ end
+
+ if values.margin < 0 then
+ values.margin = 0
+ elseif values.margin > 65 then
+ values.margin = 65
+ end
+
+ return values
+end
+
+function Cyclopedia.formatSaleData(data)
+ local s, sell, b, buy = {}, {}, {}, {}
+
+ for i = 0, #data do
+ local value = data[i]
+
+ if value then
+ if value.salePrice > 0 then
+ if s[value.name] and value.name == "Rashid" then
+ s[value.name].various = true
+ end
+
+ if not s[value.name] then
+ local formated = {
+ various = false,
+ price = value.salePrice,
+ location = value.location
+ }
+
+ s[value.name] = formated
+ end
+ end
+
+ if value.buyPrice > 0 then
+ if b[value.name] and value.name == "Rashid" then
+ b[value.name].various = true
+ end
+
+ if not b[value.name] then
+ local formated = {
+ various = false,
+ price = value.buyPrice,
+ location = value.location
+ }
+
+ b[value.name] = formated
+ end
+ end
+ end
+ end
+
+ for name, value in pairs(s) do
+ if value.various then
+ table.insert(sell,
+ string.format("%s gp, %s\nResidence: %s", formatGold(value.price), name, "Various Locations"))
+ else
+ table.insert(sell, string.format("%s gp, %s\nResidence: %s", formatGold(value.price), name, value.location))
+ end
+ end
+
+ for name, value in pairs(b) do
+ if value.various then
+ table.insert(buy,
+ string.format("%s gp, %s\nResidence: %s", formatGold(value.price), name, "Various Locations"))
+ else
+ table.insert(buy, string.format("%s gp, %s\nResidence: %s", formatGold(value.price), name, value.location))
+ end
+ end
+
+ return sell, buy
+end
+
+function Cyclopedia.compareItems(item1, item2)
+ local marketData1 = item1:getMarketData()
+ local marketData2 = item2:getMarketData()
+
+ return marketData1.name:lower() < marketData2.name:lower()
+end
+
+function Cyclopedia.hasHandedFilter(categoryId)
+ local ids = {17, 18, 19, 20, 21, 1000}
+ if table.contains(ids, categoryId) then
+ return true
+ end
+
+ return false
+end
+
+function Cyclopedia.hasClassificationFilter(categoryId)
+ local ids = {1, 24, 7, 15, 17, 18, 19, 20, 21, 1000}
+ if table.contains(ids, categoryId) then
+ return true
+ end
+
+ return false
+end
+
+Cyclopedia.House.Data = {
+ {id = 1001, name = "Cozy Cottage", description = "A small, charming house perfect for new adventurers.", rent = 1000, beds = 1, sqm = 25, gh = false, shop = false, visible = true, state = 0, owner = "?", isYourBid = false, hasBid = true, bidEnd = 1628097600, hightestBid = 50000, bidName = "Explorer123", bidHolderLimit = nil, canBid = 1, rented = false, paidUntil = nil, isYourOwner = false, inTransfer = false, transferName = nil, transferTime = 0, transferValue = 0, isTransferOwner = false, canAcceptTransfer = 0},
+ {id = 1002, name = "Merchant's Haven", description = "A spacious house with room for a shop.", rent = 5000, beds = 4, sqm = 100, gh = false, shop = true, visible = true, state = 2, owner = "Trader_Joe", isYourBid = false, hasBid = false, bidEnd = nil, hightestBid = nil, bidName = nil, bidHolderLimit = nil, canBid = 0, rented = true, paidUntil = 1630689600, isYourOwner = false, inTransfer = false, transferName = nil, transferTime = 0, transferValue = 0, isTransferOwner = false, canAcceptTransfer = 0}
+}
+
+function Cyclopedia.safeOutfit(raceData)
+ if raceData == nil or raceData <= 0 then
+ return 22
+ else
+ return raceData
+ end
+end
+
+local combatStates= {
+ CLIENT_COMBAT_PHYSICAL = 0,
+ CLIENT_COMBAT_FIRE = 1,
+ CLIENT_COMBAT_EARTH = 2,
+ CLIENT_COMBAT_ENERGY = 3,
+ CLIENT_COMBAT_ICE = 4,
+ CLIENT_COMBAT_HOLY = 5,
+ CLIENT_COMBAT_DEATH = 6,
+ CLIENT_COMBAT_HEALING = 7,
+ CLIENT_COMBAT_DROWN = 8,
+ CLIENT_COMBAT_LIFEDRAIN = 9,
+ CLIENT_COMBAT_MANADRAIN = 10,
+}
+
+Cyclopedia.clientCombat ={}
+Cyclopedia.clientCombat[combatStates.CLIENT_COMBAT_PHYSICAL] = { path = '/game_cyclopedia/images/bestiary/icons/monster-icon-physical-resist', id = 'Physical' }
+Cyclopedia.clientCombat[combatStates.CLIENT_COMBAT_FIRE] = { path = '/game_cyclopedia/images/bestiary/icons/monster-icon-fire-resist', id = 'Fire' }
+Cyclopedia.clientCombat[combatStates.CLIENT_COMBAT_EARTH] = { path = '/game_cyclopedia/images/bestiary/icons/monster-icon-earth-resist', id = 'Earth' }
+Cyclopedia.clientCombat[combatStates.CLIENT_COMBAT_ENERGY] = { path = '/game_cyclopedia/images/bestiary/icons/monster-icon-energy-resist', id = 'Energy' }
+Cyclopedia.clientCombat[combatStates.CLIENT_COMBAT_ICE] = { path = '/game_cyclopedia/images/bestiary/icons/monster-icon-ice-resist', id = 'Ice' }
+Cyclopedia.clientCombat[combatStates.CLIENT_COMBAT_HOLY] = {path = '/game_cyclopedia/images/bestiary/icons/monster-icon-holy-resist', id = 'Holy' }
+Cyclopedia.clientCombat[combatStates.CLIENT_COMBAT_DEATH] = { path = '/game_cyclopedia/images/bestiary/icons/monster-icon-death-resist', id = 'Death' }
+Cyclopedia.clientCombat[combatStates.CLIENT_COMBAT_HEALING] = { path = '/game_cyclopedia/images/bestiary/icons/monster-icon-healing-resist', id = 'Healing' }
+Cyclopedia.clientCombat[combatStates.CLIENT_COMBAT_DROWN] = { path = '/game_cyclopedia/images/bestiary/icons/monster-icon-drown-resist', id = 'Drown' }
+Cyclopedia.clientCombat[combatStates.CLIENT_COMBAT_LIFEDRAIN] = { path = '/game_cyclopedia/images/bestiary/icons/monster-icon-lifedrain-resist', id = 'Lifedrain ' }
+Cyclopedia.clientCombat[combatStates.CLIENT_COMBAT_MANADRAIN] = { path = '/game_cyclopedia/images/bestiary/icons/monster-icon-manadrain-resist', id = 'Manadrain' }
diff --git a/modules/game_interface/interface.otmod b/modules/game_interface/interface.otmod
index aba609fb96..4572a9371b 100644
--- a/modules/game_interface/interface.otmod
+++ b/modules/game_interface/interface.otmod
@@ -45,6 +45,7 @@ Module
- game_blessing
- game_store
- game_quickloot
-
+ - game_cyclopedia
+
@onLoad: init()
@onUnload: terminate()
diff --git a/modules/game_market/market.lua b/modules/game_market/market.lua
index 49f94bd845..40912e6af4 100644
--- a/modules/game_market/market.lua
+++ b/modules/game_market/market.lua
@@ -1330,6 +1330,9 @@ function Market.loadMarketItems(category)
end
end
else
+ if not marketItems[category] then
+ return
+ end
-- loop specific category
if not marketItems[category] then
return
diff --git a/modules/game_quickloot/quickloot.lua b/modules/game_quickloot/quickloot.lua
index f3200e490c..25f2ba6c90 100644
--- a/modules/game_quickloot/quickloot.lua
+++ b/modules/game_quickloot/quickloot.lua
@@ -103,25 +103,29 @@ function QuickLoot.Define()
QuickLoot.loadFilterItems()
end
- function QuickLoot.lootExists(itemId)
- return table.contains(QuickLoot.data.loots[QuickLoot.data.filter], itemId)
+ function QuickLoot.lootExists(itemId, filter)
+ if not filter then
+ filter = QuickLoot.data.filter
+ end
+ return table.contains(QuickLoot.data.loots[filter], itemId)
end
- function QuickLoot.addLootList(itemId)
- if table.contains(QuickLoot.data.loots[QuickLoot.data.filter], itemId) then
+ function QuickLoot.addLootList(itemId,filter)
+ if not filter then
+ filter = QuickLoot.data.filter
+ end
+ if table.contains(QuickLoot.data.loots[filter], itemId) then
return
end
- table.insert(QuickLoot.data.loots[QuickLoot.data.filter], itemId)
+ table.insert(QuickLoot.data.loots[filter], itemId)
- g_game.requestQuickLootBlackWhiteList(getFilter(QuickLoot.data.filter),
- #QuickLoot.data.loots[QuickLoot.data.filter], QuickLoot.data.loots[QuickLoot.data.filter])
+ g_game.requestQuickLootBlackWhiteList(getFilter(filter),
+ #QuickLoot.data.loots[filter], QuickLoot.data.loots[filter])
if quickLootController.ui:isVisible() then
QuickLoot.loadFilterItems()
end
-
end
-
function QuickLoot.clearFilterItems()
QuickLoot.data.loots[QuickLoot.data.filter] = {}
@@ -130,16 +134,21 @@ function QuickLoot.Define()
QuickLoot.loadFilterItems()
end
- function QuickLoot.removeLootList(itemId)
-
- if not table.contains(QuickLoot.data.loots[QuickLoot.data.filter], itemId) then
+ function QuickLoot.removeLootList(itemId, filter)
+ if not filter then
+ filter = QuickLoot.data.filter
+ end
+ if not table.contains(QuickLoot.data.loots[filter], itemId) then
return
end
- table.removevalue(QuickLoot.data.loots[QuickLoot.data.filter], itemId)
+ table.removevalue(QuickLoot.data.loots[filter], itemId)
- g_game.requestQuickLootBlackWhiteList(getFilter(QuickLoot.data.filter),
- #QuickLoot.data.loots[QuickLoot.data.filter], QuickLoot.data.loots[QuickLoot.data.filter])
+ g_game.requestQuickLootBlackWhiteList(getFilter(filter),
+ #QuickLoot.data.loots[filter], QuickLoot.data.loots[filter])
+ if quickLootController.ui:isVisible() then
+ QuickLoot.loadFilterItems()
+ end
end
function QuickLoot.load()
diff --git a/modules/game_shaders/shaders.lua b/modules/game_shaders/shaders.lua
index e616606d8b..1418b29fca 100644
--- a/modules/game_shaders/shaders.lua
+++ b/modules/game_shaders/shaders.lua
@@ -65,6 +65,9 @@ OUTFIT_SHADERS = { {
}, {
name = 'Outfit - Fragmented',
frag = 'shaders/fragment/noise.frag'
+}, {
+ name = 'Outfit - cyclopedia-black',
+ frag = 'shaders/fragment/cyclopedia.frag'
}, {
name = 'Outfit - Outline',
useFramebuffer = true,
diff --git a/modules/game_shaders/shaders/fragment/cyclopedia.frag b/modules/game_shaders/shaders/fragment/cyclopedia.frag
new file mode 100644
index 0000000000..7799b7b277
--- /dev/null
+++ b/modules/game_shaders/shaders/fragment/cyclopedia.frag
@@ -0,0 +1,15 @@
+uniform float u_Time;
+uniform sampler2D u_Tex0;
+varying vec2 v_TexCoord;
+
+void main()
+{
+
+ vec4 col = texture2D(u_Tex0, v_TexCoord);
+
+ col.r = 0.0;
+ col.g = 0.0;
+ col.b = 0.0;
+
+ gl_FragColor = col;
+}
diff --git a/modules/game_textmessage/textmessage.lua b/modules/game_textmessage/textmessage.lua
index 7c5ac29a94..95174f2392 100644
--- a/modules/game_textmessage/textmessage.lua
+++ b/modules/game_textmessage/textmessage.lua
@@ -53,6 +53,12 @@ MessageSettings = {
private = {
color = TextColors.lightblue,
screenTarget = 'privateLabel'
+ },
+ loot = {
+ color = TextColors.white,
+ consoleTab = 'Loot',
+ screenTarget = 'highCenterLabel',
+ consoleOption = 'showInfoMessagesInConsole'
}
}
@@ -67,7 +73,7 @@ MessageTypes = {
[MessageModes.Status] = MessageSettings.status,
[MessageModes.Warning] = MessageSettings.centerRed,
[MessageModes.Look] = MessageSettings.centerGreen,
- [MessageModes.Loot] = MessageSettings.centerGreen,
+ [MessageModes.Loot] = MessageSettings.loot,
[MessageModes.Red] = MessageSettings.consoleRed,
[MessageModes.Blue] = MessageSettings.consoleBlue,
[MessageModes.PrivateFrom] = MessageSettings.consoleBlue,
@@ -150,8 +156,12 @@ function displayMessage(mode, text)
if msgtype.screenTarget then
local label = messagesPanel:recursiveGetChildById(msgtype.screenTarget)
- label:setText(text)
- label:setColor(msgtype.color)
+ if msgtype == MessageSettings.loot then
+ label:setColoredText(ItemsDatabase.setColorLootMessage(text)) -- temp. TODO assets search
+ else
+ label:setText(text)
+ label:setColor(msgtype.color)
+ end
label:setVisible(true)
removeEvent(label.hideEvent)
label.hideEvent = scheduleEvent(function()
diff --git a/modules/gamelib/const.lua b/modules/gamelib/const.lua
index c8fc4a0b91..77c4a262d1 100644
--- a/modules/gamelib/const.lua
+++ b/modules/gamelib/const.lua
@@ -409,4 +409,19 @@ ResourceTypes = {
COIN_TOURNAMENT = 93
};
+CyclopediaCharacterInfoTypes = {
+ BaseInformation = 0,
+ GeneralStats = 1,
+ CombatStats = 2,
+ RecentDeaths = 3,
+ RecentPVPKills = 4,
+ Achievements = 5,
+ ItemSummary = 6,
+ OutfitsAndMounts = 7,
+ StoreSummary = 8,
+ Ispection = 9,
+ Badges = 10,
+ Titles = 11
+};
+
-- @}
diff --git a/modules/gamelib/gamelib.otmod b/modules/gamelib/gamelib.otmod
index c0693291dc..61b4eb89d0 100644
--- a/modules/gamelib/gamelib.otmod
+++ b/modules/gamelib/gamelib.otmod
@@ -20,5 +20,5 @@ Module
dofile 'thing'
dofile 'spells'
dofile 'tile'
-
+ dofile 'items'
dofiles 'ui'
diff --git a/modules/gamelib/items.lua b/modules/gamelib/items.lua
new file mode 100644
index 0000000000..d453704136
--- /dev/null
+++ b/modules/gamelib/items.lua
@@ -0,0 +1,5001 @@
+-- Is temp fix : you would have to see how this reading is done in the assets editor and put it in the OTC
+-- temp. TODO assets search
+-- LuaFormatter off
+
+ItemsDatabase = {}
+
+ItemsDatabase.lib = {
+ ['yellow'] = {
+ ['gold coin'] = {
+ clientId = 3031,
+ sell = 1070000,
+ },
+ ['fiery tear'] = {
+ clientId = 39040,
+ sell = 1070000,
+ },
+ ['megalomania\'s essence'] = {
+ clientId = 33928,
+ sell = 1900000,
+ },
+ ['megalomania\'s skull'] = {
+ clientId = 33925,
+ sell = 1500000,
+ },
+ ['morshabaal\'s extract'] = {
+ clientId = 37810,
+ sell = 3250000,
+ },
+ ['figurine of cruelty'] = {
+ clientId = 34019,
+ sell = 3100000,
+ },
+ ['figurine of greed'] = {
+ clientId = 34021,
+ sell = 2900000,
+ },
+ ['figurine of hatred'] = {
+ clientId = 34020,
+ sell = 2700000,
+ },
+ ['figurine of malice'] = {
+ clientId = 34018,
+ sell = 2800000,
+ },
+ ['figurine of megalomania'] = {
+ clientId = 33953,
+ sell = 5000000,
+ },
+ ['figurine of spite'] = {
+ clientId = 33952,
+ sell = 3000000,
+ },
+ },
+ ['purple'] = {
+ ['abomination\'s eye'] = {
+ clientId = 36792,
+ sell = 650000,
+ },
+ ['abomination\'s tail'] = {
+ clientId = 36791,
+ sell = 700000,
+ },
+ ['abomination\'s tongue'] = {
+ clientId = 36793,
+ sell = 950000,
+ },
+ ['alptramun\'s toothbrush'] = {
+ clientId = 29943,
+ sell = 270000,
+ },
+ ['brain head\'s giant neuron'] = {
+ clientId = 32578,
+ sell = 100000,
+ },
+ ['brainstealer\'s brain'] = {
+ clientId = 36795,
+ sell = 300000,
+ },
+ ['brainstealer\'s brainwave'] = {
+ clientId = 36796,
+ sell = 440000,
+ },
+ ['brainstealer\'s tissue'] = {
+ clientId = 36794,
+ sell = 240000,
+ },
+ ['cheesy membership card'] = {
+ clientId = 35614,
+ sell = 120000,
+ },
+ ['cruelty\'s chest'] = {
+ clientId = 33923,
+ sell = 720000,
+ },
+ ['cruelty\'s claw'] = {
+ clientId = 33922,
+ sell = 640000,
+ },
+ ['curl of hair'] = {
+ clientId = 36809,
+ sell = 320000,
+ },
+ ['dark bell'] = {
+ clientId = 32596,
+ sell = 310000,
+ },
+ ['greed\'s arm'] = {
+ clientId = 33924,
+ sell = 950000,
+ },
+ ['grimace'] = {
+ clientId = 32593,
+ sell = 120000,
+ },
+ ['izcandar\'s snow globe'] = {
+ clientId = 29944,
+ sell = 180000,
+ },
+ ['izcandar\'s sundial'] = {
+ clientId = 29945,
+ sell = 225000,
+ },
+ ['malice\'s horn'] = {
+ clientId = 33920,
+ sell = 620000,
+ },
+ ['malice\'s spine'] = {
+ clientId = 33921,
+ sell = 850000,
+ },
+ ['malofur\'s lunchbox'] = {
+ clientId = 30088,
+ sell = 240000,
+ },
+ ['maxxenius head'] = {
+ clientId = 29942,
+ sell = 500000,
+ },
+ ['one of timira\'s many heads'] = {
+ clientId = 39399,
+ sell = 215000,
+ },
+ ['pale worm\'s scalp'] = {
+ clientId = 32598,
+ sell = 489000,
+ },
+ ['piece of timira\'s sensors'] = {
+ clientId = 39400,
+ sell = 150000,
+ },
+ ['plagueroot offshoot'] = {
+ clientId = 30087,
+ sell = 280000,
+ },
+ ['ratmiral\'s hat'] = {
+ clientId = 35613,
+ sell = 150000,
+ },
+ ['ravenous circlet'] = {
+ clientId = 32597,
+ sell = 220000,
+ },
+ ['smoldering eye'] = {
+ clientId = 39543,
+ sell = 470000,
+ },
+ ['spite\'s spirit'] = {
+ clientId = 33926,
+ sell = 840000,
+ },
+ ['token of love'] = {
+ clientId = 31594,
+ sell = 440000,
+ },
+ ['urmahlullus mane'] = {
+ clientId = 31623,
+ sell = 490000,
+ },
+ ['urmahlullus paws'] = {
+ clientId = 31624,
+ sell = 245000,
+ },
+ ['urmahlullus tail'] = {
+ clientId = 31622,
+ sell = 210000,
+ },
+ ['vial of hatred'] = {
+ clientId = 33927,
+ sell = 737000,
+ },
+ ['writhing brain'] = {
+ clientId = 32600,
+ sell = 370000,
+ },
+ ['writhing heart'] = {
+ clientId = 32599,
+ sell = 185000,
+ },
+ ['jagged sickle'] = {
+ clientId = 32595,
+ sell = 150000,
+ },
+ ['noble cape'] = {
+ clientId = 31593,
+ sell = 425000,
+ },
+ ['noble amulet'] = {
+ clientId = 31595,
+ sell = 430000,
+ },
+ ['signet ring'] = {
+ clientId = 31592,
+ sell = 480000,
+ },
+ ['beast\'s nightmare-cushion'] = {
+ clientId = 29946,
+ sell = 630000,
+ },
+ ['medal of valiance'] = {
+ clientId = 31591,
+ sell = 410000,
+ },
+ ['royal almandine'] = {
+ clientId = 39038,
+ sell = 460000,
+ },
+ ['watermelon tourmaline'] = {
+ clientId = 33780,
+ sell = 230000,
+ },
+ },
+ ['blue'] = {
+ ['amber with a bug'] = {
+ clientId = 32624,
+ sell = 41000,
+ },
+ ['amber with a dragonfly'] = {
+ clientId = 32625,
+ sell = 56000,
+ },
+ ['amber'] = {
+ clientId = 32626,
+ sell = 20000,
+ },
+ ['ancient liche bone'] = {
+ clientId = 31588,
+ sell = 28000,
+ },
+ ['bejeweled ship\'s telescope'] = {
+ clientId = 9616,
+ sell = 20000,
+ },
+ ['berserker'] = {
+ clientId = 7403,
+ sell = 40000,
+ },
+ ['bloody tears'] = {
+ clientId = 32594,
+ sell = 70000,
+ },
+ ['bones of zorvorax'] = {
+ clientId = 24942,
+ sell = 10000,
+ },
+ ['brain head\'s left hemisphere'] = {
+ clientId = 32579,
+ sell = 90000,
+ },
+ ['brain head\'s right hemisphere'] = {
+ clientId = 32580,
+ sell = 50000,
+ },
+ ['brooch of embracement'] = {
+ clientId = 34023,
+ sell = 14000,
+ },
+ ['chitinous mouth'] = {
+ clientId = 27626,
+ sell = 10000,
+ },
+ ['countess sorrow\'s frozen tear'] = {
+ clientId = 6536,
+ sell = 50000,
+ },
+ ['crest of the deep seas'] = {
+ clientId = 21892,
+ sell = 10000,
+ },
+ ['crunor idol'] = {
+ clientId = 30055,
+ sell = 30000,
+ },
+ ['diabolic skull'] = {
+ clientId = 34025,
+ sell = 19000,
+ },
+ ['dracola\'s eye'] = {
+ clientId = 6546,
+ sell = 50000,
+ },
+ ['flask of warrior\'s sweat'] = {
+ clientId = 5885,
+ sell = 10000,
+ },
+ ['giant tentacle'] = {
+ clientId = 27619,
+ sell = 10000,
+ },
+ ['goblet of gloom'] = {
+ clientId = 34022,
+ sell = 12000,
+ },
+ ['grasshopper legs'] = {
+ clientId = 14087,
+ sell = 15000,
+ },
+ ['gruesome fan'] = {
+ clientId = 34024,
+ sell = 15000,
+ },
+ ['harpoon of a giant snail'] = {
+ clientId = 27625,
+ sell = 15000,
+ },
+ ['horn of kalyassa'] = {
+ clientId = 24941,
+ sell = 10000,
+ },
+ ['huge chunk of crude iron'] = {
+ clientId = 5892,
+ sell = 15000,
+ },
+ ['huge shell'] = {
+ clientId = 27621,
+ sell = 15000,
+ },
+ ['lion figurine'] = {
+ clientId = 33781,
+ sell = 10000,
+ },
+ ['magma coat'] = {
+ clientId = 826,
+ sell = 11000,
+ },
+ ['moon pin'] = {
+ clientId = 43736,
+ sell = 18000,
+ },
+ ['morgaroth\'s heart'] = {
+ clientId = 5943,
+ sell = 15000,
+ },
+ ['morshabaal\'s brain'] = {
+ clientId = 37613,
+ sell = 15000,
+ },
+ ['mr. punish\'s handcuffs'] = {
+ clientId = 6537,
+ sell = 50000,
+ },
+ ['orshabaal\'s brain'] = {
+ clientId = 5808,
+ sell = 12000,
+ },
+ ['piece of massacre\'s shell'] = {
+ clientId = 6540,
+ sell = 50000,
+ },
+ ['pristine worm head'] = {
+ clientId = 27618,
+ sell = 15000,
+ },
+ ['rotten heart'] = {
+ clientId = 31589,
+ sell = 74000,
+ },
+ ['scale of gelidrazah'] = {
+ clientId = 24939,
+ sell = 10000,
+ },
+ ['sun brooch'] = {
+ clientId = 43737,
+ sell = 18000,
+ },
+ ['tentacle of tentugly'] = {
+ clientId = 35611,
+ sell = 27000,
+ },
+ ['tentugly\'s eye'] = {
+ clientId = 35610,
+ sell = 52000,
+ },
+ ['tentugly\'s jaws'] = {
+ clientId = 35612,
+ sell = 80000,
+ },
+ ['the handmaiden\'s protector'] = {
+ clientId = 6539,
+ sell = 50000,
+ },
+ ['the imperor\'s trident'] = {
+ clientId = 6534,
+ sell = 50000,
+ },
+ ['the plasmother\'s remains'] = {
+ clientId = 6535,
+ sell = 50000,
+ },
+ ['tooth of tazhadur'] = {
+ clientId = 24940,
+ sell = 10000,
+ },
+ ['unholy book'] = {
+ clientId = 6103,
+ sell = 30000,
+ },
+ ['young lich worm'] = {
+ clientId = 31590,
+ sell = 25000,
+ },
+ ['abyss hammer'] = {
+ clientId = 7414,
+ sell = 20000,
+ },
+ ['alloy legs'] = {
+ clientId = 21168,
+ sell = 11000,
+ },
+ ['arbalest'] = {
+ clientId = 5803,
+ sell = 42000,
+ },
+ ['arcane staff'] = {
+ clientId = 3341,
+ sell = 42000,
+ },
+ ['assassin dagger'] = {
+ clientId = 7404,
+ sell = 20000,
+ },
+ ['blade of corruption'] = {
+ clientId = 11693,
+ sell = 60000,
+ },
+ ['blessed sceptre'] = {
+ clientId = 7429,
+ sell = 40000,
+ },
+ ['bloody edge'] = {
+ clientId = 7416,
+ sell = 30000,
+ },
+ ['blue legs'] = {
+ clientId = 645,
+ sell = 15000,
+ },
+ ['blue robe'] = {
+ clientId = 3567,
+ sell = 10000,
+ },
+ ['bonebreaker'] = {
+ clientId = 7428,
+ sell = 10000,
+ },
+ ['boots of haste'] = {
+ clientId = 3079,
+ sell = 30000,
+ },
+ ['butcher\'s axe'] = {
+ clientId = 7412,
+ sell = 18000,
+ },
+ ['calopteryx cape'] = {
+ clientId = 14086,
+ sell = 15000,
+ },
+ ['carapace shield'] = {
+ clientId = 14088,
+ sell = 32000,
+ },
+ ['chain bolter'] = {
+ clientId = 8022,
+ sell = 40000,
+ },
+ ['claw of \'the noxious spawn\''] = {
+ clientId = 9392,
+ sell = 15000,
+ },
+ ['cobra crown'] = {
+ clientId = 11674,
+ sell = 50000,
+ },
+ ['composite hornbow'] = {
+ clientId = 8027,
+ sell = 25000,
+ },
+ ['cranial basher'] = {
+ clientId = 7415,
+ sell = 30000,
+ },
+ ['crown armor'] = {
+ clientId = 3381,
+ sell = 12000,
+ },
+ ['crown legs'] = {
+ clientId = 3382,
+ sell = 12000,
+ },
+ ['crystal crossbow'] = {
+ clientId = 16163,
+ sell = 35000,
+ },
+ ['crystal mace'] = {
+ clientId = 3333,
+ sell = 12000,
+ },
+ ['crystal wand'] = {
+ clientId = 3068,
+ sell = 10000,
+ },
+ ['crystalline armor'] = {
+ clientId = 8050,
+ sell = 16000,
+ },
+ ['crystalline axe'] = {
+ clientId = 16161,
+ sell = 10000,
+ },
+ ['deepling axe'] = {
+ clientId = 13991,
+ sell = 40000,
+ },
+ ['demon helmet'] = {
+ clientId = 3387,
+ sell = 40000,
+ },
+ ['demon shield'] = {
+ clientId = 3420,
+ sell = 30000,
+ },
+ ['demonbone amulet'] = {
+ clientId = 3019,
+ sell = 32000,
+ },
+ ['demonrage sword'] = {
+ clientId = 7382,
+ sell = 36000,
+ },
+ ['depth calcei'] = {
+ clientId = 13997,
+ sell = 25000,
+ },
+ ['depth galea'] = {
+ clientId = 13995,
+ sell = 35000,
+ },
+ ['depth lorica'] = {
+ clientId = 13994,
+ sell = 30000,
+ },
+ ['depth ocrea'] = {
+ clientId = 13996,
+ sell = 16000,
+ },
+ ['depth scutum'] = {
+ clientId = 13998,
+ sell = 36000,
+ },
+ ['divine plate'] = {
+ clientId = 8057,
+ sell = 55000,
+ },
+ ['djinn blade'] = {
+ clientId = 3339,
+ sell = 15000,
+ },
+ ['drachaku'] = {
+ clientId = 10391,
+ sell = 10000,
+ },
+ ['dragon robe'] = {
+ clientId = 8039,
+ sell = 50000,
+ },
+ ['dragon scale mail'] = {
+ clientId = 3386,
+ sell = 40000,
+ },
+ ['dragon slayer'] = {
+ clientId = 7402,
+ sell = 15000,
+ },
+ ['draken boots'] = {
+ clientId = 4033,
+ sell = 40000,
+ },
+ ['drakinata'] = {
+ clientId = 10388,
+ sell = 10000,
+ },
+ ['dreaded cleaver'] = {
+ clientId = 7419,
+ sell = 15000,
+ },
+ ['dwarven armor'] = {
+ clientId = 3397,
+ sell = 30000,
+ },
+ ['dwarven legs'] = {
+ clientId = 3398,
+ sell = 40000,
+ },
+ ['elite draken mail'] = {
+ clientId = 11651,
+ sell = 50000,
+ },
+ ['execowtioner axe'] = {
+ clientId = 21176,
+ sell = 12000,
+ },
+ ['executioner'] = {
+ clientId = 7453,
+ sell = 55000,
+ },
+ ['giant sword'] = {
+ clientId = 3281,
+ sell = 17000,
+ },
+ ['glacier kilt'] = {
+ clientId = 823,
+ sell = 11000,
+ },
+ ['glacier robe'] = {
+ clientId = 824,
+ sell = 11000,
+ },
+ ['golden armor'] = {
+ clientId = 3360,
+ sell = 20000,
+ },
+ ['golden legs'] = {
+ clientId = 3364,
+ sell = 30000,
+ },
+ ['greenwood coat'] = {
+ clientId = 8041,
+ sell = 50000,
+ },
+ ['guardian boots'] = {
+ clientId = 10323,
+ sell = 35000,
+ },
+ ['guardian halberd'] = {
+ clientId = 3315,
+ sell = 11000,
+ },
+ ['hammer of wrath'] = {
+ clientId = 3332,
+ sell = 30000,
+ },
+ ['heat core'] = {
+ clientId = 21167,
+ sell = 10000,
+ },
+ ['heavy mace'] = {
+ clientId = 3340,
+ sell = 50000,
+ },
+ ['heroic axe'] = {
+ clientId = 7389,
+ sell = 30000,
+ },
+ ['hive bow'] = {
+ clientId = 14246,
+ sell = 28000,
+ },
+ ['hive scythe'] = {
+ clientId = 14089,
+ sell = 17000,
+ },
+ ['jade hammer'] = {
+ clientId = 7422,
+ sell = 25000,
+ },
+ ['lavos armor'] = {
+ clientId = 8049,
+ sell = 16000,
+ },
+ ['lightning legs'] = {
+ clientId = 822,
+ sell = 11000,
+ },
+ ['lightning robe'] = {
+ clientId = 825,
+ sell = 11000,
+ },
+ ['magic plate armor'] = {
+ clientId = 3366,
+ sell = 90000,
+ },
+ ['magma legs'] = {
+ clientId = 821,
+ sell = 11000,
+ },
+ ['mastermind shield'] = {
+ clientId = 3414,
+ sell = 50000,
+ },
+ ['mercenary sword'] = {
+ clientId = 7386,
+ sell = 12000,
+ },
+ ['modified crossbow'] = {
+ clientId = 8021,
+ sell = 10000,
+ },
+ ['moohtant cudgel'] = {
+ clientId = 21173,
+ sell = 14000,
+ },
+ ['mycological bow'] = {
+ clientId = 16164,
+ sell = 35000,
+ },
+ ['mystic blade'] = {
+ clientId = 7384,
+ sell = 30000,
+ },
+ ['nightmare blade'] = {
+ clientId = 7418,
+ sell = 35000,
+ },
+ ['noble axe'] = {
+ clientId = 7456,
+ sell = 10000,
+ },
+ ['onyx flail'] = {
+ clientId = 7421,
+ sell = 22000,
+ },
+ ['oriental shoes'] = {
+ clientId = 21981,
+ sell = 15000,
+ },
+ ['ornamented axe'] = {
+ clientId = 7411,
+ sell = 20000,
+ },
+ ['ornate chestplate'] = {
+ clientId = 13993,
+ sell = 60000,
+ },
+ ['ornate crossbow'] = {
+ clientId = 14247,
+ sell = 12000,
+ },
+ ['ornate legs'] = {
+ clientId = 13999,
+ sell = 40000,
+ },
+ ['ornate mace'] = {
+ clientId = 14001,
+ sell = 42000,
+ },
+ ['ornate shield'] = {
+ clientId = 14000,
+ sell = 42000,
+ },
+ ['paladin armor'] = {
+ clientId = 8063,
+ sell = 15000,
+ },
+ ['pharaoh sword'] = {
+ clientId = 3334,
+ sell = 23000,
+ },
+ ['phoenix shield'] = {
+ clientId = 3439,
+ sell = 16000,
+ },
+ ['queen\'s sceptre'] = {
+ clientId = 7410,
+ sell = 20000,
+ },
+ ['relic sword'] = {
+ clientId = 7383,
+ sell = 25000,
+ },
+ ['rift bow'] = {
+ clientId = 22866,
+ sell = 45000,
+ },
+ ['rift crossbow'] = {
+ clientId = 22867,
+ sell = 45000,
+ },
+ ['rift lance'] = {
+ clientId = 22727,
+ sell = 30000,
+ },
+ ['rift shield'] = {
+ clientId = 22726,
+ sell = 50000,
+ },
+ ['royal axe'] = {
+ clientId = 7434,
+ sell = 40000,
+ },
+ ['royal helmet'] = {
+ clientId = 3392,
+ sell = 30000,
+ },
+ ['rubber cap'] = {
+ clientId = 21165,
+ sell = 11000,
+ },
+ ['runed sword'] = {
+ clientId = 7417,
+ sell = 45000,
+ },
+ ['ruthless axe'] = {
+ clientId = 6553,
+ sell = 45000,
+ },
+ ['sai'] = {
+ clientId = 10389,
+ sell = 16500,
+ },
+ ['shadow sceptre'] = {
+ clientId = 7451,
+ sell = 10000,
+ },
+ ['silkweaver bow'] = {
+ clientId = 8029,
+ sell = 12000,
+ },
+ ['skull helmet'] = {
+ clientId = 5741,
+ sell = 40000,
+ },
+ ['skullcracker armor'] = {
+ clientId = 8061,
+ sell = 18000,
+ },
+ ['spellbook of lost souls'] = {
+ clientId = 8075,
+ sell = 19000,
+ },
+ ['spellbook of mind control'] = {
+ clientId = 8074,
+ sell = 13000,
+ },
+ ['spellweaver\'s robe'] = {
+ clientId = 10438,
+ sell = 12000,
+ },
+ ['steel boots'] = {
+ clientId = 3554,
+ sell = 30000,
+ },
+ ['swamplair armor'] = {
+ clientId = 8052,
+ sell = 16000,
+ },
+ ['tempest shield'] = {
+ clientId = 3442,
+ sell = 35000,
+ },
+ ['terra legs'] = {
+ clientId = 812,
+ sell = 11000,
+ },
+ ['terra mantle'] = {
+ clientId = 811,
+ sell = 11000,
+ },
+ ['thaian sword'] = {
+ clientId = 7391,
+ sell = 16000,
+ },
+ ['the avenger'] = {
+ clientId = 6527,
+ sell = 42000,
+ },
+ ['the ironworker'] = {
+ clientId = 8025,
+ sell = 50000,
+ },
+ ['the justice seeker'] = {
+ clientId = 7390,
+ sell = 40000,
+ },
+ ['tiara'] = {
+ clientId = 35578,
+ sell = 11000,
+ },
+ ['twiceslicer'] = {
+ clientId = 11657,
+ sell = 28000,
+ },
+ ['vampire shield'] = {
+ clientId = 3434,
+ sell = 15000,
+ },
+ ['vile axe'] = {
+ clientId = 7388,
+ sell = 30000,
+ },
+ ['war axe'] = {
+ clientId = 3342,
+ sell = 12000,
+ },
+ ['warrior\'s axe'] = {
+ clientId = 14040,
+ sell = 11000,
+ },
+ ['windborn colossus armor'] = {
+ clientId = 8055,
+ sell = 50000,
+ },
+ ['wooden spellbook'] = {
+ clientId = 25699,
+ sell = 12000,
+ },
+ ['zaoan armor'] = {
+ clientId = 10384,
+ sell = 14000,
+ },
+ ['zaoan helmet'] = {
+ clientId = 10385,
+ sell = 45000,
+ },
+ ['zaoan legs'] = {
+ clientId = 10387,
+ sell = 14000,
+ },
+ ['zaoan robe'] = {
+ clientId = 10439,
+ sell = 12000,
+ },
+ ['zaoan sword'] = {
+ clientId = 10390,
+ sell = 30000,
+ },
+ ['amulet of loss'] = {
+ clientId = 3057,
+ sell = 45000,
+ },
+ ['ornate locket'] = {
+ clientId = 30056,
+ sell = 18000,
+ },
+ ['ring of the sky'] = {
+ clientId = 3006,
+ sell = 30000,
+ },
+ ['angel figurine'] = {
+ clientId = 32589,
+ sell = 36000,
+ },
+ ['bar of gold'] = {
+ clientId = 14112,
+ sell = 10000,
+ },
+ ['blood goblet'] = {
+ clientId = 8531,
+ sell = 10000,
+ },
+ ['ceremonial ankh'] = {
+ clientId = 6561,
+ sell = 20000,
+ },
+ ['diamond'] = {
+ clientId = 32770,
+ sell = 15000,
+ },
+ ['dragon figurine'] = {
+ clientId = 30053,
+ sell = 45000,
+ },
+ ['eldritch crystal'] = {
+ clientId = 36835,
+ sell = 48000,
+ },
+ ['frozen starlight'] = {
+ clientId = 3249,
+ sell = 20000,
+ },
+ ['giant amethyst'] = {
+ clientId = 32622,
+ sell = 60000,
+ },
+ ['giant emerald'] = {
+ clientId = 30060,
+ sell = 90000,
+ },
+ ['giant ruby'] = {
+ clientId = 30059,
+ sell = 70000,
+ },
+ ['giant sapphire'] = {
+ clientId = 30061,
+ sell = 50000,
+ },
+ ['giant topaz'] = {
+ clientId = 32623,
+ sell = 80000,
+ },
+ ['golden fafnar trophy'] = {
+ clientId = 9626,
+ sell = 10000,
+ },
+ ['golden mask'] = {
+ clientId = 31324,
+ sell = 38000,
+ },
+ ['golden sun coin'] = {
+ clientId = 43734,
+ sell = 11000,
+ },
+ ['golden tiger coin'] = {
+ clientId = 43735,
+ sell = 11000,
+ },
+ ['greater guardian gem'] = {
+ clientId = 44604,
+ sell = 10000,
+ },
+ ['greater marksman gem'] = {
+ clientId = 44607,
+ sell = 10000,
+ },
+ ['greater mystic gem'] = {
+ clientId = 44613,
+ sell = 10000,
+ },
+ ['greater sage gem'] = {
+ clientId = 44610,
+ sell = 10000,
+ },
+ ['hexagonal ruby'] = {
+ clientId = 30180,
+ sell = 30000,
+ },
+ ['moonstone'] = {
+ clientId = 32771,
+ sell = 13000,
+ },
+ ['sea horse figurine'] = {
+ clientId = 31323,
+ sell = 42000,
+ },
+ ['silver foxmouse coin'] = {
+ clientId = 43733,
+ sell = 11000,
+ },
+ ['silver hand mirror'] = {
+ clientId = 32772,
+ sell = 10000,
+ },
+ ['silver moon coin'] = {
+ clientId = 43732,
+ sell = 11000,
+ },
+ ['skull coin'] = {
+ clientId = 32583,
+ sell = 12000,
+ },
+ ['unicorn figurine'] = {
+ clientId = 30054,
+ sell = 50000,
+ },
+ ['violet gem'] = {
+ clientId = 3036,
+ sell = 10000,
+ },
+ ['watermelon tourmaline (slice)'] = {
+ clientId = 33779,
+ sell = 30000,
+ },
+ ['white gem'] = {
+ clientId = 32769,
+ sell = 12000,
+ },
+ ['egg of the many'] = {
+ clientId = 9606,
+ sell = 15000,
+ },
+ ['enchanted chicken wing'] = {
+ clientId = 5891,
+ sell = 20000,
+ },
+ ['piece of royal steel'] = {
+ clientId = 5887,
+ sell = 10000,
+ },
+ ['spirit container'] = {
+ clientId = 5884,
+ sell = 40000,
+ },
+ ['baby seal doll'] = {
+ clientId = 7183,
+ sell = 20000,
+ },
+ ['behemoth trophy'] = {
+ clientId = 7396,
+ sell = 20000,
+ },
+ ['demon trophy'] = {
+ clientId = 7393,
+ sell = 40000,
+ },
+ ['dragon lord trophy'] = {
+ clientId = 7399,
+ sell = 10000,
+ },
+ ['draken trophy'] = {
+ clientId = 10398,
+ sell = 15000,
+ },
+ ['morbid tapestry'] = {
+ clientId = 34170,
+ sell = 30000,
+ },
+ ['panda teddy'] = {
+ clientId = 5080,
+ sell = 30000,
+ },
+ ['sea serpent trophy'] = {
+ clientId = 9613,
+ sell = 10000,
+ },
+ ['werebear trophy'] = {
+ clientId = 22103,
+ sell = 11000,
+ },
+ ['wereboar trophy'] = {
+ clientId = 22102,
+ sell = 10000,
+ },
+ ['werecrocodile trophy'] = {
+ clientId = 43916,
+ sell = 15000,
+ },
+ ['werehyaena trophy'] = {
+ clientId = 34219,
+ sell = 12000,
+ },
+ ['werepanther trophy'] = {
+ clientId = 43917,
+ sell = 14000,
+ },
+ ['weretiger trophy'] = {
+ clientId = 43915,
+ sell = 14000,
+ },
+ },
+ ['green'] = {
+ ['apron'] = {
+ clientId = 33933,
+ sell = 1300,
+ },
+ ['beetle necklace'] = {
+ clientId = 10457,
+ sell = 1500,
+ },
+ ['black skull'] = {
+ clientId = 9056,
+ sell = 4000,
+ },
+ ['blemished spawn tail'] = {
+ clientId = 36780,
+ sell = 1000,
+ },
+ ['broken key ring'] = {
+ clientId = 11652,
+ sell = 8000,
+ },
+ ['broken macuahuitl'] = {
+ clientId = 40530,
+ sell = 1000,
+ },
+ ['broken ring of ending'] = {
+ clientId = 12737,
+ sell = 4000,
+ },
+ ['broken visor'] = {
+ clientId = 20184,
+ sell = 1900,
+ },
+ ['brutetamer\'s staff'] = {
+ clientId = 7379,
+ sell = 1500,
+ },
+ ['buckle'] = {
+ clientId = 17829,
+ sell = 7000,
+ },
+ ['capricious heart'] = {
+ clientId = 34138,
+ sell = 2100,
+ },
+ ['capricious robe'] = {
+ clientId = 34145,
+ sell = 1200,
+ },
+ ['cat\'s paw'] = {
+ clientId = 5479,
+ sell = 2000,
+ },
+ ['cave chimera head'] = {
+ clientId = 36787,
+ sell = 1200,
+ },
+ ['crawler\'s essence'] = {
+ clientId = 33982,
+ sell = 3700,
+ },
+ ['cursed bone'] = {
+ clientId = 32774,
+ sell = 6000,
+ },
+ ['damaged worm head'] = {
+ clientId = 27620,
+ sell = 8000,
+ },
+ ['demon horn'] = {
+ clientId = 5954,
+ sell = 1000,
+ },
+ ['demonic finger'] = {
+ clientId = 12541,
+ sell = 1000,
+ },
+ ['distorted heart'] = {
+ clientId = 34142,
+ sell = 2100,
+ },
+ ['distorted robe'] = {
+ clientId = 34149,
+ sell = 1200,
+ },
+ ['emerald tortoise shell'] = {
+ clientId = 39379,
+ sell = 2150,
+ },
+ ['enigmatic voodoo skull'] = {
+ clientId = 5669,
+ sell = 4000,
+ },
+ ['eternal flames'] = {
+ clientId = 946,
+ sell = 5000,
+ },
+ ['flower dress'] = {
+ clientId = 9015,
+ sell = 1000,
+ },
+ ['goo shell'] = {
+ clientId = 19372,
+ sell = 4000,
+ },
+ ['gore horn'] = {
+ clientId = 39377,
+ sell = 2900,
+ },
+ ['gorerilla mane'] = {
+ clientId = 39392,
+ sell = 2750,
+ },
+ ['gorerilla tail'] = {
+ clientId = 39393,
+ sell = 2650,
+ },
+ ['hand'] = {
+ clientId = 33936,
+ sell = 1450,
+ },
+ ['hazardous heart'] = {
+ clientId = 34140,
+ sell = 5000,
+ },
+ ['hazardous robe'] = {
+ clientId = 34147,
+ sell = 3000,
+ },
+ ['head'] = {
+ clientId = 33937,
+ sell = 3200,
+ },
+ ['headpecker beak'] = {
+ clientId = 39387,
+ sell = 2998,
+ },
+ ['headpecker feather'] = {
+ clientId = 39388,
+ sell = 1300,
+ },
+ ['huge spiky snail shell'] = {
+ clientId = 27627,
+ sell = 8000,
+ },
+ ['infernal heart'] = {
+ clientId = 34139,
+ sell = 2100,
+ },
+ ['infernal robe'] = {
+ clientId = 34146,
+ sell = 1200,
+ },
+ ['ivory comb'] = {
+ clientId = 32773,
+ sell = 8000,
+ },
+ ['jaws'] = {
+ clientId = 34014,
+ sell = 3900,
+ },
+ ['lavaworm jaws'] = {
+ clientId = 36771,
+ sell = 1100,
+ },
+ ['longing eyes'] = {
+ clientId = 27624,
+ sell = 8000,
+ },
+ ['luminous orb'] = {
+ clientId = 11454,
+ sell = 1000,
+ },
+ ['mantosaurus jaw'] = {
+ clientId = 39386,
+ sell = 2998,
+ },
+ ['mould heart'] = {
+ clientId = 34141,
+ sell = 2100,
+ },
+ ['mould robe'] = {
+ clientId = 34148,
+ sell = 1200,
+ },
+ ['mysterious voodoo skull'] = {
+ clientId = 5668,
+ sell = 4000,
+ },
+ ['neutral matter'] = {
+ clientId = 954,
+ sell = 5000,
+ },
+ ['nighthunter wing'] = {
+ clientId = 39381,
+ sell = 2000,
+ },
+ ['orc trophy'] = {
+ clientId = 7395,
+ sell = 1000,
+ },
+ ['pair of hellflayer horns'] = {
+ clientId = 22729,
+ sell = 1300,
+ },
+ ['pair of iron fists'] = {
+ clientId = 17828,
+ sell = 4000,
+ },
+ ['patch of fine cloth'] = {
+ clientId = 28821,
+ sell = 1350,
+ },
+ ['pharaoh banner'] = {
+ clientId = 12483,
+ sell = 1000,
+ },
+ ['porcelain mask'] = {
+ clientId = 25088,
+ sell = 2000,
+ },
+ ['prehemoth claw'] = {
+ clientId = 39383,
+ sell = 2300,
+ },
+ ['prehemoth horns'] = {
+ clientId = 39382,
+ sell = 3000,
+ },
+ ['quill'] = {
+ clientId = 28567,
+ sell = 1100,
+ },
+ ['ripptor claw'] = {
+ clientId = 39389,
+ sell = 2000,
+ },
+ ['ripptor scales'] = {
+ clientId = 39391,
+ sell = 1200,
+ },
+ ['roots'] = {
+ clientId = 33938,
+ sell = 1200,
+ },
+ ['sabretooth fur'] = {
+ clientId = 39378,
+ sell = 2500,
+ },
+ ['shamanic mask'] = {
+ clientId = 22192,
+ sell = 2000,
+ },
+ ['sight of surrender\'s eye'] = {
+ clientId = 20183,
+ sell = 3000,
+ },
+ ['silken bookmark'] = {
+ clientId = 28566,
+ sell = 1300,
+ },
+ ['single human eye'] = {
+ clientId = 25701,
+ sell = 1000,
+ },
+ ['slimy leg'] = {
+ clientId = 27623,
+ sell = 4500,
+ },
+ ['some grimeleech wings'] = {
+ clientId = 22730,
+ sell = 1200,
+ },
+ ['stalking seeds'] = {
+ clientId = 39384,
+ sell = 1800,
+ },
+ ['sulphider shell'] = {
+ clientId = 39375,
+ sell = 2200,
+ },
+ ['sulphur powder'] = {
+ clientId = 39376,
+ sell = 1900,
+ },
+ ['summer dress'] = {
+ clientId = 8046,
+ sell = 1500,
+ },
+ ['telescope eye'] = {
+ clientId = 33934,
+ sell = 1600,
+ },
+ ['tentacle piece'] = {
+ clientId = 11666,
+ sell = 5000,
+ },
+ ['undertaker fangs'] = {
+ clientId = 39380,
+ sell = 2700,
+ },
+ ['vexclaw talon'] = {
+ clientId = 22728,
+ sell = 1100,
+ },
+ ['vibrant heart'] = {
+ clientId = 34143,
+ sell = 2100,
+ },
+ ['vibrant robe'] = {
+ clientId = 34144,
+ sell = 1200,
+ },
+ ['violet glass plate'] = {
+ clientId = 29347,
+ sell = 2150,
+ },
+ ['war horn'] = {
+ clientId = 2958,
+ sell = 8000,
+ },
+ ['white silk flower'] = {
+ clientId = 34008,
+ sell = 9000,
+ },
+ ['albino plate'] = {
+ clientId = 19358,
+ sell = 1500,
+ },
+ ['amber staff'] = {
+ clientId = 7426,
+ sell = 8000,
+ },
+ ['angelic axe'] = {
+ clientId = 7436,
+ sell = 5000,
+ },
+ ['badger boots'] = {
+ clientId = 22086,
+ sell = 7500,
+ },
+ ['batwing hat'] = {
+ clientId = 9103,
+ sell = 8000,
+ },
+ ['beastslayer axe'] = {
+ clientId = 3344,
+ sell = 1500,
+ },
+ ['blacksteel sword'] = {
+ clientId = 7406,
+ sell = 6000,
+ },
+ ['bonelord helmet'] = {
+ clientId = 3408,
+ sell = 7500,
+ },
+ ['bonelord shield'] = {
+ clientId = 3418,
+ sell = 1200,
+ },
+ ['bright sword'] = {
+ clientId = 3295,
+ sell = 6000,
+ },
+ ['butterfly ring'] = {
+ clientId = 25698,
+ sell = 2000,
+ },
+ ['castle shield'] = {
+ clientId = 3435,
+ sell = 5000,
+ },
+ ['chaos mace'] = {
+ clientId = 7427,
+ sell = 9000,
+ },
+ ['cowtana'] = {
+ clientId = 21177,
+ sell = 2500,
+ },
+ ['crocodile boots'] = {
+ clientId = 3556,
+ sell = 1000,
+ },
+ ['crown helmet'] = {
+ clientId = 3385,
+ sell = 2500,
+ },
+ ['crown shield'] = {
+ clientId = 3419,
+ sell = 8000,
+ },
+ ['crusader helmet'] = {
+ clientId = 3391,
+ sell = 6000,
+ },
+ ['crystalline sword'] = {
+ clientId = 16160,
+ sell = 2000,
+ },
+ ['daramian waraxe'] = {
+ clientId = 3328,
+ sell = 1000,
+ },
+ ['death ring'] = {
+ clientId = 6299,
+ sell = 1000,
+ },
+ ['deepling squelcher'] = {
+ clientId = 14250,
+ sell = 7000,
+ },
+ ['deepling staff'] = {
+ clientId = 13987,
+ sell = 4000,
+ },
+ ['devil helmet'] = {
+ clientId = 3356,
+ sell = 1000,
+ },
+ ['diamond sceptre'] = {
+ clientId = 7387,
+ sell = 3000,
+ },
+ ['dragon hammer'] = {
+ clientId = 3322,
+ sell = 2000,
+ },
+ ['dragon lance'] = {
+ clientId = 3302,
+ sell = 9000,
+ },
+ ['dragon shield'] = {
+ clientId = 3416,
+ sell = 4000,
+ },
+ ['dragonbone staff'] = {
+ clientId = 7430,
+ sell = 3000,
+ },
+ ['dream blossom staff'] = {
+ clientId = 25700,
+ sell = 5000,
+ },
+ ['dwarven axe'] = {
+ clientId = 3323,
+ sell = 1500,
+ },
+ ['elvish bow'] = {
+ clientId = 7438,
+ sell = 2000,
+ },
+ ['epee'] = {
+ clientId = 3326,
+ sell = 8000,
+ },
+ ['fire axe'] = {
+ clientId = 3320,
+ sell = 8000,
+ },
+ ['fire sword'] = {
+ clientId = 3280,
+ sell = 4000,
+ },
+ ['focus cape'] = {
+ clientId = 8043,
+ sell = 6000,
+ },
+ ['fur armor'] = {
+ clientId = 22085,
+ sell = 5000,
+ },
+ ['fur boots'] = {
+ clientId = 7457,
+ sell = 2000,
+ },
+ ['furry club'] = {
+ clientId = 7432,
+ sell = 1000,
+ },
+ ['glacial rod'] = {
+ clientId = 16118,
+ sell = 6500,
+ },
+ ['glacier amulet'] = {
+ clientId = 815,
+ sell = 1500,
+ },
+ ['glacier mask'] = {
+ clientId = 829,
+ sell = 2500,
+ },
+ ['glacier shoes'] = {
+ clientId = 819,
+ sell = 2500,
+ },
+ ['glooth axe'] = {
+ clientId = 21180,
+ sell = 1500,
+ },
+ ['glooth blade'] = {
+ clientId = 21179,
+ sell = 1500,
+ },
+ ['glooth cap'] = {
+ clientId = 21164,
+ sell = 7000,
+ },
+ ['glooth club'] = {
+ clientId = 21178,
+ sell = 1500,
+ },
+ ['glooth whip'] = {
+ clientId = 21172,
+ sell = 2500,
+ },
+ ['glorious axe'] = {
+ clientId = 7454,
+ sell = 3000,
+ },
+ ['griffin shield'] = {
+ clientId = 3433,
+ sell = 3000,
+ },
+ ['guardian axe'] = {
+ clientId = 14043,
+ sell = 9000,
+ },
+ ['guardian shield'] = {
+ clientId = 3415,
+ sell = 2000,
+ },
+ ['hailstorm rod'] = {
+ clientId = 3067,
+ sell = 3000,
+ },
+ ['haunted blade'] = {
+ clientId = 7407,
+ sell = 8000,
+ },
+ ['headchopper'] = {
+ clientId = 7380,
+ sell = 6000,
+ },
+ ['heavy trident'] = {
+ clientId = 12683,
+ sell = 2000,
+ },
+ ['helmet of the lost'] = {
+ clientId = 17852,
+ sell = 2000,
+ },
+ ['hibiscus dress'] = {
+ clientId = 8045,
+ sell = 3000,
+ },
+ ['ice rapier'] = {
+ clientId = 3284,
+ sell = 1000,
+ },
+ ['jade hat'] = {
+ clientId = 10451,
+ sell = 9000,
+ },
+ ['knight armor'] = {
+ clientId = 3370,
+ sell = 5000,
+ },
+ ['knight axe'] = {
+ clientId = 3318,
+ sell = 2000,
+ },
+ ['knight legs'] = {
+ clientId = 3371,
+ sell = 5000,
+ },
+ ['leopard armor'] = {
+ clientId = 3404,
+ sell = 1000,
+ },
+ ['lightning boots'] = {
+ clientId = 820,
+ sell = 2500,
+ },
+ ['lightning headband'] = {
+ clientId = 828,
+ sell = 2500,
+ },
+ ['lightning pendant'] = {
+ clientId = 816,
+ sell = 1500,
+ },
+ ['lunar staff'] = {
+ clientId = 7424,
+ sell = 5000,
+ },
+ ['magma boots'] = {
+ clientId = 818,
+ sell = 2500,
+ },
+ ['magma monocle'] = {
+ clientId = 827,
+ sell = 2500,
+ },
+ ['mammoth fur cape'] = {
+ clientId = 7463,
+ sell = 6000,
+ },
+ ['medusa shield'] = {
+ clientId = 3436,
+ sell = 9000,
+ },
+ ['mercurial wing'] = {
+ clientId = 39395,
+ sell = 2500,
+ },
+ ['metal bat'] = {
+ clientId = 21171,
+ sell = 9000,
+ },
+ ['metal spats'] = {
+ clientId = 21169,
+ sell = 2000,
+ },
+ ['mino lance'] = {
+ clientId = 21174,
+ sell = 7000,
+ },
+ ['mino shield'] = {
+ clientId = 21175,
+ sell = 3000,
+ },
+ ['mooh\'tah plate'] = {
+ clientId = 21166,
+ sell = 6000,
+ },
+ ['muck rod'] = {
+ clientId = 16117,
+ sell = 6000,
+ },
+ ['naginata'] = {
+ clientId = 3314,
+ sell = 2000,
+ },
+ ['necrotic rod'] = {
+ clientId = 3069,
+ sell = 1000,
+ },
+ ['norse shield'] = {
+ clientId = 7460,
+ sell = 1500,
+ },
+ ['northwind rod'] = {
+ clientId = 8083,
+ sell = 1500,
+ },
+ ['ogre choppa'] = {
+ clientId = 22172,
+ sell = 1500,
+ },
+ ['ogre klubba'] = {
+ clientId = 22171,
+ sell = 2500,
+ },
+ ['ogre scepta'] = {
+ clientId = 22183,
+ sell = 3600,
+ },
+ ['orcish maul'] = {
+ clientId = 7392,
+ sell = 6000,
+ },
+ ['ornamented shield'] = {
+ clientId = 3424,
+ sell = 1500,
+ },
+ ['patched boots'] = {
+ clientId = 3550,
+ sell = 2000,
+ },
+ ['platinum amulet'] = {
+ clientId = 3055,
+ sell = 2500,
+ },
+ ['rod'] = {
+ clientId = 33929,
+ sell = 2200,
+ },
+ ['sapphire hammer'] = {
+ clientId = 7437,
+ sell = 7000,
+ },
+ ['scarab shield'] = {
+ clientId = 3440,
+ sell = 2000,
+ },
+ ['skull staff'] = {
+ clientId = 3324,
+ sell = 6000,
+ },
+ ['spellbook of enlightenment'] = {
+ clientId = 8072,
+ sell = 4000,
+ },
+ ['spellbook of warding'] = {
+ clientId = 8073,
+ sell = 8000,
+ },
+ ['spike sword'] = {
+ clientId = 3271,
+ sell = 1000,
+ },
+ ['spiked squelcher'] = {
+ clientId = 7452,
+ sell = 5000,
+ },
+ ['springsprout rod'] = {
+ clientId = 8084,
+ sell = 3600,
+ },
+ ['terra boots'] = {
+ clientId = 813,
+ sell = 2500,
+ },
+ ['terra hood'] = {
+ clientId = 830,
+ sell = 2500,
+ },
+ ['terra rod'] = {
+ clientId = 3065,
+ sell = 2000,
+ },
+ ['titan axe'] = {
+ clientId = 7413,
+ sell = 4000,
+ },
+ ['tower shield'] = {
+ clientId = 3428,
+ sell = 8000,
+ },
+ ['underworld rod'] = {
+ clientId = 8082,
+ sell = 4400,
+ },
+ ['wand of cosmic energy'] = {
+ clientId = 3073,
+ sell = 2000,
+ },
+ ['wand of decay'] = {
+ clientId = 3072,
+ sell = 1000,
+ },
+ ['wand of defiance'] = {
+ clientId = 16096,
+ sell = 6500,
+ },
+ ['wand of draconia'] = {
+ clientId = 8093,
+ sell = 1500,
+ },
+ ['wand of everblazing'] = {
+ clientId = 16115,
+ sell = 6000,
+ },
+ ['wand of inferno'] = {
+ clientId = 3071,
+ sell = 3000,
+ },
+ ['wand of starstorm'] = {
+ clientId = 8092,
+ sell = 3600,
+ },
+ ['wand of voodoo'] = {
+ clientId = 8094,
+ sell = 4400,
+ },
+ ['war hammer'] = {
+ clientId = 3279,
+ sell = 1200,
+ },
+ ['warrior helmet'] = {
+ clientId = 3369,
+ sell = 5000,
+ },
+ ['warrior\'s shield'] = {
+ clientId = 14042,
+ sell = 9000,
+ },
+ ['wereboar loincloth'] = {
+ clientId = 22087,
+ sell = 1500,
+ },
+ ['witch hat'] = {
+ clientId = 9653,
+ sell = 5000,
+ },
+ ['wood cape'] = {
+ clientId = 3575,
+ sell = 5000,
+ },
+ ['wyvern fang'] = {
+ clientId = 7408,
+ sell = 1500,
+ },
+ ['zaoan shoes'] = {
+ clientId = 10386,
+ sell = 5000,
+ },
+ ['collar of blue plasma'] = {
+ clientId = 23542,
+ sell = 6000,
+ },
+ ['collar of green plasma'] = {
+ clientId = 23543,
+ sell = 6000,
+ },
+ ['collar of red plasma'] = {
+ clientId = 23544,
+ sell = 6000,
+ },
+ ['gearwheel chain'] = {
+ clientId = 21170,
+ sell = 5000,
+ },
+ ['glooth amulet'] = {
+ clientId = 21183,
+ sell = 2000,
+ },
+ ['leviathan\'s amulet'] = {
+ clientId = 9303,
+ sell = 3000,
+ },
+ ['magma amulet'] = {
+ clientId = 817,
+ sell = 1500,
+ },
+ ['onyx pendant'] = {
+ clientId = 22195,
+ sell = 3500,
+ },
+ ['ruby necklace'] = {
+ clientId = 3016,
+ sell = 2000,
+ },
+ ['sacred tree amulet'] = {
+ clientId = 9302,
+ sell = 3000,
+ },
+ ['shockwave amulet'] = {
+ clientId = 9304,
+ sell = 3000,
+ },
+ ['terra amulet'] = {
+ clientId = 814,
+ sell = 1500,
+ },
+ ['wailing widow\'s necklace'] = {
+ clientId = 10412,
+ sell = 3000,
+ },
+ ['werewolf amulet'] = {
+ clientId = 22060,
+ sell = 3000,
+ },
+ ['ring of blue plasma'] = {
+ clientId = 23529,
+ sell = 8000,
+ },
+ ['ring of green plasma'] = {
+ clientId = 23531,
+ sell = 8000,
+ },
+ ['ring of red plasma'] = {
+ clientId = 23533,
+ sell = 8000,
+ },
+ ['blue crystal shard'] = {
+ clientId = 16119,
+ sell = 1500,
+ },
+ ['blue gem'] = {
+ clientId = 3041,
+ sell = 5000,
+ },
+ ['brown giant shimmering pearl'] = {
+ clientId = 282,
+ sell = 3000,
+ },
+ ['crown'] = {
+ clientId = 33935,
+ sell = 2700,
+ },
+ ['cry-stal'] = {
+ clientId = 39394,
+ sell = 3200,
+ },
+ ['crystal of balance'] = {
+ clientId = 9028,
+ sell = 1000,
+ },
+ ['crystal of focus'] = {
+ clientId = 9027,
+ sell = 2000,
+ },
+ ['crystal of power'] = {
+ clientId = 9067,
+ sell = 3000,
+ },
+ ['death toll'] = {
+ clientId = 32703,
+ sell = 1000,
+ },
+ ['flawless ice crystal'] = {
+ clientId = 942,
+ sell = 5000,
+ },
+ ['gemmed figurine'] = {
+ clientId = 24392,
+ sell = 3500,
+ },
+ ['gold ingot'] = {
+ clientId = 9058,
+ sell = 5000,
+ },
+ ['gold ring'] = {
+ clientId = 3063,
+ sell = 8000,
+ },
+ ['golden amulet'] = {
+ clientId = 3013,
+ sell = 2000,
+ },
+ ['golden cheese wedge'] = {
+ clientId = 35581,
+ sell = 6000,
+ },
+ ['golden dustbin'] = {
+ clientId = 35579,
+ sell = 7000,
+ },
+ ['golden figurine'] = {
+ clientId = 5799,
+ sell = 3000,
+ },
+ ['golden sickle'] = {
+ clientId = 3306,
+ sell = 1000,
+ },
+ ['golden skull'] = {
+ clientId = 35580,
+ sell = 9000,
+ },
+ ['green crystal shard'] = {
+ clientId = 16121,
+ sell = 1500,
+ },
+ ['green gem'] = {
+ clientId = 3038,
+ sell = 5000,
+ },
+ ['green giant shimmering pearl'] = {
+ clientId = 281,
+ sell = 3000,
+ },
+ ['guardian gem'] = {
+ clientId = 44603,
+ sell = 5000,
+ },
+ ['lesser guardian gem'] = {
+ clientId = 44602,
+ sell = 1000,
+ },
+ ['lesser marksman gem'] = {
+ clientId = 44605,
+ sell = 1000,
+ },
+ ['lesser mystic gem'] = {
+ clientId = 44611,
+ sell = 1000,
+ },
+ ['lesser sage gem'] = {
+ clientId = 44608,
+ sell = 1000,
+ },
+ ['marksman gem'] = {
+ clientId = 44606,
+ sell = 5000,
+ },
+ ['mystic gem'] = {
+ clientId = 44612,
+ sell = 5000,
+ },
+ ['purple tome'] = {
+ clientId = 2848,
+ sell = 2000,
+ },
+ ['red gem'] = {
+ clientId = 3039,
+ sell = 1000,
+ },
+ ['red tome'] = {
+ clientId = 2852,
+ sell = 2000,
+ },
+ ['sage gem'] = {
+ clientId = 44609,
+ sell = 5000,
+ },
+ ['silver rune emblem explosion'] = {
+ clientId = 11607,
+ sell = 5000,
+ },
+ ['silver rune emblem heavy magic missile'] = {
+ clientId = 11605,
+ sell = 5000,
+ },
+ ['silver rune emblem sudden death'] = {
+ clientId = 11609,
+ sell = 5000,
+ },
+ ['silver rune emblem ultimate healing'] = {
+ clientId = 11603,
+ sell = 5000,
+ },
+ ['violet crystal shard'] = {
+ clientId = 16120,
+ sell = 1500,
+ },
+ ['yellow gem'] = {
+ clientId = 3037,
+ sell = 1000,
+ },
+ ['behemoth claw'] = {
+ clientId = 5930,
+ sell = 2000,
+ },
+ ['demonic essence'] = {
+ clientId = 6499,
+ sell = 1000,
+ },
+ ['dragon claw'] = {
+ clientId = 5919,
+ sell = 8000,
+ },
+ ['iced soil'] = {
+ clientId = 944,
+ sell = 2000,
+ },
+ ['energy soil'] = {
+ clientId = 945,
+ sell = 2000,
+ },
+ ['magic sulphur'] = {
+ clientId = 5904,
+ sell = 8000,
+ },
+ ['mandrake'] = {
+ clientId = 5014,
+ sell = 5000,
+ },
+ ['mother soil'] = {
+ clientId = 947,
+ sell = 5000,
+ },
+ ['natural soil'] = {
+ clientId = 940,
+ sell = 2000,
+ },
+ ['necklace of the deep'] = {
+ clientId = 13990,
+ sell = 3000,
+ },
+ ['nose ring'] = {
+ clientId = 5804,
+ sell = 2000,
+ },
+ ['piece of draconian steel'] = {
+ clientId = 5889,
+ sell = 3000,
+ },
+ ['shard'] = {
+ clientId = 7290,
+ sell = 2000,
+ },
+ ['sniper gloves'] = {
+ clientId = 5875,
+ sell = 2000,
+ },
+ ['soul stone'] = {
+ clientId = 5809,
+ sell = 6000,
+ },
+ ['spool of yarn'] = {
+ clientId = 5886,
+ sell = 1000,
+ },
+ ['bat decoration'] = {
+ clientId = 6491,
+ sell = 2000,
+ },
+ ['bonebeast trophy'] = {
+ clientId = 10244,
+ sell = 6000,
+ },
+ ['deer trophy'] = {
+ clientId = 7397,
+ sell = 3000,
+ },
+ ['disgusting trophy'] = {
+ clientId = 10421,
+ sell = 3000,
+ },
+ ['dracoyle statue'] = {
+ clientId = 9034,
+ sell = 5000,
+ },
+ ['lion trophy'] = {
+ clientId = 7400,
+ sell = 3000,
+ },
+ ['lizard trophy'] = {
+ clientId = 10419,
+ sell = 8000,
+ },
+ ['marlin trophy'] = {
+ clientId = 902,
+ sell = 5000,
+ },
+ ['model ship'] = {
+ clientId = 2994,
+ sell = 1000,
+ },
+ ['pet pig'] = {
+ clientId = 16165,
+ sell = 1500,
+ },
+ ['silver fafnar trophy'] = {
+ clientId = 9627,
+ sell = 1000,
+ },
+ ['skeleton decoration'] = {
+ clientId = 6525,
+ sell = 3000,
+ },
+ ['souleater trophy'] = {
+ clientId = 11679,
+ sell = 7500,
+ },
+ ['statue of abyssador'] = {
+ clientId = 16232,
+ sell = 4000,
+ },
+ ['statue of deathstrike'] = {
+ clientId = 16236,
+ sell = 3000,
+ },
+ ['statue of devovorga'] = {
+ clientId = 4065,
+ sell = 1500,
+ },
+ ['statue of gnomevil'] = {
+ clientId = 16240,
+ sell = 2000,
+ },
+ ['stuffed dragon'] = {
+ clientId = 5791,
+ sell = 6000,
+ },
+ ['trophy of jaul'] = {
+ clientId = 14006,
+ sell = 4000,
+ },
+ ['trophy of obujos'] = {
+ clientId = 14002,
+ sell = 3000,
+ },
+ ['trophy of tanjis'] = {
+ clientId = 14004,
+ sell = 2000,
+ },
+ ['werebadger trophy'] = {
+ clientId = 22101,
+ sell = 9000,
+ },
+ ['werefox trophy'] = {
+ clientId = 27706,
+ sell = 9000,
+ },
+ ['wolf trophy'] = {
+ clientId = 7394,
+ sell = 3000,
+ },
+ },
+ ['grey'] = {
+ ['afflicted strider head'] = {
+ clientId = 36789,
+ sell = 900,
+ },
+ ['afflicted strider worms'] = {
+ clientId = 36790,
+ sell = 500,
+ },
+ ['ancient belt buckle'] = {
+ clientId = 24384,
+ sell = 260,
+ },
+ ['antlers'] = {
+ clientId = 10297,
+ sell = 50,
+ },
+ ['banana sash'] = {
+ clientId = 11511,
+ sell = 55,
+ },
+ ['basalt fetish'] = {
+ clientId = 17856,
+ sell = 210,
+ },
+ ['bashmu fang'] = {
+ clientId = 36820,
+ sell = 600,
+ },
+ ['bashmu feather'] = {
+ clientId = 36823,
+ sell = 350,
+ },
+ ['bashmu tongue'] = {
+ clientId = 36821,
+ sell = 400,
+ },
+ ['bed of nails'] = {
+ clientId = 25743,
+ sell = 500,
+ },
+ ['beer tap'] = {
+ clientId = 32114,
+ sell = 50,
+ },
+ ['beetle carapace'] = {
+ clientId = 24381,
+ sell = 200,
+ },
+ ['black hood'] = {
+ clientId = 9645,
+ sell = 190,
+ },
+ ['black wool'] = {
+ clientId = 11448,
+ sell = 300,
+ },
+ ['blazing bone'] = {
+ clientId = 16131,
+ sell = 610,
+ },
+ ['blemished spawn abdomen'] = {
+ clientId = 36779,
+ sell = 550,
+ },
+ ['blemished spawn head'] = {
+ clientId = 36778,
+ sell = 800,
+ },
+ ['blood preservation'] = {
+ clientId = 11449,
+ sell = 320,
+ },
+ ['blood tincture in a vial'] = {
+ clientId = 18928,
+ sell = 360,
+ },
+ ['bloody dwarven beard'] = {
+ clientId = 17827,
+ sell = 110,
+ },
+ ['bloody pincers'] = {
+ clientId = 9633,
+ sell = 100,
+ },
+ ['blue glass plate'] = {
+ clientId = 29345,
+ sell = 60,
+ },
+ ['blue goanna scale'] = {
+ clientId = 31559,
+ sell = 230,
+ },
+ ['boar man hoof'] = {
+ clientId = 40584,
+ sell = 600,
+ },
+ ['boggy dreads'] = {
+ clientId = 9667,
+ sell = 200,
+ },
+ ['bone fetish'] = {
+ clientId = 17831,
+ sell = 150,
+ },
+ ['bone shoulderplate'] = {
+ clientId = 10404,
+ sell = 150,
+ },
+ ['bone toothpick'] = {
+ clientId = 24380,
+ sell = 150,
+ },
+ ['bonecarving knife'] = {
+ clientId = 17830,
+ sell = 190,
+ },
+ ['bony tail'] = {
+ clientId = 10277,
+ sell = 210,
+ },
+ ['book of necromantic rituals'] = {
+ clientId = 10320,
+ sell = 180,
+ },
+ ['book of prayers'] = {
+ clientId = 9646,
+ sell = 120,
+ },
+ ['book page'] = {
+ clientId = 28569,
+ sell = 640,
+ },
+ ['bowl of terror sweat'] = {
+ clientId = 20204,
+ sell = 500,
+ },
+ ['bright bell'] = {
+ clientId = 30324,
+ sell = 220,
+ },
+ ['brimstone fangs'] = {
+ clientId = 11702,
+ sell = 380,
+ },
+ ['brimstone shell'] = {
+ clientId = 11703,
+ sell = 210,
+ },
+ ['broken bell'] = {
+ clientId = 30185,
+ sell = 150,
+ },
+ ['broken draken mail'] = {
+ clientId = 11660,
+ sell = 340,
+ },
+ ['broken gladiator shield'] = {
+ clientId = 9656,
+ sell = 190,
+ },
+ ['broken halberd'] = {
+ clientId = 10418,
+ sell = 100,
+ },
+ ['broken iks faulds'] = {
+ clientId = 40531,
+ sell = 530,
+ },
+ ['broken iks headpiece'] = {
+ clientId = 40532,
+ sell = 560,
+ },
+ ['broken iks sandals'] = {
+ clientId = 40534,
+ sell = 440,
+ },
+ ['broken longbow'] = {
+ clientId = 34161,
+ sell = 130,
+ },
+ ['broken slicer'] = {
+ clientId = 11661,
+ sell = 120,
+ },
+ ['broken throwing axe'] = {
+ clientId = 17851,
+ sell = 230,
+ },
+ ['bunch of ripe rice'] = {
+ clientId = 10328,
+ sell = 75,
+ },
+ ['bundle of cursed straw'] = {
+ clientId = 9688,
+ sell = 800,
+ },
+ ['carniphila seeds'] = {
+ clientId = 10300,
+ sell = 50,
+ },
+ ['carnisylvan bark'] = {
+ clientId = 36806,
+ sell = 230,
+ },
+ ['carnisylvan finger'] = {
+ clientId = 36805,
+ sell = 250,
+ },
+ ['carnivostrich feathers'] = {
+ clientId = 40586,
+ sell = 550,
+ },
+ ['cave chimera leg'] = {
+ clientId = 36788,
+ sell = 650,
+ },
+ ['cave devourer eyes'] = {
+ clientId = 27599,
+ sell = 550,
+ },
+ ['cave devourer legs'] = {
+ clientId = 27601,
+ sell = 350,
+ },
+ ['cave devourer maw'] = {
+ clientId = 27600,
+ sell = 600,
+ },
+ ['cavebear skull'] = {
+ clientId = 12316,
+ sell = 550,
+ },
+ ['chasm spawn abdomen'] = {
+ clientId = 27603,
+ sell = 240,
+ },
+ ['chasm spawn head'] = {
+ clientId = 27602,
+ sell = 850,
+ },
+ ['chasm spawn tail'] = {
+ clientId = 27604,
+ sell = 120,
+ },
+ ['cheese cutter'] = {
+ clientId = 17817,
+ sell = 50,
+ },
+ ['cheesy figurine'] = {
+ clientId = 17818,
+ sell = 150,
+ },
+ ['cliff strider claw'] = {
+ clientId = 16134,
+ sell = 800,
+ },
+ ['closed trap'] = {
+ clientId = 3481,
+ sell = 75,
+ },
+ ['cobra crest'] = {
+ clientId = 31678,
+ sell = 650,
+ },
+ ['colourful feather'] = {
+ clientId = 11514,
+ sell = 110,
+ },
+ ['colourful feathers'] = {
+ clientId = 25089,
+ sell = 400,
+ },
+ ['colourful snail shell'] = {
+ clientId = 25696,
+ sell = 250,
+ },
+ ['compound eye'] = {
+ clientId = 14083,
+ sell = 150,
+ },
+ ['condensed energy'] = {
+ clientId = 23501,
+ sell = 260,
+ },
+ ['coral branch'] = {
+ clientId = 39406,
+ sell = 360,
+ },
+ ['coral brooch'] = {
+ clientId = 24391,
+ sell = 750,
+ },
+ ['corrupt naga scales'] = {
+ clientId = 39415,
+ sell = 570,
+ },
+ ['corrupted flag'] = {
+ clientId = 10409,
+ sell = 700,
+ },
+ ['cow bell'] = {
+ clientId = 32012,
+ sell = 120,
+ },
+ ['cowbell'] = {
+ clientId = 21204,
+ sell = 210,
+ },
+ ['crab man claw'] = {
+ clientId = 40582,
+ sell = 550,
+ },
+ ['crawler head plating'] = {
+ clientId = 14079,
+ sell = 210,
+ },
+ ['crystal bone'] = {
+ clientId = 23521,
+ sell = 250,
+ },
+ ['cultish mask'] = {
+ clientId = 9638,
+ sell = 280,
+ },
+ ['cultish robe'] = {
+ clientId = 9639,
+ sell = 150,
+ },
+ ['cultish symbol'] = {
+ clientId = 11455,
+ sell = 500,
+ },
+ ['curious matter'] = {
+ clientId = 23511,
+ sell = 430,
+ },
+ ['cursed shoulder spikes'] = {
+ clientId = 10410,
+ sell = 320,
+ },
+ ['cyclops toe'] = {
+ clientId = 9657,
+ sell = 55,
+ },
+ ['daedal chisel'] = {
+ clientId = 40522,
+ sell = 480,
+ },
+ ['damaged armor plates'] = {
+ clientId = 28822,
+ sell = 280,
+ },
+ ['dandelion seeds'] = {
+ clientId = 25695,
+ sell = 200,
+ },
+ ['dangerous proto matter'] = {
+ clientId = 23515,
+ sell = 300,
+ },
+ ['dark bell'] = {
+ clientId = 30325,
+ sell = 250,
+ },
+ ['dead weight'] = {
+ clientId = 20202,
+ sell = 450,
+ },
+ ['deepling breaktime snack'] = {
+ clientId = 14011,
+ sell = 90,
+ },
+ ['deepling claw'] = {
+ clientId = 14044,
+ sell = 430,
+ },
+ ['deepling guard belt buckle'] = {
+ clientId = 14010,
+ sell = 230,
+ },
+ ['deepling ridge'] = {
+ clientId = 14041,
+ sell = 360,
+ },
+ ['deepling scales'] = {
+ clientId = 14017,
+ sell = 80,
+ },
+ ['deepling warts'] = {
+ clientId = 14012,
+ sell = 180,
+ },
+ ['deeptags'] = {
+ clientId = 14013,
+ sell = 290,
+ },
+ ['deepworm jaws'] = {
+ clientId = 27594,
+ sell = 500,
+ },
+ ['deepworm spike roots'] = {
+ clientId = 27593,
+ sell = 650,
+ },
+ ['deepworm spikes'] = {
+ clientId = 27592,
+ sell = 800,
+ },
+ ['demonic skeletal hand'] = {
+ clientId = 9647,
+ sell = 80,
+ },
+ ['diremaw brainpan'] = {
+ clientId = 27597,
+ sell = 350,
+ },
+ ['diremaw legs'] = {
+ clientId = 27598,
+ sell = 270,
+ },
+ ['dirty turban'] = {
+ clientId = 11456,
+ sell = 120,
+ },
+ ['dragon blood'] = {
+ clientId = 24937,
+ sell = 700,
+ },
+ ['dragon priest\'s wandtip'] = {
+ clientId = 10444,
+ sell = 175,
+ },
+ ['dragon tongue'] = {
+ clientId = 24938,
+ sell = 550,
+ },
+ ['dragon\'s tail'] = {
+ clientId = 11457,
+ sell = 100,
+ },
+ ['draken sulphur'] = {
+ clientId = 11658,
+ sell = 550,
+ },
+ ['draken wristbands'] = {
+ clientId = 11659,
+ sell = 430,
+ },
+ ['draptor scales'] = {
+ clientId = 12309,
+ sell = 800,
+ },
+ ['dream essence egg'] = {
+ clientId = 30005,
+ sell = 205,
+ },
+ ['dung ball'] = {
+ clientId = 14225,
+ sell = 130,
+ },
+ ['elder bonelord tentacle'] = {
+ clientId = 10276,
+ sell = 150,
+ },
+ ['elven astral observer'] = {
+ clientId = 11465,
+ sell = 90,
+ },
+ ['elven hoof'] = {
+ clientId = 18994,
+ sell = 115,
+ },
+ ['elven scouting glass'] = {
+ clientId = 11464,
+ sell = 50,
+ },
+ ['empty honey glass'] = {
+ clientId = 31331,
+ sell = 270,
+ },
+ ['energy ball'] = {
+ clientId = 23523,
+ sell = 300,
+ },
+ ['energy vein'] = {
+ clientId = 23508,
+ sell = 270,
+ },
+ ['ensouled essence'] = {
+ clientId = 32698,
+ sell = 820,
+ },
+ ['essence of a bad dream'] = {
+ clientId = 10306,
+ sell = 360,
+ },
+ ['execowtioner mask'] = {
+ clientId = 21201,
+ sell = 240,
+ },
+ ['ethno coat'] = {
+ clientId = 8064,
+ sell = 200,
+ },
+ ['eye of a deepling'] = {
+ clientId = 12730,
+ sell = 150,
+ },
+ ['eye of a weeper'] = {
+ clientId = 16132,
+ sell = 650,
+ },
+ ['eye of corruption'] = {
+ clientId = 11671,
+ sell = 390,
+ },
+ ['eyeless devourer legs'] = {
+ clientId = 36776,
+ sell = 650,
+ },
+ ['eyeless devourer maw'] = {
+ clientId = 36775,
+ sell = 420,
+ },
+ ['eyeless devourer tongue'] = {
+ clientId = 36777,
+ sell = 900,
+ },
+ ['fafnar symbol'] = {
+ clientId = 31443,
+ sell = 950,
+ },
+ ['fairy wings'] = {
+ clientId = 25694,
+ sell = 200,
+ },
+ ['falcon crest'] = {
+ clientId = 28823,
+ sell = 650,
+ },
+ ['fiery heart'] = {
+ clientId = 9636,
+ sell = 375,
+ },
+ ['fig leaf'] = {
+ clientId = 25742,
+ sell = 200,
+ },
+ ['flotsam'] = {
+ clientId = 39407,
+ sell = 330,
+ },
+ ['flower wreath'] = {
+ clientId = 9013,
+ sell = 500,
+ },
+ ['fox paw'] = {
+ clientId = 27462,
+ sell = 100,
+ },
+ ['frazzle skin'] = {
+ clientId = 20199,
+ sell = 400,
+ },
+ ['frazzle tongue'] = {
+ clientId = 20198,
+ sell = 700,
+ },
+ ['frost giant pelt'] = {
+ clientId = 9658,
+ sell = 160,
+ },
+ ['frosty heart'] = {
+ clientId = 9661,
+ sell = 280,
+ },
+ ['gauze bandage'] = {
+ clientId = 9649,
+ sell = 90,
+ },
+ ['gear crystal'] = {
+ clientId = 9655,
+ sell = 200,
+ },
+ ['gear wheel'] = {
+ clientId = 8775,
+ sell = 500,
+ },
+ ['fur shred'] = {
+ clientId = 34164,
+ sell = 200,
+ },
+ ['geomancer\'s robe'] = {
+ clientId = 11458,
+ sell = 80,
+ },
+ ['geomancer\'s staff'] = {
+ clientId = 11463,
+ sell = 120,
+ },
+ ['ghastly dragon head'] = {
+ clientId = 10449,
+ sell = 700,
+ },
+ ['ghostly tissue'] = {
+ clientId = 9690,
+ sell = 90,
+ },
+ ['ghoul snack'] = {
+ clientId = 11467,
+ sell = 60,
+ },
+ ['giant crab pincer'] = {
+ clientId = 12317,
+ sell = 950,
+ },
+ ['giant eye'] = {
+ clientId = 10280,
+ sell = 380,
+ },
+ ['girtablilu warrior carapace'] = {
+ clientId = 36971,
+ sell = 520,
+ },
+ ['gland'] = {
+ clientId = 8143,
+ sell = 500,
+ },
+ ['glistening bone'] = {
+ clientId = 23522,
+ sell = 250,
+ },
+ ['glob of glooth'] = {
+ clientId = 21182,
+ sell = 125,
+ },
+ ['gloom wolf fur'] = {
+ clientId = 22007,
+ sell = 70,
+ },
+ ['glooth injection tube'] = {
+ clientId = 21103,
+ sell = 350,
+ },
+ ['goanna claw'] = {
+ clientId = 31561,
+ sell = 260,
+ },
+ ['goanna meat'] = {
+ clientId = 31560,
+ sell = 190,
+ },
+ ['goat grass'] = {
+ clientId = 3674,
+ sell = 50,
+ },
+ ['goosebump leather'] = {
+ clientId = 20205,
+ sell = 650,
+ },
+ ['grant of arms'] = {
+ clientId = 28824,
+ sell = 950,
+ },
+ ['grappling hook'] = {
+ clientId = 35588,
+ sell = 150,
+ },
+ ['green bandage'] = {
+ clientId = 25697,
+ sell = 180,
+ },
+ ['green glass plate'] = {
+ clientId = 29346,
+ sell = 180,
+ },
+ ['guidebook'] = {
+ clientId = 25745,
+ sell = 200,
+ },
+ ['hair of a banshee'] = {
+ clientId = 11446,
+ sell = 350,
+ },
+ ['half-digested piece of meat'] = {
+ clientId = 10283,
+ sell = 55,
+ },
+ ['half-eaten brain'] = {
+ clientId = 9659,
+ sell = 85,
+ },
+ ['harpy feathers'] = {
+ clientId = 40585,
+ sell = 730,
+ },
+ ['haunted piece of wood'] = {
+ clientId = 9683,
+ sell = 115,
+ },
+ ['heaven blossom'] = {
+ clientId = 5921,
+ sell = 50,
+ },
+ ['heavy machete'] = {
+ clientId = 3330,
+ sell = 90,
+ },
+ ['hellhound slobber'] = {
+ clientId = 9637,
+ sell = 500,
+ },
+ ['hellspawn tail'] = {
+ clientId = 10304,
+ sell = 475,
+ },
+ ['hemp rope'] = {
+ clientId = 20206,
+ sell = 350,
+ },
+ ['hideous chunk'] = {
+ clientId = 16140,
+ sell = 510,
+ },
+ ['hieroglyph banner'] = {
+ clientId = 12482,
+ sell = 500,
+ },
+ ['high guard flag'] = {
+ clientId = 10415,
+ sell = 550,
+ },
+ ['high guard shoulderplates'] = {
+ clientId = 10416,
+ sell = 130,
+ },
+ ['hollow stampor hoof'] = {
+ clientId = 12314,
+ sell = 400,
+ },
+ ['holy ash'] = {
+ clientId = 17850,
+ sell = 160,
+ },
+ ['horn'] = {
+ clientId = 19359,
+ sell = 300,
+ },
+ ['humongous chunk'] = {
+ clientId = 16139,
+ sell = 540,
+ },
+ ['hunter\'s quiver'] = {
+ clientId = 11469,
+ sell = 80,
+ },
+ ['hydra egg'] = {
+ clientId = 4839,
+ sell = 500,
+ },
+ ['hydra head'] = {
+ clientId = 10282,
+ sell = 600,
+ },
+ ['hydrophytes'] = {
+ clientId = 39410,
+ sell = 220,
+ },
+ ['ice flower'] = {
+ clientId = 30058,
+ sell = 370,
+ },
+ ['incantation notes'] = {
+ clientId = 18929,
+ sell = 90,
+ },
+ ['inkwell'] = {
+ clientId = 28568,
+ sell = 720,
+ },
+ ['instable proto matter'] = {
+ clientId = 23516,
+ sell = 300,
+ },
+ ['ivory carving'] = {
+ clientId = 33945,
+ sell = 300,
+ },
+ ['jewelled belt'] = {
+ clientId = 11470,
+ sell = 180,
+ },
+ ['jungle moa claw'] = {
+ clientId = 39404,
+ sell = 160,
+ },
+ ['jungle moa egg'] = {
+ clientId = 39405,
+ sell = 250,
+ },
+ ['jungle moa feather'] = {
+ clientId = 39403,
+ sell = 140,
+ },
+ ['katex\' blood'] = {
+ clientId = 34100,
+ sell = 210,
+ },
+ ['key to the drowned library'] = {
+ clientId = 14009,
+ sell = 330,
+ },
+ ['kollos shell'] = {
+ clientId = 14077,
+ sell = 420,
+ },
+ ['kongra\'s shoulderpad'] = {
+ clientId = 11471,
+ sell = 100,
+ },
+ ['lamassu hoof'] = {
+ clientId = 31441,
+ sell = 330,
+ },
+ ['lamassu horn'] = {
+ clientId = 31442,
+ sell = 240,
+ },
+ ['lancer beetle shell'] = {
+ clientId = 10455,
+ sell = 80,
+ },
+ ['lancet'] = {
+ clientId = 18925,
+ sell = 90,
+ },
+ ['lava fungus head'] = {
+ clientId = 36785,
+ sell = 900,
+ },
+ ['lava fungus ring'] = {
+ clientId = 36786,
+ sell = 390,
+ },
+ ['lavaworm spike roots'] = {
+ clientId = 36769,
+ sell = 600,
+ },
+ ['lavaworm spikes'] = {
+ clientId = 36770,
+ sell = 750,
+ },
+ ['legionnaire flags'] = {
+ clientId = 10417,
+ sell = 500,
+ },
+ ['liodile fang'] = {
+ clientId = 40583,
+ sell = 480,
+ },
+ ['lion cloak patch'] = {
+ clientId = 34162,
+ sell = 190,
+ },
+ ['lion crest'] = {
+ clientId = 34160,
+ sell = 270,
+ },
+ ['lion seal'] = {
+ clientId = 34163,
+ sell = 210,
+ },
+ ['lion\'s mane'] = {
+ clientId = 9691,
+ sell = 60,
+ },
+ ['little bowl of myrrh'] = {
+ clientId = 25702,
+ sell = 500,
+ },
+ ['lizard essence'] = {
+ clientId = 11680,
+ sell = 300,
+ },
+ ['lizard heart'] = {
+ clientId = 31340,
+ sell = 530,
+ },
+ ['lost basher\'s spike'] = {
+ clientId = 17826,
+ sell = 280,
+ },
+ ['lost bracers'] = {
+ clientId = 17853,
+ sell = 140,
+ },
+ ['lost husher\'s staff'] = {
+ clientId = 17848,
+ sell = 250,
+ },
+ ['lost soul'] = {
+ clientId = 32227,
+ sell = 120,
+ },
+ ['luminescent crystal pickaxe'] = {
+ clientId = 32711,
+ sell = 50,
+ },
+ ['lump of earth'] = {
+ clientId = 10305,
+ sell = 130,
+ },
+ ['mad froth'] = {
+ clientId = 17854,
+ sell = 80,
+ },
+ ['magma clump'] = {
+ clientId = 16130,
+ sell = 570,
+ },
+ ['makara fin'] = {
+ clientId = 39401,
+ sell = 350,
+ },
+ ['makara tongue'] = {
+ clientId = 39402,
+ sell = 320,
+ },
+ ['mantassin tail'] = {
+ clientId = 11489,
+ sell = 280,
+ },
+ ['manticore ear'] = {
+ clientId = 31440,
+ sell = 310,
+ },
+ ['manticore tail'] = {
+ clientId = 31439,
+ sell = 220,
+ },
+ ['marsh stalker beak'] = {
+ clientId = 17461,
+ sell = 65,
+ },
+ ['marsh stalker feather'] = {
+ clientId = 17462,
+ sell = 50,
+ },
+ ['maxilla'] = {
+ clientId = 12315,
+ sell = 250,
+ },
+ ['metal spike'] = {
+ clientId = 10298,
+ sell = 320,
+ },
+ ['metal toe'] = {
+ clientId = 21198,
+ sell = 430,
+ },
+ ['milk churn'] = {
+ clientId = 32011,
+ sell = 100,
+ },
+ ['minotaur horn'] = {
+ clientId = 11472,
+ sell = 75,
+ },
+ ['miraculum'] = {
+ clientId = 11474,
+ sell = 60,
+ },
+ ['mooh\'tah shell'] = {
+ clientId = 21202,
+ sell = 110,
+ },
+ ['moohtant horn'] = {
+ clientId = 21200,
+ sell = 140,
+ },
+ ['mouldy powder'] = {
+ clientId = 35596,
+ sell = 200,
+ },
+ ['mucus plug'] = {
+ clientId = 16102,
+ sell = 500,
+ },
+ ['mutated bat ear'] = {
+ clientId = 9662,
+ sell = 420,
+ },
+ ['mutated flesh'] = {
+ clientId = 10308,
+ sell = 50,
+ },
+ ['mutated rat tail'] = {
+ clientId = 9668,
+ sell = 150,
+ },
+ ['mysterious fetish'] = {
+ clientId = 3078,
+ sell = 50,
+ },
+ ['mystical hourglass'] = {
+ clientId = 9660,
+ sell = 700,
+ },
+ ['naga archer scales'] = {
+ clientId = 39413,
+ sell = 340,
+ },
+ ['naga armring'] = {
+ clientId = 39411,
+ sell = 390,
+ },
+ ['naga earring'] = {
+ clientId = 39412,
+ sell = 380,
+ },
+ ['naga warrior scales'] = {
+ clientId = 39414,
+ sell = 340,
+ },
+ ['necromantic robe'] = {
+ clientId = 11475,
+ sell = 250,
+ },
+ ['necromantic rust'] = {
+ clientId = 21196,
+ sell = 390,
+ },
+ ['nettle blossom'] = {
+ clientId = 10314,
+ sell = 75,
+ },
+ ['odd organ'] = {
+ clientId = 23510,
+ sell = 410,
+ },
+ ['ogre ear stud'] = {
+ clientId = 22188,
+ sell = 180,
+ },
+ ['ogre nose ring'] = {
+ clientId = 22189,
+ sell = 210,
+ },
+ ['old girtablilu carapace'] = {
+ clientId = 36972,
+ sell = 570,
+ },
+ ['old parchment'] = {
+ clientId = 4831,
+ sell = 500,
+ },
+ ['orc tooth'] = {
+ clientId = 10196,
+ sell = 150,
+ },
+ ['orc tusk'] = {
+ clientId = 7786,
+ sell = 700,
+ },
+ ['orcish gear'] = {
+ clientId = 11477,
+ sell = 85,
+ },
+ ['pair of old bracers'] = {
+ clientId = 32705,
+ sell = 500,
+ },
+ ['panpipes'] = {
+ clientId = 2953,
+ sell = 150,
+ },
+ ['panther head'] = {
+ clientId = 12039,
+ sell = 750,
+ },
+ ['panther paw'] = {
+ clientId = 12040,
+ sell = 300,
+ },
+ ['parder fur'] = {
+ clientId = 39418,
+ sell = 150,
+ },
+ ['parder tooth'] = {
+ clientId = 39417,
+ sell = 150,
+ },
+ ['peacock feather fan'] = {
+ clientId = 21975,
+ sell = 350,
+ },
+ ['percht horns'] = {
+ clientId = 30186,
+ sell = 200,
+ },
+ ['petrified scream'] = {
+ clientId = 10420,
+ sell = 250,
+ },
+ ['phantasmal hair'] = {
+ clientId = 32704,
+ sell = 500,
+ },
+ ['piece of dead brain'] = {
+ clientId = 9663,
+ sell = 420,
+ },
+ ['piece of hellfire armor'] = {
+ clientId = 9664,
+ sell = 550,
+ },
+ ['piece of warrior armor'] = {
+ clientId = 11482,
+ sell = 50,
+ },
+ ['pieces of magic chalk'] = {
+ clientId = 18930,
+ sell = 210,
+ },
+ ['pirat\'s tail'] = {
+ clientId = 35573,
+ sell = 180,
+ },
+ ['plasmatic lightning'] = {
+ clientId = 23520,
+ sell = 270,
+ },
+ ['poison gland'] = {
+ clientId = 29348,
+ sell = 210,
+ },
+ ['poisoned fang'] = {
+ clientId = 21195,
+ sell = 130,
+ },
+ ['poisonous slime'] = {
+ clientId = 9640,
+ sell = 50,
+ },
+ ['pool of chitinous glue'] = {
+ clientId = 20207,
+ sell = 480,
+ },
+ ['protective charm'] = {
+ clientId = 11444,
+ sell = 60,
+ },
+ ['pulverized ore'] = {
+ clientId = 16133,
+ sell = 400,
+ },
+ ['purified soul'] = {
+ clientId = 32228,
+ sell = 260,
+ },
+ ['purple robe'] = {
+ clientId = 11473,
+ sell = 110,
+ },
+ ['quara bone'] = {
+ clientId = 11491,
+ sell = 500,
+ },
+ ['quara eye'] = {
+ clientId = 11488,
+ sell = 350,
+ },
+ ['quara pincers'] = {
+ clientId = 11490,
+ sell = 410,
+ },
+ ['quara tentacle'] = {
+ clientId = 11487,
+ sell = 140,
+ },
+ ['rabbit\'s foot'] = {
+ clientId = 12172,
+ sell = 50,
+ },
+ ['rare earth'] = {
+ clientId = 27301,
+ sell = 80,
+ },
+ ['red goanna scale'] = {
+ clientId = 31558,
+ sell = 270,
+ },
+ ['red lantern'] = {
+ clientId = 10289,
+ sell = 250,
+ },
+ ['rhindeer antlers'] = {
+ clientId = 40587,
+ sell = 680,
+ },
+ ['rhino hide'] = {
+ clientId = 24388,
+ sell = 175,
+ },
+ ['rhino horn carving'] = {
+ clientId = 24386,
+ sell = 300,
+ },
+ ['rhino horn'] = {
+ clientId = 24389,
+ sell = 265,
+ },
+ ['ritual tooth'] = {
+ clientId = 40528,
+ sell = 135,
+ },
+ ['rogue naga scales'] = {
+ clientId = 39416,
+ sell = 570,
+ },
+ ['rope belt'] = {
+ clientId = 11492,
+ sell = 66,
+ },
+ ['rorc egg'] = {
+ clientId = 18996,
+ sell = 120,
+ },
+ ['rorc feather'] = {
+ clientId = 18993,
+ sell = 70,
+ },
+ ['rotten feather'] = {
+ clientId = 40527,
+ sell = 120,
+ },
+ ['sabretooth'] = {
+ clientId = 10311,
+ sell = 400,
+ },
+ ['safety pin'] = {
+ clientId = 11493,
+ sell = 120,
+ },
+ ['sample of monster blood'] = {
+ clientId = 27874,
+ sell = 250,
+ },
+ ['scale of corruption'] = {
+ clientId = 11673,
+ sell = 680,
+ },
+ ['scorpion charm'] = {
+ clientId = 36822,
+ sell = 620,
+ },
+ ['scroll of heroic deeds'] = {
+ clientId = 11510,
+ sell = 230,
+ },
+ ['scythe leg'] = {
+ clientId = 10312,
+ sell = 450,
+ },
+ ['scarab pincers'] = {
+ clientId = 9631,
+ sell = 280,
+ },
+ ['sea serpent scale'] = {
+ clientId = 9666,
+ sell = 520,
+ },
+ ['seacrest hair'] = {
+ clientId = 21801,
+ sell = 260,
+ },
+ ['seacrest scale'] = {
+ clientId = 21800,
+ sell = 150,
+ },
+ ['seeds'] = {
+ clientId = 647,
+ sell = 150,
+ },
+ ['shamanic talisman'] = {
+ clientId = 22184,
+ sell = 200,
+ },
+ ['shark fins'] = {
+ clientId = 35574,
+ sell = 250,
+ },
+ ['shimmering beetles'] = {
+ clientId = 25693,
+ sell = 150,
+ },
+ ['silencer claws'] = {
+ clientId = 20200,
+ sell = 390,
+ },
+ ['silencer resonating chamber'] = {
+ clientId = 20201,
+ sell = 600,
+ },
+ ['skull belt'] = {
+ clientId = 11480,
+ sell = 80,
+ },
+ ['skull fetish'] = {
+ clientId = 22191,
+ sell = 250,
+ },
+ ['skull shatterer'] = {
+ clientId = 17849,
+ sell = 170,
+ },
+ ['skunk tail'] = {
+ clientId = 10274,
+ sell = 50,
+ },
+ ['slime heart'] = {
+ clientId = 21194,
+ sell = 160,
+ },
+ ['slime mould'] = {
+ clientId = 12601,
+ sell = 175,
+ },
+ ['slimy leaf tentacle'] = {
+ clientId = 21197,
+ sell = 320,
+ },
+ ['small energy ball'] = {
+ clientId = 23524,
+ sell = 250,
+ },
+ ['small flask of eyedrops'] = {
+ clientId = 11512,
+ sell = 95,
+ },
+ ['small notebook'] = {
+ clientId = 11450,
+ sell = 480,
+ },
+ ['small oil lamp'] = {
+ clientId = 2933,
+ sell = 150,
+ },
+ ['small pitchfork'] = {
+ clientId = 11513,
+ sell = 70,
+ },
+ ['small tropical fish'] = {
+ clientId = 39408,
+ sell = 380,
+ },
+ ['snake skin'] = {
+ clientId = 9694,
+ sell = 400,
+ },
+ ['solid rage'] = {
+ clientId = 23517,
+ sell = 310,
+ },
+ ['spark sphere'] = {
+ clientId = 23518,
+ sell = 350,
+ },
+ ['sparkion claw'] = {
+ clientId = 23502,
+ sell = 290,
+ },
+ ['sparkion legs'] = {
+ clientId = 23504,
+ sell = 310,
+ },
+ ['sparkion stings'] = {
+ clientId = 23505,
+ sell = 280,
+ },
+ ['sparkion tail'] = {
+ clientId = 23503,
+ sell = 300,
+ },
+ ['spellsinger\'s seal'] = {
+ clientId = 14008,
+ sell = 280,
+ },
+ ['sphinx feather'] = {
+ clientId = 31437,
+ sell = 470,
+ },
+ ['sphinx tiara'] = {
+ clientId = 31438,
+ sell = 360,
+ },
+ ['spidris mandible'] = {
+ clientId = 14082,
+ sell = 450,
+ },
+ ['spiked iron ball'] = {
+ clientId = 10408,
+ sell = 100,
+ },
+ ['spiky club'] = {
+ clientId = 17859,
+ sell = 300,
+ },
+ ['spitter nose'] = {
+ clientId = 14078,
+ sell = 340,
+ },
+ ['spooky blue eye'] = {
+ clientId = 9642,
+ sell = 95,
+ },
+ ['srezz\' eye'] = {
+ clientId = 34103,
+ sell = 300,
+ },
+ ['stampor horn'] = {
+ clientId = 12312,
+ sell = 280,
+ },
+ ['stampor talons'] = {
+ clientId = 12313,
+ sell = 150,
+ },
+ ['stone nose'] = {
+ clientId = 16137,
+ sell = 590,
+ },
+ ['stone wing'] = {
+ clientId = 10278,
+ sell = 120,
+ },
+ ['stonerefiner\'s skull'] = {
+ clientId = 27606,
+ sell = 100,
+ },
+ ['strand of medusa hair'] = {
+ clientId = 10309,
+ sell = 600,
+ },
+ ['strange proto matter'] = {
+ clientId = 23513,
+ sell = 300,
+ },
+ ['strange symbol'] = {
+ clientId = 3058,
+ sell = 200,
+ },
+ ['streaked devourer eyes'] = {
+ clientId = 36772,
+ sell = 500,
+ },
+ ['streaked devourer legs'] = {
+ clientId = 36774,
+ sell = 600,
+ },
+ ['streaked devourer maw'] = {
+ clientId = 36773,
+ sell = 400,
+ },
+ ['striped fur'] = {
+ clientId = 10293,
+ sell = 50,
+ },
+ ['sulphurous stone'] = {
+ clientId = 10315,
+ sell = 100,
+ },
+ ['swarmer antenna'] = {
+ clientId = 14076,
+ sell = 130,
+ },
+ ['tail of corruption'] = {
+ clientId = 11672,
+ sell = 240,
+ },
+ ['tarantula egg'] = {
+ clientId = 10281,
+ sell = 80,
+ },
+ ['tarnished rhino figurine'] = {
+ clientId = 24387,
+ sell = 320,
+ },
+ ['tattered piece of robe'] = {
+ clientId = 9684,
+ sell = 120,
+ },
+ ['terramite eggs'] = {
+ clientId = 10453,
+ sell = 50,
+ },
+ ['terramite legs'] = {
+ clientId = 10454,
+ sell = 60,
+ },
+ ['terramite shell'] = {
+ clientId = 10452,
+ sell = 170,
+ },
+ ['terrorbird beak'] = {
+ clientId = 10273,
+ sell = 95,
+ },
+ ['thick fur'] = {
+ clientId = 10307,
+ sell = 150,
+ },
+ ['thorn'] = {
+ clientId = 9643,
+ sell = 100,
+ },
+ ['tiger eye'] = {
+ clientId = 24961,
+ sell = 350,
+ },
+ ['tooth file'] = {
+ clientId = 18924,
+ sell = 60,
+ },
+ ['torn shirt'] = {
+ clientId = 25744,
+ sell = 250,
+ },
+ ['trapped bad dream monster'] = {
+ clientId = 20203,
+ sell = 900,
+ },
+ ['tremendous tyrant head'] = {
+ clientId = 36783,
+ sell = 930,
+ },
+ ['tremendous tyrant shell'] = {
+ clientId = 36784,
+ sell = 740,
+ },
+ ['tribal mask'] = {
+ clientId = 3403,
+ sell = 250,
+ },
+ ['trollroot'] = {
+ clientId = 11515,
+ sell = 50,
+ },
+ ['tunnel tyrant head'] = {
+ clientId = 27595,
+ sell = 500,
+ },
+ ['tunnel tyrant shell'] = {
+ clientId = 27596,
+ sell = 700,
+ },
+ ['tusk'] = {
+ clientId = 3044,
+ sell = 100,
+ },
+ ['two-headed turtle heads'] = {
+ clientId = 39409,
+ sell = 460,
+ },
+ ['undead heart'] = {
+ clientId = 10450,
+ sell = 200,
+ },
+ ['unholy bone'] = {
+ clientId = 10316,
+ sell = 480,
+ },
+ ['utua\'s poison'] = {
+ clientId = 34101,
+ sell = 230,
+ },
+ ['vampire teeth'] = {
+ clientId = 9685,
+ sell = 275,
+ },
+ ['vampire\'s cape chain'] = {
+ clientId = 18927,
+ sell = 150,
+ },
+ ['varnished diremaw brainpan'] = {
+ clientId = 36781,
+ sell = 750,
+ },
+ ['varnished diremaw legs'] = {
+ clientId = 36782,
+ sell = 670,
+ },
+ ['vein of ore'] = {
+ clientId = 16135,
+ sell = 330,
+ },
+ ['venison'] = {
+ clientId = 18995,
+ sell = 55,
+ },
+ ['volatile proto matter'] = {
+ clientId = 23514,
+ sell = 300,
+ },
+ ['warmaster\'s wristguards'] = {
+ clientId = 10405,
+ sell = 200,
+ },
+ ['waspoid claw'] = {
+ clientId = 14080,
+ sell = 320,
+ },
+ ['waspoid wing'] = {
+ clientId = 14081,
+ sell = 190,
+ },
+ ['weaver\'s wandtip'] = {
+ clientId = 10397,
+ sell = 250,
+ },
+ ['werebadger claws'] = {
+ clientId = 22051,
+ sell = 160,
+ },
+ ['werebadger skull'] = {
+ clientId = 22055,
+ sell = 185,
+ },
+ ['werebear fur'] = {
+ clientId = 22057,
+ sell = 185,
+ },
+ ['werebear skull'] = {
+ clientId = 22056,
+ sell = 195,
+ },
+ ['wereboar hooves'] = {
+ clientId = 22053,
+ sell = 175,
+ },
+ ['wereboar tusk'] = {
+ clientId = 22054,
+ sell = 165,
+ },
+ ['werecrocodile tongue'] = {
+ clientId = 43729,
+ sell = 570,
+ },
+ ['werefox tail'] = {
+ clientId = 27463,
+ sell = 200,
+ },
+ ['werehyaena nose'] = {
+ clientId = 33943,
+ sell = 220,
+ },
+ ['werehyaena talisman'] = {
+ clientId = 33944,
+ sell = 350,
+ },
+ ['werepanther claw'] = {
+ clientId = 43731,
+ sell = 280,
+ },
+ ['weretiger tooth'] = {
+ clientId = 43730,
+ sell = 490,
+ },
+ ['werewolf fangs'] = {
+ clientId = 22052,
+ sell = 180,
+ },
+ ['werewolf fur'] = {
+ clientId = 10317,
+ sell = 380,
+ },
+ ['white deer antlers'] = {
+ clientId = 12544,
+ sell = 400,
+ },
+ ['white deer skin'] = {
+ clientId = 12545,
+ sell = 245,
+ },
+ ['widow\'s mandibles'] = {
+ clientId = 10411,
+ sell = 110,
+ },
+ ['wild flowers'] = {
+ clientId = 25691,
+ sell = 120,
+ },
+ ['wimp tooth chain'] = {
+ clientId = 17847,
+ sell = 120,
+ },
+ ['winged tail'] = {
+ clientId = 10313,
+ sell = 800,
+ },
+ ['witch broom'] = {
+ clientId = 9652,
+ sell = 60,
+ },
+ ['withered pauldrons'] = {
+ clientId = 27607,
+ sell = 850,
+ },
+ ['withered scalp'] = {
+ clientId = 27608,
+ sell = 900,
+ },
+ ['wyrm scale'] = {
+ clientId = 9665,
+ sell = 400,
+ },
+ ['wyvern talisman'] = {
+ clientId = 9644,
+ sell = 265,
+ },
+ ['yielocks'] = {
+ clientId = 12805,
+ sell = 600,
+ },
+ ['yielowax'] = {
+ clientId = 12742,
+ sell = 600,
+ },
+ ['yirkas\' egg'] = {
+ clientId = 34102,
+ sell = 280,
+ },
+ ['zaogun flag'] = {
+ clientId = 10413,
+ sell = 600,
+ },
+ ['zaogun\'s shoulderplates'] = {
+ clientId = 10414,
+ sell = 150,
+ },
+ ['ancient shield'] = {
+ clientId = 3432,
+ sell = 900,
+ },
+ ['bandana'] = {
+ clientId = 5917,
+ sell = 150,
+ },
+ ['battle axe'] = {
+ clientId = 3266,
+ sell = 80,
+ },
+ ['battle hammer'] = {
+ clientId = 3305,
+ sell = 120,
+ },
+ ['battle shield'] = {
+ clientId = 3413,
+ sell = 95,
+ },
+ ['belted cape'] = {
+ clientId = 8044,
+ sell = 500,
+ },
+ ['black shield'] = {
+ clientId = 3429,
+ sell = 800,
+ },
+ ['bone shield'] = {
+ clientId = 3441,
+ sell = 80,
+ },
+ ['brass armor'] = {
+ clientId = 3359,
+ sell = 150,
+ },
+ ['broadsword'] = {
+ clientId = 3301,
+ sell = 500,
+ },
+ ['carlin sword'] = {
+ clientId = 3283,
+ sell = 118,
+ },
+ ['chain armor'] = {
+ clientId = 3358,
+ sell = 70,
+ },
+ ['coconut shoes'] = {
+ clientId = 9017,
+ sell = 500,
+ },
+ ['copper shield'] = {
+ clientId = 3430,
+ sell = 50,
+ },
+ ['crowbar'] = {
+ clientId = 3304,
+ sell = 50,
+ },
+ ['crystal ring'] = {
+ clientId = 3007,
+ sell = 250,
+ },
+ ['crystal sword'] = {
+ clientId = 7449,
+ sell = 600,
+ },
+ ['crystalline spikes'] = {
+ clientId = 16138,
+ sell = 440,
+ },
+ ['daramian mace'] = {
+ clientId = 3327,
+ sell = 110,
+ },
+ ['dark armor'] = {
+ clientId = 3383,
+ sell = 400,
+ },
+ ['dark helmet'] = {
+ clientId = 3384,
+ sell = 250,
+ },
+ ['dark shield'] = {
+ clientId = 3421,
+ sell = 400,
+ },
+ ['double axe'] = {
+ clientId = 3275,
+ sell = 260,
+ },
+ ['dwarven shield'] = {
+ clientId = 3425,
+ sell = 100,
+ },
+ ['halberd'] = {
+ clientId = 3269,
+ sell = 400,
+ },
+ ['iron helmet'] = {
+ clientId = 3353,
+ sell = 150,
+ },
+ ['krimhorn helmet'] = {
+ clientId = 7461,
+ sell = 200,
+ },
+ ['leaf legs'] = {
+ clientId = 9014,
+ sell = 500,
+ },
+ ['leaf star'] = {
+ clientId = 25735,
+ sell = 50,
+ },
+ ['life preserver'] = {
+ clientId = 17813,
+ sell = 300,
+ },
+ ['light shovel'] = {
+ clientId = 5710,
+ sell = 300,
+ },
+ ['longsword'] = {
+ clientId = 3285,
+ sell = 51,
+ },
+ ['mammoth fur shorts'] = {
+ clientId = 7464,
+ sell = 850,
+ },
+ ['mammoth whopper'] = {
+ clientId = 7381,
+ sell = 300,
+ },
+ ['meat hammer'] = {
+ clientId = 32093,
+ sell = 60,
+ },
+ ['metal jaw'] = {
+ clientId = 21193,
+ sell = 260,
+ },
+ ['moonlight rod'] = {
+ clientId = 3070,
+ sell = 200,
+ },
+ ['morning star'] = {
+ clientId = 3282,
+ sell = 100,
+ },
+ ['mystic turban'] = {
+ clientId = 3574,
+ sell = 150,
+ },
+ ['noble armor'] = {
+ clientId = 3380,
+ sell = 900,
+ },
+ ['noble turban'] = {
+ clientId = 11486,
+ sell = 430,
+ },
+ ['obsidian lance'] = {
+ clientId = 3313,
+ sell = 500,
+ },
+ ['orcish axe'] = {
+ clientId = 3316,
+ sell = 350,
+ },
+ ['plate armor'] = {
+ clientId = 3357,
+ sell = 400,
+ },
+ ['plate legs'] = {
+ clientId = 3557,
+ sell = 115,
+ },
+ ['poison dagger'] = {
+ clientId = 3299,
+ sell = 50,
+ },
+ ['ragnir helmet'] = {
+ clientId = 7462,
+ sell = 400,
+ },
+ ['ratana'] = {
+ clientId = 17812,
+ sell = 500,
+ },
+ ['ripper lance'] = {
+ clientId = 3346,
+ sell = 500,
+ },
+ ['scale armor'] = {
+ clientId = 3377,
+ sell = 75,
+ },
+ ['scimitar'] = {
+ clientId = 3307,
+ sell = 150,
+ },
+ ['serpent sword'] = {
+ clientId = 3297,
+ sell = 900,
+ },
+ ['silver dagger'] = {
+ clientId = 3290,
+ sell = 500,
+ },
+ ['snakebite rod'] = {
+ clientId = 3066,
+ sell = 100,
+ },
+ ['spellwand'] = {
+ clientId = 651,
+ sell = 299,
+ },
+ ['spike shield'] = {
+ clientId = 17810,
+ sell = 250,
+ },
+ ['spirit cloak'] = {
+ clientId = 8042,
+ sell = 350,
+ },
+ ['steel helmet'] = {
+ clientId = 3351,
+ sell = 293,
+ },
+ ['steel shield'] = {
+ clientId = 3409,
+ sell = 80,
+ },
+ ['strange helmet'] = {
+ clientId = 3373,
+ sell = 500,
+ },
+ ['taurus mace'] = {
+ clientId = 7425,
+ sell = 500,
+ },
+ ['tortoise shield'] = {
+ clientId = 6131,
+ sell = 150,
+ },
+ ['twin hooks'] = {
+ clientId = 10392,
+ sell = 500,
+ },
+ ['two handed sword'] = {
+ clientId = 3265,
+ sell = 450,
+ },
+ ['viking helmet'] = {
+ clientId = 3367,
+ sell = 66,
+ },
+ ['viking shield'] = {
+ clientId = 3431,
+ sell = 85,
+ },
+ ['wand of dragonbreath'] = {
+ clientId = 3075,
+ sell = 200,
+ },
+ ['wand of vortex'] = {
+ clientId = 3074,
+ sell = 100,
+ },
+ ['zaoan halberd'] = {
+ clientId = 10406,
+ sell = 500,
+ },
+ ['ancient amulet'] = {
+ clientId = 3025,
+ sell = 200,
+ },
+ ['crystal necklace'] = {
+ clientId = 3008,
+ sell = 400,
+ },
+ ['garlic necklace'] = {
+ clientId = 3083,
+ sell = 50,
+ },
+ ['scarab amulet'] = {
+ clientId = 3018,
+ sell = 200,
+ },
+ ['star amulet'] = {
+ clientId = 3014,
+ sell = 500,
+ },
+ ['wolf tooth chain'] = {
+ clientId = 3012,
+ sell = 100,
+ },
+ ['axe ring'] = {
+ clientId = 3092,
+ sell = 100,
+ },
+ ['club ring'] = {
+ clientId = 3093,
+ sell = 100,
+ },
+ ['dwarven ring'] = {
+ clientId = 3097,
+ sell = 100,
+ },
+ ['energy ring'] = {
+ clientId = 3051,
+ sell = 100,
+ },
+ ['life ring'] = {
+ clientId = 3052,
+ sell = 50,
+ },
+ ['power ring'] = {
+ clientId = 3050,
+ sell = 50,
+ },
+ ['ring of healing'] = {
+ clientId = 3098,
+ sell = 100,
+ },
+ ['stealth ring'] = {
+ clientId = 3049,
+ sell = 200,
+ },
+ ['sword ring'] = {
+ clientId = 3091,
+ sell = 100,
+ },
+ ['time ring'] = {
+ clientId = 3053,
+ sell = 100,
+ },
+ ['wedding ring'] = {
+ clientId = 3004,
+ sell = 100,
+ },
+ ['ancient coin'] = {
+ clientId = 24390,
+ sell = 350,
+ },
+ ['ancient stone'] = {
+ clientId = 9632,
+ sell = 200,
+ },
+ ['ankh'] = {
+ clientId = 3077,
+ sell = 100,
+ },
+ ['basalt figurine'] = {
+ clientId = 17857,
+ sell = 160,
+ },
+ ['battle stone'] = {
+ clientId = 11447,
+ sell = 290,
+ },
+ ['black pearl'] = {
+ clientId = 3027,
+ sell = 280,
+ },
+ ['blue crystal splinter'] = {
+ clientId = 16124,
+ sell = 400,
+ },
+ ['broken iks cuirass'] = {
+ clientId = 40533,
+ sell = 640,
+ },
+ ['brown crystal splinter'] = {
+ clientId = 16123,
+ sell = 400,
+ },
+ ['cracked alabaster vase'] = {
+ clientId = 24385,
+ sell = 180,
+ },
+ ['crystal ball'] = {
+ clientId = 3076,
+ sell = 190,
+ },
+ ['crystallized anger'] = {
+ clientId = 23507,
+ sell = 400,
+ },
+ ['cyan crystal fragment'] = {
+ clientId = 16125,
+ sell = 800,
+ },
+ ['emerald bangle'] = {
+ clientId = 3010,
+ sell = 800,
+ },
+ ['explorer brooch'] = {
+ clientId = 4871,
+ sell = 50,
+ },
+ ['flintstone'] = {
+ clientId = 12806,
+ sell = 800,
+ },
+ ['frozen lightning'] = {
+ clientId = 23519,
+ sell = 270,
+ },
+ ['giant pacifier'] = {
+ clientId = 21199,
+ sell = 170,
+ },
+ ['glowing rune'] = {
+ clientId = 28570,
+ sell = 350,
+ },
+ ['gold nugget'] = {
+ clientId = 3040,
+ sell = 850,
+ },
+ ['gold-brocaded cloth'] = {
+ clientId = 40529,
+ sell = 175,
+ },
+ ['golden brush'] = {
+ clientId = 25689,
+ sell = 250,
+ },
+ ['golden lotus brooch'] = {
+ clientId = 21974,
+ sell = 270,
+ },
+ ['golden mug'] = {
+ clientId = 2903,
+ sell = 250,
+ },
+ ['green crystal fragment'] = {
+ clientId = 16127,
+ sell = 800,
+ },
+ ['green crystal splinter'] = {
+ clientId = 16122,
+ sell = 400,
+ },
+ ['life crystal'] = {
+ clientId = 3061,
+ sell = 85,
+ },
+ ['mind stone'] = {
+ clientId = 3062,
+ sell = 100,
+ },
+ ['onyx chip'] = {
+ clientId = 22193,
+ sell = 500,
+ },
+ ['opal'] = {
+ clientId = 22194,
+ sell = 500,
+ },
+ ['orb'] = {
+ clientId = 3060,
+ sell = 750,
+ },
+ ['pirate coin'] = {
+ clientId = 35572,
+ sell = 110,
+ },
+ ['plasma pearls'] = {
+ clientId = 23506,
+ sell = 250,
+ },
+ ['prismatic quartz'] = {
+ clientId = 24962,
+ sell = 450,
+ },
+ ['rainbow quartz'] = {
+ clientId = 25737,
+ sell = 800,
+ },
+ ['red crystal fragment'] = {
+ clientId = 16126,
+ sell = 800,
+ },
+ ['scarab coin'] = {
+ clientId = 3042,
+ sell = 100,
+ },
+ ['seacrest pearl'] = {
+ clientId = 21747,
+ sell = 400,
+ },
+ ['shiny stone'] = {
+ clientId = 10310,
+ sell = 500,
+ },
+ ['silver brooch'] = {
+ clientId = 3017,
+ sell = 150,
+ },
+ ['small amethyst'] = {
+ clientId = 3033,
+ sell = 200,
+ },
+ ['small diamond'] = {
+ clientId = 3028,
+ sell = 300,
+ },
+ ['small emerald'] = {
+ clientId = 3032,
+ sell = 250,
+ },
+ ['small enchanted amethyst'] = {
+ clientId = 678,
+ sell = 200,
+ },
+ ['small enchanted emerald'] = {
+ clientId = 677,
+ sell = 250,
+ },
+ ['small enchanted ruby'] = {
+ clientId = 676,
+ sell = 250,
+ },
+ ['small enchanted sapphire'] = {
+ clientId = 675,
+ sell = 250,
+ },
+ ['small ruby'] = {
+ clientId = 3030,
+ sell = 250,
+ },
+ ['small sapphire'] = {
+ clientId = 3029,
+ sell = 250,
+ },
+ ['small topaz'] = {
+ clientId = 9057,
+ sell = 200,
+ },
+ ['small treasure chest'] = {
+ clientId = 35571,
+ sell = 500,
+ },
+ ['spectral gold nugget'] = {
+ clientId = 32724,
+ sell = 500,
+ },
+ ['spectral silver nugget'] = {
+ clientId = 32725,
+ sell = 250,
+ },
+ ['spectral stone'] = {
+ clientId = 4840,
+ sell = 50,
+ },
+ ['talon'] = {
+ clientId = 3034,
+ sell = 320,
+ },
+ ['war crystal'] = {
+ clientId = 9654,
+ sell = 460,
+ },
+ ['white pearl'] = {
+ clientId = 3026,
+ sell = 160,
+ },
+ ['ape fur'] = {
+ clientId = 5883,
+ sell = 120,
+ },
+ ['bat wing'] = {
+ clientId = 5894,
+ sell = 50,
+ },
+ ['bear paw'] = {
+ clientId = 5896,
+ sell = 100,
+ },
+ ['blue piece of cloth'] = {
+ clientId = 5912,
+ sell = 200,
+ },
+ ['bonelord eye'] = {
+ clientId = 5898,
+ sell = 80,
+ },
+ ['brown piece of cloth'] = {
+ clientId = 5913,
+ sell = 100,
+ },
+ ['cluster of solace'] = {
+ clientId = 20062,
+ sell = 500,
+ },
+ ['demon dust'] = {
+ clientId = 5906,
+ sell = 300,
+ },
+ ['first verse of the hymn'] = {
+ clientId = 6087,
+ sell = 100,
+ },
+ ['fish fin'] = {
+ clientId = 5895,
+ sell = 150,
+ },
+ ['fourth verse of the hymn'] = {
+ clientId = 6090,
+ sell = 800,
+ },
+ ['green dragon leather'] = {
+ clientId = 5877,
+ sell = 100,
+ },
+ ['green dragon scale'] = {
+ clientId = 5920,
+ sell = 100,
+ },
+ ['green piece of cloth'] = {
+ clientId = 5910,
+ sell = 200,
+ },
+ ['hardened bone'] = {
+ clientId = 5925,
+ sell = 70,
+ },
+ ['holy orchid'] = {
+ clientId = 5922,
+ sell = 90,
+ },
+ ['iron ore'] = {
+ clientId = 5880,
+ sell = 500,
+ },
+ ['lizard leather'] = {
+ clientId = 5876,
+ sell = 150,
+ },
+ ['lizard scale'] = {
+ clientId = 5881,
+ sell = 120,
+ },
+ ['mammoth tusk'] = {
+ clientId = 10321,
+ sell = 100,
+ },
+ ['minotaur leather'] = {
+ clientId = 5878,
+ sell = 80,
+ },
+ ['perfect behemoth fang'] = {
+ clientId = 5893,
+ sell = 250,
+ },
+ ['piece of hell steel'] = {
+ clientId = 5888,
+ sell = 500,
+ },
+ ['pirate voodoo doll'] = {
+ clientId = 5810,
+ sell = 500,
+ },
+ ['red dragon leather'] = {
+ clientId = 5948,
+ sell = 200,
+ },
+ ['red dragon scale'] = {
+ clientId = 5882,
+ sell = 200,
+ },
+ ['red piece of cloth'] = {
+ clientId = 5911,
+ sell = 300,
+ },
+ ['second verse of the hymn'] = {
+ clientId = 6088,
+ sell = 250,
+ },
+ ['spider silk'] = {
+ clientId = 5879,
+ sell = 100,
+ },
+ ['third verse of the hymn'] = {
+ clientId = 6089,
+ sell = 400,
+ },
+ ['turtle shell'] = {
+ clientId = 5899,
+ sell = 90,
+ },
+ ['vampire dust'] = {
+ clientId = 5905,
+ sell = 100,
+ },
+ ['voodoo doll'] = {
+ clientId = 3002,
+ sell = 400,
+ },
+ ['white piece of cloth'] = {
+ clientId = 5909,
+ sell = 100,
+ },
+ ['wolf paw'] = {
+ clientId = 5897,
+ sell = 70,
+ },
+ ['yellow piece of cloth'] = {
+ clientId = 5914,
+ sell = 150,
+ },
+ ['blood herb'] = {
+ clientId = 3734,
+ sell = 500,
+ },
+ ['blue rose'] = {
+ clientId = 3659,
+ sell = 250,
+ },
+ ['crystal pedestal'] = {
+ clientId = 9063,
+ sell = 500,
+ },
+ ['cyclops trophy'] = {
+ clientId = 7398,
+ sell = 500,
+ },
+ ['doll'] = {
+ clientId = 2991,
+ sell = 200,
+ },
+ ['minotaur trophy'] = {
+ clientId = 7401,
+ sell = 500,
+ },
+ ['berserk potion'] = {
+ clientId = 7439,
+ sell = 500,
+ },
+ ['bullseye potion'] = {
+ clientId = 7443,
+ sell = 500,
+ },
+ ['mastermind potion'] = {
+ clientId = 7440,
+ sell = 500,
+ },
+ ['dark mushroom'] = {
+ clientId = 3728,
+ sell = 100,
+ },
+ ['ectoplasmic sushi'] = {
+ clientId = 11681,
+ sell = 300,
+ },
+ ['fire mushroom'] = {
+ clientId = 3731,
+ sell = 200,
+ },
+ ['green mushroom'] = {
+ clientId = 3732,
+ sell = 100,
+ },
+ ['orange mushroom'] = {
+ clientId = 3726,
+ sell = 150,
+ },
+ },
+}
+
+ItemsDatabase.rarityColors = {
+ yellow = TextColors.yellow,
+ purple = TextColors.purple,
+ blue = TextColors.blue,
+ green = TextColors.green,
+ grey = TextColors.white,
+}
+
+--[[ python
+import re
+
+file_path = r'D:/kzn/github/canary2/data/scripts/lib/shops.lua'
+
+with open(file_path, 'r') as file:
+ lua_content = file.read()
+
+pattern = re.compile(r'\{ itemName = "([^"]+)", clientId = (\d+), sell = (\d+) \}')
+
+matches = pattern.findall(lua_content)
+
+items_database = {
+ 'yellow': {},
+ 'purple': {},
+ 'blue': {},
+ 'green': {},
+ 'grey': {}
+}
+
+def categorize_sell(value):
+ if value >= 1000000:
+ return 'yellow'
+ elif value >= 100000:
+ return 'purple'
+ elif value >= 10000:
+ return 'blue'
+ elif value >= 1000:
+ return 'green'
+ elif value >= 50:
+ return 'grey'
+ return None
+
+for match in matches:
+ item_name, client_id, sell = match
+ client_id = int(client_id)
+ sell = int(sell)
+ category = categorize_sell(sell)
+ if category:
+ escaped_item_name = item_name.replace("'", "\\'")
+ items_database[category][escaped_item_name] = {'clientId': client_id, 'sell': sell}
+
+lua_output = ["ItemsDatabase.lib = {"]
+for category, items in items_database.items():
+ lua_output.append(f" ['{category}'] = {{")
+ for item_name, details in items.items():
+ lua_output.append(f" ['{item_name}'] = {{")
+ lua_output.append(f" clientId = {details['clientId']},")
+ lua_output.append(f" sell = {details['sell']},")
+ lua_output.append(f" }},")
+ lua_output.append(" },")
+lua_output.append("}")
+
+lua_output_str = "\n".join(lua_output)
+print(lua_output_str) ]]
+
+-- LuaFormatter on
+
+function ItemsDatabase.getRarityByClientId(clientID)
+ for profile, data in pairs(ItemsDatabase.lib) do
+ for k, itemDatabase in pairs(data) do
+ if itemDatabase.clientId == tonumber(clientID) then
+ return profile
+ end
+ end
+ end
+ return nil
+end
+
+function ItemsDatabase.setRarityItem(widget, item, style)
+
+ if not widget then
+ return
+ end
+
+ if item then
+ local itemId = item:getId()
+
+ local itemRarity = ItemsDatabase.getRarityByClientId(itemId)
+ local imagePath = '/images/ui/item'
+ if itemRarity and itemRarity:lower() ~= "normal" then
+ imagePath = '/images/ui/rarity_' .. itemRarity:lower()
+ end
+ widget:setImageSource(imagePath)
+
+ else
+ --[[ widget:getParent():setItem(nil)
+ widget:getParent():setImageSource('/images/ui/item') ]]
+ end
+
+ if style then
+ widget:setStyle(style)
+ end
+end
+
+function ItemsDatabase.getColorForRarity(rarity)
+ return ItemsDatabase.rarityColors[rarity] or TextColors.white
+end
+
+function ItemsDatabase.setColorLootMessage(text)
+ -- temp. TODO assets search
+ local function coloringLootName(match)
+ local id, itemName = match:match("(%d+)|(.+)")
+
+ local itemInfo = ItemsDatabase.getRarityByClientId(tonumber(id))
+ if itemInfo then
+ local color = ItemsDatabase.getColorForRarity(itemInfo)
+ return "{" .. itemName .. ", " .. color .. "}"
+ else
+ return itemName
+ end
+
+ end
+ return (text:gsub("{(.-)}", coloringLootName))
+end
+
+function ItemsDatabase.getSellValueAndColor(clientID)
+ for profile, data in pairs(ItemsDatabase.lib) do
+ for k, itemDatabase in pairs(data) do
+ if itemDatabase.clientId == tonumber(clientID) then
+ return itemDatabase.sell, profile
+ end
+ end
+ end
+ return 0, ""
+end
diff --git a/modules/gamelib/player.lua b/modules/gamelib/player.lua
index f3dbb71167..339a7724e6 100644
--- a/modules/gamelib/player.lua
+++ b/modules/gamelib/player.lua
@@ -55,6 +55,18 @@ InventorySlotPurse = 11
InventorySlotFirst = 1
InventorySlotLast = 10
+vocationNamesByClientId = {
+ [0] = "No Vocation",
+ [1] = "Knight",
+ [2] = "Paladin",
+ [3] = "Sorcerer",
+ [4] = "Druid",
+ [11]= "Elite Knight",
+ [12] = "Royal Paladin",
+ [13] = "Master Sorcerer",
+ [14] = "Elder Druid"
+}
+
function Player:isPartyLeader()
local shield = self:getShield()
return (shield == ShieldWhiteYellow or shield == ShieldYellow or shield == ShieldYellowSharedExp or shield ==
@@ -159,3 +171,7 @@ function Player:hasState(state, states)
end
return false
end
+
+function Player:getVocationNameByClientId()
+ return vocationNamesByClientId[self:getVocation()] or "Unknown Vocation"
+end
diff --git a/modules/gamelib/ui/uiminimap.lua b/modules/gamelib/ui/uiminimap.lua
index 2cc968b6db..7bf48d2499 100644
--- a/modules/gamelib/ui/uiminimap.lua
+++ b/modules/gamelib/ui/uiminimap.lua
@@ -126,7 +126,11 @@ function UIMinimap:setCrossPosition(pos)
local cross = self.cross
if not self.cross then
cross = g_ui.createWidget('MinimapCross', self)
- cross:setIcon('/images/game/minimap/cross')
+ if self:getParent():getId() == "MapBase" then
+ cross:setIcon('/game_cyclopedia/images/icon-map-player')
+ else
+ cross:setIcon('/images/game/minimap/cross')
+ end
self.cross = cross
end
diff --git a/src/client/const.h b/src/client/const.h
index f3a504f00c..d4878ec78b 100644
--- a/src/client/const.h
+++ b/src/client/const.h
@@ -658,10 +658,18 @@ namespace Otc
{
RESOURCE_BANK_BALANCE = 0,
RESOURCE_GOLD_EQUIPPED = 1,
+ RESOURCE_CURRENCY_CUSTOM_EQUIPPED = 2,
RESOURCE_PREY_WILDCARDS = 10,
RESOURCE_DAILYREWARD_STREAK = 20,
RESOURCE_DAILYREWARD_JOKERS = 21,
RESOURCE_TASK_HUNTING = 50,
+ RESOURCE_FORGE_DUST = 70,
+ RESOURCE_FORGE_SLIVER = 71,
+ RESOURCE_FORGE_CORES = 72,
+ RESOURCE_LESSER_GEMS = 81,
+ RESOURCE_REGULAR_GEMS = 82,
+ RESOURCE_GREATER_GEMS = 83,
+ RESOURCE_WHEEL_OF_DESTINY = 86,
RESOURE_COIN_NORMAL = 90,
RESOURE_COIN_TRANSFERRABLE = 91,
RESOURE_COIN_AUCTION = 92,
@@ -730,6 +738,30 @@ namespace Otc
SUPPLY_STASH_ACTION_WITHDRAW = 3
};
+ enum CyclopediaCharacterInfoType_t : uint8_t
+ {
+ CYCLOPEDIA_CHARACTERINFO_BASEINFORMATION = 0,
+ CYCLOPEDIA_CHARACTERINFO_GENERALSTATS = 1,
+ CYCLOPEDIA_CHARACTERINFO_COMBATSTATS = 2,
+ CYCLOPEDIA_CHARACTERINFO_RECENTDEATHS = 3,
+ CYCLOPEDIA_CHARACTERINFO_RECENTPVPKILLS = 4,
+ CYCLOPEDIA_CHARACTERINFO_ACHIEVEMENTS = 5,
+ CYCLOPEDIA_CHARACTERINFO_ITEMSUMMARY = 6,
+ CYCLOPEDIA_CHARACTERINFO_OUTFITSMOUNTS = 7,
+ CYCLOPEDIA_CHARACTERINFO_STORESUMMARY = 8,
+ CYCLOPEDIA_CHARACTERINFO_INSPECTION = 9,
+ CYCLOPEDIA_CHARACTERINFO_BADGES = 10,
+ CYCLOPEDIA_CHARACTERINFO_TITLES = 11
+ };
+
+ enum InspectObjectTypes : uint8_t
+ {
+ INSPECT_NORMALOBJECT = 0,
+ INSPECT_NPCTRADE = 1,
+ INSPECT_PLAYERTRADE = 2,
+ INSPECT_CYCLOPEDIA = 3
+ };
+
enum GameStoreInfoType_t : uint8_t
{
SHOW_NONE = 0,
diff --git a/src/client/game.cpp b/src/client/game.cpp
index d255582c4b..b8c81531a9 100644
--- a/src/client/game.cpp
+++ b/src/client/game.cpp
@@ -490,6 +490,86 @@ void Game::processModalDialog(const uint32_t id, const std::string_view title, c
g_lua.callGlobalField("g_game", "onModalDialog", id, title, message, buttonList, enterButton, escapeButton, choiceList, priority);
}
+void Game::processItemDetail(const uint32_t itemId, const std::vector>& descriptions)
+{
+ g_lua.callGlobalField("g_game", "onParseItemDetail", itemId, descriptions);
+}
+
+void Game::processBestiaryRaces(const std::vector& bestiaryRaces)
+{
+ g_lua.callGlobalField("g_game", "onParseBestiaryRaces", bestiaryRaces);
+}
+
+void Game::processCyclopediaCharacterGeneralStats(const CyclopediaCharacterGeneralStats& stats, const std::vector>& skills,
+ const std::vector>& combats)
+{
+ g_lua.callGlobalField("g_game", "onParseCyclopediaCharacterGeneralStats", stats, skills, combats);
+}
+
+void Game::processCyclopediaCharacterCombatStats(const CyclopediaCharacterCombatStats& data, const double mitigation, const std::vector>& additionalSkillsArray,
+ const std::vector>& forgeSkillsArray, const std::vector& perfectShotDamageRangesArray,
+ const std::vector>& combatsArray, const std::vector>& concoctionsArray)
+{
+ g_lua.callGlobalField("g_game", "onParseCyclopediaCharacterCombatStats", data, mitigation, additionalSkillsArray, forgeSkillsArray, perfectShotDamageRangesArray, combatsArray, concoctionsArray);
+}
+
+void Game::processCyclopediaCharacterGeneralStatsBadge(const uint8_t showAccountInformation, const uint8_t playerOnline, const uint8_t playerPremium,
+ const std::string_view loyaltyTitle, const std::vector>& badgesVector)
+{
+ g_lua.callGlobalField("g_game", "onParseCyclopediaCharacterBadges", showAccountInformation, playerOnline, playerPremium, loyaltyTitle, badgesVector);
+}
+
+void Game::processCyclopediaCharacterItemSummary(const CyclopediaCharacterItemSummary& data)
+{
+ g_lua.callGlobalField("g_game", "onUpdateCyclopediaCharacterItemSummary", data);
+}
+
+void Game::processCyclopediaCharacterAppearances(const OutfitColorStruct& currentOutfit, const std::vector& outfits,
+ const std::vector& mounts, std::vector& familiars)
+{
+ g_lua.callGlobalField("g_game", "onParseCyclopediaCharacterAppearances", currentOutfit, outfits, mounts, familiars);
+}
+
+void Game::processCyclopediaCharacterRecentDeaths(const CyclopediaCharacterRecentDeaths& data)
+{
+ g_lua.callGlobalField("g_game", "onCyclopediaCharacterRecentDeaths", data);
+}
+
+void Game::processCyclopediaCharacterRecentPvpKills(const CyclopediaCharacterRecentPvPKills& data)
+{
+ g_lua.callGlobalField("g_game", "onCyclopediaCharacterRecentKills", data);
+}
+
+void Game::processBosstiaryInfo(const std::vector& boss)
+{
+ g_lua.callGlobalField("g_game", "onParseSendBosstiary", boss);
+}
+
+void Game::processBosstiarySlots(const BosstiarySlotsData& data)
+{
+ g_lua.callGlobalField("g_game", "onParseBosstiarySlots", data);
+}
+
+void Game::processParseBestiaryRaces(const std::vector& bestiaryData)
+{
+ g_lua.callGlobalField("g_game", "onParseBestiaryRaces", bestiaryData);
+}
+
+void Game::processParseBestiaryOverview(const std::string_view raceName, const std::vector& data, const uint16_t animusMasteryPoints)
+{
+ g_lua.callGlobalField("g_game", "onParseBestiaryOverview", raceName, data, animusMasteryPoints);
+}
+
+void Game::processUpdateBestiaryMonsterData(const BestiaryMonsterData& data)
+{
+ g_lua.callGlobalField("g_game", "onUpdateBestiaryMonsterData", data);
+}
+
+void Game::processUpdateBestiaryCharmsData(const BestiaryCharmsData& charmData)
+{
+ g_lua.callGlobalField("g_game", "onUpdateBestiaryCharmsData", charmData);
+}
+
void Game::processAttackCancel(const uint32_t seq)
{
if (isAttacking() && (seq == 0 || m_seq == seq))
@@ -1766,4 +1846,92 @@ void Game::openContainerQuickLoot(const uint8_t action, const uint8_t category,
enableBotCall();
m_protocolGame->openContainerQuickLoot(action, category, pos, itemId, stackpos, useMainAsFallback);
disableBotCall();
-}
\ No newline at end of file
+}
+
+void Game::inspectionNormalObject(const Position& position)
+{
+ if (!canPerformGameAction())
+ return;
+
+ m_protocolGame->sendInspectionNormalObject(position);
+}
+
+void Game::inspectionObject(const Otc::InspectObjectTypes inspectionType, const uint16_t itemId, const uint8_t itemCount)
+{
+ if (!canPerformGameAction())
+ return;
+
+ m_protocolGame->sendInspectionObject(inspectionType , itemId, itemCount);
+}
+
+void Game::requestBestiary()
+{
+ if (!canPerformGameAction())
+ return;
+
+ m_protocolGame->sendRequestBestiary();
+}
+
+void Game::requestBestiaryOverview(const std::string_view catName)
+{
+ if (!canPerformGameAction())
+ return;
+
+ m_protocolGame->sendRequestBestiaryOverview(catName);
+}
+
+void Game::requestBestiarySearch(const uint16_t raceId)
+{
+ if (!canPerformGameAction())
+ return;
+
+ m_protocolGame->sendRequestBestiarySearch(raceId);
+}
+
+void Game::requestSendBuyCharmRune(const uint8_t runeId, const uint8_t action, const uint16_t raceId)
+{
+ if (!canPerformGameAction())
+ return;
+
+ m_protocolGame->sendBuyCharmRune(runeId, action, raceId);
+}
+
+void Game::requestSendCharacterInfo(const uint32_t playerId, const Otc::CyclopediaCharacterInfoType_t characterInfoType, const uint16_t entriesPerPage, const uint16_t page)
+{
+ if (!canPerformGameAction())
+ return;
+
+ m_protocolGame->sendCyclopediaRequestCharacterInfo(playerId, characterInfoType, entriesPerPage, page);
+}
+
+void Game::requestBosstiaryInfo()
+{
+ if (!canPerformGameAction())
+ return;
+
+ m_protocolGame->sendRequestBosstiaryInfo();
+}
+
+void Game::requestBossSlootInfo()
+{
+ if (!canPerformGameAction())
+ return;
+
+ m_protocolGame->sendRequestBossSlootInfo();
+}
+
+void Game::requestBossSlotAction(const uint8_t action, const uint32_t raceId)
+{
+ if (!canPerformGameAction())
+ return;
+
+ m_protocolGame->sendRequestBossSlotAction(action, raceId);
+
+}
+
+void Game::sendStatusTrackerBestiary(const uint16_t raceId, const bool status)
+{
+ enableBotCall();
+ m_protocolGame->sendStatusTrackerBestiary(raceId, status);
+ disableBotCall();
+}
diff --git a/src/client/game.h b/src/client/game.h
index ea09995ea3..baf7f10d16 100644
--- a/src/client/game.h
+++ b/src/client/game.h
@@ -173,6 +173,236 @@ struct StoreData
bool tooManyResults;
};
+struct CyclopediaCharacterGeneralStats
+{
+ uint64_t experience;
+ uint16_t level;
+ uint8_t levelPercent;
+ uint16_t baseExpGain;
+ uint16_t lowLevelExpBonus;
+ uint16_t XpBoostPercent;
+ uint16_t staminaExpBonus;
+ uint16_t XpBoostBonusRemainingTime;
+ uint8_t canBuyXpBoost;
+ uint32_t health;
+ uint32_t maxHealth;
+ uint32_t mana;
+ uint32_t maxMana;
+ uint8_t soul;
+ uint16_t staminaMinutes;
+ uint16_t regenerationCondition;
+ uint16_t offlineTrainingTime;
+ uint16_t speed;
+ uint16_t baseSpeed;
+ uint32_t capacity;
+ uint32_t baseCapacity;
+ uint32_t freeCapacity;
+ uint16_t magicLevel;
+ uint16_t baseMagicLevel;
+ uint16_t loyaltyMagicLevel;
+ uint16_t magicLevelPercent;
+};
+
+struct CyclopediaCharacterCombatStats
+{
+ uint8_t weaponElement;
+ uint16_t weaponMaxHitChance;
+ uint8_t weaponElementDamage;
+ uint8_t weaponElementType;
+ uint16_t defense;
+ uint16_t armor;
+ uint8_t haveBlessings;
+};
+
+struct CyclopediaBestiaryRace
+{
+ uint8_t race;
+ std::string bestClass;
+ uint16_t count;
+ uint16_t unlockedCount;
+};
+
+struct CharmData
+{
+ uint8_t id;
+ std::string name;
+ std::string description;
+ uint16_t unlockPrice;
+ bool unlocked;
+ bool asignedStatus;
+ uint16_t raceId;
+ uint32_t removeRuneCost;
+};
+
+struct BestiaryCharmsData
+{
+ uint32_t points;
+ std::vector charms;
+ std::vector finishedMonsters;
+};
+
+struct BestiaryOverviewMonsters
+{
+ uint16_t id;
+ uint8_t currentLevel;
+ uint8_t occurrence;
+ uint16_t creatureAnimusMasteryBonus;
+};
+
+struct LootItem
+{
+ uint16_t itemId;
+ uint8_t diffculty;
+ uint8_t specialEvent;
+ std::string name;
+ uint8_t amount;
+};
+
+struct BestiaryMonsterData
+{
+ uint16_t id;
+ std::string bestClass;
+ uint8_t currentLevel;
+ uint16_t AnimusMasteryBonus;
+ uint16_t AnimusMasteryPoints;
+ uint32_t killCounter;
+ uint16_t thirdDifficulty;
+ uint16_t secondUnlock;
+ uint16_t lastProgressKillCount;
+ uint8_t difficulty;
+ uint8_t ocorrence;
+ std::vector loot;
+ uint16_t charmValue;
+ uint8_t attackMode;
+ uint32_t maxHealth;
+ uint32_t experience;
+ uint16_t speed;
+ uint16_t armor;
+ double mitigation;
+ std::map combat;
+ std::string location;
+};
+
+struct BosstiaryData
+{
+ uint32_t raceId;
+ uint8_t category;
+ uint32_t kills;
+ uint8_t isTrackerActived;
+};
+
+struct BosstiarySlot
+{
+ uint8_t bossRace;
+ uint32_t killCount;
+ uint16_t lootBonus;
+ uint8_t killBonus;
+ uint8_t bossRaceRepeat;
+ uint32_t removePrice;
+ uint8_t inactive;
+};
+
+struct BossUnlocked
+{
+ uint32_t bossId;
+ uint8_t bossRace;
+};
+
+struct BosstiarySlotsData
+{
+ uint32_t playerPoints;
+ uint32_t totalPointsNextBonus;
+ uint16_t currentBonus;
+ uint16_t nextBonus;
+ bool isSlotOneUnlocked;
+ uint32_t bossIdSlotOne;
+ std::optional slotOneData;
+ bool isSlotTwoUnlocked;
+ uint32_t bossIdSlotTwo;
+ std::optional slotTwoData;
+ bool isTodaySlotUnlocked;
+ uint32_t boostedBossId;
+ std::optional todaySlotData;
+ bool bossesUnlocked;
+ std::vector bossesUnlockedData;
+};
+
+struct ItemSummary
+{
+ uint16_t itemId;
+ uint8_t classification;
+ uint32_t amount;
+};
+
+struct CyclopediaCharacterItemSummary
+{
+ std::vector inventory;
+ std::vector store;
+ std::vector stash;
+ std::vector depot;
+ std::vector inbox;
+};
+
+struct RecentPvPKillEntry
+{
+ uint32_t timestamp;
+ std::string description;
+ uint8_t status;
+};
+
+struct CyclopediaCharacterRecentPvPKills
+{
+ std::vector entries;
+};
+
+struct RecentDeathEntry
+{
+ uint32_t timestamp;
+ std::string cause;
+};
+
+struct CyclopediaCharacterRecentDeaths
+{
+ std::vector entries;
+};
+
+struct OutfitColorStruct
+{
+ uint8_t lookHead;
+ uint8_t lookBody;
+ uint8_t lookLegs;
+ uint8_t lookFeet;
+ uint8_t lookMountHead;
+ uint8_t lookMountBody;
+ uint8_t lookMountLegs;
+ uint8_t lookMountFeet;
+};
+
+struct CharacterInfoOutfits
+{
+ uint16_t lookType;
+ std::string name;
+ uint8_t addons;
+ uint8_t type;
+ uint32_t isCurrent;
+};
+
+struct CharacterInfoMounts
+{
+ uint16_t mountId;
+ std::string name;
+ uint8_t type;
+ uint32_t isCurrent;
+};
+
+struct CharacterInfoFamiliar
+{
+ uint16_t lookType;
+ std::string name;
+ uint8_t type;
+ uint32_t isCurrent;
+};
+
//@bindsingleton g_game
class Game
{
@@ -274,6 +504,31 @@ class Game
& buttonList, const uint8_t enterButton, const uint8_t escapeButton, const std::vector>
& choiceList, const bool priority);
+ // cyclopedia
+ static void processItemDetail(const uint32_t itemId, const std::vector>& descriptions);
+ static void processBestiaryRaces(const std::vector& bestiaryRaces);
+ static void processCyclopediaCharacterGeneralStats(const CyclopediaCharacterGeneralStats& stats, const std::vector>& skills,
+ const std::vector>& combats);
+ static void processCyclopediaCharacterCombatStats(const CyclopediaCharacterCombatStats& data, const double mitigation,
+ const std::vector>& additionalSkillsArray,
+ const std::vector>& forgeSkillsArray, const std::vector& perfectShotDamageRangesArray,
+ const std::vector>& combatsArray,
+ const std::vector>& concoctionsArray);
+ static void processCyclopediaCharacterGeneralStatsBadge(const uint8_t showAccountInformation, const uint8_t playerOnline, const uint8_t playerPremium,
+ const std::string_view loyaltyTitle,
+ const std::vector>& badgesVector);
+ static void processCyclopediaCharacterItemSummary(const CyclopediaCharacterItemSummary& data);
+ static void processCyclopediaCharacterAppearances(const OutfitColorStruct& currentOutfit, const std::vector& outfits,
+ const std::vector& mounts, std::vector& familiars);
+ static void processCyclopediaCharacterRecentDeaths(const CyclopediaCharacterRecentDeaths& data);
+ static void processCyclopediaCharacterRecentPvpKills(const CyclopediaCharacterRecentPvPKills& data);
+ static void processParseBestiaryRaces(const std::vector& bestiaryData);
+ static void processParseBestiaryOverview(const std::string_view raceName, const std::vector& data, const uint16_t animusMasteryPoints);
+ static void processUpdateBestiaryMonsterData(const BestiaryMonsterData& data);
+ static void processUpdateBestiaryCharmsData(const BestiaryCharmsData& charmData);
+ static void processBosstiaryInfo(const std::vector& boss);
+ static void processBosstiarySlots(const BosstiarySlotsData& data);
+
friend class ProtocolGame;
friend class Map;
@@ -517,6 +772,18 @@ class Game
void requestQuickLootBlackWhiteList(const uint8_t filter, const uint16_t size, const std::vector& listedItems);
void openContainerQuickLoot(const uint8_t action, const uint8_t category, const Position& pos, const uint16_t itemId, const uint8_t stackpos, const bool useMainAsFallback);
+ // cyclopedia related
+ void inspectionNormalObject(const Position& position);
+ void inspectionObject(const Otc::InspectObjectTypes inspectionType, const uint16_t itemId, const uint8_t itemCount);
+ void requestBestiary();
+ void requestBestiaryOverview(const std::string_view catName);
+ void requestBestiarySearch(const uint16_t raceId);
+ void requestSendBuyCharmRune(const uint8_t runeId, const uint8_t action, const uint16_t raceId);
+ void requestSendCharacterInfo(const uint32_t playerId, const Otc::CyclopediaCharacterInfoType_t characterInfoType, const uint16_t entriesPerPage = 0, const uint16_t page = 0);
+ void requestBosstiaryInfo();
+ void requestBossSlootInfo();
+ void requestBossSlotAction(const uint8_t action, const uint32_t raceId);
+ void sendStatusTrackerBestiary(const uint16_t raceId, const bool status);
protected:
void enableBotCall() { m_denyBotCall = false; }
void disableBotCall() { m_denyBotCall = true; }
diff --git a/src/client/luafunctions.cpp b/src/client/luafunctions.cpp
index 510e928810..be6004327b 100644
--- a/src/client/luafunctions.cpp
+++ b/src/client/luafunctions.cpp
@@ -365,6 +365,17 @@ void Client::registerLuaFunctions()
g_lua.bindSingletonFunction("g_game", "requestBless", &Game::requestBless, &g_game);
g_lua.bindSingletonFunction("g_game", "requestQuickLootBlackWhiteList", &Game::requestQuickLootBlackWhiteList, &g_game);
g_lua.bindSingletonFunction("g_game", "openContainerQuickLoot", &Game::openContainerQuickLoot, &g_game);
+ g_lua.bindSingletonFunction("g_game", "inspectionNormalObject", &Game::inspectionNormalObject, &g_game);
+ g_lua.bindSingletonFunction("g_game", "inspectionObject", &Game::inspectionObject, &g_game);
+ g_lua.bindSingletonFunction("g_game", "requestBestiary", &Game::requestBestiary, &g_game);
+ g_lua.bindSingletonFunction("g_game", "requestBestiaryOverview", &Game::requestBestiaryOverview, &g_game);
+ g_lua.bindSingletonFunction("g_game", "requestBestiarySearch", &Game::requestBestiarySearch, &g_game);
+ g_lua.bindSingletonFunction("g_game", "BuyCharmRune", &Game::requestSendBuyCharmRune, &g_game);
+ g_lua.bindSingletonFunction("g_game", "requestCharacterInfo", &Game::requestSendCharacterInfo, &g_game);
+ g_lua.bindSingletonFunction("g_game", "requestBosstiaryInfo", &Game::requestBosstiaryInfo, &g_game);
+ g_lua.bindSingletonFunction("g_game", "requestBossSlootInfo", &Game::requestBossSlootInfo, &g_game);
+ g_lua.bindSingletonFunction("g_game", "requestBossSlotAction", &Game::requestBossSlotAction, &g_game);
+ g_lua.bindSingletonFunction("g_game", "sendStatusTrackerBestiary", &Game::sendStatusTrackerBestiary, &g_game);
g_lua.registerSingletonClass("g_gameConfig");
g_lua.bindSingletonFunction("g_gameConfig", "loadFonts", &GameConfig::loadFonts, &g_gameConfig);
@@ -1019,4 +1030,4 @@ void Client::registerLuaFunctions()
g_lua.bindClassMemberFunction("setShowLabels", &UIGraph::setShowLabels);
g_lua.registerClass();
-}
\ No newline at end of file
+}
diff --git a/src/client/luavaluecasts_client.cpp b/src/client/luavaluecasts_client.cpp
index ee29c76a14..3d9e051415 100644
--- a/src/client/luavaluecasts_client.cpp
+++ b/src/client/luavaluecasts_client.cpp
@@ -609,3 +609,468 @@ int push_luavalue(const StoreData& storeData) {
return 1;
}
+
+// cyclopedia
+int push_luavalue(const CyclopediaBestiaryRace& race) {
+ g_lua.createTable(0, 4);
+ g_lua.pushInteger(race.race);
+ g_lua.setField("race");
+ g_lua.pushString(race.bestClass);
+ g_lua.setField("bestClass");
+ g_lua.pushInteger(race.count);
+ g_lua.setField("count");
+ g_lua.pushInteger(race.unlockedCount);
+ g_lua.setField("unlockedCount");
+ return 1;
+}
+
+int push_luavalue(const LootItem& lootItem) {
+ g_lua.createTable(0, 5);
+ g_lua.pushInteger(lootItem.itemId);
+ g_lua.setField("itemId");
+ g_lua.pushInteger(lootItem.diffculty);
+ g_lua.setField("diffculty");
+ g_lua.pushInteger(lootItem.specialEvent);
+ g_lua.setField("specialEvent");
+ g_lua.pushString(lootItem.name);
+ g_lua.setField("name");
+ g_lua.pushInteger(lootItem.amount);
+ g_lua.setField("amount");
+ return 1;
+}
+
+int push_luavalue(const BestiaryMonsterData& data) {
+ g_lua.createTable(0, 16);
+ g_lua.pushInteger(data.id);
+ g_lua.setField("id");
+ g_lua.pushString(data.bestClass);
+ g_lua.setField("class");
+ g_lua.pushInteger(data.currentLevel);
+ g_lua.setField("currentLevel");
+ g_lua.pushInteger(data.AnimusMasteryPoints);
+ g_lua.setField("AnimusMasteryPoints");
+ g_lua.pushInteger(data.AnimusMasteryBonus);
+ g_lua.setField("AnimusMasteryBonus");
+ g_lua.pushInteger(data.killCounter);
+ g_lua.setField("killCounter");
+ g_lua.pushInteger(data.thirdDifficulty);
+ g_lua.setField("thirdDifficulty");
+ g_lua.pushInteger(data.secondUnlock);
+ g_lua.setField("secondUnlock");
+ g_lua.pushInteger(data.lastProgressKillCount);
+ g_lua.setField("lastProgressKillCount");
+ g_lua.pushInteger(data.difficulty);
+ g_lua.setField("difficulty");
+ g_lua.pushInteger(data.ocorrence);
+ g_lua.setField("ocorrence");
+
+ g_lua.createTable(data.loot.size(), 0);
+ for (size_t i = 0; i < data.loot.size(); ++i) {
+ push_luavalue(data.loot[i]);
+ g_lua.rawSeti(i + 1);
+ }
+ g_lua.setField("loot");
+
+ if (data.currentLevel > 1) {
+ g_lua.pushInteger(data.charmValue);
+ g_lua.setField("charmValue");
+ g_lua.pushInteger(data.attackMode);
+ g_lua.setField("attackMode");
+ g_lua.pushInteger(data.maxHealth);
+ g_lua.setField("maxHealth");
+ g_lua.pushInteger(data.experience);
+ g_lua.setField("experience");
+ g_lua.pushInteger(data.speed);
+ g_lua.setField("speed");
+ g_lua.pushInteger(data.armor);
+ g_lua.setField("armor");
+ g_lua.pushNumber(data.mitigation);
+ g_lua.setField("mitigation");
+ }
+
+ if (data.currentLevel > 2) {
+ g_lua.createTable(data.combat.size(), 0);
+ for (const auto& [elementId, elementValue] : data.combat) {
+ g_lua.pushInteger(elementValue);
+ g_lua.rawSeti(elementId + 1);
+ }
+ g_lua.setField("combat");
+ g_lua.pushString(data.location);
+ g_lua.setField("location");
+ }
+
+ return 1;
+}
+
+int push_luavalue(const CharmData& charm) {
+ g_lua.createTable(0, 7);
+ g_lua.pushInteger(charm.id);
+ g_lua.setField("id");
+ g_lua.pushString(charm.name);
+ g_lua.setField("name");
+ g_lua.pushString(charm.description);
+ g_lua.setField("description");
+ g_lua.pushInteger(charm.unlockPrice);
+ g_lua.setField("unlockPrice");
+ g_lua.pushBoolean(charm.unlocked);
+ g_lua.setField("unlocked");
+ g_lua.pushBoolean(charm.asignedStatus);
+ g_lua.setField("asignedStatus");
+ g_lua.pushInteger(charm.raceId);
+ g_lua.setField("raceId");
+ g_lua.pushInteger(charm.removeRuneCost);
+ g_lua.setField("removeRuneCost");
+ return 1;
+}
+
+int push_luavalue(const BestiaryCharmsData& charmData) {
+ g_lua.createTable(0, 3);
+ g_lua.pushInteger(charmData.points);
+ g_lua.setField("points");
+
+ g_lua.createTable(charmData.charms.size(), 0);
+ for (size_t i = 0; i < charmData.charms.size(); ++i) {
+ push_luavalue(charmData.charms[i]);
+ g_lua.rawSeti(i + 1);
+ }
+ g_lua.setField("charms");
+
+ g_lua.createTable(charmData.finishedMonsters.size(), 0);
+ for (size_t i = 0; i < charmData.finishedMonsters.size(); ++i) {
+ g_lua.pushInteger(charmData.finishedMonsters[i]);
+ g_lua.rawSeti(i + 1);
+ }
+ g_lua.setField("finishedMonsters");
+ return 1;
+}
+
+int push_luavalue(const BestiaryOverviewMonsters& monster) {
+ g_lua.createTable(0, 3);
+ g_lua.pushInteger(monster.id);
+ g_lua.setField("id");
+ g_lua.pushInteger(monster.currentLevel);
+ g_lua.setField("currentLevel");
+ g_lua.pushInteger(monster.occurrence);
+ g_lua.setField("occurrence");
+ g_lua.pushInteger(monster.creatureAnimusMasteryBonus);
+ g_lua.setField("creatureAnimusMasteryBonus");
+ return 1;
+}
+
+int push_luavalue(const CyclopediaCharacterGeneralStats& stats) {
+ g_lua.createTable(0, 26);
+ g_lua.pushInteger(stats.experience);
+ g_lua.setField("xperiencee");
+ g_lua.pushInteger(stats.level);
+ g_lua.setField("level");
+ g_lua.pushInteger(stats.levelPercent);
+ g_lua.setField("levelPercent");
+ g_lua.pushInteger(stats.baseExpGain);
+ g_lua.setField("baseExpGain");
+ g_lua.pushInteger(stats.lowLevelExpBonus);
+ g_lua.setField("lowLevelExpBonus");
+ g_lua.pushInteger(stats.XpBoostPercent);
+ g_lua.setField("XpBoostPercent");
+ g_lua.pushInteger(stats.staminaExpBonus);
+ g_lua.setField("staminaExpBonus");
+ g_lua.pushInteger(stats.XpBoostBonusRemainingTime);
+ g_lua.setField("XpBoostBonusRemainingTime");
+ g_lua.pushInteger(stats.canBuyXpBoost);
+ g_lua.setField("canBuyXpBoost");
+ g_lua.pushInteger(stats.health);
+ g_lua.setField("health");
+ g_lua.pushInteger(stats.maxHealth);
+ g_lua.setField("maxHealth");
+ g_lua.pushInteger(stats.mana);
+ g_lua.setField("mana");
+ g_lua.pushInteger(stats.maxMana);
+ g_lua.setField("maxMana");
+ g_lua.pushInteger(stats.soul);
+ g_lua.setField("soul");
+ g_lua.pushInteger(stats.staminaMinutes);
+ g_lua.setField("staminaMinutes");
+ g_lua.pushInteger(stats.regenerationCondition);
+ g_lua.setField("regenerationCondition");
+ g_lua.pushInteger(stats.offlineTrainingTime);
+ g_lua.setField("offlineTrainingTime");
+ g_lua.pushInteger(stats.speed);
+ g_lua.setField("speed");
+ g_lua.pushInteger(stats.baseSpeed);
+ g_lua.setField("baseSpeed");
+ g_lua.pushInteger(stats.capacity);
+ g_lua.setField("capacity");
+ g_lua.pushInteger(stats.baseCapacity);
+ g_lua.setField("baseCapacity");
+ g_lua.pushInteger(stats.freeCapacity);
+ g_lua.setField("freeCapacity");
+ g_lua.pushInteger(stats.magicLevel);
+ g_lua.setField("magicLevel");
+ g_lua.pushInteger(stats.baseMagicLevel);
+ g_lua.setField("baseMagicLevel");
+ g_lua.pushInteger(stats.loyaltyMagicLevel);
+ g_lua.setField("loyaltyMagicLevel");
+ g_lua.pushInteger(stats.magicLevelPercent);
+ g_lua.setField("magicLevelPercent");
+
+ return 1;
+}
+
+int push_luavalue(const CyclopediaCharacterCombatStats& data) {
+ g_lua.createTable(0, 7);
+ g_lua.pushInteger(data.weaponElement);
+ g_lua.setField("weaponElement");
+ g_lua.pushInteger(data.weaponMaxHitChance);
+ g_lua.setField("weaponMaxHitChance");
+ g_lua.pushInteger(data.weaponElementDamage);
+ g_lua.setField("weaponElementDamage");
+ g_lua.pushInteger(data.weaponElementType);
+ g_lua.setField("weaponElementType");
+ g_lua.pushInteger(data.defense);
+ g_lua.setField("defense");
+ g_lua.pushInteger(data.armor);
+ g_lua.setField("armor");
+ g_lua.pushInteger(data.haveBlessings);
+ g_lua.setField("haveBlessings");
+ return 1;
+}
+
+int push_luavalue(const BosstiaryData& boss) {
+ g_lua.createTable(0, 4);
+ g_lua.pushInteger(boss.raceId);
+ g_lua.setField("raceId");
+ g_lua.pushInteger(boss.category);
+ g_lua.setField("category");
+ g_lua.pushInteger(boss.kills);
+ g_lua.setField("kills");
+ g_lua.pushInteger(boss.isTrackerActived);
+ g_lua.setField("isTrackerActived");
+ return 1;
+}
+
+int push_luavalue(const BosstiarySlot& slot) {
+ g_lua.createTable(0, 7);
+ g_lua.pushInteger(slot.bossRace);
+ g_lua.setField("bossRace");
+ g_lua.pushInteger(slot.killCount);
+ g_lua.setField("killCount");
+ g_lua.pushInteger(slot.lootBonus);
+ g_lua.setField("lootBonus");
+ g_lua.pushInteger(slot.killBonus);
+ g_lua.setField("killBonus");
+ g_lua.pushInteger(slot.bossRaceRepeat);
+ g_lua.setField("bossRaceRepeat");
+ g_lua.pushInteger(slot.removePrice);
+ g_lua.setField("removePrice");
+ g_lua.pushInteger(slot.inactive);
+ g_lua.setField("inactive");
+ return 1;
+}
+
+int push_luavalue(const BossUnlocked& boss) {
+ g_lua.createTable(0, 2);
+ g_lua.pushInteger(boss.bossId);
+ g_lua.setField("bossId");
+ g_lua.pushInteger(boss.bossRace);
+ g_lua.setField("bossRace");
+ return 1;
+}
+
+int push_luavalue(const BosstiarySlotsData& data) {
+ g_lua.createTable(0, 13);
+ g_lua.pushInteger(data.playerPoints);
+ g_lua.setField("playerPoints");
+ g_lua.pushInteger(data.totalPointsNextBonus);
+ g_lua.setField("totalPointsNextBonus");
+ g_lua.pushInteger(data.currentBonus);
+ g_lua.setField("currentBonus");
+ g_lua.pushInteger(data.nextBonus);
+ g_lua.setField("nextBonus");
+
+ g_lua.pushBoolean(data.isSlotOneUnlocked);
+ g_lua.setField("isSlotOneUnlocked");
+ g_lua.pushInteger(data.bossIdSlotOne);
+ g_lua.setField("bossIdSlotOne");
+ if (data.slotOneData) {
+ push_luavalue(*data.slotOneData);
+ g_lua.setField("slotOneData");
+ }
+
+ g_lua.pushBoolean(data.isSlotTwoUnlocked);
+ g_lua.setField("isSlotTwoUnlocked");
+ g_lua.pushInteger(data.bossIdSlotTwo);
+ g_lua.setField("bossIdSlotTwo");
+ if (data.slotTwoData) {
+ push_luavalue(*data.slotTwoData);
+ g_lua.setField("slotTwoData");
+ }
+
+ g_lua.pushBoolean(data.isTodaySlotUnlocked);
+ g_lua.setField("isTodaySlotUnlocked");
+ g_lua.pushInteger(data.boostedBossId);
+ g_lua.setField("boostedBossId");
+ if (data.todaySlotData) {
+ push_luavalue(*data.todaySlotData);
+ g_lua.setField("todaySlotData");
+ }
+
+ g_lua.pushBoolean(data.bossesUnlocked);
+ g_lua.setField("bossesUnlocked");
+
+ g_lua.createTable(data.bossesUnlockedData.size(), 0);
+ for (size_t i = 0; i < data.bossesUnlockedData.size(); ++i) {
+ push_luavalue(data.bossesUnlockedData[i]);
+ g_lua.rawSeti(i + 1);
+ }
+ g_lua.setField("bossesUnlockedData");
+ return 1;
+}
+
+int push_luavalue(const ItemSummary& item) {
+ g_lua.createTable(0, 2);
+ g_lua.pushInteger(item.itemId);
+ g_lua.setField("itemId");
+ g_lua.pushInteger(item.amount);
+ g_lua.setField("amount");
+ return 1;
+}
+
+int push_luavalue(const CyclopediaCharacterItemSummary& data) {
+ g_lua.createTable(0, 5);
+
+ g_lua.createTable(data.inventory.size(), 0);
+ for (size_t i = 0; i < data.inventory.size(); ++i) {
+ push_luavalue(data.inventory[i]);
+ g_lua.rawSeti(i + 1);
+ }
+ g_lua.setField("inventory");
+
+ g_lua.createTable(data.store.size(), 0);
+ for (size_t i = 0; i < data.store.size(); ++i) {
+ push_luavalue(data.store[i]);
+ g_lua.rawSeti(i + 1);
+ }
+ g_lua.setField("store");
+
+ g_lua.createTable(data.stash.size(), 0);
+ for (size_t i = 0; i < data.stash.size(); ++i) {
+ push_luavalue(data.stash[i]);
+ g_lua.rawSeti(i + 1);
+ }
+ g_lua.setField("stash");
+
+ g_lua.createTable(data.depot.size(), 0);
+ for (size_t i = 0; i < data.depot.size(); ++i) {
+ push_luavalue(data.depot[i]);
+ g_lua.rawSeti(i + 1);
+ }
+ g_lua.setField("depot");
+
+ g_lua.createTable(data.inbox.size(), 0);
+ for (size_t i = 0; i < data.inbox.size(); ++i) {
+ push_luavalue(data.inbox[i]);
+ g_lua.rawSeti(i + 1);
+ }
+ g_lua.setField("inbox");
+
+ return 1;
+}
+
+int push_luavalue(const RecentPvPKillEntry& entry) {
+ g_lua.createTable(0, 3);
+ g_lua.pushInteger(entry.timestamp);
+ g_lua.setField("timestamp");
+ g_lua.pushString(entry.description);
+ g_lua.setField("description");
+ g_lua.pushInteger(entry.status);
+ g_lua.setField("status");
+ return 1;
+}
+
+int push_luavalue(const CyclopediaCharacterRecentPvPKills& data) {
+ g_lua.createTable(data.entries.size(), 0);
+ for (size_t i = 0; i < data.entries.size(); ++i) {
+ push_luavalue(data.entries[i]);
+ g_lua.rawSeti(i + 1);
+ }
+ return 1;
+}
+
+int push_luavalue(const RecentDeathEntry& entry) {
+ g_lua.createTable(0, 2);
+ g_lua.pushInteger(entry.timestamp);
+ g_lua.setField("timestamp");
+ g_lua.pushString(entry.cause);
+ g_lua.setField("cause");
+ return 1;
+}
+
+int push_luavalue(const CyclopediaCharacterRecentDeaths& data) {
+ g_lua.createTable(data.entries.size(), 0);
+ for (size_t i = 0; i < data.entries.size(); ++i) {
+ push_luavalue(data.entries[i]);
+ g_lua.rawSeti(i + 1);
+ }
+ return 1;
+}
+
+int push_luavalue(const OutfitColorStruct& currentOutfit) {
+ g_lua.createTable(0, 8);
+ g_lua.pushInteger(currentOutfit.lookHead);
+ g_lua.setField("lookHead");
+ g_lua.pushInteger(currentOutfit.lookBody);
+ g_lua.setField("lookBody");
+ g_lua.pushInteger(currentOutfit.lookLegs);
+ g_lua.setField("lookLegs");
+ g_lua.pushInteger(currentOutfit.lookFeet);
+ g_lua.setField("lookFeet");
+ g_lua.pushInteger(currentOutfit.lookMountHead);
+ g_lua.setField("lookMountHead");
+ g_lua.pushInteger(currentOutfit.lookMountBody);
+ g_lua.setField("lookMountBody");
+ g_lua.pushInteger(currentOutfit.lookMountLegs);
+ g_lua.setField("lookMountLegs");
+ g_lua.pushInteger(currentOutfit.lookMountFeet);
+ g_lua.setField("lookMountFeet");
+ return 1;
+}
+
+int push_luavalue(const CharacterInfoOutfits& outfit) {
+ g_lua.createTable(0, 5);
+ g_lua.pushInteger(outfit.lookType);
+ g_lua.setField("lookType");
+ g_lua.pushString(outfit.name);
+ g_lua.setField("name");
+ g_lua.pushInteger(outfit.addons);
+ g_lua.setField("addons");
+ g_lua.pushInteger(outfit.type);
+ g_lua.setField("type");
+ g_lua.pushInteger(outfit.isCurrent);
+ g_lua.setField("isCurrent");
+ return 1;
+}
+
+int push_luavalue(const CharacterInfoMounts& mount) {
+ g_lua.createTable(0, 4);
+ g_lua.pushInteger(mount.mountId);
+ g_lua.setField("mountId");
+ g_lua.pushString(mount.name);
+ g_lua.setField("name");
+ g_lua.pushInteger(mount.type);
+ g_lua.setField("type");
+ g_lua.pushInteger(mount.isCurrent);
+ g_lua.setField("isCurrent");
+ return 1;
+}
+
+int push_luavalue(const CharacterInfoFamiliar& familiar) {
+ g_lua.createTable(0, 4);
+ g_lua.pushInteger(familiar.lookType);
+ g_lua.setField("lookType");
+ g_lua.pushString(familiar.name);
+ g_lua.setField("name");
+ g_lua.pushInteger(familiar.type);
+ g_lua.setField("type");
+ g_lua.pushInteger(familiar.isCurrent);
+ g_lua.setField("isCurrent");
+ return 1;
+}
diff --git a/src/client/luavaluecasts_client.h b/src/client/luavaluecasts_client.h
index c2298e7dcf..993069e57f 100644
--- a/src/client/luavaluecasts_client.h
+++ b/src/client/luavaluecasts_client.h
@@ -49,14 +49,39 @@ bool luavalue_cast(int index, UnjustifiedPoints& unjustifiedPoints);
int push_luavalue(const Imbuement& i);
int push_luavalue(const ImbuementTrackerItem& i);
-// Bless
+// bless
int push_luavalue(const BlessData& bless);
int push_luavalue(const LogData& log);
int push_luavalue(const BlessDialogData& data);
-// Store
+
+// store
int push_luavalue(const StoreCategory& category);
int push_luavalue(const SubOffer& subOffer);
int push_luavalue(const StoreOffer& offer);
int push_luavalue(const HomeOffer& homeOffer);
int push_luavalue(const Banner& banner);
int push_luavalue(const StoreData& storeData);
+
+// cyclopedia
+int push_luavalue(const CyclopediaBestiaryRace& race);
+int push_luavalue(const BestiaryOverviewMonsters& monster);
+int push_luavalue(const CharmData& charm);
+int push_luavalue(const BestiaryCharmsData& charmData);
+int push_luavalue(const CyclopediaCharacterGeneralStats& stats);
+int push_luavalue(const CyclopediaCharacterCombatStats& data);
+int push_luavalue(const CyclopediaCharacterItemSummary& data);
+int push_luavalue(const ItemSummary& item);
+int push_luavalue(const LootItem& lootItem);
+int push_luavalue(const BestiaryMonsterData& data);
+int push_luavalue(const BosstiaryData& boss);
+int push_luavalue(const BosstiarySlot& slot);
+int push_luavalue(const BossUnlocked& boss);
+int push_luavalue(const BosstiarySlotsData& data);
+int push_luavalue(const RecentPvPKillEntry& entry);
+int push_luavalue(const CyclopediaCharacterRecentPvPKills& data);
+int push_luavalue(const RecentDeathEntry& entry);
+int push_luavalue(const CyclopediaCharacterRecentDeaths& data);
+int push_luavalue(const OutfitColorStruct& currentOutfit);
+int push_luavalue(const CharacterInfoOutfits& outfit);
+int push_luavalue(const CharacterInfoMounts& mount);
+int push_luavalue(const CharacterInfoFamiliar& familiar);
diff --git a/src/client/protocolcodes.h b/src/client/protocolcodes.h
index 2b76c37a86..83d989324f 100644
--- a/src/client/protocolcodes.h
+++ b/src/client/protocolcodes.h
@@ -100,7 +100,9 @@ namespace Proto
GameServerCreateContainer = 112,
GameServerChangeInContainer = 113,
GameServerDeleteInContainer = 114,
+ GameServerBosstiaryInfo = 115,
GameServerTakeScreenshot = 117,
+ GameServerCyclopediaItemDetail = 118,
GameServerSetInventory = 120,
GameServerDeleteInventory = 121,
GameServerOpenNpcTrade = 122,
@@ -159,7 +161,7 @@ namespace Proto
GameServerWalkWait = 182,
GameServerUnjustifiedStats = 183,
GameServerPvpSituations = 184,
- GameServerRefreshBestiaryTracker = 185,
+ GameServerBestiaryRefreshTracker = 185,
GameServerTaskHuntingBasicData = 186,
GameServerTaskHuntingData = 187,
GameServerBosstiaryCooldownTimer = 189,
@@ -175,7 +177,12 @@ namespace Proto
GameServerVipAdd = 210,
GameServerVipState = 211,
GameServerVipLogout = 212,
- GameServerSendBestiaryEntryChanged = 217,
+ GameServerBestiaryRaces = 213,
+ GameServerBestiaryOverview = 214,
+ GameServerBestiaryMonsterData = 215,
+ GameServerBestiaryCharmsData = 216,
+ GameServerBestiaryEntryChanged = 217,
+ GameServerCyclopediaCharacterInfoData = 218,
GameServerTutorialHint = 220,
GameServerAutomapFlag = 221,
GameServerSendDailyRewardCollectionState = 222,
@@ -221,6 +228,7 @@ namespace Proto
ClientPing = 29,
ClientPingBack = 30,
ClientUseStash = 40,
+ ClientBestiaryTrackerStatus = 42,
// all in game opcodes must be equal or greater than 50
ClientFirstGameOpcode = 50,
@@ -291,12 +299,16 @@ namespace Proto
ClientOpenOwnChannel = 170,
ClientInviteToOwnChannel = 171,
ClientExcludeFromOwnChannel = 172,
+ ClientBosstiaryRequestInfo = 174,
+ ClientBosstiaryRequestSlotInfo = 175,
+ ClientBosstiaryRequestSlotAction = 176,
ClientRequestHighscore = 177,
ClientCancelAttackAndFollow = 190,
ClientUpdateTile = 201,
ClientRefreshContainer = 202,
ClientBrowseField = 203,
ClientSeekInContainer = 204,
+ ClientInspectionObject = 205,
ClientRequestBless = 207,
ClientRequestOutfit = 210,
ClientChangeOutfit = 211,
@@ -307,6 +319,11 @@ namespace Proto
ClientAddVip = 220,
ClientRemoveVip = 221,
ClientEditVip = 222,
+ ClientBestiaryRequest = 225,
+ ClientBestiaryRequestOverview = 226,
+ ClientBestiaryRequestSearch = 227,
+ ClientCyclopediaSendBuyCharmRune = 228,
+ ClientCyclopediaRequestCharacterInfo = 229,
ClientBugReport = 230,
ClientRuleViolation = 231,
ClientDebugReport = 232,
diff --git a/src/client/protocolgame.h b/src/client/protocolgame.h
index f7d210906d..9f95cf734a 100644
--- a/src/client/protocolgame.h
+++ b/src/client/protocolgame.h
@@ -134,8 +134,19 @@ class ProtocolGame : public Protocol
void sendStashWithdraw(const uint16_t itemId, const uint32_t count, const uint8_t stackpos);
void sendHighscoreInfo(const uint8_t action, const uint8_t category, const uint32_t vocation, const std::string_view world, const uint8_t worldType, const uint8_t battlEye, const uint16_t page, const uint8_t totalPages);
void sendImbuementDurations(bool isOpen = false);
+ void sendRequestBestiary();
+ void sendRequestBestiaryOverview(const std::string_view catName);
+ void sendRequestBestiarySearch(const uint16_t raceId);
+ void sendBuyCharmRune(const uint8_t runeId, const uint8_t action, const uint16_t raceId);
+ void sendCyclopediaRequestCharacterInfo(const uint32_t playerId, const Otc::CyclopediaCharacterInfoType_t characterInfoType, const uint16_t entriesPerPage, const uint16_t page);
+ void sendRequestBosstiaryInfo();
+ void sendRequestBossSlootInfo();
+ void sendRequestBossSlotAction(const uint8_t action, const uint32_t raceId);
+ void sendStatusTrackerBestiary(const uint16_t raceId, const bool status);
void requestQuickLootBlackWhiteList(const uint8_t filter, const uint16_t size, const std::vector& listedItems);
void openContainerQuickLoot(const uint8_t action, const uint8_t category, const Position& pos, const uint16_t itemId, const uint8_t stackpos, const bool useMainAsFallback);
+ void sendInspectionNormalObject(const Position& position);
+ void sendInspectionObject(const Otc::InspectObjectTypes inspectionType, const uint16_t itemId, const uint8_t itemCount);
// otclient only
void sendChangeMapAwareRange(const uint8_t xrange, const uint8_t yrange);
@@ -201,6 +212,9 @@ class ProtocolGame : public Protocol
void parseContainerAddItem(const InputMessagePtr& msg);
void parseContainerUpdateItem(const InputMessagePtr& msg);
void parseContainerRemoveItem(const InputMessagePtr& msg);
+ void parseBosstiaryInfo(const InputMessagePtr& msg);
+ void parseTakeScreenshot(const InputMessagePtr& msg);
+ void parseCyclopediaItemDetail(const InputMessagePtr& msg);
void parseAddInventoryItem(const InputMessagePtr& msg);
void parseRemoveInventoryItem(const InputMessagePtr& msg);
void parseOpenNpcTrade(const InputMessagePtr& msg);
@@ -290,6 +304,7 @@ class ProtocolGame : public Protocol
void parseUpdateSupplyTracker(const InputMessagePtr& msg);
void parseUpdateLootTracker(const InputMessagePtr& msg);
void parseBestiaryEntryChanged(const InputMessagePtr& msg);
+ void parseCyclopediaCharacterInfo(const InputMessagePtr& msg);
void parseDailyRewardCollectionState(const InputMessagePtr& msg);
void parseOpenRewardWall(const InputMessagePtr& msg);
void parseDailyReward(const InputMessagePtr& msg);
@@ -311,9 +326,13 @@ class ProtocolGame : public Protocol
void parseBosstiarySlots(const InputMessagePtr& msg);
void parseBosstiaryCooldownTimer(const InputMessagePtr& msg);
void parseBosstiaryEntryChanged(const InputMessagePtr& msg);
- void parseTakeScreenshot(const InputMessagePtr& msg);
- void parseHighscores(const InputMessagePtr& msg);
+ void parseBestiaryRaces(const InputMessagePtr& msg);
+ void parseBestiaryOverview(const InputMessagePtr& msg);
+ void parseBestiaryMonsterData(const InputMessagePtr& msg);
+ void parseBestiaryCharmsData(const InputMessagePtr& msg);
+
+ void parseHighscores(const InputMessagePtr& msg);
void parseAttachedEffect(const InputMessagePtr& msg);
void parseDetachEffect(const InputMessagePtr& msg);
void parseCreatureShader(const InputMessagePtr& msg);
diff --git a/src/client/protocolgameparse.cpp b/src/client/protocolgameparse.cpp
index afdd55059f..ae09463878 100644
--- a/src/client/protocolgameparse.cpp
+++ b/src/client/protocolgameparse.cpp
@@ -208,9 +208,15 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg)
case Proto::GameServerDeleteInContainer:
parseContainerRemoveItem(msg);
break;
+ case Proto::GameServerBosstiaryInfo:
+ parseBosstiaryInfo(msg);
+ break;
case Proto::GameServerTakeScreenshot:
parseTakeScreenshot(msg);
break;
+ case Proto::GameServerCyclopediaItemDetail:
+ parseCyclopediaItemDetail(msg);
+ break;
case Proto::GameServerSetInventory:
parseAddInventoryItem(msg);
break;
@@ -401,7 +407,7 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg)
case Proto::GameServerPvpSituations:
parsePvpSituations(msg);
break;
- case Proto::GameServerRefreshBestiaryTracker:
+ case Proto::GameServerBestiaryRefreshTracker:
parseBestiaryTracker(msg);
break;
case Proto::GameServerTaskHuntingBasicData:
@@ -449,9 +455,24 @@ void ProtocolGame::parseMessage(const InputMessagePtr& msg)
case Proto::GameServerVipLogout:
parseVipLogout(msg);
break;
- case Proto::GameServerSendBestiaryEntryChanged:
+ case Proto::GameServerBestiaryRaces:
+ parseBestiaryRaces(msg);
+ break;
+ case Proto::GameServerBestiaryOverview:
+ parseBestiaryOverview(msg);
+ break;
+ case Proto::GameServerBestiaryMonsterData:
+ parseBestiaryMonsterData(msg);
+ break;
+ case Proto::GameServerBestiaryCharmsData:
+ parseBestiaryCharmsData(msg);
+ break;
+ case Proto::GameServerBestiaryEntryChanged:
parseBestiaryEntryChanged(msg);
break;
+ case Proto::GameServerCyclopediaCharacterInfoData:
+ parseCyclopediaCharacterInfo(msg);
+ break;
case Proto::GameServerTutorialHint:
parseTutorialHint(msg);
break;
@@ -1422,6 +1443,49 @@ void ProtocolGame::parseContainerRemoveItem(const InputMessagePtr& msg)
g_game.processContainerRemoveItem(containerId, slot, lastItem);
}
+void ProtocolGame::parseBosstiaryInfo(const InputMessagePtr& msg)
+{
+ const uint16_t bosstiaryRaceLast = msg->getU16();
+ std::vector bossData;
+
+ for (auto i = 0; i < bosstiaryRaceLast; ++i) {
+ BosstiaryData boss;
+ boss.raceId = msg->getU32();
+ boss.category = msg->getU8();
+ boss.kills = msg->getU32();
+ msg->getU8();
+ boss.isTrackerActived = msg->getU8();
+ bossData.emplace_back(boss);
+ }
+
+ g_game.processBosstiaryInfo(bossData);
+}
+
+void ProtocolGame::parseCyclopediaItemDetail(const InputMessagePtr& msg)
+{
+ msg->getU8(); // 0x00
+ msg->getU8(); // bool is cyclopedia
+ msg->getU32(); // creature ID (version 13.00)
+ msg->getU8(); // 0x01
+
+ msg->getString(); // item name
+ const auto& item = getItem(msg);
+
+ msg->getU8(); // 0x00
+
+ const uint8_t descriptionsSize = msg->getU8();
+ std::vector> descriptions;
+ descriptions.reserve(descriptionsSize);
+
+ for (auto i = 0; i < descriptionsSize; ++i) {
+ const auto& firstDescription = msg->getString();
+ const auto& secondDescription = msg->getString();
+ descriptions.emplace_back(firstDescription, secondDescription);
+ }
+
+ g_game.processItemDetail(item->getId(), descriptions);
+}
+
void ProtocolGame::parseAddInventoryItem(const InputMessagePtr& msg)
{
const uint8_t slot = msg->getU8();
@@ -2658,6 +2722,173 @@ void ProtocolGame::parseVipLogout(const InputMessagePtr& msg)
}
}
+void ProtocolGame::parseBestiaryRaces(const InputMessagePtr& msg)
+{
+ std::vector bestiaryData;
+
+ const uint16_t bestiaryRaceLast = msg->getU16();
+ for (auto i = 0; i < bestiaryRaceLast; ++i) {
+ CyclopediaBestiaryRace race;
+ race.race = i;
+ race.bestClass = msg->getString();
+ race.count = msg->getU16();
+ race.unlockedCount = msg->getU16();
+ bestiaryData.emplace_back(race);
+ }
+
+ g_game.processParseBestiaryRaces(bestiaryData);
+}
+
+void ProtocolGame::parseBestiaryOverview(const InputMessagePtr& msg)
+{
+ const auto& raceName = msg->getString();
+
+ const uint16_t raceSize = msg->getU16();
+ std::vector data;
+
+ for (auto i = 0; i < raceSize; ++i) {
+ const uint16_t raceId = msg->getU16();
+ const uint8_t progress = msg->getU8();
+ uint8_t occurrence = 0;
+ uint16_t creatureAnimusMasteryBonus = 0;
+ if (progress > 0) {
+ occurrence = msg->getU8();
+ }
+ if (g_game.getClientVersion() >= 1340) {
+ creatureAnimusMasteryBonus = msg->getU16(); // Creature Animous Bonus
+ }
+ BestiaryOverviewMonsters monster;
+ monster.id = raceId;
+ monster.currentLevel = progress;
+ monster.occurrence = occurrence;
+ monster.creatureAnimusMasteryBonus = creatureAnimusMasteryBonus;
+ data.emplace_back(monster);
+ }
+
+ uint16_t animusMasteryPoints = 0;
+ if (g_game.getClientVersion() >= 1340) {
+ animusMasteryPoints = msg->getU16(); // Animus Mastery Points
+ }
+
+ g_game.processParseBestiaryOverview(raceName, data, animusMasteryPoints);
+}
+
+void ProtocolGame::parseBestiaryMonsterData(const InputMessagePtr& msg)
+{
+ BestiaryMonsterData data;
+ data.id = msg->getU16();
+ data.bestClass = msg->getString();
+ data.currentLevel = msg->getU8();
+
+ if (g_game.getClientVersion() >= 1340) {
+ data.AnimusMasteryBonus = msg->getU16(); // Animus Mastery Bonus
+ data.AnimusMasteryPoints = msg->getU16(); // Animus Mastery Points
+ } else {
+ data.AnimusMasteryBonus = 0;
+ data.AnimusMasteryPoints = 0;
+ }
+
+ data.killCounter = msg->getU32();
+ data.thirdDifficulty = msg->getU16();
+ data.secondUnlock = msg->getU16();
+ data.lastProgressKillCount = msg->getU16();
+ data.difficulty = msg->getU8();
+ data.ocorrence = msg->getU8();
+
+ const uint8_t lootCount = msg->getU8();
+ for (auto i = 0; i < lootCount; ++i) {
+ LootItem lootItem;
+ lootItem.itemId = msg->getU16();
+ lootItem.diffculty = msg->getU8();
+ lootItem.specialEvent = msg->getU8();
+
+ const bool shouldAddItem = lootItem.itemId != 0;
+ if (shouldAddItem) {
+ lootItem.name = msg->getString();
+ lootItem.amount = msg->getU8();
+ }
+ data.loot.emplace_back(lootItem);
+ }
+
+ if (data.currentLevel > 1) {
+ data.charmValue = msg->getU16();
+ data.attackMode = msg->getU8();
+ msg->getU8();
+ data.maxHealth = msg->getU32();
+ data.experience = msg->getU32();
+ data.speed = msg->getU16();
+ data.armor = msg->getU16();
+ data.mitigation = msg->getDouble();
+ }
+
+ if (data.currentLevel > 2) {
+ const uint8_t elementsCount = msg->getU8();
+ for (auto i = 0; i < elementsCount; ++i) {
+ const uint8_t elementId = msg->getU8();
+ const uint16_t elementValue = msg->getU16();
+ data.combat[elementId] = elementValue;
+ }
+
+ msg->getU16();
+ data.location = msg->getString();
+ }
+
+ if (data.currentLevel > 3) {
+ const bool hasCharm = static_cast(msg->getU8());
+ if (hasCharm) {
+ msg->getU8();
+ msg->getU32();
+ } else {
+ msg->getU8();
+ }
+ }
+
+ g_game.processUpdateBestiaryMonsterData(data);
+}
+
+void ProtocolGame::parseBestiaryCharmsData(const InputMessagePtr& msg)
+{
+ BestiaryCharmsData charmData;
+ charmData.points = msg->getU32();
+
+ const uint8_t charmsAmount = msg->getU8();
+ for (auto i = 0; i < charmsAmount; ++i) {
+ CharmData charm;
+ charm.id = msg->getU8();
+ charm.name = msg->getString();
+ charm.description = msg->getString();
+ msg->getU8();
+ charm.unlockPrice = msg->getU16();
+ charm.unlocked = static_cast(msg->getU8() == 1);
+ charm.asignedStatus = false;
+ charm.raceId = 0;
+ charm.removeRuneCost = 0;
+
+ if (charm.unlocked) {
+ const bool asigned = static_cast(msg->getU8());
+ if (asigned) {
+ charm.asignedStatus = asigned;
+ charm.raceId = msg->getU16();
+ charm.removeRuneCost = msg->getU32();
+ }
+ } else {
+ msg->getU8();
+ }
+
+ charmData.charms.emplace_back(charm);
+ }
+
+ msg->getU8();
+
+ const uint16_t finishedMonstersSize = msg->getU16();
+ for (auto i = 0; i < finishedMonstersSize; ++i) {
+ const uint16_t raceId = msg->getU16();
+ charmData.finishedMonsters.emplace_back(raceId);
+ }
+
+ g_game.processUpdateBestiaryCharmsData(charmData);
+}
+
void ProtocolGame::parseTutorialHint(const InputMessagePtr& msg)
{
const uint8_t id = msg->getU8();
@@ -3425,19 +3656,22 @@ void ProtocolGame::parseShowDescription(const InputMessagePtr& msg)
void ProtocolGame::parseBestiaryTracker(const InputMessagePtr& msg)
{
- if (g_game.getFeature(Otc::GameBosstiaryTracker)) {
- msg->getU8(); // is bestiary boolean
- }
+ uint8_t trackerType = msg->getU8(); // 0x00 para bestiary, 0x01 para boss
const uint8_t size = msg->getU8();
+ std::vector> trackerData;
+
for (auto i = 0; i < size; ++i) {
- msg->getU16(); // RaceID
- msg->getU32(); // Kill count
- msg->getU16(); // First unlock
- msg->getU16(); // Second unlock
- msg->getU16(); // Last unlock
- msg->getU8(); // Status
+ const uint16_t raceID = msg->getU16();
+ const uint32_t killCount = msg->getU32();
+ const uint16_t firstUnlock = msg->getU16();
+ const uint16_t secondUnlock = msg->getU16();
+ const uint16_t lastUnlock = msg->getU16();
+ const uint8_t status = msg->getU8();
+ trackerData.emplace_back(raceID, killCount, firstUnlock, secondUnlock, lastUnlock, status);
}
+
+ g_lua.callGlobalField("g_game", "onParseCyclopediaTracker", trackerType, trackerData);
}
void ProtocolGame::parseTaskHuntingBasicData(const InputMessagePtr& msg)
@@ -3754,6 +3988,435 @@ void ProtocolGame::parseBestiaryEntryChanged(const InputMessagePtr& msg)
// TODO: implement bestiary entry changed usage
}
+void ProtocolGame::parseCyclopediaCharacterInfo(const InputMessagePtr& msg)
+{
+ const auto type = static_cast(msg->getU8());
+
+ // 0: Send no error
+ // 1: No data available at the moment.
+ // 2: You are not allowed to see this character's data.
+ // 3: You are not allowed to inspect this character.
+ const uint8_t errorCode = msg->getU8();
+ if (errorCode > 0) {
+ return;
+ }
+
+ switch (type) {
+ case Otc::CYCLOPEDIA_CHARACTERINFO_BASEINFORMATION:
+ {
+ msg->getString(); // player name
+ msg->getString(); // player vocation name
+ msg->getU16(); // player level
+ getOutfit(msg, false);
+ msg->getU8(); // ???
+ msg->getString(); // current title name
+ break;
+ }
+ case Otc::CYCLOPEDIA_CHARACTERINFO_GENERALSTATS:
+ {
+ CyclopediaCharacterGeneralStats stats;
+ stats.experience = msg->getU64();
+ stats.level = msg->getU16();
+ stats.levelPercent = msg->getU8();
+ stats.baseExpGain = msg->getU16();
+ stats.lowLevelExpBonus = msg->getU16();
+ stats.XpBoostPercent = msg->getU16();
+ stats.staminaExpBonus = msg->getU16();
+ stats.XpBoostBonusRemainingTime = msg->getU16();
+ stats.canBuyXpBoost = msg->getU8();
+ stats.health = msg->getU32();
+ stats.maxHealth = msg->getU32();
+ stats.mana = msg->getU32();
+ stats.maxMana = msg->getU32();
+ stats.soul = msg->getU8();
+ stats.staminaMinutes = msg->getU16();
+ stats.regenerationCondition = msg->getU16();
+ stats.offlineTrainingTime = msg->getU16();
+ stats.speed = msg->getU16();
+ stats.baseSpeed = msg->getU16();
+ stats.capacity = msg->getU32();
+ stats.baseCapacity = msg->getU32();
+ stats.freeCapacity = msg->getU32();
+ msg->getU8();
+ msg->getU8();
+ stats.magicLevel = msg->getU16();
+ stats.baseMagicLevel = msg->getU16();
+ stats.loyaltyMagicLevel = msg->getU16();
+ stats.magicLevelPercent = msg->getU16();
+
+ std::vector> skills;
+
+ for (int_fast32_t skill = Otc::Fist; skill <= Otc::Fishing; ++skill) {
+ msg->getU8(); // Hardcoded Skill Ids
+ const uint16_t skillLevel = msg->getU16();
+ const uint16_t baseSkill = msg->getU16();
+ msg->getU16(); // base + loyalty bonus(?)
+ const uint16_t skillPercent = msg->getU16() / 100;
+ skills.push_back({ skillLevel, skillPercent, baseSkill });
+ }
+
+ const uint8_t combatCount = msg->getU8();
+ std::vector> combats;
+
+ for (auto i = 0; i < combatCount; ++i) {
+ const uint8_t element = msg->getU8();
+ const uint16_t specializedMagicLevel = msg->getU16();
+ combats.emplace_back(element, specializedMagicLevel);
+ }
+
+ g_game.processCyclopediaCharacterGeneralStats(stats, skills, combats);
+ break;
+ }
+ case Otc::CYCLOPEDIA_CHARACTERINFO_COMBATSTATS:
+ {
+ std::vector> additionalSkillsArray;
+
+ if (g_game.getFeature(Otc::GameAdditionalSkills)) {
+ // Critical, Life Leech, Mana Leech
+ for (uint16_t skill = Otc::CriticalChance; skill <= Otc::ManaLeechAmount; ++skill) {
+ if (!g_game.getFeature(Otc::GameLeechAmount)) {
+ if (skill == Otc::LifeLeechAmount || skill == Otc::ManaLeechAmount) {
+ continue;
+ }
+ }
+
+ const uint16_t skillLevel = msg->getU16();
+ msg->getU16();
+ additionalSkillsArray.push_back({ skill, skillLevel });
+ }
+ }
+
+ std::vector> forgeSkillsArray;
+
+ if (g_game.getClientVersion() >= 1281) {
+ // forge skill stats
+ const uint8_t lastSkill = g_game.getClientVersion() >= 1332 ? Otc::LastSkill : Otc::Momentum + 1;
+ for (uint16_t skill = Otc::Fatal; skill < lastSkill; ++skill) {
+ const uint16_t skillLevel = msg->getU16();
+ msg->getU16();
+ forgeSkillsArray.push_back({ skill, skillLevel });
+ }
+ }
+
+ msg->getU16(); // Cleave Percent
+ msg->getU16(); // Magic Shield Capacity Flat
+ msg->getU16(); // Magic Shield Capacity Percent
+
+ std::vector perfectShotDamageRangesArray;
+
+ for (auto i = 1; i <= 5; i++) {
+ const uint16_t perfectShotDamageRange = msg->getU16();
+ perfectShotDamageRangesArray.emplace_back(perfectShotDamageRange);
+ }
+
+ msg->getU16(); // Damage reflection
+
+ CyclopediaCharacterCombatStats data;
+ data.haveBlessings = msg->getU8();
+ msg->getU8(); // total blessings
+
+ data.weaponMaxHitChance = msg->getU16();
+ data.weaponElement = msg->getU8();
+ data.weaponElementDamage = msg->getU8();
+ data.weaponElementType = msg->getU8();
+ data.armor = msg->getU16();
+ data.defense = msg->getU16();
+ const double mitigation = msg->getDouble();
+
+ const uint8_t combatCount = msg->getU8();
+ std::vector> combatsArray;
+
+ for (auto i = 0; i < combatCount; ++i) {
+ const uint8_t element = msg->getU8();
+ const uint16_t clientModifier = msg->getU16();
+ combatsArray.emplace_back(element, clientModifier);
+ }
+
+ const uint8_t concoctionsCount = msg->getU8();
+ std::vector> concoctionsArray;
+
+ for (auto i = 0; i < concoctionsCount; ++i) {
+ const uint16_t concoctionFirst = msg->getU8();
+ const uint16_t concoctionSecond = msg->getU16();
+ concoctionsArray.emplace_back(concoctionFirst, concoctionSecond);
+ }
+
+ g_game.processCyclopediaCharacterCombatStats(data, mitigation, additionalSkillsArray, forgeSkillsArray, perfectShotDamageRangesArray, combatsArray, concoctionsArray);
+ break;
+ }
+ case Otc::CYCLOPEDIA_CHARACTERINFO_RECENTDEATHS:
+ {
+ CyclopediaCharacterRecentDeaths data;
+ msg->getU16();
+ msg->getU16();
+
+ const uint16_t entriesCount = msg->getU16();
+ for (auto i = 0; i < entriesCount; ++i) {
+ RecentDeathEntry entry;
+ entry.timestamp = msg->getU32();
+ entry.cause = msg->getString();
+ data.entries.emplace_back(entry);
+ }
+
+ g_game.processCyclopediaCharacterRecentDeaths(data);
+ break;
+ }
+ case Otc::CYCLOPEDIA_CHARACTERINFO_RECENTPVPKILLS:
+ {
+ CyclopediaCharacterRecentPvPKills data;
+ msg->getU16();
+ msg->getU16();
+
+ const uint16_t entriesCount = msg->getU16();
+ for (auto i = 0; i < entriesCount; ++i) {
+ RecentPvPKillEntry entry;
+ entry.timestamp = msg->getU32();
+ entry.description = msg->getString();
+ entry.status = msg->getU8();
+ data.entries.emplace_back(entry);
+ }
+
+ g_game.processCyclopediaCharacterRecentPvpKills(data);
+ break;
+ }
+ case Otc::CYCLOPEDIA_CHARACTERINFO_ACHIEVEMENTS:
+ {
+ break;
+ }
+ case Otc::CYCLOPEDIA_CHARACTERINFO_ITEMSUMMARY:
+ {
+ CyclopediaCharacterItemSummary data;
+
+ const uint16_t inventoryItemsCount = msg->getU16();
+ for (auto i = 0; i < inventoryItemsCount; ++i) {
+ ItemSummary item;
+ const uint16_t itemId = msg->getU16();
+ const auto& itemCreated = Item::create(itemId);
+ const uint16_t classification = itemCreated->getClassification();
+
+ uint8_t itemClass = 0;
+ if (classification > 0) {
+ itemClass = msg->getU8();
+ }
+
+ item.itemId = itemId;
+ item.classification = itemClass;
+ item.amount = msg->getU32();
+ data.inventory.emplace_back(item);
+ }
+
+ const uint16_t storeItemsCount = msg->getU16();
+ for (auto i = 0; i < storeItemsCount; ++i) {
+ ItemSummary item;
+ const uint16_t itemId = msg->getU16();
+ const auto& itemCreated = Item::create(itemId);
+ const uint16_t classification = itemCreated->getClassification();
+
+ uint8_t itemClass = 0;
+ if (classification > 0) {
+ itemClass = msg->getU8();
+ }
+
+ item.itemId = itemId;
+ item.classification = itemClass;
+ item.amount = msg->getU32();
+ data.store.emplace_back(item);
+ }
+
+ const uint16_t stashItemsCount = msg->getU16();
+ for (auto i = 0; i < stashItemsCount; ++i) {
+ ItemSummary item;
+ const uint16_t itemId = msg->getU16();
+ const auto& itemCreated = Item::create(itemId);
+ const uint16_t classification = itemCreated->getClassification();
+
+ uint8_t itemClass = 0;
+ if (classification > 0) {
+ itemClass = msg->getU8();
+ }
+
+ item.itemId = itemId;
+ item.classification = itemClass;
+ item.amount = msg->getU32();
+ data.stash.emplace_back(item);
+ }
+
+ const uint16_t depotItemsCount = msg->getU16();
+ for (auto i = 0; i < depotItemsCount; ++i) {
+ ItemSummary item;
+ const uint16_t itemId = msg->getU16();
+ const auto& itemCreated = Item::create(itemId);
+ const uint16_t classification = itemCreated->getClassification();
+
+ uint8_t itemClass = 0;
+ if (classification > 0) {
+ itemClass = msg->getU8();
+ }
+
+ item.itemId = itemId;
+ item.classification = itemClass;
+ item.amount = msg->getU32();
+ data.depot.emplace_back(item);
+ }
+
+ const uint16_t inboxItemsCount = msg->getU16();
+ for (auto i = 0; i < inboxItemsCount; ++i) {
+ ItemSummary item;
+ const uint16_t itemId = msg->getU16();
+ const auto& itemCreated = Item::create(itemId);
+ const uint16_t classification = itemCreated->getClassification();
+
+ uint8_t itemClass = 0;
+ if (classification > 0) {
+ itemClass = msg->getU8();
+ }
+
+ item.itemId = itemId;
+ item.classification = itemClass;
+ item.amount = msg->getU32();
+ data.inbox.emplace_back(item);
+ }
+
+ g_game.processCyclopediaCharacterItemSummary(data);
+ break;
+ }
+ case Otc::CYCLOPEDIA_CHARACTERINFO_OUTFITSMOUNTS:
+ {
+ const uint16_t outfitsSize = msg->getU16();
+ std::vector outfits;
+
+ for (auto i = 0; i < outfitsSize; ++i) {
+ CharacterInfoOutfits outfit;
+ outfit.lookType = msg->getU16();
+ outfit.name = msg->getString();
+ outfit.addons = msg->getU8();
+ outfit.type = msg->getU8(); // store / quest / none
+ outfit.isCurrent = msg->getU32(); // 1000 = true / 0 = false
+ outfits.emplace_back(outfit);
+ }
+
+ OutfitColorStruct currentOutfit;
+ if (outfitsSize > 0) {
+ currentOutfit.lookHead = msg->getU8();
+ currentOutfit.lookBody = msg->getU8();
+ currentOutfit.lookLegs = msg->getU8();
+ currentOutfit.lookFeet = msg->getU8();
+ }
+
+ const uint16_t mountsSize = msg->getU16();
+ std::vector mounts;
+
+ for (auto i = 0; i < mountsSize; ++i) {
+ CharacterInfoMounts mount;
+ mount.mountId = msg->getU16();
+ mount.name = msg->getString();
+ mount.type = msg->getU8(); // store / quest / none
+ mount.isCurrent = msg->getU32(); // 1000 = true / 0 = false
+ mounts.emplace_back(mount);
+ }
+
+ if (mountsSize > 0) {
+ currentOutfit.lookMountHead = msg->getU8();
+ currentOutfit.lookMountBody = msg->getU8();
+ currentOutfit.lookMountLegs = msg->getU8();
+ currentOutfit.lookMountFeet = msg->getU8();
+ }
+
+ const uint16_t familiarsSize = msg->getU16();
+ std::vector familiars;
+
+ for (auto i = 0; i < familiarsSize; ++i) {
+ CharacterInfoFamiliar familiar;
+ familiar.lookType = msg->getU16();
+ familiar.name = msg->getString();
+ familiar.type = msg->getU8(); // quest / none
+ familiar.isCurrent = msg->getU32(); // 1000 = true / 0 = false
+ familiars.emplace_back(familiar);
+ }
+
+ g_game.processCyclopediaCharacterAppearances(currentOutfit, outfits, mounts, familiars);
+ break;
+ }
+ case Otc::CYCLOPEDIA_CHARACTERINFO_STORESUMMARY:
+ {
+ const uint32_t xpBoostTime = msg->getU32();
+ const uint32_t dailyRewardXpBoostTime = msg->getU32();
+
+ std::vector> blessings;
+ const uint8_t blessingCount = msg->getU8();
+
+ for (auto i = 0; i < blessingCount; ++i) {
+ const auto& blessingName = msg->getString();
+ const uint8_t blessingObtained = msg->getU8();
+ blessings.emplace_back(blessingName, blessingObtained);
+ }
+
+ const uint8_t preySlotsUnlocked = msg->getU8();
+ const uint8_t preyWildcards = msg->getU8();
+ const uint8_t instantRewards = msg->getU8();
+ const bool hasCharmExpansion = static_cast(msg->getU8());
+ const uint8_t hirelingsObtained = msg->getU8();
+
+ std::vector hirelingSkills;
+ const uint8_t hirelingSkillsCount = msg->getU8();
+
+ for (auto i = 0; i < hirelingSkillsCount; ++i) {
+ const uint8_t skill = msg->getU8();
+ hirelingSkills.emplace_back(static_cast(skill + 1000));
+ }
+
+ msg->getU8();
+
+ std::vector> houseItems;
+ const uint16_t houseItemsCount = msg->getU16();
+
+ for (auto i = 0; i < houseItemsCount; ++i) {
+ const uint16_t itemId = msg->getU16();
+ const auto& itemName = msg->getString();
+ const uint8_t count = msg->getU8();
+ houseItems.emplace_back(itemId, itemName, count);
+ }
+ g_lua.callGlobalField("g_game", "onParseCyclopediaStoreSummary", xpBoostTime, dailyRewardXpBoostTime, blessings, preySlotsUnlocked, preyWildcards, instantRewards, hasCharmExpansion, hirelingsObtained, hirelingSkills, houseItems);
+ break;
+ }
+ case Otc::CYCLOPEDIA_CHARACTERINFO_INSPECTION:
+ {
+ break;
+ }
+ case Otc::CYCLOPEDIA_CHARACTERINFO_BADGES:
+ {
+ const uint8_t showAccountInformation = msg->getU8();
+ const uint8_t playerOnline = msg->getU8();
+ const uint8_t playerPremium = msg->getU8();
+ const auto& loyaltyTitle = msg->getString();
+
+ const uint8_t badgesSize = msg->getU8();
+ std::vector> badgesVector;
+
+ for (auto i = 0; i < badgesSize; ++i) {
+ const uint32_t badgeId = msg->getU32();
+ const auto& badgeName = msg->getString();
+ badgesVector.emplace_back(badgeId, badgeName);
+ }
+
+ g_game.processCyclopediaCharacterGeneralStatsBadge(showAccountInformation, playerOnline, playerPremium, loyaltyTitle, badgesVector);
+ break;
+ }
+ case Otc::CYCLOPEDIA_CHARACTERINFO_TITLES:
+ {
+ msg->getU8(); // current title
+ const uint8_t titlesSize = msg->getU8();
+ for (auto i = 0; i < titlesSize; ++i) {
+ msg->getString(); // title name
+ msg->getString(); // title description
+ msg->getU8(); // bool title permanent
+ msg->getU8(); // bool title unlocked
+ }
+ break;
+ }
+ }
+}
+
void ProtocolGame::parseDailyRewardCollectionState(const InputMessagePtr& msg)
{
msg->getU8(); // state
@@ -4367,47 +5030,55 @@ void ProtocolGame::parseBosstiaryData(const InputMessagePtr& msg)
void ProtocolGame::parseBosstiarySlots(const InputMessagePtr& msg)
{
- const auto& getBosstiarySlot = [&]() {
- msg->getU8(); // Boss Race
- msg->getU32(); // Kill Count
- msg->getU16(); // Loot Bonus
- msg->getU8(); // Kill Bonus
- msg->getU8(); // Boss Race
- msg->getU32(); // Remove Price
- msg->getU8(); // Inactive? (Only true if equal to Boosted Boss)
+ BosstiarySlotsData data;
+
+ auto getBosstiarySlot = [&msg]() -> BosstiarySlot {
+ BosstiarySlot slot;
+ slot.bossRace = msg->getU8();
+ slot.killCount = msg->getU32();
+ slot.lootBonus = msg->getU16();
+ slot.killBonus = msg->getU8();
+ slot.bossRaceRepeat = msg->getU8();
+ slot.removePrice = msg->getU32();
+ slot.inactive = msg->getU8();
+ return slot;
};
- msg->getU32(); // Player Points
- msg->getU32(); // Total Points next bonus
- msg->getU16(); // Current Bonus
- msg->getU16(); // Next Bonus
+ data.playerPoints = msg->getU32();
+ data.totalPointsNextBonus = msg->getU32();
+ data.currentBonus = msg->getU16();
+ data.nextBonus = msg->getU16();
- const bool isSlotOneUnlocked = static_cast(msg->getU8());
- const uint32_t bossIdSlotOne = msg->getU32();
- if (isSlotOneUnlocked && bossIdSlotOne > 0) {
- getBosstiarySlot();
+ data.isSlotOneUnlocked = msg->getU8();
+ data.bossIdSlotOne = msg->getU32();
+ if (data.isSlotOneUnlocked && data.bossIdSlotOne != 0) {
+ data.slotOneData = getBosstiarySlot();
}
- const bool isSlotTwoUnlocked = static_cast(msg->getU8());
- const uint32_t bossIdSlotTwo = msg->getU32();
- if (isSlotTwoUnlocked && bossIdSlotTwo > 0) {
- getBosstiarySlot();
+ data.isSlotTwoUnlocked = msg->getU8();
+ data.bossIdSlotTwo = msg->getU32();
+ if (data.isSlotTwoUnlocked && data.bossIdSlotTwo != 0) {
+ data.slotTwoData = getBosstiarySlot();
}
- const bool isTodaySlotUnlocked = static_cast(msg->getU8());
- const uint32_t boostedBossId = msg->getU32();
- if (isTodaySlotUnlocked && boostedBossId > 0) {
- getBosstiarySlot();
+ data.isTodaySlotUnlocked = msg->getU8();
+ data.boostedBossId = msg->getU32();
+ if (data.isTodaySlotUnlocked && data.boostedBossId != 0) {
+ data.todaySlotData = getBosstiarySlot();
}
- const bool bossesUnlocked = static_cast(msg->getU8());
- if (bossesUnlocked) {
+ data.bossesUnlocked = msg->getU8();
+ if (data.bossesUnlocked) {
const uint16_t bossesUnlockedSize = msg->getU16();
for (auto i = 0; i < bossesUnlockedSize; ++i) {
- msg->getU32(); // bossId
- msg->getU8(); // bossRace
+ BossUnlocked boss;
+ boss.bossId = msg->getU32();
+ boss.bossRace = msg->getU8();
+ data.bossesUnlockedData.emplace_back(boss);
}
}
+
+ g_game.processBosstiarySlots(data);
}
void ProtocolGame::parseBosstiaryCooldownTimer(const InputMessagePtr& msg)
diff --git a/src/client/protocolgamesend.cpp b/src/client/protocolgamesend.cpp
index 0a0e367138..aa1b25b1e5 100644
--- a/src/client/protocolgamesend.cpp
+++ b/src/client/protocolgamesend.cpp
@@ -942,6 +942,110 @@ void ProtocolGame::sendSeekInContainer(const uint8_t containerId, const uint16_t
send(msg);
}
+void ProtocolGame::sendInspectionNormalObject(const Position& position)
+{
+ const auto& msg = std::make_shared();
+ msg->addU8(Proto::ClientInspectionObject);
+ msg->addU8(Otc::INSPECT_NORMALOBJECT);
+ addPosition(msg, position);
+ send(msg);
+}
+
+void ProtocolGame::sendInspectionObject(const Otc::InspectObjectTypes inspectionType, const uint16_t itemId, const uint8_t itemCount)
+{
+ if (inspectionType != Otc::INSPECT_NPCTRADE && inspectionType != Otc::INSPECT_CYCLOPEDIA) {
+ return;
+ }
+
+ const auto& msg = std::make_shared();
+ msg->addU8(Proto::ClientInspectionObject);
+ msg->addU8(inspectionType);
+ msg->addU16(itemId);
+ msg->addU8(itemCount);
+ send(msg);
+}
+
+void ProtocolGame::sendRequestBestiary()
+{
+ const auto& msg = std::make_shared();
+ msg->addU8(Proto::ClientBestiaryRequest);
+ send(msg);
+}
+
+void ProtocolGame::sendRequestBestiaryOverview(const std::string_view catName)
+{
+ const auto& msg = std::make_shared();
+ msg->addU8(Proto::ClientBestiaryRequestOverview);
+ msg->addU8(0x02);
+ msg->addString(catName);
+ send(msg);
+}
+
+void ProtocolGame::sendRequestBestiarySearch(const uint16_t raceId)
+{
+ const auto& msg = std::make_shared();
+ msg->addU8(Proto::ClientBestiaryRequestSearch);
+ msg->addU16(raceId);
+ send(msg);
+}
+
+void ProtocolGame::sendBuyCharmRune(const uint8_t runeId, const uint8_t action, const uint16_t raceId)
+{
+ const auto& msg = std::make_shared();
+ msg->addU8(Proto::ClientCyclopediaSendBuyCharmRune);
+ msg->addU8(runeId);
+ msg->addU8(action);
+ msg->addU16(raceId);
+ send(msg);
+}
+
+void ProtocolGame::sendCyclopediaRequestCharacterInfo(const uint32_t playerId, const Otc::CyclopediaCharacterInfoType_t characterInfoType, const uint16_t entriesPerPage, const uint16_t page)
+{
+ const auto& msg = std::make_shared();
+ msg->addU8(Proto::ClientCyclopediaRequestCharacterInfo);
+ msg->addU32(playerId);
+ msg->addU8(characterInfoType);
+
+ if (characterInfoType == Otc::CYCLOPEDIA_CHARACTERINFO_RECENTDEATHS || characterInfoType == Otc::CYCLOPEDIA_CHARACTERINFO_RECENTPVPKILLS) {
+ msg->addU16(entriesPerPage);
+ msg->addU16(page);
+ }
+
+ send(msg);
+}
+
+void ProtocolGame::sendRequestBosstiaryInfo()
+{
+ const auto& msg = std::make_shared();
+ msg->addU8(Proto::ClientBosstiaryRequestInfo);
+ send(msg);
+}
+
+void ProtocolGame::sendRequestBossSlootInfo()
+{
+ const auto& msg = std::make_shared();
+ msg->addU8(Proto::ClientBosstiaryRequestSlotInfo);
+ send(msg);
+}
+
+void ProtocolGame::sendRequestBossSlotAction(const uint8_t action, const uint32_t raceId)
+{
+ const auto& msg = std::make_shared();
+ msg->addU8(Proto::ClientBosstiaryRequestSlotAction);
+ msg->addU8(action);
+ msg->addU32(raceId);
+ send(msg);
+}
+
+void ProtocolGame::sendStatusTrackerBestiary(const uint16_t raceId, const bool status)
+{
+ const auto& msg = std::make_shared();
+ msg->addU8(Proto::ClientBestiaryTrackerStatus);
+ msg->addU16(raceId);
+ msg->addU8(static_cast(status));
+ send(msg);
+}
+
void ProtocolGame::sendBuyStoreOffer(const uint32_t offerId, const uint8_t productType, const std::string_view name)
{
const auto& msg = std::make_shared();
diff --git a/src/framework/ui/uitextedit.cpp b/src/framework/ui/uitextedit.cpp
index 8d869a3b5e..a384aa1c82 100644
--- a/src/framework/ui/uitextedit.cpp
+++ b/src/framework/ui/uitextedit.cpp
@@ -30,6 +30,8 @@
#include
#include "framework/graphics/drawpoolmanager.h"
+#include "uitranslator.h"
+#include
UITextEdit::UITextEdit()
{
@@ -43,6 +45,10 @@ UITextEdit::UITextEdit()
setProp(Props::PropGlyphsMustRecache, true);
m_textAlign = Fw::AlignTopLeft;
+ m_placeholder = "";
+ m_placeholderColor = Color::gray;
+ m_placeholderFont = g_fonts.getDefaultFont();
+ m_placeholderAlign = Fw::AlignLeftCenter;
blinkCursor();
}
@@ -65,6 +71,11 @@ void UITextEdit::drawSelf(DrawPoolType drawPane)
setProp(PropGlyphsMustRecache, false);
const int textLength = std::min(m_glyphsCoords.size(), m_text.length());
+ if (textLength == 0) {
+ if (m_placeholderColor != Color::alpha && !m_placeholder.empty()) {
+ m_placeholderFont->drawText(m_placeholder, m_drawArea, m_placeholderColor, m_placeholderAlign);
+ }
+ }
if (m_color != Color::alpha) {
if (glyphsMustRecache) {
m_glyphsTextRectCache.clear();
@@ -637,6 +648,14 @@ void UITextEdit::onStyleApply(const std::string_view styleName, const OTMLNodePt
setChangeCursorImage(node->value());
else if (node->tag() == "auto-scroll")
setAutoScroll(node->value());
+ else if (node->tag() == "placeholder")
+ setPlaceholder(node->value());
+ else if (node->tag() == "placeholder-color")
+ setPlaceholderColor(node->value());
+ else if (node->tag() == "placeholder-align")
+ setPlaceholderAlign(Fw::translateAlignment(node->value()));
+ else if (node->tag() == "placeholder-font")
+ setPlaceholderFont(node->value());
}
}
@@ -839,4 +858,9 @@ bool UITextEdit::onDoubleClick(const Point& mousePos)
void UITextEdit::onTextAreaUpdate(const Point& offset, const Size& visibleSize, const Size& totalSize)
{
callLuaField("onTextAreaUpdate", offset, visibleSize, totalSize);
-}
\ No newline at end of file
+}
+
+void UITextEdit::setPlaceholderFont(const std::string_view fontName)
+{
+ m_placeholderFont = g_fonts.getFont(fontName);
+}
diff --git a/src/framework/ui/uitextedit.h b/src/framework/ui/uitextedit.h
index d0092b455e..fbb5555ebf 100644
--- a/src/framework/ui/uitextedit.h
+++ b/src/framework/ui/uitextedit.h
@@ -51,6 +51,10 @@ class UITextEdit : public UIWidget
void setSelectionColor(const Color& color) { m_selectionColor = color; }
void setSelectionBackgroundColor(const Color& color) { m_selectionBackgroundColor = color; }
void setAutoScroll(bool autoScroll) { setProp(PropAutoScroll, autoScroll); }
+ void setPlaceholder(std::string placeholder) { m_placeholder = placeholder; }
+ void setPlaceholderColor(const Color& color) { m_placeholderColor = color; }
+ void setPlaceholderAlign(Fw::AlignmentFlag align) { m_placeholderAlign = align; }
+ void setPlaceholderFont(const std::string_view fontName);
void moveCursorHorizontally(bool right);
void moveCursorVertically(bool up);
@@ -152,4 +156,9 @@ class UITextEdit : public UIWidget
std::vector> m_glyphsSelectRectCache;
std::string m_displayedText;
+
+ std::string m_placeholder;
+ Color m_placeholderColor;
+ Fw::AlignmentFlag m_placeholderAlign;
+ BitmapFontPtr m_placeholderFont;
};