1 /*
2 * Fabrikfunktionen und Fabrikbau
3 *
4 * Hansj�rg Malthaner
5 *
6 *
7 * 25.03.00 Anpassung der Lagerkapazit�ten: min. 5 normale Lieferungen
8 * sollten an Lager gehalten werden.
9 */
10
11 #include <math.h>
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16
17 #include "simdebug.h"
18 #include "display/simimg.h"
19 #include "simcolor.h"
20 #include "boden/grund.h"
21 #include "boden/boden.h"
22 #include "boden/fundament.h"
23 #include "simfab.h"
24 #include "simcity.h"
25 #include "simhalt.h"
26 #include "simware.h"
27 #include "simworld.h"
28 #include "descriptor/building_desc.h"
29 #include "descriptor/goods_desc.h"
30 #include "descriptor/sound_desc.h"
31 #include "player/simplay.h"
32
33 #include "simintr.h"
34
35 #include "obj/wolke.h"
36 #include "obj/gebaeude.h"
37 #include "obj/field.h"
38 #include "obj/leitung2.h"
39
40 #include "dataobj/settings.h"
41 #include "dataobj/environment.h"
42 #include "dataobj/translator.h"
43 #include "dataobj/loadsave.h"
44
45 #include "descriptor/factory_desc.h"
46 #include "bauer/hausbauer.h"
47 #include "bauer/goods_manager.h"
48 #include "bauer/fabrikbauer.h"
49
50 #include "gui/fabrik_info.h"
51
52 #include "utils/simrandom.h"
53 #include "utils/cbuffer_t.h"
54
55 #include "gui/simwin.h"
56 #include "display/simgraph.h"
57
58 // Fabrik_t
59
60
61 static const int FAB_MAX_INPUT = 15000;
62 // Half a display unit (0.5).
63 static const sint64 FAB_DISPLAY_UNIT_HALF = ((sint64)1 << (fabrik_t::precision_bits + DEFAULT_PRODUCTION_FACTOR_BITS - 1));
64 // Half a production factor unit (0.5).
65 static const sint32 FAB_PRODFACT_UNIT_HALF = ((sint32)1 << (DEFAULT_PRODUCTION_FACTOR_BITS - 1));
66
67 karte_ptr_t fabrik_t::welt;
68
69
70 /**
71 * Convert internal values to displayed values
72 */
convert_goods(sint64 value)73 sint64 convert_goods(sint64 value) { return ((value + FAB_DISPLAY_UNIT_HALF) >> (fabrik_t::precision_bits + DEFAULT_PRODUCTION_FACTOR_BITS) ); }
convert_power(sint64 value)74 sint64 convert_power(sint64 value) { return ( value >> POWER_TO_MW ); }
convert_boost(sint64 value)75 sint64 convert_boost(sint64 value) { return ( (value * 100 + (DEFAULT_PRODUCTION_FACTOR>>1)) >> DEFAULT_PRODUCTION_FACTOR_BITS ); }
76
77
78 /**
79 * Ordering based on relative distance to a fixed point `origin'.
80 */
81 class RelativeDistanceOrdering
82 {
83 private:
84 const koord m_origin;
85 public:
RelativeDistanceOrdering(const koord & origin)86 RelativeDistanceOrdering(const koord& origin)
87 : m_origin(origin)
88 { /* nothing */ }
89
90 /**
91 * Returns true if `a' is closer to the origin than `b', otherwise false.
92 */
operator ()(const koord & a,const koord & b) const93 bool operator()(const koord& a, const koord& b) const
94 {
95 return koord_distance(m_origin, a) < koord_distance(m_origin, b);
96 }
97 };
98
99 /**
100 * Produce a scaled production amount from a production amount and work factor.
101 */
work_scale_production(sint64 prod,sint64 work)102 sint32 work_scale_production(sint64 prod, sint64 work){
103 // compute scaled production, rounding up
104 return ((prod * work) + (1 << WORK_BITS) - 1) >> WORK_BITS;
105 }
106
107 /**
108 * Produce a work factor from a production amount and scaled production amount.
109 */
work_from_production(sint64 prod,sint64 scaled)110 sint32 work_from_production(sint64 prod, sint64 scaled){
111 // compute work, rounding up
112 return prod ? ((scaled << WORK_BITS) + prod - 1) / prod : 0;
113 }
114
init_stats()115 void ware_production_t::init_stats()
116 {
117 for( int m=0; m<MAX_MONTH; ++m ) {
118 for( int s=0; s<MAX_FAB_GOODS_STAT; ++s ) {
119 statistics[m][s] = 0;
120 }
121 }
122 weighted_sum_storage = 0;
123 }
124
125
roll_stats(uint32 factor,sint64 aggregate_weight)126 void ware_production_t::roll_stats(uint32 factor, sint64 aggregate_weight)
127 {
128 // calculate weighted average storage first
129 if( aggregate_weight>0 ) {
130 set_stat( weighted_sum_storage / aggregate_weight, FAB_GOODS_STORAGE );
131 }
132
133 for( int s=0; s<MAX_FAB_GOODS_STAT; ++s ) {
134 for( int m=MAX_MONTH-1; m>0; --m ) {
135 statistics[m][s] = statistics[m-1][s];
136 }
137 if( s==FAB_GOODS_TRANSIT ) {
138 // keep the current amount in transit
139 statistics[0][s] = statistics[1][s];
140 }
141 else {
142 statistics[0][s] = 0;
143 }
144 }
145 weighted_sum_storage = 0;
146
147 // restore current storage level
148 set_stat( (sint64)menge * (sint64)factor, FAB_GOODS_STORAGE );
149 }
150
151
rdwr(loadsave_t * file)152 void ware_production_t::rdwr(loadsave_t *file)
153 {
154 if( file->is_loading() ) {
155 init_stats();
156 }
157
158 // we use a temporary variable to save/load old data correctly
159 sint64 statistics_buf[MAX_MONTH][MAX_FAB_GOODS_STAT];
160 memcpy( statistics_buf, statistics, sizeof(statistics_buf) );
161 if( file->is_saving() && file->is_version_less(120, 1) ) {
162 for( int m=0; m<MAX_MONTH; ++m ) {
163 statistics_buf[m][0] = (statistics[m][FAB_GOODS_STORAGE] >> DEFAULT_PRODUCTION_FACTOR_BITS);
164 statistics_buf[m][2] = (statistics[m][2] >> DEFAULT_PRODUCTION_FACTOR_BITS);
165 }
166 }
167
168 if( file->is_version_atleast(112, 1) ) {
169 for( int s=0; s<MAX_FAB_GOODS_STAT; ++s ) {
170 for( int m=0; m<MAX_MONTH; ++m ) {
171 file->rdwr_longlong( statistics_buf[m][s] );
172 }
173 }
174 file->rdwr_longlong( weighted_sum_storage );
175 }
176 else if( file->is_version_atleast(110, 5) ) {
177 // save/load statistics
178 for( int s=0; s<3; ++s ) {
179 for( int m=0; m<MAX_MONTH; ++m ) {
180 file->rdwr_longlong( statistics_buf[m][s] );
181 }
182 }
183 file->rdwr_longlong( weighted_sum_storage );
184 }
185
186 if( file->is_loading() ) {
187 memcpy( statistics, statistics_buf, sizeof(statistics_buf) );
188
189 // Apply correction for output production graphs which have had their precision changed for factory normalization.
190 // Also apply a fix for corrupted in-transit values caused by a logical error.
191 if(file->is_version_less(120, 1)){
192 for( int m=0; m<MAX_MONTH; ++m ) {
193 statistics[m][0] = (statistics[m][FAB_GOODS_STORAGE] & 0xffffffff) << DEFAULT_PRODUCTION_FACTOR_BITS;
194 statistics[m][2] = (statistics[m][2] & 0xffffffff) << DEFAULT_PRODUCTION_FACTOR_BITS;
195 }
196 }
197
198 // recalc transit always on load
199 statistics[0][FAB_GOODS_TRANSIT] = 0;
200 }
201 }
202
203
book_weighted_sum_storage(uint32 factor,sint64 delta_time)204 void ware_production_t::book_weighted_sum_storage(uint32 factor, sint64 delta_time)
205 {
206 const sint64 amount = (sint64)menge * (sint64)factor;
207 weighted_sum_storage += amount * delta_time;
208 set_stat( amount, FAB_GOODS_STORAGE );
209 }
210
calculate_output_production_rate() const211 sint32 ware_production_t::calculate_output_production_rate() const {
212 return fabrik_t::calculate_work_rate_ramp(menge, min_shipment * OUTPUT_SCALE_RAMPDOWN_MULTIPLYER, max);
213 }
214
calculate_demand_production_rate() const215 sint32 ware_production_t::calculate_demand_production_rate() const {
216 return fabrik_t::calculate_work_rate_ramp(demand_buffer, max / 2, max);
217 }
218
init()219 void fabrik_t::arrival_statistics_t::init()
220 {
221 for( uint32 s=0; s<SLOT_COUNT; ++s ) {
222 slots[s] = 0;
223 }
224 current_slot = 0;
225 active_slots = 0;
226 aggregate_arrival = 0;
227 scaled_demand = 0;
228 }
229
230
rdwr(loadsave_t * file)231 void fabrik_t::arrival_statistics_t::rdwr(loadsave_t *file)
232 {
233 if( file->is_version_atleast(110, 5) ) {
234 if( file->is_loading() ) {
235 aggregate_arrival = 0;
236 for( uint32 s=0; s<SLOT_COUNT; ++s ) {
237 file->rdwr_short( slots[s] );
238 aggregate_arrival += slots[s];
239 }
240 scaled_demand = 0;
241 }
242 else {
243 for( uint32 s=0; s<SLOT_COUNT; ++s ) {
244 file->rdwr_short( slots[s] );
245 }
246 }
247 file->rdwr_short( current_slot );
248 file->rdwr_short( active_slots );
249 }
250 else if( file->is_loading() ) {
251 init();
252 }
253 }
254
255
advance_slot()256 sint32 fabrik_t::arrival_statistics_t::advance_slot()
257 {
258 sint32 result = 0;
259 // advance to the next slot
260 ++current_slot;
261 if( current_slot>=SLOT_COUNT ) {
262 current_slot = 0;
263 }
264 // handle expiration of past arrivals and reset slot to 0
265 if( slots[current_slot]>0 ) {
266 aggregate_arrival -= slots[current_slot];
267 slots[current_slot] = 0;
268 if( aggregate_arrival==0 ) {
269 // reset slot count to 0 as all previous arrivals have expired
270 active_slots = 0;
271 }
272 result |= ARRIVALS_CHANGED;
273 }
274 // count the number of slots covered since aggregate arrival last increased from 0 to +ve
275 if( active_slots>0 && active_slots<SLOT_COUNT ) {
276 ++active_slots;
277 result |= ACTIVE_SLOTS_INCREASED;
278 }
279 return result;
280 }
281
282
book_arrival(const uint16 amount)283 void fabrik_t::arrival_statistics_t::book_arrival(const uint16 amount)
284 {
285 if( aggregate_arrival==0 ) {
286 // new arrival after complete inactivity -> start counting slots
287 active_slots = 1;
288 }
289 // increment current slot and aggregate arrival
290 slots[current_slot] += amount;
291 aggregate_arrival += amount;
292 }
293
294
update_transit(const ware_t * ware,bool add)295 void fabrik_t::update_transit( const ware_t *ware, bool add )
296 {
297 if( ware->index > goods_manager_t::INDEX_NONE ) {
298 // only for freights
299 fabrik_t *fab = get_fab( ware->get_zielpos() );
300 if( fab ) {
301 fab->update_transit_intern( ware, add );
302 }
303 }
304 }
305
apply_transit(const ware_t * ware)306 void fabrik_t::apply_transit( const ware_t *ware )
307 {
308 if( ware->index > goods_manager_t::INDEX_NONE ) {
309 // only for freights
310 fabrik_t *fab = get_fab( ware->get_zielpos() );
311 if( fab ) {
312 for( uint32 input = 0; input < fab->input.get_count(); input++ ){
313 ware_production_t& w = fab->input[input];
314 if( w.get_typ()->get_index() == ware->index ) {
315 // It is now in transit.
316 w.book_stat((sint64)ware->menge, FAB_GOODS_TRANSIT );
317 // If using JIT2, must decrement demand buffers, activating if required.
318 if( welt->get_settings().get_just_in_time() >= 2 ){
319 const uint32 prod_factor = fab->desc->get_supplier(input)->get_consumption();
320 const sint32 prod_delta = (sint32)((((sint64)(ware->menge) << (DEFAULT_PRODUCTION_FACTOR_BITS + precision_bits)) + (sint64)(prod_factor - 1)) / (sint64)prod_factor);
321 const sint32 demand = w.demand_buffer;
322 w.demand_buffer -= prod_delta;
323 if( demand >= w.max && w.demand_buffer < w.max ) {
324 fab->inactive_demands --;
325 }
326 }
327 // ours is on its way, no need to handle the other
328 return;
329 }
330 }
331 }
332 }
333 }
334
335
336 // just for simplicity ...
update_transit_intern(const ware_t * ware,bool add)337 void fabrik_t::update_transit_intern( const ware_t *ware, bool add )
338 {
339 FOR( array_tpl<ware_production_t>, &w, input ) {
340 if( w.get_typ()->get_index() == ware->index ) {
341 w.book_stat(add ? (sint64)ware->menge : -(sint64)ware->menge, FAB_GOODS_TRANSIT );
342 return;
343 }
344 }
345 }
346
347
init_stats()348 void fabrik_t::init_stats()
349 {
350 for( int m=0; m<MAX_MONTH; ++m ) {
351 for( int s=0; s<MAX_FAB_STAT; ++s ) {
352 statistics[m][s] = 0;
353 }
354 }
355 weighted_sum_production = 0;
356 weighted_sum_boost_electric = 0;
357 weighted_sum_boost_pax = 0;
358 weighted_sum_boost_mail = 0;
359 weighted_sum_power = 0;
360 aggregate_weight = 0;
361 }
362
363
book_weighted_sums(sint64 delta_time)364 void fabrik_t::book_weighted_sums(sint64 delta_time)
365 {
366 aggregate_weight += delta_time;
367
368 // storage level of input/output stores
369 for( uint32 in = 0; in < input.get_count(); in++ ){
370 input[in].book_weighted_sum_storage(desc->get_supplier(in)->get_consumption(), delta_time);
371 }
372 for( uint32 out = 0; out < output.get_count(); out++ ){
373 output[out].book_weighted_sum_storage(desc->get_product(out)->get_factor(), delta_time);
374 }
375
376 // production level
377 const sint32 current_prod = get_current_production();
378 weighted_sum_production += current_prod * delta_time;
379 set_stat( current_prod, FAB_PRODUCTION );
380
381 // electricity, pax and mail boosts
382 weighted_sum_boost_electric += prodfactor_electric * delta_time;
383 set_stat( prodfactor_electric, FAB_BOOST_ELECTRIC );
384 weighted_sum_boost_pax += prodfactor_pax * delta_time;
385 weighted_sum_boost_mail += prodfactor_mail * delta_time;
386
387 // power produced or consumed
388 sint64 power = get_power();
389 weighted_sum_power += power * delta_time;
390 set_stat( power, FAB_POWER );
391 }
392
393
update_scaled_electric_demand()394 void fabrik_t::update_scaled_electric_demand()
395 {
396 if( desc->get_electric_demand()==65535 ) {
397 // demand not specified in pak, use old fixed demands
398 scaled_electric_demand = prodbase * PRODUCTION_DELTA_T;
399 if( desc->is_electricity_producer() ) {
400 scaled_electric_demand *= 4;
401 }
402 return;
403 }
404
405 const sint64 prod = desc->get_productivity();
406 scaled_electric_demand = (uint32)( (( (sint64)(desc->get_electric_demand()) * (sint64)prodbase + (prod >> 1) ) / prod) << POWER_TO_MW );
407
408 if( scaled_electric_demand == 0 ) {
409 prodfactor_electric = 0;
410 }
411 }
412
413
update_scaled_pax_demand()414 void fabrik_t::update_scaled_pax_demand()
415 {
416 // first, scaling based on current production base
417 const sint64 prod = desc->get_productivity();
418 const sint64 desc_pax_demand = ( desc->get_pax_demand()==65535 ? desc->get_pax_level() : desc->get_pax_demand() );
419 // formula : desc_pax_demand * (current_production_base / desc_production_base); (prod >> 1) is for rounding
420 const uint32 pax_demand = (uint32)( ( desc_pax_demand * (sint64)prodbase + (prod >> 1) ) / prod );
421 // then, scaling based on month length
422 scaled_pax_demand = (uint32)welt->scale_with_month_length(pax_demand);
423 if( scaled_pax_demand == 0 && desc_pax_demand > 0 ) {
424 scaled_pax_demand = 1; // since desc pax demand > 0 -> ensure no less than 1
425 }
426 // pax demand for fixed period length
427 arrival_stats_pax.set_scaled_demand( pax_demand );
428 }
429
430
update_scaled_mail_demand()431 void fabrik_t::update_scaled_mail_demand()
432 {
433 // first, scaling based on current production base
434 const sint64 prod = desc->get_productivity();
435 const sint64 desc_mail_demand = ( desc->get_mail_demand()==65535 ? (desc->get_pax_level()>>2) : desc->get_mail_demand() );
436 // formula : desc_mail_demand * (current_production_base / desc_production_base); (prod >> 1) is for rounding
437 const uint32 mail_demand = (uint32)( ( desc_mail_demand * (sint64)prodbase + (prod >> 1) ) / prod );
438 // then, scaling based on month length
439 scaled_mail_demand = (uint32)welt->scale_with_month_length(mail_demand);
440 if( scaled_mail_demand == 0 && desc_mail_demand > 0 ) {
441 scaled_mail_demand = 1; // since desc mail demand > 0 -> ensure no less than 1
442 }
443 // mail demand for fixed period length
444 arrival_stats_mail.set_scaled_demand( mail_demand );
445 }
446
447
update_prodfactor_pax()448 void fabrik_t::update_prodfactor_pax()
449 {
450 // calculate pax boost based on arrival data and demand of the fixed-length period
451 const uint32 periods = welt->get_settings().get_factory_arrival_periods();
452 const uint32 slots = arrival_stats_pax.get_active_slots();
453 const uint32 pax_demand = ( periods==1 || slots*periods<=(uint32)SLOT_COUNT ?
454 arrival_stats_pax.get_scaled_demand() :
455 ( slots==(uint32)SLOT_COUNT ?
456 arrival_stats_pax.get_scaled_demand() * periods :
457 (arrival_stats_pax.get_scaled_demand() * periods * slots) >> SLOT_BITS ) );
458 const uint32 pax_arrived = arrival_stats_pax.get_aggregate_arrival();
459 if( pax_demand==0 || pax_arrived==0 || desc->get_pax_boost()==0 ) {
460 prodfactor_pax = 0;
461 }
462 else if( pax_arrived>=pax_demand ) {
463 // maximum boost
464 prodfactor_pax = desc->get_pax_boost();
465 }
466 else {
467 // pro-rata boost : (pax_arrived / pax_demand) * desc_pax_boost; (pax_demand >> 1) is for rounding
468 prodfactor_pax = (sint32)( ( (sint64)pax_arrived * (sint64)(desc->get_pax_boost()) + (sint64)(pax_demand >> 1) ) / (sint64)pax_demand );
469 }
470 set_stat(prodfactor_pax, FAB_BOOST_PAX);
471 }
472
473
update_prodfactor_mail()474 void fabrik_t::update_prodfactor_mail()
475 {
476 // calculate mail boost based on arrival data and demand of the fixed-length period
477 const uint32 periods = welt->get_settings().get_factory_arrival_periods();
478 const uint32 slots = arrival_stats_mail.get_active_slots();
479 const uint32 mail_demand = ( periods==1 || slots*periods<=(uint32)SLOT_COUNT ?
480 arrival_stats_mail.get_scaled_demand() :
481 ( slots==(uint32)SLOT_COUNT ?
482 arrival_stats_mail.get_scaled_demand() * periods :
483 (arrival_stats_mail.get_scaled_demand() * periods * slots) >> SLOT_BITS ) );
484 const uint32 mail_arrived = arrival_stats_mail.get_aggregate_arrival();
485 if( mail_demand==0 || mail_arrived==0 || desc->get_mail_boost()==0 ) {
486 prodfactor_mail = 0;
487 }
488 else if( mail_arrived>=mail_demand ) {
489 // maximum boost
490 prodfactor_mail = desc->get_mail_boost();
491 }
492 else {
493 // pro-rata boost : (mail_arrived / mail_demand) * desc_mail_boost; (mail_demand >> 1) is for rounding
494 prodfactor_mail = (sint32)( ( (sint64)mail_arrived * (sint64)(desc->get_mail_boost()) + (sint64)(mail_demand >> 1) ) / (sint64)mail_demand );
495 }
496 set_stat(prodfactor_mail, FAB_BOOST_MAIL);
497 }
498
499
recalc_demands_at_target_cities()500 void fabrik_t::recalc_demands_at_target_cities()
501 {
502 if (!welt->get_settings().get_factory_enforce_demand()) {
503 // demand not enforced -> no splitting of demands
504 FOR(vector_tpl<stadt_t*>, const c, target_cities) {
505 c->access_target_factories_for_pax().update_factory( this, scaled_pax_demand << DEMAND_BITS);
506 c->access_target_factories_for_mail().update_factory(this, scaled_mail_demand << DEMAND_BITS);
507 }
508 return;
509 }
510 if (target_cities.empty()) {
511 // nothing to do
512 return;
513 }
514 else if( target_cities.get_count()==1 ) {
515 // only 1 target city -> no need to apportion pax/mail demand
516 target_cities[0]->access_target_factories_for_pax().update_factory(this, (scaled_pax_demand << DEMAND_BITS));
517 target_cities[0]->access_target_factories_for_mail().update_factory(this, (scaled_mail_demand << DEMAND_BITS));
518 }
519 else {
520 // more than 1 target cities -> need to apportion pax/mail demand among the cities
521 static vector_tpl<uint32> weights(8);
522 weights.clear();
523 uint32 sum_of_weights = 0;
524 // first, calculate the weights
525 for( uint32 c=0; c<target_cities.get_count(); ++c ) {
526 weights.append( weight_by_distance( target_cities[c]->get_einwohner(), shortest_distance( get_pos().get_2d(), target_cities[c]->get_center() ) ) );
527 sum_of_weights += weights[c];
528 }
529 // finally, apportion the pax/mail demand; formula : demand * (city_weight / aggregate_city_weight); (sum_of_weights >> 1) is for rounding
530 for( uint32 c=0; c<target_cities.get_count(); ++c ) {
531 const uint32 pax_amount = (uint32)(( (sint64)(scaled_pax_demand << DEMAND_BITS) * (sint64)weights[c] + (sint64)(sum_of_weights >> 1) ) / (sint64)sum_of_weights);
532 target_cities[c]->access_target_factories_for_pax().update_factory(this, pax_amount);
533 const uint32 mail_amount = (uint32)(( (sint64)(scaled_mail_demand << DEMAND_BITS) * (sint64)weights[c] + (sint64)(sum_of_weights >> 1) ) / (sint64)sum_of_weights);
534 target_cities[c]->access_target_factories_for_mail().update_factory(this, mail_amount);
535 }
536 }
537 }
538
539
recalc_storage_capacities()540 void fabrik_t::recalc_storage_capacities()
541 {
542 if( desc->get_field_group() ) {
543 // with fields -> calculate based on capacities contributed by fields
544 const uint32 ware_types = input.get_count() + output.get_count();
545 if( ware_types>0 ) {
546 // calculate total storage capacity contributed by fields
547 const field_group_desc_t *const field_group = desc->get_field_group();
548 sint32 field_capacities = 0;
549 FOR(vector_tpl<field_data_t>, const& f, fields) {
550 field_capacities += field_group->get_field_class(f.field_class_index)->get_storage_capacity();
551 }
552 const sint32 share = (sint32)( ( (sint64)field_capacities << precision_bits ) / (sint64)ware_types );
553 // first, for input goods
554 FOR(array_tpl<ware_production_t>, & g, input) {
555 for( int b=0; b<desc->get_supplier_count(); ++b ) {
556 const factory_supplier_desc_t *const input = desc->get_supplier(b);
557 if (g.get_typ() == input->get_input_type()) {
558 // Inputs are now normalized to factory production.
559 uint32 prod_factor = input->get_consumption();
560 g.max = (sint32)((((sint64)((input->get_capacity() << precision_bits) + share) << DEFAULT_PRODUCTION_FACTOR_BITS) + (sint64)(prod_factor - 1)) / (sint64)prod_factor);
561 }
562 }
563 }
564 // then, for output goods
565 FOR(array_tpl<ware_production_t>, & g, output) {
566 for( uint b=0; b<desc->get_product_count(); ++b ) {
567 const factory_product_desc_t *const output = desc->get_product(b);
568 if (g.get_typ() == output->get_output_type()) {
569 // Outputs are now normalized to factory production.
570 uint32 prod_factor = output->get_factor();
571 g.max = (sint32)((((sint64)((output->get_capacity() << precision_bits) + share) << DEFAULT_PRODUCTION_FACTOR_BITS) + (sint64)(prod_factor - 1)) / (sint64)prod_factor);
572 }
573 }
574 }
575 }
576 }
577 else {
578 // without fields -> scaling based on prodbase
579 // first, for input goods
580 FOR(array_tpl<ware_production_t>, & g, input) {
581 for( int b=0; b<desc->get_supplier_count(); ++b ) {
582 const factory_supplier_desc_t *const input = desc->get_supplier(b);
583 if (g.get_typ() == input->get_input_type()) {
584 // Inputs are now normalized to factory production.
585 uint32 prod_factor = input->get_consumption();
586 g.max = (sint32)(((((sint64)input->get_capacity() * (sint64)prodbase) << (precision_bits + DEFAULT_PRODUCTION_FACTOR_BITS)) + (sint64)(prod_factor - 1)) / ((sint64)desc->get_productivity() * (sint64)prod_factor));
587 }
588 }
589 }
590 // then, for output goods
591 FOR(array_tpl<ware_production_t>, & g, output) {
592 for( uint b=0; b<desc->get_product_count(); ++b ) {
593 const factory_product_desc_t *const output = desc->get_product(b);
594 if (g.get_typ() == output->get_output_type()) {
595 // Outputs are now normalized to factory production.
596 uint32 prod_factor = output->get_factor();
597 g.max = (sint32)(((((sint64)output->get_capacity() * (sint64)prodbase) << (precision_bits + DEFAULT_PRODUCTION_FACTOR_BITS)) + (sint64)(prod_factor - 1)) / ((sint64)desc->get_productivity() * (sint64)prod_factor));
598 }
599 }
600 }
601 }
602
603 // Now that the maximum is known, work out the recommended shipment size for outputs in normalized units.
604 for( uint32 out = 0; out < output.get_count(); out++ ){
605 const uint32 prod_factor = desc->get_product(out)->get_factor();
606
607 // Determine the maximum number of whole units the out can store.
608 const uint32 unit_size = (uint32)(((sint64)output[out].max * (sint64)prod_factor) >> ( precision_bits + DEFAULT_PRODUCTION_FACTOR_BITS ));
609
610 // Determine the number of units to ship. Prefer 10 units although in future a more dynamic choice may be appropiate.
611 uint32 shipment_size;
612 // Maximum shipment size.
613 if( unit_size >= SHIPMENT_MAX_SIZE * SHIPMENT_NUM_MIN ) {
614 shipment_size = SHIPMENT_MAX_SIZE;
615 }
616 // Dynamic shipment size.
617 else if( unit_size > SHIPMENT_NUM_MIN ) {
618 shipment_size = unit_size / SHIPMENT_NUM_MIN;
619 }
620 // Minimum shipment size.
621 else {
622 shipment_size = 1;
623 }
624
625 // Now convert it into the prefered shipment size. Always round up to prevent "off by 1" error.
626 output[out].min_shipment = (sint32)((((sint64)shipment_size << (precision_bits + DEFAULT_PRODUCTION_FACTOR_BITS)) + (sint64)(prod_factor - 1)) / (sint64)prod_factor);
627 }
628
629 if( welt->get_settings().get_just_in_time() >= 2 ) {
630 rebuild_inactive_cache();
631 }
632 }
633
634
add_target_city(stadt_t * const city)635 void fabrik_t::add_target_city(stadt_t *const city)
636 {
637 if( target_cities.append_unique(city) ) {
638 recalc_demands_at_target_cities();
639 }
640 }
641
642
remove_target_city(stadt_t * const city)643 void fabrik_t::remove_target_city(stadt_t *const city)
644 {
645 if( target_cities.is_contained(city) ) {
646 target_cities.remove(city);
647 city->access_target_factories_for_pax().remove_factory(this);
648 city->access_target_factories_for_mail().remove_factory(this);
649 recalc_demands_at_target_cities();
650 }
651 }
652
653
clear_target_cities()654 void fabrik_t::clear_target_cities()
655 {
656 FOR(vector_tpl<stadt_t*>, const c, target_cities) {
657 c->access_target_factories_for_pax().remove_factory(this);
658 c->access_target_factories_for_mail().remove_factory(this);
659 }
660 target_cities.clear();
661 }
662
663
set_base_production(sint32 p)664 void fabrik_t::set_base_production(sint32 p)
665 {
666 prodbase = p;
667 recalc_storage_capacities();
668 update_scaled_electric_demand();
669 update_scaled_pax_demand();
670 update_scaled_mail_demand();
671 update_prodfactor_pax();
672 update_prodfactor_mail();
673 recalc_demands_at_target_cities();
674 }
675
676
get_fab(const koord & pos)677 fabrik_t *fabrik_t::get_fab(const koord &pos)
678 {
679 const grund_t *gr = welt->lookup_kartenboden(pos);
680 if(gr) {
681 gebaeude_t *gb = gr->find<gebaeude_t>();
682 if(gb) {
683 return gb->get_fabrik();
684 }
685 }
686 return NULL;
687 }
688
689
link_halt(halthandle_t halt)690 void fabrik_t::link_halt(halthandle_t halt)
691 {
692 welt->access(pos.get_2d())->add_to_haltlist(halt);
693 }
694
695
unlink_halt(halthandle_t halt)696 void fabrik_t::unlink_halt(halthandle_t halt)
697 {
698 planquadrat_t *plan=welt->access(pos.get_2d());
699 if(plan) {
700 plan->remove_from_haltlist(halt);
701 }
702 }
703
704
add_lieferziel(koord ziel)705 void fabrik_t::add_lieferziel(koord ziel)
706 {
707 if( !lieferziele.is_contained(ziel) ) {
708 lieferziele.insert_ordered( ziel, RelativeDistanceOrdering(pos.get_2d()) );
709 // now tell factory too
710 fabrik_t * fab = fabrik_t::get_fab(ziel);
711 if (fab) {
712 fab->add_supplier(get_pos().get_2d());
713 }
714 }
715 }
716
717
rem_lieferziel(koord ziel)718 void fabrik_t::rem_lieferziel(koord ziel)
719 {
720 lieferziele.remove(ziel);
721 }
722
723
fabrik_t(loadsave_t * file)724 fabrik_t::fabrik_t(loadsave_t* file)
725 {
726 owner = NULL;
727 prodfactor_electric = 0;
728 lieferziele_active_last_month = 0;
729 pos = koord3d::invalid;
730
731 rdwr(file);
732
733 if( desc == NULL ) {
734 dbg->warning( "fabrik_t::fabrik_t()", "No pak-file for factory at (%s) - will not be built!", pos_origin.get_str() );
735 return;
736 }
737 else if( !welt->is_within_limits(pos_origin.get_2d()) ) {
738 dbg->warning( "fabrik_t::fabrik_t()", "%s is not a valid position! (Will not be built!)", pos_origin.get_str() );
739 desc = NULL; // to get rid of this broken factory later...
740 }
741 else {
742 build(rotate, false, false);
743 // now get rid of construction image
744 for( sint16 y=0; y<desc->get_building()->get_y(rotate); y++ ) {
745 for( sint16 x=0; x<desc->get_building()->get_x(rotate); x++ ) {
746 gebaeude_t *gb = welt->lookup_kartenboden( pos_origin.get_2d()+koord(x,y) )->find<gebaeude_t>();
747 if( gb ) {
748 gb->add_alter(10000);
749 }
750 }
751 }
752 }
753
754 delta_sum = 0;
755 delta_menge = 0;
756 menge_remainder = 0;
757 total_input = total_transit = total_output = 0;
758 status = nothing;
759 currently_producing = false;
760 transformer = NULL;
761 last_sound_ms = welt->get_ticks();
762 }
763
764
fabrik_t(koord3d pos_,player_t * owner,const factory_desc_t * factory_desc,sint32 initial_prod_base)765 fabrik_t::fabrik_t(koord3d pos_, player_t* owner, const factory_desc_t* factory_desc, sint32 initial_prod_base) :
766 desc(factory_desc),
767 pos(pos_)
768 {
769 this->pos.z = welt->max_hgt(pos.get_2d());
770 pos_origin = pos;
771
772 this->owner = owner;
773 prodfactor_electric = 0;
774 prodfactor_pax = 0;
775 prodfactor_mail = 0;
776 if (initial_prod_base < 0) {
777 prodbase = desc->get_productivity() + simrand(desc->get_range());
778 }
779 else {
780 prodbase = initial_prod_base;
781 }
782
783 delta_sum = 0;
784 delta_menge = 0;
785 menge_remainder = 0;
786 activity_count = 0;
787 currently_producing = false;
788 transformer = NULL;
789 total_input = total_transit = total_output = 0;
790 status = nothing;
791 lieferziele_active_last_month = 0;
792
793 // create input information
794 input.resize( factory_desc->get_supplier_count() );
795 for( int g=0; g<factory_desc->get_supplier_count(); ++g ) {
796 const factory_supplier_desc_t *const supp = factory_desc->get_supplier(g);
797 input[g].set_typ( supp->get_input_type() );
798 }
799
800 // create output information
801 output.resize( factory_desc->get_product_count() );
802 for( uint g=0; g<factory_desc->get_product_count(); ++g ) {
803 const factory_product_desc_t *const product = factory_desc->get_product(g);
804 output[g].set_typ( product->get_output_type() );
805 }
806
807 recalc_storage_capacities();
808 if( welt->get_settings().get_just_in_time() >= 2 ){
809 inactive_inputs = inactive_outputs = inactive_demands = 0;
810 if( input.empty() ){
811 // All sources start out with maximum product.
812 for( uint32 out = 0; out < output.get_count(); out++ ){
813 output[out].menge = output[out].max;
814 inactive_outputs ++;
815 }
816 }
817 else {
818 for( uint32 out = 0; out < output.get_count(); out++ ){
819 output[out].menge = 0;
820 }
821
822 // A consumer of sorts so output and input starts out empty but with a full demand buffer.
823 for( uint32 in = 0; in < input.get_count(); in++ ){
824 input[in].menge = 0;
825 input[in].demand_buffer = input[in].max;
826 inactive_inputs++;
827 inactive_demands++;
828 }
829 }
830 }
831 else {
832 if( input.empty() ) {
833 FOR( array_tpl<ware_production_t>, & g, output ) {
834 if( g.max > 0 ) {
835 // if source then start with full storage, so that AI will build line(s) immediately
836 g.menge = g.max - 1;
837 }
838 }
839 }
840 }
841
842 last_sound_ms = welt->get_ticks();
843 init_stats();
844 arrival_stats_pax.init();
845 arrival_stats_mail.init();
846
847 delta_slot = 0;
848 times_expanded = 0;
849 update_scaled_electric_demand();
850 update_scaled_pax_demand();
851 update_scaled_mail_demand();
852 }
853
854
~fabrik_t()855 fabrik_t::~fabrik_t()
856 {
857 while(!fields.empty()) {
858 planquadrat_t *plan = welt->access( fields.back().location );
859 // if destructor is called when world is destroyed, plan is already invalid
860 if (plan) {
861 grund_t *gr = plan->get_kartenboden();
862 if (field_t* f = gr->find<field_t>()) {
863 delete f; // implicitly removes the field from fields
864 plan->boden_ersetzen( gr, new boden_t(gr->get_pos(), slope_t::flat ) );
865 plan->get_kartenboden()->calc_image();
866 continue;
867 }
868 }
869 fields.pop_back();
870 }
871 // destroy chart window, if present
872 destroy_win((ptrdiff_t)this);
873 }
874
875
build(sint32 rotate,bool build_fields,bool force_initial_prodbase)876 void fabrik_t::build(sint32 rotate, bool build_fields, bool force_initial_prodbase)
877 {
878 this->rotate = rotate;
879 pos_origin = welt->lookup_kartenboden(pos_origin.get_2d())->get_pos();
880 gebaeude_t *gb = hausbauer_t::build(owner, pos_origin, rotate, desc->get_building(), this);
881 pos = gb->get_pos();
882 pos_origin.z = pos.z;
883
884 if(desc->get_field_group()) {
885 // if there are fields
886 if( !fields.empty() ) {
887 for( uint16 i=0; i<fields.get_count(); i++ ) {
888 const koord k = fields[i].location;
889 grund_t *gr=welt->lookup_kartenboden(k);
890 if( gr->ist_natur() ) {
891 // first make foundation below
892 grund_t *gr2 = new fundament_t(gr->get_pos(), gr->get_grund_hang());
893 welt->access(k)->boden_ersetzen(gr, gr2);
894 gr2->obj_add( new field_t(gr2->get_pos(), owner, desc->get_field_group()->get_field_class( fields[i].field_class_index ), this ) );
895 }
896 else {
897 // there was already a building at this position => do not restore!
898 fields.remove_at(i);
899 i--;
900 }
901 }
902 }
903 else if( build_fields ) {
904 // make sure not to exceed initial prodbase too much
905 sint32 org_prodbase = prodbase;
906 // we will start with a minimum number and try to get closer to start_fields
907 const uint16 spawn_fields = desc->get_field_group()->get_min_fields() + simrand( desc->get_field_group()->get_start_fields()-desc->get_field_group()->get_min_fields() );
908 while( fields.get_count() < spawn_fields && add_random_field(10000u) ) {
909 if (fields.get_count() > desc->get_field_group()->get_min_fields() && prodbase >= 2*org_prodbase) {
910 // too much productivity, no more fields needed
911 break;
912 }
913 }
914 sint32 field_prod = prodbase - org_prodbase;
915 // adjust prodbase
916 if (force_initial_prodbase) {
917 set_base_production( max(field_prod, org_prodbase) );
918 }
919 }
920 }
921 else {
922 fields.clear();
923 }
924
925 /// Determine control logic
926 if( welt->get_settings().get_just_in_time() >= 2 ) {
927 // Does it both consume and produce?
928 if( !output.empty() && !input.empty() ) {
929 control_type = CL_FACT_MANY;
930 }
931 // Does it produce?
932 else if( !output.empty() ) {
933 control_type = CL_PROD_MANY;
934 }
935 // Does it consume?
936 else if( !input.empty() ) {
937 control_type = CL_CONS_MANY;
938 }
939 // No I/O?
940 else {
941 control_type = desc->is_electricity_producer() ? CL_ELEC_PROD : CL_NONE;
942 }
943 }
944 else{
945 // Classic logic.
946 if( !output.empty() && !input.empty() ) {
947 control_type = CL_FACT_CLASSIC;
948 }
949 else if( !output.empty() ) {
950 control_type = CL_PROD_CLASSIC;
951 }
952 else if( !input.empty() ) {
953 control_type = CL_CONS_CLASSIC;
954 }
955 else {
956 control_type = CL_ELEC_CLASSIC;
957 }
958 }
959
960 // Boost logic determines what factors boost factory production.
961 if( welt->get_settings().get_just_in_time() >= 2 ) {
962 if( !desc->is_electricity_producer() && desc->get_electric_demand() > 0 ) {
963 boost_type = BL_POWER;
964 }
965 else if( desc->get_pax_demand() || desc->get_mail_demand() ) {
966 boost_type = BL_PAXM;
967 }
968 else {
969 boost_type = BL_NONE;
970 }
971 }
972 else {
973 boost_type = BL_CLASSIC;
974 }
975
976 if( welt->get_settings().get_just_in_time() >= 2 ) {
977 if( input.empty() ) {
978 demand_type = DL_NONE;
979 }
980 else if( output.empty() ) {
981 demand_type = DL_ASYNC;
982 }
983 else {
984 demand_type = DL_SYNC;
985 }
986 }
987 else {
988 demand_type = input.empty() ? DL_NONE : DL_OLD;
989 }
990 }
991
992
993 /* field generation code
994 * @author Kieron Green
995 */
add_random_field(uint16 probability)996 bool fabrik_t::add_random_field(uint16 probability)
997 {
998 // has fields, and not yet too many?
999 const field_group_desc_t *fd = desc->get_field_group();
1000 if(fd==NULL || fd->get_max_fields() <= fields.get_count()) {
1001 return false;
1002 }
1003 // we are lucky and are allowed to generate a field
1004 if( simrand(10000)>=probability ) {
1005 return false;
1006 }
1007
1008 // we start closest to the factory, and check for valid tiles as we move out
1009 uint8 radius = 1;
1010
1011 // pick a coordinate to use - create a list of valid locations and choose a random one
1012 slist_tpl<grund_t *> build_locations;
1013 do {
1014 for(sint32 xoff = -radius; xoff < radius + get_desc()->get_building()->get_size().x ; xoff++) {
1015 for(sint32 yoff =-radius ; yoff < radius + get_desc()->get_building()->get_size().y; yoff++) {
1016 // if we can build on this tile then add it to the list
1017 grund_t *gr = welt->lookup_kartenboden(pos.get_2d()+koord(xoff,yoff));
1018 if (gr != NULL &&
1019 gr->get_typ() == grund_t::boden &&
1020 get_desc()->get_building()->is_allowed_climate(welt->get_climate(pos.get_2d()+koord(xoff,yoff))) &&
1021 gr->get_grund_hang() == slope_t::flat &&
1022 gr->ist_natur() &&
1023 (gr->find<leitung_t>() || gr->kann_alle_obj_entfernen(NULL) == NULL)) {
1024 // only on same height => climate will match!
1025 build_locations.append(gr);
1026 assert(gr->find<field_t>() == NULL);
1027 }
1028 // skip inside of rectangle (already checked earlier)
1029 if(radius > 1 && yoff == -radius && (xoff > -radius && xoff < radius + get_desc()->get_building()->get_size().x - 1)) {
1030 yoff = radius + get_desc()->get_building()->get_size().y - 2;
1031 }
1032 }
1033 }
1034 if (build_locations.empty()) {
1035 radius++;
1036 }
1037 } while (radius < 10 && build_locations.empty());
1038 // built on one of the positions
1039 if (!build_locations.empty()) {
1040 grund_t *gr = build_locations.at(simrand(build_locations.get_count()));
1041 leitung_t* lt = gr->find<leitung_t>();
1042 if(lt) {
1043 gr->obj_remove(lt);
1044 }
1045 gr->obj_loesche_alle(NULL);
1046 // first make foundation below
1047 const koord k = gr->get_pos().get_2d();
1048 field_data_t new_field(k);
1049 assert(!fields.is_contained(new_field));
1050 // Knightly : fetch a random field class desc based on spawn weights
1051 const weighted_vector_tpl<uint16> &field_class_indices = fd->get_field_class_indices();
1052 new_field.field_class_index = pick_any_weighted(field_class_indices);
1053 const field_class_desc_t *const field_class = fd->get_field_class( new_field.field_class_index );
1054 fields.append(new_field);
1055 grund_t *gr2 = new fundament_t(gr->get_pos(), gr->get_grund_hang());
1056 welt->access(k)->boden_ersetzen(gr, gr2);
1057 gr2->obj_add( new field_t(gr2->get_pos(), owner, field_class, this ) );
1058 // Knightly : adjust production base and storage capacities
1059 set_base_production( prodbase + field_class->get_field_production() );
1060 if(lt) {
1061 gr2->obj_add( lt );
1062 }
1063 gr2->calc_image();
1064 return true;
1065 }
1066 return false;
1067 }
1068
1069
remove_field_at(koord pos)1070 void fabrik_t::remove_field_at(koord pos)
1071 {
1072 field_data_t field(pos);
1073 assert(fields.is_contained( field ));
1074 field = fields[ fields.index_of(field) ];
1075 const field_class_desc_t *const field_class = desc->get_field_group()->get_field_class( field.field_class_index );
1076 fields.remove(field);
1077 // Knightly : revert the field's effect on production base and storage capacities
1078 set_base_production( prodbase - field_class->get_field_production() );
1079 }
1080
1081
sind_da_welche(koord min_pos,koord max_pos)1082 vector_tpl<fabrik_t *> &fabrik_t::sind_da_welche(koord min_pos, koord max_pos)
1083 {
1084 static vector_tpl <fabrik_t*> factory_list(16);
1085 factory_list.clear();
1086
1087 for(int y=min_pos.y; y<=max_pos.y; y++) {
1088 for(int x=min_pos.x; x<=max_pos.x; x++) {
1089 fabrik_t *fab=get_fab(koord(x,y));
1090 if(fab) {
1091 if (factory_list.append_unique(fab)) {
1092 //DBG_MESSAGE("fabrik_t::sind_da_welche()","appended factory %s at (%i,%i)",gr->first_obj()->get_fabrik()->get_desc()->get_name(),x,y);
1093 }
1094 }
1095 }
1096 }
1097 return factory_list;
1098 }
1099
1100
1101 /**
1102 * if name==NULL translate desc factory name in game language
1103 */
get_name() const1104 char const* fabrik_t::get_name() const
1105 {
1106 return name ? name.c_str() : translator::translate(desc->get_name(), welt->get_settings().get_name_language_id());
1107 }
1108
1109
set_name(const char * new_name)1110 void fabrik_t::set_name(const char *new_name)
1111 {
1112 if(new_name==NULL || strcmp(new_name, translator::translate(desc->get_name(), welt->get_settings().get_name_language_id()))==0) {
1113 // new name is equal to name given by descriptor/translation -> set name to NULL
1114 name = NULL;
1115 }
1116 else {
1117 name = new_name;
1118 }
1119
1120 fabrik_info_t *win = dynamic_cast<fabrik_info_t*>(win_get_magic((ptrdiff_t)this));
1121 if (win) {
1122 win->update_info();
1123 }
1124 }
1125
1126
rdwr(loadsave_t * file)1127 void fabrik_t::rdwr(loadsave_t *file)
1128 {
1129 xml_tag_t f( file, "fabrik_t" );
1130 sint32 i;
1131 sint32 owner_n;
1132 sint32 input_count;
1133 sint32 output_count;
1134 sint32 anz_lieferziele;
1135
1136 if( file->is_saving() ) {
1137 input_count = input.get_count();
1138 output_count = output.get_count();
1139 anz_lieferziele = lieferziele.get_count();
1140 const char *s = desc->get_name();
1141 file->rdwr_str(s);
1142 }
1143 else {
1144 char s[256];
1145 file->rdwr_str(s, lengthof(s));
1146 DBG_DEBUG("fabrik_t::rdwr()","loading factory '%s'",s);
1147 desc = factory_builder_t::get_desc(s);
1148 if( desc==NULL ) {
1149 // maybe it was only renamed?
1150 desc = factory_builder_t::get_desc(translator::compatibility_name(s));
1151 }
1152 if( desc==NULL ) {
1153 dbg->warning( "fabrik_t::rdwr()", "Pak-file for factory '%s' missing!", s );
1154 // we continue loading even if desc==NULL
1155 welt->add_missing_paks( s, karte_t::MISSING_FACTORY );
1156 }
1157 }
1158 pos_origin.rdwr(file);
1159 // pos will be assigned after call to hausbauer_t::build
1160 file->rdwr_byte(rotate);
1161
1162 // now rebuilt information for received goods
1163 file->rdwr_long(input_count);
1164 if( file->is_loading() ) {
1165 input.resize( input_count );
1166 }
1167 bool mismatch = false;
1168 for( i=0; i<input_count; i++ ) {
1169 ware_production_t &ware = input[i];
1170 const char *ware_name = NULL;
1171 sint32 menge = ware.menge;
1172 if( file->is_saving() ) {
1173 ware_name = ware.get_typ()->get_name();
1174 if( file->is_version_less(120, 1) ) {
1175 // correct for older saves
1176 menge = (sint32)(((sint64)ware.menge * (sint64)desc->get_supplier(i)->get_consumption() ) >> DEFAULT_PRODUCTION_FACTOR_BITS);
1177 }
1178 }
1179 file->rdwr_str(ware_name);
1180 file->rdwr_long(menge);
1181 if( file->is_version_less(110, 5) ) {
1182 // max storage is only loaded/saved for older versions
1183 file->rdwr_long(ware.max);
1184 }
1185 // JIT2 needs to store input demand buffer
1186 if( welt->get_settings().get_just_in_time() >= 2 && file->is_version_atleast(120, 1) ){
1187 file->rdwr_long(ware.demand_buffer);
1188 }
1189
1190 ware.rdwr( file );
1191
1192 if( file->is_loading() ) {
1193
1194 ware.set_typ( goods_manager_t::get_info(ware_name) );
1195
1196 // Maximum in-transit is always 0 on load.
1197 if( welt->get_settings().get_just_in_time() < 2 ) {
1198 ware.max_transit = 0;
1199 }
1200
1201 if( !desc || !desc->get_supplier(i) ) {
1202 if (desc) dbg->warning( "fabrik_t::rdwr()", "Factory at %s requested producer for %s but has none!", pos_origin.get_fullstr(), ware_name);
1203 ware.menge = 0;
1204 }
1205 else {
1206
1207 // Inputs used to be with respect to actual units of production. They now are normalized with respect to factory production so require conversion.
1208 const uint32 prod_factor = desc ? desc->get_supplier(i)->get_consumption() : 1;
1209 if( file->is_version_less(120, 1) ) {
1210 ware.menge = (sint32)(((sint64)menge << DEFAULT_PRODUCTION_FACTOR_BITS) / (sint64)prod_factor);
1211 }
1212 else {
1213 ware.menge = menge;
1214 }
1215
1216 // Hajo: repair files that have 'insane' values
1217 const sint32 max = (sint32)((((sint64)FAB_MAX_INPUT << (precision_bits + DEFAULT_PRODUCTION_FACTOR_BITS)) + (sint64)(prod_factor - 1)) / (sint64)prod_factor);
1218 if( ware.menge < 0 ) {
1219 ware.menge = 0;
1220 }
1221 if( ware.menge > max ) {
1222 ware.menge = max;
1223 }
1224
1225 if (ware.get_typ() != desc->get_supplier(i)->get_input_type()) {
1226 mismatch = true;
1227 dbg->warning("fabrik_t::rdwr", "Factory at %s: producer[%d] mismatch in savegame=%s/%s, in pak=%s",
1228 pos_origin.get_fullstr(), i, ware_name, ware.get_typ()->get_name(), desc->get_supplier(i)->get_input_type()->get_name());
1229 }
1230 }
1231 guarded_free(const_cast<char *>(ware_name));
1232 }
1233 }
1234 if( desc && input_count != desc->get_supplier_count() ) {
1235 dbg->warning("fabrik_t::rdwr", "Mismatch of input slot count for factory %s at %s: savegame = %d, pak = %d", get_name(), pos_origin.get_fullstr(), input_count, desc->get_supplier_count());
1236 // resize input to match the descriptor
1237 input.resize( desc->get_supplier_count() );
1238 mismatch = true;
1239 }
1240 if (mismatch) {
1241 array_tpl<ware_production_t> dummy;
1242 dummy.resize(desc->get_supplier_count());
1243 for(uint16 i=0; i<desc->get_supplier_count(); i++) {
1244 dummy[i] = input[i];
1245 }
1246 for(uint16 i=0; i<desc->get_supplier_count(); i++) {
1247 // search for matching type
1248 bool missing = true;
1249 const goods_desc_t* goods = desc->get_supplier(i)->get_input_type();
1250 for(uint16 j=0; j<desc->get_supplier_count() && missing; j++) {
1251 if (dummy[j].get_typ() == goods) {
1252 input[i] = dummy[j];
1253 dummy[j].set_typ(NULL);
1254 missing = false;
1255 }
1256 }
1257 if (missing) {
1258 input[i].set_typ(goods);
1259 }
1260 }
1261 }
1262
1263 // now rebuilt information for produced goods
1264 file->rdwr_long(output_count);
1265 if( file->is_loading() ) {
1266 output.resize( output_count );
1267 }
1268 mismatch = false;
1269 for( i=0; i<output_count; ++i ) {
1270 ware_production_t &ware = output[i];
1271 const char *ware_name = NULL;
1272 sint32 menge = ware.menge;
1273 if( file->is_saving() ) {
1274 ware_name = ware.get_typ()->get_name();
1275 // correct scaling for older saves
1276 if( file->is_version_less(120, 1) ){
1277 menge = (sint32)(((sint64)ware.menge * desc->get_product(i)->get_factor() ) >> DEFAULT_PRODUCTION_FACTOR_BITS);
1278 }
1279 }
1280 file->rdwr_str(ware_name);
1281 file->rdwr_long(menge);
1282 if( file->is_version_less(110, 5) ) {
1283 // max storage is only loaded/saved for older versions
1284 file->rdwr_long(ware.max);
1285 // obsolete variables -> statistics already contain records on goods delivered
1286 sint32 abgabe_sum = (sint32)(ware.get_stat(0, FAB_GOODS_DELIVERED));
1287 sint32 abgabe_letzt = (sint32)(ware.get_stat(1, FAB_GOODS_DELIVERED));
1288 file->rdwr_long(abgabe_sum);
1289 file->rdwr_long(abgabe_letzt);
1290 }
1291 ware.rdwr( file );
1292 if( file->is_loading() ) {
1293 ware.set_typ( goods_manager_t::get_info(ware_name) );
1294
1295 if( !desc || !desc->get_product(i) ) {
1296 if (desc) dbg->warning( "fabrik_t::rdwr()", "Factory at %s requested consumer for %s but has none!", pos_origin.get_fullstr(), ware_name );
1297 ware.menge = 0;
1298 }
1299 else {
1300 // Outputs used to be with respect to actual units of production. They now are normalized with respect to factory production so require conversion.
1301 if( file->is_version_less(120, 1) ){
1302 const uint32 prod_factor = desc ? desc->get_product(i)->get_factor() : 1;
1303 ware.menge = (sint32)(((sint64)menge << DEFAULT_PRODUCTION_FACTOR_BITS) / (sint64)prod_factor);
1304 }
1305 else {
1306 ware.menge = menge;
1307 }
1308
1309 // Hajo: repair files that have 'insane' values
1310 if( ware.menge < 0 ) {
1311 ware.menge = 0;
1312 }
1313
1314 if (ware.get_typ() != desc->get_product(i)->get_output_type()) {
1315 mismatch = true;
1316 dbg->warning("fabrik_t::rdwr", "Factory at %s: consumer[%d] mismatch in savegame=%s/%s, in pak=%s",
1317 pos_origin.get_fullstr(), i, ware_name, ware.get_typ()->get_name(), desc->get_product(i)->get_output_type()->get_name());
1318 }
1319 }
1320 guarded_free(const_cast<char *>(ware_name));
1321 }
1322 }
1323 if( desc && output_count != desc->get_product_count()) {
1324 dbg->warning("fabrik_t::rdwr", "Mismatch of output slot count for factory %s at %s: savegame = %d, pak = %d", get_name(), pos_origin.get_fullstr(), output_count, desc->get_product_count());
1325 // resize output to match the descriptor
1326 output.resize( desc->get_product_count() );
1327 mismatch = true;
1328 }
1329 if (mismatch) {
1330 array_tpl<ware_production_t> dummy;
1331 dummy.resize(desc->get_product_count());
1332 for(uint16 i=0; i<desc->get_product_count(); i++) {
1333 dummy[i] = output[i];
1334 }
1335 for(uint16 i=0; i<desc->get_product_count(); i++) {
1336 // search for matching type
1337 bool missing = true;
1338 const goods_desc_t* goods = desc->get_product(i)->get_output_type();
1339 for(uint16 j=0; j<desc->get_product_count() && missing; j++) {
1340 if (dummy[j].get_typ() == goods) {
1341 output[i] = dummy[j];
1342 dummy[j].set_typ(NULL);
1343 missing = false;
1344 }
1345 }
1346 if (missing) {
1347 output[i].set_typ(goods);
1348 }
1349 }
1350 }
1351
1352 // restore other information
1353 owner_n = welt->sp2num(owner);
1354 file->rdwr_long(owner_n);
1355 file->rdwr_long(prodbase);
1356 if( file->is_version_less(110, 5) ) {
1357 // TurfIt : prodfactor saving no longer required
1358 sint32 adjusted_value = (prodfactor_electric / 16) + 16;
1359 file->rdwr_long(adjusted_value);
1360 }
1361
1362 // no longer save power at factories
1363 if( file->is_version_atleast(99, 17) && file->is_version_less(120, 4) ) {
1364 sint32 power = 0;
1365 file->rdwr_long(power);
1366 }
1367 if( file->is_version_atleast(120, 1) && file->is_version_less(120, 4) ) {
1368 sint32 power_demand = 0;
1369 file->rdwr_long(power_demand);
1370 }
1371
1372 // owner stuff
1373 if( file->is_loading() ) {
1374 // take care of old files
1375 if( file->is_version_less(86, 1) ) {
1376 koord k = desc ? desc->get_building()->get_size() : koord(1,1);
1377 DBG_DEBUG("fabrik_t::rdwr()","correction of production by %i",k.x*k.y);
1378 // since we step from 86.01 per factory, not per tile!
1379 prodbase *= k.x*k.y*2;
1380 }
1381 // Hajo: restore factory owner
1382 // Due to a omission in Volkers changes, there might be savegames
1383 // in which factories were saved without an owner. In this case
1384 // set the owner to the default of player 1
1385 if(owner_n == -1) {
1386 // Use default
1387 owner = welt->get_public_player();
1388 }
1389 else {
1390 // Restore owner pointer
1391 owner = welt->get_player(owner_n);
1392 }
1393 }
1394
1395 file->rdwr_long(anz_lieferziele);
1396
1397 // connect/save consumer
1398 for(int i=0; i<anz_lieferziele; i++) {
1399 if(file->is_loading()) {
1400 lieferziele.append(koord::invalid);
1401 }
1402 lieferziele[i].rdwr(file);
1403 }
1404
1405 if( file->is_version_atleast(112, 2) ) {
1406 file->rdwr_long( lieferziele_active_last_month );
1407 }
1408
1409 // suppliers / consumers will be recalculated in finish_rd
1410 if (file->is_loading() && welt->get_settings().is_crossconnect_factories()) {
1411 lieferziele.clear();
1412 }
1413
1414 // information on fields ...
1415 if( file->is_version_atleast(99, 10) ) {
1416 if( file->is_saving() ) {
1417 uint16 nr=fields.get_count();
1418 file->rdwr_short(nr);
1419 if( file->is_version_atleast(102, 3) ) {
1420 // each field stores location and a field class index
1421 for( uint16 i=0 ; i<nr ; ++i ) {
1422 koord k = fields[i].location;
1423 k.rdwr(file);
1424 uint16 idx = fields[i].field_class_index;
1425 file->rdwr_short(idx);
1426 }
1427 }
1428 else {
1429 // each field only stores location
1430 for( uint16 i=0 ; i<nr ; ++i ) {
1431 koord k = fields[i].location;
1432 k.rdwr(file);
1433 }
1434 }
1435 }
1436 else {
1437 uint16 nr=0;
1438 koord k;
1439 file->rdwr_short(nr);
1440 fields.resize(nr);
1441 if( file->is_version_atleast(102, 3) ) {
1442 // each field stores location and a field class index
1443 for( uint16 i=0 ; i<nr ; ++i ) {
1444 k.rdwr(file);
1445 uint16 idx;
1446 file->rdwr_short(idx);
1447 if( desc && desc->get_field_group() ) {
1448 // set class index to 0 if it is out of range, if there fields at all
1449 fields.append( field_data_t(k, idx >= desc->get_field_group()->get_field_class_count() ? 0 : idx ) );
1450 }
1451 }
1452 }
1453 else {
1454 // each field only stores location
1455 for( uint16 i=0 ; i<nr ; ++i ) {
1456 k.rdwr(file);
1457 if( desc && desc->get_field_group() ) {
1458 // oald add fields if there are any defined
1459 fields.append( field_data_t(k, 0) );
1460 }
1461 }
1462 }
1463 }
1464 }
1465
1466 // restore city pointer here
1467 if( file->is_version_atleast(99, 14) ) {
1468 sint32 nr = target_cities.get_count();
1469 file->rdwr_long(nr);
1470 for( int i=0; i<nr; i++ ) {
1471 sint32 city_index = -1;
1472 if(file->is_saving()) {
1473 city_index = welt->get_cities().index_of( target_cities[i] );
1474 }
1475 file->rdwr_long(city_index);
1476 if( file->is_loading() ) {
1477 // will also update factory information
1478 target_cities.append( welt->get_cities()[city_index] );
1479 }
1480 }
1481 }
1482 else if( file->is_loading() ) {
1483 // will be handled by the city after reloading
1484 target_cities.clear();
1485 }
1486
1487 if( file->is_version_atleast(110, 5) ) {
1488 file->rdwr_short(times_expanded);
1489 // statistics
1490 for( int s=0; s<MAX_FAB_STAT; ++s ) {
1491 for( int m=0; m<MAX_MONTH; ++m ) {
1492 file->rdwr_longlong( statistics[m][s] );
1493 }
1494 }
1495 file->rdwr_longlong( weighted_sum_production );
1496 file->rdwr_longlong( weighted_sum_boost_electric );
1497 file->rdwr_longlong( weighted_sum_boost_pax );
1498 file->rdwr_longlong( weighted_sum_boost_mail );
1499 file->rdwr_longlong( weighted_sum_power );
1500 file->rdwr_longlong( aggregate_weight );
1501 file->rdwr_long( delta_slot );
1502 }
1503 else if( file->is_loading() ) {
1504 times_expanded = 0;
1505 init_stats();
1506 delta_slot = 0;
1507 }
1508 arrival_stats_pax.rdwr( file );
1509 arrival_stats_mail.rdwr( file );
1510
1511 if( file->is_version_atleast(110, 7) ) {
1512 file->rdwr_byte(activity_count);
1513 }
1514 else if( file->is_loading() ) {
1515 activity_count = 0;
1516 }
1517
1518 // save name
1519 if( file->is_version_atleast(110, 7) ) {
1520 if( file->is_saving() && !name ) {
1521 char const* fullname = desc->get_name();
1522 file->rdwr_str(fullname);
1523 }
1524 else {
1525 file->rdwr_str(name);
1526 if( file->is_loading() && desc != NULL && name == desc->get_name() ) {
1527 // equal to desc name
1528 name = 0;
1529 }
1530 }
1531 }
1532 }
1533
1534
1535 /**
1536 * let the chimney smoke, if there is something to produce
1537 * @author Hj. Malthaner
1538 */
smoke() const1539 void fabrik_t::smoke() const
1540 {
1541 const smoke_desc_t *rada = desc->get_smoke();
1542 if(rada) {
1543 const koord size = desc->get_building()->get_size(0)-koord(1,1);
1544 const uint8 rot = (4-rotate)%desc->get_building()->get_all_layouts();
1545 koord ro = rada->get_pos_off(size,rot);
1546 grund_t *gr = welt->lookup_kartenboden(pos_origin.get_2d()+ro);
1547 // to get same random order on different compilers
1548 const sint8 offsetx = ((rada->get_xy_off(rot).x+sim_async_rand(7)-3)*OBJECT_OFFSET_STEPS)/16;
1549 const sint8 offsety = ((rada->get_xy_off(rot).y+sim_async_rand(7)-3)*OBJECT_OFFSET_STEPS)/16;
1550 wolke_t *smoke = new wolke_t(gr->get_pos(), offsetx, offsety, rada->get_images() );
1551 gr->obj_add(smoke);
1552 welt->sync_way_eyecandy.add( smoke );
1553 }
1554 // maybe sound?
1555 if( desc->get_sound()!=NO_SOUND && welt->get_ticks()>last_sound_ms+desc->get_sound_interval_ms() ) {
1556 welt->play_sound_area_clipped( get_pos().get_2d(), desc->get_sound() );
1557 }
1558 }
1559
1560
scale_output_production(const uint32 product,uint32 menge) const1561 uint32 fabrik_t::scale_output_production(const uint32 product, uint32 menge) const
1562 {
1563 // prorate production based upon amount of product in storage
1564 // but allow full production rate for storage amounts less than twice the minimum shipment size.
1565 const uint32 maxi = output[product].max;
1566 const uint32 actu = output[product].menge;
1567 if( actu<maxi ) {
1568 if( actu >= (uint32)(2 * output[product].min_shipment) ) {
1569 if( menge>(0x7FFFFFFFu/maxi) ) {
1570 // avoid overflow
1571 menge = (((maxi-actu)>>5)*(menge>>5))/(maxi>>10);
1572 }
1573 else {
1574 // and that is the simple formula
1575 menge = (menge*(maxi-actu)) / maxi;
1576 }
1577 }
1578 }
1579 else {
1580 // overfull? No production
1581 menge = 0;
1582 }
1583 return menge;
1584 }
1585
set_power_supply(uint32 supply)1586 void fabrik_t::set_power_supply(uint32 supply)
1587 {
1588 pumpe_t *const trans = dynamic_cast<pumpe_t *>(transformer);
1589 if( trans == NULL ) {
1590 return;
1591 }
1592 trans->set_power_supply(supply);
1593 }
1594
get_power_supply() const1595 uint32 fabrik_t::get_power_supply() const
1596 {
1597 pumpe_t *const trans = dynamic_cast<pumpe_t *>(transformer);
1598 if( trans == NULL ) {
1599 return 0;
1600 }
1601 return trans->get_power_supply();
1602 }
1603
get_power_consumption() const1604 sint32 fabrik_t::get_power_consumption() const
1605 {
1606 pumpe_t *const trans = dynamic_cast<pumpe_t *>(transformer);
1607 if( trans == NULL ) {
1608 return 0;
1609 }
1610 return trans->get_power_consumption();
1611 }
1612
set_power_demand(uint32 demand)1613 void fabrik_t::set_power_demand(uint32 demand)
1614 {
1615 senke_t *const trans = dynamic_cast<senke_t *>(transformer);
1616 if( trans == NULL ) {
1617 return;
1618 }
1619 trans->set_power_demand(demand);
1620 }
1621
get_power_demand() const1622 uint32 fabrik_t::get_power_demand() const
1623 {
1624 senke_t *const trans = dynamic_cast<senke_t *>(transformer);
1625 if( trans == NULL ) {
1626 return 0;
1627 }
1628 return trans->get_power_demand();
1629 }
1630
get_power_satisfaction() const1631 sint32 fabrik_t::get_power_satisfaction() const
1632 {
1633 senke_t *const trans = dynamic_cast<senke_t *>(transformer);
1634 if( trans == NULL ) {
1635 return 0;
1636 }
1637 return trans->get_power_satisfaction();
1638 }
1639
get_power() const1640 sint64 fabrik_t::get_power() const
1641 {
1642 sint64 power;
1643 if( desc->is_electricity_producer() ) {
1644 power = ((sint64)get_power_supply() * (sint64)get_power_consumption()) >> leitung_t::FRACTION_PRECISION;
1645 }
1646 else {
1647 power = -(((sint64)get_power_demand() * (sint64)get_power_satisfaction() + (((sint64)1 << leitung_t::FRACTION_PRECISION) - 1)) >> leitung_t::FRACTION_PRECISION);
1648 }
1649 return power;
1650 }
1651
1652
input_vorrat_an(const goods_desc_t * typ)1653 sint32 fabrik_t::input_vorrat_an(const goods_desc_t *typ)
1654 {
1655 sint32 menge = -1;
1656
1657 FOR(array_tpl<ware_production_t>, const& i, input) {
1658 if (typ == i.get_typ()) {
1659 menge = i.menge >> precision_bits;
1660 break;
1661 }
1662 }
1663
1664 return menge;
1665 }
1666
1667
vorrat_an(const goods_desc_t * typ)1668 sint32 fabrik_t::vorrat_an(const goods_desc_t *typ)
1669 {
1670 sint32 menge = -1;
1671
1672 FOR(array_tpl<ware_production_t>, const& i, output) {
1673 if (typ == i.get_typ()) {
1674 menge = i.menge >> precision_bits;
1675 break;
1676 }
1677 }
1678
1679 return menge;
1680 }
1681
1682
liefere_an(const goods_desc_t * typ,sint32 menge)1683 sint32 fabrik_t::liefere_an(const goods_desc_t *typ, sint32 menge)
1684 {
1685 if( typ==goods_manager_t::passengers ) {
1686 // book pax arrival and recalculate pax boost
1687 book_stat(menge, FAB_PAX_ARRIVED);
1688 arrival_stats_pax.book_arrival(menge);
1689 update_prodfactor_pax();
1690 return menge;
1691 }
1692 else if( typ==goods_manager_t::mail ) {
1693 // book mail arrival and recalculate mail boost
1694 book_stat(menge, FAB_MAIL_ARRIVED);
1695 arrival_stats_mail.book_arrival(menge);
1696 update_prodfactor_mail();
1697 return menge;
1698 }
1699 else {
1700 // case : freight
1701 for( uint32 in = 0; in < input.get_count(); in++ ){
1702 ware_production_t& ware = input[in];
1703 if( ware.get_typ() == typ ) {
1704 ware.book_stat( -menge, FAB_GOODS_TRANSIT );
1705
1706 // Resolve how much normalized production arrived, rounding up (since we rounded up when we removed it).
1707 const uint32 prod_factor = desc->get_supplier(in)->get_consumption();
1708 const sint32 prod_delta = (sint32)((((sint64)menge << (DEFAULT_PRODUCTION_FACTOR_BITS + precision_bits)) + (sint64)(prod_factor - 1)) / (sint64)prod_factor);
1709
1710 // Activate inactive inputs.
1711 if( ware.menge <= 0 ) {
1712 inactive_inputs --;
1713 }
1714 ware.menge+= prod_delta;
1715
1716 if( welt->get_settings().get_just_in_time() >= 2 ){
1717 // In JIT2 it is illegal to exceed input storage limit. All production that does so is discarded.
1718 if( ware.menge > ware.max ){
1719 const sint32 prod_comp = ware.menge - ware.max;
1720 ware.menge = ware.max;
1721
1722 // Apply demand penalty. Reactivate inactive demands.
1723 sint32 demand_old = ware.demand_buffer;
1724 ware.demand_buffer-= prod_comp;
1725 if( demand_old >= ware.max && ware.demand_buffer < ware.max ) inactive_demands-= 1;
1726
1727 // Resolve how many goods we actually used (rounding to nearest)
1728 menge -= (sint32)(((sint64)prod_comp * (sint64)prod_factor + (1 << (DEFAULT_PRODUCTION_FACTOR_BITS + precision_bits - 1))) >> (DEFAULT_PRODUCTION_FACTOR_BITS + precision_bits));
1729 }
1730 }
1731 else{
1732 // Hajo: avoid overflow
1733 const sint32 max = (sint32)((((sint64)FAB_MAX_INPUT << (precision_bits + DEFAULT_PRODUCTION_FACTOR_BITS)) + (sint64)(prod_factor - 1)) / (sint64)prod_factor);
1734 if( ware.menge >= max ) {
1735 menge -= (sint32)(((sint64)menge * (sint64)(ware.menge - max) + (sint64)(prod_delta >> 1)) / (sint64)prod_delta);
1736 ware.menge = max - 1;
1737 }
1738 }
1739 ware.book_stat(menge, FAB_GOODS_RECEIVED);
1740 return menge;
1741 }
1742 }
1743 }
1744 // ware "typ" wird hier nicht verbraucht
1745 return -1;
1746 }
1747
1748
is_needed(const goods_desc_t * typ) const1749 sint8 fabrik_t::is_needed(const goods_desc_t *typ) const
1750 {
1751 FOR(array_tpl<ware_production_t>, const& i, input) {
1752 if( i.get_typ() == typ ) {
1753 // Ordering logic is done in ticks. This means that every supplier is given a chance to fulfill an order (which they do so fairly).
1754 return i.placing_orders;
1755 }
1756 }
1757 return -1; // not needed here
1758 }
1759
1760
is_active_lieferziel(koord k) const1761 bool fabrik_t::is_active_lieferziel( koord k ) const
1762 {
1763 assert( lieferziele.is_contained(k) );
1764 return 0 < ( ( 1 << lieferziele.index_of(k) ) & lieferziele_active_last_month );
1765 }
1766
get_jit2_power_boost() const1767 sint32 fabrik_t::get_jit2_power_boost() const
1768 {
1769 // transformer boost amount
1770 sint32 boost = 0;
1771
1772 // compute power boost
1773 if( is_transformer_connected() ) {
1774 sint32 const power_satisfaction = get_power_satisfaction();
1775 if( power_satisfaction >= ((sint32)1 << leitung_t::FRACTION_PRECISION) ) {
1776 // all demand fulfilled
1777 boost = (sint32)desc->get_electric_boost();
1778 }
1779 else {
1780 // calculate bonus, rounding down
1781 boost = (sint32)(((sint64)desc->get_electric_boost() * (sint64)power_satisfaction) >> leitung_t::FRACTION_PRECISION);
1782 }
1783 }
1784
1785 return boost;
1786 }
1787
step(uint32 delta_t)1788 void fabrik_t::step(uint32 delta_t)
1789 {
1790 // Only do something if advancing in time.
1791 if( delta_t==0 ) {
1792 return;
1793 }
1794
1795 /// Declare production control variables.
1796
1797 // The production effort of the factory.
1798 sint32 prod;
1799
1800 // Actual production effort done.
1801 sint32 work = 0;
1802
1803 // Desired production effort of factory.
1804 sint32 want = 0;
1805
1806 /// Boost logic.
1807
1808 // Solve boosts.
1809 switch( boost_type ) {
1810 case BL_CLASSIC: {
1811 // JIT1 implementation for power bonus.
1812 if( !desc->is_electricity_producer() && scaled_electric_demand > 0 ) {
1813 // one may be thinking of linking this to actual production only
1814 prodfactor_electric = (sint32)(((sint64)desc->get_electric_boost() * (sint64)get_power_satisfaction() + (sint64)((sint64)1 << (leitung_t::FRACTION_PRECISION - 1))) >> leitung_t::FRACTION_PRECISION);
1815 }
1816 break;
1817 }
1818 case BL_POWER: {
1819 // get desired power boost amount
1820 sint32 const prodfactor_want = get_jit2_power_boost();
1821
1822 // calculate maximum change delta from change rate scaled by time
1823 const sint32 prodfactor_change = max(BOOST_POWER_CHANGE_RATE * delta_t / PRODUCTION_DELTA_T, 1);
1824
1825 // limit rate of change of electricity boost (improve stability)
1826 const sint32 prodfactor_delta = prodfactor_want - prodfactor_electric;
1827 if( prodfactor_delta > prodfactor_change ) {
1828 // limit increase rate
1829 prodfactor_electric += prodfactor_change;
1830 }
1831 //else if( prodfactor_delta < -prodfactor_change ) {
1832 // limit decrease rate, off because of possible exploit
1833 // prodfactor_electric -= prodfactor_change;
1834 //}
1835 else {
1836 // no limit
1837 prodfactor_electric = prodfactor_want;
1838 }
1839
1840 break;
1841 }
1842 default: {
1843 // No boost amounts to solve.
1844 break;
1845 }
1846 };
1847
1848 // Compute boost amount.
1849 const sint32 boost = get_prodfactor();
1850
1851 /// Compute base production.
1852 {
1853 // Calculate actual production. A remainder is used for extra precision.
1854 const uint64 want_prod_long = (uint64)prodbase * (uint64)boost * (uint64)delta_t + (uint64)menge_remainder;
1855 prod = (uint32)(want_prod_long >> (PRODUCTION_DELTA_T_BITS + DEFAULT_PRODUCTION_FACTOR_BITS + DEFAULT_PRODUCTION_FACTOR_BITS - fabrik_t::precision_bits));
1856 menge_remainder = (uint32)(want_prod_long & ((1 << (PRODUCTION_DELTA_T_BITS + DEFAULT_PRODUCTION_FACTOR_BITS + DEFAULT_PRODUCTION_FACTOR_BITS - fabrik_t::precision_bits)) - 1 ));
1857 }
1858
1859 /// Perform the control logic.
1860 {
1861 // Common logic locals go here.
1862
1863 // Amount of production change.
1864 sint32 prod_delta;
1865 // The amount of production available.
1866 sint32 prod_comp;
1867 // The amount of consumption available.
1868 sint32 cons_comp = 0;
1869
1870 switch( control_type ) {
1871 case CL_PROD_CLASSIC: {
1872 // Classic producer logic.
1873 currently_producing = false;
1874
1875 // produces something
1876 for( uint32 product = 0; product < output.get_count(); product++ ) {
1877 // source producer
1878 const uint32 menge_out = scale_output_production( product, prod );
1879
1880 if( menge_out > 0 ) {
1881 const sint32 p = (sint32)menge_out;
1882
1883 // compute work factor
1884 const sint32 work_fact = work_from_production(prod, p);
1885
1886 // work done is work done of maximum output
1887 if( work_fact > work ) {
1888 work = work_fact;
1889 }
1890
1891 // produce
1892 if( output[product].menge < output[product].max ) {
1893 // to find out, if storage changed
1894 delta_menge += p;
1895 output[product].menge += p;
1896 output[product].book_stat((sint64)p * (sint64)desc->get_product(0)->get_factor(), FAB_GOODS_PRODUCED);
1897 // if less than 3/4 filled we neary always consume power
1898 currently_producing |= (output[product].menge*4 < output[product].max*3);
1899 }
1900 else {
1901 output[product].book_stat((sint64)(output[product].max - 1 - output[product].menge) * (sint64)desc->get_product(product)->get_factor(), FAB_GOODS_PRODUCED);
1902 output[product].menge = output[product].max - 1;
1903 }
1904 }
1905 }
1906
1907 break;
1908 }
1909 case CL_PROD_MANY: {
1910 // A producer with many outputs.
1911 if( inactive_outputs == output.get_count() ) {
1912 break;
1913 }
1914
1915 currently_producing = true;
1916
1917 for( uint32 product = 0; product < output.get_count(); product++ ) {
1918 prod_comp = output[product].max - output[product].menge;
1919
1920 // Ignore inactive outputs.
1921 if( prod_comp <= 0 ) {
1922 continue;
1923 }
1924
1925 // get desired work factor
1926 const sint32 work_fact = output[product].calculate_output_production_rate();
1927
1928 // compute desired production
1929 prod_delta = work_scale_production(prod, work_fact);
1930
1931 // Cannot produce more than can be stored.
1932 if( prod_delta >= prod_comp ) {
1933 prod_delta = prod_comp;
1934 inactive_outputs++;
1935 if( inactive_outputs == output.get_count() ) {
1936 currently_producing = false;
1937 }
1938 }
1939
1940 delta_menge += prod_delta;
1941 output[product].menge += prod_delta;
1942 output[product].book_stat((sint64)prod_delta * (sint64)desc->get_product(product)->get_factor(), FAB_GOODS_PRODUCED);
1943
1944 work += work_fact;
1945 }
1946
1947 // normalize work with respect to output number
1948 work /= output.get_count();
1949
1950 break;
1951 }
1952 case CL_FACT_CLASSIC: {
1953 // Classic factory logic, work and want determined by the maximum output production rate.
1954 currently_producing = false;
1955
1956 // ok, calulate maximum allowed consumption.
1957 {
1958 sint32 min_menge = input[0].menge;
1959 sint32 consumed_menge = 0;
1960 for( uint32 index = 1; index < input.get_count(); index++ ) {
1961 if( input[index].menge < min_menge ) {
1962 min_menge = input[index].menge;
1963 }
1964 }
1965
1966 // produces something
1967 for( uint32 product = 0; product < output.get_count(); product++ ) {
1968 // calculate production
1969 const sint32 p_menge = (sint32)scale_output_production( product, prod );
1970
1971 // Want the maximum production rate, this is so correct amount is ordered.
1972 if( p_menge > want ) {
1973 want = p_menge;
1974 }
1975
1976 const sint32 menge_out = p_menge < min_menge ? p_menge : min_menge; // production smaller than possible due to consumption
1977 if( menge_out > consumed_menge ) {
1978 consumed_menge = menge_out;
1979 }
1980
1981 if( menge_out > 0 ) {
1982 const sint32 p = menge_out;
1983
1984 // produce
1985 if( output[product].menge < output[product].max ) {
1986 // to find out, if storage changed
1987 delta_menge += p;
1988 output[product].menge += p;
1989 output[product].book_stat((sint64)p * (sint64)desc->get_product(product)->get_factor(), FAB_GOODS_PRODUCED);
1990 // if less than 3/4 filled we neary always consume power
1991 currently_producing |= (output[product].menge*4 < output[product].max*3);
1992 }
1993 else {
1994 output[product].book_stat((sint64)(output[product].max - 1 - output[product].menge) * (sint64)desc->get_product(product)->get_factor(), FAB_GOODS_PRODUCED);
1995 output[product].menge = output[product].max - 1;
1996 }
1997 }
1998 }
1999
2000 // and finally consume stock
2001 for( uint32 index = 0; index < input.get_count(); index++ ) {
2002 const uint32 v = consumed_menge;
2003
2004 if( (uint32)input[index].menge > v + 1 ) {
2005 input[index].menge -= v;
2006 input[index].book_stat((sint64)v * (sint64)desc->get_supplier(index)->get_consumption(), FAB_GOODS_CONSUMED);
2007 }
2008 else {
2009 input[index].book_stat((sint64)input[index].menge * (sint64)desc->get_supplier(index)->get_consumption(), FAB_GOODS_CONSUMED);
2010 input[index].menge = 0;
2011 }
2012 }
2013
2014 // work done is consumption rate
2015 work = work_from_production(prod, consumed_menge);
2016 }
2017
2018 break;
2019 }
2020 case CL_FACT_MANY: {
2021 // Logic for a factory with many outputs. Work and want are based on weighted output rate so is more complicated.
2022 if( inactive_outputs == output.get_count() ) {
2023 break;
2024 }
2025 {
2026 const bool no_input = inactive_inputs > 0;
2027
2028 // Determine minimum input in form of production from all outputs. This limits production.
2029 // Determine minimum demand work rate from all inputs. This limits production rate.
2030 sint32 demand_work_limt = input[0].calculate_demand_production_rate();
2031 cons_comp = input[0].menge;
2032 for( uint32 index = 1; index < input.get_count(); index++ ) {
2033 if( input[index].menge < cons_comp ) {
2034 cons_comp = input[index].menge;
2035 }
2036 sint32 const work_limit = input[index].calculate_demand_production_rate();
2037 if( work_limit < demand_work_limt ) {
2038 demand_work_limt = work_limit;
2039 }
2040
2041 }
2042 cons_comp *= output.get_count();
2043
2044 if( !no_input ) {
2045 currently_producing = true;
2046 }
2047
2048 for( uint32 product = 0; product < output.get_count(); product++ ) {
2049 prod_comp = output[product].max - output[product].menge;
2050
2051 // Ignore inactive outputs.
2052 if( prod_comp <= 0 ) {
2053 continue;
2054 }
2055
2056 // get desired work factor
2057 const sint32 work_fact = min(output[product].calculate_output_production_rate(), demand_work_limt);
2058
2059 // compute desired production
2060 prod_delta = work_scale_production(prod, work_fact);
2061
2062 // limit to maximum storage
2063 if( prod_delta > prod_comp ) {
2064 prod_delta = prod_comp;
2065 }
2066
2067 // credit desired production for want
2068 want += prod_delta;
2069
2070 // skip producing anything if no input
2071 if( no_input ) {
2072 continue;
2073 }
2074
2075 // enforce input limits on production
2076 if( prod_delta > cons_comp ) {
2077 // not enough input
2078 prod_delta = cons_comp;
2079 cons_comp = 0;
2080 }
2081 else {
2082 // enough input
2083 cons_comp -= prod_delta;
2084 }
2085
2086 // register inactive outputs
2087 if( prod_delta == prod_comp ) {
2088 inactive_outputs++;
2089 if( inactive_outputs == output.get_count() ) {
2090 currently_producing = false;
2091 }
2092 }
2093
2094 // credit output work done
2095 work += prod_delta;
2096
2097 // Produce output
2098 delta_menge += prod_delta;
2099 output[product].menge += prod_delta;
2100 output[product].book_stat((sint64)prod_delta * (sint64)desc->get_product(product)->get_factor(), FAB_GOODS_PRODUCED);
2101 }
2102
2103 // normalize want with respect to output number
2104 want /= output.get_count();
2105
2106 // skip consuming anything if no input
2107 if( no_input ) {
2108 break;
2109 }
2110
2111 // compute work done
2112 const sint32 consumed = work / output.get_count();
2113 work = work_from_production(prod, consumed);
2114
2115 // consume inputs
2116 for( uint32 index = 0; index < input.get_count(); index++ ) {
2117 input[index].menge -= consumed;
2118 input[index].book_stat((sint64)consumed * (sint64)desc->get_supplier(index)->get_consumption(), FAB_GOODS_CONSUMED);
2119
2120 // register inactive inputs
2121 if( input[index].menge <= 0 ) {
2122 currently_producing = false;
2123 input[index].menge = 0;
2124 inactive_inputs ++;
2125 }
2126 }
2127 }
2128 break;
2129 }
2130 case CL_CONS_CLASSIC: {
2131 uint32 power = 0;
2132
2133 // Classic consumer logic.
2134 currently_producing = false;
2135
2136 if( desc->is_electricity_producer() ) {
2137 // power station => start with no production
2138 power = 0;
2139 }
2140
2141 // Always want to consume at rate of prod.
2142 want = prod;
2143
2144 // finally consume stock
2145 for( uint32 index = 0; index < input.get_count(); index++ ) {
2146 const uint32 v = prod;
2147
2148 if( (uint32)input[index].menge > v + 1 ) {
2149 input[index].menge -= v;
2150 input[index].book_stat((sint64)v * (sint64)desc->get_supplier(index)->get_consumption(), FAB_GOODS_CONSUMED);
2151 currently_producing = true;
2152 if( desc->is_electricity_producer() ) {
2153 // power station => produce power
2154 power += (uint32)( ((sint64)scaled_electric_demand * (sint64)(DEFAULT_PRODUCTION_FACTOR + prodfactor_pax + prodfactor_mail)) >> DEFAULT_PRODUCTION_FACTOR_BITS );
2155 }
2156 work += 1 << WORK_BITS;
2157 // to find out, if storage changed
2158 delta_menge += v;
2159 }
2160 else {
2161 if( desc->is_electricity_producer() ) {
2162 // power station => produce power
2163 power += (uint32)( (((sint64)scaled_electric_demand * (sint64)(DEFAULT_PRODUCTION_FACTOR + prodfactor_pax + prodfactor_mail)) >> DEFAULT_PRODUCTION_FACTOR_BITS) * input[index].menge / (v + 1) );
2164 }
2165 delta_menge += input[index].menge;
2166 work += work_from_production(prod, input[index].menge);
2167 input[index].book_stat((sint64)input[index].menge * (sint64)desc->get_supplier(index)->get_consumption(), FAB_GOODS_CONSUMED);
2168 input[index].menge = 0;
2169 }
2170 }
2171
2172 // normalize work with respect to input number
2173 work /= input.get_count();
2174 set_power_supply(power);
2175
2176 break;
2177 }
2178 case CL_CONS_MANY: {
2179 // Consumer logic for many inputs. Work done is based on the average consumption of all inputs.
2180
2181 // always consume prod
2182 want = prod;
2183
2184 // Do nothing if we cannot consume anything.
2185 if( inactive_inputs == input.get_count() ) {
2186 break;
2187 }
2188
2189 currently_producing = true;
2190
2191 for( uint32 index = 0; index < input.get_count(); index++ ) {
2192 // Only process active inputs;
2193 if( input[index].menge <= 0 ) {
2194 continue;
2195 }
2196
2197 sint32 const consumption_prod = work_scale_production(prod, input[index].calculate_demand_production_rate());
2198
2199 // limit consumption to minimum of production or storage
2200 prod_delta = input[index].menge > consumption_prod ? consumption_prod : input[index].menge;
2201
2202 // add to work done
2203 work += prod_delta;
2204
2205 // consume input
2206 delta_menge += prod_delta;
2207 input[index].menge -= prod_delta;
2208 input[index].book_stat((sint64)prod_delta * (sint64)desc->get_supplier(index)->get_consumption(), FAB_GOODS_CONSUMED);
2209
2210 // register inactive input
2211 if( input[index].menge <= 0 ) {
2212 inactive_inputs++;
2213 if( inactive_inputs == input.get_count() ) {
2214 currently_producing = false;
2215 }
2216 }
2217 }
2218
2219 // normalise and convert work into work factor
2220 work = work_from_production(prod, work / input.get_count());
2221
2222 if( desc->is_electricity_producer() ) {
2223 // compute power production
2224 uint64 pp = ((uint64)scaled_electric_demand * (uint64)boost * (uint64)work) >> (DEFAULT_PRODUCTION_FACTOR_BITS + WORK_BITS);
2225 set_power_supply((uint32)pp);
2226 }
2227
2228 break;
2229 }
2230 case CL_ELEC_PROD: {
2231 // A simple no input electricity producer, like a solar array.
2232
2233 // always maximum work
2234 currently_producing = true;
2235 work = 1 << WORK_BITS;
2236 delta_menge += prod;
2237
2238 // compute power production
2239 uint64 pp = ((uint64)scaled_electric_demand * (uint64)boost) >> DEFAULT_PRODUCTION_FACTOR_BITS;
2240 set_power_supply((uint32)pp);
2241
2242 break;
2243 }
2244 case CL_ELEC_CLASSIC: {
2245 // Classic no input power producer.
2246 currently_producing = false;
2247 work = 1 << WORK_BITS;
2248
2249 // power station? => produce power
2250 if( desc->is_electricity_producer() ) {
2251 currently_producing = true;
2252 set_power_supply((uint32)( ((sint64)scaled_electric_demand * (sint64)(DEFAULT_PRODUCTION_FACTOR + prodfactor_pax + prodfactor_mail)) >> DEFAULT_PRODUCTION_FACTOR_BITS ));
2253 }
2254 break;
2255 }
2256 case CL_NONE:
2257 default: {
2258 // None always produces maximum for whatever reason. Also default.
2259 work = 1 << WORK_BITS;
2260 break;
2261 }
2262 }
2263 }
2264
2265 /// Ordering logic.
2266 switch( demand_type ) {
2267 case DL_SYNC: {
2268 // Synchronous ordering. All buffers are filled the same amount in parallel based on desired work factor.
2269
2270 if( want == 0 || inactive_demands > 0 ) {
2271 // No ordering if any are overfull or there is no want.
2272 break;
2273 }
2274
2275 for( uint32 index = 0; index < input.get_count(); index++ ) {
2276 input[index].demand_buffer += want;
2277
2278 // register inactive demand buffer
2279 if( input[index].demand_buffer >= input[index].max ) {
2280 inactive_demands++;
2281 }
2282 }
2283 break;
2284 }
2285 case DL_ASYNC: {
2286 // Asynchronous ordering. Each buffer tries to order scaled back by the demand work factor.
2287
2288 if( want == 0 || inactive_demands == input.get_count() ) {
2289 // No ordering if all are overfull or no want.
2290 break;
2291 }
2292
2293 for( uint32 index = 0; index < input.get_count(); index++ ) {
2294 // Skip inactive demand buffers.
2295 if( input[index].demand_buffer >= input[index].max ) {
2296 continue;
2297 }
2298 input[index].demand_buffer += max(work_scale_production(want, input[index].calculate_demand_production_rate()), 1);
2299
2300 // register inactive demand buffer
2301 if( input[index].demand_buffer >= input[index].max ) {
2302 inactive_demands++;
2303 }
2304 }
2305 break;
2306 }
2307 default: {
2308 // Nothing to order.
2309 break;
2310 }
2311 }
2312
2313 /// Book the weighted sums for statistics.
2314
2315 book_weighted_sums( delta_t );
2316
2317 /// Power ordering logic.
2318
2319 switch( boost_type ) {
2320 case BL_CLASSIC: {
2321 // draw a fixed amount of power when working sufficiently, otherwise draw no power
2322 if( !desc->is_electricity_producer() ) {
2323 if( currently_producing ) {
2324 set_power_demand(scaled_electric_demand);
2325 }
2326 else {
2327 set_power_demand(0);
2328 }
2329 }
2330 break;
2331 }
2332 case BL_POWER: {
2333 // compute power demand
2334 uint64 pd = ((uint64)scaled_electric_demand * (uint64)boost * (uint64)work) >> (DEFAULT_PRODUCTION_FACTOR_BITS + WORK_BITS);
2335 set_power_demand((uint32)pd);
2336
2337 break;
2338 }
2339 default: {
2340 // No power is ordered.
2341 break;
2342 }
2343 };
2344
2345 /// Periodic tasks.
2346
2347 delta_sum += delta_t;
2348 if( delta_sum > PRODUCTION_DELTA_T ) {
2349 delta_sum = delta_sum % PRODUCTION_DELTA_T;
2350
2351 // distribute, if min shipment waiting.
2352 for( uint32 product = 0; product < output.get_count(); product++ ) {
2353 // either more than ten or nearly full (if there are less than ten output)
2354 if( output[product].menge >= output[product].min_shipment ) {
2355 verteile_waren( product );
2356 INT_CHECK("simfab 636");
2357 }
2358 }
2359
2360 // Order required inputs.
2361 for( uint32 index = 0; index < input.get_count(); index++ ) {
2362 switch( demand_type ) {
2363 case DL_SYNC:
2364 case DL_ASYNC: {
2365 // Orders based on demand buffer.
2366 input[index].placing_orders = (input[index].demand_buffer > 0);
2367 break;
2368 }
2369 case DL_OLD: {
2370 // Orders based on storage and maximum transit.
2371 input[index].placing_orders = (input[index].menge < input[index].max && (input[index].max_transit == 0 || input[index].get_in_transit() < input[index].max_transit) );
2372 break;
2373 }
2374 default: {
2375 // Unknown order logic?
2376 break;
2377 }
2378 }
2379 }
2380
2381 recalc_factory_status();
2382
2383 // rescale delta_menge here: all products should be produced at least once
2384 // (if consumer only: all supplements should be consumed once)
2385 const uint32 min_change = output.empty() ? input.get_count() : output.get_count();
2386
2387 if( (delta_menge >> fabrik_t::precision_bits) > min_change ) {
2388 // we produced some real quantity => smoke
2389 smoke();
2390
2391 // Knightly : chance to expand every 256 rounds of activities, after which activity count will return to 0 (overflow behaviour)
2392 if( (++activity_count)==0 ) {
2393 if( desc->get_field_group() ) {
2394 if( fields.get_count()<desc->get_field_group()->get_max_fields() ) {
2395 // spawn new field with given probability
2396 add_random_field(desc->get_field_group()->get_probability());
2397 }
2398 }
2399 else {
2400 if( times_expanded < desc->get_expand_times() ) {
2401 if( simrand(10000) < desc->get_expand_probability() ) {
2402 set_base_production( prodbase + desc->get_expand_minimum() + simrand( desc->get_expand_range() ) );
2403 ++times_expanded;
2404 }
2405 }
2406 }
2407 }
2408
2409 INT_CHECK("simfab 558");
2410 // reset for next cycle
2411 delta_menge = 0;
2412 }
2413 }
2414
2415 /// Knightly : advance arrival slot at calculated interval and recalculate boost where necessary
2416 delta_slot += delta_t;
2417 const sint32 periods = welt->get_settings().get_factory_arrival_periods();
2418 const sint32 slot_interval = (1 << (PERIOD_BITS - SLOT_BITS)) * periods;
2419 while( delta_slot>slot_interval ) {
2420 delta_slot -= slot_interval;
2421 const sint32 pax_result = arrival_stats_pax.advance_slot();
2422 if( pax_result&ARRIVALS_CHANGED || (periods>1 && pax_result&ACTIVE_SLOTS_INCREASED && arrival_stats_pax.get_active_slots()*periods>SLOT_COUNT ) ) {
2423 update_prodfactor_pax();
2424 }
2425 const sint32 mail_result = arrival_stats_mail.advance_slot();
2426 if( mail_result&ARRIVALS_CHANGED || (periods>1 && mail_result&ACTIVE_SLOTS_INCREASED && arrival_stats_mail.get_active_slots()*periods>SLOT_COUNT ) ) {
2427 update_prodfactor_mail();
2428 }
2429 }
2430 }
2431
2432
2433 class distribute_ware_t
2434 {
2435 public:
2436 ware_t ware; /// goods to be routed to consumer
2437 halthandle_t halt; /// potential start halt
2438 sint32 space_left; /// free space at halt
2439 sint32 amount_waiting; /// waiting goods at halt for same destination as ware
2440 private:
2441 sint32 ratio_free_space; /// ratio of free space at halt (=0 for overflowing station)
2442
2443 public:
distribute_ware_t(halthandle_t h,sint32 l,sint32 t,sint32 a,ware_t w)2444 distribute_ware_t( halthandle_t h, sint32 l, sint32 t, sint32 a, ware_t w )
2445 {
2446 halt = h;
2447 space_left = l;
2448 amount_waiting = a;
2449 ware = w;
2450 // ensure overfull stations compare equal allowing tie breaker clause (amount waiting)
2451 sint32 space_total = t > 0 ? t : 1;
2452 ratio_free_space = space_left > 0 ? ((sint64)space_left << fabrik_t::precision_bits) / space_total : 0;
2453 }
distribute_ware_t()2454 distribute_ware_t() {}
2455
compare(const distribute_ware_t & dw1,const distribute_ware_t & dw2)2456 static bool compare(const distribute_ware_t &dw1, const distribute_ware_t &dw2)
2457 {
2458 return (dw1.ratio_free_space > dw2.ratio_free_space)
2459 || (dw1.ratio_free_space == dw2.ratio_free_space && dw1.amount_waiting <= dw2.amount_waiting);
2460 }
2461 };
2462
2463
2464 /**
2465 * distribute stuff to all best destination
2466 * @author Hj. Malthaner
2467 */
verteile_waren(const uint32 product)2468 void fabrik_t::verteile_waren(const uint32 product)
2469 {
2470 // wohin liefern ?
2471 if( lieferziele.empty() ) {
2472 return;
2473 }
2474
2475 // not connected?
2476 const planquadrat_t *plan = welt->access(pos.get_2d());
2477 if( plan == NULL ) {
2478 dbg->fatal("fabrik_t::verteile_waren", "%s has not distribution target", get_name() );
2479 }
2480 if( plan->get_haltlist_count() == 0 ) {
2481 return;
2482 }
2483
2484 static vector_tpl<distribute_ware_t> dist_list(16);
2485 dist_list.clear();
2486
2487 // to distribute to all target equally, we use this counter, for the source hald, and target factory, to try first
2488 output[product].index_offset++;
2489
2490 /* prissi: distribute goods to factory
2491 * that has not an overflowing input storage
2492 * also prevent stops from overflowing, if possible
2493 * Since we can called with menge>max/2 are at least 10 are there, we must first limit the amount we distribute
2494 */
2495 //sint32 menge = min( (prodbase > 640 ? (prodbase>>6) : 10), output[product].menge >> precision_bits );
2496
2497 // We already know the distribution amount. However it has to be converted from factory units into real units.
2498 const uint32 prod_factor = desc->get_product(product)->get_factor();
2499 sint32 menge = (sint32)(((sint64)output[product].min_shipment * (sint64)(prod_factor)) >> (DEFAULT_PRODUCTION_FACTOR_BITS + precision_bits));
2500
2501 // ok, first generate list of possible destinations
2502 const halthandle_t *haltlist = plan->get_haltlist();
2503 for( unsigned i=0; i<plan->get_haltlist_count(); i++ ) {
2504 halthandle_t halt = haltlist[(i + output[product].index_offset) % plan->get_haltlist_count()];
2505
2506 if( !halt->get_ware_enabled() ) {
2507 continue;
2508 }
2509
2510 // �ber alle Ziele iterieren
2511 for( uint32 n=0; n<lieferziele.get_count(); n++ ) {
2512 // prissi: this way, the halt, that is tried first, will change. As a result, if all destinations are empty, it will be spread evenly
2513 const koord lieferziel = lieferziele[(n + output[product].index_offset) % lieferziele.get_count()];
2514 fabrik_t * ziel_fab = get_fab(lieferziel);
2515
2516 if( ziel_fab ) {
2517 const sint8 needed = ziel_fab->is_needed(output[product].get_typ());
2518 if( needed>=0 ) {
2519 ware_t ware(output[product].get_typ());
2520 ware.menge = menge;
2521 ware.to_factory = 1;
2522 ware.set_zielpos( lieferziel );
2523
2524 unsigned w;
2525 // find the index in the target factory
2526 for( w = 0; w < ziel_fab->get_input().get_count() && ziel_fab->get_input()[w].get_typ() != ware.get_desc(); w++ ) {
2527 // empty
2528 }
2529
2530 // if only overflown factories found => deliver to first
2531 // else deliver to non-overflown factory
2532 if( !(welt->get_settings().get_just_in_time() != 0) ) {
2533 // without production stop when target overflowing, distribute to least overflow target
2534 const sint32 fab_left = ziel_fab->get_input()[w].max - ziel_fab->get_input()[w].menge;
2535 dist_list.insert_ordered( distribute_ware_t( halt, fab_left, ziel_fab->get_input()[w].max, (sint32)halt->get_ware_fuer_zielpos(output[product].get_typ(),ware.get_zielpos()), ware ), distribute_ware_t::compare );
2536
2537 }
2538 else if( needed > 0 ) {
2539 // we are not overflowing: Station can only store up to a maximum amount of goods per square
2540 const sint32 halt_left = (sint32)halt->get_capacity(2) - (sint32)halt->get_ware_summe(ware.get_desc());
2541 dist_list.insert_ordered( distribute_ware_t( halt, halt_left, halt->get_capacity(2), (sint32)halt->get_ware_fuer_zielpos(output[product].get_typ(),ware.get_zielpos()), ware ), distribute_ware_t::compare );
2542 }
2543 }
2544 }
2545 }
2546 }
2547
2548 // Auswertung der Ergebnisse
2549 if( !dist_list.empty() ) {
2550 distribute_ware_t *best = NULL;
2551 FOR(vector_tpl<distribute_ware_t>, & i, dist_list) {
2552 // now search route
2553 int const result = haltestelle_t::search_route(&i.halt, 1U, welt->get_settings().is_no_routing_over_overcrowding(), i.ware);
2554 if( result == haltestelle_t::ROUTE_OK || result == haltestelle_t::ROUTE_WALK ) {
2555 // we can deliver to this destination
2556 best = &i;
2557 break;
2558 }
2559 }
2560
2561 if( best == NULL ) {
2562 return; // no route for any destination
2563 }
2564
2565 halthandle_t &best_halt = best->halt;
2566 ware_t &best_ware = best->ware;
2567
2568 // now process found route
2569 const sint32 space_left = (welt->get_settings().get_just_in_time() != 0 ) ? best->space_left : (sint32)best_halt->get_capacity(2) - (sint32)best_halt->get_ware_summe(best_ware.get_desc());
2570 menge = min( menge, 9 + space_left );
2571 // ensure amount is not negative ...
2572 if( menge<0 ) {
2573 menge = 0;
2574 }
2575 // since it is assigned here to an unsigned variable!
2576 best_ware.menge = menge;
2577
2578 if( space_left<0 ) {
2579 // find, what is most waiting here from us
2580 ware_t most_waiting(output[product].get_typ());
2581 most_waiting.menge = 0;
2582 FOR(vector_tpl<koord>, const& n, lieferziele) {
2583 uint32 const amount = best_halt->get_ware_fuer_zielpos(output[product].get_typ(), n);
2584 if( amount > most_waiting.menge ) {
2585 most_waiting.set_zielpos(n);
2586 most_waiting.menge = amount;
2587 }
2588 }
2589
2590 // we will reroute some goods
2591 if( best->amount_waiting==0 && most_waiting.menge>0 ) {
2592 // remove something from the most waiting goods
2593 if( best_halt->recall_ware( most_waiting, min((sint32)(most_waiting.menge/2), 1 - space_left) ) ) {
2594 best_ware.menge += most_waiting.menge;
2595 }
2596 else {
2597 // overcrowded with other stuff (not from us)
2598 return;
2599 }
2600
2601 // refund JIT2 demand buffers for rerouted goods
2602 if( welt->get_settings().get_just_in_time() >= 2 ) {
2603 // locate destination factory
2604 fabrik_t *fab = get_fab( most_waiting.get_zielpos() );
2605
2606 if( fab ) {
2607 for( uint32 input = 0; input < fab->input.get_count(); input++ ) {
2608 ware_production_t& w = fab->input[input];
2609 if ( w.get_typ()->get_index() == most_waiting.get_index() ) {
2610 // correct ware to refund found
2611
2612 // refund demand buffers, deactivating if required
2613 const uint32 prod_factor = fab->desc->get_supplier(input)->get_consumption();
2614 const sint32 prod_delta = (sint32)((((sint64)(most_waiting.menge) << (DEFAULT_PRODUCTION_FACTOR_BITS + precision_bits)) + (sint64)(prod_factor - 1)) / (sint64)prod_factor);
2615 const sint32 demand = w.demand_buffer;
2616 w.demand_buffer += prod_delta;
2617 if( demand < w.max && w.demand_buffer >= w.max ) {
2618 fab->inactive_demands++;
2619 }
2620 }
2621
2622 // refund successful
2623 break;
2624 }
2625 }
2626 }
2627 }
2628 else {
2629 // overflowed with our own ware and we have still nearly full stock
2630 // if( output[product].menge>= (3 * output[product].max) >> 2 ) {
2631 /* Station too full, notify player */
2632 // best_halt->bescheid_station_voll();
2633 // }
2634 // for now report only serious overcrowding on transfer stops
2635 return;
2636 }
2637 }
2638
2639 // Since menge might have been mutated, it must be converted back. This might introduce some error with some prod factors which is always rounded up.
2640 const sint32 prod_delta = (sint32)((((sint64)menge << (DEFAULT_PRODUCTION_FACTOR_BITS + precision_bits)) + (sint64)(prod_factor - 1)) / (sint64)prod_factor);
2641
2642 // If the output is inactive, reactivate it
2643 if( output[product].menge == output[product].max && prod_delta > 0 ) inactive_outputs-= 1;
2644
2645 output[product].menge -= prod_delta;
2646
2647 best_halt->starte_mit_route(best_ware);
2648 best_halt->recalc_status();
2649 fabrik_t::apply_transit( &best_ware );
2650 // add as active destination
2651 lieferziele_active_last_month |= (1 << lieferziele.index_of(best_ware.get_zielpos()));
2652 output[product].book_stat(best_ware.menge, FAB_GOODS_DELIVERED);
2653 }
2654 }
2655
2656
new_month()2657 void fabrik_t::new_month()
2658 {
2659 // calculate weighted averages
2660 if( aggregate_weight > 0 ) {
2661 set_stat( weighted_sum_production / aggregate_weight, FAB_PRODUCTION );
2662 set_stat( weighted_sum_boost_electric / aggregate_weight, FAB_BOOST_ELECTRIC );
2663 set_stat( weighted_sum_boost_pax / aggregate_weight, FAB_BOOST_PAX );
2664 set_stat( weighted_sum_boost_mail / aggregate_weight, FAB_BOOST_MAIL );
2665 set_stat( weighted_sum_power / aggregate_weight, FAB_POWER );
2666 }
2667
2668 // update statistics for input and output goods
2669 for( uint32 in = 0; in < input.get_count(); in++ ){
2670 input[in].roll_stats( desc->get_supplier(in)->get_consumption(), aggregate_weight );
2671 }
2672 for( uint32 out = 0; out < output.get_count(); out++ ){
2673 output[out].roll_stats( desc->get_product(out)->get_factor(), aggregate_weight );
2674 }
2675 lieferziele_active_last_month = 0;
2676
2677 // advance statistics a month
2678 for( int s = 0; s < MAX_FAB_STAT; ++s ) {
2679 for( int m = MAX_MONTH - 1; m > 0; --m ) {
2680 statistics[m][s] = statistics[m-1][s];
2681 }
2682 statistics[0][s] = 0;
2683 }
2684
2685 weighted_sum_production = 0;
2686 weighted_sum_boost_electric = 0;
2687 weighted_sum_boost_pax = 0;
2688 weighted_sum_boost_mail = 0;
2689 weighted_sum_power = 0;
2690 aggregate_weight = 0;
2691
2692 // restore the current values
2693 set_stat( get_current_production(), FAB_PRODUCTION );
2694 set_stat( prodfactor_electric, FAB_BOOST_ELECTRIC );
2695 set_stat( prodfactor_pax, FAB_BOOST_PAX );
2696 set_stat( prodfactor_mail, FAB_BOOST_MAIL );
2697 set_stat( get_power(), FAB_POWER );
2698
2699 // since target cities' population may be increased -> re-apportion pax/mail demand
2700 recalc_demands_at_target_cities();
2701 }
2702
2703
2704 // static !
2705 uint8 fabrik_t::status_to_color[5] = {COL_RED, COL_ORANGE, COL_GREEN, COL_YELLOW, COL_WHITE };
2706
2707 #define FL_WARE_NULL 1
2708 #define FL_WARE_ALLENULL 2
2709 #define FL_WARE_LIMIT 4
2710 #define FL_WARE_ALLELIMIT 8
2711 #define FL_WARE_UEBER75 16
2712 #define FL_WARE_ALLEUEBER75 32
2713 #define FL_WARE_FEHLT_WAS 64
2714
2715
2716 /* returns the status of the current factory, as well as output */
recalc_factory_status()2717 void fabrik_t::recalc_factory_status()
2718 {
2719 uint64 warenlager;
2720 char status_ein;
2721 char status_aus;
2722
2723 int haltcount=welt->access(pos.get_2d())->get_haltlist_count();
2724
2725 // set bits for input
2726 warenlager = 0;
2727 total_transit = 0;
2728 status_ein = FL_WARE_ALLELIMIT;
2729 uint32 i = 0;
2730 FOR( array_tpl<ware_production_t>, const& j, input ) {
2731 if( j.menge >= j.max ) {
2732 status_ein |= FL_WARE_LIMIT;
2733 }
2734 else {
2735 status_ein &= ~FL_WARE_ALLELIMIT;
2736 }
2737 warenlager+= (uint64)j.menge * (uint64)(desc->get_supplier(i++)->get_consumption());
2738 total_transit += j.get_in_transit();
2739 if( (j.menge >> fabrik_t::precision_bits) == 0 ) {
2740 status_ein |= FL_WARE_FEHLT_WAS;
2741 }
2742
2743 }
2744 warenlager >>= fabrik_t::precision_bits + DEFAULT_PRODUCTION_FACTOR_BITS;
2745 if( warenlager==0 ) {
2746 status_ein |= FL_WARE_ALLENULL;
2747 }
2748 total_input = (uint32)warenlager;
2749
2750 // one ware missing, but producing
2751 if( status_ein & FL_WARE_FEHLT_WAS && !output.empty() && haltcount > 0 ) {
2752 status = bad;
2753 return;
2754 }
2755
2756 // set bits for output
2757 warenlager = 0;
2758 status_aus = FL_WARE_ALLEUEBER75|FL_WARE_ALLENULL;
2759 i = 0;
2760 FOR( array_tpl<ware_production_t>, const& j, output ) {
2761 if( j.menge > 0 ) {
2762
2763 status_aus &= ~FL_WARE_ALLENULL;
2764 if( j.menge >= 0.75 * j.max ) {
2765 status_aus |= FL_WARE_UEBER75;
2766 }
2767 else {
2768 status_aus &= ~FL_WARE_ALLEUEBER75;
2769 }
2770 warenlager += (uint64)j.menge * (uint64)(desc->get_product(i)->get_factor());
2771 status_aus &= ~FL_WARE_ALLENULL;
2772 }
2773 else {
2774 // menge = 0
2775 status_aus &= ~FL_WARE_ALLEUEBER75;
2776 }
2777 }
2778 warenlager >>= fabrik_t::precision_bits + DEFAULT_PRODUCTION_FACTOR_BITS;
2779 total_output = (uint32)warenlager;
2780
2781 // now calculate status bar
2782 if( input.empty() ) {
2783 // does not consume anything, should just produce
2784
2785 if( output.empty() ) {
2786 // does also not produce anything
2787 status = nothing;
2788 }
2789 else if( status_aus&FL_WARE_ALLEUEBER75 || status_aus&FL_WARE_UEBER75 ) {
2790 status = inactive; // not connected?
2791 if(haltcount>0) {
2792 if(status_aus&FL_WARE_ALLEUEBER75) {
2793 status = bad; // connect => needs better service
2794 }
2795 else {
2796 status = medium; // connect => needs better service for at least one product
2797 }
2798 }
2799 }
2800 else {
2801 status = good;
2802 }
2803 }
2804 else if( output.empty() ) {
2805 // nothing to produce
2806
2807 if(status_ein&FL_WARE_ALLELIMIT) {
2808 // we assume not served
2809 status = bad;
2810 }
2811 else if(status_ein&FL_WARE_LIMIT) {
2812 // served, but still one at limit
2813 status = medium;
2814 }
2815 else if(status_ein&FL_WARE_ALLENULL) {
2816 status = inactive; // assume not served
2817 if(haltcount>0) {
2818 // there is a halt => needs better service
2819 status = bad;
2820 }
2821 }
2822 else {
2823 status = good;
2824 }
2825 }
2826 else {
2827 // produces and consumes
2828 if((status_ein&FL_WARE_ALLELIMIT)!=0 && (status_aus&FL_WARE_ALLEUEBER75)!=0) {
2829 status = bad;
2830 }
2831 else if((status_ein&FL_WARE_ALLELIMIT)!=0 || (status_aus&FL_WARE_ALLEUEBER75)!=0) {
2832 status = medium;
2833 }
2834 else if((status_ein&FL_WARE_ALLENULL)!=0 && (status_aus&FL_WARE_ALLENULL)!=0) {
2835 // not producing
2836 status = inactive;
2837 }
2838 else if(haltcount>0 && ((status_ein&FL_WARE_ALLENULL)!=0 || (status_aus&FL_WARE_ALLENULL)!=0)) {
2839 // not producing but out of supply
2840 status = medium;
2841 }
2842 else {
2843 status = good;
2844 }
2845 }
2846 }
2847
2848
open_info_window()2849 void fabrik_t::open_info_window()
2850 {
2851 gebaeude_t *gb = welt->lookup(pos)->find<gebaeude_t>();
2852 create_win(new fabrik_info_t(this, gb), w_info, (ptrdiff_t)this );
2853 }
2854
2855
info_prod(cbuffer_t & buf) const2856 void fabrik_t::info_prod(cbuffer_t& buf) const
2857 {
2858 buf.clear();
2859 buf.append( translator::translate("Durchsatz") );
2860 buf.append(get_current_production(), 0);
2861 buf.append( translator::translate("units/day") );
2862 buf.append("\n");
2863 buf.printf(translator::translate("Produces: %.1f units/minute"),
2864 get_production_per_second() * 60.0
2865 );
2866
2867 if (!output.empty()) {
2868 buf.append("\n\n");
2869 buf.append(translator::translate("Produktion"));
2870
2871 for (uint32 index = 0; index < output.get_count(); index++) {
2872 goods_desc_t const *const type = output[index].get_typ();
2873 sint64 const pfactor = (sint64)desc->get_product(index)->get_factor();
2874
2875 buf.append("\n - ");
2876 if( welt->get_settings().get_just_in_time() >= 2 ) {
2877 double const pfraction = (double)pfactor / (double)DEFAULT_PRODUCTION_FACTOR;
2878 double const storage_unit = (double)(1 << fabrik_t::precision_bits);
2879 buf.printf(translator::translate("%s %.0f%% : %.0f/%.0f @ %.1f%%"),
2880 translator::translate(type->get_name()),
2881 pfraction * 100.0,
2882 (double)output[index].menge * pfraction / storage_unit,
2883 (double)output[index].max * pfraction / storage_unit,
2884 (double)output[index].calculate_output_production_rate() * 100.0 / (double)(1 << 16)
2885 );
2886 }
2887 else {
2888 buf.printf("%s %u/%u%s",
2889 translator::translate(type->get_name()),
2890 (uint32)((FAB_DISPLAY_UNIT_HALF + (sint64)output[index].menge * pfactor) >> (fabrik_t::precision_bits + DEFAULT_PRODUCTION_FACTOR_BITS)),
2891 (uint32)((FAB_DISPLAY_UNIT_HALF + (sint64)output[index].max * pfactor) >> (fabrik_t::precision_bits + DEFAULT_PRODUCTION_FACTOR_BITS)),
2892 translator::translate(type->get_mass())
2893 );
2894
2895 if(type->get_catg() != 0) {
2896 buf.append(", ");
2897 buf.append(translator::translate(type->get_catg_name()));
2898 }
2899
2900 buf.printf(", %u%%", (uint32)((FAB_PRODFACT_UNIT_HALF + (sint32)pfactor * 100) >> DEFAULT_PRODUCTION_FACTOR_BITS));
2901 }
2902 }
2903 }
2904
2905 if (!input.empty()) {
2906 buf.append("\n\n");
2907 buf.append(translator::translate("Verbrauch"));
2908
2909 for (uint32 index = 0; index < input.get_count(); index++) {
2910 sint64 const pfactor = (sint64)desc->get_supplier(index)->get_consumption();
2911
2912 buf.append("\n - ");
2913 if( welt->get_settings().get_just_in_time() >= 2 ) {
2914 double const pfraction = (double)pfactor / (double)DEFAULT_PRODUCTION_FACTOR;
2915 double const storage_unit = (double)(1 << fabrik_t::precision_bits);
2916 buf.printf(translator::translate("%s %.0f%% : %.0f+%u/%.0f @ %.1f%%"),
2917 translator::translate(input[index].get_typ()->get_name()),
2918 pfraction * 100.0,
2919 (double)input[index].menge * pfraction / storage_unit,
2920 (uint32)input[index].get_in_transit(),
2921 (double)input[index].max * pfraction / storage_unit,
2922 (double)input[index].calculate_demand_production_rate() * 100.0 / (double)(1 << 16)
2923 );
2924 }
2925 else if( welt->get_settings().get_factory_maximum_intransit_percentage() ) {
2926 buf.printf("%s %u/%i(%i)/%u%s, %u%%",
2927 translator::translate(input[index].get_typ()->get_name()),
2928 (uint32)((FAB_DISPLAY_UNIT_HALF + (sint64)input[index].menge * pfactor) >> (fabrik_t::precision_bits + DEFAULT_PRODUCTION_FACTOR_BITS)),
2929 input[index].get_in_transit(),
2930 input[index].max_transit,
2931 (uint32)((FAB_DISPLAY_UNIT_HALF + (sint64)input[index].max * pfactor) >> (fabrik_t::precision_bits + DEFAULT_PRODUCTION_FACTOR_BITS)),
2932 translator::translate(input[index].get_typ()->get_mass()),
2933 (uint32)((FAB_PRODFACT_UNIT_HALF + (sint32)pfactor * 100) >> DEFAULT_PRODUCTION_FACTOR_BITS)
2934 );
2935 }
2936 else {
2937 buf.printf("%s %u/%i/%u%s, %u%%",
2938 translator::translate(input[index].get_typ()->get_name()),
2939 (uint32)((FAB_DISPLAY_UNIT_HALF + (sint64)input[index].menge * pfactor) >> (fabrik_t::precision_bits + DEFAULT_PRODUCTION_FACTOR_BITS)),
2940 input[index].get_in_transit(),
2941 (uint32)((FAB_DISPLAY_UNIT_HALF + (sint64)input[index].max * pfactor) >> (fabrik_t::precision_bits + DEFAULT_PRODUCTION_FACTOR_BITS)),
2942 translator::translate(input[index].get_typ()->get_mass()),
2943 (uint32)((FAB_PRODFACT_UNIT_HALF + (sint32)pfactor * 100) >> DEFAULT_PRODUCTION_FACTOR_BITS)
2944 );
2945 }
2946 }
2947 }
2948 }
2949
2950
info_conn(cbuffer_t & buf) const2951 void fabrik_t::info_conn(cbuffer_t& buf) const
2952 {
2953 buf.clear();
2954 const planquadrat_t *plan = welt->access(get_pos().get_2d());
2955 if(plan && plan->get_haltlist_count()>0) {
2956 buf.append(translator::translate("Connected stops"));
2957
2958 for( uint i=0; i<plan->get_haltlist_count(); i++ ) {
2959 buf.printf("\n - %s", plan->get_haltlist()[i]->get_name() );
2960 }
2961 }
2962 }
2963
2964
finish_rd()2965 void fabrik_t::finish_rd()
2966 {
2967 // adjust production base to be at least as large as fields productivity
2968 uint32 prodbase_adjust = 1;
2969 const field_group_desc_t *fd = desc->get_field_group();
2970 if(fd) {
2971 for(uint32 i=0; i<fields.get_count(); i++) {
2972 const field_class_desc_t *fc = fd->get_field_class( fields[i].field_class_index );
2973 if (fc) {
2974 prodbase_adjust += fc->get_field_production();
2975 }
2976 }
2977 }
2978
2979 // set production, update all production related numbers
2980 set_base_production( max(prodbase, prodbase_adjust) );
2981
2982 // now we have a valid storage limit
2983 if( welt->get_settings().is_crossconnect_factories() ) {
2984 FOR( slist_tpl<fabrik_t*>, const fab, welt->get_fab_list() ) {
2985 fab->add_supplier(this);
2986 }
2987 }
2988 else {
2989 // add as supplier to target(s)
2990 for(uint32 i=0; i<lieferziele.get_count(); i++) {
2991 fabrik_t * fab2 = fabrik_t::get_fab(lieferziele[i]);
2992 if(fab2) {
2993 fab2->add_supplier(pos.get_2d());
2994 lieferziele[i] = fab2->get_pos().get_2d();
2995 }
2996 else {
2997 // remove this ...
2998 dbg->warning( "fabrik_t::finish_rd()", "No factory at expected position %s!", lieferziele[i].get_str() );
2999 lieferziele.remove_at(i);
3000 i--;
3001 }
3002 }
3003 }
3004
3005 // Now rebuild input/output activity information.
3006 if( welt->get_settings().get_just_in_time() >= 2 ){
3007 inactive_inputs = inactive_outputs = inactive_demands = 0;
3008 for( uint32 in = 0; in < input.get_count(); in++ ){
3009 if( input[in].menge > input[in].max ) {
3010 input[in].menge = input[in].max;
3011 }
3012 input[in].placing_orders = (input[in].demand_buffer > 0);
3013
3014 // Also do a sanity check. People might try and force their saves to JIT2 mode via reloading so we need to catch any massive values.
3015 if( welt->get_settings().get_just_in_time() >= 2 && welt->get_settings().get_factory_maximum_intransit_percentage() != 0 ){
3016 const sint32 demand_minmax = (sint32)((sint64)input[in].max * (sint64)welt->get_settings().get_factory_maximum_intransit_percentage() / (sint64)100);
3017 if( input[in].demand_buffer < (-demand_minmax) ) {
3018 input[in].demand_buffer = -demand_minmax;
3019 }
3020 else if( input[in].demand_buffer > (input[in].max + demand_minmax) ) {
3021 input[in].demand_buffer = input[in].max;
3022 }
3023 }
3024 }
3025 for( uint32 out = 0 ; out < output.get_count() ; out++ ){
3026 if( output[out].menge >= output[out].max ) {
3027 output[out].menge = output[out].max;
3028 }
3029 }
3030
3031 rebuild_inactive_cache();
3032 }
3033 else {
3034 // Classic order logic.
3035 for( uint32 in = 0; in < input.get_count(); in++ ){
3036 input[in].placing_orders = (input[in].menge < input[in].max && input[in].get_in_transit() < input[in].max_transit);
3037 }
3038 }
3039
3040 // set initial power boost
3041 if ( boost_type == BL_POWER ) {
3042 prodfactor_electric = get_jit2_power_boost();
3043 }
3044 }
3045
3046
rotate90(const sint16 y_size)3047 void fabrik_t::rotate90( const sint16 y_size )
3048 {
3049 rotate = (rotate+3)%desc->get_building()->get_all_layouts();
3050 pos_origin.rotate90( y_size );
3051 pos_origin.x -= desc->get_building()->get_x(rotate)-1;
3052 pos.rotate90( y_size );
3053
3054 FOR(vector_tpl<koord>, & i, lieferziele) {
3055 i.rotate90(y_size);
3056 }
3057 FOR(vector_tpl<koord>, & i, suppliers) {
3058 i.rotate90(y_size);
3059 }
3060 FOR(vector_tpl<field_data_t>, & i, fields) {
3061 i.location.rotate90(y_size);
3062 }
3063 }
3064
3065
add_supplier(koord ziel)3066 void fabrik_t::add_supplier(koord ziel)
3067 {
3068 // Updated maximum in-transit. Only used for classic support.
3069 if( welt->get_settings().get_factory_maximum_intransit_percentage() && !suppliers.is_contained(ziel) && welt->get_settings().get_just_in_time() < 2 ) {
3070 if( fabrik_t *fab = get_fab( ziel ) ) {
3071 for( uint32 i=0; i < fab->get_output().get_count(); i++ ) {
3072 const ware_production_t &w_out = fab->get_output()[i];
3073 // now update transit limits
3074 FOR( array_tpl<ware_production_t>, &w, input ) {
3075 if( w_out.get_typ() == w.get_typ() ) {
3076 #ifdef TRANSIT_DISTANCE
3077 sint64 distance = koord_distance( fab->get_pos(), get_pos() );
3078 // calculate next mean by the following formula: average + (next - average)/(n+1)
3079 w.count_suppliers ++;
3080 sint64 next = 1 + ( distance * welt->get_settings().get_factory_maximum_intransit_percentage() * (w.max >> fabrik_t::precision_bits) ) / 131072;
3081 w.max_transit += (next - w.max_transit)/(w.count_suppliers);
3082 #else
3083 const sint32 max_storage = (sint32)(1 + ( ((sint64)w_out.max * (sint64)welt->get_settings().get_factory_maximum_intransit_percentage() ) >> fabrik_t::precision_bits) / 100);
3084 const sint32 old_max_transit = w.max_transit;
3085 w.max_transit += max_storage;
3086 if( w.max_transit < old_max_transit ) {
3087 // we have overflown, so we use the max value
3088 w.max_transit = 0x7fffffff;
3089 }
3090 #endif
3091 break;
3092 }
3093 }
3094 }
3095 // since there could be more than one good, we have to iterate over all of them
3096 }
3097 }
3098 suppliers.insert_unique_ordered( ziel, RelativeDistanceOrdering(pos.get_2d()) );
3099 }
3100
3101
rem_supplier(koord pos)3102 void fabrik_t::rem_supplier(koord pos)
3103 {
3104 suppliers.remove(pos);
3105
3106 // Updated maximum in-transit. Only used for classic support.
3107 if( welt->get_settings().get_factory_maximum_intransit_percentage() && welt->get_settings().get_just_in_time() < 2 ) {
3108 // set to zero
3109 FOR( array_tpl<ware_production_t>, &w, input ) {
3110 w.max_transit = 0;
3111 }
3112
3113 // unfourtunately we have to bite the bullet and recalc the values from scratch ...
3114 FOR( vector_tpl<koord>, ziel, suppliers ) {
3115 if( fabrik_t *fab = get_fab( ziel ) ) {
3116 for( uint32 i=0; i < fab->get_output().get_count(); i++ ) {
3117 const ware_production_t &w_out = fab->get_output()[i];
3118 // now update transit limits
3119 FOR( array_tpl<ware_production_t>, &w, input ) {
3120 if( w_out.get_typ() == w.get_typ() ) {
3121 #ifdef TRANSIT_DISTANCE
3122 sint64 distance = koord_distance( fab->get_pos(), get_pos() );
3123 // calculate next mean by the following formula: average + (next - average)/(n+1)
3124 w.count_suppliers ++;
3125 sint64 next = 1 + ( distance * welt->get_settings().get_factory_maximum_intransit_percentage() * (w.max >> fabrik_t::precision_bits) ) / 131072;
3126 w.max_transit += (next - w.max_transit)/(w.count_suppliers);
3127 #else
3128 const sint32 max_storage = (sint32)(1 + ( ((sint64)w_out.max * (sint64)welt->get_settings().get_factory_maximum_intransit_percentage() ) >> fabrik_t::precision_bits) / 100);
3129 const sint32 old_max_transit = w.max_transit;
3130 w.max_transit += max_storage;
3131 if( w.max_transit < old_max_transit ) {
3132 // we have overflown, so we use the max value
3133 w.max_transit = 0x7fffffff;
3134 }
3135 #endif
3136 break;
3137 }
3138 }
3139 }
3140 // since there could be more than one good, we have to iterate over all of them
3141 }
3142 }
3143 }
3144 }
3145
3146
3147 /** crossconnect everything possible */
add_all_suppliers()3148 void fabrik_t::add_all_suppliers()
3149 {
3150 for(int i=0; i < desc->get_supplier_count(); i++) {
3151 const factory_supplier_desc_t *supplier = desc->get_supplier(i);
3152 const goods_desc_t *ware = supplier->get_input_type();
3153
3154 FOR(slist_tpl<fabrik_t*>, const fab, welt->get_fab_list()) {
3155 // connect to an existing one, if this is an producer
3156 if(fab!=this && fab->vorrat_an(ware) > -1) {
3157 // add us to this factory
3158 // will also add to our suppliers list
3159 fab->add_lieferziel(pos.get_2d());
3160 }
3161 }
3162 }
3163 }
3164
3165
3166 /* adds a new supplier to this factory
3167 * fails if no matching goods are there
3168 */
add_supplier(fabrik_t * fab)3169 bool fabrik_t::add_supplier(fabrik_t* fab)
3170 {
3171 for(int i=0; i < desc->get_supplier_count(); i++) {
3172 const factory_supplier_desc_t *supplier = desc->get_supplier(i);
3173 const goods_desc_t *ware = supplier->get_input_type();
3174
3175 // connect to an existing one, if this is an producer
3176 if( fab!=this && fab->vorrat_an(ware) > -1 ) {
3177 // add us to this factory
3178 fab->add_lieferziel(pos.get_2d());
3179 return true;
3180 }
3181 }
3182 return false;
3183 }
3184
3185
get_tile_list(vector_tpl<koord> & tile_list) const3186 void fabrik_t::get_tile_list( vector_tpl<koord> &tile_list ) const
3187 {
3188 tile_list.clear();
3189
3190 koord pos_2d = pos.get_2d();
3191 koord size = this->get_desc()->get_building()->get_size(this->get_rotate());
3192 koord test;
3193 // Which tiles belong to the fab?
3194 for( test.x = 0; test.x < size.x; test.x++ ) {
3195 for( test.y = 0; test.y < size.y; test.y++ ) {
3196 if( fabrik_t::get_fab( pos_2d+test ) == this ) {
3197 tile_list.append( pos_2d+test );
3198 }
3199 }
3200 }
3201 }
3202
3203 // Returns a list of goods produced by this factory. The caller must delete
3204 // the list when done
get_produced_goods() const3205 slist_tpl<const goods_desc_t*> *fabrik_t::get_produced_goods() const
3206 {
3207 slist_tpl<const goods_desc_t*> *goods = new slist_tpl<const goods_desc_t*>();
3208
3209 FOR(array_tpl<ware_production_t>, const& i, output) {
3210 goods->append(i.get_typ());
3211 }
3212
3213 return goods;
3214 }
3215
rebuild_inactive_cache()3216 void fabrik_t::rebuild_inactive_cache()
3217 {
3218 inactive_inputs = inactive_outputs = inactive_demands = 0;
3219
3220 for( uint32 i = 0; i < input.get_count(); i++ ){
3221 if( input[i].menge <= 0 ) {
3222 inactive_inputs++;
3223 }
3224 if( input[i].demand_buffer >= input[i].max ) {
3225 inactive_demands++;
3226 }
3227 }
3228
3229 for( uint32 i = 0 ; i < output.get_count() ; i++ ){
3230 if( output[i].menge >= output[i].max ) {
3231 inactive_outputs++;
3232 }
3233 }
3234 }
3235
get_production_per_second() const3236 double fabrik_t::get_production_per_second() const {
3237 return (double)prodbase * (double)get_prodfactor() / (double)DEFAULT_PRODUCTION_FACTOR / (double)DEFAULT_PRODUCTION_FACTOR;
3238 }
3239
calculate_work_rate_ramp(sint32 const amount,sint32 const minimum,sint32 const maximum,uint32 const precision)3240 sint32 fabrik_t::calculate_work_rate_ramp(sint32 const amount, sint32 const minimum, sint32 const maximum, uint32 const precision)
3241 {
3242 sint32 production_rate;
3243 if( minimum >= maximum || minimum >= amount ) {
3244 // full production
3245 production_rate = 1 << precision;
3246 }
3247 else if( amount < maximum ) {
3248 // reduction production
3249 production_rate = (sint32)(((sint64)(maximum - amount) << precision) / (sint64)(maximum - minimum));
3250 // apply work factor minimum limit
3251 if( production_rate < WORK_SCALE_MINIMUM_FRACTION ){
3252 production_rate = WORK_SCALE_MINIMUM_FRACTION;
3253 }
3254 }
3255 else {
3256 // no production
3257 production_rate = 0;
3258 }
3259 return production_rate;
3260 }
3261