A CC:Tweaked peripheral block that reads Create: Numismatics cards. When a player right-clicks the block with a card, it captures the card data and fires a card_scanned event to all attached computers.
Peripheral Type
ptr_utilities:card_reader
Setup
- Craft a Card Reader (shapeless: any Numismatics card + railway casing + bank terminal)
- Place it next to a CC:Tweaked computer
- Wrap it:
local reader = peripheral.find("ptr_utilities:card_reader")
The player who places a Card Reader becomes its owner; only the owner (or creative/admin players) can break it or wrench it off.
How Card Scanning Works
A player walks up to the block and right-clicks it while holding a Numismatics card. The block captures the card data in memory (not persisted to disk), creates a short-lived banking session, and fires a card_scanned event.
Card data is lost on chunk unload or server restart.
Events
card_scanned
Fired when a player scans a card at the reader.
local event, data = os.pullEvent("card_scanned")
-- data is a table with:
-- data.type = "bank" | "authorized" | "id"
-- data.accountID = UUID string (for bank/authorized cards)
-- data.authorizationID = UUID string (for authorized cards only)
-- data.playerID = UUID string (for ID cards only)
-- data.scannedBy = UUID string of the player who scanned
-- data.scannedByName = name of the player who scanned
-- data.sessionID = UUID string of the banking session
-- data.sessionExpiresAt = unix timestamp when session expires
-- data.terminalID = UUID string of this card reader terminal
Methods
Card & Session Data
| Method | Returns | Description |
|---|---|---|
getCardData() | table | Returns all current card data + session info. Keys: type, accountID, authorizationID, playerID, scannedBy, scannedByName, timestamp, terminalID, sessionID, sessionExpiresAt, sessionConsumed. |
getAccountID() | string|nil | The scanned card’s account UUID. |
getAuthorizationID() | string|nil | The scanned authorized card’s sub-account UUID. |
getSessionID() | string|nil | The current banking session UUID. |
getTerminalID() | string | This reader’s unique terminal UUID (persisted across restarts). |
clear() | void | Clears all scanned card data and the current session. |
Bank Queries (read-only, no card required)
These query the global Numismatics bank directly. No card scan needed.
| Method | Returns | Description |
|---|---|---|
getAccounts() | string[] | All bank account UUIDs. |
getBalance(accountID) | int | Balance in spurs. |
getAccountLabel(accountID) | string|nil | Display name of the account. |
accountExists(accountID) | boolean | Whether the account exists. |
isPlayerOwned(accountID) | boolean | true if player account, false if blaze banker. |
isAuthorized(accountID, playerUUID) | boolean | Whether the player is authorized to use the account. |
getTrustList(accountID) | string[]|nil | Player UUIDs on the account’s trust list (blaze bankers only). |
getAccountInfo(accountID) | table | Detailed info: id, isPlayerOwned, balance, displayName, trustList, trustListSize. |
getAuthorizedAccounts(playerUUID) | string[] | All accounts a player is authorized to use. |
Transfer (requires card scan)
| Method | Returns | Description |
|---|---|---|
transfer(toAccountID, amount) | table | Transfers funds from the scanned account to toAccountID. Requires an active session (card scanned). Session is consumed after successful transfer. |
Routing depends on the scanned card:
- Plain bank card / ID card → direct
deduct/depositthrough this mod, only whensecurity.allowUnrestrictedTransfers=trueinconfig/ptr_utilities-server.toml(defaultfalse, which rejects with “Transfers require an Authorized Card”). - Authorized card → Numismatics sub-account flow (authorization type + spend limit enforced by Numismatics).
Transfer receipt format:
{
transactionID = "uuid",
operation = "transfer",
account = "from-account-uuid",
source = "from-account-uuid",
destination = "to-account-uuid",
amount = 640,
timestamp = 1234567890,
mac = "hmac-string"
}
Sessions
When a card is scanned, a session is created:
- Tied to the terminal (not the computer)
- Expires after 60 seconds
- Consumed after a successful transfer
- Cannot be reused once consumed
Check session status via getCardData() — the sessionConsumed and sessionExpiresAt fields tell you if the session is still usable.
Example: Wait for card, then transfer
local reader = peripheral.find("ptr_utilities:card_reader")
print("Waiting for card...")
local event, data = os.pullEvent("card_scanned")
print("Card scanned by " .. data.scannedByName)
print("Account: " .. (data.accountID or "none"))
if data.type == "bank" or data.type == "authorized" then
local balance = reader.getBalance(data.accountID)
print("Balance: " .. balance .. " spurs")
-- Transfer 100 spurs to another account
local receipt = reader.transfer("destination-account-uuid", 100)
print("Transfer OK: " .. textutils.serialize(receipt))
end
Coin Denominations
| Coin | Spurs |
|---|---|
| Spur | 1 |
| Bevel | 8 |
| Sprocket | 16 |
| Cog | 64 |
| Crown | 512 |
| Sun | 4096 |