Bug #1564 » 3_4-airlift_possible_corr1.patch
| common/movement.c | ||
|---|---|---|
|   return is_native_tile(utype, ptile); | ||
| } | ||
| /************************************************************************//** | ||
|   Return if a unit of utype could possibly "exist" at the city tile of pcity | ||
|   given the information known to pov_player. pcity is presumed to exist. | ||
|   nmap is supposed to be client map. | ||
|   This means it can physically be present on the tile (without the use of a | ||
|   transporter). See can_exist_at_tile() for the omniscient check. | ||
| ****************************************************************************/ | ||
| bool could_exist_in_city(const struct civ_map *nmap, | ||
|                          const struct player *pov_player, | ||
|                          const struct unit_type *utype, | ||
|                          const struct city *pcity) | ||
| { | ||
|   struct unit_class *uclass; | ||
|   struct tile *ctile; | ||
|   fc_assert_ret_val(nullptr != pcity && nullptr != utype, FALSE); | ||
|   ctile = city_tile(pcity); | ||
|   uclass = utype_class(utype); | ||
|   if (uclass_has_flag(uclass, UCF_BUILD_ANYWHERE)) { | ||
|     /* If the city stands, it can exist there */ | ||
|     return TRUE; | ||
|   } | ||
|   adjc_iterate(nmap, ctile, ptile) { | ||
|     if (!tile_is_seen(ptile, pov_player) | ||
|         || is_native_tile_to_class(uclass, ptile)) { | ||
|       /* Could be native. This ignores a rare case when we don't see | ||
|        * only the city center and any native terrain is NoCities */ | ||
|       return TRUE; | ||
|     } | ||
|   } adjc_iterate_end; | ||
|   if (1 == game.info.citymindist | ||
|       && is_city_channel_tile(nmap, uclass, ctile, nullptr)) { | ||
|     /* FIXME: false negative results for city channels might appear */ | ||
|     /* Channeled. */ | ||
|     return TRUE; | ||
|   } | ||
|   /* It definitely can't exist there */ | ||
|   return FALSE; | ||
| } | ||
| /************************************************************************//** | ||
|   Return TRUE iff the unit can "exist" at this location.  This means it can | ||
|   physically be present on the tile (without the use of a transporter).  See | ||
| common/movement.h | ||
|---|---|---|
| bool can_exist_at_tile(const struct civ_map *nmap, | ||
|                        const struct unit_type *utype, | ||
|                        const struct tile *ptile); | ||
| bool could_exist_in_city(const struct civ_map *nmap, | ||
|                          const struct player *pov_player, | ||
|                          const struct unit_type *utype, | ||
|                          const struct city *pcity); | ||
| bool can_unit_exist_at_tile(const struct civ_map *nmap, | ||
|                             const struct unit *punit, const struct tile *ptile); | ||
| bool can_unit_survive_at_tile(const struct civ_map *nmap, | ||
| common/unit.c | ||
|---|---|---|
| { | ||
|   const struct city *psrc_city = tile_city(unit_tile(punit)); | ||
|   const struct player *punit_owner; | ||
|   const struct tile *dst_tile = nullptr; | ||
|   const struct unit_type *putype = unit_type_get(punit); | ||
|   bool flagless = utype_has_flag(putype, UTYF_FLAGLESS); | ||
|   enum unit_airlift_result ok_result = AR_OK; | ||
|   if (0 == punit->moves_left | ||
|       && !utype_may_act_move_frags(unit_type_get(punit), | ||
|                                    ACTION_AIRLIFT, 0)) { | ||
|       && !utype_may_act_move_frags(putype, ACTION_AIRLIFT, 0)) { | ||
|     /* No moves left. */ | ||
|     return AR_NO_MOVES; | ||
|   } | ||
| ... | ... | |
|     return AR_OCCUPIED; | ||
|   } | ||
|   if (NULL == psrc_city) { | ||
|   if (nullptr == psrc_city) { | ||
|     /* No city there. */ | ||
|     return AR_NOT_IN_CITY; | ||
|   } | ||
| ... | ... | |
|     return AR_BAD_DST_CITY; | ||
|   } | ||
|   if (pdest_city | ||
|       && (NULL == restriction | ||
|           || (tile_get_known(city_tile(pdest_city), restriction) | ||
|               == TILE_KNOWN_SEEN)) | ||
|       && !can_unit_exist_at_tile(nmap, punit, city_tile(pdest_city))) { | ||
|     /* Can't exist at the destination tile. */ | ||
|     return AR_BAD_DST_CITY; | ||
|   if (nullptr != pdest_city) { | ||
|     dst_tile = city_tile(pdest_city); | ||
|     if (nullptr != restriction | ||
|         ? !can_exist_at_tile(nmap, putype, dst_tile) | ||
|         : !could_exist_in_city(nmap, restriction, putype, pdest_city)) { | ||
|       /* Can't exist at the destination tile. */ | ||
|       return AR_BAD_DST_CITY; | ||
|     } | ||
|   } | ||
|   punit_owner = unit_owner(punit); | ||
| ... | ... | |
|     return AR_BAD_SRC_CITY; | ||
|   } | ||
|   if (pdest_city | ||
|       && punit_owner != city_owner(pdest_city) | ||
|       && !(game.info.airlifting_style & AIRLIFTING_ALLIED_DEST | ||
|            && pplayers_allied(punit_owner, city_owner(pdest_city)))) { | ||
|     /* Not allowed to airlift to this destination. */ | ||
|     return AR_BAD_DST_CITY; | ||
|   /* Check diplomatic possibility of the destination */ | ||
|   if (nullptr != pdest_city) { | ||
|     if (punit_owner != city_owner(pdest_city)) { | ||
|       if (!(game.info.airlifting_style & AIRLIFTING_ALLIED_DEST | ||
|             && pplayers_allied(punit_owner, city_owner(pdest_city))) | ||
|           || flagless || is_non_allied_unit_tile(dst_tile, punit_owner, FALSE)) { | ||
|         /* Not allowed to airlift to this destination. */ | ||
|         return AR_BAD_DST_CITY; | ||
|       } | ||
|     } else if (flagless | ||
|                && is_non_allied_unit_tile(dst_tile, punit_owner, TRUE)) { | ||
|       /* Foreign units block airlifting to this destination */ | ||
|       return AR_BAD_DST_CITY; | ||
|     } | ||
|   } | ||
|   if (NULL == restriction || city_owner(psrc_city) == restriction) { | ||
|     /* We know for sure whether or not src can airlift this turn. */ | ||
|     if (0 >= psrc_city->airlift | ||
|         && (!(game.info.airlifting_style & AIRLIFTING_UNLIMITED_SRC) | ||
|             || !game.info.airlift_from_always_enabled)) { | ||
|       /* The source cannot airlift for this turn (maybe already airlifted | ||
|        * or no airport). | ||
|        * See also do_airline() in server/unittools.h. */ | ||
|       return AR_SRC_NO_FLIGHTS; | ||
|     } /* else, there is capacity; continue to other checks */ | ||
|   } else { | ||
|     /* We don't have access to the 'airlift' field. Assume it's OK; can | ||
|      * only find out for sure by trying it. */ | ||
|     ok_result = AR_OK_SRC_UNKNOWN; | ||
|   /* Check airlift capacities */ | ||
|   if (!game.info.airlift_from_always_enabled) { | ||
|     if (nullptr == restriction || city_owner(psrc_city) == restriction) { | ||
|       /* We know for sure whether or not src can airlift this turn. */ | ||
|       if (0 >= psrc_city->airlift | ||
|           && !(game.info.airlifting_style & AIRLIFTING_UNLIMITED_SRC)) { | ||
|         /* The source cannot airlift for this turn (maybe already airlifted | ||
|          * or no airport). | ||
|          * See also do_airline() in server/unittools.h. */ | ||
|         return AR_SRC_NO_FLIGHTS; | ||
|       } /* else, there is capacity; continue to other checks */ | ||
|     } else { | ||
|       /* We don't have access to the 'airlift' field. Assume it's OK; can | ||
|        * only find out for sure by trying it. */ | ||
|       ok_result = AR_OK_SRC_UNKNOWN; | ||
|     } | ||
|   } | ||
|   if (pdest_city) { | ||
|     if (NULL == restriction || city_owner(pdest_city) == restriction) { | ||
|   if (nullptr != pdest_city && !game.info.airlift_to_always_enabled) { | ||
|     if (nullptr == restriction || city_owner(pdest_city) == restriction) { | ||
|       if (0 >= pdest_city->airlift | ||
|           && (!(game.info.airlifting_style & AIRLIFTING_UNLIMITED_DEST) | ||
|               || !game.info.airlift_to_always_enabled)) { | ||
|           && !(game.info.airlifting_style & AIRLIFTING_UNLIMITED_DEST)) { | ||
|         /* The destination cannot support airlifted units for this turn | ||
|          * (maybe already airlifted or no airport). | ||
|          * See also do_airline() in server/unittools.h. */ | ||
| server/unittools.c | ||
|---|---|---|
| /**********************************************************************//** | ||
|   Moves a unit. No checks whatsoever! This is meant as a practical | ||
|   function for other functions, like do_airline(), which do the checking | ||
|   themselves. | ||
|   either by themselves or by their callers | ||
|   If you move a unit you should always use this function, as it also sets | ||
|   the transport status of the unit correctly. Note that the source tile (the | ||