Exemplo n.º 1
0
	void backpack(entity_handle e) {
		auto& container = e += components::container();
		auto& item = make_item(e);
		
		inventory_slot slot_def;
		slot_def.space_available = to_space_units("20");

		container.slots[slot_function::ITEM_DEPOSIT] = slot_def;

		item.dual_wield_accuracy_loss_multiplier = 1;
		item.dual_wield_accuracy_loss_percentage = 50;
		item.space_occupied_per_charge = to_space_units("1");
		item.categories_for_slot_compatibility.set(item_category::SHOULDER_CONTAINER);
	}
Exemplo n.º 2
0
	void populate_grenade_flavours(const populate_flavours_input in) {
		auto& flavours = in.flavours;
		auto& caches = in.caches;
		auto& plain_animations = in.plain_animations;

		(void)plain_animations;

		{
			auto& meta = get_test_flavour(flavours, test_hand_explosives::FORCE_GRENADE);

			meta.get<invariants::text_details>().description =
				"Throwable explosive with a one second delay.\nDeals damage to [color=red]Health[/color]."
			;

			{
				invariants::render render_def;
				render_def.layer = render_layer::SMALL_DYNAMIC_BODY;

				meta.set(render_def);

			}
			test_flavours::add_sprite(meta, caches, test_scene_image_id::FORCE_GRENADE, white);
			test_flavours::add_lying_item_dynamic_body(meta);

			invariants::item item;
			item.space_occupied_per_charge = to_space_units("1.0");
			item.standard_price = 800;
			meta.set(item);

			{
				invariants::hand_fuse fuse; 
				fuse.release_sound.id = to_sound_id(test_scene_sound_id::GRENADE_THROW);
				fuse.armed_sound.id = to_sound_id(test_scene_sound_id::GRENADE_UNPIN);

				fuse.released_image_id = to_image_id(test_scene_image_id::FORCE_GRENADE_RELEASED);
				fuse.released_physical_material = to_physical_material_id(test_scene_physical_material_id::GRENADE);
				fuse.additional_release_impulse.linear = 3000.f;
				fuse.additional_secondary_release_impulse.linear = 2000.f;
				fuse.fuse_delay_ms = 1000.f;

				meta.set(fuse);
			}

			invariants::explosive explosive; 

			auto& in = explosive.explosion;
			auto& dmg = in.damage;

			in.type = adverse_element_type::FORCE;

			{
				auto& c = explosive.cascade[0];
				c.flavour_id = to_entity_flavour_id(test_explosion_bodies::FORCE_GRENADE_CASCADE);
				c.num_spawned = 2;
				c.num_explosions = { 2, 0 };
				c.initial_speed = { 1300.f, 0.2f };
			}

			dmg.base = 88.f;
			in.inner_ring_color = red;
			in.outer_ring_color = orange;
			in.effective_radius = 380.f;
			dmg.impact_impulse = 550.f;
			dmg.impulse_multiplier_against_sentience = 1.f;
			in.sound.id = to_sound_id(test_scene_sound_id::GREAT_EXPLOSION);
			in.sound.modifier.max_distance = 6000.f;
			in.sound.modifier.reference_distance = 2000.f;

			dmg.pass_through_held_item_sound.id = to_sound_id(test_scene_sound_id::BULLET_PASSES_THROUGH_HELD_ITEM);
			dmg.shake.duration_ms = 500.f;
			dmg.shake.mult = 1.2f;

			meta.set(explosive);
		}

		{
			standard_explosion_input e;
			auto& dmg = e.damage;

			e.type = adverse_element_type::FORCE;
			dmg.base = 60.f;
			e.effective_radius = 600.f * 0.4f;
			dmg.impact_impulse = 950.f;
			dmg.impulse_multiplier_against_sentience = 1.f;
			e.sound.modifier.max_distance = 6000.f;
			e.sound.modifier.reference_distance = 2000.f;
			dmg.pass_through_held_item_sound.id = to_sound_id(test_scene_sound_id::BULLET_PASSES_THROUGH_HELD_ITEM);
			dmg.shake.duration_ms = 700.f;
			dmg.shake.mult = 1.4f;
			e.sound.id = to_sound_id(test_scene_sound_id::SKULL_ROCKET_DESTRUCTION);
			e.inner_ring_color = yellow;
			e.outer_ring_color = orange;
			e.ring_duration_seconds = 0.3f;
			e.wave_shake_radius_mult = 6;

			auto& meta = get_test_flavour(flavours, test_explosion_bodies::FORCE_GRENADE_CASCADE);
			auto& c = meta.get<invariants::cascade_explosion>();
			c.explosion = e;
			c.explosion_interval_ms = { 240.f, 0.2f };
			c.circle_collider_radius = 50.f;
			c.max_explosion_angle_displacement = 10.f;

			test_flavours::add_explosion_body(meta);
		}
		{
			auto& meta = get_test_flavour(flavours, test_hand_explosives::INTERFERENCE_GRENADE);

			meta.get<invariants::text_details>().description =
				"Throwable explosive with a one second delay.\nDeals damage to [color=orange]Consciousness[/color].\nCauses massive aimpunch."
			;

			{
				invariants::render render_def;
				render_def.layer = render_layer::SMALL_DYNAMIC_BODY;

				meta.set(render_def);
			}
			test_flavours::add_sprite(meta, caches, test_scene_image_id::INTERFERENCE_GRENADE, white);
			test_flavours::add_lying_item_dynamic_body(meta);

			invariants::item item;
			item.standard_price = 400;
			item.space_occupied_per_charge = to_space_units("1.0");
			meta.set(item);

			{
				invariants::hand_fuse fuse; 
				fuse.release_sound.id = to_sound_id(test_scene_sound_id::GRENADE_THROW);
				fuse.armed_sound.id = to_sound_id(test_scene_sound_id::GRENADE_UNPIN);
				fuse.released_image_id = to_image_id(test_scene_image_id::INTERFERENCE_GRENADE_RELEASED);
				fuse.released_physical_material = to_physical_material_id(test_scene_physical_material_id::GRENADE);
				fuse.additional_release_impulse.linear = 3000.f;
				fuse.additional_secondary_release_impulse.linear = 2000.f;
				fuse.fuse_delay_ms = 800.f;

				meta.set(fuse);
			}

			invariants::explosive explosive; 

			auto& in = explosive.explosion;
			auto& dmg = in.damage;

			dmg.base = 80.f;
			in.inner_ring_color = yellow;
			in.outer_ring_color = orange;
			in.effective_radius = 450.f;
			dmg.impact_impulse = 2.f;
			dmg.impulse_multiplier_against_sentience = 3000.f;
			in.sound.id = to_sound_id(test_scene_sound_id::INTERFERENCE_EXPLOSION);
			in.sound.modifier.max_distance = 6000.f;
			in.sound.modifier.reference_distance = 2000.f;
			in.type = adverse_element_type::INTERFERENCE;

			dmg.pass_through_held_item_sound.id = to_sound_id(test_scene_sound_id::BULLET_PASSES_THROUGH_HELD_ITEM);
			dmg.shake.duration_ms = 2500.f;
			dmg.shake.mult = 1.6f;

			{
				auto e = in;
				e *= 0.6f;
				e.damage.impact_impulse = 2.f * 0.6f;
				e.wave_shake_radius_mult = 6;
				e.sound.modifier.gain = 1.f;
				e.sound.id = to_sound_id(test_scene_sound_id::INTERFERENCE_EXPLOSION);
				e.sound.modifier.gain = 0.1f;
				e.sound.modifier.pitch = 0.75f;
				e.sound.modifier.max_distance = 6000.f;
				e.sound.modifier.reference_distance = 2000.f;
				e.inner_ring_color = orange;
				e.outer_ring_color = yellow;
				e.ring_duration_seconds = 0.3f;

				auto& meta = get_test_flavour(flavours, test_explosion_bodies::INTERFERENCE_CASCADE);
				auto& c = meta.get<invariants::cascade_explosion>();
				c.explosion = e;
				c.explosion_interval_ms = { 200.f, 0.4f };
				c.circle_collider_radius = 50.f;
				c.max_explosion_angle_displacement = 10.f;

				test_flavours::add_explosion_body(meta);
			}

			{
				auto& c = explosive.cascade[0];
				c.flavour_id = to_entity_flavour_id(test_explosion_bodies::INTERFERENCE_CASCADE);
				c.num_spawned = 3;
				c.num_explosions = { 2, 0 };
				c.initial_speed = { 1400.f, 0.3f };
			}

			meta.set(explosive);
		}

		{
			auto& meta = get_test_flavour(flavours, test_hand_explosives::FLASHBANG);

			meta.get<invariants::text_details>().description =
				"Throwable explosive with a one second delay.\nDeals damage to [color=orange]Consciousness[/color].\nCauses massive aimpunch."
			;

			{
				invariants::render render_def;
				render_def.layer = render_layer::SMALL_DYNAMIC_BODY;

				meta.set(render_def);
			}
			test_flavours::add_sprite(meta, caches, test_scene_image_id::FLASHBANG, white);
			auto& fixtures = test_flavours::add_lying_item_dynamic_body(meta);
			fixtures.restitution = 1.f;

			invariants::item item;
			item.standard_price = 1000;
			item.space_occupied_per_charge = to_space_units("1.0");
			meta.set(item);

			{
				invariants::hand_fuse fuse; 
				fuse.release_sound.id = to_sound_id(test_scene_sound_id::GRENADE_THROW);
				fuse.armed_sound.id = to_sound_id(test_scene_sound_id::GRENADE_UNPIN);
				fuse.released_image_id = to_image_id(test_scene_image_id::FLASHBANG_RELEASED);
				fuse.released_physical_material = to_physical_material_id(test_scene_physical_material_id::FLASHBANG);
				fuse.additional_release_impulse.linear = 3000.f;
				fuse.additional_secondary_release_impulse.linear = 2000.f;
				fuse.fuse_delay_ms = 800.f;

				meta.set(fuse);
			}

			invariants::explosive explosive; 

			auto& in = explosive.explosion;
			auto& dmg = in.damage;

			dmg.base = 6.f;
			in.inner_ring_color = white;
			in.outer_ring_color = white;
			in.effective_radius = 1000.f;
			dmg.impact_impulse = 0.f;
			dmg.impulse_multiplier_against_sentience = 0.f;
			in.sound.id = to_sound_id(test_scene_sound_id::FLASHBANG_EXPLOSION);
			in.sound.modifier.max_distance = 6000.f;
			in.sound.modifier.reference_distance = 2000.f;
			in.type = adverse_element_type::FLASH;

			dmg.pass_through_held_item_sound.id = to_sound_id(test_scene_sound_id::BULLET_PASSES_THROUGH_HELD_ITEM);
			dmg.shake.duration_ms = 300.f;
			dmg.shake.mult = 0.9f;

			meta.set(explosive);
		}

		{
			auto& meta = get_test_flavour(flavours, test_hand_explosives::PED_GRENADE);

			meta.get<invariants::text_details>().description =
				"Throwable explosive with a one second delay.\nDrains [color=cyan]Personal Electricity[/color].\nIf the subject has [color=turquoise]Electric Shield[/color] enabled,\nthe effect is doubled."
			;

			{
				invariants::render render_def;
				render_def.layer = render_layer::SMALL_DYNAMIC_BODY;

				meta.set(render_def);
			}
			test_flavours::add_sprite(meta, caches, test_scene_image_id::PED_GRENADE, white);
			test_flavours::add_lying_item_dynamic_body(meta);

			invariants::item item;
			item.standard_price = 600;
			item.space_occupied_per_charge = to_space_units("1.0");
			meta.set(item);

			{
				invariants::hand_fuse fuse; 

				fuse.release_sound.id = to_sound_id(test_scene_sound_id::GRENADE_THROW);
				fuse.armed_sound.id = to_sound_id(test_scene_sound_id::GRENADE_UNPIN);

				fuse.released_image_id = to_image_id(test_scene_image_id::PED_GRENADE_RELEASED);
				fuse.released_physical_material = to_physical_material_id(test_scene_physical_material_id::GRENADE);
				fuse.additional_release_impulse.linear = 3000.f;
				fuse.additional_secondary_release_impulse.linear = 2000.f;

				meta.set(fuse);
			}

			invariants::explosive explosive; 

			auto& in = explosive.explosion;
			auto& dmg = in.damage;

			dmg.base = 150.f;
			in.inner_ring_color = cyan;
			in.outer_ring_color = turquoise;
			in.effective_radius = 570.f;
			dmg.impact_impulse = 2.f;
			dmg.impulse_multiplier_against_sentience = 1.f;
			in.sound.id = to_sound_id(test_scene_sound_id::PED_EXPLOSION);
			in.sound.modifier.max_distance = 6000.f;
			in.sound.modifier.reference_distance = 2000.f;
			in.type = adverse_element_type::PED;
			in.create_thunders_effect = true;

			dmg.pass_through_held_item_sound.id = to_sound_id(test_scene_sound_id::BULLET_PASSES_THROUGH_HELD_ITEM);
			dmg.shake = { 0.f, 0.f };

			meta.set(explosive);
		}

		const auto bomb_explosion = []() {
			standard_explosion_input in;
			auto& dmg = in.damage;

			in.type = adverse_element_type::FORCE;
			dmg.base = 348.f;
			in.inner_ring_color = cyan;
			in.outer_ring_color = white;
			in.effective_radius = 600.f;
			dmg.impact_impulse = 950.f;
			dmg.impulse_multiplier_against_sentience = 1.f;
			in.sound.id = to_sound_id(test_scene_sound_id::BOMB_EXPLOSION);
			in.sound.modifier.max_distance = 6000.f;
			in.sound.modifier.reference_distance = 2000.f;

			dmg.pass_through_held_item_sound.id = to_sound_id(test_scene_sound_id::BULLET_PASSES_THROUGH_HELD_ITEM);
			dmg.shake.duration_ms = 700.f;
			dmg.shake.mult = 1.4f;

			return in;
		}();

		auto bomb_cascade_explosion = bomb_explosion;
		//bomb_cascade_explosion *= 0.7f;
		bomb_cascade_explosion.sound.id = to_sound_id(test_scene_sound_id::CASCADE_EXPLOSION);
		bomb_cascade_explosion.inner_ring_color = white;
		bomb_cascade_explosion.outer_ring_color = cyan;
		bomb_cascade_explosion.ring_duration_seconds = 0.3f;

		{
			auto& meta = get_test_flavour(flavours, test_explosion_bodies::BOMB_CASCADE_EXPLOSION);
			auto& c = meta.get<invariants::cascade_explosion>();
			c.explosion = bomb_cascade_explosion;
			c.explosion_interval_ms = { 200.f, 0.4f };
			c.circle_collider_radius = 50.f;
			c.max_explosion_angle_displacement = 10.f;

			test_flavours::add_explosion_body(meta);
		}

		{
			auto e = bomb_explosion;
			e *= 0.3f;
			e.sound.id = to_sound_id(test_scene_sound_id::SKULL_ROCKET_DESTRUCTION);
			e.inner_ring_color = cyan;
			e.outer_ring_color = white;
			e.ring_duration_seconds = 0.3f;
			e.wave_shake_radius_mult = 6;

			auto& meta = get_test_flavour(flavours, test_explosion_bodies::ELECTRIC_MISSILE_CASCADE);
			auto& c = meta.get<invariants::cascade_explosion>();
			c.explosion = e;
			c.explosion_interval_ms = { 200.f, 0.4f };
			c.circle_collider_radius = 50.f;
			c.max_explosion_angle_displacement = 10.f;

			test_flavours::add_explosion_body(meta);
		}

		{
			auto e = bomb_explosion;
			e *= 0.1f;
			e.wave_shake_radius_mult = 6;
			e.sound.id = to_sound_id(test_scene_sound_id::GREAT_EXPLOSION);
			e.inner_ring_color = white;
			e.outer_ring_color = cyan;
			e.ring_duration_seconds = 0.3f;

			auto& meta = get_test_flavour(flavours, test_explosion_bodies::ELECTRIC_MISSILE_CASCADE_SMALLER);
			auto& c = meta.get<invariants::cascade_explosion>();
			c.explosion = e;
			c.explosion_interval_ms = { 200.f, 0.4f };
			c.circle_collider_radius = 50.f;
			c.max_explosion_angle_displacement = 10.f;

			test_flavours::add_explosion_body(meta);
		}

		{
			auto e = bomb_explosion;
			e *= 0.3f;
			e.sound.id = to_sound_id(test_scene_sound_id::PED_EXPLOSION);
			e.inner_ring_color = cyan;
			e.outer_ring_color = turquoise;
			e.ring_duration_seconds = 0.3f;
			e.wave_shake_radius_mult = 6;
			e.type = adverse_element_type::PED;

			auto& meta = get_test_flavour(flavours, test_explosion_bodies::BLUNAZ_MISSILE_CASCADE);
			auto& c = meta.get<invariants::cascade_explosion>();
			c.explosion = e;
			c.explosion_interval_ms = { 200.f, 0.4f };
			c.circle_collider_radius = 50.f;
			c.max_explosion_angle_displacement = 10.f;

			test_flavours::add_explosion_body(meta);
		}

		{
			auto e = bomb_explosion;
			e *= 0.2f;
			e.wave_shake_radius_mult = 6;
			e.sound.id = to_sound_id(test_scene_sound_id::PED_EXPLOSION);
			e.inner_ring_color = turquoise;
			e.outer_ring_color = cyan;
			e.ring_duration_seconds = 0.3f;
			e.type = adverse_element_type::PED;

			auto& meta = get_test_flavour(flavours, test_explosion_bodies::BLUNAZ_MISSILE_CASCADE_SMALLER);
			auto& c = meta.get<invariants::cascade_explosion>();
			c.explosion = e;
			c.explosion_interval_ms = { 200.f, 0.4f };
			c.circle_collider_radius = 50.f;
			c.max_explosion_angle_displacement = 10.f;

			test_flavours::add_explosion_body(meta);
		}

		{
			auto e = bomb_explosion;
			e *= 0.4f;
			e.sound.id = to_sound_id(test_scene_sound_id::SKULL_ROCKET_DESTRUCTION);
			e.inner_ring_color = yellow;
			e.outer_ring_color = orange;
			e.ring_duration_seconds = 0.3f;
			e.wave_shake_radius_mult = 6;

			auto& meta = get_test_flavour(flavours, test_explosion_bodies::SKULL_ROCKET_CASCADE);
			auto& c = meta.get<invariants::cascade_explosion>();
			c.explosion = e;
			c.explosion_interval_ms = { 220.f, 0.4f };
			c.circle_collider_radius = 50.f;
			c.max_explosion_angle_displacement = 10.f;

			test_flavours::add_explosion_body(meta);
		}

		{
			auto e = bomb_explosion;
			e *= 0.35f;
			e.wave_shake_radius_mult = 6;
			e.sound.id = to_sound_id(test_scene_sound_id::GREAT_EXPLOSION);
			e.inner_ring_color = red;
			e.outer_ring_color = orange;
			e.ring_duration_seconds = 0.3f;

			auto& meta = get_test_flavour(flavours, test_explosion_bodies::SKULL_ROCKET_CASCADE_SMALLER);
			auto& c = meta.get<invariants::cascade_explosion>();
			c.explosion = e;
			c.explosion_interval_ms = { 200.f, 0.4f };
			c.circle_collider_radius = 50.f;
			c.max_explosion_angle_displacement = 10.f;

			test_flavours::add_explosion_body(meta);
		}

		{
			auto smaller_bomb_cascade_explosion = bomb_explosion;
			smaller_bomb_cascade_explosion *= 0.07f;
			smaller_bomb_cascade_explosion.sound.id = to_sound_id(test_scene_sound_id::FIREWORK);
			smaller_bomb_cascade_explosion.inner_ring_color = green;
			smaller_bomb_cascade_explosion.outer_ring_color = dark_green;
			smaller_bomb_cascade_explosion.ring_duration_seconds = 0.3f;

			auto& meta = get_test_flavour(flavours, test_explosion_bodies::BOMB_CASCADE_EXPLOSION_SMALLER);
			auto& c = meta.get<invariants::cascade_explosion>();
			c.explosion = smaller_bomb_cascade_explosion;
			c.explosion_interval_ms = { 60.f, 0.5f };
			c.circle_collider_radius = 5.f;
			c.max_explosion_angle_displacement = 30.f;

			test_flavours::add_explosion_body(meta);
		}

		{
			auto& meta = get_test_flavour(flavours, test_hand_explosives::BOMB);

			meta.get<invariants::text_details>().description =
				"Can be planted. Deals massive damage nearby."
			;

			{
				invariants::render render_def;
				render_def.layer = render_layer::SMALL_DYNAMIC_BODY;

				meta.set(render_def);
			}

			test_flavours::add_sprite(meta, caches, test_scene_image_id::BOMB_1, white);
			test_flavours::add_lying_item_dynamic_body(meta);

			invariants::item item;
			item.space_occupied_per_charge = to_space_units("30");
			item.categories_for_slot_compatibility = { item_category::GENERAL, item_category::OVER_BACK_WEARABLE };
			item.wear_sound.id = to_sound_id(test_scene_sound_id::BACKPACK_WEAR);

			meta.set(item);

			invariants::hand_fuse fuse; 
			fuse.release_sound.id = to_sound_id(test_scene_sound_id::GRENADE_THROW);
			fuse.armed_sound.id = to_sound_id(test_scene_sound_id::GRENADE_UNPIN);
			fuse.override_release_impulse = true;
			fuse.additional_release_impulse = {};
			fuse.additional_secondary_release_impulse = {};
#if 0
			fuse.fuse_delay_ms = 35000.f;
			fuse.set_bomb_vars(1500.f, 10000.f);
#else
			fuse.fuse_delay_ms = 35000.f;
			fuse.set_bomb_vars(1500.f, 7000.f);
#endif
			fuse.beep_sound.id = to_sound_id(test_scene_sound_id::BEEP);
			fuse.beep_sound.modifier.doppler_factor = 0.5f;
			fuse.beep_color = red;
			fuse.beep_time_mult = 0.08f;
			fuse.started_arming_sound.id = to_sound_id(test_scene_sound_id::BOMB_PLANTING);
			fuse.started_defusing_sound.id = to_sound_id(test_scene_sound_id::STARTED_DEFUSING);
			fuse.defused_sound[0].id = to_sound_id(test_scene_sound_id::STEAM_BURST);
			fuse.defused_sound[1].id = to_sound_id(test_scene_sound_id::POWER_OUT);
			fuse.defused_particles.id = to_particle_effect_id(test_scene_particle_effect_id::STEAM_BURST);
			fuse.defused_particles.modifier.colorize = cyan;
			fuse.defused_particles.modifier.scale_amounts = 2.5f;
			fuse.defused_particles.modifier.scale_lifetimes = 2.5f;

			fuse.armed_animation_id = to_animation_id(test_scene_plain_animation_id::BOMB_ARMED);
			fuse.defused_image_id = to_image_id(test_scene_image_id::BOMB_DEFUSED);

			meta.set(fuse);

			{
				invariants::explosive explosive; 
				explosive.explosion = bomb_explosion;

				{
					auto& c = explosive.cascade[0];
					c.flavour_id = to_entity_flavour_id(test_explosion_bodies::BOMB_CASCADE_EXPLOSION);
					c.num_spawned = 4;
					c.num_explosions = { 2, 1 };
					c.initial_speed = { 2000.f, 0.2f };
				}

				{
					auto& c = explosive.cascade[1];
					c.flavour_id = to_entity_flavour_id(test_explosion_bodies::BOMB_CASCADE_EXPLOSION_SMALLER);
					c.num_spawned = 7;
					c.num_explosions = { 7, 2 };
					c.initial_speed = { 2200.f, 0.6f };
					c.spawn_angle_variation = 0.5f;
				}

				meta.set(explosive);
			}
			invariants::animation anim;
			anim.id = to_animation_id(test_scene_plain_animation_id::BOMB);
			meta.set(anim);
		}

		{
			auto& meta = get_test_flavour(flavours, test_plain_missiles::SKULL_ROCKET_FLYING);

			{
				invariants::explosive explosive; 

				standard_explosion_input in;
				auto& dmg = in.damage;

				in.type = adverse_element_type::FORCE;
				dmg.base = 142.f;
				in.inner_ring_color = orange;
				in.outer_ring_color = red;
				in.effective_radius = 500.f;
				dmg.impact_impulse = 350.f;
				dmg.impulse_multiplier_against_sentience = 1.f;
				in.sound.id = to_sound_id(test_scene_sound_id::SKULL_ROCKET_DESTRUCTION);
				in.sound.modifier.max_distance = 6000.f;
				in.sound.modifier.reference_distance = 2000.f;
				in.sound.modifier.distance_model = augs::distance_model::INVERSE_DISTANCE_CLAMPED;

				in.create_thunders_effect = true;
				in.wave_shake_radius_mult = 6;

				dmg.pass_through_held_item_sound.id = to_sound_id(test_scene_sound_id::BULLET_PASSES_THROUGH_HELD_ITEM);
				dmg.shake.duration_ms = 700.f;
				dmg.shake.mult = 1.4f;

				explosive.explosion = in;

				{
					auto& c = explosive.cascade[0];
					c.flavour_id = to_entity_flavour_id(test_explosion_bodies::SKULL_ROCKET_CASCADE);
					c.num_spawned = 2;
					c.num_explosions = { 2, 0 };
					c.initial_speed = { 1300.f, 0.2f };
				}

				{
					auto& c = explosive.cascade[1];
					c.flavour_id = to_entity_flavour_id(test_explosion_bodies::SKULL_ROCKET_CASCADE_SMALLER);
					c.num_spawned = 3;
					c.num_explosions = { 2, 0 };
					c.initial_speed = { 1200.f, 0.6f };
					c.spawn_angle_variation = 0.5f;
				}

				meta.set(explosive);
			}
		}
	}
	void populate_melee_flavours(const populate_flavours_input in) {
		auto& flavours = in.flavours;
		auto& caches = in.caches;

		auto make_knife = [&](
			const auto flavour_id,
			const auto image_id,
			const auto price,
			const auto specific_to,
			const auto weight_mult,
			const auto color
		) -> auto& {
			auto& meta = get_test_flavour(flavours, flavour_id);

			{
				invariants::render render_def;
				render_def.layer = render_layer::SMALL_DYNAMIC_BODY;

				meta.set(render_def);
			}

			test_flavours::add_sprite(meta, caches, image_id, white);

			{
				auto& fixtures = test_flavours::add_lying_item_dynamic_body(meta);
				fixtures.density *= 1.5f * weight_mult;
				fixtures.restitution *= 1.5f;
				fixtures.material = to_physical_material_id(test_scene_physical_material_id::KNIFE);
			}

			{
				invariants::item item;

				item.space_occupied_per_charge = to_space_units("1.5");
				item.holding_stance = item_holding_stance::KNIFE_LIKE;
				item.wield_sound.id = to_sound_id(test_scene_sound_id::STANDARD_KNIFE_DRAW);
				item.standard_price = static_cast<money_type>(price);
				item.specific_to = specific_to;
				item.categories_for_slot_compatibility.set(item_category::SHOULDER_WEARABLE);
				item.wear_sound.id = to_sound_id(test_scene_sound_id::SHEATH_KNIFE);

				meta.set(item);
			}

			{
				invariants::melee melee;

				{
					auto& t = melee.throw_def;
					t.min_speed_to_hurt = 500.f;
					// t.throw_angular_speed = 360.f * 10.f;
					t.throw_angular_speed = 0.f;

					auto& d = t.damage;
					d.pass_through_held_item_sound.id = to_sound_id(test_scene_sound_id::BULLET_PASSES_THROUGH_HELD_ITEM);
					d.base = 88.f * weight_mult;
					auto& eff = d.effects;

					eff.sentience_impact.sound.id = to_sound_id(test_scene_sound_id::STANDARD_KNIFE_SENTIENCE_IMPACT);
					eff.sentience_impact.particles.id = to_particle_effect_id(test_scene_particle_effect_id::STANDARD_KNIFE_IMPACT);
					t.boomerang_impulse.linear = 4000.f;

					{
						auto& clash = t.clash;

						clash.sound.id = to_sound_id(test_scene_sound_id::STANDARD_KNIFE_CLASH);
						clash.particles.id = to_particle_effect_id(test_scene_particle_effect_id::STANDARD_KNIFE_CLASH);
					}
				}

				{
					auto& a = melee.actions[weapon_action_type::PRIMARY];
					a.init_sound.id = to_sound_id(test_scene_sound_id::STANDARD_KNIFE_PRIMARY);
					a.init_particles.id = to_particle_effect_id(test_scene_particle_effect_id::STANDARD_KNIFE_ATTACK);
					a.init_particles.modifier.colorize = color;
					a.wielder_init_particles.id = to_particle_effect_id(test_scene_particle_effect_id::STANDARD_KNIFE_PRIMARY_SMOKE);
					a.obstacle_hit_rotation_inertia_ms = 1000.f;
					a.obstacle_hit_recoil_mult = 1.1f * weight_mult;
					a.obstacle_hit_kickback_impulse = 2500.f;
					a.obstacle_hit_linear_inertia_ms = 140.f;
					a.wielder_impulse = 387.f * weight_mult;
					a.wielder_inert_for_ms = 200.f * weight_mult;
					a.cooldown_ms = 200.f * weight_mult;
					a.cp_required = static_cast<int>(3.f * weight_mult);

					a.obstacle_hit_recoil = 40.f;
					a.sentience_hit_recoil = 10.f * weight_mult;

					a.returning_animation_on_finish = false;

					{
						auto& clash = a.clash;

						clash.sound.id = to_sound_id(test_scene_sound_id::STANDARD_KNIFE_CLASH);
						clash.particles.id = to_particle_effect_id(test_scene_particle_effect_id::STANDARD_KNIFE_CLASH);
						clash.victim_inert_for_ms = 500.f * weight_mult;
						clash.impulse = 450.f * weight_mult;
					}

					a.damage.base = 27.f * weight_mult;
					a.damage.shake.mult *= 0.9f;
					a.damage.impact_impulse = 20.f;
					a.damage.impulse_multiplier_against_sentience = 10.f;
					a.bonus_damage_speed_ratio = 1.f / 1700.f;
					a.damage.pass_through_held_item_sound.id = to_sound_id(test_scene_sound_id::BULLET_PASSES_THROUGH_HELD_ITEM);

					auto& eff = a.damage.effects;

					eff.impact.sound.id = to_sound_id(test_scene_sound_id::STANDARD_KNIFE_PRIMARY_IMPACT);
					eff.impact.particles.id = to_particle_effect_id(test_scene_particle_effect_id::STANDARD_KNIFE_IMPACT);

					eff.sentience_impact.sound.id = to_sound_id(test_scene_sound_id::STANDARD_KNIFE_SENTIENCE_IMPACT);
				}

				{
					auto& a = melee.actions[weapon_action_type::SECONDARY];
					a.init_sound.id = to_sound_id(test_scene_sound_id::STANDARD_KNIFE_SECONDARY);
					a.init_particles.id = to_particle_effect_id(test_scene_particle_effect_id::STANDARD_KNIFE_ATTACK);
					a.init_particles.modifier.colorize = color;
					a.damage.shake.mult *= 1.15f;
					a.wielder_init_particles.id = to_particle_effect_id(test_scene_particle_effect_id::STANDARD_KNIFE_SECONDARY_SMOKE);
					a.wielder_impulse = 717.f;
					a.wielder_inert_for_ms = 300.f * weight_mult;
					a.cooldown_ms = 500.f * weight_mult;
					a.obstacle_hit_linear_inertia_ms = 100.f;
					a.cp_required = static_cast<int>(6.f * weight_mult);
					a.obstacle_hit_recoil_mult = 1.2f * weight_mult;

					a.obstacle_hit_kickback_impulse = 3600.f;
					a.obstacle_hit_rotation_inertia_ms = 1000.f;
					a.obstacle_hit_recoil = 80.f * weight_mult;
					a.sentience_hit_recoil = 20.f * weight_mult;

					a.returning_animation_on_finish = true;

					{
						auto& clash = a.clash;

						clash.sound.id = to_sound_id(test_scene_sound_id::STANDARD_KNIFE_CLASH);
						clash.particles.id = to_particle_effect_id(test_scene_particle_effect_id::STANDARD_KNIFE_CLASH);
						clash.victim_inert_for_ms = 850.f * weight_mult;
						clash.impulse = 750.f * weight_mult;
					}

					a.damage.base = 50.f * weight_mult;
					a.damage.impact_impulse = 40.f;
					a.damage.impulse_multiplier_against_sentience = 10.f;
					a.bonus_damage_speed_ratio = 1.f / 1700.f;
					a.damage.pass_through_held_item_sound.id = to_sound_id(test_scene_sound_id::BULLET_PASSES_THROUGH_HELD_ITEM);

					auto& eff = a.damage.effects;

					eff.impact.sound.id = to_sound_id(test_scene_sound_id::STANDARD_KNIFE_SECONDARY_IMPACT);
					eff.impact.particles.id = to_particle_effect_id(test_scene_particle_effect_id::STANDARD_KNIFE_IMPACT);

					eff.sentience_impact.sound.id = to_sound_id(test_scene_sound_id::STANDARD_KNIFE_SENTIENCE_IMPACT);
				}

				meta.set(melee);
			}

			return meta;
		};

		{
			auto& meta = make_knife(
				test_melee_weapons::FURY_THROWER,
				test_scene_image_id::FURY_THROWER,
				static_cast<money_type>(1000),
				faction_type::RESISTANCE,
				1.1f,
				white
			);

			invariants::continuous_particles particles_def;
			particles_def.effect.id = to_particle_effect_id(test_scene_particle_effect_id::FURY_THROWER_TRACE);
			particles_def.effect.modifier.colorize = orange;
			meta.set(particles_def);

			for (auto& a : meta.get<invariants::melee>().actions) {
				a.init_particles.id = to_particle_effect_id(test_scene_particle_effect_id::FURY_THROWER_ATTACK);
			}
		}

		make_knife(
			test_melee_weapons::ELECTRIC_RAPIER,
			test_scene_image_id::ELECTRIC_RAPIER,
			static_cast<money_type>(700),
			faction_type::SPECTATOR,
			1.f,
			white
		);

		make_knife(
			test_melee_weapons::CYAN_SCYTHE,
			test_scene_image_id::CYAN_SCYTHE,
			static_cast<money_type>(700),
			faction_type::METROPOLIS,
			1.f,
			cyan
		);

		make_knife(
			test_melee_weapons::YELLOW_DAGGER,
			test_scene_image_id::YELLOW_DAGGER,
			static_cast<money_type>(700),
			faction_type::RESISTANCE,
			1.f,
			yellow
		);

		{
			auto& meta = make_knife(
				test_melee_weapons::MINI_KNIFE,
				test_scene_image_id::MINI_KNIFE,
				static_cast<money_type>(500),
				faction_type::SPECTATOR,
				0.7f,
				white
			);

			for (auto& a : meta.get<invariants::melee>().actions) {
				a.init_particles.id = {};
			}
		}

		{
			auto& meta = make_knife(
				test_melee_weapons::POSEIDON,
				test_scene_image_id::POSEIDON,
				static_cast<money_type>(1000),
				faction_type::SPECTATOR,
				1.1f,
				white
			);
			
			invariants::continuous_particles particles_def;
			particles_def.effect.id = to_particle_effect_id(test_scene_particle_effect_id::POSEIDON_THROWER_TRACE);
			particles_def.effect.modifier.colorize = rgba(0, 200, 255, 255);
			meta.set(particles_def);

			for (auto& a : meta.get<invariants::melee>().actions) {
				a.init_particles.id = to_particle_effect_id(test_scene_particle_effect_id::POSEIDON_THROWER_ATTACK);
			}
		}

		{
			auto& meta = make_knife(
				test_melee_weapons::ASSAULT_RATTLE,
				test_scene_image_id::ASSAULT_RATTLE_1,
				static_cast<money_type>(1700),
				faction_type::SPECTATOR,
				1.8f,
				cyan
			);

			auto& melee = meta.template get<invariants::melee>();

			melee.throw_def.damage.effects.sentience_impact.sound.id = to_sound_id(test_scene_sound_id::ASSAULT_RATTLE_SECONDARY_IMPACT);
			melee.throw_def.clash.sound.id = to_sound_id(test_scene_sound_id::ASSAULT_RATTLE_CLASH);
			melee.throw_def.throw_angular_speed = 360.f * 25.f;
			melee.adversarial.knockout_award = static_cast<money_type>(700); 

			{
				auto& a = melee.actions[weapon_action_type::PRIMARY];
				a.init_sound.id = to_sound_id(test_scene_sound_id::STANDARD_KNIFE_PRIMARY);
				a.clash.sound.id = to_sound_id(test_scene_sound_id::ASSAULT_RATTLE_CLASH);

				auto& eff = a.damage.effects;
				eff.impact.sound.id = to_sound_id(test_scene_sound_id::ASSAULT_RATTLE_SECONDARY_IMPACT);
				eff.sentience_impact = {};
			}

			{
				auto& a = melee.actions[weapon_action_type::SECONDARY];
				a.init_sound.id = to_sound_id(test_scene_sound_id::STANDARD_KNIFE_SECONDARY);
				a.clash.sound.id = to_sound_id(test_scene_sound_id::ASSAULT_RATTLE_CLASH);

				auto& eff = a.damage.effects;
				eff.impact.sound.id = to_sound_id(test_scene_sound_id::ASSAULT_RATTLE_SECONDARY_IMPACT);
				eff.sentience_impact = {};
			}

			auto& snd = meta.template get<invariants::continuous_sound>().effect;
			snd.id = to_sound_id(test_scene_sound_id::ASSAULT_RATTLE_HUMMING);
			snd.modifier.gain *= 0.15f;

			auto& modifier = snd.modifier;

			modifier.distance_model = augs::distance_model::LINEAR_DISTANCE_CLAMPED;
			modifier.reference_distance = 50.f;
			modifier.max_distance = 150.f;

			invariants::animation anim;
			anim.id = to_animation_id(test_scene_plain_animation_id::ASSAULT_RATTLE);
			meta.set(anim);

			meta.template get<invariants::fixtures>().material = to_physical_material_id(test_scene_physical_material_id::METAL);
			meta.template get<invariants::item>().wield_sound.id = to_sound_id(test_scene_sound_id::ASSAULT_RATTLE_DRAW);
			meta.template get<invariants::item>().space_occupied_per_charge = to_space_units("3.0");
		}
	}