from toee import *

from Co8 import *

##  Writen By Cerulean the Blue


def OnBeginSpellCast( spell ):
	print " Extraplanar Chest OnBeginSpellCast"
	print "spell.target_list=", spell.target_list
	print "spell.caster=", spell.caster, " caster.level= ", spell.caster_level
	game.particles( "sp-conjuration-conjure", spell.caster )

def	OnSpellEffect ( spell ):
	print " Extraplanar Chest OnSpellEffect"
	spell.duration = 1
	bgfilename = 'Bag_of_Holding.mes' 
	proto = 1100
	
	mini = spell.caster.item_find(12105)
	
	if mini == OBJ_HANDLE_NULL:	# Caster hasn't used spell before.  Create miniature chest and subtract 5050 gold from caster
		if spell.caster.money_get() >= 505000:
			mini = create_item_in_inventory( 12105, spell.caster )
			set_flag(mini, 0) # sets flag for chest on the Prime Material Plane
			mini.item_flag_set( OIF_IDENTIFIED ) # Makes the mini identified.
			spell.caster.money_adj(-505000)
			chest = game.obj_create(proto, spell.caster.location)
			create_item_in_inventory(11300, chest) # Create Leomund's Secret Chest note in new chest
			game.particles( 'Orb-Summon-Balor', chest )
			bagnum = boh_newbag() # boh-newbag() is in Co8.py
			Set_ID(mini, chest, bagnum)
		else:
			game.particles( 'Fizzle', spell.caster )
		
	elif (Get_ID_Mini(mini) == 0): # Miniature found but never used before
		set_flag(mini, 0) # sets flag for chest on the Prime Material Plane
		bagnum = boh_newbag() # boh-newbag() is in Co8.py
		chest = game.obj_create(proto, spell.caster.location)
		create_item_in_inventory(11300, chest) # Create Leomund's Secret Chest note in new chest
		game.particles( 'Orb-Summon-Balor', chest )
		Set_ID(mini, chest, bagnum)
		
	else:
		# Mini found and has been used before.
		chest_here = 0  # flag for whether or not the right chest is in the casters vicinity
		for chest in game.obj_list_vicinity( spell.caster.location, OLC_CONTAINER ):
			# Find correct chest for that mini
			if (chest.name == 1100 and Compare_ID(mini, chest)):
				chest_here = 1
				game.particles( 'Orb-Summon-Balor', chest )
				allBagDict = readMes(bgfilename) # readMes is in Co8.py.
				bagnum = boh_newbag() # boh-newbag() is in Co8.py
				Set_ID_Mini(mini, bagnum)
				contents = GetContents(chest)
				allBagDict[bagnum] = contents
				writeMes(bgfilename, allBagDict) # writeMes is in Co8.py
				set_flag(mini, 1)  # Sets fkag flag for chest on Ethereal Plane
				
				# Time event added for chest destruction to allow time for game particles to fire
				Timed_Destroy(chest, 500) # 500 = 1/2 second
			
		if ( not (chest_here) and get_flag(mini) ): # Chest not on this plane:  create chest and fill it.
			chest = game.obj_create(proto, spell.caster.location)
			bagnum = Get_ID_Mini(mini)
			Set_ID(mini, chest, bagnum)
			set_flag(mini, 0) # sets flag for chest on the Prime Material Plane
			game.particles( 'Orb-Summon-Balor', chest )
			contents = boh_getContents(bagnum) # boh_getContents is in Co8.py
			Create_Contents(contents, chest)
			
		else:
			game.particles( 'Fizzle', spell.caster )
		
	End_Spell(spell)
		
	spell.spell_end(spell.id)

def OnBeginRound( spell ):
	print " Extraplanar Chest OnBeginRound"
	return

def OnEndSpellCast( spell ):
	print " Extraplanar Chest OnEndSpellCast"


	
def GetContents(chest):
	# Gets contents of the chest by proto number and adds them to an ordered list.  The list format is dynamic.
	# Reads Exclude_List.mes.  Items in the exclude list are not preserved in the contents of the chest.
	# This is to prevent charged magic items from being recharged by being in the chest.  Such items are lost if sent to the Ethereal Plane in the chest.
	#  Exclued list is not decoded because we only care about the dictionary keys (proto numbers).  There is no need to decode the descriptions in the dictionary entries.
	ExcludeDict = readMes('Exclude_List.mes')
	exclude_list = ExcludeDict.keys()
	contents = []
	# Look for proto number 4000-12999.  These are the proto numbers for items that could be in the chest.
	num = 4000 
	while num <= 12999 :
		# Check if proto number is on the exclude list
		if num not in exclude_list:
			item = chest.item_find_by_proto(num)
			# Loop finding item to check for multiple occurences of the same item
			while (item != OBJ_HANDLE_NULL):
				# add the item to the list of contents
				contents.append(num)
				# check if item is stackable, and if so get the quantity stacked
				quantity = 0
				type = item.type
				if (type == obj_t_ammo):
					quantity = item.obj_get_int(obj_f_ammo_quantity)
				else:
					quantity = item.obj_get_int(obj_f_item_quantity)
				# if there is more than one in the stack, add the quantity to the contents list.  Max quantity 3999 to keep quantity from matching any proto number in the list.
				if ( quantity > 1 ):
					if quantity >= 4000:
						quantity = 3999
					contents.append(quantity)
				# check to see if item is identified.  If so, add the identified flag 1 to the list.
				FLAGS = item.item_flags_get()
				if (FLAGS & OIF_IDENTIFIED):
					contents.append(1)
				# destroy the item and check if there is another with the same proto number
				item.destroy()
				item = chest.item_find_by_proto(num)
		num += 1
	# add "end of list" number to the end of the list.
	contents.append(99999)
	return contents

def Create_Contents(contents, chest):
	# Recreates the contents of the chest from the ordered list.
	# Uses a "while" statement rather than a "for" statement in order to be able to step through the dynamic list.
	i = 0
	while i in range(len(contents)):
		# check to make sure we are looking at a proto number and not a quantity, identified flag, or end of list marker.
		if (contents[i] >= 4000 and contents[i] != 99999):
			#create item in chest
			item = create_item_in_inventory( contents[i], chest )
			# step to the next number on the list
			i += 1
			if i in range(len(contents)): # probably not necessary here, but keeps us safe.
				# check to see if next number on the list is a quantity or identified flag
				if contents[i] < 4000:
					quantity = contents[i]
					# check if item is ammo
					if item.type == obj_t_ammo:
						# check if "quantity" is actually a quantity and not an identified flag
						if quantity > 1:
							# "quantity" is a quantity,  Set item quantity and step to next number on the list
							item.obj_set_int(obj_f_ammo_quantity, quantity)
							i += 1
						else:
							# "quantity" is an identified flag.  Set item quantity to 1.
							item.obj_set_int(obj_f_ammo_quantity, 1)
					# check if item is a potion, scroll or other stackable item.
					else:
						# check if "quantity" is actually a quantity and not an identified flag
						if quantity > 1:
							# "quantity" is a quantity,  Set item quantity and step to next number on the list
							item.obj_set_int(obj_f_item_quantity, quantity)
							i += 1
						else:
							# "quantity" is an identified flag.  Set item quantity to 1.
							item.obj_set_int(obj_f_item_quantity, 1)
			if i in range(len(contents)): # is necessary here
				# check if contents[i] is an identified flag.
				if contents[i] == 1:
					# flag item as identified and step to next number on the list.
					item.item_flag_set( OIF_IDENTIFIED )
					i += 1
		else:
			i += 1
	return

def Set_ID(mini, chest, num): # Generates a random number and sets a field in the item, chest and caster to that number.
	# ID_number = game.random_range( 1,2147483647 )
	# ID_number = ID_number^game.random_range( 1,2147483647 )#xor with next "random" number in line, should be more random
	mini.obj_set_int(obj_f_item_pad_i_2, num)
	chest.obj_set_int(obj_f_container_pad_i_1, num)
	return num

def Set_ID_Mini(mini, num):
	mini.obj_set_int(obj_f_item_pad_i_2, num)
	return mini.obj_get_int(obj_f_item_pad_i_2)

def Get_ID_Mini(mini): # Reads the ID number of the miniature chest.
	return mini.obj_get_int(obj_f_item_pad_i_2)

def Compare_ID(mini, chest): # Compares the ID number of the large chest and the miniature chest.  Returns 1 if they match, otherwise returns o.
	if (mini.obj_get_int(obj_f_item_pad_i_2) == chest.obj_get_int(obj_f_container_pad_i_1)):
		return 1
	else:
		return 0

def set_flag(mini, x): # Store a flag in a field of the miniature chest.  1 means on the Ethereal Plane, 0 means on the Prime Material Plane.
	mini.obj_set_int( obj_f_item_pad_i_3, x )
	return mini.obj_get_int( obj_f_item_pad_i_3 )

def get_flag(mini): # Reads a flag from a field of the miniature chest.
	return mini.obj_get_int( obj_f_item_pad_i_3 )





