Feature #616 » 0007-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/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 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; 
   | 
||
| 
         } else if (req1->present == req2->present) { 
   | 
||
| 
           /* Both bounds are on the same side, can't contradict */ 
   | 
||
| 
           return FALSE; 
   | 
||
| 
         } 
   | 
||
| 
         /* Different bounds ~> contradiction possible. 
   | 
||
| 
          * Need (negated req value) < (actual value) <= (present req value) 
   | 
||
| 
          * to be satisfied; impossible iff (present) <= (negated). */ 
   | 
||
| 
         return req1->present 
   | 
||
| 
           ? (req1->source.value.distance_sq <= req2->source.value.distance_sq) 
   | 
||
| 
           : (req1->source.value.distance_sq >= req2->source.value.distance_sq); 
   | 
||
| 
       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 | ||
|---|---|---|
| 
       PLAYER_STATE       "PlayerState" 
   | 
||
| 
       FORM_AGE           "FormAge" 
   | 
||
| 
       MINCITIES          "MinCities" 
   | 
||
| 
       MAX_DISTANCE_SQ    "MaxDistanceSq" 
   | 
||
| 
     end 
   | 
||
| 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; 
   | 
||