<URL: http://bugs.freeciv.org/Ticket/Display.html?id=34717 >
Wrong bugtracker address... ---------- Forwarded message ---------- 2007/1/28 Daniel Markstedt: >> >> > ~Event upon the death of a unique unit. >> >> >> >> Should be possible with scripts. Patch adding "unit_lost" event. - ML
diff -Nurd -X.diff_ignore freeciv/common/city.h freeciv/common/city.h --- freeciv/common/city.h 2008-05-13 13:26:10.000000000 +0300 +++ freeciv/common/city.h 2008-06-22 04:33:56.000000000 +0300 @@ -425,6 +425,31 @@ } players_iterate_end; \ } +#define city_list_iterate_safe(citylist, _city) \ +{ \ + int _city##_size = city_list_size(citylist); \ + \ + if (_city##_size > 0) { \ + int _city##_numbers[_city##_size]; \ + int _city##_index = 0; \ + \ + city_list_iterate(citylist, _city) { \ + _city##_numbers[_city##_index++] = _city->id; \ + } city_list_iterate_end; \ + \ + for (_city##_index = 0; \ + _city##_index < _city##_size; \ + _city##_index++) { \ + struct city *_city = \ + game_find_city_by_number(_city##_numbers[_city##_index]); \ + \ + if (NULL != _city) { + +#define city_list_iterate_safe_end \ + } \ + } \ + } \ +} /* output type functions */ diff -Nurd -X.diff_ignore freeciv/server/citytools.c freeciv/server/citytools.c --- freeciv/server/citytools.c 2008-06-18 17:45:27.000000000 +0300 +++ freeciv/server/citytools.c 2008-06-22 04:33:56.000000000 +0300 @@ -625,6 +625,8 @@ int kill_outside, bool verbose) { struct tile *ptile = pcity->tile; + int saved_id = pcity->id; + const char *name = city_name(pcity); /* Transfer enemy units in the city to the new owner. * Only relevant if we are transferring to another player. */ @@ -647,6 +649,10 @@ } unit_list_iterate_safe_end; } + if (!city_exist(saved_id)) { + saved_id = 0; + } + /* Any remaining units supported by the city are either given new home cities or maybe destroyed */ unit_list_iterate_safe(units, vunit) { @@ -656,8 +662,9 @@ /* unit is in another city: make that the new homecity, unless that city is actually the same city (happens if disbanding) */ transfer_unit(vunit, new_home_city, verbose); - } else if (kill_outside == -1 - || real_map_distance(vunit->tile, ptile) <= kill_outside) { + } else if ((kill_outside == -1 + || real_map_distance(vunit->tile, ptile) <= kill_outside) + && saved_id) { /* else transfer to specified city. */ transfer_unit(vunit, pcity, verbose); } else { @@ -670,19 +677,22 @@ city_name(pcity)); if (verbose) { notify_player(unit_owner(vunit), vunit->tile, - E_UNIT_LOST, - _("%s lost along with control of %s."), - unit_name_translation(vunit), - city_name(pcity)); + E_UNIT_LOST, + _("%s lost along with control of %s."), + unit_name_translation(vunit), name); } wipe_unit(vunit); } } unit_list_iterate_safe_end; - unit_list_iterate(pcity->units_supported, punit) { - assert(punit->homecity == pcity->id); - assert(unit_owner(punit) == pplayer); - } unit_list_iterate_end; +#ifndef NDEBUG + if (city_exist(saved_id)) { + unit_list_iterate(pcity->units_supported, punit) { + assert(punit->homecity == pcity->id); + assert(unit_owner(punit) == pplayer); + } unit_list_iterate_end; + } +#endif /* NDEBUG */ } /********************************************************************** @@ -829,6 +839,8 @@ struct unit_list *old_city_units = unit_list_new(); struct player *pgiver = city_owner(pcity); struct tile *pcenter = city_tile(pcity); + int saved_id = pcity->id; + bool city_remains = TRUE; assert(pgiver != ptaker); @@ -905,34 +917,40 @@ resolve_unit_stacks(pgiver, ptaker, transfer_unit_verbose); } - /* Update the city's trade routes. */ - for (i = 0; i < NUM_TRADEROUTES; i++) - old_trade_routes[i] = pcity->trade[i]; - for (i = 0; i < NUM_TRADEROUTES; i++) { - struct city *pother_city = game_find_city_by_number(pcity->trade[i]); + if (! city_exist(saved_id)) { + city_remains = FALSE; + } - assert(pcity->trade[i] == 0 || pother_city != NULL); + if (city_remains) { + /* Update the city's trade routes. */ + for (i = 0; i < NUM_TRADEROUTES; i++) + old_trade_routes[i] = pcity->trade[i]; + for (i = 0; i < NUM_TRADEROUTES; i++) { + struct city *pother_city = game_find_city_by_number(pcity->trade[i]); - if (pother_city) { - remove_trade_route(pother_city, pcity); + assert(pcity->trade[i] == 0 || pother_city != NULL); + + if (pother_city) { + remove_trade_route(pother_city, pcity); + } } - } - reestablish_city_trade_routes(pcity, old_trade_routes); + reestablish_city_trade_routes(pcity, old_trade_routes); - /* - * Give the new owner infos about all cities which have a traderoute - * with the transferred city. - */ - for (i = 0; i < NUM_TRADEROUTES; i++) { - struct city *pother_city = game_find_city_by_number(pcity->trade[i]); - if (pother_city) { - reality_check_city(ptaker, pother_city->tile); - update_dumb_city(ptaker, pother_city); - send_city_info(ptaker, pother_city); + /* + * Give the new owner infos about all cities which have a traderoute + * with the transferred city. + */ + for (i = 0; i < NUM_TRADEROUTES; i++) { + struct city *pother_city = game_find_city_by_number(pcity->trade[i]); + if (pother_city) { + reality_check_city(ptaker, pother_city->tile); + update_dumb_city(ptaker, pother_city); + send_city_info(ptaker, pother_city); + } } - } - city_refresh(pcity); + city_refresh(pcity); + } /* * maybe_make_contact() MUST be called before city_map_update_all(), @@ -940,64 +958,67 @@ */ maybe_make_contact(pcenter, ptaker); - if (raze) { - raze_city(pcity); - } + if (city_remains) { + if (raze) { + raze_city(pcity); + } - /* Restore any global improvement effects that this city confers */ - city_built_iterate(pcity, pimprove) { - city_add_improvement(pcity, pimprove); - } city_built_iterate_end; + /* Restore any global improvement effects that this city confers */ + city_built_iterate(pcity, pimprove) { + city_add_improvement(pcity, pimprove); + } city_built_iterate_end; - /* Set production to something valid for pplayer, if not. - * (previously allowed building obsolete units.) */ - if (!can_city_build_now(pcity, pcity->production)) { - advisor_choose_build(ptaker, pcity); - } + /* Set production to something valid for pplayer, if not. + * (previously allowed building obsolete units.) */ + if (!can_city_build_now(pcity, pcity->production)) { + advisor_choose_build(ptaker, pcity); + } - /* What wasn't obsolete for the old owner may be so now. */ - remove_obsolete_buildings_city(pcity, TRUE); + /* What wasn't obsolete for the old owner may be so now. */ + remove_obsolete_buildings_city(pcity, TRUE); - if (terrain_control.may_road - && player_knows_techs_with_flag(ptaker, TF_RAILROAD) - && !tile_has_special(pcenter, S_RAILROAD)) { - notify_player(ptaker, pcenter, E_CITY_TRANSFER, - _("The people in %s are stunned by your" - " technological insight!\n" - " Workers spontaneously gather and upgrade" - " the city with railroads."), - city_name(pcity)); - tile_set_special(pcenter, S_RAILROAD); - update_tile_knowledge(pcenter); - } + if (terrain_control.may_road + && player_knows_techs_with_flag(ptaker, TF_RAILROAD) + && !tile_has_special(pcenter, S_RAILROAD)) { + notify_player(ptaker, pcenter, E_CITY_TRANSFER, + _("The people in %s are stunned by your" + " technological insight!\n" + " Workers spontaneously gather and upgrade" + " the city with railroads."), + city_name(pcity)); + tile_set_special(pcenter, S_RAILROAD); + update_tile_knowledge(pcenter); + } - /* Build a new palace for free if the player lost her capital and - savepalace is on. */ - if (game.info.savepalace) { - build_free_small_wonders(pgiver, &had_small_wonders); - } + /* Build a new palace for free if the player lost her capital and + savepalace is on. */ + if (game.info.savepalace) { + build_free_small_wonders(pgiver, &had_small_wonders); + } - /* Remove the sight points from the giver...and refresh the city's - * vision range, since it might be different under the new owner. */ - city_refresh_vision(pcity); - vision_clear_sight(old_vision); - vision_free(old_vision); + /* Remove the sight points from the giver...and refresh the city's + * vision range, since it might be different under the new owner. */ + city_refresh_vision(pcity); + vision_clear_sight(old_vision); + vision_free(old_vision); - /* Update the national borders, within the current vision and culture. - * This could leave a border ring around the city, updated later by - * map_calculate_borders() at the next turn. - */ - map_claim_border(pcenter, ptaker); - /* city_thaw_workers_queue() later */ + /* Update the national borders, within the current vision and culture. + * This could leave a border ring around the city, updated later by + * map_calculate_borders() at the next turn. + */ + map_claim_border(pcenter, ptaker); + /* city_thaw_workers_queue() later */ - auto_arrange_workers(pcity); /* does city_map_update_all() */ - city_thaw_workers(pcity); - city_thaw_workers_queue(); /* after old city has a chance to work! */ - city_refresh_queue_processing(); + auto_arrange_workers(pcity); /* does city_map_update_all() */ + city_thaw_workers(pcity); + city_thaw_workers_queue(); /* after old city has a chance to work! */ + city_refresh_queue_processing(); - send_city_info(NULL, pcity); + send_city_info(NULL, pcity); + + sanity_check_city(pcity); + } - sanity_check_city(pcity); sync_cities(); } @@ -1200,11 +1221,20 @@ } } unit_list_iterate_safe_end; + if (!city_exist(id)) { + return; + } + /* Any remaining supported units are destroyed */ unit_list_iterate_safe(pcity->units_supported, punit) { wipe_unit(punit); } unit_list_iterate_safe_end; + if (!city_exist(id)) { + /* Wiping supported units caused city to disappear. */ + return; + } + for (o = 0; o < NUM_TRADEROUTES; o++) { struct city *pother_city = game_find_city_by_number(pcity->trade[o]); diff -Nurd -X.diff_ignore freeciv/server/cityturn.c freeciv/server/cityturn.c --- freeciv/server/cityturn.c 2008-05-13 13:26:10.000000000 +0300 +++ freeciv/server/cityturn.c 2008-06-22 04:33:56.000000000 +0300 @@ -418,9 +418,9 @@ int gold; gold=pplayer->economic.gold; pplayer->bulbs_last_turn = 0; - city_list_iterate(pplayer->cities, pcity) + city_list_iterate_safe(pplayer->cities, pcity) update_city_activity(pplayer, pcity); - city_list_iterate_end; + city_list_iterate_safe_end; pplayer->ai.prev_gold = gold; /* This test include the cost of the units because pay_for_units is called * in update_city_activity */ @@ -700,6 +700,8 @@ **************************************************************************/ static void city_populate(struct city *pcity) { + int saved_id = pcity->id; + pcity->food_stock += pcity->surplus[O_FOOD]; if (pcity->food_stock >= city_granary_size(pcity->size) || city_rapture_grow(pcity)) { @@ -723,8 +725,10 @@ wipe_unit(punit); - pcity->food_stock = (city_granary_size(pcity->size) - * granary_savings(pcity)) / 100; + if (city_exist(saved_id)) { + pcity->food_stock = (city_granary_size(pcity->size) + * granary_savings(pcity)) / 100; + } return; } } unit_list_iterate_safe_end; @@ -1717,6 +1721,7 @@ static void update_city_activity(struct player *pplayer, struct city *pcity) { struct government *g = government_of_city(pcity); + int saved_id = pcity->id; city_refresh(pcity); @@ -1756,38 +1761,41 @@ update_tech(pplayer, pcity->prod[O_SCIENCE]); pplayer->economic.gold+=pcity->prod[O_GOLD]; pay_for_units(pplayer, pcity); - pay_for_buildings(pplayer, pcity); + if (city_exist(saved_id)) { + pay_for_buildings(pplayer, pcity); - if(city_unhappy(pcity)) { - pcity->anarchy++; - if (pcity->anarchy == 1) - notify_player(pplayer, pcity->tile, E_CITY_DISORDER, - _("Civil disorder in %s."), - city_name(pcity)); - else - notify_player(pplayer, pcity->tile, E_CITY_DISORDER, - _("CIVIL DISORDER CONTINUES in %s."), - city_name(pcity)); - } - else { - if (pcity->anarchy != 0) - notify_player(pplayer, pcity->tile, E_CITY_NORMAL, - _("Order restored in %s."), - city_name(pcity)); - pcity->anarchy=0; - } - check_pollution(pcity); + if(city_unhappy(pcity)) { + pcity->anarchy++; + if (pcity->anarchy == 1) { + notify_player(pplayer, pcity->tile, E_CITY_DISORDER, + _("Civil disorder in %s."), + city_name(pcity)); + } else { + notify_player(pplayer, pcity->tile, E_CITY_DISORDER, + _("CIVIL DISORDER CONTINUES in %s."), + city_name(pcity)); + } + } else { + if (pcity->anarchy != 0) { + notify_player(pplayer, pcity->tile, E_CITY_NORMAL, + _("Order restored in %s."), + city_name(pcity)); + } + pcity->anarchy = 0; + } + check_pollution(pcity); - send_city_info(NULL, pcity); - if (pcity->anarchy>2 - && get_player_bonus(pplayer, EFT_REVOLUTION_WHEN_UNHAPPY) > 0) { - notify_player(pplayer, pcity->tile, E_ANARCHY, - _("The people have overthrown your %s, " - "your country is in turmoil."), - government_name_translation(g)); - handle_player_change_government(pplayer, government_number(g)); + send_city_info(NULL, pcity); + if (pcity->anarchy>2 + && get_player_bonus(pplayer, EFT_REVOLUTION_WHEN_UNHAPPY) > 0) { + notify_player(pplayer, pcity->tile, E_ANARCHY, + _("The people have overthrown your %s, " + "your country is in turmoil."), + government_name_translation(g)); + handle_player_change_government(pplayer, government_number(g)); + } + sanity_check_city(pcity); } - sanity_check_city(pcity); } } diff -Nurd -X.diff_ignore freeciv/server/diplomats.c freeciv/server/diplomats.c --- freeciv/server/diplomats.c 2008-06-18 17:45:27.000000000 +0300 +++ freeciv/server/diplomats.c 2008-06-22 04:33:56.000000000 +0300 @@ -326,10 +326,10 @@ struct unit *pvictim) { struct player *uplayer; - int diplomat_id; struct tile *victim_tile; struct unit *gained_unit = NULL; - + int diplomat_id = pdiplomat->id; + /* Fetch target unit's player. Sanity checks. */ if (!pvictim) return; @@ -415,8 +415,11 @@ victim_tile = pvictim->tile; wipe_unit(pvictim); + if (!unit_alive(diplomat_id)) { + return; + } + /* Now, try to move the briber onto the victim's square. */ - diplomat_id = pdiplomat->id; if (!unit_move_handling(pdiplomat, victim_tile, FALSE, FALSE)) { pdiplomat->moves_left = 0; } @@ -1049,9 +1052,9 @@ unit_name_translation(pdiplomat)); } - wipe_unit(punit); pdiplomat->moves_left = MAX(0, pdiplomat->moves_left - SINGLE_MOVE); send_unit_info(pplayer, pdiplomat); + wipe_unit(punit); return FALSE; } else { /* Attacking Spy/Diplomat dies. */ diff -Nurd -X.diff_ignore freeciv/server/scripting/script_signal.c freeciv/server/scripting/script_signal.c --- freeciv/server/scripting/script_signal.c 2007-09-02 17:21:02.000000000 +0300 +++ freeciv/server/scripting/script_signal.c 2008-06-22 04:34:33.000000000 +0300 @@ -152,6 +152,8 @@ API_TYPE_STRING); script_signal_create("hut_enter", 1, API_TYPE_UNIT); + + script_signal_create("unit_lost", 2, API_TYPE_UNIT, API_TYPE_PLAYER); } /************************************************************************** diff -Nurd -X.diff_ignore freeciv/server/unithand.c freeciv/server/unithand.c --- freeciv/server/unithand.c 2008-04-23 00:56:39.000000000 +0300 +++ freeciv/server/unithand.c 2008-06-22 04:33:56.000000000 +0300 @@ -987,6 +987,8 @@ wipe_unit(plooser); } else { /* The defender lost, the attacker punit lives! */ + int winner_id = pwinner->id; + freelog(LOG_DEBUG, "Defender lost: %s %s against %s %s.", nation_rule_name(nation_of_player(pplayer)), unit_rule_name(punit), @@ -996,8 +998,12 @@ punit->moved = TRUE; /* We moved */ kill_unit(pwinner, plooser, vet && !uclass_has_flag(unit_class(punit), UCF_MISSILE)); - if (uclass_has_flag(unit_class(pwinner), UCF_MISSILE)) { - wipe_unit(pwinner); + if (unit_alive(winner_id)) { + if (uclass_has_flag(unit_class(pwinner), UCF_MISSILE)) { + wipe_unit(pwinner); + return; + } + } else { return; } } diff -Nurd -X.diff_ignore freeciv/server/unittools.c freeciv/server/unittools.c --- freeciv/server/unittools.c 2008-06-18 17:45:27.000000000 +0300 +++ freeciv/server/unittools.c 2008-06-22 04:34:48.000000000 +0300 @@ -1486,6 +1486,7 @@ struct player *pplayer = unit_owner(punit); struct unit_type *putype_save = unit_type(punit); /* for notify messages */ int drowning = 0; + int saved_id = punit->id; /* First pull all units off of the transporter. */ if (get_transporter_capacity(punit) > 0) { @@ -1514,8 +1515,14 @@ } unit_list_iterate_end; } - /* Now remove the unit. */ - server_remove_unit(punit); + script_signal_emit("unit_lost", 2, + API_TYPE_UNIT, punit, + API_TYPE_PLAYER, pplayer); + + if (unit_alive(saved_id)) { + /* Now remove the unit. */ + server_remove_unit(punit); + } /* Finally reassign, bounce, or destroy all units that cannot exist at this * location without transport. */ @@ -1591,7 +1598,7 @@ struct player *pvictim = unit_owner(punit); struct player *pvictor = unit_owner(pkiller); int ransom, unitcount = 0; - + /* barbarian leader ransom hack */ if( is_barbarian(pvictim) && unit_has_type_role(punit, L_BARBARIAN_LEADER) && (unit_list_size(punit->tile->units) == 1) @@ -1996,7 +2003,7 @@ **************************************************************************/ static void do_nuke_tile(struct player *pplayer, struct tile *ptile) { - struct city *pcity = tile_city(ptile); + struct city *pcity = NULL; unit_list_iterate_safe(ptile->units, punit) { notify_player(unit_owner(punit), ptile, E_UNIT_LOST, @@ -2014,6 +2021,8 @@ wipe_unit(punit); } unit_list_iterate_safe_end; + pcity = tile_city(ptile); + if (pcity) { notify_player(city_owner(pcity), ptile, E_CITY_NUKED, _("%s was nuked by %s."), @@ -2246,6 +2255,7 @@ } else { struct unit_type *type = unit_type(punit); struct tile *tile = punit->tile; + wipe_unit(punit); ok = FALSE; notify_player(pplayer, tile, E_HUT_BARB_KILLED,
_______________________________________________ Freeciv-dev mailing list Freeciv-dev@gna.org https://mail.gna.org/listinfo/freeciv-dev