Mercurial > rinkhals
comparison gamelib/gameboard.py @ 472:67574723427e
Partially working (but much less crashy) multiple select support
author | Neil Muller <drnlmuller@gmail.com> |
---|---|
date | Wed, 25 Nov 2009 14:32:40 +0000 |
parents | fbbd39cfc975 |
children | 4b8ca482ea08 |
comparison
equal
deleted
inserted
replaced
471:c34d53edfa12 | 472:67574723427e |
---|---|
100 # Ensure we don't every try to create more foxes then is sane | 100 # Ensure we don't every try to create more foxes then is sane |
101 self.max_foxes = level.max_foxes | 101 self.max_foxes = level.max_foxes |
102 self.calculate_wood_groat_exchange_rate() | 102 self.calculate_wood_groat_exchange_rate() |
103 | 103 |
104 self.selected_tool = None | 104 self.selected_tool = None |
105 self.animal_to_place = None | |
106 self.sprite_cursor = None | 105 self.sprite_cursor = None |
107 self.chickens = set() | 106 self.chickens = set() |
108 self.foxes = set() | 107 self.foxes = set() |
109 self.buildings = set() | 108 self.buildings = set() |
110 self._pos_cache = AnimalPositionCache(self) | 109 self._pos_cache = AnimalPositionCache(self) |
127 for tn in equipment.EQUIP_MAP: | 126 for tn in equipment.EQUIP_MAP: |
128 cdata[tn] = (self.add_start_chickens, tn) | 127 cdata[tn] = (self.add_start_chickens, tn) |
129 | 128 |
130 self.tv.run_codes(cdata, (0,0,width,height)) | 129 self.tv.run_codes(cdata, (0,0,width,height)) |
131 | 130 |
131 self.selected_chickens = [] | |
132 | |
132 def get_top_widget(self): | 133 def get_top_widget(self): |
133 return self.top_widget | 134 return self.top_widget |
134 | 135 |
135 def create_display(self): | 136 def create_display(self): |
136 width, height = self.disp.rect.w, self.disp.rect.h | 137 width, height = self.disp.rect.w, self.disp.rect.h |
173 def loop(self): | 174 def loop(self): |
174 self.tv.loop() | 175 self.tv.loop() |
175 | 176 |
176 def set_selected_tool(self, tool, cursor): | 177 def set_selected_tool(self, tool, cursor): |
177 if not self.day: | 178 if not self.day: |
178 return | 179 return False |
180 if self.apply_tool_to_selected(tool): | |
181 return False # Using the tool on selected chickens is immediate | |
179 self.selected_tool = tool | 182 self.selected_tool = tool |
180 if self.animal_to_place: | 183 if tool in [None, constants.TOOL_SELL_BUILDING, |
181 # Clear any highlights | 184 constants.TOOL_REPAIR_BUILDING]: |
182 self.animal_to_place.unequip_by_name("Spotlight") | 185 # FIXME - this special casing is sucky |
183 self.select_animal_to_place(None) | 186 self.unselect_all() |
184 sprite_curs = None | 187 sprite_curs = None |
185 if buildings.is_building(tool): | 188 if buildings.is_building(tool): |
186 sprite_curs = sprite_cursor.SpriteCursor(tool.IMAGE, self.tv, tool.BUY_PRICE) | 189 sprite_curs = sprite_cursor.SpriteCursor(tool.IMAGE, self.tv, tool.BUY_PRICE) |
187 elif equipment.is_equipment(tool): | 190 elif equipment.is_equipment(tool): |
188 sprite_curs = sprite_cursor.SpriteCursor(tool.CHICKEN_IMAGE_FILE, self.tv) | 191 sprite_curs = sprite_cursor.SpriteCursor(tool.CHICKEN_IMAGE_FILE, self.tv) |
189 self.set_cursor(cursor, sprite_curs) | 192 self.set_cursor(cursor, sprite_curs) |
193 return True | |
194 | |
195 def apply_tool_to_selected(self, tool): | |
196 if self.selected_chickens: | |
197 # dispatch call to selected chickens if appropriate | |
198 if tool == constants.TOOL_SELL_CHICKEN: | |
199 self.sell_chicken(None) | |
200 return True | |
201 elif tool == constants.TOOL_SELL_EGG: | |
202 self.sell_egg(None) | |
203 return True | |
204 elif tool == constants.TOOL_SELL_EQUIPMENT: | |
205 self.sell_equipment(None) | |
206 return True | |
207 elif equipment.is_equipment(tool): | |
208 self.buy_equipment(None, tool) | |
209 return True | |
210 return False | |
190 | 211 |
191 def set_cursor(self, cursor=None, sprite_curs=None): | 212 def set_cursor(self, cursor=None, sprite_curs=None): |
192 if cursor: | 213 if cursor: |
193 pygame.mouse.set_cursor(*cursor) | 214 pygame.mouse.set_cursor(*cursor) |
194 else: | 215 else: |
253 self.sell_chicken(self.tv.screen_to_tile(e.pos)) | 274 self.sell_chicken(self.tv.screen_to_tile(e.pos)) |
254 elif self.selected_tool == constants.TOOL_SELL_EGG: | 275 elif self.selected_tool == constants.TOOL_SELL_EGG: |
255 self.sell_egg(self.tv.screen_to_tile(e.pos)) | 276 self.sell_egg(self.tv.screen_to_tile(e.pos)) |
256 elif self.selected_tool == constants.TOOL_PLACE_ANIMALS: | 277 elif self.selected_tool == constants.TOOL_PLACE_ANIMALS: |
257 self.place_animal(self.tv.screen_to_tile(e.pos)) | 278 self.place_animal(self.tv.screen_to_tile(e.pos)) |
279 elif self.selected_tool == constants.TOOL_SELECT_CHICKENS: | |
280 self.select_chicken(self.tv.screen_to_tile(e.pos)) | |
258 elif self.selected_tool == constants.TOOL_SELL_BUILDING: | 281 elif self.selected_tool == constants.TOOL_SELL_BUILDING: |
259 self.sell_building(self.tv.screen_to_tile(e.pos)) | 282 self.sell_building(self.tv.screen_to_tile(e.pos)) |
260 elif self.selected_tool == constants.TOOL_SELL_EQUIPMENT: | 283 elif self.selected_tool == constants.TOOL_SELL_EQUIPMENT: |
261 self.sell_equipment(self.tv.screen_to_tile(e.pos)) | 284 self.sell_equipment(self.tv.screen_to_tile(e.pos)) |
262 elif self.selected_tool == constants.TOOL_REPAIR_BUILDING: | 285 elif self.selected_tool == constants.TOOL_REPAIR_BUILDING: |
263 self.repair_building(self.tv.screen_to_tile(e.pos)) | 286 self.repair_building(self.tv.screen_to_tile(e.pos)) |
264 elif buildings.is_building(self.selected_tool): | 287 elif buildings.is_building(self.selected_tool): |
265 self.buy_building(self.tv.screen_to_tile(e.pos), self.selected_tool) | 288 self.buy_building(self.tv.screen_to_tile(e.pos), self.selected_tool) |
266 elif equipment.is_equipment(self.selected_tool): | 289 elif equipment.is_equipment(self.selected_tool): |
267 self.buy_equipment(self.tv.screen_to_tile(e.pos), self.selected_tool) | 290 if not self.selected_chickens: |
291 # old selection behaviour | |
292 self.buy_equipment(self.tv.screen_to_tile(e.pos), | |
293 self.selected_tool) | |
268 | 294 |
269 def get_outside_chicken(self, tile_pos): | 295 def get_outside_chicken(self, tile_pos): |
270 for chick in self.chickens: | 296 for chick in self.chickens: |
271 if chick.covers(tile_pos) and chick.outside(): | 297 if chick.covers(tile_pos) and chick.outside(): |
272 return chick | 298 return chick |
295 if update_button: | 321 if update_button: |
296 update_button(chicken, empty=True) | 322 update_button(chicken, empty=True) |
297 self.remove_chicken(chicken) | 323 self.remove_chicken(chicken) |
298 return True | 324 return True |
299 | 325 |
300 chick = self.get_outside_chicken(tile_pos) | 326 if tile_pos: |
301 if chick is None: | 327 chick = self.get_outside_chicken(tile_pos) |
302 building = self.get_building(tile_pos) | 328 if chick is None: |
303 if building and building.HENHOUSE: | 329 building = self.get_building(tile_pos) |
304 self.open_building_dialog(building, do_sell) | 330 if building and building.HENHOUSE: |
305 return | 331 self.open_building_dialog(building, do_sell) |
306 do_sell(chick) | 332 return |
333 do_sell(chick) | |
334 else: | |
335 for chick in self.selected_chickens[:]: | |
336 do_sell(chick) | |
307 | 337 |
308 def sell_one_egg(self, chicken): | 338 def sell_one_egg(self, chicken): |
309 if chicken.eggs: | 339 if chicken.eggs: |
310 self.add_cash(self.level.sell_price_egg) | 340 self.add_cash(self.level.sell_price_egg) |
311 chicken.remove_one_egg() | 341 chicken.remove_one_egg() |
327 | 357 |
328 building = self.get_building(tile_pos) | 358 building = self.get_building(tile_pos) |
329 if building and building.HENHOUSE: | 359 if building and building.HENHOUSE: |
330 self.open_building_dialog(building, do_sell) | 360 self.open_building_dialog(building, do_sell) |
331 | 361 |
332 def select_animal_to_place(self, animal): | 362 def select_animal(self, animal, extend=True): |
333 if self.animal_to_place: | 363 if extend: |
334 self.animal_to_place.unequip_by_name("Spotlight") | 364 self.selected_chickens.append(animal) |
335 self.animal_to_place = animal | 365 animal.equip(equipment.Spotlight()) |
336 if self.animal_to_place: | 366 else: |
337 self.animal_to_place.equip(equipment.Spotlight()) | 367 self.unselect_all() |
368 self.selected_chickens.append(animal) | |
369 animal.equip(equipment.Spotlight()) | |
370 | |
371 def unselect_all(self): | |
372 # Clear any highlights | |
373 for chick in self.selected_chickens: | |
374 chick.unequip_by_name("Spotlight") | |
375 self.selected_chickens = [] | |
376 | |
377 def unselect_animal(self, animal): | |
378 if animal in self.selected_chickens: | |
379 self.selected_chickens.remove(animal) | |
380 animal.unequip_by_name("Spotlight") | |
381 | |
382 def get_chicken_at_pos(self, tile_pos): | |
383 chicken = self.get_outside_chicken(tile_pos) | |
384 if chicken: | |
385 return chicken | |
386 building = self.get_building(tile_pos) | |
387 if building: | |
388 self.open_building_dialog(building) | |
389 | |
390 def select_chicken(self, tile_pos): | |
391 """Handle a select chicken event""" | |
392 # Get the chicken at this position | |
393 chicken = self.get_chicken_at_pos(tile_pos) | |
394 if not chicken: | |
395 return # do nothing | |
396 elif chicken in self.selected_chickens: | |
397 self.unselect_animal(chicken) | |
398 else: | |
399 self.select_animal(chicken) | |
338 | 400 |
339 def place_animal(self, tile_pos): | 401 def place_animal(self, tile_pos): |
340 """Handle an TOOL_PLACE_ANIMALS click. | 402 """Handle an TOOL_PLACE_ANIMALS click. |
341 | 403 |
342 This will either select an animal or | 404 This will either select an animal or |
343 place a selected animal in a building. | 405 place a selected animal in a building. |
344 """ | 406 """ |
345 chicken = self.get_outside_chicken(tile_pos) | 407 if tile_pos and not self.selected_chickens: |
346 if chicken: | 408 # Old behaviour |
347 if chicken is self.animal_to_place: | 409 chicken = self.get_chicken_at_pos(tile_pos) |
348 self.select_animal_to_place(None) | 410 if chicken: |
349 pygame.mouse.set_cursor(*cursors.cursors['select']) | 411 self.select_animal(chicken) |
350 else: | |
351 self.select_animal_to_place(chicken) | |
352 pygame.mouse.set_cursor(*cursors.cursors['chicken']) | 412 pygame.mouse.set_cursor(*cursors.cursors['chicken']) |
353 return | 413 return |
354 building = self.get_building(tile_pos) | 414 elif tile_pos: |
355 if building and building.ABODE: | 415 building = self.get_building(tile_pos) |
356 if self.animal_to_place: | 416 if building and building.ABODE: |
357 try: | 417 for chicken in self.selected_chickens: |
358 place = building.first_empty_place() | 418 try: |
359 self.relocate_animal(self.animal_to_place, place=place) | 419 place = building.first_empty_place() |
360 self.animal_to_place.equip(equipment.Nest()) | 420 self.relocate_animal(chicken, place=place) |
361 self.select_animal_to_place(None) | 421 chicken.equip(equipment.Nest()) |
362 pygame.mouse.set_cursor(*cursors.cursors['select']) | 422 pygame.mouse.set_cursor(*cursors.cursors['select']) |
363 except buildings.BuildingFullError: | 423 except buildings.BuildingFullError: |
364 pass | 424 pass |
365 else: | 425 else: |
366 self.open_building_dialog(building) | 426 self.open_building_dialog(building) |
367 return | 427 return |
368 if self.tv.get(tile_pos) == self.GRASSLAND: | 428 if self.tv.get(tile_pos) == self.GRASSLAND: |
369 if self.animal_to_place is not None: | 429 for chicken in self.selected_chickens: |
370 self.animal_to_place.unequip_by_name("Nest") | 430 # FIXME: find free square nearby |
371 self.relocate_animal(self.animal_to_place, tile_pos=tile_pos) | 431 if not self.get_outside_chicken(tile_pos): |
372 self.eggs -= self.animal_to_place.get_num_eggs() | 432 chicken.unequip_by_name("Nest") |
373 self.animal_to_place.remove_eggs() | 433 self.relocate_animal(chicken, tile_pos=tile_pos) |
374 self.toolbar.update_egg_counter(self.eggs) | 434 self.eggs -= chicken.get_num_eggs() |
435 chicken.remove_eggs() | |
436 self.toolbar.update_egg_counter(self.eggs) | |
375 | 437 |
376 def relocate_animal(self, chicken, tile_pos=None, place=None): | 438 def relocate_animal(self, chicken, tile_pos=None, place=None): |
377 assert((tile_pos, place) != (None, None)) | 439 assert((tile_pos, place) != (None, None)) |
378 if chicken.abode is not None: | 440 if chicken.abode is not None: |
379 chicken.abode.clear_occupant() | 441 chicken.abode.clear_occupant() |
437 def nest_clicked(place, button): | 499 def nest_clicked(place, button): |
438 """Handle a nest being clicked.""" | 500 """Handle a nest being clicked.""" |
439 if place.occupant: | 501 if place.occupant: |
440 # there is an occupant, select or sell it | 502 # there is an occupant, select or sell it |
441 if not sell_callback: | 503 if not sell_callback: |
442 old_animal = self.animal_to_place | 504 self.select_animal(place.occupant) |
443 self.select_animal_to_place(place.occupant) | |
444 # deselect old animal (on button) | |
445 update_button(old_animal) | |
446 # select new animal (on button) | 505 # select new animal (on button) |
447 update_button(self.animal_to_place) | 506 update_button(place.occupant) |
448 else: | 507 else: |
449 # Attempt to sell the occupant | 508 # Attempt to sell the occupant |
450 sell_callback(place.occupant, update_button) | 509 sell_callback(place.occupant, update_button) |
451 else: | 510 else: |
452 # there is no occupant, attempt to fill the space | 511 # there is no occupant, attempt to fill the space |
453 if self.animal_to_place is not None: | 512 if self.selected_chickens: |
454 # empty old nest (on button) | 513 # empty old nest (on button) |
455 update_button(self.animal_to_place, empty=True) | 514 update_button(self.selected_chickens[0], empty=True) |
456 self.relocate_animal(self.animal_to_place, place=place) | 515 self.relocate_animal(self.selected_chickens[0], place=place) |
457 # populate the new nest (on button) | 516 # populate the new nest (on button) |
458 update_button(self.animal_to_place) | 517 update_button(self.selected_chickens[0]) |
459 | 518 |
460 tbl = gui.Table() | 519 tbl = gui.Table() |
461 columns = building.max_floor_width() | 520 columns = building.max_floor_width() |
462 kwargs = { 'style': { 'padding_left': 10, 'padding_bottom': 10 }} | 521 kwargs = { 'style': { 'padding_left': 10, 'padding_bottom': 10 }} |
463 for floor in building.floors(): | 522 for floor in building.floors(): |
478 building.selected(True) | 537 building.selected(True) |
479 def close_callback(): | 538 def close_callback(): |
480 building.selected(False) | 539 building.selected(False) |
481 | 540 |
482 def evict_callback(): | 541 def evict_callback(): |
483 if not self.animal_to_place: | 542 if not self.selected_chickens: |
484 return | 543 return |
485 for tile_pos in building.adjacent_tiles(): | 544 for chicken in self.selected_chickens: |
486 if self.tv.get(tile_pos) != self.GRASSLAND: | 545 for tile_pos in building.adjacent_tiles(): |
487 continue | 546 if self.tv.get(tile_pos) != self.GRASSLAND: |
488 if self.get_outside_chicken(tile_pos) is None: | 547 continue |
489 update_button(self.animal_to_place, empty=True) | 548 if self.get_outside_chicken(tile_pos) is None: |
490 self.place_animal(tile_pos) | 549 update_button(chicken, empty=True) |
491 break | 550 self.place_animal(tile_pos) |
551 break | |
492 | 552 |
493 if not sell_callback: | 553 if not sell_callback: |
494 tbl.tr() | 554 tbl.tr() |
495 button = gui.Button('Evict') | 555 button = gui.Button('Evict') |
496 button.connect(gui.CLICK, evict_callback) | 556 button.connect(gui.CLICK, evict_callback) |
521 chicken.equip(equipment) | 581 chicken.equip(equipment) |
522 if update_button: | 582 if update_button: |
523 update_button(chicken) | 583 update_button(chicken) |
524 return False | 584 return False |
525 | 585 |
526 chicken = self.get_outside_chicken(tile_pos) | 586 if tile_pos: |
527 if chicken is None: | 587 chicken = self.get_outside_chicken(tile_pos) |
528 building = self.get_building(tile_pos) | 588 if chicken is None: |
529 if not (building and building.ABODE): | 589 building = self.get_building(tile_pos) |
530 return | 590 if not (building and building.ABODE): |
531 # Bounce through open dialog once more | 591 return |
532 self.open_building_dialog(building, do_equip) | 592 # Bounce through open dialog once more |
593 self.open_building_dialog(building, do_equip) | |
594 else: | |
595 do_equip(chicken) | |
533 else: | 596 else: |
534 do_equip(chicken) | 597 for chicken in self.selected_chickens: |
598 do_equip(chicken) | |
535 | 599 |
536 def sell_building(self, tile_pos): | 600 def sell_building(self, tile_pos): |
537 building = self.get_building(tile_pos) | 601 building = self.get_building(tile_pos) |
538 if building is None: | 602 if building is None: |
539 return | 603 return |
740 fox.building.remove_predator(fox) | 804 fox.building.remove_predator(fox) |
741 if fox in self.tv.sprites: | 805 if fox in self.tv.sprites: |
742 self.tv.sprites.remove(fox) | 806 self.tv.sprites.remove(fox) |
743 | 807 |
744 def remove_chicken(self, chick): | 808 def remove_chicken(self, chick): |
745 if chick is self.animal_to_place: | 809 if chick in self.selected_chickens: |
746 self.select_animal_to_place(None) | 810 self.unselect_animal(chick) |
747 self.chickens.discard(chick) | 811 self.chickens.discard(chick) |
748 self.eggs -= chick.get_num_eggs() | 812 self.eggs -= chick.get_num_eggs() |
749 self.toolbar.update_egg_counter(self.eggs) | 813 self.toolbar.update_egg_counter(self.eggs) |
750 if chick.abode: | 814 if chick.abode: |
751 chick.abode.clear_occupant() | 815 chick.abode.clear_occupant() |