1159 16, 16, 16, 16, 16, 16, 16, 16, |
1160 16, 16, 16, 16, 16, 16, 16, 16, |
1160 16, 16, 16, 16, 16, 16, 16, 16, |
1161 16, 16, 16, 16, 16, 16, 16, 16, |
1161 16, 16, 16, 16, 16, 16, 16, |
1162 16, 16, 16, 16, 16, 16, 16, |
1162 }; |
1163 }; |
1163 |
1164 |
1164 static bool CheckIfIndustryTilesAreFree(TileIndex tile, const IndustryTileTable *it, int type, const Town *t) |
1165 static bool CheckIfIndustryTilesAreFree(TileIndex tile, const IndustryTileTable *it, int type) |
1165 { |
1166 { |
1166 _error_message = STR_0239_SITE_UNSUITABLE; |
1167 _error_message = STR_0239_SITE_UNSUITABLE; |
1167 |
1168 |
1168 do { |
1169 do { |
1169 TileIndex cur_tile = tile + ToTileIndexDiff(it->ti); |
1170 TileIndex cur_tile = tile + ToTileIndexDiff(it->ti); |
1189 if (IsTileType(cur_tile, MP_WATER) && _m[cur_tile].m5 == 0) return false; |
1190 if (IsTileType(cur_tile, MP_WATER) && _m[cur_tile].m5 == 0) return false; |
1190 |
1191 |
1191 tileh = GetTileSlope(cur_tile, NULL); |
1192 tileh = GetTileSlope(cur_tile, NULL); |
1192 if (IsSteepSlope(tileh)) return false; |
1193 if (IsSteepSlope(tileh)) return false; |
1193 |
1194 |
1194 if (tileh != SLOPE_FLAT) { |
1195 if (_patches.land_generator == LG_TERRAGENESIS || !_generating_world) { |
1195 Slope t; |
1196 /* It is almost impossible to have a fully flat land in TG, so what we |
1196 byte bits = _industry_section_bits[it->gfx]; |
1197 * do is that we check if we can make the land flat later on. See |
1197 |
1198 * CheckIfCanLevelIndustryPlatform(). */ |
1198 if (bits & 0x10) return false; |
1199 if (tileh != SLOPE_FLAT) { |
1199 |
1200 Slope t; |
1200 t = ComplementSlope(tileh); |
1201 byte bits = _industry_section_bits[it->gfx]; |
1201 |
1202 |
1202 if (bits & 1 && (t & SLOPE_NW)) return false; |
1203 if (bits & 0x10) return false; |
1203 if (bits & 2 && (t & SLOPE_NE)) return false; |
1204 |
1204 if (bits & 4 && (t & SLOPE_SW)) return false; |
1205 t = ComplementSlope(tileh); |
1205 if (bits & 8 && (t & SLOPE_SE)) return false; |
1206 |
|
1207 if (bits & 1 && (t & SLOPE_NW)) return false; |
|
1208 if (bits & 2 && (t & SLOPE_NE)) return false; |
|
1209 if (bits & 4 && (t & SLOPE_SW)) return false; |
|
1210 if (bits & 8 && (t & SLOPE_SE)) return false; |
|
1211 } |
1206 } |
1212 } |
1207 |
1213 |
1208 if (type == IT_BANK_TEMP) { |
1214 if (type == IT_BANK_TEMP) { |
1209 if (!IsTileType(cur_tile, MP_HOUSE) || t->population < 1200) { |
1215 if (!IsTileType(cur_tile, MP_HOUSE)) { |
1210 _error_message = STR_029D_CAN_ONLY_BE_BUILT_IN_TOWNS; |
1216 _error_message = STR_029D_CAN_ONLY_BE_BUILT_IN_TOWNS; |
1211 return false; |
1217 return false; |
1212 } |
1218 } |
1213 } else if (type == IT_BANK_TROPIC_ARCTIC) { |
1219 } else if (type == IT_BANK_TROPIC_ARCTIC) { |
1214 if (!IsTileType(cur_tile, MP_HOUSE)) { |
1220 if (!IsTileType(cur_tile, MP_HOUSE)) { |
1215 _error_message = STR_030D_CAN_ONLY_BE_BUILT_IN_TOWNS; |
1221 _error_message = STR_030D_CAN_ONLY_BE_BUILT_IN_TOWNS; |
1216 return false; |
1222 return false; |
1217 } |
1223 } |
1218 } else if (type == IT_TOY_SHOP) { |
1224 } else if (type == IT_TOY_SHOP) { |
1219 if (DistanceMax(t->xy, cur_tile) > 9) return false; |
|
1220 if (!IsTileType(cur_tile, MP_HOUSE)) goto do_clear; |
1225 if (!IsTileType(cur_tile, MP_HOUSE)) goto do_clear; |
1221 } else if (type == IT_WATER_TOWER) { |
1226 } else if (type == IT_WATER_TOWER) { |
1222 if (!IsTileType(cur_tile, MP_HOUSE)) { |
1227 if (!IsTileType(cur_tile, MP_HOUSE)) { |
1223 _error_message = STR_0316_CAN_ONLY_BE_BUILT_IN_TOWNS; |
1228 _error_message = STR_0316_CAN_ONLY_BE_BUILT_IN_TOWNS; |
1224 return false; |
1229 return false; |
1232 } |
1237 } |
1233 } while ((++it)->ti.x != -0x80); |
1238 } while ((++it)->ti.x != -0x80); |
1234 |
1239 |
1235 return true; |
1240 return true; |
1236 } |
1241 } |
|
1242 |
|
1243 static bool CheckIfIndustryIsAllowed(TileIndex tile, int type, const Town *t) |
|
1244 { |
|
1245 if (type == IT_BANK_TEMP && t->population < 1200) { |
|
1246 _error_message = STR_029D_CAN_ONLY_BE_BUILT_IN_TOWNS; |
|
1247 return false; |
|
1248 } |
|
1249 |
|
1250 if (type == IT_TOY_SHOP && DistanceMax(t->xy, tile) > 9) { |
|
1251 _error_message = STR_0239_SITE_UNSUITABLE; |
|
1252 return false; |
|
1253 } |
|
1254 |
|
1255 return true; |
|
1256 } |
|
1257 |
|
1258 static bool CheckCanTerraformSurroundingTiles(TileIndex tile, uint height, int internal) |
|
1259 { |
|
1260 int size_x, size_y; |
|
1261 uint curh; |
|
1262 |
|
1263 size_x = 2; |
|
1264 size_y = 2; |
|
1265 |
|
1266 /* Check if we don't leave the map */ |
|
1267 if (TileX(tile) == 0 || TileY(tile) == 0 || GetTileType(tile) == MP_VOID) return false; |
|
1268 |
|
1269 tile += TileDiffXY(-1, -1); |
|
1270 BEGIN_TILE_LOOP(tile_walk, size_x, size_y, tile) { |
|
1271 curh = TileHeight(tile_walk); |
|
1272 /* Is the tile clear? */ |
|
1273 if ((GetTileType(tile_walk) != MP_CLEAR) && (GetTileType(tile_walk) != MP_TREES)) |
|
1274 return false; |
|
1275 |
|
1276 /* Don't allow too big of a change if this is the sub-tile check */ |
|
1277 if (internal != 0 && myabs(curh - height) > 1) return false; |
|
1278 |
|
1279 /* Different height, so the surrounding tiles of this tile |
|
1280 * has to be correct too (in level, or almost in level) |
|
1281 * else you get a chain-reaction of terraforming. */ |
|
1282 if (internal == 0 && curh != height) { |
|
1283 if (!CheckCanTerraformSurroundingTiles(tile_walk + TileDiffXY(-1, -1), height, internal + 1)) |
|
1284 return false; |
|
1285 } |
|
1286 } END_TILE_LOOP(tile_walk, size_x, size_y, tile); |
|
1287 |
|
1288 return true; |
|
1289 } |
|
1290 |
|
1291 /** |
|
1292 * This function tries to flatten out the land below an industry, without |
|
1293 * damaging the surroundings too much. |
|
1294 */ |
|
1295 static bool CheckIfCanLevelIndustryPlatform(TileIndex tile, uint32 flags, const IndustryTileTable* it, int type) |
|
1296 { |
|
1297 const int MKEND = -0x80; // used for last element in an IndustryTileTable (see build_industry.h) |
|
1298 int max_x = 0; |
|
1299 int max_y = 0; |
|
1300 TileIndex cur_tile; |
|
1301 uint size_x, size_y; |
|
1302 uint h, curh; |
|
1303 |
|
1304 /* Finds dimensions of largest variant of this industry */ |
|
1305 do { |
|
1306 if (it->ti.x > max_x) max_x = it->ti.x; |
|
1307 if (it->ti.y > max_y) max_y = it->ti.y; |
|
1308 } while ((++it)->ti.x != MKEND); |
|
1309 |
|
1310 /* Remember level height */ |
|
1311 h = TileHeight(tile); |
|
1312 |
|
1313 /* Check that all tiles in area and surrounding are clear |
|
1314 * this determines that there are no obstructing items */ |
|
1315 cur_tile = tile + TileDiffXY(-1, -1); |
|
1316 size_x = max_x + 4; |
|
1317 size_y = max_y + 4; |
|
1318 |
|
1319 /* Check if we don't leave the map */ |
|
1320 if (TileX(cur_tile) == 0 || TileY(cur_tile) == 0 || GetTileType(cur_tile) == MP_VOID) return false; |
|
1321 |
|
1322 BEGIN_TILE_LOOP(tile_walk, size_x, size_y, cur_tile) { |
|
1323 curh = TileHeight(tile_walk); |
|
1324 if (curh != h) { |
|
1325 /* This tile needs terraforming. Check if we can do that without |
|
1326 * damaging the surroundings too much. */ |
|
1327 if (!CheckCanTerraformSurroundingTiles(tile_walk, h, 0)) return false; |
|
1328 /* This is not 100% correct check, but the best we can do without modifying the map. |
|
1329 * What is missing, is if the difference in height is more than 1.. */ |
|
1330 if (CmdFailed(DoCommand(tile_walk, 8, (curh > h) ? 0 : 1, flags & ~DC_EXEC, CMD_TERRAFORM_LAND))) return false; |
|
1331 } |
|
1332 } END_TILE_LOOP(tile_walk, size_x, size_y, cur_tile) |
|
1333 |
|
1334 if (flags & DC_EXEC) { |
|
1335 /* Terraform the land under the industry */ |
|
1336 BEGIN_TILE_LOOP(tile_walk, size_x, size_y, cur_tile) { |
|
1337 curh = TileHeight(tile_walk); |
|
1338 while (curh != h) { |
|
1339 /* We give the terraforming for free here, because we can't calculate |
|
1340 * exact cost in the test-round, and as we all know, that will cause |
|
1341 * a nice assert if they don't match ;) */ |
|
1342 DoCommand(tile_walk, 8, (curh > h) ? 0 : 1, flags, CMD_TERRAFORM_LAND); |
|
1343 curh += (curh > h) ? -1 : 1; |
|
1344 } |
|
1345 } END_TILE_LOOP(tile_walk, size_x, size_y, cur_tile) |
|
1346 } |
|
1347 |
|
1348 return true; |
|
1349 } |
|
1350 |
1237 |
1351 |
1238 static bool CheckIfTooCloseToIndustry(TileIndex tile, int type) |
1352 static bool CheckIfTooCloseToIndustry(TileIndex tile, int type) |
1239 { |
1353 { |
1240 const IndustrySpec *indspec = GetIndustrySpec(type); |
1354 const IndustrySpec *indspec = GetIndustrySpec(type); |
1241 const Industry *i; |
1355 const Industry *i; |
1371 } |
1485 } |
1372 _industry_sort_dirty = true; |
1486 _industry_sort_dirty = true; |
1373 InvalidateWindow(WC_INDUSTRY_DIRECTORY, 0); |
1487 InvalidateWindow(WC_INDUSTRY_DIRECTORY, 0); |
1374 } |
1488 } |
1375 |
1489 |
|
1490 static Industry *CreateNewIndustryHelper(TileIndex tile, IndustryType type, uint32 flags, const IndustrySpec *indspec, const IndustryTileTable *it) |
|
1491 { |
|
1492 const Town *t; |
|
1493 Industry *i; |
|
1494 |
|
1495 if (!CheckIfIndustryTilesAreFree(tile, it, type)) return NULL; |
|
1496 if (_patches.land_generator == LG_TERRAGENESIS && _generating_world && !CheckIfCanLevelIndustryPlatform(tile, 0, it, type)) return NULL; |
|
1497 if (!_check_new_industry_procs[indspec->check_proc](tile)) return NULL; |
|
1498 if (!CheckIfTooCloseToIndustry(tile, type)) return NULL; |
|
1499 |
|
1500 t = CheckMultipleIndustryInTown(tile, type); |
|
1501 if (t == NULL) return NULL; |
|
1502 |
|
1503 if (!CheckIfIndustryIsAllowed(tile, type, t)) return NULL; |
|
1504 if (!CheckSuitableIndustryPos(tile)) return NULL; |
|
1505 |
|
1506 i = AllocateIndustry(); |
|
1507 if (i == NULL) return NULL; |
|
1508 |
|
1509 if (flags & DC_EXEC) { |
|
1510 CheckIfCanLevelIndustryPlatform(tile, DC_EXEC, it, type); |
|
1511 DoCreateNewIndustry(i, tile, type, it, t, OWNER_NONE); |
|
1512 } |
|
1513 |
|
1514 return i; |
|
1515 } |
|
1516 |
1376 /** Build/Fund an industry |
1517 /** Build/Fund an industry |
1377 * @param tile tile where industry is built |
1518 * @param tile tile where industry is built |
1378 * @param p1 industry type @see build_industry.h and @see industry.h |
1519 * @param p1 industry type @see build_industry.h and @see industry.h |
1379 * @param p2 unused |
1520 * @param p2 unused |
1380 */ |
1521 */ |
1381 int32 CmdBuildIndustry(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1522 int32 CmdBuildIndustry(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
1382 { |
1523 { |
1383 const Town *t; |
|
1384 Industry *i; |
|
1385 int num; |
1524 int num; |
1386 const IndustryTileTable * const *itt; |
1525 const IndustryTileTable * const *itt; |
1387 const IndustryTileTable *it; |
1526 const IndustryTileTable *it; |
1388 const IndustrySpec *indspec; |
1527 const IndustrySpec *indspec; |
1389 |
1528 |
1390 SET_EXPENSES_TYPE(EXPENSES_OTHER); |
1529 SET_EXPENSES_TYPE(EXPENSES_OTHER); |
1391 |
|
1392 if (!CheckSuitableIndustryPos(tile)) return CMD_ERROR; |
|
1393 |
1530 |
1394 /* Check if the to-be built/founded industry is available for this climate. |
1531 /* Check if the to-be built/founded industry is available for this climate. |
1395 * Unfortunately we have no easy way of checking, except for looping the table */ |
1532 * Unfortunately we have no easy way of checking, except for looping the table */ |
1396 { |
1533 { |
1397 const byte *i; |
1534 const byte *i; |
1416 indspec->accepts_cargo[2] == CT_INVALID && |
1553 indspec->accepts_cargo[2] == CT_INVALID && |
1417 p1 != IT_LUMBER_MILL) { |
1554 p1 != IT_LUMBER_MILL) { |
1418 return CMD_ERROR; |
1555 return CMD_ERROR; |
1419 } |
1556 } |
1420 |
1557 |
1421 if (!_check_new_industry_procs[indspec->check_proc](tile)) return CMD_ERROR; |
|
1422 |
|
1423 t = CheckMultipleIndustryInTown(tile, p1); |
|
1424 if (t == NULL) return CMD_ERROR; |
|
1425 |
|
1426 num = indspec->num_table; |
1558 num = indspec->num_table; |
1427 itt = indspec->table; |
1559 itt = indspec->table; |
1428 |
1560 |
1429 do { |
1561 do { |
1430 if (--num < 0) return_cmd_error(STR_0239_SITE_UNSUITABLE); |
1562 if (--num < 0) return_cmd_error(STR_0239_SITE_UNSUITABLE); |
1431 } while (!CheckIfIndustryTilesAreFree(tile, it = itt[num], p1, t)); |
1563 } while (!CheckIfIndustryTilesAreFree(tile, it = itt[num], p1)); |
1432 |
1564 |
1433 |
1565 if (CreateNewIndustryHelper(tile, p1, flags, indspec, it) == NULL) return CMD_ERROR; |
1434 if (!CheckIfTooCloseToIndustry(tile, p1)) return CMD_ERROR; |
|
1435 |
|
1436 i = AllocateIndustry(); |
|
1437 if (i == NULL) return CMD_ERROR; |
|
1438 |
|
1439 if (flags & DC_EXEC) DoCreateNewIndustry(i, tile, p1, it, t, OWNER_NONE); |
|
1440 |
1566 |
1441 return (_price.build_industry >> 5) * indspec->cost_multiplier; |
1567 return (_price.build_industry >> 5) * indspec->cost_multiplier; |
1442 } |
1568 } |
1443 |
1569 |
1444 |
1570 |
1445 Industry *CreateNewIndustry(TileIndex tile, IndustryType type) |
1571 Industry *CreateNewIndustry(TileIndex tile, IndustryType type) |
1446 { |
1572 { |
1447 const Town *t; |
1573 const IndustrySpec *indspec = GetIndustrySpec(type); |
1448 const IndustryTileTable *it; |
1574 const IndustryTileTable *it = indspec->table[RandomRange(indspec->num_table)]; |
1449 Industry *i; |
1575 |
1450 |
1576 return CreateNewIndustryHelper(tile, type, DC_EXEC, indspec, it); |
1451 const IndustrySpec *indspec; |
|
1452 |
|
1453 if (!CheckSuitableIndustryPos(tile)) return NULL; |
|
1454 |
|
1455 indspec = GetIndustrySpec(type); |
|
1456 |
|
1457 if (!_check_new_industry_procs[indspec->check_proc](tile)) return NULL; |
|
1458 |
|
1459 t = CheckMultipleIndustryInTown(tile, type); |
|
1460 if (t == NULL) return NULL; |
|
1461 |
|
1462 /* pick a random layout */ |
|
1463 it = indspec->table[RandomRange(indspec->num_table)]; |
|
1464 |
|
1465 if (!CheckIfIndustryTilesAreFree(tile, it, type, t)) return NULL; |
|
1466 if (!CheckIfTooCloseToIndustry(tile, type)) return NULL; |
|
1467 |
|
1468 i = AllocateIndustry(); |
|
1469 if (i == NULL) return NULL; |
|
1470 |
|
1471 DoCreateNewIndustry(i, tile, type, it, t, OWNER_NONE); |
|
1472 |
|
1473 return i; |
|
1474 } |
1577 } |
1475 |
1578 |
1476 static const byte _numof_industry_table[4][12] = { |
1579 static const byte _numof_industry_table[4][12] = { |
1477 // difficulty settings for number of industries |
1580 // difficulty settings for number of industries |
1478 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, //none |
1581 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, //none |
1510 } |
1615 } |
1511 |
1616 |
1512 void GenerateIndustries(void) |
1617 void GenerateIndustries(void) |
1513 { |
1618 { |
1514 const byte *b; |
1619 const byte *b; |
|
1620 uint i = 0; |
|
1621 |
|
1622 /* Find the total amount of industries */ |
|
1623 b = _industry_create_table[_opt.landscape]; |
|
1624 do { |
|
1625 int num = _numof_industry_table[_opt.diff.number_industries][b[0]]; |
|
1626 |
|
1627 if (b[1] == IT_OIL_REFINERY || b[1] == IT_OIL_RIG) { |
|
1628 /* These are always placed next to the coastline, so we scale by the perimeter instead. */ |
|
1629 num = ScaleByMapSize1D(num); |
|
1630 } else { |
|
1631 num = ScaleByMapSize(num); |
|
1632 } |
|
1633 |
|
1634 i += num; |
|
1635 } while ( (b+=2)[0] != 0); |
|
1636 SetGeneratingWorldProgress(GWP_INDUSTRY, i); |
1515 |
1637 |
1516 b = _industry_create_table[_opt.landscape]; |
1638 b = _industry_create_table[_opt.landscape]; |
1517 do { |
1639 do { |
1518 PlaceInitialIndustry(b[1], b[0]); |
1640 PlaceInitialIndustry(b[1], b[0]); |
1519 } while ( (b+=2)[0] != 0); |
1641 } while ( (b+=2)[0] != 0); |