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_interface/iconchat.png +0-0 View file
Binary file not shown.
A RD_Client/modules/game_interface/interface.otmod +46-0 View file
@@ -0,0 +1,46 @@
1+Module
2+ name: game_interface
3+ description: Create the game interface, where the ingame stuff starts
4+ author: OTClient team
5+ website: https://github.com/edubart/otclient
6+ sandboxed: true
7+ scripts: [ widgets/uigamemap, gameinterface ]
8+ load-later:
9+ - game_buttons
10+ - game_hotkeys
11+ - game_questlog
12+ - game_textmessage
13+
14+ - game_chat
15+ - game_outfit
16+ - game_skills
17+ - game_inventory
18+ - game_containers
19+ - game_viplist
20+ - game_battle
21+ - game_minimap
22+ - game_npctrade
23+ - game_textwindow
24+ - game_playertrade
25+ - game_bugreport
26+ - game_playerdeath
27+ - game_playermount
28+ - game_ruleviolation
29+ - game_market
30+ - game_spelllist
31+ - game_cooldown
32+ - game_modaldialog
33+ - game_unjustifiedpoints
34+ - game_walking
35+ - game_shop
36+ - game_itemselector
37+ - client_textedit
38+ - game_actionbar
39+ - game_prey
40+ - game_imbuing
41+ - game_stats
42+ - game_shaders
43+ - game_bot
44+ - game_damage_numbers
45+ @onLoad: init()
46+ @onUnload: terminate()
A RD_Client/modules/game_interface/styles/countwindow.otui +53-0 View file
@@ -0,0 +1,53 @@
1+CountWindow < MainWindow
2+ id: countWindow
3+ !text: tr('Move Stackable Item')
4+ size: 196 90
5+
6+ SpinBox
7+ id: spinBox
8+ anchors.left: parent.left
9+ anchors.top: parent.top
10+ width: 1
11+ height: 1
12+ phantom: true
13+ margin-top: 2
14+ focusable: true
15+
16+ Item
17+ id: item
18+ anchors.left: parent.left
19+ anchors.top: parent.top
20+ margin-top: 2
21+ margin-left: -4
22+ focusable: false
23+ virtual: true
24+
25+ HorizontalScrollBar
26+ id: countScrollBar
27+ anchors.left: prev.right
28+ anchors.right: parent.right
29+ anchors.top: prev.top
30+ margin-left: 10
31+ margin-top: -2
32+ focusable: false
33+
34+ Button
35+ id: buttonCancel
36+ !text: tr('Cancel')
37+ height: 20
38+ anchors.left: countScrollBar.horizontalCenter
39+ anchors.right: countScrollBar.right
40+ anchors.top: countScrollBar.bottom
41+ margin-top: 7
42+ focusable: false
43+
44+ Button
45+ id: buttonOk
46+ !text: tr('Ok')
47+ height: 20
48+ anchors.right: countScrollBar.horizontalCenter
49+ anchors.left: countScrollBar.left
50+ anchors.top: countScrollBar.bottom
51+ margin-top: 7
52+ margin-right: 6
53+ focusable: false
A RD_Client/modules/game_interface/widgets/uigamemap.lua +196-0 View file
@@ -0,0 +1,196 @@
1+UIGameMap = extends(UIMap, "UIGameMap")
2+
3+function UIGameMap.create()
4+ local gameMap = UIGameMap.internalCreate()
5+ gameMap:setKeepAspectRatio(true)
6+ gameMap:setVisibleDimension({width = 15, height = 11})
7+ gameMap:setDrawLights(true)
8+ gameMap.markedThing = nil
9+ gameMap.blockNextRelease = 0
10+ gameMap:updateMarkedCreature()
11+ return gameMap
12+end
13+
14+function UIGameMap:onDestroy()
15+ if self.updateMarkedCreatureEvent then
16+ removeEvent(self.updateMarkedCreatureEvent)
17+ end
18+end
19+
20+function UIGameMap:markThing(thing, color)
21+ if self.markedThing == thing then
22+ return
23+ end
24+ if self.markedThing then
25+ self.markedThing:setMarked('')
26+ end
27+
28+ self.markedThing = thing
29+ if self.markedThing and g_settings.getBoolean('highlightThingsUnderCursor') then
30+ self.markedThing:setMarked(color)
31+ end
32+end
33+
34+function UIGameMap:onDragEnter(mousePos)
35+ local tile = self:getTile(mousePos)
36+ if not tile then return false end
37+
38+ local thing = tile:getTopMoveThing()
39+ if not thing then return false end
40+
41+ self.currentDragThing = thing
42+
43+ g_mouse.pushCursor('target')
44+ self.allowNextRelease = false
45+ return true
46+end
47+
48+function UIGameMap:onDragLeave(droppedWidget, mousePos)
49+ self.currentDragThing = nil
50+ self.hoveredWho = nil
51+ g_mouse.popCursor('target')
52+ return true
53+end
54+
55+function UIGameMap:onDrop(widget, mousePos)
56+ if not self:canAcceptDrop(widget, mousePos) then return false end
57+
58+ local tile = self:getTile(mousePos)
59+ if not tile then return false end
60+
61+ local thing = widget.currentDragThing
62+ local toPos = tile:getPosition()
63+
64+ local thingPos = thing:getPosition()
65+ if thingPos.x == toPos.x and thingPos.y == toPos.y and thingPos.z == toPos.z then return false end
66+
67+ if thing:isItem() and thing:getCount() > 1 then
68+ modules.game_interface.moveStackableItem(thing, toPos)
69+ else
70+ g_game.move(thing, toPos, 1)
71+ end
72+
73+ return true
74+end
75+
76+function UIGameMap:onMouseMove(mousePos, mouseMoved)
77+ self.mousePos = mousePos
78+ return false
79+end
80+
81+function UIGameMap:onDragMove(mousePos, mouseMoved)
82+ self.mousePos = mousePos
83+ return false
84+end
85+
86+function UIGameMap:updateMarkedCreature()
87+ self.updateMarkedCreatureEvent = scheduleEvent(function() self:updateMarkedCreature() end, 100)
88+ if self.mousePos and g_game.isOnline() then
89+ self.markingMouseRelease = true
90+ self:onMouseRelease(self.mousePos, MouseRightButton)
91+ self.markingMouseRelease = false
92+ end
93+end
94+
95+function UIGameMap:onMousePress()
96+ if not self:isDragging() and self.blockNextRelease < g_clock.millis() then
97+ self.allowNextRelease = true
98+ self.markingMouseRelease = false
99+ end
100+end
101+
102+function UIGameMap:blockNextMouseRelease(postAction)
103+ self.allowNextRelease = false
104+ if postAction then
105+ self.blockNextRelease = g_clock.millis() + 150
106+ else
107+ self.blockNextRelease = g_clock.millis() + 250
108+ end
109+end
110+
111+function UIGameMap:onMouseRelease(mousePosition, mouseButton)
112+ if not self.allowNextRelease and not self.markingMouseRelease then
113+ return true
114+ end
115+ local autoWalkPos = self:getPosition(mousePosition)
116+ local positionOffset = self:getPositionOffset(mousePosition)
117+
118+ -- happens when clicking outside of map boundaries
119+ if not autoWalkPos then
120+ if self.markingMouseRelease then
121+ self:markThing(nil)
122+ end
123+ return false
124+ end
125+
126+ local localPlayerPos = g_game.getLocalPlayer():getPosition()
127+ if autoWalkPos.z ~= localPlayerPos.z then
128+ local dz = autoWalkPos.z - localPlayerPos.z
129+ autoWalkPos.x = autoWalkPos.x + dz
130+ autoWalkPos.y = autoWalkPos.y + dz
131+ autoWalkPos.z = localPlayerPos.z
132+ end
133+
134+ local lookThing
135+ local useThing
136+ local creatureThing
137+ local multiUseThing
138+ local attackCreature
139+
140+ local tile = self:getTile(mousePosition)
141+ if tile then
142+ lookThing = tile:getTopLookThingEx(positionOffset)
143+ useThing = tile:getTopUseThing()
144+ creatureThing = tile:getTopCreatureEx(positionOffset)
145+ end
146+
147+ local autoWalkTile = g_map.getTile(autoWalkPos)
148+ if autoWalkTile then
149+ attackCreature = autoWalkTile:getTopCreatureEx(positionOffset)
150+ end
151+
152+ if self.markingMouseRelease then
153+ if attackCreature then
154+ self:markThing(attackCreature, 'yellow')
155+ elseif creatureThing then
156+ self:markThing(creatureThing, 'yellow')
157+ elseif useThing and not useThing:isGround() then
158+ self:markThing(useThing, 'yellow')
159+ elseif lookThing and not lookThing:isGround() then
160+ self:markThing(lookThing, 'yellow')
161+ else
162+ self:markThing(nil, '')
163+ end
164+ return
165+ end
166+
167+ local ret = modules.game_interface.processMouseAction(mousePosition, mouseButton, autoWalkPos, lookThing, useThing, creatureThing, attackCreature, self.markingMouseRelease)
168+ if ret then
169+ self.allowNextRelease = false
170+ end
171+
172+ return ret
173+end
174+
175+function UIGameMap:onTouchRelease(mousePosition, mouseButton)
176+ if mouseButton ~= MouseTouch then
177+ return self:onMouseRelease(mousePosition, mouseButton)
178+ end
179+end
180+
181+function UIGameMap:canAcceptDrop(widget, mousePos)
182+ if not widget or not widget.currentDragThing then return false end
183+
184+ local children = rootWidget:recursiveGetChildrenByPos(mousePos)
185+ for i=1,#children do
186+ local child = children[i]
187+ if child == self then
188+ return true
189+ elseif not child:isPhantom() then
190+ return false
191+ end
192+ end
193+
194+ error('Widget ' .. self:getId() .. ' not in drop list.')
195+ return false
196+end
A RD_Client/modules/game_inventory/inventory.lua +487-0 View file
@@ -0,0 +1,487 @@
1+Icons = {}
2+Icons[PlayerStates.Poison] = { tooltip = tr('You are poisoned'), path = '/images/game/states/poisoned', id = 'condition_poisoned' }
3+Icons[PlayerStates.Burn] = { tooltip = tr('You are burning'), path = '/images/game/states/burning', id = 'condition_burning' }
4+Icons[PlayerStates.Energy] = { tooltip = tr('You are electrified'), path = '/images/game/states/electrified', id = 'condition_electrified' }
5+Icons[PlayerStates.Drunk] = { tooltip = tr('You are drunk'), path = '/images/game/states/drunk', id = 'condition_drunk' }
6+Icons[PlayerStates.ManaShield] = { tooltip = tr('You are protected by a magic shield'), path = '/images/game/states/magic_shield', id = 'condition_magic_shield' }
7+Icons[PlayerStates.Paralyze] = { tooltip = tr('You are paralysed'), path = '/images/game/states/slowed', id = 'condition_slowed' }
8+Icons[PlayerStates.Haste] = { tooltip = tr('You are hasted'), path = '/images/game/states/haste', id = 'condition_haste' }
9+Icons[PlayerStates.Swords] = { tooltip = tr('You may not logout during a fight'), path = '/images/game/states/logout_block', id = 'condition_logout_block' }
10+Icons[PlayerStates.Drowning] = { tooltip = tr('You are drowning'), path = '/images/game/states/drowning', id = 'condition_drowning' }
11+Icons[PlayerStates.Freezing] = { tooltip = tr('You are freezing'), path = '/images/game/states/freezing', id = 'condition_freezing' }
12+Icons[PlayerStates.Dazzled] = { tooltip = tr('You are dazzled'), path = '/images/game/states/dazzled', id = 'condition_dazzled' }
13+Icons[PlayerStates.Cursed] = { tooltip = tr('You are cursed'), path = '/images/game/states/cursed', id = 'condition_cursed' }
14+Icons[PlayerStates.PartyBuff] = { tooltip = tr('You are strengthened'), path = '/images/game/states/strengthened', id = 'condition_strengthened' }
15+Icons[PlayerStates.PzBlock] = { tooltip = tr('You may not logout or enter a protection zone'), path = '/images/game/states/protection_zone_block', id = 'condition_protection_zone_block' }
16+Icons[PlayerStates.Pz] = { tooltip = tr('You are within a protection zone'), path = '/images/game/states/protection_zone', id = 'condition_protection_zone' }
17+Icons[PlayerStates.Bleeding] = { tooltip = tr('You are bleeding'), path = '/images/game/states/bleeding', id = 'condition_bleeding' }
18+Icons[PlayerStates.Hungry] = { tooltip = tr('You are hungry'), path = '/images/game/states/hungry', id = 'condition_hungry' }
19+
20+InventorySlotStyles = {
21+ [InventorySlotHead] = "HeadSlot",
22+ [InventorySlotNeck] = "NeckSlot",
23+ [InventorySlotBack] = "BackSlot",
24+ [InventorySlotBody] = "BodySlot",
25+ [InventorySlotRight] = "RightSlot",
26+ [InventorySlotLeft] = "LeftSlot",
27+ [InventorySlotLeg] = "LegSlot",
28+ [InventorySlotFeet] = "FeetSlot",
29+ [InventorySlotFinger] = "FingerSlot",
30+ [InventorySlotAmmo] = "AmmoSlot"
31+}
32+
33+inventoryWindow = nil
34+inventoryPanel = nil
35+inventoryButton = nil
36+purseButton = nil
37+
38+combatControlsWindow = nil
39+fightOffensiveBox = nil
40+fightBalancedBox = nil
41+fightDefensiveBox = nil
42+chaseModeButton = nil
43+safeFightButton = nil
44+mountButton = nil
45+fightModeRadioGroup = nil
46+buttonPvp = nil
47+
48+soulLabel = nil
49+capLabel = nil
50+conditionPanel = nil
51+
52+function init()
53+ connect(LocalPlayer, {
54+ onInventoryChange = onInventoryChange,
55+ onBlessingsChange = onBlessingsChange
56+ })
57+ connect(g_game, { onGameStart = refresh })
58+
59+ g_keyboard.bindKeyDown('Ctrl+I', toggle)
60+
61+
62+ inventoryWindow = g_ui.loadUI('inventory', modules.game_interface.getRightPanel())
63+ inventoryWindow:disableResize()
64+ inventoryPanel = inventoryWindow:getChildById('contentsPanel'):getChildById('inventoryPanel')
65+ if not inventoryWindow.forceOpen then
66+ --inventoryButton = modules.client_topmenu.addRightGameToggleButton('inventoryButton', tr('Inventory') .. ' (Ctrl+I)', '/images/topbuttons/inventory', toggle)
67+ --inventoryButton:setOn(true)
68+ end
69+
70+ purseButton = inventoryWindow:recursiveGetChildById('purseButton')
71+ purseButton.onClick = function()
72+ local purse = g_game.getLocalPlayer():getInventoryItem(InventorySlotPurse)
73+ if purse then
74+ g_game.use(purse)
75+ end
76+ end
77+
78+ -- controls
79+ fightOffensiveBox = inventoryWindow:recursiveGetChildById('fightOffensiveBox')
80+ fightBalancedBox = inventoryWindow:recursiveGetChildById('fightBalancedBox')
81+ fightDefensiveBox = inventoryWindow:recursiveGetChildById('fightDefensiveBox')
82+
83+ chaseModeButton = inventoryWindow:recursiveGetChildById('chaseModeBox')
84+ safeFightButton = inventoryWindow:recursiveGetChildById('safeFightBox')
85+ buttonPvp = inventoryWindow:recursiveGetChildById('buttonPvp')
86+
87+ mountButton = inventoryWindow:recursiveGetChildById('mountButton')
88+ mountButton.onClick = onMountButtonClick
89+
90+ whiteDoveBox = inventoryWindow:recursiveGetChildById('whiteDoveBox')
91+ whiteHandBox = inventoryWindow:recursiveGetChildById('whiteHandBox')
92+ yellowHandBox = inventoryWindow:recursiveGetChildById('yellowHandBox')
93+ redFistBox = inventoryWindow:recursiveGetChildById('redFistBox')
94+
95+ fightModeRadioGroup = UIRadioGroup.create()
96+ fightModeRadioGroup:addWidget(fightOffensiveBox)
97+ fightModeRadioGroup:addWidget(fightBalancedBox)
98+ fightModeRadioGroup:addWidget(fightDefensiveBox)
99+
100+ connect(fightModeRadioGroup, { onSelectionChange = onSetFightMode })
101+ connect(chaseModeButton, { onCheckChange = onSetChaseMode })
102+ connect(safeFightButton, { onCheckChange = onSetSafeFight })
103+ if buttonPvp then
104+ connect(buttonPvp, { onClick = onSetSafeFight2 })
105+ end
106+ connect(g_game, {
107+ onGameStart = online,
108+ onGameEnd = offline,
109+ onFightModeChange = update,
110+ onChaseModeChange = update,
111+ onSafeFightChange = update,
112+ onPVPModeChange = update,
113+ onWalk = check,
114+ onAutoWalk = check
115+ })
116+
117+ connect(LocalPlayer, { onOutfitChange = onOutfitChange })
118+
119+ if g_game.isOnline() then
120+ online()
121+ end
122+-- controls end
123+
124+-- status
125+ soulLabel = inventoryWindow:recursiveGetChildById('soulLabel')
126+ capLabel = inventoryWindow:recursiveGetChildById('capLabel')
127+ conditionPanel = inventoryWindow:recursiveGetChildById('conditionPanel')
128+
129+
130+ connect(LocalPlayer, { onStatesChange = onStatesChange,
131+ onSoulChange = onSoulChange,
132+ onFreeCapacityChange = onFreeCapacityChange })
133+-- status end
134+
135+ refresh()
136+ inventoryWindow:setup()
137+end
138+
139+function terminate()
140+ disconnect(LocalPlayer, {
141+ onInventoryChange = onInventoryChange,
142+ onBlessingsChange = onBlessingsChange
143+ })
144+ disconnect(g_game, { onGameStart = refresh })
145+
146+ g_keyboard.unbindKeyDown('Ctrl+I')
147+
148+ -- controls
149+ if g_game.isOnline() then
150+ offline()
151+ end
152+
153+ fightModeRadioGroup:destroy()
154+
155+ disconnect(g_game, {
156+ onGameStart = online,
157+ onGameEnd = offline,
158+ onFightModeChange = update,
159+ onChaseModeChange = update,
160+ onSafeFightChange = update,
161+ onPVPModeChange = update,
162+ onWalk = check,
163+ onAutoWalk = check
164+ })
165+
166+ disconnect(LocalPlayer, { onOutfitChange = onOutfitChange })
167+ -- controls end
168+ -- status
169+ disconnect(LocalPlayer, { onStatesChange = onStatesChange,
170+ onSoulChange = onSoulChange,
171+ onFreeCapacityChange = onFreeCapacityChange })
172+ -- status end
173+
174+ inventoryWindow:destroy()
175+ --if inventoryButton then
176+ -- inventoryButton:destroy()
177+ --end
178+end
179+
180+function toggleAdventurerStyle(hasBlessing)
181+ for slot = InventorySlotFirst, InventorySlotLast do
182+ local itemWidget = inventoryPanel:getChildById('slot' .. slot)
183+ if itemWidget then
184+ itemWidget:setOn(hasBlessing)
185+ end
186+ end
187+end
188+
189+function refresh()
190+ local player = g_game.getLocalPlayer()
191+ for i = InventorySlotFirst, InventorySlotPurse do
192+ if g_game.isOnline() then
193+ onInventoryChange(player, i, player:getInventoryItem(i))
194+ else
195+ onInventoryChange(player, i, nil)
196+ end
197+ toggleAdventurerStyle(player and Bit.hasBit(player:getBlessings(), Blessings.Adventurer) or false)
198+ end
199+ if player then
200+ onSoulChange(player, player:getSoul())
201+ onFreeCapacityChange(player, player:getFreeCapacity())
202+ onStatesChange(player, player:getStates(), 0)
203+ end
204+
205+ purseButton:setVisible(g_game.getFeature(GamePurseSlot))
206+end
207+
208+function toggle()
209+ --if not inventoryButton then
210+ -- return
211+ --end
212+ --if inventoryButton:isOn() then
213+ -- inventoryWindow:close()
214+ -- inventoryButton:setOn(false)
215+ --else
216+ -- inventoryWindow:open()
217+ -- inventoryButton:setOn(true)
218+ --end
219+end
220+
221+function onMiniWindowClose()
222+ --if not inventoryButton then
223+ -- return
224+ --end
225+ --inventoryButton:setOn(false)
226+end
227+
228+-- hooked events
229+function onInventoryChange(player, slot, item, oldItem)
230+ if slot > InventorySlotPurse then return end
231+
232+ if slot == InventorySlotPurse then
233+ if g_game.getFeature(GamePurseSlot) then
234+ --purseButton:setEnabled(item and true or false)
235+ end
236+ return
237+ end
238+
239+ local itemWidget = inventoryPanel:getChildById('slot' .. slot)
240+ if item then
241+ itemWidget:setStyle('InventoryItem')
242+ itemWidget:setItem(item)
243+ else
244+ itemWidget:setStyle(InventorySlotStyles[slot])
245+ itemWidget:setItem(nil)
246+ end
247+end
248+
249+function onBlessingsChange(player, blessings, oldBlessings)
250+ local hasAdventurerBlessing = Bit.hasBit(blessings, Blessings.Adventurer)
251+ if hasAdventurerBlessing ~= Bit.hasBit(oldBlessings, Blessings.Adventurer) then
252+ toggleAdventurerStyle(hasAdventurerBlessing)
253+ end
254+end
255+
256+
257+-- controls
258+function update()
259+ local fightMode = g_game.getFightMode()
260+ if fightMode == FightOffensive then
261+ fightModeRadioGroup:selectWidget(fightOffensiveBox)
262+ elseif fightMode == FightBalanced then
263+ fightModeRadioGroup:selectWidget(fightBalancedBox)
264+ else
265+ fightModeRadioGroup:selectWidget(fightDefensiveBox)
266+ end
267+
268+ local chaseMode = g_game.getChaseMode()
269+ chaseModeButton:setChecked(chaseMode == ChaseOpponent)
270+
271+ local safeFight = g_game.isSafeFight()
272+ safeFightButton:setChecked(not safeFight)
273+ if buttonPvp then
274+ if safeFight then
275+ buttonPvp:setOn(false)
276+ else
277+ buttonPvp:setOn(true)
278+ end
279+ end
280+
281+ if g_game.getFeature(GamePVPMode) then
282+ local pvpMode = g_game.getPVPMode()
283+ local pvpWidget = getPVPBoxByMode(pvpMode)
284+ end
285+end
286+
287+function check()
288+ if modules.client_options.getOption('autoChaseOverride') then
289+ if g_game.isAttacking() and g_game.getChaseMode() == ChaseOpponent then
290+ g_game.setChaseMode(DontChase)
291+ end
292+ end
293+end
294+
295+function online()
296+ local player = g_game.getLocalPlayer()
297+ if player then
298+ local char = g_game.getCharacterName()
299+
300+ local lastCombatControls = g_settings.getNode('LastCombatControls')
301+
302+ if not table.empty(lastCombatControls) then
303+ if lastCombatControls[char] then
304+ g_game.setFightMode(lastCombatControls[char].fightMode)
305+ g_game.setChaseMode(lastCombatControls[char].chaseMode)
306+ g_game.setSafeFight(lastCombatControls[char].safeFight)
307+ if lastCombatControls[char].pvpMode then
308+ g_game.setPVPMode(lastCombatControls[char].pvpMode)
309+ end
310+ end
311+ end
312+
313+ if g_game.getFeature(GamePlayerMounts) then
314+ mountButton:setVisible(true)
315+ mountButton:setChecked(player:isMounted())
316+ else
317+ mountButton:setVisible(false)
318+ end
319+ end
320+
321+ update()
322+end
323+
324+function offline()
325+ local lastCombatControls = g_settings.getNode('LastCombatControls')
326+ if not lastCombatControls then
327+ lastCombatControls = {}
328+ end
329+
330+ conditionPanel:destroyChildren()
331+
332+ local player = g_game.getLocalPlayer()
333+ if player then
334+ local char = g_game.getCharacterName()
335+ lastCombatControls[char] = {
336+ fightMode = g_game.getFightMode(),
337+ chaseMode = g_game.getChaseMode(),
338+ safeFight = g_game.isSafeFight()
339+ }
340+
341+ if g_game.getFeature(GamePVPMode) then
342+ lastCombatControls[char].pvpMode = g_game.getPVPMode()
343+ end
344+
345+ -- save last combat control settings
346+ g_settings.setNode('LastCombatControls', lastCombatControls)
347+ end
348+end
349+
350+function onSetFightMode(self, selectedFightButton)
351+ if selectedFightButton == nil then return end
352+ local buttonId = selectedFightButton:getId()
353+ local fightMode
354+ if buttonId == 'fightOffensiveBox' then
355+ fightMode = FightOffensive
356+ elseif buttonId == 'fightBalancedBox' then
357+ fightMode = FightBalanced
358+ else
359+ fightMode = FightDefensive
360+ end
361+ g_game.setFightMode(fightMode)
362+end
363+
364+function onSetChaseMode(self, checked)
365+ local chaseMode
366+ if checked then
367+ chaseMode = ChaseOpponent
368+ else
369+ chaseMode = DontChase
370+ end
371+ g_game.setChaseMode(chaseMode)
372+end
373+
374+function onSetSafeFight(self, checked)
375+ g_game.setSafeFight(not checked)
376+ if buttonPvp then
377+ if not checked then
378+ buttonPvp:setOn(false)
379+ else
380+ buttonPvp:setOn(true)
381+ end
382+ end
383+end
384+
385+function onSetSafeFight2(self)
386+ onSetSafeFight(self, not safeFightButton:isChecked())
387+end
388+
389+function onSetPVPMode(self, selectedPVPButton)
390+ if selectedPVPButton == nil then
391+ return
392+ end
393+
394+ local buttonId = selectedPVPButton:getId()
395+ local pvpMode = PVPWhiteDove
396+ if buttonId == 'whiteDoveBox' then
397+ pvpMode = PVPWhiteDove
398+ elseif buttonId == 'whiteHandBox' then
399+ pvpMode = PVPWhiteHand
400+ elseif buttonId == 'yellowHandBox' then
401+ pvpMode = PVPYellowHand
402+ elseif buttonId == 'redFistBox' then
403+ pvpMode = PVPRedFist
404+ end
405+
406+ g_game.setPVPMode(pvpMode)
407+end
408+
409+function onMountButtonClick(self, mousePos)
410+ local player = g_game.getLocalPlayer()
411+ if player then
412+ player:toggleMount()
413+ end
414+end
415+
416+function onOutfitChange(localPlayer, outfit, oldOutfit)
417+ if outfit.mount == oldOutfit.mount then
418+ return
419+ end
420+
421+ mountButton:setChecked(outfit.mount ~= nil and outfit.mount > 0)
422+end
423+
424+function getPVPBoxByMode(mode)
425+ local widget = nil
426+ if mode == PVPWhiteDove then
427+ widget = whiteDoveBox
428+ elseif mode == PVPWhiteHand then
429+ widget = whiteHandBox
430+ elseif mode == PVPYellowHand then
431+ widget = yellowHandBox
432+ elseif mode == PVPRedFist then
433+ widget = redFistBox
434+ end
435+ return widget
436+end
437+
438+-- status
439+function toggleIcon(bitChanged)
440+ local icon = conditionPanel:getChildById(Icons[bitChanged].id)
441+ if icon then
442+ icon:destroy()
443+ else
444+ icon = loadIcon(bitChanged)
445+ icon:setParent(conditionPanel)
446+ end
447+end
448+
449+function loadIcon(bitChanged)
450+ local icon = g_ui.createWidget('ConditionWidget', conditionPanel)
451+ icon:setId(Icons[bitChanged].id)
452+ icon:setImageSource(Icons[bitChanged].path)
453+ icon:setTooltip(Icons[bitChanged].tooltip)
454+ return icon
455+end
456+
457+function onSoulChange(localPlayer, soul)
458+ if not soul then return end
459+ soulLabel:setText(tr('Soul') .. ':\n' .. soul)
460+end
461+
462+function onFreeCapacityChange(player, freeCapacity)
463+ if not freeCapacity then return end
464+ if freeCapacity > 99 then
465+ freeCapacity = math.floor(freeCapacity * 10) / 10
466+ end
467+ if freeCapacity > 999 then
468+ freeCapacity = math.floor(freeCapacity)
469+ end
470+ if freeCapacity > 99999 then
471+ freeCapacity = math.min(9999, math.floor(freeCapacity/1000)) .. "k"
472+ end
473+ capLabel:setText(tr('Cap') .. ':\n' .. freeCapacity)
474+end
475+
476+function onStatesChange(localPlayer, now, old)
477+ if now == old then return end
478+ local bitsChanged = bit32.bxor(now, old)
479+ for i = 1, 32 do
480+ local pow = math.pow(2, i-1)
481+ if pow > bitsChanged then break end
482+ local bitChanged = bit32.band(bitsChanged, pow)
483+ if bitChanged ~= 0 then
484+ toggleIcon(bitChanged)
485+ end
486+ end
487+end
A RD_Client/modules/game_inventory/inventory.otmod +9-0 View file
@@ -0,0 +1,9 @@
1+Module
2+ name: game_inventory
3+ description: View local player equipments window
4+ author: baxnie, edubart, BeniS, otclientv8
5+ website: https://github.com/edubart/otclient
6+ sandboxed: true
7+ scripts: [ inventory ]
8+ @onLoad: init()
9+ @onUnload: terminate()
A RD_Client/modules/game_inventory/inventory.otui +7-0 View file
@@ -0,0 +1,7 @@
1+InventoryWindow
2+ id: inventoryWindow
3+ !text: tr('Inventory')
4+ @onClose: modules.game_inventory.onMiniWindowClose()
5+ visible: false
6+ &save: true
7+ &autoOpen: 3
A RD_Client/modules/game_itemselector/itemselector.lua +74-0 View file
@@ -0,0 +1,74 @@
1+local activeWindow
2+
3+function init()
4+ g_ui.importStyle('itemselector')
5+
6+ connect(g_game, { onGameEnd = destroyWindow })
7+end
8+
9+function terminate()
10+ disconnect(g_game, { onGameEnd = destroyWindow })
11+
12+ destroyWindow()
13+end
14+
15+function destroyWindow()
16+ if activeWindow then
17+ activeWindow:destroy()
18+ activeWindow = nil
19+ end
20+end
21+
22+function show(itemWidget)
23+ if not itemWidget then
24+ return
25+ end
26+ if activeWindow then
27+ destroyWindow()
28+ end
29+ local window = g_ui.createWidget('ItemSelectorWindow', rootWidget)
30+
31+ local destroy = function()
32+ window:destroy()
33+ if window == activeWindow then
34+ activeWindow = nil
35+ end
36+ end
37+ local doneFunc = function()
38+ itemWidget:setItem(Item.create(window.item:getItemId(), window.item:getItemCount()))
39+ destroy()
40+ end
41+ local clearFunc = function()
42+ window.item:setItemId(0)
43+ window.item:setItemCount(0)
44+ doneFunc()
45+ end
46+
47+ window.clearButton.onClick = clearFunc
48+ window.okButton.onClick = doneFunc
49+ window.cancelButton.onClick = destroy
50+ window.onEnter = doneFunc
51+ window.onEscape = destroy
52+
53+ window.item:setItem(Item.create(itemWidget:getItemId(), itemWidget:getItemCount()))
54+
55+ window.itemId:setValue(itemWidget:getItemId())
56+ if itemWidget:getItemCount() > 1 then
57+ window.itemCount:setValue(itemWidget:getItemCount())
58+ end
59+
60+ window.itemId.onValueChange = function(widget, value)
61+ window.item:setItemId(value)
62+ end
63+ window.itemCount.onValueChange = function(widget, value)
64+ window.item:setItemCount(value)
65+ end
66+
67+ activeWindow = window
68+ activeWindow:raise()
69+ activeWindow:focus()
70+end
71+
72+function hide()
73+ destroyWindow()
74+end
A RD_Client/modules/game_itemselector/itemselector.otmod +10-0 View file
@@ -0,0 +1,10 @@
1+Module
2+ name: game_itemselector
3+ description: Allow to select item
4+ author: OTClientV8
5+ website: https://github.com/OTCv8/otclientv8
6+ sandboxed: true
7+ dependencies: [ game_interface ]
8+ scripts: [ itemselector ]
9+ @onLoad: init()
10+ @onUnload: terminate()
A RD_Client/modules/game_itemselector/itemselector.otui +72-0 View file
@@ -0,0 +1,72 @@
1+ItemSelectorWindow < MainWindow
2+ id: itemSelector
3+ size: 260 120
4+ !text: tr("Select item")
5+
6+ Item
7+ id: item
8+ virtual: true
9+ size: 32 32
10+ margin-top: 10
11+ anchors.top: parent.top
12+ anchors.left: parent.left
13+
14+ SpinBox
15+ id: itemId
16+ anchors.top: parent.top
17+ anchors.left: prev.right
18+ margin-top: 15
19+ margin-left: 5
20+ padding-left: 5
21+ width: 70
22+ minimum: 0
23+ maximum: 999999
24+ focusable: true
25+
26+ Label
27+ anchors.top: parent.top
28+ anchors.left: prev.left
29+ anchors.right: prev.right
30+ text-align: center
31+ !text: tr("Item ID")
32+
33+ SpinBox
34+ id: itemCount
35+ anchors.top: parent.top
36+ anchors.left: prev.right
37+ margin-top: 15
38+ margin-left: 5
39+ padding-left: 5
40+ width: 120
41+ minimum: 1
42+ maximum: 100
43+ focusable: true
44+
45+ Label
46+ anchors.top: parent.top
47+ anchors.left: prev.left
48+ anchors.right: prev.right
49+ text-align: center
50+ !text: tr("Count / SubType")
51+
52+ Button
53+ id: clearButton
54+ !text: tr('Clear')
55+ anchors.bottom: parent.bottom
56+ anchors.left: parent.left
57+ width: 60
58+
59+ Button
60+ id: okButton
61+ !text: tr('Ok')
62+ anchors.bottom: parent.bottom
63+ anchors.right: next.left
64+ margin-right: 10
65+ width: 60
66+
67+ Button
68+ id: cancelButton
69+ !text: tr('Cancel')
70+ anchors.bottom: parent.bottom
71+ anchors.right: parent.right
72+ width: 60
Top