- Partner 现在继承 Actor,获得统一的天赋、法术和属性系统
- Partner 覆盖 talentBonus 为自己的特殊值(hp 20, critdmg 10)
- Partner 覆盖 getStats() 以支持自定义的 baseStats 和 growth 系数
- Partner 保留特有的 autoAllocateTalent() 方法(私有,确保 HP 至少加1点)
- Partner 覆盖 gainExp() 以调用自己的 autoAllocateTalent()
- 删除重复的方法:heal(), recoverMana(), spendMana(), learnSpell()
- 保留特有方法:getTotalTalentPoints(), hasSpell(), getSpellLevel()
- 简化 Partner 构造函数,使用 Actor 的属性
统一体系:所有 Actor 子类(Player, Partner, Monster, NPC)都继承同一套天赋和属性系统
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
247 lines
6.1 KiB
PHP
247 lines
6.1 KiB
PHP
<?php
|
||
namespace Game\Entities;
|
||
|
||
use Game\Entities\Partner;
|
||
|
||
class Player extends Actor
|
||
{
|
||
|
||
// Player特有的天赋名称
|
||
public static array $talentNames = [
|
||
'hp' => '生命',
|
||
'patk' => '物攻',
|
||
'matk' => '魔攻',
|
||
'pdef' => '物防',
|
||
'mdef' => '魔防',
|
||
'crit' => '暴击',
|
||
'critdmg' => '暴伤',
|
||
];
|
||
|
||
// Player特有的NPC交互标记
|
||
public array $npcFlags = [];
|
||
|
||
// Player特有的同伴系统
|
||
public int $maxPartners = 2; // 最多可携带同伴数
|
||
public array $partners = []; // 已招募的同伴
|
||
|
||
/**
|
||
* 增加灵石
|
||
*/
|
||
public function addSpiritStones(int $amount): void
|
||
{
|
||
$this->spiritStones += $amount;
|
||
}
|
||
|
||
/**
|
||
* 扣除灵石(返回是否成功)
|
||
*/
|
||
public function spendSpiritStones(int $amount): bool
|
||
{
|
||
if ($this->spiritStones >= $amount) {
|
||
$this->spiritStones -= $amount;
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* 恢复生命值,不超过上限
|
||
* @param int $amount 恢复量
|
||
* @return int 实际恢复量
|
||
*/
|
||
public function heal(int $amount): int
|
||
{
|
||
$stats = $this->getStats();
|
||
$maxHp = $stats['maxHp'];
|
||
|
||
$oldHp = $this->hp;
|
||
$this->hp = min($this->hp + $amount, $maxHp);
|
||
|
||
return $this->hp - $oldHp;
|
||
}
|
||
|
||
/**
|
||
* 学习法术
|
||
*/
|
||
public function learnSpell(int $spellId): bool
|
||
{
|
||
if (!isset($this->spells[$spellId])) {
|
||
$this->spells[$spellId] = ['level' => 1];
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* 升级法术等级
|
||
*/
|
||
public function upgradeSpell(int $spellId): bool
|
||
{
|
||
if (!isset($this->spells[$spellId])) {
|
||
return false;
|
||
}
|
||
$this->spells[$spellId]['level'] = min($this->spells[$spellId]['level'] + 1, 10);
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* 检查是否已学习法术
|
||
*/
|
||
public function hasSpell(int $spellId): bool
|
||
{
|
||
return isset($this->spells[$spellId]);
|
||
}
|
||
|
||
/**
|
||
* 获取法术等级
|
||
*/
|
||
public function getSpellLevel(int $spellId): int
|
||
{
|
||
return $this->spells[$spellId]['level'] ?? 0;
|
||
}
|
||
|
||
/**
|
||
* 添加法术资源书
|
||
*/
|
||
public function addSpellBook(int $spellId, int $quantity = 1): void
|
||
{
|
||
if (!isset($this->spellBooks[$spellId])) {
|
||
$this->spellBooks[$spellId] = 0;
|
||
}
|
||
$this->spellBooks[$spellId] += $quantity;
|
||
}
|
||
|
||
/**
|
||
* 消耗法术资源书
|
||
*/
|
||
public function spendSpellBooks(int $spellId, int $quantity = 1): bool
|
||
{
|
||
if (($this->spellBooks[$spellId] ?? 0) >= $quantity) {
|
||
$this->spellBooks[$spellId] -= $quantity;
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* 获取法术资源书数量
|
||
*/
|
||
public function getSpellBookCount(int $spellId): int
|
||
{
|
||
return $this->spellBooks[$spellId] ?? 0;
|
||
}
|
||
|
||
/**
|
||
* Player特有的经验获取,升级时会恢复生命值
|
||
*/
|
||
public function gainExp(int $amount): bool
|
||
{
|
||
$this->exp += $amount;
|
||
if ($this->exp >= $this->maxExp) {
|
||
$this->level++;
|
||
$this->exp -= $this->maxExp;
|
||
$this->maxExp = (int)($this->maxExp * 1.5);
|
||
|
||
// 升级获得天赋点(每级3点)并通过 autoAllocateTalents 自动分配
|
||
$this->autoAllocateTalents(3);
|
||
|
||
// 升级时恢复全部生命值
|
||
$this->fullHeal();
|
||
|
||
return true; // Leveled up
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* Player特有的分配天赋点(返回布尔值)
|
||
*/
|
||
public function allocateTalent(string $talent, int $points = 1): bool
|
||
{
|
||
if ($points <= 0 || $this->talentPoints < $points) {
|
||
return false;
|
||
}
|
||
|
||
if (!isset($this->talents[$talent])) {
|
||
return false;
|
||
}
|
||
|
||
$this->talents[$talent] += $points;
|
||
$this->talentPoints -= $points;
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* Player特有的重置天赋(返还所有点数)
|
||
*/
|
||
public function resetTalents(): int
|
||
{
|
||
$total = array_sum($this->talents);
|
||
$this->talentPoints += $total;
|
||
|
||
foreach ($this->talents as $key => $value) {
|
||
$this->talents[$key] = 0;
|
||
}
|
||
|
||
return $total;
|
||
}
|
||
|
||
public function addItem(array $item)
|
||
{
|
||
// Handle stacking for consumables
|
||
if (($item['type'] ?? '') === 'consume') {
|
||
foreach ($this->inventory as &$existingItem) {
|
||
// Check if it's the same item (compare name, heal, quality, level)
|
||
// We exclude 'id' and 'quantity' from comparison
|
||
$isSame = ($existingItem['name'] === $item['name']) &&
|
||
(($existingItem['heal'] ?? 0) === ($item['heal'] ?? 0)) &&
|
||
(($existingItem['quality'] ?? '') === ($item['quality'] ?? '')) &&
|
||
(($existingItem['level'] ?? 1) === ($item['level'] ?? 1));
|
||
|
||
if ($isSame) {
|
||
$existingItem['quantity'] = ($existingItem['quantity'] ?? 1) + 1;
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
|
||
// Assign a unique ID to the item to handle duplicates
|
||
$item['id'] = uniqid();
|
||
// Initialize quantity for new items
|
||
$item['quantity'] = 1;
|
||
$this->inventory[] = $item;
|
||
}
|
||
|
||
/**
|
||
* 招募同伴
|
||
*/
|
||
public function recruitPartner(Partner $partner): bool
|
||
{
|
||
if (count($this->partners) >= $this->maxPartners) {
|
||
return false;
|
||
}
|
||
$this->partners[$partner->id] = $partner;
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* 解散同伴
|
||
*/
|
||
public function dismissPartner(string $partnerId): bool
|
||
{
|
||
if (isset($this->partners[$partnerId])) {
|
||
unset($this->partners[$partnerId]);
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* 获取同伴
|
||
*/
|
||
public function getPartner(string $partnerId): ?Partner
|
||
{
|
||
return $this->partners[$partnerId] ?? null;
|
||
}
|
||
}
|