factored out the EFFv2 saving into EFFImporter
[gemrb.git] / gemrb / GUIScripts / LUProfsSelection.py
blob55be6e4c65ef67326494f00eb823a2df0c70096f
1 # -*-python-*-
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.
19 # LUProfsSelection.py - Modular selection of proficiencies
21 import GemRB
22 from GUIDefines import *
23 from ie_stats import *
24 import GUICommon
25 import CommonTables
27 #the different types possible
28 LUPROFS_TYPE_LEVELUP = 1
29 LUPROFS_TYPE_DUALCLASS = 2
30 LUPROFS_TYPE_CHARGEN = 4
32 #refs to the script calling this
33 ProfsWindow = 0
34 ProfsCallback = 0
36 #all our offsets for the various parts of the window
37 ProfsOffsetSum = 0
38 ProfsOffsetButton1 = 0
39 ProfsOffsetLabel = 0
40 ProfsOffsetStar = 0
41 ProfsOffsetPress = 0
42 Profs2ndOffsetButton1 = Profs2ndOffsetStar = Profs2ndOffsetLabel = -1
43 ClassNameSave = 0
44 OddIDs = 0
46 #internal variables
47 ProfsPointsLeft = 0
48 ProfsNumButtons = 0
49 ProfsTopIndex = 0
50 ProfsTextArea = 0
51 ProfsColumn = 0
52 ProfsTable = 0
53 ProfCount = 0
55 # the table offset is used in bg2, since in the end they made it use different
56 # profs than in bg1, but left the table entries intact
57 ProfsTableOffset = 0
58 ProfsScrollBar = None
60 # iwd1/bg1 table that holds the allowed proficiency <-> class mapping
61 ClassWeaponsTable = None
63 ProfsType = None
65 def SetupProfsWindow (pc, type, window, callback, level1=[0,0,0], level2=[1,1,1], classid=0, scroll=True, profTableOffset=8):
66 """Opens the proficiency selection window.
68 type specifies the type of selection we are doing; choices are above.
69 window specifies the window to be updated.
70 callback specifies the function to call on changes.
71 classid is sent only during dualclassing to specify the new class."""
73 global ProfsOffsetSum, ProfsOffsetButton1, ProfsOffsetLabel, ProfsOffsetStar, OddIDs
74 global ProfsOffsetPress, ProfsPointsLeft, ProfsNumButtons, ProfsTopIndex
75 global ProfsScrollBar, ProfsTableOffset, ProfsType
76 global ProfsWindow, ProfsCallback, ProfsTextArea, ProfsColumn, ProfsTable, ProfCount
77 global Profs2ndOffsetButton1, Profs2ndOffsetStar, Profs2ndOffsetLabel, ClassNameSave, ClassWeaponsTable
79 # make sure we're within ranges
80 GemRB.SetVar ("ProfsPointsLeft", 0)
81 if not window or not callback or len(level1)!=len(level2):
82 return
84 # save the values we'll point to
85 ProfsWindow = window
86 ProfsCallback = callback
87 ProfsTableOffset = profTableOffset
88 ProfsType = type
90 if type == LUPROFS_TYPE_CHARGEN and GUICommon.GameIsBG2(): #chargen
91 ProfsOffsetSum = 9
92 ProfsOffsetButton1 = 11
93 ProfsOffsetStar = 27
94 ProfsOffsetLabel = 1
95 ProfsOffsetPress = 69
96 ProfsNumButtons = 8
97 ProfsTextArea = ProfsWindow.GetControl (68)
98 ProfsTextArea.SetText (9588)
99 if (scroll):
100 ProfsScrollBar = ProfsWindow.GetControl (78)
101 elif type == LUPROFS_TYPE_CHARGEN and GUICommon.GameIsBG1(): #chargen
102 ProfsOffsetSum = 9
103 ProfsOffsetButton1 = 11
104 ProfsOffsetStar = 27
105 ProfsOffsetLabel = 1
106 ProfsOffsetPress = 69
107 ProfsNumButtons = 8
108 ProfsTextArea = ProfsWindow.GetControl (68)
109 ProfsTextArea.SetText (9588)
110 if (scroll):
111 ProfsScrollBar = ProfsWindow.GetControl (78)
112 elif type == LUPROFS_TYPE_LEVELUP and GUICommon.GameIsBG2(): #levelup
113 ProfsOffsetSum = 36
114 ProfsOffsetButton1 = 1
115 ProfsOffsetStar = 48
116 ProfsOffsetLabel = 24
117 ProfsOffsetPress = 112
118 ProfsNumButtons = 7
119 ProfsTextArea = ProfsWindow.GetControl (110)
120 ProfsScrollBar = ProfsWindow.GetControl (108)
121 elif type == LUPROFS_TYPE_LEVELUP and GUICommon.GameIsBG1(): #levelup
122 ProfsOffsetSum = 36
123 ProfsOffsetButton1 = 1
124 ProfsOffsetStar = 48
125 ProfsOffsetLabel = 24
126 ProfsOffsetPress = 17
127 ProfsNumButtons = 8
128 ProfsTextArea = ProfsWindow.GetControl (42)
129 if (scroll):
130 ProfsScrollBar = ProfsWindow.GetControl (108)
131 elif type == LUPROFS_TYPE_LEVELUP and GUICommon.GameIsIWD1(): #levelup
132 ProfsOffsetSum = 36
133 ProfsOffsetButton1 = 1
134 ProfsOffsetStar = 48
135 ProfsOffsetLabel = 24
136 ProfsOffsetPress = -1
137 ProfsNumButtons = 15 # 8+7, the 7 are done with the following vars
138 Profs2ndOffsetButton1 = 150
139 Profs2ndOffsetStar = 115
140 Profs2ndOffsetLabel = 108
141 ProfsTextArea = ProfsWindow.GetControl (42)
142 if (scroll):
143 ProfsScrollBar = ProfsWindow.GetControl (108)
144 OddIDs = 0
145 elif type == LUPROFS_TYPE_DUALCLASS and GUICommon.GameIsIWD1(): #dualclass
146 ProfsOffsetSum = 40
147 ProfsOffsetButton1 = 50
148 ProfsOffsetStar = 0
149 ProfsOffsetLabel = 41
150 ProfsOffsetPress = -1 #66
151 ProfsNumButtons = 15
152 Profs2ndOffsetButton1 = 78
153 Profs2ndOffsetStar = 92
154 Profs2ndOffsetLabel = 126
155 ProfsTextArea = ProfsWindow.GetControl (74)
156 ProfsTextArea.SetText (9588)
157 if (scroll):
158 ProfsScrollBar = ProfsWindow.GetControl (None)
159 OddIDs = 1
160 elif type == LUPROFS_TYPE_DUALCLASS and GUICommon.GameIsBG1(): #dualclass
161 ProfsOffsetSum = 40
162 ProfsOffsetButton1 = 50
163 ProfsOffsetStar = 0
164 ProfsOffsetLabel = 41
165 ProfsOffsetPress = -1 #FIXME
166 ProfsNumButtons = 8
167 ProfsTextArea = ProfsWindow.GetControl (74)
168 ProfsTextArea.SetText (9588)
169 if (scroll):
170 ProfsScrollBar = ProfsWindow.GetControl (None)
171 elif type == LUPROFS_TYPE_DUALCLASS: #dualclass
172 ProfsOffsetSum = 40
173 ProfsOffsetButton1 = 50
174 ProfsOffsetStar = 0
175 ProfsOffsetLabel = 41
176 ProfsOffsetPress = 66
177 ProfsNumButtons = 8
178 ProfsTextArea = ProfsWindow.GetControl (74)
179 ProfsTextArea.SetText (9588)
180 if (scroll):
181 ProfsScrollBar = ProfsWindow.GetControl (78)
182 else: #unknown
183 return
185 #nullify internal variables
186 GemRB.SetVar ("ProfsTopIndex", 0)
187 ProfsPointsLeft = 0
188 ProfsTopIndex = 0
190 ProfsTable = GemRB.LoadTable ("profs")
191 if GUICommon.GameIsIWD1() or GUICommon.GameIsBG1():
192 ClassWeaponsTable = GemRB.LoadTable ("clasweap")
193 else:
194 ClassWeaponsTable = None
196 #get the class name
197 IsDual = GUICommon.IsDualClassed (pc, 1)
198 if classid: #for dual classes when we can't get the class dualing to
199 Class = classid
200 elif IsDual[0]:
201 Class = CommonTables.Classes.GetValue (IsDual[2], 5)
202 else:
203 Class = GemRB.GetPlayerStat (pc, IE_CLASS)
204 ClassName = CommonTables.Classes.FindValue (5, Class)
205 ClassName = CommonTables.Classes.GetRowName (ClassName)
206 if ClassName == "SORCERER":
207 ClassName = "MAGE"
208 ClassNameSave = ClassName
210 #find the class with the greatest prof potential
211 FastestProf = 0
212 ProfsRate = 100
213 IsMulti = GUICommon.IsMultiClassed (pc, 1)
214 if IsMulti[0] > 1:
215 for i in range (1, IsMulti[0]+1):
216 TmpRate = ProfsTable.GetValue (IsMulti[i]-1, 1)
217 if TmpRate < ProfsRate:
218 ProfsRate = TmpRate
219 FastestProf = i-1
220 else:
221 ProfsRate = ProfsTable.GetValue (Class-1, 1)
223 #figure out how many prof points we have
224 if sum (level1) == 0: #character is being generated (either chargen or dual)
225 ProfsPointsLeft = ProfsTable.GetValue (ClassName, "FIRST_LEVEL")
227 #we need these 2 number to floor before subtracting
228 ProfsPointsLeft += level2[FastestProf]/ProfsRate - level1[FastestProf]/ProfsRate
230 #setup prof vars for passing between functions
231 ProfsTable = GemRB.LoadTable ("weapprof")
233 # if we have the classweapons table, use it
234 if ClassWeaponsTable:
235 ProfsColumn = ClassWeaponsTable.GetRowIndex (ClassName)
236 else:
237 Kit = GUICommon.GetKitIndex (pc)
238 if Kit and type != LUPROFS_TYPE_DUALCLASS and IsMulti[0]<2 and not IsDual[0]:
239 #if we do kit with dualclass, we'll get the old kit
240 #also don't want to worry about kitted multis
241 ProfsColumn = CommonTables.KitList.GetValue (Kit, 5)
242 else:
243 ProfsColumn = ProfsTable.GetColumnIndex (ClassName)
245 #setup some basic counts
246 RowCount = ProfsTable.GetRowCount () - ProfsTableOffset + 1
247 ProfCount = RowCount-ProfsNumButtons #decrease it with the number of controls
249 ProfsAssignable = 0
250 TwoWeapIndex = ProfsTable.GetRowIndex ("2WEAPON")
251 for i in range(RowCount):
252 ProfName = ProfsTable.GetValue (i+ProfsTableOffset, 1)
253 #decrease it with the number of invalid proficiencies
254 if ProfName > 0x1000000 or ProfName < 0:
255 ProfCount -= 1
257 #we only need the low 3 bits for profeciencies on levelup; otherwise
258 #we just set them all to 0
259 currentprof = 0
260 if type == LUPROFS_TYPE_LEVELUP:
261 stat = ProfsTable.GetValue (i+ProfsTableOffset, 0)
262 if GUICommon.GameIsBG1():
263 stat = stat + IE_PROFICIENCYBASTARDSWORD
264 currentprof = GemRB.GetPlayerStat (pc, stat)&0x07
265 else:
266 #rangers always get 2 points in 2 weapons style
267 if (i+ProfsTableOffset) == TwoWeapIndex and "RANGER" in ClassName.split("_"):
268 currentprof = 2
269 GemRB.SetVar ("Prof "+str(i), currentprof)
270 GemRB.SetVar ("ProfBase "+str(i), currentprof)
272 #see if we can assign to this prof
273 if ClassWeaponsTable:
274 maxprof = ClassWeaponsTable.GetValue (ProfsColumn, i) # this table has profs as rows
275 else:
276 maxprof = ProfsTable.GetValue(i+ProfsTableOffset, ProfsColumn)
277 if maxprof > currentprof:
278 ProfsAssignable += maxprof-currentprof
280 #correct the profs left if we can't assign that much
281 if ProfsPointsLeft > ProfsAssignable:
282 ProfsPointsLeft = ProfsAssignable
283 GemRB.SetVar ("ProfsPointsLeft", ProfsPointsLeft)
285 # setup the +/- and info controls
286 for i in range (ProfsNumButtons):
287 if ProfsOffsetPress != -1:
288 Button=ProfsWindow.GetControl(i+ProfsOffsetPress)
289 Button.SetVarAssoc("Prof", i)
290 Button.SetEvent(IE_GUI_BUTTON_ON_PRESS, ProfsJustPress)
292 cid = i*2+ProfsOffsetButton1
293 if Profs2ndOffsetButton1 != -1 and i > 7:
294 cid = (i-8)*2+Profs2ndOffsetButton1
296 Button=ProfsWindow.GetControl(cid)
297 Button.SetVarAssoc("Prof", i)
298 Button.SetEvent(IE_GUI_BUTTON_ON_PRESS, ProfsLeftPress)
300 Button=ProfsWindow.GetControl(cid+1)
301 Button.SetVarAssoc("Prof", i)
302 Button.SetEvent(IE_GUI_BUTTON_ON_PRESS, ProfsRightPress)
304 if(ProfsScrollBar):
305 # proficiencies scrollbar
306 ProfsScrollBar.SetEvent(IE_GUI_SCROLLBAR_ON_CHANGE, ProfsScrollBarPress)
307 ProfsScrollBar.SetDefaultScrollBar ()
308 ProfsScrollBar.SetVarAssoc ("ProfsTopIndex", ProfCount)
309 ProfsRedraw (1)
310 return
312 def ProfsRedraw (first=0):
313 """Redraws the proficiencies part of the window.
315 If first is true, it skips ahead to the first assignable proficiency."""
317 global ProfsTopIndex, ProfsScrollBar
319 ProfSumLabel = ProfsWindow.GetControl(0x10000000+ProfsOffsetSum)
320 ProfSumLabel.SetText(str(ProfsPointsLeft))
321 SkipProfs = []
323 for i in range(ProfsNumButtons):
324 Pos=ProfsTopIndex+i
325 ProfName = ProfsTable.GetValue(Pos+ProfsTableOffset, 1) #we add the bg1 skill count offset
326 if ClassWeaponsTable: # iwd
327 MaxProf = ClassWeaponsTable.GetValue (ClassNameSave, ProfsTable.GetRowName(Pos))
328 else:
329 MaxProf = ProfsTable.GetValue(Pos+ProfsTableOffset, ProfsColumn)
331 cid = i*2+ProfsOffsetButton1
332 if Profs2ndOffsetButton1 != -1 and i > 7:
333 cid = (i-8)*2+Profs2ndOffsetButton1
334 Button1=ProfsWindow.GetControl (cid)
335 Button2=ProfsWindow.GetControl (cid+1)
336 if MaxProf == 0:
337 Button1.SetState(IE_GUI_BUTTON_DISABLED)
338 Button2.SetState(IE_GUI_BUTTON_DISABLED)
339 Button1.SetFlags(IE_GUI_BUTTON_NO_IMAGE,OP_OR)
340 Button2.SetFlags(IE_GUI_BUTTON_NO_IMAGE,OP_OR)
341 if GUICommon.GameIsBG2() and (i==0 or ((i-1) in SkipProfs)):
342 SkipProfs.append (i)
343 else:
344 Button1.SetState(IE_GUI_BUTTON_ENABLED)
345 Button2.SetState(IE_GUI_BUTTON_ENABLED)
346 Button1.SetFlags(IE_GUI_BUTTON_NO_IMAGE,OP_NAND)
347 Button2.SetFlags(IE_GUI_BUTTON_NO_IMAGE,OP_NAND)
349 cid = 0x10000000 + ProfsOffsetLabel + i
350 if Profs2ndOffsetLabel != -1 and i > 7:
351 if OddIDs:
352 cid = 0x10000000 + Profs2ndOffsetLabel + 2*(i - 8)
353 else:
354 cid = 0x10000000 + Profs2ndOffsetLabel + i - 8
356 Label=ProfsWindow.GetControl (cid)
357 Label.SetText(ProfName)
359 ActPoint = GemRB.GetVar("Prof "+str(Pos) )
360 for j in range(5): #5 is maximum distributable
361 cid = i*5 + j + ProfsOffsetStar
362 if Profs2ndOffsetStar != -1 and i > 7:
363 cid = (i-8)*5 + j + Profs2ndOffsetStar
364 Star=ProfsWindow.GetControl (cid)
365 Star.SetSprites("GUIPFC", 0, 0, 0, 0, 0)
366 if ActPoint > j:
367 Star.SetFlags(IE_GUI_BUTTON_NO_IMAGE,OP_NAND)
368 else:
369 Star.SetFlags(IE_GUI_BUTTON_NO_IMAGE,OP_OR)
371 if first and len (SkipProfs):
372 ProfsTopIndex += SkipProfs[-1]+1
373 GemRB.SetVar ("ProfsTopIndex", ProfsTopIndex)
374 if (ProfsScrollBar):
375 ProfsScrollBar.SetVarAssoc ("ProfsTopIndex", ProfCount)
376 ProfsRedraw ()
377 return
379 def ProfsScrollBarPress():
380 """Scrolls the window by reassigning ProfsTopIndex."""
382 global ProfsTopIndex
384 ProfsTopIndex = GemRB.GetVar ("ProfsTopIndex")
385 ProfsRedraw ()
386 return
388 def ProfsJustPress():
389 """Updates the text area with a description of the proficiency."""
390 Pos = GemRB.GetVar ("Prof")+ProfsTopIndex
391 ProfsTextArea.SetText (ProfsTable.GetValue(Pos+ProfsTableOffset, 2) )
392 return
394 def ProfsRightPress():
395 """Decrease the current proficiency by one."""
397 global ProfsPointsLeft
399 Pos = GemRB.GetVar("Prof")+ProfsTopIndex
400 ProfsTextArea.SetText(ProfsTable.GetValue(Pos+ProfsTableOffset, 2) )
401 ActPoint = GemRB.GetVar("Prof "+str(Pos) )
402 MinPoint = GemRB.GetVar ("ProfBase "+str(Pos) )
403 if ActPoint <= 0 or ActPoint <= MinPoint:
404 return
405 GemRB.SetVar("Prof "+str(Pos),ActPoint-1)
406 ProfsPointsLeft += 1
407 GemRB.SetVar ("ProfsPointsLeft", ProfsPointsLeft)
408 ProfsRedraw ()
409 ProfsCallback ()
410 return
412 def ProfsLeftPress():
413 """Increases the current proficiency by one."""
415 global ProfsPointsLeft
417 Pos = GemRB.GetVar("Prof")+ProfsTopIndex
418 ProfsTextArea.SetText(ProfsTable.GetValue(Pos+ProfsTableOffset, 2) )
419 if ProfsPointsLeft == 0:
420 return
421 if GUICommon.GameIsIWD1() or GUICommon.GameIsBG1():
422 ProfMaxTable = GemRB.LoadTable ("profsmax")
423 MaxProf = ProfMaxTable.GetValue(ClassNameSave, "OTHER_LEVELS")
424 else:
425 MaxProf = ProfsTable.GetValue(Pos+ProfsTableOffset, ProfsColumn)
426 if MaxProf>5:
427 MaxProf = 5
428 # FIXME: use profsmax.2da (in all games? could be problematic for weapon styles)
429 #if (MaxProf>2) and GUICommon.GameIsBG1():
430 # MaxProf = 2
432 ActPoint = GemRB.GetVar("Prof "+str(Pos) )
433 if ActPoint >= MaxProf:
434 return
435 GemRB.SetVar("Prof "+str(Pos),ActPoint+1)
436 ProfsPointsLeft -= 1
437 GemRB.SetVar ("ProfsPointsLeft", ProfsPointsLeft)
438 ProfsRedraw ()
439 ProfsCallback ()
440 return
442 def ProfsSave (pc, type=LUPROFS_TYPE_LEVELUP):
443 """Updates the actor with the new proficiencies."""
445 ProfCount = ProfsTable.GetRowCount () - ProfsTableOffset
446 for i in range(ProfCount): # skip bg1 weapprof.2da proficiencies
447 ProfID = ProfsTable.GetValue (i+ProfsTableOffset, 0)
448 if GUICommon.GameIsBG1():
449 ProfID = ProfID + IE_PROFICIENCYBASTARDSWORD
450 SaveProf = GemRB.GetVar ("Prof "+str(i))
452 if type == LUPROFS_TYPE_CHARGEN and GUICommon.GameIsBG2():
453 GemRB.DispelEffect (pc, "Proficiency", ProfID)
454 else:
455 if type != LUPROFS_TYPE_DUALCLASS:
456 OldProf = GemRB.GetPlayerStat (pc, ProfID) & 0x38
457 SaveProf = OldProf | SaveProf
458 else: # gotta move the old prof to the back for dual class
459 OldProf = GemRB.GetPlayerStat (pc, ProfID) & 0x07
460 SaveProf = (OldProf << 3) | SaveProf
462 GemRB.SetPlayerStat (pc, ProfID, SaveProf)
463 if GUICommon.GameIsBG2() and (type == LUPROFS_TYPE_LEVELUP or type == LUPROFS_TYPE_CHARGEN):
464 if SaveProf:
465 GemRB.ApplyEffect (pc, "Proficiency", SaveProf, ProfID)
466 return
468 def ProfsNullify ():
469 """Resets all of the internal variables to 0."""
471 global ProfsTable
472 if not ProfsTable:
473 ProfsTable = GemRB.LoadTable ("weapprof")
474 for i in range (ProfsTable.GetRowCount()-ProfsTableOffset+1): #skip bg1 profs
475 GemRB.SetVar ("Prof "+str(i), 0)
476 GemRB.SetVar ("ProfBase "+str(i), 0)
477 return