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# LevelUp.py - scripts to control the level up functionality and windows 21import GemRB 22from GUIDefines import * 23from ie_stats import * 24from ie_restype import RES_2DA 25import GameCheck 26import GUICommon 27import Spellbook 28import CommonTables 29import LUSpellSelection 30import LUCommon 31if GameCheck.HasTOB(): 32 import LUHLASelection 33import LUProfsSelection 34import LUSkillsSelection 35import Actor 36 37LevelUpWindow = None 38DoneButton = 0 39TextAreaControl = 0 40InfoCounter = 1 41NewProfPoints = 0 42NewSkillPoints = 0 43LevelDiff = 0 44Level = 0 45Classes = 0 46NumClasses = 0 47DualSwap = 0 48KitName = 0 49IsDual = 0 50IsMulti = 0 51pc = 0 52ClassName = 0 53actor = 0 54 55# old values (so we don't add too much) 56OldHPMax = 0 # << old maximum hitpoints 57OldSaves = [0]*5 # << old saves 58OldThaco = 0 # << old thac0 value 59OldLore = 0 # << old lore value 60OldDSpells = [0]*7 # << old divine spells per level 61OldWSpells = [0]*9 # << old wizard spells per level 62NewDSpells = [0]*7 # << new divine spells per level 63NewWSpells = [0]*9 # << new wizard spells per level 64DeltaDSpells = 0 # << total new divine spells 65DeltaWSpells = 0 # << total new wizard spells 66 67def OpenLevelUpWindow(): 68 """Sets up the level up window.""" 69 import GUIREC 70 71 global LevelUpWindow, TextAreaControl, NewProfPoints, actor 72 global DoneButton 73 global NewSkillPoints, KitName, LevelDiff 74 global Level, Classes, NumClasses, DualSwap, IsMulti 75 global OldHPMax, OldSaves, OldLore, OldThaco, DeltaDSpells, DeltaWSpells 76 global NewDSpells, NewWSpells, OldDSpells, OldWSpells, pc, HLACount, ClassName, IsDual 77 78 LevelUpWindow = GemRB.LoadWindow (3) 79 80 if GameCheck.IsBG2(): 81 InfoButton = LevelUpWindow.GetControl (125) 82 InfoButton.SetText (13707) 83 InfoButton.SetEvent (IE_GUI_BUTTON_ON_PRESS, LevelUpInfoPress) 84 # hide "Character Generation" 85 LevelUpWindow.DeleteControl(0x1000007e) 86 87 DoneButton = LevelUpWindow.GetControl (0) 88 DoneButton.SetText (11962) 89 DoneButton.SetEvent (IE_GUI_BUTTON_ON_PRESS, LevelUpDonePress) 90 DoneButton.SetState (IE_GUI_BUTTON_DISABLED) 91 DoneButton.MakeDefault() 92 # also disable closing by ESC, so we don't stack upgrades 93 DoneButton.MakeEscape () 94 95 # name 96 pc = GemRB.GameGetSelectedPCSingle () 97 actor = Actor.Actor(pc) 98 Label = LevelUpWindow.GetControl (0x10000000+90) 99 Label.SetText (GemRB.GetPlayerName (pc)) 100 101 # some current values 102 OldHPMax = GemRB.GetPlayerStat (pc, IE_MAXHITPOINTS, 1) 103 OldThaco = GemRB.GetPlayerStat (pc, IE_TOHIT, 1) 104 OldLore = GemRB.GetPlayerStat (pc, IE_LORE, 1) 105 for i in range (5): 106 OldSaves[i] = GemRB.GetPlayerStat (pc, IE_SAVEVSDEATH+i, 1) 107 108 # class 109 Label = LevelUpWindow.GetControl (0x10000000+106) 110 Label.SetText (GUICommon.GetActorClassTitle (pc)) 111 print("Title: " + GUICommon.GetActorClassTitle (pc) + "\tActor Title: " + actor.ClassTitle()) 112 113 Class = GemRB.GetPlayerStat (pc, IE_CLASS) 114 print("Class: " + str(Class) + "\tActor Class: " + str(actor.classid)) 115 116 # kit 117 ClassName = GUICommon.GetClassRowName (Class, "class") 118 Kit = GUICommon.GetKitIndex (pc) 119 print("Kit: " + str(Kit) + "\tActor Kit: " + str(actor.KitIndex())) 120 print("ClassName: " + ClassName + "\tActor ClassNames: " + str(actor.ClassNames())) 121 122 # need this for checking gnomes 123 RaceName = GemRB.GetPlayerStat (pc, IE_RACE, 1) 124 RaceName = CommonTables.Races.FindValue (3, RaceName) 125 RaceName = CommonTables.Races.GetRowName (RaceName) 126 127 # figure our our proficiency table and index 128 if Kit == 0: 129 KitName = ClassName 130 else: 131 #rowname is just a number, the kitname is the first data column 132 KitName = CommonTables.KitList.GetValue(Kit, 0) 133 134 # our multiclass variables 135 IsMulti = GUICommon.IsMultiClassed (pc, 1) 136 Classes = [IsMulti[1], IsMulti[2], IsMulti[3]] 137 NumClasses = IsMulti[0] # 2 or 3 if IsMulti; 0 otherwise 138 IsMulti = NumClasses > 1 139 IsDual = 0 140 DualSwap = 0 141 142 # not multi, check dual 143 if not IsMulti: 144 # check if we're dual classed 145 IsDual = GUICommon.IsDualClassed (pc, 1) 146 Classes = [] 147 148 # either dual or single only care about 1 class 149 NumClasses = 1 150 151 # not dual, must be single 152 if IsDual[0] == 0: 153 Classes = [Class] 154 else: # resolve kits to classes (new class goes first) 155 if IsDual[0] == 3: # 1st kit 156 Classes.append (CommonTables.KitList.GetValue (IsDual[2], 7)) 157 else: # 1st class 158 Classes.append (CommonTables.Classes.GetValue (IsDual[2], 5)) 159 if IsDual[0] == 1: # 2nd kit 160 Classes.append (CommonTables.KitList.GetValue (IsDual[1], 7)) 161 else: # 2nd class 162 Classes.append (CommonTables.Classes.GetValue (IsDual[1], 5)) 163 164 # store a boolean for IsDual 165 IsDual = IsDual[0] > 0 166 167 print("NumClasses: " + str(NumClasses) + "\tActor NumClasses: " + str(actor.NumClasses())) 168 169 if IsDual: 170 # convert the classes from indicies to class id's 171 DualSwap = GUICommon.IsDualSwap (pc) 172 ClassName = GUICommon.GetClassRowName (Classes[0], "index") 173 KitName = ClassName # for simplicity throughout the code 174 175 print("Classes: " + str(Classes) + "\tActor Classes: " + str(actor.Classes())) 176 print("IsDual: " + str(IsDual > 0) + "\tActor IsDual: " + str(actor.isdual)) 177 178 # get the next target levels and difference between levels 179 Level = LUCommon.GetNextLevels(pc, Classes) 180 LevelDiff = LUCommon.GetLevelDiff(pc, Level) 181 182 # clear some globals, since we may get called multiple times with different classes 183 DeltaWSpells = 0 184 DeltaDSpells = 0 185 OldDSpells = [0]*7 186 OldWSpells = [0]*9 187 NewDSpells = [0]*7 188 NewWSpells = [0]*9 189 190 # calculate the new spells (results are stored in global variables) 191 GetNewSpells(pc, Classes, Level, LevelDiff, Kit) 192 193# this is handled by core 194# # setup class bonuses for this class 195# if IsMulti or IsDual or Kit == 0: 196# ABTable = CommonTables.ClassSkills.GetValue (TmpClassName, "ABILITIES") 197# else: # single-classed with a kit 198# ABTable = CommonTables.KitList.GetValue (str(Kit), "ABILITIES") 199# 200# # add the abilites if we have a table to ref 201# if ABTable != "*" and GemRB.HasResource (ABTable, RES_2DA, 1): 202# GUICommon.AddClassAbilities (pc, ABTable, Level[i], LevelDiff[i]) 203 204 print("Actor CurrentLevels:" + str(actor.Levels())) 205 print("Levels: " + str(Level) + "\tActor NextLevels: " + str(actor.NextLevels())) 206 print("LevelDiffs: " + str(LevelDiff) + "\tActor LevelDiffs: " + str(actor.LevelDiffs())) 207 208 #update our saves, thaco, hp and lore 209 LUCommon.SetupSavingThrows (pc, Level) 210 LUCommon.SetupThaco (pc, Level) 211 LUCommon.SetupLore (pc, LevelDiff) 212 LUCommon.SetupHP (pc, Level, LevelDiff) 213 214 # we set up these labels so late, so they can show the new HP 215 if GameCheck.IsBG1() or GameCheck.IsIWD1(): 216 # armorclass 217 Label = LevelUpWindow.GetControl (0x10000057) 218 Label.SetText (str (GemRB.GetPlayerStat (pc, IE_ARMORCLASS))) 219 Label.SetTooltip (17183) 220 221 # hp now 222 Label = LevelUpWindow.GetControl (0x10000058) 223 Label.SetText (str (GemRB.GetPlayerStat (pc, IE_HITPOINTS))) 224 Label.SetTooltip (17184) 225 226 # hp max 227 Label = LevelUpWindow.GetControl (0x10000059) 228 Label.SetText (str (GemRB.GetPlayerStat (pc, IE_MAXHITPOINTS))) 229 Label.SetTooltip (17378) 230 231 # use total levels for HLAs 232 HLACount = 0 233 if GameCheck.HasTOB(): # make sure SoA doesn't try to get it 234 HLATable = GemRB.LoadTable("lunumab") 235 # we need to check each level against a multi value (this is kinda screwy) 236 if actor.multiclass: 237 print("Actor HLA Names: " + str(["MULTI" + str(actor.NumClasses()) + name \ 238 for name in actor.ClassNames()])) 239 else: 240 print("Actor HLA Names: " + str(actor.ClassNames())) 241 242 for i in range (NumClasses): 243 if IsMulti: 244 # get the row name for lookup ex. MULTI2FIGHTER, MULTI3THIEF 245 MultiName = GUICommon.GetClassRowName (Classes[i], "class") 246 MultiName = "MULTI" + str(NumClasses) + MultiName 247 else: 248 MultiName = ClassName 249 250 # if we can't learn for this class, we can't learn at all 251 FirstLevel = HLATable.GetValue (MultiName, "FIRST_LEVEL", GTV_INT) 252 if Level[i] < FirstLevel: 253 HLACount = 0 254 break 255 256 if (Level[i] - LevelDiff[i]) < FirstLevel: 257 # count only from FirstLevel up 258 HLACount += (Level[i] - FirstLevel + 1) 259 else: 260 HLACount += LevelDiff[i] 261 262 # set values required by the hla level up code 263 HLACount = HLACount // HLATable.GetValue (ClassName, "RATE", GTV_INT) 264 GemRB.SetVar ("HLACount", HLACount) 265 if GameCheck.IsBG2(): 266 HLAButton = LevelUpWindow.GetControl (126) 267 if HLACount: 268 HLAButton.SetText (4954) 269 HLAButton.SetEvent (IE_GUI_BUTTON_ON_PRESS, LevelUpHLAPress) 270 else: 271 HLAButton.SetFlags (IE_GUI_BUTTON_DISABLED, OP_OR) 272 273 # setup our profs 274 Level1 = [] 275 for i in range (len (Level)): 276 Level1.append (Level[i]-LevelDiff[i]) 277 if GameCheck.IsBG2(): 278 LUProfsSelection.SetupProfsWindow (pc, LUProfsSelection.LUPROFS_TYPE_LEVELUP, LevelUpWindow, RedrawSkills, Level1, Level) 279 else: 280 LUProfsSelection.SetupProfsWindow (pc, LUProfsSelection.LUPROFS_TYPE_LEVELUP, LevelUpWindow, RedrawSkills, Level1, Level, 0, False, 0) 281 NewProfPoints = GemRB.GetVar ("ProfsPointsLeft") 282 283 #we autohide the skills and let SetupSkillsWindow show them if needbe 284 for i in range (4): 285 HideSkills (i) 286 if GameCheck.IsBG2(): 287 LUSkillsSelection.SetupSkillsWindow (pc, LUSkillsSelection.LUSKILLS_TYPE_LEVELUP, LevelUpWindow, RedrawSkills, Level1, Level) 288 else: 289 LUSkillsSelection.SetupSkillsWindow (pc, LUSkillsSelection.LUSKILLS_TYPE_LEVELUP, LevelUpWindow, RedrawSkills, Level1, Level, 0, False) 290 NewSkillPoints = GemRB.GetVar ("SkillPointsLeft") 291 292 if GameCheck.IsBG2(): 293 TextAreaControl = LevelUpWindow.GetControl(110) 294 TextAreaControl.SetText(GetLevelUpNews()) 295 else: 296 TextAreaControl = LevelUpWindow.GetControl(42) 297 TextAreaControl.SetText(GUIREC.GetStatOverview(pc, LevelDiff)) 298 299 RedrawSkills() 300 LevelUpWindow.ShowModal (MODAL_SHADOW_GRAY) 301 302 # if we have a sorcerer who can learn spells, we need to do spell selection 303 for c in range(NumClasses): 304 if Spellbook.HasSorcererBook (pc, Classes[c]) and DeltaWSpells > 0: 305 LUSpellSelection.OpenSpellsWindow (pc, "SPLSRCKN", Level[c], LevelDiff[c]) 306 307def HideSkills(i): 308 """Hides the given skill label from view.""" 309 global LevelUpWindow 310 311 Label = LevelUpWindow.GetControl (0x10000000+32+i) 312 Label.SetText ("") 313 Button1 = LevelUpWindow.GetControl(i*2+17) 314 Button1.SetState(IE_GUI_BUTTON_DISABLED) 315 Button1.SetFlags(IE_GUI_BUTTON_NO_IMAGE,OP_OR) 316 Button2 = LevelUpWindow.GetControl(i*2+18) 317 Button2.SetState(IE_GUI_BUTTON_DISABLED) 318 Button2.SetFlags(IE_GUI_BUTTON_NO_IMAGE,OP_OR) 319 Label = LevelUpWindow.GetControl(0x10000000+43+i) 320 Label.SetText("") 321 322def RedrawSkills(): 323 """Redraws the entire window. 324 325 Called whenever a state changes, such as a proficiency or skill being 326 added or taken away.""" 327 328 global DoneButton, LevelUpWindow, HLACount 329 330 # we need to disable the HLA button if we don't have any HLAs left 331 HLACount = GemRB.GetVar ("HLACount") 332 if GameCheck.IsBG2() and HLACount == 0: 333 # turn the HLA button off 334 HLAButton = LevelUpWindow.GetControl (126) 335 HLAButton.SetState(IE_GUI_BUTTON_DISABLED) 336 337 # enable the done button if they've allocated all points 338 # sorcerer spell selection (if applicable) comes after hitting the done button 339 ProfPointsLeft = GemRB.GetVar ("ProfsPointsLeft") 340 SkillPointsLeft = GemRB.GetVar ("SkillPointsLeft") 341 if ProfPointsLeft == 0 and SkillPointsLeft == 0 and HLACount == 0: 342 DoneButton.SetState (IE_GUI_BUTTON_ENABLED) 343 else: 344 DoneButton.SetState (IE_GUI_BUTTON_DISABLED) 345 return 346 347def GetLevelUpNews(): 348 """Returns a string containing improvements gain on level up. 349 350 These include: HP, spells per level, and lore, among others.""" 351 352 News = GemRB.GetString (5259) + '\n\n' 353 354 # display if our class has been reactivated 355 if IsDual: 356 if (Level[0] - LevelDiff[0]) <= Level[1] and Level[0] > Level[1]: 357 News = GemRB.GetString (5261) + '\n\n' 358 359 # 5271 - Additional weapon proficiencies 360 if NewProfPoints > 0: 361 News += GemRB.GetString (5271) + ": " + str(NewProfPoints) + '\n\n' 362 363 # temps to compare all our new saves against (we get the best of our saving throws) 364 LOHGain = 0 365 BackstabMult = 0 366 367 for i in range(NumClasses): 368 # get the class name 369 TmpClassName = GUICommon.GetClassRowName (Classes[i], "class") 370 371 # backstab 372 # NOTE: Stalkers and assassins should get the correct mods at the correct levels based 373 # on AP_SPCL332 in their respective CLAB files. 374 # APND: Stalkers appear to get the correct mod at the correct levels; however, because they start 375 # at backstab multi x1, they are x1 too many at their respective levels. 376 if Classes[i] == 4 and GemRB.GetPlayerStat (pc, IE_BACKSTABDAMAGEMULTIPLIER, 1) > 1: # we have a thief who can backstab (2 at level 1) 377 # save the backstab multiplier if we have a thief 378 BackstabTable = GemRB.LoadTable ("BACKSTAB") 379 BackstabMult = BackstabTable.GetValue (0, Level[i]) 380 381 # lay on hands 382 LOHTable = CommonTables.ClassSkills.GetValue (TmpClassName, "LAYHANDS") 383 if LOHTable != "*": 384 # inquisitors and undead hunters don't get lay on hands out the chute, whereas cavaliers 385 # and unkitted paladins do; therefore, we check for the existence of lay on hands to ensure 386 # the character should get the new value; LoH is defined in GA_SPCL211 if anyone wants to 387 # make a pally kit with LoH 388 if (Spellbook.HasSpell (pc, IE_SPELL_TYPE_INNATE, 0, "SPCL211") >= 0): 389 LOHTable = GemRB.LoadTable (LOHTable) 390 LOHGain = LOHTable.GetValue (0, Level[i]) - LOHTable.GetValue (0, Level[i]-LevelDiff[i]) 391 392 # saving throws 393 # 5277 death 394 # 5278 wand 395 # 5279 polymorph 396 # 5282 breath 397 # 5292 spell 398 # include in news if the save is updated 399 Changed = 0 400 for i in range (5): 401 CurrentSave = GemRB.GetPlayerStat (pc, IE_SAVEVSDEATH+i, 1) 402 SaveString = 5277+i 403 if i == 3: 404 SaveString = 5282 405 elif i == 4: 406 SaveString = 5292 407 408 if CurrentSave < OldSaves[i]: 409 News += GemRB.GetString (SaveString) + ": " + str(OldSaves[i]-CurrentSave) + '\n' 410 Changed = 1 411 if Changed: 412 News += '\n' 413 414 # 5305 - THAC0 Reduced by 415 # only output if there is a change in thaco 416 NewThaco = GemRB.GetPlayerStat (pc, IE_TOHIT, 1) 417 if (NewThaco < OldThaco): 418 News += GemRB.GetString (5305) + ": " + str(OldThaco-NewThaco) + '\n\n' 419 420 # new spell slots 421 # 5373 - Additional Priest Spells 422 # 5374 - Additional Mage Spells 423 # 61269 - Level <LEVEL> Spells 424 if DeltaDSpells > 0: # new divine spells 425 News += GemRB.GetString (5373) + '\n' 426 for i in range (len (NewDSpells)): 427 # only display classes with new spells 428 if (NewDSpells[i]-OldDSpells[i]) == 0: 429 continue 430 GemRB.SetToken("level", str(i+1)) 431 News += GemRB.GetString(61269)+": " + str(NewDSpells[i]-OldDSpells[i]) + '\n' 432 News += '\n' 433 if DeltaWSpells > 0: # new wizard spells 434 News += GemRB.GetString (5374) + '\n' 435 for i in range (len (NewWSpells)): 436 # only display classes with new spells 437 if (NewWSpells[i]-OldWSpells[i]) == 0: 438 continue 439 GemRB.SetToken("level", str(i+1)) 440 News += GemRB.GetString(61269)+": " + str(NewWSpells[i]-OldWSpells[i]) + '\n' 441 News += '\n' 442 443 # 5375 - Backstab Multiplier Increased by 444 # this auto-updates... we just need to inform of the update 445 BSGain = BackstabMult - GemRB.GetPlayerStat (pc, IE_BACKSTABDAMAGEMULTIPLIER, 1) 446 if (BSGain > 0): 447 News += GemRB.GetString (5375) + ": " + str(BSGain) + '\n\n' 448 449 # 5376 - Lay on Hands increased 450 if LOHGain > 0: 451 News += GemRB.GetString (5376) + ": " + str(LOHGain) + '\n\n' 452 453 # 5293 - HP increased by 454 if (OldHPMax != GemRB.GetPlayerStat (pc, IE_MAXHITPOINTS, 1)): 455 News += GemRB.GetString (5293) + ": " + str(GemRB.GetPlayerStat (pc, IE_MAXHITPOINTS, 1) - OldHPMax) + '\n' 456 457 # 5377 - Lore Increased by 458 # add the lore gain if we haven't done so already 459 NewLore = GemRB.GetPlayerStat (pc, IE_LORE, 1) 460 if NewLore > OldLore: 461 News += GemRB.GetString (5377) + ": " + str(NewLore-OldLore) + '\n\n' 462 463 # 5378 - Additional Skill Points 464 # ranger and bard skill(point) gain is not mentioned here in the original 465 if NewSkillPoints > 0: 466 News += GemRB.GetString (5378) + ": " + str(NewSkillPoints) + '\n' 467 468 return News 469 470def LevelUpInfoPress(): 471 """Displays new abilites gained on level up. 472 473 Alternates between overall and modified stats.""" 474 import GUIREC 475 global LevelUpWindow, TextAreaControl, InfoCounter, LevelDiff 476 477 if InfoCounter % 2: 478 # call GetStatOverview with the new levels, so the future overview is shown 479 # TODO: show only xp, levels, thac0, #att, lore, reputation, backstab, saving throws 480 TextAreaControl.SetText(GUIREC.GetStatOverview(pc, LevelDiff)) 481 else: 482 TextAreaControl.SetText(GetLevelUpNews()) 483 InfoCounter += 1 484 return 485 486# save the results 487def LevelUpDonePress(): 488 """Updates the PC with the new choices. 489 490 Closes the window when finished.""" 491 import GUICommonWindows 492 import GUIREC 493 494 # proficiencies 495 LUProfsSelection.ProfsSave (pc) 496 497 # skills 498 LUSkillsSelection.SkillsSave (pc) 499 500 # level 501 if DualSwap: # swap the IE_LEVELs around if a backward dual 502 GemRB.SetPlayerStat (pc, IE_LEVEL2, Level[0]) 503 GemRB.SetPlayerStat (pc, IE_LEVEL, Level[1]) 504 else: 505 GemRB.SetPlayerStat (pc, IE_LEVEL, Level[0]) 506 GemRB.SetPlayerStat (pc, IE_LEVEL2, Level[1]) 507 GemRB.SetPlayerStat (pc, IE_LEVEL3, Level[2]) 508 509 print("Levels:", Level[0], "/", Level[1], "/", Level[2]) 510 511 # spells 512 SaveNewSpells() 513 514 # hlas 515 # level, xp and other stuff by the core? 516 517 # 5261 - Regained abilities from inactive class 518 if IsDual: # we're dual classed 519 print("activation?") 520 if (Level[0] - LevelDiff[0]) <= Level[1] and Level[0] > Level[1]: # our new classes now surpasses our old class 521 print("reactivating base class") 522 ReactivateBaseClass () 523 524 if LevelUpWindow: 525 LevelUpWindow.Close() 526 GUICommonWindows.UpdatePortraitWindow () 527 return 528 529def LevelUpHLAPress (): 530 """Opens the HLA selection window.""" 531 532 # we can turn the button off and temporarily set HLACount to 0 533 # because there is no cancel button on the HLA window; therefore, 534 # it's guaranteed to come back as 0 535 TmpCount = GemRB.GetVar ("HLACount") 536 GemRB.SetVar ("HLACount", 0) 537 RedrawSkills () 538 GemRB.SetVar ("HLACount", TmpCount) 539 540 LUHLASelection.OpenHLAWindow (pc, NumClasses, Classes, Level) 541 return 542 543def ReactivateBaseClass (): 544 """Regains all abilities of the base dual-class. 545 546 Proficiencies, THACO, saves, spells, and innate abilites, 547 most noteably.""" 548 549 # we construct the Classes array, so that the active class is always first and the base is second 550 ClassName = GUICommon.GetClassRowName (Classes[1], "class") 551 552 # force reinitialization of the actionbar by forcing the PCF to run 553 ClassID = GemRB.GetPlayerStat (pc, IE_CLASS) 554 GemRB.SetPlayerStat (pc, IE_CLASS, 0, 0) 555 GemRB.SetPlayerStat (pc, IE_CLASS, ClassID) 556 557 # reactivate all our proficiencies 558 TmpTable = GemRB.LoadTable ("weapprof") 559 ProfsTableOffset = 0 560 if GameCheck.IsBG2 (): 561 ProfsTableOffset = 8 # skip bg1 weapprof.2da proficiencies 562 ProfCount = TmpTable.GetRowCount () - ProfsTableOffset 563 for i in range(ProfCount): 564 ProfID = TmpTable.GetValue (i+ProfsTableOffset, 0) 565 if GameCheck.IsBG1(): 566 ProfID = ProfID + IE_PROFICIENCYBASTARDSWORD 567 Value = GemRB.GetPlayerStat (pc, ProfID) 568 OldProf = (Value & 0x38) >> 3 569 NewProf = Value & 0x07 570 if OldProf > NewProf: 571 Value = (OldProf << 3) | OldProf 572 print("Value:", Value) 573 if GameCheck.IsBG2(): 574 GemRB.ApplyEffect (pc, "Proficiency", Value, ProfID ) 575 else: 576 GemRB.SetPlayerStat (pc, ProfID, Value) 577 578 # see if this thac0 is lower than our current thac0 579 ThacoTable = GemRB.LoadTable ("THAC0") 580 TmpThaco = ThacoTable.GetValue(Classes[1]-1, Level[1]-1, GTV_INT) 581 if TmpThaco < GemRB.GetPlayerStat (pc, IE_TOHIT, 1): 582 GemRB.SetPlayerStat (pc, IE_TOHIT, TmpThaco) 583 584 # see if all our saves are lower than our current saves 585 SavesTable = CommonTables.Classes.GetValue (ClassName, "SAVE", GTV_STR) 586 SavesTable = GemRB.LoadTable (SavesTable) 587 for i in range (5): 588 # see if this save is lower than our old save 589 TmpSave = SavesTable.GetValue (i, Level[1]-1) 590 if TmpSave < GemRB.GetPlayerStat (pc, IE_SAVEVSDEATH+i, 1): 591 GemRB.SetPlayerStat (pc, IE_SAVEVSDEATH+i, TmpSave) 592 593 # see if we're a caster 594 SpellTables = [CommonTables.ClassSkills.GetValue (ClassName, "DRUIDSPELL", GTV_STR), CommonTables.ClassSkills.GetValue (ClassName, "CLERICSPELL", GTV_STR), CommonTables.ClassSkills.GetValue (ClassName, "MAGESPELL", GTV_STR)] 595 if SpellTables[2] != "*": # casts mage spells 596 # set up our memorizations 597 SpellTable = GemRB.LoadTable (SpellTables[2]) 598 for i in range (9): 599 # if we can cast more spells at this level (should be always), then update 600 NumSpells = SpellTable.GetValue (Level[1]-1, i) 601 if NumSpells > GemRB.GetMemorizableSpellsCount (pc, IE_SPELL_TYPE_WIZARD, i, 1): 602 GemRB.SetMemorizableSpellsCount (pc, NumSpells, IE_SPELL_TYPE_WIZARD, i) 603 elif SpellTables[1] != "*" or SpellTables[0] != "*": # casts priest spells 604 # get the correct table and mask 605 if SpellTables[1] != "*": # clerical spells 606 SpellTable = GemRB.LoadTable (SpellTables[1]) 607 ClassMask = 0x4000 608 else: # druidic spells 609 if not GemRB.HasResource(SpellTables[0], RES_2DA): 610 SpellTables[0] = "MXSPLPRS" 611 SpellTable = GemRB.LoadTable (SpellTables[0]) 612 ClassMask = 0x8000 613 614 # loop through each spell level 615 for i in range (7): 616 # update if we can cast more spells at this level 617 NumSpells = SpellTable.GetValue (str(Level[1]), str(i+1), GTV_INT) 618 if not NumSpells: 619 continue 620 if NumSpells > GemRB.GetMemorizableSpellsCount (pc, IE_SPELL_TYPE_PRIEST, i, 1): 621 GemRB.SetMemorizableSpellsCount (pc, NumSpells, IE_SPELL_TYPE_PRIEST, i) 622 623 # also re-learn the spells if we have to 624 # WARNING: this fixes the error whereby rangers dualed to clerics still got all druid spells 625 # they will now only get druid spells up to the level they could cast 626 # this should probably be noted somewhere (ranger/cleric multis still function the same, 627 # but that could be remedied if desired) 628 Learnable = Spellbook.GetLearnablePriestSpells(ClassMask, GemRB.GetPlayerStat (pc, IE_ALIGNMENT), i+1) 629 for k in range (len (Learnable)): # loop through all the learnable spells 630 if Spellbook.HasSpell (pc, IE_SPELL_TYPE_PRIEST, i, Learnable[k]) < 0: # only write it if we don't yet know it 631 GemRB.LearnSpell(pc, Learnable[k]) 632 633def GetNewSpells(actor, Classes, Level, LevelDiff, Kit=0): 634 '''Scan each class for new spells. Values are stored in the global variables''' 635 636 global DeltaDSpells, DeltaWSpells, NewDSpells, NewWSpells, OldDSpells, OldWSpells 637 638 # clear the globals, since we may get called multiple times with different classes 639 HaveCleric = 0 640 DeltaWSpells = 0 641 DeltaDSpells = 0 642 OldDSpells = [0]*7 643 OldWSpells = [0]*9 644 NewDSpells = [0]*7 645 NewWSpells = [0]*9 646 647 # run through each class to detect new spells 648 for i in range(len(Classes)): 649 650 TmpClassName = GUICommon.GetClassRowName (Classes[i], "class") 651 652 # save our current and next spell amounts 653 StartLevel = Level[i] - LevelDiff[i] 654 DruidTable = CommonTables.ClassSkills.GetValue (TmpClassName, "DRUIDSPELL", GTV_STR) 655 ClericTable = CommonTables.ClassSkills.GetValue (TmpClassName, "CLERICSPELL", GTV_STR) 656 MageTable = CommonTables.ClassSkills.GetValue (TmpClassName, "MAGESPELL", GTV_STR) 657 658 # see if we have mage spells 659 if MageTable != "*": 660 # we get 1 extra spell per level if we're a specialist 661 Specialist = 0 662 if CommonTables.KitList.GetValue (Kit, 7) == 1: # see if we're a kitted mage 663 Specialist = 1 664 665 if Spellbook.HasSorcererBook (actor, Classes[i]): 666 MageTable = "SPLSRCKN" 667 668 MageTable = GemRB.LoadTable (MageTable) 669 # loop through each spell level and save the amount possible to cast (current) 670 for j in range (MageTable.GetColumnCount ()): 671 NewWSpells[j] = MageTable.GetValue (str(Level[i]), str(j+1), GTV_INT) 672 OldWSpells[j] = MageTable.GetValue (str(StartLevel), str(j+1), GTV_INT) 673 if NewWSpells[j] > 0: # don't want specialist to get 1 in levels they should have 0 674 NewWSpells[j] += Specialist 675 if OldWSpells[j] > 0: 676 OldWSpells[j] += Specialist 677 DeltaWSpells = sum(NewWSpells)-sum(OldWSpells) 678 elif ClericTable != "*": 679 # check for cleric spells 680 if not GemRB.HasResource(ClericTable, RES_2DA, 1): 681 ClericTable = "MXSPLPRS" # iwd1 doesn't have a DRUIDSPELL column in the table 682 ClericTable = GemRB.LoadTable (ClericTable) 683 HaveCleric = 1 684 # same as above 685 for j in range (ClericTable.GetColumnCount ()): 686 NewDSpells[j] = ClericTable.GetValue (str(Level[i]), str(j+1), GTV_INT) 687 OldDSpells[j] = ClericTable.GetValue (str(StartLevel), str(j+1), GTV_INT) 688 DeltaDSpells = sum(NewDSpells)-sum(OldDSpells) 689 elif DruidTable != "*": 690 # clerics have precedence in multis (ranger/cleric) 691 if HaveCleric == 0: 692 #use MXSPLPRS if we can't find the resource (SoA fix) 693 if not GemRB.HasResource (DruidTable, RES_2DA): 694 DruidTable = "MXSPLPRS" 695 696 # check druid spells 697 DruidTable = GemRB.LoadTable (DruidTable) 698 # same as above 699 for j in range (DruidTable.GetColumnCount ()): 700 NewDSpells[j] = DruidTable.GetValue (str(Level[i]), str(j+1), GTV_INT) 701 OldDSpells[j] = DruidTable.GetValue (str(StartLevel), str(j+1), GTV_INT) 702 DeltaDSpells = sum(NewDSpells)-sum(OldDSpells) 703 704def SaveNewSpells(): 705 # save our number of memorizable spells per level 706 if DeltaWSpells > 0: 707 # loop through each wizard spell level 708 for i in range(len(NewWSpells)): 709 if NewWSpells[i] > 0: # we have new spells, so update 710 GemRB.SetMemorizableSpellsCount(pc, NewWSpells[i], IE_SPELL_TYPE_WIZARD, i) 711 712 # save our number of memorizable priest spells 713 if DeltaDSpells > 0: # druids and clerics count 714 for i in range (len(NewDSpells)): 715 # get each update 716 if NewDSpells[i] > 0: 717 GemRB.SetMemorizableSpellsCount (pc, NewDSpells[i], IE_SPELL_TYPE_PRIEST, i) 718 719 # learn all the spells we're given, but don't have, up to our given casting level 720 # bonus spells don't count in determining if we can use this level 721 if GemRB.GetMemorizableSpellsCount (pc, IE_SPELL_TYPE_PRIEST, i, 0) > 0: # we can memorize spells of this level 722 for j in range(NumClasses): # loop through each class 723 TmpClassName = GUICommon.GetClassRowName (Classes[j], "class") 724 IsDruid = CommonTables.ClassSkills.GetValue (TmpClassName, "DRUIDSPELL", GTV_STR) 725 IsCleric = CommonTables.ClassSkills.GetValue (TmpClassName, "CLERICSPELL", GTV_STR) 726 if IsCleric == "*" and IsDruid == "*": # no divine spells (so mage/cleric multis don't screw up) 727 continue 728 elif IsCleric == "*": # druid spells 729 ClassFlag = 0x8000 730 else: # cleric spells 731 ClassFlag = 0x4000 732 733 Learnable = Spellbook.GetLearnablePriestSpells(ClassFlag, GemRB.GetPlayerStat (pc, IE_ALIGNMENT), i+1) 734 for k in range(len(Learnable)): # loop through all the learnable spells 735 if Spellbook.HasSpell (pc, IE_SPELL_TYPE_PRIEST, i, Learnable[k]) < 0: # only write it if we don't yet know it 736 GemRB.LearnSpell(pc, Learnable[k]) 737