1# -*-python-*- 2# GemRB - Infinity Engine Emulator 3# Copyright (C) 2003-2004 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 20 21# GUICommonWindows.py - functions to open common 22# windows in lower part of the screen 23################################################### 24 25import GemRB 26from GUIDefines import * 27from ie_stats import * 28from ie_modal import * 29from ie_action import * 30from ie_slots import SLOT_QUIVER 31from ie_restype import RES_2DA 32from ie_sounds import CHAN_HITS 33from GameCheck import MAX_PARTY_SIZE 34from Clock import UpdateClock 35import GameCheck 36import GUICommon 37import CommonTables 38import CommonWindow 39import LUCommon 40import InventoryCommon 41if not GameCheck.IsPST(): 42 import Spellbook ##not used in pst - YET 43 44FRAME_PC_SELECTED = 0 45FRAME_PC_TARGET = 1 46 47CurrentWindow = None 48ActionBarControlOffset = 0 49ScreenHeight = GemRB.GetSystemVariable (SV_HEIGHT) 50 51if GameCheck.IsIWD2(): 52 MageSpellsKey = 'Spellbook' 53 CharacterStatsKey = 'Character_Record' 54elif GameCheck.IsPST(): 55 MageSpellsKey = 'Mage_Spells' 56 CharacterStatsKey = 'Character_Stats' 57else: 58 MageSpellsKey = 'Wizard_Spells' 59 CharacterStatsKey = 'Character_Record' 60 61#The following tables deal with the different control indexes and string refs of each game 62#so that actual interface code can be game neutral 63#the dictionary keys match entries in keymap.2da 64AITip = {"Deactivate" : 15918, "Enable" : 15917} 65if GameCheck.IsPST(): #Torment 66 import GUIClasses 67 TimeWindow = None 68 PortWindow = None 69 MenuWindow = None 70 MainWindow = None 71 DiscWindow = None 72 AITip = { "Deactivate" : 41631, "Enable" : 41646 } 73 OptionTip = { #dictionary to the stringrefs in each games dialog.tlk 74 'Inventory' : 41601,'Map': 41625, MageSpellsKey : 41624, 'Priest_Spells': 4709, CharacterStatsKey : 4707,'Journal': 41623, 75 'Options' : 41626,'Rest': 41628,'Follow': 41647,'Expand': 41660,'Toggle_AI' : 1,'Return_To_Game' : 1,'Party' : 1 76 } 77 OptionControl = { #dictionary to the control indexes in the window (.CHU) 78 'Inventory' : 1, 'Map' : 2, MageSpellsKey : 3, 'Priest_Spells': 7, CharacterStatsKey : 5, 'Journal': 6, 79 'Options' : 8, 'Rest': 9, 'Follow': 0, 'Expand': 10, 'Toggle_AI': 4, 80 'Return_To_Game': 0, 'Party' : 8 , 'Time': 9 #not in pst 81 } 82elif GameCheck.IsIWD2(): #Icewind Dale 2 83 OptionTip = { 84 'Inventory' : 16307, 'Map': 16310, MageSpellsKey : 16309, CharacterStatsKey : 16306, 'Journal': 16308, 85 'Options' : 16311, 'Rest': 11942, 'Follow': 41647, 'Expand': 41660, 'Toggle_AI' : 1,'Return_To_Game' : 16313, 'Party' : 16312, 86 'SelectAll': 10485 87 } 88 OptionControl = { 89 'Inventory' : 5, 'Map' : 7, CharacterStatsKey : 8, 'Journal': 6, 90 'Options' : 9, 'Rest': 12, 'Follow': 0, 'Expand': 10, 'Toggle_AI': 14, 91 'Return_To_Game': 0, 'Party' : 13, 'Time': 10, #not in pst 92 MageSpellsKey: 4, 'SelectAll': 11 93 } 94else: # Baldurs Gate, Icewind Dale 95 OptionTip = { 96 'Inventory' : 16307, 'Map': 16310, MageSpellsKey : 16309, 'Priest_Spells': 14930, CharacterStatsKey : 16306, 'Journal': 16308, 97 'Options' : 16311, 'Rest': 11942, 'Follow': 41647, 'Expand': 41660, 'Toggle_AI' : 1, 'Return_To_Game' : 16313, 'Party' : 16312 98 } 99 OptionControl = { 100 'Inventory' : 3, 'Map' : 1, MageSpellsKey : 5, 'Priest_Spells': 6, CharacterStatsKey : 4, 'Journal': 2, 101 'Options' : 7, 'Rest': 9, 'Follow': 0, 'Expand': 10, 'Toggle_AI': 6, 102 'Return_To_Game': 0, 'Party' : 8, 'Time': 9 #not in pst 103 } 104 105# Generic option button init. Pass it the options window. Index is a key to the dicts, 106# IsPage means whether the game should mark the button selected 107def InitOptionButton(Window, Index, HotKey=True): 108 Button = Window.GetControl (OptionControl[Index]) 109 if not Button: 110 print("InitOptionButton cannot find the button: " + Index) 111 return 112 113 Button.SetTooltip (OptionTip[Index]) 114 if HotKey: 115 Button.SetHotKey (Index, True) 116 117 # this variable isnt used anywhere (tho it might be useful to use it for knowing what window is open) 118 # however, we still need to set one because we do depend on the button having a value 119 Button.SetVarAssoc ("OPT_BTN", OptionControl[Index]) 120 121 return Button 122 123##these defaults don't seem to break the games other than pst 124def SetupMenuWindowControls (Window, Gears=None, CloseWindowCallback=None): 125 """Binds all of the basic controls and windows to the options pane.""" 126 127 global ActionBarControlOffset 128 129 bg1 = GameCheck.IsBG1() 130 bg2 = GameCheck.IsBG2() 131 iwd1 = GameCheck.IsIWD1() 132 how = GameCheck.HasHOW() 133 iwd2 = GameCheck.IsIWD2() 134 pst = GameCheck.IsPST() 135 #store these instead of doing 50 calls... 136 137 EscButton = Window.CreateButton (99, 0, 0, 0, 0); 138 EscButton.SetEvent(IE_GUI_BUTTON_ON_PRESS, CloseTopWindow) 139 EscButton.MakeEscape() 140 141 if iwd2: # IWD2 has one spellbook to rule them all 142 ActionBarControlOffset = 6 #portrait and action window were merged 143 144 InitOptionButton(Window, MageSpellsKey) 145 146 # AI 147 Button = InitOptionButton(Window, 'Toggle_AI') 148 Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, AIPress) 149 AIPress (0) #this initialises the state and tooltip 150 151 # Select All 152 Button = InitOptionButton(Window, 'SelectAll', False) 153 Button.SetEvent(IE_GUI_BUTTON_ON_PRESS, GUICommon.SelectAllOnPress) 154 elif pst: #pst has these three controls here instead of portrait pane 155 # (Un)Lock view on character 156 Button = InitOptionButton(Window, 'Follow', False) # or 41648 Unlock ... 157 Button.SetEvent(IE_GUI_BUTTON_ON_PRESS, OnLockViewPress) 158 # AI 159 Button = InitOptionButton(Window, 'Toggle_AI') 160 Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, AIPress) 161 AIPress(0) #this initialises the state and tooltip 162 163 # Message popup FIXME disable on non game screen... 164 Button = InitOptionButton(Window, 'Expand', False)# or 41661 Close ... 165 166 else: ## pst lacks this control here. it is on the clock. iwd2 seems to skip it 167 # Return to Game 168 Button = InitOptionButton(Window,'Return_To_Game') 169 170 if bg1: 171 # enabled BAM isn't present in .chu, defining it here 172 Button.SetSprites ("GUILSOP", 0,16,17,28,16) 173 if iwd1: 174 # disabled/selected frame isn't present in .chu, defining it here 175 Button.SetSprites ("GUILSOP", 0,16,17,16,16) 176 177 # Party managment / character arbitration. Distinct form reform party window. 178 if not pst: 179 Button = Window.GetControl (OptionControl['Party']) 180 Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, None) #TODO: OpenPartyWindow 181 if bg1 or bg2: 182 Button.SetState (IE_GUI_BUTTON_DISABLED) 183 Button.SetFlags (IE_GUI_BUTTON_NO_IMAGE, OP_OR) 184 else: 185 Button.SetTooltip (OptionTip['Party']) 186 187 # Map 188 Button = InitOptionButton(Window, 'Map') 189 if bg1: 190 Button.SetSprites ("GUILSOP", 0,0,1,20,0) 191 if iwd1: 192 Button.SetSprites ("GUILSOP", 0,0,1,20,20) 193 194 # Journal 195 Button = InitOptionButton(Window, 'Journal') 196 if bg1: 197 Button.SetSprites ("GUILSOP", 0,4,5,22,4) 198 if iwd1: 199 Button.SetSprites ("GUILSOP", 0,4,5,22,22) 200 201 # Inventory 202 Button = InitOptionButton(Window, 'Inventory') 203 if bg1: 204 Button.SetSprites ("GUILSOP", 0,2,3,21,2) 205 if iwd1: 206 Button.SetSprites ("GUILSOP", 0,2,3,21,21) 207 208 # Records 209 Button = InitOptionButton(Window, CharacterStatsKey) 210 if bg1: 211 Button.SetSprites ("GUILSOP", 0,6,7,23,6) 212 if iwd1: 213 Button.SetSprites ("GUILSOP", 0,6,7,23,23) 214 215 if not iwd2: # All Other Games Have Fancy Distinct Spell Pages 216 # Mage 217 Button = InitOptionButton(Window, MageSpellsKey) 218 if bg1: 219 Button.SetSprites ("GUILSOP", 0,8,9,24,8) 220 if iwd1: 221 Button.SetSprites ("GUILSOP", 0,8,9,24,24) 222 223 # Priest 224 Button = InitOptionButton(Window, 'Priest_Spells') 225 if bg1: 226 Button.SetSprites ("GUILSOP", 0,10,11,25,10) 227 if iwd1: 228 Button.SetSprites ("GUILSOP", 0,10,11,25,25) 229 230 # Options 231 Button = InitOptionButton(Window, 'Options') 232 if bg1: 233 Button.SetSprites ("GUILSOP", 0,12,13,26,12) 234 if iwd1: 235 Button.SetSprites ("GUILSOP", 0,12,13,26,26) 236 237 238 # pause button 239 if Gears: 240 # Pendulum, gears, sun/moon dial (time) 241 # FIXME: display all animations: CPEN, CGEAR, CDIAL 242 if how: # how doesn't have this in the right place 243 pos = Window.GetFrame()["h"] - 71 244 Window.CreateButton (OptionControl['Time'], 0, pos, 64, 71) 245 246 Button = Window.GetControl (OptionControl['Time']) 247 if bg2: 248 Label = Button.CreateLabel (0x10000009, "NORMAL", "", IE_FONT_SINGLE_LINE) 249 Label.SetAnimation ("CPEN") 250 251 Button.SetAnimation ("CGEAR") 252 Button.SetState (IE_GUI_BUTTON_ENABLED) 253 Button.SetFlags (IE_GUI_BUTTON_PICTURE|IE_GUI_BUTTON_ANIMATED|IE_GUI_BUTTON_NORMAL, OP_SET) 254 Button.SetEvent(IE_GUI_BUTTON_ON_PRESS, GUICommon.GearsClicked) 255 if iwd2: 256 Button.SetState (IE_GUI_BUTTON_LOCKED) #no button depression, timer is an inset stone planet 257 rb = OptionControl['Rest'] 258 else: 259 rb = 11 260 UpdateClock () 261 else: 262 rb = OptionControl['Rest'] 263 if iwd2: 264 UpdateClock () 265 266 # BG1 doesn't have a rest button on the main window, so this creates one 267 # from what would be the multiplayer arbitration control 268 if bg1: 269 Button = Window.GetControl (8) 270 Button.SetSprites("GUIRSBUT", 0,0,1,0,0) 271 Button.SetStatus (IE_GUI_BUTTON_ENABLED) 272 Button.SetSize(55,37) 273 Button.SetPos(4,359) 274 Button.SetFlags (IE_GUI_BUTTON_PICTURE, OP_SET) 275 rb = 8 276 277 # Rest 278 Button = Window.GetControl (rb) 279 if Button: 280 Button.SetTooltip (OptionTip['Rest']) 281 Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, RestPress) 282 283 return 284 285def OnLockViewPress (): 286 OptionsWindow = GemRB.GetView("OPTWIN") 287 Button = OptionsWindow.GetControl (0) 288 GemRB.GameControlSetScreenFlags (SF_CENTERONACTOR | SF_ALWAYSCENTER, OP_XOR) 289 290 # no way to get the screen flags 291 if OnLockViewPress.counter % 2: 292 # unlock 293 Button.SetTooltip (41648) 294 Button.SetState(IE_GUI_BUTTON_SELECTED)#dont ask 295 else: 296 # lock 297 Button.SetTooltip (41647) 298 Button.SetState(IE_GUI_BUTTON_NORMAL) 299 OnLockViewPress.counter += 1 300 301 return 302 303OnLockViewPress.counter = 1 304 305def PortraitPress (): 306 """Toggles the portraits pane """ 307 PP = GemRB.GetGUIFlags () & GS_PORTRAITPANE 308 if PP: 309 GemRB.GameSetScreenFlags (GS_PORTRAITPANE, OP_NAND) 310 else: 311 GemRB.GameSetScreenFlags (GS_PORTRAITPANE, OP_OR) 312 return 313 314def AIPress (toggle=1): 315 """Toggles the party AI or refreshes the button state if toggle = 0""" 316 317 if GameCheck.IsPST() or GameCheck.IsIWD2(): 318 OptionsWindow = GemRB.GetView("OPTWIN") 319 Button = OptionsWindow.GetControl (OptionControl['Toggle_AI']) 320 else: 321 PortraitWindow = GemRB.GetView("PORTWIN") 322 Button = PortraitWindow.GetControl (OptionControl['Toggle_AI']) 323 324 if toggle: 325 GemRB.GameSetScreenFlags (GS_PARTYAI, OP_XOR) 326 327 AI = GemRB.GetGUIFlags () & GS_PARTYAI 328 if AI: 329 GemRB.SetVar ("AI", 0) 330 Button.SetTooltip (AITip['Deactivate']) 331 Button.SetState(IE_GUI_BUTTON_SELECTED) 332 else: 333 GemRB.SetVar ("AI", GS_PARTYAI) 334 Button.SetTooltip (AITip['Enable']) 335 Button.SetState (IE_GUI_BUTTON_ENABLED) 336 337 if GameCheck.IsPST (): 338 GemRB.SetGlobal ("partyScriptsActive", "GLOBALS", AI) 339 340 #force redrawing, in case a hotkey triggered this function 341 Button.SetVarAssoc ("AI", GS_PARTYAI) 342 return 343 344## The following four functions are for the action bar 345## they are currently unused in pst 346def EmptyControls (): 347 if GameCheck.IsPST(): 348 return 349 Selected = GemRB.GetSelectedSize() 350 if Selected==1: 351 pc = GemRB.GameGetFirstSelectedActor () 352 #init spell list 353 GemRB.SpellCast (pc, -1, 0) 354 355 GemRB.SetVar ("ActionLevel", UAW_STANDARD) 356 if not CurrentWindow: 357 return # current case in our game demo (on right-click) 358 for i in range (12): 359 Button = CurrentWindow.GetControl (i+ActionBarControlOffset) 360 Button.SetVisible (False) 361 return 362 363def SelectFormationPreset (): 364 """Choose the default formation.""" 365 GemRB.GameSetFormation (GemRB.GetVar ("Value"), GemRB.GetVar ("Formation") ) 366 GroupControls () 367 return 368 369def SetupFormation (): 370 """Opens the formation selection section.""" 371 for i in range (12): 372 Button = CurrentWindow.GetControl (i+ActionBarControlOffset) 373 Button.SetFlags (IE_GUI_BUTTON_NORMAL, OP_SET) 374 Button.SetSprites ("GUIBTBUT",0,0,1,2,3) 375 Button.SetBAM ("FORM%x"%i,0,0,-1) 376 Button.SetVarAssoc ("Value", i) 377 Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, SelectFormationPreset) 378 Button.SetState (IE_GUI_BUTTON_UNPRESSED) 379 return 380 381def GroupControls (): 382 """Sections that control group actions.""" 383 GemRB.SetVar ("ActionLevel", UAW_STANDARD) 384 Button = CurrentWindow.GetControl (ActionBarControlOffset) 385 if GameCheck.IsBG2(): 386 Button.SetActionIcon (globals(), 7, 1) #talk icon 387 else: 388 Button.SetActionIcon (globals(), 14, 1)#guard icon 389 Button = CurrentWindow.GetControl (1+ActionBarControlOffset) 390 Button.SetActionIcon (globals(), 15, 2) 391 Button = CurrentWindow.GetControl (2+ActionBarControlOffset) 392 Button.SetActionIcon (globals(), 21, 3) 393 Button = CurrentWindow.GetControl (3+ActionBarControlOffset) 394 Button.SetActionIcon (globals(), -1, 4) 395 Button = CurrentWindow.GetControl (4+ActionBarControlOffset) 396 Button.SetActionIcon (globals(), -1, 5) 397 Button = CurrentWindow.GetControl (5+ActionBarControlOffset) 398 Button.SetActionIcon (globals(), -1, 6) 399 Button = CurrentWindow.GetControl (6+ActionBarControlOffset) 400 Button.SetActionIcon (globals(), -1, 7) 401 GemRB.SetVar ("Formation", GemRB.GameGetFormation ()) 402 for i in range (5): 403 Button = CurrentWindow.GetControl (7+ActionBarControlOffset+i) 404 Button.SetState (IE_GUI_BUTTON_ENABLED) 405 idx = GemRB.GameGetFormation (i) 406 Button.SetFlags (IE_GUI_BUTTON_RADIOBUTTON|IE_GUI_BUTTON_NORMAL, OP_SET) 407 # kill the previous sprites or they show through 408 Button.SetSprites ("GUIBTBUT",0,0,1,2,3) 409 Button.SetBAM ("FORM%x"%idx,0,0,-1) 410 Button.SetVarAssoc ("Formation", i) 411 Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, GUICommon.SelectFormation) 412 Button.SetEvent (IE_GUI_BUTTON_ON_RIGHT_PRESS, SetupFormation) 413 Button.SetTooltip (4935) 414 # 0x90 = F1 key 415 Button.SetHotKey (chr(7+i+0x90), 0, True) 416 return 417 418def OpenActionsWindowControls (Window): 419 # 1280 and higher don't have this control 420 if not Window.GetControl (62): 421 UpdateActionsWindow () 422 return 423 # Gears (time) when options pane is down 424 Button = Window.GetControl (62) 425 Label = Button.CreateLabel (0x1000003e, "NORMAL", "", IE_FONT_SINGLE_LINE) 426 427 # FIXME: display all animations 428 Label.SetAnimation ("CPEN") 429 Button.SetAnimation ("CGEAR") 430 Button.SetState (IE_GUI_BUTTON_ENABLED) 431 Button.SetFlags (IE_GUI_BUTTON_PICTURE|IE_GUI_BUTTON_ANIMATED|IE_GUI_BUTTON_NORMAL, OP_SET) 432 Button.SetEvent(IE_GUI_BUTTON_ON_PRESS, GUICommon.GearsClicked) 433 UpdateActionsWindow () 434 return 435 436##not used in pst - not sure any items have abilities, but it is worth making a note to find out 437def SelectItemAbility(): 438 pc = GemRB.GameGetFirstSelectedActor () 439 slot = GemRB.GetVar ("Slot") 440 ability = GemRB.GetVar ("Ability") 441 GemRB.SetupQuickSlot (pc, 0, slot, ability) 442 GemRB.SetVar ("ActionLevel", UAW_STANDARD) 443 return 444 445#in pst only nordom has bolts and they show on the same floatmenu as quickweapons, so needs work here 446def SelectQuiverSlot(): 447 pc = GemRB.GameGetFirstSelectedActor () 448 slot = GemRB.GetVar ("Slot") 449 slot_item = GemRB.GetSlotItem (pc, slot) 450 # HACK: implement SetEquippedAmmunition instead? 451 if not GemRB.IsDraggingItem (): 452 item = GemRB.GetItem (slot_item["ItemResRef"]) 453 GemRB.DragItem (pc, slot, item["ItemIcon"]) #, 0, 0) 454 GemRB.DropDraggedItem (pc, slot) 455 GemRB.SetVar ("ActionLevel", UAW_STANDARD) 456 return 457 458#this doubles up as an ammo selector (not yet used in pst) 459def SetupItemAbilities(pc, slot, only): 460 slot_item = GemRB.GetSlotItem(pc, slot) 461 if not slot_item: 462 # CHIV: Could configure empty quickslots from the game screen ala spells heres 463 return 464 465 item = GemRB.GetItem (slot_item["ItemResRef"]) 466 Tips = item["Tooltips"] 467 Locations = item["Locations"] 468 469 # clear buttons here 470 EmptyControls() 471 472 # check A: whether ranged weapon and B: whether to bother at all 473 ammotype = 0 474 if item["Type"] == CommonTables.ItemType.GetRowIndex ("BOW"): 475 ammotype = CommonTables.ItemType.GetRowIndex ("ARROW") 476 elif item["Type"] == CommonTables.ItemType.GetRowIndex ("XBOW"): 477 ammotype = CommonTables.ItemType.GetRowIndex ("BOLT") 478 elif item["Type"] == CommonTables.ItemType.GetRowIndex ("SLING"): 479 ammotype = CommonTables.ItemType.GetRowIndex ("BULLET") 480 481 ammoSlotCount = 0 482 if ammotype: 483 ammoslots = GemRB.GetSlots(pc, SLOT_QUIVER, 1) 484 currentammo = GemRB.GetEquippedAmmunition (pc) 485 currentbutton = None 486 for i in range (12): 487 Button = CurrentWindow.GetControl (i+ActionBarControlOffset) 488 if i < len(ammoslots): 489 ammoslot = GemRB.GetSlotItem (pc, ammoslots[i]) 490 st = GemRB.GetSlotType (ammoslots[i]) 491 ammoitem = GemRB.GetItem (ammoslot['ItemResRef']) # needed to show the ammo count 492 Tips = ammoitem["Tooltips"] 493 # if this item is valid ammo and was really found in a quiver slot 494 if ammoitem['Type'] == ammotype and st["Type"] == SLOT_QUIVER: 495 ammoSlotCount += 1 496 Button.SetFlags (IE_GUI_BUTTON_RADIOBUTTON|IE_GUI_BUTTON_ALIGN_BOTTOM|IE_GUI_BUTTON_ALIGN_RIGHT, OP_SET) 497 Button.SetSprites ("GUIBTBUT", 0, 0,1,3,5) 498 Button.SetItemIcon (ammoslot['ItemResRef']) 499 Button.SetText (str(ammoslot["Usages0"])) 500 Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, SelectQuiverSlot) 501 Button.SetEvent (IE_GUI_BUTTON_ON_RIGHT_PRESS, SelectQuiverSlot) 502 Button.SetVarAssoc ("Slot", ammoslots[i]) 503 if Tips[0] != -1: 504 Button.SetTooltip (Tips[0]) 505 if currentammo == ammoslots[i]: 506 currentbutton = Button 507 508 if currentbutton: 509 currentbutton.SetState (IE_GUI_BUTTON_SELECTED) 510 511 # skip when there is only one choice 512 if ammoSlotCount == 1: 513 ammoSlotCount = 0 514 515 # reset back to the main action bar if there are no extra headers or quivers 516 reset = not ammoSlotCount 517 518 # check for item abilities and skip irrelevant headers 519 # for quick weapons only show weapon headers 520 # for quick items only show the opposite 521 # for scrolls only show the first (second header is for learning) 522 # So depending on the context Staff of Magi will have none or 2 523 if item["Type"] == CommonTables.ItemType.GetRowIndex ("SCROLL"): 524 Tips = () 525 526 # skip launchers - handled above 527 # gesen bow (bg2:bow19) has just a projectile header (not bow) for its special attack 528 # TODO: we should append it to the list of ammo as a usability improvement 529 if only == UAW_QWEAPONS and ammoSlotCount > 1: 530 Tips = () 531 532 if len(Tips) > 0: 533 reset = False 534 rmax = min(len(Tips), 12-ammoSlotCount) 535 536 # for mixed items, only show headers if there is more than one appropriate one 537 weaps = sum([i == ITEM_LOC_WEAPON for i in Locations]) 538 if only == UAW_QWEAPONS and weaps == 1 and ammoSlotCount <= 1: 539 rmax = 0 540 reset = True 541 abils = sum([i == ITEM_LOC_EQUIPMENT for i in Locations]) 542 if only == UAW_QITEMS and abils == 1: 543 rmax = 0 544 reset = True 545 546 for i in range (rmax): 547 if only == UAW_QITEMS: 548 if Locations[i] != ITEM_LOC_EQUIPMENT: 549 continue 550 elif only == UAW_QWEAPONS: 551 if Locations[i] != ITEM_LOC_WEAPON: 552 continue 553 Button = CurrentWindow.GetControl (i+ActionBarControlOffset+ammoSlotCount) 554 Button.SetFlags (IE_GUI_BUTTON_RADIOBUTTON|IE_GUI_BUTTON_NORMAL, OP_SET) 555 Button.SetSprites ("GUIBTBUT", 0, 0,1,2,5) 556 Button.SetItemIcon (slot_item['ItemResRef'], i+6) 557 Button.SetText ("") 558 Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, SelectItemAbility) 559 Button.SetEvent (IE_GUI_BUTTON_ON_RIGHT_PRESS, SelectItemAbility) 560 Button.SetVarAssoc ("Ability", i) 561 Button.SetState (IE_GUI_BUTTON_ENABLED) 562 if Tips[i] != -1: 563 Button.SetTooltip ("F%d - %s" %(i, GemRB.GetString (Tips[i]))) 564 565 if reset: 566 GemRB.SetVar ("ActionLevel", UAW_STANDARD) 567 UpdateActionsWindow () 568 return 569 570# iwd2 spell book/class selection 571def SetupBookSelection (): 572 pc = GemRB.GameGetFirstSelectedActor () 573 574 # get all the books that still have non-depleted memorisations 575 # we need this list, so we can avoid holes in the action bar 576 usableBooks = [] 577 for i in range (IE_IWD2_SPELL_SONG): 578 bookClass = i 579 if i == IE_IWD2_SPELL_INNATE: # shape stat comes later (8 vs 10) 580 bookClass = IE_IWD2_SPELL_SHAPE 581 582 enabled = False 583 if i <= (IE_IWD2_SPELL_DOMAIN + 1): # booktypes up to and including domain + shapes 584 spellCount = len(Spellbook.GetUsableMemorizedSpells (pc, bookClass)) 585 enabled = spellCount > 0 586 if enabled: 587 usableBooks.append(i) 588 589 # if we have only one or only cleric+domain, skip to the spells 590 bookCount = len(usableBooks) 591 if bookCount == 1 or (bookCount == 2 and IE_IWD2_SPELL_CLERIC in usableBooks): 592 GemRB.SetVar ("ActionLevel", UAW_SPELLS_DIRECT) 593 UpdateActionsWindow () 594 return 595 596 for i in range (12): 597 Button = CurrentWindow.GetControl (i+ActionBarControlOffset) 598 if i >= len(usableBooks): 599 Button.SetActionIcon (globals(), -1) 600 continue 601 Button.SetActionIcon (globals(), 40+usableBooks[i]) 602 return 603 604#you can change this for custom skills, this is the original engine 605skillbar=(ACT_STEALTH, ACT_SEARCH, ACT_THIEVING, ACT_WILDERNESS, ACT_TAMING, 100, 100, 100, 100, 100, 100, 100) 606def SetupSkillSelection (): 607 pc = GemRB.GameGetFirstSelectedActor () 608 CurrentWindow.SetupControls( globals(), pc, ActionBarControlOffset, skillbar) 609 return 610 611def UpdateActionsWindow (): 612 """Redraws the actions section of the window.""" 613 global CurrentWindow 614 global level, TopIndex 615 616 PortraitWindow = GemRB.GetView("PORTWIN") 617 ActionsWindow = GemRB.GetView("ACTWIN") 618 619 if not GameCheck.IsIWD2(): 620 CurrentWindow = ActionsWindow 621 ActionBarControlOffset = 0 622 UpdateClock () 623 else: 624 CurrentWindow = PortraitWindow 625 ActionBarControlOffset = 6 # set it here too, since we get called before menu setup 626 627 if GameCheck.IsPST(): 628 return 629 630 if CurrentWindow == None: 631 return 632 633 Selected = GemRB.GetSelectedSize() 634 635 #setting up the disabled button overlay (using the second border slot) 636 for i in range (12): 637 Button = CurrentWindow.GetControl (i+ActionBarControlOffset) 638 if GameCheck.IsBG1(): 639 color = {'r' : 0, 'g' : 254, 'b' :0, 'a' : 255} 640 Button.SetBorder (0, color, 0, 0, Button.GetInsetFrame(6,6,4,4)) 641 642 color = {'r' : 50, 'g' : 30, 'b' :10, 'a' : 120} 643 Button.SetBorder (1, color, 0, 1) 644 Button.SetFont ("NUMBER") 645 Button.SetText ("") 646 Button.SetTooltip("") 647 648 if Selected == 0: 649 EmptyControls () 650 return 651 if Selected > 1: 652 GroupControls () 653 return 654 655 #we are sure there is only one actor selected 656 pc = GemRB.GameGetFirstSelectedActor () 657 658 level = GemRB.GetVar ("ActionLevel") 659 TopIndex = GemRB.GetVar ("TopIndex") 660 if level == UAW_STANDARD: 661 #this is based on class 662 CurrentWindow.SetupControls (globals(), pc, ActionBarControlOffset) 663 elif level == UAW_EQUIPMENT: 664 CurrentWindow.SetupEquipmentIcons(globals(), pc, TopIndex, ActionBarControlOffset) 665 elif level == UAW_SPELLS or level == UAW_SPELLS_DIRECT: #spells 666 667 if GameCheck.IsIWD2(): 668 if level == UAW_SPELLS: 669 # set up book selection if appropriate 670 SetupBookSelection () 671 return 672 # otherwise just throw everything in a single list 673 # everything but innates, songs and shapes 674 spelltype = (1<<IE_IWD2_SPELL_INNATE) - 1 675 else: 676 spelltype = (1<<IE_SPELL_TYPE_PRIEST) + (1<<IE_SPELL_TYPE_WIZARD) 677 GemRB.SetVar ("Type", spelltype) 678 Spellbook.SetupSpellIcons(CurrentWindow, spelltype, TopIndex, ActionBarControlOffset) 679 elif level == UAW_INNATES: #innates 680 if GameCheck.IsIWD2(): 681 spelltype = (1<<IE_IWD2_SPELL_INNATE) + (1<<IE_IWD2_SPELL_SHAPE) 682 else: 683 spelltype = 1<<IE_SPELL_TYPE_INNATE 684 GemRB.SetVar ("Type", spelltype) 685 Spellbook.SetupSpellIcons(CurrentWindow, spelltype, TopIndex, ActionBarControlOffset) 686 elif level == UAW_QWEAPONS or level == UAW_QITEMS: #quick weapon or quick item ability selection 687 SetupItemAbilities(pc, GemRB.GetVar("Slot"), level) 688 elif level == UAW_ALLMAGE: #all known mage spells 689 GemRB.SetVar ("Type", -1) 690 Spellbook.SetupSpellIcons(CurrentWindow, -1, TopIndex, ActionBarControlOffset) 691 elif level == UAW_SKILLS: # iwd2 skills 692 SetupSkillSelection() 693 elif level == UAW_QSPELLS: # quickspells, but with innates too 694 if GameCheck.IsIWD2(): 695 spelltype = (1<<IE_IWD2_SPELL_INNATE) - 1 696 spelltype += (1<<IE_IWD2_SPELL_INNATE) + (1<<IE_IWD2_SPELL_SHAPE) 697 else: 698 spelltype = (1<<IE_SPELL_TYPE_PRIEST) + (1<<IE_SPELL_TYPE_WIZARD) + (1<<IE_SPELL_TYPE_INNATE) 699 GemRB.SetVar ("Type", spelltype) 700 Spellbook.SetupSpellIcons(CurrentWindow, spelltype, TopIndex, ActionBarControlOffset) 701 elif level == UAW_QSHAPES: # shapes selection 702 spelltype = 1<<IE_IWD2_SPELL_SHAPE 703 GemRB.SetVar ("Type", spelltype) 704 Spellbook.SetupSpellIcons(CurrentWindow, spelltype, TopIndex, ActionBarControlOffset) 705 elif level == UAW_QSONGS: # songs selection 706 spelltype = 1<<IE_IWD2_SPELL_SONG 707 GemRB.SetVar ("Type", spelltype) 708 Spellbook.SetupSpellIcons(CurrentWindow, spelltype, TopIndex, ActionBarControlOffset) 709 elif level == UAW_BOOK: # spellbook selection 710 spelltype = GemRB.GetVar ("Type") 711 Spellbook.SetupSpellIcons(CurrentWindow, spelltype, TopIndex, ActionBarControlOffset) 712 elif level == UAW_2DASPELLS: # spells from a 2da (fx_select_spell) 713 if GameCheck.IsIWD2(): 714 # everything but innates, songs and shapes 715 spelltype = (1<<IE_IWD2_SPELL_INNATE) - 1 716 else: 717 spelltype = (1<<IE_SPELL_TYPE_PRIEST) + (1<<IE_SPELL_TYPE_WIZARD) 718 GemRB.SetVar ("Type", spelltype) 719 Spellbook.SetupSpellIcons (CurrentWindow, spelltype, TopIndex, ActionBarControlOffset) 720 else: 721 print("Invalid action level:", level) 722 GemRB.SetVar ("ActionLevel", UAW_STANDARD) 723 return 724 725def ActionQWeaponPressed (which): 726 """Selects the given quickslot weapon if possible.""" 727 728 pc = GemRB.GameGetFirstSelectedActor () 729 qs = GemRB.GetEquippedQuickSlot (pc, 1) 730 731 #38 is the magic slot 732 if ((qs==which) or (qs==38)) and GemRB.GameControlGetTargetMode() != TARGET_MODE_ATTACK: 733 GemRB.GameControlSetTargetMode (TARGET_MODE_ATTACK, GA_NO_DEAD|GA_NO_SELF|GA_NO_HIDDEN) 734 else: 735 GemRB.GameControlSetTargetMode (TARGET_MODE_NONE) 736 GemRB.SetEquippedQuickSlot (pc, which, -1) 737 738 CurrentWindow.SetupControls (globals(), pc, ActionBarControlOffset) 739 UpdateActionsWindow () 740 return 741 742# TODO: implement full weapon set switching instead 743def ActionQWeaponRightPressed (action): 744 """Selects the used ability of the quick weapon.""" 745 GemRB.SetVar ("Slot", action) 746 GemRB.SetVar ("ActionLevel", UAW_QWEAPONS) 747 UpdateActionsWindow () 748 return 749 750############################################### 751# quick icons for spells, innates, songs, shapes 752 753def ActionQSpellPressed (which): 754 pc = GemRB.GameGetFirstSelectedActor () 755 756 GemRB.SpellCast (pc, -2, which) 757 UpdateActionsWindow () 758 return 759 760def ActionQSpellRightPressed (which): 761 GemRB.SetVar ("QSpell", which) 762 GemRB.SetVar ("TopIndex", 0) 763 GemRB.SetVar ("ActionLevel", UAW_QSPELLS) 764 UpdateActionsWindow () 765 return 766 767suf = ["", "Right"] 768# this function is used to generate various action bar actions 769# that should be available in 9 slots (iwd2) 770def GenerateButtonActions(num, name, g, right=0, offset=0): 771 dec = "def Action" + name + str(num+1) + suf[right] + "Pressed():\n" 772 dec += "\tAction" + name + suf[right] + "Pressed(" + str(num+offset) + ")" 773 exec(dec, g) # pass on the same global dict, so we remain in the top scope 774 775for i in range(9): 776 GenerateButtonActions(i, "QSpec", globals(), 0) 777 GenerateButtonActions(i, "QSpec", globals(), 1) 778 GenerateButtonActions(i, "QSpell", globals(), 0) 779 GenerateButtonActions(i, "QSpell", globals(), 1) 780 GenerateButtonActions(i, "QShape", globals(), 0) 781 GenerateButtonActions(i, "QShape", globals(), 1) 782 GenerateButtonActions(i, "QSong", globals(), 0) 783 GenerateButtonActions(i, "QSong", globals(), 1) 784for i in range(4): 785 GenerateButtonActions(i, "QWeapon", globals(), 0) 786 GenerateButtonActions(i, "QWeapon", globals(), 1, 10) 787 788def ActionQSpecPressed (which): 789 ActionQSpellPressed (which) 790 791def ActionQSpecRightPressed (which): 792 GemRB.SetVar ("QSpell", which) 793 GemRB.SetVar ("TopIndex", 0) 794 GemRB.SetVar ("ActionLevel", UAW_INNATES) 795 UpdateActionsWindow () 796 797def ActionQShapePressed (which): 798 ActionQSpellPressed (which) 799 800def ActionQShapeRightPressed (which): 801 GemRB.SetVar ("QSpell", which) 802 GemRB.SetVar ("TopIndex", 0) 803 GemRB.SetVar ("ActionLevel", UAW_QSHAPES) 804 UpdateActionsWindow () 805 806def ActionQSongPressed (which): 807 SelectBardSong (which) # TODO: verify parameter once we have actionbar customisation 808 ActionBardSongPressed () 809 810def ActionQSongRightPressed (which): 811 GemRB.SetVar ("QSpell", which) 812 GemRB.SetVar ("TopIndex", 0) 813 GemRB.SetVar ("ActionLevel", UAW_QSONGS) 814 UpdateActionsWindow () 815 816# can't pass the globals dictionary from another module 817def SetActionIconWorkaround(Button, action, function): 818 Button.SetActionIcon (globals(), action, function) 819 820#no check needed because the button wouldn't be drawn if illegal 821def ActionLeftPressed (): 822 """Scrolls the actions window left. 823 824 Used primarily for spell selection.""" 825 826 TopIndex = GemRB.GetVar ("TopIndex") 827 if TopIndex>10: 828 TopIndex -= 10 829 else: 830 TopIndex = 0 831 GemRB.SetVar ("TopIndex", TopIndex) 832 UpdateActionsWindow () 833 return 834 835#no check needed because the button wouldn't be drawn if illegal 836def ActionRightPressed (): 837 """Scrolls the action window right. 838 839 Used primarily for spell selection.""" 840 841 pc = GemRB.GameGetFirstSelectedActor () 842 TopIndex = GemRB.GetVar ("TopIndex") 843 Type = GemRB.GetVar ("Type") 844 print("Type:", Type) 845 #Type is a bitfield if there is no level given 846 #This is to make sure cleric/mages get all spells listed 847 if GemRB.GetVar ("ActionLevel") == UAW_ALLMAGE: 848 if Type == 3: 849 Max = len(Spellbook.GetKnownSpells (pc, IE_SPELL_TYPE_PRIEST) + Spellbook.GetKnownSpells (pc, IE_SPELL_TYPE_WIZARD)) 850 else: 851 Max = GemRB.GetKnownSpellsCount (pc, Type, -1) # this can handle only one type at a time 852 else: 853 Max = GemRB.GetMemorizedSpellsCount(pc, Type, -1, 1) 854 print("Max:", Max) 855 TopIndex += 10 856 if TopIndex > Max - 10: 857 if Max>10: 858 if TopIndex > Max: 859 TopIndex = Max - 10 860 else: 861 TopIndex = 0 862 GemRB.SetVar ("TopIndex", TopIndex) 863 UpdateActionsWindow () 864 return 865 866def ActionMeleePressed (): 867 """ switches to the most damaging melee weapon""" 868 #get the party Index 869 pc = GemRB.GameGetFirstSelectedPC () 870 GemRB.ExecuteString("EquipMostDamagingMelee()", pc) 871 return 872 873def ActionRangePressed (): 874 """ switches to the most damaging ranged weapon""" 875 #get the party Index 876 pc = GemRB.GameGetFirstSelectedPC () 877 GemRB.ExecuteString("EquipRanged()", pc) 878 return 879 880def ActionShapeChangePressed (): 881 GemRB.SetVar ("ActionLevel", UAW_QSHAPES) 882 GemRB.SetVar ("TopIndex", 0) 883 UpdateActionsWindow () 884 return 885 886def SelectBardSong (which): 887 pc = GemRB.GameGetFirstSelectedActor () 888 songs = Spellbook.GetKnownSpells (pc, IE_IWD2_SPELL_SONG) 889 # "which" is a mashup of the spell index with it's type 890 idx = which % ((1<<IE_IWD2_SPELL_SHAPE)*100) 891 qsong = songs[idx]['SpellResRef'] 892 # the effect needs to be set each tick, so we use FX_DURATION_INSTANT_PERMANENT==1 timing mode 893 # GemRB.SetModalState can also set the spell, but it wouldn't persist 894 GemRB.ApplyEffect (pc, 'ChangeBardSong', 0, idx, qsong, "", "", "", 1) 895 896def ActionBardSongRightPressed (): 897 """Selects a bardsong.""" 898 GemRB.SetVar ("ActionLevel", UAW_QSONGS) 899 GemRB.SetVar ("TopIndex", 0) 900 UpdateActionsWindow () 901 return 902 903def ActionBardSongPressed (): 904 """Toggles the battle song.""" 905 906 #get the global ID 907 pc = GemRB.GameGetFirstSelectedActor () 908 GemRB.SetModalState (pc, MS_BATTLESONG) 909 GemRB.PlaySound ("act_01") 910 GemRB.SetVar ("ActionLevel", UAW_STANDARD) 911 UpdateActionsWindow () 912 return 913 914def ActionSearchPressed (): 915 """Toggles detect traps.""" 916 917 #get the global ID 918 pc = GemRB.GameGetFirstSelectedActor () 919 GemRB.SetModalState (pc, MS_DETECTTRAPS) 920 GemRB.SetVar ("ActionLevel", UAW_STANDARD) 921 UpdateActionsWindow () 922 return 923 924def ActionStealthPressed (): 925 """Toggles stealth.""" 926 pc = GemRB.GameGetFirstSelectedActor () 927 GemRB.SetModalState (pc, MS_STEALTH) 928 GemRB.PlaySound ("act_07", CHAN_HITS) 929 GemRB.SetVar ("ActionLevel", UAW_STANDARD) 930 UpdateActionsWindow () 931 return 932 933def ActionTurnPressed (): 934 """Toggles turn undead.""" 935 pc = GemRB.GameGetFirstSelectedActor () 936 GemRB.SetModalState (pc, MS_TURNUNDEAD) 937 GemRB.PlaySound ("act_06") 938 GemRB.SetVar ("ActionLevel", UAW_STANDARD) 939 UpdateActionsWindow () 940 return 941 942def ActionTamingPressed (): 943 pc = GemRB.GameGetFirstSelectedActor () 944 GemRB.SpellCast (pc, -3, 0, "spin108") 945 GemRB.SetVar ("ActionLevel", UAW_STANDARD) 946 UpdateActionsWindow () 947 return 948 949def ActionWildernessPressed (): 950 pc = GemRB.GameGetFirstSelectedActor () 951 GemRB.ApplyEffect (pc, "Reveal:Tracks", 0, 0) 952 GemRB.SetVar ("ActionLevel", UAW_STANDARD) 953 UpdateActionsWindow () 954 return 955 956def ActionUseItemPressed (): 957 GemRB.SetVar ("TopIndex", 0) 958 GemRB.SetVar ("ActionLevel", UAW_EQUIPMENT) 959 UpdateActionsWindow () 960 return 961 962def ActionCastPressed (): 963 """Opens the spell choice scrollbar.""" 964 GemRB.SetVar ("QSpell", -1) 965 GemRB.SetVar ("TopIndex", 0) 966 GemRB.SetVar ("ActionLevel", UAW_SPELLS) 967 UpdateActionsWindow () 968 return 969 970def ActionQItemPressed (action): 971 """Uses the given quick item.""" 972 pc = GemRB.GameGetFirstSelectedActor () 973 #quick slot 974 GemRB.UseItem (pc, -2, action, -1) 975 return 976 977def ActionQItem1Pressed (): 978 ActionQItemPressed (ACT_QSLOT1) 979 return 980 981def ActionQItem2Pressed (): 982 ActionQItemPressed (ACT_QSLOT2) 983 return 984 985def ActionQItem3Pressed (): 986 ActionQItemPressed (ACT_QSLOT3) 987 return 988 989def ActionQItem4Pressed (): 990 ActionQItemPressed (ACT_QSLOT4) 991 return 992 993def ActionQItem5Pressed (): 994 ActionQItemPressed (ACT_QSLOT5) 995 return 996 997def ActionQItemRightPressed (action): 998 """Selects the used ability of the quick item.""" 999 GemRB.SetVar ("Slot", action) 1000 GemRB.SetVar ("ActionLevel", UAW_QITEMS) 1001 UpdateActionsWindow () 1002 return 1003 1004def ActionQItem1RightPressed (): 1005 ActionQItemRightPressed (19) 1006 1007def ActionQItem2RightPressed (): 1008 ActionQItemRightPressed (20) 1009 1010def ActionQItem3RightPressed (): 1011 ActionQItemRightPressed (21) 1012 1013def ActionQItem4RightPressed (): 1014 ActionQItemRightPressed (22) 1015 1016def ActionQItem5RightPressed (): 1017 ActionQItemRightPressed (23) 1018 1019def ActionInnatePressed (): 1020 """Opens the innate spell scrollbar.""" 1021 GemRB.SetVar ("QSpell", -1) 1022 GemRB.SetVar ("TopIndex", 0) 1023 GemRB.SetVar ("ActionLevel", UAW_INNATES) 1024 UpdateActionsWindow () 1025 return 1026 1027def ActionSkillsPressed (): 1028 GemRB.SetVar ("TopIndex", 0) 1029 GemRB.SetVar ("ActionLevel", UAW_SKILLS) 1030 UpdateActionsWindow () 1031 return 1032 1033def TypeSpellPressed (spelltype): 1034 GemRB.SetVar ("Type", 1 << spelltype) 1035 GemRB.SetVar ("ActionLevel", UAW_BOOK) 1036 UpdateActionsWindow () 1037 return 1038 1039def ActionBardSpellPressed (): 1040 TypeSpellPressed(IE_IWD2_SPELL_BARD) 1041 return 1042 1043def ActionClericSpellPressed (): 1044 TypeSpellPressed(IE_IWD2_SPELL_CLERIC) 1045 return 1046 1047def ActionDruidSpellPressed (): 1048 TypeSpellPressed(IE_IWD2_SPELL_DRUID) 1049 return 1050 1051def ActionPaladinSpellPressed (): 1052 TypeSpellPressed(IE_IWD2_SPELL_PALADIN) 1053 return 1054 1055def ActionRangerSpellPressed (): 1056 TypeSpellPressed(IE_IWD2_SPELL_RANGER) 1057 return 1058 1059def ActionSorcererSpellPressed (): 1060 TypeSpellPressed(IE_IWD2_SPELL_SORCERER) 1061 return 1062 1063def ActionWizardSpellPressed (): 1064 TypeSpellPressed(IE_IWD2_SPELL_WIZARD) 1065 return 1066 1067def ActionDomainSpellPressed (): 1068 TypeSpellPressed(IE_IWD2_SPELL_DOMAIN) 1069 return 1070 1071def ActionWildShapesPressed (): 1072 TypeSpellPressed(IE_IWD2_SPELL_SHAPE) 1073 return 1074 1075def SpellShiftPressed (): 1076 Spell = GemRB.GetVar ("Spell") # spellindex from spellbook jumbled with booktype 1077 Type = Spell // 1000 1078 SpellIndex = Spell % 1000 1079 1080 # try spontaneous casting 1081 pc = GemRB.GameGetFirstSelectedActor () 1082 ClassRowName = GUICommon.GetClassRowName (pc) 1083 SponCastTableName = CommonTables.ClassSkills.GetValue (ClassRowName, "SPONCAST") 1084 if SponCastTableName != "*": 1085 SponCastTable = GemRB.LoadTable (SponCastTableName, 1) 1086 if not SponCastTable: 1087 print("SpellShiftPressed: skipping, non-existent spontaneous casting table used! ResRef:", SponCastTableName) 1088 SpellPressed () 1089 return 1090 1091 # determine the column number (spell variety) depending on alignment 1092 CureOrHarm = GemRB.GetPlayerStat (pc, IE_ALIGNMENT) 1093 if CureOrHarm % 16 == 3: # evil 1094 CureOrHarm = 1 1095 else: 1096 CureOrHarm = 0 1097 1098 # get the unshifted booktype 1099 BaseType = 0 1100 tmp = Type 1101 while tmp > 1: 1102 tmp = tmp>>1 1103 BaseType += 1 1104 1105 # figure out the spell's details 1106 # TODO: find a simpler way 1107 Spell = None 1108 MemorisedSpells = Spellbook.GetSpellinfoSpells (pc, BaseType) 1109 for spell in MemorisedSpells: 1110 if spell['SpellIndex']%(255000) == SpellIndex: # 255 is the engine value of Type 1111 Spell = spell 1112 break 1113 1114 # rownames==level; col1: good+neutral; col2: evil resref 1115 Level = Spell['SpellLevel'] 1116 ReplacementSpell = SponCastTable.GetValue (Level-1, CureOrHarm).upper() 1117 if ReplacementSpell != Spell['SpellResRef'].upper(): 1118 SpellIndex = GemRB.PrepareSpontaneousCast (pc, Spell['SpellResRef'], Spell['BookType'], Level, ReplacementSpell) 1119 GemRB.SetVar ("Spell", SpellIndex+1000*Type) 1120 if GameCheck.IsIWD2(): 1121 GemRB.DisplayString (39742, ColorWhite, pc) # Spontaneous Casting 1122 1123 # proceed as if nothing happened 1124 SpellPressed () 1125 1126# This is the endpoint for spellcasting, finally calling SpellCast. This always happens at least 1127# twice though, the second time to reset the action bar (more if wild magic or subspell selection is involved). 1128# Spell and Type (spellbook type) are set during the spell bar construction/use, which is in turn 1129# affected by ActionLevel (see UpdateActionsWindow of this module). 1130# Keep in mind, that the core resets Type and/or ActionLevel in the case of subspells (fx_select_spell). 1131def SpellPressed (): 1132 """Prepares a spell to be cast.""" 1133 1134 pc = GemRB.GameGetFirstSelectedActor () 1135 1136 Spell = GemRB.GetVar ("Spell") 1137 Type = GemRB.GetVar ("Type") 1138 1139 if Type == 1<<IE_IWD2_SPELL_SONG: 1140 SelectBardSong (Spell) 1141 ActionBardSongPressed() 1142 return 1143 1144 GemRB.GameControlSetTargetMode (TARGET_MODE_CAST) 1145 if Type != -1: 1146 Type = Spell // 1000 1147 Spell = Spell % 1000 1148 slot = GemRB.GetVar ("QSpell") 1149 if slot>=0: 1150 #setup quickspell slot 1151 #if spell has no target, return 1152 #otherwise continue with casting 1153 Target = GemRB.SetupQuickSpell (pc, slot, Spell, Type) 1154 #sabotage the immediate casting of self targeting spells 1155 if Target == 5 or Target == 7: 1156 Type = -1 1157 GemRB.GameControlSetTargetMode (TARGET_MODE_NONE) 1158 1159 if Type==-1: 1160 GemRB.SetVar ("ActionLevel", UAW_STANDARD) 1161 GemRB.SetVar("Type", 0) 1162 GemRB.SpellCast (pc, Type, Spell) 1163 if GemRB.GetVar ("Type")!=-1: 1164 GemRB.SetVar ("ActionLevel", UAW_STANDARD) 1165 #init spell list 1166 GemRB.SpellCast (pc, -1, 0) 1167 GemRB.SetVar ("TopIndex", 0) 1168 UpdateActionsWindow () 1169 return 1170 1171def EquipmentPressed (): 1172 pc = GemRB.GameGetFirstSelectedActor () 1173 1174 GemRB.GameControlSetTargetMode (TARGET_MODE_CAST) 1175 Item = GemRB.GetVar ("Equipment") 1176 #equipment index 1177 GemRB.UseItem (pc, -1, Item, -1) 1178 GemRB.SetVar ("ActionLevel", UAW_STANDARD) 1179 UpdateActionsWindow () 1180 return 1181 1182###################### 1183 1184#End of features that need adding to pst 1185 1186###################### 1187 1188# NOTE: the following two features are only used in pst 1189# which=INVENTORY|STATS|FMENU 1190def GetActorPortrait (actor, which): 1191 #return GemRB.GetPlayerPortrait( actor, which) 1192 1193 # only the lowest byte is meaningful here (OneByteAnimID) 1194 anim_id = GemRB.GetPlayerStat (actor, IE_ANIMATION_ID) & 255 1195 row = "0x%02X" %anim_id 1196 1197 return CommonTables.Pdolls.GetValue (row, which) 1198 1199 1200def UpdateAnimation (): 1201 if not GemRB.HasResource ("ANIMS", RES_2DA, 1): 1202 # FIXME: make a simpler version for non-pst too 1203 # this is a callback from the core on EF_UPDATEANIM! 1204 return 1205 1206 pc = GemRB.GameGetSelectedPCSingle () 1207 1208 disguise = GemRB.GetGameVar ("APPEARANCE") 1209 if disguise == 2: #dustman 1210 animid = "DR" 1211 elif disguise == 1: #zombie 1212 animid = "ZO" 1213 else: 1214 slot = GemRB.GetEquippedQuickSlot (pc) 1215 item = GemRB.GetSlotItem (pc, slot ) 1216 animid = "" 1217 if item: 1218 item = GemRB.GetItem(item["ItemResRef"]) 1219 if item: 1220 animid = item["AnimationType"] 1221 1222 BioTable = GemRB.LoadTable ("BIOS") 1223 Specific = GemRB.GetPlayerStat (pc, IE_SPECIFIC) 1224 AvatarName = BioTable.GetRowName (Specific) 1225 AnimTable = GemRB.LoadTable ("ANIMS") 1226 if animid=="": 1227 animid="*" 1228 value = AnimTable.GetValue (animid, AvatarName) 1229 if value<0: 1230 return 1231 GemRB.SetPlayerStat (pc, IE_ANIMATION_ID, value) 1232 return 1233 1234# NOTE: the following 4 functions are only used in iwd2 1235def GetActorRaceTitle (actor): 1236 import IDLUCommon 1237 RaceIndex = IDLUCommon.GetRace (actor) 1238 RaceTitle = CommonTables.Races.GetValue (RaceIndex, 2) 1239 return RaceTitle 1240 1241# NOTE: this function is called with the primary classes 1242def GetKitIndex (actor, ClassIndex): 1243 Kit = GemRB.GetPlayerStat (actor, IE_KIT) 1244 1245 KitIndex = -1 1246 ClassName = CommonTables.Classes.GetRowName (ClassIndex) 1247 ClassID = CommonTables.Classes.GetValue (ClassName, "ID") 1248 # skip the primary classes 1249 # start at the first original kit - in iwd2 both classes and kits are in the same table 1250 KitOffset = CommonTables.Classes.FindValue ("CLASS", 7) 1251 for ci in range (KitOffset, CommonTables.Classes.GetRowCount ()): 1252 RowName = CommonTables.Classes.GetRowName (ci) 1253 BaseClass = CommonTables.Classes.GetValue (RowName, "CLASS") 1254 if BaseClass == ClassID and Kit & CommonTables.Classes.GetValue (RowName, "ID"): 1255 #FIXME: this will return the last kit only, check if proper multikit return values are needed 1256 KitIndex = ci 1257 1258 if KitIndex == -1: 1259 return 0 1260 1261 return KitIndex 1262 1263def GetActorClassTitle (actor, ClassIndex): 1264 ClassTitle = GemRB.GetPlayerStat (actor, IE_TITLE1) 1265 if ClassTitle: 1266 return ClassTitle 1267 1268 KitIndex = GetKitIndex (actor, ClassIndex) 1269 if KitIndex == 0: 1270 ClassName = CommonTables.Classes.GetRowName (ClassIndex) 1271 else: 1272 ClassName = CommonTables.Classes.GetRowName (KitIndex) 1273 ClassTitle = CommonTables.Classes.GetValue (ClassName, "NAME_REF") 1274 1275 if ClassTitle == "*": 1276 return 0 1277 return ClassTitle 1278 1279# overriding the one in GUICommon, since we use a different table and animations 1280def GetActorPaperDoll (actor): 1281 level = GemRB.GetPlayerStat (actor, IE_ARMOR_TYPE) 1282 return GemRB.GetAvatarsValue (actor, level) 1283 1284 1285SelectionChangeHandler = None 1286SelectionChangeMultiHandler = None ##relates to floatmenu 1287 1288def SetSelectionChangeHandler (handler): 1289 """Updates the selection handler.""" 1290 1291 global SelectionChangeHandler 1292 1293 # Switching from walking to non-walking environment: 1294 # set the first selected PC in walking env as a selected 1295 # in nonwalking env 1296 #if (not SelectionChangeHandler) and handler: 1297 if (not SelectionChangeHandler) and handler: 1298 sel = GemRB.GameGetFirstSelectedPC () 1299 if sel: 1300 GemRB.GameSelectPCSingle (sel) 1301 1302 SelectionChangeHandler = handler 1303 1304 # redraw selection on change main selection | single selection 1305 # SelectionChanged () 1306 return 1307 1308def SetSelectionChangeMultiHandler (handler): 1309 global SelectionChangeMultiHandler 1310 SelectionChangeMultiHandler = handler 1311 #SelectionChanged () 1312 1313def CloseTopWindow (): 1314 window = GemRB.GetView("WIN_TOP") 1315 # we cannot close the current WIN_TOP unless it has focus 1316 if window and window.HasFocus == True: 1317 window.Close() 1318 UpdateClock() 1319 1320def TopWindowClosed(window): 1321 optwin = GemRB.GetView("OPTWIN") 1322 btnid = GemRB.GetVar("OPTBTN") 1323 button = optwin.GetControl(btnid) if optwin else None 1324 if button: 1325 button.SetState(IE_GUI_BUTTON_UNPRESSED) 1326 rtgbtn = optwin.GetControl(0) if optwin else None # return to game button 1327 if rtgbtn: # not in PST or IWD2 1328 rtgbtn.SetState(IE_GUI_BUTTON_SELECTED) 1329 1330 print("pause state " + str(CreateTopWinLoader.PauseState)) 1331 if CreateTopWinLoader.PauseState is not None: 1332 GemRB.GamePause (CreateTopWinLoader.PauseState, 3) 1333 1334 GameWin = GemRB.GetView("GAMEWIN") 1335 GameWin.SetDisabled(False) 1336 1337 if not CommonWindow.IsGameGUIHidden() and GemRB.GetView ("ACTWIN") and not (GameCheck.IsIWD2() or GameCheck.IsPST()): 1338 GemRB.GetView ("ACTWIN").SetVisible (True) 1339 GemRB.GetView ("MSGWIN").SetVisible(True) 1340 1341 # TODO: this should be moved to GUIINV and that window should have a custom close handler 1342 # that does this stuff then calls this manually 1343 1344 GemRB.LeaveContainer() 1345 if GemRB.IsDraggingItem () == 1: 1346 pc = GemRB.GameGetSelectedPCSingle () 1347 #store the item in the inventory before window is closed 1348 GemRB.DropDraggedItem (pc, -3) 1349 #dropping on ground if cannot store in inventory 1350 if GemRB.IsDraggingItem () == 1: 1351 GemRB.DropDraggedItem (pc, -2) 1352 1353 # for worldmap purposes 1354 GemRB.SetVar ("Travel", -1) 1355 1356 #don't go back to multi selection mode when going to the store screen 1357 if not GemRB.GetVar ("Inventory"): 1358 SetSelectionChangeHandler (None) 1359 1360 SelectionChanged() 1361 1362if GameCheck.IsIWD2(): 1363 DefaultWinPos = WINDOW_TOP|WINDOW_HCENTER 1364else: 1365 DefaultWinPos = WINDOW_CENTER 1366 1367def CreateTopWinLoader(id, pack, loader, initer = None, selectionHandler = None, pos = DefaultWinPos, pause = False): 1368 def ret (btn = None, val = None): 1369 topwin = GemRB.GetView("WIN_TOP") 1370 if topwin and topwin.HasFocus == False: 1371 return None # we cannot close the current WIN_TOP unless it has focus 1372 1373 window = loader(id, pack, pos) 1374 1375 if window: 1376 # set this before calling initer so initer can change it if it wants 1377 window.SetFlags(WF_ALPHA_CHANNEL, OP_NAND) 1378 if initer: 1379 initer(window) 1380 1381 if selectionHandler: 1382 selectionHandler(window) 1383 window.SetAction(selectionHandler, ACTION_WINDOW_FOCUS_GAINED) 1384 1385 SetTopWindow (window, selectionHandler) 1386 window.SetAction(lambda: TopWindowClosed(window), ACTION_WINDOW_CLOSED) 1387 if GameCheck.IsPST (): 1388 import FloatMenuWindow 1389 if FloatMenuWindow.FloatMenuWindow: 1390 FloatMenuWindow.FloatMenuWindow.Close () 1391 1392 if pause: 1393 CreateTopWinLoader.PauseState = GemRB.GamePause(3, 1) 1394 GemRB.GamePause (1, 3) 1395 else: 1396 CreateTopWinLoader.PauseState = None 1397 1398 optwin = GemRB.GetView("OPTWIN") 1399 if optwin: 1400 rtgbtn = optwin.GetControl(0) # return to game button 1401 if optwin and rtgbtn: # not in PST or IWD2 1402 rtgbtn.SetState(IE_GUI_BUTTON_UNPRESSED) 1403 if btn: 1404 btn.SetState(IE_GUI_BUTTON_SELECTED) 1405 GemRB.SetVar("OPTBTN", val) # cant use btn.ID because it is "too large to convert to C long" 1406 1407 GameWin = GemRB.GetView("GAMEWIN") 1408 GameWin.SetDisabled(True) 1409 1410 if not CommonWindow.IsGameGUIHidden() and GemRB.GetView ("ACTWIN") and not (GameCheck.IsIWD2() or GameCheck.IsPST()): 1411 # hide some windows to declutter higher resolutions and avoid unwanted interaction 1412 GemRB.GetView ("ACTWIN").SetVisible(False) 1413 GemRB.GetView ("MSGWIN").SetVisible(False) 1414 1415 return window 1416 1417 return ret 1418 1419def SetTopWindow (window, selectionHandler = None): 1420 topwin = GemRB.GetView("WIN_TOP") 1421 if topwin == window: 1422 return 1423 1424 pc = GemRB.GameGetSelectedPCSingle() 1425 1426 if topwin: 1427 topwin.Close() # invalidates topwin so must use a different variable 1428 preserveSelection = True 1429 else: 1430 preserveSelection = False 1431 1432 if window: 1433 window.AddAlias("WIN_TOP") 1434 window.Focus() 1435 1436 UpdateClock() 1437 1438 if selectionHandler: 1439 selectionHandler = lambda win=window, fn=selectionHandler: fn(win) 1440 1441 SetSelectionChangeHandler (selectionHandler) 1442 if preserveSelection: 1443 # we are going to another topwin so preserve the selection 1444 GemRB.GameSelectPCSingle(pc) 1445 else: 1446 SetSelectionChangeHandler (None) 1447 1448def OpenWindowOnce(id, pack, pos=WINDOW_CENTER): 1449 window = GemRB.GetView(pack, id) 1450 if window: 1451 window.Focus() 1452 return None 1453 else: 1454 return GemRB.LoadWindow(id, pack, pos) 1455 1456def ToggleWindow(id, pack, pos=WINDOW_CENTER): 1457 # do nothing while in a store 1458 if GemRB.GetView ("WIN_STORE"): 1459 return None 1460 1461 window = GemRB.GetView(pack, id) 1462 if window: 1463 window.Close() 1464 UpdateClock () 1465 return None 1466 else: 1467 return GemRB.LoadWindow(id, pack, pos) 1468 1469# returns buttons and a numerical index 1470# does nothing new in pst, iwd2 due to layout 1471# in the rest, it will enable extra button generation for higher resolutions 1472# Mode determines arrangment direction, horizontal being for party reform and potentially save/load 1473def GetPortraitButtonPairs (Window, ExtraSlots=0, Mode="vertical"): 1474 pairs = {} 1475 1476 if not Window: 1477 return pairs 1478 1479 oldSlotCount = 6 + ExtraSlots 1480 1481 for i in range(min(oldSlotCount, MAX_PARTY_SIZE + ExtraSlots)): # the default chu/game limit or less 1482 pairs[i] = Window.GetControl (i) 1483 1484 # nothing left to do 1485 PartySize = GemRB.GetPartySize () 1486 if PartySize <= oldSlotCount: 1487 return pairs 1488 1489 if GameCheck.IsIWD2() or GameCheck.IsPST(): 1490 # set Mode = "horizontal" once we can create enough space 1491 GemRB.Log(LOG_ERROR, "GetPortraitButtonPairs", "Parties larger than 6 are currently not supported in IWD2 and PST! Using 6 ...") 1492 return pairs 1493 1494 # GUIWORLD doesn't have a separate portraits window, so we need to skip 1495 # all this magic when reforming an overflowing party 1496 if GemRB.GetPartySize () > MAX_PARTY_SIZE: 1497 return pairs 1498 1499 # generate new buttons by copying from existing ones 1500 firstButton = pairs[0] 1501 firstRect = firstButton.GetFrame () 1502 buttonHeight = firstRect["h"] 1503 buttonWidth = firstRect["w"] 1504 xOffset = firstRect["x"] 1505 yOffset = firstRect["y"] 1506 windowRect = Window.GetFrame() 1507 windowHeight = windowRect["h"] 1508 windowWidth = windowRect["w"] 1509 limit = limitStep = 0 1510 scale = 0 1511 portraitGap = 0 1512 if Mode == "horizontal": 1513 xOffset += 3*buttonWidth # width of other controls in party reform; we'll draw on the other side (atleast in guiw8, guiw10 has no need for this) 1514 maxWidth = windowWidth - xOffset 1515 limit = maxWidth 1516 limitStep = buttonWidth 1517 else: 1518 # reduce it by existing slots + 0 slots in framed views (eg. inventory) and 1519 # 1 in main game control (for spacing and any other controls below (ai/select all in bg2)) 1520 maxHeight = windowHeight - buttonHeight*6 - buttonHeight // 2 1521 if windowHeight != ScreenHeight: 1522 maxHeight += buttonHeight // 2 1523 limit = maxHeight 1524 # for framed views, limited to 6, we downscale the buttons to fit, clipping their portraits 1525 if maxHeight < buttonHeight: 1526 unused = 20 # remaining unused space below the portraits 1527 scale = 1 1528 portraitGap = buttonHeight 1529 buttonHeight = (buttonHeight * 6 + unused) // PartySize 1530 portraitGap = portraitGap - buttonHeight - 2 # 2 for a quasi border 1531 limit = windowHeight - buttonHeight*6 + unused 1532 limitStep = buttonHeight 1533 1534 for i in range(len(pairs), PartySize): 1535 if limitStep > limit: 1536 raise SystemExit("Not enough window space for so many party members (portraits), bailing out! %d vs width/height of %d/%d" %(limit, buttonWidth, buttonHeight)) 1537 nextID = 1000 + i 1538 control = Window.GetControl (nextID) 1539 if control: 1540 pairs[i] = control 1541 continue 1542 if Mode == "horizontal": 1543 Window.CreateButton (nextID, xOffset+i*buttonWidth, yOffset, buttonWidth, buttonHeight) 1544 else: 1545 # vertical 1546 Window.CreateButton (nextID, xOffset, i*buttonHeight+yOffset+i*2*scale, buttonWidth, buttonHeight) 1547 1548 button = Window.GetControl (nextID) 1549 button.SetSprites ("GUIRSPOR", 0, 0, 1, 0, 0) 1550 1551 pairs[i] = button 1552 limit -= limitStep 1553 1554 # move the buttons back up, to combine the freed space 1555 if scale: 1556 for i in range(oldSlotCount): 1557 button = pairs[i] 1558 button.SetSize (buttonWidth, buttonHeight) 1559 if i == 0: 1560 continue # don't move the first portrait 1561 rect = button.GetRect () 1562 x = rect["X"] 1563 y = rect["Y"] 1564 button.SetPos (x, y-portraitGap*i) 1565 1566 return pairs 1567 1568def OpenInventoryWindowClick (btn, pcID): 1569 import GUIINV 1570 GemRB.GameSelectPC (pcID, True, SELECT_REPLACE) 1571 GUIINV.OpenInventoryWindow () 1572 return 1573 1574DragButton = None 1575def ButtonDragSourceHandler(btn): 1576 global DragButton 1577 DragButton = btn; 1578 1579def ButtonDragDestHandler(btn, pcID): 1580 global DragButton 1581 1582 # So far this is only used for portrait buttons 1583 if DragButton: # DragButton will be none for item drags instantiated by clicking (not sragging) an inventory item 1584 if DragButton.VarName == "portrait" and btn.VarName == "portrait": 1585 GemRB.GameSwapPCs (DragButton.Value, pcID) 1586 1587 else: # TODO: something like this: DragButton.VarName.startswith("slot") 1588 if btn.VarName == "portrait": 1589 InventoryCommon.OnDropItemToPC(pcID) 1590 # TODO: handle inventory/ground slots 1591 1592 DragButton = None 1593 1594def OpenPortraitWindow (needcontrols=0, pos=WINDOW_RIGHT|WINDOW_VCENTER): 1595 #take care, this window is different in how/iwd 1596 if GameCheck.HasHOW() and needcontrols: 1597 PortraitWindow = Window = GemRB.LoadWindow (26, GUICommon.GetWindowPack(), pos) 1598 else: 1599 PortraitWindow = Window = GemRB.LoadWindow (1, GUICommon.GetWindowPack(), pos) 1600 1601 PortraitWindow.AddAlias("PORTWIN") 1602 PortraitWindow.SetFlags(WF_BORDERLESS|IE_GUI_VIEW_IGNORE_EVENTS, OP_OR) 1603 1604 if needcontrols and not GameCheck.IsPST(): #not in pst 1605 # 1280 and higher don't have this control 1606 Button = Window.GetControl (8) 1607 if Button: 1608 if GameCheck.IsIWD(): 1609 # Rest (iwd) 1610 Button.SetTooltip (11942) 1611 Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, RestPress) 1612 else: 1613 Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, MinimizePortraits) 1614 else: 1615 if GameCheck.HasHOW(): 1616 # Rest (how) 1617 pos = Window.GetFrame()["h"] - 37 1618 Button = Window.CreateButton (8, 6, pos, 55, 37) 1619 Button.SetSprites ("GUIRSBUT", 0,0,1,0,0) 1620 Button.SetTooltip (11942) 1621 Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, RestPress) 1622 1623 pos = pos - 37 1624 Window.CreateButton (6, 6, pos, 27, 36) 1625 1626 # AI 1627 Button = Window.GetControl (6) 1628 #fixing a gui bug, and while we are at it, hacking it to be easier 1629 Button.SetSprites ("GUIBTACT", 0, 46, 47, 48, 49) 1630 InitOptionButton(Window, 'Toggle_AI', AIPress) 1631 AIPress(0) #this initialises the state and tooltip 1632 1633 #Select All 1634 if GameCheck.HasHOW(): 1635 Button = Window.CreateButton (7, 33, pos, 27, 36) 1636 Button.SetSprites ("GUIBTACT", 0, 50, 51, 50, 51) 1637 else: 1638 Button = Window.GetControl (7) 1639 Button.SetTooltip (10485) 1640 Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, GUICommon.SelectAllOnPress) 1641 else: 1642 # Rest 1643 if not GameCheck.IsIWD2(): 1644 Button = Window.GetControl (6) 1645 if Button: 1646 Button.SetTooltip (11942) 1647 Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, RestPress) 1648 1649 PortraitButtons = GetPortraitButtonPairs (Window) 1650 for i, Button in PortraitButtons.items(): 1651 pcID = i + 1 1652 1653 Button.SetVarAssoc("portrait", pcID) 1654 1655 if not GameCheck.IsPST(): 1656 fontref = "STATES2" 1657 if GameCheck.IsIWD1() or GameCheck.IsIWD2(): 1658 fontref = "STATES" 1659 1660 Button.SetFont (fontref) 1661 # label for status flags (dialog, store, level up) 1662 align = IE_FONT_ALIGN_TOP | IE_FONT_ALIGN_CENTER | IE_FONT_SINGLE_LINE 1663 label = Button.CreateLabel(200 + i, fontref, "", align) #level up icon is on the right 1664 label.SetFrame(Button.GetInsetFrame(4)) 1665 1666 if needcontrols or GameCheck.IsIWD2(): 1667 Button.SetEvent (IE_GUI_BUTTON_ON_RIGHT_PRESS, OpenInventoryWindowClick) 1668 else: 1669 Button.SetEvent (IE_GUI_BUTTON_ON_RIGHT_PRESS, PortraitButtonOnPress) 1670 1671 Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, PortraitButtonOnPress) 1672 Button.SetEvent (IE_GUI_BUTTON_ON_SHIFT_PRESS, PortraitButtonOnShiftPress) 1673 Button.SetAction(ButtonDragSourceHandler, IE_ACT_DRAG_DROP_SRC) 1674 Button.SetAction(ButtonDragDestHandler, IE_ACT_DRAG_DROP_DST) 1675 1676 if GameCheck.IsIWD1() or GameCheck.IsIWD2(): 1677 # overlay a label, so we can display the hp with the correct font. Regular button label 1678 # is used by effect icons 1679 Button.CreateLabel(100+i, "NUMFONT", "", IE_FONT_ALIGN_TOP|IE_FONT_ALIGN_LEFT|IE_FONT_SINGLE_LINE) 1680 1681 # unlike other buttons, this one lacks extra frames for a selection effect 1682 # so we create it and shift it to cover the grooves of the image 1683 # except iwd2's second frame already has it incorporated (but we miscolor it) 1684 yellow = {'r' : 255, 'g' : 255, 'b' : 0, 'a' : 255} 1685 green = {'r' : 0, 'g' : 255, 'b' : 0, 'a' : 255} 1686 if GameCheck.IsIWD2(): 1687 Button.SetBorder (FRAME_PC_SELECTED, green) 1688 Button.SetBorder (FRAME_PC_TARGET, yellow, 0, 0, Button.GetInsetFrame(2,2,3,3)) 1689 elif GameCheck.IsPST(): 1690 Button.SetBorder (FRAME_PC_SELECTED, green, 0, 0, Button.GetInsetFrame(1,1,2,2)) 1691 Button.SetBorder (FRAME_PC_TARGET, yellow, 0, 0, Button.GetInsetFrame(3,3,4,4)) 1692 Button.SetBAM ("PPPANN", 0, 0, -1) # NOTE: just a dummy, won't be visible 1693 ButtonHP = Window.GetControl (6 + i) 1694 ButtonHP.SetEvent (IE_GUI_BUTTON_ON_PRESS, PortraitButtonHPOnPress) 1695 ButtonHP.SetVarAssoc ("pid", i + 1) # storing so the callback knows which button it's operating on 1696 else: 1697 Button.SetBorder (FRAME_PC_SELECTED, green, 0, 0, Button.GetInsetFrame(4,3,4,3)) 1698 Button.SetBorder (FRAME_PC_TARGET, yellow, 0, 0, Button.GetInsetFrame(2,2,3,3)) 1699 1700 UpdatePortraitWindow () 1701 SelectionChanged () 1702 return Window 1703 1704def UpdatePortraitWindow (): 1705 """Updates all of the portraits.""" 1706 1707 Window = GemRB.GetView("PORTWIN") 1708 Window.Focus(None) 1709 1710 pc = GemRB.GameGetSelectedPCSingle () 1711 Inventory = GemRB.GetVar ("Inventory") 1712 GSFlags = GemRB.GetGUIFlags() 1713 indialog = GSFlags & GS_DIALOG 1714 1715 PortraitButtons = GetPortraitButtonPairs (Window) 1716 for i, Button in PortraitButtons.items(): 1717 pcID = i + 1 1718 if indialog: 1719 Button.SetHotKey(None) 1720 if (pcID <= GemRB.GetPartySize()): 1721 Button.SetAction(lambda btn, val, pc=pcID: GemRB.GameControlLocateActor(pc), IE_ACT_MOUSE_ENTER); 1722 Button.SetAction(lambda: GemRB.GameControlLocateActor(-1), IE_ACT_MOUSE_LEAVE); 1723 if (i < 6 and not indialog): 1724 Button.SetHotKey(chr(ord('1') + i), 0, True) 1725 1726 if GameCheck.IsPST(): 1727 UpdateAnimatedPortrait(Window, i) 1728 continue 1729 1730 Portrait = GemRB.GetPlayerPortrait (pcID, 1) 1731 pic = Portrait["Sprite"] 1732 Hide = False 1733 if Inventory and pc != pcID: 1734 Hide = True 1735 1736 if pic and GemRB.GetPlayerStat(pcID, IE_STATE_ID) & STATE_DEAD: 1737 import GUISTORE 1738 # dead pcs are hidden in all stores but temples 1739 if GUISTORE.StoreWindow and not GUISTORE.StoreHealWindow: 1740 Hide = True 1741 1742 if Hide or (not pic and not Portrait["ResRef"]): 1743 Button.SetFlags (IE_GUI_BUTTON_NO_IMAGE, OP_SET) 1744 Button.SetState (IE_GUI_BUTTON_DISABLED) 1745 Button.SetText ("") 1746 Button.SetTooltip ("") 1747 continue 1748 1749 portraitFlags = IE_GUI_BUTTON_PORTRAIT | IE_GUI_BUTTON_HORIZONTAL | IE_GUI_BUTTON_ALIGN_LEFT | IE_GUI_BUTTON_ALIGN_BOTTOM 1750 1751 if GameCheck.IsIWD2(): 1752 Button.SetEvent (IE_GUI_BUTTON_ON_RIGHT_PRESS, OpenInventoryWindowClick) 1753 Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, PortraitButtonOnPress) 1754 1755 Button.SetFlags (portraitFlags, OP_SET) 1756 1757 Button.SetState (IE_GUI_BUTTON_LOCKED) 1758 Button.SetPicture (pic, "NOPORTSM") 1759 ratio_str, color = GUICommon.SetupDamageInfo (pcID, Button, Window) 1760 1761 # character - 1 == bam cycle 1762 talk = store = flag = blank = ' ' 1763 if GameCheck.IsBG2(): 1764 # as far as I can tell only BG2 has icons for talk or store 1765 flag = blank = chr(238) 1766 talk = 154 # dialog icon 1767 store = 155 # shopping icon 1768 1769 if pc == pcID and GemRB.GetStore() != None: 1770 flag = chr(store) 1771 1772 # talk icon 1773 if GemRB.GameGetSelectedPCSingle(1) == pcID: 1774 flag = chr(talk) 1775 1776 if LUCommon.CanLevelUp (pcID): 1777 flag = flag + blank + chr(255) 1778 elif GameCheck.IsIWD1() or GameCheck.IsIWD2(): 1779 HPLabel = Window.GetControl (100+i) 1780 HPLabel.SetText (ratio_str) 1781 HPLabel.SetTextColor (color) 1782 1783 #add effects on the portrait 1784 effects = GemRB.GetPlayerStates (pcID) 1785 1786 numCols = 4 if GameCheck.IsIWD2() else 3 1787 numEffects = len(effects) 1788 1789 states = b"" 1790 # calculate the partial row 1791 idx = numEffects % numCols 1792 states = effects[0:idx] 1793 # now do any rows that are full 1794 for x in range(idx, numEffects): 1795 if (x - idx) % numCols == 0: 1796 states = states + b"\n" 1797 states = states + bytes(effects[x]) 1798 1799 # FIXME: hack, check shouldn't be needed 1800 FlagLabel = Window.GetControl (200 + i) 1801 if FlagLabel: 1802 if flag != blank: 1803 FlagLabel.SetText (flag.ljust(3, blank)) 1804 else: 1805 FlagLabel.SetText ("") 1806 Button.SetText(states) 1807 return 1808 1809def UpdateAnimatedPortrait (Window,i): 1810 """Selects the correct portrait cycle depending on character state""" 1811 # note: there are actually two portraits per chr, eg PPPANN (static), WMPANN (animated) 1812 Button = Window.GetControl (i) 1813 ButtonHP = Window.GetControl (6 + i) 1814 pic = GemRB.GetPlayerPortrait (i+1, 0)["ResRef"] 1815 if not pic: 1816 Button.SetFlags (IE_GUI_BUTTON_NO_IMAGE, OP_SET) 1817 Button.SetAnimation ("") 1818 ButtonHP.SetFlags (IE_GUI_BUTTON_NO_IMAGE, OP_SET) 1819 ButtonHP.SetText ("") 1820 ButtonHP.SetBAM ("", 0, 0) 1821 return 1822 1823 state = GemRB.GetPlayerStat (i+1, IE_STATE_ID) 1824 hp = GemRB.GetPlayerStat (i+1, IE_HITPOINTS) 1825 hp_max = GemRB.GetPlayerStat (i+1, IE_MAXHITPOINTS) 1826 if state & STATE_DEAD: 1827 cycle = 9 1828 elif state & STATE_HELPLESS: 1829 cycle = 8 1830 elif state & STATE_PETRIFIED: 1831 cycle = 7 1832 elif state & STATE_PANIC: 1833 cycle = 6 1834 elif state & STATE_POISONED: 1835 cycle = 2 1836 elif hp<hp_max/2: 1837 cycle = 4 1838 else: 1839 cycle = 0 1840 1841 Button.SetFlags (IE_GUI_BUTTON_PICTURE | IE_GUI_BUTTON_ANIMATED, OP_SET) 1842 if cycle<6: 1843 Button.SetFlags (IE_GUI_BUTTON_PLAYRANDOM, OP_OR) 1844 1845 Button.SetAnimation (pic, cycle) 1846 ButtonHP.SetFlags(IE_GUI_BUTTON_PICTURE, OP_SET) 1847 1848 if hp_max < 1 or hp == "?": 1849 ratio = 0.0 1850 else: 1851 ratio = hp / float(hp_max) 1852 if ratio > 1.0: ratio = 1.0 1853 1854 r = int (255 * (1.0 - ratio)) 1855 g = int (255 * ratio) 1856 1857 ButtonHP.SetText ("%s / %d" %(hp, hp_max)) 1858 ButtonHP.SetTextColor ({'r' : r, 'g' : g, 'b' : 0}) 1859 ButtonHP.SetBAM ('FILLBAR', 0, 0, -1) 1860 ButtonHP.SetPictureClipping (ratio) 1861 1862 if GemRB.GetVar('Health Bar Settings') & (1 << i): 1863 op = OP_OR 1864 else: 1865 op = OP_NAND 1866 ButtonHP.SetFlags (IE_GUI_BUTTON_PICTURE | IE_GUI_BUTTON_NO_TEXT, op) 1867 1868 return 1869 1870def PortraitButtonOnPress (btn, pcID): 1871 """Selects the portrait individually.""" 1872 1873 if GemRB.GameControlGetTargetMode() != TARGET_MODE_NONE: 1874 GemRB.ActOnPC (pcID) 1875 return 1876 1877 if (not SelectionChangeHandler): 1878 if GemRB.GameIsPCSelected (pcID): 1879 GemRB.GameControlSetScreenFlags (SF_CENTERONACTOR, OP_OR) 1880 GemRB.GameSelectPC (pcID, True, SELECT_REPLACE) 1881 else: 1882 GemRB.GameSelectPCSingle (pcID) 1883 SelectionChanged () 1884 return 1885 1886def PortraitButtonOnShiftPress (btn, pcID): 1887 """Handles selecting multiple portaits with shift.""" 1888 1889 if (not SelectionChangeHandler): 1890 sel = GemRB.GameIsPCSelected (pcID) 1891 sel = not sel 1892 GemRB.GameSelectPC (pcID, sel) 1893 else: 1894 GemRB.GameSelectPCSingle (pcID) 1895 SelectionChanged () 1896 return 1897 1898def PortraitButtonHPOnPress (btn, pcID): ##pst hitpoint display 1899 hbs = GemRB.GetVar('Health Bar Settings') 1900 if hbs & (1 << (pcID - 1)): 1901 op = OP_NAND 1902 else: 1903 op = OP_OR 1904 1905 btn.SetFlags (IE_GUI_BUTTON_PICTURE | IE_GUI_BUTTON_NO_TEXT, op) 1906 GemRB.SetVar('Health Bar Settings', hbs ^ (1 << (pcID - 1))) 1907 return 1908 1909def SelectionChanged (): 1910 """Ran by the Game class when a PC selection is changed.""" 1911 1912 PortraitWindow = GemRB.GetView("PORTWIN") 1913 # FIXME: hack. If defined, display single selection 1914 GemRB.SetVar ("ActionLevel", UAW_STANDARD) 1915 if (not SelectionChangeHandler): 1916 UpdateActionsWindow () 1917 PortraitButtons = GetPortraitButtonPairs (PortraitWindow) 1918 for i, Button in PortraitButtons.items(): 1919 Button.EnableBorder (FRAME_PC_SELECTED, GemRB.GameIsPCSelected (i + 1)) 1920 if SelectionChangeMultiHandler: 1921 SelectionChangeMultiHandler () 1922 else: 1923 sel = GemRB.GameGetSelectedPCSingle () 1924 1925 #update mage school 1926 GemRB.SetVar ("MAGESCHOOL", 0) 1927 Kit = GUICommon.GetKitIndex (sel) 1928 if Kit and CommonTables.KitList.GetValue (Kit, 7) == 1: 1929 MageTable = GemRB.LoadTable ("magesch") 1930 GemRB.SetVar ("MAGESCHOOL", MageTable.FindValue (3, CommonTables.KitList.GetValue (Kit, 6) ) ) 1931 1932 PortraitButtons = GetPortraitButtonPairs (PortraitWindow) 1933 for i, Button in PortraitButtons.items(): 1934 Button.EnableBorder (FRAME_PC_SELECTED, i + 1 == sel) 1935 1936 CommonWindow.CloseContainerWindow() 1937 if SelectionChangeHandler: 1938 SelectionChangeHandler () 1939 return 1940 1941def ActionStopPressed (): 1942 for i in GemRB.GetSelectedActors(): 1943 GemRB.ClearActions (i) 1944 return 1945 1946def ActionTalkPressed (): 1947 GemRB.GameControlSetTargetMode (TARGET_MODE_TALK,GA_NO_DEAD|GA_NO_ENEMY|GA_NO_HIDDEN) 1948 1949def ActionAttackPressed (): 1950 GemRB.GameControlSetTargetMode (TARGET_MODE_ATTACK,GA_NO_DEAD|GA_NO_SELF|GA_NO_HIDDEN) 1951 1952def ActionDefendPressed (): 1953 GemRB.GameControlSetTargetMode (TARGET_MODE_DEFEND,GA_NO_SELF|GA_NO_ENEMY|GA_NO_HIDDEN) 1954 1955def ActionThievingPressed (): 1956 GemRB.GameControlSetTargetMode (TARGET_MODE_PICK, GA_NO_DEAD|GA_NO_SELF|GA_NO_ENEMY|GA_NO_HIDDEN) 1957 1958def MinimizePortraits(): #bg2 1959 GemRB.GameSetScreenFlags(GS_PORTRAITPANE, OP_OR) 1960 1961def SetItemButton (Window, Button, Slot, PressHandler, RightPressHandler): #relates to pst containers 1962 if Slot != None: 1963 Item = GemRB.GetItem (Slot['ItemResRef']) 1964 identified = Slot['Flags'] & IE_INV_ITEM_IDENTIFIED 1965 #Button.SetVarAssoc ("LeftIndex", LeftTopIndex+i) 1966 #Button.SetSprites ('IVSLOT', 0, 0, 0, 0, 0) 1967 Button.SetItemIcon (Slot['ItemResRef'],0) 1968 1969 if Item['MaxStackAmount'] > 1: 1970 Button.SetText (str (Slot['Usages0'])) 1971 else: 1972 Button.SetText ('') 1973 1974 1975 if not identified or Item['ItemNameIdentified'] == -1: 1976 Button.SetTooltip (Item['ItemName']) 1977 else: 1978 Button.SetTooltip (Item['ItemNameIdentified']) 1979 1980 #Button.SetFlags (IE_GUI_BUTTON_PICTURE, OP_OR) 1981 #Button.SetFlags (IE_GUI_BUTTON_NO_IMAGE, OP_NAND) 1982 1983 Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, PressHandler) 1984 Button.SetEvent (IE_GUI_BUTTON_ON_RIGHT_PRESS, RightPressHandler) 1985 #Button.SetEvent (IE_GUI_BUTTON_ON_SHIFT_PRESS, ShiftPressHandler) 1986 #Button.SetEvent (IE_GUI_BUTTON_ON_DRAG_DROP, DragDropHandler) 1987 1988 else: 1989 #Button.SetVarAssoc ("LeftIndex", -1) 1990 Button.SetItemIcon ('') 1991 Button.SetTooltip (4273) # Ground Item 1992 Button.SetText ('') 1993 Button.SetFlags (IE_GUI_BUTTON_PICTURE, OP_NAND) 1994 1995 Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, None) 1996 Button.SetEvent (IE_GUI_BUTTON_ON_RIGHT_PRESS, None) 1997 #Button.SetEvent (IE_GUI_BUTTON_ON_SHIFT_PRESS, None) 1998 #Button.SetEvent (IE_GUI_BUTTON_ON_DRAG_DROP, None) 1999 2000def OpenWaitForDiscWindow (): 2001 global DiscWindow 2002 2003 if DiscWindow: 2004 DiscWindow.Unload () 2005 DiscWindow = None 2006 return 2007 2008 DiscWindow = GemRB.LoadWindow (0, "GUIID") 2009 label = DiscWindow.GetControl (0) 2010 2011 disc_num = GemRB.GetVar ("WaitForDisc") 2012 disc_path = 'XX:' 2013 2014 text = GemRB.GetString (31483) + " " + str (disc_num) + " " + GemRB.GetString (31569) + " " + disc_path + "\n" + GemRB.GetString (49152) 2015 label.SetText (text) 2016 # 31483 - Please place PS:T disc number 2017 # 31568 - Please place the PS:T DVD 2018 # 31569 - in drive 2019 # 31570 - Wrong disc in drive 2020 # 31571 - There is no disc in drive 2021 # 31578 - No disc could be found in drive. Please place Disc 1 in drive. 2022 # 49152 - To quit the game, press Alt-F4 2023 2024 2025def CheckLevelUp(pc): 2026 GemRB.SetVar ("CheckLevelUp"+str(pc), LUCommon.CanLevelUp (pc)) 2027 2028def ToggleAlwaysRun(): 2029 GemRB.GameControlToggleAlwaysRun() 2030 2031def RestPress (): 2032 CloseTopWindow () 2033 # only rest if the dream scripts haven't already 2034 # bg2 completely offloaded resting to them - if there's a talk, it has to call Rest(Party) itself 2035 if not GemRB.RunRestScripts (): 2036 # ensure the scripts run before the actual rest 2037 GemRB.SetTimedEvent (RealRestPress, 2) 2038 2039def RealRestPress (): 2040 # only bg2 has area-based rest movies 2041 # outside movies start at 2, 1 is for inns 2042 # 15 means run all checks to see if resting is possible 2043 info = GemRB.RestParty(15, 0 if GameCheck.IsBG2() else 2, 1) 2044 if info["Error"]: 2045 if GameCheck.IsPST (): 2046 # open error window 2047 Window = GemRB.LoadWindow (25, GUICommon.GetWindowPack (), WINDOW_BOTTOM|WINDOW_HCENTER) 2048 Label = Window.GetControl (0xfffffff) # -1 in the CHU 2049 Label.SetText (info["ErrorMsg"]) 2050 Button = Window.GetControl (1) 2051 Button.SetText (1403) 2052 Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, lambda: Window.Close ()) 2053 Window.ShowModal (MODAL_SHADOW_GRAY) 2054 else: 2055 GemRB.DisplayString (info["ErrorMsg"], ColorRed) 2056 2057 return 2058 2059# special pst death screen for the finale 2060def OpenPSTDeathWindow (): 2061 if not GameCheck.IsPST (): 2062 return 2063 2064 def ShowCredits(): 2065 GemRB.ExecuteString ("EndCredits()") 2066 # will also exit to the main menu 2067 2068 # reuse the main error window 2069 GemRB.LoadWindowPack (GUICommon.GetWindowPack()) 2070 Window = GemRB.LoadWindow (25) 2071 Label = Window.GetControl (0xfffffff) # -1 in the CHU 2072 Label.SetText (48155) 2073 Button = Window.GetControl (1) 2074 Button.SetText (1403) 2075 Button.SetEvent (IE_GUI_BUTTON_ON_PRESS, ShowCredits) 2076 Window.ShowModal (MODAL_SHADOW_GRAY) 2077