Feature #616 » 0003-Add-MaxDistanceSq-requirement-maximum-squared-distan.patch
| ai/default/daieffects.c | ||
|---|---|---|
|   case VUT_ACTION: | ||
|   case VUT_GOOD: | ||
|   case VUT_MINCALFRAG: | ||
|   case VUT_MAX_DISTANCE_SQ: | ||
|   case VUT_COUNT: | ||
|     /* No sensible implementation possible with data available. */ | ||
|     break; | ||
| ai/default/daimilitary.c | ||
|---|---|---|
|   case VUT_TERRAINCLASS: | ||
|   case VUT_TERRFLAG: | ||
|   case VUT_TERRAINALTER: | ||
|   case VUT_MAX_DISTANCE_SQ: | ||
|   case VUT_NONE: | ||
|     return tri_req_active(context, other_context, req); | ||
|   case VUT_COUNT: | ||
| common/fc_types.h | ||
|---|---|---|
|   int min_techs; | ||
|   int min_cities; | ||
|   int latitude; | ||
|   int distance_sq; | ||
|   enum topo_flag topo_property; | ||
|   enum wrap_flag wrap_property; | ||
| common/metaknowledge.c | ||
|---|---|---|
|     } | ||
|   } | ||
|   if (req->source.kind == VUT_MAX_DISTANCE_SQ) { | ||
|     if (context->tile == nullptr || other_context->tile == nullptr) { | ||
|       /* The tiles may exist but not be passed when the problem type is | ||
|        * RPT_POSSIBLE. */ | ||
|       return prob_type == RPT_CERTAIN; | ||
|     } | ||
|     /* Tile locations and their distance are fixed */ | ||
|     return TRUE; | ||
|   } | ||
|   if (req->source.kind == VUT_ACTION | ||
|       || req->source.kind == VUT_OTYPE) { | ||
|     /* This requirement type is intended to specify the situation. */ | ||
| common/reqtext.c | ||
|---|---|---|
|     } | ||
|     break; | ||
|   case VUT_MAX_DISTANCE_SQ: | ||
|     switch (preq->range) { | ||
|     case REQ_RANGE_TILE: | ||
|       fc_strlcat(buf, prefix, bufsz); | ||
|       /* Test some special cases */ | ||
|       switch (preq->source.value.distance_sq) | ||
|       { | ||
|       case 0: | ||
|         if (preq->present) { | ||
|           fc_strlcat(buf, _("Must be the same tile."), bufsz); | ||
|         } else { | ||
|           fc_strlcat(buf, _("Must not be the same tile."), bufsz); | ||
|         } | ||
|         break; | ||
|       case 1: | ||
|         if (preq->present) { | ||
|           fc_strlcat(buf, _("Must be cardinally adjacent."), bufsz); | ||
|         } else { | ||
|           fc_strlcat(buf, _("Must not be cardinally adjacent."), bufsz); | ||
|         } | ||
|         break; | ||
|       case 2: | ||
|       case 3: | ||
|         if (preq->present) { | ||
|           fc_strlcat(buf, _("Must be adjacent."), bufsz); | ||
|         } else { | ||
|           fc_strlcat(buf, _("Must not be adjacent."), bufsz); | ||
|         } | ||
|         break; | ||
|       default: | ||
|         if (preq->present) { | ||
|           cat_snprintf(buf, bufsz, | ||
|                       _("The squared distance between the tiles " | ||
|                         "must be at most %d."), | ||
|                       preq->source.value.distance_sq); | ||
|         } else { | ||
|           cat_snprintf(buf, bufsz, | ||
|                       _("The squared distance between the tiles " | ||
|                         "must be at least %d."), | ||
|                       preq->source.value.distance_sq + 1); | ||
|         } | ||
|         break; | ||
|       } | ||
|       return TRUE; | ||
|     case REQ_RANGE_CADJACENT: | ||
|     case REQ_RANGE_ADJACENT: | ||
|     case REQ_RANGE_CITY: | ||
|     case REQ_RANGE_TRADE_ROUTE: | ||
|     case REQ_RANGE_CONTINENT: | ||
|     case REQ_RANGE_PLAYER: | ||
|     case REQ_RANGE_TEAM: | ||
|     case REQ_RANGE_ALLIANCE: | ||
|     case REQ_RANGE_WORLD: | ||
|     case REQ_RANGE_LOCAL: | ||
|     case REQ_RANGE_COUNT: | ||
|       /* Not supported. */ | ||
|       break; | ||
|     } | ||
|     break; | ||
|   case VUT_COUNT: | ||
|     break; | ||
|   } | ||
| common/requirements.c | ||
|---|---|---|
|       return; | ||
|    } | ||
|    break; | ||
|   case VUT_MAX_DISTANCE_SQ: | ||
|     source->value.distance_sq = atoi(value); | ||
|     if (0 <= source->value.distance_sq) { | ||
|       return; | ||
|     } | ||
|     break; | ||
|   case VUT_COUNT: | ||
|     break; | ||
|   } | ||
| ... | ... | |
|   case VUT_MAXLATITUDE: | ||
|     source.value.latitude = value; | ||
|     return source; | ||
|   case VUT_MAX_DISTANCE_SQ: | ||
|     source.value.distance_sq = value; | ||
|     return source; | ||
|   case VUT_COUNT: | ||
|     break; | ||
|   } | ||
| ... | ... | |
|   case VUT_MINLATITUDE: | ||
|   case VUT_MAXLATITUDE: | ||
|     return source->value.latitude; | ||
|   case VUT_MAX_DISTANCE_SQ: | ||
|     return source->value.distance_sq; | ||
|   case VUT_COUNT: | ||
|     break; | ||
|   } | ||
| ... | ... | |
|       case VUT_MAXTILEUNITS: | ||
|       case VUT_MINLATITUDE: | ||
|       case VUT_MAXLATITUDE: | ||
|       case VUT_MAX_DISTANCE_SQ: | ||
|         req.range = REQ_RANGE_TILE; | ||
|         break; | ||
|       case VUT_COUNTER: | ||
| ... | ... | |
|                  && req.range != REQ_RANGE_ADJACENT); | ||
|       break; | ||
|     case VUT_TERRAINALTER: /* XXX could in principle support C/ADJACENT */ | ||
|     case VUT_MAX_DISTANCE_SQ: | ||
|       invalid = (req.range != REQ_RANGE_TILE); | ||
|       break; | ||
|     case VUT_CITYTILE: | ||
| ... | ... | |
|     case VUT_MINCITIES: | ||
|     case VUT_MINLATITUDE: | ||
|     case VUT_MAXLATITUDE: | ||
|     case VUT_MAX_DISTANCE_SQ: | ||
|       /* Most requirements don't support 'survives'. */ | ||
|       invalid = survives; | ||
|       break; | ||
| ... | ... | |
|   return are_requirements_contradictions(req1, &nreq2); | ||
| } | ||
| /**********************************************************************//** | ||
|   Returns TRUE iff two bounds that could each be either an upper or lower | ||
|   bound are contradicting each other. This function assumes that of the | ||
|   upper and lower bounds, one will be inclusive, the other exclusive. | ||
| **************************************************************************/ | ||
| static inline bool are_bounds_contradictions(int bound1, bool is_upper1, | ||
|                                              int bound2, bool is_upper2) | ||
| { | ||
|   /* If the bounds are on opposite sides, and one is inclusive, the other | ||
|    * exclusive, the number of values that satisfy both bounds is exactly | ||
|    * their difference, (upper bound) - (lower bound). | ||
|    * The bounds contradict each other iff this difference is 0 or less, | ||
|    * i.e. iff (upper bound) <= (lower bound) */ | ||
|   if (is_upper1 && !is_upper2) { | ||
|     return bound1 <= bound2; | ||
|   } else if (!is_upper1 && is_upper2) { | ||
|     return bound1 >= bound2; | ||
|   } | ||
|   /* Both are upper or both are lower ~> no contradiction possible */ | ||
|   return FALSE; | ||
| } | ||
| /**********************************************************************//** | ||
|   Returns TRUE if req1 and req2 contradicts each other. | ||
| ... | ... | |
|       /* Finding contradictions across requirement kinds aren't supported | ||
|        * for MinMoveFrags requirements. */ | ||
|       return FALSE; | ||
|     } else if (req1->present == req2->present) { | ||
|       /* No contradiction possible. */ | ||
|       return FALSE; | ||
|     } else { | ||
|       /* Number of move fragments left can't be larger than the number | ||
|        * required to be present and smaller than the number required to not | ||
|        * be present when the number required to be present is smaller than | ||
|        * the number required to not be present. */ | ||
|       if (req1->present) { | ||
|         return req1->source.value.minmoves >= req2->source.value.minmoves; | ||
|       } else { | ||
|         return req1->source.value.minmoves <= req2->source.value.minmoves; | ||
|       } | ||
|     } | ||
|     break; | ||
|     return are_bounds_contradictions( | ||
|         req1->source.value.minmoves, !req1->present, | ||
|         req2->source.value.minmoves, !req2->present); | ||
|   case VUT_MINLATITUDE: | ||
|   case VUT_MAXLATITUDE: | ||
|     if (req2->source.kind != VUT_MINLATITUDE | ||
| ... | ... | |
|     } | ||
|     return FALSE; | ||
|   case VUT_MAX_DISTANCE_SQ: | ||
|     if (req2->source.kind != VUT_MAX_DISTANCE_SQ) { | ||
|       /* Finding contradictions across requirement kinds isn't supported | ||
|        * for MaxDistanceSq requirements. */ | ||
|       return FALSE; | ||
|     } | ||
|     return are_bounds_contradictions( | ||
|         req1->source.value.distance_sq, req1->present, | ||
|         req2->source.value.distance_sq, req2->present); | ||
|   default: | ||
|     /* No special knowledge exists. The requirements aren't the exact | ||
|      * opposite of each other per the initial check. */ | ||
| ... | ... | |
| #define IS_REQ_ACTIVE_VARIANT_ASSERT(_kind)                \ | ||
| {                                                          \ | ||
|   fc_assert_ret_val(req != NULL, TRI_MAYBE);               \ | ||
|   fc_assert_ret_val(req != nullptr, TRI_MAYBE);            \ | ||
|   fc_assert_ret_val(req->source.kind == _kind, TRI_MAYBE); \ | ||
|   fc_assert(context != NULL);                              \ | ||
|   fc_assert(context != nullptr);                           \ | ||
|   fc_assert(other_context != nullptr);                     \ | ||
| } | ||
| /**********************************************************************//** | ||
| ... | ... | |
|   return TRI_MAYBE; | ||
| } | ||
| /**********************************************************************//** | ||
|   Determine whether a maximum squared distance 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 squared distance requirement | ||
| **************************************************************************/ | ||
| static enum fc_tristate | ||
| is_max_distance_sq_req_active(const struct civ_map *nmap, | ||
|                               const struct req_context *context, | ||
|                               const struct req_context *other_context, | ||
|                               const struct requirement *req) | ||
| { | ||
|   IS_REQ_ACTIVE_VARIANT_ASSERT(VUT_MAX_DISTANCE_SQ); | ||
|   switch (req->range) { | ||
|   case REQ_RANGE_TILE: | ||
|     if (context->tile == nullptr || other_context->tile == nullptr) { | ||
|       return TRI_MAYBE; | ||
|     } | ||
|     return BOOL_TO_TRISTATE( | ||
|       sq_map_distance(context->tile, other_context->tile) | ||
|       <= req->source.value.distance_sq | ||
|     ); | ||
|   default: | ||
|     break; | ||
|   } | ||
|   fc_assert_msg(FALSE, | ||
|                 "Illegal range %d for max squared distance requirement.", | ||
|                 req->range); | ||
|   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_IMPR_FLAG] = {is_buildingflag_req_active, REQUCH_YES}, | ||
|   [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_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_TERRFLAG: | ||
|   case VUT_TERRAINALTER: | ||
|   case VUT_MINYEAR: | ||
|   case VUT_MAX_DISTANCE_SQ: | ||
|   case VUT_NONE: | ||
|   case VUT_COUNT: | ||
|     /* Not implemented. */ | ||
| ... | ... | |
|   case VUT_MINLATITUDE: | ||
|   case VUT_MAXLATITUDE: | ||
|     return psource1->value.latitude == psource2->value.latitude; | ||
|   case VUT_MAX_DISTANCE_SQ: | ||
|     return psource1->value.distance_sq == psource2->value.distance_sq; | ||
|   case VUT_COUNT: | ||
|     break; | ||
|   } | ||
| ... | ... | |
|   case VUT_MAXLATITUDE: | ||
|     fc_snprintf(buffer, sizeof(buffer), "%d", psource->value.latitude); | ||
|     return buffer; | ||
|   case VUT_MAX_DISTANCE_SQ: | ||
|     fc_snprintf(buffer, sizeof(buffer), "%d", psource->value.distance_sq); | ||
|     return buffer; | ||
|   case VUT_COUNT: | ||
|     break; | ||
| ... | ... | |
|     cat_snprintf(buf, bufsz, _("Latitude <= %d"), | ||
|                  psource->value.latitude); | ||
|     return buf; | ||
|   case VUT_MAX_DISTANCE_SQ: | ||
|     /* TRANS: here <= means 'less than or equal'. */ | ||
|     cat_snprintf(buf, bufsz, _("Squared distance <= %d"), | ||
|                  psource->value.distance_sq); | ||
|     return buf; | ||
|   case VUT_COUNT: | ||
|     break; | ||
|   } | ||
| doc/README.actions | ||
|---|---|---|
|    target requirement vector to the actor requirement vector. | ||
|  * Asymmetric local DiplRel requirements must test for the same thing in | ||
|    the opposite direction. Example: "Hosts embassy" -> "Has embassy" | ||
| A "MaxDistanceSq" requirement with the range "Tile" should always be put in | ||
| the actor requirements, for the same reasons. | ||
| Actions and Lua | ||
| =============== | ||
| doc/README.effects | ||
|---|---|---|
| MinMoveFrags:    Local | ||
| MinVeteran:      Local | ||
| MinHitPoints:    Local | ||
| MaxDistanceSq:   Tile | ||
| MinSize is the minimum size of a city required. | ||
| ... | ... | |
|  is a port, it's a tile of the nearby ocean but not of its continent). | ||
| MinLatitude and MaxLatitude are numbers from -1000 (south pole) to 1000 | ||
|  (north pole). | ||
| MaxDistanceSq is about the (squared) distance between two tiles; currently | ||
|  only available for action enablers (see also README.actions) and a select | ||
|  few effects. | ||
| CityStatus is "OwnedByOriginal", "Transferred", "Starved", | ||
|  "Disorder", or "Celebration" | ||
|  The difference between "OwnedByOriginal" and "Transferred" is that | ||
| gen_headers/enums/fc_types_enums.def | ||
|---|---|---|
|   IMPR_GENUS         "BuildingGenus" | ||
|   MAXLATITUDE        "MaxLatitude" | ||
|   MAXTILEUNITS       "MaxUnitsOnTile" | ||
|   MAX_DISTANCE_SQ    "MaxDistanceSq" | ||
|   MINCALFRAG         "MinCalFrag" | ||
|   MINCITIES          "MinCities" | ||
|   MINCULTURE         "MinCulture" | ||
| server/cityturn.c | ||
|---|---|---|
|       case VUT_ACTION: | ||
|       case VUT_OTYPE: | ||
|       case VUT_SPECIALIST: | ||
|       case VUT_MAX_DISTANCE_SQ: | ||
|       case VUT_TERRAINALTER: /* XXX could do this in principle */ | ||
|         /* Will only happen with a bogus ruleset. */ | ||
|         log_error("worklist_change_build_target() has bogus preq"); | ||
| server/ruleset/rssanity.c | ||
|---|---|---|
|     case VUT_IMPR_GENUS: | ||
|     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 */ | ||
|       /* There can be only one requirement of these types (with current | ||
|        * range limitations) | ||
|        * Requirements might be identical, but we consider multiple | ||
| ... | ... | |
|                         req_to_fstring(preq, &astr)); | ||
|           astr_free(&astr); | ||
|           ok = FALSE; | ||
|         } else if (preq->source.kind == VUT_MAX_DISTANCE_SQ | ||
|                    && preq->range == REQ_RANGE_TILE) { | ||
|           struct astring astr; | ||
|           /* A Tile-ranged MaxDistanceSq requirement can be expressed as a | ||
|            * requirement in actor_reqs. Demand that it is there. */ | ||
|           ruleset_error(logger, LOG_ERROR, | ||
|                         _("Action enabler for %s has a tile MaxDistanceSq " | ||
|                           "requirement %s in target_reqs! Please read the " | ||
|                           "section \"Requirement vector rules\" in " | ||
|                           "doc/README.actions"), | ||
|                         action_id_rule_name(act), | ||
|                         req_to_fstring(preq, &astr)); | ||
|           astr_free(&astr); | ||
|           ok = FALSE; | ||
|         } | ||
|       } requirement_vector_iterate_end; | ||
| tools/ruledit/univ_value.c | ||
|---|---|---|
|   case VUT_MAXLATITUDE: | ||
|     src->value.latitude = 0; | ||
|     return TRUE; | ||
|   case VUT_MAX_DISTANCE_SQ: | ||
|     src->value.distance_sq = 0; | ||
|     return TRUE; | ||
|   case VUT_COUNT: | ||
|     fc_assert(src->kind != VUT_COUNT); | ||
|     return FALSE; | ||
| ... | ... | |
|   case VUT_MINCITIES: | ||
|   case VUT_MINLATITUDE: | ||
|   case VUT_MAXLATITUDE: | ||
|   case VUT_MAX_DISTANCE_SQ: | ||
|     /* Requirement types having numerical value */ | ||
|     cb(nullptr, FALSE, data); | ||
|     break; | ||
- « Previous
- 1
- 2
- 3
- Next »