1 ########################################################
2 #Copyright (c) 2006 Russ Adams, Sean Eubanks, Asgard Contributors
3 #This file is part of Asgard.
5 #Asgard is free software; you can redistribute it and/or modify
6 #it under the terms of the GNU General Public License as published by
7 #the Free Software Foundation; either version 2 of the License, or
8 #(at your option) any later version.
10 #Asgard 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 Asgard; if not, write to the Free Software
17 #Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 ########################################################
20 from equiption
import *
24 from statistic
import *
27 from utilities
import *
28 from struct
import pack
31 def __init__(self
,fTree
=None,binary
=None):
32 """ Construct a Fighter object from a job type XML tree and either a fighter type XML tree or packed binary data. """
34 # If there was a fighter tree specified
37 self
.__name
= fTree
.xpathEval("//name")[0].content
38 self
.__playable
= (fTree
.xpathEval("//playable")[0].content
== "True")
39 self
.__jobType
= fTree
.xpathEval("//job")[0].content
41 # Find correct job XML file
42 j
= fTree
.xpathEval("//job")[0].content
+ '.xml'
45 jTree
= libxml2
.parseFile('./data/job/'+j
)
48 head
= fTree
.xpathEval("//equiption/head")[0].content
49 body
= fTree
.xpathEval("//equiption/body")[0].content
50 left
= fTree
.xpathEval("//equiption/left")[0].content
51 right
= fTree
.xpathEval("//equiption/right")[0].content
52 self
.__equiption
= Equiption(head
,body
,left
,right
)
56 statTree
= fTree
.xpathEval("//stat")
57 for statElem
in statTree
:
62 # The following might should be moved to the Statistics Constructor in the future
63 sname
= statElem
.prop("name")
65 afterBattle
= (statElem
.prop("afterbattle") == "True")
67 if statElem
.prop("current") != None:
68 current
= int(statElem
.prop("current"))
70 if statElem
.prop("max") != None:
71 max = int(statElem
.prop("max"))
73 if afterBattle
== False and statElem
.prop("current") == None:
76 (plus
,chance
,growthRate
) = jobStatQuery(jTree
, sname
)
78 stat
= Statistic(sname
,current
,max,afterBattle
,plus
,chance
,growthRate
)
79 self
.__stats
.append(stat
)
81 elementTree
= fTree
.xpathEval("//modifiers/element")
82 statusTree
= fTree
.xpathEval("//modifiers/status")
84 for elementNode
in elementTree
:
85 self
.__elemMod
.append((elementNode
.prop("name"),elementNode
.prop("mod")))
88 for statusNode
in statusTree
:
89 self
.__statusMod
.append((statusNode
.prop("name"),statusNode
.prop("chance")))
95 # for the sake of more legible code
100 (name
,job
,head
,body
,right
,left
,level
,exp
,exptnl_current
,exptnl_max
,hp_current
,hp_max
,mp_current
,mp_max
,strg
,dex
,agl
,spd
,wis
,wil
) = struct
.unpack("!20s20s20s20s20s20sB7I6B",binary
)
102 #These might be useful later.
103 #print "Name:" + name
107 #print "Right" + right
109 #print "Level" + str(level)
110 #print "Exp" + str(exp)
111 #print "Exptnl_current" + str(exptnl_current)
112 #print "Exptnl_max" + str(exptnl_max)
113 #print "Hp_Current" + str(hp_current)
114 #print "Hp_Max" + str(hp_max)
115 #print "Mp_Current" + str(mp_current)
116 #print "Mp_Max" + str(mp_max)
117 #print "Str" + str(strg)
118 #print "Dex" + str(dex)
119 #print "Agl" + str(agl)
120 #print "Spd" + str(spd)
121 #print "Wis" + str(wis)
122 #print "Wil" + str(wil)
125 self
.__name
= name
.strip('\0')
126 self
.__jobType
= job
.strip('\0')
127 self
.__playable
= True
129 # Create Job XML Tree
130 jTree
= libxml2
.parseFile('./data/job/'+self
.__jobType
+'.xml')
133 self
.__equiption
= Equiption(head
.strip('\0'), body
.strip('\0'), left
.strip('\0'), right
.strip('\0'))
137 (plus
,chance
,growthRate
) = jobStatQuery(jTree
, "level")
138 self
.__stats
.append(Statistic("level",level
,level
,False,plus
,chance
,growthRate
))
140 (plus
,chance
,growthRate
) = jobStatQuery(jTree
, "exp")
141 self
.__stats
.append(Statistic("exp",level
,level
,False,plus
,chance
,growthRate
))
143 (plus
,chance
,growthRate
) = jobStatQuery(jTree
, "exptnl")
144 self
.__stats
.append(Statistic("exptnl",exptnl_current
,exptnl_max
,True,plus
,chance
,growthRate
))
146 (plus
,chance
,growthRate
) = jobStatQuery(jTree
, "hp")
147 self
.__stats
.append(Statistic("hp",hp_current
,hp_max
,True,plus
,chance
,growthRate
))
149 (plus
,chance
,growthRate
) = jobStatQuery(jTree
, "mp")
150 self
.__stats
.append(Statistic("mp",mp_current
,mp_max
,True,plus
,chance
,growthRate
))
152 (plus
,chance
,growthRate
) = jobStatQuery(jTree
, "str")
153 self
.__stats
.append(Statistic("str",strg
,strg
,False,plus
,chance
,growthRate
))
155 (plus
,chance
,growthRate
) = jobStatQuery(jTree
, "dex")
156 self
.__stats
.append(Statistic("dex",dex
,dex
,False,plus
,chance
,growthRate
))
158 (plus
,chance
,growthRate
) = jobStatQuery(jTree
, "agl")
159 self
.__stats
.append(Statistic("agl",agl
,agl
,False,plus
,chance
,growthRate
))
161 (plus
,chance
,growthRate
) = jobStatQuery(jTree
, "spd")
162 self
.__stats
.append(Statistic("spd",spd
,spd
,False,plus
,chance
,growthRate
))
164 (plus
,chance
,growthRate
) = jobStatQuery(jTree
, "wis")
165 self
.__stats
.append(Statistic("wis",wis
,wis
,False,plus
,chance
,growthRate
))
167 (plus
,chance
,growthRate
) = jobStatQuery(jTree
, "wil")
168 self
.__stats
.append(Statistic("wil",wis
,wis
,False,plus
,chance
,growthRate
))
173 self
.__statusMod
= []
176 spd
= self
.getStat("spd").getCurrent()
177 tom
= round((1/float(spd
)*100))
178 self
.__stats
.append(Statistic("tom",tom
,tom
,False,0,0,0))
180 # set canmove to true
181 self
.__stats
.append(Statistic("canMove",1,1,False,0,0,0))
184 if self
.__jobType
== 'monster':
185 self
.__stats
.append(Statistic("ai",1,1,False,0,0,0))
187 self
.__stats
.append(Statistic("ai",0,0,False,0,0,0))
189 # initialize statuses list
192 def toBinaryString(self
):
193 """Convert Fighter data to binary string."""
194 binStr
= pack("!B20s20s20s20s20s20sB7I6B",0,self
.__name
,self
.__jobType
,self
.__equiption
.getHead(),self
.__equiption
.getArmor(),self
.__equiption
.getRight(),self
.__equiption
.getLeft(),self
.getStat("level").getMax(),self
.getStat("exp").getCurrent(),self
.getStat("exptnl").getCurrent(),self
.getStat("exptnl").getMax(),self
.getStat("hp").getCurrent(),self
.getStat("hp").getMax(),self
.getStat("mp").getCurrent(),self
.getStat("mp").getMax(),self
.getStat("str").getMax(),self
.getStat("dex").getMax(),self
.getStat("agl").getMax(),self
.getStat("spd").getMax(),self
.getStat("wis").getMax(),self
.getStat("wil").getMax())
198 """Get fighter's name."""
201 def setName(self
, n
):
202 """Change fighter's name."""
205 def getJobType(self
):
206 """Get Fighter's job type"""
207 return self
.__jobType
209 def setJobType(self
,jobType
):
210 """ Set Fighter's job type"""
211 self
.__jobType
= jobType
213 def getEquiption(self
):
214 """Get equiption for fighter."""
215 return self
.__equiption
217 def setEquiption(self
, eq
):
218 """Set equiption for fighter."""
219 self
.__equiption
= eq
221 def getPlayable(self
):
222 """Is fighter playable?"""
223 return self
.__playable
225 def setPlayable(self
, plyble
):
226 """Set fighter's playability."""
227 self
.__playable
= plyble
230 """Compute value of attack."""
231 return self
.getStat("str").getCurrent() + self
.__equiption
.computeAtkMod()
233 def getDefense(self
):
234 """Compute value of defense."""
235 return self
.__equiption
.computeDefMod()
238 """Compute value of evade."""
239 return self
.getStat("agl").getCurrent() + self
.__equiption
.computeEvaMod()
242 def makeEvent(self
, eparty
, fparty
, currentTime
, cont
):
243 """ Check if ready to make move.
245 If so, select random fighter from enemy party and return.
247 if self
.getStat("tom").getCurrent() != currentTime
:
251 etypes
= cont
.getBattle().getEventTypeList()
253 # Can fighter move? (asleep?, paralysed?, dead?)
255 if self
.getStat("canMove").getCurrent() != 1:
259 # Generate per-turn status transactions
260 for s
in self
.__status
:
266 ai
= self
.getStat("ai").getCurrent()
268 # Playable fighters (ai=0) have battle menu
270 # Show battle menu and choose event from battle menu
271 command
= cont
.getBattleCommand(eparty
,fparty
,self
)
277 x
= randint(0,eparty
.sizeOfParty()-1)
278 while not eparty
.getFighter(x
).isAlive():
279 x
= randint(0,eparty
.sizeOfParty()-1)
281 d
.append(eparty
.getFighter(x
))
283 x
= randint(0,len(self
.getEventTypes(etypes
))-1)
284 t
= cont
.getBattle().getEventType(self
.getEventTypes(etypes
)[x
])
285 # Madness (attack whatever!)
287 x
= randint(0,eparty
.sizeOfParty()-1)
288 y
= randint(0,fparty
.sizeOfParty()-1)
289 while not eparty
.getFighter(x
).isAlive():
290 x
= randint(0,eparty
.sizeOfParty()-1)
291 while not fparty
.getFighter(y
).isAlive():
292 y
= randint(0,fparty
.sizeOfParty()-1)
293 # randint needs a range from SMALL to BIG
295 target
= randint(x
,y
)
297 target
= randint(y
,x
)
300 d
.append(fparty
.getFighter(y
))
303 d
.append(eparty
.getFighter(x
))
305 # fighter cannot choose QUIT while mad (only for playable fighters)
306 if self
.__jobType
!= "monster":
307 x
= randint(0,len(self
.getEventTypes(etypes
))-2)
309 x
= randint(0,len(self
.getEventTypes(etypes
))-1)
310 t
= cont
.getBattle().getEventType(self
.getEventTypes(etypes
)[x
])
312 return Event(self
,d
,[],t
)
315 """If hp is greater than 0... return true"""
316 return (self
.getStat("hp").getCurrent() > 0)
318 def getEventTypes(self
,eventTypes
):
319 """Return list of events available to fighter."""
322 if self
.__jobType
== "blackmage":
323 etypes
= ["attack","defend","fire1","ice1","lit1","poison","sleep","rabies","run"]
324 elif self
.__jobType
== "swordsman":
325 etypes
= ["attack","defend","cure1","heal","life","fog","harm","run"]
326 elif self
.__name
== "Roc":
327 etypes
= ["attack","lit1"]
328 elif self
.__name
== "Imp":
330 elif self
.__name
== "Briaru":
331 etypes
= ["attack","chokeout","sleep"]
332 elif self
.__name
== "Wolf":
333 etypes
= ["attack","rabies"]
334 elif self
.__name
== "Griffiend":
335 etypes
= ["attack","fright"]
336 elif self
.__name
== "Stonos":
338 elif self
.__name
== "Slithera":
340 elif self
.__name
== "HaintHaunt":
345 # remove the event types that don't have enough mp.
349 for s_etype
in etypes
:
350 for o_etype
in eventTypes
:
351 if o_etype
.getName() == s_etype
:
352 if o_etype
.getMpCost() > self
.getStat("mp").getCurrent():
353 etypes
.remove(s_etype
)
360 def receiveExp(self
,exp
):
361 """Fighter receives experience for leveling up."""
363 exp_s
= self
.getStat("exp")
364 exp_s
.setCurrent(exp_s
.getCurrent() + exp
)
365 exp_s
.setMax(exp_s
.getCurrent())
367 # Tax off exp from expTillNextLevel
368 exptnl_s
= self
.getStat("exptnl")
369 exptnl_s
.setCurrent(exptnl_s
.getCurrent() - exp
)
372 while exptnl_s
.getCurrent() <= 0:
373 # Increase level number
374 level_s
= self
.getStat("level")
375 level_s
.setMax(level_s
.getMax() + 1)
376 level_s
.setCurrent(level_s
.getMax())
382 hp
= self
.getStat("hp")
383 if x
<= hp
.getChance() * 100:
384 hp
.setMax(hp
.getMax() + hp
.getPlus())
388 str = self
.getStat("str")
389 if x
<= str.getChance() * 100:
390 str.setMax(str.getMax() + str.getPlus())
391 str.setCurrent(str.getMax())
396 spd
= self
.getStat("spd")
397 if x
<= spd
.getChance() * 100:
398 spd
.setMax(spd
.getMax() + spd
.getPlus())
399 spd
.setCurrent(spd
.getMax())
401 # Increase dexterity?
403 dex
= self
.getStat("dex")
404 if x
<= dex
.getChance() * 100:
405 dex
.setMax(dex
.getMax() + dex
.getPlus())
406 dex
.setCurrent(dex
.getMax())
410 agl
= self
.getStat("agl")
411 if x
<= agl
.getChance() * 100:
412 agl
.setMax(agl
.getMax() + agl
.getPlus())
413 agl
.setCurrent(agl
.getMax())
417 wis
= self
.getStat("wis")
418 if x
<= wis
.getChance() * 100:
419 wis
.setMax(wis
.getMax() + wis
.getPlus())
420 wis
.setCurrent(wis
.getMax())
424 wil
= self
.getStat("wil")
425 if x
<= wil
.getChance() * 100:
426 wil
.setMax(wil
.getMax() + wil
.getPlus())
427 wil
.setCurrent(wil
.getMax())
429 # Set new exp till next level maximum
430 exptnl_s
.setMax(int(exptnl_s
.getMax() * (1 + exptnl_s
.getGrowthRate())))
432 # Carry over any experience that didn't go towards getting the last level
433 exptnl_s
.setCurrent(int(exptnl_s
.getMax() + exptnl_s
.getCurrent()))
435 def getElemModifier(self
,elem
):
436 for elemMod
in self
.__elemMod
:
437 if elem
== elemMod
[0]:
442 def getStatusModifier(self
,stat
):
443 for statusMod
in self
.__statusMod
:
444 if stat
== statusMod
[0]:
450 """Get status(es) of fighter."""
453 def setStatus(self
,s
):
454 """Set status(es) of fighter."""
457 def addStatus(self
,s
):
458 """Add a status to status list for fighter."""
460 for i
in self
.__status
:
466 self
.__status
.append(s
)
469 print 'ERROR: Status already in list!'
471 def removeStatus(self
,s
):
472 """Remove statuses from status list for fighter."""
474 for i
in self
.__status
:
481 self
.__status
.remove(i
)
483 print 'ERROR: Status was not in list!'
485 def getStat(self
,statName
):
486 for stat
in self
.__stats
:
487 if stat
.getName() == statName
:
489 print 'ERROR: No such Fighter stat.'
491 def getAllStats(self
):
494 def setAllStats(self
,stats
):