skylib_mudos_v1/
skylib_mudos_v1/bin/
skylib_mudos_v1/bin/db/
skylib_mudos_v1/mudlib/banish/a/
skylib_mudos_v1/mudlib/banish/b/
skylib_mudos_v1/mudlib/banish/c/
skylib_mudos_v1/mudlib/banish/d/
skylib_mudos_v1/mudlib/banish/e/
skylib_mudos_v1/mudlib/banish/f/
skylib_mudos_v1/mudlib/banish/g/
skylib_mudos_v1/mudlib/banish/h/
skylib_mudos_v1/mudlib/banish/j/
skylib_mudos_v1/mudlib/banish/l/
skylib_mudos_v1/mudlib/banish/m/
skylib_mudos_v1/mudlib/banish/n/
skylib_mudos_v1/mudlib/banish/o/
skylib_mudos_v1/mudlib/banish/p/
skylib_mudos_v1/mudlib/banish/r/
skylib_mudos_v1/mudlib/banish/s/
skylib_mudos_v1/mudlib/banish/t/
skylib_mudos_v1/mudlib/banish/u/
skylib_mudos_v1/mudlib/banish/w/
skylib_mudos_v1/mudlib/cmds/
skylib_mudos_v1/mudlib/cmds/admin/
skylib_mudos_v1/mudlib/cmds/guild-race/
skylib_mudos_v1/mudlib/cmds/guild-race/crafts/
skylib_mudos_v1/mudlib/cmds/guild-race/magic/
skylib_mudos_v1/mudlib/cmds/guild-race/other/
skylib_mudos_v1/mudlib/cmds/living/broken/
skylib_mudos_v1/mudlib/cmds/player/group_cmds/
skylib_mudos_v1/mudlib/d/admin/
skylib_mudos_v1/mudlib/d/admin/room/
skylib_mudos_v1/mudlib/d/admin/room/we_care/
skylib_mudos_v1/mudlib/d/admin/save/
skylib_mudos_v1/mudlib/d/admin/text/
skylib_mudos_v1/mudlib/d/learning/TinyTown/buildings/
skylib_mudos_v1/mudlib/d/learning/TinyTown/map/
skylib_mudos_v1/mudlib/d/learning/TinyTown/roads/
skylib_mudos_v1/mudlib/d/learning/chars/
skylib_mudos_v1/mudlib/d/learning/functions/
skylib_mudos_v1/mudlib/d/learning/handlers/
skylib_mudos_v1/mudlib/d/learning/help_topics/
skylib_mudos_v1/mudlib/d/learning/help_topics/npcs/
skylib_mudos_v1/mudlib/d/learning/help_topics/objects/
skylib_mudos_v1/mudlib/d/learning/help_topics/rcs_demo/
skylib_mudos_v1/mudlib/d/learning/help_topics/rcs_demo/RCS/
skylib_mudos_v1/mudlib/d/learning/help_topics/rooms/
skylib_mudos_v1/mudlib/d/learning/help_topics/rooms/crowd/
skylib_mudos_v1/mudlib/d/learning/help_topics/rooms/situations/
skylib_mudos_v1/mudlib/d/learning/save/
skylib_mudos_v1/mudlib/d/learning/school/
skylib_mudos_v1/mudlib/d/learning/school/add_sc/
skylib_mudos_v1/mudlib/d/learning/school/characters/
skylib_mudos_v1/mudlib/d/learning/school/general/
skylib_mudos_v1/mudlib/d/learning/school/getting-started/
skylib_mudos_v1/mudlib/d/learning/school/getting-started/basic_commands/
skylib_mudos_v1/mudlib/d/learning/school/getting-started/edtutor/
skylib_mudos_v1/mudlib/d/learning/school/getting-started/unix_tutor/
skylib_mudos_v1/mudlib/d/learning/school/items/
skylib_mudos_v1/mudlib/d/learning/school/npc_school/
skylib_mudos_v1/mudlib/d/learning/school/room_school/
skylib_mudos_v1/mudlib/d/learning/school/room_school/room_basic/
skylib_mudos_v1/mudlib/d/learning/school/room_school/situations/
skylib_mudos_v1/mudlib/d/learning/school/room_school/terrain_tutor/
skylib_mudos_v1/mudlib/d/learning/text/
skylib_mudos_v1/mudlib/d/liaison/
skylib_mudos_v1/mudlib/d/mudlib/
skylib_mudos_v1/mudlib/d/mudlib/changes/
skylib_mudos_v1/mudlib/d/playtesters/
skylib_mudos_v1/mudlib/d/playtesters/effects/
skylib_mudos_v1/mudlib/d/playtesters/handlers/
skylib_mudos_v1/mudlib/d/playtesters/items/
skylib_mudos_v1/mudlib/d/sage/
skylib_mudos_v1/mudlib/doc/
skylib_mudos_v1/mudlib/doc/creator/
skylib_mudos_v1/mudlib/doc/driver/
skylib_mudos_v1/mudlib/doc/driver/efuns/arrays/
skylib_mudos_v1/mudlib/doc/driver/efuns/buffers/
skylib_mudos_v1/mudlib/doc/driver/efuns/compile/
skylib_mudos_v1/mudlib/doc/driver/efuns/filesystem/
skylib_mudos_v1/mudlib/doc/driver/efuns/floats/
skylib_mudos_v1/mudlib/doc/driver/efuns/functions/
skylib_mudos_v1/mudlib/doc/driver/efuns/general/
skylib_mudos_v1/mudlib/doc/driver/efuns/mappings/
skylib_mudos_v1/mudlib/doc/driver/efuns/mixed/
skylib_mudos_v1/mudlib/doc/driver/efuns/mudlib/
skylib_mudos_v1/mudlib/doc/driver/efuns/numbers/
skylib_mudos_v1/mudlib/doc/driver/efuns/parsing/
skylib_mudos_v1/mudlib/doc/known_command/
skylib_mudos_v1/mudlib/doc/login/
skylib_mudos_v1/mudlib/doc/lpc/basic_manual/
skylib_mudos_v1/mudlib/doc/lpc/intermediate/
skylib_mudos_v1/mudlib/doc/new/add_command/
skylib_mudos_v1/mudlib/doc/new/events/
skylib_mudos_v1/mudlib/doc/new/handlers/
skylib_mudos_v1/mudlib/doc/new/living/race/
skylib_mudos_v1/mudlib/doc/new/living/spells/
skylib_mudos_v1/mudlib/doc/new/object/
skylib_mudos_v1/mudlib/doc/new/player/
skylib_mudos_v1/mudlib/doc/new/room/guild/
skylib_mudos_v1/mudlib/doc/new/room/outside/
skylib_mudos_v1/mudlib/doc/new/room/storeroom/
skylib_mudos_v1/mudlib/doc/object/
skylib_mudos_v1/mudlib/doc/playtesters/
skylib_mudos_v1/mudlib/doc/policy/
skylib_mudos_v1/mudlib/doc/weapons/
skylib_mudos_v1/mudlib/global/
skylib_mudos_v1/mudlib/global/creator/
skylib_mudos_v1/mudlib/global/handlers/
skylib_mudos_v1/mudlib/global/virtual/setup_compiler/
skylib_mudos_v1/mudlib/include/cmds/
skylib_mudos_v1/mudlib/include/effects/
skylib_mudos_v1/mudlib/include/npc/
skylib_mudos_v1/mudlib/include/room/
skylib_mudos_v1/mudlib/include/shops/
skylib_mudos_v1/mudlib/net/daemon/
skylib_mudos_v1/mudlib/net/daemon/chars/
skylib_mudos_v1/mudlib/net/inherit/
skylib_mudos_v1/mudlib/net/obj/
skylib_mudos_v1/mudlib/obj/amulets/
skylib_mudos_v1/mudlib/obj/b_day/
skylib_mudos_v1/mudlib/obj/clothes/
skylib_mudos_v1/mudlib/obj/dwarmours/plate/
skylib_mudos_v1/mudlib/obj/dwclothes/transport/horse/
skylib_mudos_v1/mudlib/obj/dwscabbards/
skylib_mudos_v1/mudlib/obj/dwweapons/axes/
skylib_mudos_v1/mudlib/obj/dwweapons/chains/
skylib_mudos_v1/mudlib/obj/faith/symbols/
skylib_mudos_v1/mudlib/obj/fungi/
skylib_mudos_v1/mudlib/obj/gatherables/
skylib_mudos_v1/mudlib/obj/instruments/
skylib_mudos_v1/mudlib/obj/magic/
skylib_mudos_v1/mudlib/obj/media/
skylib_mudos_v1/mudlib/obj/misc/player_shop/
skylib_mudos_v1/mudlib/obj/monster/godmother/
skylib_mudos_v1/mudlib/obj/monster/transport/
skylib_mudos_v1/mudlib/obj/rings/
skylib_mudos_v1/mudlib/obj/spells/
skylib_mudos_v1/mudlib/obj/stationery/
skylib_mudos_v1/mudlib/obj/stationery/envelopes/
skylib_mudos_v1/mudlib/obj/stationery/papers/
skylib_mudos_v1/mudlib/obj/toys/
skylib_mudos_v1/mudlib/obj/vessels/
skylib_mudos_v1/mudlib/obj/weapons/swords/
skylib_mudos_v1/mudlib/save/autodoc/
skylib_mudos_v1/mudlib/save/leaflets/
skylib_mudos_v1/mudlib/save/mail/
skylib_mudos_v1/mudlib/save/new_soul/data/
skylib_mudos_v1/mudlib/save/parcels/
skylib_mudos_v1/mudlib/save/playerinfo/
skylib_mudos_v1/mudlib/save/players/d/
skylib_mudos_v1/mudlib/save/random_names/
skylib_mudos_v1/mudlib/save/random_names/data/
skylib_mudos_v1/mudlib/save/terrains/
skylib_mudos_v1/mudlib/save/terrains/tutorial_desert/
skylib_mudos_v1/mudlib/save/terrains/tutorial_grassy_field/
skylib_mudos_v1/mudlib/save/terrains/tutorial_mountain/
skylib_mudos_v1/mudlib/save/todo_lists/
skylib_mudos_v1/mudlib/secure/
skylib_mudos_v1/mudlib/secure/cmds/admin/
skylib_mudos_v1/mudlib/secure/cmds/lord/
skylib_mudos_v1/mudlib/secure/config/
skylib_mudos_v1/mudlib/secure/handlers/autodoc/
skylib_mudos_v1/mudlib/secure/handlers/intermud/
skylib_mudos_v1/mudlib/secure/include/global/
skylib_mudos_v1/mudlib/secure/save/
skylib_mudos_v1/mudlib/secure/save/handlers/
skylib_mudos_v1/mudlib/secure/std/classes/
skylib_mudos_v1/mudlib/secure/std/modules/
skylib_mudos_v1/mudlib/std/commands/
skylib_mudos_v1/mudlib/std/commands/shadows/
skylib_mudos_v1/mudlib/std/creator/
skylib_mudos_v1/mudlib/std/dom/
skylib_mudos_v1/mudlib/std/effects/
skylib_mudos_v1/mudlib/std/effects/external/
skylib_mudos_v1/mudlib/std/effects/fighting/
skylib_mudos_v1/mudlib/std/effects/priest/
skylib_mudos_v1/mudlib/std/effects/room/
skylib_mudos_v1/mudlib/std/environ/
skylib_mudos_v1/mudlib/std/guilds/
skylib_mudos_v1/mudlib/std/guilds/old/
skylib_mudos_v1/mudlib/std/languages/
skylib_mudos_v1/mudlib/std/languages/BACKUPS/
skylib_mudos_v1/mudlib/std/liquids/
skylib_mudos_v1/mudlib/std/npc/
skylib_mudos_v1/mudlib/std/npc/goals/
skylib_mudos_v1/mudlib/std/npc/goals/basic/
skylib_mudos_v1/mudlib/std/npc/goals/misc/
skylib_mudos_v1/mudlib/std/npc/plans/
skylib_mudos_v1/mudlib/std/npc/plans/basic/
skylib_mudos_v1/mudlib/std/npc/types/
skylib_mudos_v1/mudlib/std/npc/types/helper/
skylib_mudos_v1/mudlib/std/npcs/
skylib_mudos_v1/mudlib/std/outsides/
skylib_mudos_v1/mudlib/std/races/shadows/
skylib_mudos_v1/mudlib/std/room/basic/topography/
skylib_mudos_v1/mudlib/std/room/controller/
skylib_mudos_v1/mudlib/std/room/inherit/topography/
skylib_mudos_v1/mudlib/std/room/topography/area/
skylib_mudos_v1/mudlib/std/room/topography/iroom/
skylib_mudos_v1/mudlib/std/room/topography/milestone/
skylib_mudos_v1/mudlib/std/shadows/curses/
skylib_mudos_v1/mudlib/std/shadows/disease/
skylib_mudos_v1/mudlib/std/shadows/fighting/
skylib_mudos_v1/mudlib/std/shadows/healing/
skylib_mudos_v1/mudlib/std/shadows/magic/
skylib_mudos_v1/mudlib/std/shadows/poison/
skylib_mudos_v1/mudlib/std/shadows/rituals/
skylib_mudos_v1/mudlib/std/shadows/room/
skylib_mudos_v1/mudlib/std/shops/controllers/
skylib_mudos_v1/mudlib/std/shops/objs/
skylib_mudos_v1/mudlib/std/shops/player_shop/
skylib_mudos_v1/mudlib/std/socket/
skylib_mudos_v1/mudlib/std/soul/
skylib_mudos_v1/mudlib/std/soul/d/
skylib_mudos_v1/mudlib/std/soul/e/
skylib_mudos_v1/mudlib/std/soul/i/
skylib_mudos_v1/mudlib/std/soul/j/
skylib_mudos_v1/mudlib/std/soul/k/
skylib_mudos_v1/mudlib/std/soul/l/
skylib_mudos_v1/mudlib/std/soul/n/
skylib_mudos_v1/mudlib/std/soul/o/
skylib_mudos_v1/mudlib/std/soul/q/
skylib_mudos_v1/mudlib/std/soul/u/
skylib_mudos_v1/mudlib/std/soul/v/
skylib_mudos_v1/mudlib/std/soul/y/
skylib_mudos_v1/mudlib/std/soul/z/
skylib_mudos_v1/mudlib/std/stationery/
skylib_mudos_v1/mudlib/w/
skylib_mudos_v1/mudlib/w/default/
skylib_mudos_v1/mudlib/w/default/armour/
skylib_mudos_v1/mudlib/w/default/clothes/
skylib_mudos_v1/mudlib/w/default/item/
skylib_mudos_v1/mudlib/w/default/npc/
skylib_mudos_v1/mudlib/w/default/room/
skylib_mudos_v1/mudlib/w/default/weapon/
skylib_mudos_v1/mudlib/www/
skylib_mudos_v1/mudlib/www/download/
skylib_mudos_v1/mudlib/www/java/
skylib_mudos_v1/mudlib/www/secure/
skylib_mudos_v1/mudlib/www/secure/lpc/advanced/
skylib_mudos_v1/mudlib/www/secure/lpc/intermediate/
skylib_mudos_v1/v22.2b14-DSv10/
skylib_mudos_v1/v22.2b14-DSv10/ChangeLog.old/
skylib_mudos_v1/v22.2b14-DSv10/Win32/
skylib_mudos_v1/v22.2b14-DSv10/compat/
skylib_mudos_v1/v22.2b14-DSv10/compat/simuls/
skylib_mudos_v1/v22.2b14-DSv10/include/
skylib_mudos_v1/v22.2b14-DSv10/mudlib/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/clone/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/command/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/data/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/etc/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/include/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/inherit/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/inherit/master/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/log/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/single/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/single/tests/compiler/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/single/tests/efuns/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/single/tests/operators/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/u/
skylib_mudos_v1/v22.2b14-DSv10/tmp/
skylib_mudos_v1/v22.2b14-DSv10/windows/
/**
 * Handles updating the skill systems to new levels when the skill tree
 * is changed.
 * @author Deutha
 * @see /std/living/skills.c
 * @change 1/2/97 Pinkfish
 * Updated to include the new language skill tree
 */
#include <login_handler.h>
#include <language.h>
#include <tune.h>
#include <skills.h>

#define ORIGINAL "alpha"
#define VERSION "beta"
#define VERSION_2 "gamma"
#define VERSION_3 "delta"
#define VERSION_4 "epsilon"
#define VERSION_5 "zeta"

#define OLD_SKILLS ({ \
      "magic.spells.offensive.area", \
      "magic.spells.offensive.target", \
      "magic.spells.defensive.area", \
      "magic.spells.defensive.self", \
      "magic.spells.defensive.target", \
      "magic.spells.misc.area", \
      "magic.spells.misc.self", \
      "magic.spells.misc.target", \
      "magic.spells.special", \
      "magic.items.held.wand", \
      "magic.items.held.rod", \
      "magic.items.held.staff", \
      "magic.items.held.broom", \
      "magic.items.worn.amulet", \
      "magic.items.worn.ring", \
      "magic.items.scroll", \
      "magic.points", \
      "occult.methods.brewing", \
      "occult.methods.dancing", \
      "occult.methods.chanting", \
      "occult.methods.flying", \
      "occult.spells.cursing", \
      "occult.spells.summoning", \
      "occult.spells.enchanting", \
      "occult.spells.charming", \
      "occult.spells.healing", \
   })

#define OTHER_SKILLS ({ \
      "magic", \
      "magic.spells", \
      "magic.spells.offensive", \
      "magic.spells.defensive", \
      "magic.spells.misc", \
      "magic.items", \
      "magic.items.held", \
      "magic.items.worn", \
      "occult", \
      "occult.methods", \
      "occult.spells", \
   })

/** @ignore yes */
int query_level_in( mapping skills, string skill ) {
   string *bits;

   if ( !undefinedp( skills[ skill ] ) )
      return skills[ skill ];
   bits = explode( skill, "." );
   if ( sizeof( bits ) == 1 )
      return 0;
   bits = delete( bits, sizeof( bits ) - 1, 1 );
   skill = implode( bits, "." );
   return query_level_in( skills, skill );
} /* query_level_in() */

/**
 * Update the skills from the original skills system to the
 * beta skills system.
 * @param thing the person to update
 */
void change_skills( object thing ) {
   int i, total;
   mapping skills;

   skills = (mapping)thing->query_skills();
   if ( !m_sizeof( skills ) )
      return;
   for ( i = 0; i < sizeof( OLD_SKILLS ); i++ ) {
      total += query_level_in( skills, OLD_SKILLS[ i ] );
      if ( !undefinedp( skills[ OLD_SKILLS[ i ] ] ) )
          map_delete( skills, OLD_SKILLS[ i ] );
   }
   for ( i = 0; i < sizeof( OTHER_SKILLS ); i++ )
      if ( !undefinedp( skills[ OTHER_SKILLS[ i ] ] ) )
          map_delete( skills, OTHER_SKILLS[ i ] );
   if ( !total )
      return;
   thing->add_property( "magic levels", total );
   thing->set_skills( skills );
   tell_object( thing, "\n\nAn imp that only you can see flashes into "+
         "existence.\n" );
   tell_object( thing, "The imp tells you: The magic and occult skill "+
         "categories are being amalgamated and restructured.\n" );
   tell_object( thing, "The imp tells you: You have a total of "+ total +
         " levels that you can spend on the new magic skills.\n" );
   tell_object( thing, "The imp tells you: Go and find the black "+
         "monolith in the middle of Sator Square which you can use to "+
         "to spend them.\n" );
   tell_object( thing, "The imp flashes back to wherever it came from.\n\n" );
} /* change_skills() */

/**
 * Figure out thge minimum amount of xp that could have been used to
 * get the skill level.  This assumes a leaf skill
 * This appears to be the xp equation.  Using it anyway...
 * @param lvl the level to get to
 * @return the skill cost in xp
 */
int query_minimum_skill_xp(int lvl) {
   int i;
   int xp;

   xp = 0;
   for (i = 0; i < lvl; i++) {
      xp += ( DEFAULT_COST * STD_COST * 100 ) / (( LEVEL_DIV + 1) * 500);
   }
   return xp;
} /* query_minimum_skill_xp() */

/**
 * Changes the skill array up to the new tree involving the
 * languages.
 * @param thing the object to upgrade
 * @param lev the level we are changing up to.
 */
void change_language_skills( object thing, int lev ) {
   int i;
   int total_xp;
   mapping skills;
   string *bits;
   string start;
   string *langs;
   string health;

   skills = thing->query_skills();
   if (!sizeof(skills))
      return ;
   bits = keys(skills);

   health = skills["general.health"];

   /*
    * Instead of changing the skill levels directly...  We will just
    * call the appropriate functions on the player object to fiddle
    * them.
    */
   start = "general.language.";
   total_xp = 0;
   for (i = 0; i < sizeof(bits); i++) {
      if (bits[i][0..strlen(start)-1] == start) {
         /* Ok, now figure out how much xp to give back... */
         total_xp += query_minimum_skill_xp(skills[bits[i]]);
         map_delete(skills, bits[i]);
      }
   }

   langs = thing->query_languages();
   for (i = 0; i < sizeof(langs); i++) {
      thing->add_language(langs[i]);
      thing->remove_language( langs[i] );
   }
   if (skills["general.language"]) {
      total_xp += query_minimum_skill_xp(skills["general.language"]);
      map_delete(skills, "general.language");
   }

   /* Everyone gets common... */
   thing->add_language("common");

   if( skills["general.health"] != health ) {
       tell_object(thing, "A fluffy cabbage tells you: Something has gone wrong "
                   "with your language adjustment, please tell Ceres or "
                   "Pinkfish\n");
       return;
   }

   /* thing->set_skills( skills ); */
   thing->adjust_xp( total_xp );
   tell_object( thing, "A fluffy cabbage turns up and stares straight into your eyes.\n"
       "You feel that the fluffy cabbage has shuffled around some bits of your mind.\n");

   if (total_xp > 0 && lev < 2) {
      tell_object( thing,
          "Your languages have been shifted, you appear to have gained "+total_xp+" xp.\n");
   }
} /* change_language_skills() */

mapping recalc_parents(mapping skills, string skill) {
  int i, j, lvl;
  string *tree, *bits, this_skill;

  bits = explode(skill, ".");
  for(i=sizeof(bits)-1; i>=0; i--) {
    this_skill = implode(bits[0..i], ".");

    tree = (string *)SKILL_OB->query_immediate_children(this_skill);
    lvl = 0;
    for(j=0; j<sizeof(tree); j++) {
      lvl += skills[tree[j]];
    }

    if(sizeof(tree))
      skills[this_skill] = lvl / sizeof(tree);
  }
  return skills;
}

/**
 * Update the skills from the original skills system to the
 * beta skills system.
 * @param thing the person to update
 */
void change_skills_epsilon( object thing ) {
  int lvl, rest;
   mapping skills;
   string *bits;

   skills = thing->query_skills();
   if (!sizeof(skills))
      return ;
   bits = keys(skills);

   tell_object(thing, "A squirrel appears and says: I'm just updating your "
               "skill tree, will be just a jiffy.\n");

   // Do sleight-of-hand first.
   lvl = skills["covert.sleight-of-hand"];
   if( lvl > 0 ) {
       map_delete( skills, "covert.sleight-of-hand");
       if( lvl > 300 ) { // they get skills up to 300 at 2:1
           rest = lvl - 300;
           lvl = 300;
           if( rest > 600 ) { // 300-600 at 1:1
               lvl += 300;
               rest -= 600;
               lvl += rest / 5; // >600 at 4:10
           } else
               lvl += rest / 2;
     }

     skills["covert.manipulation.stealing"] = lvl;
     skills["covert.manipulation.palming"] = lvl;
     skills["covert.manipulation.passing"] = lvl;
     skills["covert.manipulation.sleight-of-hand"] = lvl;
     skills["covert.manipulation"] = lvl;

     recalc_parents(skills, "covert");
   }

   // then sharp
   lvl = skills["fighting.combat.melee.sharp"];
   if(lvl > 0) {

     if(lvl > 300) { // they get skills up to 300 at 2:1
       rest = lvl - 300;
       lvl = 300;

       if(rest > 600) { // 300-600 at 1:1
         lvl += 300;
         rest -= 600;
         lvl += rest / 5; // >600 at 4:10
       } else
         lvl += rest / 2;
     }

     skills["fighting.combat.melee.sharp"] = lvl;
     skills["fighting.combat.melee.pierce"] = lvl;
     skills = recalc_parents(skills, "fighting.combat.melee");
   }

   // then parry
   lvl = skills["fighting.combat.parry.thrown"];
   rest = skills["fighting.combat.parry.fired"];
   if(lvl > 0 || rest > 0) {
     if(rest > lvl)
       lvl = rest + (lvl / 5);
     else
       lvl += (rest / 5);

     map_delete( skills, "fighting.combat.parry.thrown");
     map_delete( skills, "fighting.combat.parry.fired");
     skills["fighting.combat.parry.range"] = lvl;

     lvl = skills["fighting.combat.parry.held"];
     map_delete( skills, "fighting.combat.parry.held");
     skills["fighting.combat.parry.melee"] = lvl;
     skills = recalc_parents(skills, "fighting.combat.parry");
   }

   // then special
   lvl = skills["fighting.combat.special"];
   if(lvl > 0) {

     if(lvl > 300) { // they get skills up to 300 at 2:1
       rest = lvl - 300;
       lvl = 300;

       if(rest > 600) { // 300-600 at 1:1
         lvl += 300;
         rest -= 600;
         lvl += rest / 5; // >600 at 4:10
       } else
         lvl += rest / 2;
     }
     skills["fighting.combat.special.weapon"] = lvl;
     skills["fighting.combat.special.unarmed"] = lvl;
     skills["fighting.combat.special.tactics"] = lvl - lvl / 4;

     skills = recalc_parents(skills, "fighting.combat.special");
   }

   // do tracking
   lvl = skills["general.tracking.woodland"];
   map_delete(skills, "general.tracking.woodland");
   lvl += skills["general.tracking.desert"];
   map_delete(skills, "general.tracking.desert");
   lvl += skills["general.tracking.mountain"];
   map_delete(skills, "general.tracking.mountain");
   lvl += skills["general.tracking.road"];
   map_delete(skills, "general.tracking.road");
   lvl += skills["general.tracking.field"];
   map_delete(skills, "general.tracking.field");

   if( lvl > 0 )
       skills["general.tracking"] = lvl;

   thing->set_skills( skills );
   tell_object(thing, "The squirrel says: Ok, all done now.\n");
} /* change_skills_epsilon() */

/**
 * Calulate the new skill value for the skills version zeta
 */
int new_skill_value(int sk) {
  float f = 1000.0;
  float k = 0.3;

  if(sk == 0)
    return 0;

  return to_int(f * log( 1.0 + sk/(f + sk * k) ) + 0.5);
}

/**
 * Change everyones skill levels (downwards).
 * @param thing the person to update
 */
void change_skills_zeta( object thing ) {
   mapping skills;
   string *bits, bit;

   skills = thing->query_skills();
   if (!sizeof(skills))
      return ;
   bits = keys(skills);

   tell_object(thing, "A small blue frog appears and says: I'm just updating "
         "your skill levels, this won't take a second.\n");

   // go through all the skills one by one
   foreach(bit in bits) {
     // if it's not a language skill & it's a leaf skill recalculate it and
     // then recalculate it's parents.
     if(bit[0..13] != "general.language" &&
        SKILL_OB->query_immediate_children(bit) == ({ })) {

       skills[bit] = new_skill_value(skills[bit]);
       skills = recalc_parents(skills, bit);
     }
   }
   // set these skills as their new skills and we're done.
   thing->set_skills( skills );
   tell_object(thing, "The frog says: Ok, all done now.\n");
}


/**
 * Called by the login handler, checks to see if an upgrade
 * is neede.
 * @param name the name of the player logging in
 * @param type the type of the login
 * @see /handlers/login_handler.c
 */
void entering( string name, string type ) {
   object thing;
   int lvl;

   if ( type != LOGIN )
      return;
   if ( !( thing = find_player( name ) ) )
      return;

   switch((string)thing->query_property( "skills version" )) {
   case VERSION:
     change_skills( thing );
   case VERSION_2:
     change_language_skills( thing, lvl );
   case VERSION_3:
     change_skills_epsilon( thing );
   case VERSION_4:
     change_skills_zeta(thing);
   default:
     // If they don't have a skill version then they're a new player and
     // don't need any modification to their skill tree.
     thing->add_property("skills version", VERSION_5);
     return;
   }
} /* entering() */

/**
 * The current version of the skill tree.
 * @return the version of the skill system
 */
string query_version() { return VERSION_5; }