Админка.

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 <?php
# Date: 12.02.2022 (20:33)
namespace Battles; namespace Battles;
use SQLite3; use Battles\Database\Db;
class Arena class Arena
{ {
public static Arena $current; private int $fight_id;
private $db; private int $team_id;
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;
public function __construct(SQLite3 $battleId) function addNew(int $membersLimit = 5, int $groupsLimit = 2, int $startTime = 3)
{ {
//Придумать человеческий путь, чтобы не создавалось в папке с классами if (
$dbname = 'battle-' . $battleId . '.db'; $this->isOnArena() &&
if (!file_exists($dbname)) { $this->hasNoPendingFights() &&
$this->createDb($dbname); $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->fight_id = $fight_id;
$this->db->query(self::DB_TEMPLATE); $this->team_id = $team_id;
} if (
$this->hasNoClanEnemies() &&
// array type: [[uid1,teamid1], [uid2,teamid2], ..., [uid_N,teamid_N]]. $this->hasFreeSpace() &&
public function Init(array $fighters) $this->isOnArena() &&
{ $this->hasNoPendingFights() &&
$init_db_query = 'create table if not exists fighters ( $this->hasNoActiveFights()
uid integer not null, ) {
strength integer not null, $query = 'insert into fights_pending_users (fight_id, user_id, team_id) values (?,?,?)';
dexterity integer not null, Db::getInstance()->execute($query, [$fight_id, User::getInstance()->getId(), $team_id]);
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();
} }
} }
public function playerTurn(int $action, int $uid): void function leave()
{ {
// Перед ходом проверить, а жив ли ты вообще? // чтобы не вылететь из заявки в момент начала поединка
if (empty($this->turn_timeout)) { if (
$this->turn_timeout = $this->db->querySingle('select turn_timeout from fighters where uid = ' . $uid); $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 */ function getPendingList(): object
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; return new \stdClass();
$stmt_update_timer = $this->db->prepare('update fighters set last_turn_time = ? where uid = ?'); /** !!PLACEHOLDER!! */
$stmt_update_timer->bindValue(1, date('U', strtotime('+3 minute'))); }
$stmt_update_timer->bindValue(2, $uid);
}
if ($action === self::MELEE_ATTACK) { public static function fight(): self
//Выполнимо только с клетки 1, только по вражеской клетке 1. {
//Выполнимо по клетке 2, если клетка 1 пуста _у всех сторон_; return new self();
//Выполнимо по клетке 3, если клетка 2 пуста _у всех сторон_; }
//Стоя на клетке 2 при пустой клетке 1 - атака невозможна!
echo 'Melee!';
}
if ($action === self::RANGED_ATTACK) { // проверка на соклана
//С клетки 1 атака на вражеские клетки 1 и 2; private function hasNoClanEnemies(): bool
//С клетки 2 атака на свою клетку 1 и вражескую клетку 1; {
//С клетки 2 атака на вражескую 2, только если пустая клетка 1, либо нет клеток 1 _ни у одной из сторон_. $query = 'select user_id from fights_pending_users where fight_id = ? and team_id = ?';
echo 'Ranged!'; $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) { // проверка на переполнение
//Достаёт кого угодно откуда угодно в любых обстоятельствах. private function hasFreeSpace(): bool
//ОЧЕНЬ внимательно проверять цель. Случайный хил трупа вызовёт апокалипсис в логике. {
echo '!MAGIC!'; $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 = арена)
//клетка 1 - ближний ряд, только шаг назад private function isOnArena(): bool
//клетка 2 - средний ряд, вперёд или назад {
//клетка 3 - тыл, только вперёд return User::getInstance()->getRoom() === 1;
//В момент хода при соблюдении условий удара может прилететь неблокируемая атака на расстоянии. }
//Перемещение - это ручной гарантированный уворот от всех летящих физических атак.
//Перемещение на пустующую клетку 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.';
}
// ПИСАТЬ РЕЗУЛЬТАТ ХОДА ТОЛЬКО ПОСЛЕ ПОВТОРНОЙ ПРОВЕРКИ НА НАЛИЧИЕ ПРОТИВНИКА - ОН МОГ УСПЕТЬ ОТОЙТИ! // проверка на нахождение в другой заявке
// !!ИЛИ УМЕРЕТЬ!! public function hasNoPendingFights(): bool
$stmt_update_timer->execute(); {
$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();
}
}