diff --git a/src/ai/ai.cpp b/src/ai/ai.cpp --- a/src/ai/ai.cpp +++ b/src/ai/ai.cpp @@ -2,6 +2,7 @@ #include "../stdafx.h" #include "../openttd.h" +#include "../player.h" #include "../variables.h" #include "../command_func.h" #include "../network/network.h" diff --git a/src/ai/default/default.cpp b/src/ai/default/default.cpp --- a/src/ai/default/default.cpp +++ b/src/ai/default/default.cpp @@ -27,11 +27,12 @@ #include "../../window_func.h" #include "../../vehicle_func.h" #include "../../functions.h" +#include "../../saveload.h" #include "default.h" - // remove some day perhaps? static uint _ai_service_interval; +PlayerAI _players_ai[MAX_PLAYERS]; typedef void AiStateAction(Player *p); @@ -74,14 +75,14 @@ static TrackBits GetRailTrackStatus(Tile static void AiCase0(Player *p) { - p->ai.state = AIS_REMOVE_TRACK; - p->ai.state_counter = 0; + _players_ai[p->index].state = AIS_REMOVE_TRACK; + _players_ai[p->index].state_counter = 0; } static void AiCase1(Player *p) { - p->ai.cur_veh = NULL; - p->ai.state = AIS_VEH_LOOP; + _players_ai[p->index].cur_veh = NULL; + _players_ai[p->index].state = AIS_VEH_LOOP; } static void AiStateVehLoop(Player *p) @@ -89,7 +90,7 @@ static void AiStateVehLoop(Player *p) Vehicle *v; uint index; - index = (p->ai.cur_veh == NULL) ? 0 : p->ai.cur_veh->index + 1; + index = (_players_ai[p->index].cur_veh == NULL) ? 0 : _players_ai[p->index].cur_veh->index + 1; FOR_ALL_VEHICLES_FROM(v, index) { if (v->owner != _current_player) continue; @@ -101,8 +102,8 @@ static void AiStateVehLoop(Player *p) /* replace engine? */ if (v->type == VEH_TRAIN && v->engine_type < 3 && (_price.build_railvehicle >> 3) < p->player_money) { - p->ai.state = AIS_VEH_CHECK_REPLACE_VEHICLE; - p->ai.cur_veh = v; + _players_ai[p->index].state = AIS_VEH_CHECK_REPLACE_VEHICLE; + _players_ai[p->index].cur_veh = v; return; } @@ -110,9 +111,9 @@ static void AiStateVehLoop(Player *p) if (v->age >= 730 && v->profit_last_year < _price.station_value * 5 && v->profit_this_year < _price.station_value * 5) { - p->ai.state_counter = 0; - p->ai.state = AIS_SELL_VEHICLE; - p->ai.cur_veh = v; + _players_ai[p->index].state_counter = 0; + _players_ai[p->index].state = AIS_SELL_VEHICLE; + _players_ai[p->index].cur_veh = v; return; } @@ -121,15 +122,15 @@ static void AiStateVehLoop(Player *p) v->age != 0 && GetEngine(v->engine_type)->reliability < 35389 )) { - p->ai.state = AIS_VEH_CHECK_REPLACE_VEHICLE; - p->ai.cur_veh = v; + _players_ai[p->index].state = AIS_VEH_CHECK_REPLACE_VEHICLE; + _players_ai[p->index].cur_veh = v; return; } } } - p->ai.state = AIS_WANT_NEW_ROUTE; - p->ai.state_counter = 0; + _players_ai[p->index].state = AIS_WANT_NEW_ROUTE; + _players_ai[p->index].state_counter = 0; } static EngineID AiChooseTrainToBuild(RailType railtype, Money money, byte flag, TileIndex tile) @@ -230,7 +231,7 @@ static Money AiGetBasePrice(const Player Money base = _price.station_value; // adjust base price when more expensive vehicles are available - switch (p->ai.railtype_to_use) { + switch (_players_ai[p->index].railtype_to_use) { default: NOT_REACHED(); case RAILTYPE_RAIL: break; case RAILTYPE_ELECTRIC: break; @@ -277,18 +278,18 @@ static EngineID AiChooseShipToReplaceWit static void AiHandleGotoDepot(Player *p, int cmd) { - if (p->ai.cur_veh->current_order.type != OT_GOTO_DEPOT) - DoCommand(0, p->ai.cur_veh->index, 0, DC_EXEC, cmd); - - if (++p->ai.state_counter <= 1387) { - p->ai.state = AIS_VEH_DO_REPLACE_VEHICLE; + if (_players_ai[p->index].cur_veh->current_order.type != OT_GOTO_DEPOT) + DoCommand(0, _players_ai[p->index].cur_veh->index, 0, DC_EXEC, cmd); + + if (++_players_ai[p->index].state_counter <= 1387) { + _players_ai[p->index].state = AIS_VEH_DO_REPLACE_VEHICLE; return; } - if (p->ai.cur_veh->current_order.type == OT_GOTO_DEPOT) { - p->ai.cur_veh->current_order.type = OT_DUMMY; - p->ai.cur_veh->current_order.flags = 0; - InvalidateWindow(WC_VEHICLE_VIEW, p->ai.cur_veh->index); + if (_players_ai[p->index].cur_veh->current_order.type == OT_GOTO_DEPOT) { + _players_ai[p->index].cur_veh->current_order.type = OT_DUMMY; + _players_ai[p->index].cur_veh->current_order.flags = 0; + InvalidateWindow(WC_VEHICLE_VIEW, _players_ai[p->index].cur_veh->index); } } @@ -304,7 +305,7 @@ static void AiRestoreVehicleOrders(Vehic static void AiHandleReplaceTrain(Player *p) { - const Vehicle* v = p->ai.cur_veh; + const Vehicle* v = _players_ai[p->index].cur_veh; BackuppedOrders orderbak; EngineID veh; @@ -334,7 +335,7 @@ static void AiHandleReplaceTrain(Player static void AiHandleReplaceRoadVeh(Player *p) { - const Vehicle* v = p->ai.cur_veh; + const Vehicle* v = _players_ai[p->index].cur_veh; BackuppedOrders orderbak[1]; EngineID veh; @@ -363,7 +364,7 @@ static void AiHandleReplaceRoadVeh(Playe static void AiHandleReplaceAircraft(Player *p) { - const Vehicle* v = p->ai.cur_veh; + const Vehicle* v = _players_ai[p->index].cur_veh; BackuppedOrders orderbak[1]; EngineID veh; @@ -414,24 +415,24 @@ static DoReplaceProc* const _veh_do_repl static void AiStateCheckReplaceVehicle(Player *p) { - const Vehicle* v = p->ai.cur_veh; + const Vehicle* v = _players_ai[p->index].cur_veh; if (!v->IsValid() || v->owner != _current_player || v->type > VEH_SHIP || _veh_check_replace_proc[v->type - VEH_TRAIN](p, v) == INVALID_ENGINE) { - p->ai.state = AIS_VEH_LOOP; + _players_ai[p->index].state = AIS_VEH_LOOP; } else { - p->ai.state_counter = 0; - p->ai.state = AIS_VEH_DO_REPLACE_VEHICLE; + _players_ai[p->index].state_counter = 0; + _players_ai[p->index].state = AIS_VEH_DO_REPLACE_VEHICLE; } } static void AiStateDoReplaceVehicle(Player *p) { - const Vehicle* v = p->ai.cur_veh; - - p->ai.state = AIS_VEH_LOOP; + const Vehicle* v = _players_ai[p->index].cur_veh; + + _players_ai[p->index].state = AIS_VEH_LOOP; // vehicle is not owned by the player anymore, something went very wrong. if (!v->IsValid() || v->owner != _current_player) return; _veh_do_replace_proc[v->type - VEH_TRAIN](p); @@ -641,8 +642,8 @@ static bool AiCheckIfRouteIsGood(Player /* Make sure distance to closest station is < min_distance tiles. */ if (dist != 0xFFFF && dist > min_distance) return false; - if (p->ai.route_type_mask != 0 && - !(p->ai.route_type_mask & bitmask) && + if (_players_ai[p->index].route_type_mask != 0 && + !(_players_ai[p->index].route_type_mask & bitmask) && !Chance16(1, 5)) { return false; } @@ -670,7 +671,7 @@ static bool AiCheckIfRouteIsGood(Player } } - p->ai.route_type_mask |= bitmask; + _players_ai[p->index].route_type_mask |= bitmask; return true; } @@ -711,85 +712,85 @@ static void AiWantLongIndustryRoute(Play if (!AiCheckIfRouteIsGood(p, &fr, 1)) return; // Fill the source field - p->ai.dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to); - p->ai.src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from); - - p->ai.src.use_tile = 0; - p->ai.src.rand_rng = 9; - p->ai.src.cur_building_rule = 0xFF; - p->ai.src.unk6 = 1; - p->ai.src.unk7 = 0; - p->ai.src.buildcmd_a = 0x24; - p->ai.src.buildcmd_b = 0xFF; - p->ai.src.direction = AiGetDirectionBetweenTiles( - p->ai.src.spec_tile, - p->ai.dst.spec_tile + _players_ai[p->index].dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to); + _players_ai[p->index].src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from); + + _players_ai[p->index].src.use_tile = 0; + _players_ai[p->index].src.rand_rng = 9; + _players_ai[p->index].src.cur_building_rule = 0xFF; + _players_ai[p->index].src.unk6 = 1; + _players_ai[p->index].src.unk7 = 0; + _players_ai[p->index].src.buildcmd_a = 0x24; + _players_ai[p->index].src.buildcmd_b = 0xFF; + _players_ai[p->index].src.direction = AiGetDirectionBetweenTiles( + _players_ai[p->index].src.spec_tile, + _players_ai[p->index].dst.spec_tile ); - p->ai.src.cargo = fr.cargo | 0x80; + _players_ai[p->index].src.cargo = fr.cargo | 0x80; // Fill the dest field - p->ai.dst.use_tile = 0; - p->ai.dst.rand_rng = 9; - p->ai.dst.cur_building_rule = 0xFF; - p->ai.dst.unk6 = 1; - p->ai.dst.unk7 = 0; - p->ai.dst.buildcmd_a = 0x34; - p->ai.dst.buildcmd_b = 0xFF; - p->ai.dst.direction = AiGetDirectionBetweenTiles( - p->ai.dst.spec_tile, - p->ai.src.spec_tile + _players_ai[p->index].dst.use_tile = 0; + _players_ai[p->index].dst.rand_rng = 9; + _players_ai[p->index].dst.cur_building_rule = 0xFF; + _players_ai[p->index].dst.unk6 = 1; + _players_ai[p->index].dst.unk7 = 0; + _players_ai[p->index].dst.buildcmd_a = 0x34; + _players_ai[p->index].dst.buildcmd_b = 0xFF; + _players_ai[p->index].dst.direction = AiGetDirectionBetweenTiles( + _players_ai[p->index].dst.spec_tile, + _players_ai[p->index].src.spec_tile ); - p->ai.dst.cargo = fr.cargo; + _players_ai[p->index].dst.cargo = fr.cargo; // Fill middle field 1 - p->ai.mid1.spec_tile = AiGetPctTileBetween( - p->ai.src.spec_tile, - p->ai.dst.spec_tile, + _players_ai[p->index].mid1.spec_tile = AiGetPctTileBetween( + _players_ai[p->index].src.spec_tile, + _players_ai[p->index].dst.spec_tile, 0x55 ); - p->ai.mid1.use_tile = 0; - p->ai.mid1.rand_rng = 6; - p->ai.mid1.cur_building_rule = 0xFF; - p->ai.mid1.unk6 = 2; - p->ai.mid1.unk7 = 1; - p->ai.mid1.buildcmd_a = 0x30; - p->ai.mid1.buildcmd_b = 0xFF; - p->ai.mid1.direction = p->ai.src.direction; - p->ai.mid1.cargo = fr.cargo; + _players_ai[p->index].mid1.use_tile = 0; + _players_ai[p->index].mid1.rand_rng = 6; + _players_ai[p->index].mid1.cur_building_rule = 0xFF; + _players_ai[p->index].mid1.unk6 = 2; + _players_ai[p->index].mid1.unk7 = 1; + _players_ai[p->index].mid1.buildcmd_a = 0x30; + _players_ai[p->index].mid1.buildcmd_b = 0xFF; + _players_ai[p->index].mid1.direction = _players_ai[p->index].src.direction; + _players_ai[p->index].mid1.cargo = fr.cargo; // Fill middle field 2 - p->ai.mid2.spec_tile = AiGetPctTileBetween( - p->ai.src.spec_tile, - p->ai.dst.spec_tile, + _players_ai[p->index].mid2.spec_tile = AiGetPctTileBetween( + _players_ai[p->index].src.spec_tile, + _players_ai[p->index].dst.spec_tile, 0xAA ); - p->ai.mid2.use_tile = 0; - p->ai.mid2.rand_rng = 6; - p->ai.mid2.cur_building_rule = 0xFF; - p->ai.mid2.unk6 = 2; - p->ai.mid2.unk7 = 1; - p->ai.mid2.buildcmd_a = 0xFF; - p->ai.mid2.buildcmd_b = 0xFF; - p->ai.mid2.direction = p->ai.dst.direction; - p->ai.mid2.cargo = fr.cargo; + _players_ai[p->index].mid2.use_tile = 0; + _players_ai[p->index].mid2.rand_rng = 6; + _players_ai[p->index].mid2.cur_building_rule = 0xFF; + _players_ai[p->index].mid2.unk6 = 2; + _players_ai[p->index].mid2.unk7 = 1; + _players_ai[p->index].mid2.buildcmd_a = 0xFF; + _players_ai[p->index].mid2.buildcmd_b = 0xFF; + _players_ai[p->index].mid2.direction = _players_ai[p->index].dst.direction; + _players_ai[p->index].mid2.cargo = fr.cargo; // Fill common fields - p->ai.cargo_type = fr.cargo; - p->ai.num_wagons = 3; - p->ai.build_kind = 2; - p->ai.num_build_rec = 4; - p->ai.num_loco_to_build = 2; - p->ai.num_want_fullload = 2; - p->ai.wagon_list[0] = INVALID_VEHICLE; - p->ai.order_list_blocks[0] = 0; - p->ai.order_list_blocks[1] = 1; - p->ai.order_list_blocks[2] = 255; - - p->ai.state = AIS_BUILD_DEFAULT_RAIL_BLOCKS; - p->ai.state_mode = UCHAR_MAX; - p->ai.state_counter = 0; - p->ai.timeout_counter = 0; + _players_ai[p->index].cargo_type = fr.cargo; + _players_ai[p->index].num_wagons = 3; + _players_ai[p->index].build_kind = 2; + _players_ai[p->index].num_build_rec = 4; + _players_ai[p->index].num_loco_to_build = 2; + _players_ai[p->index].num_want_fullload = 2; + _players_ai[p->index].wagon_list[0] = INVALID_VEHICLE; + _players_ai[p->index].order_list_blocks[0] = 0; + _players_ai[p->index].order_list_blocks[1] = 1; + _players_ai[p->index].order_list_blocks[2] = 255; + + _players_ai[p->index].state = AIS_BUILD_DEFAULT_RAIL_BLOCKS; + _players_ai[p->index].state_mode = UCHAR_MAX; + _players_ai[p->index].state_counter = 0; + _players_ai[p->index].timeout_counter = 0; } static void AiWantMediumIndustryRoute(Player *p) @@ -814,50 +815,50 @@ static void AiWantMediumIndustryRoute(Pl if (!AiCheckIfRouteIsGood(p, &fr, 1)) return; // Fill the source field - p->ai.src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from); - p->ai.src.use_tile = 0; - p->ai.src.rand_rng = 9; - p->ai.src.cur_building_rule = 0xFF; - p->ai.src.unk6 = 1; - p->ai.src.unk7 = 0; - p->ai.src.buildcmd_a = 0x10; - p->ai.src.buildcmd_b = 0xFF; - p->ai.src.direction = AiGetDirectionBetweenTiles( + _players_ai[p->index].src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from); + _players_ai[p->index].src.use_tile = 0; + _players_ai[p->index].src.rand_rng = 9; + _players_ai[p->index].src.cur_building_rule = 0xFF; + _players_ai[p->index].src.unk6 = 1; + _players_ai[p->index].src.unk7 = 0; + _players_ai[p->index].src.buildcmd_a = 0x10; + _players_ai[p->index].src.buildcmd_b = 0xFF; + _players_ai[p->index].src.direction = AiGetDirectionBetweenTiles( GET_TOWN_OR_INDUSTRY_TILE(fr.from), GET_TOWN_OR_INDUSTRY_TILE(fr.to) ); - p->ai.src.cargo = fr.cargo | 0x80; + _players_ai[p->index].src.cargo = fr.cargo | 0x80; // Fill the dest field - p->ai.dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to); - p->ai.dst.use_tile = 0; - p->ai.dst.rand_rng = 9; - p->ai.dst.cur_building_rule = 0xFF; - p->ai.dst.unk6 = 1; - p->ai.dst.unk7 = 0; - p->ai.dst.buildcmd_a = 0xFF; - p->ai.dst.buildcmd_b = 0xFF; - p->ai.dst.direction = AiGetDirectionBetweenTiles( + _players_ai[p->index].dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to); + _players_ai[p->index].dst.use_tile = 0; + _players_ai[p->index].dst.rand_rng = 9; + _players_ai[p->index].dst.cur_building_rule = 0xFF; + _players_ai[p->index].dst.unk6 = 1; + _players_ai[p->index].dst.unk7 = 0; + _players_ai[p->index].dst.buildcmd_a = 0xFF; + _players_ai[p->index].dst.buildcmd_b = 0xFF; + _players_ai[p->index].dst.direction = AiGetDirectionBetweenTiles( GET_TOWN_OR_INDUSTRY_TILE(fr.to), GET_TOWN_OR_INDUSTRY_TILE(fr.from) ); - p->ai.dst.cargo = fr.cargo; + _players_ai[p->index].dst.cargo = fr.cargo; // Fill common fields - p->ai.cargo_type = fr.cargo; - p->ai.num_wagons = 3; - p->ai.build_kind = 1; - p->ai.num_build_rec = 2; - p->ai.num_loco_to_build = 1; - p->ai.num_want_fullload = 1; - p->ai.wagon_list[0] = INVALID_VEHICLE; - p->ai.order_list_blocks[0] = 0; - p->ai.order_list_blocks[1] = 1; - p->ai.order_list_blocks[2] = 255; - p->ai.state = AIS_BUILD_DEFAULT_RAIL_BLOCKS; - p->ai.state_mode = UCHAR_MAX; - p->ai.state_counter = 0; - p->ai.timeout_counter = 0; + _players_ai[p->index].cargo_type = fr.cargo; + _players_ai[p->index].num_wagons = 3; + _players_ai[p->index].build_kind = 1; + _players_ai[p->index].num_build_rec = 2; + _players_ai[p->index].num_loco_to_build = 1; + _players_ai[p->index].num_want_fullload = 1; + _players_ai[p->index].wagon_list[0] = INVALID_VEHICLE; + _players_ai[p->index].order_list_blocks[0] = 0; + _players_ai[p->index].order_list_blocks[1] = 1; + _players_ai[p->index].order_list_blocks[2] = 255; + _players_ai[p->index].state = AIS_BUILD_DEFAULT_RAIL_BLOCKS; + _players_ai[p->index].state_mode = UCHAR_MAX; + _players_ai[p->index].state_counter = 0; + _players_ai[p->index].timeout_counter = 0; } static void AiWantShortIndustryRoute(Player *p) @@ -882,50 +883,50 @@ static void AiWantShortIndustryRoute(Pla if (!AiCheckIfRouteIsGood(p, &fr, 1)) return; // Fill the source field - p->ai.src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from); - p->ai.src.use_tile = 0; - p->ai.src.rand_rng = 9; - p->ai.src.cur_building_rule = 0xFF; - p->ai.src.unk6 = 1; - p->ai.src.unk7 = 0; - p->ai.src.buildcmd_a = 0x10; - p->ai.src.buildcmd_b = 0xFF; - p->ai.src.direction = AiGetDirectionBetweenTiles( + _players_ai[p->index].src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from); + _players_ai[p->index].src.use_tile = 0; + _players_ai[p->index].src.rand_rng = 9; + _players_ai[p->index].src.cur_building_rule = 0xFF; + _players_ai[p->index].src.unk6 = 1; + _players_ai[p->index].src.unk7 = 0; + _players_ai[p->index].src.buildcmd_a = 0x10; + _players_ai[p->index].src.buildcmd_b = 0xFF; + _players_ai[p->index].src.direction = AiGetDirectionBetweenTiles( GET_TOWN_OR_INDUSTRY_TILE(fr.from), GET_TOWN_OR_INDUSTRY_TILE(fr.to) ); - p->ai.src.cargo = fr.cargo | 0x80; + _players_ai[p->index].src.cargo = fr.cargo | 0x80; // Fill the dest field - p->ai.dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to); - p->ai.dst.use_tile = 0; - p->ai.dst.rand_rng = 9; - p->ai.dst.cur_building_rule = 0xFF; - p->ai.dst.unk6 = 1; - p->ai.dst.unk7 = 0; - p->ai.dst.buildcmd_a = 0xFF; - p->ai.dst.buildcmd_b = 0xFF; - p->ai.dst.direction = AiGetDirectionBetweenTiles( + _players_ai[p->index].dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to); + _players_ai[p->index].dst.use_tile = 0; + _players_ai[p->index].dst.rand_rng = 9; + _players_ai[p->index].dst.cur_building_rule = 0xFF; + _players_ai[p->index].dst.unk6 = 1; + _players_ai[p->index].dst.unk7 = 0; + _players_ai[p->index].dst.buildcmd_a = 0xFF; + _players_ai[p->index].dst.buildcmd_b = 0xFF; + _players_ai[p->index].dst.direction = AiGetDirectionBetweenTiles( GET_TOWN_OR_INDUSTRY_TILE(fr.to), GET_TOWN_OR_INDUSTRY_TILE(fr.from) ); - p->ai.dst.cargo = fr.cargo; + _players_ai[p->index].dst.cargo = fr.cargo; // Fill common fields - p->ai.cargo_type = fr.cargo; - p->ai.num_wagons = 2; - p->ai.build_kind = 1; - p->ai.num_build_rec = 2; - p->ai.num_loco_to_build = 1; - p->ai.num_want_fullload = 1; - p->ai.wagon_list[0] = INVALID_VEHICLE; - p->ai.order_list_blocks[0] = 0; - p->ai.order_list_blocks[1] = 1; - p->ai.order_list_blocks[2] = 255; - p->ai.state = AIS_BUILD_DEFAULT_RAIL_BLOCKS; - p->ai.state_mode = UCHAR_MAX; - p->ai.state_counter = 0; - p->ai.timeout_counter = 0; + _players_ai[p->index].cargo_type = fr.cargo; + _players_ai[p->index].num_wagons = 2; + _players_ai[p->index].build_kind = 1; + _players_ai[p->index].num_build_rec = 2; + _players_ai[p->index].num_loco_to_build = 1; + _players_ai[p->index].num_want_fullload = 1; + _players_ai[p->index].wagon_list[0] = INVALID_VEHICLE; + _players_ai[p->index].order_list_blocks[0] = 0; + _players_ai[p->index].order_list_blocks[1] = 1; + _players_ai[p->index].order_list_blocks[2] = 255; + _players_ai[p->index].state = AIS_BUILD_DEFAULT_RAIL_BLOCKS; + _players_ai[p->index].state_mode = UCHAR_MAX; + _players_ai[p->index].state_counter = 0; + _players_ai[p->index].timeout_counter = 0; } static void AiWantMailRoute(Player *p) @@ -951,82 +952,82 @@ static void AiWantMailRoute(Player *p) if (!AiCheckIfRouteIsGood(p, &fr, 1)) return; // Fill the source field - p->ai.src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from); - p->ai.src.use_tile = 0; - p->ai.src.rand_rng = 7; - p->ai.src.cur_building_rule = 0xFF; - p->ai.src.unk6 = 1; - p->ai.src.unk7 = 0; - p->ai.src.buildcmd_a = 0x24; - p->ai.src.buildcmd_b = 0xFF; - p->ai.src.direction = AiGetDirectionBetweenTiles( + _players_ai[p->index].src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from); + _players_ai[p->index].src.use_tile = 0; + _players_ai[p->index].src.rand_rng = 7; + _players_ai[p->index].src.cur_building_rule = 0xFF; + _players_ai[p->index].src.unk6 = 1; + _players_ai[p->index].src.unk7 = 0; + _players_ai[p->index].src.buildcmd_a = 0x24; + _players_ai[p->index].src.buildcmd_b = 0xFF; + _players_ai[p->index].src.direction = AiGetDirectionBetweenTiles( GET_TOWN_OR_INDUSTRY_TILE(fr.from), GET_TOWN_OR_INDUSTRY_TILE(fr.to) ); - p->ai.src.cargo = fr.cargo; + _players_ai[p->index].src.cargo = fr.cargo; // Fill the dest field - p->ai.dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to); - p->ai.dst.use_tile = 0; - p->ai.dst.rand_rng = 7; - p->ai.dst.cur_building_rule = 0xFF; - p->ai.dst.unk6 = 1; - p->ai.dst.unk7 = 0; - p->ai.dst.buildcmd_a = 0x34; - p->ai.dst.buildcmd_b = 0xFF; - p->ai.dst.direction = AiGetDirectionBetweenTiles( + _players_ai[p->index].dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to); + _players_ai[p->index].dst.use_tile = 0; + _players_ai[p->index].dst.rand_rng = 7; + _players_ai[p->index].dst.cur_building_rule = 0xFF; + _players_ai[p->index].dst.unk6 = 1; + _players_ai[p->index].dst.unk7 = 0; + _players_ai[p->index].dst.buildcmd_a = 0x34; + _players_ai[p->index].dst.buildcmd_b = 0xFF; + _players_ai[p->index].dst.direction = AiGetDirectionBetweenTiles( GET_TOWN_OR_INDUSTRY_TILE(fr.to), GET_TOWN_OR_INDUSTRY_TILE(fr.from) ); - p->ai.dst.cargo = fr.cargo; + _players_ai[p->index].dst.cargo = fr.cargo; // Fill middle field 1 - p->ai.mid1.spec_tile = AiGetPctTileBetween( + _players_ai[p->index].mid1.spec_tile = AiGetPctTileBetween( GET_TOWN_OR_INDUSTRY_TILE(fr.from), GET_TOWN_OR_INDUSTRY_TILE(fr.to), 0x55 ); - p->ai.mid1.use_tile = 0; - p->ai.mid1.rand_rng = 6; - p->ai.mid1.cur_building_rule = 0xFF; - p->ai.mid1.unk6 = 2; - p->ai.mid1.unk7 = 1; - p->ai.mid1.buildcmd_a = 0x30; - p->ai.mid1.buildcmd_b = 0xFF; - p->ai.mid1.direction = p->ai.src.direction; - p->ai.mid1.cargo = fr.cargo; + _players_ai[p->index].mid1.use_tile = 0; + _players_ai[p->index].mid1.rand_rng = 6; + _players_ai[p->index].mid1.cur_building_rule = 0xFF; + _players_ai[p->index].mid1.unk6 = 2; + _players_ai[p->index].mid1.unk7 = 1; + _players_ai[p->index].mid1.buildcmd_a = 0x30; + _players_ai[p->index].mid1.buildcmd_b = 0xFF; + _players_ai[p->index].mid1.direction = _players_ai[p->index].src.direction; + _players_ai[p->index].mid1.cargo = fr.cargo; // Fill middle field 2 - p->ai.mid2.spec_tile = AiGetPctTileBetween( + _players_ai[p->index].mid2.spec_tile = AiGetPctTileBetween( GET_TOWN_OR_INDUSTRY_TILE(fr.from), GET_TOWN_OR_INDUSTRY_TILE(fr.to), 0xAA ); - p->ai.mid2.use_tile = 0; - p->ai.mid2.rand_rng = 6; - p->ai.mid2.cur_building_rule = 0xFF; - p->ai.mid2.unk6 = 2; - p->ai.mid2.unk7 = 1; - p->ai.mid2.buildcmd_a = 0xFF; - p->ai.mid2.buildcmd_b = 0xFF; - p->ai.mid2.direction = p->ai.dst.direction; - p->ai.mid2.cargo = fr.cargo; + _players_ai[p->index].mid2.use_tile = 0; + _players_ai[p->index].mid2.rand_rng = 6; + _players_ai[p->index].mid2.cur_building_rule = 0xFF; + _players_ai[p->index].mid2.unk6 = 2; + _players_ai[p->index].mid2.unk7 = 1; + _players_ai[p->index].mid2.buildcmd_a = 0xFF; + _players_ai[p->index].mid2.buildcmd_b = 0xFF; + _players_ai[p->index].mid2.direction = _players_ai[p->index].dst.direction; + _players_ai[p->index].mid2.cargo = fr.cargo; // Fill common fields - p->ai.cargo_type = fr.cargo; - p->ai.num_wagons = 3; - p->ai.build_kind = 2; - p->ai.num_build_rec = 4; - p->ai.num_loco_to_build = 2; - p->ai.num_want_fullload = 0; - p->ai.wagon_list[0] = INVALID_VEHICLE; - p->ai.order_list_blocks[0] = 0; - p->ai.order_list_blocks[1] = 1; - p->ai.order_list_blocks[2] = 255; - p->ai.state = AIS_BUILD_DEFAULT_RAIL_BLOCKS; - p->ai.state_mode = UCHAR_MAX; - p->ai.state_counter = 0; - p->ai.timeout_counter = 0; + _players_ai[p->index].cargo_type = fr.cargo; + _players_ai[p->index].num_wagons = 3; + _players_ai[p->index].build_kind = 2; + _players_ai[p->index].num_build_rec = 4; + _players_ai[p->index].num_loco_to_build = 2; + _players_ai[p->index].num_want_fullload = 0; + _players_ai[p->index].wagon_list[0] = INVALID_VEHICLE; + _players_ai[p->index].order_list_blocks[0] = 0; + _players_ai[p->index].order_list_blocks[1] = 1; + _players_ai[p->index].order_list_blocks[2] = 255; + _players_ai[p->index].state = AIS_BUILD_DEFAULT_RAIL_BLOCKS; + _players_ai[p->index].state_mode = UCHAR_MAX; + _players_ai[p->index].state_counter = 0; + _players_ai[p->index].timeout_counter = 0; } static void AiWantPassengerRoute(Player *p) @@ -1052,57 +1053,57 @@ static void AiWantPassengerRoute(Player if (!AiCheckIfRouteIsGood(p, &fr, 1)) return; // Fill the source field - p->ai.src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from); - p->ai.src.use_tile = 0; - p->ai.src.rand_rng = 7; - p->ai.src.cur_building_rule = 0xFF; - p->ai.src.unk6 = 1; - p->ai.src.unk7 = 0; - p->ai.src.buildcmd_a = 0x10; - p->ai.src.buildcmd_b = 0xFF; - p->ai.src.direction = AiGetDirectionBetweenTiles( + _players_ai[p->index].src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from); + _players_ai[p->index].src.use_tile = 0; + _players_ai[p->index].src.rand_rng = 7; + _players_ai[p->index].src.cur_building_rule = 0xFF; + _players_ai[p->index].src.unk6 = 1; + _players_ai[p->index].src.unk7 = 0; + _players_ai[p->index].src.buildcmd_a = 0x10; + _players_ai[p->index].src.buildcmd_b = 0xFF; + _players_ai[p->index].src.direction = AiGetDirectionBetweenTiles( GET_TOWN_OR_INDUSTRY_TILE(fr.from), GET_TOWN_OR_INDUSTRY_TILE(fr.to) ); - p->ai.src.cargo = fr.cargo; + _players_ai[p->index].src.cargo = fr.cargo; // Fill the dest field - p->ai.dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to); - p->ai.dst.use_tile = 0; - p->ai.dst.rand_rng = 7; - p->ai.dst.cur_building_rule = 0xFF; - p->ai.dst.unk6 = 1; - p->ai.dst.unk7 = 0; - p->ai.dst.buildcmd_a = 0xFF; - p->ai.dst.buildcmd_b = 0xFF; - p->ai.dst.direction = AiGetDirectionBetweenTiles( + _players_ai[p->index].dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to); + _players_ai[p->index].dst.use_tile = 0; + _players_ai[p->index].dst.rand_rng = 7; + _players_ai[p->index].dst.cur_building_rule = 0xFF; + _players_ai[p->index].dst.unk6 = 1; + _players_ai[p->index].dst.unk7 = 0; + _players_ai[p->index].dst.buildcmd_a = 0xFF; + _players_ai[p->index].dst.buildcmd_b = 0xFF; + _players_ai[p->index].dst.direction = AiGetDirectionBetweenTiles( GET_TOWN_OR_INDUSTRY_TILE(fr.to), GET_TOWN_OR_INDUSTRY_TILE(fr.from) ); - p->ai.dst.cargo = fr.cargo; + _players_ai[p->index].dst.cargo = fr.cargo; // Fill common fields - p->ai.cargo_type = fr.cargo; - p->ai.num_wagons = 2; - p->ai.build_kind = 1; - p->ai.num_build_rec = 2; - p->ai.num_loco_to_build = 1; - p->ai.num_want_fullload = 0; - p->ai.wagon_list[0] = INVALID_VEHICLE; - p->ai.order_list_blocks[0] = 0; - p->ai.order_list_blocks[1] = 1; - p->ai.order_list_blocks[2] = 255; - p->ai.state = AIS_BUILD_DEFAULT_RAIL_BLOCKS; - p->ai.state_mode = UCHAR_MAX; - p->ai.state_counter = 0; - p->ai.timeout_counter = 0; + _players_ai[p->index].cargo_type = fr.cargo; + _players_ai[p->index].num_wagons = 2; + _players_ai[p->index].build_kind = 1; + _players_ai[p->index].num_build_rec = 2; + _players_ai[p->index].num_loco_to_build = 1; + _players_ai[p->index].num_want_fullload = 0; + _players_ai[p->index].wagon_list[0] = INVALID_VEHICLE; + _players_ai[p->index].order_list_blocks[0] = 0; + _players_ai[p->index].order_list_blocks[1] = 1; + _players_ai[p->index].order_list_blocks[2] = 255; + _players_ai[p->index].state = AIS_BUILD_DEFAULT_RAIL_BLOCKS; + _players_ai[p->index].state_mode = UCHAR_MAX; + _players_ai[p->index].state_counter = 0; + _players_ai[p->index].timeout_counter = 0; } static void AiWantTrainRoute(Player *p) { uint16 r = GB(Random(), 0, 16); - p->ai.railtype_to_use = GetBestRailtype(p); + _players_ai[p->index].railtype_to_use = GetBestRailtype(p); if (r > 0xD000) { AiWantLongIndustryRoute(p); @@ -1139,38 +1140,38 @@ static void AiWantLongRoadIndustryRoute( if (!AiCheckIfRouteIsGood(p, &fr, 2)) return; // Fill the source field - p->ai.src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from); - p->ai.src.use_tile = 0; - p->ai.src.rand_rng = 9; - p->ai.src.cur_building_rule = 0xFF; - p->ai.src.buildcmd_a = 1; - p->ai.src.direction = 0; - p->ai.src.cargo = fr.cargo | 0x80; + _players_ai[p->index].src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from); + _players_ai[p->index].src.use_tile = 0; + _players_ai[p->index].src.rand_rng = 9; + _players_ai[p->index].src.cur_building_rule = 0xFF; + _players_ai[p->index].src.buildcmd_a = 1; + _players_ai[p->index].src.direction = 0; + _players_ai[p->index].src.cargo = fr.cargo | 0x80; // Fill the dest field - p->ai.dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to); - p->ai.dst.use_tile = 0; - p->ai.dst.rand_rng = 9; - p->ai.dst.cur_building_rule = 0xFF; - p->ai.dst.buildcmd_a = 0xFF; - p->ai.dst.direction = 0; - p->ai.dst.cargo = fr.cargo; + _players_ai[p->index].dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to); + _players_ai[p->index].dst.use_tile = 0; + _players_ai[p->index].dst.rand_rng = 9; + _players_ai[p->index].dst.cur_building_rule = 0xFF; + _players_ai[p->index].dst.buildcmd_a = 0xFF; + _players_ai[p->index].dst.direction = 0; + _players_ai[p->index].dst.cargo = fr.cargo; // Fill common fields - p->ai.cargo_type = fr.cargo; - p->ai.num_build_rec = 2; - p->ai.num_loco_to_build = 5; - p->ai.num_want_fullload = 5; - -// p->ai.loco_id = INVALID_VEHICLE; - p->ai.order_list_blocks[0] = 0; - p->ai.order_list_blocks[1] = 1; - p->ai.order_list_blocks[2] = 255; - - p->ai.state = AIS_BUILD_DEFAULT_ROAD_BLOCKS; - p->ai.state_mode = UCHAR_MAX; - p->ai.state_counter = 0; - p->ai.timeout_counter = 0; + _players_ai[p->index].cargo_type = fr.cargo; + _players_ai[p->index].num_build_rec = 2; + _players_ai[p->index].num_loco_to_build = 5; + _players_ai[p->index].num_want_fullload = 5; + +// _players_ai[p->index].loco_id = INVALID_VEHICLE; + _players_ai[p->index].order_list_blocks[0] = 0; + _players_ai[p->index].order_list_blocks[1] = 1; + _players_ai[p->index].order_list_blocks[2] = 255; + + _players_ai[p->index].state = AIS_BUILD_DEFAULT_ROAD_BLOCKS; + _players_ai[p->index].state_mode = UCHAR_MAX; + _players_ai[p->index].state_counter = 0; + _players_ai[p->index].timeout_counter = 0; } static void AiWantMediumRoadIndustryRoute(Player *p) @@ -1195,38 +1196,38 @@ static void AiWantMediumRoadIndustryRout if (!AiCheckIfRouteIsGood(p, &fr, 2)) return; // Fill the source field - p->ai.src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from); - p->ai.src.use_tile = 0; - p->ai.src.rand_rng = 9; - p->ai.src.cur_building_rule = 0xFF; - p->ai.src.buildcmd_a = 1; - p->ai.src.direction = 0; - p->ai.src.cargo = fr.cargo | 0x80; + _players_ai[p->index].src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from); + _players_ai[p->index].src.use_tile = 0; + _players_ai[p->index].src.rand_rng = 9; + _players_ai[p->index].src.cur_building_rule = 0xFF; + _players_ai[p->index].src.buildcmd_a = 1; + _players_ai[p->index].src.direction = 0; + _players_ai[p->index].src.cargo = fr.cargo | 0x80; // Fill the dest field - p->ai.dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to); - p->ai.dst.use_tile = 0; - p->ai.dst.rand_rng = 9; - p->ai.dst.cur_building_rule = 0xFF; - p->ai.dst.buildcmd_a = 0xFF; - p->ai.dst.direction = 0; - p->ai.dst.cargo = fr.cargo; + _players_ai[p->index].dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to); + _players_ai[p->index].dst.use_tile = 0; + _players_ai[p->index].dst.rand_rng = 9; + _players_ai[p->index].dst.cur_building_rule = 0xFF; + _players_ai[p->index].dst.buildcmd_a = 0xFF; + _players_ai[p->index].dst.direction = 0; + _players_ai[p->index].dst.cargo = fr.cargo; // Fill common fields - p->ai.cargo_type = fr.cargo; - p->ai.num_build_rec = 2; - p->ai.num_loco_to_build = 3; - p->ai.num_want_fullload = 3; - -// p->ai.loco_id = INVALID_VEHICLE; - p->ai.order_list_blocks[0] = 0; - p->ai.order_list_blocks[1] = 1; - p->ai.order_list_blocks[2] = 255; - - p->ai.state = AIS_BUILD_DEFAULT_ROAD_BLOCKS; - p->ai.state_mode = UCHAR_MAX; - p->ai.state_counter = 0; - p->ai.timeout_counter = 0; + _players_ai[p->index].cargo_type = fr.cargo; + _players_ai[p->index].num_build_rec = 2; + _players_ai[p->index].num_loco_to_build = 3; + _players_ai[p->index].num_want_fullload = 3; + +// _players_ai[p->index].loco_id = INVALID_VEHICLE; + _players_ai[p->index].order_list_blocks[0] = 0; + _players_ai[p->index].order_list_blocks[1] = 1; + _players_ai[p->index].order_list_blocks[2] = 255; + + _players_ai[p->index].state = AIS_BUILD_DEFAULT_ROAD_BLOCKS; + _players_ai[p->index].state_mode = UCHAR_MAX; + _players_ai[p->index].state_counter = 0; + _players_ai[p->index].timeout_counter = 0; } static void AiWantLongRoadPassengerRoute(Player *p) @@ -1253,38 +1254,38 @@ static void AiWantLongRoadPassengerRoute if (!AiCheckIfRouteIsGood(p, &fr, 2)) return; // Fill the source field - p->ai.src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to); - p->ai.src.use_tile = 0; - p->ai.src.rand_rng = 10; - p->ai.src.cur_building_rule = 0xFF; - p->ai.src.buildcmd_a = 1; - p->ai.src.direction = 0; - p->ai.src.cargo = CT_PASSENGERS; + _players_ai[p->index].src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to); + _players_ai[p->index].src.use_tile = 0; + _players_ai[p->index].src.rand_rng = 10; + _players_ai[p->index].src.cur_building_rule = 0xFF; + _players_ai[p->index].src.buildcmd_a = 1; + _players_ai[p->index].src.direction = 0; + _players_ai[p->index].src.cargo = CT_PASSENGERS; // Fill the dest field - p->ai.dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from); - p->ai.dst.use_tile = 0; - p->ai.dst.rand_rng = 10; - p->ai.dst.cur_building_rule = 0xFF; - p->ai.dst.buildcmd_a = 0xFF; - p->ai.dst.direction = 0; - p->ai.dst.cargo = CT_PASSENGERS; + _players_ai[p->index].dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from); + _players_ai[p->index].dst.use_tile = 0; + _players_ai[p->index].dst.rand_rng = 10; + _players_ai[p->index].dst.cur_building_rule = 0xFF; + _players_ai[p->index].dst.buildcmd_a = 0xFF; + _players_ai[p->index].dst.direction = 0; + _players_ai[p->index].dst.cargo = CT_PASSENGERS; // Fill common fields - p->ai.cargo_type = CT_PASSENGERS; - p->ai.num_build_rec = 2; - p->ai.num_loco_to_build = 4; - p->ai.num_want_fullload = 0; - -// p->ai.loco_id = INVALID_VEHICLE; - p->ai.order_list_blocks[0] = 0; - p->ai.order_list_blocks[1] = 1; - p->ai.order_list_blocks[2] = 255; - - p->ai.state = AIS_BUILD_DEFAULT_ROAD_BLOCKS; - p->ai.state_mode = UCHAR_MAX; - p->ai.state_counter = 0; - p->ai.timeout_counter = 0; + _players_ai[p->index].cargo_type = CT_PASSENGERS; + _players_ai[p->index].num_build_rec = 2; + _players_ai[p->index].num_loco_to_build = 4; + _players_ai[p->index].num_want_fullload = 0; + +// _players_ai[p->index].loco_id = INVALID_VEHICLE; + _players_ai[p->index].order_list_blocks[0] = 0; + _players_ai[p->index].order_list_blocks[1] = 1; + _players_ai[p->index].order_list_blocks[2] = 255; + + _players_ai[p->index].state = AIS_BUILD_DEFAULT_ROAD_BLOCKS; + _players_ai[p->index].state_mode = UCHAR_MAX; + _players_ai[p->index].state_counter = 0; + _players_ai[p->index].timeout_counter = 0; } static void AiWantPassengerRouteInsideTown(Player *p) @@ -1309,38 +1310,38 @@ static void AiWantPassengerRouteInsideTo if (!AiCheckIfRouteIsGood(p, &fr, 2)) return; // Fill the source field - p->ai.src.spec_tile = t->xy; - p->ai.src.use_tile = 0; - p->ai.src.rand_rng = 10; - p->ai.src.cur_building_rule = 0xFF; - p->ai.src.buildcmd_a = 1; - p->ai.src.direction = 0; - p->ai.src.cargo = CT_PASSENGERS; + _players_ai[p->index].src.spec_tile = t->xy; + _players_ai[p->index].src.use_tile = 0; + _players_ai[p->index].src.rand_rng = 10; + _players_ai[p->index].src.cur_building_rule = 0xFF; + _players_ai[p->index].src.buildcmd_a = 1; + _players_ai[p->index].src.direction = 0; + _players_ai[p->index].src.cargo = CT_PASSENGERS; // Fill the dest field - p->ai.dst.spec_tile = t->xy; - p->ai.dst.use_tile = 0; - p->ai.dst.rand_rng = 10; - p->ai.dst.cur_building_rule = 0xFF; - p->ai.dst.buildcmd_a = 0xFF; - p->ai.dst.direction = 0; - p->ai.dst.cargo = CT_PASSENGERS; + _players_ai[p->index].dst.spec_tile = t->xy; + _players_ai[p->index].dst.use_tile = 0; + _players_ai[p->index].dst.rand_rng = 10; + _players_ai[p->index].dst.cur_building_rule = 0xFF; + _players_ai[p->index].dst.buildcmd_a = 0xFF; + _players_ai[p->index].dst.direction = 0; + _players_ai[p->index].dst.cargo = CT_PASSENGERS; // Fill common fields - p->ai.cargo_type = CT_PASSENGERS; - p->ai.num_build_rec = 2; - p->ai.num_loco_to_build = 2; - p->ai.num_want_fullload = 0; - -// p->ai.loco_id = INVALID_VEHICLE; - p->ai.order_list_blocks[0] = 0; - p->ai.order_list_blocks[1] = 1; - p->ai.order_list_blocks[2] = 255; - - p->ai.state = AIS_BUILD_DEFAULT_ROAD_BLOCKS; - p->ai.state_mode = UCHAR_MAX; - p->ai.state_counter = 0; - p->ai.timeout_counter = 0; + _players_ai[p->index].cargo_type = CT_PASSENGERS; + _players_ai[p->index].num_build_rec = 2; + _players_ai[p->index].num_loco_to_build = 2; + _players_ai[p->index].num_want_fullload = 0; + +// _players_ai[p->index].loco_id = INVALID_VEHICLE; + _players_ai[p->index].order_list_blocks[0] = 0; + _players_ai[p->index].order_list_blocks[1] = 1; + _players_ai[p->index].order_list_blocks[2] = 255; + + _players_ai[p->index].state = AIS_BUILD_DEFAULT_ROAD_BLOCKS; + _players_ai[p->index].state_mode = UCHAR_MAX; + _players_ai[p->index].state_counter = 0; + _players_ai[p->index].timeout_counter = 0; } static void AiWantRoadRoute(Player *p) @@ -1366,7 +1367,7 @@ static void AiWantPassengerAircraftRoute /* Get aircraft that would be bought for this route * (probably, as conditions may change before the route is fully built, * like running out of money and having to select different aircraft, etc ...) */ - EngineID veh = AiChooseAircraftToBuild(p->player_money, p->ai.build_kind != 0 ? 0 : AIR_CTOL); + EngineID veh = AiChooseAircraftToBuild(p->player_money, _players_ai[p->index].build_kind != 0 ? 0 : AIR_CTOL); /* No aircraft buildable mean no aircraft route */ if (veh == INVALID_ENGINE) return; @@ -1422,24 +1423,24 @@ static void AiWantPassengerAircraftRoute // Fill the source field - p->ai.src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to); - p->ai.src.use_tile = 0; - p->ai.src.rand_rng = 12; - p->ai.src.cur_building_rule = 0xFF; - p->ai.src.cargo = fr.cargo; + _players_ai[p->index].src.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.to); + _players_ai[p->index].src.use_tile = 0; + _players_ai[p->index].src.rand_rng = 12; + _players_ai[p->index].src.cur_building_rule = 0xFF; + _players_ai[p->index].src.cargo = fr.cargo; // Fill the dest field - p->ai.dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from); - p->ai.dst.use_tile = 0; - p->ai.dst.rand_rng = 12; - p->ai.dst.cur_building_rule = 0xFF; - p->ai.dst.cargo = fr.cargo; + _players_ai[p->index].dst.spec_tile = GET_TOWN_OR_INDUSTRY_TILE(fr.from); + _players_ai[p->index].dst.use_tile = 0; + _players_ai[p->index].dst.rand_rng = 12; + _players_ai[p->index].dst.cur_building_rule = 0xFF; + _players_ai[p->index].dst.cargo = fr.cargo; // Fill common fields - p->ai.cargo_type = fr.cargo; - p->ai.build_kind = 0; - p->ai.num_build_rec = 2; - p->ai.num_loco_to_build = 1; + _players_ai[p->index].cargo_type = fr.cargo; + _players_ai[p->index].build_kind = 0; + _players_ai[p->index].num_build_rec = 2; + _players_ai[p->index].num_loco_to_build = 1; /* Using full load always may not be the best. * Pick random value and rely on selling the vehicle & route * afterwards if the choice was utterly wrong (or maybe altering the value if AI is improved) @@ -1452,14 +1453,14 @@ static void AiWantPassengerAircraftRoute * Also, non-full load is more resistant against starving (by building better stations * or using exclusive rights) */ - p->ai.num_want_fullload = Chance16(1, 5); // 20% chance -// p->ai.loco_id = INVALID_VEHICLE; - p->ai.order_list_blocks[0] = 0; - p->ai.order_list_blocks[1] = 1; - p->ai.order_list_blocks[2] = 255; - - p->ai.state = AIS_AIRPORT_STUFF; - p->ai.timeout_counter = 0; + _players_ai[p->index].num_want_fullload = Chance16(1, 5); // 20% chance +// _players_ai[p->index].loco_id = INVALID_VEHICLE; + _players_ai[p->index].order_list_blocks[0] = 0; + _players_ai[p->index].order_list_blocks[1] = 1; + _players_ai[p->index].order_list_blocks[2] = 255; + + _players_ai[p->index].state = AIS_AIRPORT_STUFF; + _players_ai[p->index].timeout_counter = 0; } static void AiWantOilRigAircraftRoute(Player *p) @@ -1492,32 +1493,32 @@ static void AiWantOilRigAircraftRoute(Pl if (!AiCheckIfRouteIsGood(p, &fr, 4)) return; // Fill the source field - p->ai.src.spec_tile = t->xy; - p->ai.src.use_tile = 0; - p->ai.src.rand_rng = 12; - p->ai.src.cur_building_rule = 0xFF; - p->ai.src.cargo = CT_PASSENGERS; + _players_ai[p->index].src.spec_tile = t->xy; + _players_ai[p->index].src.use_tile = 0; + _players_ai[p->index].src.rand_rng = 12; + _players_ai[p->index].src.cur_building_rule = 0xFF; + _players_ai[p->index].src.cargo = CT_PASSENGERS; // Fill the dest field - p->ai.dst.spec_tile = in->xy; - p->ai.dst.use_tile = 0; - p->ai.dst.rand_rng = 5; - p->ai.dst.cur_building_rule = 0xFF; - p->ai.dst.cargo = CT_PASSENGERS; + _players_ai[p->index].dst.spec_tile = in->xy; + _players_ai[p->index].dst.use_tile = 0; + _players_ai[p->index].dst.rand_rng = 5; + _players_ai[p->index].dst.cur_building_rule = 0xFF; + _players_ai[p->index].dst.cargo = CT_PASSENGERS; // Fill common fields - p->ai.cargo_type = CT_PASSENGERS; - p->ai.build_kind = 1; - p->ai.num_build_rec = 2; - p->ai.num_loco_to_build = 1; - p->ai.num_want_fullload = 0; -// p->ai.loco_id = INVALID_VEHICLE; - p->ai.order_list_blocks[0] = 0; - p->ai.order_list_blocks[1] = 1; - p->ai.order_list_blocks[2] = 255; - - p->ai.state = AIS_AIRPORT_STUFF; - p->ai.timeout_counter = 0; + _players_ai[p->index].cargo_type = CT_PASSENGERS; + _players_ai[p->index].build_kind = 1; + _players_ai[p->index].num_build_rec = 2; + _players_ai[p->index].num_loco_to_build = 1; + _players_ai[p->index].num_want_fullload = 0; +// _players_ai[p->index].loco_id = INVALID_VEHICLE; + _players_ai[p->index].order_list_blocks[0] = 0; + _players_ai[p->index].order_list_blocks[1] = 1; + _players_ai[p->index].order_list_blocks[2] = 255; + + _players_ai[p->index].state = AIS_AIRPORT_STUFF; + _players_ai[p->index].timeout_counter = 0; } static void AiWantAircraftRoute(Player *p) @@ -1539,7 +1540,7 @@ static void AiStateWantNewRoute(Player * int i; if (p->player_money < AiGetBasePrice(p) * 500) { - p->ai.state = AIS_0; + _players_ai[p->index].state = AIS_0; return; } @@ -1568,11 +1569,11 @@ static void AiStateWantNewRoute(Player * } // got a route? - if (p->ai.state != AIS_WANT_NEW_ROUTE) break; + if (_players_ai[p->index].state != AIS_WANT_NEW_ROUTE) break; // time out? if (--i == 0) { - if (++p->ai.state_counter == 556) p->ai.state = AIS_0; + if (++_players_ai[p->index].state_counter == 556) _players_ai[p->index].state = AIS_0; break; } } @@ -1799,16 +1800,16 @@ static void AiStateBuildDefaultRailBlock CommandCost cost; // time out? - if (++p->ai.timeout_counter == 1388) { - p->ai.state = AIS_DELETE_RAIL_BLOCKS; + if (++_players_ai[p->index].timeout_counter == 1388) { + _players_ai[p->index].state = AIS_DELETE_RAIL_BLOCKS; return; } // do the following 8 times for (i = 0; i < 8; i++) { // check if we can build the default track - aib = &p->ai.src; - j = p->ai.num_build_rec; + aib = &_players_ai[p->index].src; + j = _players_ai[p->index].num_build_rec; do { // this item has already been built? if (aib->cur_building_rule != 255) continue; @@ -1819,22 +1820,22 @@ static void AiStateBuildDefaultRailBlock // check if the track can be build there. rule = AiBuildDefaultRailTrack(aib->use_tile, - p->ai.build_kind, p->ai.num_wagons, + _players_ai[p->index].build_kind, _players_ai[p->index].num_wagons, aib->unk6, aib->unk7, aib->direction, aib->cargo, - p->ai.railtype_to_use, + _players_ai[p->index].railtype_to_use, &cost ); if (rule == -1) { // cannot build, terraform after a while - if (p->ai.state_counter >= 600) { - AiDoTerraformLand(aib->use_tile, (DiagDirection)(Random() & 3), 3, (int8)p->ai.state_mode); + if (_players_ai[p->index].state_counter >= 600) { + AiDoTerraformLand(aib->use_tile, (DiagDirection)(Random() & 3), 3, (int8)_players_ai[p->index].state_mode); } // also try the other terraform direction - if (++p->ai.state_counter >= 1000) { - p->ai.state_counter = 0; - p->ai.state_mode = -p->ai.state_mode; + if (++_players_ai[p->index].state_counter >= 1000) { + _players_ai[p->index].state_counter = 0; + _players_ai[p->index].state_mode = -_players_ai[p->index].state_mode; } } else if (CheckPlayerHasMoney(cost)) { // player has money, build it. @@ -1843,7 +1844,7 @@ static void AiStateBuildDefaultRailBlock AiDoBuildDefaultRailTrack( aib->use_tile, _default_rail_track_data[rule]->data, - p->ai.railtype_to_use, + _players_ai[p->index].railtype_to_use, DC_EXEC | DC_NO_TOWN_RATING ); } @@ -1851,15 +1852,15 @@ static void AiStateBuildDefaultRailBlock } // check if we're done with all of them - aib = &p->ai.src; - j = p->ai.num_build_rec; + aib = &_players_ai[p->index].src; + j = _players_ai[p->index].num_build_rec; do { if (aib->cur_building_rule == 255) return; } while (++aib, --j); // yep, all are done. switch state to the rail building state. - p->ai.state = AIS_BUILD_RAIL; - p->ai.state_mode = 255; + _players_ai[p->index].state = AIS_BUILD_RAIL; + _players_ai[p->index].state_mode = 255; } static TileIndex AiGetEdgeOfDefaultRailBlock(byte rule, TileIndex tile, byte cmd, DiagDirection *dir) @@ -1896,11 +1897,11 @@ static bool AiDoFollowTrack(const Player { AiRailPathFindData arpfd; - arpfd.tile = p->ai.start_tile_a; - arpfd.tile2 = p->ai.cur_tile_a; + arpfd.tile = _players_ai[p->index].start_tile_a; + arpfd.tile2 = _players_ai[p->index].cur_tile_a; arpfd.flag = false; arpfd.count = 0; - FollowTrack(p->ai.cur_tile_a + TileOffsByDiagDir(p->ai.cur_dir_a), 0x2000 | TRANSPORT_RAIL, 0, ReverseDiagDir(p->ai.cur_dir_a), + FollowTrack(_players_ai[p->index].cur_tile_a + TileOffsByDiagDir(_players_ai[p->index].cur_dir_a), 0x2000 | TRANSPORT_RAIL, 0, ReverseDiagDir(_players_ai[p->index].cur_dir_a), (TPFEnumProc*)AiEnumFollowTrack, NULL, &arpfd); return arpfd.count > 8; } @@ -1937,8 +1938,8 @@ static bool AiIsTileBanned(const Player* { int i; - for (i = 0; i != p->ai.banned_tile_count; i++) { - if (p->ai.banned_tiles[i] == tile && p->ai.banned_val[i] == val) { + for (i = 0; i != _players_ai[p->index].banned_tile_count; i++) { + if (_players_ai[p->index].banned_tiles[i] == tile && _players_ai[p->index].banned_val[i] == val) { return true; } } @@ -1949,16 +1950,16 @@ static void AiBanTile(Player* p, TileInd { uint i; - for (i = lengthof(p->ai.banned_tiles) - 1; i != 0; i--) { - p->ai.banned_tiles[i] = p->ai.banned_tiles[i - 1]; - p->ai.banned_val[i] = p->ai.banned_val[i - 1]; + for (i = lengthof(_players_ai[p->index].banned_tiles) - 1; i != 0; i--) { + _players_ai[p->index].banned_tiles[i] = _players_ai[p->index].banned_tiles[i - 1]; + _players_ai[p->index].banned_val[i] = _players_ai[p->index].banned_val[i - 1]; } - p->ai.banned_tiles[0] = tile; - p->ai.banned_val[0] = val; - - if (p->ai.banned_tile_count != lengthof(p->ai.banned_tiles)) { - p->ai.banned_tile_count++; + _players_ai[p->index].banned_tiles[0] = tile; + _players_ai[p->index].banned_val[0] = val; + + if (_players_ai[p->index].banned_tile_count != lengthof(_players_ai[p->index].banned_tiles)) { + _players_ai[p->index].banned_tile_count++; } } @@ -2025,7 +2026,7 @@ static inline void AiCheckBuildRailBridg } // Is building a (rail)bridge possible at this place (type doesn't matter)? - if (CmdFailed(DoCommand(tile_new, tile, 0 | arf->player->ai.railtype_to_use << 8, DC_AUTO, CMD_BUILD_BRIDGE))) { + if (CmdFailed(DoCommand(tile_new, tile, 0 | _players_ai[arf->player->index].railtype_to_use << 8, DC_AUTO, CMD_BUILD_BRIDGE))) { return; } AiBuildRailRecursive(arf, tile_new, dir2); @@ -2042,7 +2043,7 @@ static inline void AiCheckBuildRailTunne uint z; if (GetTileSlope(tile, &z) == _dir_table_2[p[0] & 3] && z != 0) { - CommandCost cost = DoCommand(tile, arf->player->ai.railtype_to_use, 0, DC_AUTO, CMD_BUILD_TUNNEL); + CommandCost cost = DoCommand(tile, _players_ai[arf->player->index].railtype_to_use, 0, DC_AUTO, CMD_BUILD_TUNNEL); if (CmdSucceeded(cost) && cost.GetCost() <= (arf->player->player_money >> 4)) { AiBuildRailRecursive(arf, _build_tunnel_endtile, (DiagDirection)(p[0] & 3)); @@ -2098,7 +2099,7 @@ static void AiBuildRailRecursive(AiRailF do { // Make sure the tile is not in the list of banned tiles and that a rail can be built here. if (!AiIsTileBanned(arf->player, tile, p[0]) && - CmdSucceeded(DoCommand(tile, arf->player->ai.railtype_to_use, p[0], DC_AUTO | DC_NO_WATER | DC_NO_RAIL_OVERLAP, CMD_BUILD_SINGLE_RAIL))) { + CmdSucceeded(DoCommand(tile, _players_ai[arf->player->index].railtype_to_use, p[0], DC_AUTO | DC_NO_WATER | DC_NO_RAIL_OVERLAP, CMD_BUILD_SINGLE_RAIL))) { AiBuildRailRecursive(arf, tile, (DiagDirection)p[1]); } @@ -2125,18 +2126,18 @@ static void AiBuildRailConstruct(Player // Check too much lookahead? if (AiDoFollowTrack(p)) { - p->ai.state_counter = (Random()&0xE)+6; // Destruct this amount of blocks - p->ai.state_mode = 1; // Start destruct + _players_ai[p->index].state_counter = (Random()&0xE)+6; // Destruct this amount of blocks + _players_ai[p->index].state_mode = 1; // Start destruct // Ban this tile and don't reach it for a while. - AiBanTile(p, p->ai.cur_tile_a, FindFirstBit(GetRailTrackStatus(p->ai.cur_tile_a))); + AiBanTile(p, _players_ai[p->index].cur_tile_a, FindFirstBit(GetRailTrackStatus(_players_ai[p->index].cur_tile_a))); return; } // Setup recursive finder and call it. arf.player = p; - arf.final_tile = p->ai.cur_tile_b; - arf.final_dir = p->ai.cur_dir_b; + arf.final_tile = _players_ai[p->index].cur_tile_b; + arf.final_dir = _players_ai[p->index].cur_dir_b; arf.depth = 0; arf.recursive_mode = 0; arf.best_ptr = NULL; @@ -2146,11 +2147,11 @@ static void AiBuildRailConstruct(Player arf.best_depth = 0xff; arf.cur_best_tile = 0; arf.best_tile = 0; - AiBuildRailRecursive(&arf, p->ai.cur_tile_a, p->ai.cur_dir_a); + AiBuildRailRecursive(&arf, _players_ai[p->index].cur_tile_a, _players_ai[p->index].cur_dir_a); // Reached destination? if (arf.recursive_mode == 2 && arf.cur_best_depth == 0) { - p->ai.state_mode = 255; + _players_ai[p->index].state_mode = 255; return; } @@ -2158,24 +2159,24 @@ static void AiBuildRailConstruct(Player if (arf.best_ptr == NULL) { // Terraform some for (i = 0; i != 5; i++) { - AiDoTerraformLand(p->ai.cur_tile_a, p->ai.cur_dir_a, 3, 0); + AiDoTerraformLand(_players_ai[p->index].cur_tile_a, _players_ai[p->index].cur_dir_a, 3, 0); } - if (++p->ai.state_counter == 21) { - p->ai.state_counter = 40; - p->ai.state_mode = 1; + if (++_players_ai[p->index].state_counter == 21) { + _players_ai[p->index].state_counter = 40; + _players_ai[p->index].state_mode = 1; // Ban this tile - AiBanTile(p, p->ai.cur_tile_a, FindFirstBit(GetRailTrackStatus(p->ai.cur_tile_a))); + AiBanTile(p, _players_ai[p->index].cur_tile_a, FindFirstBit(GetRailTrackStatus(_players_ai[p->index].cur_tile_a))); } return; } - p->ai.cur_tile_a += TileOffsByDiagDir(p->ai.cur_dir_a); + _players_ai[p->index].cur_tile_a += TileOffsByDiagDir(_players_ai[p->index].cur_dir_a); if (arf.best_ptr[0] & 0x80) { int i; - int32 bridge_len = GetBridgeLength(arf.bridge_end_tile, p->ai.cur_tile_a); + int32 bridge_len = GetBridgeLength(arf.bridge_end_tile, _players_ai[p->index].cur_tile_a); /* Figure out which (rail)bridge type to build * start with best bridge, then go down to worse and worse bridges @@ -2185,27 +2186,27 @@ static void AiBuildRailConstruct(Player */ for (i = MAX_BRIDGES - 1; i != 0; i--) { if (CheckBridge_Stuff(i, bridge_len)) { - CommandCost cost = DoCommand(arf.bridge_end_tile, p->ai.cur_tile_a, i | (p->ai.railtype_to_use << 8), DC_AUTO, CMD_BUILD_BRIDGE); + CommandCost cost = DoCommand(arf.bridge_end_tile, _players_ai[p->index].cur_tile_a, i | (_players_ai[p->index].railtype_to_use << 8), DC_AUTO, CMD_BUILD_BRIDGE); if (CmdSucceeded(cost) && cost.GetCost() < (p->player_money >> 5)) break; } } // Build it - DoCommand(arf.bridge_end_tile, p->ai.cur_tile_a, i | (p->ai.railtype_to_use << 8), DC_AUTO | DC_EXEC, CMD_BUILD_BRIDGE); - - p->ai.cur_tile_a = arf.bridge_end_tile; - p->ai.state_counter = 0; + DoCommand(arf.bridge_end_tile, _players_ai[p->index].cur_tile_a, i | (_players_ai[p->index].railtype_to_use << 8), DC_AUTO | DC_EXEC, CMD_BUILD_BRIDGE); + + _players_ai[p->index].cur_tile_a = arf.bridge_end_tile; + _players_ai[p->index].state_counter = 0; } else if (arf.best_ptr[0] & 0x40) { // tunnel - DoCommand(p->ai.cur_tile_a, p->ai.railtype_to_use, 0, DC_AUTO | DC_EXEC, CMD_BUILD_TUNNEL); - p->ai.cur_tile_a = _build_tunnel_endtile; - p->ai.state_counter = 0; + DoCommand(_players_ai[p->index].cur_tile_a, _players_ai[p->index].railtype_to_use, 0, DC_AUTO | DC_EXEC, CMD_BUILD_TUNNEL); + _players_ai[p->index].cur_tile_a = _build_tunnel_endtile; + _players_ai[p->index].state_counter = 0; } else { // rail - p->ai.cur_dir_a = (DiagDirection)(arf.best_ptr[1] & 3); - DoCommand(p->ai.cur_tile_a, p->ai.railtype_to_use, arf.best_ptr[0], + _players_ai[p->index].cur_dir_a = (DiagDirection)(arf.best_ptr[1] & 3); + DoCommand(_players_ai[p->index].cur_tile_a, _players_ai[p->index].railtype_to_use, arf.best_ptr[0], DC_EXEC | DC_AUTO | DC_NO_WATER | DC_NO_RAIL_OVERLAP, CMD_BUILD_SINGLE_RAIL); - p->ai.state_counter = 0; + _players_ai[p->index].state_counter = 0; } if (arf.best_tile != 0) { @@ -2220,7 +2221,7 @@ static bool AiRemoveTileAndGoForward(Pla byte b; int bit; const byte *ptr; - TileIndex tile = p->ai.cur_tile_a; + TileIndex tile = _players_ai[p->index].cur_tile_a; TileIndex tilenew; if (IsTileType(tile, MP_TUNNELBRIDGE)) { @@ -2228,26 +2229,26 @@ static bool AiRemoveTileAndGoForward(Pla // Clear the tunnel and continue at the other side of it. if (CmdFailed(DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) return false; - p->ai.cur_tile_a = TILE_MASK(_build_tunnel_endtile - TileOffsByDiagDir(p->ai.cur_dir_a)); + _players_ai[p->index].cur_tile_a = TILE_MASK(_build_tunnel_endtile - TileOffsByDiagDir(_players_ai[p->index].cur_dir_a)); return true; } else { // Check if the bridge points in the right direction. // This is not really needed the first place AiRemoveTileAndGoForward is called. - if (DiagDirToAxis(GetTunnelBridgeDirection(tile)) != (p->ai.cur_dir_a & 1)) return false; + if (DiagDirToAxis(GetTunnelBridgeDirection(tile)) != (_players_ai[p->index].cur_dir_a & 1)) return false; tile = GetOtherBridgeEnd(tile); - tilenew = TILE_MASK(tile - TileOffsByDiagDir(p->ai.cur_dir_a)); + tilenew = TILE_MASK(tile - TileOffsByDiagDir(_players_ai[p->index].cur_dir_a)); // And clear the bridge. if (CmdFailed(DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR))) return false; - p->ai.cur_tile_a = tilenew; + _players_ai[p->index].cur_tile_a = tilenew; return true; } } // Find the railtype at the position. Quit if no rail there. - b = GetRailTrackStatus(tile) & _dir_table_3[p->ai.cur_dir_a]; + b = GetRailTrackStatus(tile) & _dir_table_3[_players_ai[p->index].cur_dir_a]; if (b == 0) return false; // Convert into a bit position that CMD_REMOVE_SINGLE_RAIL expects. @@ -2264,12 +2265,12 @@ static bool AiRemoveTileAndGoForward(Pla return false; // Find the direction at the other edge of the rail. - ptr = _ai_table_15[ReverseDiagDir(p->ai.cur_dir_a)]; + ptr = _ai_table_15[ReverseDiagDir(_players_ai[p->index].cur_dir_a)]; while (ptr[0] != bit) ptr += 2; - p->ai.cur_dir_a = ReverseDiagDir((DiagDirection)ptr[1]); + _players_ai[p->index].cur_dir_a = ReverseDiagDir((DiagDirection)ptr[1]); // And then also switch tile. - p->ai.cur_tile_a = TILE_MASK(p->ai.cur_tile_a - TileOffsByDiagDir(p->ai.cur_dir_a)); + _players_ai[p->index].cur_tile_a = TILE_MASK(_players_ai[p->index].cur_tile_a - TileOffsByDiagDir(_players_ai[p->index].cur_dir_a)); return true; } @@ -2278,13 +2279,13 @@ static bool AiRemoveTileAndGoForward(Pla static void AiBuildRailDestruct(Player *p) { // Decrease timeout. - if (!--p->ai.state_counter) { - p->ai.state_mode = 2; - p->ai.state_counter = 0; + if (!--_players_ai[p->index].state_counter) { + _players_ai[p->index].state_mode = 2; + _players_ai[p->index].state_counter = 0; } // Don't do anything if the destination is already reached. - if (p->ai.cur_tile_a == p->ai.start_tile_a) return; + if (_players_ai[p->index].cur_tile_a == _players_ai[p->index].start_tile_a) return; AiRemoveTileAndGoForward(p); } @@ -2292,7 +2293,7 @@ static void AiBuildRailDestruct(Player * static void AiBuildRail(Player *p) { - switch (p->ai.state_mode) { + switch (_players_ai[p->index].state_mode) { case 0: // Construct mode, build new rail. AiBuildRailConstruct(p); break; @@ -2306,12 +2307,12 @@ static void AiBuildRail(Player *p) // Terraform some and then try building again. for (i = 0; i != 4; i++) { - AiDoTerraformLand(p->ai.cur_tile_a, p->ai.cur_dir_a, 3, 0); + AiDoTerraformLand(_players_ai[p->index].cur_tile_a, _players_ai[p->index].cur_dir_a, 3, 0); } - if (++p->ai.state_counter == 4) { - p->ai.state_counter = 0; - p->ai.state_mode = 0; + if (++_players_ai[p->index].state_counter == 4) { + _players_ai[p->index].state_counter = 0; + _players_ai[p->index].state_mode = 0; } } @@ -2328,26 +2329,26 @@ static void AiStateBuildRail(Player *p) DiagDirection dir; // time out? - if (++p->ai.timeout_counter == 1388) { - p->ai.state = AIS_DELETE_RAIL_BLOCKS; + if (++_players_ai[p->index].timeout_counter == 1388) { + _players_ai[p->index].state = AIS_DELETE_RAIL_BLOCKS; return; } // Currently building a rail between two points? - if (p->ai.state_mode != 255) { + if (_players_ai[p->index].state_mode != 255) { AiBuildRail(p); // Alternate between edges - Swap(p->ai.start_tile_a, p->ai.start_tile_b); - Swap(p->ai.cur_tile_a, p->ai.cur_tile_b); - Swap(p->ai.start_dir_a, p->ai.start_dir_b); - Swap(p->ai.cur_dir_a, p->ai.cur_dir_b); + Swap(_players_ai[p->index].start_tile_a, _players_ai[p->index].start_tile_b); + Swap(_players_ai[p->index].cur_tile_a, _players_ai[p->index].cur_tile_b); + Swap(_players_ai[p->index].start_dir_a, _players_ai[p->index].start_dir_b); + Swap(_players_ai[p->index].cur_dir_a, _players_ai[p->index].cur_dir_b); return; } // Now, find two new points to build between - num = p->ai.num_build_rec; - aib = &p->ai.src; + num = _players_ai[p->index].num_build_rec; + aib = &_players_ai[p->index].src; for (;;) { cmd = aib->buildcmd_a; @@ -2360,37 +2361,37 @@ static void AiStateBuildRail(Player *p) aib++; if (--num == 0) { - p->ai.state = AIS_BUILD_RAIL_VEH; - p->ai.state_counter = 0; // timeout + _players_ai[p->index].state = AIS_BUILD_RAIL_VEH; + _players_ai[p->index].state_counter = 0; // timeout return; } } // Find first edge to build from. tile = AiGetEdgeOfDefaultRailBlock(aib->cur_building_rule, aib->use_tile, cmd & 3, &dir); - p->ai.start_tile_a = tile; - p->ai.cur_tile_a = tile; - p->ai.start_dir_a = dir; - p->ai.cur_dir_a = dir; + _players_ai[p->index].start_tile_a = tile; + _players_ai[p->index].cur_tile_a = tile; + _players_ai[p->index].start_dir_a = dir; + _players_ai[p->index].cur_dir_a = dir; DoCommand(TILE_MASK(tile + TileOffsByDiagDir(dir)), 0, (dir & 1) ? 1 : 0, DC_EXEC, CMD_REMOVE_SINGLE_RAIL); assert(TILE_MASK(tile) != 0xFF00); // Find second edge to build to - aib = (&p->ai.src) + ((cmd >> 4) & 0xF); + aib = (&_players_ai[p->index].src) + ((cmd >> 4) & 0xF); tile = AiGetEdgeOfDefaultRailBlock(aib->cur_building_rule, aib->use_tile, (cmd >> 2) & 3, &dir); - p->ai.start_tile_b = tile; - p->ai.cur_tile_b = tile; - p->ai.start_dir_b = dir; - p->ai.cur_dir_b = dir; + _players_ai[p->index].start_tile_b = tile; + _players_ai[p->index].cur_tile_b = tile; + _players_ai[p->index].start_dir_b = dir; + _players_ai[p->index].cur_dir_b = dir; DoCommand(TILE_MASK(tile + TileOffsByDiagDir(dir)), 0, (dir & 1) ? 1 : 0, DC_EXEC, CMD_REMOVE_SINGLE_RAIL); assert(TILE_MASK(tile) != 0xFF00); // And setup state. - p->ai.state_mode = 2; - p->ai.state_counter = 0; - p->ai.banned_tile_count = 0; + _players_ai[p->index].state_mode = 2; + _players_ai[p->index].state_counter = 0; + _players_ai[p->index].banned_tile_count = 0; } static StationID AiGetStationIdByDef(TileIndex tile, int id) @@ -2444,40 +2445,40 @@ static void AiStateBuildRailVeh(Player * Vehicle *v; VehicleID loco_id; - ptr = _default_rail_track_data[p->ai.src.cur_building_rule]->data; + ptr = _default_rail_track_data[_players_ai[p->index].src.cur_building_rule]->data; while (ptr->mode != 0) ptr++; - tile = TILE_ADD(p->ai.src.use_tile, ToTileIndexDiff(ptr->tileoffs)); - - - cargo = p->ai.cargo_type; + tile = TILE_ADD(_players_ai[p->index].src.use_tile, ToTileIndexDiff(ptr->tileoffs)); + + + cargo = _players_ai[p->index].cargo_type; for (i = 0;;) { - if (p->ai.wagon_list[i] == INVALID_VEHICLE) { - veh = AiFindBestWagon(cargo, p->ai.railtype_to_use); + if (_players_ai[p->index].wagon_list[i] == INVALID_VEHICLE) { + veh = AiFindBestWagon(cargo, _players_ai[p->index].railtype_to_use); /* veh will return INVALID_ENGINE if no suitable wagon is available. * We shall treat this in the same way as having no money */ if (veh == INVALID_ENGINE) goto handle_nocash; cost = DoCommand(tile, veh, 0, DC_EXEC, CMD_BUILD_RAIL_VEHICLE); if (CmdFailed(cost)) goto handle_nocash; - p->ai.wagon_list[i] = _new_vehicle_id; - p->ai.wagon_list[i + 1] = INVALID_VEHICLE; + _players_ai[p->index].wagon_list[i] = _new_vehicle_id; + _players_ai[p->index].wagon_list[i + 1] = INVALID_VEHICLE; return; } if (cargo == CT_MAIL) cargo = CT_PASSENGERS; - if (++i == p->ai.num_wagons * 2 - 1) break; + if (++i == _players_ai[p->index].num_wagons * 2 - 1) break; } // Which locomotive to build? - veh = AiChooseTrainToBuild(p->ai.railtype_to_use, p->player_money, cargo != CT_PASSENGERS ? 1 : 0, tile); + veh = AiChooseTrainToBuild(_players_ai[p->index].railtype_to_use, p->player_money, cargo != CT_PASSENGERS ? 1 : 0, tile); if (veh == INVALID_ENGINE) { handle_nocash: // after a while, if AI still doesn't have cash, get out of this block by selling the wagons. - if (++p->ai.state_counter == 1000) { - for (i = 0; p->ai.wagon_list[i] != INVALID_VEHICLE; i++) { - cost = DoCommand(tile, p->ai.wagon_list[i], 0, DC_EXEC, CMD_SELL_RAIL_WAGON); + if (++_players_ai[p->index].state_counter == 1000) { + for (i = 0; _players_ai[p->index].wagon_list[i] != INVALID_VEHICLE; i++) { + cost = DoCommand(tile, _players_ai[p->index].wagon_list[i], 0, DC_EXEC, CMD_SELL_RAIL_WAGON); assert(CmdSucceeded(cost)); } - p->ai.state = AIS_0; + _players_ai[p->index].state = AIS_0; } return; } @@ -2490,22 +2491,22 @@ handle_nocash: // Sell a vehicle if the train is double headed. v = GetVehicle(loco_id); if (v->Next() != NULL) { - i = p->ai.wagon_list[p->ai.num_wagons * 2 - 2]; - p->ai.wagon_list[p->ai.num_wagons * 2 - 2] = INVALID_VEHICLE; + i = _players_ai[p->index].wagon_list[_players_ai[p->index].num_wagons * 2 - 2]; + _players_ai[p->index].wagon_list[_players_ai[p->index].num_wagons * 2 - 2] = INVALID_VEHICLE; DoCommand(tile, i, 0, DC_EXEC, CMD_SELL_RAIL_WAGON); } // Move the wagons onto the train - for (i = 0; p->ai.wagon_list[i] != INVALID_VEHICLE; i++) { - DoCommand(tile, p->ai.wagon_list[i] | (loco_id << 16), 0, DC_EXEC, CMD_MOVE_RAIL_VEHICLE); + for (i = 0; _players_ai[p->index].wagon_list[i] != INVALID_VEHICLE; i++) { + DoCommand(tile, _players_ai[p->index].wagon_list[i] | (loco_id << 16), 0, DC_EXEC, CMD_MOVE_RAIL_VEHICLE); } - for (i = 0; p->ai.order_list_blocks[i] != 0xFF; i++) { - const AiBuildRec* aib = &p->ai.src + p->ai.order_list_blocks[i]; + for (i = 0; _players_ai[p->index].order_list_blocks[i] != 0xFF; i++) { + const AiBuildRec* aib = &_players_ai[p->index].src + _players_ai[p->index].order_list_blocks[i]; bool is_pass = ( - p->ai.cargo_type == CT_PASSENGERS || - p->ai.cargo_type == CT_MAIL || - (_opt.landscape == LT_TEMPERATE && p->ai.cargo_type == CT_VALUABLES) + _players_ai[p->index].cargo_type == CT_PASSENGERS || + _players_ai[p->index].cargo_type == CT_MAIL || + (_opt.landscape == LT_TEMPERATE && _players_ai[p->index].cargo_type == CT_VALUABLES) ); Order order; @@ -2514,7 +2515,7 @@ handle_nocash: order.dest = AiGetStationIdByDef(aib->use_tile, aib->cur_building_rule); if (!is_pass && i == 1) order.flags |= OF_UNLOAD; - if (p->ai.num_want_fullload != 0 && (is_pass || i == 0)) + if (_players_ai[p->index].num_want_fullload != 0 && (is_pass || i == 0)) order.flags |= OF_FULL_LOAD; DoCommand(0, loco_id + (i << 16), PackOrder(&order), DC_EXEC, CMD_INSERT_ORDER); @@ -2524,20 +2525,20 @@ handle_nocash: DoCommand(0, loco_id, _ai_service_interval, DC_EXEC, CMD_CHANGE_SERVICE_INT); - if (p->ai.num_want_fullload != 0) p->ai.num_want_fullload--; - - if (--p->ai.num_loco_to_build != 0) { -// p->ai.loco_id = INVALID_VEHICLE; - p->ai.wagon_list[0] = INVALID_VEHICLE; + if (_players_ai[p->index].num_want_fullload != 0) _players_ai[p->index].num_want_fullload--; + + if (--_players_ai[p->index].num_loco_to_build != 0) { +// _players_ai[p->index].loco_id = INVALID_VEHICLE; + _players_ai[p->index].wagon_list[0] = INVALID_VEHICLE; } else { - p->ai.state = AIS_0; + _players_ai[p->index].state = AIS_0; } } static void AiStateDeleteRailBlocks(Player *p) { - const AiBuildRec* aib = &p->ai.src; - uint num = p->ai.num_build_rec; + const AiBuildRec* aib = &_players_ai[p->index].src; + uint num = _players_ai[p->index].num_build_rec; do { const AiDefaultBlockData* b; @@ -2548,7 +2549,7 @@ static void AiStateDeleteRailBlocks(Play } } while (++aib, --num); - p->ai.state = AIS_0; + _players_ai[p->index].state = AIS_0; } static bool AiCheckRoadResources(TileIndex tile, const AiDefaultBlockData *p, byte cargo) @@ -2677,8 +2678,8 @@ clear_town_stuff:; // Make sure the blocks are not too close to each other static bool AiCheckBlockDistances(Player *p, TileIndex tile) { - const AiBuildRec* aib = &p->ai.src; - uint num = p->ai.num_build_rec; + const AiBuildRec* aib = &_players_ai[p->index].src; + uint num = _players_ai[p->index].num_build_rec; do { if (aib->cur_building_rule != 255) { @@ -2699,16 +2700,16 @@ static void AiStateBuildDefaultRoadBlock CommandCost cost; // time out? - if (++p->ai.timeout_counter == 1388) { - p->ai.state = AIS_DELETE_RAIL_BLOCKS; + if (++_players_ai[p->index].timeout_counter == 1388) { + _players_ai[p->index].state = AIS_DELETE_RAIL_BLOCKS; return; } // do the following 8 times for (i = 0; i != 8; i++) { // check if we can build the default track - aib = &p->ai.src; - j = p->ai.num_build_rec; + aib = &_players_ai[p->index].src; + j = _players_ai[p->index].num_build_rec; do { // this item has already been built? if (aib->cur_building_rule != 255) continue; @@ -2724,13 +2725,13 @@ static void AiStateBuildDefaultRoadBlock if (rule == -1) { // cannot build, terraform after a while - if (p->ai.state_counter >= 600) { - AiDoTerraformLand(aib->use_tile, (DiagDirection)(Random() & 3), 3, (int8)p->ai.state_mode); + if (_players_ai[p->index].state_counter >= 600) { + AiDoTerraformLand(aib->use_tile, (DiagDirection)(Random() & 3), 3, (int8)_players_ai[p->index].state_mode); } // also try the other terraform direction - if (++p->ai.state_counter >= 1000) { - p->ai.state_counter = 0; - p->ai.state_mode = -p->ai.state_mode; + if (++_players_ai[p->index].state_counter >= 1000) { + _players_ai[p->index].state_counter = 0; + _players_ai[p->index].state_mode = -_players_ai[p->index].state_mode; } } else if (CheckPlayerHasMoney(cost) && AiCheckBlockDistances(p, aib->use_tile)) { CommandCost r; @@ -2749,15 +2750,15 @@ static void AiStateBuildDefaultRoadBlock } // check if we're done with all of them - aib = &p->ai.src; - j = p->ai.num_build_rec; + aib = &_players_ai[p->index].src; + j = _players_ai[p->index].num_build_rec; do { if (aib->cur_building_rule == 255) return; } while (++aib, --j); // yep, all are done. switch state to the rail building state. - p->ai.state = AIS_BUILD_ROAD; - p->ai.state_mode = 255; + _players_ai[p->index].state = AIS_BUILD_ROAD; + _players_ai[p->index].state_mode = 255; } struct AiRoadFinder { @@ -2854,11 +2855,11 @@ static bool AiCheckRoadFinished(Player * { AiRoadEnum are; TileIndex tile; - DiagDirection dir = p->ai.cur_dir_a; + DiagDirection dir = _players_ai[p->index].cur_dir_a; uint32 bits; - are.dest = p->ai.cur_tile_b; - tile = TILE_MASK(p->ai.cur_tile_a + TileOffsByDiagDir(dir)); + are.dest = _players_ai[p->index].cur_tile_b; + tile = TILE_MASK(_players_ai[p->index].cur_tile_a + TileOffsByDiagDir(dir)); if (IsRoadStopTile(tile) || IsTileDepotType(tile, TRANSPORT_ROAD)) return false; bits = GetTileTrackStatus(tile, TRANSPORT_ROAD, ROADTYPES_ROAD) & _ai_road_table_and[dir]; @@ -2875,8 +2876,8 @@ static bool AiCheckRoadFinished(Player * if (are.best_dist == 0) return true; - p->ai.cur_tile_a = are.best_tile; - p->ai.cur_dir_a = _dir_by_track[are.best_track]; + _players_ai[p->index].cur_tile_a = are.best_tile; + _players_ai[p->index].cur_dir_a = _dir_by_track[are.best_track]; return false; } @@ -3019,14 +3020,14 @@ static void AiBuildRoadConstruct(Player // Reached destination? if (AiCheckRoadFinished(p)) { - p->ai.state_mode = 255; + _players_ai[p->index].state_mode = 255; return; } // Setup recursive finder and call it. arf.player = p; - arf.final_tile = p->ai.cur_tile_b; - arf.final_dir = p->ai.cur_dir_b; + arf.final_tile = _players_ai[p->index].cur_tile_b; + arf.final_dir = _players_ai[p->index].cur_dir_b; arf.depth = 0; arf.recursive_mode = 0; arf.best_ptr = NULL; @@ -3036,11 +3037,11 @@ static void AiBuildRoadConstruct(Player arf.best_depth = 0xff; arf.cur_best_tile = 0; arf.best_tile = 0; - AiBuildRoadRecursive(&arf, p->ai.cur_tile_a, p->ai.cur_dir_a); + AiBuildRoadRecursive(&arf, _players_ai[p->index].cur_tile_a, _players_ai[p->index].cur_dir_a); // Reached destination? if (arf.recursive_mode == 2 && arf.cur_best_depth == 0) { - p->ai.state_mode = 255; + _players_ai[p->index].state_mode = 255; return; } @@ -3049,25 +3050,25 @@ static void AiBuildRoadConstruct(Player // Terraform some do_some_terraform: for (i = 0; i != 5; i++) - AiDoTerraformLand(p->ai.cur_tile_a, p->ai.cur_dir_a, 3, 0); - - if (++p->ai.state_counter == 21) { - p->ai.state_mode = 1; - - p->ai.cur_tile_a = TILE_MASK(p->ai.cur_tile_a + TileOffsByDiagDir(p->ai.cur_dir_a)); - p->ai.cur_dir_a = ReverseDiagDir(p->ai.cur_dir_a); - p->ai.state_counter = 0; + AiDoTerraformLand(_players_ai[p->index].cur_tile_a, _players_ai[p->index].cur_dir_a, 3, 0); + + if (++_players_ai[p->index].state_counter == 21) { + _players_ai[p->index].state_mode = 1; + + _players_ai[p->index].cur_tile_a = TILE_MASK(_players_ai[p->index].cur_tile_a + TileOffsByDiagDir(_players_ai[p->index].cur_dir_a)); + _players_ai[p->index].cur_dir_a = ReverseDiagDir(_players_ai[p->index].cur_dir_a); + _players_ai[p->index].state_counter = 0; } return; } - tile = TILE_MASK(p->ai.cur_tile_a + TileOffsByDiagDir(p->ai.cur_dir_a)); + tile = TILE_MASK(_players_ai[p->index].cur_tile_a + TileOffsByDiagDir(_players_ai[p->index].cur_dir_a)); if (arf.best_ptr[0] & 0x80) { int i; int32 bridge_len; - p->ai.cur_tile_a = arf.bridge_end_tile; - bridge_len = GetBridgeLength(tile, p->ai.cur_tile_a); // tile + _players_ai[p->index].cur_tile_a = arf.bridge_end_tile; + bridge_len = GetBridgeLength(tile, _players_ai[p->index].cur_tile_a); // tile /* Figure out what (road)bridge type to build * start with best bridge, then go down to worse and worse bridges @@ -3076,28 +3077,28 @@ do_some_terraform: */ for (i = 10; i != 0; i--) { if (CheckBridge_Stuff(i, bridge_len)) { - CommandCost cost = DoCommand(tile, p->ai.cur_tile_a, i + ((0x80 | ROADTYPES_ROAD) << 8), DC_AUTO, CMD_BUILD_BRIDGE); + CommandCost cost = DoCommand(tile, _players_ai[p->index].cur_tile_a, i + ((0x80 | ROADTYPES_ROAD) << 8), DC_AUTO, CMD_BUILD_BRIDGE); if (CmdSucceeded(cost) && cost.GetCost() < (p->player_money >> 5)) break; } } // Build it - DoCommand(tile, p->ai.cur_tile_a, i + ((0x80 | ROADTYPES_ROAD) << 8), DC_AUTO | DC_EXEC, CMD_BUILD_BRIDGE); - - p->ai.state_counter = 0; + DoCommand(tile, _players_ai[p->index].cur_tile_a, i + ((0x80 | ROADTYPES_ROAD) << 8), DC_AUTO | DC_EXEC, CMD_BUILD_BRIDGE); + + _players_ai[p->index].state_counter = 0; } else if (arf.best_ptr[0] & 0x40) { // tunnel DoCommand(tile, 0x200, 0, DC_AUTO | DC_EXEC, CMD_BUILD_TUNNEL); - p->ai.cur_tile_a = _build_tunnel_endtile; - p->ai.state_counter = 0; + _players_ai[p->index].cur_tile_a = _build_tunnel_endtile; + _players_ai[p->index].state_counter = 0; } else { // road if (!AiBuildRoadHelper(tile, DC_EXEC | DC_AUTO | DC_NO_WATER | DC_AI_BUILDING, arf.best_ptr[0])) goto do_some_terraform; - p->ai.cur_dir_a = (DiagDirection)(arf.best_ptr[1] & 3); - p->ai.cur_tile_a = tile; - p->ai.state_counter = 0; + _players_ai[p->index].cur_dir_a = (DiagDirection)(arf.best_ptr[1] & 3); + _players_ai[p->index].cur_tile_a = tile; + _players_ai[p->index].state_counter = 0; } if (arf.best_tile != 0) { @@ -3109,24 +3110,24 @@ do_some_terraform: static void AiBuildRoad(Player *p) { - if (p->ai.state_mode < 1) { + if (_players_ai[p->index].state_mode < 1) { // Construct mode, build new road. AiBuildRoadConstruct(p); - } else if (p->ai.state_mode == 1) { + } else if (_players_ai[p->index].state_mode == 1) { // Destruct mode, not implemented for roads. - p->ai.state_mode = 2; - p->ai.state_counter = 0; - } else if (p->ai.state_mode == 2) { + _players_ai[p->index].state_mode = 2; + _players_ai[p->index].state_counter = 0; + } else if (_players_ai[p->index].state_mode == 2) { uint i; // Terraform some and then try building again. for (i = 0; i != 4; i++) { - AiDoTerraformLand(p->ai.cur_tile_a, p->ai.cur_dir_a, 3, 0); + AiDoTerraformLand(_players_ai[p->index].cur_tile_a, _players_ai[p->index].cur_dir_a, 3, 0); } - if (++p->ai.state_counter == 4) { - p->ai.state_counter = 0; - p->ai.state_mode = 0; + if (++_players_ai[p->index].state_counter == 4) { + _players_ai[p->index].state_counter = 0; + _players_ai[p->index].state_mode = 0; } } } @@ -3149,27 +3150,27 @@ static void AiStateBuildRoad(Player *p) DiagDirection dir; // time out? - if (++p->ai.timeout_counter == 1388) { - p->ai.state = AIS_DELETE_ROAD_BLOCKS; + if (++_players_ai[p->index].timeout_counter == 1388) { + _players_ai[p->index].state = AIS_DELETE_ROAD_BLOCKS; return; } // Currently building a road between two points? - if (p->ai.state_mode != 255) { + if (_players_ai[p->index].state_mode != 255) { AiBuildRoad(p); // Alternate between edges - Swap(p->ai.start_tile_a, p->ai.start_tile_b); - Swap(p->ai.cur_tile_a, p->ai.cur_tile_b); - Swap(p->ai.start_dir_a, p->ai.start_dir_b); - Swap(p->ai.cur_dir_a, p->ai.cur_dir_b); + Swap(_players_ai[p->index].start_tile_a, _players_ai[p->index].start_tile_b); + Swap(_players_ai[p->index].cur_tile_a, _players_ai[p->index].cur_tile_b); + Swap(_players_ai[p->index].start_dir_a, _players_ai[p->index].start_dir_b); + Swap(_players_ai[p->index].cur_dir_a, _players_ai[p->index].cur_dir_b); return; } // Now, find two new points to build between - num = p->ai.num_build_rec; - aib = &p->ai.src; + num = _players_ai[p->index].num_build_rec; + aib = &_players_ai[p->index].src; for (;;) { cmd = aib->buildcmd_a; @@ -3178,30 +3179,30 @@ static void AiStateBuildRoad(Player *p) aib++; if (--num == 0) { - p->ai.state = AIS_BUILD_ROAD_VEHICLES; + _players_ai[p->index].state = AIS_BUILD_ROAD_VEHICLES; return; } } // Find first edge to build from. tile = AiGetRoadBlockEdge(aib->cur_building_rule, aib->use_tile, &dir); - p->ai.start_tile_a = tile; - p->ai.cur_tile_a = tile; - p->ai.start_dir_a = dir; - p->ai.cur_dir_a = dir; + _players_ai[p->index].start_tile_a = tile; + _players_ai[p->index].cur_tile_a = tile; + _players_ai[p->index].start_dir_a = dir; + _players_ai[p->index].cur_dir_a = dir; // Find second edge to build to - aib = (&p->ai.src) + (cmd & 0xF); + aib = (&_players_ai[p->index].src) + (cmd & 0xF); tile = AiGetRoadBlockEdge(aib->cur_building_rule, aib->use_tile, &dir); - p->ai.start_tile_b = tile; - p->ai.cur_tile_b = tile; - p->ai.start_dir_b = dir; - p->ai.cur_dir_b = dir; + _players_ai[p->index].start_tile_b = tile; + _players_ai[p->index].cur_tile_b = tile; + _players_ai[p->index].start_dir_b = dir; + _players_ai[p->index].cur_dir_b = dir; // And setup state. - p->ai.state_mode = 2; - p->ai.state_counter = 0; - p->ai.banned_tile_count = 0; + _players_ai[p->index].state_mode = 2; + _players_ai[p->index].state_counter = 0; + _players_ai[p->index].banned_tile_count = 0; } static StationID AiGetStationIdFromRoadBlock(TileIndex tile, int id) @@ -3219,13 +3220,13 @@ static void AiStateBuildRoadVehicles(Pla EngineID veh; uint i; - ptr = _road_default_block_data[p->ai.src.cur_building_rule]->data; + ptr = _road_default_block_data[_players_ai[p->index].src.cur_building_rule]->data; for (; ptr->mode != 0; ptr++) {} - tile = TILE_ADD(p->ai.src.use_tile, ToTileIndexDiff(ptr->tileoffs)); - - veh = AiChooseRoadVehToBuild(p->ai.cargo_type, p->player_money, tile); + tile = TILE_ADD(_players_ai[p->index].src.use_tile, ToTileIndexDiff(ptr->tileoffs)); + + veh = AiChooseRoadVehToBuild(_players_ai[p->index].cargo_type, p->player_money, tile); if (veh == INVALID_ENGINE) { - p->ai.state = AIS_0; + _players_ai[p->index].state = AIS_0; return; } @@ -3233,21 +3234,21 @@ static void AiStateBuildRoadVehicles(Pla loco_id = _new_vehicle_id; - if (GetVehicle(loco_id)->cargo_type != p->ai.cargo_type) { + if (GetVehicle(loco_id)->cargo_type != _players_ai[p->index].cargo_type) { /* Cargo type doesn't match, so refit it */ - if (CmdFailed(DoCommand(tile, loco_id, p->ai.cargo_type, DC_EXEC, CMD_REFIT_ROAD_VEH))) { + if (CmdFailed(DoCommand(tile, loco_id, _players_ai[p->index].cargo_type, DC_EXEC, CMD_REFIT_ROAD_VEH))) { /* Refit failed... sell the vehicle */ DoCommand(tile, loco_id, 0, DC_EXEC, CMD_SELL_ROAD_VEH); return; } } - for (i = 0; p->ai.order_list_blocks[i] != 0xFF; i++) { - const AiBuildRec* aib = &p->ai.src + p->ai.order_list_blocks[i]; + for (i = 0; _players_ai[p->index].order_list_blocks[i] != 0xFF; i++) { + const AiBuildRec* aib = &_players_ai[p->index].src + _players_ai[p->index].order_list_blocks[i]; bool is_pass = ( - p->ai.cargo_type == CT_PASSENGERS || - p->ai.cargo_type == CT_MAIL || - (_opt.landscape == LT_TEMPERATE && p->ai.cargo_type == CT_VALUABLES) + _players_ai[p->index].cargo_type == CT_PASSENGERS || + _players_ai[p->index].cargo_type == CT_MAIL || + (_opt.landscape == LT_TEMPERATE && _players_ai[p->index].cargo_type == CT_VALUABLES) ); Order order; @@ -3256,7 +3257,7 @@ static void AiStateBuildRoadVehicles(Pla order.dest = AiGetStationIdFromRoadBlock(aib->use_tile, aib->cur_building_rule); if (!is_pass && i == 1) order.flags |= OF_UNLOAD; - if (p->ai.num_want_fullload != 0 && (is_pass || i == 0)) + if (_players_ai[p->index].num_want_fullload != 0 && (is_pass || i == 0)) order.flags |= OF_FULL_LOAD; DoCommand(0, loco_id + (i << 16), PackOrder(&order), DC_EXEC, CMD_INSERT_ORDER); @@ -3265,14 +3266,14 @@ static void AiStateBuildRoadVehicles(Pla DoCommand(0, loco_id, 0, DC_EXEC, CMD_START_STOP_ROADVEH); DoCommand(0, loco_id, _ai_service_interval, DC_EXEC, CMD_CHANGE_SERVICE_INT); - if (p->ai.num_want_fullload != 0) p->ai.num_want_fullload--; - if (--p->ai.num_loco_to_build == 0) p->ai.state = AIS_0; + if (_players_ai[p->index].num_want_fullload != 0) _players_ai[p->index].num_want_fullload--; + if (--_players_ai[p->index].num_loco_to_build == 0) _players_ai[p->index].state = AIS_0; } static void AiStateDeleteRoadBlocks(Player *p) { - const AiBuildRec* aib = &p->ai.src; - uint num = p->ai.num_build_rec; + const AiBuildRec* aib = &_players_ai[p->index].src; + uint num = _players_ai[p->index].num_build_rec; do { const AiDefaultBlockData* b; @@ -3284,7 +3285,7 @@ static void AiStateDeleteRoadBlocks(Play } } while (++aib, --num); - p->ai.state = AIS_0; + _players_ai[p->index].state = AIS_0; } @@ -3305,7 +3306,7 @@ static void AiStateAirportStuff(Player * // We do this all twice - once for the source (town in the case // of oilrig route) and then for the destination (oilrig in the // case of oilrig route). - aib = &p->ai.src + i; + aib = &_players_ai[p->index].src + i; FOR_ALL_STATIONS(st) { // Is this an airport? @@ -3316,7 +3317,7 @@ static void AiStateAirportStuff(Player * AirportFTAClass::Flags flags = st->Airport()->flags; - if (!(flags & (p->ai.build_kind == 1 && i == 0 ? AirportFTAClass::HELICOPTERS : AirportFTAClass::AIRPLANES))) { + if (!(flags & (_players_ai[p->index].build_kind == 1 && i == 0 ? AirportFTAClass::HELICOPTERS : AirportFTAClass::AIRPLANES))) { continue; } @@ -3355,11 +3356,11 @@ static void AiStateAirportStuff(Player * aib->use_tile = st->airport_tile; break; } - } while (++i != p->ai.num_build_rec); - - p->ai.state = AIS_BUILD_DEFAULT_AIRPORT_BLOCKS; - p->ai.state_mode = 255; - p->ai.state_counter = 0; + } while (++i != _players_ai[p->index].num_build_rec); + + _players_ai[p->index].state = AIS_BUILD_DEFAULT_AIRPORT_BLOCKS; + _players_ai[p->index].state_mode = 255; + _players_ai[p->index].state_counter = 0; } static CommandCost AiDoBuildDefaultAirportBlock(TileIndex tile, const AiDefaultBlockData *p, byte flag) @@ -3424,8 +3425,8 @@ static void AiStateBuildDefaultAirportBl CommandCost cost; // time out? - if (++p->ai.timeout_counter == 1388) { - p->ai.state = AIS_0; + if (++_players_ai[p->index].timeout_counter == 1388) { + _players_ai[p->index].state = AIS_0; return; } @@ -3433,8 +3434,8 @@ static void AiStateBuildDefaultAirportBl i = 8; do { // check if we can build the default - aib = &p->ai.src; - j = p->ai.num_build_rec; + aib = &_players_ai[p->index].src; + j = _players_ai[p->index].num_build_rec; do { // this item has already been built? if (aib->cur_building_rule != 255) continue; @@ -3444,19 +3445,19 @@ static void AiStateBuildDefaultAirportBl aib->use_tile = AdjustTileCoordRandomly(aib->spec_tile, aib->rand_rng); // check if the aircraft stuff can be built there. - rule = AiFindBestDefaultAirportBlock(aib->use_tile, aib->cargo, p->ai.build_kind, &cost); + rule = AiFindBestDefaultAirportBlock(aib->use_tile, aib->cargo, _players_ai[p->index].build_kind, &cost); // SetRedErrorSquare(aib->use_tile); if (rule == -1) { // cannot build, terraform after a while - if (p->ai.state_counter >= 600) { - AiDoTerraformLand(aib->use_tile, (DiagDirection)(Random() & 3), 3, (int8)p->ai.state_mode); + if (_players_ai[p->index].state_counter >= 600) { + AiDoTerraformLand(aib->use_tile, (DiagDirection)(Random() & 3), 3, (int8)_players_ai[p->index].state_mode); } // also try the other terraform direction - if (++p->ai.state_counter >= 1000) { - p->ai.state_counter = 0; - p->ai.state_mode = -p->ai.state_mode; + if (++_players_ai[p->index].state_counter >= 1000) { + _players_ai[p->index].state_counter = 0; + _players_ai[p->index].state_mode = -_players_ai[p->index].state_mode; } } else if (CheckPlayerHasMoney(cost) && AiCheckBlockDistances(p, aib->use_tile)) { // player has money, build it. @@ -3475,14 +3476,14 @@ static void AiStateBuildDefaultAirportBl } while (--i); // check if we're done with all of them - aib = &p->ai.src; - j = p->ai.num_build_rec; + aib = &_players_ai[p->index].src; + j = _players_ai[p->index].num_build_rec; do { if (aib->cur_building_rule == 255) return; } while (++aib, --j); // yep, all are done. switch state. - p->ai.state = AIS_BUILD_AIRCRAFT_VEHICLES; + _players_ai[p->index].state = AIS_BUILD_AIRCRAFT_VEHICLES; } static StationID AiGetStationIdFromAircraftBlock(TileIndex tile, int id) @@ -3500,12 +3501,12 @@ static void AiStateBuildAircraftVehicles int i; VehicleID loco_id; - ptr = _airport_default_block_data[p->ai.src.cur_building_rule]; + ptr = _airport_default_block_data[_players_ai[p->index].src.cur_building_rule]; for (; ptr->mode != 0; ptr++) {} - tile = TILE_ADD(p->ai.src.use_tile, ToTileIndexDiff(ptr->tileoffs)); - - veh = AiChooseAircraftToBuild(p->player_money, p->ai.build_kind != 0 ? 0 : AIR_CTOL); + tile = TILE_ADD(_players_ai[p->index].src.use_tile, ToTileIndexDiff(ptr->tileoffs)); + + veh = AiChooseAircraftToBuild(p->player_money, _players_ai[p->index].build_kind != 0 ? 0 : AIR_CTOL); if (veh == INVALID_ENGINE) return; /* XXX - Have the AI pick the hangar terminal in an airport. Eg get airport-type @@ -3514,9 +3515,9 @@ static void AiStateBuildAircraftVehicles if (CmdFailed(DoCommand(tile, veh, 0, DC_EXEC, CMD_BUILD_AIRCRAFT))) return; loco_id = _new_vehicle_id; - for (i = 0; p->ai.order_list_blocks[i] != 0xFF; i++) { - AiBuildRec *aib = (&p->ai.src) + p->ai.order_list_blocks[i]; - bool is_pass = (p->ai.cargo_type == CT_PASSENGERS || p->ai.cargo_type == CT_MAIL); + for (i = 0; _players_ai[p->index].order_list_blocks[i] != 0xFF; i++) { + AiBuildRec *aib = (&_players_ai[p->index].src) + _players_ai[p->index].order_list_blocks[i]; + bool is_pass = (_players_ai[p->index].cargo_type == CT_PASSENGERS || _players_ai[p->index].cargo_type == CT_MAIL); Order order; order.type = OT_GOTO_STATION; @@ -3524,7 +3525,7 @@ static void AiStateBuildAircraftVehicles order.dest = AiGetStationIdFromAircraftBlock(aib->use_tile, aib->cur_building_rule); if (!is_pass && i == 1) order.flags |= OF_UNLOAD; - if (p->ai.num_want_fullload != 0 && (is_pass || i == 0)) + if (_players_ai[p->index].num_want_fullload != 0 && (is_pass || i == 0)) order.flags |= OF_FULL_LOAD; DoCommand(0, loco_id + (i << 16), PackOrder(&order), DC_EXEC, CMD_INSERT_ORDER); @@ -3534,9 +3535,9 @@ static void AiStateBuildAircraftVehicles DoCommand(0, loco_id, _ai_service_interval, DC_EXEC, CMD_CHANGE_SERVICE_INT); - if (p->ai.num_want_fullload != 0) p->ai.num_want_fullload--; - - if (--p->ai.num_loco_to_build == 0) p->ai.state = AIS_0; + if (_players_ai[p->index].num_want_fullload != 0) _players_ai[p->index].num_want_fullload--; + + if (--_players_ai[p->index].num_loco_to_build == 0) _players_ai[p->index].state = AIS_0; } static void AiStateCheckShipStuff(Player *p) @@ -3556,7 +3557,7 @@ static void AiStateDoShipStuff(Player *p static void AiStateSellVeh(Player *p) { - Vehicle *v = p->ai.cur_veh; + Vehicle *v = _players_ai[p->index].cur_veh; if (v->owner == _current_player) { if (v->type == VEH_TRAIN) { @@ -3593,7 +3594,7 @@ static void AiStateSellVeh(Player *p) goto return_to_loop; going_to_depot:; - if (++p->ai.state_counter <= 832) return; + if (++_players_ai[p->index].state_counter <= 832) return; if (v->current_order.type == OT_GOTO_DEPOT) { v->current_order.type = OT_DUMMY; @@ -3601,7 +3602,7 @@ going_to_depot:; InvalidateWindow(WC_VEHICLE_VIEW, v->index); } return_to_loop:; - p->ai.state = AIS_VEH_LOOP; + _players_ai[p->index].state = AIS_VEH_LOOP; } static void AiStateRemoveStation(Player *p) @@ -3612,7 +3613,7 @@ static void AiStateRemoveStation(Player TileIndex tile; // Go to this state when we're done. - p->ai.state = AIS_1; + _players_ai[p->index].state = AIS_1; // Get a list of all stations that are in use by a vehicle byte *in_use = MallocT(GetMaxStationIndex() + 1); @@ -3652,9 +3653,9 @@ is_rail_crossing:; if (rails & TRACK_BIT_3WAY_NE) { pos_0: if ((GetRailTrackStatus(TILE_MASK(tile - TileDiffXY(1, 0))) & TRACK_BIT_3WAY_SW) == 0) { - p->ai.cur_dir_a = DIAGDIR_NE; - p->ai.cur_tile_a = tile; - p->ai.state = AIS_REMOVE_SINGLE_RAIL_TILE; + _players_ai[p->index].cur_dir_a = DIAGDIR_NE; + _players_ai[p->index].cur_tile_a = tile; + _players_ai[p->index].state = AIS_REMOVE_SINGLE_RAIL_TILE; return; } } @@ -3662,9 +3663,9 @@ pos_0: if (rails & TRACK_BIT_3WAY_SE) { pos_1: if ((GetRailTrackStatus(TILE_MASK(tile + TileDiffXY(0, 1))) & TRACK_BIT_3WAY_NW) == 0) { - p->ai.cur_dir_a = DIAGDIR_SE; - p->ai.cur_tile_a = tile; - p->ai.state = AIS_REMOVE_SINGLE_RAIL_TILE; + _players_ai[p->index].cur_dir_a = DIAGDIR_SE; + _players_ai[p->index].cur_tile_a = tile; + _players_ai[p->index].state = AIS_REMOVE_SINGLE_RAIL_TILE; return; } } @@ -3672,9 +3673,9 @@ pos_1: if (rails & TRACK_BIT_3WAY_SW) { pos_2: if ((GetRailTrackStatus(TILE_MASK(tile + TileDiffXY(1, 0))) & TRACK_BIT_3WAY_NE) == 0) { - p->ai.cur_dir_a = DIAGDIR_SW; - p->ai.cur_tile_a = tile; - p->ai.state = AIS_REMOVE_SINGLE_RAIL_TILE; + _players_ai[p->index].cur_dir_a = DIAGDIR_SW; + _players_ai[p->index].cur_tile_a = tile; + _players_ai[p->index].state = AIS_REMOVE_SINGLE_RAIL_TILE; return; } } @@ -3682,9 +3683,9 @@ pos_2: if (rails & TRACK_BIT_3WAY_NW) { pos_3: if ((GetRailTrackStatus(TILE_MASK(tile - TileDiffXY(0, 1))) & TRACK_BIT_3WAY_SE) == 0) { - p->ai.cur_dir_a = DIAGDIR_NW; - p->ai.cur_tile_a = tile; - p->ai.state = AIS_REMOVE_SINGLE_RAIL_TILE; + _players_ai[p->index].cur_dir_a = DIAGDIR_NW; + _players_ai[p->index].cur_tile_a = tile; + _players_ai[p->index].state = AIS_REMOVE_SINGLE_RAIL_TILE; return; } } @@ -3755,24 +3756,24 @@ static void AiStateRemoveTrack(Player *p int num = MapSizeX() * 4; do { - TileIndex tile = ++p->ai.state_counter; + TileIndex tile = ++_players_ai[p->index].state_counter; // Iterated all tiles? if (tile >= MapSize()) { - p->ai.state = AIS_REMOVE_STATION; + _players_ai[p->index].state = AIS_REMOVE_STATION; return; } // Remove player stuff in that tile AiRemovePlayerRailOrRoad(p, tile); - if (p->ai.state != AIS_REMOVE_TRACK) return; + if (_players_ai[p->index].state != AIS_REMOVE_TRACK) return; } while (--num); } static void AiStateRemoveSingleRailTile(Player *p) { // Remove until we can't remove more. - if (!AiRemoveTileAndGoForward(p)) p->ai.state = AIS_REMOVE_TRACK; + if (!AiRemoveTileAndGoForward(p)) _players_ai[p->index].state = AIS_REMOVE_TRACK; } static AiStateAction * const _ai_actions[] = { @@ -3949,11 +3950,11 @@ void AiDoGameLoop(Player *p) "AiStateRemoveSingleRailTile" }; - if (p->ai.state != old_state) { + if (_players_ai[p->index].state != old_state) { if (hasdots) printf("\n"); hasdots=false; - printf("AiState: %s\n", _ai_state_names[old_state=p->ai.state]); + printf("AiState: %s\n", _ai_state_names[old_state=_players_ai[p->index].state]); } else { printf("."); hasdots=true; @@ -3961,5 +3962,76 @@ void AiDoGameLoop(Player *p) } #endif - _ai_actions[p->ai.state](p); + _ai_actions[_players_ai[p->index].state](p); } + + +static const SaveLoad _player_ai_desc[] = { + SLE_VAR(PlayerAI, state, SLE_UINT8), + SLE_VAR(PlayerAI, tick, SLE_UINT8), + SLE_CONDVAR(PlayerAI, state_counter, SLE_FILE_U16 | SLE_VAR_U32, 0, 12), + SLE_CONDVAR(PlayerAI, state_counter, SLE_UINT32, 13, SL_MAX_VERSION), + SLE_VAR(PlayerAI, timeout_counter, SLE_UINT16), + + SLE_VAR(PlayerAI, state_mode, SLE_UINT8), + SLE_VAR(PlayerAI, banned_tile_count, SLE_UINT8), + SLE_VAR(PlayerAI, railtype_to_use, SLE_UINT8), + + SLE_VAR(PlayerAI, cargo_type, SLE_UINT8), + SLE_VAR(PlayerAI, num_wagons, SLE_UINT8), + SLE_VAR(PlayerAI, build_kind, SLE_UINT8), + SLE_VAR(PlayerAI, num_build_rec, SLE_UINT8), + SLE_VAR(PlayerAI, num_loco_to_build, SLE_UINT8), + SLE_VAR(PlayerAI, num_want_fullload, SLE_UINT8), + + SLE_VAR(PlayerAI, route_type_mask, SLE_UINT8), + + SLE_CONDVAR(PlayerAI, start_tile_a, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), + SLE_CONDVAR(PlayerAI, start_tile_a, SLE_UINT32, 6, SL_MAX_VERSION), + SLE_CONDVAR(PlayerAI, cur_tile_a, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), + SLE_CONDVAR(PlayerAI, cur_tile_a, SLE_UINT32, 6, SL_MAX_VERSION), + SLE_VAR(PlayerAI, start_dir_a, SLE_UINT8), + SLE_VAR(PlayerAI, cur_dir_a, SLE_UINT8), + + SLE_CONDVAR(PlayerAI, start_tile_b, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), + SLE_CONDVAR(PlayerAI, start_tile_b, SLE_UINT32, 6, SL_MAX_VERSION), + SLE_CONDVAR(PlayerAI, cur_tile_b, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), + SLE_CONDVAR(PlayerAI, cur_tile_b, SLE_UINT32, 6, SL_MAX_VERSION), + SLE_VAR(PlayerAI, start_dir_b, SLE_UINT8), + SLE_VAR(PlayerAI, cur_dir_b, SLE_UINT8), + + SLE_REF(PlayerAI, cur_veh, REF_VEHICLE), + + SLE_ARR(PlayerAI, wagon_list, SLE_UINT16, 9), + SLE_ARR(PlayerAI, order_list_blocks, SLE_UINT8, 20), + SLE_ARR(PlayerAI, banned_tiles, SLE_UINT16, 16), + + SLE_CONDNULL(64, 2, SL_MAX_VERSION), + SLE_END() +}; + +static const SaveLoad _player_ai_build_rec_desc[] = { + SLE_CONDVAR(AiBuildRec, spec_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), + SLE_CONDVAR(AiBuildRec, spec_tile, SLE_UINT32, 6, SL_MAX_VERSION), + SLE_CONDVAR(AiBuildRec, use_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), + SLE_CONDVAR(AiBuildRec, use_tile, SLE_UINT32, 6, SL_MAX_VERSION), + SLE_VAR(AiBuildRec, rand_rng, SLE_UINT8), + SLE_VAR(AiBuildRec, cur_building_rule, SLE_UINT8), + SLE_VAR(AiBuildRec, unk6, SLE_UINT8), + SLE_VAR(AiBuildRec, unk7, SLE_UINT8), + SLE_VAR(AiBuildRec, buildcmd_a, SLE_UINT8), + SLE_VAR(AiBuildRec, buildcmd_b, SLE_UINT8), + SLE_VAR(AiBuildRec, direction, SLE_UINT8), + SLE_VAR(AiBuildRec, cargo, SLE_UINT8), + SLE_END() +}; + + +void SaveLoad_AI(PlayerID id) +{ + PlayerAI *pai = &_players_ai[id]; + SlObject(pai, _player_ai_desc); + for (int i = 0; i != pai->num_build_rec; i++) { + SlObject(&pai->src + i, _player_ai_build_rec_desc); + } +} \ No newline at end of file diff --git a/src/ai/default/default.h b/src/ai/default/default.h --- a/src/ai/default/default.h +++ b/src/ai/default/default.h @@ -4,5 +4,61 @@ #define DEFAULT_H void AiDoGameLoop(Player*); +void SaveLoad_AI(PlayerID id); + +struct AiBuildRec { + TileIndex spec_tile; + TileIndex use_tile; + byte rand_rng; + byte cur_building_rule; + byte unk6; + byte unk7; + byte buildcmd_a; + byte buildcmd_b; + byte direction; + CargoID cargo; +}; + +struct PlayerAI { + byte state; + byte tick; ///< Used to determine how often to move + uint32 state_counter; ///< Can hold tile index! + uint16 timeout_counter; + + byte state_mode; + byte banned_tile_count; + RailTypeByte railtype_to_use; + + CargoID cargo_type; + byte num_wagons; + byte build_kind; + byte num_build_rec; + byte num_loco_to_build; + byte num_want_fullload; + + byte route_type_mask; + + TileIndex start_tile_a; + TileIndex cur_tile_a; + DiagDirectionByte cur_dir_a; + DiagDirectionByte start_dir_a; + + TileIndex start_tile_b; + TileIndex cur_tile_b; + DiagDirectionByte cur_dir_b; + DiagDirectionByte start_dir_b; + + Vehicle *cur_veh; ///< only used by some states + + AiBuildRec src, dst, mid1, mid2; + + VehicleID wagon_list[9]; + byte order_list_blocks[20]; + + TileIndex banned_tiles[16]; + byte banned_val[16]; +}; + +extern PlayerAI _players_ai[MAX_PLAYERS]; #endif diff --git a/src/ai/trolly/build.cpp b/src/ai/trolly/build.cpp --- a/src/ai/trolly/build.cpp +++ b/src/ai/trolly/build.cpp @@ -70,7 +70,7 @@ CommandCost AiNew_Build_Bridge(Player *p if (type2 == 0 && type != 0) type2 = type; // Now, simply, build the bridge! - if (p->ainew.tbt == AI_TRAIN) { + if (_players_ainew[p->index].tbt == AI_TRAIN) { return AI_DoCommand(tile_a, tile_b, (0x00 << 8) + type2, flag | DC_AUTO, CMD_BUILD_BRIDGE); } else { return AI_DoCommand(tile_a, tile_b, ((0x80 | ROADTYPES_ROAD) << 8) + type2, flag | DC_AUTO, CMD_BUILD_BRIDGE); @@ -144,7 +144,7 @@ CommandCost AiNew_Build_RoutePart(Player res = AI_DoCommand(route[part], 0, dir, flag, CMD_BUILD_SINGLE_RAIL); if (CmdFailed(res)) { // Problem.. let's just abort it all! - p->ainew.state = AI_STATE_NOTHING; + _players_ainew[p->index].state = AI_STATE_NOTHING; return CommandCost(); } cost.AddCost(res); @@ -200,7 +200,7 @@ CommandCost AiNew_Build_RoutePart(Player if (CmdFailed(res) && flag == DC_EXEC && !IsTileType(route[part], MP_ROAD) && !EnsureNoVehicleOnGround(route[part])) { // Problem.. let's just abort it all! DEBUG(ai, 0, "[BuidPath] route building failed at tile 0x%X, aborting", route[part]); - p->ainew.state = AI_STATE_NOTHING; + _players_ainew[p->index].state = AI_STATE_NOTHING; return CommandCost(); } @@ -226,7 +226,7 @@ CommandCost AiNew_Build_RoutePart(Player // It returns INVALID_ENGINE if not suitable engine is found EngineID AiNew_PickVehicle(Player *p) { - if (p->ainew.tbt == AI_TRAIN) { + if (_players_ainew[p->index].tbt == AI_TRAIN) { // Not supported yet return INVALID_ENGINE; } else { @@ -244,7 +244,7 @@ EngineID AiNew_PickVehicle(Player *p) CommandCost ret; /* Skip vehicles which can't take our cargo type */ - if (rvi->cargo_type != p->ainew.cargo && !CanRefitTo(i, p->ainew.cargo)) continue; + if (rvi->cargo_type != _players_ainew[p->index].cargo && !CanRefitTo(i, _players_ainew[p->index].cargo)) continue; // Is it availiable? // Also, check if the reliability of the vehicle is above the AI_VEHICLE_MIN_RELIABILTY @@ -272,20 +272,20 @@ void CcAI(bool success, TileIndex tile, Player* p = GetPlayer(_current_player); if (success) { - p->ainew.state = AI_STATE_GIVE_ORDERS; - p->ainew.veh_id = _new_vehicle_id; + _players_ainew[p->index].state = AI_STATE_GIVE_ORDERS; + _players_ainew[p->index].veh_id = _new_vehicle_id; - if (GetVehicle(p->ainew.veh_id)->cargo_type != p->ainew.cargo) { + if (GetVehicle(_players_ainew[p->index].veh_id)->cargo_type != _players_ainew[p->index].cargo) { /* Cargo type doesn't match, so refit it */ - if (CmdFailed(DoCommand(tile, p->ainew.veh_id, p->ainew.cargo, DC_EXEC, CMD_REFIT_ROAD_VEH))) { + if (CmdFailed(DoCommand(tile, _players_ainew[p->index].veh_id, _players_ainew[p->index].cargo, DC_EXEC, CMD_REFIT_ROAD_VEH))) { /* Refit failed, so sell the vehicle */ - DoCommand(tile, p->ainew.veh_id, 0, DC_EXEC, CMD_SELL_ROAD_VEH); - p->ainew.state = AI_STATE_NOTHING; + DoCommand(tile, _players_ainew[p->index].veh_id, 0, DC_EXEC, CMD_SELL_ROAD_VEH); + _players_ainew[p->index].state = AI_STATE_NOTHING; } } } else { /* XXX this should be handled more gracefully */ - p->ainew.state = AI_STATE_NOTHING; + _players_ainew[p->index].state = AI_STATE_NOTHING; } } @@ -296,7 +296,7 @@ CommandCost AiNew_Build_Vehicle(Player * EngineID i = AiNew_PickVehicle(p); if (i == INVALID_ENGINE) return CMD_ERROR; - if (p->ainew.tbt == AI_TRAIN) return CMD_ERROR; + if (_players_ainew[p->index].tbt == AI_TRAIN) return CMD_ERROR; if (flag & DC_EXEC) { return AI_DoCommandCc(tile, i, 0, flag, CMD_BUILD_ROAD_VEH, CcAI); @@ -308,7 +308,7 @@ CommandCost AiNew_Build_Vehicle(Player * CommandCost AiNew_Build_Depot(Player* p, TileIndex tile, DiagDirection direction, byte flag) { CommandCost ret, ret2; - if (p->ainew.tbt == AI_TRAIN) { + if (_players_ainew[p->index].tbt == AI_TRAIN) { return AI_DoCommand(tile, 0, direction, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_TRAIN_DEPOT); } else { ret = AI_DoCommand(tile, direction, 0, flag | DC_AUTO | DC_NO_WATER, CMD_BUILD_ROAD_DEPOT); diff --git a/src/ai/trolly/pathfinder.cpp b/src/ai/trolly/pathfinder.cpp --- a/src/ai/trolly/pathfinder.cpp +++ b/src/ai/trolly/pathfinder.cpp @@ -27,14 +27,14 @@ static bool TestCanBuildStationHere(Tile // TODO: currently we only allow spots that can be access from al 4 directions... // should be fixed!!! for (dir = 0; dir < 4; dir++) { - ret = AiNew_Build_Station(p, p->ainew.tbt, tile, 1, 1, dir, DC_QUERY_COST); + ret = AiNew_Build_Station(p, _players_ainew[p->index].tbt, tile, 1, 1, dir, DC_QUERY_COST); if (CmdSucceeded(ret)) return true; } return false; } // return true if command succeeded, so the inverse of CmdFailed() - return CmdSucceeded(AiNew_Build_Station(p, p->ainew.tbt, tile, 1, 1, dir, DC_QUERY_COST)); + return CmdSucceeded(AiNew_Build_Station(p, _players_ainew[p->index].tbt, tile, 1, 1, dir, DC_QUERY_COST)); } diff --git a/src/ai/trolly/shared.cpp b/src/ai/trolly/shared.cpp --- a/src/ai/trolly/shared.cpp +++ b/src/ai/trolly/shared.cpp @@ -80,8 +80,8 @@ uint AiNew_GetSpecialVehicleFlag(Player* uint i; for (i = 0; i < AI_MAX_SPECIAL_VEHICLES; i++) { - if (p->ainew.special_vehicles[i].veh_id == v->index) { - return p->ainew.special_vehicles[i].flag; + if (_players_ainew[p->index].special_vehicles[i].veh_id == v->index) { + return _players_ainew[p->index].special_vehicles[i].flag; } } @@ -96,13 +96,13 @@ bool AiNew_SetSpecialVehicleFlag(Player* uint i; for (i = 0; i < AI_MAX_SPECIAL_VEHICLES; i++) { - if (p->ainew.special_vehicles[i].veh_id == v->index) { - p->ainew.special_vehicles[i].flag |= flag; + if (_players_ainew[p->index].special_vehicles[i].veh_id == v->index) { + _players_ainew[p->index].special_vehicles[i].flag |= flag; return true; } if (new_id == -1 && - p->ainew.special_vehicles[i].veh_id == 0 && - p->ainew.special_vehicles[i].flag == 0) { + _players_ainew[p->index].special_vehicles[i].veh_id == 0 && + _players_ainew[p->index].special_vehicles[i].flag == 0) { new_id = i; } } @@ -112,7 +112,7 @@ bool AiNew_SetSpecialVehicleFlag(Player* DEBUG(ai, 1, "special_vehicles list is too small"); return false; } - p->ainew.special_vehicles[new_id].veh_id = v->index; - p->ainew.special_vehicles[new_id].flag = flag; + _players_ainew[p->index].special_vehicles[new_id].veh_id = v->index; + _players_ainew[p->index].special_vehicles[new_id].flag = flag; return true; } diff --git a/src/ai/trolly/trolly.cpp b/src/ai/trolly/trolly.cpp --- a/src/ai/trolly/trolly.cpp +++ b/src/ai/trolly/trolly.cpp @@ -37,6 +37,8 @@ #include "../ai.h" #include "../../order.h" +PlayerAiNew _players_ainew[MAX_PLAYERS]; + // This function is called after StartUp. It is the init of an AI static void AiNew_State_FirstTime(Player *p) { @@ -44,7 +46,7 @@ static void AiNew_State_FirstTime(Player // You have quickly a small mistake in the state-array // With that, everything would go wrong. Finding that, is almost impossible // With this assert, that problem can never happen. - assert(p->ainew.state == AI_STATE_FIRST_TIME); + assert(_players_ainew[p->index].state == AI_STATE_FIRST_TIME); // We first have to init some things if (_current_player == 1) ShowErrorMessage(INVALID_STRING_ID, TEMP_AI_IN_PROGRESS, 0, 0); @@ -52,20 +54,20 @@ static void AiNew_State_FirstTime(Player // The PathFinder (AyStar) // TODO: Maybe when an AI goes bankrupt, this is de-init // or when coming from a savegame.. should be checked out! - p->ainew.path_info.start_tile_tl = 0; - p->ainew.path_info.start_tile_br = 0; - p->ainew.path_info.end_tile_tl = 0; - p->ainew.path_info.end_tile_br = 0; - p->ainew.pathfinder = new_AyStar_AiPathFinder(12, &p->ainew.path_info); + _players_ainew[p->index].path_info.start_tile_tl = 0; + _players_ainew[p->index].path_info.start_tile_br = 0; + _players_ainew[p->index].path_info.end_tile_tl = 0; + _players_ainew[p->index].path_info.end_tile_br = 0; + _players_ainew[p->index].pathfinder = new_AyStar_AiPathFinder(12, &_players_ainew[p->index].path_info); - p->ainew.idle = 0; - p->ainew.last_vehiclecheck_date = _date; + _players_ainew[p->index].idle = 0; + _players_ainew[p->index].last_vehiclecheck_date = _date; // We ALWAYS start with a bus route.. just some basic money ;) - p->ainew.action = AI_ACTION_BUS_ROUTE; + _players_ainew[p->index].action = AI_ACTION_BUS_ROUTE; // Let's popup the news, and after that, start building.. - p->ainew.state = AI_STATE_WAKE_UP; + _players_ainew[p->index].state = AI_STATE_WAKE_UP; } @@ -78,13 +80,13 @@ static void AiNew_State_FirstTime(Player // This means that on Very Slow it will be between 16 and 48 days.. slow enough? static void AiNew_State_Nothing(Player *p) { - assert(p->ainew.state == AI_STATE_NOTHING); + assert(_players_ainew[p->index].state == AI_STATE_NOTHING); // If we are done idling, start over again - if (p->ainew.idle == 0) p->ainew.idle = AI_RandomRange(DAY_TICKS * 2) + DAY_TICKS; - if (--p->ainew.idle == 0) { + if (_players_ainew[p->index].idle == 0) _players_ainew[p->index].idle = AI_RandomRange(DAY_TICKS * 2) + DAY_TICKS; + if (--_players_ainew[p->index].idle == 0) { // We are done idling.. what you say? Let's do something! // I mean.. the next tick ;) - p->ainew.state = AI_STATE_WAKE_UP; + _players_ainew[p->index].state = AI_STATE_WAKE_UP; } } @@ -97,7 +99,7 @@ static void AiNew_State_Nothing(Player * static void AiNew_State_WakeUp(Player *p) { int c; - assert(p->ainew.state == AI_STATE_WAKE_UP); + assert(_players_ainew[p->index].state == AI_STATE_WAKE_UP); // First, check if we have a HQ if (p->location_of_house == 0) { // We have no HQ yet, build one on a random place @@ -112,95 +114,95 @@ static void AiNew_State_WakeUp(Player *p Money money = p->player_money - AI_MINIMUM_MONEY; // Let's pick an action! - if (p->ainew.action == AI_ACTION_NONE) { + if (_players_ainew[p->index].action == AI_ACTION_NONE) { c = AI_Random() & 0xFF; if (p->current_loan > 0 && p->old_economy[1].income > AI_MINIMUM_INCOME_FOR_LOAN && c < 10) { - p->ainew.action = AI_ACTION_REPAY_LOAN; - } else if (p->ainew.last_vehiclecheck_date + AI_DAYS_BETWEEN_VEHICLE_CHECKS < _date) { + _players_ainew[p->index].action = AI_ACTION_REPAY_LOAN; + } else if (_players_ainew[p->index].last_vehiclecheck_date + AI_DAYS_BETWEEN_VEHICLE_CHECKS < _date) { // Check all vehicles once in a while - p->ainew.action = AI_ACTION_CHECK_ALL_VEHICLES; - p->ainew.last_vehiclecheck_date = _date; + _players_ainew[p->index].action = AI_ACTION_CHECK_ALL_VEHICLES; + _players_ainew[p->index].last_vehiclecheck_date = _date; } else if (c < 100 && !_patches.ai_disable_veh_roadveh) { // Do we have any spots for road-vehicles left open? if (GetFreeUnitNumber(VEH_ROAD) <= _patches.max_roadveh) { if (c < 85) { - p->ainew.action = AI_ACTION_TRUCK_ROUTE; + _players_ainew[p->index].action = AI_ACTION_TRUCK_ROUTE; } else { - p->ainew.action = AI_ACTION_BUS_ROUTE; + _players_ainew[p->index].action = AI_ACTION_BUS_ROUTE; } } #if 0 } else if (c < 200 && !_patches.ai_disable_veh_train) { if (GetFreeUnitNumber(VEH_TRAIN) <= _patches.max_trains) { - p->ainew.action = AI_ACTION_TRAIN_ROUTE; + _players_ainew[p->index].action = AI_ACTION_TRAIN_ROUTE; } #endif } - p->ainew.counter = 0; + _players_ainew[p->index].counter = 0; } - if (p->ainew.counter++ > AI_MAX_TRIES_FOR_SAME_ROUTE) { - p->ainew.action = AI_ACTION_NONE; + if (_players_ainew[p->index].counter++ > AI_MAX_TRIES_FOR_SAME_ROUTE) { + _players_ainew[p->index].action = AI_ACTION_NONE; return; } if (_patches.ai_disable_veh_roadveh && ( - p->ainew.action == AI_ACTION_BUS_ROUTE || - p->ainew.action == AI_ACTION_TRUCK_ROUTE + _players_ainew[p->index].action == AI_ACTION_BUS_ROUTE || + _players_ainew[p->index].action == AI_ACTION_TRUCK_ROUTE )) { - p->ainew.action = AI_ACTION_NONE; + _players_ainew[p->index].action = AI_ACTION_NONE; return; } - if (p->ainew.action == AI_ACTION_REPAY_LOAN && + if (_players_ainew[p->index].action == AI_ACTION_REPAY_LOAN && money > AI_MINIMUM_LOAN_REPAY_MONEY) { // We start repaying some money.. - p->ainew.state = AI_STATE_REPAY_MONEY; + _players_ainew[p->index].state = AI_STATE_REPAY_MONEY; return; } - if (p->ainew.action == AI_ACTION_CHECK_ALL_VEHICLES) { - p->ainew.state = AI_STATE_CHECK_ALL_VEHICLES; + if (_players_ainew[p->index].action == AI_ACTION_CHECK_ALL_VEHICLES) { + _players_ainew[p->index].state = AI_STATE_CHECK_ALL_VEHICLES; return; } // It is useless to start finding a route if we don't have enough money // to build the route anyway.. - if (p->ainew.action == AI_ACTION_BUS_ROUTE && + if (_players_ainew[p->index].action == AI_ACTION_BUS_ROUTE && money > AI_MINIMUM_BUS_ROUTE_MONEY) { if (GetFreeUnitNumber(VEH_ROAD) > _patches.max_roadveh) { - p->ainew.action = AI_ACTION_NONE; + _players_ainew[p->index].action = AI_ACTION_NONE; return; } - p->ainew.cargo = AI_NEED_CARGO; - p->ainew.state = AI_STATE_LOCATE_ROUTE; - p->ainew.tbt = AI_BUS; // Bus-route + _players_ainew[p->index].cargo = AI_NEED_CARGO; + _players_ainew[p->index].state = AI_STATE_LOCATE_ROUTE; + _players_ainew[p->index].tbt = AI_BUS; // Bus-route return; } - if (p->ainew.action == AI_ACTION_TRUCK_ROUTE && + if (_players_ainew[p->index].action == AI_ACTION_TRUCK_ROUTE && money > AI_MINIMUM_TRUCK_ROUTE_MONEY) { if (GetFreeUnitNumber(VEH_ROAD) > _patches.max_roadveh) { - p->ainew.action = AI_ACTION_NONE; + _players_ainew[p->index].action = AI_ACTION_NONE; return; } - p->ainew.cargo = AI_NEED_CARGO; - p->ainew.last_id = 0; - p->ainew.state = AI_STATE_LOCATE_ROUTE; - p->ainew.tbt = AI_TRUCK; + _players_ainew[p->index].cargo = AI_NEED_CARGO; + _players_ainew[p->index].last_id = 0; + _players_ainew[p->index].state = AI_STATE_LOCATE_ROUTE; + _players_ainew[p->index].tbt = AI_TRUCK; return; } - p->ainew.state = AI_STATE_NOTHING; + _players_ainew[p->index].state = AI_STATE_NOTHING; } static void AiNew_State_ActionDone(Player *p) { - p->ainew.action = AI_ACTION_NONE; - p->ainew.state = AI_STATE_NOTHING; + _players_ainew[p->index].action = AI_ACTION_NONE; + _players_ainew[p->index].state = AI_STATE_NOTHING; } @@ -230,7 +232,7 @@ static bool AiNew_Check_City_or_Industry // Do we own it? if (st->owner == _current_player) { // Are we talking busses? - if (p->ainew.tbt == AI_BUS && (FACIL_BUS_STOP & st->facilities) != FACIL_BUS_STOP) continue; + if (_players_ainew[p->index].tbt == AI_BUS && (FACIL_BUS_STOP & st->facilities) != FACIL_BUS_STOP) continue; // Is it the same city as we are in now? if (st->town != t) continue; // When was this station build? @@ -288,7 +290,7 @@ static bool AiNew_Check_City_or_Industry // Do we own it? if (st->owner == _current_player) { // Are we talking trucks? - if (p->ainew.tbt == AI_TRUCK && (FACIL_TRUCK_STOP & st->facilities) != FACIL_TRUCK_STOP) continue; + if (_players_ainew[p->index].tbt == AI_TRUCK && (FACIL_TRUCK_STOP & st->facilities) != FACIL_TRUCK_STOP) continue; // Is it the same city as we are in now? if (st->town != i->town) continue; // When was this station build? @@ -332,30 +334,30 @@ static bool AiNew_Check_City_or_Industry // This functions tries to locate a good route static void AiNew_State_LocateRoute(Player *p) { - assert(p->ainew.state == AI_STATE_LOCATE_ROUTE); + assert(_players_ainew[p->index].state == AI_STATE_LOCATE_ROUTE); // For now, we only support PASSENGERS, CITY and BUSSES // We don't have a route yet - if (p->ainew.cargo == AI_NEED_CARGO) { - p->ainew.new_cost = 0; // No cost yet - p->ainew.temp = -1; + if (_players_ainew[p->index].cargo == AI_NEED_CARGO) { + _players_ainew[p->index].new_cost = 0; // No cost yet + _players_ainew[p->index].temp = -1; // Reset the counter - p->ainew.counter = 0; + _players_ainew[p->index].counter = 0; - p->ainew.from_ic = -1; - p->ainew.to_ic = -1; - if (p->ainew.tbt == AI_BUS) { + _players_ainew[p->index].from_ic = -1; + _players_ainew[p->index].to_ic = -1; + if (_players_ainew[p->index].tbt == AI_BUS) { // For now we only have a passenger route - p->ainew.cargo = CT_PASSENGERS; + _players_ainew[p->index].cargo = CT_PASSENGERS; // Find a route to cities - p->ainew.from_type = AI_CITY; - p->ainew.to_type = AI_CITY; - } else if (p->ainew.tbt == AI_TRUCK) { - p->ainew.cargo = AI_NO_CARGO; + _players_ainew[p->index].from_type = AI_CITY; + _players_ainew[p->index].to_type = AI_CITY; + } else if (_players_ainew[p->index].tbt == AI_TRUCK) { + _players_ainew[p->index].cargo = AI_NO_CARGO; - p->ainew.from_type = AI_INDUSTRY; - p->ainew.to_type = AI_INDUSTRY; + _players_ainew[p->index].from_type = AI_INDUSTRY; + _players_ainew[p->index].to_type = AI_INDUSTRY; } // Now we are doing initing, we wait one tick @@ -363,63 +365,63 @@ static void AiNew_State_LocateRoute(Play } // Increase the counter and abort if it is taking too long! - p->ainew.counter++; - if (p->ainew.counter > AI_LOCATE_ROUTE_MAX_COUNTER) { + _players_ainew[p->index].counter++; + if (_players_ainew[p->index].counter > AI_LOCATE_ROUTE_MAX_COUNTER) { // Switch back to doing nothing! - p->ainew.state = AI_STATE_NOTHING; + _players_ainew[p->index].state = AI_STATE_NOTHING; return; } // We are going to locate a city from where we are going to connect - if (p->ainew.from_ic == -1) { - if (p->ainew.temp == -1) { + if (_players_ainew[p->index].from_ic == -1) { + if (_players_ainew[p->index].temp == -1) { // First, we pick a random spot to search from - if (p->ainew.from_type == AI_CITY) { - p->ainew.temp = AI_RandomRange(GetMaxTownIndex() + 1); + if (_players_ainew[p->index].from_type == AI_CITY) { + _players_ainew[p->index].temp = AI_RandomRange(GetMaxTownIndex() + 1); } else { - p->ainew.temp = AI_RandomRange(GetMaxIndustryIndex() + 1); + _players_ainew[p->index].temp = AI_RandomRange(GetMaxIndustryIndex() + 1); } } - if (!AiNew_Check_City_or_Industry(p, p->ainew.temp, p->ainew.from_type)) { + if (!AiNew_Check_City_or_Industry(p, _players_ainew[p->index].temp, _players_ainew[p->index].from_type)) { // It was not a valid city // increase the temp with one, and return. We will come back later here // to try again - p->ainew.temp++; - if (p->ainew.from_type == AI_CITY) { - if (p->ainew.temp > GetMaxTownIndex()) p->ainew.temp = 0; + _players_ainew[p->index].temp++; + if (_players_ainew[p->index].from_type == AI_CITY) { + if (_players_ainew[p->index].temp > GetMaxTownIndex()) _players_ainew[p->index].temp = 0; } else { - if (p->ainew.temp > GetMaxIndustryIndex()) p->ainew.temp = 0; + if (_players_ainew[p->index].temp > GetMaxIndustryIndex()) _players_ainew[p->index].temp = 0; } // Don't do an attempt if we are trying the same id as the last time... - if (p->ainew.last_id == p->ainew.temp) return; - p->ainew.last_id = p->ainew.temp; + if (_players_ainew[p->index].last_id == _players_ainew[p->index].temp) return; + _players_ainew[p->index].last_id = _players_ainew[p->index].temp; return; } // We found a good city/industry, save the data of it - p->ainew.from_ic = p->ainew.temp; + _players_ainew[p->index].from_ic = _players_ainew[p->index].temp; // Start the next tick with finding a to-city - p->ainew.temp = -1; + _players_ainew[p->index].temp = -1; return; } // Find a to-city - if (p->ainew.temp == -1) { + if (_players_ainew[p->index].temp == -1) { // First, we pick a random spot to search to - if (p->ainew.to_type == AI_CITY) { - p->ainew.temp = AI_RandomRange(GetMaxTownIndex() + 1); + if (_players_ainew[p->index].to_type == AI_CITY) { + _players_ainew[p->index].temp = AI_RandomRange(GetMaxTownIndex() + 1); } else { - p->ainew.temp = AI_RandomRange(GetMaxIndustryIndex() + 1); + _players_ainew[p->index].temp = AI_RandomRange(GetMaxIndustryIndex() + 1); } } // The same city is not allowed // Also check if the city is valid - if (p->ainew.temp != p->ainew.from_ic && AiNew_Check_City_or_Industry(p, p->ainew.temp, p->ainew.to_type)) { + if (_players_ainew[p->index].temp != _players_ainew[p->index].from_ic && AiNew_Check_City_or_Industry(p, _players_ainew[p->index].temp, _players_ainew[p->index].to_type)) { // Maybe it is valid.. /* We need to know if they are not to far apart from eachother.. @@ -427,9 +429,9 @@ static void AiNew_State_LocateRoute(Play * route is. */ - if (p->ainew.from_type == AI_CITY && p->ainew.tbt == AI_BUS) { - const Town* town_from = GetTown(p->ainew.from_ic); - const Town* town_temp = GetTown(p->ainew.temp); + if (_players_ainew[p->index].from_type == AI_CITY && _players_ainew[p->index].tbt == AI_BUS) { + const Town* town_from = GetTown(_players_ainew[p->index].from_ic); + const Town* town_temp = GetTown(_players_ainew[p->index].temp); uint distance = DistanceManhattan(town_from->xy, town_temp->xy); int max_cargo; @@ -440,23 +442,23 @@ static void AiNew_State_LocateRoute(Play // If it is more than the distance, we allow it if (distance <= max_cargo * AI_LOCATEROUTE_BUS_CARGO_DISTANCE) { // We found a good city/industry, save the data of it - p->ainew.to_ic = p->ainew.temp; - p->ainew.state = AI_STATE_FIND_STATION; + _players_ainew[p->index].to_ic = _players_ainew[p->index].temp; + _players_ainew[p->index].state = AI_STATE_FIND_STATION; DEBUG(ai, 1, "[LocateRoute] found bus-route of %d tiles long (from %d to %d)", distance, - p->ainew.from_ic, - p->ainew.temp + _players_ainew[p->index].from_ic, + _players_ainew[p->index].temp ); - p->ainew.from_tile = 0; - p->ainew.to_tile = 0; + _players_ainew[p->index].from_tile = 0; + _players_ainew[p->index].to_tile = 0; return; } - } else if (p->ainew.tbt == AI_TRUCK) { - const Industry* ind_from = GetIndustry(p->ainew.from_ic); - const Industry* ind_temp = GetIndustry(p->ainew.temp); + } else if (_players_ainew[p->index].tbt == AI_TRUCK) { + const Industry* ind_from = GetIndustry(_players_ainew[p->index].from_ic); + const Industry* ind_temp = GetIndustry(_players_ainew[p->index].temp); bool found = false; int max_cargo = 0; uint i; @@ -470,8 +472,8 @@ static void AiNew_State_LocateRoute(Play // Found a compatible industry max_cargo = ind_from->last_month_production[0] - ind_from->last_month_transported[0]; found = true; - p->ainew.from_deliver = true; - p->ainew.to_deliver = false; + _players_ainew[p->index].from_deliver = true; + _players_ainew[p->index].to_deliver = false; break; } } @@ -484,8 +486,8 @@ static void AiNew_State_LocateRoute(Play // Found a compatbiel industry found = true; max_cargo = ind_temp->last_month_production[0] - ind_temp->last_month_transported[0]; - p->ainew.from_deliver = false; - p->ainew.to_deliver = true; + _players_ainew[p->index].from_deliver = false; + _players_ainew[p->index].to_deliver = true; break; } } @@ -497,22 +499,22 @@ static void AiNew_State_LocateRoute(Play if (distance > AI_LOCATEROUTE_TRUCK_MIN_DISTANCE && distance <= max_cargo * AI_LOCATEROUTE_TRUCK_CARGO_DISTANCE) { - p->ainew.to_ic = p->ainew.temp; - if (p->ainew.from_deliver) { - p->ainew.cargo = ind_from->produced_cargo[0]; + _players_ainew[p->index].to_ic = _players_ainew[p->index].temp; + if (_players_ainew[p->index].from_deliver) { + _players_ainew[p->index].cargo = ind_from->produced_cargo[0]; } else { - p->ainew.cargo = ind_temp->produced_cargo[0]; + _players_ainew[p->index].cargo = ind_temp->produced_cargo[0]; } - p->ainew.state = AI_STATE_FIND_STATION; + _players_ainew[p->index].state = AI_STATE_FIND_STATION; DEBUG(ai, 1, "[LocateRoute] found truck-route of %d tiles long (from %d to %d)", distance, - p->ainew.from_ic, - p->ainew.temp + _players_ainew[p->index].from_ic, + _players_ainew[p->index].temp ); - p->ainew.from_tile = 0; - p->ainew.to_tile = 0; + _players_ainew[p->index].from_tile = 0; + _players_ainew[p->index].to_tile = 0; return; } @@ -523,16 +525,16 @@ static void AiNew_State_LocateRoute(Play // It was not a valid city // increase the temp with one, and return. We will come back later here // to try again - p->ainew.temp++; - if (p->ainew.to_type == AI_CITY) { - if (p->ainew.temp > GetMaxTownIndex()) p->ainew.temp = 0; + _players_ainew[p->index].temp++; + if (_players_ainew[p->index].to_type == AI_CITY) { + if (_players_ainew[p->index].temp > GetMaxTownIndex()) _players_ainew[p->index].temp = 0; } else { - if (p->ainew.temp > GetMaxIndustryIndex()) p->ainew.temp = 0; + if (_players_ainew[p->index].temp > GetMaxIndustryIndex()) _players_ainew[p->index].temp = 0; } // Don't do an attempt if we are trying the same id as the last time... - if (p->ainew.last_id == p->ainew.temp) return; - p->ainew.last_id = p->ainew.temp; + if (_players_ainew[p->index].last_id == _players_ainew[p->index].temp) return; + _players_ainew[p->index].last_id = _players_ainew[p->index].temp; } @@ -571,29 +573,29 @@ static void AiNew_State_FindStation(Play TileIndex new_tile = 0; DiagDirection direction = DIAGDIR_NE; Town *town = NULL; - assert(p->ainew.state == AI_STATE_FIND_STATION); + assert(_players_ainew[p->index].state == AI_STATE_FIND_STATION); - if (p->ainew.from_tile == 0) { + if (_players_ainew[p->index].from_tile == 0) { // First we scan for a station in the from-city - if (p->ainew.from_type == AI_CITY) { - town = GetTown(p->ainew.from_ic); + if (_players_ainew[p->index].from_type == AI_CITY) { + town = GetTown(_players_ainew[p->index].from_ic); tile = town->xy; } else { - tile = GetIndustry(p->ainew.from_ic)->xy; + tile = GetIndustry(_players_ainew[p->index].from_ic)->xy; } - } else if (p->ainew.to_tile == 0) { + } else if (_players_ainew[p->index].to_tile == 0) { // Second we scan for a station in the to-city - if (p->ainew.to_type == AI_CITY) { - town = GetTown(p->ainew.to_ic); + if (_players_ainew[p->index].to_type == AI_CITY) { + town = GetTown(_players_ainew[p->index].to_ic); tile = town->xy; } else { - tile = GetIndustry(p->ainew.to_ic)->xy; + tile = GetIndustry(_players_ainew[p->index].to_ic)->xy; } } else { // Unsupported request // Go to FIND_PATH - p->ainew.temp = -1; - p->ainew.state = AI_STATE_FIND_PATH; + _players_ainew[p->index].temp = -1; + _players_ainew[p->index].state = AI_STATE_FIND_PATH; return; } @@ -604,16 +606,16 @@ static void AiNew_State_FindStation(Play // Euhmz, this should not happen _EVER_ // Quit finding a route... if (i == INVALID_ENGINE) { - p->ainew.state = AI_STATE_NOTHING; + _players_ainew[p->index].state = AI_STATE_NOTHING; return; } FOR_ALL_STATIONS(st) { if (st->owner == _current_player) { - if (p->ainew.tbt == AI_BUS && (FACIL_BUS_STOP & st->facilities) == FACIL_BUS_STOP) { + if (_players_ainew[p->index].tbt == AI_BUS && (FACIL_BUS_STOP & st->facilities) == FACIL_BUS_STOP) { if (st->town == town) { // Check how much cargo there is left in the station - if ((int)st->goods[p->ainew.cargo].cargo.Count() > RoadVehInfo(i)->capacity * AI_STATION_REUSE_MULTIPLER) { + if ((int)st->goods[_players_ainew[p->index].cargo].cargo.Count() > RoadVehInfo(i)->capacity * AI_STATION_REUSE_MULTIPLER) { if (AiNew_CheckVehicleStation(p, st)) { // We did found a station that was good enough! new_tile = st->xy; @@ -631,11 +633,11 @@ static void AiNew_State_FindStation(Play // No more than 2 stations allowed in a city // This is because only the best 2 stations of one cargo do get any cargo if (count > 2) { - p->ainew.state = AI_STATE_NOTHING; + _players_ainew[p->index].state = AI_STATE_NOTHING; return; } - if (new_tile == 0 && p->ainew.tbt == AI_BUS) { + if (new_tile == 0 && _players_ainew[p->index].tbt == AI_BUS) { uint x, y, i = 0; CommandCost r; uint best; @@ -655,20 +657,20 @@ static void AiNew_State_FindStation(Play // XXX - Get the catchment area GetAcceptanceAroundTiles(accepts, new_tile, 1, 1, 4); // >> 3 == 0 means no cargo - if (accepts[p->ainew.cargo] >> 3 == 0) continue; + if (accepts[_players_ainew[p->index].cargo] >> 3 == 0) continue; // See if we can build the station - r = AiNew_Build_Station(p, p->ainew.tbt, new_tile, 0, 0, 0, DC_QUERY_COST); + r = AiNew_Build_Station(p, _players_ainew[p->index].tbt, new_tile, 0, 0, 0, DC_QUERY_COST); if (CmdFailed(r)) continue; // We can build it, so add it to found_spot found_spot[i] = new_tile; - found_best[i++] = accepts[p->ainew.cargo]; + found_best[i++] = accepts[_players_ainew[p->index].cargo]; } } } // If i is still zero, we did not find anything if (i == 0) { - p->ainew.state = AI_STATE_NOTHING; + _players_ainew[p->index].state = AI_STATE_NOTHING; return; } @@ -685,11 +687,11 @@ static void AiNew_State_FindStation(Play } // See how much it is going to cost us... - r = AiNew_Build_Station(p, p->ainew.tbt, new_tile, 0, 0, 0, DC_QUERY_COST); - p->ainew.new_cost += r.GetCost(); + r = AiNew_Build_Station(p, _players_ainew[p->index].tbt, new_tile, 0, 0, 0, DC_QUERY_COST); + _players_ainew[p->index].new_cost += r.GetCost(); direction = (DiagDirection)AI_PATHFINDER_NO_DIRECTION; - } else if (new_tile == 0 && p->ainew.tbt == AI_TRUCK) { + } else if (new_tile == 0 && _players_ainew[p->index].tbt == AI_TRUCK) { // Truck station locater works differently.. a station can be on any place // as long as it is in range. So we give back code AI_STATION_RANGE // so the pathfinder routine can work it out! @@ -697,17 +699,17 @@ static void AiNew_State_FindStation(Play direction = (DiagDirection)AI_PATHFINDER_NO_DIRECTION; } - if (p->ainew.from_tile == 0) { - p->ainew.from_tile = new_tile; - p->ainew.from_direction = direction; + if (_players_ainew[p->index].from_tile == 0) { + _players_ainew[p->index].from_tile = new_tile; + _players_ainew[p->index].from_direction = direction; // Now we found thisone, go in for to_tile return; - } else if (p->ainew.to_tile == 0) { - p->ainew.to_tile = new_tile; - p->ainew.to_direction = direction; + } else if (_players_ainew[p->index].to_tile == 0) { + _players_ainew[p->index].to_tile = new_tile; + _players_ainew[p->index].to_direction = direction; // K, done placing stations! - p->ainew.temp = -1; - p->ainew.state = AI_STATE_FIND_PATH; + _players_ainew[p->index].temp = -1; + _players_ainew[p->index].state = AI_STATE_FIND_PATH; return; } } @@ -717,56 +719,56 @@ static void AiNew_State_FindStation(Play static void AiNew_State_FindPath(Player *p) { int r; - assert(p->ainew.state == AI_STATE_FIND_PATH); + assert(_players_ainew[p->index].state == AI_STATE_FIND_PATH); // First time, init some data - if (p->ainew.temp == -1) { + if (_players_ainew[p->index].temp == -1) { // Init path_info - if (p->ainew.from_tile == AI_STATION_RANGE) { - const Industry* i = GetIndustry(p->ainew.from_ic); + if (_players_ainew[p->index].from_tile == AI_STATION_RANGE) { + const Industry* i = GetIndustry(_players_ainew[p->index].from_ic); // For truck routes we take a range around the industry - p->ainew.path_info.start_tile_tl = i->xy - TileDiffXY(1, 1); - p->ainew.path_info.start_tile_br = i->xy + TileDiffXY(i->width + 1, i->height + 1); - p->ainew.path_info.start_direction = p->ainew.from_direction; + _players_ainew[p->index].path_info.start_tile_tl = i->xy - TileDiffXY(1, 1); + _players_ainew[p->index].path_info.start_tile_br = i->xy + TileDiffXY(i->width + 1, i->height + 1); + _players_ainew[p->index].path_info.start_direction = _players_ainew[p->index].from_direction; } else { - p->ainew.path_info.start_tile_tl = p->ainew.from_tile; - p->ainew.path_info.start_tile_br = p->ainew.from_tile; - p->ainew.path_info.start_direction = p->ainew.from_direction; + _players_ainew[p->index].path_info.start_tile_tl = _players_ainew[p->index].from_tile; + _players_ainew[p->index].path_info.start_tile_br = _players_ainew[p->index].from_tile; + _players_ainew[p->index].path_info.start_direction = _players_ainew[p->index].from_direction; } - if (p->ainew.to_tile == AI_STATION_RANGE) { - const Industry* i = GetIndustry(p->ainew.to_ic); + if (_players_ainew[p->index].to_tile == AI_STATION_RANGE) { + const Industry* i = GetIndustry(_players_ainew[p->index].to_ic); - p->ainew.path_info.end_tile_tl = i->xy - TileDiffXY(1, 1); - p->ainew.path_info.end_tile_br = i->xy + TileDiffXY(i->width + 1, i->height + 1); - p->ainew.path_info.end_direction = p->ainew.to_direction; + _players_ainew[p->index].path_info.end_tile_tl = i->xy - TileDiffXY(1, 1); + _players_ainew[p->index].path_info.end_tile_br = i->xy + TileDiffXY(i->width + 1, i->height + 1); + _players_ainew[p->index].path_info.end_direction = _players_ainew[p->index].to_direction; } else { - p->ainew.path_info.end_tile_tl = p->ainew.to_tile; - p->ainew.path_info.end_tile_br = p->ainew.to_tile; - p->ainew.path_info.end_direction = p->ainew.to_direction; + _players_ainew[p->index].path_info.end_tile_tl = _players_ainew[p->index].to_tile; + _players_ainew[p->index].path_info.end_tile_br = _players_ainew[p->index].to_tile; + _players_ainew[p->index].path_info.end_direction = _players_ainew[p->index].to_direction; } - p->ainew.path_info.rail_or_road = (p->ainew.tbt == AI_TRAIN); + _players_ainew[p->index].path_info.rail_or_road = (_players_ainew[p->index].tbt == AI_TRAIN); // First, clean the pathfinder with our new begin and endpoints - clean_AyStar_AiPathFinder(p->ainew.pathfinder, &p->ainew.path_info); + clean_AyStar_AiPathFinder(_players_ainew[p->index].pathfinder, &_players_ainew[p->index].path_info); - p->ainew.temp = 0; + _players_ainew[p->index].temp = 0; } // Start the pathfinder - r = p->ainew.pathfinder->main(p->ainew.pathfinder); + r = _players_ainew[p->index].pathfinder->main(_players_ainew[p->index].pathfinder); switch (r) { case AYSTAR_NO_PATH: DEBUG(ai, 1, "No route found by pathfinder"); // Start all over again - p->ainew.state = AI_STATE_NOTHING; + _players_ainew[p->index].state = AI_STATE_NOTHING; break; case AYSTAR_FOUND_END_NODE: // We found the end-point - p->ainew.temp = -1; - p->ainew.state = AI_STATE_FIND_DEPOT; + _players_ainew[p->index].temp = -1; + _players_ainew[p->index].state = AI_STATE_FIND_DEPOT; break; // In any other case, we are still busy finding the route @@ -787,12 +789,12 @@ static void AiNew_State_FindDepot(Player CommandCost r; DiagDirection j; TileIndex tile; - assert(p->ainew.state == AI_STATE_FIND_DEPOT); + assert(_players_ainew[p->index].state == AI_STATE_FIND_DEPOT); - p->ainew.depot_tile = 0; + _players_ainew[p->index].depot_tile = 0; - for (i=2;iainew.path_info.route_length-2;i++) { - tile = p->ainew.path_info.route[i]; + for (i=2;i<_players_ainew[p->index].path_info.route_length-2;i++) { + tile = _players_ainew[p->index].path_info.route[i]; for (j = DIAGDIR_BEGIN; j < DIAGDIR_END; j++) { TileIndex t = tile + TileOffsByDiagDir(j); @@ -800,9 +802,9 @@ static void AiNew_State_FindDepot(Player GetRoadTileType(t) == ROAD_TILE_DEPOT && IsTileOwner(t, _current_player) && GetRoadDepotDirection(t) == ReverseDiagDir(j)) { - p->ainew.depot_tile = t; - p->ainew.depot_direction = ReverseDiagDir(j); - p->ainew.state = AI_STATE_VERIFY_ROUTE; + _players_ainew[p->index].depot_tile = t; + _players_ainew[p->index].depot_direction = ReverseDiagDir(j); + _players_ainew[p->index].state = AI_STATE_VERIFY_ROUTE; return; } } @@ -810,19 +812,19 @@ static void AiNew_State_FindDepot(Player // This routine let depot finding start in the middle, and work his way to the stations // It makes depot placing nicer :) - i = p->ainew.path_info.route_length / 2; + i = _players_ainew[p->index].path_info.route_length / 2; g = 1; - while (i > 1 && i < p->ainew.path_info.route_length - 2) { + while (i > 1 && i < _players_ainew[p->index].path_info.route_length - 2) { i += g; g *= -1; (g < 0?g--:g++); - if (p->ainew.path_info.route_extra[i] != 0 || p->ainew.path_info.route_extra[i+1] != 0) { + if (_players_ainew[p->index].path_info.route_extra[i] != 0 || _players_ainew[p->index].path_info.route_extra[i+1] != 0) { // Bridge or tunnel.. we can't place a depot there continue; } - tile = p->ainew.path_info.route[i]; + tile = _players_ainew[p->index].path_info.route[i]; for (j = DIAGDIR_BEGIN; j < DIAGDIR_END; j++) { TileIndex t = tile + TileOffsByDiagDir(j); @@ -830,12 +832,12 @@ static void AiNew_State_FindDepot(Player // It may not be placed on the road/rail itself // And because it is not build yet, we can't see it on the tile.. // So check the surrounding tiles :) - if (t == p->ainew.path_info.route[i - 1] || - t == p->ainew.path_info.route[i + 1]) { + if (t == _players_ainew[p->index].path_info.route[i - 1] || + t == _players_ainew[p->index].path_info.route[i + 1]) { continue; } // Not around a bridge? - if (p->ainew.path_info.route_extra[i] != 0) continue; + if (_players_ainew[p->index].path_info.route_extra[i] != 0) continue; if (IsTileType(tile, MP_TUNNELBRIDGE)) continue; // Is the terrain clear? if (IsTileType(t, MP_CLEAR) || IsTileType(t, MP_TREES)) { @@ -845,17 +847,17 @@ static void AiNew_State_FindDepot(Player r = AiNew_Build_Depot(p, t, ReverseDiagDir(j), 0); if (CmdFailed(r)) continue; // Found a spot! - p->ainew.new_cost += r.GetCost(); - p->ainew.depot_tile = t; - p->ainew.depot_direction = ReverseDiagDir(j); // Reverse direction - p->ainew.state = AI_STATE_VERIFY_ROUTE; + _players_ainew[p->index].new_cost += r.GetCost(); + _players_ainew[p->index].depot_tile = t; + _players_ainew[p->index].depot_direction = ReverseDiagDir(j); // Reverse direction + _players_ainew[p->index].state = AI_STATE_VERIFY_ROUTE; return; } } } // Failed to find a depot? - p->ainew.state = AI_STATE_NOTHING; + _players_ainew[p->index].state = AI_STATE_NOTHING; } @@ -866,7 +868,7 @@ static void AiNew_State_FindDepot(Player // It returns the cost for the vehicles static int AiNew_HowManyVehicles(Player *p) { - if (p->ainew.tbt == AI_BUS) { + if (_players_ainew[p->index].tbt == AI_BUS) { // For bus-routes we look at the time before we are back in the station EngineID i; int length, tiles_a_day; @@ -874,7 +876,7 @@ static int AiNew_HowManyVehicles(Player i = AiNew_PickVehicle(p); if (i == INVALID_ENGINE) return 0; // Passenger run.. how long is the route? - length = p->ainew.path_info.route_length; + length = _players_ainew[p->index].path_info.route_length; // Calculating tiles a day a vehicle moves is not easy.. this is how it must be done! tiles_a_day = RoadVehInfo(i)->max_speed * DAY_TICKS / 256 / 16; // We want a vehicle in a station once a month at least, so, calculate it! @@ -882,7 +884,7 @@ static int AiNew_HowManyVehicles(Player amount = length * 2 * 2 / tiles_a_day / 30; if (amount == 0) amount = 1; return amount; - } else if (p->ainew.tbt == AI_TRUCK) { + } else if (_players_ainew[p->index].tbt == AI_TRUCK) { // For truck-routes we look at the cargo EngineID i; int length, amount, tiles_a_day; @@ -890,13 +892,13 @@ static int AiNew_HowManyVehicles(Player i = AiNew_PickVehicle(p); if (i == INVALID_ENGINE) return 0; // Passenger run.. how long is the route? - length = p->ainew.path_info.route_length; + length = _players_ainew[p->index].path_info.route_length; // Calculating tiles a day a vehicle moves is not easy.. this is how it must be done! tiles_a_day = RoadVehInfo(i)->max_speed * DAY_TICKS / 256 / 16; - if (p->ainew.from_deliver) { - max_cargo = GetIndustry(p->ainew.from_ic)->last_month_production[0]; + if (_players_ainew[p->index].from_deliver) { + max_cargo = GetIndustry(_players_ainew[p->index].from_ic)->last_month_production[0]; } else { - max_cargo = GetIndustry(p->ainew.to_ic)->last_month_production[0]; + max_cargo = GetIndustry(_players_ainew[p->index].to_ic)->last_month_production[0]; } // This is because moving 60% is more than we can dream of! @@ -922,58 +924,58 @@ static int AiNew_HowManyVehicles(Player static void AiNew_State_VerifyRoute(Player *p) { int res, i; - assert(p->ainew.state == AI_STATE_VERIFY_ROUTE); + assert(_players_ainew[p->index].state == AI_STATE_VERIFY_ROUTE); // Let's calculate the cost of the path.. // new_cost already contains the cost of the stations - p->ainew.path_info.position = -1; + _players_ainew[p->index].path_info.position = -1; do { - p->ainew.path_info.position++; - p->ainew.new_cost += AiNew_Build_RoutePart(p, &p->ainew.path_info, DC_QUERY_COST).GetCost(); - } while (p->ainew.path_info.position != -2); + _players_ainew[p->index].path_info.position++; + _players_ainew[p->index].new_cost += AiNew_Build_RoutePart(p, &_players_ainew[p->index].path_info, DC_QUERY_COST).GetCost(); + } while (_players_ainew[p->index].path_info.position != -2); // Now we know the price of build station + path. Now check how many vehicles // we need and what the price for that will be res = AiNew_HowManyVehicles(p); // If res == 0, no vehicle was found, or an other problem did occour if (res == 0) { - p->ainew.state = AI_STATE_NOTHING; + _players_ainew[p->index].state = AI_STATE_NOTHING; return; } - p->ainew.amount_veh = res; - p->ainew.cur_veh = 0; + _players_ainew[p->index].amount_veh = res; + _players_ainew[p->index].cur_veh = 0; // Check how much it it going to cost us.. for (i=0;iainew.new_cost += AiNew_Build_Vehicle(p, 0, DC_QUERY_COST).GetCost(); + _players_ainew[p->index].new_cost += AiNew_Build_Vehicle(p, 0, DC_QUERY_COST).GetCost(); } // Now we know how much the route is going to cost us // Check if we have enough money for it! - if (p->ainew.new_cost > p->player_money - AI_MINIMUM_MONEY) { + if (_players_ainew[p->index].new_cost > p->player_money - AI_MINIMUM_MONEY) { // Too bad.. - DEBUG(ai, 1, "Insufficient funds to build route (%" OTTD_PRINTF64 "d)", (int64)p->ainew.new_cost); - p->ainew.state = AI_STATE_NOTHING; + DEBUG(ai, 1, "Insufficient funds to build route (%" OTTD_PRINTF64 "d)", (int64)_players_ainew[p->index].new_cost); + _players_ainew[p->index].state = AI_STATE_NOTHING; return; } // Now we can build the route, check the direction of the stations! - if (p->ainew.from_direction == AI_PATHFINDER_NO_DIRECTION) { - p->ainew.from_direction = AiNew_GetDirection(p->ainew.path_info.route[p->ainew.path_info.route_length - 1], p->ainew.path_info.route[p->ainew.path_info.route_length - 2]); + if (_players_ainew[p->index].from_direction == AI_PATHFINDER_NO_DIRECTION) { + _players_ainew[p->index].from_direction = AiNew_GetDirection(_players_ainew[p->index].path_info.route[_players_ainew[p->index].path_info.route_length - 1], _players_ainew[p->index].path_info.route[_players_ainew[p->index].path_info.route_length - 2]); } - if (p->ainew.to_direction == AI_PATHFINDER_NO_DIRECTION) { - p->ainew.to_direction = AiNew_GetDirection(p->ainew.path_info.route[0], p->ainew.path_info.route[1]); + if (_players_ainew[p->index].to_direction == AI_PATHFINDER_NO_DIRECTION) { + _players_ainew[p->index].to_direction = AiNew_GetDirection(_players_ainew[p->index].path_info.route[0], _players_ainew[p->index].path_info.route[1]); } - if (p->ainew.from_tile == AI_STATION_RANGE) - p->ainew.from_tile = p->ainew.path_info.route[p->ainew.path_info.route_length - 1]; - if (p->ainew.to_tile == AI_STATION_RANGE) - p->ainew.to_tile = p->ainew.path_info.route[0]; + if (_players_ainew[p->index].from_tile == AI_STATION_RANGE) + _players_ainew[p->index].from_tile = _players_ainew[p->index].path_info.route[_players_ainew[p->index].path_info.route_length - 1]; + if (_players_ainew[p->index].to_tile == AI_STATION_RANGE) + _players_ainew[p->index].to_tile = _players_ainew[p->index].path_info.route[0]; - p->ainew.state = AI_STATE_BUILD_STATION; - p->ainew.temp = 0; + _players_ainew[p->index].state = AI_STATE_BUILD_STATION; + _players_ainew[p->index].temp = 0; - DEBUG(ai, 1, "The route is set and buildable, building 0x%X to 0x%X...", p->ainew.from_tile, p->ainew.to_tile); + DEBUG(ai, 1, "The route is set and buildable, building 0x%X to 0x%X...", _players_ainew[p->index].from_tile, _players_ainew[p->index].to_tile); } @@ -981,54 +983,54 @@ static void AiNew_State_VerifyRoute(Play static void AiNew_State_BuildStation(Player *p) { CommandCost res; - assert(p->ainew.state == AI_STATE_BUILD_STATION); - if (p->ainew.temp == 0) { - if (!IsTileType(p->ainew.from_tile, MP_STATION)) - res = AiNew_Build_Station(p, p->ainew.tbt, p->ainew.from_tile, 0, 0, p->ainew.from_direction, DC_EXEC); + assert(_players_ainew[p->index].state == AI_STATE_BUILD_STATION); + if (_players_ainew[p->index].temp == 0) { + if (!IsTileType(_players_ainew[p->index].from_tile, MP_STATION)) + res = AiNew_Build_Station(p, _players_ainew[p->index].tbt, _players_ainew[p->index].from_tile, 0, 0, _players_ainew[p->index].from_direction, DC_EXEC); } else { - if (!IsTileType(p->ainew.to_tile, MP_STATION)) - res = AiNew_Build_Station(p, p->ainew.tbt, p->ainew.to_tile, 0, 0, p->ainew.to_direction, DC_EXEC); - p->ainew.state = AI_STATE_BUILD_PATH; + if (!IsTileType(_players_ainew[p->index].to_tile, MP_STATION)) + res = AiNew_Build_Station(p, _players_ainew[p->index].tbt, _players_ainew[p->index].to_tile, 0, 0, _players_ainew[p->index].to_direction, DC_EXEC); + _players_ainew[p->index].state = AI_STATE_BUILD_PATH; } if (CmdFailed(res)) { - DEBUG(ai, 0, "[BuildStation] station could not be built (0x%X)", p->ainew.to_tile); - p->ainew.state = AI_STATE_NOTHING; + DEBUG(ai, 0, "[BuildStation] station could not be built (0x%X)", _players_ainew[p->index].to_tile); + _players_ainew[p->index].state = AI_STATE_NOTHING; // If the first station _was_ build, destroy it - if (p->ainew.temp != 0) - AI_DoCommand(p->ainew.from_tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR); + if (_players_ainew[p->index].temp != 0) + AI_DoCommand(_players_ainew[p->index].from_tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR); return; } - p->ainew.temp++; + _players_ainew[p->index].temp++; } // Build the path static void AiNew_State_BuildPath(Player *p) { - assert(p->ainew.state == AI_STATE_BUILD_PATH); - // p->ainew.temp is set to -1 when this function is called for the first time - if (p->ainew.temp == -1) { + assert(_players_ainew[p->index].state == AI_STATE_BUILD_PATH); + // _players_ainew[p->index].temp is set to -1 when this function is called for the first time + if (_players_ainew[p->index].temp == -1) { DEBUG(ai, 1, "Starting to build new path"); // Init the counter - p->ainew.counter = (4 - _opt.diff.competitor_speed) * AI_BUILDPATH_PAUSE + 1; + _players_ainew[p->index].counter = (4 - _opt.diff.competitor_speed) * AI_BUILDPATH_PAUSE + 1; // Set the position to the startingplace (-1 because in a minute we do ++) - p->ainew.path_info.position = -1; + _players_ainew[p->index].path_info.position = -1; // And don't do this again - p->ainew.temp = 0; + _players_ainew[p->index].temp = 0; } // Building goes very fast on normal rate, so we are going to slow it down.. // By let the counter count from AI_BUILDPATH_PAUSE to 0, we have a nice way :) - if (--p->ainew.counter != 0) return; - p->ainew.counter = (4 - _opt.diff.competitor_speed) * AI_BUILDPATH_PAUSE + 1; + if (--_players_ainew[p->index].counter != 0) return; + _players_ainew[p->index].counter = (4 - _opt.diff.competitor_speed) * AI_BUILDPATH_PAUSE + 1; // Increase the building position - p->ainew.path_info.position++; + _players_ainew[p->index].path_info.position++; // Build route - AiNew_Build_RoutePart(p, &p->ainew.path_info, DC_EXEC); - if (p->ainew.path_info.position == -2) { + AiNew_Build_RoutePart(p, &_players_ainew[p->index].path_info, DC_EXEC); + if (_players_ainew[p->index].path_info.position == -2) { // This means we are done building! - if (p->ainew.tbt == AI_TRUCK && !_patches.roadveh_queue) { + if (_players_ainew[p->index].tbt == AI_TRUCK && !_patches.roadveh_queue) { // If they not queue, they have to go up and down to try again at a station... // We don't want that, so try building some road left or right of the station DiagDirection dir1, dir2, dir3; @@ -1036,15 +1038,15 @@ static void AiNew_State_BuildPath(Player CommandCost ret; for (int i = 0; i < 2; i++) { if (i == 0) { - tile = p->ainew.from_tile + TileOffsByDiagDir(p->ainew.from_direction); - dir1 = ChangeDiagDir(p->ainew.from_direction, DIAGDIRDIFF_90LEFT); - dir2 = ChangeDiagDir(p->ainew.from_direction, DIAGDIRDIFF_90RIGHT); - dir3 = p->ainew.from_direction; + tile = _players_ainew[p->index].from_tile + TileOffsByDiagDir(_players_ainew[p->index].from_direction); + dir1 = ChangeDiagDir(_players_ainew[p->index].from_direction, DIAGDIRDIFF_90LEFT); + dir2 = ChangeDiagDir(_players_ainew[p->index].from_direction, DIAGDIRDIFF_90RIGHT); + dir3 = _players_ainew[p->index].from_direction; } else { - tile = p->ainew.to_tile + TileOffsByDiagDir(p->ainew.to_direction); - dir1 = ChangeDiagDir(p->ainew.to_direction, DIAGDIRDIFF_90LEFT); - dir2 = ChangeDiagDir(p->ainew.to_direction, DIAGDIRDIFF_90RIGHT); - dir3 = p->ainew.to_direction; + tile = _players_ainew[p->index].to_tile + TileOffsByDiagDir(_players_ainew[p->index].to_direction); + dir1 = ChangeDiagDir(_players_ainew[p->index].to_direction, DIAGDIRDIFF_90LEFT); + dir2 = ChangeDiagDir(_players_ainew[p->index].to_direction, DIAGDIRDIFF_90RIGHT); + dir3 = _players_ainew[p->index].to_direction; } ret = AI_DoCommand(tile, DiagDirToRoadBits(ReverseDiagDir(dir1)), 0, DC_EXEC | DC_NO_WATER, CMD_BUILD_ROAD); @@ -1085,8 +1087,8 @@ static void AiNew_State_BuildPath(Player } } - DEBUG(ai, 1, "Finished building path, cost: %" OTTD_PRINTF64 "d", (int64)p->ainew.new_cost); - p->ainew.state = AI_STATE_BUILD_DEPOT; + DEBUG(ai, 1, "Finished building path, cost: %" OTTD_PRINTF64 "d", (int64)_players_ainew[p->index].new_cost); + _players_ainew[p->index].state = AI_STATE_BUILD_DEPOT; } } @@ -1095,34 +1097,34 @@ static void AiNew_State_BuildPath(Player static void AiNew_State_BuildDepot(Player *p) { CommandCost res; - assert(p->ainew.state == AI_STATE_BUILD_DEPOT); + assert(_players_ainew[p->index].state == AI_STATE_BUILD_DEPOT); - if (IsTileType(p->ainew.depot_tile, MP_ROAD) && GetRoadTileType(p->ainew.depot_tile) == ROAD_TILE_DEPOT) { - if (IsTileOwner(p->ainew.depot_tile, _current_player)) { + if (IsTileType(_players_ainew[p->index].depot_tile, MP_ROAD) && GetRoadTileType(_players_ainew[p->index].depot_tile) == ROAD_TILE_DEPOT) { + if (IsTileOwner(_players_ainew[p->index].depot_tile, _current_player)) { // The depot is already built - p->ainew.state = AI_STATE_BUILD_VEHICLE; + _players_ainew[p->index].state = AI_STATE_BUILD_VEHICLE; return; } else { // There is a depot, but not of our team! :( - p->ainew.state = AI_STATE_NOTHING; + _players_ainew[p->index].state = AI_STATE_NOTHING; return; } } // There is a bus on the tile we want to build road on... idle till he is gone! (BAD PERSON! :p) - if (!EnsureNoVehicleOnGround(p->ainew.depot_tile + TileOffsByDiagDir(p->ainew.depot_direction))) + if (!EnsureNoVehicleOnGround(_players_ainew[p->index].depot_tile + TileOffsByDiagDir(_players_ainew[p->index].depot_direction))) return; - res = AiNew_Build_Depot(p, p->ainew.depot_tile, p->ainew.depot_direction, DC_EXEC); + res = AiNew_Build_Depot(p, _players_ainew[p->index].depot_tile, _players_ainew[p->index].depot_direction, DC_EXEC); if (CmdFailed(res)) { - DEBUG(ai, 0, "[BuildDepot] depot could not be built (0x%X)", p->ainew.depot_tile); - p->ainew.state = AI_STATE_NOTHING; + DEBUG(ai, 0, "[BuildDepot] depot could not be built (0x%X)", _players_ainew[p->index].depot_tile); + _players_ainew[p->index].state = AI_STATE_NOTHING; return; } - p->ainew.state = AI_STATE_BUILD_VEHICLE; - p->ainew.idle = 10; - p->ainew.veh_main_id = INVALID_VEHICLE; + _players_ainew[p->index].state = AI_STATE_BUILD_VEHICLE; + _players_ainew[p->index].idle = 10; + _players_ainew[p->index].veh_main_id = INVALID_VEHICLE; } @@ -1130,34 +1132,34 @@ static void AiNew_State_BuildDepot(Playe static void AiNew_State_BuildVehicle(Player *p) { CommandCost res; - assert(p->ainew.state == AI_STATE_BUILD_VEHICLE); + assert(_players_ainew[p->index].state == AI_STATE_BUILD_VEHICLE); // Check if we need to build a vehicle - if (p->ainew.amount_veh == 0) { + if (_players_ainew[p->index].amount_veh == 0) { // Nope, we are done! // This means: we are all done! The route is open.. go back to NOTHING // He will idle some time and it will all start over again.. :) - p->ainew.state = AI_STATE_ACTION_DONE; + _players_ainew[p->index].state = AI_STATE_ACTION_DONE; return; } - if (--p->ainew.idle != 0) return; + if (--_players_ainew[p->index].idle != 0) return; // It is realistic that the AI can only build 1 vehicle a day.. // This makes sure of that! - p->ainew.idle = AI_BUILD_VEHICLE_TIME_BETWEEN; + _players_ainew[p->index].idle = AI_BUILD_VEHICLE_TIME_BETWEEN; // Build the vehicle - res = AiNew_Build_Vehicle(p, p->ainew.depot_tile, DC_EXEC); + res = AiNew_Build_Vehicle(p, _players_ainew[p->index].depot_tile, DC_EXEC); if (CmdFailed(res)) { // This happens when the AI can't build any more vehicles! - p->ainew.state = AI_STATE_NOTHING; + _players_ainew[p->index].state = AI_STATE_NOTHING; return; } // Increase the current counter - p->ainew.cur_veh++; + _players_ainew[p->index].cur_veh++; // Decrease the total counter - p->ainew.amount_veh--; + _players_ainew[p->index].amount_veh--; // Go give some orders! - p->ainew.state = AI_STATE_WAIT_FOR_BUILD; + _players_ainew[p->index].state = AI_STATE_WAIT_FOR_BUILD; } @@ -1167,15 +1169,15 @@ static void AiNew_State_GiveOrders(Playe int idx; Order order; - assert(p->ainew.state == AI_STATE_GIVE_ORDERS); + assert(_players_ainew[p->index].state == AI_STATE_GIVE_ORDERS); - if (p->ainew.veh_main_id != INVALID_VEHICLE) { - AI_DoCommand(0, p->ainew.veh_id + (p->ainew.veh_main_id << 16), CO_SHARE, DC_EXEC, CMD_CLONE_ORDER); + if (_players_ainew[p->index].veh_main_id != INVALID_VEHICLE) { + AI_DoCommand(0, _players_ainew[p->index].veh_id + (_players_ainew[p->index].veh_main_id << 16), CO_SHARE, DC_EXEC, CMD_CLONE_ORDER); - p->ainew.state = AI_STATE_START_VEHICLE; + _players_ainew[p->index].state = AI_STATE_START_VEHICLE; return; } else { - p->ainew.veh_main_id = p->ainew.veh_id; + _players_ainew[p->index].veh_main_id = _players_ainew[p->index].veh_id; } // Very handy for AI, goto depot.. but yeah, it needs to be activated ;) @@ -1183,46 +1185,46 @@ static void AiNew_State_GiveOrders(Playe idx = 0; order.type = OT_GOTO_DEPOT; order.flags = OF_UNLOAD; - order.dest = GetDepotByTile(p->ainew.depot_tile)->index; - AI_DoCommand(0, p->ainew.veh_id + (idx << 16), PackOrder(&order), DC_EXEC, CMD_INSERT_ORDER); + order.dest = GetDepotByTile(_players_ainew[p->index].depot_tile)->index; + AI_DoCommand(0, _players_ainew[p->index].veh_id + (idx << 16), PackOrder(&order), DC_EXEC, CMD_INSERT_ORDER); } idx = 0; order.type = OT_GOTO_STATION; order.flags = 0; - order.dest = GetStationIndex(p->ainew.to_tile); - if (p->ainew.tbt == AI_TRUCK && p->ainew.to_deliver) + order.dest = GetStationIndex(_players_ainew[p->index].to_tile); + if (_players_ainew[p->index].tbt == AI_TRUCK && _players_ainew[p->index].to_deliver) order.flags |= OF_FULL_LOAD; - AI_DoCommand(0, p->ainew.veh_id + (idx << 16), PackOrder(&order), DC_EXEC, CMD_INSERT_ORDER); + AI_DoCommand(0, _players_ainew[p->index].veh_id + (idx << 16), PackOrder(&order), DC_EXEC, CMD_INSERT_ORDER); idx = 0; order.type = OT_GOTO_STATION; order.flags = 0; - order.dest = GetStationIndex(p->ainew.from_tile); - if (p->ainew.tbt == AI_TRUCK && p->ainew.from_deliver) + order.dest = GetStationIndex(_players_ainew[p->index].from_tile); + if (_players_ainew[p->index].tbt == AI_TRUCK && _players_ainew[p->index].from_deliver) order.flags |= OF_FULL_LOAD; - AI_DoCommand(0, p->ainew.veh_id + (idx << 16), PackOrder(&order), DC_EXEC, CMD_INSERT_ORDER); + AI_DoCommand(0, _players_ainew[p->index].veh_id + (idx << 16), PackOrder(&order), DC_EXEC, CMD_INSERT_ORDER); // Start the engines! - p->ainew.state = AI_STATE_START_VEHICLE; + _players_ainew[p->index].state = AI_STATE_START_VEHICLE; } // Start the vehicle static void AiNew_State_StartVehicle(Player *p) { - assert(p->ainew.state == AI_STATE_START_VEHICLE); + assert(_players_ainew[p->index].state == AI_STATE_START_VEHICLE); // Skip the first order if it is a second vehicle // This to make vehicles go different ways.. - if (p->ainew.cur_veh & 1) - AI_DoCommand(0, p->ainew.veh_id, 1, DC_EXEC, CMD_SKIP_TO_ORDER); + if (_players_ainew[p->index].cur_veh & 1) + AI_DoCommand(0, _players_ainew[p->index].veh_id, 1, DC_EXEC, CMD_SKIP_TO_ORDER); // 3, 2, 1... go! (give START_STOP command ;)) - AI_DoCommand(0, p->ainew.veh_id, 0, DC_EXEC, CMD_START_STOP_ROADVEH); + AI_DoCommand(0, _players_ainew[p->index].veh_id, 0, DC_EXEC, CMD_START_STOP_ROADVEH); // Try to build an other vehicle (that function will stop building when needed) - p->ainew.idle = 10; - p->ainew.state = AI_STATE_BUILD_VEHICLE; + _players_ainew[p->index].idle = 10; + _players_ainew[p->index].state = AI_STATE_BUILD_VEHICLE; } @@ -1234,7 +1236,7 @@ static void AiNew_State_RepayMoney(Playe for (i = 0; i < AI_LOAN_REPAY; i++) { AI_DoCommand(0, 0, 0, DC_EXEC, CMD_DECREASE_LOAN); } - p->ainew.state = AI_STATE_ACTION_DONE; + _players_ainew[p->index].state = AI_STATE_ACTION_DONE; } @@ -1293,7 +1295,7 @@ static void AiNew_State_CheckAllVehicles AiNew_CheckVehicle(p, v); } - p->ainew.state = AI_STATE_ACTION_DONE; + _players_ainew[p->index].state = AI_STATE_ACTION_DONE; } @@ -1325,24 +1327,24 @@ static AiNew_StateFunction* const _ainew static void AiNew_OnTick(Player *p) { - if (_ainew_state[p->ainew.state] != NULL) - _ainew_state[p->ainew.state](p); + if (_ainew_state[_players_ainew[p->index].state] != NULL) + _ainew_state[_players_ainew[p->index].state](p); } void AiNewDoGameLoop(Player *p) { - if (p->ainew.state == AI_STATE_STARTUP) { + if (_players_ainew[p->index].state == AI_STATE_STARTUP) { // The AI just got alive! - p->ainew.state = AI_STATE_FIRST_TIME; - p->ainew.tick = 0; + _players_ainew[p->index].state = AI_STATE_FIRST_TIME; + _players_ainew[p->index].tick = 0; // Only startup the AI return; } // We keep a ticker. We use it for competitor_speed - p->ainew.tick++; + _players_ainew[p->index].tick++; // If we come here, we can do a tick.. do so! AiNew_OnTick(p); diff --git a/src/ai/trolly/trolly.h b/src/ai/trolly/trolly.h --- a/src/ai/trolly/trolly.h +++ b/src/ai/trolly/trolly.h @@ -239,6 +239,22 @@ typedef void AiNew_StateFunction(Player // ai_new.c void AiNewDoGameLoop(Player *p); +struct Ai_PathFinderInfo { + TileIndex start_tile_tl; ///< tl = top-left + TileIndex start_tile_br; ///< br = bottom-right + TileIndex end_tile_tl; ///< tl = top-left + TileIndex end_tile_br; ///< br = bottom-right + DiagDirection start_direction; ///< 0 to 3 or AI_PATHFINDER_NO_DIRECTION + DiagDirection end_direction; ///< 0 to 3 or AI_PATHFINDER_NO_DIRECTION + + TileIndex route[500]; + byte route_extra[500]; ///< Some extra information about the route like bridge/tunnel + int route_length; + int position; ///< Current position in the build-path, needed to build the path + + bool rail_or_road; ///< true = rail, false = road +}; + // ai_pathfinder.c AyStar *new_AyStar_AiPathFinder(int max_tiles_around, Ai_PathFinderInfo *PathFinderInfo); void clean_AyStar_AiPathFinder(AyStar *aystar, Ai_PathFinderInfo *PathFinderInfo); @@ -259,4 +275,64 @@ EngineID AiNew_PickVehicle(Player *p); CommandCost AiNew_Build_Vehicle(Player *p, TileIndex tile, byte flag); CommandCost AiNew_Build_Depot(Player* p, TileIndex tile, DiagDirection direction, byte flag); +/* The amount of memory reserved for the AI-special-vehicles */ +#define AI_MAX_SPECIAL_VEHICLES 100 + +struct Ai_SpecialVehicle { + VehicleID veh_id; + uint32 flag; +}; + +struct PlayerAiNew { + uint8 state; + uint tick; + uint idle; + + int temp; ///< A value used in more than one function, but it just temporary + ///< The use is pretty simple: with this we can 'think' about stuff + ///< in more than one tick, and more than one AI. A static will not + ///< do, because they are not saved. This way, the AI is almost human ;) + int counter; ///< For the same reason as temp, we have counter. It can count how + ///< long we are trying something, and just abort if it takes too long + + /* Pathfinder stuff */ + Ai_PathFinderInfo path_info; + AyStar *pathfinder; + + /* Route stuff */ + + CargoID cargo; + byte tbt; ///< train/bus/truck 0/1/2 AI_TRAIN/AI_BUS/AI_TRUCK + Money new_cost; + + byte action; + + int last_id; ///< here is stored the last id of the searched city/industry + Date last_vehiclecheck_date; // Used in CheckVehicle + Ai_SpecialVehicle special_vehicles[AI_MAX_SPECIAL_VEHICLES]; ///< Some vehicles have some special flags + + TileIndex from_tile; + TileIndex to_tile; + + DiagDirectionByte from_direction; + DiagDirectionByte to_direction; + + bool from_deliver; ///< True if this is the station that GIVES cargo + bool to_deliver; + + TileIndex depot_tile; + DiagDirectionByte depot_direction; + + byte amount_veh; ///< How many vehicles we are going to build in this route + byte cur_veh; ///< How many vehicles did we bought? + VehicleID veh_id; ///< Used when bought a vehicle + VehicleID veh_main_id; ///< The ID of the first vehicle, for shared copy + + int from_ic; ///< ic = industry/city. This is the ID of them + byte from_type; ///< AI_NO_TYPE/AI_CITY/AI_INDUSTRY + int to_ic; + byte to_type; +}; +extern PlayerAiNew _players_ainew[MAX_PLAYERS]; + #endif /* AI_TROLLY_H */ diff --git a/src/oldloader.cpp b/src/oldloader.cpp --- a/src/oldloader.cpp +++ b/src/oldloader.cpp @@ -20,6 +20,7 @@ #include "depot.h" #include "newgrf_config.h" #include "ai/ai.h" +#include "ai/default/default.h" #include "zoom_func.h" #include "functions.h" #include "date_func.h" @@ -811,10 +812,10 @@ static bool OldLoadAIBuildRec(LoadgameSt Player *p = GetPlayer(_current_player_id); switch (num) { - case 0: return LoadChunk(ls, &p->ai.src, player_ai_build_rec_chunk); - case 1: return LoadChunk(ls, &p->ai.dst, player_ai_build_rec_chunk); - case 2: return LoadChunk(ls, &p->ai.mid1, player_ai_build_rec_chunk); - case 3: return LoadChunk(ls, &p->ai.mid2, player_ai_build_rec_chunk); + case 0: return LoadChunk(ls, &_players_ai[p->index].src, player_ai_build_rec_chunk); + case 1: return LoadChunk(ls, &_players_ai[p->index].dst, player_ai_build_rec_chunk); + case 2: return LoadChunk(ls, &_players_ai[p->index].mid1, player_ai_build_rec_chunk); + case 3: return LoadChunk(ls, &_players_ai[p->index].mid2, player_ai_build_rec_chunk); } return false; @@ -924,11 +925,10 @@ static const OldChunks player_ai_chunk[] static bool OldPlayerAI(LoadgameState *ls, int num) { - Player *p = GetPlayer(_current_player_id); - - return LoadChunk(ls, &p->ai, player_ai_chunk); + return LoadChunk(ls, &_players_ai[_current_player_id], player_ai_chunk); } +uint8 ai_tick; static const OldChunks player_chunk[] = { OCL_VAR ( OC_UINT16, 1, &_old_string_id ), OCL_SVAR( OC_UINT32, Player, name_2 ), @@ -958,7 +958,7 @@ static const OldChunks player_chunk[] = OCL_CHUNK( 1, OldPlayerAI ), OCL_SVAR( OC_UINT8, Player, block_preview ), - OCL_SVAR( OC_UINT8, Player, ai.tick ), + OCL_VAR( OC_UINT8, 1, &ai_tick ), OCL_SVAR( OC_UINT8, Player, avail_railtypes ), OCL_SVAR( OC_TILE, Player, location_of_house ), OCL_SVAR( OC_UINT8, Player, share_owners[0] ), @@ -982,6 +982,7 @@ static bool LoadOldPlayer(LoadgameState p->name_1 = RemapOldStringID(_old_string_id); p->president_name_1 = RemapOldStringID(_old_string_id_2); p->player_money = p->player_money; + _players_ai[_current_player_id].tick = ai_tick; if (num == 0) { /* If the first player has no name, make sure we call it UNNAMED */ @@ -1007,10 +1008,10 @@ static bool LoadOldPlayer(LoadgameState p->location_of_house = 0; /* State 20 for AI players is sell vehicle. Since the AI struct is not - * really figured out as of now, p->ai.cur_veh; needed for 'sell vehicle' + * really figured out as of now, _players_ai[p->index].cur_veh; needed for 'sell vehicle' * is NULL and the function will crash. To fix this, just change the state * to some harmless state, like 'loop vehicle'; 1 */ - if (!IsHumanPlayer((PlayerID)num) && p->ai.state == 20) p->ai.state = 1; + if (!IsHumanPlayer((PlayerID)num) && _players_ai[p->index].state == 20) _players_ai[p->index].state = 1; if (p->is_ai && (!_networking || _network_server) && _ai.enabled) AI_StartNewAI(p->index); diff --git a/src/player.h b/src/player.h --- a/src/player.h +++ b/src/player.h @@ -5,12 +5,7 @@ #ifndef PLAYER_H #define PLAYER_H -#include "oldpool.h" -#include "aystar.h" -#include "rail_type.h" #include "road_func.h" -#include "cargo_type.h" -#include "command_type.h" #include "date_type.h" #include "engine.h" #include "livery.h" @@ -25,136 +20,6 @@ struct PlayerEconomyEntry { Money company_value; }; -struct AiBuildRec { - TileIndex spec_tile; - TileIndex use_tile; - byte rand_rng; - byte cur_building_rule; - byte unk6; - byte unk7; - byte buildcmd_a; - byte buildcmd_b; - byte direction; - CargoID cargo; -}; - -struct PlayerAI { - byte state; - byte tick; ///< Used to determine how often to move - uint32 state_counter; ///< Can hold tile index! - uint16 timeout_counter; - - byte state_mode; - byte banned_tile_count; - RailTypeByte railtype_to_use; - - CargoID cargo_type; - byte num_wagons; - byte build_kind; - byte num_build_rec; - byte num_loco_to_build; - byte num_want_fullload; - - byte route_type_mask; - - TileIndex start_tile_a; - TileIndex cur_tile_a; - DiagDirectionByte cur_dir_a; - DiagDirectionByte start_dir_a; - - TileIndex start_tile_b; - TileIndex cur_tile_b; - DiagDirectionByte cur_dir_b; - DiagDirectionByte start_dir_b; - - Vehicle *cur_veh; ///< only used by some states - - AiBuildRec src, dst, mid1, mid2; - - VehicleID wagon_list[9]; - byte order_list_blocks[20]; - - TileIndex banned_tiles[16]; - byte banned_val[16]; -}; - -struct Ai_PathFinderInfo { - TileIndex start_tile_tl; ///< tl = top-left - TileIndex start_tile_br; ///< br = bottom-right - TileIndex end_tile_tl; ///< tl = top-left - TileIndex end_tile_br; ///< br = bottom-right - DiagDirection start_direction; ///< 0 to 3 or AI_PATHFINDER_NO_DIRECTION - DiagDirection end_direction; ///< 0 to 3 or AI_PATHFINDER_NO_DIRECTION - - TileIndex route[500]; - byte route_extra[500]; ///< Some extra information about the route like bridge/tunnel - int route_length; - int position; ///< Current position in the build-path, needed to build the path - - bool rail_or_road; ///< true = rail, false = road -}; - -/* The amount of memory reserved for the AI-special-vehicles */ -#define AI_MAX_SPECIAL_VEHICLES 100 - -struct Ai_SpecialVehicle { - VehicleID veh_id; - uint32 flag; -}; - -struct PlayerAiNew { - uint8 state; - uint tick; - uint idle; - - int temp; ///< A value used in more than one function, but it just temporary - ///< The use is pretty simple: with this we can 'think' about stuff - ///< in more than one tick, and more than one AI. A static will not - ///< do, because they are not saved. This way, the AI is almost human ;) - int counter; ///< For the same reason as temp, we have counter. It can count how - ///< long we are trying something, and just abort if it takes too long - - /* Pathfinder stuff */ - Ai_PathFinderInfo path_info; - AyStar *pathfinder; - - /* Route stuff */ - - CargoID cargo; - byte tbt; ///< train/bus/truck 0/1/2 AI_TRAIN/AI_BUS/AI_TRUCK - Money new_cost; - - byte action; - - int last_id; ///< here is stored the last id of the searched city/industry - Date last_vehiclecheck_date; // Used in CheckVehicle - Ai_SpecialVehicle special_vehicles[AI_MAX_SPECIAL_VEHICLES]; ///< Some vehicles have some special flags - - TileIndex from_tile; - TileIndex to_tile; - - DiagDirectionByte from_direction; - DiagDirectionByte to_direction; - - bool from_deliver; ///< True if this is the station that GIVES cargo - bool to_deliver; - - TileIndex depot_tile; - DiagDirectionByte depot_direction; - - byte amount_veh; ///< How many vehicles we are going to build in this route - byte cur_veh; ///< How many vehicles did we bought? - VehicleID veh_id; ///< Used when bought a vehicle - VehicleID veh_main_id; ///< The ID of the first vehicle, for shared copy - - int from_ic; ///< ic = industry/city. This is the ID of them - byte from_type; ///< AI_NO_TYPE/AI_CITY/AI_INDUSTRY - int to_ic; - byte to_type; - -}; - - /* The "steps" in loan size, in British Pounds! */ enum { LOAN_INTERVAL = 10000, @@ -198,8 +63,6 @@ struct Player { bool is_active; bool is_ai; - PlayerAI ai; - PlayerAiNew ainew; Money yearly_expenses[3][13]; PlayerEconomyEntry cur_economy; diff --git a/src/players.cpp b/src/players.cpp --- a/src/players.cpp +++ b/src/players.cpp @@ -30,6 +30,8 @@ #include "autoreplace_func.h" #include "autoreplace_gui.h" #include "string_func.h" +#include "ai/default/default.h" +#include "ai/trolly/trolly.h" /** * Sets the local player and updates the patch settings that are set on a @@ -441,6 +443,8 @@ static Player *AllocatePlayer() if (!p->is_active) { PlayerID i = p->index; memset(p, 0, sizeof(Player)); + memset(&_players_ai[i], 0, sizeof(PlayerAI)); + memset(&_players_ainew[i], 0, sizeof(PlayerAiNew)); p->index = i; return p; } @@ -480,7 +484,7 @@ Player *DoStartupNewPlayer(bool is_ai) p->player_money = p->current_loan = 100000; p->is_ai = is_ai; - p->ai.state = 5; // AIS_WANT_NEW_ROUTE + _players_ai[p->index].state = 5; // AIS_WANT_NEW_ROUTE p->share_owners[0] = p->share_owners[1] = p->share_owners[2] = p->share_owners[3] = PLAYER_SPECTATOR; p->avail_railtypes = GetPlayerRailtypes(p->index); @@ -1193,66 +1197,6 @@ static const SaveLoad _player_economy_de SLE_END() }; -static const SaveLoad _player_ai_desc[] = { - SLE_VAR(PlayerAI, state, SLE_UINT8), - SLE_VAR(PlayerAI, tick, SLE_UINT8), - SLE_CONDVAR(PlayerAI, state_counter, SLE_FILE_U16 | SLE_VAR_U32, 0, 12), - SLE_CONDVAR(PlayerAI, state_counter, SLE_UINT32, 13, SL_MAX_VERSION), - SLE_VAR(PlayerAI, timeout_counter, SLE_UINT16), - - SLE_VAR(PlayerAI, state_mode, SLE_UINT8), - SLE_VAR(PlayerAI, banned_tile_count, SLE_UINT8), - SLE_VAR(PlayerAI, railtype_to_use, SLE_UINT8), - - SLE_VAR(PlayerAI, cargo_type, SLE_UINT8), - SLE_VAR(PlayerAI, num_wagons, SLE_UINT8), - SLE_VAR(PlayerAI, build_kind, SLE_UINT8), - SLE_VAR(PlayerAI, num_build_rec, SLE_UINT8), - SLE_VAR(PlayerAI, num_loco_to_build, SLE_UINT8), - SLE_VAR(PlayerAI, num_want_fullload, SLE_UINT8), - - SLE_VAR(PlayerAI, route_type_mask, SLE_UINT8), - - SLE_CONDVAR(PlayerAI, start_tile_a, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), - SLE_CONDVAR(PlayerAI, start_tile_a, SLE_UINT32, 6, SL_MAX_VERSION), - SLE_CONDVAR(PlayerAI, cur_tile_a, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), - SLE_CONDVAR(PlayerAI, cur_tile_a, SLE_UINT32, 6, SL_MAX_VERSION), - SLE_VAR(PlayerAI, start_dir_a, SLE_UINT8), - SLE_VAR(PlayerAI, cur_dir_a, SLE_UINT8), - - SLE_CONDVAR(PlayerAI, start_tile_b, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), - SLE_CONDVAR(PlayerAI, start_tile_b, SLE_UINT32, 6, SL_MAX_VERSION), - SLE_CONDVAR(PlayerAI, cur_tile_b, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), - SLE_CONDVAR(PlayerAI, cur_tile_b, SLE_UINT32, 6, SL_MAX_VERSION), - SLE_VAR(PlayerAI, start_dir_b, SLE_UINT8), - SLE_VAR(PlayerAI, cur_dir_b, SLE_UINT8), - - SLE_REF(PlayerAI, cur_veh, REF_VEHICLE), - - SLE_ARR(PlayerAI, wagon_list, SLE_UINT16, 9), - SLE_ARR(PlayerAI, order_list_blocks, SLE_UINT8, 20), - SLE_ARR(PlayerAI, banned_tiles, SLE_UINT16, 16), - - SLE_CONDNULL(64, 2, SL_MAX_VERSION), - SLE_END() -}; - -static const SaveLoad _player_ai_build_rec_desc[] = { - SLE_CONDVAR(AiBuildRec, spec_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), - SLE_CONDVAR(AiBuildRec, spec_tile, SLE_UINT32, 6, SL_MAX_VERSION), - SLE_CONDVAR(AiBuildRec, use_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), - SLE_CONDVAR(AiBuildRec, use_tile, SLE_UINT32, 6, SL_MAX_VERSION), - SLE_VAR(AiBuildRec, rand_rng, SLE_UINT8), - SLE_VAR(AiBuildRec, cur_building_rule, SLE_UINT8), - SLE_VAR(AiBuildRec, unk6, SLE_UINT8), - SLE_VAR(AiBuildRec, unk7, SLE_UINT8), - SLE_VAR(AiBuildRec, buildcmd_a, SLE_UINT8), - SLE_VAR(AiBuildRec, buildcmd_b, SLE_UINT8), - SLE_VAR(AiBuildRec, direction, SLE_UINT8), - SLE_VAR(AiBuildRec, cargo, SLE_UINT8), - SLE_END() -}; - static const SaveLoad _player_livery_desc[] = { SLE_CONDVAR(Livery, in_use, SLE_BOOL, 34, SL_MAX_VERSION), SLE_CONDVAR(Livery, colour1, SLE_UINT8, 34, SL_MAX_VERSION), @@ -1268,10 +1212,7 @@ static void SaveLoad_PLYR(Player* p) /* Write AI? */ if (!IsHumanPlayer(p->index)) { - SlObject(&p->ai, _player_ai_desc); - for (i = 0; i != p->ai.num_build_rec; i++) { - SlObject(&p->ai.src + i, _player_ai_build_rec_desc); - } + SaveLoad_AI(p->index); } /* Write economy */