Будь проклят тот день, когда я решил ввести неймспейсы...

This commit is contained in:
lopar
2020-10-28 22:21:08 +02:00
parent f1b9ce6a45
commit d38d62c5b5
159 changed files with 339 additions and 304 deletions
+237
View File
@@ -0,0 +1,237 @@
<?php
/**
* Author: lopiu
* Date: 03.07.2020
* Time: 07:24
*/
namespace Battles;
class Bank
{
public $user_id;
private $money;
private $user;
const ERROR_NO_MONEY_IN_WALLET = "Ошибка! Нет денег в кошельке!";
const ERROR_NO_BANK_ACCOUNT = "Ошибка! Счёта не существует!";
const ERROR_NO_MONEY_IN_BANK_ACCOUNT = "Ошибка! Нет денег на счету!";
const ERROR_WRONG_AMOUNT = "Ошибка! Сумма должна быть положительной!";
const LOG = [
'sendMoney' => 'Банк: Перевод средств на другой счёт.',
'receiveMoney' => 'Банк: Получение средств.',
'depositMoney' => 'Пополнение счёта.',
'withdrawMoney' => 'Снятие денег со счёта.',
'clanRegister' => 'Оплата стоимости регистрации клана.',
];
public function __construct($row)
{
$bank_row = \db::c()->query('SELECT user_id, money FROM bank WHERE user_id = ?i', $row)->fetch_assoc();
$this->user = \db::c()->query('SELECT money FROM users WHERE id = ?i', $row)->fetch_object();
foreach ($this as $key => $value) {
if (isset($bank_row[$key])) {
$this->$key = $bank_row[$key];
}
}
// Если ВДРУГ у человека нет счёта в банке - создаём.
if (empty($this->user_id)) {
\db::c()->query('INSERT INTO bank (user_id) VALUES (?i)', $row);
$this->user_id = $row;
}
}
/**
* Комиссия: процент от переводимой суммы, но не менее 1 кр. Задаётся в config.php.
*
* @param int $amount сумма.
*
* @return int
*/
private function bankCommission(int $amount): int
{
$bankCommission = round($amount * \Config::$bank_commission);
if ($bankCommission < 1) {
return 1;
} else {
return (int)$bankCommission;
}
}
/**
* Пишем банковское событие в лог в БД
*
* @param int $receiverId ID получателя.
* @param int $amount сумма.
* @param string $operationType тип банковской операции.
* @param int $senderId ID отправителя (ID игрока, если не указано иное).
*
* @return void
* @throws \Krugozor\Database\Mysql\Exception
*/
private function bankLogs(int $receiverId, int $amount, string $operationType, int $senderId = 0): void
{
if (!$senderId) {
$senderId = $this->user_id;
}
$text = self::LOG[$operationType];
if ($operationType == "sendMoney") {
$text .= " Комиссия: " . $this->bankCommission($amount);
} elseif ($operationType == "depositMoney") {
$receiverId = $this->user_id;
} elseif ($operationType == "withdrawMoney") {
$receiverId = $this->user_id;
$text .= " Комиссия: " . $this->bankCommission($amount);
}
\db::c()->query('INSERT INTO `bank_logs` (sender_id, receiver_id, amount_result, type, text)
VALUES (?i, ?i, ?i, "?s", "?s")', $senderId, $receiverId, $amount, $operationType, $text);
}
/**
* Перевод денег между банковскими счетами игроков с банковской комиссией.
*
* @param int $receiver ID получателя.
* @param int $amount сумма.
*
* @return int
* @throws \Krugozor\Database\Mysql\Exception
*/
public function sendMoney(int $receiver, int $amount): int
{
$receiverWallet = \db::c()->query('SELECT money FROM bank WHERE user_id = ?i', $receiver)->fetch_object();
if ($amount <= 0) {
throw new \Exceptions\GameException(self::ERROR_WRONG_AMOUNT);
}
if (!$receiverWallet) {
throw new \Exceptions\GameException(self::ERROR_NO_BANK_ACCOUNT);
}
$amountWithComission = $amount + $this->bankCommission($amount);
if ($amountWithComission > $this->money) {
throw new \Exceptions\GameException(self::ERROR_NO_MONEY_IN_BANK_ACCOUNT);
}
// Снимаем сумму с комиссией у отправителя
$this->money -= $amountWithComission;
self::setBankMoney($this->money, $this->user_id);
$this->bankLogs($receiver, $this->money, "sendMoney");
// Отдаём сумму на счёт получателю
$receiverWallet->money += $amount;
self::setBankMoney($receiverWallet->money, $receiver);
$this->bankLogs($receiver, $receiverWallet->money, "receiveMoney");
// Возвращаем изменившиеся значения
return $this->money;
}
/**
* Пополнение банковского счёта игрока
*
* @param int $amount сумма.
*
* @return array
* @throws \Krugozor\Database\Mysql\Exception
*/
public function depositMoney(int $amount): array
{
if ($amount <= 0) {
throw new \Exceptions\GameException(self::ERROR_WRONG_AMOUNT);
}
$wallet = \db::c()->query('SELECT money FROM users WHERE id = ?i', $this->user_id)->fetch_object();
if ($wallet->money < $amount) {
throw new \Exceptions\GameException(self::ERROR_NO_MONEY_IN_WALLET);
}
// Забираем деньги из кошелька получателя
$this->user->money -= $amount;
self::setWalletMoney($this->user->money, $this->user_id);
// Отдаём сумму на счёт получателю
$this->money += $amount;
self::setBankMoney($this->money, $this->user_id);
$this->bankLogs(0, $this->money, "depositMoney");
// Возвращаем изменившиеся значения
return [
'walletMoney' => $this->user->money,
'bankMoney' => $this->money
];
}
/**
* Снятие денег с банковского счёта игрока с банковской комиссией.
*
* @param int $amount сумма.
*
* @return array
* @throws \Krugozor\Database\Mysql\Exception
*/
public function withdrawMoney(int $amount):array
{
if ($amount <= 0) {
throw new \Exceptions\GameException(self::ERROR_WRONG_AMOUNT);
}
$amountWithComission = $amount + $this->bankCommission($amount);
if ($this->money < $amountWithComission) {
throw new \Exceptions\GameException(self::ERROR_NO_MONEY_IN_BANK_ACCOUNT);
}
// Снимаем сумму с комиссией у отправителя
$this->money -= $amountWithComission;
self::setBankMoney($this->money, $this->user_id);
$this->bankLogs(0, $this->money, "withdrawMoney");
// Отдаём сумму в кошелёк получателя
$this->user->money += $amount;
self::setWalletMoney($this->user->money, $this->user_id);
// Возвращаем изменившиеся значения
return [
'walletMoney' => $this->user->money,
'bankMoney' => $this->money
];
}
/**
* Установить количество денег на банковском счету.
*
* @param int $amount сумма.
* @param int $user_id ID пользователя.
* @param string $operationType Тип операции. По умолчанию пусто. Если ввести, система запишет событие в банковский лог.
*
* @return void
* @throws \Krugozor\Database\Mysql\Exception
*/
public static function setBankMoney(int $amount, int $user_id, string $operationType = ''): void
{
try {
\db::c()->query('UPDATE bank SET money = ?i WHERE user_id = ?i', $amount, $user_id);
if ($operationType) {
(new Bank($user_id))->bankLogs(0, $amount, $operationType);
}
} catch (\Throwable $e) {
echo "Не отработал запрос в БД в файле {$e->getFile()}({$e->getLine()})";
}
}
/**
* Установить количество денег на руках.
*
* @param int $amount сумма.
* @param int $user_id ID пользователя.
*
* @return void
* @throws \Krugozor\Database\Mysql\Exception
*/
public static function setWalletMoney(int $amount, int $user_id): void
{
try {
\db::c()->query('UPDATE users SET money = ?i WHERE `id` = ?i', $amount, $user_id);
} catch (\Throwable $e) {
echo "Не отработал запрос в БД в файле {$e->getFile()}({$e->getLine()})";
}
}
public function getMoney()
{
return $this->money;
}
public function setMoney($amount)
{
$this->money = $amount;
}
}
+86
View File
@@ -0,0 +1,86 @@
<?php
# Date: 26.10.2020 (17:56)
namespace Battles;
// todo: #10
class City
{
use Rooms;
public static function showStreet(int $id)
{
if ($id === 20) {
echo '<div style="position:relative; display: inline-block;" id="ione"><img alt="background" src="/i/city/spring_cap_cp_day.jpg">' .
self::showBuilding(1, "spring_cap_club", 30, 235, self::$roomNames[1]) .
self::showBuilding(2, "spring_cap_shop", 202, 171, self::$roomNames[22]) .
self::showBuilding(3, "spring_cap_kom", 205, 105, self::$roomNames[25]) .
self::showBuilding(4, "spring_cap_rem", 202, 290, self::$roomNames[23]) .
self::showBuilding(6, "spring_cap_po4ta", 180, 540, self::$roomNames[27]) .
self::showBuilding(7, "cap_arr_right", 260, 710, self::$roomNames[21]) .
self::showBuilding(8, "cap_arr_left", 258, 21, self::$roomNames[26]) .
self::showBuilding(9, "winter_cap_tree2", 215, 500, self::$roomNames[44]) .
self::showBuilding(13, "spring_cap_statue", 222, 365, self::$roomNames[24]) .
self::showBuilding(14, "winter_cap_statue", 210, 390, "Снеговик") .
self::showBuilding(222, "cap_arr_top", 180, 650, "Торговая улица") .
'</div>';
} elseif ($id === 21) {
echo '<div style="position:relative; display: inline-block;" id="ione"><img alt="background" src="/i/city/spring_cap_strash_day.jpg">' .
self::showBuilding(3, "cap_arr_right", 255, 708, "Ристалище") .
self::showBuilding(4, "cap_arr_left", 258, 21, self::$roomNames[20]) .
self::showBuilding(5, "spring_cap_bank", 180, 485, self::$roomNames[29]) .
self::showBuilding(13, "spring_cap_flowershop", 220, 613, self::$roomNames[34]) .
self::showBuilding(14, "spring_cap_registratura", 170, 113, self::$roomNames[30]) .
self::showBuilding(16, "spring_cap_tower", 5, 315, self::$roomNames[31]) .
'</div>';
} elseif ($id === 26) {
echo '<div style="position:relative; display: inline-block;" id="ione"><img alt="background" src="/i/city/spring_cap_park_day.jpg">' .
self::showBuilding(3, "cap_arr_left", 259, 27, self::$roomNames[2601]) .
self::showBuilding(4, "cap_arr_right", 259, 715, self::$roomNames[20]) .
self::showBuilding(6, "cap_gate", 170, 340, "Городские ворота") .
self::showBuilding(660, "spring_cap_vokzal", 163, 43, self::$roomNames[661]) .
'</div>';
} elseif ($id === 2601) {
echo '<div style="position:relative; display: inline-block;" id="ione"><img alt="background" src="/i/city/sub/cap_zamk_day.jpg">' .
self::showBuilding(1, "spring_cap_ruins", 166, 48, "Руины Старого замка") .
self::showBuilding(4, "cap_arr_right", 260, 710, self::$roomNames[26]) .
self::showBuilding(10, "ava_post", 240, 300, self::$roomNames[35]) .
self::showBuilding(55, "cap_arr_left", 258, 21, self::$roomNames[2655]) .
self::showBuilding(1051, "spring_cap_lab", 130, 327, self::$roomNames[33]) .
self::showBuilding(1052, "spring_cap_lavka", 240, 425, self::$roomNames[1053]) .
'</div>';
} elseif ($id === 2655) {
echo '<div style="position:relative; display: inline-block;" id="ione"><img alt="background" src="/i/city/ar_e_d.jpg">' .
self::showBuilding(10, "arr_right_png2", 260, 710, self::$roomNames[2601]) .
self::showBuilding(2055, "altr_g", 230, 340, self::$roomNames[603]) .
'</div>';
} elseif ($id === 2111) {
echo '<div style="position:relative; display: inline-block;" id="ione"><img alt="background" src="/i/city/av_rist_day.jpg">' .
self::showBuilding(1, "cap_arr_left", 240, 30, self::$roomNames[21]) .
self::showBuilding(14, "spring_cap_rist_solo", 210, 160, "Вход в Одиночные сражения") .
self::showBuilding(14, "spring_cap_rist_group", 243, 340, "Вход в Сражение отрядов") .
self::showBuilding(203, "spring_cap_rist_monstr", 145, 570, "Вход в Груповые сражения") .
self::showBuilding(1000, "av_zamk_rud", 80, 310, self::$roomNames[1001]) .
'</div>';
} elseif ($id === 2701) {
echo '<div style="position:relative; display: inline-block;" id="ione"><img alt="background" src="/i/city/av_arena_bg1_day2.jpg">' .
self::showBuilding(1, "cap_3strelka", 260, 30, "Берег Залива") .
self::showBuilding(2, "cap_shar_dark", 234, 356, "Лабиринт Хаоса") .
'</div>';
} elseif ($id === 2702) {
echo '<div style="position:relative; display: inline-block;" id="ione"><img alt="background" src="/i/city/spring_cap_torg_day.jpg">' .
self::showBuilding(6, "spring_cap_build1", 175, 70, "Академия") .
self::showBuilding(10, "cap_rist_arr_left", 259, 25, self::$roomNames[20]) .
self::showBuilding(16, "auk", 120, 300, "Аукцион") .
self::showBuilding(21, "spring_cap_build2", 150, 565, "Ломбард") .
self::showBuilding(16555, "spring_cap_build3", 155, 480, "Прокатная лавка") .
'</div>';
}
}
private static function showBuilding(int $id, string $image, int $top, int $left, string $description)
{
return sprintf('
<div style="position:absolute; left:%spx; top:%spx; z-index:90; cursor: pointer;">
<img src="/i/city/sub/%s.png" alt="%s" title="%s" class="building" id="%s" onclick="window.location.href = \'city.php?got/level%s\'">
</div>',
$left, $top, $image, $description, $description, $id, $id);
}
}
+148
View File
@@ -0,0 +1,148 @@
<?php
/**
* Author: lopiu
* Date: 06.07.2020
* Time: 22:41
*/
namespace Battles;
class DressedItems
{
private $DB;
private $DBSUM;
private $USERID;
private $dressedItem;
/**
* DressedItems constructor.
*
* @param $user_id - ID игрока.
*/
public function __construct($user_id)
{
$this->USERID = $user_id;
}
private function getDressedItems()
{
try {
$this->DB = db::c()->query('SELECT * FROM inventory WHERE owner_id = ?i AND dressed_slot > 0', $this->USERID);
} catch (Exception $e) {
echo '<div class="debug">Не прогрузилась таблица inventory (*) для класса DressedItems.</div>';
}
}
private function getDressedItemById($item_id)
{
return db::c()->query('SELECT * FROM inventory WHERE item_id = ?i AND dressed_slot > 0', $item_id)->fetch_assoc();
}
private function getBonusesFromDressedItems()
{
try {
$query = <<<SQL
SELECT SUM(add_strength) as sum_strength,
SUM(add_dexterity) as sum_dexterity,
SUM(add_intuition) as sum_intuition,
SUM(add_endurance) as sum_endurance,
SUM(add_intelligence) as sum_intelligence,
SUM(add_wisdom) as sum_wisdom,
SUM(add_accuracy) as sum_accuracy,
SUM(add_evasion) as sum_evasion,
SUM(add_criticals) as sum_criticals,
SUM(add_min_physical_damage) as sum_min_phys_damage,
SUM(add_max_physical_damage) as sum_max_phys_damage
FROM inventory WHERE owner_id = ?i AND dressed_slot > 0
SQL;
$this->DBSUM = db::c()->query($query, $this->USERID)->fetch_assoc();
} catch (Exception $e) {
echo '<div class="debug">Не прогрузилась таблица inventory (SUM) для класса DressedItems:' . $e . '</div>';
}
}
public function getItemsInSlots()
{
if (!$this->DB) {
self::getDressedItems();
}
while ($row = $this->DB->fetch_assoc()) {
$this->dressedItem[$row['dressed_slot']] = $row;
}
return $this->dressedItem;
}
private function getBonuses()
{
if (!$this->DBSUM) {
self::getBonusesFromDressedItems();
}
return $this->DBSUM;
}
public function getStrengthBonus()
{
return self::getBonuses()['sum_strength'];
}
public function getDexterityBonus()
{
return self::getBonuses()['sum_dexterity'];
}
public function getIntuitionBonus()
{
return self::getBonuses()['sum_intuition'];
}
public function getEnduranceBonus()
{
return self::getBonuses()['sum_endurance'];
}
public function getIntelliganceBonus()
{
return self::getBonuses()['sum_intelligence'];
}
public function getWisdomBonus()
{
return self::getBonuses()['sum_wisdom'];
}
public function getAccuracyBonus()
{
return self::getBonuses()['sum_accuracy'] ?? 0;
}
public function getEvasionBonus()
{
return self::getBonuses()['sum_evasion'] ?? 0;
}
public function getCriticalsBonus()
{
return self::getBonuses()['sum_criticals'] ?? 0;
}
public function getMinPhysDamage()
{
return self::getBonuses()['sum_min_phys_damage'];
}
public function getMaxPhysDamage()
{
return self::getBonuses()['sum_max_phys_damage'];
}
/**
* Снимает с предмета статус одетого на персонажа в определённом слоте персонажа.
* @param $slot_id - номер слота.
*
* @throws \Krugozor\Database\Mysql\Exception
*/
public function undressItem($slot_id)
{
self::getItemsInSlots();
// Проверяем, что используется один из 12 слотов и наличие предмета в слоте.
if (in_array($slot_id, Item::ITEM_TYPES_ALLOWED_IN_SLOTS) && $this->dressedItem[$slot_id]) {
db::c()->query('UPDATE inventory SET dressed_slot = 0 WHERE dressed_slot = ?i AND owner_id = ?i', $slot_id, $this->USERID);
}
}
public function slotStatus($slot_id)
{
self::getItemsInSlots();
if ($this->dressedItem[$slot_id]) {
}
}
}
+49
View File
@@ -0,0 +1,49 @@
<?php
namespace Battles;
class InventoryItem extends Item
{
private $present;
public function __construct($row)
{
parent::__construct($row);
if (isset($row['present'])) {
$this->present = $row['present'];
}
}
public function printInfo()
{
parent::printAllInfo();
if ($this->present) {
echo "<p style='color: maroon; font-style: italic'>Это подарок от {$this->present}. Вы не можете передать его кому-либо ещё.</p>";
}
}
public function printImage()
{
if (in_array($this->item_type, range(1,12))) {
echo "<a href=/main.php?edit=1&dress={$this->item_id} title='Надеть'>";
parent::printImage();
echo "</a>";
} else {
parent::printImage();
}
}
/**
* Для кнопок управления под картинкой предмета в зависимости от ситуации.
*/
public function printControls()
{
//FIXME Сменить заглушку на нормальную функцию!!
echo <<<BTN
<p><button class="button danger" onclick="location.href='/admin.php'">Выбросить</button>
BTN;
}
public function getId()
{
return $this->item_id;
}
}
+177
View File
@@ -0,0 +1,177 @@
<?php
namespace Battles;
abstract class Item
{
protected $item_id;
protected $name;
protected $item_type;
protected $durability;
protected $price;
protected $need_strength;
protected $need_dexterity;
protected $need_intuition;
protected $need_endurance;
protected $need_intelligence;
protected $need_wisdom;
protected $add_strength;
protected $add_dexterity;
protected $add_intuition;
protected $add_endurance;
protected $add_intelligence;
protected $add_wisdom;
protected $add_accuracy;
protected $add_evasion;
protected $add_criticals;
protected $add_min_physical_damage;
protected $add_max_physical_damage;
protected $weight;
protected $image;
public const ITEM_TYPES_ALLOWED_IN_SLOTS = [1,2,3,4,5,6,7,8,9,10,11,12];
public const ITEM_TYPE_HELMET = 1;
public const ITEM_TYPE_ARMOR = 2;
const ITEM_TYPE_LEGS = 3;
const ITEM_TYPE_BOOTS = 4;
const ITEM_TYPE_GLOVES = 5;
const ITEM_TYPE_WEAPON = 6;
const ITEM_TYPE_SHIELD = 7;
const ITEM_TYPE_BELT = 8;
public const ITEM_TYPE_RING = 9;
const ITEM_TYPE_AMULET = 10;
const ITEM_TYPE_CONSUMABLE = 20;
const ITEM_TYPE_OTHER = 50;
const ITEM_TYPE_TRASH = 100;
/**
* Item constructor.
*
* @param $row
*/
public function __construct($row)
{
foreach ($this as $key => $value) {
if (isset($row[$key])) {
$this->$key = $row[$key];
}
}
switch ($this->item_type) {
case self::ITEM_TYPE_HELMET:
$this->typename = 'Шлем';
break;
case self::ITEM_TYPE_ARMOR:
$this->typename = 'Броня';
break;
case self::ITEM_TYPE_LEGS:
$this->typename = 'Поножи';
break;
case self::ITEM_TYPE_BOOTS:
$this->typename = 'Сапоги';
break;
case self::ITEM_TYPE_GLOVES:
$this->typename = 'Перчатки';
break;
case self::ITEM_TYPE_WEAPON:
$this->typename = 'Оружие';
break;
case self::ITEM_TYPE_SHIELD:
$this->typename = 'Щит';
break;
case self::ITEM_TYPE_BELT:
$this->typename = 'Пояс';
break;
case self::ITEM_TYPE_RING:
$this->typename = 'Кольцо';
break;
case self::ITEM_TYPE_AMULET:
$this->typename = 'Амулет';
break;
case self::ITEM_TYPE_CONSUMABLE:
$this->typename = 'Расходуемый предмет';
break;
default:
$this->typename = 'Хлам';
}
}
abstract public function printInfo();
public function printImage()
{
echo <<<IMG
<img src="/i/sh/{$this->image}" class="item-wrap-normal" alt="">
IMG;
}
protected function wrap($number)
{
if ($number > 0) {
return ": <b>" . $number . "</b>";
} else {
return ": <b style='color: maroon;'>" . $number . "</b>";
}
}
protected function printAllInfo()
{
echo "<b>" . $this->name . "</b> (Масса: " . $this->weight . ")";
if ($this->durability) {
echo "<br> Долговечность: " . $this->durability;
}
echo "<br><em>{$this->typename}</em><br>";
if ($this->need_strength > 0) {
echo "<br>Требуется сила" . $this->wrap($this->need_strength);
}
if ($this->need_dexterity > 0) {
echo "<br>Требуется ловкость" . $this->wrap($this->need_dexterity);
}
if ($this->need_intuition > 0) {
echo "<br>Требуется интуиция" . $this->wrap($this->need_intuition);
}
if ($this->need_endurance > 0) {
echo "<br>Требуется выносливость" . $this->wrap($this->need_endurance);
}
if ($this->need_intelligence > 0) {
echo "<br>Требуется интеллект" . $this->wrap($this->need_intelligence);
}
if ($this->need_wisdom > 0) {
echo "<br>Требуется мудрость" . $this->wrap($this->need_wisdom);
}
if ($this->add_strength) {
echo "<br>Сила" . $this->wrap($this->add_strength);
}
if ($this->add_dexterity) {
echo "<br>Ловкость" . $this->wrap($this->add_dexterity);
}
if ($this->add_intuition) {
echo "<br>Интуиция" . $this->wrap($this->add_intuition);
}
if ($this->add_endurance) {
echo "<br>Выносливость" . $this->wrap($this->add_endurance);
}
if ($this->add_intelligence) {
echo "<br>Интеллект" . $this->wrap($this->add_intelligence);
}
if ($this->add_wisdom) {
echo "<br>Мудрость" . $this->wrap($this->add_wisdom);
}
if ($this->add_accuracy) {
echo "<br>Точность" . $this->wrap($this->add_accuracy);
}
if ($this->add_evasion) {
echo "<br>Увёртливость" . $this->wrap($this->add_evasion);
}
if ($this->add_criticals) {
echo "<br>Шанс крита" . $this->wrap($this->add_criticals);
}
if ($this->add_min_physical_damage && !$this->add_max_physical_damage) {
$damage = $this->add_min_physical_damage . " - " . $this->add_min_physical_damage;
} elseif (!$this->add_min_physical_damage && $this->add_max_physical_damage) {
$damage = $this->add_max_physical_damage . " - " . $this->add_max_physical_damage;
} elseif ($this->add_min_physical_damage && $this->add_max_physical_damage) {
$damage = $this->add_min_physical_damage . " - " . $this->add_max_physical_damage;
}
if (isset($damage)) {
echo "<br>Урон: " . $damage;
}
}
}
+58
View File
@@ -0,0 +1,58 @@
<?php
# Date: 16.09.2020 (08:23)
// Магия лечения травм
namespace Battles\Magic;
use Battles\UserEffects;
use Battles\User;
class CureInjury extends magic
{
private $target;
use UserEffects;
/**
* Магия лечения травм. Если у персонажа несколько травм, лечится самая тяжёлая.
* @param $target - кого лечим.
* @param $injuryType - тип травмы, которую лечим. 11 лёгкая, 12 средняя, 13 тяжёлая, 14 неизлечимая.
* @throws \Krugozor\Database\Mysql\Exception
*/
public function __construct($target, $injuryType)
{
$this->target = $target;
if ($target && $this->isUsable()) {
$injury = \db::c()->query('SELECT effect_id, type, name FROM users_effects WHERE type IN (11,12,13,14) AND owner_id = ?i ORDER BY type DESC LIMIT 1', $target)->fetch_object();
$targetName = $this->target->login;
if (in_array($injury->effect_id, [11, 12, 13, 14]) && $injuryType >= $injury->type) {
\db::c()->query('DELETE FROM users_effects WHERE effect_id = ?i', $injury->effect_id);
if (empty($injury->name) || $injury->name == 'Неизвестный эффект') {
$injuryName = self::$effectName[$injury->type];
} else {
$injuryName = $injury->name;
}
return "Вы вылечили повреждение ${injuryName} персонажу ${targetName}.";
} elseif ($injury->effect_id && $injuryType == 15) {
\db::c()->query('DELETE FROM users_effects WHERE type IN (11,12,13,14) AND owner_id = ?i', $target);
return "Вы вылечили все повреждения персонажу ${targetName}.";
} else {
return false;
}
} else {
return $this->status;
}
}
/**
* Проверки на успех.
* @return bool
*/
private function isUsable()
{
$caster = new User($_SESSION['uid']);
if ($this->target == $_SESSION['uid']) {
$this->target = $caster;
} else {
$this->target = new User($this->target);
}
return ($this->isVisible($caster, $this->target) && $this->isNotDead($caster) && $this->enoughMana($caster) && $this->isNotInBattle($caster));
}
}
+47
View File
@@ -0,0 +1,47 @@
<?php
# Date: 16.09.2020 (08:45)
namespace Battles\Magic;
class Magic
{
protected $status;
protected function isVisible($caster, $target)
{
if ($caster->battle != $target->battle || $caster->room != $target->room) {
$this->status = 'Вы не видите цель!';
return false;
} else {
return true;
}
}
protected function isNotDead($caster)
{
if ($caster->health < 1) {
$this->status = 'Вы мертвы!';
return false;
} else {
return true;
}
}
protected function enoughMana($caster)
{
if ($caster->mana < 1) {
$this->status = 'Недостаточно пыли!';
return false;
} else {
return true;
}
}
protected function isNotInBattle($caster)
{
if ($caster->battle) {
$this->status = 'Невозможно применить в поединке!';
return false;
} else {
return true;
}
}
}
+41
View File
@@ -0,0 +1,41 @@
<?php
namespace Battles\Magic;
use db;
class attack
{
private $target_user;
private $caster;
private function __construct($target_user_id)
{
if (!$this->caster) {
$this->caster = db::c()->query('SELECT * FROM `users` WHERE `id` = ?i', $_SESSION['uid']);
}
if (!$this->target_user) {
$this->target_user = db::c()->query('SELECT * FROM `users` WHERE `id` = ?i', $target_user_id);
}
if ($this->checks() == 1) {
return 'Done!';
}
}
private function checks()
{
if ($this->caster['battle']) {
return 'Не в бою...';
}
else {
return 1;
}
}
public static function id($playerId)
{
return new self($playerId);
}
}
+38
View File
@@ -0,0 +1,38 @@
<?php
/**
* Author: lopiu
* Date: 05.07.2020
* Time: 23:32
*/
namespace Battles\Models;
class EffectsModel
{
protected $DB;
const EFFECT_HIDEUSERINFO = 5; // Обезлик
public function __construct(int $user_id) {
try {
$this->DB = \db::c()->query('SELECT * FROM users_effects WHERE owner_id = ?i', $user_id);
} catch (\Throwable $e) {echo '<div class="debug">class EffectsModel: Не могу подключиться к таблице effects!</div>';}
}
private function getEffects($user_id)
{
}
/**
* Проверка обезличен ли персонаж.
* @return int date() до конца эффекта или 0.
*/
public function getHideUserInfoStatus()
{
if ($this->DB) {
while ($row = $this->DB->fetch_object()) {
if ($row->type == self::EFFECT_HIDEUSERINFO) {
return $row->time;
}
}
}
return 0;
}
}
+33
View File
@@ -0,0 +1,33 @@
<?php
/**
* Author: lopiu
* Date: 04.07.2020
* Time: 13:17
*/
namespace Battles\Models;
use Exceptions\GameException;
class PresentsModel
{
protected $DB;
public function __construct(int $user_id)
{
if (!$this->DB) {
$this->DB = \db::c()->query('SELECT sender_id, image FROM `users_presents` WHERE owner_id = ?i', $user_id);
if ($this->DB->getNumRows() == 0) {
throw new GameException("<div class='debug'>class PresentsModel: Не прогрузилась база!</div>");
}
}
}
public function getAllPresents()
{
return $this->DB;
}
public function getPresentsSum()
{
return $this->DB->getNumRows();
}
}
+22
View File
@@ -0,0 +1,22 @@
<?php
/**
* Author: lopiu
* Date: 05.07.2020
* Time: 22:38
*/
namespace Battles\Models;
class UserLogModel
{
protected $DB;
public function __construct(int $user_id)
{
$this->DB = \db::c()->query('SELECT * FROM users_logs WHERE user_id = ?i ORDER BY `id` ASC', $user_id);
}
public function getUserLog()
{
return $this->DB;
}
}
+106
View File
@@ -0,0 +1,106 @@
<?php
namespace Battles;
/**
* Разные способы отображения строки с логином персонажа.
*/
class Nick extends User
{
private function getInvisibilityStatus()
{
return db::c()->query('SELECT 1 FROM users_effects WHERE type = 1022 AND owner_id = ?i', $this->id);
}
/**
* Отображение иконки склонности.
* @return string
*/
private function getAlign()
{
if (isset($this->align)) {
return sprintf('<img src="i/align_%s.gif">', $this->align);
} else {
return '';
}
}
/**
* Отображение иконки клана.
* @return string
*/
private function getClan()
{
if (isset($this->clan)) {
return sprintf('<img src="i/clan/%s.png">', $this->clan);
} else {
return '';
}
}
/**
* Берем ID и возвращаем его. Что-то для обратной совместимости, скорее всего.
* TODO: Отвязаться от функции и удалить.
* @param $playerId
*
* @return Nick
*/
public static function id($playerId)
{
return new self($playerId);
}
/**
* Возвращает строку со склонностью, кланом, логином, уровнем, ссылкой на профиль.
*
* @param int $showInvisibility - По умолчанию 0. Выбрать 1, если надо отображать невидимый статус.
*
* @return string
* @throws \Krugozor\Database\Mysql\Exception
*/
public function full($showInvisibility = 0)
{
if ($showInvisibility && $this->getInvisibilityStatus()) {
return '<i>невидимка</i>';
}
return $this->getAlign().$this->getClan().sprintf('<b>%s</b> [%s] <a href="inf.php?%s" target="_blank"><img src="i/inf.gif" style="width:12px;height:11px"></a>', $this->login, $this->level, $this->login);
}
/**
* Возвращает строку с логином или невидимым статусом.
* @return string
* @throws \Krugozor\Database\Mysql\Exception
*/
public function short()
{
if ($this->getInvisibilityStatus()) {
return '<i>невидимка</i>';
} else {
return htmlspecialchars($this->login);
}
}
/**
* Возвращает строку со склонностью, кланом, логином, уровнем, ссылкой на профиль, здоровьем.
* @return string
*/
public function battle()
{
return $this->getAlign().$this->getClan().sprintf('<b>%s</b> [%s] <a href="inf.php?%s" target="_blank"><img src="i/inf.gif" style="width:12px;height:11px"></a> <img src="i/herz.gif" alt="HP"> _hp_/_maxhp_', $this->login, $this->level, $this->login);
}
/**
* Возвращает строку с логином и здоровьем, выделяя строку определённым стилем.
* @param $textstyle - Название стиля отображения логина персонажа (main.css) для цветового разделения команд.
*
* @return string
*/
public function battleShort($textstyle)
{
if ($this->getInvisibilityStatus()) {
return '<i>невидимка</i>';
}
else {
return sprintf('<span style="%s">%s</span> [_hp_/_maxhp_]', $textstyle, $this->login);
}
}
}
+190
View File
@@ -0,0 +1,190 @@
<?php
namespace Battles;
/*
* Список наименований игровых комнат.
*/
trait Rooms
{
public static $roomNames = [
0 => "Секретная Комната",
1 => "Дом поединков",
20 => "Центральная площадь",
21 => "Страшилкина улица",
22 => "Магазин",
23 => "Ремонтная мастерская",
24 => "Памятник Архангелу",
25 => "Комиссионный магазин",
26 => "Большая парковая улица",
27 => "Почта",
29 => "Банк",
30 => "Регистратура кланов",
31 => "Башня смерти",
32 => "Готический замок",
33 => "Лабиринт хаоса",
34 => "Цветочный магазин",
35 => "Сувенирный магазин",
37 => "Готический замок - приемная",
38 => "Готический замок - арсенал",
39 => "Готический замок - внутренний двор",
40 => "Готический замок - мастерские",
41 => "Готический замок - комнаты отдыха",
42 => "Лотерея Сталкеров",
43 => "Хижина Знахаря",
44 => "Новогодняя елка",
45 => "Замок Мэра",
47 => "Замок (строительство)",
48 => "Обитель Хаоса",
49 => "Проход к Цитадели Хаоса",
51 => "Парковая улица",
52 => "Квартал Законников",
53 => "Библиотека",
61 => "Академия",
200 => "Турнир",
401 => "Врата Ада",
// БС
501 => "Восточная Крыша",
502 => "Бойница",
503 => "Келья 3",
504 => "Келья 2",
505 => "Западная Крыша 2",
506 => "Келья 4",
507 => "Келья 1",
508 => "Служебная комната",
509 => "Зал Отдыха 2",
510 => "Западная Крыша 1",
511 => "Выход на Крышу",
512 => "Зал Статуй 2",
513 => "Храм",
514 => "Восточная комната",
515 => "Зал Отдыха 1",
516 => "Старый Зал 2",
517 => "Старый Зал 1",
518 => "Красный Зал 3",
519 => "Зал Статуй 1",
520 => "Зал Статуй 3",
521 => "Трапезная 3",
522 => "Зал Ожиданий",
523 => "Оружейная",
524 => "Красный Зал-Окна",
525 => "Красный Зал",
526 => "Гостинная",
527 => "Трапезная 1",
528 => "Внутренний Двор",
529 => "Внутр.Двор-Вход",
530 => "Желтый Коридор",
531 => "Мраморный Зал 1",
532 => "Красный Зал 2",
533 => "Библиотека 1",
534 => "Трапезная 2",
535 => "Проход Внутр. Двора",
536 => "Комната с Камином",
537 => "Библиотека 3",
538 => "Выход из Мрам.Зала",
539 => "Красный Зал-Коридор",
540 => "Лестница в Подвал 1",
541 => "Южный Внутр. Двор",
542 => "Трапезная 4",
543 => "Мраморный Зал 3",
544 => "Мраморный Зал 2",
545 => "Картинная Галерея 1",
546 => "Лестница в Подвал 2",
547 => "Проход Внутр. Двора 2",
548 => "Внутр.Двор-Выход",
549 => "Библиотека 2",
550 => "Картинная Галерея 3",
551 => "Картинная Галерея 2",
552 => "Лестница в Подвал 3",
553 => "Терасса",
554 => "Оранжерея",
555 => "Зал Ораторов",
556 => "Лестница в Подвал 4",
557 => "Темная Комната",
558 => "Винный Погреб",
559 => "Комната в Подвале",
560 => "Подвал",
600 => "Вход в Цитадель Хаоса",
601 => "Цитадель Хаоса",
602 => "Городской парк",
603 => "Арена Ангелов",
620 => "Вход в Рудник",
621 => "Рудник",
660 => "Гостиница, холл",
661 => "Гостиница",
662 => "Памятник Архангелу",
// Клановая улица
650 => "Клановая улица",
651 => "Клановая улица",
652 => "Клановый Замок",
760 => "Тёмный Лес",
1000 => "Вход в рудник",
1001 => "Рудник",
1051 => "Вход в Лабиринты",
1052 => "Лабиринты",
1053 => "Храмовая лавка",
1054 => "Фонтан Удачи",
1055 => "Групповое сражение",
// Тайный проход из Клуба в Замок Законников
2000 => "Подземный проход",
2001 => "Подземный проход (1)",
2002 => "Подземный проход (2)",
2003 => "Подземный проход (3)",
2004 => "Подземный проход (4)",
2005 => "Подземный проход (5)",
2006 => "Подземный проход (6)",
2007 => "Подземный проход (7)",
2008 => "Подземный проход (8)",
2009 => "Подземный проход (9)",
2010 => "Подземный проход (10)",
2011 => "Подземный проход (11)",
2012 => "Подземный проход (12)",
2013 => "Подземный проход (13)",
2014 => "Подземный проход (14)",
2015 => "Подземный проход (15)",
2016 => "Подземный проход (16)",
2017 => "Подземный проход (17)",
2018 => "Подземный проход (18)",
2019 => "Подземный проход (19)",
2020 => "Подземный проход (20)",
2021 => "Подземный проход (21)",
2022 => "Подземный проход (22)",
2023 => "Подземный проход (23)",
2024 => "Подземный проход (24)",
2025 => "Подземный проход (25)",
2026 => "Подземный проход (26)",
2027 => "Подземный проход (27)",
2028 => "Подземный проход (28)",
2029 => "Подземный проход (29)",
2030 => "Подземный проход (30)",
2031 => "Подземный проход (31)",
2032 => "Подземный проход (32)",
2033 => "Подземный проход (33)",
2034 => "Подземный проход (34)",
2035 => "Подземный проход (35)",
2036 => "Подземный проход (36)",
2037 => "Подземный проход (37)",
2038 => "Подземный проход (38)",
2039 => "Подземный проход (39)",
2040 => "Подземный проход (40)",
2041 => "Подземный проход (41)",
2042 => "Подземный проход (42)",
2043 => "Подземный проход (43)",
2044 => "Подземный проход (44)",
2045 => "Подземный проход (45)",
2046 => "Подземный проход (46)",
2047 => "Подземный проход (47)",
2048 => "Подземный проход (48)",
2049 => "Подземный проход (49)",
2050 => "Подземный проход (50)",
2051 => "Подземный проход (51)",
2052 => "Подземный проход (52)",
2053 => "Подземный проход (53)",
2054 => "Подземный проход (54)",
2055 => "Подземный проход (55)",
2056 => "Подземный проход (56)",
2057 => "Подземный проход (57)",
2100 => "Сектор 2100",
2655 => "Арена Богов",
2601 => "Замковая Площадь",
2702 => "Центральная площадь (мираж)",
];
}
+71
View File
@@ -0,0 +1,71 @@
<?php
namespace Battles;
class ShopItem extends Item
{
public function printInfo()
{
parent::printAllInfo();
}
public function buyItem($owner)
{
if ($owner) {
db::c()->query('
INSERT INTO `inventory` (`prototype`,`owner`,`name`,`type`,`massa`,`cost`,`img`,`maxdur`,`isrep`,`gsila`,`glovk`,`ginta`,`gintel`,
`ghp`,`gnoj`,`gtopor`,`gdubina`,`gmech`,`gfire`,`gwater`,`gair`,`gearth`,`glight`,`ggray`,`gdark`,
`needident`,`nsila`,`nlovk`,`ninta`,`nintel`,`nmudra`,`nvinos`,`nnoj`,`ntopor`,`ndubina`,`nmech`,
`nfire`,`nwater`,`nair`,`nearth`,`nlight`,`ngray`,`ndark`,`mfkrit`,`mfakrit`,`mfuvorot`,`mfauvorot`,
`bron1`,`bron2`,`bron3`,`bron4`,`maxu`,`minu`,`magic`,`nlevel`,`nalign`,`dategoden`,`goden`,`otdel`,
`artefact`, `koll`) VALUES (?i,?i,"?s",?i,?i,?i,"?s",?i,?i,?i,?i,?i,?i,?i,?i,?i,?i,?i,?i,?i,?i,?i,?i,?i,?i,
?i,?i,?i,?i,?i,?i,?i,?i,?i,?i,?i,?i,?i,?i,?i,?i,?i,?i,?i,?i,?i,?i,?i,?i,?i,?i,?i,?i,?i,?i,?i,?i,?i,"?s",?i,?i)
', $this->id, $owner, $this->name, $this->type, $this->massa, $this->cost, $this->img, $this->maxdur, $this->isrep, $this->gsila, $this->glovk, $this->ginta, $this->gintel,
$this->ghp, $this->gnoj, $this->gtopor, $this->gdubina, $this->gmech, $this->gfire, $this->gwater, $this->gair, $this->gearth, $this->glight, $this->ggray, $this->gdark,
$this->needident, $this->nsila, $this->nlovk, $this->ninta, $this->nintel, $this->nmudra, $this->nvinos, $this->nnoj, $this->ntopor, $this->ndubina, $this->nmech,
$this->nfire, $this->nwater, $this->nair, $this->nearth, $this->nlight, $this->ngray, $this->ndark, $this->mfkrit, $this->mfakrit, $this->mfuvorot, $this->mfauvorot,
$this->bron1, $this->bron2, $this->bron3, $this->bron4, $this->maxu, $this->minu, $this->magic, $this->nlevel, $this->nalign, $this->dategoden, $this->goden, $this->razdel,
$this->artefact, $this->koll);
}
}
/**
* Для кнопок управления под картинкой прелмета в зависимости от ситуации.
*/
public function printControls($shopType = false)
{
if ($shopType === 'marketput') {
echo <<<BTN
<form method="post">
<input placeholder="{$this->cost}" name="cost">
<input type="hidden" name="putId" value="{$this->id}">
<br><input type="submit" name="putToMarket" value="Cдать в магазин">
</form>
BTN;
} else {
switch ($shopType) {
default:
$btnValue = "Купить за " . intval($this->cost) . " кр.";
$btnLink = "/shop.php?buy={$this->id}&rnd=" . mt_rand();
break;
case 'sell':
$btnValue = "Продать";
$btnLink = "/shop.php?sell={$this->id}&rnd=" . mt_rand();
break;
case 'marketgetback':
$btnValue = "Снять с продажи";
$btnLink = "?back={$this->id}&rnd=" . mt_rand();
break;
case 'marketbuy':
$btnValue = "Купить за " . intval($this->setsale) . " кр.";
$btnLink = "?otdel={$this->otdel}&set={$this->id}&rnd=" . mt_rand();
break;
}
echo <<<BTN
<p><input type="button" style="background: darkgrey; border: 1px solid grey; border-radius: 2px;" value="{$btnValue}"
onclick="location='{$btnLink}'">
BTN;
if ($this->count > 0) echo "<br><small>В наличии: {$this->count} штук</small>";
}
}
}
+50
View File
@@ -0,0 +1,50 @@
<?php
# Date: 30.09.2020 (09:42)
namespace Battles;
class Template
{
/**
* Template constructor.
*/
public function __construct()
{
}
/**
* @param string|null $title
* @param int|null $return
*
* @return false|string
*/
public static function header(string $title = null, int $return = null)
{
$head = <<<HTML_HEADER
<!doctype html>
<html lang="ru">
<meta charset="utf-8">
<link href="/css/main.css" rel="stylesheet">
<link href="/css/btn.css" rel=stylesheet >
<title>$title</title>
HTML_HEADER;
if (!$return) {
echo $head;
return false;
}
return $head;
}
/**
* @param string $buildingName название здания
* @param string $streetName служебное название улицы на которой стоит здание для кнопки возврата.
* @return string
*/
public static function buildingTop(string $buildingName, string $streetName): void
{
echo <<<HTML
<div style="float: right">
<button onclick="top.frames['gameframe'].location = 'city.php?$streetName'">Выйти из здания</button>
</div>
<h1>$buildingName</h1>
HTML;
}
}
+130
View File
@@ -0,0 +1,130 @@
<?php
# Date: 26.10.2020 (16:08)
namespace Battles;
class Travel
{
/**
* Соответствие ID комнаты игровому файлу.
* @var string[]
*/
private static $roomFileName = [
1 => 'main.php',
20 => 'city.php',
21 => 'city.php',
22 => 'shop.php',
23 => 'repair.php',
25 => 'comission.php',
26 => 'city.php',
27 => 'post.php',
29 => 'bank.php',
30 => 'clan_create.php',
31 => 'tower.php',
34 => 'fshop.php',
37 => 'gotzamok.php',
51 => 'city.php',
61 => 'akadem.php',
401 => 'hell.php',
402 => 'lab_chaos_enter.php',
404 => 'vxod.php',
603 => 'aren_of_angels.php',
620 => 'enter_cave.php',
650 => 'ul_clans.php',
660 => 'hostel.php',
666 => 'jail.php',
777 => 'obshaga.php',
1051 => 'lab_enter.php',
1055 => 'group_arena.php',
2111 => 'city.php',
2601 => 'city.php',
2655 => 'city.php',
2702 => 'city.php'
];
/**
* Перемещение по комнатам.
* @param int $roomId ID куда идём.
* @param int $roomIdCurrent ID откуда идём.
* @throws \Krugozor\Database\Mysql\Exception
*/
public static function toRoom(int $roomId, int $roomIdCurrent): void
{
$itemsWeight = \db::c()->query('SELECT SUM(weight) AS all_weight FROM `inventory` WHERE owner_id = ?i AND on_sale = 0', $_SESSION['uid'])->fetch_assoc();
$eff = \db::c()->query('SELECT type FROM users_effects WHERE owner_id = ?i AND (`type` = 10 OR `type` = 13 OR `type` = 14)', $_SESSION['uid'])->fetch_assoc();
$errors = [];
if ($itemsWeight['all_weight'] > get_meshok()) {
$errors[0] = 'У вас переполнен рюкзак, вы не можете передвигаться...';
}
if ($eff['type'] == 10) {
$errors[1] = 'Вы парализованы и не можете передвигаться...';
}
if ($eff['type'] == 13 || $eff['type'] == 14) {
$errors[2] = 'У вас тяжелая травма, вы не можете передвигаться...';
}
if ($errors) {
foreach ($errors as $error) {
echo sprintf('<span class="error">%s</span>', $error);
}
} elseif (in_array($roomId, self::allowedRoomMoves($roomIdCurrent))) {
\db::c()->query('UPDATE users, online SET users.room = ?i, online.room = ?i WHERE `online`.`user_id` = `users`.`id` AND `online`.`user_id` = ?i', $roomId, $roomId, $_SESSION['uid']);
header('location: ' . self::$roomFileName[$roomId]);
exit;
}
}
/**
* Проверка можно ли перейти из комнаты в комнату.
* @param int $roomId ID комнаты
* @return array|int[]
*/
private static function allowedRoomMoves(int $roomId): array
{
/*
* 1 location: main.php?goto=arena
* 2 Room 22 shop.php
* 3 Room 25 comission.php
* 4 Room 23 repair.php
* 6 Room 27 posr.php
* 7 Room 21 [STREET]
* 8 Room 26 [STREET]
* 13 location: quest_room.php
* 222 Room 2702 [STREET]
*/
$room[20] = [1, 21, 22, 23, 25, 26, 27, 2702];
$room[1] = $room[22] = $room[23] = $room[25] = $room[27] = [20];
/*
* 3 Room 2111 [STREET]
* 4 Room 20 [STREET]
* 5 Room 29 Bank.php
* 13 Room 34 fshop.php
* 14 Room 30 clan_create.php
* 16 Room 31 tower.php
* 650 Room 650 ul_clans.php
*/
$room[21] = [20, 29, 30, 31, 34, 650, 2111];
$room[29] = $room[30] = $room[31] = $room[34] = [21];
$room[26] = [20, 401, 660, 777, 2601];
$room[401] = $room[660] = $room[777] = [26];
$room[2601] = [26, 37, 404, 1051, 2655];
$room[2655] = [603, 2601];
/*
* 1 Room 21 [STREET]
* 2 location: city.php?haos - где эта херня вообще?
* 14 NULL
* 21 NULL
* 203 Room 1055 group_arena.php
* [!not on map]666 Room 666 jail.php
* 1000
*/
$room[2111] = [21, 620, 666, 1055];
$room[2701] = [402, 2111];
$room[2702] = [20, 61];
if ($room[$roomId] === null) {
return [];
}
return $room[$roomId];
}
}
+159
View File
@@ -0,0 +1,159 @@
<?php
namespace Battles;
use Exceptions\GameException;
class User
{
public $id = 0;
public $login = '<em>Некто</em>';
public $pass;
public $email = '<em>неизвестно</em>';
public $realname;
public $borndate;
public $info;
public $level = 0;
public $align = 0;
public $clan = 0;
public $money = 0;
public $strength = 0;
public $dexterity = 0;
public $intuition = 0;
public $endurance = 0;
public $intelligence = 0;
public $wisdom = 0;
public $health;
public $mana;
public $ip;
public $session_id;
public $admin = 0;
public $enter_game;
public $room;
public $block;
public $shadow;
// Удар кулаком всегда 1-2.
public $minDamage = 1;
public $maxDamage = 2;
//Броня без предметов не существует.
public $headArmor = 0;
public $chestArmor = 0;
public $legArmor = 0;
public $free_stat_points = 0;
public const STAT_MAXIMUM_AMOUNT = 40;
private const ERROR_STAT_IS_MAXIMUM = 'Ошибка: Параметр достиг своего лимита!';
private const ERROR_STAT_UNKNOWN = 'Ошибка: Неизвестный параметр!';
// Пока несуществующие, для совместимости.
public $married = 'Someone или нет.';
public $experience = 200;
public $battle = 0;
public $in_tower = 0; // Скорее башню похороним чем запустим...
public $zayavka = 0;
// Динамически рассчитываемые
public $maxHealth = 5;
public $maxMana = 5;
public function __construct($user)
{
$user_query = \db::c()->query('SELECT * FROM users WHERE id = "?s" OR login = "?s"', $user, $user)->fetch_assoc();
foreach ($this as $key => $value) {
if (isset($user_query[$key])) {
$this->$key = $user_query[$key];
}
}
$this->maxHealth = round(($this->endurance * 3) + ($this->endurance / 2) * ($this->level - 1) + ($this->endurance / 5) * (($this->level - 1) * ($this->level - 2) / 2));
$this->maxMana = round(($this->wisdom * 3) + ($this->wisdom / 2) * ($this->level - 1) + ($this->wisdom / 5) * (($this->level - 1) * ($this->level - 2) / 2));
}
/**
* Отдаёт информацию о базовом(!) стате.
* @param $stat_name - имя стата. Может принимать значения 'strength', 'dexterity', 'intuition', 'endurance', 'intelligence', 'wisdom'.
* @param int $isMainWindow - переключатель "главного окна". Если включить, дополнительно будет показывать ссылку на повышение стата на 1, при условии наличия свободных очков статов.
* @return string
* @throws GameException
*/
public function getStat($stat_name, $isMainWindow = 0)
{
$allowed = ['strength', 'dexterity', 'intuition', 'endurance', 'intelligence', 'wisdom'];
if (in_array($stat_name, $allowed)) {
if ($this->free_stat_points && $isMainWindow && $this->$stat_name < self::STAT_MAXIMUM_AMOUNT) {
return sprintf('%s <a href="/main.php?edit=%s&ups=%s">[+]</a>', $this->$stat_name, mt_rand(), $stat_name);
} else {
return $this->$stat_name;
}
} else {
throw new \Exceptions\GameException(self::ERROR_STAT_UNKNOWN);
}
}
/**
* Повышает один из выбранных статов на 1, но не выше self::STAT_MAXIMUM_AMOUNT при условии наличия свободных очков статов.
* @param $stat_name - имя стата. Может принимать значения 'strength', 'dexterity', 'intuition', 'endurance', 'intelligence', 'wisdom'.
* @throws GameException
*/
public function addOnePointToStat($stat_name)
{
$allowed = ['strength', 'dexterity', 'intuition', 'endurance', 'intelligence', 'wisdom'];
if (in_array($stat_name, $allowed)) {
if ($this->free_stat_points > 0 && $this->$stat_name <= self::STAT_MAXIMUM_AMOUNT) {
$query = 'UPDATE users SET ?f = ?f + 1, free_stat_points = free_stat_points - 1 WHERE id = ?i';
\db::c()->query($query, $stat_name, $stat_name, $this->id);
} else {
throw new \Exceptions\GameException(self::ERROR_STAT_IS_MAXIMUM);
}
} else {
throw new \Exceptions\GameException(self::ERROR_STAT_UNKNOWN);
}
}
protected function showStarSign()
{
/*
* 1 aries
* 2 taurus
* 3 gemini
* 4 cancer
* 5 leo
* 6 virgo
* 7 libra
* 8 scorpio
* 9 sagittarios
* 10 capricorn
* 11 aquarius
* 12 pisches
*/
$zodiac[356] = "10";
$zodiac[326] = "09";
$zodiac[296] = "08";
$zodiac[266] = "07";
$zodiac[235] = "06";
$zodiac[203] = "05";
$zodiac[172] = "04";
$zodiac[140] = "03";
$zodiac[111] = "02";
$zodiac[78] = "01";
$zodiac[51] = "12";
$zodiac[20] = "11";
$zodiac[0] = "10";
$dayOfYear = date("z", strtotime($this->borndate));
$isLeapYear = date("L", strtotime($this->borndate)); //Высокосный?
if ($isLeapYear && $dayOfYear > 59) {
--$dayOfYear;
}
foreach ($zodiac as $day => $sign) {
if ($dayOfYear > $day) {
break;
}
}
return $sign ?? null;
}
public function getHealth(): string
{
return $this->health . '/' . $this->maxHealth;
}
public function getMana(): string
{
return $this->mana . '/' . $this->maxMana;
}
}
+52
View File
@@ -0,0 +1,52 @@
<?php
# Date: 16.09.2020 (08:28)
# Названия эффектов, налагаемых на персонажа.
namespace Battles;
trait UserEffects
{
public static $effectName = [
10 => 'паралич',
11 => 'легкая травма',
12 => 'средняя травма',
13 => 'тяжёлая травма',
14 => 'неизлечимая травма',
1022 => 'невидимость',
2 => 'Заклинание молчания',
3 => 'Заклятие форумного молчания',
4 => 'Заклятие хаоса',
5 => 'Заклятие обезличивания',
20 => 'Проверка Паладинов',
21 => 'Сила нейтралитета',
22 => 'Защита от кулачного нападения',
51 => 'Опьянение',
201 => 'Защита от оружия',
202 => 'Сокрушение',
203 => 'Туманный образ [1]',
204 => 'Туманный образ [2]',
205 => 'Туманный образ [3]',
206 => 'Гравитация [1]',
207 => 'Гравитация [2]',
208 => 'Гравитация [3]',
209 => 'Стена Огня [1]',
210 => 'Стена Огня [2]',
211 => 'Стена Огня [3]',
212 => 'Чистота Воды [1]',
213 => 'Чистота Воды [2]',
214 => 'Чистота Воды [3]',
215 => 'Защита эфира [1]',
216 => 'Защита эфира [2]',
217 => 'Защита эфира [3]',
218 => 'Песчаный щит [1]',
219 => 'Песчаный щит [2]',
220 => 'Песчаный щит [3]',
221 => 'Огненный Щит [1]',
222 => 'Огненный Щит [2]',
223 => 'Огненный Щит [3]',
224 => 'Стена Воды [1]',
225 => 'Стена Воды [2]',
226 => 'Стена Воды [3]',
227 => 'Защита от нападений',
405 => 'Микстура жизненных сил',
9994 => 'Антидот/Путы (Эликсир?)',
];
}
+199
View File
@@ -0,0 +1,199 @@
<?php
namespace Battles;
class UserInfo extends User
{
use Rooms;
//Статусы того, кто смотрит на информацию.
public $watcher_id;
private $watcherIsAdmin;
private $watcherIsModerator;
/**
* Отображает куклу персонажа (образ и слоты).
*
* @param int $isBattle - установить 1, если куклу нужно отобразить в поединке (показывает параметры при наведении
* на образ).
* @param int $isMain - установить 1, если куклу надо показать на странице игрока (по клику на предмет снимает
* его).
*
* @throws \Krugozor\Database\Mysql\Exception
*/
private function UserInfoDoll($isBattle = 0, $isMain = 0)
{
//https://jsfiddle.net/ngx0yvhc
//TODO переверстать grid, чтобы он касался только куклы.
$di = new DressedItems($this->id);
$dressedItems = $di->getItemsInSlots();
for ($i = 1; $i <= 12; $i++) {
echo sprintf('<div class="slot-%s">', $i);
if (!empty($dressedItems[$i])) {
if (!$isBattle && $isMain) {
$itemString = '<a href="?edit=%s&drop=%s"><img src="/i/sh/%s" class="item-wrap-normal" alt="%s" title="%s"></a>';
echo sprintf($itemString, mt_rand(), $i, $dressedItems[$i]['image'], $dressedItems[$i]['name'], $dressedItems[$i]['name']);
} else {
$itemString = '<img src="/i/sh/%s" class="item-wrap-normal tip" alt="%s"><span class="tiptext"><strong>%s</strong></span>';
echo sprintf($itemString, $dressedItems[$i]['image'], $dressedItems[$i]['name'], $dressedItems[$i]['name']);
}
} else {
echo sprintf('<img src="/i/sh/noitem.png" class="item-wrap-normal" title="Пустой слот [%s]" alt="Пустой слот [%s]">', $i, $i);
}
echo sprintf('</div><!-- slot-%s -->', $i);
}
echo '<div class="slot-image">';
if ($isBattle) {
$sh = '<img src="/i/shadow/%s" alt="%s" class="tip"><span class="tiptext"><b>%s</b>Уровень: %s<br>Сила: %s<br>Ловкость: %s<br>Интуиция: %s<br>Выносливость: %s<br>Интеллект: %s<br>Мудрость: %s</span>';
echo sprintf($sh, $this->shadow, $this->login, $this->login, $this->level, $this->strength, $this->dexterity, $this->intuition, $this->endurance, $this->intelligence, $this->wisdom);
unset($sh);
} else {
echo '<img src="/i/shadow/' . $this->shadow . '" alt="' . $this->login . '">';
}
echo '</div><!-- slot-image -->';
}
private function UserInfoStats($isMainWindow = 0)
{
$captions = 'Уровень:<br>Сила:<br>Ловкость:<br>Интуиция:<br>Выносливость:<br>Интеллект:<br>Мудрость:<br>Местонахождение:';
$variables =
$this->level . '<br>' .
parent::getStat('strength') . '<br>' .
parent::getStat('dexterity') . '<br>' .
parent::getStat('intuition') . '<br>' .
parent::getStat('endurance') . '<br>' .
parent::getStat('intelligence') . '<br>' .
parent::getStat('wisdom') . '<br>' .
Rooms::$roomNames[$this->room];
if ($isMainWindow) {
$this->Bank = new Bank($this->id);
$captions = 'Уровень:<br>Здоровье:<br>Сила:<br>Ловкость:<br>Интуиция:<br>Выносливость:<br>Интеллект:<br>Мудрость:<br>Опыт:<br>Очки характеристик:<br>Деньги:<br>Деньги в банке:';
$variables =
$this->level . '<br>' .
$this->health . '<br>' .
parent::getStat('strength', 1) . '<br>' .
parent::getStat('dexterity', 1) . '<br>' .
parent::getStat('intuition', 1) . '<br>' .
parent::getStat('endurance', 1) . '<br>' .
parent::getStat('intelligence', 1) . '<br>' .
parent::getStat('wisdom', 1) . '<br>' .
$this->experience . '<br>' .
$this->free_stat_points . '<br>' .
$this->money . '<br>' .
$this->Bank->getMoney();
}
$nameString = '';
if ($this->align) {
$nameString = sprintf('<img src="/i/align_%s.png" alt="Склонность">', $this->align);
}
if ($this->block) {
$nameString .= '<span class="private"><s>' . $this->login . '</s></span>';
} else {
$nameString .= ' <b>' . $this->login . '</b> ';
}
if ($this->clan) {
$nameString .= sprintf('<img src="/i/clan/%s.png" alt="Клан">', $this->clan);
}
echo '<div class="user-info">';
echo '<div class="info">';
echo '<b>' . $nameString . '</b>';
echo '</div><!-- info -->';
echo '<div class="stats-container">';
echo '<div class="column">';
echo $captions;
echo '</div><!-- column -->';
echo '<div class="column">';
echo $variables;
echo '</div><!-- column -->';
echo '</div><!-- stats-container -->';
echo '<div class="debug">TODO: Сделать рассчёт модификаторов. Вывести полоску здоровья когда будет от чего отталкиваться.</div>';
echo '</div><!-- user-info -->';
}
private function Info()
{
echo '<div class="user-info-container">';
$this->UserInfoDoll();
$this->UserInfoStats();
echo '<div class="slot-lower">';
if ($this->married) {
echo sprintf('<a href = "inf.php?%s" target = _blank ><img alt = "В браке с %s" src = "i/married.gif" title = "В браке с %s"></a >', $this->married, $this->married, $this->married);
}
echo '</div><!-- slot-lower -->';
echo '<div class="user-signs">';
echo sprintf('<img src="i/zodiac/%s.png" alt="Родовой знак">', $this->showStarSign());
echo '</div><!-- user-signs -->';
echo '</div><!-- user-info-container -->';
echo '<hr><!-- Нижняя часть -->';
echo '<div class="user-info-container-lower">';
echo '<h2>Об игроке</h2>';
if ($this->realname) {
echo sprintf('Имя: %s<br>', $this->realname);
}
if ($this->info) {
echo nl2br($this->info);
}
echo '</div><!-- user-info-container-lower -->';
if ($this->watcherIsAdmin || $this->watcherIsModerator) {
echo '<div class="secret-info">';
$infoString = 'E-Mail: %s<br> ДР Игрока: %s<br> IP Регистрации: %s';
echo sprintf($infoString, $this->email, date('d.m.Y', strtotime($this->borndate)), $this->ip);
if ($this->watcherIsAdmin) {
$this->Bank = new Bank($this->id);
$infoString = '<br><span>ИД Игрока: %s<br> ИД Комнаты: %s<br> Деньги: %s<br> Деньги в банке: %s<br> Опыт: %s<br> Нераспределённые очки: %s<br> Текущая сессия: %s</span>';
echo sprintf($infoString, $this->id, $this->room, $this->money, $this->Bank->getMoney(), $this->experience, $this->free_stat_points, $this->session_id);
}
$this->UserLogs = new \Battles\Models\UserLogModel($this->id);
echo '<div class="secret-info-user-log"><b>Личное дело</b><br>';
while ($userLogRow = $this->UserLogs->getUserLog()->fetch_object()) {
echo sprintf('<code>%s</code><br>', date("d.m.Y H:i ", strtotime($userLogRow->date)) . $userLogRow->text);
}
echo '</div><!-- secret-info-user-log -->';
echo '</div><!-- secret-info -->';
}
}
public function showUserInfo()
{
$this->effects = new \Battles\Models\EffectsModel($this->id);
$this->WatcherStatus();
if ($this->block && (!$this->watcherIsAdmin || !$this->watcherIsModerator)) {
throw new \Exceptions\GameException('<span class="error">Персонаж ' . $this->login . ' заблокирован!</span>');
} elseif ($this->effects->getHideUserInfoStatus() && (!$this->watcherIsAdmin || !$this->watcherIsModerator)) {
if ($this->effects->getHideUserInfoStatus() == -1) {
$date = 'навсегда';
} else {
$date = 'до' . date('d.m.Y', strtotime($this->effects->getHideUserInfoStatus()));
}
throw new \Exceptions\GameException('<span class="error">Персонаж ' . $this->login . ' обезличен ' . $date . '.</span>');
} else {
$this->Info();
}
}
private function WatcherStatus()
{
$query = db::c()->query('SELECT `align`,`admin` FROM `users` WHERE `id` = ?i', $this->watcher_id)->fetch_assoc();
if ($query['admin']) {
$this->watcherIsAdmin = 1;
}
if ($query['align'] == 1) {
$this->watcherIsModerator = 1;
}
}
public function showUserDoll($isBattle = 0, $isMain = 0)
{
echo '<div class="user-info-container">';
$this->UserInfoDoll($isBattle, $isMain);
echo '</div><!-- user-info-container -->';
}
public function showUserInfoMain()
{
echo '<div class="user-info-container">';
$this->UserInfoDoll();
$this->userInfoStats(1);
echo '</div><!-- user-info-container -->';
}
}