--
-- BuyableMFWheels
-- Specialization for Buyable Twin Wheels
--
-- @author  	Manuel Leithner (SFM-Modding)
-- @version 	v3.0
-- @date  		30/10/10
-- @history:	v1.0 - Initial version
--				v2.0 - added network support, changed update to updateTick
--				v3.0 - Added dynamic collision support, ls13-ready
--				v3.1 - Some modifications (by fruktor) 
--
-- free for noncommerical-usage
--

BuyableMFWheels = {};

function BuyableMFWheels.prerequisitesPresent(specializations)
    return true;
end;

function BuyableMFWheels:load(xmlFile)

	self.twinWheelTriggerCallback = BuyableMFWheels.twinWheelTriggerCallback;
	self.wheelDelete = BuyableMFWheels.wheelDelete;
	self.assembleTwinWheels = SpecializationUtil.callSpecializationsFunction("assembleTwinWheels");
	self.disassembleTwinWheels = SpecializationUtil.callSpecializationsFunction("disassembleTwinWheels");
	self.assembleCareWheels = SpecializationUtil.callSpecializationsFunction("assembleCareWheels");
	self.disassembleCareWheels = SpecializationUtil.callSpecializationsFunction("disassembleCareWheels");
	self.assembleFloatWheels = SpecializationUtil.callSpecializationsFunction("assembleFloatWheels");
	self.disassembleFloatWheels = SpecializationUtil.callSpecializationsFunction("disassembleFloatWheels");

	self.checkString = Utils.getNoNil(getXMLString(xmlFile, "vehicle.extraWheels#checkString"), "standard");
	self.usingTrigger = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.extraWheels#activationTrigger"));
	
	addTrigger(self.usingTrigger, "twinWheelTriggerCallback", self);
    self.deleteListenerId = addDeleteListener(self.usingTrigger, "wheelDelete", self);
	
	self.twinBelts = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.extraWheels#twinBelts"));
	
    self.twinWheels = {};
    local i = 0;
    while true do
        local wheelnamei = string.format("vehicle.extraWheels.twinWheel(%d)", i);
        local twinWheel = {};
        local wheelIndex = getXMLInt(xmlFile, wheelnamei .. "#wheelIndex");
        if wheelIndex == nil then
            break;
        end;
		
		twinWheel.wheelIndex = wheelIndex;
		twinWheel.node = Utils.indexToObject(self.components, getXMLString(xmlFile, wheelnamei .. "#node"));
		twinWheel.savePosition = Utils.indexToObject(self.components, getXMLString(xmlFile, wheelnamei .. "#savePosition"));
		table.insert(self.twinWheels, twinWheel);
		i = i + 1;
	end;
	
	self.careBelts = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.extraWheels#careBelts"));
	self.careBeltsOff = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.extraWheels#careBeltsOff"));

    self.careWheels = {};
    local i = 0;
    while true do
        local wheelnamei = string.format("vehicle.extraWheels.careWheel(%d)", i);
        local careWheel = {};
		local node = Utils.indexToObject(self.components, getXMLString(xmlFile, wheelnamei .. "#node"));
        if node == nil then
            break;
        end;

		careWheel.node = node;
		careWheel.savePosition = Utils.indexToObject(self.components, getXMLString(xmlFile, wheelnamei .. "#savePosition"));
		careWheel.standardTire = nil;
		careWheel.tire = nil;
		careWheel.standardWheelPos = Utils.indexToObject(self.components, getXMLString(xmlFile, wheelnamei .. "#standardWheelPos"));
		table.insert(self.careWheels, careWheel);
		i = i + 1;
	end;
	
	self.floatBelts = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.extraWheels#floatBelts"));
	self.floatBeltsOff = Utils.indexToObject(self.components, getXMLString(xmlFile, "vehicle.extraWheels#floatBeltsOff"));
	
    self.floatWheels = {};
    local i = 0;
    while true do
        local wheelnamei = string.format("vehicle.extraWheels.floatWheel(%d)", i);
        local floatWheel = {};
		local node = Utils.indexToObject(self.components, getXMLString(xmlFile, wheelnamei .. "#node"));
        if node == nil then
            break;
        end;

		floatWheel.node = node;
		floatWheel.savePosition = Utils.indexToObject(self.components, getXMLString(xmlFile, wheelnamei .. "#savePosition"));
		floatWheel.standardTire = nil;
		floatWheel.standardWheel = nil;
		floatWheel.tire = nil;
		floatWheel.rim = nil;
		floatWheel.standardWheelPos = Utils.indexToObject(self.components, getXMLString(xmlFile, wheelnamei .. "#standardWheelPos"));
		table.insert(self.floatWheels, floatWheel);
		i = i + 1;
	end;

	self.loadedTwinCoords = nil;
	self.loadedCareCoords = nil;
	self.loadedFloatCoords = nil;
	self.twinWheelsUser = nil;
	self.careWheelsUser = nil;
	self.floatWheelsUser = nil;
end;

function BuyableMFWheels:delete()
	if self.twinWheelsUser ~= nil then
		self.twinWheelsUser:onDisassemblingTwins(true);
		for _,twinWheel in pairs(self.twinWheels) do
			delete(twinWheel.node);
		end;
		self.twinWheels = {};
	end;
	if self.careWheelsUser ~= nil then
		self.careWheelsUser:onDisassemblingCare(true);
		self:disassembleCareWheels();
		self.careWheels = {};
	end;
	if self.floatWheelsUser ~= nil then
		self.floatWheelsUser:onDisassemblingFloat(true);
		self:disassembleFloatWheels();
		self.floatWheels = {};
	end;
    removeTrigger(self.usingTrigger);
end;

function BuyableMFWheels:wheelDelete()
    removeDeleteListener(self.usingTrigger, self.deleteListenerId);
end;

function BuyableMFWheels:readStream(streamId, connection)
	local id = streamReadInt32(streamId);
	if id ~= -1 then
		local twinWheelsUser = networkGetObject(id);
		if twinWheelsUser ~= nil and careWheelsUser then
			self:assembleTwinWheels(twinWheelsUser, true);
		end;
	end;
	local id = streamReadInt32(streamId);
	if id ~= -1 then
		local careWheelsUser = networkGetObject(id);
		if careWheelsUser ~= nil and careWheelsUser then
			self:assembleCareWheels(careWheelsUser, true);
		end;
	end;
	local id = streamReadInt32(streamId);
	if id ~= -1 then
		local floatWheelsUser = networkGetObject(id);
		if floatWheelsUser ~= nil and floatWheelsUser then
			self:assembleFloatWheels(floatWheelsUser, true);
		end;
	end;
end;

function BuyableMFWheels:writeStream(streamId, connection)
	local idToWrite = -1;
	if self.twinWheelsUser ~= nil then
		idToWrite = networkGetObjectId(self.twinWheelsUser);
	end;
	streamWriteInt32(streamId, idToWrite);
	local idToWrite = -1;
	if self.careWheelsUser ~= nil then
		idToWrite = networkGetObjectId(self.careWheelsUser);
	end;
	streamWriteInt32(streamId, idToWrite);
	local idToWrite = -1;
	if self.floatWheelsUser ~= nil then
		idToWrite = networkGetObjectId(self.floatWheelsUser);
	end;
	streamWriteInt32(streamId, idToWrite);
end;

function BuyableMFWheels:mouseEvent(posX, posY, isDown, isUp, button)
end;

function BuyableMFWheels:keyEvent(unicode, sym, modifier, isDown)
end;

function BuyableMFWheels:loadFromAttributesAndNodes(xmlFile, key, resetVehicles)

	if not resetVehicles then
		local extraWheelsCoords = getXMLString(xmlFile, key.."#extraWheelsCoords");		
		if extraWheelsCoords ~= nil then
			local x1,y1,z1,x2,y2,z2,x3,y3,z3 = Utils.getVectorFromString(extraWheelsCoords);
			if x1 ~= nil and y1 ~= nil and z1 ~= nil and x1 ~= 0 and y1 ~= 0 and z1 ~= 0 then 
				self.loadedTwinCoords = {x = x1, y = y1, z = z1};
			end;
			if x2 ~= nil and y2 ~= nil and z2 ~= nil and x2 ~= 0 and y2 ~= 0 and z2 ~= 0 then 
				self.loadedCareCoords = {x = x2, y = y2, z = z2};
			end;
			if x3 ~= nil and y3 ~= nil and z3 ~= nil and x3 ~= 0 and y3 ~= 0 and z3 ~= 0 then 
				self.loadedFloatCoords = {x = x3, y = y3, z = z3};
			end;
		end;
	end; 

    return BaseMission.VEHICLE_LOAD_OK;
end;

function BuyableMFWheels:getSaveAttributesAndNodes(nodeIdent)	
    local attributes = nil;
	local x1,y1,z1 = 0, 0, 0;
	local x2,y2,z2 = 0, 0, 0;
	local x3,y3,z3 = 0, 0, 0;
	if self.twinWheelsUser ~= nil then
		x1,y1,z1 = getWorldTranslation(self.twinWheelsUser.rootNode);
	end;
	if self.careWheelsUser ~= nil then
		x2,y2,z2 = getWorldTranslation(self.careWheelsUser.rootNode);
	end;
	if self.floatWheelsUser ~= nil then
		x3,y3,z3 = getWorldTranslation(self.floatWheelsUser.rootNode);
	end;
	attributes = 'extraWheelsCoords="'.. x1 .. " " .. y1 .. " " .. z1 .. " " .. x2 .. " " .. y2 .. " " .. z2 .. " " .. x3 .. " " .. y3 .. " " .. z3 .. '"';

    return attributes, nil;
end;

function BuyableMFWheels:update(dt)
end;

function BuyableMFWheels:updateTick(dt)
	if self.loadedTwinCoords ~= nil then
		for k,steerable in pairs(g_currentMission.steerables) do
			local a,b,c = getWorldTranslation(steerable.rootNode);
			local distance = Utils.vector3Length(self.loadedTwinCoords.x-a, self.loadedTwinCoords.y-b, self.loadedTwinCoords.z-c);
			if distance < 0.15 then				
				self:assembleTwinWheels(steerable);
				break;
			end;
		end;
		self.loadedTwinCoords = nil;
	end;
	if self.loadedCareCoords ~= nil then
		for k,steerable in pairs(g_currentMission.steerables) do
			local a,b,c = getWorldTranslation(steerable.rootNode);
			local distance = Utils.vector3Length(self.loadedCareCoords.x-a, self.loadedCareCoords.y-b, self.loadedCareCoords.z-c);
			if distance < 0.15 then				
				self:assembleCareWheels(steerable);
				break;
			end;
		end;
		self.loadedCareCoords = nil;
	end;
	if self.loadedFloatCoords ~= nil then
		for k,steerable in pairs(g_currentMission.steerables) do
			local a,b,c = getWorldTranslation(steerable.rootNode);
			local distance = Utils.vector3Length(self.loadedFloatCoords.x-a, self.loadedFloatCoords.y-b, self.loadedFloatCoords.z-c);
			if distance < 0.15 then				
				self:assembleFloatWheels(steerable);
				break;
			end;
		end;
		self.loadedFloatCoords = nil;
	end;
end;

function BuyableMFWheels:draw()	
end;

function BuyableMFWheels:twinWheelTriggerCallback(triggerId, otherId, onEnter, onLeave, onStay, otherShapeId)
	local vehicle = g_currentMission.controlledVehicle;
	if vehicle ~= nil then
		if onEnter then		
			if vehicle.rootNode == otherId then
				if vehicle.buyableTwinWheels ~= nil then
					if vehicle.buyableTwinWheels.checkString == self.checkString then
						if self.twinWheelsUser ~= nil then
							if self.twinWheelsUser == vehicle then
								vehicle.buyableTwinWheels.wheelsInRange = self;
							end;
						else
							vehicle.buyableTwinWheels.wheelsInRange = self;
						end;
					end;
				end;
				if vehicle.buyableCareWheels ~= nil then
					if vehicle.buyableCareWheels.checkString == self.checkString then
						if self.careWheelsUser ~= nil then
							if self.careWheelsUser == vehicle then
								vehicle.buyableCareWheels.wheelsInRange = self;
							end;
						else
							vehicle.buyableCareWheels.wheelsInRange = self;
						end;
					end;
				end;
				if vehicle.buyableFloatWheels ~= nil then
					if vehicle.buyableFloatWheels.checkString == self.checkString then
						if self.floatWheelsUser ~= nil then
							if self.floatWheelsUser == vehicle then
								vehicle.buyableFloatWheels.wheelsInRange = self;
							end;
						else
							vehicle.buyableFloatWheels.wheelsInRange = self;
						end;
					end;
				end;
			end;
		elseif onLeave then		
			if otherId == vehicle.rootNode then
				if vehicle.buyableTwinWheels ~= nil then
					vehicle.buyableTwinWheels.wheelsInRange = nil;
				end;
				if vehicle.buyableCareWheels ~= nil then
					vehicle.buyableCareWheels.wheelsInRange = nil;
				end;
				if vehicle.buyableFloatWheels ~= nil then
					vehicle.buyableFloatWheels.wheelsInRange = nil;
				end;
			end;
		end;
	end;
end;

function BuyableMFWheels:assembleTwinWheels(vehicle, noEventSend)
	BuyableMFdualsAttachEvent.sendEvent(self, vehicle, noEventSend);
	
	if self.twinBelts ~= nil then
		setVisibility(self.twinBelts, false);
	end;
	
	if self.twinWheelsUser == nil then
		if vehicle.buyableTwinWheels ~= nil then
			self.twinWheelsUser = vehicle;	
			for l,twinWheel in pairs(self.twinWheels) do 				
				for k,wheel in pairs(vehicle.wheels) do
					if k == twinWheel.wheelIndex then
						link(wheel.driveNode, twinWheel.node);
						local x,y,z = getWorldTranslation(wheel.driveNode);							
						x,y,z = worldToLocal(getParent(twinWheel.node), x,y,z);
						setTranslation(twinWheel.node,x,y,z);
						break;
					end;
				end;
			end;			
			self.twinWheelsUser:onAssemblingTwins(self);
		end;
	end;
end;

function BuyableMFWheels:disassembleTwinWheels(noEventSend)
	BuyableMFdualsDetachEvent.sendEvent(self, noEventSend);
	
	if self.twinBelts ~= nil then
		setVisibility(self.twinBelts, true);		
	end;

	self.twinWheelsUser:onDisassemblingTwins();
	
	for k,wheel in pairs(self.twinWheels) do
		link(wheel.savePosition, wheel.node);
		setRotation(wheel.node, 0,0,0);
		setTranslation(wheel.node, 0,0,0);
	end;	
	self.twinWheelsUser = nil;
end;

function BuyableMFWheels:assembleCareWheels(vehicle, noEventSend)
	BuyableMFcareAttachEvent.sendEvent(self, vehicle, noEventSend);
	
	if self.careBelts ~= nil and self.careBeltsOff ~= nil then
		setVisibility(self.careBelts, false);
		setVisibility(self.careBeltsOff, true);
	end;
	
	if self.careWheelsUser == nil then
		if vehicle.buyableCareWheels ~= nil then
			self.careWheelsUser = vehicle;	
			for l,careWheel in pairs(self.careWheels) do
				for k,wheel in pairs(vehicle.standardWheels) do
					if k == l then	
						careWheel.standardTire = getChildAt(wheel.tire, 0);	
						careWheel.tire = wheel.tire;
						link(wheel.rim, careWheel.node);	
						link(careWheel.standardWheelPos, careWheel.standardTire);
						break;
					end;
				end;
			end;			
			self.careWheelsUser:onAssemblingCare(self);
		end;
	end;
end;

function BuyableMFWheels:disassembleCareWheels(noEventSend)
	BuyableMFcareDetachEvent.sendEvent(self, noEventSend);
	
	if self.careBelts ~= nil and self.careBeltsOff ~= nil then
		setVisibility(self.careBelts, true);
		setVisibility(self.careBeltsOff, false);
	end;

	self.careWheelsUser:onDisassemblingCare();
	
	for k,careWheel in pairs(self.careWheels) do
		link(careWheel.tire, careWheel.standardTire);	
		link(careWheel.savePosition, careWheel.node);
		careWheel.standardTire = nil;
		careWheel.tire = nil;
	end;	
	self.careWheelsUser = nil;
end;

function BuyableMFWheels:assembleFloatWheels(vehicle, noEventSend)
	BuyableMFfloatAttachEvent.sendEvent(self, vehicle, noEventSend);
	
	if self.floatBelts ~= nil and self.floatBeltsOff ~= nil then
		setVisibility(self.floatBelts, false);
		setVisibility(self.floatBeltsOff, true);
	end;
	
	if self.floatWheelsUser == nil then
		if vehicle.buyableFloatWheels ~= nil then
			self.floatWheelsUser = vehicle;	
			for l,floatWheel in pairs(self.floatWheels) do 				
				for k,wheel in pairs(vehicle.standardWheels) do	
					if k == l then
						floatWheel.standardWheel = getChildAt(wheel.rim, 0);
						floatWheel.standardTire = getChildAt(wheel.tire, 0);
						floatWheel.rim = wheel.rim;
						floatWheel.tire = wheel.tire;
						link(wheel.rim, floatWheel.node);	
						link(floatWheel.standardWheelPos, floatWheel.standardWheel);
						link(floatWheel.standardWheelPos, floatWheel.standardTire);
						break;
					end;
				end;
			end;			
			self.floatWheelsUser:onAssemblingFloat(self);
		end;
	end;
end;

function BuyableMFWheels:disassembleFloatWheels(noEventSend)
	BuyableMFfloatDetachEvent.sendEvent(self, noEventSend);

	if self.floatBelts ~= nil and self.floatBeltsOff ~= nil then
		setVisibility(self.floatBelts, true);
		setVisibility(self.floatBeltsOff, false);
	end;
	
	self.floatWheelsUser:onDisassemblingFloat();
	
	for k,floatWheel in pairs(self.floatWheels) do
		link(floatWheel.rim, floatWheel.standardWheel);	
		link(floatWheel.tire, floatWheel.standardTire);
		link(floatWheel.savePosition, floatWheel.node);
		floatWheel.standardTire = nil;
		floatWheel.standardWheel = nil;
		floatWheel.rim = nil;
		floatWheel.tire = nil;
	end;	
	self.floatWheelsUser = nil;
end;


BuyableMFdualsAttachEvent = {};
BuyableMFdualsAttachEvent_mt = Class(BuyableMFdualsAttachEvent, Event);

InitEventClass(BuyableMFdualsAttachEvent, "BuyableMFdualsAttachEvent");

function BuyableMFdualsAttachEvent:emptyNew()
    local self = Event:new(BuyableMFdualsAttachEvent_mt);
    return self;
end;

function BuyableMFdualsAttachEvent:new(vehicle, attacherVehicle)
    local self = BuyableMFdualsAttachEvent:emptyNew()
    self.vehicle = vehicle;
	self.attacherVehicle = attacherVehicle;
    return self;
end;

function BuyableMFdualsAttachEvent:readStream(streamId, connection)
    local id = streamReadInt32(streamId);
	local attacherId = streamReadInt32(streamId);
	self.attacherVehicle = networkGetObject(attacherId);
    self.vehicle = networkGetObject(id);
    self:run(connection);
end;

function BuyableMFdualsAttachEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.vehicle));
	streamWriteInt32(streamId, networkGetObjectId(self.attacherVehicle));
end;

function BuyableMFdualsAttachEvent:run(connection)
	self.vehicle:assembleTwinWheels(self.attacherVehicle, true);
    if not connection:getIsServer() then
        g_server:broadcastEvent(BuyableMFdualsAttachEvent:new(self.vehicle, self.attacherVehicle), nil, connection, self.object);
    end;
end;


function BuyableMFdualsAttachEvent.sendEvent(vehicle, attacherVehicle, noEventSend)
	if noEventSend == nil or noEventSend == false then
		if g_server ~= nil then
			g_server:broadcastEvent(BuyableMFdualsAttachEvent:new(vehicle, attacherVehicle), nil, nil, vehicle);
		else
			g_client:getServerConnection():sendEvent(BuyableMFdualsAttachEvent:new(vehicle, attacherVehicle));
		end;
	end;
end;


BuyableMFdualsDetachEvent = {};
BuyableMFdualsDetachEvent_mt = Class(BuyableMFdualsDetachEvent, Event);

InitEventClass(BuyableMFdualsDetachEvent, "BuyableMFdualsDetachEvent");

function BuyableMFdualsDetachEvent:emptyNew()
    local self = Event:new(BuyableMFdualsDetachEvent_mt);
    return self;
end;

function BuyableMFdualsDetachEvent:new(vehicle)
    local self = BuyableMFdualsDetachEvent:emptyNew()
    self.vehicle = vehicle;
    return self;
end;

function BuyableMFdualsDetachEvent:readStream(streamId, connection)
    local id = streamReadInt32(streamId);
    self.vehicle = networkGetObject(id);
    self:run(connection);
end;

function BuyableMFdualsDetachEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.vehicle));
end;

function BuyableMFdualsDetachEvent:run(connection)
	self.vehicle:disassembleTwinWheels(true);
    if not connection:getIsServer() then
        g_server:broadcastEvent(BuyableMFdualsDetachEvent:new(self.vehicle), nil, connection, self.object);
    end;
end;

function BuyableMFdualsDetachEvent.sendEvent(vehicle, noEventSend)
	if noEventSend == nil or noEventSend == false then
		if g_server ~= nil then
			g_server:broadcastEvent(BuyableMFdualsDetachEvent:new(vehicle), nil, nil, vehicle);
		else
			g_client:getServerConnection():sendEvent(BuyableMFdualsDetachEvent:new(vehicle));
		end;
	end;
end;

BuyableMFcareAttachEvent = {};
BuyableMFcareAttachEvent_mt = Class(BuyableMFcareAttachEvent, Event);

InitEventClass(BuyableMFcareAttachEvent, "BuyableMFcareAttachEvent");

function BuyableMFcareAttachEvent:emptyNew()
    local self = Event:new(BuyableMFcareAttachEvent_mt);
    return self;
end;

function BuyableMFcareAttachEvent:new(vehicle, attacherVehicle)
    local self = BuyableMFcareAttachEvent:emptyNew()
    self.vehicle = vehicle;
	self.attacherVehicle = attacherVehicle;
    return self;
end;

function BuyableMFcareAttachEvent:readStream(streamId, connection)
    local id = streamReadInt32(streamId);
	local attacherId = streamReadInt32(streamId);
	self.attacherVehicle = networkGetObject(attacherId);
    self.vehicle = networkGetObject(id);
    self:run(connection);
end;

function BuyableMFcareAttachEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.vehicle));
	streamWriteInt32(streamId, networkGetObjectId(self.attacherVehicle));
end;

function BuyableMFcareAttachEvent:run(connection)
	self.vehicle:assembleCareWheels(self.attacherVehicle, true);
    if not connection:getIsServer() then
        g_server:broadcastEvent(BuyableMFcareAttachEvent:new(self.vehicle, self.attacherVehicle), nil, connection, self.object);
    end;
end;


function BuyableMFcareAttachEvent.sendEvent(vehicle, attacherVehicle, noEventSend)
	if noEventSend == nil or noEventSend == false then
		if g_server ~= nil then
			g_server:broadcastEvent(BuyableMFcareAttachEvent:new(vehicle, attacherVehicle), nil, nil, vehicle);
		else
			g_client:getServerConnection():sendEvent(BuyableMFcareAttachEvent:new(vehicle, attacherVehicle));
		end;
	end;
end;


BuyableMFcareDetachEvent = {};
BuyableMFcareDetachEvent_mt = Class(BuyableMFcareDetachEvent, Event);

InitEventClass(BuyableMFcareDetachEvent, "BuyableMFcareDetachEvent");

function BuyableMFcareDetachEvent:emptyNew()
    local self = Event:new(BuyableMFcareDetachEvent_mt);
    return self;
end;

function BuyableMFcareDetachEvent:new(vehicle)
    local self = BuyableMFcareDetachEvent:emptyNew()
    self.vehicle = vehicle;
    return self;
end;

function BuyableMFcareDetachEvent:readStream(streamId, connection)
    local id = streamReadInt32(streamId);
    self.vehicle = networkGetObject(id);
    self:run(connection);
end;

function BuyableMFcareDetachEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.vehicle));
end;

function BuyableMFcareDetachEvent:run(connection)
	if self.vehicle ~= nil then
		self.vehicle:disassembleCareWheels(true);
	end;
    if not connection:getIsServer() then
        g_server:broadcastEvent(BuyableMFcareDetachEvent:new(self.vehicle), nil, connection, self.object);
    end;
end;

function BuyableMFcareDetachEvent.sendEvent(vehicle, noEventSend)
	if noEventSend == nil or noEventSend == false then
		if g_server ~= nil then
			g_server:broadcastEvent(BuyableMFcareDetachEvent:new(vehicle), nil, nil, vehicle);
		else
			g_client:getServerConnection():sendEvent(BuyableMFcareDetachEvent:new(vehicle));
		end;
	end;
end;

BuyableMFfloatAttachEvent = {};
BuyableMFfloatAttachEvent_mt = Class(BuyableMFfloatAttachEvent, Event);

InitEventClass(BuyableMFfloatAttachEvent, "BuyableMFfloatAttachEvent");

function BuyableMFfloatAttachEvent:emptyNew()
    local self = Event:new(BuyableMFfloatAttachEvent_mt);
    return self;
end;

function BuyableMFfloatAttachEvent:new(vehicle, attacherVehicle)
    local self = BuyableMFfloatAttachEvent:emptyNew()
    self.vehicle = vehicle;
	self.attacherVehicle = attacherVehicle;
    return self;
end;

function BuyableMFfloatAttachEvent:readStream(streamId, connection)
    local id = streamReadInt32(streamId);
	local attacherId = streamReadInt32(streamId);
	self.attacherVehicle = networkGetObject(attacherId);
    self.vehicle = networkGetObject(id);
    self:run(connection);
end;

function BuyableMFfloatAttachEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.vehicle));
	streamWriteInt32(streamId, networkGetObjectId(self.attacherVehicle));
end;

function BuyableMFfloatAttachEvent:run(connection)
	if self.vehicle ~= nil then
		self.vehicle:assembleFloatWheels(self.attacherVehicle, true);
	end;
    if not connection:getIsServer() then
        g_server:broadcastEvent(BuyableMFfloatAttachEvent:new(self.vehicle, self.attacherVehicle), nil, connection, self.object);
    end;
end;


function BuyableMFfloatAttachEvent.sendEvent(vehicle, attacherVehicle, noEventSend)
	if noEventSend == nil or noEventSend == false then
		if g_server ~= nil then
			g_server:broadcastEvent(BuyableMFfloatAttachEvent:new(vehicle, attacherVehicle), nil, nil, vehicle);
		else
			g_client:getServerConnection():sendEvent(BuyableMFfloatAttachEvent:new(vehicle, attacherVehicle));
		end;
	end;
end;


BuyableMFfloatDetachEvent = {};
BuyableMFfloatDetachEvent_mt = Class(BuyableMFfloatDetachEvent, Event);

InitEventClass(BuyableMFfloatDetachEvent, "BuyableMFfloatDetachEvent");

function BuyableMFfloatDetachEvent:emptyNew()
    local self = Event:new(BuyableMFfloatDetachEvent_mt);
    return self;
end;

function BuyableMFfloatDetachEvent:new(vehicle)
    local self = BuyableMFfloatDetachEvent:emptyNew()
    self.vehicle = vehicle;
    return self;
end;

function BuyableMFfloatDetachEvent:readStream(streamId, connection)
    local id = streamReadInt32(streamId);
    self.vehicle = networkGetObject(id);
    self:run(connection);
end;

function BuyableMFfloatDetachEvent:writeStream(streamId, connection)
    streamWriteInt32(streamId, networkGetObjectId(self.vehicle));
end;

function BuyableMFfloatDetachEvent:run(connection)
	if self.vehicle ~= nil then
		self.vehicle:disassembleFloatWheels(true);
	end;
    if not connection:getIsServer() then
        g_server:broadcastEvent(BuyableMFfloatDetachEvent:new(self.vehicle), nil, connection, self.object);
    end;
end;

function BuyableMFfloatDetachEvent.sendEvent(vehicle, noEventSend)
	if noEventSend == nil or noEventSend == false then
		if g_server ~= nil then
			g_server:broadcastEvent(BuyableMFfloatDetachEvent:new(vehicle), nil, nil, vehicle);
		else
			g_client:getServerConnection():sendEvent(BuyableMFfloatDetachEvent:new(vehicle));
		end;
	end;
end;