belugas@6629: /* $Id$ */ belugas@6629: belugas@6629: /** @file newgrf_commons.cpp Implementation of the class OverrideManagerBase belugas@6629: * and its descendance, present and futur belugas@6629: */ belugas@6629: belugas@6629: #include "stdafx.h" belugas@6629: #include "openttd.h" belugas@6801: #include "variables.h" maedhros@6849: #include "landscape.h" belugas@6629: #include "town.h" belugas@6629: #include "industry.h" belugas@6629: #include "newgrf.h" belugas@6629: #include "newgrf_commons.h" rubidium@8108: #include "tile_map.h" glx@8118: #include "station_map.h" rubidium@8270: #include "settings_type.h" frosch@8459: #include "tree_map.h" belugas@6629: belugas@6629: /** Constructor of generic class belugas@6629: * @param offset end of original data for this entity. i.e: houses = 110 belugas@6629: * @param maximum of entities this manager can deal with. i.e: houses = 512 belugas@6629: * @param invalid is the ID used to identify an invalid entity id belugas@6629: */ belugas@6629: OverrideManagerBase::OverrideManagerBase(uint16 offset, uint16 maximum, uint16 invalid) belugas@6629: { belugas@6629: max_offset = offset; belugas@6629: max_new_entities = maximum; belugas@6629: invalid_ID = invalid; belugas@6629: belugas@6629: mapping_ID = CallocT(max_new_entities); belugas@6629: entity_overrides = MallocT(max_offset); belugas@6629: memset(entity_overrides, invalid, sizeof(entity_overrides)); glx@7873: grfid_overrides = CallocT(max_offset); belugas@6629: } belugas@6629: belugas@6629: /** Destructor of the generic class. belugas@6629: * Frees allocated memory of constructor belugas@6629: */ belugas@6629: OverrideManagerBase::~OverrideManagerBase() belugas@6629: { belugas@6629: free(mapping_ID); belugas@6629: free(entity_overrides); glx@7873: free(grfid_overrides); belugas@6629: } belugas@6629: belugas@6629: /** Since the entity IDs defined by the GRF file does not necessarily correlate belugas@6629: * to those used by the game, the IDs used for overriding old entities must be belugas@6629: * translated when the entity spec is set. glx@7873: * @param local_id ID in grf file glx@7873: * @param grfid ID of the grf file belugas@6629: * @param entity_type original entity type belugas@6629: */ glx@7873: void OverrideManagerBase::Add(uint8 local_id, uint32 grfid, uint entity_type) belugas@6629: { belugas@6629: assert(entity_type < max_offset); glx@7874: /* An override can be set only once */ glx@7874: if (entity_overrides[entity_type] != invalid_ID) return; belugas@6629: entity_overrides[entity_type] = local_id; glx@7873: grfid_overrides[entity_type] = grfid; belugas@6629: } belugas@6629: belugas@6629: /** Resets the mapping, which is used while initializing game */ belugas@6629: void OverrideManagerBase::ResetMapping() belugas@6629: { belugas@6629: memset(mapping_ID, 0, (max_new_entities - 1) * sizeof(EntityIDMapping)); belugas@6629: } belugas@6629: belugas@6629: /** Resets the override, which is used while initializing game */ belugas@6629: void OverrideManagerBase::ResetOverride() belugas@6629: { belugas@6629: for (uint16 i = 0; i < max_offset; i++) { belugas@6629: entity_overrides[i] = invalid_ID; glx@7873: grfid_overrides[i] = 0; belugas@6629: } belugas@6629: } belugas@6629: belugas@6629: /** Return the ID (if ever available) of a previously inserted entity. belugas@6629: * @param grf_local_id ID of this enity withing the grfID belugas@6629: * @param grfid ID of the grf file belugas@6629: * @return the ID of the candidate, of the Invalid flag item ID belugas@6629: */ belugas@6629: uint16 OverrideManagerBase::GetID(uint8 grf_local_id, uint32 grfid) belugas@6629: { belugas@6629: const EntityIDMapping *map; belugas@6629: rubidium@7235: for (uint16 id = 0; id < max_new_entities; id++) { belugas@6629: map = &mapping_ID[id]; belugas@6629: if (map->entity_id == grf_local_id && map->grfid == grfid) { belugas@6629: return id; belugas@6629: } belugas@6629: } glx@7875: belugas@6629: return invalid_ID; belugas@6629: } belugas@6629: belugas@6629: /** Reserves a place in the mapping array for an entity to be installed belugas@6629: * @param grf_local_id is an arbitrary id given by the grf's author. Also known as setid belugas@6629: * @param grfid is the id of the grf file itself belugas@6629: * @param substitute_id is the original entity from which data is copied for the new one belugas@6629: * @return the proper usable slot id, or invalid marker if none is found belugas@6629: */ belugas@6629: uint16 OverrideManagerBase::AddEntityID(byte grf_local_id, uint32 grfid, byte substitute_id) belugas@6629: { belugas@6629: uint16 id = this->GetID(grf_local_id, grfid); belugas@6629: EntityIDMapping *map; belugas@6629: belugas@6629: /* Look to see if this entity has already been added. This is done belugas@6629: * separately from the loop below in case a GRF has been deleted, and there belugas@6629: * are any gaps in the array. belugas@6629: */ belugas@6629: if (id != invalid_ID) { belugas@6629: return id; belugas@6629: } belugas@6629: belugas@6629: /* This entity hasn't been defined before, so give it an ID now. */ belugas@6629: for (id = max_offset; id < max_new_entities; id++) { belugas@6629: map = &mapping_ID[id]; belugas@6629: belugas@7632: if (CheckValidNewID(id) && map->entity_id == 0 && map->grfid == 0) { belugas@6629: map->entity_id = grf_local_id; belugas@6629: map->grfid = grfid; belugas@6629: map->substitute_id = substitute_id; belugas@6629: return id; belugas@6629: } belugas@6629: } belugas@6629: belugas@6629: return invalid_ID; belugas@6629: } belugas@6629: belugas@6629: /** Gives the substitute of the entity, as specified by the grf file belugas@6629: * @param entity_id of the entity being queried belugas@6629: * @return mapped id belugas@6629: */ belugas@6629: uint16 OverrideManagerBase::GetSubstituteID(byte entity_id) belugas@6629: { belugas@6629: return mapping_ID[entity_id].substitute_id; belugas@6629: } belugas@6629: belugas@6629: /** Install the specs into the HouseSpecs array belugas@6629: * It will find itself the proper slot onwhich it will go belugas@6629: * @param hs HouseSpec read from the grf file, ready for inclusion belugas@6629: */ belugas@6629: void HouseOverrideManager::SetEntitySpec(const HouseSpec *hs) belugas@6629: { belugas@6629: HouseID house_id = this->AddEntityID(hs->local_id, hs->grffile->grfid, hs->substitute_id); belugas@6629: belugas@6629: if (house_id == invalid_ID) { belugas@6629: grfmsg(1, "House.SetEntitySpec: Too many houses allocated. Ignoring."); belugas@6629: return; belugas@6629: } belugas@6629: belugas@6629: memcpy(&_house_specs[house_id], hs, sizeof(*hs)); belugas@6629: belugas@6629: /* Now add the overrides. */ belugas@6629: for (int i = 0; i != max_offset; i++) { belugas@6629: HouseSpec *overridden_hs = GetHouseSpecs(i); belugas@6629: glx@7873: if (entity_overrides[i] != hs->local_id || grfid_overrides[i] != hs->grffile->grfid) continue; belugas@6629: belugas@6629: overridden_hs->override = house_id; belugas@6629: entity_overrides[i] = invalid_ID; glx@7873: grfid_overrides[i] = 0; belugas@6629: } belugas@6629: } belugas@6801: glx@8511: /** Return the ID (if ever available) of a previously inserted entity. glx@8511: * @param grf_local_id ID of this enity withing the grfID glx@8511: * @param grfid ID of the grf file glx@8511: * @return the ID of the candidate, of the Invalid flag item ID glx@8511: */ glx@8511: uint16 IndustryOverrideManager::GetID(uint8 grf_local_id, uint32 grfid) glx@8511: { glx@8511: uint16 id = OverrideManagerBase::GetID(grf_local_id, grfid); glx@8511: if (id != invalid_ID) return id; glx@8511: glx@8511: /* No mapping found, try the overrides */ glx@8511: for (id = 0; id < max_offset; id++) { glx@8511: if (entity_overrides[id] == grf_local_id && grfid_overrides[id] == grfid) return id; glx@8511: } glx@8511: glx@8511: return invalid_ID; glx@8511: } glx@8511: belugas@6835: /** Method to find an entity ID and to mark it as reserved for the Industry to be included. belugas@6835: * @param grf_local_id ID used by the grf file for pre-installation work (equivalent of TTDPatch's setid belugas@6835: * @param grfid ID of the current grf file belugas@6835: * @param substitute_id industry from which data has been copied belugas@6835: * @return a free entity id (slotid) if ever one has been found, or Invalid_ID marker otherwise belugas@6835: */ belugas@6835: uint16 IndustryOverrideManager::AddEntityID(byte grf_local_id, uint32 grfid, byte substitute_id) belugas@6835: { belugas@6835: /* This entity hasn't been defined before, so give it an ID now. */ belugas@6835: for (uint16 id = 0; id < max_new_entities; id++) { glx@7875: /* Skip overriden industries */ glx@7875: if (id < max_offset && entity_overrides[id] != invalid_ID) continue; glx@7875: belugas@6835: /* Get the real live industry */ belugas@6835: const IndustrySpec *inds = GetIndustrySpec(id); belugas@6835: belugas@6835: /* This industry must be one that is not available(enabled), mostly because of climate. belugas@6835: * And it must not already be used by a grf (grffile == NULL). belugas@6835: * So reseve this slot here, as it is the chosen one */ belugas@6835: if (!inds->enabled && inds->grf_prop.grffile == NULL) { belugas@6835: EntityIDMapping *map = &mapping_ID[id]; belugas@6835: belugas@6835: if (map->entity_id == 0 && map->grfid == 0) { belugas@6835: /* winning slot, mark it as been used */ belugas@6835: map->entity_id = grf_local_id; belugas@6835: map->grfid = grfid; belugas@6835: map->substitute_id = substitute_id; belugas@6835: return id; belugas@6835: } belugas@6835: } belugas@6835: } belugas@6835: belugas@6835: return invalid_ID; belugas@6835: } belugas@6835: belugas@6835: /** Method to install the new indistry data in its proper slot belugas@6835: * The slot assigment is internal of this method, since it requires belugas@6835: * checking what is available belugas@6835: * @param inds Industryspec that comes from the grf decoding process belugas@6835: */ belugas@7667: void IndustryOverrideManager::SetEntitySpec(IndustrySpec *inds) belugas@6835: { belugas@6835: /* First step : We need to find if this industry is already specified in the savegame data */ belugas@6835: IndustryType ind_id = this->GetID(inds->grf_prop.local_id, inds->grf_prop.grffile->grfid); belugas@6835: glx@7875: if (ind_id == invalid_ID) { glx@7875: /* Not found. glx@7875: * Or it has already been overriden, so you've lost your place old boy. glx@7875: * Or it is a simple substitute. glx@7875: * We need to find a free available slot */ glx@7875: ind_id = this->AddEntityID(inds->grf_prop.local_id, inds->grf_prop.grffile->grfid, inds->grf_prop.subst_id); glx@7875: inds->grf_prop.override = invalid_ID; // make sure it will not be detected as overriden belugas@6835: } belugas@6835: belugas@6835: if (ind_id == invalid_ID) { belugas@6835: grfmsg(1, "Industry.SetEntitySpec: Too many industries allocated. Ignoring."); belugas@6835: return; belugas@6835: } belugas@6835: belugas@6835: /* Now that we know we can use the given id, copy the spech to its final destination*/ belugas@6835: memcpy(&_industry_specs[ind_id], inds, sizeof(*inds)); belugas@6835: /* and mark it as usable*/ belugas@6835: _industry_specs[ind_id].enabled = true; belugas@6835: } belugas@6835: belugas@7000: void IndustryTileOverrideManager::SetEntitySpec(const IndustryTileSpec *its) belugas@7000: { belugas@7000: IndustryGfx indt_id = this->AddEntityID(its->grf_prop.local_id, its->grf_prop.grffile->grfid, its->grf_prop.subst_id); belugas@7000: belugas@7000: if (indt_id == invalid_ID) { belugas@7000: grfmsg(1, "IndustryTile.SetEntitySpec: Too many industry tiles allocated. Ignoring."); belugas@7000: return; belugas@7000: } belugas@7000: belugas@7000: memcpy(&_industry_tile_specs[indt_id], its, sizeof(*its)); belugas@7000: belugas@7000: /* Now add the overrides. */ belugas@7000: for (int i = 0; i < max_offset; i++) { belugas@7000: IndustryTileSpec *overridden_its = &_industry_tile_specs[i]; belugas@7000: glx@7873: if (entity_overrides[i] != its->grf_prop.local_id || grfid_overrides[i] != its->grf_prop.grffile->grfid) continue; belugas@7000: belugas@7000: overridden_its->grf_prop.override = indt_id; belugas@7000: overridden_its->enabled = false; belugas@7000: entity_overrides[i] = invalid_ID; glx@7873: grfid_overrides[i] = 0; belugas@7000: } belugas@7000: } belugas@7000: belugas@6801: /** Function used by houses (and soon industries) to get information belugas@6801: * on type of "terrain" the tile it is queries sits on. belugas@6801: * @param tile TileIndex of the tile been queried belugas@6801: * @return value corresponding to the grf expected format: belugas@6801: * Terrain type: 0 normal, 1 desert, 2 rainforest, 4 on or above snowline */ belugas@6801: uint32 GetTerrainType(TileIndex tile) belugas@6801: { rubidium@9413: switch (_settings_game.game_creation.landscape) { peter1138@8394: case LT_TROPIC: return GetTropicZone(tile); belugas@7538: case LT_ARCTIC: return GetTileZ(tile) > GetSnowLine() ? 4 : 0; belugas@6801: default: return 0; belugas@6801: } belugas@6801: } belugas@6801: belugas@6827: TileIndex GetNearbyTile(byte parameter, TileIndex tile) belugas@6827: { belugas@6827: int8 x = GB(parameter, 0, 4); belugas@6827: int8 y = GB(parameter, 4, 4); belugas@6827: belugas@6827: if (x >= 8) x -= 16; belugas@6827: if (y >= 8) y -= 16; belugas@6827: glx@8118: /* Swap width and height depending on axis for railway stations */ peter1138@8533: if (IsRailwayStationTile(tile) && GetRailStationAxis(tile) == AXIS_Y) Swap(x, y); glx@8118: rubidium@7238: /* Make sure we never roam outside of the map */ rubidium@7238: return TILE_MASK(tile + TileDiffXY(x, y)); belugas@6827: } frosch@8458: frosch@8458: /** frosch@8458: * Common part of station var 0x67 , house var 0x62, indtile var 0x60, industry var 0x62. frosch@8458: * frosch@8458: * @param tile the tile of interest. frosch@8458: * @return 0czzbbss: c = TileType; zz = TileZ; bb: 7-3 zero, 4-2 TerrainType, 1 water/shore, 0 zero; ss = TileSlope frosch@8458: */ frosch@8458: uint32 GetNearbyTileInformation(TileIndex tile) frosch@8458: { frosch@8458: TileType tile_type = GetTileType(tile); frosch@8458: frosch@8459: /* Fake tile type for trees on shore */ frosch@8459: if (IsTileType(tile, MP_TREES) && GetTreeGround(tile) == TREE_GROUND_SHORE) tile_type = MP_WATER; frosch@8459: frosch@8458: uint z; frosch@8458: Slope tileh = GetTileSlope(tile, &z); frosch@8458: byte terrain_type = GetTerrainType(tile) << 2 | (tile_type == MP_WATER ? 1 : 0) << 1; frosch@8458: return tile_type << 24 | z << 16 | terrain_type << 8 | tileh; frosch@8458: }