====================== Weapon Proficiencies ====================== by Fabrizio Baldi (baldif@tin.it) This piece of code implements a rudimental weapon proficiencies system for warriors. I got the idea from the Smaug codebase, but i wrote all this code on my own. I haven't made a patch of it because I have already modified beyond this code so I can not do a patch directly. I hope I haven't forgot anything. :-) I also hope you'll be able to read my english. *** (quoted disclaimer from Mr. Karl N. Matthias) :-)) *** You can do whatever you want with this code as long as my copyright notice remains in place. Giving me credit on your mud would be nice, but is not necessary if you don't. If you use it, drop me a note to let me know. If you find bugs or nasties, let me know that, too! But you are on your own in installing this. If it completely junks your Mud, it's not my fault. You have been warned. If you're not a coder, get one to add this for you: it's simple, but not THAT simple. *** (end of quoted disclaimer from Mr. Karl N. Matthias) :-)) *** With weapon proficiencies, warriors gain bonuses to hitrolls and damrolls. In addition, when they reach a good knowledge of the skill (80% circa), they get bonus to AC and gain additionals attacks (up to 4 for 100%, when a charcter become a Master). On the other side, if a warrior fight with a weapon he doesn't know, instead of bonuses he gets penalities!! *** STRUCTS.H *** Somewhere near the end of file, add: +#define PROF_LVL_START 3 + +struct weapon_prof_data { + sh_int to_hit; + sh_int to_dam; + sh_int to_ac; + sh_int num_of_attacks; +}; This is the base structure for weapon proficiencies system. The PROF_LVL_START define is the minimum character level for practicing the skills (see below in CLASS.C). You may change the level to set the proper value you feel right for your Mud. It is used in get_weapon_prof() function to test if a character could have learned a weapon prof or not. *** CONSTANTS.C *** Wherever you want, insert: +const struct weapon_prof_data wpn_prof[] = { + { 0, 0, 0, 0}, /* not warriors or level < PROF_LVL_START */ + { 1, 0, 0, 0}, /* prof <= 20 */ + { 2, 1, 0, 0}, /* prof <= 40 */ + { 3, 2, 0, 0}, /* prof <= 60 */ + { 4, 3, 0, 1}, /* prof <= 80 */ + { 5, 4, -1, 2}, /* prof <= 85 */ + { 6, 5, -2, 2}, /* prof <= 90 */ + { 7, 6, -3, 3}, /* prof <= 95 */ + { 8, 7, -4, 3}, /* prof <= 99 */ + { 9, 9, -5, 4}, /* prof == 100 */ + {-2, -2, 0, 0} /* prof == 0 */ +}; Remember that in stock Circle 80% is considered the learned level for warriors' skills. That's not true in my mud. I have made deep modifications to the stock practice system so every class reach the 100% of knowledge in a skill, but character cannot reach the maximum knowledge simply practicing it, and that each skill require different number of practices (weapon proficiencies require 3 pracs each). Beyond a certain level of knowledge (usually 80%), for these skills you must find special trainers in the land, and some trainers want special items and/or a lot of gold to train someone (in my mud it will cost a total of about 2.000.000 gold coins, spent among three different trainers, plus seven special items, to become a Master). Penalities when fighting with a weapon a warrior is not skilled with is, for me, absolutely right. Fighting styles are strongly linked with the weapon used, and a warrior used to battle with a long sword CANNOT use effectively, for example, a warhammer or a battle axe without any train. He'll find himself in serious troubles, and then he MUST have penalities. In the end, adjust the values in table in the way you feel right for your Mud. *** SPELLS.H *** Add these defines at end of your current skills declarations: +/* weapon proficiencies */ +#define SKILL_WEAPON_SWORDS 160 +#define SKILL_WEAPON_DAGGERS 161 +#define SKILL_WEAPON_WHIPS 162 +#define SKILL_WEAPON_TALONOUS_ARMS 163 +#define SKILL_WEAPON_BLUDGEONS 164 +#define SKILL_WEAPON_EXOTICS 165 Remember to change the numbers to match the correct declaration values. *** SPELL_PARSER.C *** Add these lines after other skillo() declarations, at end of void mag_assign_spells(void): + skillo(SKILL_WEAPON_SWORDS, "swords"); + skillo(SKILL_WEAPON_DAGGERS, "daggers"); + skillo(SKILL_WEAPON_WHIPS, "whips"); + skillo(SKILL_WEAPON_TALONOUS_ARMS, "talonous arms"); + skillo(SKILL_WEAPON_BLUDGEONS, "bludgeons"); + skillo(SKILL_WEAPON_EXOTICS, "exotics"); *** CLASS.C *** Add these lines in warrior skills assignement section, in init_spell_levels(): + spell_level(SKILL_WEAPON_SWORDS, CLASS_WARRIOR, PROF_LVL_START); + spell_level(SKILL_WEAPON_DAGGERS, CLASS_WARRIOR, PROF_LVL_START); + spell_level(SKILL_WEAPON_WHIPS, CLASS_WARRIOR, PROF_LVL_START); + spell_level(SKILL_WEAPON_TALONOUS_ARMS, CLASS_WARRIOR, PROF_LVL_START); + spell_level(SKILL_WEAPON_BLUDGEONS, CLASS_WARRIOR, PROF_LVL_START); + spell_level(SKILL_WEAPON_EXOTICS, CLASS_WARRIOR, PROF_LVL_START); *** FIGHT.C *** In this file are concentrated the major changes. First, prototype the profs table: extern struct str_app_type str_app[]; extern struct dex_app_type dex_app[]; +extern const struct weapon_prof_data wpn_prof[]; extern struct room_data *world; Then, insert prototype for the get_weapon_prof() function: int compute_armor_class(struct char_data *ch); int compute_thaco(struct char_data *ch); +int get_weapon_prof(struct char_data *ch, struct obj_data *wield); In compute_armor_class(), insert the lines marked with + int compute_armor_class(struct char_data *ch) { + struct obj_data *wielded = GET_EQ(ch, WEAR_WIELD); int armorclass = GET_AC(ch); if (AWAKE(ch)) armorclass += dex_app[GET_DEX(ch)].defensive * 10; + if (!IS_NPC(ch)) + if (wielded && GET_OBJ_TYPE(wielded) == ITEM_WEAPON) + armorclass += wpn_prof[get_weapon_prof(ch, wielded)].to_ac * 10; + return (MAX(-100, armorclass)); /* -100 is lowest */ } Add the lines marked with + inside the hit() function: void hit(struct char_data * ch, struct char_data * victim, int type) { struct obj_data *wielded = GET_EQ(ch, WEAR_WIELD); int w_type, victim_ac, calc_thaco, dam, diceroll; + int wpnprof; (....) /* Find the weapon type (for display purposes only) */ if (wielded && GET_OBJ_TYPE(wielded) == ITEM_WEAPON) w_type = GET_OBJ_VAL(wielded, 3) + TYPE_HIT; else { if (IS_NPC(ch) && (ch->mob_specials.attack_type != 0)) w_type = ch->mob_specials.attack_type + TYPE_HIT; else w_type = TYPE_HIT; } + /* Weapon proficiencies */ + if (!IS_NPC(ch) && wielded && GET_OBJ_TYPE(wielded) == ITEM_WEAPON) + wpnprof = get_weapon_prof(ch, wielded); + else + wpnprof = 0; + /* Calculate the THAC0 of the attacker */ if (!IS_NPC(ch)) calc_thaco = thaco((int) GET_CLASS(ch), (int) GET_LEVEL(ch)); else /* THAC0 for monsters is set in the HitRoll */ calc_thaco = 20; calc_thaco -= str_app[STRENGTH_APPLY_INDEX(ch)].tohit; calc_thaco -= GET_HITROLL(ch); + calc_thaco -= wpn_prof[wpnprof].to_hit; calc_thaco -= (int) ((GET_INT(ch) - 13) / 1.5); /* Intelligence helps! */ calc_thaco -= (int) ((GET_WIS(ch) - 13) / 1.5); /* So does wisdom */ (....) /* Maybe holding arrow? */ if (wielded && GET_OBJ_TYPE(wielded) == ITEM_WEAPON) { /* Add weapon-based damage if a weapon is being wielded */ dam += dice(GET_OBJ_VAL(wielded, 1), GET_OBJ_VAL(wielded, 2)); + dam += wpn_prof[wpnprof].to_dam; } else { /* If no weapon, add bare hand damage instead */ if (IS_NPC(ch)) { dam += dice(ch->mob_specials.damnodice, ch->mob_specials.damsizedice); } else { dam += number(0, 2); /* Max 2 bare hand damage for players */ } } Add the lines marked with + inside the perform_violence() function: void perform_violence(void) { struct char_data *ch; + struct obj_data *wielded; + sh_int num_of_attacks = 1, loop_attacks; (...) if (GET_POS(ch) < POS_FIGHTING) { send_to_char("You can't fight while sitting!!\r\n", ch); continue; } + /* reset to 1 attack */ + num_of_attacks = 1; + + if (!IS_NPC(ch)) { + wielded = GET_EQ(ch, WEAR_WIELD); + if (wielded && GET_OBJ_TYPE(wielded) == ITEM_WEAPON) + num_of_attacks += wpn_prof[get_weapon_prof(ch, wielded)].num_of_attacks; + } else { + /* have to implement a better way for number of attacks for mobs */ + num_of_attacks += ((int) GET_LEVEL(ch) / 10) - 1; + } + + for (loop_attacks = 0; loop_attacks < num_of_attacks && ch && FIGHTING(ch); loop_attacks++) --> hit(ch, FIGHTING(ch), TYPE_UNDEFINED); <-- the call to hit() function is automatically inserted into the for cycle.. just indent it :-) -------------------------------------------------------------------- This is the heart function of the weapon profs system. I have placed it at the end of fight.c, but you can put anywhere you want. +/* Weapon Proficiecies -- (C) 1999 by Fabrizio Baldi */ +int get_weapon_prof(struct char_data *ch, struct obj_data *wield) +{ + int value = 0, bonus = 0, learned = 0, type = -1; + + /* No mobs here */ + if (IS_NPC(ch)) + return (bonus); + + /* Only current class warriors gain bonuses */ + if (GET_CLASS(ch) != CLASS_WARRIOR) + return (bonus); + + /* Check for proficiencies only if characters could have learned it */ + if (GET_LEVEL(ch) < PROF_LVL_START) + return (bonus); + + value = GET_OBJ_VAL(wield, 3) + TYPE_HIT; + switch (value) { + case TYPE_SLASH: + type = SKILL_WEAPON_SWORDS; + break; + + case TYPE_STING: + case TYPE_PIERCE: + case TYPE_STAB: + type = SKILL_WEAPON_DAGGERS; + break; + + case TYPE_THRASH: + case TYPE_WHIP: + type = SKILL_WEAPON_WHIPS; + break; + + case TYPE_CLAW: + type = SKILL_WEAPON_TALONOUS_ARMS; + break; + + case TYPE_BLUDGEON: + case TYPE_MAUL: + case TYPE_POUND: + case TYPE_CRUSH: + type = SKILL_WEAPON_BLUDGEONS; + break; + + case TYPE_HIT: + case TYPE_PUNCH: + case TYPE_BITE: + case TYPE_BLAST: + type = SKILL_WEAPON_EXOTICS; + break; + + default: + type = -1; + break; + } + + if (type != -1) { + learned = GET_SKILL(ch, type); + if (learned == 0) + /* + * warriors are less effective with weapons that they don't know + * and have penalities to hitroll & damroll (-2 & -2) + */ + bonus = 10; + else if (learned <= 20) + bonus = 1; + else if (learned <= 40) + bonus = 2; + else if (learned <= 60) + bonus = 3; + else if (learned <= 80) + bonus = 4; + else if (learned <= 85) + bonus = 5; + else if (learned <= 90) + bonus = 6; + else if (learned <= 95) + bonus = 7; + else if (learned <= 99) + bonus = 8; + else + bonus = 9; + } + return (bonus); +} -------------------------------------- That's all. I have tested it only under Win98, but should work with no probs under other platforms. Anyway, if you experience problems with this code email me and I will try to help you. If you find bugs or nasties, please let me know! Have fun. FB "There is always ONE MORE bug." -- Murphy