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