This commit is contained in:
hant 2025-12-07 22:01:41 +08:00
parent 8014ba64e6
commit d63e756265
7 changed files with 42 additions and 121 deletions

File diff suppressed because one or more lines are too long

View File

@ -70,6 +70,7 @@ class Game
$p = $data['player'] ?? [];
$this->player->hp = $p['hp'] ?? $this->player->hp;
$this->player->maxHp = $p['maxHp'] ?? $this->player->maxHp;
$this->player->potionPool = $p['potionPool'] ?? $this->player->potionPool;
// 新属性系统,向后兼容旧存档
$this->player->patk = $p['patk'] ?? $p['atk'] ?? $this->player->patk;
$this->player->matk = $p['matk'] ?? $this->player->matk;
@ -103,7 +104,7 @@ class Game
$this->player->skillSlots = $p['skillSlots'] ?? $this->player->skillSlots;
$this->dungeonId = $data['dungeonId'] ?? $this->dungeonId;
$this->state = $data['state'] ?? self::MENU;
$this->state = self::MENU;
}
}
}
@ -150,6 +151,7 @@ class Game
'critdmg' => $this->player->critdmg,
'level' => $this->player->level,
'exp' => $this->player->exp,
'potionPool' => $this->player->potionPool,
'maxExp' => $this->player->maxExp,
'inventory' => $this->player->inventory,
'equip' => $this->player->equip,
@ -201,7 +203,6 @@ class Game
$this->saveState();
return;
}
$this->saveState();
}
}
}

View File

@ -154,7 +154,7 @@ class GameProcessServer implements MessageComponentInterface
$type = $data['type'] ?? null;
$input = $data['input'] ?? '';
if ($type === 'input' && $input) {
if ($type === 'input') {
// 将输入写入进程的STDIN
$process = $this->processes[$from->resourceId] ?? null;
if ($process && is_resource($process['stdin'])) {

View File

@ -373,7 +373,10 @@ class ItemDisplay
{
$quality = $item['quality'] ?? $item['rarity'] ?? 'common';
$color = self::getQualityColor($quality);
$name = ($item['name'] ?? '未知物品') . 'lv.' . $item['level'];
if ($item['type'] == 'potion_pool'){
return self::$green .$item['name'] . '+' .$item['heal'];
}
$name = ($item['name'] ?? '未知物品') . 'lv.' . ($item['level'] ?? '');
$enhanceLevel = $item['enhanceLevel'] ?? 0;
$enhanceStr = $enhanceLevel > 0 ? self::$yellow . "+{$enhanceLevel}" . self::$reset : "";

View File

@ -61,7 +61,7 @@ class Player extends Actor
public function consumePotionPool(int $amount): int
{
$consumed = min($amount, $this->potionPool);
$this->potionPool -= $consumed;
$this->potionPool = max(0,$this->potionPool - $amount);
return $consumed;
}

View File

@ -76,9 +76,14 @@ class InventoryPanel
if (empty($items)) {
$out->writeln("该分类下没有物品...");
$out->writeln("");
$out->writeln("[h] 使用小绿瓶回血");
$out->writeln("[c] 切换分类 | [0] 返回");
$choice = Screen::input($out, "选择操作:");
if ($choice === 'h'){
$this->autoHeal();
return $this->show($page, $category);
}
if ($choice === "c" || $choice === "C") {
return $this->showCategoryMenu($page, $category);
}
@ -243,6 +248,11 @@ class InventoryPanel
// 从小绿瓶池获取实际恢复量
$healAmount = $item['heal'];
$actualPotionHeal = $player->consumePotionPool($healAmount);
if ($actualPotionHeal == 0){
$out->writeln("小绿瓶已用尽");
Screen::sleep(1);
return;
}
$actualHeal = $player->heal($actualPotionHeal);
$out->writeln("你使用了 {$item['name']},从小绿瓶中恢复了 {$actualHeal} HP(当前: {$player->hp}/{$maxHp})");
$out->writeln("小绿瓶剩余: {$player->potionPool}");
@ -253,6 +263,11 @@ class InventoryPanel
// 从小绿瓶池获取实际恢复量
$healAmount = $item['heal'];
$actualPotionHeal = $player->consumePotionPool($healAmount);
if ($actualPotionHeal == 0){
$out->writeln("小绿瓶已用尽");
Screen::sleep(1);
return;
}
$actualHeal = $target->heal($actualPotionHeal);
$out->writeln("你使用了 {$item['name']} 来恢复 {$target->name},从小绿瓶中恢复了 {$actualHeal} HP(当前: {$target->hp}/{$partnerMaxHp})");
$out->writeln("小绿瓶剩余: {$player->potionPool}");
@ -387,87 +402,29 @@ class InventoryPanel
return;
}
// 获取所有消耗品并按治疗量排序(优先使用小瓶)
$consumables = [];
foreach ($player->inventory as $index => $item) {
if (($item['type'] ?? '') === 'consume' && ($item['heal'] ?? 0) > 0) {
$consumables[] = ['index' => $index, 'item' => $item];
}
}
if (empty($consumables)) {
$out->writeln("没有可用的回复药品!");
Screen::sleep(1);
return;
}
// 按治疗量从小到大排序(优先使用小瓶,避免浪费)
usort($consumables, fn($a, $b) => ($a['item']['heal'] ?? 0) <=> ($b['item']['heal'] ?? 0));
$totalHealed = 0;
$itemsUsed = 0;
$healLog = [];
// 回复玩家
while ($playerNeedsHeal && $player->hp < $playerMaxHp && !empty($consumables)) {
while ($playerNeedsHeal && $player->hp < $playerMaxHp) {
// 计算需要恢复的量
$needHeal = $playerMaxHp - $player->hp;
// 找到最合适的药品(不浪费或浪费最少的)
$bestIndex = null;
$bestWaste = PHP_INT_MAX;
foreach ($consumables as $i => $c) {
$healAmount = $c['item']['heal'] ?? 0;
$waste = max(0, $healAmount - $needHeal);
if ($waste < $bestWaste) {
$bestWaste = $waste;
$bestIndex = $i;
}
// 如果找到完美匹配或不浪费的,直接使用
if ($waste === 0) break;
}
if ($bestIndex === null) break;
$selected = $consumables[$bestIndex];
$inventoryIndex = $selected['index'];
$item = $selected['item'];
// 使用药品,从小绿瓶池里扣除
$actualPotionHeal = $player->consumePotionPool($item['heal']);
$actualPotionHeal = $player->consumePotionPool($needHeal);
if ($actualPotionHeal == 0){
$out->writeln("小绿瓶已用尽");
Screen::sleep(1);
return;
}
$actualHeal = $player->heal($actualPotionHeal);
$totalHealed += $actualHeal;
$itemsUsed++;
$healLog[] = "玩家: +{$actualHeal} HP";
// 减少数量或移除物品
if (($player->inventory[$inventoryIndex]['quantity'] ?? 1) > 1) {
$player->inventory[$inventoryIndex]['quantity']--;
$consumables[$bestIndex]['item']['quantity']--;
} else {
unset($player->inventory[$inventoryIndex]);
unset($consumables[$bestIndex]);
$consumables = array_values($consumables);
}
// 重新整理背包索引
$player->inventory = array_values($player->inventory);
// 更新 consumables 的索引引用
$consumables = [];
foreach ($player->inventory as $index => $invItem) {
if (($invItem['type'] ?? '') === 'consume' && ($invItem['heal'] ?? 0) > 0) {
$consumables[] = ['index' => $index, 'item' => $invItem];
}
}
usort($consumables, fn($a, $b) => ($a['item']['heal'] ?? 0) <=> ($b['item']['heal'] ?? 0));
}
// 回复队友(按需要程度优先恢复)
if (!empty($partnersNeedHeal) && !empty($consumables)) {
if (!empty($partnersNeedHeal)) {
// 按需要治疗量从大到小排序(优先治疗伤势最重的)
usort($partnersNeedHeal, fn($a, $b) => $b['needHeal'] <=> $a['needHeal']);
@ -475,60 +432,20 @@ class InventoryPanel
$partner = $healData['partner'];
$partnerMaxHp = $healData['maxHp'];
while ($partner->hp < $partnerMaxHp && !empty($consumables)) {
while ($partner->hp < $partnerMaxHp) {
// 计算需要恢复的量
$needHeal = $partnerMaxHp - $partner->hp;
// 找到最合适的药品
$bestIndex = null;
$bestWaste = PHP_INT_MAX;
foreach ($consumables as $i => $c) {
$healAmount = $c['item']['heal'] ?? 0;
$waste = max(0, $healAmount - $needHeal);
if ($waste < $bestWaste) {
$bestWaste = $waste;
$bestIndex = $i;
}
if ($waste === 0) break;
}
if ($bestIndex === null) break;
$selected = $consumables[$bestIndex];
$inventoryIndex = $selected['index'];
$item = $selected['item'];
// 使用药品回复队友,从小绿瓶池里扣除
$actualPotionHeal = $player->consumePotionPool($item['heal']);
$actualPotionHeal = $player->consumePotionPool($needHeal);
if ($actualPotionHeal == 0){
$out->writeln("小绿瓶已用尽");
Screen::sleep(1);
return;
}
$actualHeal = $partner->heal($actualPotionHeal);
$totalHealed += $actualHeal;
$itemsUsed++;
$healLog[] = "{$partner->name}: +{$actualHeal} HP";
// 减少数量或移除物品
if (($player->inventory[$inventoryIndex]['quantity'] ?? 1) > 1) {
$player->inventory[$inventoryIndex]['quantity']--;
$consumables[$bestIndex]['item']['quantity']--;
} else {
unset($player->inventory[$inventoryIndex]);
unset($consumables[$bestIndex]);
$consumables = array_values($consumables);
}
// 重新整理背包索引
$player->inventory = array_values($player->inventory);
// 更新 consumables 的索引引用
$consumables = [];
foreach ($player->inventory as $index => $invItem) {
if (($invItem['type'] ?? '') === 'consume' && ($invItem['heal'] ?? 0) > 0) {
$consumables[] = ['index' => $index, 'item' => $invItem];
}
}
usort($consumables, fn($a, $b) => ($a['item']['heal'] ?? 0) <=> ($b['item']['heal'] ?? 0));
}
}
}
@ -540,7 +457,7 @@ class InventoryPanel
$out->writeln("╔════════════════════════════════════╗");
$out->writeln("║ 一键回血结果 ║");
$out->writeln("╚════════════════════════════════════╝");
$out->writeln("使用了 {$itemsUsed} 个药品,共恢复 {$totalHealed} HP");
$out->writeln("共恢复 {$totalHealed} HP");
$out->writeln("");
$out->writeln("治疗详情:");
foreach ($healLog as $log) {

View File

@ -279,7 +279,7 @@
}
switch (data.type) {
case 'output':
terminal.clear();
// terminal.clear();
const lines = data.text.split('\n');
lines.forEach(line => {
terminal.writeln(line);