GitHub

Aliveskan Autopaa

A car dealership mod for My Winter Car built on MSCLoader. It adds a dealership building to the world and a public API so other mods can list cars for sale.

Note
This mod is a dependency. Players must install it before any car mod that registers vehicles at the dealership.

What it does

  • Spawns a functional dealership building near highway
  • Dealership.RegisterCar() so other mods can list cars for sale.
  • Each registered car is placed on a parking spot, made kinematic, and has its ignition FSMs disabled until purchased.
  • A window sticker is spawned on the car. Hovering it shows the car name and subtitle.
  • On purchase the car is unfrozen, the sticker is removed, and your onPurchase callback fires.

Installation

Requirements

  • MSCLoader 1.3.3 or newer

Steps

  1. Place Aliveskan_Autopaa.dll in Mods/.
  2. Place dealership.unity3d in Mods/Assets/Aliveskan_Autopaa/.
  3. Launch the game. The dealership appears automatically when a save is loaded.

Registering a Car

Call Dealership.RegisterCar() from your mod's OnLoad(). The dealership handles placement, sticker spawning, freeze state, and the purchase flow.

private void Mod_OnLoad()
{
    GameObject myCar = GameObject.Find("MYCAR");

    string texPath = Path.Combine(
        ModLoader.GetModAssetsFolder(this), "listing.png");

    Dealership.RegisterCar(
        mod:                  this,
        carID:                "mymod_mycar",
        carName:              "1994 Rivett Coupe",
        subtitleText:         "1994 Rivett Coupe - 45 000 mk",
        price:                45000f,
        listingTexturePath:   texPath,
        carObject:            myCar,
        lotRotation:          Quaternion.Euler(0f, -90f, 0f),
        stickerLocalPosition: new Vector3(0f, 0.6f, 0.42f),
        stickerLocalRotation: Quaternion.Euler(0f, 0f, 0f),
        stickerScaleX:        0.28f,
        stickerScaleY:        0.28f,
        onPurchase:           OnCarPurchased
    );
}

private void OnCarPurchased(ParkingSpot spot)
{
    Dealership.UnfreezeCarOnPurchase(myCar);
}

Sticker Positioning

The window sticker is parented to your car. You adjust its position, rotation, and scale through the parameters of RegisterCar().

ParameterTypeDescription
stickerLocalPositionVector3Position relative to the car root.
stickerLocalRotationQuaternionRotation relative to the car root.
stickerScaleXfloatHorizontal scale of the sticker quad.
stickerScaleYfloatVertical scale of the sticker quad.

Use a PNG with a transparent background so it blends with the glass, we reccomend Delicious Handrawn Font for custom text.

Freeze and Ignition Lock

The dealership automatically freezes registered cars and locks their ignition on load. You are responsible for calling the unfreeze helper when the player buys the car.

What happens automatically

  • When RegisterCar() is called, the car is moved to its spot, set kinematic, and its Starter, Engine, and Ignition PlayMaker FSMs are disabled.
  • After all mods finish loading, PostLoadFlush() re-applies the freeze and ignition lock to all unsold registered cars.

What you must do

Call this inside your onPurchase callback:

Dealership.UnfreezeCarOnPurchase(myCar);
Warning
If you do not call UnfreezeCarOnPurchase() the car stays frozen after purchase and the player cannot drive it.

Manual helpers

Both helpers can be called at any time outside of the purchase flow:

Dealership.FreezeCarForSale(car);
Dealership.UnfreezeCarOnPurchase(car);

FSMs that are locked

The lock disables every PlayMakerFSM on the car (including children) whose FsmName is one of:

  • Starter
  • Engine
  • Ignition

If your car uses different FSM names for its start logic, disable and re-enable those yourself in addition to calling the helpers.

Purchase Callback

The onPurchase delegate fires the moment a player confirms a purchase. Its signature is:

Action<ParkingSpot> onPurchase

The ParkingSpot argument is the spot the car was on. You can read its WorldPosition or SpotIndex if needed.

private void OnCarPurchased(ParkingSpot spot)
{
    Dealership.UnfreezeCarOnPurchase(myCar);
    GiveKeyToPlayer();
    ModConsole.Log("sold at spot " + spot.SpotIndex);
}

Dealership.RegisterCar

public static DealerListing RegisterCar(
    Mod                 mod,
    string              carID,
    string              carName,
    string              subtitleText,
    float               price,
    string              listingTexturePath,
    GameObject          carObject,
    Quaternion          lotRotation,
    Vector3             stickerLocalPosition,
    Quaternion          stickerLocalRotation,
    float               stickerScaleX,
    float               stickerScaleY,
    Action<ParkingSpot> onPurchase
)

Registers a car for sale at the dealership.

ParameterTypeRequiredDescription
modModYesYour mod instance (this). Used for the mod ID.
carIDstringYesUnique identifier for this car. Use a namespaced string like "mymod_mycar".
carNamestringYesDisplay name shown in GUIinteraction when hovering the sticker.
subtitleTextstringYesCaption text shown below the crosshair when the player looks at the sticker.
pricefloatYesPrice in markka. Deducted from PlayerMoney on purchase.
listingTexturePathstringYesAbsolute path to a PNG used as the sticker texture.
carObjectGameObjectYesThe car root. Moved to the parking spot immediately on registration.
lotRotationQuaternionYesWorld rotation the car will have when parked on the lot.
stickerLocalPositionVector3YesLocal position of the sticker quad relative to the car root.
stickerLocalRotationQuaternionYesLocal rotation of the sticker quad.
stickerScaleXfloatYesHorizontal scale of the sticker quad.
stickerScaleYfloatYesVertical scale of the sticker quad.
onPurchaseAction<ParkingSpot>YesCallback fired when the player buys the car. Call UnfreezeCarOnPurchase() here.

Returns a DealerListing reference, or null if validation failed. Check the MSCLoader console for error messages.

Dealership.FreezeCarForSale

public static void FreezeCarForSale(GameObject car)

Sets isKinematic = true on the car's Rigidbody and disables its Starter, Engine, and Ignition PlayMaker FSMs. Called automatically by RegisterCar() and PostLoadFlush(). Call manually if you need to re-freeze the car at a later point.

ParameterTypeDescription
carGameObjectThe car root GameObject.

Dealership.UnfreezeCarOnPurchase

public static void UnfreezeCarOnPurchase(GameObject car)

Sets isKinematic = false and re-enables the Starter, Engine, and Ignition FSMs. Call this inside your onPurchase callback.

ParameterTypeDescription
carGameObjectThe car root GameObject.

Dealership.GetListings

public static List<DealerListing> GetListings()

Returns all registered DealerListing objects, including sold ones. Use this if you need to read the current inventory from another mod.

DealerListing

Data class representing one car for sale. Returned by RegisterCar().

FieldTypeDescription
ModIDstringID of the mod that registered this car.
CarIDstringUnique car identifier.
CarNamestringDisplay name.
SubtitleTextstringYellow GUI caption text.
PricefloatPrice in markka.
ListingTextureTexture2DLoaded sticker texture.
CarObjectGameObjectThe car root GameObject.
LotRotationQuaternionRotation the car has when parked on the lot.
StickerLocalPositionVector3Local position of the sticker.
StickerLocalRotationQuaternionLocal rotation of the sticker.
StickerScaleXfloatHorizontal scale of the sticker.
StickerScaleYfloatVertical scale of the sticker.
SpotIndexintIndex of the assigned parking spot (0 to 9). Assigned automatically. you cannot choose it.
Purchasedbooltrue after the player has bought this car.
OnPurchaseAction<ParkingSpot>Your purchase callback.

ParkingSpot

MonoBehaviour attached to each numbered spot transform in the dealership prefab.

MemberTypeDescription
SpotIndexintZero-based index of this spot (0 to 9).
ListingDealerListingThe listing assigned to this spot, or null if empty.
WorldPositionVector3World position of the spot transform.
IsOccupiedbooltrue if a listing is assigned to this spot.

FAQ

My car falls through the floor on load.
Call RegisterCar() from OnLoad(). The dealership freezes cars at load time but only the ones it knows about. If your car is not in the hardcoded freeze list, add a kinematic lock in your own PreLoad() by calling FreezeCarForSale() there. Then call RegisterCar() in OnLoad() as normal.
The sticker does not appear on the car.
Check that listingTexturePath points to a PNG that exists on disk. Check the MSCLoader console for a warning from [Aliveskan]. If the path is correct but the sticker is blank, make sure the PNG is in RGBA format and is not corrupted.
The player can still start the car before buying it.
The ignition lock only targets FSMs named Starter, Engine, or Ignition. If your car uses different FSM names for its start logic, disable those FSMs yourself in OnLoad() and re-enable them in your onPurchase callback.
The car is still frozen after the player buys it.
Call Dealership.UnfreezeCarOnPurchase(myCar) inside your onPurchase callback. The dealership does not call this for you.