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/16 00:40:40 @@ -63,6 +63,7 @@ Widget dip_tech_menubutton1; Widget dip_city_menubutton0; Widget dip_city_menubutton1; + Widget dip_unit_menubutton0; Widget dip_gold_label0; Widget dip_gold_label1; Widget dip_gold_input0; @@ -110,6 +111,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); @@ -264,6 +267,57 @@ } } +/**************************************************************** + +Creates a sorted list of plr0's units, excluding diplomats and +Spies. + + - Kris Bubendorfer +*****************************************************************/ + +void 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 */ + 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); + sprintf(buf,"%s near %s",unit_name(unit_list_ptrs[j]->type), pcity->name); + } + unit_description[j] = strdup(buf); + } + + for(j=0; jplayer_no*100000+plr1->player_no*10000+unit_list_ptrs[j]->id)); + } +} /**************************************************************** ... @@ -274,6 +328,7 @@ char buf[512], *pheadlinem; struct Diplomacy_dialog *pdialog; Dimension width, height, maxwidth; + int tradeunits = FALSE; Widget popupmenu; Widget entry; XtTranslations textfieldtranslations; @@ -408,7 +463,36 @@ 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_menubutton0=XtVaCreateManagedWidget("dipunitmenubutton0", + menuButtonWidgetClass, + pdialog->dip_form0, + NULL); + popupmenu=XtVaCreatePopupShell("menu", + simpleMenuWidgetClass, + pdialog->dip_unit_menubutton0, + NULL); + + + fill_diplomacy_unit_menu(popupmenu, plr0, plr1); + XtSetSensitive(pdialog->dip_unit_menubutton0, 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 +613,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_menubutton0, 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_menubutton0, XtNwidth, maxwidth, NULL); XtVaSetValues(pdialog->dip_gold_input0, XtNwidth, maxwidth, NULL); XtVaGetValues(pdialog->dip_formm, XtNheight, &height, NULL); @@ -575,6 +661,11 @@ get_race_name_plural(pclause->from->race), find_city_by_id(pclause->value)->name); break; + 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), @@ -647,6 +738,30 @@ choice -= pa.plrno1 * 10000; pa.clause_type=CLAUSE_CITY; + pa.plrno_from=pa.plrno0; + pa.value=choice; + + send_packet_diplomacy_info(&aconnection, PACKET_DIPLOMACY_CREATE_CLAUSE, + &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; + + choice=(size_t)client_data; + + pa.plrno0=choice/100000; + choice -= pa.plrno0 * 100000; + pa.plrno1=(choice/10000); + choice -= pa.plrno1 * 10000; + + pa.clause_type=CLAUSE_UNIT; pa.plrno_from=pa.plrno0; pa.value=choice; 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/16 00:40:43 @@ -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/16 00:40:43 @@ -257,6 +257,7 @@ 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); 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/16 00:40:43 @@ -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.39 diff -u -r1.39 shared.h --- shared.h 1999/03/14 00:17:34 1.39 +++ shared.h 1999/03/16 00:40:43 @@ -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.46 diff -u -r1.46 unit.c --- unit.c 1999/03/15 12:25:44 1.46 +++ unit.c 1999/03/16 00:40:44 @@ -1131,3 +1131,14 @@ } return U_LAST; } + +/************************************************************************** +Comparison function for qsort for city _pointers_, sorting by city name. +Args are really (struct unit**), to sort an array of pointers. +(Compare with old_city_name_compare() in game.c, which use city_id's) +**************************************************************************/ +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.21 diff -u -r1.21 unit.h --- unit.h 1999/03/07 10:35:58 1.21 +++ unit.h 1999/03/16 00:40:44 @@ -296,5 +296,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.85 diff -u -r1.85 Freeciv --- Freeciv 1999/03/15 11:42:16 1.85 +++ Freeciv 1999/03/16 00:40:46 @@ -334,9 +334,18 @@ Freeciv*dipcitymenubutton1.left: chainLeft Freeciv*dipcitymenubutton1.right: chainRight +Freeciv*dipunitmenubutton0.label: Units +Freeciv*dipunitmenubutton0.fromVert: dipcitymenubutton0 +Freeciv*dipunitmenubutton0.foreground: white +Freeciv*dipunitmenubutton0.background: blue +Freeciv*dipunitmenubutton0.top: chainTop +Freeciv*dipunitmenubutton0.bottom: chainTop +Freeciv*dipunitmenubutton0.left: chainLeft +Freeciv*dipunitmenubutton0.right: chainRight + Freeciv*dipgoldinput0.foreground: black Freeciv*dipgoldinput0.background: white -Freeciv*dipgoldinput0.fromVert: dipcitymenubutton0 +Freeciv*dipgoldinput0.fromVert: dipunitmenubutton0 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: dipunitmenubutton0 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/16 00:40:50 @@ -655,31 +655,6 @@ } -/* - * 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 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/16 00:40:50 @@ -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.10 diff -u -r1.10 diplhand.c --- diplhand.c 1999/02/27 07:10:03 1.10 +++ diplhand.c 1999/03/16 00:40:50 @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -168,6 +169,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; @@ -191,6 +196,7 @@ 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); @@ -258,17 +264,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/16 00:40:51 @@ -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(0, punit); + } +} 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/16 00:40:51 @@ -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