1 # ###################################################
2 # Copyright (C) 2008 The OpenAnno Team
4 # This file is part of OpenAnno.
6 # OpenAnno 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.
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.
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 # ###################################################
22 from game
.world
.units
.unit
import Unit
23 from game
.world
.storageholder
import StorageHolder
24 from game
.util
import Rect
, Point
25 from game
.world
.pathfinding
import Movement
26 from game
.world
.production
import PrimaryProducer
32 class BuildingCollector(StorageHolder
, Unit
):
33 movement
= Movement
.CARRIAGE_MOVEMENT
35 How does this class work ?
39 |- get_job - he found a job ( it's best )
43 def __init__(self
, home_building
, slots
= 1, size
= 6, start_hidden
=True, **kwargs
):
44 super(BuildingCollector
, self
).__init
__(x
=home_building
.position
.origin
.x
,
45 y
=home_building
.position
.origin
.y
,
49 #print 'carriage beeing inited'
50 self
.home_building
= weakref
.ref(home_building
)
51 self
.inventory
.limit
= size
;
52 #for res in home_building.get_consumed_res(): # NOTE: this does not work for multiple production lines yet.
53 # if not self.inventory.hasSlot(res):
54 # self.inventory.addSlot(res, size)
56 self
.start_hidden
= start_hidden
60 # start searching jobs just when construction (of subclass) is completed
61 game
.main
.session
.scheduler
.add_new_object(self
.search_job
, self
, 1)
64 super(BuildingCollector
, self
).save(db
)
65 db("UPDATE unit SET owner = ? WHERE rowid = ?", self
.home_building().getId(), self
.getId())
66 #print 'savin job', (self.job is not None)
67 if self
.job
is not None:
68 db("INSERT INTO collector_job(rowid, object, resource, amount) VALUES(?, ?, ?, ?)", self
.getId(), self
.job
.object.getId(), self
.job
.res
, self
.job
.amount
)
71 # state of current job
74 """Search for a job, only called if the collector does not have a job."""
75 self
.job
= self
.get_job()
77 #print self.id, 'JOB NONE'
78 game
.main
.session
.scheduler
.add_new_object(self
.search_job
, self
, 32)
80 #print self.id, 'EXECUTE JOB'
81 self
.begin_current_job()
84 """Returns the next job or None"""
86 if self
.home_building() is None:
89 #print self.id, 'GET JOB'
90 collectable_res
= self
.get_collectable_res()
91 if len(collectable_res
) == 0:
94 for building
in self
.get_buildings_in_range():
95 #if isinstance(building, self.home_building().__class__): # Continue if building is of the same class as the home building, to prevent e.g. weaver picking up from weaver.
97 for res
in collectable_res
:
98 if isinstance(building
, PrimaryProducer
) and building
.active_production_line
is not None and building
.production
[building
.active_production_line
].production
.get(res
,1) < 0:
100 res_amount
= building
.inventory
[res
]
102 # get sum of picked up resources by other collectors for res
103 total_pickup_amount
= sum([ carriage
.job
.amount
for carriage
in building
._Provider
__collectors
if carriage
.job
.res
== res
])
104 # check how much will be delivered
105 total_registered_amount_consumer
= sum([ carriage
.job
.amount
for carriage
in self
.home_building()._Consumer
__collectors
if carriage
.job
.res
== res
])
106 # check if there are resources left to pickup
107 max_consumer_res_free
= self
.home_building().inventory
.get_limit(res
)-(total_registered_amount_consumer
+self
.home_building().inventory
[res
])
108 if res_amount
> total_pickup_amount
and max_consumer_res_free
> 0:
110 jobs
.append(Job(building
, res
, min(res_amount
- total_pickup_amount
, self
.inventory
.get_limit(res
), max_consumer_res_free
)))
113 jobs
.sort(key
=operator
.attrgetter('rating') )
117 if self
.check_move(job
.object.position
):
121 def setup_new_job(self
):
122 """Executes the necessary actions to begin a new job"""
123 self
.job
.object._Provider
__collectors
.append(self
)
124 self
.home_building()._Consumer
__collectors
.append(self
)
126 def begin_current_job(self
):
127 """Executes the current job"""
128 #print self.id, 'BEGIN CURRENT JOB'
131 self
.move(self
.job
.object.position
, self
.begin_working
)
133 def begin_working(self
):
134 """Pretends that the collector works by waiting some time"""
135 # uncomment the following line when all collectors have a "stopped" animation
136 #self._instance.act("stopped", self._instance.getFacingLocation(), True)
138 #print self.getId(), 'BEGIN WORKING'
139 game
.main
.session
.scheduler
.add_new_object(self
.finish_working
, self
, 16)
143 def finish_working(self
):
145 #print self.getId(), 'FINISH WORKING'
146 self
.act("default", self
._instance
.getFacingLocation(), True)
149 # deregister at the target we're at
150 self
.job
.object._Provider
__collectors
.remove(self
)
152 self
.move_home(callback
=self
.reached_home
)
157 #print self.getId(), 'Rerouting from', self.position
159 #print "Old job %s" % self.job
161 # Check if there is a new job
163 # There is a new job!
165 #print "New job %s" % self.job
166 self
.begin_current_job()
168 # There is no new job...
169 # Return home and end job
170 self
.move_home(callback
=self
.reached_home
)
172 def reached_home(self
):
173 """ we finished now our complete work. Let's do it again in 32 ticks
174 you can use this as event as after work
176 #print self.id, 'FINISHED WORK'
178 if self
.home_building() is not None:
179 remnant
= self
.home_building().inventory
.alter(self
.job
.res
, self
.job
.amount
)
180 #assert(remnant == 0, "Home building could not take all ressources from carriage.")
181 remnant
= self
.inventory
.alter(self
.job
.res
, -self
.job
.amount
)
182 #assert(remnant == 0, "Carriage did not pick up amount of ressources specified by the job.")
183 self
.home_building()._Consumer
__collectors
.remove(self
)
187 # he finished the job now
188 # before the new job can begin this will be executed
189 if self
.start_hidden
:
191 game
.main
.session
.scheduler
.add_new_object(self
.search_job
, self
, 32)
193 def transfer_res(self
):
194 #print self.id, 'TRANSFER PICKUP'
195 res_amount
= self
.job
.object.pickup_resources(self
.job
.res
, self
.job
.amount
)
196 # should not to be. register_collector function at the building should prevent it
197 #print self.id, 'TRANSFERED res:', self.job.res,' amount: ', res_amount,' we should :', self.job.amount
198 assert(res_amount
== self
.job
.amount
, "Carriage could not pickup amount of ressources, that was planned for the current job.")
199 self
.inventory
.alter(self
.job
.res
, res_amount
)
201 def get_collectable_res(self
):
202 """Gets all resources the Collector can collect"""
203 #print self.id, 'GET COLLECTABLE RES'
204 # find needed res (only res that we have free room for) - Building function
205 return self
.home_building().get_needed_res()
207 def get_buildings_in_range(self
):
208 #print self.id, 'GET BUILDINGS IN RANGE'
209 """returns all buildings in range
210 Overwrite in subclasses that need ranges arroung the pickup."""
211 from game
.world
.provider
import Provider
212 return [building
for building
in self
.home_building().get_buildings_in_range() if isinstance(building
, Provider
)]
214 def move_home(self
, callback
=None):
215 self
.move(self
.home_building().position
, callback
=callback
, destination_in_building
=True)
218 class StorageCollector(BuildingCollector
):
219 """ Same as BuildingCollector, except that it moves on roads.
220 Used in storage facilities.
222 movement
= Movement
.STORAGE_CARRIAGE_MOVEMENT
224 def begin_current_job(self
):
225 """Declare target of StorageCollector as building, because it always is"""
226 super(StorageCollector
, self
).begin_current_job()
227 self
.move(self
.job
.object.position
, self
.begin_working
, destination_in_building
= True)
229 class AnimalCollector(BuildingCollector
):
230 """ Collector that gets resources from animals """
232 def begin_current_job(self
):
233 """Tell the animal to stop. First step of a job"""
234 #print self.id, 'BEGIN CURRENT JOB'
238 def pickup_animal(self
):
239 """Moves collector to animal. Called by animal when it actually stopped"""
240 #print self.id, 'PICKUP ANIMAL'
242 self
.move(self
.job
.object.position
, self
.begin_working
)
244 def finish_working(self
):
245 """Transfer res and such. Called when collector arrives at the animal"""
246 super(AnimalCollector
, self
).finish_working()
249 def reached_home(self
):
250 """Transfer res to home building and such. Called when collector arrives at it's home"""
251 super(AnimalCollector
, self
).reached_home()
252 # sheep and herder are inside the building now, pretending to work.
253 self
.release_animal()
255 def get_buildings_in_range(self
):
256 # This is only a small workarround
257 # as long we have no Collector class
258 return self
.get_animals_in_range()
260 def get_animals_in_range(self
):
261 # TODO: use the Collector class instead of BuildCollector
262 #print self.id, 'GET ANIMALS IN RANGE'
263 """returns all buildings in range
264 Overwrite in subclasses that need ranges arroung the pickup."""
265 return self
.home_building().animals
267 def stop_animal(self
):
268 """Tell animal to stop at the next occasion"""
269 #print self.id, 'STOP ANIMAL', self.job.object.id
270 self
.job
.object.stop_after_job(self
)
272 def get_animal(self
):
273 """Sends animal to collectors home building"""
274 #print self.id, 'GET ANIMAL'
275 self
.job
.object.move(self
.home_building().position
, destination_in_building
= True)
277 def release_animal(self
):
278 """Let animal free after shearing"""
279 #print self.id, 'RELEASE ANIMAL', self.job.object.getId()
280 game
.main
.session
.scheduler
.add_new_object(self
.job
.object.search_job
, self
.job
.object, 16)
284 def __init__(self
, object, res
, amount
):
285 self
._object
= weakref
.ref(object)
289 # this is rather a dummy
294 return self
._object
()