Package horizons :: Package world :: Package disaster
[hide private]
[frames] | no frames]

Source Code for Package horizons.world.disaster

  1  # ################################################### 
  2  # Copyright (C) 2008-2017 The Unknown Horizons Team 
  3  # team@unknown-horizons.org 
  4  # This file is part of Unknown Horizons. 
  5  # 
  6  # Unknown Horizons is free software; you can redistribute it and/or modify 
  7  # it under the terms of the GNU General Public License as published by 
  8  # the Free Software Foundation; either version 2 of the License, or 
  9  # (at your option) any later version. 
 10  # 
 11  # This program is distributed in the hope that it will be useful, 
 12  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 13  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 14  # GNU General Public License for more details. 
 15  # 
 16  # You should have received a copy of the GNU General Public License 
 17  # along with this program; if not, write to the 
 18  # Free Software Foundation, Inc., 
 19  # 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA 
 20  # ################################################### 
 21   
 22  import logging 
 23  from typing import Optional 
 24   
 25  from horizons.component.storagecomponent import StorageComponent 
 26  from horizons.constants import GAME_SPEED 
 27  from horizons.scheduler import Scheduler 
 28  from horizons.util.worldobject import WorldObject 
 29  from horizons.world.settlement import Settlement 
30 31 32 -class Disaster(WorldObject):
33 """Prototype class for disasters.""" 34 log = logging.getLogger("world.disaster") 35 36 TYPE = None # type: str 37 38 # Chance this disaster is seeded into a settlement in a tick of the 39 # disaster manager 40 SEED_CHANCE = 0.5 41 42 # Time in ticks this disasters pauses between each expansion 43 EXPANSION_TIME = GAME_SPEED.TICKS_PER_SECOND * 5 44 45 # Resource to distribute to infected buildings 46 # This is how preventory units (doctors) spot affected buildings. 47 DISASTER_RES = None # type: Optional[int] 48
49 - def __init__(self, settlement, manager):
50 """ 51 @param settlement: Settlement instance this disaster operates on 52 @param manager: The disaster manager that initiated this disaster 53 """ 54 super().__init__() 55 assert isinstance(settlement, Settlement), "Not a settlement!" 56 self._settlement = settlement 57 self._manager = manager
58
59 - def save(self, db):
60 ticks = Scheduler().get_remaining_ticks(self, self.expand, True) 61 db("INSERT INTO disaster(rowid, type, remaining_ticks_expand, settlement) VALUES(?, ?, ?, ?)", 62 self.worldid, self.__class__.TYPE, ticks, self._settlement.worldid)
63
64 - def load(self, db, worldid):
65 ticks = db("SELECT remaining_ticks_expand from disaster where rowid = ?", worldid)[0][0] 66 Scheduler().add_new_object(self.expand, self, run_in=ticks, loops=-1, 67 loop_interval=self.EXPANSION_TIME)
68
69 - def evaluate(self):
70 """Called to evaluate if this disaster is still active""" 71 raise NotImplementedError
72
73 - def expand(self):
74 """Called to make the disaster expand further""" 75 raise NotImplementedError
76
77 - def infect(self, building, load):
78 """Used to expand disaster to this building. Usually called by expand and breakout 79 @load: (db, disaster_worldid), set on restoring infected state of savegame""" 80 self.log.debug("%s infecting %s at %s", self, building, building.position) 81 building.disaster = self 82 if self.DISASTER_RES is not None and not load: # in load, storage save/load will kick in 83 remnant = building.get_component(StorageComponent).inventory.alter(self.DISASTER_RES, 1) 84 assert remnant == 0, 'remn: ' + str(remnant) + " " + str(building)
85
86 - def recover(self, building):
87 """Inverse of infect(). Is also called when buildings are torn down by the user.""" 88 self.log.debug("%s recovering %s at %s", self, building, building.position) 89 del building.disaster 90 if self.DISASTER_RES is not None: 91 # make sure to remove everything in case of random recovery 92 inv = building.get_component(StorageComponent).inventory 93 if inv[self.DISASTER_RES] > 0: 94 remnant = inv.alter(self.DISASTER_RES, -inv[self.DISASTER_RES]) 95 assert remnant == 0, 'remn: ' + str(remnant) + " " + str(building)
96
97 - def breakout(self):
98 """Picks (a) object(s) to start a breakout.""" 99 Scheduler().add_new_object(self.expand, self, run_in=self.EXPANSION_TIME, loops=-1)
100
101 - def wreak_havoc(self, building):
102 """The implementation to whatever the disaster does to affected 103 objects goes here""" 104 self.log.debug("%s wreak havoc %s at %s", self, building, building.position) 105 del building.disaster
106 107 @classmethod
108 - def can_breakout(cls, settlement):
109 """Returns whether or not a disaster can break out in the 110 settlement""" 111 raise NotImplementedError
112
113 - def end(self):
114 """End this class, used for cleanup. Called by the DisasterManager 115 in end_disaster() automatically""" 116 pass
117