예제 #1
0
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();
				}
			}
		}
	}
}
예제 #2
0
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());
		}
	}
}