text: from globals import *
  
  import life as lfe
  
  import language
  import missions
  import bad_numbers
  import weapons
  import spawns
  import alife
  import items
  
  import logging
  import random
  
  
  def generate():
  	create_territories()
  	create_faction('Dawn', ['dawn_scout', 'dawn_sentry'], enemies=['Bandits', 'Runners', 'Military'])
  	create_faction('Runners', ['loner', 'loner_rifleman'], enemies=['Bandits', 'Dawn', 'Military'])
  	create_faction('Loners', ['loner', 'loner_rifleman'], enemies=['Bandits', 'Military'])
  	create_faction('ZES', ['zes_guard'], enemies=['Bandits', 'Military'])
  	create_faction('Military', ['bandit'], enemies=['Runners', 'Dawn', 'Loners'])
  	create_faction('Bandits', ['bandit'], enemies=['Runners', 'Dawn', 'Loners', 'Military'])
  	create_faction('Dogs', ['bandit'], enemies=['Runners', 'Dawn', 'Loners', 'Military'])
  	create_zes_export()
  	create_fields()
  	create_outposts()
  
  def create_territories():
  	for town in WORLD_INFO['refs']['towns']:
  		_place_name = language.generate_place_name()
  		
  		WORLD_INFO['territories'][_place_name] = {'chunk_keys': town,
  		                                          'owner': None,
  		                                          'danger': False,
  		                                          'flags': {}}
  		
  		logging.debug('Created territory: %s' % _place_name)
  
  def get_territory(territory_name):
  	return WORLD_INFO['territories'][territory_name]
  
  def claim_territory(faction_name):
  	_territory_name = random.choice([t for t in WORLD_INFO['territories'] if not WORLD_INFO['territories'][t]['owner']])
  	_territory = get_territory(_territory_name)
  	_territory['owner'] = faction_name
  	_territory['groups'] = []
  	_faction = get_faction(faction_name)
  	_faction['territories'][_territory_name] = {'groups': []}
  	
  	logging.debug('%s has claimed %s.' % (faction_name, _territory_name))
  	
  	return _territory
  
  def claim_existing_territory(faction_name, territory_id):
  	_territory = WORLD_INFO['territories'][territory_id]
  	_territory['owner'] = faction_name
  	_territory['groups'] = []
  	_faction['territories'][_territory_name] = {'groups': []}
  	
  	logging.debug('%s has claimed %s.' % (faction_name, _territory_name))
  
  def create_faction(name, life_types, friendlies=[], enemies=['Bandits']):
  	WORLD_INFO['factions'][name] = {'members': [],
  	                                'groups': [],
  	                                'group_orders': {},
  	                                'territories': {},
  	                                'friendlies': friendlies,
  	                                'enemies': enemies,
  	                                'life_types': life_types,
  	                                'flags': {}}
  	
  	logging.debug('Created faction: %s' % name)
  
  def get_faction(faction_name):
  	return WORLD_INFO['factions'][faction_name]
  
  def get_faction_enemies(faction_name):
  	return get_faction(faction_name)['enemies']
  
  def is_enemy(life, life_id):
  	if not life['faction'] or not LIFE[life_id]['faction']:
  		return False
  	
  	_faction = get_faction(life['faction'])
  	_target_faction_name = LIFE[life_id]['faction']
  	
  	return _target_faction_name in _faction['enemies']
  
  def is_faction_enemy(life, faction_name):
  	if not life['faction']:
  		return False
  	
  	_faction = get_faction(life['faction'])
  	
  	return faction_name in _faction['enemies']
  
  def add_member(faction_name, life_id):
  	_faction = get_faction(faction_name)
  	
  	if life_id in _faction['members']:
  		return False
  	
  	_faction['members'].append(life_id)
  	
  	LIFE[life_id]['faction'] = faction_name
  
  def add_group(faction_name, group_id):
  	for life_id in alife.groups.get_group({}, group_id)['members']:
  		add_member(faction_name, life_id)
  	
  	_faction = get_faction(faction_name)
  	_faction['groups'].append(group_id)
  	
  	for territory_name in _faction['territories']:
  		_territory = _faction['territories'][territory_name]
  		
  		if not _territory['groups']:
  			patrol_territory(faction_name, group_id, territory_name)
  			
  			break
  
  def get_group_order(faction_name, group_id):
  	_faction = get_faction(faction_name)
  	
  	if group_id in _faction['group_orders']:
  		return _faction['group_orders'][group_id]
  	
  	return None
  
  def set_group_order(faction_name, group_id, order):
  	_faction = get_faction(faction_name)
  	_faction['group_orders'][group_id] = {'order': order,
  	                                      'flags': {}}
  
  def clear_group_order(faction_name, group_id):
  	_faction = get_faction(faction_name)
  	
  	del _faction['group_orders'][group_id]
  
  def get_free_groups(faction_name):
  	_faction = get_faction(faction_name)
  	
  	return list(set(_faction['groups']) - set(_faction['group_orders']))
  
  def get_nearest_group(faction_name, pos, free_only=True, max_distance=250):
  	_faction = get_faction(faction_name)
  	_nearest_group = {'group_id': None, 'distance': max_distance}
  	
  	for group_id in _faction['groups']:
  		if free_only and group_id in _faction['group_orders']:
  			continue
  		
  		for member_id in alife.groups.get_group({}, group_id)['members']:
  			_distance = bad_numbers.distance(LIFE[member_id]['pos'], pos)
  			
  			if _distance < _nearest_group['distance']:
  				_nearest_group['group_id'] = group_id
  				_nearest_group['distance'] = _distance
  	
  	return _nearest_group['group_id']
  
  def patrol_territory(faction_name, group_id, territory_name):
  	_faction = get_faction(faction_name)
  	_territory = _faction['territories'][territory_name]
  	_territory['groups'].append(group_id)
  	
  	#alife.groups.focus_on
  
  def capture_territory(faction_name, group_id):
  	if faction_name == 'ZES':
  		return False
  	
  	_closest_territory = {'distance': 0, 'chunk_key': None, 'territory_id': None}
  	_group_center = None
  	
  	for member_id in alife.groups.get_group({}, group_id)['members']:
  		_member = LIFE[member_id]
  		
  		if not _group_center:
  			_group_center = _member['pos'][:]
  			
  			continue
  		
  		_group_center = bad_numbers.lerp_velocity(_group_center, _member['pos'], .5)
  	
  	for territory_id in WORLD_INFO['territories']:
  		_territory = WORLD_INFO['territories'][territory_id]
  		
  		if _territory['owner'] == faction_name:
  			continue
  		
  		#TODO: Pre-compute?
  		_nearest_chunk = alife.chunks.get_nearest_chunk_in_list(_group_center, _territory['chunk_keys'], include_distance=True)
  		
  		if not _closest_territory['chunk_key'] or _nearest_chunk['distance'] < _closest_territory['distance']:
  			_closest_territory['distance'] = _nearest_chunk['distance']
  			_closest_territory['chunk_key'] = _nearest_chunk['chunk_key']
  			_closest_territory['territory_id'] = territory_id
  	
  	for member_id in alife.groups.get_group({}, group_id)['members']:
  		_member = LIFE[member_id]
  		
  		missions.create_mission_for_self(_member, 'travel_to', chunk_key=_closest_territory['chunk_key'])
  		missions.create_mission_for_self(_member, 'capture_territory', territory_id=_closest_territory['territory_id'])
  		set_group_order(faction_name, group_id, 'travel_to')
  
  def move_group_to(faction_name, group_id, chunk_key):
  	for member_id in alife.groups.get_group({}, group_id)['members']:
  		_member = LIFE[member_id]
  		
  		if not missions.has_mission_with_name(_member, 'travel_to'):
  			missions.create_mission_for_self(_member, 'travel_to', chunk_key=chunk_key)
  			set_group_order(faction_name, group_id, 'travel_to')
  
  def resupply(faction_name, group_id, chunk_key):
  	for member_id in alife.groups.get_group({}, group_id)['members']:
  		_member = LIFE[member_id]
  		
  		missions.create_mission_for_self(_member, 'travel_to', chunk_key=chunk_key)
  		#missions.create_mission_for_self(_member, 'resupply', chunk_key=chunk_key)
  		set_group_order(faction_name, group_id, 'travel_to')
  
  def manage_faction_groups():
  	for faction_name in WORLD_INFO['factions']:
  		_faction = get_faction(faction_name)
  		
  		for group_id in _faction['groups']:
  			_group_order = get_group_order(faction_name, group_id)
  			
  			if not _group_order:
  				continue
  			
  			for member_id in alife.groups.get_group({}, group_id)['members']:
  				if missions.has_mission_with_name(LIFE[member_id], _group_order['order']):
  					break
  			else:
  				continue
  			
  			clear_group_order(faction_name, group_id)
  
  def create_zes_export():
  	_zes_camp_chunk_key = random.choice(claim_territory('ZES')['chunk_keys'])
  	
  	spawns.generate_group('zes_guard', faction='ZES', amount=random.randint(3, 4), spawn_chunks=[_zes_camp_chunk_key])
  
  def create_fields():
  	_lower_half_chunk_keys = alife.chunks.get_chunks_in_range(0, 1, .6, 1)
  	
  	spawns.generate_group('loner', faction='Loners', amount=random.randint(3, 4), spawn_chunks=random.sample(_lower_half_chunk_keys, 1))
  	spawns.generate_group('bandit', faction='Bandits', amount=random.randint(3, 4), spawn_chunks=random.sample(_lower_half_chunk_keys, 1))
  
  def create_outposts():
  	for outpost_chunks in WORLD_INFO['refs']['outposts']:
  		spawns.generate_group('soldier', faction='Military', amount=random.randint(1, 2), spawn_chunks=outpost_chunks)
  		spawns.generate_group('soldier_riflemen', faction='Military', amount=random.randint(1, 2), spawn_chunks=outpost_chunks)
  
  def control_loners():
  	_loners = get_faction('Loners')
  	
  	for squad in _loners['groups']:
  		for member in [LIFE[i] for i in squad]:
  			#print member['name'], alife.groups.get_stage(member, member['group'])
  			if not alife.groups.is_leader(member, member['group'], member['id']):
  				continue
  		
  			alife.groups.set_stage(member, member['group'], STAGE_RAIDING)
  			alife.groups.flag(member, member['group'], 'raid_chunk', WORLD_INFO['refs']['outposts'][0][0])
  
  def control_zes():
  	_zes = get_faction('ZES')
  	
  	if not 'intro_created' in _zes['flags'] and _zes['members'] and SETTINGS['controlling']:
  		_zes = get_faction('ZES')
  		_zes['flags']['intro_created'] = True
  		_item_uid = weapons.spawn_and_arm('glock', '9x19mm magazine', '9x19mm round', 17)
  		_kill_target = get_faction('Bandits')['members'][0]
  		_kill_target_direction = bad_numbers.distance(LIFE[_zes['members'][0]]['pos'], LIFE[_kill_target]['pos'])
  		_quest_item_uid = lfe.get_inventory_item_matching(LIFE[_kill_target], {'type': 'radio'})
  		_mission = missions.create_mission('zes_glock', target=SETTINGS['controlling'],
  		                                   item_uid=_item_uid,
  		                                   quest_item_uid=_quest_item_uid,
  		                                   deliver_target=_zes['members'][0],
  		                                   kill_target=_kill_target,
  		                                   location=lfe.get_current_chunk_id(LIFE[_kill_target]))
  		
  		lfe.add_item_to_inventory(LIFE[_zes['members'][0]], _item_uid)
  		alife.brain.meet_alife(LIFE[_zes['members'][0]], LIFE[SETTINGS['controlling']])
  		alife.memory.create_question(LIFE[_zes['members'][0]],
  		                             SETTINGS['controlling'],
  		                             'zes_intro',
  		                             kill_target_name=' '.join(LIFE[_kill_target]['name']),
  		                             kill_target_direction=language.get_real_direction(_kill_target_direction))
  		missions.remember_mission(LIFE[_zes['members'][0]], _mission)
  		missions.activate_mission(LIFE[_zes['members'][0]], '1')
  	
  	#for group_id in _zes['groups']:
  	#	pass
  	#	#for member in [LIFE[i] for i in alife.groups.get_group({}, group_id)['members']]:
  	
  	#for group_id in _loners['groups']:
  	#	for member in [LIFE[i] for i in squad]:
  	#		#print member['name'], alife.groups.get_stage(member, member['group'])
  	#		if not alife.groups.is_leader(member, member['group'], member['id']):
  	#			continue
  	#	
  	#		alife.groups.set_stage(member, member['group'], STAGE_RAIDING)
  	#		alife.groups.flag(member, member['group'], 'raid_chunk', WORLD_INFO['refs']['outposts'][0][0])
  
  def direct():
  	#for faction_name in WORLD_INFO['factions']:
  	#if faction_name == 'Loners':
  	#control_loners()
  	manage_faction_groups()
  	control_zes()