def create_action_menu(entity, x, y, on_path=False): _menu = ui_menu.create(ui_cursor.CURSOR['tile']['x']+2, ui_cursor.CURSOR['tile']['y']-1, title='Context') if items.get_items_in_holder(entity, 'weapon'): ui_menu.add_selectable(_menu, 'Shoot', lambda: select_target(x, y, on_path)) ui_menu.add_selectable(_menu, 'Reload', lambda: create_action_node(entity, x, y, 30, lambda: entities.trigger_event(entity, 'reload'), name='Reload', on_path=on_path)) ui_menu.add_selectable(_menu, 'Crouch', lambda: create_action_node(entity, x, y, 30, lambda: entities.trigger_event(entity, 'set_motion', motion='crouch'), name='Crouch', on_path=on_path)) ui_menu.add_selectable(_menu, 'Crawl', lambda: create_action_node(entity, x, y, 30, lambda: entities.trigger_event(entity, 'set_motion', motion='crawl'), name='Prone', on_path=on_path)) ui_menu.add_selectable(_menu, 'Stand', lambda: create_action_node(entity, x, y, 30, lambda: entities.trigger_event(entity, 'set_motion', motion='stand'), name='Stand', on_path=on_path))
def show_weapons(entity): global ACTIVE_MENU, REDRAW_TIMES _holder_menu = ui_menu.create(1, 1, title='Weapons', surface='ui_inventory', click_offset=(constants.MAP_VIEW_WIDTH-35, 0)) ACTIVE_MENU = _holder_menu REDRAW_TIMES = 3 _equipped_weapon = items.get_items_in_holder(entity, 'weapon') _weapons = [] if _equipped_weapon: _weapons.append(_equipped_weapon[0]) for item_id in items.get_items_matching(entity, {'type': 'weapon'}): if item_id in _weapons: continue _weapons.add(item_id) for item_id in _weapons: _item = entities.get_entity(item_id) entities.trigger_event(_item, 'get_display_name') if item_id in _equipped_weapon: _fg = (245, 245, 245) else: _fg = (230, 230, 230) ui_menu.add_selectable(_holder_menu, _item['stats']['display_name'], show_weapon_menu, fore_color=_fg, item_id=item_id)
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))
def reload_weapon(entity): if timers.has_timer_with_name(entity, 'Reloading'): return _weapon = items.get_items_in_holder(entity, 'weapon')[0] _ammo = items.get_items_matching(entity, {'type': 'ammo'})[0] entities.trigger_event(entity, 'create_timer', time=30, name='Reloading', exit_callback=lambda _: _reload_weapon(entity, _weapon, _ammo))
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 reload_weapon(entity): if timers.has_timer_with_name(entity, 'Reloading'): return _weapon = items.get_items_in_holder(entity, 'weapon')[0] _ammo = items.get_items_matching(entity, {'type': 'ammo'})[0] entities.trigger_event( entity, 'create_timer', time=30, name='Reloading', exit_callback=lambda _: _reload_weapon(entity, _weapon, _ammo))
def create_action_menu(entity, x, y, on_path=False): _menu = ui_menu.create(ui_cursor.CURSOR['tile']['x'] + 2, ui_cursor.CURSOR['tile']['y'] - 1, title='Context') if items.get_items_in_holder(entity, 'weapon'): ui_menu.add_selectable(_menu, 'Shoot', lambda: select_target(x, y, on_path)) ui_menu.add_selectable( _menu, 'Reload', lambda: create_action_node(entity, x, y, 30, lambda: entities.trigger_event( entity, 'reload'), name='Reload', on_path=on_path)) ui_menu.add_selectable( _menu, 'Crouch', lambda: create_action_node(entity, x, y, 30, lambda: entities.trigger_event( entity, 'set_motion', motion='crouch'), name='Crouch', on_path=on_path)) ui_menu.add_selectable( _menu, 'Crawl', lambda: create_action_node(entity, x, y, 30, lambda: entities.trigger_event( entity, 'set_motion', motion='crawl'), name='Prone', on_path=on_path)) ui_menu.add_selectable( _menu, 'Stand', lambda: create_action_node(entity, x, y, 30, lambda: entities.trigger_event( entity, 'set_motion', motion='stand'), name='Stand', on_path=on_path))
def create_life_interact_menu(entity, target_id): if not items.get_items_in_holder(entity, 'weapon'): return _target = entities.get_entity(target_id) _is_enemy = ai_factions.is_enemy(entity, target_id) _menu = ui_menu.create(ui_cursor.CURSOR['tile']['x']+2, ui_cursor.CURSOR['tile']['y']-4, title='Context') if not _is_enemy: if _target['missions']['inactive']: ui_menu.add_selectable(_menu, 'Talk', lambda: create_talk_menu(entity, target_id)) ui_menu.add_selectable(_menu, 'Inquire', lambda: create_mission_menu(entity, target_id)) ui_menu.add_selectable(_menu, 'Trade', lambda: create_mission_menu(entity, target_id)) ui_menu.add_selectable(_menu, 'Shoot%s' % (' (Friendly fire)' * (not _is_enemy)), lambda: create_shoot_menu(entity, target_id))
def draw_squad_info(squad_id): _text_y_mod = 0 _squad = entities.get_entity(squad_id) for member_id in _squad['members']: _member = entities.get_entity(member_id) _health_string = '[OK]' _weapon = items.get_items_in_holder(_member, 'weapon') if _weapon: _weapon_name = '<%s>' % entities.get_entity( _weapon[0])['stats']['name'] else: _weapon_name = '<None>' _class = _member['stats']['class'] display.write_string('ui_bar', 1, 1 + _text_y_mod, _member['stats']['name'], fore_color=(204, 200, 204)) display.write_string('ui_bar', 2 + len(_member['stats']['name']), 1 + _text_y_mod, _health_string, fore_color=(200, 200, 34)) display.write_string('ui_bar', 3 + len(_member['stats']['name']) + len(_health_string), 1 + _text_y_mod, _weapon_name, fore_color=(0, 200, 34)) display.write_string('ui_bar', 4 + len(_member['stats']['name']) + len(_health_string) + len(_weapon_name), 1 + _text_y_mod, _class, fore_color=(200, 50, 200), back_color=(50, 12, 50)) _text_y_mod += 1
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))
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 draw_squad_info(squad_id): _text_y_mod = 0 _squad = entities.get_entity(squad_id) for member_id in _squad["members"]: _member = entities.get_entity(member_id) _health_string = "[OK]" _weapon = items.get_items_in_holder(_member, "weapon") if _weapon: _weapon_name = "<%s>" % entities.get_entity(_weapon[0])["stats"]["name"] else: _weapon_name = "<None>" _class = _member["stats"]["class"] display.write_string("ui_bar", 1, 1 + _text_y_mod, _member["stats"]["name"], fore_color=(204, 200, 204)) display.write_string( "ui_bar", 2 + len(_member["stats"]["name"]), 1 + _text_y_mod, _health_string, fore_color=(200, 200, 34) ) display.write_string( "ui_bar", 3 + len(_member["stats"]["name"]) + len(_health_string), 1 + _text_y_mod, _weapon_name, fore_color=(0, 200, 34), ) display.write_string( "ui_bar", 4 + len(_member["stats"]["name"]) + len(_health_string) + len(_weapon_name), 1 + _text_y_mod, _class, fore_color=(200, 50, 200), back_color=(50, 12, 50), ) _text_y_mod += 1
def show_weapons(entity): global ACTIVE_MENU, REDRAW_TIMES _holder_menu = ui_menu.create(1, 1, title='Weapons', surface='ui_inventory', click_offset=(constants.MAP_VIEW_WIDTH - 35, 0)) ACTIVE_MENU = _holder_menu REDRAW_TIMES = 3 _equipped_weapon = items.get_items_in_holder(entity, 'weapon') _weapons = [] if _equipped_weapon: _weapons.append(_equipped_weapon[0]) for item_id in items.get_items_matching(entity, {'type': 'weapon'}): if item_id in _weapons: continue _weapons.add(item_id) for item_id in _weapons: _item = entities.get_entity(item_id) entities.trigger_event(_item, 'get_display_name') if item_id in _equipped_weapon: _fg = (245, 245, 245) else: _fg = (230, 230, 230) ui_menu.add_selectable(_holder_menu, _item['stats']['display_name'], show_weapon_menu, fore_color=_fg, item_id=item_id)
def create_life_interact_menu(entity, target_id): if not items.get_items_in_holder(entity, 'weapon'): return _target = entities.get_entity(target_id) _is_enemy = ai_factions.is_enemy(entity, target_id) _menu = ui_menu.create(ui_cursor.CURSOR['tile']['x'] + 2, ui_cursor.CURSOR['tile']['y'] - 4, title='Context') if not _is_enemy: if _target['missions']['inactive']: ui_menu.add_selectable(_menu, 'Talk', lambda: create_talk_menu(entity, target_id)) ui_menu.add_selectable(_menu, 'Inquire', lambda: create_mission_menu(entity, target_id)) ui_menu.add_selectable(_menu, 'Trade', lambda: create_mission_menu(entity, target_id)) ui_menu.add_selectable(_menu, 'Shoot%s' % (' (Friendly fire)' * (not _is_enemy)), lambda: create_shoot_menu(entity, target_id))
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 _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 _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"]