def _printer_move(entity): _x, _y = flags.get_flag(entity, 'text_pos') _move_direction = flags.get_flag(entity, 'move_direction') _vx, _vy = numbers.velocity(_move_direction, 1) _x += int(round(_vx)) _y += int(round(_vy)) entities.trigger_event(entity, 'set_flag', flag='text_pos', value=(_x, _y))
def _tick_fire(entity): _x, _y = movement.get_position(entity) _alpha = flags.get_flag(entity, 'alpha') _alpha += random.uniform(-.3, .3) _alpha = numbers.clip(_alpha, 0, 1) if not _alpha: #char(_x, _y, numbers.clip(flags.get_flag(entity, 'alpha_max') - random.uniform(.1, .2), 0, 1)) entities.delete_entity(entity) return #entities.trigger_event(entity, 'set_char', char=random.choice(['*', '&', '%'])) _color = list(display.get_color_at('tiles', _x, _y)) _color[0] = numbers.interp_velocity(_color[0], random.choice([constants.FIRE_1, constants.FIRE_2, constants.FIRE_3]), _alpha) _color[1] = numbers.interp_velocity(_color[1], random.choice([constants.FIRE_1, constants.FIRE_2, constants.FIRE_3]), _alpha) for c in range(len(_color)): for i in range(len(_color)): _color[c][i] = int((round(_color[c][i]))) entities.trigger_event(entity, 'set_fore_color', color=_color[0]) entities.trigger_event(entity, 'set_back_color', color=_color[1]) entities.trigger_event(entity, 'set_flag', flag='alpha', value=_alpha)
def _smoke_shooter_push(entity): _x, _y = movement.get_position(entity) _direction = movement.get_direction(entity) _mod = random.randint(-35, 35) _alpha = flags.get_flag(entity, 'alpha') if _mod < 0: _mod = numbers.clip(_mod, -35, -20) else: _mod = numbers.clip(_mod, 20, 35) _direction += _mod _v_x, _v_y = numbers.velocity(_direction, random.uniform(.65, .85)) if not int(round(_x + _v_x)) == int(round(_x)) or not int(round(_y + _v_y)) == int(round(_y)): #smoke_cloud(_x + _v_x, _y + _v_y, random.randint(1, 2), start_alpha=_alpha, decay_amount=1.2) smoke(_x + _v_x, _y + _v_y, .75, start_amount=_alpha, decay_amount=random.uniform(3.0, 4.0)) _x += _v_x _y += _v_y if (int(round(_x)), int(round(_y))) in zones.get_active_solids({}, no_life=True): entities.delete_entity(entity) return entities.trigger_event(entity, 'set_direction', direction=_direction) entities.trigger_event(entity, 'set_position', x=_x, y=_y) entities.trigger_event(entity, 'set_flag', flag='alpha', value=_alpha - .05)
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 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, weapon_id, ammo_id): _weapon = entities.get_entity(weapon_id) _ammo = entities.get_entity(ammo_id) _weapon_ammo = flags.get_flag(_weapon, 'ammo') _weapon_ammo_max = flags.get_flag(_weapon, 'ammo_max') _ammo_count = flags.get_flag(_ammo, 'ammo') if _weapon_ammo == _weapon_ammo_max: return _need_ammo = numbers.clip(_weapon_ammo_max - _weapon_ammo, 1, _ammo_count) _ammo_count -= _need_ammo entities.trigger_event(_weapon, 'set_flag', flag='ammo', value=_weapon_ammo + _need_ammo) if _ammo_count: entities.trigger_event(_ammo, 'set_flag', flag='ammo', value=_ammo_count) else: entities.delete_entity(_ammo)
def handle_player_heard_noise(entity, x, y, text, direction, accuracy, show_on_sight, callback, context_callback): _entity = effects.show_noise(entity, x, y, accuracy, direction, text, show_on_sight, callback) if not _entity: return if not context_callback: return _x, _y = flags.get_flag(_entity, 'text_orig_pos') entities.register_event(_entity, 'delete', lambda e: noise.create_context(_x, _y, text, context_callback))
def _message_draw(entity): _text = flags.get_flag(entity, 'text') _index = flags.get_flag(entity, 'index') _center = flags.get_flag(entity, 'center') _vert_center = flags.get_flag(entity, 'vert_center') if _center: _x = (constants.MAP_VIEW_WIDTH / 2) - (len(_text) / 2) else: _x = 3 if _vert_center: _y = (constants.MAP_VIEW_HEIGHT / 2) - 1 else: _y = 1 for i in range(0, 3): if i == 1: display.write_string('ui', _x, _y + i + (4 * _index), ' %s ' % _text, fore_color=(200, 200, 200), back_color=(60, 60, 60)) else: display.write_string('ui', _x, _y + i + (4 * _index), ' ' * (len(_text) + 4), fore_color=(20, 20, 20), back_color=(60, 60, 60))
def handle_member_killed(entity, member_id, target_id): _member = entities.get_entity(member_id) _target = entities.get_entity(target_id) _target_faction = _target['ai']['faction'] if _target_faction == _member['ai']['faction']: logging.info('Friendly fire resulted in death: %s' % _target_faction) return if not _target_faction in entity['enemies']: entity['relations'][_target_faction] = 0 entity['enemies'].append(_target_faction) logging.info('%s is now hostile to %s: Murder' % (_member['ai']['faction'], _target_faction)) if flags.has_flag(_target, 'is_player') and flags.get_flag(_target, 'is_player'): effects.message('%s now see you as hostile.' % _member['ai']['faction'])
def _cleanup(entity): if entity["_id"] in ONLINE_ENTITIES: ONLINE_ENTITIES.remove(entity["_id"]) elif entity["_id"] in OFFLINE_ENTITIES: OFFLINE_ENTITIES.remove(entity["_id"]) _x, _y = movement.get_position(entity) if flags.has_flag(entity, "fire_data"): _fire_data = flags.get_flag(entity, "fire_data") _node = entities.get_entity(zones.get_active_node_grid()[_fire_data["node"]]) entities.trigger_event(_node, "set_flag", flag="owner", value=None) flags.delete_flag(entity, "fire_data") _item_id = items.corpse(_x, _y, entity["tile"]["char"], entity["_id"])["_id"] entities.trigger_event(entity, "handle_corpse", corpse_id=_item_id)
def get_accuracy(entity, weapon_id): entity['stats']['accuracy'] = entity['stats']['max_accuracy'] _weapon = entities.get_entity(weapon_id) entities.trigger_event(entity, 'get_accuracy') _weapon_accuracy = flags.get_flag(_weapon, 'accuracy') if _weapon['stats']['kind'] == 'pistol': _weapon_accuracy *= 1 + (1 - (entity['stats']['pistols'] / 100.0)) elif _weapon['stats']['kind'] == 'rifle': _weapon_accuracy *= 1 + (1 - (entity['stats']['rifles'] / 100.0)) elif _weapon['stats']['kind'] == 'explosive': _weapon_accuracy *= 1 + (1 - (entity['stats']['explosives'] / 100.0)) else: raise Exception('Invalid gun type.') return int(round(_weapon_accuracy * entity['stats']['accuracy']))
def _shoot_weapon(entity, weapon_id, target_id): _weapon = entities.get_entity(weapon_id) _x, _y = movement.get_position(entities.get_entity(_weapon['stats']['owner'])) if not target_id in entities.ENTITIES: logging.warning('Target deleted during shooting.') return _tx, _ty = movement.get_position(entities.get_entity(target_id)) _direction = numbers.direction_to((_x, _y), (_tx, _ty)) effects.muzzle_flash(_x, _y, _direction) entities.trigger_event(_weapon, 'flag_sub', flag='ammo', value=1) entities.trigger_event(entity, 'create_noise', volume=80, direction=numbers.direction_to((_x, _y), (_tx, _ty)), text='BAM', callback=lambda t, x, y: entities.trigger_event(t, 'update_target_memory', target_id=entity['_id'], key='last_seen_at', value=[x, y]), context_callback=lambda x, y: ui_dialog.create(x, y, 'Gunshot (Unknown)', title='Noise')) entity['stats']['action_points'] -= stats.get_shoot_cost(entity, weapon_id) entities.trigger_event(entity, 'get_accuracy') _accuracy = stats.get_accuracy(entity, weapon_id) _damage = flags.get_flag(_weapon, 'damage') effects.light(_x, _y, random.randint(3, 5), r=1.5, g=1.5, b=0) if _weapon['stats']['kind'] == 'explosive': items.explosive(entity, _x, _y, _tx, _ty, 4, _accuracy, _damage) else: items.bullet(entity, _x, _y, _tx, _ty, 1, _accuracy, _damage)
def _printer_draw(entity): _text = flags.get_flag(entity, 'text') _text_index = flags.get_flag(entity, 'text_index') _text_center = flags.get_flag(entity, 'text_center') _text_fore_color = flags.get_flag(entity, 'text_fore_color') _text_back_color = flags.get_flag(entity, 'text_back_color') _x, _y = flags.get_flag(entity, 'text_pos') if _text_center: if _x + len(_text[:_text_index])/2 >= camera.X + constants.MAP_VIEW_WIDTH-1: return if _x - len(_text[:_text_index])/2 < camera.X: return if _y >= camera.Y + constants.MAP_VIEW_HEIGHT: return _x -= len(_text[:_text_index])/2 display.write_string('ui', _x-camera.X, _y-camera.Y, _text[:_text_index], fore_color=_text_fore_color, back_color=_text_back_color)
def _tick_smoke(entity): _x, _y = movement.get_position(entity) _alpha = flags.get_flag(entity, 'alpha') _alpha_mode = flags.get_flag(entity, 'alpha_mode') _alpha_max = flags.get_flag(entity, 'alpha_max') _fore_color = flags.get_flag(entity, 'fore_color') _back_color = flags.get_flag(entity, 'back_color') _decay_mod = flags.get_flag(entity, 'decay') if _alpha_mode: _alpha -= random.uniform(.001 * _decay_mod, .005 * _decay_mod) if _alpha <= 0: display._set_char('tiles', _x, _y, ' ', (0, 0, 0), None) entities.delete_entity(entity) return else: _alpha += random.uniform(.01, .05) if _alpha > _alpha_max: _alpha_mode = 1 _alpha = numbers.clip(_alpha, 0, 1) #entities.trigger_event(entity, 'set_char', char=random.choice(['*', '&', '%'])) _color = list(display.get_color_at('tiles', _x, _y)) _color[0] = numbers.interp_velocity(_color[0], _fore_color, _alpha) _color[1] = numbers.interp_velocity(_color[1], _back_color, _alpha) for c in range(len(_color)): for i in range(len(_color)): _color[c][i] = int((round(_color[c][i]))) entities.trigger_event(entity, 'set_fore_color', color=_color[0]) entities.trigger_event(entity, 'set_back_color', color=_color[1]) entities.trigger_event(entity, 'set_flag', flag='alpha', value=_alpha) entities.trigger_event(entity, 'set_flag', flag='alpha_mode', value=_alpha_mode)
def fire(x, y, amount): _blood = _create(x, y) _x, _y = (int(round(x)), int(round(y))) flags.register(_blood) timers.register(_blood) entities.trigger_event(_blood, 'set_flag', flag='alpha', value=amount) entities.trigger_event(_blood, 'set_flag', flag='alpha_max', value=amount) entities.trigger_event(_blood, 'set_char', char=' ') _color = list(display.get_color_at('tiles', _x, _y)) _color[0] = numbers.interp_velocity(_color[0], random.choice([constants.FIRE_1, constants.FIRE_2, constants.FIRE_3]), amount) _color[1] = numbers.interp_velocity(_color[1], random.choice([constants.FIRE_1, constants.FIRE_2, constants.FIRE_3]), amount) for c in range(len(_color)): for i in range(len(_color)): _color[c][i] = int((round(_color[c][i]))) #display._set_char('tiles', _x, _y, random.choice([',', '.', '^']), _color[0], _color[1]) entities.register_event(_blood, 'tick', _tick_fire) entities.register_event(_blood, 'position_changed', lambda e, x, y, **kwargs: char(x, y, flags.get_flag(e, 'alpha'))) entities.trigger_event(_blood, 'create_timer', time=120, repeat=-1, repeat_callback=lambda e: movement.push(e, random.randint(-1, 1), random.randint(-1, 1), time=1)) entities.trigger_event(_blood, 'set_fore_color', color=_color[0]) entities.trigger_event(_blood, 'set_back_color', color=_color[1]) entities.trigger_event(_blood, 'set_position', x=_x, y=_y) #light(_x, _y, random.randint(5, 7), r=1.5, g=.1, b=.1) return _blood
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 get_shoot_cost(entity, weapon_id): _weapon = entities.get_entity(weapon_id) _weapon_accuracy = flags.get_flag(_weapon, 'shoot_cost') return _weapon_accuracy
def _handle_weapon_display_name(entity): _weapon_ammo = flags.get_flag(entity, 'ammo') _weapon_ammo_max = flags.get_flag(entity, 'ammo_max') entity['stats']['display_name'] += ' (%s/%s)' % (_weapon_ammo, _weapon_ammo_max)
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