/* This is my take at adding a poisoning ability to an assassin class, with various kinds of specifically tailored poisons. The gsns have to be defined separately in index.h, as INDEX_NUM(gsn_bloodcurse), etc. The actual damage (where applicable) is called in update.c, on void char_update.*/ /*This goes into fight.c, after the check for poison in the weapon */ if (ch->fighting == victim && IsWeaponStat(wield, WEAPON_BLOODCURSE)) { int level; AffectData *poison, af; if ((poison = affect_find(wield->affect_first, gsn_bloodcurse) == NULL)) level = wield->level; else level = poison->level; if (!saves_spell(level, victim, DAM_POISON)) { chprintln(victim, "You feel liquid flame flowing through your veins!"); act("$n is poisoned by the venom on $p.", victim, wield, NULL, TO_ROOM); af.where = TO_AFFECTS; af.type = gsn_bloodcurse; af.level = level * 4; af.duration = level; af.location = APPLY_CON; af.modifier = -10; af.bitvector = AFF_BLOODCURSE; affect_join(victim, &af); } if (poison != NULL) { poison->level = Max(0, poison->level - 1); poison->duration = Max(0, poison->duration - 1); if (poison->level == 0 || poison->duration == 0) act("The poison on $p has worn off.", ch, wield, NULL, TO_CHAR); } } if (ch->fighting == victim && IsWeaponStat(wield, WEAPON_VITRIOL)) { int level; AffectData *poison, af; if ((poison = affect_find(wield->affect_first, gsn_vitriol)) == NULL) level = wield->level; else level = poison->level; pdam = number_range(level, level * ch->level); if (poison != NULL) { poison->level = Max(0, poison->level - 1); poison->duration = Max(0, poison->duration - 1); } act("$n is seared by $p!", victim, wield, NULL, TO_ROOM); act("You scream as $p burns you!", victim, wield, NULL, TO_CHAR); damage(ch, victim, pdam, 0, DAM_ACID, false); } if (ch->fighting == victim && IsWeaponStat(wield, WEAPON_MAGEBANE)) { int level; AffectData *poison, af; if ((poison = affect_find(wield->affect_first, gsn_magebane)) == NULL) level = wield->level; else level = poison->level; if (!saves_spell(level, victim, DAM_POISON)) { chprintln(victim, "You feel poison coursing through your veins."); act("$n is poisoned by the venom on $p.", victim, wield, NULL, TO_ROOM); af.where = TO_AFFECTS; af.type = gsn_magebane; af.level = level * 3; af.duration = level; af.bitvector = AFF_MAGEBANE; af.modifier = -5; af.location = APPLY_INT; affect_join(victim, &af); af.location = APPLY_WIS; affect_join(victim, &af); } if (poison != NULL) { poison->level = Max(0, poison->level - 1); poison->duration = Max(0, poison->duration - 1); if (poison->level == 0 || poison->duration == 0) act("The poison on $p has worn off.", ch, wield, NULL, TO_CHAR); } } if (ch->fighting == victim && (IsWeaponStat(wield, WEAPON_COLD_ESSENCE))) { int level; AffectData *poison, af; poison = (affect_find(wield->affect_first, gsn_cold_essence)); if (poison == NULL) level = wield->level; else level = poison->level; if (!saves_spell(level, victim, DAM_COLD)) { act("You feel cold as $p drinks your blood!", victim, wield, NULL, TO_VICT); act("$n shivers as $p draws blood!", victim, wield, NULL, TO_ROOM); af.where = TO_AFFECTS; af.type = gsn_cold_essence; af.level = level; af.duration = level; af.modifier = -2; af.bitvector = AFF_COLD_ESSENCE; af.location = APPLY_CON; affect_join(victim, &af); af.location = APPLY_STR; affect_join(victim, &af); } if (poison != NULL) { poison->level = Max(0, poison->level - 1); poison->duration = Max(0, poison->duration - 1); } } if (ch->fighting == victim && IsWeaponStat(wield, WEAPON_ACONITE)) { int level; AffectData *poison, af; if ((poison = affect_find(wield->affect_first, gsn_aconite)) == NULL) level = wield->level; else level = poison->level; if (!saves_spell(level, victim, DAM_POISON)) { chprintln(victim, "You feel faint as poison courses through your veins!"); act("$n is poisoned by the aconite on $p.", victim, wield, NULL, TO_ROOM); af.where = TO_AFFECTS; af.type = gsn_aconite; af.level = level * 6; af.duration = level; af.bitvector = AFF_ACONITE; af.modifier = -5; af.location = APPLY_STR; affect_join(victim, &af); af.location = APPLY_CON; affect_join(victim, &af); } if (poison != NULL) { poison->level = Max(0, poison->level - 1); poison->duration = Max(0, poison->duration - 1); if (poison->level == 0 || poison->duration == 0) act("The aconite on $p has worn off.", ch, wield, NULL, TO_CHAR); } } /* This goes into act_obj.c. Note that there are checks for the "poison" skill, as well as for the various poison subtypes, so they can be learned at various levels. Azalea is the default poison, so it only checks for the poison skill itself. The skill is gsn_poison2 so the poison spell, etc., is not affected. Conversely, I had to change the name of the poison spell to taint. The same functions keep being called so these where the only changes */ Do_Fun(do_poison2) { char arg1[MAX_STRING_LENGTH], buf[MAX_STRING_LENGTH], arg2[MAX_STRING_LENGTH]; ObjData *obj; obj = get_obj_list(ch, arg1, ch->carrying_first); CharData *vch = NULL; AffectData af; int percent, skill; argument = one_argument(argument, arg1); argument = one_argument(argument, arg2); if (!IsNPC(ch) && get_skill(ch, gsn_poison2)) < 1) { chprintln(ch, "You lack the training necessary to do that."); return; } if (NullStr(arg) || NullStr(argument)) { chprintln(ch, "What do you want to poison?"); return; } if (obj == NULL) { chprintln(ch, "You don't have that item."); return; } else if (obj->item_type != ITEM_WEAPON || obj->item_type != ITEM_FOOD || obj->item_type != ITEM_DRINK_CON) { chprintln(ch, "You can't poison that."); return; } else if ((is_name(arg2, "bloodcurse") && (skill = get_skill(ch, gsn_bloodcurse) < 1)) || (is_name(arg2, "magebane mage") && (skill = get_skill(ch, gsn_magebane) < 1)) || (is_name(arg2, "aconite") && !can_use_skpell(ch, gsn_aconite)) || (is_name(arg2, "cold essence") && !can_use_skpell(ch, gsn_cold_essence)) || (is_name(arg2, "vitriol") && (skill = get_skill(ch, gsn_vitriol)) < 1)) { chprintln(ch, "You are unfamiliar with that poison."); return; } if (obj->item_type == ITEM_FOOD || obj->item_type == ITEM_DRINK_CON) { int level = ch->level; if (IsObjStat(obj, ITEM_ACONITE) || (obj->value[3] != 0) || IsObjStat(obj, ITEM_BLOODCURSE) || IsObjStat(obj, ITEM_MAGEBANE) || IsObjStat(obj, ITEM_COLD_ESSENCE)) { act("$p is already poisoned. Don't overdo it.", ch, obj, NULL, TO_CHAR); return; } if (is_name(arg2, "aconite")) { skill = ((get_skill(ch, gsn_poison2) + get_skill(ch, gsn_aconite)) / 2); if (percent < skill) { act("$n fixes up the looks of $p. There! All better.", ch, obj, NULL, TO_ROOM); act("You treat $p with aconite extract.", ch, obj, NULL, TO_CHAR); af.where = TO_OBJECT; af.type = gsn_aconite; af.level = level; af.duration = level * 2; af.location = APPLY_NONE; af.modifier = 0; af.bitvector = ITEM_ACONITE; affect_to_obj(obj, &af); WaitState(ch, skill_table[gsn_aconite].beats); return; } else { act("You fail to poison $p.", ch, obj, NULL, TO_CHAR); check_improve(ch, gsn_poison2, false, 4); check_improve(ch, gsn_aconite, false, 4); WaitState(ch, skill_table[gsn_aconite].beats); return; } } else if (is_name(arg2, "mage magebane")) { skill = ((get_skill(ch, gsn_poison2) + get_skill(ch, gsn_magebane)) / 2); if (percent < skill) { act("$n straigthens $p. It look more presentable.", ch, obj, NULL, TO_ROOM); act("You treat $p with a dose of magebane poison.", ch, obj, NULL, TO_CHAR); af.where = TO_OBJECT; af.type = gsn_magebane; af.level = level; af.duration = level * 2; af.location = APPLY_NONE; af.modifier = 0; af.bitvector = ITEM_MAGEBANE; affect_to_obj(obj, &af); WaitState(ch, skill_table[gsn_magebane].beats); return; } else { act("You fail to poison $p.", ch, obj, NULL, TO_CHAR); check_improve(ch, gsn_poison2, false, 4); check_improve(ch, gsn_magebane, false, 4); WaitState(ch, skill_table[gsn_magebane].beats); return; } } else if (is_name(arg2, "bloodcurse blood")) { skill = ((get_skill(ch, gsn_poison2) + get_skill(ch, gsn_bloodcurse)) / 2); if (percent < skill) { act("$n fiddles with $p. It's left looking much the same.", ch, obj, NULL, TO_ROOM); act("You add a dose of bloodcurse poison to $p.", ch, obj, NULL, TO_CHAR); af.where = TO_OBJECT; af.type = gsn_bloodcurse; af.level = level; af.duration = level * 2; af.location = APPLY_NONE; af.modifier = 0; af.bitvector = ITEM_BLOODCURSE; affect_to_obj(obj, &af); WaitState(ch, skill_table[gsn_bloodcurse].beats); return; } else { act("You fail to poison $p.", ch, obj, NULL, TO_CHAR); check_improve(ch, gsn_poison2, false, 4); check_improve(ch, gsn_bloodcurse, false, 4); WaitState(ch, skill_table[gsn_bloodcurse].beats); return; } } else if (is_name(arg2, "cold essence")) { skill = ((get_skill(ch, gsn_poison2) + get_skill(ch, gsn_cold_essence)) / 2); if (percent < skill) { act("$n sprinkles something on $p. Frost crystals form over it.", ch, obj, NULL, TO_ROOM); act("You sprinkle $p with cold essence. It becomes chilled.", ch, obj, NULL, TO_CHAR); af.where = TO_OBJECT; af.type = gsn_cold_essence; af.level = level; af.duration = level * 2; af.location = APPLY_NONE; af.modifier = 0; af.bitvector = ITEM_COLD_ESSENCE; affect_to_obj(obj, &af); WaitState(ch, skill_table[gsn_cold_essence].beats); return; } else { act("You fail to poison $p.", ch, obj, NULL, TO_CHAR); check_improve(ch, gsn_poison2, false, 4); check_improve(ch, gsn_cold_essence, false, 4); WaitState(ch, skill_table[gsn_cold_essence].beats); return; } } else if (is_name(arg2, "azalea")) { skill = get_skill(ch, gsn_poison2); if (percent < skill) { act("$n treats $p with deadly poison.", ch, obj, NULL, TO_ROOM); act("You treat $p with deadly poison.", ch, obj, NULL, TO_CHAR); if (obj->value[3] != 1) { obj->value[3] = 1; check_improve(ch, gsn_poison2, true, 4); } WaitState(ch, skill_table[gsn_poison2].beats); return; } else { act("You fail to poison $p.", ch, obj, NULL, TO_CHAR); check_improve(ch, gsn_poison2, false, 4); WaitState(ch, skill_table[gsn_poison2].beats); return; } } else if (is_name(arg2, "vitriol")) { act("Adding a powerful acid to $p would only ruin it.", ch, obj, NULL, TO_CHAR); return; } else if (NullStr(arg2)) { act("You need to specify a poison to be used.", ch, obj, NULL, TO_CHAR); return; } else { act("You are unfamiliar with that poison.", ch, obj, NULL, TO_CHAR); return; } } if (obj->item_type == ITEM_WEAPON) { if (obj->value[3] < 0 || attack_table[obj->value[3]].damage == DAM_BASH) { chprintln(ch, "You can only envenom edged weapons."); return; } if (IsWeaponStat(obj, WEAPON_POISON) || IsWeaponStat(obj, WEAPON_BLOODCURSE) || IsWeaponStat(obj, WEAPON_MAGEBANE) || IsWeaponStat(obj, WEAPON_COLD_ESSENCE) || IsWeaponStat(obj, WEAPON_VITRIOL) || IsWeaponStat(obj, WEAPON_ACONITE)) { act("It seems it's already been poisoned.", ch, obj, NULL, TO_CHAR); return; } if (is_name (arg2, "bloodcurse blood")) { skill = ((get_skill(ch, gsn_bloodcurse)/2) + ((get_skill(ch, gsn_poison2)/2); if (number_percent() < skill) { act("$n coats $p with deadly poison.", ch, obj, NULL, TO_ROOM); act("You coat $p with a debilitating poison.", ch, obj, NULL, TO_CHAR); af.where = TO_WEAPON; af.type = gsn_bloodcurse; af.level = ch->level * percent / 100; af.duration = ch->level / 2 * percent / 100; af.location = APPLY_NONE; af.modifier = 0; af.bitvector = WEAPON_BLOODCURSE; affect_to_obj(obj, &af); check_improve(ch, gsn_bloodcurse, true, 4); check_improve(ch, gsn_poison2, true, 4); WaitState(ch, skill_table[gsn_bloodcurse].beats); return; } else { act("You fail to poison $p.", ch, obj, NULL, TO_CHAR); check_improve(ch, gsn_bloodcurse, false, 4); check_improve(ch, gsn_poison2, false, 4); WaitState(ch, skill_table[gsn_bloodcurse].beats); return; } } if (is_name(arg2, "aconite")) { skill = ((get_skill(ch, gsn_aconite)/2) + ((get_skill(ch, gsn_poison2)/2); if (number_percent() < skill) { af.where = TO_WEAPON; af.type = gsn_aconite; af.level = ch->level * percent / 100; af.duration = ch->level / 2 * percent / 100; af.location = APPLY_NONE; af.modifier = 0; af.bitvector = WEAPON_ACONITE; affect_to_obj(obj, &af); check_improve(ch, gsn_aconite, true, 4); check_improve(ch, gsn_poison2, true, 4); WaitState(ch, skill_table[gsn_aconite].beats); return; } else { act("You fail to poison $p.", ch, obj, NULL, TO_CHAR); check_improve(ch, gsn_aconite, false, 4); check_improve(ch, gsn_poison2, false, 4); WaitState(ch, skill_table[gsn_aconite].beats); return; } } if (is_name(arg2, "magebane mage")) { skill = ((get_skill(ch, gsn_magebane)/2) + ((get_skill(ch, gsn_poison2)/2); if (number_percent() < skill) { act("$n coats $p with deadly poison.", ch, obj, NULL, TO_ROOM); act("You coat $p with a powerful mystic poison.", ch, obj, NULL, TO_CHAR); af.where = TO_WEAPON; af.type = gsn_magebane; af.level = ch->level * percent / 100; af.duration = ch->level / 2 * percent / 100; af.location = APPLY_NONE; af.modifier = 0; af.bitvector = WEAPON_MAGEBANE; affect_to_obj(obj, &af); check_improve(ch, gsn_magebanee, true, 4); check_improve(ch, gsn_poison2, true, 4); WaitState(ch, skill_table[gsn_magebane].beats); return; } else { act("You fail to poison $p.", ch, obj, NULL, TO_CHAR); check_improve(ch, gsn_magebane, false, 4); check_improve(ch, gsn_poison2, false, 4); WaitState(ch, skill_table[gsn_magebane].beats); return; } } if (is_name(arg2, "azalea") { skill = get_skill(ch, gsn_poison2); if (number_percent() < skill) { act("$n treats $p with deadly poison.", ch, obj, NULL, TO_ROOM); act("You treat $p with deadly poison.", ch, obj, NULL, TO_CHAR); af.where = TO_WEAPON; af.type = gsn_poison2; af.level = ch->level * percent / 100; af.duration = ch->level / 2 * percent / 100; af.location = APPLY_NONE; af.modifier = 0; af.bitvector = WEAPON_POISON; affect_to_obj(obj, &af); check_improve(ch, gsn_poison2, true, 4); WaitState(ch, skill_table[gsn_poison2].beats); return; } else { act("You fail to poison $p.", ch, obj, NULL, TO_CHAR); check_improve(ch, gsn_poison2, false, 4); WaitState(ch, skill_table[gsn_poison2].beats); return; } } } } /* In bits.h, affects are added for the new poison types, and for the weapon affects. These go under define AFF_FLAMESHIELD*/ #define AFF_BLOODCURSE (BIT_Bx) #define AFF_MAGEBANE (BIT_Cx) #define AFF_ACONITE (BIT_Dx) #define AFF_COLD_ESSENCE (BIT_Ex) /*This goes under the rest of the weapon flags, under #define WEAPON_POISON, or something. In my file, this goes under the flags for weapon materials, so change (BIT_letter) so it fits the bit right over it*/ #define WEAPON_ACONITE (BIT_I) #define WEAPON_MAGEBANE (BIT_J) #define WEAPON_BLOODCURSE (BIT_K) #define WEAPON_VITRIOL (BIT_L) #define WEAPON_COLD_ESSENCE (BIT_M) /*These definitions are called for edible items or drinks poisoned with each respective poison. Vitriol isn't included because I don't really think it's a good idea to poison food with acid. Too obvious. Put this after #define ITEM_QUEST*/ #define ITEM_ACONITE (BIT_b) #define ITEM_BLOODCURSE (BIT_c) #define ITEM_MAGEBANE (BIT_d) #define ITEM_COLD_ESSENCE (BIT_e) /* For magebane poison, I added a check in do_cast for a 40% chance of spell failure. Make it smaller if it feels too powerful Add this after the check for minimum position, or somewhere thereabouts.*/ if (ch->position < skill_table[sn].minimum_position) { chprintln(ch, "You can't concentrate enough."); return; } + if (IsAffected(ch, AFF_MAGEBANE) && percent < 41 ) + { + chprintln(ch, "You can't seem to focus your mind!"); + return; + } /*I decided cold essence should have an annoying effect similar to magebane, so it makes you miss on attacks sometimes. Add this on the void one_hit function, after the variable declarations at the beginning.*/ if (IsAffected(ch, AFF_COLD_ESSENCE) && (miss_chance < 41)) { act("A nasty tremor makes you miss your attack on $N!", ch, NULL, victim, TO_CHAR); return; } /*In order for poisons to do damage, they need to be checked in update.c. Since I use micro ticks, and I don't know if you do, you might need to adjust the damage so it's not too high or low. Put this after the if (IsAffected(ch, AFF_POISON)) check. Since vitriol does damage on hit, it's only called from fight.c, and since bloodcurse only diminishes stats and healing, it's only checked on update.c, in the in hit_gain function. Magebane status is checked on int mana_gain.*/ /*Put this on void char_update, or void micro_tenth, as appropriate*/ if (IsAffected(ch, AFF_ACONITE) && ch != NULL) { AffectData *poison; poison = affect_find(ch->affect_first, gsn_aconite); if (poison != NULL) { act("$n shivers and suffers.", ch, NULL, NULL, TO_ROOM); chprintln(ch, "You shiver and suffer."); damage(ch, ch, poison->level / 10 + 1, gsn_aconite, DAM_POISON, false); } } if (IsAffected(ch, AFF_MAGEBANE) && ch != NULL) { AffectData *poison; poison = affect_find(ch->affect_first, gsn_magebane); if (poison != NULL) { act("$n shivers uncomfortably.", ch, NULL, NULL, TO_ROOM); chprintln(ch, "Your sight blurs as a shiver overtakes you."); ch->mana = Max(0, ch->mana - (poison->level / 20 + 1)); } } if (IsAffected(ch, AFF_COLD_ESSENCE) && ch != NULL) { AffectData *poison; poison = affect_find(ch->affect_first, gsn_cold_essence); if (poison != NULL) { act("$n is overtaken by a shivering fit.", ch, NULL, NULL, TO_ROOM); chprintln(ch, "You feel cold to your bones!."); damage(ch, ch, poison->level / 15 + 1, gsn_cold_essence, DAM_COLD, false); } } /*Put this on in hit_gain, after if (IsAffected(ch, AFF_POISON))*/ if (IsAffected(ch, AFF_PLAGUE) || IsAffected(ch, AFF_ACONITE)) gain /= 8; if (IsAffected(ch, AFF_HASTE) || IsAffected(ch, AFF_SLOW)) gain /= 2; if (IsAffected(ch, AFF_BLOODCURSE)) gain = 0; /*Put this on int mana_gain, after if (IsAffected(ch, AFF_POISON)) too*/ if (IsAffected(ch, AFF_PLAGUE) || IsAffected(ch, AFF_ACONITE)) gain /= 8; if (IsAffected(ch, AFF_HASTE) || IsAffected(ch, AFF_SLOW)) gain /= 2; if (IsAffected(ch, AFF_MAGEBANE)) gain = 0; /*That should be enough to get it to work. Email me at riayi81(at)gmail.com if it doesn't. I swear it all does work on my mud!*/