// // SA_DiceBot.h // RPGBot // // Created by Sandy Achmiz on 12/30/15. // // /* The SA_DiceBot class hierarchy works like this: SA_DiceBot is the root class. A user of the SA_DiceBot package usually only needs to create and manage objects of this class. An SA_DiceBot creates and manages all other objects and classes in the package (directly or through its other members), as needed. An SA_DiceBot owns a single SA_DiceRoller and a single SA_DiceFormatter. The objects owned by an SA_DiceBot are for the SA_DiceBot's internal use only, and not accessible to users of the package. (But see SA_DiceRoller.h and SA_DiceFormatter.h for information on standalone use.) An SA_DiceRoller owns an SA_DiceParser and an SA_DiceEvaluator. An SA_DiceEvaluator owns an SA_DiceBag. (See Figure 1, below.) *--------------------------------------------------------------------------* | Fig. 1. SA_DiceBot class hierarchy diagram. | | | | | | SA_DiceBot | | / \ | | SA_DiceFormatter SA_DiceRoller | | / \ | | SA_DiceParser SA_DiceEvaluator | | | | | SA_DiceBag | | | *--------------------------------------------------------------------------* When the SA_DiceBot receives a recognized command that involves rolling some dice or otherwise evaluating some sort of string of semantically meaningful text (like just adding some numbers), it extracts that string (which may optionally include some text label) from the rest of the message body, and passes it to the SA_DiceRoller. The SA_DiceRoller strips off the label (if any), and passes the 'pure' string to the SA_DiceParser. The SA_DiceParser parses the string and produces an 'expression tree' representation of the string. An expression tree is an NSDictionary with a certain structure (which is described in SA_DiceExpressionStringConstants.h). The SA_DiceRoller then passes the expression tree to the SA_DiceEvaluator. The evaluator recursively traverses the expression tree in a depth-first manner, computing the results of each subtree, and storing those results in (a mutable copy of) the expression tree itself. Once the entire tree has been evaluated, (a mutable copy of) it is returned to the SA_DiceRoller. The SA_DiceRoller reattaches the stripped-off label (inserting it into the top level of the expresion tree) and returns the evaluated expression tree (now called a result) to the SA_DiceBot. The SA_DiceBot passes the evaluated result tree to its SA_DiceFormatter. The formatter traverses the tree, constructing a human-readable string form of the results, with whatever formatting it (the formatter) has been configured to provide. The formatter then returns this formatted result string to the SA_DiceBot. The SA_DiceBot then incorporates the formatted result string into some appropriate reply message or messages, and sends the reply(ies) back to its delegate, for transmission to the appropriate endpoint. */ #import #import "SA_Bot.h" @class SA_CommandResponder; /* ###################################### #### SA_DiceBot Usage Information #### ###################################### I. SUPPORTED COMMANDS & PARSER MODES The set of commands, and the syntax and behavior of those commands, that an SA_DiceBot supports depends on its currently set parser behavior mode (and, in some cases, also on the currently set formatter behavior mode). (Read more about parser behavior modes in SA_DiceParser.h, and about formatter behavior modes in SA_DiceFormatter.h.) Below is a list of available parser modes, along with the commands supported in each mode. (See section II for a list of commands that are supported in all parser modes.) NOTE: Commands are not case-sensitive; e.g., 'roll', 'ROLL', and 'rOLl' all work equally well. 1. DEFAULT mode "Default" mode is an alias for whatever default behavior is currently set for new SA_DiceParser instances. (The "default default" behavior for the current implementation is "legacy".) 2. LEGACY mode "Legacy" mode (mostly) emulates DiceBot by Sabin (and Dawn by xthemage before it). The following commands are available in legacy mode. 1. ROLL command. Takes 1 or more whitespace-delimited roll strings as parameters. The roll command is executed once for every parameter, and each execution generates a separate result string. One reply message is sent for each result string (or, if the simple formatter is being used, the results may optionally be collapsed into a single reply message). Each roll string may optionally be suffixed with with a (configurable) delimiter character (such as ';'), which may be followed with an arbitrary text label (which may not contain whitespace, however). That label may then be included in the result string (depending on the selected formatter behavior mode and other formatter settings). The body of the roll string (up to the label delimiter, if any) is simply parsed and evaluated. EXAMPLES (assuming legacy formatter behavior): Obormot: !roll 1d20 SA_DiceBot: 1d20 < 14 = 14 > = 14 Obormot: .roll 2+4-5 SA_DiceBot: 2 + 4 - 5 = 1 Obormot: /roll 2d4 1d20+19 4d10 SA_DiceBot: 2d4 < 3 1 = 4 > = 4 SA_DiceBot: 1d20 < 5 = 5 > + 19 = 24 SA_DiceBot: 4d10 < 2 2 1 2 = 7 > = 7 Obormot: !roll 1d20+4;fort_save SA_DiceBot: (fort_save) 1d20 < 8 = 8 > + 4 = 12 Obormot: SA_DiceBot: 1d8+6;longsword 1d6+3;shortsword SA_DiceBot: (longsword) 1d8 < 4 = 4 > + 6 = 10 SA_DiceBot: (shortsword) 1d6 < 2 = 2 > + 3 = 5 2. TRY command. Takes 1 or more whitespace-delimited roll strings. Prepends "1d20+" to each roll string, and otherwise behaves in the same way as the ROLL command. 3. CHAR command. II. OTHER COMMANDS III. CONFIGURATION */ /****************************************/ #pragma mark SA_DiceBot class declaration /****************************************/ @interface SA_DiceBot : SA_Bot /************************/ #pragma mark - Properties /************************/ @property (strong) SA_CommandResponder *botCommandresponder; @property (strong) SA_CommandResponder *legacyCommandResponder; @property (strong) SA_CommandResponder *currentCommandResponder; @property (copy) NSString *commandDesignatorCharacters; /****************************/ #pragma mark - Public methods /****************************/ - (void)message:(NSString *)messageBody withInfo:(NSDictionary *)messageInfo; /****************************/ #pragma mark - Helper methods /****************************/ - (NSArray *)repliesForCommandString:(NSString *)commandString messageInfo:(NSDictionary *)messageInfo byName:(BOOL)byName; - (void)loadDefaultCommandResponders; @end