Index: client/diplodlg.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/client/diplodlg.c,v retrieving revision 1.5 diff -u -r1.5 diplodlg.c --- diplodlg.c 1999/03/06 00:05:15 1.5 +++ diplodlg.c 1999/03/29 23:09:08 @@ -63,6 +63,7 @@ Widget dip_tech_menubutton1; Widget dip_city_menubutton0; Widget dip_city_menubutton1; + Widget dip_unit_menubutton; Widget dip_gold_label0; Widget dip_gold_label1; Widget dip_gold_input0; @@ -86,6 +87,7 @@ }; char *dummy_clause_list_strings[]={ "\n", "\n", "\n", "\n", "\n", "\n", 0}; +int orig_x, orig_y; struct Diplomacy_dialog *create_diplomacy_dialog(struct player *plr0, struct player *plr1); @@ -110,6 +112,8 @@ XtPointer call_data); void diplomacy_dialog_city_callback(Widget w, XtPointer client_data, XtPointer call_data); +void diplomacy_dialog_unit_callback(Widget w, XtPointer client_data, + XtPointer call_data); void close_diplomacy_dialog(struct Diplomacy_dialog *pdialog); void update_diplomacy_dialog(struct Diplomacy_dialog *pdialog); @@ -197,6 +201,7 @@ Dimension width, height; struct Diplomacy_dialog *pdialog; + get_center_tile_mapcanvas(&orig_x, &orig_y); if(!(pdialog=find_diplomacy_dialog(plr0, plr1))) { pdialog=create_diplomacy_dialog(plr0, plr1); XtVaGetValues(toplevel, XtNwidth, &width, XtNheight, &height, NULL); @@ -264,6 +269,67 @@ } } +/**************************************************************** + +Creates a sorted list of plr0's units, excluding diplomats and +Spies. + + - Kris Bubendorfer +*****************************************************************/ + +int fill_diplomacy_unit_menu(Widget popupmenu, + struct player *plr0, struct player *plr1) +{ + int i = 0, j = 0, n = unit_list_size(&plr0->units); + struct unit **unit_list_ptrs; + struct city *pcity; + char** unit_description; + + unit_list_ptrs = (struct unit **)malloc(sizeof(struct unit*)*n); + unit_description = (char **)malloc(sizeof(char*)*n); + + unit_list_iterate(plr0->units, punit) + if(!(unit_flag(punit->type, F_DIPLOMAT) || unit_flag(punit->type, F_SPY))){ + unit_list_ptrs[i] = punit; + i++; + } + unit_list_iterate_end; + + qsort(unit_list_ptrs, i, sizeof(struct unit*), unit_name_compare); + + /* Create a list of unit descriptions (name + location) */ + + for(j=0; jx, unit_list_ptrs[j]->y))){ + /* Unit is in a city */ + if(unit_list_ptrs[j]->veteran) + sprintf(buf,"Veteran %s in %s", unit_name(unit_list_ptrs[j]->type),pcity->name); + else + sprintf(buf,"%s in %s",unit_name(unit_list_ptrs[j]->type),pcity->name); + }else{ + /* Unit is outside */ + pcity = find_closest_city(NULL, unit_list_ptrs[j]->x, + unit_list_ptrs[j]->y); + if(unit_list_ptrs[j]->veteran) + sprintf(buf,"Veteran %s near %s",unit_name(unit_list_ptrs[j]->type), pcity->name); + else + sprintf(buf,"%s near %s",unit_name(unit_list_ptrs[j]->type), pcity->name); + } + unit_description[j] = strdup(buf); + } + + for(j=0; jplayer_no+plr1->player_no*32+unit_list_ptrs[j]->id*1024)); + } + + return i; +} + /**************************************************************** ... @@ -274,6 +340,7 @@ char buf[512], *pheadlinem; struct Diplomacy_dialog *pdialog; Dimension width, height, maxwidth; + int tradeunits = FALSE; Widget popupmenu; Widget entry; XtTranslations textfieldtranslations; @@ -408,7 +475,38 @@ XtSetSensitive(pdialog->dip_city_menubutton1, TRUE); /* End of trade city code */ + + /* Start of trade unit code - Kris Bubendorfer */ + + if(has_capability("tradeunits", aconnection.capability) + && has_capability("tradeunits", plr0->conn->capability) + && has_capability("tradeunits", plr1->conn->capability)) + tradeunits = TRUE; + + pdialog->dip_unit_menubutton=XtVaCreateManagedWidget("dipunitmenubutton", + menuButtonWidgetClass, + pdialog->dip_form0, + NULL); + popupmenu=XtVaCreatePopupShell("menu", + simpleMenuWidgetClass, + pdialog->dip_unit_menubutton, + NULL); + + /* please be careful removing this when updating the capabilities */ + + tradeunits = tradeunits && fill_diplomacy_unit_menu(popupmenu, plr0, plr1); + XtSetSensitive(pdialog->dip_unit_menubutton, tradeunits); + + + /* We do not permit the other party in the treaty to select any units - + * even those on visible squares. Otherwise this would provide a + * mechanism to detect the defending units in visible cities - all + * that would be needed is an embassy with a hostile foe to obtain + * this unfair advantage. + */ + /* End of trade unit code */ + pdialog->dip_gold_input0=XtVaCreateManagedWidget("dipgoldinput0", asciiTextWidgetClass, pdialog->dip_form0, @@ -529,12 +627,14 @@ XtVaGetValues(pdialog->dip_map_menubutton0, XtNwidth, &maxwidth, NULL); XtVaGetValues(pdialog->dip_tech_menubutton0, XtNwidth, &width, NULL); XtVaGetValues(pdialog->dip_city_menubutton0, XtNwidth, &width, NULL); + XtVaGetValues(pdialog->dip_unit_menubutton, XtNwidth, &width, NULL); maxwidth=MAX(width, maxwidth); XtVaGetValues(pdialog->dip_gold_input0, XtNwidth, &width, NULL); maxwidth=MAX(width, maxwidth); XtVaSetValues(pdialog->dip_map_menubutton0, XtNwidth, maxwidth, NULL); XtVaSetValues(pdialog->dip_tech_menubutton0, XtNwidth, maxwidth, NULL); XtVaSetValues(pdialog->dip_city_menubutton0, XtNwidth, maxwidth, NULL); + XtVaSetValues(pdialog->dip_unit_menubutton, XtNwidth, maxwidth, NULL); XtVaSetValues(pdialog->dip_gold_input0, XtNwidth, maxwidth, NULL); XtVaGetValues(pdialog->dip_formm, XtNheight, &height, NULL); @@ -575,7 +675,12 @@ get_race_name_plural(pclause->from->race), find_city_by_id(pclause->value)->name); break; - case CLAUSE_GOLD: + case CLAUSE_UNIT: + sprintf(pdialog->clauselist_strings[i], "The %s give %s", + get_race_name_plural(pclause->from->race), + unit_name(find_unit_by_id(pclause->value)->type)); + break; + case CLAUSE_GOLD: sprintf(pdialog->clauselist_strings[i], "The %s give %d gold", get_race_name_plural(pclause->from->race), pclause->value); @@ -654,6 +759,37 @@ &pa); } +/**************************************************************** +Callback for trading units + - Kris Bubendorfer +*****************************************************************/ +void diplomacy_dialog_unit_callback(Widget w, XtPointer client_data, + XtPointer call_data) +{ + size_t choice; + struct packet_diplomacy_info pa; + struct unit *punit; + + choice=(size_t)client_data; + + pa.value = choice/1024; + choice %= 1024; + pa.plrno0=choice%32; + pa.plrno1=choice/32; + + pa.clause_type=CLAUSE_UNIT; + pa.plrno_from=pa.plrno0; + + if((punit = find_unit_by_id(pa.value))){ + center_tile_mapcanvas(punit->x, punit->y); + put_cross_overlay_tile(punit->x, punit->y); + } + + send_packet_diplomacy_info(&aconnection, PACKET_DIPLOMACY_CREATE_CLAUSE, + &pa); +} + + /**************************************************************** ... @@ -773,6 +909,7 @@ pa.plrno_from=game.player_idx; send_packet_diplomacy_info(&aconnection, PACKET_DIPLOMACY_ACCEPT_TREATY, &pa); + } @@ -785,6 +922,7 @@ genlist_unlink(&diplomacy_dialogs, pdialog); free(pdialog); + center_tile_mapcanvas(orig_x ,orig_y); } /***************************************************************** Index: common/city.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/city.c,v retrieving revision 1.37 diff -u -r1.37 city.c --- city.c 1999/03/14 22:15:16 1.37 +++ city.c 1999/03/29 23:09:10 @@ -1473,3 +1473,40 @@ return mystrcasecmp( (*(struct city**)p1)->name, (*(struct city**)p2)->name ); } + +/************************************************************************** +I'm putting this here because it is now needed in both client and server. + +This routine finds the closest city. If the player is specified, then +it finds the closest owned city. If the player is null, when called from +the server it will find the closest of all cities, when called from the +client it will find the closest of the visible cities. + + - Kris Bubendorfer +**************************************************************************/ + +struct city *find_closest_city(struct player *pplayer, int x, int y) +{ + int dist = 10000; /* dist == infinity (as far as the map goes) */ + int i = 0; + struct city *rcity = NULL; + + if(pplayer){ + city_list_iterate(pplayer->cities, pcity) + if (real_map_distance(x, y, pcity->x, pcity->y) < dist){ + dist = real_map_distance(x, y, pcity->x, pcity->y); + rcity = pcity; + } + city_list_iterate_end; + }else{ + for(i=0; ix, pcity->y) < dist){ + dist = real_map_distance(x, y, pcity->x, pcity->y); + rcity = pcity; + } + city_list_iterate_end; + } + } + return rcity; +} Index: common/city.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/city.h,v retrieving revision 1.29 diff -u -r1.29 city.h --- city.h 1999/03/01 08:15:27 1.29 +++ city.h 1999/03/29 23:09:10 @@ -257,7 +257,8 @@ void city_list_insert_back(struct city_list *This, struct city *pcity); int city_name_compare(const void *p1, const void *p2); - +struct city *find_closest_city(struct player *pplayer, int x, int y); + /* citycache */ struct city *find_city_by_id(int id); void initialize_city_cache(void); Index: common/diptreaty.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/diptreaty.h,v retrieving revision 1.2 diff -u -r1.2 diptreaty.h --- diptreaty.h 1999/01/17 09:44:28 1.2 +++ diptreaty.h 1999/03/29 23:09:10 @@ -1,7 +1,7 @@ #ifndef __DIPTREATY__H #define __DIPTREATY__H -enum clause_type { CLAUSE_ADVANCE, CLAUSE_GOLD, CLAUSE_MAP, CLAUSE_SEAMAP, CLAUSE_CITY}; +enum clause_type { CLAUSE_ADVANCE, CLAUSE_GOLD, CLAUSE_MAP, CLAUSE_SEAMAP, CLAUSE_CITY, CLAUSE_UNIT}; struct Clause { enum clause_type type; Index: common/shared.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/shared.h,v retrieving revision 1.40 diff -u -r1.40 shared.h --- shared.h 1999/03/23 11:24:09 1.40 +++ shared.h 1999/03/29 23:09:10 @@ -73,7 +73,7 @@ */ /* The default string is really simple */ -#define CAPABILITY "+1.8pre2" +#define CAPABILITY "+1.8pre2 tradeunits" #define CITY_NAMES_FONT "10x20" #define BROADCAST_EVENT -2 Index: common/unit.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/unit.c,v retrieving revision 1.47 diff -u -r1.47 unit.c --- unit.c 1999/03/27 11:43:15 1.47 +++ unit.c 1999/03/29 23:09:11 @@ -1150,3 +1150,12 @@ } return U_LAST; } + +/************************************************************************** +Comparison function for qsort for unit _pointers_, sorting by unit name. +**************************************************************************/ +int unit_name_compare(const void *p1, const void *p2) +{ + return mystrcasecmp( unit_name((*(struct unit**)p1)->type), + unit_name((*(struct unit**)p2)->type)); +} Index: common/unit.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/common/unit.h,v retrieving revision 1.22 diff -u -r1.22 unit.h --- unit.h 1999/03/27 11:43:16 1.22 +++ unit.h 1999/03/29 23:09:12 @@ -297,5 +297,6 @@ int num_role_units(int role); enum unit_type_id get_role_unit(int role, int index); enum unit_type_id best_role_unit(struct city *pcity, int role); +int unit_name_compare(const void *p1, const void *p2); #endif Index: data/Freeciv =================================================================== RCS file: /home/freeciv/CVS/freeciv/data/Freeciv,v retrieving revision 1.89 diff -u -r1.89 Freeciv --- Freeciv 1999/03/24 10:27:37 1.89 +++ Freeciv 1999/03/29 23:09:14 @@ -334,9 +334,18 @@ Freeciv*dipcitymenubutton1.left: chainLeft Freeciv*dipcitymenubutton1.right: chainRight +Freeciv*dipunitmenubutton.label: Units +Freeciv*dipunitmenubutton.fromVert: dipcitymenubutton0 +Freeciv*dipunitmenubutton.foreground: white +Freeciv*dipunitmenubutton.background: blue +Freeciv*dipunitmenubutton.top: chainTop +Freeciv*dipunitmenubutton.bottom: chainTop +Freeciv*dipunitmenubutton.left: chainLeft +Freeciv*dipunitmenubutton.right: chainRight + Freeciv*dipgoldinput0.foreground: black Freeciv*dipgoldinput0.background: white -Freeciv*dipgoldinput0.fromVert: dipcitymenubutton0 +Freeciv*dipgoldinput0.fromVert: dipunitmenubutton Freeciv*dipgoldinput0.top: chainTop Freeciv*dipgoldinput0.bottom: chainTop Freeciv*dipgoldinput0.left: chainLeft @@ -359,7 +368,7 @@ Freeciv*dipgoldlabel0.background: lightgrey Freeciv*dipgoldlabel0.foreground: black Freeciv*dipgoldlabel0.fromHoriz: dipgoldinput0 -Freeciv*dipgoldlabel0.fromVert: dipcitymenubutton0 +Freeciv*dipgoldlabel0.fromVert: dipunitmenubutton Freeciv*dipgoldlabel0.top: chainTop Freeciv*dipgoldlabel0.bottom: chainTop Freeciv*dipgoldlabel0.left: chainLeft Index: server/citytools.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/citytools.c,v retrieving revision 1.36 diff -u -r1.36 citytools.c --- citytools.c 1999/03/15 12:11:30 1.36 +++ citytools.c 1999/03/29 23:09:15 @@ -654,33 +654,6 @@ } unit_list_iterate_end; } - -/* - * dist_nearest_city (in ai.c) does not seem to do what I want or expect - * this function finds the closest friendly city to pos x,y. I'm sure - * there must be a similar function somewhere, I just can't find it. - * - * - Kris Bubendorfer - */ - -struct city *find_closest_owned_city(struct player *pplayer, int x, int y) -{ - int dist; - struct city *rcity = city_list_get(&pplayer->cities, 0); - - if(rcity){ - dist = real_map_distance(x, y, rcity->x, rcity->y); - - city_list_iterate(pplayer->cities, pcity) - if (real_map_distance(x, y, pcity->x, pcity->y) < dist){ - dist = real_map_distance(x, y, pcity->x, pcity->y); - rcity = pcity; - } - city_list_iterate_end; - } - return rcity; -} - /* * This function creates a new player and copies all of it's science * research etc. Players are both thrown into anarchy and gold is Index: server/citytools.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/citytools.h,v retrieving revision 1.12 diff -u -r1.12 citytools.h --- citytools.h 1999/03/15 02:34:37 1.12 +++ citytools.h 1999/03/29 23:09:15 @@ -57,7 +57,6 @@ int civil_war_triggered(struct player *pplayer); void civil_war(struct player *pplayer); struct city *transfer_city(struct player *pplayer, struct player *cplayer, struct city *pcity); -struct city *find_closest_owned_city(struct player *pplayer, int x, int y); #endif Index: server/diplhand.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/diplhand.c,v retrieving revision 1.11 diff -u -r1.11 diplhand.c --- diplhand.c 1999/03/18 10:43:53 1.11 +++ diplhand.c 1999/03/29 23:09:15 @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -160,6 +161,10 @@ notify_player(pdest, "Game: You receive %s's seamap", pgiver->name); break; + case CLAUSE_UNIT: + give_unit_from_player_to_player(find_unit_by_id(pclause->value), + pgiver, pdest); + break; case CLAUSE_CITY:{ struct city *pcity = find_city_by_id(pclause->value); struct city *pnewcity = NULL; @@ -183,24 +188,28 @@ transfer_city_units(pdest, pgiver, pnewcity, pcity, 0, 1); remove_city(pcity); /* don't forget this! */ map_set_city(pnewcity->x, pnewcity->y, pnewcity); - + lighten_area(pdest, pnewcity->x, pnewcity->y); + reestablish_city_trade_routes(pnewcity); city_check_workers(pdest ,pnewcity); update_map_with_city_workers(pnewcity); city_refresh(pnewcity); initialize_infrastructure_cache(pnewcity); send_city_info(0, pnewcity, 0); - - unit_list_iterate(pdest->units, punit) - resolve_unit_stack(punit->x, punit->y, 1); - unit_list_iterate_end; - + break; } } } cleanup: + + /* Make sure we haven't ended up with multi owner stacks. */ + + unit_list_iterate(pdest->units, punit) + resolve_unit_stack(punit->x, punit->y, 1); + unit_list_iterate_end; + genlist_unlink(&treaties, ptreaty); free(ptreaty); send_player_info(plr0, 0); @@ -250,17 +259,23 @@ /* * If we are trading cities, then it is possible that the - * dest is unaware of it's existence. We have 2 choices, - * forbid it, or lighten that area. If we assume that - * the giver knows what they are doing, then 2. is the - * most powerful option - I'll choose that for now. + * dest is unaware of it's existence. Here we'll + * just ensure that the client knows about it by + * updating it. We don't lighten the map at this + * point, as this is sensitive information until + * the city is exchanged. * - Kris Bubendorfer */ if(packet->clause_type == CLAUSE_CITY){ struct city *pcity = find_city_by_id(packet->value); if(pcity && !map_get_known(pcity->x, pcity->y, plr1)) - lighten_area(plr1, pcity->x, pcity->y); + send_city_info(plr1, pcity, 1); + } + + if(packet->clause_type == CLAUSE_UNIT){ + struct unit *punit = find_unit_by_id(packet->value); + send_unit_info(plr1, punit, 1); } if((ptreaty=find_treaty(plr0, plr1))) { Index: server/unittools.c =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/unittools.c,v retrieving revision 1.36 diff -u -r1.36 unittools.c --- unittools.c 1999/02/12 21:36:20 1.36 +++ unittools.c 1999/03/29 23:09:16 @@ -656,8 +656,8 @@ struct unit *cunit = is_enemy_unit_on_tile(x, y, punit->owner); while(punit && cunit){ - struct city *pcity = find_closest_owned_city(get_player(punit->owner), x, y); - struct city *ccity = find_closest_owned_city(get_player(cunit->owner), x, y); + struct city *pcity = find_closest_city(get_player(punit->owner), x, y); + struct city *ccity = find_closest_city(get_player(cunit->owner), x, y); if(map_distance(x, y, pcity->x, pcity->y) < map_distance(x, y, ccity->x, ccity->y)){ @@ -692,7 +692,7 @@ if(punit && map_get_terrain(punit->x, punit->y)==T_OCEAN && !is_enough_transporter_space(get_player(punit->owner), x, y)){ unit_list_iterate(map_get_tile(x, y)->units, vunit){ - struct city *vcity = find_closest_owned_city(get_player(vunit->owner), x, y); + struct city *vcity = find_closest_city(get_player(vunit->owner), x, y); if(is_ground_unit(vunit)){ teleport_unit_to_city(vunit, vcity, 0); freelog(LOG_DEBUG,"Teleported %s's %s to %s as there is no transport space on square (%d, %d)",get_player(vunit->owner)->name, unit_name(vunit->type),vcity->name, x, y); @@ -708,3 +708,62 @@ } } +void give_unit_from_player_to_player(struct unit *punit, + struct player *pgiver, + struct player *pdest){ + + struct city *gcity = NULL, *dcity = NULL; + + if(!punit){ + notify_player(pgiver, "Game: Error, could not transfer unit. It has either been destoyed or is no longer yours to give."); + notify_player(pdest, "Game: Error, could not transfer unit"); + return; + } + + if((gcity = map_get_city(punit->x, punit->y))){ + /* Gifted unit is in a city, so create at closest owned city */ + if((dcity = find_closest_city(pdest, punit->x, punit->y))){ + create_unit_full(pdest, dcity->x, dcity->y, punit->type, punit->veteran, + dcity->id, punit->moves_left, punit->hp); + + notify_player(pgiver, "Game: You gave a %s from %s to the %s", + unit_name(punit->type), gcity->name, + get_race_name_plural(pdest->race)); + notify_player(pdest, "Game: The %s gave a %s to your city %s", + get_race_name_plural(pgiver->race), unit_name(punit->type), + dcity->name); + wipe_unit(0, punit); + return; + }else{ + /* Barf, there is no closest city ???? */ + freelog(LOG_DEBUG,"Error in `give_unit_from_player_to_player' no closest city found, aborting"); + notify_player(pgiver, "Game: Error, could not transfer unit"); + notify_player(pdest, "Game: Error, could not transfer unit"); + return; + } + }else{ + /* Unit isn't in a city - phew! no teleporting! */ + + /* find a new homecity */ + + if(!(dcity = find_closest_city(pdest, punit->x, punit->y))){ + /* Barf, there is no closest city ???? */ + freelog(LOG_DEBUG,"Error in `give_unit_from_player_to_player' no closest city found, aborting"); + notify_player(pgiver, "Game: Error, could not transfer unit"); + notify_player(pdest, "Game: Error, could not transfer unit"); + return; + } + + /* Transfer the unit */ + + create_unit_full(pdest, punit->x, punit->y, punit->type, punit->veteran, + dcity->id, punit->moves_left, punit->hp); + lighten_area(pdest, punit->x, punit->y); + + notify_player(pgiver, "Game: You gave a %s to the %s", + unit_name(punit->type), get_race_name_plural(pdest->race)); + notify_player(pdest, "Game: The %s gave you a %s", + get_race_name_plural(pgiver->race), unit_name(punit->type)); + wipe_unit_spec_safe(0, punit, NULL, 0); + } +} Index: server/unittools.h =================================================================== RCS file: /home/freeciv/CVS/freeciv/server/unittools.h,v retrieving revision 1.12 diff -u -r1.12 unittools.h --- unittools.h 1999/01/20 10:27:22 1.12 +++ unittools.h 1999/03/29 23:09:16 @@ -50,4 +50,7 @@ int teleport_unit_to_city(struct unit *punit, struct city *pcity, int mov_cost); struct unit *is_enemy_unit_on_tile(int x, int y, int owner); void resolve_unit_stack(int x, int y, int verbose); +void give_unit_from_player_to_player(struct unit *punit, + struct player *pgiver, + struct player *pdest); #endif