地图
This commit is contained in:
parent
81402717b5
commit
3dbe8cbd73
3
bin/game
3
bin/game
|
|
@ -12,9 +12,8 @@ if (file_exists(__DIR__ . '/../vendor/autoload.php')) {
|
|||
require 'phar://hanli-idle.phar/vendor/autoload.php';
|
||||
}
|
||||
|
||||
use Game\Console\ConsoleOutput;
|
||||
use Game\Core\Input;
|
||||
use Symfony\Component\Console\Input\ArgvInput;
|
||||
use Symfony\Component\Console\Output\ConsoleOutput;
|
||||
use Game\Core\Game;
|
||||
|
||||
// 设置终端为 UTF-8
|
||||
|
|
|
|||
22
src/Console/ConsoleOutput.php
Normal file
22
src/Console/ConsoleOutput.php
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
namespace Game\Console;
|
||||
|
||||
use Game\Core\Colors;
|
||||
use Symfony\Component\Console\Formatter\OutputFormatterInterface;
|
||||
use Symfony\Component\Console\Output\ConsoleOutput as Out;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class ConsoleOutput extends Out
|
||||
{
|
||||
public function __construct(int $verbosity = OutputInterface::VERBOSITY_NORMAL, ?bool $decorated = null, ?OutputFormatterInterface $formatter = null)
|
||||
{
|
||||
Out::__construct($verbosity, $decorated, $formatter);
|
||||
}
|
||||
|
||||
public function writeln(string|iterable $messages, int $options = self::OUTPUT_NORMAL)
|
||||
{
|
||||
$messages.=Colors::RESET;
|
||||
parent::writeln($messages,$options);
|
||||
}
|
||||
}
|
||||
154
src/Core/UserManager.php
Normal file
154
src/Core/UserManager.php
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
<?php
|
||||
namespace Game\Core;
|
||||
|
||||
/**
|
||||
* 用户管理器 - 简单的文件存储用户系统
|
||||
*/
|
||||
class UserManager
|
||||
{
|
||||
private string $usersFile;
|
||||
private array $users = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->usersFile = __DIR__ . '/../../data/users.json';
|
||||
|
||||
// 确保目录存在
|
||||
$dir = dirname($this->usersFile);
|
||||
if (!is_dir($dir)) {
|
||||
mkdir($dir, 0755, true);
|
||||
}
|
||||
|
||||
$this->loadUsers();
|
||||
}
|
||||
|
||||
private function loadUsers(): void
|
||||
{
|
||||
if (file_exists($this->usersFile)) {
|
||||
$data = json_decode(file_get_contents($this->usersFile), true);
|
||||
if (is_array($data)) {
|
||||
$this->users = $data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function saveUsers(): void
|
||||
{
|
||||
file_put_contents($this->usersFile, json_encode($this->users, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册新用户
|
||||
* @return array ['success' => bool, 'message' => string, 'userId' => string|null]
|
||||
*/
|
||||
public function register(string $username, string $password): array
|
||||
{
|
||||
// 验证用户名
|
||||
$username = trim($username);
|
||||
if (strlen($username) < 2 || strlen($username) > 20) {
|
||||
return ['success' => false, 'message' => '用户名长度需要在2-20个字符之间', 'userId' => null];
|
||||
}
|
||||
|
||||
if (!preg_match('/^[a-zA-Z0-9_\x{4e00}-\x{9fa5}]+$/u', $username)) {
|
||||
return ['success' => false, 'message' => '用户名只能包含字母、数字、下划线和中文', 'userId' => null];
|
||||
}
|
||||
|
||||
// 检查用户名是否已存在
|
||||
if ($this->userExists($username)) {
|
||||
return ['success' => false, 'message' => '用户名已存在', 'userId' => null];
|
||||
}
|
||||
|
||||
// 验证密码
|
||||
if (strlen($password) < 4) {
|
||||
return ['success' => false, 'message' => '密码长度至少4个字符', 'userId' => null];
|
||||
}
|
||||
|
||||
// 生成用户ID
|
||||
$userId = $this->generateUserId($username);
|
||||
|
||||
// 保存用户
|
||||
$this->users[$userId] = [
|
||||
'id' => $userId,
|
||||
'username' => $username,
|
||||
'password' => password_hash($password, PASSWORD_DEFAULT),
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
'last_login' => null,
|
||||
];
|
||||
|
||||
$this->saveUsers();
|
||||
|
||||
return ['success' => true, 'message' => '注册成功', 'userId' => $userId];
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户登录
|
||||
* @return array ['success' => bool, 'message' => string, 'userId' => string|null]
|
||||
*/
|
||||
public function login(string $username, string $password): array
|
||||
{
|
||||
$username = trim($username);
|
||||
|
||||
// 查找用户
|
||||
$user = $this->findUserByUsername($username);
|
||||
if (!$user) {
|
||||
return ['success' => false, 'message' => '用户不存在', 'userId' => null];
|
||||
}
|
||||
|
||||
// 验证密码
|
||||
if (!password_verify($password, $user['password'])) {
|
||||
return ['success' => false, 'message' => '密码错误', 'userId' => null];
|
||||
}
|
||||
|
||||
// 更新最后登录时间
|
||||
$this->users[$user['id']]['last_login'] = date('Y-m-d H:i:s');
|
||||
$this->saveUsers();
|
||||
|
||||
return ['success' => true, 'message' => '登录成功', 'userId' => $user['id']];
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查用户名是否存在
|
||||
*/
|
||||
public function userExists(string $username): bool
|
||||
{
|
||||
return $this->findUserByUsername($username) !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户名查找用户
|
||||
*/
|
||||
private function findUserByUsername(string $username): ?array
|
||||
{
|
||||
foreach ($this->users as $user) {
|
||||
if (strcasecmp($user['username'], $username) === 0) {
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成用户ID
|
||||
*/
|
||||
private function generateUserId(string $username): string
|
||||
{
|
||||
// 使用用户名+时间戳的哈希
|
||||
return substr(md5($username . time() . rand(1000, 9999)), 0, 16);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户信息
|
||||
*/
|
||||
public function getUser(string $userId): ?array
|
||||
{
|
||||
return $this->users[$userId] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有用户数量
|
||||
*/
|
||||
public function getUserCount(): int
|
||||
{
|
||||
return count($this->users);
|
||||
}
|
||||
}
|
||||
|
|
@ -454,8 +454,8 @@
|
|||
"hp": 1,
|
||||
"patk": 0,
|
||||
"matk": 0,
|
||||
"pdef": 999,
|
||||
"mdef": 999,
|
||||
"pdef": 100,
|
||||
"mdef": 100,
|
||||
"crit": 0,
|
||||
"critdmg": 100,
|
||||
"exp": 400,
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ class Actor
|
|||
public int $crit = 0;
|
||||
public float $critdmg = 110.0;
|
||||
|
||||
public int $mana = 60;
|
||||
public int $maxMana = 60;
|
||||
public int $mana = 100;
|
||||
public int $maxMana = 100;
|
||||
|
||||
// 防护系统
|
||||
public bool $isProtecting = false; // 是否处于防护状态
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ namespace Game\Entities;
|
|||
|
||||
use Game\Modules\Bag\Consume;
|
||||
use Game\Modules\Bag\Equipment;
|
||||
use Game\Modules\Bag\Quest;
|
||||
use Game\Modules\Bag\Spell;
|
||||
|
||||
class Monster extends Actor
|
||||
|
|
@ -84,6 +85,14 @@ class Monster extends Actor
|
|||
$monsterConfig_allow [] = $item;
|
||||
}
|
||||
}
|
||||
if (empty($monsterConfig_allow)){
|
||||
if ($dungeonId < 2){
|
||||
$monsterConfig_allow = $monsterConfig[0];
|
||||
}else{
|
||||
$monsterConfig_allow = $monsterConfig;
|
||||
}
|
||||
}
|
||||
// dd($monsterConfig_allow,$dungeonId);
|
||||
$monsterConfig = $monsterConfig_allow;
|
||||
$levels = array_column($monsterConfig,'level');
|
||||
$total = 0;
|
||||
|
|
@ -98,19 +107,18 @@ class Monster extends Actor
|
|||
$groupSize = rand(2, 4);
|
||||
}
|
||||
$group = [];
|
||||
|
||||
// Create each enemy independently using weighted random selection
|
||||
for ($i = 1; $i < $groupSize; $i++) {
|
||||
for ($i = 1; $i <= $groupSize; $i++) {
|
||||
$totalWeight = 0;
|
||||
foreach ($monsterConfig as $m) {
|
||||
$totalWeight += $m['weight'] ?? 100;
|
||||
$totalWeight += $m['weight'] ?? 10;
|
||||
}
|
||||
|
||||
$rand = rand(1, $totalWeight);
|
||||
$selectedConfig = null;
|
||||
|
||||
foreach ($monsterConfig as $m) {
|
||||
$rand -= $m['weight'] ?? 100;
|
||||
$rand -= $m['weight'] ?? 10;
|
||||
if ($rand <= 0) {
|
||||
$selectedConfig = $m;
|
||||
break;
|
||||
|
|
@ -185,6 +193,9 @@ class Monster extends Actor
|
|||
}
|
||||
}
|
||||
$this->dropTable[] = Consume::createItem($dungeonId,$config['level']);
|
||||
if ($this->is_boss){
|
||||
$this->dropTable[] = Quest::createItem($dungeonId);
|
||||
}
|
||||
// 为怪物配置法术
|
||||
$this->generateSpells($config);
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ class Player extends Actor
|
|||
public array $partners = []; // 已招募的同伴
|
||||
|
||||
// Player特有的小绿瓶回复池
|
||||
public int $potionPool = 1000; // 小绿瓶初始回复量
|
||||
public int $potionPool = 10000; // 小绿瓶初始回复量
|
||||
|
||||
/**
|
||||
* 增加灵石
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ abstract class Item
|
|||
return Colors::GREEN.'小绿瓶+'.$item['heal'].Colors::RESET;
|
||||
} else if ($item['type'] == 'spell') {
|
||||
return Spell::getLineShow($item);
|
||||
} elseif ($item['type'] == 'quest') {
|
||||
} elseif ($item['type'] == 'quest_item') {
|
||||
return Quest::getLineShow($item);
|
||||
} elseif ($item['type'] == 'consume') {
|
||||
return Consume::getLineShow($item);
|
||||
|
|
@ -44,7 +44,7 @@ abstract class Item
|
|||
{
|
||||
if ($item['type'] == 'spell') {
|
||||
return Spell::calculateSellPrice($item);
|
||||
} elseif ($item['type'] == 'quest') {
|
||||
} elseif ($item['type'] == 'quest_item') {
|
||||
return Quest::calculateSellPrice($item);
|
||||
} elseif ($item['type'] == 'consume') {
|
||||
return Consume::calculateSellPrice($item);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
namespace Game\Modules\Bag;
|
||||
|
||||
use Game\Core\Colors;
|
||||
|
||||
/**
|
||||
* Simple representation of an equipment/consumable item.
|
||||
*/
|
||||
|
|
@ -25,6 +27,23 @@ class Quest extends Item
|
|||
];
|
||||
}
|
||||
|
||||
public static function createItem($dungeonId)
|
||||
{
|
||||
$data = file_get_contents(__DIR__.'/../../Data/quest.json');
|
||||
$data = json_decode($data,true);
|
||||
$name = $data[$dungeonId];
|
||||
return [
|
||||
'id' => uniqid('quest_'),
|
||||
'type' => 'quest_item',
|
||||
'rate' => 20,
|
||||
'name' => $name,
|
||||
'quality' => 'legendary',
|
||||
'level' => 1,
|
||||
'quantity' => 1,
|
||||
'desc' => '关键任务物品,用于解锁新区域',
|
||||
];
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
return [
|
||||
|
|
@ -38,7 +57,7 @@ class Quest extends Item
|
|||
|
||||
public static function getLineShow($item): string
|
||||
{
|
||||
// TODO: Implement getLineShow() method.
|
||||
return Colors::YELLOW.$item['name'].Colors::RESET;
|
||||
}
|
||||
|
||||
public static function getDetailShow($item): array
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
<?php
|
||||
|
||||
namespace Game\Modules;
|
||||
|
||||
use Game\Core\Game;
|
||||
|
|
@ -56,9 +57,9 @@ class Battle
|
|||
$this->blue = Colors::BLUE;
|
||||
|
||||
$this->qualityColors = [
|
||||
'common' => Colors::WHITE,
|
||||
'rare' => Colors::BLUE,
|
||||
'epic' => Colors::MAGENTA,
|
||||
'common' => Colors::WHITE,
|
||||
'rare' => Colors::BLUE,
|
||||
'epic' => Colors::MAGENTA,
|
||||
'legendary' => Colors::YELLOW,
|
||||
];
|
||||
}
|
||||
|
|
@ -131,7 +132,7 @@ class Battle
|
|||
Screen::delay(500000);
|
||||
|
||||
// 创建敌人群组
|
||||
$this->enemies = Monster::createGroup($this->game->dungeonId,$this->player->level);
|
||||
$this->enemies = Monster::createGroup($this->game->dungeonId, $this->player->level);
|
||||
|
||||
$this->totalMaxHp = 0;
|
||||
foreach ($this->enemies as $enemy) {
|
||||
|
|
@ -174,7 +175,6 @@ class Battle
|
|||
|
||||
// 怪物攻击
|
||||
if ($this->enemiesAttack($out)) {
|
||||
Screen::delay(1000000, $out);
|
||||
$this->syncPartnerHp();
|
||||
return;
|
||||
}
|
||||
|
|
@ -182,7 +182,6 @@ class Battle
|
|||
} else {
|
||||
// 怪物先攻
|
||||
if ($this->enemiesAttack($out)) {
|
||||
Screen::delay(1000000, $out);
|
||||
$this->syncPartnerHp();
|
||||
return;
|
||||
}
|
||||
|
|
@ -203,8 +202,6 @@ class Battle
|
|||
Screen::delay(800000, $out);
|
||||
if ($result) break;
|
||||
}
|
||||
|
||||
Screen::delay(500000, $out);
|
||||
// 同步队友HP到Partner对象,然后保存状态
|
||||
$this->syncPartnerHp();
|
||||
$this->game->saveState();
|
||||
|
|
@ -212,37 +209,17 @@ class Battle
|
|||
}
|
||||
}
|
||||
|
||||
private function showEncounter($out)
|
||||
{
|
||||
Screen::clear($out);
|
||||
$out->writeln("");
|
||||
$out->writeln("{$this->yellow}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━{$this->reset}");
|
||||
$out->writeln("");
|
||||
$out->writeln(" {$this->red}⚔️ 遭遇敌人!{$this->reset}");
|
||||
$out->writeln("");
|
||||
|
||||
foreach ($this->enemies as $enemy) {
|
||||
$out->writeln(" {$this->bold}{$this->white}{$enemy->name}{$this->reset} {$this->cyan}Lv.{$enemy->level}{$this->reset}");
|
||||
}
|
||||
|
||||
$out->writeln("");
|
||||
$out->writeln("{$this->yellow}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━{$this->reset}");
|
||||
Screen::delay(1000000, $out); // 1秒
|
||||
}
|
||||
|
||||
private function renderBattleScreen($out, bool $playerFirst)
|
||||
{
|
||||
Screen::clear($out);
|
||||
$stats = $this->player->getStats();
|
||||
|
||||
$out->writeln("{$this->cyan}╔══════════════════════════════════════════╗{$this->reset}");
|
||||
$out->writeln("{$this->cyan}║{$this->reset} {$this->bold}第 {$this->round} 回合{$this->reset} {$this->white}[q] 逃跑{$this->reset} {$this->cyan}║{$this->reset}");
|
||||
$out->writeln("{$this->cyan}╠══════════════════════════════════════════╣{$this->reset}");
|
||||
$out->writeln("{$this->bold}第 {$this->round} 回合{$this->reset} {$this->white}[q] 逃跑{$this->reset} ");
|
||||
|
||||
// 敌人信息
|
||||
foreach ($this->enemies as $enemy) {
|
||||
if ($enemy->hp <= 0) {
|
||||
$out->writeln("{$this->cyan}║{$this->reset} {$this->red}💀{$this->reset} {$this->white}{$enemy->name}{$this->reset} {$this->red}[已击败]{$this->reset}");
|
||||
$out->writeln(" {$this->red}💀{$this->reset} {$this->white}{$enemy->name}{$this->reset} {$this->red}[已击败]{$this->reset}");
|
||||
continue;
|
||||
}
|
||||
$enemyStats = $enemy->getStats();
|
||||
|
|
@ -251,25 +228,25 @@ class Battle
|
|||
$enemyHpBar = $this->renderHpBar($enemyHpPercent, 15);
|
||||
$enemyHpText = $enemy->hp . "/" . $enemyMaxHp;
|
||||
|
||||
$out->writeln("{$this->cyan}║{$this->reset} {$this->red}👹{$this->reset} {$this->bold}{$enemy->name}{$this->reset} Lv.{$enemy->level}");
|
||||
$out->writeln("{$this->cyan}║{$this->reset} {$enemyHpBar} {$this->white}{$enemyHpText}{$this->reset}");
|
||||
$out->writeln("{$this->cyan}║{$this->reset} {$this->yellow}⚔️{$this->reset} {$enemyStats['patk']}/{$enemyStats['matk']} {$this->green}🛡️{$this->reset} {$enemyStats['pdef']}/{$enemyStats['mdef']} {$this->red}💥{$this->reset} {$enemyStats['crit']}/{$enemyStats['critdmg']}%");
|
||||
$out->writeln("{$this->red}👹{$this->reset} {$this->bold}{$enemy->name}{$this->reset} Lv.{$enemy->level}");
|
||||
$out->writeln("{$enemyHpBar} {$this->white}{$enemyHpText}{$this->reset}");
|
||||
$out->writeln("{$this->yellow}⚔️{$this->reset} {$enemyStats['patk']}/{$enemyStats['matk']} {$this->green}🛡️{$this->reset} {$enemyStats['pdef']}/{$enemyStats['mdef']} {$this->red}💥{$this->reset} {$enemyStats['crit']}/{$enemyStats['critdmg']}%");
|
||||
}
|
||||
|
||||
$out->writeln("{$this->cyan}║{$this->reset}");
|
||||
|
||||
$out->writeln("");
|
||||
|
||||
// VS 分隔
|
||||
$out->writeln("{$this->cyan}║{$this->reset} {$this->yellow}⚔️ VS ⚔️{$this->reset}");
|
||||
$out->writeln("{$this->cyan}║{$this->reset}");
|
||||
$out->writeln(" {$this->yellow}⚔️ VS ⚔️{$this->reset}");
|
||||
$out->writeln("");
|
||||
|
||||
// 玩家信息
|
||||
$playerHpPercent = $this->player->hp / $stats['maxHp'];
|
||||
$playerHpBar = $this->renderHpBar($playerHpPercent, 20);
|
||||
$playerHpText = $this->player->hp . "/" . $stats['maxHp'];
|
||||
$out->writeln("{$this->cyan}║{$this->reset} {$this->green}🧙{$this->reset} {$this->bold}玩家{$this->reset} Lv.{$this->player->level}");
|
||||
$out->writeln("{$this->cyan}║{$this->reset} {$playerHpBar} {$this->white}{$playerHpText}{$this->reset}");
|
||||
$out->writeln("{$this->cyan}║{$this->reset} {$this->blue}🔮 {$stats['mana']}/{$stats['maxMana']}{$this->reset}");
|
||||
$out->writeln("{$this->cyan}║{$this->reset} {$this->yellow}⚔️{$this->reset} {$stats['patk']}/{$stats['matk']} {$this->green}🛡️{$this->reset} {$stats['pdef']}/{$stats['mdef']} {$this->red}💥{$this->reset} {$stats['crit']}/{$stats['critdmg']}%");
|
||||
$out->writeln("{$this->green}🧙{$this->reset} {$this->bold}玩家{$this->reset} Lv.{$this->player->level}");
|
||||
$out->writeln("{$playerHpBar} {$this->white}{$playerHpText}{$this->reset}");
|
||||
$out->writeln("{$this->blue}🔮 {$stats['mana']}/{$stats['maxMana']}{$this->reset}");
|
||||
$out->writeln("{$this->yellow}⚔️{$this->reset} {$stats['patk']}/{$stats['matk']} {$this->green}🛡️{$this->reset} {$stats['pdef']}/{$stats['mdef']} {$this->red}💥{$this->reset} {$stats['crit']}/{$stats['critdmg']}%");
|
||||
|
||||
// 显示同伴信息
|
||||
foreach ($this->player->partners as $partner) {
|
||||
|
|
@ -281,20 +258,18 @@ class Battle
|
|||
$partnerHpText = $partnerHp . "/" . $partnerMaxHp;
|
||||
|
||||
$status = $partnerHp > 0 ? "" : " {$this->red}[倒下]{$this->reset}";
|
||||
$out->writeln("{$this->cyan}║{$this->reset} {$this->magenta}👤{$this->reset} {$partner->name} Lv.{$partner->level}{$status}");
|
||||
$out->writeln("{$this->cyan}║{$this->reset} {$partnerHpBar} {$this->white}{$partnerHpText}{$this->reset}");
|
||||
$out->writeln("{$this->cyan}║{$this->reset} {$this->blue}🔮 {$partnerStats['mana']}/{$partnerStats['maxMana']}{$this->reset}");
|
||||
$out->writeln("{$this->cyan}║{$this->reset} {$this->yellow}⚔️{$this->reset} {$partnerStats['patk']}/{$partnerStats['matk']} {$this->green}🛡️{$this->reset} {$partnerStats['pdef']}/{$partnerStats['mdef']} {$this->red}💥{$this->reset} {$partnerStats['crit']}/{$partnerStats['critdmg']}%");
|
||||
$out->writeln("{$this->magenta}👤{$this->reset} {$partner->name} Lv.{$partner->level}{$status}");
|
||||
$out->writeln("{$partnerHpBar} {$this->white}{$partnerHpText}{$this->reset}");
|
||||
$out->writeln("{$this->blue}🔮 {$partnerStats['mana']}/{$partnerStats['maxMana']}{$this->reset}");
|
||||
$out->writeln("{$this->yellow}⚔️{$this->reset} {$partnerStats['patk']}/{$partnerStats['matk']} {$this->green}🛡️{$this->reset} {$partnerStats['pdef']}/{$partnerStats['mdef']} {$this->red}💥{$this->reset} {$partnerStats['crit']}/{$partnerStats['critdmg']}%");
|
||||
}
|
||||
|
||||
$out->writeln("{$this->cyan}╠══════════════════════════════════════════╣{$this->reset}");
|
||||
$out->writeln("{$this->cyan}║{$this->reset} {$this->white}战斗日志:{$this->reset}");
|
||||
$out->writeln(" {$this->white}战斗日志:{$this->reset}");
|
||||
}
|
||||
|
||||
private function renderHpBar(float $percent, int $width): string
|
||||
{
|
||||
$filled = max((int)($percent * $width),0);
|
||||
$empty = max($width - $filled,0);
|
||||
$filled = max((int)($percent * $width), 0);
|
||||
$empty = max($width - $filled, 0);
|
||||
|
||||
// 根据血量百分比选择颜色
|
||||
if ($percent > 0.6) {
|
||||
|
|
@ -341,7 +316,7 @@ class Battle
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!$hasSpells || $this->player->mana < 15) {
|
||||
return 'attack';
|
||||
}
|
||||
|
|
@ -407,7 +382,7 @@ class Battle
|
|||
$threat += $target->getThreatBonus();
|
||||
|
||||
// 血量比例也会影响威胁值(血量越多越有威胁)
|
||||
$threat += (int)($stats['hp'] / $stats['maxHp'] * 10);
|
||||
$threat -= (int)($stats['hp'] / $stats['maxHp'] * 10);
|
||||
|
||||
return $threat;
|
||||
}
|
||||
|
|
@ -453,9 +428,9 @@ class Battle
|
|||
// 1. 分析战场状态
|
||||
$opponents = $this->getOpponents($actor);
|
||||
$allies = $this->getAllies($actor);
|
||||
|
||||
|
||||
$enemyCount = count($opponents);
|
||||
|
||||
|
||||
$lowHpAllies = [];
|
||||
foreach ($allies as $ally) {
|
||||
$status = $ally->getStats();
|
||||
|
|
@ -485,9 +460,9 @@ class Battle
|
|||
'cost' => $actualCost,
|
||||
'level' => $spellItem['enhanceLevel'] ?? 0
|
||||
];
|
||||
|
||||
|
||||
$type = $spellItem['spellType'] ?? 'damage_single';
|
||||
|
||||
|
||||
if (isset($availableSpells[$type])) {
|
||||
$availableSpells[$type][] = $spellData;
|
||||
}
|
||||
|
|
@ -529,7 +504,7 @@ class Battle
|
|||
$selected = $availableSpells['all'][array_rand($availableSpells['all'])];
|
||||
}
|
||||
|
||||
if ($selected && in_array($selected['item']['spellType'],['heal_aoe', 'heal_single']) && $lowHpCount == 0){
|
||||
if ($selected && in_array($selected['item']['spellType'], ['heal_aoe', 'heal_single']) && $lowHpCount == 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
|
|
@ -563,12 +538,12 @@ class Battle
|
|||
$casterName = ($caster instanceof Player) ? "你" : $caster->name;
|
||||
$actionVerb = ($caster instanceof Player) ? "施放" : "施放了";
|
||||
|
||||
$out->writeln("{$this->cyan}║{$this->reset} {$this->magenta}✦{$this->reset} {$casterName} {$actionVerb} {$qualityColor}{$name}{$this->reset}");
|
||||
$out->writeln("{$this->magenta}✦{$this->reset} {$casterName} {$actionVerb} {$qualityColor}{$name}{$this->reset}");
|
||||
|
||||
if ($isCrit) {
|
||||
$out->writeln("{$this->cyan}║{$this->reset} {$this->magenta}✨ {$this->red}{$this->bold}暴击!{$this->reset} 对 {$target->name} 造成 {$this->red}{$damage}{$this->reset} 点魔法伤害!");
|
||||
$out->writeln("{$this->magenta}✨ {$this->red}{$this->bold}暴击!{$this->reset} 对 {$target->name} 造成 {$this->red}{$damage}{$this->reset} 点魔法伤害!");
|
||||
} else {
|
||||
$out->writeln("{$this->cyan}║{$this->reset} {$this->magenta}✨ 对 {$target->name} 造成 {$this->green}{$damage}{$this->reset} 点魔法伤害");
|
||||
$out->writeln("{$this->magenta}✨ 对 {$target->name} 造成 {$this->green}{$damage}{$this->reset} 点魔法伤害");
|
||||
}
|
||||
|
||||
// 应用防护机制:防护角色承受更多伤害
|
||||
|
|
@ -579,12 +554,12 @@ class Battle
|
|||
// // 如果防护角色正在保护队友,需要显示保护效果
|
||||
// if ($target->isProtecting && $actualDamage > $damage) {
|
||||
// $extraDamage = $actualDamage - $damage;
|
||||
// $out->writeln("{$this->cyan}║{$this->reset} {$this->yellow}🛡️ 防护状态:额外承受 {$extraDamage} 伤害!{$this->reset}");
|
||||
// $out->writeln(" {$this->yellow}🛡️ 防护状态:额外承受 {$extraDamage} 伤害!{$this->reset}");
|
||||
// }
|
||||
|
||||
if ($target->hp <= 0) {
|
||||
$target->hp = 0;
|
||||
$out->writeln("{$this->cyan}║{$this->reset} {$this->red}💀 {$target->name} 被击败了!{$this->reset}");
|
||||
$out->writeln("{$this->red}💀 {$target->name} 被击败了!{$this->reset}");
|
||||
|
||||
// 如果是玩家击败了所有敌人
|
||||
if (($caster instanceof Player || $caster instanceof Partner) && empty($this->getAliveEnemies())) {
|
||||
|
|
@ -616,9 +591,9 @@ class Battle
|
|||
$casterName = ($caster instanceof Player) ? "你" : $caster->name;
|
||||
$actionVerb = ($caster instanceof Player) ? "施放" : "施放了";
|
||||
|
||||
$out->writeln("{$this->cyan}║{$this->reset} {$this->magenta}✦{$this->reset} {$casterName} {$actionVerb} {$qualityColor}{$name}{$this->reset}");
|
||||
$out->writeln("{$this->magenta}✦{$this->reset} {$casterName} {$actionVerb} {$qualityColor}{$name}{$this->reset}");
|
||||
|
||||
$out->writeln("{$this->cyan}║{$this->reset} {$this->magenta}✨ 魔法在整个战场爆炸!{$this->reset}");
|
||||
$out->writeln("{$this->magenta}✨ 魔法在整个战场爆炸!{$this->reset}");
|
||||
|
||||
$opponents = $this->getOpponents($caster);
|
||||
$allOpponentsDefeated = true;
|
||||
|
|
@ -629,30 +604,30 @@ class Battle
|
|||
$damageResult = SpellCalculator::calculateDamage($spellInfo, $stats, $enemy->getStats(), $damageBonus, true);
|
||||
$damage = $damageResult['damage'];
|
||||
|
||||
$out->writeln("{$this->cyan}║{$this->reset} {$enemy->name} 受到 {$damage} 点伤害");
|
||||
$out->writeln("{$enemy->name} 受到 {$damage} 点伤害");
|
||||
$enemy->hp -= $damage;
|
||||
|
||||
if ($enemy->hp <= 0) {
|
||||
$enemy->hp = 0;
|
||||
$out->writeln("{$this->cyan}║{$this->reset} {$this->red}💀 {$enemy->name} 被击败了!{$this->reset}");
|
||||
|
||||
$out->writeln("{$this->red}💀 {$enemy->name} 被击败了!{$this->reset}");
|
||||
|
||||
if ($enemy instanceof Player) {
|
||||
Screen::delay(500000, $out);
|
||||
$this->showDefeat($out, $caster);
|
||||
return true;
|
||||
Screen::delay(500000, $out);
|
||||
$this->showDefeat($out, $caster);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
$allOpponentsDefeated = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 更新同伴血量显示 (如果敌人是同伴)
|
||||
if (!($caster instanceof Player) && !($caster instanceof Partner)) {
|
||||
foreach ($this->player->partners as $partner) {
|
||||
if (isset($this->partnerHp[$partner->id])) {
|
||||
$this->partnerHp[$partner->id] = $partner->hp;
|
||||
}
|
||||
}
|
||||
foreach ($this->player->partners as $partner) {
|
||||
if (isset($this->partnerHp[$partner->id])) {
|
||||
$this->partnerHp[$partner->id] = $partner->hp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($allOpponentsDefeated && ($caster instanceof Player || $caster instanceof Partner) && empty($this->getAliveEnemies())) {
|
||||
|
|
@ -674,7 +649,7 @@ class Battle
|
|||
$allies = $this->getAllies($caster);
|
||||
$lowestHpRatio = 1.0;
|
||||
foreach ($allies as $ally) {
|
||||
$status = $ally->getStats();
|
||||
$status = $ally->getStats();
|
||||
$ratio = $status['hp'] / $status['maxHp'];
|
||||
if ($ratio < $lowestHpRatio) {
|
||||
$lowestHpRatio = $ratio;
|
||||
|
|
@ -692,20 +667,20 @@ class Battle
|
|||
$casterName = ($caster instanceof Player) ? "你" : $caster->name;
|
||||
$actionVerb = ($caster instanceof Player) ? "施放" : "施放了";
|
||||
|
||||
$out->writeln("{$this->cyan}║{$this->reset} {$this->green}✦{$this->reset} {$casterName} {$actionVerb} {$qualityColor}{$name}{$this->reset}");
|
||||
$out->writeln("{$this->green}✦{$this->reset} {$casterName} {$actionVerb} {$qualityColor}{$name}{$this->reset}");
|
||||
|
||||
|
||||
$healAmount = SpellCalculator::calculateHeal($spellInfo, $stats, $healBonus);
|
||||
|
||||
$actualHeal = $target->heal($healAmount);
|
||||
|
||||
|
||||
// 更新同伴血量显示
|
||||
if ($target instanceof Partner && isset($this->partnerHp[$target->id])) {
|
||||
$this->partnerHp[$target->id] = $target->hp;
|
||||
}
|
||||
|
||||
$targetName = ($target === $this->player) ? "你" : $target->name;
|
||||
$out->writeln("{$this->cyan}║{$this->reset} {$this->green}💚 {$targetName} 恢复了 {$actualHeal} 点生命值{$this->reset}");
|
||||
$out->writeln("{$this->green}💚 {$targetName} 恢复了 {$actualHeal} 点生命值{$this->reset}");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -722,28 +697,28 @@ class Battle
|
|||
$casterName = ($caster instanceof Player) ? "你" : $caster->name;
|
||||
$actionVerb = ($caster instanceof Player) ? "施放" : "施放了";
|
||||
|
||||
$out->writeln("{$this->cyan}║{$this->reset} {$this->green}✦{$this->reset} {$casterName} {$actionVerb} {$qualityColor}{$name}{$this->reset}");
|
||||
$out->writeln("{$this->green}✦{$this->reset} {$casterName} {$actionVerb} {$qualityColor}{$name}{$this->reset}");
|
||||
|
||||
|
||||
$healAmount = SpellCalculator::calculateHeal($spellInfo, $stats, $healBonus);
|
||||
|
||||
$allies = $this->getAllies($caster);
|
||||
|
||||
|
||||
foreach ($allies as $ally) {
|
||||
if ($ally->hp <= 0) continue;
|
||||
|
||||
|
||||
// 如果是施法者本人,全额治疗;如果是队友,80%效果
|
||||
$finalHeal = ($ally === $caster) ? $healAmount : (int)($healAmount * 0.9);
|
||||
|
||||
|
||||
$actualHeal = $ally->heal($finalHeal);
|
||||
|
||||
|
||||
// 更新同伴血量显示
|
||||
if ($ally instanceof Partner && isset($this->partnerHp[$ally->id])) {
|
||||
$this->partnerHp[$ally->id] = $ally->hp;
|
||||
}
|
||||
|
||||
$allyName = ($ally === $this->player) ? "你" : $ally->name;
|
||||
$out->writeln("{$this->cyan}║{$this->reset} {$this->green}💚 {$allyName} 恢复了 {$actualHeal} 点生命值{$this->reset}");
|
||||
$out->writeln("{$this->green}💚 {$allyName} 恢复了 {$actualHeal} 点生命值{$this->reset}");
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
@ -764,7 +739,7 @@ class Battle
|
|||
$casterName = ($caster instanceof Player) ? "你" : $caster->name;
|
||||
$actionVerb = ($caster instanceof Player) ? "施放" : "施放了";
|
||||
|
||||
$out->writeln("{$this->cyan}║{$this->reset} {$this->cyan}✦{$this->reset} {$casterName} {$actionVerb} {$qualityColor}{$name}{$this->reset}");
|
||||
$out->writeln("{$this->cyan}✦{$this->reset} {$casterName} {$actionVerb} {$qualityColor}{$name}{$this->reset}");
|
||||
|
||||
$subtype = $spellInfo['subtype'] ?? '';
|
||||
|
||||
|
|
@ -778,7 +753,7 @@ class Battle
|
|||
}
|
||||
} elseif ($subtype === 'defend') {
|
||||
// 简单的防御提升逻辑 (目前只是显示,实际效果需在伤害计算中支持buff)
|
||||
$out->writeln("{$this->cyan}║{$this->reset} {$this->cyan}🛡️ 防御力提升!{$this->reset}");
|
||||
$out->writeln("{$this->cyan}🛡️ 防御力提升!{$this->reset}");
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
@ -848,12 +823,12 @@ class Battle
|
|||
$protectingAlly->exitProtectMode();
|
||||
|
||||
$protectingName = ($protectingAlly instanceof Player) ? "你" : $protectingAlly->name;
|
||||
$out->writeln("{$this->cyan}║{$this->reset} {$this->yellow}🛡️{$this->reset} {$protectingName} 退出防护状态。{$this->reset}");
|
||||
$out->writeln(" {$this->yellow}🛡️{$this->reset} {$protectingName} 退出防护状态。{$this->reset}");
|
||||
|
||||
$actor->enterProtectMode();
|
||||
|
||||
$actorName = ($actor instanceof Player) ? "你" : $actor->name;
|
||||
$out->writeln("{$this->cyan}║{$this->reset} {$this->yellow}🛡️{$this->reset} {$actorName} 主动进入防护状态,为队友抗伤!{$this->reset}");
|
||||
$out->writeln("{$this->yellow}🛡️{$this->reset} {$actorName} 主动进入防护状态,为队友抗伤!{$this->reset}");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -862,7 +837,7 @@ class Battle
|
|||
$actor->enterProtectMode();
|
||||
|
||||
$actorName = ($actor instanceof Player) ? "你" : $actor->name;
|
||||
$out->writeln("{$this->cyan}║{$this->reset} {$this->yellow}🛡️{$this->reset} {$actorName} 主动进入防护状态,为队友抗伤!{$this->reset}");
|
||||
$out->writeln("{$this->yellow}🛡️{$this->reset} {$actorName} 主动进入防护状态,为队友抗伤!{$this->reset}");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -871,7 +846,7 @@ class Battle
|
|||
*/
|
||||
private function executeActorTurn(Actor $actor, $out): bool
|
||||
{
|
||||
if ($actor->hp <= 0){
|
||||
if ($actor->hp <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -896,7 +871,7 @@ class Battle
|
|||
|
||||
$spellInfo = $spellItem;
|
||||
$spellInfo['type'] = $type;
|
||||
|
||||
|
||||
$stats = $actor->getStats();
|
||||
|
||||
if ($type === 'damage_single') {
|
||||
|
|
@ -920,7 +895,7 @@ class Battle
|
|||
|
||||
$stats = $actor->getStats();
|
||||
$targetStats = $target->getStats();
|
||||
|
||||
|
||||
// 计算伤害
|
||||
$physicalDamage = max(1, $stats['patk'] - $targetStats['pdef']);
|
||||
// $magicDamage = max(0, $stats['matk'] - $targetStats['mdef']);
|
||||
|
|
@ -933,32 +908,25 @@ class Battle
|
|||
$actorName = ($actor instanceof Player) ? "你" : $actor->name;
|
||||
$targetName = ($target === $this->player) ? "你" : $target->name;
|
||||
$actionVerb = ($actor instanceof Player) ? "攻击" : "向 {$targetName} 发起攻击";
|
||||
|
||||
|
||||
if ($actor instanceof Player) {
|
||||
$out->writeln("{$this->cyan}║{$this->reset} {$this->green}➤{$this->reset} 你攻击 {$targetName}...");
|
||||
$out->writeln("{$this->green}➤{$this->reset} 你攻击 {$targetName}...");
|
||||
} else {
|
||||
$out->writeln("{$this->cyan}║{$this->reset} {$this->red}➤{$this->reset} {$actorName} {$actionVerb}...");
|
||||
$out->writeln("{$this->red}➤{$this->reset} {$actorName} {$actionVerb}...");
|
||||
}
|
||||
|
||||
if ($isCrit) {
|
||||
$damage = (int)($baseDamage * ($critDmg / 100));
|
||||
$out->writeln("{$this->cyan}║{$this->reset} {$this->red}💥 造成 {$damage} 点暴击伤害!{$this->reset}");
|
||||
$out->writeln("{$this->red}💥 造成 {$damage} 点暴击伤害!{$this->reset}");
|
||||
} else {
|
||||
$damage = $baseDamage;
|
||||
$out->writeln("{$this->cyan}║{$this->reset} {$this->white}⚔️ 造成 {$damage} 点伤害{$this->reset}");
|
||||
$out->writeln("{$this->white}⚔️ 造成 {$damage} 点伤害{$this->reset}");
|
||||
}
|
||||
|
||||
// 应用防护机制:防护角色承受更多伤害
|
||||
$actualDamage = (int)($damage * (1 + $target->getProtectDamageTakenBonus()));
|
||||
|
||||
$target->hp -= $damage;
|
||||
|
||||
// 如果防护角色正在保护队友,需要显示保护效果
|
||||
// if ($target->isProtecting && $actualDamage > $damage) {
|
||||
// $extraDamage = $actualDamage - $damage;
|
||||
// $out->writeln("{$this->cyan}║{$this->reset} {$this->yellow}🛡️ 防护状态:额外承受 {$extraDamage} 伤害!{$this->reset}");
|
||||
// }
|
||||
|
||||
|
||||
// 蓝量恢复机制
|
||||
// 攻击者恢复 15 点
|
||||
$actorRecovered = $actor->recoverMana(15);
|
||||
|
|
@ -972,14 +940,14 @@ class Battle
|
|||
|
||||
if ($target->hp <= 0) {
|
||||
$target->hp = 0;
|
||||
$out->writeln("{$this->cyan}║{$this->reset} {$this->red}💀 {$targetName} 倒下了!{$this->reset}");
|
||||
|
||||
$out->writeln("{$this->red}💀 {$targetName} 倒下了!{$this->reset}");
|
||||
|
||||
if (($actor instanceof Player || $actor instanceof Partner) && empty($this->getAliveEnemies())) {
|
||||
Screen::delay(500000, $out);
|
||||
$this->showVictory($out, $stats);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if ($target instanceof Player) {
|
||||
Screen::delay(500000, $out);
|
||||
$this->showDefeat($out, $actor);
|
||||
|
|
@ -1037,17 +1005,11 @@ class Battle
|
|||
private function showVictory($out, $stats)
|
||||
{
|
||||
Screen::clear($out);
|
||||
$out->writeln("");
|
||||
$out->writeln("{$this->yellow}╔══════════════════════════════════════════╗{$this->reset}");
|
||||
$out->writeln("{$this->yellow}║{$this->reset} {$this->yellow}║{$this->reset}");
|
||||
$out->writeln("{$this->yellow}║{$this->reset} {$this->green}{$this->bold}🎉 胜 利 ! 🎉{$this->reset} {$this->yellow}║{$this->reset}");
|
||||
$out->writeln("{$this->yellow}║{$this->reset} {$this->yellow}║{$this->reset}");
|
||||
$out->writeln("{$this->yellow}╠══════════════════════════════════════════╣{$this->reset}");
|
||||
|
||||
|
||||
$enemyNames = [];
|
||||
foreach ($this->enemies as $e) $enemyNames[] = $e->name;
|
||||
$out->writeln("{$this->yellow}║{$this->reset} 击败: {$this->white}" . implode(', ', array_unique($enemyNames)) . "{$this->reset}");
|
||||
$out->writeln("{$this->yellow}║{$this->reset} 血量: {$this->green}{$this->player->hp}{$this->reset}/{$stats['maxHp']}");
|
||||
$out->writeln("击败: {$this->white}" . implode(', ', array_unique($enemyNames)) . "{$this->reset}");
|
||||
$out->writeln("血量: {$this->green}{$this->player->hp}{$this->reset}/{$stats['maxHp']}");
|
||||
|
||||
// 汇总经验和灵石
|
||||
$totalExp = 0;
|
||||
|
|
@ -1083,6 +1045,9 @@ class Battle
|
|||
'heal' => $item['heal'],
|
||||
'quantity' => 1
|
||||
];
|
||||
}else{
|
||||
unset($item['rate']);
|
||||
$this->player->addItem($item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1093,7 +1058,7 @@ class Battle
|
|||
if ($this->player->gainExp($totalExp)) {
|
||||
$levelUpMsg = " {$this->yellow}🎊 升级! Lv.{$this->player->level}{$this->reset}";
|
||||
}
|
||||
$out->writeln("{$this->yellow}║{$this->reset} 经验: {$this->cyan}+{$totalExp}{$this->reset}{$levelUpMsg}");
|
||||
$out->writeln("经验: {$this->cyan}+{$totalExp}{$this->reset}{$levelUpMsg}");
|
||||
|
||||
// 同伴经验
|
||||
$alivePartners = $this->getAlivePartners();
|
||||
|
|
@ -1104,20 +1069,20 @@ class Battle
|
|||
if ($partner->gainExp($partnerExp)) {
|
||||
$partnerLevelUp = " {$this->yellow}🎊 升级! Lv.{$partner->level}{$this->reset}";
|
||||
}
|
||||
$out->writeln("{$this->yellow}║{$this->reset} {$this->magenta}{$partner->name}{$this->reset}: {$this->cyan}+{$partnerExp}{$this->reset}{$partnerLevelUp}");
|
||||
$out->writeln("{$this->magenta}{$partner->name}{$this->reset}: {$this->cyan}+{$partnerExp}{$this->reset}{$partnerLevelUp}");
|
||||
}
|
||||
}
|
||||
|
||||
// 灵石
|
||||
if ($totalStones > 0) {
|
||||
$this->player->addSpiritStones($totalStones);
|
||||
$out->writeln("{$this->yellow}║{$this->reset} 灵石: {$this->yellow}+{$totalStones}{$this->reset}");
|
||||
$out->writeln("灵石: {$this->yellow}+{$totalStones}{$this->reset}");
|
||||
}
|
||||
|
||||
// 恢复魔法值
|
||||
$manaRecover = (int)($this->player->maxMana * 0.3); // 恢复30%的最大魔法值
|
||||
$actualManaRecover = $this->player->recoverMana($manaRecover);
|
||||
$out->writeln("{$this->yellow}║{$this->reset} 魔法: {$this->magenta}+{$actualManaRecover}{$this->reset}");
|
||||
$out->writeln("魔法: {$this->magenta}+{$actualManaRecover}{$this->reset}");
|
||||
|
||||
// 恢复队友魔法值
|
||||
$alivePartners = $this->getAlivePartners();
|
||||
|
|
@ -1128,15 +1093,11 @@ class Battle
|
|||
}
|
||||
|
||||
if (!empty($allDrops)) {
|
||||
$out->writeln("{$this->yellow}║{$this->reset} {$this->white}掉落:{$this->reset}");
|
||||
$out->writeln("{$this->white}掉落:{$this->reset}");
|
||||
foreach ($allDrops as $item) {
|
||||
$out->writeln(Item::show($item));
|
||||
}
|
||||
}
|
||||
|
||||
$out->writeln("{$this->yellow}╚══════════════════════════════════════════╝{$this->reset}");
|
||||
$out->writeln("");
|
||||
|
||||
$this->game->saveState();
|
||||
Screen::delay(1500000, $out);
|
||||
}
|
||||
|
|
@ -1145,19 +1106,8 @@ class Battle
|
|||
{
|
||||
Screen::clear($out);
|
||||
$killerName = $killer ? $killer->name : "敌人";
|
||||
|
||||
$out->writeln("");
|
||||
$out->writeln("{$this->red}╔══════════════════════════════════════════╗{$this->reset}");
|
||||
$out->writeln("{$this->red}║{$this->reset} {$this->red}║{$this->reset}");
|
||||
$out->writeln("{$this->red}║{$this->reset} {$this->red}{$this->bold}💀 战 败 ! 💀{$this->reset} {$this->red}║{$this->reset}");
|
||||
$out->writeln("{$this->red}║{$this->reset} {$this->red}║{$this->reset}");
|
||||
$out->writeln("{$this->red}╠══════════════════════════════════════════╣{$this->reset}");
|
||||
$out->writeln("{$this->red}║{$this->reset} 你被 {$this->white}{$killerName}{$this->reset} 击败了...");
|
||||
$out->writeln("{$this->red}║{$this->reset}");
|
||||
$out->writeln("{$this->red}║{$this->reset} {$this->white}不要气馁,休整后再战!{$this->reset}");
|
||||
$out->writeln("{$this->red}╚══════════════════════════════════════════╝{$this->reset}");
|
||||
$out->writeln("");
|
||||
|
||||
$out->writeln("你被 {$this->white}{$killerName}{$this->reset} 击败了...");
|
||||
$out->writeln("{$this->white}不要气馁,休整后再战!{$this->reset}");
|
||||
$this->game->state = Game::MENU;
|
||||
Screen::pause($out);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,12 +97,7 @@ class InventoryPanel
|
|||
foreach ($pageItems as $i => $item) {
|
||||
$index = $start + $i + 1;
|
||||
// 装备使用 ItemDisplay 显示
|
||||
if ($item['type'] == 'quest_item'){
|
||||
|
||||
}else{
|
||||
$displayStr = Item::show($item);
|
||||
}
|
||||
|
||||
$displayStr = Item::show($item);
|
||||
$out->writeln("[{$index}] {$displayStr}");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<?php
|
||||
namespace Game\Modules;
|
||||
|
||||
use Game\Core\Colors;
|
||||
use Game\Core\Screen;
|
||||
use Game\Core\Input;
|
||||
use Game\Core\Game;
|
||||
|
|
@ -14,7 +15,7 @@ class Menu
|
|||
Screen::clear($this->game->output);
|
||||
|
||||
$out = $this->game->output;
|
||||
$out->writeln("=========================");
|
||||
$out->writeln(Colors::RESET."=========================");
|
||||
$out->writeln("[1] 开始战斗");
|
||||
$out->writeln("[2] 属性面板");
|
||||
$out->writeln("[3] 背包");
|
||||
|
|
|
|||
|
|
@ -6,8 +6,10 @@ use Game\Modules\Bag\Spell;
|
|||
require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
|
||||
$res = \Game\Entities\Monster::create(1);
|
||||
dd($res);
|
||||
$data = file_get_contents('/Users/hant/MyData/study/idle/src/Data/map.json');
|
||||
$data = json_decode($data,true);
|
||||
$data = array_column($data,'key_item');
|
||||
file_put_contents('/Users/hant/MyData/study/idle/src/Data/quest.json',json_encode($data,JSON_UNESCAPED_UNICODE));
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
140
web/server.php
140
web/server.php
|
|
@ -4,9 +4,21 @@
|
|||
* 使用方法: php -S 0.0.0.0:8080 web/server.php
|
||||
*/
|
||||
|
||||
// 设置错误报告
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', 0);
|
||||
|
||||
// 自动加载
|
||||
require_once __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
|
||||
use Game\Core\UserManager;
|
||||
|
||||
|
||||
|
||||
// 启动会话
|
||||
session_start();
|
||||
|
||||
// 设置响应头
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
header('Access-Control-Allow-Origin: *');
|
||||
|
|
@ -26,29 +38,117 @@ $path = parse_url($requestUri, PHP_URL_PATH);
|
|||
// 静态文件处理
|
||||
if ($path === '/' || $path === '/process.html') {
|
||||
header('Content-Type: text/html; charset=utf-8');
|
||||
echo '<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>凡人修仙传 - Web Terminal Edition</title>
|
||||
<style>
|
||||
body { font-family: monospace; background: #000; color: #0f0; margin: 0; padding: 20px; }
|
||||
#game { height: 600px; overflow-y: auto; border: 1px solid #0f0; padding: 10px; margin-bottom: 10px; }
|
||||
input { background: #000; color: #0f0; border: 1px solid #0f0; padding: 5px; width: 100%; box-sizing: border-box; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="game">游戏初始化中...</div>
|
||||
<input type="text" id="input" placeholder="输入命令..." autofocus>
|
||||
<script>
|
||||
console.log("Web game interface loaded");
|
||||
</script>
|
||||
</body>
|
||||
</html>';
|
||||
readfile(__DIR__ . '/process.html');
|
||||
exit;
|
||||
}
|
||||
|
||||
// API 路由
|
||||
$response = ['success' => true, 'message' => 'Web server is running. This is a CLI-based game.'];
|
||||
$response = ['success' => false, 'message' => '未知请求'];
|
||||
|
||||
try {
|
||||
switch ($path) {
|
||||
case '/api/register':
|
||||
$response = handleRegister();
|
||||
break;
|
||||
|
||||
case '/api/login':
|
||||
$response = handleLogin();
|
||||
break;
|
||||
|
||||
case '/api/logout':
|
||||
$response = handleLogout();
|
||||
break;
|
||||
|
||||
case '/api/status':
|
||||
$response = handleStatus();
|
||||
break;
|
||||
|
||||
default:
|
||||
// 检查是否是静态文件
|
||||
$filePath = __DIR__ . $path;
|
||||
if (file_exists($filePath) && is_file($filePath)) {
|
||||
$ext = pathinfo($path, PATHINFO_EXTENSION);
|
||||
$mimeTypes = [
|
||||
'js' => 'application/javascript',
|
||||
'css' => 'text/css',
|
||||
'html' => 'text/html',
|
||||
'png' => 'image/png',
|
||||
'jpg' => 'image/jpeg',
|
||||
'gif' => 'image/gif',
|
||||
];
|
||||
header('Content-Type: ' . ($mimeTypes[$ext] ?? 'application/octet-stream'));
|
||||
readfile($filePath);
|
||||
exit;
|
||||
}
|
||||
http_response_code(404);
|
||||
$response = ['success' => false, 'message' => '未找到'];
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
http_response_code(500);
|
||||
$response = ['success' => false, 'message' => '服务器错误: ' . $e->getMessage()];
|
||||
}
|
||||
|
||||
http_response_code(200);
|
||||
echo json_encode($response, JSON_UNESCAPED_UNICODE);
|
||||
|
||||
// ============ 处理函数 ============
|
||||
|
||||
function getInput(): array
|
||||
{
|
||||
$input = file_get_contents('php://input');
|
||||
return json_decode($input, true) ?? [];
|
||||
}
|
||||
|
||||
function handleRegister(): array
|
||||
{
|
||||
$data = getInput();
|
||||
$username = $data['username'] ?? '';
|
||||
$password = $data['password'] ?? '';
|
||||
|
||||
$userManager = new UserManager();
|
||||
$result = $userManager->register($username, $password);
|
||||
|
||||
if ($result['success']) {
|
||||
$_SESSION['user_id'] = $result['userId'];
|
||||
$_SESSION['username'] = $username;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
function handleLogin(): array
|
||||
{
|
||||
$data = getInput();
|
||||
$username = $data['username'] ?? '';
|
||||
$password = $data['password'] ?? '';
|
||||
|
||||
$userManager = new UserManager();
|
||||
$result = $userManager->login($username, $password);
|
||||
|
||||
if ($result['success']) {
|
||||
$_SESSION['user_id'] = $result['userId'];
|
||||
$_SESSION['username'] = $username;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
function handleLogout(): array
|
||||
{
|
||||
session_destroy();
|
||||
return ['success' => true, 'message' => '已退出登录'];
|
||||
}
|
||||
|
||||
function handleStatus(): array
|
||||
{
|
||||
if (empty($_SESSION['user_id'])) {
|
||||
return ['success' => false, 'loggedIn' => false, 'message' => '未登录'];
|
||||
}
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'loggedIn' => true,
|
||||
'userId' => $_SESSION['user_id'],
|
||||
'username' => $_SESSION['username'] ?? '未知',
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user