/** Cargo filter functions */ static bool CDECL CargoFilter(const EngineID *eid, const CargoID cid) { if (cid == CF_ANY) return true; uint32 refit_mask = GetUnionOfArticulatedRefitMasks(*eid, true); return (cid == CF_NONE ? refit_mask == 0 : HasBit(refit_mask, cid)); }
/** * Check blitter needed by NewGRF config and switch if needed. * @return False when nothing changed, true otherwise. */ static bool SwitchNewGRFBlitter() { /* Never switch if the blitter was specified by the user. */ if (!_blitter_autodetected) return false; /* Null driver => dedicated server => do nothing. */ if (BlitterFactory::GetCurrentBlitter()->GetScreenDepth() == 0) return false; /* Get preferred depth. * - depth_wanted_by_base: Depth required by the baseset, i.e. the majority of the sprites. * - depth_wanted_by_grf: Depth required by some NewGRF. * Both can force using a 32bpp blitter. depth_wanted_by_base is used to select * between multiple 32bpp blitters, which perform differently with 8bpp sprites. */ uint depth_wanted_by_base = BaseGraphics::GetUsedSet()->blitter == BLT_32BPP ? 32 : 8; uint depth_wanted_by_grf = _support8bpp == S8BPP_NONE ? 32 : 8; for (GRFConfig *c = _grfconfig; c != NULL; c = c->next) { if (c->status == GCS_DISABLED || c->status == GCS_NOT_FOUND || HasBit(c->flags, GCF_INIT_ONLY)) continue; if (c->palette & GRFP_BLT_32BPP) depth_wanted_by_grf = 32; } /* Search the best blitter. */ static const struct { const char *name; uint animation; ///< 0: no support, 1: do support, 2: both uint min_base_depth, max_base_depth, min_grf_depth, max_grf_depth; } replacement_blitters[] = { #ifdef WITH_SSE { "32bpp-sse4", 0, 32, 32, 8, 32 }, { "32bpp-ssse3", 0, 32, 32, 8, 32 }, { "32bpp-sse2", 0, 32, 32, 8, 32 }, { "32bpp-sse4-anim", 1, 32, 32, 8, 32 }, #endif { "8bpp-optimized", 2, 8, 8, 8, 8 }, { "32bpp-optimized", 0, 8, 32, 8, 32 }, { "32bpp-anim", 1, 8, 32, 8, 32 }, }; const bool animation_wanted = HasBit(_display_opt, DO_FULL_ANIMATION); const char *cur_blitter = BlitterFactory::GetCurrentBlitter()->GetName(); for (uint i = 0; i < lengthof(replacement_blitters); i++) { if (animation_wanted && (replacement_blitters[i].animation == 0)) continue; if (!animation_wanted && (replacement_blitters[i].animation == 1)) continue; if (!IsInsideMM(depth_wanted_by_base, replacement_blitters[i].min_base_depth, replacement_blitters[i].max_base_depth + 1)) continue; if (!IsInsideMM(depth_wanted_by_grf, replacement_blitters[i].min_grf_depth, replacement_blitters[i].max_grf_depth + 1)) continue; const char *repl_blitter = replacement_blitters[i].name; if (strcmp(repl_blitter, cur_blitter) == 0) return false; if (BlitterFactory::GetBlitterFactory(repl_blitter) == NULL) continue; DEBUG(misc, 1, "Switching blitter from '%s' to '%s'... ", cur_blitter, repl_blitter); Blitter *new_blitter = BlitterFactory::SelectBlitter(repl_blitter); if (new_blitter == NULL) NOT_REACHED(); DEBUG(misc, 1, "Successfully switched to %s.", repl_blitter); break; } if (!VideoDriver::GetInstance()->AfterBlitterChange()) { /* Failed to switch blitter, let's hope we can return to the old one. */ if (BlitterFactory::SelectBlitter(cur_blitter) == NULL || !VideoDriver::GetInstance()->AfterBlitterChange()) usererror("Failed to reinitialize video driver. Specify a fixed blitter in the config"); } return true; }
void GameLoop() { if (_game_mode == GM_BOOTSTRAP) { #ifdef ENABLE_NETWORK /* Check for UDP stuff */ if (_network_available) NetworkBackgroundLoop(); #endif InputLoop(); return; } ProcessAsyncSaveFinish(); /* autosave game? */ if (_do_autosave) { _do_autosave = false; DoAutosave(); SetWindowDirty(WC_STATUS_BAR, 0); } /* switch game mode? */ if (_switch_mode != SM_NONE && !HasModalProgress()) { SwitchToMode(_switch_mode); _switch_mode = SM_NONE; } IncreaseSpriteLRU(); InteractiveRandom(); extern int _caret_timer; _caret_timer += 3; CursorTick(); #ifdef ENABLE_NETWORK /* Check for UDP stuff */ if (_network_available) NetworkBackgroundLoop(); if (_networking && !HasModalProgress()) { /* Multiplayer */ NetworkGameLoop(); } else { if (_network_reconnect > 0 && --_network_reconnect == 0) { /* This means that we want to reconnect to the last host * We do this here, because it means that the network is really closed */ NetworkClientConnectGame(NetworkAddress(_settings_client.network.last_host, _settings_client.network.last_port), COMPANY_SPECTATOR); } /* Singleplayer */ StateGameLoop(); } /* Check chat messages roughly once a second. */ static uint check_message = 0; if (++check_message > 1000 / MILLISECONDS_PER_TICK) { check_message = 0; NetworkChatMessageLoop(); } #else StateGameLoop(); #endif /* ENABLE_NETWORK */ if (!_pause_mode && HasBit(_display_opt, DO_FULL_ANIMATION)) DoPaletteAnimations(); if (!_pause_mode || _game_mode == GM_EDITOR || _settings_game.construction.command_pause_level > CMDPL_NO_CONSTRUCTION) MoveAllTextEffects(); InputLoop(); _sound_driver->MainLoop(); MusicLoop(); }
static void HeightMapCurves(uint level) { height_t ht[lengthof(_curve_maps)]; MemSetT(ht, 0, lengthof(ht)); /* Set up a grid to choose curve maps based on location */ uint sx = Clamp(1 << level, 2, 32); uint sy = Clamp(1 << level, 2, 32); byte *c = AllocaM(byte, sx * sy); for (uint i = 0; i < sx * sy; i++) { c[i] = Random() % lengthof(_curve_maps); } /* Apply curves */ for (uint x = 0; x < _height_map.size_x; x++) { /* Get our X grid positions and bi-linear ratio */ float fx = (float)(sx * x) / _height_map.size_x + 0.5f; uint x1 = (uint)fx; uint x2 = x1; float xr = 2.0f * (fx - x1) - 1.0f; xr = sin(xr * M_PI_2); xr = sin(xr * M_PI_2); xr = 0.5f * (xr + 1.0f); float xri = 1.0f - xr; if (x1 > 0) { x1--; if (x2 >= sx) x2--; } for (uint y = 0; y < _height_map.size_y; y++) { /* Get our Y grid position and bi-linear ratio */ float fy = (float)(sy * y) / _height_map.size_y + 0.5f; uint y1 = (uint)fy; uint y2 = y1; float yr = 2.0f * (fy - y1) - 1.0f; yr = sin(yr * M_PI_2); yr = sin(yr * M_PI_2); yr = 0.5f * (yr + 1.0f); float yri = 1.0f - yr; if (y1 > 0) { y1--; if (y2 >= sy) y2--; } uint corner_a = c[x1 + sx * y1]; uint corner_b = c[x1 + sx * y2]; uint corner_c = c[x2 + sx * y1]; uint corner_d = c[x2 + sx * y2]; /* Bitmask of which curve maps are chosen, so that we do not bother * calculating a curve which won't be used. */ uint corner_bits = 0; corner_bits |= 1 << corner_a; corner_bits |= 1 << corner_b; corner_bits |= 1 << corner_c; corner_bits |= 1 << corner_d; height_t *h = &_height_map.height(x, y); /* Apply all curve maps that are used on this tile. */ for (uint t = 0; t < lengthof(_curve_maps); t++) { if (!HasBit(corner_bits, t)) continue; const control_point_t *cm = _curve_maps[t].list; for (uint i = 0; i < _curve_maps[t].length - 1; i++) { const control_point_t &p1 = cm[i]; const control_point_t &p2 = cm[i + 1]; if (*h >= p1.x && *h < p2.x) { ht[t] = p1.y + (*h - p1.x) * (p2.y - p1.y) / (p2.x - p1.x); break; } } } /* Apply interpolation of curve map results. */ *h = (height_t)((ht[corner_a] * yri + ht[corner_b] * yr) * xri + (ht[corner_c] * yri + ht[corner_d] * yr) * xr); } } }
/** * Determines capacity of a given vehicle from scratch. * For aircraft the main capacity is determined. Mail might be present as well. * @param v Vehicle of interest; NULL in purchase list * @param mail_capacity returns secondary cargo (mail) capacity of aircraft * @return Capacity */ uint Engine::DetermineCapacity(const Vehicle *v, uint16 *mail_capacity) const { assert(v == NULL || this->index == v->engine_type); if (mail_capacity != NULL) *mail_capacity = 0; if (!this->CanCarryCargo()) return 0; bool new_multipliers = HasBit(this->info.misc_flags, EF_NO_DEFAULT_CARGO_MULTIPLIER); CargoID default_cargo = this->GetDefaultCargoType(); CargoID cargo_type = (v != NULL) ? v->cargo_type : default_cargo; if (mail_capacity != NULL && this->type == VEH_AIRCRAFT && IsCargoInClass(cargo_type, CC_PASSENGERS)) { *mail_capacity = GetEngineProperty(this->index, PROP_AIRCRAFT_MAIL_CAPACITY, this->u.air.mail_capacity, v); } /* Check the refit capacity callback if we are not in the default configuration, or if we are using the new multiplier algorithm. */ if (HasBit(this->info.callback_mask, CBM_VEHICLE_REFIT_CAPACITY) && (new_multipliers || default_cargo != cargo_type || (v != NULL && v->cargo_subtype != 0))) { uint16 callback = GetVehicleCallback(CBID_VEHICLE_REFIT_CAPACITY, 0, 0, this->index, v); if (callback != CALLBACK_FAILED) return callback; } /* Get capacity according to property resp. CB */ uint capacity; uint extra_mail_cap = 0; switch (this->type) { case VEH_TRAIN: capacity = GetEngineProperty(this->index, PROP_TRAIN_CARGO_CAPACITY, this->u.rail.capacity, v); /* In purchase list add the capacity of the second head. Always use the plain property for this. */ if (v == NULL && this->u.rail.railveh_type == RAILVEH_MULTIHEAD) capacity += this->u.rail.capacity; break; case VEH_ROAD: capacity = GetEngineProperty(this->index, PROP_ROADVEH_CARGO_CAPACITY, this->u.road.capacity, v); break; case VEH_SHIP: capacity = GetEngineProperty(this->index, PROP_SHIP_CARGO_CAPACITY, this->u.ship.capacity, v); break; case VEH_AIRCRAFT: capacity = GetEngineProperty(this->index, PROP_AIRCRAFT_PASSENGER_CAPACITY, this->u.air.passenger_capacity, v); if (!IsCargoInClass(cargo_type, CC_PASSENGERS)) { extra_mail_cap = GetEngineProperty(this->index, PROP_AIRCRAFT_MAIL_CAPACITY, this->u.air.mail_capacity, v); } if (!new_multipliers && cargo_type == CT_MAIL) return capacity + extra_mail_cap; default_cargo = CT_PASSENGERS; // Always use 'passengers' wrt. cargo multipliers break; default: NOT_REACHED(); } if (!new_multipliers) { /* Use the passenger multiplier for mail as well */ capacity += extra_mail_cap; extra_mail_cap = 0; } /* Apply multipliers depending on cargo- and vehicletype. */ if (new_multipliers || (this->type != VEH_SHIP && default_cargo != cargo_type)) { uint16 default_multiplier = new_multipliers ? 0x100 : CargoSpec::Get(default_cargo)->multiplier; uint16 cargo_multiplier = CargoSpec::Get(cargo_type)->multiplier; capacity *= cargo_multiplier; if (extra_mail_cap > 0) { uint mail_multiplier = CargoSpec::Get(CT_MAIL)->multiplier; capacity += (default_multiplier * extra_mail_cap * cargo_multiplier + mail_multiplier / 2) / mail_multiplier; } capacity = (capacity + default_multiplier / 2) / default_multiplier; } return capacity; }
/** * Add the remaining articulated parts to the given vehicle. * @param first The head of the articulated bit. */ void AddArticulatedParts(Vehicle *first) { VehicleType type = first->type; if (!HasBit(EngInfo(first->engine_type)->callback_mask, CBM_VEHICLE_ARTIC_ENGINE)) return; Vehicle *v = first; for (uint i = 1; i < MAX_ARTICULATED_PARTS; i++) { bool flip_image; EngineID engine_type = GetNextArticulatedPart(i, first->engine_type, first, &flip_image); if (engine_type == INVALID_ENGINE) return; /* In the (very rare) case the GRF reported wrong number of articulated parts * and we run out of available vehicles, bail out. */ if (!Vehicle::CanAllocateItem()) return; GroundVehicleCache *gcache = v->GetGroundVehicleCache(); gcache->first_engine = v->engine_type; // Needs to be set before first callback const Engine *e_artic = Engine::Get(engine_type); switch (type) { default: NOT_REACHED(); case VEH_TRAIN: { Train *front = Train::From(first); Train *t = new Train(); v->SetNext(t); v = t; t->subtype = 0; t->track = front->track; t->railtype = front->railtype; t->spritenum = e_artic->u.rail.image_index; if (e_artic->CanCarryCargo()) { t->cargo_type = e_artic->GetDefaultCargoType(); t->cargo_cap = e_artic->u.rail.capacity; // Callback 36 is called when the consist is finished } else { t->cargo_type = front->cargo_type; // Needed for livery selection t->cargo_cap = 0; } t->SetArticulatedPart(); break; } case VEH_ROAD: { RoadVehicle *front = RoadVehicle::From(first); RoadVehicle *rv = new RoadVehicle(); v->SetNext(rv); v = rv; rv->subtype = 0; gcache->cached_veh_length = VEHICLE_LENGTH; // Callback is called when the consist is finished rv->state = RVSB_IN_DEPOT; rv->roadtype = front->roadtype; rv->compatible_roadtypes = front->compatible_roadtypes; rv->spritenum = e_artic->u.road.image_index; if (e_artic->CanCarryCargo()) { rv->cargo_type = e_artic->GetDefaultCargoType(); rv->cargo_cap = e_artic->u.road.capacity; // Callback 36 is called when the consist is finished } else { rv->cargo_type = front->cargo_type; // Needed for livery selection rv->cargo_cap = 0; } rv->SetArticulatedPart(); break; } } /* get common values from first engine */ v->direction = first->direction; v->owner = first->owner; v->tile = first->tile; v->x_pos = first->x_pos; v->y_pos = first->y_pos; v->z_pos = first->z_pos; v->build_year = first->build_year; v->vehstatus = first->vehstatus & ~VS_STOPPED; v->cargo_subtype = 0; v->max_age = 0; v->engine_type = engine_type; v->value = 0; v->cur_image = SPR_IMG_QUERY; v->random_bits = VehicleRandomBits(); if (flip_image) v->spritenum++; VehicleUpdatePosition(v); } }
static uint32 StationGetVariable(const ResolverObject *object, byte variable, byte parameter, bool *available) { const BaseStation *st = object->u.station.st; TileIndex tile = object->u.station.tile; if (object->scope == VSG_SCOPE_PARENT) { /* Pass the request on to the town of the station */ const Town *t; if (st != NULL) { t = st->town; } else if (tile != INVALID_TILE) { t = ClosestTownFromTile(tile, UINT_MAX); } else { *available = false; return UINT_MAX; } return TownGetVariable(variable, parameter, available, t); } if (st == NULL) { /* Station does not exist, so we're in a purchase list */ switch (variable) { case 0x40: case 0x41: case 0x46: case 0x47: case 0x49: return 0x2110000; // Platforms, tracks & position case 0x42: return 0; // Rail type (XXX Get current type from GUI?) case 0x43: return _current_company; // Station owner case 0x44: return 2; // PBS status case 0xFA: return Clamp(_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0, 65535); // Build date, clamped to a 16 bit value } *available = false; return UINT_MAX; } switch (variable) { /* Calculated station variables */ case 0x40: if (!HasBit(_svc.valid, 0)) { _svc.v40 = GetPlatformInfoHelper(tile, false, false, false); SetBit(_svc.valid, 0); } return _svc.v40; case 0x41: if (!HasBit(_svc.valid, 1)) { _svc.v41 = GetPlatformInfoHelper(tile, true, false, false); SetBit(_svc.valid, 1); } return _svc.v41; case 0x42: return GetTerrainType(tile) | (GetReverseRailTypeTranslation(GetRailType(tile), object->u.station.statspec->grf_prop.grffile) << 8); case 0x43: return st->owner; // Station owner case 0x44: return HasStationReservation(tile) ? 7 : 4; // PBS status case 0x45: if (!HasBit(_svc.valid, 2)) { _svc.v45 = GetRailContinuationInfo(tile); SetBit(_svc.valid, 2); } return _svc.v45; case 0x46: if (!HasBit(_svc.valid, 3)) { _svc.v46 = GetPlatformInfoHelper(tile, false, false, true); SetBit(_svc.valid, 3); } return _svc.v46; case 0x47: if (!HasBit(_svc.valid, 4)) { _svc.v47 = GetPlatformInfoHelper(tile, true, false, true); SetBit(_svc.valid, 4); } return _svc.v47; case 0x49: if (!HasBit(_svc.valid, 5)) { _svc.v49 = GetPlatformInfoHelper(tile, false, true, false); SetBit(_svc.valid, 5); } return _svc.v49; case 0x4A: // Animation frame of tile return GetAnimationFrame(tile); /* Variables which use the parameter */ /* Variables 0x60 to 0x65 are handled separately below */ case 0x66: // Animation frame of nearby tile if (parameter != 0) tile = GetNearbyTile(parameter, tile); return st->TileBelongsToRailStation(tile) ? GetAnimationFrame(tile) : UINT_MAX; case 0x67: { // Land info of nearby tile Axis axis = GetRailStationAxis(tile); if (parameter != 0) tile = GetNearbyTile(parameter, tile); // only perform if it is required Slope tileh = GetTileSlope(tile, NULL); bool swap = (axis == AXIS_Y && HasBit(tileh, CORNER_W) != HasBit(tileh, CORNER_E)); return GetNearbyTileInformation(tile) ^ (swap ? SLOPE_EW : 0); } case 0x68: { // Station info of nearby tiles TileIndex nearby_tile = GetNearbyTile(parameter, tile); if (!HasStationTileRail(nearby_tile)) return 0xFFFFFFFF; uint32 grfid = st->speclist[GetCustomStationSpecIndex(tile)].grfid; bool perpendicular = GetRailStationAxis(tile) != GetRailStationAxis(nearby_tile); bool same_station = st->TileBelongsToRailStation(nearby_tile); uint32 res = GB(GetStationGfx(nearby_tile), 1, 2) << 12 | !!perpendicular << 11 | !!same_station << 10; if (IsCustomStationSpecIndex(nearby_tile)) { const StationSpecList ssl = BaseStation::GetByTile(nearby_tile)->speclist[GetCustomStationSpecIndex(nearby_tile)]; res |= 1 << (ssl.grfid != grfid ? 9 : 8) | ssl.localidx; } return res; } /* General station variables */ case 0x82: return 50; case 0x84: return st->string_id; case 0x86: return 0; case 0xF0: return st->facilities; case 0xFA: return Clamp(st->build_date - DAYS_TILL_ORIGINAL_BASE_YEAR, 0, 65535); } return st->GetNewGRFVariable(object, variable, parameter, available); }
/** * Check if all GRFs in the GRF config from a savegame can be loaded. * @param grfconfig GrfConfig to check * @return will return any of the following 3 values:<br> * <ul> * <li> GLC_ALL_GOOD: No problems occurred, all GRF files were found and loaded * <li> GLC_COMPATIBLE: For one or more GRF's no exact match was found, but a * compatible GRF with the same grfid was found and used instead * <li> GLC_NOT_FOUND: For one or more GRF's no match was found at all * </ul> */ GRFListCompatibility IsGoodGRFConfigList(GRFConfig *grfconfig) { GRFListCompatibility res = GLC_ALL_GOOD; for (GRFConfig *c = grfconfig; c != NULL; c = c->next) { const GRFConfig *f = FindGRFConfig(c->ident.grfid, FGCM_EXACT, c->ident.md5sum); if (f == NULL || HasBit(f->flags, GCF_INVALID)) { char buf[256]; /* If we have not found the exactly matching GRF try to find one with the * same grfid, as it most likely is compatible */ f = FindGRFConfig(c->ident.grfid, FGCM_COMPATIBLE, NULL, c->version); if (f != NULL) { md5sumToString(buf, lastof(buf), c->ident.md5sum); DEBUG(grf, 1, "NewGRF %08X (%s) not found; checksum %s. Compatibility mode on", BSWAP32(c->ident.grfid), c->filename, buf); if (!HasBit(c->flags, GCF_COMPATIBLE)) { /* Preserve original_md5sum after it has been assigned */ SetBit(c->flags, GCF_COMPATIBLE); memcpy(c->original_md5sum, c->ident.md5sum, sizeof(c->original_md5sum)); } /* Non-found has precedence over compatibility load */ if (res != GLC_NOT_FOUND) res = GLC_COMPATIBLE; goto compatible_grf; } /* No compatible grf was found, mark it as disabled */ md5sumToString(buf, lastof(buf), c->ident.md5sum); DEBUG(grf, 0, "NewGRF %08X (%s) not found; checksum %s", BSWAP32(c->ident.grfid), c->filename, buf); c->status = GCS_NOT_FOUND; res = GLC_NOT_FOUND; } else { compatible_grf: DEBUG(grf, 1, "Loading GRF %08X from %s", BSWAP32(f->ident.grfid), f->filename); /* The filename could be the filename as in the savegame. As we need * to load the GRF here, we need the correct filename, so overwrite that * in any case and set the name and info when it is not set already. * When the GCF_COPY flag is set, it is certain that the filename is * already a local one, so there is no need to replace it. */ if (!HasBit(c->flags, GCF_COPY)) { free(c->filename); c->filename = strdup(f->filename); memcpy(c->ident.md5sum, f->ident.md5sum, sizeof(c->ident.md5sum)); c->name->Release(); c->name = f->name; c->name->AddRef(); c->info->Release(); c->info = f->name; c->info->AddRef(); c->error = NULL; c->version = f->version; c->min_loadable_version = f->min_loadable_version; c->num_valid_params = f->num_valid_params; c->has_param_defaults = f->has_param_defaults; for (uint i = 0; i < f->param_info.Length(); i++) { if (f->param_info[i] == NULL) { *c->param_info.Append() = NULL; } else { *c->param_info.Append() = new GRFParameterInfo(*f->param_info[i]); } } } } } return res; }
/** * @note Used by the resolver to get values for feature 07 deterministic spritegroups. */ /* virtual */ uint32 HouseScopeResolver::GetVariable(byte variable, uint32 parameter, bool *available) const { switch (variable) { /* Construction stage. */ case 0x40: return (IsTileType(this->tile, MP_HOUSE) ? GetHouseBuildingStage(this->tile) : 0) | TileHash2Bit(TileX(this->tile), TileY(this->tile)) << 2; /* Building age. */ case 0x41: return IsTileType(this->tile, MP_HOUSE) ? GetHouseAge(this->tile) : 0; /* Town zone */ case 0x42: return GetTownRadiusGroup(this->town, this->tile); /* Terrain type */ case 0x43: return GetTerrainType(this->tile); /* Number of this type of building on the map. */ case 0x44: return GetNumHouses(this->house_id, this->town); /* Whether the town is being created or just expanded. */ case 0x45: return _generating_world ? 1 : 0; /* Current animation frame. */ case 0x46: return IsTileType(this->tile, MP_HOUSE) ? GetAnimationFrame(this->tile) : 0; /* Position of the house */ case 0x47: return TileY(this->tile) << 16 | TileX(this->tile); /* Building counts for old houses with id = parameter. */ case 0x60: return parameter < NEW_HOUSE_OFFSET ? GetNumHouses(parameter, this->town) : 0; /* Building counts for new houses with id = parameter. */ case 0x61: { const HouseSpec *hs = HouseSpec::Get(this->house_id); if (hs->grf_prop.grffile == NULL) return 0; HouseID new_house = _house_mngr.GetID(parameter, hs->grf_prop.grffile->grfid); return new_house == INVALID_HOUSE_ID ? 0 : GetNumHouses(new_house, this->town); } /* Land info for nearby tiles. */ case 0x62: return GetNearbyTileInformation(parameter, this->tile, this->ro.grffile->grf_version >= 8); /* Current animation frame of nearby house tiles */ case 0x63: { TileIndex testtile = GetNearbyTile(parameter, this->tile); return IsTileType(testtile, MP_HOUSE) ? GetAnimationFrame(testtile) : 0; } /* Cargo acceptance history of nearby stations */ case 0x64: { CargoID cid = GetCargoTranslation(parameter, this->ro.grffile); if (cid == CT_INVALID) return 0; /* Extract tile offset. */ int8 x_offs = GB(GetRegister(0x100), 0, 8); int8 y_offs = GB(GetRegister(0x100), 8, 8); TileIndex testtile = TILE_MASK(this->tile + TileDiffXY(x_offs, y_offs)); StationFinder stations(TileArea(testtile, 1, 1)); const StationList *sl = stations.GetStations(); /* Collect acceptance stats. */ uint32 res = 0; for (Station * const * st_iter = sl->Begin(); st_iter != sl->End(); st_iter++) { const Station *st = *st_iter; if (HasBit(st->goods[cid].acceptance_pickup, GoodsEntry::GES_EVER_ACCEPTED)) SetBit(res, 0); if (HasBit(st->goods[cid].acceptance_pickup, GoodsEntry::GES_LAST_MONTH)) SetBit(res, 1); if (HasBit(st->goods[cid].acceptance_pickup, GoodsEntry::GES_CURRENT_MONTH)) SetBit(res, 2); if (HasBit(st->goods[cid].acceptance_pickup, GoodsEntry::GES_ACCEPTED_BIGTICK)) SetBit(res, 3); } /* Cargo triggered CB 148? */ if (HasBit(this->watched_cargo_triggers, cid)) SetBit(res, 4); return res; } /* Distance test for some house types */ case 0x65: return GetDistanceFromNearbyHouse(parameter, this->tile, this->house_id); /* Class and ID of nearby house tile */ case 0x66: { TileIndex testtile = GetNearbyTile(parameter, this->tile); if (!IsTileType(testtile, MP_HOUSE)) return 0xFFFFFFFF; HouseSpec *hs = HouseSpec::Get(GetHouseType(testtile)); /* Information about the grf local classid if the house has a class */ uint houseclass = 0; if (hs->class_id != HOUSE_NO_CLASS) { houseclass = (hs->grf_prop.grffile == this->ro.grffile ? 1 : 2) << 8; houseclass |= _class_mapping[hs->class_id].class_id; } /* old house type or grf-local houseid */ uint local_houseid = 0; if (this->house_id < NEW_HOUSE_OFFSET) { local_houseid = this->house_id; } else { local_houseid = (hs->grf_prop.grffile == this->ro.grffile ? 1 : 2) << 8; local_houseid |= hs->grf_prop.local_id; } return houseclass << 16 | local_houseid; } /* GRFID of nearby house tile */ case 0x67: { TileIndex testtile = GetNearbyTile(parameter, this->tile); if (!IsTileType(testtile, MP_HOUSE)) return 0xFFFFFFFF; HouseID house_id = GetHouseType(testtile); if (house_id < NEW_HOUSE_OFFSET) return 0; /* Checking the grffile information via HouseSpec doesn't work * in case the newgrf was removed. */ return _house_mngr.GetGRFID(house_id); } } DEBUG(grf, 1, "Unhandled house variable 0x%X", variable); *available = false; return UINT_MAX; }
static void OpenBankFile(const char *filename) { memset(_original_sounds, 0, sizeof(_original_sounds)); FioOpenFile(SOUND_SLOT, filename); size_t pos = FioGetPos(); uint count = FioReadDword(); /* The new format has the highest bit always set */ bool new_format = HasBit(count, 31); ClrBit(count, 31); count /= 8; /* Simple check for the correct number of original sounds. */ if (count != ORIGINAL_SAMPLE_COUNT) { /* Corrupt sample data? Just leave the allocated memory as those tell * there is no sound to play (size = 0 due to calloc). Not allocating * the memory disables valid NewGRFs that replace sounds. */ DEBUG(misc, 6, "Incorrect number of sounds in '%s', ignoring.", filename); return; } FioSeekTo(pos, SEEK_SET); for (uint i = 0; i != ORIGINAL_SAMPLE_COUNT; i++) { _original_sounds[i].file_slot = SOUND_SLOT; _original_sounds[i].file_offset = GB(FioReadDword(), 0, 31) + pos; _original_sounds[i].file_size = FioReadDword(); } for (uint i = 0; i != ORIGINAL_SAMPLE_COUNT; i++) { SoundEntry *sound = &_original_sounds[i]; char name[255]; FioSeekTo(sound->file_offset, SEEK_SET); /* Check for special case, see else case */ FioReadBlock(name, FioReadByte()); // Read the name of the sound if (new_format || strcmp(name, "Corrupt sound") != 0) { FioSeekTo(12, SEEK_CUR); // Skip past RIFF header /* Read riff tags */ for (;;) { uint32 tag = FioReadDword(); uint32 size = FioReadDword(); if (tag == ' tmf') { FioReadWord(); // wFormatTag sound->channels = FioReadWord(); // wChannels sound->rate = FioReadDword(); // samples per second if (!new_format) sound->rate = 11025; // seems like all old samples should be played at this rate. FioReadDword(); // avg bytes per second FioReadWord(); // alignment sound->bits_per_sample = FioReadByte(); // bits per sample FioSeekTo(size - (2 + 2 + 4 + 4 + 2 + 1), SEEK_CUR); } else if (tag == 'atad') { sound->file_size = size; sound->file_slot = SOUND_SLOT; sound->file_offset = FioGetPos(); break; } else { sound->file_size = 0; break; } } } else { /* * Special case for the jackhammer sound * (name in sample.cat is "Corrupt sound") * It's no RIFF file, but raw PCM data */ sound->channels = 1; sound->rate = 11025; sound->bits_per_sample = 8; sound->file_slot = SOUND_SLOT; sound->file_offset = FioGetPos(); } } }
void UpdateVehicleTimetable(Vehicle *v, bool travelling) { uint timetabled = travelling ? v->current_order.travel_time : v->current_order.wait_time; uint time_taken = v->current_order_time; v->current_order_time = 0; if (v->current_order.IsType(OT_AUTOMATIC)) return; // no timetabling of auto orders VehicleOrderID first_manual_order = 0; for (Order *o = v->GetFirstOrder(); o != NULL && o->IsType(OT_AUTOMATIC); o = o->next) { ++first_manual_order; } bool just_started = false; /* This vehicle is arriving at the first destination in the timetable. */ if (v->cur_real_order_index == first_manual_order && travelling) { /* If the start date hasn't been set, or it was set automatically when * the vehicle last arrived at the first destination, update it to the * current time. Otherwise set the late counter appropriately to when * the vehicle should have arrived. */ just_started = !HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED); if (v->timetable_start != 0) { v->lateness_counter = (_date - v->timetable_start) * DAY_TICKS + _date_fract; v->timetable_start = 0; } SetBit(v->vehicle_flags, VF_TIMETABLE_STARTED); SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index); } if (!HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED)) return; if (HasBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE)) { if (travelling && !HasBit(v->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME)) { /* Need to clear that now as otherwise we are not able to reduce the wait time */ v->current_order.wait_time = 0; } if (just_started) return; /* Modify station waiting time only if our new value is larger (this is * always the case when we cleared the timetable). */ if (!v->current_order.IsType(OT_CONDITIONAL) && (travelling || time_taken > v->current_order.wait_time)) { /* Round the time taken up to the nearest day, as this will avoid * confusion for people who are timetabling in days, and can be * adjusted later by people who aren't. * For trains/aircraft multiple movement cycles are done in one * tick. This makes it possible to leave the station and process * e.g. a depot order in the same tick, causing it to not fill * the timetable entry like is done for road vehicles/ships. * Thus always make sure at least one tick is used between the * processing of different orders when filling the timetable. */ time_taken = CeilDiv(max(time_taken, 1U), DAY_TICKS) * DAY_TICKS; ChangeTimetable(v, v->cur_real_order_index, time_taken, travelling); } if (v->cur_real_order_index == first_manual_order && travelling) { /* If we just started we would have returned earlier and have not reached * this code. So obviously, we have completed our round: So turn autofill * off again. */ ClrBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE); ClrBit(v->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME); } return; } if (just_started) return; /* Vehicles will wait at stations if they arrive early even if they are not * timetabled to wait there, so make sure the lateness counter is updated * when this happens. */ if (timetabled == 0 && (travelling || v->lateness_counter >= 0)) return; v->lateness_counter -= (timetabled - time_taken); /* When we are more late than this timetabled bit takes we (somewhat expensively) * check how many ticks the (fully filled) timetable has. If a timetable cycle is * shorter than the amount of ticks we are late we reduce the lateness by the * length of a full cycle till lateness is less than the length of a timetable * cycle. When the timetable isn't fully filled the cycle will be INVALID_TICKS. */ if (v->lateness_counter > (int)timetabled) { Ticks cycle = v->orders.list->GetTimetableTotalDuration(); if (cycle != INVALID_TICKS && v->lateness_counter > cycle) { v->lateness_counter %= cycle; } } for (v = v->FirstShared(); v != NULL; v = v->NextShared()) { SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index); } }
virtual void OnClick(Point pt, int widget, int click_count) { /* clicked a letter */ if (widget >= WID_OSK_LETTERS) { WChar c = _keyboard[this->shift][widget - WID_OSK_LETTERS]; if (!IsValidChar(c, this->qs->text.afilter)) return; if (this->qs->text.InsertChar(c)) this->OnEditboxChanged(WID_OSK_TEXT); if (HasBit(_keystate, KEYS_SHIFT)) { ToggleBit(_keystate, KEYS_SHIFT); this->UpdateOskState(); this->SetDirty(); } return; } switch (widget) { case WID_OSK_BACKSPACE: if (this->qs->text.DeleteChar(WKC_BACKSPACE)) this->OnEditboxChanged(WID_OSK_TEXT); break; case WID_OSK_SPECIAL: /* * Anything device specific can go here. * The button itself is hidden by default, and when you need it you * can not hide it in the create event. */ break; case WID_OSK_CAPS: ToggleBit(_keystate, KEYS_CAPS); this->UpdateOskState(); this->SetDirty(); break; case WID_OSK_SHIFT: ToggleBit(_keystate, KEYS_SHIFT); this->UpdateOskState(); this->SetDirty(); break; case WID_OSK_SPACE: if (this->qs->text.InsertChar(' ')) this->OnEditboxChanged(WID_OSK_TEXT); break; case WID_OSK_LEFT: if (this->qs->text.MovePos(WKC_LEFT)) this->InvalidateData(); break; case WID_OSK_RIGHT: if (this->qs->text.MovePos(WKC_RIGHT)) this->InvalidateData(); break; case WID_OSK_OK: if (this->qs->orig == NULL || strcmp(this->qs->text.buf, this->qs->orig) != 0) { /* pass information by simulating a button press on parent window */ if (this->qs->ok_button >= 0) { this->parent->OnClick(pt, this->qs->ok_button, 1); /* Window gets deleted when the parent window removes itself. */ return; } } delete this; break; case WID_OSK_CANCEL: if (this->qs->cancel_button >= 0) { // pass a cancel event to the parent window this->parent->OnClick(pt, this->qs->cancel_button, 1); /* Window gets deleted when the parent window removes itself. */ return; } else { // or reset to original string qs->text.Assign(this->orig_str_buf); qs->text.MovePos(WKC_END); this->OnEditboxChanged(WID_OSK_TEXT); delete this; } break; } }
/** * Returns the current value of the given flag on the given AyStarNode. */ static inline bool NPFGetFlag(const AyStarNode *node, NPFNodeFlag flag) { return HasBit(node->user_data[NPF_NODE_FLAGS], flag); }
/* Will just follow the results of GetTileTrackStatus concerning where we can * go and where not. Uses AyStar.user_data[NPF_TYPE] as the transport type and * an argument to GetTileTrackStatus. Will skip tunnels, meaning that the * entry and exit are neighbours. Will fill * AyStarNode.user_data[NPF_TRACKDIR_CHOICE] with an appropriate value, and * copy AyStarNode.user_data[NPF_NODE_FLAGS] from the parent */ static void NPFFollowTrack(AyStar *aystar, OpenListNode *current) { /* We leave src_tile on track src_trackdir in direction src_exitdir */ Trackdir src_trackdir = current->path.node.direction; TileIndex src_tile = current->path.node.tile; DiagDirection src_exitdir = TrackdirToExitdir(src_trackdir); /* Is src_tile valid, and can be used? * When choosing track on a junction src_tile is the tile neighboured to the junction wrt. exitdir. * But we must not check the validity of this move, as src_tile is totally unrelated to the move, if a roadvehicle reversed on a junction. */ bool ignore_src_tile = (current->path.parent == NULL && NPFGetFlag(¤t->path.node, NPF_FLAG_IGNORE_START_TILE)); /* Information about the vehicle: TransportType (road/rail/water) and SubType (compatible rail/road types) */ TransportType type = (TransportType)aystar->user_data[NPF_TYPE]; uint subtype = aystar->user_data[NPF_SUB_TYPE]; /* Initialize to 0, so we can jump out (return) somewhere an have no neighbours */ aystar->num_neighbours = 0; DEBUG(npf, 4, "Expanding: (%d, %d, %d) [%d]", TileX(src_tile), TileY(src_tile), src_trackdir, src_tile); /* We want to determine the tile we arrive, and which choices we have there */ TileIndex dst_tile; TrackdirBits trackdirbits; /* Find dest tile */ if (ignore_src_tile) { /* Do not perform any checks that involve src_tile */ dst_tile = src_tile + TileOffsByDiagDir(src_exitdir); trackdirbits = GetDriveableTrackdirBits(dst_tile, src_trackdir, type, subtype); } else if (IsTileType(src_tile, MP_TUNNELBRIDGE) && GetTunnelBridgeDirection(src_tile) == src_exitdir) { /* We drive through the wormhole and arrive on the other side */ dst_tile = GetOtherTunnelBridgeEnd(src_tile); trackdirbits = TrackdirToTrackdirBits(src_trackdir); } else if (ForceReverse(src_tile, src_exitdir, type, subtype)) { /* We can only reverse on this tile */ dst_tile = src_tile; src_trackdir = ReverseTrackdir(src_trackdir); trackdirbits = TrackdirToTrackdirBits(src_trackdir); } else { /* We leave src_tile in src_exitdir and reach dst_tile */ dst_tile = AddTileIndexDiffCWrap(src_tile, TileIndexDiffCByDiagDir(src_exitdir)); if (dst_tile != INVALID_TILE && !CanEnterTile(dst_tile, src_exitdir, type, subtype, (RailTypes)aystar->user_data[NPF_RAILTYPES], (Owner)aystar->user_data[NPF_OWNER])) dst_tile = INVALID_TILE; if (dst_tile == INVALID_TILE) { /* We cannot enter the next tile. Road vehicles can reverse, others reach dead end */ if (type != TRANSPORT_ROAD || HasBit(subtype, ROADTYPE_TRAM)) return; dst_tile = src_tile; src_trackdir = ReverseTrackdir(src_trackdir); } trackdirbits = GetDriveableTrackdirBits(dst_tile, src_trackdir, type, subtype); if (trackdirbits == 0) { /* We cannot enter the next tile. Road vehicles can reverse, others reach dead end */ if (type != TRANSPORT_ROAD || HasBit(subtype, ROADTYPE_TRAM)) return; dst_tile = src_tile; src_trackdir = ReverseTrackdir(src_trackdir); trackdirbits = GetDriveableTrackdirBits(dst_tile, src_trackdir, type, subtype); } } if (NPFGetFlag(¤t->path.node, NPF_FLAG_IGNORE_RESERVED)) { /* Mask out any reserved tracks. */ TrackBits reserved = GetReservedTrackbits(dst_tile); trackdirbits &= ~TrackBitsToTrackdirBits(reserved); uint bits = TrackdirBitsToTrackBits(trackdirbits); int i; FOR_EACH_SET_BIT(i, bits) { if (TracksOverlap(reserved | TrackToTrackBits((Track)i))) trackdirbits &= ~TrackToTrackdirBits((Track)i); } }
static void PollEvent() { poll_mouse(); bool mouse_action = false; /* Mouse buttons */ static int prev_button_state; if (prev_button_state != mouse_b) { uint diff = prev_button_state ^ mouse_b; while (diff != 0) { uint button = FindFirstBit(diff); ClrBit(diff, button); if (HasBit(mouse_b, button)) { /* Pressed mouse button */ if (_rightclick_emulate && (key_shifts & KB_CTRL_FLAG)) { button = RIGHT_BUTTON; ClrBit(diff, RIGHT_BUTTON); } switch (button) { case LEFT_BUTTON: _left_button_down = true; break; case RIGHT_BUTTON: _right_button_down = true; _right_button_clicked = true; break; default: /* ignore rest */ break; } } else { /* Released mouse button */ if (_rightclick_emulate) { _right_button_down = false; _left_button_down = false; _left_button_clicked = false; } else if (button == LEFT_BUTTON) { _left_button_down = false; _left_button_clicked = false; } else if (button == RIGHT_BUTTON) { _right_button_down = false; } } } prev_button_state = mouse_b; mouse_action = true; } /* Mouse movement */ if (_cursor.UpdateCursorPosition(mouse_x, mouse_y, false)) { position_mouse(_cursor.pos.x, _cursor.pos.y); } if (_cursor.delta.x != 0 || _cursor.delta.y) mouse_action = true; static int prev_mouse_z = 0; if (prev_mouse_z != mouse_z) { _cursor.wheel = (prev_mouse_z - mouse_z) < 0 ? -1 : 1; prev_mouse_z = mouse_z; mouse_action = true; } if (mouse_action) HandleMouseEvents(); poll_keyboard(); if ((key_shifts & KB_ALT_FLAG) && (key[KEY_ENTER] || key[KEY_F])) { ToggleFullScreen(!_fullscreen); } else if (keypressed()) { WChar character; uint keycode = ConvertAllegroKeyIntoMy(&character); HandleKeypress(keycode, character); } }
void AnimateNewHouseTile(TileIndex tile) { const HouseSpec *hs = HouseSpec::Get(GetHouseType(tile)); byte animation_speed = hs->animation_speed; bool frame_set_by_callback = false; if (HasBit(hs->callback_mask, CBM_HOUSE_ANIMATION_SPEED)) { uint16 callback_res = GetHouseCallback(CBID_HOUSE_ANIMATION_SPEED, 0, 0, GetHouseType(tile), Town::GetByTile(tile), tile); if (callback_res != CALLBACK_FAILED) animation_speed = Clamp(callback_res & 0xFF, 2, 16); } /* An animation speed of 2 means the animation frame changes 4 ticks, and * increasing this value by one doubles the wait. 2 is the minimum value * allowed for animation_speed, which corresponds to 120ms, and 16 is the * maximum, corresponding to around 33 minutes. */ if (_tick_counter % (1 << animation_speed) != 0) return; byte frame = GetHouseAnimationFrame(tile); byte num_frames = GB(hs->animation_frames, 0, 7); if (HasBit(hs->callback_mask, CBM_HOUSE_ANIMATION_NEXT_FRAME)) { uint32 param = (hs->extra_flags & CALLBACK_1A_RANDOM_BITS) ? Random() : 0; uint16 callback_res = GetHouseCallback(CBID_HOUSE_ANIMATION_NEXT_FRAME, param, 0, GetHouseType(tile), Town::GetByTile(tile), tile); if (callback_res != CALLBACK_FAILED) { frame_set_by_callback = true; switch (callback_res & 0xFF) { case 0xFF: DeleteAnimatedTile(tile); break; case 0xFE: /* Carry on as normal. */ frame_set_by_callback = false; break; default: frame = callback_res & 0xFF; break; } /* If the lower 7 bits of the upper byte of the callback * result are not empty, it is a sound effect. */ if (GB(callback_res, 8, 7) != 0) PlayTileSound(hs->grffile, GB(callback_res, 8, 7), tile); } } if (!frame_set_by_callback) { if (frame < num_frames) { frame++; } else if (frame == num_frames && HasBit(hs->animation_frames, 7)) { /* This animation loops, so start again from the beginning */ frame = 0; } else { /* This animation doesn't loop, so stay here */ DeleteAnimatedTile(tile); } } SetHouseAnimationFrame(tile, frame); MarkTileDirtyByTile(tile); }
bool GameObject::IsEnabled() { return HasBit( m_systemFlags, GO_SYSTEMFLAG_ENABLED ); }
/** * Get the tile location group of a tile. * @param t The tile to get the tile location group of. * @return The tile location group. */ static inline TLG GetTLG(TileIndex t) { return (TLG)((HasBit(TileX(t), 0) << 1) + HasBit(TileY(t), 0)); }
/** * Does a NewGRF report that this should be an articulated vehicle? * @param engine_type The engine to check. * @return True iff the articulated engine callback flag is set. */ bool IsArticulatedEngine(EngineID engine_type) { return HasBit(EngInfo(engine_type)->callback_mask, CBM_VEHICLE_ARTIC_ENGINE); }
FORCEINLINE bool IsTram() {return IsRoadTT() && HasBit(RoadVehicle::From(m_veh)->compatible_roadtypes, ROADTYPE_TRAM);}
/** * Check whether a rail station tile is NOT traversable. * @param tile %Tile to test. * @return Station tile is blocked. * @note This could be cached (during build) in the map array to save on all the dereferencing. */ bool IsStationTileBlocked(TileIndex tile) { const StationSpec *statspec = GetStationSpec(tile); return statspec != NULL && HasBit(statspec->blocked, GetStationGfx(tile)); }
/** * Tries to find a suitable destination for the given source and cargo. * @param cid Subsidized cargo. * @param src_type Type of \a src. * @param src Index of source. * @return True iff the subsidy was created. */ bool FindSubsidyCargoDestination(CargoID cid, SourceType src_type, SourceID src) { /* Choose a random destination. Only consider towns if they can accept the cargo. */ SourceType dst_type = (HasBit(_town_cargoes_accepted, cid) && Chance16(1, 2)) ? ST_TOWN : ST_INDUSTRY; CargoSourceSink *src_sink = (src_type == ST_TOWN) ? (CargoSourceSink *) Town::Get(src) : (CargoSourceSink *) Industry::Get(src); SourceID dst; switch (dst_type) { case ST_TOWN: { /* Select a random town. */ const Town *dst_town = NULL; if (CargoHasDestinations(cid)) { /* Try to get a town from the demand destinations. */ CargoLink *link = src_sink->GetRandomLink(cid, false); if (link == src_sink->cargo_links[cid].End()) return NULL; if (link->dest != NULL && link->dest->GetType() != dst_type) return NULL; dst_town = static_cast<const Town *>(link->dest); } if (dst_town == NULL) dst_town = Town::GetRandom(); /* Check if the town can accept this cargo. */ if (!HasBit(dst_town->cargo_accepted_total, cid)) return false; dst = dst_town->index; break; } case ST_INDUSTRY: { /* Select a random industry. */ const Industry *dst_ind = Industry::GetRandom(); if (CargoHasDestinations(cid)) { /* Try to get a town from the demand destinations. */ CargoLink *link = src_sink->GetRandomLink(cid, false); if (link == src_sink->cargo_links[cid].End()) return NULL; if (link->dest != NULL && link->dest->GetType() != dst_type) return NULL; dst_ind = static_cast<const Industry *>(link->dest); } if (dst_ind == NULL) dst_ind = Industry::GetRandom(); dst = dst_ind->index; /* The industry must accept the cargo */ if (dst_ind == NULL || (src_type == dst_type && src == dst) || (cid != dst_ind->accepts_cargo[0] && cid != dst_ind->accepts_cargo[1] && cid != dst_ind->accepts_cargo[2])) { return false; } break; } default: NOT_REACHED(); } /* Check that the source and the destination are not the same. */ if (src_type == dst_type && src == dst) return false; /* Check distance between source and destination. */ if (!CheckSubsidyDistance(src_type, src, dst_type, dst)) return false; /* Avoid duplicate subsidies. */ if (CheckSubsidyDuplicate(cid, src_type, src, dst_type, dst)) return false; CreateSubsidy(cid, src_type, src, dst_type, dst); return true; }
/** * Checks whether the engine is a valid (non-articulated part of an) engine. * @return true if enabled */ bool Engine::IsEnabled() const { return this->info.string_id != STR_NEWGRF_INVALID_ENGINE && HasBit(this->info.climates, _settings_game.game_creation.landscape); }
/** * Perform all steps to upgrade from the old waypoints to the new version * that uses station. This includes some old saveload mechanics. */ void MoveWaypointsToBaseStations() { /* In version 17, ground type is moved from m2 to m4 for depots and * waypoints to make way for storing the index in m2. The custom graphics * id which was stored in m4 is now saved as a grf/id reference in the * waypoint struct. */ if (IsSavegameVersionBefore(17)) { for (OldWaypoint *wp = _old_waypoints.Begin(); wp != _old_waypoints.End(); wp++) { if (wp->delete_ctr != 0) continue; // The waypoint was deleted /* Waypoint indices were not added to the map prior to this. */ _m[wp->xy].m2 = (StationID)wp->index; if (HasBit(_m[wp->xy].m3, 4)) { wp->spec = StationClass::Get(STAT_CLASS_WAYP, _m[wp->xy].m4 + 1); } } } else { /* As of version 17, we recalculate the custom graphic ID of waypoints * from the GRF ID / station index. */ for (OldWaypoint *wp = _old_waypoints.Begin(); wp != _old_waypoints.End(); wp++) { for (uint i = 0; i < StationClass::GetCount(STAT_CLASS_WAYP); i++) { const StationSpec *statspec = StationClass::Get(STAT_CLASS_WAYP, i); if (statspec != NULL && statspec->grf_prop.grffile->grfid == wp->grfid && statspec->grf_prop.local_id == wp->localidx) { wp->spec = statspec; break; } } } } if (!Waypoint::CanAllocateItem(_old_waypoints.Length())) SlError(STR_ERROR_TOO_MANY_STATIONS_LOADING); /* All saveload conversions have been done. Create the new waypoints! */ for (OldWaypoint *wp = _old_waypoints.Begin(); wp != _old_waypoints.End(); wp++) { Waypoint *new_wp = new Waypoint(wp->xy); new_wp->town = wp->town; new_wp->town_cn = wp->town_cn; new_wp->name = wp->name; new_wp->delete_ctr = 0; // Just reset delete counter for once. new_wp->build_date = wp->build_date; new_wp->owner = wp->owner; new_wp->string_id = STR_SV_STNAME_WAYPOINT; TileIndex t = wp->xy; if (IsTileType(t, MP_RAILWAY) && GetRailTileType(t) == 2 /* RAIL_TILE_WAYPOINT */ && _m[t].m2 == wp->index) { /* The tile might've been reserved! */ bool reserved = !IsSavegameVersionBefore(100) && HasBit(_m[t].m5, 4); /* The tile really has our waypoint, so reassign the map array */ MakeRailWaypoint(t, GetTileOwner(t), new_wp->index, (Axis)GB(_m[t].m5, 0, 1), 0, GetRailType(t)); new_wp->facilities |= FACIL_TRAIN; new_wp->owner = GetTileOwner(t); SetRailStationReservation(t, reserved); if (wp->spec != NULL) { SetCustomStationSpecIndex(t, AllocateSpecToStation(wp->spec, new_wp, true)); } new_wp->rect.BeforeAddTile(t, StationRect::ADD_FORCE); } wp->new_index = new_wp->index; } /* Update the orders of vehicles */ OrderList *ol; FOR_ALL_ORDER_LISTS(ol) { if (ol->GetFirstSharedVehicle()->type != VEH_TRAIN) continue; for (Order *o = ol->GetFirstOrder(); o != NULL; o = o->next) UpdateWaypointOrder(o); } Vehicle *v; FOR_ALL_VEHICLES(v) { if (v->type != VEH_TRAIN) continue; UpdateWaypointOrder(&v->current_order); } _old_waypoints.Reset(); }
bool IsCompatibleRailType(RailType rt) { return HasBit(m_compatible_railtypes, rt); }
static void ShipController(Ship *v) { uint32 r; const byte *b; Direction dir; Track track; TrackBits tracks; v->tick_counter++; v->current_order_time++; if (v->breakdown_ctr != 0) { if (v->breakdown_ctr <= 2) { HandleBrokenShip(v); return; } if (!v->current_order.IsType(OT_LOADING)) v->breakdown_ctr--; } if (v->vehstatus & VS_STOPPED) return; ProcessOrders(v); v->HandleLoading(); if (v->current_order.IsType(OT_LOADING)) return; CheckShipLeaveDepot(v); if (!ShipAccelerate(v)) return; GetNewVehiclePosResult gp = GetNewVehiclePos(v); if (v->state != TRACK_BIT_WORMHOLE) { /* Not on a bridge */ if (gp.old_tile == gp.new_tile) { /* Staying in tile */ if (v->IsInDepot()) { gp.x = v->x_pos; gp.y = v->y_pos; } else { /* Not inside depot */ r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y); if (HasBit(r, VETS_CANNOT_ENTER)) goto reverse_direction; /* A leave station order only needs one tick to get processed, so we can * always skip ahead. */ if (v->current_order.IsType(OT_LEAVESTATION)) { v->current_order.Free(); SetWindowWidgetDirty(WC_VEHICLE_VIEW, v->index, VVW_WIDGET_START_STOP_VEH); } else if (v->dest_tile != 0) { /* We have a target, let's see if we reached it... */ if (v->current_order.IsType(OT_GOTO_WAYPOINT) && DistanceManhattan(v->dest_tile, gp.new_tile) <= 3) { /* We got within 3 tiles of our target buoy, so let's skip to our * next order */ UpdateVehicleTimetable(v, true); v->IncrementOrderIndex(); v->current_order.MakeDummy(); } else { /* Non-buoy orders really need to reach the tile */ if (v->dest_tile == gp.new_tile) { if (v->current_order.IsType(OT_GOTO_DEPOT)) { if ((gp.x & 0xF) == 8 && (gp.y & 0xF) == 8) { VehicleEnterDepot(v); return; } } else if (v->current_order.IsType(OT_GOTO_STATION)) { v->last_station_visited = v->current_order.GetDestination(); /* Process station in the orderlist. */ Station *st = Station::Get(v->current_order.GetDestination()); if (st->facilities & FACIL_DOCK) { // ugly, ugly workaround for problem with ships able to drop off cargo at wrong stations ShipArrivesAt(v, st); v->BeginLoading(); } else { // leave stations without docks right aways v->current_order.MakeLeaveStation(); v->IncrementOrderIndex(); } } } } } } } else { DiagDirection diagdir; /* New tile */ if (TileX(gp.new_tile) >= MapMaxX() || TileY(gp.new_tile) >= MapMaxY()) { goto reverse_direction; } dir = ShipGetNewDirectionFromTiles(gp.new_tile, gp.old_tile); assert(dir == DIR_NE || dir == DIR_SE || dir == DIR_SW || dir == DIR_NW); diagdir = DirToDiagDir(dir); tracks = GetAvailShipTracks(gp.new_tile, diagdir); if (tracks == TRACK_BIT_NONE) goto reverse_direction; /* Choose a direction, and continue if we find one */ track = ChooseShipTrack(v, gp.new_tile, diagdir, tracks); if (track == INVALID_TRACK) goto reverse_direction; b = _ship_subcoord[diagdir][track]; gp.x = (gp.x & ~0xF) | b[0]; gp.y = (gp.y & ~0xF) | b[1]; /* Call the landscape function and tell it that the vehicle entered the tile */ r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y); if (HasBit(r, VETS_CANNOT_ENTER)) goto reverse_direction; if (!HasBit(r, VETS_ENTERED_WORMHOLE)) { v->tile = gp.new_tile; v->state = TrackToTrackBits(track); } v->direction = (Direction)b[2]; } } else { /* On a bridge */ if (!IsTileType(gp.new_tile, MP_TUNNELBRIDGE) || !HasBit(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y), VETS_ENTERED_WORMHOLE)) { v->x_pos = gp.x; v->y_pos = gp.y; VehicleMove(v, !(v->vehstatus & VS_HIDDEN)); return; } } /* update image of ship, as well as delta XY */ dir = ShipGetNewDirection(v, gp.x, gp.y); v->x_pos = gp.x; v->y_pos = gp.y; v->z_pos = GetSlopeZ(gp.x, gp.y); getout: v->UpdateViewport(true, true); return; reverse_direction: dir = ReverseDir(v->direction); v->direction = dir; goto getout; }
const Sprite *GetGlyph(FontSize size, WChar key) { FT_Face face = GetFontFace(size); FT_GlyphSlot slot; GlyphEntry new_glyph; GlyphEntry *glyph; SpriteLoader::Sprite sprite; int width; int height; int x; int y; assert(IsPrintable(key)); /* Bail out if no face loaded, or for our special characters */ if (face == NULL || (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END)) { SpriteID sprite = GetUnicodeGlyph(size, key); if (sprite == 0) sprite = GetUnicodeGlyph(size, '?'); return GetSprite(sprite, ST_FONT); } /* Check for the glyph in our cache */ glyph = GetGlyphPtr(size, key); if (glyph != NULL && glyph->sprite != NULL) return glyph->sprite; slot = face->glyph; bool aa = GetFontAAState(size); FT_UInt glyph_index = FT_Get_Char_Index(face, key); if (glyph_index == 0) { if (key == '?') { /* The font misses the '?' character. Use sprite font. */ SpriteID sprite = GetUnicodeGlyph(size, key); Sprite *spr = (Sprite*)GetRawSprite(sprite, ST_FONT, AllocateFont); assert(spr != NULL); new_glyph.sprite = spr; new_glyph.width = spr->width + (size != FS_NORMAL); SetGlyphPtr(size, key, &new_glyph, false); return new_glyph.sprite; } else { /* Use '?' for missing characters. */ GetGlyph(size, '?'); glyph = GetGlyphPtr(size, '?'); SetGlyphPtr(size, key, glyph, true); return glyph->sprite; } } FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); FT_Render_Glyph(face->glyph, aa ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO); /* Despite requesting a normal glyph, FreeType may have returned a bitmap */ aa = (slot->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY); /* Add 1 pixel for the shadow on the medium font. Our sprite must be at least 1x1 pixel */ width = max(1, slot->bitmap.width + (size == FS_NORMAL)); height = max(1, slot->bitmap.rows + (size == FS_NORMAL)); /* Limit glyph size to prevent overflows later on. */ if (width > 256 || height > 256) usererror("Font glyph is too large"); /* FreeType has rendered the glyph, now we allocate a sprite and copy the image into it */ sprite.AllocateData(width * height); sprite.width = width; sprite.height = height; sprite.x_offs = slot->bitmap_left; sprite.y_offs = _ascender[size] - slot->bitmap_top; /* Draw shadow for medium size */ if (size == FS_NORMAL) { for (y = 0; y < slot->bitmap.rows; y++) { for (x = 0; x < slot->bitmap.width; x++) { if (aa ? (slot->bitmap.buffer[x + y * slot->bitmap.pitch] > 0) : HasBit(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) { sprite.data[1 + x + (1 + y) * sprite.width].m = SHADOW_COLOUR; sprite.data[1 + x + (1 + y) * sprite.width].a = aa ? slot->bitmap.buffer[x + y * slot->bitmap.pitch] : 0xFF; } } } } for (y = 0; y < slot->bitmap.rows; y++) { for (x = 0; x < slot->bitmap.width; x++) { if (aa ? (slot->bitmap.buffer[x + y * slot->bitmap.pitch] > 0) : HasBit(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) { sprite.data[x + y * sprite.width].m = FACE_COLOUR; sprite.data[x + y * sprite.width].a = aa ? slot->bitmap.buffer[x + y * slot->bitmap.pitch] : 0xFF; } } } new_glyph.sprite = BlitterFactoryBase::GetCurrentBlitter()->Encode(&sprite, AllocateFont); new_glyph.width = slot->advance.x >> 6; SetGlyphPtr(size, key, &new_glyph); return new_glyph.sprite; }
/* static */ bool AITown::IsActionAvailable(TownID town_id, TownAction town_action) { if (!IsValidTown(town_id)) return false; return HasBit(::GetMaskOfTownActions(NULL, _current_company, ::Town::Get(town_id)), town_action); }
/** * Additional map variety is provided by applying different curve maps * to different parts of the map. A randomized low resolution grid contains * which curve map to use on each part of the make. This filtered non-linearly * to smooth out transitions between curves, so each tile could have between * 100% of one map applied or 25% of four maps. * * The curve maps define different land styles, i.e. lakes, low-lands, hills * and mountain ranges, although these are dependent on the landscape style * chosen as well. * * The level parameter dictates the resolution of the grid. A low resolution * grid will result in larger continuous areas of a land style, a higher * resolution grid splits the style into smaller areas. * @param level Rough indication of the size of the grid sections to style. Small level means large grid sections. */ static void HeightMapCurves(uint level) { height_t mh = TGPGetMaxHeight() - I2H(1); // height levels above sea level only /** Basically scale height X to height Y. Everything in between is interpolated. */ struct control_point_t { height_t x; ///< The height to scale from. height_t y; ///< The height to scale to. }; /* Scaled curve maps; value is in height_ts. */ #define F(fraction) ((height_t)(fraction * mh)) const control_point_t curve_map_1[] = { { F(0.0), F(0.0) }, { F(0.8), F(0.13) }, { F(1.0), F(0.4) } }; const control_point_t curve_map_2[] = { { F(0.0), F(0.0) }, { F(0.53), F(0.13) }, { F(0.8), F(0.27) }, { F(1.0), F(0.6) } }; const control_point_t curve_map_3[] = { { F(0.0), F(0.0) }, { F(0.53), F(0.27) }, { F(0.8), F(0.57) }, { F(1.0), F(0.8) } }; const control_point_t curve_map_4[] = { { F(0.0), F(0.0) }, { F(0.4), F(0.3) }, { F(0.7), F(0.8) }, { F(0.92), F(0.99) }, { F(1.0), F(0.99) } }; #undef F /** Helper structure to index the different curve maps. */ struct control_point_list_t { size_t length; ///< The length of the curve map. const control_point_t *list; ///< The actual curve map. }; const control_point_list_t curve_maps[] = { { lengthof(curve_map_1), curve_map_1 }, { lengthof(curve_map_2), curve_map_2 }, { lengthof(curve_map_3), curve_map_3 }, { lengthof(curve_map_4), curve_map_4 }, }; height_t ht[lengthof(curve_maps)]; MemSetT(ht, 0, lengthof(ht)); /* Set up a grid to choose curve maps based on location; attempt to get a somewhat square grid */ float factor = sqrt((float)_height_map.size_x / (float)_height_map.size_y); uint sx = Clamp((int)(((1 << level) * factor) + 0.5), 1, 128); uint sy = Clamp((int)(((1 << level) / factor) + 0.5), 1, 128); byte *c = AllocaM(byte, sx * sy); for (uint i = 0; i < sx * sy; i++) { c[i] = Random() % lengthof(curve_maps); } /* Apply curves */ for (int x = 0; x < _height_map.size_x; x++) { /* Get our X grid positions and bi-linear ratio */ float fx = (float)(sx * x) / _height_map.size_x + 1.0f; uint x1 = (uint)fx; uint x2 = x1; float xr = 2.0f * (fx - x1) - 1.0f; xr = sin(xr * M_PI_2); xr = sin(xr * M_PI_2); xr = 0.5f * (xr + 1.0f); float xri = 1.0f - xr; if (x1 > 0) { x1--; if (x2 >= sx) x2--; } for (int y = 0; y < _height_map.size_y; y++) { /* Get our Y grid position and bi-linear ratio */ float fy = (float)(sy * y) / _height_map.size_y + 1.0f; uint y1 = (uint)fy; uint y2 = y1; float yr = 2.0f * (fy - y1) - 1.0f; yr = sin(yr * M_PI_2); yr = sin(yr * M_PI_2); yr = 0.5f * (yr + 1.0f); float yri = 1.0f - yr; if (y1 > 0) { y1--; if (y2 >= sy) y2--; } uint corner_a = c[x1 + sx * y1]; uint corner_b = c[x1 + sx * y2]; uint corner_c = c[x2 + sx * y1]; uint corner_d = c[x2 + sx * y2]; /* Bitmask of which curve maps are chosen, so that we do not bother * calculating a curve which won't be used. */ uint corner_bits = 0; corner_bits |= 1 << corner_a; corner_bits |= 1 << corner_b; corner_bits |= 1 << corner_c; corner_bits |= 1 << corner_d; height_t *h = &_height_map.height(x, y); /* Do not touch sea level */ if (*h < I2H(1)) continue; /* Only scale above sea level */ *h -= I2H(1); /* Apply all curve maps that are used on this tile. */ for (uint t = 0; t < lengthof(curve_maps); t++) { if (!HasBit(corner_bits, t)) continue; bool found = false; const control_point_t *cm = curve_maps[t].list; for (uint i = 0; i < curve_maps[t].length - 1; i++) { const control_point_t &p1 = cm[i]; const control_point_t &p2 = cm[i + 1]; if (*h >= p1.x && *h < p2.x) { ht[t] = p1.y + (*h - p1.x) * (p2.y - p1.y) / (p2.x - p1.x); found = true; break; } } assert(found); } /* Apply interpolation of curve map results. */ *h = (height_t)((ht[corner_a] * yri + ht[corner_b] * yr) * xri + (ht[corner_c] * yri + ht[corner_d] * yr) * xr); /* Readd sea level */ *h += I2H(1); } } }
void UpdateVehicleTimetable(Vehicle *v, bool travelling) { uint timetabled = travelling ? v->current_order.travel_time : v->current_order.wait_time; uint time_taken = v->current_order_time; v->current_order_time = 0; if (!_settings_game.order.timetabling) return; bool just_started = false; /* This vehicle is arriving at the first destination in the timetable. */ if (v->cur_order_index == 0 && travelling) { /* If the start date hasn't been set, or it was set automatically when * the vehicle last arrived at the first destination, update it to the * current time. Otherwise set the late counter appropriately to when * the vehicle should have arrived. */ just_started = !HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED); if (v->timetable_start != 0) { v->lateness_counter = (_date - v->timetable_start) * DAY_TICKS + _date_fract; v->timetable_start = 0; } SetBit(v->vehicle_flags, VF_TIMETABLE_STARTED); SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index); } if (!HasBit(v->vehicle_flags, VF_TIMETABLE_STARTED)) return; if (HasBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE)) { if (travelling && !HasBit(v->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME)) { /* Need to clear that now as otherwise we are not able to reduce the wait time */ v->current_order.wait_time = 0; } if (just_started) return; /* Modify station waiting time only if our new value is larger (this is * always the case when we cleared the timetable). */ if (!v->current_order.IsType(OT_CONDITIONAL) && (travelling || time_taken > v->current_order.wait_time)) { /* Round the time taken up to the nearest day, as this will avoid * confusion for people who are timetabling in days, and can be * adjusted later by people who aren't. */ time_taken = CeilDiv(time_taken, DAY_TICKS) * DAY_TICKS; ChangeTimetable(v, v->cur_order_index, time_taken, travelling); } if (v->cur_order_index == 0 && travelling) { /* If we just started we would have returned earlier and have not reached * this code. So obviously, we have completed our round: So turn autofill * off again. */ ClrBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE); ClrBit(v->vehicle_flags, VF_AUTOFILL_PRES_WAIT_TIME); } return; } if (just_started) return; /* Vehicles will wait at stations if they arrive early even if they are not * timetabled to wait there, so make sure the lateness counter is updated * when this happens. */ if (timetabled == 0 && (travelling || v->lateness_counter >= 0)) return; v->lateness_counter -= (timetabled - time_taken); for (v = v->FirstShared(); v != NULL; v = v->NextShared()) { SetWindowDirty(WC_VEHICLE_TIMETABLE, v->index); } }