Date: Tuesday August 1, 2000 @ 23:04 Author: cvs Update of /home/cvs/CVS/crossfire/server In directory boltzmann.eecs.berkeley.edu:/tmp/cvs-serv32470/server Modified Files: init.c player.c skill_util.c Log Message: include/config.h, include/global.h, common/init.c, common/living.c, server/init.c, server/player.c, server/skill_util.c: Add permanent experience and balanced stat loss features (code by Garth Denley). Permanent experience make some experience in the skills permanent. Balance stat loss makes stat loss less likely/costly at low level and more costly at higher levels. These features are by default off, but can be turned on either in the config.h file or via command line options. Code checked in by MSW 8/1/2000 **************************************** Index: crossfire/server/init.c diff -u crossfire/server/init.c:1.6 crossfire/server/init.c:1.7 --- crossfire/server/init.c:1.6 Thu Jun 15 23:07:07 2000 +++ crossfire/server/init.c Tue Aug 1 23:04:50 2000 @@ -1,12 +1,12 @@ /* * static char *rcsid_init_c = - * "$Id: init.c,v 1.6 2000/06/16 06:07:07 cvs Exp $"; + * "$Id: init.c,v 1.7 2000/08/02 06:04:50 cvs Exp $"; */ /* CrossFire, A Multiplayer game for X-windows - Copyright (C) 1992 Mark Wedel + Copyright (C) 2000 Mark Wedel Copyright (C) 1992 Frank Tore Johansen This program is free software; you can redistribute it and/or modify @@ -23,7 +23,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - The author can be reached via e-mail to master at rahul.net + The author can be reached via e-mail to mwedel at scruz.net */ #include <global.h> @@ -77,6 +77,12 @@ static void stat_loss_on_death_true() {settings.stat_loss_on_death = 1; } static void stat_loss_on_death_false() {settings.stat_loss_on_death = 0; } +static void use_permanent_experience_true() {settings.use_permanent_experience = 1; } +static void use_permanent_experience_false() {settings.use_permanent_experience = 0; } + +static void balanced_stat_loss_true() {settings.balanced_stat_loss = 1; } +static void balanced_stat_loss_false() {settings.balanced_stat_loss = 0; } + static void simple_exp_true() {settings.simple_exp = 1; } static void simple_exp_false() {settings.simple_exp = 0; } @@ -152,6 +158,10 @@ {"+simple_exp", 0, 3, simple_exp_false}, {"-stat_loss_on_death", 0, 3, stat_loss_on_death_true}, {"+stat_loss_on_death", 0, 3, stat_loss_on_death_false}, +{"-balanced_stat_loss", 0, 3, balanced_stat_loss_true}, +{"+balanced_stat_loss", 0, 3, balanced_stat_loss_false}, +{"-use_permanent_experience", 0, 3, use_permanent_experience_true}, +{"+use_permanent_experience", 0, 3, use_permanent_experience_false} }; @@ -265,8 +275,12 @@ printf(" -o Prints out info on what was defined at compile time.\n"); printf(" -s Display the high-score list.\n"); printf(" -score <name or class> Displays all high scores with matching name/class.\n"); - printf(" -stat_loss_on_death - if set, player loses stat when they die"); - printf(" +stat_loss_on_death - if set, player does not lose a stat when they die"); + printf(" -stat_loss_on_death - if set, player loses stat when they die\n"); + printf(" +stat_loss_on_death - if set, player does not lose a stat when they die\n"); + printf(" -use_permanent_experience - if set, player may gain permanent experience\n"); + printf(" +use_permanent_experience - if set, player does not gain permanent experience\n"); + printf(" -balanced_stat_loss - if set, death stat depletion is balanced by level etc\n"); + printf(" +balanced_stat_loss - if set, ordinary death stat depletion is used\n"); printf(" -v Print version and contributors.\n"); #ifndef SECURE Index: crossfire/server/player.c diff -u crossfire/server/player.c:1.15 crossfire/server/player.c:1.16 --- crossfire/server/player.c:1.15 Fri Jun 23 02:55:11 2000 +++ crossfire/server/player.c Tue Aug 1 23:04:50 2000 @@ -1,6 +1,6 @@ /* * static char *rcsid_player_c = - * "$Id: player.c,v 1.15 2000/06/23 09:55:11 jec Exp $"; + * "$Id: player.c,v 1.16 2000/08/02 06:04:50 cvs Exp $"; */ /* @@ -38,7 +38,6 @@ #include <skills.h> #include <newclient.h> - void display_motd(object *op) { #ifdef MOTD char buf[MAX_BUF]; @@ -1597,7 +1596,12 @@ int x,y,i; mapstruct *map; /* this is for resurrection */ object *tmp; - + int z; + int num_stats_lose; + int lost_a_stat; + int lose_this_stat; + int this_stat; + if(save_life(op)) return; @@ -1640,33 +1644,93 @@ * make it depletion. This bunch of code deals with that aspect * of death. */ - if (settings.stat_loss_on_death) { - /* Pick a random stat and take a point off it. Tell the player - * what he lost. - */ - i = RANDOM() % 7; - change_attr_value(&(op->stats), i,-1); - check_stat_bounds(&(op->stats)); - change_attr_value(&(op->contr->orig_stats), i,-1); - check_stat_bounds(&(op->contr->orig_stats)); - new_draw_info(NDI_UNIQUE, 0,op, lose_msg[i]); + + if (settings.balanced_stat_loss) { + /* If stat loss is permanent, lose one stat only. */ + /* Lower level chars don't lose as many stats because they suffer more + if they do. */ + /* Higher level characters can afford things such as potions of + restoration, or better, stat potions. So we slug them that little + bit harder. */ + /* GD */ + if (settings.stat_loss_on_death) + num_stats_lose = 1; + else + num_stats_lose = 1 + op->level/BALSL_NUMBER_LOSSES_RATIO; } else { - /* deplete a stat */ - archetype *deparch=find_archetype("depletion"); - object *dep; - - i = RANDOM() % 7; - dep = present_arch_in_ob(deparch,op); - if(!dep) { - dep = arch_to_object(deparch); - insert_ob_in_ob(dep, op); - } - change_attr_value(&(dep->stats), i,-1); - SET_FLAG(dep, FLAG_APPLIED); - new_draw_info(NDI_UNIQUE, 0,op, lose_msg[i]); - fix_player(op); + num_stats_lose = 1; } + lost_a_stat = 0; + for (z=0; z<num_stats_lose; z++) { + if (settings.stat_loss_on_death) { + /* Pick a random stat and take a point off it. Tell the player + * what he lost. + */ + i = RANDOM() % 7; + change_attr_value(&(op->stats), i,-1); + check_stat_bounds(&(op->stats)); + change_attr_value(&(op->contr->orig_stats), i,-1); + check_stat_bounds(&(op->contr->orig_stats)); + new_draw_info(NDI_UNIQUE, 0,op, lose_msg[i]); + lost_a_stat = 1; + } else { + /* deplete a stat */ + archetype *deparch=find_archetype("depletion"); + object *dep; + + i = RANDOM() % 7; + dep = present_arch_in_ob(deparch,op); + if(!dep) { + dep = arch_to_object(deparch); + insert_ob_in_ob(dep, op); + } + lose_this_stat = 1; + if (settings.balanced_stat_loss) { + /* GD */ + /* Get the stat that we're about to deplete. */ + this_stat = get_attr_value(&(dep->stats), i); + if (this_stat < 0) { + int loss_chance = 1 + op->level/BALSL_LOSS_CHANCE_RATIO; + int keep_chance = this_stat * this_stat; + /* Yes, I am paranoid. Sue me. */ + if (keep_chance < 1) + keep_chance = 1; + + /* There is a maximum depletion total per level. */ + if (this_stat < -1 - op->level/BALSL_MAX_LOSS_RATIO) { + lose_this_stat = 0; + /* Take loss chance vs keep chance to see if we retain the stat. */ + } else { + if ((RANDOM() % (loss_chance + keep_chance)) < keep_chance) + lose_this_stat = 0; + /* LOG(llevDebug, "Determining stat loss. Stat: %d Keep: %d Lose: %d Result: %s.\n", + this_stat, keep_chance, loss_chance, + lose_this_stat?"LOSE":"KEEP"); */ + } + } + } + + if (lose_this_stat) { + change_attr_value(&(dep->stats), i, -1); + SET_FLAG(dep, FLAG_APPLIED); + new_draw_info(NDI_UNIQUE, 0,op, lose_msg[i]); + fix_player(op); + lost_a_stat = 1; + } + } + } + /* If no stat lost, tell the player. */ + if (!lost_a_stat) + { + /* determine_god() seems to not work sometimes... why is this? + Should I be using something else? GD */ + char *god = determine_god(op); + if (god && (strcmp(god, "none"))) + new_draw_info_format(NDI_UNIQUE, 0, op, "For a brief moment you feel the holy presence of %s protecting you.", god); + else + new_draw_info(NDI_UNIQUE, 0, op, "For a brief moment you feel a holy presence protecting you."); + } /* Put a gravestone up where the character 'almost' died. List the * exp loss on the stone. Index: crossfire/server/skill_util.c diff -u crossfire/server/skill_util.c:1.6 crossfire/server/skill_util.c:1.7 --- crossfire/server/skill_util.c:1.6 Tue Jun 13 21:04:16 2000 +++ crossfire/server/skill_util.c Tue Aug 1 23:04:50 2000 @@ -1,6 +1,6 @@ /* * static char *rcsid_skill_util_c = - * "$Id: skill_util.c,v 1.6 2000/06/14 04:04:16 cvs Exp $"; + * "$Id: skill_util.c,v 1.7 2000/08/02 06:04:50 cvs Exp $"; */ /* CrossFire, A Multiplayer game for X-windows @@ -1000,6 +1000,22 @@ return 1; } +/* Gives a percentage clipped to 0% -> 100% of a/b. */ +/* Probably belongs in some global utils-type file? */ +static int clipped_percent(int a, int b) +{ + int rv; + + rv = (a*100)/b; + + if (rv < 0) + return 0; + else if (rv > 100) + return 100; + + return rv; +} + /* show_skills() - Meant to allow players to examine * their current skill list. b.t. ( thomas at nomad.astro.psu.edu ) * I have now added capability to show assoc. experience objects too. @@ -1060,9 +1076,18 @@ char tmpbuf[40]; strcpy(tmpbuf,tmp_exp->name); while(k>0) {k--; strcat(tmpbuf,".");} - new_draw_info_format(NDI_UNIQUE,0,op,"%slvl:%3d (xp:%d/%d)", - tmpbuf,tmp_exp->level,tmp_exp->stats.exp, - level_exp(tmp_exp->level+1, op->expmul)); + if (settings.use_permanent_experience) { + new_draw_info_format(NDI_UNIQUE,0,op,"%slvl:%3d (xp:%d/%d/%d%%)", + tmpbuf,tmp_exp->level, + tmp_exp->stats.exp, + level_exp(tmp_exp->level+1, op->expmul), + clipped_percent(tmp_exp->last_heal,tmp_exp->stats.exp)); + } else { + new_draw_info_format(NDI_UNIQUE,0,op,"%slvl:%3d (xp:%d/%d)", + tmpbuf,tmp_exp->level, + tmp_exp->stats.exp, + level_exp(tmp_exp->level+1, op->expmul)); + } if (strcmp(tmp_exp->name,"physique")==0) { sprintf(Special,"You can handle %d weapon improvements.",tmp_exp->level/5+5);