Beispiel #1
0
    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."
                )
Beispiel #2
0
	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)
Beispiel #3
0
    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)