diff -Nur -Xfreecivdiff.ignore freeciv-cvs/client/civclient.c freeciv-patched/client/civclient.c --- freeciv-cvs/client/civclient.c 2003-07-23 16:36:52.000000000 +0100 +++ freeciv-patched/client/civclient.c 2003-07-24 17:24:46.000000000 +0100 @@ -377,6 +377,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-cvs/client/gui-gtk/dialogs.c freeciv-patched/client/gui-gtk/dialogs.c --- freeciv-cvs/client/gui-gtk/dialogs.c 2003-07-21 13:58:23.000000000 +0100 +++ freeciv-patched/client/gui-gtk/dialogs.c 2003-07-24 17:24:46.000000000 +0100 @@ -176,6 +176,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; + /**************************************************************** ... *****************************************************************/ @@ -1118,6 +1130,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-cvs/client/gui-gtk/menu.c freeciv-patched/client/gui-gtk/menu.c --- freeciv-cvs/client/gui-gtk/menu.c 2003-07-23 16:36:52.000000000 +0100 +++ freeciv-patched/client/gui-gtk/menu.c 2003-07-24 17:24:46.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, @@ -213,6 +215,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; @@ -610,6 +618,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!"), @@ -1049,6 +1063,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-cvs/client/gui-gtk-2.0/dialogs.c freeciv-patched/client/gui-gtk-2.0/dialogs.c --- freeciv-cvs/client/gui-gtk-2.0/dialogs.c 2003-07-21 13:58:23.000000000 +0100 +++ freeciv-patched/client/gui-gtk-2.0/dialogs.c 2003-07-24 17:24:46.000000000 +0100 @@ -130,6 +130,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; + /**************************************************************** ... *****************************************************************/ @@ -2366,3 +2378,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-cvs/client/gui-gtk-2.0/menu.c freeciv-patched/client/gui-gtk-2.0/menu.c --- freeciv-cvs/client/gui-gtk-2.0/menu.c 2003-07-23 16:36:52.000000000 +0100 +++ freeciv-patched/client/gui-gtk-2.0/menu.c 2003-07-24 17:24:46.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, @@ -214,6 +216,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; @@ -609,6 +617,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"), @@ -1068,6 +1082,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-cvs/client/helpdata.c freeciv-patched/client/helpdata.c --- freeciv-cvs/client/helpdata.c 2003-07-24 17:23:22.000000000 +0100 +++ freeciv-patched/client/helpdata.c 2003-07-24 17:24:46.000000000 +0100 @@ -714,9 +714,13 @@ strcat(astr.str, deli_str); } } - - assert(num_allowed_units > 0); + if (num_allowed_units == 0) { + char *deli_str = _("carrier unit"); + astr_minsize(&astr, strlen(deli_str)); + strcpy(astr.str, deli_str); + } + sprintf(buf + strlen(buf), PL_("* Unit has to be in a city, or on a %s" " after %d turn.\n", diff -Nur -Xfreecivdiff.ignore freeciv-cvs/client/include/dialogs_g.h freeciv-patched/client/include/dialogs_g.h --- freeciv-cvs/client/include/dialogs_g.h 2002-11-29 12:25:10.000000000 +0000 +++ freeciv-patched/client/include/dialogs_g.h 2003-07-24 17:24:46.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-cvs/client/Makefile.am freeciv-patched/client/Makefile.am --- freeciv-cvs/client/Makefile.am 2003-06-07 19:58:19.000000000 +0100 +++ freeciv-patched/client/Makefile.am 2003-07-24 17:24:46.000000000 +0100 @@ -185,4 +185,4 @@ civclient_LDADD = @gui_sources@/libguiclient.a \ @INTLLIBS@ ../common/aicore/libaicore.a \ ../common/libcivcommon.a agents/libagents.a \ - @CLIENT_LIBS@ @SOUND_LIBS@ + @CLIENT_LIBS@ @SOUND_LIBS@ -lslang-utf8 diff -Nur -Xfreecivdiff.ignore freeciv-cvs/client/packhand.c freeciv-patched/client/packhand.c --- freeciv-cvs/client/packhand.c 2003-07-24 17:23:22.000000000 +0100 +++ freeciv-patched/client/packhand.c 2003-07-24 17:24:46.000000000 +0100 @@ -1978,6 +1978,25 @@ game.borders = packet->borders; + 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); @@ -1998,12 +2017,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); @@ -2039,9 +2063,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 */ } /************************************************************************** @@ -2244,13 +2331,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; @@ -2263,6 +2358,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; @@ -2319,6 +2419,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-cvs/client/packhand.h freeciv-patched/client/packhand.h --- freeciv-cvs/client/packhand.h 2003-06-27 15:51:10.000000000 +0100 +++ freeciv-patched/client/packhand.h 2003-07-24 17:24:46.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-cvs/common/capstr.c freeciv-patched/common/capstr.c --- freeciv-cvs/common/capstr.c 2003-07-24 17:23:22.000000000 +0100 +++ freeciv-patched/common/capstr.c 2003-07-24 17:24:46.000000000 +0100 @@ -79,7 +79,7 @@ "+impr_req +waste +fastfocus +continent +small_dipl " \ "+no_nation_selected +diplomacy +no_extra_tiles " \ "+diplomacy2 +citizens_style +root_tech auth " \ - "+nat_ulimit retake +goto_pack borders impr_gen" + "+nat_ulimit retake +goto_pack borders impr_gen compounds" /* "+1.14.0" is protocol for 1.14.0 release. * diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/game.h freeciv-patched/common/game.h --- freeciv-cvs/common/game.h 2003-07-24 17:23:22.000000000 +0100 +++ freeciv-patched/common/game.h 2003-07-24 17:24:46.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-cvs/common/government.c freeciv-patched/common/government.c --- freeciv-cvs/common/government.c 2003-07-24 17:23:22.000000000 +0100 +++ freeciv-patched/common/government.c 2003-07-24 17:24:46.000000000 +0100 @@ -19,10 +19,12 @@ #include #include +#include "fcintl.h" #include "game.h" #include "log.h" #include "mem.h" #include "player.h" +#include "script.h" #include "shared.h" #include "support.h" #include "tech.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" @@ -142,6 +146,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; +} + /*************************************************************** ... ***************************************************************/ @@ -324,3 +347,95 @@ governments = NULL; game.government_count = 0; } + +/*************************************************************** +... +***************************************************************/ +static void copy_government(struct government *dest, struct government *src) +{ + int i; + + memcpy(dest, src, sizeof(struct government)); + + dest->effect = NULL; + append_effects(&dest->effect, src->effect); + + dest->num_ruler_titles = src->num_ruler_titles; + dest->ruler_titles = fc_calloc(dest->num_ruler_titles, + sizeof(struct ruler_title)); + for (i = 0; i < dest->num_ruler_titles; i++) { + struct ruler_title *fromtitle = &(src->ruler_titles[i]); + struct ruler_title *totitle = &(dest->ruler_titles[i]); + + totitle->nation = fromtitle->nation; + sz_strlcpy(totitle->male_title, fromtitle->male_title); + sz_strlcpy(totitle->female_title, fromtitle->female_title); + } + + dest->helptext = src->helptext ? mystrdup(src->helptext) : NULL; +} + +/*************************************************************** +... +***************************************************************/ +int form_compound_gov(struct player *pplayer, const char *name, + const int basetype, const int modifiers[MAX_MODS]) +{ + struct government *gov = NULL, *base; + struct modifier *mod; + char buffer[200]; + 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]; + } else if (pplayer) { + government_free(gov); + } + base = &governments[basetype]; + copy_government(gov, base); + gov->index = id; + 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'; + my_snprintf(buffer, sizeof(buffer), + "variable gt = get_gov(%d);", id); + script_execute(buffer); + for (i = 0; i < game.num_gov_modifier_types; ++i) { + if (gov->modifiers[i] < U_LAST) { + mod = &gov_modifiers[gov->modifiers[i]]; + script_execute(mod->action); + } + } + for (i = 0; i < game.num_gov_modifier_types; ++i) { + if (gov->modifiers[i] < U_LAST) { + mod = &gov_modifiers[gov->modifiers[i]]; + script_execute(mod->final_action); + append_effects(&gov->effect, mod->effect); + } + } + my_snprintf(buffer, sizeof(buffer), + "set_gov(%d, gt);", id); + script_execute(buffer); + if (name && name[0]) { + sz_strlcpy(gov->name_orig, name); + sz_strlcpy(gov->name, _(gov->name_orig)); + } + + return id; +} diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/government.h freeciv-patched/common/government.h --- freeciv-cvs/common/government.h 2003-07-24 17:23:22.000000000 +0100 +++ freeciv-patched/common/government.h 2003-07-24 17:24:46.000000000 +0100 @@ -14,6 +14,7 @@ #define FC__GOVERNMENT_H #include "shared.h" +#include "modifier.h" struct city; struct player; @@ -39,6 +40,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 +158,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 +177,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 +189,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,6 +210,8 @@ const char *male, const char *female); void governments_alloc(int num); void governments_free(void); +int form_compound_gov(struct player *pplayer, const char *name, + const int basetype, const int modifiers[MAX_MODS]); #define government_iterate(gov) \ { \ diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/improvement.c freeciv-patched/common/improvement.c --- freeciv-cvs/common/improvement.c 2003-07-24 17:23:22.000000000 +0100 +++ freeciv-patched/common/improvement.c 2003-07-24 17:24:46.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-cvs/common/improvement.h freeciv-patched/common/improvement.h --- freeciv-cvs/common/improvement.h 2003-07-24 17:23:22.000000000 +0100 +++ freeciv-patched/common/improvement.h 2003-07-24 17:24:46.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-cvs/common/Makefile.am freeciv-patched/common/Makefile.am --- freeciv-cvs/common/Makefile.am 2003-06-07 19:58:26.000000000 +0100 +++ freeciv-patched/common/Makefile.am 2003-07-24 17:24:46.000000000 +0100 @@ -63,12 +63,16 @@ pqueue.h \ mem.c \ mem.h \ + modifier.c \ + modifier.h \ rand.c \ rand.h \ registry.c \ registry.h \ sbuffer.c \ sbuffer.h \ + script.c \ + script.h \ shared.c \ shared.h \ spaceship.c \ diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/modifier.c freeciv-patched/common/modifier.c --- freeciv-cvs/common/modifier.c 1970-01-01 01:00:00.000000000 +0100 +++ freeciv-patched/common/modifier.c 2003-07-24 17:24:46.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-cvs/common/modifier.h freeciv-patched/common/modifier.h --- freeciv-cvs/common/modifier.h 1970-01-01 01:00:00.000000000 +0100 +++ freeciv-patched/common/modifier.h 2003-07-24 17:24:46.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-cvs/common/packets.c freeciv-patched/common/packets.c --- freeciv-cvs/common/packets.c 2003-07-24 17:23:22.000000000 +0100 +++ freeciv-patched/common/packets.c 2003-07-24 17:24:46.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" @@ -431,6 +432,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: @@ -1956,6 +1963,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); @@ -2011,6 +2024,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); @@ -2085,6 +2107,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) { @@ -2152,6 +2181,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) { @@ -2238,6 +2276,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) @@ -2262,6 +2417,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); @@ -2342,6 +2500,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)); @@ -2664,6 +2825,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) { @@ -2764,6 +2932,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-cvs/common/packets.h freeciv-patched/common/packets.h --- freeciv-cvs/common/packets.h 2003-07-24 17:23:22.000000000 +0100 +++ freeciv-patched/common/packets.h 2003-07-24 17:24:46.000000000 +0100 @@ -130,6 +130,9 @@ PACKET_PING_INFO, PACKET_AUTHENTICATION_REQUEST, PACKET_AUTHENTICATION_REPLY, + PACKET_RULESET_MODIFIER_TYPE, + PACKET_RULESET_MODIFIER, + PACKET_REQUEST_COMPOUND, PACKET_LAST /* leave this last */ }; @@ -597,6 +600,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; @@ -654,6 +661,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 @@ -662,6 +672,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], root_req; /* indices for advances[] */ int flags; @@ -755,6 +792,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; @@ -1097,6 +1137,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-cvs/common/packets_lsend.c freeciv-patched/common/packets_lsend.c --- freeciv-cvs/common/packets_lsend.c 2003-07-10 11:41:09.000000000 +0100 +++ freeciv-patched/common/packets_lsend.c 2003-07-24 17:24:46.000000000 +0100 @@ -255,6 +255,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-cvs/common/packets_lsend.h freeciv-patched/common/packets_lsend.h --- freeciv-cvs/common/packets_lsend.h 2003-07-10 11:41:09.000000000 +0100 +++ freeciv-patched/common/packets_lsend.h 2003-07-24 17:24:46.000000000 +0100 @@ -76,6 +76,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-cvs/common/script.c freeciv-patched/common/script.c --- freeciv-cvs/common/script.c 1970-01-01 01:00:00.000000000 +0100 +++ freeciv-patched/common/script.c 2003-07-24 17:24:46.000000000 +0100 @@ -0,0 +1,346 @@ +/********************************************************************** + 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 +#include + +#include "fcintl.h" +#include "game.h" +#include "government.h" +#include "log.h" +#include "shared.h" +#include "support.h" +#include "unit.h" + +#include "script.h" + +static void ut_set_name(int *id, char *name) +{ + struct unit_type *ut = get_unit_type(*id); + sz_strlcpy(ut->name_orig, name); + sz_strlcpy(ut->name, _(name)); +} + +static void ut_set_graphic(int *id, char *name, char *name_alt) +{ + struct unit_type *ut = get_unit_type(*id); + sz_strlcpy(ut->graphic_str, name); + sz_strlcpy(ut->graphic_alt, name_alt); +} + +static void ut_set_move_rate(int *id, int *move_rate) +{ + struct unit_type *ut = get_unit_type(*id); + ut->move_rate = *move_rate * SINGLE_MOVE; +} + +struct members { + char *name; + unsigned long offset; +}; + +#define FC_UT_MEMBER(member, name) \ + {#name, ((unsigned long) ((char *) &((struct unit_type *)0)->member))} + +#define FC_MEMBER_P(struct_p, offset) \ + ((int *) ((char *)(struct_p) + offset)) + +static struct members ut_members[] = +{ + FC_UT_MEMBER(move_type, move_type), + FC_UT_MEMBER(build_cost, build_cost), + FC_UT_MEMBER(pop_cost, pop_cost), + FC_UT_MEMBER(attack_strength, attack), + FC_UT_MEMBER(defense_strength, defense), + FC_UT_MEMBER(vision_range, vision_range), + FC_UT_MEMBER(transport_capacity, transport_cap), + FC_UT_MEMBER(hp, hitpoints), + FC_UT_MEMBER(firepower, firepower), + FC_UT_MEMBER(fuel, fuel), + FC_UT_MEMBER(happy_cost, uk_happy), + FC_UT_MEMBER(shield_cost, uk_shield), + FC_UT_MEMBER(food_cost, uk_food), + FC_UT_MEMBER(gold_cost, uk_gold) +}; +#define num_ut_members (sizeof(ut_members) / sizeof(ut_members[0])) + +static void ut_get(int *id) +{ + char *field_names[num_ut_members + 6]; + unsigned char field_types[num_ut_members + 6]; + VOID_STAR field_values[num_ut_members + 6]; + struct unit_type *ut = get_unit_type(*id); + int move_rate = ut->move_rate / SINGLE_MOVE; + char *name = ut->name_orig; + char *graphic = ut->graphic_str, *graphic_alt = ut->graphic_alt; + int i; + + for (i = 0; i < num_ut_members; i++) { + field_names[i] = ut_members[i].name; + field_types[i] = SLANG_INT_TYPE; + field_values[i] = FC_MEMBER_P(ut, ut_members[i].offset); + } + + field_names[i] = "name"; + field_types[i] = SLANG_STRING_TYPE; + field_values[i++] = &name; + + field_names[i] = "graphic"; + field_types[i] = SLANG_STRING_TYPE; + field_values[i++] = &graphic; + + field_names[i] = "graphic_alt"; + field_types[i] = SLANG_STRING_TYPE; + field_values[i++] = &graphic_alt; + + field_names[i] = "move_rate"; + field_types[i] = SLANG_INT_TYPE; + field_values[i++] = &move_rate; + + field_names[i] = "flags"; + field_types[i] = SLANG_NULL_TYPE; + field_values[i++] = NULL; + + field_names[i] = "roles"; + field_types[i] = SLANG_NULL_TYPE; + field_values[i++] = NULL; + + SLstruct_create_struct(i, field_names, field_types, field_values); +} + +static void ut_set_ints(void) +{ + int i, id; + unsigned int num = SLang_Num_Function_Args; + struct unit_type *ut; + + assert(num == num_ut_members + 1); + + SLang_pop_integer(&id); + ut = get_unit_type(id); + + for (i = num_ut_members - 1; i >= 0; i--) { + int val, *pt; + SLang_pop_integer(&val); + pt = FC_MEMBER_P(ut, ut_members[i].offset); + *pt = val; + } +} + +static void gt_set_name(int *id, char *name) +{ + struct government *gov = get_government(*id); + sz_strlcpy(gov->name_orig, name); + sz_strlcpy(gov->name, _(name)); +} + +#define FC_GT_MEMBER(member, name) \ + {#name, ((unsigned long) ((char *) &((struct government *)0)->member))} + +static struct members gt_members[] = +{ + FC_GT_MEMBER(max_rate, max_single_rate), + FC_GT_MEMBER(civil_war, civil_war_chance), + FC_GT_MEMBER(free_happy, unit_free_unhappy), + FC_GT_MEMBER(free_shield, unit_free_shield), + FC_GT_MEMBER(free_food, unit_free_food), + FC_GT_MEMBER(free_gold, unit_free_gold) +}; +#define num_gt_members (sizeof(gt_members) / sizeof(gt_members[0])) + +static void gt_get(int *id) +{ + char *field_names[num_gt_members + 3]; + unsigned char field_types[num_gt_members + 3]; + VOID_STAR field_values[num_gt_members + 3]; + struct government *gov = get_government(*id); + char *name = gov->name_orig; + char *graphic = gov->graphic_str, *graphic_alt = gov->graphic_alt; + int i; + + for (i = 0; i < num_gt_members; i++) { + field_names[i] = gt_members[i].name; + field_types[i] = SLANG_INT_TYPE; + field_values[i] = FC_MEMBER_P(gov, gt_members[i].offset); + } + + field_names[i] = "name"; + field_types[i] = SLANG_STRING_TYPE; + field_values[i++] = &name; + + field_names[i] = "graphic"; + field_types[i] = SLANG_STRING_TYPE; + field_values[i++] = &graphic; + + field_names[i] = "graphic_alt"; + field_types[i] = SLANG_STRING_TYPE; + field_values[i++] = &graphic_alt; + + SLstruct_create_struct(i, field_names, field_types, field_values); +} + +static void sl_freelog(char *str) +{ + freelog(LOG_NORMAL, "%s", str); +} + +static void ut_get_flags(int *id) +{ + int i, dims[1] = {F_LAST}; + SLang_Array_Type *arr; + + arr = SLang_create_array(SLANG_INT_TYPE, 0, NULL, dims, 1); + + for (i = 0; i < F_LAST; i++) { + int val = unit_type_flag(*id, i) ? 1 : 0; + dims[0] = i; + SLang_set_array_element(arr, dims, &val); + } + + SLang_push_array(arr, 1); +} + +static void ut_set_flags(void) +{ + SLang_Array_Type *arr; + int id, i; + struct unit_type *ut; + + SLang_pop_array_of_type(&arr, SLANG_INT_TYPE); + assert(arr->num_dims == 1 && arr->dims[0] == F_LAST); + + SLang_pop_integer(&id); + ut = get_unit_type(id); + BV_CLR_ALL(ut->flags); + for (i = 0; i < F_LAST; i++) { + int val; + SLang_get_array_element(arr, &i, &val); + if (val) { + BV_SET(ut->flags, i); + } + } + SLang_free_array(arr); +} + +static void ut_get_roles(int *id) +{ + int i, dims[1] = {L_LAST - L_FIRST}; + SLang_Array_Type *arr; + + arr = SLang_create_array(SLANG_INT_TYPE, 0, NULL, dims, 1); + + for (i = L_FIRST; i < L_LAST; i++) { + int val = unit_has_role(*id, i) ? 1 : 0; + dims[0] = i - L_FIRST; + SLang_set_array_element(arr, dims, &val); + } + + SLang_push_array(arr, 1); +} + +static void ut_set_roles(void) +{ + SLang_Array_Type *arr; + int id, i; + struct unit_type *ut; + + SLang_pop_array_of_type(&arr, SLANG_INT_TYPE); + assert(arr->num_dims == 1 && arr->dims[0] == L_LAST - L_FIRST); + + SLang_pop_integer(&id); + ut = get_unit_type(id); + BV_CLR_ALL(ut->roles); + for (i = 0; i < L_LAST - L_FIRST; i++) { + int val; + SLang_get_array_element(arr, &i, &val); + if (val) { + BV_SET(ut->roles, i); + } + } + SLang_free_array(arr); +} + +static void register_intrinsics(void) +{ + char buffer[1024]; + static SLang_Intrin_Fun_Type intrins[] = + { + MAKE_INTRINSIC_I("ut_get", ut_get, SLANG_VOID_TYPE), + MAKE_INTRINSIC_IS("ut_set_name", ut_set_name, SLANG_VOID_TYPE), + MAKE_INTRINSIC_ISS("ut_set_graphic", ut_set_graphic, SLANG_VOID_TYPE), + MAKE_INTRINSIC_II("ut_set_move_rate", ut_set_move_rate, SLANG_VOID_TYPE), + MAKE_INTRINSIC_0("ut_set_flags", ut_set_flags, SLANG_VOID_TYPE), + MAKE_INTRINSIC_I("ut_get_flags", ut_get_flags, SLANG_VOID_TYPE), + MAKE_INTRINSIC_0("ut_set_roles", ut_set_roles, SLANG_VOID_TYPE), + MAKE_INTRINSIC_I("ut_get_roles", ut_get_roles, SLANG_VOID_TYPE), + MAKE_INTRINSIC_0("ut_set_ints", ut_set_ints, SLANG_VOID_TYPE), + MAKE_INTRINSIC_S("unit_flag_from_str", unit_flag_from_str, SLANG_INT_TYPE), + MAKE_INTRINSIC_S("unit_role_from_str", unit_role_from_str, SLANG_INT_TYPE), + MAKE_INTRINSIC_I("gt_get", gt_get, SLANG_VOID_TYPE), + MAKE_INTRINSIC_IS("gt_set_name", gt_set_name, SLANG_VOID_TYPE), + MAKE_INTRINSIC_S("freelog", sl_freelog, SLANG_VOID_TYPE), + SLANG_END_INTRIN_FUN_TABLE + }; + SLadd_intrin_fun_table(intrins, NULL); + my_snprintf(buffer, sizeof(buffer), + "variable Land = %d, Sea = %d, Heli = %d, Air = %d;", + LAND_MOVING, SEA_MOVING, HELI_MOVING, AIR_MOVING); + SLang_load_string(buffer); + my_snprintf(buffer, sizeof(buffer), + "variable F_LAST = %d, L_LAST = %d, L_FIRST = %d;", + F_LAST, L_LAST, L_FIRST); + SLang_load_string(buffer); +} + +void script_test(void) +{ + SLang_load_file("test.sl"); +} + +void script_execute(char *cmds) +{ + if (cmds) { + if (SLang_load_string(cmds) == -1) { + SLang_restart(1); + SLang_Error = 0; + } + } +} + +void script_load_library(void) +{ + char filename[512], *dfilename; + + my_snprintf(filename, sizeof(filename), "%s/library.sl", game.rulesetdir); + dfilename = datafilename(filename); + if (dfilename) { + if (SLang_load_file(dfilename) == -1) { + SLang_restart(1); + SLang_Error = 0; + } + } +} + +void script_init(void) +{ + if (SLang_init_slang() == -1) { + freelog(LOG_ERROR, "SLang init error"); + } else { + register_intrinsics(); + } +} diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/script.h freeciv-patched/common/script.h --- freeciv-cvs/common/script.h 1970-01-01 01:00:00.000000000 +0100 +++ freeciv-patched/common/script.h 2003-07-24 17:24:46.000000000 +0100 @@ -0,0 +1,21 @@ +/********************************************************************** + 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__SCRIPT_H +#define FC__SCRIPT_H + +void script_init(void); +void script_load_library(void); +void script_test(void); +void script_execute(char *cmds); + +#endif /* FC__SCRIPT_H */ diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/unittype.c freeciv-patched/common/unittype.c --- freeciv-cvs/common/unittype.c 2003-07-24 17:23:23.000000000 +0100 +++ freeciv-patched/common/unittype.c 2003-07-24 17:24:46.000000000 +0100 @@ -22,8 +22,11 @@ #include "fcintl.h" #include "game.h" #include "government.h" +#include "log.h" #include "mem.h" +#include "modifier.h" #include "player.h" +#include "script.h" #include "shared.h" #include "support.h" #include "tech.h" @@ -31,6 +34,8 @@ #include "unittype.h" 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,7 +57,7 @@ "DefendOk", "DefendGood", "AttackFast", "AttackStrong", "Ferryboat", "Barbarian", "BarbarianTech", "BarbarianBoat", "BarbarianBuild", "BarbarianBuildTech", "BarbarianLeader", - "BarbarianSea", "BarbarianSeaTech" + "BarbarianSea", "BarbarianSeaTech", "CanModify" }; /************************************************************************** @@ -379,6 +384,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 +475,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. */ @@ -643,6 +683,12 @@ free(p->helptext); p->helptext = NULL; + + free(p->action); + p->action = NULL; + + free(p->final_action); + p->final_action = NULL; } /*************************************************************** @@ -654,3 +700,132 @@ 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; + char newname[MAX_LEN_NAME]; + 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'; + } + + sz_strlcpy(newname, utype->name); + utype->name[0] = '\0'; /* Prevent this unittype from matching */ + while (find_unit_type_by_name(newname) != U_LAST) { + my_snprintf(newname, sizeof(newname), _("%s Mk%d"), tmpname, mark); + my_snprintf(utype->name_orig, sizeof(utype->name_orig), "%s Mk%d", + tmporig, mark); + assert(mark < 100); + mark++; + }; + sz_strlcpy(utype->name, newname); + + free(tmpname); + free(tmporig); +} + +/************************************************************************** + ... +**************************************************************************/ +static void copy_unit_type(struct unit_type *dest, struct unit_type *src) +{ + memcpy(dest, src, sizeof(struct unit_type)); + dest->effect = NULL; + append_effects(&dest->effect, src->effect); + dest->helptext = src->helptext ? mystrdup(src->helptext) : NULL; + dest->action = dest->final_action = NULL; +} + +/************************************************************************** + ... +**************************************************************************/ +Unit_Type_id form_compound_unit(const char *name, + const Unit_Type_id basetype, + const int modifiers[MAX_MODS], + char *final_action) +{ + Unit_Type_id id; + struct unit_type *u, *base; + struct modifier *mod; + char buffer[200]; + int i; + + id = game.num_unit_types; + if (id >= U_LAST) { + freelog(LOG_FATAL, "form_compound_unit: out of unit types"); + exit(EXIT_FAILURE); + } + game.num_unit_types++; + u = &unit_types[id]; + base = &unit_types[basetype]; + copy_unit_type(u, base); + u->basetype = basetype; + 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'; + my_snprintf(buffer, sizeof(buffer), + "variable ut = get_unit_type(%d);", id); + script_execute(buffer); + script_execute(base->action); + for (i = 0; i < game.num_unit_modifier_types; ++i) { + if (u->modifiers[i] < U_LAST) { + mod = &unit_modifiers[u->modifiers[i]]; + script_execute(mod->action); + } + } + for (i = 0; i < game.num_unit_modifier_types; ++i) { + if (u->modifiers[i] < U_LAST) { + mod = &unit_modifiers[u->modifiers[i]]; + script_execute(mod->final_action); + append_effects(&u->effect, mod->effect); + } + } + script_execute(base->final_action); + if (final_action) { + script_execute(final_action); + } + my_snprintf(buffer, sizeof(buffer), + "set_unit_type(%d, ut);", id); + script_execute(buffer); + /* 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); + return id; +} diff -Nur -Xfreecivdiff.ignore freeciv-cvs/common/unittype.h freeciv-patched/common/unittype.h --- freeciv-cvs/common/unittype.h 2003-07-24 17:23:23.000000000 +0100 +++ freeciv-patched/common/unittype.h 2003-07-24 17:24:46.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,10 @@ 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 *action, *final_action; + char *helptext; }; @@ -188,6 +197,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 +235,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 +262,11 @@ } \ } +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], + char *final_action); #endif /* FC__UNITTYPE_H */ diff -Nur -Xfreecivdiff.ignore freeciv-cvs/server/Makefile.am freeciv-patched/server/Makefile.am --- freeciv-cvs/server/Makefile.am 2003-07-21 13:58:26.000000000 +0100 +++ freeciv-patched/server/Makefile.am 2003-07-24 17:25:11.000000000 +0100 @@ -76,5 +76,5 @@ civserver_DEPENDENCIES = ../common/libcivcommon.a ../ai/libcivai.a ./libcivserver.a ../common/aicore/libaicore.a $(USER_DB_DEP) -civserver_LDADD = ../common/libcivcommon.a ../ai/libcivai.a ./libcivserver.a @INTLLIBS@ ../common/libcivcommon.a ../ai/libcivai.a ./libcivserver.a ../common/aicore/libaicore.a $(USER_DB_LIB) $(SERVER_LIBS) +civserver_LDADD = ../common/libcivcommon.a ../ai/libcivai.a ./libcivserver.a @INTLLIBS@ ../common/libcivcommon.a ../ai/libcivai.a ./libcivserver.a ../common/aicore/libaicore.a $(USER_DB_LIB) $(SERVER_LIBS) -lslang-utf8 diff -Nur -Xfreecivdiff.ignore freeciv-cvs/server/plrhand.c freeciv-patched/server/plrhand.c --- freeciv-cvs/server/plrhand.c 2003-07-24 17:23:24.000000000 +0100 +++ freeciv-patched/server/plrhand.c 2003-07-24 17:24:46.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" @@ -747,26 +748,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 */ @@ -788,6 +779,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) && @@ -849,6 +858,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, NULL); + 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-cvs/server/plrhand.h freeciv-patched/server/plrhand.h --- freeciv-cvs/server/plrhand.h 2003-06-07 19:58:49.000000000 +0100 +++ freeciv-patched/server/plrhand.h 2003-07-24 17:24:46.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-cvs/server/ruleset.c freeciv-patched/server/ruleset.c --- freeciv-cvs/server/ruleset.c 2003-07-24 17:23:24.000000000 +0100 +++ freeciv-patched/server/ruleset.c 2003-07-24 17:24:47.000000000 +0100 @@ -31,10 +31,12 @@ #include "nation.h" #include "packets.h" #include "registry.h" +#include "script.h" #include "shared.h" #include "support.h" #include "tech.h" #include "unit.h" +#include "unittype.h" #include "citytools.h" @@ -63,8 +65,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 +98,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 +353,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)", @@ -781,6 +787,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') { @@ -897,6 +920,92 @@ /************************************************************************** ... **************************************************************************/ +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; @@ -908,6 +1017,8 @@ 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 @@ -920,20 +1031,10 @@ 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; u->impr_requirement = find_improvement_by_name(secfile_lookup_str_default(file, "None", @@ -1000,6 +1101,10 @@ u->effect = load_effects(sec[i], u->name, file, TRUE, FALSE); u->helptext = lookup_helptext(file, sec[i]); + u->action = secfile_lookup_str_default(file, NULL, "%s.action", + sec[i]); + u->final_action = secfile_lookup_str_default(file, NULL, + "%s.final_action", sec[i]); } unit_type_iterate_end; /* flags */ @@ -1059,10 +1164,67 @@ } free(slist); } unit_type_iterate_end; + free(sec); 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; + + 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 { + 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; + } + } + } + sval = secfile_lookup_str(file, "%s.action", sec[i]); + form_compound_unit(name, basetype, modifiers, sval); + } + free(sec); + + sec = secfile_get_secnames_prefix(file, "unit_", &nval); + for (i = 0; i < nval; 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; + } + } + free(sec); + /* Some more consistency checking: */ unit_type_iterate(i) { if (unit_type_exists(i)) { @@ -1167,7 +1329,6 @@ update_simple_ai_types(); - free(sec); section_file_check_unused(file, filename); section_file_free(file); } @@ -1633,33 +1794,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; iindex; + g->basetype = G_MAGIC; g->required_tech = lookup_tech(file, sec[i], "tech_req", FALSE, filename, g->name); @@ -1829,6 +1970,71 @@ } freelog(LOG_DEBUG, "%s subgoal %d", g->name, g->subgoal); } government_iterate_end; + 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 based on %d", name, basetype); + + 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); } /************************************************************************** @@ -2750,90 +3047,110 @@ **************************************************************************/ 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; - int j; + struct government *g; + int i; - government_iterate(g) { - /* send one packet_government */ - gov.id = g->index; + g = &governments[id]; + + /* send one packet_government */ + gov.id = g->index; - 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); - - /* send one packet_government_ruler_title per ruler title */ - for(j=0; jnum_ruler_titles; j++) { - p_title = &g->ruler_titles[j]; - - title.gov = g->index; - 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); + lsend_packet_ruleset_government(dest, &gov); - lsend_packet_ruleset_government_ruler_title(dest, &title); - } - } government_iterate_end; + /* 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); + } } /************************************************************************** @@ -2938,6 +3255,8 @@ freelog(LOG_NORMAL, _("Loading rulesets")); + script_load_library(); + openload_ruleset_file(&techfile, "techs"); load_tech_names(&techfile); @@ -2982,7 +3301,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-cvs/server/ruleset.h freeciv-patched/server/ruleset.h --- freeciv-cvs/server/ruleset.h 2003-01-03 16:09:50.000000000 +0000 +++ freeciv-patched/server/ruleset.h 2003-07-24 17:24:47.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-cvs/server/savegame.c freeciv-patched/server/savegame.c --- freeciv-cvs/server/savegame.c 2003-07-24 17:23:24.000000000 +0100 +++ freeciv-patched/server/savegame.c 2003-07-24 17:24:47.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" @@ -1851,6 +1852,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, NULL); + } +} + +/*************************************************************** +... +***************************************************************/ void game_load(struct section_file *file) { int i; @@ -2082,6 +2149,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); } { @@ -2273,6 +2345,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; @@ -2365,6 +2501,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-cvs/server/srv_main.c freeciv-patched/server/srv_main.c --- freeciv-cvs/server/srv_main.c 2003-07-24 17:23:24.000000000 +0100 +++ freeciv-patched/server/srv_main.c 2003-07-24 17:24:47.000000000 +0100 @@ -59,6 +59,7 @@ #include "player.h" #include "rand.h" #include "registry.h" +#include "script.h" #include "shared.h" #include "support.h" #include "tech.h" @@ -177,6 +178,9 @@ /* initialize teams */ team_init(); + /* set up script interpreter */ + script_init(); + /* mark as initialized */ has_been_srv_init = TRUE; @@ -844,6 +848,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;