"""
#**************************************************************************
* Original Diku Mud copyright=C) 1990, 1991 by Sebastian Hammer, *
* Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. *
* *
* Merc Diku Mud improvments copyright=C) 1992, 1993 by Michael *
* Chastain, Michael Quan, and Mitchell Tse. *
* *
* In order to use any part of this Merc Diku Mud, you must comply with *
* both the original Diku license in 'license.doc' as well the Merc *
* license in 'license.txt'. In particular, you may not remove either of *
* these copyright notices. *
* *
* Much time and thought has gone into this software and you are *
* benefitting. We hope that you share your changes too. What goes *
* around, comes around. *
***************************************************************************/
#**************************************************************************
* ROM 2.4 is copyright 1993-1998 Russ Taylor *
* ROM has been brought to you by the ROM consortium *
* Russ Taylor=rtaylor@hypercube.org) *
* Gabrielle Taylor=gtaylor@hypercube.org) *
* Brian Moore=zump@rom.org) *
* By using this code, you have agreed to follow the terms of the *
* ROM license, in the file Rom24/doc/rom.license *
***************************************************************************/
#***********
* Ported to Python by Davion of MudBytes.net
* Using Miniboa https://code.google.com/p/miniboa/
* Now using Python 3 version https://code.google.com/p/miniboa-py3/
************/
"""
from merc import *
from handler import *
from skills import check_improve
from update import gain_exp
import const
# * Control the fights going on.
# * Called periodically by update_handler.
def violence_update( ):
for ch in char_list[:]:
if not ch.fighting or not ch.in_room:
continue
victim = ch.fighting
if IS_AWAKE(ch) and ch.in_room == victim.in_room:
multi_hit( ch, victim, TYPE_UNDEFINED )
else:
stop_fighting( ch, False )
if not ch.fighting:
continue
victim = ch.fighting
#
#* Fun for the whole family!
#*/
check_assist(ch,victim)
return
# for auto assisting */
def check_assist( ch, victim):
for rch in ch.in_room.people[:]:
if IS_AWAKE(rch) and rch.fighting == None:
# quick check for ASSIST_PLAYER */
if not IS_NPC(ch) and IS_NPC(rch) and IS_SET(rch.off_flags,ASSIST_PLAYERS) and rch.level + 6 > victim.level:
rch.do_emote("screams and attacks!")
multi_hit(rch,victim,TYPE_UNDEFINED)
continue
# PCs next */
if not IS_NPC(ch) or IS_AFFECTED(ch,AFF_CHARM):
if( (not IS_NPC(rch) and IS_SET(rch.act,PLR_AUTOASSIST)) \
or IS_AFFECTED(rch,AFF_CHARM)) \
and ch.is_same_group(rch) \
and not is_safe(rch, victim):
multi_hit (rch,victim,TYPE_UNDEFINED)
continue
# now check the NPC cases */
if IS_NPC(ch) and not IS_AFFECTED(ch,AFF_CHARM):
if (IS_NPC(rch) and IS_SET(rch.off_flags,ASSIST_ALL)) \
or (IS_NPC(rch) and rch.group and rch.group == ch.group) \
or (IS_NPC(rch) and rch.race == ch.race and IS_SET(rch.off_flags,ASSIST_RACE)) \
or (IS_NPC(rch) and IS_SET(rch.off_flags,ASSIST_ALIGN) \
and ((IS_GOOD(rch) and IS_GOOD(ch)) or (IS_EVIL(rch) and IS_EVIL(ch)) \
or (IS_NEUTRAL(rch) and IS_NEUTRAL(ch)))) \
or (rch.pIndexData == ch.pIndexData and IS_SET(rch.off_flags,ASSIST_VNUM)):
if random.randint(0,1) == 0:
continue
target = None
number = 0
for vch in ch.in_room.people:
if rch.can_see(vch) and vch.is_same_group(victim) and random.randint(0,number) == 0:
target = vch
number += 1
if target:
rch.do_emote("screams and attacks!")
multi_hit(rch,target,TYPE_UNDEFINED)
# * Do one group of attacks.
def multi_hit( ch, victim, dt ):
# decrement the wait */
if ch.desc == None:
ch.wait = max(0,ch.wait - PULSE_VIOLENCE)
if ch.desc == None:
ch.daze = max(0,ch.daze - PULSE_VIOLENCE)
# no attacks for stunnies -- just a check */
if ch.position < POS_RESTING:
return
if IS_NPC(ch):
mob_hit(ch,victim,dt)
return
one_hit( ch, victim, dt )
if ch.fighting != victim:
return
if IS_AFFECTED(ch,AFF_HASTE):
one_hit(ch,victim,dt)
if ch.fighting != victim or dt == 'backstab':
return
chance = ch.get_skill('second attack') // 2
if IS_AFFECTED(ch,AFF_SLOW):
chance //= 2
if random.randint(1,99) < chance:
one_hit( ch, victim, dt )
check_improve(ch,'second_attack',True,5)
if ch.fighting != victim:
return
chance = ch.get_skill('third attack') // 4
if IS_AFFECTED(ch,AFF_SLOW):
chance = 0
if random.randint(1,99) < chance:
one_hit( ch, victim, dt )
check_improve(ch,'third attack',True,6)
if ch.fighting != victim:
return
return
# procedure for all mobile attacks */
def mob_hit (ch, victim, dt):
one_hit(ch,victim,dt)
if ch.fighting != victim:
return
# Area attack -- BALLS nasty! */
if IS_SET(ch.off_flags,OFF_AREA_ATTACK):
for vch in ch.in_room.people[:]:
if vch != victim and vch.fighting == ch:
one_hit(ch,vch,dt)
if IS_AFFECTED(ch,AFF_HASTE) or (IS_SET(ch.off_flags,OFF_FAST) and not IS_AFFECTED(ch,AFF_SLOW)):
one_hit(ch,victim,dt)
if ch.fighting != victim or dt == 'backstab':
return
chance = ch.get_skill("second attack") // 2
if IS_AFFECTED(ch,AFF_SLOW) and not IS_SET(ch.off_flags,OFF_FAST):
chance //= 2
if random.randint(1,99) < chance:
one_hit(ch,victim,dt)
if ch.fighting != victim:
return
chance = ch.get_skill('third attack') // 4
if IS_AFFECTED(ch,AFF_SLOW) and not IS_SET(ch.off_flags,OFF_FAST):
chance = 0
if random.randint(1,99) < chance:
one_hit(ch,victim,dt)
if ch.fighting != victim:
return
# oh boy! Fun stuff! */
if ch.wait > 0:
return
number = random.randint(0,2)
if number == 1 and IS_SET(ch.act,ACT_MAGE):
pass
# { mob_cast_mage(ch,victim) return } */
if number == 2 and IS_SET(ch.act,ACT_CLERIC):
pass
# { mob_cast_cleric(ch,victim) return } */
# now for the skills */
number = random.randint(0,8)
if number == 0:
if IS_SET(ch.off_flags,OFF_BASH):
ch.do_bash("")
elif number == 1:
if IS_SET(ch.off_flags,OFF_BERSERK) and not IS_AFFECTED(ch,AFF_BERSERK):
ch.do_berserk("")
elif number == 2:
if IS_SET(ch.off_flags,OFF_DISARM) \
or (ch.get_weapon_sn() != 'hand_to_hand' \
and (IS_SET(ch.act,ACT_WARRIOR) \
or IS_SET(ch.act,ACT_THIEF))):
ch.do_disarm("")
elif number == 3:
if IS_SET(ch.off_flags,OFF_KICK):
ch.do_kick("")
elif number == 4:
if IS_SET(ch.off_flags,OFF_KICK_DIRT):
ch.do_dirt("")
elif number == 5:
if IS_SET(ch.off_flags,OFF_TAIL):
pass # do_function(ch, &do_tail, "") */
elif number == 6:
if IS_SET(ch.off_flags,OFF_TRIP):
ch.do_trip("")
elif number == 7:
if IS_SET(ch.off_flags,OFF_CRUSH):
pass # do_function(ch, &do_crush, "") */
elif number == 8:
if IS_SET(ch.off_flags,OFF_BACKSTAB):
ch.do_backstab("")
# * Hit one guy once.
# */
def one_hit( ch, victim, dt ):
sn = -1
# just in case */
if victim == ch or ch == None or victim == None:
return
#* Can't beat a dead char!
#* Guard against weird room-leavings.
if victim.position == POS_DEAD or ch.in_room != victim.in_room:
return
#* Figure out the type of damage message.
wield = ch.get_eq(WEAR_WIELD)
if dt == TYPE_UNDEFINED:
dt = TYPE_HIT
if wield and wield.item_type == ITEM_WEAPON:
dt += wield.value[3]
else :
dt += ch.dam_type
if dt < TYPE_HIT:
if wield:
dam_type = const.attack_table[wield.value[3]].damage
else:
dam_type = const.attack_table[ch.dam_type].damage
else:
dam_type = const.attack_table[dt - TYPE_HIT].damage
if dam_type == -1:
dam_type = DAM_BASH
# get the weapon skill */
sn = ch.get_weapon_sn()
skill = 20 + ch.get_weapon_skill(sn)
#* Calculate to-hit-armor-guild-0 versus armor.
if IS_NPC(ch):
thac0_00 = 20
thac0_32 = -4 # as good as a thief */
if IS_SET(ch.act,ACT_WARRIOR):
thac0_32 = -10
elif IS_SET(ch.act,ACT_THIEF):
thac0_32 = -4
elif IS_SET(ch.act,ACT_CLERIC):
thac0_32 = 2
elif IS_SET(ch.act,ACT_MAGE):
thac0_32 = 6
else:
thac0_00 = ch.guild.thac0_00
thac0_32 = ch.guild.thac0_32
thac0 = interpolate( ch.level, thac0_00, thac0_32 )
if thac0 < 0:
thac0 = thac0 // 2
if thac0 < -5:
thac0 = -5 + (thac0 + 5) // 2
thac0 -= GET_HITROLL(ch) * skill // 100
thac0 += 5 * (100 - skill) // 100
if dt == 'backstab':
thac0 -= 10 * (100 - ch.get_skill('backstab'))
if dam_type == DAM_PIERCE: victim_ac = GET_AC(victim,AC_PIERCE) // 10
elif dam_type == DAM_BASH: victim_ac = GET_AC(victim,AC_BASH) // 10
elif dam_type == DAM_SLASH: victim_ac = GET_AC(victim,AC_SLASH) // 10
else: victim_ac = GET_AC(victim,AC_EXOTIC) // 10
if victim_ac < -15:
victim_ac = (victim_ac + 15) // 5 - 15
if not ch.can_see(victim):
victim_ac -= 4
if victim.position < POS_FIGHTING:
victim_ac += 4
if victim.position < POS_RESTING:
victim_ac += 6
#* The moment of excitement!
diceroll = random.randint(0,20)
if diceroll == 0 or ( diceroll != 19 and diceroll < thac0 - victim_ac ):
# Miss. */
damage( ch, victim, 0, dt, dam_type, True )
return
# Hit.
# Calc damage.
if IS_NPC(ch) and (not ch.pIndexData.new_format or wield == None):
if not ch.pIndexData.new_format:
dam = random.randint( ch.level // 2, ch.level * 3 // 2 )
if wield != None:
dam += dam // 2
else:
dam = dice(ch.damage[DICE_NUMBER],ch.damage[DICE_TYPE])
else:
if sn != -1:
check_improve(ch,sn,True,5)
if wield:
if wield.pIndexData.new_format:
dam = dice(wield.value[1],wield.value[2]) * skill // 100
else:
dam = random.randint( wield.value[1] * skill // 100, wield.value[2] * skill // 100)
if ch.get_eq(WEAR_SHIELD) == None: # no shield = more */
dam = dam * 11 // 10
# sharpness! */
if IS_WEAPON_STAT(wield,WEAPON_SHARP):
percent = random.randint(1,99)
if percent <= (skill // 8):
dam = 2 * dam + (dam * 2 * percent // 100)
else:
low = 1 + 4 * skill // 100
high = 2 * ch.level // 3 * skill // 100
if low <= high:
dam = random.randint(low, high)
else:
dam = low
#
# * Bonuses.
if ch.get_skill('enhanced damage') > 0:
diceroll = random.randint(1,99)
if diceroll <= ch.get_skill('enhanced_damage'):
check_improve(ch,'enhanced damage',True,6)
dam += 2 * ( dam * diceroll // 300)
if not IS_AWAKE(victim):
dam *= 2
elif victim.position < POS_FIGHTING:
dam = dam * 3 // 2
if dt == 'backstab' and wield:
if wield.value[0] != 2:
dam *= 2 + (ch.level // 10)
else:
dam *= 2 + (ch.level // 8)
dam += GET_DAMROLL(ch) * min(100,skill) // 100
if dam <= 0:
dam = 1
result = damage( ch, victim, dam, dt, dam_type, True )
# but do we have a funky weapon? */
if result and wield != None:
if ch.fighting == victim and IS_WEAPON_STAT(wield,WEAPON_POISON):
poison = affect_find(wield.affected,'poison')
if poison:
level = wield.level
else:
level = poison.level
if not saves_spell(level // 2,victim,DAM_POISON):
victim.send("You feel poison coursing through your veins.")
act("$n is poisoned by the venom on $p.", victim,wield,None,TO_ROOM)
af = AFFECT_DATA()
af.where = TO_AFFECTS
af.type = 'poison'
af.level = level * 3 // 4
af.duration = level // 2
af.location = APPLY_STR
af.modifier = -1
af.bitvector = AFF_POISON
victim.affect_join(af)
# weaken the poison if it's temporary */
if poison:
poison.level = max(0,poison.level - 2)
poison.duration = max(0,poison.duration - 1)
if poison.level == 0 or poison.duration == 0:
act("The poison on $p has worn off.",ch,wield,None,TO_CHAR)
if ch.fighting == victim and IS_WEAPON_STAT(wield,WEAPON_VAMPIRIC):
dam = random.randint(1, wield.level // 5 + 1)
act("$p draws life from $n.",victim,wield,None,TO_ROOM)
act("You feel $p drawing your life away.", victim,wield,None,TO_CHAR)
damage(ch,victim,dam,0,DAM_NEGATIVE,False)
ch.alignment = max(-1000,ch.alignment - 1)
ch.hit += dam // 2
if ch.fighting == victim and IS_WEAPON_STAT(wield,WEAPON_FLAMING):
dam = random.randint(1,wield.level // 4 + 1)
act("$n is burned by $p.",victim,wield,None,TO_ROOM)
act("$p sears your flesh.",victim,wield,None,TO_CHAR)
fire_effect(victim,wield.level // 2,dam,TARGET_CHAR)
damage(ch,victim,dam,0,DAM_FIRE,False)
if ch.fighting == victim and IS_WEAPON_STAT(wield,WEAPON_FROST):
dam = random.randint(1,wield.level // 6 + 2)
act("$p freezes $n.",victim,wield,None,TO_ROOM)
act("The cold touch of $p surrounds you with ice.",
victim,wield,None,TO_CHAR)
cold_effect(victim,wield.level // 2,dam,TARGET_CHAR)
damage(ch,victim,dam,0,DAM_COLD,False)
if ch.fighting == victim and IS_WEAPON_STAT(wield,WEAPON_SHOCKING):
dam = random.randint(1,wield.level // 5 + 2)
act("$n is struck by lightning from $p.",victim,wield,None,TO_ROOM)
act("You are shocked by $p.",victim,wield,None,TO_CHAR)
shock_effect(victim,wield.level // 2,dam,TARGET_CHAR)
damage(ch,victim,dam,0,DAM_LIGHTNING,False)
return
# * Inflict damage from a hit.
def damage(ch,victim,dam,dt,dam_type,show):
if victim.position == POS_DEAD:
return False
#Stop up any residual loopholes.
if dam > 1200 and dt >= TYPE_HIT:
print ("BUG: Damage: %d: more than 1200 points!" % dam)
dam = 1200
if not IS_IMMORTAL(ch):
obj = ch.get_eq(WEAR_WIELD)
ch.send("You really shouldn't cheat.\n\r")
if obj:
obj.extract()
# damage reduction */
if dam > 35:
dam = (dam - 35) // 2 + 35
if dam > 80:
dam = (dam - 80) // 2 + 80
if victim != ch:
# Certain attacks are forbidden.
# Most other attacks are returned.
if is_safe( ch, victim ):
return False
check_killer( ch, victim )
if victim.position > POS_STUNNED:
if not victim.fighting:
set_fighting( victim, ch )
if victim.timer <= 4:
victim.position = POS_FIGHTING
if victim.position > POS_STUNNED:
if not ch.fighting:
set_fighting( ch, victim )
# More charm stuff.
if victim.master == ch:
stop_follower( victim )
# * Inviso attacks ... not.
if IS_AFFECTED(ch, AFF_INVISIBLE):
ch.affect_strip("invis")
ch.affect_strip("mass invis")
REMOVE_BIT( ch.affected_by, AFF_INVISIBLE )
act( "$n fades into existence.", ch, None, None, TO_ROOM )
# Damage modifiers.
if dam > 1 and not IS_NPC(victim) and victim.pcdata.condition[COND_DRUNK] > 10:
dam = 9 * dam // 10
if dam > 1 and IS_AFFECTED(victim, AFF_SANCTUARY):
dam //= 2
if dam > 1 and ((IS_AFFECTED(victim, AFF_PROTECT_EVIL) and IS_EVIL(ch)) \
or (IS_AFFECTED(victim, AFF_PROTECT_GOOD) and IS_GOOD(ch) )):
dam -= dam // 4
immune = False
# Check for parry, and dodge.
if dt >= TYPE_HIT and ch != victim:
if check_parry( ch, victim ):
return False
if check_dodge( ch, victim ):
return False
if check_shield_block(ch,victim):
return False
imm = victim.check_immune(dam_type)
if imm == IS_IMMUNE:
immune = True
dam = 0
elif imm == IS_RESISTANT:
dam -= dam // 3
elif imm == IS_VULNERABLE:
dam += dam // 2
dam = int(dam)
if show:
dam_message( ch, victim, dam, dt, immune )
if dam == 0:
return False
# Hurt the victim.
# Inform the victim of his new state.
victim.hit -= dam
if not IS_NPC(victim) and victim.level >= LEVEL_IMMORTAL and victim.hit < 1:
victim.hit = 1
update_pos( victim )
if victim.position == POS_MORTAL:
act( "$n is mortally wounded, and will die soon, if not aided.", victim, None, None, TO_ROOM )
victim.send("You are mortally wounded, and will die soon, if not aided.\n\r")
elif victim.position == POS_INCAP:
act( "$n is incapacitated and will slowly die, if not aided.", victim, None, None, TO_ROOM )
victim.send("You are incapacitated and will slowly die, if not aided.\n\r")
elif victim.position == POS_STUNNED:
act( "$n is stunned, but will probably recover.", victim, None, None, TO_ROOM )
victim.send("You are stunned, but will probably recover.\n\r")
elif victim.position == POS_DEAD:
act( "$n is DEAD!!", victim, 0, 0, TO_ROOM )
victim.send("You have been KILLED!!\n\r\n\r")
else:
if dam > victim.max_hit // 4:
victim.send("That really did HURT!\n\r")
if victim.hit < victim.max_hit // 4:
victim.send("You sure are BLEEDING!\n\r")
# Sleep spells and extremely wounded folks.
if not IS_AWAKE(victim):
stop_fighting( victim, False )
# Payoff for killing things.
if victim.position == POS_DEAD:
group_gain( ch, victim )
if not IS_NPC(victim):
print ("%s killed by %s at %d" % ( victim.name, ch.short_descr if IS_NPC(ch) else ch.name, ch.in_room.vnum ))
# Dying penalty:
# 2/3 way back to previous level.
if victim.exp > victim.exp_per_level(victim.pcdata.points) * victim.level:
gain_exp( victim, (2 * (victim.exp_per_level(victim.pcdata.points) * victim.level - victim.exp) // 3) + 50 )
log_buf = "%s got toasted by %s at %s [room %d]" % ( victim.short_descr if IS_NPC(victim) else victim.name,
ch.short_descr if IS_NPC(ch) else ch.name, ch.in_room.name, ch.in_room.vnum)
if IS_NPC(victim):
wiznet(log_buf,None,None,WIZ_MOBDEATHS,0,0)
else:
wiznet(log_buf,None,None,WIZ_DEATHS,0,0)
raw_kill( victim )
# dump the flags */
if ch != victim and not IS_NPC(ch) and not ch.is_same_clan(victim):
if IS_SET(victim.act,PLR_KILLER):
REMOVE_BIT(victim.act,PLR_KILLER)
else:
REMOVE_BIT(victim.act,PLR_THIEF)
# RT new auto commands */
corpse = ch.get_obj_list("corpse", ch.in_room.contents)
if not IS_NPC(ch) and corpse and corpse.item_type == ITEM_CORPSE_NPC and ch.can_see_obj(corpse):
if IS_SET(ch.act, PLR_AUTOLOOT) and corpse and corpse.contains: # exists and not empty */
ch.do_get("all corpse")
if IS_SET(ch.act,PLR_AUTOGOLD) and corpse and corpse.contains and not IS_SET(ch.act,PLR_AUTOLOOT):
coins = ch.get_obj_list("gcash",corpse.contains)
if coins: ch.do_get("all.gcash corpse")
if IS_SET(ch.act, PLR_AUTOSAC):
if IS_SET(ch.act,PLR_AUTOLOOT) and corpse and corpse.contains:
return True # leave if corpse has treasure */
else:
ch.do_sacrifice("corpse")
return True
if victim == ch:
return True
#* Take care of link dead people.
if not IS_NPC(victim) and victim.desc == None:
if random.randint( 0, victim.wait ) == 0:
victim.do_recall("")
return True
# * Wimp out?
if IS_NPC(victim) and dam > 0 and victim.wait < PULSE_VIOLENCE // 2:
if (IS_SET(victim.act, ACT_WIMPY) and random.randint(0,4) == 0 \
and victim.hit < victim.max_hit // 5) \
or ( IS_AFFECTED(victim, AFF_CHARM) and victim.master \
and victim.master.in_room != victim.in_room ):
victim.do_flee("")
if not IS_NPC(victim) and victim.hit > 0 and victim.hit <= victim.wimpy and victim.wait < PULSE_VIOLENCE // 2:
victim.do_flee("")
return True
def is_safe(ch, victim):
if victim.in_room == None or ch.in_room == None:
return True
if victim.fighting == ch or victim == ch:
return False
if IS_IMMORTAL(ch) and ch.level > LEVEL_IMMORTAL:
return False
# killing mobiles */
if IS_NPC(victim):
# safe room? */
if IS_SET(victim.in_room.room_flags,ROOM_SAFE):
ch.send("Not in this room.\n\r")
return True
if victim.pIndexData.pShop:
ch.send("The shopkeeper wouldn't like that.\n\r")
return True
# no killing healers, trainers, etc */
if IS_SET(victim.act,ACT_TRAIN) \
or IS_SET(victim.act,ACT_PRACTICE) \
or IS_SET(victim.act,ACT_IS_HEALER) \
or IS_SET(victim.act,ACT_IS_CHANGER):
ch.send("I don't think Mota would approve.\n\r")
return True
if not IS_NPC(ch):
# no pets */
if IS_SET(victim.act,ACT_PET):
act("But $N looks so cute and cuddly...", ch,None,victim,TO_CHAR)
return True
# no charmed creatures unless owner */
if IS_AFFECTED(victim,AFF_CHARM) and ch != victim.master:
ch.send("You don't own that monster.\n\r")
return True
# killing players */
else:
# NPC doing the killing */
if IS_NPC(ch):
# safe room check */
if IS_SET(victim.in_room.room_flags,ROOM_SAFE):
ch.send("Not in this room.\n\r")
return True
# charmed mobs and pets cannot attack players while owned */
if IS_AFFECTED(ch,AFF_CHARM) and ch.master and ch.master.fighting != victim:
ch.send("Players are your friends!\n\r")
return True
# player doing the killing */
else:
if not ch.is_clan():
ch.send("Join a clan if you want to kill players.\n\r")
return True
if IS_SET(victim.act,PLR_KILLER) or IS_SET(victim.act,PLR_THIEF):
return False
if not victim.is_clan():
ch.send("They aren't in a clan, leave them alone.\n\r")
return True
if ch.level > victim.level + 8:
ch.send("Pick on someone your own size.\n\r")
return True
return False
def is_safe_spell(ch, victim, area ):
if victim.in_room == None or ch.in_room == None:
return True
if victim == ch and area:
return True
if victim.fighting == ch or victim == ch:
return False
if IS_IMMORTAL(ch) and ch.level > LEVEL_IMMORTAL and not area:
return False
# killing mobiles */
if IS_NPC(victim):
# safe room? */
if IS_SET(victim.in_room.room_flags,ROOM_SAFE):
return True
if victim.pIndexData.pShop:
return True
# no killing healers, trainers, etc */
if IS_SET(victim.act,ACT_TRAIN) \
or IS_SET(victim.act,ACT_PRACTICE) \
or IS_SET(victim.act,ACT_IS_HEALER) \
or IS_SET(victim.act,ACT_IS_CHANGER):
return True
if not IS_NPC(ch):
# no pets */
if IS_SET(victim.act,ACT_PET):
return True
# no charmed creatures unless owner */
if IS_AFFECTED(victim,AFF_CHARM) and (area or ch != victim.master):
return True
# legal kill? -- cannot hit mob fighting non-group member */
if victim.fighting != None and not ch.is_same_group(victim.fighting):
return True
else:
# area effect spells do not hit other mobs */
if area and not victim.is_same_group(ch.fighting):
return True
# killing players */
else:
if area and IS_IMMORTAL(victim) and victim.level > LEVEL_IMMORTAL:
return True
# NPC doing the killing */
if IS_NPC(ch):
# charmed mobs and pets cannot attack players while owned */
if IS_AFFECTED(ch,AFF_CHARM) and ch.master and ch.master.fighting != victim:
return True
# safe room? */
if IS_SET(victim.in_room.room_flags,ROOM_SAFE):
return True
# legal kill? -- mobs only hit players grouped with opponent*/
if ch.fighting and not ch.fighting.is_same_group(victim):
return True
# player doing the killing */
else:
if not ch.is_clan():
return True
if IS_SET(victim.act,PLR_KILLER) or IS_SET(victim.act,PLR_THIEF):
return False
if not victim.is_clan():
return True
if ch.level > victim.level + 8:
return True
return False
#
# * See if an attack justifies a KILLER flag.
def check_killer( ch, victim ):
# * Follow charm thread to responsible character.
# * Attacking someone's charmed char is hostile!
while IS_AFFECTED(victim, AFF_CHARM) and victim.master != None:
victim = victim.master
# NPC's are fair game.
# So are killers and thieves.
if IS_NPC(victim) or IS_SET(victim.act, PLR_KILLER) or IS_SET(victim.act, PLR_THIEF):
return
# Charm-o-rama.
if IS_SET(ch.affected_by, AFF_CHARM):
if ch.master == None:
print ("BUG: Check_killer: %s bad AFF_CHARM" % (ch.short_descr if IS_NPC(ch) else ch.name ))
ch.affect_strip('charm person')
REMOVE_BIT(ch.affected_by, AFF_CHARM)
return
# send_to_char( "*** You are now a KILLER!! ***\n\r", ch.master )
# SET_BIT(ch.master.act, PLR_KILLER)
stop_follower( ch )
return
# NPC's are cool of course (as long as not charmed).
# Hitting yourself is cool too (bleeding).
# So is being immortal (Alander's idea).
# And current killers stay as they are.
if IS_NPC(ch) or ch == victim or ch.level >= LEVEL_IMMORTAL \
or not ch.is_clan() or IS_SET(ch.act, PLR_KILLER) or ch.fighting == victim:
return
ch.send("*** You are now a KILLER!! ***\n\r")
SET_BIT(ch.act, PLR_KILLER)
wiznet("$N is attempting to murder %s" % victim.name,ch,None,WIZ_FLAGS,0,0)
save_char_obj( ch )
return
# Check for parry.
def check_parry( ch, victim ):
if IS_AWAKE(victim):
return False
chance = victim.get_skill('parry') // 2
if victim.get_eq(WEAR_WIELD) == None:
if IS_NPC(victim):
chance //= 2
else:
return False
if not ch.can_see(victim):
chance //= 2
if random.randint(1,99) >= chance + victim.level - ch.level:
return False
act( "You parry $n's attack.", ch, None, victim, TO_VICT )
act( "$N parries your attack.", ch, None, victim, TO_CHAR )
check_improve(victim,'parry',True,6)
return True
# Check for shield block.
def check_shield_block( ch, victim ):
if not IS_AWAKE(victim):
return False
chance = victim.get_skill('shield block') // 5 + 3
if victim.get_eq(WEAR_SHIELD) == None:
return False
if random.randint(1,99) >= chance + victim.level - ch.level:
return False
act( "You block $n's attack with your shield.", ch, None, victim, TO_VICT)
act( "$N blocks your attack with a shield.", ch, None, victim, TO_CHAR)
check_improve(victim,'shield block',True,6)
return True
# Check for dodge.
def check_dodge( ch, victim ):
if not IS_AWAKE(victim):
return False
chance = victim.get_skill('dodge') // 2
if not victim.can_see(ch):
chance //= 2
if random.randint(1,99) >= chance + victim.level - ch.level:
return False
act( "You dodge $n's attack.", ch, None, victim, TO_VICT )
act( "$N dodges your attack.", ch, None, victim, TO_CHAR )
check_improve(victim,'dodge',True,6)
return True
# Set position of a victim.
def update_pos(victim):
if victim.hit > 0:
if victim.position <= POS_STUNNED:
victim.position = POS_STANDING
return
if IS_NPC(victim) and victim.hit < 1:
victim.position = POS_DEAD
return
if victim.hit <= -11:
victim.position = POS_DEAD
return
if victim.hit <= -6: victim.position = POS_MORTAL
elif victim.hit <= -3: victim.position = POS_INCAP
else: victim.position = POS_STUNNED
# Start fights.
def set_fighting( ch, victim ):
if ch.fighting != None:
print ("BUG: Set_fighting: already fighting")
return
if IS_AFFECTED(ch, AFF_SLEEP):
ch.affect_strip('sleep')
ch.fighting = victim
ch.position = POS_FIGHTING
# Stop fights.
def stop_fighting( ch, fBoth ):
for fch in char_list:
if fch == ch or ( fBoth and fch.fighting == ch ):
fch.fighting = None
fch.position = fch.default_pos if IS_NPC(fch) else POS_STANDING
update_pos( fch )
return
#
# * Make a corpse out of a character.
def make_corpse(ch):
from db import create_object
if IS_NPC(ch):
name = ch.short_descr
corpse = create_object(obj_index_hash[OBJ_VNUM_CORPSE_NPC], 0)
corpse.timer = random.randint( 3, 6 )
if ch.gold > 0:
create_money(ch.gold, ch.silver).to_obj(corpse)
ch.gold = 0
ch.silver = 0
corpse.cost = 0
else:
name = ch.name
corpse = create_object(obj_index_hash[OBJ_VNUM_CORPSE_PC], 0)
corpse.timer = random.randint(25, 40)
REMOVE_BIT(ch.act, PLR_CANLOOT)
if not ch.is_clan():
corpse.owner = ch.name
else:
corpse.owner = ""
if ch.gold > 1 or ch.silver > 1:
create_money(ch.gold // 2, ch.silver // 2).to_obj(corpse)
ch.gold -= ch.gold // 2
ch.silver -= ch.silver // 2
corpse.cost = 0
corpse.level = ch.level
corpse.short_descr = corpse.short_descr % name
corpse.description = corpse.description % name
for obj in ch.carrying[:]:
floating = False
if obj.wear_loc == WEAR_FLOAT:
floating = True
obj.from_char()
if obj.item_type == ITEM_POTION:
obj.timer = random.randint(500,1000)
if obj.item_type == ITEM_SCROLL:
obj.timer = random.randint(1000,2500)
if IS_SET(obj.extra_flags,ITEM_ROT_DEATH) and not floating:
obj.timer = random.randint(5,10)
REMOVE_BIT(obj.extra_flags,ITEM_ROT_DEATH)
REMOVE_BIT(obj.extra_flags,ITEM_VIS_DEATH)
if IS_SET( obj.extra_flags, ITEM_INVENTORY ):
obj.extract()
elif floating:
if IS_OBJ_STAT(obj,ITEM_ROT_DEATH): # get rid of it! */
if obj.contains:
act("$p evaporates,scattering its contents.", ch,obj,None,TO_ROOM)
for o in obj.contains[:]:
o.from_obj()
o.to_room(ch.in_room)
else:
act("$p evaporates.", ch,obj,None,TO_ROOM)
obj.extract()
else:
act("$p falls to the floor.",ch,obj,None,TO_ROOM)
obj.to_room(ch.in_room)
else:
obj.to_obj(corpse)
corpse.to_room(ch.in_room)
return
#
# Improved Death_cry contributed by Diavolo.
def death_cry( ch ):
from db import create_object
vnum = 0
msg = "You hear $n's death cry."
num = random.randint(0,7)
if num == 0: msg = "$n hits the ground ... DEAD."
elif num == 1:
if ch.material == 0:
msg = "$n splatters blood on your armor."
elif num == 2:
if IS_SET(ch.parts,PART_GUTS):
msg = "$n spills $s guts all over the floor."
vnum = OBJ_VNUM_GUTS
elif num == 3:
if IS_SET(ch.parts,PART_HEAD):
msg = "$n's severed head plops on the ground."
vnum = OBJ_VNUM_SEVERED_HEAD
elif num == 4:
if IS_SET(ch.parts,PART_HEART):
msg = "$n's heart is torn from $s chest."
vnum = OBJ_VNUM_TORN_HEART
elif num == 5:
if IS_SET(ch.parts,PART_ARMS):
msg = "$n's arm is sliced from $s dead body."
vnum = OBJ_VNUM_SLICED_ARM
elif num == 6:
if IS_SET(ch.parts,PART_LEGS):
msg = "$n's leg is sliced from $s dead body."
vnum = OBJ_VNUM_SLICED_LEG
elif num == 7:
if IS_SET(ch.parts,PART_BRAINS):
msg = "$n's head is shattered, and $s brains splash all over you."
vnum = OBJ_VNUM_BRAINS
act( msg, ch, None, None, TO_ROOM )
if vnum != 0:
name = ch.short_descr if IS_NPC(ch) else ch.name
obj = create_object( obj_index_hash[vnum], 0 )
obj.timer = random.randint( 4, 7 )
obj.short_descr = obj.short_descr % name
obj.description = obj.description % name
if obj.item_type == ITEM_FOOD:
if IS_SET(ch.form,FORM_POISON):
obj.value[3] = 1
elif not IS_SET(ch.form,FORM_EDIBLE):
obj.item_type = ITEM_TRASH
obj.to_room(ch.in_room)
if IS_NPC(ch):
msg = "You hear something's death cry."
else:
msg = "You hear someone's death cry."
was_in_room = ch.in_room
for pexit in was_in_room.exit:
if pexit and pexit.to_room and pexit.to_room != was_in_room:
ch.in_room = pexit.to_room
act( msg, ch, None, None, TO_ROOM )
ch.in_room = was_in_room
return
def raw_kill( victim ):
stop_fighting( victim, True )
death_cry( victim )
make_corpse( victim )
if IS_NPC(victim):
victim.pIndexData.killed += 1
#kill_table[max(0, min(victim.level, MAX_LEVEL-1))].killed += 1
victim.extract(True)
return
victim.extract(False)
for af in victim.affected[:]:
victim.affect_remove(af)
victim.affected_by = victim.race.aff
victim.armor = [100 for i in range(4)]
victim.position = POS_RESTING
victim.hit = max( 1, victim.hit )
victim.mana = max( 1, victim.mana )
victim.move = max( 1, victim.move )
# save_char_obj( victim ) we're stable enough to not need this :) */
return
def group_gain( ch, victim ):
# Monsters don't get kill xp's or alignment changes.
# P-killing doesn't help either.
# Dying of mortal wounds or poison doesn't give xp to anyone!
if victim == ch:
return
members = 0
group_levels = 0
for gch in ch.in_room.people:
if gch.is_same_group(ch):
members += 1
group_levels += gch.level // 2 if IS_NPC(gch) else gch.level
if members == 0:
print ("BUG: Group_gain: members. %s" % members)
members = 1
group_levels = ch.level
lch = ch.leader if ch.leader else ch
for gch in ch.in_room.people:
if not gch.is_same_group(ch) or IS_NPC(gch):
continue
#Taken out, add it back if you want it
if gch.level - lch.level >= 5:
gch.send("You are too high for this group.\n\r")
continue
if gch.level - lch.level <= -5:
gch.send("You are too low for this group.\n\r")
continue
#*/
xp = xp_compute( gch, victim, group_levels )
gch.send("You receive %d experience points.\n\r" % xp)
gain_exp( gch, xp )
for obj in ch.carrying[:]:
if obj.wear_loc == WEAR_NONE:
continue
if (IS_OBJ_STAT(obj, ITEM_ANTI_EVIL) and IS_EVIL(ch) ) \
or (IS_OBJ_STAT(obj, ITEM_ANTI_GOOD) and IS_GOOD(ch) ) \
or (IS_OBJ_STAT(obj, ITEM_ANTI_NEUTRAL) and IS_NEUTRAL(ch) ):
act( "You are zapped by $p.", ch, obj, None, TO_CHAR )
act( "$n is zapped by $p.", ch, obj, None, TO_ROOM )
obj.from_char()
obj.to_room(ch.in_room)
# Compute xp for a kill.
# Also adjust alignment of killer.
# Edit this function to change xp computations.
def xp_compute( gch, victim, total_levels ):
level_range = victim.level - gch.level
# compute the base exp */
if level_range == -9 : base_exp = 1
elif level_range == -8: base_exp = 2
elif level_range == -7: base_exp = 5
elif level_range == -6: base_exp = 9
elif level_range == -5: base_exp = 11
elif level_range == -4: base_exp = 22
elif level_range == -3: base_exp = 33
elif level_range == -2: base_exp = 50
elif level_range == -1: base_exp = 66
elif level_range == 0: base_exp = 83
elif level_range == 1: base_exp = 99
elif level_range == 2: base_exp = 121
elif level_range == 3: base_exp = 143
elif level_range == 4: base_exp = 165
else: base_exp = 0
if level_range > 4:
base_exp = 160 + 20 * (level_range - 4)
# do alignment computations */
align = victim.alignment - gch.alignment
if IS_SET(victim.act,ACT_NOALIGN):
pass # no change */
elif align > 500: # monster is more good than slayer */
change = (align - 500) * base_exp // 500 * gch.level // total_levels
change = max(1,change)
gch.alignment = max(-1000,gch.alignment - change)
elif align < -500: # monster is more evil than slayer */
change = ( -1 * align - 500) * base_exp // 500 * gch.level // total_levels
change = max(1,change)
gch.alignment = min(1000,gch.alignment + change)
else: # improve this someday */
change = gch.alignment * base_exp // 500 * gch.level // total_levels
gch.alignment -= change
# calculate exp multiplier */
if IS_SET(victim.act,ACT_NOALIGN):
xp = base_exp
elif gch.alignment > 500: # for goodie two shoes */
if victim.alignment < -750:
xp = (base_exp *4) // 3
elif victim.alignment < -500:
xp = (base_exp * 5) // 4
elif victim.alignment > 750:
xp = base_exp // 4
elif victim.alignment > 500:
xp = base_exp // 2
elif victim.alignment > 250:
xp = (base_exp * 3) // 4
else:
xp = base_exp
elif gch.alignment < -500:# for baddies */
if victim.alignment > 750:
xp = (base_exp * 5) // 4
elif victim.alignment > 500:
xp = (base_exp * 11) // 10
elif victim.alignment < -750:
xp = base_exp // 2
elif victim.alignment < -500:
xp = (base_exp * 3) // 4
elif victim.alignment < -250:
xp = (base_exp * 9) // 10
else:
xp = base_exp
elif gch.alignment > 200: # a little good */
if victim.alignment < -500:
xp = (base_exp * 6) // 5
elif victim.alignment > 750:
xp = base_exp // 2
elif victim.alignment > 0:
xp = (base_exp * 3) // 4
else:
xp = base_exp
elif gch.alignment < -200: # a little bad */
if victim.alignment > 500:
xp = (base_exp * 6) // 5
elif victim.alignment < -750:
xp = base_exp // 2
elif victim.alignment < 0:
xp = (base_exp * 3) // 4
else:
xp = base_exp
else: # neutral */
if victim.alignment > 500 or victim.alignment < -500:
xp = (base_exp * 4) // 3
elif victim.alignment < 200 and victim.alignment > -200:
xp = base_exp // 2
else:
xp = base_exp
# more exp at the low levels */
if gch.level < 6:
xp = 10 * xp // (gch.level + 4)
# less at high */
if gch.level > 35:
xp = 15 * xp // (gch.level - 25 )
# reduce for playing time */
# compute quarter-hours per level */
time_per_level = 4 * (gch.played + (int) (current_time - gch.logon)) // 3600 // gch.level
time_per_level = max(2, min(time_per_level,12))
if gch.level < 15: # make it a curve */
time_per_level = max(time_per_level,(15 - gch.level))
xp = xp * time_per_level // 12
# randomize the rewards */
xp = random.randint (int(xp * 3 // 4), int(xp * 5 // 4))
# adjust for grouping */
xp = xp * gch.level // ( max(1,total_levels -1) )
return xp
def dam_message( ch, victim, dam, dt, immune ):
if ch == None or victim == None:
return
if dam == 0: msg = {'vs':"miss", 'vp':"misses"}
elif dam <= 4: msg = {'vs':"scratch", 'vp':"scratches"}
elif dam <= 8: msg = {'vs':"graze", 'vp':"grazes"}
elif dam <= 12: msg = {'vs':"hit", 'vp':"hits"}
elif dam <= 16: msg = {'vs':"injure", 'vp':"injures"}
elif dam <= 20: msg = {'vs':"wound", 'vp':"wounds"}
elif dam <= 24: msg = {'vs':"maul", 'vp':"mauls"}
elif dam <= 28: msg = {'vs':"decimate", 'vp':"decimates"}
elif dam <= 32: msg = {'vs':"devastate", 'vp':"devastates"}
elif dam <= 36: msg = {'vs':"maim", 'vp':"maims"}
elif dam <= 40: msg = {'vs':"MUTILATE", 'vp':"MUTILATES"}
elif dam <= 44: msg = {'vs':"DISEMBOWEL", 'vp':"DISEMBOWELS"}
elif dam <= 48: msg = {'vs':"DISMEMBER", 'vp':"DISMEMBERS"}
elif dam <= 52: msg = {'vs':"MASSACRE", 'vp':"MASSACRES"}
elif dam <= 56: msg = {'vs':"MANGLE", 'vp':"MANGLES"}
elif dam <= 60: msg = {'vs':"*** DEMOLISH ***", 'vp':"*** DEMOLISHES ***"}
elif dam <= 75: msg = {'vs':"*** DEVASTATE ***", 'vp':"*** DEVASTATES ***"}
elif dam <= 100: msg = {'vs':"=== OBLITERATE ===", 'vp':"=== OBLITERATES ==="}
elif dam <= 125: msg = {'vs':">>> ANNIHILATE <<<", 'vp':">>> ANNIHILATES <<<"}
elif dam <= 150: msg = {'vs':"<<< ERADICATE >>>", 'vp':"<<< ERADICATES >>>"}
else: msg = {'vs':"do UNSPEAKABLE things to", 'vp':"does UNSPEAKABLE things to"}
vs = msg['vs']
vp = msg['vp']
punct = '.' if dam <= 24 else '!'
if dt == TYPE_HIT:
if ch == victim:
buf1 = "$n %s $melf%c" % (vp,punct)
buf2 = "You %s yourself%c" % (vs, punct)
else:
buf1 = "$n %s $N%c" % ( vp, punct )
buf2 = "You %s $N%c" % ( vs, punct )
buf3 = "$n %s you%c" % ( vp, punct )
else:
if dt >= 0 and dt < MAX_SKILL:
attack = const.skill_table[dt].noun_damage
elif dt >= TYPE_HIT and dt < TYPE_HIT + len(const.attack_table):
attack = const.attack_table[dt - TYPE_HIT].noun
else:
print ("BUG: Dam_message: bad dt %d.")
dt = TYPE_HIT
attack = const.attack_table[0].name
if immune:
if ch == victim:
buf1 = "$n is unaffected by $s own %s." % attack
buf2 = "Luckily, you are immune to that."
else:
buf1 = "$N is unaffected by $n's %s!" % attack
buf2 = "$N is unaffected by your %s!" % attack
buf3 = "$n's %s is powerless against you." % attack
else:
if ch == victim:
buf1 = "$n's %s %s $m%c" % (attack,vp,punct)
buf2 = "Your %s %s you%c" % (attack,vp,punct)
else:
buf1 = "$n's %s %s $N%c" % (attack, vp, punct)
buf2 = "Your %s %s $N%c" % (attack, vp, punct)
buf3 = "$n's %s %s you%c" % (attack, vp, punct)
if ch == victim:
act(buf1,ch,None,None,TO_ROOM)
act(buf2,ch,None,None,TO_CHAR)
else:
act( buf1, ch, None, victim, TO_NOTVICT )
act( buf2, ch, None, victim, TO_CHAR )
act( buf3, ch, None, victim, TO_VICT )
return
# * Disarm a creature.
# * Caller must check for successful attack.
def disarm( ch, victim ):
obj = victim.get_eq(WEAR_WIELD)
if not obj:
ch.send("I think you're taking disarm a little too literally")
return
if IS_OBJ_STAT(obj,ITEM_NOREMOVE):
act("$S weapon won't budge!",ch,None,victim,TO_CHAR)
act("$n tries to disarm you, but your weapon won't budge!", ch,None,victim,TO_VICT)
act("$n tries to disarm $N, but fails.",ch,None,victim,TO_NOTVICT)
return
act( "$n DISARMS you and sends your weapon flying!", ch, None, victim, TO_VICT)
act( "You disarm $N!", ch, None, victim, TO_CHAR )
act( "$n disarms $N!", ch, None, victim, TO_NOTVICT )
obj.from_char()
if IS_OBJ_STAT(obj,ITEM_NODROP) or IS_OBJ_STAT(obj,ITEM_INVENTORY):
obj.to_char(victim)
else:
obj.to_room(victim.in_room)
if IS_NPC(victim) and victim.wait == 0 and victim.can_see_obj(obj):
get_obj(victim,obj,None)
return
def do_berserk( self, argument):
ch = self
chance = ch.get_skill('berserk')
if chance== 0 or (IS_NPC(ch) and not IS_SET(ch.off_flags,OFF_BERSERK)) \
or (not IS_NPC(ch) and ch.level < const.skill_table['berserk'].skill_level[ch.guild.name]):
ch.send("You turn red in the face, but nothing happens.\n\r")
return
if IS_AFFECTED(ch,AFF_BERSERK) or is_affected(ch,'berserk') or is_affected(ch,"frenzy"):
ch.send("You get a little madder.\n\r")
return
if IS_AFFECTED(ch,AFF_CALM):
ch.send("You're feeling to mellow to berserk.\n\r")
return
if ch.mana < 50:
ch.send("You can't get up enough energy.\n\r")
return
# modifiers */
# fighting */
if ch.position == POS_FIGHTING:
chance += 10
# damage -- below 50% of hp helps, above hurts */
hp_percent = 100 * ch.hit // ch.max_hit
chance += 25 - hp_percent // 2
if random.randint(1,99) < chance:
WAIT_STATE(ch,PULSE_VIOLENCE)
ch.mana -= 50
ch.move //= 2
# heal a little damage */
ch.hit += ch.level * 2
ch.hit = min(ch.hit,ch.max_hit)
ch.send("Your pulse races as you are consumed by rage!\n\r")
act("$n gets a wild look in $s eyes.",ch,None,None,TO_ROOM)
check_improve(ch,'berserk',True,2)
af = AFFECT_DATA()
af.where = TO_AFFECTS
af.type = 'berserk'
af.level = ch.level
af.duration = number_fuzzy(ch.level // 8)
af.modifier = max(1,ch.level // 5)
af.bitvector = AFF_BERSERK
af.location = APPLY_HITROLL
ch.affect_add(af)
af.location = APPLY_DAMROLL
ch.affect_add(af)
af.modifier = max(10,10 * (ch.level // 5))
af.location = APPLY_AC
ch.affect_add(af)
else:
WAIT_STATE(ch,3 * PULSE_VIOLENCE)
ch.mana -= 25
ch.move //= 2
ch.send("Your pulse speeds up, but nothing happens.\n\r")
check_improve(ch,'berserk',False,2)
def do_bash( ch, argument ):
arghold, arg = read_word(argument)
chance = ch.get_skill('bash')
if chance == 0 or (IS_NPC(ch) and not IS_SET(ch.off_flags,OFF_BASH)) \
or (not IS_NPC(ch) and ch.level < const.skill_table['bash'].skill_level[ch.guild.name] ):
ch.send("Bashing? What's that?\n\r")
return
victim = None
if not arg:
victim = ch.fighting
if not victim:
ch.send("But you aren't fighting anyone!\n\r")
return
else:
victim = ch.get_char_room(arg)
if not victim:
ch.send("They aren't here.\n\r")
return
if victim.position < POS_FIGHTING:
act("You'll have to let $M get back up first.",ch,None,victim,TO_CHAR)
return
if victim == ch:
ch.send("You try to bash your brains out, but fail.\n\r")
return
if is_safe(ch,victim):
return
if IS_NPC(victim) and victim.fighting and not ch.is_same_group(victim.fighting):
ch.send("Kill stealing is not permitted.\n\r")
return
if IS_AFFECTED(ch,AFF_CHARM) and ch.master == victim:
act("But $N is your friend!",ch,None,victim,TO_CHAR)
return
# modifiers */
# size and weight */
chance += ch.carry_weight // 250
chance -= victim.carry_weight // 200
if ch.size < victim.size:
chance += (ch.size - victim.size) * 15
else:
chance += (ch.size - victim.size) * 10
# stats */
chance += ch.get_curr_stat(STAT_STR)
chance -= (victim.get_curr_stat(STAT_DEX) * 4) // 3
chance -= GET_AC(victim,AC_BASH) // 25
# speed */
if IS_SET(ch.off_flags,OFF_FAST) or IS_AFFECTED(ch,AFF_HASTE):
chance += 10
if IS_SET(victim.off_flags,OFF_FAST) or IS_AFFECTED(victim,AFF_HASTE):
chance -= 30
# level */
chance += (ch.level - victim.level)
if not IS_NPC(victim) and chance < victim.get_skill('dodge'):
pass
#act("$n tries to bash you, but you dodge it.",ch,None,victim,TO_VICT)
#act("$N dodges your bash, you fall flat on your face.",ch,None,victim,TO_CHAR)
#WAIT_STATE(ch,const.skill_table['bash'].beats)
#return*/
chance -= 3 * (victim.get_skill('dodge') - chance)
# now the attack */
if random.randint(1,99) < chance:
act("$n sends you sprawling with a powerful bash!", ch,None,victim,TO_VICT)
act("You slam into $N, and send $M flying!",ch,None,victim,TO_CHAR)
act("$n sends $N sprawling with a powerful bash.", ch,None,victim,TO_NOTVICT)
check_improve(ch,'bash',True,1)
DAZE_STATE(victim, 3 * PULSE_VIOLENCE)
WAIT_STATE(ch,const.skill_table['bash'].beats)
victim.position = POS_RESTING
damage(ch,victim,random.randint(2,2 + 2 * ch.size + chance // 20),'bash', DAM_BASH,False)
else:
damage(ch,victim,0,'bash',DAM_BASH,False)
act("You fall flat on your face!", ch,None,victim,TO_CHAR)
act("$n falls flat on $s face.", ch,None,victim,TO_NOTVICT)
act("You evade $n's bash, causing $m to fall flat on $s face.", ch,None,victim,TO_VICT)
check_improve(ch,'bash',False,1)
ch.position = POS_RESTING
WAIT_STATE(ch,const.skill_table['bash'].beats * 3 // 2)
check_killer(ch,victim)
def do_dirt( self, argument ):
ch = self
arghold, arg = read_word(argument)
chance = ch.get_skill('dirt kicking')
if chance == 0 or (IS_NPC(ch) and not IS_SET(ch.off_flags,OFF_KICK_DIRT)) \
or ( not IS_NPC(ch) and ch.level < const.skill_table['dirt kicking'].skill_level[ch.guild.name]):
ch.send("You get your feet dirty.\n\r")
return
if not arg:
victim = ch.fighting
if victim == None:
ch.send("But you aren't in combat!\n\r")
return
else:
victim = ch.get_char_room(arg)
if victim == None:
ch.send("They aren't here.\n\r")
return
if IS_AFFECTED(victim,AFF_BLIND):
act("$E's already been blinded.",ch,None,victim,TO_CHAR)
return
if victim == ch:
ch.send("Very funny.\n\r")
return
if is_safe(ch,victim):
return
if IS_NPC(victim) and victim.fighting != None and not ch.is_same_group(victim.fighting):
ch.send("Kill stealing is not permitted.\n\r")
return
if IS_AFFECTED(ch,AFF_CHARM) and ch.master == victim:
act("But $N is such a good friend!",ch,None,victim,TO_CHAR)
return
# modifiers */
# dexterity */
chance += ch.get_curr_stat(STAT_DEX)
chance -= 2 * victim.get_curr_stat(STAT_DEX)
# speed */
if IS_SET(ch.off_flags,OFF_FAST) or IS_AFFECTED(ch,AFF_HASTE):
chance += 10
if IS_SET(victim.off_flags,OFF_FAST) or IS_AFFECTED(victim,AFF_HASTE):
chance -= 25
# level */
chance += (ch.level - victim.level) * 2
# sloppy hack to prevent false zeroes */
if chance % 5 == 0:
chance += 1
# terrain */
nochance = [ SECT_WATER_SWIM, SECT_WATER_NOSWIM, SECT_AIR ]
modifiers = { SECT_INSIDE: -20,
SECT_CITY: -10,
SECT_FIELD: 5,
SECT_MOUNTAIN: -10,
SECT_DESERT: 10
}
if ch.in_room.sector_type in nochance:
chance = 0
elif ch.in_room.sector_type in modifiers:
chance += modifiers[ch.in_room.sector_type]
if chance == 0:
ch.send("There isn't any dirt to kick.\n\r")
return
# now the attack */
if random.randint(1,99) < chance:
act("$n is blinded by the dirt in $s eyes!",victim,None,None,TO_ROOM)
act("$n kicks dirt in your eyes!",ch,None,victim,TO_VICT)
damage(ch,victim,random.randint(2,5),'dirt kicking',DAM_NONE,False)
victim.send("You can't see a thing!\n\r")
check_improve(ch,'dirt kicking',True,2)
WAIT_STATE(ch,const.skill_table['dirt kicking'].beats)
af = AFFECT_DATA()
af.where = TO_AFFECTS
af.type = 'dirt kicking'
af.level = ch.level
af.duration = 0
af.location = APPLY_HITROLL
af.modifier = -4
af.bitvector = AFF_BLIND
victim.affect_add(af)
else:
damage(ch,victim,0,'dirt kicking',DAM_NONE,True)
check_improve(ch,'dirt kicking',False,2)
WAIT_STATE(ch,const.skill_table['dirt kicking'].beats)
check_killer(ch,victim)
def do_trip( self, argument ):
ch = self
arghold, arg = read_word(argument)
chance = ch.get_skill('trip')
if chance == 0 or (IS_NPC(ch) and not IS_SET(ch.off_flags,OFF_TRIP)) \
or ( not IS_NPC(ch) and ch.level < const.skill_table['trip'].skill_level[ch.guild.name]):
ch.send("Tripping? What's that?\n\r")
return
if not arg:
victim = ch.fighting
if victim == None:
ch.send("But you aren't fighting anyone!\n\r")
return
else:
victim = ch.get_char_room(arg)
if victim == None:
ch.send("They aren't here.\n\r")
return
if is_safe(ch,victim):
return
if IS_NPC(victim) and victim.fighting and not ch.is_same_group(victim.fighting):
ch.send("Kill stealing is not permitted.\n\r")
return
if IS_AFFECTED(victim,AFF_FLYING):
act("$S feet aren't on the ground.",ch,None,victim,TO_CHAR)
return
if victim.position < POS_FIGHTING:
act("$N is already down.",ch,None,victim,TO_CHAR)
return
if victim == ch:
ch.send("You fall flat on your face!\n\r")
WAIT_STATE(ch,2 * const.skill_table['trip'].beats)
act("$n trips over $s own feet!",ch,None,None,TO_ROOM)
return
if IS_AFFECTED(ch,AFF_CHARM) and ch.master == victim:
act("$N is your beloved master.",ch,None,victim,TO_CHAR)
return
# modifiers */
# size */
if ch.size < victim.size:
chance += (ch.size - victim.size) * 10 # bigger = harder to trip */
# dex */
chance += ch.get_curr_stat(STAT_DEX)
chance -= victim.get_curr_stat(STAT_DEX) * 3 // 2
# speed */
if IS_SET(ch.off_flags,OFF_FAST) or IS_AFFECTED(ch,AFF_HASTE):
chance += 10
if IS_SET(victim.off_flags,OFF_FAST) or IS_AFFECTED(victim,AFF_HASTE):
chance -= 20
# level */
chance += (ch.level - victim.level) * 2
# now the attack */
if random.randint(1,99) < chance:
act("$n trips you and you go down!",ch,None,victim,TO_VICT)
act("You trip $N and $N goes down!",ch,None,victim,TO_CHAR)
act("$n trips $N, sending $M to the ground.",ch,None,victim,TO_NOTVICT)
check_improve(ch,'trip',True,1)
DAZE_STATE(victim,2 * PULSE_VIOLENCE)
WAIT_STATE(ch,const.skill_table['trip'].beats)
victim.position = POS_RESTING
damage(ch,victim,random.randint(2, 2 + 2 * victim.size),'trip', DAM_BASH,True)
else:
damage(ch,victim,0,'trip',DAM_BASH,True)
WAIT_STATE(ch,const.skill_table['trip'].beats*2 // 3)
check_improve(ch,'trip',False,1)
check_killer(ch,victim)
def do_kill( self, argument ):
ch = self
argument, arg = read_word(argument)
if not arg:
ch.send("Kill whom?\n\r")
return
victim = ch.get_char_room(arg)
if victim == None:
ch.send("They aren't here.\n\r")
return
# Allow player killing
# if not IS_NPC(victim):
# if not IS_SET(victim.act, PLR_KILLER) and not IS_SET(victim.act, PLR_THIEF):
# ch.send("You must MURDER a player.\n\r")
# return
if victim == ch:
ch.send("You hit yourself. Ouch!\n\r")
multi_hit( ch, ch, TYPE_UNDEFINED )
return
if is_safe( ch, victim ):
return
if victim.fighting and not ch.is_same_group(victim.fighting):
ch.send("Kill stealing is not permitted.\n\r")
return
if IS_AFFECTED(ch, AFF_CHARM) and ch.master == victim:
act( "$N is your beloved master.", ch, None, victim, TO_CHAR )
return
if ch.position == POS_FIGHTING:
ch.send("You do the best you can!\n\r")
return
WAIT_STATE( ch, 1 * PULSE_VIOLENCE )
check_killer( ch, victim )
multi_hit( ch, victim, TYPE_UNDEFINED )
return
def do_murde( self, argument ):
self.send("If you want to MURDER, spell it out.\n\r")
return
def do_murder( self, argument ):
ch = self
argument, arg = read_word(argument)
if not arg:
ch.send("Murder whom?\n\r")
return
if IS_AFFECTED(ch,AFF_CHARM) or (IS_NPC(ch) and IS_SET(ch.act,ACT_PET)):
return
victim = ch.get_char_room(arg)
if victim == None:
ch.send("They aren't here.\n\r")
return
if victim == ch:
ch.send("Suicide is a mortal sin.\n\r")
return
if is_safe( ch, victim ):
return
if IS_NPC(victim) and victim.fighting and not ch.is_same_group(victim.fighting):
ch.send("Kill stealing is not permitted.\n\r")
return
if IS_AFFECTED(ch, AFF_CHARM) and ch.master == victim:
act( "$N is your beloved master.", ch, None, victim, TO_CHAR )
return
if ch.position == POS_FIGHTING:
ch.send("You do the best you can!\n\r")
return
WAIT_STATE( ch, 1 * PULSE_VIOLENCE )
if IS_NPC(ch):
buf = "Help! I am being attacked by %s!" % ch.short_descr
else:
buf = "Help! I am being attacked by %s!" % ch.name
victim.do_yell(buf)
check_killer( ch, victim )
multi_hit( ch, victim, TYPE_UNDEFINED )
return
def do_backstab( self, argument ):
ch = self
argument, arg = read_word(argument)
if not arg:
ch.send("Backstab whom?\n\r")
return
victim = None
if ch.fighting:
ch.send("You're facing the wrong end.\n\r")
return
else:
victim = ch.get_char_room(arg)
if not victim:
ch.send("They aren't here.\n\r")
return
if victim == ch:
ch.send("How can you sneak up on yourself?\n\r")
return
if is_safe( ch, victim ):
return
if IS_NPC(victim) and victim.fighting and not ch.is_same_group(victim.fighting):
ch.send("Kill stealing is not permitted.\n\r")
return
obj = ch.get_eq(WEAR_WIELD)
if obj:
ch.send("You need to wield a weapon to backstab.\n\r")
return
if victim.hit < victim.max_hit // 3:
act( "$N is hurt and suspicious ... you can't sneak up.", ch, None, victim, TO_CHAR )
return
check_killer( ch, victim )
WAIT_STATE( ch, const.skill_table['backstab'].beats )
if random.randint(1,99) < ch.get_skill('backstab') \
or ( ch.get_skill('backstab') >= 2 and not IS_AWAKE(victim) ):
check_improve(ch,'backstab',True,1)
multi_hit( ch, victim, 'backstab' )
else:
check_improve(ch,'backstab',False,1)
damage( ch, victim, 0, 'backstab',DAM_NONE,True)
return
def do_flee( ch, argument ):
victim = ch.fighting
if not victim:
if ch.position == POS_FIGHTING:
ch.position = POS_STANDING
ch.send("You aren't fighting anyone.\n\r")
return
was_in = ch.in_room
for attempt in range(6):
door = number_door( )
pexit = was_in.exit[door]
if not pexit or not pexit.to_room or IS_SET(pexit.exit_info, EX_CLOSED) or random.randint(0,ch.daze) != 0 \
or ( IS_NPC(ch) and IS_SET(pexit.u1.to_room.room_flags, ROOM_NO_MOB) ):
continue
move_char( ch, door, False )
now_in = ch.in_room
if now_in == was_in:
continue
ch.in_room = was_in
act( "$n has fled!", ch, None, None, TO_ROOM )
ch.in_room = now_in
if not IS_NPC(ch):
ch.send("You flee from combat!\n\r")
if ch.guild.name == 'thief' and (random.randint(1,99) < 3*(ch.level // 2) ):
ch.send("You snuck away safely.\n\r")
else:
ch.send("You lost 10 exp.\n\r")
gain_exp( ch, -10 )
stop_fighting( ch, True )
return
ch.send("PANIC! You couldn't escape!\n\r")
return
def do_rescue( self, argument ):
ch = self
argument, arg = read_word(argument)
if not arg:
ch.send("Rescue whom?\n\r")
return
victim = ch.get_char_room(arg)
if not victim:
ch.send("They aren't here.\n\r")
return
if victim == ch:
ch.send("What about fleeing instead?\n\r")
return
if not IS_NPC(ch) and IS_NPC(victim):
ch.send("Doesn't need your help!\n\r")
return
if ch.fighting == victim:
ch.send("Too late.\n\r")
return
fch = victim.fighting
if not fch:
ch.send("That person is not fighting right now.\n\r")
return
if IS_NPC(fch) and not ch.is_same_group(victim):
ch.send("Kill stealing is not permitted.\n\r")
return
WAIT_STATE( ch, const.skill_table['rescue'].beats )
if random.randint(1,99) > ch.get_skill('rescue'):
ch.send("You fail the rescue.\n\r")
check_improve(ch,'rescue',False,1)
return
act( "You rescue $N!", ch, None, victim, TO_CHAR )
act( "$n rescues you!", ch, None, victim, TO_VICT )
act( "$n rescues $N!", ch, None, victim, TO_NOTVICT )
check_improve(ch,'rescue',True,1)
stop_fighting( fch, False )
stop_fighting( victim, False )
check_killer( ch, fch )
set_fighting( ch, fch )
set_fighting( fch, ch )
return
def do_kick( self, argument ):
ch = self
if not IS_NPC(ch) and ch.level < const.skill_table['kick'].skill_level[ch.guild.name]:
ch.send("You better leave the martial arts to fighters.\n\r")
return
if IS_NPC(ch) and not IS_SET(ch.off_flags,OFF_KICK):
return
victim = ch.fighting
if not victim:
ch.send("You aren't fighting anyone.\n\r")
return
WAIT_STATE( ch, const.skill_table['kick'].beats )
if ch.get_skill('kick') > random.randint(1,99):
damage(ch,victim,random.randint( 1, ch.level ), 'kick',DAM_BASH,True)
check_improve(ch,'kick',True,1)
else:
damage( ch, victim, 0, 'kick',DAM_BASH,True)
check_improve(ch,'kick',False,1)
check_killer(ch,victim)
return
def do_disarm( ch, argument ):
hth = 0
chance = ch.get_skill('disarm')
if chance == 0:
ch.send("You don't know how to disarm opponents.\n\r")
return
hth = ch.get_skill('hand to hand')
if not ch.get_eq(WEAR_WIELD) \
and hth == 0 or (IS_NPC(ch) and not IS_SET(ch.off_flags,OFF_DISARM)):
ch.send("You must wield a weapon to disarm.\n\r")
return
victim = ch.fighting
if not victim:
ch.send("You aren't fighting anyone.\n\r")
return
obj = victim.get_eq(WEAR_WIELD)
if not obj:
ch.send("Your opponent is not wielding a weapon.\n\r")
return
# find weapon skills */
ch_weapon = ch.get_weapon_skill(ch.get_weapon_sn())
vict_weapon = victim.get_weapon_skill(victim.get_weapon_sn())
ch_vict_weapon = ch.get_weapon_skill(victim.get_weapon_sn())
# modifiers */
# skill */
if ch.get_eq(WEAR_WIELD) == None:
chance = chance * hth // 150
else:
chance = chance * ch_weapon // 100
chance += (ch_vict_weapon // 2 - vict_weapon) // 2
# dex vs. strength */
chance += ch.get_curr_stat(STAT_DEX)
chance -= 2 * victim.get_curr_stat(STAT_STR)
# level */
chance += (ch.level - victim.level) * 2
# and now the attack */
if random.randint(1,99) < chance:
WAIT_STATE( ch, const.skill_table['disarm'].beats )
disarm( ch, victim )
check_improve(ch,'disarm',True,1)
else:
WAIT_STATE(ch,const.skill_table['disarm'].beats)
act("You fail to disarm $N.",ch,None,victim,TO_CHAR)
act("$n tries to disarm you, but fails.",ch,None,victim,TO_VICT)
act("$n tries to disarm $N, but fails.",ch,None,victim,TO_NOTVICT)
check_improve(ch,'disarm',False,1)
check_killer(ch,victim)
return
def do_sla(ch, argument ):
ch.send("If you want to SLAY, spell it out.\n\r")
return
def do_slay( ch, argument ):
argument, arg = read_word(argument)
if not arg:
ch.send("Slay whom?\n\r")
return
victim = ch.get_char_room(arg)
if not victim:
ch.send("They aren't here.\n\r")
return
if ch == victim:
ch.send("Suicide is a mortal sin.\n\r")
return
if not IS_NPC(victim) and victim.level >= ch.get_trust():
ch.send("You failed.\n\r")
return
act( "You slay $M in cold blood!", ch, None, victim, TO_CHAR )
act( "$n slays you in cold blood!", ch, None, victim, TO_VICT )
act( "$n slays $N in cold blood!", ch, None, victim, TO_NOTVICT )
raw_kill( victim )
return