コード例 #1
0
/**
 * Sells all vehicles in a depot
 * @param tile Tile of the depot where the depot is
 * @param flags type of operation
 * @param p1 Vehicle type
 * @param p2 unused
 * @param text unused
 * @return the cost of this operation or an error
 */
CommandCost CmdDepotSellAllVehicles(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
{
	VehicleList list;

	CommandCost cost(EXPENSES_NEW_VEHICLES);
	VehicleType vehicle_type = Extract<VehicleType, 0, 3>(p1);

	if (!IsCompanyBuildableVehicleType(vehicle_type)) return CMD_ERROR;

	uint sell_command = GetCmdSellVeh(vehicle_type);

	/* Get the list of vehicles in the depot */
	BuildDepotVehicleList(vehicle_type, tile, &list, &list);

	CommandCost last_error = CMD_ERROR;
	bool had_success = false;
	for (uint i = 0; i < list.Length(); i++) {
		CommandCost ret = DoCommand(tile, list[i]->index | (1 << 20), 0, flags, sell_command);
		if (ret.Succeeded()) {
			cost.AddCost(ret);
			had_success = true;
		} else {
			last_error = ret;
		}
	}

	return had_success ? cost : last_error;
}
コード例 #2
0
/**
 * Starts or stops a lot of vehicles
 * @param tile Tile of the depot where the vehicles are started/stopped (only used for depots)
 * @param flags type of operation
 * @param p1 bitmask
 *   - bit 0 set = start vehicles, unset = stop vehicles
 *   - bit 1 if set, then it's a vehicle list window, not a depot and Tile is ignored in this case
 * @param p2 packed VehicleListIdentifier
 * @param text unused
 * @return the cost of this operation or an error
 */
CommandCost CmdMassStartStopVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
{
	VehicleList list;
	bool do_start = HasBit(p1, 0);
	bool vehicle_list_window = HasBit(p1, 1);

	VehicleListIdentifier vli;
	if (!vli.UnpackIfValid(p2)) return CMD_ERROR;
	if (!IsCompanyBuildableVehicleType(vli.vtype)) return CMD_ERROR;

	if (vehicle_list_window) {
		if (!GenerateVehicleSortList(&list, vli)) return CMD_ERROR;
	} else {
		/* Get the list of vehicles in the depot */
		BuildDepotVehicleList(vli.vtype, tile, &list, NULL);
	}

	for (uint i = 0; i < list.Length(); i++) {
		const Vehicle *v = list[i];

		if (!!(v->vehstatus & VS_STOPPED) != do_start) continue;

		if (!vehicle_list_window && !v->IsChainInDepot()) continue;

		/* Just try and don't care if some vehicle's can't be stopped. */
		DoCommand(tile, v->index, 0, flags, CMD_START_STOP_VEHICLE);
	}

	return CommandCost();
}
コード例 #3
0
uint DeparturesWindow<Twaypoint>::GetMinWidth() const
{
	uint result = 0;

	/* Time */
	result = cached_date_width;

	/* Vehicle type icon */
	result += _settings_client.gui.departure_show_vehicle_type ? (GetStringBoundingBox(STR_DEPARTURES_TYPE_PLANE)).width : 0;

	/* Status */
	result += cached_status_width;

	/* Find the maximum company name width. */
	int toc_width = 0;

	/* Find the maximum company name width. */
	int group_width = 0;

	/* Find the maximum vehicle name width. */
	int veh_width = 0;

	if (_settings_client.gui.departure_show_vehicle || _settings_client.gui.departure_show_company || _settings_client.gui.departure_show_group) {
		for (uint i = 0; i < 4; ++i) {
			VehicleList vehicles;

			/* MAX_COMPANIES is probably the wrong thing to put here, but it works. GenerateVehicleSortList doesn't check the company when the type of list is VL_STATION_LIST (r20801). */
			if (!GenerateVehicleSortList(&vehicles, VehicleListIdentifier(VL_STATION_LIST, (VehicleType)(VEH_TRAIN + i), MAX_COMPANIES, station).Pack())) {
				/* Something went wrong: panic! */
				continue;
			}

			for (const Vehicle **v = vehicles.Begin(); v != vehicles.End(); v++) {
				SetDParam(0, (uint64)((*v)->index));
				int width = (GetStringBoundingBox(STR_DEPARTURES_VEH)).width;
				if (_settings_client.gui.departure_show_vehicle && width > veh_width) veh_width = width;

				if ((*v)->group_id != INVALID_GROUP && (*v)->group_id != DEFAULT_GROUP) {
					SetDParam(0, (uint64)((*v)->group_id));
					width = (GetStringBoundingBox(STR_DEPARTURES_GROUP)).width;
					if (_settings_client.gui.departure_show_group && width > group_width) group_width = width;
				}

				SetDParam(0, (uint64)((*v)->owner));
				width = (GetStringBoundingBox(STR_DEPARTURES_TOC)).width;
				if (_settings_client.gui.departure_show_company && width > toc_width) toc_width = width;
			}
		}
	}

	result += toc_width + veh_width + group_width;

	return result + 140;
}
コード例 #4
0
ファイル: vehicle_cmd.cpp プロジェクト: Voxar/OpenTTD
/** Autoreplace all vehicles in the depot
 * Note: this command can make incorrect cost estimations
 * Luckily the final price can only drop, not increase. This is due to the fact that
 * estimation can't predict wagon removal so it presumes worst case which is no income from selling wagons.
 * @param tile Tile of the depot where the vehicles are
 * @param flags type of operation
 * @param p1 Type of vehicle
 * @param p2 If bit 0 is set, then either replace all or nothing (instead of replacing until money runs out)
 * @param text unused
 * @return the cost of this operation or an error
 */
CommandCost CmdDepotMassAutoReplace(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
{
    VehicleList list;
    CommandCost cost = CommandCost(EXPENSES_NEW_VEHICLES);
    VehicleType vehicle_type = (VehicleType)GB(p1, 0, 8);
    bool all_or_nothing = HasBit(p2, 0);

    if (!IsDepotTile(tile) || !IsTileOwner(tile, _current_company)) return CMD_ERROR;

    /* Get the list of vehicles in the depot */
    BuildDepotVehicleList(vehicle_type, tile, &list, &list, true);

    bool did_something = false;

    for (uint i = 0; i < list.Length(); i++) {
        const Vehicle *v = list[i];

        /* Ensure that the vehicle completely in the depot */
        if (!v->IsInDepot()) continue;

        CommandCost ret = DoCommand(0, v->index, 0, flags, CMD_AUTOREPLACE_VEHICLE);

        if (CmdSucceeded(ret)) {
            did_something = true;
            cost.AddCost(ret);
        } else {
            if (ret.GetErrorMessage() != STR_ERROR_AUTOREPLACE_NOTHING_TO_DO && all_or_nothing) {
                /* We failed to replace a vehicle even though we set all or nothing.
                 * We should never reach this if DC_EXEC is set since then it should
                 * have failed the estimation guess. */
                assert(!(flags & DC_EXEC));
                /* Now we will have to return an error. */
                return CMD_ERROR;
            }
        }
    }

    if (!did_something) {
        /* Either we didn't replace anything or something went wrong.
         * Either way we want to return an error and not execute this command. */
        cost = CMD_ERROR;
    }

    return cost;
}
コード例 #5
0
ファイル: vehicle_cmd.cpp プロジェクト: Voxar/OpenTTD
/** Sells all vehicles in a depot
 * @param tile Tile of the depot where the depot is
 * @param flags type of operation
 * @param p1 Vehicle type
 * @param p2 unused
 * @param text unused
 * @return the cost of this operation or an error
 */
CommandCost CmdDepotSellAllVehicles(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
{
    VehicleList list;

    CommandCost cost(EXPENSES_NEW_VEHICLES);
    VehicleType vehicle_type = (VehicleType)GB(p1, 0, 8);
    uint sell_command = GetCmdSellVeh(vehicle_type);

    /* Get the list of vehicles in the depot */
    BuildDepotVehicleList(vehicle_type, tile, &list, &list);

    for (uint i = 0; i < list.Length(); i++) {
        CommandCost ret = DoCommand(tile, list[i]->index, 1, flags, sell_command);
        if (CmdSucceeded(ret)) cost.AddCost(ret);
    }

    if (cost.GetCost() == 0) return CMD_ERROR; // no vehicles to sell
    return cost;
}
コード例 #6
0
ファイル: vehicle_cmd.cpp プロジェクト: Voxar/OpenTTD
/** Starts or stops a lot of vehicles
 * @param tile Tile of the depot where the vehicles are started/stopped (only used for depots)
 * @param flags type of operation
 * @param p1 Station/Order/Depot ID (only used for vehicle list windows)
 * @param p2 bitmask
 *   - bit 0-4 Vehicle type
 *   - bit 5 false = start vehicles, true = stop vehicles
 *   - bit 6 if set, then it's a vehicle list window, not a depot and Tile is ignored in this case
 *   - bit 8-11 Vehicle List Window type (ignored unless bit 1 is set)
 * @param text unused
 * @return the cost of this operation or an error
 */
CommandCost CmdMassStartStopVehicle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
{
    VehicleList list;
    CommandCost return_value = CMD_ERROR;
    VehicleType vehicle_type = (VehicleType)GB(p2, 0, 5);
    bool start_stop = HasBit(p2, 5);
    bool vehicle_list_window = HasBit(p2, 6);

    if (vehicle_list_window) {
        uint32 id = p1;
        uint16 window_type = p2 & VLW_MASK;

        GenerateVehicleSortList(&list, vehicle_type, _current_company, id, window_type);
    } else {
        /* Get the list of vehicles in the depot */
        BuildDepotVehicleList(vehicle_type, tile, &list, NULL);
    }

    for (uint i = 0; i < list.Length(); i++) {
        const Vehicle *v = list[i];

        if (!!(v->vehstatus & VS_STOPPED) != start_stop) continue;

        if (!vehicle_list_window) {
            if (vehicle_type == VEH_TRAIN) {
                if (!Train::From(v)->IsInDepot()) continue;
            } else {
                if (!(v->vehstatus & VS_HIDDEN)) continue;
            }
        }

        CommandCost ret = DoCommand(tile, v->index, 0, flags, CMD_START_STOP_VEHICLE);

        if (CmdSucceeded(ret)) {
            return_value = CommandCost();
            /* We know that the command is valid for at least one vehicle.
             * If we haven't set DC_EXEC, then there is no point in continueing because it will be valid */
            if (!(flags & DC_EXEC)) break;
        }
    }

    return return_value;
}
コード例 #7
0
ファイル: vehicle_cmd.cpp プロジェクト: Voxar/OpenTTD
/**
 * Send all vehicles of type to depots
 * @param type type of vehicle
 * @param flags the flags used for DoCommand()
 * @param service should the vehicles only get service in the depots
 * @param owner owner of the vehicles to send
 * @param vlw_flag tells what kind of list requested the goto depot
 * @param id general purpose id whoms meaning is given by @c vlw_flag; e.g. StationID for station lists
 * @return 0 for success and CMD_ERROR if no vehicle is able to go to depot
 */
CommandCost SendAllVehiclesToDepot(VehicleType type, DoCommandFlag flags, bool service, Owner owner, uint16 vlw_flag, uint32 id)
{
    VehicleList list;

    GenerateVehicleSortList(&list, type, owner, id, vlw_flag);

    /* Send all the vehicles to a depot */
    for (uint i = 0; i < list.Length(); i++) {
        const Vehicle *v = list[i];
        CommandCost ret = DoCommand(v->tile, v->index, (service ? 1 : 0) | DEPOT_DONT_CANCEL, flags, GetCmdSendToDepot(type));

        /* Return 0 if DC_EXEC is not set this is a valid goto depot command)
         * In this case we know that at least one vehicle can be sent to a depot
         * and we will issue the command. We can now safely quit the loop, knowing
         * it will succeed at least once. With DC_EXEC we really need to send them to the depot */
        if (CmdSucceeded(ret) && !(flags & DC_EXEC)) {
            return CommandCost();
        }
    }

    return (flags & DC_EXEC) ? CommandCost() : CMD_ERROR;
}
コード例 #8
0
/**
 * Autoreplace all vehicles in the depot
 * @param tile Tile of the depot where the vehicles are
 * @param flags type of operation
 * @param p1 Type of vehicle
 * @param p2 unused
 * @param text unused
 * @return the cost of this operation or an error
 */
CommandCost CmdDepotMassAutoReplace(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
{
	VehicleList list;
	CommandCost cost = CommandCost(EXPENSES_NEW_VEHICLES);
	VehicleType vehicle_type = Extract<VehicleType, 0, 3>(p1);

	if (!IsCompanyBuildableVehicleType(vehicle_type)) return CMD_ERROR;
	if (!IsDepotTile(tile) || !IsTileOwner(tile, _current_company)) return CMD_ERROR;

	/* Get the list of vehicles in the depot */
	BuildDepotVehicleList(vehicle_type, tile, &list, &list, true);

	for (uint i = 0; i < list.Length(); i++) {
		const Vehicle *v = list[i];

		/* Ensure that the vehicle completely in the depot */
		if (!v->IsChainInDepot()) continue;

		CommandCost ret = DoCommand(0, v->index, 0, flags, CMD_AUTOREPLACE_VEHICLE);

		if (ret.Succeeded()) cost.AddCost(ret);
	}
	return cost;
}
コード例 #9
0
void DeparturesWindow<Twaypoint>::DrawDeparturesListItems(const Rect &r) const
{
	int left = r.left + WD_MATRIX_LEFT;
	int right = r.right - WD_MATRIX_RIGHT;

	bool rtl = _current_text_dir == TD_RTL;
	bool ltr = !rtl;

	int text_offset = WD_FRAMERECT_RIGHT;
	int text_left  = left  + (rtl ?           0 : text_offset);
	int text_right = right - (rtl ? text_offset :           0);

	int y = r.top + 1;
	uint max_departures = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->departures->Length() + this->arrivals->Length());

	if (max_departures > _settings_client.gui.max_departures) {
		max_departures = _settings_client.gui.max_departures;
	}

	byte small_font_size = _settings_client.gui.departure_larger_font ? FONT_HEIGHT_NORMAL : FONT_HEIGHT_SMALL;

	/* Draw the black background. */
	GfxFillRect(r.left + 1, r.top, r.right - 1, r.bottom, PC_BLACK);

	/* Nothing selected? Then display the information text. */
	bool none_selected[2] = {true, true};
	for (uint i = 0; i < 4; ++i)
	{
		if (this->show_types[i]) {
			none_selected[0] = false;
			break;
		}
	}

	for (uint i = 0; i < 2; ++i)
	{
		if (this->departure_types[i]) {
			none_selected[1] = false;
			break;
		}
	}

	if (none_selected[0] || none_selected[1]) {
		DrawString(text_left, text_right, y + 1, STR_DEPARTURES_NONE_SELECTED);
		return;
	}

	/* No scheduled departures? Then display the information text. */
	if (max_departures == 0) {
		DrawString(text_left, text_right, y + 1, STR_DEPARTURES_EMPTY);
		return;
	}

	/* Find the maximum possible width of the departure time and "Expt <time>" fields. */
	int time_width = cached_date_width;

	if (!_settings_client.gui.departure_show_both) {
		time_width += (departure_types[0] && departure_types[1] ? cached_date_arrow_width : 0);
	}

	/* Vehicle type icon */
	int type_width = _settings_client.gui.departure_show_vehicle_type ? (GetStringBoundingBox(STR_DEPARTURES_TYPE_PLANE)).width : 0;

	/* Find the maximum width of the status field */
	int status_width = cached_status_width;

	/* Find the width of the "Calling at:" field. */
	int calling_at_width = (GetStringBoundingBox(_settings_client.gui.departure_larger_font ? STR_DEPARTURES_CALLING_AT_LARGE : STR_DEPARTURES_CALLING_AT)).width;

	/* Find the maximum company name width. */
	int toc_width = 0;

	/* Find the maximum group name width. */
	int group_width = 0;

	/* Find the maximum vehicle name width. */
	int veh_width = 0;

	if (_settings_client.gui.departure_show_vehicle || _settings_client.gui.departure_show_company || _settings_client.gui.departure_show_group) {
		for (uint i = 0; i < 4; ++i) {
			VehicleList vehicles;

			/* MAX_COMPANIES is probably the wrong thing to put here, but it works. GenerateVehicleSortList doesn't check the company when the type of list is VL_STATION_LIST (r20801). */
			if (!GenerateVehicleSortList(&vehicles, VehicleListIdentifier(VL_STATION_LIST, (VehicleType)(VEH_TRAIN + i), MAX_COMPANIES, station).Pack())) {
				/* Something went wrong: panic! */
				continue;
			}

			for (const Vehicle **v = vehicles.Begin(); v != vehicles.End(); v++) {
				SetDParam(0, (uint64)((*v)->index));
				int width = (GetStringBoundingBox(STR_DEPARTURES_VEH)).width;
				if (_settings_client.gui.departure_show_vehicle && width > veh_width) veh_width = width;

				if ((*v)->group_id != INVALID_GROUP && (*v)->group_id != DEFAULT_GROUP) {
					SetDParam(0, (uint64)((*v)->group_id));
					width = (GetStringBoundingBox(STR_DEPARTURES_GROUP)).width;
					if (_settings_client.gui.departure_show_group && width > group_width) group_width = width;
				}

				SetDParam(0, (uint64)((*v)->owner));
				width = (GetStringBoundingBox(STR_DEPARTURES_TOC)).width;
				if (_settings_client.gui.departure_show_company && width > toc_width) toc_width = width;
			}
		}
	}

	uint departure = 0;
	uint arrival = 0;

	/* Draw each departure. */
	for (uint i = 0; i < max_departures; ++i) {
		const Departure *d;

		if (arrival == this->arrivals->Length()) {
			d = (*(this->departures))[departure++];
		} else if (departure == this->departures->Length()) {
			d = (*(this->arrivals))[arrival++];
		} else {
			d = (*(this->departures))[departure];
			const Departure *a = (*(this->arrivals))[arrival];

			if (a->scheduled_date < d->scheduled_date) {
				d = a;
				arrival++;
			} else {
				departure++;
			}
		}

		if (i < this->vscroll->GetPosition()) {
			continue;
		}

		/* If for some reason the departure is too far in the future or is at a negative time, skip it. */
		if ((d->scheduled_date / DAY_TICKS) > (_date + _settings_client.gui.max_departure_time) ||
			d->scheduled_date < 0) {
			continue;
		}

		if (d->terminus == INVALID_STATION) continue;

		StringID time_str = (departure_types[0] && departure_types[1]) ? (d->type == D_DEPARTURE ? STR_DEPARTURES_TIME_DEP : STR_DEPARTURES_TIME_ARR) : STR_DEPARTURES_TIME;

		if (_settings_client.gui.departure_show_both) time_str = STR_DEPARTURES_TIME_BOTH;

		/* Time */
		SetDParam(0, d->scheduled_date);
		SetDParam(1, d->scheduled_date - d->order->wait_time);
		ltr ? DrawString(              text_left, text_left + time_width, y + 1, time_str)
			: DrawString(text_right - time_width,             text_right, y + 1, time_str);

		/* Vehicle type icon, with thanks to sph */
		if (_settings_client.gui.departure_show_vehicle_type) {
			StringID type = STR_DEPARTURES_TYPE_TRAIN;
			int offset = (_settings_client.gui.departure_show_vehicle_color ? 1 : 0);

			switch (d->vehicle->type) {
				case VEH_TRAIN:
					type = STR_DEPARTURES_TYPE_TRAIN;
					break;
				case VEH_ROAD:
					type = IsCargoInClass(d->vehicle->cargo_type, CC_PASSENGERS) ? STR_DEPARTURES_TYPE_BUS : STR_DEPARTURES_TYPE_LORRY;
					break;
				case VEH_SHIP:
					type = STR_DEPARTURES_TYPE_SHIP;
					break;
				case VEH_AIRCRAFT:
					type = STR_DEPARTURES_TYPE_PLANE;
					break;
				default:
					break;
			}

			type += offset;

			DrawString(text_left + time_width + 3, text_left + time_width + type_width + 3, y, type);
		}

		/* The icons to show with the destination and via stations. */
		StringID icon = STR_DEPARTURES_STATION_NONE;
		StringID icon_via = STR_DEPARTURES_STATION_NONE;

		if (_settings_client.gui.departure_destination_type) {
			Station *t = Station::Get(d->terminus.station);

			if (t->facilities & FACIL_DOCK &&
					t->facilities & FACIL_AIRPORT &&
					d->vehicle->type != VEH_SHIP &&
					d->vehicle->type != VEH_AIRCRAFT) {
				icon = STR_DEPARTURES_STATION_PORTAIRPORT;
			} else if (t->facilities & FACIL_DOCK &&
					d->vehicle->type != VEH_SHIP) {
				icon = STR_DEPARTURES_STATION_PORT;
			} else if (t->facilities & FACIL_AIRPORT &&
					d->vehicle->type != VEH_AIRCRAFT) {
				icon = STR_DEPARTURES_STATION_AIRPORT;
			}
		}

		if (_settings_client.gui.departure_destination_type && d->via != INVALID_STATION) {
			Station *t = Station::Get(d->via);

			if (t->facilities & FACIL_DOCK &&
					t->facilities & FACIL_AIRPORT &&
					d->vehicle->type != VEH_SHIP &&
					d->vehicle->type != VEH_AIRCRAFT) {
				icon_via = STR_DEPARTURES_STATION_PORTAIRPORT;
			} else if (t->facilities & FACIL_DOCK &&
					d->vehicle->type != VEH_SHIP) {
				icon_via = STR_DEPARTURES_STATION_PORT;
			} else if (t->facilities & FACIL_AIRPORT &&
					d->vehicle->type != VEH_AIRCRAFT) {
				icon_via = STR_DEPARTURES_STATION_AIRPORT;
			}
		}

		/* Destination */
		if (d->via == INVALID_STATION) {
			/* Only show the terminus. */
			SetDParam(0, d->terminus.station);
			SetDParam(1, icon);
			ltr ? DrawString(              text_left + time_width + type_width + 6,   text_right - status_width - (toc_width + veh_width + group_width + 2) - 2, y + 1, STR_DEPARTURES_TERMINUS)
				: DrawString(text_left + status_width + (toc_width + veh_width + group_width + 2) + 2,                 text_right - time_width - type_width - 6, y + 1, STR_DEPARTURES_TERMINUS);
		} else {
			/* Show the terminus and the via station. */
			SetDParam(0, d->terminus.station);
			SetDParam(1, icon);
			SetDParam(2, d->via);
			SetDParam(3, icon_via);
			int text_width = (GetStringBoundingBox(STR_DEPARTURES_TERMINUS_VIA_STATION)).width;

			if (text_width < text_right - status_width - (toc_width + veh_width + group_width + 2) - 2 - (text_left + time_width + type_width + 6)) {
				/* They will both fit, so show them both. */
				SetDParam(0, d->terminus.station);
				SetDParam(1, icon);
				SetDParam(2, d->via);
				SetDParam(3, icon_via);
				ltr ? DrawString(              text_left + time_width + type_width + 6, text_right - status_width - (toc_width + veh_width + group_width + 2) - 2, y + 1, STR_DEPARTURES_TERMINUS_VIA_STATION)
					: DrawString(text_left + status_width + (toc_width + veh_width + group_width + 2) + 2,               text_right - time_width - type_width - 6, y + 1, STR_DEPARTURES_TERMINUS_VIA_STATION);
			} else {
				/* They won't both fit, so switch between showing the terminus and the via station approximately every 4 seconds. */
				if (this->tick_count & (1 << 7)) {
					SetDParam(0, d->via);
					SetDParam(1, icon_via);
					ltr ? DrawString(              text_left + time_width + type_width + 6, text_right - status_width - (toc_width + veh_width + group_width + 2) - 2, y + 1, STR_DEPARTURES_VIA)
						: DrawString(text_left + status_width + (toc_width + veh_width + group_width + 2) + 2,               text_right - time_width - type_width - 6, y + 1, STR_DEPARTURES_VIA);
				} else {
					SetDParam(0, d->terminus.station);
					SetDParam(1, icon);
					ltr ? DrawString(              text_left + time_width + type_width + 6, text_right - status_width - (toc_width + veh_width + group_width + 2) - 2, y + 1, STR_DEPARTURES_TERMINUS_VIA)
						: DrawString(text_left + status_width + (toc_width + veh_width + group_width + 2) + 2,               text_right - time_width - type_width - 6, y + 1, STR_DEPARTURES_TERMINUS_VIA);
				}
			}
		}

		/* Status */
		{
			int status_left = ltr ? text_right - status_width - 2 - (toc_width + veh_width + group_width + 2) : text_left + (toc_width + veh_width + group_width + 2) + 7;
			int status_right = ltr ? text_right - (toc_width + veh_width + group_width + 2) + 2 : text_left + status_width + 2 + (toc_width + veh_width + group_width + 7);

			if (d->status == D_ARRIVED) {
				/* The vehicle has arrived. */
				DrawString(status_left, status_right, y + 1, STR_DEPARTURES_ARRIVED);
			} else if(d->status == D_CANCELLED) {
				/* The vehicle has been cancelled. */
				DrawString(status_left, status_right, y + 1, STR_DEPARTURES_CANCELLED);
			} else{
				if (d->lateness <= DAY_TICKS && d->scheduled_date > ((_date * DAY_TICKS) + _date_fract)) {
					/* We have no evidence that the vehicle is late, so assume it is on time. */
					DrawString(status_left, status_right, y + 1, STR_DEPARTURES_ON_TIME);
				} else {
					if ((d->scheduled_date + d->lateness) < ((_date * DAY_TICKS) + _date_fract)) {
						/* The vehicle was expected to have arrived by now, even if we knew it was going to be late. */
						/* We assume that the train stays at least a day at a station so it won't accidentally be marked as delayed for a fraction of a day. */
						DrawString(status_left, status_right, y + 1, STR_DEPARTURES_DELAYED);
					} else {
						/* The vehicle is expected to be late and is not yet due to arrive. */
						SetDParam(0, d->scheduled_date + d->lateness);
						DrawString(status_left, status_right, y + 1, STR_DEPARTURES_EXPECTED);
					}
				}
			}
		}

		/* Vehicle name */

		if (_settings_client.gui.departure_show_vehicle) {
			SetDParam(0, (uint64)(d->vehicle->index));
			ltr ? DrawString(text_right - (toc_width + veh_width + group_width + 2),              text_right - toc_width - group_width - 2, y + 1, STR_DEPARTURES_VEH)
				: DrawString(               text_left + toc_width + group_width + 2, text_left + (toc_width + veh_width + group_width + 2), y + 1, STR_DEPARTURES_VEH);
		}

		/* Group name */

		if (_settings_client.gui.departure_show_group && d->vehicle->group_id != INVALID_GROUP && d->vehicle->group_id != DEFAULT_GROUP) {
			SetDParam(0, (uint64)(d->vehicle->group_id));
			ltr ? DrawString(text_right - (toc_width + group_width + 2),              text_right - toc_width - 2, y + 1, STR_DEPARTURES_GROUP)
				: DrawString(               text_left + toc_width + 2, text_left + (toc_width + group_width + 2), y + 1, STR_DEPARTURES_GROUP);
		}

		/* Operating company */
		if (_settings_client.gui.departure_show_company) {
			SetDParam(0, (uint64)(d->vehicle->owner));
			ltr ? DrawString(text_right - toc_width,            text_right, y + 1, STR_DEPARTURES_TOC, TC_FROMSTRING, SA_RIGHT)
				: DrawString(             text_left, text_left + toc_width, y + 1, STR_DEPARTURES_TOC, TC_FROMSTRING, SA_LEFT);
		}

		int bottom_y = y + this->entry_height - small_font_size - (_settings_client.gui.departure_larger_font ? 1 : 3);

		/* Calling at */
		ltr ? DrawString(                    text_left,  text_left + calling_at_width, bottom_y, _settings_client.gui.departure_larger_font ? STR_DEPARTURES_CALLING_AT_LARGE : STR_DEPARTURES_CALLING_AT)
			: DrawString(text_right - calling_at_width,                    text_right, bottom_y, _settings_client.gui.departure_larger_font ? STR_DEPARTURES_CALLING_AT_LARGE : STR_DEPARTURES_CALLING_AT);

		/* List of stations */
		/* RTL languages can be handled in the language file, e.g. by having the following: */
		/* STR_DEPARTURES_CALLING_AT_STATION      :{STATION}, {RAW_STRING} */
		/* STR_DEPARTURES_CALLING_AT_LAST_STATION :{STATION} & {RAW_STRING}*/
		char buffer[512], scratch[512];

		if (d->calling_at.Length() != 0) {
			SetDParam(0, (uint64)(*d->calling_at.Get(0)).station);
			GetString(scratch, STR_DEPARTURES_CALLING_AT_FIRST_STATION, lastof(scratch));

			StationID continuesTo = INVALID_STATION;

			if (d->calling_at.Get(0)->station == d->terminus.station && d->calling_at.Length() > 1) {
				continuesTo = d->calling_at.Get(d->calling_at.Length() - 1)->station;
			} else if (d->calling_at.Length() > 1) {
				/* There's more than one stop. */

				uint i;
				/* For all but the last station, write out ", <station>". */
				for (i = 1; i < d->calling_at.Length() - 1; ++i) {
					StationID s = d->calling_at.Get(i)->station;
					if (s == d->terminus.station) {
						continuesTo = d->calling_at.Get(d->calling_at.Length() - 1)->station;
						break;
					}
					SetDParam(0, (uint64)scratch);
					SetDParam(1, (uint64)s);
					GetString(buffer, STR_DEPARTURES_CALLING_AT_STATION, lastof(buffer));
					strncpy(scratch, buffer, sizeof(scratch));
				}

				/* Finally, finish off with " and <station>". */
				SetDParam(0, (uint64)scratch);
				SetDParam(1, (uint64)d->calling_at.Get(i)->station);
				GetString(buffer, STR_DEPARTURES_CALLING_AT_LAST_STATION, lastof(buffer));
				strncpy(scratch, buffer, sizeof(scratch));
			}

			SetDParam(0, (uint64)scratch);
			StringID string;
			if (continuesTo == INVALID_STATION) {
				string = _settings_client.gui.departure_larger_font ? STR_DEPARTURES_CALLING_AT_LIST_LARGE : STR_DEPARTURES_CALLING_AT_LIST;
			} else {
				SetDParam(1, continuesTo);
				string = _settings_client.gui.departure_larger_font ? STR_DEPARTURES_CALLING_AT_LIST_SMART_TERMINUS_LARGE : STR_DEPARTURES_CALLING_AT_LIST_SMART_TERMINUS;
			}
			GetString(buffer, string, lastof(buffer));
		} else {
			buffer[0] = 0;
			//SetDParam(0, d->terminus);
			//GetString(scratch, STR_DEPARTURES_CALLING_AT_FIRST_STATION, lastof(scratch));
		}

		int list_width = (GetStringBoundingBox(buffer, _settings_client.gui.departure_larger_font ? FS_NORMAL : FS_SMALL)).width;

		/* Draw the whole list if it will fit. Otherwise scroll it. */
		if (list_width < text_right - (text_left + calling_at_width + 2)) {
			ltr ? DrawString(text_left + calling_at_width + 2,                        text_right, bottom_y, buffer)
				: DrawString(                       text_left, text_right - calling_at_width - 2, bottom_y, buffer);
		} else {
			DrawPixelInfo tmp_dpi;
			if (ltr
				? !FillDrawPixelInfo(&tmp_dpi, text_left + calling_at_width + 2, bottom_y, text_right - (text_left + calling_at_width + 2), small_font_size + 3)
				: !FillDrawPixelInfo(&tmp_dpi, text_left                       , bottom_y, text_right - (text_left + calling_at_width + 2), small_font_size + 3)) {
				y += this->entry_height;
				continue;
			}
			DrawPixelInfo *old_dpi = _cur_dpi;
			_cur_dpi = &tmp_dpi;

			/* The scrolling text starts out of view at the right of the screen and finishes when it is out of view at the left of the screen. */
			int pos = ltr
				? text_right - (this->tick_count % (list_width + text_right - text_left))
				:  text_left + (this->tick_count % (list_width + text_right - text_left));

			ltr ? DrawString(       pos, INT16_MAX, 0, buffer, TC_FROMSTRING,  SA_LEFT | SA_FORCE)
				: DrawString(-INT16_MAX,       pos, 0, buffer, TC_FROMSTRING, SA_RIGHT | SA_FORCE);

			_cur_dpi = old_dpi;
		}

		y += this->entry_height;
	}
}
コード例 #10
0
void map::generate_lightmap()
{
    memset(lm, 0, sizeof(lm));
    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: Profit!
     */
    memset(light_source_buffer, 0, sizeof(light_source_buffer));


    const int dir_x[] = { 1, 0 , -1,  0 };
    const int dir_y[] = { 0, 1 ,  0, -1 };
    const int dir_d[] = { 180, 270, 0, 90 };
    const float held_luminance = g->u.active_light();
    const float natural_light = g->natural_light_level();

    if (natural_light > LIGHT_SOURCE_BRIGHT) {
        // Apply sunlight, first light source so just assign
        for(int sx = DAYLIGHT_LEVEL - (natural_light / 2);
            sx < LIGHTMAP_CACHE_X - (natural_light / 2); ++sx) {
            for(int sy = DAYLIGHT_LEVEL - (natural_light / 2);
                sy < LIGHTMAP_CACHE_Y - (natural_light / 2); ++sy) {
                // In bright light indoor light exists to some degree
                if (!is_outside(sx, sy)) {
                    lm[sx][sy] = LIGHT_AMBIENT_LOW;
                } else if (g->u.posx == sx && g->u.posy == sy ) {
                    //Only apply daylight on square where player is standing to avoid flooding
                    // the lightmap  when in less than total sunlight.
                    lm[sx][sy] = natural_light;
                }
            }
        }
    }

    // Apply player light sources
    if (held_luminance > LIGHT_AMBIENT_LOW) {
        apply_light_source(g->u.posx, g->u.posy, held_luminance, trigdist);
    }
    for(int sx = 0; sx < LIGHTMAP_CACHE_X; ++sx) {
        for(int sy = 0; sy < LIGHTMAP_CACHE_Y; ++sy) {
            const ter_id terrain = ter(sx, sy);
            const std::vector<item> &items = i_at(sx, sy);
            field &current_field = field_at(sx, sy);
            // When underground natural_light is 0, if this changes we need to revisit
            // Only apply this whole thing if the player is inside,
            // buildings will be shadowed when outside looking in.
            if (natural_light > LIGHT_AMBIENT_LOW && !is_outside(g->u.posx, g->u.posy) ) {
                if (!is_outside(sx, sy)) {
                    // Apply light sources for external/internal divide
                    for(int i = 0; i < 4; ++i) {
                        if (INBOUNDS(sx + dir_x[i], sy + dir_y[i]) &&
                            is_outside(sx + dir_x[i], sy + dir_y[i])) {
                            lm[sx][sy] = natural_light;

                            if (light_transparency(sx, sy) > LIGHT_TRANSPARENCY_SOLID) {
                                apply_light_arc(sx, sy, dir_d[i], natural_light);
                            }
                        }
                    }
                }
            }
            for( std::vector<item>::const_iterator itm = items.begin(); itm != items.end(); ++itm ) {

                float ilum = 0.0; // brightness
                int iwidth = 0; // 0-360 degrees. 0 is a circular light_source
                int idir = 0;   // otherwise, it's a light_arc pointed in this direction
                if ( itm->getlight(ilum, iwidth, idir ) ) {
                    if ( iwidth > 0 ) {
                        apply_light_arc( sx, sy, idir, ilum, iwidth );
                    } else {
                        add_light_source(sx, sy, ilum);
                    }
                }
            }
            if(terrain == t_lava) {
                add_light_source(sx, sy, 50 );
            }

            if(terrain == t_console) {
                add_light_source(sx, sy, 3 );
            }

            if(terrain == t_emergency_light) {
                add_light_source(sx, sy, 3 );
            }

            if(terrain == t_utility_light) {
                add_light_source(sx, sy, 35 );
            }

            field_entry *cur = NULL;
            for(std::map<field_id, field_entry *>::iterator field_list_it = current_field.getFieldStart();
                field_list_it != current_field.getFieldEnd(); ++field_list_it) {
                cur = field_list_it->second;

                if(cur == NULL) {
                    continue;
                }
                // TODO: [lightmap] Attach light brightness to fields
                switch(cur->getFieldType()) {
                case fd_fire:
                    if (3 == cur->getFieldDensity()) {
                        add_light_source(sx, sy, 160);
                    } else if (2 == cur->getFieldDensity()) {
                        add_light_source(sx, sy, 60);
                    } else {
                        add_light_source(sx, sy, 16);
                    }
                    break;
                case fd_fire_vent:
                case fd_flame_burst:
                    add_light_source(sx, sy, 8);
                    break;
                case fd_electricity:
                case fd_plasma:
                    if (3 == cur->getFieldDensity()) {
                        add_light_source(sx, sy, 8);
                    } else if (2 == cur->getFieldDensity()) {
                        add_light_source(sx, sy, 1);
                    } else {
                        apply_light_source(sx, sy, LIGHT_SOURCE_LOCAL,
                                           trigdist);    // kinda a hack as the square will still get marked
                    }
                    break;
                case fd_incendiary:
                    if (3 == cur->getFieldDensity()) {
                        add_light_source(sx, sy, 30);
                    } else if (2 == cur->getFieldDensity()) {
                        add_light_source(sx, sy, 16);
                    } else {
                        add_light_source(sx, sy, 8);
                    }
                    break;
                case fd_laser:
                    apply_light_source(sx, sy, 1, trigdist);
                    break;
                case fd_spotlight:
                    add_light_source(sx, sy, 20);
                    break;
                case fd_dazzling:
                    add_light_source(sx, sy, 2);
                    break;
                default:
                    //Suppress warnings
                    break;
                }
            }
        }
    }

    for (size_t i = 0; i < g->num_zombies(); ++i) {
        int mx = g->zombie(i).posx();
        int my = g->zombie(i).posy();
        if (INBOUNDS(mx, my)) {
            if (g->zombie(i).has_effect("onfire")) {
                apply_light_source(mx, my, 3, trigdist);
            }
            // 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 (g->zombie(i).type->luminance > 0) {
                apply_light_source(mx, my, g->zombie(i).type->luminance, trigdist);
            }
        }
    }

    // Apply any vehicle light sources
    VehicleList vehs = get_vehicles();
    for( size_t v = 0; v < vehs.size(); ++v ) {
        if(vehs[v].v->lights_on) {
            int dir = vehs[v].v->face.dir();
            float veh_luminance = 0.0;
            float iteration = 1.0;
            std::vector<int> light_indices = vehs[v].v->all_parts_with_feature(VPFLAG_CONE_LIGHT);
            for (std::vector<int>::iterator part = light_indices.begin();
                 part != light_indices.end(); ++part) {
                veh_luminance += ( vehs[v].v->part_info(*part).bonus / iteration );
                iteration = iteration * 1.1;
            }
            if (veh_luminance > LL_LIT) {
                for (std::vector<int>::iterator part = light_indices.begin();
                     part != light_indices.end(); ++part) {
                    int px = vehs[v].x + vehs[v].v->parts[*part].precalc_dx[0];
                    int py = vehs[v].y + vehs[v].v->parts[*part].precalc_dy[0];
                    if(INBOUNDS(px, py)) {
                        apply_light_arc(px, py, dir + vehs[v].v->parts[*part].direction, veh_luminance, 45);
                    }
                }
            }
        }
        if(vehs[v].v->overhead_lights_on) {
            std::vector<int> light_indices = vehs[v].v->all_parts_with_feature(VPFLAG_CIRCLE_LIGHT);
            for (std::vector<int>::iterator part = light_indices.begin();
                 part != light_indices.end(); ++part) {
                if((calendar::turn % 2 && vehs[v].v->part_info(*part).has_flag(VPFLAG_ODDTURN)) ||
                   (!(calendar::turn % 2) && vehs[v].v->part_info(*part).has_flag(VPFLAG_EVENTURN)) ||
                   (!vehs[v].v->part_info(*part).has_flag(VPFLAG_EVENTURN) &&
                    !vehs[v].v->part_info(*part).has_flag(VPFLAG_ODDTURN))) {
                    int px = vehs[v].x + vehs[v].v->parts[*part].precalc_dx[0];
                    int py = vehs[v].y + vehs[v].v->parts[*part].precalc_dy[0];
                    if(INBOUNDS(px, py)) {
                        add_light_source( px, py, vehs[v].v->part_info(*part).bonus );
                    }
                }
            }
        }
    }

    /* 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
    */
    for(int sx = 0; sx < LIGHTMAP_CACHE_X; ++sx) {
        for(int sy = 0; sy < LIGHTMAP_CACHE_Y; ++sy) {
            if ( light_source_buffer[sx][sy] > 0. ) {
                apply_light_source(sx, sy, light_source_buffer[sx][sy],
                                   ( trigdist && light_source_buffer[sx][sy] > 3. ) );
            }
        }
    }


    if (g->u.has_active_bionic("bio_night") ) {
        for(int sx = 0; sx < LIGHTMAP_CACHE_X; ++sx) {
            for(int sy = 0; sy < LIGHTMAP_CACHE_Y; ++sy) {
                if (rl_dist(sx, sy, g->u.posx, g->u.posy) < 15) {
                    lm[sx][sy] = 0;
                }
            }
        }
    }
}
コード例 #11
0
ファイル: lightmap.cpp プロジェクト: Karethoth/Cataclysm-DDA
void map::generate_lightmap(game* g)
{
 memset(lm, 0, sizeof(lm));
 memset(sm, 0, sizeof(sm));

 const int dir_x[] = { 1, 0 , -1,  0 };
 const int dir_y[] = { 0, 1 ,  0, -1 };
 const int dir_d[] = { 180, 270, 0, 90 };
 const float luminance = g->u.active_light();
 const float natural_light = g->natural_light_level();

 // Daylight vision handling returned back to map due to issues it causes here
 if (natural_light > LIGHT_SOURCE_BRIGHT) {
  // 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 (!g->m.is_outside(sx, sy))
     lm[sx][sy] = LIGHT_AMBIENT_LOW;
   }
  }
 }

 // Apply player light sources
 if (luminance > LIGHT_AMBIENT_LOW)
  apply_light_source(g->u.posx, g->u.posy, luminance);

  for(int sx = 0; sx < LIGHTMAP_CACHE_X; ++sx) {
   for(int sy = 0; sy < LIGHTMAP_CACHE_Y; ++sy) {
    const ter_id terrain = g->m.ter(sx, sy);
    const std::vector<item> items = g->m.i_at(sx, sy);
    const field current_field = g->m.field_at(sx, sy);
    // When underground natural_light is 0, if this changes we need to revisit
    if (natural_light > LIGHT_AMBIENT_LOW) {
     if (!g->m.is_outside(sx, sy)) {
      // Apply light sources for external/internal divide
      for(int i = 0; i < 4; ++i) {
       if (INBOUNDS(sx + dir_x[i], sy + dir_y[i]) &&
           g->m.is_outside(sx + dir_x[i], sy + dir_y[i])) {
        if (INBOUNDS(sx, sy) && g->m.is_outside(0, 0))
         lm[sx][sy] = natural_light;

        if (g->m.light_transparency(sx, sy) > LIGHT_TRANSPARENCY_SOLID)
         apply_light_arc(sx, sy, dir_d[i], natural_light);
       }
      }
     }
    }

    if (items.size() == 1 &&
        items[0].type->id == itm_flashlight_on)
     apply_light_source(sx, sy, 20);

   if(terrain == t_lava)
    apply_light_source(sx, sy, 50);

   if(terrain == t_console)
    apply_light_source(sx, sy, 3);

   if (items.size() == 1 &&
       items[0].type->id == itm_candle_lit)
    apply_light_source(sx, sy, 4);

   if(terrain == t_emergency_light)
    apply_light_source(sx, sy, 3);

   // TODO: [lightmap] Attach light brightness to fields
  switch(current_field.type) {
    case fd_fire:
     if (3 == current_field.density)
      apply_light_source(sx, sy, 160);
     else if (2 == current_field.density)
      apply_light_source(sx, sy, 60);
     else
      apply_light_source(sx, sy, 16);
     break;
    case fd_fire_vent:
    case fd_flame_burst:
     apply_light_source(sx, sy, 8);
     break;
    case fd_electricity:
     if (3 == current_field.density)
      apply_light_source(sx, sy, 8);
     else if (2 == current_field.density)
      apply_light_source(sx, sy, 1);
     else
      apply_light_source(sx, sy, LIGHT_SOURCE_LOCAL);  // kinda a hack as the square will still get marked
     break;
   }
  }
 }

 for (int i = 0; i < g->z.size(); ++i) {
  int mx = g->z[i].posx;
  int my = g->z[i].posy;
  if (INBOUNDS(mx, my)) {
   if (g->z[i].has_effect(ME_ONFIRE)) {
    apply_light_source(mx, my, 3);
   }
   // 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
   switch (g->z[i].type->id) {
    case mon_zombie_electric:
     apply_light_source(mx, my, 1);
     break;
    case mon_turret:
     apply_light_source(mx, my, 2);
     break;
    case mon_flaming_eye:
     apply_light_source(mx, my, LIGHT_SOURCE_BRIGHT);
     break;
    case mon_manhack:
     apply_light_source(mx, my, LIGHT_SOURCE_LOCAL);
     break;
   }
  }
 }

 // Apply any vehicle light sources
 VehicleList vehs = g->m.get_vehicles();
 for(int v = 0; v < vehs.size(); ++v) {
  if(vehs[v].v->lights_on) {
   int dir = vehs[v].v->face.dir();
   for (std::vector<int>::iterator part = vehs[v].v->external_parts.begin();
        part != vehs[v].v->external_parts.end(); ++part) {
    int px = vehs[v].x + vehs[v].v->parts[*part].precalc_dx[0];
    int py = vehs[v].y + vehs[v].v->parts[*part].precalc_dy[0];
    if(INBOUNDS(px, py)) {
     int dpart = vehs[v].v->part_with_feature(*part , vpf_light);
     if (dpart >= 0) {
      float luminance = vehs[v].v->part_info(dpart).power;
      if (luminance > LL_LIT) {
        apply_light_arc(px, py, dir, luminance);
      }
     }
    }
   }
  }
 }
}
コード例 #12
0
void map::generate_lightmap(game* g)
{
 memset(lm, 0, sizeof(lm));
 memset(sm, 0, sizeof(sm));

 const int dir_x[] = { 1, 0 , -1,  0 };
 const int dir_y[] = { 0, 1 ,  0, -1 };
 const int dir_d[] = { 180, 270, 0, 90 };
 const float held_luminance = g->u.active_light();
 const float natural_light = g->natural_light_level();

 // Daylight vision handling returned back to map due to issues it causes here
 if (natural_light > LIGHT_SOURCE_BRIGHT)
 {
     // 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 (!g->m.is_outside(sx, sy))
             {
                 lm[sx][sy] = LIGHT_AMBIENT_LOW;
             }
             else if (g->u.posx == sx && g->u.posy == sy )
             {
                 //Only apply daylight on square where player is standing to avoid flooding
                 // the lightmap  when in less than total sunlight.
                 lm[sx][sy] = natural_light;
             }
         }
     }
 }

 // Apply player light sources
 if (held_luminance > LIGHT_AMBIENT_LOW)
  apply_light_source(g->u.posx, g->u.posy, held_luminance, trigdist);
  int flood_basalt_check = 0; // does excessive lava need high quality lighting? Nope nope nope nope
  for(int sx = 0; sx < LIGHTMAP_CACHE_X; ++sx) {
   for(int sy = 0; sy < LIGHTMAP_CACHE_Y; ++sy) {
    const ter_id terrain = g->m.ter(sx, sy);
    const std::vector<item> &items = g->m.i_at(sx, sy);
    field &current_field = g->m.field_at(sx, sy);
    // When underground natural_light is 0, if this changes we need to revisit
    if (natural_light > LIGHT_AMBIENT_LOW) {
     if (!g->m.is_outside(sx, sy)) {
      // Apply light sources for external/internal divide
      for(int i = 0; i < 4; ++i) {
       if (INBOUNDS(sx + dir_x[i], sy + dir_y[i]) &&
           g->m.is_outside(sx + dir_x[i], sy + dir_y[i])) {
        if (INBOUNDS(sx, sy) && g->m.is_outside(0, 0))
         lm[sx][sy] = natural_light;

        if (g->m.light_transparency(sx, sy) > LIGHT_TRANSPARENCY_SOLID)
         apply_light_arc(sx, sy, dir_d[i], natural_light);
       }
      }
     }
    }

    for( std::vector<item>::const_iterator itm = items.begin(); itm != items.end(); ++itm )
    {
        if ( itm->has_flag("LIGHT_20")) { apply_light_source(sx, sy, 20, trigdist); }
        if ( itm->has_flag("LIGHT_1")) { apply_light_source(sx, sy, 1, trigdist); }
        if ( itm->has_flag("LIGHT_4")) { apply_light_source(sx, sy, 4, trigdist); }
        if ( itm->has_flag("LIGHT_8")) { apply_light_source(sx, sy, 8, trigdist); }
    }

   if(terrain == t_lava) {
     flood_basalt_check++;
     apply_light_source(sx, sy, 50, trigdist && flood_basalt_check < 512 ); // todo: optimize better
   }

   if(terrain == t_console)
    apply_light_source(sx, sy, 3, false); // 3^2 circle is just silly

   if(terrain == t_emergency_light)
    apply_light_source(sx, sy, 3, false);

   field_entry *cur = NULL;
   for(std::map<field_id, field_entry*>::iterator field_list_it = current_field.getFieldStart(); field_list_it != current_field.getFieldEnd(); ++field_list_it){
       cur = field_list_it->second;

		if(cur == NULL) continue;
   // TODO: [lightmap] Attach light brightness to fields
		switch(cur->getFieldType()) {
    case fd_fire:
		if (3 == cur->getFieldDensity())
      apply_light_source(sx, sy, 160, trigdist);
     else if (2 == cur->getFieldDensity())
      apply_light_source(sx, sy, 60, trigdist);
     else
      apply_light_source(sx, sy, 16, trigdist);
     break;
    case fd_fire_vent:
    case fd_flame_burst:
     apply_light_source(sx, sy, 8, trigdist);
     break;
    case fd_electricity:
    case fd_plasma:
     if (3 == cur->getFieldDensity())
      apply_light_source(sx, sy, 8, trigdist);
     else if (2 == cur->getFieldDensity())
      apply_light_source(sx, sy, 1, trigdist);
     else
      apply_light_source(sx, sy, LIGHT_SOURCE_LOCAL, trigdist);  // kinda a hack as the square will still get marked
     break;
    case fd_laser:
     apply_light_source(sx, sy, 1, trigdist);
     break;
   }
	}
  }
 }

 for (int i = 0; i < g->num_zombies(); ++i) {
  int mx = g->zombie(i).posx();
  int my = g->zombie(i).posy();
  if (INBOUNDS(mx, my)) {
   if (g->zombie(i).has_effect(ME_ONFIRE)) {
     apply_light_source(mx, my, 3, trigdist);
   }
   // 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
   switch (g->zombie(i).type->id) {
    case mon_zombie_electric:
     apply_light_source(mx, my, 1, trigdist);
     break;
    case mon_turret:
     apply_light_source(mx, my, 2, trigdist);
     break;
    case mon_flaming_eye:
     apply_light_source(mx, my, LIGHT_SOURCE_BRIGHT, trigdist);
     break;
    case mon_manhack:
     apply_light_source(mx, my, LIGHT_SOURCE_LOCAL, trigdist);
     break;
   }
  }
 }

 // Apply any vehicle light sources
 VehicleList vehs = g->m.get_vehicles();
 for(int v = 0; v < vehs.size(); ++v) {
   if(vehs[v].v->lights_on) {
     int dir = vehs[v].v->face.dir();
     float veh_luminance=0.0;
     float iteration=1.0;
     for (std::vector<int>::iterator part = vehs[v].v->external_parts.begin();
          part != vehs[v].v->external_parts.end(); ++part) {
         int dpart = vehs[v].v->part_with_feature(*part , "LIGHT");
         if (dpart >= 0) {
             veh_luminance += ( vehs[v].v->part_info(dpart).power / iteration );
             iteration=iteration * 1.1;
         }
     }
     if (veh_luminance > LL_LIT) {
       for (std::vector<int>::iterator part = vehs[v].v->external_parts.begin();
            part != vehs[v].v->external_parts.end(); ++part) {
         int px = vehs[v].x + vehs[v].v->parts[*part].precalc_dx[0];
         int py = vehs[v].y + vehs[v].v->parts[*part].precalc_dy[0];
         if(INBOUNDS(px, py)) {
           int dpart = vehs[v].v->part_with_feature(*part , "LIGHT");

           if (dpart >= 0) {
             apply_light_arc(px, py, dir + vehs[v].v->parts[dpart].direction, veh_luminance, 45);
           }
         }
       }
     }
   }
 }
if (g->u.has_active_bionic("bio_night") ) {
   for(int sx = 0; sx < LIGHTMAP_CACHE_X; ++sx)
   {
      for(int sy = 0; sy < LIGHTMAP_CACHE_Y; ++sy)
      {
          if (rl_dist(sx, sy, g->u.posx, g->u.posy) < 15)
          {
              lm[sx][sy] = 0;
          }
      }
   }
  }
}