def net_cmd_ms(self, args): """IC message. Refer to the implementation for details. """ if not self.client.is_checked: return elif self.client.is_muted: # Checks to see if the client has been muted by a mod self.client.send_ooc('You are muted by a moderator.') return elif not self.client.area.can_send_message(self.client): return target_area = [] showname = "" charid_pair = -1 offset_pair = "" nonint_pre = 0 sfx_looping = "0" screenshake = 0 frames_shake = "" frames_realization = "" frames_sfx = "" additive = 0 effect = "" pair_order = 0 if self.validate_net_cmd( args, self.ArgType.STR, # msg_type self.ArgType.STR_OR_EMPTY, self.ArgType.STR, # pre, folder self.ArgType.STR, self.ArgType.STR_OR_EMPTY, # anim, text self.ArgType.STR, self.ArgType.STR, # pos, sfx self.ArgType.INT, self.ArgType.INT, # anim_type, cid self.ArgType.INT, self.ArgType.INT_OR_STR, # sfx_delay, button self.ArgType.INT, self.ArgType.INT, # evidence, flip self.ArgType.INT, self.ArgType.INT, # ding, color ): # Pre-2.6 validation monstrosity. msg_type, pre, folder, anim, text, pos, sfx, anim_type, cid, sfx_delay, button, evidence, flip, ding, color = args elif self.validate_net_cmd( args, self.ArgType.STR, self.ArgType.STR_OR_EMPTY, # msg_type, pre self.ArgType.STR, self.ArgType.STR, self.ArgType.STR_OR_EMPTY, # folder, anim, text self.ArgType.STR, self.ArgType.STR, self.ArgType.INT, # pos, sfx, anim_type self.ArgType.INT, self.ArgType.INT, self.ArgType.INT_OR_STR, # cid, sfx_delay, button self.ArgType.INT, self.ArgType.INT, self.ArgType.INT, # evidence, flip, ding # color, showname, charid_pair self.ArgType.INT, self.ArgType.STR_OR_EMPTY, self.ArgType.INT, # offset_pair, nonint_pre self.ArgType.STR, self.ArgType.INT, ): # 2.6 validation monstrosity. msg_type, pre, folder, anim, text, pos, sfx, anim_type, cid, sfx_delay, button, evidence, flip, ding, color, showname, charid_pair, offset_pair, nonint_pre = args elif self.validate_net_cmd( args, self.ArgType.STR, self.ArgType.STR_OR_EMPTY, # msg_type, pre self.ArgType.STR, self.ArgType.STR, self.ArgType.STR_OR_EMPTY, # folder, anim, text self.ArgType.STR, self.ArgType.STR, self.ArgType.INT, # pos, sfx, anim_type self.ArgType.INT, self.ArgType.INT, self.ArgType.INT_OR_STR, # cid, sfx_delay, button self.ArgType.INT, self.ArgType.INT, self.ArgType.INT, # evidence, flip, ding # color, showname, charid_pair self.ArgType.INT, self.ArgType.STR_OR_EMPTY, self.ArgType.STR, # offset_pair, nonint_pre, sfx_looping self.ArgType.STR, self.ArgType.INT, self.ArgType.STR, # screenshake, frames_shake, frames_realization self.ArgType.INT, self.ArgType.STR, self.ArgType.STR, # frames_sfx, additive, effect self.ArgType.STR, self.ArgType.INT, self.ArgType.STR, ): # 2.8 validation monstrosity. (rip 2.7) msg_type, pre, folder, anim, text, pos, sfx, anim_type, cid, sfx_delay, button, evidence, flip, ding, color, showname, charid_pair, offset_pair, nonint_pre, sfx_looping, screenshake, frames_shake, frames_realization, frames_sfx, additive, effect = args pair_args = charid_pair.split("^") charid_pair = int(pair_args[0]) if (len(pair_args) > 1): pair_order = pair_args[1] else: return if additive == 1 and self.client.area.client_can_additive(self.client): additive = 1 else: additive = 0 if len(showname) > 0 and not self.client.area.showname_changes_allowed: self.client.send_ooc( "Showname changes are forbidden in this area!") return else: self.client.showname = showname if self.client.area.is_iniswap(self.client, pre, anim, folder, sfx): self.client.send_ooc( "Iniswap/custom emotes are blocked in this area") return if len(self.client.charcurse) > 0 and \ folder != self.client.char_name: self.client.send_ooc( "You may not iniswap while you are charcursed!") return if not self.client.area.blankposting_allowed: if text.strip() == '': self.client.send_ooc("Blankposting is forbidden in this area!") return if len(re.sub(r'[{}\\`|(~~)]', '', text).replace( ' ', '')) < 3 and not text.startswith( '<') and not text.startswith('>'): self.client.send_ooc( "While that is not a blankpost, it is still pretty spammy. Try forming sentences." ) return if text.startswith( '/a ' ): # Send a message to a specific area the client is CM in part = text.split(' ') try: aid = int(part[1]) area = self.server.area_manager.get_area_by_id(aid) if self.client in area.owners: target_area.append(aid) if not target_area: self.client.send_ooc(f'You don\'t own {area.name}!') return text = ' '.join(part[2:]) except ValueError: self.client.send_ooc( "That does not look like a valid area ID!") return elif text.startswith( '/s '): # Send a message to all areas client is CM in part = text.split(' ') for a in self.server.area_manager.areas: if self.client in a.owners: target_area.append(a.id) if not target_area: self.client.send_ooc('You don\'t any areas!') return text = ' '.join(part[1:]) elif text.startswith( '/testify '): # Start a new testimony in this area. part = text.split(' ') text = ' '.join(part[1:]) # remove command if not self.client.area.start_testimony(self.client, text): return text = '~~-- ' + text + ' --' color = 3 # orange elif text.startswith( '/examine'): # Start an examination of this area's testimony. if not self.client.area.start_examination(self.client): return text = '~~-- ' + self.client.area.testimony.title + ' --' color = 3 if self.client.area.is_testifying or self.client.area.is_examining: if text.startswith( '/end'): # End the current testimony or examination. if not self.client.area.end_testimony(self.client): return text = '' elif text.startswith('/amend '): part = text.split(' ') text = ' '.join(part[2:]) args[4] = text color = 1 try: index = int(part[1]) if not self.client.area.amend_testimony( self.client, index, args): return if self.client.area.is_testifying: return # don't send it again or it'll be rerecorded elif self.client.area.is_examining: self.client.area.examine_index = index # jump to the amended statement except ValueError: self.client.send_ooc( "That does not look like a valid statement number!") return elif text.startswith('/add ') and self.client.area.is_examining: part = text.split(' ') text = ' '.join(part[1:]) args[4] = text self.client.area.testimony.add_statement(tuple(args)) color = 1 # green self.client.area.examine_index = len( self.client.area.testimony.statements ) - 1 # jump to the new statement elif text.startswith('/remove '): part = text.split(' ') try: index = int(part[1]) if not self.client.area.remove_statement( self.client, index): return text = '' except ValueError: self.client.send_ooc( "That does not look like a valid statement number!") return if self.client.area.is_examining and text != '' and text[0] in [ '>', '<', '=' ]: try: self.client.area.navigate_testimony( self.client, text[0], int(text[1:])) except ValueError: self.client.area.navigate_testimony(self.client, text[0]) return if msg_type not in ('chat', '0', '1', '2', '3', '4', '5'): return if anim_type == 4: anim_type = 6 if anim_type not in (0, 1, 2, 5, 6): return if cid != self.client.char_id: return if sfx_delay < 0: return if '4' in str(button) and "<and>" not in str(button): if not button.isdigit(): return if evidence < 0: return if ding not in (0, 1): return if color not in (0, 1, 2, 3, 4, 5, 6, 7, 8): return if len(showname) > 15: self.client.send_ooc("Your IC showname is way too long!") return if nonint_pre == 1: if button in (1, 2, 3, 4, 23): if anim_type == 1 or anim_type == 2: anim_type = 0 elif anim_type == 6: anim_type = 5 if self.client.area.non_int_pres_only: if anim_type == 1 or anim_type == 2: anim_type = 0 nonint_pre = 1 elif anim_type == 6: anim_type = 5 nonint_pre = 1 if not self.client.area.shouts_allowed: # Old clients communicate the objecting in anim_type. if anim_type == 2: anim_type = 1 elif anim_type == 6: anim_type = 5 # New clients do it in a specific objection message area. button = 0 # Turn off the ding. ding = 0 max_char = 0 try: max_char = int(self.server.config['max_chars']) except: max_char = 256 if len(text) > max_char: return # Transform text msg = self.dezalgo(text)[:256] if self.client.shaken: msg = self.client.shake_message(msg) if self.client.disemvowel: msg = self.client.disemvowel_message(msg) # Really simple spam protection that functions on the clientside pre-2.8.5, and really should've been serverside from the start if msg.strip( ) != '' and self.client.area.last_ic_message is not None and cid == self.client.area.last_ic_message[ 8] and msg.rstrip( ) == self.client.area.last_ic_message[4].rstrip(): self.client.send_ooc( "Your message is a repeat of the last one. Don't spam!") return if evidence not in self.client.evi_list: evidence = 0 # Reveal evidence to everyone if hidden elif evidence and self.client.area.evi_list.evidences[ self.client.evi_list[evidence] - 1].pos != 'all': self.client.area.evi_list.evidences[self.client.evi_list[evidence] - 1].pos = 'all' self.client.area.broadcast_evidence_list() # Here, we check the pair stuff, and save info about it to the client. # Notably, while we only get a charid_pair and an offset, we send back a chair_pair, an emote, a talker offset # and an other offset. self.client.charid_pair = charid_pair self.client.offset_pair = offset_pair if anim_type not in (5, 6): self.client.last_sprite = anim self.client.flip = flip self.client.claimed_folder = folder other_offset = '0' other_emote = '' other_flip = 0 other_folder = '' confirmed = False if charid_pair > -1: for target in self.client.area.clients: if not confirmed and target.char_id == self.client.charid_pair and target.charid_pair == self.client.char_id and target != self.client and target.pos == self.client.pos: confirmed = True other_offset = target.offset_pair other_emote = target.last_sprite other_flip = target.flip other_folder = target.claimed_folder if (pair_order != ""): charid_pair = "{}^{}".format(charid_pair, pair_order) break if not confirmed: charid_pair = -1 if self.client in self.client.area.afkers: self.client.server.client_manager.toggle_afk(self.client) send_args = (msg_type, pre, folder, anim, msg, pos, sfx, anim_type, cid, sfx_delay, button, self.client.evi_list[evidence], flip, ding, color, showname, charid_pair, other_folder, other_emote, offset_pair, other_offset, other_flip, nonint_pre, sfx_looping, screenshake, frames_shake, frames_realization, frames_sfx, additive, effect) self.client.area.last_ic_message = send_args self.client.area.send_command('MS', *send_args) self.server.area_manager.send_remote_command(target_area, 'MS', *send_args) self.client.area.send_owner_command( 'MS', *send_args[:4], '[' + self.client.area.abbreviation + ']' + msg, *send_args[5:]) self.client.area.set_next_msg_delay(len(msg)) database.log_ic(self.client, self.client.area, showname, msg) if self.client.area.is_recording: self.client.area.recorded_messages.append(args) if self.client.area.is_testifying: if (not self.client.area.testimony.add_statement(send_args)): self.client.send_ooc( "That statement was not recorded because you reached the statement limit." )
def net_cmd_ms(self, args): """IC message. Refer to the implementation for details. -Steel: Doing some documentation on this giga-function. You'll find my stuff sprinkled about through here. It's mostly theorized ideas of what the code is doing as I read, with references to functions and the files they come from. Enjoy. And good luck. """ """ is_checked is part of the ban checking process, which is found in net_cmd_hi further up this file. is_muted is kind of obvious. can_send_message is defined in server/area_manager.py, checking to see if you can send a message in an area. 'permission' is if you can use Web AO or not, I think. It's granted by ooc_cmd_permit in server/admin.py. """ if not self.client.is_checked: return elif self.client.is_muted: # Checks to see if the client has been muted by a mod self.client.send_ooc('You are muted by a moderator.') return elif not self.client.area.can_send_message(self.client): return elif not self.client.permission: self.client.send_ooc('You need permission to use a web client, please ask staff.') return statement = None target_area = [] showname = "" charid_pair = -1 offset_pair = "" nonint_pre = 0 looping_sfx = 0 screenshake = 0 frame_screenshake = "" frame_realization = "" frame_sfx = "" additive = 0 effect = "" pair_order = 0 """ Client validation for the message starts here. -Break off into net_cmd_validate_pre26, calling validate_net_cmd with appropriate parameters Looks like it runs the IC message from the client through the validator, then returns """ if self.validate_net_cmd(args, *AOProtocol.msgpre260): # Pre-2.6 validation monstrosity. (msg_type, pre, folder, anim, text, pos, sfx, anim_type, cid, sfx_delay, button, evidence, flip, ding, color) = args #-Break off into net_cmd_validate_27, calling validate_net_cmd with appropriate parameters elif self.validate_net_cmd(args, *AOProtocol.msg270): # 2.7.0 validation monstrosity (msg_type, pre, folder, anim, text, pos, sfx, anim_type, cid, sfx_delay, button, evidence, flip, ding, color, showname, charid_pair, offset_pair, nonint_pre, looping_sfx, screenshake, frame_screenshake, frame_realization, frame_sfx) = args if len(showname) > 0 and not self.client.area.showname_changes_allowed: self.client.send_host_message("Showname changes are forbidden in this area!") return #-Break off into net_cmd_validate_29, calling validate_net_cmd with appropriate parameters. #I think this is the latest set of validations... God, what a mess. elif self.validate_net_cmd(args, *AOProtocol.msg290): (msg_type, pre, folder, anim, text, pos, sfx, anim_type, cid, sfx_delay, button, evidence, flip, ding, color, showname, charid_pair, offset_pair, nonint_pre, looping_sfx, screenshake, frame_screenshake, frame_realization, frame_sfx, additive, effect) = args pair_args = charid_pair.split("^") charid_pair = int(pair_args[0]) if (len(pair_args) > 1): pair_order = pair_args[1] if len(showname) > 0 and not self.client.area.showname_changes_allowed: self.client.send_host_message("Showname changes are forbidden in this area!") return else: return #Client message validation ends here. #Showname is set here, followed by an iniswap check. is_iniswap takes the client, a 'pre', the anim integer I think, folder name and sfx. #Considering the context, I think it's checking to see if you are iniswapped? #You can find is_iniswap in server/network/area_manager.py self.client.showname = showname if self.client.area.is_iniswap(self.client, pre, anim, folder, sfx): self.client.send_ooc("Iniswap/custom emotes are blocked in this area") return #Checking if charcurse (ooc_cmd_charcurse in server/commands/character.py) Charcurse is if len(self.client.charcurse) > 0 and \ folder != self.client.char_name: self.client.send_ooc( "You may not iniswap while you are charcursed!") return if not self.client.area.blankposting_allowed: if text == ' ': self.client.send_ooc( "Blankposting is forbidden in this area!") return if text.isspace(): self.client.send_ooc( "Blankposting is forbidden in this area, and putting more spaces in does not make it not blankposting." ) return if len(re.sub(r'[{}\\`|(~~)]', '', text).replace( ' ', '')) < 3 and text != '<' and text != '>': self.client.send_ooc( "While that is not a blankpost, it is still pretty spammy. Try forming sentences." ) return if text.startswith('/a '): part = text.split(' ') try: abbr = part[1] area = self.server.area_manager.get_area_by_abbreviation(abbr) if self.client in area.owners: target_area.append(area) if not target_area: self.client.send_ooc(f'You don\'t own {area.name}!') return text = ' '.join(part[2:]) except AreaError: self.client.send_ooc("That does not look like a valid area ID!") return elif text.startswith('/s '): part = text.split(' ') for a in self.server.area_manager.areas: if a.is_hub: for sub in a.subareas: if self.client in sub.owners: target_area.append(sub) if self.client in a.owners: target_area.append(a) if not target_area: self.client.send_ooc('You aren\'t CMing any areas!') return text = ' '.join(part[1:]) if msg_type not in ('chat', '0', '1'): return if sfx.startswith('../music'): sfx = '' if anim_type not in (0, 1, 2, 4, 5, 6): return if cid != self.client.char_id: return if sfx_delay < 0: return if not '4' in str(button) and "<and>" not in str(button): strbutton = str(button) if not button.isdigit(): return if evidence < 0: return if ding not in (0, 1): return if color not in (0, 1, 2, 3, 4, 5, 6, 7, 8): return if len(showname) > 22: self.client.send_ooc("Your IC showname is way too long!") return if nonint_pre == 1: if button in (1, 2, 3, 4, 23): if anim_type == 1 or anim_type == 2: anim_type = 0 elif anim_type == 6: anim_type = 5 if self.client.area.non_int_pres_only: if anim_type == 1 or anim_type == 2: anim_type = 0 nonint_pre = 1 elif anim_type == 6: anim_type = 5 nonint_pre = 1 if not self.client.area.shouts_allowed and not (self.client.is_mod or self.client in self.client.area.owners): # Old clients communicate the objecting in anim_type. if anim_type == 2: anim_type = 1 elif anim_type == 6: anim_type = 5 # New clients do it in a specific objection message area. button = 0 # Turn off the ding. ding = 0 if color == 2 and not (self.client.is_mod or self.client in self.client.area.owners): color = 0 if pos != self.client.pos: self.client.change_position(pos, True) if not len(self.client.area.poslock) == 0 and not (self.client.is_mod or self.client in self.client.area.owners): if pos not in self.client.area.poslock: pos = self.client.area.poslock[0] self.client.send_ooc(f'Your pos isn\'t in /poslock, falling back on {pos}.') self.client.change_position(pos, True) msg = self.dezalgo(text)[:256] if self.client.shaken: msg = self.client.shake_message(msg) if self.client.gimp: # If you're gimped, gimp message. msg = self.client.gimp_message(msg) if self.client.disemvowel: msg = self.client.disemvowel_message(msg) if evidence: if self.client.area.evi_list.evidences[ self.client.evi_list[evidence] - 1].pos != 'all': self.client.area.evi_list.evidences[ self.client.evi_list[evidence] - 1].pos = 'all' self.client.area.broadcast_evidence_list() if msg.lstrip().startswith('(('): msg = msg.lstrip() msg = msg.replace('((', '') msg = msg.replace('))', '') name = self.client.name if name == '': name = self.client.char_name if not msg == self.client.area.last_ooc: self.client.area.send_command('CT', name, msg) self.client.area.send_owner_command('CT', '[' + self.client.area.abbreviation + ']' + name, msg) self.client.area.last_ooc = msg return # Here, we check the pair stuff, and save info about it to the client. # Notably, while we only get a charid_pair and an offset, we send back a chair_pair, an emote, a talker offset # and an other offset. self.client.charid_pair = charid_pair self.client.offset_pair = offset_pair if anim_type not in (5, 6): self.client.last_sprite = anim self.client.flip = flip self.client.claimed_folder = folder other_offset = '0' other_emote = '' other_flip = 0 other_folder = '' confirmed = False if charid_pair > -1 and not confirmed: for target in self.client.area.clients: if target.char_id == self.client.charid_pair and target.charid_pair == self.client.char_id and target != self.client and target.pos == self.client.pos: confirmed = True other_offset = target.offset_pair other_emote = target.last_sprite other_flip = target.flip other_folder = target.claimed_folder if (pair_order != 0): charid_pair = "{}^{}".format(charid_pair, pair_order) break if not confirmed: charid_pair = -1 #offset_pair = 0 if self.client.afk: self.client.server.client_manager.toggle_afk(self.client) if self.client.afktime: self.client.afktime.cancel() if self.server.config['afk_delay'] > 0: self.client.afktime = asyncio.get_event_loop().call_later(self.client.server.config['afk_delay'], lambda: self.client.server.client_manager.toggle_afk(self.client)) send_args = [msg_type, pre, folder, anim, msg, pos, sfx, anim_type, cid, sfx_delay, button, self.client.evi_list[evidence], flip, ding, color, showname, charid_pair, other_folder, other_emote, offset_pair, other_offset, other_flip, nonint_pre, looping_sfx, screenshake, frame_screenshake, frame_realization, frame_sfx, additive, effect] msg2 = f'[{self.client.area.abbreviation}]{msg}' owner_args = [msg_type, pre, folder, anim, msg2, pos, sfx, anim_type, cid, sfx_delay, button, self.client.evi_list[evidence], flip, ding, color, showname, charid_pair, other_folder, other_emote, offset_pair, other_offset, other_flip, nonint_pre, looping_sfx, screenshake, frame_screenshake, frame_realization, frame_sfx, additive, effect] if self.client.area.last_speaker != self.client: additive = 0 if not self.client.incall: if msg == '///': if self.client in self.client.area.owners and not self.client.area.is_recording and len(self.client.area.recorded_messages) != 0: for statements in self.client.area.recorded_messages: if statements.id == 0: statement = statements self.client.area.send_command('MS', *statement.args) if self.client.can_wtce: self.client.area.send_command('RT', 'testimony2') self.client.area.statement = 0 elif msg.startswith('//'): if self.client in self.client.area.owners and not self.client.area.is_recording: self.client.area.is_recording = True self.client.area.recorded_messages.clear() self.client.area.statement = 0 statement = Statement(send_args) statement.args[4] = msg[2:] self.client.area.recorded_messages.append(statement) self.client.send_ooc('Recording testimony!') if self.client.can_wtce: self.client.area.send_command('RT', 'testimony1') if msg == '/end': if self.client in self.client.area.owners and self.client.area.is_recording: self.client.area.is_recording = False self.client.area.statement += 1 statement = Statement(send_args) statement.id = self.client.area.statement self.client.area.statement = 0 self.client.area.recorded_messages.append(statement) self.client.send_ooc('No longer recording testimony.') if msg.startswith('+'): if self.client in self.client.area.owners and self.client.area.is_recording: if self.client.area.statement >= 30: return self.client.send_ooc('You\'re trying to add too many statements.') self.client.area.statement += 1 statement = Statement(send_args) statement.args[4] = msg[1:] statement.id = self.client.area.statement self.client.area.recorded_messages.append(statement) self.client.send_ooc('Statement added!') elif self.client in self.client.area.owners and not self.client.area.is_recording and len(self.client.area.recorded_messages) != 0: if self.client.area.statement >= 30: return self.client.send_ooc('You\'re trying to add too many statements.') oldstatement = self.client.area.statement self.client.area.statement += 1 statement = Statement(send_args) statement.args[4] = msg[1:] statement.args[14] = 1 statement.id = self.client.area.statement for s in self.client.area.recorded_messages: if s.id >= statement.id: s.id += 1 self.client.area.recorded_messages.append(statement) self.client.send_ooc(f'Substatement added after statement {oldstatement}!') if msg.startswith('<and>'): if self.client in self.client.area.owners and not self.client.area.is_recording and len(self.client.area.recorded_messages) != 0: """for s in self.client.area.recorded_messages: if s.id == self.client.area.statement: msg = msg[5:] s = Statement(send_args) s.id = self.client.area.statement s.args[4] = msg[4:] s.args[14] = 1 self.client.send_ooc(f'Statement {s.id} amended.') """ amend = None for s in self.client.area.recorded_messages: if s.id == self.client.area.statement: amend = s if amend != None: newamend = self.client.area.recorded_messages[amend.id] = Statement(send_args) newamend.id = self.client.area.statement newamend.args[4] = msg[5:] newamend.args[14] = 1 self.client.send_ooc(f'Statement {newamend.id} amended.') playback = False fastforward = False if msg == '>' or msg == '>>': if len(self.client.area.recorded_messages) != 0 and not self.client.area.is_recording: self.client.area.statement += 1 if self.client.area.statement >= len(self.client.area.recorded_messages): self.client.area.statement = 1 self.client.area.broadcast_ooc(f'{self.client.char_name} reached end, looping back to first statement.') else: self.client.area.broadcast_ooc(f'Testimony advanced by {self.client.char_name}.') for s in self.client.area.recorded_messages: if s.id == self.client.area.statement: statement = s break playback = True if msg == '>>': fastforward = True elif msg.startswith('>'): if len(self.client.area.recorded_messages) != 0 and not self.client.area.is_recording: if msg.startswith('>>'): msg = msg[2:] fastforward = True else: msg = msg[1:] try: statementno = int(msg) except: self.client.send_ooc('That is not a valid statement number.') return for s in self.client.area.recorded_messages: if s.id == statementno: statement = s self.client.area.statement = statementno playback = True self.client.area.broadcast_ooc(f'{self.client.char_name} skipped to statement {self.client.area.statement}.') break if not playback: self.client.send_ooc('No statement with that number found.') return if msg == '<' or msg == '<<': if len(self.client.area.recorded_messages) != 0 and not self.client.area.is_recording: self.client.area.statement += -1 if self.client.area.statement < 1: self.client.area.statement = 1 self.client.send_ooc('At first statement, no previous statement available.') for s in self.client.area.recorded_messages: if s.id == self.client.area.statement: statement = s break playback = True if msg == '<<': fastforward = True else: for s in self.client.area.recorded_messages: if s.id == self.client.area.statement: statement = s playback = True if msg == '<<': fastforward = True break self.client.area.broadcast_ooc(f'{self.client.char_name} went to the previous statement of the testimony.') if msg == '=' or msg == '==': if len(self.client.area.recorded_messages) != 0 and not self.client.area.is_recording: if self.client.area.statement <= 0: self.client.area.statement = 1 for s in self.client.area.recorded_messages: if s.id == self.client.area.statement: statement = s break playback = True if msg == '==': fastforward = True self.client.area.broadcast_ooc(f'{self.client.char_name} repeated the current statement.') if playback: last = len(self.client.area.recorded_messages) - 1 if not self.client.area.statement < 1 and not self.client.area.statement == last: statement.prepce() if fastforward: nargs = statement.args[4] statement.args[4] = '}}}' statement.args[4] += nargs self.client.area.send_command('MS', *statement.args) if fastforward: nargs = statement.args[4] statement.args[4] = nargs[3:] if not msg == '///' or not self.client in self.client.area.owners or len(self.client.area.recorded_messages) == 0: if not playback: if self.client.narrator: send_args[2] = 'Narrator' send_args[3] = 'normal' elif not self.client.visible: if '/' in send_args[2]: send_args[3] = '../../../background/AADetentionCenter/defensedesk' else: send_args[3] = '../../background/AADetentionCenter/defensedesk' self.client.area.send_command('MS', *send_args) self.server.area_manager.send_remote_command(target_area, 'MS', *send_args) self.client.area.send_owner_command('MS', *owner_args) self.client.area.set_next_msg_delay(len(msg)) self.client.area.last_speaker = self.client if msg != '' and msg != ' ': database.log_ic(self.client, self.client.area, showname, msg) else: self.client.call.send_owner_command('MS', *owner_args) self.client.call.set_next_msg_delay(len(msg)) self.client.call.last_speaker = self.client if msg != '' and msg != ' ': database.log_ic(self.client, self.client.area, showname, msg)
def net_cmd_ms(self, args): """IC message. Refer to the implementation for details. """ if not self.client.is_checked: return elif self.client.is_muted: # Checks to see if the client has been muted by a mod self.client.send_ooc('You are muted by a moderator.') return elif not self.client.area.can_send_message(self.client): return target_area = [] showname = "" charid_pair = -1 offset_pair = 0 nonint_pre = 0 sfx_looping = "0" screenshake = 0 frames_shake = "" frames_realization = "" frames_sfx = "" additive = 0 effect = "" pair_order = 0 if self.validate_net_cmd(args, self.ArgType.STR, # msg_type self.ArgType.STR_OR_EMPTY, self.ArgType.STR, # pre, folder self.ArgType.STR, self.ArgType.STR, # anim, text self.ArgType.STR, self.ArgType.STR, # pos, sfx self.ArgType.INT, self.ArgType.INT, # anim_type, cid self.ArgType.INT, self.ArgType.INT_OR_STR, # sfx_delay, button self.ArgType.INT, self.ArgType.INT, # evidence, flip self.ArgType.INT, self.ArgType.INT, # ding, color ): # Pre-2.6 validation monstrosity. msg_type, pre, folder, anim, text, pos, sfx, anim_type, cid, sfx_delay, button, evidence, flip, ding, color = args elif self.validate_net_cmd( args, self.ArgType.STR, self.ArgType.STR_OR_EMPTY, # msg_type, pre self.ArgType.STR, self.ArgType.STR, self.ArgType.STR, # folder, anim, text self.ArgType.STR, self.ArgType.STR, self.ArgType.INT, # pos, sfx, anim_type self.ArgType.INT, self.ArgType.INT, self.ArgType.INT_OR_STR, # cid, sfx_delay, button self.ArgType.INT, self.ArgType.INT, self.ArgType.INT, # evidence, flip, ding self.ArgType.INT, self.ArgType.STR_OR_EMPTY, self.ArgType.INT, # color, showname, charid_pair self.ArgType.INT, self.ArgType.INT, # offset_pair, nonint_pre ): # 2.6 validation monstrosity. msg_type, pre, folder, anim, text, pos, sfx, anim_type, cid, sfx_delay, button, evidence, flip, ding, color, showname, charid_pair, offset_pair, nonint_pre = args elif self.validate_net_cmd( args, self.ArgType.STR, self.ArgType.STR_OR_EMPTY, # msg_type, pre self.ArgType.STR, self.ArgType.STR, self.ArgType.STR, # folder, anim, text self.ArgType.STR, self.ArgType.STR, self.ArgType.INT, # pos, sfx, anim_type self.ArgType.INT, self.ArgType.INT, self.ArgType.INT_OR_STR, # cid, sfx_delay, button self.ArgType.INT, self.ArgType.INT, self.ArgType.INT, # evidence, flip, ding self.ArgType.INT, self.ArgType.STR_OR_EMPTY, self.ArgType.STR, # color, showname, charid_pair self.ArgType.INT, self.ArgType.INT, self.ArgType.STR, # offset_pair, nonint_pre, sfx_looping self.ArgType.INT, self.ArgType.STR, self.ArgType.STR, # screenshake, frames_shake, frames_realization self.ArgType.STR, self.ArgType.INT, self.ArgType.STR, # frames_sfx, additive, effect ): # 2.8 validation monstrosity. (rip 2.7) msg_type, pre, folder, anim, text, pos, sfx, anim_type, cid, sfx_delay, button, evidence, flip, ding, color, showname, charid_pair, offset_pair, nonint_pre, sfx_looping, screenshake, frames_shake, frames_realization, frames_sfx, additive, effect = args pair_args = charid_pair.split("^") charid_pair = int(pair_args[0]) if (len(pair_args) > 1): pair_order = pair_args[1] else: return if len(showname) > 0 and not self.client.area.showname_changes_allowed: self.client.send_ooc( "Showname changes are forbidden in this area!") return if self.client.area.is_iniswap(self.client, pre, anim, folder, sfx): self.client.send_ooc("Iniswap/custom emotes are blocked in this area") return if len(self.client.charcurse) > 0 and \ folder != self.client.char_name: self.client.send_ooc( "You may not iniswap while you are charcursed!") return if not self.client.area.blankposting_allowed: if text == ' ': self.client.send_ooc( "Blankposting is forbidden in this area!") return if text.isspace(): self.client.send_ooc( "Blankposting is forbidden in this area, and putting more spaces in does not make it not blankposting." ) return if len(re.sub(r'[{}\\`|(~~)]', '', text).replace( ' ', '')) < 3 and text != '<' and text != '>': self.client.send_ooc( "While that is not a blankpost, it is still pretty spammy. Try forming sentences." ) return if text.startswith('/a '): part = text.split(' ') try: aid = int(part[1]) area = self.server.area_manager.get_area_by_id(aid) if self.client in area.owners: target_area.append(aid) if not target_area: self.client.send_ooc(f'You don\'t own {area.name}!') return text = ' '.join(part[2:]) except ValueError: self.client.send_ooc( "That does not look like a valid area ID!") return elif text.startswith('/s '): part = text.split(' ') for a in self.server.area_manager.areas: if self.client in a.owners: target_area.append(a.id) if not target_area: self.client.send_ooc('You don\'t any areas!') return text = ' '.join(part[1:]) if msg_type not in ('chat', '0', '1'): return if anim_type not in (0, 1, 2, 4, 5, 6): return if cid != self.client.char_id: return if sfx_delay < 0: return if '4' in str(button) and "<and>" not in str(button): if not button.isdigit(): return if evidence < 0: return if ding not in (0, 1): return if color not in (0, 1, 2, 3, 4, 5, 6, 7, 8): return if len(showname) > 15: self.client.send_ooc("Your IC showname is way too long!") return if nonint_pre == 1: if button in (1, 2, 3, 4, 23): if anim_type == 1 or anim_type == 2: anim_type = 0 elif anim_type == 6: anim_type = 5 if self.client.area.non_int_pres_only: if anim_type == 1 or anim_type == 2: anim_type = 0 nonint_pre = 1 elif anim_type == 6: anim_type = 5 nonint_pre = 1 if not self.client.area.shouts_allowed: # Old clients communicate the objecting in anim_type. if anim_type == 2: anim_type = 1 elif anim_type == 6: anim_type = 5 # New clients do it in a specific objection message area. button = 0 # Turn off the ding. ding = 0 max_char = 0 try: max_char = int(self.server.config['max_chars']) except: max_char = 256 if len(text) > max_char: return msg = self.dezalgo(text)[:256] if self.client.shaken: msg = self.client.shake_message(msg) if self.client.disemvowel: msg = self.client.disemvowel_message(msg) if evidence: if self.client.area.evi_list.evidences[ self.client.evi_list[evidence] - 1].pos != 'all': self.client.area.evi_list.evidences[ self.client.evi_list[evidence] - 1].pos = 'all' self.client.area.broadcast_evidence_list() # Here, we check the pair stuff, and save info about it to the client. # Notably, while we only get a charid_pair and an offset, we send back a chair_pair, an emote, a talker offset # and an other offset. self.client.charid_pair = charid_pair self.client.offset_pair = offset_pair if anim_type not in (5, 6): self.client.last_sprite = anim self.client.flip = flip self.client.claimed_folder = folder other_offset = 0 other_emote = '' other_flip = 0 other_folder = '' confirmed = False if charid_pair > -1: for target in self.client.area.clients: if not confirmed and target.char_id == self.client.charid_pair and target.charid_pair == self.client.char_id and target != self.client and target.pos == self.client.pos: confirmed = True other_offset = target.offset_pair other_emote = target.last_sprite other_flip = target.flip other_folder = target.claimed_folder if (pair_order != ""): charid_pair = "{}^{}".format(charid_pair, pair_order) break if not confirmed: charid_pair = -1 if self.client in self.client.area.afkers: self.client.server.client_manager.toggle_afk(self.client) self.client.area.send_command('MS', msg_type, pre, folder, anim, msg, pos, sfx, anim_type, cid, sfx_delay, button, self.client.evi_list[evidence], flip, ding, color, showname, charid_pair, other_folder, other_emote, offset_pair, other_offset, other_flip, nonint_pre, sfx_looping, screenshake, frames_shake, frames_realization, frames_sfx, additive, effect) self.client.area.send_owner_command( 'MS', msg_type, pre, folder, anim, '[' + self.client.area.abbreviation + ']' + msg, pos, sfx, anim_type, cid, sfx_delay, button, self.client.evi_list[evidence], flip, ding, color, showname, charid_pair, other_folder, other_emote, offset_pair, other_offset, other_flip, nonint_pre, sfx_looping, screenshake, frames_shake, frames_realization, frames_sfx, additive, effect) self.server.area_manager.send_remote_command( target_area, 'MS', msg_type, pre, folder, anim, msg, pos, sfx, anim_type, cid, sfx_delay, button, self.client.evi_list[evidence], flip, ding, color, showname, charid_pair, other_folder, other_emote, offset_pair, other_offset, other_flip, nonint_pre, sfx_looping, screenshake, frames_shake, frames_realization, frames_sfx, additive, effect) self.client.area.set_next_msg_delay(len(msg)) database.log_ic(self.client, self.client.area, showname, msg) if (self.client.area.is_recording): self.client.area.recorded_messages.append(args)
def net_cmd_ms(self, args): """IC message. Refer to the implementation for details. """ if not self.client.is_checked: return elif self.client.is_muted: # Checks to see if the client has been muted by a mod self.client.send_ooc('You are muted by a moderator.') return elif not self.client.area.can_send_message(self.client): return target_area = [] if self.validate_net_cmd(args, self.ArgType.STR, self.ArgType.STR_OR_EMPTY, self.ArgType.STR, self.ArgType.STR, self.ArgType.STR, self.ArgType.STR, self.ArgType.STR, self.ArgType.INT, self.ArgType.INT, self.ArgType.INT, self.ArgType.INT, self.ArgType.INT, self.ArgType.INT, self.ArgType.INT, self.ArgType.INT): # Pre-2.6 validation monstrosity. msg_type, pre, folder, anim, text, pos, sfx, anim_type, cid, sfx_delay, button, evidence, flip, ding, color = args showname = "" charid_pair = -1 offset_pair = 0 nonint_pre = 0 elif self.validate_net_cmd( args, self.ArgType.STR, self.ArgType.STR_OR_EMPTY, self.ArgType.STR, self.ArgType.STR, self.ArgType.STR, self.ArgType.STR, self.ArgType.STR, self.ArgType.INT, self.ArgType.INT, self.ArgType.INT, self.ArgType.INT, self.ArgType.INT, self.ArgType.INT, self.ArgType.INT, self.ArgType.INT, self.ArgType.STR_OR_EMPTY, self.ArgType.INT, self.ArgType.INT, self.ArgType.INT): # 2.6+ validation monstrosity. msg_type, pre, folder, anim, text, pos, sfx, anim_type, cid, sfx_delay, button, evidence, flip, ding, color, showname, charid_pair, offset_pair, nonint_pre = args if len(showname ) > 0 and not self.client.area.showname_changes_allowed: self.client.send_ooc( "Showname changes are forbidden in this area!") return else: return if self.client.area.is_iniswap(self.client, pre, anim, folder, sfx): self.client.send_ooc( "Iniswap/custom emotes are blocked in this area") return if len(self.client.charcurse) > 0 and \ folder != self.client.char_name: self.client.send_ooc( "You may not iniswap while you are charcursed!") return if not self.client.area.blankposting_allowed: if text == ' ': self.client.send_ooc("Blankposting is forbidden in this area!") return if text.isspace(): self.client.send_ooc( "Blankposting is forbidden in this area, and putting more spaces in does not make it not blankposting." ) return if len(re.sub(r'[{}\\`|(~~)]', '', text).replace( ' ', '')) < 3 and text != '<' and text != '>': self.client.send_ooc( "While that is not a blankpost, it is still pretty spammy. Try forming sentences." ) return if text.startswith('/a '): part = text.split(' ') try: aid = int(part[1]) area = self.server.area_manager.get_area_by_id(aid) if self.client in area.owners: target_area.append(aid) if not target_area: self.client.send_ooc(f'You don\'t own {area.name}!') return text = ' '.join(part[2:]) except ValueError: self.client.send_ooc( "That does not look like a valid area ID!") return elif text.startswith('/s '): part = text.split(' ') for a in self.server.area_manager.areas: if self.client in a.owners: target_area.append(a.id) if not target_area: self.client.send_ooc('You don\'t any areas!') return text = ' '.join(part[1:]) if msg_type not in ('chat', '0', '1'): return if anim_type not in (0, 1, 2, 5, 6): return if cid != self.client.char_id: return if sfx_delay < 0: return if button not in (0, 1, 2, 3, 4): return if evidence < 0: return if ding not in (0, 1): return if color not in (0, 1, 2, 3, 4, 5, 6, 7, 8): return if len(showname) > 15: self.client.send_ooc("Your IC showname is way too long!") return if nonint_pre == 1: if button in (1, 2, 3, 4, 23): if anim_type == 1 or anim_type == 2: anim_type = 0 elif anim_type == 6: anim_type = 5 if self.client.area.non_int_pres_only: if anim_type == 1 or anim_type == 2: anim_type = 0 nonint_pre = 1 elif anim_type == 6: anim_type = 5 nonint_pre = 1 if not self.client.area.shouts_allowed: # Old clients communicate the objecting in anim_type. if anim_type == 2: anim_type = 1 elif anim_type == 6: anim_type = 5 # New clients do it in a specific objection message area. button = 0 # Turn off the ding. ding = 0 if color == 2 and not (self.client.is_mod or self.client in self.client.area.owners): color = 0 if color == 6: text = re.sub(r'[^\x00-\x7F]+', ' ', text) # remove all unicode to prevent redtext abuse if len(text.strip(' ')) == 1: color = 0 else: if text.strip(' ') in ('<num>', '<percent>', '<dollar>', '<and>'): color = 0 if self.client.pos: pos = self.client.pos else: if pos not in ('def', 'pro', 'hld', 'hlp', 'jud', 'wit', 'jur', 'sea'): return msg = self.dezalgo(text)[:256] if self.client.shaken: msg = self.client.shake_message(msg) if self.client.disemvowel: msg = self.client.disemvowel_message(msg) self.client.pos = pos if evidence: if self.client.area.evi_list.evidences[ self.client.evi_list[evidence] - 1].pos != 'all': self.client.area.evi_list.evidences[ self.client.evi_list[evidence] - 1].pos = 'all' self.client.area.broadcast_evidence_list() # Here, we check the pair stuff, and save info about it to the client. # Notably, while we only get a charid_pair and an offset, we send back a chair_pair, an emote, a talker offset # and an other offset. self.client.charid_pair = charid_pair self.client.offset_pair = offset_pair if anim_type not in (5, 6): self.client.last_sprite = anim self.client.flip = flip self.client.claimed_folder = folder other_offset = 0 other_emote = '' other_flip = 0 other_folder = '' confirmed = False if charid_pair > -1: for target in self.client.area.clients: if target.char_id == self.client.charid_pair and target.charid_pair == self.client.char_id and target != self.client and target.pos == self.client.pos: confirmed = True other_offset = target.offset_pair other_emote = target.last_sprite other_flip = target.flip other_folder = target.claimed_folder break if not confirmed: charid_pair = -1 offset_pair = 0 self.client.area.send_command('MS', msg_type, pre, folder, anim, msg, pos, sfx, anim_type, cid, sfx_delay, button, self.client.evi_list[evidence], flip, ding, color, showname, charid_pair, other_folder, other_emote, offset_pair, other_offset, other_flip, nonint_pre) self.client.area.send_owner_command( 'MS', msg_type, pre, folder, anim, '[' + self.client.area.abbreviation + ']' + msg, pos, sfx, anim_type, cid, sfx_delay, button, self.client.evi_list[evidence], flip, ding, color, showname, charid_pair, other_folder, other_emote, offset_pair, other_offset, other_flip, nonint_pre) self.server.area_manager.send_remote_command( target_area, 'MS', msg_type, pre, folder, anim, msg, pos, sfx, anim_type, cid, sfx_delay, button, self.client.evi_list[evidence], flip, ding, color, showname, charid_pair, other_folder, other_emote, offset_pair, other_offset, other_flip, nonint_pre) self.client.area.set_next_msg_delay(len(msg)) database.log_ic(self.client, self.client.area, showname, msg) if (self.client.area.is_recording): self.client.area.recorded_messages.append(args)