meta data for this page

Vehicles/VehicleManager.lua

Together with Vehicle, VehicleManager is at the core of all scripts relating to vehicles. It is responsible for managing many features that are shared between all vehicles (such as switching vehicles using the Tab key and the distribution of various events such as update(dt)).

  34  VehicleManager                      = VehicleManager or {};

VehicleManager:setup()

Is called upon initialisation of the game. This will also set up SnowmakingManager.

  39  function VehicleManager:setup()
  40      self.vehicles                   = {};
  41      self.vehiclesByOrder            = {};
  42      self.vehiclesById               = {};
  43      self.vehicleTypes               = {};
  44  
  45      self.allowSwitchVehicle         = true;
  46      self.currentVehicle             = nil; -- the vehicle this player is currently in
  47  
  48      self.vehicleSpawnPositons       = {};
  49      self.dummyFunction              = function() end;
  50  
  51      VehicleManager.vehicleFallbacks     = {};
  52      VehicleManager:registerVehicleFallback("default.MarmottaGigaSnow100", "default.TechnoalpinTR10");
  53  
  54      SnowmakingManager:setup();
  55  end;
  56  

VehicleManager:newFunction(functionName)

This function will return a new function which calls the function named functionName (string) for all vehicle scripts of the vehicle it is called on. Check the load() function of any vehicle script (e.g. RopeWinch) to see how it is used.

  59  function VehicleManager:newFunction(functionName)
  60      -- returns a function that calls all vehicle scripts
  61      
  62      return function(self, ...)
  63          -- call all vehicle scripts
  64          
  65          for _, script in ipairs(self.vehicleScripts) do
  66              -- ensure its not nil
  67              if script[functionName] ~= nil then
  68                  script[functionName](self, ...);
  69              end;
  70          end;
  71      end;
  72  end;
  73  

VehicleManager:dummyFunction()

This function will return a dummy function that does not perform any action at all. This is easier than checking the functions against nil in some cases.

  77  function VehicleManager:dummyFunction()
  78      return self.dummyFunction;
  79  end;

VehicleManager:registerVehicleType(typeName, dataTable)

Registers a new vehicle template named typeName (string). The data regarding this template are stored within template (table).

  87  function VehicleManager:registerVehicleType(typeName, dataTable)
  88      self.vehicleTypes[typeName]     = dataTable;
  89      -- mark this as non-customizable, only if self:loadCustomizations() succeeds, this will be overwritten by true
  90      dataTable.isCustomizable        = false;
  91      if type(dataTable.customizations) == "table" then
  92          self:loadCustomizations(typeName, dataTable);
  93          
  94      -- throw a warning if a modder wants to add a customization, but chose the wrong data type
  95      elseif dataTable.customizations ~= nil then
  96          print("Warning while loading vehicle type " .. tostring(typeName) .. ". Invalid value customizations is a " .. type(dataTable.customizations) .. " (table expected). Customizations will be ignored.");
  97      end;
  98  end;
  99  

VehicleManager:registerVehicleFallback(fallbackFrom, fallbackTo)

Registers a new vehicle fallback for the vehicle type fallbackFrom (string). If this vehicle cannot be found, the game will use the vehicle type fallbackTo (string) instead. Note that both must be the full vehicle name including mod path, workshop id and asset bundle name.

 102  function VehicleManager:registerVehicleFallback(fallbackFrom, fallbackTo)
 103      VehicleManager.vehicleFallbacks[fallbackFrom]       = fallbackTo;
 104  end;
 105  

VehicleManager:registerVehicle(vehicle)

Registers a new vehicle instance vehicle (table of the instance).

 108  function VehicleManager:registerVehicle(vehicle)
 109      -- add this entry to vehicles list
 110      -- note: key is actually the vehicle value
 111      self.vehicles[vehicle.mainId or vehicle.id]     = vehicle;
 112      
 113      -- avoid double entries
 114      for n, vhc in ipairs(self.vehiclesByOrder) do
 115          if vehicle == vhc then
 116              return;
 117          end;
 118      end;
 119      
 120      table.insert(self.vehiclesByOrder, vehicle);
 121  end;
 122  

VehicleManager:registerVehicleRigidBody(vehicle, id)

 124  function VehicleManager:registerVehicleRigidBody(vehicle, id)
 125      self.vehiclesById[id]                   = vehicle;
 126  end;
 127  

VehicleManager:unregisterVehicleRigidBody(id)

 129  function VehicleManager:unregisterVehicleRigidBody(id)
 130      self.vehiclesById[id]                   = nil;
 131  end;
 132  

VehicleManager:getVehicleById(id)

Returns the vehicle to which the rigid body id id (transform id) belongs.

 135  function VehicleManager:getVehicleById(id)
 136      return self.vehiclesById[id];
 137  end;
 138  

VehicleManager:getOwnsVehicleOfType(vehicleType, contentPrefix)

Returns true if the player returns a vehicle of type vehicleType (string) coming from a mod with contentPrefix contentPrefix (string). Otherwise returns false.

 141  function VehicleManager:getOwnsVehicleOfType(vehicleType, contentPrefix)
 142      for k, v in ipairs(self.vehiclesByOrder) do
 143          if v.vehicleType == vehicleType or v.vehicleType == ("default." .. vehicleType) then
 144              return true;
 145          end;
 146          if contentPrefix ~= nil and v.vehicleType == (contentPrefix .. vehicleType) then
 147              return true;
 148          end;
 149      end;
 150      return false;
 151  end;
 152  

VehicleManager:unregisterVehicle(vehicle)

Unregisters the vehicle instance vehicle (table of the instance). This is called in Vehicle:destroy() (see Vehicle).

 155  function VehicleManager:unregisterVehicle(vehicle)
 156      -- delete this entry
 157      if vehicle.mainId ~= nil then
 158          self.vehicles[vehicle.mainId]       = nil;
 159      end;
 160      if vehicle.id ~= nil then
 161          self.vehicles[vehicle.id]           = nil;
 162      end;
 163      
 164      for n, vhc in ipairs(self.vehiclesByOrder) do
 165          if vehicle == vhc then
 166              table.remove(self.vehiclesByOrder, n);
 167              break;
 168          end;
 169      end;
 170  end;
 171  

VehicleManager:onEnterVehicle(vehicle)

Is called every time the player enters the vehicle vehicle (table of the instance).

 174  function VehicleManager:onEnterVehicle(vehicle)
 175      -- in case we are still sitting in another vehicle, we first need to leave that vehicle
 176      if self.currentVehicle ~= nil then
 177          -- this is just an additional sanity check that should not be in use after 21/09/2020 any more!
 178          self.currentVehicle:handleLeave(g_scenario.player, true);
 179      end;
 180      self.currentVehicle             = vehicle;
 181  
 182      -- reset player controller's parent
 183      if g_scenario.player ~= nil then
 184          g_scenario.player:setParent(0);
 185      end;
 186  
 187      -- micro lag: call this every now and then to refresh the snow system
 188      g_scenario:allowMicroLag();
 189  end;
 190  

VehicleManager:onLeaveVehicle(vehicle)

Is called every time the player leaves the vehicle vehicle (table of the instance).

 193  function VehicleManager:onLeaveVehicle(vehicle)
 194      if self.currentVehicle == vehicle then
 195          self.currentVehicle         = nil;
 196      end;
 197  end;
 198  

VehicleManager:switchVehicle(delta, player)

Is called every time the player wants to switch vehicles, e.g. by pressing the Tab key. delta (eiter larger 0 or less than 0). The function walks through all available vehicles in the given order and activates the next possible one.

If called on a client, the function will trigger a EventRequestSwitchVehicle, which will let the server execute the code.

 203  function VehicleManager:switchVehicle(delta, player)
 204      if g_scenario == nil then
 205          return;
 206      end;
 207  
 208      if g_isClient then
 209          EventRequestSwitchVehicle:send(delta);
 210          return;
 211      end;
 212      
 213      if not self.allowSwitchVehicle or not g_scenario.freeplayMode then
 214          return;
 215      end;
 216  
 217      -- nil means its the local player
 218      if player == nil then
 219          player                      = g_scenario.player;
 220  
 221          if g_GUI:getAnyGuiActive() or player == nil or player:isEditorActive() then
 222              return;
 223          end;
 224  
 225      end;
 226  
 227      -- this is a bit slow, but simpler in programming
 228      local currentIndex              = 0;
 229      local vehicleCount              = 0;
 230      local vehicleList               = {};
 231      
 232      for i, vehicle in ipairs(self.vehiclesByOrder) do
 233          
 234          -- count all vehicles that have driver seats
 235          if not vehicle.nonTabbable and (vehicle.driverSeat ~= nil or vehicle:getMayEnterOnAnySeat(player)) then
 236              vehicleCount            = vehicleCount + 1;
 237              table.insert(vehicleList, vehicle);
 238          end;
 239          
 240          -- determine current vehicle number in that list
 241          if vehicle:getIsEnteredAsPassenger(player) and not vehicle:getIsEntered(player) and vehicle:getMayEnter(player) then
 242              if vehicle:tryEnter(player) then
 243                  return;
 244              end;
 245  
 246          end;
 247          if vehicle:getIsEntered(player) or vehicle:getIsEnteredAsPassenger(player) then
 248              currentIndex            = vehicleCount;
 249          end;
 250      end;
 251      
 252      -- fix current index if we're not sitting in a vehicle
 253      if currentIndex == 0 then
 254          currentIndex                = ifelse(delta > 0, 0, 1);
 255      end;
 256  
 257      local i                         = 1;
 258      while i <= vehicleCount do
 259          -- get the index of the new vehicle
 260          local index                 = currentIndex + i * delta;
 261          while index <= 0 do
 262              --print("lower " .. index)
 263              index                   = index + vehicleCount;
 264          end;
 265          while index > vehicleCount do
 266              --print("raise " .. index)
 267              index                   = index - vehicleCount;
 268          end;
 269          
 270          local vehicle               = vehicleList[index];
 271  
 272          -- try to enter that vehicle
 273          if not vehicle.nonTabbable and (vehicle.driverSeat ~= nil or vehicle:getMayEnterOnAnySeat(player)) then
 274              -- jump into this vehicle, then quit
 275              if vehicle:tryEnter(player) then
 276                  return;
 277              end;
 278          end;
 279          
 280          i                           = i + 1;
 281      end;
 282  
 283      -- has not worked -> stay where you are
 284  end;
 285  

VehicleManager:update(...)

This is directly called by the game's update function. It distributes the update(dt) call to the currently active vehicle seat.

In Season 2, vehicles receive their update() event from the entity system and not from the Vehicle Manager any more.

 290  function VehicleManager:update(...)
 291      -- call this once per frame
 292      SnowmakingManager:preUpdate(...);
 293  
 294      -- switch vehicle function
 295      if InputMapper:getKeyDown(InputMapper.Vehicle_Switch_Inverse) then
 296          -- switch with inverse order
 297          self:switchVehicle(-1);
 298          
 299      elseif InputMapper:getKeyDown(InputMapper.Vehicle_Switch) then
 300          -- switch to next vehicle
 301          self:switchVehicle(1);
 302      end;
 303  
 304      if g_currentVehicleSeat ~= nil and g_currentVehicleSeat.update ~= nil then
 305          g_currentVehicleSeat:update(...);
 306      end;
 307  end;
 308  

VehicleManager:fixedUpdate(...)

This again is called directly by the game's fixedUpdate function. It always calls the active vehicle seat to allow for smooth camera control.

In Season 2, vehicles receive their fixedUpdate() event from the entity system and not from the Vehicle Manager any more.

 313  function VehicleManager:fixedUpdate(...)
 314      if g_currentVehicleSeat ~= nil and g_currentVehicleSeat.fixedUpdate ~= nil then
 315          g_currentVehicleSeat:fixedUpdate(...);
 316      end;
 317  end;

VehicleManager:spawnVehicle(typeName, x,y,z, rx,ry,rz, customizationName, color, isDummy)

Spawns a new vehicle of template name typeName (string) at position x,y,z (all float) with rotation rx,ry,rz (all float in degrees). In case the vehicle can be customized, the customization named customizationName (optional string) will be used.

 321  function VehicleManager:spawnVehicle(typeName, x,y,z, rx,ry,rz, customizationName, color, isDummy)
 322      -- parameters for Vehicle:new are returned by getVehicleParams
 323      local successful, params        = self:getVehicleParams(typeName, customizationName, isDummy, color);
 324      
 325      -- if the vehicle was not found, we need to return a nil value
 326      if not successful then
 327          return nil;
 328      end;
 329  
 330      -- create the vehicle instance
 331      local instance                  = Vehicle:new(unpack(params));
 332      instance.customColors           = color;
 333      -- spawn the vehicle
 334      instance:spawnAt(x,y,z, rx or 0, ry or 0, rz or 0);
 335      
 336      if not isDummy then
 337          -- now finally register
 338          instance:register();
 339      end;
 340  
 341      return instance;
 342  end;
 343  

VehicleManager:spawnDummyVehicle(typeName, x,y,z, rx,ry,rz, customizationName, customColor)

Spawns a new dummy vehicle of template name typeName (string) at position x,y,z (all float) with rotation rx,ry,rz (all float in degrees). In case the vehicle can be customized, the customization named customizationName (optional string) will be used. Dummy vehicles will not be functional or registered to any events (e.g. update events). They are used for example if a snow cannon is placed via the placing menu.

 347  function VehicleManager:spawnDummyVehicle(typeName, x,y,z, rx,ry,rz, customizationName, customColor)
 348      local vehicle                   = self:spawnVehicle(typeName, x,y,z, rx,ry,rz, customizationName, customColor, true);
 349  
 350      -- if we failed to load the vehicle, quit immediately
 351      if vehicle == nil then
 352          return nil;
 353      end;
 354  
 355      -- if there is a rigidbody, turn collision detection off
 356      if Rigidbody.isRigidbody(vehicle.mainId) then
 357          Rigidbody.setDetectCollisions(vehicle.mainId, false);
 358      end;
 359  
 360      -- disable all child colliders
 361      Rigidbody.disableAllColliders(vehicle.mainId);
 362  
 363      return vehicle;
 364  end;
 365  

VehicleManager:getVehicleParams(typeName, customizationName, isDummy, customColors)

Internal use only

 368  function VehicleManager:getVehicleParams(typeName, customizationName, isDummy, customColors)
 369      -- find the type's data table
 370      local dataTable                 = self:getDataTable(typeName, nil);
 371      
 372      if dataTable == nil then
 373          print("Error VehicleManager: attempt to spawn non-existing vehicle with template name " .. tostring(typeName) .. ". Make sure you've installed all mods that are used in this savegame.");
 374          return false;
 375      end;
 376  
 377      -- load the configuration
 378      local mod, bundleId             = ModLoader.getModByName(dataTable.modName);
 379  
 380      -- find the correct data table
 381      if dataTable.isCustomizable and type(customizationName) == "string" then
 382          local customDataTable       = dataTable.customizedDataTables[customizationName];
 383          if customDataTable ~= nil then
 384              -- this is indeed available
 385              dataTable               = customDataTable;
 386          else
 387              -- throw a warning message
 388              print("Warning in VehicleManager: attempt to spawn vehicle type '" .. tostring(typeName) .. "' in customization named '" .. tostring(customizationName) .. "'. This customization is not available. The vehicle will be loaded without any customization (might lead to unexpected results).");
 389          end;
 390      end;
 391  
 392      return true, { bundleId, typeName, dataTable, isDummy or false, customColors};
 393  end;
 394  

VehicleManager:getFallbackDatatable(typeName)

This function will be used to return the fallback datatable(saved in 'VehicleManager.vehicleFallbacks') for a vehicle, where the content name has changed but the old name is saved in savegame.

 397  function VehicleManager:getFallbackDatatable(typeName)
 398      local newTypeName               = VehicleManager.vehicleFallbacks[typeName];
 399      return self.vehicleTypes[newTypeName];
 400  end
 401  

VehicleManager:saveToTable()

Called directly by the scenario when the game is saved. The function passes the call on to each vehicle.

 404  function VehicleManager:saveToTable()
 405      local vehicles = {};
 406      for k, vehicle in ipairs(VehicleManager.vehiclesByOrder) do
 407          table.insert(vehicles, vehicle:saveToTable());
 408      end;
 409      return vehicles;
 410  end;
 411  

VehicleManager:loadFromTable(tbl)

Also called directly by the scenario when the game is loaded. The function spawns a new vehicle for each table entry and calls Vehicle:loadFromTable() on each vehicle.

 414  function VehicleManager:loadFromTable(tbl)
 415      if tbl == nil then return end;
 416      if g_isClient then return end;
 417      
 418      for k, vehicle in ipairs(tbl) do
 419          self:loadVehicleFromTable(vehicle);
 420      end;
 421  end;
 422  

VehicleManager:loadVehicleFromTable(tbl)

Loads a vehicle from a table.

 425  function VehicleManager:loadVehicleFromTable(tbl)
 426      if tbl == nil then return; end;
 427      if g_isClient then return; end;
 428  
 429      -- type name was called template name before 27/04/2020, but we still need to keep savegames compatible
 430      local vehicleType               = getNoNil(tbl.vehicleType, tbl.templateName);
 431      local vehicle                   = VehicleManager:spawnVehicle(vehicleType, tbl.px,tbl.py,tbl.pz, tbl.rx,tbl.ry,tbl.rz, tbl.customizationName, tbl.customColors, false);
 432  
 433      -- check this against nil (nil will be returned if the template is invalid)
 434      if vehicle ~= nil then
 435          vehicle:loadFromTable(tbl);
 436      end;
 437  
 438      return vehicle;
 439  end;
 440  

VehicleManager:reloadVehicle(vehicle)

Allows to reload a vehicle on-the-fly, thereby applying changes made to the data table during runtime (if available).

 443  function VehicleManager:reloadVehicle(vehicle)
 444      assert(g_isMaster, "Not allowed on network clients. Reload must be performed by host.");
 445      local tbl                       = vehicle:saveToTable();
 446      vehicle:onDestroy();
 447  
 448      return self:loadVehicleFromTable(tbl);
 449  end;
 450  

VehicleManager:addSpawnPosition(id, customVehicleRotation)

Permanently adds a spawn position to the game. Any time vehicles are bought or resetted, they will be placed on the first available spawn position.

 453  function VehicleManager:addSpawnPosition(id, customVehicleRotation)
 454      local pos                       = {};
 455      pos.startPosition               = VectorUtils.getWorldPosition(id);
 456      pos.endPosition                 = VectorUtils.getWorldPosition(getChildAt(id, 0));
 457      pos.width                       = (pos.endPosition - pos.startPosition):magnitude();
 458      pos.direction                   = (pos.endPosition - pos.startPosition):normalized();
 459  
 460      x,y,z                           = getWorldRotation(id);
 461      pos.ry                          = y;
 462  
 463      pos.vehicleRotation             = customVehicleRotation or y;
 464  
 465      table.insert(self.vehicleSpawnPositons, pos);
 466  end;
 467  

VehicleManager:newTempSpawnPosition(posBegin, posEnd, ry, customVehicleRotation)

Temporarily creates a new spawn position, e.g. if a tutorial mission is active.

 470  function VehicleManager:newTempSpawnPosition(posBegin, posEnd, ry, customVehicleRotation)
 471      local place                     = {};
 472      place.startPosition             = posBegin;
 473      place.endPosition               = posEnd;
 474      place.width                     = (posEnd - posBegin):magnitude();
 475      place.direction                 = (posEnd - posBegin):normalized();
 476  
 477      place.ry                        = ry or 0;
 478      place.vehicleRotation           = customVehicleRotation or place.ry;
 479  
 480      return place;
 481  end;
 482  

VehicleManager:addSpawnPositionOverride(place)

Temporarily adds a spawn position to the overrides. Any time a vehicle is bought or resetted, override spawn positions will be preferred over permanent spawn positions.

 485  function VehicleManager:addSpawnPositionOverride(place)
 486      if self.spawnPositionOverrides == nil then
 487          self.spawnPositionOverrides = {};
 488      end;
 489  
 490      table.insert(self.spawnPositionOverrides, place);
 491  end;
 492  

VehicleManager:cleanupSpawnPositionOverrides()

Removes any temporary spawn position overrides.

 495  function VehicleManager:cleanupSpawnPositionOverrides()
 496      self.spawnPositionOverrides     = nil;
 497  end;
 498  

VehicleManager:findPosition(width, length)

Returns the first suitable spawn position (spawn position overrides first, then permanent spawn positions).

 501  function VehicleManager:findPosition(width, length)
 502      local positions                 = {};
 503  
 504      if self.spawnPositionOverrides ~= nil then
 505          Utils.copyAndInsert(self.spawnPositionOverrides, positions);
 506      end;
 507      
 508      Utils.copyAndInsert(self.vehicleSpawnPositons, positions);
 509  
 510  
 511      local height                = 5;
 512      width, length               = width+2.5, length+1; -- leave a minimum gap
 513  
 514      for k, place in ipairs(positions) do
 515          -- do some box casts there
 516  
 517          for i=width/2, place.width-width/2, 1 do
 518              local p                 = place.startPosition + place.direction:multiply(i);
 519              p.y                     = Utils.sampleTerrainHeight(p.x, p.z) + height/2;
 520  
 521              local isFull            = Utils.checkBox(Vector3:new(p.x, p.y, p.z), Vector3:new(width, height, length), place.ry);
 522  
 523              if not isFull then
 524                  return p.x,p.y,p.z, place.vehicleRotation;
 525              end;
 526          end;
 527      end;
 528  
 529      if #positions <= 0 and g_scenario.player ~= nil and g_scenario.player.isActive then
 530          -- there are no spawn positions within the map!
 531          -- therefore spawn at player position
 532          local p                     = VectorUtils.getWorldPosition(g_scenario.player.transformId);
 533          p.y                         = Utils.sampleTerrainHeight(p.x, p.z) + height/2;
 534  
 535          local isFull                = Utils.checkBox(Vector3:new(p.x, p.y, p.z), Vector3:new(width, height, length), 0, (2^32) - 1 - 2^19 - 2^2);
 536  
 537          -- return this as backup position
 538          if not isFull then
 539              local rx,ry,rz          = getWorldRotation(g_scenario.player.transformId);
 540              return p.x,p.y,p.z, ry, true;
 541          end;
 542      end;
 543  
 544      -- nothing found if we actually arrive here (so nothing is returned)
 545  end;
 546  

VehicleManager:addMaintenanceExpenses(dayShare)

Charges maintenance expenses for all vehicles. The daily maintenance costs are multiplied by the factor dayShare (float, share of the day passed since the last call).

 549  function VehicleManager:addMaintenanceExpenses(dayShare)
 550      -- add maintenance cost for each vehicle
 551      for k, v in pairs(self.vehiclesByOrder) do
 552          local cost                  = v:getMaintenanceCost() or 0;
 553          g_scenario.accounting:addExpense("vehicles", -cost*dayShare);
 554      end;
 555  end;
 556  

VehicleManager:vehicleOutOfBounds(vehicle)

Gets called if vehicle (table of the vehicle instance) is out of bounds. (Added in Season 1 Update 7.1)

 559  function VehicleManager:vehicleOutOfBounds(vehicle)
 560      -- vehicle shouldn't be sold, if the cursor points outside the map
 561      if vehicle ~= nil then
 562      local soldFor               = vehicle:sell();
 563          
 564          if vehicle.dataTable ~= nil then
 565              vehicleName             = l10n.getDollar(vehicle.dataTable.title);
 566          end;
 567  
 568          g_scenario.notifications:add(Notifications.WARNING,
 569              l10n.format("msg_vehicleOutOfBounds_title", vehicleName),
 570              l10n.format("msg_vehicleOutOfBounds_desc", vehicleName, l10n.formatCurrencyAmount(soldFor, "float"))
 571          );
 572      end;
 573  end;
 574  

VehicleManager:loadCustomizations(typeName, dataTable)

Prepares the data tables for all customizations of vehicle type typeName (string) based on the raw data table dataTable (table).

 577  function VehicleManager:loadCustomizations(typeName, dataTable)
 578      if type(dataTable) ~= "table" and type(dataTable.customizations) ~= "table" then
 579          return;
 580      end;
 581      
 582      -- create copy of data table, because we don't want the customizations in the customized data table
 583      local dataTableCopy                     = TableUtil.deepCopy(dataTable);
 584      
 585      -- mark this as customizable
 586      dataTable.customizedDataTables          = {};
 587      dataTable.customizedDataTablesOrdered   = {};
 588      
 589      -- force this value to be nil
 590      dataTable.customizationName             = nil;
 591  
 592      -- get the bundle id
 593      local mod, bundleId             = ModLoader.getModByName(dataTable.modName);
 594  
 595      -- go through all available customizations
 596      for i, v in pairs(dataTable.customizations) do
 597          if type(v) ~= "table" then
 598              print("Error while loading vehicle type '" .. tostring(typeName) .. "': Invalid customization '" .. tostring(i) .. "', it is a " .. type(v) .. "value (table expected). Skipping this customization.");
 599  
 600          elseif type(v.customizationName) ~= "string" then
 601              print("Error while loading vehicle type '" .. tostring(typeName) .. "': each customization must have a customizationName (must be a string)! Skipping invalid customization.");
 602              
 603          elseif dataTable.customizedDataTables[v.customizationName] ~= nil then
 604              print("Error while loading vehicle type '" .. tostring(typeName) .. "': Customization name '".. tostring(v.customizationName) .. "' was used twice. Skipping invalid customization.");
 605  
 606          else
 607              -- everything is okay, let's load the customization
 608  
 609              -- v is the table that contains all changes to the original vehicle's dataTable
 610              -- create a new data table containing all information relevant to the vehicle
 611              local customDataTable           = self:constructCustomDataTable(TableUtil.deepCopy(dataTableCopy), v);
 612  
 613              -- force the correct content name
 614              customDataTable.contentName     = dataTable.contentName;
 615              customDataTable.customizations  = nil;
 616              customDataTable.originalDataTable   = dataTable;
 617  
 618              -- load a sprite if necessary
 619              if customDataTable.previewFilename ~= nil and customDataTable.previewFilename ~= dataTable.previewFilename then
 620                  customDataTable.previewSprite       = Utils.loadBundleSprite(bundleId, customDataTable.previewFilename);
 621              end;
 622   
 623              --set width, height, length to the customiziation 
 624              customDataTable.width                   = getNoNil(customDataTable.width,        2);
 625              customDataTable.height                  = getNoNil(customDataTable.height,       5);
 626              customDataTable.length                  = getNoNil(customDataTable.length,       2);
 627  
 628              -- note that customDataTable.customizationName was implicitly assigned! Yay!
 629              dataTable.customizedDataTables[v.customizationName] = customDataTable;
 630              table.insert(dataTable.customizedDataTablesOrdered, customDataTable);
 631  
 632              -- store the id inside the ordered table
 633              customDataTable.internalCustomizationId = #dataTable.customizedDataTablesOrdered;
 634          end;
 635      end;
 636  
 637      -- everything went well up to now, therefore enable customizing
 638      dataTable.isCustomizable                = true;
 639      -- the data table was changed by reference, so the return value does not need to be used
 640      return dataTable;
 641  end;
 642  

VehicleManager:constructCustomDataTable(dataTable, customDataTable)

Internal use only

 645  function VehicleManager:constructCustomDataTable(dataTable, customDataTable)
 646      if customDataTable == nil then
 647          return dataTable;
 648      end;
 649  
 650      -- custom data table is not nil, therefore we need to care about its data type
 651      if dataTable == nil or type(customDataTable) ~= "table" then
 652          return customDataTable;
 653      end;
 654  
 655      -- custom data table is a table, therefore we need to go through each item
 656      -- also, dataTable cannot be nil (since this was checked above already)
 657  
 658      for k, v in pairs(customDataTable) do
 659          dataTable[k]                = self:constructCustomDataTable(dataTable[k], v);
 660      end;
 661  
 662      return dataTable;
 663  end;
 664  

VehicleManager:getDataTable(vehicleType, contentPrefix)

Returns the dataTable (table) of vehicle type vehicleType (string) from a mod with content prefix contentPrefix (string). If the data table is not found, nil will be returned.

 667  function VehicleManager:getDataTable(vehicleType, contentPrefix)
 668      return Utils.getDataTable(VehicleManager.vehicleTypes, VehicleManager.vehicleFallbacks, vehicleType, contentPrefix);
 669  end;
 670  

VehicleManager:getVehicleTypeName(vehicleType, contentPrefix)

Returns the display name (string) of vehicle type vehicleType (string) from a mod with content prefix contentPrefix (string). If the data table is not found, nil will be returned.

 673  function VehicleManager:getVehicleTypeName(vehicleType, contentPrefix)
 674      if vehicleType == nil then
 675          return nil;
 676      end;
 677  
 678      local dataTable                 = VehicleManager:getDataTable(vehicleType, contentPrefix);
 679      if dataTable == nil then
 680          return nil;
 681      end;
 682      
 683      return l10n.getDollar(dataTable.title or "");
 684  end;

All contents of this page may be used for modding use for Winter Resort Simulator - Season 2 only. Any use exceeding this regulation is not permitted.

Copyright (C) HR Innoways, 2021. All Rights Reserved.