DK2/src/models/char.php

182 lines
6.3 KiB
PHP

<?php
/*
Players are the living, breathing entities that interact with the game world. They are inextricably linked to their
accounts, and are the primary means by which the player interacts with the game world. Separating the player from
the account allows for multiple players to be associated with a single account, and to prevent concurrency issues
when performing auth checks on the database.
When creating a player, we want to init all of the related data tables; wallets, inventory, bank, etc.
When retrieving a player, we will get the tables as-needed, to prevent allocating more memory than we need.
*/
const currently = [
0 => 'Exploring',
1 => 'In Town',
2 => 'In Combat',
4 => 'In Shop',
5 => 'In Inn'
];
/**
* Create a player. Only a user ID and a name are required. All other fields are optional. Pass a key-value array
* of overrides to set additional fields. A player's name must be unique, but this function does not check for
* that. Returns the created player's ID.
*/
function char_create(int $user_id, string $name, array $overrides = []): int
{
// Prep the data and merge in any overrides
$data = ['user_id' => $user_id, 'name' => $name];
if (!empty($overrides)) $data = array_merge($data, $overrides);
// Prep the fields for the query
$k = array_keys($data);
$f = implode(', ', $k);
$v = implode(', ', array_map(fn($x) => ":$x", $k));
// Create the player!
if (db_query(db_live(), "INSERT INTO characters ($f) VALUES ($v)", $data) === false) {
// @TODO: Log this error
throw new Exception('Failed to create player.');
}
// Get the player ID
return db_live()->lastInsertRowID();
}
/**
* Create a player's location record. A player's location is where they are in the game world. A player can only be
* in one location at a time. Can define a starting location for the player. Default state is 'Exploring'.
*/
function char_location_create(int $char_id, int $x = 0, int $y = 0, int $currently = 0): void
{
if (db_query(db_live(), "INSERT INTO char_locations (char_id, x, y, currently) VALUES (:p, :x, :y, :c)", [
':p' => $char_id,
':x' => $x,
':y' => $y,
':c' => $currently
]) === false) {
throw new Exception('Failed to create player location.');
}
}
/**
* Creates a player's wallet. A player's wallet is where they store their currencies. Can optionally specify the
* starting balances of the wallet. Returns the created wallet's ID. If a currency is set to -1, the starting_silver
* or starting_star_gems fields from the env will be used.
*/
function char_wallet_create(int $char_id, int $silver = -1, int $starGems = -1): void
{
if (db_query(db_live(), "INSERT INTO char_wallets (char_id, silver, stargem) VALUES (:p, :s, :sg)", [
':p' => $char_id,
':s' => $silver === -1 ? env('start_silver', 10) : $silver,
':sg' => $starGems === -1 ? env('start_star_gems', 0) : $starGems
]) === false) {
throw new Exception('Failed to create player wallet.');
}
}
/**
* Create the player's gear table. A player's gear is where they store their equipped items.
* @TODO: implement initial gear
*/
function char_gear_create(int $char_id, array $initialGear = []): void
{
if (db_query(db_live(), "INSERT INTO char_gear (char_id) VALUES (:p)", [':p' => $char_id]) === false) {
throw new Exception('Failed to create player gear.');
}
}
/**
* Create the player's bank account. The bank stores items and currency, with an interest rate based on
* the bank account's tier. The bank account has a limited number of slots, which can be increased by upgrading
* the bank account. The bank account starts with 0 silver and 5 slots.
*/
function char_bank_create(int $char_id, int $slots = 5, int $silver = 0, int $tier = 0): void
{
if (db_query(db_live(), "INSERT INTO char_banks (char_id, slots, silver, tier) VALUES (:p, :s, :si, :t)", [
':p' => $char_id,
':s' => $slots,
':si' => $silver,
':t' => $tier
]) === false) {
throw new Exception('Failed to create player bank.');
}
}
/**
* Get a charcter by their ID. Returns the character's data as an associative array.
*/
function char_find(int $char_id): array
{
$char = db_query(db_live(), "SELECT * FROM characters WHERE id = :id", [':id' => $char_id])->fetchArray(SQLITE3_ASSOC);
if ($char === false) throw new Exception('Character not found.');
return $char;
}
/**
* Count the number of players associated with an account ID.
*/
function char_count(int $user_id): int
{
$count = db_query(db_live(), "SELECT COUNT(*) FROM characters WHERE user_id = :u", [':u' => $user_id])->fetchArray(SQLITE3_NUM);
if ($count === false) throw new Exception('Failed to count players.');
return (int) $count[0];
}
/**
* Get a an array of id => [name, level] for all players associated with an account ID.
*/
function char_list(int $user_id): array
{
$stmt = db_query(db_live(), "SELECT id, name, level FROM characters WHERE user_id = :u", [':u' => $user_id]);
if ($stmt === false) throw new Exception('Failed to list players.');
$players = [];
while ($row = $stmt->fetchArray(SQLITE3_ASSOC)) {
$players[$row['id']] = ['name' => $row['name'], 'level' => $row['level']];
}
return $players;
}
/**
* Get a player's location info by their player ID. Returns the location's data as an associative array.
*/
function char_get_location(int $char_id): array
{
// Get the location
$location = db_query(db_live(), "SELECT * FROM char_locations WHERE char_id = :p", [':p' => $char_id])->fetchArray(SQLITE3_ASSOC);
if ($location === false) throw new Exception('Location not found.');
return $location;
}
/**
* Get a player's wallet by their player ID. Returns the wallet's data as an associative array.
*/
function char_get_wallet(int $char_id): array
{
$wallet = db_query(db_live(), "SELECT * FROM char_wallets WHERE char_id = :p", [':p' => $char_id])->fetchArray(SQLITE3_ASSOC);
if ($wallet === false) throw new Exception('Wallet not found.');
return $wallet;
}
/**
* See if a player name exists.
*/
function char_nameExists(string $name): bool
{
$exists = db_query(db_live(), "SELECT COUNT(*) FROM characters WHERE name = :n", [':n' => $name])->fetchArray(SQLITE3_NUM);
if ($exists === false) throw new Exception('Failed to check for player name.');
return (int) $exists[0] > 0;
}
/**
* Checks whether a character exists at a certain ID.
*/
function char_exists(int $char_id): bool
{
return db_exists(db_live(), 'characters', 'id', $char_id);
}