Client Upload Part 2

RD Core / Commit #5

Commit Client Upload Part 2

Alex Alex committed 19/10/2026 00:06 main Patch
1,244 files +271,215 -0
A RD_Client/modules/game_npc/npc.otmod +13-0 View file
@@ -0,0 +1,13 @@
1+Module
2+ name: game_npc
3+ description: NPC Chat
4+ author: Frenesy
5+ website: https://github.com/edubart/otclient
6+ sandboxed: true
7+ scripts: [ npc ]
8+
9+ autoload: true
10+ autoload-priority: 1000
11+
12+ @onLoad: init()
13+ @onUnload: terminate()
A RD_Client/modules/game_npc/npc.otui +90-0 View file
@@ -0,0 +1,90 @@
1+MainWindow
2+ id: npcWindow
3+ size: 600 270
4+ image-source: /images/custom/UI/npc_chat
5+ draggable: false
6+ focusable: true
7+ @onEscape: closeNPCChat()
8+
9+ UIButton
10+ id: NPCname
11+ size: 450 30
12+ font: sans-bold-16px
13+ text-align: left
14+ anchors.top: parent.top
15+ anchors.left: parent.left
16+ margin-left: 45
17+ margin-top: -20
18+
19+ UIButton
20+ id: S
21+ size: 530 3
22+ image-source: /images/custom/UI/s
23+ anchors.top: NPCname.bottom
24+ anchors.left: parent.left
25+ margin-left: 42
26+
27+ $mobile:
28+ visible: false
29+
30+ Label
31+ id: textNPC
32+ size: 520 100
33+ font: verdana-11px-rounded
34+ text-wrap: true
35+ text: "Texto de exemplo do NPC"
36+ anchors.top: S.bottom
37+ anchors.left: parent.left
38+ margin-left: 42
39+ margin-top: 10
40+
41+ $mobile:
42+ size: 450 100
43+
44+ UIButton
45+ id: choose1
46+ size: 520 25
47+ image-source: /images/custom/UI/choose_off
48+ font: verdana-11px-rounded
49+ text-align: left
50+ text-offset: 10 0
51+ text: "Escolha a opcao 01"
52+ anchors.top: textNPC.bottom
53+ anchors.left: parent.left
54+ margin-left: 10
55+ margin-top: 10
56+
57+ $mobile:
58+ size: 450 25
59+
60+ UIButton
61+ id: choose2
62+ size: 520 25
63+ image-source: /images/custom/UI/choose_off
64+ font: verdana-11px-rounded
65+ text-align: left
66+ text-offset: 10 0
67+ text: "Escolha a opcao 02"
68+ anchors.top: choose1.bottom
69+ anchors.left: parent.left
70+ margin-left: 10
71+ margin-top: 5
72+
73+ $mobile:
74+ size: 450 25
75+
76+ UIButton
77+ id: choose3
78+ size: 520 25
79+ image-source: /images/custom/UI/choose_off
80+ font: verdana-11px-rounded
81+ text-align: left
82+ text-offset: 10 0
83+ text: "Escolha a opcao 03"
84+ anchors.top: choose2.bottom
85+ anchors.left: parent.left
86+ margin-left: 10
87+ margin-top: 5
88+
89+ $mobile:
90+ size: 450 25
A RD_Client/modules/game_npctrade/npctrade.lua +579-0 View file
@@ -0,0 +1,579 @@
1+BUY = 1
2+SELL = 2
3+CURRENCY = 'gold'
4+CURRENCY_DECIMAL = false
5+WEIGHT_UNIT = 'oz'
6+LAST_INVENTORY = 10
7+
8+npcWindow = nil
9+itemsPanel = nil
10+radioTabs = nil
11+radioItems = nil
12+searchText = nil
13+setupPanel = nil
14+quantity = nil
15+quantityScroll = nil
16+idLabel = nil
17+nameLabel = nil
18+priceLabel = nil
19+moneyLabel = nil
20+weightDesc = nil
21+weightLabel = nil
22+capacityDesc = nil
23+capacityLabel = nil
24+tradeButton = nil
25+buyTab = nil
26+sellTab = nil
27+initialized = false
28+
29+showWeight = true
30+buyWithBackpack = nil
31+ignoreCapacity = nil
32+ignoreEquipped = nil
33+showAllItems = nil
34+sellAllButton = nil
35+sellAllWithDelayButton = nil
36+playerFreeCapacity = 0
37+playerMoney = 0
38+tradeItems = {}
39+playerItems = {}
40+selectedItem = nil
41+
42+cancelNextRelease = nil
43+
44+sellAllWithDelayEvent = nil
45+
46+function init()
47+ npcWindow = g_ui.displayUI('npctrade')
48+ npcWindow:setVisible(false)
49+
50+ itemsPanel = npcWindow:recursiveGetChildById('itemsPanel')
51+ searchText = npcWindow:recursiveGetChildById('searchText')
52+
53+ setupPanel = npcWindow:recursiveGetChildById('setupPanel')
54+ quantityScroll = setupPanel:getChildById('quantityScroll')
55+ idLabel = setupPanel:getChildById('id')
56+ nameLabel = setupPanel:getChildById('name')
57+ priceLabel = setupPanel:getChildById('price')
58+ moneyLabel = setupPanel:getChildById('money')
59+ weightDesc = setupPanel:getChildById('weightDesc')
60+ weightLabel = setupPanel:getChildById('weight')
61+ capacityDesc = setupPanel:getChildById('capacityDesc')
62+ capacityLabel = setupPanel:getChildById('capacity')
63+ tradeButton = npcWindow:recursiveGetChildById('tradeButton')
64+
65+ buyWithBackpack = npcWindow:recursiveGetChildById('buyWithBackpack')
66+ ignoreCapacity = npcWindow:recursiveGetChildById('ignoreCapacity')
67+ ignoreEquipped = npcWindow:recursiveGetChildById('ignoreEquipped')
68+ showAllItems = npcWindow:recursiveGetChildById('showAllItems')
69+ sellAllButton = npcWindow:recursiveGetChildById('sellAllButton')
70+ sellAllWithDelayButton = npcWindow:recursiveGetChildById('sellAllWithDelayButton')
71+ buyTab = npcWindow:getChildById('buyTab')
72+ sellTab = npcWindow:getChildById('sellTab')
73+
74+ radioTabs = UIRadioGroup.create()
75+ radioTabs:addWidget(buyTab)
76+ radioTabs:addWidget(sellTab)
77+ radioTabs:selectWidget(buyTab)
78+ radioTabs.onSelectionChange = onTradeTypeChange
79+
80+ cancelNextRelease = false
81+
82+ if g_game.isOnline() then
83+ playerFreeCapacity = g_game.getLocalPlayer():getFreeCapacity()
84+ end
85+
86+ connect(g_game, { onGameEnd = hide,
87+ onOpenNpcTrade = onOpenNpcTrade,
88+ onCloseNpcTrade = onCloseNpcTrade,
89+ onPlayerGoods = onPlayerGoods } )
90+
91+ connect(LocalPlayer, { onFreeCapacityChange = onFreeCapacityChange,
92+ onInventoryChange = onInventoryChange } )
93+
94+ initialized = true
95+end
96+
97+function terminate()
98+ initialized = false
99+ npcWindow:destroy()
100+ removeEvent(sellAllWithDelayEvent)
101+
102+ disconnect(g_game, { onGameEnd = hide,
103+ onOpenNpcTrade = onOpenNpcTrade,
104+ onCloseNpcTrade = onCloseNpcTrade,
105+ onPlayerGoods = onPlayerGoods } )
106+
107+ disconnect(LocalPlayer, { onFreeCapacityChange = onFreeCapacityChange,
108+ onInventoryChange = onInventoryChange } )
109+end
110+
111+function show()
112+ if g_game.isOnline() then
113+ if #tradeItems[BUY] > 0 then
114+ radioTabs:selectWidget(buyTab)
115+ else
116+ radioTabs:selectWidget(sellTab)
117+ end
118+
119+ npcWindow:show()
120+ npcWindow:raise()
121+ npcWindow:focus()
122+ end
123+end
124+
125+function hide()
126+ removeEvent(sellAllWithDelayEvent)
127+
128+ npcWindow:hide()
129+
130+ local layout = itemsPanel:getLayout()
131+ layout:disableUpdates()
132+
133+ clearSelectedItem()
134+
135+ searchText:clearText()
136+ setupPanel:disable()
137+ itemsPanel:destroyChildren()
138+
139+ if radioItems then
140+ radioItems:destroy()
141+ radioItems = nil
142+ end
143+
144+ layout:enableUpdates()
145+ layout:update()
146+end
147+
148+function onItemBoxChecked(widget)
149+ if widget:isChecked() then
150+ local item = widget.item
151+ selectedItem = item
152+ refreshItem(item)
153+ tradeButton:enable()
154+
155+ if getCurrentTradeType() == SELL then
156+ quantityScroll:setValue(quantityScroll:getMaximum())
157+ end
158+ end
159+end
160+
161+function onQuantityValueChange(quantity)
162+ if selectedItem then
163+ weightLabel:setText(string.format('%.2f', selectedItem.weight*quantity) .. ' ' .. WEIGHT_UNIT)
164+ priceLabel:setText(formatCurrency(getItemPrice(selectedItem)))
165+ end
166+end
167+
168+function onTradeTypeChange(radioTabs, selected, deselected)
169+ tradeButton:setText(selected:getText())
170+ selected:setOn(true)
171+ deselected:setOn(false)
172+
173+ local currentTradeType = getCurrentTradeType()
174+ buyWithBackpack:setVisible(currentTradeType == BUY)
175+ ignoreCapacity:setVisible(currentTradeType == BUY)
176+ ignoreEquipped:setVisible(currentTradeType == SELL)
177+ showAllItems:setVisible(currentTradeType == SELL)
178+ sellAllButton:setVisible(currentTradeType == SELL)
179+ sellAllWithDelayButton:setVisible(currentTradeType == SELL)
180+
181+ refreshTradeItems()
182+ refreshPlayerGoods()
183+end
184+
185+function onTradeClick()
186+ removeEvent(sellAllWithDelayEvent)
187+ if getCurrentTradeType() == BUY then
188+ g_game.buyItem(selectedItem.ptr, quantityScroll:getValue(), ignoreCapacity:isChecked(), buyWithBackpack:isChecked())
189+ else
190+ g_game.sellItem(selectedItem.ptr, quantityScroll:getValue(), ignoreEquipped:isChecked())
191+ end
192+end
193+
194+function onSearchTextChange()
195+ refreshPlayerGoods()
196+end
197+
198+function itemPopup(self, mousePosition, mouseButton)
199+ if cancelNextRelease then
200+ cancelNextRelease = false
201+ return false
202+ end
203+
204+ if mouseButton == MouseRightButton then
205+ local menu = g_ui.createWidget('PopupMenu')
206+ menu:setGameMenu(true)
207+ menu:addOption(tr('Look'), function() return g_game.inspectNpcTrade(self:getItem()) end)
208+ menu:display(mousePosition)
209+ return true
210+ elseif ((g_mouse.isPressed(MouseLeftButton) and mouseButton == MouseRightButton)
211+ or (g_mouse.isPressed(MouseRightButton) and mouseButton == MouseLeftButton)) then
212+ cancelNextRelease = true
213+ g_game.inspectNpcTrade(self:getItem())
214+ return true
215+ end
216+ return false
217+end
218+
219+function onBuyWithBackpackChange()
220+ if selectedItem then
221+ refreshItem(selectedItem)
222+ end
223+end
224+
225+function onIgnoreCapacityChange()
226+ refreshPlayerGoods()
227+end
228+
229+function onIgnoreEquippedChange()
230+ refreshPlayerGoods()
231+end
232+
233+function onShowAllItemsChange()
234+ refreshPlayerGoods()
235+end
236+
237+function setCurrency(currency, decimal)
238+ CURRENCY = currency
239+ CURRENCY_DECIMAL = decimal
240+end
241+
242+function setShowWeight(state)
243+ showWeight = state
244+ weightDesc:setVisible(state)
245+ weightLabel:setVisible(state)
246+end
247+
248+function setShowYourCapacity(state)
249+ capacityDesc:setVisible(state)
250+ capacityLabel:setVisible(state)
251+ ignoreCapacity:setVisible(state)
252+end
253+
254+function clearSelectedItem()
255+ idLabel:clearText()
256+ nameLabel:clearText()
257+ weightLabel:clearText()
258+ priceLabel:clearText()
259+ tradeButton:disable()
260+ quantityScroll:setMinimum(0)
261+ quantityScroll:setMaximum(0)
262+ if selectedItem then
263+ radioItems:selectWidget(nil)
264+ selectedItem = nil
265+ end
266+end
267+
268+function getCurrentTradeType()
269+ if tradeButton:getText() == tr('Buy') then
270+ return BUY
271+ else
272+ return SELL
273+ end
274+end
275+
276+function getItemPrice(item, single)
277+ local amount = 1
278+ local single = single or false
279+ if not single then
280+ amount = quantityScroll:getValue()
281+ end
282+ if getCurrentTradeType() == BUY then
283+ if buyWithBackpack:isChecked() then
284+ if item.ptr:isStackable() then
285+ return item.price*amount + 20
286+ else
287+ return item.price*amount + math.ceil(amount/20)*20
288+ end
289+ end
290+ end
291+ return item.price*amount
292+end
293+
294+function getSellQuantity(item)
295+ if not item or not playerItems[item:getId()] then return 0 end
296+ local removeAmount = 0
297+ if ignoreEquipped:isChecked() then
298+ local localPlayer = g_game.getLocalPlayer()
299+ for i=1,LAST_INVENTORY do
300+ local inventoryItem = localPlayer:getInventoryItem(i)
301+ if inventoryItem and inventoryItem:getId() == item:getId() then
302+ removeAmount = removeAmount + inventoryItem:getCount()
303+ end
304+ end
305+ end
306+ return playerItems[item:getId()] - removeAmount
307+end
308+
309+function canTradeItem(item)
310+ if getCurrentTradeType() == BUY then
311+ return (ignoreCapacity:isChecked() or (not ignoreCapacity:isChecked() and playerFreeCapacity >= item.weight)) and playerMoney >= getItemPrice(item, true)
312+ else
313+ return getSellQuantity(item.ptr) > 0
314+ end
315+end
316+
317+function refreshItem(item)
318+ idLabel:setText(item.ptr:getId())
319+ nameLabel:setText(item.name)
320+ weightLabel:setText(string.format('%.2f', item.weight) .. ' ' .. WEIGHT_UNIT)
321+ priceLabel:setText(formatCurrency(getItemPrice(item)))
322+
323+ if getCurrentTradeType() == BUY then
324+ local capacityMaxCount = math.floor(playerFreeCapacity / item.weight)
325+ if ignoreCapacity:isChecked() then
326+ capacityMaxCount = 65535
327+ end
328+ local priceMaxCount = math.floor(playerMoney / getItemPrice(item, true))
329+ local finalCount = math.max(0, math.min(getMaxAmount(), math.min(priceMaxCount, capacityMaxCount)))
330+ quantityScroll:setMinimum(1)
331+ quantityScroll:setMaximum(finalCount)
332+ else
333+ quantityScroll:setMinimum(1)
334+ quantityScroll:setMaximum(math.max(0, math.min(getMaxAmount(), getSellQuantity(item.ptr))))
335+ end
336+
337+ setupPanel:enable()
338+end
339+
340+function refreshTradeItems()
341+ local layout = itemsPanel:getLayout()
342+ layout:disableUpdates()
343+
344+ clearSelectedItem()
345+
346+ searchText:clearText()
347+ setupPanel:disable()
348+ itemsPanel:destroyChildren()
349+
350+ if radioItems then
351+ radioItems:destroy()
352+ end
353+ radioItems = UIRadioGroup.create()
354+
355+ local currentTradeItems = tradeItems[getCurrentTradeType()]
356+ for key,item in pairs(currentTradeItems) do
357+ local itemBox = g_ui.createWidget('NPCItemBox', itemsPanel)
358+ itemBox.item = item
359+
360+ local text = ''
361+ local name = item.name
362+ text = text .. name
363+ if showWeight then
364+ local weight = string.format('%.2f', item.weight) .. ' ' .. WEIGHT_UNIT
365+ text = text .. '\n' .. weight
366+ end
367+ local price = formatCurrency(item.price)
368+ text = text .. '\n' .. price
369+ itemBox:setText(text)
370+
371+ local itemWidget = itemBox:getChildById('item')
372+ itemWidget:setItem(item.ptr)
373+ itemWidget.onMouseRelease = itemPopup
374+
375+ radioItems:addWidget(itemBox)
376+ end
377+
378+ layout:enableUpdates()
379+ layout:update()
380+end
381+
382+function refreshPlayerGoods()
383+ if not initialized then return end
384+
385+ checkSellAllTooltip()
386+
387+ moneyLabel:setText(formatCurrency(playerMoney))
388+ capacityLabel:setText(string.format('%.2f', playerFreeCapacity) .. ' ' .. WEIGHT_UNIT)
389+
390+ local currentTradeType = getCurrentTradeType()
391+ local searchFilter = searchText:getText():lower()
392+ local foundSelectedItem = false
393+
394+ local items = itemsPanel:getChildCount()
395+ for i=1,items do
396+ local itemWidget = itemsPanel:getChildByIndex(i)
397+ local item = itemWidget.item
398+
399+ local canTrade = canTradeItem(item)
400+ itemWidget:setOn(canTrade)
401+ itemWidget:setEnabled(canTrade)
402+
403+ local searchCondition = (searchFilter == '') or (searchFilter ~= '' and string.find(item.name:lower(), searchFilter) ~= nil)
404+ local showAllItemsCondition = (currentTradeType == BUY) or (showAllItems:isChecked()) or (currentTradeType == SELL and not showAllItems:isChecked() and canTrade)
405+ itemWidget:setVisible(searchCondition and showAllItemsCondition)
406+
407+ if selectedItem == item and itemWidget:isEnabled() and itemWidget:isVisible() then
408+ foundSelectedItem = true
409+ end
410+ end
411+
412+ if not foundSelectedItem then
413+ clearSelectedItem()
414+ end
415+
416+ if selectedItem then
417+ refreshItem(selectedItem)
418+ end
419+end
420+
421+function onOpenNpcTrade(items)
422+ tradeItems[BUY] = {}
423+ tradeItems[SELL] = {}
424+ for key,item in pairs(items) do
425+ if item[4] > 0 then
426+ local newItem = {}
427+ newItem.ptr = item[1]
428+ newItem.name = item[2]
429+ newItem.weight = item[3] / 100
430+ newItem.price = item[4]
431+ table.insert(tradeItems[BUY], newItem)
432+ end
433+
434+ if item[5] > 0 then
435+ local newItem = {}
436+ newItem.ptr = item[1]
437+ newItem.name = item[2]
438+ newItem.weight = item[3] / 100
439+ newItem.price = item[5]
440+ table.insert(tradeItems[SELL], newItem)
441+ end
442+ end
443+
444+ refreshTradeItems()
445+ addEvent(show) -- player goods has not been parsed yet
446+end
447+
448+function closeNpcTrade()
449+ g_game.closeNpcTrade()
450+ addEvent(hide)
451+end
452+
453+function onCloseNpcTrade()
454+ addEvent(hide)
455+end
456+
457+function onPlayerGoods(money, items)
458+ playerMoney = money
459+
460+ playerItems = {}
461+ for key,item in pairs(items) do
462+ local id = item[1]:getId()
463+ if not playerItems[id] then
464+ playerItems[id] = item[2]
465+ else
466+ playerItems[id] = playerItems[id] + item[2]
467+ end
468+ end
469+
470+ refreshPlayerGoods()
471+end
472+
473+function onFreeCapacityChange(localPlayer, freeCapacity, oldFreeCapacity)
474+ playerFreeCapacity = freeCapacity
475+
476+ if npcWindow:isVisible() then
477+ refreshPlayerGoods()
478+ end
479+end
480+
481+function onInventoryChange(inventory, item, oldItem)
482+ refreshPlayerGoods()
483+end
484+
485+function getTradeItemData(id, type)
486+ if table.empty(tradeItems[type]) then
487+ return false
488+ end
489+
490+ if type then
491+ for key,item in pairs(tradeItems[type]) do
492+ if item.ptr and item.ptr:getId() == id then
493+ return item
494+ end
495+ end
496+ else
497+ for _,items in pairs(tradeItems) do
498+ for key,item in pairs(items) do
499+ if item.ptr and item.ptr:getId() == id then
500+ return item
501+ end
502+ end
503+ end
504+ end
505+ return false
506+end
507+
508+function checkSellAllTooltip()
509+ sellAllButton:setEnabled(true)
510+ sellAllButton:removeTooltip()
511+ sellAllWithDelayButton:setEnabled(true)
512+ sellAllWithDelayButton:removeTooltip()
513+
514+ local total = 0
515+ local info = ''
516+ local first = true
517+
518+ for key, amount in pairs(playerItems) do
519+ local data = getTradeItemData(key, SELL)
520+ if data then
521+ amount = getSellQuantity(data.ptr)
522+ if amount > 0 then
523+ if data and amount > 0 then
524+ info = info..(not first and "\n" or "")..
525+ amount.." "..
526+ data.name.." ("..
527+ data.price*amount.." gold)"
528+
529+ total = total+(data.price*amount)
530+ if first then first = false end
531+ end
532+ end
533+ end
534+ end
535+ if info ~= '' then
536+ info = info.."\nTotal: "..total.." gold"
537+ sellAllButton:setTooltip(info)
538+ sellAllWithDelayButton:setTooltip(info)
539+ else
540+ sellAllButton:setEnabled(false)
541+ sellAllWithDelayButton:setEnabled(false)
542+ end
543+end
544+
545+function formatCurrency(amount)
546+ if CURRENCY_DECIMAL then
547+ return string.format("%.02f", amount/100.0) .. ' ' .. CURRENCY
548+ else
549+ return amount .. ' ' .. CURRENCY
550+ end
551+end
552+
553+function getMaxAmount()
554+ if getCurrentTradeType() == SELL and g_game.getFeature(GameDoubleShopSellAmount) then
555+ return 10000
556+ end
557+ return 100
558+end
559+
560+function sellAll(delayed)
561+ removeEvent(sellAllWithDelayEvent)
562+ local queue = {}
563+ for _,entry in ipairs(tradeItems[SELL]) do
564+ local sellQuantity = getSellQuantity(entry.ptr)
565+ while sellQuantity > 0 do
566+ local maxAmount = math.min(sellQuantity, getMaxAmount())
567+ if delayed then
568+ g_game.sellItem(entry.ptr, maxAmount, ignoreEquipped:isChecked())
569+ sellAllWithDelayEvent = scheduleEvent(function() sellAll(true) end, 1100)
570+ return
571+ end
572+ table.insert(queue, {entry.ptr, maxAmount, ignoreEquipped:isChecked()})
573+ sellQuantity = sellQuantity - maxAmount
574+ end
575+ end
576+ for _, entry in ipairs(queue) do
577+ g_game.sellItem(entry[1], entry[2], entry[3])
578+ end
579+end
A RD_Client/modules/game_npctrade/npctrade.otmod +9-0 View file
@@ -0,0 +1,9 @@
1+Module
2+ name: game_npctrade
3+ description: NPC trade interface
4+ author: andrefaramir, baxnie
5+ website: https://github.com/edubart/otclient
6+ sandboxed: true
7+ scripts: [ npctrade ]
8+ @onLoad: init()
9+ @onUnload: terminate()
A RD_Client/modules/game_npctrade/npctrade.otui +289-0 View file
@@ -0,0 +1,289 @@
1+NPCOfferLabel < Label
2+ anchors.left: prev.right
3+ anchors.top: prev.top
4+ margin-left: 5
5+ text-auto-resize: true
6+
7+NPCItemBox < UICheckBox
8+ border-width: 1
9+ border-color: #000000
10+ color: #aaaaaa
11+ text-align: center
12+ text-offset: 0 30
13+ @onCheckChange: modules.game_npctrade.onItemBoxChecked(self)
14+
15+ Item
16+ id: item
17+ phantom: true
18+ anchors.top: parent.top
19+ anchors.horizontalCenter: parent.horizontalCenter
20+ image-color: #ffffffff
21+ margin-top: 3
22+
23+ $checked on:
24+ border-color: #ffffff
25+
26+ $!checked:
27+ border-color: #000000
28+
29+ $!on:
30+ image-color: #ffffff88
31+ color: #aaaaaa88
32+
33+MainWindow
34+ id: npcWindow
35+ !text: tr('NPC Trade')
36+ size: 550 340
37+ @onEscape: modules.game_npctrade.closeNpcTrade()
38+
39+ TabButton
40+ id: buyTab
41+ !tooltip: tr("List of items that you're able to buy")
42+ !text: tr('Buy')
43+ checked: true
44+ on: true
45+ anchors.left: parent.left
46+ anchors.right: parent.horizontalCenter
47+ anchors.top: parent.top
48+ margin-top: 0
49+
50+ TabButton
51+ id: sellTab
52+ !tooltip: tr("List of items that you're able to sell")
53+ !text: tr('Sell')
54+ anchors.left: parent.horizontalCenter
55+ anchors.right: parent.right
56+ anchors.top: parent.top
57+
58+ FlatPanel
59+ height: 150
60+ anchors.left: parent.left
61+ anchors.right: parent.right
62+ anchors.top: prev.bottom
63+ margin-top: 5
64+
65+ VerticalScrollBar
66+ id: itemsPanelListScrollBar
67+ anchors.top: parent.top
68+ anchors.bottom: parent.bottom
69+ anchors.right: parent.right
70+ step: 24
71+ pixels-scroll: true
72+
73+ ScrollablePanel
74+ id: itemsPanel
75+ height: 200
76+ anchors.left: parent.left
77+ anchors.right: prev.left
78+ anchors.top: parent.top
79+ anchors.bottom: parent.bottom
80+ vertical-scrollbar: itemsPanelListScrollBar
81+ margin-left: 5
82+ margin-right: 5
83+ layout:
84+ type: grid
85+ cell-size: 160 90
86+ flow: true
87+ auto-spacing: true
88+
89+ FlatPanel
90+ id: setupPanel
91+ height: 105
92+ enabled: false
93+ anchors.left: parent.left
94+ anchors.right: parent.horizontalCenter
95+ anchors.top: prev.bottom
96+ margin-top: 5
97+ margin-right: 5
98+ image-color: #ffffff88
99+
100+ Label
101+ !text: tr('Name') .. ':'
102+ anchors.left: parent.left
103+ anchors.top: parent.top
104+ margin-top: 5
105+ margin-left: 5
106+ width: 85
107+
108+ NPCOfferLabel
109+ id: name
110+
111+ Label
112+ !text: tr('Id') .. ':'
113+ anchors.left: parent.left
114+ anchors.top: parent.top
115+ margin-top: 5
116+ margin-left: 5
117+ margin-left: 195
118+ width: 15
119+
120+ NPCOfferLabel
121+ id: id
122+
123+ Label
124+ !text: tr('Price') .. ':'
125+ anchors.left: parent.left
126+ anchors.top: prev.bottom
127+ margin-top: 3
128+ margin-left: 5
129+ width: 85
130+
131+ NPCOfferLabel
132+ id: price
133+
134+ Label
135+ !text: tr('Your Money') .. ':'
136+ anchors.left: parent.left
137+ anchors.top: prev.bottom
138+ margin-top: 3
139+ margin-left: 5
140+ width: 85
141+
142+ NPCOfferLabel
143+ id: money
144+
145+ Label
146+ id: weightDesc
147+ !text: tr('Weight') .. ':'
148+ anchors.left: parent.left
149+ anchors.top: prev.bottom
150+ margin-top: 3
151+ margin-left: 5
152+ width: 85
153+
154+ NPCOfferLabel
155+ id: weight
156+
157+ Label
158+ id: capacityDesc
159+ !text: tr('Your Capacity') .. ':'
160+ anchors.left: parent.left
161+ anchors.top: prev.bottom
162+ margin-top: 3
163+ margin-left: 5
164+ width: 85
165+
166+ NPCOfferLabel
167+ id: capacity
168+
169+ HorizontalScrollBar
170+ id: quantityScroll
171+ anchors.left: parent.left
172+ anchors.right: parent.right
173+ anchors.top: prev.bottom
174+ margin-top: 3
175+ margin-left: 5
176+ margin-right: 5
177+ show-value: true
178+ minimum: 1
179+ maximum: 100
180+ step: 1
181+ @onValueChange: modules.game_npctrade.onQuantityValueChange(self:getValue())
182+
183+ FlatPanel
184+ id: buyOptions
185+ height: 80
186+ anchors.top: prev.top
187+ anchors.left: parent.horizontalCenter
188+ anchors.right: parent.right
189+ margin-left: 5
190+ image-color: #ffffff88
191+
192+ Label
193+ id: searchLabel
194+ !text: tr('Search') .. ':'
195+ anchors.left: parent.left
196+ anchors.top: parent.top
197+ text-auto-resize: true
198+ margin-top: 7
199+ margin-left: 5
200+
201+ TextEdit
202+ id: searchText
203+ anchors.left: prev.right
204+ anchors.top: prev.top
205+ anchors.right: parent.right
206+ margin-top: -2
207+ margin-left: 5
208+ margin-right: 5
209+ @onTextChange: modules.game_npctrade.onSearchTextChange()
210+
211+ CheckBox
212+ id: buyWithBackpack
213+ !text: tr('Buy with backpack')
214+ anchors.top: searchText.bottom
215+ anchors.left: parent.left
216+ anchors.right: parent.right
217+ margin-left: 5
218+ margin-top: 3
219+ @onCheckChange: modules.game_npctrade.onBuyWithBackpackChange()
220+
221+ CheckBox
222+ id: ignoreCapacity
223+ !text: tr('Ignore capacity')
224+ anchors.top: prev.bottom
225+ anchors.left: parent.left
226+ anchors.right: parent.right
227+ margin-left: 5
228+ margin-top: 3
229+ @onCheckChange: modules.game_npctrade.onIgnoreCapacityChange()
230+
231+ CheckBox
232+ id: ignoreEquipped
233+ !text: tr('Ignore equipped')
234+ anchors.top: searchText.bottom
235+ anchors.left: parent.left
236+ anchors.right: parent.right
237+ margin-left: 5
238+ margin-top: 3
239+ visible: false
240+ checked: true
241+ @onCheckChange: modules.game_npctrade.onIgnoreEquippedChange()
242+
243+ CheckBox
244+ id: showAllItems
245+ !text: tr('Show all items')
246+ anchors.top: prev.bottom
247+ anchors.left: parent.left
248+ anchors.right: parent.right
249+ margin-left: 5
250+ margin-top: 3
251+ visible: false
252+ checked: true
253+ @onCheckChange: modules.game_npctrade.onShowAllItemsChange()
254+
255+ Button
256+ id: sellAllWithDelayButton
257+ !text: tr('Sell all with delay')
258+ width: 128
259+ anchors.right: next.left
260+ anchors.bottom: parent.bottom
261+ margin-right: 10
262+ visible: false
263+ @onClick: modules.game_npctrade.sellAll(true)
264+
265+ Button
266+ id: sellAllButton
267+ !text: tr('Sell all')
268+ width: 64
269+ anchors.right: next.left
270+ anchors.bottom: parent.bottom
271+ margin-right: 10
272+ visible: false
273+ @onClick: modules.game_npctrade.sellAll()
274+
275+ Button
276+ id: tradeButton
277+ !text: tr('Buy')
278+ width: 64
279+ anchors.right: next.left
280+ anchors.bottom: parent.bottom
281+ margin-right: 10
282+ @onClick: modules.game_npctrade.onTradeClick()
283+
284+ Button
285+ !text: tr('Close')
286+ width: 64
287+ anchors.right: parent.right
288+ anchors.bottom: parent.bottom
289+ @onClick: modules.game_npctrade.closeNpcTrade()
A RD_Client/modules/game_outfit/outfit.otmod +10-0 View file
@@ -0,0 +1,10 @@
1+Module
2+ name: game_outfit
3+ description: Outfit customization panel - v2
4+ author: HoneyServer
5+ website: HoneyServer
6+ sandboxed: true
7+ version: 2.0
8+ scripts: [ outfit ]
9+ @onLoad: init()
10+ @onUnload: terminate()
Top