Админка.
This commit is contained in:
parent
fdaadf69e6
commit
6509a796f6
@ -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
142
classes/Battles/Fight.php
Normal 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user