Skip to content
This repository was archived by the owner on Jul 16, 2026. It is now read-only.
This repository was archived by the owner on Jul 16, 2026. It is now read-only.

Fix vanilla FL Bug to transfer Nanoboty/ShieldBatts to ships with 0 capacity #480

Description

@erikroe

If you have a ship with Nanobots/Batteries capacity, and then switch to one that has zero capacity (0) then Freelancer will NOT remove those bats/bots. They will stay on the new ship, despite not having any capacity for it.

FLSR solution, Hook 2 syntax:

namespace BatsBotsShipTransferFix
{
	static std::unordered_map<uint, uint> boughtShipArchByClientId;

	void __stdcall GFGoodBuy(const SGFGoodBuyInfo& gbi, unsigned int clientId)
	{
		returncode = DEFAULT_RETURNCODE;

		boughtShipArchByClientId.erase(clientId);
		const GoodInfo* goodInfo = GoodList::find_by_id(gbi.iGoodID);
		if (!goodInfo || goodInfo->iType != 3)
			return;
		const GoodInfo* hullGoodInfo = GoodList::find_by_id(goodInfo->iHullGoodID);
		if (hullGoodInfo && hullGoodInfo->iType == 2)
			boughtShipArchByClientId[clientId] = hullGoodInfo->iShipGoodID;
	}

	struct Result
	{
		bool erase = false;
		float refund = 0.0f;
	};

	static Result ReduceAndRefund(const st6::list<EquipDesc>::iterator& it, const int maxCount, const uint clientId)
	{
		Result result;
		const int countDiff = std::max(0, it->get_count() - maxCount);
		if (countDiff <= 0)
			return result;
		const GoodInfo* goodInfo = GoodList::find_by_id(it->get_arch_id());
		if (goodInfo)
			result.refund = goodInfo->fPrice * countDiff;
		if (maxCount > 0)
			it->iCount -= countDiff;
		else
			result.erase = true;
		return result;
	}

	void __stdcall ReqEquipment(const EquipDescList& equipDescriptorList, unsigned int clientId)
	{
		returncode = DEFAULT_RETURNCODE;

		if (!boughtShipArchByClientId.contains(clientId))
			return;

		Archetype::Ship* ship = Archetype::GetShip(boughtShipArchByClientId[clientId]);
		boughtShipArchByClientId.erase(clientId);
		if (!ship)
			return;

		float refund = 0;
		EquipDescList* list = (EquipDescList*)&equipDescriptorList;
		for (auto it = list->equip.begin(); it != list->equip.end(); )
		{
			const Archetype::Equipment* archetype = Archetype::GetEquipment(it->get_arch_id());
			if (!archetype)
			{
				it++;
				continue;
			}

			const Archetype::AClassType type = archetype->get_class_type();
			Result result;

			if (type == Archetype::AClassType::REPAIR_KIT)
				result = ReduceAndRefund(it, ship->iMaxNanobots, clientId);
			else if (type == Archetype::AClassType::SHIELD_BATTERY)
				result = ReduceAndRefund(it, ship->iMaxShieldBats, clientId);

			refund += result.refund;
			if (result.erase)
				it = list->equip.erase(it);
			else
				it++;
		}
		if (refund > 0.0f)
			pub::Player::AdjustCash(clientId, static_cast<int>(std::ceil(refund)));
	}
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions