<URL: http://bugs.freeciv.org/Ticket/Display.html?id=34717 >

2008/7/2 Marko Lindqvist:
> 2008/6/22 Marko Lindqvist:
>> 2007/1/28 Daniel Markstedt:
>>>> >> > ~Event upon the death of a unique unit.
>>>> >>
>>>> >> Should be possible with scripts.
>>
>>  Patch adding "unit_lost" event.
>
>  Updated against svn.

 Again

>  Autogames still differ. Not sure if it's some other memory problem or
> really caused by this patch.

 Found out that autogames differ even when running my testgame twice
in a row with same binary. Since problem is not in this patch, I'm
going to finally commit this.


 - ML

diff -Nurd -X.diff_ignore freeciv/common/city.h freeciv/common/city.h
--- freeciv/common/city.h       2008-07-10 12:49:28.000000000 +0300
+++ freeciv/common/city.h       2008-07-14 23:13:22.000000000 +0300
@@ -449,8 +449,6 @@
   }                                                                    \
 }
 
-
-
 /* output type functions */
 
 const char *get_output_identifier(Output_type_id output);
diff -Nurd -X.diff_ignore freeciv/server/citytools.c freeciv/server/citytools.c
--- freeciv/server/citytools.c  2008-07-03 21:02:59.000000000 +0300
+++ freeciv/server/citytools.c  2008-07-14 23:13:03.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 {
@@ -667,22 +674,23 @@
              nation_rule_name(nation_of_unit(vunit)),
              unit_rule_name(vunit),
              TILE_XY(vunit->tile),
-             city_name(pcity));
+             name);
       if (verbose) {
        notify_player(unit_owner(vunit), vunit->tile,
-                        E_UNIT_LOST_MISC,
-                        _("%s lost along with control of %s."),
-                        unit_name_translation(vunit),
-                        city_name(pcity));
+                      E_UNIT_LOST_MISC,
+                      _("%s lost along with control of %s."),
+                      unit_name_translation(vunit), name);
       }
       wipe_unit(vunit);
     }
   } unit_list_iterate_safe_end;
 
+#ifndef NDEBUG
   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 +837,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 +915,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 +956,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 +1219,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-07-10 12:49:29.000000000 +0300
+++ freeciv/server/cityturn.c   2008-07-14 23:13:06.000000000 +0300
@@ -709,6 +709,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)) {
@@ -733,8 +735,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;
@@ -1727,6 +1731,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);
 
@@ -1766,38 +1771,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-07-01 01:07:31.000000000 +0300
+++ freeciv/server/diplomats.c  2008-07-14 23:13:06.000000000 +0300
@@ -392,9 +392,9 @@
   struct player *uplayer;
   struct tile *victim_tile;
   int bribe_cost;
-  int diplomat_id;
+  int diplomat_id = pdiplomat->id;
   struct unit *gained_unit = NULL;
-  
+
   /* Fetch target unit's player.  Sanity checks. */
   if (!pvictim)
     return;
@@ -476,8 +476,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;
   }
@@ -1110,9 +1113,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    2008-07-01 01:07:29.000000000 
+0300
+++ freeciv/server/scripting/script_signal.c    2008-07-14 23:13:06.000000000 
+0300
@@ -158,6 +158,8 @@
                        3, API_TYPE_CITY, API_TYPE_PLAYER, API_TYPE_PLAYER);
 
   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-07-01 01:07:31.000000000 +0300
+++ freeciv/server/unithand.c   2008-07-14 23:13:06.000000000 +0300
@@ -1032,6 +1032,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),
@@ -1041,8 +1043,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-07-01 01:07:31.000000000 +0300
+++ freeciv/server/unittools.c  2008-07-14 23:13:06.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_MISC,
@@ -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