"""Classes, functions, and constants relating to monsters. @var TINY: The smallest kind of monster. @var SMALL: f @var NORMAL: f @var LARGE: v @var GIANT: f """ from . import Utl, Ifc, Item, g import th class Level(object): str = dex = int = hp = 1 mst = mdx = min = mhp = 1 pst = pdx = pin = 0 def __init__(self, str, dex, int, hp, mst, mdx, min, mhp, pst, pdx, pin): self.str, self.dex, self.int, self.hp = str, dex, int, hp self.mst, self.mdx, self.min, self.mhp = mst, mdx, min, mhp self.pst, self.pdx, self.pin = pst, pdx, pin def level_up(self, mon): delta = Utl.d(1, self.dex) if Utl.rn(100) < self.pdx and delta + mon.mdx <= self.mdx: Ifc.you('|are| more dexterous!', mon) mon.mdx += delta mon.dex += delta delta = Utl.d(1, self.str) if Utl.rn(100) < self.pst and delta + mon.mst <= self.mst: Ifc.you('|are| stronger!', mon) mon.mst += delta mon.str += delta delta = Utl.d(1, self.int) if Utl.rn(100) < self.pin and delta + mon.min <= self.min: Ifc.you('|are| smarter!', mon) mon.min += delta mon.int += delta delta = Utl.d(1, self.hp) if delta + mon.mhp <= self.hp: Ifc.you('|are| healthier!', mon) mon.mhp += delta mon.hp += delta def levels(self, mon, n): for x in range(n): self.level_up(mon) # st dx in hp mst mdx min mhp pst pdx pin lHumanoid = Level(2, 2, 2, 8, 25, 25, 30, 150, 33, 33, 33) lDragon = Level(2, 2, 2, 8, 45, 45, 45, 250, 13, 13, 13) lPatheticCreature = Level(1, 1, 1, 4, 10, 10, 10, 20, 25, 25, 25) lModerateAnimal = Level(2, 2, 1, 8, 30, 30, 10, 160, 50, 33, 10) lIntPunch = Level(1, 2, 2, 8, 10, 30, 30, 160, 25, 33, 50) lFox = Level(4, 4, 4, 8, 25, 50, 30, 120, 50, 75, 50) lBeast = Level(5, 2, 2, 15, 36, 36, 12, 250, 55, 25, 15) lFlayer = Level(3, 3, 3, 6, 25, 25, 40, 110, 50, 50, 50) TINY, SMALL, NORMAL, LARGE, GIANT = range(5) SLEEPING, WANDERING, ATTACKING, FLEEING, PET = range(5) GENDER_FMT = [ {'you': 'it', 'youm': 'it', 'your': 'its', 've': 's'}, {'you': 'he', 'youm': 'him', 'your': 'his', 've': 's'}, {'you': 'she', 'youm': 'her', 'your': 'her', 've': 's'}, {'you': 'it', 'youm': 'it', 'your': 'its', 've': 's'} ] NOT_TALKATIVE = [ "|do| not share your penchant for conversation.", "|are|n't much of a conversationalist.", "can't carry on a decent conversation.", "|do|n't share your penchant for conversation.", "|are|n't very talkative." ] RABID_TALK = [ "snarl|s|.", "growl|s|.", "hiss|es|.", "make|s| vicious-sounding noises.", "stare|s| at you with a crazed look.", "watch|es| you with murderous intent." ] BORG_TALK = [ "YOU WILL BE ASSIMILATED", "RESISTANCE IS FUTILE", "EXTERMINATE! EXTERMINATE", "YOU WILL BE ASSIMILATED. RESISTANCE IS FUTILE" ] GENDER = ["ungendered", "male", "female", "hermaphrodite"] MALE, FEMALE = 1, 2 ALIGNMENT = ['neutrally', 'nerd', 'jock'] AI_STATUS = [ '%s(asleep)%s' % (Ifc.color(Ifc.MAGENTA), Ifc.color()), '%s(peaceful)%s' % (Ifc.color(Ifc.CYAN), Ifc.color()), '%s(hostile)%s' % (Ifc.color(Ifc.BRIGHT_RED), Ifc.color()), '%s(fleeing)%s' % (Ifc.color(Ifc.YELLOW), Ifc.color()), '%s(allied)%s' % (Ifc.color(Ifc.GREEN), Ifc.color()) ] GENDER_FMT = [ {'you': 'it', 'youm': 'it', 'your': 'its', 've': 's'}, {'you': 'he', 'youm': 'him', 'your': 'his', 've': 's'}, {'you': 'she', 'youm': 'her', 'your': 'her', 've': 's'}, {'you': 'it', 'youm': 'it', 'your': 'its', 've': 's'} ] CANNIBAL = [ "question your sanity.", "feel guilty.", "wonder how things came to this so quickly.", "think this is really weird.", "question your sanity." ] class Monster(object): seen_owner = True @property def mod_dex(self): return int(self.dex / float(self.stunned + 1)) def add(self, itm): self.inventory.append(itm) itm.here = self def photograph(self, photographer): if photographer.dex < Utl.rn(12): return "a picture of " + Utl.rn_seq([ "a flesh-tone blob", "a blurry finger", "the lens cap"]) if self.name: name = " named " + self.name else: name = '' if photographer == self: return "a self-portrait of the photographer%s as %s at level %s" % (name, self.species.adesc, self.level) if photographer.int < Utl.rn(8): return "a picture of %s accidentally holding the camera backward." % self.species.adesc if self.rabid and Utl.rn(): return "a photo of a %s %s" % ('crazed' if self.species.human else 'frothing', self.species.name) if self.ai == PET and Utl.rn(): return "a photo of your pet %s%s" % (self.species.name, name) if self.ai == SLEEPING and Utl.rn(): return "a photograph of a sleeping " + self.species.name if self.ai == ATTACKING and Utl.rn(): return "a blurry photo of an angry " + self.species.name rn = Utl.rn(4) if rn == 0: return "a photo of %s%s" % (self.species.adesc, name) elif rn == 1: return "a photo of %s%s%s" % (self.species.adesc, name, " wielding a " + self.wielded.kind.name if self.wielded else '') elif rn == 2: return "a photo of %s%s%s" % (self.species.adesc, name, " with a " + Utl.rn_seq(self.inventory).kind.name if self.inventory else '') if self.species.photos: return Utl.rn_seq(self.species.photos) else: return "an unidentifiable blur" def i_like(self, target): if self.ai == PET and target is self.owner: return True if self.xenophobic or target.xenophobic and not self.species & target.species: return False if self.rabid or target.rabid: return False if self.ai == PET and target.ai == PET and self.owner is target.owner: return True if target.target is self: return False if Utl.coaligned(self, target) or self.species.peaceful: return True return False def will_fight(self, target): if self is target: return False if self.ai == PET and target is self.owner: return False if self.ai == PET and target.ai == PET and self.owner is target.owner: return False if self.target_player_first and (target is g.player or (target.ai == PET and target.owner is g.player)): return True if self.rabid: return True if self.species.flees and self.hp >= self.mhp / 2: return False return not self.i_like(target) def damage(self, amt, attacker=None, usearmor=True, msg=None, setamt=False, dodie=True): if self.dead: return if msg is None: if attacker.name: self.last_damage = "the %s called %s" % (attacker.species.name, attacker.name) else: self.last_damage = attacker.species.adesc if attacker.wielded: self.last_damage += " wielding " + attacker.wielded.kind.adesc else: self.last_damage = msg tmp = amt if usearmor and not setamt: tmp -= self.armor if tmp <= 0: Ifc.your("%sarmor totally protected |youm|%s." % (Ifc.color(Ifc.BOLD), Ifc.color()), self) if setamt: self.hp = tmp elif tmp > 0: self.hp -= tmp self.species.damaged(self, attacker, self.here) if self.hp <= 0: if dodie: self.die(attacker) return True if self.ai == SLEEPING: self.ai = WANDERING return False def stun(self, stun=1, stunner=''): self.stunned = max(self.stunned, stun) self.stunner = stunner def die(self, killer=None, docorpse=True): if self.dead: return self.species.die(self, killer, self.here) if self.ai == PET: g.pets_lost += 1 self.species.dead += 1 self.dead = True if killer: killer.vanquished += 1 killer.xp += self.mhp + self.mst + self.min + self.mdx + self.armor if self.wielded: killer.xp += self.wielded.kind.damage if killer.pc and not self.rabid and self.species.peaceful: Ifc.you("%s%s the poor %s!%s" % (Ifc.color(Ifc.BRIGHT_GREEN), self.species.die_verb, self.species.name, Ifc.color()), killer) else: Ifc.you("%s%s|s| %s!%s" % (Ifc.color(Ifc.BRIGHT_GREEN), self.species.die_verb, Ifc.the_mon(self), Ifc.color()), killer) killer.check_xp() else: Ifc.you("|are| %sed!" % self.species.die_verb, self) self.here.mons.remove(self) for itm in self.inventory[:]: itm.wielded = itm.worn = False self.drop(itm) if not self.here is g.player.here: Ifc.you("hear some noises in the distance.", do_pk=False) if docorpse: if self.species.corpse: Ifc.you("fall|s| to the ground, %s." % self.species.corpse.adesc, self) itm = self.species.corpse.make() itm.living_form = self if self.name: itm.name = self.name self.corpse = itm self.here.add(itm) else: Ifc.your('body vanish|es| into thin air!', self) self.species.after_die(self, killer, self.here) def describe(self, article=True): if self.name: ret = '%s%s named %s' % ('the ' if article else '', self.species.name, self.name) else: ret = self.species.adesc if article else self.species.name if self.rabid: ret += ' %s(%s)%s' % (Ifc.color(Ifc.YELLOW), 'insane' if self.species.smart else 'rabid', Ifc.color()) if self.cyborg: ret += ' (borg)' if self.stunned: ret += ' %s(stunned)%s' % (Ifc.color(Ifc.CYAN), Ifc.color()) if self is not g.player: ret += ' %s' % AI_STATUS[self.perceived_ai(g.player)] return ret def check_xp(self): while self.xp > self.level * (100 + (self.level**1.15) * 20): self.level += 1 Ifc.you('%sseem|s| more experienced.%s' % (Ifc.color(Ifc.BRIGHT_WHITE), Ifc.color()), self) if self.species.level: self.species.level.level_up(self) def move(self, direction): if self is not g.player and not (self.ai == PET and self.owner is g.player and g.glide): Ifc.you("travel|s| %s." % th.Map._DIRS[direction], self) next_node = None if direction == 0: if self.here.north: self.here.mons.remove(self) next_node = self.here.north elif direction == 1: if self.here.east: self.here.mons.remove(self) next_node = self.here.east elif direction == 2: if self.here.south: self.here.mons.remove(self) next_node = self.here.south elif direction == 3: if self.here.west: self.here.mons.remove(self) next_node = self.here.west if not next_node: return next_node.add(self) if self is not g.player: text = "arrive|s| from the %s." % th.Map._DIRS[th.Map.rotate(direction, 2)] if self.ai != PET or self.owner is not g.player: Ifc.you(text, self) else: if g.player in next_node.mons: if not self.seen_owner: Ifc.you(text, self, False) self.seen_owner = True else: self.seen_owner = False def node_move(self, n): if self.here.north is n: self.move(0) elif self.here.east is n: self.move(1) elif self.here.south is n: self.move(2) elif self.here.west is n: self.move(3) def perceived_ai(self, viewer): if self.ai == WANDERING or self.ai == ATTACKING: if not self.i_like(viewer) or self.target is viewer: return ATTACKING else: return WANDERING elif self.ai == PET: if self.owner is viewer: return PET elif not self.i_like(viewer) or self.target is viewer: return ATTACKING else: return WANDERING else: return self.ai # AI functions. def update_ai(self): if self.ai == SLEEPING: for m in self.here.mons: if m.ai != SLEEPING: break else: return SLEEPING if self.species.wake_text and self.here is g.player.here: Ifc.msg(Ifc.color(Ifc.MAJOR_WHITE) + self.species.wake_text + Ifc.color()) Ifc.you('wake|s| up.', self) return WANDERING elif self.ai == WANDERING: if self.target: return ATTACKING else: return WANDERING elif self.ai == ATTACKING: if self.hp < self.mhp / 5 and self.species.flees: Ifc.you('turn|s| to flee!', self) return FLEEING elif not self.target: return WANDERING else: return ATTACKING elif self.ai == FLEEING: if self.hp >= self.mhp / 2: return WANDERING else: return FLEEING elif self.ai == PET: if self.owner.dead: self.owner = None return WANDERING else: return PET else: raise ValueError('invalid AI state') def update(self): if not self.here: return if self.hp <= 0: self.die() return if self.stunned > 0: self.stunned -= 1 Ifc.you('|are| helplessly %s.' % self.stunner, self) return self.ai = self.update_ai() if self.ai == SLEEPING: return if (self.species.chatty and Utl.rn(10) == 0) or (self.cyborg and Utl.rn()): self.do_talk(0) if g.turns % self.species.regeneration == 0 and self.hp < self.mhp: self.hp += 1 if self.hp <= self.mhp / 2: if self.do_food(): return if self.species.auto_special and self.species.useSpecial(self, self): self.species.doSpecial(self, self) return if self.ai == WANDERING: if self.do_goodies(): return if self.do_battle(): return if self.species.chase and self.target and self.target.here is not self.here: if self.move_nonrandomly(): return if not self.species.no_wander and Utl.rn(4) == 0 and self.move_randomly(): return elif self.ai == ATTACKING: if self.do_inventory(Item.TYPE_OFFENSE): return if self.do_battle(): return if Utl.rn() and self.hp > self.mhp / 3: if self.species.chase and self.target and self.target.here is not self.here: if self.move_nonrandomly(): return if self.do_goodies(): return if Utl.rn() and self.do_inventory(Item.TYPE_DEFENSE): return elif self.ai == FLEEING: if self.do_inventory(Item.TYPE_ESCAPE): return if Utl.rn(5) != 0 and self.move_randomly(): return if self.do_goodies(): return if self.do_inventory(Item.TYPE_DEFENSE): return elif self.ai == PET: if self.owner.here is not self.here: if g.config['pet_pathfinding'] == 0: self.here.mons.remove(self) self.owner.here.add(self) elif g.config['pet_pathfinding'] == 1: if not self.owner.here.dijkstra: self.owner.here.dijkstra = th.Map.Dijkstra(self.owner.here) d, p = self.owner.here.dijkstra if p.has_key(self.here): n = p[self.here] self.node_move(n) elif g.config['pet_pathfinding'] == 2: n = self.here.p_nodes[self.owner.here] self.node_move(n) return if self.do_inventory(Item.TYPE_OFFENSE): return if self.do_battle(): return if Utl.rn() and self.do_goodies(): return if Utl.rn() and self.do_inventory(Item.TYPE_DEFENSE): return if self.do_equip(): return self.do_inventory(Item.TYPE_MISC) def do_goodies(self): if len(self.inventory) >= self.str and self.str > 0 and Utl.rn(): itm = Utl.rn_seq(self.inventory) if not (itm.wielded or itm.worn or itm.kind.pc_only or itm.kind.use_type == Item.TYPE_OFFENSE or itm.kind.heal > 0): self.drop(itm) if (len(self.inventory) >= self.str and Utl.rn(5) != 0) or not self.here.items: return False for itm, e in zip(Utl.gen_shuffle(self.here.items), xrange(5)): if not self.will_pick_up(itm): continue if self.pick_up(itm): return True return False def will_pick_up(self, itm): if itm.kind.tainted_chance == 100: return False if itm.kind is self.species.corpse and self.species.smart: return False if not self.species.smart and not ( self.species.scavenger and itm.kind in th.data.Items.corpses): return False if not self.species.wields and itm.kind.damage != 0: return False if itm.kind.damage != 0 and ( self.wielded and self.wielded.kind.damage > itm.kind.damage): return False if not self.species.eats and itm.kind.heal != 0: return False if not self.species.wears and itm.kind.armor != 0: return False if itm.kind.armor != 0 and self.armor >= self.dex / 2: return False return True def do_battle(self): if self.str <= 0: return False if self.ai == PET and self.target and self.target.here is not self.here: self.target = None elif self.target and self.target.here is not self.here: cache = self.get_target() if cache and cache is not self: self.target = cache if not self.target or self.target.dead or self.i_like(self.target): if self.ai == PET and Utl.rn(): self.target = self.owner.get_target() else: self.target = self.get_target() if (not self.target or self.target is self) and self.ai != PET and self.species.chase: self.target = self.get_target(src=self.here.gen_closemons(4 if g.config['pet_pathfinding'] != 0 else 1)) if not self.target or self.target is self: self.target = None return False if self.target.here is self.here: if not self.do_attack(self.target): Ifc.your('%sattack missed %s.%s' % (Ifc.color(Ifc.BRIGHT_BLUE), Ifc.the_mon(self.target), Ifc.color()), self) if not self.target.dead and self.species.useSpecial(self, self.target): self.species.doSpecial(self, self.target) return True return False def move_randomly(self): if self.species.teleports and Utl.rn(): dest = Utl.rn_node(False, 0) Ifc.you('disappear|s| in a flash!', self) self.here.mons.remove(self) dest.add(self) Ifc.you('appear|s| in a flash!', self) return True dest = Utl.rn_exit(self.here, False) if dest is None: return False self.move(dest) return True def move_nonrandomly(self): where = None if g.config['pet_pathfinding'] != 0: if g.config['pet_pathfinding'] == 1: if not self.target.here.dijkstra: self.target.here.dijkstra = th.Map.Dijkstra(self.target.here) d, n = self.target.here.dijkstra else: d, n = self.here.p_distance, self.here.p_nodes if self.str >= Utl.rn(int(max((40 - self.str), 0) ** (d[self.target.here] * .3))): where = n[self.here] else: if self.here.north is self.target.here: where = self.here.north elif self.here.east is self.target.here: where = self.here.east elif self.here.south is self.target.here: where = self.here.south elif self.here.west is self.target.here: where = self.here.west if where and self.target.here is where: if Utl.rn(self.dex) < Utl.rn(self.target.mod_dex): Ifc.you('evade|s| the %s chasing |youm|.' % self.species.name, self.target) return True elif not where: where = Utl.rn_exit(self.here) if not where or where.locked: return False self.node_move(where) if self.here is self.target.here: Ifc.you('see|s| %s chase after |youm|!' % Ifc.the_mon(self), self.target) return True def do_talk(self, pc_talking=False): if self is g.player and pc_talking: Ifc.you('have heard that talking to yourself is a sign of instability.') elif self.rabid and not self.species.smart: Ifc.you(Utl.rn_seq(RABID_TALK), self) elif self.cyborg: Ifc.you('say|s| "%s."' % Utl.rn_seq(BORG_TALK), self) elif self.species.talk: if self.species.special_talk: Ifc.you(Utl.rn_seq(self.species.talk), self) else: Ifc.you('say|s| "%s"' % Utl.rn_seq(self.species.talk), self) elif pc_talking: Ifc.you('note that %s %s' % (Ifc.the_mon(self), Ifc.format(Utl.rn_seq(NOT_TALKATIVE), self))) else: Ifc.you('mutter|s| incomprehensibly.', self) def do_attack(self, target): target.species.attacked(target, self, self.here) self.xp += 2 if self is g.player and target.ai != FLEEING: target.ai = ATTACKING hit = 1 hit_modifier = target.mod_dex + (100 - g.config['hit_thresh']) hit_modifier -= self.dex + (self.wielded.kind.to_hit if self.wielded else 0) mod_modifier = (target.species.size - self.species.size) * 3 if mod_modifier < 0: mod_modifier *= .8 hit_modifier += mod_modifier hit_modifier = min(90, max(10, hit_modifier)) if hit_modifier > Utl.rn(100): hit = 0 if self.wielded: self.wielded.kind.used_as_weapon(self.wielded, self, self.here, target, hit) if target.dead or target.here is not self.here: return True if not hit: return False if target.ai == SLEEPING: target.ai = WANDERING self.xp += 8 if self.species.attack_verb and not self.wielded: Ifc.you('%s%s %s!%s' % (Ifc.color(Ifc.BRIGHT_RED), self.species.attack_verb, Ifc.the_mon(target), Ifc.color()), self) else: cache = Ifc.color(Ifc.BRIGHT_RED) + 'hit|s| ' + Ifc.the_mon(target) if self.wielded: cache += ' with |your| %s' % self.wielded.kind.name cache += '!' + Ifc.color() Ifc.you(cache, self) if self is g.player and self.wielded: g.used_weapon += 1 target.damage(Utl.rn(self.str) + (self.wielded.kind.damage if self.wielded else 0), self) return True def get_target(self, src=None): sel_score = selection = None for m in src or self.here.mons: if ((self.ai == PET and self.owner is m) or (m.ai == PET and m.owner is self) or not self.will_fight(m)): continue current_score = m.str / 2 + (m.wielded.kind.damage if m.wielded else 0) current_score += (self.hp - m.hp) + Utl.rn(20) + (-2 if m is g.player else 2) if self.target_player_first: if target is g.player: current_score += 40 elif target.ai == PET and target.owner is g.player: current_score += 30 if sel_score is None or current_score > sel_score: sel_score, selection = current_score, m return selection def get_wand_target(self): sel_score = selection = None for m in self.here.mons: if self.ai == PET and self.owner is m: continue if m.ai == PET and m.owner is self: continue if not self.will_fight(m): continue current_score = m.str / 2 + (m.wielded.kind.damage if m.wielded else 0) current_score += m.hp - self.hp if self.target_player_first: if target is g.player: current_score += 40 elif target.ai == PET and target.owner is g.player: current_score += 30 if sel_score is None or current_score > sel_score: sel_score, selection = current_score, m if selection is None: return my_score = self.str / 2 + (self.wielded.kind.damage if self.wielded else 0) if self.hp < self.mhp / 6: my_score -= 30 elif self.hp < self.mhp / 3: my_score -= 20 elif self.hp < self.mhp / 1.5: my_score -= 10 if my_score > sel_score: return return selection def init_inventory(self, inventory): for itm in inventory: self._set_picked_up(itm) def setup_inventory(self): for itm in self.inventory: if self.species.wields and (not self.wielded or self.wielded.kind.damage < itm.kind.damage) \ and itm.kind.damage > 0: if self.wielded: self._set_unwielded(self.wielded) self._set_wielded(itm) if self.species.wears and not itm.worn and itm.kind.armor > 0: self._set_worn(itm) def do_equip(self): for itm in self.inventory: if self.species.wields and (not self.wielded or self.wielded.kind.damage < itm.kind.damage) \ and itm.kind.damage > 0: if self.wield(itm): return True if self.species.wears and not itm.worn and itm.kind.armor > 0: if self.wear(itm): return True return False def do_inventory(self, type): for itm in self.inventory: if itm.kind.monUse(itm, self, self.here) and Utl.rn() and (not itm.wielded or \ itm.kind.using_does_not_destroy) and self.species.uses and g.phase > 0 \ and self.here and itm.kind.use_type == type: if self.use(itm): return True return False def do_food(self): best_food = None for itm in self.inventory: if itm.tainted and self.species.smart: continue if not best_food and itm.kind.heal > 0: best_food = itm elif itm.kind.heal > 0 and itm.kind.heal > best_food.kind.heal: best_food = itm if best_food: if self.eat(best_food): return True return False def eat(self, food): if not self.species.eats: if self is g.player: Ifc.you("aren't able to eat or drink.") return False l = self.hp if food.worn: result = food.kind.unwear(food, self, self.here) if result == Item.RETURN_TRUE: return True elif result == Item.RETURN_FALSE: return False self.armor -= food.kind.armor food.worn = False food.kind.do_unenhance(food, self, self.here) if food.wielded: self.wielded = None food.wielded = 0 result = food.kind.eat(food, self, self.here) if result == Item.RETURN_TRUE: return True elif result == Item.RETURN_FALSE: return False if food.tainted and result != Item.HANDLED_TAINTED: Ifc.you('%sdiscover|s| that the %s was rotten! Yuck!%s' % (Ifc.color(Ifc.MAGENTA), food.kind.name, Ifc.color()), self) if self.damage(Utl.rn(food.kind.heal), usearmor=0, msg='eating a tainted ' + food.kind.name): pass elif Utl.rn(6) == 0: Ifc.you('feel|s| very sick.', self) self.damage(Utl.rn(2), msg='food poisoning', setamt=1) else: if self is g.player: Ifc.msg(food.kind.tasty) g.food += 1 if food.kind.veg_level < Item.VEGAN: g.vegan += 1 if food.kind.veg_level < Item.VEGETARIAN: g.vegetarian += 1 self.hp = min(self.mhp, self.hp + food.kind.heal) l = ', which made |youm| healthier' if self.hp > l else '' Ifc.you('%sconsumed |your| %s%s.%s' % (Ifc.color(Ifc.GREEN), food.kind.name, l, Ifc.color()), self) if not food.destroyed: food.destroy() return True def use(self, itm): if self is not g.player and ((itm.kind.use == Item.TYPE_ESCAPE and self.hp > self.mhp / 2) or self.species.boss): return False result = itm.kind.use(itm, self, self.here) if result == Item.RETURN_TRUE: return True elif result == Item.RETURN_FALSE: return False Ifc.you('%sused %s.%s' % (Ifc.color(Ifc.CYAN), itm.kind.adesc, Ifc.color()), self) return True def _set_picked_up(self, itm): if itm.here: itm.here.items.remove(itm) self.add(itm) itm.kind.get_update(self, itm, self.here) def _pick_up(self, itm): result = itm.kind.get(itm, self, self.here) if result != Item.HANDLED_NONE: return result self._set_picked_up(itm) return Item.HANDLED_NONE def pick_up(self, itm): if itm.kind.fixed or len(self.inventory) >= self.str: Ifc.you("do|es|n't have the strength to lift anything else.", self) if self is g.player: Ifc.pk() return False if itm.kind.pc_only and not self.pc: Ifc.you('look|s| at the %s.' % itm.kind.name, self) return False result = self._pick_up(itm) if result == Item.RETURN_TRUE: return True elif result == Item.RETURN_FALSE: return False Ifc.you('pick|s| up the %s.' % itm.kind.name, self) itm.kind.get_action(itm, self, self.here) return True def _set_wielded(self, itm): itm.wielded = True self.wielded = itm itm.kind.wield_update(itm, self, self.here) def _wield(self, itm): if self.wielded is not None: result = self._unwield(self.wielded) if result != Item.HANDLED_NONE: return result result = itm.kind.wield(itm, self, self.here) if result != Item.HANDLED_NONE: return result self._set_wielded(itm) return Item.HANDLED_NONE def wield(self, itm): if self.wielded is not None: result = self._unwield(self.wielded) if result == Item.RETURN_TRUE: return True elif result == Item.RETURN_FALSE: return False result = self._wield(itm) if result == Item.RETURN_TRUE: return True elif result == Item.RETURN_FALSE: return False Ifc.you('wield|s| %s!' % itm.kind.adesc, self) itm.kind.wield_action(itm, self, self.here) return True def _set_worn(self, itm): itm.worn = True self.armor += itm.kind.armor itm.kind.wear_update(itm, self, self.here) if itm.kind.armor > 5: self.xap += 1 def _wear(self, itm): result = itm.kind.wear(itm, self, self.here) if result != Item.HANDLED_NONE: return result self._set_worn(itm) return Item.HANDLED_NONE def wear(self, itm): if itm.worn: Ifc.you('|are| already wearing this %s.' % itm.kind.name, self) return False if self.armor >= self.dex / 2: if self is g.player: Ifc.you('are not dexterous enough to wear more armor.') return False result = self._wear(itm) if result == Item.RETURN_TRUE: return True elif result == Item.RETURN_FALSE: return False Ifc.you('%swear|s| %s.%s' % (Ifc.color(Ifc.BLUE), itm.kind.adesc, Ifc.color()), self) itm.kind.wear_action(itm, self, self.here) return True def _set_unwielded(self, itm): itm.wielded = False self.wielded = None itm.kind.unwield_update(itm, self, self.here) def _unwield(self, itm): result = itm.kind.unwield(itm, self, self.here) if result != Item.HANDLED_NONE: return result self._set_unwielded(itm) return Item.HANDLED_NONE def unwield(self, itm): result = self._unwield(itm) if result == Item.RETURN_TRUE: return True elif result == Item.RETURN_FALSE: return False Ifc.you('|are| no longer wielding the %s.' % itm.kind.name, self) itm.kind.unwield_action(itm, self, self.here) return True def _set_unworn(self, itm): self.armor -= itm.kind.armor itm.worn = False itm.kind.unwear_update(itm, self, self.here) def _unwear(self, itm): result = itm.kind.unwear(itm, self, self.here) if result != Item.HANDLED_NONE: return result self._set_unworn(itm) return Item.HANDLED_NONE def unwear(self, itm): result = self._unwear(itm) if result == Item.RETURN_TRUE: return True elif result == Item.RETURN_FALSE: return False Ifc.you('take|s| off the %s.' % itm.kind.name, self) itm.kind.unwear_action(itm, self, self.here) return True def _set_dropped(self, itm): self.inventory.remove(itm) self.here.add(itm) itm.kind.drop_update(itm, self, self.here) def _drop(self, itm): if itm.wielded: result = self._unwield(itm) if result != Item.HANDLED_NONE: return result if itm.worn: result = self._unwear(itm) if result != Item.HANDLED_NONE: return result result = itm.kind.drop(itm, self, self.here) if result != Item.HANDLED_NONE: return result self._set_dropped(itm) return Item.HANDLED_NONE def drop(self, itm): if itm.wielded: result = self._unwield(itm) if result == Item.RETURN_TRUE: return True elif result == Item.RETURN_FALSE: return False Ifc.you('|are| no longer wielding the %s.' % itm.kind.name, self) itm.kind.unwield_action(itm, self, self.here) if itm.worn: result = self._unwear(itm) if result == Item.RETURN_TRUE: return True elif result == Item.RETURN_FALSE: return False itm.kind.unwear_action(itm, self, self.here) result = self._drop(itm) if result == Item.RETURN_TRUE: return True elif result == Item.RETURN_FALSE: return False Ifc.you('%sdrop|s| %s.%s' % (Ifc.color(Ifc.YELLOW), itm.kind.adesc, Ifc.color()), self) itm.kind.drop_action(itm, self, self.here) return True def _try_pick_up(self, itm): if not itm.kind.check_pick_up(itm, self, self.here): return False result = self._pick_up(itm) if result != Item.HANDLED_NONE: raise ValueError('%r returned from %r.get, expected %r' % ( result, itm.kind, Item.HANDLED_NONE)) return True def _try_wield(self, itm): if not itm.kind.check_wield(itm, self, self.here): return False result = self._wield(itm) if result != Item.HANDLED_NONE: raise ValueError('%r returned from %r.wield, expected %r' % ( result, itm.kind, Item.HANDLED_NONE)) return True def _try_wear(self, itm): if not itm.kind.check_wear(itm, self, self.here): return False result = self._wear(itm) if result != Item.HANDLED_NONE: raise ValueError('%r returned from %r.wear, expected %r' % ( result, itm.kind, Item.HANDLED_NONE)) return True def _try_unwield(self, itm): if not itm.kind.check_unwield(itm, self, self.here): return False result = self._unwield(itm) if result != Item.HANDLED_NONE: raise ValueError('%r returned from %r.unwield, expected %r' % ( result, itm.kind, Item.HANDLED_NONE)) return True def _try_unwear(self, itm): if not itm.kind.check_unwear(itm, self, self.here): return False result = self._unwear(itm) if result != Item.HANDLED_NONE: raise ValueError('%r returned from %r.unwear, expected %r' % ( result, itm.kind, Item.HANDLED_NONE)) return True def _try_drop(self, itm): if itm.wielded and not self._try_unwield(itm): return False if itm.worn and not self._try_unwear(itm): return False if not itm.kind.check_drop(itm, self, self.here): return False result = self._drop(itm) if result != Item.HANDLED_NONE: raise ValueError('%r returned from %r.drop, expected %r' % ( result, itm.kind, Item.HANDLED_NONE)) return True def reroll_stats(self): self.int = self.min = self.species.int + Utl.rn(-self.species.vin) self.str = self.mst = self.species.str + Utl.rn(-self.species.vst) self.dex = self.mdx = self.species.dex + Utl.rn(-self.species.vdx) self.hp = self.mhp = self.species.hp + Utl.rn(-self.species.vhp) inv = self.inventory[:] g.rng.shuffle(inv) while inv and len(inventory) > self.str: itm = inv.pop() if itm.worn: if not self._try_unwear(itm): continue itm.kind.unwear_action(itm, self, self.here) Ifc.your('%s falls off.' % itm.kind.name, self) if itm.wielded: if not self._try_unwield(itm): continue itm.kind.unwield_action(itm, self, self.here) Ifc.you('find|s| the %s too heavy to wield.' % itm.kind.name, self) itm.kind.drop_action(itm, self, self.here) Ifc.you('|are| overloaded by the %s and drop|s| it.' % itm.kind.name, self) self._drop(itm) while inv and self.armor > self.dex / 2: itm = inv.pop() if not itm.worn: continue if not self._try_unwear(itm): continue itm.kind.unwear_action(itm, self, self.here) Ifc.your('%s falls off.' % itm.kind.name, self) self.resist_gas = self.resist_gas or self.species.resist_gas self.resist_bullets = self.resist_bullets or self.species.resist_bullets self.resist_chemical = self.resist_chemical or self.species.resist_chemical self.resist_polymorph = self.resist_polymorph or self.species.resist_polymorph self.ap = self.species.ap self.alignment = self.species.alignment self.species.xmake(self) def __init__(self): self.name = '' self.species = None self.gender = 0 self.int = self.str = self.dex = self.hp = 1 self.min = self.mst = self.mdx = self.mhp = 1 self.armor = 0 self.ap = 2 self.xap = 0 self.pet_attacked = False self.stunned = 0 self.ai = 0 self.alignment = 0 self.last_damage = "rolling really badly" self.ai_timer = 0 self.inventory = [] self.here = None self.wielded = None self.rabid = False self.cyborg = False self.dead = False self.resist_chemical = False self.resist_bullets = False self.resist_polymorph = False self.resist_gas = False self.stunner = None self.murders = 0 self.peacefuls = 0 self.cannibal = 0 self.vanquished = 0 self.xp = 0 self.level = 0 self._target = None self._corpse = None self._owner = None target = Utl.WeakrefProperty('_target') corpse = Utl.WeakrefProperty('_corpse') owner = Utl.WeakrefProperty('_owner') def __getstate__(self): return self.species.mon_getstate(self) def __setstate__(self, d): self.species = d['species'] self.species.mon_setstate(self, d) def good_mon(level=None): if level is None: level = g.player.level if level < g.config['easy_mon_max']: return Utl.rn_seq(th.data.Species.easy_creatures) for mon in Utl.gen_shuffle(th.data.Species.all_creatures): if mon.number == 1: continue if mon.difficulty <= level * g.config['difficulty']: return mon return Utl.rn_seq(th.data.Species.all_creatures)