1# -*-python-*-
2# GemRB - Infinity Engine Emulator
3# Copyright (C) 2010 The GemRB Project
4#
5# This program is free software; you can redistribute it and/or
6# modify it under the terms of the GNU General Public License
7# as published by the Free Software Foundation; either version 2
8# of the License, or (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18#
19
20import GemRB
21import GameCheck
22import GUICommon
23import Spellbook
24from GUIDefines import *
25from ie_stats import *
26from ie_slots import *
27from ie_spells import *
28from ie_sounds import DEF_IDENTIFY
29
30UsedSlot = None
31ItemInfoWindow = None
32ItemAmountWindow = None
33ItemIdentifyWindow = None
34ItemAbilitiesWindow = None
35ErrorWindow = None
36ColorPicker = None
37StackAmount = 0
38
39 # A map that defines which inventory slots are used per character (PST)
40SlotMap = None
41
42UpdateInventoryWindow = None
43
44def OnDragItemGround (btn, slot):
45	"""Drops and item to the ground."""
46
47	pc = GemRB.GameGetSelectedPCSingle ()
48	slot = slot + GemRB.GetVar ("TopIndex") - (47 if GameCheck.IsPST () else 68)
49
50	if GemRB.IsDraggingItem ()==0:
51		slot_item = GemRB.GetContainerItem (pc, slot)
52		item = GemRB.GetItem (slot_item["ItemResRef"])
53		GemRB.DragItem (pc, slot, item["ItemIcon"], 0, 1) #container
54		if GameCheck.IsPST():
55			GemRB.PlaySound (item["DescIcon"])
56	else:
57		GemRB.DropDraggedItem (pc, -2) #dropping on ground
58
59	UpdateInventoryWindow ()
60	return
61
62def OnAutoEquip ():
63	"""Auto-equips equipment if possible."""
64
65	if GemRB.IsDraggingItem ()!=1:
66		return
67
68	pc = GemRB.GameGetSelectedPCSingle ()
69
70	#-1 : drop stuff in equipable slots (but not inventory)
71	GemRB.DropDraggedItem (pc, -1)
72
73	if GemRB.IsDraggingItem ()==1:
74		GemRB.PlaySound("GAM_47") #failed equip
75
76	UpdateInventoryWindow ()
77	return
78
79def OnDragItem (btn, slot):
80	"""Updates dragging."""
81
82	#don't call when splitting items
83	if ItemAmountWindow != None:
84		return
85
86	pc = GemRB.GameGetSelectedPCSingle ()
87	slot_item = GemRB.GetSlotItem (pc, slot)
88
89	if not GemRB.IsDraggingItem ():
90		item = GemRB.GetItem (slot_item["ItemResRef"])
91		GemRB.DragItem (pc, slot, item["ItemIcon"], 0, 0)
92	else:
93		SlotType = GemRB.GetSlotType (slot, pc)
94		#special monk check
95		if GemRB.GetPlayerStat (pc, IE_CLASS) == 20 and SlotType["Effects"] == TYPE_OFFHAND:
96			SlotType["ResRef"] = ""
97			GemRB.DisplayString (61355, ColorWhite)
98
99		if SlotType["ResRef"]!="":
100			if slot_item:
101				item = GemRB.GetItem (slot_item["ItemResRef"])
102				#drag items into a bag
103				if item["Function"] & ITM_F_CONTAINER:
104					#first swap them
105					GemRB.DropDraggedItem (pc, slot)
106					#enter the store
107					GemRB.EnterStore (slot_item["ItemResRef"])
108					#if it is possible to add, then do it
109					ret = GemRB.IsValidStoreItem (pc, slot, 0)
110					if ret&SHOP_SELL:
111						GemRB.ChangeStoreItem (pc, slot, SHOP_SELL)
112					else:
113						msg = 9375
114						if ret&SHOP_FULL:
115							if GameCheck.IsIWD1() or GameCheck.IsIWD2():
116								msg = 24893
117							elif GameCheck.HasTOB():
118								msg = 54692
119						GemRB.DisplayString(msg, ColorWhite)
120					#leave (save) store
121					GemRB.LeaveStore()
122
123			GemRB.DropDraggedItem (pc, slot)
124			# drop item if it caused us to disable the inventory view (example: cursed berserking sword)
125			if GemRB.GetPlayerStat (pc, IE_STATE_ID) & (STATE_BERSERK) and GemRB.IsDraggingItem ():
126				GemRB.DropDraggedItem (pc, -3)
127
128	UpdateInventoryWindow ()
129	return
130
131def OnDropItemToPC (pc):
132	"""Gives an item to another character."""
133
134	if pc > GemRB.GetPartySize ():
135		return
136	#-3 : drop stuff in inventory (but not equippable slots)
137	GemRB.DropDraggedItem (pc, -3)
138	UpdateInventoryWindow ()
139	return
140
141def DecreaseStackAmount ():
142	"""Decreases the split size."""
143
144	Text = ItemAmountWindow.GetControl (6)
145	Amount = Text.QueryText ()
146	number = int ("0"+Amount)-1
147	if number<1:
148		number=1
149	Text.SetText (str (number))
150	return
151
152def IncreaseStackAmount ():
153	"""Increases the split size."""
154
155	Text = ItemAmountWindow.GetControl (6)
156	Amount = Text.QueryText ()
157	number = int ("0"+Amount)+1
158	if number>StackAmount:
159		number=StackAmount
160	Text.SetText (str (number))
161	return
162
163def DragItemAmount ():
164	"""Drag a split item."""
165
166	pc = GemRB.GameGetSelectedPCSingle ()
167
168	#emergency dropping
169	if GemRB.IsDraggingItem()==1:
170		GemRB.DropDraggedItem (pc, UsedSlot)
171		UpdateSlot (pc, UsedSlot-1)
172
173	slot_item = GemRB.GetSlotItem (pc, UsedSlot)
174
175	#if dropping didn't help, don't die if slot_item isn't here
176	if slot_item:
177		Text = ItemAmountWindow.GetControl (6)
178		Amount = Text.QueryText ()
179		item = GemRB.GetItem (slot_item["ItemResRef"])
180		GemRB.DragItem (pc, UsedSlot, item["ItemIcon"], int ("0"+Amount), 0)
181	ItemAmountWindow.Close()
182	return
183
184def MouseEnterSlot (btn, slot):
185	pc = GemRB.GameGetSelectedPCSingle ()
186
187	if GemRB.IsDraggingItem ()==1:
188		drag_item = GemRB.GetSlotItem (0,0)
189		SlotType = UpdateSlot (pc, slot-1)
190
191		if GemRB.CanUseItemType (SlotType["Type"], drag_item["ItemResRef"]):
192			btn.SetState (IE_GUI_BUTTON_SELECTED)
193		else:
194			btn.SetState (IE_GUI_BUTTON_ENABLED)
195
196	return
197
198def MouseLeaveSlot (btn, slot):
199	pc = GemRB.GameGetSelectedPCSingle ()
200
201	UpdateSlot (pc, slot-1)
202	return
203
204def MouseEnterGround (Button):
205	if GemRB.IsDraggingItem ()==1:
206		Button.SetState (IE_GUI_BUTTON_SELECTED)
207	return
208
209def MouseLeaveGround (Button):
210	if GemRB.IsDraggingItem ()==1:
211		Button.SetState (IE_GUI_BUTTON_FAKEPRESSED)
212	return
213
214def CloseItemInfoWindow ():
215	if ItemInfoWindow:
216		ItemInfoWindow.Unload ()
217	UpdateInventoryWindow ()
218	return
219
220def DisplayItem (slotItem, itemtype):
221	global ItemInfoWindow
222
223	item = GemRB.GetItem (slotItem["ItemResRef"])
224
225	#window can be refreshed by cycling to next/prev item, so it may still exist
226	if not ItemInfoWindow:
227		ItemInfoWindow = GemRB.LoadWindow (5)
228
229	Window = ItemInfoWindow
230	def OnClose():
231		global ItemInfoWindow
232		ItemInfoWindow = None
233	Window.SetAction (OnClose, ACTION_WINDOW_CLOSED)
234
235	if GameCheck.IsPST():
236		strrefs = [ 1403, 4256, 4255, 4251, 4252, 4254, 4279 ]
237	elif GameCheck.IsGemRBDemo ():
238		strrefs = [ 84, 105, 106, 104, 107, item["DialogName"], 108 ]
239	else:
240		strrefs = [ 11973, 14133, 11960, 19392, 17104, item["DialogName"], 17108 ]
241
242	# item name
243	Label = Window.GetControl (0x10000000)
244	if (itemtype & 2):
245		text = item["ItemName"]
246	else:
247		text = item["ItemNameIdentified"]
248	Label.SetText (text)
249
250	#item icon
251	Button = Window.GetControl (2)
252	if GameCheck.IsPST():
253		Button.SetFlags (IE_GUI_BUTTON_PICTURE | IE_GUI_BUTTON_NO_IMAGE, OP_SET)
254		Button.SetItemIcon (slotItem["ItemResRef"])
255	else:
256		Button.SetFlags (IE_GUI_BUTTON_PICTURE, OP_OR)
257		Button.SetItemIcon (slotItem["ItemResRef"], 0)
258	Button.SetState (IE_GUI_BUTTON_LOCKED)
259
260	#middle button
261	Button = Window.GetControl (4)
262	Button.SetText (strrefs[0])
263	Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, CloseItemInfoWindow)
264	Button.MakeDefault()
265
266	#textarea
267	Text = Window.GetControl (5)
268	if GameCheck.IsBG2(): # I believe only BG2 has special initials
269		Text.SetColor (ColorWhitish, TA_COLOR_INITIALS)
270	if (itemtype & 2):
271		text = item["ItemDesc"]
272	else:
273		text = item["ItemDescIdentified"]
274
275	Text.Clear ()
276	Text.Append (text)
277
278	Window.SetEventProxy(Text)
279
280	#left button
281	Button = Window.GetControl(8)
282	select = (itemtype & 1) and (item["Function"]&ITM_F_ABILITIES)
283
284	if itemtype & 2:
285		Button.SetText (strrefs[1])
286		Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, IdentifyItemWindow)
287		Button.SetFlags (IE_GUI_BUTTON_PICTURE, OP_SET)
288	elif select and not GameCheck.IsPST():
289		Button.SetText (strrefs[2])
290		Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, AbilitiesItemWindow)
291		Button.SetFlags (IE_GUI_BUTTON_PICTURE, OP_SET)
292	else:
293		Button.SetText ("")
294		Button.SetState (IE_GUI_BUTTON_LOCKED)
295		Button.SetFlags (IE_GUI_BUTTON_NO_IMAGE, OP_SET)
296		Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, None)
297
298	# description icon (not present in iwds)
299	if not GameCheck.IsIWD1() and not GameCheck.IsIWD2():
300		Button = Window.GetControl (7)
301		Button.SetFlags (IE_GUI_BUTTON_PICTURE | IE_GUI_BUTTON_CENTER_PICTURES | IE_GUI_BUTTON_NO_IMAGE, OP_OR)
302		if GameCheck.IsPST():
303			Button.SetItemIcon (slotItem["ItemResRef"], 1) # no DescIcon
304		else:
305			Button.SetItemIcon (slotItem["ItemResRef"], 2)
306		Button.SetState (IE_GUI_BUTTON_LOCKED)
307
308	#right button
309	Button = Window.GetControl(9)
310	Button.SetFlags (IE_GUI_BUTTON_PICTURE, OP_SET)
311	drink = (itemtype & 1) and (item["Function"]&ITM_F_DRINK)
312	read = (itemtype & 1) and (item["Function"]&ITM_F_READ)
313	# sorcerers cannot learn spells
314	pc = GemRB.GameGetSelectedPCSingle ()
315	if Spellbook.HasSorcererBook (pc):
316		read = 0
317	container = (itemtype & 1) and (item["Function"]&ITM_F_CONTAINER)
318	dialog = (itemtype & 1) and (item["Dialog"]!="" and item["Dialog"]!="*")
319	familiar = (itemtype & 1) and (item["Type"] == 38)
320
321	# The "conversable" bit in PST actually means "usable", eg clot charm
322	# unlike BG2 (which only has the bit set on SW2H14 Lilarcor)
323	# Meanwhile IWD series has the bit set on important quest items
324	# So the widely accepted name of this bit is misleading
325
326	# There are also items in PST, cube.itm and doll.itm
327	# that are not flagged usable but still have dialog attached.
328	# this is how the original game draws the distinction between 'use item' and 'talk to item'
329
330	# if the item has dialog and is flagged usable = use item string, open dialog
331	# if the item has dialog and is not flagged usable = talk to item, open dialog
332	# if the item has no dialog and is flagged usable = use item string, consume item
333
334	if GameCheck.IsPST() and slotItem["Flags"] & IE_INV_ITEM_CONVERSABLE:
335
336		drink = True # "Use"
337
338	if drink and not dialog:
339		# Standard consumable item
340		Button.SetText (strrefs[3])
341		Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, ConsumeItem)
342	elif read:
343		Button.SetText (strrefs[4])
344		Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, ReadItemWindow)
345	elif container:
346		# Just skip the redundant info page and go directly to the container
347		if GemRB.GetVar("GUIEnhancements")&GE_ALWAYS_OPEN_CONTAINER_ITEMS:
348			OpenItemWindow()
349			return
350		if GameCheck.IsIWD2() or GameCheck.IsHOW():
351			Button.SetText (24891) # Open Container
352		elif GameCheck.IsBG2():
353			Button.SetText (44002) # open container
354		else:
355			# a fallback, since the originals have nothing appropriate from not having any bags
356			Button.SetText ("Open container")
357		Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, OpenItemWindow)
358	elif dialog:
359		if drink:
360			# Dialog item that is 'used'
361			Button.SetText (strrefs[3])
362		else:
363			# Dialog item that is 'talked to'
364			Button.SetText (strrefs[5])
365		Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, DialogItemWindow)
366	elif familiar and not GameCheck.IsPST():
367		# PST earings share a type with familiars, so no
368		# mods that allow familiars would be possible in PST
369		Button.SetText (4373)
370		Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, ReleaseFamiliar)
371	else:
372		Button.SetState (IE_GUI_BUTTON_LOCKED)
373		Button.SetFlags (IE_GUI_BUTTON_NO_IMAGE, OP_SET)
374		Button.SetText ("")
375		Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, None)
376
377	Label = Window.GetControl(0x1000000b)
378	if Label:
379		if (itemtype & 2):
380			# NOT IDENTIFIED
381			Label.SetText (strrefs[6])
382		else:
383			Label.SetText ("")
384
385	# in pst one can cycle through all the items from the description window
386	if GameCheck.IsPST():
387
388		#left scroll
389		Button = Window.GetControl (13)
390		Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, lambda: CycleDisplayItem(-1))
391
392		#right scroll
393		Button = Window.GetControl (14)
394		Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, lambda: CycleDisplayItem(1))
395
396	ItemInfoWindow.ShowModal(MODAL_SHADOW_GRAY)
397	return
398
399def CycleDisplayItem(direction):
400
401	slot = int(GemRB.GetVar('ItemButton'))
402
403	pc = GemRB.GameGetSelectedPCSingle ()
404
405	slot_item = None
406
407	#try the next slot for an item. if the slot is empty, loop until one is found.
408	while not slot_item:
409		slot += direction
410
411		#wrap around if last slot is reached
412		if slot > 53:
413			slot = 0
414		elif slot < 0:
415			slot = 53
416
417		slot_item = GemRB.GetSlotItem (pc, slot)
418		GemRB.SetVar('ItemButton', slot)
419
420	if slot_item:
421		OpenItemInfoWindow (None, slot)
422
423def OpenItemInfoWindow (btn, slot):
424	pc = GemRB.GameGetSelectedPCSingle ()
425
426	slotItem = GemRB.GetSlotItem (pc, slot)
427	slotType = GemRB.GetSlotType (slot, pc)
428
429	# PST: if the slot is empty but is also the first quick weapon slot, display the info for the "default" weapon
430	if GameCheck.IsPST() and slotItem is None and slotType["ID"] == 10 and GemRB.GetEquippedQuickSlot(pc) == 10:
431		DisplayItem (GemRB.GetSlotItem (pc, 0), 1)
432		return
433
434	item = GemRB.GetItem (slotItem["ItemResRef"])
435
436	if TryAutoIdentification(pc, item, slot, slotItem, True):
437		UpdateInventoryWindow ()
438
439	if slotItem["Flags"] & IE_INV_ITEM_IDENTIFIED:
440		value = 1
441	else:
442		value = 3
443	DisplayItem (slotItem, value)
444	return
445
446#auto identify when lore is high enough
447def TryAutoIdentification(pc, item, slot, slot_item, enabled=0):
448	if enabled and item["LoreToID"]<=GemRB.GetPlayerStat (pc, IE_LORE):
449		GemRB.ChangeItemFlag (pc, slot, IE_INV_ITEM_IDENTIFIED, OP_OR)
450		slot_item["Flags"] |= IE_INV_ITEM_IDENTIFIED
451		return True
452	return False
453
454def OpenGroundItemInfoWindow (btn, slot):
455	global ItemInfoWindow
456
457	pc = GemRB.GameGetSelectedPCSingle ()
458	slot = slot + GemRB.GetVar ("TopIndex") - (47 if GameCheck.IsPST () else 68)
459	slot_item = GemRB.GetContainerItem (pc, slot)
460
461	#the ground items are only displayable
462	if slot_item["Flags"] & IE_INV_ITEM_IDENTIFIED:
463		value = 0
464	else:
465		value = 2
466	DisplayItem(slot_item, value)
467	return
468
469# TODO: implement, reuse OpenItemAmountWindow, but be careful about any other uses of ItemButton
470def OpenGroundItemAmountWindow ():
471	pass
472
473def ItemAmountWindowClosed(win):
474	global ItemAmountWindow, UsedSlot
475
476	ItemAmountWindow = None
477	UsedSlot = None
478	UpdateInventoryWindow()
479
480# TODO: can the GUISTORE be consolidate with this one?
481def OpenItemAmountWindow (btn, slot):
482	"""Open the split window."""
483
484	global UsedSlot, OverSlot
485	global ItemAmountWindow, StackAmount
486
487	pc = GemRB.GameGetSelectedPCSingle ()
488
489	UsedSlot = slot
490	if GemRB.IsDraggingItem ()==1:
491		GemRB.DropDraggedItem (pc, UsedSlot)
492		#redraw slot
493		UpdateSlot (pc, UsedSlot-1)
494		# disallow splitting while holding split items (double splitting)
495		if GemRB.IsDraggingItem () == 1:
496			return
497
498	slot_item = GemRB.GetSlotItem (pc, UsedSlot)
499
500	if slot_item:
501		StackAmount = slot_item["Usages0"]
502	else:
503		StackAmount = 0
504	if StackAmount<=1:
505		UpdateSlot (pc, UsedSlot-1)
506		return
507
508	ItemAmountWindow = Window = GemRB.LoadWindow (4)
509	Window.SetFlags(WF_ALPHA_CHANNEL, OP_OR)
510	Window.SetAction(ItemAmountWindowClosed, ACTION_WINDOW_CLOSED)
511
512	strings = { 'Done': 11973, "Cancel": 13727}
513	if GameCheck.IsPST():
514		strings = { 'Done': 1403, "Cancel": 4196}
515	elif GameCheck.IsGemRBDemo ():
516		strings = { 'Done': 84, 'Cancel': 103}
517
518	# item icon
519	Icon = Window.GetControl (0)
520	Icon.SetFlags (IE_GUI_BUTTON_PICTURE | IE_GUI_BUTTON_NO_IMAGE, OP_SET)
521	Icon.SetItemIcon (slot_item['ItemResRef'])
522
523	# item amount
524	Text = Window.GetControl (6)
525	# FIXME: use a proper size
526	# FIXME: fix it for all the games
527	if GameCheck.IsIWD2():
528		Text.SetSize (40, 40)
529	Text.SetText (str (StackAmount//2))
530	Text.SetFlags (IE_GUI_TEXTEDIT_ALPHACHARS, OP_NAND)
531	Text.Focus()
532
533	# Decrease
534	Button = Window.GetControl (4)
535	Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, DecreaseStackAmount)
536	Button.SetActionInterval (200)
537
538	# Increase
539	Button = Window.GetControl (3)
540	Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, IncreaseStackAmount)
541	Button.SetActionInterval (200)
542
543	# Done
544	Button = Window.GetControl (2)
545	Button.SetText (strings['Done'])
546	Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, DragItemAmount)
547	Button.MakeDefault()
548
549	# Cancel
550	Button = Window.GetControl (1)
551	Button.SetText (strings['Cancel'])
552	Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, lambda: Window.Close())
553	Button.MakeEscape()
554
555	Window.ShowModal (MODAL_SHADOW_GRAY)
556	return
557
558def UpdateSlot (pc, slot):
559	"""Updates a specific slot."""
560
561	Window = GemRB.GetView("WIN_INV")
562
563	using_fists = slot_item = SlotType = None
564
565	if GameCheck.IsPST():
566		if slot >= len(SlotMap):
567			#this prevents accidental out of range errors from the avslots list
568			return GemRB.GetSlotType (slot+1)
569		elif SlotMap[slot] == -1:
570			# This decides which icon to display in the empty slot
571			# NOTE: there are invisible items (e.g. MORTEP) in inaccessible slots
572			# used to assign powers and protections
573
574			SlotType = GemRB.GetSlotType (slot+1, pc)
575			slot_item = None
576		else:
577			SlotType = GemRB.GetSlotType (SlotMap[slot]+1)
578			slot_item = GemRB.GetSlotItem (pc, SlotMap[slot]+1)
579			#PST displays the default weapon in the first slot if nothing else was equipped
580			if slot_item is None and SlotType["ID"] == 10 and GemRB.GetEquippedQuickSlot(pc) == 10:
581				slot_item = GemRB.GetSlotItem (pc, 0)
582				using_fists = 1
583	else:
584		SlotType = GemRB.GetSlotType (slot+1, pc)
585		slot_item = GemRB.GetSlotItem (pc, slot+1)
586
587	ControlID = SlotType["ID"]
588
589	if ControlID == -1:
590		return None
591
592	if GemRB.IsDraggingItem ()==1:
593		#get dragged item
594		drag_item = GemRB.GetSlotItem (0,0)
595		itemname = drag_item["ItemResRef"]
596	else:
597		itemname = ""
598
599	Button = Window.GetControl (ControlID)
600
601	# It is important to check for a control - some games use CID 0 for slots with no control, others -1
602	if not Button:
603		return
604
605	Button.SetAction (OnDragItem, IE_ACT_DRAG_DROP_DST)
606	Button.SetFlags (IE_GUI_BUTTON_NO_IMAGE, OP_NAND)
607
608	# characters should auto-identify any item they recieve
609	if slot_item:
610		item = GemRB.GetItem (slot_item["ItemResRef"])
611		TryAutoIdentification(pc, item, slot+1, slot_item, GemRB.GetVar("GUIEnhancements")&GE_TRY_IDENTIFY_ON_TRANSFER)
612
613	UpdateInventorySlot (pc, Button, slot_item, "inventory", SlotType["Type"]&SLOT_INVENTORY == 0)
614
615	if slot_item:
616		Button.SetAction(OnDragItem, IE_ACT_DRAG_DROP_CRT)
617		Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, OnDragItem)
618		Button.SetEvent (IE_GUI_BUTTON_ON_RIGHT_PRESS, OpenItemInfoWindow)
619		Button.SetEvent (IE_GUI_BUTTON_ON_SHIFT_PRESS, OpenItemAmountWindow)
620		#If the slot is being used to display the 'default' weapon, disable dragging.
621		if SlotType["ID"] == 10 and using_fists:
622			Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, None)
623			#dropping is ok, because it will drop in the quick weapon slot and not the default weapon slot.
624	else:
625		if SlotType["ResRef"]=="*":
626			Button.SetBAM ("",0,0)
627			Button.SetTooltip (SlotType["Tip"])
628			itemname = ""
629		elif SlotType["ResRef"]=="":
630			Button.SetBAM ("",0,0)
631			Button.SetFlags (IE_GUI_BUTTON_NO_IMAGE, OP_OR)
632			Button.SetTooltip ("")
633			itemname = ""
634		else:
635			if SlotType["Flags"] & 2:
636				Button.SetPicture (SlotType["ResRef"])
637			else:
638				Button.SetBAM (SlotType["ResRef"], 0, 0)
639			Button.SetTooltip (SlotType["Tip"])
640
641		if SlotMap and SlotMap[slot]<0:
642			Button.SetBAM ("",0,0)
643			Button.SetFlags (IE_GUI_BUTTON_NO_IMAGE, OP_OR)
644			Button.SetTooltip ("")
645			itemname = ""
646
647		Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, None)
648		Button.SetEvent (IE_GUI_BUTTON_ON_RIGHT_PRESS, None)
649		Button.SetEvent (IE_GUI_BUTTON_ON_SHIFT_PRESS, None)
650		Button.SetEvent (IE_GUI_BUTTON_ON_DOUBLE_PRESS, OpenItemAmountWindow)
651
652	if (SlotType["Type"]&SLOT_INVENTORY) or not GemRB.CanUseItemType (SlotType["Type"], itemname):
653		Button.SetState (IE_GUI_BUTTON_ENABLED)
654	else:
655		Button.SetState (IE_GUI_BUTTON_FAKEPRESSED)
656
657	if slot_item and (GemRB.GetEquippedQuickSlot (pc)==slot+1 or GemRB.GetEquippedAmmunition (pc)==slot+1):
658		Button.SetState (IE_GUI_BUTTON_FAKEDISABLED)
659
660	return SlotType
661
662def CancelColor():
663	global ColorPicker
664	if ColorPicker:
665		ColorPicker.Unload ()
666	InventoryWindow = GemRB.GetView ("WIN_INV")
667	InventoryWindow.Focus ()
668	return
669
670def ColorDonePress():
671	"""Saves the selected colors."""
672
673	pc = GemRB.GameGetSelectedPCSingle ()
674
675	if ColorPicker:
676		ColorPicker.Unload ()
677
678	ColorTable = GemRB.LoadTable ("clowncol")
679	PickedColor=ColorTable.GetValue (ColorIndex, GemRB.GetVar ("Selected"))
680	if ColorIndex==0:
681		GUICommon.SetColorStat (pc, IE_HAIR_COLOR, PickedColor)
682	elif ColorIndex==1:
683		GUICommon.SetColorStat (pc, IE_SKIN_COLOR, PickedColor)
684	elif ColorIndex==2:
685		GUICommon.SetColorStat (pc, IE_MAJOR_COLOR, PickedColor)
686	else:
687		GUICommon.SetColorStat (pc, IE_MINOR_COLOR, PickedColor)
688	UpdateInventoryWindow ()
689	return
690
691def HairPress():
692	global ColorIndex, PickedColor
693
694	pc = GemRB.GameGetSelectedPCSingle ()
695	ColorIndex = 0
696	PickedColor = GemRB.GetPlayerStat (pc, IE_HAIR_COLOR, 1) & 0xFF
697	GetColor()
698	return
699
700def SkinPress():
701	global ColorIndex, PickedColor
702
703	pc = GemRB.GameGetSelectedPCSingle ()
704	ColorIndex = 1
705	PickedColor = GemRB.GetPlayerStat (pc, IE_SKIN_COLOR, 1) & 0xFF
706	GetColor()
707	return
708
709def MajorPress():
710	"""Selects the major color."""
711	global ColorIndex, PickedColor
712
713	pc = GemRB.GameGetSelectedPCSingle ()
714	ColorIndex = 2
715	PickedColor = GemRB.GetPlayerStat (pc, IE_MAJOR_COLOR, 1) & 0xFF
716	GetColor()
717	return
718
719def MinorPress():
720	"""Selects the minor color."""
721	global ColorIndex, PickedColor
722
723	pc = GemRB.GameGetSelectedPCSingle ()
724	ColorIndex = 3
725	PickedColor = GemRB.GetPlayerStat (pc, IE_MINOR_COLOR, 1) & 0xFF
726	GetColor()
727	return
728
729def GetColor():
730	"""Opens the color selection window."""
731
732	global ColorPicker
733
734	ColorTable = GemRB.LoadTable ("clowncol")
735	InventoryWindow = GemRB.GetView ("WIN_INV")
736	InventoryWindow.SetDisabled (True) #darken it
737	ColorPicker = GemRB.LoadWindow (3)
738	GemRB.SetVar ("Selected",-1)
739	if GameCheck.IsIWD2 () or GameCheck.IsGemRBDemo ():
740		Button = ColorPicker.GetControl (35)
741		Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, CancelColor)
742		Button.SetText (103)
743		if GameCheck.IsIWD2 ():
744			Button.SetText (13727)
745
746	for i in range (34):
747		Button = ColorPicker.GetControl (i)
748		MyColor = ColorTable.GetValue (ColorIndex, i)
749		if MyColor == "*":
750			Button.SetState (IE_GUI_BUTTON_LOCKED)
751			continue
752		if PickedColor == MyColor:
753			GemRB.SetVar ("Selected",i)
754			Button.SetState (IE_GUI_BUTTON_LOCKED)
755			Button.MakeEscape()
756		else:
757			Button.SetBAM ("COLGRAD", 2, 0, MyColor)
758			Button.SetFlags (IE_GUI_BUTTON_PICTURE|IE_GUI_BUTTON_RADIOBUTTON, OP_OR)
759			Button.SetState (IE_GUI_BUTTON_ENABLED)
760		Button.SetVarAssoc ("Selected",i)
761		Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, ColorDonePress)
762	ColorPicker.Focus()
763	return
764
765def ReleaseFamiliar ():
766	"""Simple Use Item"""
767
768	pc = GemRB.GameGetSelectedPCSingle ()
769	slot = GemRB.GetVar ("ItemButton")
770	# the header is always the first, target is always self
771	GemRB.UseItem (pc, slot, 0, 5)
772	CloseItemInfoWindow ()
773	return
774
775def ConsumeItem ():
776	"""Drink the potion"""
777
778	pc = GemRB.GameGetSelectedPCSingle ()
779	slot = GemRB.GetVar ("ItemButton")
780	# the drink item header is always the first
781	# pst also requires forcing the target (eg. clot charms), which doesn't hurt elsewhere
782	GemRB.UseItem (pc, slot, 0, 5)
783	CloseItemInfoWindow ()
784	return
785
786def OpenErrorWindow (strref):
787	"""Opens the error window and displays the string."""
788
789	global ErrorWindow
790
791	ErrorWindow = Window = GemRB.LoadWindow (7)
792	Button = Window.GetControl (0)
793	if GameCheck.IsPST():
794		Button.SetText (1403)
795	else:
796		Button.SetText (11973)
797	Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, CloseErrorWindow)
798	Button.MakeDefault()
799
800	TextArea = Window.GetControl (3)
801	TextArea.SetText (strref)
802	Window.ShowModal (MODAL_SHADOW_GRAY)
803	return
804
805def CloseErrorWindow ():
806	if ErrorWindow:
807		ErrorWindow.Unload ()
808	UpdateInventoryWindow ()
809	return
810
811def ReadItemWindow ():
812	"""Tries to learn the mage scroll."""
813
814	pc = GemRB.GameGetSelectedPCSingle ()
815	slot = GemRB.GetVar ("ItemButton")
816	ret = Spellbook.CannotLearnSlotSpell()
817
818	if ret:
819		# these failures are soft - the scroll is not destroyed
820		if ret == LSR_KNOWN and GameCheck.HasTOB():
821			strref = 72873
822		elif ret == LSR_KNOWN and GameCheck.IsPST():
823			strref = 50394
824		elif ret == LSR_STAT and GameCheck.HasTOB():
825			# reached for sorcerers, schools/usability is handled before
826			strref = 72874 # your spell school does not permit you to learn
827		elif ret == LSR_LEVEL and GameCheck.HasTOB():
828			strref = 48806 # inadequate intelligence (good enough approximation)
829		elif ret == LSR_FULL and GameCheck.IsBG2():
830			strref = 32097
831		elif ret == LSR_FULL and GameCheck.IsPST():
832			strref = 50395
833		elif GameCheck.IsPST():
834			strref = 4250
835		else:
836			strref = 10831
837
838		CloseItemInfoWindow ()
839		GemRB.PlaySound ("EFF_M10") # failure!
840		OpenErrorWindow (strref)
841		return
842
843	# we already checked for most failures, but we can still fail with bad % rolls vs intelligence
844	ret = Spellbook.LearnFromScroll (pc, slot)
845	if ret == LSR_OK:
846		GemRB.PlaySound ("GAM_44") # success!
847		if GameCheck.IsPST():
848			strref = 4249
849		else:
850			strref = 10830
851	else:
852		GemRB.PlaySound ("EFF_M10") # failure!
853		if GameCheck.IsPST():
854			strref = 4250
855		else:
856			strref = 10831
857
858	CloseItemInfoWindow ()
859	OpenErrorWindow (strref)
860
861def OpenItemWindow ():
862	"""Displays information about the item."""
863
864	#close inventory
865	GemRB.SetVar ("Inventory", 1)
866	slot = GemRB.GetVar ("ItemButton") #get this before closing win
867	if ItemInfoWindow:
868		ItemInfoWindow.Unload ()
869
870	pc = GemRB.GameGetSelectedPCSingle ()
871	slot_item = GemRB.GetSlotItem (pc, slot)
872	ResRef = slot_item['ItemResRef']
873	#the store will have to reopen the inventory
874	GemRB.EnterStore (ResRef)
875	return
876
877def DialogItemWindow ():
878	"""Converse with an item."""
879
880	pc = GemRB.GameGetSelectedPCSingle ()
881
882	slot = GemRB.GetVar ("ItemButton")
883	slot_item = GemRB.GetSlotItem (pc, slot)
884
885	ResRef = slot_item['ItemResRef']
886	item = GemRB.GetItem (ResRef)
887	dialog=item["Dialog"]
888	if ItemInfoWindow:
889		ItemInfoWindow.Unload ()
890
891	GemRB.ExecuteString ("StartDialogOverride(\""+dialog+"\",Myself,0,0,1)", pc)
892	return
893
894def IdentifyUseSpell ():
895	"""Identifies the item with a memorized spell."""
896
897	global ItemIdentifyWindow
898
899	pc = GemRB.GameGetSelectedPCSingle ()
900	slot = GemRB.GetVar ("ItemButton")
901	if ItemIdentifyWindow:
902		ItemIdentifyWindow.Unload ()
903	GemRB.HasSpecialSpell (pc, SP_IDENTIFY, 1)
904	if ItemInfoWindow:
905		ItemInfoWindow.Unload ()
906	GemRB.ChangeItemFlag (pc, slot, IE_INV_ITEM_IDENTIFIED, OP_OR)
907	GemRB.PlaySound(DEF_IDENTIFY)
908	OpenItemInfoWindow(None, slot)
909	return
910
911def IdentifyUseScroll ():
912	"""Identifies the item with a scroll or other item."""
913
914	global ItemIdentifyWindow
915
916	pc = GemRB.GameGetSelectedPCSingle ()
917	slot = GemRB.GetVar ("ItemButton")
918	if ItemIdentifyWindow:
919		ItemIdentifyWindow.Unload ()
920	if ItemInfoWindow:
921		ItemInfoWindow.Unload ()
922	if GemRB.HasSpecialItem (pc, 1, 1):
923		GemRB.ChangeItemFlag (pc, slot, IE_INV_ITEM_IDENTIFIED, OP_OR)
924	GemRB.PlaySound(DEF_IDENTIFY)
925	OpenItemInfoWindow(None, slot)
926	return
927
928def CloseIdentifyItemWindow ():
929	global ItemIdentifyWindow, ItemInfoWindow
930
931	if ItemIdentifyWindow:
932		ItemIdentifyWindow.Unload ()
933		ItemIdentifyWindow = None
934	if ItemInfoWindow:
935		ItemInfoWindow.ShowModal (MODAL_SHADOW_GRAY)
936	return
937
938def IdentifyItemWindow ():
939	global ItemIdentifyWindow
940
941	pc = GemRB.GameGetSelectedPCSingle ()
942
943	ItemIdentifyWindow = Window = GemRB.LoadWindow (9)
944	Button = Window.GetControl (0)
945	if GameCheck.IsPST():
946		Button.SetText (4259)
947	else:
948		Button.SetText (17105)
949	Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, IdentifyUseSpell)
950	if not GemRB.HasSpecialSpell (pc, SP_IDENTIFY, 0):
951		Button.SetState (IE_GUI_BUTTON_DISABLED)
952
953	Button = Window.GetControl (1)
954	if GameCheck.IsPST():
955		Button.SetText (4260)
956	else:
957		Button.SetText (17106)
958	Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, IdentifyUseScroll)
959	if not GemRB.HasSpecialItem (pc, 1, 0):
960		Button.SetState (IE_GUI_BUTTON_DISABLED)
961
962	Button = Window.GetControl (2)
963	if GameCheck.IsPST():
964		Button.SetText (4196)
965	else:
966		Button.SetText (13727)
967	Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, CloseIdentifyItemWindow)
968	Button.MakeEscape()
969
970	TextArea = Window.GetControl (3)
971	if GameCheck.IsPST():
972		TextArea.SetText (4258)
973	else:
974		TextArea.SetText (19394)
975	Window.ShowModal (MODAL_SHADOW_GRAY)
976	return
977
978def DoneAbilitiesItemWindow ():
979	pc = GemRB.GameGetSelectedPCSingle ()
980	slot = GemRB.GetVar ("ItemButton")
981	GemRB.SetupQuickSlot (pc, 0, slot, GemRB.GetVar ("Ability") )
982	CloseAbilitiesItemWindow ()
983	return
984
985def CloseAbilitiesItemWindow ():
986	global ItemAbilitiesWindow, ItemInfoWindow
987
988	if ItemAbilitiesWindow:
989		ItemAbilitiesWindow.Unload ()
990		ItemAbilitiesWindow = None
991	if ItemInfoWindow:
992		ItemInfoWindow.ShowModal (MODAL_SHADOW_GRAY)
993	return
994
995def AbilitiesItemWindow ():
996	global ItemAbilitiesWindow
997
998	ItemAbilitiesWindow = Window = GemRB.LoadWindow (6)
999
1000	pc = GemRB.GameGetSelectedPCSingle ()
1001	slot = GemRB.GetVar ("ItemButton")
1002	slot_item = GemRB.GetSlotItem (pc, slot)
1003	item = GemRB.GetItem (slot_item["ItemResRef"])
1004	Tips = item["Tooltips"]
1005
1006	GemRB.SetVar ("Ability", slot_item["Header"])
1007	for i in range(3):
1008		Button = Window.GetControl (i+1)
1009		if GameCheck.IsBG2(): # TODO: check pst
1010			Button.SetSprites ("GUIBTBUT",i,0,1,2,0)
1011		Button.SetFlags (IE_GUI_BUTTON_RADIOBUTTON, OP_OR)
1012		Button.SetVarAssoc ("Ability",i)
1013		Text = Window.GetControl (i+0x10000003)
1014		if i<len(Tips):
1015			Button.SetItemIcon (slot_item['ItemResRef'],i+6)
1016			Text.SetText (Tips[i])
1017		else:
1018			#disable button
1019			Button.SetItemIcon ("",3)
1020			Text.SetText ("")
1021			Button.SetState (IE_GUI_BUTTON_DISABLED)
1022
1023	TextArea = Window.GetControl (8)
1024	TextArea.SetText (11322)
1025
1026	Button = Window.GetControl (7)
1027	Button.SetText (11973)
1028	Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, DoneAbilitiesItemWindow)
1029	Button.MakeDefault()
1030
1031	Button = Window.GetControl (10)
1032	Button.SetText (13727)
1033	Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, CloseAbilitiesItemWindow)
1034	Button.MakeEscape()
1035	Window.ShowModal (MODAL_SHADOW_GRAY)
1036	return
1037
1038def UpdateInventorySlot (pc, Button, Slot, Type, Equipped=False):
1039	Button.SetFont ("NUMBER")
1040
1041	color = {'r' : 128, 'g' : 128, 'b' : 255, 'a' : 64}
1042	Button.SetBorder (0, color, 0,1)
1043	color = {'r' : 32, 'g' : 32, 'b' : 255, 'a' : 255}
1044	Button.SetBorder (1, color, 0,0, Button.GetInsetFrame(2))
1045	color = {'r' : 255, 'g' : 128, 'b' : 128, 'a' : 64}
1046	Button.SetBorder (2, color, 0,1)
1047
1048	Button.SetText ("")
1049	Button.SetFlags (IE_GUI_BUTTON_ALIGN_RIGHT | IE_GUI_BUTTON_ALIGN_BOTTOM | IE_GUI_BUTTON_PICTURE, OP_OR)
1050
1051	if Slot == None:
1052		Button.SetFlags (IE_GUI_BUTTON_PICTURE, OP_NAND)
1053		tooltips = { "inventory": 12013, "ground": 12011, "container": "" }
1054		if GameCheck.IsGemRBDemo ():
1055			tooltips = { "inventory": 82, "ground": 83, "container": "" }
1056		Button.SetTooltip (tooltips[Type])
1057		Button.EnableBorder (0, 0)
1058		Button.EnableBorder (1, 0)
1059		Button.EnableBorder (2, 0)
1060	else:
1061		item = GemRB.GetItem (Slot['ItemResRef'])
1062		identified = Slot["Flags"] & IE_INV_ITEM_IDENTIFIED
1063		magical = item["Enchantment"] > 0
1064
1065		# MaxStackAmount holds the *maximum* item count in the stack while Usages0 holds the actual
1066		if item["MaxStackAmount"] > 1:
1067			Button.SetText (str (Slot["Usages0"]))
1068		else:
1069			Button.SetText ("")
1070
1071		# auto-identify mundane items; the actual indentification will happen on transfer
1072		if not identified and item["LoreToID"] == 0:
1073			identified = True
1074
1075		if not identified or item["ItemNameIdentified"] == -1:
1076			Button.SetTooltip (item["ItemName"])
1077			Button.EnableBorder (0, 1)
1078			Button.EnableBorder (1, 0)
1079		else:
1080			Button.SetTooltip (item["ItemNameIdentified"])
1081			Button.EnableBorder (0, 0)
1082			if magical and not GameCheck.IsPST():
1083				Button.EnableBorder (1, 1)
1084			else:
1085				Button.EnableBorder (1, 0)
1086
1087		if GemRB.CanUseItemType (SLOT_ALL, Slot['ItemResRef'], pc, Equipped):
1088			Button.EnableBorder (2, 0)
1089		else:
1090			Button.EnableBorder (2, 1)
1091
1092		Button.SetItemIcon (Slot['ItemResRef'], 0)
1093
1094	return
1095