/*************************************************************************** * file: limits.c , Limit and gain control module. Part of DIKUMUD * * Usage: Procedures controling gain and limit. * * Copyright (C) 1990, 1991 - see 'license.doc' for complete information. * * * * Copyright (C) 1992, 1993 Michael Chastain, Michael Quan, Mitchell Tse * * Performance optimization and bug fixes by MERC Industries. * * You can use our stuff in any way you like whatsoever so long as this * * copyright notice remains intact. If you like it please drop a line * * to mec@garnet.berkeley.edu. * * * * This is free software and you are benefitting. We hope that you * * share your changes too. What goes around, comes around. * ***************************************************************************/ #include <stdlib.h> #include <stdio.h> #include <string.h> #include <assert.h> #include "structs.h" #include "mob.h" #include "obj.h" #include "limits.h" #include "utils.h" #include "spells.h" #include "db.h" extern struct char_data *character_list; extern struct obj_data *object_list; extern struct room_data *world; /* External procedures */ void update_pos( struct char_data *victim ); /* in fight.c */ struct time_info_data age(struct char_data *ch); /* When age < 15 return the value p0 */ /* When age in 15..29 calculate the line between p1 & p2 */ /* When age in 30..44 calculate the line between p2 & p3 */ /* When age in 45..59 calculate the line between p3 & p4 */ /* When age in 60..79 calculate the line between p4 & p5 */ /* When age >= 80 return the value p6 */ int graf(int age, int p0, int p1, int p2, int p3, int p4, int p5, int p6) { if (age < 15) return(p0); /* < 15 */ else if (age <= 29) return (int) (p1+(((age-15)*(p2-p1))/15)); /* 15..29 */ else if (age <= 44) return (int) (p2+(((age-30)*(p3-p2))/15)); /* 30..44 */ else if (age <= 59) return (int) (p3+(((age-45)*(p4-p3))/15)); /* 45..59 */ else if (age <= 79) return (int) (p4+(((age-60)*(p5-p4))/20)); /* 60..79 */ else return(p6); /* >= 80 */ } /* The three MAX functions define a characters Effective maximum */ /* Which is NOT the same as the ch->points.max_xxxx !!! */ int mana_limit(struct char_data *ch) { int max; if (!IS_NPC(ch)) max = (ch->points.max_mana); else max = 100; return(max); } int hit_limit(struct char_data *ch) { int max; if (!IS_NPC(ch)) max = (ch->points.max_hit) + (graf(age(ch).year, 2,4,17,14,8,4,3)); else max = (ch->points.max_hit); /* Class/Level calculations */ /* Skill/Spell calculations */ return (max); } int move_limit(struct char_data *ch) { int max; if (!IS_NPC(ch)) /* HERE SHOULD BE CON CALCULATIONS INSTEAD */ max = (ch->points.max_move) + graf(age(ch).year, 50,70,160,120,100,40,20); else max = ch->points.max_move; /* Class/Level calculations */ /* Skill/Spell calculations */ return (max); } /* manapoint gain pr. game hour */ int mana_gain(struct char_data *ch) { int gain; int divisor = 100000; if(IS_NPC(ch)) { /* Neat and fast */ gain = GET_LEVEL(ch); } else { gain = graf(age(ch).year, 2,4,6,8,6,5,8); /* Class calculations */ /* Skill/Spell calculations */ /* Position calculations */ switch (GET_POS(ch)) { case POSITION_SLEEPING: divisor = 2; break; case POSITION_RESTING: divisor = 4; break; case POSITION_SITTING: divisor = 8; break; } gain += (GET_INT(ch) + GET_WIS(ch)) / divisor; if (GET_CLASS(ch) == CLASS_MAGIC_USER || GET_CLASS(ch) == CLASS_CLERIC) gain += gain; } if (IS_AFFECTED(ch,AFF_POISON)) gain >>= 2; if((GET_COND(ch,FULL)==0)||(GET_COND(ch,THIRST)==0)) gain >>= 2; return (gain); } int hit_gain(struct char_data *ch) /* Hitpoint gain pr. game hour */ { int gain; int divisor = 100000; if(IS_NPC(ch)) { gain = (GET_LEVEL(ch) * 3 ) / 2; /* Neat and fast */ } else { gain = graf(age(ch).year, 2,5,10,18,6,4,2); /* Class/Level calculations */ /* Skill/Spell calculations */ /* Position calculations */ switch (GET_POS(ch)) { case POSITION_SLEEPING: divisor = 1; break; case POSITION_RESTING: divisor = 2; break; case POSITION_SITTING: divisor = 4; break; } gain += GET_CON(ch) / divisor; if (GET_CLASS(ch) == CLASS_MAGIC_USER || GET_CLASS(ch) == CLASS_CLERIC) gain >>= 1; } if (IS_AFFECTED(ch,AFF_POISON)) { gain >>= 2; damage(ch,ch,2,SPELL_POISON); } if((GET_COND(ch,FULL)==0)||(GET_COND(ch,THIRST)==0)) gain >>= 2; return (gain); } int move_gain(struct char_data *ch) /* move gain pr. game hour */ { int gain; int divisor = 100000; if(IS_NPC(ch)) { return(GET_LEVEL(ch)); /* Neat and fast */ } else { gain = graf(age(ch).year, 6,9,11,10,7,5,3); /* Class/Level calculations */ /* Skill/Spell calculations */ /* Position calculations */ switch (GET_POS(ch)) { case POSITION_SLEEPING: divisor = 1; break; case POSITION_RESTING: divisor = 3; break; case POSITION_SITTING: divisor = 6; break; } gain += (GET_CON(ch) + GET_DEX(ch)) / divisor; } if (IS_AFFECTED(ch,AFF_POISON)) gain >>= 2; if((GET_COND(ch,FULL)==0)||(GET_COND(ch,THIRST)==0)) gain >>= 2; return (gain); } /* Gain maximum in various points */ void advance_level(struct char_data *ch) { int add_hp; int add_mana = 0; int add_moves = 0; int add_practices; int i; char buf[MAX_STRING_LENGTH]; extern struct wis_app_type wis_app[]; extern struct con_app_type con_app[]; add_hp = con_app[GET_CON(ch)].hitp; switch(GET_CLASS(ch)) { case CLASS_MAGIC_USER: add_hp += number(6, 8); add_mana += number(2, (GET_INT(ch) + GET_WIS(ch))/6); add_moves += number(5, (GET_CON(ch) + 2 * GET_DEX(ch)) / 5); break; case CLASS_CLERIC: add_hp += number(7, 10); add_mana += number(2, (GET_INT(ch) + GET_WIS(ch))/6); add_moves += number(5, (GET_CON(ch) + 2 * GET_DEX(ch)) / 5); break; case CLASS_THIEF: add_hp += number(8, 13); add_moves += number(5, (GET_CON(ch) + 2 * GET_DEX(ch)) / 5); break; case CLASS_WARRIOR: add_hp += number(11, 15); add_moves += number(5, (GET_CON(ch) + 2 * GET_DEX(ch)) / 5); break; } add_hp = MAX( 1, add_hp); add_mana = MAX( 0, add_mana); add_moves = MAX(10, add_moves); add_practices = wis_app[GET_WIS(ch)].bonus; ch->points.max_hit += add_hp; ch->points.max_mana += add_mana; ch->points.max_move += add_moves; ch->specials.practices += add_practices; sprintf( buf, "Your gain is: %d/%d hp, %d/%d m, %d/%d mv %d/%d prac.\n\r", add_hp, GET_MAX_HIT(ch), add_mana, GET_MAX_MANA(ch), add_moves, GET_MAX_MOVE(ch), add_practices, ch->specials.practices ); send_to_char( buf, ch ); if (GET_LEVEL(ch) > 31) for (i = 0; i < 3; i++) ch->specials.conditions[i] = -1; } void set_title(struct char_data *ch) { FREE( GET_TITLE(ch) ); GET_TITLE(ch) = str_dup( title_table [GET_CLASS(ch)-1] [(int) GET_LEVEL(ch)] [GET_SEX(ch)==SEX_FEMALE] ); return; } void gain_exp( CHAR_DATA *ch, int gain ) { if ( !IS_NPC(ch) ) { if ( GET_LEVEL(ch) >= 31 ) return; switch ( GET_CLASS(ch) ) { case CLASS_THIEF: gain += gain / 8; break; case CLASS_MAGIC_USER: gain += gain / 4; break; case CLASS_CLERIC: gain += gain / 2; break; } } GET_EXP(ch) += gain; if ( GET_EXP(ch) < 0 ) GET_EXP(ch) = 0; if ( IS_NPC(ch) ) return; while ( GET_EXP(ch) >= exp_table[GET_LEVEL(ch)+1] ) { send_to_char( "You raise a level!! ", ch ); GET_LEVEL(ch) += 1; advance_level( ch ); set_title( ch ); } return; } void gain_exp_regardless( CHAR_DATA *ch, int gain ) { GET_EXP(ch) += gain; if ( GET_EXP(ch) < 0 ) GET_EXP(ch) = 0; if ( IS_NPC(ch) ) return; while ( GET_EXP(ch) >= exp_table[GET_LEVEL(ch)+1] ) { send_to_char( "You raise a level!! ", ch ); GET_LEVEL(ch) += 1; advance_level( ch ); set_title( ch ); } return; } void gain_condition(struct char_data *ch,int condition,int value) { bool intoxicated; if(GET_COND(ch, condition)==-1) /* No change */ return; intoxicated=(GET_COND(ch, DRUNK) > 0); GET_COND(ch, condition) += value; GET_COND(ch,condition) = MAX(0,GET_COND(ch,condition)); GET_COND(ch,condition) = MIN(24,GET_COND(ch,condition)); if(GET_COND(ch,condition)) return; switch(condition){ case FULL : { send_to_char("You are hungry.\n\r",ch); return; } case THIRST : { send_to_char("You are thirsty.\n\r",ch); return; } case DRUNK : { if(intoxicated) send_to_char("You are now sober.\n\r",ch); return; } default : break; } } /* Update both PC's & NPC's and objects*/ void point_update( void ) { void update_char_objects( struct char_data *ch ); /* handler.c */ void extract_obj(struct obj_data *obj); /* handler.c */ struct char_data *i, *next_dude; struct obj_data *j, *next_thing; /* characters */ for (i = character_list; i; i = next_dude) { next_dude = i->next; if (GET_POS(i) > POSITION_STUNNED) { GET_HIT(i) = MIN(GET_HIT(i) + hit_gain(i), hit_limit(i)); GET_MANA(i) = MIN(GET_MANA(i) + mana_gain(i), mana_limit(i)); GET_MOVE(i) = MIN(GET_MOVE(i) + move_gain(i), move_limit(i)); } else if (GET_POS(i) == POSITION_STUNNED) { GET_HIT(i) = MIN(GET_HIT(i) + hit_gain(i), hit_limit(i)); GET_MANA(i) = MIN(GET_MANA(i) + mana_gain(i), mana_limit(i)); GET_MOVE(i) = MIN(GET_MOVE(i) + move_gain(i), move_limit(i)); update_pos( i ); } else if (GET_POS(i) == POSITION_INCAP) damage(i, i, 1, TYPE_SUFFERING); else if (!IS_NPC(i) && (GET_POS(i) == POSITION_MORTALLYW)) damage(i, i, 2, TYPE_SUFFERING); if (!IS_NPC(i)) { update_char_objects(i); if (GET_LEVEL(i) < 35) { if ( i->desc && i->desc->tick_wait > 0 ) i->desc->tick_wait--; check_idling(i); } } gain_condition(i,FULL,-1); gain_condition(i,DRUNK,-1); gain_condition(i,THIRST,-1); } /* for */ /* objects */ for(j = object_list; j ; j = next_thing){ next_thing = j->next; /* Next in object list */ /* If this is a corpse */ if ( (GET_ITEM_TYPE(j) == ITEM_CONTAINER) && (j->obj_flags.value[3]) ) { /* timer count down */ if (j->obj_flags.timer > 0) j->obj_flags.timer--; if (!j->obj_flags.timer) { if (j->carried_by) act("$p decay in your hands.", FALSE, j->carried_by, j, 0, TO_CHAR); else if ((j->in_room != NOWHERE) && (world[j->in_room].people)) { act("A quivering hoard of maggots consume $p.", TRUE, world[j->in_room].people, j, 0, TO_ROOM); act("A quivering hoard of maggots consume $p.", TRUE, world[j->in_room].people, j, 0, TO_CHAR); } #if defined(KEEP_CORPSE_CONTENTS) for(jj = j->contains; jj; jj = next_thing2) { next_thing2 = jj->next_content; /* Next in inventory */ obj_from_obj(jj); if (j->in_obj) obj_to_obj(jj,j->in_obj); else if (j->carried_by) obj_to_room(jj,j->carried_by->in_room); else if (j->in_room != NOWHERE) obj_to_room(jj,j->in_room); else assert(FALSE); } #endif extract_obj(j); } } } }