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