Complete.Org: Mailing Lists: Archives: freeciv-dev: August 2005:
[Freeciv-Dev] (PR#13717) Karma
Home

[Freeciv-Dev] (PR#13717) Karma

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
Subject: [Freeciv-Dev] (PR#13717) Karma
From: "Per I. Mathisen" <per@xxxxxxxxxxx>
Date: Sat, 20 Aug 2005 07:12:41 -0700
Reply-to: bugs@xxxxxxxxxxx

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

This patch adds a new game concept: Karma.

A new concept of 'karma' is introduced. This is meant to balance out some
game strategies that we can deem somehow 'evil'. What comes around comes
around. The chickens come home to roost. And so on. The idea is that if
you carry out stuff that others see as evil, it (or rather, they) will
come back to haunt you.

Eventually, this will be used (or that is the idea) to generate barbarians
in a not-random, but also not-predictable manner that can be used also in
multiplayer games. I would also like to use it to balance the 'raze city'
functionality I want to add.

See http://www.freeciv.org/index.php/Barbarians for the full plans and
karma description.

In this patch, all that it does is that players with positive karma (a
rare thing), will never generate barbarians from huts. This is the only
benefit from having positive karma I plan to add.

  - Per

Index: server/cityturn.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/cityturn.c,v
retrieving revision 1.331
diff -u -r1.331 cityturn.c
--- server/cityturn.c   18 Aug 2005 06:44:28 -0000      1.331
+++ server/cityturn.c   20 Aug 2005 13:42:59 -0000
@@ -529,6 +529,8 @@
 **************************************************************************/
 static void city_populate(struct city *pcity)
 {
+  struct player *pplayer = city_owner(pcity);
+
   pcity->food_stock += pcity->surplus[O_FOOD];
   if (pcity->food_stock >= city_granary_size(pcity->size) 
      || city_rapture_grow(pcity)) {
@@ -551,6 +553,7 @@
  
         gamelog(GAMELOG_UNITLOSS, punit, NULL, "famine");
         wipe_unit(punit);
+        pplayer->karma += KARMA_FAMINE_UNIT_LOSS;
 
        pcity->food_stock = (city_granary_size(pcity->size)
                             * granary_savings(pcity)) / 100;
@@ -561,9 +564,11 @@
       notify_player_ex(city_owner(pcity), pcity->tile, E_CITY_FAMINE,
                       _("Famine causes population loss in %s."),
                       pcity->name);
+      pplayer->karma += KARMA_FAMINE_CITY_REDUCTION;
     } else {
       notify_player_ex(city_owner(pcity), pcity->tile, E_CITY_FAMINE,
                       _("Famine destroys %s entirely."), pcity->name);
+      pplayer->karma += KARMA_FAMINE_CITY_LOSS;
     }
     pcity->food_stock = (city_granary_size(pcity->size - 1)
                         * granary_savings(pcity)) / 100;
@@ -1001,6 +1006,7 @@
                         _("%s can't upkeep %s, unit disbanded."),
                         pcity->name, unit_type(punit)->name);
         handle_unit_disband(pplayer, punit->id);
+        pplayer->karma += KARMA_DISBAND_UNSUPPORTABLE;
        /* pcity->surplus[O_SHIELD] is automatically updated. */
       }
     } unit_list_iterate_safe_end;
@@ -1019,6 +1025,7 @@
        notify_player_ex(pplayer, pcity->tile, E_UNIT_LOST,
                         _("Citizens in %s perish for their failure to "
                         "upkeep %s!"), pcity->name, unit_type(punit)->name);
+        pplayer->karma += KARMA_FAMINE_UNIT_UNDISBANDABLE;
        if (!city_reduce_size(pcity, 1)) {
          return FALSE;
        }
@@ -1222,6 +1225,7 @@
        (food) needed. */
     if (pop_cost > 0) {
       city_reduce_size(pcity, pop_cost);
+      pplayer->karma += KARMA_BUILD_UNIT_POPLOSS * pop_cost;
     }
 
     /* to eliminate micromanagement, we only subtract the unit's
@@ -1287,11 +1291,15 @@
 }
 
 /**************************************************************************
- Add some Pollution if we have waste
+  Maybe pollute some tiles if we have pollution.
 **************************************************************************/
 static void check_pollution(struct city *pcity)
 {
+  struct player *pplayer = city_owner(pcity);
   int k=100;
+
+  pplayer->karma += KARMA_POLLUTION * pcity->pollution;
+
   if (pcity->pollution != 0 && myrand(100) <= pcity->pollution) {
     while (k > 0) {
       /* place pollution somewhere in city radius */
@@ -1309,7 +1317,7 @@
          && !tile_has_special(ptile, S_POLLUTION)) {
        tile_set_special(ptile, S_POLLUTION);
        update_tile_knowledge(ptile);
-       notify_player_ex(city_owner(pcity), pcity->tile,
+       notify_player_ex(pplayer, pcity->tile,
                         E_POLLUTION, _("Pollution near %s."),
                         pcity->name);
        return;
Index: server/diplhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/diplhand.c,v
retrieving revision 1.100
diff -u -r1.100 diplhand.c
--- server/diplhand.c   20 Jul 2005 18:28:48 -0000      1.100
+++ server/diplhand.c   20 Aug 2005 13:43:00 -0000
@@ -340,6 +340,7 @@
                          _("%s allowed you to create an embassy!"),
                          pgiver->name);
         gamelog(GAMELOG_TREATY, GL_EMBASSY, pgiver, pdest);
+        pgiver += KARMA_GAVE_EMBASSY;
         break;
       case CLAUSE_ADVANCE:
         /* It is possible that two players open the diplomacy dialog
@@ -370,7 +371,7 @@
         gamelog(GAMELOG_TECH, pdest, pgiver, pclause->value, "acquire");
         gamelog(GAMELOG_TREATY, GL_TECH, pgiver, pdest);
        do_dipl_cost(pdest, pclause->value);
-
+        pgiver->karma += KARMA_GAVE_TECH;
        found_new_tech(pdest, pclause->value, FALSE, TRUE);
        break;
       case CLAUSE_GOLD:
@@ -434,6 +435,11 @@
        check_city_workers(pother);
        break;
       case CLAUSE_PEACE:
+        if (pgiver->diplstates[pdest->player_no].max_state < DS_PEACE) {
+          /* This bonus given only once */
+          pgiver->karma += KARMA_FIRST_PEACE;
+          pdest->karma += KARMA_FIRST_PEACE;
+        }
        pgiver->diplstates[pdest->player_no].type=DS_PEACE;
        pdest->diplstates[pgiver->player_no].type=DS_PEACE;
        pgiver->diplstates[pdest->player_no].max_state = 
@@ -454,6 +460,11 @@
        check_city_workers(pother);
        break;
       case CLAUSE_ALLIANCE:
+        if (pgiver->diplstates[pdest->player_no].max_state < DS_ALLIANCE) {
+          /* This bonus given only once */
+          pgiver->karma += KARMA_FIRST_ALLIANCE;
+          pdest->karma += KARMA_FIRST_ALLIANCE;
+        }
        pgiver->diplstates[pdest->player_no].type=DS_ALLIANCE;
        pdest->diplstates[pgiver->player_no].type=DS_ALLIANCE;
        pgiver->diplstates[pdest->player_no].max_state = 
Index: server/diplomats.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/diplomats.c,v
retrieving revision 1.90
diff -u -r1.90 diplomats.c
--- server/diplomats.c  26 Jul 2005 16:36:00 -0000      1.90
+++ server/diplomats.c  20 Aug 2005 13:43:01 -0000
@@ -104,7 +104,8 @@
   freelog (LOG_DEBUG, "poison: succeeded");
 
   /* Poison people! */
-  city_reduce_size(pcity, 1);
+  city_reduce_size(pcity, 1); /* random amount? not used as is now */
+  pplayer->karma += KARMA_DIPLOMAT_POISON;
 
   /* Notify everybody involved. */
   notify_player_ex(pplayer, pcity->tile, E_MY_DIPLOMAT_POISON,
@@ -994,6 +995,7 @@
 
   /* this may cause a diplomatic incident */
   maybe_cause_incident(DIPLOMAT_SABOTAGE, pplayer, NULL, pcity);
+  pplayer->karma += KARMA_DIPLOMAT_SABOTAGE;
 
   /* Check if a spy survives her mission. Diplomats never do. */
   diplomat_escape(pplayer, pdiplomat, pcity);
Index: server/plrhand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/plrhand.c,v
retrieving revision 1.410
diff -u -r1.410 plrhand.c
--- server/plrhand.c    18 Aug 2005 18:30:08 -0000      1.410
+++ server/plrhand.c    20 Aug 2005 13:43:05 -0000
@@ -609,6 +606,11 @@
   }
   if (new_type == DS_WAR) {
     ai_incident_war(pplayer, pplayer2);
+    if (pplayer->diplstates[pplayer2->player_no].has_reason_to_cancel <= 0) {
+      pplayer->karma += KARMA_WAR_UNPROVOKED;
+    } else {
+      pplayer->karma += KARMA_WAR_PROVOKED;
+    }
   }
   pplayer->diplstates[pplayer2->player_no].has_reason_to_cancel = 0;
 
Index: server/plrhand.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/plrhand.h,v
retrieving revision 1.80
diff -u -r1.80 plrhand.h
--- server/plrhand.h    18 Jul 2005 22:46:29 -0000      1.80
+++ server/plrhand.h    20 Aug 2005 13:43:06 -0000
@@ -102,4 +102,53 @@
 
 void update_players_after_alliance_breakup(struct player* pplayer,
                                           struct player* pplayer2);
+
+/* Karma
+ *
+ * Karma is not about why you do something, but about the 
+ * consequences of your actions spreading like ripples in the
+ * water. */
+
+/* Negative karma. Pretty much anything but sitting on your ass
+ * will generate some bad karma. */
+#define KARMA_FAMINE_UNIT_LOSS          -5 
+#define KARMA_FAMINE_CITY_REDUCTION    -20
+#define KARMA_FAMINE_UNIT_UNDISBANDABLE        -40
+#define KARMA_FAMINE_CITY_LOSS         -60
+#define KARMA_DISBAND_UNSUPPORTABLE     -5
+/* moving lots of people around penalty */
+#define KARMA_BUILD_UNIT_POPLOSS        -5
+/* just because there is not a big fancy civ there, does not mean
+ * the territory is not populated; the original population of hunters
+ * and gatherers may not be thrilled to see you settling in their back 
+ * yard... */
+#define KARMA_BUILD_CITY               -10
+#define KARMA_EXPLODE_NUCLEAR         -200
+#define KARMA_POLLUTION                         -1
+#define KARMA_WAR_UNPROVOKED           -40
+#define KARMA_WAR_PROVOKED              -5
+/* mining is usually slavery and/or highly destructive to nature */
+#define KARMA_TERRAIN_MINE              -5
+/* transforming terrain disrupts nature and/or aboriginal peoples */
+#define KARMA_TERRAIN_TRANSFORM                -15
+#define KARMA_DIPLOMAT_POISON         -100
+#define KARMA_DIPLOMAT_SABOTAGE                 -5
+#define KARMA_CITY_RAIDED              -20
+
+/* Positive karma. It is much like the Nobel's Peace Prize - 
+ * if you do something horrible and then clean up after yourself,
+ * then you are a hero; but if you never did something bad, you
+ * are just nobody. Sigh. */
+#define KARMA_DISBAND_MILITARY           5
+#define KARMA_DISBAND_NUCLEAR           20
+#define KARMA_CLEAN_POLLUTION           10
+#define KARMA_CLEAN_FALLOUT             20
+#define KARMA_GAVE_EMBASSY              50
+#define KARMA_GAVE_TECH                         10
+#define KARMA_FIRST_PEACE              100
+#define KARMA_FIRST_ALLIANCE            50
+
+/* Cost of bad stuff, fuelled by negative karma. */
+#define KARMA_BARBARIAN_COST           100
+
 #endif  /* FC__PLRHAND_H */
Index: server/savegame.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/savegame.c,v
retrieving revision 1.275
diff -u -r1.275 savegame.c
--- server/savegame.c   18 Aug 2005 06:44:29 -0000      1.275
+++ server/savegame.c   20 Aug 2005 13:43:10 -0000
@@ -1760,6 +1752,7 @@
 
   plr->nturns_idle=0;
   plr->is_male=secfile_lookup_bool_default(file, TRUE, "player%d.is_male", 
plrno);
+  plr->karma = secfile_lookup_int_default(file, 0, "player%d.karma", plrno);
   plr->is_alive=secfile_lookup_bool(file, "player%d.is_alive", plrno);
   plr->is_observer=secfile_lookup_bool_default(file, FALSE, 
                                                "player%d.is_observer", plrno);
@@ -2506,6 +2499,7 @@
                       "player%d.city_style_by_name", plrno);
 
   secfile_insert_bool(file, plr->is_male, "player%d.is_male", plrno);
+  secfile_insert_int(file, plr->karma, "player%d.karma", plrno);
   secfile_insert_bool(file, plr->is_alive, "player%d.is_alive", plrno);
   secfile_insert_bool(file, plr->is_observer, "player%d.is_observer", plrno);
   secfile_insert_bool(file, plr->ai.control, "player%d.ai.control", plrno);
Index: server/unithand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/unithand.c,v
retrieving revision 1.346
diff -u -r1.346 unithand.c
--- server/unithand.c   26 Jul 2005 16:36:00 -0000      1.346
+++ server/unithand.c   20 Aug 2005 13:43:18 -0000
@@ -35,7 +35,6 @@
 #include "shared.h"
 #include "unit.h"
 
-#include "barbarian.h"
 #include "citytools.h"
 #include "cityturn.h"
 #include "diplomats.h"
@@ -389,6 +388,13 @@
     send_city_info(city_owner(pcity), pcity);
   }
 
+  if (is_military_unit(punit)) {
+    if (unit_flag(punit, F_NUCLEAR)) {
+      pplayer->karma += KARMA_DISBAND_NUCLEAR;
+    } else {
+      pplayer->karma += KARMA_DISBAND_MILITARY;
+    }
+  }
   wipe_unit(punit);
 }
 
@@ -529,12 +535,14 @@
 
   res = test_unit_add_or_build_city(punit);
 
-  if (res == AB_BUILD_OK)
+  if (res == AB_BUILD_OK) {
     city_build(pplayer, punit, name);
-  else if (res == AB_ADD_OK)
+  } else if (res == AB_ADD_OK) {
     city_add_unit(pplayer, punit);
-  else
+    pplayer->karma += KARMA_BUILD_CITY;
+  } else {
     city_add_or_build_error(pplayer, punit, res);
+  }
 }
 
 /**************************************************************************
Index: server/unittools.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/unittools.c,v
retrieving revision 1.375
diff -u -r1.375 unittools.c
--- server/unittools.c  13 Aug 2005 05:27:24 -0000      1.375
+++ server/unittools.c  20 Aug 2005 13:43:20 -0000
@@ -729,6 +729,7 @@
     if (total_activity(ptile, ACTIVITY_POLLUTION)
        >= tile_activity_time(ACTIVITY_POLLUTION, ptile)) {
       tile_clear_special(ptile, S_POLLUTION);
+      pplayer->karma += KARMA_CLEAN_POLLUTION;
       unit_activity_done = TRUE;
     }
   }
@@ -737,6 +738,7 @@
     if (total_activity(ptile, ACTIVITY_FALLOUT)
        >= tile_activity_time(ACTIVITY_FALLOUT, ptile)) {
       tile_clear_special(ptile, S_FALLOUT);
+      pplayer->karma += KARMA_CLEAN_FALLOUT;
       unit_activity_done = TRUE;
     }
   }
@@ -804,6 +806,7 @@
       struct terrain *old = tile_get_terrain(ptile);
 
       tile_apply_activity(ptile, ACTIVITY_MINE);
+      pplayer->karma += KARMA_TERRAIN_MINE;
       check_terrain_change(ptile, old);
       unit_activity_done = TRUE;
       check_adjacent_units = TRUE;
@@ -816,6 +819,7 @@
       struct terrain *old = tile_get_terrain(ptile);
 
       tile_apply_activity(ptile, ACTIVITY_TRANSFORM);
+      pplayer->karma += KARMA_TERRAIN_TRANSFORM;
       check_terrain_change(ptile, old);
       unit_activity_done = TRUE;
       check_adjacent_units = TRUE;
@@ -1995,6 +1999,7 @@
 
   notify_conn_ex(game.game_connections, ptile, E_NUKE,
                 _("%s detonated a nuke!"), pplayer->name);
+  pplayer->karma += KARMA_EXPLODE_NUCLEAR;
 }
 
 /**************************************************************************
@@ -2183,7 +2188,8 @@
   bool ok = TRUE;
 
   if (city_exists_within_city_radius(punit->tile, TRUE)
-      || unit_flag(punit, F_GAMELOSS)) {
+      || unit_flag(punit, F_GAMELOSS)
+      || pplayer->karma >= 0) {
     notify_player_ex(pplayer, punit->tile, E_HUT_BARB_CITY_NEAR,
                     _("An abandoned village is here."));
   } else {
Index: common/player.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/player.c,v
retrieving revision 1.190
diff -u -r1.190 player.c
--- common/player.c     18 Aug 2005 06:44:28 -0000      1.190
+++ common/player.c     20 Aug 2005 14:11:11 -0000
@@ -108,6 +115,7 @@
   sz_strlcpy(plr->name, ANON_PLAYER_NAME);
   sz_strlcpy(plr->username, ANON_USER_NAME);
   plr->is_male = TRUE;
+  plr->karma = 0;
   plr->government = NULL;
   plr->target_government = NULL;
   plr->nation = NO_NATION_SELECTED;
Index: common/player.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/player.h,v
retrieving revision 1.163
diff -u -r1.163 player.h
--- common/player.h     18 Aug 2005 06:44:28 -0000      1.163
+++ common/player.h     20 Aug 2005 14:11:11 -0000
@@ -154,6 +142,7 @@
   char name[MAX_LEN_NAME];
   char username[MAX_LEN_NAME];
   bool is_male;
+  int karma;
   struct government *government; /* may be NULL in pregame */
   struct government *target_government; /* may be NULL */
   struct nation_type *nation;

[Prev in Thread] Current Thread [Next in Thread]
  • [Freeciv-Dev] (PR#13717) Karma, Per I. Mathisen <=