/* * MusicMUD - Combat Module * Copyright (C) 1998-2003 Abigail Brady * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include "musicmud.h" #include "verbs.h" #include "misc.h" #include "util.h" #include "misc.h" #include "rooms.h" #include "pflags.h" #include "death.h" #include "trap.h" #include "events.h" #include "hooks.h" #include "vsprintf.h" #include "units.h" #include "shared.h" #include "match.h" #include "move.h" #include "nations.h" /* * * NEW STYLE COMBAT ENGINE * */ #define MODULE "combat" static bool peaceful(MudObject *where) { if (where->get_flag(FL_UNPEACEFUL)) return 0; if (where==mud) return 0; if (where->get_flag(FL_PEACEFUL)) return 1; return peaceful(where->owner); } static bool is_policed(MudObject *who) { if (peaceful(who->owner)) { if (streq(who->get("nation"), "evil")) return 0; return 1; } return 0; } static int tourn() { return mud->get_int("tournament", 0); } static bool verb_tournament(MudObject *who, int argc, const char **argv) { MudObject *o; int i; if (argc>1) { int nowon = tourn(); if (nowon && streq(argv[1], "off")) { if (IS_CAPTAIN(who) || who->ilc) { who->interpret2("announce Tournament off"); mud->set("tjoin", 0); mud->unset("tournament"); foreach(planet, o, i) { if (is_player(o) && o->get("tourn")) { o->unset("_fighting"); } MudObject *f = o->get_object("_fighting"); if (f && is_player(f) && f->get("tourn")) { o->unset("_fighting"); } } } } if (!nowon && streq(argv[1], "prepare")) { if (IS_CAPTAIN(who) || who->ilc) { who->interpret2("announce Tournament starting soon."); mud->set("tfrom", 1); foreach(players, o, i) { o->unset("tourn"); o->unset("tplayers"); o->unset("tmobiles"); o->unset("tdiedp"); o->unset("tdiedm"); } } } else if (!nowon && streq(argv[1], "begin")) { if (IS_CAPTAIN(who) || who->ilc) { mud->unset("tfrom"); who->interpret2("announce Tournament on."); mud->set("tournament", now+(15*60)); } } if (streq(argv[1], "join")) { if (strlen(who->id)!=4 || who->get_int("skill.combat",0)!=0) { who->printf("You can't join a tournament with your regular character. Quit then create a character with a 4 letter name.\n"); } else { who->set("tourn", "yes"); /// XXX make this a mud property MudObject *l2 = MUD_TOURNSTART; if (l2 && l2 != who->owner) { who->oprintf("%#M vanishes.\n", who); set_owner(who, l2); who->oprintf("%#M appears.\n", who); who->interpret("look"); } } } } return true; } static bool is_immune(MudObject *who, MudObject *at) { if (who->get("tourn")) return 0; if (is_mobile(who) && tourn()) return 0; if (dotrap(E_ONUNJUST, at, who, 0, 0)) return 0; return is_policed(who) || who->get_priv(PFL_IMMORTAL); } static bool dropweapon(MudObject *who) { if (MudObject *w=who->get_object(KEY_WIELD)) { NewWorld ww; ww.add(*w); drop_obs(who, ww); return 1; } return 0; } static void damageroom(MudObject *who, int damage) { MudObject *room = who->owner; MudObject *o; int i; foreach(room->children, o, i) if (is_player(o) || is_mobile(o)) { set_strength(o, strength_of(o)-damage); /* XXX do death detection and corpse creation here */ } } static bool verb_wield(MudObject *who, int argc, const char **argv) { if (argc < 2) { who->printf("Wield what?\n"); return true; } if (who->get_flag(FL_SLEEPING)) { who->printf("You toss and turn in your sleep.\n"); who->oprintf(cansee, "%#M attempts to grab you in %s sleep.\n", who, his_or_her(who)); return true; } MudObject *what=0; NewWorld whatg = match(who, argc-1, argv+1, NULL, LOOK_INV|IGNORE_EXITS); if (whatg.getsize()>1) { who->printf("You can only wield one thing at a time.\n"); return true; } if (whatg.getsize()) { what = whatg.get_nth(0); } if (!what) { who->printf("Wield what?\n", argv[1]); return true; } if (what->owner != who) { who->printf("You aren't carrying %Y.\n", what); return true; } set_prons(who, what); if (dotrap(E_BEFOREWIELD, who, what)) return true; /* ::: before_wield o1==weapon; before most things, return 1 to abort */ if (what->get_int("damage")==-1 && iswornby(what, who)) { who->printf("%#M cannot be wielded whilst you are wearing %s.\n", what, it_them(what)); return true; } if (mount(who) == what) { who->printf("You cannot wield your mount.\n"); return true; } if (weapon(who) == what) { who->printf("You are already wielding it.\n"); return true; } who->set(KEY_WIELD, what->id); who->printf("You wield %Y^n.\n", what); who->oprintf(cansee, "%#M wields %P^n.\n", who, what); what->printf("%#M wields you.\n", who); if (dotrap(E_AFTERWIELD, who, what)) return true; /* ::: after_wield o1==weapon; after everything */ return true; } static bool verb_unwield(MudObject *who, int argc, const char **argv) { MudObject *what = weapon(who); if (who->get_flag(FL_SLEEPING)) { who->printf("You toss and turn in your sleep.\n"); who->oprintf(cansee, "%#M attempts to grab you in %s sleep.\n", who, his_or_her(who)); return true; } if (argc >= 2) { NewWorld whatg = match(who, argc-1, argv+1, NULL, LOOK_INV|IGNORE_EXITS); if (whatg.getsize()>1) { who->printf("You can only unwield one thing at a time.\n"); return true; } if (whatg.getsize()) { what = whatg.get_nth(0); } if (!what) { who->printf("Unwield what?\n", argv[1]); return true; } } if (!what) { who->printf("You aren't wielding anything.\n"); return true; } set_prons(who, what); if (what->owner != who) { who->printf("You aren't carrying %Y.\n", what); return true; } if (weapon(who) != what) { who->printf("You aren't wielding it.\n"); return true; } who->unset(KEY_WIELD); who->printf("You unwield %Y^n.\n", what); who->oprintf(cansee, "%#M unwields %P^n.\n", who, what); what->printf("%#M unwields you.\n", who); return true; } static int damage(MudObject *weapon) { if (int x=weapon->get_int("damage", 0)) return x; if (weapon->get_int("wtype")==-1) { int s = mass_in_grams(weapon) / HECTOGRAM; int d = 0; if (s<2) d = 1; else if (s>30) d = 1; else d = abs(15-abs(s-15)); return d; } return 0; } static bool iswielded(MudObject *what) { if (what && what->owner) { MudObject *o = weapon(what->owner); return o == what; } return false; } static bool isweapon(Object *what) { return what->get_int("damage") >= 0; } static int pdam(Object *what) { int dam = what->get_int("damage"); if (dam>=0) return dam; return 10; } static void retaliate(MudObject *at, MudObject *vi) { if (!vi->get("_fighting")) { if (vi->get_flag(FL_SLEEPING) || vi->get_flag(FL_SITTING)) { vi->interpret("stand"); } vi->set("_fighting", at->id); } MudObject *o; int i; const char *n = vi->get("nation"); if (!n) return; foreach(vi->owner->children, o, i) { if (!is_mobile(o)) continue; if (o->get_object("_fighting")) continue; const char *m = o->get("nation"); if (streq(m, n)) { if (dotrap(E_BEFOREJOININ, o, o, at)) /* ::: before_joinin o1==mobile that wants to join in, o2==mobile it wants to attack; return true to not join in */ continue; o->oprintf(cansee, "%#M %[joins/join] in against %Y.\n", o, at); o->printf("You join in against %Y.\n", at); o->set("_fighting", at->id); continue; } } } static bool isdead(MudObject *who) { if (who && who->owner && streq(who->owner->get("zone"), "dead")) return 1; return 0; } static bool verb_tscores(MudObject *who, int argc, const char **argv) { MudObject *o; int i; who->printf("%-12s [ Kil PKs Mob ] [ Dth PKs Mob ]\n", "Player"); foreach(players, o, i) { if (o->get("tourn")) { int pkills = o->get_int("tplayers", 0); int mkills = o->get_int("tmobiles", 0); int pdeaths = o->get_int("tdiedp", 0); int mdeaths = o->get_int("tdiedm", 0); int score = pkills * 100 + mkills * 30; score -= pdeaths * 70; score -= mdeaths * 15; who->printf("^p%#-12M^n [ %3i %3i %3i ] [ %3i %3i %3i ] %5i\n", o, pkills + mkills, pkills, mkills, pdeaths + mdeaths, pdeaths, mdeaths, score); } } time_t when = mud->get_int("tournament", 0); if (when && when>=now) { when -= now; who->printf("Tournament to end in %i min %i sec.\n", when/60, when%60); } return true; } static bool combat_kill(MudObject *attacker, MudObject *victim, const char *how2, const char *corpsedesc=0) { victim->unset("_fighting"); attacker->unset("_fighting"); if (is_player(victim) && victim->get("tourn") && tourn()) { if (is_player(attacker) && attacker->get("tourn")) victim->set("tdiedp", victim->get_int("tdiedp", 0)+1); else victim->set("tdiedm", victim->get_int("tdiedm", 0)+1); } if (is_player(attacker) && attacker->get("tourn") && tourn()) { if (is_player(victim) && victim->get("tourn")) attacker->set("tplayers", attacker->get_int("tplayers", 0)+1); else attacker->set("tmobiles", attacker->get_int("tmobiles", 0)+1); } set_strength (victim, -1); string how = ""; if (strncmp(how2, "(fumble) ", 9)) { how = how2; how += " by "; how += attacker->get("name"); } else { how = how2+10; how += " by self fighting "; how += attacker->get("name"); } const char *howmsg = how.c_str(); // log(PFL_SEEINFO, LEV_INTERNAL, "combat", "%s slain by %s", // victim->id, // attacker->id); if (is_player(attacker) && (strength_of(attacker)<random_number(100) || attacker->get_int("skill.combat")<victim->get_int("skill.combat"))) { attacker->printf("You are now more skilled at combat.\n"); attacker->set("skill.combat", attacker->get_int("skill.combat", 0)+1); how += " (gaining a skillpoint)"; howmsg = how.c_str(); } victim->set(KEY_KILLEDBY, attacker->id); /* remember who killed the mobile */ if (is_mobile(victim)) { /* Kill mobile */ MudObject *corpse = do_die(victim, 0, howmsg); /* do_die knows what to do */ if (corpse) { static const char *descs[] = { "brutally savaged", "completely massacred", "obliterated", "slain", "fatally wounded", "severely battered", "completely obliterated", "hacked apart", "killed" }; int corpseno = random_number(9); if (corpsedesc) { corpse->setf("desc", "%#M %s.", victim, corpsedesc); } else { corpse->setf("desc", "%#M has been %s.", victim, descs[corpseno]); } } if (const char *on_kill = victim->get("on_kill")) { attacker->ilc++; attacker->interpret(on_kill); attacker->ilc--; } dotrap(E_ONFIGHTOVER, attacker, attacker, 0, 0); /* ::: fight_over o1==attacker; after a fight has finished however */ if (dotrap(E_AFTERSLAIN, attacker, victim, 0, 0)) return true; /* ::: after_slain o1==victim; after mobile killed in combat */ } else if (victim->get_priv(PFL_IMMORTAL)) { victim->printf("If you were mortal, you would be dead.\n"); dotrap(E_ONFIGHTOVER, attacker, attacker, 0, 0); return false; /* Wizards don't die */ } else { set_strength (victim, 40); do_die(victim, privs_of(victim)*20, howmsg); /* do_die knows what to die */ dotrap(E_ONFIGHTOVER, attacker, attacker, 0, 0); } return true; } static bool wound_player (MudObject* attacker, MudObject* victim, int damage) { if (!attacker || !victim) { return false; } retaliate(attacker, victim); if (damage <= 0) return false; if (victim->get_priv(PFL_IMMORTAL)) return 0; if (is_mobile(victim)) { set_strength (victim, strength_of (victim) - damage); } else if (privs_of (victim) < LEV_CAPTAIN) { if ((strength_of (victim) - damage) >= 0) { set_strength (victim, strength_of (victim) - damage); victim ->printf( "^W[^nYour strength is now ^r%d^W]\n", strength_of(victim)); } else { set_strength(victim, -1); victim ->printf ("The blow was too much for you to stand. You have died.\n"); } } if (strength_of(victim)>0) { return 0; } return combat_kill(attacker, victim, "slain"); /* Victim has died */ return 1; } static int encumberance(MudObject *what) { int i; MudObject *o; int total = 0; foreach(what->children, o, i) { int size = mass_in_grams(o); total += size; } // what->printf("t:%i/%i\n", total, what->get_int("capacity", 200*HECTOGRAM)); total = (total * 100) / mass_capacity_in_grams(what, 20 * KILOGRAM); // what->printf("tc:%i\n", total); total -= 50; if (total <= 0) return 0; if (total >= 50) total = 50; return total / 3; } #include "fumble.h" #include "blow.h" static void do_combat(MudObject *attacker, MudObject *victim) { wtype_t wtype = W_UNARMED; #ifdef DEBUG_COMBAT printf("::%s attacks %s\n", attacker->id, victim->id); #endif const char *skillfor[] = {"skill.unarmed", "skill.impact", "skill.cutting", "skill.energy", "skill.stunning", "skill.stabbing"}; if (attacker->owner != victim->owner) { attacker->unset("_fighting"); victim->unset("_fighting"); dotrap(E_ONFIGHTOVER, attacker, attacker, 0, 0); // attacker->oprintf(cansee, "%#M visibly relaxes.\n"); return; } // attacker->printf("%20s rounds : %i\n", "you", attacker->get_int("!rounds", 0)); // attacker->oprintf(cansee, "%#20M rounds : %i\n", attacker, attacker->get_int("!rounds", 0)); if (attacker->get_int("!rounds", 0)>0) { attacker->set("!rounds", attacker->get_int("!rounds", 0)-1); attacker->printf("You can't attack yet...\n"); // attacker->oprintf(cansee, "%#M can't attack yet.\n", attacker); return; } else { attacker->unset("!rounds"); } int d = 0; MudObject *w = weapon(attacker); if (w && w->owner != attacker) { attacker->printf("You belatedly realise you don't have %Y,\n" "and are forced to use your hands instead.\n", w); attacker->unset(KEY_WIELD); w = 0; } { if (w && w->owner==attacker && iswielded(w) && isweapon(w)) { d = w->get_int("damage", 0); } d += pdam(attacker); } #ifdef WORNFROM MudObject *wornfrom = archetype(attacker); if (attacker->get("wornfrom")) { wornfrom = attacker->get_object("wornfrom"); } #endif if (w) { wtype = (wtype_t)(w->get_int("wtype")); } if (wtype==-1) { int s = mass_in_grams(w) / HECTOGRAM; if (s<2) d = 1; else if (s>30) d = 1; else d = abs(15-abs(s-15)); wtype = W_IMPACT; } #ifdef WORNFROM if (!w && wornfrom && wornfrom->get_object(KEY_WIELD)) { w = wornfrom->get_object(KEY_WIELD); wtype = (wtype_t)(w->get_int("wtype")); } #endif int roll = random_number(100); int mroll = roll; mroll += encumberance(victim); /* encumberance of defender */ int skil = (attacker->get_int(skillfor[wtype])/5, attacker->get_int("skill.combat")/5) + (is_player(attacker)?20:0); mroll += skil; /* skill at this weapon */ mroll += attacker->get_int("att.str", is_player(attacker)?15:10); /* strength of attacker */ mroll -= encumberance(attacker); /* encumberance of attacker */ mroll -= victim->get_int("att.dex", is_player(victim)?30:10); /* dexterity of defender */ // int vdex = victim->get_int("att.dex", is_player(victim)?30:10); // should we be using the victims dexterity??? // attacker->printf("The bias is %i, skill bonus is %i.\n", mroll-roll, skil); int delay = 1; int victimdelay = 0; if (w) delay += w->get_int("delay", 0); delay += attacker->get_int("delay", 0); bool DONTKILL = 0; if (is_player(attacker) && is_immune(victim, attacker) /*&& !IS_CAPTAIN(attacker)*/) { // mroll = 1; // roll = 1; DONTKILL = 1; /* delay += 2; */ } bool DONTDIE = 0; if (is_player(victim) && is_immune(attacker, victim)) { DONTDIE = 1; } int selfdamage = 0; const char *verb = "hit"; const char *verb_s = "hits"; switch (wtype) { case W_UNARMED: break; case W_CUTTING: verb = "slash"; verb_s = "slashes"; break; case W_IMPACT: verb = "bash"; verb_s = "bashes"; break; case W_ENERGY: verb = "shoot"; verb_s = "shoots"; break; case W_STABBING: verb = "stab"; verb_s = "stabs"; break; } int deathblow = 0; retaliate(attacker, victim); int cantfumble=0; if (!streq(body(attacker), "human")) cantfumble = 1; if (roll<=0 || mroll<=0 && !DONTDIE && !cantfumble) { /* Fumbles */ int fumblenum = -random_number(100) + skil; /* attacker->printf("You fumble (%i).\n", fumblenum); attacker->oprintf(cansee, "%#M fumbles (%i)\n", attacker, fumblenum); */ switch (wtype) { case W_UNARMED: unarmed_do_fumble(attacker, victim, w, selfdamage, delay, fumblenum); break; case W_IMPACT: impact_do_fumble(attacker, victim, w, selfdamage, delay, fumblenum); break; case W_CUTTING: case W_STABBING: cutting_do_fumble(attacker, victim, w, selfdamage, delay, fumblenum); break; case W_ENERGY: energy_do_fumble(attacker, victim, w, selfdamage, delay, fumblenum); break; } } else if (mroll < 20) { /* Miss! */ attacker->printf("You take a swing at %M but miss.\n", victim); attacker->oprintf(cansee && avoid(victim), "%#M takes a swing at %M but misses.\n", attacker, victim); victim->printf("%#M takes a swing at you but misses.\n", attacker); } else { int roll2 = random_number(d?d:1); /* Regular hits */ if (wtype != W_ENERGY) { roll2 += attacker->get_int("att.str", 10); roll2 += (mroll-20) / 20; roll2 -= random_number(player_armour( victim )+parmour(victim)); } if (roll2 <= 0) roll2 = 0; if (DONTKILL) { if (roll2 > (strength_of(victim)/2)) { roll2 = strength_of(victim)/2; } } if (streq(body(victim), "droid") && (wtype==W_CUTTING || wtype==W_STABBING)) { roll2 /= 10; wtype = W_IMPACT; } if (victim->owner->get_flag(FL_UNDERWATER)) { if (wtype==W_CUTTING) { roll2 /= 2; } if (wtype==W_IMPACT) { roll2 /= 3; } } if (roll2 > strength_of(victim)) { deathblow = 1; } else { newblow(attacker, victim, roll2, w, wtype); if (!isdead(victim)) wound_player(attacker, victim, roll2); } } if (deathblow) { newblow(attacker, victim, -100, w, wtype); } victimdelay += victim->get_int("delay", 0); victim->set("!rounds", victimdelay); attacker->set("!rounds", delay); if (selfdamage && !isdead(attacker)) wound_player(victim, attacker, selfdamage); /* Combat algorithm Calculate where we hit, and with what force (Where is determined by) Rolling at random. (Force is determined by) + encumberance of defender + skill of attacker at this weapon type + strength of attacker (should current state of health come into this? ratio of health:maxhealth) - encumberance of attacker - dexterity of victim If we roll really badly here we could get a fumble. If the _unmodified_ hit roll is exceptionaly high (natural 99? asuming rand(100) is 0->99) -We get a 'superhit' (this gives even weak attackers a tiny chance of fancy stuff) -we dont carry on and calculate damage as well as the superhit. Calculate damage actually done - armour of victim + weapon damage + strength of blow If the damage caused after calculation would kill the victim -We get a deathblow _instead_ else If the _modified_ damage roll is very high (exact number unknown yet) -We get a superhit _instead_ of normal damage -must make sure all superhits do more damage than the best normal hit... -what do we do if the super-hit kills someone, but it is a weak one, like scratching of the face, should we look at the potential damage of the super hit, and if that would kill, do a deathblow instead? */ // if (is_player(attacker)) attacker->interpret("calc_level"); // if (is_player(victim)) victim->interpret("calc_level"); } static MudObject *random_exit(MudObject *player) { MudObject *what = 0; MudObject *o; int i; NewWorld exits; foreach(player->owner->children, o, i) { if (MudObject *l=o->get_object("link")) { if (is_mobile(player) && l->get_flag(FL_NOMOBILES)) continue; exits.add(*o); } } if (exits.getsize()) { what = exits.get_nth(random_number(exits.getsize())); } return what; } static void docombat(MudObject *who) { #ifdef DEBUG_COMBAT printf("::docombat(%s)\n", who->id); #endif if (who->get("_fighting")) { MudObject *victim = who->get_object("_fighting"); if (!victim) { who->unset("_fighting"); dotrap(E_ONFIGHTOVER, who, who, 0, 0); } else { if (who->get_int("wimpy")>strength_of(who)) { if (who->get("$camefrom")) { who->interpretf("flee %s", who->get("$camefrom")); } else { MudObject *re = random_exit(who); if (re) { who->interpretf("flee %s", re->get("short")); } } } do_combat(who, victim); } } return; } static bool verb_arrest(MudObject *who, int argc, const char **argv) { /* can we use this for non lethal stun combat as well?*/ if (argc==1) { who->printf("syntax : arrest <who>\n"); return true; } if (!who->get_flag(FL_POLICE)) { who->printf("You aren't a police officer.\n"); return true; } NewWorld whatg = match(who, argc-1, argv+1, 0, LOOK_BOTH|IGNORE_EXITS|ALLOW_ME); MudObject *what = 0; if (whatg.getsize()>1) { who->printf("You can only do one arrest at a time!\n"); return true; } else if (whatg.getsize()) { what = whatg.get_nth(0); } if (!what) what = planet->get(argv[1]); if (!what) { who->printf("Arrest who?\n"); return true; } if (who->owner != what->owner) { who->interpretf(lang("say We'll catch %M, don't you worry.", who), what); who->interpretf("tell %s %s", what->id, lang("You can run but you can't hide!", what)); } else { who->interpretf(lang("say %M, you're nicked!", who), what); } MudObject *fighter = what->get_object("_fighting"); if (fighter) { fighter->unset("_fighting"); } what->unset("_fighting"); what->set("arrested", 1); return true; } static bool iscopper(MudObject *ob) { return (ob->get_flag(FL_MOBILE) && ob->get_flag(FL_POLICE) && !ob->get_flag(FL_SITTING)); } static bool verb_attack(MudObject *who , int argc, const char **argv) { int unjust = 0; MudObject *coproom = 0; if (!is_player(who) && !is_mobile(who)) { who->printf("Sorry, you're not even a mobile! :)\n"); return true; } if (who->get_flag(FL_SLEEPING)) { who->printf("You wave your hands about in your sleep.\n"); who->oprintf(cansee, "%#M is obviously dreaming in %s sleep.\n", who, his_or_her(who)); return true; } if (wf_wears_with_flag(who, FL_HANDSTIED)) { who->printf("Your hands are tied!\n"); return true; } if (argc==1) { who->printf("Attack what?\n"); return true; } if (streq(argv[1], "myself") && argc==2) { MudObject *cor=do_die(who, privs_of(who)*20, "committed suicide", 1); if (cor) { cor->setf("desc", "%#M commited suicide.\n", who); } return true; } NewWorld whatg = match(who, argc-1, argv+1, 0, LOOK_BOTH|IGNORE_EXITS|ALLOW_ME); MudObject *what = 0; if (whatg.getsize()>1) { who->printf("You can only do one attack at a time!\n"); return true; } else if (whatg.getsize()) { what = whatg.get_nth(0); } NewWorld withg = match(who, argc-1, argv+1, 0, LOOK_INV|IGNORE_EXITS, "with"); MudObject *with=0; if (withg.getsize()>1) { who->printf("You can only attack with one thing at a time!\n"); return true; } else if (withg.getsize()) { with = withg.get_nth(0); } if (!what) what = planet->get(argv[1]); if (!what) { who->printf("Cannot find %s.\n", whatg.txt.c_str()); return true; } set_prons(who, what); if (what->get_object("_fighting")==who) { if (who->get_object("_fighting")==what) { who->printf("You are already fighting %M.\n", what); return true; } who->printf("You shift your attention to %M.\n", what); who->set("_fighting", what->id); what->printf("%#M %[has/have] shifted %s attention to you.", who, his_or_her(who)); who->set("!rounds", who->get_int("!rounds",0)+2); return true; } who->set("!rounds", 0); if (who->get_object("_fighting")) { who->printf("You are already fighting someone...\n"); return true; } if (what == who) { who->printf("Are you sure? If so, 'kill myself'.\n"); return true; } MudObject *where = who->owner; MudObject *zon = where?where->owner:NULL; if (zon && zon->get_flag(FL_SANCTUARY)) { who->printf("Something interferes with your attack.\n"); return true; } if (where && where->get_flag(FL_SANCTUARY) && who->get("tourn")) { who->printf("This room is not part of the tournament.\n"); return true; } if (mud->get_int("tfrom", 0) && who->get("tourn")) { who->printf("Not until the tournament has formally started.\n"); return true; } if (!tourn() || !who->get("tourn") || (is_player(what) && !what->get("tourn"))) { if (is_player(what) || is_mobile(what)) { if (peaceful(who->owner)) { coproom = find_coproom(who->owner); unjust = 1; if (who->get_flag(FL_POLICE)) unjust = 0; if (streq(what->get("nation"), "evil")) unjust = 0; } } } if (unjust && !coproom && !who->owner->get_flag(FL_SHIP)) { who->printf("It is too peaceful here.\n"); return true; } if (what->get_priv(PFL_NOHASSLE) && !who->get_flag(FL_MOBILE)) { who->printf("Something interferes with your attack.\n"); return true; } if (what->get_priv(PFL_NOHASSLE)) { who->printf("No point.\n"); what->printf("%#M would normally attack you now.\n", who); return true; } if (dotrap(E_ONKILL, who, what, with, 0)) return true; /* ::: kill o1==victim; before fight started. o1 can be an object. */ if (what->get_flag(FL_FRAGILE)) { who->printf("You smash %Y to bits.\n", what); who->oprintf(avoid(what) && cansee, "%#M %[smashes/smash] %Y to bits.\n", who, what); what->printf("%#M %[smashes/smash] you to bits.\n", who); vanish(what); return true; } if ((who->ilc || IS_CAPTAIN(who)) && what->get_flag(FL_CANOPEN) && what->get_object("other") && what->get_int(KEY_STATE, 0)!=0) { MudObject *oth = what->get_object("other"); who->printf("You bash %Y down.\n", what); who->oprintf(cansee, "%#M %[bashes/bash] %P down.\n", who, what); what->set(KEY_STATE, 0); oth->set(KEY_STATE, 0); oth->oprintf(cansee, "%#M %[is/are] bashed down.\n", oth); return true; } if (!is_player(what) && !is_mobile(what)) { who->printf("You can't attack %Y.\n", what); return true; } if (what->owner == who) { who->printf("%#M %[escapes/escape] your grasp.\n", what); set_owner(what, who->owner); } if (what->owner != who->owner) { who->printf("%#M %[is/are] not here.\n", what); return true; } if (what->get_object("_fighting")==who) unjust = 0; who->set("_fighting", what->id); what->set("_fighting", who->id); /* added 07042002 */ who->printf("You unleash an attack on %M!\n", what); if (what->get_flag(FL_SLEEPING)) { what->printf("You clamber dozily to your feet as %#M %[unleashes/unleash] an attack on you!\n", who); what->set_flag(FL_SLEEPING, 0); } else if (what->get_flag(FL_SITTING)) { what->printf("You clamber to your feet as %#M %[unleashes/unleash] an attack on you!\n", who); what->set_flag(FL_SITTING, 0); } else { what->printf("%#M %[unleashes/unleash] an attack on you.\n", who); } who->oprintf(cansee && avoid(what), "%#M %[unleashes/unleash] an attack on %M!\n", who, what); if (!is_player(what) && dotrap(E_ONUNJUST, who, what, 0, 0)) { /* ::: unjust o1==victim; return 1 if player killing o1 would be ok */ unjust = 0; } if (is_mobile(who) && is_player(what)) { unjust = 0; } if (unjust && !what->get_flag(FL_CANTTALK) && !what->get_flag(FL_DUMB)) { int po = 0; if (what->get_flag(FL_POLICE)) { po = 1; } if (who->owner->get_flag(FL_SHIP)) { what->interpretf(lang("%s Help! %M is commiting piracy!", what), MUD_HELPCHAN, who); fine(who, 500, ssprintf("Piracy", what).c_str()); } else { if (!po) { what->interpretf(lang("%s Help! I'm being attacked by %M!", what), MUD_HELPCHAN, who); if (streq(body(what),"droid")) fine(who, 50, ssprintf("Vandalism upon %M", what).c_str()); else fine(who, 100, ssprintf("Assaulting %M", what).c_str()); } else { if (!coproom || coproom->get_object("interview") != who->owner) what->interpretf(lang("%s %M is attacking an officer of the law!", what), MUD_HELPCHAN, who); else coproom = 0; fine(who, 150, "Assaulting an officer of the law."); } } if (coproom) { MudObject *plod = choose_random_object_from(coproom, iscopper); if (plod) { if (streq(what->get("nation"), "evil")) { plod->interpretf("%s Good!", MUD_HELPCHAN); return true; } } if (plod) { plod->setf("!plan", "1 goto %s;0 say %s;0 arrest %s;1 goin %s;0 summon %s;0 heal %s;2 goto", who->id, lang("What's going on here then?", plod), who->id, coproom->get("interview"), who->id, what->id); set_owner(plod, "empty"); plod->set("!when", 1); plod->setf("!what", "%s %s", MUD_HELPCHAN, lang("On my way.", plod)); plod->set_bflag(FL_TIMER, 1); plod->set_bflag(FL_REFUSEMOVE, 1); } } } docombat(who); return true; } bool is_person(const TeleObject &t) { return is_person(t.what); } static bool verb_consider(MudObject *who, int argc, const char **argv) { int unjust = 0; MudObject *coproom = 0; NewWorld whatg = match(who, argc-1, argv+1, is_person, LOOK_BOTH|IGNORE_EXITS|ALLOW_ME); MudObject *what = 0; if (whatg.getsize()>1) { who->printf("You can only consider one thing at a time!\n"); return true; } else if (whatg.getsize()) { what = whatg.get_nth(0); } if (!what) { who->printf("Consider who or what?\n"); return true; } set_prons(who, whatg); if (!is_person(what)) { string ab = abilities(what); if (ab.length()) who->printf("%#M: %s\n", what, ab.c_str()); else who->printf("You note nothing out of the ordinary.\n"); return true; } if (what==who) { who->printf("If it came to it, you could probably kill yourself.\n"); return true; } if (!tourn() || !who->get("tourn") || (is_player(what) && !what->get("tourn"))) { if (is_player(what) || is_mobile(what)) { if (peaceful(who->owner)) { coproom = find_coproom(who->owner); unjust = 1; if (who->get_flag(FL_POLICE)) unjust = 0; if (streq(what->get("nation"), "evil")) unjust = 0; } } } if (!is_player(what) && dotrap(E_ONUNJUST, who, what, 0, 0)) { unjust = 0; } if (unjust && coproom) who->printf("You'd get arrested by %s police.\n", jname(who->owner)); else if (unjust && who->owner->get_flag(FL_SHIP)) who->printf("You'd get done for piracy the next dock you went to under %s law.\n", jname(who->owner)); else if (unjust) who->printf("You can't attack %s.\n", him_or_her(what)); else who->printf("You can feel free to attack %s.\n", him_or_her(what)); if (!unjust) { int skildif = who->get_int("skill.combat",0) - what->get_int("fakeskill.combat", what->get_int("skill.combat",0)); skildif += random_number(5) - 2; skildif += random_number(5) - 2; if (skildif > 20) who->printf("You are much more skilled,"); else if (skildif > 10) who->printf("You are more skilled,"); else if (skildif > 0) who->printf("You have a slight edge in skill,"); else if (skildif == 0) who->printf("You are about equally skilled,"); else if (skildif > -10) who->printf("%#s has a slight edge in skill,", he_or_she(what)); else if (skildif > -20) who->printf("%#s %s more skilled than you,", he_or_she(what), is_are(what)); else if (skildif > -40) who->printf("%#s %s much more skilled than you,", he_or_she(what), is_are(what)); else who->printf("%#s %s you greatly,", he_or_she(what), what->get_flag(FL_PLURAL)?"outclass":"outclasses"); MudObject *w = weapon(what); int dam = pdam(what); if (w) dam += damage(w); dam += random_number(3) - 1; dam += random_number(3) - 1; int fd=what->get_int("fakedamage"); if (fd != -1) dam = fd; const char *damstr = "minimal damage"; if (dam>5) damstr = "some damage"; if (dam>10) damstr = "a fair bit of damage"; if (dam>15) damstr = "quite a bit of damage"; if (dam>20) damstr = "a lot of damage"; if (dam>25) damstr = "lots of damage"; who->printf(" %s %s will do %s.\n", (skildif>0&&dam>10)?"but":"and", he_or_she(what), damstr); } int hp = (strength_of(what) * 100) / what->get_int("maxstrength", 200); hp += random_number(5) - 2; hp += random_number(5) - 2; const char *cond = "in excellent condition"; if (hp < 90) cond = "in very good condition"; if (hp < 80) cond = "in pretty good condition"; if (hp < 70) cond = "in good condition"; if (hp < 60) cond = "in fair condition"; if (hp < 50) cond = "starting to feel the pain"; if (hp < 40) cond = "not so good"; if (hp < 30) cond = "pretty bad"; if (hp < 20) cond = "very bad"; if (hp < 10) cond = "close to death"; who->printf("%#s %s %s.\n", he_or_she(what), is_are(what), cond); return true; } static bool verb_flee(MudObject *who, int, const char **argv) { if (!argv[1]) { who->printf("You must specify a direction to flee.\n"); return false; } if (who->get_flag(FL_SITTING)) { who->printf("You are sitting down.\n"); return true; } switch (argv[1][0]) { case 'n' : case 'N': argv[1] = "north"; break; case 's' : case 'S': if (who->owner->get_flag(FL_SHIP)) argv[1] = "starboard"; else argv[1] = "south"; break; case 'e' : case 'E': argv[1] = "east";break; case 'f' : case 'F': argv[1] = "fore";break; case 'w' : case 'W': argv[1] = "west";break; case 'u' : case 'U': argv[1] = "up";break; case 'd' : case 'D': argv[1] = "down";break; case 'r' : case 'R': argv[1] = "rimwards"; break; case 'p' : case 'P': argv[1] = "port"; break; case 'h' : case 'H': argv[1] = "hubwards";break; case 'a' : case 'A': if (who->owner->get_flag(FL_SHIP)) argv[1] = "aft"; else argv[1] = "anticlockwise"; break; case 'c' : case 'C': argv[1] = "clockwise";break; case 'o' : case 'O': argv[1] = "out";break; case 'i' : case 'I': argv[1] = "in";break; } MudObject *what = find_exit(who->owner, argv[1]); MudObject *mob = who->get_object("_fighting"); if (what && (what->get_flag(FL_EXIT) || what->get_flag(FL_PARTEXIT))) { MudObject *o; int i; if (mob) who->printf("You hurry away from %M.\n", mob); if (!trigger_mobiles(who->owner, who, what, 1)) { return true; } NewWorld todrop; foreach(who->children, o, i) { if (!iswornby(o, who) && !iswielded(o) && !o->get(KEY_ACCEPTER)) { todrop.add(*o); } } if (todrop.getsize()) { drop_obs(who, todrop); } MudObject *wasin = who->owner; who->unset("_fighting"); traverse(who, what, "flee"); if (wasin == who->owner && mob) { who->set("_fighting", mob->id); } if (mob) mob->unset("_fighting"); return false; } who->printf("You can't go ^d%s^n.\n", argv[1]);; return true; } #define CLEANUP COMBAT_ROUTINE = 0; #include "verbmodule.h" void startup() { AUTO_VERB(arrest, 4, 0, PFL_NONE); AUTO_VERB(flee, 4, 0, PFL_AWAKE); AUTO_VERB(consider, 4, 0, PFL_NONE); AUTO_VERB(attack, 4, 0, PFL_NONE); ADD_ALIAS(kill, 1, attack); ADD_ALIAS(hit, 2, attack); ADD_ALIAS(smash, 2, attack); AUTO_VERB(wield, 4, 0, PFL_NONE); AUTO_VERB(unwield, 4, 0, PFL_NONE); ADD_ALIAS(lower, 4, unwield); AUTO_VERB(tscores, 2, 0, PFL_NONE); AUTO_VERB(tournament, 4, 0, PFL_NONE); AUTO_VERB(cmsg, 4, 0, PFL_NONE); COMBAT_ROUTINE = docombat; }