/* * $Id: skill_info.c 1019 2007-02-15 00:52:41Z zsuzsu $ */ /*************************************************************************** * ANATOLIA 2.1 is copyright 1996-1997 Serdar BULUT, Ibrahim CANPUNAR * * ANATOLIA has been brought to you by ANATOLIA consortium * * Serdar BULUT {Chronos} bulut@rorqual.cc.metu.edu.tr * * Ibrahim Canpunar {Asena} canpunar@rorqual.cc.metu.edu.tr * * Murat BICER {KIO} mbicer@rorqual.cc.metu.edu.tr * * D.Baris ACAR {Powerman} dbacar@rorqual.cc.metu.edu.tr * * By using this code, you have agreed to follow the terms of the * * ANATOLIA license, in the file Anatolia/anatolia.licence * ***************************************************************************/ /*************************************************************************** * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. * * * * Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael * * Chastain, Michael Quan, and Mitchell Tse. * * * * In order to use any part of this Merc Diku Mud, you must comply with * * both the original Diku license in 'license.doc' as well the Merc * * license in 'license.txt'. In particular, you may not remove either of * * these copyright notices. * * * * Much time and thought has gone into this software and you are * * benefitting. We hope that you share your changes too. What goes * * around, comes around. * ***************************************************************************/ /*************************************************************************** * ROM 2.4 is copyright 1993-1995 Russ Taylor * * ROM has been brought to you by the ROM consortium * * Russ Taylor (rtaylor@pacinfo.com) * * Gabrielle Taylor (gtaylor@pacinfo.com) * * Brian Moore (rom@rom.efn.org) * * By using this code, you have agreed to follow the terms of the * * ROM license, in the file Rom24/doc/rom.license * ***************************************************************************/ #include <sys/types.h> #include <sys/time.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include "merc.h" #include "update.h" #include "magic.h" #include "stats.h" #include "debug.h" extern int gsn_anathema; varr skills = { sizeof(skill_t), 8 }; /* command procedures needed */ DECLARE_DO_FUN(do_help ); DECLARE_DO_FUN(do_say ); int ch_skill_nok (CHAR_DATA *ch , int sn); /* used to converter of prac and train */ void do_gain(CHAR_DATA *ch, const char *argument) { char arg[MAX_INPUT_LENGTH]; CHAR_DATA *tr; if (IS_NPC(ch)) return; /* find a trainer */ for (tr = ch->in_room->people; tr; tr = tr->next_in_room) if (IS_NPC(tr) && IS_SET(tr->pIndexData->act, ACT_PRACTICE | ACT_TRAIN | ACT_GAIN)) break; if (tr == NULL || !can_see(ch, tr)) { char_puts("You can't do that here.\n",ch); return; } one_argument(argument, arg, sizeof(arg)); if (arg[0] == '\0') { do_say(tr, "You may convert 10 practices into 1 train."); do_say(tr, "You may revert 1 train into 10 practices."); do_say(tr, "Simply type 'gain convert' or 'gain revert'."); return; } if (!str_prefix(arg, "revert")) { if (ch->train < 1) { do_tell_raw(tr, ch, "You are not yet ready."); return; } act("$N helps you apply your training to practice", ch, NULL, tr, TO_CHAR); ch->practice += 10; ch->train -=1 ; return; } if (!str_prefix(arg, "convert")) { if (ch->practice < 10) { do_tell_raw(tr, ch, "You are not yet ready."); return; } act("$N helps you apply your practice to training", ch, NULL, tr, TO_CHAR); ch->practice -= 10; ch->train +=1 ; return; } do_tell_raw(tr, ch, "I do not understand..."); } /* RT spells and skills show the players spells (or skills) */ void do_spells(CHAR_DATA *ch, const char *argument) { char spell_list[LEVEL_IMMORTAL+1][MAX_STRING_LENGTH]; char spell_columns[LEVEL_IMMORTAL+1]; int lev; int i, j, min; bool found = FALSE; char buf[MAX_STRING_LENGTH]; char buf2[MAX_STRING_LENGTH]; BUFFER *output; if (IS_NPC(ch)) return; /* initialize data */ for (lev = 0; lev <= LEVEL_IMMORTAL; lev++) { spell_columns[lev] = 0; spell_list[lev][0] = '\0'; } for (i = 0; i < ch->pcdata->learned.nused; i++) { pcskill_t *ps = VARR_GET(&ch->pcdata->learned, i); skill_t *sk; if (ps->percent == 0 || (sk = skill_lookup(ps->sn)) == NULL || sk->spell_fun == NULL) continue; found = TRUE; lev = skill_level(ch, ps->sn); if (lev > (IS_IMMORTAL(ch) ? LEVEL_IMMORTAL : LEVEL_HERO)) continue; if (ch->level < lev) snprintf(buf, sizeof(buf), "%-17s %-4s ", sk->name, "n/a"); else snprintf(buf, sizeof(buf), "%-17s %4dm ", sk->name, mana_cost(ch, ps->sn)); for (j=0; j < MAX_STATS; j++) { if (j == STAT_LCK) continue; if ((min = skill_min_stat(ch, j, ps->sn)) > 0) { snprintf(buf2, sizeof(buf2), "%s:%3d ", flag_string(stat_names, j), min); strnzcat(buf, sizeof(buf), buf2); } /* if ((min = skill_min_stat(ch, j, ps->sn)) <= 0) snprintf(buf2, sizeof(buf2), "{D%s - ", flag_string(stat_names, j)); else snprintf(buf2, sizeof(buf2), "%s%s %2d ", min > get_curr_stat(ch, j) ? "{r" : "{x", flag_string(stat_names, j), min); strnzcat(buf, sizeof(buf), buf2); */ } strnzcat(buf, sizeof(buf), "{x"); if (spell_list[lev][0] == '\0') snprintf(spell_list[lev], sizeof(spell_list[lev]), "\nLevel %2d: %s", lev, buf); else { /* append */ strnzcat(spell_list[lev], sizeof(spell_list[lev]), "\n "); strnzcat(spell_list[lev], sizeof(spell_list[lev]), buf); } } /* return results */ if (!found) { char_puts("You know no spells.\n",ch); return; } output = buf_new(-1); for (lev = 0; lev <= LEVEL_IMMORTAL; lev++) if (spell_list[lev][0] != '\0') buf_add(output, spell_list[lev]); buf_add(output, "\n"); page_to_char(buf_string(output), ch); buf_free(output); } void do_skills(CHAR_DATA *ch, const char *argument) { char skill_list[LEVEL_IMMORTAL+1][MAX_STRING_LENGTH]; char skill_columns[LEVEL_IMMORTAL+1]; int lev; int i, j, min; bool found = FALSE; char buf[MAX_STRING_LENGTH]; char buf2[MAX_STRING_LENGTH]; BUFFER *output; if (IS_NPC(ch)) return; /* initialize data */ for (lev = 0; lev <= LEVEL_IMMORTAL; lev++) { skill_columns[lev] = 0; skill_list[lev][0] = '\0'; } for (i = 0; i < ch->pcdata->learned.nused; i++) { pcskill_t *ps = VARR_GET(&ch->pcdata->learned, i); skill_t *sk; if (ps->percent == 0 || (sk = skill_lookup(ps->sn)) == NULL || sk->spell_fun) continue; found = TRUE; lev = skill_level(ch, ps->sn); if (lev > (IS_IMMORTAL(ch) ? LEVEL_IMMORTAL : LEVEL_HERO)) continue; snprintf(buf, sizeof(buf), ch->level < lev ? "%-17s n/a " : "%-17s %3d%% ", sk->name, ps->percent); for (j=0; j < MAX_STATS; j++) { if (j == STAT_LCK) continue; if ((min = skill_min_stat(ch, j, ps->sn)) > 0) { snprintf(buf2, sizeof(buf2), "%s:%3d ", flag_string(stat_names, j), min); strnzcat(buf, sizeof(buf), buf2); } /* if ((min = skill_min_stat(ch, j, ps->sn)) <= 0) snprintf(buf2, sizeof(buf2), "{D%s - ", flag_string(stat_names, j)); else snprintf(buf2, sizeof(buf2), "%s%s %2d ", min > get_curr_stat(ch, j) ? "{r" : "{x", flag_string(stat_names, j), min); strnzcat(buf, sizeof(buf), buf2); */ } strnzcat(buf, sizeof(buf), "{x"); if (skill_list[lev][0] == '\0') snprintf(skill_list[lev], sizeof(skill_list[lev]), "\nLevel %2d: %s", lev, buf); else { /* append */ strnzcat(skill_list[lev], sizeof(skill_list[lev]), "\n "); strnzcat(skill_list[lev], sizeof(skill_list[lev]), buf); } } /* return results */ if (!found) { char_puts("You know no skills.\n",ch); return; } output = buf_new(-1); for (lev = 0; lev <= LEVEL_IMMORTAL; lev++) if (skill_list[lev][0] != '\0') buf_add(output, skill_list[lev]); buf_add(output, "\n"); page_to_char(buf_string(output), ch); buf_free(output); } int base_exp(CHAR_DATA *ch) { int expl; class_t *cl; race_t *r; rclass_t *rcl; if (IS_NPC(ch) || (cl = class_lookup(ch->class)) == NULL || (r = race_lookup(ch->pcdata->race)) == NULL || !r->pcdata || (rcl = rclass_lookup(r, cl->name)) == NULL) return 1500; expl = 1000 + r->pcdata->points + cl->points; return (expl * rcl->mult/100) * 150/100; } int exp_for_level(CHAR_DATA *ch, int level) { int i = base_exp(ch) * level; return i + i * (level-1) / 20; } int exp_to_level(CHAR_DATA *ch) { return exp_for_level(ch, ch->level+1) - ch->exp; } /* checks for skill improvement */ void check_improve(CHAR_DATA *ch, int sn, bool success, int multiplier) { pcskill_t *ps; class_t *cl; cskill_t *cs; int chance; int rating; int curve; int curve2; if (IS_NPC(ch) || ch->in_room == NULL || (cl = class_lookup(ch->class)) == NULL || (ps = pcskill_lookup(ch, sn)) == NULL || ps->percent == 0 || ps->percent == 100 || skill_level(ch, sn) > ch->level) return; /* can't improve skills while dishonored */ if (is_affected(ch, gsn_dishonor)) return; /* can't improve in the arena */ if (IS_SET(ch->in_room->room_flags, ROOM_BATTLE_ARENA)) return; if ((cs = cskill_lookup(cl, sn))) rating = cs->rating; else rating = 1; /* check to see if the character has a chance to learn */ chance = 10 * ch_learn_rate(ch); chance /= (multiplier * rating * 4); chance += ch->level; if (number_range(1, 2000) > chance) return; /* harder to master a skill if you just learned it */ curve = skill_level(ch, ps->sn) + 5 - ch->level; /* harder to master as kill as you get better at it */ curve2 = (ps->percent-70) / 5; curve = (curve < curve2) ? curve : curve2; if (curve > 0 && number_range(1, 1000 * curve)) return; /* now that the character has a CHANCE to learn, see if they really have */ if (success) { chance = URANGE(2, 100 - ps->percent, 50); if (number_percent() < chance) { ps->percent++; gain_exp(ch, number_range(25, 75)); if (ps->percent == 100) char_printf(ch, "{gYou mastered {W%s{g!{x\n", skill_name(sn)); else char_printf(ch, "{gYou have become better at {W%s{g!{x\n", skill_name(sn)); } } else { chance = URANGE(2, ps->percent / 2, 30); if (number_percent() < chance) { if ((ps->percent += number_range(1, 3)) > 100) ps->percent = 100; if (ps->percent == 100) char_printf(ch, "{gYou learn from your mistakes and you manage to master {W%s{g!{x\n", skill_name(sn)); else char_printf(ch, "{gYou learn from your mistakes and your {W%s{g skill improves!{x\n", skill_name(sn)); } } } /* * simply adds sn to ch's known skills (if skill is not already known). */ void set_skill_raw(CHAR_DATA *ch, int sn, int percent, bool replace) { pcskill_t *ps; if (sn <= 0) return; if ((ps = pcskill_lookup(ch, sn))) { if (replace || ps->percent < percent) ps->percent = percent; return; } ps = varr_enew(&ch->pcdata->learned); ps->sn = sn; ps->percent = percent; varr_qsort(&ch->pcdata->learned, cmpint); } /* use for adding/updating all skills available for that ch */ void update_skills(CHAR_DATA *ch) { int i; class_t *cl; race_t *r; clan_t *clan; const char *p; /* NPCs do not have skills */ if (IS_NPC(ch) || (cl = class_lookup(ch->class)) == NULL || (r = race_lookup(ch->race)) == NULL || !r->pcdata) return; /* add class skills */ for (i = 0; i < cl->skills.nused; i++) { cskill_t *cs = VARR_GET(&cl->skills, i); set_skill_raw(ch, cs->sn, 1, FALSE); } /* add race skills */ for (i = 0; i < r->pcdata->skills.nused; i++) { rskill_t *rs = VARR_GET(&r->pcdata->skills, i); set_skill_raw(ch, rs->sn, 100, FALSE); } if ((p = r->pcdata->bonus_skills)) for (;;) { int sn; char name[MAX_STRING_LENGTH]; p = one_argument(p, name, sizeof(name)); if (name[0] == '\0') break; sn = sn_lookup(name); if (sn < 0) continue; set_skill_raw(ch, sn, 100, FALSE); } /* add clan skills */ if ((clan = clan_lookup(ch->clan))) { for (i = 0; i < clan->skills.nused; i++) { clskill_t *cs = VARR_GET(&clan->skills, i); set_skill_raw(ch, cs->sn, cs->percent, FALSE); } } /* remove not matched skills */ for (i = 0; i < ch->pcdata->learned.nused; i++) { pcskill_t *ps = VARR_GET(&ch->pcdata->learned, i); if (skill_level(ch, ps->sn) > LEVEL_HERO && !IS_IMMORTAL(ch)) ps->percent = 0; } } void set_skill(CHAR_DATA *ch, int sn, int percent) { set_skill_raw(ch, sn, percent, TRUE); } DO_FUN(do_glist) { char arg[MAX_INPUT_LENGTH]; int col = 0; flag64_t group = GROUP_NONE; int sn; one_argument(argument, arg, sizeof(arg)); if (arg[0] == '\0') { char_puts("Syntax: glist group\n" "Use 'glist ?' to get the list of groups.\n", ch); return; } if (!str_cmp(arg, "?")) { show_flags(ch, skill_groups); return; } if (str_prefix(arg, "none") && (group = flag_value(skill_groups, arg)) == 0) { char_puts("That is not a valid group.\n", ch); do_glist(ch, str_empty); return; } char_printf(ch, "Now listing group '%s':\n", flag_string(skill_groups, group)); for (sn = 0; sn < skills.nused; sn++) { skill_t *sk = VARR_GET(&skills, sn); if (group == sk->group) { char_printf(ch, "%c%-18s", pcskill_lookup(ch, sn) ? '*' : ' ', sk->name); if (col) char_puts("\n", ch); col = 1 - col; } } if (col) char_puts("\n", ch); } void do_slook(CHAR_DATA *ch, const char *argument) { int sn = -1; char arg[MAX_INPUT_LENGTH]; one_argument(argument, arg, sizeof(arg)); if (arg[0] == '\0') { char_puts("Syntax : slook <skill | spell>\n",ch); return; } /* search in known skills first */ if (!IS_NPC(ch)) { pcskill_t *ps; ps = (pcskill_t*) skill_vlookup(&ch->pcdata->learned, arg); if (ps) sn = ps->sn; } /* search in all skills */ if (sn < 0) sn = sn_lookup(arg); if (sn < 0) { char_puts("That is not a spell or skill.\n",ch); return; } char_printf(ch, "Skill '%s' in group '%s'.\n", SKILL(sn)->name, flag_string(skill_groups, SKILL(sn)->group)); } void do_learn(CHAR_DATA *ch, const char *argument) { char arg[MAX_INPUT_LENGTH]; int sn; CHAR_DATA *practicer; int adept; class_t *cl; cskill_t *cs; pcskill_t *ps; skill_t *sk; int rating; if (IS_NPC(ch) || (cl = class_lookup(ch->class)) == NULL) return; if (!IS_AWAKE(ch)) { char_puts("In your dreams, or what?\n", ch); return; } if (argument[0] == '\0') { char_puts("Syntax: learn <skill | spell> <player>\n", ch); return; } if (ch->practice <= 0) { char_puts("You have no practice sessions left.\n", ch); return; } argument = one_argument(argument, arg, sizeof(arg)); ps = (pcskill_t*) skill_vlookup(&ch->pcdata->learned, arg); if (!ps || get_skill(ch, sn = ps->sn) == 0) { char_puts("You can't learn that.\n", ch); return; } if (sn == gsn_vampire) { char_puts("You can't practice that, only available " "at questor.\n", ch); return; } argument = one_argument(argument, arg, sizeof(arg)); if ((practicer = get_char_room(ch,arg)) == NULL) { char_puts("Your hero is not here.\n", ch); return; } if (IS_NPC(practicer) || practicer->level != HERO) { char_puts("You must find a hero, not an ordinary one.\n", ch); return; } if (!IS_SET(practicer->conf_flags, PLR_CONF_PRACTICER)) { char_puts("Your hero doesn't want to teach you anything.\n",ch); return; } if (get_skill(practicer, sn) < 100) { char_puts("Your hero doesn't know that skill enough to teach you.\n",ch); return; } sk = SKILL(sn); adept = cl->skill_adept; if (ps->percent >= adept) { char_printf(ch, "You are already learned at %s.\n", sk->name); return; } ch->practice--; cs = cskill_lookup(cl, sn); rating = cs ? UMAX(cs->rating, 1) : 1; ps->percent += ch_learn_rate(ch) / rating; act("You teach $T.", practicer, NULL, sk->name, TO_CHAR); act("$n teaches $T.", practicer, NULL, sk->name, TO_ROOM); REMOVE_BIT(practicer->conf_flags, PLR_CONF_PRACTICER); if (ps->percent < adept) { act("You learn $T.", ch, NULL, sk->name, TO_CHAR); act("$n learn $T.", ch, NULL, sk->name, TO_ROOM); } else { ps->percent = adept; act("You are now learned at $T.", ch, NULL, sk->name, TO_CHAR); act("$n is now learned at $T.", ch, NULL, sk->name, TO_ROOM); } } void do_teach(CHAR_DATA *ch, const char *argument) { if (IS_NPC(ch) || ch->level != LEVEL_HERO) { char_puts("You must be a hero.\n",ch); return; } SET_BIT(ch->conf_flags, PLR_CONF_PRACTICER); char_puts("Now, you can teach youngsters your 100% skills.\n",ch); } void show_skills(CHAR_DATA *ch, CHAR_DATA *victim) { BUFFER *output; pcskill_t *ps; skill_t *sk; int col = 0; int i; output = buf_new(-1); for (i = 0; i < victim->pcdata->learned.nused; i++) { ps = VARR_GET(&victim->pcdata->learned, i); if (ps->percent == 0 || (sk = skill_lookup(ps->sn)) == NULL || skill_level(victim, ps->sn) > victim->level) continue; buf_printf(output, "%s%-19s %3d%%%s ", (ps->percent >= 100) ? "{W" : (ps->percent <= 1) ? "{D" : "", sk->name, ps->percent, (ps->percent >= 100) ? "{x" : (ps->percent <= 1) ? "{x" : "" ); if (++col % 3 == 0) buf_add(output, "\n"); } if (col % 3) buf_add(output, "\n"); if (ch == victim) buf_printf(output, "You have %d practice sessions left.\n", victim->practice); page_to_char(buf_string(output), ch); buf_free(output); } /* new practice */ void do_practice(CHAR_DATA *ch, const char *argument) { CHAR_DATA *mob; int sn; skill_t *sk; pcskill_t *ps; class_t *cl; cskill_t *cs; int adept; bool found; int rating; char arg[MAX_STRING_LENGTH]; if (IS_NPC(ch)) return; if (argument[0] == '\0') { show_skills(ch, ch); return; } if ((cl = CLASS(ch->class)) == NULL) { BUG("do_practice: %s: class %d: unknown", ch->name, ch->class); return; } if (ch->practice <= 0) { char_puts("You have no practice sessions left.\n", ch); return; } if (is_affected(ch, gsn_dishonor)) { char_puts("The guild master refuses to teach new skills to" " someone with such little honor.\n", ch); return; } one_argument(argument, arg, sizeof(arg)); ps = (pcskill_t*) skill_vlookup(&ch->pcdata->learned, arg); if (ps && !ch_skill_stats_ok(ch, sn)) { char_puts("You are unfit to learn that.\n", ch); return; } if (!ps || get_skill(ch, sn = ps->sn) == 0) { char_puts("You can't practice that.\n", ch); return; } if (sn == gsn_vampire) { char_puts("You can't practice that, only available " "at questor.\n", ch); return; } found = FALSE; sk = SKILL(sn); if (IS_SET(sk->flags, SKILL_UNTRAINABLE)) { char_puts("You can only learn that skill through experience.", ch); return; } for (mob = ch->in_room->people; mob != NULL; mob = mob->next_in_room) { if (!IS_NPC(mob) || !IS_SET(mob->pIndexData->act, ACT_PRACTICE)) continue; found = TRUE; if (IS_SET(sk->flags, SKILL_CLAN)) { if (ch->clan == mob->clan) break; continue; } if ((mob->pIndexData->practicer == 0 && (sk->group == GROUP_NONE || IS_SET(sk->group, GROUP_CREATION | GROUP_HARMFUL | GROUP_PROTECTIVE | GROUP_DETECTION | GROUP_WEATHER))) || IS_SET(mob->pIndexData->practicer, sk->group)) break; } if (mob == NULL) { if (found) char_puts("You can't do that here. " "Use 'slook skill', 'help practice' " "for more info.\n", ch); else char_puts("You couldn't find anyone " "who can teach you.\n", ch); return; } adept = cl->skill_adept; if (ps->percent >= adept) { char_printf(ch, "You are already learned at %s.\n", sk->name); return; } ch->practice--; cs = cskill_lookup(cl, sn); rating = cs ? UMAX(cs->rating, 1) : 1; ps->percent += ch_learn_rate(ch) / rating; if (ps->percent < adept) { act("You practice $T.", ch, NULL, sk->name, TO_CHAR); act("$n practices $T.", ch, NULL, sk->name, TO_ROOM); } else { ps->percent = adept; act("You are now learned at $T.", ch, NULL, sk->name, TO_CHAR); act("$n is now learned at $T.", ch, NULL, sk->name, TO_ROOM); } } const char *skill_name(int sn) { skill_t *sk = varr_get(&skills, sn); if (sk) return sk->name; return "none"; } /* for returning skill information */ int get_skill(CHAR_DATA *ch, int sn) { int skill; skill_t *sk; if ((sk = skill_lookup(sn)) == NULL || (IS_SET(sk->flags, SKILL_CLAN) && (!clan_item_ok(ch->clan) || (!IS_NPC(ch) && ch->clan != 0 && ch->pcdata->clan_status < CLAN_RECRUIT)))) return 0; if (!ch_skill_stats_ok(ch, sn)) return 0; if (!IS_NPC(ch)) { pcskill_t *ps; if ((ps = pcskill_lookup(ch, sn)) == NULL || skill_level(ch, sn) > ch->level) skill = 0; else skill = ps->percent; } else { flag64_t act = ch->pIndexData->act; flag64_t off = ch->pIndexData->off_flags; flag64_t attr = ch->pIndexData->attr_flags; /* mobiles */ if (sk->spell_fun) skill = 40 + 2 * ch->level; else if (sn == gsn_track) skill = 100; else if ((sn == gsn_sneak || sn == gsn_hide || sn == gsn_pick) && IS_SET(act, ACT_THIEF)) skill = ch->level * 2 + 20; else if (sn == gsn_backstab && (IS_SET(act, ACT_THIEF) || IS_SET(off, OFF_BACKSTAB))) skill = ch->level * 2 + 20; else if (sn == gsn_dual_backstab && (IS_SET(act, ACT_THIEF) || IS_SET(off, OFF_BACKSTAB))) skill = ch->level + 20; else if ((sn == gsn_dodge && IS_SET(off, OFF_DODGE)) || (sn == gsn_parry && IS_SET(off, OFF_PARRY)) || (sn == gsn_haft_block && IS_SET(off, OFF_HAFT_BLOCK)) || (sn == gsn_tumble && IS_SET(off, OFF_TUMBLE)) || (sn == gsn_dirt && IS_SET(off, OFF_DIRT_KICK))) skill = ch->level * 2; else if (sn == gsn_shield_block) skill = 10 + 2 * ch->level; else if (sn == gsn_second_attack && (IS_SET(act, ACT_WARRIOR | ACT_THIEF))) skill = 10 + 3 * ch->level; else if (sn == gsn_third_attack && IS_SET(act, ACT_WARRIOR)) skill = 4 * ch->level - 40; else if (sn == gsn_fourth_attack && IS_SET(act, ACT_WARRIOR)) skill = 4 * ch->level - 60; else if (sn == gsn_hand_to_hand) skill = 40 + 2 * ch->level; else if (sn == gsn_trip && IS_SET(off, OFF_TRIP)) skill = 10 + 3 * ch->level; else if ((sn == gsn_bash) && IS_SET(off, OFF_BASH)) skill = 10 + 3 * ch->level; else if ((sn == gsn_bash_door) && IS_SET(attr, MOB_ATTR_BASHES_DOORS)) skill = 10 + 3 * ch->level; else if (sn == gsn_kick && IS_SET(off, OFF_KICK)) skill = 10 + 3 * ch->level; else if ((sn == gsn_critical) && IS_SET(act, ACT_WARRIOR)) skill = ch->level; else if (sn == gsn_disarm && (IS_SET(off, OFF_DISARM) || IS_SET(act, ACT_WARRIOR | ACT_THIEF))) skill = 20 + 3 * ch->level; else if (sn == gsn_grip && (IS_SET(act, ACT_WARRIOR | ACT_THIEF))) skill = ch->level; else if ((sn == gsn_berserk || sn == gsn_tiger_power) && IS_SET(off, OFF_BERSERK)) skill = 3 * ch->level; else if (sn == gsn_kick) skill = 10 + 3 * ch->level; else if (sn == gsn_rescue) skill = 40 + ch->level; else if (sn == gsn_longsword || sn == gsn_dagger || sn == gsn_shortsword || sn == gsn_bastardsword || sn == gsn_spear || sn == gsn_mace || sn == gsn_axe || sn == gsn_flail || sn == gsn_whip || sn == gsn_polearm || sn == gsn_staff || sn == gsn_bow || sn == gsn_arrow || sn == gsn_lance || sn == gsn_hammer || sn == gsn_katana) skill = 40 + 5 * ch->level / 2; else if (sn == gsn_crush && IS_SET(off, OFF_CRUSH)) skill = 10 + 3 * ch->level; else skill = 0; } if (IS_AFFECTED(ch, AFF_CURSE)) { AFFECT_DATA* paf; for (paf = ch->affected; paf; paf=paf->next) { if (paf->type == gsn_anathema && paf->location == APPLY_LEVEL) { skill = skill * 4 / (4-paf->modifier); } } } if (ch->daze > 0) { if (sk->spell_fun) skill /= 2; else skill = 2 * skill / 3; } /*XXX- this needs to be fixed so an infinite loop isn't * called by IS_DRUNK(ch) (because of the drinking skill*/ /* if (!IS_NPC(ch) && ch->pcdata->condition[COND_DRUNK] > 10) skill = 9 * skill / 10; */ skill = URANGE(0, skill, 100); if (skill != 0 && !IS_NPC(ch)) { class_t *cl; cskill_t *csk; if (/*sk->spell_fun == NULL && XXX not sure why this was here */ (cl = class_lookup(ch->class)) != NULL && (csk = cskill_lookup(cl, sn)) != NULL) skill += csk->mod; } return skill; } /* * Lookup a skill by name. */ int sn_lookup(const char *name) { int sn; if (IS_NULLSTR(name)) return -1; for (sn = 0; sn < skills.nused; sn++) if (!str_prefix(name, SKILL(sn)->name)) return sn; return -1; } /* * Lookup skill in varr. * First field of structure assumed to be sn */ void *skill_vlookup(varr *v, const char *name) { int i; if (IS_NULLSTR(name)) return NULL; for (i = 0; i < v->nused; i++) { skill_t *skill; int *psn = (int*) VARR_GET(v, i); if ((skill = skill_lookup(*psn)) && !str_prefix(name, skill->name)) return psn; } return NULL; } /* for returning weapon information */ int get_weapon_sn(OBJ_DATA *wield) { int sn; if (wield == NULL) return gsn_hand_to_hand; if (wield->pIndexData->item_type != ITEM_WEAPON) return 0; switch (wield->value[ITEM_WEAPON_TYPE]) { default : sn = -1; break; case(WEAPON_KATANA): sn = gsn_katana; break; case(WEAPON_LONGSWORD): sn = gsn_longsword; break; case(WEAPON_SHORTSWORD): sn = gsn_shortsword; break; case(WEAPON_BASTARDSWORD): sn = gsn_bastardsword; break; case(WEAPON_DAGGER): sn = gsn_dagger; break; case(WEAPON_SPEAR): sn = gsn_spear; break; case(WEAPON_MACE): sn = gsn_mace; break; case(WEAPON_AXE): sn = gsn_axe; break; case(WEAPON_HAMMER): sn = gsn_hammer; break; case(WEAPON_FLAIL): sn = gsn_flail; break; case(WEAPON_WHIP): sn = gsn_whip; break; case(WEAPON_POLEARM): sn = gsn_polearm; break; case(WEAPON_BOW): sn = gsn_bow; break; case(WEAPON_ARROW): sn = gsn_arrow; break; case(WEAPON_LANCE): sn = gsn_lance; break; case(WEAPON_STAFF): sn = gsn_staff; break; case(WEAPON_SHURIKEN): sn = gsn_shuriken; break; } return sn; } int get_weapon_skill(CHAR_DATA *ch, int sn) { int sk; /* -1 is exotic */ if (sn == -1) sk = 3 * ch->level; else if (!IS_NPC(ch)) sk = get_skill(ch, sn); else if (sn == gsn_hand_to_hand) sk = 40 + 2 * ch->level; else sk = 40 + 5 * ch->level / 2; return URANGE(0, sk, 100); } /* * Utter mystical words for an sn. */ void say_spell(CHAR_DATA *ch, int sn) { char buf [MAX_STRING_LENGTH]; CHAR_DATA *rch; const char *pName; int iSyl; int length; int skill; const char *cast_msg = NULL; struct syl_type { char * old; char * new; }; static const struct syl_type syl_table[] = { { " ", " " }, { "ar", "abra" }, { "au", "kada" }, { "bless", "fido" }, { "blind", "nose" }, { "bur", "mosa" }, { "cu", "judi" }, { "de", "oculo" }, { "en", "unso" }, { "light", "dies" }, { "lo", "hi" }, { "mor", "zak" }, { "move", "sido" }, { "ness", "lacri" }, { "ning", "illa" }, { "per", "duda" }, { "ra", "gru" }, { "fresh", "ima" }, { "re", "candus" }, { "son", "sabru" }, { "tect", "infra" }, { "tri", "cula" }, { "ven", "nofo" }, { "a", "a" }, { "b", "b" }, { "c", "q" }, { "d", "e" }, { "e", "z" }, { "f", "y" }, { "g", "o" }, { "h", "p" }, { "i", "u" }, { "j", "y" }, { "k", "t" }, { "l", "r" }, { "m", "w" }, { "n", "i" }, { "o", "a" }, { "p", "s" }, { "q", "d" }, { "r", "f" }, { "s", "g" }, { "t", "h" }, { "u", "j" }, { "v", "z" }, { "w", "x" }, { "x", "n" }, { "y", "l" }, { "z", "k" }, { str_empty, str_empty } }; buf[0] = '\0'; for (pName = skill_name(sn); *pName != '\0'; pName += length) { for (iSyl = 0; (length = strlen(syl_table[iSyl].old)); iSyl++) { if (!str_prefix(syl_table[iSyl].old, pName)) { strnzcat(buf, sizeof(buf), syl_table[iSyl].new); break; } } if (length == 0) length = 1; } /* set the display message */ switch (cast_type(ch)) { case CAST_COMMUNE: cast_msg = "$n puts $s hands together and breathes, '$t'."; break; case CAST_CHANNEL: cast_msg = "$n relaxes and intones, '$t'."; break; case CAST_CAST: default: cast_msg = "$n utters the words, '$t'."; } for (rch = ch->in_room->people; rch; rch = rch->next_in_room) { if (rch == ch) continue; /* if you cast in the same way * and either have the skill * or have spellcraft * then you should see the proper name of the spell */ skill = (get_skill(rch, sn) * 9) / 10; skill = UMAX(skill, (get_skill(rch, gsn_spell_craft) * 9) / 10); if (IS_SET(rch->conf_flags, PLR_CONF_HOLYLIGHT) || (cast_type(ch) == cast_type(rch) && number_percent() < skill)) { act(cast_msg, ch, skill_name(sn), rch, TO_VICT); check_improve(rch, gsn_spell_craft, TRUE, 1); } else { act(cast_msg, ch, buf, rch, TO_VICT); check_improve(rch, gsn_spell_craft, FALSE, 1); } } } /* find min level of the skill for char */ int skill_level(CHAR_DATA *ch, int sn) { int slevel = LEVEL_IMMORTAL; skill_t *sk = NULL; clan_t *clan; clskill_t *clan_skill; class_t *cl = NULL; cskill_t *class_skill; race_t *r = NULL; rskill_t *race_skill; /* noone can use ill-defined skills */ /* broken chars can't use any skills */ if (IS_NPC(ch) || (sk = skill_lookup(sn)) == NULL || (cl = class_lookup(ch->class)) == NULL || (r = race_lookup(ch->race)) == NULL || !r->pcdata) return slevel; if ((clan = clan_lookup(ch->clan)) && (clan_skill = clskill_lookup(clan, sn))) slevel = UMIN(slevel, clan_skill->level); if ((class_skill = cskill_lookup(cl, sn))) { if (cskill_restricted_ok(ch, class_skill)) { slevel = UMIN(slevel, class_skill->level); if (is_name(sk->name, r->pcdata->bonus_skills)) slevel = UMIN(slevel, 1); } } if ((race_skill = rskill_lookup(r, sn))) slevel = UMIN(slevel, race_skill->level); return slevel; } /* * assumes !IS_NPC(ch) && ch->level >= skill_level(ch, sn) */ int mana_cost(CHAR_DATA *ch, int sn) { skill_t *sk; int mana = 0; if ((sk = skill_lookup(sn)) == NULL) return 0; mana = UMAX(sk->min_mana, 100 / (2 + ch->level - skill_level(ch, sn))); mana = mana * ch_mana_cost_mod(ch) / 100; return mana; } /* * returns the move cost for invoking the skill * mod_stat - is the stat which modifies the skill's cost * multi - is the multiplier for how much the stat modifies the cost * * by Zsuzsu */ int move_cost(CHAR_DATA *ch, int sn, int mod_stat, int multi) { int cost = 0; int min_cost = 0; int stat = 0; skill_t *skill = NULL; skill = SKILL(sn); if (!skill) { bug("move_cost with unknown skill %d", sn); return 0; } cost = skill->move_cost; min_cost = skill->move_cost_min; if (mod_stat < STAT_STR) return cost; stat = get_curr_stat(ch, mod_stat); if (stat > STAT_AVG_MAX) cost = UMAX(min_cost, cost - ((stat - STAT_AVG_MAX)/3 * multi)); else if (stat < STAT_AVG_MIN) cost = UMAX(min_cost, cost + ((STAT_AVG_MAX - stat)/3 * multi)); return cost; } /** * tax the move, and make sure it doesn't go below zero. */ bool tax_move (CHAR_DATA *ch, int cost) { if (ch->move < cost) return FALSE; ch->move -= cost; return TRUE; } /** * for many rogue skills the success depends on how alert the * mark is. This function returns the modifier to the chance of * success due to the vigilance of the victim */ int vigilance_modifier (CHAR_DATA *ch, CHAR_DATA *victim) { int chance = 0; if (IS_DRUNK(victim)) chance += 10; if (!IS_AWAKE(victim)) { chance += 20; return chance; } if (!can_see(victim, ch)) chance += 10; return chance; }