Beispiel #1
0
void movement_system::set_movement_flags_from_input(const logic_step step) {
	auto& cosmos = step.cosm;
	const auto& delta = step.get_delta();
	const auto& events = step.transient.messages.get_queue<messages::intent_message>();

	for (const auto& it : events) {
		auto* const movement = cosmos[it.subject].find<components::movement>();
		
		if (movement == nullptr) {
			continue;
		}

		switch (it.intent) {
		case intent_type::MOVE_FORWARD:
			movement->moving_forward = it.is_pressed;
			break;
		case intent_type::MOVE_BACKWARD:
			movement->moving_backward = it.is_pressed;
			break;
		case intent_type::MOVE_LEFT:
			movement->moving_left = it.is_pressed;
			break;
		case intent_type::MOVE_RIGHT:
			movement->moving_right = it.is_pressed;
			break;
		case intent_type::WALK:
			movement->walking_enabled = it.is_pressed;
			break;
		case intent_type::SPRINT:
			movement->sprint_enabled = it.is_pressed;
			break;
		default: break;
		}
	}
}
Beispiel #2
0
void trace_system::lengthen_sprites_of_traces(logic_step& step) const {
	auto& cosmos = step.cosm;
	const auto delta = step.get_delta();

	for (const auto t : cosmos.get(processing_subjects::WITH_TRACE)) {
		auto& trace = t.get<components::trace>();
		auto& sprite = t.get<components::sprite>();

		if (trace.chosen_lengthening_duration_ms < 0.f) {
			trace.reset(cosmos.get_rng_for(t));
		}

		vec2 surplus_multiplier;
		
		if (!trace.is_it_finishing_trace) {
			surplus_multiplier = trace.chosen_multiplier * trace.lengthening_time_passed_ms / trace.chosen_lengthening_duration_ms;
		}
		else {
			surplus_multiplier = (trace.chosen_multiplier + vec2(1, 1)) * (1.f - (trace.lengthening_time_passed_ms / trace.chosen_lengthening_duration_ms)) - vec2(1, 1);
		}

		sprite.size_multiplier = vec2(1, 1) + surplus_multiplier;

		sprite.center_offset = sprite.size * (surplus_multiplier / 2.f);

		trace.lengthening_time_passed_ms += static_cast<float>(delta.in_milliseconds());
	}
}
Beispiel #3
0
void item_system::handle_trigger_confirmations_as_pick_requests(const logic_step step) {
	auto& cosmos = step.cosm;
	const auto& delta = step.get_delta();
	const auto& confirmations = step.transient.messages.get_queue<messages::trigger_hit_confirmation_message>();

	for (const auto& e : confirmations) {
		const auto detector = cosmos[e.detector_body];

		auto* const item_slot_transfers = detector.find<components::item_slot_transfers>();
		const auto item_entity = cosmos[e.trigger].get_owner_body();

		const auto* const item = item_entity.find<components::item>();

		if (item_slot_transfers && item && item_entity.get_owning_transfer_capability().dead()) {
			const auto& pick_list = item_slot_transfers->only_pick_these_items;
			const bool found_on_subscription_list = found_in(pick_list, item_entity);

			const bool item_subscribed = (pick_list.empty() && item_slot_transfers->pick_all_touched_items_if_list_to_pick_empty)
				|| found_in(item_slot_transfers->only_pick_these_items, item_entity);
			
			if (item_subscribed) {
				const auto pickup_slot = detector.determine_pickup_target_slot_for(item_entity);
				const bool can_pick_already = item_slot_transfers->pickup_timeout.try_to_fire_and_reset(cosmos.get_timestamp(), delta);

				if (pickup_slot.alive() && can_pick_already) {
					const item_slot_transfer_request request(item_entity, pickup_slot);
					perform_transfer(request, step);
				}
				else {
					// TODO: post gui message
				}
			}
		}
	}
}
Beispiel #4
0
void melee_system::consume_melee_intents(const logic_step step) {
	auto& cosmos = step.cosm;
	const auto& delta = step.get_delta();
	const auto& events = step.transient.messages.get_queue<messages::intent_message>();


	for (const auto& it : events) {
		/* 
			we search the whole intent message queue for events of interest;
			here we can even find gunshot requests for some distant enemy AI,
			therefore we need to filter out events we're interested in, and that would be
			melee-related intents and only these applied to an entity with a melee component
		*/
		auto* const maybe_melee = cosmos[it.subject].find<components::melee>();
		
		if (maybe_melee == nullptr) 
			continue;

		auto& melee = *maybe_melee;

		if (it.intent == intent_type::MELEE_PRIMARY_MOVE) {
			melee.primary_move_flag = it.is_pressed;
		}

		if (it.intent == intent_type::MELEE_SECONDARY_MOVE) {
			melee.secondary_move_flag = it.is_pressed;
		}
		
		if (it.intent == intent_type::MELEE_TERTIARY_MOVE) {
			melee.tertiary_move_flag = it.is_pressed;
		}
	}
}
Beispiel #5
0
void destruction_system::apply_damages_and_split_fixtures(const logic_step step) const {
	auto& cosmos = step.cosm;
	const auto delta = step.get_delta();
	const auto& damages = step.transient.messages.get_queue<messages::damage_message>();

	for (const auto& d : damages) {
		const auto subject = cosmos[d.subject];
		
		if (subject.has<components::fixtures>()) {
			auto& fixtures = subject.get<components::fixtures>();
			
			const auto& data_indices = d.subject_collider_and_convex_indices;

			const auto& coll = fixtures.get_collider_data(data_indices.first);

			if (coll.destructible) {
				auto& dest_data = fixtures.get_modifiable_destruction_data(data_indices);
				dest_data.scars.resize(1);
				dest_data.scars[0].first_impact = d.point_of_impact;
				dest_data.scars[0].depth_point = d.point_of_impact + d.impact_velocity;

				//LOG("Destructible fixture has been applied damage to with direction: %x", d.impact_velocity);
			}
		}
	}
}
void detonate_if(const entity_id& id, const transformr& where, const logic_step& step) {
	step.get_cosmos()[id].dispatch_on_having_all<invariants::explosive>([&](const auto typed_handle) {
		detonate({
			step, id, typed_handle.template get<invariants::explosive>(), where
		});
	});
}
Beispiel #7
0
void movement_system::generate_movement_responses(const logic_step step) {
	auto& cosmos = step.cosm;
	const auto& delta = step.get_delta();
	step.transient.messages.get_queue<messages::movement_response>().clear();

	for (const auto& it : cosmos.get(processing_subjects::WITH_MOVEMENT)) {
		const auto& movement = it.get<components::movement>();

		float32 speed = 0.0f;

		if (movement.enable_animation) {
			if (it.has<components::physics>()) {
				speed = it.get<components::physics>().velocity().length();
			}
		}

		messages::movement_response msg;

		if (movement.max_speed_for_movement_response == 0.f) msg.speed = 0.f;
		else msg.speed = speed / movement.max_speed_for_movement_response;
		
		for (const auto receiver : movement.response_receivers) {
			messages::movement_response copy(msg);
			copy.stop_response_at_zero_speed = receiver.stop_response_at_zero_speed;
			copy.subject = receiver.target;
			step.transient.messages.post(copy);
		}
	}
}
Beispiel #8
0
void physics_system::step_and_set_new_transforms(logic_step& step) {
	auto& cosmos = step.cosm;
	const auto delta = step.get_delta();

	int32 velocityIterations = 8;
	int32 positionIterations = 3;

	ray_casts_since_last_step = 0;

	b2world->Step(static_cast<float32>(delta.in_seconds()), velocityIterations, positionIterations);

	post_and_clear_accumulated_collision_messages(step);

	for (b2Body* b = b2world->GetBodyList(); b != nullptr; b = b->GetNext()) {
		if (b->GetType() == b2_staticBody) continue;
		entity_handle entity = cosmos[b->GetUserData()];
		auto& physics = entity.get<components::physics>();

		recurential_friction_handler(step, b, b->m_ownerFrictionGround);

		physics.component.transform = b->m_xf;
		physics.component.sweep = b->m_sweep;
		physics.component.velocity = b->GetLinearVelocity();
		physics.component.angular_velocity = b->GetAngularVelocity();
	}
}
void demolitions_system::advance_cascade_explosions(const logic_step step) {
	auto& cosm = step.get_cosmos();
	const auto& clk = cosm.get_clock();

	cosm.for_each_having<components::cascade_explosion>(
		[&](const auto it) {
			const auto& cascade_def = it.template get<invariants::cascade_explosion>();
			auto& cascade = it.template get<components::cascade_explosion>();

			auto& when_next = cascade.when_next_explosion;

			if (clk.now >= when_next) {
				auto rng = cosm.get_nontemporal_rng_for(it);

				{
					const auto next_explosion_in_ms = rng.randval(cascade_def.explosion_interval_ms);
					when_next = clk.now;
					when_next.step += next_explosion_in_ms / clk.dt.in_milliseconds();
				}

				{
					const auto angle_displacement = rng.randval_h(cascade_def.max_explosion_angle_displacement);
					const auto& body = it.template get<components::rigid_body>();

					auto vel = body.get_velocity();
					vel.rotate(angle_displacement, vec2());
					body.set_velocity(vel);
				}

				auto expl_in = cascade_def.explosion;
				expl_in *= rng.randval_vm(1.f, cascade_def.explosion_scale_variation);

				expl_in.instantiate(
					step,
					it.get_logic_transform(),
					damage_cause(it)
				);

				--cascade.explosions_left;

				if (0 == cascade.explosions_left) {
					step.queue_deletion_of(it, "Cascade explosions exhausted");
				}
			}
		}
	);
}
Beispiel #10
0
void intent_contextualization_system::contextualize_crosshair_action_intents(const logic_step step) {
	auto& cosmos = step.cosm;
	const auto& delta = step.get_delta();
	auto& events = step.transient.messages.get_queue<messages::intent_message>();

	for (auto& it : events) {
		entity_id callee;

		const auto subject = cosmos[it.subject];

		const auto maybe_crosshair = subject[sub_entity_name::CHARACTER_CROSSHAIR];

		if (it.intent == intent_type::MOVE_CROSSHAIR && maybe_crosshair.alive()) {
			it.subject = maybe_crosshair;
			continue;
		}

		if (subject.has<components::container>()) {
			if (it.intent == intent_type::CROSSHAIR_PRIMARY_ACTION) {
				const auto hand = subject[slot_function::PRIMARY_HAND];

				if (hand.alive() && hand->items_inside.size() > 0)
					callee = hand.get_items_inside()[0];
			}

			if (it.intent == intent_type::CROSSHAIR_SECONDARY_ACTION) {
				const auto hand = subject[slot_function::SECONDARY_HAND];

				if (hand.alive() && hand->items_inside.size() > 0)
					callee = hand.get_items_inside()[0];
				else {
					const auto prim_hand = subject[slot_function::PRIMARY_HAND];

					if (prim_hand.alive() && prim_hand->items_inside.size() > 0)
						callee = prim_hand.get_items_inside()[0];
				}
			}
		}

		const auto callee_handle = cosmos[callee];

		if (callee_handle.alive()) {
			if (callee_handle.find<components::gun>()) {
				it.intent = intent_type::PRESS_GUN_TRIGGER;
				it.subject = callee;
				continue;
			}
			if (callee_handle.find<components::melee>()) {
				if (it.intent == intent_type::CROSSHAIR_PRIMARY_ACTION)
					it.intent = intent_type::MELEE_PRIMARY_MOVE;
				else if (it.intent == intent_type::CROSSHAIR_SECONDARY_ACTION)
					it.intent = intent_type::MELEE_SECONDARY_MOVE;

				it.subject = callee;
				continue;
			}
		}
	}
}
Beispiel #11
0
void driver_system::release_drivers_due_to_requests(const logic_step step) {
	auto& cosmos = step.cosm;
	const auto& delta = step.get_delta();
	const auto& intents = step.transient.messages.get_queue<messages::intent_message>();

	for (const auto& e : intents) {
		if (e.intent == intent_type::RELEASE_CAR && e.is_pressed) {
			release_car_ownership(cosmos[e.subject]);
		}
	}
}
Beispiel #12
0
void intent_contextualization_system::contextualize_movement_intents(const logic_step step) {
	auto& cosmos = step.cosm;
	const auto& delta = step.get_delta();
	auto& intents = step.transient.messages.get_queue<messages::intent_message>();

	for (auto& e : intents) {
		entity_id callee;
		bool callee_resolved = false;

		const auto subject = cosmos[e.subject];

		const auto* const maybe_driver = subject.find<components::driver>();
		const auto* const maybe_container = subject.find<components::container>();

		if (maybe_driver && cosmos[maybe_driver->owned_vehicle].alive()) {
			if (e.intent == intent_type::MOVE_FORWARD
				|| e.intent == intent_type::MOVE_BACKWARD
				|| e.intent == intent_type::MOVE_LEFT
				|| e.intent == intent_type::MOVE_RIGHT
				|| e.intent == intent_type::WALK
				|| e.intent == intent_type::SPRINT
				) {
				callee = maybe_driver->owned_vehicle;
				callee_resolved = true;
			}
			else if (e.intent == intent_type::SPACE_BUTTON) {
				callee = maybe_driver->owned_vehicle;
				callee_resolved = true;
				e.intent = intent_type::HAND_BRAKE;
			}
		}
		
		if (!callee_resolved) {
			if (maybe_container) {
				if (e.intent == intent_type::SPACE_BUTTON) {
					const auto hand = subject[slot_function::PRIMARY_HAND];

					if (hand.alive() && hand->items_inside.size() > 0) {
						e.intent = intent_type::MELEE_TERTIARY_MOVE;
						callee = hand.get_items_inside()[0];
						callee_resolved = true;
					}
				}
			}
		}

		if (callee_resolved) {
			e.subject = callee;
		}
	}
}
Beispiel #13
0
void melee_system::initiate_and_update_moves(const logic_step step) {
	auto& cosmos = step.cosm;
	const auto& delta = step.get_delta();
	/* 
	- fixed delta timestep if it's a logic procedure 
	- variable frame time if it is a rendering-time procedure 
	*/
	const auto dt = static_cast<float>(delta.in_milliseconds());

	/* clear melee swing response queue because this is the only place where we send them */
	step.transient.messages.get_queue<messages::melee_swing_response>().clear();

	/* all entities in the "targets" vector are guaranteed to have both melee and damage components
		therefore we use get instead of find
	*/

	const auto targets_copy = cosmos.get(processing_subjects::WITH_MELEE);

	for (const auto& t : targets_copy) {
		auto& melee = t.get<components::melee>();
		auto& damage = t.get<components::damage>();

		//		 LOG("P: %x, S: %x, T: %x CDT: %x MVT: %x STATE: %x", melee.primary_move_flag, melee.secondary_move_flag, melee.tertiary_move_flag,melee.swing_current_cooldown_time,melee.swing_current_time,melee.state);

		switch (melee.current_state) {
		case melee_state::FREE:
			if (melee.primary_move_flag) {
				melee.current_state = primary_action(step, dt, t, melee, damage);
			}
			/* send a response message so that the rest of the game knows that a swing has occured;
			the message could be read by particles system, audio system and possibly animation system
			to apply each their own effects.
			*/
			break;
		case melee_state::ONCOOLDOWN:
			melee.swing_current_cooldown_time += dt;
			if (melee.swing_current_cooldown_time >= melee.swings[0].cooldown_ms) {
				melee.swing_current_cooldown_time = 0;
				melee.current_state = melee_state::FREE;
			}
			break;
		case melee_state::PRIMARY:
			melee.current_state = primary_action(step,dt,t,melee,damage);
			break;
		 default:
			LOG("Uknown action in melee_system.cpp");
		}
	}
}
Beispiel #14
0
void trigger_detector_system::post_trigger_requests_from_continuous_detectors(const logic_step step) const {
	auto& cosmos = step.cosm;
	const auto delta = step.get_delta();
	auto targets_copy = cosmos.get(processing_subjects::WITH_TRIGGER_QUERY_DETECTOR);

	for (auto& t : targets_copy) {
		if (!t.get<components::trigger_query_detector>().detection_intent_enabled) {
			t.get<components::processing>().disable_in(processing_subjects::WITH_TRIGGER_QUERY_DETECTOR);
		}
		else {
			messages::trigger_hit_request_message request;
			request.detector = t;
			step.transient.messages.post(request);
		}
	}
}
void demolitions_system::detonate_fuses(const logic_step step) {
	auto& cosm = step.get_cosmos();
	const auto& clk = cosm.get_clock();

	cosm.for_each_having<components::hand_fuse>(
		[&](const auto& it) {
			const auto fuse_logic = fuse_logic_provider(it, step);
			fuse_logic.advance_arming_and_defusing();

			auto& fuse = fuse_logic.fuse;
			const auto& fuse_def = fuse_logic.fuse_def;

			if (fuse.armed()) {
				{
					auto& when_beep = fuse.when_last_beep;

					if (!when_beep.was_set()) {
						when_beep = clk.now;
						/* Don't play the beep effect for the first time. */
					}
					else {
						const auto beep = beep_math { fuse, fuse_def, clk };

						if (beep.should_beep_again()) {
							fuse_def.beep_sound.start(
								step,
								sound_effect_start_input::fire_and_forget(fuse_logic.fused_transform),
								always_predictable_v
							);

							when_beep = clk.now;
						}
					}
				}

				const auto when_armed = fuse.when_armed;
				const auto& fuse_def = it.template get<invariants::hand_fuse>();

				if (clk.is_ready(fuse_def.fuse_delay_ms, when_armed)) {
					detonate_if(it, step);
				}
			}
		}
	);
}
Beispiel #16
0
void driver_system::assign_drivers_from_successful_trigger_hits(const logic_step step) {
	auto& cosmos = step.cosm;
	const auto& delta = step.get_delta();
	const auto& confirmations = step.transient.messages.get_queue<messages::trigger_hit_confirmation_message>();

	for (const auto& e : confirmations) {
		const auto& subject_car = cosmos[cosmos[e.trigger].get<components::trigger>().entity_to_be_notified];

		if (subject_car.dead()) {
			continue;
		}

		const auto* const maybe_car = subject_car.find<components::car>();

		if (maybe_car && e.trigger == maybe_car->left_wheel_trigger) {
			assign_car_ownership(cosmos[e.detector_body], subject_car);
		}
	}
}
Beispiel #17
0
void item_system::handle_holster_item_intents(const logic_step step) {
	auto& cosmos = step.cosm;
	const auto& delta = step.get_delta();
	const auto& requests = step.transient.messages.get_queue<messages::intent_message>();

	for (const auto& r : requests) {
		if (r.is_pressed &&
			(r.intent == intent_type::HOLSTER_PRIMARY_ITEM
				|| r.intent == intent_type::HOLSTER_SECONDARY_ITEM)
			) {
			const auto subject = cosmos[r.subject];

			if (subject.has<components::gui_element>() && subject.find<components::item_slot_transfers>()) {
				const auto hand_type = subject.map_primary_action_to_secondary_hand_if_primary_empty(intent_type::HOLSTER_SECONDARY_ITEM == r.intent).get_id().type;

				auto new_setup = components::gui_element::get_actual_selection_setup(subject);

				if (hand_type == slot_function::PRIMARY_HAND) {
					new_setup.primary_selection.unset();
				}
				else if (hand_type == slot_function::SECONDARY_HAND) {
					new_setup.secondary_selection.unset();
				}

				components::gui_element::apply_and_save_hotbar_selection_setup(step, new_setup, subject);
			}
			else if (subject.has<components::item_slot_transfers>()) {
				const auto hand = subject.map_primary_action_to_secondary_hand_if_primary_empty(intent_type::HOLSTER_SECONDARY_ITEM == r.intent);
				const auto item_inside = hand.get_item_if_any();

				if (item_inside.alive()) {
					const auto holstering_slot = subject.determine_hand_holstering_slot_for(item_inside);

					if (holstering_slot.alive()) {
						const item_slot_transfer_request request(item_inside, holstering_slot);
						perform_transfer(request, step);
					}
				}
			}
		}
	}
}
Beispiel #18
0
void animation_system::game_responses_to_animation_messages(const logic_step step) {
	auto& cosmos = step.cosm;
	const auto& delta = step.get_delta();
	const auto& movements = step.transient.messages.get_queue<movement_response>();
	const auto& gunshots = step.transient.messages.get_queue<gunshot_response>();

	for (auto it : movements) {
		animation_message msg;

		msg.subject = it.subject;
		msg.change_speed = true;

		msg.change_animation = true;
		msg.preserve_state_if_animation_changes = false;
		msg.action = ((it.speed <= 1.f) ? animation_message::STOP : animation_message::CONTINUE);

		if (!it.stop_response_at_zero_speed)
			msg.action = animation_message::CONTINUE;

		msg.animation_priority = 0;

		msg.set_animation = (*(cosmos[it.subject].get<components::animation_response>().response))[animation_response_type::MOVE];
		msg.speed_factor = it.speed;

		step.transient.messages.post(msg);
	}

	for (auto it : gunshots) {
		// animation_message msg;
		// msg.preserve_state_if_animation_changes = false;
		// msg.change_animation = true;
		// msg.change_speed = true;
		// msg.speed_factor = 1.f;
		// msg.subject = it.subject;
		// msg.action = messages::animation_message::START;
		// msg.animation_priority = 1;
		// msg.set_animation = (*(it.subject.get<components::animation_response>().response))[animation_response_type::SHOT];
		// 
		// step.transient.messages.post(msg);
	}
}
Beispiel #19
0
void driver_system::release_drivers_due_to_ending_contact_with_wheel(const logic_step step) {
	auto& cosmos = step.cosm;
	const auto& delta = step.get_delta();
	const auto& contacts = step.transient.messages.get_queue<messages::collision_message>();
	const auto& physics = cosmos.systems_temporary.get<physics_system>();

	for (const auto& c : contacts) {
		if (c.type == messages::collision_message::event_type::END_CONTACT) {
			const auto& driver = cosmos[c.subject];
			const auto& car = cosmos[c.collider].get_owner_body();

			const auto* const maybe_driver = driver.find<components::driver>();

			if (maybe_driver) {
				if (maybe_driver->owned_vehicle == car) {
					release_car_ownership(driver);
					driver.get<components::movement>().make_inert_for_ms = 500.f;
				}
			}
		}
	}
}
Beispiel #20
0
void item_system::handle_throw_item_intents(const logic_step step) {
	auto& cosmos = step.cosm;
	const auto& delta = step.get_delta();
	const auto& requests = step.transient.messages.get_queue<messages::intent_message>();

	for (const auto& r : requests) {
		if (r.is_pressed &&
			(r.intent == intent_type::THROW_PRIMARY_ITEM
				|| r.intent == intent_type::THROW_SECONDARY_ITEM)
			) {
			const auto subject = cosmos[r.subject];

			if (subject.find<components::item_slot_transfers>()) {
				const auto hand = subject.map_primary_action_to_secondary_hand_if_primary_empty(intent_type::THROW_SECONDARY_ITEM == r.intent);
				const auto item_inside = hand.get_item_if_any();

				if (item_inside.alive()) {
					perform_transfer({ item_inside, cosmos[inventory_slot_id()] }, step);
				}
			}
		}
	}
}
Beispiel #21
0
void intent_contextualization_system::contextualize_use_button_intents(const logic_step step) {
	auto& cosmos = step.cosm;
	auto& delta = step.get_delta();
	auto& intents = step.transient.messages.get_queue<messages::intent_message>();
	
	for (auto& e : intents) {
		const auto subject = cosmos[e.subject];

		const auto* const query_detector = subject.find<components::trigger_query_detector>();
		const auto* const collision_detector = subject.find<components::trigger_collision_detector>();
		
		if (e.intent == intent_type::USE_BUTTON) {
			const auto* const maybe_driver = subject.find<components::driver>();

			if (maybe_driver) {
				const auto car_id = maybe_driver->owned_vehicle;
				const auto car = cosmos[car_id];

				if (car.alive() && car.get<components::car>().current_driver == e.subject) {
					e.intent = intent_type::RELEASE_CAR;
					continue;
				}
			}

			if (query_detector) {
				e.intent = intent_type::QUERY_TOUCHING_TRIGGERS;
				continue;
			}
		}
		else if (e.intent == intent_type::START_PICKING_UP_ITEMS) {
			if (collision_detector) {
				e.intent = intent_type::DETECT_TRIGGER_COLLISIONS;
				continue;
			}
		}
	}
}
Beispiel #22
0
void item_system::process_mounting_and_unmounting(const logic_step step) {
	ensure(false);
	auto& cosmos = step.cosm;
	const auto& delta = step.get_delta();
	for (const auto& e : cosmos.get(processing_subjects::WITH_ITEM_SLOT_TRANSFERS)) {
		auto& item_slot_transfers = e.get<components::item_slot_transfers>();

		const auto currently_mounted_item = cosmos[item_slot_transfers.mounting.current_item];

		if (currently_mounted_item.alive()) {
			auto& item = currently_mounted_item.get<components::item>();

			if (item.current_slot != item_slot_transfers.mounting.intented_mounting_slot) {
				item_slot_transfers.interrupt_mounting();
			}
			else {
				ensure(item.intended_mounting != item.current_mounting);

				if (item.montage_time_left_ms > 0) {
					item.montage_time_left_ms -= static_cast<float>(delta.in_milliseconds());
				}
				else {
					item.current_mounting = item.intended_mounting;

					if (item.current_mounting == components::item::UNMOUNTED) {
						perform_transfer({ currently_mounted_item, cosmos[item.target_slot_after_unmount] }, step);
					}
				}
			}
		}

		if (currently_mounted_item.dead()) {
			item_slot_transfers.mounting = components::item_slot_transfers::find_suitable_montage_operation(e);
		}
	}
}
Beispiel #23
0
void animation_system::handle_animation_messages(const logic_step step) {
	auto& cosmos = step.cosm;
	const auto& delta = step.get_delta();
	const auto& events = step.transient.messages.get_queue<animation_message>();

	for (auto it : events) {
		auto ptr = cosmos[it.subject].find<components::animation>();
		if (!ptr) continue; auto& animation = *ptr;

		if (it.animation_priority >= animation.priority || animation.state == components::animation::playing_state::PAUSED) {
			if (it.change_speed)
				animation.speed_factor = it.speed_factor;

			//if (it.change_animation) {
				assets::animation_id new_instance = it.set_animation;
				
				if (new_instance != animation.current_animation) {
					animation.current_animation = new_instance;

					if (it.action == animation_message::CONTINUE) {
						it.action = animation_message::START;
					}
					//if (!it.preserve_state_if_animation_changes) {
					//	animation.set_current_frame(0, it.subject);
					//	animation.player_position_ms = 0.f;
					//}
					//else {
						/* update callback */
						//animation.set_current_frame(animation.get_current_frame(), it.subject);
					//}
				}
			//}
			
			animation.priority = it.animation_priority;

			switch (it.action) {
			case animation_message::PAUSE:
				if (animation.state != components::animation::playing_state::PAUSED) {
					animation.paused_state = animation.state;
					animation.state = components::animation::playing_state::PAUSED;
				}
				break;
			case animation_message::STOP:
				animation.paused_state = components::animation::playing_state::PAUSED;
				animation.state = components::animation::playing_state::PAUSED;
				animation.set_current_frame(0);
				animation.player_position_ms = 0.f;
				break;
			case animation_message::START:
				animation.state = components::animation::playing_state::INCREASING;
				animation.set_current_frame(0);
				animation.player_position_ms = 0.f;
				break;
			case animation_message::CONTINUE:
				if (animation.state == components::animation::playing_state::PAUSED) {
					if (animation.paused_state == components::animation::playing_state::PAUSED)
						animation.paused_state = components::animation::playing_state::INCREASING;

					animation.state = animation.paused_state;
				}
				break;
			default: break;
			}
		}
	}

	step.transient.messages.get_queue<animation_message>().clear();
}
Beispiel #24
0
void animation_system::progress_animation_states(const logic_step step) {
	auto& cosmos = step.cosm;
	const auto& delta = step.get_delta();

	for (const auto& it : cosmos.get(processing_subjects::WITH_ANIMATION)) {
		auto& animation_state = it.get<components::animation>();

		if (animation_state.state != components::animation::playing_state::PAUSED) {
			auto& animation = *get_resource_manager().find(animation_state.current_animation);

			if (animation.frames.empty()) continue;

			animation_state.player_position_ms += static_cast<float>(delta.in_milliseconds()) * animation_state.speed_factor;

			while (true) {
				float frame_duration = animation.frames[animation_state.get_current_frame()].duration_milliseconds;

				if (animation_state.player_position_ms > frame_duration) {
					animation_state.player_position_ms -= frame_duration;

					if (animation.loop_mode == animation::loop_type::INVERSE) {

						if (animation_state.state == components::animation::playing_state::INCREASING) {
							if (animation_state.get_current_frame() < animation.frames.size() - 1) animation_state.increase_frame();
							else {
								animation_state.decrease_frame();
								animation_state.state = components::animation::playing_state::DECREASING;
							}
						}

						else if (animation_state.state == components::animation::playing_state::DECREASING) {
							if (animation_state.get_current_frame() > 0) animation_state.decrease_frame();
							else {
								animation_state.increase_frame();
								animation_state.state = components::animation::playing_state::INCREASING;
							}
						}
					}

					else if (animation.loop_mode == animation::loop_type::REPEAT) {
						if (animation_state.state == components::animation::playing_state::INCREASING) {
							if (animation_state.get_current_frame() < animation.frames.size() - 1)
								animation_state.increase_frame();
							else animation_state.set_current_frame(0);
						}
						else if (animation_state.state == components::animation::playing_state::DECREASING) {
							if (animation_state.get_current_frame() > 0) animation_state.decrease_frame();
							else animation_state.set_current_frame(animation.frames.size() - 1);
						}
					}

					else if (animation.loop_mode == animation::loop_type::NONE) {
						if (animation_state.state == components::animation::playing_state::INCREASING) {
							if (animation_state.get_current_frame() < animation.frames.size() - 1)
								animation_state.increase_frame();
							else animation_state.state = components::animation::playing_state::PAUSED;
						}
						else if (animation_state.state == components::animation::playing_state::DECREASING) {
							if (animation_state.get_current_frame() > 0) animation_state.decrease_frame();
							else animation_state.state = components::animation::playing_state::PAUSED;
						}
					}
				}
				else break;
			}

			auto& sprite = it.get<components::sprite>();
			sprite = animation.frames[animation_state.get_current_frame()].sprite;
		}
	}
}
Beispiel #25
0
void force_joint_system::apply_forces_towards_target_entities(logic_step& step) {
	auto& cosmos = step.cosm;
	const auto delta = step.get_delta();

	for (const auto& it : cosmos.get(processing_subjects::WITH_FORCE_JOINT)) {
		if (!it.has<components::physics>()) continue;

		const auto& physics = it.get<components::physics>();

		if (!physics.is_constructed()) continue;

		const auto& force_joint = it.get<components::force_joint>();
		const auto& chased_entity = cosmos[force_joint.chased_entity];

		if (chased_entity.dead()) continue;

		const auto& chased_entity_transform = chased_entity.logic_transform();
		const auto& chased_transform = chased_entity_transform + force_joint.chased_entity_offset;

		auto direction = chased_transform.pos - physics.get_position();
		const auto& distance = direction.length();
		direction.normalize_hint(distance);

		if (force_joint.divide_transform_mode) {
			const auto current_transform = it.logic_transform();
			const auto interpolated = augs::interp(current_transform, chased_transform, 1.0 - 1.0 / (1.0 + delta.in_seconds() * (60.0)));
			//LOG("Cur: %x,%x, Chas: %x,%x, Inter: %x,%x", current_transform.pos, current_transform.rotation, chased_entity_transform.pos, chased_entity_transform.rotation, interpolated.pos, interpolated.rotation);
			physics.set_transform(interpolated);
		}
		else {
			float force_length = force_joint.force_towards_chased_entity;

			if (distance < force_joint.distance_when_force_easing_starts) {
				auto mult = distance / force_joint.distance_when_force_easing_starts;
				force_length *= pow(mult, force_joint.power_of_force_easing_multiplier);
			}

			const auto& force_for_chaser = vec2(direction).set_length(force_length * 1.f - force_joint.percent_applied_to_chased_entity);
			const auto& force_for_chased = -force_for_chaser * force_joint.percent_applied_to_chased_entity;

			const bool is_force_epsilon = force_for_chaser.length() < 500;

			const auto& offsets = force_joint.force_offsets;

			const int& offsets_count = static_cast<int>(offsets.size());

			//if (!is_force_epsilon) 
			{
				for (const auto& offset : offsets)
					physics.apply_force(force_for_chaser * physics.get_mass() / offsets_count, offset);

				//LOG("F: %x, %x, %x", force_for_chaser, physics.velocity(), AS_INTV physics.get_position());
			}
			//else if (is_force_epsilon && physics.velocity().is_epsilon(1.f)) {
			//	physics.set_velocity(vec2(0, 0));
			//	//physics.set_transform(components::transform(chased_transform.pos, physics.get_angle()));
			//	LOG("Zeroed");
			//}

			if (force_for_chased.length() > 5) {
				const auto& chased_physics = cosmos[force_joint.chased_entity].get<components::physics>();
				chased_physics.apply_force(force_for_chaser * chased_physics.get_mass());
			}

			//if (force_joint.consider_rotation)
			//	it.get<components::rotation_copying>().target_angle = chased_transform.rotation;

			//LOG("F: %x", physics.body->GetLinearDamping());
		}
	}
}