diff --git a/Makefile b/Makefile
index 8c209448650..c3a9db3d43d 100644
--- a/Makefile
+++ b/Makefile
@@ -144,6 +144,7 @@ SOURCES += besch/reader/way_reader.cc
SOURCES += besch/reader/xref_reader.cc
SOURCES += besch/sound_besch.cc
SOURCES += besch/tunnel_besch.cc
+SOURCES += besch/vehikel_besch.cc
SOURCES += besch/ware_besch.cc
SOURCES += boden/boden.cc
SOURCES += boden/brueckenboden.cc
@@ -204,6 +205,8 @@ SOURCES += gui/colors.cc
SOURCES += gui/components/gui_button.cc
SOURCES += gui/components/gui_chart.cc
SOURCES += gui/components/gui_combobox.cc
+SOURCES += gui/components/gui_convoy_assembler.cc
+SOURCES += gui/components/gui_convoy_label.cc
SOURCES += gui/components/gui_flowtext.cc
SOURCES += gui/components/gui_image_list.cc
SOURCES += gui/components/gui_label.cc
@@ -261,6 +264,7 @@ SOURCES += gui/money_frame.cc
SOURCES += gui/optionen.cc
SOURCES += gui/pakselector.cc
SOURCES += gui/player_frame_t.cc
+SOURCES += gui/replace_frame.cc
SOURCES += gui/savegame_frame.cc
SOURCES += gui/scenario_frame.cc
SOURCES += gui/schedule_list.cc
diff --git a/Simutrans-Experimental.sln b/Simutrans-Experimental.sln
new file mode 100644
index 00000000000..f521e11686b
--- /dev/null
+++ b/Simutrans-Experimental.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual C++ Express 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Simutrans-Experimental", "Simutrans-Experimental.vcproj", "{0621B295-BEB7-4767-82F1-F27995610323}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {0621B295-BEB7-4767-82F1-F27995610323}.Debug|Win32.ActiveCfg = Debug|Win32
+ {0621B295-BEB7-4767-82F1-F27995610323}.Debug|Win32.Build.0 = Debug|Win32
+ {0621B295-BEB7-4767-82F1-F27995610323}.Release|Win32.ActiveCfg = Release|Win32
+ {0621B295-BEB7-4767-82F1-F27995610323}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/Simutrans-Experimental.vcproj b/Simutrans-Experimental.vcproj
new file mode 100644
index 00000000000..10a2524790c
--- /dev/null
+++ b/Simutrans-Experimental.vcproj
@@ -0,0 +1,2357 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Simutrans.sln b/Simutrans.sln
index f94aa531a2e..8bfb66f0f41 100644
--- a/Simutrans.sln
+++ b/Simutrans.sln
@@ -1,6 +1,6 @@

-Microsoft Visual Studio Solution File, Format Version 9.00
-# Visual C++ Express 2005
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual C++ Express 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Simutrans", "Simutrans.vcproj", "{0621B295-BEB7-4767-82F1-F27995610323}"
EndProject
Global
@@ -18,4 +18,3 @@ Global
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
-
diff --git a/Simutrans.vcproj b/Simutrans.vcproj
index 78855cf06a3..9785e20916b 100644
--- a/Simutrans.vcproj
+++ b/Simutrans.vcproj
@@ -1,11 +1,12 @@
-
@@ -152,6 +152,8 @@
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
TargetMachine="1"
/>
-
diff --git a/bauer/brueckenbauer.cc b/bauer/brueckenbauer.cc
index dee3a449eb4..607b04016c8 100644
--- a/bauer/brueckenbauer.cc
+++ b/bauer/brueckenbauer.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997 - 2001 Hj. Malthaner
+ * Copyright (c) 1997 - 2001 Hansjörg Malthaner
*
* This file is part of the Simutrans project under the artistic licence.
* (see licence.txt)
@@ -172,8 +172,8 @@ void brueckenbauer_t::fill_menu(werkzeug_waehler_t *wzw, const waytype_t wtyp, c
koord3d brueckenbauer_t::finde_ende(karte_t *welt, koord3d pos, koord zv, const bruecke_besch_t *besch, const char *&error_msg, bool ai_bridge )
{
- const grund_t *gr1; // on the level of the bridge
- const grund_t *gr2; // the level under the bridge
+ const grund_t *gr1; // auf Brückenebene
+ const grund_t *gr2; // unter Brückenebene
waytype_t wegtyp = besch->get_waytype();
leitung_t *lt;
error_msg = NULL;
@@ -194,43 +194,27 @@ koord3d brueckenbauer_t::finde_ende(karte_t *welt, koord3d pos, koord zv, const
}
// check for height
sint16 height = pos.z -welt->lookup_kartenboden(pos.get_2d())->get_hoehe();
- if(besch->get_max_height()!=0 && height>besch->get_max_height()) {
+ if(besch->get_max_height()!=0 && height>besch->get_max_height() ) {
error_msg = "bridge is too high for its type!";
return koord3d::invalid;
}
- // and if ground is above bridge / double slopes
- if (height<-Z_TILE_STEP){
- break; // to trigger the right error message
- }
+
gr1 = welt->lookup(pos + koord3d(0, 0, Z_TILE_STEP));
if( gr1 && gr1->get_weg_hang()==hang_t::flach ) {
if( gr1->get_typ()==grund_t::boden ) {
// on slope ok, but not on other bridges
- if( gr1->has_two_ways() ) {
- // crossing => then we must be sure we have our way in our direction
- const weg_t* weg = gr1->get_weg(wegtyp);
- if( ribi_t::ist_gerade(ribi_typ(zv)|weg->get_ribi_unmasked()) ) {
- // way goes in our direction already
- return gr1->get_pos();
- }
- }
- else {
- // no or one way
- const weg_t* weg = gr1->get_weg_nr(0);
- if( weg==NULL || weg->get_waytype()==wegtyp
- || (crossing_logic_t::get_crossing(wegtyp, weg->get_waytype()) && (ribi_typ(zv)&weg->get_ribi_unmasked())==0)
- ) {
- return gr1->get_pos();
- }
- }
+ return gr1->get_pos();
}
else if( gr1->get_typ()==grund_t::monorailboden ) {
// check if we can connect ro elevated way
- if( gr1->hat_weg(wegtyp) ) {
+ const weg_t* weg = gr1->get_weg_nr(0);
+ if( weg==NULL || weg->get_waytype()==wegtyp
+// || (crossing_logic_t::get_crossing(wegtyp, weg->get_waytype()))
+// || (wegtyp==powerline_wt)
+ ) {
return gr1->get_pos();
}
}
- // invalid ground in its way => while loop will finish
}
gr2 = welt->lookup(pos);
if(gr2 && (gr2->get_typ()==grund_t::boden || gr2->get_typ()==grund_t::monorailboden)) {
@@ -259,27 +243,27 @@ koord3d brueckenbauer_t::finde_ende(karte_t *welt, koord3d pos, koord zv, const
}
if(gr2->get_typ()==grund_t::boden && !gr2->get_halt().is_bound()) {
if(ribi_t::ist_einfach(ribi) && koord(ribi) == zv) {
- // end with ramp, end way is already built
+ // Ende mit Rampe - Endschiene vorhanden
return pos;
}
if(ribi==ribi_t::keine && wegtyp!=powerline_wt && gr2->hat_weg(wegtyp)) {
- // end with ramp, end way is already built but ribi's are missing
+ // Ende mit Rampe - Endschiene hat keine ribis
return pos;
}
if(ribi==ribi_t::keine && wegtyp==powerline_wt && gr2->suche_obj(ding_t::leitung)) {
- // end with ramp, end way is already built but ribi's are missing - for powerlines
+ // Ende mit Rampe - Endschiene hat keine ribis
return pos;
}
}
}
else {
if(ribi_t::ist_einfach(ribi) && koord(ribi) == zv) {
- // end on slope with way
+ // Ende am Hang - Endschiene vorhanden
return pos;
}
if(!ribi && gr2->get_grund_hang()==hang_typ(zv)) {
- // end on slope, way (or ribi) is missing
- // check if another way is blocking us
+ // Ende am Hang - Endschiene fehlt oder hat keine ribis
+ // Wir prüfen noch, ob uns dort ein anderer Weg stört
if(wegtyp!=powerline_wt && (!gr2->hat_wege() || gr2->hat_weg(wegtyp))) {
return pos;
}
@@ -289,8 +273,8 @@ koord3d brueckenbauer_t::finde_ende(karte_t *welt, koord3d pos, koord zv, const
}
}
}
- } while(!gr1 && // no bridge is crossing
- (!gr2 || gr2->get_grund_hang()==hang_t::flach || gr2->get_hoehe()get_grund_hang()==hang_t::flach || gr2->get_hoehe()get_typ()!=grund_t::boden && gr->get_typ()!=grund_t::monorailboden) {
return false;
}
- if( gr->ist_uebergang() || ( gr->hat_wege() && gr->get_leitung() ) ) {
+ if(gr->ist_uebergang()) {
return false;
}
ding_t *d=gr->obj_bei(0);
@@ -392,7 +376,8 @@ const char *brueckenbauer_t::baue( karte_t *welt, spieler_t *sp, koord pos, cons
}
zv = koord(ribi_t::rueckwaerts(ribi));
- // search for suitable bridge end tile
+ // Brückenende suchen
+ // "Bridge End Search" (Google)
const char *msg;
koord3d end = finde_ende(welt, gr->get_pos(), zv, besch, msg );
@@ -406,10 +391,21 @@ DBG_MESSAGE("brueckenbauer_t::baue()", "end not ok");
if(gr_end->kann_alle_obj_entfernen(sp)) {
return "Tile not empty.";
}
+
+ if(!sp->can_afford(besch->get_preis()))
+ {
+ return "That would exceed\nyour credit limit.";
+ }
+
// Anfang und ende sind geprueft, wir konnen endlich bauen
- if(powerbridge) {
+ // "Beginning and end are approved, we can finally build" (Google)
+ if(powerbridge)
+ {
baue_bruecke(welt, sp, gr->get_pos(), end, zv, besch, wegbauer_t::leitung_besch );
- } else {
+ }
+
+ else
+ {
baue_bruecke(welt, sp, gr->get_pos(), end, zv, besch, weg->get_besch() );
}
return NULL;
@@ -469,7 +465,7 @@ void brueckenbauer_t::baue_bruecke(karte_t *welt, spieler_t *sp, koord3d pos, ko
// must determine end tile: on a slope => likely need auffahrt
bool need_auffahrt = (pos.z==end.z);
- if(need_auffahrt) {
+ if(need_auffahrt) { //"Need ramp" (Google)
grund_t *gr = welt->lookup(end);
weg_t *w = gr->get_weg( (waytype_t)weg_besch->get_wtyp());
if(w) {
@@ -502,7 +498,7 @@ void brueckenbauer_t::baue_bruecke(karte_t *welt, spieler_t *sp, koord3d pos, ko
spieler_t::accounting(sp, -wegbauer_t::leitung_besch->get_preis(), gr->get_pos().get_2d(), COST_CONSTRUCTION);
gr->obj_add(lt);
}
- lt->calc_neighbourhood();
+ lt->calc_neighbourhood();
}
}
}
@@ -520,8 +516,7 @@ void brueckenbauer_t::baue_auffahrt(karte_t* welt, spieler_t* sp, koord3d end, k
if(grund_hang == hang_t::flach) {
weg_hang = hang_typ(zv); // nordhang - suedrampe
}
-
- bruecke = new brueckenboden_t(welt, end, grund_hang, weg_hang);
+ bruecke = new brueckenboden_t(welt, end, grund_hang, weg_hang);
// add the ramp
if(bruecke->get_grund_hang() == hang_t::flach) {
img = besch->get_rampe(ribi_neu);
@@ -544,10 +539,12 @@ void brueckenbauer_t::baue_auffahrt(karte_t* welt, spieler_t* sp, koord3d end, k
bruecke->neuen_weg_bauen( weg, ribi_neu, sp );
}
weg->set_max_speed( besch->get_topspeed() );
+ weg->set_max_weight( besch->get_max_weight() );
+ weg->add_way_constraints(besch->get_way_constraints_permissive(), besch->get_way_constraints_prohibitive());
} else {
leitung_t *lt = bruecke->get_leitung();
if(!lt) {
- lt = new leitung_t(welt, bruecke->get_pos(), sp);
+ lt = new leitung_t(welt, bruecke->get_pos(), sp); //"leading" (Google)
bruecke->obj_add( lt );
} else {
// remove maintainance
@@ -555,6 +552,7 @@ void brueckenbauer_t::baue_auffahrt(karte_t* welt, spieler_t* sp, koord3d end, k
}
lt->laden_abschliessen();
}
+
bruecke_t *br = new bruecke_t(welt, end, sp, besch, img);
bruecke->obj_add( br );
br->laden_abschliessen();
@@ -572,6 +570,8 @@ const char *brueckenbauer_t::remove(karte_t *welt, spieler_t *sp, koord3d pos, w
slist_tpl tmp_list;
const char *msg;
+ // Erstmal das ganze Außmaß der Brücke bestimmen und sehen,
+ // ob uns was im Weg ist.
tmp_list.insert(pos);
marker.markiere(welt->lookup(pos));
waytype_t delete_wegtyp = wegtyp==powerline_wt ? invalid_wt : wegtyp;
@@ -585,7 +585,8 @@ const char *brueckenbauer_t::remove(karte_t *welt, spieler_t *sp, koord3d pos, w
koord zv = koord::invalid;
if(from->ist_karten_boden()) {
- // gr is start/end - test only one direction
+ // Der Grund ist Brückenanfang/-ende - hier darf nur in
+ // eine Richtung getestet werden.
if(from->get_grund_hang() != hang_t::flach) {
zv = koord(hang_t::gegenueber(from->get_grund_hang()));
}
@@ -597,14 +598,14 @@ const char *brueckenbauer_t::remove(karte_t *welt, spieler_t *sp, koord3d pos, w
else if(from->ist_bruecke()) {
part_list.insert(pos);
}
- // can we delete everything there?
+ // Alle Brückenteile auf Entfernbarkeit prüfen!
msg = from->kann_alle_obj_entfernen(sp);
if(msg != NULL || (from->get_halt().is_bound() && from->get_halt()->get_besitzer()!=sp)) {
return "Die Bruecke ist nicht frei!\n";
}
- // search neighbors
+ // Nachbarn raussuchen
for(int r = 0; r < 4; r++) {
if( (zv == koord::invalid || zv == koord::nsow[r]) && from->get_neighbour(to, delete_wegtyp, koord::nsow[r]) && !marker.ist_markiert(to) && to->ist_bruecke() ) {
tmp_list.insert(to->get_pos());
@@ -613,7 +614,7 @@ const char *brueckenbauer_t::remove(karte_t *welt, spieler_t *sp, koord3d pos, w
}
} while (!tmp_list.empty());
- // now delete the bridge
+ // Jetzt geht es ans löschen der Brücke
while (!part_list.empty()) {
pos = part_list.remove_first();
@@ -640,7 +641,7 @@ const char *brueckenbauer_t::remove(karte_t *welt, spieler_t *sp, koord3d pos, w
delete p;
}
}
- // finally delete the bridge ends
+ // Und die Brückenenden am Schluß
while (!end_list.empty()) {
pos = end_list.remove_first();
diff --git a/bauer/fabrikbauer.cc b/bauer/fabrikbauer.cc
index 30d7777643b..348a6a92a27 100644
--- a/bauer/fabrikbauer.cc
+++ b/bauer/fabrikbauer.cc
@@ -66,9 +66,13 @@ void init_fab_map( karte_t *welt )
for( int i=0; iget_groesse_y(); i++ ) {
fab_map[i] = 0;
}
- slist_iterator_tpl iter(welt->get_fab_list());
- while(iter.next()) {
- add_factory_to_fab_map( welt, iter.get_current() );
+ //slist_iterator_tpl iter(welt->get_fab_list());
+ //vector_tpl factories = welt->get_fab_list();
+ for(sint16 i = welt->get_fab_list().get_count() - 1; i >= 0; i --)
+ {
+ //while(iter.next()) {
+ //add_factory_to_fab_map( welt, iter.get_current() );
+ add_factory_to_fab_map( welt, welt->get_fab_list()[i] );
}
}
@@ -371,6 +375,7 @@ void fabrikbauer_t::verteile_tourist(karte_t* welt, int max_number)
/**
* baue fabrik nach Angaben in info
+ * "build the factory, according to info" (Google)
* @author Hj.Malthaner
*/
fabrik_t* fabrikbauer_t::baue_fabrik(karte_t* welt, koord3d* parent, const fabrik_besch_t* info, int rotate, koord3d pos, spieler_t* spieler)
@@ -500,7 +505,8 @@ int fabrikbauer_t::baue_hierarchie(koord3d* parent, const fabrik_besch_t* info,
pos->rotate90( welt->get_groesse_y()-info->get_haus()->get_h(rotate) );
welt->rotate90();
}
- assert( !welt->cannot_save() );
+ bool can_save = !welt->cannot_save();
+ assert( can_save );
}
// intown needs different place search
@@ -520,6 +526,13 @@ int fabrikbauer_t::baue_hierarchie(koord3d* parent, const fabrik_besch_t* info,
// Das könnte ein Zeitproblem geben, wenn eine Stadt keine solchen Bauplatz
// hat und die Suche bis zur nächsten Stadt weiterläuft
// Ansonsten erscheint mir das am realistischtsten..
+
+ /* Three variants:
+ * A:
+ * A building site, preferably close to the town hall with a street next to it.
+ * This could be a temporary problem, if a city has no such site and the search until
+ * the next city continues Otherwise seems to me the most realistic Google)*/
+
bool is_rotate=info->get_haus()->get_all_layouts()>1;
k = factory_bauplatz_mit_strasse_sucher_t(welt).suche_platz(sf.stadt->get_pos(), size.x, size.y, info->get_haus()->get_allowed_climate_bits(), &is_rotate);
rotate = is_rotate?1:0;
@@ -529,13 +542,21 @@ int fabrikbauer_t::baue_hierarchie(koord3d* parent, const fabrik_besch_t* info,
// B:
// Gefällt mir auch. Die Endfabriken stehen eventuell etwas außerhalb der Stadt
// aber nicht weit weg.
+
+ // Pleases me also. The final factories stand possibly somewhat outside of the city however not far away. (Babelfish)
// (does not obey climates though!)
+
// k = finde_zufallsbauplatz(welt, welt->lookup(sf.stadt->get_pos())->get_boden()->get_pos(), 3, land_bau.dim).get_2d();
// C:
// Ein Bauplatz, möglichst nah am Rathaus.
// Wenn mehrere Endfabriken bei einer Stadt landen, sind die oft hinter
// einer Reihe Häuser "versteckt", von Strassen abgeschnitten.
+
+ // A building site, as near as possible at the city hall.
+ // If several final factories land with a city, often behind
+ // a row the houses are hidden, of roads cut off.(Babelfish)
+
//k = bauplatz_sucher_t(welt).suche_platz(sf.stadt->get_pos(), land_bau.dim.x, land_bau.dim.y, info->get_haus()->get_allowed_climate_bits(), &is_rotate);
if(k != koord::invalid) {
@@ -612,18 +633,22 @@ int fabrikbauer_t::baue_link_hierarchie(const fabrik_t* our_fab, const fabrik_be
DBG_MESSAGE("fabrikbauer_t::baue_hierarchie","lieferanten %i, lcount %i (need %i of %s)",info->get_lieferanten(),lcount,verbrauch,ware->get_name());
// Hajo: search if there already is one or two (crossconnect everything if possible)
- const slist_tpl & list = welt->get_fab_list();
- slist_iterator_tpl iter (list);
+ //const slist_tpl & list = welt->get_fab_list();
+ const vector_tpl & list = welt->get_fab_list();
+ //slist_iterator_tpl iter (list);
bool found = false;
- while( iter.next() &&
+ //while( iter.next() &&
+ for(sint16 i = list.get_count() - 1; (i >= 0) && ( (lcount==0 && verbrauch>0) || (lcount>=lfound+1) ); i --)
+ {
// try to find matching factories for this consumption
- ( (lcount==0 && verbrauch>0) ||
+ //( (lcount==0 && verbrauch>0) ||
// but don't find more than two times number of factories requested
- (lcount>=lfound+1) )
- )
- {
- fabrik_t * fab = iter.get_current();
+ //(lcount>=lfound+1) )
+ //)
+ //{
+ //fabrik_t * fab = iter.get_current();
+ fabrik_t * fab = list[i];
// connect to an existing one, if this is an producer
if(fab->vorrat_an(ware) > -1) {
@@ -815,9 +840,12 @@ int fabrikbauer_t::increase_industry_density( karte_t *welt, bool tell_me )
// find last consumer
if(!welt->get_fab_list().empty()) {
- slist_iterator_tpl iter (welt->get_fab_list());
- while(iter.next()) {
- fabrik_t *fab = iter.get_current();
+ //slist_iterator_tpl iter (welt->get_fab_list());
+ //while(iter.next()) {
+ for(sint16 i = welt->get_fab_list().get_count() - 1; i >= 0; i --)
+ {
+ //fabrik_t *fab = iter.get_current();
+ fabrik_t *fab = welt->get_fab_list()[i];
if(fab->get_besch()->get_produkte()==0) {
last_built_consumer = fab;
break;
@@ -876,9 +904,13 @@ int fabrikbauer_t::increase_industry_density( karte_t *welt, bool tell_me )
uint32 total_produktivity = 1;
uint32 electric_productivity = 0;
- slist_iterator_tpl iter (welt->get_fab_list());
- while(iter.next()) {
- fabrik_t * fab = iter.get_current();
+ //slist_iterator_tpl iter (welt->get_fab_list());
+ //vector_tpl factories = welt->get_fab_list();
+ //while(iter.next()) {
+ for(sint16 i = welt->get_fab_list().get_count() - 1; i >= 0; i --)
+ {
+ //fabrik_t * fab = iter.get_current();
+ fabrik_t * fab = welt->get_fab_list()[i];
if(fab->get_besch()->is_electricity_producer()) {
electric_productivity += fab->get_base_production();
}
diff --git a/bauer/hausbauer.cc b/bauer/hausbauer.cc
index e66da22a9bc..6230364eeff 100644
--- a/bauer/hausbauer.cc
+++ b/bauer/hausbauer.cc
@@ -37,6 +37,7 @@
/*
* Die verschiedenen Gebäudegruppen sind in eigenen Listen gesammelt.
+ * The various groups are building their own lists collected.
*/
static vector_tpl wohnhaeuser;
static vector_tpl gewerbehaeuser;
@@ -49,6 +50,7 @@ slist_tpl hausbauer_t::ungebaute_denkmaeler;
/*
* Diese Tabelle ermöglicht das Auffinden einer Beschreibung durch ihren Namen
+ * This table allows you to find a description by its name
*/
static stringhashtable_tpl besch_names;
@@ -223,7 +225,7 @@ void hausbauer_t::neue_karte()
-void hausbauer_t::remove( karte_t *welt, spieler_t *sp, gebaeude_t *gb )
+void hausbauer_t::remove( karte_t *welt, spieler_t *sp, gebaeude_t *gb ) //gebaeude = "building" (Babelfish)
{
const haus_tile_besch_t *tile = gb->get_tile();
const haus_besch_t *hb = tile->get_besch();
@@ -718,6 +720,7 @@ const haus_besch_t* hausbauer_t::get_wohnhaus(int level, uint16 time, climate cl
// get a random object
const haus_besch_t *hausbauer_t::waehle_aus_liste(slist_tpl &liste, uint16 time, bool ignore_retire, climate cl)
{
+ //"select from list" (Google)
if (!liste.empty()) {
// previously just returned a random object; however, now we do als look at the chance entry
weighted_vector_tpl auswahl(16);
diff --git a/bauer/tunnelbauer.cc b/bauer/tunnelbauer.cc
index 4af2f56a9da..9901d339e4f 100644
--- a/bauer/tunnelbauer.cc
+++ b/bauer/tunnelbauer.cc
@@ -261,15 +261,23 @@ const char *tunnelbauer_t::baue( karte_t *welt, spieler_t *sp, koord pos, const
}
}
+ if(!sp->can_afford(besch->get_preis()))
+ {
+ return "That would exceed\nyour credit limit.";
+ }
+
// pruefe ob Tunnel auf strasse/schiene endet
+ // "examine whether the tunnel on road / rail ends" (Google)
if(!welt->ist_in_kartengrenzen(end.get_2d())) {
return "Tunnel must start on single way!";
}
// Anfang und ende sind geprueft, wir konnen endlich bauen
+ // "examine whether the tunnel on road / rail ends" (Google)
if(!baue_tunnel(welt, sp, gr->get_pos(), end, zv, besch)) {
return "Ways not connected";
}
+
return NULL;
}
@@ -288,8 +296,8 @@ DBG_MESSAGE("tunnelbauer_t::baue()","build from (%d,%d,%d) to (%d,%d,%d) ", pos.
// now we seach a matchin way for the tunnels top speed
const weg_besch_t *weg_besch = besch->get_weg_besch();
if(weg_besch==NULL) {
- // now we seach a matchin wy for the tunnels top speed
- weg_besch = wegbauer_t::weg_search( wegtyp, besch->get_topspeed(), welt->get_timeline_year_month(), weg_t::type_flat );
+ // now we seach a matching way for the tunnels top speed
+ weg_besch = wegbauer_t::weg_search( wegtyp, besch->get_topspeed(), besch->get_max_weight(), welt->get_timeline_year_month(), weg_t::type_flat );
}
const weg_besch_t *einfahrt_weg_besch = baue_einfahrt(welt, sp, pos, zv, besch, NULL, cost);
@@ -308,6 +316,9 @@ DBG_MESSAGE("tunnelbauer_t::baue()","build from (%d,%d,%d) to (%d,%d,%d) ", pos.
weg->set_besch(weg_besch);
weg->set_max_speed(besch->get_topspeed());
welt->access(pos.get_2d())->boden_hinzufuegen(tunnel);
+ weg->set_max_weight(besch->get_max_weight());
+ weg->add_way_constraints(besch->get_way_constraints_permissive(), besch->get_way_constraints_prohibitive());
+
tunnel->neuen_weg_bauen(weg, ribi_t::doppelt(ribi), sp);
tunnel->obj_add(new tunnel_t(welt, pos, sp, besch));
assert(!tunnel->ist_karten_boden());
@@ -327,7 +338,9 @@ DBG_MESSAGE("tunnelbauer_t::baue()","build from (%d,%d,%d) to (%d,%d,%d) ", pos.
weg->set_besch(weg_besch);
weg->set_max_speed(besch->get_topspeed());
welt->access(pos.get_2d())->boden_hinzufuegen(tunnel);
+ weg->set_max_weight(besch->get_max_weight());
tunnel->neuen_weg_bauen(weg, ribi, sp);
+ weg->add_way_constraints(besch->get_way_constraints_permissive(), besch->get_way_constraints_prohibitive());
tunnel->obj_add(new tunnel_t(welt, pos, sp, besch));
assert(!tunnel->ist_karten_boden());
spieler_t::add_maintenance( sp, -weg->get_besch()->get_wartung() );
@@ -367,6 +380,8 @@ const weg_besch_t *tunnelbauer_t::baue_einfahrt(karte_t *welt, spieler_t *sp, ko
}
spieler_t::add_maintenance( sp, -weg->get_besch()->get_wartung() );
weg->set_max_speed( besch->get_topspeed() );
+ weg->set_max_weight( besch->get_max_weight() );
+ weg->add_way_constraints(besch->get_way_constraints_permissive(), besch->get_way_constraints_prohibitive());
tunnel->calc_bild();
if(sp!=NULL) {
@@ -429,7 +444,8 @@ tunnelbauer_t::remove(karte_t *welt, spieler_t *sp, koord3d start, waytype_t weg
}
} while (!tmp_list.empty());
- assert(!end_list.empty());
+ bool end_list_empty = !end_list.empty();
+ assert(end_list_empty);
// Jetzt geht es ans löschen der Tunnel
while (!part_list.empty()) {
diff --git a/bauer/vehikelbauer.cc b/bauer/vehikelbauer.cc
index 19659bf73c5..9bd246f9729 100644
--- a/bauer/vehikelbauer.cc
+++ b/bauer/vehikelbauer.cc
@@ -147,7 +147,7 @@ sint32 vehikelbauer_t::get_speedbonus( sint32 monthyear, waytype_t wt )
-vehikel_t* vehikelbauer_t::baue(koord3d k, spieler_t* sp, convoi_t* cnv, const vehikel_besch_t* vb )
+vehikel_t* vehikelbauer_t::baue(koord3d k, spieler_t* sp, convoi_t* cnv, const vehikel_besch_t* vb, bool upgrade )
{
vehikel_t* v;
switch (vb->get_waytype()) {
@@ -164,7 +164,15 @@ vehikel_t* vehikelbauer_t::baue(koord3d k, spieler_t* sp, convoi_t* cnv, const v
dbg->fatal("vehikelbauer_t::baue()", "cannot built a vehicle with waytype %i", vb->get_waytype());
}
- sp->buche(-(sint32)vb->get_preis(), k.get_2d(), COST_NEW_VEHICLE );
+ if(upgrade)
+ {
+ sp->buche(-(sint32)vb->get_upgrade_price(), k.get_2d(), COST_NEW_VEHICLE );
+ }
+ else
+ {
+ sp->buche(-(sint32)vb->get_preis(), k.get_2d(), COST_NEW_VEHICLE );
+ }
+
sp->buche( (sint32)vb->get_preis(), COST_ASSETS );
return v;
diff --git a/bauer/vehikelbauer.h b/bauer/vehikelbauer.h
index 9ae06985fa8..b77a21c659e 100644
--- a/bauer/vehikelbauer.h
+++ b/bauer/vehikelbauer.h
@@ -27,6 +27,9 @@ template class vector_tpl;
* Baut Fahrzeuge. Fahrzeuge sollten nicht direct instanziiert werden
* sondern immer von einem vehikelbauer_t erzeugt werden.
*
+ * Builds vehicles. Vehicles should not be instantiated directly,
+ * but always from a vehikelbauer_t produced. (Google)
+ *
* @author Hj. Malthaner
*/
class vehikelbauer_t
@@ -38,7 +41,12 @@ class vehikelbauer_t
static bool register_besch(const vehikel_besch_t *besch);
static bool alles_geladen();
- static vehikel_t* baue(koord3d k, spieler_t* sp, convoi_t* cnv, const vehikel_besch_t* vb );
+ static vehikel_t* baue(koord3d k, spieler_t* sp, convoi_t* cnv, const vehikel_besch_t* vb )
+ {
+ return baue(k, sp, cnv, vb, false);
+ }
+
+ static vehikel_t* baue(koord3d k, spieler_t* sp, convoi_t* cnv, const vehikel_besch_t* vb, bool upgrade );
static const vehikel_besch_t * get_info(const char *name);
static slist_tpl* get_info(waytype_t typ);
diff --git a/bauer/warenbauer.h b/bauer/warenbauer.h
index 7183c01d837..3059543d8f8 100644
--- a/bauer/warenbauer.h
+++ b/bauer/warenbauer.h
@@ -15,7 +15,7 @@ class ware_besch_t;
/**
* Factory-Klasse fuer Waren.
- *
+ * "Factory class for goods" (Google)
* @author Hj. Malthaner
*/
class warenbauer_t
@@ -36,7 +36,7 @@ class warenbauer_t
static const ware_besch_t *passagiere;
static const ware_besch_t *post;
- static const ware_besch_t *nichts;
+ static const ware_besch_t *nichts; //"Nothing".
static bool alles_geladen();
static bool register_besch(ware_besch_t *besch);
@@ -48,6 +48,9 @@ class warenbauer_t
* Beschreibung davon zurück. Gibt NULL zurück wenn die
* Ware nicht bekannt ist.
*
+ * Searches for information on software 'name' and gives
+ * the description of it back. Returns NULL if the product is not known.
+ *
* @param name der nicht-übersetzte Warenname
* @author Hj. Malthaner/V. Meyer
*/
diff --git a/bauer/wegbauer.cc b/bauer/wegbauer.cc
index 5615be07a6b..2bb89b76596 100644
--- a/bauer/wegbauer.cc
+++ b/bauer/wegbauer.cc
@@ -144,6 +144,39 @@ const weg_besch_t* wegbauer_t::weg_search(const waytype_t wtyp, const uint32 spe
return best;
}
+// Finds a way with a given speed *and* weight limit
+// for a given way type.
+// @author: jamespetts (slightly adapted from the standard version with just speed limit)
+const weg_besch_t* wegbauer_t::weg_search(const waytype_t wtyp, const uint32 speed_limit, const uint32 weight_limit, const uint16 time, const weg_t::system_type system_type)
+{
+ const weg_besch_t* best = NULL;
+ for( stringhashtable_iterator_tpl iter(alle_wegtypen); iter.next(); )
+ {
+ const weg_besch_t* const test = iter.get_current_value();
+ if( ((test->get_wtyp()==wtyp &&
+ (test->get_styp()==system_type || system_type==weg_t::type_all)) || (test->get_wtyp()==track_wt && test->get_styp()==weg_t::type_tram && wtyp==tram_wt))
+ && test->get_cursor()->get_bild_nr(1)!=IMG_LEER )
+ {
+ if( best==NULL || time==0 || (test->get_intro_year_month()<=time && timeget_retire_year_month()))
+ {
+ if( best == NULL ||
+ ((best->get_topspeed() < speed_limit && test->get_topspeed() >= speed_limit) ||
+ (best->get_max_weight() < weight_limit && test->get_max_weight() >= weight_limit)) ||
+ ((test->get_topspeed() <= speed_limit && best->get_topspeed() < test->get_topspeed()) ||
+ (((test->get_max_weight() <= weight_limit && best->get_max_weight() < test->get_max_weight())))) ||
+ ((best->get_topspeed() > speed_limit && test->get_topspeed() < best->get_topspeed()) ||
+ ((best->get_max_weight() > weight_limit && test->get_max_weight()) < best->get_max_weight())) ||
+ (time != 0 && (best->get_intro_year_month()>time || time>=best->get_retire_year_month()))
+ )
+ {
+ best = test;
+ }
+ }
+ }
+ }
+ return best;
+}
+
const weg_besch_t * wegbauer_t::get_besch(const char * way_name,const uint16 time)
@@ -1712,9 +1745,10 @@ wegbauer_t::baue_tunnelboden()
tunnel->neuen_weg_bauen(weg, calc_ribi(i), sp);
tunnel->obj_add(new tunnel_t(welt, route[i], sp, tunnel_besch));
weg->set_max_speed(tunnel_besch->get_topspeed());
+ weg->set_max_weight(tunnel_besch->get_max_weight());
+ weg->add_way_constraints(besch->get_way_constraints_permissive(), besch->get_way_constraints_prohibitive());
tunnel->calc_bild();
cost -= tunnel_besch->get_preis();
- spieler_t::add_maintenance( sp, -weg->get_besch()->get_wartung());
spieler_t::add_maintenance( sp, tunnel_besch->get_wartung() );
}
else if(gr->get_typ()==grund_t::tunnelboden) {
@@ -1733,6 +1767,7 @@ wegbauer_t::baue_tunnelboden()
tunnel->set_besch(tunnel_besch);
weg->set_besch(wb);
weg->set_max_speed(tunnel_besch->get_topspeed());
+ weg->set_max_weight(tunnel_besch->get_max_weight());
gr->calc_bild();
cost -= tunnel_besch->get_preis();
diff --git a/bauer/wegbauer.h b/bauer/wegbauer.h
index ca3508a9a8c..3d8a74e6aa2 100644
--- a/bauer/wegbauer.h
+++ b/bauer/wegbauer.h
@@ -44,7 +44,9 @@ class wegbauer_t
* Finds a way with a given speed limit for a given waytype
* @author prissi
*/
- static const weg_besch_t * weg_search(const waytype_t wtyp,const uint32 speed_limit,const uint16 time, const weg_t::system_type system_type);
+ static const weg_besch_t * weg_search(const waytype_t wtyp,const uint32 speed_limit, const uint16 time, const weg_t::system_type system_type);
+
+ static const weg_besch_t * weg_search(const waytype_t wtyp,const uint32 speed_limit, const uint32 weight_limit, const uint16 time, const weg_t::system_type system_type);
static const weg_besch_t * get_besch(const char *way_name,const uint16 time=0);
diff --git a/besch/bruecke_besch.h b/besch/bruecke_besch.h
index 6bcb41eca49..4e33682b8bd 100644
--- a/besch/bruecke_besch.h
+++ b/besch/bruecke_besch.h
@@ -45,6 +45,7 @@ class bruecke_besch_t : public obj_besch_std_name_t {
uint8 max_length; // =0 off, else maximum length
uint8 max_height; // =0 off, else maximum length
+ uint32 max_weight; //@author: jamespetts. Weight limit for vehicles.
// allowed eara
uint16 intro_date;
@@ -53,6 +54,12 @@ class bruecke_besch_t : public obj_besch_std_name_t {
/* number of seasons (0 = none, 1 = no snow/snow
*/
sint8 number_seasons;
+
+ /*Way constraints for, e.g., loading gauges, types of electrification, etc.
+ * @author: jamespetts*/
+ uint8 way_constraints_permissive;
+ uint8 way_constraints_prohibitive;
+
public:
/*
* Nummerierung all der verschiedenen Schienstücke
@@ -108,6 +115,12 @@ class bruecke_besch_t : public obj_besch_std_name_t {
*/
uint32 get_topspeed() const { return topspeed; }
+ /**
+ * Determines max weight in tonnes for vehicles allowed on this bridge
+ * @author jamespetts
+ */
+ uint32 get_max_weight() const { return max_weight; }
+
/**
* Distance of pillars (=0 for no pillars)
* @author prissi
@@ -143,6 +156,26 @@ class bruecke_besch_t : public obj_besch_std_name_t {
* @author prissi
*/
int get_retire_year_month() const { return obsolete_date; }
+
+ /* Way constraints: determines whether vehicles
+ * can travel on this way. This method decodes
+ * the byte into bool values. See here for
+ * information on bitwise operations:
+ * http://www.cprogramming.com/tutorial/bitwise_operators.html
+ * @author: jamespetts
+ * */
+ const bool permissive_way_constraint_set(uint8 i)
+ {
+ return (way_constraints_permissive & 1<(get_child(0)); }
- int get_kapazitaet() const { return kapazitaet; }
- int get_anzahl() const { return anzahl; }
- int get_verbrauch() const { return verbrauch; }
+ int get_kapazitaet() const { return kapazitaet; } //"capacity" (Babelfish)
+ int get_anzahl() const { return anzahl; } //"number" (Babelfish)
+ int get_verbrauch() const { return verbrauch; } //"consumption" (Babelfish)
};
@@ -175,13 +175,13 @@ class fabrik_besch_t : public obj_besch_t {
enum platzierung {Land, Wasser, Stadt};
private:
- enum platzierung platzierung;
- uint16 produktivitaet;
- uint16 bereich;
- uint16 gewichtung; // Wie wahrscheinlich soll der Bau sein?
- uint8 kennfarbe;
- uint16 lieferanten;
- uint16 produkte;
+ enum platzierung platzierung; //"placement" (Babelfish)
+ uint16 produktivitaet; //"productivity" (Babelfish)
+ uint16 bereich; //"range" (Babelfish)
+ uint16 gewichtung; // Wie wahrscheinlich soll der Bau sein? ("How likely will the building be?" (Google)).
+ uint8 kennfarbe; //"identification colour code" (Babelfish)
+ uint16 lieferanten; //"supplier" (Babelfish)
+ uint16 produkte; //"products" (Babelfish)
uint8 fields; // only if there are any ...
uint16 pax_level;
bool electricity_producer;
@@ -196,7 +196,7 @@ class fabrik_besch_t : public obj_besch_t {
const rauch_besch_t *get_rauch() const { return static_cast(get_child(1)); }
// we must take care, for the case of no producer/consumer
- const fabrik_lieferant_besch_t *get_lieferant(int i) const
+ const fabrik_lieferant_besch_t *get_lieferant(int i) const //"supplier" (Babelfish)
{
return (i >= 0 && i < lieferanten) ? static_cast(get_child(2 + i)) : NULL;
}
@@ -209,18 +209,18 @@ class fabrik_besch_t : public obj_besch_t {
return static_cast(get_child(2 + lieferanten + produkte));
}
- int get_lieferanten() const { return lieferanten; }
+ int get_lieferanten() const { return lieferanten; } //"supplier" (Babelfish)
uint get_produkte() const { return produkte; }
/* where to built */
enum platzierung get_platzierung() const { return platzierung; }
int get_gewichtung() const { return gewichtung; }
- uint8 get_kennfarbe() const { return kennfarbe; }
+ uint8 get_kennfarbe() const { return kennfarbe; } //"identification colour code" (Babelfish)
void set_produktivitaet(int p) { produktivitaet=p; }
int get_produktivitaet() const { return produktivitaet; }
- int get_bereich() const { return bereich; }
+ int get_bereich() const { return bereich; } //"range" (Babelfish)
/* level for post and passenger generation */
int get_pax_level() const { return pax_level; }
diff --git a/besch/objversion.h b/besch/objversion.h
index 454e0b276dd..783761d9c9f 100644
--- a/besch/objversion.h
+++ b/besch/objversion.h
@@ -5,6 +5,9 @@
#define COMPILER_VERSION "0.1.2exp"
#define COMPILER_VERSION_CODE (0 * 1000000 + 1 * 1000 + 1)
+//The experimental subversion
+#define EXP_VER 0x4000
+
/*
* obj_type value are stored inside the pak-files. Values are choosen to make
* them somewhat readable (up to 4 uppercase letters describing the type).
@@ -31,7 +34,7 @@ enum obj_type
obj_fsupplier = C4ID('F','S','U','P'),
obj_good = C4ID('G','O','O','D'),
obj_ground = C4ID('G','R','N','D'),
- obj_groundobj = C4ID('G','O','B','J'),
+ obj_groundobj = C4ID('G','O','B','J'),
obj_image = C4ID('I','M','G', 0 ),
obj_imagelist = C4ID('I','M','G','1'),
obj_imagelist2d = C4ID('I','M','G','2'),
diff --git a/besch/reader/bridge_reader.cc b/besch/reader/bridge_reader.cc
index 8c106bfd6e0..53e248dc054 100644
--- a/besch/reader/bridge_reader.cc
+++ b/besch/reader/bridge_reader.cc
@@ -40,7 +40,24 @@ obj_besch_t * bridge_reader_t::read_node(FILE *fp, obj_node_info_t &node)
// But we know, the higher most bit was always cleared.
const uint16 v = decode_uint16(p);
- const int version = v & 0x8000 ? v & 0x7FFF : 0;
+ int version = v & 0x8000 ? v & 0x7FFF : 0;
+
+ // Whether the read file is from Simutrans-Experimental
+ //@author: jamespetts
+
+ const bool experimental = version > 0 ? v & EXP_VER : false;
+ uint16 experimental_version = 0;
+ if(experimental)
+ {
+ // Experimental version to start at 0 and increment.
+ version = version & EXP_VER ? version & 0x3FFF : 0;
+ while(version > 0x100)
+ {
+ version -= 0x100;
+ experimental_version ++;
+ }
+ experimental_version -=1;
+ }
// some defaults
besch->maintenance = 800;
@@ -48,9 +65,12 @@ obj_besch_t * bridge_reader_t::read_node(FILE *fp, obj_node_info_t &node)
besch->pillars_asymmetric = false;
besch->max_length = 0;
besch->max_height = 0;
+ besch->max_weight = 999;
besch->intro_date = DEFAULT_INTRO_DATE*12;
besch->obsolete_date = DEFAULT_RETIRE_DATE*12;
besch->number_seasons = 0;
+ besch->way_constraints_permissive = 0;
+ besch->way_constraints_prohibitive = 0;
if(version == 1) {
// Versioned node, version 1
@@ -137,6 +157,19 @@ obj_besch_t * bridge_reader_t::read_node(FILE *fp, obj_node_info_t &node)
besch->pillars_asymmetric = (decode_uint8(p)!=0);
besch->max_height = decode_uint8(p);
besch->number_seasons = decode_uint8(p);
+ if(experimental)
+ {
+ if(experimental_version == 0)
+ {
+ besch->max_weight = decode_uint32(p);
+ besch->way_constraints_permissive = decode_uint8(p);
+ besch->way_constraints_prohibitive = decode_uint8(p);
+ }
+ else
+ {
+ dbg->fatal( "bridge_reader_t::read_node()","Incompatible pak file version for Simutrans-E, number %i", experimental_version );
+ }
+ }
} else {
// old node, version 0
@@ -145,6 +178,16 @@ obj_besch_t * bridge_reader_t::read_node(FILE *fp, obj_node_info_t &node)
decode_uint16(p); // Menupos, no more used
besch->preis = decode_uint32(p);
besch->topspeed = 999; // Safe default ...
+ besch->max_weight = 999;
+ besch->way_constraints_permissive = 0;
+ besch->way_constraints_prohibitive = 0;
+ }
+
+ if(!experimental)
+ {
+ besch->max_weight = 999;
+ besch->way_constraints_permissive = 0;
+ besch->way_constraints_prohibitive = 0;
}
// pillars cannot be heigher than this to avoid drawing errors
@@ -155,8 +198,8 @@ obj_besch_t * bridge_reader_t::read_node(FILE *fp, obj_node_info_t &node)
besch->offset = version<8 ? 0 : 2;
DBG_DEBUG("bridge_reader_t::read_node()",
- "version=%d waytype=%d price=%d topspeed=%d,pillars=%i,max_length=%i",
- version, besch->wegtyp, besch->preis, besch->topspeed,besch->pillars_every,besch->max_length);
+ "version=%d waytype=%d price=%d topspeed=%d,pillars=%i,max_length=%i,max_weight%d",
+ version, besch->wegtyp, besch->preis, besch->topspeed,besch->pillars_every,besch->max_length,besch->max_weight);
return besch;
}
diff --git a/besch/reader/factory_reader.cc b/besch/reader/factory_reader.cc
index 4064fe3ff62..c048177b21b 100644
--- a/besch/reader/factory_reader.cc
+++ b/besch/reader/factory_reader.cc
@@ -176,14 +176,14 @@ factory_reader_t::read_node(FILE *fp, obj_node_info_t &node)
if(version == 2) {
// Versioned node, version 2
- besch->platzierung = (enum fabrik_besch_t::platzierung)decode_uint16(p);
- besch->produktivitaet = decode_uint16(p);
- besch->bereich = decode_uint16(p);
- besch->gewichtung = decode_uint16(p);
- besch->kennfarbe = decode_uint8(p);
- besch->fields = decode_uint8(p);
- besch->lieferanten = decode_uint16(p);
- besch->produkte = decode_uint16(p);
+ besch->platzierung = (enum fabrik_besch_t::platzierung)decode_uint16(p); //"placement" (Babelfish)
+ besch->produktivitaet = decode_uint16(p); //"productivity" (Babelfish)
+ besch->bereich = decode_uint16(p); //"range" (Babelfish)
+ besch->gewichtung = decode_uint16(p); //"weighting" (Babelfish)
+ besch->kennfarbe = decode_uint8(p); //"identification colour code" (Babelfish)
+ besch->fields = decode_uint8(p); //"fields" (Babelfish)
+ besch->lieferanten = decode_uint16(p); //"supplier" (Babelfish)
+ besch->produkte = decode_uint16(p); //"products" (Babelfish)
besch->pax_level = decode_uint16(p);
DBG_DEBUG("factory_reader_t::read_node()","version=2, platz=%i, lieferanten=%i, pax=%i", besch->platzierung, besch->lieferanten, besch->pax_level );
} else if(version == 1) {
diff --git a/besch/reader/good_reader.cc b/besch/reader/good_reader.cc
index d9a61fc60bf..5046ecffe84 100644
--- a/besch/reader/good_reader.cc
+++ b/besch/reader/good_reader.cc
@@ -21,7 +21,7 @@ void good_reader_t::register_obj(obj_besch_t *&data)
bool good_reader_t::successfully_loaded() const
{
- return warenbauer_t::alles_geladen();
+ return warenbauer_t::alles_geladen(); //"Alles geladen" = "Everything laoded" (Babelfish)
}
diff --git a/besch/reader/tunnel_reader.cc b/besch/reader/tunnel_reader.cc
index bedd332399f..74c5de8491f 100644
--- a/besch/reader/tunnel_reader.cc
+++ b/besch/reader/tunnel_reader.cc
@@ -27,7 +27,6 @@ tunnel_reader_t::successfully_loaded() const
}
-
obj_besch_t * tunnel_reader_t::read_node(FILE *fp, obj_node_info_t &node)
{
tunnel_besch_t *besch = new tunnel_besch_t();
@@ -43,7 +42,24 @@ obj_besch_t * tunnel_reader_t::read_node(FILE *fp, obj_node_info_t &node)
char * p = besch_buf;
const uint16 v = decode_uint16(p);
- const int version = v & 0x8000 ? v & 0x7FFF : 0;
+ int version = v & 0x8000 ? v & 0x7FFF : 0;
+
+ // Whether the read file is from Simutrans-Experimental
+ //@author: jamespetts
+
+ const bool experimental = version > 0 ? v & EXP_VER : false;
+ uint16 experimental_version = 0;
+ if(experimental)
+ {
+ // Experimental version to start at 0 and increment.
+ version = version & EXP_VER ? version & 0x3FFF : 0;
+ while(version > 0x100)
+ {
+ version -= 0x100;
+ experimental_version ++;
+ }
+ experimental_version -=1;
+ }
if(version == 3) {
// versioned node, version 2 - snow image support
@@ -54,6 +70,20 @@ obj_besch_t * tunnel_reader_t::read_node(FILE *fp, obj_node_info_t &node)
besch->intro_date = decode_uint16(p);
besch->obsolete_date = decode_uint16(p);
besch->number_seasons = decode_uint8(p);
+
+ if(experimental)
+ {
+ if(experimental_version == 0)
+ {
+ besch->max_weight = decode_uint32(p);
+ besch->way_constraints_permissive = decode_uint8(p);
+ besch->way_constraints_prohibitive = decode_uint8(p);
+ }
+ else
+ {
+ dbg->fatal( "tunnel_reader_t::read_node()","Incompatible pak file version for Simutrans-E, number %i", experimental_version );
+ }
+ }
besch->has_way = decode_uint8(p);
}
else if(version == 2) {
@@ -65,6 +95,19 @@ obj_besch_t * tunnel_reader_t::read_node(FILE *fp, obj_node_info_t &node)
besch->intro_date = decode_uint16(p);
besch->obsolete_date = decode_uint16(p);
besch->number_seasons = decode_uint8(p);
+ if(experimental)
+ {
+ if(experimental_version == 0)
+ {
+ besch->max_weight = decode_uint32(p);
+ besch->way_constraints_permissive = decode_uint8(p);
+ besch->way_constraints_prohibitive = decode_uint8(p);
+ }
+ else
+ {
+ dbg->fatal( "tunnel_reader_t::read_node()","Incompatible pak file version for Simutrans-E, number %i", experimental_version );
+ }
+ }
besch->has_way = 0;
}
else if(version == 1) {
@@ -76,15 +119,25 @@ obj_besch_t * tunnel_reader_t::read_node(FILE *fp, obj_node_info_t &node)
besch->intro_date = decode_uint16(p);
besch->obsolete_date = decode_uint16(p);
besch->number_seasons = 0;
+ besch->max_weight = 999;
+ besch->way_constraints_permissive = 0;
+ besch->way_constraints_prohibitive = 0;
besch->has_way = 0;
} else {
dbg->fatal("tunnel_reader_t::read_node()","illegal version %d",version);
}
+ if(!experimental)
+ {
+ besch->max_weight = 999;
+ besch->way_constraints_permissive = 0;
+ besch->way_constraints_prohibitive = 0;
+ }
+
DBG_DEBUG("bridge_reader_t::read_node()",
- "version=%d waytype=%d price=%d topspeed=%d, intro_year=%d",
- version, besch->wegtyp, besch->preis, besch->topspeed, besch->intro_date/12);
+ "version=%d waytype=%d price=%d topspeed=%d, intro_year=%d, max_weight%d",
+ version, besch->wegtyp, besch->preis, besch->topspeed, besch->intro_date/12, besch->max_weight);
}
return besch;
diff --git a/besch/reader/vehicle_reader.cc b/besch/reader/vehicle_reader.cc
index ae3b6eafd2c..f54a1b3ddf0 100644
--- a/besch/reader/vehicle_reader.cc
+++ b/besch/reader/vehicle_reader.cc
@@ -10,8 +10,6 @@
#include "vehicle_reader.h"
#include "../obj_node_info.h"
-
-
void
vehicle_reader_t::register_obj(obj_besch_t *&data)
{
@@ -21,7 +19,6 @@ vehicle_reader_t::register_obj(obj_besch_t *&data)
}
-
bool
vehicle_reader_t::successfully_loaded() const
{
@@ -45,7 +42,24 @@ vehicle_reader_t::read_node(FILE *fp, obj_node_info_t &node)
// But we know, the higher most bit was always cleared.
const uint16 v = decode_uint16(p);
- const int version = v & 0x8000 ? v & 0x7FFF : 0;
+ int version = v & 0x8000 ? v & 0x7FFF : 0;
+
+ // Whether the read file is from Simutrans-Experimental
+ //@author: jamespetts
+
+ const bool experimental = version > 0 ? v & EXP_VER : false;
+ uint16 experimental_version = 0;
+ if(experimental)
+ {
+ // Experimental version to start at 0 and increment.
+ version = version & EXP_VER ? version & 0x3FFF : 0;
+ while(version > 0x100)
+ {
+ version -= 0x100;
+ experimental_version ++;
+ }
+ experimental_version -=1;
+ }
if(version == 1) {
// Versioned node, version 1
@@ -152,7 +166,7 @@ vehicle_reader_t::read_node(FILE *fp, obj_node_info_t &node)
besch->zuladung = decode_uint16(p);
besch->geschw = decode_uint16(p);
besch->gewicht = decode_uint16(p);
- besch->leistung = decode_uint32(p);
+ besch->leistung = decode_uint32(p); //"performance" (Google)
besch->betriebskosten = decode_uint16(p);
besch->intro_date = decode_uint16(p);
@@ -163,9 +177,31 @@ vehicle_reader_t::read_node(FILE *fp, obj_node_info_t &node)
besch->sound = decode_sint8(p);
besch->engine_type = decode_uint8(p);
besch->len = decode_uint8(p);
- besch->vorgaenger = decode_uint8(p);
- besch->nachfolger = decode_uint8(p);
+ besch->vorgaenger = decode_uint8(p); //"Predecessors" (Google)
+ besch->nachfolger = decode_uint8(p); //"Successor" (Google)
besch->freight_image_type = decode_uint8(p);
+ if(experimental)
+ {
+ if(experimental_version == 0)
+ {
+ besch->is_tilting = decode_uint8(p);
+ besch->way_constraints_permissive = decode_uint8(p);
+ besch->way_constraints_prohibitive = decode_uint8(p);
+ besch->catering_level = decode_uint8(p);
+ besch->bidirectional = decode_uint8(p);
+ besch->can_lead_from_rear = decode_uint8(p);
+ besch->comfort = decode_uint8(p);
+ besch->overcrowded_capacity = decode_uint16(p);
+ besch->loading_time = decode_uint16(p);
+ besch->upgrades = decode_uint8(p);
+ besch->upgrade_price = decode_uint32(p);
+ besch->available_only_as_upgrade = decode_uint8(p);
+ }
+ else
+ {
+ dbg->fatal( "vehicle_reader_t::read_node()","Incompatible pak file version for Simutrans-E, number %i", experimental_version );
+ }
+ }
}
else {
if( version!=0 ) {
@@ -224,10 +260,29 @@ vehicle_reader_t::read_node(FILE *fp, obj_node_info_t &node)
besch->len *= TILE_STEPS/16;
// before version 8 vehicles could only have one freight image in each direction
- if(version<8) {
- besch->freight_image_type=0;
+ if(version<8)
+ {
+ besch->freight_image_type = 0;
}
+ if(!experimental)
+ {
+ // Default values for items not in the standard vehicle format.
+ besch->is_tilting = false;
+ besch->way_constraints_permissive = 0;
+ besch->way_constraints_prohibitive = 0;
+ besch->catering_level = 0;
+ besch->bidirectional = false;
+ besch->can_lead_from_rear = false;
+ besch->comfort = 100;
+ besch->overcrowded_capacity = 0;
+ besch->loading_time = 2000;
+ besch->upgrades = 0;
+ besch->upgrade_price = besch->preis;
+ besch->available_only_as_upgrade = false;
+ }
+
+
if(besch->sound==LOAD_SOUND) {
uint8 len=decode_sint8(p);
char wavname[256];
@@ -248,7 +303,8 @@ DBG_MESSAGE("vehicle_reader_t::register_obj()","old sound %i to %i",old_id,besch
"version=%d "
"way=%d zuladung=%d preis=%d geschw=%d gewicht=%d leistung=%d "
"betrieb=%d sound=%d vor=%d nach=%d "
- "date=%d/%d gear=%d engine_type=%d len=%d",
+ "date=%d/%d gear=%d engine_type=%d len=%d is_tilting=%d catering_level=%d "
+ "way_constraints_permissive=%d way_constraints_prohibitive%d bidirectional%d can_lead_from_rear%d",
version,
besch->typ,
besch->zuladung,
@@ -264,7 +320,13 @@ DBG_MESSAGE("vehicle_reader_t::register_obj()","old sound %i to %i",old_id,besch
besch->intro_date/12,
besch->gear,
besch->engine_type,
- besch->len);
+ besch->len,
+ besch->is_tilting,
+ besch->catering_level,
+ besch->way_constraints_permissive,
+ besch->way_constraints_prohibitive,
+ besch->bidirectional,
+ besch->can_lead_from_rear);
return besch;
}
diff --git a/besch/reader/vehicle_reader.h b/besch/reader/vehicle_reader.h
index 0eda7c49bc0..44aa76f02d5 100644
--- a/besch/reader/vehicle_reader.h
+++ b/besch/reader/vehicle_reader.h
@@ -8,6 +8,7 @@ class vehicle_reader_t : public obj_reader_t {
static vehicle_reader_t the_instance;
vehicle_reader_t() { register_reader(); }
+
protected:
virtual void register_obj(obj_besch_t *&data);
virtual bool successfully_loaded() const;
diff --git a/besch/reader/way_obj_reader.cc b/besch/reader/way_obj_reader.cc
index 914d3d53e28..29a891b4ed1 100644
--- a/besch/reader/way_obj_reader.cc
+++ b/besch/reader/way_obj_reader.cc
@@ -37,7 +37,24 @@ obj_besch_t * way_obj_reader_t::read_node(FILE *fp, obj_node_info_t &node)
// Hajo: old versions of PAK files have no version stamp.
// But we know, the higher most bit was always cleared.
const uint16 v = decode_uint16(p);
- const uint16 version = v & 0x7FFF;
+ uint16 version = v & 0x7FFF;
+
+ // Whether the read file is from Simutrans-Experimental
+ //@author: jamespetts
+
+ const bool experimental = version > 0 ? v & EXP_VER : false;
+ uint16 experimental_version = 0;
+ if(experimental)
+ {
+ // Experimental version to start at 0 and increment.
+ version = version & EXP_VER ? version & 0x3FFF : 0;
+ while(version > 0x100)
+ {
+ version -= 0x100;
+ experimental_version ++;
+ }
+ experimental_version -=1;
+ }
if(version==1) {
// Versioned node, version 3
@@ -48,10 +65,29 @@ obj_besch_t * way_obj_reader_t::read_node(FILE *fp, obj_node_info_t &node)
besch->obsolete_date = decode_uint16(p);
besch->wtyp = decode_uint8(p);
besch->own_wtyp = decode_uint8(p);
+ if(experimental)
+ {
+ if(experimental_version == 0)
+ {
+ besch->way_constraints_permissive = decode_uint8(p);
+ besch->way_constraints_prohibitive = decode_uint8(p);
+ }
+ else
+ {
+ dbg->fatal( "way_obj_reader_t::read_node()","Incompatible pak file version for Simutrans-E, number %i", experimental_version );
+ }
+ }
}
else {
dbg->fatal("way_obj_reader_t::read_node()","Invalid version %d", version);
}
+
+ if(!experimental)
+ {
+ besch->way_constraints_permissive = 0;
+ besch->way_constraints_prohibitive = 0;
+ }
+
DBG_DEBUG("way_obj_reader_t::read_node()",
"version=%d price=%d maintenance=%d topspeed=%d max_weight=%d "
"wtype=%d styp=%d intro_year=%i",
diff --git a/besch/reader/way_reader.cc b/besch/reader/way_reader.cc
index a8baa86c749..06ba7d93875 100644
--- a/besch/reader/way_reader.cc
+++ b/besch/reader/way_reader.cc
@@ -60,6 +60,28 @@ obj_besch_t * way_reader_t::read_node(FILE *fp, obj_node_info_t &node)
const uint16 v = decode_uint16(p);
version = v & 0x7FFF;
+ // Whether the read file is from Simutrans-Experimental
+ //@author: jamespetts
+
+ const bool experimental = version > 0 ? v & EXP_VER : false;
+ uint16 experimental_version = 0;
+ if(experimental)
+ {
+ // Experimental version to start at 0 and increment.
+ version = version & EXP_VER ? version & 0x3FFF : 0;
+ while(version > 0x100)
+ {
+ version -= 0x100;
+ experimental_version ++;
+ }
+ experimental_version -=1;
+ }
+ else
+ {
+ besch->way_constraints_permissive = 0;
+ besch->way_constraints_prohibitive = 0;
+ }
+
if(version==4) {
// Versioned node, version 4
besch->price = decode_uint32(p);
@@ -72,6 +94,19 @@ obj_besch_t * way_reader_t::read_node(FILE *fp, obj_node_info_t &node)
besch->styp = decode_uint8(p);
besch->draw_as_ding = decode_uint8(p);
besch->number_seasons = decode_sint8(p);
+ if(experimental)
+ {
+ if(experimental_version == 0)
+ {
+ besch->way_constraints_permissive = decode_uint8(p);
+ besch->way_constraints_prohibitive = decode_uint8(p);
+ }
+ else
+ {
+ dbg->fatal( "way_reader_t::read_node()","Incompatible pak file version for Simutrans-E, number %i", experimental_version );
+ }
+ }
+
}
else if(version==3) {
// Versioned node, version 3
@@ -130,6 +165,7 @@ obj_besch_t * way_reader_t::read_node(FILE *fp, obj_node_info_t &node)
else if(besch->wtyp==128) {
besch->wtyp = powerline_wt;
}
+
if(version<=2 && besch->wtyp==air_wt && besch->topspeed>=250) {
// runway!
besch->styp = 1;
@@ -137,7 +173,8 @@ obj_besch_t * way_reader_t::read_node(FILE *fp, obj_node_info_t &node)
DBG_DEBUG("way_reader_t::read_node()",
"version=%d price=%d maintenance=%d topspeed=%d max_weight=%d "
- "wtype=%d styp=%d intro_year=%i",
+ "wtype=%d styp=%d intro_year=%i way_constraints_permissive = %d "
+ "way_constraints_prohibitive = %d",
version,
besch->price,
besch->maintenance,
@@ -145,7 +182,9 @@ obj_besch_t * way_reader_t::read_node(FILE *fp, obj_node_info_t &node)
besch->max_weight,
besch->wtyp,
besch->styp,
- besch->intro_date/12);
+ besch->intro_date/12,
+ besch->way_constraints_permissive,
+ besch->way_constraints_prohibitive);
return besch;
}
diff --git a/besch/roadsign_besch.h b/besch/roadsign_besch.h
index ad71a2faae1..8c58af97450 100644
--- a/besch/roadsign_besch.h
+++ b/besch/roadsign_besch.h
@@ -25,7 +25,10 @@ class skin_besch_t;
* Beschreibung:
* Straßenschildere
*
- * Kindknoten:
+ * Description:
+ * Street Signs
+ *
+ * Kindknoten: ("Child nodes" - Google)
* 0 Name
* 1 Copyright
* 2 Bildliste
diff --git a/besch/tunnel_besch.h b/besch/tunnel_besch.h
index a1c07f9985b..d7ebf8469c2 100644
--- a/besch/tunnel_besch.h
+++ b/besch/tunnel_besch.h
@@ -35,18 +35,25 @@ class tunnel_besch_t : public obj_besch_std_name_t {
uint32 preis; // 1/100 credits
uint32 maintenance; // monthly cost for bits_per_month=18
uint8 wegtyp; // waytype for tunnel
+ uint32 max_weight; // maximum weight for vehicles. @author: jamespetts
- // allowed eara
+ // allowed era
uint16 intro_date;
uint16 obsolete_date;
- /* number of seasons (0 = none, 1 = no snow/snow
+ /* number of seasons (0 = none, 1 = no snow/snow)
*/
sint8 number_seasons;
- /* has underground way image ? ( 0 = no, 1 = yes
+ /*Way constraints for, e.g., loading gauges, types of electrification, etc.
+ * @author: jamespetts*/
+ uint8 way_constraints_permissive;
+ uint8 way_constraints_prohibitive;
+
+ /* has underground way image ? (0 = no, 1 = yes)
*/
uint8 has_way;
+
public:
const bild_besch_t *get_hintergrund(hang_t::typ hang, uint8 season) const
{
@@ -96,9 +103,31 @@ class tunnel_besch_t : public obj_besch_std_name_t {
uint32 get_topspeed() const { return topspeed; }
+ uint32 get_max_weight() const { return max_weight; }
+
uint16 get_intro_year_month() const { return intro_date; }
uint16 get_retire_year_month() const { return obsolete_date; }
+
+ /* Way constraints: determines whether vehicles
+ * can travel on this way. This method decodes
+ * the byte into bool values. See here for
+ * information on bitwise operations:
+ * http://www.cprogramming.com/tutorial/bitwise_operators.html
+ * @author: jamespetts
+ * */
+ const bool permissive_way_constraint_set(uint8 i)
+ {
+ return (way_constraints_permissive & 1<get_current_month();
+ int normal_running_costs = get_betriebskosten();
+ if(!welt->use_timeline() || !is_retired(month_now))
+ {
+ return normal_running_costs;
+ }
+ //Else
+ uint16 base_obsolete_running_costs = normal_running_costs * (welt->get_einstellungen()->get_obsolete_running_cost_increase_percent() / 100);
+ uint16 obsolete_date = get_retire_year_month();
+ if((month_now - obsolete_date) >= (welt->get_einstellungen()->get_obsolete_running_cost_increase_phase_years() * 12))
+ {
+ return base_obsolete_running_costs;
+ }
+ //Else
+ //If not at end of phasing period, apply only a proportion of the obsolescence cost increase.
+ float tmp1 = base_obsolete_running_costs - normal_running_costs;
+ float tmp2 = month_now - obsolete_date;
+ float proportion = tmp2 / (welt->get_einstellungen()->get_obsolete_running_cost_increase_phase_years() * 12);
+ return (tmp1 * proportion) + normal_running_costs;
+}
\ No newline at end of file
diff --git a/besch/vehikel_besch.h b/besch/vehikel_besch.h
index 15f8946144b..d6bf7a937ac 100644
--- a/besch/vehikel_besch.h
+++ b/besch/vehikel_besch.h
@@ -14,6 +14,7 @@
#include "skin_besch.h"
#include "sound_besch.h"
#include "../dataobj/ribi.h"
+#include "../simworld.h"
#include "../simtypes.h"
@@ -63,28 +64,51 @@ class vehikel_besch_t : public obj_besch_std_name_t {
private:
- uint32 preis;
- uint16 zuladung;
- uint16 geschw;
- uint16 gewicht;
- uint32 leistung;
- uint16 betriebskosten;
-
- uint16 intro_date; // introduction date
- uint16 obsolete_date; //phase out at
- uint16 gear; // engine gear (power multiplier), 64=100
-
- sint8 typ; // see weg_t for allowed types
+ uint32 preis; //Price
+ uint32 upgrade_price; //Price if this vehicle is bought as an upgrade, not a new vehicle.
+ uint16 zuladung; //Payload
+ uint16 overcrowded_capacity; // The capacity of a vehicle if overcrowded (usually expressed as the standing capacity).
+ uint16 geschw; //Speed
+ uint16 gewicht; //Weight
+ uint32 leistung; //Power
+ uint16 betriebskosten; //Running costs
+
+ uint16 intro_date; // introduction date
+ uint16 obsolete_date; //phase out at
+ uint16 gear; // engine gear (power multiplier), 64=100
+
+ sint8 typ; // see weg_t for allowed types
uint8 len; // length (=8 is half a tile, the old default)
sint8 sound;
- uint8 vorgaenger; // all defined leading vehicles
- uint8 nachfolger; // all defined trailer
+ uint8 vorgaenger; // all defined leading vehicles
+ uint8 nachfolger; // all defined trailer
+ uint8 upgrades; // The vehicles types to which this type may be upgraded.
- uint8 engine_type; // diesel, steam, electric (requires electrified ways), fuel_cell, etc.
+ uint8 engine_type; // diesel, steam, electric (requires electrified ways), fuel_cell, etc.
sint8 freight_image_type; // number of freight images (displayed for different goods)
+ bool is_tilting; //Whether it is a tilting train (can take corners at higher speeds). 0 for no, 1 for yes. Anything other than 1 is assumed to be no.
+
+ uint8 way_constraints_permissive; //Way constraints. Actually, 8 boolean values. Bitwise operations necessary
+ uint8 way_constraints_prohibitive; //to uncompress this (but if value is 0, are no constraints).
+
+ uint8 catering_level; //The level of catering. 0 for no catering. Higher numbers for better catering.
+
+ bool bidirectional; //Whether must always travel in one direction
+ bool can_lead_from_rear; //Whether vehicle can lead a convoy when it is at the rear.
+
+ uint8 comfort; // How comfortable that a vehicle is for passengers.
+
+ uint16 loading_time; //Time in MS (at speed 1.0) to load/unload.
+
+ bool available_only_as_upgrade; //If yes, can not be bought as new: only upgraded.
+
+
+
+
+
public:
// since we have a second constructor
@@ -93,14 +117,17 @@ class vehikel_besch_t : public obj_besch_std_name_t {
// default vehicle (used for way seach and similar tasks)
// since it has no images and not even a name knot any calls to this will case a crash
vehikel_besch_t(uint8 wtyp, uint16 speed, engine_t engine) {
- freight_image_type = preis = zuladung = betriebskosten = intro_date = vorgaenger = nachfolger = 0;
- leistung = gewicht = 1;
+ freight_image_type = preis = upgrade_price = zuladung = overcrowded_capacity = betriebskosten = intro_date = vorgaenger = nachfolger = catering_level = upgrades = 0;
+ leistung = gewicht = comfort = 1;
gear = 64;
len = 8;
sound = -1;
typ = wtyp;
engine_type = (uint8)engine;
geschw = speed;
+ is_tilting = bidirectional = can_lead_from_rear = available_only_as_upgrade = false;
+ way_constraints_prohibitive = way_constraints_permissive = 0;
+ loading_time = 2000;
}
const ware_besch_t *get_ware() const { return static_cast(get_child(2)); }
@@ -175,10 +202,15 @@ class vehikel_besch_t : public obj_besch_std_name_t {
// liefert get_vorgaenger(0) == NULL, so bedeutet das entweder alle
// Vorgänger sind erlaubt oder keine. Um das zu unterscheiden, sollte man
// vorher hat_vorgaenger() befragen
+
+ // Returns allowed predecessor.
+ // provides get_vorgaenger (0) == NULL, it means that either all
+ // predecessors are allowed or not. To distinguish, one should
+ // predict hat_vorgaenger () question (Google)
const vehikel_besch_t *get_vorgaenger(int i) const
{
if(i < 0 || i >= vorgaenger) {
- return 0;
+ return NULL;
}
return static_cast(get_child(6 + i));
}
@@ -205,16 +237,34 @@ class vehikel_besch_t : public obj_besch_std_name_t {
// liefert get_nachfolger(0) == NULL, so bedeutet das entweder alle
// Nachfolger sind erlaubt oder keine. Um das zu unterscheiden, sollte
// man vorher hat_nachfolger() befragen
+
+ // Returns the lawful successor.
+ // provides get_nachfolger (0) == NULL, it means that either all
+ // succeed or none are allowed. To distinguish, one should
+ // predict hat_nachfolger () question (Google)
const vehikel_besch_t *get_nachfolger(int i) const
{
if(i < 0 || i >= nachfolger) {
- return 0;
+ return NULL;
}
return static_cast(get_child(6 + vorgaenger + i));
}
int get_nachfolger_count() const { return nachfolger; }
+ // Returns the vehicle types to which this vehicle type may be upgraded.
+
+ const vehikel_besch_t * get_upgrades(int i) const
+ {
+ if(i < 0 || i >= upgrades)
+ {
+ return NULL;
+ }
+ return static_cast(get_child(6 + nachfolger + i));
+ }
+
+ int get_upgrades_count() const { return upgrades; }
+
waytype_t get_waytype() const { return static_cast(typ); }
uint16 get_zuladung() const { return zuladung; }
uint32 get_preis() const { return preis; }
@@ -222,7 +272,16 @@ class vehikel_besch_t : public obj_besch_std_name_t {
uint16 get_gewicht() const { return gewicht; }
uint32 get_leistung() const { return leistung; }
uint16 get_betriebskosten() const { return betriebskosten; }
+ uint16 get_betriebskosten(karte_t *welt) const; //Overloaded method - includes increase for obsolescence.
sint8 get_sound() const { return sound; }
+ bool is_bidirectional() const { return bidirectional; }
+ bool get_can_lead_from_rear() const { return can_lead_from_rear; }
+ uint8 get_comfort() const { return comfort; }
+ uint16 get_overcrowded_capacity() const { return overcrowded_capacity; }
+ uint16 get_loading_time() const { return zuladung > 0 ? loading_time : 0; }
+ uint32 get_upgrade_price() const { return upgrade_price; }
+ bool is_available_only_as_upgrade() const { return available_only_as_upgrade; }
+
/**
* @return introduction year
@@ -266,6 +325,33 @@ class vehikel_besch_t : public obj_besch_std_name_t {
* @author prissi
*/
uint8 get_length() const { return len; }
+
+ /*Whether this is a tilting train (and can take coerners faster
+ *@author: jamespetts*/
+ bool get_tilting() const { return (is_tilting); }
+
+ /*Bitwise encoded way constraints (permissive)
+ *@author: jamespetts*/
+ uint8 get_permissive_constraints() const { return way_constraints_permissive; }
+
+ /*Bitwise encoded way constraints (prohibitive)
+ *@author: jamespetts*/
+ uint8 get_prohibitive_constraints() const { return way_constraints_prohibitive; }
+
+ bool permissive_way_constraint_set(uint8 i) const
+ {
+ return (way_constraints_permissive & 1< 0) ? max_weight : 999; }
+
/**
* get way type
* @see waytype_t
@@ -173,8 +181,10 @@ class weg_besch_t : public obj_besch_std_name_t {
* @return introduction year
* @author Hj. Malthaner
*/
+
uint16 get_intro_year_month() const { return intro_date; }
+
/**
* @return introduction month
* @author Hj. Malthaner
@@ -192,6 +202,26 @@ class weg_besch_t : public obj_besch_std_name_t {
{
return (const skin_besch_t *)(get_child(5));
}
+
+ /* Way constraints: determines whether vehicles
+ * can travel on this way. This method decodes
+ * the byte into bool values. See here for
+ * information on bitwise operations:
+ * http://www.cprogramming.com/tutorial/bitwise_operators.html
+ * @author: jamespetts
+ * */
+ const bool permissive_way_constraint_set(uint8 i) const
+ {
+ return (way_constraints_permissive & 1<
#include "../../utils/cstring_t.h"
#include "../../dataobj/tabfile.h"
#include "obj_node.h"
@@ -12,7 +13,7 @@
void bridge_writer_t::write_obj(FILE* outfp, obj_node_t& parent, tabfileobj_t& obj)
{
- obj_node_t node(this, 22, &parent);
+ obj_node_t node(this, 28, &parent);
uint8 wegtyp = get_waytype(obj.get("waytype"));
uint16 topspeed = obj.get_int("topspeed", 999);
@@ -23,6 +24,7 @@ void bridge_writer_t::write_obj(FILE* outfp, obj_node_t& parent, tabfileobj_t& o
uint8 max_length = obj.get_int("max_lenght",0); // max_lenght==0: unlimited
max_length = obj.get_int("max_length",max_length); // with correct spelling
uint8 max_height = obj.get_int("max_height",0); // max_height==0: unlimited
+ uint32 max_weight = obj.get_int("max_weight",999);
// prissi: timeline
uint16 intro_date = obj.get_int("intro_year", DEFAULT_INTRO_DATE) * 12;
@@ -33,20 +35,67 @@ void bridge_writer_t::write_obj(FILE* outfp, obj_node_t& parent, tabfileobj_t& o
sint8 number_seasons = 0;
+ // Way constraints
+ // One byte for permissive, one byte for prohibitive.
+ // Therefore, 8 possible constraints of each type.
+ // Permissive: way allows vehicles with matching constraint:
+ // vehicles not allowed on any other sort of way. Vehicles
+ // without that constraint also allowed on the way.
+ // Prohibitive: way allows only vehicles with matching constraint:
+ // vehicles with matching constraint allowed on other sorts of way.
+ // @author: jamespetts
+
+ uint8 permissive_way_constraints = 0;
+ uint8 prohibitive_way_constraints = 0;
+ char buf_permissive[60];
+ char buf_prohibitive[60];
+ //Read the values from a file, and put them into an array.
+ for(uint8 i = 0; i < 8; i++)
+ {
+ sprintf(buf_permissive, "way_constraint_permissive[%d]", i);
+ sprintf(buf_prohibitive, "way_constraint_prohibitive[%d]", i);
+ uint8 tmp_permissive = (obj.get_int(buf_permissive, 255));
+ uint8 tmp_prohibitive = (obj.get_int(buf_prohibitive, 255));
+
+ // Values must fit into one byte
+ // Must therefore be 0-7
+ if(tmp_permissive > 7 || tmp_prohibitive > 7)
+ {
+ continue;
+ }
+
+ //Compress values into a single byte using bitwise OR.
+ permissive_way_constraints = (tmp_permissive > 0) ? permissive_way_constraints | (uint8)pow(2, (double)tmp_permissive) : permissive_way_constraints | 1;
+ prohibitive_way_constraints = (tmp_prohibitive > 0) ? prohibitive_way_constraints | (uint8)pow(2, (double)tmp_prohibitive) : prohibitive_way_constraints | 1;
+ }
+
// Hajo: Version needs high bit set as trigger -> this is required
// as marker because formerly nodes were unversionend
uint16 version = 0x8008;
- node.write_uint16(outfp, version, 0);
- node.write_uint16(outfp, topspeed, 2);
- node.write_uint32(outfp, preis, 4);
- node.write_uint32(outfp, maintenance, 8);
- node.write_uint8 (outfp, wegtyp, 12);
- node.write_uint8 (outfp, pillars_every, 13);
- node.write_uint8 (outfp, max_length, 14);
- node.write_uint16(outfp, intro_date, 15);
- node.write_uint16(outfp, obsolete_date, 17);
- node.write_uint8 (outfp, pillar_asymmetric, 19);
- node.write_uint8 (outfp, max_height, 20);
+
+ // This is the overlay flag for Simutrans-Experimental
+ // This sets the *second* highest bit to 1.
+ version |= EXP_VER;
+
+ // Finally, this is the experimental version number. This is *added*
+ // to the standard version number, to be subtracted again when read.
+ // Start at 0x100 and increment in hundreds (hex).
+ version += 0x100;
+
+ node.write_uint16(outfp, version, 0);
+ node.write_uint16(outfp, topspeed, 2);
+ node.write_uint32(outfp, preis, 4);
+ node.write_uint32(outfp, maintenance, 8);
+ node.write_uint8 (outfp, wegtyp, 12);
+ node.write_uint8 (outfp, pillars_every, 13);
+ node.write_uint8 (outfp, max_length, 14);
+ node.write_uint16(outfp, intro_date, 15);
+ node.write_uint16(outfp, obsolete_date, 17);
+ node.write_uint8 (outfp, pillar_asymmetric, 19);
+ node.write_uint8 (outfp, max_height, 20);
+ node.write_uint32(outfp, max_weight, 22);
+ node.write_uint8(outfp, permissive_way_constraints, 26);
+ node.write_uint8(outfp, prohibitive_way_constraints,27);
static const char* const names[] = {
"image",
diff --git a/besch/writer/root_writer.cc b/besch/writer/root_writer.cc
index e154585b01a..d48df6764c2 100644
--- a/besch/writer/root_writer.cc
+++ b/besch/writer/root_writer.cc
@@ -1,3 +1,5 @@
+#include
+
#include "../../utils/cstring_t.h"
#include "../../dataobj/tabfile.h"
#include "../../utils/searchfolder.h"
diff --git a/besch/writer/tunnel_writer.cc b/besch/writer/tunnel_writer.cc
index f75e83377d5..d486a7354c1 100644
--- a/besch/writer/tunnel_writer.cc
+++ b/besch/writer/tunnel_writer.cc
@@ -1,3 +1,4 @@
+#include
#include "../../utils/cstring_t.h"
#include "../../dataobj/tabfile.h"
#include "../../dataobj/ribi.h"
@@ -15,12 +16,13 @@ void tunnel_writer_t::write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj)
{
int pos, i;
- obj_node_t node(this, 21, &parent);
+ obj_node_t node(this, 27, &parent);
- uint32 topspeed = obj.get_int("topspeed", 999);
- uint32 preis = obj.get_int("cost", 0);
- uint32 maintenance = obj.get_int("maintenance", 1000);
+ uint32 topspeed = obj.get_int("topspeed", 999);
+ uint32 preis = obj.get_int("cost", 0);
+ uint32 maintenance = obj.get_int("maintenance",1000);
uint8 wegtyp = get_waytype(obj.get("waytype"));
+ uint32 max_weight = obj.get_int("max_weight", 999);
// prissi: timeline
uint16 intro_date = obj.get_int("intro_year", DEFAULT_INTRO_DATE) * 12;
@@ -29,16 +31,73 @@ void tunnel_writer_t::write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj)
uint16 obsolete_date = obj.get_int("retire_year", DEFAULT_RETIRE_DATE) * 12;
obsolete_date += obj.get_int("retire_month", 1) - 1;
+ // Way constraints
+ // One byte for permissive, one byte for prohibitive.
+ // Therefore, 8 possible constraints of each type.
+ // Permissive: way allows vehicles with matching constraint:
+ // vehicles not allowed on any other sort of way. Vehicles
+ // without that constraint also allowed on the way.
+ // Prohibitive: way allows only vehicles with matching constraint:
+ // vehicles with matching constraint allowed on other sorts of way.
+ // @author: jamespetts
+
+ uint8 permissive_way_constraints = 0;
+ uint8 prohibitive_way_constraints = 0;
+ char buf_permissive[60];
+ char buf_prohibitive[60];
+ //Read the values from a file, and put them into an array.
+ for(uint8 i = 0; i < 8; i++)
+ {
+ sprintf(buf_permissive, "way_constraint_permissive[%d]", i);
+ sprintf(buf_prohibitive, "way_constraint_prohibitive[%d]", i);
+ uint8 tmp_permissive = (obj.get_int(buf_permissive, 255));
+ uint8 tmp_prohibitive = (obj.get_int(buf_prohibitive, 255));
+
+ //Compress values into a single byte using bitwise OR.
+ if(tmp_permissive < 8)
+ {
+ permissive_way_constraints = (tmp_permissive > 0) ? permissive_way_constraints | (uint8)pow(2, (double)tmp_permissive) : permissive_way_constraints | 1;
+ }
+ if(tmp_prohibitive < 8)
+ {
+ prohibitive_way_constraints = (tmp_prohibitive > 0) ? prohibitive_way_constraints | (uint8)pow(2, (double)tmp_prohibitive) : prohibitive_way_constraints | 1;
+ }
+ }
+
// Version uses always high bit set as trigger
// version 2: snow images
+ // Version 3: pre-defined ways
uint16 version = 0x8003;
- node.write_uint16(fp, version, 0);
- node.write_uint32(fp, topspeed, 2);
- node.write_uint32(fp, preis, 6);
- node.write_uint32(fp, maintenance, 10);
- node.write_uint8 (fp, wegtyp, 14);
- node.write_uint16(fp, intro_date, 15);
- node.write_uint16(fp, obsolete_date, 17);
+
+ // This is the overlay flag for Simutrans-Experimental
+ // This sets the *second* highest bit to 1.
+ version |= EXP_VER;
+
+ // Finally, this is the experimental version number. This is *added*
+ // to the standard version number, to be subtracted again when read.
+ // Start at 0x100 and increment in hundreds (hex).
+ version += 0x100;
+
+ node.write_uint16(fp, version, 0);
+ node.write_uint32(fp, topspeed, 2);
+ node.write_uint32(fp, preis, 6);
+ node.write_uint32(fp, maintenance, 10);
+ node.write_uint8 (fp, wegtyp, 14);
+ node.write_uint16(fp, intro_date, 15);
+ node.write_uint16(fp, obsolete_date, 17);
+ node.write_uint32(fp, max_weight, 20);
+ node.write_uint8(fp, permissive_way_constraints, 24);
+ node.write_uint8(fp, prohibitive_way_constraints, 25);
+ cstring_t str = obj.get("way");
+ if (str.len() > 0)
+ {
+ xref_writer_t::instance()->write_obj(fp, node, obj_way, str, true);
+ node.write_sint8(fp, 1, 26);
+ }
+ else
+ {
+ node.write_sint8(fp, 0, 26);
+ }
sint8 number_seasons = 0;
@@ -53,7 +112,7 @@ void tunnel_writer_t::write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj)
char buf[40];
sprintf(buf, "%simage[%s][0]", "back", indices[0]);
- cstring_t str = obj.get(buf);
+ str = obj.get(buf);
if (strlen(str) == 0) {
node.write_sint8(fp, number_seasons, 19);
write_head(fp, node, obj);
@@ -100,15 +159,7 @@ void tunnel_writer_t::write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj)
}
}
}
- str = obj.get("way");
- if (str.len() > 0) {
- xref_writer_t::instance()->write_obj(fp, node, obj_way, str, true);
- node.write_sint8(fp, 1, 20);
- }
- else {
- node.write_sint8(fp, 0, 20);
- }
-
+
cursorkeys.clear();
node.write(fp);
diff --git a/besch/writer/vehicle_writer.cc b/besch/writer/vehicle_writer.cc
index 898730a7171..6b516061072 100644
--- a/besch/writer/vehicle_writer.cc
+++ b/besch/writer/vehicle_writer.cc
@@ -1,3 +1,4 @@
+#include
#include "../../utils/simstring.h"
#include "../../utils/cstring_t.h"
#include "../../dataobj/tabfile.h"
@@ -49,15 +50,35 @@ static uint8 get_engine_type(const char* engine_type, tabfileobj_t& obj)
/**
* Writes vehicle node data to file
+ *
+ * NOTE: The data must be written in _exactly_
+ * the same sequence as it is to be read in the
+ * relevant reader file. The "total_len" field is
+ * the length in bytes of the VHCL node of the
+ * pak file. The VHCL node is the first node
+ * beneath the header node, and contains all of
+ * the _numerical_ information about the vehicle,
+ * such as the introduction date, running costs,
+ * etc.. Text (including filenames of sound files),
+ * and graphics are _not_ part of the VHCL node,
+ * and therefore do not count towards total length.
+ * Furthermore, the third argument to the node.write
+ * method must ascend sequentially with the number
+ * of bytes written so far (up 1 for a uint8, 2 for
+ * a uint16, 4 for a uint32 and so forth). Failure
+ * to observe these rules will result in data
+ * corruption and errors when the pak file is read
+ * by the main program.
+ * @author of note: jamespetts
*/
void vehicle_writer_t::write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj)
{
int i;
uint8 uv8;
- int total_len = 31;
+ int total_len = 48;
- // prissi: must be done here, since it may affect the len of the header!
+ // prissi: must be done here, since it may affect the length of the header!
cstring_t sound_str = ltrim( obj.get("sound") );
sint8 sound_id=NO_SOUND;
if (sound_str.len() > 0) {
@@ -85,6 +106,16 @@ void vehicle_writer_t::write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj
// Hajo: Version needs high bit set as trigger -> this is required
// as marker because formerly nodes were unversionend
uint16 version = 0x8008;
+
+ // This is the overlay flag for Simutrans-Experimental
+ // This sets the *second* highest bit to 1.
+ version |= EXP_VER;
+
+ // Finally, this is the experimental version number. This is *added*
+ // to the standard version number, to be subtracted again when read.
+ // Start at 0x100 and increment in hundreds (hex).
+ version += 0x100;
+
node.write_uint16(fp, version, 0);
@@ -141,7 +172,6 @@ void vehicle_writer_t::write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj
uint16 gear = (obj.get_int("gear", 100) * 64) / 100;
node.write_uint16(fp, gear, 22);
-
// Hajodoc: Type of way this vehicle drives on
// Hajoval: road, track, electrified_track, monorail_track, maglev_track, water
const char* waytype = obj.get("waytype");
@@ -159,6 +189,7 @@ void vehicle_writer_t::write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj
xref_writer_t::instance()->write_obj(fp, node, obj_smoke, obj.get("smoke"), false);
// Jetzt kommen die Bildlisten
+ // "Now the picture lists" (Google)
static const char* const dir_codes[] = {
"s", "w", "sw", "se", "n", "e", "ne", "nw"
};
@@ -185,7 +216,7 @@ void vehicle_writer_t::write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj
for (i = 0; i < 8; i++) {
char buf[40];
- // Hajodoc: Empty vehicle image for direction, direction in "s", "w", "sw", "se", unsymmetric vehicles need also "n", "e", "ne", "nw"
+ // Hajodoc: Empty vehicle image for direction, direction in "s", "w", "sw", "se", asymmetric vehicles need also "n", "e", "ne", "nw"
sprintf(buf, "emptyimage[%s]", dir_codes[i]);
str = obj.get(buf);
if (str.len() > 0) {
@@ -245,6 +276,7 @@ void vehicle_writer_t::write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj
//
// Vorgänger/Nachfolgerbedingungen
+ // "Predecessor / Successor conditions" (Google)
//
uint8 besch_vorgaenger = 0;
do {
@@ -282,6 +314,23 @@ void vehicle_writer_t::write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj
}
} while (str.len() > 0);
+ // Upgrades: these are the vehicle types to which this vehicle
+ // can be upgraded. "None" means that it cannot be upgraded.
+ uint8 upgrades = 0;
+ do {
+ char buf[40];
+ sprintf(buf, "upgrade[%d]", upgrades);
+ str = obj.get(buf);
+ if (str.len() > 0) {
+ if (upgrades == 0 && !STRICMP(str, "none"))
+ {
+ str = "";
+ }
+ xref_writer_t::instance()->write_obj(fp, node, obj_vehicle, str, false);
+ upgrades++;
+ }
+ } while (str.len() > 0);
+
// multiple freight image types - define what good uses each index
// good without index will be an error
for (i = 0; i <= freight_max; i++) {
@@ -328,10 +377,103 @@ void vehicle_writer_t::write_obj(FILE* fp, obj_node_t& parent, tabfileobj_t& obj
node.write_sint8(fp, besch_nachfolger, 29);
node.write_uint8(fp, (uint8) freight_max, 30);
+ // Whether this is a tilting train
+ // int
+ //@author: jamespetts
+ uint8 tilting = (obj.get_int("is_tilting", 0));
+ node.write_uint8(fp, tilting, 31);
+
+ // Way constraints
+ // One byte for permissive, one byte for prohibitive.
+ // Therefore, 8 possible constraints of each type.
+ // Permissive: way allows vehicles with matching constraint:
+ // vehicles not allowed on any other sort of way. Vehicles
+ // without that constraint also allowed on the way.
+ // Prohibitive: way allows only vehicles with matching constraint:
+ // vehicles with matching constraint allowed on other sorts of way.
+ // @author: jamespetts
+
+ uint8 permissive_way_constraints = 0;
+ uint8 prohibitive_way_constraints = 0;
+ char buf_permissive[60];
+ char buf_prohibitive[60];
+ //Read the values from a file, and put them into an array.
+ for(uint8 i = 0; i < 8; i++)
+ {
+ sprintf(buf_permissive, "way_constraint_permissive[%d]", i);
+ sprintf(buf_prohibitive, "way_constraint_prohibitive[%d]", i);
+ uint8 tmp_permissive = (obj.get_int(buf_permissive, 255));
+ uint8 tmp_prohibitive = (obj.get_int(buf_prohibitive, 255));
+
+ //Compress values into a single byte using bitwise OR.
+ if(tmp_permissive < 8)
+ {
+ permissive_way_constraints = (tmp_permissive > 0) ? permissive_way_constraints | (uint8)pow(2, (double)tmp_permissive) : permissive_way_constraints | 1;
+ }
+ if(tmp_prohibitive < 8)
+ {
+ prohibitive_way_constraints = (tmp_prohibitive > 0) ? prohibitive_way_constraints | (uint8)pow(2, (double)tmp_prohibitive) : prohibitive_way_constraints | 1;
+ }
+ }
+ node.write_uint8(fp, permissive_way_constraints, 32);
+ node.write_uint8(fp, prohibitive_way_constraints, 33);
+
+ // Catering level. 0 = no catering.
+ // Higher numbers, better catering.
+ // Catering boosts passenger revenue.
+ // @author: jamespetts
+ uint8 catering_level = (obj.get_int("catering_level", 0));
+ node.write_uint8(fp, catering_level, 34);
+
+ //Reverseing settings.
+ //@author: jamespetts
+
+ // Bidirectional: vehicle can travel backwards without turning around.
+ // Function is disabled for road and air vehicles.
+ uint8 bidirectional = (obj.get_int("bidirectional", 0));
+ node.write_uint8(fp, bidirectional, 35);
+
+ // Can lead from rear: train can run backwards without turning around.
+ uint8 can_lead_from_rear = (obj.get_int("can_lead_from_rear", 0));
+ node.write_uint8(fp, can_lead_from_rear, 36);
+
+ // Passenger comfort rating - affects revenue on longer journies.
+ //@author: jamespetts
+ uint8 comfort = (obj.get_int("comfort", 100));
+ node.write_uint8(fp, comfort, 37);
+
+ // Overcrowded capacity - can take this much *in addition to* normal capacity,
+ // but revenue will be lower and dwell times higher. Mainly for passengers.
+ //@author: jamespetts
+ uint16 overcrowded_capacity = (obj.get_int("overcrowded_capacity", 0));
+ node.write_uint8(fp, overcrowded_capacity, 38);
+
+ // The time that it takes the vehicle to load and unload at stations (i.e., the
+ // dwell time). The default is 2,000 because that is the value used in Simutrans-
+ // Standard.
+ //@author: jamespetts
+ uint16 loading_time = (obj.get_int("loading_time", 2000));
+ node.write_uint16(fp, loading_time, 40);
+
+ // Upgrading settings
+ //@author: jamespetts
+
+ node.write_sint8(fp, upgrades, 42);
+
+ // This is the cost of upgrading to this vehicle, rather than buying it new.
+ // By default, the cost is the same as a new purchase.
+ uint32 upgrade_price = (obj.get_int("upgrade_price", cost));
+ node.write_uint32(fp, upgrade_price, 43);
+
+ // If this is set to true (is read as a bool), this will only be able to be purchased
+ // as an upgrade to another vehicle, not as a new vehicle.
+ uint8 available_only_as_upgrade = (obj.get_int("available_only_as_upgrade", 0));
+ node.write_uint8(fp, available_only_as_upgrade, 47);
+
sint8 sound_str_len = sound_str.len();
if (sound_str_len > 0) {
- node.write_sint8 (fp, sound_str_len, 31);
- node.write_data_at(fp, sound_str, 32, sound_str_len);
+ node.write_sint8 (fp, sound_str_len, 48);
+ node.write_data_at(fp, sound_str, 49, sound_str_len);
}
node.write(fp);
diff --git a/besch/writer/way_obj_writer.cc b/besch/writer/way_obj_writer.cc
index c5cfcc356d8..6bd5c1149e5 100644
--- a/besch/writer/way_obj_writer.cc
+++ b/besch/writer/way_obj_writer.cc
@@ -1,3 +1,4 @@
+#include
#include "../../utils/cstring_t.h"
#include "../../dataobj/tabfile.h"
#include "obj_node.h"
@@ -21,12 +22,22 @@ void way_obj_writer_t::write_obj(FILE* outfp, obj_node_t& parent, tabfileobj_t&
};
int ribi, hang;
- obj_node_t node(this, 20, &parent);
+ obj_node_t node(this, 22, &parent);
// Hajo: Version needs high bit set as trigger -> this is required
// as marker because formerly nodes were unversionend
uint16 version = 0x8001;
+
+ // This is the overlay flag for Simutrans-Experimental
+ // This sets the *second* highest bit to 1.
+ version |= EXP_VER;
+
+ // Finally, this is the experimental version number. This is *added*
+ // to the standard version number, to be subtracted again when read.
+ // Start at 0x100 and increment in hundreds (hex).
+ version += 0x100;
+
uint32 price = obj.get_int("cost", 100);
uint32 maintenance = obj.get_int("maintenance", 100);
uint32 topspeed = obj.get_int("topspeed", 999);
@@ -40,14 +51,49 @@ void way_obj_writer_t::write_obj(FILE* outfp, obj_node_t& parent, tabfileobj_t&
uint8 wtyp = get_waytype(obj.get("waytype"));
uint8 own_wtyp = get_waytype(obj.get("own_waytype"));
- node.write_uint16(outfp, version, 0);
- node.write_uint32(outfp, price, 2);
- node.write_uint32(outfp, maintenance, 6);
- node.write_uint32(outfp, topspeed, 10);
- node.write_uint16(outfp, intro, 14);
- node.write_uint16(outfp, retire, 16);
- node.write_uint8 (outfp, wtyp, 18);
- node.write_uint8 (outfp, own_wtyp, 19);
+ // Way constraints
+ // One byte for permissive, one byte for prohibitive.
+ // Therefore, 8 possible constraints of each type.
+ // Permissive: way allows vehicles with matching constraint:
+ // vehicles not allowed on any other sort of way. Vehicles
+ // without that constraint also allowed on the way.
+ // Prohibitive: way allows only vehicles with matching constraint:
+ // vehicles with matching constraint allowed on other sorts of way.
+ // @author: jamespetts
+
+ uint8 permissive_way_constraints = 0;
+ uint8 prohibitive_way_constraints = 0;
+ char buf_permissive[60];
+ char buf_prohibitive[60];
+ //Read the values from a file, and put them into an array.
+ for(uint8 i = 0; i < 8; i++)
+ {
+ sprintf(buf_permissive, "way_constraint_permissive[%d]", i);
+ sprintf(buf_prohibitive, "way_constraint_prohibitive[%d]", i);
+ uint8 tmp_permissive = (obj.get_int(buf_permissive, 255));
+ uint8 tmp_prohibitive = (obj.get_int(buf_prohibitive, 255));
+
+ //Compress values into a single byte using bitwise OR.
+ if(tmp_permissive < 8)
+ {
+ permissive_way_constraints = (tmp_permissive > 0) ? permissive_way_constraints | (uint8)pow(2, (double)tmp_permissive) : permissive_way_constraints | 1;
+ }
+ if(tmp_prohibitive < 8)
+ {
+ prohibitive_way_constraints = (tmp_prohibitive > 0) ? prohibitive_way_constraints | (uint8)pow(2, (double)tmp_prohibitive) : prohibitive_way_constraints | 1;
+ }
+ }
+
+ node.write_uint16(outfp, version, 0);
+ node.write_uint32(outfp, price, 2);
+ node.write_uint32(outfp, maintenance, 6);
+ node.write_uint32(outfp, topspeed, 10);
+ node.write_uint16(outfp, intro, 14);
+ node.write_uint16(outfp, retire, 16);
+ node.write_uint8 (outfp, wtyp, 18);
+ node.write_uint8 (outfp, own_wtyp, 19);
+ node.write_uint8(outfp, permissive_way_constraints, 20);
+ node.write_uint8(outfp, prohibitive_way_constraints,21);
write_head(outfp, node, obj);
diff --git a/besch/writer/way_writer.cc b/besch/writer/way_writer.cc
index fc48ca9099f..a01348f5409 100644
--- a/besch/writer/way_writer.cc
+++ b/besch/writer/way_writer.cc
@@ -1,3 +1,4 @@
+#include
#include "../../utils/cstring_t.h"
#include "../../dataobj/tabfile.h"
#include "obj_node.h"
@@ -21,13 +22,23 @@ void way_writer_t::write_obj(FILE* outfp, obj_node_t& parent, tabfileobj_t& obj)
};
int ribi, hang;
- // Hajo: node size is 25 bytes
- obj_node_t node(this, 26, &parent);
+ // Hajo: node size is 27 bytes
+ obj_node_t node(this, 28, &parent);
// Hajo: Version needs high bit set as trigger -> this is required
// as marker because formerly nodes were unversionend
uint16 version = 0x8004;
+
+ // This is the overlay flag for Simutrans-Experimental
+ // This sets the *second* highest bit to 1.
+ version |= EXP_VER;
+
+ // Finally, this is the experimental version number. This is *added*
+ // to the standard version number, to be subtracted again when read.
+ // Start at 0x100 and increment in hundreds (hex).
+ version += 0x100;
+
uint32 price = obj.get_int("cost", 100);
uint32 maintenance = obj.get_int("maintenance", 100);
uint32 topspeed = obj.get_int("topspeed", 999);
@@ -52,16 +63,51 @@ void way_writer_t::write_obj(FILE* outfp, obj_node_t& parent, tabfileobj_t& obj)
uint8 draw_as_ding = (obj.get_int("draw_as_ding", 0) == 1);
sint8 number_seasons = 0;
- node.write_uint16(outfp, version, 0);
- node.write_uint32(outfp, price, 2);
- node.write_uint32(outfp, maintenance, 6);
- node.write_uint32(outfp, topspeed, 10);
- node.write_uint32(outfp, max_weight, 14);
- node.write_uint16(outfp, intro, 18);
- node.write_uint16(outfp, retire, 20);
- node.write_uint8 (outfp, wtyp, 22);
- node.write_uint8 (outfp, styp, 23);
- node.write_uint8 (outfp, draw_as_ding, 24);
+ // Way constraints
+ // One byte for permissive, one byte for prohibitive.
+ // Therefore, 8 possible constraints of each type.
+ // Permissive: way allows vehicles with matching constraint:
+ // vehicles not allowed on any other sort of way. Vehicles
+ // without that constraint also allowed on the way.
+ // Prohibitive: way allows only vehicles with matching constraint:
+ // vehicles with matching constraint allowed on other sorts of way.
+ // @author: jamespetts
+
+ uint8 permissive_way_constraints = 0;
+ uint8 prohibitive_way_constraints = 0;
+ char buf_permissive[60];
+ char buf_prohibitive[60];
+ //Read the values from a file, and put them into an array.
+ for(uint8 i = 0; i < 8; i++)
+ {
+ sprintf(buf_permissive, "way_constraint_permissive[%d]", i);
+ sprintf(buf_prohibitive, "way_constraint_prohibitive[%d]", i);
+ uint8 tmp_permissive = (obj.get_int(buf_permissive, 255));
+ uint8 tmp_prohibitive = (obj.get_int(buf_prohibitive, 255));
+
+ //Compress values into a single byte using bitwise OR.
+ if(tmp_permissive < 8)
+ {
+ permissive_way_constraints = (tmp_permissive > 0) ? permissive_way_constraints | (uint8)pow(2, (double)tmp_permissive) : permissive_way_constraints | 1;
+ }
+ if(tmp_prohibitive < 8)
+ {
+ prohibitive_way_constraints = (tmp_prohibitive > 0) ? prohibitive_way_constraints | (uint8)pow(2, (double)tmp_prohibitive) : prohibitive_way_constraints | 1;
+ }
+ }
+
+ node.write_uint16(outfp, version, 0);
+ node.write_uint32(outfp, price, 2);
+ node.write_uint32(outfp, maintenance, 6);
+ node.write_uint32(outfp, topspeed, 10);
+ node.write_uint32(outfp, max_weight, 14);
+ node.write_uint16(outfp, intro, 18);
+ node.write_uint16(outfp, retire, 20);
+ node.write_uint8 (outfp, wtyp, 22);
+ node.write_uint8 (outfp, styp, 23);
+ node.write_uint8 (outfp, draw_as_ding, 24);
+ node.write_uint8(outfp, permissive_way_constraints, 26);
+ node.write_uint8(outfp, prohibitive_way_constraints,27);
slist_tpl keys;
char buf[40];
diff --git a/boden/grund.cc b/boden/grund.cc
index 5f9d269c08c..c8c661e12b0 100644
--- a/boden/grund.cc
+++ b/boden/grund.cc
@@ -227,6 +227,8 @@ void grund_t::rdwr(loadsave_t *file)
w->set_besch(sch->get_besch());
w->set_max_speed(sch->get_max_speed());
w->set_ribi(sch->get_ribi_unmasked());
+ weg->set_max_weight(sch->get_max_weight());
+ weg->add_way_constraints(sch->get_way_constraints_permissive(), sch->get_way_constraints_prohibitive());
delete sch;
weg = w;
}
diff --git a/boden/wege/kanal.cc b/boden/wege/kanal.cc
index a15af0b8632..30bea37b1cb 100644
--- a/boden/wege/kanal.cc
+++ b/boden/wege/kanal.cc
@@ -66,5 +66,6 @@ kanal_t::rdwr(loadsave_t *file)
if(old_max_speed>0) {
set_max_speed(old_max_speed);
}
+
}
}
diff --git a/boden/wege/maglev.cc b/boden/wege/maglev.cc
index 2051d0499aa..c8c12bfb65d 100644
--- a/boden/wege/maglev.cc
+++ b/boden/wege/maglev.cc
@@ -28,11 +28,16 @@ maglev_t::rdwr(loadsave_t *file)
if(get_besch()->get_wtyp()!=maglev_wt) {
int old_max_speed = get_max_speed();
+ int old_max_weight = get_max_weight();
const weg_besch_t *besch = wegbauer_t::weg_search( maglev_wt, (old_max_speed>0 ? old_max_speed : 120), 0, (weg_t::system_type)((get_besch()->get_styp()==weg_t::type_elevated)*weg_t::type_elevated) );
dbg->warning("maglev_t::rwdr()", "Unknown way replaced by maglev %s (old_max_speed %i)", besch->get_name(), old_max_speed );
set_besch(besch);
- if(old_max_speed>0) {
+ if(old_max_speed > 0) {
set_max_speed(old_max_speed);
}
+ if(old_max_weight > 0)
+ {
+ set_max_weight(old_max_weight);
+ }
}
}
diff --git a/boden/wege/monorail.cc b/boden/wege/monorail.cc
index 688065bef12..279ea362ebb 100644
--- a/boden/wege/monorail.cc
+++ b/boden/wege/monorail.cc
@@ -23,11 +23,16 @@ void monorail_t::rdwr(loadsave_t *file)
if(get_besch()->get_wtyp()!=monorail_wt) {
int old_max_speed = get_max_speed();
+ int old_max_weight = get_max_weight();
const weg_besch_t *besch = wegbauer_t::weg_search( monorail_wt, (old_max_speed>0 ? old_max_speed : 120), 0, (weg_t::system_type)((get_besch()->get_styp()==weg_t::type_elevated)*weg_t::type_elevated) );
dbg->warning("monorail_t::rwdr()", "Unknown way replaced by monorail %s (old_max_speed %i)", besch->get_name(), old_max_speed );
set_besch(besch);
if(old_max_speed>0) {
set_max_speed(old_max_speed);
}
+ if(old_max_weight > 0)
+ {
+ set_max_weight(old_max_weight);
+ }
}
}
diff --git a/boden/wege/narrowgauge.cc b/boden/wege/narrowgauge.cc
index 922b2e40584..cd75228b6ec 100644
--- a/boden/wege/narrowgauge.cc
+++ b/boden/wege/narrowgauge.cc
@@ -24,11 +24,16 @@ narrowgauge_t::rdwr(loadsave_t *file)
if(get_besch()->get_wtyp()!=narrowgauge_wt) {
int old_max_speed = get_max_speed();
+ int old_max_weight = get_max_weight();
const weg_besch_t *besch = wegbauer_t::weg_search( narrowgauge_wt, (old_max_speed>0 ? old_max_speed : 120), 0, (weg_t::system_type)((get_besch()->get_styp()==weg_t::type_elevated)*weg_t::type_elevated) );
dbg->warning("narrowgauge_t::rwdr()", "Unknown way replaced by narrow gauge %s (old_max_speed %i)", besch->get_name(), old_max_speed );
set_besch(besch);
if(old_max_speed>0) {
set_max_speed(old_max_speed);
}
+ if(old_max_weight > 0)
+ {
+ set_max_weight(old_max_weight);
+ }
}
}
diff --git a/boden/wege/schiene.cc b/boden/wege/schiene.cc
index f1ac67b58a2..b2da76083af 100644
--- a/boden/wege/schiene.cc
+++ b/boden/wege/schiene.cc
@@ -165,6 +165,7 @@ schiene_t::rdwr(loadsave_t *file)
file->rdwr_str(bname, 128 );
int old_max_speed=get_max_speed();
+ int old_max_weight = get_max_weight();
const weg_besch_t *besch = wegbauer_t::get_besch(bname);
if(besch==NULL) {
int old_max_speed=get_max_speed();
@@ -179,5 +180,10 @@ schiene_t::rdwr(loadsave_t *file)
set_max_speed(old_max_speed);
}
//DBG_MESSAGE("schiene_t::rdwr","track %s at (%i,%i) max_speed %i",bname,get_pos().x,get_pos().y,old_max_speed);
+ if(old_max_weight > 0)
+ {
+ set_max_weight(old_max_weight);
+ }
+ //DBG_MESSAGE("schiene_t::rdwr","track %s at (%i,%i) max_speed %i",bname,get_pos().x,get_pos().y,old_max_speed);
}
}
diff --git a/boden/wege/weg.cc b/boden/wege/weg.cc
index 40d191db806..4698fd97f84 100644
--- a/boden/wege/weg.cc
+++ b/boden/wege/weg.cc
@@ -134,21 +134,45 @@ void weg_t::set_max_speed(unsigned int s)
max_speed = s;
}
+void weg_t::set_max_weight(uint32 w)
+{
+ max_weight = w;
+}
+
+void weg_t::add_way_constraints(const uint8 permissive, const uint8 prohibitive)
+{
+ way_constraints_permissive |= permissive;
+ way_constraints_prohibitive |= prohibitive;
+}
+
+void weg_t::reset_way_constraints()
+{
+ way_constraints_permissive = besch->get_way_constraints_permissive();
+ way_constraints_prohibitive = besch->get_way_constraints_prohibitive();
+}
+
/**
* Setzt neue Beschreibung. Ersetzt alte Höchstgeschwindigkeit
* mit wert aus Beschreibung.
+ *
+ * "Sets new description. Replaced old with maximum speed value of description." (Google)
* @author Hj. Malthaner
*/
void weg_t::set_besch(const weg_besch_t *b)
{
besch = b;
if (hat_gehweg() && besch->get_wtyp() == road_wt && besch->get_topspeed() > 50) {
+ //Limit speeds for city roads.
max_speed = 50;
}
else {
max_speed = besch->get_topspeed();
}
+
+ max_weight = besch->get_max_weight();
+ way_constraints_permissive = besch->get_way_constraints_permissive();
+ way_constraints_prohibitive = besch->get_way_constraints_prohibitive();
}
@@ -175,6 +199,7 @@ void weg_t::init()
set_flag(ding_t::is_wayding);
ribi = ribi_maske = ribi_t::keine;
max_speed = 450;
+ max_weight = 999;
besch = 0;
init_statistics();
alle_wege.insert(this);
@@ -234,6 +259,13 @@ void weg_t::rdwr(loadsave_t *file)
// DBG_DEBUG("weg_t::rdwr()", "statistics[%d][%d]=%d", month, type, statistics[month][type]);
}
}
+
+ if(file->get_experimental_version() >= 1)
+ {
+ uint16 wdummy16 = max_weight;
+ file->rdwr_short(wdummy16, "\n");
+ max_weight = wdummy16;
+ }
}
@@ -249,13 +281,34 @@ void weg_t::info(cbuffer_t & buf) const
buf.append(max_speed);
buf.append(translator::translate("km/h\n"));
+ buf.append(translator::translate("\nMax. weight:"));
+ buf.append(" ");
+ buf.append(max_weight);
+ buf.append("t ");
+ buf.append("\n");
+ for(sint8 i = -8; i < 8; i ++)
+ {
+ if(permissive_way_constraint_set(i + 8))
+ {
+ buf.append(translator::translate("Way constraint permissive "));
+ buf.append(i);
+ buf.append("\n");
+ }
+ if(prohibitive_way_constraint_set(i))
+ {
+ buf.append(translator::translate("Way constraint prohibitive %n\n"));
+ buf.append(i);
+ buf.append("\n");
+ }
+ }
+#ifdef DEBUG
buf.append(translator::translate("\nRibi (unmasked)"));
buf.append(get_ribi_unmasked());
buf.append(translator::translate("\nRibi (masked)"));
buf.append(get_ribi());
buf.append("\n");
-
+#endif
if(has_sign()) {
buf.append(translator::translate("\nwith sign/signal\n"));
}
diff --git a/boden/wege/weg.h b/boden/wege/weg.h
index e79a5ef0b70..4adddf861ff 100644
--- a/boden/wege/weg.h
+++ b/boden/wege/weg.h
@@ -107,6 +107,12 @@ class weg_t : public ding_t
*/
uint16 max_speed;
+ /**
+ * Likewise for weight
+ * @author: jamespetts
+ */
+ uint32 max_weight;
+
image_id bild;
/**
@@ -121,6 +127,11 @@ class weg_t : public ding_t
*/
void init_statistics();
+ /*Way constraints for, e.g., loading gauges, types of electrification, etc.
+ * @author: jamespetts*/
+ uint8 way_constraints_permissive;
+ uint8 way_constraints_prohibitive;
+
public:
weg_t(karte_t* welt, loadsave_t*) : ding_t(welt) { init(); }
@@ -140,15 +151,43 @@ class weg_t : public ding_t
*/
void set_max_speed(unsigned int s);
+ void set_max_weight(uint32 w);
+
+ //Adds the way constraints to the way. Note: does *not* replace them - they are added together.
+ void add_way_constraints(const uint8 permissive, const uint8 prohibitive);
+
+ //Resets constraints to their base values. Used when removing way objects.
+ void reset_way_constraints();
+
+ uint8 get_way_constraints_permissive() const { return way_constraints_permissive; }
+ uint8 get_way_constraints_prohibitive() const { return way_constraints_prohibitive; }
+
+
+ bool permissive_way_constraint_set(uint8 i) const
+ {
+ return (way_constraints_permissive & 1<get_version()>101000) {
file->rdwr_bool( seperate_halt_capacities, "" );
- file->rdwr_byte( pay_for_total_distance, "" );
+ if(file->get_experimental_version() < 2)
+ {
+ // Was pay for total distance.
+ // Now depracated.
+ uint8 dummy;
+ file->rdwr_byte( dummy, "" );
+ }
file->rdwr_short(starting_month, "");
@@ -455,9 +550,162 @@ void einstellungen_t::rdwr(loadsave_t *file)
if(file->get_version()>102000) {
file->rdwr_bool( avoid_overcrowding, "" );
}
- if(file->get_version()>102001) {
+#ifndef NEW_PATHING
+ if(file->get_version()>102001)
+ {
file->rdwr_bool( no_routing_over_overcrowding, "" );
}
+#else
+ if(file->get_version()>102001)
+ {
+ bool dummy;
+ file->rdwr_bool(dummy, "" );
+ }
+#endif
+ if(file->get_experimental_version() >= 1)
+ {
+ file->rdwr_short(min_bonus_max_distance, "");
+ file->rdwr_short(max_bonus_min_distance, "");
+ if(file->get_experimental_version() == 1)
+ {
+ uint16 dummy;
+ file->rdwr_short(dummy, "");
+ }
+ else
+ {
+ file->rdwr_short(median_bonus_distance, "");
+ file->rdwr_short(max_bonus_multiplier_percent, "");
+ file->rdwr_short(journey_time_multiplier_percent, "");
+ file->rdwr_byte(tolerable_comfort_short, "");
+ file->rdwr_byte(tolerable_comfort_median_short, "");
+ file->rdwr_byte(tolerable_comfort_median_median, "");
+ file->rdwr_byte(tolerable_comfort_median_long, "");
+ file->rdwr_byte(tolerable_comfort_long, "");
+ file->rdwr_short(tolerable_comfort_short_minutes, "");
+ file->rdwr_short(tolerable_comfort_median_short_minutes, "");
+ file->rdwr_short(tolerable_comfort_median_median_minutes, "");
+ file->rdwr_short(tolerable_comfort_median_long_minutes, "");
+ file->rdwr_short(tolerable_comfort_long_minutes, "");
+ file->rdwr_byte(max_luxury_bonus_differential, "");
+ file->rdwr_byte(max_discomfort_penalty_differential, "");
+ file->rdwr_short(max_discomfort_penalty_percent, "");
+ file->rdwr_short(max_luxury_bonus_percent, "");
+
+ file->rdwr_short(catering_min_minutes, "");
+ file->rdwr_short(catering_level1_minutes, "");
+ file->rdwr_short(catering_level1_max_revenue, "");
+ file->rdwr_short(catering_level2_minutes, "");
+ file->rdwr_short(catering_level2_max_revenue, "");
+ file->rdwr_short(catering_level3_minutes, "");
+ file->rdwr_short(catering_level3_max_revenue, "");
+ file->rdwr_short(catering_level4_minutes, "");
+ file->rdwr_short(catering_level4_max_revenue, "");
+ file->rdwr_short(catering_level5_minutes, "");
+ file->rdwr_short(catering_level5_max_revenue, "");
+
+ file->rdwr_short(tpo_min_minutes, "");
+ file->rdwr_short(tpo_revenue, "");
+ }
+
+ file->rdwr_short(obsolete_running_cost_increase_percent, "");
+ file->rdwr_short(obsolete_running_cost_increase_phase_years, "");
+
+ file->rdwr_short(local_passengers_min_distance, "");
+ file->rdwr_short(local_passengers_max_distance, "");
+ file->rdwr_short(midrange_passengers_min_distance, "");
+ file->rdwr_short(midrange_passengers_max_distance, "");
+ file->rdwr_short(longdistance_passengers_min_distance, "");
+ file->rdwr_short(longdistance_passengers_max_distance, "");
+
+ file->rdwr_byte(passenger_routing_packet_size, "");
+ file->rdwr_byte(max_alternative_destinations, "");
+ file->rdwr_byte(passenger_routing_local_chance, "");
+ file->rdwr_byte(passenger_routing_midrange_chance, "");
+ file->rdwr_byte(base_car_preference_percent, "");
+ file->rdwr_byte(always_prefer_car_percent, "");
+ file->rdwr_byte(congestion_density_factor, "");
+
+ file->rdwr_long(max_corner_limit[waytype_t(road_wt)], "");
+ file->rdwr_long(min_corner_limit[waytype_t(road_wt)], "");
+ double tmp = (double)max_corner_adjustment_factor[waytype_t(road_wt)];
+ file->rdwr_double(tmp);
+ tmp = (double)min_corner_adjustment_factor[waytype_t(road_wt)];
+ file->rdwr_double(tmp);
+ file->rdwr_byte(min_direction_steps[waytype_t(road_wt)], "");
+ file->rdwr_byte(max_direction_steps[waytype_t(road_wt)], "");
+ file->rdwr_byte(curve_friction_factor[waytype_t(road_wt)], "");
+
+ file->rdwr_long(max_corner_limit[waytype_t(track_wt)], "");
+ file->rdwr_long(min_corner_limit[waytype_t(track_wt)], "");
+ tmp = (double)max_corner_adjustment_factor[waytype_t(track_wt)];
+ file->rdwr_double(tmp);
+ tmp = (double)min_corner_adjustment_factor[waytype_t(track_wt)];
+ file->rdwr_double(tmp);
+ file->rdwr_byte(min_direction_steps[waytype_t(track_wt)], "");
+ file->rdwr_byte(max_direction_steps[waytype_t(track_wt)], "");
+ file->rdwr_byte(curve_friction_factor[waytype_t(track_wt)], "");
+
+ file->rdwr_long(max_corner_limit[waytype_t(tram_wt)], "");
+ file->rdwr_long(min_corner_limit[waytype_t(tram_wt)], "");
+ tmp = (double)max_corner_adjustment_factor[waytype_t(tram_wt)];
+ file->rdwr_double(tmp);
+ tmp = (double)min_corner_adjustment_factor[waytype_t(tram_wt)];
+ file->rdwr_double(tmp);
+ file->rdwr_byte(min_direction_steps[waytype_t(tram_wt)], "");
+ file->rdwr_byte(max_direction_steps[waytype_t(tram_wt)], "");
+ file->rdwr_byte(curve_friction_factor[waytype_t(tram_wt)], "");
+
+ file->rdwr_long(max_corner_limit[waytype_t(monorail_wt)], "");
+ file->rdwr_long(min_corner_limit[waytype_t(monorail_wt)], "");
+ tmp = (double)max_corner_adjustment_factor[waytype_t(monorail_wt)];
+ file->rdwr_double(tmp);
+ tmp = (double)min_corner_adjustment_factor[waytype_t(monorail_wt)];
+ file->rdwr_double(tmp);
+ file->rdwr_byte(min_direction_steps[waytype_t(monorail_wt)], "");
+ file->rdwr_byte(max_direction_steps[waytype_t(monorail_wt)], "");
+ file->rdwr_byte(curve_friction_factor[waytype_t(monorail_wt)], "");
+
+ file->rdwr_long(max_corner_limit[waytype_t(maglev_wt)], "");
+ file->rdwr_long(min_corner_limit[waytype_t(maglev_wt)], "");
+ tmp = (double)max_corner_adjustment_factor[waytype_t(maglev_wt)];
+ file->rdwr_double(tmp);
+ tmp = (double)min_corner_adjustment_factor[waytype_t(maglev_wt)];
+ file->rdwr_double(tmp);
+ file->rdwr_byte(min_direction_steps[waytype_t(maglev_wt)], "");
+ file->rdwr_byte(max_direction_steps[waytype_t(maglev_wt)], "");
+ file->rdwr_byte(curve_friction_factor[waytype_t(maglev_wt)], "");
+
+ file->rdwr_long(max_corner_limit[waytype_t(narrowgauge_wt)], "");
+ file->rdwr_long(min_corner_limit[waytype_t(narrowgauge_wt)], "");
+ tmp = (double)max_corner_adjustment_factor[waytype_t(narrowgauge_wt)];
+ file->rdwr_double(tmp);
+ tmp = min_corner_adjustment_factor[waytype_t(narrowgauge_wt)];
+ file->rdwr_double(tmp);
+ file->rdwr_byte(min_direction_steps[waytype_t(narrowgauge_wt)], "");
+ file->rdwr_byte(max_direction_steps[waytype_t(narrowgauge_wt)], "");
+ file->rdwr_byte(curve_friction_factor[waytype_t(narrowgauge_wt)], "");
+
+ file->rdwr_short(factory_max_years_obsolete, "");
+
+ file->rdwr_byte(interest_rate_percent, "");
+ file->rdwr_bool(allow_bankruptsy, "");
+ file->rdwr_bool(allow_purhcases_when_insolvent, "");
+
+ file->rdwr_short(unit_reverse_time, "");
+ file->rdwr_short(hauled_reverse_time, "");
+ file->rdwr_short(turntable_reverse_time, "");
+
+ }
+
+ if(file->get_experimental_version() >= 2)
+ {
+ uint16 global_power_factor_percent = global_power_factor * 100;
+ file->rdwr_short(global_power_factor_percent, "");
+ global_power_factor = (float)global_power_factor_percent / 100;
+ file->rdwr_short(passenger_max_wait, "");
+ file->rdwr_byte(max_rerouting_interval_months, "");
+ }
+
}
}
@@ -522,10 +770,12 @@ void einstellungen_t::parse_simuconf( tabfile_t &simuconf, sint16 &disp_width, s
max_transfers = contents.get_int("max_transfers", max_transfers );
passenger_factor = contents.get_int("passenger_factor", passenger_factor ); /* this can manipulate the passenger generation */
seperate_halt_capacities = contents.get_int("seperate_halt_capacities", seperate_halt_capacities ) != 0;
- pay_for_total_distance = contents.get_int("pay_for_total_distance", pay_for_total_distance );
avoid_overcrowding = contents.get_int("avoid_overcrowding", avoid_overcrowding )!=0;
+#ifndef NEW_PATHING
no_routing_over_overcrowding = contents.get_int("no_routing_over_overcrowded", no_routing_over_overcrowding )!=0;
-
+#endif
+ passenger_max_wait = contents.get_int("passenger_max_wait", passenger_max_wait);
+ max_rerouting_interval_months = contents.get_int("max_rerouting_interval_months", max_rerouting_interval_months);
fussgaenger = contents.get_int("random_pedestrians", fussgaenger ) != 0;
show_pax = contents.get_int("stop_pedestrians", show_pax ) != 0;
@@ -602,6 +852,142 @@ void einstellungen_t::parse_simuconf( tabfile_t &simuconf, sint16 &disp_width, s
way_max_bridge_len = contents.get_int("way_max_bridge_len", way_max_bridge_len);
way_count_leaving_road = contents.get_int("way_leaving_road", way_count_leaving_road);
+ // Revenue calibration settings
+ // @author: jamespetts
+ min_bonus_max_distance = contents.get_int("min_bonus_max_distance", min_bonus_max_distance);
+ max_bonus_min_distance = contents.get_int("max_bonus_min_distance", max_bonus_min_distance);
+ median_bonus_distance = contents.get_int("median_bonus_distance", median_bonus_distance);
+ max_bonus_multiplier_percent = contents.get_int("max_bonus_multiplier_percent", max_bonus_multiplier_percent);
+ journey_time_multiplier_percent = contents.get_int("journey_time_multiplier_percent", journey_time_multiplier_percent);
+ tolerable_comfort_short = contents.get_int("tolerable_comfort_short", tolerable_comfort_short);
+ tolerable_comfort_long = contents.get_int("tolerable_comfort_long", tolerable_comfort_long);
+ tolerable_comfort_short_minutes = contents.get_int("tolerable_comfort_short_minutes", tolerable_comfort_short_minutes);
+ tolerable_comfort_long_minutes = contents.get_int("tolerable_comfort_long_minutes", tolerable_comfort_long_minutes);
+ tolerable_comfort_median_short = contents.get_int("tolerable_comfort_median_short", tolerable_comfort_median_short);
+ tolerable_comfort_median_median = contents.get_int("tolerable_comfort_median_median", tolerable_comfort_median_median);
+ tolerable_comfort_median_long = contents.get_int("tolerable_comfort_median_long", tolerable_comfort_median_long);
+ tolerable_comfort_median_short_minutes = contents.get_int("tolerable_comfort_median_short_minutes", tolerable_comfort_median_short_minutes);
+ tolerable_comfort_median_short_minutes = contents.get_int("tolerable_comfort_median_median_minutes", tolerable_comfort_median_median_minutes);
+ tolerable_comfort_median_long_minutes = contents.get_int("tolerable_comfort_median_long_minutes", tolerable_comfort_median_long_minutes);
+ max_luxury_bonus_differential = contents.get_int("max_luxury_bonus_differential", max_luxury_bonus_differential);
+ max_discomfort_penalty_differential = contents.get_int("max_discomfort_penalty_differential", max_discomfort_penalty_differential);
+ max_luxury_bonus_percent = contents.get_int("max_luxury_bonus_percent", max_luxury_bonus_percent);
+ max_discomfort_penalty_percent = contents.get_int("max_discomfort_penalty_percent", max_discomfort_penalty_percent);
+
+ catering_min_minutes = contents.get_int("catering_min_minutes", catering_min_minutes);
+ catering_level1_minutes = contents.get_int("catering_level1_minutes", catering_level1_minutes);
+ catering_level1_max_revenue = contents.get_int("catering_level1_max_revenue", catering_level1_max_revenue);
+ catering_level2_minutes = contents.get_int("catering_level2_minutes", catering_level2_minutes);
+ catering_level2_max_revenue = contents.get_int("catering_level2_max_revenue", catering_level2_max_revenue);
+ catering_level3_minutes = contents.get_int("catering_level3_minutes", catering_level3_minutes);
+ catering_level3_max_revenue = contents.get_int("catering_level3_max_revenue", catering_level3_max_revenue);
+ catering_level4_minutes = contents.get_int("catering_level4_minutes", catering_level4_minutes);
+ catering_level4_max_revenue = contents.get_int("catering_level4_max_revenue", catering_level4_max_revenue);
+ catering_level5_minutes = contents.get_int("catering_level5_minutes", catering_level5_minutes);
+ catering_level5_max_revenue = contents.get_int("catering_level5_max_revenue", catering_level5_max_revenue);
+
+ tpo_min_minutes = contents.get_int("tpo_min_minutes", tpo_min_minutes);
+ tpo_revenue = contents.get_int("tpo_revenue", tpo_revenue);
+
+ // Obsolete vehicles' running cost increase
+ obsolete_running_cost_increase_percent = contents.get_int("obsolete_running_cost_increase_percent", obsolete_running_cost_increase_percent);
+ obsolete_running_cost_increase_phase_years = contents.get_int("obsolete_running_cost_increase_phase_years", obsolete_running_cost_increase_phase_years);
+
+ // Passenger destination ranges
+ local_passengers_min_distance = contents.get_int("local_passengers_min_distance", local_passengers_min_distance);
+ local_passengers_max_distance = contents.get_int("local_passengers_max_distance", local_passengers_max_distance);
+ midrange_passengers_min_distance = contents.get_int("midrange_passengers_min_distance", midrange_passengers_min_distance);
+ midrange_passengers_max_distance = contents.get_int("midrange_passengers_max_distance", midrange_passengers_max_distance);
+ longdistance_passengers_min_distance = contents.get_int("longdistance_passengers_min_distance", longdistance_passengers_min_distance);
+ longdistance_passengers_max_distance = contents.get_int("longdistance_passengers_max_distance", longdistance_passengers_max_distance);
+
+ // Passenger routing settings
+ passenger_routing_packet_size = contents.get_int("passenger_routing_packet_size", passenger_routing_packet_size);
+ max_alternative_destinations = contents.get_int("max_alternative_destinations", max_alternative_destinations);
+ passenger_routing_local_chance = contents.get_int("passenger_routing_local_chance ", passenger_routing_local_chance);
+ passenger_routing_midrange_chance = contents.get_int("passenger_routing_midrange_chance", passenger_routing_midrange_chance);
+ base_car_preference_percent = contents.get_int("base_car_preference_percent", base_car_preference_percent);
+ always_prefer_car_percent = contents.get_int("always_prefer_car_percent", always_prefer_car_percent);
+ congestion_density_factor = contents.get_int("congestion_density_factor", congestion_density_factor);
+
+ // Cornering settings
+ max_corner_limit[waytype_t(road_wt)] = contents.get_int("max_corner_limit_road", 200);
+ min_corner_limit[waytype_t(road_wt)] = contents.get_int("min_corner_limit_road", 30);
+ max_corner_adjustment_factor[waytype_t(road_wt)] = contents.get_int("max_corner_adjustment_factor_road", 75);
+ min_corner_adjustment_factor[waytype_t(road_wt)] = contents.get_int("min_corner_adjustment_factor_road", 97);
+ min_direction_steps[waytype_t(road_wt)] = contents.get_int("min_direction_steps_road", 3);
+ max_direction_steps[waytype_t(road_wt)] = contents.get_int("max_direction_steps_road", 6);
+ curve_friction_factor[waytype_t(road_wt)] = contents.get_int("curve_friction_factor_road", 0);
+
+ max_corner_limit[waytype_t(track_wt)] = contents.get_int("max_corner_limit_track", 425);
+ min_corner_limit[waytype_t(track_wt)] = contents.get_int("min_corner_limit_track", 45);
+ max_corner_adjustment_factor[waytype_t(track_wt)] = contents.get_int("max_corner_adjustment_factor_track", 50);
+ min_corner_adjustment_factor[waytype_t(track_wt)] = contents.get_int("min_corner_adjustment_factor_track", 85);
+ min_direction_steps[waytype_t(track_wt)] = contents.get_int("min_direction_steps_track", 4);
+ max_direction_steps[waytype_t(track_wt)] = contents.get_int("max_direction_steps_track", 14);
+ curve_friction_factor[waytype_t(track_wt)] = contents.get_int("curve_friction_factor_track", 0);
+
+ max_corner_limit[waytype_t(tram_wt)] = contents.get_int("max_corner_limit_tram", 425);
+ min_corner_limit[waytype_t(tram_wt)] = contents.get_int("min_corner_limit_tram", 45);
+ max_corner_adjustment_factor[waytype_t(tram_wt)] = contents.get_int("max_corner_adjustment_factor_tram", 50);
+ min_corner_adjustment_factor[waytype_t(tram_wt)] = contents.get_int("min_corner_adjustment_factor_tram", 85);
+ min_direction_steps[waytype_t(tram_wt)] = contents.get_int("min_direction_steps_tram", 4);
+ max_direction_steps[waytype_t(tram_wt)] = contents.get_int("max_direction_steps_tram", 14);
+ curve_friction_factor[waytype_t(tram_wt)] = contents.get_int("curve_friction_factor_tram", 0);
+
+ max_corner_limit[waytype_t(tram_wt)] = contents.get_int("max_corner_limit_tram", 250);
+ min_corner_limit[waytype_t(tram_wt)] = contents.get_int("min_corner_limit_tram", 30);
+ max_corner_adjustment_factor[waytype_t(tram_wt)] = contents.get_int("max_corner_adjustment_factor_tram", 60);
+ min_corner_adjustment_factor[waytype_t(tram_wt)] = contents.get_int("min_corner_adjustment_factor_tram", 90);
+ min_direction_steps[waytype_t(tram_wt)] = contents.get_int("min_direction_steps_tram", 3);
+ max_direction_steps[waytype_t(tram_wt)] = contents.get_int("max_direction_steps_tram", 10);
+ curve_friction_factor[waytype_t(tram_wt)] = contents.get_int("curve_friction_factor_tram", 0);
+
+ max_corner_limit[waytype_t(monorail_wt)] = contents.get_int("max_corner_limit_monorail", 425);
+ min_corner_limit[waytype_t(monorail_wt)] = contents.get_int("min_corner_limit_monorail", 75);
+ max_corner_adjustment_factor[waytype_t(monorail_wt)] = contents.get_int("max_corner_adjustment_factor_monorail", 50);
+ min_corner_adjustment_factor[waytype_t(monorail_wt)] = contents.get_int("min_corner_adjustment_factor_monorail", 85);
+ min_direction_steps[waytype_t(monorail_wt)] = contents.get_int("min_direction_steps_monorail", 5);
+ max_direction_steps[waytype_t(monorail_wt)] = contents.get_int("max_direction_steps_monorail", 16);
+ curve_friction_factor[waytype_t(monorail_wt)] = contents.get_int("curve_friction_factor_monorail", 0);
+
+ max_corner_limit[waytype_t(maglev_wt)] = contents.get_int("max_corner_limit_maglev", 500);
+ min_corner_limit[waytype_t(maglev_wt)] = contents.get_int("min_corner_limit_maglev", 50);
+ max_corner_adjustment_factor[waytype_t(maglev_wt)] = contents.get_int("max_corner_adjustment_factor_maglev", 40);
+ min_corner_adjustment_factor[waytype_t(maglev_wt)] = contents.get_int("min_corner_adjustment_factor_maglev", 80);
+ min_direction_steps[waytype_t(maglev_wt)] = contents.get_int("min_direction_steps_maglev", 4);
+ max_direction_steps[waytype_t(maglev_wt)] = contents.get_int("max_direction_steps_maglev", 16);
+ curve_friction_factor[waytype_t(maglev_wt)] = contents.get_int("curve_friction_factor_maglev", 0);
+
+ max_corner_limit[waytype_t(narrowgauge_wt)] = contents.get_int("max_corner_limit_narrowgauge", 250);
+ min_corner_limit[waytype_t(narrowgauge_wt)] = contents.get_int("min_corner_limit_narrowgauge", 30);
+ max_corner_adjustment_factor[waytype_t(narrowgauge_wt)] = contents.get_int("max_corner_adjustment_factor_narrowgauge", 66);
+ min_corner_adjustment_factor[waytype_t(narrowgauge_wt)] = contents.get_int("min_corner_adjustment_factor_narrowgauge", 92);
+ min_direction_steps[waytype_t(narrowgauge_wt)] = contents.get_int("min_direction_steps_narrowgauge", 3);
+ max_direction_steps[waytype_t(narrowgauge_wt)] = contents.get_int("max_direction_steps_narrowgauge", 8);
+ curve_friction_factor[waytype_t(narrowgauge_wt)] = contents.get_int("curve_friction_factor_narrowgauge", 0);
+
+ // Factory settings
+ factory_max_years_obsolete = contents.get_int("max_years_obsolete", factory_max_years_obsolete);
+
+ // @author: jamespetts
+ // Insolvency and debt settings
+ interest_rate_percent = contents.get_int("interest_rate_percent", interest_rate_percent);
+ allow_bankruptsy = contents.get_int("allow_bankruptsy", allow_bankruptsy);
+ allow_purhcases_when_insolvent = contents.get_int("allow_purhcases_when_insolvent", allow_purhcases_when_insolvent);
+
+ // Reversing settings
+ // @author: jamespetts
+ unit_reverse_time = contents.get_int("unit_reverse_time", unit_reverse_time);
+ hauled_reverse_time = contents.get_int("hauled_reverse_time", hauled_reverse_time);
+ turntable_reverse_time = contents.get_int("turntable_reverse_time", turntable_reverse_time);
+
+ // Global power factor
+ // @author: jamespetts
+ uint16 global_power_factor_percent = 100;
+ global_power_factor_percent = contents.get_int("global_power_factor_percent", global_power_factor_percent);
+ global_power_factor = (float)global_power_factor_percent / 100;
+
/*
* Selection of savegame format through inifile
*/
diff --git a/dataobj/einstellungen.h b/dataobj/einstellungen.h
index 6a597286146..bdd186b9802 100644
--- a/dataobj/einstellungen.h
+++ b/dataobj/einstellungen.h
@@ -7,6 +7,7 @@
/**
* Spieleinstellungen
+ * "Game options"
*
* Hj. Malthaner
*
@@ -137,21 +138,119 @@ class einstellungen_t
// true, if the different caacities (passengers/mail/freight) are counted seperately
bool seperate_halt_capacities;
- /**
- * payment is only for the distance that got shorter between target and start
- * three modes:
- * 0 = pay for travelled manhattan distance
- * 1 = pay for distance difference to next transfer stop
- * 2 = pay for distance to destination
- * 0 allows chaeting, but the income with 1 or two are much lower
- */
- uint8 pay_for_total_distance;
+ //Cornering settings
+ //@author: jamespetts
+
+ //The array index corresponds
+ //to the waytype index.
+
+ uint32 max_corner_limit[10];
+ uint32 min_corner_limit[10];
+ float max_corner_adjustment_factor[10];
+ float min_corner_adjustment_factor[10];
+ uint8 min_direction_steps[10];
+ uint8 max_direction_steps[10];
+ uint8 curve_friction_factor[10];
/* if set, goods will avoid being routed over overcrowded stops */
bool avoid_overcrowding;
+#ifndef NEW_PATHING
/* if set, goods will not routed over overcroded stations but rather try detours (if possible) */
bool no_routing_over_overcrowding;
+#endif
+
+ // The longest time that a passenger is
+ // prepared to wait for transport.
+ // @author: jamespetts
+ uint16 passenger_max_wait;
+
+ uint8 max_rerouting_interval_months;
+
+ //@author: jamespetts
+ // Revenue calibration settings
+ uint16 min_bonus_max_distance;
+ uint16 max_bonus_min_distance;
+ uint16 median_bonus_distance;
+ uint16 max_bonus_multiplier_percent;
+ uint16 journey_time_multiplier_percent;
+ uint8 tolerable_comfort_short;
+ uint8 tolerable_comfort_median_short;
+ uint8 tolerable_comfort_median_median;
+ uint8 tolerable_comfort_median_long;
+ uint8 tolerable_comfort_long;
+ uint16 tolerable_comfort_short_minutes;
+ uint16 tolerable_comfort_median_short_minutes;
+ uint16 tolerable_comfort_median_median_minutes;
+ uint16 tolerable_comfort_median_long_minutes;
+ uint16 tolerable_comfort_long_minutes;
+ uint8 max_luxury_bonus_differential;
+ uint8 max_discomfort_penalty_differential;
+ uint16 max_luxury_bonus_percent;
+ uint16 max_discomfort_penalty_percent;
+
+ uint16 catering_min_minutes;
+ uint16 catering_level1_minutes;
+ uint16 catering_level1_max_revenue;
+ uint16 catering_level2_minutes;
+ uint16 catering_level2_max_revenue;
+ uint16 catering_level3_minutes;
+ uint16 catering_level3_max_revenue;
+ uint16 catering_level4_minutes;
+ uint16 catering_level4_max_revenue;
+ uint16 catering_level5_minutes;
+ uint16 catering_level5_max_revenue;
+
+ uint16 tpo_min_minutes;
+ uint16 tpo_revenue;
+
+ //@author: jamespetts
+ // Obsolete vehicle maintenance cost increases
+ uint16 obsolete_running_cost_increase_percent;
+ uint16 obsolete_running_cost_increase_phase_years;
+
+ //@author: jamespetts
+ // Passenger destination ranges
+ // Use to set the extent to which passengers prefer local, medium, or long-range destinations.
+ // The distances can (and probably should) overlap.
+ uint16 local_passengers_min_distance;
+ uint16 local_passengers_max_distance;
+ uint16 midrange_passengers_min_distance;
+ uint16 midrange_passengers_max_distance;
+ uint16 longdistance_passengers_min_distance;
+ uint16 longdistance_passengers_max_distance;
+
+ // @author: jamespetts
+ // Private car settings
+ uint8 always_prefer_car_percent;
+ uint8 base_car_preference_percent;
+ uint8 congestion_density_factor;
+
+ //@author: jamespetts
+ // Passenger routing settings
+ uint8 passenger_routing_packet_size;
+ uint8 max_alternative_destinations;
+ uint8 passenger_routing_local_chance;
+ uint8 passenger_routing_midrange_chance;
+
+ //@author: jamespetts
+ // Factory retirement settings
+ uint16 factory_max_years_obsolete;
+
+ //@author: jamespetts
+ // Insolvency and debt settings
+ uint8 interest_rate_percent;
+ bool allow_bankruptsy;
+ bool allow_purhcases_when_insolvent;
+
+ // Reversing settings
+ //@author: jamespetts
+ uint16 unit_reverse_time;
+ uint16 hauled_reverse_time;
+ uint16 turntable_reverse_time;
+
+ //@author: jamespetts
+ float global_power_factor;
public:
/* the big cost section */
@@ -269,7 +368,7 @@ class einstellungen_t
short get_starting_month() const {return starting_month;}
void set_bits_per_month(short n) {bits_per_month=n;} // prissi, Oct-2005
- short get_bits_per_month() const {return bits_per_month;}
+ sint16 get_bits_per_month() const {return bits_per_month;}
void set_filename(const char *n) {filename=n;} // prissi, Jun-06
const char* get_filename() const { return filename; }
@@ -338,23 +437,96 @@ class einstellungen_t
bool is_seperate_halt_capacities() const { return seperate_halt_capacities ; }
void set_seperate_halt_capacities( bool b ) { seperate_halt_capacities = b; }
- // allowed modes are 0,1,2
- enum { TO_PREVIOUS, TO_TRANSFER, TO_DESTINATION };
- uint8 get_pay_for_total_distance_mode() const { return pay_for_total_distance ; }
- void set_pay_for_total_distance_mode( uint8 b ) { pay_for_total_distance = b < 2 ? b : 0; }
+ uint16 get_min_bonus_max_distance() const { return min_bonus_max_distance; }
+ uint16 get_max_bonus_min_distance() const { return max_bonus_min_distance; }
+ uint16 get_median_bonus_distance() const { return median_bonus_distance; }
+ float get_max_bonus_multiplier() const { return (float)max_bonus_multiplier_percent * 0.01; }
+ float get_journey_time_multiplier() const { return (float)journey_time_multiplier_percent * 0.01; }
+ uint8 get_tolerable_comfort_short() const { return tolerable_comfort_short; }
+ uint8 get_tolerable_comfort_median_short() const { return tolerable_comfort_median_short; }
+ uint8 get_tolerable_comfort_median_median() const { return tolerable_comfort_median_median; }
+ uint8 get_tolerable_comfort_median_long() const { return tolerable_comfort_median_long; }
+ uint8 get_tolerable_comfort_long() const { return tolerable_comfort_long; }
+ uint16 get_tolerable_comfort_short_minutes() const { return tolerable_comfort_short_minutes; }
+ uint16 get_tolerable_comfort_median_short_minutes() const { return tolerable_comfort_median_short_minutes; }
+ uint16 get_tolerable_comfort_median_median_minutes() const { return tolerable_comfort_median_median_minutes; }
+ uint16 get_tolerable_comfort_median_long_minutes() const { return tolerable_comfort_median_long_minutes; }
+ uint16 get_tolerable_comfort_long_minutes() const { return tolerable_comfort_long_minutes; }
+ uint8 get_max_luxury_bonus_differential() const { return max_luxury_bonus_differential; }
+ uint8 get_max_discomfort_penalty_differential() const { return max_discomfort_penalty_differential; }
+ float get_max_luxury_bonus() const { return (float)max_luxury_bonus_percent * 0.01; }
+ float get_max_discomfort_penalty() const { return (float) max_discomfort_penalty_percent * 0.01; }
+
+ uint16 get_catering_min_minutes() const { return catering_min_minutes; }
+ uint16 get_catering_level1_minutes() const { return catering_level1_minutes; }
+ uint16 get_catering_level1_max_revenue() const { return catering_level1_max_revenue; }
+ uint16 get_catering_level2_minutes() const { return catering_level2_minutes; }
+ uint16 get_catering_level2_max_revenue() const { return catering_level2_max_revenue; }
+ uint16 get_catering_level3_minutes() const { return catering_level3_minutes; }
+ uint16 get_catering_level3_max_revenue() const { return catering_level3_max_revenue; }
+ uint16 get_catering_level4_minutes() const { return catering_level4_minutes; }
+ uint16 get_catering_level4_max_revenue() const { return catering_level4_max_revenue; }
+ uint16 get_catering_level5_minutes() const { return catering_level5_minutes; }
+ uint16 get_catering_level5_max_revenue() const { return catering_level5_max_revenue; }
+
+ uint16 get_tpo_min_minutes() const { return tpo_min_minutes; }
+ uint16 get_tpo_revenue() const { return tpo_revenue; }
+
+ uint16 get_obsolete_running_cost_increase_percent() const { return obsolete_running_cost_increase_percent; }
+ uint16 get_obsolete_running_cost_increase_phase_years() const { return obsolete_running_cost_increase_phase_years; }
+
+ uint16 get_local_passengers_min_distance() const { return local_passengers_min_distance; }
+ uint16 get_local_passengers_max_distance() const { return local_passengers_max_distance; }
+ uint16 get_midrange_passengers_min_distance() const { return midrange_passengers_min_distance; }
+ uint16 get_midrange_passengers_max_distance() const { return midrange_passengers_max_distance; }
+ uint16 get_longdistance_passengers_min_distance() const { return longdistance_passengers_min_distance; }
+ uint16 get_longdistance_passengers_max_distance() const { return longdistance_passengers_max_distance; }
+
+ uint8 get_passenger_routing_packet_size() const { return passenger_routing_packet_size; }
+ uint8 get_max_alternative_destinations() const { return max_alternative_destinations; }
+ uint8 get_passenger_routing_local_chance() const { return passenger_routing_local_chance; }
+ uint8 get_passenger_routing_midrange_chance() const { return passenger_routing_midrange_chance; }
+
+ uint8 get_always_prefer_car_percent() const { return always_prefer_car_percent; }
+ uint8 get_base_car_preference_percent () const { return base_car_preference_percent; }
+ uint8 get_congestion_density_factor () const { return (congestion_density_factor > 0) ? congestion_density_factor : 1; }
+
+ uint32 get_max_corner_limit(waytype_t waytype) const { return kmh_to_speed(max_corner_limit[waytype]); }
+ uint32 get_min_corner_limit (waytype_t waytype) const { return kmh_to_speed(min_corner_limit[waytype]); }
+ float get_max_corner_adjustment_factor (waytype_t waytype) const { return max_corner_adjustment_factor[waytype] / 100; }
+ float get_min_corner_adjustment_factor (waytype_t waytype) const { return min_corner_adjustment_factor[waytype] / 100; }
+ uint8 get_min_direction_steps (waytype_t waytype) const { return min_direction_steps[waytype]; }
+ uint8 get_max_direction_steps (waytype_t waytype) const { return max_direction_steps[waytype]; }
+ uint8 get_curve_friction_factor (waytype_t waytype) const { return curve_friction_factor[waytype]; }
+
+ uint16 get_factory_max_years_obsolete() const { return factory_max_years_obsolete; }
+
+ uint8 get_interest_rate_percent() const { return interest_rate_percent; }
+ bool bankruptsy_allowed() const { return allow_bankruptsy; }
+ bool insolvent_purchases_allowed() const { return allow_purhcases_when_insolvent; }
+
+ uint16 get_unit_reverse_time() const { return unit_reverse_time; }
+ uint16 get_hauled_reverse_time() const { return hauled_reverse_time; }
+ uint16 get_turntable_reverse_time() const { return turntable_reverse_time; }
+
+ float get_global_power_factor() const { return global_power_factor; }
- // do not take people to overcrowded destinations
bool is_avoid_overcrowding() const { return avoid_overcrowding; }
+#ifndef NEW_PATHING
// do not allow routes over overcrowded destinations
bool is_no_routing_over_overcrowding() const { return no_routing_over_overcrowding; }
+#endif
+ uint16 get_passenger_max_wait() const { return passenger_max_wait; }
+
+ uint8 get_max_rerouting_interval_months() const { return max_rerouting_interval_months; }
sint16 get_river_number() const { return river_number; }
- void set_river_number( sint16 n ) { river_number=n; }
+ void set_river_number( sint16 n ) { river_number = n; }
sint16 get_min_river_length() const { return min_river_length; }
- void set_min_river_length( sint16 n ) { min_river_length=n; }
+ void set_min_river_length( sint16 n ) { min_river_length = n; }
sint16 get_max_river_length() const { return max_river_length; }
- void set_max_river_length( sint16 n ) { max_river_length=n; }
+ void set_max_river_length( sint16 n ) { max_river_length = n; }
};
#endif
diff --git a/dataobj/koord.h b/dataobj/koord.h
index 737fa495f13..1eb28efdc05 100644
--- a/dataobj/koord.h
+++ b/dataobj/koord.h
@@ -71,12 +71,35 @@ class koord
static const koord from_hang[16];
};
+static inline uint32 int_sqrt(const uint32 num)
+{
+ if (0 == num)
+ {
+ // Avoid zero divide
+ return 0;
+ }
+ uint32 n = (num / 2) + 1; // Initial estimate, never low
+ uint32 n1 = (n + (num / n)) / 2;
+ while (n1 < n)
+ {
+ n = n1;
+ n1 = (n + (num / n)) / 2;
+ }
+ return n;
+}
static inline uint32 abs_distance(const koord &a, const koord &b)
{
+ // Manhattan distance
return abs(a.x - b.x) + abs(a.y - b.y);
}
+static inline uint32 accurate_distance(const koord &a, const koord &b)
+{
+ // Euclidian distance
+ return int_sqrt(((a.x - b.x) * (a.x - b.x)) + ((a.y - b.y) * (a.y - b.y)));
+}
+
static inline koord operator * (const koord &k, const sint16 m)
{
@@ -109,6 +132,10 @@ static inline koord operator + (const koord &a, const koord &b)
return koord(a.x + b.x, a.y + b.y);
}
+static inline bool operator <= (const koord & a, const koord & b)
+{
+ return (a.x == b.x) ? (a.y <= b.y) : (a.x < b.x);
+}
static inline koord operator - (const koord &a, const koord &b)
{
diff --git a/dataobj/loadsave.cc b/dataobj/loadsave.cc
index f84fe15c0fc..de2c0a209be 100644
--- a/dataobj/loadsave.cc
+++ b/dataobj/loadsave.cc
@@ -18,9 +18,16 @@
loadsave_t::mode_t loadsave_t::save_mode = zipped; // default to use for saving
+loadsave_t::loadsave_t(bool experimental) : filename()
+{
+ fp = NULL;
+ save_experimental = experimental;
+}
+
loadsave_t::loadsave_t() : filename()
{
fp = NULL;
+ save_experimental = true;
}
loadsave_t::~loadsave_t()
@@ -33,6 +40,7 @@ bool loadsave_t::rd_open(const char *filename)
close();
version = 0;
+ experimental_version = 0;
fp = (FILE *)gzopen(filename, "rb");
if(!fp) {
return false;
@@ -70,7 +78,10 @@ bool loadsave_t::rd_open(const char *filename)
}
*s = 0;
int dummy;
- version = int_version(str, &dummy, pak_extension);
+
+ combined_version versions = int_version(str, &dummy, pak_extension);
+ version = versions.version;
+ experimental_version = versions.experimental_version;
read( buf, sizeof(" pak=\"")-1 );
s = pak_extension;
@@ -86,7 +97,9 @@ bool loadsave_t::rd_open(const char *filename)
}
}
else {
- version = int_version(buf + sizeof(SAVEGAME_PREFIX) - 1, &mode, pak_extension);
+ combined_version versions = int_version(buf + sizeof(SAVEGAME_PREFIX) - 1, &mode, pak_extension);
+ version = versions.version;
+ experimental_version = versions.experimental_version;
}
if(mode==text) {
close();
@@ -135,6 +148,21 @@ bool loadsave_t::wr_open(const char *filename, mode_t m, const char *pak_extensi
const char *start = pak_extension;
const char *end = pak_extension + strlen(pak_extension)-1;
const char *c = pak_extension;
+
+ // Use Experimental version numbering if appropriate.
+ char *savegame_version;
+ char *savegame_ver_nr;
+ if(save_experimental)
+ {
+ savegame_version = EXPERIMENTAL_SAVEGAME_VERSION;
+ savegame_ver_nr = COMBINED_VER_NR;
+ }
+ else
+ {
+ savegame_version = SAVEGAME_VERSION;
+ savegame_ver_nr = SAVEGAME_VER_NR;
+ }
+
// find the start
while(*c<*end) {
if(*c==':' || *c=='\\' || *c=='/') {
@@ -149,20 +177,22 @@ bool loadsave_t::wr_open(const char *filename, mode_t m, const char *pak_extensi
if( !is_xml() ) {
if(is_zipped()) {
- gzprintf(fp, "%s%s%s\n", SAVEGAME_VERSION, "zip", this->pak_extension);
+ gzprintf(fp, "%s%s%s\n", savegame_version, "zip", this->pak_extension);
}
else {
- fprintf(fp, "%s%s%s\n", SAVEGAME_VERSION, mode == binary ? "bin" : "", this->pak_extension);
+ fprintf(fp, "%s%s%s\n", savegame_version, mode == binary ? "bin" : "", this->pak_extension);
}
}
else {
char str[4096];
- int n = sprintf( str, "\n\n", SAVEGAME_VER_NR, this->pak_extension );
+ int n = sprintf( str, "\n\n", savegame_ver_nr, this->pak_extension );
write( str, n );
ident = 1;
}
- version = int_version(SAVEGAME_VER_NR, NULL, NULL );
+ combined_version versions = int_version(savegame_ver_nr, NULL, NULL );
+ version = versions.version;
+ experimental_version = versions.experimental_version;
this->mode = mode;
this->filename = filename;
@@ -447,6 +477,7 @@ void loadsave_t::rdwr_xml_number(sint64 &s, const char *typ)
this->write( nr, strlen(nr) );
}
else {
+ uint32 test = get_version();
const int len = (int)strlen(typ);
assert(len<256);
// find start of tag
@@ -777,29 +808,63 @@ void loadsave_t::rd_obj_id(char *id_buf, int size)
}
-uint32 loadsave_t::int_version(const char *version_text, int *mode, char *pak_extension)
-{
+loadsave_t::combined_version loadsave_t::int_version(const char *version_text, int *mode, char *pak_extension)
+{
+ uint32 version;
+ uint32 experimental_version = 0;
+
// major number (0..)
uint32 v0 = atoi(version_text);
- while(*version_text && *version_text++ != '.')
- ;
+ while(*version_text && *version_text++ != '.');
if(!*version_text) {
dbg->fatal( "loadsave_t::int_version()","Really broken version string!" );
- return 0;
+ combined_version dud;
+ dud.version = 0;
+ dud.experimental_version = 0;
+ return dud;
}
// middle number (.99.)
uint32 v1 = atoi(version_text);
- while(*version_text && *version_text++ != '.')
- ;
+ while(*version_text && *version_text++ != '.');
if(!*version_text) {
dbg->fatal( "loadsave_t::int_version()","Really broken version string!" );
- return 0;
+ combined_version dud;
+ dud.version = 0;
+ dud.experimental_version = 0;
+ return dud;
}
// minor number (..08)
uint32 v2 = atoi(version_text);
- uint32 version = v0 * 1000000 + v1 * 1000 + v2;
+ uint16 count = 0;
+ while(*version_text && *version_text++ != '.')
+ {
+ count++;
+ }
+ if(!*version_text)
+ {
+ experimental_version = 0;
+ // Decrement the pointer if this is not an Experimental version.
+ //*version_text -= count;
+ while(count > 0)
+ {
+ *version_text --;
+ count--;
+ }
+ }
+ else
+ {
+ experimental_version = atoi(version_text);
+ while(count > 0)
+ {
+ *version_text --;
+ count--;
+ }
+ }
+
+
+ version = v0 * 1000000 + v1 * 1000 + v2;
if(mode) {
while(*version_text && *version_text != 'b' && *version_text != 'z') {
@@ -814,7 +879,7 @@ uint32 loadsave_t::int_version(const char *version_text, int *mode, char *pak_ex
}
// also pak extension was saved
- if(version>=99008) {
+ if(version >= 99008) {
if(*mode!=text) {
version_text += 3;
}
@@ -825,9 +890,12 @@ uint32 loadsave_t::int_version(const char *version_text, int *mode, char *pak_ex
*pak_extension = 0;
}
- return version;
-}
+ combined_version loadsave_version;
+ loadsave_version.version = version;
+ loadsave_version.experimental_version = experimental_version;
+ return loadsave_version;
+}
void loadsave_t::start_tag(const char *tag)
diff --git a/dataobj/loadsave.h b/dataobj/loadsave.h
index 7f9b82fca96..526871924b1 100644
--- a/dataobj/loadsave.h
+++ b/dataobj/loadsave.h
@@ -36,7 +36,8 @@ class loadsave_t {
private:
int mode;
bool saving;
- int version;
+ uint32 version;
+ uint32 experimental_version;
int ident; // only for XML formatting
char pak_extension[64]; // name of the pak folder during savetime
@@ -54,10 +55,16 @@ class loadsave_t {
void rdwr_xml_number(sint64 &s, const char *typ);
+ bool save_experimental;
+
public:
+
+ struct combined_version { uint32 version; uint32 experimental_version; };
+
static mode_t save_mode; // default to use for saving
- static uint32 int_version(const char *version_text, int *mode, char *pak);
+ static combined_version int_version(const char *version_text, int *mode, char *pak);
+ loadsave_t(bool experimental);
loadsave_t();
~loadsave_t();
@@ -78,7 +85,9 @@ class loadsave_t {
bool is_zipped() const { return mode&zipped; }
bool is_xml() const { return mode&xml; }
uint32 get_version() const { return version; }
+ uint32 get_experimental_version() const { return experimental_version; }
const char *get_pak_extension() const { return pak_extension; }
+ bool get_save_experimental() const { return save_experimental; }
void rdwr_byte(sint8 &c, const char *delim);
void rdwr_byte(uint8 &c, const char *delim);
diff --git a/dataobj/ribi.h b/dataobj/ribi.h
index a130c1e5159..eadfaa3706d 100644
--- a/dataobj/ribi.h
+++ b/dataobj/ribi.h
@@ -83,6 +83,10 @@ class hang_t {
* brauchen wir etwas entsprechendes für Richtungsbits. Deshalb habe ich hier
* eine Klasse mit einer Sammlung von Daten für richtungsbits angelegt
*
+ * Hajo: After Volkers introduction of the NSOW array in the coordinates class
+ * we need something similar for direction bits. That is why I have a class with
+ * a collection of data created for direction bits.
+ *
* @author Hansjörg Malthaner
*/
class ribi_t {
@@ -96,24 +100,30 @@ class ribi_t {
* 1=Nord, 2=Ost, 4=Sued, 8=West
*
* richtungsbits (ribi) koennen 16 Komb. darstellen.
+ *
+ * the enum direction is a generalization of the
+ * direction bits to designated constants, the
+ * values are as follows 1 = North, 2 = East, 4 = South, 8 = West
+ *
+ * direction bits (ribi) can 16 Komb. represent.
*/
enum _ribi {
- keine=0,
- nord = 1,
- ost = 2,
- nordost = 3,
- sued = 4,
- nordsued = 5,
- suedost = 6,
- nordsuedost = 7,
- west = 8,
- nordwest = 9,
- ostwest = 10,
+ keine = 0, //None
+ nord = 1, //North
+ ost = 2, //East
+ nordost = 3, //North-East
+ sued = 4, // South
+ nordsued = 5,
+ suedost = 6, //South-East
+ nordsuedost = 7,
+ west = 8, //West
+ nordwest = 9, //North-West
+ ostwest = 10,
nordostwest = 11,
- suedwest = 12,
- nordsuedwest = 13,
- suedostwest = 14,
- alle = 15
+ suedwest = 12, //South-West
+ nordsuedwest = 13,
+ suedostwest = 14,
+ alle = 15 //"Everything".
};
typedef uint8 ribi;
@@ -161,6 +171,7 @@ class ribi_t {
static bool ist_kreuzung(ribi x) { return x > 0 && flags[x] == 0; }
static dir get_dir(ribi x) { return dirs[x]; }
+
};
//
@@ -168,6 +179,7 @@ class ribi_t {
//
// ribi_t::nord entspricht koord::nord entspricht hang_t::sued !!!
// -> ich denke aufwaerts, also geht es auf einem Suedhang nach Norden!
+// I think upwards, so it goes on a southern slope to the north! (Google)
//
hang_t::typ hang_typ(koord dir); // dir:nord -> hang:sued, ...
ribi_t::ribi ribi_typ(koord dir);
diff --git a/dataobj/route.cc b/dataobj/route.cc
index 75fbaa75bd4..41e30f936d5 100644
--- a/dataobj/route.cc
+++ b/dataobj/route.cc
@@ -401,7 +401,7 @@ bool route_t::intern_calc_route(karte_t *welt, const koord3d ziel, const koord3d
// we took the target pos out of the closed list
if(ziel==gr->get_pos()) {
- ziel_erreicht = true;
+ ziel_erreicht = true; //"a goal reaches" (Babelfish).
break;
}
diff --git a/dataobj/route.h b/dataobj/route.h
index 4c0e1e856e9..d30f93b978f 100644
--- a/dataobj/route.h
+++ b/dataobj/route.h
@@ -49,8 +49,8 @@ class route_t
// next one only needed for sorted_heap_tpl
inline bool operator == (const ANode k) const { return f==k.f && g==k.g; }
// next two only needed for HOT-queues
- inline bool is_matching(const ANode &l) const { return gr==l.gr; }
- inline uint32 get_distance() const { return f; }
+ //inline bool is_matching(const ANode &l) const { return gr==l.gr; }
+ //inline uint32 get_distance() const { return f; }
};
static ANode *nodes;
diff --git a/dataobj/warenziel.cc b/dataobj/warenziel.cc
index 08389c301de..99e7af731d8 100644
--- a/dataobj/warenziel.cc
+++ b/dataobj/warenziel.cc
@@ -1,3 +1,4 @@
+#ifndef NEW_PATHING
/*
* Copyright (c) 1997 - 2001 Hansjörg Malthaner
*
@@ -41,3 +42,4 @@ warenziel_t::rdwr(loadsave_t *file)
catg_index = warenbauer_t::get_info(tn)->get_catg_index();
}
}
+#endif
diff --git a/dataobj/warenziel.h b/dataobj/warenziel.h
index 30867ba82e0..e5200b0c70c 100644
--- a/dataobj/warenziel.h
+++ b/dataobj/warenziel.h
@@ -4,7 +4,7 @@
* This file is part of the Simutrans project under the artistic licence.
* (see licence.txt)
*/
-
+#ifndef NEW_PATHING
#ifndef dataobj_warenziel_h
#define dataobj_warenziel_h
@@ -18,6 +18,10 @@ class loadsave_t;
* Haltestellen benutzt. Grundlegende Elemente sind
* eine Koordinate und ein Zeitstempel.
*
+ * This class is for the management of targets
+ * used by bus stops. Essential elements are a
+ * coordinate and a time stamp.
+ *
* @author Hj. Malthaner
*/
@@ -52,3 +56,4 @@ class warenziel_t
};
#endif
+#endif
diff --git a/dings/baum.cc b/dings/baum.cc
index 23579aea13f..5b13fb8fae2 100644
--- a/dings/baum.cc
+++ b/dings/baum.cc
@@ -599,7 +599,7 @@ void baum_t::info(cbuffer_t & buf) const
void
-baum_t::entferne(spieler_t *sp)
+baum_t::entferne(spieler_t *sp) //"remove" (Babelfish)
{
spieler_t::accounting(sp, welt->get_einstellungen()->cst_remove_tree, get_pos().get_2d(), COST_CONSTRUCTION);
mark_image_dirty( get_bild(), 0 );
diff --git a/dings/bruecke.cc b/dings/bruecke.cc
index e4a7538523e..aabe0c854de 100644
--- a/dings/bruecke.cc
+++ b/dings/bruecke.cc
@@ -92,7 +92,7 @@ void bruecke_t::rdwr(loadsave_t *file)
-// correct speed and maitainace
+// correct speed, maitainace and weight limit
void bruecke_t::laden_abschliessen()
{
grund_t *gr = welt->lookup(get_pos());
@@ -117,7 +117,9 @@ void bruecke_t::laden_abschliessen()
gr->neuen_weg_bauen( weg, 0, welt->get_spieler(1) );
}
weg->set_max_speed(besch->get_topspeed());
- weg->set_besitzer(sp);
+ weg->set_max_weight(besch->get_max_weight());
+ weg->add_way_constraints(besch->get_way_constraints_permissive(), besch->get_way_constraints_prohibitive());
+ weg->set_besitzer(sp); //"besitzer" = owner (Babelfish)
spieler_t::add_maintenance( sp, -weg->get_besch()->get_wartung());
}
spieler_t::add_maintenance( sp, besch->get_wartung() );
@@ -137,6 +139,8 @@ void bruecke_t::entferne( spieler_t *sp2 )
weg_t *weg = gr->get_weg( besch->get_waytype() );
if(weg) {
weg->set_max_speed( weg->get_besch()->get_topspeed() );
+ weg->set_max_weight(weg->get_besch()->get_max_weight());
+ weg->add_way_constraints(besch->get_way_constraints_permissive(), besch->get_way_constraints_prohibitive());
spieler_t::add_maintenance( sp, weg->get_besch()->get_wartung());
}
}
diff --git a/dings/field.cc b/dings/field.cc
index 3ebad506b50..15410ad7ab3 100644
--- a/dings/field.cc
+++ b/dings/field.cc
@@ -87,7 +87,7 @@ field_t::get_bild() const
}
else {
// resolution 1/8th month (0..95)
- const uint32 yearsteps = (welt->get_current_month()%12)*8 + ((welt->get_zeit_ms()>>(welt->ticks_bits_per_tag-3))&7) + 1;
+ const sint64 yearsteps = (welt->get_current_month()%12)*8 + ((welt->get_zeit_ms()>>(welt->ticks_bits_per_tag-3))&7) + 1;
const image_id bild = s->get_bild_nr( (anzahl*yearsteps-1)/96 );
if((anzahl*yearsteps-1)%96get_besch()->get_groesse();
+ koord dim = tile->get_besch()->get_groesse(); //("Groesse" = "size")
long pax = tile->get_besch()->get_level();
if (!is_factory && ptr.stadt != NULL) {
// belongs to a city ...
@@ -702,7 +702,16 @@ gebaeude_t::rdwr(loadsave_t *file)
file->rdwr_str(buf, 128 );
}
file->rdwr_short(idx, "\n");
- file->rdwr_long(insta_zeit, " ");
+ if(file->get_experimental_version() <= 1)
+ {
+ uint32 old_insta_zeit = (uint32) insta_zeit;
+ file->rdwr_long(old_insta_zeit, " ");
+ insta_zeit = old_insta_zeit;
+ }
+ else
+ {
+ file->rdwr_longlong(insta_zeit, " ");
+ }
if(file->is_loading()) {
tile = hausbauer_t::find_tile(buf, idx);
diff --git a/dings/gebaeude.h b/dings/gebaeude.h
index cdd6bf54313..045aad3fd4e 100644
--- a/dings/gebaeude.h
+++ b/dings/gebaeude.h
@@ -43,9 +43,10 @@ class gebaeude_t : public ding_t, sync_steppable
/**
* Zeitpunkt an dem das Gebaeude Gebaut wurde
+ * "Time at that was built the building" (Babelfish)
* @author Hj. Malthaner
*/
- uint32 insta_zeit;
+ sint64 insta_zeit;
/**
* Time control for animation progress.
diff --git a/dings/groundobj.cc b/dings/groundobj.cc
index a79387331c2..98c2a3996ab 100644
--- a/dings/groundobj.cc
+++ b/dings/groundobj.cc
@@ -131,7 +131,7 @@ void groundobj_t::calc_bild()
}
else {
// resolution 1/8th month (0..95)
- const uint32 yearsteps = (welt->get_current_month()%12)*8 + ((welt->get_zeit_ms()>>(welt->ticks_bits_per_tag-3))&7) + 1;
+ const sint64 yearsteps = (welt->get_current_month()%12)*8 + ((welt->get_zeit_ms()>>(welt->ticks_bits_per_tag-3))&7) + 1;
season = (seasons*yearsteps-1)/96;
}
break;
diff --git a/dings/tunnel.cc b/dings/tunnel.cc
index 1253da7dcc1..5c5f83e4c3f 100644
--- a/dings/tunnel.cc
+++ b/dings/tunnel.cc
@@ -94,6 +94,7 @@ void tunnel_t::laden_abschliessen()
// change maintainance
weg_t *weg = gr->get_weg(besch->get_waytype());
if(weg) {
+ weg->set_max_speed(besch->get_topspeed());
weg->set_max_speed(besch->get_topspeed());
spieler_t::add_maintenance( sp, -weg->get_besch()->get_wartung());
}
@@ -117,6 +118,8 @@ void tunnel_t::entferne( spieler_t *sp2 )
if(gr) {
weg_t *weg = gr->get_weg( besch->get_waytype() );
weg->set_max_speed( weg->get_besch()->get_topspeed() );
+ weg->set_max_weight( weg->get_besch()->get_max_weight() );
+ weg->add_way_constraints(besch->get_way_constraints_permissive(), besch->get_way_constraints_prohibitive());
spieler_t::add_maintenance( sp, weg->get_besch()->get_wartung());
spieler_t::add_maintenance( sp, -besch->get_wartung() );
}
diff --git a/dings/wayobj.cc b/dings/wayobj.cc
index 51c4d26efa8..4b41f53e63f 100644
--- a/dings/wayobj.cc
+++ b/dings/wayobj.cc
@@ -81,18 +81,21 @@ wayobj_t::~wayobj_t()
if(weg) {
// Weg wieder freigeben, wenn das Signal nicht mehr da ist.
weg->set_electrify(false);
- // restore old speed limit
+ // restore old speed limit and way constraints
+ weg->reset_way_constraints();
uint32 max_speed = weg->hat_gehweg() ? 50 : weg->get_besch()->get_topspeed();
if(gr->get_typ()==grund_t::tunnelboden) {
tunnel_t *t = gr->find(1);
if(t) {
max_speed = t->get_besch()->get_topspeed();
+ weg->add_way_constraints(t->get_besch()->get_way_constraints_permissive(), t->get_besch()->get_way_constraints_prohibitive());
}
}
if(gr->get_typ()==grund_t::brueckenboden) {
bruecke_t *b = gr->find(1);
if(b) {
max_speed = b->get_besch()->get_topspeed();
+ weg->add_way_constraints(b->get_besch()->get_way_constraints_permissive(), b->get_besch()->get_way_constraints_prohibitive());
}
}
weg->set_max_speed(max_speed);
@@ -174,10 +177,11 @@ wayobj_t::laden_abschliessen()
set_dir(dir);
}
+ const waytype_t wt = (besch->get_wtyp()==tram_wt) ? track_wt : besch->get_wtyp();
+ weg_t *weg = welt->lookup(get_pos())->get_weg(wt);
+
// electrify a way if we are a catenary
- if(besch->get_own_wtyp()==overheadlines_wt) {
- const waytype_t wt = (besch->get_wtyp()==tram_wt) ? track_wt : besch->get_wtyp();
- weg_t *weg = welt->lookup(get_pos())->get_weg(wt);
+ if(besch->get_own_wtyp()==overheadlines_wt) {
if(weg) {
// Weg wieder freigeben, wenn das Signal nicht mehr da ist.
weg->set_electrify(true);
@@ -190,6 +194,9 @@ wayobj_t::laden_abschliessen()
}
}
+ //Add the way constraints together.
+ weg->add_way_constraints(besch->get_way_constraints_permissive(), besch->get_way_constraints_prohibitive());
+
if(get_besitzer()) {
spieler_t::add_maintenance(get_besitzer(), besch->get_wartung());
}
diff --git a/freight_list_sorter.cc b/freight_list_sorter.cc
index 9f0bf0126ba..ecc007ffa43 100644
--- a/freight_list_sorter.cc
+++ b/freight_list_sorter.cc
@@ -22,6 +22,7 @@ struct travel_details
ware_t ware;
halthandle_t destination;
halthandle_t via_destination;
+ halthandle_t origin;
};
@@ -40,12 +41,14 @@ int freight_list_sorter_t::compare_ware(const void *td1, const void *td2)
halthandle_t halt2 = td2p->destination;
halthandle_t via_halt1 = td1p->via_destination;
halthandle_t via_halt2 = td2p->via_destination;
+ halthandle_t origin_halt1 = td1p->origin;
+ halthandle_t origin_halt2 = td2p->origin;
- if(!halt1.is_bound() || !via_halt1.is_bound()) {
+ if(!halt1.is_bound() || !via_halt1.is_bound() || !origin_halt1.is_bound()) {
return -1;
}
- if( !halt2.is_bound() || !via_halt2.is_bound() ) {
+ if( !halt2.is_bound() || !via_halt2.is_bound() || !origin_halt2.is_bound()) {
return -2;
}
@@ -74,6 +77,11 @@ dbg->error("freight_list_sorter::compare_ware()","illegal sort mode!");
if (order != 0) break;
/* FALLTHROUGH */
+ case by_origin:
+ order = strcmp(origin_halt1->get_name(), origin_halt2->get_name());
+ if (order != 0) break;
+ /* FALLTHROUGH */
+
case by_name: // sort by destination name
order = strcmp(halt1->get_name(), halt2->get_name());
break;
@@ -115,7 +123,7 @@ void freight_list_sorter_t::sort_freight(const vector_tpl* warray, cbuff
// if there, give the capacity for each freight
slist_tpl dummy;
slist_iterator_tpl full_iter ( full_list==NULL ? &dummy : full_list );
- bool list_finish=1;
+ bool list_finish = true;
// hsiegeln
// added sorting to ware's destination list
@@ -131,6 +139,7 @@ void freight_list_sorter_t::sort_freight(const vector_tpl* warray, cbuff
tdlist[pos].ware = ware;
tdlist[pos].destination = ware.get_ziel();
tdlist[pos].via_destination = ware.get_zwischenziel();
+ tdlist[pos].origin = ware.get_origin();
// for the sorting via the number for the next stop we unify entries
if(sort_mode==by_via_sum && pos>0) {
//DBG_MESSAGE("freight_list_sorter_t::get_freight_info()","for halt %i check connection",pos);
@@ -159,8 +168,9 @@ void freight_list_sorter_t::sort_freight(const vector_tpl* warray, cbuff
for (int j = 0; jget_name();
}
@@ -210,25 +220,39 @@ void freight_list_sorter_t::sort_freight(const vector_tpl* warray, cbuff
buf.append(translator::translate(ware.get_besch()->get_name()));
buf.append(" > ");
// the target name is not correct for the via sort
- if(sortby!=by_via_sum || via_halt==halt ) {
+ if(sortby != by_via_sum || via_halt==halt )
+ {
buf.append(name);
}
// for debugging
- const char *via_name = "Error in Routing";
- if(via_halt.is_bound()) {
- via_name = via_halt->get_name();
- }
- if(via_halt != halt) {
+ if(via_halt != halt && (sortby == by_via || sortby == by_via_sum))
+ {
+ const char *via_name = "unknown";
+ if(via_halt.is_bound())
+ {
+ via_name = via_halt->get_name();
+ }
char tmp [512];
- sprintf(tmp, translator::translate("via %s\n"), via_name);
+ sprintf(tmp, translator::translate(" via %s"), via_name);
buf.append(tmp);
}
- else {
- buf.append("\n");
- }
// debug ende
+
+ if(sortby == by_origin)
+ {
+ const char *origin_name = "unknown";
+ if(origin_halt.is_bound())
+ {
+ origin_name = origin_halt->get_name();
+ }
+
+ char tmp [512];
+ sprintf(tmp, translator::translate(" from %s"), origin_name);
+ buf.append(tmp);
+ }
+ buf.append("\n");
}
}
diff --git a/freight_list_sorter.h b/freight_list_sorter.h
index d6493dce468..461b9d80cef 100644
--- a/freight_list_sorter.h
+++ b/freight_list_sorter.h
@@ -13,7 +13,7 @@ class cbuffer_t;
class freight_list_sorter_t
{
public:
- enum sort_mode_t { by_name=0, by_via=1, by_via_sum=2, by_amount=3};
+ enum sort_mode_t { by_name=0, by_via=1, by_via_sum=2, by_amount=3, by_origin=4};
static void sort_freight(const vector_tpl* warray, cbuffer_t& buf, sort_mode_t sort_mode, const slist_tpl* full_list, const char* what_doing);
diff --git a/gui/banner.cc b/gui/banner.cc
index 02e7c1156db..bd912a4477c 100644
--- a/gui/banner.cc
+++ b/gui/banner.cc
@@ -55,19 +55,20 @@ void banner_t::zeichnen(koord /*pos*/, koord)
int heading = (s == 0 ? 7 : COL_BLACK);
int color = (s == 0 ? COL_WHITE : COL_BLACK);
- display_proportional(xoff + s + 24+30, yoff + s + 10, "This is a beta version of Simutrans:", ALIGN_LEFT, heading, true);
- display_proportional(xoff + s + 48+30, yoff + s + 22, "Version " VERSION_NUMBER " " VERSION_DATE, ALIGN_LEFT, color, true);
- display_proportional(xoff + s + 24+30, yoff + s + 40, "This version is developed by", ALIGN_LEFT, heading, true);
- display_proportional(xoff + s + 48+30, yoff + s + 56, "the simutrans team, based on", ALIGN_LEFT, color, true);
- display_proportional(xoff + s + 48+30, yoff + s + 70, "Simutrans 0.84.21.2 by", ALIGN_LEFT, color, true);
- display_proportional(xoff + s + 48+30, yoff + s + 82, "Hansjörg Malthaner et al.", ALIGN_LEFT, color, true);
- display_proportional(xoff + s + 48+30, yoff + s + 94, "under Artistic Licence.", ALIGN_LEFT, color, true);
- display_proportional(xoff + s + 24+30, yoff + s + 112, "Please send ideas and questions to:", ALIGN_LEFT, heading, true);
- display_proportional(xoff + s + 48+30, yoff + s + 128, "Markus Pristovsek", ALIGN_LEFT, color, true);
- display_proportional(xoff + s + 48+30, yoff + s + 140, "", ALIGN_LEFT, color, true);
- display_proportional(xoff + s + 24+30, yoff + s + 158, "or visit the Simutrans pages on the web:", ALIGN_LEFT, heading, true);
+ display_proportional(xoff + s + 24+30, yoff + s + 10, "This is an experimental version of Simutrans:", ALIGN_LEFT, heading, true);
+ display_proportional(xoff + s + 48+30, yoff + s + 22, "Version " VERSION_NUMBER " " VERSION_DATE, ALIGN_LEFT, color, true);
+ display_proportional(xoff + s + 24+30, yoff + s + 40, "This experimental version", ALIGN_LEFT, heading, true);
+ display_proportional(xoff + s + 24+30+155, yoff + s + 40, (const char*)EXPERIMENTAL_VERSION, ALIGN_LEFT, color, true);
+ display_proportional(xoff + s + 48+30, yoff + s + 56, "is modified by James E. Petts", ALIGN_LEFT, color, true);
+ display_proportional(xoff + s + 48+30, yoff + s + 70, "from Simutrans, 1997-2005", ALIGN_LEFT, color, true);
+ display_proportional(xoff + s + 48+30, yoff + s + 82, "(c) Hj. Malthaner; and", ALIGN_LEFT, color, true);
+ display_proportional(xoff + s + 48+30, yoff + s + 94, "2005-2009 maintained by", ALIGN_LEFT, color, true);
+ display_proportional(xoff + s + 24+30, yoff + s + 112, "Markus Pristovsek and the Simutrans team,", ALIGN_LEFT, heading, true);
+ display_proportional(xoff + s + 48+30, yoff + s + 128, "released under the Artistic Licence.", ALIGN_LEFT, color, true);
+ display_proportional(xoff + s + 48+30, yoff + s + 140, "For more information, please", ALIGN_LEFT, color, true);
+ display_proportional(xoff + s + 24+30, yoff + s + 158, "visit the Simutrans website or forum", ALIGN_LEFT, heading, true);
display_proportional(xoff + s + 48+30, yoff + s + 174, "http://www.simutrans.com", ALIGN_LEFT, color, true);
- display_proportional(xoff + s + 48+30, yoff + s + 186, "http://simutrans.sourceforge.net", ALIGN_LEFT, color, true);
+ display_proportional(xoff + s + 48+30, yoff + s + 186, "http://forum.simutrans.com", ALIGN_LEFT, color, true);
}
// now the scrolling
diff --git a/gui/components/gui_convoy_assembler.cc b/gui/components/gui_convoy_assembler.cc
new file mode 100644
index 00000000000..a4a60033449
--- /dev/null
+++ b/gui/components/gui_convoy_assembler.cc
@@ -0,0 +1,1380 @@
+/*
+ * Copyright (c) 1997 - 2001 Hansjörg Malthaner
+ *
+ * This file is part of the Simutrans project under the artistic licence.
+ * (see licence.txt)
+ */
+
+#include
+#include
+
+#include "gui_convoy_assembler.h"
+
+#include "../depot_frame.h"
+#include "../replace_frame.h"
+
+#include "../../simworld.h"
+
+#include "../../bauer/warenbauer.h"
+#include "../../bauer/vehikelbauer.h"
+#include "../../besch/intro_dates.h"
+#include "../../besch/vehikel_besch.h"
+#include "../../dataobj/translator.h"
+#include "../../dataobj/umgebung.h"
+#include "../../utils/simstring.h"
+#include "../../vehicle/simvehikel.h"
+
+
+static const char * engine_type_names [9] =
+{
+ "unknown",
+ "steam",
+ "diesel",
+ "electric",
+ "bio",
+ "sail",
+ "fuel_cell",
+ "hydrogene",
+ "battery"
+};
+
+
+koord gui_convoy_assembler_t::get_placement(waytype_t wt)
+{
+ if (wt==road_wt) {
+ return koord(-20,-25);
+ }
+ if (wt==water_wt) {
+ return koord(-1,-11);
+ }
+ if (wt==air_wt) {
+ return koord(-10,-23);
+ }
+ return koord(-25,-28);
+}
+
+
+koord gui_convoy_assembler_t::get_grid(waytype_t wt)
+{
+ if (wt==water_wt) {
+ return koord(60,46);
+ }
+ if (wt==air_wt) {
+ return koord(36,36);
+ }
+ return koord(24,24);
+}
+
+
+// Names for the tabs for different depot types, defaults to railway depots
+const char * gui_convoy_assembler_t::get_passenger_name(waytype_t wt)
+{
+ if (wt==road_wt) {
+ return "Bus_tab";
+ }
+ if (wt==water_wt) {
+ return "Ferry_tab";
+ }
+ if (wt==air_wt) {
+ return "Flug_tab";
+ }
+ return "Pas_tab";
+}
+
+const char * gui_convoy_assembler_t::get_electrics_name(waytype_t wt)
+{
+ if (wt==road_wt) {
+ return "TrolleyBus_tab";
+ }
+ return "Electrics_tab";
+}
+
+const char * gui_convoy_assembler_t::get_zieher_name(waytype_t wt)
+{
+ if (wt==road_wt) {
+ return "LKW_tab";
+ }
+ if (wt==water_wt) {
+ return "Schiff_tab";
+ }
+ if (wt==air_wt) {
+ return "aircraft_tab";
+ }
+ return "Lokomotive_tab";
+}
+
+const char * gui_convoy_assembler_t::get_haenger_name(waytype_t wt)
+{
+ if (wt==road_wt) {
+ return "Anhaenger_tab";
+ }
+ if (wt==water_wt) {
+ return "Schleppkahn_tab";
+ }
+ return "Waggon_tab";
+}
+
+bool gui_convoy_assembler_t::show_retired_vehicles = false;
+
+bool gui_convoy_assembler_t::show_all = false;
+
+
+gui_convoy_assembler_t::gui_convoy_assembler_t(karte_t *w, waytype_t wt, bool electrified, signed char player_nr) :
+ way_type(wt), weg_electrified(electrified), welt(w), last_changed_vehicle(NULL),
+ depot_frame(NULL), replace_frame(NULL), placement(get_placement(wt)),
+ placement_dx(get_grid(wt).x * get_base_tile_raster_width() / 64 / 4),
+ grid(get_grid(wt)),
+ grid_dx(get_grid(wt).x * get_base_tile_raster_width() / 64 / 2),
+ max_convoy_length(depot_t::get_max_convoy_length(wt)), panel_rows(3), convoy_tabs_skip(0),
+ lb_convoi_count(NULL, COL_BLACK, gui_label_t::left),
+ lb_convoi_speed(NULL, COL_BLACK, gui_label_t::left),
+ lb_veh_action("Fahrzeuge:", COL_BLACK, gui_label_t::left),
+ //lb_upgrade("New/upgrade:", COL_BLACK, gui_label_t::left),
+ convoi_pics(depot_t::get_max_convoy_length(wt)),
+ convoi(&convoi_pics),
+ pas(&pas_vec),
+ electrics(&electrics_vec),
+ loks(&loks_vec),
+ waggons(&waggons_vec),
+ scrolly_pas(&cont_pas),
+ scrolly_electrics(&cont_electrics),
+ scrolly_loks(&cont_loks),
+ scrolly_waggons(&cont_waggons)
+{
+ /*
+ * These parameter are adjusted to resolution.
+ * - Some extra space looks nicer.
+ */
+ placement.x=placement.x* get_base_tile_raster_width() / 64 + 2;
+ placement.y=placement.y* get_base_tile_raster_width() / 64 + 2;
+ grid.x=grid.x* get_base_tile_raster_width() / 64 + 4;
+ grid.y=grid.y* get_base_tile_raster_width() / 64 + 6;
+ if(wt==road_wt && umgebung_t::drive_on_left) {
+ // correct for dive on left
+ placement.x -= (12*get_base_tile_raster_width())/64;
+ placement.y -= (6*get_base_tile_raster_width())/64;
+ }
+
+ vehicles.clear();
+
+ /*
+ * [CONVOI]
+ */
+ convoi.set_player_nr(player_nr);
+ convoi.add_listener(this);
+
+ add_komponente(&convoi);
+ add_komponente(&lb_convoi_count);
+ add_komponente(&lb_convoi_speed);
+
+ /*
+ * [PANEL]
+ * to test for presence, we must fist switch on all vehicles,
+ * and switch off the timeline ...
+ * otherwise the tabs will not be present at all
+ */
+ bool old_retired=show_retired_vehicles;
+ bool old_show_all=show_all;
+ show_retired_vehicles = true;
+ show_all = true;
+ einstellungen_t* e = get_welt()->get_einstellungen();
+ char timeline = e->get_use_timeline();
+ e->set_use_timeline(0);
+ build_vehicle_lists();
+ e->set_use_timeline(timeline);
+ show_retired_vehicles = old_retired;
+ show_all = old_show_all;
+
+ cont_pas.add_komponente(&pas);
+ scrolly_pas.set_show_scroll_x(false);
+ scrolly_pas.set_size_corner(false);
+ scrolly_pas.set_read_only(false);
+
+ // always add
+ tabs.add_tab(&scrolly_pas, translator::translate( get_passenger_name(wt) ) );
+
+ cont_electrics.add_komponente(&electrics);
+ scrolly_electrics.set_show_scroll_x(false);
+ scrolly_electrics.set_size_corner(false);
+ scrolly_electrics.set_read_only(false);
+ // add only if there are any trolleybuses
+ if(!electrics_vec.empty()) {
+ tabs.add_tab(&scrolly_electrics, translator::translate( get_electrics_name(wt) ) );
+ }
+
+ cont_loks.add_komponente(&loks);
+ scrolly_loks.set_show_scroll_x(false);
+ scrolly_loks.set_size_corner(false);
+ scrolly_loks.set_read_only(false);
+ // add, if waggons are there ...
+ if (!loks_vec.empty() || !waggons_vec.empty()) {
+ tabs.add_tab(&scrolly_loks, translator::translate( get_zieher_name(wt) ) );
+ }
+
+ cont_waggons.add_komponente(&waggons);
+ scrolly_waggons.set_show_scroll_x(false);
+ scrolly_waggons.set_size_corner(false);
+ scrolly_waggons.set_read_only(false);
+ // only add, if there are waggons
+ if (!waggons_vec.empty()) {
+ tabs.add_tab(&scrolly_waggons, translator::translate( get_haenger_name(wt) ) );
+ }
+
+ pas.set_player_nr(player_nr);
+ pas.add_listener(this);
+
+ electrics.set_player_nr(player_nr);
+ electrics.add_listener(this);
+
+ loks.set_player_nr(player_nr);
+ loks.add_listener(this);
+
+ waggons.set_player_nr(player_nr);
+ waggons.add_listener(this);
+
+ add_komponente(&tabs);
+ add_komponente(&div_tabbottom);
+ add_komponente(&lb_veh_action);
+ //add_komponente(&lb_upgrade);
+
+ veh_action = va_append;
+ action_selector.add_listener(this);
+ add_komponente(&action_selector);
+ action_selector.clear_elements();
+ static const char *txt_veh_action[3] = { "anhaengen", "voranstellen", "verkaufen" };
+ action_selector.append_element( new gui_scrolled_list_t::const_text_scrollitem_t( translator::translate(txt_veh_action[0]), COL_BLACK ) );
+ action_selector.append_element( new gui_scrolled_list_t::const_text_scrollitem_t( translator::translate(txt_veh_action[1]), COL_BLACK ) );
+ action_selector.append_element( new gui_scrolled_list_t::const_text_scrollitem_t( translator::translate(txt_veh_action[2]), COL_BLACK ) );
+ action_selector.set_selection( 0 );
+
+ upgrade = u_buy;
+ upgrade_selector.add_listener(this);
+ add_komponente(&upgrade_selector);
+ upgrade_selector.clear_elements();
+ static const char *txt_upgrade[2] = { "Buy/sell", "Upgrade" };
+ upgrade_selector.append_element(new gui_scrolled_list_t::const_text_scrollitem_t(translator::translate(txt_upgrade[0]), COL_BLACK ) );
+ upgrade_selector.append_element(new gui_scrolled_list_t::const_text_scrollitem_t(translator::translate(txt_upgrade[1]), COL_BLACK ) );
+ upgrade_selector.set_selection(0);
+
+ bt_obsolete.set_typ(button_t::square);
+ bt_obsolete.set_text("Show obsolete");
+ bt_obsolete.add_listener(this);
+ bt_obsolete.set_tooltip("Show also vehicles no longer in production.");
+ add_komponente(&bt_obsolete);
+
+ bt_show_all.set_typ(button_t::square);
+ bt_show_all.set_text("Show all");
+ bt_show_all.add_listener(this);
+ bt_show_all.set_tooltip("Show also vehicles that do not match for current action.");
+ add_komponente(&bt_show_all);
+
+ lb_convoi_count.set_text_pointer(txt_convoi_count);
+ lb_convoi_speed.set_text_pointer(txt_convoi_speed);
+
+}
+
+
+
+void gui_convoy_assembler_t::layout()
+{
+ /*
+ * The component has two parts:
+ * CONVOY IMAGE
+ * [[ optional blank space ]]
+ * VEHICLE SELECTION
+ * VINFO
+ */
+
+ /*
+ * Structure of [VINFO] is one multiline text.
+ */
+
+ /*
+ * Structure of [CONVOY IMAGE] is a image_list and an infos:
+ *
+ * [List]
+ * [Info]
+ *
+ * The image list is horizontally "condensed".
+ */
+
+ /*
+ * [CONVOI]
+ */
+ convoi.set_grid(koord(grid.x - grid_dx, grid.y));
+ convoi.set_placement(koord(placement.x - placement_dx, placement.y));
+ convoi.set_pos(koord((groesse.x-get_convoy_image_width())/2, 0));
+ convoi.set_groesse(koord(get_convoy_image_width(), get_convoy_image_height()));
+
+ int CINFO_VSTART = get_convoy_image_height();
+ lb_convoi_count.set_pos(koord(4, CINFO_VSTART));
+ lb_convoi_speed.set_pos(koord(4, CINFO_VSTART + LINESPACE));
+
+ /*
+ * [PANEL]
+ */
+ int PANEL_VSTART = get_convoy_height() + convoy_tabs_skip + 8;
+ tabs.set_pos(koord(0, PANEL_VSTART));
+ tabs.set_groesse(koord(groesse.x, get_panel_height()));
+
+ pas.set_grid(grid);
+ pas.set_placement(placement);
+ pas.set_groesse(tabs.get_groesse());
+ pas.recalc_size();
+ pas.set_pos(koord(1,1));
+ cont_pas.set_groesse(pas.get_groesse());
+ scrolly_pas.set_groesse(scrolly_pas.get_groesse());
+
+ electrics.set_grid(grid);
+ electrics.set_placement(placement);
+ electrics.set_groesse(tabs.get_groesse());
+ electrics.recalc_size();
+ electrics.set_pos(koord(1,1));
+ cont_electrics.set_groesse(electrics.get_groesse());
+ scrolly_electrics.set_groesse(scrolly_electrics.get_groesse());
+
+ loks.set_grid(grid);
+ loks.set_placement(placement);
+ loks.set_groesse(tabs.get_groesse());
+ loks.recalc_size();
+ loks.set_pos(koord(1,1));
+ cont_loks.set_pos(koord(0,0));
+ cont_loks.set_groesse(loks.get_groesse());
+ scrolly_loks.set_groesse(scrolly_loks.get_groesse());
+
+ waggons.set_grid(grid);
+ waggons.set_placement(placement);
+ waggons.set_groesse(tabs.get_groesse());
+ waggons.recalc_size();
+ waggons.set_pos(koord(1,1));
+ cont_waggons.set_groesse(waggons.get_groesse());
+ scrolly_waggons.set_groesse(scrolly_waggons.get_groesse());
+
+ div_tabbottom.set_pos(koord(0,PANEL_VSTART+ get_panel_height()));
+ div_tabbottom.set_groesse(koord(groesse.x,0));
+
+ int ABUTTON_WIDTH=96;
+ int ABUTTON_HEIGHT=14;
+ lb_veh_action.set_pos(koord(groesse.x-ABUTTON_WIDTH, PANEL_VSTART + get_panel_height() + 4));
+ //lb_upgrade.set_pos(koord(groesse.x-ABUTTON_WIDTH, PANEL_VSTART + get_panel_height() + 34));
+
+ action_selector.set_pos(koord(groesse.x-ABUTTON_WIDTH, PANEL_VSTART + get_panel_height() + 14));
+ action_selector.set_groesse(koord(ABUTTON_WIDTH, ABUTTON_HEIGHT));
+ action_selector.set_max_size(koord(ABUTTON_WIDTH - 8, LINESPACE*3+2+16));
+ action_selector.set_highlight_color(1);
+
+ upgrade_selector.set_pos(koord(groesse.x-ABUTTON_WIDTH, PANEL_VSTART + get_panel_height() + 34));
+ upgrade_selector.set_groesse(koord(ABUTTON_WIDTH, ABUTTON_HEIGHT));
+ upgrade_selector.set_max_size(koord(ABUTTON_WIDTH - 8, LINESPACE*2+2+16));
+ upgrade_selector.set_highlight_color(1);
+
+ bt_show_all.set_pos(koord(groesse.x-(ABUTTON_WIDTH*5)/2, PANEL_VSTART + get_panel_height() + 4 ));
+ bt_show_all.set_groesse(koord(ABUTTON_WIDTH, ABUTTON_HEIGHT));
+ bt_show_all.pressed = show_all;
+
+ bt_obsolete.set_pos(koord(groesse.x-(ABUTTON_WIDTH*5)/2, PANEL_VSTART + get_panel_height() + 16));
+ bt_obsolete.set_groesse(koord(ABUTTON_WIDTH, ABUTTON_HEIGHT));
+ bt_obsolete.pressed = show_retired_vehicles;
+
+ if(replace_frame == NULL)
+ {
+ // Do not display this if this is not the replacing window.
+ // Vehicles cannot be upgraded from the depot window.
+ //upgrade_selector.set_visible(false);
+ }
+}
+
+
+bool gui_convoy_assembler_t::action_triggered( gui_action_creator_t *komp,value_t p)
+{
+ if(komp != NULL) { // message from outside!
+ // image lsit selction here ...
+ if(komp == &convoi) {
+ image_from_convoi_list( p.i );
+ } else if(komp == &pas) {
+ image_from_storage_list(&pas_vec[p.i]);
+ } else if (komp == &electrics) {
+ image_from_storage_list(&electrics_vec[p.i]);
+ } else if(komp == &loks) {
+ image_from_storage_list(&loks_vec[p.i]);
+ } else if(komp == &waggons) {
+ image_from_storage_list(&waggons_vec[p.i]);
+ } else if(komp == &bt_obsolete) {
+ show_retired_vehicles = (show_retired_vehicles==0);
+ build_vehicle_lists();
+ update_data();
+ } else if(komp == &bt_show_all) {
+ show_all = (show_all==0);
+ build_vehicle_lists();
+ update_data();
+ } else if(komp == &action_selector) {
+ int selection = p.i;
+ if ( selection < 0 ) {
+ action_selector.set_selection(0);
+ selection=0;
+ }
+ if( (unsigned)(selection)<=va_sell ) {
+ veh_action=(unsigned)(selection);
+ build_vehicle_lists();
+ update_data();
+ }
+ } else if(komp == &upgrade_selector) {
+ int upgrade_selection = p.i;
+ if ( upgrade_selection < 0 ) {
+ upgrade_selector.set_selection(0);
+ upgrade_selection=0;
+ }
+ if( (unsigned)(upgrade_selection)<=u_upgrade ) {
+ upgrade=(unsigned)(upgrade_selection);
+ build_vehicle_lists();
+ update_data();
+ }
+
+ } else {
+ return false;
+ }
+ }
+ return true;
+}
+
+void gui_convoy_assembler_t::zeichnen(koord parent_pos)
+{
+ *txt_convoi_count = '\0';
+ *txt_convoi_speed = '\0';
+ if (vehicles.get_count()>0) {
+ uint32 total_power=0;
+ uint32 total_max_weight=0;
+ uint32 total_min_weight=0;
+ uint16 max_speed=0;
+ uint16 min_speed=0;
+ sint32 min_top_speed=9999999;
+ for( unsigned i=0; iget_leistung()*besch->get_gear()/64;
+ total_min_weight += besch->get_gewicht();
+ total_max_weight += besch->get_gewicht();
+
+ uint32 max_weight =0;
+ uint32 min_weight =100000;
+ for(uint32 j=0; jget_ware()->get_catg_index()==ware->get_catg_index()) {
+ max_weight = max(max_weight, ware->get_weight_per_unit());
+ min_weight = min(min_weight, ware->get_weight_per_unit());
+ }
+ }
+ total_max_weight += (max_weight*besch->get_zuladung()+499)/1000;
+ total_min_weight += (min_weight*besch->get_zuladung()+499)/1000;
+
+ min_top_speed=min(min_top_speed, besch->get_geschw()); // In kmh
+ }
+ max_speed = min(min_top_speed, (uint32) sqrt((((double)total_power/total_min_weight)-1)*2500));
+ min_speed = min(min_top_speed, (uint32) sqrt((((double)total_power/total_max_weight)-1)*2500));
+ uint16 tile_length;
+ if(depot_frame != NULL)
+ {
+ tile_length = depot_frame->get_convoy()->get_tile_length();
+ }
+ else
+ {
+ tile_length = replace_frame->get_convoy()->get_tile_length();
+ }
+ sprintf(txt_convoi_count, "%s %d (%s %i)",
+ translator::translate("Fahrzeuge:"), vehicles.get_count(),
+ translator::translate("Station tiles:"), tile_length );
+ sprintf(txt_convoi_speed, "%s %d(%d)km/h", translator::translate("Max. speed:"), min_speed, max_speed );
+ }
+
+ bt_obsolete.pressed = show_retired_vehicles; // otherwise the button would not show depressed
+ bt_show_all.pressed = show_all; // otherwise the button would not show depressed
+ draw_vehicle_info_text(parent_pos+pos);
+ gui_container_t::zeichnen(parent_pos);
+}
+
+
+
+// add all current vehicles
+void gui_convoy_assembler_t::build_vehicle_lists()
+{
+ if(vehikelbauer_t::get_info(way_type)==NULL) {
+ // there are tracks etc. but now vehicles => do nothing
+ return;
+ }
+
+ const int month_now = get_welt()->get_timeline_year_month();
+
+ if(electrics_vec.empty() && pas_vec.empty() && loks_vec.empty() && waggons_vec.empty()) {
+ int loks = 0, waggons = 0, pax=0, electrics = 0;
+ slist_iterator_tpl vehinfo(vehikelbauer_t::get_info(way_type));
+ while (vehinfo.next()) {
+ const vehikel_besch_t* info = vehinfo.get_current();
+ if( info->get_engine_type() == vehikel_besch_t::electric && (info->get_ware()==warenbauer_t::passagiere || info->get_ware()==warenbauer_t::post)) {
+ electrics++;
+ }
+ else if(info->get_ware()==warenbauer_t::passagiere || info->get_ware()==warenbauer_t::post) {
+ pax++;
+ }
+ else if(info->get_leistung() > 0 || info->get_zuladung()==0) {
+ loks++;
+ }
+ else {
+ waggons++;
+ }
+ }
+ pas_vec.resize(pax);
+ electrics_vec.resize(electrics);
+ loks_vec.resize(loks);
+ waggons_vec.resize(waggons);
+ }
+ pas_vec.clear();
+ electrics_vec.clear();
+ loks_vec.clear();
+ waggons_vec.clear();
+
+ vehicle_map.clear();
+
+ // we do not allow to built electric vehicle in a depot without electrification (weg_electrified)
+
+ // use this to show only sellable vehicles
+ if(!show_all && veh_action==va_sell && depot_frame) {
+ // just list the one to sell
+ slist_iterator_tpl iter2(depot_frame->get_depot()->get_vehicle_list());
+ while(iter2.next()) {
+ if(vehicle_map.get(iter2.get_current()->get_besch())) {
+ continue;
+ }
+ add_to_vehicle_list( iter2.get_current()->get_besch() );
+ }
+ }
+ else {
+ // list only matching ones
+ slist_iterator_tpl vehinfo(vehikelbauer_t::get_info(way_type));
+ while (vehinfo.next()) {
+ const vehikel_besch_t* info = vehinfo.get_current();
+ const vehikel_besch_t *veh = NULL;
+ if(vehicles.get_count()>0) {
+ veh = (veh_action == va_insert) ? vehicles[0] : vehicles[vehicles.get_count() - 1];
+ }
+
+ // current vehicle
+ if( (depot_frame && depot_frame->get_depot()->is_contained(info)) ||
+ ((weg_electrified || info->get_engine_type()!=vehikel_besch_t::electric) &&
+ ((!info->is_future(month_now)) && (show_retired_vehicles || (!info->is_retired(month_now)) ) ) )) {
+ // check, if allowed
+ bool append = true;
+ bool upgradeable = true;
+ if(!show_all)
+ {
+ if(veh_action == va_insert)
+ {
+ append = !(!convoi_t::pruefe_nachfolger(info, veh) || (veh && !convoi_t::pruefe_vorgaenger(info, veh)));
+ }
+ else if(veh_action == va_append)
+ {
+ append = convoi_t::pruefe_vorgaenger(veh, info);
+ }
+ if(upgrade == u_upgrade)
+ {
+ vector_tpl vehicle_list;
+ upgradeable = false;
+
+ if(replace_frame == NULL)
+ {
+ ITERATE(vehicles,i)
+ {
+ vehicle_list.append(vehicles[i]);
+ }
+ }
+ else
+ {
+ const convoihandle_t cnv = replace_frame->get_convoy();
+
+ for(uint8 i = 0; i < cnv->get_vehikel_anzahl(); i ++)
+ {
+ vehicle_list.append(cnv->get_vehikel(i)->get_besch());
+ }
+ }
+
+ if(vehicle_list.get_count() < 1)
+ {
+ break;
+ }
+
+ ITERATE(vehicle_list, i)
+ {
+ for(uint16 c = 0; c < vehicle_list[i]->get_upgrades_count(); c++)
+ {
+ if(info->get_name() == vehicle_list[i]->get_upgrades(c)->get_name())
+ {
+ upgradeable = true;
+ }
+ }
+ }
+ }
+ else
+ {
+ if(info->is_available_only_as_upgrade())
+ {
+ append = false;
+ }
+ }
+ }
+ if(append && (upgrade == u_buy || upgradeable))
+ {
+ add_to_vehicle_list( info );
+ }
+ }
+ }
+ }
+DBG_DEBUG("gui_convoy_assembler_t::build_vehicle_lists()","finally %i passenger vehicle, %i engines, %i good wagons",pas_vec.get_count(),loks_vec.get_count(),waggons_vec.get_count());
+}
+
+
+
+// add a single vehicle (helper function)
+void gui_convoy_assembler_t::add_to_vehicle_list(const vehikel_besch_t *info)
+{
+ // prissi: ist a non-electric track?
+ // Hajo: check for timeline
+ // prissi: and retirement date
+ gui_image_list_t::image_data_t img_data;
+
+ img_data.image = info->get_basis_bild();
+ img_data.count = 0;
+ img_data.lcolor = img_data.rcolor = EMPTY_IMAGE_BAR;
+ img_data.text = info->get_name();
+
+ if( info->get_engine_type() == vehikel_besch_t::electric && (info->get_ware()==warenbauer_t::passagiere || info->get_ware()==warenbauer_t::post) ) {
+ electrics_vec.append(img_data);
+ vehicle_map.set(info, &electrics_vec.back());
+ }
+ // since they come "pre-sorted" for the vehikelbauer, we have to do nothing to keep them sorted
+ else if(info->get_ware()==warenbauer_t::passagiere || info->get_ware()==warenbauer_t::post) {
+ pas_vec.append(img_data);
+ vehicle_map.set(info, &pas_vec.back());
+ }
+ else if(info->get_leistung() > 0 || info->get_zuladung()==0) {
+ loks_vec.append(img_data);
+ vehicle_map.set(info, &loks_vec.back());
+ }
+ else {
+ waggons_vec.append(img_data);
+ vehicle_map.set(info, &waggons_vec.back());
+ }
+}
+
+
+
+void gui_convoy_assembler_t::image_from_convoi_list(uint nr)
+{
+ if(nr < vehicles.get_count()) {
+
+ // we remove all connected vehicles together!
+ // find start
+ unsigned start_nr = nr;
+ while(start_nr>0) {
+ start_nr --;
+ const vehikel_besch_t *info = vehicles[start_nr];
+ if(info->get_nachfolger_count()!=1) {
+ start_nr ++;
+ break;
+ }
+ }
+ // find end
+ while(nrget_nachfolger_count()!=1) {
+ break;
+ }
+ }
+ // now remove the vehicles
+ if(vehicles.get_count()==nr-start_nr) {
+ clear_convoy();
+ koord k=koord(clear_convoy_action,0);
+ value_t v;
+ v.p=&k;
+ last_changed_vehicle=NULL;
+ call_listeners(v);
+ }
+ else {
+ koord k=koord(remove_vehicle_action,0);
+ value_t v;
+ v.p=&k;
+ for( unsigned i=start_nr; itext);
+
+ if(bild_data->lcolor != COL_RED &&
+ bild_data->rcolor != COL_RED &&
+ bild_data->rcolor != COL_DARK_PURPLE &&
+ bild_data->lcolor != COL_DARK_PURPLE &&
+ bild_data->rcolor != COL_PURPLE &&
+ bild_data->lcolor != COL_PURPLE &&
+ !((bild_data->lcolor == COL_DARK_ORANGE || bild_data->rcolor == COL_DARK_ORANGE)
+ && veh_action != va_sell
+ && depot_frame != NULL && !depot_frame->get_depot()->find_oldest_newest(info, true))) {
+
+ // Dark orange = too expensive
+ // Purple = available only as upgrade
+
+ // we buy/sell all vehicles together!
+ slist_tplnew_vehicle_info;
+
+ const vehikel_besch_t *start_info = info;
+ if(veh_action==va_insert || veh_action==va_sell) {
+ // start of composition
+ while (info->get_vorgaenger_count() == 1 && info->get_vorgaenger(0) != NULL) {
+ info = info->get_vorgaenger(0);
+ new_vehicle_info.insert(info);
+ }
+ info = start_info;
+ }
+ // not get the end ...
+ while(info)
+ {
+ new_vehicle_info.append( info );
+DBG_MESSAGE("gui_convoy_assembler_t::image_from_storage_list()","appended %s",info->get_name() );
+ if(info->get_nachfolger_count()!=1 || (veh_action==va_insert && info==start_info)) {
+ break;
+ }
+ info = info->get_nachfolger(0);
+ }
+
+ if(veh_action == va_sell)
+ {
+ while(new_vehicle_info.get_count() && depot_frame) {
+ /*
+ * We sell the newest vehicle - gives most money back.
+ */
+ vehikel_t* veh = depot_frame->get_depot()->find_oldest_newest(new_vehicle_info.remove_first(), false);
+ if (veh != NULL) {
+ depot_frame->get_depot()->sell_vehicle(veh);
+ build_vehicle_lists();
+ update_data();
+ }
+ }
+ }
+ else
+ {
+ // append/insert into convoi
+ if(vehicles.get_count()+new_vehicle_info.get_count() <= max_convoy_length) {
+
+ koord k=koord(veh_action==va_insert?insert_vehicle_in_front_action:append_vehicle_action,0);
+ value_t v;
+ v.p=&k;
+ for( unsigned i=0; iget_timeline_year_month();
+
+ const vehikel_besch_t *veh = NULL;
+
+ convoi_pics.clear();
+ if(vehicles.get_count() > 0) {
+
+ unsigned i;
+ for(i=0; iget_basis_bild();
+ img_data.count = 0;
+ img_data.lcolor = img_data.rcolor= EMPTY_IMAGE_BAR;
+ img_data.text = vehicles[i]->get_name();
+ convoi_pics.append(img_data);
+ }
+
+ /* color bars for current convoi: */
+ convoi_pics[0].lcolor = convoi_t::pruefe_vorgaenger(NULL, vehicles[0]) ? COL_DARK_GREEN : COL_YELLOW;
+ for( i=1; iis_future(month_now) || vehicles[i]->is_retired(month_now)) {
+ if (convoi_pics[i].lcolor == COL_DARK_GREEN) {
+ convoi_pics[i].lcolor = COL_DARK_BLUE;
+ }
+ if (convoi_pics[i].rcolor == COL_DARK_GREEN) {
+ convoi_pics[i].rcolor = COL_DARK_BLUE;
+ }
+ }
+ }
+
+ if(veh_action == va_insert) {
+ veh = vehicles[0];
+ } else if(veh_action == va_append) {
+ veh = vehicles[vehicles.get_count() - 1];
+ }
+ }
+
+ ptrhashtable_iterator_tpl iter1(vehicle_map);
+
+ const spieler_t *sp = welt->get_active_player();
+
+ while(iter1.next())
+ {
+ const vehikel_besch_t *info = iter1.get_current_key();
+ const uint8 ok_color = info->is_future(month_now) || info->is_retired(month_now) ? COL_DARK_BLUE: COL_DARK_GREEN;
+
+ iter1.get_current_value()->count = 0;
+ iter1.get_current_value()->lcolor = ok_color;
+ iter1.get_current_value()->rcolor = ok_color;
+
+ /*
+ * color bars for current convoi:
+ * green/green okay to append/insert
+ * red/red cannot be appended/inserted
+ * green/yellow append okay, cannot be end of train
+ * yellow/green insert okay, cannot be start of train
+ * orange/orange - too expensive
+ * purple/purple available only as upgrade
+ * dark purple/dark purple cannot upgrade to this vehicle
+ */
+
+ if(veh_action == va_insert) {
+ if (!convoi_t::pruefe_nachfolger(info, veh) || (veh && !convoi_t::pruefe_vorgaenger(info, veh))) {
+ iter1.get_current_value()->lcolor = COL_RED;
+ iter1.get_current_value()->rcolor = COL_RED;
+ } else if(!convoi_t::pruefe_vorgaenger(NULL, info)) {
+ iter1.get_current_value()->lcolor = COL_YELLOW;
+ }
+ } else if(veh_action == va_append) {
+ if(!convoi_t::pruefe_vorgaenger(veh, info) || (veh && !convoi_t::pruefe_nachfolger(veh, info))) {
+ iter1.get_current_value()->lcolor = COL_RED;
+ iter1.get_current_value()->rcolor = COL_RED;
+ } else if(!convoi_t::pruefe_nachfolger(info, NULL)) {
+ iter1.get_current_value()->rcolor = COL_YELLOW;
+ }
+ }
+ if (veh_action != va_sell)
+ {
+ //Check whether too expensive
+ //@author: jamespetts
+ if(iter1.get_current_value()->lcolor == ok_color || iter1.get_current_value()->lcolor == COL_YELLOW)
+ {
+ //Only flag as too expensive that which could be purchased anyway.
+ if(upgrade == u_buy)
+ {
+ if(!sp->can_afford(info->get_preis()))
+ {
+ iter1.get_current_value()->lcolor = COL_DARK_ORANGE;
+ iter1.get_current_value()->rcolor = COL_DARK_ORANGE;
+ }
+ }
+ else
+ {
+ if(!sp->can_afford(info->get_upgrade_price()))
+ {
+ iter1.get_current_value()->lcolor = COL_DARK_ORANGE;
+ iter1.get_current_value()->rcolor = COL_DARK_ORANGE;
+ }
+ }
+ }
+ }
+
+ if(upgrade == u_upgrade)
+ {
+ //Check whether there are any vehicles to upgrade
+ iter1.get_current_value()->lcolor = COL_DARK_PURPLE;
+ iter1.get_current_value()->rcolor = COL_DARK_PURPLE;
+ vector_tpl vehicle_list;
+
+ if(replace_frame == NULL)
+ {
+ ITERATE(vehicles,i)
+ {
+ vehicle_list.append(vehicles[i]);
+ }
+ }
+ else
+ {
+ const convoihandle_t cnv = replace_frame->get_convoy();
+
+ for(uint8 i = 0; i < cnv->get_vehikel_anzahl(); i ++)
+ {
+ vehicle_list.append(cnv->get_vehikel(i)->get_besch());
+ }
+ }
+
+ ITERATE(vehicle_list, i)
+ {
+ for(uint16 c = 0; c < vehicle_list[i]->get_upgrades_count(); c++)
+ {
+ if(info->get_name() == vehicle_list[i]->get_upgrades(c)->get_name())
+ {
+ iter1.get_current_value()->lcolor = COL_DARK_GREEN;
+ iter1.get_current_value()->rcolor = COL_DARK_GREEN;
+ if(replace_frame != NULL)
+ {
+ // If we are using the replacing window,
+ // vehicle_list is the list of all vehicles in the current convoy.
+ // vehicles is the list of the vehicles to replace them with.
+ sint8 upgradeable_count = 0;
+ ITERATE(vehicles,j)
+ {
+ if(vehicles[j]->get_name() == info->get_name())
+ {
+ // Counts the number of vehicles in the current convoy that can
+ // upgrade to the currently selected vehicle.
+ upgradeable_count --;
+ }
+ }
+ ITERATE(vehicle_list,j)
+ {
+ for(uint16 k = 0; k < vehicle_list[j]->get_upgrades_count(); k++)
+ {
+ if(vehicle_list[j]->get_upgrades(k)->get_name() == info->get_name())
+ {
+ // Counts the number of vehicles currently marked to be upgraded
+ // to the selected vehicle.
+ upgradeable_count ++;
+ }
+ }
+ }
+
+ if(upgradeable_count < 1)
+ {
+ //There are not enough vehicles left to upgrade.
+ iter1.get_current_value()->lcolor = COL_DARK_PURPLE;
+ iter1.get_current_value()->rcolor = COL_DARK_PURPLE;
+ }
+
+ }
+ if(veh_action == va_insert)
+ {
+ if (!convoi_t::pruefe_nachfolger(info, veh) || (veh && !convoi_t::pruefe_vorgaenger(info, veh)))
+ {
+ iter1.get_current_value()->lcolor = COL_RED;
+ iter1.get_current_value()->rcolor = COL_RED;
+ }
+ else if(!convoi_t::pruefe_vorgaenger(NULL, info))
+ {
+ iter1.get_current_value()->lcolor = COL_YELLOW;
+ }
+ }
+ else if(veh_action == va_append)
+ {
+ if(!convoi_t::pruefe_vorgaenger(veh, info) || (veh && !convoi_t::pruefe_nachfolger(veh, info))) {
+ iter1.get_current_value()->lcolor = COL_RED;
+ iter1.get_current_value()->rcolor = COL_RED;
+ }
+ else if(!convoi_t::pruefe_nachfolger(info, NULL))
+ {
+ iter1.get_current_value()->rcolor = COL_YELLOW;
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ if(info->is_available_only_as_upgrade())
+ {
+ iter1.get_current_value()->lcolor = COL_PURPLE;
+ iter1.get_current_value()->rcolor = COL_PURPLE;
+ }
+ }
+
+DBG_DEBUG("gui_convoy_assembler_t::update_data()","current %i = %s with color %i",info->get_name(),iter1.get_current_value()->lcolor);
+ }
+
+ if (depot_frame) {
+ slist_iterator_tpl iter2(depot_frame->get_depot()->get_vehicle_list());
+ while(iter2.next()) {
+ gui_image_list_t::image_data_t *imgdat=vehicle_map.get(iter2.get_current()->get_besch());
+ // can fail, if currently not visible
+ if(imgdat) {
+ imgdat->count++;
+ if(veh_action == va_sell) {
+ imgdat->lcolor = COL_DARK_GREEN;
+ imgdat->rcolor = COL_DARK_GREEN;
+ }
+ }
+ }
+ }
+}
+
+
+
+void gui_convoy_assembler_t::draw_vehicle_info_text(koord pos)
+{
+ char buf[1024];
+ const char *c;
+
+ gui_image_list_t *lst;
+ if( tabs.get_aktives_tab()==&scrolly_pas ) {
+ lst = dynamic_cast(&pas);
+ }
+ else if( tabs.get_aktives_tab()==&scrolly_electrics ) {
+ lst = dynamic_cast(&electrics);
+ }
+ else if( tabs.get_aktives_tab()==&scrolly_loks ) {
+ lst = dynamic_cast(&loks);
+ }
+ else {
+ lst = dynamic_cast(&waggons);
+ }
+ int x = get_maus_x();
+ int y = get_maus_y();
+ int value = -1;
+ const vehikel_besch_t *veh_type = NULL;
+ koord relpos = koord( 0, ((gui_scrollpane_t *)tabs.get_aktives_tab())->get_scroll_y() );
+ int sel_index = lst->index_at(pos + tabs.get_pos() - relpos, x, y - 16 - gui_tab_panel_t::HEADER_VSIZE);
+
+ if ((sel_index != -1) && (tabs.getroffen(x-pos.x,y-pos.y))) {
+ const vector_tpl& vec = (lst == &electrics ? electrics_vec : (lst == &pas ? pas_vec : (lst == &loks ? loks_vec : waggons_vec)));
+ veh_type = vehikelbauer_t::get_info(vec[sel_index].text);
+ if (depot_frame && vec[sel_index].count > 0) {
+ value = depot_frame->get_depot()->calc_restwert(veh_type) / 100;
+ }
+ }
+ else {
+ sel_index = convoi.index_at(pos , x, y );
+ if(sel_index != -1) {
+ if (depot_frame) {
+ convoihandle_t cnv = depot_frame->get_convoy();
+ veh_type = cnv->get_vehikel(sel_index)->get_besch();
+ value = cnv->get_vehikel(sel_index)->calc_restwert()/100;
+ }
+ }
+ }
+
+ buf[0]='\0';
+ c=buf;
+ if (depot_frame)
+ {
+ switch(depot_frame->get_depot()->vehicle_count())
+ {
+ case 0:
+ c = translator::translate("Keine Einzelfahrzeuge im Depot");
+ break;
+ case 1:
+ c = translator::translate("1 Einzelfahrzeug im Depot");
+ break;
+ default:
+ sprintf(buf, translator::translate("%d Einzelfahrzeuge im Depot"), depot_frame->get_depot()->vehicle_count());
+ c = buf;
+ break;
+ }
+ }
+
+ display_proportional( pos.x + 4, pos.y + tabs.get_pos().y + tabs.get_groesse().y + 16 + 4, c, ALIGN_LEFT, COL_BLACK, true );
+
+ if(veh_type) {
+ int k = 0;
+ // lok oder waggon ?
+ if(veh_type->get_leistung() > 0) { //"Leistung" = performance (Google)
+ //lok
+ const int zuladung = veh_type->get_zuladung(); //"Zuladung" = payload (Google)
+
+ char name[128];
+
+ sprintf(name,
+ "%s (%s)",
+ translator::translate(veh_type->get_name()),
+ translator::translate(engine_type_names[veh_type->get_engine_type()+1]));
+
+ int n;
+
+ if(upgrade == u_buy)
+ {
+ n = sprintf(buf,
+ translator::translate("LOCO_INFO"),
+ name,
+ veh_type->get_preis()/100,
+ veh_type->get_betriebskosten(get_welt())/100.0,
+ veh_type->get_leistung(),
+ veh_type->get_geschw(),
+ veh_type->get_gewicht()
+ );
+ }
+ else
+ {
+ n = sprintf(buf,
+ translator::translate("LOCO_INFO"),
+ name,
+ veh_type->get_upgrade_price()/100,
+ veh_type->get_betriebskosten(get_welt())/100.0,
+ veh_type->get_leistung(),
+ veh_type->get_geschw(),
+ veh_type->get_gewicht()
+ );
+ }
+
+ //"Payload" (Google)
+ if(zuladung > 0 && veh_type->get_overcrowded_capacity() < 1)
+ {
+ n += sprintf(buf + n,
+ translator::translate("LOCO_CAP"),
+ zuladung,
+ translator::translate(veh_type->get_ware()->get_mass()),
+ veh_type->get_ware()->get_catg() == 0 ? translator::translate(veh_type->get_ware()->get_name()) : translator::translate(veh_type->get_ware()->get_catg_name())
+ );
+ k = n;
+ }
+ else if(zuladung > 0 && veh_type->get_overcrowded_capacity() > 0)
+ {
+ n += sprintf(buf + n,
+ translator::translate("Capacity: %d (%d)%s %s\n"),
+ zuladung,
+ veh_type->get_overcrowded_capacity(),
+ translator::translate(veh_type->get_ware()->get_mass()),
+ veh_type->get_ware()->get_catg() == 0 ? translator::translate(veh_type->get_ware()->get_name()) : translator::translate(veh_type->get_ware()->get_catg_name())
+ );
+ k = n;
+ }
+
+ }
+ else {
+ // waggon
+ int n;
+ if(upgrade == u_buy)
+ {
+ if(veh_type->get_overcrowded_capacity() < 1)
+ {
+ n = sprintf(buf,
+ translator::translate("WAGGON_INFO"),
+ translator::translate(veh_type->get_name()),
+ veh_type->get_preis()/100,
+ veh_type->get_betriebskosten(get_welt())/100.0,
+ veh_type->get_zuladung(),
+ translator::translate(veh_type->get_ware()->get_mass()),
+ veh_type->get_ware()->get_catg() == 0 ?
+ translator::translate(veh_type->get_ware()->get_name()) :
+ translator::translate(veh_type->get_ware()->get_catg_name()),
+ veh_type->get_gewicht(),
+ veh_type->get_geschw()
+ );
+ }
+ else
+ {
+ n = sprintf(buf,
+ translator::translate("%s\nCost: %d$ (%1.2f$/km)\nCapacity: %d (%d)%s %s\nWeight: %dt\nTop speed: %dkm/h\n"),
+ translator::translate(veh_type->get_name()),
+ veh_type->get_preis()/100,
+ veh_type->get_betriebskosten(get_welt())/100.0,
+ veh_type->get_zuladung(),
+ veh_type->get_overcrowded_capacity(),
+ translator::translate(veh_type->get_ware()->get_mass()),
+ veh_type->get_ware()->get_catg() == 0 ?
+ translator::translate(veh_type->get_ware()->get_name()) :
+ translator::translate(veh_type->get_ware()->get_catg_name()),
+ veh_type->get_gewicht(),
+ veh_type->get_geschw()
+ );
+ }
+ }
+ else
+ {
+ if(veh_type->get_overcrowded_capacity() < 1)
+ {
+ n = sprintf(buf,
+ translator::translate("WAGGON_INFO"),
+ translator::translate(veh_type->get_name()),
+ veh_type->get_upgrade_price()/100,
+ veh_type->get_betriebskosten(get_welt())/100.0,
+ veh_type->get_zuladung(),
+ translator::translate(veh_type->get_ware()->get_mass()),
+ veh_type->get_ware()->get_catg() == 0 ?
+ translator::translate(veh_type->get_ware()->get_name()) :
+ translator::translate(veh_type->get_ware()->get_catg_name()),
+ veh_type->get_gewicht(),
+ veh_type->get_geschw()
+ );
+ }
+ else
+ {
+ n = sprintf(buf,
+ translator::translate("%s\nCost: %d$ (%1.2f$/km)\nCapacity: %d (%d)%s %s\nWeight: %dt\nTop speed: %dkm/h\n"),
+ translator::translate(veh_type->get_name()),
+ veh_type->get_upgrade_price()/100,
+ veh_type->get_betriebskosten(get_welt())/100.0,
+ veh_type->get_zuladung(),
+ veh_type->get_overcrowded_capacity(),
+ translator::translate(veh_type->get_ware()->get_mass()),
+ veh_type->get_ware()->get_catg() == 0 ?
+ translator::translate(veh_type->get_ware()->get_name()) :
+ translator::translate(veh_type->get_ware()->get_catg_name()),
+ veh_type->get_gewicht(),
+ veh_type->get_geschw()
+ );
+ }
+ }
+
+ k = n;
+ }
+
+ if(veh_type->get_catering_level() > 0)
+ {
+ if(veh_type->get_ware()->get_catg_index() == 1)
+ {
+ //Catering vehicles that carry mail are treated as TPOs.
+ k += sprintf(buf + k, translator::translate("This is a travelling post office"));
+ }
+ else
+ {
+ k += sprintf(buf + k, translator::translate("Catering level: %i"), veh_type->get_catering_level());
+ }
+ }
+
+ // Permissive way constraints
+ // (If vehicle has, way must have)
+ // @author: jamespetts
+ for(uint8 i = 0; i < 8; i++)
+ {
+ if(veh_type->permissive_way_constraint_set(i))
+ {
+ k += sprintf(buf + k, translator::translate("\nMUST USE: "));
+ char tmpbuf[30];
+ sprintf(tmpbuf, "Permissive %i", i);
+ k += sprintf(buf + k, translator::translate(tmpbuf));
+ }
+ }
+
+ display_multiline_text( pos.x + 4, pos.y + tabs.get_pos().y + tabs.get_groesse().y + 31 + LINESPACE*1 + 4, buf, COL_BLACK);
+
+ // column 2
+
+ int j = 0;
+
+ if(veh_type->get_zuladung() > 0)
+ {
+ //Loading time is only relevant if there is something to load.
+ j += sprintf(buf, "%s %i \n", translator::translate("Loading time:"), veh_type->get_loading_time());
+ }
+
+ if(veh_type->get_ware()->get_catg_index() == 0)
+ {
+ //Comfort only applies to passengers.
+ j += sprintf(buf + j, "%s %i \n", translator::translate("Comfort:"), veh_type->get_comfort());
+ }
+
+ j += sprintf(buf + j, "%s %s %04d\n",
+ translator::translate("Intro. date:"),
+ translator::get_month_name(veh_type->get_intro_year_month()%12),
+ veh_type->get_intro_year_month()/12 );
+
+ if(veh_type->get_retire_year_month() !=DEFAULT_RETIRE_DATE*12) {
+ j += sprintf(buf + j, "%s %s %04d\n",
+ translator::translate("Retire. date:"),
+ translator::get_month_name(veh_type->get_retire_year_month()%12),
+ veh_type->get_retire_year_month()/12 );
+ }
+
+ if(veh_type->get_leistung() > 0 && veh_type->get_gear()!=64) {
+ j+= sprintf(buf + j, "%s %0.2f : 1\n", translator::translate("Gear: "), veh_type->get_gear()/64.0);
+ }
+
+ if(veh_type->get_tilting())
+ {
+ j += sprintf(buf + j, translator::translate("This is a tilting vehicle\n"));
+ }
+
+ if(veh_type->get_copyright()!=NULL && veh_type->get_copyright()[0]!=0)
+ {
+ j += sprintf(buf + j, translator::translate("Constructed by %s\n"), veh_type->get_copyright());
+ }
+
+ if(value != -1)
+ {
+ sprintf(buf + strlen(buf), "%s %d Cr", translator::translate("Restwert: "), value); //"Restwert" = residual (Google)
+ }
+
+ // Prohibitibve way constraints
+ // (If way has, vehicle must have)
+ // @author: jamespetts
+ j += sprintf(buf + j, "\n");
+ for(uint8 i = 0; i < 8; i++)
+ {
+ if(veh_type->prohibitive_way_constraint_set(i))
+ {
+ j += sprintf(buf + j, translator::translate("\nMAY USE: "));
+ char tmpbuf[30];
+ sprintf(tmpbuf, "Prohibitive %i", i);
+ j += sprintf(buf + j, translator::translate(tmpbuf));
+ }
+ }
+
+ display_multiline_text( pos.x + 200, pos.y + tabs.get_pos().y + tabs.get_groesse().y + 31 + LINESPACE*2 + 4, buf, COL_BLACK);
+ }
+}
+
+
+
+void gui_convoy_assembler_t::set_vehicles(convoihandle_t cnv)
+{
+ clear_convoy();
+ if (cnv.is_bound()) {
+ for (int i=0; iget_vehikel_anzahl(); i++) {
+ vehicles.append(cnv->get_vehikel(i)->get_besch());
+ }
+ }
+}
+
+
+void gui_convoy_assembler_t::set_vehicles(const vector_tpl* vv)
+{
+ vehicles.clear();
+ vehicles.resize(vv->get_count()); // To save some memory
+ for (uint16 i=0; iget_count(); ++i) {
+ vehicles.append((*vv)[i]);
+ }
+}
+
+
+void gui_convoy_assembler_t::infowin_event(const event_t *ev)
+{
+ gui_container_t::infowin_event(ev);
+
+ if(IS_LEFTCLICK(ev) && !action_selector.getroffen(ev->cx, ev->cy-16)) {
+ // close combo box; we must do it ourselves, since the box does not recieve outside events ...
+ action_selector.close_box();
+ }
+
+ if(IS_LEFTCLICK(ev) && !upgrade_selector.getroffen(ev->cx, ev->cy-16)) {
+ // close combo box; we must do it ourselves, since the box does not recieve outside events ...
+ upgrade_selector.close_box();
+ }
+}
\ No newline at end of file
diff --git a/gui/components/gui_convoy_assembler.h b/gui/components/gui_convoy_assembler.h
new file mode 100644
index 00000000000..888c8ff9ab0
--- /dev/null
+++ b/gui/components/gui_convoy_assembler.h
@@ -0,0 +1,259 @@
+#ifndef gui_convoy_assembler_h
+#define gui_convoy_assembler_h
+
+#include "action_listener.h"
+#include "gui_button.h"
+#include "gui_combobox.h"
+#include "gui_divider.h"
+#include "gui_image_list.h"
+#include "gui_label.h"
+#include "gui_scrollpane.h"
+#include "gui_tab_panel.h"
+
+#include "../gui_container.h"
+
+#include "../../convoihandle_t.h"
+
+#include "../../besch/vehikel_besch.h"
+
+#include "../../ifc/gui_action_creator.h"
+#include "../../ifc/gui_komponente.h"
+
+#include "../../tpl/ptrhashtable_tpl.h"
+#include "../../tpl/vector_tpl.h"
+
+
+/**
+ * This class allows the player to assemble a convoy from vehicles.
+ * The code was extracted from depot_frame_t and adapted by isidoro
+ * in order to be used elsewhere if needed (Jan-09).
+ * The author markers of the original code have been preserved when
+ * possible.
+ *
+ * @author Hansjörg Malthaner
+ * @date 22-Nov-01
+ */
+class gui_convoy_assembler_t :
+ public gui_container_t,
+ public gui_action_creator_t,
+ public action_listener_t
+{
+ /* show retired vehicles (same for all depot)
+ * @author prissi
+ */
+ static bool show_retired_vehicles;
+
+ /* show retired vehicles (same for all depot)
+ * @author prissi
+ */
+ static bool show_all;
+
+ /**
+ * Parameters to determine layout and behaviour of convoy images.
+ * Originally in simdepot.h. Based in the code of:
+ * @author Volker Meyer
+ * @date 09.06.2003
+ */
+ static koord get_placement(waytype_t wt);
+ static koord get_grid(waytype_t wt);
+
+ waytype_t way_type;
+ const bool weg_electrified;
+ class karte_t *welt;
+
+ // The selected convoy so far...
+ vector_tpl vehicles;
+
+ // Last changed vehicle (added/deleted)
+ const vehikel_besch_t *last_changed_vehicle;
+
+
+ // If this is used for a depot, which depot_frame manages, else NULL
+ class depot_frame_t *depot_frame;
+ class replace_frame_t *replace_frame;
+
+ /* Gui parameters */
+ koord placement; // ...of first vehicle image
+ int placement_dx;
+ koord grid; // Offsets for adjacent vehicle images
+ int grid_dx; // Horizontal offset adjustment for vehicles in convoy
+ unsigned int max_convoy_length;
+ int panel_rows;
+ int convoy_tabs_skip;
+
+ /* Gui elements */
+ gui_label_t lb_convoi_count;
+ gui_label_t lb_convoi_speed;
+
+ button_t bt_obsolete;
+ button_t bt_show_all;
+
+ gui_tab_panel_t tabs;
+ gui_divider_t div_tabbottom;
+
+ gui_label_t lb_veh_action;
+ gui_combobox_t action_selector;
+
+ //gui_label_t lb_upgrade;
+ gui_combobox_t upgrade_selector;
+
+ vector_tpl convoi_pics;
+ gui_image_list_t convoi;
+
+ vector_tpl pas_vec;
+ vector_tpl electrics_vec;
+ vector_tpl loks_vec;
+ vector_tpl waggons_vec;
+
+ gui_image_list_t pas;
+ gui_image_list_t electrics;
+ gui_image_list_t loks;
+ gui_image_list_t waggons;
+ gui_scrollpane_t scrolly_pas;
+ gui_scrollpane_t scrolly_electrics;
+ gui_scrollpane_t scrolly_loks;
+ gui_scrollpane_t scrolly_waggons;
+ gui_container_t cont_pas;
+ gui_container_t cont_electrics;
+ gui_container_t cont_loks;
+ gui_container_t cont_waggons;
+
+ char txt_convoi_count[40];
+ char txt_convoi_speed[80];
+
+ enum { va_append, va_insert, va_sell };
+ uint8 veh_action;
+ uint8 upgrade;
+
+ // text for the tabs is defaulted to the train names
+ static const char * get_electrics_name(waytype_t wt);
+ static const char * get_passenger_name(waytype_t wt);
+ static const char * get_zieher_name(waytype_t wt);
+ static const char * get_haenger_name(waytype_t wt);
+
+ /**
+ * A helper map to update loks_vec and waggons_Vec. All entries from
+ * loks_vec and waggons_vec are referenced here.
+ * @author Volker Meyer
+ * @date 09.06.2003
+ */
+ ptrhashtable_tpl vehicle_map;
+
+ /**
+ * Draw the info text for the vehicle the mouse is over - if any.
+ * @author Volker Meyer, Hj. Malthaner
+ * @date 09.06.2003
+ * @update 09-Jan-04
+ */
+ void draw_vehicle_info_text(koord pos);
+
+ // for convoi image
+ void image_from_convoi_list(uint nr);
+
+ void image_from_storage_list(gui_image_list_t::image_data_t *bild_data);
+
+ // add a single vehicle (helper function)
+ void add_to_vehicle_list(const vehikel_besch_t *info);
+
+ static const int VINFO_HEIGHT = 186;
+
+public:
+ // Used for listeners to know what has happened
+ enum { clear_convoy_action, remove_vehicle_action, insert_vehicle_in_front_action, append_vehicle_action };
+
+ enum { u_buy, u_upgrade };
+
+ gui_convoy_assembler_t(karte_t *w, waytype_t wt, bool electrified, signed char player_nr );
+
+ /**
+ * Create and fill loks_vec and waggons_vec.
+ * @author Volker Meyer
+ * @date 09.06.2003
+ */
+ void build_vehicle_lists();
+
+ /**
+ * Do the dynamic component layout
+ * @author Volker Meyer
+ * @date 18.06.2003
+ */
+ void layout();
+
+ /**
+ * This method is called if an action is triggered
+ * @author Hj. Malthaner
+ *
+ * Returns true, if action is done and no more
+ * components should be triggered.
+ * V.Meyer
+ */
+ bool action_triggered( gui_action_creator_t *komp, value_t extra);
+
+ /**
+ * Update texts, image lists and buttons according to the current state.
+ * @author Volker Meyer
+ * @date 09.06.2003
+ */
+ void update_data();
+
+ /* The gui_komponente_t interface */
+ virtual void zeichnen(koord offset);
+
+ void infowin_event(const event_t *ev);
+
+ inline void clear_convoy() {vehicles.clear();}
+
+ inline void remove_vehicle_at(int n) {vehicles.remove_at(n);}
+ inline void append_vehicle(const vehikel_besch_t* vb, bool in_front) {vehicles.insert_at(in_front?0:vehicles.get_count(),vb);}
+
+ /* Getter/setter methods */
+
+ inline const vehikel_besch_t *get_last_changed_vehicle() const {return last_changed_vehicle;}
+
+ inline karte_t *get_welt() const {return welt;}
+
+ inline void set_depot_frame(depot_frame_t *df) {depot_frame=df;}
+ inline void set_replace_frame(replace_frame_t *rf) {replace_frame=rf;}
+
+ inline const vector_tpl* get_vehicles() const {return &vehicles;}
+ void set_vehicles(convoihandle_t cnv);
+ void set_vehicles(const vector_tpl* vv);
+
+ inline void set_convoy_tabs_skip(int skip) {convoy_tabs_skip=skip;}
+
+ inline int get_convoy_clist_width() const {return vehicles.get_count() * (grid.x - grid_dx) + 2 * gui_image_list_t::BORDER;}
+ //inline int get_convoy_clist_width() const {return depot_frame->get_depot()->get_max_convoi_length() * (grid.x - grid_dx) + 2 * gui_image_list_t::BORDER;}
+
+ inline int get_convoy_image_width() const {return get_convoy_clist_width() + placement_dx;}
+
+ inline int get_convoy_image_height() const {return grid.y + 2 * gui_image_list_t::BORDER;}
+
+ inline int get_convoy_height() const {
+ int CINFO_HEIGHT = 14;
+ return get_convoy_image_height() + CINFO_HEIGHT + 2 + LINESPACE * 2;
+ }
+
+ inline int get_vinfo_height() const { return VINFO_HEIGHT; }
+
+ inline void set_panel_rows(int dy) {
+ if (dy==-1) {
+ panel_rows=3;
+ return;
+ }
+ dy -= get_convoy_height() + convoy_tabs_skip + 8 + get_vinfo_height() + 17 + gui_tab_panel_t::HEADER_VSIZE + 2 * gui_image_list_t::BORDER;
+ panel_rows = max(1, (dy/grid.y) );
+ }
+
+ inline int get_panel_height() const {return panel_rows * grid.y + gui_tab_panel_t::HEADER_VSIZE + 2 * gui_image_list_t::BORDER;}
+
+ inline int get_min_panel_height() const {return grid.y + gui_tab_panel_t::HEADER_VSIZE + 2 * gui_image_list_t::BORDER;}
+
+ inline int get_height() const {return get_convoy_height() + convoy_tabs_skip + 8 + get_panel_height() + get_vinfo_height();}
+
+ inline int get_min_height() const {return get_convoy_height() + convoy_tabs_skip + 8 + get_min_panel_height() + get_vinfo_height();}
+
+ inline uint8 get_upgrade() const { return upgrade; }
+ inline uint8 get_action() const { return veh_action; }
+};
+
+#endif
\ No newline at end of file
diff --git a/gui/components/gui_convoy_label.cc b/gui/components/gui_convoy_label.cc
new file mode 100644
index 00000000000..82095def25c
--- /dev/null
+++ b/gui/components/gui_convoy_label.cc
@@ -0,0 +1,124 @@
+/*
+* Copyright (c) 1997 - 2001 Hansjörg Malthaner
+ *
+ * This file is part of the Simutrans project under the artistic licence.
+ * (see licence.txt)
+ */
+
+#include
+
+#include "gui_convoy_label.h"
+
+#include "../../simconst.h"
+#include "../../simgraph.h"
+#include "../../bauer/warenbauer.h"
+#include "../../dataobj/translator.h"
+#include "../../player/simplay.h"
+#include "../../vehicle/simvehikel.h"
+
+
+gui_convoy_label_t::gui_convoy_label_t(convoihandle_t cnv, bool show_number_of_convoys, bool show_max_speed):
+ gui_label_t(NULL,COL_BLACK,centered),
+ show_number(show_number_of_convoys), show_max_speed(show_max_speed), cnv(cnv)
+{
+}
+
+
+koord gui_convoy_label_t::get_image_size() const
+{
+ int tamx=0;
+ int tamy=0;
+ if (cnv.is_bound() && cnv->get_vehikel_anzahl()>0) {
+ for(unsigned i=0; iget_vehikel_anzahl();i++) {
+ KOORD_VAL x, y, w, h;
+ const image_id bild=cnv->get_vehikel(i)->get_basis_bild();
+ display_get_base_image_offset(bild, &x, &y, &w, &h );
+ tamx += (w*2)/3;
+ tamy = max(tamy,h+26);
+ }
+ }
+ return koord(tamx,tamy);
+}
+
+
+koord gui_convoy_label_t::get_size() const
+{
+ int tamx=0, tamy=0;
+ if (get_text_pointer()!=NULL) {
+ tamx=display_calc_proportional_string_len_width(get_text_pointer(), 35535) + 2;
+ tamy+=LINESPACE+separation;
+ }
+ tamy+=(show_number?LINESPACE:0)+(show_max_speed?LINESPACE:0);
+ koord img_tam=get_image_size();
+ return koord(max(tamx,img_tam.x),tamy+img_tam.y);
+}
+
+
+void gui_convoy_label_t::zeichnen(koord offset)
+{
+ if (get_text_pointer()!=NULL) {
+ gui_label_t::zeichnen(offset);
+ offset=offset+koord(0,LINESPACE+separation);
+ }
+ int left=pos.x+offset.x;
+ koord tam=get_image_size();
+ if (get_align()==centered) {
+ left-=tam.x/2;
+ } else if (get_align()==right) {
+ left-=tam.x;
+ }
+ if (cnv.is_bound() && cnv->get_vehikel_anzahl()>0) {
+ for(unsigned i=0; iget_vehikel_anzahl();i++) {
+ KOORD_VAL x, y, w, h;
+ const image_id bild=cnv->get_vehikel(i)->get_basis_bild();
+ display_get_base_image_offset(bild, &x, &y, &w, &h );
+ display_base_img(bild,left-x,pos.y+offset.y+13-y-h/2,cnv->get_besitzer()->get_player_nr(),false,true);
+ left += (w*2)/3;
+ }
+ }
+ offset.y+=get_image_size().y;
+ char tmp[128];
+ if (show_number) {
+ sprintf(tmp, "%s %d (%s %i)",
+ translator::translate("Fahrzeuge:"), cnv->get_vehikel_anzahl(),
+ translator::translate("Station tiles:"), (cnv->get_length()+TILE_STEPS-1)/TILE_STEPS );
+ display_proportional( offset.x + 4, offset.y , tmp, ALIGN_LEFT, COL_BLACK, true );
+ offset.y+=LINESPACE;
+ }
+ if (show_max_speed) {
+ uint16 max_speed=0;
+ uint16 min_speed=0;
+ if(cnv->get_vehikel_anzahl() > 0) {
+// int length=0;
+ uint32 total_power=0;
+ uint32 total_max_weight=0;
+ uint32 total_min_weight=0;
+ for( unsigned i=0; iget_vehikel_anzahl(); i++) {
+ const vehikel_besch_t *besch = cnv->get_vehikel(i)->get_besch();
+
+// length += besch->get_length();
+ total_power += besch->get_leistung()*besch->get_gear()/64;
+ total_min_weight += besch->get_gewicht();
+ total_max_weight += besch->get_gewicht();
+
+ uint32 max_weight =0;
+ uint32 min_weight =100000;
+ for(uint32 j=0; jget_ware()->get_catg_index()==ware->get_catg_index()) {
+ max_weight = max(max_weight, ware->get_weight_per_unit());
+ min_weight = min(min_weight, ware->get_weight_per_unit());
+ }
+ }
+ total_max_weight += (max_weight*besch->get_zuladung()+499)/1000;
+ total_min_weight += (min_weight*besch->get_zuladung()+499)/1000;
+ }
+ max_speed = min(speed_to_kmh(cnv->get_min_top_speed()), (uint32) sqrt((((double)total_power/total_min_weight)-1)*2500));
+ min_speed = min(speed_to_kmh(cnv->get_min_top_speed()), (uint32) sqrt((((double)total_power/total_max_weight)-1)*2500));
+ }
+ sprintf(tmp, "%s %d(%d)km/h", translator::translate("Max. speed:"), min_speed, max_speed );
+ display_proportional( offset.x + 4, offset.y , tmp, ALIGN_LEFT, COL_BLACK, true );
+ offset.y+=LINESPACE;
+ }
+}
\ No newline at end of file
diff --git a/gui/components/gui_convoy_label.h b/gui/components/gui_convoy_label.h
new file mode 100644
index 00000000000..c5bbb71afae
--- /dev/null
+++ b/gui/components/gui_convoy_label.h
@@ -0,0 +1,48 @@
+/*
+ * just displays a label with a convoy under it, the label will be auto-translated
+ *
+ * Copyright (c) 1997 - 2001 Hansjörg Malthaner
+ *
+ * This file is part of the Simutrans project under the artistic licence.
+ * (see licence.txt)
+ */
+
+//#ifndef gui_convoy_label_t_h
+//#define gui_convoy_label_t_h
+
+#include "gui_label.h"
+
+#include "../../simconvoi.h"
+
+
+/**
+ * A label with a convoy image underneath
+ *
+ * @author isidoro
+ * @date 06-Feb-09
+ */
+class gui_convoy_label_t:public gui_label_t
+{
+private:
+ // Adjustable parameters
+ static const int separation=4;
+
+ bool show_number;
+ bool show_max_speed;
+
+ /**
+ * The convoy to be painted
+ */
+ convoihandle_t cnv;
+
+public:
+ gui_convoy_label_t(convoihandle_t cnv, bool show_number_of_convoys=false, bool show_max_speed=false);
+
+ koord get_image_size() const;
+
+ koord get_size() const;
+
+ virtual void zeichnen(koord offset);
+};
+
+//#endif
\ No newline at end of file
diff --git a/gui/components/gui_label.h b/gui/components/gui_label.h
index 6cc3b024f59..d59f23d5ec3 100644
--- a/gui/components/gui_label.h
+++ b/gui/components/gui_label.h
@@ -63,7 +63,7 @@ class gui_label_t : public gui_komponente_t
* returns the pointer (i.e. for freeing untranslater contents)
* @author Hansjörg Malthaner
*/
- const char * get_text_pointer() { return text; }
+ const char * get_text_pointer() const { return text; }
/**
* Zeichnet die Komponente
@@ -83,6 +83,7 @@ class gui_label_t : public gui_komponente_t
* @author Volker Meyer
*/
+ align_t get_align() const {return align;}
void set_align(align_t align) { this->align = align; }
};
diff --git a/gui/convoi_detail_t.cc b/gui/convoi_detail_t.cc
index c4bb2560aa7..e31e2539ee6 100644
--- a/gui/convoi_detail_t.cc
+++ b/gui/convoi_detail_t.cc
@@ -52,6 +52,13 @@ convoi_detail_t::convoi_detail_t(convoihandle_t cnv)
withdraw_button.set_tooltip("Convoi is sold when all wagons are empty.");
add_komponente(&withdraw_button);
withdraw_button.add_listener(this);
+ retire_button.set_groesse(koord(BUTTON_WIDTH, BUTTON_HEIGHT));
+ retire_button.set_pos(koord(BUTTON3_X,16+BUTTON_HEIGHT));
+ retire_button.set_text("Retire");
+ retire_button.set_typ(button_t::roundbox);
+ retire_button.set_tooltip("Convoi is sent to depot when all wagons are empty.");
+ add_komponente(&retire_button);
+ retire_button.add_listener(this);
scrolly.set_pos(koord(0, 64));
add_komponente(&scrolly);
@@ -81,12 +88,15 @@ convoi_detail_t::zeichnen(koord pos, koord gr)
if(cnv->get_besitzer()==cnv->get_welt()->get_active_player()) {
withdraw_button.enable();
sale_button.enable();
+ retire_button.enable();
}
else {
- sale_button.disable();
withdraw_button.disable();
+ sale_button.disable();
+ retire_button.disable();
}
withdraw_button.pressed = cnv->get_withdraw();
+ retire_button.pressed = cnv->get_depot_when_empty();
// all gui stuff set => display it
veh_info.set_groesse(koord(1,1));
@@ -128,6 +138,11 @@ convoi_detail_t::action_triggered(gui_action_creator_t *komp,value_t /* */)
cnv->set_no_load(cnv->get_withdraw());
return true;
}
+ else if(komp==&retire_button) {
+ cnv->set_depot_when_empty(!cnv->get_depot_when_empty());
+ cnv->set_no_load(cnv->get_depot_when_empty());
+ return true;
+ }
}
return false;
}
@@ -207,6 +222,32 @@ void gui_vehicleinfo_t::zeichnen(koord offset)
extra_y += LINESPACE;
}
+ //Catering
+ if(v->get_besch()->get_catering_level() > 0)
+ {
+ if(v->get_besch()->get_ware()->get_catg_index() == 1)
+ {
+ //Catering vehicles that carry mail are treated as TPOs.
+ sprintf(buf , translator::translate("This is a travelling post office\n"));
+ display_proportional_clip( pos.x+w+offset.x, pos.y+offset.y+total_height+extra_y, buf, ALIGN_LEFT, COL_BLACK, true );
+ extra_y += LINESPACE;
+ }
+ else
+ {
+ sprintf(buf, translator::translate("Catering level: %i\n"), v->get_besch()->get_catering_level());
+ display_proportional_clip( pos.x+w+offset.x, pos.y+offset.y+total_height+extra_y, buf, ALIGN_LEFT, COL_BLACK, true );
+ extra_y += LINESPACE;
+ }
+ }
+
+ //Tilting
+ if(v->get_besch()->get_tilting())
+ {
+ sprintf(buf, translator::translate("This is a tilting vehicle\n"));
+ display_proportional_clip( pos.x+w+offset.x, pos.y+offset.y+total_height+extra_y, buf, ALIGN_LEFT, COL_BLACK, true );
+ extra_y += LINESPACE;
+ }
+
// friction
sprintf( buf, "%s %i", translator::translate("Friction:"), v->get_frictionfactor() );
display_proportional_clip( pos.x+w+offset.x, pos.y+offset.y+total_height+extra_y, buf, ALIGN_LEFT, MONEY_PLUS, true );
@@ -218,7 +259,7 @@ void gui_vehicleinfo_t::zeichnen(koord offset)
int len = 5+display_proportional_clip( pos.x+w+offset.x, pos.y+offset.y+total_height+extra_y, translator::translate("Max income:"), ALIGN_LEFT, COL_BLACK, true );
const sint32 grundwert128 = v->get_fracht_typ()->get_preis()<<7;
const sint32 grundwert_bonus = v->get_fracht_typ()->get_preis()*(1000l+speed_base*v->get_fracht_typ()->get_speed_bonus());
- const sint32 price = (v->get_fracht_max()*(grundwert128>grundwert_bonus ? grundwert128 : grundwert_bonus))/30 - v->get_betriebskosten();
+ const sint32 price = (v->get_fracht_max()*(grundwert128>grundwert_bonus ? grundwert128 : grundwert_bonus))/30 - v->get_betriebskosten(cnv->get_welt());
money_to_string( tmp, price/100.0 );
display_proportional_clip( pos.x+w+offset.x+len, pos.y+offset.y+total_height+extra_y, tmp, ALIGN_LEFT, price>0?MONEY_PLUS:MONEY_MINUS, true );
extra_y += LINESPACE;
@@ -242,6 +283,41 @@ void gui_vehicleinfo_t::zeichnen(koord offset)
}
extra_y += returns*LINESPACE;
}
+
+ // Permissive way constraints
+ // (If vehicle has, way must have)
+ // @author: jamespetts
+ for(uint8 i = 0; i < 8; i++)
+ {
+ if(v->get_besch()->permissive_way_constraint_set(i))
+ {
+ char tmpbuf1[13];
+ sprintf(tmpbuf1, "\nMUST USE: ");
+ char tmpbuf[14];
+ sprintf(tmpbuf, "Permissive %i", i);
+ sprintf(buf, "%s %s", translator::translate(tmpbuf1), translator::translate(tmpbuf));
+ display_proportional_clip( pos.x+w+offset.x, pos.y+offset.y+total_height+extra_y, buf, ALIGN_LEFT, COL_BLACK, true );
+ extra_y += LINESPACE;
+ }
+ }
+
+ // Prohibitive way constraints
+ // (If way has, vehicle must have)
+ // @author: jamespetts
+ for(uint8 i = 0; i < 8; i++)
+ {
+ if(v->get_besch()->prohibitive_way_constraint_set(i))
+ {
+ char tmpbuf1[13];
+ sprintf(tmpbuf1, "\nMAY USE: ");
+ char tmpbuf[14];
+ sprintf(tmpbuf, "Prohibitive %i", i);
+ sprintf(buf, "%s %s", translator::translate(tmpbuf1), translator::translate(tmpbuf));
+ display_proportional_clip( pos.x+w+offset.x, pos.y+offset.y+total_height+extra_y, buf, ALIGN_LEFT, COL_BLACK, true );
+ extra_y += LINESPACE;
+ }
+ }
+
//skip at least five lines
total_height += max(extra_y,4*LINESPACE)+5;
}
diff --git a/gui/convoi_detail_t.h b/gui/convoi_detail_t.h
index 7dae04b09c4..3d57846b544 100644
--- a/gui/convoi_detail_t.h
+++ b/gui/convoi_detail_t.h
@@ -65,7 +65,8 @@ class convoi_detail_t : public gui_frame_t , private action_listener_t
convoihandle_t cnv;
button_t sale_button;
- button_t withdraw_button;
+ button_t withdraw_button;
+ button_t retire_button;
public:
convoi_detail_t(convoihandle_t cnv);
diff --git a/gui/convoi_frame.cc b/gui/convoi_frame.cc
index f38e8a3f5ec..ce2f793b8e2 100644
--- a/gui/convoi_frame.cc
+++ b/gui/convoi_frame.cc
@@ -47,7 +47,7 @@ const char *convoi_frame_t::sort_text[SORT_MODES] = {
"cl_btn_sort_name",
"cl_btn_sort_income",
"cl_btn_sort_type",
- "cl_btn_sort_id"
+ "cl_btn_sort_id",
};
diff --git a/gui/convoi_frame.h b/gui/convoi_frame.h
index c592a8ed321..b0fb56c7c38 100644
--- a/gui/convoi_frame.h
+++ b/gui/convoi_frame.h
@@ -30,7 +30,7 @@ class convoi_frame_t :
private action_listener_t //28-Dec-01 Markus Weber Added , private action_listener_t
{
public:
- enum sort_mode_t { nach_name=0, nach_gewinn=1, nach_typ=2, nach_id=3, SORT_MODES=4 };
+ enum sort_mode_t { nach_name=0, nach_gewinn=1, nach_typ=2, nach_id=3, SORT_MODES=5 };
enum filter_flag_t { any_filter=1, name_filter=2, typ_filter=4, ware_filter=8, spezial_filter=16,
sub_filter=32, // Ab hier beginnen die Unterfilter!
lkws_filter=32, zuege_filter=64, schiffe_filter=128, aircraft_filter=256,
diff --git a/gui/convoi_info_t.cc b/gui/convoi_info_t.cc
index 5850dc08b00..7bdd60b51d8 100644
--- a/gui/convoi_info_t.cc
+++ b/gui/convoi_info_t.cc
@@ -8,6 +8,7 @@
#include
#include "convoi_info_t.h"
+#include "replace_frame.h"
#include "../simconvoi.h"
#include "../simdepot.h"
@@ -37,31 +38,35 @@ const char cost_type[MAX_CONVOI_COST][64] =
{
"Free Capacity",
"Transported",
+ "Average speed",
+ "Comfort",
"Revenue",
"Operation",
"Profit"
};
-bool convoi_info_t::route_search_in_progress=false;
+bool convoi_info_t::route_search_in_progress = false;
/**
* This variable defines by which column the table is sorted
- * Values: 0 = destination
- * 1 = via
- * 2 = via_amount
- * 3 = amount
- * @author prissi
+ * Values: 0 = destination
+ * 1 = via
+ * 2 = via_amount
+ * 3 = amount
+ * 4 = origin
+ * @author prissi - amended by jamespetts (origins)
*/
const char *convoi_info_t::sort_text[SORT_MODES] = {
"Zielort",
"via",
"via Menge",
- "Menge"
+ "Menge",
+ "origin"
};
const int cost_type_color[MAX_CONVOI_COST] =
{
- COL_FREE_CAPACITY, COL_TRANSPORTED, COL_REVENUE, COL_OPERATION, COL_PROFIT
+ COL_FREE_CAPACITY, COL_TRANSPORTED, COL_AVERAGE_SPEED, COL_COMFORT, COL_REVENUE, COL_OPERATION, COL_PROFIT
};
@@ -134,7 +139,10 @@ convoi_info_t::convoi_info_t(convoihandle_t cnv)
set_fenstergroesse(koord(TOTAL_WIDTH, 278));
// chart
- chart.set_pos(koord(44,76+BUTTON_HEIGHT+8));
+ chart.set_pos(koord(44,76+BUTTON_HEIGHT+18));
+ chart.set_groesse(koord(TOTAL_WIDTH-44-4, 100));
+ chart.set_dimension(12, 10000);
+ chart.set_visible(false);
chart.set_groesse(koord(TOTAL_WIDTH-44-4, 100));
chart.set_dimension(12, 10000);
chart.set_visible(false);
@@ -176,6 +184,14 @@ convoi_info_t::convoi_info_t(convoihandle_t cnv)
add_komponente(&no_load_button);
no_load_button.add_listener(this);
+ replace_button.set_groesse(koord(BUTTON_WIDTH, BUTTON_HEIGHT));
+ replace_button.set_pos(koord(BUTTON3_X,76+BUTTON_HEIGHT+1));
+ replace_button.set_text("Replace");
+ replace_button.set_typ(button_t::box);
+ replace_button.set_tooltip("Automatically replace this convoy.");
+ add_komponente(&replace_button);
+ replace_button.add_listener(this);
+
follow_button.set_groesse(koord(66, BUTTON_HEIGHT));
follow_button.set_text("follow me");
follow_button.set_typ(button_t::roundbox_state);
@@ -197,6 +213,11 @@ convoi_info_t::convoi_info_t(convoihandle_t cnv)
* komponente neu zeichnen. Die übergebenen Werte beziehen sich auf
* das Fenster, d.h. es sind die Bildschirkoordinaten des Fensters
* in dem die Komponente dargestellt wird.
+ *
+ * Component draw again. The handed over values refer to the window,
+ * i.e. there is the Bildschirkoordinaten of the window in that the
+ * component is represented. (Babelfish)
+ *
* @author Hj. Malthaner
*/
void
@@ -233,6 +254,9 @@ convoi_info_t::zeichnen(koord pos, koord gr)
}
no_load_button.pressed = cnv->get_no_load();
no_load_button.enable();
+ replace_button.background= cnv->get_replace()?COL_LIGHT_RED:MN_GREY3;
+ replace_button.set_text(cnv->get_replace()?"Replacing":"Replace");
+ replace_button.enable();
}
else {
if( line_bound ) {
@@ -243,6 +267,7 @@ convoi_info_t::zeichnen(koord pos, koord gr)
button.disable();
go_home_button.disable();
no_load_button.disable();
+ replace_button.disable();
}
follow_button.pressed = (cnv->get_welt()->get_follow_convoi()==cnv);
@@ -364,66 +389,23 @@ bool convoi_info_t::action_triggered( gui_action_creator_t *komp,value_t /* */)
return true;
}
- if(komp == &go_home_button && !route_search_in_progress) {
- // limit update to certain states that are considered to be save for fahrplan updates
- int state = cnv->get_state();
- if(state==convoi_t::FAHRPLANEINGABE) {
-DBG_MESSAGE("convoi_info_t::action_triggered()","convoi state %i => cannot change schedule ... ", state );
+ if(komp == &replace_button) {
+ if (cnv->get_replace()) {
+ cnv->set_replace(false);
return true;
}
- route_search_in_progress = true;
-
- // iterate over all depots and try to find shortest route
- slist_iterator_tpl depot_iter(depot_t::get_depot_list());
- route_t * shortest_route = new route_t();
- route_t * route = new route_t();
- koord3d home = koord3d(0,0,0);
- while (depot_iter.next()) {
- depot_t *depot = depot_iter.get_current();
- if(depot->get_wegtyp()!=cnv->get_vehikel(0)->get_besch()->get_waytype() || depot->get_besitzer()!=cnv->get_besitzer()) {
- continue;
- }
- koord3d pos = depot->get_pos();
- if(!shortest_route->empty() && abs_distance(pos.get_2d(),cnv->get_pos().get_2d())>=shortest_route->get_max_n()) {
- // the current route is already shorter, no need to search further
- continue;
- }
- bool found = cnv->get_vehikel(0)->calc_route(cnv->get_pos(), pos, 50, route); // do not care about speed
- if (found) {
- if( route->get_max_n() < shortest_route->get_max_n() || shortest_route->empty() ) {
- shortest_route->kopiere(route);
- home = pos;
- }
- }
- }
- delete route;
- DBG_MESSAGE("shortest route has ", "%i hops", shortest_route->get_max_n());
-
- // if route to a depot has been found, update the convoi's schedule
- bool b_depot_found = false;
- if(!shortest_route->empty()) {
- schedule_t *fpl = cnv->get_schedule();
- fpl->insert(cnv->get_welt()->lookup(home));
- fpl->set_aktuell( (fpl->get_aktuell()+fpl->get_count()-1)%fpl->get_count() );
- b_depot_found = cnv->set_schedule(fpl);
- }
- delete shortest_route;
- route_search_in_progress = false;
-
- // show result
- const char* txt;
- if (b_depot_found) {
- txt = "Convoi has been sent\nto the nearest depot\nof appropriate type.\n";
- } else {
- txt = "Home depot not found!\nYou need to send the\nconvoi to the depot\nmanually.";
- }
- create_win( new news_img(txt), w_time_delete, magic_none);
+ create_win(20, 20, new replace_frame_t(cnv, get_name()), w_info, (long)this);
+ return true;
+ }
+ if(komp == &go_home_button && !route_search_in_progress) {
+ cnv->go_to_depot(true);
+ return true;
} // end go home button
}
if (komp == &toggler) {
toggler.pressed = !toggler.pressed;
- const koord offset = toggler.pressed ? koord(0, 170) : koord(0, -170);
+ const koord offset = toggler.pressed ? koord(0, 170) : koord(0, -180);
set_min_windowsize( koord(TOTAL_WIDTH, toggler.pressed ? 364: 194));
scrolly.set_pos( scrolly.get_pos()+koord(0,offset.y) );
// toggle visibility of components
diff --git a/gui/convoi_info_t.h b/gui/convoi_info_t.h
index 153fa84d3f2..7bc39529df0 100644
--- a/gui/convoi_info_t.h
+++ b/gui/convoi_info_t.h
@@ -30,7 +30,7 @@
class convoi_info_t : public gui_frame_t, private action_listener_t
{
public:
- enum sort_mode_t { by_destination=0, by_via=1, by_amount_via=2, by_amount=3, SORT_MODES=4 };
+ enum sort_mode_t { by_destination=0, by_via=1, by_amount_via=2, by_amount=3, by_origin=4, SORT_MODES=5 };
private:
gui_scrollpane_t scrolly;
@@ -46,6 +46,7 @@ class convoi_info_t : public gui_frame_t, private action_listener_t
button_t follow_button;
button_t go_home_button;
button_t no_load_button;
+ button_t replace_button;
button_t filterButtons[7];
button_t sort_button;
@@ -68,10 +69,10 @@ class convoi_info_t : public gui_frame_t, private action_listener_t
*/
cbuffer_t freight_info;
- static bool route_search_in_progress;
static const char *sort_text[SORT_MODES];
public:
+ static bool route_search_in_progress;
convoi_info_t(convoihandle_t cnv);
/**
diff --git a/gui/depot_frame.cc b/gui/depot_frame.cc
index 930bd051b6a..f2809025923 100644
--- a/gui/depot_frame.cc
+++ b/gui/depot_frame.cc
@@ -43,45 +43,14 @@
char depot_frame_t::no_line_text[128]; // contains the current translation of ""
-static const char * engine_type_names [9] =
-{
- "unknown",
- "steam",
- "diesel",
- "electric",
- "bio",
- "sail",
- "fuel_cell",
- "hydrogene",
- "battery"
-};
-
-
-bool depot_frame_t::show_retired_vehicles = false;
-
-bool depot_frame_t::show_all = true;
-
depot_frame_t::depot_frame_t(depot_t* depot) :
gui_frame_t(txt_title, depot->get_besitzer()),
depot(depot),
icnv(depot->convoi_count()-1),
lb_convois(NULL, COL_BLACK, gui_label_t::left),
- lb_convoi_count(NULL, COL_BLACK, gui_label_t::left),
- lb_convoi_speed(NULL, COL_BLACK, gui_label_t::left),
lb_convoi_value(NULL, COL_BLACK, gui_label_t::right),
- lb_convoi_line(NULL, COL_BLACK, gui_label_t::left),
- lb_veh_action("Fahrzeuge:", COL_BLACK, gui_label_t::left),
- convoi_pics(depot->get_max_convoi_length()),
- convoi(&convoi_pics),
- pas(&pas_vec),
- electrics(&electrics_vec),
- loks(&loks_vec),
- waggons(&waggons_vec),
- scrolly_pas(&cont_pas),
- scrolly_electrics(&cont_electrics),
- scrolly_loks(&cont_loks),
- scrolly_waggons(&cont_waggons)
+ lb_convoi_line(NULL, COL_BLACK, gui_label_t::left)
{
DBG_DEBUG("depot_frame_t::depot_frame_t()","get_max_convoi_length()=%i",depot->get_max_convoi_length());
selected_line = depot->get_selected_line(); //linehandle_t();
@@ -90,8 +59,19 @@ DBG_DEBUG("depot_frame_t::depot_frame_t()","get_max_convoi_length()=%i",depot->g
sprintf(txt_title, "(%d,%d) %s", depot->get_pos().x, depot->get_pos().y, translator::translate(depot->get_name()));
/*
- * [SELECT]:
- */
+ * [CONVOY ASSEMBLER]
+ */
+ const waytype_t wt = depot->get_wegtyp();
+ const weg_t *w = get_welt()->lookup(depot->get_pos())->get_weg(wt!=tram_wt ? wt : track_wt);
+ const bool weg_electrified = w ? w->is_electrified() : false;
+ convoy_assembler = new gui_convoy_assembler_t(get_welt(), wt, weg_electrified, depot->get_player_nr() );
+ convoy_assembler->set_depot_frame(this);
+ convoy_assembler->add_listener(this);
+ update_convoy();
+
+ /*
+ * [SELECT]:
+ */
add_komponente(&lb_convois);
bt_prev.set_typ(button_t::arrowleft);
@@ -112,15 +92,6 @@ DBG_DEBUG("depot_frame_t::depot_frame_t()","get_max_convoi_length()=%i",depot->g
add_komponente(&line_selector);
depot->get_besitzer()->simlinemgmt.sort_lines();
- /*
- * [CONVOI]
- */
- convoi.set_player_nr(depot->get_player_nr());
- convoi.add_listener(this);
-
- add_komponente(&convoi);
- add_komponente(&lb_convoi_count);
- add_komponente(&lb_convoi_speed);
add_komponente(&lb_convoi_value);
add_komponente(&lb_convoi_line);
@@ -170,93 +141,6 @@ DBG_DEBUG("depot_frame_t::depot_frame_t()","get_max_convoi_length()=%i",depot->g
bt_copy_convoi.set_tooltip("Copy the selected convoi and its schedule or line");
add_komponente(&bt_copy_convoi);
- /*
- * [PANEL]
- * to test for presence, we must fist switch on all vehicles,
- * and switch off the timeline ...
- * otherwise the tabs will not be present at all
- */
- bool old_retired=show_retired_vehicles;
- bool old_show_all=show_all;
- show_retired_vehicles = true;
- show_all = true;
- einstellungen_t* e = get_welt()->get_einstellungen();
- char timeline = e->get_use_timeline();
- e->set_use_timeline(0);
- build_vehicle_lists();
- e->set_use_timeline(timeline);
- show_retired_vehicles = old_retired;
- show_all = old_show_all;
-
- cont_pas.add_komponente(&pas);
- scrolly_pas.set_show_scroll_x(false);
- scrolly_pas.set_size_corner(false);
- scrolly_pas.set_read_only(false);
-
- // always add
- tabs.add_tab(&scrolly_pas, translator::translate( depot->get_passenger_name() ) );
-
- cont_electrics.add_komponente(&electrics);
- scrolly_electrics.set_show_scroll_x(false);
- scrolly_electrics.set_size_corner(false);
- scrolly_electrics.set_read_only(false);
- // add only if there are any trolleybuses
- if(!electrics_vec.empty()) {
- tabs.add_tab(&scrolly_electrics, translator::translate( depot->get_electrics_name() ) );
- }
-
- cont_loks.add_komponente(&loks);
- scrolly_loks.set_show_scroll_x(false);
- scrolly_loks.set_size_corner(false);
- scrolly_loks.set_read_only(false);
- // add, if waggons are there ...
- if (!loks_vec.empty() || !waggons_vec.empty()) {
- tabs.add_tab(&scrolly_loks, translator::translate( depot->get_zieher_name() ) );
- }
-
- cont_waggons.add_komponente(&waggons);
- scrolly_waggons.set_show_scroll_x(false);
- scrolly_waggons.set_size_corner(false);
- scrolly_waggons.set_read_only(false);
- // only add, if there are waggons
- if (!waggons_vec.empty()) {
- tabs.add_tab(&scrolly_waggons, translator::translate( depot->get_haenger_name() ) );
- }
-
- pas.set_player_nr(depot->get_player_nr());
- pas.add_listener(this);
-
- electrics.set_player_nr(depot->get_player_nr());
- electrics.add_listener(this);
-
- loks.set_player_nr(depot->get_player_nr());
- loks.add_listener(this);
-
- waggons.set_player_nr(depot->get_player_nr());
- waggons.add_listener(this);
-
- add_komponente(&tabs);
- add_komponente(&div_tabbottom);
- add_komponente(&lb_veh_action);
-
- veh_action = va_append;
- bt_veh_action.set_typ(button_t::roundbox);
- bt_veh_action.add_listener(this);
- bt_veh_action.set_tooltip("Choose operation executed on clicking stored/new vehicles");
- add_komponente(&bt_veh_action);
-
- bt_obsolete.set_typ(button_t::square);
- bt_obsolete.set_text("Show obsolete");
- bt_obsolete.add_listener(this);
- bt_obsolete.set_tooltip("Show also vehicles no longer in production.");
- add_komponente(&bt_obsolete);
-
- bt_show_all.set_typ(button_t::square);
- bt_show_all.set_text("Show all");
- bt_show_all.add_listener(this);
- bt_show_all.set_tooltip("Show also vehicles that do not match for current action.");
- add_komponente(&bt_show_all);
-
koord gr = koord(0,0);
layout(&gr);
update_data();
@@ -264,53 +148,37 @@ DBG_DEBUG("depot_frame_t::depot_frame_t()","get_max_convoi_length()=%i",depot->g
// text will be translated by ourselves (after update data)!
lb_convois.set_text_pointer(txt_convois);
- lb_convoi_count.set_text_pointer(txt_convoi_count);
- lb_convoi_speed.set_text_pointer(txt_convoi_speed);
lb_convoi_value.set_text_pointer(txt_convoi_value);
lb_convoi_line.set_text_pointer(txt_convoi_line);
+ add_komponente(convoy_assembler);
+
// Hajo: Trigger layouting
set_resizemode(diagonal_resize);
}
-
+depot_frame_t::~depot_frame_t()
+{
+ delete convoy_assembler;
+}
void depot_frame_t::layout(koord *gr)
{
- koord placement;
- koord grid;
- int grid_dx;
- int placement_dx;
-
koord fgr = (gr!=NULL)? *gr : get_fenstergroesse();
- /*
- * These parameter are adjusted to resolution.
- * - Some extra space looks nicer.
- */
- grid.x = depot->get_x_grid() * get_base_tile_raster_width() / 64 + 4;
- grid.y = depot->get_y_grid() * get_base_tile_raster_width() / 64 + 6;
- placement.x = depot->get_x_placement() * get_base_tile_raster_width() / 64 + 2;
- placement.y = depot->get_y_placement() * get_base_tile_raster_width() / 64 + 2;
- if(depot->get_wegtyp()==road_wt && umgebung_t::drive_on_left) {
- // correct for dive on left
- placement.x -= (12*get_base_tile_raster_width())/64;
- placement.y -= (6*get_base_tile_raster_width())/64;
- }
- grid_dx = depot->get_x_grid() * get_base_tile_raster_width() / 64 / 2;
- placement_dx = depot->get_x_grid() * get_base_tile_raster_width() / 64 / 4;
-
/*
* Dialog format:
*
* Main structure are these parts from top to bottom:
*
* [SELECT] convoi-selector
- * [CONVOI] current convoi
+ * [CONVOI] current convoi (*)
* [ACTIONS] convoi action buttons
- * [PANEL] vehicle panel
- * [VINFO] vehicle infotext
+ * [PANEL] vehicle panel (*)
+ * [VINFO] vehicle infotext (*)
+ *
+ * (*) In CONVOI ASSEMBLER
*
*
* Structure of [SELECT] is:
@@ -322,49 +190,30 @@ void depot_frame_t::layout(koord *gr)
*/
int SELECT_HEIGHT = 14;
- /*
- * Structure of [CONVOI] is a image_list and an infos:
- *
- * [List]
- * [Info]
- *
- * The image list is horizontally "condensed".
- */
- int CINFO_HEIGHT = 14;
- int CLIST_WIDTH = depot->get_max_convoi_length() * (grid.x - grid_dx) + 2 * gui_image_list_t::BORDER;
- int CLIST_HEIGHT = grid.y + 2 * gui_image_list_t::BORDER;
- int CONVOI_WIDTH = CLIST_WIDTH + placement_dx;
-
/*
* Structure of [ACTIONS] is a row of buttons:
*
* [Start][Schedule][Destroy][Sell]
* [new Route][change Route][delete Route]
*/
- int ABUTTON_WIDTH = 96;
+ int ABUTTON_WIDTH = 128;
int ABUTTON_HEIGHT = 14;
int ACTIONS_WIDTH = 4 * ABUTTON_WIDTH;
int ACTIONS_HEIGHT = ABUTTON_HEIGHT + ABUTTON_HEIGHT; // @author hsiegeln: added "+ ABUTTON_HEIGHT"
-
- /*
- * Structure of [VINFO] is one multiline text.
- */
- int VINFO_HEIGHT = 86;
+ convoy_assembler->set_convoy_tabs_skip(ACTIONS_HEIGHT);
/*
* Total width is the max from [CONVOI] and [ACTIONS] width.
*/
- int MIN_TOTAL_WIDTH = max(CONVOI_WIDTH, ACTIONS_WIDTH);
- int TOTAL_WIDTH = max(fgr.x,max(CONVOI_WIDTH, ACTIONS_WIDTH));
+ int MIN_TOTAL_WIDTH = max(convoy_assembler->get_convoy_image_width(), ACTIONS_WIDTH);
+ int TOTAL_WIDTH = max(fgr.x,max(convoy_assembler->get_convoy_image_width(), ACTIONS_WIDTH));
/*
* Now we can do the first vertical adjustement:
*/
int SELECT_VSTART = 16;
- int CONVOI_VSTART = SELECT_VSTART + SELECT_HEIGHT + LINESPACE;
- int CINFO_VSTART = CONVOI_VSTART + CLIST_HEIGHT;
- int ACTIONS_VSTART = CINFO_VSTART + CINFO_HEIGHT + 2 + LINESPACE * 2;
- int PANEL_VSTART = ACTIONS_VSTART + ACTIONS_HEIGHT + 8;
+ int ASSEMBLER_VSTART = SELECT_VSTART + SELECT_HEIGHT + LINESPACE;
+ int ACTIONS_VSTART = ASSEMBLER_VSTART + convoy_assembler->get_convoy_height();
/*
* Now we determine the row/col layout for the panel and the total panel
@@ -372,19 +221,13 @@ void depot_frame_t::layout(koord *gr)
* build_vehicle_lists() fills loks_vec and waggon_vec.
* Total width will be expanded to match completo columns in panel.
*/
- int total_h = PANEL_VSTART+VINFO_HEIGHT + 17 + gui_tab_panel_t::HEADER_VSIZE + 2 * gui_image_list_t::BORDER;
- int PANEL_ROWS = max(1, ((fgr.y-total_h)/grid.y) );
- if(gr && gr->y==0) {
- PANEL_ROWS = 3;
- }
- int PANEL_HEIGHT = PANEL_ROWS * grid.y + gui_tab_panel_t::HEADER_VSIZE + 2 * gui_image_list_t::BORDER;
- int MIN_PANEL_HEIGHT = grid.y + gui_tab_panel_t::HEADER_VSIZE + 2 * gui_image_list_t::BORDER;
+ convoy_assembler->set_panel_rows(gr && gr->y==0?-1:fgr.y-ASSEMBLER_VSTART);
/*
* Now we can do the complete vertical adjustement:
*/
- int TOTAL_HEIGHT = PANEL_VSTART + PANEL_HEIGHT + VINFO_HEIGHT + 17;
- int MIN_TOTAL_HEIGHT = PANEL_VSTART + MIN_PANEL_HEIGHT + VINFO_HEIGHT + 17;
+ int TOTAL_HEIGHT = ASSEMBLER_VSTART + convoy_assembler->get_height();
+ int MIN_TOTAL_HEIGHT = ASSEMBLER_VSTART + convoy_assembler->get_min_height();
/*
* DONE with layout planning - now build everything.
@@ -424,15 +267,13 @@ void depot_frame_t::layout(koord *gr)
/*
* [CONVOI]
*/
- convoi.set_grid(koord(grid.x - grid_dx, grid.y));
- convoi.set_placement(koord(placement.x - placement_dx, placement.y));
- convoi.set_pos(koord((TOTAL_WIDTH-CLIST_WIDTH)/2, CONVOI_VSTART));
- convoi.set_groesse(koord(CLIST_WIDTH, CLIST_HEIGHT));
+ convoy_assembler->set_pos(koord(0,ASSEMBLER_VSTART));
+ convoy_assembler->set_groesse(koord(TOTAL_WIDTH,convoy_assembler->get_height()));
+ convoy_assembler->layout();
- lb_convoi_count.set_pos(koord(4, CINFO_VSTART));
- lb_convoi_speed.set_pos(koord(4, CINFO_VSTART + LINESPACE));
- lb_convoi_value.set_pos(koord(TOTAL_WIDTH-10, CINFO_VSTART));
- lb_convoi_line.set_pos(koord(4, CINFO_VSTART + LINESPACE * 2));
+ lb_convoi_value.set_pos(koord(TOTAL_WIDTH-10, ASSEMBLER_VSTART + convoy_assembler->get_convoy_image_height()));
+ lb_convoi_line.set_pos(koord(4, ASSEMBLER_VSTART + convoy_assembler->get_convoy_image_height() + LINESPACE * 2));
+
/*
* [ACTIONS]
@@ -472,61 +313,6 @@ void depot_frame_t::layout(koord *gr)
bt_copy_convoi.set_pos(koord(TOTAL_WIDTH*3/4, ACTIONS_VSTART+ABUTTON_HEIGHT));
bt_copy_convoi.set_groesse(koord(TOTAL_WIDTH-TOTAL_WIDTH*3/4, ABUTTON_HEIGHT));
bt_copy_convoi.set_text("Copy Convoi");
-
- /*
- * [PANEL]
- */
- tabs.set_pos(koord(0, PANEL_VSTART));
- tabs.set_groesse(koord(TOTAL_WIDTH, PANEL_HEIGHT));
-
- pas.set_grid(grid);
- pas.set_placement(placement);
- pas.set_groesse(tabs.get_groesse());
- pas.recalc_size();
- pas.set_pos(koord(1,1));
- cont_pas.set_groesse(pas.get_groesse());
- scrolly_pas.set_groesse(scrolly_pas.get_groesse());
-
- electrics.set_grid(grid);
- electrics.set_placement(placement);
- electrics.set_groesse(tabs.get_groesse());
- electrics.recalc_size();
- electrics.set_pos(koord(1,1));
- cont_electrics.set_groesse(electrics.get_groesse());
- scrolly_electrics.set_groesse(scrolly_electrics.get_groesse());
-
- loks.set_grid(grid);
- loks.set_placement(placement);
- loks.set_groesse(tabs.get_groesse());
- loks.recalc_size();
- loks.set_pos(koord(1,1));
- cont_loks.set_pos(koord(0,0));
- cont_loks.set_groesse(loks.get_groesse());
- scrolly_loks.set_groesse(scrolly_loks.get_groesse());
-
- waggons.set_grid(grid);
- waggons.set_placement(placement);
- waggons.set_groesse(tabs.get_groesse());
- waggons.recalc_size();
- waggons.set_pos(koord(1,1));
- cont_waggons.set_groesse(waggons.get_groesse());
- scrolly_waggons.set_groesse(scrolly_waggons.get_groesse());
-
- div_tabbottom.set_pos(koord(0,PANEL_VSTART+PANEL_HEIGHT));
- div_tabbottom.set_groesse(koord(TOTAL_WIDTH,0));
-
- lb_veh_action.set_pos(koord(TOTAL_WIDTH-ABUTTON_WIDTH, PANEL_VSTART + PANEL_HEIGHT+4));
-
- bt_veh_action.set_pos(koord(TOTAL_WIDTH-ABUTTON_WIDTH, PANEL_VSTART + PANEL_HEIGHT + 14));
- bt_veh_action.set_groesse(koord(ABUTTON_WIDTH, ABUTTON_HEIGHT));
-
- bt_show_all.set_pos(koord(TOTAL_WIDTH-(ABUTTON_WIDTH*5)/2, PANEL_VSTART + PANEL_HEIGHT + 4 ));
- bt_show_all.set_groesse(koord(ABUTTON_WIDTH, ABUTTON_HEIGHT));
- bt_show_all.pressed = show_all;
-
- bt_obsolete.set_pos(koord(TOTAL_WIDTH-(ABUTTON_WIDTH*5)/2, PANEL_VSTART + PANEL_HEIGHT + 16));
- bt_obsolete.set_groesse(koord(ABUTTON_WIDTH, ABUTTON_HEIGHT));
- bt_obsolete.pressed = show_retired_vehicles;
}
@@ -540,146 +326,6 @@ void depot_frame_t::set_fenstergroesse( koord gr )
gui_frame_t::set_fenstergroesse(gr);
}
-
-// true if already stored here
-bool depot_frame_t::is_contained(const vehikel_besch_t *info)
-{
- if(depot->vehicle_count()>0) {
- slist_iterator_tpl iter(depot->get_vehicle_list());
- while(iter.next()) {
- if(iter.get_current()->get_besch()==info) {
- return true;
- }
- }
- }
- return false;
-}
-
-
-// add a single vehicle (helper function)
-void depot_frame_t::add_to_vehicle_list(const vehikel_besch_t *info)
-{
- // prissi: ist a non-electric track?
- // Hajo: check for timeline
- // prissi: and retirement date
- gui_image_list_t::image_data_t img_data;
-
- img_data.image = info->get_basis_bild();
- img_data.count = 0;
- img_data.lcolor = img_data.rcolor = EMPTY_IMAGE_BAR;
- img_data.text = info->get_name();
-
- if( info->get_engine_type() == vehikel_besch_t::electric && (info->get_ware()==warenbauer_t::passagiere || info->get_ware()==warenbauer_t::post) ) {
- electrics_vec.append(img_data);
- vehicle_map.set(info, &electrics_vec.back());
- }
- // since they come "pre-sorted" for the vehikelbauer, we have to do nothing to keep them sorted
- else if(info->get_ware()==warenbauer_t::passagiere || info->get_ware()==warenbauer_t::post) {
- pas_vec.append(img_data);
- vehicle_map.set(info, &pas_vec.back());
- }
- else if(info->get_leistung() > 0 || info->get_zuladung()==0) {
- loks_vec.append(img_data);
- vehicle_map.set(info, &loks_vec.back());
- }
- else {
- waggons_vec.append(img_data);
- vehicle_map.set(info, &waggons_vec.back());
- }
-}
-
-
-
-// add all current vehicles
-void depot_frame_t::build_vehicle_lists()
-{
- if(depot->get_vehicle_type()==NULL) {
- // there are tracks etc. but now vehicles => do nothing
- return;
- }
-
- const int month_now = get_welt()->get_timeline_year_month();
-
- if(electrics_vec.empty() && pas_vec.empty() && loks_vec.empty() && waggons_vec.empty()) {
- int loks = 0, waggons = 0, pax=0, electrics = 0;
- slist_iterator_tpl vehinfo(depot->get_vehicle_type());
- while (vehinfo.next()) {
- const vehikel_besch_t* info = vehinfo.get_current();
- if( info->get_engine_type() == vehikel_besch_t::electric && (info->get_ware()==warenbauer_t::passagiere || info->get_ware()==warenbauer_t::post)) {
- electrics++;
- }
- else if(info->get_ware()==warenbauer_t::passagiere || info->get_ware()==warenbauer_t::post) {
- pax++;
- }
- else if(info->get_leistung() > 0 || info->get_zuladung()==0) {
- loks++;
- }
- else {
- waggons++;
- }
- }
- pas_vec.resize(pax);
- electrics_vec.resize(electrics);
- loks_vec.resize(loks);
- waggons_vec.resize(waggons);
- }
- pas_vec.clear();
- electrics_vec.clear();
- loks_vec.clear();
- waggons_vec.clear();
-
- vehicle_map.clear();
-
- // we do not allow to built electric vehicle in a depot without electrification
- const waytype_t wt = depot->get_wegtyp();
- const weg_t *w = get_welt()->lookup(depot->get_pos())->get_weg(wt!=tram_wt ? wt : track_wt);
- const bool weg_electrified = w ? w->is_electrified() : false;
-
- // use this to show only sellable vehicles
- if(!show_all && veh_action==va_sell) {
- // just list the one to sell
- slist_iterator_tpl iter2(depot->get_vehicle_list());
- while(iter2.next()) {
- if(vehicle_map.get(iter2.get_current()->get_besch())) {
- continue;
- }
- add_to_vehicle_list( iter2.get_current()->get_besch() );
- }
- }
- else {
- // list only matching ones
- slist_iterator_tpl vehinfo(depot->get_vehicle_type());
- while (vehinfo.next()) {
- const vehikel_besch_t* info = vehinfo.get_current();
- const vehikel_besch_t *veh = NULL;
- convoihandle_t cnv = depot->get_convoi(icnv);
- if(cnv.is_bound() && cnv->get_vehikel_anzahl()>0) {
- veh = (veh_action == va_insert) ? cnv->get_vehikel(0)->get_besch() : cnv->get_vehikel(cnv->get_vehikel_anzahl() - 1)->get_besch();
- }
-
- // current vehicle
- if( is_contained(info) ||
- ((weg_electrified || info->get_engine_type()!=vehikel_besch_t::electric) &&
- ((!info->is_future(month_now)) && (show_retired_vehicles || (!info->is_retired(month_now)) ) ) )) {
- // check, if allowed
- bool append = true;
- if(!show_all) {
- if(veh_action == va_insert) {
- append = !(!convoi_t::pruefe_nachfolger(info, veh) || (veh && !convoi_t::pruefe_vorgaenger(info, veh)));
- } else if(veh_action == va_append) {
- append = convoi_t::pruefe_vorgaenger(veh, info);
- }
- }
- if(append) {
- add_to_vehicle_list( info );
- }
- }
- }
- }
-DBG_DEBUG("depot_frame_t::build_vehicle_lists()","finally %i passenger vehicle, %i engines, %i good wagons",pas_vec.get_count(),loks_vec.get_count(),waggons_vec.get_count());
-}
-
-
static void get_line_list(const depot_t* depot, vector_tpl* lines)
{
depot->get_besitzer()->simlinemgmt.get_lines(depot->get_line_type(), lines);
@@ -688,13 +334,6 @@ static void get_line_list(const depot_t* depot, vector_tpl* lines)
void depot_frame_t::update_data()
{
- static const char *txt_veh_action[3] = { "anhaengen", "voranstellen", "verkaufen" };
-
- // change green into blue for retired vehicles
- const int month_now = get_welt()->get_timeline_year_month();
-
- bt_veh_action.set_text(txt_veh_action[veh_action]);
-
switch(depot->convoi_count()) {
case 0:
tstrncpy(txt_convois, translator::translate("no convois"), lengthof(txt_convois));
@@ -719,105 +358,9 @@ void depot_frame_t::update_data()
* Reset counts and check for valid vehicles
*/
convoihandle_t cnv = depot->get_convoi(icnv);
- const vehikel_besch_t *veh = NULL;
-
- convoi_pics.clear();
if(cnv.is_bound() && cnv->get_vehikel_anzahl() > 0) {
-
tstrncpy(txt_cnv_name, cnv->get_internal_name(), lengthof(txt_cnv_name));
inp_name.set_text(txt_cnv_name, lengthof(txt_cnv_name));
-
- unsigned i;
- for(i=0; iget_vehikel_anzahl(); i++) {
-
- // just make sure, there is this vehicle also here!
- const vehikel_besch_t *info=cnv->get_vehikel(i)->get_besch();
- if(vehicle_map.get(info)==NULL) {
- add_to_vehicle_list( info );
- }
-
- gui_image_list_t::image_data_t img_data;
- img_data.image = cnv->get_vehikel(i)->get_besch()->get_basis_bild();
- img_data.count = 0;
- img_data.lcolor = img_data.rcolor= EMPTY_IMAGE_BAR;
- img_data.text = cnv->get_vehikel(i)->get_besch()->get_name();
- convoi_pics.append(img_data);
- }
-
- /* color bars for current convoi: */
- convoi_pics[0].lcolor = convoi_t::pruefe_vorgaenger(NULL, cnv->get_vehikel(0)->get_besch()) ? COL_GREEN : COL_YELLOW;
- for( i=1; iget_vehikel_anzahl(); i++) {
- convoi_pics[i - 1].rcolor = convoi_t::pruefe_nachfolger(cnv->get_vehikel(i - 1)->get_besch(), cnv->get_vehikel(i)->get_besch()) ? COL_GREEN : COL_RED;
- convoi_pics[i].lcolor = convoi_t::pruefe_vorgaenger(cnv->get_vehikel(i - 1)->get_besch(), cnv->get_vehikel(i)->get_besch()) ? COL_GREEN : COL_RED;
- }
- convoi_pics[i - 1].rcolor = convoi_t::pruefe_nachfolger(cnv->get_vehikel(i - 1)->get_besch(), NULL) ? COL_GREEN : COL_YELLOW;
-
- // change grren into blue for retired vehicles
- for(i=0; iget_vehikel_anzahl(); i++) {
- if(cnv->get_vehikel(i)->get_besch()->is_future(month_now) || cnv->get_vehikel(i)->get_besch()->is_retired(month_now)) {
- if (convoi_pics[i].lcolor == COL_GREEN) {
- convoi_pics[i].lcolor = COL_BLUE;
- }
- if (convoi_pics[i].rcolor == COL_GREEN) {
- convoi_pics[i].rcolor = COL_BLUE;
- }
- }
- }
-
- if(veh_action == va_insert) {
- veh = cnv->get_vehikel(0)->get_besch();
- } else if(veh_action == va_append) {
- veh = cnv->get_vehikel(cnv->get_vehikel_anzahl() - 1)->get_besch();
- }
- }
-
- ptrhashtable_iterator_tpl iter1(vehicle_map);
- while(iter1.next()) {
- const vehikel_besch_t *info = iter1.get_current_key();
- const uint8 ok_color = info->is_future(month_now) || info->is_retired(month_now) ? COL_BLUE: COL_GREEN;
-
- iter1.get_current_value()->count = 0;
- iter1.get_current_value()->lcolor = ok_color;
- iter1.get_current_value()->rcolor = ok_color;
-
- /*
- * color bars for current convoi:
- * green/green okay to append/insert
- * red/red cannot be appended/inserted
- * green/yellow append okay, cannot be end of train
- * yellow/green insert okay, cannot be start of train
- */
-
- if(veh_action == va_insert) {
- if (!convoi_t::pruefe_nachfolger(info, veh) || (veh && !convoi_t::pruefe_vorgaenger(info, veh))) {
- iter1.get_current_value()->lcolor = COL_RED;
- iter1.get_current_value()->rcolor = COL_RED;
- } else if(!convoi_t::pruefe_vorgaenger(NULL, info)) {
- iter1.get_current_value()->lcolor = COL_YELLOW;
- }
- } else if(veh_action == va_append) {
- if(!convoi_t::pruefe_vorgaenger(veh, info) || (veh && !convoi_t::pruefe_nachfolger(veh, info))) {
- iter1.get_current_value()->lcolor = COL_RED;
- iter1.get_current_value()->rcolor = COL_RED;
- } else if(!convoi_t::pruefe_nachfolger(info, NULL)) {
- iter1.get_current_value()->rcolor = COL_YELLOW;
- }
- }
-
-//DBG_DEBUG("depot_frame_t::update_data()","current %i = %s with color %i",info->get_name(),iter1.get_current_value()->lcolor);
- }
-
- slist_iterator_tpl iter2(depot->get_vehicle_list());
- while(iter2.next()) {
- gui_image_list_t::image_data_t *imgdat=vehicle_map.get(iter2.get_current()->get_besch());
- // can fail, if currently not visible
- if(imgdat) {
- imgdat->count++;
- if(veh_action == va_sell) {
- imgdat->lcolor = COL_GREEN;
- imgdat->rcolor = COL_GREEN;
- }
- }
}
// update the line selector
@@ -837,162 +380,9 @@ void depot_frame_t::update_data()
line_selector.set_selection( line_selector.count_elements()-1 );
}
}
+ convoy_assembler->update_data();
}
-
-sint32 depot_frame_t::calc_restwert(const vehikel_besch_t *veh_type)
-{
- sint32 wert = 0;
-
- slist_iterator_tpl iter(depot->get_vehicle_list());
- while(iter.next()) {
- if(iter.get_current()->get_besch() == veh_type) {
- wert += iter.get_current()->calc_restwert();
- }
- }
- return wert;
-}
-
-
-// returns the indest of the old/newest vehicle in a list
-vehikel_t* depot_frame_t::find_oldest_newest(const vehikel_besch_t* besch, bool old)
-{
- vehikel_t* found_veh = NULL;
- slist_iterator_tpl iter(depot->get_vehicle_list());
- while (iter.next()) {
- vehikel_t* veh = iter.get_current();
- if (veh->get_besch() == besch) {
- // joy of XOR, finally a line where I could use it!
- if (found_veh == NULL ||
- old ^ (found_veh->get_insta_zeit() > veh->get_insta_zeit())) {
- found_veh = veh;
- }
- }
- }
- return found_veh;
-}
-
-
-
-void depot_frame_t::image_from_storage_list(gui_image_list_t::image_data_t *bild_data)
-{
- if(bild_data->lcolor != COL_RED && bild_data->rcolor != COL_RED) {
- // we buy/sell all vehicles together!
- slist_tplnew_vehicle_info;
- const vehikel_besch_t *info = vehikelbauer_t::get_info(bild_data->text);
- const vehikel_besch_t *start_info = info;
-
- if(veh_action==va_insert || veh_action==va_sell) {
- // start of composition
- while (info->get_vorgaenger_count() == 1 && info->get_vorgaenger(0) != NULL) {
- info = info->get_vorgaenger(0);
- new_vehicle_info.insert(info);
- }
- info = start_info;
- }
- // not get the end ...
- while(info) {
- new_vehicle_info.append( info );
-DBG_MESSAGE("depot_frame_t::image_from_storage_list()","appended %s",info->get_name() );
- if(info->get_nachfolger_count()!=1 || (veh_action==va_insert && info==start_info)) {
- break;
- }
- info = info->get_nachfolger(0);
- }
-
- if(veh_action == va_sell) {
- while(new_vehicle_info.get_count()) {
- /*
- * We sell the newest vehicle - gives most money back.
- */
- vehikel_t* veh = find_oldest_newest(new_vehicle_info.remove_first(), false);
- if (veh != NULL) {
- depot->sell_vehicle(veh);
- }
- }
- }
- else {
-
- // append/insert into convoi
- convoihandle_t cnv = depot->get_convoi(icnv);
- if(!cnv.is_bound()) {
- if( convoihandle_t::is_exhausted() ) {
- create_win( new news_img("Convoi handles exhausted!"), w_time_delete, magic_none);
- return;
- }
- // create a new convoi
- cnv = depot->add_convoi();
- icnv = depot->convoi_count() - 1;
- cnv->set_name(new_vehicle_info.front()->get_name());
- }
-
- if(cnv->get_vehikel_anzahl()+new_vehicle_info.get_count() <= depot->get_max_convoi_length()) {
-
- for( unsigned i=0; i we buy it
- veh = depot->buy_vehicle(vb);
- }
- depot->append_vehicle(cnv, veh, veh_action == va_insert);
- }
- }
- }
-
- build_vehicle_lists();
- update_data();
- layout(NULL);
- }
-}
-
-
-
-void depot_frame_t::image_from_convoi_list(uint nr)
-{
- const convoihandle_t cnv = depot->get_convoi(icnv);
-
-//DBG_DEBUG("depot_frame_t::bild_gewaehlt()","convoi index %i",nr);
- if(cnv.is_bound() && nrget_vehikel_anzahl() ) {
-
- // we remove all connected vehicles together!
- // find start
- unsigned start_nr = nr;
- while(start_nr>0) {
- start_nr --;
- const vehikel_besch_t *info = cnv->get_vehikel(start_nr)->get_besch();
- if(info->get_nachfolger_count()!=1) {
- start_nr ++;
- break;
- }
- }
- // find end
- while(nrget_vehikel_anzahl()) {
- const vehikel_besch_t *info = cnv->get_vehikel(nr)->get_besch();
- nr ++;
- if(info->get_nachfolger_count()!=1) {
- break;
- }
- }
- // now remove the vehicles
- if(cnv->get_vehikel_anzahl()==nr-start_nr) {
- depot->disassemble_convoi(cnv, false);
- icnv--;
- }
- else {
- for( unsigned i=start_nr; iremove_vehicle(cnv, start_nr);
- }
- }
- }
-}
-
-
-
bool depot_frame_t::action_triggered( gui_action_creator_t *komp,value_t p)
{
convoihandle_t cnv = depot->get_convoi(icnv);
@@ -1001,9 +391,68 @@ bool depot_frame_t::action_triggered( gui_action_creator_t *komp,value_t p)
}
if(komp != NULL) { // message from outside!
- if(komp == &bt_start) {
+ if(komp == convoy_assembler) {
+ const koord k=*static_cast(p.p);
+ switch (k.x) {
+ case gui_convoy_assembler_t::clear_convoy_action:
+ if (cnv.is_bound()) {
+ depot->disassemble_convoi(cnv, false);
+ icnv--;
+ update_convoy();
+ }
+ break;
+ case gui_convoy_assembler_t::remove_vehicle_action:
+ if (cnv.is_bound()) {
+ depot->remove_vehicle(cnv, k.y);
+ }
+ break;
+ default: // append/insert_in_front
+ const vehikel_besch_t* vb;
+ if (k.x==gui_convoy_assembler_t::insert_vehicle_in_front_action) {
+ vb=(*convoy_assembler->get_vehicles())[0];
+ } else {
+ vb=(*convoy_assembler->get_vehicles())[convoy_assembler->get_vehicles()->get_count()-1];
+ }
+ vehikel_t* veh = depot->find_oldest_newest(vb, true);
+ if (veh == NULL)
+ {
+ // nothing there => we buy it
+ veh = depot->buy_vehicle(vb, convoy_assembler->get_upgrade() == gui_convoy_assembler_t::u_upgrade);
+ if(convoy_assembler->get_upgrade() == gui_convoy_assembler_t::u_upgrade && cnv.is_bound())
+ {
+ //Upgrading, so vehicles must be *replaced*.
+ for(uint16 i = 0; i < cnv->get_vehikel_anzahl(); i ++)
+ {
+ for(uint8 c = 0; c < cnv->get_vehikel(i)->get_besch()->get_upgrades_count(); c ++)
+ {
+ if(cnv->get_vehikel(i)->get_besch()->get_upgrades(c)->get_name() == vb->get_name())
+ {
+ cnv->get_vehikel(i)->set_besch(vb);
+ update_convoy();
+ goto end;
+ }
+ }
+ }
+ }
+ }
+end:
+ if(!cnv.is_bound())
+ {
+ // create a new convoi
+ cnv = depot->add_convoi();
+ icnv = depot->convoi_count() - 1;
+ cnv->set_name((*convoy_assembler->get_vehicles())[0]->get_name());
+ }
+ if(convoy_assembler->get_upgrade() == gui_convoy_assembler_t::u_buy)
+ {
+ depot->append_vehicle(cnv, veh, k.x == gui_convoy_assembler_t::insert_vehicle_in_front_action);
+ }
+ break;
+ }
+ } else if(komp == &bt_start) {
if (depot->start_convoi(cnv)) {
icnv--;
+ update_convoy();
}
} else if(komp == &bt_schedule) {
fahrplaneingabe();
@@ -1011,48 +460,32 @@ bool depot_frame_t::action_triggered( gui_action_creator_t *komp,value_t p)
} else if(komp == &bt_destroy) {
if (depot->disassemble_convoi(cnv, false)) {
icnv--;
+ update_convoy();
}
} else if(komp == &bt_sell) {
if (depot->disassemble_convoi(cnv, true)) {
icnv--;
+ update_convoy();
}
} else if(komp == &bt_next) {
if(++icnv == (int)depot->convoi_count()) {
icnv = -1;
}
+ update_convoy();
} else if(komp == &bt_prev) {
if(icnv-- == -1) {
icnv = depot->convoi_count() - 1;
}
- // image lsit selction here ...
- } else if(komp == &convoi) {
- image_from_convoi_list( p.i );
- } else if(komp == &pas) {
- image_from_storage_list(&pas_vec[p.i]);
- } else if (komp == &electrics) {
- image_from_storage_list(&electrics_vec[p.i]);
- } else if(komp == &loks) {
- image_from_storage_list(&loks_vec[p.i]);
- } else if(komp == &waggons) {
- image_from_storage_list(&waggons_vec[p.i]);
- } else if(komp == &bt_obsolete) {
- show_retired_vehicles = (show_retired_vehicles==0);
- } else if(komp == &bt_show_all) {
- show_all = (show_all==0);
- } else if(komp == &bt_veh_action) {
- if(veh_action== va_sell) {
- veh_action = va_append;
- }
- else {
- veh_action = veh_action+1;
- }
+ update_convoy();
} else if(komp == &bt_new_line) {
new_line();
return true;
} else if(komp == &bt_change_line) {
change_line();
return true;
- } else if(komp == &bt_copy_convoi) {
+ }
+ else if(komp == &bt_copy_convoi)
+ {
if( convoihandle_t::is_exhausted() ) {
create_win( new news_img("Convoi handles exhausted!"), w_time_delete, magic_none);
}
@@ -1066,7 +499,7 @@ bool depot_frame_t::action_triggered( gui_action_creator_t *komp,value_t p)
} else if(komp == &line_selector) {
int selection = p.i;
//DBG_MESSAGE("depot_frame_t::action_triggered()","line selection=%i",selection);
- if( (uint32)(selection-1)<(uint32)line_selector.count_elements() ) {
+ if( (unsigned)(selection-1) lines;
get_line_list(depot, &lines);
selected_line = lines[selection - 1];
@@ -1081,7 +514,7 @@ bool depot_frame_t::action_triggered( gui_action_creator_t *komp,value_t p)
else {
return false;
}
- build_vehicle_lists();
+ convoy_assembler->build_vehicle_lists();
}
update_data();
layout(NULL);
@@ -1125,7 +558,7 @@ void depot_frame_t::infowin_event(const event_t *ev)
koord gr = get_fenstergroesse();
set_fenstergroesse(gr);
} else if(ev->ev_class == INFOWIN && ev->ev_code == WIN_OPEN) {
- build_vehicle_lists();
+ convoy_assembler->build_vehicle_lists();
update_data();
layout(NULL);
}
@@ -1150,38 +583,7 @@ depot_frame_t::zeichnen(koord pos, koord groesse)
const convoihandle_t cnv = depot->get_convoi(icnv);
if(cnv.is_bound()) {
if(cnv->get_vehikel_anzahl() > 0) {
- uint32 total_power=0;
- uint32 total_max_weight=0;
- uint32 total_min_weight=0;
- uint16 max_speed=0;
- uint16 min_speed=0;
- for( unsigned i=0; iget_vehikel_anzahl(); i++) {
- const vehikel_besch_t *besch = cnv->get_vehikel(i)->get_besch();
-
- total_power += besch->get_leistung()*besch->get_gear()/64;
- total_min_weight += besch->get_gewicht();
- total_max_weight += besch->get_gewicht();
-
- uint32 max_weight =0;
- uint32 min_weight =100000;
- for(uint32 j=0; jget_ware()->get_catg_index()==ware->get_catg_index()) {
- max_weight = max(max_weight, ware->get_weight_per_unit());
- min_weight = min(min_weight, ware->get_weight_per_unit());
- }
- }
- total_max_weight += (max_weight*besch->get_zuladung()+499)/1000;
- total_min_weight += (min_weight*besch->get_zuladung()+499)/1000;
- }
- max_speed = min(speed_to_kmh(cnv->get_min_top_speed()), (uint32) sqrt((((double)total_power/total_min_weight)-1)*2500));
- min_speed = min(speed_to_kmh(cnv->get_min_top_speed()), (uint32) sqrt((((double)total_power/total_max_weight)-1)*2500));
- sprintf(txt_convoi_count, "%s %d (%s %i)",
- translator::translate("Fahrzeuge:"), cnv->get_vehikel_anzahl(),
- translator::translate("Station tiles:"), cnv->get_tile_length() );
- sprintf(txt_convoi_speed, "%s %d(%d)km/h", translator::translate("Max. speed:"), min_speed, max_speed );
- sprintf(txt_convoi_value, "%s %ld$", translator::translate("Restwert:"), (long)(cnv->calc_restwert()/100) );
+ sprintf(txt_convoi_value, "%s %d$", translator::translate("Restwert:"), cnv->calc_restwert()/100);
// just recheck if schedules match
if( cnv->get_line().is_bound() && cnv->get_line()->get_schedule()->ist_abgeschlossen() ) {
cnv->check_pending_updates();
@@ -1198,28 +600,21 @@ depot_frame_t::zeichnen(koord pos, koord groesse)
}
}
else {
- tstrncpy(txt_convoi_count, "keine Fahrzeuge", lengthof(txt_convoi_count));
*txt_convoi_value = '\0';
}
}
else {
static char empty[2] = "\0";
inp_name.set_text( empty, 0);
- *txt_convoi_count = '\0';
- *txt_convoi_speed = '\0';
*txt_convoi_value = '\0';
*txt_convoi_line = '\0';
}
- bt_obsolete.pressed = show_retired_vehicles; // otherwise the button would not show depressed
- bt_show_all.pressed = show_all; // otherwise the button would not show depressed
-
gui_frame_t::zeichnen(pos, groesse);
if(!cnv.is_bound()) {
display_proportional_clip(pos.x+inp_name.get_pos().x+2, pos.y+inp_name.get_pos().y+18, translator::translate("new convoi"), ALIGN_LEFT, COL_GREY1, true);
}
- draw_vehicle_info_text(pos);
}
@@ -1239,7 +634,8 @@ void depot_frame_t::apply_line()
if(icnv > -1) {
convoihandle_t cnv = depot->get_convoi(icnv);
// if no convoi is selected, do nothing
- if (!cnv.is_bound()) {
+ if (!cnv.is_bound())
+ {
return;
}
@@ -1295,139 +691,3 @@ void depot_frame_t::fahrplaneingabe()
create_win( new news_img("Please choose vehicles first\n"), w_time_delete, magic_none);
}
}
-
-
-void depot_frame_t::draw_vehicle_info_text(koord pos)
-{
- char buf[1024];
- const char *c;
-
- gui_image_list_t *lst;
- if( tabs.get_aktives_tab()==&scrolly_pas ) {
- lst = dynamic_cast(&pas);
- }
- else if( tabs.get_aktives_tab()==&scrolly_electrics ) {
- lst = dynamic_cast(&electrics);
- }
- else if( tabs.get_aktives_tab()==&scrolly_loks ) {
- lst = dynamic_cast(&loks);
- }
- else {
- lst = dynamic_cast(&waggons);
- }
- int x = get_maus_x();
- int y = get_maus_y();
- int value = -1;
- const vehikel_besch_t *veh_type = NULL;
- koord relpos = koord( 0, ((gui_scrollpane_t *)tabs.get_aktives_tab())->get_scroll_y() );
- int sel_index = lst->index_at(pos + tabs.get_pos() - relpos, x, y - 16 - gui_tab_panel_t::HEADER_VSIZE);
-
- if ((sel_index != -1) && (tabs.getroffen(x-pos.x,y-pos.y))) {
- const vector_tpl& vec = (lst == &electrics ? electrics_vec : (lst == &pas ? pas_vec : (lst == &loks ? loks_vec : waggons_vec)));
- veh_type = vehikelbauer_t::get_info(vec[sel_index].text);
- if (vec[sel_index].count > 0) {
- value = calc_restwert(veh_type) / 100;
- }
- }
- else {
- sel_index = convoi.index_at(pos , x, y - 16);
- if(sel_index != -1) {
- convoihandle_t cnv = depot->get_convoi(icnv);
- veh_type = cnv->get_vehikel(sel_index)->get_besch();
- value = cnv->get_vehikel(sel_index)->calc_restwert()/100;
- }
- }
-
- switch(depot->vehicle_count()) {
- case 0:
- c = translator::translate("Keine Einzelfahrzeuge im Depot");
- break;
- case 1:
- c = translator::translate("1 Einzelfahrzeug im Depot");
- break;
- default:
- sprintf(buf, translator::translate("%d Einzelfahrzeuge im Depot"), depot->vehicle_count());
- c = buf;
- break;
- }
- display_proportional( pos.x + 4, pos.y + tabs.get_pos().y + tabs.get_groesse().y + 16 + 4, c, ALIGN_LEFT, COL_BLACK, true );
-
- if(veh_type) {
- // lok oder waggon ?
- if(veh_type->get_leistung() > 0) {
- //lok
- const int zuladung = veh_type->get_zuladung();
-
- char name[128];
-
- sprintf(name,
- "%s (%s)",
- translator::translate(veh_type->get_name()),
- translator::translate(engine_type_names[veh_type->get_engine_type()+1]));
-
- int n = sprintf(buf,
- translator::translate("LOCO_INFO"),
- name,
- veh_type->get_preis()/100,
- veh_type->get_betriebskosten()/100.0,
- veh_type->get_leistung(),
- veh_type->get_geschw(),
- veh_type->get_gewicht()
- );
-
- if(zuladung>0) {
- sprintf(buf + n,
- translator::translate("LOCO_CAP"),
- zuladung,
- translator::translate(veh_type->get_ware()->get_mass()),
- veh_type->get_ware()->get_catg() == 0 ? translator::translate(veh_type->get_ware()->get_name()) : translator::translate(veh_type->get_ware()->get_catg_name())
- );
- }
-
- }
- else {
- // waggon
- sprintf(buf,
- translator::translate("WAGGON_INFO"),
- translator::translate(veh_type->get_name()),
- veh_type->get_preis()/100,
- veh_type->get_betriebskosten()/100.0,
- veh_type->get_zuladung(),
- translator::translate(veh_type->get_ware()->get_mass()),
- veh_type->get_ware()->get_catg() == 0 ?
- translator::translate(veh_type->get_ware()->get_name()) :
- translator::translate(veh_type->get_ware()->get_catg_name()),
- veh_type->get_gewicht(),
- veh_type->get_geschw()
- );
- }
- display_multiline_text( pos.x + 4, pos.y + tabs.get_pos().y + tabs.get_groesse().y + 31 + LINESPACE*1 + 4, buf, COL_BLACK);
-
- // column 2
- int n = sprintf(buf, "%s %s %04d\n",
- translator::translate("Intro. date:"),
- translator::get_month_name(veh_type->get_intro_year_month()%12),
- veh_type->get_intro_year_month()/12 );
-
- if(veh_type->get_retire_year_month() !=DEFAULT_RETIRE_DATE*12) {
- n += sprintf(buf+n, "%s %s %04d\n",
- translator::translate("Retire. date:"),
- translator::get_month_name(veh_type->get_retire_year_month()%12),
- veh_type->get_retire_year_month()/12 );
- }
-
- if(veh_type->get_leistung() > 0 && veh_type->get_gear()!=64) {
- n+= sprintf(buf+n, "%s %0.2f : 1\n", translator::translate("Gear:"), veh_type->get_gear()/64.0);
- }
-
- if(veh_type->get_copyright()!=NULL && veh_type->get_copyright()[0]!=0) {
- n += sprintf(buf + n, translator::translate("Constructed by %s"), veh_type->get_copyright());
- }
-
- if(value != -1) {
- sprintf(buf + strlen(buf), "%s %d Cr", translator::translate("Restwert:"), value);
- }
-
- display_multiline_text( pos.x + 200, pos.y + tabs.get_pos().y + tabs.get_groesse().y + 31 + LINESPACE*2 + 4, buf, COL_BLACK);
- }
-}
diff --git a/gui/depot_frame.h b/gui/depot_frame.h
index c261d90492c..ade8de38feb 100644
--- a/gui/depot_frame.h
+++ b/gui/depot_frame.h
@@ -20,7 +20,9 @@
#include "components/gui_button.h"
#include "components/action_listener.h"
#include "components/gui_scrollpane.h"
+#include "components/gui_convoy_assembler.h"
#include "../simtypes.h"
+#include "../simdepot.h"
class depot_t;
class vehikel_besch_t;
@@ -47,16 +49,6 @@ class depot_frame_t : public gui_frame_t,
*/
int icnv;
- /* show retired vehicles (same for all depot)
- * @author prissi
- */
- static bool show_retired_vehicles;
-
- /* show retired vehicles (same for all depot)
- * @author prissi
- */
- static bool show_all;
-
/**
* Gui elements
* @author Volker Meyer
@@ -67,8 +59,6 @@ class depot_frame_t : public gui_frame_t,
gui_label_t lb_convois;
button_t bt_next;
- gui_label_t lb_convoi_count;
- gui_label_t lb_convoi_speed;
gui_label_t lb_convoi_value;
gui_label_t lb_convoi_line;
@@ -77,15 +67,6 @@ class depot_frame_t : public gui_frame_t,
button_t bt_destroy;
button_t bt_sell;
- button_t bt_obsolete;
- button_t bt_show_all;
-
- gui_tab_panel_t tabs;
- gui_divider_t div_tabbottom;
-
- gui_label_t lb_veh_action;
- button_t bt_veh_action;
-
/**
* buttons for new route-management
* @author hsiegeln
@@ -95,30 +76,12 @@ class depot_frame_t : public gui_frame_t,
button_t bt_copy_convoi;
button_t bt_apply_line;
- vector_tpl convoi_pics;
- gui_image_list_t convoi;
-
- vector_tpl pas_vec;
- vector_tpl electrics_vec;
- vector_tpl loks_vec;
- vector_tpl waggons_vec;
-
- gui_image_list_t pas;
- gui_image_list_t electrics;
- gui_image_list_t loks;
- gui_image_list_t waggons;
- gui_scrollpane_t scrolly_pas;
- gui_scrollpane_t scrolly_electrics;
- gui_scrollpane_t scrolly_loks;
- gui_scrollpane_t scrolly_waggons;
- gui_container_t cont_pas;
- gui_container_t cont_electrics;
- gui_container_t cont_loks;
- gui_container_t cont_waggons;
-
static char no_line_text[128];
gui_combobox_t line_selector;
+ gui_convoy_assembler_t *convoy_assembler;
+
+
linehandle_t selected_line;
/**
@@ -132,22 +95,9 @@ class depot_frame_t : public gui_frame_t,
char txt_cnv_name[118];
- char txt_convoi_count[40];
char txt_convoi_value[40];
- char txt_convoi_speed[80];
char txt_convoi_line[128];
- enum { va_append, va_insert, va_sell };
- uint8 veh_action;
-
- /**
- * A helper map to update loks_vec and waggons_Vec. All entries from
- * loks_vec and waggons_vec are referenced here.
- * @author Volker Meyer
- * @date 09.06.2003
- */
- ptrhashtable_tpl vehicle_map;
-
/**
* Update texts, image lists and buttons according to the current state.
* @author Volker Meyer
@@ -155,22 +105,6 @@ class depot_frame_t : public gui_frame_t,
*/
void update_data();
- /**
- * Draw the info text for the vehicle the mouse is over - if any.
- * @author Volker Meyer, Hj. Malthaner
- * @date 09.06.2003
- * @update 09-Jan-04
- */
- void draw_vehicle_info_text(koord pos);
-
- /**
- * Calulate the values of the vehicles of the given type owned by the
- * player.
- * @author Volker Meyer
- * @date 09.06.2003
- */
- sint32 calc_restwert(const vehikel_besch_t *veh_type);
-
/**
* Do the dynamic dialog layout
* @author Volker Meyer
@@ -185,23 +119,11 @@ class depot_frame_t : public gui_frame_t,
*/
bool has_min_sizer() const {return true;}
- // true if already stored here
- bool is_contained(const vehikel_besch_t *info);
-
- // add a single vehicle (helper function)
- void add_to_vehicle_list(const vehikel_besch_t *info);
-
- // for convoi image
- void image_from_convoi_list(uint nr);
-
- vehikel_t* find_oldest_newest(const vehikel_besch_t* besch, bool old);
-
- void image_from_storage_list(gui_image_list_t::image_data_t *bild_data);
-
karte_t* get_welt() { return depot->get_welt(); }
public:
depot_frame_t(depot_t* depot);
+ virtual ~depot_frame_t();
/**
* Setzt die Fenstergroesse
@@ -210,13 +132,6 @@ class depot_frame_t : public gui_frame_t,
*/
void set_fenstergroesse(koord groesse);
- /**
- * Create and fill loks_vec and waggons_vec.
- * @author Volker Meyer
- * @date 09.06.2003
- */
- void build_vehicle_lists();
-
/**
* Manche Fenster haben einen Hilfetext assoziiert.
* @return den Dateinamen für die Hilfe, oder NULL
@@ -259,6 +174,9 @@ class depot_frame_t : public gui_frame_t,
* V.Meyer
*/
bool action_triggered( gui_action_creator_t *komp, value_t extra);
+ inline depot_t *get_depot() const {return depot;}
+ inline convoihandle_t get_convoy() const {return depot->get_convoi(icnv);}
+ inline void update_convoy() {icnv<0?convoy_assembler->clear_convoy():convoy_assembler->set_vehicles(get_convoy());}
};
#endif
diff --git a/gui/factorylist_stats_t.cc b/gui/factorylist_stats_t.cc
index b7c11c0eac1..0cf2f764ea6 100644
--- a/gui/factorylist_stats_t.cc
+++ b/gui/factorylist_stats_t.cc
@@ -211,8 +211,11 @@ void factorylist_stats_t::sort(factorylist::sort_mode_t sortby, bool sortreverse
{
fab_list.clear();
fab_list.resize(welt->get_fab_list().get_count());
- for (slist_iterator_tpl i(welt->get_fab_list()); i.next();) {
- fab_list.append(i.get_current());
+ //for (slist_iterator_tpl i(welt->get_fab_list()); i.next();) {
+ for(sint16 i = welt->get_fab_list().get_count() - 1; i >= 0; i --)
+ {
+ //fab_list.append(i.get_current());
+ fab_list.append(welt->get_fab_list()[i]);
}
std::sort(fab_list.begin(), fab_list.end(), compare_factories(sortby, sortreverse));
set_groesse(koord(210, welt->get_fab_list().get_count()*(LINESPACE+1)-10));
diff --git a/gui/goods_frame_t.cc b/gui/goods_frame_t.cc
index a60aa654357..9ebb3fcb1de 100644
--- a/gui/goods_frame_t.cc
+++ b/gui/goods_frame_t.cc
@@ -147,7 +147,6 @@ int goods_frame_t::compare_goods(const void *p1, const void *p2)
}
-
// creates the list and pass it to the child finction good_stats, which does the display stuff ...
void goods_frame_t::sort_list()
{
diff --git a/gui/halt_detail.cc b/gui/halt_detail.cc
index b283e023f7f..d7ad5ec5384 100644
--- a/gui/halt_detail.cc
+++ b/gui/halt_detail.cc
@@ -206,22 +206,41 @@ void halt_detail_t::halt_detail_info(cbuffer_t & buf)
bool has_stops = false;
- for (uint i=0; i *connexions = halt->get_connexions(i);
+#else
const vector_tpl *ziele = halt->get_warenziele(i);
- if(!ziele->empty()) {
+ if(!ziele->empty())
+ {
+#endif
+
+#ifdef NEW_PATHING
+ if(!connexions->empty())
+ {
buf.append("\n");
offset_y += LINESPACE;
-
+#endif
buf.append(" ·");
const ware_besch_t* info = warenbauer_t::get_info_catg_index(i);
// If it is a special freight, we display the name of the good, otherwise the name of the category.
buf.append(translator::translate(info->get_catg()==0?info->get_name():info->get_catg_name()));
buf.append(":\n");
offset_y += LINESPACE;
-
+#ifdef NEW_PATHING
+ quickstone_hashtable_iterator_tpl iter(*connexions);
+ while(iter.next())
+ {
+ halthandle_t a_halt = iter.get_current_key();
+ haltestelle_t::connexion* cnx = iter.get_current_value();
+#else
for( uint32 idx=0; idx < ziele->get_count(); idx++ ) {
halthandle_t a_halt = (*ziele)[idx];
- if(a_halt.is_bound()) {
+#endif
+ if(a_halt.is_bound())
+ {
has_stops = true;
@@ -238,7 +257,19 @@ void halt_detail_t::halt_detail_info(cbuffer_t & buf)
}
buf.append("\n");
+#ifdef NEW_PATHING
+ buf.append("(");
+ buf.append(cnx->journey_time * 0.1); // Convert from tenths
+ buf.append(translator::translate(" mins. travelling"));
+ buf.append(", ");
+ buf.append(cnx->waiting_time * 0.1); // Convert from tenths
+ buf.append(translator::translate(" mins. waiting)"));
+ buf.append("\n");
+
+ offset_y += 2 * LINESPACE;
+#else
offset_y += LINESPACE;
+#endif
}
}
}
@@ -275,7 +306,6 @@ bool halt_detail_t::action_triggered( gui_action_creator_t *, value_t extra)
linehandle_t line=halt->registered_lines[j];
spieler_t *sp=halt->get_welt()->get_active_player();
if( sp==line->get_besitzer() ) {
- //TODO:
// Change player => change marked lines
sp->simlinemgmt.show_lineinfo(sp,line);
halt->get_welt()->set_dirty();
diff --git a/gui/halt_info.cc b/gui/halt_info.cc
index 7a20bbc1520..5e95fb9dd6f 100644
--- a/gui/halt_info.cc
+++ b/gui/halt_info.cc
@@ -26,11 +26,12 @@
karte_t *halt_info_t::welt = NULL;
-static const char *sort_text[4] = {
+static const char *sort_text[5] = {
"Zielort",
"via",
"via Menge",
- "Menge"
+ "Menge",
+ "origin"
};
const char cost_type[MAX_HALT_COST][64] =
@@ -277,7 +278,7 @@ bool halt_info_t::action_triggered( gui_action_creator_t *comp,value_t /* */)
if (comp == &button) { // details button pressed
create_win( new halt_detail_t(halt), w_info, (long)this);
} else if (comp == &sort_button) { // @author hsiegeln sort button pressed
- umgebung_t::default_sortmode = ((int)(halt->get_sortby())+1)%4;
+ umgebung_t::default_sortmode = ((int)(halt->get_sortby())+1)%5;
halt->set_sortby((freight_list_sorter_t::sort_mode_t) umgebung_t::default_sortmode);
sort_button.set_text(sort_text[umgebung_t::default_sortmode]);
} else if (comp == &toggler) {
diff --git a/gui/halt_list_frame.cc b/gui/halt_list_frame.cc
index 37ce7d4521b..515442abba7 100644
--- a/gui/halt_list_frame.cc
+++ b/gui/halt_list_frame.cc
@@ -145,8 +145,13 @@ bool halt_list_frame_t::passes_filter(halthandle_t halt)
}
if(!ok && get_filter(ohneverb_filter)) {
ok = true;
- for (uint8 i = 0; iget_connexions(i)->empty(); //only display stations with NO connexion
+#else
ok &= halt->get_warenziele(i)->empty(); //only display stations with NO connection
+#endif
}
}
if(!ok) {
diff --git a/gui/karte.cc b/gui/karte.cc
index b47cc07fe93..e5b5029f33b 100644
--- a/gui/karte.cc
+++ b/gui/karte.cc
@@ -634,11 +634,15 @@ void reliefkarte_t::calc_map()
// since we do iterate the factory info list, this must be done here
if(mode==MAP_FACTORIES) {
- slist_iterator_tpl iter (welt->get_fab_list());
- while(iter.next()) {
- koord pos = iter.get_current()->get_pos().get_2d();
+ //slist_iterator_tpl iter (welt->get_fab_list());
+ //vector_tpl factories = welt->get_fab_list();
+ for(sint16 i = welt->get_fab_list().get_count() - 1; i >= 0; i --)
+ {
+ //while(iter.next()) {
+ //koord pos = iter.get_current()->get_pos().get_2d();
+ koord pos = welt->get_fab_list()[i]->get_pos().get_2d();
set_relief_farbe_area( pos, 9, COL_BLACK );
- set_relief_farbe_area( pos, 7, iter.get_current()->get_kennfarbe() );
+ set_relief_farbe_area( pos, 7, welt->get_fab_list()[i]->get_kennfarbe() );
}
return;
}
diff --git a/gui/map_frame.h b/gui/map_frame.h
index 24dbddb4170..a4c92eec7a4 100644
--- a/gui/map_frame.h
+++ b/gui/map_frame.h
@@ -24,6 +24,7 @@ class karte_t;
/**
* Reliefkartenfenster für Simutrans.
+ * Relief map window for Simutrans. (Babelfish)
*
* @author Hj. Malthaner
* @date 03-Mar-01
diff --git a/gui/money_frame.cc b/gui/money_frame.cc
index 2517f04fd2c..54d4cbe0ad3 100644
--- a/gui/money_frame.cc
+++ b/gui/money_frame.cc
@@ -37,7 +37,8 @@ static uint32 bFilterStates[MAX_PLAYER_COUNT];
const char money_frame_t::cost_type[MAX_PLAYER_COST][64] =
{
"Construction_Btn", "Operation", "New Vehicles", "Revenue",
- "Maintenance", "Assets", "Cash", "Net Wealth", "Gross Profit", "Ops Profit", "Margin (%)", "Transported", "Powerlines"
+ "Maintenance", "Assets", "Cash", "Net Wealth", "Gross Profit", "Ops Profit", "Margin (%)", "Transported", "Powerlines",
+ "", "", "", "", "", "Interest", "Credit limit"
};
const int money_frame_t::cost_type_color[MAX_PLAYER_COST] =
@@ -54,13 +55,20 @@ const int money_frame_t::cost_type_color[MAX_PLAYER_COST] =
COL_OPS_PROFIT,
COL_MARGIN,
COL_TRANSPORTED,
- COL_POWERLINES
+ COL_POWERLINES,
+ COL_WHITE,
+ COL_WHITE,
+ COL_WHITE,
+ COL_WHITE,
+ COL_WHITE,
+ COL_INTEREST,
+ COL_PURPLE
};
const uint8 button_order[MAX_PLAYER_COST] =
{
- 3, 1, 4, 9, 2, 0, 8, 12, 11,
- 6, 5, 10, 7
+ 3, 1, 4, 9, 2, 0, 18, 8, 12, 11,
+ 6, 5, 10, 7, 19
};
char money_frame_t::digit[4];
@@ -119,9 +127,13 @@ money_frame_t::money_frame_t(spieler_t *sp)
maintenance_money(NULL, COL_RED, gui_label_t::money),
warn("", COL_YELLOW, gui_label_t::left),
scenario("", COL_BLACK, gui_label_t::left),
- headquarter_view(sp->get_welt(), koord3d::invalid)
+ headquarter_view(sp->get_welt(), koord3d::invalid),
+ credit_limit(NULL, COL_WHITE, gui_label_t::money),
+ interest(NULL, COL_WHITE, gui_label_t::money),
+ old_interest(NULL, COL_WHITE, gui_label_t::money)
{
- if(sp->get_welt()->get_spieler(0)!=sp) {
+ if(sp->get_welt()->get_spieler(0)!=sp)
+ {
sprintf(money_frame_title,translator::translate("Finances of %s"),translator::translate(sp->get_name()) );
set_name(money_frame_title);
}
@@ -137,8 +149,9 @@ money_frame_t::money_frame_t(spieler_t *sp)
chart.set_dimension(MAX_PLAYER_HISTORY_YEARS, 10000);
chart.set_seed(sp->get_welt()->get_last_year());
chart.set_background(MN_GREY1);
- for (int i = 0; iget_finance_history_year(), MAX_PLAYER_COST, i, 12, (i < 10) || i==COST_POWERLINES ? MONEY: STANDARD, false, false);
+ for (int i = 0; iget_finance_history_year(), MAX_PLAYER_COST, i, 12, (i < 10) || i == COST_POWERLINES || i == COST_INTEREST || i == COST_CREDIT_LIMIT ? MONEY: STANDARD, false, false);
}
//CHART YEAR END
@@ -148,8 +161,9 @@ money_frame_t::money_frame_t(spieler_t *sp)
mchart.set_dimension(MAX_PLAYER_HISTORY_MONTHS, 10000);
mchart.set_seed(0);
mchart.set_background(MN_GREY1);
- for (int i = 0; iget_finance_history_month(), MAX_PLAYER_COST, i, 12, (i < 10) || i==COST_POWERLINES ? MONEY: STANDARD, false, false);
+ for (int i = 0; iget_finance_history_month(), MAX_PLAYER_COST, i, 12, (i < 10) || i == COST_POWERLINES || i == COST_INTEREST || i == COST_CREDIT_LIMIT ? MONEY: STANDARD, false, false);
}
mchart.set_visible(false);
//CHART MONTH END
@@ -180,22 +194,28 @@ money_frame_t::money_frame_t(spieler_t *sp)
old_nvmoney.set_pos(koord(lyl_x,top+4*BUTTONSPACE));
conmoney.set_pos(koord(tyl_x,top+5*BUTTONSPACE));
old_conmoney.set_pos(koord(lyl_x,top+5*BUTTONSPACE));
- tmoney.set_pos(koord(tyl_x,top+6*BUTTONSPACE));
- old_tmoney.set_pos(koord(lyl_x,top+6*BUTTONSPACE));
- powerline.set_pos(koord(tyl_x,top+7*BUTTONSPACE));
- old_powerline.set_pos(koord(lyl_x,top+7*BUTTONSPACE));
- transport.set_pos(koord(tyl_x+19, top+8*BUTTONSPACE));
- old_transport.set_pos(koord(lyl_x+19, top+8*BUTTONSPACE));
+ interest.set_pos(koord(tyl_x,top+6*BUTTONSPACE));
+ old_interest.set_pos(koord(lyl_x,top+6*BUTTONSPACE));
+ tmoney.set_pos(koord(tyl_x,top+7*BUTTONSPACE));
+ old_tmoney.set_pos(koord(lyl_x,top+7*BUTTONSPACE));
+ powerline.set_pos(koord(tyl_x,top+8*BUTTONSPACE));
+ old_powerline.set_pos(koord(lyl_x,top+8*BUTTONSPACE));
+ transport.set_pos(koord(tyl_x+19, top+9*BUTTONSPACE));
+ old_transport.set_pos(koord(lyl_x+19, top+9*BUTTONSPACE));
// right column
maintenance_label.set_pos(koord(left+340+80, top+1*BUTTONSPACE-2));
maintenance_money.set_pos(koord(left+340+55, top+2*BUTTONSPACE));
- tylabel2.set_pos(koord(left+140+80+335,top+4*BUTTONSPACE-2));
- gtmoney.set_pos(koord(left+140+335+55, top+5*BUTTONSPACE));
- vtmoney.set_pos(koord(left+140+335+55, top+6*BUTTONSPACE));
- margin.set_pos(koord(left+140+335+55, top+7*BUTTONSPACE));
- money.set_pos(koord(left+140+335+55, top+8*BUTTONSPACE));
+ //credit_limit.set_pos(koord(left+140+80+335,top+3*BUTTONSPACE-8));
+ //clamount.set_pos(koord(left+140+335+55,top+4*BUTTONSPACE-8));
+
+ tylabel2.set_pos(koord(left+140+80+335,top+5*BUTTONSPACE-14));
+ gtmoney.set_pos(koord(left+140+335+55, top+6*BUTTONSPACE-12));
+ vtmoney.set_pos(koord(left+140+335+55, top+7*BUTTONSPACE-12));
+ margin.set_pos(koord(left+140+335+55, top+8*BUTTONSPACE-12));
+ money.set_pos(koord(left+140+335+55, top+9*BUTTONSPACE-12));
+ credit_limit.set_pos(koord(left+140+335+55, top+10*BUTTONSPACE-12));
// return money or else stuff ...
warn.set_pos(koord(left+335, top+10*BUTTONSPACE));
@@ -210,6 +230,7 @@ money_frame_t::money_frame_t(spieler_t *sp)
add_komponente(&vrmoney);
add_komponente(&mmoney);
add_komponente(&imoney);
+ add_komponente(&interest);
add_komponente(&tmoney);
add_komponente(&omoney);
add_komponente(&powerline);
@@ -220,19 +241,27 @@ money_frame_t::money_frame_t(spieler_t *sp)
add_komponente(&old_vrmoney);
add_komponente(&old_mmoney);
add_komponente(&old_imoney);
+ add_komponente(&old_interest);
add_komponente(&old_tmoney);
add_komponente(&old_omoney);
add_komponente(&old_powerline);
add_komponente(&old_transport);
-
+
add_komponente(&lylabel);
add_komponente(&tylabel);
+ /*if(!sp->get_welt()->get_einstellungen()->insolvent_purchases_allowed() || sp->get_welt()->get_einstellungen()->is_freeplay())
+ {
+ add_komponente(&credit_limit);
+ add_komponente(&clamount);
+ }*/
+
add_komponente(&tylabel2);
add_komponente(>money);
add_komponente(&vtmoney);
add_komponente(&money);
add_komponente(&margin);
+ add_komponente(&credit_limit);
add_komponente(&maintenance_label);
add_komponente(&maintenance_money);
@@ -268,16 +297,18 @@ money_frame_t::money_frame_t(spieler_t *sp)
}
// add filter buttons
- for(int i=0; i<9; i++) {
+ for(int i = 0; i < 10; i++)
+ {
int ibutton=button_order[i];
filterButtons[ibutton].init(button_t::box, cost_type[ibutton], koord(left, top+i*BUTTONSPACE-2), koord(120, BUTTONSPACE));
filterButtons[ibutton].add_listener(this);
filterButtons[ibutton].background = cost_type_color[ibutton];
add_komponente(filterButtons + ibutton);
}
- for(int i=9; i<13; i++) {
+ for(int i = 10; i < 15; i++)
+ {
int ibutton=button_order[i];
- filterButtons[ibutton].init(button_t::box, cost_type[ibutton], koord(left+335, top+(i-4)*BUTTONSPACE-2), koord(120, BUTTONSPACE));
+ filterButtons[ibutton].init(button_t::box, cost_type[ibutton], koord(left+335, top+(i-5)*BUTTONSPACE-2), koord(120, BUTTONSPACE));
filterButtons[ibutton].add_listener(this);
filterButtons[ibutton].background = cost_type_color[ibutton];
add_komponente(filterButtons + ibutton);
@@ -308,7 +339,7 @@ money_frame_t::money_frame_t(spieler_t *sp)
void money_frame_t::zeichnen(koord pos, koord gr)
{
// Hajo: each label needs its own buffer
- static char str_buf[24][256];
+ static char str_buf[28][256];
sp->calc_finance_history();
@@ -319,34 +350,40 @@ void money_frame_t::zeichnen(koord pos, koord gr)
imoney.set_text(display_money(COST_INCOME, str_buf[4], 0));
tmoney.set_text(display_money(COST_PROFIT, str_buf[5], 0));
omoney.set_text(display_money(COST_OPERATING_PROFIT, str_buf[6], 0));
+ interest.set_text(display_money(COST_INTEREST, str_buf[7], 0));
- old_conmoney.set_text(display_money(COST_CONSTRUCTION, str_buf[7], 1));
- old_nvmoney.set_text(display_money(COST_NEW_VEHICLE, str_buf[8], 1));
- old_vrmoney.set_text(display_money(COST_VEHICLE_RUN, str_buf[9], 1));
- old_mmoney.set_text(display_money(COST_MAINTENANCE, str_buf[10], 1));
- old_imoney.set_text(display_money(COST_INCOME, str_buf[11], 1));
- old_tmoney.set_text(display_money(COST_PROFIT, str_buf[12], 1));
- old_omoney.set_text(display_money(COST_OPERATING_PROFIT, str_buf[13], 1));
+ old_conmoney.set_text(display_money(COST_CONSTRUCTION, str_buf[8], 1));
+ old_nvmoney.set_text(display_money(COST_NEW_VEHICLE, str_buf[9], 1));
+ old_vrmoney.set_text(display_money(COST_VEHICLE_RUN, str_buf[10], 1));
+ old_mmoney.set_text(display_money(COST_MAINTENANCE, str_buf[11], 1));
+ old_imoney.set_text(display_money(COST_INCOME, str_buf[12], 1));
+ old_tmoney.set_text(display_money(COST_PROFIT, str_buf[13], 1));
+ old_omoney.set_text(display_money(COST_OPERATING_PROFIT, str_buf[14], 1));
+ old_interest.set_text(display_money(COST_INTEREST, str_buf[15], 1));
// transported goods
- money_to_string(str_buf[20], sp->get_finance_history_year(0, COST_ALL_TRANSPORTED) );
- str_buf[20][strlen(str_buf[20])-4] = 0; // remove comma
- transport.set_text(str_buf[20]);
+ money_to_string(str_buf[16], sp->get_finance_history_year(0, COST_ALL_TRANSPORTED) );
+ str_buf[16][strlen(str_buf[16])-4] = 0; // remove comma
+ transport.set_text(str_buf[16]);
transport.set_color(get_money_colour(COST_ALL_TRANSPORTED, 0));
- money_to_string(str_buf[21], sp->get_finance_history_year(1, COST_ALL_TRANSPORTED) );
- str_buf[21][strlen(str_buf[21])-4] = 0; // remove comma
- old_transport.set_text(str_buf[21]);
+ money_to_string(str_buf[17], sp->get_finance_history_year(1, COST_ALL_TRANSPORTED) );
+ str_buf[17][strlen(str_buf[17])-4] = 0; // remove comma
+ old_transport.set_text(str_buf[17]);
old_transport.set_color(get_money_colour(COST_ALL_TRANSPORTED, 0));
//money_to_string(str_buf[22], sp->get_finance_history_year(0, COST_POWERLINES) );
- powerline.set_text(display_money(COST_POWERLINES, str_buf[22], 0)); //set_text(str_buf[22]);
+ powerline.set_text(display_money(COST_POWERLINES, str_buf[18], 0)); //set_text(str_buf[22]);
powerline.set_color(get_money_colour(COST_POWERLINES, 0));
//money_to_string(str_buf[23], sp->get_finance_history_year(1, COST_POWERLINES) );
- old_powerline.set_text(display_money(COST_POWERLINES, str_buf[23], 1));
+ old_powerline.set_text(display_money(COST_POWERLINES, str_buf[19], 1));
old_powerline.set_color(get_money_colour(COST_POWERLINES, 1));
+ //clamount.set_text(display_money(sp->get_credit_limit(), str_buf[24], 1));
+ /*money_to_string(str_buf[24], sp->get_credit_limit() / 100.0);
+ clamount.set_text(str_buf[24]);*/
+
conmoney.set_color(get_money_colour(COST_CONSTRUCTION, 0));
nvmoney.set_color(get_money_colour(COST_NEW_VEHICLE, 0));
vrmoney.set_color(get_money_colour(COST_VEHICLE_RUN, 0));
@@ -354,6 +391,7 @@ void money_frame_t::zeichnen(koord pos, koord gr)
imoney.set_color(get_money_colour(COST_INCOME, 0));
tmoney.set_color(get_money_colour(COST_PROFIT, 0));
omoney.set_color(get_money_colour(COST_OPERATING_PROFIT, 0));
+ interest.set_color(get_money_colour(COST_INTEREST, 0));
old_conmoney.set_color(get_money_colour(COST_CONSTRUCTION, 1));
old_nvmoney.set_color(get_money_colour(COST_NEW_VEHICLE, 1));
@@ -362,38 +400,41 @@ void money_frame_t::zeichnen(koord pos, koord gr)
old_imoney.set_color(get_money_colour(COST_INCOME, 1));
old_tmoney.set_color(get_money_colour(COST_PROFIT, 1));
old_omoney.set_color(get_money_colour(COST_OPERATING_PROFIT, 1));
+ old_interest.set_color(get_money_colour(COST_INTEREST, 1));
- gtmoney.set_text(display_money(COST_CASH, str_buf[14], 0));
+ gtmoney.set_text(display_money(COST_CASH, str_buf[20], 0));
gtmoney.set_color(get_money_colour(COST_CASH, 0));
- vtmoney.set_text(display_money(COST_ASSETS, str_buf[17], 0));
+ vtmoney.set_text(display_money(COST_ASSETS, str_buf[21], 0));
vtmoney.set_color(get_money_colour(COST_ASSETS, 0));
- money.set_text(display_money(COST_NETWEALTH, str_buf[18], 0));
+ money.set_text(display_money(COST_NETWEALTH, str_buf[22], 0));
money.set_color(get_money_colour(COST_NETWEALTH, 0));
- display_money(COST_MARGIN, str_buf[19], 0);
- str_buf[19][strlen(str_buf[19])-1] = 0; // remove percent sign
- margin.set_text(str_buf[19]);
+ display_money(COST_MARGIN, str_buf[23], 0);
+ str_buf[23][strlen(str_buf[23])-1] = 0; // remove percent sign
+ margin.set_text(str_buf[23]);
+ credit_limit.set_text(display_money(COST_CREDIT_LIMIT, str_buf[24], 0));
margin.set_color(get_money_colour(COST_MARGIN, 0));
+ credit_limit.set_color(get_money_colour(COST_CREDIT_LIMIT, 0));
// warning/success messages
if(sp->get_player_nr()==0 && sp->get_welt()->get_scenario()->active()) {
- sprintf( str_buf[15], translator::translate("Scenario complete: %i%%"), sp->get_welt()->get_scenario()->completed(0) );
+ sprintf( str_buf[25], translator::translate("Scenario complete: %i%%"), sp->get_welt()->get_scenario()->completed(0) );
}
else if(sp->get_konto_ueberzogen()) {
warn.set_color( COL_RED );
if(sp->get_finance_history_year(0, COST_NETWEALTH)<0) {
- sprintf(str_buf[15], translator::translate("Company bankrupt") );
+ sprintf(str_buf[25], translator::translate("Company bankrupt") );
}
else {
- sprintf(str_buf[15], translator::translate("On loan since %i month(s)"), sp->get_konto_ueberzogen() );
+ sprintf(str_buf[25], translator::translate("On loan since %i month(s)"), sp->get_konto_ueberzogen() );
}
}
else {
- str_buf[15][0] = '\0';
+ str_buf[25][0] = '\0';
}
- warn.set_text(str_buf[15]);
+ warn.set_text(str_buf[26]);
headquarter.disable();
if(sp!=sp->get_welt()->get_active_player()) {
@@ -433,8 +474,8 @@ void money_frame_t::zeichnen(koord pos, koord gr)
}
// Hajo: Money is counted in credit cents (100 cents = 1 Cr)
- money_to_string(str_buf[16], (double)((sint64)sp->get_maintenance()<<((sint64)sp->get_welt()->ticks_bits_per_tag-18l))/100.0 );
- maintenance_money.set_text(str_buf[16]);
+ money_to_string(str_buf[27], (double)((sint64)sp->get_maintenance()<<((sint64)sp->get_welt()->ticks_bits_per_tag-18l))/100.0 );
+ maintenance_money.set_text(str_buf[27]);
maintenance_money.set_color(sp->get_maintenance()>=0?MONEY_PLUS:MONEY_MINUS);
for (int i = 0; iget_besitzer()),
+ cnv(cnv),
+ replace_line(false), replace_all(false), depot(false), autostart(true),
+ state(state_replace), replaced_so_far(0),
+ lb_convoy(cnv, true, true),
+ lb_to_be_replaced(NULL, COL_BLACK, gui_label_t::centered),
+ lb_money(NULL, COL_BLACK, gui_label_t::money),
+ lb_replace_cycle(NULL, COL_BLACK, gui_label_t::right),
+ lb_replace(NULL, COL_BLACK, gui_label_t::left),
+ lb_sell(NULL, COL_BLACK, gui_label_t::left),
+ lb_skip(NULL, COL_BLACK, gui_label_t::left),
+ lb_n_replace(NULL, COL_BLACK, gui_label_t::left),
+ lb_n_sell(NULL, COL_BLACK, gui_label_t::left),
+ lb_n_skip(NULL, COL_BLACK, gui_label_t::left)
+
+{
+ const int a_button_height=14;
+ const int margin=6;
+ lb_money.set_text_pointer(txt_money);
+ add_komponente(&lb_money);
+
+ lb_convoy.set_text_pointer(name);
+ add_komponente(&lb_convoy);
+
+ lb_to_be_replaced.set_text_pointer(translator::translate("To be replaced by:"));
+ add_komponente(&lb_to_be_replaced);
+
+ lb_replace_cycle.set_text_pointer(translator::translate("Replace cycle:"));
+ lb_replace.set_text_pointer(translator::translate("Replace"));
+ lb_sell.set_text_pointer(translator::translate("Sell"));
+ lb_skip.set_text_pointer(translator::translate("Skip"));
+ numinp[state_replace].set_value( 1 );
+ numinp[state_replace].set_limits( 0, 99 );
+ numinp[state_replace].set_increment_mode( 1 );
+ numinp[state_replace].add_listener(this);
+ numinp[state_sell].set_value( 0 );
+ numinp[state_sell].set_limits( 0, 99 );
+ numinp[state_sell].set_increment_mode( 1 );
+ numinp[state_sell].add_listener(this);
+ numinp[state_skip].set_value( 0 );
+ numinp[state_skip].set_limits( 0, 99 );
+ numinp[state_skip].set_increment_mode( 1 );
+ numinp[state_skip].add_listener(this);
+ lb_n_replace.set_text_pointer(txt_n_replace);
+ lb_n_sell.set_text_pointer(txt_n_sell);
+ lb_n_skip.set_text_pointer(txt_n_skip);
+ add_komponente(&lb_replace_cycle);
+ add_komponente(&lb_replace);
+ add_komponente(&numinp[state_replace]);
+ add_komponente(&lb_n_replace);
+ add_komponente(&lb_sell);
+ add_komponente(&numinp[state_sell]);
+ add_komponente(&lb_n_sell);
+ add_komponente(&lb_skip);
+ add_komponente(&numinp[state_skip]);
+ add_komponente(&lb_n_skip);
+
+ waytype_t wt = road_wt;
+ if (cnv->get_vehikel_anzahl()>0) { // Should always be true
+ wt=cnv->get_vehikel(0)->get_besch()->get_waytype();
+ }
+ const bool weg_electrified = cnv->get_welt()->lookup(cnv->get_vehikel(0)->get_pos())->get_weg(wt)->is_electrified();
+ convoy_assembler = new gui_convoy_assembler_t(cnv->get_welt(), wt, weg_electrified, cnv->get_besitzer()->get_player_nr() );
+ convoy_assembler->set_convoy_tabs_skip(-2*LINESPACE+3*LINESPACE+2*margin+a_button_height);
+ convoy_assembler->add_listener(this);
+ convoy_assembler->set_vehicles(cnv->get_replacing_vehicles());
+ add_komponente(convoy_assembler);
+
+ bt_replace_line.set_typ(button_t::square);
+ bt_replace_line.set_text("replace all in line");
+ bt_replace_line.set_tooltip("Replace all convoys like this belonging to this line");
+ bt_replace_line.add_listener(this);
+ add_komponente(&bt_replace_line);
+ bt_replace_all.set_typ(button_t::square);
+ bt_replace_all.set_text("replace all");
+ bt_replace_all.set_tooltip("Replace all convoys like this");
+ bt_replace_all.add_listener(this);
+ add_komponente(&bt_replace_all);
+
+ bt_autostart.set_typ(button_t::roundbox);
+ bt_autostart.set_text("Full replace");
+ bt_autostart.set_tooltip("Send convoy to depot, replace and restart it automatically");
+ bt_autostart.add_listener(this);
+ add_komponente(&bt_autostart);
+ bt_depot.set_typ(button_t::roundbox);
+ bt_depot.set_text("Replace but stay");
+ bt_depot.set_tooltip("Send convoy to depot, replace it and stay there");
+ bt_depot.add_listener(this);
+ add_komponente(&bt_depot);
+
+ bt_mark.set_typ(button_t::roundbox);
+ bt_mark.set_text("Mark for replacing");
+ bt_mark.set_tooltip("Mark for replacing. The convoy will replace when manually sent to depot");
+ bt_mark.add_listener(this);
+ add_komponente(&bt_mark);
+
+ koord gr = koord(0,0);
+ layout(&gr);
+ update_data();
+ gui_frame_t::set_fenstergroesse(gr);
+
+ // Hajo: Trigger layouting
+ set_resizemode(diagonal_resize);
+
+ convoy_assembler->set_replace_frame(this);
+}
+
+
+replace_frame_t::~replace_frame_t()
+{
+ delete convoy_assembler;
+}
+
+
+void replace_frame_t::update_total_height(int height)
+{
+ total_height+=height;
+ min_total_height+=height;
+}
+
+
+void replace_frame_t::update_total_width(int width)
+{
+ total_width=max(total_width,width);
+ min_total_width=max(min_total_width,width);
+}
+
+
+void replace_frame_t::layout(koord *gr)
+{
+ const int window_bar_height=16;
+ const int margin=6;
+ const int a_button_width=96;
+ const int a_button_height=14;
+
+ /**
+ * Let's calculate the space and min space
+ */
+ koord fgr = (gr!=NULL)? *gr : get_fenstergroesse();
+ min_total_width=0;
+ total_width=fgr.x;
+ total_height=window_bar_height+2*margin;
+ min_total_height=total_height;
+
+ // Width at least to see labels ok
+ update_total_width(400);
+
+ // Convoy label: name+image+specs
+ koord img_size=lb_convoy.get_size();
+ update_total_width(img_size.x);
+ update_total_height(img_size.y);
+
+ // Label to be replaced
+ update_total_height(LINESPACE);
+
+ // 3 buttons
+ update_total_width(2*margin+3*a_button_width);
+ // No update height needed, convoy assembler
+
+ // Rest of the vertical space, if any, for convoy_assembler
+ update_total_width(convoy_assembler->get_convoy_image_width());
+ convoy_assembler->set_panel_rows(gr && gr->y==0?-1:fgr.y-total_height);
+ total_height+=convoy_assembler->get_height()+margin;
+ min_total_height+=convoy_assembler->get_min_height()+margin;
+
+ set_min_windowsize(koord(min_total_width, min_total_height));
+ if(fgr.xx==0) {
+ gr->x = total_width;
+ }
+ if(gr && gr->y==0) {
+ gr->y = total_height;
+ }
+
+ /**
+ * Now do the layout
+ */
+ int current_y=margin;
+ if (gr) {
+ fgr=*gr;
+ } else {
+ fgr=koord(total_width,total_height);
+ }
+
+ lb_convoy.set_pos(koord(fgr.x/2,current_y));
+ current_y+=lb_convoy.get_size().y;
+
+ lb_to_be_replaced.set_pos(koord(fgr.x/2,current_y));
+ current_y+=LINESPACE;
+
+ convoy_assembler->set_pos(koord(0,current_y));
+ convoy_assembler->set_groesse(koord(fgr.x,convoy_assembler->get_height()));
+ convoy_assembler->layout();
+
+ int buttons_y=current_y+convoy_assembler->get_convoy_height()-2*LINESPACE+8;
+ int buttons_width=(fgr.x-2*margin)/3;
+ bt_autostart.set_groesse(koord(buttons_width, a_button_height));
+ bt_depot.set_groesse(koord(buttons_width, a_button_height));
+ bt_mark.set_groesse(koord(buttons_width, a_button_height));
+ bt_autostart.set_pos(koord(margin,buttons_y));
+ bt_depot.set_pos(koord(margin+buttons_width,buttons_y));
+ bt_mark.set_pos(koord(margin+buttons_width+buttons_width,buttons_y));
+ current_y=buttons_y+a_button_height+margin;
+ lb_money.set_pos(koord(110,current_y));
+ lb_replace_cycle.set_pos(koord(fgr.x-170,current_y));
+ lb_replace.set_pos(koord(fgr.x-166,current_y));
+ numinp[state_replace].set_pos( koord( fgr.x-110, current_y ) );
+
+ numinp[state_replace].set_groesse( koord( 50, a_button_height ) );
+ lb_n_replace.set_pos( koord( fgr.x-50, current_y ) );
+ current_y+=LINESPACE+2;
+ bt_replace_line.set_pos(koord(margin,current_y));
+ lb_sell.set_pos(koord(fgr.x-166,current_y));
+ numinp[state_sell].set_groesse( koord( 50, a_button_height ) );
+ lb_n_sell.set_pos( koord( fgr.x-50, current_y ) );
+ current_y+=LINESPACE+2;
+ bt_replace_all.set_pos(koord(margin,current_y));
+ lb_skip.set_pos(koord(fgr.x-166,current_y));
+ numinp[state_skip].set_pos( koord( fgr.x-110, current_y ) );
+ numinp[state_skip].set_groesse( koord( 50, a_button_height ) );
+ lb_n_skip.set_pos( koord( fgr.x-50, current_y ) );
+ current_y+=LINESPACE+margin;
+}
+
+
+void replace_frame_t::set_fenstergroesse( koord gr )
+{
+ koord g=gr;
+ layout(&g);
+ update_data();
+ gui_frame_t::set_fenstergroesse(gr);
+}
+
+
+void replace_frame_t::update_data()
+{
+ convoy_assembler->update_data();
+
+ txt_n_replace[0]='\0';
+ txt_n_sell[0]='\0';
+ txt_n_skip[0]='\0';
+ int n[3];
+ n[0]=0;
+ n[1]=0;
+ n[2]=0;
+ money = 0;
+ sint32 base_total_cost = calc_total_cost();
+ if (replace_line || replace_all) {
+ start_replacing();
+ } else {
+ money -= base_total_cost;
+ }
+ if (replace_line) {
+ linehandle_t line=cnv.is_bound()?cnv->get_line():linehandle_t();
+ if (line.is_bound()) {
+ for (unsigned int i=0; icount_convoys(); i++) {
+ convoihandle_t cnv_aux=line->get_convoy(i);
+ if (cnv->has_same_vehicles(cnv_aux)) {
+ int present_state=get_present_state();
+ if (present_state==-1) {
+ continue;
+ }
+ switch(convoy_assembler->get_action())
+ {
+
+ case gui_convoy_assembler_t::clear_convoy_action:
+ money = 0;
+ n[present_state]++;
+ break;
+
+ case gui_convoy_assembler_t::remove_vehicle_action:
+ money += base_total_cost;
+ n[present_state]++;
+ break;
+
+ default:
+ money -= base_total_cost;
+ n[present_state]++;
+ };
+ }
+ }
+ }
+ } else if (replace_all) {
+ karte_t *welt=cnv->get_welt();
+ for (unsigned int i=0; iget_convoi_count(); i++) {
+ convoihandle_t cnv_aux=welt->get_convoi(i);
+ if (cnv_aux.is_bound() && cnv_aux->get_besitzer()==cnv->get_besitzer() && cnv->has_same_vehicles(cnv_aux))
+ {
+ int present_state=get_present_state();
+ if (present_state==-1)
+ {
+ continue;
+ }
+
+ switch(convoy_assembler->get_action())
+ {
+
+ case gui_convoy_assembler_t::clear_convoy_action:
+ money = 0;
+ n[present_state]++;
+ break;
+
+ case gui_convoy_assembler_t::remove_vehicle_action:
+ money += base_total_cost;
+ n[present_state]++;
+ break;
+
+ default:
+ money -= base_total_cost;
+ n[present_state]++;
+ };
+ }
+ }
+ }
+ if (replace_all || replace_line) {
+ sprintf(txt_n_replace,"%d",n[0]);
+ sprintf(txt_n_sell,"%d",n[1]);
+ sprintf(txt_n_skip,"%d",n[2]);
+ }
+ if (convoy_assembler->get_vehicles()->get_count()>0) {
+ money_to_string(txt_money,money/100.0);
+ lb_money.set_color(money>=0?MONEY_PLUS:MONEY_MINUS);
+ } else {
+ txt_money[0]='\0';
+ }
+
+}
+
+
+uint8 replace_frame_t::get_present_state() {
+ if (numinp[state_replace].get_value()==0 && numinp[state_sell].get_value()==0 && numinp[state_skip].get_value()==0) {
+ return -1;
+ }
+ for (int i=0; i=numinp[state].get_value()) {
+ replaced_so_far=0;
+ state=(state+1)%n_states;
+ } else {
+ break;
+ }
+ }
+ replaced_so_far++;
+ return state;
+ }
+
+
+void replace_frame_t::replace_convoy(convoihandle_t cnv)
+{
+ int state=get_present_state();
+ if (!cnv.is_bound() || cnv->in_depot() || state==-1) {
+ return;
+ }
+
+ switch (state) {
+ case state_replace:
+ if(!cnv->get_welt()->get_active_player()->can_afford(0 - money))
+ {
+ const char *err = "That would exceed\nyour credit limit.";
+ news_img *box = new news_img(err);
+ create_win(box, w_time_delete, magic_none);
+ break;
+ }
+
+ cnv->set_replacing_vehicles(convoy_assembler->get_vehicles());
+ cnv->set_depot_when_empty( (depot || autostart) && convoy_assembler->get_vehicles()->get_count()>0 );
+ cnv->set_autostart(autostart);
+ cnv->set_no_load( cnv->get_depot_when_empty() && convoy_assembler->get_vehicles()->get_count()>0 );
+ cnv->set_replace(convoy_assembler->get_vehicles()->get_count()>0);
+ // If already empty, no need to be emptied
+ if(cnv->get_replace() && cnv->get_depot_when_empty() && cnv->has_no_cargo()) {
+ cnv->set_depot_when_empty(false);
+ cnv->set_no_load(false);
+ cnv->go_to_depot(false);
+ }
+ break;
+
+ case state_sell:
+ cnv->set_replace(false);
+ cnv->set_withdraw(true);
+ cnv->set_no_load(true);
+ break;
+ case state_skip:
+ break;
+ }
+
+ replaced_so_far++;
+}
+
+bool replace_frame_t::action_triggered( gui_action_creator_t *komp,value_t p)
+{
+ if(komp != NULL) { // message from outside!
+ if(komp == convoy_assembler) {
+ //const koord k=*static_cast(p.p);
+ //switch (k.x) {
+ // case gui_convoy_assembler_t::clear_convoy_action:
+ // new_convoy_cost=0;
+ // break;
+ // case gui_convoy_assembler_t::remove_vehicle_action:
+ // new_convoy_cost-=convoy_assembler->get_last_changed_vehicle()->get_preis();
+ // break;
+ // default: // append/insert_in_front
+ // new_convoy_cost+=convoy_assembler->get_last_changed_vehicle()->get_preis();
+ // break;
+ //}
+
+ } else if(komp == &bt_replace_line) {
+ replace_line=!replace_line;
+ replace_all=false;
+ } else if(komp == &bt_replace_all) {
+ replace_all=!replace_all;
+ replace_line=false;
+
+ } else if(komp == numinp+state_replace) {
+ } else if(komp == numinp+state_sell) {
+ } else if(komp == numinp+state_skip) {
+ } else if(komp==&bt_autostart || komp== &bt_depot || komp == &bt_mark) {
+ depot=(komp==&bt_depot);
+ autostart=(komp==&bt_autostart);
+
+ start_replacing();
+ if (!replace_line && !replace_all) {
+ replace_convoy(cnv);
+ } else if (replace_line) {
+ linehandle_t line=cnv.is_bound()?cnv->get_line():linehandle_t();
+ if (line.is_bound()) {
+ for (unsigned int i=0; icount_convoys(); i++) {
+ convoihandle_t cnv_aux=line->get_convoy(i);
+ if (cnv->has_same_vehicles(cnv_aux)) {
+ replace_convoy(cnv_aux);
+ }
+ }
+ }
+ } else if (replace_all) {
+ karte_t *welt=cnv->get_welt();
+ for (unsigned int i=0; iget_convoi_count(); i++) {
+ convoihandle_t cnv_aux=welt->get_convoi(i);
+ if (cnv_aux.is_bound() && cnv_aux->get_besitzer()==cnv->get_besitzer() && cnv->has_same_vehicles(cnv_aux)) {
+ replace_convoy(cnv_aux);
+ }
+ }
+ }
+ destroy_win(this);
+ return true;
+ }
+ }
+ convoy_assembler->build_vehicle_lists();
+ update_data();
+ layout(NULL);
+ return true;
+}
+
+
+void replace_frame_t::infowin_event(const event_t *ev)
+{
+ gui_frame_t::infowin_event(ev);
+ if(IS_WINDOW_REZOOM(ev)) {
+ koord gr = get_fenstergroesse();
+ set_fenstergroesse(gr);
+ } else if(ev->ev_class == INFOWIN && ev->ev_code == WIN_OPEN) {
+ convoy_assembler->build_vehicle_lists();
+ update_data();
+ layout(NULL);
+ }
+}
+
+
+void replace_frame_t::zeichnen(koord pos, koord groesse)
+{
+ if (get_welt()->get_active_player() != cnv->get_besitzer()) {
+ destroy_win(this);
+ return;
+ }
+
+ // Refresh button state. Otherwise, they would not show pressed.
+ bt_replace_line.pressed=replace_line;
+ if (cnv.is_bound() && cnv->get_line().is_bound()) {
+ bt_replace_line.enable();
+ } else {
+ bt_replace_line.disable();
+ replace_line=false;
+ }
+ bt_replace_all.pressed=replace_all;
+
+ // Make replace cycle grey if not in use
+ int color=(replace_line||replace_all?COL_BLACK:COL_GREY4);
+ lb_replace_cycle.set_color(color);
+ lb_replace.set_color(color);
+ lb_sell.set_color(color);
+ lb_skip.set_color(color);
+
+ gui_frame_t::zeichnen(pos, groesse);
+}
+
+sint32 replace_frame_t::calc_total_cost()
+{
+ sint32 total_cost = 0;
+ vector_tpl current_vehicles;
+ vector_tpl keep_vehicles;
+ for(uint8 i = 0; i < cnv->get_vehikel_anzahl(); i ++)
+ {
+ current_vehicles.append(cnv->get_vehikel(i));
+ }
+ ITERATE((*convoy_assembler->get_vehicles()),j)
+ {
+ const vehikel_besch_t* veh = NULL;
+ const vehikel_besch_t* test_new_vehicle = (*convoy_assembler->get_vehicles())[j];
+ // First - check whether there are any of the required vehicles already
+ // in the convoy (free)
+ ITERATE(current_vehicles,k)
+ {
+ const vehikel_besch_t* test_old_vehicle = current_vehicles[k]->get_besch();
+ if(!keep_vehicles.is_contained(k) && current_vehicles[k]->get_besch() == (*convoy_assembler->get_vehicles())[j])
+ {
+ veh = current_vehicles[k]->get_besch();
+ keep_vehicles.append_unique(k);
+ // No change to price here.
+ break;
+ }
+ }
+
+ // We cannot look up the home depot here, so we cannot check whether there are any
+ // suitable vehicles stored there as is done when the actual replacing takes place.
+
+ if (veh == NULL)
+ {
+ // Second - check whether the vehicle can be upgraded (cheap)
+ ITERATE(current_vehicles,l)
+ {
+ for(uint8 c = 0; c < current_vehicles[l]->get_besch()->get_upgrades_count(); c ++)
+ {
+ const vehikel_besch_t* possible_upgrade_test = current_vehicles[l]->get_besch()->get_upgrades(c);
+ if(!keep_vehicles.is_contained(l) && (*convoy_assembler->get_vehicles())[j] == current_vehicles[l]->get_besch()->get_upgrades(c))
+ {
+ veh = current_vehicles[l]->get_besch();
+ keep_vehicles.append_unique(l);
+ total_cost += veh->get_upgrades(c)->get_upgrade_price();
+ goto end_loop;
+ }
+ }
+ }
+end_loop:
+ if(veh == NULL)
+ {
+ // Third - if all else fails, buy from new (expensive).
+ total_cost += (*convoy_assembler->get_vehicles())[j]->get_preis();
+ }
+ }
+ }
+ ITERATE(current_vehicles,m)
+ {
+ if(!keep_vehicles.is_contained(m))
+ {
+ // This vehicle will not be kept after replacing -
+ // deduct its resale value from the total cost.
+ total_cost -= current_vehicles[m]->calc_restwert();
+ }
+ }
+
+ return total_cost;
+}
\ No newline at end of file
diff --git a/gui/replace_frame.h b/gui/replace_frame.h
new file mode 100644
index 00000000000..f859bd9b4f3
--- /dev/null
+++ b/gui/replace_frame.h
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 1997 - 2001 Hansjörg Malthaner
+ *
+ * This file is part of the Simutrans project under the artistic licence.
+ * (see licence.txt)
+ */
+
+#ifndef replace_frame_t_h
+#define replace_frame_t_h
+
+#include "gui_frame.h"
+
+#include "components/action_listener.h"
+#include "components/gui_button.h"
+#include "components/gui_convoy_assembler.h"
+#include "components/gui_convoy_label.h"
+#include "components/gui_label.h"
+#include "components/gui_numberinput.h"
+#include "messagebox.h"
+
+
+/**
+ * Replace frame, makes convoys be marked for replacing.
+ *
+ * @author isidoro
+ * @date Jan-09
+ */
+class replace_frame_t : public gui_frame_t,
+ public action_listener_t
+{
+private:
+ /**
+ * The convoy to be replaced
+ */
+ convoihandle_t cnv;
+
+ bool replace_line; // True if all convoys like this in its line are to be replaced
+ bool replace_all; // True if all convoys like this are to be replaced
+ bool depot; // True if convoy is to be sent to depot only
+ bool autostart; // True if convoy is to be sent to depot and restarted automatically
+ enum {state_replace=0, state_sell, state_skip, n_states};
+ uint8 state;
+ uint8 replaced_so_far;
+ sint32 money;
+
+ /**
+ * Gui elements
+ */
+ gui_convoy_label_t lb_convoy;
+ gui_label_t lb_to_be_replaced;
+ gui_convoy_assembler_t *convoy_assembler;
+ gui_label_t lb_money;
+ button_t bt_replace_line;
+ button_t bt_replace_all;
+ button_t bt_autostart;
+ button_t bt_depot;
+ button_t bt_mark;
+ gui_label_t lb_replace_cycle;
+ gui_label_t lb_replace;
+ gui_label_t lb_sell;
+ gui_label_t lb_skip;
+ gui_label_t lb_n_replace;
+ gui_label_t lb_n_sell;
+ gui_label_t lb_n_skip;
+ gui_numberinput_t numinp[n_states];
+ char txt_money[16];
+ char txt_n_replace[8];
+ char txt_n_sell[8];
+ char txt_n_skip[8];
+
+ /**
+ * Update texts, image lists and buttons according to the current state.
+ * @author Volker Meyer
+ * @date 09.06.2003
+ */
+ void update_data();
+
+ /**
+ * Do the dynamic dialog layout
+ */
+ void layout(koord *);
+
+ int total_width, min_total_width, total_height, min_total_height;
+
+ // Some helper functions
+ void update_total_height(int height);
+ void update_total_width(int width);
+ void replace_convoy(convoihandle_t cnv);
+ inline void start_replacing() {state=state_replace; replaced_so_far=0;}
+ uint8 get_present_state();
+
+ karte_t* get_welt() { return cnv->get_welt(); }
+
+ sint32 calc_total_cost();
+
+public:
+ replace_frame_t(convoihandle_t cnv, const char *name);
+ virtual ~replace_frame_t();
+
+ /**
+ * Setzt die Fenstergroesse
+ * @author (Mathew Hounsell)
+ * @date 11-Mar-2003
+ */
+ void set_fenstergroesse(koord groesse);
+
+ /**
+ * Manche Fenster haben einen Hilfetext assoziiert.
+ * @return den Dateinamen für die Hilfe, oder NULL
+ * @author Hj. Malthaner
+ */
+ const char * get_hilfe_datei() const {return "replace.txt";}
+
+ void infowin_event(const event_t *ev);
+
+ /**
+ * Zeichnet das Frame
+ * @author Hansjörg Malthaner
+ */
+ void zeichnen(koord pos, koord gr);
+
+ /**
+ * This method is called if an action is triggered
+ * @author Hj. Malthaner
+ *
+ * Returns true, if action is done and no more
+ * components should be triggered.
+ * V.Meyer
+ */
+ bool action_triggered( gui_action_creator_t *komp, value_t extra);
+
+ const convoihandle_t get_convoy() const { return cnv; }
+
+};
+
+#endif
\ No newline at end of file
diff --git a/gui/schedule_list.cc b/gui/schedule_list.cc
index c835649de41..485f652e80b 100644
--- a/gui/schedule_list.cc
+++ b/gui/schedule_list.cc
@@ -49,26 +49,28 @@ const char schedule_list_gui_t::cost_type[MAX_LINE_COST][64] =
{
"Free Capacity",
"Transported",
+ "Average speed",
+ "Comfort",
"Revenue",
"Operation",
"Profit",
"Convoys"
};
-static uint8 tabs_to_lineindex[9];
+static uint8 tabs_to_lineindex[8];
static uint8 max_idx=0;
const int schedule_list_gui_t::cost_type_color[MAX_LINE_COST] =
{
- COL_FREE_CAPACITY, COL_TRANSPORTED, COL_REVENUE, COL_OPERATION, COL_PROFIT, COL_VEHICLE_ASSETS
+ COL_FREE_CAPACITY, COL_TRANSPORTED, COL_AVERAGE_SPEED, COL_COMFORT, COL_REVENUE, COL_OPERATION, COL_PROFIT, COL_VEHICLE_ASSETS
};
uint8 schedule_list_gui_t::statistic[MAX_LINE_COST]={
- LINE_CAPACITY, LINE_TRANSPORTED_GOODS, LINE_REVENUE, LINE_OPERATIONS, LINE_PROFIT, LINE_CONVOIS
+ LINE_CAPACITY, LINE_TRANSPORTED_GOODS, LINE_AVERAGE_SPEED, LINE_COMFORT, LINE_REVENUE, LINE_OPERATIONS, LINE_PROFIT, LINE_CONVOIS
};
uint8 schedule_list_gui_t::statistic_type[MAX_LINE_COST]={
- STANDARD, STANDARD, MONEY, MONEY, MONEY, STANDARD
+ STANDARD, STANDARD, STANDARD, STANDARD, MONEY, MONEY, MONEY, STANDARD
};
#define LINE_NAME_COLUMN_WIDTH ((BUTTON_WIDTH*3)+11+11)
diff --git a/gui/stadt_info.cc b/gui/stadt_info.cc
index 6ad0a4d14f5..d6aeaf945a9 100644
--- a/gui/stadt_info.cc
+++ b/gui/stadt_info.cc
@@ -23,17 +23,20 @@
// @author hsiegeln
const char *hist_type[MAX_CITY_HISTORY] =
{
- "citicens", "Growth", "Buildings", "Verkehrsteilnehmer",
- "Transported", "Passagiere", "sended", "Post",
- "Arrived", "Goods", "Electricity"
+ "citicens", "Growth", "Buildings", "Verkehrsteilnehmer",
+ "Transported", "Passagiere", "sended", "Post",
+ "Arrived", "Goods", "Congestion"
+
};
+// Note: "Congestion" was "Electricity", but this value was unused.
+//@author: jamespetts
const int hist_type_color[MAX_CITY_HISTORY] =
{
COL_WHITE, COL_DARK_GREEN, COL_LIGHT_PURPLE, COL_POWERLINES,
COL_LIGHT_BLUE, COL_BLUE, COL_LIGHT_YELLOW, COL_YELLOW,
- COL_LIGHT_BROWN, COL_BROWN
+ COL_LIGHT_BROWN, COL_BROWN, COL_DARK_TURQOISE
};
@@ -80,7 +83,8 @@ stadt_info_t::stadt_info_t(stadt_t* stadt_) :
add_komponente(&year_month_tabs);
// add filter buttons
- for( int hist=0; histstadtinfo_options & (1<get_homeless()
);
+ b += sprintf(b, "%s: %d %%. \n",
+ translator::translate("Car ownership"),
+ c->get_private_car_ownership(c->get_welt()->get_timeline_year_month())
+ );
+
display_multiline_text(pos.x+8, pos.y+48, buf, COL_BLACK);
const unsigned long current_pax_destinations = c->get_pax_destinations_new_change();
diff --git a/ifc/fahrer.h b/ifc/fahrer.h
index a29ed1a8bf9..9022d96016d 100644
--- a/ifc/fahrer.h
+++ b/ifc/fahrer.h
@@ -12,6 +12,8 @@ class grund_t;
/**
* Interface für Verbindung von Fahrzeugen mit der Route.
+ *
+ * Interface for connection of vehicles with the route. (Google)
*
* @author Hj. Malthaner, 15.01.00
*/
@@ -20,6 +22,7 @@ class fahrer_t
public:
virtual ~fahrer_t() {}
+ //Is passable (Babelfish)
virtual bool ist_befahrbar(const grund_t* ) const = 0;
/**
diff --git a/makeobj/Makeobj-experimental.vcproj b/makeobj/Makeobj-experimental.vcproj
new file mode 100644
index 00000000000..16d90496e70
--- /dev/null
+++ b/makeobj/Makeobj-experimental.vcproj
@@ -0,0 +1,506 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/makeobj/Makeobj.sln b/makeobj/Makeobj.sln
new file mode 100644
index 00000000000..cb23159d2c6
--- /dev/null
+++ b/makeobj/Makeobj.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual C++ Express 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Makeobj", "Makeobj-experimental.vcproj", "{24CE8A5F-8B92-40EE-9491-31E2DFF019F9}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {24CE8A5F-8B92-40EE-9491-31E2DFF019F9}.Debug|Win32.ActiveCfg = Debug|Win32
+ {24CE8A5F-8B92-40EE-9491-31E2DFF019F9}.Debug|Win32.Build.0 = Debug|Win32
+ {24CE8A5F-8B92-40EE-9491-31E2DFF019F9}.Release|Win32.ActiveCfg = Release|Win32
+ {24CE8A5F-8B92-40EE-9491-31E2DFF019F9}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/makeobj/Makeobj.vcproj b/makeobj/Makeobj.vcproj
new file mode 100644
index 00000000000..ddffb9357d9
--- /dev/null
+++ b/makeobj/Makeobj.vcproj
@@ -0,0 +1,506 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/makeobj/makeobj.cc b/makeobj/makeobj.cc
index 03f97d1fae8..e7c79e3666e 100644
--- a/makeobj/makeobj.cc
+++ b/makeobj/makeobj.cc
@@ -33,8 +33,9 @@ int main(int argc, char* argv[])
argv++, argc--;
} else {
puts(
- "\nMakeobj version " MAKEOBJ_VERSION " for simutrans " VERSION_NUMBER " and higher\n"
- "(c) 2002-2006 V. Meyer , Hj. Malthaner, M. Pristovsek (markus@pristovsek.de)\n"
+ "\nMakeobj-Experimental, based on Makeobj version " MAKEOBJ_VERSION " for Simutrans-Experimental " VERSION_NUMBER " and higher\n"
+ "Experimental version by James E. Petts, derived from Makeobj, \n (c) 2002-2006 V. Meyer , Hj. Malthaner and \n"
+ "M. Pristovsek (markus@pristovsek.de). This is open source software, released under the Artistic Licence.\n"
);
}
diff --git a/player/ai.cc b/player/ai.cc
index d5db59d09c5..2c888b0606a 100755
--- a/player/ai.cc
+++ b/player/ai.cc
@@ -83,7 +83,7 @@ bool ai_t::is_my_halt(koord pos) const
*/
bool ai_t::is_connected( const koord start_pos, const koord dest_pos, const ware_besch_t *wtyp ) const
{
- // Dario: Check if there's a stop near destination
+ // Dario: Check if there's a stop near the start
const planquadrat_t* start_plan = welt->lookup(start_pos);
const halthandle_t* start_list = start_plan->get_haltlist();
@@ -115,8 +115,15 @@ bool ai_t::is_connected( const koord start_pos, const koord dest_pos, const ware
ware_t ware(wtyp);
ware.set_zielpos(dest_pos);
ware.menge = 1;
- for (uint16 hh = 0; hhget_haltlist_count(); hh++) {
- if( start_list[hh]->suche_route( ware, NULL, false ) != haltestelle_t::NO_ROUTE ) {
+ for (uint16 hh = 0; hhget_haltlist_count(); hh++)
+ {
+#ifdef NEW_PATHING
+ if(start_list[hh]->find_route(ware) < 65535)
+ {
+#else
+ if( start_list[hh]->suche_route( ware, NULL, false ) != haltestelle_t::NO_ROUTE )
+ {
+#endif
// ok, already connected
return true;
}
@@ -365,7 +372,8 @@ bool ai_t::built_update_headquarter()
}
// needs new place?
if(place==koord::invalid && !halt_list.empty()) {
- stadt_t *st = welt->suche_naechste_stadt(halt_list.front()->get_basis_pos());
+ //stadt_t *st = welt->suche_naechste_stadt(halt_list.front()->get_basis_pos());
+ stadt_t *st = welt->suche_naechste_stadt(halt_list[0]->get_basis_pos());
if(st) {
bool is_rotate=besch->get_all_layouts()>1;
place = ai_bauplatz_mit_strasse_sucher_t(welt).suche_platz(st->get_pos(), besch->get_b(), besch->get_h(), besch->get_allowed_climate_bits(), &is_rotate);
diff --git a/player/ai_goods.cc b/player/ai_goods.cc
index d52fe3a3170..7b462c402bc 100755
--- a/player/ai_goods.cc
+++ b/player/ai_goods.cc
@@ -679,9 +679,14 @@ void ai_goods_t::step()
if(root==NULL) {
// find a tree root to complete
weighted_vector_tpl start_fabs(20);
- slist_iterator_tpl fabiter( welt->get_fab_list() );
- while(fabiter.next()) {
- fabrik_t *fab = fabiter.get_current();
+ //slist_iterator_tpl fabiter( welt->get_fab_list() );
+ //while(fabiter.next()) {
+ //vector_tpl factories = welt->get_fab_list();
+ sint16 number_of_factories = welt->get_fab_list().get_count();
+ for(sint16 i = number_of_factories - 1; i >= 0; i --)
+ {
+ fabrik_t *fab = welt->get_fab_list()[i];
+ //fabrik_t *fab = fabiter.get_current();
// consumer and not completely overcrowded
if(fab->get_besch()->get_produkte()==0 && fab->get_status()!=fabrik_t::bad) {
int missing = get_factory_tree_missing_count( fab );
@@ -830,7 +835,7 @@ DBG_MESSAGE("do_ki()","check railway");
if( road_vehicle!=NULL ) {
best_road_speed = road_vehicle->get_geschw();
// find cheapest road
- road_weg = wegbauer_t::weg_search( road_wt, best_road_speed, welt->get_timeline_year_month(),weg_t::type_flat );
+ road_weg = wegbauer_t::weg_search( road_wt, best_road_speed, road_vehicle->get_gewicht(), welt->get_timeline_year_month(),weg_t::type_flat );
if( road_weg!=NULL ) {
if( best_road_speed>road_weg->get_topspeed() ) {
best_road_speed = road_weg->get_topspeed();
@@ -857,7 +862,7 @@ DBG_MESSAGE("ai_goods_t::do_ki()","No roadway possible.");
// only uneven number of cars bigger than 3 makes sense ...
count_rail = max( 3, count_rail );
income_rail = (freight_price*best_rail_speed)/(2*dist+count_rail);
- cost_rail = rail_weg->get_wartung() + (((count_rail+1)/2)*300)/dist + ((count_rail*rail_vehicle->get_betriebskosten()+rail_engine->get_betriebskosten())*best_rail_speed)/(2*dist+count_rail);
+ cost_rail = rail_weg->get_wartung() + (((count_rail+1)/2)*300)/dist + ((count_rail*rail_vehicle->get_betriebskosten(welt)+rail_engine->get_betriebskosten(welt))*best_rail_speed)/(2*dist+count_rail);
DBG_MESSAGE("ai_goods_t::do_ki()","Netto credits per day for rail transport %.2f (income %.2f)",cost_rail/100.0, income_rail/100.0 );
cost_rail -= income_rail;
}
@@ -868,7 +873,7 @@ DBG_MESSAGE("ai_goods_t::do_ki()","No roadway possible.");
// calculated here, since the above number was based on production
count_road = CLIP( (dist*15)/best_road_speed, 2, count_road );
int freight_price = (freight->get_preis()*road_vehicle->get_zuladung()*count_road)/24*((8000+(best_road_speed-80)*freight->get_speed_bonus())/1000);
- cost_road = road_weg->get_wartung() + 300/dist + (count_road*road_vehicle->get_betriebskosten()*best_road_speed)/(2*dist+5);
+ cost_road = road_weg->get_wartung() + 300/dist + (count_road*road_vehicle->get_betriebskosten(welt)*best_road_speed)/(2*dist+5);
income_road = (freight_price*best_road_speed)/(2*dist+5);
DBG_MESSAGE("ai_goods_t::do_ki()","Netto credits per day and km for road transport %.2f (income %.2f)",cost_road/100.0, income_road/100.0 );
cost_road -= income_road;
@@ -962,7 +967,7 @@ DBG_MESSAGE("ai_goods_t::do_ki()","No roadway possible.");
// for engine: gues number of cars
long power_needed=(long)(((best_rail_speed*best_rail_speed)/2500.0+1.0)*(100.0+count_rail*(rail_vehicle->get_gewicht()+rail_vehicle->get_zuladung()*freight->get_weight_per_unit()*0.001)));
const vehikel_besch_t *v=vehikelbauer_t::vehikel_search( track_wt, month_now, power_needed, best_rail_speed, NULL, false, false );
- if(v->get_betriebskosten()get_betriebskosten()) {
+ if(v->get_betriebskosten(welt)get_betriebskosten(welt)) {
rail_engine = v;
}
}
diff --git a/player/ai_passenger.cc b/player/ai_passenger.cc
index 7fbd4d39201..8e325bb32f3 100755
--- a/player/ai_passenger.cc
+++ b/player/ai_passenger.cc
@@ -70,14 +70,18 @@ bool ai_passenger_t::set_active(bool new_state)
*/
halthandle_t ai_passenger_t::get_our_hub( const stadt_t *s ) const
{
- slist_iterator_tpl iter( halt_list );
- while(iter.next()) {
- halthandle_t halt = iter.get_current();
+ //slist_iterator_tpl iter( halt_list );
+ //while(iter.next()) {
+ ITERATE(halt_list,i)
+ {
+ //halthandle_t halt = iter.get_current();
+ halthandle_t halt = halt_list[i];
if( halt->get_pax_enabled() && (halt->get_station_type()&haltestelle_t::busstop)!=0 ) {
koord h=halt->get_basis_pos();
if(h.x>=s->get_linksoben().x && h.y>=s->get_linksoben().y && h.x<=s->get_rechtsunten().x && h.y<=s->get_rechtsunten().y ) {
DBG_MESSAGE("ai_passenger_t::get_our_hub()","found %s at (%i,%i)",s->get_name(),h.x,h.y);
- return iter.get_current();
+ //return iter.get_current();
+ return halt_list[i];
}
}
}
@@ -210,9 +214,18 @@ bool ai_passenger_t::create_water_transport_vehikel(const stadt_t* start_stadt,
start_connect_hub = start_hub;
start_hub = halthandle_t();
// is there already one harbour next to this one?
- for( uint32 i=0; iget_warenziele(0)->get_count(); i++ ) {
+#ifdef NEW_PATHING
+ quickstone_hashtable_iterator_tpl iter(*start_connect_hub->get_connexions(0));
+ while(iter.next())
+ {
+ halthandle_t h = iter.get_current_key();
+#else
+ for(uint32 i = 0; i < start_connect_hub->get_warenziele(0)->get_count(); i++)
+ {
halthandle_t h = (*(start_connect_hub->get_warenziele(0)))[i];
- if( h->get_station_type()&haltestelle_t::dock ) {
+#endif
+ if( h->get_station_type()&haltestelle_t::dock )
+ {
start_hub = h;
break;
}
@@ -239,9 +252,18 @@ bool ai_passenger_t::create_water_transport_vehikel(const stadt_t* start_stadt,
end_connect_hub = end_hub;
end_hub = halthandle_t();
// is there already one harbour next to this one?
- for( uint32 i=0; iget_warenziele(0)->get_count(); i++ ) {
+#ifdef NEW_PATHING
+ quickstone_hashtable_iterator_tpl iter(*end_connect_hub->get_connexions(0));
+ while(iter.next())
+ {
+ halthandle_t h = iter.get_current_key();
+#else
+ for( uint32 i=0; iget_warenziele(0)->get_count(); i++ )
+ {
halthandle_t h = (*(end_connect_hub->get_warenziele(0)))[i];
- if( h->get_station_type()&haltestelle_t::dock ) {
+#endif
+ if( h->get_station_type()&haltestelle_t::dock )
+ {
start_hub = h;
break;
}
@@ -284,7 +306,7 @@ bool ai_passenger_t::create_water_transport_vehikel(const stadt_t* start_stadt,
if(town_road!=bushalt) {
wegbauer_t bauigel(welt, this);
// no bridges => otherwise first tile might be bridge start ...
- bauigel.route_fuer( wegbauer_t::strasse, wegbauer_t::weg_search( road_wt, 25, welt->get_timeline_year_month(), weg_t::type_flat ), tunnelbauer_t::find_tunnel(road_wt,road_vehicle->get_geschw(),welt->get_timeline_year_month()), NULL );
+ bauigel.route_fuer( wegbauer_t::strasse, wegbauer_t::weg_search( road_wt, road_vehicle->get_geschw(), road_vehicle->get_gewicht(), welt->get_timeline_year_month(), weg_t::type_flat ), tunnelbauer_t::find_tunnel(road_wt,road_vehicle->get_geschw(),welt->get_timeline_year_month()), NULL );
bauigel.set_keep_existing_faster_ways(true);
bauigel.set_keep_city_roads(true);
bauigel.set_maximum(10000);
@@ -302,7 +324,7 @@ bool ai_passenger_t::create_water_transport_vehikel(const stadt_t* start_stadt,
if(town_road!=bushalt) {
wegbauer_t bauigel(welt, this);
// no bridges => otherwise first tile might be bridge start ...
- bauigel.route_fuer( wegbauer_t::strasse, wegbauer_t::weg_search( road_wt, 25, welt->get_timeline_year_month(), weg_t::type_flat ), tunnelbauer_t::find_tunnel(road_wt,road_vehicle->get_geschw(),welt->get_timeline_year_month()), NULL );
+ bauigel.route_fuer( wegbauer_t::strasse, wegbauer_t::weg_search( road_wt, road_vehicle->get_geschw(), road_vehicle->get_gewicht(), welt->get_timeline_year_month(), weg_t::type_flat ), tunnelbauer_t::find_tunnel(road_wt,road_vehicle->get_geschw(),welt->get_timeline_year_month()), NULL );
bauigel.set_keep_existing_faster_ways(true);
bauigel.set_keep_city_roads(true);
bauigel.set_maximum(10000);
@@ -520,7 +542,7 @@ halthandle_t ai_passenger_t::build_airport(const stadt_t* city, koord pos, int r
sint32 lenght=9999;
rotation=-1;
- bauigel.route_fuer( wegbauer_t::strasse, wegbauer_t::weg_search( road_wt, 25, welt->get_timeline_year_month(), weg_t::type_flat ), tunnelbauer_t::find_tunnel(road_wt,road_vehicle->get_geschw(),welt->get_timeline_year_month()), brueckenbauer_t::find_bridge(road_wt,road_vehicle->get_geschw(),welt->get_timeline_year_month()) );
+ bauigel.route_fuer( wegbauer_t::strasse, wegbauer_t::weg_search( road_wt, road_vehicle->get_geschw(), road_vehicle->get_gewicht(), welt->get_timeline_year_month(), weg_t::type_flat ), tunnelbauer_t::find_tunnel(road_wt,road_vehicle->get_geschw(),welt->get_timeline_year_month()), brueckenbauer_t::find_bridge(road_wt,road_vehicle->get_geschw(),welt->get_timeline_year_month()) );
bauigel.set_keep_existing_faster_ways(true);
bauigel.set_keep_city_roads(true);
bauigel.set_maximum(10000);
@@ -640,8 +662,15 @@ bool ai_passenger_t::create_air_transport_vehikel(const stadt_t *start_stadt, co
start_connect_hub = start_hub;
start_hub = halthandle_t();
// is there already one airport next to this town?
+#ifdef NEW_PATHING
+ quickstone_hashtable_iterator_tpl iter(*start_connect_hub->get_connexions(0));
+ while(iter.next())
+ {
+ halthandle_t h = iter.get_current_key();
+#else
for( uint32 i=0; iget_warenziele(0)->get_count(); i++ ) {
halthandle_t h = (*(start_connect_hub->get_warenziele(0)))[i];
+#endif
if( h->get_station_type()&haltestelle_t::airstop ) {
start_hub = h;
break;
@@ -669,9 +698,18 @@ bool ai_passenger_t::create_air_transport_vehikel(const stadt_t *start_stadt, co
end_connect_hub = end_hub;
end_hub = halthandle_t();
// is there already one airport next to this town?
- for( uint32 i=0; iget_warenziele(0)->get_count(); i++ ) {
+#ifdef NEW_PATHING
+ quickstone_hashtable_iterator_tpl iter(*end_connect_hub->get_connexions(0));
+ while(iter.next())
+ {
+ halthandle_t h = iter.get_current_key();
+#else
+ for( uint32 i=0; iget_warenziele(0)->get_count(); i++ )
+ {
halthandle_t h = (*(end_connect_hub->get_warenziele(0)))[i];
- if( h->get_station_type()&haltestelle_t::airstop ) {
+#endif
+ if( h->get_station_type()&haltestelle_t::airstop )
+ {
start_hub = h;
break;
}
@@ -709,14 +747,23 @@ bool ai_passenger_t::create_air_transport_vehikel(const stadt_t *start_stadt, co
}
if(!end_hub.is_bound()) {
end_hub = build_airport(end_stadt, end_airport, true);
- if(!end_hub.is_bound()) {
- if(start_hub->get_warenziele_passenger()->get_count()==0) {
+ if(!end_hub.is_bound())
+ {
+#ifdef NEW_PATHING
+ if(start_hub->get_connexions(0)->empty())
+ {
+#else
+ if(start_hub->get_warenziele_passenger()->get_count()==0)
+ {
+#endif
// remove airport busstop
welt->lookup_kartenboden(start_hub->get_basis_pos())->remove_everything_from_way( this, road_wt, ribi_t::keine );
koord center = start_hub->get_basis_pos() + koord( welt->lookup_kartenboden(start_hub->get_basis_pos())->get_weg_ribi_unmasked( air_wt ) );
// now the remaining taxi-/runways
- for( sint16 y=center.y-1; y<=center.y+1; y++ ) {
- for( sint16 x=center.x-1; x<=center.x+1; x++ ) {
+ for( sint16 y=center.y-1; y<=center.y+1; y++ )
+ {
+ for( sint16 x=center.x-1; x<=center.x+1; x++ )
+ {
welt->lookup_kartenboden(koord(x,y))->remove_everything_from_way( this, air_wt, ribi_t::keine );
}
}
@@ -1136,7 +1183,7 @@ DBG_MESSAGE("ai_passenger_t::do_passenger_ki()","no suitable hub found");
// find the best => AI will never survive
// road_weg = wegbauer_t::weg_search( road_wt, road_vehicle->get_geschw(), welt->get_timeline_year_month(),weg_t::type_flat );
// find the really cheapest road
- road_weg = wegbauer_t::weg_search( road_wt, 10, welt->get_timeline_year_month(), weg_t::type_flat );
+ road_weg = wegbauer_t::weg_search( road_wt, road_vehicle->get_geschw(), road_vehicle->get_gewicht(), welt->get_timeline_year_month(), weg_t::type_flat );
state = NR_BAUE_STRASSEN_ROUTE;
DBG_MESSAGE("ai_passenger_t::do_passenger_ki()","using %s on %s",road_vehicle->get_name(),road_weg->get_name());
}
diff --git a/player/simplay.cc b/player/simplay.cc
index 0d82c111010..cb3f3a46f88 100644
--- a/player/simplay.cc
+++ b/player/simplay.cc
@@ -121,6 +121,9 @@ spieler_t::spieler_t(karte_t *wl, uint8 nr) :
// we have different AI, try to find out our type:
sprintf(spieler_name_buf,"player %i",player_nr-1);
+
+ base_credit_limit = get_base_credit_limit();
+ finance_history_month[0][COST_CREDIT_LIMIT] = calc_credit_limit();
}
@@ -246,10 +249,13 @@ void spieler_t::step()
{
// die haltestellen müssen die Fahrpläne rgelmaessig pruefen
uint8 i = (uint8)(welt->get_steps()+player_nr);
- slist_iterator_tpl iter( halt_list );
- while(iter.next()) {
+ //slist_iterator_tpl iter( halt_list );
+ //while(iter.next()) {
+ for(sint16 j = halt_list.get_count() - 1; j >= 0; j --)
+ {
if( (i & 31) == 0 ) {
- iter.get_current()->step();
+ //iter.get_current()->step();
+ halt_list[j]->step();
INT_CHECK("simplay 156");
}
i++;
@@ -267,8 +273,8 @@ void spieler_t::neuer_monat()
// since the messages must remain on the screen longer ...
static char buf[256];
-
// Wartungskosten abziehen
+ // "Deduct maintenance costs" (Google)
calc_finance_history();
roll_finance_history_month();
@@ -305,33 +311,98 @@ void spieler_t::neuer_monat()
return;
}
- // Bankrott ?
- if(konto < 0) {
+ // Insolvency settings.
+ // Modified by jamespetts, February 2009
+ if(konto < 0)
+ {
+ // Record of the number of months for which a player has been overdrawn.
konto_ueberzogen++;
- if(!welt->get_einstellungen()->is_freeplay()) {
- if(this == welt->get_spieler(0)) {
- if(finance_history_year[0][COST_NETWEALTH]<0) {
+
+ // Add interest
+
+ // Monthly rate
+ if(welt->get_einstellungen()->get_interest_rate_percent() > 0.0)
+ {
+ double interest_rate = ((welt->get_einstellungen()->get_interest_rate_percent() / 100.0) / 12.0);
+ sint32 monthly_interest = interest_rate * konto;
+ konto += monthly_interest;
+ finance_history_month[0][COST_INTEREST] += monthly_interest;
+ finance_history_month[0][COST_PROFIT] -= monthly_interest;
+ }
+
+ // Adjust credit limit
+ // Substract 1/5th of credit limit for each month overdrawn after three months
+ if(konto_ueberzogen > 3)
+ {
+ const sint64 adjusted_credit_limit = get_base_credit_limit() - (get_base_credit_limit() / 5) * (konto_ueberzogen - 3);
+ base_credit_limit = adjusted_credit_limit > 0 ? adjusted_credit_limit : 0;
+ }
+
+ if(!welt->get_einstellungen()->is_freeplay())
+ {
+ if(this == welt->get_spieler(0))
+ {
+ if(finance_history_year[0][COST_NETWEALTH] < 0 && welt->get_einstellungen()->bankruptsy_allowed())
+ {
destroy_all_win();
create_win(280, 40, new news_img("Bankrott:\n\nDu bist bankrott.\n"), w_info, magic_none);
welt->beenden(false);
}
- else {
+ else
+ {
+
+ int n = 0;
// tell the player
- sprintf(buf, translator::translate("On loan since %i month(s)"), konto_ueberzogen );
+ if(konto_ueberzogen > 1)
+ {
+ // Plural detection for the months.
+ // Different languages pluralise in different ways, so whole string must
+ // be re-translated.
+ n += sprintf(buf, translator::translate("You have been overdrawn\nfor %i months"), konto_ueberzogen );
+ if(konto_ueberzogen > 3)
+ {
+ n += sprintf(buf + n, translator::translate("\n\nYour credit rating is being affected."));
+ }
+ }
+ else
+ {
+ n += sprintf(buf, translator::translate("You have been overdrawn\nfor one month"));
+ }
+ if(welt->get_einstellungen()->get_interest_rate_percent() > 0)
+ {
+ n += sprintf(buf + n, translator::translate("\n\nInterest on your debt is\naccumulating at %i %%"), welt->get_einstellungen()->get_interest_rate_percent() );
+ }
// sprintf(buf,translator::translate("Verschuldet:\n\nDu hast %d Monate Zeit,\ndie Schulden zurueckzuzahlen.\n"), MAX_KONTO_VERZUG-konto_ueberzogen+1 );
welt->get_message()->add_message(buf,koord::invalid,message_t::problems,player_nr,IMG_LEER);
}
}
- else if(automat && this!=welt->get_spieler(1)) {
+ else if(automat && this!=welt->get_spieler(1))
+ {
// for AI, we only declare bankrupt, if total assest are below zero
- if(finance_history_year[0][COST_NETWEALTH]<0) {
+ // Also, AI players play by the same rules as human players: will only go bankrupt if humans can.
+ if(finance_history_year[0][COST_NETWEALTH]<0 && welt->get_einstellungen()->bankruptsy_allowed())
+ {
ai_bankrupt();
}
}
}
}
- else {
+ else
+ {
konto_ueberzogen = 0;
+ if(base_credit_limit < get_base_credit_limit())
+ {
+ // Restore credit rating slowly
+ // after a period of debt
+ base_credit_limit += (get_base_credit_limit() *0.1);
+ }
+ if(base_credit_limit > get_base_credit_limit())
+ {
+ // Make sure that the above computation does not
+ // allow the credit limit to increase beyond its
+ // normal level.
+ base_credit_limit = get_base_credit_limit();
+ }
}
}
@@ -399,6 +470,12 @@ void spieler_t::calc_finance_history()
margin_div = -margin_div;
}
finance_history_year[0][COST_MARGIN] = margin_div!= 0 ? (100*finance_history_year[0][COST_OPERATING_PROFIT]) / margin_div : 0;
+ sint64 total_credit_limit = 0;
+ for(uint8 i = 0; i < MAX_PLAYER_HISTORY_MONTHS; i ++)
+ {
+ total_credit_limit = finance_history_month[i][COST_CREDIT_LIMIT];
+ }
+ finance_history_year[0][COST_CREDIT_LIMIT] = total_credit_limit / MAX_PLAYER_HISTORY_MONTHS;
finance_history_month[0][COST_NETWEALTH] = finance_history_month[0][COST_ASSETS] + konto;
finance_history_month[0][COST_CASH] = konto;
@@ -409,14 +486,46 @@ void spieler_t::calc_finance_history()
}
finance_history_month[0][COST_MARGIN] = margin_div!=0 ? (100*finance_history_month[0][COST_OPERATING_PROFIT]) / margin_div : 0;
finance_history_month[0][COST_SCENARIO_COMPLETED] = finance_history_year[0][COST_SCENARIO_COMPLETED] = welt->get_scenario()->completed(player_nr);
+ finance_history_month[0][COST_CREDIT_LIMIT] = calc_credit_limit();
}
+sint64 spieler_t::calc_credit_limit()
+{
+ sint32 profit = 0;
+ sint32 assets = 0;
+ for(uint8 i = 0; i <= MAX_PLAYER_HISTORY_MONTHS; i++)
+ {
+ profit += finance_history_month[i][COST_OPERATING_PROFIT];
+ assets += finance_history_month[i][COST_NETWEALTH];
+ }
+ // Credit limit is 40% of net profit for the past year,
+ // plus 40% of the net assets for the past year,
+ // or 0, whichever is lower.
+ profit = (profit / 12.0) * 0.4;
+ assets = (assets/ 12.0) * 0.4;
+
+ sint64 new_limit = ((profit + assets) > base_credit_limit) ? profit + assets : base_credit_limit;
+
+ if(base_credit_limit < get_base_credit_limit())
+ {
+ // Credit rating adversely affected.
+ const float proportion = (float)base_credit_limit / (float)get_base_credit_limit();
+ new_limit *= proportion;
+ }
+
+ return new_limit;
+}
+
+sint64 spieler_t::get_base_credit_limit()
+{
+ return welt->get_einstellungen()->get_starting_money() / 10;
+}
// add and amount, including the display of the message and some other things ...
void spieler_t::buche(const sint64 betrag, const koord pos, enum player_cost type)
{
- buche(betrag, type);
+ buche(betrag, type); //"Buche" = "books"; "betrag" = "amount" (Babelfish).
if(betrag != 0) {
if( abs_distance(welt->get_world_position(),pos)<2*(uint32)(display_get_width()/get_tile_raster_width())+3 ) {
@@ -464,11 +573,25 @@ void spieler_t::buche(const sint64 betrag, enum player_cost type)
void spieler_t::accounting( spieler_t *sp, const sint64 amount, koord k, enum player_cost pc )
{
if(sp!=NULL && sp!=welt->get_spieler(1)) {
- sp->buche( amount, k, pc );
+ sp->buche( amount, k, pc ); //"Books" (Babelfish)
}
}
+// Will only process the transaction if it can be afforded.
+// @author: jamespetts
+bool spieler_t::accounting_with_check( spieler_t *sp, const sint64 amount, koord k, enum player_cost pc )
+{
+ if(sp->can_afford(amount))
+ {
+ accounting(sp, amount, k, pc);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
bool spieler_t::check_owner( const spieler_t *owner, const spieler_t *test )
@@ -542,9 +665,11 @@ void spieler_t::ai_bankrupt()
// remove headquarter pos
headquarter_pos = koord::invalid;
- // remove all stops
- while(halt_list.get_count()>0) {
- halthandle_t h = halt_list.remove_first();
+ // remove all stops
+ for(sint16 i = halt_list.get_count() - 1; i >= 0; i --)
+ {
+ halthandle_t h = halt_list[0];
+ halt_list.remove(h);
haltestelle_t::destroy( h );
}
@@ -647,107 +772,199 @@ void spieler_t::rdwr(loadsave_t *file)
}
file->rdwr_long(haltcount, " ");
- if (file->get_version() < 84008) {
+ if (file->get_version() < 84008)
+ {
// not so old save game
- for (int year = 0;yearget_version() < 84007) {
+ for (int year = 0; year < MAX_PLAYER_HISTORY_YEARS; year++)
+ {
+ for (int cost_type = 0; cost_type < MAX_PLAYER_COST; cost_type++)
+ {
+ if (file->get_version() < 84007)
+ {
// a cost_type has has been added. For old savegames we only have 9 cost_types, now we have 10.
// for old savegames only load 9 types and calculate the 10th; for new savegames load all 10 values
- if (cost_type < 9) {
+ if (cost_type < 9)
+ {
file->rdwr_longlong(finance_history_year[year][cost_type], " ");
- } else {
- sint64 tmp = finance_history_year[year][COST_VEHICLE_RUN] + finance_history_year[year][COST_MAINTENANCE];
- if(tmp<0) { tmp = -tmp; }
- finance_history_year[year][COST_MARGIN] = (tmp== 0) ? 0 : (finance_history_year[year][COST_OPERATING_PROFIT] * 100) / tmp;
+ }
+ else
+ {
+ if(cost_type == COST_INTEREST || cost_type == COST_CREDIT_LIMIT)
+ {
+ finance_history_year[year][cost_type] = 0;
+ }
+
+ else
+ {
+
+ sint64 tmp = finance_history_year[year][COST_VEHICLE_RUN] + finance_history_year[year][COST_MAINTENANCE];
+ if(tmp < 0)
+ {
+ tmp = -tmp;
+ }
+ finance_history_year[year][COST_MARGIN] = (tmp == 0) ? 0 : (finance_history_year[year][COST_OPERATING_PROFIT] * 100) / tmp;
+ }
}
- } else {
- if (cost_type < 10) {
+ }
+ else
+ {
+ if (cost_type < 10)
+ {
file->rdwr_longlong(finance_history_year[year][cost_type], " ");
- } else {
- sint64 tmp = finance_history_year[year][COST_VEHICLE_RUN] + finance_history_year[year][COST_MAINTENANCE];
- if(tmp<0) { tmp = -tmp; }
- finance_history_year[year][COST_MARGIN] = (tmp==0) ? 0 : (finance_history_year[year][COST_OPERATING_PROFIT] * 100) / tmp;
+ }
+ else
+ {
+ if(cost_type == COST_INTEREST || cost_type == COST_CREDIT_LIMIT)
+ {
+ finance_history_year[year][cost_type] = 0;
+ }
+ else
+ {
+ sint64 tmp = finance_history_year[year][COST_VEHICLE_RUN] + finance_history_year[year][COST_MAINTENANCE];
+ if(tmp < 0)
+ {
+ tmp = -tmp;
+ }
+ finance_history_year[year][COST_MARGIN] = (tmp==0) ? 0 : (finance_history_year[year][COST_OPERATING_PROFIT] * 100) / tmp;
+ }
}
}
}
//DBG_MESSAGE("player_t::rdwr()", "finance_history[year=%d][cost_type=%d]=%ld", year, cost_type,finance_history_year[year][cost_type]);
}
}
- else if (file->get_version() < 86000) {
- for (int year = 0;yearget_version() < 86000)
+ {
+ for (int year = 0; year < MAX_PLAYER_HISTORY_YEARS; year++)
+ {
+ for (int cost_type = 0; cost_type < 10; cost_type++)
+ {
file->rdwr_longlong(finance_history_year[year][cost_type], " ");
}
sint64 tmp = finance_history_year[year][COST_VEHICLE_RUN] + finance_history_year[year][COST_MAINTENANCE];
- if(tmp<0) { tmp = -tmp; }
+ if(tmp < 0)
+ {
+ tmp = -tmp;
+ }
finance_history_year[year][COST_MARGIN] = (tmp== 0) ? 0 : (finance_history_year[year][COST_OPERATING_PROFIT] * 100) / tmp;
+ finance_history_year[year][COST_INTEREST] = 0;
+ finance_history_year[year][COST_CREDIT_LIMIT] = 0;
}
// in 84008 monthly finance history was introduced
- for (int month = 0;monthrdwr_longlong(finance_history_month[month][cost_type], " ");
}
sint64 tmp = finance_history_month[month][COST_VEHICLE_RUN] + finance_history_month[month][COST_MAINTENANCE];
- if(tmp<0) { tmp = -tmp; }
+ if(tmp < 0)
+ {
+ tmp = -tmp;
+ }
finance_history_month[month][COST_MARGIN] = (tmp==0) ? 0 : (finance_history_month[month][COST_OPERATING_PROFIT] * 100) / tmp;
+ finance_history_year[month][COST_INTEREST] = 0;
+ finance_history_year[month][COST_CREDIT_LIMIT] = 0;
+ finance_history_month[month][COST_INTEREST] = 0;
+ finance_history_month[month][COST_CREDIT_LIMIT] = 0;
}
}
- else if (file->get_version() < 99011) {
+ else if (file->get_version() < 99011)
+ {
// powerline category missing
- for (int year = 0;yearrdwr_longlong(finance_history_year[year][cost_type], " ");
+ finance_history_year[year][COST_INTEREST] = 0;
+ finance_history_year[year][COST_CREDIT_LIMIT] = 0;
}
}
- for (int month = 0;monthrdwr_longlong(finance_history_month[month][cost_type], " ");
+ finance_history_month[month][COST_INTEREST] = 0;
+ finance_history_month[month][COST_CREDIT_LIMIT] = 0;
}
}
+
+
}
- else if (file->get_version() < 99017) {
+ else if (file->get_version() < 99017)
+ {
// without detailed goo statistics
- for (int year = 0;yearrdwr_longlong(finance_history_year[year][cost_type], " ");
+ finance_history_year[year][COST_INTEREST] = 0;
+ finance_history_year[year][COST_CREDIT_LIMIT] = 0;
}
}
- for (int month = 0;monthrdwr_longlong(finance_history_month[month][cost_type], " ");
+ finance_history_month[month][COST_INTEREST] = 0;
+ finance_history_month[month][COST_CREDIT_LIMIT] = 0;
}
}
}
else {
// most recent savegame version
- for (int year = 0;yearrdwr_longlong(finance_history_year[year][cost_type], " ");
+ for (int year = 0; year < MAX_PLAYER_HISTORY_YEARS;year++)
+ {
+ for (int cost_type = 0; cost_typeget_experimental_version() <= 1 && (cost_type == COST_INTEREST || cost_type == COST_CREDIT_LIMIT))
+ {
+ finance_history_year[year][cost_type] = 0;
+ }
+ else
+ {
+ file->rdwr_longlong(finance_history_year[year][cost_type], " ");
+ }
}
}
- for (int month = 0;monthrdwr_longlong(finance_history_month[month][cost_type], " ");
+ for (int month = 0;monthget_experimental_version() <= 1 && (cost_type == COST_INTEREST || cost_type == COST_CREDIT_LIMIT))
+ {
+ finance_history_year[month][cost_type] = 0;
+ }
+ else
+ {
+ file->rdwr_longlong(finance_history_month[month][cost_type], " ");
+ }
}
}
}
// we have to pay maintenance at the beginning of a month
- if(file->get_version()<99018 && file->is_loading()) {
+ if(file->get_version()<99018 && file->is_loading())
+ {
buche( -finance_history_month[1][COST_MAINTENANCE], COST_MAINTENANCE );
}
file->rdwr_bool(automat, "\n");
// state is not saved anymore
- if(file->get_version()<99014) {
+ if(file->get_version()<99014)
+ {
sint32 ldummy=0;
file->rdwr_long(ldummy, " ");
file->rdwr_long(ldummy, "\n");
}
// the AI stuff is now saved directly by the different AI
- if( file->get_version()<101000) {
+ if( file->get_version()<101000)
+ {
sint32 ldummy = -1;
file->rdwr_long(ldummy, " ");
file->rdwr_long(ldummy, "\n");
@@ -759,15 +976,19 @@ void spieler_t::rdwr(loadsave_t *file)
}
// Hajo: sanity checks
- if(halt_count < 0 || haltcount < 0) {
+ if(halt_count < 0 || haltcount < 0)
+ {
dbg->fatal("spieler_t::rdwr()", "Halt count is out of bounds: %d -> corrupt savegame?", halt_count|haltcount);
}
- if(file->is_loading()) {
+ if(file->is_loading())
+ {
// first: financial sanity check
- for (int year = 0;yearsp2num( this
halthandle_t halt = haltestelle_t::create( welt, file );
// it was possible to have stops without ground: do not load them
if(halt.is_bound()) {
- halt_list.insert(halt);
+ halt_list.insert_at(halt_list.get_count(), halt);
if(!halt->existiert_in_welt()) {
dbg->warning("spieler_t::rdwr()","empty halt id %i qill be ignored", halt.get_id() );
}
@@ -814,6 +1035,13 @@ DBG_DEBUG("spieler_t::rdwr()","player %i: loading %i halts.",welt->sp2num( this
if(file->get_version()>=88003) {
simlinemgmt.rdwr(welt,file,this);
}
+
+ base_credit_limit = get_base_credit_limit();
+ //credit_limit = calc_credit_limit();
+ if(file->get_experimental_version() <= 1)
+ {
+ finance_history_month[0][COST_CREDIT_LIMIT] = calc_credit_limit();
+ }
}
@@ -923,7 +1151,8 @@ spieler_t::undo()
return false;
}
// check, if we can still do undo
- for(unsigned short i=0; ilookup(last_built[i]);
if(gr==NULL || gr->get_typ()!=grund_t::boden) {
// well, something was built here ... so no undo
diff --git a/player/simplay.h b/player/simplay.h
index 6f40ec1dc90..2ccd97c7298 100644
--- a/player/simplay.h
+++ b/player/simplay.h
@@ -18,26 +18,30 @@
#include "../tpl/slist_tpl.h"
#include "../tpl/vector_tpl.h"
+#include "../simworld.h"
+
enum player_cost {
- COST_CONSTRUCTION=0,// Construction
- COST_VEHICLE_RUN, // Vehicle running costs
- COST_NEW_VEHICLE, // New vehicles
- COST_INCOME, // Income
- COST_MAINTENANCE, // Upkeep
- COST_ASSETS, // value of all vehicles and buildings
- COST_CASH, // Cash
- COST_NETWEALTH, // Total Cash + Assets
- COST_PROFIT, // COST_POWERLINES+COST_INCOME-(COST_CONSTRUCTION+COST_VEHICLE_RUN+COST_NEW_VEHICLE+COST_MAINTENANCE)
- COST_OPERATING_PROFIT, // COST_POWERLINES+COST_INCOME-(COST_VEHICLE_RUN+COST_MAINTENANCE)
- COST_MARGIN, // COST_OPERATING_PROFIT/(COST_VEHICLE_RUN+COST_MAINTENANCE)
- COST_ALL_TRANSPORTED, // all transported goods
- COST_POWERLINES, // revenue from the power grid
+ COST_CONSTRUCTION = 0, // Construction
+ COST_VEHICLE_RUN, // Vehicle running costs
+ COST_NEW_VEHICLE, // New vehicles
+ COST_INCOME, // Income
+ COST_MAINTENANCE, // Upkeep
+ COST_ASSETS, // value of all vehicles and buildings
+ COST_CASH, // Cash
+ COST_NETWEALTH, // Total Cash + Assets
+ COST_PROFIT, // COST_POWERLINES+COST_INCOME-(COST_CONSTRUCTION+COST_VEHICLE_RUN+COST_NEW_VEHICLE+COST_MAINTENANCE)
+ COST_OPERATING_PROFIT, // COST_POWERLINES+COST_INCOME-(COST_VEHICLE_RUN+COST_MAINTENANCE)
+ COST_MARGIN, // COST_OPERATING_PROFIT/(COST_VEHICLE_RUN+COST_MAINTENANCE)
+ COST_ALL_TRANSPORTED, // all transported goods
+ COST_POWERLINES, // revenue from the power grid
COST_TRANSPORTED_PAS, // number of passengers that actually reached destination
COST_TRANSPORTED_MAIL,
COST_TRANSPORTED_GOOD,
COST_ALL_CONVOIS, // number of convois
COST_SCENARIO_COMPLETED,// scenario success (only useful if there is one ... )
+ COST_INTEREST, // Interest paid servicing debt
+ COST_CREDIT_LIMIT, // Player's credit limit.
MAX_PLAYER_COST
};
@@ -45,7 +49,6 @@ enum player_cost {
#define MAX_PLAYER_HISTORY_MONTHS (12) // number of months to keep history
-class karte_t;
class fabrik_t;
class stadt_t;
class gebaeude_t;
@@ -94,19 +97,22 @@ class spieler_t
/**
* Der Kontostand.
+ * "The account balance." (Google)
*
* @author Hj. Malthaner
*/
- sint64 konto;
+ sint64 konto; //"account" (Google)
/**
* Zählt wie viele Monate das Konto schon ueberzogen ist
+ * "Count how many months the account is already overdrawn" (Google)
*
* @author Hj. Malthaner
*/
- sint32 konto_ueberzogen;
+ sint32 konto_ueberzogen; //"overdrawn account" (Google)
- slist_tpl halt_list; ///< Liste der Haltestellen
+ //slist_tpl halt_list; ///< Liste der Haltestellen
+ vector_tpl halt_list; ///< "List of the stops" (Babelfish)
class income_message_t {
public:
@@ -223,6 +229,8 @@ class spieler_t
// this is also save to be called with sp==NULL, which may happen for unowned objects like bridges, ways, trees, ...
static void accounting( spieler_t *sp, const sint64 betrag, koord k, enum player_cost pc );
+
+ static bool accounting_with_check( spieler_t *sp, const sint64 betrag, koord k, enum player_cost pc );
/**
* @return Kontostand als double (Gleitkomma) Wert
@@ -345,11 +353,28 @@ class spieler_t
vector_tpl last_built;
waytype_t undo_type;
+ // The maximum amount overdrawn that a player can be
+ // before no more purchases can be made.
+ sint32 base_credit_limit;
+
+protected:
+ sint64 calc_credit_limit();
+
+ sint64 get_base_credit_limit();
+
public:
void init_undo(waytype_t t, unsigned short max );
void add_undo(koord3d k);
bool undo();
+ //Checks the affordability of any possible purchase.
+ inline bool can_afford(sint64 price) const
+ {
+ return (price < (konto + finance_history_month[0][COST_CREDIT_LIMIT]) || welt->get_einstellungen()->insolvent_purchases_allowed() || welt->get_einstellungen()->is_freeplay());
+ }
+
+ uint32 get_credit_limit() const { return finance_history_month[0][COST_CREDIT_LIMIT]; }
+
// headquarter stuff
private:
sint32 headquarter_level;
diff --git a/simcity.cc b/simcity.cc
index 5d89864902c..c22aba11cf4 100644
--- a/simcity.cc
+++ b/simcity.cc
@@ -21,7 +21,6 @@
#include "player/simplay.h"
#include "simplan.h"
#include "simimg.h"
-#include "vehicle/simverkehr.h"
#include "simtools.h"
#include "simhalt.h"
#include "simfab.h"
@@ -53,9 +52,106 @@
#include "utils/cbuffer_t.h"
#include "utils/simstring.h"
+#include "tpl/ptrhashtable_tpl.h"
+
karte_t* stadt_t::welt = NULL; // one is enough ...
+sint16 number_of_cars;
+
+// Private car ownership information.
+// @author: jamespetts
+// (But much of this code is adapted from the speed bonus code,
+// written by Prissi).
+
+class car_ownership_record_t {
+public:
+ sint32 year;
+ sint16 ownership_percent;
+ car_ownership_record_t( sint32 y = 0, sint16 ownership = 0 ) {
+ year = y*12;
+ ownership_percent = ownership;
+ };
+};
+
+static sint16 default_car_ownership_percent = 25;
+
+static vector_tpl car_ownership[1];
+
+void stadt_t::privatecar_init(cstring_t objfilename)
+{
+ tabfile_t ownership_file;
+ // first take user data, then user global data
+ if (!ownership_file.open(objfilename+"config/privatecar.tab"))
+ {
+ dbg->message("stadt_t::privatecar_init()", "Error opening config/privatecar.tab.\nWill use default value." );
+ return;
+ }
+
+ tabfileobj_t contents;
+ ownership_file.read(contents);
+
+ /* init the values from line with the form year, speed, year, speed
+ * must be increasing order!
+ */
+ int *tracks = contents.get_ints("car_ownership");
+ if((tracks[0]&1)==1)
+ {
+ dbg->message("stadt_t::privatecar_init()", "Ill formed line in config/privatecar.tab.\nWill use default value. Format is year,ownership percentage[ year,ownership percentage]!" );
+ car_ownership->clear();
+ return;
+ }
+ car_ownership[0].resize( tracks[0]/2 );
+ for( int i=1; iget_count())
+ {
+ uint i=0;
+ while( iget_count() && monthyear>=car_ownership[0][i].year ) {
+ i++;
+ }
+ if( i==car_ownership->get_count() )
+ {
+ // maxspeed already?
+ return car_ownership[0][i-1].ownership_percent;
+ }
+ else if(i==0)
+ {
+ // minspeed below
+ return car_ownership[0][0].ownership_percent;
+ }
+ else
+ {
+ // interpolate linear
+ const sint32 delta_ownership_percent = car_ownership[0][i].ownership_percent - car_ownership[0][i-1].ownership_percent;
+ const sint32 delta_years = car_ownership[0][i].year - car_ownership[0][i-1].year;
+ return ( (delta_ownership_percent*(monthyear-car_ownership[0][i-1].year)) / delta_years ) + car_ownership[0][i-1].ownership_percent;
+ }
+ }
+ else
+ {
+ return default_car_ownership_percent;
+ }
+}
+
+
/********************************* From here on cityrules stuff *****************************************/
@@ -161,6 +257,7 @@ static const uint8 rotate_rules_270[] = {
48, 41, 34, 27, 20, 13, 6
};
+
/**
* Symbols in rules:
* S = darf keine Strasse sein
@@ -710,6 +807,9 @@ stadt_t::~stadt_t()
// close info win
destroy_win((long)this);
+ // Empty the list of city cars
+ current_cars.clear();
+
if( reliefkarte_t::get_karte()->get_city() == this ) {
reliefkarte_t::get_karte()->set_city(NULL);
}
@@ -828,6 +928,9 @@ next_name:;
}
city_history_year[0][HIST_CITICENS] = get_einwohner();
city_history_month[0][HIST_CITICENS] = get_einwohner();
+
+ outgoing_private_cars = 0;
+ incoming_private_cars = 0;
}
@@ -848,6 +951,12 @@ stadt_t::stadt_t(karte_t* wl, loadsave_t* file) :
name = NULL;
stadtinfo_options = 3;
+ // These things are not yet saved as part of the city's history,
+ // as doing so would require reversioning saved games.
+
+ incoming_private_cars = 0;
+ outgoing_private_cars = 0;
+
rdwr(file);
verbinde_fabriken();
@@ -1088,10 +1197,13 @@ void stadt_t::verbinde_fabriken()
{
DBG_MESSAGE("stadt_t::verbinde_fabriken()", "search factories near %s (center at %i,%i)", get_name(), pos.x, pos.y);
- slist_iterator_tpl fab_iter(welt->get_fab_list());
+ //slist_iterator_tpl fab_iter(welt->get_fab_list());
arbeiterziele.clear();
- while (fab_iter.next()) {
- add_factory_arbeiterziel(fab_iter.get_current());
+ for(sint16 i = welt->get_fab_list().get_count() - 1; i >= 0; i --)
+ {
+ //while (fab_iter.next()) {
+ //add_factory_arbeiterziel(fab_iter.get_current());
+ add_factory_arbeiterziel(welt->get_fab_list()[i]);
}
DBG_MESSAGE("stadt_t::verbinde_fabriken()", "is connected with %i factories (sum_weight=%i).", arbeiterziele.get_count(), arbeiterziele.get_sum_weight());
}
@@ -1141,6 +1253,7 @@ void stadt_t::step(long delta_t)
while(stadt_t::step_bau_interval < next_bau_step) {
calc_growth();
+ outgoing_private_cars = 0;
step_bau();
next_bau_step -= stadt_t::step_bau_interval;
}
@@ -1184,6 +1297,15 @@ void stadt_t::roll_history()
city_history_month[0][HIST_BUILDING] = buildings.get_count();
city_history_month[0][HIST_GOODS_NEEDED] = 0;
+ // Congestion figures for the year should be an average of the last 12 months.
+ uint16 total_congestion = 0;
+ for(int i = 0; i < 12; i ++)
+ {
+ total_congestion += city_history_month[i][HIST_CONGESTION];
+ }
+
+ city_history_year[0][HIST_CONGESTION] = total_congestion / 12;
+
//need to roll year too?
if (welt->get_last_month() == 0) {
for (int i = MAX_CITY_HISTORY_YEARS - 1; i > 0; i--) {
@@ -1198,12 +1320,13 @@ void stadt_t::roll_history()
city_history_year[0][HIST_CITICENS] = get_einwohner();
city_history_year[0][HIST_BUILDING] = buildings.get_count();
city_history_year[0][HIST_GOODS_NEEDED] = 0;
+
}
}
-void stadt_t::neuer_monat()
+void stadt_t::neuer_monat() //"New month" (Google)
{
swap( pax_destinations_old, pax_destinations_new );
pax_destinations_new.clear();
@@ -1211,22 +1334,130 @@ void stadt_t::neuer_monat()
roll_history();
+ // Calculate the level of congestion.
+ // Used in determining growth and passenger preferences.
+ // From observations in game: anything < 2, not very congested.
+ // Anything > 4, very congested.
+ // @author: jamespetts
+
+ float city_size = (float)(ur.x - lo.x) * (ur.y - lo.y);
+ float cars_per_tile = (float)city_history_month[1][HIST_CITYCARS] / city_size;
+ float population_density = (float)city_history_month[1][HIST_CITICENS] / city_size;
+ if(cars_per_tile <= 0.4)
+ {
+ city_history_month[0][HIST_CONGESTION] = 0;
+ }
+ else
+ {
+ float proportion = (((cars_per_tile - 0.4) / 4.5) * population_density) / welt->get_einstellungen()->get_congestion_density_factor();
+ city_history_month[0][HIST_CONGESTION] = proportion * 100;
+ }
+
if (!stadtauto_t::list_empty()) {
// spawn eventuall citycars
// the more transported, the less are spawned
// the larger the city, the more spawned ...
- double pfactor = (double)(city_history_month[1][HIST_PAS_TRANSPORTED]) / (double)(city_history_month[1][HIST_PAS_GENERATED]+1);
- double mfactor = (double)(city_history_month[1][HIST_MAIL_TRANSPORTED]) / (double)(city_history_month[1][HIST_MAIL_GENERATED]+1);
- double gfactor = (double)(city_history_month[1][HIST_GOODS_RECIEVED]) / (double)(city_history_month[1][HIST_GOODS_NEEDED]+1);
+
+ // Citycars now used as an accurate measure of actual traffic level, not just the number of cars generated
+ // graphically on the map. Thus, the "traffic level" setting no longer has an effect on the city cars graph,
+ // but still affects the number of actual cars generated.
+
+ // Divide by a factor because number of cars drawn on screen should be a fraction of actual traffic, or else
+ // everywhere will become completely clogged with traffic. Linear rather than logorithmic scaling so
+ // that the player can have a better idea visually of the amount of traffic.
+
+#define DESTINATION_CITYCARS
+
+#ifdef DESTINATION_CITYCARS
+ // Subtract incoming trips and cars already generated to prevent double counting.
+ sint16 factor = city_history_month[1][HIST_CITYCARS] - incoming_private_cars - current_cars.get_count();
+
+ //Manual assignment of traffic level modifiers, since I could not find a suitable mathematical formula.
+ float traffic_level;
+ switch(welt->get_einstellungen()->get_verkehr_level())
+ {
+ case 0:
+ traffic_level = 0;
+ break;
+
+ case 1:
+ traffic_level = 0.001;
+ break;
+
+ case 2:
+ traffic_level = 0.005;
+ break;
+
+ case 3:
+ traffic_level = 0.01;
+ break;
+
+ case 4:
+ traffic_level = 0.02;
+ break;
+
+ case 5:
+ traffic_level = 0.025;
+ break;
+
+ case 6:
+ traffic_level = 0.05;
+ break;
+
+ case 7:
+ traffic_level = 0.075;
+ break;
+
+ case 8:
+ traffic_level = 0.1;
+ break;
+
+ case 9:
+ traffic_level = 0.15;
+ break;
+
+ case 10:
+ traffic_level = 0.2;
+ break;
+
+ case 11:
+ traffic_level = 0.25;
+ break;
+
+ case 12:
+ traffic_level = 0.33;
+ break;
+
+ case 13:
+ traffic_level = 0.5;
+ break;
+
+ case 14:
+ traffic_level = 0.66;
+ break;
+
+ case 15:
+ traffic_level = 0.75;
+ break;
- double factor = pfactor > mfactor ? (gfactor > pfactor ? gfactor : pfactor ) : mfactor;
- factor = (1.0-factor)*city_history_month[1][HIST_CITICENS];
- factor = log10( factor );
- uint16 number_of_cars = simrand( (uint16)(factor * (double)welt->get_einstellungen()->get_verkehr_level()) ) / 16;
+ case 16:
+ default:
+ traffic_level = 1;
+ };
+
+ number_of_cars = factor * traffic_level;
+ incoming_private_cars = 0;
+#else
+ //uint16 number_of_cars = ((city_history_month[1][HIST_CITYCARS] * welt->get_einstellungen()->get_verkehr_level()) / 16) / 64;
+#endif
- city_history_month[0][HIST_CITYCARS] = number_of_cars;
- city_history_year[0][HIST_CITYCARS] += number_of_cars;
+ while(current_cars.get_count() > number_of_cars)
+ {
+ //Make sure that there are not too many cars on the roads.
+ stadtauto_t* car = current_cars.remove_first();
+ car->kill();
+ }
koord k;
koord pos = get_zufallspunkt();
@@ -1237,10 +1468,13 @@ void stadt_t::neuer_monat()
}
grund_t* gr = welt->lookup_kartenboden(k);
- if (gr != NULL && gr->get_weg(road_wt) && ribi_t::is_twoway(gr->get_weg_ribi_unmasked(road_wt)) && gr->find() == NULL) {
- stadtauto_t* vt = new stadtauto_t(welt, gr->get_pos(), koord::invalid);
+ if (gr != NULL && gr->get_weg(road_wt) && ribi_t::is_twoway(gr->get_weg_ribi_unmasked(road_wt)) && gr->find() == NULL)
+ {
+ slist_tpl *car_list = ¤t_cars;
+ stadtauto_t* vt = new stadtauto_t(welt, gr->get_pos(), koord::invalid, car_list);
gr->obj_add(vt);
welt->sync_add(vt);
+ current_cars.append(vt);
number_of_cars--;
}
}
@@ -1248,6 +1482,11 @@ void stadt_t::neuer_monat()
}
}
+sint16 stadt_t::get_outstanding_cars()
+{
+ return number_of_cars - current_cars.get_count();
+}
+
void stadt_t::calc_growth()
{
@@ -1271,8 +1510,13 @@ void stadt_t::calc_growth()
/* four parts contribute to town growth:
* passenger transport 40%, mail 20%, goods (30%), and electricity (10%)
+ *
+ * Congestion detracts from growth, but towns can now grow as a result of private car
+ * transport as well as public transport: if private car ownership is high enough.
+ * (@author: jamespetts)
*/
- sint32 pas = (city_history_month[0][HIST_PAS_TRANSPORTED] * (40<<6)) / (city_history_month[0][HIST_PAS_GENERATED] + 1);
+ //sint32 pas = (city_history_month[0][HIST_PAS_TRANSPORTED] * (40<<6)) / (city_history_month[0][HIST_PAS_GENERATED] + 1);
+ sint32 pas = ((city_history_month[0][HIST_PAS_TRANSPORTED] + (city_history_month[0][HIST_CITYCARS] - outgoing_private_cars)) * (40<<6)) / (city_history_month[0][HIST_PAS_GENERATED] + 1);
sint32 mail = (city_history_month[0][HIST_MAIL_TRANSPORTED] * (20<<6)) / (city_history_month[0][HIST_MAIL_GENERATED] + 1);
sint32 electricity = 0;
sint32 goods = city_history_month[0][HIST_GOODS_NEEDED]==0 ? 0 : (city_history_month[0][HIST_GOODS_RECIEVED] * (20<<6)) / (city_history_month[0][HIST_GOODS_NEEDED]);
@@ -1287,10 +1531,21 @@ void stadt_t::calc_growth()
}
// now give the growth for this step
- wachstum += (pas+mail+electricity+goods) / weight_factor;
+ sint32 growth_factor = (pas+mail+electricity+goods) / weight_factor; //"wachstum" = growth (Google)
+
+ //Congestion adversely impacts on growth. At 100% congestion, there will be no growth.
+ float congestion_factor;
+ if(city_history_month[0][HIST_CONGESTION] > 0)
+ {
+ congestion_factor = (city_history_month[0][HIST_CONGESTION] / 100.0);
+ growth_factor -= (congestion_factor * growth_factor);
+ }
+
+ wachstum += growth_factor;
}
+
// does constructions ...
void stadt_t::step_bau()
{
@@ -1321,10 +1576,25 @@ void stadt_t::step_bau()
*/
void stadt_t::step_passagiere()
{
-// DBG_MESSAGE("stadt_t::step_passagiere()", "%s step_passagiere called (%d,%d - %d,%d)\n", name, li, ob, re, un);
-// long t0 = get_current_time_millis();
+ //@author: jamespetts
+ // Passenger routing and generation metrics.
+ static uint16 local_passengers_min_distance = welt->get_einstellungen()->get_local_passengers_min_distance();
+ static uint16 local_passengers_max_distance = welt->get_einstellungen()->get_local_passengers_max_distance();
+ static uint16 midrange_passengers_min_distance = welt->get_einstellungen()->get_midrange_passengers_min_distance();
+ static uint16 midrange_passengers_max_distance = welt->get_einstellungen()->get_midrange_passengers_max_distance();
+ static uint16 longdistance_passengers_min_distance = welt->get_einstellungen()->get_longdistance_passengers_min_distance();
+ static uint16 longdistance_passengers_max_distance = welt->get_einstellungen()->get_longdistance_passengers_max_distance();
+
+ static uint8 passenger_packet_size = welt->get_einstellungen()->get_passenger_routing_packet_size();
+ static uint8 max_destinations = (welt->get_einstellungen()->get_max_alternative_destinations()) + 1;
+ static uint8 passenger_routing_local_chance = welt->get_einstellungen()->get_passenger_routing_local_chance();
+ static uint8 passenger_routing_midrange_chance = welt->get_einstellungen()->get_passenger_routing_midrange_chance();
+
+ // DBG_MESSAGE("stadt_t::step_passagiere()", "%s step_passagiere called (%d,%d - %d,%d)\n", name, li, ob, re, un);
+ // long t0 = get_current_time_millis();
// post oder pax erzeugen ?
+ // "post or generate pax"
const ware_besch_t* wtyp;
if (simrand(400) < 300) {
wtyp = warenbauer_t::passagiere;
@@ -1350,7 +1620,8 @@ void stadt_t::step_passagiere()
max(1,(gb->get_tile()->get_besch()->get_post_level() + 5) >> 4);
// create pedestrians in the near area?
- if (welt->get_einstellungen()->get_random_pedestrians() && wtyp == warenbauer_t::passagiere) {
+ if (welt->get_einstellungen()->get_random_pedestrians() && wtyp == warenbauer_t::passagiere)
+ {
haltestelle_t::erzeuge_fussgaenger(welt, gb->get_pos(), num_pax);
}
@@ -1360,12 +1631,13 @@ void stadt_t::step_passagiere()
const halthandle_t* halt_list = plan->get_haltlist();
// suitable start search
- halthandle_t start_halt = halthandle_t();
- for (uint h = 0; h < plan->get_haltlist_count(); h++) {
+ vector_tpl start_halts(2);
+ for (uint h = 0; h < plan->get_haltlist_count(); h++)
+ {
halthandle_t halt = halt_list[h];
- if( halt->is_enabled(wtyp) && !halt->is_overcrowded(wtyp->get_catg_index()) ) {
- start_halt = halt;
- break;
+ if (halt->is_enabled(wtyp) && !halt->is_overcrowded(wtyp->get_catg_index()))
+ {
+ start_halts.append(halt);
}
}
@@ -1373,173 +1645,690 @@ void stadt_t::step_passagiere()
city_history_year[0][history_type+1] += num_pax;
city_history_month[0][history_type+1] += num_pax;
- // only continue, if this is a good start halt
- if (start_halt.is_bound()) {
+ // Check whether this batch of passengers has access to a private car each.
+ // Check run in batches to save computational effort.
+ bool has_private_car = (simrand(100) <= get_private_car_ownership(welt->get_timeline_year_month()));
+
+ //Only continue if there are suitable start halts nearby, or the passengers have their own car.
+ if(start_halts.get_count() > 0 || has_private_car)
+ {
+ if(passenger_routing_local_chance < 1)
+ {
+ passenger_routing_local_chance = 33;
+ }
+ if(passenger_routing_midrange_chance < 1)
+ {
+ passenger_routing_midrange_chance = 33;
+ }
+ while(passenger_routing_midrange_chance + passenger_routing_local_chance > 99)
+ {
+ passenger_routing_midrange_chance = passenger_routing_midrange_chance / 2;
+ passenger_routing_local_chance = passenger_routing_local_chance / 2;
+ }
+ uint8 passenger_routing_longdistance_chance = 100 - (passenger_routing_local_chance + passenger_routing_midrange_chance);
+ //Add 1 because the simuconf.tab setting is for maximum *alternative* destinations, whereas we need maximum *actual* desintations
+ if(max_destinations > 16) max_destinations = 16;
+ if(passenger_packet_size < 1) passenger_packet_size = 7;
+
// Find passenger destination
- for (int pax_routed = 0; pax_routed < num_pax; pax_routed += 7) {
- // number of passengers that want to travel
- // Hajo: for efficiency we try to route not every
- // single pax, but packets. If possible, we do 7 passengers at a time
- // the last packet might have less then 7 pax
- int pax_left_to_do = min(7, num_pax - pax_routed);
+ for (int pax_routed = 0; pax_routed < num_pax; pax_routed += passenger_packet_size)
+ {
+
+ /* number of passengers that want to travel
+ * Hajo: for efficiency we try to route not every
+ * single pax, but packets. If possible, we do 7 passengers at a time
+ * the last packet might have less then 7 pax
+ * Number now not fixed at 7, but set in simuconf.tab (@author: jamespetts)*/
+
+ int pax_left_to_do = min(passenger_packet_size, num_pax - pax_routed);
// Ziel für Passagier suchen
+ // "The aim for passenger search"
pax_zieltyp will_return;
- const koord ziel = finde_passagier_ziel(&will_return);
-#ifdef DESTINATION_CITYCARS
- //citycars with destination
- if (pax_routed == 0) {
- erzeuge_verkehrsteilnehmer(start_halt->get_basis_pos(), step_count, ziel);
+ uint8 destination_count = simrand((max_destinations + 1));
+ if(destination_count < 1) destination_count = 1;
+
+ // Split passengers: 1/3rd are local only,
+ // 1/3rd are local or medium distance,
+ // and 1/3rd are of any distance.
+ // Note: a random town will be found if there are no towns within range.
+ uint8 passenger_routing_choice;
+ destination destinations[16];
+ for(int destinations_assigned = 0; destinations_assigned < destination_count; destinations_assigned ++)
+ {
+ passenger_routing_choice = simrand(100);
+
+ //if(pax_routed < (number_packets / 3))
+ if(passenger_routing_choice <= passenger_routing_local_chance)
+ {
+ //Local
+ destinations[destinations_assigned] = finde_passagier_ziel(&will_return, local_passengers_min_distance, local_passengers_max_distance);
+ }
+ //else if(pax_routed < ((number_packets / 3) * 2))
+ else if(passenger_routing_choice <= (passenger_routing_local_chance + passenger_routing_midrange_chance))
+ {
+ //Medium
+ destinations[destinations_assigned] = finde_passagier_ziel(&will_return, midrange_passengers_min_distance, midrange_passengers_max_distance);
+ }
+ else
+ //else if(passenger_routing_choice >= (100 - passenger_routing_longdistance_chance))
+ {
+ //Long distance
+ destinations[destinations_assigned] = finde_passagier_ziel(&will_return, longdistance_passengers_min_distance, longdistance_passengers_max_distance); //"Ziel" = "target" (Google)
+ }
}
+
+ uint8 current_destination = 0;
+#ifdef NEW_PATHING
+ bool route_good = false;
+#else
+ route_result = haltestelle_t::NO_ROUTE;
#endif
- // Dario: Check if there's a stop near destination
- const planquadrat_t* dest_plan = welt->lookup(ziel);
- const halthandle_t* dest_list = dest_plan->get_haltlist();
bool can_walk_ziel = false;
- // suitable end search
- unsigned ziel_count = 0;
- for( uint8 h = 0; h < dest_plan->get_haltlist_count(); h++ ) {
- halthandle_t halt = dest_list[h];
- if( halt->is_enabled(wtyp) ) {
- ziel_count++;
- if( halt == start_halt ) {
- can_walk_ziel = true;
- break; // because we found at least one valid step ...
- }
- }
- }
+#ifdef NEW_PATHING
+ while(!route_good && !can_walk_ziel && current_destination < destination_count)
+ {
+#else
+ while(route_result != haltestelle_t::ROUTE_OK && !can_walk_ziel && current_destination < destination_count)
+ {
+#endif
- if( ziel_count == 0 ) {
-// DBG_MESSAGE("stadt_t::step_passagiere()", "No stop near dest (%d, %d)", ziel.x, ziel.y);
- // Thus, routing is not possible and we do not need to do a calculation.
- // Mark ziel as destination without route and continue.
- merke_passagier_ziel(ziel, COL_DARK_ORANGE);
- start_halt->add_pax_no_route(pax_left_to_do);
#ifdef DESTINATION_CITYCARS
//citycars with destination
- erzeuge_verkehrsteilnehmer(start_halt->get_basis_pos(), step_count, ziel);
+ if(has_private_car)
+ {
+ if(start_halts.get_count() > 0)
+ {
+ halthandle_t start_halt = start_halts.get_element(0);
+ if(start_halt.is_bound())
+ {
+ erzeuge_verkehrsteilnehmer(start_halt->get_basis_pos(), step_count, destinations[current_destination].location);
+ }
+ }
+ }
#endif
- continue;
- }
+
+ // Dario: Check if there's a stop near destination
+ const planquadrat_t* dest_plan = welt->lookup(destinations[current_destination].location);
+ const halthandle_t* dest_list = dest_plan->get_haltlist();
+
+ halthandle_t start_halt;
+
+ unsigned ziel_count = 0;
+ for (uint h = 0; h < dest_plan->get_haltlist_count(); h++)
+ {
+ halthandle_t halt = dest_list[h];
+ if (halt->is_enabled(wtyp))
+ {
+ ziel_count++;
+ for(int i = start_halts.get_count(); i >= 0; i--)
+ {
+ if(start_halts.get_count() > i && halt == start_halts.get_element(i))
+ {
+ can_walk_ziel = true;
+ start_halt = start_halts.get_element(i);
+ }
+ }
+ break; // because we found at least one valid step ...
+ }
+ }
- // check, if they can walk there?
- if (can_walk_ziel) {
- // so we have happy passengers
- start_halt->add_pax_happy(pax_left_to_do);
- merke_passagier_ziel(ziel, COL_YELLOW);
- city_history_year[0][history_type] += pax_left_to_do;
- city_history_month[0][history_type] += pax_left_to_do;
- continue;
- }
+ //if (ziel_count == 0)
+ if(ziel_count == 0 && !can_walk_ziel)
+ {
+ // DBG_MESSAGE("stadt_t::step_passagiere()", "No stop near dest (%d, %d)", ziel.x, ziel.y);
+ // Thus, routing is not possible and we do not need to do a calculation.
+ // Mark ziel as destination without route and continue.
+ merke_passagier_ziel(destinations[current_destination].location, COL_DARK_ORANGE);
+ if(start_halts.get_count() > 0)
+ {
+ halthandle_t current_halt = start_halts.get_element(0);
+ current_halt->add_pax_no_route(pax_left_to_do);
+ }
+#ifdef NEW_PATHING
+ route_good = false;
+#else
+ route_result = haltestelle_t::NO_ROUTE;
+#endif
+
+ if(has_private_car)
+ {
+
+ // No way of getting there by public transport, so must go
+ // by private car if available.
+
+ // One day, it would be good if this could check to see whether
+ // there was a road between the origin and destination towns, too.
+
+ //@author: jamespetts
+
+ set_private_car_trip(pax_left_to_do, destinations[current_destination].town);
+#ifdef NEW_PATHING
+ route_good = true;
+#else
+ route_result = haltestelle_t::ROUTE_OK;
+#endif
- // ok, they are not in walking distance
- ware_t pax(wtyp);
- pax.set_zielpos(ziel);
- pax.menge = (wtyp == warenbauer_t::passagiere ? pax_left_to_do : max(1, pax_left_to_do >> 2));
-
- // now, finally search a route; this consumes most of the time
- koord return_zwischenziel = koord::invalid; // for people going back ...
- const int route_result = start_halt->suche_route( pax, will_return ? &return_zwischenziel : NULL, welt->get_einstellungen()->is_no_routing_over_overcrowding() );
-
- if( route_result == haltestelle_t::ROUTE_OK ) {
- // so we have happy traveling passengers
- start_halt->starte_mit_route(pax);
- start_halt->add_pax_happy(pax.menge);
- // and show it
- merke_passagier_ziel(ziel, COL_YELLOW);
- city_history_year[0][history_type] += pax.menge;
- city_history_month[0][history_type] += pax.menge;
- }
- else if( route_result==haltestelle_t::ROUTE_OVERCROWDED ) {
- merke_passagier_ziel(ziel, COL_ORANGE );
- start_halt->add_pax_unhappy(pax_left_to_do);
- if( will_return ) {
- pax.get_ziel()->add_pax_unhappy(pax_left_to_do);
- }
- }
- else {
- start_halt->add_pax_no_route(pax_left_to_do);
- merke_passagier_ziel(ziel, COL_DARK_ORANGE);
#ifdef DESTINATION_CITYCARS
- //citycars with destination
- erzeuge_verkehrsteilnehmer(start_halt->get_basis_pos(), step_count, ziel);
+ //citycars with destinations
+ if(start_halts.get_count() > 0)
+ {
+ //"Produce road users" (Babelfish)
+ erzeuge_verkehrsteilnehmer(start_halts[0]->get_basis_pos(), step_count, destinations[current_destination].location);
+ }
#endif
- }
+ }
+ current_destination ++;
+ continue;
+ }
- // send them also back
- if( route_result==haltestelle_t::ROUTE_OK && will_return != no_return ) {
- // this comes most of the times for free and balances also the amounts!
- halthandle_t ret_halt = pax.get_ziel();
- if(will_return != town_return) {
- // restore normal mail amount => more mail from attractions and factories than going to them
- pax.menge = pax_left_to_do;
+ // check, if they can walk there?
+ if (can_walk_ziel)
+ {
+ // so we have happy passengers
+ start_halt->add_pax_happy(pax_left_to_do);
+ merke_passagier_ziel(destinations[0].location, COL_YELLOW);
+ city_history_year[0][history_type] += pax_left_to_do;
+ city_history_month[0][history_type] += pax_left_to_do;
+#ifdef NEW_PATHING
+ route_good = true;
+#else
+ route_result = haltestelle_t::ROUTE_OK;
+#endif
+ current_destination ++;
+ continue;
}
- // we just have to ensure, the ware can be delivered at this station
- bool found = false;
- for (uint i = 0; i < plan->get_haltlist_count(); i++) {
- halthandle_t test_halt = halt_list[i];
- if (test_halt->is_enabled(wtyp) && (start_halt==test_halt || test_halt->get_warenziele(wtyp->get_catg_index())->is_contained(start_halt))) {
- found = true;
- start_halt = test_halt;
+ // ok, they are not in walking distance
+ ware_t pax(wtyp); //Journey start information needs to be added later.
+ pax.set_zielpos(destinations[current_destination].location);
+ pax.menge = (wtyp == warenbauer_t::passagiere ? pax_left_to_do : max(1, pax_left_to_do >> 2));
+ //"Menge" = volume (Google)
+
+ // now, finally search a route; this consumes most of the time
+
+#ifdef NEW_PATHING
+ uint16 best_journey_time = 65535;
+ uint8 best_start_halt = 0;
+#else
+ koord return_zwischenziel = koord::invalid; // for people going back ...
+ halthandle_t best_destination[3];
+ uint8 best_journey_steps = 255;
+#endif
+
+ ITERATE(start_halts,i)
+ {
+ if(start_halts.get_count() < 1)
+ {
break;
}
+ halthandle_t current_halt = start_halts[i];
+#ifdef NEW_PATHING
+ uint16 current_journey_time = current_halt->find_route(pax, best_journey_time);
+ if(current_journey_time < best_journey_time)
+ {
+ best_journey_time = current_journey_time;
+ best_start_halt = i;
+ }
+#else
+ route_result = current_halt->suche_route( pax, will_return ? &return_zwischenziel : NULL, welt->get_einstellungen()->is_no_routing_over_overcrowding() );
+#endif
+ if(!pax.get_ziel().is_bound())
+ {
+ //Only continue processing if there is a route.
+ continue;
+ }
+
+#ifdef NEW_PATHING
+ route_good = true;
+#else
+ halthandle_t tmp[3];
+ tmp[0] = pax.get_ziel();
+ tmp[1] = pax.get_zwischenziel();
+ tmp[2] = current_halt;
+ // Will fail if there is another journey with the same number of steps,
+ // but this does not matter, since they both count as the same.
+ uint8 tmp2 = pax.get_journey_steps();
+ if(tmp2 < best_journey_steps)
+ {
+ best_journey_steps = tmp2;
+ best_destination[0] = pax.get_ziel();
+ best_destination[1] = pax.get_zwischenziel();
+ best_destination[2] = tmp[2];
+ }
+#endif
+ }
+
+
+#ifdef NEW_PATHING
+ if(route_good)
+ {
+#else
+ if(route_result == haltestelle_t::ROUTE_OK)
+ {
+ //Only add passengers to the start halt (etc.) if a route was found.
+ pax.set_ziel(best_destination[0]);
+ pax.set_zwischenziel(best_destination[1]);
+ pax.set_journey_steps(best_journey_steps);
+#endif
+ pax.arrival_time = welt->get_zeit_ms();
+#ifndef NEW_PATHING
+ start_halt = best_destination[2];
+#else
+ // All passengers will use the quickest route.
+ // TODO: Consider whether to randomise a little.
+ start_halt = start_halts[best_start_halt];
+#endif
+#ifdef NEW_PATHING
+ if(start_halt == pax.get_ziel())
+ {
+#else
+ if(start_halt == best_destination[0])
+ {
+#endif
+ // Without this, where there are overlapping stops, passengers
+ // for nearby destinations accumulate at a stop, destined for
+ // that same stop, and never leave.
+ can_walk_ziel = true;
+ break;
+ }
+ pax.set_origin(start_halt);
+
+ // Now, decide whether passengers would prefer to use their private cars,
+ // even though they can travel by public transport.
+ uint16 distance = accurate_distance(destinations[current_destination].location, pos);
+ if(has_private_car)
+ {
+ //Weighted random.
+ uint8 private_car_chance = simrand(100);
+ if(private_car_chance < 1)
+ {
+ // If the chances are zero, skip all the rest of this code. This
+ // will speed up processing, and enable reversion to older behaviour.
+ goto public_transport;
+ }
+
+ // The basic preference for using a private car if available.
+ sint16 car_preference = welt->get_einstellungen()->get_base_car_preference_percent();
+
+ //First, adjust for distance. For very long-distance journies, cars are less popular.
+
+ //uint16 distance = abs(destinations[current_destination].location.x - pos.x) + abs(destinations[current_destination].location.x - pos.y);
+ if(distance > (midrange_passengers_max_distance * 3))
+ {
+ if(distance >= longdistance_passengers_max_distance)
+ {
+ car_preference /= 10;
+ }
+ else
+ {
+ float proportion = ((float)distance - (float)(midrange_passengers_max_distance * 3)) / (float)longdistance_passengers_max_distance;
+ car_preference /= (10 * proportion);
+ }
+ }
+
+ // Secondly, congestion. Drivers will turn to public transport if the oirin or destination towns are congested.
+
+ // This percentage of drivers will prefer to use the car however congested that it is.
+ static const sint16 always_prefer_car_percent = welt->get_einstellungen()->get_always_prefer_car_percent();
+
+ //Average congestion of origin and destination towns, and, at the same time, reduce factor.
+ uint8 congestion_total;
+ if(destinations[current_destination].town != NULL)
+ {
+ congestion_total = (city_history_month[0][HIST_CONGESTION] + destinations[current_destination].town->get_congestion()) / 4;
+ }
+ else
+ {
+ congestion_total = (city_history_month[0][HIST_CONGESTION] / 1.33);
+ }
+ sint16 congestion_factor = ((car_preference - congestion_total) > always_prefer_car_percent) ? congestion_total : (car_preference - always_prefer_car_percent);
+ car_preference -= congestion_factor;
+
+ // Thirdly adjust for service quality of the public transport.
+#ifdef NEW_PATHING
+ // Compare the average speed, including waiting times, with the speed bonus speed for
+ // *road* transport.
+
+ // This is the speed bonus calculation, without reference to price.
+ const ware_besch_t* passengers = pax.get_besch();
+ const uint16 average_speed = (60 * distance) / (best_journey_time * (1.0 - welt->get_einstellungen()->get_journey_time_multiplier()));
+ const sint32 ref_speed = welt->get_average_speed(road_wt);
+ const uint16 speed_bonus_rating = convoi_t::calc_adjusted_speed_bonus(passengers->get_speed_bonus(), distance);
+ const sint32 speed_base = (100 * average_speed) / ref_speed - 100;
+ const float base_bonus = (float)speed_base * ((float)speed_bonus_rating / 100.0);
+ //base_bonus should be 1 if the average speed is the same as the bonus speed.
+
+ if(base_bonus > 0)
+ {
+ // Positive bonus - reduce probability of car use
+ // by up to 50% if the bonus is 50 or more.
+ if(base_bonus >= 50)
+ {
+ private_car_chance *= 0.5;
+ }
+ else
+ {
+ const float proportion = (float)base_bonus / 50.0;
+ private_car_chance -= (private_car_chance * 0.5) * proportion;
+ }
+ }
+ else if(base_bonus < 0)
+ {
+ // Negative bonus - increase probability of car use
+ // by up to 85% if the bonus is -50 or less.
+ if(base_bonus <= -50)
+ {
+ private_car_chance += private_car_chance * 0.85;
+ }
+ else
+ {
+ const float proportion = (float)base_bonus / -50.0;
+ private_car_chance += (private_car_chance * 0.85) * proportion;
+ }
+ }
+ // Do nothing if base_bonus == 0.
+
+#else
+
+ //For some reason, the journey steps seem to be multiplied by 7.
+ uint8 hops = best_journey_steps / 7;
+
+ //Firstly, the number of steps
+ float hop_factor;
+ switch(hops)
+ {
+ case 0:
+ case 1:
+
+ hop_factor = 1.16;
+ break;
+
+ case 2:
+
+ hop_factor = 1.1;
+ break;
+
+ case 3:
+
+ hop_factor = 1;
+ break;
+
+ case 4:
+ hop_factor = 0.8;
+ break;
+
+ case 5:
+ hop_factor = 0.75;
+ break;
+
+ case 6:
+ hop_factor = 0.66;
+ break;
+
+ case 7:
+ hop_factor = 0.575;
+ break;
+
+ case 8:
+ hop_factor = 0.48;
+ break;
+
+ case 9:
+ hop_factor = 0.4;
+ break;
+
+ default:
+ hop_factor = 0.33;
+ };
+
+ private_car_chance *= hop_factor;
+#endif
+
+ //Secondly, the number of unhappy passengers at the start station compared with the number of happy passengers.
+ float unhappy_factor = start_halt->get_unhappy_proportion(0);
+ /*float unhappy_total = start_halt->get_pax_unhappy() - start_halt->get_pax_happy();
+ float unhappy_factor;
+ if(unhappy_total > 0)
+ {
+ unhappy_factor = unhappy_total / start_halt->get_capacity(0);
+ }
+ else
+ {
+ unhappy_factor = 0.0;
+ }*/
+
+ if(unhappy_factor > 0.8)
+ {
+ private_car_chance /= unhappy_factor;
+ }
+
+ //Finally, determine whether the private car is used.
+ if(private_car_chance <= car_preference)
+ {
+ set_private_car_trip(num_pax, destinations[current_destination].town);
+#ifdef DESTINATION_CITYCARS
+ //citycars with destination
+ if(start_halt.is_bound())
+ {
+ erzeuge_verkehrsteilnehmer(start_halt->get_basis_pos(), step_count, destinations[current_destination].location);
+ }
+#endif
+ current_destination ++;
+ break;
+ }
+ }
+
+ public_transport :
+
+ //This code should only be reached if the passengers do not use a private car.
+ start_halt->starte_mit_route(pax);
+ start_halt->add_pax_happy(pax.menge);
+ // and show it
+ merke_passagier_ziel(destinations[current_destination].location, COL_YELLOW);
+ city_history_year[0][history_type] += pax.menge;
+ city_history_month[0][history_type] += pax.menge;
+
+ }
+ else
+ {
+ if(start_halts.get_count() > 0)
+ {
+ start_halt = start_halts.get_element(0); //If there is no route, it does not matter where passengers express their unhappiness.
+#ifndef NEW_PATHING
+ if( route_result == haltestelle_t::ROUTE_OVERCROWDED )
+ {
+ merke_passagier_ziel(destinations[current_destination].location, COL_ORANGE );
+ start_halt->add_pax_unhappy(pax_left_to_do);
+ if( will_return )
+ {
+ pax.get_ziel()->add_pax_unhappy(pax_left_to_do);
+ }
+ }
+ else
+ {
+#endif
+ start_halt->add_pax_no_route(pax_left_to_do);
+ merke_passagier_ziel(destinations[current_destination].location, COL_DARK_ORANGE);
+#ifndef NEW_PATHING
+ }
+#endif
+ }
+
+ if(has_private_car)
+ {
+ //Must use private car, since there is no suitable route.
+ set_private_car_trip(num_pax, destinations[current_destination].town);
+#ifdef DESTINATION_CITYCARS
+ //citycars with destination
+ if(start_halt.is_bound())
+ {
+ erzeuge_verkehrsteilnehmer(start_halt->get_basis_pos(), step_count, destinations[current_destination].location);
+ }
+#endif
+ }
}
+ // send them also back
+#ifdef NEW_PATHING
+ if(will_return != no_return && route_good)
+ {
+#else
+ if (will_return != no_return && route_result == haltestelle_t::ROUTE_OK)
+ {
+#endif
+ // this comes most of the times for free and balances also the amounts!
+ halthandle_t ret_halt = pax.get_ziel();
+ if (will_return != town_return)
+ {
+ // restore normal mail amount => more mail from attractions and factories than going to them
+ pax.menge = pax_left_to_do;
+ }
+
+ // we just have to ensure, the ware can be delivered at this station
+ bool found = false;
+ for (uint i = 0; i < plan->get_haltlist_count(); i++)
+ {
+ halthandle_t test_halt = halt_list[i];
+#ifdef NEW_PATHING
+ if(test_halt->is_enabled(wtyp) && (start_halt == test_halt || test_halt->get_connexions(wtyp->get_catg_index())->access(start_halt) != NULL))
+ {
+#else
+ if (test_halt->is_enabled(wtyp) && (start_halt==test_halt || test_halt->get_warenziele(wtyp->get_catg_index())->is_contained(start_halt)))
+ {
+#endif
+ found = true;
+ start_halt = test_halt;
+ break;
+ }
+ }
+
// now try to add them to the target halt
- uint32 max_ware =ret_halt->get_capacity(wtyp->get_index());
- if( !ret_halt->is_overcrowded(wtyp->get_catg_index()) ) {
+ uint32 max_ware = ret_halt->get_capacity(wtyp->get_catg_index());
+ if( !ret_halt->is_overcrowded(wtyp->get_catg_index()) )
+ {
// prissi: not overcrowded and can recieve => add them
- if (found) {
- ware_t return_pax (wtyp);
-
- return_pax.menge = pax_left_to_do;
- return_pax.set_zielpos(k);
- return_pax.set_ziel(start_halt);
- return_pax.set_zwischenziel(welt->lookup(return_zwischenziel)->get_halt());
-
- ret_halt->starte_mit_route(return_pax);
- ret_halt->add_pax_happy(pax_left_to_do);
- } else {
- // no route back
- ret_halt->add_pax_no_route(pax_left_to_do);
+ if (found)
+ {
+ ware_t return_pax(wtyp, ret_halt);
+ return_pax.menge = pax_left_to_do;
+ return_pax.set_zielpos(k);
+ return_pax.set_ziel(start_halt);
+#ifndef NEW_PATHING
+ return_pax.set_zwischenziel(welt->lookup(return_zwischenziel)->get_halt());
+ return_pax.set_journey_steps(best_journey_steps);
+#else
+ if(ret_halt->find_route(return_pax) != 65535)
+ {
+#endif
+ return_pax.arrival_time = welt->get_zeit_ms();
+
+ ret_halt->starte_mit_route(return_pax);
+ ret_halt->add_pax_happy(pax_left_to_do);
+#ifdef NEW_PATHING
+ }
+ else
+ {
+ ret_halt->add_pax_no_route(pax_left_to_do);
+ }
+#endif
+ }
+ else
+ {
+ // no route back
+ ret_halt->add_pax_no_route(pax_left_to_do);
+ if(has_private_car)
+ {
+ //Must use private car, since there is no route back.
+ set_private_car_trip(num_pax, destinations[current_destination].town);
+ }
+
+ }
+ }
+ else
+ {
+ // return halt crowded
+ ret_halt->add_pax_unhappy(pax_left_to_do);
+
+ if(has_private_car)
+ {
+ //Must use private car, since the halt is crowded.
+ set_private_car_trip(num_pax, destinations[current_destination].town);
+ }
}
}
- else {
- // return halt crowded
- ret_halt->add_pax_unhappy(pax_left_to_do);
- }
+ INT_CHECK( "simcity 1579" );
+ current_destination ++;
}
- INT_CHECK( "simcity 1579" );
}
- }
- else {
+ }
+ else
+ {
// the unhappy passengers will be added to all crowded stops
// however, there might be no stop too
- for( uint h=0; hget_haltlist_count(); h++ ) {
- halthandle_t halt = halt_list[h];
- if (halt->is_enabled(wtyp)) {
-// assert(halt->get_ware_summe(wtyp)>halt->get_capacity();
- halt->add_pax_unhappy(num_pax);
- }
- }
// all passengers without suitable start:
// fake one ride to get a proper display of destinations (although there may be more) ...
pax_zieltyp will_return;
- const koord ziel = finde_passagier_ziel(&will_return);
-#ifdef DESTINATION_CITYCARS
- //citycars with destination
- erzeuge_verkehrsteilnehmer(k, step_count, ziel);
-#endif
- merke_passagier_ziel(ziel, COL_DARK_ORANGE);
- // we do not show no route for destination stop!
+ //const koord ziel = finde_passagier_ziel(&will_return);
+ destination destination_now = finde_passagier_ziel(&will_return);
+
+ if(!has_private_car)
+ {
+ //If the passengers do not have their own private transport, they will be unhappy.
+ for( uint h=0; hget_haltlist_count(); h++ ) {
+ halthandle_t halt = halt_list[h];
+ if (halt->is_enabled(wtyp)) {
+ //assert(halt->get_ware_summe(wtyp)>halt->get_capacity();
+ halt->add_pax_unhappy(num_pax);
+ }
+ }
+
+ #ifdef DESTINATION_CITYCARS
+ //citycars with destination
+ erzeuge_verkehrsteilnehmer(k, step_count, destination_now.location);
+ #endif
+ merke_passagier_ziel(destination_now.location, COL_DARK_ORANGE);
+ // we do not show no route for destination stop!
+ }
+ else
+ {
+ // Otherwise, they have a car and can get to their destination.
+ // They are not recorded as passengers, and drop out of the system.
+ // (Except to be recorded as private car trips).
+ set_private_car_trip(num_pax, destination_now.town);
+ }
}
+ // long t1 = get_current_time_millis();
+ // DBG_MESSAGE("stadt_t::step_passagiere()", "Zeit für Passagierstep: %ld ms\n", (long)(t1 - t0));
+}
-// long t1 = get_current_time_millis();
-// DBG_MESSAGE("stadt_t::step_passagiere()", "Zeit für Passagierstep: %ld ms\n", (long)(t1 - t0));
+
+inline void
+stadt_t::set_private_car_trip(int passengers, stadt_t* destination_town)
+{
+ if(destination_town == NULL || (destination_town->get_pos().x == pos.x && destination_town->get_pos().y == pos.y))
+ {
+ // Destination town is not set - so going to a factory or tourist attraction.
+ // Or origin and destination towns are the same.
+ // Count as a local trip
+ city_history_year[0][HIST_CITYCARS] += passengers;
+ city_history_month[0][HIST_CITYCARS] += passengers;
+ }
+ else
+ {
+ //Inter-city trip
+ city_history_year[0][HIST_CITYCARS] += passengers;
+ city_history_month[0][HIST_CITYCARS] += passengers;
+
+ //Also add private car trips to the *destination*.
+ destination_town->set_private_car_trips(passengers);
+
+ //And mark the trip as outgoing for growth calculations
+ outgoing_private_cars += passengers;
+ }
}
@@ -1569,35 +2358,70 @@ koord stadt_t::get_zufallspunkt() const
/* this function generates a random target for passenger/mail
* changing this strongly affects selection of targets and thus game strategy
*/
-koord stadt_t::finde_passagier_ziel(pax_zieltyp* will_return)
+
+stadt_t::destination stadt_t::finde_passagier_ziel(pax_zieltyp* will_return, uint16 min_distance, uint16 max_distance)
{
const int rand = simrand(100);
+ destination current_destination;
+ current_destination.town = NULL;
+ current_destination.type = 1;
// about 1/3 are workers
if (rand < FACTORY_PAX && arbeiterziele.get_sum_weight() > 0) {
const fabrik_t* fab = arbeiterziele.at_weight(simrand(arbeiterziele.get_sum_weight()));
*will_return = factoy_return; // worker will return
- return fab->get_pos().get_2d();
+ current_destination.type = FACTORY_PAX;
+ current_destination.location = fab->get_pos().get_2d();
+ return current_destination;
} else if (rand < TOURIST_PAX + FACTORY_PAX && welt->get_ausflugsziele().get_sum_weight() > 0) {
*will_return = tourist_return; // tourists will return
const gebaeude_t* gb = welt->get_random_ausflugsziel();
- return gb->get_pos().get_2d();
+ current_destination.type = TOURIST_PAX ;
+ current_destination.location = gb->get_pos().get_2d();
+ return current_destination;
} else {
// if we reach here, at least a single town existes ...
- const stadt_t* zielstadt = welt->get_random_stadt();
+ //const stadt_t* zielstadt = welt->get_random_stadt();
// we like nearer towns more
- if (abs(zielstadt->pos.x - pos.x) + abs(zielstadt->pos.y - pos.y) > 120) {
+ //if (abs(zielstadt->pos.x - pos.x) + abs(zielstadt->pos.y - pos.y) > 120) {
// retry once ...
- zielstadt = welt->get_random_stadt();
+ // zielstadt = welt->get_random_stadt();
+ //}
+
+ // Ensure that the returned town is within the distance range specified,
+ // or else find a new town and repeat.
+ stadt_t* zielstadt;
+ bool town_within_range = false;
+ uint8 retry_count = 0;
+ do
+ {
+ zielstadt = welt->get_random_town();
+ if(abs(zielstadt->pos.x - pos.x) + abs(zielstadt->pos.y - pos.y) >= min_distance && (zielstadt->pos.x - pos.x) + abs(zielstadt->pos.y - pos.y)<= max_distance)
+ {
+ town_within_range = true;
+ }
+ //Prevent infinite loops here if there are no suitable towns at all.
+ retry_count++;
+ if(retry_count > 32) town_within_range = true;
}
+ while(!town_within_range);
// long distance traveller? => then we return
+ // zielstadt = "Destination city"
*will_return = (this != zielstadt) ? town_return : no_return;
- return zielstadt->get_zufallspunkt();
+ current_destination.location = zielstadt->get_zufallspunkt(); //"random dot"
+ current_destination.town = zielstadt;
+ return current_destination;
}
}
+stadt_t::destination stadt_t::finde_passagier_ziel(pax_zieltyp* will_return)
+{
+ //Default version, gives wide range of distances.
+ return finde_passagier_ziel(will_return, 0, 4096);
+}
+
void stadt_t::merke_passagier_ziel(koord k, uint8 color)
{
@@ -2053,9 +2877,10 @@ void stadt_t::erzeuge_verkehrsteilnehmer(koord pos, sint32 level, koord target)
}
#endif
if (!stadtauto_t::list_empty()) {
- stadtauto_t* vt = new stadtauto_t(welt, gr->get_pos(), target);
+ stadtauto_t* vt = new stadtauto_t(welt, gr->get_pos(), target, ¤t_cars);
gr->obj_add(vt);
welt->sync_add(vt);
+ current_cars.append(vt);
}
return;
}
diff --git a/simcity.h b/simcity.h
index edb422b0436..0f96c03d698 100644
--- a/simcity.h
+++ b/simcity.h
@@ -13,6 +13,10 @@
#include "tpl/vector_tpl.h"
#include "tpl/weighted_vector_tpl.h"
+#include "tpl/array2d_tpl.h"
+#include "tpl/slist_tpl.h"
+
+#include "vehicle/simverkehr.h"
#include "tpl/sparse_tpl.h"
class karte_t;
@@ -37,11 +41,11 @@ enum city_cost {
HIST_CITYCARS, // number of citycars generated
HIST_PAS_TRANSPORTED, // number of passengers who could start their journey
HIST_PAS_GENERATED, // total number generated
- HIST_MAIL_TRANSPORTED, // letters that could be sended
+ HIST_MAIL_TRANSPORTED, // letters that could be sent
HIST_MAIL_GENERATED, // all letters generated
HIST_GOODS_RECIEVED, // times all storages were not empty
HIST_GOODS_NEEDED, // times sotrages checked
- HIST_POWER_RECIEVED, // power consumption (not used at the moment!)
+ HIST_CONGESTION, // Level of congestion in the city, expressed in percent.(Was power consumption - disused)
MAX_CITY_HISTORY // Total number of items in array
};
@@ -84,6 +88,8 @@ class stadt_t
* @author Hj. Malthaner
*/
static bool cityrules_init(cstring_t objpathname);
+ static void privatecar_init(cstring_t objfilename);
+ sint16 get_private_car_ownership(sint32 monthyear);
private:
static karte_t *welt;
@@ -153,6 +159,18 @@ class stadt_t
*/
void roll_history(void);
+ inline void set_private_car_trip(int passengers, stadt_t* destination_town);
+
+ // This is needed to prevent double counting of incoming traffic.
+ sint16 incoming_private_cars;
+
+ //This is needed because outgoing cars are disregarded when calculating growth.
+ sint16 outgoing_private_cars;
+
+ slist_tpl current_cars;
+
+ uint8 route_result;
+
public:
/**
* Returns pointer to history for city
@@ -161,11 +179,20 @@ class stadt_t
sint64* get_city_history_year() { return *city_history_year; }
sint64* get_city_history_month() { return *city_history_month; }
+ sint16 get_outstanding_cars();
+
// just needed by stadt_info.cc
static inline karte_t* get_welt() { return welt; }
uint32 stadtinfo_options;
+ void set_private_car_trips(uint16 number)
+ {
+ city_history_month[0][HIST_CITYCARS] += number;
+ city_history_year[0][HIST_CITYCARS] += number;
+ incoming_private_cars += number;
+ }
+
/* end of histroy related thingies */
private:
sint32 best_haus_wert;
@@ -408,11 +435,21 @@ class stadt_t
void neuer_monat();
+ //@author: jamespetts
+ struct destination
+ {
+ koord location;
+ uint16 type; //1 = town; others as #define above.
+ stadt_t* town; //NULL if the type is not a town.
+ };
+
+
/**
* such ein (zufälliges) ziel für einen Passagier
* @author Hj. Malthaner
*/
- koord finde_passagier_ziel(pax_zieltyp *will_return);
+ destination finde_passagier_ziel(pax_zieltyp* will_return);
+ destination finde_passagier_ziel(pax_zieltyp* will_return, uint16 min_distance, uint16 max_distance);
/**
* Gibt die Gruendungsposition der Stadt zurueck.
@@ -439,6 +476,8 @@ class stadt_t
void zeige_info(void);
void add_factory_arbeiterziel(fabrik_t *fab);
+
+ uint8 get_congestion() { return city_history_month[0][HIST_CONGESTION]; }
};
#endif
diff --git a/simcolor.h b/simcolor.h
index 842af4bd2ed..73d36f7f0de 100644
--- a/simcolor.h
+++ b/simcolor.h
@@ -95,5 +95,10 @@ typedef unsigned char COLOR_VAL;
#define COL_ARRIVED COL_DARK_ORANGE
#define COL_DEPARTED COL_DARK_YELLOW
#define COL_POWERLINES (87)
+#define COL_AVERAGE_SPEED (69)
+#define COL_AVEARGE_WAIT COL_DARK_PURPLE
+#define COL_COMFORT COL_DARK_TURQOISE
+#define COL_INTEREST (101)
+#define COL_CREDIT_LIMIT (99)
#endif
diff --git a/simconvoi.cc b/simconvoi.cc
index 3d3b98d30b0..6c22036fd09 100644
--- a/simconvoi.cc
+++ b/simconvoi.cc
@@ -28,6 +28,8 @@
#include "boden/grund.h"
#include "boden/wege/schiene.h" // for railblocks
+#include "bauer/vehikelbauer.h"
+
#include "besch/vehikel_besch.h"
#include "besch/roadsign_besch.h"
@@ -75,7 +77,7 @@ karte_t *convoi_t::welt = NULL;
static const char * state_names[convoi_t::MAX_STATES] =
{
"INITIAL",
- "FAHRPLANEINGABE",
+ "FAHRPLANEINGABE", //"Schedule input"
"ROUTING_1",
"",
"",
@@ -108,15 +110,43 @@ static int calc_min_top_speed(const array_tpl& fahr, uint8 anz_vehik
}
+// Reset some values. Used in init and replacing.
+void convoi_t::reset()
+{
+ is_electric = false;
+ sum_gesamtgewicht = sum_gewicht = sum_gear_und_leistung = sum_leistung = power_from_steam = power_from_steam_with_gear = 0;
+ previous_delta_v = 0;
+ min_top_speed = 9999999;
+
+ withdraw = false;
+ has_obsolete = false;
+ no_load = false;
+ replace = false;
+ depot_when_empty = false;
+
+ jahresgewinn = 0;
+
+ max_record_speed = 0;
+ akt_speed_soll = 0; // Sollgeschwindigkeit
+ akt_speed = 0; // momentane Geschwindigkeit
+ sp_soll = 0;
+
+ heaviest_vehicle = 0;
+ longest_loading_time = 0;
+ last_departure_time = welt->get_zeit_ms();
+ for(uint8 i = 0; i < MAX_CONVOI_COST; i ++)
+ {
+ rolling_average[i] = 0;
+ rolling_average_count[i] = 0;
+ }
+}
+
void convoi_t::init(karte_t *wl, spieler_t *sp)
{
welt = wl;
besitzer_p = sp;
- is_electric = false;
- sum_gesamtgewicht = sum_gewicht = sum_gear_und_leistung = sum_leistung = 0;
- previous_delta_v = 0;
- min_top_speed = 9999999;
+ reset();
fpl = NULL;
line = linehandle_t();
@@ -124,14 +154,10 @@ void convoi_t::init(karte_t *wl, spieler_t *sp)
anz_vehikel = 0;
steps_driven = -1;
- withdraw = false;
- has_obsolete = false;
- no_load = false;
+ autostart = true;
wait_lock = 0;
go_on_ticks = WAIT_INFINITE;
- jahresgewinn = 0;
-
alte_richtung = ribi_t::keine;
next_wolke = 0;
@@ -145,17 +171,15 @@ void convoi_t::init(karte_t *wl, spieler_t *sp)
loading_level = 0;
loading_limit = 0;
- max_record_speed = 0;
- akt_speed_soll = 0; // Sollgeschwindigkeit
- akt_speed = 0; // momentane Geschwindigkeit
- sp_soll = 0;
-
next_stop_index = 65535;
line_update_pending = linehandle_t();
home_depot = koord3d::invalid;
last_stop_pos = koord3d::invalid;
+
+ reversable = false;
+ reversed = false;
}
@@ -166,7 +190,6 @@ convoi_t::convoi_t(karte_t* wl, loadsave_t* file) : fahr(max_vehicle, NULL)
rdwr(file);
}
-
convoi_t::convoi_t(spieler_t* sp) : fahr(max_vehicle, NULL)
{
self = convoihandle_t(this);
@@ -203,12 +226,28 @@ DBG_MESSAGE("convoi_t::~convoi_t()", "destroying %d, %p", self.get_id(), this);
// force asynchronous recalculation
if(fpl) {
- if(!fpl->ist_abgeschlossen()) {
+ if(!fpl->ist_abgeschlossen()) { //"is completed" (Google)
destroy_win((long)fpl);
}
- if(fpl->get_count()>0 && !line.is_bound() ) {
- welt->set_schedule_counter();
+
+#ifdef NEW_PATHING
+ if(fpl->get_count()>0 && !line.is_bound() )
+ {
+ // New method - recalculate as necessary
+ ITERATE_PTR(fpl, j)
+ {
+ halthandle_t tmp_halt = haltestelle_t::get_halt(welt, fpl->eintrag[j].pos);
+ if(tmp_halt.is_bound())
+ {
+ tmp_halt->reschedule = true;
+ tmp_halt->force_paths_stale();
+ }
+ }
}
+#else
+ // Old method - brute force
+ welt->set_schedule_counter();
+#endif
delete fpl;
}
@@ -353,7 +392,7 @@ DBG_MESSAGE("convoi_t::laden_abschliessen()","next_stop_index=%d", next_stop_ind
for(unsigned i=0; idarf_rauchen(false);
+ v->darf_rauchen(false); //"Allowed to smoke" (Google)
fahr[i]->fahre_basis( ((TILE_STEPS)*train_length)<<12 );
train_length -= v->get_besch()->get_length();
v->darf_rauchen(true);
@@ -488,7 +527,9 @@ void convoi_t::calc_acceleration(long delta_t)
// prissi:
// integer sucks with planes => using floats ...
- sint32 delta_v = (sint32)( ( (double)( (akt_speed>akt_speed_soll?0l:sum_gear_und_leistung) - deccel)*(double)delta_t)/(double)sum_gesamtgewicht);
+ //sint32 delta_v = (sint32)( ( (double)( (akt_speed>akt_speed_soll?0l:sum_gear_und_leistung) - deccel)*(double)delta_t)/(double)sum_gesamtgewicht);
+ sint32 delta_v = (sint32)( ( (double)( (akt_speed>akt_speed_soll?0l:calc_adjusted_power()) - deccel)*(double)delta_t)/(double)sum_gesamtgewicht);
+ //"leistung" = "performance" (Google)
// we normalize delta_t to 1/64th and check for speed limit */
// sint32 delta_v = ( ( (akt_speed>akt_speed_soll?0l:sum_gear_und_leistung) - deccel) * delta_t)/sum_gesamtgewicht;
@@ -497,7 +538,11 @@ void convoi_t::calc_acceleration(long delta_t)
delta_v += previous_delta_v;
previous_delta_v = delta_v & 0x0FFF;
// and finally calculate new speed
+#ifdef TEST_SPEED
+ akt_speed = kmh_to_speed(10);
+#else
akt_speed = max(akt_speed_soll>>4, akt_speed+(sint32)(delta_v>>12l) );
+
}
else {
// very old vehicle ...
@@ -510,6 +555,7 @@ void convoi_t::calc_acceleration(long delta_t)
if(akt_speed > akt_speed_soll+kmh_to_speed(20)) {
akt_speed = akt_speed_soll+kmh_to_speed(20);
}
+#endif
}
// new record?
@@ -519,6 +565,85 @@ void convoi_t::calc_acceleration(long delta_t)
}
}
+sint32 convoi_t::calc_adjusted_power()
+{
+ //uint16 max_speed = speed_to_kmh(fahr[0]->get_besch()->get_geschw());
+ uint16 max_speed = fahr[0]->get_besch()->get_geschw();
+ float highpoint_speed = (max_speed >= 30) ? max_speed - 30 : 30;
+ uint16 current_speed = speed_to_kmh(akt_speed);
+
+ // Within 15% of top speed - locomotive less efficient
+ float high_speed = (float)max_speed * 0.85;
+
+ if(power_from_steam < 1 || current_speed > highpoint_speed && current_speed < high_speed)
+ {
+ // Either no steam engines, or going fast
+ // enough that it makes no difference,
+ // so the simple formula prevails.
+ return sum_gear_und_leistung;
+ }
+ // There must be a steam locomotive here.
+ // So, reduce the power at higher and lower speeds.
+ // Should be approx (for medium speed locomotive):
+ // 40% power at 15kph 70% power at 25kph;
+ // 85% power at 32kph; and 100% power at >50kph.
+ // See here for details: http://www.railway-technical.com/st-vs-de.shtml
+
+ //This is needed to add back at the end.
+ uint32 power_without_steam = sum_gear_und_leistung - power_from_steam_with_gear;
+
+ float speed_factor;
+
+ if(power_from_steam > 500)
+ {
+ speed_factor = 1.0;
+ }
+ else
+ {
+ float difference = 450 - (power_from_steam - 50);
+ float proportion = difference / 450.0;
+ float factor = 0.66 * proportion;
+ speed_factor = 1 + factor;
+ }
+
+ //These values are needed to apply different power reduction factors
+ //depending on the maximum speed.
+
+ float lowpoint_speed = highpoint_speed * 0.3;
+ float midpoint_speed = lowpoint_speed * 2;
+
+ if(current_speed <= lowpoint_speed)
+ {
+ speed_factor *= 0.4;
+ }
+ else if(current_speed <= midpoint_speed)
+ {
+ float speed_differential_actual = (float)current_speed - (float)lowpoint_speed;
+ float speed_differential_maximum = (float)midpoint_speed - (float)lowpoint_speed;
+ float factor_modification = speed_differential_actual / speed_differential_maximum;
+ speed_factor *= ((factor_modification * 0.4) + 0.4);
+ }
+ else if(current_speed <= high_speed)
+ {
+ // Not at high speed
+ float speed_differential_actual = (float)current_speed - (float)midpoint_speed;
+ float speed_differential_maximum = (float)highpoint_speed - (float)lowpoint_speed;
+ float factor_modification = speed_differential_actual / speed_differential_maximum;
+ speed_factor *= ((factor_modification * 0.15) + 0.8);
+ }
+ else
+ {
+ // Must be within 15% of top speed here.
+ float speed_differential_actual = (float)max_speed - (float)current_speed;
+ float speed_differential_maximum = (float)max_speed - (float)high_speed;
+ float factor_modification = speed_differential_actual / speed_differential_maximum;
+ speed_factor *= ((factor_modification * 0.15) + 0.8);
+ }
+
+ uint32 modified_power_from_steam = power_from_steam_with_gear * speed_factor;
+ return modified_power_from_steam + power_without_steam;
+}
+
int convoi_t::get_vehicle_at_length(uint16 length)
@@ -551,6 +676,9 @@ bool convoi_t::sync_step(long delta_t)
case INITIAL:
// jemand muß start aufrufen, damit der convoi von INITIAL
// nach ROUTING_1 geht, das kann nicht automatisch gehen
+
+ //someone must call start, so that convoi from INITIAL
+ //to ROUTING_1 goes, which cannot go automatically (Google)
break;
case FAHRPLANEINGABE:
@@ -606,9 +734,16 @@ bool convoi_t::sync_step(long delta_t)
}
// until all are moving or something went wrong (sp_hat==0)
if(sp_hat==0 || v_nr==anz_vehikel) {
- steps_driven = -1;
- state = DRIVING;
- return true;
+ // Attempted fix of depot squashing problem:
+ // but causes problems with signals.
+ //if (v_nr==anz_vehikel) {
+ steps_driven = -1;
+ //}
+ //else {
+ //}
+
+ state = DRIVING;
+ return true;
}
// now only the right numbers
for(int i=1; i<=v_nr; i++) {
@@ -622,9 +757,13 @@ bool convoi_t::sync_step(long delta_t)
next_wolke = 0;
for(int i=0; irauche();
+ fahr[i]->last_stop_pos = fahr[i]->get_pos().get_2d();
}
}
}
+
+ last_departure_time = welt->get_zeit_ms();
+
break; // LEAVING_DEPOT
case DRIVING:
@@ -640,7 +779,7 @@ bool convoi_t::sync_step(long delta_t)
}
// now move the rest (so all vehikel are moving synchroniously)
for(unsigned i=1; ifahre_basis(sp_hat);
+ fahr[i]->fahre_basis(sp_hat); //"cycle basis" (Google)
}
// maybe we have been stopped be something => avoid wide jumps
sp_soll = (sp_soll-sp_hat) & 0x0FFF;
@@ -675,6 +814,19 @@ bool convoi_t::sync_step(long delta_t)
break;
}
+#ifdef TEST_SPEED
+
+ speed_testing tmp;
+ tmp.ticks = welt->get_steps();
+ tmp.tile = fahr[0]->get_pos().get_2d();
+ if(ticks_per_tile.get_count() < 1 || ((tmp.tile.x != ticks_per_tile[0].tile.x) || (tmp.tile.y != ticks_per_tile[0].tile.y)))
+ {
+ ticks_per_tile.add_to_head(tmp);
+ }
+
+
+#endif
+
return true;
}
@@ -682,6 +834,7 @@ bool convoi_t::sync_step(long delta_t)
/**
* Berechne route von Start- zu Zielkoordinate
+ * "Compute route from starting to goal coordinate" (Babelfish)
* @author Hanjsörg Malthaner
*/
int convoi_t::drive_to(koord3d start, koord3d ziel)
@@ -702,6 +855,8 @@ int convoi_t::drive_to(koord3d start, koord3d ziel)
/**
* Ein Fahrzeug hat ein Problem erkannt und erzwingt die
* Berechnung einer neuen Route
+ *
+ * "A vehicle recognized and forces a problem the computation of a new route" (Babelfish)
* @author Hanjsörg Malthaner
*/
void convoi_t::suche_neue_route()
@@ -718,6 +873,7 @@ void convoi_t::suche_neue_route()
*/
void convoi_t::step()
{
+
// moved check to here, as this will apply the same update
// logic/constraints convois have for manual schedule manipulation
if (line_update_pending.is_bound()) {
@@ -730,6 +886,114 @@ void convoi_t::step()
switch(state) {
+ case INITIAL:
+
+ // If there is a pending replacement, just do it
+ if (get_replace() && replacing_vehicles.get_count()>0) {
+ const grund_t *gr = welt->lookup(home_depot);
+ depot_t *dep;
+ if ( gr && (dep=gr->get_depot()) ) {
+ bool keep_name=(anz_vehikel>0 && strcmp(get_name(),fahr[0]->get_besch()->get_name())!=0);
+ vector_tpl new_vehicles;
+
+ // Acquire the new one
+ ITERATE(replacing_vehicles,i)
+ {
+ vehikel_t* veh = NULL;
+ // First - check whether there are any of the required vehicles already
+ // in the convoy (free)
+ for(uint8 k = 0; k < anz_vehikel; k++)
+ {
+ if(fahr[k]->get_besch() == replacing_vehicles[i])
+ {
+ veh = remove_vehikel_bei(k);
+ //keep_vehicles.append_unique(k);
+ break;
+ }
+ }
+
+ // This part of the code is abandoned, as it causes problems: vehicles that have already been bought
+ // are added twice to the convoy, causing bizarre corruption issues.
+ /*if( veh == NULL)
+ {
+ //Second - check whether there are any of the required vehicles already
+ //in the depot (more or less free).
+ veh = dep->find_oldest_newest(replacing_vehicles[i], true);
+ }*/
+
+ if (veh == NULL)
+ {
+ // Third - check whether the vehicle can be upgraded (cheap)
+ for(uint16 j = 0; j < anz_vehikel; j ++)
+ {
+
+ for(uint8 c = 0; c < fahr[j]->get_besch()->get_upgrades_count(); c ++)
+ {
+ if(replacing_vehicles[i] == fahr[j]->get_besch()->get_upgrades(c))
+ {
+ veh = remove_vehikel_bei(j);
+ veh->set_besch(replacing_vehicles[i]);
+ dep->buy_vehicle(veh->get_besch(), true);
+ goto end_loop;
+ }
+ }
+ }
+end_loop:
+ if(veh == NULL)
+ {
+ // Fourth - if all else fails, buy from new (expensive).
+ veh = dep->buy_vehicle(replacing_vehicles[i], false);
+ }
+ }
+
+ //dep->append_vehicle(self, veh, false);
+
+ // This new method is needed to enable this method to iterate over
+ // the existing vehicles in the convoy while it is adding new vehicles.
+ // They must be added to temporary storage, and appended to the existing
+ // convoy at the end, after the existing convoy has been deleted.
+ new_vehicles.append(veh);
+
+ }
+
+ //First, delete the existing convoy
+ for(sint8 a = anz_vehikel-1; a >= 0; a--)
+ {
+ //Sell any vehicles not upgraded or kept.
+ besitzer_p->buche( fahr[a]->calc_restwert(), dep->get_pos().get_2d(), COST_NEW_VEHICLE );
+ besitzer_p->buche( -fahr[a]->calc_restwert(), COST_ASSETS );
+ delete fahr[a];
+ }
+ anz_vehikel = 0;
+ reset();
+
+ //Next, add all the new vehicles to the convoy in order.
+ ITERATE(new_vehicles,b)
+ {
+ dep->append_vehicle(self, new_vehicles[b], false);
+ }
+
+ if (!keep_name) {
+ set_name(fahr[0]->get_besch()->get_name());
+ }
+ set_replace(false);
+ replacing_vehicles.clear();
+ if (line.is_bound()) {
+ line->recalc_status();
+ if (line->get_replacing_convoys_count()==0) {
+ char buf[128];
+ sprintf(buf, translator::translate("Replacing\nvehicles of\n%-20s\ncompleted"), line->get_name());
+ welt->get_message()->add_message(buf, home_depot.get_2d(),message_t::convoi, PLAYER_FLAG|get_besitzer()->get_player_nr(), IMG_LEER);
+ }
+
+ }
+ if (autostart) {
+ dep->start_convoi(self);
+ }
+ }
+ }
+ break;
+
case LOADING:
laden();
break;
@@ -751,8 +1015,8 @@ void convoi_t::step()
}
// Hajo: now calculate a new route
drive_to(v->get_pos(), fpl->get_current_eintrag().pos);
- if(!route.empty()) {
- vorfahren();
+ if(!route.empty()) {
+ vorfahren(); //"Drive"
}
else {
state = NO_ROUTE;
@@ -846,9 +1110,10 @@ void convoi_t::step()
default: /* keeps compiler silent*/
break;
}
-}
+}
+
void convoi_t::neues_jahr()
{
@@ -856,6 +1121,58 @@ void convoi_t::neues_jahr()
}
+uint16 convoi_t::get_overcrowded() const
+{
+ uint16 overcrowded = 0;
+ for(uint8 i = 0; i < anz_vehikel; i ++)
+ {
+ overcrowded += fahr[i]->get_overcrowding();
+ }
+ return overcrowded;
+}
+
+uint8 convoi_t::get_comfort() const
+{
+ uint8 base_comfort = 0;
+ uint8 catering_level = get_catering_level(0);
+ for(uint8 i = 0; i < anz_vehikel; i ++)
+ {
+ base_comfort += fahr[i]->get_comfort();
+ }
+ if(anz_vehikel > 1)
+ {
+ // Avoid division if possible
+ base_comfort /= anz_vehikel;
+ }
+ //Else
+ switch(catering_level)
+ {
+ case 0:
+ return base_comfort;
+ break;
+
+ case 1:
+ return base_comfort + 5;
+ break;
+
+ case 2:
+ return base_comfort + 10;
+ break;
+
+ case 3:
+ return base_comfort + 16;
+ break;
+
+ case 4:
+ return base_comfort + 20;
+ break;
+
+ default:
+ case 5:
+ return base_comfort + 25;
+ break;
+ };
+}
void convoi_t::new_month()
{
@@ -872,6 +1189,13 @@ void convoi_t::new_month()
}
financial_history[0][j] = 0;
}
+
+ for(uint8 i = 0; i < MAX_CONVOI_COST; i ++)
+ {
+ rolling_average[i] = 0;
+ rolling_average_count[i] = 0;
+ }
+
// check for traffic jam
if(state==WAITING_FOR_CLEARANCE) {
state = WAITING_FOR_CLEARANCE_ONE_MONTH;
@@ -936,6 +1260,7 @@ convoi_t::betrete_depot(depot_t *dep)
// the sync list from inside sync_step()
welt->sync_remove(this);
state = INITIAL;
+ wait_lock = 0;
}
@@ -977,8 +1302,29 @@ void convoi_t::start()
// might have changed the vehicles in this car ...
line->recalc_catg_index();
}
- else {
+ else
+ {
+#ifdef NEW_PATHING
+
+ // New method - recalculate as necessary
+ ITERATE_PTR(fpl, j)
+ {
+ halthandle_t tmp_halt = haltestelle_t::get_halt(welt, fpl->eintrag[j].pos);
+ if(tmp_halt.is_bound())
+ {
+ tmp_halt->reschedule = true;
+ tmp_halt->force_paths_stale();
+ }
+ else
+ {
+ dbg->error("convoi_t::start()", "Halt in schedule does not exist");
+ }
+ }
+
+#else
+ // Old method - brute force
welt->set_schedule_counter();
+#endif
}
DBG_MESSAGE("convoi_t::start()","Convoi %s wechselt von INITIAL nach ROUTING_1", name_and_id);
@@ -1004,14 +1350,24 @@ void convoi_t::ziel_erreicht()
if(dp) {
// ok, we are entering a depot
char buf[128];
+ if(reversed)
+ {
+ //Always enter a depot facing forward
+ reversable = fahr[anz_vehikel - 1]->get_besch()->get_can_lead_from_rear() || (anz_vehikel == 1 && fahr[0]->get_besch()->is_bidirectional());
+ reverse_order(reversable);
+ }
// we still book the money for the trip; however, the frieght will be lost
- calc_gewinn();
+ //calc_gewinn();
+ last_departure_time = welt->get_zeit_ms();
akt_speed = 0;
- sprintf(buf, translator::translate("!1_DEPOT_REACHED"), get_name());
- welt->get_message()->add_message(buf, v->get_pos().get_2d(),message_t::convoi, PLAYER_FLAG|get_besitzer()->get_player_nr(), IMG_LEER);
+ if (!replace || !autostart) {
+ sprintf(buf, translator::translate("!1_DEPOT_REACHED"), get_name());
+ welt->get_message()->add_message(buf, v->get_pos().get_2d(),message_t::convoi, PLAYER_FLAG|get_besitzer()->get_player_nr(), IMG_LEER);
+ }
+ home_depot=v->get_pos();
betrete_depot(dp);
}
else {
@@ -1028,6 +1384,11 @@ void convoi_t::ziel_erreicht()
// Neither depot nor station: waypoint
fpl->advance();
state = ROUTING_1;
+ if(replace && depot_when_empty && has_no_cargo()) {
+ depot_when_empty=false;
+ no_load=false;
+ go_to_depot(false);
+ }
}
}
wait_lock = 0;
@@ -1037,6 +1398,7 @@ void convoi_t::ziel_erreicht()
/**
* Wartet bis Fahrzeug 0 freie Fahrt meldet
+ * Wait until the vehicle returns 0 free ride (Google)
* @author Hj. Malthaner
*/
void convoi_t::warten_bis_weg_frei(int restart_speed)
@@ -1047,6 +1409,7 @@ void convoi_t::warten_bis_weg_frei(int restart_speed)
}
if(restart_speed>=0) {
// langsam anfahren
+ // "slow start" (Google)
akt_speed = restart_speed;
}
}
@@ -1060,7 +1423,8 @@ DBG_MESSAGE("convoi_t::add_vehikel()","at pos %i of %i totals.",anz_vehikel,max_
// extend array if requested (only needed for trains)
if(anz_vehikel == max_vehicle) {
DBG_MESSAGE("convoi_t::add_vehikel()","extend array_tpl to %i totals.",max_rail_vehicle);
- fahr.resize(max_rail_vehicle, NULL);
+ //fahr.resize(max_rail_vehicle, NULL);
+ fahr.resize(max_rail_vehicle);
}
// now append
if (anz_vehikel < fahr.get_size()) {
@@ -1081,7 +1445,12 @@ DBG_MESSAGE("convoi_t::add_vehikel()","extend array_tpl to %i totals.",max_rail_
is_electric |= info->get_engine_type()==vehikel_besch_t::electric;
}
sum_leistung += info->get_leistung();
- sum_gear_und_leistung += info->get_leistung()*info->get_gear();
+ if(info->get_engine_type() == vehikel_besch_t::steam)
+ {
+ power_from_steam += info->get_leistung();
+ power_from_steam_with_gear += info->get_leistung() * info->get_gear() * welt->get_einstellungen()->get_global_power_factor();
+ }
+ sum_gear_und_leistung += info->get_leistung() * info->get_gear() * welt->get_einstellungen()->get_global_power_factor();
sum_gewicht += info->get_gewicht();
min_top_speed = min( min_top_speed, kmh_to_speed( v->get_besch()->get_geschw() ) );
sum_gesamtgewicht = sum_gewicht;
@@ -1099,6 +1468,9 @@ DBG_MESSAGE("convoi_t::add_vehikel()","extend array_tpl to %i totals.",max_rail_
// der convoi hat jetzt ein neues ende
set_erstes_letztes();
+ heaviest_vehicle = calc_heaviest_vehicle();
+ longest_loading_time = calc_longest_loading_time();
+
DBG_MESSAGE("convoi_t::add_vehikel()","now %i of %i total vehikels.",anz_vehikel,max_vehicle);
return true;
}
@@ -1122,7 +1494,12 @@ convoi_t::remove_vehikel_bei(uint16 i)
const vehikel_besch_t *info = v->get_besch();
sum_leistung -= info->get_leistung();
- sum_gear_und_leistung -= info->get_leistung()*info->get_gear();
+ if(info->get_engine_type() == vehikel_besch_t::steam)
+ {
+ power_from_steam -= info->get_leistung();
+ power_from_steam_with_gear -= info->get_leistung() * info->get_gear() * welt->get_einstellungen()->get_global_power_factor();
+ }
+ sum_gear_und_leistung -= info->get_leistung() * info->get_gear() * welt->get_einstellungen()->get_global_power_factor();
sum_gewicht -= info->get_gewicht();
}
sum_gesamtgewicht = sum_gewicht;
@@ -1156,13 +1533,18 @@ convoi_t::remove_vehikel_bei(uint16 i)
}
}
}
+
+ heaviest_vehicle = calc_heaviest_vehicle();
+ longest_loading_time = calc_longest_loading_time();
+
return v;
}
void
-convoi_t::set_erstes_letztes()
+convoi_t::set_erstes_letztes() //"set only last" (Google)
{
// anz_vehikel muss korrekt init sein
+ // "anz vehicle must be correctly INIT" (Babelfish)
if(anz_vehikel>0) {
fahr[0]->set_erstes(true);
for(unsigned i=1; ieintrag[j].pos);
+ if(tmp_halt.is_bound())
+ {
+ tmp_halt->reschedule = true;
+ tmp_halt->force_paths_stale();
+ }
+ }
+
+ ITERATE_PTR(f, k)
+ {
+ halthandle_t tmp_halt = haltestelle_t::get_halt(welt, fpl->eintrag[k].pos);
+ tmp_halt->reschedule = true;
+ tmp_halt->force_paths_stale();
+ }
+ }
+#endif
+
// happens to be identical?
- if(fpl!=f) {
+ if(fpl != f)
+ {
// destroy a possibly open schedule window
- if(fpl && !fpl->ist_abgeschlossen()) {
+ if(fpl && !fpl->ist_abgeschlossen())
+ {
+ //"is completed" (Google)
destroy_win((long)fpl);
delete fpl;
}
@@ -1200,23 +1609,29 @@ bool convoi_t::set_schedule(schedule_t * f)
}
// remove wrong freight
- for(unsigned i=0; iremove_stale_freight();
}
// ok, now we have a schedule
- if(old_state!=INITIAL) {
+ if(old_state != INITIAL)
+ {
state = FAHRPLANEINGABE;
- if( !line.is_bound() ) {
+
+#ifndef NEW_PATHING
+ // Old method - brute force
+ if( !line.is_bound() )
+ {
// asynchronous recalculation of routes
welt->set_schedule_counter();
}
+#endif
}
return true;
}
-
schedule_t *convoi_t::create_schedule()
{
if(fpl == NULL) {
@@ -1300,7 +1715,7 @@ convoi_t::can_go_alte_richtung()
//DBG_MESSAGE("convoi_t::go_alte_richtung()","alte=%d, neu_rwr=%d",alte_richtung,neue_richtung_rwr);
// we continue our journey; however later cars need also a correct route entry
- // eventually we need to add their positions to the convois route
+ // eventually we need to add their positions to the convoi's route
koord3d pos = fahr[0]->get_pos();
assert(pos==route.position_bei(0));
if(welt->lookup(pos)->get_depot()) {
@@ -1363,12 +1778,14 @@ convoi_t::can_go_alte_richtung()
void
-convoi_t::vorfahren()
+convoi_t::vorfahren() //"move forward" (Babelfish)
{
// Hajo: init speed settings
sp_soll = 0;
set_tiles_overtaking( 0 );
+ uint16 reverse_delay = 0;
+
set_akt_speed_soll( vehikel_t::SPEED_UNLIMITED );
koord3d k0 = route.position_bei(0);
@@ -1412,7 +1829,50 @@ convoi_t::vorfahren()
}
else {
// still leaving depot (steps_driven!=0) or going in other direction or misalignment?
- if( steps_driven>0 || !can_go_alte_richtung() ) {
+ if( steps_driven>0 || !can_go_alte_richtung() )
+ {
+
+ //Convoy needs to reverse
+ //@author: jamespetts
+ if(!can_go_alte_richtung())
+ {
+ switch(fahr[0]->get_waytype())
+ {
+ case road_wt:
+ case air_wt:
+ //Road vehicles and aircraft do not need to change direction
+ //Canal barges *may* change direction, so water is omitted.
+ break;
+
+ default:
+ if(reversed)
+ {
+ reversable = fahr[0]->get_besch()->get_can_lead_from_rear() || (anz_vehikel == 1 && fahr[0]->get_besch()->is_bidirectional());
+ }
+ else
+ {
+ reversable = fahr[anz_vehikel - 1]->get_besch()->get_can_lead_from_rear() || (anz_vehikel == 1 && fahr[0]->get_besch()->is_bidirectional());
+ }
+
+ if(reversable)
+ {
+ //Multiple unit or similar: quick reverse
+ reverse_delay = welt->get_einstellungen()->get_unit_reverse_time();
+ }
+ else if(fahr[0]->get_besch()->is_bidirectional())
+ {
+ //Loco hauled, no turntable.
+ reverse_delay = welt->get_einstellungen()->get_hauled_reverse_time();
+ }
+ else
+ {
+ //Locomotive needs turntable: slow reverse
+ reverse_delay = welt->get_einstellungen()->get_turntable_reverse_time();
+ }
+
+ reverse_order(reversable);
+ }
+ }
// since start may have been changed
k0 = route.position_bei(0);
@@ -1424,7 +1884,7 @@ convoi_t::vorfahren()
grund_t* gr = welt->lookup(v->get_pos());
if(gr) {
v->mark_image_dirty( v->get_bild(), v->get_hoff() );
- v->verlasse_feld();
+ v->verlasse_feld(); //"leave field" (Google)
// eventually unreserve this
schiene_t * sch0 = dynamic_cast( gr->get_weg(fahr[i]->get_waytype()) );
if(sch0) {
@@ -1440,34 +1900,63 @@ convoi_t::vorfahren()
gr=welt->lookup(v->get_pos());
if(gr) {
v->set_pos(k0);
- v->betrete_feld();
+ v->betrete_feld(); //"enter field" (Google)
}
}
// move one train length to the start position ...
int train_length = 0;
- for(unsigned i=0; iget_besch()->get_length(); // this give the length in 1/TILE_STEPS of a full tile
}
// in north/west direction, we leave the vehicle away to start as much back as possible
- ribi_t::ribi neue_richtung = fahr[0]->get_fahrtrichtung();
- if(neue_richtung==ribi_t::sued || neue_richtung==ribi_t::ost) {
+ ribi_t::ribi neue_richtung = fahr[0]->get_direction_of_travel();
+ if(neue_richtung==ribi_t::sued || neue_richtung==ribi_t::ost)
+ {
train_length += fahr[anz_vehikel-1]->get_besch()->get_length();
}
- else {
+ else
+ {
train_length += 1;
}
train_length = max(1,train_length);
// now advance all convoi until it is completely on the track
fahr[0]->set_erstes(false); // switches off signal checks ...
- for(unsigned i=0; iis_reversed()))
+ {
+ //train_length -= fahr[0]->get_besch()->get_length();
+ train_length = 0;
+ for(sint8 i = anz_vehikel - 1; i >= 0; i--)
+ {
+ vehikel_t* v = fahr[i];
+ v->darf_rauchen(false);
+ fahr[i]->fahre_basis( ((TILE_STEPS)*train_length)<<12 ); //"fahre" = "go" (Google)
+ train_length += (v->get_besch()->get_length()); // this give the length in 1/TILE_STEPS of a full tile => all cars closely coupled!
+ v->darf_rauchen(true);
+ }
+ train_length -= fahr[anz_vehikel - 1]->get_besch()->get_length();
+ }
- v->darf_rauchen(false);
- fahr[i]->fahre_basis( ((TILE_STEPS)*train_length)<<12 );
- train_length -= v->get_besch()->get_length(); // this give the length in 1/TILE_STEPS of a full tile => all cars closely coupled!
- v->darf_rauchen(true);
+ else
+ {
+ //if(!reversable && fahr[0]->get_besch()->is_bidirectional())
+ //{
+ // //This can sometimes relieve excess setting back on reversing.
+ // //Unfortunately, it seems to produce bizarre results on occasion.
+ // train_length -= (fahr[0]->get_besch()->get_length()) / 2;
+ // train_length = train_length > 0 ? train_length : 0;
+ //}
+ for(sint8 i = 0; i < anz_vehikel; i++)
+ {
+ vehikel_t* v = fahr[i];
+ v->darf_rauchen(false);
+ fahr[i]->fahre_basis( ((TILE_STEPS)*train_length)<<12 ); //"fahre" = "go" (Google)
+ train_length -= (v->get_besch()->get_length()); // this give the length in 1/TILE_STEPS of a full tile => all cars closely coupled!
+ v->darf_rauchen(true);
+ }
+
}
fahr[0]->set_erstes(true);
}
@@ -1480,7 +1969,8 @@ convoi_t::vorfahren()
if(haltestelle_t::get_halt(welt,k0).is_bound()) {
fahr[0]->play_sound();
}
- wait_lock = 0;
+ //wait_lock = 0;
+ wait_lock = reverse_delay;
state = DRIVING;
}
}
@@ -1503,6 +1993,77 @@ convoi_t::vorfahren()
INT_CHECK("simconvoi 711");
}
+void
+convoi_t::reverse_order(bool rev)
+{
+ // Code snippet obtained and adapted from:
+ // http://www.cprogramming.com/snippets/show.php?tip=15&count=30&page=0
+ // by John Shao (public domain work)
+
+ uint8 a = 0;
+ vehikel_t* reverse;
+ uint8 b = anz_vehikel;
+
+ if(rev)
+ {
+ fahr[0]->set_erstes(false);
+ }
+ else
+ {
+ if(!fahr[anz_vehikel - 1]->get_besch()->is_bidirectional())
+ {
+ //Do not change the order at all if the last vehicle is not bidirectional
+ return;
+ }
+
+ a++;
+ a += fahr[0]->get_besch()->get_nachfolger_count();
+ for(uint8 i = 1; i < anz_vehikel; i++)
+ {
+ if(fahr[i]->get_besch()->get_leistung() > 0)
+ {
+ a++;
+ }
+ }
+ }
+
+ fahr[anz_vehikel - 1]->set_letztes(false);
+
+ for(a; a<--b; a++) //increment a and decrement b until they meet each other
+ {
+ reverse = fahr[a]; //put what's in a into swap space
+ fahr[a] = fahr[b]; //put what's in b into a
+ fahr[b] = reverse; //put what's in the swap (a) into b
+ }
+
+ if(!rev)
+ {
+ fahr[0]->set_erstes(true);
+ }
+
+ fahr[anz_vehikel - 1]->set_letztes(true);
+
+ if(reversed)
+ {
+ reversed = false;
+ for(uint8 i = 0; i < anz_vehikel; i ++)
+ {
+ fahr[i]->set_reversed(false);
+ }
+ }
+ else
+ {
+ reversed = true;
+ for(uint8 i = 0; i < anz_vehikel; i ++)
+ {
+ fahr[i]->set_reversed(true);
+ }
+ }
+}
+
+
+
+
void
convoi_t::rdwr(loadsave_t *file)
@@ -1540,7 +2101,7 @@ convoi_t::rdwr(loadsave_t *file)
}
file->rdwr_long(wait_lock, " ");
- // some versions may produce broken safegames apparently
+ // some versions may produce broken savegames apparently
if(wait_lock > 60000) {
dbg->warning("convoi_t::sync_prepre()","Convoi %d: wait lock out of bounds: wait_lock = %d, setting to 60000",self.get_id(), wait_lock);
wait_lock = 60000;
@@ -1651,7 +2212,12 @@ convoi_t::rdwr(loadsave_t *file)
// info
if(info) {
sum_leistung += info->get_leistung();
- sum_gear_und_leistung += info->get_leistung()*info->get_gear();
+ if(info->get_engine_type() == vehikel_besch_t::steam)
+ {
+ power_from_steam += info->get_leistung();
+ power_from_steam_with_gear += info->get_leistung() * info->get_gear() * welt->get_einstellungen()->get_global_power_factor();
+ }
+ sum_gear_und_leistung += info->get_leistung() * info->get_gear() * welt->get_einstellungen()->get_global_power_factor();
sum_gewicht += info->get_gewicht();
is_electric |= info->get_engine_type()==vehikel_besch_t::electric;
}
@@ -1678,7 +2244,7 @@ convoi_t::rdwr(loadsave_t *file)
}
state = INITIAL;
}
- // add to blockstrecke
+ // add to blockstrecke "block stretch" (Google). Possibly "block section"?
if(v->get_waytype()==track_wt || v->get_waytype()==monorail_wt || v->get_waytype()==maglev_wt || v->get_waytype()==narrowgauge_wt) {
schiene_t* sch = (schiene_t*)gr->get_weg(v->get_waytype());
if(sch) {
@@ -1730,24 +2296,59 @@ convoi_t::rdwr(loadsave_t *file)
// Hajo: since sp_ist became obsolete, sp_soll is used modulo 65536
sp_soll &= 65535;
- if(file->get_version()<=88003) {
+ if(file->get_version()<=88003)
+ {
// load statistics
int j;
- for (j = 0; j<3; j++) {
- for (int k = MAX_MONTHS-1; k>=0; k--) {
+ for (j = 0; j < 3; j++)
+ {
+ for (int k = MAX_MONTHS-1; k >= 0; k--)
+ {
+ if((j == CONVOI_AVERAGE_SPEED || j == CONVOI_COMFORT) && file->get_experimental_version() <= 1)
+ {
+ // Versions of Experimental saves with 1 and below
+ // did not have settings for average speed or comfort.
+ // Thus, this value must be skipped properly to
+ // assign the values.
+ financial_history[k][j] = 0;
+ continue;
+ }
file->rdwr_longlong(financial_history[k][j], " ");
}
}
- for (j = 2; j<5; j++) {
- for (int k = MAX_MONTHS-1; k>=0; k--) {
+ for (j = 2; j < 5; j++)
+ {
+ for (int k = MAX_MONTHS-1; k >= 0; k--)
+ {
+ if((j == CONVOI_AVERAGE_SPEED || j == CONVOI_COMFORT) && file->get_experimental_version() <= 1)
+ {
+ // Versions of Experimental saves with 1 and below
+ // did not have settings for average speed or comfort.
+ // Thus, this value must be skipped properly to
+ // assign the values.
+ financial_history[k][j] = 0;
+ continue;
+ }
file->rdwr_longlong(financial_history[k][j], " ");
}
}
}
- else {
+ else
+ {
// load statistics
- for (int j = 0; j=0; k--) {
+ for (int j = 0; j < MAX_CONVOI_COST; j++)
+ {
+ for (int k = MAX_MONTHS-1; k >= 0; k--)
+ {
+ if((j == CONVOI_AVERAGE_SPEED || j == CONVOI_COMFORT) && file->get_experimental_version() <= 1)
+ {
+ // Versions of Experimental saves with 1 and below
+ // did not have settings for average speed or comfort.
+ // Thus, this value must be skipped properly to
+ // assign the values.
+ financial_history[k][j] = 0;
+ continue;
+ }
file->rdwr_longlong(financial_history[k][j], " ");
}
}
@@ -1755,9 +2356,11 @@ convoi_t::rdwr(loadsave_t *file)
// since it was saved as an signed int
// we recalc it anyhow
- if(file->is_loading()) {
- jahresgewinn = 0;
- for(int i=welt->get_last_month()%12; i>=0; i-- ) {
+ if(file->is_loading())
+ {
+ jahresgewinn = 0; //"annual profit" (Babelfish)
+ for(int i=welt->get_last_month()%12; i>=0; i-- )
+ {
jahresgewinn += financial_history[i][CONVOI_PROFIT];
}
}
@@ -1790,19 +2393,43 @@ convoi_t::rdwr(loadsave_t *file)
}
// waiting time left ...
- if(file->get_version()>=99017) {
- if(file->is_saving()) {
- if(go_on_ticks==WAIT_INFINITE) {
- file->rdwr_long( go_on_ticks, "dt" );
+ if(file->get_version()>=99017)
+ {
+ if(file->is_saving())
+ {
+ if(go_on_ticks==WAIT_INFINITE)
+ {
+ if(file->get_experimental_version() <= 1)
+ {
+ uint32 old_go_on_ticks = (uint32)go_on_ticks;
+ file->rdwr_long( old_go_on_ticks, "dt" );
+ }
+ else
+ {
+ file->rdwr_longlong(go_on_ticks, "dt" );
+ }
}
- else {
- uint32 diff_ticks = welt->get_zeit_ms()>go_on_ticks ? 0 : go_on_ticks-welt->get_zeit_ms();
- file->rdwr_long( diff_ticks, "dt" );
+ else
+ {
+ sint64 diff_ticks= welt->get_zeit_ms()>go_on_ticks ? 0 : go_on_ticks-welt->get_zeit_ms();
+ file->rdwr_longlong(diff_ticks, "dt" );
}
}
- else {
- file->rdwr_long( go_on_ticks, "dt" );
- if(go_on_ticks!=WAIT_INFINITE) {
+ else
+ {
+ if(file->get_experimental_version() <= 1)
+ {
+ uint32 old_go_on_ticks = (uint32)go_on_ticks;
+ file->rdwr_long( old_go_on_ticks, "dt" );
+ go_on_ticks = old_go_on_ticks;
+ }
+ else
+ {
+ file->rdwr_longlong(go_on_ticks, "dt" );
+ }
+
+ if(go_on_ticks!=WAIT_INFINITE)
+ {
go_on_ticks += welt->get_zeit_ms();
}
}
@@ -1823,6 +2450,9 @@ convoi_t::rdwr(loadsave_t *file)
file->rdwr_byte( tiles_overtaking, "o" );
set_tiles_overtaking( tiles_overtaking );
}
+
+
+
// no_load, withdraw
if(file->get_version()<102001) {
no_load = false;
@@ -1832,6 +2462,74 @@ convoi_t::rdwr(loadsave_t *file)
file->rdwr_bool( no_load, "" );
file->rdwr_bool( withdraw, "" );
}
+
+ // Simutrans-Experimental specific parameters.
+ // Must *always* go after standard parameters.
+
+ heaviest_vehicle = calc_heaviest_vehicle();
+ longest_loading_time = calc_longest_loading_time();
+
+ if(file->get_experimental_version() >= 1)
+ {
+ file->rdwr_bool(reversed, "");
+
+ //Replacing settings
+ file->rdwr_bool(replace, "");
+ file->rdwr_bool(autostart, "");
+ file->rdwr_bool(depot_when_empty, "");
+
+ uint16 replacing_vehicles_count;
+
+ if(file->is_saving())
+ {
+ replacing_vehicles_count = replacing_vehicles.get_count();
+ file->rdwr_short(replacing_vehicles_count, "");
+ ITERATE(replacing_vehicles, i)
+ {
+ const char *s = replacing_vehicles[i]->get_name();
+ file->rdwr_str(s);
+ }
+ }
+ else
+ {
+
+ file->rdwr_short(replacing_vehicles_count, "");
+ for(uint16 i = 0; i < replacing_vehicles_count; i ++)
+ {
+ char vehicle_name[256];
+ file->rdwr_str(vehicle_name, 256);
+ const vehikel_besch_t* besch = vehikelbauer_t::get_info(vehicle_name);
+ if(besch == NULL)
+ {
+ besch = vehikelbauer_t::get_info(translator::compatibility_name(vehicle_name));
+ }
+ if(besch == NULL)
+ {
+ dbg->warning("convoi_t::rdwr()","no vehicle pak for '%s' search for something similar", vehicle_name);
+ }
+ else
+ {
+ replacing_vehicles.append(besch);
+ }
+ }
+ }
+ }
+ if(file->get_experimental_version() >= 2)
+ {
+ file->rdwr_longlong(last_departure_time, "");
+ for(uint8 i = 0; i < MAX_CONVOI_COST; i ++)
+ {
+ file->rdwr_long(rolling_average[i], "");
+ file->rdwr_short(rolling_average_count[i], "");
+ }
+ }
+ else
+ {
+ // For loading older games, assume that the convoy
+ // left twenty seconds ago, to avoid anomalies when
+ // measuring average speed.
+ last_departure_time = welt->get_zeit_ms() - 20000;
+ }
}
@@ -1884,7 +2582,7 @@ void convoi_t::set_sortby(uint8 sort_order)
-//chaches the last info; resorts only when needed
+//caches the last info; resorts only when needed
void convoi_t::get_freight_info(cbuffer_t & buf)
{
if(freight_info_resort) {
@@ -1910,14 +2608,26 @@ void convoi_t::get_freight_info(cbuffer_t & buf)
slist_iterator_tpl iter_vehicle_ware(v->get_fracht());
while(iter_vehicle_ware.next()) {
ware_t ware = iter_vehicle_ware.get_current();
- for(unsigned i=0; icapacity;
- for(i=0; i0 && i!=warenbauer_t::INDEX_NONE) {
+ for(i=0; i0 && i!=warenbauer_t::INDEX_NONE)
+ {
ware_t ware(warenbauer_t::get_info(i));
ware.menge = max_loaded_waren[i];
if(ware.get_catg()==0) {
capacity.append( ware );
- } else {
+ }
+ else
+ {
// append to category?
slist_tpl::iterator j = capacity.begin();
slist_tpl::iterator end = capacity.end();
while (j != end && j->get_catg() < ware.get_catg()) ++j;
if (j != end && j->get_catg() == ware.get_catg()) {
j->menge += max_loaded_waren[i];
- } else {
+ }
+ else
+ {
// not yet there
capacity.insert(j, ware);
}
@@ -1984,7 +2700,8 @@ void convoi_t::open_schedule_window()
if(state==DRIVING) {
// book the current value of goods
- calc_gewinn();
+ //calc_gewinn();
+ last_departure_time = welt->get_zeit_ms();
}
akt_speed = 0; // stop the train ...
@@ -2000,6 +2717,9 @@ void convoi_t::open_schedule_window()
/* Fahrzeuge passen oft nur in bestimmten kombinationen
* die Beschraenkungen werden hier geprueft, die für die Nachfolger von
* vor gelten - daher muß vor != NULL sein..
+ * TRANSLATION: (Google)
+ * Vehicles are often triggered only in certain combinations restrictions are approved,
+ * the successor to continue to apply - therefore must be done before != NULL.
*/
bool
convoi_t::pruefe_nachfolger(const vehikel_besch_t *vor, const vehikel_besch_t *hinter)
@@ -2019,6 +2739,7 @@ convoi_t::pruefe_nachfolger(const vehikel_besch_t *vor, const vehikel_besch_t *h
if(hinter == soll) {
// Diese Beschränkung erlaubt unseren Nachfolger
+ // This restriction allows our successors (Google translations)
return true;
}
}
@@ -2030,14 +2751,19 @@ convoi_t::pruefe_nachfolger(const vehikel_besch_t *vor, const vehikel_besch_t *h
/* Fahrzeuge passen oft nur in bestimmten kombinationen
* die Beschraenkungen werden hier geprueft, die für die Vorgänger von
* hinter gelten - daher muß hinter != NULL sein.
+ *
+ * Vehicles are often only fit in certain combinations,
+ * the restrictions are approved, the predecessor of
+ * behind apply - must be behind! = NULL. (Google)
*/
bool
convoi_t::pruefe_vorgaenger(const vehikel_besch_t *vor, const vehikel_besch_t *hinter)
{
- const vehikel_besch_t *soll;
+ const vehikel_besch_t *soll; //"Soll" = should (Google)
if(!hinter->get_vorgaenger_count()) {
// Alle Vorgänger erlaubt
+ // "All previous permits" (Google).
return true;
}
for(int i=0; i < hinter->get_vorgaenger_count(); i++) {
@@ -2049,6 +2775,7 @@ convoi_t::pruefe_vorgaenger(const vehikel_besch_t *vor, const vehikel_besch_t *h
if(vor == soll) {
// Diese Beschränkung erlaubt unseren Vorgänger
+ // This restriction allows our predecessors (Google)
return true;
}
}
@@ -2060,7 +2787,7 @@ convoi_t::pruefe_vorgaenger(const vehikel_besch_t *vor, const vehikel_besch_t *h
bool
-convoi_t::pruefe_alle()
+convoi_t::pruefe_alle() //"examine all" (Babelfish)
{
bool ok = (anz_vehikel == 0 || pruefe_vorgaenger(NULL, fahr[0]->get_besch()));
unsigned i;
@@ -2086,33 +2813,65 @@ convoi_t::pruefe_alle()
*
* V.Meyer: ladegrad is now stored in the object (not returned)
*/
-void convoi_t::laden()
+void convoi_t::laden() //"load" (Babelfish)
{
- if(state == FAHRPLANEINGABE) {
+ //Calculate average speed
+ //@author: jamespetts
+ const double journey_time = (welt->get_zeit_ms() - last_departure_time) / 4096.0;
+ const uint32 journey_distance = accurate_distance(fahr[0]->get_pos().get_2d(), fahr[0]->last_stop_pos);
+ //const uint16 TEST_speed = (1 / journey_time) * 20;
+ //const uint16 TEST_minutes = (((float)1 / TEST_speed) * welt->get_einstellungen()->get_journey_time_multiplier() * 60);
+ const uint16 average_speed = (journey_distance / journey_time) * 20;
+ //const uint16 TEST_actual_minutes = (((float)journey_distance / average_speed) * welt->get_einstellungen()->get_journey_time_multiplier() * 60);
+ book(average_speed, CONVOI_AVERAGE_SPEED);
+ last_departure_time = welt->get_zeit_ms();
+
+ // Recalculate comfort
+ book(get_comfort(), CONVOI_COMFORT);
+
+ for(uint8 i = 0; i < anz_vehikel; i++)
+ {
+ // Accumulate distance
+ slist_iterator_tpl iter_cargo(fahr[i]->get_fracht());
+ while(iter_cargo.next())
+ {
+ iter_cargo.access_current().add_distance(journey_distance);
+ }
+ }
+
+ if(state == FAHRPLANEINGABE) //"ENTER SCHEDULE" (Google)
+ {
return;
}
halthandle_t halt = haltestelle_t::get_halt(welt, fpl->get_current_eintrag().pos);
// eigene haltestelle ?
- if (halt.is_bound()) {
- const koord k = fpl->get_current_eintrag().pos.get_2d();
- const spieler_t* owner = halt->get_besitzer();
- if( owner == get_besitzer() || owner == welt->get_spieler(1) ) {
+ // "own stop?" (Babelfish)
+ if (halt.is_bound())
+ {
+ const koord k = fpl->get_current_eintrag().pos.get_2d(); //"eintrag" = "entry" (Google)
+ const spieler_t* owner = halt->get_besitzer(); //"get owner" (Google)
+ if( owner == get_besitzer() || owner == welt->get_spieler(1) )
+ {
// loading/unloading ...
hat_gehalten(k, halt);
}
}
- if(go_on_ticks==WAIT_INFINITE && fpl->get_current_eintrag().waiting_time_shift>0) {
+ if(go_on_ticks==WAIT_INFINITE && fpl->get_current_eintrag().waiting_time_shift>0)
+ {
go_on_ticks = welt->get_zeit_ms() + (welt->ticks_per_tag >> (16-fpl->get_current_eintrag().waiting_time_shift));
}
INT_CHECK("simconvoi 1077");
// Nun wurde ein/ausgeladen werden
- if(loading_level>=loading_limit || no_load || welt->get_zeit_ms()>go_on_ticks) {
+ // "Now, a / unloaded" (Google)
+ if(loading_level >= loading_limit || no_load || welt->get_zeit_ms()>go_on_ticks)
+ {
- if(withdraw && loading_level==0) {
+ if(withdraw && has_no_cargo())
+ {
// destroy when empty
besitzer_p->buche( calc_restwert(), COST_NEW_VEHICLE );
besitzer_p->buche( -calc_restwert(), COST_ASSETS );
@@ -2122,7 +2881,8 @@ void convoi_t::laden()
}
// add available capacity after loading(!) to statistics
- for (unsigned i = 0; iget_fracht_max()-get_vehikel(i)->get_fracht_menge(), CONVOI_CAPACITY);
}
@@ -2130,8 +2890,10 @@ void convoi_t::laden()
fpl->advance();
state = ROUTING_1;
}
+
// This is the minimum time it takes for loading
- wait_lock = WTT_LOADING;
+ //wait_lock = WTT_LOADING;
+ wait_lock = longest_loading_time;
}
@@ -2139,13 +2901,14 @@ void convoi_t::laden()
* calculate income for last hop
* @author Hj. Malthaner
*/
-void convoi_t::calc_gewinn()
+/*void convoi_t::calc_gewinn()
{
sint64 gewinn = 0;
for(unsigned i=0; icalc_gewinn(v->last_stop_pos, v->get_pos().get_2d() );
+ convoi_t *tmp = this;
+ gewinn += v->calc_gewinn(v->last_stop_pos, v->get_pos().get_2d(), tmp );
v->last_stop_pos = v->get_pos().get_2d();
}
@@ -2156,41 +2919,388 @@ void convoi_t::calc_gewinn()
book(gewinn, CONVOI_PROFIT);
book(gewinn, CONVOI_REVENUE);
}
+}*/
+
+
+sint64 convoi_t::calc_revenue(ware_t& ware)
+{
+ float average_speed;
+
+ if(!line.is_bound())
+ {
+ // No line - must use convoy
+ if(financial_history[1][CONVOI_AVERAGE_SPEED] < 1)
+ {
+ average_speed = financial_history[0][CONVOI_AVERAGE_SPEED];
+ }
+ else
+ {
+ average_speed = financial_history[1][CONVOI_AVERAGE_SPEED];
+ }
+ }
+
+ else
+ {
+ if(line->get_finance_history(1, LINE_AVERAGE_SPEED) < 1)
+ {
+ average_speed = line->get_finance_history(0, LINE_AVERAGE_SPEED);
+ }
+ else
+ {
+ average_speed = line->get_finance_history(1, LINE_AVERAGE_SPEED);
+ }
+ }
+
+ // Cannot not charge for journey if the journey distance is more than a certain proportion of the straight line distance.
+ // This eliminates the possibility of cheating by building circuitous routes, or the need to prevent that by always using
+ // the straight line distance, which makes the game difficult and unrealistic.
+ // If the origin has been deleted since the packet departed, then the best that we can do is guess by
+ // trebling the distance to the last stop.
+ const uint32 max_distance = ware.get_origin().is_bound() ? accurate_distance(ware.get_origin()->get_basis_pos(), fahr[0]->get_pos().get_2d()) * 2.2 : 3 * accurate_distance(last_stop_pos.get_2d(), fahr[0]->get_pos().get_2d());
+ const uint32 distance = ware.get_accumulated_distance();
+ const uint32 revenue_distance = distance < max_distance ? distance : max_distance;
+
+ ware.reset_accumulated_distance();
+
+ //Multiply by a factor (default: 0.3) to ensure that it fits the scale properly. Journey times can easily appear too long.
+ uint16 journey_minutes = (((float)distance / average_speed) * welt->get_einstellungen()->get_journey_time_multiplier() * 60);
+
+ const ware_besch_t* goods = ware.get_besch();
+ const uint16 price = goods->get_preis();
+ const sint32 min_price = price << 7;
+ const uint16 speed_bonus_rating = calc_adjusted_speed_bonus(goods->get_speed_bonus(), distance);
+ const sint32 ref_speed = welt->get_average_speed( fahr[0]->get_besch()->get_waytype() );
+ const sint32 speed_base = (100 * average_speed) / ref_speed - 100;
+ const sint32 base_bonus = (price * (1000 + speed_base * speed_bonus_rating));
+ const sint64 revenue = (sint64)(min_price > base_bonus ? min_price : base_bonus) * (sint64)revenue_distance * (sint64)ware.menge;
+ sint64 final_revenue = revenue;
+
+ const float happy_ratio = ware.get_origin().is_bound() ? ware.get_origin()->get_unhappy_proportion(1) : 1;
+ if(speed_bonus_rating > 0 && happy_ratio > 0)
+ {
+ // Reduce revenue if the origin stop is crowded, if speed is important for the cargo.
+ sint64 tmp = ((float)speed_bonus_rating / 100.0) * revenue;
+ tmp *= (happy_ratio * 2);
+ final_revenue -= tmp;
+ }
+
+ if(ware.is_passenger())
+ {
+ //Passengers care about their comfort
+ const uint8 tolerable_comfort = calc_tolerable_comfort(journey_minutes);
+ uint8 comfort = 100;
+ if(line.is_bound())
+ {
+ if(line->get_finance_history(1, LINE_COMFORT) < 1)
+ {
+ comfort = line->get_finance_history(0, LINE_COMFORT);
+ }
+ else
+ {
+ comfort = line->get_finance_history(1, LINE_COMFORT);
+ }
+ }
+ else
+ {
+ // No line - must use convoy
+ if(financial_history[1][CONVOI_COMFORT] < 1)
+ {
+ comfort = financial_history[0][CONVOI_COMFORT];
+ }
+ else
+ {
+ comfort = financial_history[1][CONVOI_COMFORT];
+ }
+ }
+
+ if(comfort > tolerable_comfort)
+ {
+ // Apply luxury bonus
+ const uint8 max_differential = welt->get_einstellungen()->get_max_luxury_bonus_differential();
+ const uint8 differential = comfort - tolerable_comfort;
+ const float multiplier = welt->get_einstellungen()->get_max_luxury_bonus();
+ if(differential >= max_differential)
+ {
+ final_revenue += (revenue * multiplier);
+ }
+ else
+ {
+ const float proportion = (float)differential / (float)max_differential;
+ final_revenue += revenue * (multiplier * proportion);
+ }
+ }
+ else if(comfort < tolerable_comfort)
+ {
+ // Apply discomfort penalty
+ const uint8 max_differential = welt->get_einstellungen()->get_max_discomfort_penalty_differential();
+ const uint8 differential = tolerable_comfort - comfort;
+ const float multiplier = welt->get_einstellungen()->get_max_discomfort_penalty();
+ if(differential >= max_differential)
+ {
+ final_revenue -= (revenue * multiplier);
+ }
+ else
+ {
+ const float proportion = (float)differential / (float)max_differential;
+ final_revenue -= revenue * (multiplier * proportion);
+ }
+ }
+
+ // Do nothing if comfort == tolerable_comfort
+ }
+
+ //Add catering or TPO revenue
+ const uint8 catering_level = get_catering_level(ware.get_besch()->get_catg_index());
+ if(catering_level > 0)
+ {
+ if(ware.is_mail())
+ {
+ // Mail
+ if(journey_minutes >= welt->get_einstellungen()->get_tpo_min_minutes())
+ {
+ final_revenue += (welt->get_einstellungen()->get_tpo_revenue() * ware.menge);
+ }
+ }
+ else if(ware.is_passenger())
+ {
+ // Passengers
+ float proportion = 0.0;
+ switch(catering_level)
+ {
+
+ case 1:
+ case_1:
+ if(journey_minutes < welt->get_einstellungen()->get_catering_min_minutes())
+ {
+ break;
+ }
+ if(journey_minutes > welt->get_einstellungen()->get_catering_level1_minutes())
+ {
+ final_revenue += (welt->get_einstellungen()->get_catering_level1_max_revenue() * ware.menge);
+ break;
+ }
+
+ proportion = (journey_minutes - welt->get_einstellungen()->get_catering_min_minutes()) / (welt->get_einstellungen()->get_catering_level1_minutes() - welt->get_einstellungen()->get_catering_min_minutes());
+ final_revenue += (proportion * (welt->get_einstellungen()->get_catering_level1_max_revenue() * ware.menge));
+ break;
+
+ case 2:
+ case_2:
+ if(journey_minutes < welt->get_einstellungen()->get_catering_level1_minutes())
+ {
+ // If only C++ had C#'s goto case syntax...
+ goto case_1;
+ }
+ if(journey_minutes > welt->get_einstellungen()->get_catering_level2_minutes())
+ {
+ final_revenue += (welt->get_einstellungen()->get_catering_level2_max_revenue() * ware.menge);
+ break;
+ }
+
+ proportion = (journey_minutes - welt->get_einstellungen()->get_catering_level1_max_revenue()) / (welt->get_einstellungen()->get_catering_level2_minutes() - welt->get_einstellungen()->get_catering_level1_minutes());
+ final_revenue += (proportion * (welt->get_einstellungen()->get_catering_level2_max_revenue() * ware.menge));
+ break;
+
+ case 3:
+ case_3:
+ if(journey_minutes < welt->get_einstellungen()->get_catering_level2_minutes())
+ {
+ goto case_2;
+ }
+
+ if(journey_minutes > welt->get_einstellungen()->get_catering_level3_minutes())
+ {
+ final_revenue += (welt->get_einstellungen()->get_catering_level3_max_revenue() * ware.menge);
+ break;
+ }
+
+ proportion = (journey_minutes - welt->get_einstellungen()->get_catering_level2_max_revenue()) / (welt->get_einstellungen()->get_catering_level3_minutes() - welt->get_einstellungen()->get_catering_level2_minutes());
+ final_revenue += (proportion * (welt->get_einstellungen()->get_catering_level3_max_revenue() * ware.menge));
+ break;
+
+ case 4:
+ case_4:
+ if(journey_minutes < welt->get_einstellungen()->get_catering_level3_minutes())
+ {
+ goto case_3;
+ }
+
+ if(journey_minutes > welt->get_einstellungen()->get_catering_level4_minutes())
+ {
+ final_revenue += (welt->get_einstellungen()->get_catering_level4_max_revenue() * ware.menge);
+ break;
+ }
+
+ proportion = (journey_minutes - welt->get_einstellungen()->get_catering_level3_max_revenue()) / (welt->get_einstellungen()->get_catering_level4_minutes() - welt->get_einstellungen()->get_catering_level3_minutes());
+ final_revenue += (proportion * (welt->get_einstellungen()->get_catering_level4_max_revenue() * ware.menge));
+ break;
+
+ case 5:
+ default:
+ if(journey_minutes < welt->get_einstellungen()->get_catering_level4_minutes())
+ {
+ goto case_4;
+ }
+
+ if(journey_minutes > welt->get_einstellungen()->get_catering_level5_minutes())
+ {
+ final_revenue += (welt->get_einstellungen()->get_catering_level5_max_revenue() * ware.menge);
+ break;
+ }
+
+ proportion = (journey_minutes - welt->get_einstellungen()->get_catering_level4_max_revenue()) / (welt->get_einstellungen()->get_catering_level5_minutes() - welt->get_einstellungen()->get_catering_level4_minutes());
+ final_revenue += (proportion * (welt->get_einstellungen()->get_catering_level5_max_revenue() * ware.menge));
+ break;
+ };
+ }
+ }
+
+ final_revenue = (final_revenue + 1500ll) / 3000ll;
+
+ return final_revenue;
}
+const uint8 convoi_t::calc_tolerable_comfort(uint16 journey_minutes) const
+{
+ const uint16 comfort_short_minutes = welt->get_einstellungen()->get_tolerable_comfort_short_minutes();
+ const uint8 comfort_short = welt->get_einstellungen()->get_tolerable_comfort_short();
+ if(journey_minutes <= comfort_short_minutes)
+ {
+ return comfort_short;
+ }
+
+ const uint16 comfort_median_short_minutes = welt->get_einstellungen()->get_tolerable_comfort_median_short_minutes();
+ const uint8 comfort_median_short = welt->get_einstellungen()->get_tolerable_comfort_median_short();
+ if(journey_minutes == comfort_median_short_minutes)
+ {
+ return comfort_median_short;
+ }
+ if(journey_minutes < comfort_median_short_minutes)
+ {
+ const float proportion = (float)(journey_minutes - comfort_short_minutes) / (float)(comfort_median_short_minutes - comfort_short_minutes);
+ return (proportion * (comfort_median_short_minutes - comfort_short)) + comfort_short;
+ }
+
+ const uint16 comfort_median_median_minutes = welt->get_einstellungen()->get_tolerable_comfort_median_median_minutes();
+ const uint8 comfort_median_median = welt->get_einstellungen()->get_tolerable_comfort_median_median();
+ if(journey_minutes == comfort_median_median_minutes)
+ {
+ return comfort_median_median;
+ }
+ if(journey_minutes < comfort_median_median_minutes)
+ {
+ const float proportion = (float)(journey_minutes - comfort_median_short_minutes) / (float)(comfort_median_median_minutes - comfort_median_short_minutes);
+ return (proportion * (comfort_median_median_minutes - comfort_median_short)) + comfort_median_short;
+ }
+
+ const uint16 comfort_median_long_minutes = welt->get_einstellungen()->get_tolerable_comfort_median_long_minutes();
+ const uint8 comfort_median_long = welt->get_einstellungen()->get_tolerable_comfort_median_long();
+ if(journey_minutes == comfort_median_long_minutes)
+ {
+ return comfort_median_long;
+ }
+ if(journey_minutes < comfort_median_long_minutes)
+ {
+ const float proportion = (float)(journey_minutes - comfort_median_median_minutes) / (float)(comfort_median_long_minutes - comfort_median_median_minutes);
+ return (proportion * (comfort_median_long_minutes - comfort_median_median)) + comfort_median_median;
+ }
+
+ const uint16 comfort_long_minutes = welt->get_einstellungen()->get_tolerable_comfort_long_minutes();
+ const uint8 comfort_long = welt->get_einstellungen()->get_tolerable_comfort_long();
+ if(journey_minutes >= comfort_long_minutes)
+ {
+ return comfort_long;
+ }
+
+ const float proportion = (float)(journey_minutes - comfort_median_long_minutes) / (float)(comfort_long_minutes - comfort_median_long_minutes);
+ return (proportion * (comfort_long - comfort_median_long)) + comfort_median_long;
+}
+
+const uint16 convoi_t::calc_adjusted_speed_bonus(uint16 base_bonus, uint32 distance)
+{
+ const uint32 min_distance = welt->get_einstellungen()->get_min_bonus_max_distance();
+ if(distance <= min_distance)
+ {
+ return 0;
+ }
+
+ const uint16 max_distance = welt->get_einstellungen()->get_max_bonus_min_distance();
+ const float multiplier = welt->get_einstellungen()->get_max_bonus_multiplier();
+
+ if(distance >= max_distance)
+ {
+ return base_bonus * multiplier;
+ }
+
+ const uint16 median_distance = welt->get_einstellungen()->get_median_bonus_distance();
+ if(median_distance == 0)
+ {
+ // There is no median, so scale evenly.
+ const double proportion = (double)(distance - min_distance) / (double)(max_distance - min_distance);
+ return (base_bonus * multiplier) * proportion;
+ }
+
+ // There is a median, so scale differently each side of the median.
+
+ if(distance == median_distance)
+ {
+ return base_bonus;
+ }
+
+ if(distance < median_distance)
+ {
+ const double proportion = (double)(distance - min_distance) / (double)(median_distance - min_distance);
+ return base_bonus * proportion;
+ }
+
+ // If the program gets here, it must be true that:
+ // distance > median_distance
+
+ const double proportion = (double)(distance - median_distance) / (double)(max_distance - min_distance);
+ uint16 intermediate_bonus = (base_bonus * multiplier) - base_bonus;
+ intermediate_bonus *= proportion;
+ return intermediate_bonus + base_bonus;
+}
/**
* convoi an haltestelle anhalten
+ * "Convoi stop at stop" (Google translations)
* @author Hj. Malthaner
*
* V.Meyer: ladegrad is now stored in the object (not returned)
*/
-void convoi_t::hat_gehalten(koord k, halthandle_t halt)
+void convoi_t::hat_gehalten(koord k, halthandle_t halt) //"has held" (Google)
{
sint64 gewinn = 0;
- grund_t *gr=welt->lookup(fahr[0]->get_pos());
+ grund_t *gr = welt->lookup(fahr[0]->get_pos());
- int station_lenght=0;
- if(gr->ist_wasser()) {
+ int station_lenght = 0;
+ if(gr->ist_wasser())
+ {
// habour has any size
station_lenght = 24*16;
}
- else {
+ else
+ {
// calculate real station length
koord zv = koord( ribi_t::rueckwaerts(fahr[0]->get_fahrtrichtung()) );
koord3d pos = fahr[0]->get_pos();
const grund_t *grund = welt->lookup(pos);
- if( grund->get_weg_yoff()==TILE_HEIGHT_STEP ) {
+ if( grund->get_weg_yoff()==TILE_HEIGHT_STEP )
+ {
// start on bridge?
pos.z += Z_TILE_STEP;
}
- while( grund && grund->get_halt() == halt ) {
+ while( grund && grund->get_halt() == halt )
+ {
station_lenght += TILE_STEPS;
pos += zv;
grund = welt->lookup(pos);
- if( grund==NULL ) {
+ if( grund==NULL )
+ {
grund = welt->lookup(pos-koord3d(0,0,Z_TILE_STEP));
- if( grund && grund->get_weg_yoff()!=TILE_HEIGHT_STEP ) {
+ if( grund && grund->get_weg_yoff()!=TILE_HEIGHT_STEP )
+ {
// not end/start of bridge
break;
}
@@ -2200,37 +3310,55 @@ void convoi_t::hat_gehalten(koord k, halthandle_t halt)
// only load vehicles in station
// don't load when vehicle is being withdrawn
- for(unsigned i=0; iget_besch()->get_length();
- if(station_lenght<0) {
+ if(station_lenght<0)
+ {
break;
}
- // we need not to call this on the same position
- if( v->last_stop_pos != v->get_pos().get_2d() ) {
- // calc_revenue
- gewinn += v->calc_gewinn(v->last_stop_pos, v->get_pos().get_2d() );
+ // we need not to call this on the same position if( v->last_stop_pos != v->get_pos().get_2d() ) { // calc_revenue
+ if(!second_run || anz_vehikel == 1)
+ {
+ convoi_t *tmp = this;
+ // Replaced by new revenue model
+ //gewinn += v->calc_gewinn(v->last_stop_pos, v->get_pos().get_2d(), tmp );
v->last_stop_pos = v->get_pos().get_2d();
+ //Unload
+ v->current_revenue = 0;
+ freight_info_resort |= v->entladen(k, halt);
+ gewinn += v->current_revenue;
}
-
- freight_info_resort |= v->entladen(k, halt);
- if(!no_load) {
+ if(!no_load)
+ {
// do not load anymore
- freight_info_resort |= v->beladen(k, halt);
+ freight_info_resort |= v->beladen(k, halt, second_run);
+
+ }
+
+ // Run this routine twice: first, load all vehicles to their non-overcrowded capacity.
+ // Then, allow them to run to their overcrowded capacity.
+ if(!second_run && i >= anz_vehikel - 1)
+ {
+ //Reset counter for one more go
+ second_run = true;
+ i = 0;
}
}
// any loading went on?
calc_loading();
- loading_limit = fpl->get_current_eintrag().ladegrad;
+ loading_limit = fpl->get_current_eintrag().ladegrad; //"charge degree" (??) (Babelfish)
- if(gewinn) {
+ if(gewinn)
+ {
+ jahresgewinn += gewinn; //"annual profit" (Babelfish)
besitzer_p->buche(gewinn, fahr[0]->get_pos().get_2d(), COST_INCOME);
- jahresgewinn += gewinn;
-
book(gewinn, CONVOI_PROFIT);
book(gewinn, CONVOI_REVENUE);
}
@@ -2268,7 +3396,7 @@ void convoi_t::calc_loading()
/**
- * Schedule convoid for self destruction. Will be executed
+ * Schedule convoi for self destruction. Will be executed
* upon next sync step
* @author Hj. Malthaner
*/
@@ -2382,14 +3510,40 @@ void convoi_t::set_line(linehandle_t org_line)
if(line.is_bound()) {
unset_line();
}
- else if(fpl && fpl->get_count()>0) {
+ else if(fpl && fpl->get_count()>0)
+ {
// since this schedule is no longer served
+
+#ifdef NEW_PATHING
+ // New method - recalculate on demand
+ ITERATE_PTR(fpl, j)
+ {
+ halthandle_t tmp_halt = haltestelle_t::get_halt(welt, fpl->eintrag[j].pos);
+ if(tmp_halt.is_bound())
+ {
+ tmp_halt->reschedule = true;
+ tmp_halt->force_paths_stale();
+ }
+ }
+#else
+ // Old method - brute force
welt->set_schedule_counter();
+#endif
}
line = org_line;
line_id = org_line->get_line_id();
schedule_t *new_fpl= org_line->get_schedule()->copy();
set_schedule(new_fpl);
+
+#ifdef NEW_PATHING
+ ITERATE_PTR(new_fpl, j)
+ {
+ halthandle_t tmp_halt = haltestelle_t::get_halt(welt, fpl->eintrag[j].pos);
+ tmp_halt->reschedule = true;
+ tmp_halt->force_paths_stale();
+ }
+#endif
+
line->add_convoy(self);
}
@@ -2432,12 +3586,26 @@ void convoi_t::book(sint64 amount, int cost_type)
{
assert( cost_typebook(amount, simline_t::convoi_to_line_catgory[cost_type] );
}
- if(cost_type == CONVOI_TRANSPORTED_GOODS) {
+ if(cost_type == CONVOI_TRANSPORTED_GOODS)
+ {
besitzer_p->buche(amount, COST_ALL_TRANSPORTED);
}
}
@@ -2452,12 +3620,12 @@ convoi_t::init_financial_history()
}
}
-sint32
-convoi_t::get_running_cost() const
+sint32 convoi_t::get_running_cost() const
{
sint32 running_cost = 0;
- for (unsigned i = 0; iget_betriebskosten();
+ for (unsigned i = 0; iget_betriebskosten(welt); //"get_operatingCost" (Google). "Fahr" = "Drive" (Babelfish)
+ running_cost += vehicle_running_cost;
}
return running_cost;
}
@@ -2490,32 +3658,182 @@ void convoi_t::check_pending_updates()
/*
* the current state saved as color
- * Meanings are BLACK (ok), WHITE (no convois), YELLOW (no vehicle moved), RED (last month income minus), BLUE (at least one convoi vehicle is obsolete)
+ * Meanings are BLACK (ok), WHITE (no convois), YELLOW (no vehicle moved), RED (last month income minus), DARK_PURPLE (convoy has overcrowded vehicles), BLUE (at least one convoi vehicle is obsolete)
*/
uint8 convoi_t::get_status_color() const
{
- if(state==INITIAL) {
+ if(state==INITIAL)
+ {
// in depot/under assembly
return COL_WHITE;
}
- else if(state==WAITING_FOR_CLEARANCE_ONE_MONTH || state==CAN_START_ONE_MONTH || hat_keine_route()) {
+ else if(state==WAITING_FOR_CLEARANCE_ONE_MONTH || state==CAN_START_ONE_MONTH || hat_keine_route())
+ {
// stuck or no route
return COL_ORANGE;
}
- else if(financial_history[0][CONVOI_PROFIT]+financial_history[1][CONVOI_PROFIT]<0) {
+ else if(financial_history[0][CONVOI_PROFIT]+financial_history[1][CONVOI_PROFIT]<0)
+ {
// ok, not performing best
return COL_RED;
- } else if((financial_history[0][CONVOI_OPERATIONS]|financial_history[1][CONVOI_OPERATIONS])==0) {
+ }
+ else if((financial_history[0][CONVOI_OPERATIONS]|financial_history[1][CONVOI_OPERATIONS])==0)
+ {
// nothing moved
return COL_YELLOW;
}
- else if(has_obsolete) {
+ else if(get_overcrowded() > 0)
+ {
+ // Overcrowded
+ return COL_DARK_PURPLE;
+ }
+ else if(has_obsolete)
+ {
return COL_BLUE;
}
// normal state
return COL_BLACK;
}
+uint8
+convoi_t::get_catering_level(uint8 type) const
+{
+ uint8 max_catering_level = 0;
+ uint8 current_catering_level;
+ //for(sint16 i = fahr.get_size() - 1; i >= 0; i --)
+ for(uint8 i = 0; i < anz_vehikel; i ++)
+ {
+ vehikel_t* v = get_vehikel(i);
+ if(v == NULL)
+ {
+ continue;
+ }
+ current_catering_level = v->get_besch()->get_catering_level();
+ if(current_catering_level > max_catering_level && v->get_besch()->get_ware()->get_catg_index() == type)
+ {
+ max_catering_level = current_catering_level;
+ }
+ }
+ return max_catering_level;
+}
+
+void convoi_t::set_replacing_vehicles(const vector_tpl *rv)
+{
+ replacing_vehicles.clear();
+ replacing_vehicles.resize(rv->get_count()); // To save some memory
+ for (unsigned int i=0; iget_count(); ++i) {
+ replacing_vehicles.append((*rv)[i]);
+ }
+}
+
+
+ /**
+ * True if this convoy has the same vehicles as the other
+ * @author isidoro
+ */
+bool convoi_t::has_same_vehicles(convoihandle_t other) const
+{
+ if (other.is_bound()) {
+ if (get_vehikel_anzahl()!=other->get_vehikel_anzahl()) {
+ return false;
+ }
+ for (int i=0; iget_besch()!=other->get_vehikel(i)->get_besch()) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+
+/**
+ * Convoy is sent to depot. Return value, success or not.
+ */
+bool convoi_t::go_to_depot(bool show_success)
+{
+ if (convoi_info_t::route_search_in_progress) {
+ return false;
+ }
+ // limit update to certain states that are considered to be save for fahrplan updates
+ int state = get_state();
+ if(state==convoi_t::FAHRPLANEINGABE) {
+DBG_MESSAGE("convoi_t::go_to_depot()","convoi state %i => cannot change schedule ... ", state );
+ return false;
+ }
+ convoi_info_t::route_search_in_progress = true;
+
+ // iterate over all depots and try to find shortest route
+ slist_iterator_tpl depot_iter(depot_t::get_depot_list());
+ route_t * shortest_route = new route_t();
+ route_t * route = new route_t();
+ koord3d home = koord3d(0,0,0);
+ while (depot_iter.next()) {
+ depot_t *depot = depot_iter.get_current();
+ if(depot->get_wegtyp()!=get_vehikel(0)->get_besch()->get_waytype() || depot->get_besitzer()!=get_besitzer()) {
+ continue;
+ }
+ koord3d pos = depot->get_pos();
+ if(!shortest_route->empty() && abs_distance(pos.get_2d(),get_pos().get_2d())>=shortest_route->get_max_n()) {
+ // the current route is already shorter, no need to search further
+ continue;
+ }
+ bool found = get_vehikel(0)->calc_route(get_pos(), pos, 50, route); // do not care about speed
+ if (found) {
+ if( route->get_max_n() < shortest_route->get_max_n() || shortest_route->empty() ) {
+ shortest_route->kopiere(route);
+ home = pos;
+ }
+ }
+ }
+ delete route;
+ DBG_MESSAGE("shortest route has ", "%i hops", shortest_route->get_max_n());
+
+ // if route to a depot has been found, update the convoi's schedule
+ bool b_depot_found = false;
+ if(!shortest_route->empty()) {
+ schedule_t *fpl = get_schedule();
+ fpl->insert(get_welt()->lookup(home));
+ fpl->set_aktuell( (fpl->get_aktuell()+fpl->get_count()-1)%fpl->get_count() );
+ b_depot_found = set_schedule(fpl);
+ }
+ delete shortest_route;
+ convoi_info_t::route_search_in_progress = false;
+
+ // show result
+ const char* txt;
+ if (b_depot_found) {
+ txt = "Convoi has been sent\nto the nearest depot\nof appropriate type.\n";
+ } else {
+ txt = "Home depot not found!\nYou need to send the\nconvoi to the depot\nmanually.";
+ }
+ if (!b_depot_found || show_success) {
+ create_win( new news_img(txt), w_time_delete, magic_none);
+ }
+ return b_depot_found;
+}
+
+bool convoi_t::has_no_cargo() const
+{
+ if (loading_level==0)
+ {
+ return true;
+ }
+ if (loading_level!=100)
+ {
+ return false;
+ }
+ /* a convoy with max capacity of zero, has always loading_level==100 */
+ for(unsigned i=0; iget_fracht_max()>0)
+ {
+ return false;
+ }
+ }
+ return true;
+}
// returns tiles needed for this convoi
@@ -2680,3 +3998,33 @@ bool convoi_t::can_overtake(overtaker_t *other_overtaker, int other_speed, int s
other_overtaker->set_tiles_overtaking( -1-(n_tiles/2) );
return true;
}
+
+uint32
+convoi_t::calc_heaviest_vehicle()
+{
+ uint32 heaviest = 0;
+ for(uint8 i = 0; i < anz_vehikel; i ++)
+ {
+ uint32 tmp = fahr[i]->get_sum_weight();
+ if(tmp > heaviest)
+ {
+ heaviest = tmp;
+ }
+ }
+ return heaviest;
+}
+
+uint16
+convoi_t::calc_longest_loading_time()
+{
+ uint16 longest = 0;
+ for(uint8 i = 0; i < anz_vehikel; i ++)
+ {
+ uint16 tmp = fahr[i]->get_besch()->get_loading_time();
+ if(tmp > longest)
+ {
+ longest = tmp;
+ }
+ }
+ return longest;
+}
diff --git a/simconvoi.h b/simconvoi.h
index 7ac55e39d2b..73c853d976c 100644
--- a/simconvoi.h
+++ b/simconvoi.h
@@ -5,6 +5,7 @@
#ifndef simconvoi_h
#define simconvoi_h
+//#define TEST_SPEED
#include "simtypes.h"
#include "linehandle_t.h"
@@ -14,18 +15,27 @@
#include "dataobj/route.h"
#include "vehicle/overtaker.h"
#include "tpl/array_tpl.h"
+#include "tpl/fixed_list_tpl.h"
#include "convoihandle_t.h"
#include "halthandle_t.h"
-#define MAX_CONVOI_COST 5 // Total number of cost items
+#ifdef TEST_SPEED
+#include "simconst.h"
+#endif
+
+#define MAX_CONVOI_COST 7 // Total number of cost items
#define MAX_MONTHS 12 // Max history
-#define MAX_CONVOI_NON_MONEY_TYPES 2 // number of non money types in convoi's financial statistic
-#define CONVOI_CAPACITY 0 // the amount of ware that could be transported, theoretically
-#define CONVOI_TRANSPORTED_GOODS 1 // the amount of ware that has been transported
-#define CONVOI_REVENUE 2 // the income this CONVOI generated
-#define CONVOI_OPERATIONS 3 // the cost of operations this CONVOI generated
-#define CONVOI_PROFIT 4 // total profit of this convoi
+#define MAX_CONVOI_NON_MONEY_TYPES 4 // number of non money types in convoi's financial statistic
+
+#define CONVOI_CAPACITY 0 // the amount of ware that could be transported, theoretically
+#define CONVOI_TRANSPORTED_GOODS 1 // the amount of ware that has been transported
+#define CONVOI_AVERAGE_SPEED 2 // The average speed of the convoy per rolling month
+#define CONVOI_COMFORT 3 // The aggregate comfort rating of this convoy
+#define CONVOI_REVENUE 4 // the income this CONVOI generated
+#define CONVOI_OPERATIONS 5 // the cost of operations this CONVOI generated
+#define CONVOI_PROFIT 6 // total profit of this convoi
+
class depot_t;
class karte_t;
@@ -35,6 +45,7 @@ class vehikel_t;
class vehikel_besch_t;
class schedule_t;
class cbuffer_t;
+class ware_t;
/**
* Basisklasse für alle Fahrzeugverbände. Convois könnnen über Zeiger
@@ -49,7 +60,7 @@ class convoi_t : public sync_steppable, public overtaker_t
/* Konstanten
* @author prissi
*/
- enum { max_vehicle=4, max_rail_vehicle = 24 };
+ enum { max_vehicle=4, max_rail_vehicle = 64 };
enum states {INITIAL,
FAHRPLANEINGABE,
@@ -146,6 +157,7 @@ class convoi_t : public sync_steppable, public overtaker_t
* Current map
* @author Hj. Malthaner
*/
+
static karte_t *welt;
/**
@@ -160,6 +172,24 @@ class convoi_t : public sync_steppable, public overtaker_t
*/
bool no_load;
+ /*
+ * the convoy is marked for automatic replacing
+ * @author isidoro
+ */
+ bool replace;
+
+ /**
+ * if marked for replacing, once in depot, auto restar the vehicle
+ * @author isidoro
+ */
+ bool autostart;
+
+ /**
+ * send to depot when empty
+ * @author isidoro
+ */
+ bool depot_when_empty;
+
/**
* the convoi caches its freight info; it is only recalculation after loading or resorting
* @author prissi
@@ -196,6 +226,11 @@ class convoi_t : public sync_steppable, public overtaker_t
*/
uint32 sum_leistung;
+ // How much of the convoy's power comes from steam engines?
+ // Needed when applying realistic physics to steam engines.
+ // @author: jamespetts
+ uint32 power_from_steam;
+
/**
* Gesamtleistung mit Gear. Wird nicht gespeichert, sondern aus den Einzelleistungen
* errechnet.
@@ -203,6 +238,9 @@ class convoi_t : public sync_steppable, public overtaker_t
*/
sint32 sum_gear_und_leistung;
+ // @author: jamespetts
+ sint32 power_from_steam_with_gear;
+
/* sum_gewicht: leergewichte aller vehicles *
* sum_gesamtgewicht: gesamtgewichte aller vehicles *
* Werden nicht gespeichert, sondern aus den Einzelgewichten
@@ -238,7 +276,7 @@ class convoi_t : public sync_steppable, public overtaker_t
* time, when a convoi waiting for full load will drive on
* @author prissi
*/
- uint32 go_on_ticks;
+ sint64 go_on_ticks;
/**
* akkumulierter gewinn über ein jahr hinweg
@@ -267,7 +305,10 @@ class convoi_t : public sync_steppable, public overtaker_t
enum states state;
- ribi_t::ribi alte_richtung;
+ ribi_t::ribi alte_richtung; //"Old direction" (Google)
+
+ // The replacing vehicles, if any
+ vector_tpl replacing_vehicles;
/**
* Initialize all variables with default values.
@@ -303,7 +344,7 @@ class convoi_t : public sync_steppable, public overtaker_t
* only used for entering depot or recalculating routes when a schedule window is opened
* @author Hj. Malthaner
*/
- void calc_gewinn();
+ //void calc_gewinn();
/**
* Recalculates loading level and limit.
@@ -318,8 +359,13 @@ class convoi_t : public sync_steppable, public overtaker_t
*/
void calc_acceleration(long delta_t);
+ // Calculate the total power as adjusted to take account of steam engine physics
+ //@author: jamespetts
+ sint32 calc_adjusted_power();
+
/**
* Convoi haelt an Haltestelle und setzt quote fuer Fracht
+ * "Convoi holds by stop and sets ratio for freight" (Babelfish)
* @author Hj. Malthaner
*/
void hat_gehalten(koord k, halthandle_t halt);
@@ -343,6 +389,31 @@ class convoi_t : public sync_steppable, public overtaker_t
*/
koord3d home_depot;
+ // Helper function: used in init and replacing
+ void reset();
+
+ // Reverses the order of the convoy.
+ // @author: jamespetts
+ void reverse_order(bool rev);
+ bool reversable;
+ bool reversed;
+
+ uint32 heaviest_vehicle;
+ uint16 longest_loading_time;
+
+ // Time in ticks since it departed from the previous stop.
+ // Used for measuring average speed.
+ // @author: jamespetts
+ sint64 last_departure_time;
+
+ // @author: jamespetts
+ uint32 rolling_average[MAX_CONVOI_COST];
+ uint16 rolling_average_count[MAX_CONVOI_COST];
+
+ // @author: jamespetts
+ const uint8 calc_tolerable_comfort(uint16 journey_minutes) const;
+
+
public:
route_t* get_route() { return &route; }
@@ -407,6 +478,7 @@ class convoi_t : public sync_steppable, public overtaker_t
/**
* Der Gewinn in diesem Jahr
+ * "The profit in this year" (Babelfish)
* @author Hanjsörg Malthaner
*/
const sint64 & get_jahresgewinn() const {return jahresgewinn;}
@@ -488,7 +560,14 @@ class convoi_t : public sync_steppable, public overtaker_t
* set from the first vehicle, and takes into account all speed limits, brakes at stations etc.
* @author Hj. Malthaner
*/
+#ifdef TEST_SPEED
+ void set_akt_speed_soll(sint32 set_akt_speed) { akt_speed_soll = kmh_to_speed(10); }
+ struct speed_testing { uint32 ticks; koord tile; };
+ fixed_list_tpl ticks_per_tile;
+ uint32 average_speed;
+#else
void set_akt_speed_soll(sint32 set_akt_speed) { akt_speed_soll = min( set_akt_speed, min_top_speed ); }
+#endif
/**
* @return current speed, this might be different from topspeed
@@ -501,10 +580,12 @@ class convoi_t : public sync_steppable, public overtaker_t
* @return total power of this convoi
* @author Hj. Malthaner
*/
- const uint32 & get_sum_leistung() const {return sum_leistung;}
- const sint32 & get_min_top_speed() const {return min_top_speed;}
- const sint32 & get_sum_gewicht() const {return sum_gewicht;}
- const sint32 & get_sum_gesamtgewicht() const {return sum_gesamtgewicht;}
+ uint32 get_sum_leistung() const {return sum_leistung;}
+ uint32 get_power_from_steam() const {return power_from_steam;}
+ uint32 get_power_from_steam_with_gear() const {return power_from_steam_with_gear;}
+ sint32 get_min_top_speed() const {return min_top_speed;}
+ sint32 get_sum_gewicht() const {return sum_gewicht;}
+ sint32 get_sum_gesamtgewicht() const {return sum_gesamtgewicht;}
uint32 get_length() const;
@@ -640,12 +721,14 @@ class convoi_t : public sync_steppable, public overtaker_t
/**
* pruefe ob Beschraenkungen fuer alle Fahrzeuge erfuellt sind
+ * " examine whether restrictions for all vehicles are fulfilled" (Google)
* @author Hj. Malthaner
*/
bool pruefe_alle();
/**
* Kontrolliert Be- und Entladen.
+ * "Controlled loading and unloading" (Google)
* V.Meyer: returns nothing
* @author Hj. Malthaner
*/
@@ -779,8 +862,70 @@ class convoi_t : public sync_steppable, public overtaker_t
void set_no_load(bool new_no_load) { no_load = new_no_load; }
+ bool get_replace() const { return replace; }
+
+ void set_replace(bool new_replace) { replace = new_replace; }
+
+ bool get_depot_when_empty() const { return depot_when_empty; }
+
+ void set_depot_when_empty(bool new_dwe) { depot_when_empty=new_dwe; }
+
+ bool get_autostart() const { return autostart; }
+
+ void set_autostart(bool new_autostart) { autostart=new_autostart; }
+
+ const vector_tpl *get_replacing_vehicles() const { return &replacing_vehicles; }
+ void set_replacing_vehicles(const vector_tpl *rv);
+
+ // True if the convoy has the same vehicles
+ bool has_same_vehicles(convoihandle_t other) const;
+
+ // Go to depot, if possible
+ bool go_to_depot(bool show_success);
+
+ // True if convoy has no cargo
+ //@author: isidoro
+ bool has_no_cargo() const;
+
// Overtaking for convois
virtual bool can_overtake(overtaker_t *other_overtaker, int other_speed, int steps_other, int diagonal_length);
+
+ //Returns the maximum catering level of the category type given in the convoy.
+ //@author: jamespetts
+ uint8 get_catering_level(uint8 type) const;
+
+ //@author: jamespetts
+ bool get_reversable() const { return reversable; }
+ bool is_reversed() const { return reversed; }
+
+ //@author: jamespetts
+ uint32 calc_heaviest_vehicle();
+ uint32 get_heaviest_vehicle() const { return heaviest_vehicle; }
+
+ //@author: jamespetts
+ uint16 calc_longest_loading_time();
+ uint16 get_longest_loading_time() const { return longest_loading_time; }
+
+ // @author: jamespetts
+ // Returns the number of standing passengers (etc.) in this convoy.
+ uint16 get_overcrowded() const;
+
+ // @author: jamespetts
+ // Returns the average comfort of this convoy,
+ // taking into account any catering.
+ uint8 get_comfort() const;
+
+ // The new revenue calculation method for per-leg
+ // based revenue calculation, rather than per-hop
+ // based revenue calculation. This method calculates
+ // the revenue of a ware packet unloaded, rather
+ // than iterating through each ware packet in each
+ // vehicle in the convoy.
+ // @author: jamespetts
+ sint64 calc_revenue(ware_t &ware);
+
+ // @author: jamespetts
+ static const uint16 calc_adjusted_speed_bonus(uint16 base_bonus, uint32 distance);
};
#endif
diff --git a/simdebug.h b/simdebug.h
index 46676c392a5..83f87bffb7b 100644
--- a/simdebug.h
+++ b/simdebug.h
@@ -13,7 +13,7 @@
// check assertions
-#undef NDEBUG
+//#undef NDEBUG
//#define NDEBUG
diff --git a/simdepot.cc b/simdepot.cc
index d11922341e3..bd581455499 100644
--- a/simdepot.cc
+++ b/simdepot.cc
@@ -109,6 +109,16 @@ depot_t *depot_t::find_depot( koord3d start, const ding_t::typ depot_type, const
return found;
}
+unsigned depot_t::get_max_convoy_length(waytype_t wt)
+{
+ if (wt==road_wt || wt==water_wt) {
+ return 4;
+ }
+ if (wt==air_wt) {
+ return 1;
+ }
+ return convoi_t::max_rail_vehicle;
+}
/* this is called on two occasions:
@@ -165,16 +175,21 @@ bool depot_t::can_convoi_start(convoihandle_t /*cnv*/) const
}
-vehikel_t* depot_t::buy_vehicle(const vehikel_besch_t* info)
+vehikel_t* depot_t::buy_vehicle(const vehikel_besch_t* info, bool upgrade)
{
// Offen: prüfen ob noch platz im depot ist???
+ // "Hours: check whether there is space in the depot?" (Google)
DBG_DEBUG("depot_t::buy_vehicle()", info->get_name());
- vehikel_t* veh = vehikelbauer_t::baue(get_pos(), get_besitzer(), NULL, info );
+ vehikel_t* veh = vehikelbauer_t::baue(get_pos(), get_besitzer(), NULL, info, upgrade ); //"besitzer" = "owner" (Google)
DBG_DEBUG("depot_t::buy_vehicle()", "vehiclebauer %p", veh);
- vehicles.append(veh);
- DBG_DEBUG("depot_t::buy_vehicle()", "appended %i vehicle", vehicles.get_count());
- return veh;
+ if(!upgrade)
+ {
+ vehicles.append(veh);
+ DBG_DEBUG("depot_t::buy_vehicle()", "appended %i vehicle", vehicles.get_count());
+ return veh;
+ }
+ return NULL;
}
@@ -434,6 +449,25 @@ const char * depot_t::ist_entfernbar(const spieler_t *sp)
return NULL;
}
+// returns the indest of the old/newest vehicle in a list
+//@author: isidoro
+vehikel_t* depot_t::find_oldest_newest(const vehikel_besch_t* besch, bool old)
+{
+ vehikel_t* found_veh = NULL;
+ slist_iterator_tpl iter(get_vehicle_list());
+ while (iter.next()) {
+ vehikel_t* veh = iter.get_current();
+ if (veh != NULL && veh->get_besch() == besch) {
+ // joy of XOR, finally a line where I could use it!
+ if (found_veh == NULL ||
+ old ^ (found_veh->get_insta_zeit() > veh->get_insta_zeit())) {
+ found_veh = veh;
+ }
+ }
+ }
+ return found_veh;
+}
+
slist_tpl* depot_t::get_vehicle_type()
{
@@ -478,6 +512,21 @@ linehandle_t depot_t::get_selected_line()
return selected_line;
}
+
+sint32 depot_t::calc_restwert(const vehikel_besch_t *veh_type)
+{
+ sint32 wert = 0;
+
+ slist_iterator_tpl iter(get_vehicle_list());
+ while(iter.next()) {
+ if(iter.get_current()->get_besch() == veh_type) {
+ wert += iter.get_current()->calc_restwert();
+ }
+ }
+ return wert;
+}
+
+
bool bahndepot_t::can_convoi_start(convoihandle_t cnv) const
{
waytype_t wt=cnv->get_vehikel(0)->get_waytype();
@@ -521,3 +570,17 @@ bool bahndepot_t::can_convoi_start(convoihandle_t cnv) const
}
return success;
}
+
+// true if already stored here
+bool depot_t::is_contained(const vehikel_besch_t *info)
+{
+ if(vehicle_count()>0) {
+ slist_iterator_tpl iter(get_vehicle_list());
+ while(iter.next()) {
+ if(iter.get_current()->get_besch()==info) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
diff --git a/simdepot.h b/simdepot.h
index c5122f214d4..ee7d783f04a 100644
--- a/simdepot.h
+++ b/simdepot.h
@@ -19,6 +19,7 @@ class vehikel_t;
class schedule_t;
class depot_frame_t;
class vehikel_besch_t;
+class gui_convoy_assembler;
/**
@@ -28,7 +29,7 @@ class vehikel_besch_t;
class depot_t : public gebaeude_t
{
protected:
- /**
+ /**
* Reworked depot data!
*
* It can now contain any number of vehicles bough by the user (as before).
@@ -56,6 +57,8 @@ class depot_t : public gebaeude_t
static const slist_tpl& get_depot_list() { return all_depots; }
+ static unsigned get_max_convoy_length(waytype_t wt);
+
depot_t(karte_t *welt,loadsave_t *file);
depot_t(karte_t *welt, koord3d pos, spieler_t *sp, const haus_tile_besch_t *t);
virtual ~depot_t();
@@ -66,12 +69,6 @@ class depot_t : public gebaeude_t
virtual linehandle_t create_line();
- // text for the tabs is defaulted to the train names
- virtual const char * get_electrics_name() { return "Electrics_tab"; };
- virtual const char * get_passenger_name() { return "Pas_tab"; }
- virtual const char * get_zieher_name() { return "Lokomotive_tab"; }
- virtual const char * get_haenger_name() { return "Waggon_tab"; }
-
/**
* Access to convoi list.
* @author Volker Meyer
@@ -136,7 +133,7 @@ class depot_t : public gebaeude_t
* @author Volker Meyer
* @date 09.06.2003
*/
- vehikel_t* buy_vehicle(const vehikel_besch_t* info);
+ vehikel_t* buy_vehicle(const vehikel_besch_t* info, bool upgrade);
/**
* Sell a vehicle from the vehicle list.
@@ -165,17 +162,6 @@ class depot_t : public gebaeude_t
*/
void convoi_arrived(convoihandle_t cnv, bool fpl_adjust);
- /**
- * Parameters to determine layout and behaviour of the depot_frame_t.
- * @author Volker Meyer
- * @date 09.06.2003
- */
- virtual int get_x_grid() const = 0;
- virtual int get_y_grid() const = 0;
- virtual int get_x_placement() const = 0;
- virtual int get_y_placement() const = 0;
- virtual unsigned get_max_convoi_length() const = 0;
-
/**
* Öffnet ein neues Beobachtungsfenster für das Objekt.
* @author Hj. Malthaner
@@ -195,12 +181,31 @@ class depot_t : public gebaeude_t
*/
vehikel_t* get_oldest_vehicle(const vehikel_besch_t* besch);
+ /**
+ * Calulate the values of the vehicles of the given type owned by the
+ * player in this depot.
+ * @author Volker Meyer
+ * @date 09.06.2003
+ */
+ sint32 calc_restwert(const vehikel_besch_t *veh_type);
+
/*
* sets/gets the line that was selected the last time in the depot-dialog
*/
void set_selected_line(const linehandle_t sel_line);
linehandle_t get_selected_line();
+ /*
+ * Find the oldest/newest vehicle in the depot
+ */
+ vehikel_t* find_oldest_newest(const vehikel_besch_t* besch, bool old);
+
+ // true if already stored here
+ bool is_contained(const vehikel_besch_t *info);
+
+ // Helper function
+ inline unsigned get_max_convoi_length() const {return get_max_convoy_length(get_wegtyp());}
+
private:
linehandle_t selected_line;
};
@@ -225,17 +230,6 @@ class bahndepot_t : public depot_t
void rdwr_vehicles(loadsave_t *file) { depot_t::rdwr_vehikel(vehicles,file); }
- /**
- * Parameters to determine layout and behaviour of the depot_frame_t.
- * @author Volker Meyer
- * @date 09.06.2003
- */
- int get_x_placement() const {return -25; }
- int get_y_placement() const {return -28; }
- int get_x_grid() const { return 24; }
- int get_y_grid() const { return 24; }
- unsigned get_max_convoi_length() const { return convoi_t::max_rail_vehicle; }
-
virtual waytype_t get_wegtyp() const {return track_wt;}
virtual enum ding_t::typ get_typ() const {return bahndepot;}
virtual const char *get_name() const {return "Bahndepot"; }
@@ -302,29 +296,12 @@ class narrowgaugedepot_t : public bahndepot_t
*/
class strassendepot_t : public depot_t
{
-protected:
- virtual const char * get_passenger_name() { return "Bus_tab"; }
- virtual const char * get_electrics_name() { return "TrolleyBus_tab"; }
- virtual const char * get_zieher_name() { return "LKW_tab"; }
- virtual const char * get_haenger_name() { return "Anhaenger_tab"; }
-
public:
strassendepot_t(karte_t *welt, loadsave_t *file) : depot_t(welt,file) {}
strassendepot_t(karte_t *welt, koord3d pos,spieler_t *sp, const haus_tile_besch_t *t) : depot_t(welt,pos,sp,t) {}
virtual simline_t::linetype get_line_type() const { return simline_t::truckline; }
- /**
- * Parameters to determine layout and behaviour of the depot_frame_t.
- * @author Volker Meyer
- * @date 09.06.2003
- */
- int get_x_placement() const { return -20; }
- int get_y_placement() const { return -25; }
- int get_x_grid() const { return 24; }
- int get_y_grid() const { return 24; }
- unsigned get_max_convoi_length() const { return 4; }
-
virtual waytype_t get_wegtyp() const {return road_wt; }
enum ding_t::typ get_typ() const {return strassendepot;}
const char *get_name() const {return "Strassendepot";}
@@ -339,28 +316,12 @@ class strassendepot_t : public depot_t
*/
class schiffdepot_t : public depot_t
{
-protected:
- virtual const char * get_passenger_name() { return "Ferry_tab"; }
- virtual const char * get_zieher_name() { return "Schiff_tab"; }
- virtual const char * get_haenger_name() { return "Schleppkahn_tab"; }
-
public:
schiffdepot_t(karte_t *welt, loadsave_t *file) : depot_t(welt,file) {}
schiffdepot_t(karte_t *welt, koord3d pos, spieler_t *sp, const haus_tile_besch_t *t) : depot_t(welt,pos,sp,t) {}
virtual simline_t::linetype get_line_type() const { return simline_t::shipline; }
- /**
- * Parameters to determine layout and behaviour of the depot_frame_t.
- * @author Volker Meyer
- * @date 09.06.2003
- */
- int get_x_placement() const { return -1; }
- int get_y_placement() const { return -11; }
- int get_x_grid() const { return 60; }
- int get_y_grid() const { return 46; }
-
- unsigned get_max_convoi_length() const { return 4; }
virtual waytype_t get_wegtyp() const {return water_wt; }
enum ding_t::typ get_typ() const {return schiffdepot;}
const char *get_name() const {return "Schiffdepot";}
@@ -368,27 +329,12 @@ class schiffdepot_t : public depot_t
class airdepot_t : public depot_t
{
-protected:
- virtual const char * get_zieher_name() { return "aircraft_tab"; }
- virtual const char * get_passenger_name() { return "Flug_tab"; }
-
public:
airdepot_t(karte_t *welt, loadsave_t *file) : depot_t(welt,file) {}
airdepot_t(karte_t *welt, koord3d pos,spieler_t *sp, const haus_tile_besch_t *t) : depot_t(welt,pos,sp,t) {}
virtual simline_t::linetype get_line_type() const { return simline_t::airline; }
- /**
- * Parameters to determine layout and behaviour of the depot_frame_t.
- * @author Volker Meyer
- * @date 09.06.2003
- */
- int get_x_placement() const {return -10; }
- int get_y_placement() const {return -23; }
- int get_x_grid() const { return 36; }
- int get_y_grid() const { return 36; }
- unsigned get_max_convoi_length() const { return 1; }
-
virtual waytype_t get_wegtyp() const { return air_wt; }
enum ding_t::typ get_typ() const { return airdepot; }
const char *get_name() const {return "Hangar";}
diff --git a/simdings.cc b/simdings.cc
index ec24f9e21d8..4a0983c2006 100644
--- a/simdings.cc
+++ b/simdings.cc
@@ -129,6 +129,7 @@ ding_t::~ding_t()
/**
* setzt den Besitzer des dings
* (public wegen Rathausumbau - V.Meyer)
+ * "sets the owner of the thing" (Babelfish)
* @author Hj. Malthaner
*/
void ding_t::set_besitzer(spieler_t *sp)
diff --git a/simfab.cc b/simfab.cc
index 52e592e876d..86aa1425352 100644
--- a/simfab.cc
+++ b/simfab.cc
@@ -33,7 +33,7 @@
#include "besch/ware_besch.h"
#include "player/simplay.h"
-
+#include "simmesg.h"
#include "simintr.h"
#include "dings/wolke.h"
@@ -118,6 +118,57 @@ fabrik_t::rem_lieferziel(koord ziel)
lieferziele.remove(ziel);
}
+bool
+fabrik_t::disconnect_consumer(koord pos) //Returns true if must be destroyed.
+{
+ rem_lieferziel(pos);
+ if(lieferziele.get_count() < 1)
+ {
+ // If there are no consumers left, industry is orphaned.
+ // Reconnect or close.
+
+ //Attempt to reconnect. NOTE: This code may not work well if there are multiple supply types.
+
+ for(sint16 i = welt->get_fab_list().get_count() - 1; i >= 0; i --)
+ {
+ fabrik_t* fab = welt->get_fab_list()[i];
+ if(add_customer(fab))
+ {
+ //Only reconnect one.
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+bool
+fabrik_t::disconnect_supplier(koord pos) //Returns true if must be destroyed.
+{
+ rem_supplier(pos);
+ if(suppliers.get_count() < 1)
+ {
+ // If there are no suppliers left, industry is orphaned.
+ // Reconnect or close.
+
+ //Attempt to reconnect. NOTE: This code may not work well if there are multiple supply types.
+
+ for(sint16 i = welt->get_fab_list().get_count() - 1; i >= 0; i --)
+ {
+
+ fabrik_t* fab = welt->get_fab_list()[i];
+ if(add_supplier(fab))
+ {
+ //Only reconnect one.
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
fabrik_t::fabrik_t(karte_t* wl, loadsave_t* file)
{
@@ -200,7 +251,8 @@ fabrik_t::fabrik_t(koord3d pos_, spieler_t* spieler, const fabrik_besch_t* fabes
fabrik_t::~fabrik_t()
{
- while(!fields.empty()) {
+ while(!fields.empty())
+ {
planquadrat_t *plan = welt->access( fields.back() );
assert(plan);
grund_t *gr = plan->get_kartenboden();
@@ -210,6 +262,46 @@ fabrik_t::~fabrik_t()
plan->boden_ersetzen( gr, new boden_t( welt, gr->get_pos(), hang_t::flach ) );
plan->get_kartenboden()->calc_bild();
}
+
+ fabrik_t* tmp = this;
+
+ //Disconnect this factory from all chains.
+ //@author: jamespetts
+ uint32 number_of_customers = lieferziele.get_count();
+ uint32 number_of_suppliers = suppliers.get_count();
+
+ if (!welt->get_is_shutting_down())
+ {
+ char buf[192];
+ uint16 jobs = besch->get_pax_level();
+ sprintf(buf, translator::translate("Industry: %s has closed down, with the loss of %d jobs. %d upstream suppliers and %d downstream customers are affected."), translator::translate(get_name()), jobs, number_of_suppliers, number_of_customers);
+ welt->get_message()->add_message(buf, pos.get_2d(), message_t::general, COL_DARK_RED, skinverwaltung_t::neujahrsymbol->get_bild_nr(0));
+ for(sint32 i = number_of_customers - 1; i >= 0; i --)
+ {
+ fabrik_t* tmp = get_fab(welt, lieferziele[i]);
+ if(tmp->disconnect_supplier(pos.get_2d()))
+ {
+ //Orphaned, must be deleted.
+ grund_t *gr = 0;
+ gr = welt->lookup(tmp->get_pos());
+ gebaeude_t* gb = gr->find();
+ hausbauer_t::remove(welt, welt->get_spieler(1), gb);
+ }
+ }
+
+ for(sint32 i = number_of_suppliers - 1; i >= 0; i --)
+ {
+ fabrik_t* tmp = get_fab(welt, suppliers[i]);
+ if(tmp->disconnect_consumer(pos.get_2d()))
+ {
+ //Orphaned, must be deleted.
+ grund_t *gr = 0;
+ gr = welt->lookup(tmp->get_pos());
+ gebaeude_t* gb = gr->find