/* /lib/spell.c * From Dead Souls LPMud * An object all spells inherit. * Created by Descartes of Borg 951027 * Version: @(#) spell.c 1.22@(#) * Last modified: 96/12/17 */ #include <lib.h> #include <magic.h> #include <damage_types.h> inherit LIB_DAEMON; inherit LIB_HELP; private int AutoDamage = -1; // perform dmg? private int AutoHeal = -1; // perform healing? private string Conjure = 0; // file to clone private int array Damage = ({ 0, 0 }); // base, random private mixed array Messages = ({}); // damage/heal messages private int DamageType = MAGIC; // damage type done private int Difficulty = 0; // 1-100 scale private int array Healing = ({ 0, 0 }); // base, random private int array MagicCost = ({ 0, 0 }); // base, random private int Morality = 0; // bad? good? private string array Religions = 0; // limit who can cast private int RemoteTargets = 0; // can targets be remote private int RequiredMagic = 0; // min magic pts to cast private int RequiredStamina = 0; // min stam pts to cast private string array Rules = ({}); // spell rules private mapping Skills = ([]); // skill requirements private string SpellName = ""; // name of spell private int SpellType = SPELL_HEALING; // spell type private int array StaminaCost = ({ 0, 0 }); // base, random private int TrainingModifier= 1; // training factor private string Verb = "cast"; // use what verb? /* ********************* spell.c attributes ************************ */ int GetAutoDamage() { return AutoDamage; } static int SetAutoDamage(int x) { return (AutoDamage = x); } int GetAutoHeal() { return AutoHeal; } static int SetAutoHeal(int x) { return (AutoHeal = x); } string GetConjure() { return Conjure; } static string SetConjure(string str) { return (Conjure = str); } int GetDamage() { int tmp = 0; int damage = Damage[0]; if( Damage[1] ) { damage += random(Damage[1]); } if(this_player()->GetSkill("magic attack")){ tmp = (this_player()->GetSkill("magic attack")["level"]) * 2; tmp = tmp/this_player()->GetSkill("magic attack")["class"]; } damage += tmp; return damage; } varargs static void SetDamage(int type, mixed array rest...) { DamageType = type; if( arrayp(rest[0]) ) { rest = rest[0]; } Damage[0] = rest[0]; if( sizeof(rest) == 2 ) { Damage[1] = rest[1]; } return; } int GetDamageType() { return DamageType; } int GetDifficulty() { return Difficulty; } static int SetDifficulty(int x) { return (Difficulty = x); } string GetErrorMessage() { string rule = Rules[0]; switch(rule) { case "": if( Verb == "pray" ) { return "Just pray for it."; } else { return "Simply cast it?"; } case "LIV": if( Verb == "pray" ) { return "Pray for it for whom?"; } else { return "Cast it on whom?"; } case "OBJ": case "STR": if( Verb == "pray" ) { return "Pray for it for what?"; } else { return "Cast it on what?"; } case "STR of LIV": if( Verb == "pray" ) { return "Pray for it for whom against what?"; } else { return "Cast it on what of whom?"; } case "for LIV": return "Pray for it for whom?"; case "for OBJ": return "Pray for it for what?"; case "against STR": if( Verb == "pray" ) { return "Pray against what?"; } else { return "Cast against what?"; } case "against STR for LIV": return "Pray against what for whom?"; } if( Verb == "pray" ) { return "Pray for it?"; } return "Cast it?"; } int GetHealing() { return Healing[0] + random(Healing[1]); } static varargs int array SetHealing(mixed args...) { Healing[0] = args[0]; if( sizeof(args) == 2 ) { Healing[1] = args[1]; } return Healing; } int GetMagicCost() { return MagicCost[0] + random(MagicCost[1]); } static varargs int array SetMagicCost(mixed args...) { MagicCost[0] = args[0]; if( sizeof(args) == 2 ) { MagicCost[1] = args[1]; } return MagicCost; } varargs string array GetMessage(int damage, int healing) { int max, div, i; if( damage < 1 ) { return Messages[0]; } if( sizeof(Messages) == 2 ) { return Messages[1]; } if( healing) { max = Healing[0] + Healing[1]; } else { max = Damage[0] + Damage[1]; } div = max/(sizeof(Messages) - 1); i = (damage/div) + 1; if( i >= sizeof(Messages) ) { i = sizeof(Messages)-1; } return Messages[i]; } static mixed array SetMessages(mixed array messages) { return (Messages = messages); } int GetMorality() { return Morality; } static int SetMorality(int x) { return (Morality = x); } string array GetReligions() { return copy(Religions); } varargs static string array SetReligions(string array religions...) { return (Religions = religions); } int GetRemoteTargets() { return RemoteTargets; } static int SetRemoteTargets(int x) { return (RemoteTargets = x); } int GetRequiredMagic() { return RequiredMagic; } static int SetRequiredMagic(int x) { return (RequiredMagic = x); } int GetRequiredStamina() { return RequiredStamina; } static int SetRequiredStamina(int x) { return (RequiredStamina = x); } int GetRequiredSkill(string skill) { return Skills[skill]; } string array GetRules() { return Rules; } varargs static string array SetRules(mixed args...) { if( !args ) { args = ({ "" }); } else if( arrayp(args[0]) ) { args = args[0]; } return (Rules = args); } string array GetSkills() { return keys(Skills); } static mapping SetSkills(mapping mp) { return (Skills = mp); } string GetSpell() { return SpellName; } static string SetSpell(string str) { return (SpellName = str); } int GetSpellType() { return SpellType; } static int SetSpellType(int x) { return (SpellType = x); } int GetStaminaCost() { return StaminaCost[0] + random(StaminaCost[1]); } static varargs int array SetStaminaCost(mixed args...) { StaminaCost[0] = args[0]; if( sizeof(args) == 2 ) { StaminaCost[1] = args[1]; } return StaminaCost; } varargs object array GetTargets(object who, mixed args...) { int count = sizeof(args); int attack = (SpellType == SPELL_COMBAT); object def; if( attack ) { def = who->GetCurrentEnemy(); } else { def = who; } if( Verb == "cast" ) { if( !count) { if( member_array("", Rules) == -1 ) { return 0; } else { if( def ) { return ({ def }); } else { return 0; } } } else if( count == 1 ) { // on LIV || on STR if( objectp(args[0]) ) { // on LIV if( !living(args[0]) ) { return 0; } if( member_array("LIV", Rules) == -1 ) { return 0; } else { return ({ args[0] }); } } if( stringp(args[0]) ) { // on STR int which = member_array("against STR", Rules); if( which == -1 && member_array("STR", Rules) == -1 ) { return 0; } else { if( def ) { return ({ def }); } else { return 0; } } } } if( objectp(args[1]) ) { // on STR of LIV if( !living(args[1]) ) { return 0; } if( member_array("STR of LIV", Rules) == -1 ) { return 0; } else { return ({ args[1] }); } } } else { if( !count) { if( member_array("", Rules) == -1 ) { return 0; } else { if( def ) { return ({ def }); } else { return 0; } } } else if( count == 1 ) { // against STR if( objectp(args[0]) ) { if( !sizeof(({ "for LIV", "for OBJ" }) & Rules) ) { return 0; } if( !living(args[0]) && member_array("for OBJ",Rules) == -1 ) { return 0; } return ({ args[0] }); } if( member_array("against STR", Rules) == -1 ) { return 0; } else { if( def ) { return ({ def }); } else { return 0; } } } if( objectp(args[1]) ) { // against STR for LIV if( !living(args[1]) ) { return 0; } if( member_array("against STR for LIV", Rules) == -1 ) { return 0; } else { return ({ args[1] }); } } } return 0; } static int SetTrainingModifier(int modifier) { return TrainingModifier = modifier; } int GetTrainingModifier() { return TrainingModifier; } string GetVerb() { return Verb; } static string SetVerb(string verb) { return (Verb = verb); } /* ******************** spell.c modals *************************** */ static int CanAttack(object who, object array enemies, int power) { int i, maxi = sizeof(enemies); int hits = 0; int misses = 0; int hit_count = 0; int miss_count = 0; int hit_con = 0; int miss_con = 0; int bonus; if( !maxi ) { return -1; } for(i=0; i<maxi; i++) { mixed area; if( !enemies[i] ) { continue; } if( !enemies[i]->eventPreAttack(who) ) { enemies[i] = 0; continue; } if( environment(enemies[i]) != environment(who) ) { if( RemoteTargets ) { area = 0; } else { enemies[i] = 0; continue; } } else { area = environment(who); } moral_act(who, enemies[i], GetMorality()); if( !enemies[i]->eventReceiveAttack(power, "magic", who) ) { misses += enemies[i]->GetLevel(); miss_count++; miss_con += enemies[i]->GetMagicResistance(); send_messages("repel", "$target_name $target_verb " "$agent_possessive_noun magic attack.", who, enemies[i], area); enemies[i] = 0; } else { hit_count++; hits += enemies[i]->GetLevel(); hit_con += enemies[i]->GetMagicResistance(); } } if( miss_count > 0 ) { bonus = who->GetCombatBonus(misses/miss_count); bonus *= GetTrainingModifier(); foreach(string skill in GetSkills()) { who->eventTrainSkill(skill, power/(hit_count+miss_count), miss_con/miss_count, 0, bonus); } } if( hit_count < 1 ) { return -1; } bonus = who->GetCombatBonus(hits/hit_count); bonus *= GetTrainingModifier(); foreach(string skill in GetSkills()) { who->eventTrainSkill(skill, power/(hit_count+miss_count), hit_con/hit_count, 1, bonus); } return 1; } varargs int CanCast(object who, int level, string limb, object array targets) { string array skills = GetSkills(); int count = sizeof(skills); int cost = GetMagicCost(); int x; if( Religions ) { if( member_array(who->GetReligion(1), Religions) == -1 ) { who->eventPrint("Your deity does not have that kind of power."); return 0; } } if( cost > 0 ) { who->AddMagicPoints(-cost); } cost = GetStaminaCost(); if( cost > 0 ) { who->AddStaminaPoints(-cost); } if( AutoHeal != -1 ) { int i, maxi = sizeof(targets); for(i=0; i<maxi; i++) { int hp, max_hp; if( !targets[i] ) { continue; } if( limb ) { if( member_array(limb, targets[i]->GetLimbs()) == -1 ) { send_messages("have", "$target_name $target_verb no " + limb + ".", who, targets[i]); targets[i] = 0; continue; } } hp = targets[i]->GetHealthPoints(limb); max_hp = targets[i]->GetMaxHealthPoints(limb); if( max_hp - hp < (Healing[0]+Healing[1])/10 + 1 ) { if( limb ) { send_messages("", "$target_possessive_noun " + limb + " needs no healing.", who, targets[i]); } else { send_messages("need", "$target_name $target_verb no " "healing.", who, targets[i]); } targets[i] = 0; continue; } } if( !sizeof(filter(targets, (: $1 :))) ) { return 0; } } foreach(string skill in skills) { level += who->GetSkillLevel(skill); } level = level/(count+1); x = who->GetMagicChance(level/2 + random(level/2)); if( x < GetDifficulty() ) { // Can't even cast it... foreach(string skill in skills) { who->eventTrainSkill(skill, level, GetDifficulty(), 0, GetTrainingModifier()); } who->eventPrint("You must have gotten the words wrong."); return 0; } if( AutoDamage != -1 ) { if( CanAttack(who, targets, x) == - 1 ) { who->eventPrint("Your powers fail you."); return 0; } } else { if( GetMorality() ) { moral_act(who, 0, GetMorality()); } foreach(string skill in skills) { who->eventTrainSkill(skill, level, GetDifficulty(), 1, GetTrainingModifier()); } } return 1; } /* ******************** spell.c events *********************** */ /* -1 means this did nothing * otherwise return damage amount for SPELL_DAMAGE * or heal amount for SPELL_HEAL */ varargs int eventCast(object who, int level, mixed limb, object array targets) { if( GetConjure() ) { object ob = new(GetConjure()); if( !ob ) { who->eventPrint("An error occurred in conjuring."); return 1; } send_messages(Messages[0][0], Messages[0][1], who, 0,environment(who)); if( !ob->eventMove(who) ) { send_messages("drop", "$agent_name could not carry " + ob->GetShort() + " and $agent_verb it!", who, 0, environment(who)); ob->eventMove(environment(who)); } return 1; } if( AutoHeal != -1 ) { mapping messages = ([]); int total_healing = 0; foreach(object target in targets) { string array tmp; int healing; if( !target ) { continue; } healing = (GetHealing() * level)/100; healing = target->eventHealDamage(healing, AutoHeal, limb); total_healing += healing; tmp = GetMessage(healing, 1); if( !messages[tmp[1]] ) { messages[tmp[1]] = ([ tmp[0] : ({ target }) ]); } else { if( !messages[tmp[1]][tmp[0]] ) { messages[tmp[1]][tmp[0]] = ({ target }); } else { messages[tmp[1]][tmp[0]] += ({ target }); } } } foreach(string message, mapping tmp in messages) { foreach(string verb, object array obs in tmp) { send_messages(verb, message, who, obs, environment(who), ([ "$limb" : limb ])); } } if( sizeof(targets) ) { return total_healing/sizeof(targets); } else { return 0; } } if( AutoDamage != -1 ) { mapping messages = ([]); int total_damage = 0; foreach(object target in targets) { string array tmp; int damage; if( !target ) { continue; } damage = (GetDamage() * level)/100; if(!limb) limb = "torso"; if(grepp(identify(limb),"leg") || grepp(identify(limb),"foot")) limb = "torso"; damage = target->eventReceiveDamage(who, GetDamageType(), damage, AutoDamage, limb); total_damage += damage; tmp = GetMessage(damage); if( !messages[tmp[1]] ) { messages[tmp[1]] = ([ tmp[0] : ({ target }) ]); } else { if( !messages[tmp[1]][tmp[0]] ) { messages[tmp[1]][tmp[0]] = ({ target }); } else { messages[tmp[1]][tmp[0]] += ({ target }); } } } foreach(string message, mapping tmp in messages) { foreach(string verb, object array obs in tmp) { send_messages(verb, message, who, obs, environment(who), ([ "$limb" : limb ])); } } if( sizeof(targets) ) { return total_damage/sizeof(targets); } else { return 0; } } return -1; } varargs mixed eventParse(object who, mixed array args...) { int count = sizeof(args); if( count < 1 ) { if( member_array("", Rules) == -1 ) { return GetErrorMessage(); } return ({}); } if( Verb == "cast" ) { if( count == 1 ) { if( objectp(args[0]) ) { if( !living(args[0]) ) { if( member_array("OBJ", Rules) == -1 ) { return GetErrorMessage(); } return ({ args[0] }); } if( sizeof(({ "OBJ", "LIV"}) & Rules) == 0 ) { return GetErrorMessage(); } return ({ args[0] }); } if( stringp(args[0]) ) { int which = member_array("against STR", Rules); if( which == -1 && member_array("STR", Rules) == -1 ) { return GetErrorMessage(); } return ({ args[0] }); } } if( member_array("STR of LIV", Rules) == -1 ) { return GetErrorMessage(); } if( stringp(args[0]) && objectp(args[1]) && living(args[1]) ) { return ({ args[0], args[1] }); } return "Cast it on what of whom?"; } else { if( count == 1 ) { if( objectp(args[0]) ) { if( sizeof(({ "for OBJ", "for LIV" }) & Rules) ) { if( !living(args[0]) ) { if( member_array("for OBJ", Rules) == -1 ) { return GetErrorMessage(); } } return ({ args[0] }); } return GetErrorMessage(); } if( member_array("against STR", Rules) == -1 ) { return GetErrorMessage(); } return ({ args[0] }); } if( member_array("against STR for LIV", Rules) == -1 ) { return GetErrorMessage(); } if( stringp(args[0]) && objectp(args[1]) && living(args[1]) ) { return ({ args[0], args[1] }); } return "Pray for it against what for whom?"; } } /* ***************** spell.c driver applies ******************** */ static void create() { daemon::create(); SetNoClean(1); }