1 # GemRB - Infinity Engine Emulator
2 # Copyright (C) 2003 The GemRB Project
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 #character generation, skills (GUICG6)
21 from GUIDefines
import *
22 from ie_stats
import *
38 # returns the number of feat levels (for example cleave can be taken twice)
39 def MultiLevelFeat(feat
):
41 return FeatReqTable
.GetValue(feat
, "MAX_LEVEL")
43 # FIXME: CheckFeatCondition doesn't check for higher level prerequisites
44 # (eg. cleave2 needs +4 BAB and weapon specialisation needs 4 fighter levels)
46 # NOTE: cleave formula is now:
47 # HITBONUS>=4 OR FEAT_CLEAVE<1
49 # specialisation formulas:
50 # FIGHTERLEVEL>=4 OR FEAT_*<2
51 # The default operator was set to 4 (greater or equal), so the majority of the formulas
52 # don't need any more change
55 def IsFeatUsable(feat
):
58 a_value
= FeatReqTable
.GetValue(feat
, "A_VALUE")
61 a_stat
= FeatReqTable
.GetValue(feat
, "A_STAT", 0)
64 a_stat
= FeatReqTable
.GetValue(feat
, "A_STAT",2)
65 b_stat
= FeatReqTable
.GetValue(feat
, "B_STAT",2)
66 c_stat
= FeatReqTable
.GetValue(feat
, "C_STAT",2)
67 d_stat
= FeatReqTable
.GetValue(feat
, "D_STAT",2)
68 b_value
= FeatReqTable
.GetValue(feat
, "B_VALUE")
69 c_value
= FeatReqTable
.GetValue(feat
, "C_VALUE")
70 d_value
= FeatReqTable
.GetValue(feat
, "D_VALUE")
71 a_op
= FeatReqTable
.GetValue(feat
, "A_OP")
72 b_op
= FeatReqTable
.GetValue(feat
, "B_OP")
73 c_op
= FeatReqTable
.GetValue(feat
, "C_OP")
74 d_op
= FeatReqTable
.GetValue(feat
, "D_OP")
75 slot
= GemRB
.GetVar("Slot")
77 return GemRB
.CheckFeatCondition(slot
, a_stat
, a_value
, b_stat
, b_value
, c_stat
, c_value
, d_stat
, d_value
, a_op
, b_op
, c_op
, d_op
)
79 # checks if a feat was granted due to class/kit/race and returns the number
80 # of granted levels. The bonuses aren't cumulative.
81 def GetBaseValue(feat
):
82 global FeatsClassColumn
, RaceColumn
, KitName
84 Val1
= FeatTable
.GetValue(feat
, FeatsClassColumn
)
85 Val2
= FeatTable
.GetValue(feat
, RaceColumn
)
92 # only cleric kits have feat bonuses in the original, but the column names are shortened
93 KitName
= KitName
.replace("CLERIC_","C_")
94 KitColumn
= FeatTable
.GetColumnIndex(KitName
)
96 Val3
= FeatTable
.GetValue(feat
, KitColumn
)
103 global TopIndex
, PointsLeft
, FeatWindow
, FeatReqTable
105 SumLabel
= FeatWindow
.GetControl(0x1000000c)
107 DoneButton
.SetState(IE_GUI_BUTTON_ENABLED
)
108 SumLabel
.SetTextColor(255, 255, 255)
110 DoneButton
.SetState(IE_GUI_BUTTON_DISABLED
)
111 SumLabel
.SetTextColor(255, 255, 0)
113 SumLabel
.SetText(str(PointsLeft
) )
115 for i
in range(0,10):
117 FeatName
= FeatTable
.GetValue(Pos
, 1)
118 Label
= FeatWindow
.GetControl(0x10000001+i
)
119 Label
.SetText(FeatName
)
121 FeatName
=FeatTable
.GetRowName(Pos
) #row name
122 FeatValue
= GemRB
.GetVar("Feat "+str(Pos
))
124 ButtonPlus
= FeatWindow
.GetControl(i
*2+14)
125 ButtonMinus
= FeatWindow
.GetControl(i
*2+15)
127 ButtonMinus
.SetState(IE_GUI_BUTTON_DISABLED
)
128 # check if feat is usable - can be taken
129 if IsFeatUsable(FeatName
):
130 ButtonPlus
.SetState(IE_GUI_BUTTON_ENABLED
)
131 Label
.SetTextColor(255, 255, 255)
133 ButtonPlus
.SetState(IE_GUI_BUTTON_DISABLED
)
134 Label
.SetTextColor(150, 150, 150)
136 # check for maximum if there are more feat levels
137 # FIXME also verify that the next level of the feat is usable
138 if MultiLevelFeat(FeatName
) > FeatValue
:
139 ButtonPlus
.SetState(IE_GUI_BUTTON_ENABLED
)
140 Label
.SetTextColor(255, 255, 255)
142 ButtonPlus
.SetState(IE_GUI_BUTTON_DISABLED
)
143 Label
.SetTextColor(150, 150, 150)
144 BaseValue
= GemRB
.GetVar("BaseFeatValue " + str(Pos
))
145 if FeatValue
> BaseValue
:
146 ButtonMinus
.SetState(IE_GUI_BUTTON_ENABLED
)
148 ButtonMinus
.SetState(IE_GUI_BUTTON_DISABLED
)
151 ButtonPlus
.SetState(IE_GUI_BUTTON_DISABLED
)
152 Label
.SetTextColor(150, 150, 150)
154 levels
= FeatReqTable
.GetValue(FeatName
, "MAX_LEVEL")
155 FeatValueCounter
= FeatValue
156 # count backwards, since the controls follow each other in rtl order,
157 # while we need to change the bams in ltr order
158 for j
in range(4, -1, -1):
159 Star
= FeatWindow
.GetControl(i
*5+j
+36)
160 if 5 - j
- 1 < levels
:
161 # the star should be there, but which one?
162 if FeatValueCounter
> 0:
163 # the full one - the character has already taken a level of this feat
164 Star
.SetState(IE_GUI_BUTTON_LOCKED
)
165 Star
.SetBAM("GUIPFC", 0, 0, -1)
166 Star
.SetFlags(IE_GUI_BUTTON_PICTURE
, OP_OR
)
167 FeatValueCounter
= FeatValueCounter
- 1
169 # the empty one - the character hasn't taken any levels of this feat yet
170 Star
.SetState(IE_GUI_BUTTON_LOCKED
)
171 Star
.SetBAM("GUIPFC", 0, 1, -1)
172 Star
.SetFlags(IE_GUI_BUTTON_PICTURE
, OP_OR
)
174 # no star, no bad bam crap
175 Star
.SetState(IE_GUI_BUTTON_DISABLED
)
176 Star
.SetFlags(IE_GUI_BUTTON_NO_IMAGE
, OP_OR
)
177 Star
.SetFlags(IE_GUI_BUTTON_PICTURE
, OP_NAND
)
180 def ScrollBarPress():
183 TopIndex
= GemRB
.GetVar("TopIndex")
188 global FeatWindow
, TextAreaControl
, DoneButton
, TopIndex
189 global FeatTable
, FeatReqTable
190 global KitName
, Level
, PointsLeft
191 global ClassColumn
, KitColumn
, RaceColumn
, FeatsClassColumn
193 GemRB
.SetVar("Level",1) #for simplicity
195 Race
= GemRB
.GetVar("Race")
196 RaceColumn
= CommonTables
.Races
.FindValue(3, Race
)
197 RaceName
= CommonTables
.Races
.GetRowName(RaceColumn
)
198 # could use column ID as well, but they tend to change :)
199 RaceColumn
= CommonTables
.Races
.GetValue(RaceName
, "SKILL_COLUMN")
201 Class
= GemRB
.GetVar("Class") - 1
202 KitName
= CommonTables
.Classes
.GetRowName(Class
)
203 # classcolumn is base class or 0 if it is not a kit
204 ClassColumn
= CommonTables
.Classes
.GetValue(Class
, 3) - 1
205 if ClassColumn
< 0: #it was already a base class
207 FeatsClassColumn
= CommonTables
.Classes
.GetValue(Class
, 2) + 2
209 FeatsClassColumn
= CommonTables
.Classes
.GetValue(Class
, 3) + 2
211 FeatTable
= GemRB
.LoadTable("feats")
212 RowCount
= FeatTable
.GetRowCount()
213 FeatReqTable
= GemRB
.LoadTable("featreq")
215 for i
in range(RowCount
):
216 GemRB
.SetVar("Feat "+str(i
), GetBaseValue(i
))
217 GemRB
.SetVar("BaseFeatValue " + str(i
), GetBaseValue(i
))
219 FeatLevelTable
= GemRB
.LoadTable("featlvl")
220 FeatClassTable
= GemRB
.LoadTable("featclas")
221 #calculating the number of new feats for the next level
224 Level
= GemRB
.GetVar("Level")-1
226 #this one exists only for clerics
227 # Although it should be made extendable to all kits
228 # A FEAT_COLUMN is needed in classes.2da or better yet, a whole new 2da
229 if CommonTables
.Classes
.GetValue(Class
, 3) == "CLERIC":
232 KitColumn
= 3 + KitColumn
+ 11
234 #Always raise one level at once
235 PointsLeft
+= FeatLevelTable
.GetValue(Level
, 0)
236 PointsLeft
+= FeatClassTable
.GetValue(Level
, ClassColumn
)
238 #racial abilities which seem to be hardcoded in the IWD2 engine
239 #are implemented in races.2da
241 PointsLeft
+= CommonTables
.Races
.GetValue(RaceName
,'FEATBONUS')
244 GemRB
.SetToken("number",str(PointsLeft
) )
246 GemRB
.LoadWindowPack("GUICG", 800, 600)
247 FeatWindow
= GemRB
.LoadWindow(55)
249 Button
= FeatWindow
.GetControl(i
+93)
250 Button
.SetVarAssoc("Feat",i
)
251 Button
.SetEvent(IE_GUI_BUTTON_ON_PRESS
, JustPress
)
253 Button
= FeatWindow
.GetControl(i
*2+14)
254 Button
.SetVarAssoc("Feat",i
)
255 Button
.SetEvent(IE_GUI_BUTTON_ON_PRESS
, LeftPress
)
257 Button
= FeatWindow
.GetControl(i
*2+15)
258 Button
.SetVarAssoc("Feat",i
)
259 Button
.SetEvent(IE_GUI_BUTTON_ON_PRESS
, RightPress
)
261 Star
=FeatWindow
.GetControl(i
*5+j
+36)
262 Star
.SetState(IE_GUI_BUTTON_DISABLED
)
263 Star
.SetFlags(IE_GUI_BUTTON_NO_IMAGE
,OP_OR
)
265 BackButton
= FeatWindow
.GetControl(105)
266 BackButton
.SetText(15416)
267 BackButton
.SetFlags(IE_GUI_BUTTON_CANCEL
,OP_OR
)
269 DoneButton
= FeatWindow
.GetControl(0)
270 DoneButton
.SetText(36789)
271 DoneButton
.SetFlags(IE_GUI_BUTTON_DEFAULT
,OP_OR
)
273 TextAreaControl
= FeatWindow
.GetControl(92)
274 TextAreaControl
.SetText(36476)
276 ScrollBarControl
= FeatWindow
.GetControl(104)
277 ScrollBarControl
.SetEvent(IE_GUI_SCROLLBAR_ON_CHANGE
, ScrollBarPress
)
278 #decrease it with the number of controls on screen (list size)
280 GemRB
.SetVar("TopIndex",0)
281 ScrollBarControl
.SetVarAssoc("TopIndex",RowCount
-10)
282 ScrollBarControl
.SetDefaultScrollBar ()
284 DoneButton
.SetEvent(IE_GUI_BUTTON_ON_PRESS
, NextPress
)
285 BackButton
.SetEvent(IE_GUI_BUTTON_ON_PRESS
, BackPress
)
287 FeatWindow
.SetVisible(WINDOW_VISIBLE
)
292 Pos
= GemRB
.GetVar("Feat")+TopIndex
293 TextAreaControl
.SetText(FeatTable
.GetValue(Pos
,2) )
299 Pos
= GemRB
.GetVar("Feat")+TopIndex
301 TextAreaControl
.SetText(FeatTable
.GetValue(Pos
,2) )
302 ActPoint
= GemRB
.GetVar("Feat "+str(Pos
) )
303 BaseValue
= GemRB
.GetVar("BaseFeatValue " + str(Pos
))
304 if ActPoint
<= 0 or ActPoint
<= BaseValue
:
306 GemRB
.SetVar("Feat "+str(Pos
),ActPoint
-1)
307 PointsLeft
= PointsLeft
+ 1
314 Pos
= GemRB
.GetVar("Feat")+TopIndex
316 TextAreaControl
.SetText(FeatTable
.GetValue(Pos
,2) )
319 ActPoint
= GemRB
.GetVar("Feat "+str(Pos
) )
320 # if ActPoint > Level: #Level is 0 for level 1
322 GemRB
.SetVar("Feat "+str(Pos
), ActPoint
+1)
323 PointsLeft
= PointsLeft
- 1
330 for i
in range(FeatTable
.GetRowCount()):
331 GemRB
.SetVar("Feat "+str(i
),0)
332 GemRB
.SetNextScript("Skills")
336 GemRB
.SetRepeatClickFlags(GEM_RK_DISABLE
, OP_OR
)
339 GemRB
.SetNextScript("CharGen7")
342 #Custom feat check functions
343 def Check_AnyOfThree(pl
, ass
, a
, bs
, b
, cs
, c
, *garbage
):
345 if GemRB
.GetPlayerStat(pl
, ass
)==a
: return True
346 if GemRB
.GetPlayerStat(pl
, bs
)==b
: return True
347 if GemRB
.GetPlayerStat(pl
, cs
)==c
: return True
350 #Custom feat check functions
351 def Check_AnyOfThreeGE(pl
, ass
, a
, bs
, b
, cs
, c
, *garbage
):
353 if GemRB
.GetPlayerStat(pl
, ass
)>=a
: return True
354 if GemRB
.GetPlayerStat(pl
, bs
)>=b
: return True
355 if GemRB
.GetPlayerStat(pl
, cs
)>=c
: return True
358 def Check_AllOfThreeGE(pl
, ass
, a
, bs
, b
, cs
, c
, *garbage
):
360 if GemRB
.GetPlayerStat(pl
, ass
) < a
: return False
361 if GemRB
.GetPlayerStat(pl
, bs
) < b
: return False
362 if GemRB
.GetPlayerStat(pl
, cs
) < c
: return False
365 def Check_IsCaster(pl
, *garbage
):
366 # CLASSLEVELMAGE is IE_LEVEL2 (pst)
367 possible_casters
= { IE_LEVEL2
:1, IE_LEVELCLERIC
:1, IE_LEVELDRUID
:1,
368 IE_LEVELSORCEROR
:1, IE_LEVELPALADIN
:4, IE_LEVELRANGER
:4, IE_LEVELBARD
:2 }
371 for stat
in possible_casters
:
372 if GemRB
.GetPlayerStat(pl
, stat
) >= possible_casters
[stat
]:
378 # besides Concentration > 3, this feat requires Weapon Specialization in 2 weapons.
379 def Check_MaximizedAttacks(pl
, a
, ass
, *garbage
):
380 if GemRB
.GetPlayerStat(pl
, ass
) < a
: return False
381 # tuple of all weapon proficiency types
382 proficiencies
= ( IE_FEAT_BASTARDSWORD
, IE_FEAT_AXE
, IE_FEAT_BOW
, IE_FEAT_FLAIL
,
383 IE_FEAT_GREAT_SWORD
, IE_FEAT_HAMMER
, IE_FEAT_LARGE_SWORD
, IE_FEAT_POLEARM
)
384 SpecializationCount
= 0
386 for proficiency
in proficiencies
:
387 if GemRB
.GetPlayerStat(pl
, proficiency
) == 3:
388 SpecializationCount
+= 1
390 return SpecializationCount
>= 2