From 8de924fa706e51c7cd38dc7307e724053a5f5391 Mon Sep 17 00:00:00 2001 From: Sveinung Kvilhaugsvik Date: Sat, 31 Aug 2013 20:12:02 +0000 Subject: [PATCH] Define action enablers in the rule sets. See patch #4078 [[originally from svn r23247]] --- client/packhand.c | 27 +++++++++++ common/actions.c | 16 ------- common/actions.h | 1 + common/generate_packets.py | 1 + common/packets.def | 11 ++++- data/alien/units.ruleset | 2 +- data/civ2/game.ruleset | 37 +++++++++++++++ data/civ2civ3/game.ruleset | 37 +++++++++++++++ data/civ2civ3/units.ruleset | 2 +- data/classic/game.ruleset | 37 +++++++++++++++ data/classic/units.ruleset | 2 +- data/experimental/game.ruleset | 37 +++++++++++++++ data/experimental/units.ruleset | 2 +- data/multiplayer/game.ruleset | 37 +++++++++++++++ data/multiplayer/units.ruleset | 2 +- fc_version | 2 +- server/ruleset.c | 81 +++++++++++++++++++++++++++++++++ 17 files changed, 311 insertions(+), 23 deletions(-) diff --git a/client/packhand.c b/client/packhand.c index 0907a4c7e7..770c3824f7 100644 --- a/client/packhand.c +++ b/client/packhand.c @@ -28,6 +28,7 @@ /* common */ #include "achievements.h" +#include "actions.h" #include "capstr.h" #include "citizens.h" #include "events.h" @@ -3314,6 +3315,32 @@ void handle_ruleset_road(const struct packet_ruleset_road *p) tileset_setup_road(tileset, proad); } +/**************************************************************************** + Handle a packet about a particular action enabler. +****************************************************************************/ +void +handle_ruleset_action_enabler(const struct packet_ruleset_action_enabler *p) +{ + struct action_enabler *enabler; + int i; + + enabler = action_enabler_new(); + + enabler->action = p->enabled_action; + + for (i = 0; i < p->actor_reqs_count; i++) { + requirement_vector_append(&enabler->actor_reqs, p->actor_reqs[i]); + } + fc_assert(enabler->actor_reqs.size == p->actor_reqs_count); + + for (i = 0; i < p->target_reqs_count; i++) { + requirement_vector_append(&enabler->target_reqs, p->target_reqs[i]); + } + fc_assert(enabler->target_reqs.size == p->target_reqs_count); + + action_enabler_add(enabler); +} + /**************************************************************************** Handle a packet about a particular disaster type. ****************************************************************************/ diff --git a/common/actions.c b/common/actions.c index d8a6aa7618..54cb4e1732 100644 --- a/common/actions.c +++ b/common/actions.c @@ -27,25 +27,9 @@ static struct action_enabler_list *action_enablers_by_action[ACTION_COUNT]; **************************************************************************/ void actions_init(void) { - struct action_enabler *hardCoded; - action_iterate(act) { action_enablers_by_action[act] = action_enabler_list_new(); } action_iterate_end; - - hardCoded = action_enabler_new(); - hardCoded->action = ACTION_SPY_POISON; - requirement_vector_append( - &hardCoded->actor_reqs, - req_from_str("UnitFlag", "Local", FALSE, TRUE, "Spy")); - action_enabler_add(hardCoded); - - hardCoded = action_enabler_new(); - hardCoded->action = ACTION_SPY_SABOTAGE_UNIT; - requirement_vector_append( - &hardCoded->actor_reqs, - req_from_str("UnitFlag", "Local", FALSE, TRUE, "Spy")); - action_enabler_add(hardCoded); } /************************************************************************** diff --git a/common/actions.h b/common/actions.h index 12272c120b..7f7b2ce10f 100644 --- a/common/actions.h +++ b/common/actions.h @@ -22,6 +22,7 @@ extern "C" { #endif /* __cplusplus */ +/* Used in the network protocol. */ #define SPECENUM_NAME gen_action #define SPECENUM_VALUE0 ACTION_SPY_POISON #define SPECENUM_VALUE0NAME "Poison City" diff --git a/common/generate_packets.py b/common/generate_packets.py index f2d8a7171f..c302dc762a 100755 --- a/common/generate_packets.py +++ b/common/generate_packets.py @@ -1585,6 +1585,7 @@ def main(): #endif /* __cplusplus */ /* common */ +#include "actions.h" #include "disaster.h" ''') diff --git a/common/packets.def b/common/packets.def index 40087da8b0..bcdfeda086 100644 --- a/common/packets.def +++ b/common/packets.def @@ -3,7 +3,7 @@ Max used id: ============ -Max id: 234 +Max id: 235 Packets are not ordered by their id, but by their category. New packet with higher id may get added to existing category, and not to the end of file. @@ -232,6 +232,7 @@ type UTYF = uint8(enum unit_type_flag_id) type CBONUS_TYPE = uint8(enum combat_bonus_type) type TRI = uint8(enum traderoute_illegal_cancelling) type MOVE_MODE = uint8(enum road_move_mode) +type GEN_ACTION = uint8(enum gen_action) # typedefs for bit vectors type BV_EXTRA_FLAGS = bitvector(bv_extra_flags) @@ -1510,6 +1511,14 @@ PACKET_RULESET_TRADE = 227; sc, lsend TRI cancelling; end +PACKET_RULESET_ACTION_ENABLER = 235; sc, lsend + GEN_ACTION enabled_action; + UINT8 actor_reqs_count; + REQUIREMENT actor_reqs[MAX_NUM_REQS:actor_reqs_count]; + UINT8 target_reqs_count; + REQUIREMENT target_reqs[MAX_NUM_REQS:target_reqs_count]; +end + /************************************************************************** Ruleset control values: single values, all of which are needed before sending other ruleset data. After sending this packet, resend every diff --git a/data/alien/units.ruleset b/data/alien/units.ruleset index 58a7f6a106..e4a6b11729 100644 --- a/data/alien/units.ruleset +++ b/data/alien/units.ruleset @@ -240,7 +240,7 @@ flags = "Missile", "DoesntOccupyTile" ; units other than missiles ; "Settlers" = can irrigate and build roads ; "Diplomat" = can do diplomat actions (see diplchance server option) -; "Spy" = can do poison and sabotage, _must_ be "Diplomat" also +; "Spy" = enhanced diplomat actions. _Must_ be "Diplomat" also ; "Trireme" = (sea only) cannot leave shoreline ; "Nuclear" = nuke! ; "Paratroopers"= (land only) can paradrop diff --git a/data/civ2/game.ruleset b/data/civ2/game.ruleset index 8b80ac3690..9945382135 100644 --- a/data/civ2/game.ruleset +++ b/data/civ2/game.ruleset @@ -154,6 +154,43 @@ total_factor = 100 ; strength even if they have only fractional moves left. tired_attack = TRUE +; /* <-- avoid gettext warnings +; +; Action enablers: +; +; action = the action to enable. +; actor_reqs = requirements that apply to the actor. +; target_reqs = requirements that apply to the target. +; +; An action enabler is active when its actor_reqs AND its target_reqs are +; satisfied. +; +; actions and their hard coded requirements +; - "Poison City" = Kill a citizen in the target city. +; * actor and target must be at war. +; * actor must have the diplomat flag. +; * target city must be size 2 or larger. +; - "Sabotage Unit" = Halve the target unit's hit points. +; * actor and target must be at war. +; * actor must have the diplomat flag. +; * target must have > 1 hp. +; * target must be alone at its tile. +; +; */ <-- avoid gettext warnings +[actionenabler_poison_city] +action = "Poison City" +actor_reqs = + { "type", "name", "range" + "UnitFlag", "Spy", "Local" + } + +[actionenabler_sabotage_unit] +action = "Sabotage Unit" +actor_reqs = + { "type", "name", "range" + "Unitflag", "Spy", "Local" + } + [borders] ; Base border radius from city. radius_sq_city = 17 diff --git a/data/civ2civ3/game.ruleset b/data/civ2civ3/game.ruleset index 6ee9de0ec9..dd0a1c6905 100644 --- a/data/civ2civ3/game.ruleset +++ b/data/civ2civ3/game.ruleset @@ -190,6 +190,43 @@ slow_invasions = TRUE ; strength even if they have only fractional moves left. tired_attack = FALSE +; /* <-- avoid gettext warnings +; +; Action enablers: +; +; action = the action to enable. +; actor_reqs = requirements that apply to the actor. +; target_reqs = requirements that apply to the target. +; +; An action enabler is active when its actor_reqs AND its target_reqs are +; satisfied. +; +; actions and their hard coded requirements +; - "Poison City" = Kill a citizen in the target city. +; * actor and target must be at war. +; * actor must have the diplomat flag. +; * target city must be size 2 or larger. +; - "Sabotage Unit" = Halve the target unit's hit points. +; * actor and target must be at war. +; * actor must have the diplomat flag. +; * target must have > 1 hp. +; * target must be alone at its tile. +; +; */ <-- avoid gettext warnings +[actionenabler_poison_city] +action = "Poison City" +actor_reqs = + { "type", "name", "range" + "UnitFlag", "Spy", "Local" + } + +[actionenabler_sabotage_unit] +action = "Sabotage Unit" +actor_reqs = + { "type", "name", "range" + "Unitflag", "Spy", "Local" + } + [borders] ; Base border radius from city. radius_sq_city = 5 diff --git a/data/civ2civ3/units.ruleset b/data/civ2civ3/units.ruleset index a5d76ac09d..32295e8995 100644 --- a/data/civ2civ3/units.ruleset +++ b/data/civ2civ3/units.ruleset @@ -282,7 +282,7 @@ flags = "Unreachable", "DoesntOccupyTile" ; units other than missiles ; "Settlers" = can irrigate and build roads ; "Diplomat" = can do diplomat actions (see diplchance server option) -; "Spy" = can do poison and sabotage, _must_ be "Diplomat" also +; "Spy" = enhanced diplomat actions. _Must_ be "Diplomat" also ; "Trireme" = (sea only) cannot leave shoreline ; "Nuclear" = nuke! ; "Paratroopers"= (land only) can paradrop diff --git a/data/classic/game.ruleset b/data/classic/game.ruleset index 4212c3399e..08f188a40d 100644 --- a/data/classic/game.ruleset +++ b/data/classic/game.ruleset @@ -182,6 +182,43 @@ slow_invasions = TRUE ; strength even if they have only fractional moves left. tired_attack = FALSE +; /* <-- avoid gettext warnings +; +; Action enablers: +; +; action = the action to enable. +; actor_reqs = requirements that apply to the actor. +; target_reqs = requirements that apply to the target. +; +; An action enabler is active when its actor_reqs AND its target_reqs are +; satisfied. +; +; actions and their hard coded requirements +; - "Poison City" = Kill a citizen in the target city. +; * actor and target must be at war. +; * actor must have the diplomat flag. +; * target city must be size 2 or larger. +; - "Sabotage Unit" = Halve the target unit's hit points. +; * actor and target must be at war. +; * actor must have the diplomat flag. +; * target must have > 1 hp. +; * target must be alone at its tile. +; +; */ <-- avoid gettext warnings +[actionenabler_poison_city] +action = "Poison City" +actor_reqs = + { "type", "name", "range" + "UnitFlag", "Spy", "Local" + } + +[actionenabler_sabotage_unit] +action = "Sabotage Unit" +actor_reqs = + { "type", "name", "range" + "Unitflag", "Spy", "Local" + } + [borders] ; Base border radius from city. radius_sq_city = 17 diff --git a/data/classic/units.ruleset b/data/classic/units.ruleset index 80824233e0..e38fcf54b6 100644 --- a/data/classic/units.ruleset +++ b/data/classic/units.ruleset @@ -258,7 +258,7 @@ flags = "Unreachable", "DoesntOccupyTile" ; units other than missiles ; "Settlers" = can irrigate and build roads ; "Diplomat" = can do diplomat actions (see diplchance server option) -; "Spy" = can do poison and sabotage, _must_ be "Diplomat" also +; "Spy" = enhanced diplomat actions. _Must_ be "Diplomat" also ; "Trireme" = (sea only) cannot leave shoreline ; "Nuclear" = nuke! ; "Paratroopers"= (land only) can paradrop diff --git a/data/experimental/game.ruleset b/data/experimental/game.ruleset index 039985a98f..c106213e47 100644 --- a/data/experimental/game.ruleset +++ b/data/experimental/game.ruleset @@ -188,6 +188,43 @@ slow_invasions = TRUE ; strength even if they have only fractional moves left. tired_attack = FALSE +; /* <-- avoid gettext warnings +; +; Action enablers: +; +; action = the action to enable. +; actor_reqs = requirements that apply to the actor. +; target_reqs = requirements that apply to the target. +; +; An action enabler is active when its actor_reqs AND its target_reqs are +; satisfied. +; +; actions and their hard coded requirements +; - "Poison City" = Kill a citizen in the target city. +; * actor and target must be at war. +; * actor must have the diplomat flag. +; * target city must be size 2 or larger. +; - "Sabotage Unit" = Halve the target unit's hit points. +; * actor and target must be at war. +; * actor must have the diplomat flag. +; * target must have > 1 hp. +; * target must be alone at its tile. +; +; */ <-- avoid gettext warnings +[actionenabler_poison_city] +action = "Poison City" +actor_reqs = + { "type", "name", "range" + "UnitFlag", "Spy", "Local" + } + +[actionenabler_sabotage_unit] +action = "Sabotage Unit" +actor_reqs = + { "type", "name", "range" + "Unitflag", "Spy", "Local" + } + [borders] ; Base border radius from city. radius_sq_city = 17 diff --git a/data/experimental/units.ruleset b/data/experimental/units.ruleset index db5ecc5f82..ee6b1ed6bf 100644 --- a/data/experimental/units.ruleset +++ b/data/experimental/units.ruleset @@ -272,7 +272,7 @@ flags = "Unreachable", "DoesntOccupyTile" ; units other than missiles ; "Settlers" = can irrigate and build roads ; "Diplomat" = can do diplomat actions (see diplchance server option) -; "Spy" = can do poison and sabotage, _must_ be "Diplomat" also +; "Spy" = enhanced diplomat actions. _Must_ be "Diplomat" also ; "Trireme" = (sea only) cannot leave shoreline ; "Nuclear" = nuke! ; "Paratroopers"= (land only) can paradrop diff --git a/data/multiplayer/game.ruleset b/data/multiplayer/game.ruleset index 56b9c3d4e4..b77bd8e13e 100644 --- a/data/multiplayer/game.ruleset +++ b/data/multiplayer/game.ruleset @@ -186,6 +186,43 @@ slow_invasions = TRUE ; strength even if they have only fractional moves left. tired_attack = FALSE +; /* <-- avoid gettext warnings +; +; Action enablers: +; +; action = the action to enable. +; actor_reqs = requirements that apply to the actor. +; target_reqs = requirements that apply to the target. +; +; An action enabler is active when its actor_reqs AND its target_reqs are +; satisfied. +; +; actions and their hard coded requirements +; - "Poison City" = Kill a citizen in the target city. +; * actor and target must be at war. +; * actor must have the diplomat flag. +; * target city must be size 2 or larger. +; - "Sabotage Unit" = Halve the target unit's hit points. +; * actor and target must be at war. +; * actor must have the diplomat flag. +; * target must have > 1 hp. +; * target must be alone at its tile. +; +; */ <-- avoid gettext warnings +[actionenabler_poison_city] +action = "Poison City" +actor_reqs = + { "type", "name", "range" + "UnitFlag", "Spy", "Local" + } + +[actionenabler_sabotage_unit] +action = "Sabotage Unit" +actor_reqs = + { "type", "name", "range" + "Unitflag", "Spy", "Local" + } + [borders] ; Base border radius from city. radius_sq_city = 17 diff --git a/data/multiplayer/units.ruleset b/data/multiplayer/units.ruleset index 1b0dba8c28..4b48131aa6 100644 --- a/data/multiplayer/units.ruleset +++ b/data/multiplayer/units.ruleset @@ -258,7 +258,7 @@ flags = "Unreachable", "DoesntOccupyTile" ; units other than missiles ; "Settlers" = can irrigate and build roads ; "Diplomat" = can do diplomat actions (see diplchance server option) -; "Spy" = can do poison and sabotage, _must_ be "Diplomat" also +; "Spy" = enhanced diplomat actions. _Must_ be "Diplomat" also ; "Trireme" = (sea only) cannot leave shoreline ; "Nuclear" = nuke! ; "Paratroopers"= (land only) can paradrop diff --git a/fc_version b/fc_version index 6212a141bd..c14647ed08 100755 --- a/fc_version +++ b/fc_version @@ -30,7 +30,7 @@ DEFAULT_FOLLOW_TAG=stable # - Avoid adding a new mandatory capability to the development branch for # as long as possible. We want to maintain network compatibility with # the stable branch for as long as possible. -NETWORK_CAPSTRING_MANDATORY="+Freeciv.Devel-2.6-2013.Aug.30" +NETWORK_CAPSTRING_MANDATORY="+Freeciv.Devel-2.6-2013.Aug.31" NETWORK_CAPSTRING_OPTIONAL="" FREECIV_DISTRIBUTOR="" diff --git a/server/ruleset.c b/server/ruleset.c index 85227242d2..11ee3c69f1 100644 --- a/server/ruleset.c +++ b/server/ruleset.c @@ -32,6 +32,7 @@ /* common */ #include "achievements.h" +#include "actions.h" #include "ai.h" #include "base.h" #include "capability.h" @@ -105,6 +106,7 @@ #define UNIT_SECTION_PREFIX "unit_" #define DISASTER_SECTION_PREFIX "disaster_" #define ACHIEVEMENT_SECTION_PREFIX "achievement_" +#define ACTION_ENABLER_SECTION_PREFIX "actionenabler_" #define check_name(name) (check_strlen(name, MAX_LEN_NAME, NULL)) @@ -4752,6 +4754,57 @@ static bool load_ruleset_game(struct section_file *file) = secfile_lookup_bool_default(file, RS_DEFAULT_SLOW_INVASIONS, "global_unit_options.slow_invasions"); + if (ok) { + sec = secfile_sections_by_name_prefix(file, + ACTION_ENABLER_SECTION_PREFIX); + + section_list_iterate(sec, psection) { + struct action_enabler *enabler; + const char *sec_name = section_name(psection); + enum gen_action action; + struct requirement_vector *actor_reqs; + struct requirement_vector *target_reqs; + const char *action_text; + + enabler = action_enabler_new(); + + action_text = secfile_lookup_str(file, "%s.action", sec_name); + + if (action_text == NULL) { + log_error("\"%s\" [%s] missing action to enable.", + filename, sec_name); + continue; + } + + action = gen_action_by_name(action_text, fc_strcasecmp); + if (!gen_action_is_valid(action)) { + log_error("\"%s\" [%s] lists unknown action type \"%s\".", + filename, sec_name, action_text); + continue; + } + + enabler->action = action; + + actor_reqs = lookup_req_list(file, sec_name, "actor_reqs", action_text); + if (actor_reqs == NULL) { + ok = FALSE; + break; + } + + requirement_vector_copy(&enabler->actor_reqs, actor_reqs); + + target_reqs = lookup_req_list(file, sec_name, "target_reqs", action_text); + if (target_reqs == NULL) { + ok = FALSE; + break; + } + + requirement_vector_copy(&enabler->target_reqs, target_reqs); + + action_enabler_add(enabler); + } section_list_iterate_end; + } + /* section: combat_rules */ game.info.tired_attack = secfile_lookup_bool_default(file, RS_DEFAULT_TIRED_ATTACK, @@ -5542,6 +5595,33 @@ static void send_ruleset_achievements(struct conn_list *dest) } achievements_iterate_end; } +/************************************************************************** + Send the action enabler ruleset information to the specified connections. +**************************************************************************/ +static void send_ruleset_action_enablers(struct conn_list *dest) +{ + int counter; + struct packet_ruleset_action_enabler packet; + + action_enablers_iterate(enabler) { + packet.enabled_action = enabler->action; + + counter = 0; + requirement_vector_iterate(&enabler->actor_reqs, req) { + packet.actor_reqs[counter++] = *req; + } requirement_vector_iterate_end; + packet.actor_reqs_count = counter; + + counter = 0; + requirement_vector_iterate(&enabler->target_reqs, req) { + packet.target_reqs[counter++] = *req; + } requirement_vector_iterate_end; + packet.target_reqs_count = counter; + + lsend_packet_ruleset_action_enabler(dest, &packet); + } action_enablers_iterate_end; +} + /************************************************************************** Send the disaster ruleset information (all individual disaster types) to the specified connections. @@ -6010,6 +6090,7 @@ void send_rulesets(struct conn_list *dest) send_ruleset_achievements(dest); send_ruleset_trade_routes(dest); send_ruleset_team_names(dest); + send_ruleset_action_enablers(dest); send_ruleset_techs(dest); send_ruleset_governments(dest); send_ruleset_unit_classes(dest);