Пример #1
0
    def func(self):
        """Run the @check command"""
        caller = self.caller
        retainer = None
        is_retainer = "retainer" in self.switches
        flub = "flub" in self.switches

        if not self.args:
            if is_retainer:
                caller.msg(
                    "Usage: @check/retainer <id>|<stat>[+<skill>][ at <difficulty number>][=receiver1,receiver2,etc]"
                )
                return
            else:
                caller.msg(
                    "Usage: @check <stat>[+<skill>][ at <difficulty number>][=receiver1,receiver2,etc]"
                )
                return

        args = self.lhs if self.rhs else self.args
        args = args.lower()
        quiet = bool(self.rhs)

        # NOTE: The order of calls here matters, due to str.split() usage.
        # Retainer ID -> Difficulty -> Stat/Skill.
        try:
            if is_retainer:
                args, retainer_id = self._extract_retainer_id(args)
                retainer = caller.player_ob.retainers.get(id=retainer_id)

            args, difficulty = self._extract_difficulty(args)
            stat, skill = self._extract_stat_skill(args)
        except ValueError as err:
            caller.msg(str(err))
            return
        except Agent.DoesNotExist:
            caller.msg("No retainer found with ID %s." % retainer_id)
            return

        stats_and_skills.do_dice_check(
            caller=caller,
            retainer=retainer,
            stat=stat,
            skill=skill,
            difficulty=difficulty,
            quiet=quiet,
            flub=flub,
        )

        if quiet:
            self._send_quiet_roll_msg()
Пример #2
0
 def roll_flee_success(self):
     """
     Determines if we can flee. Called during initiative. If successful,
     we're added to the list of people who can now gtfo. If someone is
     covering our retreat, we succeed automatically. We must outroll every
     player attempting to block us to flee otherwise.
     """
     if self.covered_by:
         return True
     myroll = do_dice_check(self.character, stat="dexterity", skill="dodge", difficulty=0)
     for guy in self.blocker_list:
         if myroll < do_dice_check(guy, stat="dexterity", skill="brawl", difficulty=0):
             return False
     return True
Пример #3
0
 def roll_attack(self, target, penalty=0):
     """
     Returns our roll to hit with an attack. Half of our roll is randomized.
     """
     autohit = self.damage is not None
     diff = 2  # base difficulty before mods
     penalty -= self.atk_modifiers
     diff += penalty
     diff += self.difficulty_mod
     if not autohit:
         roll = do_dice_check(self.attacker, stat=self.attack_stat, skill=self.attack_skill,
                              difficulty=diff)
     else:
         roll_object = Roll()
         roll_object.character_name = self.attacker_name
         if self.attack_skill:
             roll_object.skills = {self.attack_skill: self.attack_skill_value}
         else:
             roll_object.stat_keep = True
             roll_object.skill_keep = False
         roll_object.stats = {self.attack_stat: self.attack_stat_value}
         roll = roll_object.roll()
     if self.attacker_is_npc:
         roll = self.modify_difficulty_by_risk(roll)
     if roll > 2:
         roll = (roll//2) + randint(0, (roll//2))
     if not autohit:
         roll += self.get_modifier(target, RollModifier.ATTACK)
     return roll
Пример #4
0
 def roll_damage(self, target, penalty=0, dmgmult=1.0):
     """
     Returns our roll for damage against target. If damage is to be
     enhanced, (dmgmult > 1.0) it is done pre-mitigation, here.
     """
     keep_dice = self.handler.weapon_damage + 1
     try:
         keep_dice += self.attacker.attributes.get(self.damage_stat)//2
     except (TypeError, AttributeError, ValueError):
         pass
     if keep_dice < 3:
         keep_dice = 3
     diff = 0  # base difficulty before mods
     diff += penalty
     damage = do_dice_check(self.attacker, stat=self.handler.damage_stat, stat_keep=True, difficulty=diff,
                            bonus_dice=self.handler.weapon_damage, keep_override=keep_dice)
     damage += self.handler.flat_damage_bonus
     if dmgmult > 1.0:  # if dmg is enhanced, it is done pre-mitigation
         damage = int(damage * dmgmult)
     if self.attacker_is_npc:
         damage = self.modify_difficulty_by_risk(damage)
     if damage <= 0:
         damage = 1
     # 3/4ths of our damage is purely random
     damage = damage//4 + randint(0, ((damage * 3)//4)+1)
     damage += self.get_modifier(target, RollModifier.DAMAGE)
     return damage
Пример #5
0
 def roll_initiative(self):
     """Rolls and stores initiative for the character."""
     self.initiative = do_dice_check(self.character,
                                     stat_list=["dexterity", "composure"],
                                     stat_keep=True,
                                     difficulty=0)
     self.tiebreaker = randint(1, 1000000000)
Пример #6
0
 def roll_fatigue(self):
     """
     Chance of incrementing our fatigue penalty. The difficulty is the
     number of combat actions we've taken plus our armor penalty.
     """
     if self.combat_handler.multiple:
         # figure out way later to track fatigue for units
         return
     if self.character.db.never_tire:
         return
     armor_penalty = 0
     if hasattr(self.character, 'armor_penalties'):
         armor_penalty = self.character.armor_penalties
     penalty = armor_penalty
     self.num_actions += 1 + (0.12 * armor_penalty)
     penalty += self.num_actions + 25
     keep = self.fatigue_soak
     penalty = int(penalty)
     penalty = penalty/2 + randint(0, penalty/2)
     myroll = do_dice_check(self.character, stat_list=["strength", "stamina", "dexterity", "willpower"],
                            skill="athletics", keep_override=keep, difficulty=int(penalty), divisor=2)
     myroll += randint(0, 25)
     if myroll < 0 and self.fatigue_gained_this_turn < 1:
         self._fatigue_penalty += 0.5
         self.fatigue_gained_this_turn += 0.5
Пример #7
0
    def roll_for_fame(self):
        """
        Rolls for amount of fame the item generates, minimum 2 fame. The fashion model's social clout and
        skill check of composure + performance is made exponential to be an enormous swing in the efficacy
        of fame generated: Someone whose roll+social_clout is 50 will be hundreds of times as effective
        as someone who flubs the roll.
        """
        from world.stats_and_skills import do_dice_check

        char = self.fashion_model.player.char_ob
        roll = do_dice_check(caller=char,
                             stat="composure",
                             skill="performance",
                             difficulty=30)
        roll = pow(max((roll + char.social_clout * 5), 1), 1.5)
        percentage = max(roll / 100.0, 0.01)
        level_mod = self.fashion_item.item_data.recipe.level / 6.0
        percentage *= max(level_mod, 0.01)
        percentage *= max((self.fashion_item.item_data.quality_level / 40.0),
                          0.01)
        percentage = max(percentage, 0.2)
        # they get either their percentage of the item's worth, their modified roll, or 4, whichever is highest
        self.fame = min(
            max(int(self.fashion_item.item_worth * percentage),
                max(int(roll), 4)),
            self.FAME_CAP,
        )
        self.save()
Пример #8
0
    def func(self):
        if not self.args:
            self.msg("You must provide a direction to assist the party with!")
            return

        last_assist = self.caller.db.shardhaven_last_assist
        if last_assist and time.time() - last_assist < 1800:
            self.msg("You cannot assist through a direction again yet.")
            return

        exit_objs = self.caller.search(self.args, quiet=True, global_search=False,
                                       typeclass='typeclasses.exits.ShardhavenInstanceExit')
        if not exit_objs or len(exit_objs) == 0:
            self.msg("There doesn't appear to be a shardhaven exit by that name!")
            return

        if len(exit_objs) > 1:
            self.msg("That matches too many exits!")
            return

        exit_obj = exit_objs[0]
        haven_exit = exit_obj.haven_exit
        if not haven_exit:
            self.msg("Something is horribly wrong with that exit; it's not set up as a Shardhaven exit.")
            return

        if not haven_exit.obstacle:
            self.msg("There's no obstacle in that direction to assist with!")
            return

        self.caller.db.shardhaven_last_assist = time.time()
        roll = do_dice_check(self.caller, "wits", "leadership", 30, quiet=False)
        haven_exit.modify_diff(amount=roll / 2, reason="%s assisted with a leadership roll" % self.caller.name)
        self.caller.location.msg_contents("%s attempts to assist the party with the obstacle to the %s, "
                                          "adjusting the difficulty." % (self.caller.name, exit_obj.direction_name))
Пример #9
0
    def func(self):
        if not self.args:
            self.msg("You must provide a direction to sneak!")
            return

        exit_objs = self.caller.search(self.args, quiet=True, global_search=False,
                                       typeclass='typeclasses.exits.ShardhavenInstanceExit')
        if not exit_objs or len(exit_objs) == 0:
            self.msg("There doesn't appear to be a shardhaven exit by that name!")
            return

        if len(exit_objs) > 1:
            self.msg("That matches too many exits!")
            return

        exit_obj = exit_objs[0]

        if not exit_obj.passable(self.caller):
            self.msg("You cannot sneak that way; there's still an obstacle there you have to pass!")
            return

        roll = do_dice_check(self.caller, "dexterity", "stealth", 25, quiet=False)
        if roll < 0:
            self.caller.location.msg_contents("%s attempts to sneak %s, but makes noise as they do so!"
                                              % (self.caller.name, exit_obj.direction_name))
        elif roll > 1:
            self.caller.location.msg_contents("%s moves stealthily through %s."
                                              % (self.caller.name, exit_obj.direction_name))

        self.caller.ndb.shardhaven_sneak_value = roll
        self.caller.execute_cmd(exit_obj.direction_name)
Пример #10
0
def do_crafting_roll(char, recipe, diffmod=0, diffmult=1.0, room=None):
    diff = int(recipe.difficulty * diffmult) - diffmod
    ability = get_ability_val(char, recipe)
    skill = recipe.skill
    if skill in ("all", "any"):
        skill = get_highest_crafting_skill(char)
    stat = "luck" if char.traits.luck > char.traits.dexterity else "dexterity"
    can_crit = False
    try:
        if char.roster.roster.name == "Active":
            can_crit = True
    except AttributeError:
        pass
    # use real name if we're not present (someone using our shop, for example). If we're here, use masked name
    real_name = char.location != room
    return do_dice_check(
        char,
        stat=stat,
        difficulty=diff,
        skill=skill,
        bonus_dice=ability,
        quiet=False,
        announce_room=room,
        can_crit=can_crit,
        use_real_name=real_name,
    )
Пример #11
0
    def roll_for_fame(self):
        """
        Rolls for amount of fame the item generates, minimum 2 fame. The fashion model's social clout and
        skill check of composure + performance is made exponential to be an enormous swing in the efficacy
        of fame generated: Someone whose roll+social_clout is 50 will be hundreds of times as effective
        as someone who flubs the roll.
        """
        from world.stats_and_skills import do_dice_check
        char = self.fashion_model.player.char_ob
        total_weight = 0
        for obj in char.location.contents:
            if obj.is_typeclass("typeclasses.characters.Character") and obj != char:
                self.characters.add(obj)
                total_weight += 11 - (obj.db.social_rank or 10)

        self.multiplier = min(total_weight / 25.0, 7.)
        roll = do_dice_check(caller=char, stat="composure", skill="performance", difficulty=30)
        roll = pow(max((roll + char.social_clout * 3), 1), 1.5)
        percentage = max(roll/100.0, 0.01)
        level_mod = self.fashion_item.recipe.level/6.0
        percentage *= max(level_mod, 0.01)
        percentage *= max((self.fashion_item.quality_level/40.0), 0.01)
        percentage *= self.multiplier
        # they get either their percentage of the item's worth, their modified roll, or 4, whichever is highest
        self.fame = min(max(int(self.fashion_item.item_worth * percentage), max(int(roll), 4)), self.FAME_CAP)
        self.save()
Пример #12
0
 def intimidate(caller, diff):
     result = do_dice_check(
         caller, stat="command", skill="intimidation", difficulty=diff
     )
     if result > 0:
         return True
     return False
Пример #13
0
 def investigate(rumor, caller, diff):
     result = do_dice_check(
         caller, stat="perception", skill="investigation", difficulty=diff
     )
     if result > 0:
         senders = rumor.db_sender_objects.all()
         return senders
Пример #14
0
 def recovery_test(self, diff_mod=0, free=False):
     """
     A mechanism for healing characters. Whenever they get a recovery
     test, they heal the result of a willpower+stamina roll, against
     a base difficulty of 0. diff_mod can change that difficulty value,
     and with a higher difficulty can mean it can heal a negative value,
     resulting in the character getting worse off. We go ahead and change
     the player's health now, but leave the result of the roll in the
     caller's hands to trigger other checks - death checks if we got
     worse, unconsciousness checks, whatever.
     """
     diff = 0 + diff_mod
     roll = do_dice_check(self,
                          stat_list=["willpower", "stamina"],
                          difficulty=diff)
     if roll > 0:
         self.msg("You feel better.")
     else:
         self.msg("You feel worse.")
     applied_damage = self.dmg - roll  # how much dmg character has after the roll
     if applied_damage < 0:
         applied_damage = 0  # no remaining damage
     self.db.damage = applied_damage
     if not free:
         self.db.last_recovery_test = time.time()
     return roll
Пример #15
0
 def get_refund_chance(self):
     """Gets our chance of material refund based on a skill check"""
     roll = do_dice_check(self.caller,
                          stat="dexterity",
                          skill="legerdemain",
                          quiet=False)
     return max(roll, 1)
Пример #16
0
 def train_agent(self, trainer, conditioning):
     """
     Gives xp to this agent if they haven't been trained yet this week.
     The skill used to train them is based on our type - animal ken for
     animals, teaching for non-animals.
     """
     # use real name if we're not present. If we're here, use masked name
     use_real_name = self.location != trainer.location
     name = trainer.key if use_real_name else str(trainer)
     self.conditioning += conditioning
     roll = do_dice_check(trainer,
                          stat="command",
                          skill=self.training_skill,
                          difficulty=self.training_difficulty,
                          quiet=False,
                          use_real_name=use_real_name)
     if roll < 0:
         trainer.msg("You have failed to teach them anything.")
         msg = "%s has attempted to train %s, but utterly failed to teach them anything." % (
             name, self)
     else:
         self.agent.xp += roll
         self.agent.save()
         trainer.msg("You have trained %s, giving them %s xp." %
                     (self, roll))
         msg = "%s has trained %s, giving them %s xp." % (name, self, roll)
         self.conditioning = 0
     self.inform_owner(msg)
     print "Training log: %s" % msg
Пример #17
0
 def get_refund_chance():
     """Gets our chance of material refund based on a skill check"""
     from world.stats_and_skills import do_dice_check
     roll = do_dice_check(caller,
                          stat="dexterity",
                          skill="legerdemain",
                          quiet=False)
     return max(roll, 1)
Пример #18
0
 def sensing_check(self, difficulty=15, invis=False, allow_wake=False):
     """
     See if the character detects something that is hiding or invisible.
     The difficulty is supplied by the calling function.
     Target can be included for additional situational
     """
     if not self.conscious and not allow_wake:
         return -100
     roll = do_dice_check(self, stat="perception", stat_keep=True, difficulty=difficulty)
     return roll
Пример #19
0
 def sense_ambush(self, attacker, sneaking=False, invis=False):
     """
     Returns the dice roll of our attempt to detect an ambusher.
     """
     diff = 0  # base difficulty
     if sneaking:
         diff += 15
     sense = self.char.sensing_check(difficulty=0, invis=invis)
     stealth = do_dice_check(attacker, stat="dexterity", skill="stealth")
     return sense - stealth
Пример #20
0
    def search_for_deal_roll(self, material, amount):
        """Does the roll to search for a deal. Positive roll * 5000 is how
        much of the value of the material they're able to buy/sell.
            Args:
                material: The type of material we're looking for
                amount: Max amount much we're looking to buy/sell
            Returns:
                The amount we're able to buy/sell and a modifier to haggling rolls
            Raises:
                HaggleError if they fail to find a deal.
        """
        from math import ceil

        skill = self.caller.traits.get_highest_skill(
            ("economics", "streetwise")).name
        difficulty = 20
        bonus = 0
        roll = do_dice_check(
            self.caller,
            skill=skill,
            stat="perception",
            difficulty=difficulty,
            quiet=False,
        )
        if roll < 0:
            raise HaggleError(
                "You failed to find anyone willing to deal with you at all.")
        if material in HaggledDeal.VALID_RESOURCES:
            # resources are worth 500 each
            value_per_object = 500
        else:
            value_per_object = round(pow(material.value, 1.05))
        value_we_found = roll * 5000.0
        value_for_amount = value_we_found / value_per_object
        if value_for_amount < 1.0:
            penalty = int((1.0 - value_for_amount) * -100)
            amount_found = 1
            self.msg(
                "You had trouble finding a deal for such a valuable item. "
                "Haggling rolls will have a penalty of %s." % penalty)
            return amount_found, penalty
        # minimum of 1
        amount_found = max(int(ceil(value_we_found / value_per_object)), 1)
        if amount_found > amount:
            bonus = min(amount_found - amount, 25)
            self.msg(
                "Due to your success in searching for a deal, haggling rolls will have a bonus of %s."
                % bonus)
        return min(amount, amount_found), bonus
Пример #21
0
 def noble_discovery_check(self):
     """Checks if a noble loses fame for haggling"""
     rank = self.caller.db.social_rank or 10
     if rank > 6:
         return
     msg = "Engaging in crass mercantile haggling is considered beneath those of high social rank."
     if do_dice_check(stat="wits", skill="stealth", difficulty=30) < 1:
         fame_loss = self.caller.player_ob.Dominion.assets.fame // 100
         if not fame_loss:
             msg += " You were noticed, but fortunately, so few people know of you that it hardly matters."
         else:
             msg += " Unfortunately, you were noticed and lose %d fame." % fame_loss
             self.caller.player_ob.Dominion.assets.fame -= fame_loss
             self.caller.player_ob.Dominion.assets.save()
     else:
         msg += " Fortunately, no one noticed this time."
     self.caller.msg(msg)
Пример #22
0
 def recovery_test(self, diff_mod=0, free=False):
     """
     A mechanism for healing characters. Whenever they get a recovery
     test, they heal the result of a willpower+stamina roll, against
     a base difficulty of 0. diff_mod can change that difficulty value,
     and with a higher difficulty can mean it can heal a negative value,
     resulting in the character getting worse off. We go ahead and change
     the player's health now, but leave the result of the roll in the
     caller's hands to trigger other checks - death checks if we got
     worse, unconsciousness checks, whatever.
     """
     # no helping us if we're dead
     if self.db.health_status == "dead":
         return
     diff = 0 + diff_mod
     roll = do_dice_check(self, stat_list=["willpower", "stamina"], difficulty=diff)
     self.change_health(roll)
     if not free:
         self.db.last_recovery_test = time.time()
     return roll
Пример #23
0
 def haggle(self):
     """Alters the terms of our deal. Pray they do not alter it further."""
     if not self.caller.player_ob.pay_action_points(5):
         return
     self.noble_discovery_check()
     difficulty = randint(-15, 65) - self.roll_bonus
     clout = self.caller.social_clout
     if clout > 0:
         difficulty -= randint(0, clout)
     roll = do_dice_check(
         self.caller,
         stat="charm",
         skill_list=["haggling", "haggling", "haggling", "streetwise"],
         difficulty=difficulty)
     if roll <= self.discount_roll:
         self.caller.msg("You failed to find a better deal.\n%s" %
                         self.display())
     else:
         self.discount_roll = roll
         self.save()
         self.caller.msg("You have found a better deal:\n%s" %
                         self.display())
Пример #24
0
 def haggle(self):
     """Alters the terms of our deal. Pray they do not alter it further."""
     if not self.caller.player_ob.pay_action_points(5):
         return
     self.noble_discovery_check()
     difficulty = randint(1, 50) - self.roll_bonus
     clout = self.caller.social_clout
     if clout > 0:
         difficulty -= randint(0, clout)
     try:
         prest_factor = int(self.caller.player_ob.Dominion.assets.prestige_mod)
         if prest_factor > 0:
             difficulty -= randint(0, prest_factor)
     except (AttributeError, ValueError, TypeError):
         pass
     roll = do_dice_check(self.caller, stat="charm", skill="haggling", difficulty=difficulty)
     if roll <= self.discount_roll:
         self.caller.msg("You failed to find a better deal.\n%s" % self.display())
     else:
         self.discount_roll = roll
         self.save()
         self.caller.msg("You have found a better deal:\n%s" % self.display())
Пример #25
0
    def func(self):
        """Run the @check command"""

        caller = self.caller
        skill = None
        maximum_difference = 100
        flub = "flub" in self.switches
        
        if not self.args:
            caller.msg("Usage: @check <stat>[+<skill>][ at <difficulty number>][=receiver1,receiver2,etc]")
            return
        args = self.lhs if self.rhs else self.args
        args = args.lower()
        # if args contains ' at ', then we split into halves. otherwise, it's default of 6
        diff_list = args.split(' at ')
        difficulty = stats_and_skills.DIFF_DEFAULT
        if len(diff_list) > 1:
            if not diff_list[1].isdigit() or not 0 < int(diff_list[1]) < maximum_difference:
                caller.msg("Difficulty must be a number between 1 and %s." % maximum_difference)
                return
            difficulty = int(diff_list[1])
        args = diff_list[0]
        arg_list = args.split("+")
        if len(arg_list) > 1:
            skill = arg_list[1].strip()
        stat = arg_list[0].strip()
        matches = stats_and_skills.get_partial_match(stat, "stat")
        if not matches or len(matches) > 1:
            caller.msg("There must be one unique match for a character stat. Please check spelling and try again.")
            return
        # get unique string that matches stat
        stat = matches[0]
        
        if skill:
            matches = stats_and_skills.get_partial_match(skill, "skill")
            if not matches:
                # check for a skill not in the normal valid list
                if skill in caller.db.skills:
                    matches = [skill]
                else:
                    caller.msg("No matches for a skill by that name. Check spelling and try again.")
                    return
            if len(matches) > 1:
                caller.msg("There must be one unique match for a character skill. Please check spelling and try again.")
                return
            skill = matches[0]
        quiet = bool(self.rhs)
        stats_and_skills.do_dice_check(caller, stat, skill, difficulty, quiet=quiet, flub=flub)
        if quiet:
            namelist = [name.strip() for name in self.rhs.split(",") if caller.search(name.strip(), use_nicks=True)]
            roll_msg = Roll.build_msg(caller.ndb.last_roll) + " " + "(Private roll sent to: %s)" % ", ".join(namelist)
            caller.msg(roll_msg)
            # they have a recipient list; only tell those people (and GMs)
            for name in namelist:
                recipient = caller.search(name, use_nicks=True)
                recipient.msg(roll_msg, options={'roll':True})
            # GMs always get to see rolls.
            staff_list = [x for x in caller.location.contents if x.check_permstring("Builders")]
            for GM in staff_list:
                GM.msg("{w(Private roll) {n" + roll_msg)
            return
Пример #26
0
    def take_damage(self, victim, dmg):
        """
        This is where the consequences of final damage are applied to a victim. They can
        be knocked unconscious or killed, and any combat they're in is informed.
        Characters who are incapacitated are moved to the appropriate dictionary.
        Health rating is 10xsta + 10.
        Unconsciousness checks are after health rating is exceeded. When
        damage is double health rating, death checks begin. Player characters
        will always fall unconscious first, then be required to make death
        checks after further damage, with the exception of extraordinary
        situations. NPCs, on the other hand, can be killed outright.

            Args:
                victim: Our target
                dmg: The amount of damage after all mitgation/reductions
        """
        allow_one_shot = True
        affect_real_dmg = self.affect_real_dmg
        can_kill = self.can_kill
        if self.combat:
            allow_one_shot = self.combat.ndb.random_deaths
        loc = victim.location
        # some flags so messaging is in proper order
        knock_uncon = False
        kill = False
        remove = False
        glass_jaw = victim.glass_jaw
        is_npc = victim.is_npc
        message = ""
        # max hp is (stamina * 10) + 10
        max_hp = victim.max_hp
        # apply AE damage to multinpcs if we're cleaving
        if self.cleaving and hasattr(victim, 'ae_dmg'):
            victim.ae_dmg += dmg
        victim.change_health(-dmg, quiet=True, affect_real_dmg=affect_real_dmg, wake=False)
        grace_period = False  # one round delay between incapacitation and death for PCs if allowed
        if victim.dmg > max_hp:
            # if we're not incapacitated, we start making checks for it
            if victim.conscious and not victim.sleepless:
                # check is sta + willpower against % dmg past uncon to stay conscious
                if not glass_jaw:
                    diff = int((float(victim.dmg - max_hp)/max_hp) * 100)
                    consc_check = do_dice_check(victim, stat_list=["stamina", "willpower"], skill="survival",
                                                stat_keep=True, difficulty=diff, quiet=False)
                else:
                    consc_check = -1
                if consc_check >= 0:
                    if not self.private:
                        message = "%s remains capable of fighting." % victim
                    grace_period = True  # we can't be killed if we succeeded this check to remain standing
                    # we're done, so send the message for the attack
                else:
                    knock_uncon = True
                # for PCs who were knocked unconscious this round
                if not is_npc and not grace_period and not allow_one_shot:
                    grace_period = True  # if allow_one_shot is off, we can't be killed yet
            # PC/NPC who was already unconscious before attack, or an NPC who was knocked unconscious by our attack
            if not grace_period:  # we are allowed to kill the character
                dt = victim.death_threshold
                diff = int((float(victim.dmg - int(dt * max_hp))/int(dt * max_hp)) * 100)
                if affect_real_dmg and not is_npc and not glass_jaw:
                    diff = self.modify_difficulty_by_risk(diff)
                if diff < 0:
                    diff = 0
                # npcs always die. Sucks for them.
                if not glass_jaw and do_dice_check(victim, stat_list=["stamina", "willpower"], skill="survival",
                                                   stat_keep=True, difficulty=diff, quiet=False) >= 0:
                    message = "%s remains alive, but close to death." % victim
                    if victim.combat.multiple:
                        # was incapacitated but not killed, but out of fight and now we're on another targ
                        if affect_real_dmg:
                            victim.real_dmg = victim.ae_dmg
                        else:
                            victim.temp_dmg = victim.ae_dmg
                elif not victim.combat.multiple:
                    if affect_real_dmg:
                        kill = can_kill
                    # remove a 'killed' character from combat whether it was a real death or fake
                    remove = True
                else:
                    if affect_real_dmg:
                        kill = can_kill
                    else:
                        knock_uncon = True
        if loc and message:
            loc.msg_contents(message, options={'roll': True})
        if knock_uncon:
            victim.fall_asleep(uncon=True, verb="incapacitated", affect_real_dmg=affect_real_dmg)
        if kill:
            victim.death_process(affect_real_dmg=affect_real_dmg)
        if victim.combat.multiple:
            try:
                if victim.quantity <= 0:
                    remove = True
            except AttributeError:
                pass
        if self.combat and remove:
            self.combat.remove_combatant(victim)
Пример #27
0
    def roll_defense(self, target, penalty=0):
        """
        Returns target's roll to avoid being hit. We use the highest roll out of
        parry, block, and dodge. Half of our roll is then randomized.
        """
        if not target.conscious:
            return -self.AUTO_HIT
        defense = target.combat
        # making defense easier than attack to slightly lower combat lethality
        diff = -2  # base difficulty before mods
        penalty -= defense.defense_modifier
        diff += penalty
        if defense.state:
            defense.state.times_attacked += 1
        total = None

        def change_total(current_total, new_roll):
            """Helper function to change total of defense rolls"""
            if new_roll >= 2:
                new_roll = (new_roll//2) + randint(0, (new_roll//2))
            if not current_total:
                current_total = new_roll
            elif new_roll > 0:
                if current_total > new_roll:
                    current_total += new_roll//2
                else:
                    current_total = (current_total//2) + new_roll
            elif new_roll > current_total:
                current_total = (current_total + new_roll)//2
            return current_total, new_roll

        if self.can_be_parried and defense.can_parry:
            parry_diff = diff + 10
            parry_roll = int(do_dice_check(target, stat=defense.attack_stat, skill=self.attack_skill,
                                           difficulty=parry_diff))
            if parry_roll > 1:
                parry_roll = (parry_roll//2) + randint(0, (parry_roll//2))
            total = parry_roll
        else:
            parry_roll = -1000
        if self.can_be_blocked and defense.can_block:
            try:
                block_diff = diff + defense.dodge_penalty
            except (AttributeError, TypeError, ValueError):
                block_diff = diff
            block_roll = int(do_dice_check(target, stat="dexterity", skill="dodge", difficulty=block_diff))
            total, block_roll = change_total(total, block_roll)
        else:
            block_roll = -1000
        if self.can_be_dodged and defense.can_dodge:
            # dodging is easier than parrying
            dodge_diff = diff - 10
            try:
                dodge_diff += defense.dodge_penalty
            except (AttributeError, TypeError, ValueError):
                pass
            dodge_roll = int(do_dice_check(target, stat="dexterity", skill="dodge", difficulty=dodge_diff))
            total, dodge_roll = change_total(total, dodge_roll)
        else:
            dodge_roll = -1000
        if total is None:
            total = -1000
        # return our highest defense roll
        if parry_roll > block_roll and parry_roll > dodge_roll:
            defense.last_defense_method = "parry"
        elif block_roll > parry_roll and block_roll > dodge_roll:
            defense.last_defense_method = "block"
        else:
            defense.last_defense_method = "dodge"
        return total