diff --git a/ai_old.c b/ai_old.c --- a/ai_old.c +++ b/ai_old.c @@ -1075,7 +1075,7 @@ static void AiWantPassengerRoute(Player static void AiWantTrainRoute(Player *p) { uint16 r; - p->ai.railtype_to_use = p->max_railtype - 1; + p->ai.railtype_to_use = GetBestRailtype(p); r = (uint16)Random(); if (r > 0xD000) { diff --git a/engine.c b/engine.c --- a/engine.c +++ b/engine.c @@ -12,8 +12,6 @@ #include "saveload.h" #include "sprite.h" -#define UPDATE_PLAYER_RAILTYPE(e,p) if ((byte)(e->railtype + 1) > p->max_railtype) p->max_railtype = e->railtype + 1; - enum { ENGINE_AVAILABLE = 1, ENGINE_INTRODUCING = 2, @@ -755,9 +753,9 @@ void AcceptEnginePreview(Engine *e, Play { Player *p = GetPlayer(player); + assert(e->railtype < RAILTYPE_END); SETBIT(e->player_avail, player); - - UPDATE_PLAYER_RAILTYPE(e, p); + SETBIT(p->avail_railtypes, e->railtype); e->preview_player = 0xFF; InvalidateWindowClasses(WC_BUILD_VEHICLE); @@ -897,8 +895,10 @@ static void NewVehicleAvailable(Engine * // make maglev / monorail available FOR_ALL_PLAYERS(p) { - if (p->is_active) - UPDATE_PLAYER_RAILTYPE(e,p); + if (p->is_active) { + assert(e->railtype < RAILTYPE_END); + SETBIT(p->avail_railtypes, e->railtype); + } } if ((byte)index < NUM_TRAIN_ENGINES) { @@ -967,26 +967,6 @@ int32 CmdRenameEngine(int x, int y, uint return 0; } -int GetPlayerMaxRailtype(int p) -{ - Engine *e; - int rt = 0; - int i; - - for(e=_engines,i=0; i!=lengthof(_engines); e++,i++) { - if (!HASBIT(e->player_avail, p)) - continue; - - if ((i >= 27 && i < 54) || (i >= 57 && i < 84) || (i >= 89 && i < 116)) - continue; - - if (rt < e->railtype) - rt = e->railtype; - } - - return rt + 1; -} - static const SaveLoad _engine_desc[] = { SLE_VAR(Engine,intro_date, SLE_UINT16), diff --git a/main_gui.c b/main_gui.c --- a/main_gui.c +++ b/main_gui.c @@ -327,8 +327,7 @@ static void MenuClickShowAir(int index) static void MenuClickBuildRail(int index) { - Player *p = GetPlayer(_local_player); - _last_built_railtype = min(index, p->max_railtype-1); + _last_built_railtype = index; ShowBuildRailToolbar(_last_built_railtype, -1); } @@ -941,7 +940,7 @@ static void ToolbarBuildRailClick(Window { Player *p = GetPlayer(_local_player); Window *w2; - w2 = PopupMainToolbMenu(w, 457, 19, STR_1015_RAILROAD_CONSTRUCTION, p->max_railtype); + w2 = PopupMainToolbMenu(w, 457, 19, STR_1015_RAILROAD_CONSTRUCTION, GetNumRailtypes(p)); WP(w2,menu_d).sel_index = _last_built_railtype; } diff --git a/oldloader.c b/oldloader.c --- a/oldloader.c +++ b/oldloader.c @@ -1020,7 +1020,7 @@ static const OldChunks player_chunk[] = OCL_SVAR( OC_UINT8, Player, block_preview ), OCL_SVAR( OC_UINT8, Player, ai.tick ), - OCL_SVAR( OC_UINT8, Player, max_railtype ), + OCL_SVAR( OC_UINT8, Player, avail_railtypes ), OCL_SVAR( OC_TILE, Player, location_of_house ), OCL_SVAR( OC_UINT8, Player, share_owners[0] ), OCL_SVAR( OC_UINT8, Player, share_owners[1] ), diff --git a/openttd.c b/openttd.c --- a/openttd.c +++ b/openttd.c @@ -1279,6 +1279,7 @@ bool AfterLoadGame(uint version) { Window *w; ViewPort *vp; + Player *p; // in version 2.1 of the savegame, town owner was unified. if (version <= 0x200) { @@ -1432,5 +1433,9 @@ bool AfterLoadGame(uint version) } END_TILE_LOOP(tile, MapSizeX(), MapSizeY(), 0); } + FOR_ALL_PLAYERS(p) { + p->avail_railtypes = GetPlayerRailtypes(p->index); + } + return true; } diff --git a/player.h b/player.h --- a/player.h +++ b/player.h @@ -2,6 +2,8 @@ #define PLAYER_H #include "aystar.h" +#include "engine.h" +#include "rail.h" typedef struct PlayerEconomyEntry { int32 income; @@ -157,7 +159,7 @@ typedef struct Player { byte player_color; byte player_money_fraction; - byte max_railtype; + byte avail_railtypes; byte block_preview; PlayerID index; @@ -203,6 +205,44 @@ static inline Player* GetPlayer(uint i) return &_players[i]; } +/** Returns the number of rail types the player can build + * @param *p Player in question + */ +static inline int GetNumRailtypes(Player *p) +{ + int num = 0; + int i; + + for (i = 0; i < (int)sizeof(p->avail_railtypes) * 8; i++) + if (HASBIT(p->avail_railtypes, i)) num++; + + assert(num <= RAILTYPE_END); + return num; +} + +byte GetPlayerRailtypes(int p); + +/** Finds out if a Player has a certain railtype available + */ +static inline bool HasRailtypeAvail(Player *p, RailType Railtype) +{ + return HASBIT(p->avail_railtypes, Railtype); +} + +/** Returns the "best" railtype a player can build. + * As the AI doesn't know what the BEST one is, we + * have our own priority list here. When adding + * new railtypes, modify this function + * @param p the player "in action" + * @return The "best" railtype a player has available + */ +static inline byte GetBestRailtype(Player *p) +{ + if (HasRailtypeAvail(p, RAILTYPE_MAGLEV)) return RAILTYPE_MAGLEV; + if (HasRailtypeAvail(p, RAILTYPE_MONO)) return RAILTYPE_MONO; + return RAILTYPE_RAIL; +} + #define IS_HUMAN_PLAYER(p) (!GetPlayer((byte)(p))->is_ai) #define IS_INTERACTIVE_PLAYER(p) (((byte)p) == _local_player) diff --git a/players.c b/players.c --- a/players.c +++ b/players.c @@ -487,7 +487,7 @@ Player *DoStartupNewPlayer(bool is_ai) p->ai.state = 5; /* AIS_WANT_NEW_ROUTE */ p->share_owners[0] = p->share_owners[1] = p->share_owners[2] = p->share_owners[3] = 0xFF; - p->max_railtype = GetPlayerMaxRailtype(index); + p->avail_railtypes = GetPlayerRailtypes(index); p->inaugurated_year = _cur_year; p->face = Random(); @@ -622,6 +622,27 @@ void DeletePlayerWindows(int pi) DeleteWindowById(WC_BUY_COMPANY, pi); } +byte GetPlayerRailtypes(int p) +{ + Engine *e; + int rt = 0; + int i; + + for(e = _engines, i = 0; i != lengthof(_engines); e++, i++) { + if (!HASBIT(e->player_avail, p)) + continue; + + /* Skip all wagons */ + if ((i >= 27 && i < 54) || (i >= 57 && i < 84) || (i >= 89 && i < 116)) + continue; + + assert(e->railtype < RAILTYPE_END); + SETBIT(rt, e->railtype); + } + + return rt; +} + static void DeletePlayerStuff(int pi) { Player *p; @@ -969,7 +990,7 @@ static const SaveLoad _player_desc[] = { SLE_VAR(Player,player_color, SLE_UINT8), SLE_VAR(Player,player_money_fraction,SLE_UINT8), - SLE_VAR(Player,max_railtype, SLE_UINT8), + SLE_VAR(Player,avail_railtypes, SLE_UINT8), SLE_VAR(Player,block_preview, SLE_UINT8), SLE_VAR(Player,cargo_types, SLE_UINT16), diff --git a/table/engines.h b/table/engines.h --- a/table/engines.h +++ b/table/engines.h @@ -9,9 +9,18 @@ /** Writes the properties of a vehicle into the EngineInfo struct. * @see EngineInfo + * @param a Introduction date + * @param e Rail Type of the vehicle + * @param f Bitmask of the climates */ - #define MK(a,b,c,d,e,f) {a,b,c,d,((e)<<4)|(f)} +/** Writes the properties of a train carriage into the EngineInfo struct. + * @see EngineInfo + * @param a Introduction date + * @param e Rail Type of the vehicle + * @param f Bitmask of the climates + * @note the 0x80 in parameter b sets the "is carriage bit" + */ #define MW(a,b,c,d,e,f) {a,b|0x80,c,d,((e)<<4)|(f)} EngineInfo _engine_info[TOTAL_NUM_ENGINES] = { diff --git a/train_gui.c b/train_gui.c --- a/train_gui.c +++ b/train_gui.c @@ -323,7 +323,7 @@ static void ShowBuildTrainWindow(TileInd WP(w,buildtrain_d).railtype = _m[tile].m3 & 0xF; } else { w->caption_color = _local_player; - WP(w,buildtrain_d).railtype = GetPlayer(_local_player)->max_railtype - 1; + WP(w,buildtrain_d).railtype = GetBestRailtype(GetPlayer(_local_player)); } } diff --git a/vehicle.h b/vehicle.h --- a/vehicle.h +++ b/vehicle.h @@ -435,7 +435,7 @@ static inline Vehicle *GetFirstVehicleFr } /* Validate functions for rail building */ -static inline bool ValParamRailtype(uint32 rail) { return rail <= GetPlayer(_current_player)->max_railtype;} +static inline bool ValParamRailtype(uint32 rail) { return HASBIT(GetPlayer(_current_player)->avail_railtypes, rail);} // NOSAVE: Can be regenerated by inspecting the vehicles. VARDEF VehicleID _vehicle_position_hash[0x1000];