/* receptionist's surcharge on top of item costs */ int min_rent_cost(CHAR_DATA * ch) { if (1/*(GET_LEVEL(ch) < 15) && (GET_REMORT(ch) == 0)*/) // prool return (0); else return ((GET_LEVEL(ch) + 30 * GET_REMORT(ch)) * 2); }
/** * Считаем реальные статы с учетом мортов и влитой славы. * \return 0 - все ок, любое другое число - все плохо */ int bad_real_stats(CHAR_DATA *ch, int check) { check -= SUM_ALL_STATS; // стартовые статы у всех по 95 check -= 6 * GET_REMORT(ch); // реморты // влитая слава check -= Glory::get_spend_glory(ch); check -= GloryConst::main_stats_count(ch); return check; }
int max_exp_gain_pc(CHAR_DATA * ch) { int result = 1; if (!IS_NPC(ch)) { int max_per_lev = level_exp(ch, GET_LEVEL(ch) + 1) - level_exp(ch, GET_LEVEL(ch) + 0); result = max_per_lev / (10 + GET_REMORT(ch)); } return result; }
/* Может ли персонаж использовать способность? Проверка по уровню, ремортам, параметрам персонажа, требованиям. */ bool can_use_feat(CHAR_DATA *ch, int feat) { if (!HAVE_FEAT(ch, feat)) return FALSE; if (IS_NPC(ch)) return TRUE; if (NUM_LEV_FEAT(ch) < feat_info[feat].slot[(int) GET_CLASS(ch)][(int) GET_KIN(ch)]) return FALSE; if (GET_REMORT(ch) < feat_info[feat].min_remort[(int) GET_CLASS(ch)][(int) GET_KIN(ch)]) return FALSE; switch (feat) { case WEAPON_FINESSE_FEAT: if (GET_REAL_DEX(ch) < GET_REAL_STR(ch) || GET_REAL_DEX(ch) < 18) return FALSE; break; case PARRY_ARROW_FEAT: if (GET_REAL_DEX(ch) < 16) return FALSE; break; case POWER_ATTACK_FEAT: if (GET_REAL_STR(ch) < 20) return FALSE; break; case GREAT_POWER_ATTACK_FEAT: if (GET_REAL_STR(ch) < 22) return FALSE; break; case AIMING_ATTACK_FEAT: if (GET_REAL_DEX(ch) < 16) return FALSE; break; case GREAT_AIMING_ATTACK_FEAT: if (GET_REAL_DEX(ch) < 18) return FALSE; break; case DOUBLESHOT_FEAT: if (ch->get_skill(SKILL_BOWS) < 40) return FALSE; break; } return TRUE; }
/** * Пересчет статов чара на основании стартовых статов, ремортов и славы. */ void recalculate_stats(CHAR_DATA *ch) { // стартовые статы ch->set_str(ch->get_start_stat(G_STR)); ch->set_dex(ch->get_start_stat(G_DEX)); ch->set_con(ch->get_start_stat(G_CON)); ch->set_int(ch->get_start_stat(G_INT)); ch->set_wis(ch->get_start_stat(G_WIS)); ch->set_cha(ch->get_start_stat(G_CHA)); // морты if (GET_REMORT(ch)) { ch->inc_str(GET_REMORT(ch)); ch->inc_dex(GET_REMORT(ch)); ch->inc_con(GET_REMORT(ch)); ch->inc_wis(GET_REMORT(ch)); ch->inc_int(GET_REMORT(ch)); ch->inc_cha(GET_REMORT(ch)); } // влитая слава Glory::set_stats(ch); GloryConst::set_stats(ch); }
/* Может ли персонаж изучить эту способность? */ bool can_get_feat(CHAR_DATA *ch, int feat) { int i, count = 0; if (feat <= 0 || feat >= MAX_FEATS) { sprintf(buf, "Неверный номер способности (feat=%d, ch=%s) передан в features::can_get_feat!", feat, ch->get_name()); mudlog(buf, BRF, LVL_IMMORT, SYSLOG, TRUE); return FALSE; } /* Доступность по классу, реморту. */ if ((!feat_info[feat].classknow[(int) GET_CLASS(ch)][(int) GET_KIN(ch)] && !PlayerRace::FeatureCheck(GET_KIN(ch),GET_RACE(ch),feat)) || (GET_REMORT(ch) < feat_info[feat].min_remort[(int) GET_CLASS(ch)][(int) GET_KIN(ch)])) return FALSE; /* Наличие свободных слотов */ if (!find_feat_slot(ch, feat)) return FALSE; /* Специальные требования для изучения */ switch (feat) { case PARRY_ARROW_FEAT: if (!ch->get_skill(SKILL_MULTYPARRY) && !ch->get_skill(SKILL_PARRY)) return FALSE; break; case CONNOISEUR_FEAT: if (!ch->get_skill(SKILL_IDENTIFY)) return FALSE; break; case EXORCIST_FEAT: if (!ch->get_skill(SKILL_TURN_UNDEAD)) return FALSE; break; case HEALER_FEAT: if (!ch->get_skill(SKILL_AID)) return FALSE; break; case STEALTHY_FEAT: if (!ch->get_skill(SKILL_HIDE) && !ch->get_skill(SKILL_SNEAK) && !ch->get_skill(SKILL_CAMOUFLAGE)) return FALSE; break; case TRACKER_FEAT: if (!ch->get_skill(SKILL_TRACK) && !ch->get_skill(SKILL_SENSE)) return FALSE; break; case PUNCH_MASTER_FEAT: case CLUBS_MASTER_FEAT: case AXES_MASTER_FEAT: case LONGS_MASTER_FEAT: case SHORTS_MASTER_FEAT: case NONSTANDART_MASTER_FEAT: case BOTHHANDS_MASTER_FEAT: case PICK_MASTER_FEAT: case SPADES_MASTER_FEAT: case BOWS_MASTER_FEAT: if (!HAVE_FEAT(ch, (ubyte) feat_info[feat].affected[1].location)) return FALSE; for (i = PUNCH_MASTER_FEAT; i <= BOWS_MASTER_FEAT; i++) if (HAVE_FEAT(ch, i)) count++; if (count >= 1+GET_REMORT(ch)/7) return FALSE; break; case SPIRIT_WARRIOR_FEAT: if (!HAVE_FEAT(ch, GREAT_FORTITUDE_FEAT)) return FALSE; break; case NIMBLE_FINGERS_FEAT: if (!ch->get_skill(SKILL_STEAL) && !ch->get_skill(SKILL_PICK_LOCK)) return FALSE; break; case GREAT_POWER_ATTACK_FEAT: if (!HAVE_FEAT(ch, POWER_ATTACK_FEAT)) return FALSE; break; case PUNCH_FOCUS_FEAT: case CLUB_FOCUS_FEAT: case AXES_FOCUS_FEAT: case LONGS_FOCUS_FEAT: case SHORTS_FOCUS_FEAT: case NONSTANDART_FOCUS_FEAT: case BOTHHANDS_FOCUS_FEAT: case PICK_FOCUS_FEAT: case SPADES_FOCUS_FEAT: case BOWS_FOCUS_FEAT: if (!ch->get_skill((ubyte) feat_info[feat].affected[0].location)) return FALSE; for (i = PUNCH_FOCUS_FEAT; i <= BOWS_FOCUS_FEAT; i++) if (HAVE_FEAT(ch, i)) count++; if (count >= 2+GET_REMORT(ch)/6) return FALSE; break; case GREAT_AIMING_ATTACK_FEAT: if (!HAVE_FEAT(ch, AIMING_ATTACK_FEAT)) return FALSE; break; case DOUBLESHOT_FEAT: if (!HAVE_FEAT(ch, BOWS_FOCUS_FEAT) || ch->get_skill(SKILL_BOWS) < 40) return FALSE; break; case RUNE_USER_FEAT: if (!HAVE_FEAT(ch, RUNE_NEWBIE_FEAT)) return FALSE; break; case RUNE_MASTER_FEAT: if (!HAVE_FEAT(ch, RUNE_USER_FEAT)) return FALSE; break; case RUNE_ULTIMATE_FEAT: if (!HAVE_FEAT(ch, RUNE_MASTER_FEAT)) return FALSE; break; } return TRUE; }
/** * Проверка стартовых и итоговых статов. * Если невалидные стартовые статы - чар отправляется на реролл. * Если невалидные только итоговые статы - идет перезапись со стартовых с учетом мортов и славы. */ bool check_stats(CHAR_DATA *ch) { // иммов травмировать не стоит if (IS_IMMORTAL(ch)) { return 1; } int have_stats = ch->get_inborn_str() + ch->get_inborn_dex() + ch->get_inborn_int() + ch->get_inborn_wis() + ch->get_inborn_con() + ch->get_inborn_cha(); // чар со старым роллом статов или после попыток поправить статы в файле if (bad_start_stats(ch)) { snprintf(buf, MAX_STRING_LENGTH, "\r\n%sВаши параметры за вычетом перевоплощений:\r\n" "Сила: %d, Ловкость: %d, Ум: %d, Мудрость: %d, Телосложение: %d, Обаяние: %d\r\n" "Если вы долго отсутствовали в игре, то изменения, касающиеся стартовых параметров были следующие:%s\r\n" "\r\n" "\tДобавлено ограничение на максимальный класс защиты:\r\n" "\tВоры, наемники и дружинники - -250\r\n" "\tКупцы, богатыри, витязи, охотники, кузнецы - -200\r\n" "\tЛекари, волхвы - -150\r\n" "\tКудесники, чернокнижники, колдуны, волшебники - -100\r\n" "\r\n" "\tТелосложение: изменились коэффициенты профессий и максимальное родное тело (50) в расчетах при\r\n" "\tполучении уровня, поэтому изменены границы стартового телосложения у некоторых профессий,\r\n" "\tв целом это увеличивает кол-во жизней персонажа тем сильнее, чем больше у него было ремортов.\r\n" "\r\n", CCIGRN(ch, C_SPR), ch->get_inborn_str() - GET_REMORT(ch), ch->get_inborn_dex() - GET_REMORT(ch), ch->get_inborn_int() - GET_REMORT(ch), ch->get_inborn_wis() - GET_REMORT(ch), ch->get_inborn_con() - GET_REMORT(ch), ch->get_inborn_cha() - GET_REMORT(ch), CCNRM(ch, C_SPR)); SEND_TO_Q(buf, ch->desc); // данную фигню мы делаем для того, чтобы из ролла нельзя было случайно так просто выйти // сразу, не раскидав статы, а то много любителей тригов и просто нажатий не глядя ch->set_str(MIN_STR(ch)); ch->set_dex(MIN_DEX(ch)); ch->set_int(MIN_INT(ch)); ch->set_wis(MIN_WIS(ch)); ch->set_con(MIN_CON(ch)); ch->set_cha(MIN_CHA(ch)); snprintf(buf, MAX_STRING_LENGTH, "%sПросим вас заново распределить основные параметры персонажа.%s\r\n", CCIGRN(ch, C_SPR), CCNRM(ch, C_SPR)); SEND_TO_Q(buf, ch->desc); SEND_TO_Q("\r\n* В связи с проблемами перевода фразы ANYKEY нажмите ENTER *", ch->desc); STATE(ch->desc) = CON_RESET_STATS; return 0; } // стартовые статы в поряде, но слава не сходится (снялась по времени или иммом) if (bad_real_stats(ch, have_stats)) { recalculate_stats(ch); } return 1; }
void gain_exp(CHAR_DATA * ch, int gain) { int is_altered = FALSE; int num_levels = 0; char buf[128]; if (IS_NPC(ch)) { ch->set_exp(ch->get_exp() + gain); return; } else { ch->dps_add_exp(gain); ZoneExpStat::add(zone_table[world[IN_ROOM(ch)]->zone].number, gain); } if (!IS_NPC(ch) && ((GET_LEVEL(ch) < 1 || GET_LEVEL(ch) >= LVL_IMMORT))) return; if (gain > 0 && GET_LEVEL(ch) < LVL_IMMORT) { gain = MIN(max_exp_gain_pc(ch), gain); // put a cap on the max gain per kill ch->set_exp(ch->get_exp() + gain); if (GET_EXP(ch) >= level_exp(ch, LVL_IMMORT)) { if (!GET_GOD_FLAG(ch, GF_REMORT) && GET_REMORT(ch) < MAX_REMORT) { if (Remort::can_remort_now(ch)) { send_to_char(ch, "%sПоздравляем, вы получили право на перевоплощение!%s\r\n", CCIGRN(ch, C_NRM), CCNRM(ch, C_NRM)); } else { send_to_char(ch, "%sПоздравляем, вы набрали максимальное количество опыта!\r\n" "%s%s\r\n", CCIGRN(ch, C_NRM), Remort::WHERE_TO_REMORT_STR.c_str(), CCNRM(ch, C_NRM)); } SET_GOD_FLAG(ch, GF_REMORT); } } ch->set_exp(MIN(GET_EXP(ch), level_exp(ch, LVL_IMMORT) - 1)); while (GET_LEVEL(ch) < LVL_IMMORT && GET_EXP(ch) >= level_exp(ch, GET_LEVEL(ch) + 1)) { ch->set_level(ch->get_level() + 1); num_levels++; sprintf(buf, "%sВы достигли следующего уровня!%s\r\n", CCWHT(ch, C_NRM), CCNRM(ch, C_NRM)); send_to_char(buf, ch); advance_level(ch); is_altered = TRUE; } if (is_altered) { sprintf(buf, "%s advanced %d level%s to level %d.", GET_NAME(ch), num_levels, num_levels == 1 ? "" : "s", GET_LEVEL(ch)); mudlog(buf, BRF, LVL_IMPL, SYSLOG, TRUE); } } else if (gain < 0 && GET_LEVEL(ch) < LVL_IMMORT) { gain = MAX(-max_exp_loss_pc(ch), gain); // Cap max exp lost per death ch->set_exp(ch->get_exp() + gain); while (GET_LEVEL(ch) > 1 && GET_EXP(ch) < level_exp(ch, GET_LEVEL(ch))) { ch->set_level(ch->get_level() - 1); num_levels++; sprintf(buf, "%sВы потеряли уровень. Вам должно быть стыдно!%s\r\n", CCIRED(ch, C_NRM), CCNRM(ch, C_NRM)); send_to_char(buf, ch); decrease_level(ch); is_altered = TRUE; } if (is_altered) { sprintf(buf, "%s decreases %d level%s to level %d.", GET_NAME(ch), num_levels, num_levels == 1 ? "" : "s", GET_LEVEL(ch)); mudlog(buf, BRF, LVL_IMPL, SYSLOG, TRUE); } } if ((GET_EXP(ch) < level_exp(ch, LVL_IMMORT) - 1) && GET_GOD_FLAG(ch, GF_REMORT) && gain && (GET_LEVEL(ch) < LVL_IMMORT)) { if (Remort::can_remort_now(ch)) { send_to_char(ch, "%sВы потеряли право на перевоплощение!%s\r\n", CCIRED(ch, C_NRM), CCNRM(ch, C_NRM)); } CLR_GOD_FLAG(ch, GF_REMORT); } char_stat::add_class_exp(GET_CLASS(ch), gain); update_clan_exp(ch, gain); }