示例#1
0
def sub_parser_add(sub_parser):
    add_parser = sub_parser.add_parser('add', help="Add event to calendar")
    add_parser.add_argument('-c', '--calendar', type=str, help="Calendar name")
    add_parser.add_argument('title', type=str, help="Event title")
    add_parser.add_argument('start_date',
                            type=valid_date,
                            help="Event start time, format: YYYY-MM-DD")
    add_parser.add_argument('start_time',
                            type=valid_time,
                            help="Event start time, format: HH:MM")
    add_parser.add_argument('-d',
                            '--duration',
                            type=int,
                            help="Event duration (minutes)")
    add_parser.add_argument('-a',
                            '--attendees',
                            type=valid_attendees,
                            help="List of emails of attendees",
                            required=False)
    add_parser.add_argument('-o',
                            '--override-color',
                            type=str,
                            choices=[c for c in sorted(COLORS.keys())],
                            help="List of emails of attendees",
                            default="")
def plot_totals(ts_dict):
    """
    Plot the total statistics (number of words, number of texts) per person.

    Args:
        ts_dict (dict): {"PersonName": TextSummary for that person}.

    Returns:
        None. Opens plot.

    """
    total_attrs = ['texts', 'words']
    titles = ['Texts', 'Words']
    number_of_plots = len(total_attrs)
    fig = make_subplots(rows=number_of_plots,
                        cols=1,
                        shared_xaxes=False,
                        subplot_titles=(titles))

    for index in range(number_of_plots):
        for sender in list(COLORS.keys()):
            fig.append_trace(
                go.Bar(x=[titles[index]],
                       y=[ts_dict[sender].count[total_attrs[index]]],
                       name=sender,
                       showlegend=True,
                       marker_color=COLORS[sender]), index + 1, 1)

    fig.update_layout(width=600, height=400 * number_of_plots, barmode='group')
    fig.update_yaxes(title_text='Total')

    plot(fig, auto_open=True, filename="Total Stats.html")
示例#3
0
    def prepare_summary(self, n_keywords: int = 4):
        """
        Now prepare data for summary page
        The output is [(topic_idx, [(word, weight, color_in_hex), ...]), ...]
        """

        # `temp_all_topic_word_weight_sent` = [(topic_idx, word, weight, sentiment), ...]
        temp_all_topic_word_weight_sent = []
        for topic in self.topic_words:
            temp_list = []
            for ww in topic[1]:
                if ww[0] in self.sent.keys():
                    temp_list.append(
                        (topic[0], ww[0], ww[1], self.sent[ww[0]]))
            temp_all_topic_word_weight_sent.extend(temp_list)
        # sort by sentiment
        temp_all_topic_word_weight_sent.sort(key=lambda x: x[3], reverse=True)

        # initialize topic_summary [(topic_idx, topic_sent_value, topic_keywords, [(word,weight,color_hex), ...]), ...]
        topic_summary = []
        for idx in range(self.n_topics):
            topic_summary.append([idx, None, None, []])

        for x in enumerate(temp_all_topic_word_weight_sent):
            color = list(COLORS.keys())[int(
                float(x[0]) / len(temp_all_topic_word_weight_sent) * 7.999)]
            topic_summary[x[1][0]][3].append((
                x[1][1],  # word
                np.float64(x[1][2]),  # weight
                color,  # sentiment color
            ))

        def get_topic_sent(t):
            d = {}
            for w in t:
                if w[2] in d.keys():
                    d[w[2]] += w[1]
                else:
                    d[w[2]] = w[1]
            return sorted(d.items(), key=lambda x: x[1], reverse=True)[0][0]

        for topic in topic_summary:
            # topic_sent_value color string
            topic[1] = get_topic_sent(topic[3])
            # topic_keywords
            topic[2] = [
                kw[0] for kw in sorted(
                    topic[3], key=lambda x: x[1], reverse=True)[:n_keywords]
            ]

        # Save the data
        self._dump_intermediate(f"{self.topic_summary_fname}.pkl",
                                topic_summary)
    x = [c['duration'].delta / 60e9 for c in convos]
    y = [c['total_words'] for c in convos]
    fig = go.Figure(data=go.Scatter(x=x, y=y, mode='markers'))
    fig.update_layout(title='Convo duration vs words',
                      xaxis_title="Duration (minutes)",
                      yaxis_title="Words",
                      yaxis_scaleanchor="x",
                      yaxis_scaleratio=1)
    fig.update_xaxes(type='log')
    fig.update_yaxes(type='log')
    plot(fig, auto_open=True, filename="Convo Duration vs Words.html")


if __name__ == "__main__":
    START_TIME = time.time()

    df = pd.read_csv(LOADPATH, index_col=False)
    df = convert_raw_csv_types(df)

    names = list(COLORS.keys())
    df_person_list = [df[df['sender'] == name] for name in names]
    summary_all = TextSummary(df)
    ts_dict = dict(
        zip(names, [TextSummary(df_person) for df_person in df_person_list]))
    plot_totals(ts_dict)
    conversations = summary_all.get_conversations(names)
    plot_convo_words(conversations, names)
    plot_convo_length(conversations)

    print("--- %s sec execution time ---" % (time.time() - START_TIME))
def make_scatter_plots(text_summary_by_person):
    """
    Create scatter plot of ratio of each person's usage of words

    Args:
        text_summary_by_person (dict): {"Person1": TextSummary for that person, etc.}.

    Returns:
        None. Opens plot.

    """

    MIN_WORD_OCCUR = 10  # minimum number of occurrences to be plotted
    MIN_EMOTE_OCCUR = 5

    names = list(COLORS.keys())

    diffs = dict()  # stores dictionaries with key word and value (total, ratio)

    # make dictionaries
    diffs['words'] = text_summary_by_person[0].compare_freq(text_summary_by_person[1], 'words')
    diffs['emotes'] = text_summary_by_person[0].compare_freq(text_summary_by_person[1], 'emotes')

    # strip less frequent tokens
    diffs['words'] = {key: value for (key, value) in diffs['words'].items() if
                      value[0] >= MIN_WORD_OCCUR}
    diffs['emotes'] = {key: value for (key, value) in diffs['emotes'].items() if
                       value[0] >= MIN_EMOTE_OCCUR}

    number_of_plots = 2
    titles = ['Words', 'Emotes']

    # initialize subplot figure
    fig = make_subplots(rows=number_of_plots, cols=1, shared_xaxes=True,
                        subplot_titles=(titles))

    subplot = 0
    for token_type, diff_dict in diffs.items():

        x, y, customdata = [], [], []
        for word, v in diff_dict.items():
            y.append(v[0])
            x.append(v[1])
            customdata.append([word, names[0], v[2], names[1], v[3]])

        fig.append_trace(go.Scatter(x=x,
                                    y=y,
                                    customdata=customdata,
                                    hovertemplate="<b>%{customdata[0]}</b><br>" +\
                                                  "Total: %{y} <br>Ratio: %{x:.2f}<br>" +\
                                                  "%{customdata[1]}: %{customdata[2]}<br>" +\
                                                  "%{customdata[3]}: %{customdata[4]}<extra></extra>",
                                    showlegend=False,
                                    mode='markers'),
                         subplot+1, 1)
        subplot += 1

    fig.update_layout(width=1200, height=600*number_of_plots)
    fig.update_xaxes(type='log', title_text=f'{names[0]}: {names[1]} ratio')
    fig.update_yaxes(type='log', title_text='Total')

    plot(fig, auto_open=True, filename="Word Ratio Scatterplot.html")
def convertitem(output, item):
	if item.amount == 0:
		return

	classname = 'cItem' # fixed for now
	name = item.name
	
	# Replace %[^%]%

	direction = 1
	tags = {}
	dispid = item.dispid
	events = []
	baseid = '%x' % item.dispid
	contserial = -1
	layer = 0
	itemtype = 0
	amount = item.amount
	hits = 0
	maxhits = 0
	magic = 0 # Gm movable
	owner = -1 # Normal
	visible = 0 # normally visible
	spawnregion = ''
	flags = 0
	buyprice = item.price
	sellprice = floor(item.price * 0.75)
	restock = item.amount # No shop items should be imported (RESTOCK: item.layer)

	if item.container:
		contserial = item.container.serial
		if contserial < 0x40000000:
			layer = item.layer

	# Delete restock information for unvended items.	
	if not item.container or (item.container.isitem() and (item.container.layer < 26 or item.container.layer > 28)):
		restock = 0
	else:
		# switch... restock is the amount we can sell while amount is the maximum amount.
		if item.pos[2] > 0:
			amount = item.pos[2]
		elif amount < 1:
			amount = 1

	# Locked Items
	if item.type == T_DOOR or item.type == T_DOOR_LOCKED or \
		item.type == T_CONTAINER or item.type == T_CONTAINER_LOCKED:
		if item.getproperty('MORE1'):
			events.append('lock')
			tags['lock'] = item.getproperty('MORE1')
			
	if item.type == T_DOOR_LOCKED or item.type == T_CONTAINER_LOCKED:
		tags['locked'] = 1

	# Doors
	if item.type in [T_DOOR_LOCKED, T_DOOR_OPEN, T_DOOR]:
		events.append('door')

	# Containers
	elif item.type in [T_CONTAINER, T_CONTAINER_LOCKED, T_EQ_BANK_BOX, T_EQ_VENDOR_BOX]:
		itemtype = 1

	# Rocks (Disregard i_worldgem_bit's with T_ROCK type)
	elif item.type == T_ROCK:
		if item.baseid == 'I_WORLDGEM_BIT':
			return

	# Mount Items
	elif item.type == T_EQ_HORSE:
		if not item.hasproperty('MORE2'):
			return
		tags['pet'] = item.hex2dec(item.getproperty('MORE2'))

	# Figurine Items (Stablemasters, Shrinked NPCs)
	elif item.type == T_FIGURINE:		
		if item.hasproperty('MORE2'):
			pet = findobject(item.hex2dec(item.getproperty('MORE2')))
			if pet and pet.saved:
				# "UPDATE" it
				# This is rather special but should work
				pass
				
			# Shrinked NPCs shouldn't be owned by anyone
			# Otherwise they count agains the follower limit
			elif pet:
				events.append('figurine')
				tags['pet'] = pet.serial
				pet.stablemaster = item.serial
				if item.link != 0:
					tags['player'] = item.link

	# Keys
	elif item.type == T_KEY:
		events.append('key')
		if name[:7] == 'Key to:':
			name = name[7:]

		if item.getproperty('MORE1'):
			tags['lock'] = item.getproperty('MORE1')

	# Light objects
	elif item.type in [T_LIGHT_LIT, T_LIGHT_OUT]:
		# Morez has the type
	
		events.append('lightsource')

	# Food
	elif item.type == T_FOOD:
		events.append('food')
		
	# Empty pitcher (fill with something?)
	elif item.type == T_PITCHER_EMPTY:
		pass
		
	# Drinks
	elif item.type == T_PITCHER:
		pass
		
	# Res Shrines (Walk On)
	elif item.type == T_SHRINE:
		itemtype = 16
		events.append('shrine')
		
 	# Convert Spellbook
	elif item.type == T_SPELLBOOK:
 		events.append('magic.spellbook')
 		spells1 = 0
 		spells2 = 0
 		if item.hasproperty('MORE1'):
 			spells1 = item.hex2dec(item.getproperty('MORE1'))
		if item.hasproperty('MORE2'):
 			spells2 = item.hex2dec(item.getproperty('MORE2'))
 		for circle in range(1, 5):
 			spells = (spells1 >> ((circle - 1) * 8)) & 0xFF
 			tags['circle%u' % circle] = spells

 		for circle in range(5, 9):
 			spells = (spells2 >> ((circle - 5) * 8)) & 0xFF
 			if spells != 0:
 				tags['circle%u' % circle] = spells

	# Convert Armors
	# Try to convert it to one of the "normal" ores/colors
	# Simply use the real displayid for getting the new color/resname/etc.
	elif item.type == T_ARMOR:
		dura = item.hex2dec(item.getproperty('MORE1', '0'))
		hits = dura & 0xFFFF
		maxhits = (dura >> 16) & 0xFFFF
		itemtype = 1009
		name = ''
		events.append('equipment')

		# Find a suitable color and resname here.
		if COLORS.has_key(item.color):
			info = COLORS[item.color]
			item.color = info[1]
			tags['resname'] = info[0]
		else:
			print "Unknown color %x for armor %x found. Converting to iron." % (item.serial,item.color)
			# Exceptional items are not convertable, crafted by will be discarded as well.
			tags['resname'] = 'iron'
			item.color = 0

		# Grant special effects based on the resname
		DURABONUS = {
			'dullcopper': 1.5,
			'shadowiron': 2.0,
			'valorite': 1.5
			}
			
		if DURABONUS.has_key(tags['resname']):
			bonus = DURABONUS[tags['resname']]
			if hits == maxhits:
				maxhits = int(ceil(maxhits * bonus))
				hits = maxhits
			else:
				maxhits = int(ceil(maxhits * bonus))
				hits = int(ceil(hits * bonus))

		# Dont forget the suitable strength requirement as well.
		# Use the default table here.
		pass

	#
	# There is only one type of leather yet.
	#
	elif item.type == T_ARMOR_LEATHER:
		item.name = ''
		item.color = 0
		tags['resname'] = 'leather'
		dura = item.hex2dec(item.getproperty('MORE1', '0'))
		hits = dura & 0xFFFF
		maxhits = (dura >> 16) & 0xFFFF
		itemtype = 1009
		events.append('equipment')

	# There is nothing we could do to convert these
	# at the moment. Maybe just skip?
	elif item.type in [T_WEAPON_MACE_SMITH, T_WEAPON_MACE_SHARP, T_WEAPON_SWORD, T_WEAPON_FENCE, T_WEAPON_BOW, T_WEAPON_MACE_STAFF, T_WEAPON_XBOW, T_WEAPON_AXE]:
		if item.type == T_WEAPON_MACE_SMITH:
			tags['remaining_uses'] = 50
			events.append('skills.blacksmithing')			
			
		# Translate types
		if item.type == T_WEAPON_MACE_SMITH:
			itemtype = 1004
		elif item.type == T_WEAPON_MACE_SHARP:
			itemtype = 1002 # Axe
			events.append('blades')
		elif item.type == T_WEAPON_AXE:
			itemtype = 1002 # Axe
			events.append('blades')
		elif item.type == T_WEAPON_MACE_STAFF:
			itemtype = 1003
		elif item.type == T_WEAPON_SWORD:
			itemtype = 1001
			events.append('blades')
		elif item.type == T_WEAPON_FENCE:
			itemtype = 1005
			events.append('blades')
		elif item.type == T_WEAPON_BOW:
			tags['range'] = 12
			itemtype = 1006
		elif item.type == T_WEAPON_XBOW:
			tags['range'] = 12
			itemtype = 1007
		events.append('equipment')
		
		# Convert durability
		dura = item.hex2dec(item.getproperty('MORE1', '0'))
		hits = dura & 0xFFFF
		maxhits = (dura >> 16) & 0xFFFF		

	# Simply do nothing for these types
	elif item.type in [T_DIRT, T_JEWELRY, T_LAVA, T_WINDOW, T_WALL]:
		pass

	# No support for wands in wolfpack yet.
	elif item.type == T_WAND:
		pass

	# Scissors
	elif item.type == T_SCISSORS:
		events.append('scissors')

	# Make sure resources will work in wolfpack
	elif item.type == T_LOG:
		name = ''
		baseid = '1bdd'
		dispid = 0x1bdd
		item.color = 0
		tags['resname'] = 'plainwood'
		
	elif item.type == T_BOARD:
		name = ''
		baseid = '1bd7'
		dispid = 0x1bd7
		item.color = 0
		tags['resname'] = 'plainwood'

	# Convert all types of hides to one type of hide
	elif item.type == T_HIDE:
		item.color = 0
		tags['resname'] = 'leather'
		name = ''
		baseid = 'leather_hides'
		
	# Convert all leather types to one leathertype
	elif item.type == T_LEATHER:
		item.color = 0
		tags['resname'] = 'leather'
		name = ''
		baseid = 'leather_cut'
		
	# Spawn Detected
	elif item.type == T_SPAWN_CHAR:
		if item.hasproperty('MORE1') and item.hasproperty('MOREP'):
			if item.hasproperty('MORE2'):
				more2 = item.hex2dec(item.getproperty('MORE2'))
			else:
				more2 = 0
			dispid = 0x1F13 # Worldgem Large
			item.color = 0
			npc = item.getproperty('MORE1').upper()
			props = map(int, item.getproperty('MOREP').split(','))
			if not NPCS.has_key(npc):
				if not npc in MISSINGNPCS:
					MISSINGNPCS.append(npc)
			else:
				tags['spawndef'] = NPCS[npc]
				tags['spawntype'] = 1
				tags['current'] = more2 # We only increase this number by npcs we find
				tags['mininterval'] = props[0]
				tags['maxinterval'] = props[1]
				if len(props) >= 3:
					tags['area'] = props[2]
				tags['maximum'] = amount
				events.append('spawngem')

		else:
			print "Broken NPC Spawn: 0%x" % item.serial
	
	# recall rune
	elif item.type == T_RUNE:
		events.append('magic.rune')
		if item.hasproperty('MOREP') and item.hasproperty('MORE1'):
			#tags['charges'] = item.hex2dec(item.getproperty('MORE1'))
			location = ['0', '0', '0', '1']
			morep = item.getproperty('MOREP').split(',')
			for i in range(0, len(morep)):
				location[i] = morep[i]
			tags['marked'] = 1
			tags['location'] = ','.join(location)			
			
		# Normalize name
		if name.startswith('Rune to:'):
			name = name[8:]
			
	# Keyrings
	elif item.type == T_KEYRING:
		events.append('keyring')
	
	elif item.type == T_ORE:
		# Resolve the correct wolfpack ore based on a 
		# sphere2wolfpack translation table (config)
		events.append('ore')
		dispid = 0x19b7 # We convert to one ore-id
		itemtype = 1102

		if not ORES.has_key(item.baseid):
			print "Unknown Ore: %s. Converting to iron." % item.baseid
			tags['resname'] = 'iron'
			item.color = 0 # Convert to the correct color
		else:
			ore = ORES[item.baseid]
			tags['resname'] = ore[0]
			item.color = ore[1]
			
	elif item.type == T_INGOT:
		# Resolve the correct wolfpack ore based on a 
		# sphere2wolfpack translation table (config)
		dispid = 0x1bf2
		events.append('ingot')
		
		if not INGOTS.has_key(item.baseid):
			print "Unknown Ingot: %s. Converting to iron." % item.baseid
			baseid = 'iron_ingot' # Convert to the correct baseid
			tags['resname'] = 'iron'
			item.color = 0 # Convert to the correct color
		else:
			ingot = INGOTS[item.baseid]
			tags['resname'] = ingot[0]
			baseid = tags['resname'] + '_ingot'
			item.color = ingot[1] # Convert to the correct color			
		
	# Teleporters	
	elif item.type == T_TELEPAD:
		# More 1: Players only
		# More 2: No noise
		# MoreP: Target
		if item.hasproperty('MOREP'):
			target = item.getproperty('MOREP').split(',')
			x = 0
			y = 0
			z = 0
			x = int(target[0])
			if len(target) >= 2:
				y = int(target[1])
			if len(target) >= 3:
				z = int(target[2])
			target = '%u,%u,%d,1' % (x, y, z)
			tags['target'] = target

		if item.hasproperty('MORE2'):
			prop = item.hex2dec(item.getproperty('MORE2'))
			if prop != 0:
				tags['silent'] = 1
				
		if item.hasproperty('MORE1'):
			prop = item.hex2dec(item.getproperty('MORE1'))
			if prop != 0:
				tags['playersonly'] = 1

		events.append('gate')

	# Carpentry Tools
	elif item.type == T_CARPENTRY:
		events.append('skills.carpentry')
		tags['remaining_uses'] = 50
		
	# Tailoring Tools
	elif item.type == T_SEWING_KIT:
		events.append('skills.tailoring')
		tags['remaining_uses'] = 50
		
	# Tinker Tools
	elif item.type == T_TINKER_TOOLS:
		events.append('skills.tinkering')
		tags['remaining_uses'] = 50

	# Convert book
	elif item.type == T_BOOK:
		events.append('book')

		if item.hasproperty('AUTHOR'):
			tags['author'] = item.getproperty('AUTHOR')

		# Process all pages (1-64)
		for i in range(0, 64):
			page = 'BODY.%u' % i
			if item.hasproperty(page):
				tags['page%u' % (i + 1)] = item.getproperty(page).replace("\t", "\n")

	# Raw Meat -> Cooking
	elif item.type == T_FOOD_RAW:
		events.append('cooking')

	# Bulletin Boards
	elif item.type == T_BBOARD:
		events.append('bulletinboard')

	# Dye Tub + Hairdye
	elif item.type in [T_DYE_VAT, T_HAIR_DYE]:
		events.append('environment')

	# Dyes
	elif item.type == T_DYE:
		events.append('dyes')
		tags['remaining_uses'] = 10

	# Bandages
	elif item.type == T_BANDAGE:
		events.append('bandages')

	# Musical Instrument
	elif item.type == T_MUSICAL:
		events.append('environment')

	# Training
	elif item.type == T_ARCHERY_BUTTE:
		events.append('archery_butte')

	elif item.type == T_TRAIN_DUMMY:
		events.append('training_dummy')
		
	else:
		if item.baseid == 'I_PFERDEPLATTE':
			events.append('ancientrealms.pferdeplatte')
			name = 'Pferdeplatte'
		else:	
			# Add a tag containing the original sphere 
			# information
			tags['sphere_conversion'] = 'Type: %u, Baseid: %s' % (item.type, item.baseid)

	# Process Attributes
	if item.attr & 0x0010: # Never movable
		magic = 2 # GM Movable
		
	# If not stated otherwise
	#if not item.attr & 0x4000:	
	#	if item.attr & (ATTR_MOVE_NEVER|ATTR_MOVE_ALWAYS|ATTR_OWNED|ATTR_INVIS|ATTR_STATIC):
	#		flags |= 0x01 # No Decay
	#	elif TILEINFO[item.dispid]['weight'] == 255:
	#		flags |= 0x01 # No Decay
	flags |= 0x01 # Everything is nodecay *whee*
			
	if item.dye:
		flags |= 0x80

	if item.attr & 0x0004: # Newbie
		flags |= 0x02 # Newbie

	if item.attr & 0x0080: # Invisible
		visible = 2

	# UObjectmap Entry
	sql = "INSERT INTO uobjectmap VALUES(%u, '%s');\n"
	output.write(sql % (item.serial, classname))

	# UObject entry
	sql = "INSERT INTO uobject VALUES('%s', %u, %d, %u, %d, %d, %d, %u, '%s', '%s', %u);\n"
	output.write(sql % (quote(name), item.serial, -1, direction, item.pos[0], item.pos[1], item.pos[2], item.pos[3], quote(','.join(events)), '', len(tags) != 0))

	# ITEM entry
	sql = "INSERT INTO items VALUES(%u, %u, %u, %d, %u, %u, %u, %u, %f, %u, %u, %u, %d, %u, '%s', %u, %u, %u, %u, '%s');\n"
	output.write(sql % (item.serial, dispid, item.color, contserial, layer, itemtype, amount, 0, item.weight, hits, maxhits, magic, \
		owner, visible, spawnregion, flags, sellprice, buyprice, restock, baseid))

	# Tags
	for (name, value) in tags.items():
		savetag(output, item.serial, name, value)
		
	# Export all subitems
	for cont in item.content:
		convertitem(output, cont)
示例#7
0
def convertitem(output, item):
    if item.amount == 0:
        return

    classname = 'cItem'  # fixed for now
    name = item.name

    # Replace %[^%]%

    direction = 1
    tags = {}
    dispid = item.dispid
    events = []
    baseid = '%x' % item.dispid
    contserial = -1
    layer = 0
    itemtype = 0
    amount = item.amount
    hits = 0
    maxhits = 0
    magic = 0  # Gm movable
    owner = -1  # Normal
    visible = 0  # normally visible
    spawnregion = ''
    flags = 0
    buyprice = item.price
    sellprice = floor(item.price * 0.75)
    restock = item.amount  # No shop items should be imported (RESTOCK: item.layer)

    if item.container:
        contserial = item.container.serial
        if contserial < 0x40000000:
            layer = item.layer

    # Delete restock information for unvended items.
    if not item.container or (item.container.isitem() and
                              (item.container.layer < 26
                               or item.container.layer > 28)):
        restock = 0
    else:
        # switch... restock is the amount we can sell while amount is the maximum amount.
        if item.pos[2] > 0:
            amount = item.pos[2]
        elif amount < 1:
            amount = 1

    # Locked Items
    if item.type == T_DOOR or item.type == T_DOOR_LOCKED or \
     item.type == T_CONTAINER or item.type == T_CONTAINER_LOCKED:
        if item.getproperty('MORE1'):
            events.append('lock')
            tags['lock'] = item.getproperty('MORE1')

    if item.type == T_DOOR_LOCKED or item.type == T_CONTAINER_LOCKED:
        tags['locked'] = 1

    # Doors
    if item.type in [T_DOOR_LOCKED, T_DOOR_OPEN, T_DOOR]:
        events.append('door')

    # Containers
    elif item.type in [
            T_CONTAINER, T_CONTAINER_LOCKED, T_EQ_BANK_BOX, T_EQ_VENDOR_BOX
    ]:
        itemtype = 1

    # Rocks (Disregard i_worldgem_bit's with T_ROCK type)
    elif item.type == T_ROCK:
        if item.baseid == 'I_WORLDGEM_BIT':
            return

    # Mount Items
    elif item.type == T_EQ_HORSE:
        if not item.hasproperty('MORE2'):
            return
        tags['pet'] = item.hex2dec(item.getproperty('MORE2'))

    # Figurine Items (Stablemasters, Shrinked NPCs)
    elif item.type == T_FIGURINE:
        if item.hasproperty('MORE2'):
            pet = findobject(item.hex2dec(item.getproperty('MORE2')))
            if pet and pet.saved:
                # "UPDATE" it
                # This is rather special but should work
                pass

            # Shrinked NPCs shouldn't be owned by anyone
            # Otherwise they count agains the follower limit
            elif pet:
                events.append('figurine')
                tags['pet'] = pet.serial
                pet.stablemaster = item.serial
                if item.link != 0:
                    tags['player'] = item.link

    # Keys
    elif item.type == T_KEY:
        events.append('key')
        if name[:7] == 'Key to:':
            name = name[7:]

        if item.getproperty('MORE1'):
            tags['lock'] = item.getproperty('MORE1')

    # Light objects
    elif item.type in [T_LIGHT_LIT, T_LIGHT_OUT]:
        # Morez has the type

        events.append('lightsource')

    # Food
    elif item.type == T_FOOD:
        events.append('food')

    # Empty pitcher (fill with something?)
    elif item.type == T_PITCHER_EMPTY:
        pass

    # Drinks
    elif item.type == T_PITCHER:
        pass

    # Res Shrines (Walk On)
    elif item.type == T_SHRINE:
        itemtype = 16
        events.append('shrine')

# Convert Spellbook
    elif item.type == T_SPELLBOOK:
        events.append('magic.spellbook')
        spells1 = 0
        spells2 = 0
        if item.hasproperty('MORE1'):
            spells1 = item.hex2dec(item.getproperty('MORE1'))
        if item.hasproperty('MORE2'):
            spells2 = item.hex2dec(item.getproperty('MORE2'))
        for circle in range(1, 5):
            spells = (spells1 >> ((circle - 1) * 8)) & 0xFF
            tags['circle%u' % circle] = spells

        for circle in range(5, 9):
            spells = (spells2 >> ((circle - 5) * 8)) & 0xFF
            if spells != 0:
                tags['circle%u' % circle] = spells

    # Convert Armors
    # Try to convert it to one of the "normal" ores/colors
    # Simply use the real displayid for getting the new color/resname/etc.
    elif item.type == T_ARMOR:
        dura = item.hex2dec(item.getproperty('MORE1', '0'))
        hits = dura & 0xFFFF
        maxhits = (dura >> 16) & 0xFFFF
        itemtype = 1009
        name = ''
        events.append('equipment')

        # Find a suitable color and resname here.
        if COLORS.has_key(item.color):
            info = COLORS[item.color]
            item.color = info[1]
            tags['resname'] = info[0]
        else:
            print "Unknown color %x for armor %x found. Converting to iron." % (
                item.serial, item.color)
            # Exceptional items are not convertable, crafted by will be discarded as well.
            tags['resname'] = 'iron'
            item.color = 0

        # Grant special effects based on the resname
        DURABONUS = {'dullcopper': 1.5, 'shadowiron': 2.0, 'valorite': 1.5}

        if DURABONUS.has_key(tags['resname']):
            bonus = DURABONUS[tags['resname']]
            if hits == maxhits:
                maxhits = int(ceil(maxhits * bonus))
                hits = maxhits
            else:
                maxhits = int(ceil(maxhits * bonus))
                hits = int(ceil(hits * bonus))

        # Dont forget the suitable strength requirement as well.
        # Use the default table here.
        pass

    #
    # There is only one type of leather yet.
    #
    elif item.type == T_ARMOR_LEATHER:
        item.name = ''
        item.color = 0
        tags['resname'] = 'leather'
        dura = item.hex2dec(item.getproperty('MORE1', '0'))
        hits = dura & 0xFFFF
        maxhits = (dura >> 16) & 0xFFFF
        itemtype = 1009
        events.append('equipment')

    # There is nothing we could do to convert these
    # at the moment. Maybe just skip?
    elif item.type in [
            T_WEAPON_MACE_SMITH, T_WEAPON_MACE_SHARP, T_WEAPON_SWORD,
            T_WEAPON_FENCE, T_WEAPON_BOW, T_WEAPON_MACE_STAFF, T_WEAPON_XBOW,
            T_WEAPON_AXE
    ]:
        if item.type == T_WEAPON_MACE_SMITH:
            tags['remaining_uses'] = 50
            events.append('skills.blacksmithing')

        # Translate types
        if item.type == T_WEAPON_MACE_SMITH:
            itemtype = 1004
        elif item.type == T_WEAPON_MACE_SHARP:
            itemtype = 1002  # Axe
            events.append('blades')
        elif item.type == T_WEAPON_AXE:
            itemtype = 1002  # Axe
            events.append('blades')
        elif item.type == T_WEAPON_MACE_STAFF:
            itemtype = 1003
        elif item.type == T_WEAPON_SWORD:
            itemtype = 1001
            events.append('blades')
        elif item.type == T_WEAPON_FENCE:
            itemtype = 1005
            events.append('blades')
        elif item.type == T_WEAPON_BOW:
            tags['range'] = 12
            itemtype = 1006
        elif item.type == T_WEAPON_XBOW:
            tags['range'] = 12
            itemtype = 1007
        events.append('equipment')

        # Convert durability
        dura = item.hex2dec(item.getproperty('MORE1', '0'))
        hits = dura & 0xFFFF
        maxhits = (dura >> 16) & 0xFFFF

    # Simply do nothing for these types
    elif item.type in [T_DIRT, T_JEWELRY, T_LAVA, T_WINDOW, T_WALL]:
        pass

    # No support for wands in wolfpack yet.
    elif item.type == T_WAND:
        pass

    # Scissors
    elif item.type == T_SCISSORS:
        events.append('scissors')

    # Make sure resources will work in wolfpack
    elif item.type == T_LOG:
        name = ''
        baseid = '1bdd'
        dispid = 0x1bdd
        item.color = 0
        tags['resname'] = 'plainwood'

    elif item.type == T_BOARD:
        name = ''
        baseid = '1bd7'
        dispid = 0x1bd7
        item.color = 0
        tags['resname'] = 'plainwood'

    # Convert all types of hides to one type of hide
    elif item.type == T_HIDE:
        item.color = 0
        tags['resname'] = 'leather'
        name = ''
        baseid = 'leather_hides'

    # Convert all leather types to one leathertype
    elif item.type == T_LEATHER:
        item.color = 0
        tags['resname'] = 'leather'
        name = ''
        baseid = 'leather_cut'

    # Spawn Detected
    elif item.type == T_SPAWN_CHAR:
        if item.hasproperty('MORE1') and item.hasproperty('MOREP'):
            if item.hasproperty('MORE2'):
                more2 = item.hex2dec(item.getproperty('MORE2'))
            else:
                more2 = 0
            dispid = 0x1F13  # Worldgem Large
            item.color = 0
            npc = item.getproperty('MORE1').upper()
            props = map(int, item.getproperty('MOREP').split(','))
            if not NPCS.has_key(npc):
                if not npc in MISSINGNPCS:
                    MISSINGNPCS.append(npc)
            else:
                tags['spawndef'] = NPCS[npc]
                tags['spawntype'] = 1
                tags[
                    'current'] = more2  # We only increase this number by npcs we find
                tags['mininterval'] = props[0]
                tags['maxinterval'] = props[1]
                if len(props) >= 3:
                    tags['area'] = props[2]
                tags['maximum'] = amount
                events.append('spawngem')

        else:
            print "Broken NPC Spawn: 0%x" % item.serial

    # recall rune
    elif item.type == T_RUNE:
        events.append('magic.rune')
        if item.hasproperty('MOREP') and item.hasproperty('MORE1'):
            #tags['charges'] = item.hex2dec(item.getproperty('MORE1'))
            location = ['0', '0', '0', '1']
            morep = item.getproperty('MOREP').split(',')
            for i in range(0, len(morep)):
                location[i] = morep[i]
            tags['marked'] = 1
            tags['location'] = ','.join(location)

        # Normalize name
        if name.startswith('Rune to:'):
            name = name[8:]

    # Keyrings
    elif item.type == T_KEYRING:
        events.append('keyring')

    elif item.type == T_ORE:
        # Resolve the correct wolfpack ore based on a
        # sphere2wolfpack translation table (config)
        events.append('ore')
        dispid = 0x19b7  # We convert to one ore-id
        itemtype = 1102

        if not ORES.has_key(item.baseid):
            print "Unknown Ore: %s. Converting to iron." % item.baseid
            tags['resname'] = 'iron'
            item.color = 0  # Convert to the correct color
        else:
            ore = ORES[item.baseid]
            tags['resname'] = ore[0]
            item.color = ore[1]

    elif item.type == T_INGOT:
        # Resolve the correct wolfpack ore based on a
        # sphere2wolfpack translation table (config)
        dispid = 0x1bf2
        events.append('ingot')

        if not INGOTS.has_key(item.baseid):
            print "Unknown Ingot: %s. Converting to iron." % item.baseid
            baseid = 'iron_ingot'  # Convert to the correct baseid
            tags['resname'] = 'iron'
            item.color = 0  # Convert to the correct color
        else:
            ingot = INGOTS[item.baseid]
            tags['resname'] = ingot[0]
            baseid = tags['resname'] + '_ingot'
            item.color = ingot[1]  # Convert to the correct color

    # Teleporters
    elif item.type == T_TELEPAD:
        # More 1: Players only
        # More 2: No noise
        # MoreP: Target
        if item.hasproperty('MOREP'):
            target = item.getproperty('MOREP').split(',')
            x = 0
            y = 0
            z = 0
            x = int(target[0])
            if len(target) >= 2:
                y = int(target[1])
            if len(target) >= 3:
                z = int(target[2])
            target = '%u,%u,%d,1' % (x, y, z)
            tags['target'] = target

        if item.hasproperty('MORE2'):
            prop = item.hex2dec(item.getproperty('MORE2'))
            if prop != 0:
                tags['silent'] = 1

        if item.hasproperty('MORE1'):
            prop = item.hex2dec(item.getproperty('MORE1'))
            if prop != 0:
                tags['playersonly'] = 1

        events.append('gate')

    # Carpentry Tools
    elif item.type == T_CARPENTRY:
        events.append('skills.carpentry')
        tags['remaining_uses'] = 50

    # Tailoring Tools
    elif item.type == T_SEWING_KIT:
        events.append('skills.tailoring')
        tags['remaining_uses'] = 50

    # Tinker Tools
    elif item.type == T_TINKER_TOOLS:
        events.append('skills.tinkering')
        tags['remaining_uses'] = 50

    # Convert book
    elif item.type == T_BOOK:
        events.append('book')

        if item.hasproperty('AUTHOR'):
            tags['author'] = item.getproperty('AUTHOR')

        # Process all pages (1-64)
        for i in range(0, 64):
            page = 'BODY.%u' % i
            if item.hasproperty(page):
                tags['page%u' % (i + 1)] = item.getproperty(page).replace(
                    "\t", "\n")

    # Raw Meat -> Cooking
    elif item.type == T_FOOD_RAW:
        events.append('cooking')

    # Bulletin Boards
    elif item.type == T_BBOARD:
        events.append('bulletinboard')

    # Dye Tub + Hairdye
    elif item.type in [T_DYE_VAT, T_HAIR_DYE]:
        events.append('environment')

    # Dyes
    elif item.type == T_DYE:
        events.append('dyes')
        tags['remaining_uses'] = 10

    # Bandages
    elif item.type == T_BANDAGE:
        events.append('bandages')

    # Musical Instrument
    elif item.type == T_MUSICAL:
        events.append('environment')

    # Training
    elif item.type == T_ARCHERY_BUTTE:
        events.append('archery_butte')

    elif item.type == T_TRAIN_DUMMY:
        events.append('training_dummy')

    else:
        if item.baseid == 'I_PFERDEPLATTE':
            events.append('ancientrealms.pferdeplatte')
            name = 'Pferdeplatte'
        else:
            # Add a tag containing the original sphere
            # information
            tags['sphere_conversion'] = 'Type: %u, Baseid: %s' % (item.type,
                                                                  item.baseid)

    # Process Attributes
    if item.attr & 0x0010:  # Never movable
        magic = 2  # GM Movable

    # If not stated otherwise
    #if not item.attr & 0x4000:
    #	if item.attr & (ATTR_MOVE_NEVER|ATTR_MOVE_ALWAYS|ATTR_OWNED|ATTR_INVIS|ATTR_STATIC):
    #		flags |= 0x01 # No Decay
    #	elif TILEINFO[item.dispid]['weight'] == 255:
    #		flags |= 0x01 # No Decay
    flags |= 0x01  # Everything is nodecay *whee*

    if item.dye:
        flags |= 0x80

    if item.attr & 0x0004:  # Newbie
        flags |= 0x02  # Newbie

    if item.attr & 0x0080:  # Invisible
        visible = 2

    # UObjectmap Entry
    sql = "INSERT INTO uobjectmap VALUES(%u, '%s');\n"
    output.write(sql % (item.serial, classname))

    # UObject entry
    sql = "INSERT INTO uobject VALUES('%s', %u, %d, %u, %d, %d, %d, %u, '%s', '%s', %u);\n"
    output.write(sql % (quote(name), item.serial, -1, direction, item.pos[0],
                        item.pos[1], item.pos[2], item.pos[3],
                        quote(','.join(events)), '', len(tags) != 0))

    # ITEM entry
    sql = "INSERT INTO items VALUES(%u, %u, %u, %d, %u, %u, %u, %u, %f, %u, %u, %u, %d, %u, '%s', %u, %u, %u, %u, '%s');\n"
    output.write(sql % (item.serial, dispid, item.color, contserial, layer, itemtype, amount, 0, item.weight, hits, maxhits, magic, \
     owner, visible, spawnregion, flags, sellprice, buyprice, restock, baseid))

    # Tags
    for (name, value) in tags.items():
        savetag(output, item.serial, name, value)

    # Export all subitems
    for cont in item.content:
        convertitem(output, cont)