News:

Do you need help?
Simutrans Wiki Manual can help you to play and extend Simutrans. In 9 languages.

Late starting games with historical buildings

Started by diesseits, May 28, 2010, 11:04:44 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

diesseits

Is there any way to get new cities generated 'late' (for a map starting say 1950) to use a mixture of current and historical buildings? I'm not so interested in playing steam-era games, but I don't like the look of cities that appear to have just sprung up with only a handful of building types, especially in pak128.britain where the older buildings are important for the overall look and feel of the game.

Alternately, is there a way to use the timeline for vehicles but nothing else?

mobo

Well, if those old buildings are still being built in 1950, You could delete the more modern buildings from the pak folder before map creation. When you got xour map you can save it and add the files again. Not a very elegant way, but should work. If you want to do this more often you can have some prepared pakbritain folder for map creation in a different folder, then you only have to exchange the folders.


wlindley

Perhaps the city generation could be modified to include old buildings along with current ones; there would be some modification required to the chance calculation.

diesseits

@wlindley I think that would be good. I don't see any rationale for cities to be built with only current buildings in any pak. At the moment the only maps that look good are those created in the 18th century and those created without the 'use timeline' checkbox on, but I want to use the timeline for vehicles and infrastructure. City creation should obey the introduction date but not the retirement date of buildings to get a good mix.

I could probably fix it myself, except that the code seems to be in German so I'm a bit lost.

sdog

#4
QuoteWell, if those old buildings are still being built in 1950, You could delete the more modern buildings from the pak folder before map creation.
this doesn't work for pak128.britain, since all buildings are in one pak. He'd need to generate that pak from the source.

QuoteCity creation should obey the introduction date but not the retirement date of buildings to get a good mix.
that would be quite worth a try.


you could start looking for it in  simcity.cc  comments are mostly translated to english already in this file.

this routine replaces buildings with higher level buildings:

void stadt_t::renoviere_gebaeude(gebaeude_t* gb)
{
        const gebaeude_t::typ alt_typ = gb->get_haustyp();
        if (alt_typ == gebaeude_t::unbekannt) {
                return; // only renovate res, com, ind
        }

        if (gb->get_tile()->get_besch()->get_b()*gb->get_tile()->get_besch()->get_h()!=1) {
                return; // too big ...
        }

        // hier sind wir sicher dass es ein Gebaeude ist
        const int level = gb->get_tile()->get_besch()->get_level();

        // bisher gibt es 2 Sorten Haeuser
        // arbeit-spendende und wohnung-spendende
        const int will_arbeit  = (bev - arb) / 4;  // Nur ein viertel arbeitet
        const int will_wohnung = (bev - won);

        // does the timeline allow this buildings?
        const uint16 current_month = welt->get_timeline_year_month();
        const climate cl = welt->get_climate(gb->get_pos().z);
[\code]
[code]
// check for residence
        // (sum_wohnung>sum_industrie  &&  sum_wohnung>sum_gewerbe
        if (will_haben == gebaeude_t::unbekannt) {
                // we must check, if we can really update to higher level ...
                const int try_level = (alt_typ == gebaeude_t::wohnung ? level + 1 : level);
                h = hausbauer_t::get_wohnhaus(try_level, current_month, cl);
                if (h != NULL && h->get_level() >= try_level) {
                        will_haben = gebaeude_t::wohnung;
                        sum = sum_wohnung;
                } else {
                        h = NULL;
                }
        }

btw (my graps of the code is rather lacklustre, so pls don't get offended if i'm totally wrong):
hausbauer_t::get_wohnhaus(try_level, current_month, cl); gets a random house from a list, i think?
here it is checked if it is suitable. is it getting less effective if the timeline is very long and only a few houses are available at any given point in time? for a list with many suitable entries it should be much better than first selecting the list, then randomizing.[/code]

diesseits

#5
sdog: thanks.

With the aid of google translate, I think I've tracked it down to this code.

In experimental:

L:3593

               if (h == NULL  &&  sum_wohnung > sum_industrie  &&  sum_wohnung > sum_gewerbe) {                                                                                                          
                       h = hausbauer_t::get_wohnhaus(0, current_month, cl, new_town);                                                                                                                    
                       if (h != NULL) {                                                                                                                                                                  
                               // will be aligned next to a street                                                                                                                                        
                               won += h->get_level() * 10;                                                                                                                                                
                       }                                                                                                                                                                                  
               }                                                                                                                                                                                          


... which appears to call " 'housebuilder_t': get a family house, passing (0, the current month, the climate, and whether it's a new town) as arguments]. All of which is great but I can't see where the hausbauer_t comes from, grepping though the files doesn't turn anything up, it's called a lot but where does it come from?

EDIT: oh, it was in a subdirectory.

sdog

it's in bauer/hausbauer.cc

it just calls  get_aus_liste  (trans: get_from_list), which does the actual work (line 696 in std)*
i think it randomly selects a house fitting to the conditions.

*if i knew you're looking to experimental too, i wouldn't have needed to look into standard, i know even less.

ps.: just post any comments you don't understand, i (or others) will try  to translate them for you.

diesseits

Yes, I'm looking at that now, but I'm confused because it already seems to be written as if it should behave as I've described, with the "allow_earlier" being set, in this instance, from "new_town" being passed to it. Then it appears to give a 35% chance of an old building being allowed to be selected from the list. So maybe it's a bug that prevents old buildings being used?


static const haus_besch_t* get_aus_liste(const vector_tpl<const haus_besch_t*>& liste, int level, uint16 time, climate cl, bool allow_earlier)                                                             
{                                                                                                                                                                                                         
        weighted_vector_tpl<const haus_besch_t *> auswahl(16);                                                                                                                                             
                                                                                                                                                                                                           
//      DBG_MESSAGE("hausbauer_t::get_aus_liste()","target level %i", level );                                                                                                                             
        const haus_besch_t *besch_at_least=NULL;                                                                                                                                                           
        for (vector_tpl<const haus_besch_t*>::const_iterator i = liste.begin(), end = liste.end(); i != end; ++i) {                                                                                       
                const haus_besch_t* besch = *i;                                                                                                                                                           
                const uint16 random = simrand(100);                                                                                                                                                       
                if(     besch->is_allowed_climate(cl)  &&                                                                                                                                                 
                        besch->get_chance()>0  &&                                                                                                                                                         
                        (time==0  ||  (besch->get_intro_year_month()<=time  &&  ((allow_earlier && random > 65) || besch->get_retire_year_month()>time)))) {                                               
                        besch_at_least = besch;                                                                                                                                                           
                }                                                                                                                                                                                         
                                                                                                                                                                                                           
                const int thislevel = besch->get_level();                                                                                                                                                 
                if(thislevel>level) {n                                                                                                                                                                     
                        if (auswahl.empty()) {                                                                                                                                                             
                                // continue with search ...                                                                                                                                               
                                level = thislevel;                                                                                                                                                         
                        }                                                                                                                                                                                 
                        else {                                                                                                                                                                             
                                // ok, we found something                                                                                                                                                 
                                break;                                                                                                                                                                     
                        }                                                     
                }

                if(thislevel==level  &&  besch->get_chance()>0) {
                        if(cl==MAX_CLIMATES  ||  besch->is_allowed_climate(cl)) {
                                if(time==0  ||  (besch->get_intro_year_month()<=time  &&  ((allow_earlier && random > 65) || besch->get_retire_year_month()>time))) {
//                              DBG_MESSAGE("hausbauer_t::get_aus_liste()","appended %s at %i", besch->get_name(), thislevel );                                                                           
                                        auswahl.append(besch,besch->get_chance(),4);
                                }
                        }
                }
        }

        if(auswahl.get_sum_weight()==0) {
                // this is some level below, but at least it is something                                                                                                                                 
                return besch_at_least;
        }
        if(auswahl.get_count()==1) {
                return auswahl.front();
        }
        // now there is something to choose                                                                                                                                                               
        return auswahl.at_weight( simrand(auswahl.get_sum_weight()) );
}



sdog

  if(     besch->is_allowed_climate(cl)  &&
                        besch->get_chance()>0  &&
                        (time==0  ||  (besch->get_intro_year_month()<=time  &&  besch->get_retire_year_month()>time))) {
                        besch_at_least = besch;
                }

it's different in standard, so james should likely know more about it.

diesseits

Well removing "&&  ((allow_earlier && random > 65) || besch->get_retire_year_month()>time)" gets the behaviour I want, which is fine, but I don't think that would do for a patch to simutrans. For one thing, that would mean new cities founded during the game would get all types of building, which is not necessarily what you want. An extra argument ... 'map_creation' is probably needed to go through to the building selection algorithm. Secondly, I'm nonplussed as to why the current code isn't allowing at least some old buildings through.

For really good looking maps, 'regions' of (large) towns built largely in one period's style (and small towns being built to a particular style) or another would be great, but that's a whole other level of complexity.

sdog

you could read the probability (now 1-65) from citirules.tab

i expect allow_earlier should be set to 1 only when welt is created. perhaps it is set already, or not. Have  you tried what happes if you get rid of  "&& random > 65" ?

jamespetts

The code in Experimental that you've found is code that was intended to acheive this result, but, for reasons that I have not been able to ascertain so far, oddly, it does not have that effect.
Download Simutrans-Extended.

Want to help with development? See here for things to do for coding, and here for information on how to make graphics/objects.

Follow Simutrans-Extended on Facebook.