Feature #629 » 0005-Add-MaxRegionTiles-continent-size-requirement-type.patch
| ai/default/daieffects.c | ||
|---|---|---|
|   case VUT_GOOD: | ||
|   case VUT_MINCALFRAG: | ||
|   case VUT_MAX_DISTANCE_SQ: | ||
|   case VUT_MAX_REGION_TILES: | ||
|   case VUT_COUNT: | ||
|     /* No sensible implementation possible with data available. */ | ||
|     break; | ||
| ai/default/daimilitary.c | ||
|---|---|---|
|   case VUT_TERRFLAG: | ||
|   case VUT_TERRAINALTER: | ||
|   case VUT_MAX_DISTANCE_SQ: | ||
|   case VUT_MAX_REGION_TILES: | ||
|   case VUT_NONE: | ||
|     return tri_req_active(context, other_context, req); | ||
|   case VUT_COUNT: | ||
| common/fc_types.h | ||
|---|---|---|
|   int min_cities; | ||
|   int latitude; | ||
|   int distance_sq; | ||
|   int region_tiles; | ||
|   enum topo_flag topo_property; | ||
|   enum wrap_flag wrap_property; | ||
| common/reqtext.c | ||
|---|---|---|
|     } | ||
|     break; | ||
|   case VUT_MAX_REGION_TILES: | ||
|     switch (preq->range) { | ||
|     case REQ_RANGE_CONTINENT: | ||
|       fc_strlcat(buf, prefix, bufsz); | ||
|       if (preq->present) { | ||
|         cat_snprintf(buf, bufsz, | ||
|                     _("Requires a continent or ocean size of at most %d."), | ||
|                     preq->source.value.region_tiles); | ||
|       } else { | ||
|         cat_snprintf(buf, bufsz, | ||
|                     _("Requires a continent or ocean size of at least %d."), | ||
|                     preq->source.value.region_tiles + 1); | ||
|       } | ||
|       return TRUE; | ||
|     case REQ_RANGE_PLAYER: | ||
|     case REQ_RANGE_TEAM: | ||
|     case REQ_RANGE_ALLIANCE: | ||
|     case REQ_RANGE_WORLD: | ||
|     case REQ_RANGE_LOCAL: | ||
|     case REQ_RANGE_TILE: | ||
|     case REQ_RANGE_CADJACENT: | ||
|     case REQ_RANGE_ADJACENT: | ||
|     case REQ_RANGE_CITY: | ||
|     case REQ_RANGE_TRADE_ROUTE: | ||
|     case REQ_RANGE_COUNT: | ||
|       /* Not supported. */ | ||
|       break; | ||
|     } | ||
|     break; | ||
|   case VUT_COUNT: | ||
|     break; | ||
|   } | ||
| common/requirements.c | ||
|---|---|---|
|       return; | ||
|     } | ||
|     break; | ||
|   case VUT_MAX_REGION_TILES: | ||
|     source->value.region_tiles = atoi(value); | ||
|     if (0 < source->value.region_tiles) { | ||
|       return; | ||
|     } | ||
|     break; | ||
|   case VUT_COUNT: | ||
|     break; | ||
|   } | ||
| ... | ... | |
|   case VUT_MAX_DISTANCE_SQ: | ||
|     source.value.distance_sq = value; | ||
|     return source; | ||
|   case VUT_MAX_REGION_TILES: | ||
|     source.value.region_tiles = value; | ||
|     return source; | ||
|   case VUT_COUNT: | ||
|     break; | ||
|   } | ||
| ... | ... | |
|     return source->value.latitude; | ||
|   case VUT_MAX_DISTANCE_SQ: | ||
|     return source->value.distance_sq; | ||
|   case VUT_MAX_REGION_TILES: | ||
|     return source->value.region_tiles; | ||
|   case VUT_COUNT: | ||
|     break; | ||
|   } | ||
| ... | ... | |
|       case VUT_SERVERSETTING: | ||
|         req.range = REQ_RANGE_WORLD; | ||
|         break; | ||
|       case VUT_MAX_REGION_TILES: | ||
|         req.range = REQ_RANGE_CONTINENT; | ||
|         break; | ||
|       } | ||
|     } | ||
| ... | ... | |
|     case VUT_PLAYER_STATE: | ||
|       invalid = (req.range != REQ_RANGE_PLAYER); | ||
|       break; | ||
|     case VUT_MAX_REGION_TILES: | ||
|       invalid = (req.range != REQ_RANGE_CONTINENT); | ||
|       break; | ||
|     case VUT_IMPROVEMENT: | ||
|       /* Valid ranges depend on the building genus (wonder/improvement), | ||
|        * which might not have been loaded from the ruleset yet. | ||
| ... | ... | |
|     case VUT_MINLATITUDE: | ||
|     case VUT_MAXLATITUDE: | ||
|     case VUT_MAX_DISTANCE_SQ: | ||
|     case VUT_MAX_REGION_TILES: | ||
|       /* Most requirements don't support 'survives'. */ | ||
|       invalid = survives; | ||
|       break; | ||
| ... | ... | |
|     return are_bounds_contradictions( | ||
|         req1->source.value.distance_sq, req1->present, | ||
|         req2->source.value.distance_sq, req2->present); | ||
|   case VUT_MAX_REGION_TILES: | ||
|     if (req2->source.kind != VUT_MAX_REGION_TILES) { | ||
|       /* Finding contradictions across requirement kinds isn't supported | ||
|        * for MaxRegionTiles requirements. */ | ||
|       return FALSE; | ||
|     } | ||
|     return are_bounds_contradictions( | ||
|         req1->source.value.region_tiles, req1->present, | ||
|         req2->source.value.region_tiles, req2->present); | ||
|   default: | ||
|     /* No special knowledge exists. The requirements aren't the exact | ||
|      * opposite of each other per the initial check. */ | ||
| ... | ... | |
|   return TRI_MAYBE; | ||
| } | ||
| /**********************************************************************//** | ||
|   Determine whether a maximum tiles of same region requirement is satisfied | ||
|   in a given context, ignoring parts of the requirement that can be handled | ||
|   uniformly for all requirement types. | ||
|   context, other_context and req must not be null, | ||
|   and req must be a max region tiles requirement | ||
| **************************************************************************/ | ||
| static enum fc_tristate | ||
| is_max_region_tiles_req_active(const struct civ_map *nmap, | ||
|                                const struct req_context *context, | ||
|                                const struct req_context *other_context, | ||
|                                const struct requirement *req) | ||
| { | ||
|   int max_tiles, min_tiles = 1; | ||
|   IS_REQ_ACTIVE_VARIANT_ASSERT(VUT_MAX_REGION_TILES); | ||
|   switch (req->range) { | ||
|   case REQ_RANGE_CONTINENT: | ||
|     { | ||
|       Continent_id cont = context->tile ? tile_continent(context->tile) : 0; | ||
|       fc_assert_ret_val(cont <= nmap->num_continents, TRI_MAYBE); | ||
|       fc_assert_ret_val(-cont <= nmap->num_oceans, TRI_MAYBE); | ||
|       /* Note: We could come up with a better upper bound by subtracting | ||
|        * all other continent/ocean sizes, or all except the largest if we | ||
|        * don't know the tile. | ||
|        * We could even do a flood-fill count of the unknown area bordered | ||
|        * by known tiles of the continent. | ||
|        * Probably not worth the effort though. */ | ||
|       max_tiles = nmap->xsize * nmap->ysize; | ||
|       if (cont > 0) { | ||
|         min_tiles = nmap->continent_sizes[cont]; | ||
|         if (is_server() || (nmap->client.continent_unknown_adj_counts[cont] | ||
|                             == 0)) { | ||
|           max_tiles = min_tiles; | ||
|         } | ||
|       } else if (cont < 0) { | ||
|         min_tiles = nmap->ocean_sizes[-cont]; | ||
|         if (is_server() || (nmap->client.ocean_unknown_adj_counts[-cont] | ||
|                             == 0)) { | ||
|           max_tiles = min_tiles; | ||
|         } | ||
|       } | ||
|     } | ||
|     break; | ||
|   default: | ||
|     fc_assert_msg(FALSE, | ||
|                   "Illegal range %d for max region tiles requirement.", | ||
|                   req->range); | ||
|     return TRI_MAYBE; | ||
|   } | ||
|   if (min_tiles > req->source.value.region_tiles) { | ||
|     return TRI_NO; | ||
|   } else if (max_tiles <= req->source.value.region_tiles) { | ||
|     return TRI_YES; | ||
|   } | ||
|   return TRI_MAYBE; | ||
| } | ||
| /**********************************************************************//** | ||
|   Determine whether a minimum year requirement is satisfied in a given | ||
|   context, ignoring parts of the requirement that can be handled uniformly | ||
| ... | ... | |
|   [VUT_PLAYER_FLAG] = {is_plr_flag_req_active, REQUCH_NO}, | ||
|   [VUT_PLAYER_STATE] = {is_plr_state_req_active, REQUCH_NO}, | ||
|   [VUT_MAX_DISTANCE_SQ] = {is_max_distance_sq_req_active, REQUCH_YES}, | ||
|   [VUT_MAX_REGION_TILES] = {is_max_region_tiles_req_active, REQUCH_NO}, | ||
|   [VUT_MAXLATITUDE] = {is_latitude_req_active, REQUCH_YES}, | ||
|   [VUT_MAXTILEUNITS] = {is_maxunitsontile_req_active, REQUCH_NO}, | ||
|   [VUT_MINCALFRAG] = {is_mincalfrag_req_active, REQUCH_NO}, | ||
| ... | ... | |
|   case VUT_TERRAINALTER: | ||
|   case VUT_MINYEAR: | ||
|   case VUT_MAX_DISTANCE_SQ: | ||
|   case VUT_MAX_REGION_TILES: | ||
|   case VUT_NONE: | ||
|   case VUT_COUNT: | ||
|     /* Not implemented. */ | ||
| ... | ... | |
|     return psource1->value.latitude == psource2->value.latitude; | ||
|   case VUT_MAX_DISTANCE_SQ: | ||
|     return psource1->value.distance_sq == psource2->value.distance_sq; | ||
|   case VUT_MAX_REGION_TILES: | ||
|     return psource1->value.region_tiles == psource2->value.region_tiles; | ||
|   case VUT_COUNT: | ||
|     break; | ||
|   } | ||
| ... | ... | |
|   case VUT_MAX_DISTANCE_SQ: | ||
|     fc_snprintf(buffer, sizeof(buffer), "%d", psource->value.distance_sq); | ||
|     return buffer; | ||
|   case VUT_MAX_REGION_TILES: | ||
|     fc_snprintf(buffer, sizeof(buffer), "%d", psource->value.region_tiles); | ||
|     return buffer; | ||
|   case VUT_COUNT: | ||
|     break; | ||
| ... | ... | |
|     cat_snprintf(buf, bufsz, _("Squared distance <= %d"), | ||
|                  psource->value.distance_sq); | ||
|     return buf; | ||
|   case VUT_MAX_REGION_TILES: | ||
|     cat_snprintf(buf, bufsz, _("%d or fewer region tiles"), | ||
|                  psource->value.region_tiles); | ||
|     return buf; | ||
|   case VUT_COUNT: | ||
|     break; | ||
|   } | ||
| doc/README.effects | ||
|---|---|---|
| MinVeteran:      Local | ||
| MinHitPoints:    Local | ||
| MaxDistanceSq:   Tile | ||
| MaxRegionTiles:  Continent | ||
| MinSize is the minimum size of a city required. | ||
| ... | ... | |
| MaxDistanceSq is about the (squared) distance between two tiles; currently | ||
|  only available for action enablers (see also README.actions) and a select | ||
|  few effects. | ||
| MaxRegionTiles is continent or ocean size (number of tiles). | ||
| CityStatus is "OwnedByOriginal", "Transferred", "Starved", | ||
|  "Disorder", or "Celebration" | ||
|  The difference between "OwnedByOriginal" and "Transferred" is that | ||
| gen_headers/enums/fc_types_enums.def | ||
|---|---|---|
|   FORM_AGE           "FormAge" | ||
|   MINCITIES          "MinCities" | ||
|   MAX_DISTANCE_SQ    "MaxDistanceSq" | ||
|   MAX_REGION_TILES   "MaxRegionTiles" | ||
| end | ||
| server/cityturn.c | ||
|---|---|---|
|                                     pcity, "have_terrainflag"); | ||
|         } | ||
|         break; | ||
|       case VUT_MAX_REGION_TILES: | ||
|         /* Changing the continent size is hard; cf. VUT_TERRAINCLASS above. | ||
|          * Change this when we support less fixed ranges (e.g. city?). */ | ||
|         purge = TRUE; | ||
|         break; | ||
|       case VUT_ROADFLAG: | ||
|         if (preq->present) { | ||
|           notify_player(pplayer, city_tile(pcity), | ||
| server/ruleset/rssanity.c | ||
|---|---|---|
|     case VUT_ORIGINAL_OWNER: /* City range -> only one original owner */ | ||
|     case VUT_FORM_AGE: | ||
|     case VUT_MAX_DISTANCE_SQ: /* Breaks nothing, but has no sense either */ | ||
|     case VUT_MAX_REGION_TILES: /* Breaks nothing, but has no sense either */ | ||
|       /* There can be only one requirement of these types (with current | ||
|        * range limitations) | ||
|        * Requirements might be identical, but we consider multiple | ||
| tools/ruledit/univ_value.c | ||
|---|---|---|
|   case VUT_MAX_DISTANCE_SQ: | ||
|     src->value.distance_sq = 0; | ||
|     return TRUE; | ||
|   case VUT_MAX_REGION_TILES: | ||
|     src->value.region_tiles = 0; | ||
|     return TRUE; | ||
|   case VUT_COUNT: | ||
|     fc_assert(src->kind != VUT_COUNT); | ||
|     return FALSE; | ||
| ... | ... | |
|   case VUT_MINLATITUDE: | ||
|   case VUT_MAXLATITUDE: | ||
|   case VUT_MAX_DISTANCE_SQ: | ||
|   case VUT_MAX_REGION_TILES: | ||
|     /* Requirement types having numerical value */ | ||
|     cb(nullptr, FALSE, data); | ||
|     break; | ||