"**A Dumb of the Generic Voodoo Doll (#74) on Sun Dec 17 11:57:21 1995 PST @create $root_class named generic voodoo doll:PC,generic,voodoo,doll @prop #74."coalcar" 0 c @prop #74."storm" 0 "" @prop #74."total" 325 rc @prop #74."pick" 0 c @prop #74."machete" 0 c @prop #74."dagger_melee" 0 c @prop #74."dagger_throw" 0 c @prop #74."weight" #-1 "" @prop #74."trick" 0 c @prop #74."pray" 0 c @prop #74."persuade" 0 c @prop #74."convince" 0 c @prop #74."star" 0 c @prop #74."search" 0 c @prop #74."notice" 0 c @prop #74."observe" 0 c @prop #74."revolver" 0 c @prop #74."handguns" 0 c @prop #74."javelin_melee" 0 c @prop #74."javelin_throw" 0 c @prop #74."spear" 0 c @prop #74."javelin" 0 c @prop #74."longbow" 0 "" @prop #74."drawbow" 0 "" @prop #74."crossbow" 0 "" @prop #74."longarms" 0 "" @prop #74."missiles" 0 "" @prop #74."sai" 0 "" @prop #74."heal" 0 "" @prop #74."life" 0 "" @prop #74."heat" 0 "" @prop #74."schedule" {} "" @prop #74."pushbike" 0 "" @prop #74."bike" 0 "" @prop #74."drive" 0 "" @prop #74."baxe2" 0 "" @prop #74."baxe1" 0 "" @prop #74."baxe" 0 "" @prop #74."forcewall" 0 "" @prop #74."force" 0 "" @prop #74."free_will" 1 "" @prop #74."slow" 0 "" @prop #74."time" 0 "" @prop #74."knives" 0 "" @prop #74."dagger" 0 "" @prop #74."tclimb" 0 "" @prop #74."kat2" 0 "" @prop #74."kat1" 0 "" @prop #74."teeth" 0 "" @prop #74."tenta" 0 "" @prop #74."claw" 0 "" @prop #74."natweap" 0 "" @prop #74."scim" 0 "" @prop #74."wclim" 0 "" @prop #74."last_action" 0 "" @prop #74."throw" 0 "" @prop #74."furn" 0 "" @prop #74."paralyzed" 0 "" @prop #74."ecacc" 0 "" @prop #74."scyth" 0 "" @prop #74."swim" 0 "" @prop #74."econf" 0 "" @prop #74."etrap" 0 "" @prop #74."ecto" 0 "" @prop #74."gadget" 0 "" @prop #74."sanity" 0 "" @prop #74."ins" 0 "" @prop #74."wearing" {} r @prop #74."wielding" {} r @prop #74."climb" 0 "" @prop #74."staff" 0 "" @prop #74."firebolt" 0 "" @prop #74."fire" 0 "" @prop #74."magic" 0 "" @prop #74."kites" 0 "" @prop #74."shield" 0 "" @prop #74."thswd" 0 "" @prop #74."kat" 0 "" @prop #74."rap" 0 "" @prop #74."size" 10 "" @prop #74."tclub" 0 "" @prop #74."thhft" 0 "" @prop #74."ohhfw" 0 "" @prop #74."club" 0 "" @prop #74."character" 0 r @prop #74."shock" 0 "" @prop #74."dodge" 0 "" @prop #74."slowness" 10 "" @prop #74."act" 0 "" @prop #74."aggressor" {} "" @prop #74."brswd" 0 "" @prop #74."ohswd" 0 "" @prop #74."melee" 0 "" @prop #74."pot" 0 "" @prop #74."inj" 0 "" @prop #74."app" 0 "" @prop #74."pcn" 0 "" @prop #74."wil" 0 "" @prop #74."emp" 0 "" @prop #74."int" 0 "" @prop #74."agl" 0 "" @prop #74."dex" 0 "" @prop #74."end" 0 "" @prop #74."str" 0 "" @prop #74."lockpick" 0 "" @prop #74."last_attack" 728204129 r @prop #74."spellsing" 0 "" @prop #74."attack_forked" 0 r @prop #74."hands" 2 r @prop #74."teleport" 0 "" @prop #74."charm" 0 "" @prop #74."recall" 0 "" @prop #74."pacify" 0 "" @prop #74."fat" 0 "" @prop #74."stamina" 0 "" @prop #74."body_areas" {} r ;;#74.("body_areas") = {#39284, #61605, #51172, #60746, #61688, #52374, #47817} @prop #74."combat_effects" {} "" @prop #74."death_effects" {} "" @prop #74."longsword" 0 "" @prop #74."misc_notes" {} "" @prop #74."thieving" 0 "" @prop #74."natural_weapons" {} r ;;#74.("natural_weapons") = {#9130} @prop #74."claimed_objects" {} r @prop #74."max_claims" 21 r @prop #74."unarmed" 0 "" @prop #74."brawl" 0 "" @prop #74."moofu" 0 "" @prop #74."magic_effects" {} "" ;;#74.("key") = 0 ;;#74.("aliases") = {"PC", "generic", "voodoo", "doll"} ;;#74.("description") = "A little humanoid doll hung from a peg on the wall. Every now and then it twitches feebly." ;;#74.("object_size") = {81759, 819192190} @verb #74:"get" this none none rxd @program #74:get player:tell("As you approach the voodoo doll, a little hooded man shouts at you to leave it alone and starts beating you with a cane stick until you do."); . @verb #74:"attack" this any none rx @program #74:attack ":attack(OBJ target, LIST weapons[, NUM modifier, OBJ area, NUM no_invite])"; if (!$local.rpg:trusted(caller_perms())) return E_PERM; endif by = this.character; target = args[1]; weapons = (typeof(w = args[2]) == LIST) ? w | {w}; weapon = weapons[1]; weapons = listdelete(weapons, 1); if (typeof(effect = this:combat_effects(target, weapon)) != NUM) return effect; endif bmods = (((argc = length(args)) > 2) && (typeof(args[3]) == NUM)) ? args[3] | 0; bmods = bmods + effect; if (!this:legal_target(target, doll = $local.rpg:get_doll(target), caller)) return; endif if ((!valid(weapon)) || (typeof(use = weapon:used(by, target)) != NUM)) "If :used returns a non-numeric value, the weapon is unusable."; return; endif this:do_attack_notification(target, weapon); barea = ((argc > 3) && (typeof(args[4]) == OBJ)) ? args[4] | doll:random_hit_lo cation(); weapon:announce_swing(by, target); if (doll.end <= 0) target:room_announce_all("The blow passes through ", target.name, " without visible effect."); return; endif weap_slow = weapon:slowness(by, target); weap_dam = weapon:dam(by, target); attack_bonus = weapon:attack(by, target); mods = ((bmods + use) + attack_bonus) - (length(weapons) * 10); if ((typeof(by.location.space) == NUM) && ((z = weapon:length(by, target) - by.location.space) > 0)) "'z' is the difference between room length and weapon length."; mods = mods - (3 * z); damage = (2 * (weap_dam - z)) + this.str; if ((((z > 3) && is_player(by)) && (((time() - this.last_action) > 10) || (random(20) == 1))) && (length(callers()) < 3)) by:tell("The room is a little small to ", weapon.swing, " your ", weapon.name, " properly."); endif else damage = (2 * weap_dam) + this.str; endif "Damage will never be greater than 3 * base."; damage = min(damage, 3 * weap_dam); "'y' is encumbrance penalty of the weapon. Wielding a heavy weapon with more than one hand reduces the total penalty."; "A weak person wielding a heavy weapon will be greatly penalized."; y = this.str - (((3 * weapon:encumbrance(this)) / 5) / (1 + weapon:hands(by, target))); if (y < 0) mods = mods + (5 * y); damage = damage + (y / 2); endif connects = (qual = weapon:skill(by, target):resolve(by, mods)) > -25; if (connects) doll:respond(by, qual, damage, weapon, barea); endif if ((!connects) && (!weapon:critical_miss(by, target, qual))) "No critical miss."; weapon:announce_miss(by, target, qual); endif if (weapons && valid(this)) this.aggressor = setadd(this.aggressor, target); "this:invite(this.slowness + weap_slow, {1, by, target})"; this.act = this.act + this.slowness; "return this:attack(target, weapons, bmods - 10)"; this:attack(target, weapons, bmods - 10); endif no_invite = ((length(args) > 4) && (typeof(args[5]) == NUM)) ? args[5] | 0; if (valid(doll) && (!no_invite)) doll.aggressor = setadd(doll.aggressor, by); doll:invite(this.slowness + (valid(weapon) ? weapon:slowness(by, target) | 0), {1, by, target, weapon}); endif "Quinn 05-JAN-93: Use verbs for referencing weapon properties."; "Quinn 28-FEB-93: Won't fork notification if a fork is already pending."; "Quinn 11-AUG-93: Big re-write. Created :legal_target and :do_attack_notifica ion to do the mundane chore of checking and notifying targets; cut down the unwieldly verb size; added some minor comments."; "Quinn 11-AUG-93: Send weapon to :respond."; "Quinn 22-OCT-93: Added combat_effect."; "Quinn 19-NOV-93: Added body area support, :critical_miss. New args to :Respond."; "Ogwul 01-JAN-94: Allowed :attack to be called without adding the target to the aggressor list and without :invite via the no_invite parameter."; . @verb #74:"invite" this any none rxd @program #74:invite ":invite(NUM slowness[, LIST some_arcane_value_nobody_ever_documented])"; if (!$local.rpg:trust()) return E_PERM; elseif (!valid(where = (by = this.character).location)) return this.act = 0; endif slow = args[1]; this.act = (this.act + slow) - (this:encumbrance() / 10); temp = $local.rpg:find_chars(by.location); for doll in (dolls = temp[2]) doll:check_schedule(); endfor things = temp[1]; min = $maxint; for doll in (dolls) if ((doll.act < min) && doll.free_will) min = doll.act; endif endfor if (min == $maxint) for doll in (dolls) doll.act = doll.slowness / 2; endfor return; else for doll in (dolls) doll.act = doll.act - min; endfor endif max = -1; for doll in (dolls) which = doll; if ((valid(doll) && ((!is_player(things[doll in dolls])) || (doll.act > (2 * doll.slowness)))) && ((doll.act - doll.slowness) > max)) max = doll.act - doll.slowness; which = doll; endif endfor value = 0; if (max < 0) return; endif if ((ticks_left() >= 8000) && (seconds_left() >= 2)) "if (!$command_utils:running_out_of_time())"; value = "act"; this:act(); else return; fork (0) this:act(); value = "act"; endfork endif return value; "Quinn 12-OCT-93 0358: Major cleanup re-write of the code."; "MAJOR CHANGE: Scheduled events now fire at an absolute time. Firing times are not decremented with each check, as before. Changed slow and forcewall to account for this. May break old code."; "Quinn 15-JUN-94 1857: Moved schedule checking to :check_schedule."; "Isagi 10-23 12:20P -- Commented out the return in line 41, now everything will attack no matter what."; "Isagi 11-19-94 2:10P -- Put the return back into line 41 [Or thereabouts]"; "StarDancer 11-17-95 02:07 EST -- Historical note, the list values for args[2] were NUM (true-false) respond, OBJ attacker, OBJ target. Values deduced from code in/on ghosts, and Ghostbuster weapons/equipment."; . @verb #74:"hit_aggressor" this any none rx @program #74:hit_aggressor me = this.character; here = me.location; rpg = $local.rpg; if (this.aggressor = setremove(this.aggressor, me)) "if (((this.wielding == {}) && (!is_player(me))) && (this:wielding() == this.natural_weapons))"; if (0) this:arm(); return $failed_match; else weapon = this:wielding()[1]; if ($object_utils:isa(weapon, #8816) && (weapon.loaded <= 0)) weapon:do_load(me, this); return $failed_match; endif endif if (($object_utils:isa(weapon, #8816) && (weapon.loaded > 0)) && $object_utils:isa(here, #258)) here = here:missile_dests(me); else here = {here}; endif while (this.aggressor) targ = me:pick_aggressor(); if (!valid(targ)) targ = this.aggressor[random(length(this.aggressor))]; endif if (targ.location in here) this:attack(targ, weapon); return targ; else this.aggressor = setremove(this.aggressor, targ); endif endwhile endif this:set_att("act", 0); return $nothing; "DR 17-AUG-94 -- Changed line 4 (if around :arm) to keep monsters checking for other non .natural_weapons weapons ... also takes out PC autowielding since they have fists now."; "Isagi 10-15-94 8:30P -- Fixed code that didn't let monsters rewield weapons, added check for PICK_AGGRESSOR verb on attacker to choose a target to attack."; "Isagi 10-23-94 11:10A -- Took out arm checking code that prevented monsters only using their .natural_weapons from attacking."; . @verb #74:"respond" this any none rx @program #74:respond ":respond(attacker, quality, damage, weapon, loc)"; "attacker -> character initiating the attack"; "quality -> quality of the attack (final hit roll)"; "damage -> damage to be applied"; "weapon -> weapon used to attack"; "loc -> body area object of hit location"; if (!$local.rpg:trusted(caller_perms())) return E_PERM; elseif (typeof(args[4]) != OBJ) return this:respond_passed_numbers(@args); endif by = args[1]; me = this.character; qual = args[2]; weapon = args[4]; loc = args[5]; locstr = loc:title(me); dodgable = weapon:dodgable(by, me); parryable = weapon:parryable(by, me) + loc:parry_mod(me, by, weapon); best = hand = try = 0; space = by.location.space; for thing in (this:wielding()) mods = (thing:parry(me, by) - qual) + parryable; length = thing:length(me, by); if (space && (space < length)) mods = mods - (3 * (length - space)); endif hand = hand + thing:hands(me, by); if (typeof(u = thing:used(me, by)) == NUM) try = thing:skill(me, by):resolve(me, mods + u); if ((best = max(best, try)) > 0) weapon:notify_parry(by, me, locstr, thing, qual, best); return thing:announce_parry(by, me, locstr, weapon, qual, best); endif endif endfor if (hand < 3) mods = ((((25 * (2 - hand)) - this.inj) - (2 * this:encumbrance())) - qual) + dodgable; try = $local.rpg:resolve(me, "dodge", mods); if ((best = max(best, try)) > 0) return weapon:announce_dodge(by, me, locstr); endif endif this:receive_damage(args[3] * (1 + random(3)), weapon:pen(by, me), qual, loc, by, weapon); "Quinn 17-FEB-93: hacked to send attacker to :receive_damage."; "Quinn 11-AUG-93: Receive weapon (if any) from caller and send to :Receive_damage."; "Quinn 22-OCT-93: Receive and send hit location. Removed some literal dodge resolve."; "Quinn 19-NOV-93: Major re-write. Cut a lot of kruft. Redirect old-style calls to :respond_passed_numbers."; "Profane 9-FEB-95 23:06EST: Added 'qual' and 'try' to :announce_parry call in preparation for weapon degrading."; "Profane 2-13-95 20:47EST: Added call to weapon:notify_parry for weapon damage hook."; . @verb #74:"set_att" this any none rxd @program #74:set_att ":set_att(att, val)"; "Sets the doll's `att' property to `val'."; RPG = $local.rpg; if (!RPG:trusted(caller_perms())) return E_PERM; elseif ($code_utils:verb_loc() == this) "Grand_Master can set $local.rpg.doll stats manually."; return E_NACC; elseif (RPG:approve_att_change(player, {this, @args}, callers()) == E_PERM) return E_PERM; endif return this.(args[1]) = args[2]; . @verb #74:"die" this any none rxd @program #74:die ":die([whoby])"; rpg = $local.rpg; if (!rpg:trusted(cp = caller_perms())) return E_PERM; endif victim = this.character; where = victim.location; if (typeof(effect = this:death_effects(@args)) != NUM) "If a :death_effect does not return a number, then abort the death."; return; endif contents = where:contents(); "Miles 5/25/94 placing contents() outside the fork as suggested by Dred"; fork (0) rpg:check_notification(contents, "notify_death", {victim, @args}); endfork if (is_player(victim)) rpg.owner:record_death(cp, @args); rpg:die(this); else victim:die(@args); endif . @verb #74:"receive_damage" this none this rx @program #74:receive_damage ":receive_damage(dam, pen, qual, hitloc, attacker, weapon)"; "dam -> damage to be applied"; "pen -> penetration of the weapon"; "qual -> quality of the attack (final hit roll)"; "hitloc -> body area object of hit location"; "attacker -> character initiating the attack"; "weapon -> weapon used to attack"; if (!$local.rpg:trusted(caller_perms())) return E_PERM; elseif (this.end <= 0) return 0; elseif ((dam = args[1]) <= 0) return 0; elseif (typeof(qual = args[3]) != NUM) "compat with the old arg syntax"; return this:receive_damage_passed_messages(@args); endif weapon = args[6]; me = this.character; whoby = args[5]; loc = args[4]; if (weapon:critical_hit(whoby, me, qual, loc, dam)) "weapon handled a critical hit"; return; endif pen = args[2]; locstr = loc:title(me); protection = this:armour(pen, loc, whoby, weapon, dam); dam = (dam - protection) / this.size; if (dam <= 0) armour = this:wearing(loc) || {$local.rpg.armour}; weapon:notify_clang(whoby, me, loc, armour[1], qual); armour[1]:announce_clang(whoby, me, locstr, weapon, qual); return -1; endif special_damage = weapon:special_damage(me, dam, pen, qual, loc, whoby) || 0; this.inj = (this.inj + dam) + special_damage; sev = (2 * (dam + special_damage)) / this.end; bad = {"scratched", "slightly wounded", "hit", "hit", "hit", "severely wounded"}[min(sev + 1, 6)]; shockmod = loc:shock_mod(me, whoby, weapon); stunmod = loc:stun_resistance(me, whoby, weapon); try = $local.rpg:resolve(me, "shock", shockmod); if (try > (-2 * this.end)) weapon:announce_hit(whoby, me, locstr, bad, 0); return -2; elseif (try > ((-4 * this.end) - stunmod)) weapon:announce_hit(whoby, me, locstr, bad, 1); this.act = max(this.act - 20, -20); return -3; else weapon:announce_kill(whoby, me, locstr); this:die(whoby); return -9; endif "Quinn 11-AUG-93 0958: Hacked to send attacker and weapon to :armour."; "Quinn 18-NOV-93 0510: Big re-write slimmed and trimmed. Added support for new hit location stuff. Messages now handled by armour/weapons."; "DR 04-APR-94 -- Added call to weapon:notify_clang() to support weapons degradation and other special effects."; "DR 24-APR-94 -- Added special_damage() addition to the total inj incurred."; "Miles 6/16/94 added args to :special_damage(me) requested by Taskmaster"; "DR 03-AUG-94 -- Added special_damage to severity of wound."; "Isagi Christmas-94 Added whoby parameter to special_damage hook"; "Profane 2/9/95 23:08EST - Added weapon and qual to args of :announce_clang call in preparation for armour degrading."; "Profane 6-APR-95 15:09EST - Added `|| 0' onna end of line 36 so we stop getting E_TYPE in doll's .inj properties."; . @verb #74:"act" none none none rxd @program #74:act if (is_player(who = this.character) || (!$local.rpg:trusted_verb(who, verb))) this:hit_aggressor(@args); else who:(verb)(@args); endif "DR 23-NOV-94 -- Put in :act() call for monsters. Where had it gone?"; "Profane 1/30/95 20:20EST - rewrote to save a few ticks over using $object_utils:isa and check trustworthiness of monster :act verbs."; . @verb #74:"check_ins" this none this @program #74:check_ins ":check_ins(amount) -> Test the character's sanity."; if (!$local.rpg:trusted(caller_perms())) return E_PERM; endif by = this.character; this.ins = this.ins + ((args[1] * 3) / this.wil); qual = $local.rpg:resolve(by, "sanity", 55 - args[1]); if (qual < -50) this.act = this.act - 30; this.ins = this.ins + 25; by.location:announce_all(by.name, "'s eyes glaze over, and ", by.ps, " begins to gibber."); elseif (qual < 0) this.act = this.act - 15; this.ins = this.ins + 4; by.location:announce_all(by.name, " holds ", by.pp, " head and screams in mental anguish."); endif . @verb #74:"armour" this none this @program #74:armour ":armour(penetration, hit-location[, attacker, weapon-used, damage]) => NUM amount of protection this.character has at hit-location."; RPG = $local.RPG; if (!RPG:trusted(caller_perms())) return E_PERM; endif if (info = this:read_misc_note("force_wall")) damage = (length(args) > 4) ? args[5] | 0; caster = valid(info[1]) ? info[1].character | this.character; plus = RPG:resolve(caster, "forcewall", damage); if (plus < 15) if (random(5) == 1) caster:tell(("You struggle to maintain the wall of force around " + this.character.name) + "."); $you:say_action("The shield of magical force around %n fluctuates with the force of the blow.", this.character); endif this:check_fatigue(damage); plus = 0; else plus = max(damage / 2, 25); endif else plus = 0; endif if (RPG:trusted_verb(char = this.character, "armour")) return char:armour(@args) + plus; else return this:protection(@args) + plus; endif "Quinn 22-OCT-93 0329: Hacked to use the new :trusted_verb."; "Quinn 25-Sep-94 0756: Hacked in the new force-wall bonus."; "Profane 1/30/95 20:37EST - changed `caster' to `this.character' in the $you:say_action, which I THINK is what it was supposed to be. Expanded comment."; . @verb #74:"protection" this none this @program #74:protection ":protection(penetration, hit-location, attacker, weapon-used, dam)"; pen = args[1]; loc = args[2]; attacker = args[3]; weapon = args[4]; dam = args[5]; r = random(100); max = 0; me = this.character; protargs = {attacker, me, weapon, loc, pen, dam}; for armour in (this.wearing) protection = armour:protection(@protargs); if ((armour:cover(loc) > r) && (max < protection)) max = protection; endif endfor shield = $local.rpg.shield; if (((loc == 4) && (max < 10)) && (r < 75)) for q in (this.wielding) if ($object_utils:isa(q, shield)) max = 10; endif endfor endif return max(pen * max, 0); "Quinn 11-AUG-93 1010: Re-written to send attacker and weapon (if given) to the new armour:protection() verb; changed literal shield reference to $local.rpg.shield"; "Quinn 16-OCT-93 0115: Use armour:cover verb instead of propref."; . @verb #74:"encumbrance" none none none rx @program #74:encumbrance ":encumbrance() -> Total encumbrance of this character. Usually [0..10]."; char = this.character; if (((load = char:encumbrance()) && (char.owner in $local.rpg.gms)) && (load != E_VERBNF)) return load; elseif (!(strength = this.str)) return 0; elseif (typeof(this.weight) == NUM) return this.weight / strength; else return (this.weight = $local.rpg:weight(char, this) + (strength / 2)) / strength; endif "Quinn 21-AUG-93 0706: Hacked to return character:encumbrance if exists and is owned by a GM."; "Profane 2/5/95 13:48EST - fixed use of `STR' as a variable name."; "StarDancer Oct 21 06:39 1995 PDT - took out call to $object_utils:has_callable _verb, made verb !d"; . @verb #74:"get_att" none none none rxd @program #74:get_att return (caller_perms() in $local.rpg.gms) ? this.(args[1]) | E_PERM; . @verb #74:"schedule" this none this @program #74:schedule ":schedule(OBJ object, STR verb, NUM time, LIST args)"; "Schedule this doll to call object:(verb)(@args) at time."; "The time is approximate, since the schedule is checked only when :invite is called."; if (!$local.rpg:trusted(caller_perms())) return E_PERM; endif this.schedule = listappend(this.schedule, args); . @verb #74:"cancel" this none this @program #74:cancel ":cancel(LIST schedule element)"; if ($local.rpg:trust()) this.schedule = setremove(this.schedule, args); endif . @verb #74:"get_schedule" this none this @program #74:get_schedule if (args == {}) return this.schedule; else r = {}; for w in (this.schedule) if (w[1] == args[1]) r = listappend(r, w); endif endfor return r; endif . @verb #74:"recycle" this none this @program #74:recycle if ($perm_utils:controls(caller_perms(), this)) if (z = this in $local.rpg.dolls) $local.rpg.pcs = listdelete($local.rpg.pcs, z); $local.rpg.dolls = listdelete($local.rpg.dolls, z); endif pass(@args); else return E_PERM; endif . @verb #74:"arm" this none this rx @program #74:arm "Grab a weapon and wield it. Called when an unarmed character is attacked."; me = this.character; if (this.wielding || ($local.rpg:trusted_verb(me, verb) && me:(verb)())) "Either character is already wielding a weapon, or"; "The character's :arm verb has taken care of it."; return E_NONE; endif weapon = $local.rpg.weapon; for w in (me:contents()) if ($object_utils:isa(w, weapon) && (this:hands_free() >= w.hands)) this.wielding = {w}; me:tell("You ", w.wield, " your ", w.name, "."); me.location:announce_all_but({me}, $string_utils:pronoun_sub(((("%n %<" + w.owield) + "> %p ") + w:title()) + ".", me)); " this:invite((this.slowness + w:slowness()) / 3, {2, w})"; " w:wield() "; return; endif endfor this.act = 0; "DR 01-AUG-94 -- Just call weapon:wield instead of doing it manually."; "Profane 1/30/95 20:29EST - added trustworthiness check for custom :arm verbs."; . @verb #74:"resolve_attack" this none this @verb #74:"total" this none this @program #74:total ":total(skill) -> Total (percentage-based) rank for the given skill."; "Governing attributes are totaled and added to the raw rank for 'skill', then governing skills are each :totaled in turn and the final sum is returned."; if (!(caller_perms() in $local.rpg.gms)) return E_PERM; endif att_obj = $local.rpg:match_skill(args[1]); skill = this.(att_obj.aliases[1]); deps = att_obj.dependant; for dep_att in (deps[1]) skill = skill + this.(dep_att.aliases[1]); endfor for dep_att in (deps[2]) skill = skill + this:total(dep_att); endfor return skill; . @verb #74:"improve" this none this @program #74:improve ":improve(skill) Make a check for improvement of the given skill."; "Character has a 1 in skill.learn chance of improvement for each skill."; " Skills will not naturally raise higher than 25."; " If a skill is maxed, player has a chance of gaining potential; a chance decreasing with the amount e's been given thus far."; "If 'skill' did not improve, the same process is repeated for one of the skills that control it, and so on."; if (!(caller_perms() in $local.rpg.gms)) return E_PERM; elseif (((ease = (skill = args[1]).learn) > 0) && (random(ease) == 1)) skill_prop = skill.aliases[1]; if ((skill_val = this.(skill_prop)) < random(25)) this.(skill_prop) = skill_val + 1; elseif (random(500) > this.total) this.total = this.total + 1; this.pot = this.pot + 1; endif elseif (deps = {@skill.dependant[1], @skill.dependant[2]}) this:improve(deps[random(length(deps))]); endif "Quinn 11-AUG-93 0923: Added comments."; . @verb #74:"magic_effect(old)" this none this @program #74:magic_effect(old) ":magic_effect(OBJ caster doll, OBJ target doll, NUM spell quality, OBJ spell skill) -- Check any objects effecting the target magically, and eir `magic resistance'."; qual = args[3]; if (typeof(effect = this.magic_effect) == OBJ) effect = effect:magic_effect(@args); return qual - effect; else if ((qual = qual - effect) <= 0) args[2].character.location:announce_all(args[2].character.name, " seems unaffected by the spell."); endif return qual; endif . @verb #74:"moveto" this none this @program #74:moveto if ($local.rpg:trust()) return pass(@args); else player:tell("From ", this, " (#74:moveto). You have no business messing with the doll anyway, get a GM to move it for you if perchance it is bothering you."); endif . @verb #74:"mod_att" this none this @program #74:mod_att ":mod_att(STR attribute, NUM value[, NUM min_value[, NUM max_value]])"; " Modifies the given attribute by `value', keeping it greater than or equal to min_value, and less than or equal to max_value. Default min_value is -$maxint. Default max_value is $maxint."; " => E_NACC, if this is the generic doll."; " => E_TYPE, if attribute is not numerical."; " => E_INVARG, if any argument 2.. isn't numerical."; " => new_value, if all was successful."; RPG = $local.rpg; if (!RPG:trusted(caller_perms())) return E_PERM; elseif ($code_utils:verb_loc() == this) return E_NACC; elseif (typeof(old = this.(att = args[1])) != NUM) return E_TYPE; elseif (typeof(mod = args[2]) != NUM) return E_INVARG; elseif (RPG:approve_att_change(player, {this, att, old + mod}, callers()) == E_PERM) return E_PERM; elseif ((la = length(args)) == 2) return this.(att) = old + mod; endif min = ((la > 2) && (typeof(x = args[3]) == NUM)) ? x | (-$maxint); max = ((la > 3) && (typeof(x = args[4]) == NUM)) ? x | $maxint; return this.(att) = min(max(old + mod, min), max); . @verb #74:"long_enough" this none this @program #74:long_enough "Checks to see if enough time has elapsed for this character to attempt another RPG action."; " $local.rpg.lag_standard => Sum of 10 samples considered to be heavy-lag."; " $local.rpg.min_command_interval => Default wait-time."; "Phantom revision 3-26-93 (20:22 PST)--make lag response more dynamic"; "Quinn 29-JUL-93 0335-ET: moved lag_standard and min_command_interval to $local.rpg."; db = $local.rpg; interval = max(db.rpg_lag_sum / db.lag_standard, db.min_command_interval); return (time() - this.last_attack) > interval; . @verb #74:"wearing" this none this rx @program #74:wearing ":wearing([STR|OBJ body_area])"; "If a body area is given (either by object or name), return clothing worn on that area. Else, return the entire property value."; if (!args) return this.wearing; endif area = args[1]; area = (typeof(area) == OBJ) ? area | this:match_body_area(area); duds = {}; for dud in (this.wearing) if (dud:cover(area)) duds = {@duds, dud}; endif endfor return duds; "Quinn 08-MAR-93 xxxx: Added."; "Quinn 18-NOV-93 0404: Use objects/strings instead of indices."; . @verb #74:"hit_location_names" this none this rx @program #74:hit_location_names "Returns hit location names of this doll -- either a property on the doll's character, or the hard-coded default. This verb must be !d. --Quinn (11-MAR-93) after the big crash...SIGH"; return this.character.locations || {"head", "chest", "abdomen", "left arm", "right arm", "left leg", "right leg"}; . @verb #74:"hands_free" this none this @program #74:hands_free ":hands_free() => How many hands this character has free, subtracting total hands from those required for all wielded weapons."; "Actually, this should be hacked even further, to count all unsheathed weapons as being carried, and thus in the character's hands. Realistic, but sticky with regards to monster setup, and the potential to be quite annoying."; hands = this.hands; for w in (this.wielding) hands = hands - w.hands; endfor return max(hands, 0); "Quinn 29-JUL-93 0107-ET: Added."; . @verb #74:"legal_target(nomissile)" this none this @program #74:legal_target(nomissile) ":legal_target(target)"; "=> True if this character may attack 'target'"; "=> Else explain the failure and return false."; by = this.character; target = args[1]; doll = listdelete(args, 1) ? args[2] | $local.rpg:get_doll(target); if (by == target) by:tell("If you want to commit seppuku there are cleaner and neater ways."); elseif (p = this.paralyzed) if (typeof(p) == STR) by:tell(p); endif elseif (!valid(doll)) by:tell($string_utils:pronoun_sub("At the last moment, you realise %n isn't worth killing, and spare %p worthless life.", target)); elseif (is_player(target) && (!(target in connected_players()))) by:tell("Attack a comatose player? Forget it, you evil swine."); elseif ((!(by in target.location:contents())) && (!(target in this.aggressor))) "Allow characters to attack a distant target only if it is 'hated'. This check is to catch problems with phantom attacks after fleeing a battle."; "Perhaps hack this to check if the weapon used is a missile weapon?"; else return 1; endif "Quinn 11-AUG-93 0900: Added. Different message when attempting to attack an unconnected player."; "Quinn 22-AUG-93 1409: Use :contents instead of .location check, to provide for metaroom support."; . @verb #74:"do_attack_notification" this none this @program #74:do_attack_notification ":do_attack_notification(target, weapon)"; "Do notification of this character attacking 'target' with 'weapon'."; if (!(caller_perms() in $local.rpg.gms)) return E_PERM; endif by = this.character; target = args[1]; weapon = args[2]; "Notify both rooms if target is not in character's location."; if (target.location != by.location) folks_list = {@by.location:contents(), @target.location:contents()}; else folks_list = {@by.location:contents()}; endif "Do an extra :notify_aggression if character is drawing first blood."; if (!(target in this.aggressor)) notlist = {"notify_aggression", "notify_attack"}; else notlist = {"notify_attack"}; endif notargs = {setremove(folks_list, by), "", {by, target, weapon}}; "If another notification is pending, do the new notification without forking."; if ($code_utils:task_valid(this.attack_forked)) for notverb in (notlist) $local.rpg:check_notification(@listset(notargs, notverb, 2)); endfor else fork af (min(abs($login:current_lag()), 5)) "Froxx 4/11/94: suspend according to lag"; "Miles 6/16/94: $login:current_lag() => -1 so added abs() ..."; "... suggested fix by Dred ..."; for notverb in (notlist) $local.rpg:check_notification(@listset(notargs, notverb, 2)); endfor endfork this.attack_forked = af; endif "Quinn 11-AUG-93 0902: Added. :notify_aggression is now called correctly."; . @verb #74:"protection(old)" this none this @program #74:protection(old) pen = args[1]; loc = args[2]; r = random(100); max = 0; for foo in (this.wearing) if ((foo.cover[loc] > r) && (max < foo.protection)) max = foo.protection; endif endfor if (((loc == 4) && (max < 10)) && (r < 75)) for q in (this.wielding) if ($object_utils:isa(q, #3451)) max = 10; endif endfor endif return max(pen * max, 0); "...Following line bypassed so negative penetration isn't returned..."; return pen * max; . @verb #74:"check_fat*igue" this none this @program #74:check_fatigue ":check_fat(amount) -> Test the character's stamina."; if (!$local.rpg:trusted(caller_perms())) return E_PERM; endif by = this.character; this.fat = this.fat + ((args[1] * 3) / (((this.end * 7) + (this.wil * 3)) / 10)); qual = $local.rpg:resolve(by, "stamina", 55 - args[1]); if (qual < -50) this.act = this.act - 40; this.fat = this.fat + 25; by.location:announce_all(by.name, " staggers wearily, tongue wagging and knees buckling with weariness."); elseif (qual < 0) this.act = this.act - 20; this.fat = this.fat + 4; by.location:announce_all(by.name, " wipes ", by.pp, " brow and pants heavily."); endif . @verb #74:"invite(old)" this any none rxd @program #74:invite(old) if (!$local.rpg:trust()) return E_PERM; endif by = this.character; if (!valid(by.location)) this.act = 0; return; endif slow = args[1] + (this:encumbrance() / 10); dolls = {}; things = {}; this.act = this.act - slow; temp = {}; temp = $local.rpg:find_chars(by.location); things = temp[1]; dolls = temp[2]; min = 999; toady = $local.rpg.toady; for doll in (dolls) schedule = doll.schedule; doll.schedule = {}; for q in (schedule) t = q[3] - (slow * 10); if (t <= time()) "Commented out the following, since it would allow recycling of dolls."; "q[1]:(q[2])(doll, @q[4]);"; toady:call_verb(q[1], q[2], {doll, @q[4]}); else doll.schedule = listappend(doll.schedule, {q[1], q[2], t, q[4]}); endif endfor endfor for doll in (dolls) if ((doll.act < min) && doll.free_will) min = doll.act; endif endfor if (min == 999) for doll in (dolls) doll.act = doll.slowness / 2; endfor return; else for doll in (dolls) doll.act = doll.act - min; endfor endif max = -1; for doll in (dolls) if ((valid(doll) && ((!is_player(things[doll in dolls])) || (doll.act > (2 * doll.slowness)))) && ((doll.act - doll.slowness) > max)) max = doll.act - doll.slowness; which = doll; endif endfor if (max >= 0) if ($object_utils:has_verb(who = which.character, "act")) if (((is_player(who) && (!is_player(by))) && (max < (which.slowness * 2))) || $local.rpg:time_trouble()) fork (0) if ((valid(which) && valid(who)) && (which.act > which.slowness)) who:act(which); endif endfork else who:act(which); endif else if (((is_player(who) && (!is_player(by))) && (max < (which.slowness * 2))) || $local.rpg:time_trouble()) fork (0) if (valid(which) && (which.act > which.slowness)) which:hit_aggressor(); endif endfork else which:hit_aggressor(); endif endif endif . @verb #74:"match_body_area" this none this @program #74:match_body_area ":match_body_area(STR name) -> OBJ body-area-object"; return $string_utils:match(args[1], this.body_areas, "aliases"); "Quinn 18-NOV-93 0201: Added."; . @verb #74:"random_hit_location" this none this rx @program #74:random_hit_location ":random_hit_location() -> {OBJ body_area[, ...]}"; "Determine which body area the attack has hit."; if ($local.rpg:trusted_verb(c = this.character, verb)) return c:(verb)(@args); endif areas = this.body_areas; while (length(areas) > 1) where = areas[random(length(areas))]; if (random(100) <= where.chance) return where; endif areas = setremove(areas, where); endwhile return areas[1]; "Quinn 18-NOV-93 0201: Added."; . @verb #74:"respond_passed_numbers" this any none rx @program #74:respond_passed_numbers if (!$local.rpg:trust()) return E_PERM; endif by = args[1]; qual = args[2]; dam = args[3]; pen = args[4]; dodgable = args[5]; parryable = args[6]; "Quinn 11-AUG-93 0948: Receive weapon (if any) from caller."; weapon = (length(args) > 6) ? args[7] | $nothing; me = this.character; best = 0; hand = 0; for thing in (this:wielding()) mods = (thing:parry(me, by) - qual) + parryable; if ($object_utils:has_property(by.location, "space")) if (by.location.space < (length = thing:length(me, by))) mods = mods - (3 * (length - by.location.space)); endif endif "try = (u = thing:used(by, me)) ? -1 | thing:skill(me, by):resolve(me, mods);"; "Quinn 10-AUG-93 0111-ET: Replaced the above with the below. okay?"; try = (typeof(u = thing:used(me, by)) != NUM) ? -1 | thing:skill(me, by):resolve(me, mods + u); hand = hand + thing:hands(me, by); if (try > best) best = try; omsg = ((("parries with " + me.pp) + " ") + thing.name) + "."; msg = ("You parry with your " + thing.name) + "."; endif endfor if (hand < 3) mods = ((((25 * (2 - hand)) - this.inj) - (2 * this:encumbrance())) - qual) + dodgable; try = #19856:resolve(me, mods); if (try > best) best = try; omsg = "dodges."; msg = "You dodge."; endif endif if (best > 0) me.location:announce_all_but({me}, me.name, " ", omsg); me:tell(msg); else "Quinn 17-FEB-93: hacked to send attacker"; "Quinn 11-AUG-93: hacked to send weapon (if any)"; this:receive_damage(dam * (1 + random(3)), pen, "Your armoured %w deflects the blow.", ("The blow is stopped by the armour on " + me.name) + "'s %w.", "You are %b on the %w.", me.name + " is %b on the %w but keeps fighting.", "You are %b on the %w and briefly stunned.", me.name + " is %b on %p %w and stunned.", by.name + " has killed you! Your soul is returned to the cycle of transmigrations.", ((by.name + " killed ") + me.name) + "!", by, weapon); endif . @verb #74:"receive_damage_passed_messages" this none this rx @program #74:receive_damage_passed_messages if (!$local.rpg:trust()) return E_PERM; elseif (this.end <= 0) return 0; endif whoby = ((la = length(args)) > 10) ? args[11] | $nothing; weapon = (la > 11) ? args[12] | $nothing; dam = args[1]; me = this.character; pen = args[2]; if (dam <= 0) return 0; endif "...hacked to use hit_location_names 11-MAR-93 quinn..."; places = this:hit_location_names(); loc = {1, 2, 2, 3, 3, 4, 5, 6, 6, 7, 7}[random(11)]; mess = {}; for k in (args) mess = listappend(mess, strsub(tostr(k), "%w", places[loc])); endfor mess = {@mess, "", "", "", "", "", "", "", ""}; clang = mess[3]; oclang = mess[4]; wound = mess[5]; owound = mess[6]; stun = mess[7]; ostun = mess[8]; kill = mess[9]; okill = mess[10]; "Quinn 11-AUG-93 0958: Hacked to send attacked and weapon to :armour."; dam = (dam - this:armour(pen, loc, whoby, weapon, dam)) / this.size; if (dam <= 0) if (clang) me:tell(clang); endif if (oclang) $local.rpg:rpg_announce_all_but(me.location, {me}, $string_utils:pronoun_su b(oclang, me)); endif return -1; endif this.inj = this.inj + dam; if (!(bad = (2 * dam) / this.end)) bad = "scratched"; elseif (bad == 1) bad = "slightly wounded"; elseif (bad < 4) bad = "hit"; else bad = "seriously wounded"; endif try = $local.rpg:resolve(me, #19835, -{0, 10, 0, 20, 20, 20, 20}[loc]); if (try > (-2 * this.end)) if (wound) me:tell(strsub(wound, "%b", bad)); endif if (owound) $local.rpg:rpg_announce_all_but(me.location, {me}, $string_utils:pronoun_su b(strsub(owound, "%b", bad), me)); endif return -2; elseif (try > ((-4 * this.end) - {20, 40, 50, 80, 80, 55, 55}[loc])) if (stun) me:tell(strsub(stun, "%b", bad)); endif if (ostun) $local.rpg:rpg_announce_all_but(me.location, {me}, $string_utils:pronoun_su b(strsub(ostun, "%b", bad), me)); endif this.act = this.act - 20; if (this.act < -20) this.act = -20; endif return -3; else if (kill) me:tell(kill); endif if (okill) $local.rpg:rpg_announce_all_but(me.location, {me}, $string_utils:pronoun_su b(okill, me)); endif this:die(whoby); return -9; endif "StarDancer 26-NOV-1995 -- replaced location:announce with :rpg_announce."; . @verb #74:"die(old)" this any none rxd @program #74:die(old) if (!$local.rpg:trust()) return E_PERM; endif victim = this.character; "record location so that we notify correct objects of death in fork below"; " -quinn (01-FEB-93)"; location = victim.location; fork (0) for character in (location.contents) if (character != victim) "hacked to send killer's object as well -quinn (03-FEB-93)"; $local.rpg:check_notification(character, "notify_death", {victim, @args}); endif endfor endfork if (is_player(victim)) #2693:record_death(caller_perms(), @args); $local.rpg:die(this); else victim:die(@args); endif . @verb #74:"combat_effects" this none this rx @program #74:combat_effects ":combat_effect(target[, weapon])"; "Give the attacker's location, and any objects affecting em, a chance to influence combat."; "The `combat effects' property should be a list of objects whose :combat_effect verb will be called with the args (by, target, weapon)."; "If a non-Numeric value is returned by any object, the attack is cancelled."; "Else, the sum of all effects is returned as a mod to the attack."; rpg = $local.rpg; if (!rpg:trusted(caller_perms())) return E_PERM; endif by = this.character; target = args[1]; weapon = (length(args) > 1) ? args[2] | $local.rpg.weapon; effect = 0; if (rpg:trusted_verb(by.location, "combat_effect") && (typeof(effect = by.location:combat_effect(by, target, weapon)) != NUM)) "Room stopped the combat."; return effect; endif for effobj in (this.combat_effects) if (typeof(e = effobj:combat_effect(by, target, weapon)) != NUM) return e; else effect = effect + e; endif endfor return effect; . @verb #74:"death_effects" this none this rx @program #74:death_effects ":death_effect([killer])"; "Give the attacker's location, and any objects affecting em, a chance to influence eir death."; "The `death effects' property should be a list of objects whose :death_effect verb will be called with the args (corpse, killer). Killer may, in some cases, be $no_one."; "If a non-Numeric value is returned by any object, the death is cancelled. Any other value is, for now, discarded. It may apply to a shock check later, in case you'd like to return something."; "Keep in mind that the `%N has killed %d!' message has already been printed by the time the effect is called. Returning a non-numeric will prevent the recycling of the doll, but you'll have to announce your own explanations."; rpg = $local.rpg; if (!rpg:trusted(caller_perms())) return E_PERM; endif corpse = this.character; killer = args ? args[1] | $no_one; if (rpg:trusted_verb(corpse.location, "death_effect") && (typeof(effect = corpse.location:death_effect(corpse, killer)) != NUM)) "Room stopped the death."; return effect; endif effect = 0; for effobj in (this.death_effects) if (typeof(e = effobj:death_effect(corpse, killer)) != NUM) return e; else effect = effect + e; endif endfor return effect; . @verb #74:"initialize" this none this @program #74:initialize if ((caller == this) || $perm_utils:controls(caller_perms(), this)) pass(@args); $quota_utils:object_bytes(this); else return E_PERM; endif "Quinn 16-DEC-93 1300-ET: $quota_utils:object_size."; . @verb #74:"legal_target(old)" this none this @program #74:legal_target(old) ":legal_target(target)"; "=> True if this character may attack 'target'"; "=> Else explain the failure and return false."; by = this.character; target = args[1]; doll = listdelete(args, 1) ? args[2] | $local.rpg:get_doll(target); if (by == target) by:tell("If you want to commit seppuku there are cleaner and neater ways."); elseif (p = this.paralyzed) if (typeof(p) == STR) by:tell(p); endif elseif (!valid(doll)) by:tell($string_utils:pronoun_sub("At the last moment, you realise %n isn't worth killing, and spare %p worthless life.", target)); elseif (is_player(target) && (!(target in connected_players()))) by:tell("Attack a comatose player? Forget it, you evil swine."); elseif ((!(by in target.location:contents())) && (!(target in this.aggressor))) "Allow characters to attack a distant target only if it is 'hated'. This check is to catch problems with phantom attacks after fleeing a battle."; "Perhaps hack this to check if the weapon used is a missile weapon?"; else return 1; endif "Quinn 11-AUG-93 0900: Added. Different message when attempting to attack an unconnected player."; "Quinn 22-AUG-93 1409: Use :contents instead of .location check, to provide for metaroom support."; . @verb #74:"legal_target" this none this @program #74:legal_target ":legal_target(target, doll, weapon)"; "=> True if this character may attack 'target'"; "=> Else explain the failure and return false."; by = this.character; target = args[1]; doll = listdelete(args, 1) ? args[2] | $local.rpg:get_doll(target); weapon = (length(args) > 2) ? args[3] | #-1; if (by == target) by:tell("If you want to commit seppuku there are cleaner and neater ways."); elseif (p = this.paralyzed) if (typeof(p) == STR) by:tell(p); endif elseif (!valid(doll)) by:tell($string_utils:pronoun_sub("At the last moment, you realise %n isn't worth killing, and spare %p worthless life.", target)); elseif (is_player(target) && ((!$object_utils:connected(target)) || ((idle_seconds(target) > 180) && ((time() - doll.last_attack) > 180)))) "Quinn Sep-20-94 1340: Forbid attacks on players idle more than 3 minutes as well as those not connected."; "Quinn Sep-23-94 0721: Figure in last attack when considering idleness."; by:tell("Attack a comatose player? Forget it, you evil swine."); elseif (((valid(weapon) && (!(target in by.location:contents()))) && $object_utils:isa(weapon, #8816)) && ((dests = $code_utils:verb_or_property(by .location, "dests")) != E_PROPNF)) "Allow players with missile weapons to shoot non-hated targets in rooms"; "listed as valid target locations by other rooms with support for range"; "weapons...(whew!)"; for each_destination in (dests) if (target in each_destination:contents()) return 1; endif endfor return 0; elseif ((!(by in target.location:contents())) && (!(target in this.aggressor))) "Allow characters to attack a distant target only if it is 'hated'. This check is to catch problems with phantom attacks after fleeing a battle."; "Perhaps hack this to check if the weapon used is a missile weapon?"; else return 1; endif "Quinn 11-AUG-93 0900: Added. Different message when attempting to attack an unconnected player."; "Quinn 22-AUG-93 1409: Use :contents instead of .location check, to provide for metaroom support."; "DR 16-MAY-94 -- Reinstated missile weapon support."; . @verb #74:"attack_new" this none this rx @program #74:attack_new ":attack(OBJ target, LIST weapons[, NUM modifier, OBJ area, NUM no_invite])"; "Note: This verb depends on being !d."; if (!$local.rpg:trusted(caller_perms())) return E_PERM; endif by = this.character; target = args[1]; weapons = (typeof(w = args[2]) == LIST) ? w | {w}; weapon = weapons[1]; weapons = listdelete(weapons, 1); effect = 0; if ((effect = this:combat_effects(target, weapon)) != NUM) return effect; endif bmods = (((argc = length(args)) > 2) && (typeof(args[3]) == NUM)) ? args[3] | 0; bmods = bmods + effect; if (!this:legal_target_new(target, doll = $local.rpg:get_doll(target), caller)) return; endif this:do_attack_notification(target, weapon); if ((!valid(weapon)) || (typeof(use = weapon:used_new(by, target)) != NUM)) "If :used returns a non-numeric value, the weapon is unusable."; return; endif barea = ((argc > 3) && (typeof(args[4]) == OBJ)) ? args[4] | doll:random_hit_lo cation(); weapon:announce_swing(by, target); if (doll.end <= 0) target:room_announce_all("The blow passes through ", target.name, " without visible effect."); return; endif if (valid(doll)) doll.aggressor = setadd(doll.aggressor, by); endif weap_slow = weapon:slowness(by, target); weap_dam = weapon:dam(by, target); attack_bonus = weapon:attack(by, target); mods = ((bmods + use) + attack_bonus) - (length(weapons) * 10); if ((typeof(by.location.space) == NUM) && ((z = weapon:length(by, target) - by.location.space) > 0)) "'z' is the difference between room length and weapon length."; mods = mods - (3 * z); damage = (2 * (weap_dam - z)) + this.str; if ((((z > 3) && is_player(by)) && (((time() - this.last_action) > 10) || (random(20) == 1))) && (length(callers()) < 3)) by:tell("The room is a little small to ", weapon.swing, " your ", weapon.name, " properly."); endif else damage = (2 * weap_dam) + this.str; endif "Damage will never be greater than 3 * base."; damage = min(damage, 3 * weap_dam); "'y' is encumbrance penalty of the weapon. Wielding a heavy weapon with more than one hand reduces the total penalty."; "A weak person wielding a heavy weapon will be greatly penalized."; y = this.str - (((3 * weapon:encumbrance(this)) / 5) / (1 + weapon:hands(by, target))); if (y < 0) mods = mods + (5 * y); damage = damage + (y / 2); endif connects = (qual = weapon:skill(by, target):resolve(by, mods)) > -25; if (connects) doll:respond(by, qual, damage, weapon, barea); else if (!weapon:critical_miss(by, target, qual)) "No critical miss."; weapon:announce_miss(by, target, qual); endif if (weapons && valid(this)) this.aggressor = setadd(this.aggressor, target); this:invite(this.slowness + weap_slow, {1, by, target}); this.act = this.act + this.slowness; return this:attack(target, weapons, bmods - 10); endif endif no_invite = ((length(args) > 4) && (typeof(args[5]) == NUM)) ? args[5] | 0; if (valid(this) && (!no_invite)) this.aggressor = setadd(this.aggressor, target); this:invite(this.slowness + (valid(weapon) ? weapon:slowness(by, target) | 0), {1, by, target, weapon}); endif "Quinn 05-JAN-93: Use verbs for referencing weapon properties."; "Quinn 28-FEB-93: Won't fork notification if a fork is already pending."; "Quinn 11-AUG-93: Big re-write. Created :legal_target and :do_attack_notificat ion to do the mundane chore of checking and notifying targets; cut down the unwieldly verb size; added some minor comments."; "Quinn 11-AUG-93: Send weapon to :respond."; "Quinn 22-OCT-93: Added combat_effect."; "Quinn 19-NOV-93: Added body area support, :critical_miss. New args to :Respond."; "Ogwul 01-JAN-94: Allowed :attack to be called without adding the target to the aggressor list and without :invite via the no_invite parameter."; . @verb #74:"write_misc_note" this none this @program #74:write_misc_note ":write_misc_note(name, value)"; "Store a miscellaneous note on the voodoo doll."; if (!$local.rpg:trusted(caller_perms())) return E_PERM; elseif (length(args) != 2) return E_ARGS; endif notes = this.misc_notes; index = args[1]; for i in [1..length(notes)] if (notes[i][1] == index) this.misc_notes[i][2] = args[2]; return i; endif endfor this.misc_notes = listappend(notes, args); return length(notes) + 1; . @verb #74:"read_misc_note" this none this @program #74:read_misc_note ":read_misc_note(name)"; "View a miscellaneous note on the voodoo doll."; if (!$local.rpg:trusted(caller_perms())) return E_PERM; endif index = args[1]; for elm in (this.misc_notes) if (elm[1] == index) return elm[2]; endif endfor return E_PROPNF; . @verb #74:"erase_misc_note" this none this @program #74:erase_misc_note ":erase_misc_note(name)"; "Remove a miscellaneous note from the voodoo doll."; if (!$local.rpg:trusted(caller_perms())) return E_PERM; endif notes = this.misc_notes; index = args[1]; for i in [1..length(notes)] if (notes[i][1] == index) this.misc_notes = listdelete(notes, i); size = length(notes) - 1; if (size == 0) clear_property(this, "misc_notes"); endif return size; endif endfor return E_PROPNF; "Isagi 29-SEP-94: Use clear_property() to clear the list when it becomes empty."; . @verb #74:"attack(nomissiles)" this any none rx @program #74:attack(nomissiles) ":attack(OBJ target, LIST weapons[, NUM modifier, OBJ area, NUM no_invite])"; if (!$local.rpg:trusted(caller_perms())) return E_PERM; endif by = this.character; target = args[1]; weapons = (typeof(w = args[2]) == LIST) ? w | {w}; weapon = weapons[1]; weapons = listdelete(weapons, 1); effect = 0; if ((effect = this:combat_effects(target, weapon)) != NUM) return effect; endif bmods = (((argc = length(args)) > 2) && (typeof(args[3]) == NUM)) ? args[3] | 0; bmods = bmods + effect; if (!this:legal_target(target, doll = $local.rpg:get_doll(target))) return; endif this:do_attack_notification(target, weapon); if ((!valid(weapon)) || (typeof(use = weapon:used(by, target)) != NUM)) "If :used returns a non-numeric value, the weapon is unusable."; return; endif barea = ((argc > 3) && (typeof(args[4]) == OBJ)) ? args[4] | doll:random_hit_lo cation(); weapon:announce_swing(by, target); if (doll.end <= 0) target:room_announce_all("The blow passes through ", target.name, " without visible effect."); return; endif if (valid(doll)) doll.aggressor = setadd(doll.aggressor, by); endif weap_slow = weapon:slowness(by, target); weap_dam = weapon:dam(by, target); attack_bonus = weapon:attack(by, target); mods = ((bmods + use) + attack_bonus) - (length(weapons) * 10); if ((typeof(by.location.space) == NUM) && ((z = weapon:length(by, target) - by.location.space) > 0)) "'z' is the difference between room length and weapon length."; mods = mods - (3 * z); damage = (2 * (weap_dam - z)) + this.str; if ((((z > 3) && is_player(by)) && (((time() - this.last_action) > 10) || (random(20) == 1))) && (length(callers()) < 3)) by:tell("The room is a little small to ", weapon.swing, " your ", weapon.name, " properly."); endif else damage = (2 * weap_dam) + this.str; endif "Damage will never be greater than 3 * base."; damage = min(damage, 3 * weap_dam); "'y' is encumbrance penalty of the weapon. Wielding a heavy weapon with more than one hand reduces the total penalty."; "A weak person wielding a heavy weapon will be greatly penalized."; y = this.str - (((3 * weapon:encumbrance(this)) / 5) / (1 + weapon:hands(by, target))); if (y < 0) mods = mods + (5 * y); damage = damage + (y / 2); endif connects = (qual = weapon:skill(by, target):resolve(by, mods)) > -25; if (connects) doll:respond(by, qual, damage, weapon, barea); else if (!weapon:critical_miss(by, target, qual)) "No critical miss."; weapon:announce_miss(by, target, qual); endif if (weapons && valid(this)) this.aggressor = setadd(this.aggressor, target); this:invite(this.slowness + weap_slow, {1, by, target}); this.act = this.act + this.slowness; return this:attack(target, weapons, bmods - 10); endif endif no_invite = ((length(args) > 4) && (typeof(args[5]) == NUM)) ? args[5] | 0; if (valid(this) && (!no_invite)) this.aggressor = setadd(this.aggressor, target); this:invite(this.slowness + (valid(weapon) ? weapon:slowness(by, target) | 0), {1, by, target, weapon}); endif "Quinn 05-JAN-93: Use verbs for referencing weapon properties."; "Quinn 28-FEB-93: Won't fork notification if a fork is already pending."; "Quinn 11-AUG-93: Big re-write. Created :legal_target and :do_attack_notificat ion to do the mundane chore of checking and notifying targets; cut down the unwieldly verb size; added some minor comments."; "Quinn 11-AUG-93: Send weapon to :respond."; "Quinn 22-OCT-93: Added combat_effect."; "Quinn 19-NOV-93: Added body area support, :critical_miss. New args to :Respond."; "Ogwul 01-JAN-94: Allowed :attack to be called without adding the target to the aggressor list and without :invite via the no_invite parameter."; . @verb #74:"check_schedule" this none this rx @program #74:check_schedule ":check_schedule()"; "Check the items in the doll's schedule, firing those which need firing."; rpg = $local.rpg; if (!rpg:trusted(caller_perms())) return E_PERM; endif toady = rpg.toady; time = time(); for q in (this.schedule) "Extra (q in schedule) to be sure the element wasn't removed during a suspending call to toady."; if ((q in this.schedule) && (q[3] <= time)) this.schedule = setremove(this.schedule, q); toady:call_verb(q[1], q[2], {this, @q[4]}); endif endfor . @verb #74:"wielding" this none this @program #74:wielding ":wielding()"; "-> List of weapons this character is wielding,"; " or a list of natural weapons if wielding nothing."; return this.wielding || (this.hands ? this.natural_weapons | {}); "DR 17-AUG-94 -- Added hands check as per Isagi."; . @verb #74:"add_claimed_object" this none this @program #74:add_claimed_object ":add_claimed_object(obj[, ignore_quota])"; "Add the given object to this.claimed_objects, keeping a record of all items claimed."; "If the total number of claimed objects is greater than or equal to this.max_claims, and ignore_quota is not given or false, E_QUOTA is returned."; rpg = $local.rpg; if (!rpg:trusted(caller_perms())) return E_PERM; endif claimed_objs = this:claimed_objects(); ignore_quota = (length(args) > 1) && args[2]; if ((!ignore_quota) && (length(claimed_objs) >= this.max_claims)) return E_QUOTA; else this.claimed_objects = setadd(claimed_objs, args[1]); return 1; endif "Profane 5-APR-95 20:03EST - s/.claimed_objects/:claimed_objects()/8"; . @verb #74:"remove_claimed_object" this none this @program #74:remove_claimed_object ":remove_claimed_object(obj)"; "Remove the given object from this.claimed_objects."; rpg = $local.rpg; if (!rpg:trusted(caller_perms())) return E_PERM; endif this.claimed_objects = setremove(this.claimed_objects, args[1]); return 1; . @verb #74:"claimed_objects" this none this rx @program #74:claimed_objects ":claimed_objects()"; "Verify claimed objects list and return the clean result."; userobj = this.character; claimed = {}; for c in (this.claimed_objects) if (c.claimed_by == userobj) claimed = {@claimed, c}; endif endfor return this.claimed_objects = claimed; . @verb #74:"att_schedule" this none this rx @program #74:att_schedule ":att_schedule(STR attname, NUM time, NUM modifier)"; " to be used in conjunction with :get_unmod_att() and :get_att_mod()"; " TIME is in the form of 'time()' plus a modifier. EX: 'time() + 3 * 60' means the change only lasts three minutes."; " => E_TYPE That attribute is not a number"; " => E_INVARG The modifier that you gave is not a number"; if (!$local.rpg:trust()) return E_PERM; elseif (typeof(this.(stat = args[1])) != NUM) return E_TYPE; elseif (typeof(mod = args[3]) != NUM) return E_INVARG; endif schedule = this:read_misc_note("ATT_Schedule"); if (typeof(schedule) != LIST) schedule = {}; endif schedule = listappend(schedule, args); this:write_misc_note("ATT_Schedule", schedule); this.(stat) = this.(stat) + mod; return {1, this.(stat)}; "Isagi 093194 Added"; "Isagi 100294 2:05P Added help for units of time."; . @verb #74:"get_unmod_att" this none this rx @program #74:get_unmod_att ":get_unmod_att(STR attname) ==> NUM unmodified_attribute"; if (!$local.rpg:trust()) return E_PERM; endif mod = 0; stat = args[1]; schedule = this:read_misc_note("ATT_Schedule"); if (typeof(schedule) != LIST) return this.(stat); endif for line in (schedule) if (line[1] == stat) mod = mod + line[3]; endif endfor return this.(stat) - mod; . @verb #74:"do_att_schedule" this none this rx @program #74:do_att_schedule if (schedule = this:read_misc_note("ATT_Schedule")) removed = 0; for line in (schedule) if ((time() > line[2]) && (line[2] > 0)) schedule = setremove(schedule, line); removed = removed + 1; stat = line[1]; this.(stat) = this.(stat) - line[3]; endif endfor if (length(schedule)) this:write_misc_note("ATT_Schedule", schedule); else this:erase_misc_note("ATT_schedule"); endif return removed; endif return; . @verb #74:"erase_misc_note(old)" this none this @program #74:erase_misc_note(old) ":erase_misc_note(name)"; "Remove a miscellaneous note from the voodoo doll."; if (!$local.rpg:trusted(caller_perms())) return E_PERM; endif notes = this.misc_notes; index = args[1]; for i in [1..length(notes)] if (notes[i][1] == index) this.misc_notes = listdelete(notes, i); return length(notes) - 1; endif endfor return E_PROPNF; . @verb #74:"hit_aggressor(old)" this any none rxd @program #74:hit_aggressor(old) me = this.character; here = me.location; if (this.aggressor = setremove(this.aggressor, me)) if ((this:wielding() == {}) && ((!is_player(this.character)) && (this.wielding == this.natural_weapons))) this:arm(); return $failed_match; else weapon = this:wielding()[1]; if ($object_utils:isa(weapon, #8816) && (weapon.loaded <= 0)) weapon:do_load(me, this); return $failed_match; endif endif if (($object_utils:isa(weapon, #8816) && (weapon.loaded > 0)) && $object_utils:isa(here, #258)) here = here:missile_dests(me); else here = {here}; endif while (this.aggressor) targ = this.aggressor[random(length(this.aggressor))]; if (targ.location in here) this:attack(targ, weapon); return targ; else this.aggressor = setremove(this.aggressor, targ); endif endwhile endif this:set_att("act", 0); return $nothing; "DR 17-AUG-94 -- Changed line 4 (if around :arm) to keep monsters checking for other non .natural_weapons weapons ... also takes out PC autowielding since they have fists now."; . @verb #74:"invite_isagi_broke" this any none rxd @program #74:invite_isagi_broke ":invite(NUM slowness[, LIST some_arcane_value_nobody_ever_documented])"; if (!$local.rpg:trust()) return E_PERM; elseif (!valid(where = (by = this.character).location)) return this.act = 0; endif slow = args[1] + (this:encumbrance() / 10); this.act = this.act - slow; temp = $local.rpg:find_chars(by.location); dolls = temp[2]; for doll in (dolls = temp[2]) doll:check_schedule(); endfor things = temp[1]; min = $maxint; for doll in (dolls) if ((doll.act < min) && doll.free_will) min = doll.act; endif endfor if (min == $maxint) for doll in (dolls) doll.act = doll.slowness / 2; endfor return; else for doll in (dolls) doll.act = doll.act - min; endfor endif max = -1; for doll in (dolls) which = doll; if ((valid(doll) && ((!is_player(things[doll in dolls])) || (doll.act > (2 * doll.slowness)))) && ((doll.act - doll.slowness) > max)) max = doll.act - doll.slowness; which = doll; endif endfor if (max < 0) return; elseif ($object_utils:has_callable_verb(who = which.character, "act")) object = who; verbname = "act"; else object = which; verbname = "hit_aggressor"; endif if ((is_player(who) && (!is_player(by))) || $local.rpg:time_trouble()) fork (0) if ((valid(which) && valid(who)) && (which.act > which.slowness)) object:(verbname)(which); endif endfork else object:(verbname)(which); endif "Quinn 12-OCT-93 0358: Major cleanup re-write of the code."; "MAJOR CHANGE: Scheduled events now fire at an absolute time. Firing times are not decremented with each check, as before. Changed slow and forcewall to account for this. May break old code."; "Quinn 15-JUN-94 1857: Moved schedule checking to :check_schedule."; . @verb #74:"old_invite" this any none rxd @program #74:old_invite ":invite(NUM slowness[, LIST some_arcane_value_nobody_ever_documented])"; if (!$local.rpg:trust()) return E_PERM; elseif (!valid(where = (by = this.character).location)) return this.act = 0; endif slow = args[1] + (this:encumbrance() / 10); this.act = this.act - slow; temp = $local.rpg:find_chars(by.location); for doll in (dolls = temp[2]) doll:check_schedule(); endfor things = temp[1]; min = $maxint; for doll in (dolls) if ((doll.act < min) && doll.free_will) min = doll.act; endif endfor if (min == $maxint) for doll in (dolls) doll.act = doll.slowness / 2; endfor return; else for doll in (dolls) doll.act = doll.act - min; endfor endif max = -1; for doll in (dolls) which = doll; if ((valid(doll) && ((!is_player(things[doll in dolls])) || (doll.act > (2 * doll.slowness)))) && ((doll.act - doll.slowness) > max)) max = doll.act - doll.slowness; which = doll; endif endfor value = 0; if (max < 0) return; endif if (!$command_utils:running_out_of_time()) value = "act"; this:act(); else fork (0) this:act(); value = "act"; endfork endif return value; "Quinn 12-OCT-93 0358: Major cleanup re-write of the code."; "MAJOR CHANGE: Scheduled events now fire at an absolute time. Firing times are not decremented with each check, as before. Changed slow and forcewall to account for this. May break old code."; "Quinn 15-JUN-94 1857: Moved schedule checking to :check_schedule."; "Isagi 10-23 12:20P -- Commented out the return in line 41, now everything will attack no matter what."; "Isagi 11-19-94 2:10P -- Put the return back into line 41 [Or thereabouts]"; . @verb #74:"magic_effect*s" this none this @program #74:magic_effects ":magic_effects(OBJ caster doll, OBJ target doll, NUM quality of spell, OBJ skill of spell) -- check objects affecting the target doll `magically' and give them a chance to influence/stop the spell."; rpg = $local.rpg; if (!rpg:trusted(caller_perms())) return E_PERM; else effect = $object_utils:has_property(doll = args[2], "magic_effect") ? doll.magic_effect | 0; "Unlike :combat_effects(), we don't check the area's :magic_effect, since that's _offensive_, and this verb is _defensive_."; for effobj in (this.magic_effects) if (rpg:trusted_verb(effobj, "magic_effect")) if (typeof(e = effobj:magic_effect(@args)) != NUM) if (verb == "magic_effect") return -200; else return e; endif else effect = effect + e; endif endif endfor if (verb == "magic_effect") return args[3] - effect; else return effect; endif endif "Profane - 2/4/95 11:17EST - Added."; "Profane - 2/7/95 11:04EST - Added check for any .magic_effect prop on target doll (which shouldn't be there, but for backwards compatibility..) Renamed verb to ``magic_effect*s'', if called as ``magic_effect'' will always return numeric value, again for backwards compatibility. Moved old :magic_effect to ``magic_effect(old)''."; . @verb #74:"attack(old)" this any none rx @program #74:attack(old) ":attack(OBJ target, LIST weapons[, NUM modifier, OBJ area, NUM no_invite])"; if (!$local.rpg:trusted(caller_perms())) return E_PERM; endif by = this.character; target = args[1]; weapons = (typeof(w = args[2]) == LIST) ? w | {w}; weapon = weapons[1]; weapons = listdelete(weapons, 1); effect = 0; if (typeof(effect = this:combat_effects(target, weapon)) != NUM) return effect; endif bmods = (((argc = length(args)) > 2) && (typeof(args[3]) == NUM)) ? args[3] | 0; bmods = bmods + effect; if (!this:legal_target(target, doll = $local.rpg:get_doll(target), caller)) return; endif this:do_attack_notification(target, weapon); if ((!valid(weapon)) || (typeof(use = weapon:used(by, target)) != NUM)) "If :used returns a non-numeric value, the weapon is unusable."; return; endif barea = ((argc > 3) && (typeof(args[4]) == OBJ)) ? args[4] | doll:random_hit_lo cation(); weapon:announce_swing(by, target); if (doll.end <= 0) target:room_announce_all("The blow passes through ", target.name, " without visible effect."); return; endif if (valid(doll)) doll.aggressor = setadd(doll.aggressor, by); endif weap_slow = weapon:slowness(by, target); weap_dam = weapon:dam(by, target); attack_bonus = weapon:attack(by, target); mods = ((bmods + use) + attack_bonus) - (length(weapons) * 10); if ((typeof(by.location.space) == NUM) && ((z = weapon:length(by, target) - by.location.space) > 0)) "'z' is the difference between room length and weapon length."; mods = mods - (3 * z); damage = (2 * (weap_dam - z)) + this.str; if ((((z > 3) && is_player(by)) && (((time() - this.last_action) > 10) || (random(20) == 1))) && (length(callers()) < 3)) by:tell("The room is a little small to ", weapon.swing, " your ", weapon.name, " properly."); endif else damage = (2 * weap_dam) + this.str; endif "Damage will never be greater than 3 * base."; damage = min(damage, 3 * weap_dam); "'y' is encumbrance penalty of the weapon. Wielding a heavy weapon with more than one hand reduces the total penalty."; "A weak person wielding a heavy weapon will be greatly penalized."; y = this.str - (((3 * weapon:encumbrance(this)) / 5) / (1 + weapon:hands(by, target))); if (y < 0) mods = mods + (5 * y); damage = damage + (y / 2); endif connects = (qual = weapon:skill(by, target):resolve(by, mods)) > -25; if (connects) doll:respond(by, qual, damage, weapon, barea); else if (!weapon:critical_miss(by, target, qual)) "No critical miss."; weapon:announce_miss(by, target, qual); endif if (weapons && valid(this)) this.aggressor = setadd(this.aggressor, target); this:invite(this.slowness + weap_slow, {1, by, target}); this.act = this.act + this.slowness; return this:attack(target, weapons, bmods - 10); endif endif no_invite = ((length(args) > 4) && (typeof(args[5]) == NUM)) ? args[5] | 0; if (valid(this) && (!no_invite)) this.aggressor = setadd(this.aggressor, target); doll:invite(this.slowness + (valid(weapon) ? weapon:slowness(by, target) | 0), {1, by, target, weapon}); endif "Quinn 05-JAN-93: Use verbs for referencing weapon properties."; "Quinn 28-FEB-93: Won't fork notification if a fork is already pending."; "Quinn 11-AUG-93: Big re-write. Created :legal_target and :do_attack_notifica ion to do the mundane chore of checking and notifying targets; cut down the unwieldly verb size; added some minor comments."; "Quinn 11-AUG-93: Send weapon to :respond."; "Quinn 22-OCT-93: Added combat_effect."; "Quinn 19-NOV-93: Added body area support, :critical_miss. New args to :Respond."; "Ogwul 01-JAN-94: Allowed :attack to be called without adding the target to the aggressor list and without :invite via the no_invite parameter."; . @verb #74:"hit_result" this none this rx @program #74:hit_result "(NUM dam, NUM pen, [OBJ whoby], [OBJ weapon])"; "returns 0 if there's no effect, or returns a list of the following values:"; "bad => a number from 0 (the attack bounced off this.character's armor) to 5 (he's dead, Jim)"; "place_name => a string indicating where this.character got hit."; "stun => 1 if this.character got stunned, 0 if not."; if (!$local.rpg:trust()) return E_PERM; elseif (this.end <= 0) return 0; endif whoby = ((la = length(args)) > 2) ? args[3] | $nothing; weapon = (la > 3) ? args[4] | $nothing; dam = args[1]; me = this.character; pen = args[2]; bad = 0; stun = 0; shock = #19835; if (dam <= 0) return 0; endif "...hacked to use hit_location_names 11-MAR-93 quinn..."; places = this:hit_location_names(); loc = {1, 2, 2, 3, 3, 4, 5, 6, 6, 7, 7}[random(11)]; place_name = places[loc]; "Quinn 11-AUG-93 0958: Hacked to send attacked and weapon to :armour."; dam = (dam - this:armour(pen, loc, whoby, weapon, dam)) / this.size; if (dam <= 0) return {bad, place_name, stun}; endif this.inj = this.inj + dam; if (!(bad = (2 * dam) / this.end)) bad = 1; elseif (bad == 1) bad = 2; elseif (bad < 4) bad = 3; else bad = 4; endif try = $local.rpg:resolve(me, shock, -{0, 10, 0, 20, 20, 20, 20}[loc]); if (try > (-2 * this.end)) return {bad, place_name, stun}; elseif (try > ((-4 * this.end) - {20, 40, 50, 80, 80, 55, 55}[loc])) this.act = this.act - 20; if (this.act < -20) this.act = -20; endif stun = 1; return {bad, place_name, stun}; else bad = 5; this:die(whoby); return {bad, place_name, stun}; endif "This verb is intended to eventually replace :receive_damage_passed_messages. As is, the aforementioned verb does not properly handle lightning or firebolts, strangulation, (as in 'fangs and crushing coils', object #906) cones of frost, (remember the wyverns?) or any other situation where one wishes to indicate severity and/or a stun result in an unconventional manner."; . "***finished***