A set of classes for parsing, evaluating, and formatting die roll strings.
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

SA_DiceBot.m 4.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. //
  2. // SA_DiceBot.m
  3. //
  4. // Copyright (c) 2016 Said Achmiz.
  5. //
  6. // This software is licensed under the MIT license.
  7. // See the file "LICENSE" for more information.
  8. #import "SA_DiceBot.h"
  9. #import "SA_BotDelegate.h"
  10. #import "SA_CommandResponder.h"
  11. #import "SA_BotCommandResponder.h"
  12. #import "SA_LegacyCommandResponder.h"
  13. #import "SA_ErrorCatalog.h"
  14. #import "NSString+SA_NSStringExtensions.h"
  15. #import "NSRange-Conventional.h"
  16. /*********************************************/
  17. #pragma mark - SA_DiceBot class implementation
  18. /*********************************************/
  19. @implementation SA_DiceBot
  20. /**************************/
  21. #pragma mark - Initializers
  22. /**************************/
  23. - (instancetype)init
  24. {
  25. return [self initWithName:@"DIE_BOT"];
  26. }
  27. - (instancetype)initWithName:(NSString *)name
  28. {
  29. if(self = [super initWithName:name])
  30. {
  31. NSLog(NSLocalizedString(@"Initializing SA_DiceBot with name \"%@\"", @"{display name of the bot}"), name);
  32. self.commandDesignatorCharacters = @".!/";
  33. [self loadDefaultCommandResponders];
  34. }
  35. return self;
  36. }
  37. /****************************/
  38. #pragma mark - Public methods
  39. /****************************/
  40. - (void)message:(NSString *)messageBody withInfo:(NSDictionary *)messageInfo
  41. {
  42. if([messageBody isEqualToString:@""])
  43. {
  44. // Ignore empty messages.
  45. }
  46. else
  47. {
  48. NSRange commandRange;
  49. BOOL byName;
  50. // Is the message a possible command? That is, does it start with any of
  51. // the permitted initial characters that designate a command?
  52. NSString *firstChar = [messageBody substringToIndex:1];
  53. if([self.commandDesignatorCharacters containsCharactersInString:firstChar])
  54. {
  55. commandRange = NSMakeRange(1, messageBody.length - 1);
  56. byName = NO;
  57. }
  58. else
  59. {
  60. // We also recognize commands that come after mentions of the bot's
  61. // name at the beginning of the message.
  62. NSRange possibleNameRange = NSRangeMake(0, self.name.length);
  63. if(messageBody.length > self.name.length &&
  64. [[messageBody substringWithRange:possibleNameRange] isEqualToString:self.name])
  65. {
  66. commandRange = [messageBody rangeToEndFrom:[messageBody firstNonWhitespaceAfterRange:[messageBody firstWhitespaceAfterRange:possibleNameRange]]];
  67. byName = YES;
  68. }
  69. else
  70. {
  71. // Does not begin with a command. Ignore.
  72. return;
  73. }
  74. }
  75. // Extract the part of the string that is the actual command.
  76. NSString *commandString = [messageBody substringWithRange:commandRange];
  77. // Get the replies for this command.
  78. NSArray <NSDictionary *> *replies = [self repliesForCommandString:commandString messageInfo:messageInfo byName:byName];
  79. // Send the replies.
  80. [replies enumerateObjectsUsingBlock:^(NSDictionary *reply, NSUInteger idx, BOOL *stop) {
  81. [self.delegate SA_botMessage:reply[SA_DB_MESSAGE_BODY]
  82. from:self
  83. withInfo:reply[SA_DB_MESSAGE_INFO]];
  84. }];
  85. }
  86. }
  87. /****************************/
  88. #pragma mark - Helper methods
  89. /****************************/
  90. - (NSArray <NSDictionary *> *)repliesForCommandString:(NSString *)commandString messageInfo:(NSDictionary *)messageInfo byName:(BOOL)byName
  91. {
  92. NSError *error;
  93. NSArray <NSDictionary *> *replies = [self.botCommandresponder repliesForCommandString:commandString messageInfo:messageInfo error:&error];
  94. if(error && error.code == SA_DiceBotErrorUnknownCommand)
  95. {
  96. error = nil;
  97. replies = [self.currentCommandResponder repliesForCommandString:commandString messageInfo:messageInfo error:&error];
  98. }
  99. if(error)
  100. {
  101. // Is outputting the provided error the right way to do error handling
  102. // here? I don't know. Maybe not. For now, that's what it is.
  103. NSString *errorReply = [NSString stringWithFormat:NSLocalizedString(@"ERROR: %@ (%@ %@)", @"{description}, {failure reason}, {recovery suggestion}"),
  104. error.localizedDescription,
  105. error.localizedFailureReason,
  106. error.localizedRecoverySuggestion];
  107. replies = [replies arrayByAddingObject:@{ SA_DB_MESSAGE_BODY : errorReply,
  108. SA_DB_MESSAGE_INFO : messageInfo }];
  109. }
  110. return replies;
  111. }
  112. - (void)loadDefaultCommandResponders
  113. {
  114. self.legacyCommandResponder = [SA_LegacyCommandResponder new];
  115. self.botCommandresponder = [SA_BotCommandResponder new];
  116. // The default command responder, in the current implementation, is the
  117. // legacy command responder.
  118. self.currentCommandResponder = self.legacyCommandResponder;
  119. }
  120. @end