diff -Nur -Xfreecivdiff.ignore freeciv-patched/client/civclient.c freeciv-compunit/client/civclient.c --- freeciv-patched/client/civclient.c 2003-06-07 19:58:20.000000000 +0100 +++ freeciv-compunit/client/civclient.c 2003-06-12 13:42:19.000000000 +0100 @@ -365,6 +365,15 @@ handle_ruleset_unit((struct packet_ruleset_unit *)packet); break; + case PACKET_RULESET_MODIFIER_TYPE: + handle_ruleset_modifier_type( + (struct packet_ruleset_modifier_type *)packet); + break; + + case PACKET_RULESET_MODIFIER: + handle_ruleset_modifier((struct packet_ruleset_modifier *)packet); + break; + case PACKET_RULESET_TECH: handle_ruleset_tech((struct packet_ruleset_tech *)packet); break; diff -Nur -Xfreecivdiff.ignore freeciv-patched/client/gui-gtk/dialogs.c freeciv-compunit/client/gui-gtk/dialogs.c --- freeciv-patched/client/gui-gtk/dialogs.c 2003-06-07 19:58:20.000000000 +0100 +++ freeciv-compunit/client/gui-gtk/dialogs.c 2003-06-12 13:42:19.000000000 +0100 @@ -175,6 +175,18 @@ popdown_notify_dialog(); } +static void workshop_update_selection(bool is_gov); +static bool is_showing_workshop_dialog = FALSE; +static bool workshop_is_gov = FALSE; +static Unit_Type_id workshop_base; +struct workshop_selection { + GtkWidget *option_menu, *popup; + int modifier; +}; +static struct workshop_selection wkshp_selection[MAX_MODS]; +static struct workshop_selection wkshp_name; +static GtkWidget *wkshp_create_button; + /**************************************************************** ... *****************************************************************/ @@ -1181,6 +1193,380 @@ send_packet_unit_request(&aconnection, &req, PACKET_UNIT_ESTABLISH_TRADE); } +static gint workshop_del_callback(GtkWidget *widget, GdkEvent *event, + gpointer data) +{ + gtk_widget_set_sensitive((GtkWidget *)data, TRUE); + is_showing_workshop_dialog = FALSE; + return FALSE; +} + +static void workshop_create_callback(GtkWidget *widget, gpointer data) +{ + struct packet_request_compound packet; + int i; + + packet.is_gov = workshop_is_gov; + packet.basetype = workshop_base; + for (i = 0; i < MAX_MODS; ++i) { + packet.modifiers[i] = wkshp_selection[i].modifier; + } + /* Use an auto-generated name */ + packet.name[0] ='\0'; + send_packet_request_compound(&aconnection, &packet); +} + +static void workshop_close_callback(GtkWidget *widget, gpointer data) +{ + gtk_widget_set_sensitive(toplevel, TRUE); + gtk_widget_destroy((GtkWidget *)data); + is_showing_workshop_dialog = FALSE; +} + +static void workshop_select_callback(GtkWidget *widget, gpointer data) +{ + int mod, i, modifiers[MAX_MODS], type; + int num_modtypes; + Unit_Type_id uid; + + mod = GPOINTER_TO_INT(data); + type = GPOINTER_TO_INT(gtk_object_get_data(GTK_OBJECT(widget), "type")); + + num_modtypes = workshop_is_gov ? game.num_gov_modifier_types + : game.num_unit_modifier_types; + assert(type >=0 && type < num_modtypes); + + wkshp_selection[type].modifier = mod; + for (i = 0; i < num_modtypes; ++i) { + modifiers[i] = wkshp_selection[i].modifier; + } + + if (workshop_is_gov) { + workshop_update_selection(TRUE); + } else { + uid = find_unit_type_by_modifiers(workshop_base, modifiers); + gtk_widget_set_sensitive(wkshp_create_button, uid == U_LAST); + if (uid < U_LAST) { + workshop_dialog_update(uid); + } else { + workshop_update_selection(FALSE); + } + } +} + +static void workshop_selname_callback(GtkWidget *widget, gpointer data) +{ + workshop_dialog_update(GPOINTER_TO_INT(data)); +} + +static bool is_duplicate_modifier(int type, int num_mod_types, int mod) +{ + int i; + for (i = 0; i < num_mod_types; ++i) { + if (i != type && wkshp_selection[i].modifier == mod) { + return TRUE; + } + } + return FALSE; +} + +static void workshop_update_selection(bool is_gov) +{ + int i, j, index, selindex, num_mod_types, num_mods; + struct modifier *modifiers; + struct modifier_type *modifier_types; + GtkWidget *item; + + if (is_gov) { + num_mod_types = game.num_gov_modifier_types; + num_mods = game.num_gov_modifiers; + modifier_types = gov_modifier_types; + modifiers = gov_modifiers; + } else { + num_mod_types = game.num_unit_modifier_types; + num_mods = game.num_unit_modifiers; + modifier_types = unit_modifier_types; + modifiers = unit_modifiers; + } + + for (i = 0; i < num_mod_types; ++i) { + int id = modifier_types[i].id; + + if (wkshp_selection[i].popup) { + gtk_widget_destroy(wkshp_selection[i].popup); + } + wkshp_selection[i].popup = gtk_menu_new(); + + if (get_invention(game.player_ptr, + modifier_types[i].tech_requirement) == TECH_KNOWN) { + index = selindex = -1; + if (!modifier_types[i].must_use) { + item = gtk_menu_item_new_with_label(_("")); + index++; + gtk_object_set_data(GTK_OBJECT(item), "type", GINT_TO_POINTER(i)); + gtk_signal_connect(GTK_OBJECT(item), "activate", + GTK_SIGNAL_FUNC(workshop_select_callback), + GINT_TO_POINTER(U_LAST)); + gtk_menu_append(GTK_MENU(wkshp_selection[i].popup), item); + } + + for (j = 0; j < num_mods; ++j) { + struct modifier *u = &modifiers[j]; + + if (u->type == id && get_invention(game.player_ptr, + u->tech_requirement) == TECH_KNOWN + && !is_duplicate_modifier(i, num_mod_types, j)) { + index++; + if (wkshp_selection[i].modifier == j) { + selindex = index; + } + item = gtk_menu_item_new_with_label(modifiers[j].name); + gtk_object_set_data(GTK_OBJECT(item), "type", GINT_TO_POINTER(i)); + gtk_signal_connect(GTK_OBJECT(item), "activate", + GTK_SIGNAL_FUNC(workshop_select_callback), + GINT_TO_POINTER(j)); + gtk_menu_append(GTK_MENU(wkshp_selection[i].popup), item); + } + } + gtk_menu_set_active(GTK_MENU(wkshp_selection[i].popup), selindex); + gtk_widget_set_sensitive(wkshp_selection[i].option_menu, TRUE); + } else { + char buf[100]; + + my_snprintf(buf, sizeof(buf), "(Requires %s)", + get_tech_name(game.player_ptr, + modifier_types[i].tech_requirement)); + item = gtk_menu_item_new_with_label(buf); + gtk_menu_append(GTK_MENU(wkshp_selection[i].popup), item); + gtk_widget_set_sensitive(wkshp_selection[i].option_menu, FALSE); + } + gtk_widget_show_all(wkshp_selection[i].popup); + gtk_option_menu_set_menu(GTK_OPTION_MENU(wkshp_selection[i].option_menu), + wkshp_selection[i].popup); + } +} + +void workshop_dialog_update(Unit_Type_id id) +{ + int i, index, selindex; + GtkWidget *item; + + if (!is_showing_workshop_dialog || id < 0 || id >= game.num_unit_types + || unit_types[id].basetype == U_LAST + || !can_player_build_unit_direct(game.player_ptr, id)) { + return; + } + + for (i = 0; i < game.num_unit_modifier_types; ++i) { + wkshp_selection[i].modifier = unit_types[id].modifiers[i]; + } + + if (wkshp_name.popup) { + gtk_widget_destroy(wkshp_name.popup); + } + wkshp_name.popup = gtk_menu_new(); + + index = selindex = -1; + unit_type_iterate(uid) { + if (unit_types[uid].basetype >= 0 + && unit_types[uid].basetype < game.num_unit_types + && can_player_build_unit_direct(game.player_ptr, uid)) { + index++; + if (uid == id) { + selindex = index; + } + item = gtk_menu_item_new_with_label(unit_types[uid].name); + gtk_signal_connect(GTK_OBJECT(item), "activate", + GTK_SIGNAL_FUNC(workshop_selname_callback), + GINT_TO_POINTER(uid)); + gtk_menu_append(GTK_MENU(wkshp_name.popup), item); + } + } unit_type_iterate_end; + gtk_menu_set_active(GTK_MENU(wkshp_name.popup), selindex); + gtk_widget_show_all(wkshp_name.popup); + gtk_option_menu_set_menu(GTK_OPTION_MENU(wkshp_name.option_menu), + wkshp_name.popup); + + workshop_update_selection(FALSE); + + gtk_widget_set_sensitive(wkshp_create_button, FALSE); +} + +/**************************************************************** +... +*****************************************************************/ +static void engineering_dialog_update() +{ + int i; + struct government *gov = get_gov_pplayer(game.player_ptr); + + for (i = 0; i < game.num_gov_modifier_types; ++i) { + wkshp_selection[i].modifier = gov->modifiers[i]; + } + workshop_update_selection(TRUE); +} + +/**************************************************************** +... +*****************************************************************/ +void popup_engineering_dialog(void) +{ + GtkWidget *dshell, *vbox, *table, *label, *hbox, *button, *sep; + int i; + + if (!is_showing_workshop_dialog && game.num_gov_modifier_types > 0) { + is_showing_workshop_dialog = TRUE; + workshop_is_gov = TRUE; + workshop_base = 1; + + gtk_widget_set_sensitive(toplevel, FALSE); + dshell = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_policy(GTK_WINDOW(dshell), 1, 1, 1); + gtk_window_set_position(GTK_WINDOW(dshell), GTK_WIN_POS_MOUSE); + + gtk_signal_connect(GTK_OBJECT(dshell), "delete_event", + GTK_SIGNAL_FUNC(workshop_del_callback), + (gpointer)toplevel); + gtk_window_set_title(GTK_WINDOW(dshell), _("Social Engineering")); + + vbox = gtk_vbox_new(FALSE, 8); + gtk_container_add(GTK_CONTAINER(dshell), vbox); + + gtk_container_border_width(GTK_CONTAINER(vbox), 5); + + table = gtk_table_new(game.num_gov_modifier_types, 2, FALSE); + gtk_table_set_row_spacings(GTK_TABLE(table), 6); + gtk_table_set_col_spacings(GTK_TABLE(table), 6); + + for (i = 0; i < game.num_gov_modifier_types; ++i) { + label = gtk_label_new(gov_modifier_types[i].name); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, i, i + 1); + + wkshp_selection[i].option_menu = gtk_option_menu_new(); + gtk_table_attach_defaults(GTK_TABLE(table), + wkshp_selection[i].option_menu, + 1, 2, i, i + 1); + wkshp_selection[i].popup = NULL; + } + engineering_dialog_update(); + + gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 0); + + sep = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, FALSE, 0); + + hbox = gtk_hbox_new(TRUE, 8); + button = gtk_button_new_with_label(_("Apply")); + gtk_signal_connect(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(workshop_create_callback), NULL); + gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); + + button = gtk_button_new_with_label(_("Close")); + gtk_signal_connect(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(workshop_close_callback), dshell); + gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); + + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + + gtk_widget_show_all(vbox); + gtk_widget_show(dshell); + } +} + +/**************************************************************** +... +*****************************************************************/ +void popup_workshop_dialog(void) +{ + GtkWidget *dshell, *vbox, *table, *label; + GtkWidget *button, *hbox, *sep; + int i; + + workshop_base = -1; + unit_type_iterate(uid) { + if (unit_has_role(uid, L_CANMODIFY)) { + workshop_base = uid; + break; + } + } unit_type_iterate_end; + + if (!is_showing_workshop_dialog && game.num_unit_modifier_types > 0) { + is_showing_workshop_dialog = TRUE; + workshop_is_gov = FALSE; + + gtk_widget_set_sensitive(toplevel, FALSE); + dshell = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_policy(GTK_WINDOW(dshell), 1, 1, 1); + gtk_window_set_position(GTK_WINDOW(dshell), GTK_WIN_POS_MOUSE); + + gtk_signal_connect(GTK_OBJECT(dshell), "delete_event", + GTK_SIGNAL_FUNC(workshop_del_callback), + (gpointer)toplevel); + gtk_window_set_title(GTK_WINDOW(dshell), _("Design Workshop")); + + vbox = gtk_vbox_new(FALSE, 8); + gtk_container_add(GTK_CONTAINER(dshell), vbox); + + gtk_container_border_width(GTK_CONTAINER(vbox), 5); + + table = gtk_table_new(game.num_unit_modifier_types + 2, 2, FALSE); + gtk_table_set_row_spacings(GTK_TABLE(table), 6); + gtk_table_set_col_spacings(GTK_TABLE(table), 6); + + label = gtk_label_new(_("Name")); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1); + wkshp_name.option_menu = gtk_option_menu_new(); + gtk_table_attach_defaults(GTK_TABLE(table), + wkshp_name.option_menu, 1, 2, 0, 1); + wkshp_name.popup = NULL; + + sep = gtk_hseparator_new(); + gtk_table_attach_defaults(GTK_TABLE(table), sep, 0, 2, 1, 2); + + for (i = 0; i < game.num_unit_modifier_types; ++i) { + label = gtk_label_new(unit_modifier_types[i].name); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, i + 2, i + 3); + + wkshp_selection[i].option_menu = gtk_option_menu_new(); + gtk_table_attach_defaults(GTK_TABLE(table), + wkshp_selection[i].option_menu, + 1, 2, i + 2, i + 3); + wkshp_selection[i].popup = NULL; + } + + gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 0); + + sep = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, FALSE, 0); + + hbox = gtk_hbox_new(TRUE, 8); + button = gtk_button_new_with_label(_("Create")); + wkshp_create_button = button; + gtk_widget_set_sensitive(button, FALSE); + gtk_signal_connect(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(workshop_create_callback), NULL); + gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); + + button = gtk_button_new_with_label(_("Close")); + gtk_signal_connect(GTK_OBJECT(button), "clicked", + GTK_SIGNAL_FUNC(workshop_close_callback), dshell); + gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); + + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + + unit_type_iterate(uid) { + if (unit_types[uid].basetype >= 0 + && unit_types[uid].basetype < game.num_unit_types + && can_player_build_unit_direct(game.player_ptr, uid)) { + workshop_dialog_update(uid); + break; + } + } unit_type_iterate_end; + + gtk_widget_show_all(vbox); + gtk_widget_show(dshell); + } +} /**************************************************************** ... diff -Nur -Xfreecivdiff.ignore freeciv-patched/client/gui-gtk/menu.c freeciv-compunit/client/gui-gtk/menu.c --- freeciv-patched/client/gui-gtk/menu.c 2003-06-07 19:58:21.000000000 +0100 +++ freeciv-compunit/client/gui-gtk/menu.c 2003-06-12 13:46:51.000000000 +0100 @@ -79,6 +79,8 @@ MENU_KINGDOM_TAX_RATE, MENU_KINGDOM_FIND_CITY, MENU_KINGDOM_WORKLISTS, + MENU_KINGDOM_WORKSHOP, + MENU_KINGDOM_ENGINEERING, MENU_KINGDOM_REVOLUTION, MENU_VIEW_SHOW_MAP_GRID, @@ -211,6 +213,12 @@ case MENU_KINGDOM_WORKLISTS: popup_worklists_report(game.player_ptr); break; + case MENU_KINGDOM_WORKSHOP: + popup_workshop_dialog(); + break; + case MENU_KINGDOM_ENGINEERING: + popup_engineering_dialog(); + break; case MENU_KINGDOM_REVOLUTION: popup_revolution_dialog(); break; @@ -598,6 +606,12 @@ kingdom_menu_callback, MENU_KINGDOM_WORKLISTS }, { "/" N_("Kingdom") "/sep2", NULL, NULL, 0, "" }, + { "/" N_("Kingdom") "/" N_("Design _Workshop"), NULL, + kingdom_menu_callback, MENU_KINGDOM_WORKSHOP }, + { "/" N_("Kingdom") "/" N_("Social _Engineering"), NULL, + kingdom_menu_callback, MENU_KINGDOM_ENGINEERING }, + { "/" N_("Kingdom") "/sep3", NULL, + NULL, 0, "" }, { "/" N_("Kingdom") "/" N_("_Government"), NULL, NULL, 0, "" }, { "/" N_("Kingdom") "/" N_("_Government") "/" N_("_Revolution!"), @@ -1033,6 +1047,10 @@ } menus_set_sensitive("
/_Reports", TRUE); + menus_set_sensitive("
/_Kingdom/Design _Workshop", + game.num_unit_modifier_types > 0); + menus_set_sensitive("
/_Kingdom/Social _Engineering", + game.num_gov_modifier_types > 0); menus_set_sensitive("
/_Kingdom", TRUE); menus_set_sensitive("
/_View", TRUE); menus_set_sensitive("
/_Orders", can_client_issue_orders()); diff -Nur -Xfreecivdiff.ignore freeciv-patched/client/gui-gtk-2.0/dialogs.c freeciv-compunit/client/gui-gtk-2.0/dialogs.c --- freeciv-patched/client/gui-gtk-2.0/dialogs.c 2003-06-07 19:58:21.000000000 +0100 +++ freeciv-compunit/client/gui-gtk-2.0/dialogs.c 2003-06-12 18:02:46.000000000 +0100 @@ -129,6 +129,18 @@ static int connect_unit_x; static int connect_unit_y; +static void workshop_update_selection(bool is_gov); +static bool is_showing_workshop_dialog = FALSE; +static bool workshop_is_gov = FALSE; +static Unit_Type_id workshop_base; +struct workshop_selection { + GtkWidget *option_menu, *popup; + int modifier; +}; +static struct workshop_selection wkshp_selection[MAX_MODS]; +static struct workshop_selection wkshp_name; +static GtkWidget *wkshp_create_button; + /**************************************************************** ... *****************************************************************/ @@ -2424,3 +2436,375 @@ g_list_free(res); } +static gint workshop_del_callback(GtkWidget *widget, GdkEvent *event, + gpointer data) +{ + gtk_widget_set_sensitive((GtkWidget *)data, TRUE); + is_showing_workshop_dialog = FALSE; + return FALSE; +} + +static void workshop_create_callback(GtkWidget *widget, gpointer data) +{ + struct packet_request_compound packet; + int i; + + packet.is_gov = workshop_is_gov; + packet.basetype = workshop_base; + for (i = 0; i < MAX_MODS; ++i) { + packet.modifiers[i] = wkshp_selection[i].modifier; + } + /* Use an auto-generated name */ + packet.name[0] ='\0'; + send_packet_request_compound(&aconnection, &packet); +} + +static void workshop_close_callback(GtkWidget *widget, gpointer data) +{ + gtk_widget_set_sensitive(toplevel, TRUE); + gtk_widget_destroy((GtkWidget *)data); + is_showing_workshop_dialog = FALSE; +} + +static void workshop_select_callback(GtkWidget *widget, gpointer data) +{ + int mod, i, modifiers[MAX_MODS], type; + int num_modtypes; + Unit_Type_id uid; + + mod = GPOINTER_TO_INT(data); + type = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "type")); + + num_modtypes = workshop_is_gov ? game.num_gov_modifier_types + : game.num_unit_modifier_types; + assert(type >=0 && type < num_modtypes); + + wkshp_selection[type].modifier = mod; + for (i = 0; i < num_modtypes; ++i) { + modifiers[i] = wkshp_selection[i].modifier; + } + + if (workshop_is_gov) { + workshop_update_selection(TRUE); + } else { + uid = find_unit_type_by_modifiers(workshop_base, modifiers); + gtk_widget_set_sensitive(wkshp_create_button, uid == U_LAST); + if (uid < U_LAST) { + workshop_dialog_update(uid); + } else { + workshop_update_selection(FALSE); + } + } +} + +static void workshop_selname_callback(GtkWidget *widget, gpointer data) +{ + workshop_dialog_update(GPOINTER_TO_INT(data)); +} + +static bool is_duplicate_modifier(int type, int num_mod_types, int mod) +{ + int i; + for (i = 0; i < num_mod_types; ++i) { + if (i != type && wkshp_selection[i].modifier == mod) { + return TRUE; + } + } + return FALSE; +} + +static void workshop_update_selection(bool is_gov) +{ + int i, j, index, selindex, num_mod_types, num_mods; + struct modifier *modifiers; + struct modifier_type *modifier_types; + GtkWidget *item; + + if (is_gov) { + num_mod_types = game.num_gov_modifier_types; + num_mods = game.num_gov_modifiers; + modifier_types = gov_modifier_types; + modifiers = gov_modifiers; + } else { + num_mod_types = game.num_unit_modifier_types; + num_mods = game.num_unit_modifiers; + modifier_types = unit_modifier_types; + modifiers = unit_modifiers; + } + + for (i = 0; i < num_mod_types; ++i) { + int id = modifier_types[i].id; + + if (wkshp_selection[i].popup) { + gtk_widget_destroy(wkshp_selection[i].popup); + } + wkshp_selection[i].popup = gtk_menu_new(); + + if (get_invention(game.player_ptr, + modifier_types[i].tech_requirement) == TECH_KNOWN) { + index = selindex = -1; + if (!modifier_types[i].must_use) { + item = gtk_menu_item_new_with_label(_("")); + index++; + g_object_set_data(G_OBJECT(item), "type", GINT_TO_POINTER(i)); + g_signal_connect(G_OBJECT(item), "activate", + G_CALLBACK(workshop_select_callback), + GINT_TO_POINTER(U_LAST)); + gtk_menu_shell_append(GTK_MENU_SHELL(wkshp_selection[i].popup), item); + } + + for (j = 0; j < num_mods; ++j) { + struct modifier *u = &modifiers[j]; + + if (u->type == id && get_invention(game.player_ptr, + u->tech_requirement) == TECH_KNOWN + && !is_duplicate_modifier(i, num_mod_types, j)) { + index++; + if (wkshp_selection[i].modifier == j) { + selindex = index; + } + item = gtk_menu_item_new_with_label(modifiers[j].name); + g_object_set_data(G_OBJECT(item), "type", GINT_TO_POINTER(i)); + g_signal_connect(G_OBJECT(item), "activate", + G_CALLBACK(workshop_select_callback), + GINT_TO_POINTER(j)); + gtk_menu_shell_append(GTK_MENU_SHELL(wkshp_selection[i].popup), item); + } + } + gtk_menu_set_active(GTK_MENU(wkshp_selection[i].popup), selindex); + gtk_widget_set_sensitive(wkshp_selection[i].option_menu, TRUE); + } else { + char buf[100]; + + my_snprintf(buf, sizeof(buf), "(Requires %s)", + get_tech_name(game.player_ptr, + modifier_types[i].tech_requirement)); + item = gtk_menu_item_new_with_label(buf); + gtk_menu_shell_append(GTK_MENU_SHELL(wkshp_selection[i].popup), item); + gtk_widget_set_sensitive(wkshp_selection[i].option_menu, FALSE); + } + gtk_widget_show_all(wkshp_selection[i].popup); + gtk_option_menu_set_menu(GTK_OPTION_MENU(wkshp_selection[i].option_menu), + wkshp_selection[i].popup); + } +} + +void workshop_dialog_update(Unit_Type_id id) +{ + int i, index, selindex; + GtkWidget *item; + + if (!is_showing_workshop_dialog || id < 0 || id >= game.num_unit_types + || unit_types[id].basetype == U_LAST + || !can_player_build_unit_direct(game.player_ptr, id)) { + return; + } + + for (i = 0; i < game.num_unit_modifier_types; ++i) { + wkshp_selection[i].modifier = unit_types[id].modifiers[i]; + } + + if (wkshp_name.popup) { + gtk_widget_destroy(wkshp_name.popup); + } + wkshp_name.popup = gtk_menu_new(); + + index = selindex = -1; + unit_type_iterate(uid) { + if (unit_types[uid].basetype >= 0 + && unit_types[uid].basetype < game.num_unit_types + && can_player_build_unit_direct(game.player_ptr, uid)) { + index++; + if (uid == id) { + selindex = index; + } + item = gtk_menu_item_new_with_label(unit_types[uid].name); + g_signal_connect(G_OBJECT(item), "activate", + G_CALLBACK(workshop_selname_callback), + GINT_TO_POINTER(uid)); + gtk_menu_shell_append(GTK_MENU_SHELL(wkshp_name.popup), item); + } + } unit_type_iterate_end; + gtk_menu_set_active(GTK_MENU(wkshp_name.popup), selindex); + gtk_widget_show_all(wkshp_name.popup); + gtk_option_menu_set_menu(GTK_OPTION_MENU(wkshp_name.option_menu), + wkshp_name.popup); + + workshop_update_selection(FALSE); + + gtk_widget_set_sensitive(wkshp_create_button, FALSE); +} + +/**************************************************************** +... +*****************************************************************/ +static void engineering_dialog_update() +{ + int i; + struct government *gov = get_gov_pplayer(game.player_ptr); + + for (i = 0; i < game.num_gov_modifier_types; ++i) { + wkshp_selection[i].modifier = gov->modifiers[i]; + } + workshop_update_selection(TRUE); +} + +/**************************************************************** +... +*****************************************************************/ +void popup_engineering_dialog(void) +{ + GtkWidget *dshell, *vbox, *table, *label, *hbox, *button, *sep; + int i; + + if (!is_showing_workshop_dialog && game.num_gov_modifier_types > 0) { + is_showing_workshop_dialog = TRUE; + workshop_is_gov = TRUE; + workshop_base = 1; + + gtk_widget_set_sensitive(toplevel, FALSE); + dshell = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_position(GTK_WINDOW(dshell), GTK_WIN_POS_MOUSE); + + g_signal_connect(G_OBJECT(dshell), "delete_event", + G_CALLBACK(workshop_del_callback), + (gpointer)toplevel); + gtk_window_set_title(GTK_WINDOW(dshell), _("Social Engineering")); + + vbox = gtk_vbox_new(FALSE, 8); + gtk_container_add(GTK_CONTAINER(dshell), vbox); + + gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); + + table = gtk_table_new(game.num_gov_modifier_types, 2, FALSE); + gtk_table_set_row_spacings(GTK_TABLE(table), 6); + gtk_table_set_col_spacings(GTK_TABLE(table), 6); + + for (i = 0; i < game.num_gov_modifier_types; ++i) { + label = gtk_label_new(gov_modifier_types[i].name); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, i, i + 1); + + wkshp_selection[i].option_menu = gtk_option_menu_new(); + gtk_table_attach_defaults(GTK_TABLE(table), + wkshp_selection[i].option_menu, + 1, 2, i, i + 1); + wkshp_selection[i].popup = NULL; + } + engineering_dialog_update(); + + gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 0); + + sep = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, FALSE, 0); + + hbox = gtk_hbox_new(TRUE, 8); + button = gtk_button_new_from_stock(GTK_STOCK_APPLY); + g_signal_connect(G_OBJECT(button), "clicked", + G_CALLBACK(workshop_create_callback), NULL); + gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); + + button = gtk_button_new_from_stock(GTK_STOCK_CLOSE); + g_signal_connect(G_OBJECT(button), "clicked", + G_CALLBACK(workshop_close_callback), dshell); + gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); + + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + + gtk_widget_show_all(vbox); + gtk_widget_show(dshell); + } +} + +/**************************************************************** +... +*****************************************************************/ +void popup_workshop_dialog(void) +{ + GtkWidget *dshell, *vbox, *table, *label; + GtkWidget *button, *hbox, *sep; + int i; + + workshop_base = -1; + unit_type_iterate(uid) { + if (unit_has_role(uid, L_CANMODIFY)) { + workshop_base = uid; + break; + } + } unit_type_iterate_end; + + if (!is_showing_workshop_dialog && game.num_unit_modifier_types > 0) { + is_showing_workshop_dialog = TRUE; + workshop_is_gov = FALSE; + + gtk_widget_set_sensitive(toplevel, FALSE); + dshell = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_position(GTK_WINDOW(dshell), GTK_WIN_POS_MOUSE); + + g_signal_connect(G_OBJECT(dshell), "delete_event", + G_CALLBACK(workshop_del_callback), + (gpointer)toplevel); + gtk_window_set_title(GTK_WINDOW(dshell), _("Design Workshop")); + + vbox = gtk_vbox_new(FALSE, 8); + gtk_container_add(GTK_CONTAINER(dshell), vbox); + + gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); + + table = gtk_table_new(game.num_unit_modifier_types + 2, 2, FALSE); + gtk_table_set_row_spacings(GTK_TABLE(table), 6); + gtk_table_set_col_spacings(GTK_TABLE(table), 6); + + label = gtk_label_new(_("Name")); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1); + wkshp_name.option_menu = gtk_option_menu_new(); + gtk_table_attach_defaults(GTK_TABLE(table), + wkshp_name.option_menu, 1, 2, 0, 1); + wkshp_name.popup = NULL; + + sep = gtk_hseparator_new(); + gtk_table_attach_defaults(GTK_TABLE(table), sep, 0, 2, 1, 2); + + for (i = 0; i < game.num_unit_modifier_types; ++i) { + label = gtk_label_new(unit_modifier_types[i].name); + gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, i + 2, i + 3); + + wkshp_selection[i].option_menu = gtk_option_menu_new(); + gtk_table_attach_defaults(GTK_TABLE(table), + wkshp_selection[i].option_menu, + 1, 2, i + 2, i + 3); + wkshp_selection[i].popup = NULL; + } + + gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 0); + + sep = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, FALSE, 0); + + hbox = gtk_hbox_new(TRUE, 8); + button = gtk_stockbutton_new(GTK_STOCK_NEW, _("C_reate")); + wkshp_create_button = button; + gtk_widget_set_sensitive(button, FALSE); + g_signal_connect(G_OBJECT(button), "clicked", + G_CALLBACK(workshop_create_callback), NULL); + gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); + + button = gtk_button_new_from_stock(GTK_STOCK_CLOSE); + g_signal_connect(G_OBJECT(button), "clicked", + G_CALLBACK(workshop_close_callback), dshell); + gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); + + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + + unit_type_iterate(uid) { + if (unit_types[uid].basetype >= 0 + && unit_types[uid].basetype < game.num_unit_types + && can_player_build_unit_direct(game.player_ptr, uid)) { + workshop_dialog_update(uid); + break; + } + } unit_type_iterate_end; + + gtk_widget_show_all(vbox); + gtk_widget_show(dshell); + } +} diff -Nur -Xfreecivdiff.ignore freeciv-patched/client/gui-gtk-2.0/menu.c freeciv-compunit/client/gui-gtk-2.0/menu.c --- freeciv-patched/client/gui-gtk-2.0/menu.c 2003-06-07 19:58:22.000000000 +0100 +++ freeciv-compunit/client/gui-gtk-2.0/menu.c 2003-06-12 16:38:29.000000000 +0100 @@ -80,6 +80,8 @@ MENU_KINGDOM_TAX_RATE, MENU_KINGDOM_FIND_CITY, MENU_KINGDOM_WORKLISTS, + MENU_KINGDOM_WORKSHOP, + MENU_KINGDOM_ENGINEERING, MENU_KINGDOM_REVOLUTION, MENU_VIEW_SHOW_MAP_GRID, @@ -212,6 +214,12 @@ case MENU_KINGDOM_WORKLISTS: popup_worklists_report(); break; + case MENU_KINGDOM_WORKSHOP: + popup_workshop_dialog(); + break; + case MENU_KINGDOM_ENGINEERING: + popup_engineering_dialog(); + break; case MENU_KINGDOM_REVOLUTION: popup_revolution_dialog(); break; @@ -597,6 +605,12 @@ kingdom_menu_callback, MENU_KINGDOM_WORKLISTS }, { "/" N_("Kingdom") "/sep2", NULL, NULL, 0, "" }, + { "/" N_("Kingdom") "/" N_("Design _Workshop"), NULL, + kingdom_menu_callback, MENU_KINGDOM_WORKSHOP }, + { "/" N_("Kingdom") "/" N_("Social _Engineering"), NULL, + kingdom_menu_callback, MENU_KINGDOM_ENGINEERING }, + { "/" N_("Kingdom") "/sep3", NULL, + NULL, 0, "" }, { "/" N_("_Kingdom") "/" N_("_Government"), NULL, NULL, 0, "" }, { "/" N_("Kingdom") "/" N_("_Government") "/" N_("_Revolution"), @@ -1052,6 +1066,10 @@ } menus_set_sensitive("
/_Reports", TRUE); + menus_set_sensitive("
/_Kingdom/Design _Workshop", + game.num_unit_modifier_types > 0); + menus_set_sensitive("
/_Kingdom/Social _Engineering", + game.num_gov_modifier_types > 0); menus_set_sensitive("
/_Kingdom", TRUE); menus_set_sensitive("
/_View", TRUE); menus_set_sensitive("
/_Orders", can_client_issue_orders()); Binary files freeciv-patched/client/gui-gtk-2.0/stBWIIWx and freeciv-compunit/client/gui-gtk-2.0/stBWIIWx differ Binary files freeciv-patched/client/gui-gtk-2.0/stfY6B6n and freeciv-compunit/client/gui-gtk-2.0/stfY6B6n differ Binary files freeciv-patched/client/gui-gtk-2.0/stQfEWjw and freeciv-compunit/client/gui-gtk-2.0/stQfEWjw differ diff -Nur -Xfreecivdiff.ignore freeciv-patched/client/include/dialogs_g.h freeciv-compunit/client/include/dialogs_g.h --- freeciv-patched/client/include/dialogs_g.h 2002-11-29 12:25:10.000000000 +0000 +++ freeciv-compunit/client/include/dialogs_g.h 2003-06-12 13:42:19.000000000 +0100 @@ -15,10 +15,9 @@ #include "shared.h" /* bool type */ #include "terrain.h" /* enum tile_special_type */ +#include "unittype.h" /* Unit_Type_id type */ struct tile; -struct unit; -struct city; struct packet_nations_used; void popup_notify_goto_dialog(char *headline, char *lines, int x, int y); @@ -33,6 +32,9 @@ void popup_revolution_dialog(void); void popup_government_dialog(void); +void popup_workshop_dialog(void); +void popup_engineering_dialog(void); +void workshop_dialog_update(Unit_Type_id id); void popup_caravan_dialog(struct unit *punit, struct city *phomecity, struct city *pdestcity); bool caravan_dialog_is_open(void); diff -Nur -Xfreecivdiff.ignore freeciv-patched/client/packhand.c freeciv-compunit/client/packhand.c --- freeciv-patched/client/packhand.c 2003-06-12 13:39:42.000000000 +0100 +++ freeciv-compunit/client/packhand.c 2003-06-12 16:28:24.000000000 +0100 @@ -1922,6 +1922,25 @@ game.num_impr_types = packet->num_impr_types; game.num_tech_types = packet->num_tech_types; + game.num_unit_modifier_types = packet->num_unit_modifier_types; + game.num_unit_modifiers = packet->num_unit_modifiers; + game.num_gov_modifier_types = packet->num_gov_modifier_types; + game.num_gov_modifiers = packet->num_gov_modifiers; + + if (game.num_unit_modifiers > 0) { + unit_modifiers = fc_calloc(game.num_unit_modifiers, + sizeof(struct modifier)); + } else { + unit_modifiers = NULL; + } + + if (game.num_gov_modifiers > 0) { + gov_modifiers = fc_calloc(game.num_gov_modifiers, + sizeof(struct modifier)); + } else { + gov_modifiers = NULL; + } + governments_alloc(packet->government_count); nations_alloc(packet->nation_count); @@ -1942,12 +1961,17 @@ void handle_ruleset_unit(struct packet_ruleset_unit *p) { struct unit_type *u; + int i; - if(p->id < 0 || p->id >= game.num_unit_types || p->id >= U_LAST) { + if(p->id < 0 || p->id >= U_LAST) { freelog(LOG_ERROR, "Received bad unit_type id %d in handle_ruleset_unit()", p->id); return; } + if (p->id >= game.num_unit_types) { + freelog(LOG_NORMAL, "Number of unit types increased to %d", p->id + 1); + game.num_unit_types = p->id + 1; + } u = get_unit_type(p->id); sz_strlcpy(u->name, p->name); @@ -1983,9 +2007,72 @@ u->paratroopers_mr_sub = p->paratroopers_mr_sub; u->effect = p->effect; /* pointer assignment */ + u->basetype = p->basetype; + for (i = 0; i < MAX_MODS; ++i) { + u->modifiers[i] = p->modifiers[i]; + } + u->helptext = p->helptext; /* pointer assignment */ tilespec_setup_unit_type(p->id); + + workshop_dialog_update(p->id); +} + +/************************************************************************** +... +**************************************************************************/ +void handle_ruleset_modifier_type( + struct packet_ruleset_modifier_type *p) +{ + struct modifier_type *u; + int max_mod; + + max_mod = (p->is_gov ? game.num_gov_modifier_types + : game.num_unit_modifier_types); + + if (p->id < 0 || p->id >= max_mod) { + freelog(LOG_ERROR, "Received bad modifier type id %d in " + "handle_ruleset_modifier_type()", p->id); + return; + } + if (p->is_gov) { + u = &gov_modifier_types[p->id]; + } else { + u = &unit_modifier_types[p->id]; + } + sz_strlcpy(u->name, p->name); + u->id = p->basetype; + u->tech_requirement = p->tech_requirement; + u->must_use = p->must_use; +} + +/************************************************************************** +... +**************************************************************************/ +void handle_ruleset_modifier(struct packet_ruleset_modifier *p) +{ + struct modifier *u; + int max_mod; + + max_mod = (p->is_gov ? game.num_gov_modifiers + : game.num_unit_modifiers); + + if (p->id < 0 || p->id >= max_mod) { + freelog(LOG_ERROR, + "Received bad modifier id %d in handle_ruleset_modifier()", + p->id); + return; + } + if (p->is_gov) { + u = &gov_modifiers[p->id]; + } else { + u = &unit_modifiers[p->id]; + } + sz_strlcpy(u->name, p->name); + u->type = p->type; + u->tech_requirement = p->tech_requirement; + u->effect = p->effect; /* pointer assignment */ } /************************************************************************** @@ -2188,13 +2275,21 @@ void handle_ruleset_government(struct packet_ruleset_government *p) { struct government *gov; + int i; - if (p->id < 0 || p->id >= game.government_count) { + if (p->id < 0 || p->id >= G_MAGIC) { freelog(LOG_ERROR, "Received bad government id %d in handle_ruleset_government", p->id); return; } + if (p->id >= game.government_count) { + freelog(LOG_NORMAL, "Number of gov types increased to %d", p->id + 1); + game.government_count = p->id + 1; + governments = (struct government *)fc_realloc(governments, + game.government_count + * sizeof(struct government)); + } gov = &governments[p->id]; gov->index = p->id; @@ -2207,6 +2302,11 @@ gov->empire_size_mod = p->empire_size_mod; gov->empire_size_inc = p->empire_size_inc; gov->rapture_size = p->rapture_size; + gov->basetype = p->basetype; + + for (i = 0; i < MAX_MODS; ++i) { + gov->modifiers[i] = p->modifiers[i]; + } gov->unit_happy_cost_factor = p->unit_happy_cost_factor; gov->unit_shield_cost_factor = p->unit_shield_cost_factor; @@ -2263,6 +2363,13 @@ gov->helptext = p->helptext; /* pointer assignment */ tilespec_setup_government(p->id); + + /* If we're getting governments re-sent after the game has started, + * then this generally means a player has changed government, and + * thus an effect update is needed. */ + if(get_client_state()==CLIENT_GAME_RUNNING_STATE) { + update_all_effects(); + } } void handle_ruleset_government_ruler_title (struct packet_ruleset_government_ruler_title *p) diff -Nur -Xfreecivdiff.ignore freeciv-patched/client/packhand.h freeciv-compunit/client/packhand.h --- freeciv-patched/client/packhand.h 2003-06-07 19:58:20.000000000 +0100 +++ freeciv-compunit/client/packhand.h 2003-06-12 13:42:20.000000000 +0100 @@ -47,6 +47,9 @@ void handle_remove_player(struct packet_generic_integer *packet); void handle_ruleset_control(struct packet_ruleset_control *packet); void handle_ruleset_unit(struct packet_ruleset_unit *p); +void handle_ruleset_modifier_type( + struct packet_ruleset_modifier_type *p); +void handle_ruleset_modifier(struct packet_ruleset_modifier *p); void handle_ruleset_tech(struct packet_ruleset_tech *p); void handle_ruleset_building(struct packet_ruleset_building *p); void handle_ruleset_terrain(struct packet_ruleset_terrain *p); diff -Nur -Xfreecivdiff.ignore freeciv-patched/common/capstr.c freeciv-compunit/common/capstr.c --- freeciv-patched/common/capstr.c 2003-06-12 13:39:42.000000000 +0100 +++ freeciv-compunit/common/capstr.c 2003-06-12 13:47:33.000000000 +0100 @@ -78,7 +78,7 @@ "city_struct_minor_cleanup obsolete_last class_legend " \ "+impr_req +waste +fastfocus +continent +small_dipl " \ "+no_nation_selected +diplomacy +no_extra_tiles" \ - "+diplomacy2 +citizens_style impr_gen" + "+diplomacy2 +citizens_style impr_gen compounds" /* "+1.14.0" is protocol for 1.14.0 release. * * "conn_info" is sending the conn_id field. To preserve compatability diff -Nur -Xfreecivdiff.ignore freeciv-patched/common/game.h freeciv-compunit/common/game.h --- freeciv-patched/common/game.h 2003-06-12 13:39:42.000000000 +0100 +++ freeciv-compunit/common/game.h 2003-06-12 13:42:20.000000000 +0100 @@ -152,6 +152,10 @@ int num_unit_types; int num_impr_types; int num_tech_types; /* including A_NONE */ + int num_unit_modifier_types; + int num_unit_modifiers; + int num_gov_modifier_types; + int num_gov_modifiers; int government_count; int default_government; diff -Nur -Xfreecivdiff.ignore freeciv-patched/common/government.c freeciv-compunit/common/government.c --- freeciv-patched/common/government.c 2003-06-12 13:39:42.000000000 +0100 +++ freeciv-compunit/common/government.c 2003-06-12 13:47:59.000000000 +0100 @@ -19,9 +19,11 @@ #include #include +#include "fcintl.h" #include "game.h" #include "log.h" #include "mem.h" +#include "member.h" #include "player.h" #include "shared.h" #include "support.h" @@ -59,6 +61,8 @@ */ struct government *governments = NULL; +struct modifier_type gov_modifier_types[MAX_MODS]; +struct modifier *gov_modifiers = NULL; struct ai_gov_tech_hint ai_gov_tech_hints[MAX_NUM_TECH_LIST]; @@ -66,7 +70,7 @@ "(unused)", "Revolution_When_Unhappy", "Has_Senate", "Unbribable", "Inspires_Partisans", "Rapture_City_Growth", "Fanatic_Troops", "No_Unhappy_Citizens", "Convert_Tithes_To_Money", - "Reduced_Research" + "Reduced_Research", "CanModify" }; static const char *hint_names[] = { "Is_Nice", "Favors_Growth" @@ -143,6 +147,25 @@ return NULL; } +int find_gov_modifier_by_name(const char *s) +{ + return find_modifier_by_name(s, gov_modifiers, game.num_gov_modifiers); +} + +bool government_has_modifier(struct government *gov, int govmod) +{ + if (gov && gov->basetype != G_MAGIC) { + int i; + + for (i = 0; i < game.num_gov_modifier_types; ++i) { + if (gov->modifiers[i] == govmod) { + return TRUE; + } + } + } + return FALSE; +} + /*************************************************************** ... ***************************************************************/ @@ -316,3 +339,226 @@ governments = NULL; game.government_count = 0; } + +static void set_city_cost(void *structpt, unsigned long offset, + const size_t size, const char *val) +{ + int *member = FC_STRUCT_MEMBER_P(int, structpt, offset); + + if (mystrcasecmp(val, "City_Size") == 0) { + *member = G_CITY_SIZE_FREE; + } else { + *member = atoi(val); + } +} + +static void read_city_cost(void *structpt, unsigned long offset, + const size_t size, struct section_file *file, + const char *sec, const char *membername) +{ + char *sval; + + sval = secfile_lookup_str(file, "%s.%s", sec, membername); + set_city_cost(structpt, offset, size, sval); +} + +#define FC_GOV_OFFSET(member) \ + FC_STRUCT_OFFSET(struct government, member) +#define FC_GOV_SIZE(member) \ + FC_MEMBER_SIZE(struct government, member) + +static struct members gov_members[] = { + { "name", + FC_GOV_OFFSET(name_orig), + FC_GOV_SIZE(name_orig), + NULL, set_string, get_string, binary_string }, + { "graphic", FC_GOV_OFFSET(graphic_str), FC_GOV_SIZE(graphic_str), + read_string, set_string, get_string, binary_string }, + { "graphic_alt", FC_GOV_OFFSET(graphic_alt), FC_GOV_SIZE(graphic_alt), + read_string, set_string, get_string, binary_string }, + { "tech_req", FC_GOV_OFFSET(required_tech), + FC_GOV_SIZE(required_tech), + NULL, set_tech, get_tech, NULL }, + { "martial_law_max", FC_GOV_OFFSET(martial_law_max), + FC_GOV_SIZE(martial_law_max), + read_int, set_int, get_int, binary_int }, + { "martial_law_per", FC_GOV_OFFSET(martial_law_per), + FC_GOV_SIZE(martial_law_per), + read_int, set_int, get_int, binary_int }, + { "max_single_rate", FC_GOV_OFFSET(max_rate), FC_GOV_SIZE(max_rate), + read_int, set_int, get_int, binary_int }, + { "civil_war_chance", FC_GOV_OFFSET(civil_war), FC_GOV_SIZE(civil_war), + read_int, set_int, get_int, binary_int }, + { "empire_size_mod", FC_GOV_OFFSET(empire_size_mod), + FC_GOV_SIZE(empire_size_mod), + read_int, set_int, get_int, binary_int }, + { "empire_size_inc", FC_GOV_OFFSET(empire_size_inc), + FC_GOV_SIZE(empire_size_inc), + read_int, set_int, get_int, binary_int }, + { "rapture_size", FC_GOV_OFFSET(rapture_size), FC_GOV_SIZE(rapture_size), + read_int, set_int, get_int, binary_int }, + { "unit_free_unhappy", FC_GOV_OFFSET(free_happy), + FC_GOV_SIZE(free_happy), + read_city_cost, set_city_cost, get_int, binary_int }, + { "unit_free_shield", FC_GOV_OFFSET(free_shield), + FC_GOV_SIZE(free_shield), + read_city_cost, set_city_cost, get_int, binary_int }, + { "unit_free_food", FC_GOV_OFFSET(free_food), + FC_GOV_SIZE(free_food), + read_city_cost, set_city_cost, get_int, binary_int }, + { "unit_free_gold", FC_GOV_OFFSET(free_gold), + FC_GOV_SIZE(free_gold), + read_city_cost, set_city_cost, get_int, binary_int }, + { "unit_unhappy_factor", FC_GOV_OFFSET(unit_happy_cost_factor), + FC_GOV_SIZE(unit_happy_cost_factor), + read_int, set_int, get_int, binary_int }, + { "unit_shield_factor", FC_GOV_OFFSET(unit_shield_cost_factor), + FC_GOV_SIZE(unit_shield_cost_factor), + read_int, set_int, get_int, binary_int }, + { "unit_food_factor", FC_GOV_OFFSET(unit_food_cost_factor), + FC_GOV_SIZE(unit_food_cost_factor), + read_int, set_int, get_int, binary_int }, + { "unit_gold_factor", FC_GOV_OFFSET(unit_gold_cost_factor), + FC_GOV_SIZE(unit_gold_cost_factor), + read_int, set_int, get_int, binary_int }, + { "corruption_level", FC_GOV_OFFSET(corruption_level), + FC_GOV_SIZE(corruption_level), + read_int, set_int, get_int, binary_int }, + { "corruption_modifier", FC_GOV_OFFSET(corruption_modifier), + FC_GOV_SIZE(corruption_modifier), + read_int, set_int, get_int, binary_int }, + { "corruption_fixed_distance", FC_GOV_OFFSET(fixed_corruption_distance), + FC_GOV_SIZE(fixed_corruption_distance), + read_int, set_int, get_int, binary_int }, + { "corruption_distance_factor", FC_GOV_OFFSET(corruption_distance_factor), + FC_GOV_SIZE(corruption_distance_factor), + read_int, set_int, get_int, binary_int }, + { "corruption_extra_distance", FC_GOV_OFFSET(extra_corruption_distance), + FC_GOV_SIZE(extra_corruption_distance), + read_int, set_int, get_int, binary_int }, + { "trade_penalty", FC_GOV_OFFSET(trade_before_penalty), + FC_GOV_SIZE(trade_before_penalty), + read_int, set_int, get_int, binary_int }, + { "shield_penalty", FC_GOV_OFFSET(shields_before_penalty), + FC_GOV_SIZE(shields_before_penalty), + read_int, set_int, get_int, binary_int }, + { "food_penalty", FC_GOV_OFFSET(food_before_penalty), + FC_GOV_SIZE(food_before_penalty), + read_int, set_int, get_int, binary_int }, + { "celeb_trade_penalty", FC_GOV_OFFSET(celeb_trade_before_penalty), + FC_GOV_SIZE(celeb_trade_before_penalty), + read_int, set_int, get_int, binary_int }, + { "celeb_shield_penalty", FC_GOV_OFFSET(celeb_shields_before_penalty), + FC_GOV_SIZE(celeb_shields_before_penalty), + read_int, set_int, get_int, binary_int }, + { "celeb_food_penalty", FC_GOV_OFFSET(celeb_food_before_penalty), + FC_GOV_SIZE(celeb_food_before_penalty), + read_int, set_int, get_int, binary_int }, + { "trade_bonus", FC_GOV_OFFSET(trade_bonus), + FC_GOV_SIZE(trade_bonus), + read_int, set_int, get_int, binary_int }, + { "shield_bonus", FC_GOV_OFFSET(shield_bonus), + FC_GOV_SIZE(shield_bonus), + read_int, set_int, get_int, binary_int }, + { "food_bonus", FC_GOV_OFFSET(food_bonus), + FC_GOV_SIZE(food_bonus), + read_int, set_int, get_int, binary_int }, + { "celeb_trade_bonus", FC_GOV_OFFSET(celeb_trade_bonus), + FC_GOV_SIZE(celeb_trade_bonus), + read_int, set_int, get_int, binary_int }, + { "celeb_shield_bonus", FC_GOV_OFFSET(celeb_shield_bonus), + FC_GOV_SIZE(celeb_shield_bonus), + read_int, set_int, get_int, binary_int }, + { "celeb_food_bonus", FC_GOV_OFFSET(celeb_food_bonus), + FC_GOV_SIZE(celeb_food_bonus), + read_int, set_int, get_int, binary_int }, + { NULL, 0, 0, NULL, NULL, NULL, NULL } +}; + +void gov_copy_members(struct government *dest, const struct government *src) +{ + copy_members((void *)dest, (const void *)src, gov_members); +} + +void gov_read_members(struct government *gov, struct section_file *file, + const char *sec) +{ + read_members((void *)gov, gov_members, file, sec); +} + +static void ApplyGovModAction(struct government *gov, char *action) +{ + apply_action((void *)gov, gov_members, action); +} + +/*************************************************************** +... +***************************************************************/ +int form_compound_gov(const struct player *pplayer, const char *name, + const int basetype, const int modifiers[MAX_MODS]) +{ + struct government *gov = NULL, *base; + struct modifier *mod; + int id = -1, i; + + if (pplayer) { + id = pplayer->government; + gov = get_gov_pplayer(pplayer); + } + if (!pplayer || gov->basetype == G_MAGIC) { + id = game.government_count++; + if (id >= G_MAGIC) { + freelog(LOG_FATAL, "form_compound_gov: out of government types"); + exit(EXIT_FAILURE); + } + + governments = (struct government *)fc_realloc(governments, + game.government_count + * sizeof(struct government)); + gov = &governments[id]; + gov->helptext = NULL; + gov->index = id; + } else if (pplayer) { + government_free(gov); + } + base = &governments[basetype]; + gov_copy_members(gov, base); + gov->effect = NULL; + append_effects(&gov->effect, base->effect); + gov->flags = base->flags; + gov->hints = base->hints; + gov->subgoal = base->subgoal; + gov->num_ruler_titles = base->num_ruler_titles; + gov->ruler_titles = fc_calloc(gov->num_ruler_titles, + sizeof(struct ruler_title)); + for (i = 0; i < gov->num_ruler_titles; ++i) { + struct ruler_title *fromtitle = &(base->ruler_titles[i]); + struct ruler_title *totitle = &(gov->ruler_titles[i]); + + totitle->nation = fromtitle->nation; + sz_strlcpy(totitle->male_title, fromtitle->male_title); + sz_strlcpy(totitle->female_title, fromtitle->female_title); + } + gov->basetype = basetype; + for (i = 0; i < game.num_gov_modifier_types; ++i) { + gov->modifiers[i] = modifiers[i]; + } + gov->required_tech = A_NONE; + gov->name_orig[0] = '\0'; + for (i = 0; i < game.num_gov_modifier_types; ++i) { + if (gov->modifiers[i] < U_LAST) { + mod = &gov_modifiers[gov->modifiers[i]]; + ApplyGovModAction(gov, mod->action); + } + } + for (i = 0; i < game.num_gov_modifier_types; ++i) { + if (gov->modifiers[i] < U_LAST) { + mod = &gov_modifiers[gov->modifiers[i]]; + ApplyGovModAction(gov, mod->final_action); + append_effects(&gov->effect, mod->effect); + } + } + sz_strlcpy(gov->name, _(gov->name_orig)); + + return id; +} diff -Nur -Xfreecivdiff.ignore freeciv-patched/common/government.h freeciv-compunit/common/government.h --- freeciv-patched/common/government.h 2003-06-12 13:39:42.000000000 +0100 +++ freeciv-compunit/common/government.h 2003-06-12 13:42:20.000000000 +0100 @@ -14,11 +14,13 @@ #define FC__GOVERNMENT_H #include "shared.h" +#include "modifier.h" struct city; struct player; struct Sprite; /* opaque; client-gui specific */ struct impr_effect; +struct section_file; #define G_MAGIC (127) /* magic constant, used as flag value */ @@ -39,6 +41,7 @@ G_CONVERT_TITHES_TO_MONEY, /* tithes to money, needed by fundamentalism */ G_REDUCED_RESEARCH, /* penalty for research, needed by fundamentalism */ + G_CAN_MODIFY, /* can apply government modifiers */ G_LAST_FLAG }; #define G_FIRST_FLAG G_BUILD_VETERAN_DIPLOMAT @@ -156,6 +159,9 @@ struct Sprite *sprite; struct impr_effect *effect; /* list; .type==EFT_LAST terminated */ + + int basetype; /* if !G_MAGIC, government modifiers are applied */ + int modifiers[MAX_MODS]; char *helptext; }; @@ -172,6 +178,8 @@ }; extern struct government *governments; +extern struct modifier_type gov_modifier_types[MAX_MODS]; +extern struct modifier *gov_modifiers; extern struct ai_gov_tech_hint ai_gov_tech_hints[MAX_NUM_TECH_LIST]; /* like game.rtech lists, A_LAST terminated (for .tech) @@ -182,6 +190,8 @@ struct government *get_gov_pcity(struct city *pcity); struct government *find_government_by_name(const char *name); +int find_gov_modifier_by_name(const char *s); +bool government_has_modifier(struct government *gov, int govmod); enum government_flag_id government_flag_from_str(const char *s); bool government_has_flag(const struct government *gov, @@ -201,5 +211,10 @@ const char *male, const char *female); void governments_alloc(int num); void governments_free(void); +void gov_copy_members(struct government *dest, const struct government *src); +void gov_read_members(struct government *gov, struct section_file *file, + const char *sec); +int form_compound_gov(const struct player *pplayer, const char *name, + const int basetype, const int modifiers[MAX_MODS]); #endif /* FC__GOVERNMENT_H */ diff -Nur -Xfreecivdiff.ignore freeciv-patched/common/improvement.c freeciv-compunit/common/improvement.c --- freeciv-patched/common/improvement.c 2003-06-12 13:39:42.000000000 +0100 +++ freeciv-compunit/common/improvement.c 2003-06-12 13:42:20.000000000 +0100 @@ -1035,6 +1035,12 @@ freelog(LOG_DEBUG, "Effect requires a government"); return FALSE; } + if (imeff->cond_govmod != game.num_gov_modifiers && pplayer + && !government_has_modifier(get_gov_pplayer(pplayer), + imeff->cond_govmod)) { + freelog(LOG_DEBUG, "Effect requires a government modifier"); + return FALSE; + } if (pplayer && get_invention(pplayer, imeff->cond_adv) != TECH_KNOWN) { freelog(LOG_DEBUG, "Effect requires a future tech"); return FALSE; @@ -1457,3 +1463,30 @@ } } } + +void append_effects(struct impr_effect **dest, struct impr_effect *src) +{ + int numsrc = 0, numdest = 0, numeff; + struct impr_effect *eff; + + for (eff = *dest; eff && eff->type != EFT_LAST; ++eff) { + numdest++; + } + for (eff = src; eff && eff->type != EFT_LAST; ++eff) { + numsrc++; + } + numeff = numdest + numsrc; + + if (numeff > MAX_EFFECTS) { + freelog(LOG_FATAL, "MAX_EFFECTS exceeded"); + exit(EXIT_FAILURE); + } + + if (numsrc) { + *dest = fc_realloc(*dest, (numeff + 1) * sizeof(struct impr_effect)); + memcpy(*dest + numdest, src, (numsrc + 1) * sizeof(struct impr_effect)); + } else if (!*dest) { + *dest = fc_malloc(sizeof(struct impr_effect)); + (*dest)->type = EFT_LAST; + } +} diff -Nur -Xfreecivdiff.ignore freeciv-patched/common/improvement.h freeciv-compunit/common/improvement.h --- freeciv-patched/common/improvement.h 2003-06-12 13:39:42.000000000 +0100 +++ freeciv-compunit/common/improvement.h 2003-06-12 13:48:55.000000000 +0100 @@ -201,6 +201,7 @@ * center tile */ Impr_Type_id cond_bldg; /* B_LAST = unconditional */ int cond_gov; /* game.government_count = unconditional */ + int cond_govmod; /* game.num_gov_modifiers = unconditional */ Tech_Type_id cond_adv; /* A_NONE = unconditional; A_LAST = never */ enum effect_type cond_eff; /* EFT_LAST = unconditional */ Unit_Class_id aff_unit; /* UCL_LAST = all */ @@ -440,6 +441,7 @@ struct ceff_vector *get_eff_city(struct city *pcity); void remove_global_effects(Impr_Type_id impr, struct player *pplayer); void add_global_effects(Impr_Type_id impr, struct player *pplayer); +void append_effects(struct impr_effect **dest, struct impr_effect *src); void allot_island_improvs(void); void improvements_update_obsolete(void); diff -Nur -Xfreecivdiff.ignore freeciv-patched/common/Makefile.am freeciv-compunit/common/Makefile.am --- freeciv-patched/common/Makefile.am 2003-06-07 19:58:26.000000000 +0100 +++ freeciv-compunit/common/Makefile.am 2003-06-12 13:42:20.000000000 +0100 @@ -63,6 +63,10 @@ pqueue.h \ mem.c \ mem.h \ + member.c \ + member.h \ + modifier.c \ + modifier.h \ rand.c \ rand.h \ registry.c \ diff -Nur -Xfreecivdiff.ignore freeciv-patched/common/member.c freeciv-compunit/common/member.c --- freeciv-patched/common/member.c 1970-01-01 01:00:00.000000000 +0100 +++ freeciv-compunit/common/member.c 2003-06-12 13:42:20.000000000 +0100 @@ -0,0 +1,216 @@ +/********************************************************************** + Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "member.h" +#include "support.h" + +void read_sound(void *structpt, unsigned long offset, const size_t size, + struct section_file *file, + const char *sec, const char *membername) +{ + char *member = FC_STRUCT_MEMBER_P(char, structpt, offset); + + mystrlcpy(member, + secfile_lookup_str_default(file, "-", "%s.%s", sec, membername), + size); +//printf("Read %s -> (sound) %s\n", membername, member); +} + +void read_string(void *structpt, unsigned long offset, const size_t size, + struct section_file *file, + const char *sec, const char *membername) +{ + char *member = FC_STRUCT_MEMBER_P(char, structpt, offset); + + mystrlcpy(member, + secfile_lookup_str(file, "%s.%s", sec, membername), + size); +//printf("Read %s -> (string) %s\n", membername, member); +} + +void set_string(void *structpt, unsigned long offset, const size_t size, + const char *val) +{ + char *member = FC_STRUCT_MEMBER_P(char, structpt, offset); + + mystrlcpy(member, val, size); +} + +void get_string(const void *structpt, unsigned long offset, + struct memberdata *data) +{ + char *member = FC_STRUCT_MEMBER_P(char, structpt, offset); + + sz_strlcpy(data->str, member); +} + +void binary_string(const char *arg1, const char *arg2, const char op, + struct memberdata *result) +{ + if (op == '+') { + sz_strlcpy(result->str, arg1); + sz_strlcat(result->str, arg2); + } +} + +void read_int(void *structpt, unsigned long offset, const size_t size, + struct section_file *file, + const char *sec, const char *membername) +{ + int *member = FC_STRUCT_MEMBER_P(int, structpt, offset); + + *member = secfile_lookup_int(file, "%s.%s", sec, membername); +//printf("Read %s -> (int) %d\n", membername, *member); +} + +void set_int(void *structpt, unsigned long offset, const size_t size, + const char *val) +{ + int *member = FC_STRUCT_MEMBER_P(int, structpt, offset); + + *member = atoi(val); +} + +void get_int(const void *structpt, unsigned long offset, + struct memberdata *data) +{ + int *member = FC_STRUCT_MEMBER_P(int, structpt, offset); + + my_snprintf(data->str, sizeof(data->str), "%d", *member); +} + +void binary_int(const char *arg1, const char *arg2, const char op, + struct memberdata *result) +{ + int int1, int2, ires; + + int1 = atoi(arg1); + int2 = atoi(arg2); + switch(op) { + case '+': + ires = int1 + int2; + break; + case '-': + ires = int1 - int2; + break; + case '*': + ires = int1 * int2; + break; + case '/': + ires = int1 / int2; + break; + default: + return; + } + my_snprintf(result->str, sizeof(result->str), "%d", ires); +} + +void read_tech(void *structpt, unsigned long offset, const size_t size, + struct section_file *file, + const char *sec, const char *membername) +{ +} + +void set_tech(void *structpt, unsigned long offset, const size_t size, + const char *val) +{ +} + +void get_tech(const void *structpt, unsigned long offset, + struct memberdata *data) +{ +} + +void copy_members(void *deststructpt, const void *srcstructpt, + const struct members *memberlist) +{ + const struct members *pt; + struct memberdata data; + + for (pt = memberlist; pt && pt->name; ++pt) { + pt->getfunc(srcstructpt, pt->offset, &data); + pt->setfunc(deststructpt, pt->offset, pt->size, data.str); + } +} + +void read_members(void *structpt, const struct members *memberlist, + struct section_file *file, const char *sec) +{ + const struct members *pt; + + for (pt = memberlist; pt && pt->name; ++pt) { + if (pt->readfunc) { + pt->readfunc(structpt, pt->offset, pt->size, file, sec, pt->name); + } + } +} + +void read_member(void *structpt, const struct members *memberlist, + const char *membername, struct section_file *file, + const char *sec) +{ + const struct members *pt; + + for (pt = memberlist; pt && pt->name; ++pt) { + if (strcmp(pt->name, membername) == 0 && pt->readfunc) { + pt->readfunc(structpt, pt->offset, pt->size, file, sec, pt->name); + return; + } + } +} + +void set_member(void *structpt, const struct members *memberlist, + const char *membername, const char *val) +{ + const struct members *pt; + + for (pt = memberlist; pt && pt->name; ++pt) { + if (strcmp(pt->name, membername) == 0) { + pt->setfunc(structpt, pt->offset, pt->size, val); + return; + } + } +} + +void binary_member(void *structpt, const struct members *memberlist, + const char *membername, const char *arg1, const char *arg2, + const char op, struct memberdata *result) +{ + const struct members *pt; + + for (pt = memberlist; pt && pt->name; ++pt) { + if (strcmp(pt->name, membername) == 0 && pt->binfunc) { + pt->binfunc(arg1, arg2, op, result); + return; + } + } +} + +void get_member(const void *structpt, const struct members *memberlist, + const char *membername, struct memberdata *data) +{ + const struct members *pt; + + for (pt = memberlist; pt && pt->name; ++pt) { + if (strcmp(pt->name, membername) == 0) { + pt->getfunc(structpt, pt->offset, data); + return; + } + } +} diff -Nur -Xfreecivdiff.ignore freeciv-patched/common/member.h freeciv-compunit/common/member.h --- freeciv-patched/common/member.h 1970-01-01 01:00:00.000000000 +0100 +++ freeciv-compunit/common/member.h 2003-06-12 13:42:20.000000000 +0100 @@ -0,0 +1,98 @@ +/********************************************************************** + Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +***********************************************************************/ +#ifndef FC__MEMBER_H +#define FC__MEMBER_H + +/* Functions for accessing structure members by name at runtime */ + +#include "registry.h" + +/* Macros for converting structure members to and from offsets - taken + * from GLib. + */ +#define FC_STRUCT_OFFSET(struct_type, member) \ + ((unsigned long) ((char *) &((struct_type *) 0)->member)) +#define FC_STRUCT_MEMBER_P(member_type, struct_p, struct_offset) \ + ((member_type *) ((char *)(struct_p) + (unsigned long)(struct_offset))) +#define FC_MEMBER_SIZE(struct_type, member) \ + (sizeof ((struct_type *) 0)->member) + +struct memberdata { + char str[400]; +}; + +typedef void (*MemberReadFunc)(void *structpt, unsigned long offset, + const size_t size, struct section_file *file, + const char *sec, const char *membername); +typedef void (*MemberSetFunc)(void *structpt, unsigned long offset, + const size_t size, const char *val); +typedef void (*MemberGetFunc)(const void *structpt, unsigned long offset, + struct memberdata *data); +typedef void (*MemberBinaryFunc)(const char *arg1, const char *arg2, + const char op, struct memberdata *result); + +struct members { + char *name; + unsigned long offset; + size_t size; + MemberReadFunc readfunc; + MemberSetFunc setfunc; + MemberGetFunc getfunc; + MemberBinaryFunc binfunc; +}; + +void read_sound(void *structpt, unsigned long offset, const size_t size, + struct section_file *file, + const char *sec, const char *membername); +void read_string(void *structpt, unsigned long offset, const size_t size, + struct section_file *file, + const char *sec, const char *membername); +void set_string(void *structpt, unsigned long offset, const size_t size, + const char *val); +void get_string(const void *structpt, unsigned long offset, + struct memberdata *data); +void binary_string(const char *arg1, const char *arg2, const char op, + struct memberdata *result); +void read_int(void *structpt, unsigned long offset, const size_t size, + struct section_file *file, + const char *sec, const char *membername); +void set_int(void *structpt, unsigned long offset, const size_t size, + const char *val); +void get_int(const void *structpt, unsigned long offset, + struct memberdata *data); +void binary_int(const char *arg1, const char *arg2, const char op, + struct memberdata *result); +void read_tech(void *structpt, unsigned long offset, const size_t size, + struct section_file *file, + const char *sec, const char *membername); +void set_tech(void *structpt, unsigned long offset, const size_t size, + const char *val); +void get_tech(const void *structpt, unsigned long offset, + struct memberdata *data); + +void binary_member(void *structpt, const struct members *memberlist, + const char *membername, const char *arg1, const char *arg2, + const char op, struct memberdata *result); +void copy_members(void *deststructpt, const void *srcstructpt, + const struct members *memberlist); +void read_members(void *structpt, const struct members *memberlist, + struct section_file *file, const char *sec); +void read_member(void *structpt, const struct members *memberlist, + const char *membername, struct section_file *file, + const char *sec); +void set_member(void *structpt, const struct members *memberlist, + const char *membername, const char *val); +void get_member(const void *structpt, const struct members *memberlist, + const char *membername, struct memberdata *data); + +#endif /* FC__MEMBER_H */ diff -Nur -Xfreecivdiff.ignore freeciv-patched/common/modifier.c freeciv-compunit/common/modifier.c --- freeciv-patched/common/modifier.c 1970-01-01 01:00:00.000000000 +0100 +++ freeciv-compunit/common/modifier.c 2003-06-12 13:42:20.000000000 +0100 @@ -0,0 +1,56 @@ +/********************************************************************** + Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +***********************************************************************/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "modifier.h" +#include "shared.h" +#include "support.h" + +/************************************************************************** + Convert modifier_type names to int; case insensitive; + returns -1 if can't match. +**************************************************************************/ +int modifier_type_from_str(const char *s, + struct modifier_type *modifier_types, + int num_mod_types) +{ + int i; + for (i = 0; i < num_mod_types; ++i) { + if (mystrcasecmp(modifier_types[i].name, s) == 0) { + return i; + } + } + return -1; +} + +/************************************************************************** +Does a linear search of modifiers[].name +Returns -1 if none match. +**************************************************************************/ +int find_modifier_by_name(const char *s, + struct modifier *modifiers, + int num_mods) +{ + int i; + for (i = 0; i < num_mods; ++i) { + if (mystrcasecmp(modifiers[i].name, s) == 0) { + return i; + } + } + return -1; +} diff -Nur -Xfreecivdiff.ignore freeciv-patched/common/modifier.h freeciv-compunit/common/modifier.h --- freeciv-patched/common/modifier.h 1970-01-01 01:00:00.000000000 +0100 +++ freeciv-compunit/common/modifier.h 2003-06-12 13:42:20.000000000 +0100 @@ -0,0 +1,48 @@ +/********************************************************************** + Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +***********************************************************************/ +#ifndef FC__MODIFIER_H +#define FC__MODIFIER_H + +#include "shared.h" + +struct impr_effect; + +/* Maximum number of modifier types */ +#define MAX_MODS 16 + +struct modifier { + char name[MAX_LEN_NAME]; + int type; + int tech_requirement; + int obsoleted_by; + char *action; + char *final_action; + struct impr_effect *effect; /* list; .type==EFT_LAST terminated */ +}; + +struct modifier_type { + char name[MAX_LEN_NAME]; + int id; + int tech_requirement; + int obsoleted_by; + bool must_use; +}; + +int modifier_type_from_str(const char *s, + struct modifier_type *modifier_types, + int num_mod_types); +int find_modifier_by_name(const char *s, + struct modifier *modifiers, + int num_mods); + +#endif /* FC__MODIFIER_H */ diff -Nur -Xfreecivdiff.ignore freeciv-patched/common/packets.c freeciv-compunit/common/packets.c --- freeciv-patched/common/packets.c 2003-06-12 13:39:42.000000000 +0100 +++ freeciv-compunit/common/packets.c 2003-06-12 15:18:30.000000000 +0100 @@ -38,6 +38,7 @@ #include "dataio.h" #include "events.h" #include "fcintl.h" +#include "government.h" #include "log.h" #include "mem.h" #include "support.h" @@ -425,6 +426,12 @@ return receive_packet_ruleset_government_ruler_title(pc); case PACKET_RULESET_NATION: return receive_packet_ruleset_nation(pc); + case PACKET_RULESET_MODIFIER_TYPE: + return receive_packet_ruleset_modifier_type(pc); + case PACKET_RULESET_MODIFIER: + return receive_packet_ruleset_modifier(pc); + case PACKET_REQUEST_COMPOUND: + return receive_packet_request_compound(pc); case PACKET_RULESET_CITY: return receive_packet_ruleset_city(pc); case PACKET_RULESET_GAME: @@ -1890,6 +1897,12 @@ if (has_capability("impr_gen", pc->capability)) { dio_put_uint8(&dout, packet->num_unit_flags); } + if (has_capability("compounds", pc->capability)) { + dio_put_uint8(&dout, packet->num_unit_modifier_types); + dio_put_uint8(&dout, packet->num_unit_modifiers); + dio_put_uint8(&dout, packet->num_gov_modifier_types); + dio_put_uint8(&dout, packet->num_gov_modifiers); + } dio_put_uint8(&dout, packet->num_unit_types); dio_put_uint8(&dout, packet->num_impr_types); dio_put_uint8(&dout, packet->num_tech_types); @@ -1941,6 +1954,15 @@ } else { packet->num_unit_flags = F_LAST; } + if (has_capability("compounds", pc->capability)) { + dio_get_uint8(&din, &packet->num_unit_modifier_types); + dio_get_uint8(&din, &packet->num_unit_modifiers); + dio_get_uint8(&din, &packet->num_gov_modifier_types); + dio_get_uint8(&din, &packet->num_gov_modifiers); + } else { + packet->num_unit_modifier_types = packet->num_unit_modifiers = 0; + packet->num_gov_modifier_types = packet->num_gov_modifiers = 0; + } dio_get_uint8(&din, &packet->num_unit_types); dio_get_uint8(&din, &packet->num_impr_types); dio_get_uint8(&din, &packet->num_tech_types); @@ -2009,6 +2031,13 @@ if (has_capability("impr_gen", pc->capability)) { dio_put_effects(&dout, pc, packet->effect); } + if (has_capability("compounds", pc->capability)) { + int i; + dio_put_uint16(&dout, packet->basetype); + for (i = 0; i < MAX_MODS; ++i) { + dio_put_uint16(&dout, packet->modifiers[i]); + } + } /* This must be last, so client can determine length: */ if(packet->helptext) { @@ -2076,6 +2105,15 @@ packet->effect = fc_malloc(sizeof(struct impr_effect)); packet->effect[0].type = EFT_LAST; } + if (has_capability("compounds", pc->capability)) { + int i; + dio_get_uint16(&din, &packet->basetype); + for (i = 0; i < MAX_MODS; ++i) { + dio_get_uint16(&din, &packet->modifiers[i]); + } + } else { + packet->basetype = U_LAST; + } len = dio_input_remaining(&din); if (len > 0) { @@ -2160,6 +2198,123 @@ /************************************************************************** ... **************************************************************************/ +int send_packet_ruleset_modifier_type(struct connection *pc, + const struct packet_ruleset_modifier_type *packet) +{ + SEND_PACKET_START(PACKET_RULESET_MODIFIER_TYPE); + + dio_put_uint8(&dout, packet->id); + dio_put_bool8(&dout, packet->is_gov); + dio_put_uint8(&dout, packet->basetype); + dio_put_string(&dout, packet->name); + dio_put_uint8(&dout, packet->tech_requirement); + dio_put_bool8(&dout, packet->must_use); + + SEND_PACKET_END; +} + +/************************************************************************** +... +**************************************************************************/ +struct packet_ruleset_modifier_type * +receive_packet_ruleset_modifier_type(struct connection *pc) +{ + RECEIVE_PACKET_START(packet_ruleset_modifier_type, packet); + + dio_get_uint8(&din, &packet->id); + dio_get_bool8(&din, &packet->is_gov); + dio_get_uint8(&din, &packet->basetype); + dio_get_string(&din, packet->name, sizeof(packet->name)); + dio_get_uint8(&din, &packet->tech_requirement); + dio_get_bool8(&din, &packet->must_use); + + RECEIVE_PACKET_END(packet); +} + +/************************************************************************** +... +**************************************************************************/ +int send_packet_ruleset_modifier(struct connection *pc, + const struct packet_ruleset_modifier *packet) +{ + SEND_PACKET_START(PACKET_RULESET_MODIFIER); + + dio_put_uint8(&dout, packet->id); + dio_put_bool8(&dout, packet->is_gov); + dio_put_string(&dout, packet->name); + dio_put_uint8(&dout, packet->type); + dio_put_uint8(&dout, packet->tech_requirement); + if (has_capability("impr_gen", pc->capability)) { + dio_put_effects(&dout, pc, packet->effect); + } + + SEND_PACKET_END; +} + +/************************************************************************** +... +**************************************************************************/ +struct packet_ruleset_modifier * +receive_packet_ruleset_modifier(struct connection *pc) +{ + RECEIVE_PACKET_START(packet_ruleset_modifier, packet); + + dio_get_uint8(&din, &packet->id); + dio_get_bool8(&din, &packet->is_gov); + dio_get_string(&din, packet->name, sizeof(packet->name)); + dio_get_uint8(&din, &packet->type); + dio_get_uint8(&din, &packet->tech_requirement); + if (has_capability("impr_gen", pc->capability)) { + dio_get_effects(&din, pc, &packet->effect); + } else { + packet->effect = fc_malloc(sizeof(struct impr_effect)); + packet->effect[0].type = EFT_LAST; + } + + RECEIVE_PACKET_END(packet); +} + +/************************************************************************** +... +**************************************************************************/ +int send_packet_request_compound(struct connection *pc, + struct packet_request_compound *req) +{ + int i; + SEND_PACKET_START(PACKET_REQUEST_COMPOUND); + + dio_put_bool8(&dout, req->is_gov); + dio_put_string(&dout, req->name); + dio_put_uint16(&dout, req->basetype); + for (i = 0; i < MAX_MODS; ++i) { + dio_put_uint16(&dout, req->modifiers[i]); + } + + SEND_PACKET_END; +} + +/************************************************************************** +... +**************************************************************************/ +struct packet_request_compound * +receive_packet_request_compound(struct connection *pc) +{ + int i; + RECEIVE_PACKET_START(packet_request_compound, packet); + + dio_get_bool8(&din, &packet->is_gov); + dio_get_string(&din, packet->name, sizeof(packet->name)); + dio_get_uint16(&din, &packet->basetype); + for (i = 0; i < MAX_MODS; ++i) { + dio_get_uint16(&din, &packet->modifiers[i]); + } + + RECEIVE_PACKET_END(packet); +} + +/************************************************************************** +... +**************************************************************************/ static void dio_put_effects(struct data_out *dout, struct connection *pc, const struct impr_effect *effect) @@ -2184,6 +2339,9 @@ } dio_put_uint8(dout, eff->cond_bldg); dio_put_uint8(dout, eff->cond_gov); + if (has_capability("compounds", pc->capability)) { + dio_put_uint8(dout, eff->cond_govmod); + } dio_put_uint8(dout, eff->cond_adv); dio_put_uint8(dout, eff->cond_eff); dio_put_uint8(dout, eff->aff_unit); @@ -2264,6 +2422,9 @@ } dio_get_uint8(din, &(effect[inx].cond_bldg)); dio_get_uint8(din, &(effect[inx].cond_gov)); + if (has_capability("compounds", pc->capability)) { + dio_get_uint8(din, &(effect[inx].cond_govmod)); + } dio_get_uint8(din, &(effect[inx].cond_adv)); dio_get_uint8(din, (int *)&(effect[inx].cond_eff)); dio_get_uint8(din, (int *)&(effect[inx].aff_unit)); @@ -2586,6 +2747,13 @@ if (has_capability("impr_gen", pc->capability)) { dio_put_effects(&dout, pc, packet->effect); } + if (has_capability("compounds", pc->capability)) { + int i; + dio_put_uint16(&dout, packet->basetype); + for (i = 0; i < MAX_MODS; ++i) { + dio_put_uint16(&dout, packet->modifiers[i]); + } + } /* This must be last, so client can determine length: */ if(packet->helptext) { @@ -2686,6 +2854,15 @@ packet->effect = fc_malloc(sizeof(struct impr_effect)); packet->effect[0].type = EFT_LAST; } + if (has_capability("compounds", pc->capability)) { + int i; + dio_get_uint16(&din, &packet->basetype); + for (i = 0; i < MAX_MODS; ++i) { + dio_get_uint16(&din, &packet->modifiers[i]); + } + } else { + packet->basetype = G_MAGIC; + } len = dio_input_remaining(&din); if (len > 0) { diff -Nur -Xfreecivdiff.ignore freeciv-patched/common/packets.h freeciv-compunit/common/packets.h --- freeciv-patched/common/packets.h 2003-06-12 13:39:42.000000000 +0100 +++ freeciv-compunit/common/packets.h 2003-06-12 14:11:52.000000000 +0100 @@ -127,6 +127,9 @@ PACKET_FREEZE_HINT, PACKET_THAW_HINT, PACKET_PING_INFO, + PACKET_RULESET_MODIFIER_TYPE, + PACKET_RULESET_MODIFIER, + PACKET_REQUEST_COMPOUND, PACKET_LAST /* leave this last */ }; @@ -571,6 +574,10 @@ int num_unit_types; int num_impr_types; int num_tech_types; + int num_unit_modifier_types; + int num_unit_modifiers; + int num_gov_modifier_types; + int num_gov_modifiers; struct { int cathedral_plus; int cathedral_minus; @@ -627,6 +634,9 @@ int paratroopers_mr_sub; struct impr_effect *effect; + int basetype; + int modifiers[MAX_MODS]; + /* Following is a pointer to malloced memory; on the server, it points to putype->helptext, malloced earlier; on the client, it is malloced when packet received, and then putype->helptext @@ -635,6 +645,33 @@ char *helptext; }; +struct packet_ruleset_modifier_type { + bool is_gov; + int id; + char name[MAX_LEN_NAME]; + int basetype; + int tech_requirement; + bool must_use; +}; + +struct packet_ruleset_modifier { + bool is_gov; + int id; + char name[MAX_LEN_NAME]; + int type; + int tech_requirement; + char *action; + char *final_action; + struct impr_effect *effect; +}; + +struct packet_request_compound { + bool is_gov; + int basetype; + char name[MAX_LEN_NAME]; + int modifiers[MAX_MODS]; +}; + struct packet_ruleset_tech { int id, req[2]; /* indices for advances[] */ int flags; @@ -728,6 +765,9 @@ int empire_size_mod; int empire_size_inc; int rapture_size; + + int basetype; + int modifiers[MAX_MODS]; int unit_happy_cost_factor; int unit_shield_cost_factor; @@ -1060,6 +1100,19 @@ struct packet_ruleset_unit * receive_packet_ruleset_unit(struct connection *pc); +int send_packet_ruleset_modifier_type(struct connection *pc, + const struct packet_ruleset_modifier_type *packet); +struct packet_ruleset_modifier_type * +receive_packet_ruleset_modifier_type(struct connection *pc); +int send_packet_ruleset_modifier(struct connection *pc, + const struct packet_ruleset_modifier *packet); +struct packet_ruleset_modifier * +receive_packet_ruleset_modifier(struct connection *pc); +int send_packet_request_compound(struct connection *pc, + struct packet_request_compound *req); +struct packet_request_compound * +receive_packet_request_compound(struct connection *pc); + int send_packet_ruleset_tech(struct connection *pc, const struct packet_ruleset_tech *packet); struct packet_ruleset_tech * diff -Nur -Xfreecivdiff.ignore freeciv-patched/common/packets_lsend.c freeciv-compunit/common/packets_lsend.c --- freeciv-patched/common/packets_lsend.c 2003-06-07 19:58:26.000000000 +0100 +++ freeciv-compunit/common/packets_lsend.c 2003-06-12 13:42:20.000000000 +0100 @@ -239,6 +239,30 @@ conn_list_iterate_end; } +void lsend_packet_ruleset_modifier_type(struct conn_list *dest, + const struct packet_ruleset_modifier_type *packet) +{ + conn_list_iterate(*dest, pconn) + send_packet_ruleset_modifier_type(pconn, packet); + conn_list_iterate_end; +} + +void lsend_packet_ruleset_modifier(struct conn_list *dest, + const struct packet_ruleset_modifier *packet) +{ + conn_list_iterate(*dest, pconn) + send_packet_ruleset_modifier(pconn, packet); + conn_list_iterate_end; +} + +void lsend_packet_request_compound(struct conn_list *dest, + struct packet_request_compound *req) +{ + conn_list_iterate(*dest, pconn) + send_packet_request_compound(pconn, req); + conn_list_iterate_end; +} + void lsend_packet_ruleset_tech(struct conn_list *dest, const struct packet_ruleset_tech *packet) { diff -Nur -Xfreecivdiff.ignore freeciv-patched/common/packets_lsend.h freeciv-compunit/common/packets_lsend.h --- freeciv-patched/common/packets_lsend.h 2003-06-07 19:58:26.000000000 +0100 +++ freeciv-compunit/common/packets_lsend.h 2003-06-12 13:42:20.000000000 +0100 @@ -72,6 +72,12 @@ const struct packet_ruleset_control *packet); void lsend_packet_ruleset_unit(struct conn_list *dest, const struct packet_ruleset_unit *packet); +void lsend_packet_ruleset_modifier_type(struct conn_list *dest, + const struct packet_ruleset_modifier_type *packet); +void lsend_packet_ruleset_modifier(struct conn_list *dest, + const struct packet_ruleset_modifier *packet); +void lsend_packet_request_compound(struct conn_list *dest, + struct packet_request_compound *req); void lsend_packet_ruleset_tech(struct conn_list *dest, const struct packet_ruleset_tech *packet); void lsend_packet_ruleset_building(struct conn_list *dest, diff -Nur -Xfreecivdiff.ignore freeciv-patched/common/shared.c freeciv-compunit/common/shared.c --- freeciv-patched/common/shared.c 2003-06-07 19:58:26.000000000 +0100 +++ freeciv-compunit/common/shared.c 2003-06-12 13:42:20.000000000 +0100 @@ -186,7 +186,7 @@ Like strcspn but also handles quotes, i.e. *reject chars are ignored if they are inside single or double quotes. ***************************************************************/ -static size_t my_strcspn(const char *s, const char *reject) +size_t my_strcspn(const char *s, const char *reject) { bool in_single_quotes = FALSE, in_double_quotes = FALSE; size_t i, len = strlen(s); diff -Nur -Xfreecivdiff.ignore freeciv-patched/common/shared.h freeciv-compunit/common/shared.h --- freeciv-patched/common/shared.h 2003-06-07 19:58:27.000000000 +0100 +++ freeciv-compunit/common/shared.h 2003-06-12 13:42:20.000000000 +0100 @@ -136,6 +136,7 @@ char *create_centered_string(const char *s); +size_t my_strcspn(const char *s, const char *reject); char * get_option(const char *option_name,char **argv,int *i,int argc); bool is_option(const char *option_name,char *option); int get_tokens(const char *str, char **tokens, size_t num_tokens, diff -Nur -Xfreecivdiff.ignore freeciv-patched/common/unittype.c freeciv-compunit/common/unittype.c --- freeciv-patched/common/unittype.c 2003-06-12 13:39:42.000000000 +0100 +++ freeciv-compunit/common/unittype.c 2003-06-12 16:27:28.000000000 +0100 @@ -17,12 +17,16 @@ #include #include +#include #include "astring.h" #include "fcintl.h" #include "game.h" #include "government.h" +#include "log.h" #include "mem.h" +#include "member.h" +#include "modifier.h" #include "player.h" #include "shared.h" #include "support.h" @@ -30,7 +34,30 @@ #include "unittype.h" +struct atoken { + enum { + NULL_TOKEN, + OP_TOKEN, + EQUALS_TOKEN, + LEFTPAREN_TOKEN, + RIGHTPAREN_TOKEN, + IF_TOKEN, + STRING_TOKEN, + IDENT_TOKEN + } type; + char *str; + char optype; + bool has_equals; +}; + +char *action_getline(char **iter, struct astring *str); +void action_doline(void *structpt, struct members *memberlist, char *line); +void action_parsetokens(void *structpt, struct members *memberlist, + struct atoken *tokens, int numtokens); + struct unit_type unit_types[U_LAST]; +struct modifier_type unit_modifier_types[MAX_MODS]; +struct modifier *unit_modifiers = NULL; /* the unit_types array is now setup in: server/ruleset.c (for the server) client/packhand.c (for the client) @@ -52,9 +79,11 @@ "DefendOk", "DefendGood", "AttackFast", "AttackStrong", "Ferryboat", "Barbarian", "BarbarianTech", "BarbarianBoat", "BarbarianBuild", "BarbarianBuildTech", "BarbarianLeader", - "BarbarianSea", "BarbarianSeaTech" + "BarbarianSea", "BarbarianSeaTech", "CanModify" }; +static void ApplyUnitModAction(struct unit_type *u, char *action); + /************************************************************************** Returns 1 if the unit_type "exists" in this game, 0 otherwise. A unit_type doesn't exist if one of: @@ -379,6 +408,27 @@ } /************************************************************************** + Returns the unit type which is built from the given base type and unit + modifiers, or U_LAST if none match. +**************************************************************************/ +Unit_Type_id find_unit_type_by_modifiers(Unit_Type_id basetype, int *modifiers) +{ + unit_type_iterate(uid) { + int i; + if (unit_types[uid].basetype == basetype) { + for (i = 0; i < game.num_unit_modifier_types; ++i) { + if (unit_types[uid].modifiers[i] != modifiers[i]) { + break; + } else if (i == game.num_unit_modifier_types - 1) { + return uid; + } + } + } + } unit_type_iterate_end; + return U_LAST; +} + +/************************************************************************** Convert unit_move_type names to enum; case insensitive; returns 0 if can't match. **************************************************************************/ @@ -449,17 +499,31 @@ **************************************************************************/ bool can_player_build_unit_direct(struct player *p, Unit_Type_id id) { + struct unit_type *u; Impr_Type_id impr_req; Tech_Type_id tech_req; if (!unit_type_exists(id)) return FALSE; + u = &unit_types[id]; if (unit_type_flag(id, F_FANATIC) && !government_has_flag(get_gov_pplayer(p), G_FANATIC_TROOPS)) return FALSE; - if (get_invention(p,unit_types[id].tech_requirement)!=TECH_KNOWN) + if (get_invention(p, u->tech_requirement) != TECH_KNOWN) return FALSE; + /* Check tech requirements of unit modifiers if applicable */ + if (u->basetype != U_LAST) { + int i; + for (i = 0; i < game.num_unit_modifier_types; ++i) { + if (u->modifiers[i] < U_LAST + && get_invention(p, unit_modifiers[u->modifiers[i]].tech_requirement) + != TECH_KNOWN) { + return FALSE; + } + } + } + /* If the unit has a building requirement, we check to see if the player * can build that building. Note that individual cities may not have * that building, so they still may not be able to build the unit. */ @@ -654,3 +718,714 @@ unit_type_free(i); } unit_type_iterate_end; } + +/************************************************************************** + Convert unit_modifier_type names to int; case insensitive; + returns -1 if can't match. +**************************************************************************/ +int unit_modifier_type_from_str(const char *s) +{ + return modifier_type_from_str(s, unit_modifier_types, + game.num_unit_modifier_types); +} + +/************************************************************************** +Does a linear search of unit_modifiers[].name +Returns -1 if none match. +**************************************************************************/ +int find_unit_modifier_by_name(const char *s) +{ + return find_modifier_by_name(s, unit_modifiers, game.num_unit_modifiers); +} + +static void ensure_unique_unit_name(struct unit_type *utype) +{ + char *tmpname, *tmporig; + int mark = 2; + int maxlen = sizeof(utype->name) - 10; /* To allow for longer translations */ + int maxorig = sizeof(utype->name_orig) - 6; + + assert(maxlen > 0 && maxorig > 0); + tmpname = mystrdup(utype->name); + tmporig = mystrdup(utype->name_orig); + + /* Make sure that the suffix won't be truncated each time */ + if (strlen(tmpname) > maxlen) { + tmpname[maxlen - 1] = '\0'; + } + if (strlen(tmporig) > maxorig) { + tmporig[maxorig - 1] = '\0'; + } + + while (find_unit_type_by_name(utype->name) != U_LAST) { + my_snprintf(utype->name, sizeof(utype->name), _("%s Mk%d"), tmpname, + mark); + my_snprintf(utype->name_orig, sizeof(utype->name_orig), "%s Mk%d", + tmporig, mark++); + assert(mark < 100); + } + free(tmpname); + free(tmporig); +} + +Unit_Type_id form_compound_unit(const char *name, + const Unit_Type_id basetype, + const int modifiers[MAX_MODS]) +{ + Unit_Type_id id; + struct unit_type *u, *base; + struct modifier *mod; + int i; + + id = game.num_unit_types; + if (id >= U_LAST) { + freelog(LOG_FATAL, "form_compound_unit: out of unit types"); + exit(EXIT_FAILURE); + } + u = &unit_types[id]; + base = &unit_types[basetype]; + utype_copy_members(u, base); + u->basetype = basetype; + u->effect = NULL; + append_effects(&u->effect, base->effect); + for (i = 0; i < game.num_unit_modifier_types; ++i) { + u->modifiers[i] = modifiers[i]; + } + u->tech_requirement = A_NONE; + u->obsoleted_by = -1; + u->name_orig[0] = '\0'; + for (i = 0; i < game.num_unit_modifier_types; ++i) { + if (u->modifiers[i] < U_LAST) { + mod = &unit_modifiers[u->modifiers[i]]; + ApplyUnitModAction(u, mod->action); + } + } + for (i = 0; i < game.num_unit_modifier_types; ++i) { + if (u->modifiers[i] < U_LAST) { + mod = &unit_modifiers[u->modifiers[i]]; + ApplyUnitModAction(u, mod->final_action); + append_effects(&u->effect, mod->effect); + } + } + /* Overwrite the auto-generated name if a name is supplied */ + if (name && name[0]) { + sz_strlcpy(u->name_orig, name); + } + sz_strlcpy(u->name, _(u->name_orig)); + ensure_unique_unit_name(u); + game.num_unit_types++; + return id; +} + +static void read_moverate(void *structpt, unsigned long offset, + const size_t size, struct section_file *file, + const char *sec, const char *membername) +{ + int *member = FC_STRUCT_MEMBER_P(int, structpt, offset); + + *member = secfile_lookup_int(file, "%s.%s", sec, membername) + * SINGLE_MOVE; +} + +static void set_moverate(void *structpt, unsigned long offset, + const size_t size, const char *val) +{ + int *member = FC_STRUCT_MEMBER_P(int, structpt, offset); + + *member = SINGLE_MOVE * atoi(val); +} + +static void get_moverate(const void *structpt, unsigned long offset, + struct memberdata *data) +{ + int *member = FC_STRUCT_MEMBER_P(int, structpt, offset); + + my_snprintf(data->str, sizeof(data->str), "%d", *member / SINGLE_MOVE); +} + +static void set_unit(void *structpt, unsigned long offset, const size_t size, + const char *val) +{ +} + +static void get_unit(const void *structpt, unsigned long offset, + struct memberdata *data) +{ +} + +static void read_movetype(void *structpt, unsigned long offset, + const size_t size, struct section_file *file, + const char *sec, const char *membername) +{ + char *str; + enum unit_move_type *member = FC_STRUCT_MEMBER_P(enum unit_move_type, + structpt, offset); + + str = secfile_lookup_str(file, "%s.%s", sec, membername); + if ((*member = unit_move_type_from_str(str)) == 0) { + freelog(LOG_FATAL, "for unit_type \"%s\": bad move_type %s", + ((struct unit_type *)structpt)->name, str); + exit(EXIT_FAILURE); + } +//printf("Read %s -> (movetype) %s\n", membername, str); +} + +static void set_movetype(void *structpt, unsigned long offset, + const size_t size, const char *val) +{ + enum unit_move_type *member = FC_STRUCT_MEMBER_P(enum unit_move_type, + structpt, offset); + + if ((*member = unit_move_type_from_str(val)) == 0) { + freelog(LOG_FATAL, "bad move type %s", val); + } +} + +static void get_movetype(const void *structpt, unsigned long offset, + struct memberdata *data) +{ + enum unit_move_type *member = FC_STRUCT_MEMBER_P(enum unit_move_type, + structpt, offset); + + sz_strlcpy(data->str, move_type_names[*member - LAND_MOVING]); +} + +static void read_flags(void *structpt, unsigned long offset, const size_t size, + struct section_file *file, + const char *sec, const char *membername) +{ + char **slist, *str; + int nval, i; + enum unit_flag_id flag; + bv_flags *member = FC_STRUCT_MEMBER_P(bv_flags, structpt, offset); + + BV_CLR_ALL(*member); + slist = secfile_lookup_str_vec(file, &nval, "%s.%s", sec, membername); + for (i = 0; i < nval; ++i) { + str = slist[i]; + if (strcmp(str, "") == 0) { + continue; + } + if (strcmp(str, "Submarine")==0) { + /* Backwards compatibility */ + freelog(LOG_NORMAL, "Old-style \"Submarine\" flag (ok)"); + BV_SET(*member, F_NO_LAND_ATTACK); + BV_SET(*member, F_MISSILE_CARRIER); + flag = F_PARTIAL_INVIS; + } else { + flag = unit_flag_from_str(str); + } + if (flag == F_MAX) { + freelog(LOG_ERROR, "for unit_type \"%s\": bad flag name \"%s\"", + ((struct unit_type *)structpt)->name, str); + } else { + BV_SET(*member, flag); + } + } + free(slist); +//printf("Read %s -> (flag) %u\n", membername, *member); +} + +#define FLAGS_MAX_TOKENS 80 +static void set_flags(void *structpt, unsigned long offset, const size_t size, + const char *val) +{ + bv_flags *member = FC_STRUCT_MEMBER_P(bv_flags, structpt, offset); + char *tokens[FLAGS_MAX_TOKENS]; + int numtokens, i; + enum unit_flag_id flag; + + BV_CLR_ALL(*member); + numtokens = get_tokens(val, tokens, FLAGS_MAX_TOKENS, " ,"); + for (i = 0; i < numtokens; ++i) { + flag = unit_flag_from_str(tokens[i]); + if (flag == F_MAX) { + freelog(LOG_NORMAL, "bad flag name \"%s\" - ignoring", tokens[i]); + } else { + BV_SET(*member, flag); + } + free(tokens[i]); + } +} + +static void get_flags(const void *structpt, unsigned long offset, + struct memberdata *data) +{ + enum unit_flag_id i; + bool first = TRUE; + bv_flags *member = FC_STRUCT_MEMBER_P(bv_flags, structpt, offset); + + data->str[0] = '\0'; + for (i = 0; i < game.num_unit_flags; ++i) { + if (BV_ISSET(*member, i)) { + if (!first) { + sz_strlcat(data->str, ", "); + } else { + first = FALSE; + } + sz_strlcat(data->str, "'"); + sz_strlcat(data->str, flag_names[i]); + sz_strlcat(data->str, "'"); + } + } + + freelog(LOG_DEBUG, "(flag) = %s\n", data->str); +} + +static void binary_roleflags(const char *arg1, const char *arg2, const char op, + struct memberdata *result) +{ + if (op == '+') { + sz_strlcpy(result->str, arg1); + if (arg1[0] && arg2[0]) { + sz_strlcat(result->str, ", "); + } + sz_strlcat(result->str, arg2); + } else if (op == '-') { + freelog(LOG_NORMAL, "Fixme..."); + } +} + +static void read_roles(void *structpt, unsigned long offset, const size_t size, + struct section_file *file, + const char *sec, const char *membername) +{ + char **slist, *str; + int nval, i; + enum unit_role_id role; + bv_roles *member = FC_STRUCT_MEMBER_P(bv_roles, structpt, offset); + + BV_CLR_ALL(*member); + slist = secfile_lookup_str_vec(file, &nval, "%s.%s", sec, membername); + for (i = 0; i < nval; ++i) { + str = slist[i]; + if (strcmp(str, "") == 0) { + continue; + } + role = unit_role_from_str(str); + if (role == L_LAST) { + freelog(LOG_ERROR, "for unit_type \"%s\": bad role name \"%s\"", + ((struct unit_type *)structpt)->name, str); + } else { + BV_SET(*member, role - L_FIRST); + } + } + free(slist); +//printf("Read %s -> (role) %u\n", membername, *member); +} + +static void set_roles(void *structpt, unsigned long offset, const size_t size, + const char *val) +{ +} + +static void get_roles(const void *structpt, unsigned long offset, + struct memberdata *data) +{ + enum unit_role_id i; + bool first = TRUE; + bv_roles *member = FC_STRUCT_MEMBER_P(bv_roles, structpt, offset); + + data->str[0] = '\0'; + for (i = L_FIRST; i < L_LAST; ++i) { + if (BV_ISSET(*member, (i - L_FIRST))) { + if (!first) { + sz_strlcat(data->str, ", "); + } else { + first = FALSE; + } + sz_strlcat(data->str, "'"); + sz_strlcat(data->str, role_names[i - L_FIRST]); + sz_strlcat(data->str, "'"); + } + } + + freelog(LOG_DEBUG, "(role) = %s\n", data->str); +} + +#define FC_UTYPE_OFFSET(member) \ + FC_STRUCT_OFFSET(struct unit_type, member) +#define FC_UTYPE_SIZE(member) \ + FC_MEMBER_SIZE(struct unit_type, member) + +static struct members utype_members[] = { + { "name", + FC_UTYPE_OFFSET(name_orig), + FC_UTYPE_SIZE(name_orig), + NULL, set_string, get_string, binary_string }, + { "tech_req", FC_UTYPE_OFFSET(tech_requirement), + FC_UTYPE_SIZE(tech_requirement), NULL, set_tech, get_tech, NULL }, + { "impr_req", FC_UTYPE_OFFSET(impr_requirement), + FC_UTYPE_SIZE(impr_requirement), NULL, set_int, get_int, NULL }, + { "obsolete_by", FC_UTYPE_OFFSET(obsoleted_by), FC_UTYPE_SIZE(obsoleted_by), + NULL, set_unit, get_unit, NULL }, + { "move_type", FC_UTYPE_OFFSET(move_type), FC_UTYPE_SIZE(move_type), + read_movetype, set_movetype, get_movetype, binary_int }, + { "sound_move", FC_UTYPE_OFFSET(sound_move), FC_UTYPE_SIZE(sound_move), + read_sound, set_string, get_string, binary_string }, + { "sound_move_alt", FC_UTYPE_OFFSET(sound_move_alt), + FC_UTYPE_SIZE(sound_move_alt), read_sound, set_string, get_string, + binary_string }, + { "sound_fight", FC_UTYPE_OFFSET(sound_fight), FC_UTYPE_SIZE(sound_fight), + read_sound, set_string, get_string, binary_string }, + { "sound_fight_alt", FC_UTYPE_OFFSET(sound_fight_alt), + FC_UTYPE_SIZE(sound_fight_alt), read_sound, set_string, get_string, + binary_string }, + { "graphic", FC_UTYPE_OFFSET(graphic_str), FC_UTYPE_SIZE(graphic_str), + read_string, set_string, get_string, binary_string }, + { "graphic_alt", FC_UTYPE_OFFSET(graphic_alt), FC_UTYPE_SIZE(graphic_alt), + read_string, set_string, get_string, binary_string }, + { "build_cost", FC_UTYPE_OFFSET(build_cost), FC_UTYPE_SIZE(build_cost), + read_int, set_int, get_int, binary_int }, + { "pop_cost", FC_UTYPE_OFFSET(pop_cost), FC_UTYPE_SIZE(pop_cost), + read_int, set_int, get_int, binary_int }, + { "attack", FC_UTYPE_OFFSET(attack_strength), + FC_UTYPE_SIZE(attack_strength), read_int, set_int, get_int, binary_int }, + { "defense", FC_UTYPE_OFFSET(defense_strength), + FC_UTYPE_SIZE(defense_strength), read_int, set_int, get_int, binary_int }, + { "move_rate", FC_UTYPE_OFFSET(move_rate), FC_UTYPE_SIZE(move_rate), + read_moverate, set_moverate, get_moverate, binary_int }, + { "vision_range", FC_UTYPE_OFFSET(vision_range), FC_UTYPE_SIZE(vision_range), + read_int, set_int, get_int, binary_int }, + { "transport_cap", FC_UTYPE_OFFSET(transport_capacity), + FC_UTYPE_SIZE(transport_capacity), read_int, set_int, get_int, + binary_int }, + { "hitpoints", FC_UTYPE_OFFSET(hp), FC_UTYPE_SIZE(hp), + read_int, set_int, get_int, binary_int }, + { "firepower", FC_UTYPE_OFFSET(firepower), FC_UTYPE_SIZE(firepower), + read_int, set_int, get_int, binary_int }, + { "fuel", FC_UTYPE_OFFSET(fuel), FC_UTYPE_SIZE(fuel), + read_int, set_int, get_int, binary_int }, + { "uk_happy", FC_UTYPE_OFFSET(happy_cost), FC_UTYPE_SIZE(happy_cost), + read_int, set_int, get_int, binary_int }, + { "uk_shield", FC_UTYPE_OFFSET(shield_cost), FC_UTYPE_SIZE(shield_cost), + read_int, set_int, get_int, binary_int }, + { "uk_food", FC_UTYPE_OFFSET(food_cost), FC_UTYPE_SIZE(food_cost), + read_int, set_int, get_int, binary_int }, + { "uk_gold", FC_UTYPE_OFFSET(gold_cost), FC_UTYPE_SIZE(gold_cost), + read_int, set_int, get_int, binary_int }, + { "flags", FC_UTYPE_OFFSET(flags), FC_UTYPE_SIZE(flags), + read_flags, set_flags, get_flags, binary_roleflags }, + { "roles", FC_UTYPE_OFFSET(roles), FC_UTYPE_SIZE(roles), + read_roles, set_roles, get_roles, binary_roleflags }, + { "paratroopers_range", FC_UTYPE_OFFSET(paratroopers_range), + FC_UTYPE_SIZE(paratroopers_range), NULL, set_int, get_int, binary_int }, + { "paratroopers_mr_req", FC_UTYPE_OFFSET(paratroopers_mr_req), + FC_UTYPE_SIZE(paratroopers_mr_req), NULL, set_moverate, get_moverate, + binary_int }, + { "paratroopers_mr_sub", FC_UTYPE_OFFSET(paratroopers_mr_sub), + FC_UTYPE_SIZE(paratroopers_mr_sub), NULL, set_moverate, get_moverate, + binary_int }, + { NULL, 0, 0, NULL, NULL, NULL, NULL } +}; + +void utype_copy_members(struct unit_type *dest, const struct unit_type *src) +{ + copy_members((void *)dest, (const void *)src, utype_members); +} + +void utype_read_members(struct unit_type *utype, + struct section_file *file, const char *sec) +{ + read_members((void *)utype, utype_members, file, sec); +} + +void utype_read_member(struct unit_type *utype, const char *membername, + struct section_file *file, const char *sec) +{ + read_member((void *)utype, utype_members, membername, file, sec); +} + +void utype_set_member(struct unit_type *utype, const char *membername, + const char *val) +{ + set_member((void *)utype, utype_members, membername, val); +} + +void utype_get_member(struct unit_type *utype, const char *membername, + struct memberdata *data) +{ + get_member((void *)utype, utype_members, membername, data); +} + +char *action_getline(char **iter, struct astring *str) +{ + int linelen; + char *startline = *iter; + + startline += strspn(startline, "\r\n\t "); + linelen = my_strcspn(startline, "\r\n"); + if (linelen) { + astr_minsize(str, linelen + 1); + mystrlcpy(str->str, startline, linelen + 1); /* to add the '/0' */ + *iter = startline + linelen; + } + + return startline[0] ? str->str : NULL; +} + +static void get_str_data(void *structpt, struct members *memberlist, + struct atoken *token, struct memberdata *result, + char **identname) +{ + if (token->type == STRING_TOKEN) { + sz_strlcpy(result->str, token->str); + } else if (token->type == IDENT_TOKEN) { + get_member(structpt, memberlist, token->str, result); + if (identname) { + *identname = token->str; + } + } else { + freelog(LOG_NORMAL, "parse error"); + } +} + +static int find_operator(struct atoken *tokens, int numtokens, char *ops) +{ + int i, numparen = 0; + + for (i = 0; i < numtokens; ++i) { + switch(tokens[i].type) { + case LEFTPAREN_TOKEN: + numparen++; + break; + case RIGHTPAREN_TOKEN: + numparen--; + break; + case OP_TOKEN: + if (numparen == 0 && (!ops || strchr(ops, tokens[i].optype))) { + return i; + } + break; + default: + break; + } + } + if (numparen != 0) { + freelog(LOG_NORMAL, "Unbalanced parentheses"); + } + return -1; +} + +static void eval_expr(void *structpt, struct members *memberlist, + struct atoken *tokens, int numtokens, + struct atoken *result, char **identname) +{ + result->type = STRING_TOKEN; + result->str = NULL; + + /* Strip surrounding parentheses */ + while (numtokens >= 2 && tokens[0].type == LEFTPAREN_TOKEN + && tokens[numtokens - 1].type == RIGHTPAREN_TOKEN) { + numtokens -= 2; + tokens++; + } + + if (numtokens == 1) { + struct memberdata rhs; + size_t len; + + get_str_data(structpt, memberlist, &tokens[0], &rhs, identname); + len = strlen(rhs.str) + 1; + result->str = fc_malloc(len); + mystrlcpy(result->str, rhs.str, len); + } else { + struct atoken lhs, rhs; + struct memberdata member; + size_t len; + int oppos; + + oppos = find_operator(tokens, numtokens, "+-"); + if (oppos < 0) { + oppos = find_operator(tokens, numtokens, "*/"); + } + if (oppos < 0) { + oppos = find_operator(tokens, numtokens, NULL); + } + if (oppos <= 0 || oppos >= numtokens) { + freelog(LOG_NORMAL, "parse error"); + } else { + char *membname = NULL; + + eval_expr(structpt, memberlist, &tokens[0], oppos, &lhs, &membname); + eval_expr(structpt, memberlist, &tokens[oppos + 1], + numtokens - oppos - 1, &rhs, &membname); + + freelog(LOG_DEBUG, "Binary op %c on %s and %s", tokens[oppos].optype, + lhs.str, rhs.str); + + if (membname) { + binary_member(structpt, memberlist, membname, + lhs.str, rhs.str, tokens[oppos].optype, &member); + if (identname) { + *identname = membname; + } + } else if (isdigit(lhs.str[0]) || isdigit(rhs.str[0])) { + binary_int(lhs.str, rhs.str, tokens[oppos].optype, &member); + } else { + binary_string(lhs.str, rhs.str, tokens[oppos].optype, &member); + } + len = strlen(member.str) + 1; + result->str = fc_malloc(len); + mystrlcpy(result->str, member.str, len); + } + } +} + +void action_parsetokens(void *structpt, struct members *memberlist, + struct atoken *tokens, int numtokens) +{ + struct memberdata data; + + if (numtokens > 4 && tokens[0].type == IF_TOKEN + && tokens[2].type == EQUALS_TOKEN) { + get_member(structpt, memberlist, tokens[1].str, &data); + if (strcmp(data.str, tokens[3].str) == 0) { + freelog(LOG_DEBUG, "if %s = %s: TRUE", tokens[1].str, tokens[3].str); + action_parsetokens(structpt, memberlist, &tokens[4], numtokens - 4); + } else { + freelog(LOG_DEBUG, "if %s = %s: FALSE", tokens[1].str, tokens[3].str); + } + } else if (numtokens >= 3 && tokens[1].type == EQUALS_TOKEN + && tokens[0].type == IDENT_TOKEN) { + struct atoken result; + + eval_expr(structpt, memberlist, &tokens[2], numtokens - 2, &result, NULL); + freelog(LOG_DEBUG, "%s set to %s", tokens[0].str, result.str); + set_member(structpt, memberlist, tokens[0].str, result.str); + } else if (numtokens >= 3 && tokens[1].type == OP_TOKEN + && tokens[1].has_equals && tokens[0].type == IDENT_TOKEN) { + struct atoken rhs; + struct memberdata result; + + get_member(structpt, memberlist, tokens[0].str, &data); + eval_expr(structpt, memberlist, &tokens[2], numtokens - 2, &rhs, NULL); + binary_member(structpt, memberlist, tokens[0].str, data.str, rhs.str, + tokens[1].optype, &result); + freelog(LOG_DEBUG, "%s %c= %s -> %s", tokens[0].str, tokens[1].optype, + rhs.str, result.str); + set_member(structpt, memberlist, tokens[0].str, result.str); + } else { + freelog(LOG_NORMAL, "Parse error"); + } +} + +static void add_op_token(const char **strpt, struct atoken *token) +{ + const char *str = *strpt; + + switch(str[0]) { + case '(': + token->type = LEFTPAREN_TOKEN; break; + case ')': + token->type = RIGHTPAREN_TOKEN; break; + case '=': + token->type = EQUALS_TOKEN; break; + default: + token->type = OP_TOKEN; + token->optype = str[0]; + token->has_equals = FALSE; + if (str[1] == '=') { + token->has_equals = TRUE; + (*strpt)++; + } + break; + } + (*strpt)++; +} + +static int action_tokens(const char *str, struct atoken *tokens, + size_t num_tokens) +{ + int token; + + for (token = 0; token < num_tokens; ++token) { + tokens[token].str = NULL; + tokens[token].type = NULL_TOKEN; + } + + token = 0; + while (token < num_tokens && str[0] != '\0') { + size_t len; + const char *stpt; + bool strlist; + + switch (str[0]) { + case '+': case '-': case '*': case '/': + case '(': case ')': case '=': + add_op_token(&str, &tokens[token]); + token++; + break; + default: + strlist = FALSE; + str += strspn(str, "\t, "); + stpt = str; + len = my_strcspn(str, "\t -+=*/()"); + while (len > 0 && str[len - 1] == ',' && (strchr("\t ", str[len]))) { + strlist = TRUE; + str += len; + str += strspn(str, "\t, "); + len = my_strcspn(str, "\t -+=*/()"); + } + str += len; + if (str > stpt) { + len = str - stpt; + if (strlist) { + tokens[token].type = STRING_TOKEN; + } else if ((stpt[0] == '\'' && str[-1] == '\'') + || (stpt[0] == '\"' && str[-1] == '\"')) { + len -= 2; + stpt++; + tokens[token].type = STRING_TOKEN; + } else if (!isalpha(stpt[0])) { + tokens[token].type = STRING_TOKEN; + } else { + tokens[token].type = IDENT_TOKEN; + } + if (strncmp(stpt, "if", len) == 0) { + tokens[token].type = IF_TOKEN; + } else { + tokens[token].str = fc_malloc(len + 1); + mystrlcpy(tokens[token].str, stpt, len + 1); + } + token++; + } + break; + } + } + return token; +} + +#define ACTION_MAX_TOKENS 80 +void action_doline(void *structpt, struct members *memberlist, char *line) +{ + struct atoken atokens[ACTION_MAX_TOKENS]; + int numtokens, i; + + numtokens = action_tokens(line, atokens, ACTION_MAX_TOKENS); + freelog(LOG_DEBUG, "Attempting to apply action line %s", line); + action_parsetokens(structpt, memberlist, atokens, numtokens); + for (i = 0; i < numtokens; ++i) { + free(atokens[i].str); + } +} + +void apply_action(void *structpt, struct members *memberlist, char *action) +{ + char *iter, *line; + struct astring str; + + assert(action); + astr_init(&str); + iter = action; + while ((line = action_getline(&iter, &str)) != NULL) { + action_doline(structpt, memberlist, line); + } + astr_free(&str); +} + +static void ApplyUnitModAction(struct unit_type *u, char *action) +{ + apply_action((void *)u, utype_members, action); +} + diff -Nur -Xfreecivdiff.ignore freeciv-patched/common/unittype.h freeciv-compunit/common/unittype.h --- freeciv-patched/common/unittype.h 2003-06-12 13:39:42.000000000 +0100 +++ freeciv-compunit/common/unittype.h 2003-06-12 15:18:03.000000000 +0100 @@ -14,6 +14,7 @@ #define FC__UNITTYPE_H #include "shared.h" +#include "modifier.h" struct player; struct city; @@ -21,6 +22,9 @@ struct Sprite; /* opaque; client-gui specific */ struct unit; struct impr_effect; +struct section_file; +struct memberdata; +struct members; typedef int Unit_Type_id; /* @@ -132,6 +136,7 @@ L_BARBARIAN_LEADER, /* barbarian leader */ L_BARBARIAN_SEA, /* sea raider unit */ L_BARBARIAN_SEA_TECH, /* sea raider unit, global tech required */ + L_CANMODIFY, /* we can apply unit modifiers to this unit type */ L_LAST }; #define L_MAX 64 @@ -179,6 +184,9 @@ struct impr_effect *effect; /* list; .type==EFT_LAST terminated */ + Unit_Type_id basetype; /* if !U_LAST, unit modifiers are applied */ + int modifiers[MAX_MODS]; + char *helptext; }; @@ -188,6 +196,8 @@ }; extern struct unit_type unit_types[U_LAST]; +extern struct modifier_type unit_modifier_types[MAX_MODS]; +extern struct modifier *unit_modifiers; bool unit_type_exists(Unit_Type_id id); struct unit_type *get_unit_type(Unit_Type_id id); @@ -224,6 +234,7 @@ Unit_Type_id find_unit_type_by_name(const char *s); +Unit_Type_id find_unit_type_by_modifiers(Unit_Type_id basetype, int *modifiers); enum unit_move_type unit_move_type_from_str(const char *s); enum unit_flag_id unit_flag_from_str(const char *s); void unit_flag_set_name(enum unit_flag_id id, const char *s); @@ -250,4 +261,22 @@ } \ } +int unit_modifier_type_from_str(const char *s); +int find_unit_modifier_by_name(const char *s); + +Unit_Type_id form_compound_unit(const char *name, + const Unit_Type_id basetype, + const int modifiers[MAX_MODS]); + +void utype_copy_members(struct unit_type *dest, const struct unit_type *src); +void utype_read_members(struct unit_type *utype, + struct section_file *file, const char *sec); +void utype_read_member(struct unit_type *utype, const char *membername, + struct section_file *file, const char *sec); +void utype_set_member(struct unit_type *utype, const char *membername, + const char *val); +void utype_get_member(struct unit_type *utype, const char *membername, + struct memberdata *data); +void apply_action(void *structpt, struct members *memberlist, char *action); + #endif /* FC__UNITTYPE_H */ diff -Nur -Xfreecivdiff.ignore freeciv-patched/data/default/governments.ruleset freeciv-compunit/data/default/governments.ruleset --- freeciv-patched/data/default/governments.ruleset 2003-06-12 13:39:47.000000000 +0100 +++ freeciv-compunit/data/default/governments.ruleset 2003-06-12 13:42:20.000000000 +0100 @@ -154,13 +154,19 @@ waste_extra_distance = 0 waste_max_distance_cap = 36 -production_trade_bonus = 0, 0 -production_shield_bonus = 0, 0 -production_food_bonus = 0, 0 - -production_trade_penalty = 2, 0 -production_shield_penalty = 2, 0 -production_food_penalty = 2, 0 +trade_bonus = 0 +shield_bonus = 0 +food_bonus = 0 +celeb_trade_bonus = 0 +celeb_shield_bonus = 0 +celeb_food_bonus = 0 + +trade_penalty = 2 +shield_penalty = 2 +food_penalty = 2 +celeb_trade_penalty = 0 +celeb_shield_penalty = 0 +celeb_food_penalty = 0 ruler_male_title = _("Mr.") ruler_female_title = _("Ms.") @@ -232,13 +238,19 @@ waste_extra_distance = 0 waste_max_distance_cap = 36 -production_trade_bonus = 0, 0 -production_shield_bonus = 0, 0 -production_food_bonus = 0, 0 - -production_trade_penalty = 2, 0 -production_shield_penalty = 2, 0 -production_food_penalty = 2, 0 +trade_bonus = 0 +shield_bonus = 0 +food_bonus = 0 +celeb_trade_bonus = 0 +celeb_shield_bonus = 0 +celeb_food_bonus = 0 + +trade_penalty = 2 +shield_penalty = 2 +food_penalty = 2 +celeb_trade_penalty = 0 +celeb_shield_penalty = 0 +celeb_food_penalty = 0 ruler_male_title = _("Emperor") ruler_female_title = _("Empress") @@ -311,13 +323,19 @@ waste_extra_distance = 0 waste_max_distance_cap = 36 -production_trade_bonus = 0, 1 -production_shield_bonus = 0, 0 -production_food_bonus = 0, 0 - -production_trade_penalty = 0, 0 -production_shield_penalty = 0, 0 -production_food_penalty = 0, 0 +trade_bonus = 0 +shield_bonus = 0 +food_bonus = 0 +celeb_trade_bonus = 1 +celeb_shield_bonus = 0 +celeb_food_bonus = 0 + +trade_penalty = 0 +shield_penalty = 0 +food_penalty = 0 +celeb_trade_penalty = 0 +celeb_shield_penalty = 0 +celeb_food_penalty = 0 ruler_male_title = _("King") ruler_female_title = _("Queen") @@ -389,13 +407,19 @@ waste_extra_distance = 0 waste_max_distance_cap = 36 -production_trade_bonus = 0, 1 -production_shield_bonus = 0, 0 -production_food_bonus = 0, 0 - -production_trade_penalty = 0, 0 -production_shield_penalty = 0, 0 -production_food_penalty = 0, 0 +trade_bonus = 0 +shield_bonus = 0 +food_bonus = 0 +celeb_trade_bonus = 1 +celeb_shield_bonus = 0 +celeb_food_bonus = 0 + +trade_penalty = 0 +shield_penalty = 0 +food_penalty = 0 +celeb_trade_penalty = 0 +celeb_shield_penalty = 0 +celeb_food_penalty = 0 ruler_male_title = _("Comrade") ruler_female_title = _("Comrade") @@ -475,13 +499,19 @@ waste_extra_distance = 0 waste_max_distance_cap = 36 -production_trade_bonus = 1, 1 -production_shield_bonus = 0, 0 -production_food_bonus = 0, 0 - -production_trade_penalty = 0, 0 -production_shield_penalty = 0, 0 -production_food_penalty = 0, 0 +trade_bonus = 1 +shield_bonus = 0 +food_bonus = 0 +celeb_trade_bonus = 1 +celeb_shield_bonus = 0 +celeb_food_bonus = 0 + +trade_penalty = 0 +shield_penalty = 0 +food_penalty = 0 +celeb_trade_penalty = 0 +celeb_shield_penalty = 0 +celeb_food_penalty = 0 ruler_male_title = _("Consul") ruler_female_title = _("Consul") @@ -564,13 +594,19 @@ waste_extra_distance = 0 waste_max_distance_cap = 36 -production_trade_bonus = 1, 1 -production_shield_bonus = 0, 0 -production_food_bonus = 0, 0 - -production_trade_penalty = 0, 0 -production_shield_penalty = 0, 0 -production_food_penalty = 0, 0 +trade_bonus = 1 +shield_bonus = 0 +food_bonus = 0 +celeb_trade_bonus = 1 +celeb_shield_bonus = 0 +celeb_food_bonus = 0 + +trade_penalty = 0 +shield_penalty = 0 +food_penalty = 0 +celeb_trade_penalty = 0 +celeb_shield_penalty = 0 +celeb_food_penalty = 0 ruler_male_title = _("President") ruler_female_title = _("President") diff -Nur -Xfreecivdiff.ignore freeciv-patched/data/smac/buildings.ruleset freeciv-compunit/data/smac/buildings.ruleset --- freeciv-patched/data/smac/buildings.ruleset 2003-06-12 13:39:47.000000000 +0100 +++ freeciv-compunit/data/smac/buildings.ruleset 2003-06-12 16:45:04.000000000 +0100 @@ -45,6 +45,8 @@ name = _("Aerospace Complex") tech_req = "Doctrine: Air Power" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -70,6 +72,8 @@ name = _("Bioenhancement Center") tech_req = "Neural Grafting" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -93,6 +97,8 @@ name = _("Biology Lab") tech_req = "Centauri Empathy" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -113,6 +119,8 @@ name = _("Centauri Preserve") tech_req = "Centauri Meditation" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -130,6 +138,8 @@ name = _("Children's Creche") tech_req = "Ethical Calculus" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -147,6 +157,8 @@ name = _("Command Center") tech_req = "Doctrine: Mobility" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -174,6 +186,8 @@ name = _("Energy Bank") tech_req = "Industrial Economics" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -196,6 +210,8 @@ name = _("Fusion Lab") tech_req = "Fusion Power" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -219,6 +235,8 @@ name = _("Genejack Factory") tech_req = "Retroviral Engineering" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -243,6 +261,8 @@ name = _("Hab Complex") tech_req = "Industrial Automation" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -266,6 +286,8 @@ name = _("Habitation Dome") tech_req = "Super Tensile Solids" bldg_req = "Hab Complex" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -289,6 +311,8 @@ name = _("Headquarters") tech_req = "None" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "Player" @@ -319,6 +343,8 @@ name = _("Hologram Theatre") tech_req = "Planetary Networks" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -343,6 +369,8 @@ name = _("Hybrid Forest") tech_req = "Planetary Economics" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -373,6 +401,8 @@ name = _("Nanohospital") tech_req = "Homo Superior" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -399,6 +429,8 @@ name = _("Nanoreplicator") tech_req = "Matter Editation" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -421,6 +453,8 @@ name = _("Naval Yard") tech_req = "Doctrine: Initiative" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" terr_gate = "Ocean" ;spec_gate = equiv_range = "City" @@ -446,6 +480,8 @@ name = _("Nessus Mining Station") tech_req = "Self-Aware Machines" bldg_req = "Aerospace Complex" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -463,6 +499,8 @@ name = _("Network Node") tech_req = "Information Networks" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -485,6 +523,8 @@ name = _("Orbital Defense Pod") tech_req = "Self-Aware Machines" bldg_req = "Aerospace Complex" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -502,6 +542,8 @@ name = _("Orbital Power Transmitter") tech_req = "Advanced Spaceflight" bldg_req = "Aerospace Complex" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -519,6 +561,8 @@ name = _("Paradise Garden") tech_req = "Sentient Econometrics" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -541,6 +585,8 @@ name = _("Perimeter Defense") tech_req = "Doctrine: Loyalty" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -566,6 +612,8 @@ name = _("Pressure Dome") tech_req = "Doctrine: Flexibility" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" terr_gate = "Ocean" ;spec_gate = equiv_range = "City" @@ -583,6 +631,8 @@ name = _("Psi Gate") tech_req = "Matter Transmission" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -608,6 +658,8 @@ name = _("Punishment Sphere") tech_req = "Advanced Military Algorithms" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -634,6 +686,8 @@ name = _("Quantum Converter") tech_req = "Quantum Machinery" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -656,6 +710,8 @@ name = _("Quantum Lab") tech_req = "Quantum Power" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -679,6 +735,8 @@ name = _("Recreation Commons") tech_req = "Social Psych" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -701,6 +759,8 @@ name = _("Recycling Tanks") tech_req = "Biogenetics" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -718,6 +778,8 @@ name = _("Research Hospital") tech_req = "Gene Splicing" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -744,6 +806,8 @@ name = _("Robotic Assembly Plant") tech_req = "Industrial Nanorobotics" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -767,6 +831,8 @@ name = _("Skunkworks") tech_req = "Advanced Subatomic Theory" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -784,6 +850,8 @@ name = _("Sky Hydroponics Lab") tech_req = "Orbital Spaceflight" bldg_req = "Aerospace Complex" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -801,6 +869,8 @@ name = _("Stockpile Energy") tech_req = "None" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -825,6 +895,8 @@ name = _("Tachyon Field") tech_req = "Probability Mechanics" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -854,6 +926,8 @@ name = _("Temple of Planet") tech_req = "Secrets of Alpha Centauri" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -871,6 +945,8 @@ name = _("Tree Farm") tech_req = "Environmental Economics" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -902,6 +978,8 @@ name = _("The Ascent to Transcendence") tech_req = "Threshold of Transcendence" bldg_req = "The Voice Of Planet" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -919,6 +997,8 @@ name = _("The Ascetic Virtues") tech_req = "Planetary Economics" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -936,6 +1016,8 @@ name = _("The Bulk Matter Transmitter") tech_req = "Matter Transmission" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -953,6 +1035,8 @@ name = _("The Citizens' Defense Force") tech_req = "Intellectual Integrity" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "Player" @@ -978,6 +1062,8 @@ name = _("Clinical Immortality") tech_req = "Matter Editation" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -1000,6 +1086,8 @@ name = _("The Cloning Vats") tech_req = "Biomachinery" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -1017,6 +1105,8 @@ name = _("The Command Nexus") tech_req = "Doctrine: Loyalty" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "Player" @@ -1040,6 +1130,8 @@ name = _("The Cyborg Factory") tech_req = "Mind-Machine Interface" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "Player" @@ -1062,6 +1154,8 @@ name = _("The Dream Twister") tech_req = "The Will To Power" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -1079,6 +1173,8 @@ name = _("The Empath Guild") tech_req = "Centauri Empathy" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -1101,6 +1197,8 @@ name = _("The Human Genome Project") tech_req = "Biogenetics" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -1123,6 +1221,8 @@ name = _("The Hunter-Seeker Algorithm") tech_req = "Presentient Algorithms" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -1143,6 +1243,8 @@ name = _("The Living Refinery") tech_req = "Advanced Spaceflight" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -1160,6 +1262,8 @@ name = _("The Longevity Vaccine") tech_req = "Bio-Engineering" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -1188,6 +1292,8 @@ name = _("The Maritime Control Center") tech_req = "Doctrine: Initiative" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "Player" @@ -1213,6 +1319,8 @@ name = _("The Merchant Exchange") tech_req = "Industrial Base" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -1236,6 +1344,8 @@ name = _("The Nano Factory") tech_req = "Industrial Nanorobotics" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -1262,6 +1372,8 @@ name = _("The Network Backbone") tech_req = "Digital Sentience" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -1279,6 +1391,8 @@ name = _("The Neural Amplifier") tech_req = "Neural Grafting" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -1296,6 +1410,8 @@ name = _("The Pholus Mutagen") tech_req = "Centauri Genetics" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -1313,6 +1429,8 @@ name = _("The Planetary Datalinks") tech_req = "Cyberethics" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -1336,6 +1454,8 @@ name = _("The Planetary Transit System") tech_req = "Industrial Automation" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -1353,6 +1473,8 @@ name = _("The Self-Aware Colony") tech_req = "Self-Aware Machines" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -1370,6 +1492,8 @@ name = _("The Singularity Inductor") tech_req = "Controlled Singularity" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "Player" @@ -1392,6 +1516,8 @@ name = _("The Space Elevator") tech_req = "Super Tensile Solids" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -1409,6 +1535,8 @@ name = _("The Supercollider") tech_req = "Applied Relativity" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -1431,6 +1559,8 @@ name = _("The Telepathic Matrix") tech_req = "Eudaimonia" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -1448,6 +1578,8 @@ name = _("The Theory of Everything") tech_req = "Unified Field Theory" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -1470,6 +1602,8 @@ name = _("The Universal Translator") tech_req = "Homo Superior" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -1492,6 +1626,8 @@ name = _("The Virtual World") tech_req = "Planetary Networks" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -1520,6 +1656,8 @@ name = _("The Voice Of Planet") tech_req = "Threshold of Transcendence" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -1537,6 +1675,8 @@ name = _("The Weather Paradigm") tech_req = "Centauri Ecology" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" @@ -1554,6 +1694,8 @@ name = _("The Xenoempathy Dome") tech_req = "Centauri Meditation" bldg_req = "None" +graphic = "b.oracle" +graphic_alt = "-" ;terr_gate = ;spec_gate = equiv_range = "City" diff -Nur -Xfreecivdiff.ignore freeciv-patched/data/smac/governments.ruleset freeciv-compunit/data/smac/governments.ruleset --- freeciv-patched/data/smac/governments.ruleset 2003-06-12 13:39:47.000000000 +0100 +++ freeciv-compunit/data/smac/governments.ruleset 2003-06-12 15:30:28.000000000 +0100 @@ -15,7 +15,7 @@ options="1.9" [governments] -default="Simple" +default="Simple Frontier State" when_anarchy="Anarchy" ai_goal="Simple" max_revolution_turns=0 @@ -158,6 +158,13 @@ corruption_distance_factor = 1 corruption_extra_distance = 0 +waste_level = 0 +waste_modifier = 1 +waste_fixed_distance = 0 +waste_distance_factor = 0 +waste_extra_distance = 0 +waste_max_distance_cap = 36 + trade_bonus = 1 shield_bonus = 0 food_bonus = 0 @@ -211,6 +218,13 @@ corruption_distance_factor = 1 corruption_extra_distance = 0 +waste_level = 0 +waste_modifier = 1 +waste_fixed_distance = 0 +waste_distance_factor = 0 +waste_extra_distance = 0 +waste_max_distance_cap = 36 + trade_bonus = 1 shield_bonus = 0 food_bonus = 0 @@ -389,3 +403,8 @@ "Unit_Cost", "Player", -10 } final_action = "" + +[compound_government_default] +name = "Simple Frontier State" +base = "Simple" +modifiers = "Simple", "None", "Frontier", "Survival" diff -Nur -Xfreecivdiff.ignore freeciv-patched/server/plrhand.c freeciv-compunit/server/plrhand.c --- freeciv-patched/server/plrhand.c 2003-06-12 13:39:43.000000000 +0100 +++ freeciv-compunit/server/plrhand.c 2003-06-12 13:42:20.000000000 +0100 @@ -38,6 +38,7 @@ #include "gamehand.h" #include "gamelog.h" #include "maphand.h" +#include "ruleset.h" #include "sernet.h" #include "settlers.h" #include "srv_main.h" @@ -738,26 +739,16 @@ /************************************************************************** ... **************************************************************************/ -void handle_player_government(struct player *pplayer, - struct packet_player_request *preq) +static void change_player_gov(struct player *pplayer, int newgov) { - if (pplayer->government != game.government_when_anarchy || - preq->government < 0 || preq->government >= game.government_count || - !can_change_to_government(pplayer, preq->government)) { - return; - } - - if((pplayer->revolution<=5) && (pplayer->revolution>0)) - return; - - pplayer->government=preq->government; + pplayer->government = newgov; notify_player(pplayer, _("Game: %s now governs the %s as a %s."), pplayer->name, get_nation_name_plural(pplayer->nation), - get_government_name(preq->government)); + get_government_name(newgov)); gamelog(GAMELOG_GOVERNMENT, _("%s form a %s"), get_nation_name_plural(pplayer->nation), - get_government_name(preq->government)); + get_government_name(newgov)); if (!pplayer->ai.control) { /* Keep luxuries if we have any. Try to max out science. -GJW */ @@ -779,6 +770,24 @@ /************************************************************************** ... **************************************************************************/ +void handle_player_government(struct player *pplayer, + struct packet_player_request *preq) +{ + if (pplayer->government != game.government_when_anarchy || + preq->government < 0 || preq->government >= game.government_count || + !can_change_to_government(pplayer, preq->government)) { + return; + } + + if((pplayer->revolution<=5) && (pplayer->revolution>0)) + return; + + change_player_gov(pplayer, preq->government); +} + +/************************************************************************** +... +**************************************************************************/ void handle_player_revolution(struct player *pplayer) { if ((pplayer->revolution<=5) && @@ -840,6 +849,26 @@ } /************************************************************************** +... +**************************************************************************/ +void handle_request_compound(struct player *pplayer, + struct packet_request_compound *req) +{ + if (req->is_gov) { + int id; + + id = form_compound_gov(pplayer, req->name, req->basetype, req->modifiers); + send_single_government(&game.game_connections, id); + change_player_gov(pplayer, id); + } else { + Unit_Type_id id; + + id = form_compound_unit(req->name, req->basetype, req->modifiers); + send_single_unit(&game.game_connections, id); + } +} + +/************************************************************************** Handles a player cancelling a "pact" with another player. packet.id is id of player we want to cancel a pact with diff -Nur -Xfreecivdiff.ignore freeciv-patched/server/plrhand.h freeciv-compunit/server/plrhand.h --- freeciv-patched/server/plrhand.h 2003-06-07 19:58:49.000000000 +0100 +++ freeciv-compunit/server/plrhand.h 2003-06-12 13:42:20.000000000 +0100 @@ -63,6 +63,8 @@ struct packet_player_request *preq); void handle_player_research(struct player *pplayer, struct packet_player_request *preq); +void handle_request_compound(struct player *pplayer, + struct packet_request_compound *req); void handle_player_tech_goal(struct player *pplayer, struct packet_player_request *preq); void handle_player_attribute_chunk(struct player *pplayer, diff -Nur -Xfreecivdiff.ignore freeciv-patched/server/ruleset.c freeciv-compunit/server/ruleset.c --- freeciv-patched/server/ruleset.c 2003-06-12 13:39:43.000000000 +0100 +++ freeciv-compunit/server/ruleset.c 2003-06-12 15:11:58.000000000 +0100 @@ -35,6 +35,7 @@ #include "support.h" #include "tech.h" #include "unit.h" +#include "unittype.h" #include "citytools.h" @@ -63,8 +64,8 @@ static Impr_Type_id lookup_impr_type(struct section_file *file, const char *prefix, const char *entry, bool required, const char *filename, const char *description); -static int lookup_government(struct section_file *file, const char *entry, - const char *filename); +static int lookup_government(struct section_file *file, const char *prefix, + const char *entry, const char *filename); static int lookup_city_cost(struct section_file *file, const char *prefix, const char *entry, const char *filename); static char *lookup_helptext(struct section_file *file, char *prefix); @@ -96,6 +97,10 @@ static void send_ruleset_techs(struct conn_list *dest); static void send_ruleset_units(struct conn_list *dest); +static void send_ruleset_unit_modifier_types(struct conn_list *dest); +static void send_ruleset_unit_modifiers(struct conn_list *dest); +static void send_ruleset_gov_modifier_types(struct conn_list *dest); +static void send_ruleset_gov_modifiers(struct conn_list *dest); static void send_ruleset_buildings(struct conn_list *dest); static void send_ruleset_terrain(struct conn_list *dest); static void send_ruleset_governments(struct conn_list *dest); @@ -347,13 +352,13 @@ Lookup entry in the file and return the corresponding government index; dies if can't find/match. filename is for error message. **************************************************************************/ -static int lookup_government(struct section_file *file, const char *entry, - const char *filename) +static int lookup_government(struct section_file *file, const char *prefix, + const char *entry, const char *filename) { char *sval; struct government *gov; - sval = secfile_lookup_str(file, "%s", entry); + sval = secfile_lookup_str(file, "%s.%s", prefix, entry); gov = find_government_by_name(sval); if (!gov) { freelog(LOG_FATAL, "for %s couldn't match government \"%s\" (%s)", @@ -741,6 +746,23 @@ e->cond_bldg = B_LAST; } + item = secfile_lookup_str_default(file, "", "%s.effect%d.cond_govmod", + secname, j); + if (*item != '\0') { + int govmod = find_gov_modifier_by_name(item); + if (govmod < 0) { + freelog(LOG_ERROR, "for %s effect[%d].cond_govmod couldn't match " + "government modifier \"%s\" (%s)", + name, j, item, filename); + e->cond_govmod = game.num_gov_modifiers; + problem = TRUE; + } else { + e->cond_govmod = govmod; + } + } else { + e->cond_govmod = game.num_gov_modifiers; + } + item = secfile_lookup_str_default(file, "", "%s.effect%d.cond_gov", secname, j); if (*item != '\0') { @@ -857,17 +879,105 @@ /************************************************************************** ... **************************************************************************/ +static void read_modifier_types(struct section_file *file, + struct modifier_type *modifier_types, + int *num_modifier_types) +{ + char **sec; + int num_mods, i; + const char *filename = secfile_filename(file); + + /* Read modifier types from mod_type_xxx entries */ + sec = secfile_get_secnames_prefix(file, "mod_type_", &num_mods); + if (num_mods > MAX_MODS) { + freelog(LOG_FATAL, "Too many modifier types! (%d, max %d; %s)", + num_mods, MAX_MODS, filename); + exit(EXIT_FAILURE); + } + *num_modifier_types = num_mods; + + /* Read in names first so that lookup works later on */ + for (i = 0; i < num_mods; ++i) { + struct modifier_type *um = &modifier_types[i]; + sz_strlcpy(um->name, secfile_lookup_str(file, "%s.name", sec[i])); + } + + for (i = 0; i < num_mods; ++i) { + struct modifier_type *um = &modifier_types[i]; + + um->id = modifier_type_from_str(um->name, modifier_types, num_mods); + um->tech_requirement = lookup_tech(file, sec[i], "tech_req", 0, + filename, um->name); + um->obsoleted_by = lookup_unit_type(file, sec[i], "obsolete_by", 0, + filename, um->name); + um->must_use = secfile_lookup_bool(file, "%s.must_use", sec[i]); + } + free(sec); +} + +/************************************************************************** +... +**************************************************************************/ +static struct modifier *read_modifiers(struct section_file *file, + int *num_modifiers, + struct modifier_type *modifier_types, + int num_modifier_types) +{ + char **sec; + int num_mods, i; + struct modifier *modifiers; + const char *filename = secfile_filename(file); + + sec = secfile_get_secnames_prefix(file, "modifier_", &num_mods); + if (num_mods > U_LAST) { + freelog(LOG_FATAL, "Too many unit modifiers (%d, max %d) in %s", + num_mods, U_LAST, filename); + exit(EXIT_FAILURE); + } + *num_modifiers = num_mods; + if (num_mods) { + modifiers = fc_calloc(num_mods, sizeof(struct modifier)); + } else { + modifiers = NULL; + } + for (i = 0; i < num_mods; ++i) { + struct modifier *um = &modifiers[i]; + char *str; + + sz_strlcpy(um->name, secfile_lookup_str(file, "%s.name", sec[i])); + um->tech_requirement = lookup_tech(file, sec[i], "tech_req", + FALSE, filename, um->name); + um->action = mystrdup(secfile_lookup_str(file, "%s.action", sec[i])); + um->final_action = mystrdup(secfile_lookup_str(file, "%s.final_action", + sec[i])); + str = secfile_lookup_str(file, "%s.type", sec[i]); + if ((um->type = modifier_type_from_str(str, modifier_types, num_modifier_types)) == -1) { + freelog(LOG_FATAL, "Bad unit modifier type %s for \"%s\" (%s)", str, + um->name, filename); + exit(EXIT_FAILURE); + } + um->effect = load_effects(sec[i], um->name, file, FALSE, TRUE); + } + free(sec); + return modifiers; +} + +/************************************************************************** +... +**************************************************************************/ static void load_ruleset_units(struct section_file *file) { char *datafile_options; struct unit_type *u; - int i, j, ival, nval; - char *sval, **slist, **sec; + int i, j, nval; + char **sec; const char *filename = secfile_filename(file); datafile_options = check_ruleset_capabilities(file, "+1.9", filename); + read_modifier_types(file, unit_modifier_types, &game.num_unit_modifier_types); + sec = secfile_get_secnames_prefix(file, "unit_", &nval); /* Tech requirement is used to flag removed unit_types, which @@ -880,69 +990,16 @@ FALSE, filename, u->name); } unit_type_iterate_end; - unit_type_iterate(i) { - u = &unit_types[i]; - if (unit_type_exists(i)) { - u->obsoleted_by = lookup_unit_type(file, sec[i], - "obsolete_by", FALSE, filename, u->name); - } else { - (void) section_file_lookup(file, "%s.obsolete_by", sec[i]); /* unused */ - u->obsoleted_by = -1; - } - } unit_type_iterate_end; - /* main stats: */ unit_type_iterate(i) { u = &unit_types[i]; + u->basetype = U_LAST; + utype_read_members(u, file, sec[i]); u->impr_requirement = find_improvement_by_name(secfile_lookup_str_default(file, "None", "%s.impr_req", sec[i])); - sval = secfile_lookup_str(file, "%s.move_type", sec[i]); - ival = unit_move_type_from_str(sval); - if (ival==0) { - freelog(LOG_FATAL, "for unit_type \"%s\": bad move_type %s (%s)", - u->name, sval, filename); - exit(EXIT_FAILURE); - } - u->move_type = ival; - - sz_strlcpy(u->sound_move, - secfile_lookup_str_default(file, "-", "%s.sound_move", - sec[i])); - sz_strlcpy(u->sound_move_alt, - secfile_lookup_str_default(file, "-", "%s.sound_move_alt", - sec[i])); - sz_strlcpy(u->sound_fight, - secfile_lookup_str_default(file, "-", "%s.sound_fight", - sec[i])); - sz_strlcpy(u->sound_fight_alt, - secfile_lookup_str_default(file, "-", "%s.sound_fight_alt", - sec[i])); - - sz_strlcpy(u->graphic_str, - secfile_lookup_str(file,"%s.graphic", sec[i])); - sz_strlcpy(u->graphic_alt, - secfile_lookup_str(file,"%s.graphic_alt", sec[i])); - - u->build_cost = - secfile_lookup_int(file,"%s.build_cost", sec[i]); - u->pop_cost = - secfile_lookup_int(file,"%s.pop_cost", sec[i]); - u->attack_strength = - secfile_lookup_int(file,"%s.attack", sec[i]); - u->defense_strength = - secfile_lookup_int(file,"%s.defense", sec[i]); - u->move_rate = - SINGLE_MOVE*secfile_lookup_int(file,"%s.move_rate", sec[i]); - - u->vision_range = - secfile_lookup_int(file,"%s.vision_range", sec[i]); - u->transport_capacity = - secfile_lookup_int(file,"%s.transport_cap", sec[i]); - u->hp = secfile_lookup_int(file,"%s.hitpoints", sec[i]); - u->firepower = secfile_lookup_int(file,"%s.firepower", sec[i]); if (u->firepower <= 0) { freelog(LOG_FATAL, "for unit_type \"%s\": firepower is %d but " "must be at least 1.\nSet the unit's attack strength to 0 " @@ -950,78 +1007,96 @@ u->name, u->firepower, filename); exit(EXIT_FAILURE); } - u->fuel = secfile_lookup_int(file,"%s.fuel", sec[i]); - - u->happy_cost = secfile_lookup_int(file, "%s.uk_happy", sec[i]); - u->shield_cost = secfile_lookup_int(file, "%s.uk_shield", sec[i]); - u->food_cost = secfile_lookup_int(file, "%s.uk_food", sec[i]); - u->gold_cost = secfile_lookup_int(file, "%s.uk_gold", sec[i]); - u->effect = load_effects(sec[i], u->name, file, TRUE, FALSE); u->helptext = lookup_helptext(file, sec[i]); } unit_type_iterate_end; - /* flags */ unit_type_iterate(i) { u = &unit_types[i]; - BV_CLR_ALL(u->flags); - assert(!unit_type_flag(i, F_LAST-1)); + if (unit_type_flag(i, F_PARATROOPERS)) { + u->paratroopers_range = secfile_lookup_int(file, + "%s.paratroopers_range", sec[i]); + u->paratroopers_mr_req = SINGLE_MOVE * secfile_lookup_int(file, + "%s.paratroopers_mr_req", sec[i]); + u->paratroopers_mr_sub = SINGLE_MOVE * secfile_lookup_int(file, + "%s.paratroopers_mr_sub", sec[i]); + } else { + u->paratroopers_range = 0; + u->paratroopers_mr_req = 0; + u->paratroopers_mr_sub = 0; + } + } unit_type_iterate_end; + free(sec); - slist = secfile_lookup_str_vec(file, &nval, "%s.flags", sec[i]); - for(j=0; jname, sval, filename); - } - BV_SET(u->flags, ival); - assert(unit_type_flag(i, ival)); - - if(ival == F_PARATROOPERS) { - u->paratroopers_range = secfile_lookup_int(file, - "%s.paratroopers_range", sec[i]); - u->paratroopers_mr_req = 3*secfile_lookup_int(file, - "%s.paratroopers_mr_req", sec[i]); - u->paratroopers_mr_sub = 3*secfile_lookup_int(file, - "%s.paratroopers_mr_sub", sec[i]); + lookup_tech_list(file, "u_specials", "partisan_req", + game.rtech.partisan_req, filename); + + unit_modifiers = read_modifiers(file, &game.num_unit_modifiers, + unit_modifier_types, + game.num_unit_modifier_types); + + sec = secfile_get_secnames_prefix(file, "compound_unit_", &nval); + for (i = 0; i < nval; ++i) { + int modifiers[MAX_MODS]; + char *name, *sval; + Unit_Type_id basetype; + struct unit_type *utype; + + name = secfile_lookup_str(file, "%s.name", sec[i]); + basetype = lookup_unit_type(file, sec[i], "base", TRUE, + filename, name); + freelog(LOG_DEBUG, "Forming compound unit %s", name); + + for (j = 0; j < game.num_unit_modifier_types; ++j) { + sval = secfile_lookup_str(file, "%s.modifiers,%d", sec[i], j); + if (!unit_modifier_types[j].must_use && sval[0] == '\0') { + modifiers[j] = U_LAST; } else { - u->paratroopers_range = 0; - u->paratroopers_mr_req = 0; - u->paratroopers_mr_sub = 0; + int ival = find_unit_modifier_by_name(sval); + + if (ival == U_LAST) { + freelog(LOG_FATAL, + "for %s, couldn't match unit modifier \"%s\" (%s)", + sec[i], sval, filename); + exit(EXIT_FAILURE); + } else if (unit_modifiers[ival].type != unit_modifier_types[j].id) { + freelog(LOG_FATAL, "for %s, unit modifier \"%s\" is not of " + "required compound type %s (%s)", + sec[i], sval, unit_modifier_types[j].name, + filename); + exit(EXIT_FAILURE); + } else { + modifiers[j] = ival; + } } } - free(slist); - } unit_type_iterate_end; - - /* roles */ + utype = &unit_types[form_compound_unit(name, basetype, modifiers)]; + /* Allow override of flags and roles if specified */ + if (secfile_lookup_str_default(file, NULL, "%s.roles", sec[i])) { + utype_read_member(utype, "roles", file, sec[i]); + } + if (secfile_lookup_str_default(file, NULL, "%s.flags", sec[i])) { + utype_read_member(utype, "flags", file, sec[i]); + } + } + free(sec); + + sec = secfile_get_secnames_prefix(file, "unit_", &nval); unit_type_iterate(i) { u = &unit_types[i]; - BV_CLR_ALL(u->roles); - - slist = secfile_lookup_str_vec(file, &nval, "%s.roles", sec[i] ); - for(j=0; jname, sval, filename); + if (u->basetype == U_LAST) { + if (unit_type_exists(i)) { + u->obsoleted_by = lookup_unit_type(file, sec[i], + "obsolete_by", FALSE, filename, + u->name); + } else { + (void) section_file_lookup(file, "%s.obsolete_by", sec[i]); /* unused */ + u->obsoleted_by = -1; } - BV_SET(u->roles, ival - L_FIRST); - assert(unit_has_role(i, ival)); } - free(slist); } unit_type_iterate_end; - - lookup_tech_list(file, "u_specials", "partisan_req", - game.rtech.partisan_req, filename); + free(sec); /* Some more consistency checking: */ unit_type_iterate(i) { @@ -1127,7 +1202,6 @@ update_simple_ai_types(); - free(sec); section_file_check_unused(file, filename); section_file_free(file); } @@ -1593,33 +1667,13 @@ sec = secfile_get_secnames_prefix(file, "government_", &nval); - game.default_government - = lookup_government(file, "governments.default", filename); - - game.government_when_anarchy - = lookup_government(file, "governments.when_anarchy", filename); - - game.ai_goal_government - = lookup_government(file, "governments.ai_goal", filename); - - freelog(LOG_DEBUG, "govs: def %d, anarchy %d, ai_goal %d", - game.default_government, game.government_when_anarchy, - game.ai_goal_government); - - /* Because player_init is called before rulesets are loaded we set - * all players governments here, if they have not been previously - * set (eg by loading game). - */ - for(i=0; ibasetype = G_MAGIC; g->required_tech = lookup_tech(file, sec[i], "tech_req", FALSE, filename, g->name); @@ -1683,32 +1737,32 @@ = secfile_lookup_int_default(file, 36, "%s.waste_max_distance_cap", sec[i]); g->trade_bonus - = secfile_lookup_int(file, "%s.production_trade_bonus", sec[i]); + = secfile_lookup_int(file, "%s.trade_bonus", sec[i]); g->shield_bonus - = secfile_lookup_int(file, "%s.production_shield_bonus", sec[i]); + = secfile_lookup_int(file, "%s.shield_bonus", sec[i]); g->food_bonus - = secfile_lookup_int(file, "%s.production_food_bonus", sec[i]); + = secfile_lookup_int(file, "%s.food_bonus", sec[i]); g->celeb_trade_bonus - = secfile_lookup_int(file, "%s.production_trade_bonus,1", sec[i]); + = secfile_lookup_int(file, "%s.celeb_trade_bonus", sec[i]); g->celeb_shield_bonus - = secfile_lookup_int(file, "%s.production_shield_bonus,1", sec[i]); + = secfile_lookup_int(file, "%s.celeb_shield_bonus", sec[i]); g->celeb_food_bonus - = secfile_lookup_int(file, "%s.production_food_bonus,1", sec[i]); + = secfile_lookup_int(file, "%s.celeb_food_bonus", sec[i]); g->trade_before_penalty - = secfile_lookup_int(file, "%s.production_trade_penalty", sec[i]); + = secfile_lookup_int(file, "%s.trade_penalty", sec[i]); g->shields_before_penalty - = secfile_lookup_int(file, "%s.production_shield_penalty", sec[i]); + = secfile_lookup_int(file, "%s.shield_penalty", sec[i]); g->food_before_penalty - = secfile_lookup_int(file, "%s.production_food_penalty", sec[i]); + = secfile_lookup_int(file, "%s.food_penalty", sec[i]); g->celeb_trade_before_penalty - = secfile_lookup_int(file, "%s.production_trade_penalty,1", sec[i]); + = secfile_lookup_int(file, "%s.celeb_trade_penalty", sec[i]); g->celeb_shields_before_penalty - = secfile_lookup_int(file, "%s.production_shield_penalty,1", sec[i]); + = secfile_lookup_int(file, "%s.celeb_shield_penalty", sec[i]); g->celeb_food_before_penalty - = secfile_lookup_int(file, "%s.production_food_penalty,1", sec[i]); + = secfile_lookup_int(file, "%s.celeb_food_penalty", sec[i]); g->effect = load_effects(sec[i], g->name, file, FALSE, TRUE); @@ -1793,6 +1847,72 @@ } freelog(LOG_DEBUG, "%s subgoal %d", g->name, g->subgoal); } + free(sec); + + gov_modifiers = read_modifiers(file, &game.num_gov_modifiers, + gov_modifier_types, + game.num_gov_modifier_types); + + sec = secfile_get_secnames_prefix(file, "compound_government_", &nval); + for (i = 0; i < nval; ++i) { + int modifiers[MAX_MODS]; + char *name, *sval; + int basetype; + + name = secfile_lookup_str(file, "%s.name", sec[i]); + basetype = lookup_government(file, sec[i], "base", filename); + freelog(LOG_DEBUG, "Forming compound gov %s", name); + + for (j = 0; j < game.num_gov_modifier_types; ++j) { + sval = secfile_lookup_str(file, "%s.modifiers,%d", sec[i], j); + if (!gov_modifier_types[j].must_use && sval[0] == '\0') { + modifiers[j] = -1; + } else { + int ival = find_gov_modifier_by_name(sval); + + if (ival < 0) { + freelog(LOG_FATAL, + "for %s, couldn't match gov modifier \"%s\" (%s)", + sec[i], sval, filename); + exit(EXIT_FAILURE); + } else if (gov_modifiers[ival].type != gov_modifier_types[j].id) { + freelog(LOG_FATAL, "for %s, gov modifier \"%s\" is not of " + "required compound type %s (%s)", + sec[i], sval, gov_modifier_types[j].name, + filename); + exit(EXIT_FAILURE); + } else { + modifiers[j] = ival; + } + } + } + form_compound_gov(NULL, name, basetype, modifiers); + } + free(sec); + + game.default_government + = lookup_government(file, "governments", "default", filename); + + game.government_when_anarchy + = lookup_government(file, "governments", "when_anarchy", filename); + + game.ai_goal_government + = lookup_government(file, "governments", "ai_goal", filename); + + freelog(LOG_DEBUG, "govs: def %d, anarchy %d, ai_goal %d", + game.default_government, game.government_when_anarchy, + game.ai_goal_government); + + /* Because player_init is called before rulesets are loaded we set + * all players governments here, if they have not been previously + * set (eg by loading game). + */ + for(i=0; iid; + sz_strlcpy(packet.name, u->name); + packet.tech_requirement = u->tech_requirement; + packet.must_use = u->must_use; + lsend_packet_ruleset_modifier_type(dest, &packet); + } +} + +static void send_ruleset_unit_modifier_types(struct conn_list *dest) +{ + send_ruleset_modifier_types(dest, FALSE); +} + +static void send_ruleset_gov_modifier_types(struct conn_list *dest) +{ + send_ruleset_modifier_types(dest, TRUE); +} + +static void send_ruleset_modifiers(struct conn_list *dest, bool is_gov) +{ + struct packet_ruleset_modifier packet; + int i, num_mods; + struct modifier *modifiers; + + if (is_gov) { + num_mods = game.num_gov_modifiers; + modifiers = gov_modifiers; + } else { + num_mods = game.num_unit_modifiers; + modifiers = unit_modifiers; + } + + for (i = 0; i < num_mods; ++i) { + struct modifier *u = &modifiers[i]; + + packet.id = i; + packet.is_gov = is_gov; + sz_strlcpy(packet.name, u->name); + packet.type = u->type; + packet.tech_requirement = u->tech_requirement; + packet.effect = u->effect; /* pointer assignment */ + lsend_packet_ruleset_modifier(dest, &packet); + } +} + +static void send_ruleset_unit_modifiers(struct conn_list *dest) +{ + send_ruleset_modifiers(dest, FALSE); +} + +static void send_ruleset_gov_modifiers(struct conn_list *dest) +{ + send_ruleset_modifiers(dest, TRUE); +} + /************************************************************************** Send the units ruleset information (all individual units) to the specified connections. **************************************************************************/ static void send_ruleset_units(struct conn_list *dest) { - struct packet_ruleset_unit packet; - unit_type_iterate(utype_id) { - struct unit_type *u = get_unit_type(utype_id); + send_single_unit(dest, utype_id); + } unit_type_iterate_end; +} - packet.id = u-unit_types; - sz_strlcpy(packet.name, u->name_orig); - sz_strlcpy(packet.sound_move, u->sound_move); - sz_strlcpy(packet.sound_move_alt, u->sound_move_alt); - sz_strlcpy(packet.sound_fight, u->sound_fight); - sz_strlcpy(packet.sound_fight_alt, u->sound_fight_alt); - sz_strlcpy(packet.graphic_str, u->graphic_str); - sz_strlcpy(packet.graphic_alt, u->graphic_alt); - packet.move_type = u->move_type; - packet.build_cost = u->build_cost; - packet.pop_cost = u->pop_cost; - packet.attack_strength = u->attack_strength; - packet.defense_strength = u->defense_strength; - packet.move_rate = u->move_rate; - packet.tech_requirement = u->tech_requirement; - packet.impr_requirement = u->impr_requirement; - packet.vision_range = u->vision_range; - packet.transport_capacity = u->transport_capacity; - packet.hp = u->hp; - packet.firepower = u->firepower; - packet.obsoleted_by = u->obsoleted_by; - packet.fuel = u->fuel; - packet.flags = u->flags; - packet.roles = u->roles; - packet.happy_cost = u->happy_cost; - packet.shield_cost = u->shield_cost; - packet.food_cost = u->food_cost; - packet.gold_cost = u->gold_cost; - packet.paratroopers_range = u->paratroopers_range; - packet.paratroopers_mr_req = u->paratroopers_mr_req; - packet.paratroopers_mr_sub = u->paratroopers_mr_sub; - packet.effect = u->effect; /* pointer assignment */ - packet.helptext = u->helptext; /* pointer assignment */ +/************************************************************************** + Sends a single unit type to the player, to allow individual unit types + to be resent later during the game if the details change +**************************************************************************/ +void send_single_unit(struct conn_list *dest, Unit_Type_id utype_id) +{ + struct packet_ruleset_unit packet; + struct unit_type *u = get_unit_type(utype_id); + int i; - lsend_packet_ruleset_unit(dest, &packet); - } unit_type_iterate_end; + packet.id = u-unit_types; + sz_strlcpy(packet.name, u->name_orig); + sz_strlcpy(packet.sound_move, u->sound_move); + sz_strlcpy(packet.sound_move_alt, u->sound_move_alt); + sz_strlcpy(packet.sound_fight, u->sound_fight); + sz_strlcpy(packet.sound_fight_alt, u->sound_fight_alt); + sz_strlcpy(packet.graphic_str, u->graphic_str); + sz_strlcpy(packet.graphic_alt, u->graphic_alt); + packet.move_type = u->move_type; + packet.build_cost = u->build_cost; + packet.pop_cost = u->pop_cost; + packet.attack_strength = u->attack_strength; + packet.defense_strength = u->defense_strength; + packet.move_rate = u->move_rate; + packet.tech_requirement = u->tech_requirement; + packet.impr_requirement = u->impr_requirement; + packet.vision_range = u->vision_range; + packet.transport_capacity = u->transport_capacity; + packet.hp = u->hp; + packet.firepower = u->firepower; + packet.obsoleted_by = u->obsoleted_by; + packet.fuel = u->fuel; + packet.flags = u->flags; + packet.roles = u->roles; + packet.happy_cost = u->happy_cost; + packet.shield_cost = u->shield_cost; + packet.food_cost = u->food_cost; + packet.gold_cost = u->gold_cost; + packet.paratroopers_range = u->paratroopers_range; + packet.paratroopers_mr_req = u->paratroopers_mr_req; + packet.paratroopers_mr_sub = u->paratroopers_mr_sub; + packet.basetype = u->basetype; + for (i = 0; i < MAX_MODS; ++i) { + packet.modifiers[i] = u->modifiers[i]; + } + packet.effect = u->effect; /* pointer assignment */ + packet.helptext = u->helptext; /* pointer assignment */ + + lsend_packet_ruleset_unit(dest, &packet); } /************************************************************************** @@ -2716,92 +2927,109 @@ **************************************************************************/ static void send_ruleset_governments(struct conn_list *dest) { + int i; + + for (i = 0; i < game.government_count; ++i) { + send_single_government(dest, i); + } +} + +/************************************************************************** + Send a single government type to the connections - this allows portions + of the government ruleset to be resent to the clients as they change + during the course of the game. +**************************************************************************/ +void send_single_government(struct conn_list *dest, int id) +{ struct packet_ruleset_government gov; struct packet_ruleset_government_ruler_title title; struct ruler_title *p_title; struct government *g; - int i, j; + int i; - for (i = 0; i < game.government_count; i++) { - g = &governments[i]; + g = &governments[id]; - /* send one packet_government */ - gov.id = i; + /* send one packet_government */ + gov.id = id; - gov.required_tech = g->required_tech; - gov.max_rate = g->max_rate; - gov.civil_war = g->civil_war; - gov.martial_law_max = g->martial_law_max; - gov.martial_law_per = g->martial_law_per; - gov.empire_size_mod = g->empire_size_mod; - gov.empire_size_inc = g->empire_size_inc; - gov.rapture_size = g->rapture_size; - - gov.unit_happy_cost_factor = g->unit_happy_cost_factor; - gov.unit_shield_cost_factor = g->unit_shield_cost_factor; - gov.unit_food_cost_factor = g->unit_food_cost_factor; - gov.unit_gold_cost_factor = g->unit_gold_cost_factor; - - gov.free_happy = g->free_happy; - gov.free_shield = g->free_shield; - gov.free_food = g->free_food; - gov.free_gold = g->free_gold; - - gov.trade_before_penalty = g->trade_before_penalty; - gov.shields_before_penalty = g->shields_before_penalty; - gov.food_before_penalty = g->food_before_penalty; - - gov.celeb_trade_before_penalty = g->celeb_trade_before_penalty; - gov.celeb_shields_before_penalty = g->celeb_shields_before_penalty; - gov.celeb_food_before_penalty = g->celeb_food_before_penalty; - - gov.trade_bonus = g->trade_bonus; - gov.shield_bonus = g->shield_bonus; - gov.food_bonus = g->food_bonus; - - gov.celeb_trade_bonus = g->celeb_trade_bonus; - gov.celeb_shield_bonus = g->celeb_shield_bonus; - gov.celeb_food_bonus = g->celeb_food_bonus; - - gov.corruption_level = g->corruption_level; - gov.corruption_modifier = g->corruption_modifier; - gov.fixed_corruption_distance = g->fixed_corruption_distance; - gov.corruption_distance_factor = g->corruption_distance_factor; - gov.extra_corruption_distance = g->extra_corruption_distance; - gov.corruption_max_distance_cap = g->corruption_max_distance_cap; - - gov.waste_level = g->waste_level; - gov.waste_modifier = g->waste_modifier; - gov.fixed_waste_distance = g->fixed_waste_distance; - gov.waste_distance_factor = g->waste_distance_factor; - gov.extra_waste_distance = g->extra_waste_distance; - gov.waste_max_distance_cap = g->waste_max_distance_cap; + gov.required_tech = g->required_tech; + gov.max_rate = g->max_rate; + gov.civil_war = g->civil_war; + gov.martial_law_max = g->martial_law_max; + gov.martial_law_per = g->martial_law_per; + gov.empire_size_mod = g->empire_size_mod; + gov.empire_size_inc = g->empire_size_inc; + gov.rapture_size = g->rapture_size; + + gov.basetype = g->basetype; + for (i = 0; i < MAX_MODS; ++i) { + gov.modifiers[i] = g->modifiers[i]; + } + + gov.unit_happy_cost_factor = g->unit_happy_cost_factor; + gov.unit_shield_cost_factor = g->unit_shield_cost_factor; + gov.unit_food_cost_factor = g->unit_food_cost_factor; + gov.unit_gold_cost_factor = g->unit_gold_cost_factor; + + gov.free_happy = g->free_happy; + gov.free_shield = g->free_shield; + gov.free_food = g->free_food; + gov.free_gold = g->free_gold; + + gov.trade_before_penalty = g->trade_before_penalty; + gov.shields_before_penalty = g->shields_before_penalty; + gov.food_before_penalty = g->food_before_penalty; + + gov.celeb_trade_before_penalty = g->celeb_trade_before_penalty; + gov.celeb_shields_before_penalty = g->celeb_shields_before_penalty; + gov.celeb_food_before_penalty = g->celeb_food_before_penalty; + + gov.trade_bonus = g->trade_bonus; + gov.shield_bonus = g->shield_bonus; + gov.food_bonus = g->food_bonus; + + gov.celeb_trade_bonus = g->celeb_trade_bonus; + gov.celeb_shield_bonus = g->celeb_shield_bonus; + gov.celeb_food_bonus = g->celeb_food_bonus; + + gov.corruption_level = g->corruption_level; + gov.corruption_modifier = g->corruption_modifier; + gov.fixed_corruption_distance = g->fixed_corruption_distance; + gov.corruption_distance_factor = g->corruption_distance_factor; + gov.extra_corruption_distance = g->extra_corruption_distance; + gov.corruption_max_distance_cap = g->corruption_max_distance_cap; + + gov.waste_level = g->waste_level; + gov.waste_modifier = g->waste_modifier; + gov.fixed_waste_distance = g->fixed_waste_distance; + gov.waste_distance_factor = g->waste_distance_factor; + gov.extra_waste_distance = g->extra_waste_distance; + gov.waste_max_distance_cap = g->waste_max_distance_cap; - gov.flags = g->flags; - gov.hints = g->hints; - gov.num_ruler_titles = g->num_ruler_titles; - - sz_strlcpy(gov.name, g->name_orig); - sz_strlcpy(gov.graphic_str, g->graphic_str); - sz_strlcpy(gov.graphic_alt, g->graphic_alt); + gov.flags = g->flags; + gov.hints = g->hints; + gov.num_ruler_titles = g->num_ruler_titles; + + sz_strlcpy(gov.name, g->name_orig); + sz_strlcpy(gov.graphic_str, g->graphic_str); + sz_strlcpy(gov.graphic_alt, g->graphic_alt); - gov.effect = g->effect; /* pointer assignment */ - gov.helptext = g->helptext; /* pointer assignment */ + gov.effect = g->effect; /* pointer assignment */ + gov.helptext = g->helptext; /* pointer assignment */ - lsend_packet_ruleset_government(dest, &gov); + lsend_packet_ruleset_government(dest, &gov); - /* send one packet_government_ruler_title per ruler title */ - for(j=0; jnum_ruler_titles; j++) { - p_title = &g->ruler_titles[j]; - - title.gov = i; - title.id = j; - title.nation = p_title->nation; - sz_strlcpy(title.male_title, p_title->male_title); - sz_strlcpy(title.female_title, p_title->female_title); + /* send one packet_government_ruler_title per ruler title */ + for(i = 0; i < g->num_ruler_titles; i++) { + p_title = &g->ruler_titles[i]; + + title.gov = id; + title.id = i; + title.nation = p_title->nation; + sz_strlcpy(title.male_title, p_title->male_title); + sz_strlcpy(title.female_title, p_title->female_title); - lsend_packet_ruleset_government_ruler_title(dest, &title); - } + lsend_packet_ruleset_government_ruler_title(dest, &title); } } @@ -2951,7 +3179,11 @@ send_ruleset_game(dest); send_ruleset_techs(dest); send_ruleset_governments(dest); + send_ruleset_gov_modifier_types(dest); + send_ruleset_gov_modifiers(dest); send_ruleset_units(dest); + send_ruleset_unit_modifier_types(dest); + send_ruleset_unit_modifiers(dest); send_ruleset_terrain(dest); send_ruleset_buildings(dest); send_ruleset_nations(dest); diff -Nur -Xfreecivdiff.ignore freeciv-patched/server/ruleset.h freeciv-compunit/server/ruleset.h --- freeciv-patched/server/ruleset.h 2003-01-03 16:09:50.000000000 +0000 +++ freeciv-compunit/server/ruleset.h 2003-06-12 13:42:21.000000000 +0100 @@ -13,9 +13,14 @@ #ifndef FC__RULESET_H #define FC__RULESET_H +#include "unittype.h" + struct conn_list; void load_rulesets(void); void send_rulesets(struct conn_list *dest); +void send_single_unit(struct conn_list *dest, Unit_Type_id utype_id); +void send_single_government(struct conn_list *dest, int id); + #endif /* FC__RULESET_H */ diff -Nur -Xfreecivdiff.ignore freeciv-patched/server/savegame.c freeciv-compunit/server/savegame.c --- freeciv-patched/server/savegame.c 2003-06-12 13:39:43.000000000 +0100 +++ freeciv-compunit/server/savegame.c 2003-06-12 13:42:21.000000000 +0100 @@ -24,6 +24,7 @@ #include "city.h" #include "fcintl.h" #include "game.h" +#include "government.h" #include "idex.h" #include "log.h" #include "map.h" @@ -1809,6 +1810,72 @@ /*************************************************************** ... ***************************************************************/ +static void govs_load(struct section_file *file) +{ + int numcomps, compind, govind; + + numcomps = secfile_lookup_int_default(file, 0, "game.num_compound_govs"); + + /* Truncate unit list at the first generated compound gov */ + for (govind = 0; govind < game.government_count; ++govind) { + if (governments[govind].basetype != G_MAGIC) { + game.government_count = govind; + freelog(LOG_DEBUG, "govs truncated to %d", govind); + governments = (struct government *)fc_realloc(governments, + game.government_count * sizeof(struct government)); + break; + } + } + for (compind = 0; compind < numcomps; ++compind) { + int modind, modifiers[MAX_MODS]; + int basetype; + char *name; + + name = secfile_lookup_str(file, "game.cgov%d.name", compind); + basetype = secfile_lookup_int(file, "game.cgov%d.basetype", compind); + for (modind = 0; modind < game.num_gov_modifier_types; ++modind) { + modifiers[modind] = secfile_lookup_int(file, "game.cgov%d.modifiers%d", + compind, modind); + } + form_compound_gov(NULL, name, basetype, modifiers); + } +} + +/*************************************************************** +... +***************************************************************/ +static void units_load(struct section_file *file) +{ + int numcomps, compind; + + numcomps = secfile_lookup_int_default(file, 0, "game.num_compound_units"); + + /* Truncate unit list at the first generated compound unit */ + unit_type_iterate(uid) { + if (unit_types[uid].basetype != U_LAST) { + game.num_unit_types = uid; + freelog(LOG_DEBUG, "units truncated to %d", uid); + break; + } + } unit_type_iterate_end; + for (compind = 0; compind < numcomps; ++compind) { + int modind, modifiers[MAX_MODS]; + Unit_Type_id basetype; + char *name; + + name = secfile_lookup_str(file, "game.cunit%d.name", compind); + basetype = secfile_lookup_int(file, "game.cunit%d.basetype", compind); + for (modind = 0; modind < game.num_unit_modifier_types; ++modind) { + modifiers[modind] = secfile_lookup_int(file, "game.cunit%d.modifiers%d", + compind, modind); + } + form_compound_unit(name, basetype, modifiers); + } +} + +/*************************************************************** +... +***************************************************************/ void game_load(struct section_file *file) { int i; @@ -2037,6 +2104,11 @@ game.cooling=0; load_rulesets(); + + /* This needs to be after rulesets are loaded so that we can access + * the base types for generating compound units */ + units_load(file); + govs_load(file); } { @@ -2225,6 +2297,70 @@ /*************************************************************** ... ***************************************************************/ +static void govs_save(struct section_file *file) +{ + bool write = FALSE; + int govind, compind = -1; + + for (govind = 0; govind < game.government_count; ++govind) { + struct government *g = &governments[govind]; + + if (!write && g->basetype != G_MAGIC) { + write = TRUE; + secfile_insert_int(file, game.government_count - govind, + "game.num_compound_govs"); + } + if (write) { + int modind; + + compind++; + secfile_insert_str(file, g->name, "game.cgov%d.name", compind); + secfile_insert_int(file, g->basetype, "game.cgov%d.basetype", + compind); + for (modind = 0; modind < game.num_gov_modifier_types; ++modind) { + secfile_insert_int(file, g->modifiers[modind], + "game.cgov%d.modifiers%d", + compind, modind); + } + } + } +} + +/*************************************************************** +... +***************************************************************/ +static void units_save(struct section_file *file) +{ + bool write = FALSE; + int compind = -1; + + unit_type_iterate(uid) { + struct unit_type *u = &unit_types[uid]; + + if (!write && u->basetype != U_LAST) { + write = TRUE; + secfile_insert_int(file, game.num_unit_types - uid, + "game.num_compound_units"); + } + if (write) { + int modind; + + compind++; + secfile_insert_str(file, u->name, "game.cunit%d.name", compind); + secfile_insert_int(file, u->basetype, "game.cunit%d.basetype", + compind); + for (modind = 0; modind < game.num_unit_modifier_types; ++modind) { + secfile_insert_int(file, u->modifiers[modind], + "game.cunit%d.modifiers%d", + compind, modind); + } + } + } unit_type_iterate_end; +} + +/*************************************************************** +... +***************************************************************/ void game_save(struct section_file *file) { int i; @@ -2316,6 +2452,9 @@ secfile_insert_int(file, game.watchtower_extra_vision, "game.watchtower_extra_vision"); secfile_insert_int(file, game.allowed_city_names, "game.allowed_city_names"); + units_save(file); + govs_save(file); + if (TRUE) { /* Now always save these, so the server options reflect the * actual values used at the start of the game. diff -Nur -Xfreecivdiff.ignore freeciv-patched/server/srv_main.c freeciv-compunit/server/srv_main.c --- freeciv-patched/server/srv_main.c 2003-06-12 13:39:43.000000000 +0100 +++ freeciv-compunit/server/srv_main.c 2003-06-12 13:42:21.000000000 +0100 @@ -833,6 +833,10 @@ handle_player_tech_goal(pplayer, (struct packet_player_request *)packet); break; + case PACKET_REQUEST_COMPOUND: + handle_request_compound(pplayer, (struct packet_request_compound *)packet); + break; + case PACKET_UNIT_BUILD_CITY: handle_unit_build_city(pplayer, (struct packet_unit_request *)packet); break;