Index: test/unit/common/check_living.c
===================================================================
--- test/unit/common/check_living.c	(Revision 9134)
+++ test/unit/common/check_living.c	(Arbeitskopie)
@@ -32,10 +32,17 @@
 
 #include <stdlib.h>
 #include <check.h>
+#include <global.h>
+#include <config.h>
+#include <toolkit_common.h>
 
 
 void setup(void) {
     /* put any initialisation steps here, they will be run before each testcase */
+	cctk_setdatadir(SOURCE_ROOT "lib");
+	cctk_setlog(LOGDIR "/unit/common/living.out");
+	printf("set log to %s\n",LOGDIR "/unit/common/living.out");
+	cctk_init_std_archetypes();
 }
 
 void teardown(void)
@@ -43,9 +50,72 @@
     /* put any cleanup steps here, they will be run after each testcase */
 }
 
-START_TEST (test_empty)
+
+START_TEST (test_resistance_calculation)
 {
-    /*TESTME test not yet developped*/
+#ifdef NEW_RESISTANCE_CALCULATION
+  object *ob1;
+  object *ob2;
+  object *ob3;
+  object *ob4;
+  unsigned long sum;
+  ob1 = cctk_create_game_object(NULL);
+  ob2 = cctk_create_game_object(NULL);
+  ob3 = cctk_create_game_object(NULL);
+  ob4 = cctk_create_game_object(NULL);
+  ob1->type=CONTAINER;
+  insert_ob_in_ob(ob2,ob1);
+  insert_ob_in_ob(ob3,ob1);
+  insert_ob_in_ob(ob4,ob1);
+  SET_FLAG(ob2, FLAG_APPLIED);
+  SET_FLAG(ob3, FLAG_APPLIED);
+  SET_FLAG(ob4, FLAG_APPLIED);
+
+  srand(23896423); // initialized to a fixed value to be reproducible
+  int i;
+  int damage_factor_pct;
+  for(i = 0; i < 1000; ++i)
+  {
+	  float dmg_pct = 100.0;
+
+	  damage_factor_pct = rand()*(200.0/(RAND_MAX+1.0));
+	  ob1->arch->clone.resist[ATNR_FIRE] = 100 - damage_factor_pct;
+#ifdef NEW_RESISTANCE_CALCULATION_OLD_ARCHETYPES
+	  if(damage_factor_pct > 100) dmg_pct = dmg_pct * (float)((damage_factor_pct-100)*2+100) / 100.0;
+	  else
+#endif
+	  dmg_pct = dmg_pct * (float)damage_factor_pct / 100.0;
+
+	  damage_factor_pct = rand()*(200.0/(RAND_MAX+1.0));
+	  ob2->resist[ATNR_FIRE] = 100 - damage_factor_pct;
+#ifdef NEW_RESISTANCE_CALCULATION_OLD_ARCHETYPES
+	  if(damage_factor_pct > 100) dmg_pct = dmg_pct * (float)((damage_factor_pct-100)*2+100) / 100.0;
+	  else
+#endif
+	  dmg_pct = dmg_pct * (float)damage_factor_pct / 100.0;
+	  
+	  damage_factor_pct = rand()*(200.0/(RAND_MAX+1.0));
+	  ob3->resist[ATNR_FIRE] = 100 - damage_factor_pct;
+#ifdef NEW_RESISTANCE_CALCULATION_OLD_ARCHETYPES
+	  if(damage_factor_pct > 100) dmg_pct = dmg_pct * (float)((damage_factor_pct-100)*2+100) / 100.0;
+	  else
+#endif
+	  dmg_pct = dmg_pct * (float)damage_factor_pct / 100.0;
+	  
+	  damage_factor_pct = rand()*(200.0/(RAND_MAX+1.0));
+	  ob4->resist[ATNR_FIRE] = 100 - damage_factor_pct;
+#ifdef NEW_RESISTANCE_CALCULATION_OLD_ARCHETYPES
+	  if(damage_factor_pct > 100) dmg_pct = dmg_pct * (float)((damage_factor_pct-100)*2+100) / 100.0;
+	  else
+#endif
+	  dmg_pct = dmg_pct * (float)damage_factor_pct / 100.0;
+
+	  fix_object(ob1);
+	  
+	  /* We tolerate a difference of 1 that may be caused by rounding errors. */
+	  fail_unless(abs(ob1->resist[ATNR_FIRE] - (100 - (int)dmg_pct)) <= 1,"object resistance should be %d, but is %d, resistances are: %d, %d, %d, %d", (100 - (int)dmg_pct), ob1->resist[ATNR_FIRE], ob1->arch->clone.resist[ATNR_FIRE], ob2->resist[ATNR_FIRE], ob3->resist[ATNR_FIRE], ob4->resist[ATNR_FIRE]);
+  }
+#endif
 }
 END_TEST
 
@@ -57,7 +127,7 @@
   tcase_add_checked_fixture(tc_core,setup,teardown);
 
   suite_add_tcase (s, tc_core);
-  tcase_add_test(tc_core, test_empty);
+  tcase_add_test(tc_core, test_resistance_calculation);
 
   return s;
 }
Index: test/unit/common/Makefile.am
===================================================================
--- test/unit/common/Makefile.am	(Revision 9134)
+++ test/unit/common/Makefile.am	(Arbeitskopie)
@@ -17,10 +17,10 @@
 
 # disabled tests, enable them when they have some real content
 # check_anim check_button check_exp check_friend check_glue check_holy check_image check_info check_init
-# check_links check_living check_logger check_los check_map
+# check_links check_logger check_los check_map
 # check_player check_porting check_readable check_recipe check_re-cmp check_region
 # check_time check_treasure check_utils
-TESTS= check_arch check_item check_loader check_object check_path check_shstr check_time
+TESTS= check_arch check_living check_item check_loader check_object check_path check_shstr check_time
 
 clean-local:
 	$(RM) .autorun.xml
Index: include/config.h
===================================================================
--- include/config.h	(Revision 9134)
+++ include/config.h	(Arbeitskopie)
@@ -136,6 +136,23 @@
  */
 #define BASE_WEAPON_SPEED   1.0
 
+/* Use the new resistance calculation code?
+ * The old code accumulates protection and vulnerability values separately
+ * and then substracts the total vulnerability from the total protection.
+ * The new code applies every single protection and vulnerability relative
+ * to the remaining share of the original damage.
+ * A vulnerability can be overcome with additional protection. Since this
+ * makes vulnerability values somewhat less severe, the archetypes should be
+ * adapted to higher vulnerability values. Until this is done,
+ * NEW_RESISTANCE_CALCULATION_OLD_ARCHETYPES doubles the vulnerability values
+ * in the calculation code. NEW_RESISTANCE_CALCULATION_OLD_ARCHETYPES also
+ * reduces the effect of resistance potions (95% -> 90%, 90% -> 80%), since
+ * these are handled like any other additional resistance on top of the
+ * normal resistance value.
+ */
+#define NEW_RESISTANCE_CALCULATION
+#define NEW_RESISTANCE_CALCULATION_OLD_ARCHETYPES
+
 /* Use balanced stat loss code?
  * This code is a little more merciful with repeated stat loss at lower
  * levels. Basically, the more stats you have lost, the less likely that
Index: common/living.c
===================================================================
--- common/living.c	(Revision 9134)
+++ common/living.c	(Arbeitskopie)
@@ -903,7 +903,12 @@
     float max=9,added_speed=0, sp_tmp,speed_reduce_from_disease=1;
     int weapon_weight=0,weapon_speed=0;
     int best_wc=0, best_ac=0, wc=0, ac=0;
-    int prot[NROFATTACKS], vuln[NROFATTACKS], potion_resist[NROFATTACKS];
+#ifdef NEW_RESISTANCE_CALCULATION
+    float resist[NROFATTACKS];
+#else
+    int prot[NROFATTACKS], vuln[NROFATTACKS];
+#endif
+	 int potion_resist[NROFATTACKS];
     object *grace_obj=NULL,*mana_obj=NULL,*wc_obj=NULL,*tmp;
 
     /* First task is to clear all the values back to their original values */
@@ -967,10 +972,17 @@
     memcpy(&op->resist, &op->arch->clone.resist, sizeof(op->resist));
 
     for (i=0;i<NROFATTACKS;i++) {
+#ifdef NEW_RESISTANCE_CALCULATION
+		 resist[i] = op->resist[i];
+#ifdef NEW_RESISTANCE_CALCULATION_OLD_ARCHETYPES
+		 if(resist[i] < 0) resist[i] *= 2;
+#endif
+#else
         if (op->resist[i] > 0)
             prot[i]= op->resist[i], vuln[i]=0;
         else
             vuln[i]= -(op->resist[i]), prot[i]=0;
+#endif
         potion_resist[i]=0;
     }
 
@@ -986,7 +998,11 @@
      */
     if(!QUERY_FLAG(op,FLAG_USE_ARMOUR) && op->type==PLAYER) {
         ac=MAX(-10,op->arch->clone.stats.ac - op->level/3);
+#ifdef NEW_RESISTANCE_CALCULATION
+        resist[ATNR_PHYSICAL] += ((100.0-resist[AT_PHYSICAL])*(80.0*op->level/settings.max_level))/100.0;
+#else
         prot[ATNR_PHYSICAL] += ((100-prot[AT_PHYSICAL])*(80*op->level/settings.max_level))/100;
+#endif
     } else
         ac=op->arch->clone.stats.ac;
 
@@ -1082,26 +1098,51 @@
 		    speed_reduce_from_disease = (float)tmp->last_sp / 100.0;
             }
 
-            /* Pos. and neg. protections are counted seperate (-> pro/vuln).
-             * (Negative protections are calculated extactly like positive.)
-             * Resistance from potions are treated special as well. If there's
-             * more than one potion-effect, the bigger prot.-value is taken.
-             */
             if (tmp->type != POTION) {
                 for (i=0; i<NROFATTACKS; i++) {
                     /* Potential for cursed potions, in which case we just can use
                      * a straight MAX, as potion_resist is initialized to zero.
                      */
+						  int item_resist = tmp->resist[i];
                     if (tmp->type==POTION_EFFECT) {
-                        if (potion_resist[i])
-                            potion_resist[i] = MAX(potion_resist[i], tmp->resist[i]);
-                        else
-                            potion_resist[i] = tmp->resist[i];
-                    }
-                    else if (tmp->resist[i] > 0)
-                        prot[i] += ((100-prot[i])*tmp->resist[i])/100;
-                    else if (tmp->resist[i] < 0)
-                        vuln[i] += ((100-vuln[i])*(-tmp->resist[i]))/100;
+#ifdef NEW_RESISTANCE_CALCULATION
+#ifdef NEW_RESISTANCE_CALCULATION_OLD_ARCHETYPES
+								/* As long as we haven't adjusted the archetypes, we
+								 * halve the additional resistance provided by
+								 * potions, and we double the effect of cursed potions:
+								 */
+								if(item_resist > 0) item_resist -= 100 - item_resist;
+								else item_resist *= 2;
+#endif
+#endif
+                        if (potion_resist[i]) {
+                            potion_resist[i] = MAX(potion_resist[i], item_resist);
+								} else {
+                            potion_resist[i] = item_resist;
+								}
+                    } else {
+#ifdef NEW_RESISTANCE_CALCULATION
+							 /* All resistance changes are counted equally and multiplied to
+							  * the resist[] value.
+							  */
+#ifdef NEW_RESISTANCE_CALCULATION_OLD_ARCHETYPES
+							  /* If the vulnerability in archetypes hasn't been
+								* adjusted yet, we double the value here: */
+							 if(item_resist < 0) item_resist *= 2;
+#endif
+							 resist[i] += ((100.0-resist[i])*item_resist)/100.0;
+#else
+							 /* Pos. and neg. protections are counted seperate (-> pro/vuln).
+							  * (Negative protections are calculated extactly like positive.)
+							  * Resistance from potions are treated special as well. If there's
+							  * more than one potion-effect, the bigger prot.-value is taken.
+							  */
+							  if (item_resist > 0)
+									prot[i] += ((100-prot[i])*item_resist)/100;
+							  else if (tmp->resist[i] < 0)
+									vuln[i] += ((100-vuln[i])*(-item_resist))/100;
+#endif
+						  }
                 }
             }
 
@@ -1271,17 +1312,23 @@
      * have generated intermediate values which we now need to assign.
      */
 
-    /* 'total resistance = total protections - total vulnerabilities'.
-     * If there is an uncursed potion in effect, granting more protection
-     * than that, we take: 'total resistance = resistance from potion'.
-     * If there is a cursed (and no uncursed) potion in effect, we take
-     * 'total resistance = vulnerability from cursed potion'.
-     */
     for (i=0; i<NROFATTACKS; i++) {
+#ifdef NEW_RESISTANCE_CALCULATION
+		 /* We include the potion_resist value just like any other item: */
+		 resist[i] += ((100.0-resist[i])*potion_resist[i])/100.0;
+		 op->resist[i] = resist[i];
+#else
+		 /* 'total resistance = total protections - total vulnerabilities'.
+		  * If there is an uncursed potion in effect, granting more protection
+		  * than that, we take: 'total resistance = resistance from potion'.
+		  * If there is a cursed (and no uncursed) potion in effect, we take
+		  * 'total resistance = vulnerability from cursed potion'.
+		  */
         op->resist[i] = prot[i] - vuln[i];
         if (potion_resist[i] && ((potion_resist[i] > op->resist[i]) ||
             (potion_resist[i] < 0)))
             op->resist[i] = potion_resist[i];
+#endif
     }
 
     /* Figure out the players sp/mana/hp totals. */
