Making a Service Truck

Game Version: FS17
Programs required:


Modding Index | Vehicle Tutorials


The excellent repairVehicles and Seasons mods have made significant alterations to the GIANTS game engine calculations for things like vehicle maintenance.  They've also allowed the ability to repair and configure equipment, primarily at the placeable workshop.  The [font=courier]repairVehicles[/font] script used to allow repairs to be made in the field, but the updated version of this mod allows it only at the placeable workshop.  I've been unable to find a 'service truck' whereby a player can make repairs/configuration to vehicles that are in proximity to the 'service truck.'  These appear to be allowed only at the placeable workshop.  Perhaps there is a 'service truck' out there, and I haven't known just where to look.  This one on the modhub is the closest I know of, but it says the [font=courier]repairVehicles[/font] script isn't yet implemented (though it does have functionality for Seasons mod maintenance, as Mike3650 points out below ;)).  Probably will be some day, in which case you should ignore everything that follows. :D  But if someone is aware of a service truck out there, please do chime in, as it's highly likely better than anything I can come up with.

In the meantime, below is a tutorial on how to make a service truck yourself, if you'd like to have the ability to 'drive to' your equipment to repair/configure them.  My focus was only on the ability to repair/configure vehicles.  There are certainly many other features that might be integrated into a service truck, such as the ability to replenish fuel, or to provide seed/fertilizer, etc.

1.  Find a 'truck' mod to work with.  I chose to download the FS17 All Seeds Service Pickup v2.0 from FS-UK.  It could really be most any vehicle, but this one will work, and has the additional advantage of being able to replenish sowing machines with seeds, and both liquid and dry fertilizer spreaders.

2.  Unzip the 'truck' mod in the game's mod folder and delete the zip file.  I like working with the mod in the mods folder as one can easily go in-game to run tests.  Just make sure to delete the downloaded zip after unzipping it, as it will interfere with the one you're going to be modifying.

3.  Download also the tool box mod, and unzip it in the mods folder.  Unzip the mod and delete the zip file as you did with the service truck.  Having this mod will hopefully make set up of the service truck a little easier than it otherwise would be, as it has all the triggers set up that are needed.

4.  Open the tool box mod in the GIANTS Editor and export all files.  When asked where to export the files to, name the i3d file [font=courier]toolBox.i3d[/font] (or whatever you please), and export everything into the pickup mod's file you downloaded in step # 1.  Don't keep the parent directory structure.
s1.bild.me_bilder_110417_4115999capture.jpg[/URL] If you want to use the Tool Box Fix script, note also the user attributes in the picture above (click to expand if you wish) and set them up accordingly.  See the link just given for instructions on how to set these attributes up on the trigger as shown.  Two additional steps, assuming you want the tool box fix, are to (1) copy and paste the [font=courier]store_toolbox.dds[/font] file into the root directory of the service truck mod, as the tool box fix will be looking for this as an icon to display on the PDA map in-game; and (2) copy and paste the [font=courier]ToolBox.lua[/font] script into the service truck mod (note the location for later reference in its [font=courier]modDesc.xml[/font] file – more on this in a bit).  Again, you can get the [font=courier]ToolBox.lua[/font] script at the link just given above for the tool box fix.  I'll also attach a copy of the script to this post.

5.  Open the service truck mod in the GIANTS Editor and import the files you just exported.  Cut and paste the import into the main transform group as shown in the picture below: s1.bild.me_bilder_110417_1622211capture.jpg[/URL] Note a couple things to update.  (1) Click on the 'Rigid Body' tab and click the 'trigger' button, and a 'Rigid Body Type' of Kinematic.  That'll hopefully keep the toolbox from moving around.  (2) Next, place the tool box some open place in the back of the pickup… if you can find one. :)  You'll then need to move the objects/triggers accordingly so that they are placed as shown in the picture (or where ever you wish).  I chose to have the configuration trigger be just outside the pickup door, and the other trigger surrounding the truck.  You can even scale it up or down to the size you wish.  (3) Write down the index of the tool box triggers, which is shown on the 'Transform' tab in the upper right hand (not shown in the picture).  For this truck, it happens to be [font=courier]0>19[/font]. (4) Save changes in the editor and close the file.  (5)  Within the service truck mod's file directories, remove the i3d file you imported and its shape file.  These are no longer needed, as they've now been incorporated into the service truck's model.

6.  Open the service truck mod's xml file and make one small edit to note the presence of the new triggers.  You can do this with something like Notepad++.  Add a line at the bottom, just before the end tag at the bottom that looks like this, using the trigger index you wrote down in step # 5(5) above:

<vehicleSellTrigger index="0>19" />

When you're done, save and close the xml file.

7.  Open the service truck mod's [font=courier]modDesc.xml[/font] file and make a couple small modifications.  We need to update the mod to the latest patch version for Farming Simulator (by revising the [font=courier]descVersion[/font] to 37), add a new specialization to handle the repair/configuration functionality (called [font=courier]service[/font]), and add the toolbox fix if desired (by calling an [font=courier]extraSourceFiles[/font] – make sure the location of the script is correct based on what you wrote down in step # 4 above).  The lines to add or modify in the [font=courier]modDesc.xml[/font] file are as follows.  All other lines of the file are represented with (……….):

<?xml version="1.0" encoding="utf-8" standalone="no" ?>
<modDesc descVersion="37">
     ..........
    <extraSourceFiles>
        <sourceFile filename="shared/ToolBox.lua" />
    </extraSourceFiles>

    <specializations>
        ..........
        <specialization name="service"  className="Service"  filename="shared/Service.lua" />
    </specializations>

    <vehicleTypes>
        <type name="ServicePickup" className="Vehicle" filename="$dataS/scripts/vehicles/Vehicle.lua">
            ..........
            <specialization name="service" />
        </type>
    </vehicleTypes>
    ..........
</modDesc>

8.  Draft the [font=courier]Service.lua[/font] script and save it into the service truck's directory.  This file should be saved into the truck's directories as noted in the [font=courier]modDesc.xml[/font] file.  In step # 7 above we show it to be in the [font=courier]shared[/font] directory.  The script should look something like this:

--=====================================================================================
-- SERVICE TRUCK
--
-- @For:		Anybody
-- @Date:		2017-10-14
-- @Purpose:	To affix vehicle selling trigger to truck, enabling field repairs.
--=====================================================================================


Service = {};

function Service.prerequisitesPresent(specializations)
    return SpecializationUtil.hasSpecialization(Drivable, specializations)
end;

function Service:load(savegame)
	self.addVehicleSellTrigger = Service.addVehicleSellTrigger
	self.removeVehicleSellTrigger = Service.removeVehicleSellTrigger
	
	self.vehicleSellTriggers = {}
	
	local vehicleSellTriggerNode = Utils.indexToObject(self.components, getXMLString(self.xmlFile, "vehicle.vehicleSellTrigger#index"))

	if vehicleSellTriggerNode ~= nil then
		self.vehicleSellTrigger = VehicleSellingPoint:new(vehicleSellTriggerNode, self)
	end;
	
end;

function Service:delete()
	for _, trigger in pairs(self.vehicleSellTriggers) do
		trigger:onVehicleDeleted(self);
	end;

	if self.vehicleSellTrigger ~= nil then
		self.vehicleSellTrigger:delete();
		self.vehicleSellTrigger = nil;
	end;
end;

function Service:readStream(streamId, connection)
end;

function Service:writeStream(streamId, connection)
end;

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

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

function Service:update(dt)
end;

function Service:updateTick(dt)
end;

function Service:draw()	
end;

function Service:addVehicleSellTrigger(trigger)
	table.insert(self.vehicleSellTriggers, trigger);
end;

function Service:removeVehicleSellTrigger(trigger)
	for i = 1, table.getn(self.vehicleSellTriggers) do
		if self.vehicleSellTriggers[i] == trigger then
			table.remove(self.vehicleSellTriggers, i);
			break;
		end;
	end;
end;

oldVehicleSellingPointNew = VehicleSellingPoint.new
VehicleSellingPoint.new = function(self, id)

	local self
	if oldVehicleSellingPointNew ~= nil then
		self = oldVehicleSellingPointNew(self, id)
	end;

	self.vehiclesSellTriggerCount = {}
	
	return self
end;

oldVehicleSellingPointDelete = VehicleSellingPoint.delete
VehicleSellingPoint.delete = function(self)
	
	oldVehicleSellingPointDelete(self)
	
	for vehicle, count in pairs(self.vehiclesSellTriggerCount) do
		if count > 0 then
			if vehicle.removeVehicleSellTrigger ~= nil then
				vehicle:removeVehicleSellTrigger(self);
			end;
		end;
	end;
	
end;

function VehicleSellingPoint:onVehicleDeleted(vehicle)
	self.vehiclesSellTriggerCount[vehicle] = nil
end;

VehicleSellingPoint.triggerCallback = function(self, triggerId, otherId, onEnter, onLeave, onStay)
	if self.isEnabled and (not g_isPresentationVersion or g_isPresentationVersionShopEnabled) and g_currentMission.missionInfo:isa(FSCareerMissionInfo) then

		if onEnter or onLeave then
			if g_currentMission.player ~= nil and otherId == g_currentMission.player.rootNode then
				if onEnter then
					if not self.objectActivated then
						g_currentMission:addActivatableObject(self)
						self.objectActivated = true
					end;
				elseif onLeave then
					if self.objectActivated then
						g_currentMission:removeActivatableObject(self)
						self.objectActivated = false
					end;
				end;
			end;
			
			local vehicle = g_currentMission.nodeToVehicle[otherId];
			if vehicle ~= nil then 
				if vehicle.addVehicleSellTrigger ~= nil and vehicle.removeVehicleSellTrigger ~= nil and vehicle ~= self then
					local count = Utils.getNoNil(self.vehiclesSellTriggerCount[vehicle], 0);
					if onEnter then
						self.vehiclesSellTriggerCount[vehicle] = count + 1
						if count == 0 then
							vehicle:addVehicleSellTrigger(self);
						end;
					else -- onLeave
						self.vehiclesSellTriggerCount[vehicle] = count - 1
						if count == 1 then
							self.vehiclesSellTriggerCount[vehicle] = nil;
							vehicle:removeVehicleSellTrigger(self);
						end;
					end;
				end;
			end;
		end;
	end;
end;

VehicleSellingPoint.sellAreaTriggerCallback = function(self, triggerId, otherId, onEnter, onLeave, onStay, otherShapeId)
	if otherShapeId ~= nil and (onEnter or onLeave) then
		if onEnter then
			self.vehicleInRange[otherShapeId] = true
		elseif onLeave then
			self.vehicleInRange[otherShapeId] = nil
		end;

		self:determineCurrentVehicle()
		
		local vehicle = self.currentVehicle
		if vehicle ~= nil then
			if onEnter then
				vehicle.rvWIRTrigger = true
			else
				vehicle.rvWIRTrigger = false
			end;
		end;

	end;
end;

Mission00.loadMission00Finished = Utils.appendedFunction(Mission00.loadMission00Finished, function(...)
	local repairMod = "FS17_repairVehicles"

	if g_modIsLoaded[repairMod] then
		envRepairVehicles = getfenv(0)[repairMod]
	end;
	
	if envRepairVehicles ~= nil then
		envRepairVehicles.repairVehicles.updateTick = Utils.overwrittenFunction(envRepairVehicles.repairVehicles.updateTick, function(self, dt)
			if g_currentMission.player ~= nil then
				local vx, vy, vz = getWorldTranslation(g_currentMission.player.rootNode);
				local sx, sy, sz = getWorldTranslation(self.rootNode); 
				local distance = Utils.vector3Length(sx-vx, sy-vy, sz-vz);
				if distance < 3.5 then
					self.rvPIR = true; 
				else
					self.rvPIR = false; 
				end;
			end;

			if self.vehicleNode == nil then
				for vehicleNode,vehicleTable in pairs(g_currentMission.nodeToVehicle) do
					if vehicleTable == self then
						self.vehicleNode = vehicleNode;
					end
				end
			else
				local numWorkshops = 0;
				self.rvWIR = false;
				for infoTable,name in pairs(g_currentMission.objectsToClassName) do
					if name == "Workshop" then
						numWorkshops = numWorkshops + 1;
						if infoTable.sellingPoint.vehicleInRange ~= nil then
							if infoTable.sellingPoint.vehicleInRange[self.vehicleNode] ~= nil then
								self.rvWIR = true;
								break;
							end
						end
					end
				end
				if numWorkshops == 0 then
					self.rvWIR = false;
				end
				if self.rvWIRTrigger and not self.rvWIR then
					self.rvWIR = true
				end;
			end;
		end)
	end;
end)

The script documents the specialization, which forms a bridge between the triggers you imported, and the game engine scripts.  Also included are a few modifications to the GIANTS [color=blue][font=courier]Vehicle Selling Point scripts[/font][/color] to adapt them to our use.  Finally, it makes one small tweak to the [font=courier]repairVehicles[/font] mod script so that our changes can talk to it.  My fingers are crossed anyway. :) A copy of the script is attached to this post… and hopefully those that really know how to script won't laugh at it too much. :D

9.  Re-zip the mod and try in-game.  If you're going to use this in single player only, you wouldn't need to re-zip the file.  But if you want to use it in a multiplayer setting, it'll need to be zipped back up.  If all goes well, you should now be able to do any repairs or vehicle configuration of vehicles and equipment in close proximity to the service truck.  You might at times need to move the service truck around so as to get at particular vehicles, but you 'should' be able to take care of everything with this roving truck, and not have to take anything to the workshop placeable.  Here are a couple pictures from in-game, including the PDA map: s1.bild.me_bilder_110417_4355304fsscreen_2017_10_15_00_02_58.jpg    s1.bild.me_bilder_110417_6847731fsscreen_2017_10_15_00_02_41.jpg     s1.bild.me_bilder_110417_4258931fsscreen_2017_10_15_00_03_35.jpg     s1.bild.me_bilder_110417_9352378fsscreen_2017_10_15_00_06_45.jpg As shown, proximity to the truck allows for repairs (Z key), vehicle modifications (R key), and vehicle repairs (Left-Alt-R key).

I 'think' (or hope) the above is all that's needed to make this work.  It appears to be working even in a multiplayer environment, so hopefully it also works on your end if you give this a try.  Best of luck! :)


Original Author: akuenzi | Date: October 15, 2017

Modding Index | Vehicle Tutorials