main.py has been removed as it's now deprecated. asgard.py now launches the program...
[asgard.git] / asgard.py
blob3adf8d7e640cc9317b47205111a7401e843b19b3
1 import pygame
2 from pygame.locals import *
3 import struct
4 import copy
5 import sys
6 import utilities
7 import libxml2
8 from time import sleep
9 from os import listdir
11 from statistic import Statistic
12 from screen import BattleScreen
13 from battle import Battle
14 from equiption import Equiption
15 from fighter import Fighter
16 from eventtype import EventType
19 class Asgard:
20 """ This is the game controller. Currently, it mostly controls
21 battles, but does a few other meta processes that will no doubt be
22 completely unnecessary in a few releases. Additionally, it handles
23 saving, loading and game initialization using binary saves and XML
24 files. """
26 __battle = None
27 """ A link to the model currently being used. Battle is currently the only model. """
29 __view = None
30 """ A link to the current screen being used. BattleScreen is currently the only screen. """
32 __display = None
34 def __init__(self,m,v):
35 """ Hook up Battle, BattleScreen and Asgard Controller. Initialize display surface. """
36 self.__view = v
37 self.__battle = m
38 self.__view.model = m
39 self.__battle.view = v
41 pygame.init()
44 self.__display = pygame.display.set_mode((800,600))
45 pygame.display.set_caption("Asgard Free Software RPG - Menu Testing Module")
47 s = pygame.Surface((20,20))
48 pygame.draw.rect(s,255,pygame.Rect((0,0),(20,20)))
49 self.__display.blit(s,(20,20))
50 pygame.display.flip()
52 self.game()
54 def wait(self):
55 """ Handles Pygame Events. Especially quit, minimize, maximize, window movement, up, down, left, right, and enter. When enter is pressed, it processes the requested operation (through hardcoded procedures). """
57 while (True):
58 et = pygame.event.wait()
60 # Program needs to be shut down
61 if et.type == QUIT:
62 pygame.display.quit()
63 sys.exit()
65 # Key's been pressed
66 elif et.type == KEYUP:
68 # Select
69 if et.key == K_f:
70 print "SELECT"
71 # Cancel
72 elif et.key == K_d:
73 print "CANCEL"
74 #Up or Left
75 elif et.key == K_UP or et.key == K_LEFT:
76 print "UP"
77 #Down or Right
78 elif et.key == K_DOWN or et.key == K_RIGHT:
79 print "DOWN"
82 """
83 if choice == 1:
84 self.unloadStaticData()
85 self.loadStaticData(True)
86 print "loaded..."
87 else:
88 if choice == 2:
89 print "Path to Save File: ",
90 path = sys.stdin.readline()
91 self.load("" + path.strip() + "")
92 print "loaded..."
94 elif choice == 3:
95 print "Path to Save File: ",
96 path = sys.stdin.readline()
97 self.save("" + path.strip() + "")
98 print "saved..."
100 elif choice == 4:
102 if self.__battle.getParty1() == None:
103 print "No game loaded."
104 choice = 0
105 else:
106 self.createRandomBattle()
107 print "============================================================="
108 else:
109 sys.exit()
112 def game(self):
113 """ 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. """
115 self.loadStaticData(False)
117 while True:
118 self.__view.drawStartup()
119 self.__view.drawMagic(None,None)
120 self.__view.drawCommands()
122 self.wait()
124 print "Battle Starts."
125 self.__view.printState()
127 # initialize the event checker boolean
128 wereEvents = False
130 while not self.__battle.isOver():
131 # next iteration
132 wereEvents = self.__battle.nextTurn()
134 # only print out state if something actually happened
135 if wereEvents:
136 self.__view.printState()
138 if self.__battle.getParty1().isAlive():
141 # sum exp from enemy party
142 exp = 0
143 for f in self.__battle.getParty2().getFighters():
144 exp += f.getStat("exp").getMax()
146 # hero party gets exp
147 self.__battle.getParty1().giveExp(exp)
150 print "Final Results"
151 print "============================================================="
152 self.__view.printParty(self.__battle.getParty1())
153 print "============================================================="
154 print "Victory Fanfare. Hand's party wins "+str(exp)+" exp!"
156 for f in self.__battle.getParty1().getFighters():
157 # remove all statuses
158 for s in f.getStatus():
159 s.genExit()
160 f.getStat("mp").setCurrent(f.getStat("mp").getMax())
162 else:
163 print "Game Over. Asgard mourns."
165 # clear out the hero party - they're dead!
166 self.__battle.setParty1(None)
169 def load(self,savefile):
170 """ Destroy hero Party and playable Fighters. Construct new hero Party and playable Fighters. """
172 #clear party1 and it's fighters
173 self.__battle.setParty1(Party("Heroes"))
175 #open savefile
176 fptr = open(savefile,"rb")
178 fptr.seek(0,2)
179 size = fptr.tell()
181 fptr.seek(0,0)
183 # number of bytes read in so far
184 readin = 0
186 while readin != size:
187 #read in struct descriptor
189 tstring = fptr.read(struct.calcsize("!B"))
190 [type] = struct.unpack("!B",tstring)
191 readin += struct.calcsize("!B")
194 if type == 0:
195 fstring = fptr.read(struct.calcsize("!20s20s20s20s20s20sB7I6B"))
196 readin += struct.calcsize("!20s20s20s20s20s20sB7I6B")
200 fptr.seek(readin,0)
201 fighter = Fighter(binary=fstring)
202 self.__battle.getParty1().addFighter(fighter)
204 #close savefile
205 fptr.close()
207 def save(self,savefile):
208 """ Calls Party.getBinaryString() for hero Party. Calls Fighter.getBinaryString() for all playable Fighters. Concatenates binary string and writes to save file. """
210 # Retrieving playable fighters
211 fighters = self.__battle.getParty1().getFighters()
213 # Writing each fighter to savefile
214 fptr = open(savefile,"wb")
216 for f in fighters:
217 # Convert fighter f to binary string
218 binStr = f.toBinaryString()
220 # Write binary string to savefile
221 fptr.write(binStr.strip())
223 fptr.close()
225 def createRandomBattle(self):
226 """ Randomly selects some number (1 to 6) of monsters, and randomly determines which monsters they are. Copies each monster to populate an enemy party. """
228 self.__battle.setParty2(Party("Villains"))
229 partySize = 2
230 partySize += random.randint(-1,2)
231 for x in range(0, partySize):
232 monstI = random.randint(0,len(self.__battle.getMonsters())-1)
234 monster = copy.deepcopy(self.__battle.getMonsters()[monstI])
235 self.__battle.getParty2().addFighter(monster)
237 for f in self.__battle.getParty1().getFighters():
238 spd = f.getStat("spd").getCurrent()
239 tom = round((1/float(spd)*100))
240 f.getStat("tom").setCurrent(tom)
241 f.getStat("tom").setMax(tom)
242 f.getStat("canMove").setCurrent(1)
243 f.getStat("ai").setCurrent(0)
245 self.__battle.setCurrentTime(0)
247 def loadStaticData(self,newGame):
248 """ 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. """
250 dir = listdir('./data/eventtypes/')
252 self.__battle.setEventTypeList([])
254 for et in dir:
256 if et[0] == ".":
257 continue
259 etTree = libxml2.parseFile('./data/eventtypes/'+et)
261 #uncomment these
262 eventType = EventType(etTree)
263 self.__battle.getEventTypeList().append(eventType)
265 if newGame:
266 self.__battle.setParty1(Party("Heroes"))
268 ### Loading fighters ###
269 dir = listdir('./data/fighter/')
270 for f in dir:
272 # f cannot be a "." file
273 if f[0] == '.':
274 continue
276 # Create Fighter XML Tree
277 fTree = libxml2.parseFile('./data/fighter/'+f)
279 # Create Fighter Object
280 fighter = Fighter(fTree=fTree)
282 # Add fighter to respective party (1 or 2)
283 if fighter.getPlayable() and newGame:
284 self.__battle.getParty1().addFighter(fighter)
285 elif not fighter.getPlayable():
286 self.__battle.getMonsters().append(fighter)
288 def unloadStaticData(self):
289 """ Clears out all monsters and EventTypes. """
291 # Clearing out monsters
292 self.__battle.setMonsters([])
294 # Clearing out EventTypes
295 self.__battle.setEventTypeList([])
298 m = Battle()
299 v = BattleScreen()
300 c = Asgard(m,v)