asgard 0.2.5 has been moved to tags/trash
[asgard.git] / consolecontroller.py
blob89e135c356c49c8c963b33b214feeb28072e1c0c
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 ########################################################
19 from statistic import *
20 from os import listdir
21 from battle import *
22 from equiption import *
23 from fighter import *
24 from eventtype import *
25 import struct
26 import copy
27 import sys
28 import utilities
30 class ConsoleController:
31 """ Model: ConsoleController Class """
33 __battle = None
34 """ A link to the Battle. Set by constructor. """
36 __view = None
37 """ A link to ConsoleView. Set by constructor. """
39 __debug = False
40 """ Are we in debug mode? This prints out extra information during program execution. """
42 def __init__(self,debug,battle,view):
43 """ Sets the links for Battle and ConsoleView so that each of them can access ConsoleController and themselves. It sets the mode of gameplay, normal or debug. Afterwards, the game loop starts. This function does not automatically load nor save binary data! Additionally, it uses self.loadStaticData() to load EventTypes and non-playable Fighters. """
45 self.__debug = debug
46 self.__battle = battle
47 self.__view = view
49 battle.setController(self)
50 battle.setView(view)
51 view.setController(self)
52 view.setBattle(battle)
54 self.__gameLoop()
56 def getBattleCommand(self,vp,hp,f):
57 """ Prints out an event selection menu and collects a choice from the user. It returns the enemy selected for attack and the type of attack. Should use pygame's event driven input functionallity. """
59 command = []
61 print "\033[1;34m[SELCT]\033[1;0m Turn:" + f.getName() + "; HP:" + str(f.getStat("hp").getCurrent()) + "/" + str(f.getStat("hp").getMax()) + " - MP:"+str(f.getStat("mp").getCurrent())+"/"+str(f.getStat("mp").getMax())
63 self.__view.printEventTypeMenu(f,self.__battle.getEventTypeList())
64 n = raw_input("% ")
65 t = self.__battle.getEventType(f.getEventTypes(self.__battle.getEventTypeList())[int(n)-1])
67 if t.getName() == "quit":
68 sys.exit()
70 self.__view.printTargetSelectMenu(vp,hp)
71 n = raw_input("% ")
72 # Select Villain
73 if vp.sizeOfParty() - int(n) >= 0:
74 d = vp.getFighter(int(n)-1)
75 # Select Hero
76 else:
77 d = hp.getFighter(int(n)-vp.sizeOfParty()-1)
78 return [d,t]
80 def getMenuCommand(self):
81 """ Prints out the startup menu, via ConsoleController.printStartupMenu() then obtains user input. Returns result. """
83 self.__view.printStartupMenu()
85 n = raw_input("% ")
87 return int(n)
89 def getDebug(self):
90 return self.__debug
92 def setDebug(self,d):
93 self.__debug = d
95 def __gameLoop(self):
96 """ Show dummy menu. Get user choices. If New Game selected, call self.createNewSave(..). If Load Game selected, call self.load(..). If Save Game selected, call self.save(..) (show only if game loaded), show menu again. If Random Battle selected: (1)Create a random battle. (self.createRandomBattle(..)). (2)Print out the state of affairs before the battle begins. Executes Battle.nextTurn() once. The experience passed to giveExp should be the sum of the defeated party's experience. (3)After battle, show dummy menu again. If Quit selected, end program. """
98 print "Asgard Free Software RPG - Testing Module"
100 self.loadStaticData(False)
102 while True:
103 choice = 0
104 while choice != 4:
105 choice = self.getMenuCommand()
107 if choice == 1:
108 self.unloadStaticData()
109 self.loadStaticData(True)
110 print "loaded..."
111 else:
112 if choice == 2:
113 print "Path to Save File: ",
114 path = sys.stdin.readline()
115 self.load("" + path.strip() + "")
116 print "loaded..."
118 elif choice == 3:
119 print "Path to Save File: ",
120 path = sys.stdin.readline()
121 self.save("" + path.strip() + "")
122 print "saved..."
124 elif choice == 4:
126 if self.__battle.getParty1() == None:
127 print "No game loaded."
128 choice = 0
129 else:
130 self.createRandomBattle()
131 print "============================================================="
132 else:
133 sys.exit()
135 print "Battle Starts."
136 self.__view.printState()
138 # initialize the event checker boolean
139 wereEvents = False
141 while not self.__battle.isOver():
142 # next iteration
143 wereEvents = self.__battle.nextTurn()
145 # only print out state if something actually happened
146 if wereEvents:
147 self.__view.printState()
149 if self.__battle.getParty1().isAlive():
152 # sum exp from enemy party
153 exp = 0
154 for f in self.__battle.getParty2().getFighters():
155 exp += f.getStat("exp").getMax()
157 # hero party gets exp
158 self.__battle.getParty1().giveExp(exp)
161 print "Final Results"
162 print "============================================================="
163 self.__view.printParty(self.__battle.getParty1())
164 print "============================================================="
165 print "Victory Fanfare. Hand's party wins "+str(exp)+" exp!"
167 for f in self.__battle.getParty1().getFighters():
168 # remove all statuses
169 for s in f.getStatus():
170 s.genExit()
171 f.getStat("mp").setCurrent(f.getStat("mp").getMax())
173 else:
174 print "Game Over. Asgard mourns."
176 # clear out the hero party - they're dead!
177 self.__battle.setParty1(None)
180 def load(self,savefile):
181 """ Destroy hero Party and playable Fighters. Construct new hero Party and playable Fighters. """
183 #clear party1 and it's fighters
184 self.__battle.setParty1(Party("Heroes"))
186 #open savefile
187 fptr = open(savefile,"rb")
189 fptr.seek(0,2)
190 size = fptr.tell()
192 fptr.seek(0,0)
194 # number of bytes read in so far
195 readin = 0
197 while readin != size:
198 #read in struct descriptor
200 tstring = fptr.read(struct.calcsize("!B"))
201 [type] = struct.unpack("!B",tstring)
202 readin += struct.calcsize("!B")
205 if type == 0:
206 fstring = fptr.read(struct.calcsize("!20s20s20s20s20s20sB7I6B"))
207 readin += struct.calcsize("!20s20s20s20s20s20sB7I6B")
211 fptr.seek(readin,0)
212 fighter = Fighter(binary=fstring)
213 self.__battle.getParty1().addFighter(fighter)
215 #close savefile
216 fptr.close()
218 def save(self,savefile):
219 """ Calls Party.getBinaryString() for hero Party. Calls Fighter.getBinaryString() for all playable Fighters. Concatenates binary string and writes to save file. """
221 # Retrieving playable fighters
222 fighters = self.__battle.getParty1().getFighters()
224 # Writing each fighter to savefile
225 fptr = open(savefile,"wb")
227 for f in fighters:
228 # Convert fighter f to binary string
229 binStr = f.toBinaryString()
231 # Write binary string to savefile
232 fptr.write(binStr.strip())
234 fptr.close()
236 def createRandomBattle(self):
237 """ Randomly selects some number (1 to 6) of monsters, and randomly determines which monsters they are. Copies each monster to populate an enemy party. """
239 self.__battle.setParty2(Party("Villains"))
240 partySize = 2
241 partySize += random.randint(-1,2)
242 for x in range(0, partySize):
243 monstI = random.randint(0,len(self.__battle.getMonsters())-1)
245 monster = copy.deepcopy(self.__battle.getMonsters()[monstI])
246 self.__battle.getParty2().addFighter(monster)
248 for f in self.__battle.getParty1().getFighters():
249 spd = f.getStat("spd").getCurrent()
250 tom = round((1/float(spd)*100))
251 f.getStat("tom").setCurrent(tom)
252 f.getStat("tom").setMax(tom)
253 f.getStat("canMove").setCurrent(1)
254 f.getStat("ai").setCurrent(0)
256 self.__battle.setCurrentTime(0)
258 def loadStaticData(self,newGame):
259 """ Loads EventTypes and non-playable/initial playable Fighters. (at some point, other things too). Utilizes the Fighter xml constructor. By default it loads fighter objects that are non-playable into Battle.monsters, but when newGame is True, it also creates the hero party from the files in ./data/fighter/playable. It does not load playable fighters into Battle.monsters. """
261 dir = listdir('./data/eventtypes/')
263 self.__battle.setEventTypeList([])
265 for et in dir:
267 if et[0] == ".":
268 continue
270 etTree = libxml2.parseFile('./data/eventtypes/'+et)
272 #uncomment these
273 eventType = EventType(etTree)
274 self.__battle.getEventTypeList().append(eventType)
276 if newGame:
277 self.__battle.setParty1(Party("Heroes"))
279 ### Loading fighters ###
280 dir = listdir('./data/fighter/')
281 for f in dir:
283 # f cannot be a "." file
284 if f[0] == '.':
285 continue
287 # Create Fighter XML Tree
288 fTree = libxml2.parseFile('./data/fighter/'+f)
290 # Create Fighter Object
291 fighter = Fighter(fTree=fTree)
293 # Add fighter to respective party (1 or 2)
294 if fighter.getPlayable() and newGame:
295 self.__battle.getParty1().addFighter(fighter)
296 elif not fighter.getPlayable():
297 self.__battle.getMonsters().append(fighter)
299 def unloadStaticData(self):
300 """ Clears out all monsters and EventTypes. """
302 # Clearing out monsters
303 self.__battle.setMonsters([])
305 # Clearing out EventTypes
306 self.__battle.setEventTypeList([])
308 def getBattle(self):
309 return self.__battle
311 def getView(self):
312 return self.__view