def get_check_values_from_args(self, args, syntax): try: stats_string, rating_string = args.split(" at ") except (TypeError, ValueError): raise self.error_class(syntax) stat, skill = self.get_stat_and_skill_from_args(stats_string) rating_string = rating_string.strip() rating = DifficultyRating.get_instance_by_name(rating_string) if not rating: raise self.error_class( f"'{rating_string}' is not a valid difficulty rating.") return stat, skill, rating
def _extract_difficulty(self, args: str, syntax: str) -> (str, DifficultyRating): try: lhs, rhs, *remainder = args.split(" at ") except ValueError: raise self.error_class(syntax) else: if remainder: raise self.error_class(syntax) rhs = rhs.strip().lower() difficulty = DifficultyRating.get_instance_by_name(rhs) if not difficulty: raise self.error_class(f"{rhs} is not a valid difficulty rating.") return lhs, difficulty
def get_help(self, caller, cmdset): msg = """ Usage: @check stat + skill at <difficulty rating>[=<player1>,<player2>,etc.] @check/contest name1,name2,name3,etc=stat (+ skill) at <rating> @check/contest/here stat (+ skill) at <difficulty rating> @check/vs stat (+ skill) vs stat(+skill)=<target name> @check/retainer <id/name>/<stat> [+ <skill>] at <difficulty rating> [=<player1>,<player2>,etc.] Normal check is at a difficulty rating. Rating must be one of {difficulty_ratings}. check/contest allows a GM to have everyone selected to make a check, listing the results in order of results. check/contest/here is shorthand to check everyone in a room aside from the GM. """ ratings = ", ".join(str(ob) for ob in DifficultyRating.get_all_instances()) return msg.format(difficulty_ratings=ratings)
def do_opposing_checks(self): if not self.rhs: raise self.error_class("You must provide a target.") target = self.search(self.rhs) if not target: return if not target.is_character: raise self.error_class("That is not a character.") check_strings = self.lhs.split(" vs ") if len(check_strings) != 2: raise self.error_class("Must provide two checks.") args = [(self.caller, check_strings[0]), (target, check_strings[1])] # use first difficulty value as the rating both checks share rating = DifficultyRating.get_all_cached_instances()[0] rolls = [] for arg in args: stat, skill = self.get_stat_and_skill_from_args(arg[1]) rolls.append( SimpleRoll(character=arg[0], stat=stat, skill=skill, rating=rating) ) OpposingRolls(rolls[0], rolls[1], self.caller, target).announce()
def get_help(self, caller, cmdset): ratings = ", ".join(str(obj) for obj in DifficultyRating.get_all_instances()) msg = f""" @gmcheck Usage: @gmcheck <stat>/<value> [+ <skill>/<value>] at <difficulty>[=<npc name>] @gmcheck/crit <same as above> @gmcheck/flub <same as above> Performs a stat + skill at difficulty check with specified values. Intended for GMs to make rolls for NPCs that don't necessarily exist as characters in-game. The /crit switch allows the roll to crit or botch. The /flub switch intentionally fails the roll. NPC name allows for a GM to optionally assign an NPC name to their roll. Difficulty ratings are as follows: {ratings} """ return msg
def test_stat_check_cmd_normal(self, mock_randint): # test help message fetches Difficulty Ratings from lookup table help_msg = self.instance.get_help(None, None) self.assertIn("easy", help_msg) self.assertIn("Normal", help_msg) # check to see if the memory model cache has added case-insensitive key self.assertEqual(self.normal, DifficultyRating.get_instance_by_name("normal")) self.call_cmd("foo", "Usage: stat [+ skill] at <difficulty rating>") self.call_cmd("dex at foo", "'foo' is not a valid difficulty rating.") # check that a normal roll works mock_randint.return_value = 25 self.call_cmd("dex at normal", "") self.char1.msg_location_or_contents.assert_called_with( f"{self.char1} checks dex at {self.normal}. {self.char1} rolls marginal.", options=self.options, ) # check that we can trigger a higher value result self.char1.traits.set_stat_value("dex", 5) self.call_cmd("dex at easy", "") self.char1.msg_location_or_contents.assert_called_with( f"{self.char1} checks dex at {self.easy}. {self.char1} rolls okay.", options=self.options, ) # check a crit mock_randint.return_value = 99 self.call_cmd("dex at normal", "") self.char1.msg_location_or_contents.assert_called_with( f"{self.char1} checks dex at {self.normal}. Crit! {self.char1} rolls a crit yay!!!!.", options=self.options, ) # check a botch mock_randint.return_value = 1 self.call_cmd("dex at normal", "") self.char1.msg_location_or_contents.assert_called_with( f"{self.char1} checks dex at {self.normal}. Botch! {self.char1} rolls a botch - boo!!!.", options=self.options, )