evennia/src/commands/search.py

235 lines
No EOL
9.6 KiB
Python

"""
Implementation of the @search command that resembles MUX2.
"""
from django.db.models import Q
from src.objects.models import Object
from src import defines_global
from src.cmdtable import GLOBAL_CMD_TABLE
def _parse_restriction_split(source_object, restriction_split, search_low_dbnum,
search_high_dbnum):
"""
Parses a split restriction string and sets some needed variables.
Returns a tuple in the form of: (low dbnum, high dbnum)
"""
restriction_size = len(restriction_split)
if restriction_size >= 2:
try:
search_low_dbnum = int(restriction_split[1].strip())
except ValueError:
source_object.emit_to("Invalid value for low dbref limit.")
return False
if restriction_size >= 3:
try:
search_high_dbnum = int(restriction_split[2].strip())
except ValueError:
source_object.emit_to("Invalid value for high dbref limit.")
return False
return search_low_dbnum, search_high_dbnum
def display_results(source_object, search_query):
"""
Display the results to the searcher.
"""
# Lists to hold results by type. There may be a better way to do this
thing_list = []
room_list = []
exit_list = []
player_list = []
for obj in search_query:
if obj.is_thing():
thing_list.append(obj)
elif obj.is_room():
room_list.append(obj)
elif obj.is_exit():
exit_list.append(obj)
elif obj.is_player():
player_list.append(obj)
# Render each section for different object types
if thing_list:
source_object.emit_to("\n\rTHINGS:")
for thing in thing_list:
source_object.emit_to(thing.get_name(show_dbref=True, show_flags=True))
if exit_list:
source_object.emit_to("\n\rEXITS:")
for exit in exit_list:
source_object.emit_to(exit.get_name(show_dbref=True, show_flags=True))
if room_list:
source_object.emit_to("\n\rROOMS:")
for room in room_list:
source_object.emit_to(room.get_name(show_dbref=True, show_flags=True))
if player_list:
source_object.emit_to("\n\rPLAYER:")
for player in player_list:
source_object.emit_to(player.get_name(show_dbref=True, show_flags=True))
# Show the total counts by type
source_object.emit_to("\n\rFound: Rooms...%d Exits...%d Things...%d Players...%d" % (
len(room_list),
len(exit_list),
len(thing_list),
len(player_list)))
def build_query(source_object, search_query, search_player, search_type,
search_restriction, search_low_dbnum, search_high_dbnum):
"""
Builds and returns a QuerySet object, or None if an error occurs.
"""
# Look up an Object matching the player search query
if search_player:
# Replace the string variable with an Object reference
search_player = source_object.search_for_object(search_player)
# Use standard_objsearch to handle duplicate/nonexistant results
if not search_player:
return None
# Searching by player, chain filter
search_query = search_query.filter(owner=search_player)
# Check to ensure valid search types
if search_type == "type":
if search_restriction == "room":
search_query = search_query.filter(type=defines_global.OTYPE_ROOM)
elif search_restriction == "thing":
search_query = search_query.filter(type=defines_global.OTYPE_THING)
elif search_restriction == "exit":
search_query = search_query.filter(type=defines_global.OTYPE_EXIT)
elif search_restriction == "player":
search_query = search_query.filter(type=defines_global.OTYPE_PLAYER)
else:
source_object.emit_to("Invalid class. See 'help SEARCH CLASSES'.")
return None
elif search_type == "parent":
search_query = search_query.filter(script_parent__iexact=search_restriction)
elif search_type == "object" or search_type == "thing":
search_query = search_query.filter(name__icontains=search_restriction,
type=defines_global.OTYPE_THING)
elif search_type == "rooms":
search_query = search_query.filter(name__icontains=search_restriction,
type=defines_global.OTYPE_ROOM)
elif search_type == "exits":
search_query = search_query.filter(name__icontains=search_restriction,
type=defines_global.OTYPE_EXIT)
elif search_type == "players":
search_query = search_query.filter(name__icontains=search_restriction,
type=defines_global.OTYPE_PLAYER)
elif search_type == "zone":
zone_obj = source_object.search_for_object(search_restriction)
# Use search_for_object to handle duplicate/nonexistant results.
if not zone_obj:
return None
search_query = search_query.filter(zone=zone_obj)
elif search_type == "power":
# TODO: Need this once we have powers implemented.
source_object.emit_to("To be implemented...")
return None
elif search_type == "flags":
flag_list = search_restriction.split()
#source_object.emit_to("restriction: %s" % flag_list)
for flag in flag_list:
search_query = search_query.filter(Q(flags__icontains=flag) | Q(nosave_flags__icontains=flag))
if search_low_dbnum:
search_query = search_query.filter(id__gte=search_low_dbnum)
if search_high_dbnum:
search_query = search_query.filter(id__lte=search_high_dbnum)
return search_query
def cmd_search(command):
"""
Searches for owned objects as per MUX2.
"""
source_object = command.source_object
search_player = None
search_type = None
search_restriction = None
search_low_dbnum = None
search_high_dbnum = None
if not command.command_argument:
search_player = "#" + str(source_object.id)
else:
first_check_split = command.command_argument.split(' ', 1)
if '=' in first_check_split[0]:
# @search class=restriction...
eq_split = command.command_argument.split('=', 1)
search_type = eq_split[0]
restriction_split = eq_split[1].split(',')
search_restriction = restriction_split[0].strip()
#source_object.emit_to("@search class=restriction")
#source_object.emit_to("eq_split: %s" % eq_split)
#source_object.emit_to("restriction_split: %s" % restriction_split)
try:
search_low_dbnum, search_high_dbnum = _parse_restriction_split(source_object,
restriction_split,
search_low_dbnum,
search_high_dbnum)
except TypeError:
return
else:
# @search player
if len(first_check_split) == 1:
#source_object.emit_to("@search player")
#source_object.emit_to(first_check_split)
search_player = first_check_split[0]
else:
#source_object.emit_to("@search player class=restriction")
#source_object.emit_to(first_check_split)
search_player = first_check_split[0]
eq_split = first_check_split[1].split('=', 1)
search_type = eq_split[0]
#source_object.emit_to("eq_split: %s" % eq_split)
restriction_split = eq_split[1].split(',')
search_restriction = restriction_split[0]
#source_object.emit_to("restriction_split: %s" % restriction_split)
try:
search_low_dbnum, search_high_dbnum = _parse_restriction_split(source_object,
restriction_split,
search_low_dbnum,
search_high_dbnum)
except TypeError:
return
search_query = Object.objects.all()
#source_object.emit_to("search_player: %s" % search_player)
#source_object.emit_to("search_type: %s" % search_type)
#source_object.emit_to("search_restriction: %s" % search_restriction)
#source_object.emit_to("search_lowdb: %s" % search_low_dbnum)
#source_object.emit_to("search_highdb: %s" % search_high_dbnum)
# Clean up these variables for comparisons.
try:
search_type = search_type.strip().lower()
except AttributeError:
pass
try:
search_restriction = search_restriction.strip().lower()
except AttributeError:
pass
# Build the search query.
search_query = build_query(source_object, search_query, search_player, search_type,
search_restriction, search_low_dbnum,
search_high_dbnum)
# Something bad happened in query construction, die here.
if search_query is None:
return
display_results(source_object, search_query)
GLOBAL_CMD_TABLE.add_command("@search", cmd_search,
priv_tuple=("genperms.builder")),