Exemple #1
0
def _printer_move(entity):
	_x, _y = flags.get_flag(entity, 'text_pos')
	_move_direction = flags.get_flag(entity, 'move_direction')
	_vx, _vy = numbers.velocity(_move_direction, 1)
	_x += int(round(_vx))
	_y += int(round(_vy))
	
	entities.trigger_event(entity, 'set_flag', flag='text_pos', value=(_x, _y))
Exemple #2
0
def _tick_fire(entity):
	_x, _y = movement.get_position(entity)
	_alpha = flags.get_flag(entity, 'alpha')
	_alpha += random.uniform(-.3, .3)
	_alpha = numbers.clip(_alpha, 0, 1)
	
	if not _alpha:
		#char(_x, _y, numbers.clip(flags.get_flag(entity, 'alpha_max') - random.uniform(.1, .2), 0, 1))
		entities.delete_entity(entity)
		
		return
	
	#entities.trigger_event(entity, 'set_char', char=random.choice(['*', '&', '%']))

	_color = list(display.get_color_at('tiles', _x, _y))
	_color[0] = numbers.interp_velocity(_color[0], random.choice([constants.FIRE_1, constants.FIRE_2, constants.FIRE_3]), _alpha)
	_color[1] = numbers.interp_velocity(_color[1], random.choice([constants.FIRE_1, constants.FIRE_2, constants.FIRE_3]), _alpha)
	
	for c in range(len(_color)):
		for i in range(len(_color)):
			_color[c][i] = int((round(_color[c][i])))
	
	entities.trigger_event(entity, 'set_fore_color', color=_color[0])
	entities.trigger_event(entity, 'set_back_color', color=_color[1])
	entities.trigger_event(entity, 'set_flag', flag='alpha', value=_alpha)
Exemple #3
0
def _smoke_shooter_push(entity):
	_x, _y = movement.get_position(entity)
	_direction = movement.get_direction(entity)
	_mod = random.randint(-35, 35)
	_alpha = flags.get_flag(entity, 'alpha')
	
	if _mod < 0:
		_mod = numbers.clip(_mod, -35, -20)
	else:
		_mod = numbers.clip(_mod, 20, 35)
	
	_direction += _mod
	
	_v_x, _v_y = numbers.velocity(_direction, random.uniform(.65, .85))
	
	if not int(round(_x + _v_x)) == int(round(_x)) or not int(round(_y + _v_y)) == int(round(_y)):
		#smoke_cloud(_x + _v_x, _y + _v_y, random.randint(1, 2), start_alpha=_alpha, decay_amount=1.2)
		smoke(_x + _v_x, _y + _v_y, .75, start_amount=_alpha, decay_amount=random.uniform(3.0, 4.0))
	
	_x += _v_x
	_y += _v_y
	
	if (int(round(_x)), int(round(_y))) in zones.get_active_solids({}, no_life=True):
		entities.delete_entity(entity)
		
		return
	
	entities.trigger_event(entity, 'set_direction', direction=_direction)
	entities.trigger_event(entity, 'set_position', x=_x, y=_y)
	entities.trigger_event(entity, 'set_flag', flag='alpha', value=_alpha - .05)
Exemple #4
0
def _search_for_target(entity, target_id):
    _nodes = flags.get_flag(entity, 'search_nodes')

    if not _nodes:
        flags.delete_flag(entity, 'search_nodes')

        entities.trigger_event(entity,
                               'target_search_failed',
                               target_id=target_id)

        return

    _node_list = _nodes.keys()
    _node_list.sort()
    _node_x, _node_y = _nodes[_node_list[0]][0]
    _distance = numbers.distance(movement.get_position(entity),
                                 (_node_x, _node_y))

    if _distance <= 15 and life.can_see_position(entity, (_node_x, _node_y)):
        _nodes[_node_list[0]].remove((_node_x, _node_y))

        if not _nodes[_node_list[0]]:
            del _nodes[_node_list[0]]
    else:
        movement.walk_to_position(entity, _node_x, _node_y,
                                  zones.get_active_astar_map(),
                                  zones.get_active_weight_map())
Exemple #5
0
def shoot_weapon(entity, target_id):
	if timers.has_timer_with_name(entity, 'shoot'):
		return

	_weapon = items.get_items_in_holder(entity, 'weapon')[0]
	_ammo = flags.get_flag(entities.get_entity(_weapon), 'ammo')
	_rounds_per_shot = flags.get_flag(entities.get_entity(_weapon), 'rounds_per_shot')
	_pause_time = 15

	if not _ammo:
		return

	entities.trigger_event(entity,
		                   'create_timer',
		                   time=_pause_time,
	                       repeat=_rounds_per_shot,
		                   name='shoot',
	                       enter_callback=lambda _: entities.trigger_event(entity, 'animate', animation=['\\', '|', '/', '-'], delay=_pause_time/4),
		                   repeat_callback=lambda _: _shoot_weapon(entity, _weapon, target_id))
Exemple #6
0
def _reload_weapon(entity, weapon_id, ammo_id):
	_weapon = entities.get_entity(weapon_id)
	_ammo = entities.get_entity(ammo_id)
	_weapon_ammo = flags.get_flag(_weapon, 'ammo')
	_weapon_ammo_max = flags.get_flag(_weapon, 'ammo_max')
	_ammo_count = flags.get_flag(_ammo, 'ammo')

	if _weapon_ammo == _weapon_ammo_max:
		return

	_need_ammo = numbers.clip(_weapon_ammo_max - _weapon_ammo, 1, _ammo_count)
	_ammo_count -= _need_ammo

	entities.trigger_event(_weapon, 'set_flag', flag='ammo', value=_weapon_ammo + _need_ammo)

	if _ammo_count:
		entities.trigger_event(_ammo, 'set_flag', flag='ammo', value=_ammo_count)
	else:
		entities.delete_entity(_ammo)
Exemple #7
0
def handle_player_heard_noise(entity, x, y, text, direction, accuracy, show_on_sight, callback, context_callback):
	_entity = effects.show_noise(entity, x, y, accuracy, direction, text, show_on_sight, callback)
	
	if not _entity:
		return
	
	if not context_callback:
		return
	
	_x, _y = flags.get_flag(_entity, 'text_orig_pos')
	
	entities.register_event(_entity, 'delete', lambda e: noise.create_context(_x, _y, text, context_callback))
Exemple #8
0
def _message_draw(entity):
	_text = flags.get_flag(entity, 'text')
	_index = flags.get_flag(entity, 'index')
	_center = flags.get_flag(entity, 'center')
	_vert_center = flags.get_flag(entity, 'vert_center')
	
	if _center:
		_x = (constants.MAP_VIEW_WIDTH / 2) - (len(_text) / 2)
	
	else:
		_x = 3
	
	if _vert_center:
		_y = (constants.MAP_VIEW_HEIGHT / 2) - 1
	
	else:
		_y = 1
	
	for i in range(0, 3):
		if i == 1:
			display.write_string('ui', _x, _y + i + (4 * _index), '  %s  ' % _text, fore_color=(200, 200, 200), back_color=(60, 60, 60))
		else:
			display.write_string('ui', _x, _y + i + (4 * _index), ' ' * (len(_text) + 4), fore_color=(20, 20, 20), back_color=(60, 60, 60))
Exemple #9
0
def handle_member_killed(entity, member_id, target_id):
	_member = entities.get_entity(member_id)
	_target = entities.get_entity(target_id)
	_target_faction = _target['ai']['faction']
	
	if _target_faction == _member['ai']['faction']:
		logging.info('Friendly fire resulted in death: %s' % _target_faction)
		
		return
	
	if not _target_faction in entity['enemies']:
		entity['relations'][_target_faction] = 0
		entity['enemies'].append(_target_faction)
		
		logging.info('%s is now hostile to %s: Murder' % (_member['ai']['faction'], _target_faction))
		
		if flags.has_flag(_target, 'is_player') and flags.get_flag(_target, 'is_player'):
			effects.message('%s now see you as hostile.' % _member['ai']['faction'])
Exemple #10
0
def _cleanup(entity):
    if entity["_id"] in ONLINE_ENTITIES:
        ONLINE_ENTITIES.remove(entity["_id"])

    elif entity["_id"] in OFFLINE_ENTITIES:
        OFFLINE_ENTITIES.remove(entity["_id"])

    _x, _y = movement.get_position(entity)

    if flags.has_flag(entity, "fire_data"):
        _fire_data = flags.get_flag(entity, "fire_data")
        _node = entities.get_entity(zones.get_active_node_grid()[_fire_data["node"]])

        entities.trigger_event(_node, "set_flag", flag="owner", value=None)
        flags.delete_flag(entity, "fire_data")

    _item_id = items.corpse(_x, _y, entity["tile"]["char"], entity["_id"])["_id"]

    entities.trigger_event(entity, "handle_corpse", corpse_id=_item_id)
Exemple #11
0
def get_accuracy(entity, weapon_id):
	entity['stats']['accuracy'] = entity['stats']['max_accuracy']
	_weapon = entities.get_entity(weapon_id)
	
	entities.trigger_event(entity, 'get_accuracy')
	_weapon_accuracy = flags.get_flag(_weapon, 'accuracy')
	
	if _weapon['stats']['kind'] == 'pistol':
		_weapon_accuracy *= 1 + (1 - (entity['stats']['pistols'] / 100.0))
	
	elif _weapon['stats']['kind'] == 'rifle':
		_weapon_accuracy *= 1 + (1 - (entity['stats']['rifles'] / 100.0))
	
	elif _weapon['stats']['kind'] == 'explosive':
		_weapon_accuracy *= 1 + (1 - (entity['stats']['explosives'] / 100.0))
	
	else:
		raise Exception('Invalid gun type.')
	
	return int(round(_weapon_accuracy * entity['stats']['accuracy']))
Exemple #12
0
def _search_for_target(entity, target_id):
	_nodes = flags.get_flag(entity, 'search_nodes')
	
	if not _nodes:
		flags.delete_flag(entity, 'search_nodes')
		
		entities.trigger_event(entity, 'target_search_failed', target_id=target_id)
		
		return
	
	_node_list = _nodes.keys()
	_node_list.sort()	
	_node_x, _node_y = _nodes[_node_list[0]][0]
	_distance = numbers.distance(movement.get_position(entity), (_node_x, _node_y))
	
	if _distance <= 15 and life.can_see_position(entity, (_node_x, _node_y)):
		_nodes[_node_list[0]].remove((_node_x, _node_y))
		
		if not _nodes[_node_list[0]]:
			del _nodes[_node_list[0]]
	else:
		movement.walk_to_position(entity, _node_x, _node_y, zones.get_active_astar_map(), zones.get_active_weight_map())
Exemple #13
0
def _shoot_weapon(entity, weapon_id, target_id):
	_weapon = entities.get_entity(weapon_id)
	_x, _y = movement.get_position(entities.get_entity(_weapon['stats']['owner']))
	
	if not target_id in entities.ENTITIES:
		logging.warning('Target deleted during shooting.')
		
		return
	
	_tx, _ty = movement.get_position(entities.get_entity(target_id))
	_direction = numbers.direction_to((_x, _y), (_tx, _ty))
	effects.muzzle_flash(_x, _y, _direction)

	entities.trigger_event(_weapon, 'flag_sub', flag='ammo', value=1)
	entities.trigger_event(entity,
	                       'create_noise',
	                       volume=80,
	                       direction=numbers.direction_to((_x, _y), (_tx, _ty)),
	                       text='BAM',
	                       callback=lambda t, x, y: entities.trigger_event(t,
	                                                                'update_target_memory',
	                                                                target_id=entity['_id'],
	                                                                key='last_seen_at',
	                                                                value=[x, y]),
	                       context_callback=lambda x, y: ui_dialog.create(x, y, 'Gunshot (Unknown)', title='Noise'))

	entity['stats']['action_points'] -= stats.get_shoot_cost(entity, weapon_id)

	entities.trigger_event(entity, 'get_accuracy')
	_accuracy = stats.get_accuracy(entity, weapon_id)
	_damage = flags.get_flag(_weapon, 'damage')

	effects.light(_x, _y, random.randint(3, 5), r=1.5, g=1.5, b=0)
	
	if _weapon['stats']['kind'] == 'explosive':
		items.explosive(entity, _x, _y, _tx, _ty, 4, _accuracy, _damage)
	
	else:
		items.bullet(entity, _x, _y, _tx, _ty, 1, _accuracy, _damage)
Exemple #14
0
def _printer_draw(entity):
	_text = flags.get_flag(entity, 'text')
	_text_index = flags.get_flag(entity, 'text_index')
	_text_center = flags.get_flag(entity, 'text_center')
	_text_fore_color = flags.get_flag(entity, 'text_fore_color')
	_text_back_color = flags.get_flag(entity, 'text_back_color')
	_x, _y = flags.get_flag(entity, 'text_pos')
	
	if _text_center:
		if _x + len(_text[:_text_index])/2 >= camera.X + constants.MAP_VIEW_WIDTH-1:
			return
		
		if _x - len(_text[:_text_index])/2 < camera.X:
			return
		
		if _y >= camera.Y + constants.MAP_VIEW_HEIGHT:
			return
		
		_x -= len(_text[:_text_index])/2
		display.write_string('ui', _x-camera.X, _y-camera.Y, _text[:_text_index], fore_color=_text_fore_color, back_color=_text_back_color)
Exemple #15
0
def _tick_smoke(entity):
	_x, _y = movement.get_position(entity)
	_alpha = flags.get_flag(entity, 'alpha')
	_alpha_mode = flags.get_flag(entity, 'alpha_mode')
	_alpha_max = flags.get_flag(entity, 'alpha_max')
	_fore_color = flags.get_flag(entity, 'fore_color')
	_back_color = flags.get_flag(entity, 'back_color')
	_decay_mod = flags.get_flag(entity, 'decay')
	
	if _alpha_mode:
		_alpha -= random.uniform(.001 * _decay_mod, .005 * _decay_mod)
		
		if _alpha <= 0:
			display._set_char('tiles', _x, _y, ' ', (0, 0, 0), None)
			entities.delete_entity(entity)
			
			return
	
	else:
		_alpha += random.uniform(.01, .05)
		
		if _alpha > _alpha_max:
			_alpha_mode = 1
	
	_alpha = numbers.clip(_alpha, 0, 1)
	
	#entities.trigger_event(entity, 'set_char', char=random.choice(['*', '&', '%']))

	_color = list(display.get_color_at('tiles', _x, _y))
	_color[0] = numbers.interp_velocity(_color[0], _fore_color, _alpha)
	_color[1] = numbers.interp_velocity(_color[1], _back_color, _alpha)
	
	for c in range(len(_color)):
		for i in range(len(_color)):
			_color[c][i] = int((round(_color[c][i])))
	
	entities.trigger_event(entity, 'set_fore_color', color=_color[0])
	entities.trigger_event(entity, 'set_back_color', color=_color[1])
	
	entities.trigger_event(entity, 'set_flag', flag='alpha', value=_alpha)
	entities.trigger_event(entity, 'set_flag', flag='alpha_mode', value=_alpha_mode)
Exemple #16
0
def fire(x, y, amount):
	_blood = _create(x, y)
	_x, _y = (int(round(x)), int(round(y)))
	
	flags.register(_blood)
	timers.register(_blood)
	
	entities.trigger_event(_blood, 'set_flag', flag='alpha', value=amount)
	entities.trigger_event(_blood, 'set_flag', flag='alpha_max', value=amount)
	entities.trigger_event(_blood, 'set_char', char=' ')

	_color = list(display.get_color_at('tiles', _x, _y))
	_color[0] = numbers.interp_velocity(_color[0], random.choice([constants.FIRE_1, constants.FIRE_2, constants.FIRE_3]), amount)
	_color[1] = numbers.interp_velocity(_color[1], random.choice([constants.FIRE_1, constants.FIRE_2, constants.FIRE_3]), amount)
	
	for c in range(len(_color)):
		for i in range(len(_color)):
			_color[c][i] = int((round(_color[c][i])))
	
	#display._set_char('tiles', _x, _y, random.choice([',', '.', '^']), _color[0], _color[1])
	entities.register_event(_blood, 'tick', _tick_fire)
	entities.register_event(_blood, 'position_changed', lambda e, x, y, **kwargs: char(x, y, flags.get_flag(e, 'alpha')))
	entities.trigger_event(_blood, 'create_timer', time=120, repeat=-1, repeat_callback=lambda e: movement.push(e,
	                                                                                                            random.randint(-1, 1),
	                                                                                                            random.randint(-1, 1),
	                                                                                                            time=1))
	entities.trigger_event(_blood, 'set_fore_color', color=_color[0])
	entities.trigger_event(_blood, 'set_back_color', color=_color[1])
	entities.trigger_event(_blood, 'set_position', x=_x, y=_y)
	
	#light(_x, _y, random.randint(5, 7), r=1.5, g=.1, b=.1)

	return _blood
Exemple #17
0
def _human_logic(entity):
    _t = time.time()
    ai_visuals.build_item_list(entity)
    ai_visuals.build_life_list(entity)

    if ai_flow.is_flow_active() and not ai_flow.can_act(entity):
        return

    if timers.has_timer_with_name(entity, "passout"):
        return

        # if not ai_squads.is_active(ai_squads.get_assigned_squad(entity)) or entity['stats']['action_points'] <= 0:
        # 	return

    _old_meta = entity["ai"]["meta"].copy()

    entity["ai"]["meta"]["sees_item_type_weapon"] = len(entity["ai"]["visible_items"]["weapon"]) > 0
    entity["ai"]["meta"]["sees_item_type_ammo"] = len(entity["ai"]["visible_items"]["ammo"]) > 0
    entity["ai"]["meta"]["sees_item_type_container"] = len(entity["ai"]["visible_items"]["container"]) > 0
    entity["ai"]["meta"]["has_weapon"] = len(items.get_items_in_holder(entity, "weapon")) > 0
    entity["ai"]["meta"]["has_ammo"] = len(items.get_items_matching(entity, {"type": "ammo"})) > 0
    entity["ai"]["meta"]["has_container"] = len(items.get_items_matching(entity, {"type": "container"})) > 0
    entity["ai"]["meta"]["weapon_loaded"] = (
        len(
            [
                w
                for w in items.get_items_in_holder(entity, "weapon")
                if entities.get_entity(w)["flags"]["ammo"]["value"] > 0
            ]
        )
        > 0
    )
    entity["ai"]["meta"]["in_engagement"] = (
        len([t for t in entity["ai"]["targets"] if not entity["ai"]["life_memory"][t]["is_lost"]]) > 0
    )
    entity["ai"]["meta"]["has_lost_target"] = len(entity["ai"]["targets_to_search"]) > 0
    entity["ai"]["meta"]["in_enemy_los"] = (
        len([t for t in entity["ai"]["targets"] if entity["ai"]["life_memory"][t]["in_los"]]) > 0
    )
    entity["ai"]["meta"]["has_needs"] = (
        not entity["ai"]["meta"]["has_weapon"]
        or not entity["ai"]["meta"]["has_container"]
        or not entity["ai"]["meta"]["weapon_loaded"]
    )
    entity["ai"]["meta"]["is_injured"] = skeleton.has_critical_injury(entity)

    if not entity["ai"]["meta"] == _old_meta:
        entities.trigger_event(entity, "meta_change")

    if entity["ai"]["meta"]["in_engagement"]:
        _target = entity["ai"]["nearest_target"]
        _target_distance = numbers.distance(movement.get_position_via_id(_target), movement.get_position(entity))
        _engage_distance = stats.get_vision(entity) * 0.75
        _weapon = entities.get_entity(items.get_items_in_holder(entity, "weapon")[0])
        _engage_distance = numbers.clip(
            _engage_distance - (flags.get_flag(_weapon, "accuracy") * 3), 1, stats.get_vision(entity)
        )
        _min_engage_distance = 3

        if _weapon["stats"]["kind"] == "explosive":
            _engage_distance /= 2
            _min_engage_distance = 8

        entities.trigger_event(entity, "set_flag", flag="engage_distance", value=_engage_distance)
        entities.trigger_event(entity, "set_flag", flag="min_engage_distance", value=_min_engage_distance)

        # NOTE: Mirror change in ai_logic!
        entity["ai"]["meta"]["in_firing_range"] = (
            _target_distance <= _engage_distance and _target_distance >= _min_engage_distance
        )

        if entity["ai"]["meta"]["in_enemy_los"]:
            if flags.has_flag(entity, "search_nodes"):
                flags.delete_flag(entity, "search_nodes")

            entity["ai"]["meta"]["is_in_melee_range"] = _target_distance == 1

    else:
        entity["ai"]["meta"]["is_target_near"] = False
        entity["ai"]["meta"]["in_firing_range"] = False

    entity["ai"]["meta"]["is_target_armed"] = (
        len([t for t in entity["ai"]["targets"] if entity["ai"]["life_memory"][t]["is_armed"]]) > 0
    )
    entity["ai"]["meta"]["is_panicked"] = (
        not entity["ai"]["meta"]["weapon_loaded"] and entity["ai"]["meta"]["is_target_armed"]
    )

    if entity["ai"]["is_player"]:
        return

        # TODO: Experimental!
        # if entity['ai']['meta'] == _old_meta:
        # print 'Something changed...'

        # return

    if (
        timers.has_timer_with_name(entity, "shoot")
        or entity["movement"]["path"]["positions"]
        or timers.has_timer_with_name(entity, "move")
    ):
        # print 'Clearing existing action...'
        return

    _goap = _handle_goap(entity)

    if not _goap:
        entity["ai"]["current_action"] = "idle"

        entities.trigger_event(entity, "finish_turn")
        entities.trigger_event(entity, "stop")

        # print
        # print entity['stats']['name'], 'no possible action'
        # print

        # for meta_name in entity['ai']['meta']:
        # 	print meta_name, '\t', entity['ai']['meta'][meta_name]

        return

    _plan = _goap[0]

    if not entity["ai"]["last_action"] == _plan["actions"][0]["name"]:
        if entity["_id"] in ai_debugger.WATCHING:
            logging.info("%s: %s -> %s" % (entity["_id"], entity["ai"]["last_action"], _plan["actions"][0]["name"]))

            # TODO: Only do this if the action requires movement changes
        entities.trigger_event(entity, "stop")

        entity["ai"]["last_action"] = _plan["actions"][0]["name"]

        # print entity['stats']['name'], _plan['actions'][0]['name']

    _plan["planner"].trigger_callback(entity, _plan["actions"][0]["name"])

    # print time.time() - _t

    entity["ai"]["current_action"] = _plan["actions"][0]["name"]
Exemple #18
0
def get_shoot_cost(entity, weapon_id):
	_weapon = entities.get_entity(weapon_id)
	_weapon_accuracy = flags.get_flag(_weapon, 'shoot_cost')
	
	return _weapon_accuracy
Exemple #19
0
def _handle_weapon_display_name(entity):
	_weapon_ammo = flags.get_flag(entity, 'ammo')
	_weapon_ammo_max = flags.get_flag(entity, 'ammo_max')	
	
	entity['stats']['display_name'] += ' (%s/%s)' % (_weapon_ammo, _weapon_ammo_max)
Exemple #20
0
def get_vantage_point(squad, member_id):
	_member = entities.get_entity(member_id)
	_member_pos = movement.get_position(_member)
	_best_vantage = {'position': None, 'score': 1000}
	_engage_range = flags.get_flag(_member, 'engage_distance')
	_min_engage_range = flags.get_flag(_member, 'min_engage_distance')
	
	if _member['movement']['path']['destination']:
		if _member['movement']['path']['destination'] in squad['position_map_scores']:
			_scores = squad['position_map_scores'][_member['movement']['path']['destination']]
			_score = _scores['vantage']# + _scores['member_coverage']
			_continue = False
			
			for target_id in squad['known_targets']:
				_last_known_position = _member['ai']['life_memory'][target_id]['last_seen_at']
				_distance_to_target = numbers.distance(_member['movement']['path']['destination'], _last_known_position)
				
				if _distance_to_target < _min_engage_range:
					_continue = True
					
					break
			
			if not _continue and _scores['targets'] and _score >= _min_engage_range and _score <= _engage_range:
				return _member['movement']['path']['destination']
	
	for pos in squad['position_map_scores']:
		_scores = squad['position_map_scores'][pos]
		_dist = numbers.distance(_member_pos, pos)
		_score = _scores['vantage'] + _dist
		_continue = False
		
		if not _scores['targets'] or _score - _dist < _min_engage_range or _score > _engage_range + _dist:
			continue
		
		for target_id in squad['known_targets']:
			_last_known_position = _member['ai']['life_memory'][target_id]['last_seen_at']
			_distance_to_target = numbers.distance(pos, _last_known_position)
			
			if _distance_to_target < _min_engage_range:
				_continue = True
				
				break
			
		if _continue:
			continue

		if _score < _best_vantage['score']:
			_astar_distance = len(pathfinding.astar(_member_pos, pos, zones.get_active_astar_map(), zones.get_active_weight_map()))
			_best_vantage['score'] = _score + _scores['member_coverage'] + int(round((_astar_distance * .15)))
			_best_vantage['position'] = pos[:]
	
	if not _best_vantage['position']:
		_member['ai']['meta']['has_firing_position'] = False
		
		entities.trigger_event(_member, 'create_timer', time=60, exit_callback=_reset_fire_position)
		
		return
	
	_x, _y = movement.get_position(_member)
	_member_positions = set()
	
	for squad_member_id in squad['members']:
		if squad_member_id == member_id:
			continue
		
		_member_positions.add(movement.get_position_via_id(squad_member_id))
	
	_v_p = _best_vantage['position']
	_friendly_fire = False
	
	for pos in shapes.line((_x, _y), _best_vantage['position']):
		if pos in _member_positions:
			_friendly_fire = True
			
			break

	if _friendly_fire:
		for n_pos in [(_v_p[0]-1, _v_p[1]-1), (_v_p[0], _v_p[1]-1), (_v_p[0]+1, _v_p[1]-1), (_v_p[0]-1, _v_p[1]), (_v_p[0]+1, _v_p[1]), (_v_p[0]-1, _v_p[1]+1), (_v_p[0], _v_p[1]+1), (_v_p[0]+1, _v_p[1]+1)]:
			if not n_pos in squad['position_map_scores']:
				continue
			
			_break = False
			for nn_pos in shapes.line((_x, _y), n_pos):
				if nn_pos in _member_positions:
					_break = True
					
					break
			else:
				_v_p = n_pos
				
				break
			
			if _break:
				continue
	
	for coverage_pos in shapes.circle(_v_p[0], _v_p[1], 6):
		if not coverage_pos in squad['position_map_scores']:
			continue
		
		_c_dist = 15 * (1 - (numbers.distance(coverage_pos, (_x, _y)) / 6.0))
		
		squad['position_map_scores'][coverage_pos]['member_coverage'] += _c_dist
	
	squad['position_map_scores'][_v_p]['member_coverage'] += 6
	
	return _v_p