Personal carts
A free cart is a wagon with two horses - or a two-wheeled cart with one - that stands where it was put until a player takes the reins at its bench. Then their game drives it - W trots, W with Shift held canters, S brakes and backs up, A / D steer - and everyone sees it move; a wall, a tree or another cart in the way stops the horses. Other players get on beside the driver or in the back with the game’s own prompt (“Get on”) and off with the game’s dismount key. The carts that drive a road by themselves are the other half of the carts: the routes guide.
The server does the driving, the seats and the looks; the game mode decides everything else - who may drive which cart, what it looks like, what it costs, and whether it is still there after the player’s next login.
Putting a cart down
Section titled “Putting a cart down”A cart is of one of two kinds:
| Kind | What it is |
|---|---|
wagon |
four wheels, two horses at the pole, a bench and a bed behind it - six seats |
cart |
the game’s two-wheeled cart: one horse between its shafts, the driver on the bed’s front edge, a passenger on each side rail - three seats |
An admin’s /cart (or /cart cart for a two-wheeler) puts a free cart 4.5 m ahead, across their way with the bench at their
right hand; /cart remove takes away the free cart nearest them. A mode uses
CreateCart - with the cart’s parts if it should not look like the default one - and
DestroyEntity; GetEntityTemplate
answers a cart’s kind:
-- a covered wagon full of sacks, 4 m ahead of the player, across their waylocal x, y, z = GetPlayerPos(pid)local r = math.rad(GetPlayerYaw(pid))local cart = CreateCart("wagon", x - math.sin(r) * 4, y + math.cos(r) * 4, z, GetPlayerYaw(pid) + 90, nil, {body = "b_covered", axle = "b_covered", load = "sacks"})-- a peddler's two-wheeler with a market load behind a palominolocal peddler = CreateCart("cart", x + 6, y, z, 0, nil, {load = "market", horse1 = "palomino"})How fast a player may drive is [carts] drive_speed (server settings), one
cart’s own with SetCartSpeed.
The seats
Section titled “The seats”| Seat | On a wagon | On a two-wheeler |
|---|---|---|
0 |
at the reins - the driver | at the reins, on the bed’s front edge |
1 |
the bench beside the driver | the right side rail, behind the wheel |
2, 3 |
the back of the bed, right and left | 2: the left side rail |
4, 5 |
the bed ahead of them, right and left | - |
The bench’s prompt gives the reins of a cart nobody drives, else the seat beside them (a side rail on a two-wheeler); the
bed’s prompt a seat in the back on the player’s side. The mode sees and moves every seat: GetCartSeatPlayer
says who sits where, SetPlayerCartSeat moves a seated player (to the reins
too), SetCartSeatLocked keeps a seat from the prompt, and
OnPlayerEnterCart may keep a player out or seat them elsewhere. The shipped
modes give every player /seat (who sits where) and /seat <n> (move there).
What a cart is made of
Section titled “What a cart is made of”A wagon is the game’s own parts, and the game builds every one of its wagons on the same chassis - so any body goes with any front axle, wheels and load. Each slot holds one part; a slot the mode never set shows the default (the first named below). A change shows on every screen at once, while the cart drives too. A wagon’s slots:
| Slot | Parts |
|---|---|
body |
the game’s three wagons: a (the default), b (boards lying in its bed), b_plain (the same, its bed empty), c (long, with ladder sides); a_covered, b_covered, c_covered - under a canvas cover |
axle |
b (the default), b_covered - the front axle with the pole |
wheels |
b_covered (the default), b, polygonal (rough-hewn) |
load |
none (the default), sacks, charcoal, carpets (cloth, rolls of fabric, crates), stones, hay_small, hay_medium, hay_large, goods (sacks, crates, baskets, a barrel), junk (hides, chains, shackles, rotten apples …), cabbage |
horse1, horse2 |
the horses’ coats (left, right): black, bay_dun, chestnut, light_grey, buckskin, palomino, seal_brown, dark_grey, red_roan, brown - unset, each cart has a pair of its own |
The two-wheeler is one body with its shafts, so it has fewer slots:
| Slot | Parts |
|---|---|
body |
b - the only one |
wheels |
b - the only one |
load |
none (the default), goods (barrels, a basket, sacks), market (baskets and a barrel), sacks, cabbage (wicker sides full of cabbages) |
horse1 |
the horse’s coat, the same names as a wagon’s |
The functions: SetCartPart and SetCartParts
change them, GetCartPart and GetCartParts
read them - in any callback too - and GetCartPartSlots /
GetCartPartNames list the catalogue of a kind for a shop’s menu (a slot
the kind has not is refused). An admin’s /cart parts lists the nearest cart’s in the chat and /cart part <slot> <part>
changes it.
A load is a look: the sacks and the hay take no room from the seats in the back. A mode that fills a cart with hay can keep
the back seats from the prompt with SetCartSeatLocked.
A cart dealer
Section titled “A cart dealer”A dealer sells carts, the buyer’s own from then on: nobody else takes its reins, anyone may ride along. The whole of it in Lua (the prices are the mode’s):
CART_OWNER = {} -- cart id -> the player who bought itPLAYER_CART = {} -- player id -> their cartlocal MODELS = { peddler = {price = 150, kind = "cart", parts = {load = "market"}}, farmer = {price = 300, kind = "wagon", parts = {body = "c", wheels = "polygonal"}}, merchant = {price = 800, kind = "wagon", parts = {body = "b_covered", axle = "b_covered", wheels = "b"}},}
-- /buycart peddler | farmer | merchant: the cart 4 m ahead, its reins kept for the buyerfunction buyCart(pid, model) local m = MODELS[model] if not m then SendClientMessage(pid, COLOR_WHITE, "The dealer sells: peddler (150), farmer (300), merchant (800).") return end if PLAYER_CART[pid] then SendClientMessage(pid, COLOR_RED, "You have a cart already.") return end if GetPlayerMoney(pid) < m.price then SendClientMessage(pid, COLOR_RED, "That is " .. m.price .. " Groschen.") return end local x, y, z = GetPlayerPos(pid) local r = math.rad(GetPlayerYaw(pid)) local cart = CreateCart(m.kind, x - math.sin(r) * 4, y + math.cos(r) * 4, z, GetPlayerYaw(pid) + 90, nil, m.parts) if not cart then return end GivePlayerMoney(pid, -m.price) SetCartSeatLocked(cart, 0) -- the bench's prompt offers a seat, not the reins ... CART_OWNER[cart], PLAYER_CART[pid] = pid, cartend
-- ... and the owner at the bench (at either side of a two-wheeler) is seated at the reinsfunction OnPlayerEnterCart(pid, id, seat) local bench = seat == 1 or GetEntityTemplate(id) == "cart" if CART_OWNER[id] == pid and bench and not GetCartSeatPlayer(id, 0) then return 0 end return trueendA cartwright
Section titled “A cartwright”A cartwright does up the player’s own cart for a price: a covered body, other wheels, a load, other horses.
local WORK = {body = 150, axle = 40, wheels = 60, load = 20, horse1 = 100, horse2 = 100}
-- /cartwright <slot> <part>, next to your own cartfunction cartwright(pid, slot, part) local cart = PLAYER_CART[pid] local cx, cy = GetEntityPos(cart or -1) local px, py = GetPlayerPos(pid) if not cx or (cx - px) ^ 2 + (cy - py) ^ 2 > 10 * 10 then SendClientMessage(pid, COLOR_RED, "Bring your cart here.") return end local kind = GetEntityTemplate(cart) local names = GetCartPartNames(slot, kind) if not WORK[slot] or #names == 0 then SendClientMessage(pid, COLOR_WHITE, table.concat(GetCartPartSlots(kind), ", ")) return end if not part then SendClientMessage(pid, COLOR_WHITE, table.concat(names, ", ")) return end if GetCartPart(cart, slot) == part then return end if GetPlayerMoney(pid) < WORK[slot] then SendClientMessage(pid, COLOR_RED, "That is " .. WORK[slot] .. " Groschen.") return end if SetCartPart(cart, slot, part) then GivePlayerMoney(pid, -WORK[slot]) else SendClientMessage(pid, COLOR_RED, "No such " .. slot .. ".") endendKeeping a player’s cart
Section titled “Keeping a player’s cart”The server forgets a cart when it stops, and a mode’s tables when it reloads - what a player owns is the mode’s to keep, in
its database: the parts (GetCartParts(cart) is a plain table of slot names) and where the cart stood
(GetEntityPos). At the player’s next login CreateCart with those parts brings
it back; at their disconnect the mode saves it and takes it away (DestroyEntity) or leaves it standing - a cart left
standing is anyone’s to drive unless its reins stay locked.
