/* SillyMUD Distribution V1.1b (c) 1993 SillyMUD Developement See license.doc for distribution terms. SillyMUD is based on DIKUMUD */ #include <stdio.h> #include <assert.h> #include "protos.h" struct room_data *real_roomp(int); extern struct char_data *character_list; extern struct obj_data *object_list; extern struct title_type titles[MAX_CLASS][ABS_MAX_LVL]; extern struct room_data *world; extern const char *RaceName[]; extern int RacialMax[][MAX_CLASS]; extern struct wis_app_type wis_app[]; extern struct con_app_type con_app[]; char *ClassTitles(struct char_data *ch) { unsigned char i, count=0; char buf[256]; for (i = MAGE_LEVEL_IND; i <= MONK_LEVEL_IND; i++) { if (GET_LEVEL(ch, i)) { count++; if (count > 1) { sprintf(buf + strlen(buf), "/%s",GET_CLASS_TITLE(ch, i,GET_LEVEL(ch,i))); } else { sprintf(buf, "%s", GET_CLASS_TITLE(ch, i, GET_LEVEL(ch, i))); } } } return(buf); } /* 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, tmp; max = 0; if (IS_NPC(ch)) return(100); if (HasClass(ch, CLASS_MAGIC_USER)) { max += 100; max += GET_LEVEL(ch, MAGE_LEVEL_IND) * 5; } if (HasClass(ch, CLASS_CLERIC)) { max += 100; max += (GET_LEVEL(ch, CLERIC_LEVEL_IND)/3) * 5; } if (HasClass(ch, CLASS_DRUID)) { max += 100; max += (GET_LEVEL(ch, DRUID_LEVEL_IND)/3) * 5; } if (HasClass(ch, CLASS_THIEF)) { max += 100; } if (HasClass(ch, CLASS_WARRIOR)) { max += 100; } if (HasClass(ch, CLASS_MONK)) { max += 100; } max /= HowManyClasses(ch); /* new classes should be inserted here. */ tmp = GET_INT(ch)/3; tmp += 2; tmp = tmp*3; max += tmp; max += ch->points.max_mana; /* bonus mana */ return(max); } int hit_limit(struct char_data *ch) { int max; if (!IS_NPC(ch)) { struct time_info_data ma; age2(ch, &ma); max = (ch->points.max_hit) + (graf(ma.year, 2,4,17,14,8,0,-10)); } 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)) { max = 100 + GET_CON(ch); } else { max = ch->points.max_move; } if (IsRideable(ch)) max *= 2; if (GET_RACE(ch) == RACE_DWARF || GET_RACE(ch) == RACE_GNOME) max -= 35; else if (GET_RACE(ch) == RACE_ELVEN) max += 20; else if (GET_RACE(ch) == RACE_HALFLING) max -= 45; max += ch->points.max_move; /* move bonus */ return (max); } /* manapoint gain pr. game hour */ int mana_gain(struct char_data *ch) { int gain; if((IS_NPC(ch)) && (!IS_SET(ch->specials.act, ACT_POLYSELF))) { /* Neat and fast */ gain = 8; } else { struct time_info_data ma; age2(ch, &ma); gain = graf(ma.year, 2,4,6,8,10,16,2); } /* 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; } gain += gain; gain += wis_app[GET_WIS(ch)].bonus*2; if (IS_AFFECTED(ch,AFF_POISON)) gain >>= 2; if((GET_COND(ch,FULL)==0)||(GET_COND(ch,THIRST)==0)) gain >>= 2; if (GET_RACE(ch) == RACE_ELVEN || GET_RACE(ch) == RACE_GNOME) gain+=2; if (GET_COND(ch, DRUNK)>10) gain += (gain >> 1); else if (GET_COND(ch, DRUNK)>0) gain += (gain >> 2); return (gain); } int hit_gain(struct char_data *ch) /* Hitpoint gain pr. game hour */ { int gain, dam, i; if(IS_NPC(ch)) { gain = 8; /* Neat and fast */ } else { if (GET_POS(ch) == POSITION_FIGHTING) { gain = 0; } else { struct time_info_data ma; age2(ch, &ma); gain = graf(ma.year, 2,4,6,8,6,3,1); } } /* Class/Level calculations */ /* Skill/Spell calculations */ /* Position calculations */ switch (GET_POS(ch)) { case POSITION_SLEEPING: gain += gain>>2; break; case POSITION_RESTING: gain+= gain>>3; break; case POSITION_SITTING: gain += gain>>4; break; } if (GET_RACE(ch) == RACE_DWARF) gain += 2; if (GET_RACE(ch) == RACE_HALFLING) gain += 1; gain += con_app[GET_CON(ch)].hitp/2; if (IS_AFFECTED(ch,AFF_POISON)) { gain = 0; dam = 32; if (GET_RACE(ch) == RACE_HALFLING) dam = 16; if (affected_by_spell(ch, SPELL_SLOW_POISON)) dam /= 4; damage(ch, ch, dam, SPELL_POISON); } if (IS_AFFECTED2(ch, AFF2_HEAT_STUFF)) { dam = 0; /* count items in eq */ for (i=0;i<=HOLD;i++) { if (ch->equipment[i]) { dam += 2; } } damage(ch, ch, dam, SPELL_HEAT_STUFF); } if((GET_COND(ch,FULL)==0)||(GET_COND(ch,THIRST)==0)) gain >>= 4; if (GET_COND(ch, DRUNK)>10) gain += (gain >> 1); else if (GET_COND(ch, DRUNK)>0) gain += (gain >> 2); if (GET_RACE(ch) == RACE_TROLL) gain *= 2; return (gain); } int move_gain(struct char_data *ch) /* move gain pr. game hour */ { int gain; if(IS_NPC(ch)) { gain = 22; if (IsRideable(ch)) gain += gain/2; /* Neat and fast */ } else { struct time_info_data ma; age2(ch, &ma); if (GET_POS(ch) != POSITION_FIGHTING) gain = graf(ma.year, 10,15,20,22,15,7,1); else gain = 0; } /* Position calculations */ switch (GET_POS(ch)) { case POSITION_SLEEPING: gain += (gain>>2); /* Divide by 4 */ break; case POSITION_RESTING: gain+= (gain>>3); /* Divide by 8 */ break; case POSITION_SITTING: gain += (gain>>4); /* Divide by 16 */ break; } if (GET_RACE(ch) == RACE_DWARF) gain += 4; if (IS_AFFECTED(ch,AFF_POISON)) gain >>= 5; if((GET_COND(ch,FULL)==0)||(GET_COND(ch,THIRST)==0)) gain >>= 3; return (gain); } /* Gain maximum in various points */ void advance_level(struct char_data *ch, int class) { int add_hp, i; if (class > MAX_CLASS) { log("Bad advance class.. no such class"); return; } if (GET_LEVEL(ch, class) > 0 && GET_EXP(ch) < titles[class][GET_LEVEL(ch, class)+1].exp) { /* they can't advance here */ log("Bad advance_level"); return; } GET_LEVEL(ch, class) += 1; if (class == WARRIOR_LEVEL_IND) add_hp = con_app[GET_RCON(ch)].hitp; else add_hp = MIN(con_app[GET_RCON(ch)].hitp,2); switch(class) { case MAGE_LEVEL_IND : { if (GET_LEVEL(ch, MAGE_LEVEL_IND) < 12) add_hp += number(1, 4); else add_hp += 1; } break; case CLERIC_LEVEL_IND : { if (GET_LEVEL(ch, CLERIC_LEVEL_IND) < 12) add_hp += number(1, 8); else add_hp += 3; } break; case THIEF_LEVEL_IND : { if (GET_LEVEL(ch, THIEF_LEVEL_IND) < 12) add_hp += number(1,6); else add_hp += 2; } break; case WARRIOR_LEVEL_IND : { if (GET_LEVEL(ch, WARRIOR_LEVEL_IND) < 10) add_hp += number(1,10); else add_hp += 4; } break; case DRUID_LEVEL_IND: if (GET_LEVEL(ch, DRUID_LEVEL_IND) < 15) add_hp += number(1,8); else add_hp += 3; break; case MONK_LEVEL_IND: if (GET_LEVEL(ch, MONK_LEVEL_IND) < 17) add_hp += number(1,6); else add_hp += 2; break; } add_hp /= HowManyClasses(ch); ch->points.max_hit += MAX(1, add_hp); if (ch->specials.spells_to_learn < 50) ch->specials.spells_to_learn += MAX(1, MAX(2, wis_app[GET_RWIS(ch)].bonus)/HowManyClasses(ch)); else { send_to_char("Practices: Use them or lose them.\n\r", ch); } ClassSpecificStuff(ch); if (GetMaxLevel(ch) >= LOW_IMMORTAL) for (i = 0; i < 3; i++) ch->specials.conditions[i] = -1; } /* Lose in various points */ /* ** Damn tricky for multi-class... */ void drop_level(struct char_data *ch, int class) { int add_hp, lin_class; extern struct wis_app_type wis_app[]; extern struct con_app_type con_app[]; if (GetMaxLevel(ch) >= LOW_IMMORTAL) return; if (GetMaxLevel(ch) == 1) return; add_hp = con_app[GET_RCON(ch)].hitp; switch(class) { case CLASS_MAGIC_USER : { lin_class = MAGE_LEVEL_IND; if (GET_LEVEL(ch, MAGE_LEVEL_IND) < 12) add_hp += number(2, 8); else add_hp += 2; } break; case CLASS_CLERIC : { lin_class = CLERIC_LEVEL_IND; if (GET_LEVEL(ch, CLERIC_LEVEL_IND) < 12) add_hp += number(2, 12); else add_hp += 5; } break; case CLASS_THIEF : { lin_class = THIEF_LEVEL_IND; if (GET_LEVEL(ch, THIEF_LEVEL_IND) < 12) add_hp += number(2,10); else add_hp += 4; } break; case CLASS_WARRIOR : { lin_class = WARRIOR_LEVEL_IND; if (GET_LEVEL(ch, WARRIOR_LEVEL_IND) < 10) add_hp += number(2,14); else add_hp += 6; } break; case CLASS_DRUID: lin_class = DRUID_LEVEL_IND; if (GET_LEVEL(ch, DRUID_LEVEL_IND) < 15) add_hp += number(2,12); else add_hp += 5; break; case CLASS_MONK: lin_class = MONK_LEVEL_IND; if (GET_LEVEL(ch, MONK_LEVEL_IND) < 17) add_hp += number(2,10); else add_hp += 4; break; } GET_LEVEL(ch, class) -= 1; if (GET_LEVEL(ch, class) < 1) { GET_LEVEL(ch, class) = 1; if (ch->points.max_hit > 15) ch->points.max_hit = 15; } if (class = WARRIOR_LEVEL_IND) add_hp = MAX(add_hp, 6); if (class = CLERIC_LEVEL_IND) add_hp = MAX(add_hp, 5); if (class = THIEF_LEVEL_IND) add_hp = MAX(add_hp, 4); if (class = MAGE_LEVEL_IND) add_hp = MAX(add_hp, 3); if (class = MONK_LEVEL_IND) add_hp = MAX(add_hp, 4); if (class = DRUID_LEVEL_IND) add_hp = MAX(add_hp, 5); add_hp /= HowManyClasses(ch); if (add_hp <=2) add_hp=3; ch->points.max_hit -= MAX(1,add_hp); if (ch->points.max_hit < 1) ch->points.max_hit = 1; ch->specials.spells_to_learn -= MAX(1, MAX(2, wis_app[GET_RWIS(ch)].bonus)/HowManyClasses(ch)); ch->points.exp = MIN(titles[lin_class][GET_LEVEL(ch, lin_class)].exp, GET_EXP(ch)); if (ch->points.exp < 0) ch->points.exp = 0; send_to_char("You lose a level\n\r", ch); } void set_title(struct char_data *ch) { char buf[256]; sprintf(buf, "the %s %s", RaceName[ch->race], ClassTitles(ch)); if (GET_TITLE(ch)) { free(GET_TITLE(ch)); CREATE(GET_TITLE(ch),char,strlen(buf)+1); } else { CREATE(GET_TITLE(ch),char,strlen(buf)+1); } strcpy(GET_TITLE(ch), buf); } void gain_exp(struct char_data *ch, int gain) { int i; char buf[256]; short chrace; save_char(ch,AUTO_RENT); if (!IS_PC(ch) && ch->master && IS_AFFECTED(ch, AFF_CHARM)) { if (ch->master->in_room == ch->in_room) { if (gain > 1) { gain/=2; sprintf(buf, "you gain $N's share of %d exp", gain); act(buf, 0, ch->master, 0, ch, TO_CHAR); gain_exp(ch->master, gain); } } return; } if (!IS_IMMORTAL(ch)) { if (gain > 0) { gain /= HowManyClasses(ch); if (GetMaxLevel(ch) == 1) { gain *= 2; } if (IS_PC(ch)) { if (ch->desc && ch->desc->original) chrace = ch->desc->original->race; else chrace = GET_RACE(ch); for (i = MAGE_LEVEL_IND; i < MAX_CLASS; i++) { if (GET_LEVEL(ch,i)&&(GET_LEVEL(ch,i))<RacialMax[chrace][i]) { if (GET_EXP(ch) >= titles[i][GET_LEVEL(ch,i)+2].exp) { send_to_char("You must practice at a guild before you can gain any more experience\n\r", ch); GET_EXP(ch) = titles[i][GET_LEVEL(ch,i)+2].exp - 1; return; } else if (GET_EXP(ch) >= titles[i][GET_LEVEL(ch,i)+1].exp) { /* do nothing..this is cool */ } else if (GET_EXP(ch)+gain >= titles[i][GET_LEVEL(ch,i)+1].exp) { sprintf(buf, "You have gained enough to be a(n) %s\n\r", GET_CLASS_TITLE(ch, i, GET_LEVEL(ch, i)+1)); send_to_char(buf, ch); send_to_char("You must return to a guild to earn the level\n\r",ch); if (GET_EXP(ch)+gain >= titles[i][GET_LEVEL(ch,i)+2].exp) { GET_EXP(ch) = titles[i][GET_LEVEL(ch,i)+2].exp - 1; return; } } } } } GET_EXP(ch)+=gain; if (IS_PC(ch)) { for (i=MAGE_LEVEL_IND; i< MAX_CLASS; i++) { if (GET_LEVEL(ch,i)&&GET_LEVEL(ch, i)<RacialMax[chrace][i]) { if (GET_EXP(ch) > titles[i][GET_LEVEL(ch,i)+2].exp) { GET_EXP(ch) = titles[i][GET_LEVEL(ch,i)+2].exp - 1; } } } } } if (gain < 0) { GET_EXP(ch) += gain; if (GET_EXP(ch) < 0) GET_EXP(ch) = 0; } } } void gain_exp_regardless(struct char_data *ch, int gain, int class) { int i; bool is_altered = FALSE; save_char(ch,AUTO_RENT); if (!IS_NPC(ch)) { if (gain > 0) { GET_EXP(ch) += gain; for (i=0;(i<ABS_MAX_LVL) &&(titles[class][i].exp <= GET_EXP(ch)); i++) { if (i > GET_LEVEL(ch,class)) { send_to_char("You raise a level\n\r", ch); GET_LEVEL(ch,class) = i; advance_level(ch,class); 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) { void do_save(struct char_data *ch, char *argument, int cmd); if (++(ch->specials.timer) == 8) { do_save(ch, "", 0); } else if (ch->specials.timer == 72) { if (ch->in_room != NOWHERE && ch->in_room != 0) { 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, 0); /* Into room number 0 */ } } else if (ch->specials.timer == 120) { struct obj_cost cost; if (ch->in_room != NOWHERE) char_from_room(ch); char_to_room(ch, 4); if (ch->desc) close_socket(ch->desc); ch->desc = 0; if (recep_offer(ch, NULL, &cost)) { if (cost.total_cost < 100) { cost.total_cost = 1000*(GetTotLevel(ch)* (GetTotLevel(ch)-1)); } save_obj(ch, &cost, 1); } extract_char(ch); } } int ObjFromCorpse( struct obj_data *c) { struct obj_data *jj, *next_thing; for(jj = c->contains; jj; jj = next_thing) { next_thing = jj->next_content; /* Next in inventory */ if (jj->in_obj) { obj_from_obj(jj); if (c->in_obj) obj_to_obj(jj,c->in_obj); else if (c->carried_by) { obj_to_room(jj,c->carried_by->in_room); check_falling_obj(jj, c->carried_by->in_room); } else if (c->in_room != NOWHERE) { obj_to_room(jj,c->in_room); check_falling_obj(jj, c->in_room); } else assert(FALSE); } else { /* ** hmm.. it isn't in the object it says it is in. ** don't extract it. */ c->contains = 0; log("Memory lost in ObjFromCorpse."); return(TRUE); } } extract_obj(c); } int ClassSpecificStuff( struct char_data *ch) { if (HasClass(ch, CLASS_WARRIOR) || HasClass(ch, CLASS_MONK)) { ch->mult_att = 1.0; if (HasClass(ch, CLASS_WARRIOR)) { ch->mult_att+=(MIN(30,(GET_LEVEL(ch, WARRIOR_LEVEL_IND)))*.05); } else { if (HasClass(ch, CLASS_MONK)) { ch->mult_att+= (GET_LEVEL(ch, MONK_LEVEL_IND)/16.0); } /* fix up damage stuff */ switch(GET_LEVEL(ch, MONK_LEVEL_IND)) { case 1: case 2: case 3: ch->specials.damnodice = 1; ch->specials.damsizedice = 3; break; case 4: case 5: ch->specials.damnodice = 1; ch->specials.damsizedice = 4; break; case 6: case 7: case 8: case 9: case 10: case 11: ch->specials.damnodice = 1; ch->specials.damsizedice = 6; break; case 12: case 13: case 14: ch->specials.damnodice = 2; ch->specials.damsizedice = 3; break; case 15: case 16: case 17: case 18: case 19: ch->specials.damnodice = 2; ch->specials.damsizedice = 4; break; case 20: case 21: ch->specials.damnodice = 3; ch->specials.damsizedice = 3; break; case 22: case 23: case 24: case 25: case 26: ch->specials.damnodice = 3; ch->specials.damsizedice = 4; break; case 27: case 28: case 29: ch->specials.damnodice = 4; ch->specials.damsizedice = 3; break; case 30: case 31: case 32: case 33: case 34: ch->specials.damnodice = 4; ch->specials.damsizedice = 4; break; case 35: case 36: ch->specials.damnodice = 4; ch->specials.damsizedice = 5; break; case 37: case 38: case 39: case 40: case 41: ch->specials.damnodice = 5; ch->specials.damsizedice = 4; break; case 42: case 43: case 44: ch->specials.damnodice = 6; ch->specials.damsizedice = 4; break; case 45: case 46: case 47: case 48: case 49: ch->specials.damnodice = 6; ch->specials.damsizedice = 5; break; case 50: ch->specials.damnodice = 8; ch->specials.damsizedice = 4; break; default: ch->specials.damnodice=1; ch->specials.damsizedice = 2; break; } } } /* other stuff.. immunities, etc, are set here */ if (HasClass(ch, CLASS_MONK)) { /* */ if (GET_LEVEL(ch, MONK_LEVEL_IND) > 10) SET_BIT(ch->M_immune, IMM_HOLD); if (GET_LEVEL(ch, MONK_LEVEL_IND) > 18) SET_BIT(ch->immune, IMM_CHARM); if (GET_LEVEL(ch, MONK_LEVEL_IND) > 22) SET_BIT(ch->M_immune, IMM_POISON); if (GET_LEVEL(ch, MONK_LEVEL_IND) > 36) SET_BIT(ch->M_immune, IMM_CHARM); } else { if (HasClass(ch, CLASS_DRUID)) { if (GET_LEVEL(ch, DRUID_LEVEL_IND) >= 14) { SET_BIT(ch->immune, IMM_CHARM); } if (GET_LEVEL(ch, DRUID_LEVEL_IND) >= 32) { SET_BIT(ch->M_immune, IMM_POISON); } } if (HasClass(ch, CLASS_THIEF)) { if (OnlyClass(ch, CLASS_THIEF)) GET_CHR(ch)+=1; GET_CHR(ch) += GET_LEVEL(ch, THIEF_LEVEL_IND)/10; } } }