<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

Reply via email to