source: gamelib/gameboard.py @ 200:67d10f7e0159

Last change on this file since 200:67d10f7e0159 was 200:67d10f7e0159, checked in by Adrianna Pińska <adrianna.pinska@…>, 11 years ago

selected chickens are selected

File size: 27.8 KB
Line 
1import random
2
3import pygame
4from pygame.locals import MOUSEBUTTONDOWN, MOUSEMOTION, KEYDOWN, K_UP, K_DOWN, K_LEFT, K_RIGHT
5from pgu import gui
6
7import data
8import tiles
9import icons
10import constants
11import buildings
12import animal
13import equipment
14import sound
15import cursors
16import sprite_cursor
17
18class OpaqueLabel(gui.Label):
19    def __init__(self, value, **params):
20        gui.Label.__init__(self, value, **params)
21        if 'width' in params:
22            self._width = params['width']
23        if 'height' in params:
24            self._height = params['height']
25        self._set_size()
26
27    def _set_size(self):
28        width, height = self.font.size(self.value)
29        width = getattr(self, '_width', width)
30        height = getattr(self, '_height', height)
31        self.style.width, self.style.height = width, height
32
33    def paint(self, s):
34        s.fill(self.style.background)
35        if self.style.align > 0:
36            r = s.get_rect()
37            w, _ = self.font.size(self.value)
38            s = s.subsurface(r.move((r.w-w, 0)).clip(r))
39        gui.Label.paint(self, s)
40
41    def update_value(self, value):
42        self.value = value
43        self._set_size()
44        self.repaint()
45
46def mklabel(text="", **params):
47    params.setdefault('color', constants.FG_COLOR)
48    params.setdefault('width', GameBoard.TOOLBAR_WIDTH/2)
49    return OpaqueLabel(text, **params)
50
51def mkcountupdate(counter):
52    def update_counter(self, value):
53        getattr(self, counter).update_value("%s  " % value)
54        self.repaint()
55    return update_counter
56
57class ToolBar(gui.Table):
58    def __init__(self, gameboard, **params):
59        gui.Table.__init__(self, **params)
60        self.gameboard = gameboard
61        self.cash_counter = mklabel(align=1)
62        self.chicken_counter = mklabel(align=1)
63        self.egg_counter = mklabel(align=1)
64        self.day_counter = mklabel(align=1)
65        self.killed_foxes = mklabel(align=1)
66
67        self.tr()
68        self.td(gui.Spacer(self.rect.w/2, 0))
69        self.td(gui.Spacer(self.rect.w/2, 0))
70        self.add_counter(mklabel("Day:"), self.day_counter)
71        self.add_counter(mklabel("Groats:"), self.cash_counter)
72        self.add_counter(mklabel("Eggs:"), self.egg_counter)
73        self.add_counter(icons.CHKN_ICON, self.chicken_counter)
74        self.add_counter(icons.KILLED_FOX, self.killed_foxes)
75        self.add_spacer(20)
76
77        self.add_tool_button("Move Hen", constants.TOOL_PLACE_ANIMALS,
78                cursors.cursors['select'])
79        self.add_tool_button("Cut Trees", constants.TOOL_LOGGING)
80        self.add_spacer(20)
81
82        self.add_heading("Sell ...")
83        self.add_tool_button("Chicken", constants.TOOL_SELL_CHICKEN,
84                cursors.cursors['select'])
85        self.add_tool_button("Egg", constants.TOOL_SELL_EGG,
86                cursors.cursors['select'])
87        self.add_tool_button("Building", constants.TOOL_SELL_BUILDING,
88                cursors.cursors['select'])
89        self.add_tool_button("Equipment", constants.TOOL_SELL_EQUIPMENT)
90        self.add_spacer(20)
91
92        self.add_heading("Buy ...")
93        self.add_tool_button("Fence", constants.TOOL_BUY_FENCE)
94        for building_cls in buildings.BUILDINGS:
95            self.add_tool_button(building_cls.NAME.title(), building_cls,
96                    cursors.cursors.get('build', None))
97        for equipment_cls in equipment.EQUIPMENT:
98            self.add_tool_button(equipment_cls.NAME.title(), equipment_cls,
99                    cursors.cursors.get(equipment_cls.NAME, None))
100        self.add_spacer(30)
101
102        self.add_button("Finished Day", self.day_done)
103
104    def day_done(self):
105        import engine
106        pygame.event.post(engine.START_NIGHT)
107
108    update_cash_counter = mkcountupdate('cash_counter')
109    update_fox_counter = mkcountupdate('killed_foxes')
110    update_chicken_counter = mkcountupdate('chicken_counter')
111    update_egg_counter = mkcountupdate('egg_counter')
112    update_day_counter = mkcountupdate('day_counter')
113
114    def add_spacer(self, height):
115        self.tr()
116        self.td(gui.Spacer(0, height), colspan=2)
117
118    def add_heading(self, text):
119        self.tr()
120        self.td(mklabel(text), colspan=2)
121
122    def add_tool_button(self, text, tool, cursor=None):
123        self.add_button(text, lambda: self.gameboard.set_selected_tool(tool,
124            cursor))
125
126    def add_button(self, text, func):
127        button = gui.Button(text, width=self.rect.w, style={"padding_left": 0})
128        button.connect(gui.CLICK, func)
129        self.tr()
130        self.td(button, align=-1, colspan=2)
131
132    def add_counter(self, icon, label):
133        self.tr()
134        self.td(icon, width=self.rect.w/2)
135        self.td(label, width=self.rect.w/2)
136
137    def resize(self, width=None, height=None):
138        width, height = gui.Table.resize(self, width, height)
139        width = GameBoard.TOOLBAR_WIDTH
140        return width, height
141
142
143class VidWidget(gui.Widget):
144    def __init__(self, gameboard, vid, **params):
145        gui.Widget.__init__(self, **params)
146        self.gameboard = gameboard
147        self.vid = vid
148        self.vid.bounds = pygame.Rect((0, 0), vid.tile_to_view(vid.size))
149
150    def paint(self, surface):
151        self.vid.paint(surface)
152
153    def update(self, surface):
154        return self.vid.update(surface)
155
156    def move_view(self, x, y):
157        self.vid.view.move_ip((x, y))
158
159    def event(self, e):
160        if e.type == MOUSEBUTTONDOWN:
161            self.gameboard.use_tool(e)
162        elif e.type == MOUSEMOTION and self.gameboard.sprite_cursor:
163            self.gameboard.update_sprite_cursor(e)
164
165
166class GameBoard(object):
167    TILE_DIMENSIONS = (20, 20)
168    TOOLBAR_WIDTH = 140
169
170    GRASSLAND = tiles.REVERSE_TILE_MAP['grassland']
171    FENCE = tiles.REVERSE_TILE_MAP['fence']
172    WOODLAND = tiles.REVERSE_TILE_MAP['woodland']
173    BROKEN_FENCE = tiles.REVERSE_TILE_MAP['broken fence']
174
175    def __init__(self, main_app):
176        self.disp = main_app
177        self.tv = tiles.FarmVid()
178        self.tv.tga_load_tiles(data.filepath('tiles.tga'), self.TILE_DIMENSIONS)
179        self.tv.png_folder_load_tiles(data.filepath('tiles'))
180        self.tv.tga_load_level(data.filepath('level1.tga'))
181        self.create_display()
182
183        self.selected_tool = None
184        self.animal_to_place = None
185        self.sprite_cursor = None
186        self.chickens = set()
187        self.foxes = set()
188        self.buildings = []
189        self.cash = 0
190        self.eggs = 0
191        self.days = 0
192        self.killed_foxes = 0
193        self.add_cash(constants.STARTING_CASH)
194
195        self.fix_buildings()
196
197        self.add_some_chickens()
198
199    def get_top_widget(self):
200        return self.top_widget
201
202    def create_display(self):
203        width, height = self.disp.rect.w, self.disp.rect.h
204        tbl = gui.Table()
205        tbl.tr()
206        self.toolbar = ToolBar(self, width=self.TOOLBAR_WIDTH)
207        tbl.td(self.toolbar, valign=-1)
208        self.tvw = VidWidget(self, self.tv, width=width-self.TOOLBAR_WIDTH, height=height)
209        tbl.td(self.tvw)
210        self.top_widget = tbl
211
212    def update(self):
213        self.tvw.reupdate()
214
215    def loop(self):
216        self.tv.loop()
217
218    def set_selected_tool(self, tool, cursor):
219        self.selected_tool = tool
220        self.select_animal_to_place(None)
221        if cursor:
222            pygame.mouse.set_cursor(*cursor)
223        else:
224            pygame.mouse.set_cursor(*cursors.cursors['arrow'])
225        if self.sprite_cursor:
226            self.tv.sprites.remove(self.sprite_cursor)
227            self.sprite_cursor = None
228        if buildings.is_building(tool):
229            self.sprite_cursor = sprite_cursor.SpriteCursor(tool.IMAGE, self.tv)
230            self.tv.sprites.append(self.sprite_cursor)
231
232    def reset_cursor(self):
233        pygame.mouse.set_cursor(*cursors.cursors['arrow'])
234
235    def update_sprite_cursor(self, e):
236        tile_pos = self.tv.screen_to_tile(e.pos)
237        self.sprite_cursor.set_pos(tile_pos)
238
239    def in_bounds(self, pos):
240        """Check if a position is within the game boundaries"""
241        if pos.x < 0 or pos.y < 0:
242            return False
243        width, height = self.tv.size
244        if pos.x >= width or pos.y >= height:
245            return False
246        return True
247
248    def use_tool(self, e):
249        if e.button == 3: # Right button
250            self.selected_tool = None
251            self.reset_cursor()
252        elif e.button != 1: # Left button
253            return
254        if self.selected_tool == constants.TOOL_SELL_CHICKEN:
255            self.sell_chicken(self.tv.screen_to_tile(e.pos))
256        elif self.selected_tool == constants.TOOL_SELL_EGG:
257            self.sell_egg(self.tv.screen_to_tile(e.pos))
258        elif self.selected_tool == constants.TOOL_PLACE_ANIMALS:
259            self.place_animal(self.tv.screen_to_tile(e.pos))
260        elif self.selected_tool == constants.TOOL_BUY_FENCE:
261            self.buy_fence(self.tv.screen_to_tile(e.pos))
262        elif self.selected_tool == constants.TOOL_SELL_BUILDING:
263            self.sell_building(self.tv.screen_to_tile(e.pos))
264        elif self.selected_tool == constants.TOOL_SELL_EQUIPMENT:
265            self.sell_equipment(self.tv.screen_to_tile(e.pos))
266        elif self.selected_tool == constants.TOOL_LOGGING:
267            self.logging_forest(self.tv.screen_to_tile(e.pos))
268        elif buildings.is_building(self.selected_tool):
269            self.buy_building(self.tv.screen_to_tile(e.pos), self.selected_tool)
270        elif equipment.is_equipment(self.selected_tool):
271            self.buy_equipment(self.tv.screen_to_tile(e.pos), self.selected_tool)
272
273    def get_outside_chicken(self, tile_pos):
274        for chick in self.chickens:
275            if chick.covers(tile_pos) and chick.outside():
276                return chick
277        return None
278
279    def get_building(self, tile_pos):
280        for building in self.buildings:
281            if building.covers(tile_pos):
282                return building
283        return None
284
285    def sell_chicken(self, tile_pos):
286
287        def do_sell(chicken):
288            if not chicken:
289                return False # sanity check
290            if len(self.chickens) == 1:
291                print "You can't sell your last chicken!"
292                return False
293            self.add_cash(constants.SELL_PRICE_CHICKEN)
294            sound.play_sound("sell-chicken.ogg")
295            self.remove_chicken(chicken)
296            return True
297
298        chick = self.get_outside_chicken(tile_pos)
299        if chick is None:
300            building = self.get_building(tile_pos)
301            if building and building.NAME in buildings.HENHOUSES:
302                self.open_building_dialog(building, do_sell)
303            return
304        do_sell(chick)
305
306
307    def sell_egg(self, tile_pos):
308        def do_sell(chicken):
309            if chicken.egg:
310                # We sell the egg
311                self.add_cash(constants.SELL_PRICE_EGG)
312                sound.play_sound("sell-chicken.ogg")
313                chicken.egg = None
314                self.eggs -= 1
315                self.toolbar.update_egg_counter(self.eggs)
316                # Force update
317                self.toolbar.chsize()
318            return False
319
320        building = self.get_building(tile_pos)
321        if building and building.NAME in buildings.HENHOUSES:
322            self.open_building_dialog(building, do_sell)
323
324    def select_animal_to_place(self, animal):
325        if self.animal_to_place:
326            self.animal_to_place.unequip_by_name("spotlight")
327        self.animal_to_place = animal
328        if self.animal_to_place:
329            self.animal_to_place.equip(equipment.Spotlight())
330
331    def place_animal(self, tile_pos):
332        """Handle an TOOL_PLACE_ANIMALS click.
333
334           This will either select an animal or
335           place a selected animal in a building.
336           """
337        chicken = self.get_outside_chicken(tile_pos)
338        if chicken:
339            if chicken is self.animal_to_place:
340                self.select_animal_to_place(None)
341                pygame.mouse.set_cursor(*cursors.cursors['select'])
342            else:
343                self.select_animal_to_place(chicken)
344                pygame.mouse.set_cursor(*cursors.cursors['chicken'])
345            return
346        building = self.get_building(tile_pos)
347        if building:
348            if self.animal_to_place:
349                try:
350                    place = building.first_empty_place()
351                    self.relocate_animal(self.animal_to_place, place=place)
352                    self.select_animal_to_place(None)
353                    pygame.mouse.set_cursor(*cursors.cursors['select'])
354                except buildings.BuildingFullError:
355                    pass
356            else:
357                self.open_building_dialog(building)
358            return
359        if self.tv.get(tile_pos) == self.GRASSLAND:
360            if self.animal_to_place is not None:
361                self.relocate_animal(self.animal_to_place, tile_pos=tile_pos)
362
363    def relocate_animal(self, chicken, tile_pos=None, place=None):
364        assert((tile_pos, place) != (None, None))
365        if chicken.abode is not None:
366            chicken.abode.clear_occupant()
367        if tile_pos:
368            chicken.set_pos(tile_pos)
369        else:
370            place.set_occupant(chicken)
371            chicken.set_pos(place.get_pos())
372        self.set_visibility(chicken)
373
374    def set_visibility(self, chicken):
375        if chicken.outside():
376            if chicken not in self.tv.sprites:
377                self.tv.sprites.append(chicken)
378        else:
379            if chicken in self.tv.sprites:
380                self.tv.sprites.remove(chicken)
381
382    def open_dialog(self, widget, close_callback=None):
383        """Open a dialog for the given widget. Add close button."""
384        tbl = gui.Table()
385
386        def close_dialog():
387            self.disp.close(tbl)
388            if close_callback is not None:
389                close_callback()
390
391        close_button = gui.Button("Close")
392        close_button.connect(gui.CLICK, close_dialog)
393
394        tbl = gui.Table()
395        tbl.tr()
396        tbl.td(widget, colspan=2)
397        tbl.tr()
398        tbl.td(gui.Spacer(100, 0))
399        tbl.td(close_button, align=1)
400
401        self.disp.open(tbl)
402        return tbl
403
404    def open_building_dialog(self, building, sell_callback=None):
405        """Create dialog for manipulating the contents of a building."""
406        def select_occupant(place, button, sell_callback):
407            """Select occupant in place."""
408            # sell_callback should return true if we need to remove the
409            # occupant
410            self.select_animal_to_place(place.occupant)
411            if not sell_callback:
412                pygame.mouse.set_cursor(*cursors.cursors['chicken'])
413            else:
414                # Attempt to sell the occupant
415                self.select_animal_to_place(None)
416                if sell_callback(place.occupant):
417                    button.value = icons.EMPTY_NEST_ICON
418                    button.disconnect(gui.CLICK, select_occupant)
419                    button.connect(gui.CLICK, set_occupant, place, button,
420                            sell_callback)
421
422        def set_occupant(place, button, sell_callback):
423            """Set occupant of a given place."""
424            if self.animal_to_place is not None:
425                button.value = icons.CHKN_NEST_ICON
426                button.disconnect(gui.CLICK, set_occupant)
427                button.connect(gui.CLICK, select_occupant, place, button,
428                        sell_callback)
429
430                old_abode = self.animal_to_place.abode
431                if id(old_abode) in place_button_map:
432                    old_button = place_button_map[id(old_abode)]
433                    old_button.value = icons.EMPTY_NEST_ICON
434                    old_button.disconnect(gui.CLICK, select_occupant)
435                    old_button.connect(gui.CLICK, set_occupant, place, button,
436                            sell_callback)
437
438                self.relocate_animal(self.animal_to_place, place=place)
439
440        place_button_map = {}
441
442        tbl = gui.Table()
443        columns = building.max_floor_width()
444        kwargs = { 'style': { 'padding_left': 10, 'padding_bottom': 10 }}
445        for floor in building.floors():
446            tbl.tr()
447            tbl.td(gui.Button(floor.title), colspan=columns, align=-1, **kwargs)
448            tbl.tr()
449            for row in floor.rows():
450                tbl.tr()
451                for place in row:
452                    if place.occupant is None:
453                        button = gui.Button(icons.EMPTY_NEST_ICON)
454                        button.connect(gui.CLICK, set_occupant, place, button,
455                                sell_callback)
456                    else:
457                        button = gui.Button(icons.CHKN_NEST_ICON)
458                        button.connect(gui.CLICK, select_occupant, place, button,
459                                sell_callback)
460                    place_button_map[id(place)] = button
461                    tbl.td(button, **kwargs)
462
463        building.selected(True)
464        def close_callback():
465            building.selected(False)
466
467        self.open_dialog(tbl, close_callback=close_callback)
468
469    def buy_fence(self, tile_pos):
470        this_tile = self.tv.get(tile_pos)
471        if this_tile not in [self.GRASSLAND, self.BROKEN_FENCE]:
472            return
473        if this_tile == self.GRASSLAND:
474            cost = constants.BUY_PRICE_FENCE
475        else:
476            cost = constants.REPAIR_PRICE_FENCE
477        if any((chicken.pos.x, chicken.pos.y) == tile_pos for chicken in self.chickens):
478            return
479
480        if self.cash < cost:
481            print "You can't afford a fence."
482            return
483        self.add_cash(-cost)
484        self.tv.set(tile_pos, self.FENCE)
485
486    def sell_fence(self, tile_pos):
487        if self.tv.get(tile_pos) != self.FENCE:
488            return
489        self.add_cash(constants.SELL_PRICE_FENCE)
490        self.tv.set(tile_pos, self.GRASSLAND)
491
492    def logging_forest(self, tile_pos):
493        if self.tv.get(tile_pos) != self.WOODLAND:
494            return
495        if self.cash < constants.LOGGING_PRICE:
496            return
497        self.add_cash(-constants.LOGGING_PRICE)
498        self.tv.set(tile_pos, self.GRASSLAND)
499
500    def buy_building(self, tile_pos, building_cls):
501        building = building_cls(tile_pos)
502        if self.cash < building.buy_price():
503            return
504        if any(building.covers((chicken.pos.x, chicken.pos.y)) for chicken in self.chickens):
505            return
506        if building.place(self.tv):
507            self.add_cash(-building.buy_price())
508            self.add_building(building)
509
510    def buy_equipment(self, tile_pos, equipment_cls):
511        chicken = self.get_outside_chicken(tile_pos)
512        equipment = equipment_cls()
513        if chicken is None or self.cash < equipment.buy_price():
514            return
515        if equipment.place(chicken):
516            self.add_cash(-equipment.buy_price())
517            chicken.equip(equipment)
518
519    def sell_building(self, tile_pos):
520        if self.tv.get(tile_pos) == self.FENCE:
521            return self.sell_fence(tile_pos)
522        building = self.get_building(tile_pos)
523        if building is None:
524            return
525        if list(building.occupants()):
526            warning = gui.Button("Occupied buildings may not be sold.")
527            self.open_dialog(warning)
528            return
529        self.add_cash(building.sell_price())
530        building.remove(self.tv)
531        self.remove_building(building)
532
533    def sell_equipment(self, tile_pos):
534        chicken = self.get_outside_chicken(tile_pos)
535        if chicken is None or not chicken.equipment:
536            return
537        if len(chicken.equipment) == 1:
538            item = chicken.equipment[0]
539            self.add_cash(item.sell_price())
540            chicken.unequip(item)
541        else:
542            self.open_equipment_dialog(chicken)
543
544    def open_equipment_dialog(self, chicken):
545        tbl = gui.Table()
546
547        def sell_item(item, button):
548            """Select item of equipment."""
549            self.add_cash(item.sell_price())
550            chicken.unequip(item)
551            self.disp.close(dialog)
552
553        kwargs = { 'style': { 'padding_left': 10, 'padding_bottom': 10 }}
554
555        tbl.tr()
556        tbl.td(gui.Button("Sell ...     "), align=-1, **kwargs)
557
558        for item in chicken.equipment:
559            tbl.tr()
560            button = gui.Button(item.name().title())
561            button.connect(gui.CLICK, sell_item, item, button)
562            tbl.td(button, align=1, **kwargs)
563
564        dialog = self.open_dialog(tbl)
565
566    def event(self, e):
567        if e.type == KEYDOWN:
568            if e.key == K_UP:
569                self.tvw.move_view(0, -self.TILE_DIMENSIONS[1])
570            if e.key == K_DOWN:
571                self.tvw.move_view(0, self.TILE_DIMENSIONS[1])
572            if e.key == K_LEFT:
573                self.tvw.move_view(-self.TILE_DIMENSIONS[0], 0)
574            if e.key == K_RIGHT:
575                self.tvw.move_view(self.TILE_DIMENSIONS[0], 0)
576        else:
577            self.disp.event(e)
578
579    def advance_day(self):
580        self.days += 1
581        self.toolbar.update_day_counter(self.days)
582
583    def clear_foxes(self):
584        for fox in self.foxes.copy():
585            # Any foxes that didn't make it to the woods are automatically
586            # killed
587            if self.in_bounds(fox.pos) and self.tv.get(fox.pos.to_tuple()) \
588                    != self.WOODLAND:
589                self.kill_fox(fox)
590            else:
591                self.tv.sprites.remove(fox)
592        self.foxes = set() # Remove all the foxes
593
594    def move_foxes(self):
595        """Move the foxes.
596       
597           We return True if there are no more foxes to move or all the
598           foxes are safely back. This end's the night"""
599        if not self.foxes:
600            return True
601        over = True
602        for fox in self.foxes:
603            fox.move(self)
604            if not fox.safe:
605                over = False
606        for chicken in self.chickens:
607            chicken.attack(self)
608        return over
609
610    def add_chicken(self, chicken):
611        self.chickens.add(chicken)
612        if chicken.outside():
613            self.tv.sprites.append(chicken)
614        self.toolbar.update_chicken_counter(len(self.chickens))
615
616    def add_fox(self, fox):
617        self.foxes.add(fox)
618        self.tv.sprites.append(fox)
619
620    def add_building(self, building):
621        self.buildings.append(building)
622        self.tv.sprites.append(building)
623
624    def lay_eggs(self):
625        self.eggs = 0
626        for building in self.buildings:
627            if building.NAME in buildings.HENHOUSES:
628                for chicken in building.occupants():
629                    chicken.lay()
630                    if chicken.egg:
631                        self.eggs += 1
632        self.toolbar.update_egg_counter(self.eggs)
633
634    def hatch_eggs(self):
635        for building in self.buildings:
636            if building.NAME in buildings.HENHOUSES:
637                for chicken in building.occupants():
638                    new_chick = chicken.hatch()
639                    if new_chick:
640                        self.eggs -= 1
641                        try:
642                            building.add_occupant(new_chick)
643                            self.add_chicken(new_chick)
644                        except buildings.BuildingFullError:
645                            print "Building full."
646        self.toolbar.update_egg_counter(self.eggs)
647
648    def kill_fox(self, fox):
649        if fox in self.foxes:
650            if not fox.survive_damage():
651                self.killed_foxes += 1
652                self.toolbar.update_fox_counter(self.killed_foxes)
653                self.add_cash(constants.SELL_PRICE_DEAD_FOX)
654                self.remove_fox(fox)
655
656    def remove_fox(self, fox):
657        self.foxes.discard(fox)
658        if fox in self.tv.sprites:
659            self.tv.sprites.remove(fox)
660
661    def remove_chicken(self, chick):
662        self.chickens.discard(chick)
663        if chick.egg:
664            self.eggs -= 1
665            self.toolbar.update_egg_counter(self.eggs)
666        if chick.abode:
667            chick.abode.clear_occupant()
668        self.toolbar.update_chicken_counter(len(self.chickens))
669        if chick in self.tv.sprites and chick.outside():
670            self.tv.sprites.remove(chick)
671
672    def remove_building(self, building):
673        if building in self.buildings:
674            self.buildings.remove(building)
675            self.tv.sprites.remove(building)
676
677    def add_cash(self, amount):
678        self.cash += amount
679        self.toolbar.update_cash_counter(self.cash)
680
681    def add_some_chickens(self):
682        """Add some random chickens to start the game"""
683        x, y = 0, 0
684        width, height = self.tv.size
685        while len(self.chickens) < 10:
686            if x < width:
687                tile = self.tv.get((x, y))
688            else:
689                y += 1
690                if y >= height:
691                    break
692                x = 0
693                continue
694            # See if we place a chicken
695            if 'grassland' == tiles.TILE_MAP[tile]:
696                # Farmland
697                roll = random.randint(1, 20)
698                # We don't place within a tile of the fence, this is to make things
699                # easier
700                for xx in range(x-1, x+2):
701                    if xx >= width or xx < 0:
702                        continue
703                    for yy in range(y-1, y+2):
704                        if yy >= height or yy < 0:
705                            continue
706                        neighbour = self.tv.get((xx, yy))
707                        if 'fence' == tiles.TILE_MAP[neighbour]:
708                            # Fence
709                            roll = 10
710                if roll == 1:
711                    # Create a chicken
712                    chick = animal.Chicken((x, y))
713                    self.add_chicken(chick)
714            x += 1
715
716    def spawn_foxes(self):
717        """The foxes come at night, and this is where they come from."""
718        # Foxes spawn just outside the map
719        x, y = 0, 0
720        width, height = self.tv.size
721        new_foxes = random.randint(3, 7)
722        while len(self.foxes) < new_foxes:
723            side = random.randint(0, 3)
724            if side == 0:
725                # top
726                y = -1
727                x = random.randint(-1, width)
728            elif side == 1:
729                # bottom
730                y = height
731                x = random.randint(-1, width)
732            elif side == 2:
733                # left
734                x = -1
735                y = random.randint(-1, height)
736            else:
737                x = width
738                y = random.randint(-1, height)
739            skip = False
740            for other_fox in self.foxes:
741                if other_fox.pos.x == x and other_fox.pos.y == y:
742                    skip = True # Choose a new position
743                    break
744            if not skip:
745                roll = random.randint(0, 10)
746                if roll < 8:
747                    fox = animal.Fox((x, y))
748                elif roll < 9:
749                    fox = animal.NinjaFox((x, y))
750                else:
751                    fox = animal.GreedyFox((x, y))
752                self.add_fox(fox)
753
754    def fix_buildings(self):
755        """Go through the level map looking for buildings that haven't
756           been added to self.buildings and adding them.
757
758           Where partial buildings exist (i.e. places where the building
759           cannot fit on the available tiles) the building is added anyway
760           to the top left corner.
761
762           Could be a lot faster.
763           """
764        tile_to_building = dict((b.TILE_NO, b) for b in buildings.BUILDINGS)
765
766        w, h = self.tv.size
767        for x in xrange(w):
768            for y in xrange(h):
769                tile_pos = (x, y)
770                tile_no = self.tv.get(tile_pos)
771                if tile_no not in tile_to_building:
772                    continue
773
774                covered = False
775                for building in self.buildings:
776                    if building.covers(tile_pos):
777                        covered = True
778                        break
779
780                if covered:
781                    continue
782
783                building_cls = tile_to_building[tile_no]
784                building = building_cls(tile_pos)
785                building.remove(self.tv)
786                building.place(self.tv)
787                self.add_building(building)
788
789    def is_game_over(self):
790        """Return true if we're complete"""
791        if self.days > constants.TURN_LIMIT:
792            return True
793        if len(self.chickens) == 0:
794            return True
Note: See TracBrowser for help on using the repository browser.