Админка.

This commit is contained in:
lopar 2022-02-13 01:50:04 +02:00
parent fdaadf69e6
commit 6509a796f6
2 changed files with 233 additions and 143 deletions

View File

@ -1,169 +1,117 @@
<?php
# Date: 12.02.2022 (20:33)
namespace Battles;
use SQLite3;
use Battles\Database\Db;
class Arena
{
public static Arena $current;
private $db;
private const DB_TEMPLATE = 'create table if not exists fighters (
uid integer not null,
strength integer not null,
dexterity integer not null,
intuition integer not null,
endurance integer not null,
intelligence integer not null,
wisdom integer not null,
accuracy integer not null,
evasion integer not null,
criticals integer not null,
health integer not null,
max_health integer not null,
mana integer not null,
max_mana integer not null,
melee_min integer not null,
melee_max integer not null,
teamid integer not null,
rowid integer not null,
turn_timeout integer)';
public const MELEE_ATTACK = 1;
public const RANGED_ATTACK = 2;
public const USE_MAGIC = 3;
public const MOVE = 4;
public const FLEE = 5;
public const PASS = 0;
private int $turn_timeout;
private int $fight_id;
private int $team_id;
public function __construct(SQLite3 $battleId)
function addNew(int $membersLimit = 5, int $groupsLimit = 2, int $startTime = 3)
{
//Придумать человеческий путь, чтобы не создавалось в папке с классами
$dbname = 'battle-' . $battleId . '.db';
if (!file_exists($dbname)) {
$this->createDb($dbname);
if (
$this->isOnArena() &&
$this->hasNoPendingFights() &&
$this->hasNoActiveFights() &&
in_array($startTime, [1,3,5,10])
) {
$query1 = 'insert into fights_pending (fight_id, start_time, members_limit, groups_limit) VALUES (?,?,?,?)';
$query2 = 'insert into fights_pending_users (fight_id, user_id, team_id) values (?,?,?)';
$startTime = strtotime("+{$startTime}minutes");
$uid = User::getInstance()->getId();
//последовательность важна!
Db::getInstance()->execute($query1, [$uid, $startTime, $membersLimit, $groupsLimit]);
Db::getInstance()->execute($query2, [$uid, $uid, 1]);
}
}
private function createDb($dbname)
function join(int $fight_id, int $team_id)
{
$this->db = new SQLite3($dbname);
$this->db->query(self::DB_TEMPLATE);
}
// array type: [[uid1,teamid1], [uid2,teamid2], ..., [uid_N,teamid_N]].
public function Init(array $fighters)
{
$init_db_query = 'create table if not exists fighters (
uid integer not null,
strength integer not null,
dexterity integer not null,
intuition integer not null,
endurance integer not null,
intelligence integer not null,
wisdom integer not null,
accuracy integer not null,
evasion integer not null,
criticals integer not null,
health integer not null,
max_health integer not null,
mana integer not null,
max_mana integer not null,
melee_min integer not null,
melee_max integer not null,
teamid integer not null,
rowid integer not null,
turn_timeout integer)';
$init_table_query = 'insert into fighters (
uid,
strength, dexterity, intuition, endurance, intelligence, wisdom,
accuracy, evasion, criticals,
health, max_health, mana, max_mana, melee_min, melee_max,
teamid, rowid)
values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
$stmt = $this->db->prepare($init_table_query);
foreach ($fighters as [$uid, $team]) {
$fighter = new UserStats($uid);
$stats = $fighter->getFullStats();
$stmt->bindValue(1, $fighter->getId());
$stmt->bindValue(2, $stats->strength);
$stmt->bindValue(3, $stats->dexterity);
$stmt->bindValue(4, $stats->intuition);
$stmt->bindValue(5, $stats->endurance);
$stmt->bindValue(6, $stats->intelligence);
$stmt->bindValue(7, $stats->wisdom);
$stmt->bindValue(8, $stats->accuracy);
$stmt->bindValue(9, $stats->evasion);
$stmt->bindValue(10, $stats->criticals);
$stmt->bindValue(11, $fighter->getHealth());
$stmt->bindValue(12, $fighter->getMaxHealth());
$stmt->bindValue(13, $fighter->getMana());
$stmt->bindValue(14, $fighter->getMaxMana());
$stmt->bindValue(15, $stats->min_physical_damage);
$stmt->bindValue(16, $stats->min_physical_damage);
$stmt->bindValue(17, $team);
$stmt->bindValue(18, 1);
$stmt->execute();
$this->fight_id = $fight_id;
$this->team_id = $team_id;
if (
$this->hasNoClanEnemies() &&
$this->hasFreeSpace() &&
$this->isOnArena() &&
$this->hasNoPendingFights() &&
$this->hasNoActiveFights()
) {
$query = 'insert into fights_pending_users (fight_id, user_id, team_id) values (?,?,?)';
Db::getInstance()->execute($query, [$fight_id, User::getInstance()->getId(), $team_id]);
}
}
public function playerTurn(int $action, int $uid): void
function leave()
{
// Перед ходом проверить, а жив ли ты вообще?
if (empty($this->turn_timeout)) {
$this->turn_timeout = $this->db->querySingle('select turn_timeout from fighters where uid = ' . $uid);
// чтобы не вылететь из заявки в момент начала поединка
if (
$this->hasNoActiveFights() &&
!$this->isFightStarter()
) {
Db::getInstance()->execute('delete from fights_pending_users where user_id = ?', User::getInstance()->getId());
}
$now = date('U');
}
/* select from last_turn_time and look at $now_plus_3_minutes - if ok, continue, if no, do nothing */
if ($now > $this->turn_timeout && !in_array($action, [self::MELEE_ATTACK, self::RANGED_ATTACK, self::USE_MAGIC, self::MOVE, self::PASS, self::FLEE])) {
$action = self::PASS;
$stmt_update_timer = $this->db->prepare('update fighters set last_turn_time = ? where uid = ?');
$stmt_update_timer->bindValue(1, date('U', strtotime('+3 minute')));
$stmt_update_timer->bindValue(2, $uid);
}
function getPendingList(): object
{
return new \stdClass();
/** !!PLACEHOLDER!! */
}
if ($action === self::MELEE_ATTACK) {
//Выполнимо только с клетки 1, только по вражеской клетке 1.
//Выполнимо по клетке 2, если клетка 1 пуста _у всех сторон_;
//Выполнимо по клетке 3, если клетка 2 пуста _у всех сторон_;
//Стоя на клетке 2 при пустой клетке 1 - атака невозможна!
echo 'Melee!';
}
public static function fight(): self
{
return new self();
}
if ($action === self::RANGED_ATTACK) {
//С клетки 1 атака на вражеские клетки 1 и 2;
//С клетки 2 атака на свою клетку 1 и вражескую клетку 1;
//С клетки 2 атака на вражескую 2, только если пустая клетка 1, либо нет клеток 1 _ни у одной из сторон_.
echo 'Ranged!';
// проверка на соклана
private function hasNoClanEnemies(): bool
{
$query = 'select user_id from fights_pending_users where fight_id = ? and team_id = ?';
$enemies = Db::getInstance()->ofetchAll($query, [$this->fight_id, $this->team_id]);
foreach ($enemies as $enemy) {
if (User::getInstance()->getClan() && User::getInstance()->getClan() === User::getInstance($enemy->user_id)->getClan()) {
return false;
}
}
return true;
}
if ($action === self::USE_MAGIC) {
//Достаёт кого угодно откуда угодно в любых обстоятельствах.
//ОЧЕНЬ внимательно проверять цель. Случайный хил трупа вызовёт апокалипсис в логике.
echo '!MAGIC!';
}
// проверка на переполнение
private function hasFreeSpace(): bool
{
$query = 'select members_limit, groups_limit from fights_pending where fight_id = ?';
$query2 = 'select count(*) from fights_pending_users where fight_id = ? and team_id = ?';
$limits = Db::getInstance()->ofetch($query, $this->fight_id);
$currentUsers = Db::getInstance()->fetchColumn($query2, [$this->fight_id, $this->team_id]);
return $limits->members_limit > $currentUsers && $limits->groups_limit >= $this->team_id;
}
if ($action === self::MOVE) {
//клетка 1 - ближний ряд, только шаг назад
//клетка 2 - средний ряд, вперёд или назад
//клетка 3 - тыл, только вперёд
//В момент хода при соблюдении условий удара может прилететь неблокируемая атака на расстоянии.
//Перемещение - это ручной гарантированный уворот от всех летящих физических атак.
//Перемещение на пустующую клетку 1 с клетки 2 - это ручной гарантированный уворот всех стоящих на клетке 2 от всех летящих немагических атак по всей клетке.
echo 'I have legs!!';
}
if ($action === self::FLEE) {
//побег из боя, только с клетки 3.
echo 'Help me, mommy!';
}
if ($action === self::PASS) {
//Пропуск хода.
echo 'I pass this turn.';
}
// проверка на нахождение в комнате (1 = арена)
private function isOnArena(): bool
{
return User::getInstance()->getRoom() === 1;
}
// ПИСАТЬ РЕЗУЛЬТАТ ХОДА ТОЛЬКО ПОСЛЕ ПОВТОРНОЙ ПРОВЕРКИ НА НАЛИЧИЕ ПРОТИВНИКА - ОН МОГ УСПЕТЬ ОТОЙТИ!
// !!ИЛИ УМЕРЕТЬ!!
$stmt_update_timer->execute();
// проверка на нахождение в другой заявке
public function hasNoPendingFights(): bool
{
$query = 'select count(*) from fights_pending_users where user_id = ?';
return Db::getInstance()->fetchColumn($query, User::getInstance()->getId()) > 0;
}
// проверка на нахождение в поединке
public function hasNoActiveFights(): bool
{
$query = 'select count(*) from fighters where user_id = ?';
return Db::getInstance()->fetchColumn($query, User::getInstance()->getId()) > 0;
}
// проверка на создателя поединка
private function isFightStarter(): bool
{
$query = 'select count(*) from fights_pending_users where user_id = fight_id and user_id = ?';
return Db::getInstance()->fetchColumn($query, User::getInstance()->getId()) > 0;
}
}

142
classes/Battles/Fight.php Normal file
View File

@ -0,0 +1,142 @@
<?php
namespace Battles;
use Battles\Database\Db;
class Fight
{
public static Fight $current;
private $db;
private \DateTimeImmutable $timer;
public const MELEE_ATTACK = 1;
public const RANGED_ATTACK = 2;
public const USE_MAGIC = 3;
public const MOVE = 4;
public const FLEE = 5;
public const PASS = 0;
private int $turn_timeout;
public function init($fighters)
{
$defaultRow = 2;
$defaultTimer = $this->timer->format('U');
$query = 'insert into fighters (
user_id,
strength,
dexterity,
intuition,
endurance,
intelligence,
wisdom,
accuracy,
evasion,
criticals,
health,
max_health,
mana,
max_mana,
melee_min,
melee_max,
battle_id,
team_id,
row_id,
turn_timeout
) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)';
$i = 1;
$mergedOptions = [];
foreach ($fighters as $fighter) {
$statsObj = new UserStats($fighter->user_id);
$stats = $statsObj->getFullStats();
$options[$i] = [
$fighter->user_id,
$stats->strength,
$stats->dexterity,
$stats->intuition,
$stats->endurance,
$stats->intelligence,
$stats->wisdom,
$stats->accuracy,
$stats->evasion,
$stats->criticals,
$statsObj->getHealth(),
$statsObj->getMaxHealth(),
$statsObj->getMana(),
$statsObj->getMaxMana(),
$stats->min_physical_damage,
$stats->max_physical_damage,
$fighter->fight_id,
$fighter->team_id,
$defaultRow,
$defaultTimer,
];
if ($i > 1) {
$query .= ', (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)';
$mergedOptions = array_merge_recursive($mergedOptions, $options[$i]);
}
$i++;
}
Db::getInstance()->execute($query, $mergedOptions);
}
public function playerTurn(int $action, int $uid): void
{
// Перед ходом проверить, а жив ли ты вообще?
if (empty($this->turn_timeout)) {
$this->turn_timeout = $this->db->querySingle('select turn_timeout from fighters where uid = ' . $uid);
}
$now = date('U');
/* select from last_turn_time and look at $now_plus_3_minutes - if ok, continue, if no, do nothing */
if ($now > $this->turn_timeout && !in_array($action, [self::MELEE_ATTACK, self::RANGED_ATTACK, self::USE_MAGIC, self::MOVE, self::PASS, self::FLEE])) {
$action = self::PASS;
$stmt_update_timer = $this->db->prepare('update fighters set last_turn_time = ? where uid = ?');
$stmt_update_timer->bindValue(1, date('U', strtotime('+3 minute')));
$stmt_update_timer->bindValue(2, $uid);
}
if ($action === self::MELEE_ATTACK) {
//Выполнимо только с клетки 1, только по вражеской клетке 1.
//Выполнимо по клетке 2, если клетка 1 пуста _у всех сторон_;
//Выполнимо по клетке 3, если клетка 2 пуста _у всех сторон_;
//Стоя на клетке 2 при пустой клетке 1 - атака невозможна!
echo 'Melee!';
}
if ($action === self::RANGED_ATTACK) {
//С клетки 1 атака на вражеские клетки 1 и 2;
//С клетки 2 атака на свою клетку 1 и вражескую клетку 1;
//С клетки 2 атака на вражескую 2, только если пустая клетка 1, либо нет клеток 1 _ни у одной из сторон_.
echo 'Ranged!';
}
if ($action === self::USE_MAGIC) {
//Достаёт кого угодно откуда угодно в любых обстоятельствах.
//ОЧЕНЬ внимательно проверять цель. Случайный хил трупа вызовёт апокалипсис в логике.
echo '!MAGIC!';
}
if ($action === self::MOVE) {
//клетка 1 - ближний ряд, только шаг назад
//клетка 2 - средний ряд, вперёд или назад
//клетка 3 - тыл, только вперёд
//В момент хода при соблюдении условий удара может прилететь неблокируемая атака на расстоянии.
//Перемещение - это ручной гарантированный уворот от всех летящих физических атак.
//Перемещение на пустующую клетку 1 с клетки 2 - это ручной гарантированный уворот всех стоящих на клетке 2 от всех летящих немагических атак по всей клетке.
echo 'I have legs!!';
}
if ($action === self::FLEE) {
//побег из боя, только с клетки 3.
echo 'Help me, mommy!';
}
if ($action === self::PASS) {
//Пропуск хода.
echo 'I pass this turn.';
}
// ПИСАТЬ РЕЗУЛЬТАТ ХОДА ТОЛЬКО ПОСЛЕ ПОВТОРНОЙ ПРОВЕРКИ НА НАЛИЧИЕ ПРОТИВНИКА - ОН МОГ УСПЕТЬ ОТОЙТИ!
// !!ИЛИ УМЕРЕТЬ!!
$stmt_update_timer->execute();
}
}