def _explosive_tick(entity): _direction = movement.get_direction(entity) entities.trigger_event(entity, 'push_tank', direction=_direction) _x, _y = movement.get_position(entity) _distance = numbers.distance((_x, _y), entity['end_position']) _starting_target_distance = numbers.distance(entity['start_position'], entity['end_position']) if _distance <= entity['accuracy'] * 2.5: entity['slow_down'] = True if entity['slow_down']: entity['speed'] = numbers.clip(entity['speed'] * 1.2, 0, 40) if entity['speed'] < 40: entities.trigger_event(entity, 'create_timer', time=int(round(entity['speed'])), name='movement', exit_callback=_explosive_tick) else: entities.trigger_event(entity, 'activate_explosive')
def walk_to_position(entity, x, y, astar_map, weight_map, avoid=[], smp=-1): _start_position = get_position(entity) _target_position = (x, y) if _start_position == _target_position: return False if smp == True or (smp == -1 and numbers.distance(_start_position, _target_position) > settings.SMP_MIN_PATH_DISTANCE): smp = settings.ALLOW_SMP if entity['movement']['path']['destination']: if not numbers.distance(entity['movement']['path']['destination'], _target_position): return False if smp == True: pathfinding.astar_mp(_start_position, _target_position, astar_map, weight_map, lambda path: set_path(entity, path), avoid=avoid) else: entity['movement']['path']['positions'] = pathfinding.astar( get_position(entity), _target_position, astar_map, weight_map, avoid=avoid) entity['movement']['path']['destination'] = _target_position entity['movement']['path']['refresh'] = False return True
def update_position_maps(squad): _t = time.time() _coverage_positions = squad['coverage_positions'] _known_targets = squad['known_targets'] _known_squads = squad['known_squads'] _known_targets_left_to_check = _known_targets.copy() _score_map = {pos: {'coverage': 0, 'vantage': 100, 'member_coverage': 0, 'danger': 0, 'targets': [], 'owned': False} for pos in _coverage_positions} for faction_name, squad_id in _known_squads: if not squad_id in ai_factions.FACTIONS[faction_name]['squads']: continue _squad = entities.get_entity(ai_factions.FACTIONS[faction_name]['squads'][squad_id]) _member_set = set(_squad['members']) _check_members = _known_targets_left_to_check & _member_set _known_targets_left_to_check = _known_targets_left_to_check - _member_set for target_id in list(_check_members): _target_position = movement.get_position_via_id(target_id) _closest_member = {'distance': 0, 'member_id': None} for member_id in squad['members']: _member_position = movement.get_position_via_id(member_id) _distance = numbers.clip(numbers.distance(_target_position, _member_position), 0, 60) if not _closest_member['member_id'] or _distance < _closest_member['distance']: _closest_member['distance'] = _distance _closest_member['member_id'] = member_id _target_coverage_map = _squad['member_position_maps'][target_id] _overlap_positions = _coverage_positions & _target_coverage_map _cover_positions = _coverage_positions - _target_coverage_map if not _closest_member['member_id']: logging.warning('Couldn\'t find closest member for target during squad positioning.') continue _closest_member_pos = movement.get_position_via_id(_closest_member['member_id']) for pos in _overlap_positions: _distance = numbers.distance(_closest_member_pos, pos) if _distance < _score_map[pos]['vantage']: _score_map[pos]['vantage'] = _distance #_score_map[pos]['danger'] = 60 - _distance _score_map[pos]['targets'].append(target_id) for pos in _cover_positions: _distance = numbers.distance(_closest_member_pos, pos) if _distance > _score_map[pos]['coverage']: _score_map[pos]['coverage'] = _distance _score_map[pos]['danger'] = 60 - _distance squad['position_map_scores'] = _score_map
def _bullet_tick(entity): _direction = movement.get_direction(entity) entities.trigger_event(entity, 'push_tank', direction=_direction) _x, _y = movement.get_position(entity) _distance = numbers.distance((_x, _y), entity['start_position']) _starting_target_distance = numbers.distance(entity['start_position'], entity['end_position']) if _distance > _starting_target_distance + (12 - (entity['speed'] * 2)): entities.delete_entity(entity)
def logic(entity): _last_pos = None _stop_here = False for node_id in entity['node_grid']['path'][:]: _node = entity['node_grid']['nodes'][node_id] if not (_node['node']['x'], _node['node']['y']) == movement.get_position(entity): if _stop_here and not (_node['node']['x'], _node['node']['y']) == _last_pos: break _distance = numbers.distance((_node['node']['x'], _node['node']['y']), movement.get_position(entity)) if _node['call_on_touch'] and _distance: continue elif not _distance: entity['node_grid']['path'].remove(node_id) del entity['node_grid']['nodes'][node_id] entities.delete_entity_via_id(node_id) _node['callback']() if not _node['passive']: _stop_here = True _last_pos = (_node['node']['x'], _node['node']['y'])
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())
def get_push_position(squad, member_id): _member = entities.get_entity(member_id) _best_vantage = {'position': None, 'score': 1000} _vision = stats.get_vision(_member) _engage_range = int(round(_vision * .75)) for pos in squad['position_map_scores']: _scores = squad['position_map_scores'][pos] _score = _scores['vantage'] + _scores['member_coverage'] if not _scores['targets'] or _score < 6 or _score > _engage_range: continue if _score < _best_vantage['score']: _best_vantage['score'] = _score _best_vantage['position'] = pos[:] if not _best_vantage['position']: _member['ai']['meta']['has_firing_position'] = False return _x, _y = movement.get_position(_member) for coverage_pos in shapes.circle(_best_vantage['position'][0], _best_vantage['position'][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'][_best_vantage['position']]['member_coverage'] += 20 return _best_vantage['position']
def create_noise(entity, text, volume, owner_can_hear=False, show_on_sight=False, direction=-1000, callback=None, context_callback=None): _x, _y = movement.get_position(entity) for entity_id in entities.get_entity_group('life'): if not owner_can_hear and entity['_id'] == entity_id: continue _target = entities.get_entity(entity_id) if entity['ai']['faction'] == _target['ai']['faction']: continue #TODO: Hearing stat _distance = numbers.distance(movement.get_position(entity), movement.get_position(_target)) _accuracy = 1 - numbers.clip(_distance / float(volume), 0, 1) entities.trigger_event(_target, 'heard_noise', x=_x, y=_y, text=text, direction=direction, show_on_sight=show_on_sight, accuracy=_accuracy, callback=callback, context_callback=context_callback)
def explosive(entity, x, y, tx, ty, speed, accuracy, damage): _entity = _create(x, y, 'Explosive', '.', 0, 'bullet') _entity['owner'] = entity['_id'] _entity['start_position'] = (x, y) _entity['end_position'] = (tx, ty) _entity['speed'] = speed _entity['damage'] = damage _toss_distance = numbers.distance(_entity['start_position'], _entity['end_position']) _entity['accuracy'] = numbers.clip( random.randint(int(round(accuracy * .25)), accuracy), 0, 100) - (accuracy * (1 - (_toss_distance / 20.0))) _entity['slow_down'] = False _direction_mod = random.uniform(-accuracy, accuracy) * 2 entities.create_event(_entity, 'explode') entities.create_event(_entity, 'activate_explosive') entities.register_event(_entity, 'explode', frag_grenade_explode) entities.register_event(_entity, 'explode', entities.delete_entity) entities.register_event( _entity, 'activate_explosive', lambda e: entities.trigger_event( e, 'create_timer', time=90, exit_callback=lambda ee: entities.trigger_event(ee, 'explode'))) entities.register_event(_entity, 'check_next_position', check_next_position) entities.add_entity_to_group(_entity, 'bullets') timers.register(_entity) entities.trigger_event(_entity, 'set_direction', direction=numbers.direction_to( (x, y), (tx, ty)) + _direction_mod) entities.trigger_event(_entity, 'create_timer', time=speed, enter_callback=_explosive_tick, name='movement') entities.register_event(_entity, 'position_changed', lambda e, **kwargs: check_for_collisions(e)) if not '--no-fx' in sys.argv: entities.register_event( _entity, 'position_changed', lambda e, x, y, **kwargs: _bullet_effects(e, x, y)) entities.register_event( _entity, 'collision_with_entity', lambda e, **kwargs: entities.trigger_event(e, 'activate_explosive')) entities.register_event(_entity, 'collision_with_entity', lambda e, **kwargs: _explosive_stop_dumb_hack(e)) entities.register_event(_entity, 'collision_with_solid', lambda e: timers.stop_timer(e, 'movement')) entities.register_event(_entity, 'collision_with_solid', _explosive_stop_dumb_hack) entities.register_event( _entity, 'collision_with_solid', lambda e: entities.trigger_event(e, 'activate_explosive'))
def _locate_npc_message(goal, member_id): _target_id = goal['target_id'] _member = entities.get_entity(member_id) _mission = entities.get_entity(goal['mission_id']) if not _target_id in _member['ai']['life_memory'] or not _member['ai']['life_memory'][_target_id]['last_seen_at']: goal['message'] = 'Gather location info on target.' return if _member['ai']['life_memory'][_target_id]['is_dead']: goal['message'] = 'Confirmed: Target is dead.' entities.trigger_event(_member, 'complete_goal', mission_id=goal['mission_id'], goal_id=goal['_id']) elif _member['ai']['life_memory'][_target_id]['can_see']: goal['message'] = 'Target in line of sight.' entities.trigger_event(_member, 'complete_goal', mission_id=goal['mission_id'], goal_id=goal['_id']) elif _member['ai']['life_memory'][_target_id]['last_seen_at']: _direction = numbers.direction_to(movement.get_position(_member), _member['ai']['life_memory'][_target_id]['last_seen_at']) _distance = numbers.distance(movement.get_position(_member), _member['ai']['life_memory'][_target_id]['last_seen_at']) _real_direction = conversions.get_real_direction(_direction) _real_distance = conversions.get_real_distance(_distance) goal['message'] = 'Target last seen %s meters to the %s' % (_real_distance, _real_direction) _member['ai']['life_memory'][_target_id]['mission_related'] = True
def explosive(entity, x, y, tx, ty, speed, accuracy, damage): _entity = _create(x, y, 'Explosive', '.', 0, 'bullet') _entity['owner'] = entity['_id'] _entity['start_position'] = (x, y) _entity['end_position'] = (tx, ty) _entity['speed'] = speed _entity['damage'] = damage _toss_distance = numbers.distance(_entity['start_position'], _entity['end_position']) _entity['accuracy'] = numbers.clip(random.randint(int(round(accuracy * .25)), accuracy), 0, 100) - (accuracy * (1 - (_toss_distance / 20.0))) _entity['slow_down'] = False _direction_mod = random.uniform(-accuracy, accuracy) * 2 entities.create_event(_entity, 'explode') entities.create_event(_entity, 'activate_explosive') entities.register_event(_entity, 'explode', frag_grenade_explode) entities.register_event(_entity, 'explode', entities.delete_entity) entities.register_event(_entity, 'activate_explosive', lambda e: entities.trigger_event(e, 'create_timer', time=90, exit_callback=lambda ee: entities.trigger_event(ee, 'explode'))) entities.register_event(_entity, 'check_next_position', check_next_position) entities.add_entity_to_group(_entity, 'bullets') timers.register(_entity) entities.trigger_event(_entity, 'set_direction', direction=numbers.direction_to((x, y), (tx, ty)) + _direction_mod) entities.trigger_event(_entity, 'create_timer', time=speed, enter_callback=_explosive_tick, name='movement') entities.register_event(_entity, 'position_changed', lambda e, **kwargs: check_for_collisions(e)) if not '--no-fx' in sys.argv: entities.register_event(_entity, 'position_changed', lambda e, x, y, **kwargs: _bullet_effects(e, x, y)) entities.register_event(_entity, 'collision_with_entity', lambda e, **kwargs: entities.trigger_event(e, 'activate_explosive')) entities.register_event(_entity, 'collision_with_entity', lambda e, **kwargs: _explosive_stop_dumb_hack(e)) entities.register_event(_entity, 'collision_with_solid', lambda e: timers.stop_timer(e, 'movement')) entities.register_event(_entity, 'collision_with_solid', _explosive_stop_dumb_hack) entities.register_event(_entity, 'collision_with_solid', lambda e: entities.trigger_event(e, 'activate_explosive'))
def build_item_list(entity): entity['ai']['visible_items'] = {'weapon': [], 'container': [], 'ammo': [], 'bullet': [], 'corpse': []} return _active_solids = zones.get_active_solids(entity) for entity_id in entities.get_entity_group('items'): _item = entities.get_entity(entity_id) if not _item['stats']['type'] in entity['ai']['visible_items']: continue if _item['stats']['owner']: continue _distance = numbers.distance(movement.get_position(entity), movement.get_position(_item)) if _distance >= stats.get_vision(entity): continue for pos in shapes.line(movement.get_position(entity), movement.get_position(_item)): if pos in _active_solids: break else: entity['ai']['visible_items'][_item['stats']['type']].append(entity_id) entities.trigger_event(_item, 'seen', target_id=entity['_id'])
def create_bases(ownable_plots): _width = constants.STRAT_MAP_WIDTH/constants.MAP_CELL_SPACE _height = constants.STRAT_MAP_HEIGHT/constants.MAP_CELL_SPACE _bases = [] for i in range(6): while 1: _new_base_pos = random.choice(ownable_plots) _min_distance = 0 for base_pos in _bases: _distance = numbers.distance(_new_base_pos, base_pos) if _distance <= 2: break _min_distance = _distance else: if _min_distance >= 7: continue _bases.append(_new_base_pos) ownable_plots.remove(_new_base_pos) break for b_x, b_y in _bases: world_strategy.MAP['grid'][b_x, b_y]['is_ownable'] = True
def add_plot_pole(x, y, radius, solids, cell_split=3.0, debug=False): global NODE_SET_ID _node_set = set() _min_x = 999999999 _max_x = 0 _min_y = 999999999 _max_y = 0 for node_pos in list(UNCLAIMED_NODES): if numbers.distance((x, y), node_pos) > radius: continue if node_pos[0] < _min_x: _min_x = node_pos[0] if node_pos[0] > _max_x: _max_x = node_pos[0] if node_pos[1] < _min_y: _min_y = node_pos[1] if node_pos[1] > _max_y: _max_y = node_pos[1] _node_set.add(node_pos) _map = numpy.ones(((_max_y-_min_y)+1, (_max_x-_min_x)+1)) for _x, _y in solids: if _x >= _max_x or _x <= _min_x or _y >= _max_y or _y <= _min_y: continue _map[int(round((_y-_min_y))), int(round((_x-_min_x)))] = -2 NODE_SETS[NODE_SET_ID] = {'owner': None, 'nodes': _node_set, 'center': (x, y), 'astar_map': _map, 'min_x': _min_x, 'min_y': _min_y, 'cell_split': float(cell_split), 'weight_map': numpy.ones(((_max_y-_min_y)+1, (_max_x-_min_x)+1), dtype=numpy.int16)} NODE_SET_ID += 1 if debug: for y in range(_max_y-_min_y): for x in range(_max_x-_min_x): _val = int(round(_map[y, x])) if _val == -2: print '#', elif _val == 1: print '.', print return NODE_SET_ID-1
def handle_keyboard_input(): if controls.get_input_char_pressed('\t'): if settings.TICK_MODE == 'strategy': if ui_panel.ACTIVE_MENU: ui_panel.close() else: ui_panel.show_inventory(entity) else: _x, _y = movement.get_position(entity) camera.set_pos(_x - constants.MAP_VIEW_WIDTH / 2, _y - constants.MAP_VIEW_HEIGHT / 2) if controls.get_input_char_pressed('O'): settings.toggle_show_node_grid() elif controls.get_input_char_pressed('o'): settings.toggle_observer_mode() if controls.get_input_char_pressed('d'): _mx, _my = ui_cursor.get_map_position() for entity_id in entities.get_entity_group('life'): _entity = entities.get_entity(entity_id) if not numbers.distance( (_mx, _my), movement.get_position(_entity)): _x, _y = ui_cursor.get_screen_position() _menu = ui_menu.create(_x, _y, title='Debug') ui_menu.add_selectable(_menu, 'Show Metas', lambda: _show_metas(_entity)) ui_menu.add_selectable( _menu, 'Kill', lambda: entities.trigger_event(_entity, 'kill')) ui_menu.add_selectable(_menu, 'Overwatch', lambda: ai_debugger.register(_entity)) break if controls.get_input_char_pressed('l'): _x, _y = ui_cursor.get_screen_position() _mx, _my = ui_cursor.get_map_position() _weight = zones.get_active_weight_map()[_my, _mx] _menu = ui_menu.create(_x, _y, title='Tile Info') ui_menu.add_selectable( _menu, 'Warp', lambda: entities.trigger_event( entity, 'set_position', x=_mx, y=_my)) ui_menu.add_selectable( _menu, 'Light', lambda: effects.light(_mx, _my, 15, r=random.uniform(1.0, 1.5), g=random.uniform(1.0, 1.5), light_map='static_lighting')) ui_menu.add_selectable(_menu, 'Weight: %s' % _weight, lambda: _)
def _bullet_effects(entity, x, y): _distance = numbers.distance((x, y), entity['start_position']) _target_distance = numbers.distance((x, y), entity['end_position']) + numbers.clip(10 - _distance, 0, 10) _x, _y = movement.get_position(entity) _mod = (0.6 - (_distance / 35.0)) + random.uniform(-.1, .1) _alpha = numbers.clip(_mod, 0, 1) _crash_dist = 60 - (entity['speed'] * 2) if _alpha > 0: effects.vapor(x, y, start_alpha=_alpha) if _target_distance < 30: _size = int(round(2 * (1 - (1 * numbers.clip(numbers.clip(_target_distance, 0, 100)/60.0, 0, 1))))) + random.randint(1, 2) if _distance > _crash_dist: _size = int(round(_size * (_crash_dist/float(_distance)))) if _size > 1: effects.light(_x, _y, _size, r=1.3, g=1.3, b=1.3)
def find_cover(entity): _squad = entities.get_entity(ai_factions.FACTIONS[entity['ai']['faction']]['squads'][entity['ai']['squad']]) _cover_position = ai_squad_director.get_cover_position(_squad, entity['_id']) if not _cover_position or not numbers.distance(movement.get_position(entity), _cover_position): entities.trigger_event(entity, 'finish_turn') return movement.walk_to_position(entity, _cover_position[0], _cover_position[1], zones.get_active_astar_map(), zones.get_active_weight_map())
def can_see_position(entity, position): _solids = zones.get_active_solids(entity) if numbers.distance(movement.get_position(entity), position) > stats.get_vision(entity): return False for pos in shapes.line(movement.get_position(entity), position): if pos in _solids: return False return True
def get_cover_position(squad, member_id): _member = entities.get_entity(member_id) _best_coverage = {'position': None, 'score': 0} _inside = zones.get_active_inside_positions() if _member['movement']['path']['destination']: _hide_pos = _member['movement']['path']['destination'] else: _hide_pos = movement.get_position(_member) if _hide_pos in squad['position_map_scores']: _scores = squad['position_map_scores'][_hide_pos] _score = _scores['coverage'] + _scores['member_coverage'] if not _scores['targets'] and _score > 0: return _hide_pos for pos in squad['position_map_scores']: _scores = squad['position_map_scores'][pos] #TODO: Add or subtract here? Subtraction will make some NPCs run away from teammates _score = _scores['coverage'] + _scores['member_coverage'] if not pos in _inside: continue if _scores['targets'] or _score <= 0: continue if _score > _best_coverage['score']: _best_coverage['score'] = _score _best_coverage['position'] = pos[:] if not _best_coverage['position']: #print 'no good coverage position' return _x, _y = movement.get_position(_member) for coverage_pos in shapes.circle(_best_coverage['position'][0], _best_coverage['position'][1], 6): if not coverage_pos in squad['position_map_scores']: continue _c_dist = 10 * (1 - (numbers.distance(coverage_pos, (_x, _y)) / 3.0)) squad['position_map_scores'][coverage_pos][ 'member_coverage'] += _c_dist squad['position_map_scores'][ _best_coverage['position']]['member_coverage'] += 15 return _best_coverage['position']
def get_nearest_entity_in_list(entity, entity_list): _nearest_entity = {'entity': None, 'distance': 0} for entity_id in entity_list: _entity = entities.get_entity(entity_id) _distance = numbers.distance(movement.get_position(entity), movement.get_position(_entity)) if not _nearest_entity['entity'] or _distance < _nearest_entity['distance']: _nearest_entity['entity'] = _entity _nearest_entity['distance'] = _distance return _nearest_entity['entity']
def create_shoot_menu(entity, target_id): _tx, _ty = movement.get_position_via_id(target_id) _weapon = entities.get_entity(items.get_items_in_holder(entity, 'weapon')[0]) _menu = ui_menu.create(_tx-camera.X+2, _ty-camera.Y-4, title='Shoot') _accuracy = stats.get_accuracy(entity, _weapon['_id']) _x, _y = movement.get_position(entity) _direction = numbers.direction_to((_x, _y), (_tx, _ty)) _final_direction = _direction + (_accuracy * numbers.distance((_x, _y), (_tx, _ty))) _spray_accuracy = (100 * (_direction / float(_final_direction))) entities.trigger_event(_weapon, 'get_actions', menu=_menu) ui_menu.add_selectable(_menu, 'Spray (Acc: %.2d)' % _spray_accuracy, lambda: entities.trigger_event(entity, 'shoot', target_id=target_id) and settings.set_tick_mode('normal')) ui_menu.add_selectable(_menu, 'Snipe (Acc: %s)' % _accuracy, lambda: _)
def _bullet_effects(entity, x, y): _distance = numbers.distance((x, y), entity['start_position']) _target_distance = numbers.distance( (x, y), entity['end_position']) + numbers.clip(10 - _distance, 0, 10) _x, _y = movement.get_position(entity) _mod = (0.6 - (_distance / 35.0)) + random.uniform(-.1, .1) _alpha = numbers.clip(_mod, 0, 1) _crash_dist = 60 - (entity['speed'] * 2) if _alpha > 0: effects.vapor(x, y, start_alpha=_alpha) if _target_distance < 30: _size = int( round(2 * (1 - (1 * numbers.clip( numbers.clip(_target_distance, 0, 100) / 60.0, 0, 1)))) ) + random.randint(1, 2) if _distance > _crash_dist: _size = int(round(_size * (_crash_dist / float(_distance)))) if _size > 1: effects.light(_x, _y, _size, r=1.3, g=1.3, b=1.3)
def get_cover_position(squad, member_id): _member = entities.get_entity(member_id) _best_coverage = {'position': None, 'score': 0} _inside = zones.get_active_inside_positions() if _member['movement']['path']['destination']: _hide_pos = _member['movement']['path']['destination'] else: _hide_pos = movement.get_position(_member) if _hide_pos in squad['position_map_scores']: _scores = squad['position_map_scores'][_hide_pos] _score = _scores['coverage'] + _scores['member_coverage'] if not _scores['targets'] and _score > 0: return _hide_pos for pos in squad['position_map_scores']: _scores = squad['position_map_scores'][pos] #TODO: Add or subtract here? Subtraction will make some NPCs run away from teammates _score = _scores['coverage'] + _scores['member_coverage'] if not pos in _inside: continue if _scores['targets'] or _score <= 0: continue if _score > _best_coverage['score']: _best_coverage['score'] = _score _best_coverage['position'] = pos[:] if not _best_coverage['position']: #print 'no good coverage position' return _x, _y = movement.get_position(_member) for coverage_pos in shapes.circle(_best_coverage['position'][0], _best_coverage['position'][1], 6): if not coverage_pos in squad['position_map_scores']: continue _c_dist = 10 * (1 - (numbers.distance(coverage_pos, (_x, _y)) / 3.0)) squad['position_map_scores'][coverage_pos]['member_coverage'] += _c_dist squad['position_map_scores'][_best_coverage['position']]['member_coverage'] += 15 return _best_coverage['position']
def get_nearest_entity_in_list(entity, entity_list): _nearest_entity = {'entity': None, 'distance': 0} for entity_id in entity_list: _entity = entities.get_entity(entity_id) _distance = numbers.distance(movement.get_position(entity), movement.get_position(_entity)) if not _nearest_entity[ 'entity'] or _distance < _nearest_entity['distance']: _nearest_entity['entity'] = _entity _nearest_entity['distance'] = _distance return _nearest_entity['entity']
def walk_to_position(entity, x, y, astar_map, weight_map, avoid=[], smp=-1): _start_position = get_position(entity) _target_position = (x, y) if _start_position == _target_position: return False if smp == True or (smp == -1 and numbers.distance(_start_position, _target_position) > settings.SMP_MIN_PATH_DISTANCE): smp = settings.ALLOW_SMP if entity['movement']['path']['destination']: if not numbers.distance(entity['movement']['path']['destination'], _target_position): return False if smp == True: pathfinding.astar_mp(_start_position, _target_position, astar_map, weight_map, lambda path: set_path(entity, path), avoid=avoid) else: entity['movement']['path']['positions'] = pathfinding.astar(get_position(entity), _target_position, astar_map, weight_map, avoid=avoid) entity['movement']['path']['destination'] = _target_position entity['movement']['path']['refresh'] = False return True
def generate_shadow_map(width, height, solids, trees, inside): global SHADOWS SHADOWS = display.create_shader(width, height) SHADOWS[0] += 1 SHADOWS[1] += 1 SHADOWS[2] += 1 _taken = set() for x, y in solids: if (x, y) in trees: continue for y1 in range(-3, 4): for x1 in range(-3, 4): if (x + x1, y + y1) in solids or (x + x1, y + y1) in inside or ( x + x1, y + y1 ) in _taken or x + x1 >= width or y + y1 >= height: continue _shadow = numbers.clip( numbers.distance((x, y), (x + x1, y + y1)) / 5.0, .25, .6) + .25 if _shadow < SHADOWS[0][y + y1][x + x1]: SHADOWS[0][y + y1][x + x1] = _shadow SHADOWS[1][y + y1][x + x1] = _shadow SHADOWS[2][y + y1][x + x1] = _shadow _taken = set() for _x, _y in trees.keys(): _tree_size = float(trees[_x, _y]) for x, y in shapes.circle(_x, _y, int(_tree_size)): if (x, y) in solids or x >= width or y >= height or x < 0 or y < 0: continue _distance = numbers.float_distance((x, y), (_x, _y)) * 1.25 _shadow = numbers.clip(1 - ((_distance / _tree_size) + .25), .1, .9) SHADOWS[0][y][x] = numbers.clip(SHADOWS[0][y][x] - _shadow, .45, 1) SHADOWS[1][y][x] = numbers.clip(SHADOWS[1][y][x] - _shadow, .45, 1) SHADOWS[2][y][x] = numbers.clip(SHADOWS[2][y][x] - _shadow, .45, 1) return SHADOWS
def find_cover(entity): _squad = entities.get_entity(ai_factions.FACTIONS[entity['ai']['faction']] ['squads'][entity['ai']['squad']]) _cover_position = ai_squad_director.get_cover_position( _squad, entity['_id']) if not _cover_position or not numbers.distance( movement.get_position(entity), _cover_position): entities.trigger_event(entity, 'finish_turn') return movement.walk_to_position(entity, _cover_position[0], _cover_position[1], zones.get_active_astar_map(), zones.get_active_weight_map())
def frag_grenade_explode(entity): _x, _y = movement.get_position(entity) _damage = entity['damage'] _size = 3 * int(round((_damage * .01))) effects.explosion(_x, _y, _size) for entity_id in entities.get_entity_group('life'): _entity = entities.get_entity(entity_id) _distance = numbers.distance((_x, _y), movement.get_position(_entity)) if _distance - 1 > _size or not life.can_see_position(_entity, (_x, _y)): continue entities.trigger_event(_entity, 'hit', projectile=entity, damage_mod=1 - ((_distance - 1) / float(_size)))
def _get_item(entity, item_id, hold=False, weight=None): _item = entities.get_entity(item_id) _x, _y = movement.get_position(_item) _distance = numbers.distance(movement.get_position(entity), (_x, _y)) if weight: ai.set_meta_weight(entity, weight, 10*numbers.clip(_distance/30.0, 0, 1)) if _distance: movement.walk_to_position(entity, _x, _y, zones.get_active_astar_map(), zones.get_active_weight_map(), smp=True) else: if hold: life.get_and_hold_item(entity, item_id) else: life.get_and_store_item(entity, item_id)
def find_melee_position(entity): _target = entity['ai']['nearest_target'] _x, _y = entity['ai']['life_memory'][_target]['last_seen_at'] _closest_pos = {'pos': None, 'distance': 0} _solids = zones.get_active_solids(entity, ignore_entities=[_target]) for x, y in [(_x-1, _y), (_x+1, _y), (_x, _y-1), (_x, _y+1), (_x-1, _y-1), (_x+1, _y-1), (_x-1, _y+1), (_x+1, _y+1)]: if (x, y) in _solids: continue _distance = numbers.distance(movement.get_position(entity), (x, y)) if not _closest_pos['pos'] or _distance < _closest_pos['distance']: _closest_pos['distance'] = _distance _closest_pos['pos'] = (x, y) movement.walk_to_position(entity, _closest_pos['pos'][0], _closest_pos['pos'][1], zones.get_active_astar_map(), zones.get_active_weight_map())
def draw_raid_info(squad_id, camp_id): _camp = world_strategy.MAP['grid'][camp_id] _squad = entities.get_entity(squad_id) _travel_distance = numbers.distance(movement.get_position_via_id(squad_id), camp_id) _highest_speed = 0 _cost = ai_squads.get_attack_cost(_squad, camp_id) for member_id in _squad['members']: _member = entities.get_entity(member_id) _speed = movement.get_move_cost(_member) if _speed > _highest_speed: _highest_speed = _speed _travel_time = _travel_distance * (_highest_speed * 80) _time_string = '%s hours %s minutes' % (_travel_time / 60, _travel_time - ((_travel_time / 60) * 60)) _info = 'Right Click Camp to Confirm Order, ESC to cancel' if time.time() % 1 >= .5: _info_color = (200, 0, 0) else: _info_color = (200, 80, 80) display.write_string('ui_bar', (constants.WINDOW_WIDTH / 2) - (len(_info) / 2), 0, _info, fore_color=_info_color) display.write_string('ui_bar', 1, 1, 'Raid Order', fore_color=(200, 50, 70)) flavor_print(1, 3, [('Risk: ', 'Low', constants.STATUS_GOOD), ('Cost: $ ', '%i' % _cost, constants.STATUS_GOOD), ('Supplies needed: ', '%i' % 12, constants.STATUS_OK), ('Travel time: ', _time_string, constants.STATUS_OK)]) flavor_print(35, 3, [('Test value: ', 'Low', constants.STATUS_GOOD)])
def generate_shadow_map(width, height, solids, trees, inside): global SHADOWS SHADOWS = display.create_shader(width, height) SHADOWS[0] += 1 SHADOWS[1] += 1 SHADOWS[2] += 1 _taken = set() for x, y in solids: if (x, y) in trees: continue for y1 in range(-3, 4): for x1 in range(-3, 4): if (x+x1, y+y1) in solids or (x+x1, y+y1) in inside or (x+x1, y+y1) in _taken or x+x1 >= width or y+y1 >= height: continue _shadow = numbers.clip(numbers.distance((x, y), (x+x1, y+y1))/5.0, .25, .6) + .25 if _shadow < SHADOWS[0][y+y1][x+x1]: SHADOWS[0][y+y1][x+x1] = _shadow SHADOWS[1][y+y1][x+x1] = _shadow SHADOWS[2][y+y1][x+x1] = _shadow _taken = set() for _x, _y in trees.keys(): _tree_size = float(trees[_x, _y]) for x, y in shapes.circle(_x, _y, int(_tree_size)): if (x, y) in solids or x >= width or y >= height or x < 0 or y <0: continue _distance = numbers.float_distance((x, y), (_x, _y))*1.25 _shadow = numbers.clip(1 - ((_distance / _tree_size) + .25), .1, .9) SHADOWS[0][y][x] = numbers.clip(SHADOWS[0][y][x]-_shadow, .45, 1) SHADOWS[1][y][x] = numbers.clip(SHADOWS[1][y][x]-_shadow, .45, 1) SHADOWS[2][y][x] = numbers.clip(SHADOWS[2][y][x]-_shadow, .45, 1) return SHADOWS
def frag_grenade_explode(entity): _x, _y = movement.get_position(entity) _damage = entity['damage'] _size = 3 * int(round((_damage * .01))) effects.explosion(_x, _y, _size) for entity_id in entities.get_entity_group('life'): _entity = entities.get_entity(entity_id) _distance = numbers.distance((_x, _y), movement.get_position(_entity)) if _distance - 1 > _size or not life.can_see_position( _entity, (_x, _y)): continue entities.trigger_event(_entity, 'hit', projectile=entity, damage_mod=1 - ((_distance - 1) / float(_size)))
def handle_keyboard_input(): if controls.get_input_char_pressed('\t'): if settings.TICK_MODE == 'strategy': if ui_panel.ACTIVE_MENU: ui_panel.close() else: ui_panel.show_inventory(entity) else: _x, _y = movement.get_position(entity) camera.set_pos(_x - constants.MAP_VIEW_WIDTH/2, _y - constants.MAP_VIEW_HEIGHT/2) if controls.get_input_char_pressed('O'): settings.toggle_show_node_grid() elif controls.get_input_char_pressed('o'): settings.toggle_observer_mode() if controls.get_input_char_pressed('d'): _mx, _my = ui_cursor.get_map_position() for entity_id in entities.get_entity_group('life'): _entity = entities.get_entity(entity_id) if not numbers.distance((_mx, _my), movement.get_position(_entity)): _x, _y = ui_cursor.get_screen_position() _menu = ui_menu.create(_x, _y, title='Debug') ui_menu.add_selectable(_menu, 'Show Metas', lambda: _show_metas(_entity)) ui_menu.add_selectable(_menu, 'Kill', lambda: entities.trigger_event(_entity, 'kill')) ui_menu.add_selectable(_menu, 'Overwatch', lambda: ai_debugger.register(_entity)) break if controls.get_input_char_pressed('l'): _x, _y = ui_cursor.get_screen_position() _mx, _my = ui_cursor.get_map_position() _weight = zones.get_active_weight_map()[_my, _mx] _menu = ui_menu.create(_x, _y, title='Tile Info') ui_menu.add_selectable(_menu, 'Warp', lambda: entities.trigger_event(entity, 'set_position', x=_mx, y=_my)) ui_menu.add_selectable(_menu, 'Light', lambda: effects.light(_mx, _my, 15, r=random.uniform(1.0, 1.5), g=random.uniform(1.0, 1.5), light_map='static_lighting')) ui_menu.add_selectable(_menu, 'Weight: %s' % _weight, lambda: _)
def create_shoot_menu(entity, target_id): _tx, _ty = movement.get_position_via_id(target_id) _weapon = entities.get_entity( items.get_items_in_holder(entity, 'weapon')[0]) _menu = ui_menu.create(_tx - camera.X + 2, _ty - camera.Y - 4, title='Shoot') _accuracy = stats.get_accuracy(entity, _weapon['_id']) _x, _y = movement.get_position(entity) _direction = numbers.direction_to((_x, _y), (_tx, _ty)) _final_direction = _direction + (_accuracy * numbers.distance((_x, _y), (_tx, _ty))) _spray_accuracy = (100 * (_direction / float(_final_direction))) entities.trigger_event(_weapon, 'get_actions', menu=_menu) ui_menu.add_selectable( _menu, 'Spray (Acc: %.2d)' % _spray_accuracy, lambda: entities.trigger_event(entity, 'shoot', target_id=target_id ) and settings.set_tick_mode('normal')) ui_menu.add_selectable(_menu, 'Snipe (Acc: %s)' % _accuracy, lambda: _)
def _locate_npc_message(goal, member_id): _target_id = goal['target_id'] _member = entities.get_entity(member_id) _mission = entities.get_entity(goal['mission_id']) if not _target_id in _member['ai']['life_memory'] or not _member['ai'][ 'life_memory'][_target_id]['last_seen_at']: goal['message'] = 'Gather location info on target.' return if _member['ai']['life_memory'][_target_id]['is_dead']: goal['message'] = 'Confirmed: Target is dead.' entities.trigger_event(_member, 'complete_goal', mission_id=goal['mission_id'], goal_id=goal['_id']) elif _member['ai']['life_memory'][_target_id]['can_see']: goal['message'] = 'Target in line of sight.' entities.trigger_event(_member, 'complete_goal', mission_id=goal['mission_id'], goal_id=goal['_id']) elif _member['ai']['life_memory'][_target_id]['last_seen_at']: _direction = numbers.direction_to( movement.get_position(_member), _member['ai']['life_memory'][_target_id]['last_seen_at']) _distance = numbers.distance( movement.get_position(_member), _member['ai']['life_memory'][_target_id]['last_seen_at']) _real_direction = conversions.get_real_direction(_direction) _real_distance = conversions.get_real_distance(_distance) goal['message'] = 'Target last seen %s meters to the %s' % ( _real_distance, _real_direction) _member['ai']['life_memory'][_target_id]['mission_related'] = True
def draw_raid_info(squad_id, camp_id): _camp = world_strategy.MAP["grid"][camp_id] _squad = entities.get_entity(squad_id) _travel_distance = numbers.distance(movement.get_position_via_id(squad_id), camp_id) _highest_speed = 0 _cost = ai_squads.get_attack_cost(_squad, camp_id) for member_id in _squad["members"]: _member = entities.get_entity(member_id) _speed = movement.get_move_cost(_member) if _speed > _highest_speed: _highest_speed = _speed _travel_time = _travel_distance * (_highest_speed * 80) _time_string = "%s hours %s minutes" % (_travel_time / 60, _travel_time - ((_travel_time / 60) * 60)) _info = "Right Click Camp to Confirm Order, ESC to cancel" if time.time() % 1 >= 0.5: _info_color = (200, 0, 0) else: _info_color = (200, 80, 80) display.write_string("ui_bar", (constants.WINDOW_WIDTH / 2) - (len(_info) / 2), 0, _info, fore_color=_info_color) display.write_string("ui_bar", 1, 1, "Raid Order", fore_color=(200, 50, 70)) flavor_print( 1, 3, [ ("Risk: ", "Low", constants.STATUS_GOOD), ("Cost: $ ", "%i" % _cost, constants.STATUS_GOOD), ("Supplies needed: ", "%i" % 12, constants.STATUS_OK), ("Travel time: ", _time_string, constants.STATUS_OK), ], ) flavor_print(35, 3, [("Test value: ", "Low", constants.STATUS_GOOD)])
def find_melee_position(entity): _target = entity['ai']['nearest_target'] _x, _y = entity['ai']['life_memory'][_target]['last_seen_at'] _closest_pos = {'pos': None, 'distance': 0} _solids = zones.get_active_solids(entity, ignore_entities=[_target]) for x, y in [(_x - 1, _y), (_x + 1, _y), (_x, _y - 1), (_x, _y + 1), (_x - 1, _y - 1), (_x + 1, _y - 1), (_x - 1, _y + 1), (_x + 1, _y + 1)]: if (x, y) in _solids: continue _distance = numbers.distance(movement.get_position(entity), (x, y)) if not _closest_pos['pos'] or _distance < _closest_pos['distance']: _closest_pos['distance'] = _distance _closest_pos['pos'] = (x, y) movement.walk_to_position(entity, _closest_pos['pos'][0], _closest_pos['pos'][1], zones.get_active_astar_map(), zones.get_active_weight_map())
def _get_item(entity, item_id, hold=False, weight=None): _item = entities.get_entity(item_id) _x, _y = movement.get_position(_item) _distance = numbers.distance(movement.get_position(entity), (_x, _y)) if weight: ai.set_meta_weight(entity, weight, 10 * numbers.clip(_distance / 30.0, 0, 1)) if _distance: movement.walk_to_position(entity, _x, _y, zones.get_active_astar_map(), zones.get_active_weight_map(), smp=True) else: if hold: life.get_and_hold_item(entity, item_id) else: life.get_and_store_item(entity, item_id)
def get_push_position(squad, member_id): _member = entities.get_entity(member_id) _best_vantage = {'position': None, 'score': 1000} _vision = stats.get_vision(_member) _engage_range = int(round(_vision * .75)) for pos in squad['position_map_scores']: _scores = squad['position_map_scores'][pos] _score = _scores['vantage'] + _scores['member_coverage'] if not _scores['targets'] or _score < 6 or _score > _engage_range: continue if _score < _best_vantage['score']: _best_vantage['score'] = _score _best_vantage['position'] = pos[:] if not _best_vantage['position']: _member['ai']['meta']['has_firing_position'] = False return _x, _y = movement.get_position(_member) for coverage_pos in shapes.circle(_best_vantage['position'][0], _best_vantage['position'][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'][ _best_vantage['position']]['member_coverage'] += 20 return _best_vantage['position']
def build_life_list(entity): entity['ai']['visible_targets'] = [] _nearest_target = {'target_id': None, 'distance': 0} _solids = zones.get_active_solids(entity) _visible_life = set() _vision = stats.get_vision(entity) _visible_by_friendlies = [entities.get_entity(e)['ai']['visible_targets'] for e in entity['ai']['life_memory'] if not entity['ai']['life_memory'][e]['is_target'] and e in entities.ENTITIES] #Warning: Makes AI super smart _visible_by_friendlies = [item for sublist in _visible_by_friendlies for item in sublist] for entity_id in entities.get_entity_group('life'): if entity['_id'] == entity_id: continue _target = entities.get_entity(entity_id) if not entity_id in entity['ai']['life_memory']: life.create_life_memory(entity, entity_id) if not ai_factions.is_enemy(entity, entity_id): _visible = True else: if numbers.distance(movement.get_position(entity), movement.get_position(_target)) > _vision: if entity['ai']['life_memory'][entity_id]['can_see'] and ai_factions.is_enemy(entity, _target['_id']): entities.trigger_event(entity, 'target_lost', target_id=entity_id) if entity_id in _visible_by_friendlies: entity['ai']['life_memory'][entity_id]['in_los'] = False entity['ai']['life_memory'][entity_id]['can_see'] = True _visible = True else: entity['ai']['life_memory'][entity_id]['can_see'] = False entity['ai']['life_memory'][entity_id]['in_los'] = False if entity_id in entity['ai']['visible_life']: entity['ai']['visible_life'].remove(entity_id) _visible = False else: for pos in shapes.line(movement.get_position(entity), movement.get_position(_target)): if pos in _solids: if entity['ai']['life_memory'][entity_id]['can_see'] and ai_factions.is_enemy(entity, _target['_id']): entities.trigger_event(entity, 'target_lost', target_id=entity_id) if entity_id in _visible_by_friendlies: entity['ai']['life_memory'][entity_id]['in_los'] = False entity['ai']['life_memory'][entity_id]['can_see'] = True _visible = True else: entity['ai']['life_memory'][entity_id]['can_see'] = False entity['ai']['life_memory'][entity_id]['in_los'] = False if entity_id in entity['ai']['visible_life']: entity['ai']['visible_life'].remove(entity_id) _visible = False break else: entity['ai']['life_memory'][entity_id]['in_los'] = True _visible = True if not _visible and entity['ai']['life_memory'][entity_id]['seen_time'] > 0: _visible = True entity['ai']['life_memory'][entity_id]['in_los'] = False entity['ai']['life_memory'][entity_id]['can_see'] = True entity['ai']['life_memory'][entity_id]['seen_time'] -= 1 if entity_id in entity['ai']['visible_life']: entity['ai']['visible_life'].remove(entity_id) elif not _visible and entity_id in entity['ai']['visible_life']: entity['ai']['visible_life'].remove(entity_id) if _visible: _previous_last_seen_at = entity['ai']['life_memory'][entity_id]['last_seen_at'] _target_position = movement.get_position(_target)[:] entity['ai']['life_memory'][entity_id]['is_lost'] = False if entity['ai']['life_memory'][entity_id]['in_los']: if entity['ai']['life_memory'][entity_id]['seen_time'] < 30: entity['ai']['life_memory'][entity_id]['seen_time'] += 1 else: entity['ai']['life_memory'][entity_id]['seen_time'] -= 1 if entity['ai']['life_memory'][entity_id]['seen_time'] < 0 and entity_id in entity['ai']['visible_life']: entity['ai']['visible_life'].remove(entity_id) entity['ai']['life_memory'][entity_id]['in_los'] = False if movement.get_position(_target) == _previous_last_seen_at: _new_last_seen_at = _previous_last_seen_at else: _new_last_seen_at = _target_position _is_target = ai_factions.is_enemy(entity, _target['_id']) _profile = {'distance': numbers.distance(movement.get_position(entity), movement.get_position(_target)), 'is_target': _is_target, 'is_armed': items.get_items_in_holder(_target, 'weapon'), 'is_lost': False, 'can_see': True, 'last_seen_at': _new_last_seen_at, 'last_seen_velocity': None} if not entity_id in entity['ai']['visible_life']: entities.trigger_event(entity, 'new_target_spotted', target_id=entity_id) if entity['ai']['life_memory'][entity_id]['in_los']: entity['ai']['visible_life'].add(entity_id) if _is_target: ai_flow.register_combat(entity, entity_id) if _is_target: entity['ai']['targets'].add(entity_id) _distance = numbers.distance(movement.get_position(entity), movement.get_position_via_id(entity_id)) if not _nearest_target['target_id'] or _distance < _nearest_target['distance']: _nearest_target['distance'] = _distance _nearest_target['target_id'] = entity_id if entity['ai']['life_memory'][entity_id]['last_seen_at']: _last_seen_at = entity['ai']['life_memory'][entity_id]['last_seen_at'][:] _velocity = (_profile['last_seen_at'][0]-_last_seen_at[0], _profile['last_seen_at'][1]-_last_seen_at[1]) _profile['last_seen_velocity'] = _velocity else: _profile['last_seen_velocity'] = None if not entity['ai']['life_memory'][entity_id]['can_see'] and _is_target: _could_not_see_target_before = True else: _could_not_see_target_before = False entity['ai']['life_memory'][entity_id].update(_profile) if _could_not_see_target_before: entities.trigger_event(entity, 'target_found', target_id=entity_id) #TODO: What? #for t in entity['ai']['life_memory']: # if not 'is_lost' in entity['ai']['life_memory'][t]: # print entity['ai']['life_memory'][t] entity['ai']['visible_targets'] = list(entity['ai']['visible_life'] & entity['ai']['targets']) entity['ai']['targets_to_search'] = [t for t in entity['ai']['life_memory'].keys() if entity['ai']['life_memory'][t]['is_lost'] and not entity['ai']['life_memory'][t]['searched_for'] and t in entities.ENTITIES] if _nearest_target['target_id']: if not entity['ai']['nearest_target'] == _nearest_target['target_id']: entity['ai']['meta']['has_firing_position'] = True entity['ai']['nearest_target'] = _nearest_target['target_id'] elif entity['ai']['targets']: for target_id in list(entity['ai']['targets']): _target = entity['ai']['life_memory'][target_id] if not target_id in entities.ENTITIES or _target['is_lost']: entity['ai']['targets'].remove(target_id) continue _distance = numbers.distance(movement.get_position(entity), _target['last_seen_at']) if not _nearest_target['target_id'] or _distance < _nearest_target['distance']: _nearest_target['target_id'] = target_id _nearest_target['distance'] = _distance if not entity['ai']['nearest_target'] == _nearest_target['target_id']: entity['ai']['meta']['has_firing_position'] = True entity['ai']['nearest_target'] = _nearest_target['target_id']
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
def update_position_maps(squad): _t = time.time() _coverage_positions = squad['coverage_positions'] _known_targets = squad['known_targets'] _known_squads = squad['known_squads'] _known_targets_left_to_check = _known_targets.copy() _score_map = { pos: { 'coverage': 0, 'vantage': 100, 'member_coverage': 0, 'danger': 0, 'targets': [], 'owned': False } for pos in _coverage_positions } for faction_name, squad_id in _known_squads: if not squad_id in ai_factions.FACTIONS[faction_name]['squads']: continue _squad = entities.get_entity( ai_factions.FACTIONS[faction_name]['squads'][squad_id]) _member_set = set(_squad['members']) _check_members = _known_targets_left_to_check & _member_set _known_targets_left_to_check = _known_targets_left_to_check - _member_set for target_id in list(_check_members): _target_position = movement.get_position_via_id(target_id) _closest_member = {'distance': 0, 'member_id': None} for member_id in squad['members']: _member_position = movement.get_position_via_id(member_id) _distance = numbers.clip( numbers.distance(_target_position, _member_position), 0, 60) if not _closest_member[ 'member_id'] or _distance < _closest_member['distance']: _closest_member['distance'] = _distance _closest_member['member_id'] = member_id _target_coverage_map = _squad['member_position_maps'][target_id] _overlap_positions = _coverage_positions & _target_coverage_map _cover_positions = _coverage_positions - _target_coverage_map if not _closest_member['member_id']: logging.warning( 'Couldn\'t find closest member for target during squad positioning.' ) continue _closest_member_pos = movement.get_position_via_id( _closest_member['member_id']) for pos in _overlap_positions: _distance = numbers.distance(_closest_member_pos, pos) if _distance < _score_map[pos]['vantage']: _score_map[pos]['vantage'] = _distance #_score_map[pos]['danger'] = 60 - _distance _score_map[pos]['targets'].append(target_id) for pos in _cover_positions: _distance = numbers.distance(_closest_member_pos, pos) if _distance > _score_map[pos]['coverage']: _score_map[pos]['coverage'] = _distance _score_map[pos]['danger'] = 60 - _distance squad['position_map_scores'] = _score_map
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
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"]
def generate(width, height): _weight_map, _tile_map, _solids, _node_grid = mapgen.create_map( width, height) _zoom = .95 _noise = tcod.noise_new(3) _low_grass = 25 _fsl = {} _building_space = set() _walls = set() _possible_trees = set() _river_start_x = random.randint(int(round(width * .35)), int(round(width * .65))) _river_start_y = 0 #random.randint(int(round(height * .15)), int(round(height * .85))) _x = _river_start_x _y = _river_start_y _px, _py = _river_start_x, _river_start_y _river_direction = 270 _turn_rate = random.randint(-1, 1) _river_tiles = set() _river_size = random.randint(7, 10) _ground_tiles = set() _possible_camps = set() while 1: for i in range(4, 10): for __x, __y in shapes.circle(_x, _y, _river_size): if __x < 0 or __y < 0 or __x >= width or __y >= height or ( __x, __y) in _solids: continue _river_tiles.add((__x, __y)) _tile = tiles.swamp_water(__x, __y) _tile_map[__y][__x] = _tile _weight_map[__y][__x] = _tile['w'] _river_direction += _turn_rate _xv, _yv = numbers.velocity(_river_direction, 1) _px += _xv _py += _yv _x = int(round(_px)) _y = int(round(_py)) if _x < 0 or _y < 0 or _x >= width or _y >= height or ( _x, _y) in _solids: break if _x < 0 or _y < 0 or _x >= width or _y >= height: break _turn_rate = random.uniform(-2.5, 2.5) _river_size = numbers.clip(_river_size + random.randint(-1, 1), 7, 10) for y in range(height): for x in range(width): if (x, y) in _river_tiles: continue _tile = tiles.grass(x, y) _tile_map[y][x] = _tile _weight_map[y][x] = _tile['w'] _ground_tiles.add((x, y)) tcod.noise_set_type(_noise, tcod.NOISE_WAVELET) for y in range(height): for x in range(width): if (x, y) in _river_tiles: continue _noise_values = [(_zoom * x / (constants.MAP_VIEW_WIDTH)), (_zoom * y / (constants.MAP_VIEW_HEIGHT))] _noise_value = 100 * tcod.noise_get_turbulence( _noise, _noise_values, tcod.NOISE_WAVELET) if _low_grass <= _noise_value <= 100: _tile = tiles.tall_grass(x, y) if _noise_value >= 40: if not x < width * .15 and not x > width * .85 and not y < height * .15 and not y > height * .85: _possible_camps.add((x, y)) if random.uniform(0, 1) > .5: _possible_trees.add((x, y)) elif _noise_value >= _low_grass - 10 and 10 * random.uniform( 0, 1) > _low_grass - _noise_value: _tile = tiles.grass(x, y) else: _tile = tiles.rock(x, y) _solids.add((x, y)) _tile_map[y][x] = _tile _weight_map[y][x] = _tile['w'] _trees = {} _tree_plots = _possible_trees - _solids - _river_tiles _used_trees = random.sample( _tree_plots, numbers.clip(int(round((width * height) * .002)), 0, len(_tree_plots))) for x, y in _used_trees: _size = random.randint(1, 3) for _x, _y in shapes.circle(x, y, _size): if _x < 0 or _y < 0 or _x >= width or _y >= height or ( _x, _y) in _solids: break _tile = tiles.tree(_x, _y) _weight_map[_y][_x] = _tile['w'] _tile_map[_y][_x] = _tile _trees[_x, _y] = random.uniform(2, 3.5) * _size _solids.add((_x, _y)) _ground_tiles = _ground_tiles - _solids _plot_pole_x, _plot_pole_y = width / 2, height / 2 _bushes = random.sample( _ground_tiles, numbers.clip(int(round((width * height) * .0003)), 0, len(_ground_tiles))) _camps = set() while len(_possible_camps): _camp_1 = random.choice(list(_possible_camps)) _possible_camps.remove(_camp_1) _camps.add(_camp_1) for camp_2 in _possible_camps.copy(): _dist = numbers.distance(_camp_1, camp_2) if _dist <= 250: _possible_camps.remove(camp_2) for x, y in _bushes: _walker_x = x _walker_y = y _last_dir = -2, -2 for i in range(random.randint(10, 15)): _tile = tiles.tree(_walker_x, _walker_y) _weight_map[_walker_y][_walker_x] = _tile['w'] _tile_map[_walker_y][_walker_x] = _tile _dir = random.randint(-1, 1), random.randint(-1, 1) _n_x = _walker_x + _dir[0] _n_y = _walker_y + _dir[1] if _n_x < 0 or _n_y < 0 or _n_x >= width or _n_y >= height or ( _n_x, _n_y) in _solids: break _last_dir = _dir[0] * -1, _dir[0] * -1 _walker_x = _n_x _walker_y = _n_y _camp_info = {} for c_x, c_y in _camps: _building_walls = random.sample(['north', 'south', 'east', 'west'], random.randint(2, 3)) _broken_walls = random.sample( _building_walls, numbers.clip(random.randint(0, 3), 0, len(_building_walls))) _camp = {'center': (c_x, c_y)} _camp_ground = [] for y in range(-10, 10 + 1): for x in range(-10, 10 + 1): _x = x + c_x _y = y + c_y if (_x, _y) in _solids or (_x, _y) in _river_tiles: continue if (x == -10 and 'west' in _building_walls) or ( y == -10 and 'north' in _building_walls) or ( x == 10 and 'east' in _building_walls) or ( y == 10 and 'south' in _building_walls): if x == -10 and 'west' in _building_walls and 'west' in _broken_walls and random.uniform( 0, 1) > .75: continue if x == 10 and 'east' in _building_walls and 'east' in _broken_walls and random.uniform( 0, 1) > .75: continue if y == -10 and 'north' in _building_walls and 'north' in _broken_walls and random.uniform( 0, 1) > .75: continue if y == 10 and 'south' in _building_walls and 'south' in _broken_walls and random.uniform( 0, 1) > .75: continue _tile = tiles.wooden_fence(_x, _y) _weight_map[_y][_x] = _tile['w'] _tile_map[_y][_x] = _tile _solids.add((_x, _y)) elif (x > -10 and x <= 10) and (y > -10 and y <= 10): _camp_ground.append((_x, _y)) _camp['ground'] = _camp_ground[:] _camp_info[c_x, c_y] = _camp mapgen.build_node_grid(_node_grid, _solids) for c_x, c_y in _camps: mapgen.add_plot_pole(c_x, c_y, 40, _solids) _fsl = { 'Terrorists': { 'bases': 1, 'squads': 0, 'trader': False, 'type': life.human_runner } } # #'Militia': {'bases': 0, 'squads': 1, 'trader': False, 'type': life.human_bandit}, # 'Wild Dogs': {'bases': 0, 'squads': 1, 'trader': False, 'type': life.wild_dog}} return width, height, _node_grid, mapgen.NODE_SETS.copy( ), _weight_map, _tile_map, _solids, _fsl, _trees, _building_space - _walls
def _animal_logic(entity): if timers.has_timer_with_name(entity, "passout"): return ai_visuals.build_item_list(entity) ai_visuals.build_life_list(entity) _old_meta = entity["ai"]["meta"].copy() entity["ai"]["meta"]["in_engagement"] = len(entity["ai"]["targets"]) > 0 entity["ai"]["meta"]["in_enemy_los"] = ( len([t for t in entity["ai"]["targets"] if entity["ai"]["life_memory"][t]["in_los"]]) > 0 ) 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)) entity["ai"]["meta"]["is_target_near"] = _target_distance <= 25 if not entity["ai"]["meta"]["in_enemy_los"] and life.can_see_position( entity, entity["ai"]["life_memory"][_target]["last_seen_at"] ): entity["ai"]["meta"]["has_lost_target"] = entity["ai"]["meta"]["is_target_near"] elif 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"]["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'] = skeleton.has_critical_injury(entity) entity["ai"]["meta"]["is_injured"] = skeleton.has_critical_injury(entity) entity["ai"]["meta"]["is_panicked"] = entity["ai"]["meta"]["is_injured"] if entity["ai"]["is_player"]: return _goap = _handle_goap(entity) if not _goap: entity["ai"]["current_action"] = "idle" return _plan = _goap[0] _plan["planner"].trigger_callback(entity, _plan["actions"][0]["name"]) # print time.time() - _t if not entity["ai"]["last_action"] == _plan["actions"][0]["name"]: logging.debug("%s: %s -> %s" % (entity["_id"], entity["ai"]["last_action"], _plan["actions"][0]["name"])) entity["ai"]["last_action"] = _plan["actions"][0]["name"] entity["ai"]["current_action"] = _plan["actions"][0]["name"]
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) * .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']
def get_attack_cost(entity, camp_id): return numbers.distance(movement.get_position(entity), camp_id) * 125
def generate(width, height): _weight_map, _tile_map, _solids, _node_grid = mapgen.create_map(width, height) _zoom = .95 _noise = tcod.noise_new(3) _low_grass = 25 _fsl = {} _building_space = set() _walls = set() _possible_trees = set() _river_start_x = random.randint(int(round(width * .35)), int(round(width * .65))) _river_start_y = 0#random.randint(int(round(height * .15)), int(round(height * .85))) _x = _river_start_x _y = _river_start_y _px, _py = _river_start_x, _river_start_y _river_direction = 270 _turn_rate = random.randint(-1, 1) _river_tiles = set() _river_size = random.randint(7, 10) _ground_tiles = set() _possible_camps = set() while 1: for i in range(4, 10): for __x, __y in shapes.circle(_x, _y, _river_size): if __x < 0 or __y < 0 or __x >= width or __y >= height or (__x, __y) in _solids: continue _river_tiles.add((__x, __y)) _tile = tiles.swamp_water(__x, __y) _tile_map[__y][__x] = _tile _weight_map[__y][__x] = _tile['w'] _river_direction += _turn_rate _xv, _yv = numbers.velocity(_river_direction, 1) _px += _xv _py += _yv _x = int(round(_px)) _y = int(round(_py)) if _x < 0 or _y < 0 or _x >= width or _y >= height or (_x, _y) in _solids: break if _x < 0 or _y < 0 or _x >= width or _y >= height: break _turn_rate = random.uniform(-2.5, 2.5) _river_size = numbers.clip(_river_size + random.randint(-1, 1), 7, 10) for y in range(height): for x in range(width): if (x, y) in _river_tiles: continue _tile = tiles.grass(x, y) _tile_map[y][x] = _tile _weight_map[y][x] = _tile['w'] _ground_tiles.add((x, y)) tcod.noise_set_type(_noise, tcod.NOISE_WAVELET) for y in range(height): for x in range(width): if (x, y) in _river_tiles: continue _noise_values = [(_zoom * x / (constants.MAP_VIEW_WIDTH)), (_zoom * y / (constants.MAP_VIEW_HEIGHT))] _noise_value = 100 * tcod.noise_get_turbulence(_noise, _noise_values, tcod.NOISE_WAVELET) if _low_grass <= _noise_value <= 100: _tile = tiles.tall_grass(x, y) if _noise_value >= 40: if not x < width * .15 and not x > width * .85 and not y < height * .15 and not y > height * .85: _possible_camps.add((x, y)) if random.uniform(0, 1) > .5: _possible_trees.add((x, y)) elif _noise_value >= _low_grass - 10 and 10 * random.uniform(0, 1) > _low_grass-_noise_value: _tile = tiles.grass(x, y) else: _tile = tiles.rock(x, y) _solids.add((x, y)) _tile_map[y][x] = _tile _weight_map[y][x] = _tile['w'] _trees = {} _tree_plots = _possible_trees - _solids - _river_tiles _used_trees = random.sample(_tree_plots, numbers.clip(int(round((width * height) * .002)), 0, len(_tree_plots))) for x, y in _used_trees: _size = random.randint(1, 3) for _x, _y in shapes.circle(x, y, _size): if _x < 0 or _y < 0 or _x >= width or _y >= height or (_x, _y) in _solids: break _tile = tiles.tree(_x, _y) _weight_map[_y][_x] = _tile['w'] _tile_map[_y][_x] = _tile _trees[_x, _y] = random.uniform(2, 3.5) * _size _solids.add((_x, _y)) _ground_tiles = _ground_tiles - _solids _plot_pole_x, _plot_pole_y = width/2, height/2 _bushes = random.sample(_ground_tiles, numbers.clip(int(round((width * height) * .0003)), 0, len(_ground_tiles))) _camps = set() while len(_possible_camps): _camp_1 = random.choice(list(_possible_camps)) _possible_camps.remove(_camp_1) _camps.add(_camp_1) for camp_2 in _possible_camps.copy(): _dist = numbers.distance(_camp_1, camp_2) if _dist <= 250: _possible_camps.remove(camp_2) for x, y in _bushes: _walker_x = x _walker_y = y _last_dir = -2, -2 for i in range(random.randint(10, 15)): _tile = tiles.tree(_walker_x, _walker_y) _weight_map[_walker_y][_walker_x] = _tile['w'] _tile_map[_walker_y][_walker_x] =_tile _dir = random.randint(-1, 1), random.randint(-1, 1) _n_x = _walker_x + _dir[0] _n_y = _walker_y + _dir[1] if _n_x < 0 or _n_y < 0 or _n_x >= width or _n_y >= height or (_n_x, _n_y) in _solids: break _last_dir = _dir[0] * -1, _dir[0] * -1 _walker_x = _n_x _walker_y = _n_y _camp_info = {} for c_x, c_y in _camps: _building_walls = random.sample(['north', 'south', 'east', 'west'], random.randint(2, 3)) _broken_walls = random.sample(_building_walls, numbers.clip(random.randint(0, 3), 0, len(_building_walls))) _camp = {'center': (c_x, c_y)} _camp_ground = [] for y in range(-10, 10+1): for x in range(-10, 10+1): _x = x + c_x _y = y + c_y if (_x, _y) in _solids or (_x, _y) in _river_tiles: continue if (x == -10 and 'west' in _building_walls) or (y == -10 and 'north' in _building_walls) or (x == 10 and 'east' in _building_walls) or (y == 10 and 'south' in _building_walls): if x == -10 and 'west' in _building_walls and 'west' in _broken_walls and random.uniform(0, 1) > .75: continue if x == 10 and 'east' in _building_walls and 'east' in _broken_walls and random.uniform(0, 1) > .75: continue if y == -10 and 'north' in _building_walls and 'north' in _broken_walls and random.uniform(0, 1) > .75: continue if y == 10 and 'south' in _building_walls and 'south' in _broken_walls and random.uniform(0, 1) > .75: continue _tile = tiles.wooden_fence(_x, _y) _weight_map[_y][_x] = _tile['w'] _tile_map[_y][_x] = _tile _solids.add((_x, _y)) elif (x > -10 and x <= 10) and (y > -10 and y <= 10): _camp_ground.append((_x, _y)) _camp['ground'] = _camp_ground[:] _camp_info[c_x, c_y] = _camp mapgen.build_node_grid(_node_grid, _solids) for c_x, c_y in _camps: mapgen.add_plot_pole(c_x, c_y, 40, _solids) _fsl = {'Terrorists': {'bases': 1, 'squads': 0, 'trader': False, 'type': life.human_runner}} # #'Militia': {'bases': 0, 'squads': 1, 'trader': False, 'type': life.human_bandit}, # 'Wild Dogs': {'bases': 0, 'squads': 1, 'trader': False, 'type': life.wild_dog}} return width, height, _node_grid, mapgen.NODE_SETS.copy(), _weight_map, _tile_map, _solids, _fsl, _trees, _building_space - _walls
def add_plot_pole(x, y, radius, solids, cell_split=3.0, debug=False): global NODE_SET_ID _node_set = set() _min_x = 999999999 _max_x = 0 _min_y = 999999999 _max_y = 0 for node_pos in list(UNCLAIMED_NODES): if numbers.distance((x, y), node_pos) > radius: continue if node_pos[0] < _min_x: _min_x = node_pos[0] if node_pos[0] > _max_x: _max_x = node_pos[0] if node_pos[1] < _min_y: _min_y = node_pos[1] if node_pos[1] > _max_y: _max_y = node_pos[1] _node_set.add(node_pos) _map = numpy.ones(((_max_y - _min_y) + 1, (_max_x - _min_x) + 1)) for _x, _y in solids: if _x >= _max_x or _x <= _min_x or _y >= _max_y or _y <= _min_y: continue _map[int(round((_y - _min_y))), int(round((_x - _min_x)))] = -2 NODE_SETS[NODE_SET_ID] = { 'owner': None, 'nodes': _node_set, 'center': (x, y), 'astar_map': _map, 'min_x': _min_x, 'min_y': _min_y, 'cell_split': float(cell_split), 'weight_map': numpy.ones(((_max_y - _min_y) + 1, (_max_x - _min_x) + 1), dtype=numpy.int16) } NODE_SET_ID += 1 if debug: for y in range(_max_y - _min_y): for x in range(_max_x - _min_x): _val = int(round(_map[y, x])) if _val == -2: print '#', elif _val == 1: print '.', print return NODE_SET_ID - 1
def _animal_logic(entity): if timers.has_timer_with_name(entity, 'passout'): return ai_visuals.build_item_list(entity) ai_visuals.build_life_list(entity) _old_meta = entity['ai']['meta'].copy() entity['ai']['meta']['in_engagement'] = len(entity['ai']['targets']) > 0 entity['ai']['meta']['in_enemy_los'] = len([ t for t in entity['ai']['targets'] if entity['ai']['life_memory'][t]['in_los'] ]) > 0 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)) entity['ai']['meta']['is_target_near'] = _target_distance <= 25 if not entity['ai']['meta']['in_enemy_los'] and life.can_see_position( entity, entity['ai']['life_memory'][_target]['last_seen_at']): entity['ai']['meta']['has_lost_target'] = entity['ai']['meta'][ 'is_target_near'] elif 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']['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'] = skeleton.has_critical_injury(entity) entity['ai']['meta']['is_injured'] = skeleton.has_critical_injury(entity) entity['ai']['meta']['is_panicked'] = entity['ai']['meta']['is_injured'] if entity['ai']['is_player']: return _goap = _handle_goap(entity) if not _goap: entity['ai']['current_action'] = 'idle' return _plan = _goap[0] _plan['planner'].trigger_callback(entity, _plan['actions'][0]['name']) #print time.time() - _t if not entity['ai']['last_action'] == _plan['actions'][0]['name']: logging.debug('%s: %s -> %s' % (entity['_id'], entity['ai']['last_action'], _plan['actions'][0]['name'])) entity['ai']['last_action'] = _plan['actions'][0]['name'] entity['ai']['current_action'] = _plan['actions'][0]['name']
def search_for_target(entity): _lost_targets = entity['ai']['targets_to_search'] _inside = zones.get_active_inside_positions() if not _lost_targets: print 'Trying to search with no lost targets' return _closest_target = {'distance': 0, 'target_id': None} for target_id in _lost_targets: _memory = entity['ai']['life_memory'][target_id] _distance = numbers.distance(movement.get_position(entity), _memory['last_seen_at']) if not _closest_target['target_id'] or _distance < _closest_target['distance']: _closest_target['target_id'] = target_id _closest_target['distance'] = _distance _target = entities.get_entity(_closest_target['target_id']) _solids = zones.get_active_solids(entity) if flags.has_flag(entity, 'search_nodes'): _search_for_target(entity, _target['_id']) return _x, _y = movement.get_position(entity) _tx, _ty = entity['ai']['life_memory'][_target['_id']]['last_seen_at'] _nodes_to_search = {} if entity['ai']['life_memory'][_target['_id']]['last_seen_velocity']: _vx, _vy = entity['ai']['life_memory'][_target['_id']]['last_seen_velocity'] _tx + _vx*6 _ty + _vy*6 entities.trigger_event(entity, 'set_flag', flag='search_nodes', value=_nodes_to_search) for node_x, node_y in zones.get_active_node_grid(): _distance = numbers.distance((_tx, _ty), (node_x, node_y)) if _distance >= 30: continue if not (node_x, node_y) in _inside: continue _continue = False for pos in shapes.line((_tx, _ty), (node_x, node_y)): if pos in _solids: _continue = True break if _continue: continue if _distance in _nodes_to_search: if not (node_x, node_y) in _nodes_to_search[_distance]: _nodes_to_search[_distance].append((node_x, node_y)) else: _nodes_to_search[_distance] = [(node_x, node_y)]