celestar@9912: /* $Id$ */ celestar@9912: celestar@9912: /** @file newgrf_industries.cpp */ celestar@9912: celestar@9912: #include "stdafx.h" celestar@9912: #include "openttd.h" celestar@9912: #include "debug.h" celestar@9912: #include "functions.h" celestar@9912: #include "macros.h" celestar@9912: #include "industry.h" celestar@9913: #include "industry_map.h" celestar@9912: #include "newgrf.h" celestar@9912: #include "newgrf_callbacks.h" celestar@9912: #include "newgrf_spritegroup.h" celestar@9912: #include "newgrf_industries.h" celestar@9912: #include "newgrf_commons.h" celestar@9912: celestar@9912: /* Since the industry IDs defined by the GRF file don't necessarily correlate celestar@9912: * to those used by the game, the IDs used for overriding old industries must be celestar@9912: * translated when the idustry spec is set. */ celestar@9912: IndustryOverrideManager _industry_mngr(NEW_INDUSTRYOFFSET, NUM_INDUSTRYTYPES, INVALID_INDUSTRYTYPE); celestar@9912: celestar@9912: /** celestar@9912: * Finds the distance for the closest tile with water/land given a tile celestar@9912: * @param tile the tile to find the distance too celestar@9912: * @param water whether to find water or land celestar@9912: * @note FAILS when an industry should be seen as water celestar@9912: */ celestar@9912: static uint GetClosestWaterDistance(TileIndex tile, bool water) celestar@9912: { celestar@9912: TileIndex t; celestar@9912: uint best_dist; celestar@9912: for (t = 1; t < MapSize(); t++) { celestar@9912: if (IsTileType(t, MP_WATER) == water) break; celestar@9912: } celestar@9912: best_dist = DistanceManhattan(tile, t); celestar@9912: celestar@9912: for (; t < MapSize(); t++) { celestar@9912: uint dist = DistanceManhattan(tile, t); celestar@9912: if (dist < best_dist) { celestar@9912: if (IsTileType(t, MP_WATER) == water) best_dist = dist; celestar@9912: } else { celestar@9912: /* When the Y distance between the current row and the 'source' tile celestar@9912: * is larger than the best distance, we've found the best distance */ celestar@9912: if (TileY(t) - TileY(tile) > best_dist) return best_dist; celestar@9912: if (TileX(tile) > TileX(t)) { celestar@9912: /* We can safely skip this many tiles; from here all tiles have a celestar@9912: * higher or equal distance than the best distance */ celestar@9912: t |= MapMaxX(); celestar@9912: continue; celestar@9912: } else { celestar@9912: /* We can safely skip this many tiles; up to here all tiles have a celestar@9912: * higher or equal distance than the best distance */ celestar@9912: t += best_dist - dist; celestar@9912: continue; celestar@9912: } celestar@9912: } celestar@9912: } celestar@9912: celestar@9912: return best_dist; celestar@9912: } celestar@9912: celestar@9913: /** Make an analysis of a tile and check for its belonging to the same celestar@9913: * industry, and/or the same grf file celestar@9913: * @param new_tile TileIndex of the tile to query celestar@9913: * @param old_tile TileINdex of teh reference tile celestar@9913: * @param i Industry to which old_tile belongs to celestar@9913: * @return value encoded as per NFO specs */ celestar@9913: uint32 GetIndustryIDAtOffset(TileIndex new_tile, TileIndex old_tile, const Industry *i) celestar@9913: { celestar@9913: if (IsTileType(new_tile, MP_INDUSTRY)) { // Is this an industry tile? celestar@9913: celestar@9913: if (GetIndustryIndex(new_tile) == i->index) { // Does it belong to the same industry? celestar@9913: IndustryGfx gfx = GetIndustryGfx(new_tile); celestar@9913: const IndustryTileSpec *indtsp = GetIndustryTileSpec(gfx); celestar@9913: const IndustryTileSpec *indold = GetIndustryTileSpec(GetIndustryGfx(old_tile)); celestar@9913: celestar@9913: if (gfx < NEW_INDUSTRYOFFSET) { // Does it belongs to an old type? celestar@9913: /* It is an old tile. We have to see if it's been overriden */ celestar@9913: if (indtsp->grf_prop.override == INVALID_INDUSTRYTILE) { // has it been overridden? celestar@9913: return 0xFF << 8 | gfx; // no. Tag FF + the gfx id of that tile celestar@9913: } else { // yes. FInd out if it is from the same grf file or not celestar@9913: const IndustryTileSpec *old_tile_ovr = GetIndustryTileSpec(indtsp->grf_prop.override); celestar@9913: celestar@9913: if (old_tile_ovr->grf_prop.grffile->grfid == indold->grf_prop.grffile->grfid) { celestar@9913: return old_tile_ovr->grf_prop.local_id; // same grf file celestar@9913: } else { celestar@9913: return 0xFFFE; // not the same grf file celestar@9913: } celestar@9913: } celestar@9913: } else { celestar@9913: if (indtsp->grf_prop.spritegroup != NULL) { // tile has a spritegroup ? celestar@9913: if (indtsp->grf_prop.grffile->grfid == indold->grf_prop.grffile->grfid) { // same industry, same grf ? celestar@9913: return indtsp->grf_prop.local_id; celestar@9913: } else { celestar@9913: return 0xFFFE; // Defined in another grf file celestar@9913: } celestar@9913: } else { // tile has no spritegroup celestar@9913: return 0xFF << 8 | indtsp->grf_prop.subst_id; // so just give him the substitute celestar@9913: } celestar@9913: } celestar@9913: } celestar@9913: } celestar@9913: celestar@9913: return 0xFFFF; // tile is not an industry one or does not belong to the current industry celestar@9913: } celestar@9913: celestar@9912: /** This function implements the industries variables that newGRF defines. celestar@9912: * @param variable that is queried celestar@9912: * @param parameter unused celestar@9912: * @param available will return false if ever the variable asked for does not exist celestar@9912: * @param ind is of course the industry we are inquiring celestar@9912: * @return the value stored in the corresponding variable*/ celestar@9912: uint32 IndustryGetVariable(const ResolverObject *object, byte variable, byte parameter, bool *available) celestar@9912: { celestar@9912: const Industry *industry = object->u.industry.ind; celestar@9912: TileIndex tile = object->u.industry.tile; celestar@9912: const IndustrySpec *indspec = GetIndustrySpec(industry->type); celestar@9912: celestar@9912: switch (variable) { celestar@9912: case 0x40: celestar@9912: case 0x41: celestar@9912: case 0x42: { // waiting cargo, but only if those two callback flags are set celestar@9912: uint16 callback = indspec->callback_flags; celestar@9912: if (callback & (CBM_IND_PRODUCTION_CARGO_ARRIVAL | callback & CBM_IND_PRODUCTION_256_TICKS)) { celestar@9912: return max(industry->cargo_waiting[variable - 0x40], (uint16)0x7FFF); celestar@9912: } else { celestar@9912: return 0; celestar@9912: } celestar@9912: } celestar@9912: /* TODO: somehow determine whether we're in water or not */ celestar@9912: case 0x43: return GetClosestWaterDistance(tile, true); // Manhattan distance of closes dry/water tile celestar@9912: celestar@9913: /* Get industry ID at offset param */ celestar@9913: case 0x60: return GetIndustryIDAtOffset(GetNearbyTile(parameter, industry->xy), tile, industry); celestar@9912: celestar@9912: case 0x61: return 0; // Get random tile bits at offset param celestar@9912: celestar@9912: case 0x62: // Land info of nearby tiles celestar@9912: case 0x63: // Animation stage of nerby tiles celestar@9912: case 0x64: break; // Distance of nearest industry of given type celestar@9912: /* Get town zone and Manhattan distance of closest town */ celestar@9912: case 0x65: return industry->town->GetRadiusGroup(tile) << 16 | min(DistanceManhattan(tile, industry->town->xy), 0xFFFF); celestar@9912: /* Get square of Euclidian distance of closes town */ celestar@9912: case 0x66: return industry->town->GetRadiusGroup(tile) << 16 | min(DistanceSquare(tile, industry->town->xy), 0xFFFF); celestar@9912: celestar@9912: /* Count of industry, distance of closest instance celestar@9912: * format is rr(reserved) cc(count) dddd(manhattan distance of closest sister) celestar@9912: * A lot more should be done, since it has to check for local id, grf id etc... celestar@9912: * let's just say it is a beginning ;) */ celestar@9912: case 0x67: return GetIndustryTypeCount(industry->type) << 16 | 0; celestar@9912: celestar@9912: /* Industry founder information. celestar@9912: * 0x10 if randomly created or from a map pre-newindustry. celestar@9912: * Else, the company who funded it */ celestar@9912: case 0xA7: return 0x10; celestar@9912: celestar@9912: case 0xB0: // Date when built since 1920 (in days) celestar@9912: case 0xB3: // Construction type celestar@9912: case 0xB4: break; // Date last cargo accepted since 1920 (in days) celestar@9912: celestar@9912: /* Industry structure access*/ celestar@9912: case 0x80: return industry->xy; celestar@9912: case 0x81: return GB(industry->xy, 8, 8); celestar@9912: /* Pointer to the town the industry is associated with */ celestar@9912: case 0x82: celestar@9912: case 0x83: celestar@9912: case 0x84: celestar@9912: case 0x85: break; // not supported celestar@9912: case 0x86: return industry->width; celestar@9912: case 0x87: return industry->height;// xy dimensions celestar@9912: /* */ celestar@9912: case 0x88: celestar@9912: case 0x89: return indspec->produced_cargo[variable - 0x88]; celestar@9912: case 0x8A: return industry->cargo_waiting[0]; celestar@9912: case 0x8B: return GB(industry->cargo_waiting[0], 8, 8); celestar@9912: case 0x8C: return industry->cargo_waiting[1]; celestar@9912: case 0x8D: return GB(industry->cargo_waiting[1], 8, 8); celestar@9912: case 0x8E: celestar@9912: case 0x8F: return industry->production_rate[variable - 0x8E]; celestar@9912: case 0x90: celestar@9912: case 0x91: celestar@9912: case 0x92: return indspec->accepts_cargo[variable - 0x90]; celestar@9912: case 0x93: return industry->prod_level; celestar@9912: /* amount of cargo produced so far THIS month. */ celestar@9912: case 0x94: return industry->this_month_production[0]; celestar@9912: case 0x95: return GB(industry->this_month_production[0], 8, 8); celestar@9912: case 0x96: return industry->this_month_production[1]; celestar@9912: case 0x97: return GB(industry->this_month_production[1], 8, 8); celestar@9912: /* amount of cargo transported so far THIS month. */ celestar@9912: case 0x98: return industry->this_month_transported[0]; celestar@9912: case 0x99: return GB(industry->this_month_transported[0], 8, 8); celestar@9912: case 0x9A: return industry->this_month_transported[1]; celestar@9912: case 0x9B: return GB(industry->this_month_transported[0], 8, 8); celestar@9912: /* fraction of cargo transported LAST month. */ celestar@9912: case 0x9C: celestar@9912: case 0x9D: return industry->last_month_pct_transported[variable - 0x9C]; celestar@9912: /* amount of cargo produced LAST month. */ celestar@9912: case 0x9E: return industry->last_month_production[0]; celestar@9912: case 0x9F: return GB(industry->last_month_production[0], 8, 8); celestar@9912: case 0xA0: return industry->last_month_production[1]; celestar@9912: case 0xA1: return GB(industry->last_month_production[1], 8, 8); celestar@9912: /* amount of cargo transported last month. */ celestar@9912: case 0xA2: return industry->last_month_transported[0]; celestar@9912: case 0xA3: return GB(industry->last_month_transported[0], 8, 8); celestar@9912: case 0xA4: return industry->last_month_transported[1]; celestar@9912: case 0xA5: return GB(industry->last_month_transported[0], 8, 8); celestar@9912: celestar@9912: case 0xA6: return industry->type; celestar@9912: celestar@9912: case 0xA8: return industry->random_color; celestar@9912: case 0xA9: return industry->last_prod_year; // capped? celestar@9912: case 0xAA: return industry->counter; celestar@9912: case 0xAB: return GB(industry->counter, 8, 8); celestar@9912: case 0xAC: return industry->was_cargo_delivered; celestar@9912: } celestar@9912: celestar@9912: DEBUG(grf, 1, "Unhandled industry property 0x%X", variable); celestar@9912: celestar@9912: *available = false; celestar@9912: return (uint32)-1; celestar@9912: } celestar@9912: celestar@9912: static const SpriteGroup *IndustryResolveReal(const ResolverObject *object, const SpriteGroup *group) celestar@9912: { celestar@9912: /* IndustryTile do not have 'real' groups */ celestar@9912: return NULL; celestar@9912: } celestar@9912: celestar@9913: static void NewIndustryResolver(ResolverObject *res, TileIndex tile, Industry *indus) celestar@9912: { celestar@9913: res->GetRandomBits = IndustryTileGetRandomBits; celestar@9913: res->GetTriggers = IndustryTileGetTriggers; celestar@9913: res->SetTriggers = IndustryTileSetTriggers; celestar@9912: res->GetVariable = IndustryGetVariable; celestar@9912: res->ResolveReal = IndustryResolveReal; celestar@9912: celestar@9912: res->u.industry.tile = tile; celestar@9912: res->u.industry.ind = indus; celestar@9913: res->u.industry.gfx = INVALID_INDUSTRYTILE; celestar@9912: celestar@9912: res->callback = 0; celestar@9912: res->callback_param1 = 0; celestar@9912: res->callback_param2 = 0; celestar@9912: res->last_value = 0; celestar@9912: res->trigger = 0; celestar@9912: res->reseed = 0; celestar@9912: } celestar@9912: celestar@9912: uint16 GetIndustryCallback(uint16 callback, uint32 param1, uint32 param2, Industry *industry, TileIndex tile) celestar@9912: { celestar@9912: ResolverObject object; celestar@9912: const SpriteGroup *group; celestar@9912: celestar@9913: NewIndustryResolver(&object, tile, industry); celestar@9912: object.callback = callback; celestar@9912: object.callback_param1 = param1; celestar@9912: object.callback_param2 = param2; celestar@9912: celestar@9912: group = Resolve(GetIndustrySpec(industry->type)->grf_prop.spritegroup, &object); celestar@9912: if (group == NULL || group->type != SGT_CALLBACK) return CALLBACK_FAILED; celestar@9912: celestar@9912: return group->g.callback.result; celestar@9912: }