/** need to be called to load aircraft from old version */ void UpdateOldAircraft() { /* set airport_flags to 0 for all airports just to be sure */ Station *st; FOR_ALL_STATIONS(st) { st->airport.flags = 0; // reset airport } Aircraft *a; FOR_ALL_AIRCRAFT(a) { /* airplane has another vehicle with subtype 4 (shadow), helicopter also has 3 (rotor) * skip those */ if (a->IsNormalAircraft()) { /* airplane in terminal stopped doesn't hurt anyone, so goto next */ if ((a->vehstatus & VS_STOPPED) && a->state == 0) { a->state = HANGAR; continue; } AircraftLeaveHangar(a, a->direction); // make airplane visible if it was in a depot for example a->vehstatus &= ~VS_STOPPED; // make airplane moving UpdateAircraftCache(a); a->cur_speed = a->vcache.cached_max_speed; // so aircraft don't have zero speed while in air if (!a->current_order.IsType(OT_GOTO_STATION) && !a->current_order.IsType(OT_GOTO_DEPOT)) { /* reset current order so aircraft doesn't have invalid "station-only" order */ a->current_order.MakeDummy(); } a->state = FLYING; AircraftNextAirportPos_and_Order(a); // move it to the entry point of the airport GetNewVehiclePosResult gp = GetNewVehiclePos(a); a->tile = 0; // aircraft in air is tile=0 /* correct speed of helicopter-rotors */ if (a->subtype == AIR_HELICOPTER) a->Next()->Next()->cur_speed = 32; /* set new position x,y,z */ SetAircraftPosition(a, gp.x, gp.y, GetAircraftFlyingAltitude(a)); } } }
/** * Check the validity of some of the caches. * Especially in the sense of desyncs between * the cached value and what the value would * be when calculated from the 'base' data. */ static void CheckCaches() { /* Return here so it is easy to add checks that are run * always to aid testing of caches. */ if (_debug_desync_level <= 1) return; /* Check the town caches. */ SmallVector<TownCache, 4> old_town_caches; Town *t; FOR_ALL_TOWNS(t) { MemCpyT(old_town_caches.Append(), &t->cache); } extern void RebuildTownCaches(); RebuildTownCaches(); RebuildSubsidisedSourceAndDestinationCache(); uint i = 0; FOR_ALL_TOWNS(t) { if (MemCmpT(old_town_caches.Get(i), &t->cache) != 0) { DEBUG(desync, 2, "town cache mismatch: town %i", (int)t->index); } i++; } /* Check company infrastructure cache. */ SmallVector<CompanyInfrastructure, 4> old_infrastructure; Company *c; FOR_ALL_COMPANIES(c) MemCpyT(old_infrastructure.Append(), &c->infrastructure); extern void AfterLoadCompanyStats(); AfterLoadCompanyStats(); i = 0; FOR_ALL_COMPANIES(c) { if (MemCmpT(old_infrastructure.Get(i), &c->infrastructure) != 0) { DEBUG(desync, 2, "infrastructure cache mismatch: company %i", (int)c->index); } i++; } /* Strict checking of the road stop cache entries */ const RoadStop *rs; FOR_ALL_ROADSTOPS(rs) { if (IsStandardRoadStopTile(rs->xy)) continue; assert(rs->GetEntry(DIAGDIR_NE) != rs->GetEntry(DIAGDIR_NW)); rs->GetEntry(DIAGDIR_NE)->CheckIntegrity(rs); rs->GetEntry(DIAGDIR_NW)->CheckIntegrity(rs); } Vehicle *v; FOR_ALL_VEHICLES(v) { extern void FillNewGRFVehicleCache(const Vehicle *v); if (v != v->First() || v->vehstatus & VS_CRASHED || !v->IsPrimaryVehicle()) continue; uint length = 0; for (const Vehicle *u = v; u != NULL; u = u->Next()) length++; NewGRFCache *grf_cache = CallocT<NewGRFCache>(length); VehicleCache *veh_cache = CallocT<VehicleCache>(length); GroundVehicleCache *gro_cache = CallocT<GroundVehicleCache>(length); TrainCache *tra_cache = CallocT<TrainCache>(length); length = 0; for (const Vehicle *u = v; u != NULL; u = u->Next()) { FillNewGRFVehicleCache(u); grf_cache[length] = u->grf_cache; veh_cache[length] = u->vcache; switch (u->type) { case VEH_TRAIN: gro_cache[length] = Train::From(u)->gcache; tra_cache[length] = Train::From(u)->tcache; break; case VEH_ROAD: gro_cache[length] = RoadVehicle::From(u)->gcache; break; default: break; } length++; } switch (v->type) { case VEH_TRAIN: Train::From(v)->ConsistChanged(CCF_TRACK); break; case VEH_ROAD: RoadVehUpdateCache(RoadVehicle::From(v)); break; case VEH_AIRCRAFT: UpdateAircraftCache(Aircraft::From(v)); break; case VEH_SHIP: Ship::From(v)->UpdateCache(); break; default: break; } length = 0; for (const Vehicle *u = v; u != NULL; u = u->Next()) { FillNewGRFVehicleCache(u); if (memcmp(&grf_cache[length], &u->grf_cache, sizeof(NewGRFCache)) != 0) { DEBUG(desync, 2, "newgrf cache mismatch: type %i, vehicle %i, company %i, unit number %i, wagon %i", (int)v->type, v->index, (int)v->owner, v->unitnumber, length); } if (memcmp(&veh_cache[length], &u->vcache, sizeof(VehicleCache)) != 0) { DEBUG(desync, 2, "vehicle cache mismatch: type %i, vehicle %i, company %i, unit number %i, wagon %i", (int)v->type, v->index, (int)v->owner, v->unitnumber, length); } switch (u->type) { case VEH_TRAIN: if (memcmp(&gro_cache[length], &Train::From(u)->gcache, sizeof(GroundVehicleCache)) != 0) { DEBUG(desync, 2, "train ground vehicle cache mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); } if (memcmp(&tra_cache[length], &Train::From(u)->tcache, sizeof(TrainCache)) != 0) { DEBUG(desync, 2, "train cache mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); } break; case VEH_ROAD: if (memcmp(&gro_cache[length], &RoadVehicle::From(u)->gcache, sizeof(GroundVehicleCache)) != 0) { DEBUG(desync, 2, "road vehicle ground vehicle cache mismatch: vehicle %i, company %i, unit number %i, wagon %i", v->index, (int)v->owner, v->unitnumber, length); } break; default: break; } length++; } free(grf_cache); free(veh_cache); free(gro_cache); free(tra_cache); } /* Check whether the caches are still valid */ FOR_ALL_VEHICLES(v) { byte buff[sizeof(VehicleCargoList)]; memcpy(buff, &v->cargo, sizeof(VehicleCargoList)); v->cargo.InvalidateCache(); assert(memcmp(&v->cargo, buff, sizeof(VehicleCargoList)) == 0); } Station *st; FOR_ALL_STATIONS(st) { for (CargoID c = 0; c < NUM_CARGO; c++) { byte buff[sizeof(StationCargoList)]; memcpy(buff, &st->goods[c].cargo, sizeof(StationCargoList)); st->goods[c].cargo.InvalidateCache(); assert(memcmp(&st->goods[c].cargo, buff, sizeof(StationCargoList)) == 0); } } }
/** * Refits a vehicle to the specified cargo type. * @param tile unused * @param flags type of operation * @param p1 vehicle ID to refit * @param p2 various bitstuffed elements * - p2 = (bit 0-4) - New cargo type to refit to. * - p2 = (bit 6) - Automatic refitting. * - p2 = (bit 7) - Refit only this vehicle. Used only for cloning vehicles. * - p2 = (bit 8-15) - New cargo subtype to refit to. 0xFF means to try keeping the same subtype according to GetBestFittingSubType(). * - p2 = (bit 16-23) - Number of vehicles to refit (not counting articulated parts). Zero means all vehicles. * Only used if "refit only this vehicle" is false. * @param text unused * @return the cost of this operation or an error */ CommandCost CmdRefitVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { Vehicle *v = Vehicle::GetIfValid(p1); if (v == NULL) return CMD_ERROR; /* Don't allow disasters and sparks and such to be refitted. * We cannot check for IsPrimaryVehicle as autoreplace also refits in free wagon chains. */ if (!IsCompanyBuildableVehicleType(v->type)) return CMD_ERROR; Vehicle *front = v->First(); CommandCost ret = CheckOwnership(front->owner); if (ret.Failed()) return ret; bool auto_refit = HasBit(p2, 6); /* Don't allow shadows and such to be refitted. */ if (v != front && (v->type == VEH_SHIP || v->type == VEH_AIRCRAFT)) return CMD_ERROR; /* Allow auto-refitting only during loading and normal refitting only in a depot. */ if ((!auto_refit || !front->current_order.IsType(OT_LOADING)) && !front->IsStoppedInDepot()) return_cmd_error(STR_ERROR_TRAIN_MUST_BE_STOPPED_INSIDE_DEPOT + front->type); if (front->vehstatus & VS_CRASHED) return_cmd_error(STR_ERROR_VEHICLE_IS_DESTROYED); /* Check cargo */ CargoID new_cid = GB(p2, 0, 5); byte new_subtype = GB(p2, 8, 8); if (new_cid >= NUM_CARGO) return CMD_ERROR; /* For ships and aircrafts there is always only one. */ bool only_this = HasBit(p2, 7) || front->type == VEH_SHIP || front->type == VEH_AIRCRAFT; uint8 num_vehicles = GB(p2, 16, 8); CommandCost cost = RefitVehicle(v, only_this, num_vehicles, new_cid, new_subtype, flags, auto_refit); if (flags & DC_EXEC) { /* Update the cached variables */ switch (v->type) { case VEH_TRAIN: Train::From(front)->ConsistChanged(auto_refit); break; case VEH_ROAD: RoadVehUpdateCache(RoadVehicle::From(front), auto_refit); if (_settings_game.vehicle.roadveh_acceleration_model != AM_ORIGINAL) RoadVehicle::From(front)->CargoChanged(); break; case VEH_SHIP: v->InvalidateNewGRFCacheOfChain(); v->colourmap = PAL_NONE; // invalidate vehicle colour map Ship::From(v)->UpdateCache(); break; case VEH_AIRCRAFT: v->InvalidateNewGRFCacheOfChain(); v->colourmap = PAL_NONE; // invalidate vehicle colour map UpdateAircraftCache(Aircraft::From(v), true); break; default: NOT_REACHED(); } InvalidateWindowData(WC_VEHICLE_DETAILS, front->index); SetWindowDirty(WC_VEHICLE_DEPOT, front->tile); InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0); } else { /* Always invalidate the cache; querycost might have filled it. */ v->InvalidateNewGRFCacheOfChain(); } return cost; }