/* ************************************************************************ * 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. * ************************************************************************* */ #include "os.h" #include "structs.h" #include "limits.h" #include "utils.h" #include "spells.h" #include "comm.h" #include "handler.h" #include "prototypes.h" #define READ_TITLE(ch) \ ( GET_SEX(ch) == SEX_MALE ? \ titles[(int)GET_CLASS(ch)-1][(int)GET_LEVEL(ch)].title_m : \ titles[(int)GET_CLASS(ch)-1][(int)GET_LEVEL(ch)].title_f ) extern struct char_data *character_list; extern struct obj_data *object_list; extern struct title_type titles[4][25]; extern struct room_data *world; /* External procedures */ void update_pos (struct char_data *victim); /* in fight.c */ void damage (struct char_data *ch, struct char_data *victim, /* do */ int damage, int weapontype); 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 = (100); /* + (graf(age(ch).year, 0,0,10,30,50,70,60)); */ 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 = 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; 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: gain += gain; break; case POSITION_RESTING: gain += (gain >> 1); /* Divide by 2 */ break; case POSITION_SITTING: gain += (gain >> 2); /* Divide by 4 */ break; } 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; if (IS_NPC (ch)) { gain = GET_LEVEL (ch); /* 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: gain += (gain >> 1); /* Divide by 2 */ break; case POSITION_RESTING: gain += (gain >> 2); /* Divide by 4 */ break; case POSITION_SITTING: gain += (gain >> 3); /* Divide by 8 */ break; } 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; if (IS_NPC (ch)) { return (GET_LEVEL (ch)); /* Neat and fast */ } else { gain = graf (age (ch).year, 12, 18, 22, 21, 14, 10, 6); /* Class/Level calculations */ /* Skill/Spell calculations */ /* Position calculations */ switch (GET_POS (ch)) { case POSITION_SLEEPING: gain += (gain >> 1); /* Divide by 2 */ break; case POSITION_RESTING: gain += (gain >> 2); /* Divide by 4 */ break; case POSITION_SITTING: gain += (gain >> 3); /* Divide by 8 */ break; } } 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, i; 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 (3, 8); } break; case CLASS_CLERIC:{ add_hp += number (5, 10); } break; case CLASS_THIEF:{ add_hp += number (7, 13); } break; case CLASS_WARRIOR:{ add_hp += number (10, 15); } break; } ch->points.max_hit += MAX (1, add_hp); if (GET_CLASS (ch) == CLASS_MAGIC_USER || GET_CLASS (ch) == CLASS_CLERIC) ch->specials.spells_to_learn += MAX (2, wis_app[GET_WIS (ch)].bonus); else ch->specials.spells_to_learn += MIN (2, MAX (1, wis_app[GET_WIS (ch)].bonus)); if (GET_LEVEL (ch) > 20) for (i = 0; i < 3; i++) ch->specials.conditions[i] = -1; } void set_title (struct char_data *ch) { if (GET_TITLE (ch)) RECREATE (GET_TITLE (ch), char, strlen (READ_TITLE (ch)) + 1); else CREATE (GET_TITLE (ch), char, strlen (READ_TITLE (ch))); strcpy (GET_TITLE (ch), READ_TITLE (ch)); } void gain_exp (struct char_data *ch, int gain) { int i; bool is_altered = FALSE; if (IS_NPC (ch) || ((GET_LEVEL (ch) < 21) && (GET_LEVEL (ch) > 0))) { if (gain > 0) { gain = MIN (100000, gain); GET_EXP (ch) += gain; if (!IS_NPC (ch)) { for (i = 0; titles[GET_CLASS (ch) - 1][i].exp <= GET_EXP (ch); i++) { if (i > GET_LEVEL (ch)) { send_to_char ("You raise a level\n\r", ch); GET_LEVEL (ch) = i; advance_level (ch); is_altered = TRUE; } } } } if (gain < 0) { gain = MAX (-500000, gain); /* Never loose more than 1/2 mil */ GET_EXP (ch) += gain; if (GET_EXP (ch) < 0) GET_EXP (ch) = 0; } if (is_altered) set_title (ch); } } void gain_exp_regardless (struct char_data *ch, int gain) { int i; bool is_altered = FALSE; if (!IS_NPC (ch)) { if (gain > 0) { GET_EXP (ch) += gain; for (i = 0; (i < 25) && (titles[GET_CLASS (ch) - 1][i].exp <= GET_EXP (ch)); i++) { if (i > GET_LEVEL (ch)) { send_to_char ("You raise a level\n\r", ch); GET_LEVEL (ch) = i; advance_level (ch); is_altered = TRUE; } } } if (gain < 0) GET_EXP (ch) += gain; if (GET_EXP (ch) < 0) GET_EXP (ch) = 0; } if (is_altered) set_title (ch); } 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; } } void check_idling (struct char_data *ch) { if (++(ch->specials.timer) > 8) if (ch->specials.was_in_room == NOWHERE && ch->in_room != NOWHERE) { ch->specials.was_in_room = ch->in_room; if (ch->specials.fighting) { stop_fighting (ch->specials.fighting); stop_fighting (ch); } act ("$n disappears into the void.", TRUE, ch, 0, 0, TO_ROOM); send_to_char ("You have been idle, and are pulled into a void.\n\r", ch); char_from_room (ch); char_to_room (ch, 1); /* Into room number 0 */ } else if (ch->specials.timer > 48) { if (ch->in_room != NOWHERE) char_from_room (ch); if (ch->specials.was_in_room != NOWHERE) char_to_room (ch, ch->specials.was_in_room); else char_to_room (ch, 1); if (ch->desc) close_socket (ch->desc); ch->desc = 0; extract_char (ch); } } /* 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, *jj, *next_thing2; /* 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) < 22) 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); } 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); } extract_obj (j); } } } }