Esempio n. 1
0
void slot_button::update_rc(const logic_gui_context& context, const this_in_container& this_id) {
	const auto& step = context.get_step();
	const auto& cosmos = step.get_cosmos();

	const auto slot_id = cosmos[this_id.get_location().slot_id];

	if (slot_id->always_allow_exactly_one_item) {
		this_id->set_flag(augs::gui::flag::ENABLE_DRAWING);

		if (slot_id.has_items()) {
			const_dereferenced_location<item_button_in_item> child_item_button = context.dereference_location(item_button_in_item{ slot_id.get_items_inside()[0].get_id() });

			if (child_item_button->is_being_wholely_dragged_or_pending_finish(context, child_item_button)) {
				this_id->set_flag(augs::gui::flag::ENABLE_DRAWING);
			}
			else {
				this_id->unset_flag(augs::gui::flag::ENABLE_DRAWING);
			}
		}
	}

	this_id->slot_relative_pos = griddify(this_id->slot_relative_pos);
	this_id->user_drag_offset = griddify(this_id->user_drag_offset);

	vec2i absolute_pos = this_id->slot_relative_pos + this_id->user_drag_offset;

	if (context.get_rect_world().is_currently_dragging(this_id)) {
		absolute_pos += griddify(context.get_rect_world().current_drag_amount);
	}

	this_id->rc.set_position(absolute_pos);
}
ammunition_information calc_reloadable_ammo_info(const const_entity_handle item) {
	ammunition_information out;

	const auto maybe_magazine_slot = item[slot_function::GUN_DETACHABLE_MAGAZINE];

	if (maybe_magazine_slot.alive() && maybe_magazine_slot.has_items()) {
		const auto mag = item.get_cosmos()[maybe_magazine_slot.get_items_inside()[0]];
		const auto ammo_depo = mag[slot_function::ITEM_DEPOSIT];

		ensure(ammo_depo->has_limited_space());

		out.total_charges += count_charges_in_deposit(mag);
		out.total_ammo_space += ammo_depo->space_available;
		out.available_ammo_space += ammo_depo.calc_local_space_available();
	}

	return out;
}
Esempio n. 3
0
static void
break_dlg(const GSList * frame_list)
{
	gdbui_enable(TRUE);
	if (has_items(frame_list))
	{
		const GSList *p;
		GtkTreeIter iter;
		GtkListStore *store;
		GtkWidget *listview;
		GtkTreeViewColumn *column;
		GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
		GtkTreeSelection *selection;
		GtkWidget *scroll;
		GtkWidget *delete_btn;
		GtkWidget *add_btn;
		GtkWidget *edit_btn;
		GtkWidget *close_btn;
		gboolean HaveWhat = FALSE;
		gboolean HaveFile = FALSE;
		gboolean HaveLine = FALSE;
		gboolean HaveFunc = FALSE;
		gboolean HaveAccess = FALSE;
		gint resp = 0;
		const gchar *access_type;
		BkPtDlgData bpd = { NULL, NULL };
		gint rowcount = 0;
		store = gtk_list_store_new(bcNumCols, G_TYPE_STRING,	/*bcNumber*/
					   G_TYPE_STRING,	/*bcEnabled*/
					   G_TYPE_STRING,	/*bcWhat*/
					   G_TYPE_STRING,	/*bcFile*/
					   G_TYPE_STRING,	/*bcLine*/
					   G_TYPE_STRING,	/*bcFunc*/
					   G_TYPE_STRING,	/*bcTimes*/
					   G_TYPE_STRING,	/*bcIgnore*/
					   G_TYPE_STRING,	/*bcCond*/
					   G_TYPE_STRING,	/*bcAccess*/
					   G_TYPE_POINTER	/*bcData*/
			);
		for (p = frame_list; p; p = p->next)
		{
			GdbBreakPointInfo *bpi = p->data;
			if (bpi)
			{
				gboolean iswatch = !g_str_equal("breakpoint", bpi->type);
				if (is_watchlist != iswatch)
				{
					continue;
				}
				if (g_str_equal(bpi->number, "1"))
				{
					continue;
				}
				access_type = access_txt(bpi);

				gtk_list_store_append(store, &iter);
				gtk_list_store_set(store, &iter,
						   bcNumber, bpi->number,
						   bcEnabled, bpi->enabled,
						   bcWhat, bpi->what,
						   bcFile, bpi->file,
						   bcLine, bpi->line,
						   bcFunc, bpi->func,
						   bcTimes, bpi->times,
						   bcIgnore, bpi->ignore ? bpi->ignore : "0",
						   bcCond, bpi->cond,
						   bcAccess, access_type, bcData, bpi, -1);
				HaveWhat = HaveWhat || (bpi->what && *bpi->what);
				HaveFile = HaveFile || (bpi->file && *bpi->file);
				HaveLine = HaveLine || (bpi->line && *bpi->line);
				HaveFunc = HaveFunc || (bpi->func && *bpi->func);
				HaveAccess = HaveAccess || access_type;
				rowcount++;
			}
		}
		listview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));

		g_signal_connect(G_OBJECT(listview), "key-press-event", G_CALLBACK(list_keypress),
				 &bpd);
		column = gtk_tree_view_column_new_with_attributes("#", renderer, "text", bcNumber,
								  NULL);
		gtk_tree_view_append_column(GTK_TREE_VIEW(listview), column);

		column = gtk_tree_view_column_new_with_attributes("on", renderer, "text", bcEnabled,
								  NULL);
		gtk_tree_view_append_column(GTK_TREE_VIEW(listview), column);

		if (HaveWhat)
		{
			column = gtk_tree_view_column_new_with_attributes("what", renderer, "text",
									  bcWhat, NULL);
			gtk_tree_view_append_column(GTK_TREE_VIEW(listview), column);
		}

		if (HaveFile)
		{
			column = gtk_tree_view_column_new_with_attributes("filename", renderer,
									  "text", bcFile, NULL);
			gtk_tree_view_append_column(GTK_TREE_VIEW(listview), column);
		}

		if (HaveLine)
		{
			column = gtk_tree_view_column_new_with_attributes("line", renderer, "text",
									  bcLine, NULL);
			gtk_tree_view_append_column(GTK_TREE_VIEW(listview), column);
		}

		if (HaveFunc)
		{
			column = gtk_tree_view_column_new_with_attributes("function", renderer,
									  "text", bcFunc, NULL);
			gtk_tree_view_append_column(GTK_TREE_VIEW(listview), column);
		}


		if (HaveAccess)
		{
			column = gtk_tree_view_column_new_with_attributes("trap", renderer, "text",
									  bcAccess, NULL);
			gtk_tree_view_append_column(GTK_TREE_VIEW(listview), column);
		}


		column = gtk_tree_view_column_new_with_attributes("times", renderer, "text",
								  bcTimes, NULL);
		gtk_tree_view_append_column(GTK_TREE_VIEW(listview), column);

		column = gtk_tree_view_column_new_with_attributes("skip", renderer, "text",
								  bcIgnore, NULL);
		gtk_tree_view_append_column(GTK_TREE_VIEW(listview), column);

		column = gtk_tree_view_column_new_with_attributes("condition", renderer, "text",
								  bcCond, NULL);
		gtk_tree_view_append_column(GTK_TREE_VIEW(listview), column);

		selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(listview));
		gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
		g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(break_select_cb), &bpd);

		bpd.dlg = gdbui_new_dialog(is_watchlist ? _("Watchpoints") : _("Breakpoints"));

		scroll = gtk_scrolled_window_new(NULL, NULL);
		gtk_widget_set_usize(scroll,
				     (gdk_screen_get_width(gdk_screen_get_default()) / 3) * 2,
				     (gdk_screen_get_height(gdk_screen_get_default()) / 3) * 1);
		gtk_container_add(GTK_CONTAINER(scroll), listview);

		gtk_box_pack_start(GTK_BOX(GTK_DIALOG(bpd.dlg)->vbox), scroll, FALSE, FALSE, 0);
		delete_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);

		g_signal_connect(G_OBJECT(delete_btn), "clicked", G_CALLBACK(delete_click), &bpd);
		gtk_container_add(GTK_CONTAINER(GTK_DIALOG(bpd.dlg)->action_area), delete_btn);
		edit_btn = gtk_button_new_from_stock(GTK_STOCK_EDIT);

		g_signal_connect(G_OBJECT(edit_btn), "clicked", G_CALLBACK(edit_click), &bpd);
		gtk_container_add(GTK_CONTAINER(GTK_DIALOG(bpd.dlg)->action_area), edit_btn);
		add_btn = gtk_button_new_from_stock(GTK_STOCK_ADD);

		g_signal_connect(G_OBJECT(add_btn), "clicked", G_CALLBACK(add_click), &bpd);
		gtk_container_add(GTK_CONTAINER(GTK_DIALOG(bpd.dlg)->action_area), add_btn);



		close_btn =
			gtk_dialog_add_button(GTK_DIALOG(bpd.dlg), GTK_STOCK_CLOSE, dlgRespClose);
		gtk_widget_set_sensitive(delete_btn, rowcount > 0);
		gtk_widget_set_sensitive(edit_btn, rowcount > 0);
		gtk_dialog_set_default_response(GTK_DIALOG(bpd.dlg), dlgRespClose);
		gtk_widget_show_all(bpd.dlg);
		do
		{
			resp = gtk_dialog_run(GTK_DIALOG(bpd.dlg));
			switch (resp)
			{
				case dlgRespDeleteConfirmed:
					{
						resp = dlgRespClose;
						gtk_widget_destroy(bpd.dlg);
						break;
					}
				case dlgRespDeleteCancelled:
					{
						break;
					}
				case dlgRespEditConfirmed:
					{
						resp = dlgRespClose;
						gtk_widget_destroy(bpd.dlg);
						gdbio_wait(100);
						gdbui_enable(FALSE);
						gdbio_show_breaks(break_dlg);
						break;
					}
				case dlgRespEditCancelled:
					{
						break;
					}
				case dlgRespAddConfirmed:
					{
						resp = dlgRespClose;
						gtk_widget_destroy(bpd.dlg);
						break;
					}
				case dlgRespAddCancelled:
					{
						break;
					}
				case dlgRespClose:
				default:
					{
						gtk_widget_destroy(bpd.dlg);
						resp = dlgRespClose;
						break;
					}
			}
		}
		while (resp != dlgRespClose);
		gtk_window_present(GTK_WINDOW(gdbui_setup.main_window));
	}
	else
	{
		add_click(NULL, NULL);
	}

}
Esempio n. 4
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();
				}
			}
		}
	}
}
Esempio n. 5
0
void map::generate_lightmap( const int zlev )
{
    auto &map_cache = get_cache( zlev );
    auto &lm = map_cache.lm;
    auto &sm = map_cache.sm;
    auto &outside_cache = map_cache.outside_cache;
    std::memset(lm, 0, sizeof(lm));
    std::memset(sm, 0, sizeof(sm));

    /* Bulk light sources wastefully cast rays into neighbors; a burning hospital can produce
         significant slowdown, so for stuff like fire and lava:
     * Step 1: Store the position and luminance in buffer via add_light_source, for efficient
         checking of neighbors.
     * Step 2: After everything else, iterate buffer and apply_light_source only in non-redundant
         directions
     * Step 3: ????
     * Step 4: Profit!
     */
    auto &light_source_buffer = map_cache.light_source_buffer;
    std::memset(light_source_buffer, 0, sizeof(light_source_buffer));

    constexpr int dir_x[] = {  0, -1 , 1, 0 };   //    [0]
    constexpr int dir_y[] = { -1,  0 , 0, 1 };   // [1][X][2]
    constexpr int dir_d[] = { 90, 0, 180, 270 }; //    [3]

    const float natural_light  = g->natural_light_level( zlev );
    const float inside_light = (natural_light > LIGHT_SOURCE_BRIGHT) ?
        LIGHT_AMBIENT_LOW + 1.0 : LIGHT_AMBIENT_MINIMAL;
    // Apply sunlight, first light source so just assign
    for( int sx = 0; sx < LIGHTMAP_CACHE_X; ++sx ) {
        for( int sy = 0; sy < LIGHTMAP_CACHE_Y; ++sy ) {
            // In bright light indoor light exists to some degree
            if( !outside_cache[sx][sy] ) {
                lm[sx][sy] = inside_light;
            } else {
                lm[sx][sy] = natural_light;
            }
        }
    }

    apply_character_light( g->u );
    for( auto &n : g->active_npc ) {
        apply_character_light( *n );
    }

    // Traverse the submaps in order
    for (int smx = 0; smx < my_MAPSIZE; ++smx) {
        for (int smy = 0; smy < my_MAPSIZE; ++smy) {
            auto const cur_submap = get_submap_at_grid( smx, smy, zlev );

            for (int sx = 0; sx < SEEX; ++sx) {
                for (int sy = 0; sy < SEEY; ++sy) {
                    const int x = sx + smx * SEEX;
                    const int y = sy + smy * SEEY;
                    const tripoint p( x, y, zlev );
                    // Project light into any openings into buildings.
                    if (natural_light > LIGHT_SOURCE_BRIGHT && !outside_cache[p.x][p.y]) {
                        // Apply light sources for external/internal divide
                        for(int i = 0; i < 4; ++i) {
                            if (INBOUNDS(p.x + dir_x[i], p.y + dir_y[i]) &&
                                outside_cache[p.x + dir_x[i]][p.y + dir_y[i]]) {
                                lm[p.x][p.y] = natural_light;

                                if (light_transparency( p ) > LIGHT_TRANSPARENCY_SOLID) {
                                    apply_directional_light( p, dir_d[i], natural_light );
                                }
                            }
                        }
                    }

                    if( cur_submap->lum[sx][sy] && has_items( p ) ) {
                        auto items = i_at( p );
                        add_light_from_items( p, items.begin(), items.end() );
                    }

                    const ter_id terrain = cur_submap->ter[sx][sy];
                    if (terrain == t_lava) {
                        add_light_source( p, 50 );
                    } else if (terrain == t_console) {
                        add_light_source( p, 10 );
                    } else if (terrain == t_utility_light) {
                        add_light_source( p, 240 );
                    }

                    for( auto &fld : cur_submap->fld[sx][sy] ) {
                        const field_entry *cur = &fld.second;
                        // TODO: [lightmap] Attach light brightness to fields
                        switch(cur->getFieldType()) {
                        case fd_fire:
                            if (3 == cur->getFieldDensity()) {
                                add_light_source( p, 160 );
                            } else if (2 == cur->getFieldDensity()) {
                                add_light_source( p, 60 );
                            } else {
                                add_light_source( p, 20 );
                            }
                            break;
                        case fd_fire_vent:
                        case fd_flame_burst:
                            add_light_source( p, 20 );
                            break;
                        case fd_electricity:
                        case fd_plasma:
                            if (3 == cur->getFieldDensity()) {
                                add_light_source( p, 20 );
                            } else if (2 == cur->getFieldDensity()) {
                                add_light_source( p, 4 );
                            } else {
                                // Kinda a hack as the square will still get marked.
                                apply_light_source( p, LIGHT_SOURCE_LOCAL );
                            }
                            break;
                        case fd_incendiary:
                            if (3 == cur->getFieldDensity()) {
                                add_light_source( p, 160 );
                            } else if (2 == cur->getFieldDensity()) {
                                add_light_source( p, 60 );
                            } else {
                                add_light_source( p, 20 );
                            }
                            break;
                        case fd_laser:
                            apply_light_source( p, 4 );
                            break;
                        case fd_spotlight:
                            add_light_source( p, 80 );
                            break;
                        case fd_dazzling:
                            add_light_source( p, 5 );
                            break;
                        default:
                            //Suppress warnings
                            break;
                        }
                    }
                }
            }
        }
    }

    for (size_t i = 0; i < g->num_zombies(); ++i) {
        auto &critter = g->zombie(i);
        if(critter.is_hallucination()) {
            continue;
        }
        const tripoint &mp = critter.pos();
        if( inbounds( mp ) ) {
            if (critter.has_effect( effect_onfire)) {
                apply_light_source( mp, 8 );
            }
            // TODO: [lightmap] Attach natural light brightness to creatures
            // TODO: [lightmap] Allow creatures to have light attacks (ie: eyebot)
            // TODO: [lightmap] Allow creatures to have facing and arc lights
            if (critter.type->luminance > 0) {
                apply_light_source( mp, critter.type->luminance );
            }
        }
    }

    // Apply any vehicle light sources
    VehicleList vehs = get_vehicles();
    for( auto &vv : vehs ) {
        vehicle *v = vv.v;
        if(v->lights_on) {
            int dir = v->face.dir();
            float veh_luminance = 0.0;
            float iteration = 1.0;
            std::vector<int> light_indices = v->all_parts_with_feature(VPFLAG_CONE_LIGHT);
            for( auto &light_indice : light_indices ) {
                veh_luminance += ( v->part_info( light_indice ).bonus / iteration );
                iteration = iteration * 1.1;
            }
            if (veh_luminance > LL_LIT) {
                for( auto &light_indice : light_indices ) {
                    tripoint pp = tripoint( vv.x, vv.y, vv.z ) +
                                  v->parts[light_indice].precalc[0];
                    if( inbounds( pp ) ) {
                        add_light_source( pp, SQRT_2 ); // Add a little surrounding light
                        apply_light_arc( pp, dir + v->parts[light_indice].direction,
                                         veh_luminance, 45 );
                    }
                }
            }
        }
        if(v->overhead_lights_on) {
            std::vector<int> light_indices = v->all_parts_with_feature(VPFLAG_CIRCLE_LIGHT);
            for( auto &light_indice : light_indices ) {
                if( ( calendar::turn % 2 &&
                      v->part_info( light_indice ).has_flag( VPFLAG_ODDTURN ) ) ||
                    ( !( calendar::turn % 2 ) &&
                      v->part_info( light_indice ).has_flag( VPFLAG_EVENTURN ) ) ||
                    ( !v->part_info( light_indice ).has_flag( VPFLAG_EVENTURN ) &&
                      !v->part_info( light_indice ).has_flag( VPFLAG_ODDTURN ) ) ) {
                    tripoint pp = tripoint( vv.x, vv.y, vv.z ) +
                                  v->parts[light_indice].precalc[0];
                    if(inbounds( pp )) {
                        add_light_source( pp, v->part_info( light_indice ).bonus );
                    }
                }
            }
        }
        // why reinvent the [lightmap] wheel
        if(v->dome_lights_on) {
            std::vector<int> light_indices = v->all_parts_with_feature(VPFLAG_DOME_LIGHT);
            for( auto &light_indice : light_indices ) {
                tripoint pp = tripoint( vv.x, vv.y, vv.z ) +
                              v->parts[light_indice].precalc[0];
                if( inbounds( pp )) {
                    add_light_source( pp, v->part_info( light_indice ).bonus );
                }
            }
        }
        if(v->aisle_lights_on) {
            std::vector<int> light_indices = v->all_parts_with_feature(VPFLAG_AISLE_LIGHT);
            for( auto &light_indice : light_indices ) {
                tripoint pp = tripoint( vv.x, vv.y, vv.z ) +
                              v->parts[light_indice].precalc[0];
                if( inbounds( pp )) {
                    add_light_source( pp, v->part_info( light_indice ).bonus );
                }
            }
        }
        if(v->has_atomic_lights) {
            // atomic light is always on
            std::vector<int> light_indices = v->all_parts_with_feature(VPFLAG_ATOMIC_LIGHT);
            for( auto &light_indice : light_indices ) {
                tripoint pp = tripoint( vv.x, vv.y, vv.z ) +
                              v->parts[light_indice].precalc[0];
                if(inbounds( pp )) {
                    add_light_source( pp, v->part_info( light_indice ).bonus );
                }
            }
        }
        for( size_t p = 0; p < v->parts.size(); ++p ) {
            tripoint pp = tripoint( vv.x, vv.y, vv.z ) +
                          v->parts[p].precalc[0];
            if( !inbounds( pp ) ) {
                continue;
            }
            if( v->part_flag( p, VPFLAG_CARGO ) && !v->part_flag( p, "COVERED" ) ) {
                add_light_from_items( pp, v->get_items(p).begin(), v->get_items(p).end() );
            }
        }
    }

    /* Now that we have position and intensity of all bulk light sources, apply_ them
      This may seem like extra work, but take a 12x12 raging inferno:
        unbuffered: (12^2)*(160*4) = apply_light_ray x 92160
        buffered:   (12*4)*(160)   = apply_light_ray x 7680
    */
    const tripoint cache_start( 0, 0, zlev );
    const tripoint cache_end( LIGHTMAP_CACHE_X, LIGHTMAP_CACHE_Y, zlev );
    for( const tripoint &p : points_in_rectangle( cache_start, cache_end ) ) {
        if( light_source_buffer[p.x][p.y] > 0.0 ) {
            apply_light_source( p, light_source_buffer[p.x][p.y] );
        }
    }


    if (g->u.has_active_bionic("bio_night") ) {
        for( const tripoint &p : points_in_rectangle( cache_start, cache_end ) ) {
            if( rl_dist( p, g->u.pos() ) < 15 ) {
                lm[p.x][p.y] = LIGHT_AMBIENT_MINIMAL;
            }
        }
    }
}