Module controller
[hide private]
[frames] | no frames]

Source Code for Module controller

  1  ''' 
  2  controller.py 
  3   
  4  contrains the game controller 
  5  to play the game, run game.py 
  6  ''' 
  7   
  8  from cocos.director import director 
  9  from cocos.layer import * 
 10  from cocos import collision_model 
 11  from pyglet.window import key 
 12  from cocos import audio 
 13  import cocos.euclid as eu 
 14  from cocos import tiles 
 15   
 16  from constants import * 
 17  from models import * 
 18  from maps import Vertex, Map 
 19  from utils import * 
 20  from imageLayer import * 
 21  from game_layers import * 
 22  from player import * 
 23  from tutorial import * 
 24   
 25  from music import theme_player 
 26   
 27  import os 
 28   
 29  options = { 
 30      "humanPlayerNum": 1, 
 31      "aiPlayerNum": 1 
 32  } 
 33   
34 -class GameController(Layer, EventDispatcher):
35 is_event_handler = True 36
37 - def __init__(self):
38 super(GameController, self).__init__() 39 self.selectedUnits = [] # Stores units that have been selected 40 41 self.map = Map(os.path.join("maps", "level1.map")) 42 self.map.draw_map() 43 self.cm = collision_model.CollisionManagerGrid( 44 0.0, self.map.w * CELL_SIZE, 0.0, self.map.h * CELL_SIZE, 32.0, 32.0) 45 self.map.cm = self.cm 46 47 self.scroller = ScrollingManager(viewport=director.window) 48 self.scroller.add(self.map) 49 50 # Arbitrary starting location. I suggest this is info be stored in each map file. 51 52 self.scroller.set_focus((self.map.w * CELL_SIZE) / 53 16, (self.map.h * CELL_SIZE) / 16) 54 self.infoLayer = InfoLayer(self.map, self.scroller, None) 55 self.statusMenu = StatusMenu() 56 self.add(self.infoLayer) 57 58 self.curAction = None 59 60 self.level = 1 61 self.tutorial = Tutorial(self.level, self) 62 63 self.horizontalSize = CELL_SIZE * self.map.w 64 self.verticalSize = CELL_SIZE * self.map.h 65 # self.mouseClickGraphic = Sprite(os.path.join("images", "menus", 66 # "mouse_click_graphic.png")) 67 68 #Handshake 69 self.is_shake_selected = False 70 self.source_handshake = None 71 self.handshake_units_selected = [] 72 73 74 if self.horizontalSize < WINDOW_WIDTH: 75 self.horizontalSize = WINDOW_WIDTH 76 if self.verticalSize < WINDOW_HEIGHT: 77 self.verticalSize = WINDOW_HEIGHT
78
79 - def on_enter(self):
80 super(GameController, self).on_enter() 81 82 # TODO: this will at somepoint be an array of players 83 # but it will go in the server code for multiplayer 84 self.player = Player(0, self.map, self.cm, PLAYER_COLORS[0]) 85 self.player.setup( 86 ) # Adds starting troops/buildings/research from the map file. 87 88 self.ai = ComputerPlayer( 89 1, self.map, self.cm, PLAYER_COLORS[1], self.player) 90 self.ai.setup( 91 ) # Adds starting troops/buildings/research from the map file. 92 93 self.players = [self.player, self.ai] 94 self.infoLayer.player = self.player.ID 95 self.ai.run_basic_ai() 96 97 # tutorial stuff 98 if SHOW_TUTORIAL: 99 self.tutorial.first_prompt("on_enter") 100 self.player.push_handlers( 101 self.tutorial.player_add_troop, self.tutorial.player_unit_attack, self.tutorial.player_add_building) 102 self.push_handlers( 103 self.tutorial.click_on_move, self.tutorial.click_on_action) 104 105 self.player.push_handlers(self.on_loss) 106 self.ai.push_handlers(self.on_loss) 107 108 for player in self.players: 109 self.schedule(player.step) 110 self.schedule(self.step) 111 112 self.bindings = { # key constant : button name 113 key.LEFT: 'left', 114 key.RIGHT: 'right', 115 key.UP: 'up', 116 key.DOWN: 'down' 117 } 118 119 self.buttons = { # button name : current value, 0 not pressed, 1 pressed 120 'left': 0, 121 'right': 0, 122 'up': 0, 123 'down': 0 124 } 125 126 self.mouse_flag = { 127 'x': 0, 128 'y': 0 129 }
130
131 - def on_loss(self, loser):
132 if loser.ID == 0: 133 director.push(Scene(self.lost)) 134 else: 135 director.push(Scene(self.won))
136
137 - def step(self, dt):
138 # step is called every frame 139 if self.mouse_flag["x"] == 0 and self.mouse_flag["y"] == 0: # keyboard scrolling 140 buttons = self.buttons 141 move_dir = eu.Vector2(buttons['right'] - buttons['left'], 142 buttons['up'] - buttons['down']) 143 else: # mouse scrolling 144 move_dir = eu.Vector2(self.mouse_flag['x'], self.mouse_flag['y']) 145 newPos = move_dir.normalize() * dt * MAP_SCROLL_SPEED 146 newx, newy = self.clamp(newPos) 147 self.scroller.set_focus(newx, newy)
148
149 - def clamp(self, pos):
150 x, y = pos 151 newx = self.scroller.fx + x 152 newy = self.scroller.fy + y 153 if newx <= 1: 154 newx = 1.0 155 elif newx >= self.horizontalSize - WINDOW_WIDTH: 156 newx = self.horizontalSize - WINDOW_WIDTH + 1.0 157 if newy <= 1: 158 newy = 1.0 159 elif newy >= self.verticalSize - WINDOW_HEIGHT: 160 newy = self.verticalSize - WINDOW_HEIGHT + 1.0 161 return newx, newy
162
163 - def on_mouse_motion(self, x, y, dx, dy):
164 # x,y = self.scroller.pixel_from_screen(x,y) 165 if x == 0: 166 self.mouse_flag["x"] = -1.0 167 self.mouse_flag["y"] = float(y - (WINDOW_HEIGHT / 168 2)) / WINDOW_HEIGHT 169 elif x == WINDOW_WIDTH or x == WINDOW_WIDTH - 1: 170 self.mouse_flag["x"] = 1.0 171 self.mouse_flag["y"] = float(y - (WINDOW_HEIGHT / 172 2)) / WINDOW_HEIGHT 173 elif y == 0: 174 self.mouse_flag["y"] = -1.0 175 self.mouse_flag["x"] = float(x - (WINDOW_WIDTH / 2)) / WINDOW_WIDTH 176 elif y == WINDOW_HEIGHT or y == WINDOW_HEIGHT - 1: 177 self.mouse_flag["y"] = 1.0 178 self.mouse_flag["x"] = float(x - (WINDOW_WIDTH / 2)) / WINDOW_WIDTH 179 else: 180 self.mouse_flag["x"] = 0 181 self.mouse_flag["y"] = 0
182
183 - def on_key_press(self, k, modifiers):
184 if k == key.ESCAPE: 185 theme_player.fadeout() 186 187 binds = self.bindings 188 if k in binds: 189 self.buttons[binds[k]] = 1 190 return True 191 return False
192
193 - def on_key_release(self, k, m):
194 # Determine the type of units we've selected so we can assign hotkeys 195 # appropriately 196 197 selType = None 198 199 if len(self.selectedUnits) > 0: 200 selType = type(self.selectedUnits[0]) 201 202 actNum = None 203 if selType != None and issubclass(selType, Troop): 204 actNum = { 205 key.A: 0, # A 206 key.S: 1, # S 207 key.D: 2 # D 208 }.get(k, None) 209 elif selType != None and issubclass(selType, Building): 210 actNum = { 211 key.Q: 7, # Q 212 key.W: 3, # W 213 key.E: 5, # E 214 key.A: 1, # A 215 key.D: 0, # D 216 key.Z: 6, # Z 217 key.X: 2, # X 218 key.C: 4, # C 219 }.get(k, None) 220 221 if actNum != None: 222 # Loop through selected units and execute action associated with 223 # hotkey. 224 225 for unit in self.selectedUnits: 226 # Make sure this unit has the action we're trying to execute 227 # with the hotkey 228 if actNum < len(unit.actionList): 229 # Execute the action. Also deselects the unit (all actions 230 # automatically deselect) 231 232 self.execute_action(unit.actionList[actNum], unit) 233 234 # scrolling logic 235 binds = self.bindings 236 if k in binds: 237 self.buttons[binds[k]] = 0 238 return True 239 return False
240 241 # def on_mouse_press(self, x, y, buttons, modifiers): 242 # # Add the mouse down sprite to the map where the mouse was pressed. 243 # x, y = self.scroller.pixel_from_screen(x, y) 244 # self.mouseClickGraphic.position = euclid.Vector2(x, y) 245 # self.map.add(self.mouseClickGraphic, z = 10) 246
247 - def on_mouse_release(self, x, y, buttons, modifiers):
248 # Mouse clicked. Perform unit selection, check for button presses, and executes actions. 249 # Check if we clicked the minimap - if so, don't perform any selection logic on units behind the map. 250 # for i in range(1000,1,-0.25): 251 # self.mouseClickGraphic.scale = 0.001 * i 252 # self.map.remove(self.mouseClickGraphic) 253 if self.statusMenu.cm.objs_touching_point(x,y): 254 director.pop() 255 256 if self.infoLayer.miniMapToggled: 257 # First check to see if the minimap is toggled to save our CM from 258 # checking collisions if the minimap isn't up. 259 minimap = self.infoLayer.cm.objs_touching_point( 260 x - self.infoLayer.position[0], y - self.infoLayer.position[1]) 261 if self.infoLayer.miniMap in minimap: 262 return 263 x, y = self.scroller.pixel_from_screen(x, y) 264 clicked_units = self.cm.objs_touching_point(x, y) 265 266 for unit in clicked_units: 267 if type(unit) == SurrenderButton: 268 director.push(Scene(self.lost)) 269 270 # Set selectedUnits. If a vertex is clicked on, all troops in the 271 # vertex are selected/unselected 272 if buttons == 1: # Left button clicked 273 # Did we click on an action button? 274 actionButton = get_action_button_clicked(clicked_units) 275 if actionButton: 276 # Clicked on an action button. Execute the action. 277 self.execute_action(actionButton.name, actionButton.unitParent) 278 elif clicked_units: 279 if self.curAction: 280 # Attack 281 self.player.unit_attack(self.selectedUnits, clicked_units) 282 self.curAction = None 283 else: 284 # If clicked on vertex or clicked on a single unit, switch 285 # select state of all units in vertex 286 self.select_units(clicked_units) 287 if constants.SOUND: 288 self.play_sound("click_troop.wav") 289 # Move 290 if clicked_units != set([]) and self.selectedUnits != []: 291 if buttons == 4: # Button == 4 means right click 292 # Perform move action. 293 self.execute_move(clicked_units) 294 return True
295
296 - def __deselect_units_of_type(self, units, unitType):
297 # Deselect buildings if we're selecting Troops. 298 unitsToDeselect = [] 299 for unit in self.selectedUnits: 300 if issubclass(type(unit), unitType): 301 unitsToDeselect.append(unit) 302 if unitsToDeselect != []: 303 self.player.switch_units_select_state( 304 unitsToDeselect, self.selectedUnits)
305
306 - def select_units(self, clicked_units):
307 # Performs all selection logic. Sets the select state (inverts it) of 308 # units that were just clicked on. 309 if len(clicked_units) >= 1: 310 clicked = None 311 for item in clicked_units: 312 if type(item) == Vertex: 313 clicked = item 314 break 315 else: 316 clicked = item 317 318 #Handshake 319 if type(clicked) == Handshake: 320 #seeing if the shake action is enabled 321 if(self.source_handshake != None): 322 if self.source_handshake == clicked: 323 self.is_shake_selected = False 324 325 if self.is_shake_selected: 326 #constructing a list of vids 327 adjacency_vid_list = [] 328 for vertex in self.source_handshake.curVertex.adjacentVertices: 329 adjacency_vid_list.append(vertex.vid) 330 331 #checking to see if edge exists already 332 if clicked.curVertex.vid not in adjacency_vid_list: 333 dest_handshake = clicked 334 edge = self.source_handshake.shake(dest_handshake, self.map) 335 self.cm.remove_tricky(self.source_handshake) 336 self.cm.remove_tricky(dest_handshake) 337 self.is_shake_selected = False 338 self.source_handshake = None 339 else: 340 utils.play_sound("error.wav") 341 self.player.switch_units_select_state( 342 [clicked], self.selectedUnits) 343 self.is_shake_selected = False 344 pass 345 else: 346 self.is_shake_selected = False 347 self.source_handshake = None 348 349 350 if type(clicked) == Vertex: 351 # Deselect all buildings if we're selecting troops. 352 self.__deselect_units_of_type(self.selectedUnits, Building) 353 self.player.switch_units_select_state( 354 clicked.troops, self.selectedUnits) 355 356 elif issubclass(type(clicked), Unit) and clicked.pid == 0: 357 # Deselect all troops if we're selecting a building, and vice 358 # versa. 359 #TODO: use Dave's player building and troop action list instead 360 if issubclass(type(clicked), Building): 361 if type(clicked) == SoftwareUpdater: 362 self.player.update_research_action_button(clicked) 363 if type(clicked) == AlgorithmFactory: 364 self.player.update_troop_action_button(clicked) 365 self.__deselect_units_of_type(self.selectedUnits, Troop) 366 elif issubclass(type(clicked), Troop): 367 self.__deselect_units_of_type(self.selectedUnits, Building) 368 369 self.player.switch_units_select_state( 370 [clicked], self.selectedUnits) 371 372 else: 373 # More than one thing clicked on. Switch select state of all of 374 # them. 375 self.player.switch_units_select_state( 376 clicked_units, self.selectedUnits) # We COULD change this so only the unit with the higehst Z value get selected.
377
378 - def execute_move(self, clickedUnits):
379 # Moves the selected troops (self.selectedUnits) to the destination 380 # vertex (which is in clickedUnits) 381 dest = None 382 while type(dest) != Vertex and clickedUnits != (): 383 dest = clickedUnits.pop() 384 if type(dest) == Vertex: 385 for selectedUnit in self.selectedUnits: 386 if issubclass(type(selectedUnit), Troop): 387 if selectedUnit.player_move(dest, self.map, self.cm) == True and constants.SOUND: 388 # If we successfully moved, play the move sound. 389 self.play_sound("Move.wav") 390 selectedUnit.set_is_selected(False, self.map, self.cm, self.player) 391 self.selectedUnits = [] 392 self.dispatch_event("click_on_move", type(selectedUnit), dest.vid)
393
394 - def execute_action(self, actionName, unit):
395 # ActionButton <actionButton> clicked. Execute the action associated 396 # with the button/building/vertex 397 self.curAction = None 398 # Need to add conditional to account for resource availability. 399 self.player.switch_units_select_state([unit], self.selectedUnits) 400 if actionName[0] == "B": 401 # BUILD A BUILDING (also deselects the troop) 402 if self.player.execute_build_building(actionName[1:], unit, self.selectedUnits) and constants.SOUND: 403 self.play_sound("Clock.wav") 404 elif actionName[0] == "T": 405 # BUILD A TROOP (also deselects the building) 406 if self.player.execute_build_troop(actionName[1:], unit, self.selectedUnits) and constants.SOUND: 407 self.play_sound("Clock.wav") 408 elif actionName[0] == "R": 409 # RESEARCH 410 if self.player.perform_research(actionName, unit, self.cm) and constants.SOUND: 411 self.play_sound("Clock.wav") 412 # BEGIN UPGRADES 413 elif actionName == "USinkhole": 414 unit.upgrade_to_sinkhole(self.player) 415 elif actionName == "UPingOfDeath": 416 unit.upgrade_to_pod(self.player) 417 elif actionName == "UNMap": 418 unit.upgrade_to_nmap(self.player) 419 # BEGIN UTILITY 420 #Handshake 421 elif actionName == "Shake": 422 self.is_shake_selected = True 423 self.source_handshake = unit 424 #if type(troop) == Handshake and troop != unit: 425 #self.source_handshake = troop 426 #print "GOT ME A TROOP TO SELECT" 427 # Got the other selected handshake to shake with 428 #self.source_handshake = troop 429 #print self.source_handshake.pid 430 #print "MY SELECTED HANDSHAKE",troop 431 #unit.shake(troop) 432 # PLAY HANDSHAKE SOUND 433 #break 434 elif actionName == "DEL": 435 # TODO: we could have multple servers 436 if issubclass(type(unit), Server): 437 if self.player.numServers == 1: 438 self.add_surrender_button(unit) 439 if constants.SOUND: 440 self.play_sound("Eraser.wav") 441 self.player.on_destruction(unit, self.selectedUnits) 442 elif actionName == "CANCEL": 443 self.player.cancel_cpu(unit) 444 elif actionName == "Encrypt": 445 unit.encrypt(unit.curVertex.troops, self.player) 446 elif actionName == "Decrypt": 447 unit.decrypt(self.player) 448 elif actionName == "Ping": 449 unit.ping(self.player.on_destruction, self.map, self.cm) 450 451 else: 452 self.curAction = actionName 453 # dummy array, because we don't want to change self.selectedUnit 454 self.dispatch_event("click_on_action", actionName)
455
456 - def play_sound(self, filename):
457 sound = pyglet.resource.media('sounds/' + filename, streaming=False) 458 sound.play()
459 460 # No image, crash game
461 - def add_surrender_button(self, actionButton):
462 self.player.has_server = False 463 x = actionButton.position[0] 464 y = actionButton.position[1] 465 surrender = SurrenderButton(x, y) 466 self.map.add(surrender, z=10) 467 self.cm.add(surrender)
468 # Yasin was here. 469 470 GameController.register_event_type("click_on_move") 471 GameController.register_event_type("click_on_action") 472