2 # GemRB - Infinity Engine Emulator
3 # Copyright (C) 2003-2004 The GemRB Project
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.
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.
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.
21 from GUIDefines
import *
22 from ie_stats
import *
23 from ie_restype
import RES_2DA
26 import LUSpellSelection
27 import LUProfsSelection
28 import LUSkillsSelection
30 #######################
39 #######################
42 DCMainSkillsButton
= 0
45 #######################
50 #######################
53 #######################
55 DCSkillsDoneButton
= 0
56 #######################
58 def DualClassWindow ():
59 """Opens the dual class selection window."""
61 global pc
, OldClassName
, NewMageSpells
, NewPriestMask
, NewClassId
, OldKitName
, DualClassTable
62 global DCMainWindow
, DCMainClassButton
, DCMainDoneButton
, DCMainSkillsButton
, DCMainStep
64 # get our basic globals
65 pc
= GemRB
.GameGetSelectedPCSingle ()
68 # make sure to nullify old values
73 # set up our main window
74 DCMainWindow
= GemRB
.LoadWindow (5)
77 DCMainDoneButton
= DCMainWindow
.GetControl (2)
78 DCMainDoneButton
.SetText (11973)
79 DCMainDoneButton
.SetEvent (IE_GUI_BUTTON_ON_PRESS
, DCMainDonePress
)
80 DCMainDoneButton
.SetState (IE_GUI_BUTTON_DISABLED
)
81 DCMainDoneButton
.SetFlags (IE_GUI_BUTTON_DEFAULT
, OP_OR
)
84 DCMainCancelButton
= DCMainWindow
.GetControl (1)
85 DCMainCancelButton
.SetText (13727)
86 DCMainCancelButton
.SetEvent (IE_GUI_BUTTON_ON_PRESS
, DCMainCancelPress
)
87 DCMainCancelButton
.SetState (IE_GUI_BUTTON_ENABLED
)
88 DCMainCancelButton
.SetFlags (IE_GUI_BUTTON_DEFAULT
, OP_OR
)
91 DCMainClassButton
= DCMainWindow
.GetControl (3)
92 DCMainClassButton
.SetText (11959)
93 DCMainClassButton
.SetEvent (IE_GUI_BUTTON_ON_PRESS
, DCMainClassPress
)
94 DCMainClassButton
.SetState (IE_GUI_BUTTON_ENABLED
)
95 DCMainClassButton
.SetFlags (IE_GUI_BUTTON_DEFAULT
, OP_OR
)
98 DCMainSkillsButton
= DCMainWindow
.GetControl (4)
99 DCMainSkillsButton
.SetText (17372)
100 DCMainSkillsButton
.SetEvent (IE_GUI_BUTTON_ON_PRESS
, DCMainSkillsPress
)
101 DCMainSkillsButton
.SetState (IE_GUI_BUTTON_DISABLED
)
102 DCMainSkillsButton
.SetFlags (IE_GUI_BUTTON_DEFAULT
, OP_OR
)
105 DCMainBackButton
= DCMainWindow
.GetControl (5)
106 if GUICommon
.GameIsBG2():
107 DCMainBackButton
.SetText (15416)
108 DCMainBackButton
.SetEvent (IE_GUI_BUTTON_ON_PRESS
, DCMainBackPress
)
109 DCMainBackButton
.SetState (IE_GUI_BUTTON_ENABLED
)
110 DCMainBackButton
.SetFlags (IE_GUI_BUTTON_DEFAULT
, OP_OR
)
112 # picture of character
113 DCMainPictureButton
= DCMainWindow
.GetControl (6)
114 DCMainPictureButton
.SetState (IE_GUI_BUTTON_LOCKED
)
115 DCMainPictureButton
.SetFlags (IE_GUI_BUTTON_NO_IMAGE | IE_GUI_BUTTON_PICTURE
, OP_SET
)
116 DCMainPictureButton
.SetPicture (GemRB
.GetPlayerPortrait (pc
, 0), "NOPORTMD")
119 DCTextArea
= DCMainWindow
.GetControl (7)
120 DCTextArea
.SetText (10811)
123 DCLabel
= DCMainWindow
.GetControl (0x10000008)
124 DCLabel
.SetText (GemRB
.GetPlayerName (pc
, 0))
127 Kit
= GUICommon
.GetKitIndex (pc
)
128 OldClassName
= CommonTables
.Classes
.GetRowName (CommonTables
.Classes
.FindValue (5, GemRB
.GetPlayerStat (pc
, IE_CLASS
) ) )
130 OldKitName
= CommonTables
.KitList
.GetValue (Kit
, 0, 0)
132 OldKitName
= OldClassName
133 DCLabel
= DCMainWindow
.GetControl (0x10000009)
134 DCLabel
.SetText (GUICommon
.GetActorClassTitle (pc
))
136 # get the names of the classes we can dual to
137 DualClassTable
= GemRB
.LoadTable ("dualclas")
138 for i
in range (DualClassTable
.GetColumnCount ()):
139 DCClasses
.append (DualClassTable
.GetColumnName (i
))
142 DCMainWindow
.ShowModal (MODAL_SHADOW_GRAY
)
145 def DCMainDonePress ():
146 """Saves our dualclass changes and closes the window.
148 This de-activates our old class and readjusts the basic actor stats, such as
149 THAC0, spell casting, proficiencies, and so forth, to the new class."""
152 # save our proficiencies
153 LUProfsSelection
.ProfsSave (pc
, LUProfsSelection
.LUPROFS_TYPE_DUALCLASS
)
155 # remove old class abilities
156 KitIndex
= GUICommon
.GetKitIndex (pc
)
158 ABTable
= CommonTables
.KitList
.GetValue (str(KitIndex
), "ABILITIES")
160 ABTable
= CommonTables
.ClassSkills
.GetValue (OldClassName
, "ABILITIES")
161 if ABTable
!= "*" and GemRB
.HasResource (ABTable
, RES_2DA
, 1):
162 GUICommon
.RemoveClassAbilities (pc
, ABTable
, GemRB
.GetPlayerStat (pc
, IE_LEVEL
))
164 # remove old class casting
165 if not NewMageSpells
:
167 GemRB
.SetMemorizableSpellsCount (pc
, 0, IE_SPELL_TYPE_WIZARD
, i
)
168 GUICommon
.RemoveKnownSpells (pc
, IE_SPELL_TYPE_PRIEST
, 1,7, 1)
170 # apply our class abilities
171 ABTable
= CommonTables
.ClassSkills
.GetValue (ClassName
, "ABILITIES")
172 if ABTable
!= "*" and GemRB
.HasResource (ABTable
, RES_2DA
, 1):
173 GUICommon
.AddClassAbilities (pc
, ABTable
)
175 # learn our new priest spells
177 GUICommon
.LearnPriestSpells (pc
, 1, NewPriestMask
)
178 GemRB
.SetMemorizableSpellsCount (pc
, 1, IE_SPELL_TYPE_PRIEST
, 0)
180 # save our thief skills if we have them
181 LUSkillsSelection
.SkillsSave (pc
)
183 # save our new class and say was multi
184 OldClassId
= GemRB
.GetPlayerStat (pc
, IE_CLASS
)
185 MultClassId
= (1 << (NewClassId
-1)) |
(1 << (OldClassId
-1))
186 MultClassId
= CommonTables
.Classes
.FindValue (4, MultClassId
)
187 MultClassId
= CommonTables
.Classes
.GetValue (MultClassId
, 5)
188 GemRB
.SetPlayerStat (pc
, IE_CLASS
, MultClassId
)
189 GemRB
.SetPlayerStat (pc
, IE_MC_FLAGS
, CommonTables
.Classes
.GetValue (OldClassName
, "MC_WAS_ID", 1))
191 # update our levels and xp
192 if GUICommon
.IsDualSwap (pc
):
193 GemRB
.SetPlayerStat (pc
, IE_LEVEL2
, 1)
195 GemRB
.SetPlayerStat (pc
, IE_LEVEL2
, GemRB
.GetPlayerStat (pc
, IE_LEVEL
), 0)
196 GemRB
.SetPlayerStat (pc
, IE_LEVEL
, 1)
197 GemRB
.SetPlayerStat (pc
, IE_XP
, 0)
200 ThacoTable
= GemRB
.LoadTable ("THAC0")
201 GemRB
.SetPlayerStat (pc
, IE_TOHIT
, ThacoTable
.GetValue (NewClassId
-1, 0, 1))
204 SavesTable
= CommonTables
.Classes
.GetValue (CommonTables
.Classes
.FindValue (5, NewClassId
), 3, 0)
205 SavesTable
= GemRB
.LoadTable (SavesTable
)
207 GemRB
.SetPlayerStat (pc
, IE_SAVEVSDEATH
+i
, SavesTable
.GetValue (i
, 0))
211 DCMainWindow
.Unload ()
212 GUIREC
.UpdateRecordsWindow()
215 def DCMainCancelPress ():
216 """Revert all changes and close the dual class window."""
218 # simulate pressing the back button until we get back to DCMainStep = 1
219 # to unset all things from the new class
220 while DCMainStep
> 1:
225 DCMainWindow
.Unload ()
229 def DCMainBackPress ():
230 """Reverts all current changes and reverts back to the previous step."""
231 global DCMainStep
, DCClass
, NewMageSpells
234 if DCMainStep
== 2: # class selected, wait to choose skills
235 # disable the skills button and re-enable the class button
236 # the class will be reset when the class button is clicked
237 DCMainSkillsButton
.SetState (IE_GUI_BUTTON_DISABLED
)
238 DCMainClassButton
.SetState (IE_GUI_BUTTON_ENABLED
)
242 elif DCMainStep
== 3: # skills selected
243 # re-enable our skills button
244 DCMainSkillsButton
.SetState (IE_GUI_BUTTON_ENABLED
)
246 # un-learn our spells and skills
248 GUICommon
.RemoveKnownSpells (pc
, IE_SPELL_TYPE_WIZARD
, 1,1, 1)
250 LUSkillsSelection
.SkillsNullify ()
258 def DCMainClassPress ():
259 """Opens the class selection window."""
261 global DCClassWindow
, DCClassDoneButton
, DCClass
263 # we default the class back down to -1
265 GemRB
.SetVar ("DCClass", DCClass
)
268 DCClassWindow
= GemRB
.LoadWindow (6)
270 # string refs for the given classes
272 for classname
in DCClasses
:
273 DCClassStrings
.append(CommonTables
.Classes
.GetValue (classname
, "NAME_REF", 1))
275 # setup the class buttons
277 # get the button and associate it with the correct var
278 DCClassButton
= DCClassWindow
.GetControl (i
+1)
279 DCClassButton
.SetEvent (IE_GUI_BUTTON_ON_PRESS
, DCClassSelect
)
280 DCClassButton
.SetVarAssoc ("DCClass", i
)
281 DCClassButton
.SetText (DCClassStrings
[i
])
282 DCClassButton
.SetFlags (IE_GUI_BUTTON_DEFAULT
, OP_OR
)
284 # enable only if we can dual into the given class
286 DCClassButton
.SetState (IE_GUI_BUTTON_ENABLED
)
288 DCClassButton
.SetState (IE_GUI_BUTTON_DISABLED
)
291 DCClassDoneButton
= DCClassWindow
.GetControl (8)
292 DCClassDoneButton
.SetText (11973)
293 DCClassDoneButton
.SetEvent (IE_GUI_BUTTON_ON_PRESS
, DCClassDonePress
)
294 DCClassDoneButton
.SetState (IE_GUI_BUTTON_DISABLED
)
295 DCClassDoneButton
.SetFlags (IE_GUI_BUTTON_DEFAULT
, OP_OR
)
298 DCClassBackButton
= DCClassWindow
.GetControl (7)
299 DCClassBackButton
.SetText (15416)
300 DCClassBackButton
.SetEvent (IE_GUI_BUTTON_ON_PRESS
, DCClassBackPress
)
301 DCClassBackButton
.SetState (IE_GUI_BUTTON_ENABLED
)
302 DCClassBackButton
.SetFlags (IE_GUI_BUTTON_DEFAULT
, OP_OR
)
304 # setup the text area with default text
305 DCClassTextArea
= DCClassWindow
.GetControl (9)
306 DCClassTextArea
.SetText (10949)
309 DCClassWindow
.ShowModal (MODAL_SHADOW_GRAY
)
313 def DCClassSelect ():
314 """Updates the current class based on the button pressed."""
318 # un-select the old button and save and select the new one
320 DCClassButton
= DCClassWindow
.GetControl (DCClass
+1)
321 DCClassButton
.SetState (IE_GUI_BUTTON_ENABLED
)
323 # if we clicked the same class twice, turn the done button off (toggled)
324 if DCClass
== GemRB
.GetVar ("DCClass"):
325 DCClassDoneButton
.SetState (IE_GUI_BUTTON_DISABLED
)
328 # don't need to worry about setting a new text area, as it would be the same
331 # save the new class, select it's button, and enable the done button
332 DCClass
= GemRB
.GetVar ("DCClass")
333 DCClassButton
= DCClassWindow
.GetControl (DCClass
+1)
334 DCClassButton
.SetState (IE_GUI_BUTTON_SELECTED
)
335 DCClassDoneButton
.SetState (IE_GUI_BUTTON_ENABLED
)
337 # all the possible strrefs for the different classes
339 for classname
in DCClasses
:
340 DCClassStrings
.append (CommonTables
.Classes
.GetValue (classname
, "DESC_REF", 1))
342 # update the text are with the new string
343 DCClassTextArea
= DCClassWindow
.GetControl (9)
344 DCClassTextArea
.SetText (DCClassStrings
[DCClass
])
348 def DCClassDonePress ():
349 """Stores the selected class and moves to the next step."""
351 global DCMainStep
, ClassName
, NewClassId
353 # unload our class selection window
355 DCClassWindow
.Unload ()
357 # enable the skills button and disable the class selection button
358 DCMainClassButton
.SetState (IE_GUI_BUTTON_DISABLED
)
359 DCMainSkillsButton
.SetState (IE_GUI_BUTTON_ENABLED
)
362 ClassName
= DCClasses
[DCClass
]
363 NewClassId
= CommonTables
.Classes
.GetValue (ClassName
, "ID", 1)
365 # set our step to 2 so that the back button knows where we are
370 def CanDualInto (index
):
371 """Determines if a given class can be dualed into.
373 Index defines the position within the DCClasses list."""
375 # make sure index isn't out of range
376 if index
< 0 or index
>= len (DCClasses
):
379 # return 0 if we can't dual into the class
380 if not DualClassTable
.GetValue (OldKitName
, DCClasses
[index
], 1):
383 # make sure we aren't restricted by alignment
384 AlignmentTable
= GemRB
.LoadTable ("alignmnt")
385 AlignsTable
= GemRB
.LoadTable ("aligns")
386 Alignment
= GemRB
.GetPlayerStat (pc
, IE_ALIGNMENT
) # our alignment
387 Alignment
= AlignsTable
.FindValue (3, Alignment
)
388 Alignment
= AlignsTable
.GetValue (Alignment
, 4) # convert the alignment
389 if not AlignmentTable
.GetValue (DCClasses
[index
], Alignment
, 1): # check it
392 # make sure we have the minimum stats required for the next class
393 StatTable
= GemRB
.LoadTable ("abdcdsrq")
394 ClassStatIndex
= StatTable
.GetRowIndex (DCClasses
[index
])
395 for stat
in range (6): # loop through each stat
396 minimum
= StatTable
.GetValue (ClassStatIndex
, stat
)
397 name
= StatTable
.GetColumnName (stat
)
398 if GemRB
.GetPlayerStat (pc
, eval("IE_" + name
[4:])) < minimum
: # see if we're under the minimum
401 # if we made it here, we can dual to the class
404 def DCClassBackPress ():
405 """Unloads the class selection window without making any changes."""
406 # close the class window
408 DCClassWindow
.Unload ()
411 def DCMainSkillsPress ():
412 """Opens the proficiency selection window.
414 Then follows the skills proficiency and spells windows, if required."""
416 global DCSkillsWindow
, DCMainStep
, DCHasProfs
418 # we're onto the next step
419 DCMainSkillsButton
.SetState (IE_GUI_BUTTON_DISABLED
)
425 def DCOpenProfsWindow ():
426 """Opens the proficiency selection window."""
428 global DCProfsWindow
, DCProfsDoneButton
430 # load up our window and set some basic variables
431 DCProfsWindow
= GemRB
.LoadWindow (15)
432 NewClassId
= CommonTables
.Classes
.GetValue (ClassName
, "ID", 1)
433 if GUICommon
.GameIsBG2():
434 LUProfsSelection
.SetupProfsWindow (pc
, \
435 LUProfsSelection
.LUPROFS_TYPE_DUALCLASS
, DCProfsWindow
, DCProfsRedraw
, classid
=NewClassId
)
437 LUProfsSelection
.SetupProfsWindow (pc
, \
438 LUProfsSelection
.LUPROFS_TYPE_DUALCLASS
, DCProfsWindow
, \
439 DCProfsRedraw
, [0,0,0], [1,1,1], NewClassId
, False, 0)
441 # setup the done and cancel
442 DCProfsDoneButton
= DCProfsWindow
.GetControl (76)
443 DCProfsDoneButton
.SetText (11973)
444 DCProfsDoneButton
.SetEvent (IE_GUI_BUTTON_ON_PRESS
, DCProfsDonePress
)
445 DCProfsDoneButton
.SetState (IE_GUI_BUTTON_DISABLED
)
446 DCProfsDoneButton
.SetFlags (IE_GUI_BUTTON_DEFAULT
, OP_OR
)
448 DCProfsCancelButton
= DCProfsWindow
.GetControl (77)
449 DCProfsCancelButton
.SetText (13727)
450 DCProfsCancelButton
.SetEvent (IE_GUI_BUTTON_ON_PRESS
, DCProfsCancelPress
)
451 DCProfsCancelButton
.SetState (IE_GUI_BUTTON_ENABLED
)
452 DCProfsCancelButton
.SetFlags (IE_GUI_BUTTON_DEFAULT
, OP_OR
)
454 # show the window and draw away
455 DCProfsWindow
.ShowModal (MODAL_SHADOW_GRAY
)
459 def DCProfsRedraw ():
460 """Redraws the proficiency selection window.
462 Called whenever a proficiency is assigned or removed."""
464 ProfsPointsLeft
= GemRB
.GetVar ("ProfsPointsLeft")
466 if ProfsPointsLeft
== 0:
467 DCProfsDoneButton
.SetState (IE_GUI_BUTTON_ENABLED
)
469 DCProfsDoneButton
.SetState (IE_GUI_BUTTON_DISABLED
)
472 def DCProfsDonePress ():
473 """Goes to the next applicable step.
475 This is either skill selection, spell selection, or nothing."""
477 global NewMageSpells
, NewPriestMask
479 # check for mage spells and thief skills
480 SpellTable
= CommonTables
.ClassSkills
.GetValue (ClassName
, "MAGESPELL")
481 ClericTable
= CommonTables
.ClassSkills
.GetValue (ClassName
, "CLERICSPELL")
482 DruidTable
= CommonTables
.ClassSkills
.GetValue (ClassName
, "DRUIDSPELL")
483 if SpellTable
!= "*":
484 # we go 2,2 to get an extra spell
485 # TODO: add a mod to the function instead?
486 LUSpellSelection
.OpenSpellsWindow (pc
, SpellTable
, 2, 2, 0)
487 SpellTable
= GemRB
.LoadTable (SpellTable
)
488 GemRB
.SetMemorizableSpellsCount (pc
, SpellTable
.GetValue (0, 0), IE_SPELL_TYPE_WIZARD
, 0)
490 if ClericTable
!= "*":
491 print "Setting PriestMask"
492 if not GemRB
.HasResource(ClericTable
, RES_2DA
, 1):
493 ClericTable
= "MXSPLPRS" # iwd1 doesn't have a DRUIDSPELL column in the table
494 # make sure we can cast spells at this level (paladins)
495 ClericTable
= GemRB
.LoadTable (ClericTable
)
496 if ClericTable
.GetRowName (0) == "1":
497 NewPriestMask
= 0x4000
498 elif DruidTable
!= "*":
499 # make sure we can cast spells at this level (rangers)
500 if GUICommon
.HasTOB ():
501 DruidTable
= GemRB
.LoadTable (DruidTable
)
502 if DruidTable
.GetRowName (0) == "1":
503 NewPriestMask
= 0x8000
505 NewPriestMask
= 0x8000
507 # open the thieves selection window
511 DCMainDoneButton
.SetState (IE_GUI_BUTTON_ENABLED
)
513 # close out the profs window (don't assign yet!)
515 DCProfsWindow
.Unload ()
518 def DCProfsCancelPress ():
519 """Closes the profeciency selection window."""
521 # close out the profs window and go back a step
523 DCProfsWindow
.Unload ()
528 def OpenSkillsWindow ():
529 """Opens the skills selection window.
531 This will allow the selection of thief skills for appropriate classes, or
532 auto-assign them for classes that recieve skills based on level."""
534 global DCSkillsWindow
, DCSkillsDoneButton
536 DCSkillsWindow
= GemRB
.LoadWindow (7)
537 if GUICommon
.GameIsBG2():
538 LUSkillsSelection
.SetupSkillsWindow (pc
, \
539 LUSkillsSelection
.LUSKILLS_TYPE_DUALCLASS
, DCSkillsWindow
, DCSkillsRedraw
, classid
=NewClassId
)
541 LUSkillsSelection
.SetupSkillsWindow (pc
, \
542 LUSkillsSelection
.LUSKILLS_TYPE_DUALCLASS
, DCSkillsWindow
, \
543 DCSkillsRedraw
, [0,0,0], [1,1,1], NewClassId
, False)
545 #just go back if we can't assign skills
546 if GemRB
.GetVar ("SkillPointsLeft") <= 0:
549 # setup the back and done buttons
550 BackButton
= DCSkillsWindow
.GetControl(24)
551 BackButton
.SetText(15416)
552 BackButton
.SetFlags (IE_GUI_BUTTON_CANCEL
, OP_OR
)
553 BackButton
.SetEvent(IE_GUI_BUTTON_ON_PRESS
,DCSkillsBackPress
)
555 DCSkillsDoneButton
= DCSkillsWindow
.GetControl(25)
556 DCSkillsDoneButton
.SetText(11973)
557 DCSkillsDoneButton
.SetFlags(IE_GUI_BUTTON_DEFAULT
,OP_OR
)
558 DCSkillsDoneButton
.SetEvent(IE_GUI_BUTTON_ON_PRESS
, DCSkillsDonePress
)
559 DCSkillsDoneButton
.SetState(IE_GUI_BUTTON_DISABLED
)
561 # setup the default text area
562 TextArea
= DCSkillsWindow
.GetControl(22)
563 TextArea
.SetText(17248)
565 DCSkillsWindow
.ShowModal (MODAL_SHADOW_GRAY
)
567 GemRB
.SetRepeatClickFlags(GEM_RK_DISABLE
, OP_NAND
)
570 def DCSkillsRedraw ():
571 """Redraws the skills selection window.
573 Called whenever a skill is assigned or removed."""
575 # no points left? we can be done! :)
576 DCSkillsLeft
= GemRB
.GetVar ("SkillPointsLeft")
577 if DCSkillsLeft
<= 0:
578 DCSkillsDoneButton
.SetState (IE_GUI_BUTTON_ENABLED
)
580 DCSkillsDoneButton
.SetState (IE_GUI_BUTTON_DISABLED
)
582 def DCSkillsBackPress ():
583 """Reverts all changes to this points."""
586 DCSkillsWindow
.Unload ()
587 LUSkillsSelection
.SkillsNullify ()
591 def DCSkillsDonePress ():
592 """Closes the skills selection window."""
595 DCSkillsWindow
.Unload ()
596 GemRB
.SetRepeatClickFlags (GEM_RK_DISABLE
, OP_OR
)