1
#include "utils/simstring.h"
2
#include "dataobj/translator.h"
3
#include "dataobj/loadsave.h"
7
#include "player/simplay.h"
8
#include "vehicle/simvehikel.h"
10
#include "convoihandle_t.h"
12
#include "simlinemgmt.h"
15
uint8 simline_t::convoi_to_line_catgory[MAX_CONVOI_COST] = {
16
LINE_CAPACITY, LINE_TRANSPORTED_GOODS, LINE_REVENUE, LINE_OPERATIONS, LINE_PROFIT, LINE_DISTANCE
19
karte_t *simline_t::welt=NULL;
22
simline_t::simline_t(karte_t* welt, spieler_t* sp, linetype type)
24
self = linehandle_t(this);
26
sprintf( printname, "(%i) %s", self.get_id(), translator::translate("Line",welt->get_einstellungen()->get_name_language_id()) );
29
init_financial_history();
35
state_color = COL_YELLOW;
40
simline_t::simline_t(karte_t* welt, spieler_t* sp, linetype type, loadsave_t *file)
42
// id will be read and assigned during rdwr
43
self = linehandle_t();
50
// now self has the right id but the this-pointer is not assigned to the quickstone handle yet
52
self = linehandle_t(this, self.get_id());
56
simline_t::~simline_t()
58
DBG_DEBUG("simline_t::~simline_t()", "deleting fpl=%p", fpl);
60
assert(count_convoys()==0);
65
DBG_MESSAGE("simline_t::~simline_t()", "line %d (%p) destroyed", self.get_id(), this);
69
void simline_t::create_schedule()
72
case simline_t::truckline: set_schedule(new autofahrplan_t()); break;
73
case simline_t::trainline: set_schedule(new zugfahrplan_t()); break;
74
case simline_t::shipline: set_schedule(new schifffahrplan_t()); break;
75
case simline_t::airline: set_schedule(new airfahrplan_t()); break;
76
case simline_t::monorailline: set_schedule(new monorailfahrplan_t()); break;
77
case simline_t::tramline: set_schedule(new tramfahrplan_t()); break;
78
case simline_t::maglevline: set_schedule(new maglevfahrplan_t()); break;
79
case simline_t::narrowgaugeline: set_schedule(new narrowgaugefahrplan_t()); break;
81
dbg->fatal( "simline_t::create_schedule()", "Cannot create default schedule!" );
86
void simline_t::add_convoy(convoihandle_t cnv)
88
if (line_managed_convoys.empty()) {
89
// first convoi -> ok, now we can announce this connection to the stations
93
// first convoi may change line type
94
if (type == trainline && line_managed_convoys.empty() && cnv.is_bound()) {
95
// check, if needed to convert to tram/monorail line
96
if (vehikel_t const* const v = cnv->front()) {
97
switch (v->get_besch()->get_waytype()) {
98
case tram_wt: type = simline_t::tramline; break;
99
// elevated monorail were saved with wrong coordinates for some versions.
100
// We try to recover here
101
case monorail_wt: type = simline_t::monorailline; break;
106
// only add convoy if not already member of line
107
line_managed_convoys.append_unique(cnv);
109
// what goods can this line transport?
110
bool update_schedules = false;
111
if( cnv->get_state()!=convoi_t::INITIAL ) {
112
const minivec_tpl<uint8> &convoys_goods = cnv->get_goods_catg_index();
113
for( uint8 i = 0; i < convoys_goods.get_count(); i++ ) {
114
const uint8 catg_index = convoys_goods[i];
115
if( !goods_catg_index.is_contained( catg_index ) ) {
116
goods_catg_index.append( catg_index, 1 );
117
update_schedules = true;
123
financial_history[0][LINE_CONVOIS] = count_convoys();
126
// do we need to tell the world about our new schedule?
127
if( update_schedules ) {
128
welt->set_schedule_counter();
134
void simline_t::remove_convoy(convoihandle_t cnv)
136
if(line_managed_convoys.is_contained(cnv)) {
137
line_managed_convoys.remove(cnv);
139
financial_history[0][LINE_CONVOIS] = count_convoys();
142
if(line_managed_convoys.empty()) {
147
// invalid line id prior to 110.0
148
#define INVALID_LINE_ID_OLD ((uint16)(-1))
149
// invalid line id from 110.0 on
150
#define INVALID_LINE_ID ((uint16)(0))
152
void simline_t::rdwr_linehandle_t(loadsave_t *file, linehandle_t &line)
155
if (file->is_saving()) {
156
id = line.is_bound() ? line.get_id(): (file->get_version() < 110000 ? INVALID_LINE_ID_OLD : INVALID_LINE_ID);
158
if(file->get_version()<88003) {
160
file->rdwr_long(dummy);
164
file->rdwr_short(id);
166
if (file->is_loading()) {
167
// invalid line_id's: 0 and 65535
168
if (id == INVALID_LINE_ID_OLD) {
176
void simline_t::rdwr(loadsave_t *file)
178
xml_tag_t s( file, "simline_t" );
182
if( file->is_loading() ) {
184
file->rdwr_str(name, lengthof(name));
189
tstrncpy( name, this->name.c_str(), lengthof(name) );
190
file->rdwr_str(name, lengthof(name));
193
rdwr_linehandle_t(file, self);
198
if( file->get_version()<=102002 ) {
199
for (int j = 0; j<6; j++) {
200
for (int k = MAX_MONTHS-1; k>=0; k--) {
201
file->rdwr_longlong(financial_history[k][j]);
204
for (int k = MAX_MONTHS-1; k>=0; k--) {
205
financial_history[k][LINE_DISTANCE] = 0;
209
for (int j = 0; j<MAX_LINE_COST; j++) {
210
for (int k = MAX_MONTHS-1; k>=0; k--) {
211
file->rdwr_longlong(financial_history[k][j]);
216
if(file->get_version()>=102002) {
217
file->rdwr_bool(withdraw);
220
// otherwise inintialized to zero if loading ...
221
financial_history[0][LINE_CONVOIS] = count_convoys();
226
void simline_t::laden_abschliessen()
228
if( line_managed_convoys.get_count()>0 ) {
236
void simline_t::register_stops(schedule_t * fpl)
238
DBG_DEBUG("simline_t::register_stops()", "%d fpl entries in schedule %p", fpl->get_count(),fpl);
239
for (int i = 0; i<fpl->get_count(); i++) {
240
const halthandle_t halt = haltestelle_t::get_halt( welt, fpl->eintrag[i].pos, sp );
241
if(halt.is_bound()) {
242
//DBG_DEBUG("simline_t::register_stops()", "halt not null");
243
halt->add_line(self);
246
DBG_DEBUG("simline_t::register_stops()", "halt null");
253
void simline_t::unregister_stops()
255
unregister_stops(fpl);
260
void simline_t::unregister_stops(schedule_t * fpl)
262
for (int i = 0; i<fpl->get_count(); i++) {
263
halthandle_t halt = haltestelle_t::get_halt( welt, fpl->eintrag[i].pos, sp );
264
if(halt.is_bound()) {
265
halt->remove_line(self);
272
void simline_t::renew_stops()
274
if( line_managed_convoys.get_count()>0 ) {
275
register_stops( fpl );
276
DBG_DEBUG("simline_t::renew_stops()", "Line id=%d, name='%s'", self.get_id(), name.c_str());
282
void simline_t::new_month()
285
for (int j = 0; j<MAX_LINE_COST; j++) {
286
for (int k = MAX_MONTHS-1; k>0; k--) {
287
financial_history[k][j] = financial_history[k-1][j];
289
financial_history[0][j] = 0;
291
financial_history[0][LINE_CONVOIS] = count_convoys();
295
void simline_t::init_financial_history()
297
MEMZERO(financial_history);
303
* the current state saved as color
304
* Meanings are BLACK (ok), WHITE (no convois), YELLOW (no vehicle moved), RED (last month income minus), BLUE (at least one convoi vehicle is obsolete)
306
void simline_t::recalc_status()
308
if(financial_history[0][LINE_CONVOIS]==0) {
309
// noconvois assigned to this line
310
state_color = COL_WHITE;
313
else if(financial_history[0][LINE_PROFIT]<0) {
314
// ok, not performing best
315
state_color = COL_RED;
316
} else if((financial_history[0][LINE_OPERATIONS]|financial_history[1][LINE_OPERATIONS])==0) {
318
state_color = COL_YELLOW;
320
else if(welt->use_timeline()) {
321
// convois has obsolete vehicles?
322
bool has_obsolete = false;
323
for(unsigned i=0; !has_obsolete && i<line_managed_convoys.get_count(); i++ ) {
324
has_obsolete = line_managed_convoys[i]->has_obsolete_vehicles();
326
// now we have to set it
327
state_color = has_obsolete ? COL_DARK_BLUE : COL_BLACK;
331
state_color = COL_BLACK;
337
// recalc what good this line is moving
338
void simline_t::recalc_catg_index()
341
minivec_tpl<uint8> old_goods_catg_index(goods_catg_index.get_count());
342
for( uint i=0; i<goods_catg_index.get_count(); i++ ) {
343
old_goods_catg_index.append( goods_catg_index[i] );
345
goods_catg_index.clear();
346
withdraw = line_managed_convoys.get_count()>0;
347
// then recreate current
348
for(unsigned i=0; i<line_managed_convoys.get_count(); i++ ) {
349
// what goods can this line transport?
350
// const convoihandle_t cnv = line_managed_convoys[i];
351
const convoi_t *cnv = line_managed_convoys[i].get_rep();
352
withdraw &= cnv->get_withdraw();
354
const minivec_tpl<uint8> &convoys_goods = cnv->get_goods_catg_index();
355
for( uint8 i = 0; i < convoys_goods.get_count(); i++ ) {
356
const uint8 catg_index = convoys_goods[i];
357
goods_catg_index.append_unique( catg_index, 1 );
360
// if different => schedule need recalculation
361
if( goods_catg_index.get_count()!=old_goods_catg_index.get_count() ) {
363
welt->set_schedule_counter();
366
// maybe changed => must test all entries
367
for( uint i=0; i<goods_catg_index.get_count(); i++ ) {
368
if( !old_goods_catg_index.is_contained(goods_catg_index[i]) ) {
369
// different => recalc
370
welt->set_schedule_counter();
379
void simline_t::set_withdraw( bool yes_no )
381
withdraw = yes_no && (line_managed_convoys.get_count()>0);
382
// convois in depots will be immeadiately destroyed, thus we go backwards
383
for( sint32 i=line_managed_convoys.get_count()-1; i>=0; i-- ) {
384
line_managed_convoys[i]->set_no_load(yes_no); // must be first, since set withdraw might destroy convoi if in depot!
385
line_managed_convoys[i]->set_withdraw(yes_no);