void gun_system::launch_shots_due_to_pressed_triggers() { auto& physics_sys = parent_world.get_system<physics_system>(); auto& render = parent_world.get_system<render_system>(); for (auto it : targets) { const auto& gun_transform = it->get<components::transform>(); auto& gun = it->get<components::gun>(); auto& container = it->get<components::container>(); if (gun.trigger_pressed && check_timeout_and_reset(gun.timeout_between_shots)) { if (gun.action_mode != components::gun::action_type::AUTOMATIC) gun.trigger_pressed = false; auto chamber_slot = it[slot_function::GUN_CHAMBER]; if (chamber_slot->get_mounted_items().size() == 1) { auto barrel_transform = gun_transform; barrel_transform.pos += vec2(gun.bullet_spawn_offset).rotate(gun_transform.rotation, vec2()); auto catridge = chamber_slot->get_mounted_items()[0]; static thread_local std::vector<augs::entity_id> bullet_entities; bullet_entities.clear(); auto pellets_slot = catridge[slot_function::ITEM_DEPOSIT]; if (pellets_slot.alive()) bullet_entities = pellets_slot->get_mounted_items(); else bullet_entities.push_back(catridge); for(auto& charge_stack : bullet_entities) { size_t charges = charge_stack->get<components::item>().charges; while (charges--) { { auto round_entity = parent_world.create_entity(); round_entity->clone(charge_stack[sub_entity_name::BULLET_ROUND_DEFINITION]); round_entity->get<components::damage>().amount *= gun.damage_multiplier; auto& physics_definition = round_entity->get<components::physics_definition>(); physics_definition.dont_create_fixtures_and_body = false; physics_definition.body.velocity.set_from_degrees(barrel_transform.rotation).set_length(randval(gun.muzzle_velocity)); round_entity->get<components::transform>() = barrel_transform; } auto shell_definition = charge_stack[sub_entity_name::BULLET_SHELL_DEFINITION]; if (shell_definition.alive()) { auto shell_entity = parent_world.create_entity(); shell_entity->clone(shell_definition); auto shell_transform = gun_transform; shell_transform.pos += vec2(gun.shell_spawn_offset).rotate(gun_transform.rotation, vec2()); auto& physics_definition = shell_entity->get<components::physics_definition>(); physics_definition.dont_create_fixtures_and_body = false; physics_definition.body.velocity.set_from_degrees( barrel_transform.rotation) .set_length(randval(gun.shell_velocity)); shell_entity->get<components::transform>() = shell_transform; } } parent_world.post_message(messages::destroy_message(charge_stack)); } messages::animation_response_message msg; msg.response = messages::animation_response_message::SHOT; msg.preserve_state_if_animation_changes = false; msg.change_animation = true; msg.change_speed = true; msg.speed_factor = 1.f; msg.subject = it; msg.action = messages::animation_message::START; msg.animation_priority = 1; parent_world.post_message(msg); auto* maybe_item = it->find<components::item>(); if (maybe_item) gun.shake_camera(get_root_container(it)[associated_entity_name::WATCHING_CAMERA], gun_transform.rotation); messages::particle_burst_message burst; burst.pos = barrel_transform.pos; burst.rotation = barrel_transform.rotation; burst.subject = it; burst.type = messages::particle_burst_message::burst_type::WEAPON_SHOT; burst.target_group_to_refresh = it[sub_entity_name::BARREL_SMOKE]; parent_world.post_message(burst); parent_world.post_message(messages::destroy_message(chamber_slot->items_inside[0])); chamber_slot->items_inside.clear(); if (gun.action_mode >= components::gun::action_type::SEMI_AUTOMATIC) { std::vector<augs::entity_id> source_catridge_store; auto chamber_magazine_slot = it[slot_function::GUN_CHAMBER_MAGAZINE]; if (chamber_magazine_slot.alive()) { source_catridge_store = chamber_magazine_slot->items_inside; } else { auto detachable_magazine_slot = it[slot_function::GUN_DETACHABLE_MAGAZINE]; if (detachable_magazine_slot.has_items()) { source_catridge_store = detachable_magazine_slot->items_inside[0][slot_function::ITEM_DEPOSIT]->items_inside; } } auto new_singular_charge = parent_world.create_entity(); auto source_charge_stack = *source_catridge_store.rbegin(); new_singular_charge->clone(source_charge_stack); new_singular_charge->get<components::item>().charges = 1; source_charge_stack->get<components::item>().charges--; chamber_slot.add_item(new_singular_charge); new_singular_charge->get<components::item>().set_mounted(); } } } } }
void perform_transfer(const item_slot_transfer_request r, logic_step& step) { auto& cosmos = r.get_item().get_cosmos(); auto& item = r.get_item().get<components::item>(); const auto previous_slot_id = item.current_slot; const auto previous_slot = cosmos[previous_slot_id]; const auto result = query_transfer_result(r); const bool is_pickup_or_transfer = result.result == item_transfer_result_type::SUCCESSFUL_TRANSFER; const bool is_drop_request = result.result == item_transfer_result_type::SUCCESSFUL_DROP; if (result.result == item_transfer_result_type::UNMOUNT_BEFOREHAND) { ensure(false); ensure(previous_slot.alive()); //item.request_unmount(r.get_target_slot()); //item.mark_parent_enclosing_containers_for_unmount(); return; } else if (is_pickup_or_transfer || is_drop_request) { components::transform previous_container_transform; entity_id target_item_to_stack_with; if (is_pickup_or_transfer) { for (auto& i : cosmos.get_handle(r.get_target_slot())->items_inside) { if (can_stack_entities(r.get_item(), cosmos[i])) { target_item_to_stack_with = i; } } } const bool whole_item_grabbed = item.charges == result.transferred_charges; if (previous_slot.alive()) { previous_container_transform = previous_slot.get_container().logic_transform(); if (whole_item_grabbed) { remove_item(previous_slot, r.get_item()); } if (previous_slot.is_input_enabling_slot()) { unset_input_flags_of_orphaned_entity(r.get_item()); } } if (cosmos[target_item_to_stack_with].alive()) { if (whole_item_grabbed) { step.transient.messages.post(messages::queue_destruction(r.get_item())); } else { item.charges -= result.transferred_charges; } cosmos[target_item_to_stack_with].get<components::item>().charges += result.transferred_charges; return; } entity_id grabbed_item_part; if (whole_item_grabbed) { grabbed_item_part = r.get_item(); } else { grabbed_item_part = cosmos.clone_entity(r.get_item()); item.charges -= result.transferred_charges; cosmos[grabbed_item_part].get<components::item>().charges = result.transferred_charges; } const auto grabbed_item_part_handle = cosmos[grabbed_item_part]; if (is_pickup_or_transfer) { add_item(r.get_target_slot(), grabbed_item_part_handle); } auto physics_updater = [previous_container_transform](const entity_handle descendant, ...) { const auto& cosmos = descendant.get_cosmos(); const auto parent_slot = cosmos[descendant.get<components::item>().current_slot]; auto def = descendant.get<components::fixtures>().get_data(); entity_id owner_body; if (parent_slot.alive()) { def.activated = parent_slot.should_item_inside_keep_physical_body(); if (def.activated) { owner_body = parent_slot.get_root_container(); def.offsets_for_created_shapes[colliders_offset_type::ITEM_ATTACHMENT_DISPLACEMENT] = sum_attachment_offsets(cosmos, descendant.get_address_from_root()); } else { owner_body = descendant; } def.offsets_for_created_shapes[colliders_offset_type::SPECIAL_MOVE_DISPLACEMENT].reset(); } else { def.activated = true; owner_body = descendant; def.offsets_for_created_shapes[colliders_offset_type::ITEM_ATTACHMENT_DISPLACEMENT].reset(); def.offsets_for_created_shapes[colliders_offset_type::SPECIAL_MOVE_DISPLACEMENT].reset(); } descendant.get<components::fixtures>() = def; descendant.get<components::fixtures>().set_owner_body(owner_body); if (descendant.has<components::physics>()) { descendant.get<components::physics>().set_transform(previous_container_transform); if (descendant.has<components::interpolation>()) { descendant.get<components::interpolation>().place_of_birth = descendant.logic_transform(); } } }; physics_updater(grabbed_item_part_handle); grabbed_item_part_handle.for_each_contained_item_recursive(physics_updater); if (is_pickup_or_transfer) { initialize_item_button_for_new_gui_owner(grabbed_item_part_handle, inventory_traversal()); grabbed_item_part_handle.for_each_contained_slot_and_item_recursive(initialize_slot_button_for_new_gui_owner, initialize_item_button_for_new_gui_owner); } const auto previous_capability = previous_slot.get_container().get_owning_transfer_capability(); const auto target_capability = r.get_target_slot().get_container().get_owning_transfer_capability(); if (target_capability.alive() && target_capability != previous_capability) { if (target_capability.has<components::gui_element>()) { components::gui_element::assign_item_to_first_free_hotbar_button(target_capability, grabbed_item_part_handle); } } auto& grabbed_item = grabbed_item_part_handle.get<components::item>(); if (is_pickup_or_transfer) { if (r.get_target_slot()->items_need_mounting) { grabbed_item.intended_mounting = components::item::MOUNTED; if (r.force_immediate_mount) { grabbed_item.current_mounting = components::item::MOUNTED; } } } if (is_drop_request) { const auto force = vec2().set_from_degrees(previous_container_transform.rotation).set_length(60); const auto offset = vec2().random_on_circle(20, cosmos.get_rng_for(r.get_item())); auto& physics = grabbed_item_part_handle.get<components::physics>(); physics.apply_force(force, offset, true); auto& special_physics = grabbed_item_part_handle.get<components::special_physics>(); special_physics.since_dropped.set(200, cosmos.get_timestamp()); } } }