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# LUSkillSelection.py - selection of thief skills 20 21import GemRB 22from GUIDefines import * 23from ie_stats import * 24import GameCheck 25import GUICommon 26import CommonTables 27 28#constants 29LUSKILLS_TYPE_LEVELUP = 1 30LUSKILLS_TYPE_CHARGEN = 2 31LUSKILLS_TYPE_DUALCLASS = 4 32LUSKILLS_MAX = 250 33 34#refs to the script calling this 35SkillsWindow = 0 36SkillsCallback = 0 37 38#offsets to the various parts of all 3 windows 39SkillsOffsetPress = 0 40SkillsOffsetButton1 = 0 41SkillsOffsetName = 0 42SkillsOffsetPoints = 0 43SkillsOffsetSum = 0 44SkillsNumButtons = 0 45 46#The number of steps between each control ID for the skill label and points of each skill 47#Set to 2 for PST, as they are 'interleaved' ie label/amount/label/amount 48SkillsLabelIncrement = 1 49 50#internal variables 51SkillsIndices = [] 52SkillPointsLeft = 0 53SkillsTopIndex = 0 54SkillsTable = 0 55SkillsOldPos = 0 56SkillsClickCount = 0 57SkillsOldDirection = 0 58SkillsTextArea = 0 59SkillsKitName = 0 60SkillsAssignable = 0 61 62#WARNING: This WILL NOT show the window, only access it. To see the return, call GemRB.GetVar ("SkillPointsLeft"). 63# If nothing can be assigned, it will return 0 prior to accessing any of the window methods. 64def SetupSkillsWindow (pc, skilltype, window, callback, level1=[0,0,0], level2=[1,1,1], classid=0, scroll=True): 65 global SkillsWindow, SkillsCallback, SkillsOffsetPress, SkillsOffsetButton1, SkillsOffsetName 66 global SkillsOffsetPoints, SkillsOffsetSum, SkillsIndices, SkillPointsLeft, SkillsTopIndex 67 global SkillsTable, SkillsOldPos, SkillsClickCount, SkillsOldDirection, SkillsNumButtons 68 global SkillsTextArea, SkillsKitName, SkillsAssignable, SkillsLabelIncrement 69 70 #reset some basic values 71 SkillLeftPress = SkillIncreasePress 72 SkillRightPress = SkillDecreasePress 73 SkillsWindow = window 74 SkillsCallback = callback 75 SkillsOldPos = 0 76 SkillsClickCount = 0 77 SkillsOldDirection = 0 78 SkillsAssignable = 0 79 SkillsTable = GemRB.LoadTable ("skills") 80 SkillPointsLeft = 0 81 GemRB.SetVar ("SkillPointsLeft", 0) 82 SkillsNullify () 83 84 #make sure we're within ranges 85 if not window or not callback or len(level1)!=len(level2): 86 return 87 88 #setup the offsets 89 if skilltype == LUSKILLS_TYPE_LEVELUP and GameCheck.IsBG2(): 90 SkillsOffsetPress = 120 91 SkillsOffsetButton1 = 17 92 SkillsOffsetSum = 37 93 SkillsOffsetName = 32 94 SkillsOffsetPoints = 43 95 SkillsNumButtons = 4 96 SkillsTextArea = SkillsWindow.GetControl (110) 97 ScrollBar = SkillsWindow.GetControl (109) 98 elif skilltype == LUSKILLS_TYPE_LEVELUP and GameCheck.IsPST(): 99 SkillsOffsetPress = -1 100 SkillsOffsetButton1 = 16 101 SkillsOffsetSum = 6 102 SkillsOffsetName = 7 103 SkillsOffsetPoints = 8 104 SkillsNumButtons = 4 105 SkillsLabelIncrement = 2 106 #The order of the buttons is the opposite of the other games 107 SkillLeftPress = SkillDecreasePress 108 SkillRightPress = SkillIncreasePress 109 #There is actually no hint text to describe the skills, so this is a dummy 110 SkillsWindow.CreateTextArea (45, 1, 1, 1, 1, "FONTDLG") 111 SkillsTextArea = SkillsWindow.GetControl (45) 112 elif skilltype == LUSKILLS_TYPE_LEVELUP: 113 SkillsOffsetPress = -1 114 SkillsOffsetButton1 = 17 115 SkillsOffsetSum = 37 116 SkillsOffsetName = 32 117 SkillsOffsetPoints = 43 118 SkillsNumButtons = 4 119 SkillsTextArea = SkillsWindow.GetControl (42) 120 if (scroll): 121 ScrollBar = SkillsWindow.GetControl (109) 122 elif skilltype == LUSKILLS_TYPE_DUALCLASS: 123 SkillsOffsetPress = 5 124 SkillsOffsetButton1 = 14 125 SkillsOffsetSum = 8 126 SkillsOffsetName = 0 127 SkillsOffsetPoints = 9 128 SkillsNumButtons = 4 129 SkillsTextArea = SkillsWindow.GetControl (22) 130 SkillsTextArea.SetText(17248) 131 if (scroll): 132 ScrollBar = SkillsWindow.GetControl (26) 133 SkillsWindow.SetEventProxy(ScrollBar) 134 elif skilltype == LUSKILLS_TYPE_CHARGEN: 135 SkillsOffsetPress = 21 136 SkillsOffsetButton1 = 11 137 SkillsOffsetSum = 5 138 SkillsOffsetName = 6 139 SkillsOffsetPoints = 1 140 SkillsNumButtons = 4 141 SkillsTextArea = SkillsWindow.GetControl (19) 142 SkillsTextArea.SetText(17248) 143 if (scroll): 144 ScrollBar = SkillsWindow.GetControl (26) 145 SkillsWindow.SetEventProxy(ScrollBar) 146 else: 147 return 148 149 #get our class id and name 150 IsDual = GUICommon.IsDualClassed (pc, 1) 151 IsMulti = GUICommon.IsMultiClassed (pc, 1) 152 if classid: #used when dual-classing 153 Class = classid 154 elif IsDual[0] == 3: 155 Class = CommonTables.KitList.GetValue (IsDual[2], 7) 156 elif IsDual[0]: #only care about the current class 157 Class = GUICommon.GetClassRowName(IsDual[2], "index") 158 Class = CommonTables.Classes.GetValue (Class, "ID") 159 else: 160 Class = GemRB.GetPlayerStat (pc, IE_CLASS) 161 ClassName = GUICommon.GetClassRowName(Class, "class") 162 163 #get the number of classes 164 if IsMulti[0]>1: 165 NumClasses = IsMulti[0] 166 else: 167 NumClasses = 1 168 if NumClasses > len (level2): 169 return 170 171 #figure out the kitname if we need it 172 #protect against kitted multiclasses 173 Kit = GUICommon.GetKitIndex (pc) 174 if not Kit or skilltype == LUSKILLS_TYPE_DUALCLASS or IsDual[0] in [1, 2] or IsMulti[0]>1: 175 SkillsKitName = ClassName 176 else: 177 SkillsKitName = CommonTables.KitList.GetValue (Kit, 0, GTV_STR) 178 179 # also treat most mod-introduced kits as kitless for skills.2da 180 # lookups - unless they add the required columns 181 if SkillsTable.GetValue ("OPEN_LOCKS", SkillsKitName) == -1: 182 SkillsKitName = ClassName 183 184 #figure out the correct skills table 185 SkillIndex = -1 186 for i in range (NumClasses): 187 TmpClass = Class 188 if NumClasses > 1: 189 TmpClass = IsMulti[i+1] 190 TmpClass = GUICommon.GetClassRowName (TmpClass, "class") 191 if (CommonTables.ClassSkills.GetValue (TmpClass, "THIEFSKILL", GTV_STR) != "*"): 192 SkillIndex = i 193 break 194 195 #see if we got a thief (or monk) 196 SkillsIndices = [] 197 if SkillIndex >= 0: 198 #SkillsKitName should be fine as all multis are in classes.2da 199 #also allows for thief kits 200 SkillsAssignable = 1 201 for i in range(SkillsTable.GetRowCount()-2): 202 # -2/+2 to compensate for the special first_level and rate rows 203 SkillName = SkillsTable.GetRowName (i+2) 204 if SkillsTable.GetValue (SkillName, SkillsKitName) != -1: 205 SkillsIndices.append(i) 206 207 LevelDiff = [] 208 for i in range (NumClasses): 209 LevelDiff.append (level2[i]-level1[i]) 210 if level1[SkillIndex] == 0: 211 SkillPointsLeft = SkillsTable.GetValue ("FIRST_LEVEL", SkillsKitName, GTV_INT) 212 LevelDiff[SkillIndex] -= 1 213 SkillPointsLeft += LevelDiff[SkillIndex] * SkillsTable.GetValue("RATE", SkillsKitName, GTV_INT) 214 TotalSkillsAssignable = 0 215 216 if SkillPointsLeft < 0: 217 #really don't have an entry 218 SkillPointsLeft = 0 219 else: 220 #get the skill values 221 for i in range(SkillsTable.GetRowCount()-2): 222 # -2/+2 to compensate for the special first_level and rate rows 223 SkillName = SkillsTable.GetRowName (i+2) 224 SkillID = SkillsTable.GetValue (SkillName, "ID") 225 SkillValue = GemRB.GetPlayerStat (pc, SkillID) 226 BaseSkillValue = GemRB.GetPlayerStat (pc, SkillID, 1) 227 GemRB.SetVar("Skill "+str(i), SkillValue) 228 GemRB.SetVar("SkillBase "+str(i), SkillValue) 229 # display the modified stat to avoid confusion (account for dex, race and effect boni) 230 GemRB.SetVar("SkillDisplayMod "+str(i), SkillValue-BaseSkillValue) 231 TotalSkillsAssignable += LUSKILLS_MAX-SkillValue 232 233 #protect against having more skills than we can assign 234 if SkillPointsLeft > TotalSkillsAssignable: 235 SkillPointsLeft = TotalSkillsAssignable 236 GemRB.SetVar ("SkillPointsLeft", SkillPointsLeft) 237 else: 238 #get ranger and bard skills 239 SpecialSkillsMap = [] 240 for i in range(NumClasses): 241 if IsMulti[0]>1: 242 classname = IsMulti[i+1] 243 else: 244 classname = Class 245 classname = GUICommon.GetClassRowName (classname, "class") 246 for table in "RANGERSKILL", "BARDSKILL": 247 SpecialSkillsTable = CommonTables.ClassSkills.GetValue (classname, table) 248 if SpecialSkillsTable != "*": 249 SpecialSkillsMap.append((SpecialSkillsTable, i)) 250 break 251 for skills in SpecialSkillsMap: 252 SpecialSkillsTable = GemRB.LoadTable (skills[0]) 253 for skill in range(SpecialSkillsTable.GetColumnCount ()): 254 skillname = SpecialSkillsTable.GetColumnName (skill) 255 value = SpecialSkillsTable.GetValue (str(level2[skills[1]]), skillname) 256 skillindex = SkillsTable.GetRowIndex (skillname) - 2 257 GemRB.SetVar ("Skill " + str(skillindex), value) 258 SkillsIndices.append(skillindex) 259 260 #we didn't find anything, so don't continue (will show as a return of 0) 261 #or don't display if we aren't leveling and have a bard/ranger 262 if not len (SkillsIndices) or (not SkillPointsLeft and skilltype != LUSKILLS_TYPE_LEVELUP): 263 SkillSumLabel = SkillsWindow.GetControl(0x10000000+SkillsOffsetSum) 264 SkillSumLabel.SetText("") 265 return 266 267 #skills scrollbar 268 SkillsTopIndex = 0 269 GemRB.SetVar ("SkillsTopIndex", SkillsTopIndex) 270 if len(SkillsIndices) > SkillsNumButtons: 271 ScrollBar.SetEvent (IE_GUI_SCROLLBAR_ON_CHANGE, SkillScrollBarPress) 272 #decrease it with the number of controls on screen (list size) and two unrelated rows 273 ScrollBar.SetVarAssoc ("SkillsTopIndex", SkillsTable.GetRowCount()-SkillsNumButtons-2) 274 else: 275 if len(SkillsIndices) and SkillsAssignable: 276 #autoscroll to the first valid skill; luckily all three monk ones are adjacent 277 GemRB.SetVar ("SkillsTopIndex", SkillsIndices[0]) 278 279 #setup all the visible buttons 280 for i in range(len(SkillsIndices)): 281 if i == SkillsNumButtons: 282 break 283 if SkillsOffsetPress != -1: 284 Button = SkillsWindow.GetControl(i+SkillsOffsetPress) 285 Button.SetVarAssoc("Skill",SkillsIndices[i]) 286 Button.SetEvent(IE_GUI_BUTTON_ON_PRESS, SkillJustPress) 287 288 Button = SkillsWindow.GetControl(i*2+SkillsOffsetButton1) 289 Button.SetVarAssoc("Skill",SkillsIndices[i]) 290 Button.SetEvent(IE_GUI_BUTTON_ON_PRESS, SkillLeftPress) 291 Button.SetActionInterval(20); 292 293 Button = SkillsWindow.GetControl(i*2+SkillsOffsetButton1+1) 294 Button.SetVarAssoc("Skill",SkillsIndices[i]) 295 Button.SetEvent(IE_GUI_BUTTON_ON_PRESS, SkillRightPress) 296 Button.SetActionInterval(20); 297 298 SkillsRedraw () 299 return 300 301def SkillsRedraw (direction=0): 302 global SkillsOldDirection, SkillsClickCount, SkillsLabelIncrement 303 304 #update how many skill points are left and call the callback function 305 SkillSumLabel = SkillsWindow.GetControl(0x10000000+SkillsOffsetSum) 306 SkillSumLabel.SetText(str(SkillPointsLeft)) 307 308 for i in range (SkillsNumButtons): 309 if len(SkillsIndices) <= i: 310 SkillsHide (i) 311 continue 312 313 #show the current skills name 314 Pos = SkillsIndices[SkillsTopIndex+i] 315 SkillName = SkillsTable.GetValue (SkillsTable.GetRowName (Pos+2), "CAP_REF") 316 Label = SkillsWindow.GetControl (0x10000000+SkillsOffsetName+(i*SkillsLabelIncrement)) 317 Label.SetText (SkillName) 318 319 #enable/disable the button if we can(not) get the skills 320 SkillName = SkillsTable.GetRowName (Pos+2) 321 Ok = SkillsTable.GetValue (SkillName, SkillsKitName) and SkillsAssignable 322 Button1 = SkillsWindow.GetControl(i*2+SkillsOffsetButton1) 323 Button2 = SkillsWindow.GetControl(i*2+SkillsOffsetButton1+1) 324 if not Ok: 325 Button1.SetState(IE_GUI_BUTTON_DISABLED) 326 Button2.SetState(IE_GUI_BUTTON_DISABLED) 327 Button1.SetFlags(IE_GUI_BUTTON_NO_IMAGE,OP_OR) 328 Button2.SetFlags(IE_GUI_BUTTON_NO_IMAGE,OP_OR) 329 else: 330 Button1.SetState(IE_GUI_BUTTON_ENABLED) 331 Button2.SetState(IE_GUI_BUTTON_ENABLED) 332 Button1.SetFlags(IE_GUI_BUTTON_NO_IMAGE,OP_NAND) 333 Button2.SetFlags(IE_GUI_BUTTON_NO_IMAGE,OP_NAND) 334 335 #show how many points are allocated to this skill 336 Label = SkillsWindow.GetControl(0x10000000+SkillsOffsetPoints+(i*SkillsLabelIncrement)) 337 ActPoint = GemRB.GetVar("Skill "+str(Pos) ) 338 Label.SetText(str(ActPoint)) 339 340 #setup doublespeed 341 if SkillsOldDirection == direction: 342 SkillsClickCount = SkillsClickCount + 1 343 return 344 345 SkillsOldDirection = direction 346 SkillsClickCount = 0 347 return 348 349def SkillJustPress(btn, val): 350 Pos = val+SkillsTopIndex 351 SkillsTextArea.SetText (SkillsTable.GetValue (SkillsTable.GetRowName (Pos+2), "DESC_REF")) 352 return 353 354def SkillDecreasePress(btn, val): 355 global SkillPointsLeft, SkillsClickCount, SkillsOldPos 356 357 Pos = val+SkillsTopIndex 358 SkillsTextArea.SetText (SkillsTable.GetValue (SkillsTable.GetRowName (Pos+2), "DESC_REF")) 359 ActPoint = GemRB.GetVar("Skill "+str(Pos) ) 360 BasePoint = GemRB.GetVar("SkillBase "+str(Pos) ) 361 if ActPoint <= 0 or ActPoint <= BasePoint: 362 return 363 GemRB.SetVar("Skill "+str(Pos),ActPoint-1) 364 SkillPointsLeft = SkillPointsLeft + 1 365 if SkillsOldPos != Pos: 366 SkillsOldPos = Pos 367 SkillsClickCount = 0 368 369 GemRB.SetVar ("SkillPointsLeft", SkillPointsLeft) 370 SkillsRedraw(2) 371 SkillsCallback () 372 return 373 374def SkillIncreasePress(btn, val): 375 global SkillPointsLeft, SkillsClickCount, SkillsOldPos 376 377 Pos = val+SkillsTopIndex 378 SkillsTextArea.SetText (SkillsTable.GetValue (SkillsTable.GetRowName (Pos+2), "DESC_REF")) 379 if SkillPointsLeft == 0: 380 return 381 ActPoint = GemRB.GetVar("Skill "+str(Pos) ) 382 if ActPoint >= LUSKILLS_MAX: 383 return 384 GemRB.SetVar("Skill "+str(Pos), ActPoint+1) 385 SkillPointsLeft = SkillPointsLeft - 1 386 if SkillsOldPos != Pos: 387 SkillsOldPos = Pos 388 SkillsClickCount = 0 389 390 GemRB.SetVar ("SkillPointsLeft", SkillPointsLeft) 391 SkillsRedraw(1) 392 SkillsCallback () 393 return 394 395def SkillScrollBarPress(): 396 global SkillsTopIndex 397 398 SkillsTopIndex = GemRB.GetVar("SkillsTopIndex") 399 SkillsRedraw () 400 return 401 402# saves all the skills 403def SkillsSave (pc): 404 global SkillsTable 405 if not SkillsTable: 406 SkillsTable = GemRB.LoadTable ("skills") 407 408 for i in range(SkillsTable.GetRowCount() - 2): 409 SkillName = SkillsTable.GetRowName (i+2) 410 SkillID = SkillsTable.GetValue (SkillName, "ID") 411 SkillValue = GemRB.GetVar ("Skill "+str(i)) - GemRB.GetVar("SkillDisplayMod "+str(i)) 412 if SkillValue > 0: 413 GemRB.SetPlayerStat (pc, SkillID, SkillValue) 414 415def SkillsNullify (pc = None): 416 global SkillsTable 417 if not SkillsTable: 418 SkillsTable = GemRB.LoadTable ("skills") 419 420 for i in range(SkillsTable.GetRowCount()-2): 421 GemRB.SetVar ("Skill "+str(i), 0) 422 GemRB.SetVar ("SkillBase "+str(i), 0) 423 if pc: 424 SkillName = SkillsTable.GetRowName (i+2) 425 SkillID = SkillsTable.GetValue (SkillName, "ID") 426 GemRB.SetPlayerStat (pc, SkillID, 0) 427 428def SkillsHide (i): 429 Label = SkillsWindow.GetControl (0x10000000+SkillsOffsetName+i) 430 Label.SetText ("") 431 Button1 = SkillsWindow.GetControl(i*2+SkillsOffsetButton1) 432 Button1.SetState(IE_GUI_BUTTON_DISABLED) 433 Button1.SetFlags(IE_GUI_BUTTON_NO_IMAGE,OP_OR) 434 Button2 = SkillsWindow.GetControl(i*2+SkillsOffsetButton1+1) 435 Button2.SetState(IE_GUI_BUTTON_DISABLED) 436 Button2.SetFlags(IE_GUI_BUTTON_NO_IMAGE,OP_OR) 437 Label = SkillsWindow.GetControl(0x10000000+SkillsOffsetPoints+i) 438 Label.SetText("") 439