This commit is contained in:
hantao 2025-12-23 20:22:14 +08:00
parent 09383708de
commit 2a8b44765c
15 changed files with 437 additions and 197 deletions

View File

@ -1,18 +1,29 @@
[
{
"id": "FIREBALL",
"name": "火球术",
"type": "damage",
"mana_cost": 10,
"power": 25,
"scaling": "mana"
},
{
"id": "HEAL",
"name": "初级治疗",
"type": "heal",
"mana_cost": 8,
{
"ABILITY_01": {
"id": "ABILIT_01",
"name": "基础剑法",
"description": "七玄门基础剑法,简单实用。",
"type": "attack",
"cost": 5,
"power": 15,
"scaling": "mana"
"cooldown": 1
},
"ABILIT_02": {
"id": "ABILIT_02",
"name": "长春功",
"description": "墨大夫传授的神秘功法,可以恢复生命。",
"type": "heal",
"cost": 10,
"power": 25,
"cooldown": 2
},
"ABILIT_03": {
"id": "ABILIT_03",
"name": "灵力护盾",
"description": "初级防护技能,可以减少受到的伤害。",
"type": "defense",
"cost": 8,
"power": 10,
"cooldown": 3
}
]
}

View File

@ -1,42 +1,63 @@
[
{
{
"GOBLIN": {
"id": "GOBLIN",
"name": "哥布林",
"name": "七玄门守卫",
"health": 30,
"attack": 8,
"defense": 2,
"xp_reward": 20,
"min_gold": 5,
"max_gold": 15,
"loot_table": [
{
"item_id": 1,
"chance": 70
},
{
"item_id": 2,
"chance": 10
}
"xp": 15,
"loot": [
{"id": "ZHENGBI", "chance": 0.8, "amount": {"min": 1, "max": 5}},
{"id": "POTION_01", "chance": 0.3, "amount": {"min": 1, "max": 1}}
]
},
{
"WOLF": {
"id": "WOLF",
"name": "野狼",
"health": 45,
"attack": 12,
"name": "山中野狼",
"health": 25,
"attack": 10,
"defense": 1,
"xp_reward": 35,
"min_gold": 10,
"max_gold": 25,
"loot_table": [
{
"item_id": 1,
"chance": 50
},
{
"item_id": 4,
"chance": 20
}
"xp": 12,
"loot": [
{"id": "CAOYAO", "chance": 0.5, "amount": {"min": 1, "max": 2}},
{"id": "ZHENGBI", "chance": 0.6, "amount": {"min": 1, "max": 3}}
]
},
"BEAR": {
"id": "BEAR",
"name": "山中巨熊",
"health": 50,
"attack": 15,
"defense": 3,
"xp": 25,
"loot": [
{"id": "CAOYAO", "chance": 0.7, "amount": {"min": 2, "max": 4}},
{"id": "ZHENGBI", "chance": 0.8, "amount": {"min": 3, "max": 8}}
]
},
"STRANGE_CULTIVATOR": {
"id": "STRANGE_CULTIVATOR",
"name": "神秘修士",
"health": 60,
"attack": 20,
"defense": 5,
"xp": 40,
"loot": [
{"id": "POTION_03", "chance": 0.4, "amount": {"min": 1, "max": 1}},
{"id": "CAOYAO", "chance": 0.8, "amount": {"min": 1, "max": 3}},
{"id": "ZHENGBI", "chance": 1.0, "amount": {"min": 5, "max": 15}}
]
},
"GUARD": {
"id": "GUARD",
"name": "地牢守卫",
"health": 40,
"attack": 12,
"defense": 4,
"xp": 20,
"loot": [
{"id": "WEAPON_01", "chance": 0.2, "amount": {"min": 1, "max": 1}},
{"id": "ZHENGBI", "chance": 0.9, "amount": {"min": 2, "max": 6}}
]
}
]
}

View File

@ -1,18 +0,0 @@
[
{
"name": "森林哥布林",
"health": 30,
"attack": 10,
"defense": 5,
"xp": 25,
"dropId": 1
},
{
"name": "愤怒的野猪",
"health": 45,
"attack": 15,
"defense": 5,
"xp": 40,
"dropId": 2
}
]

View File

@ -1,38 +1,80 @@
[
{
{
"POTION_01": {
"id": 1,
"name": "小型治疗药",
"name": "药",
"type": "potion",
"description": "恢复少量生命。",
"description": "普通的疗伤药,可以恢复少量生命。",
"value": 10,
"effects": {"heal": 20}
"effects": {
"heal": 20
}
},
{
"POTION_02": {
"id": 2,
"name": "破旧的短剑",
"type": "weapon",
"description": "攻击力微弱。",
"value": 50,
"effects": {},
"slot": "weapon",
"stat_modifiers": {"attack": 5}
},
{
"id": 3,
"name": "高级治疗药水",
"name": "回气丹",
"type": "potion",
"description": "恢复大量生命。",
"value": 200,
"effects": {"heal": 100}
"description": "可以恢复一定量的真气。",
"value": 20,
"effects": {
"mana": 30
}
},
{
"POTION_03": {
"id": 3,
"name": "长春丹",
"type": "potion",
"description": "传说中的长春丹,据说有延年益寿之效。",
"value": 100,
"effects": {
"heal": 50,
"strength": 5
}
},
"WEAPON_01": {
"id": 4,
"name": "布甲头盔",
"name": "精钢剑",
"type": "weapon",
"description": "一柄精钢打造的长剑,锋利坚韧。",
"value": 50,
"slot": "weapon",
"statModifiers": {
"attack": 5
}
},
"ARMOR_01": {
"id": 5,
"name": "铁布衫",
"type": "armor",
"description": "提供少量防御。",
"description": "一件铁布衫,可以有效防护。",
"value": 30,
"effects": {},
"slot": "helmet",
"stat_modifiers": {"defense": 3, "health": 10}
"slot": "armor",
"statModifiers": {
"defense": 3
}
},
"CAOYAO": {
"id": 6,
"name": "灵草药",
"type": "material",
"description": "一株灵草药,可用于炼制丹药。",
"value": 50
},
"ZHENGBI": {
"id": 7,
"name": "银两",
"type": "currency",
"description": "七玄门通行的货币,可用于交易。",
"value": 1
},
"ZHUTIANPING": {
"id": 8,
"name": "掌天瓶",
"type": "treasure",
"description": "传说中的至宝掌天瓶,具有神秘力量。",
"value": 10000,
"effects": {
"maxHealth": 100,
"maxMana": 100
}
}
]
}

View File

@ -1,21 +1,52 @@
{
"TOWN_01": {
"name": "新手村",
"description": "安全的小镇。",
"connections": {"N": "FOREST_01"},
"encounter_pool": null,
"encounter_chance": 0.0,
"npc_ids": ["VILLAGER_1", "BLACKSMITH"]
"id": "TOWN_01",
"name": "七玄门",
"description": "七玄门总部,一座古老的门派建筑群,青砖黛瓦,透着古老的气息。",
"connections": {
"E": "VILLAGE_01",
"W": "FOREST_01"
},
"encounterPool": ["GOBLIN", "WOLF"],
"encounterChance": 0.5,
"npcIds": ["VILLAGER_1"],
"lootIds": ["POTION_01"]
},
"VILLAGE_01": {
"id": "VILLAGE_01",
"name": "七玄门后山",
"description": "七玄门的后山区域,山林茂密,常有野兽出没。",
"connections": {
"W": "TOWN_01",
"N": "CAVE_01"
},
"encounterPool": ["WOLF", "BEAR"],
"encounterChance": 0.5,
"npcIds": [],
"lootIds": ["HERB_BASIC"]
},
"FOREST_01": {
"name": "新手森林",
"description": "有一些弱小的怪物。",
"connections": {"S": "TOWN_01", "E": "FOREST_02"},
"encounter_chance": 0.6,
"encounter_pool": [
{"enemyId": "GOBLIN", "weight": 70},
{"enemyId": "WOLF", "weight": 30}
],
"npc_ids": []
"id": "FOREST_01",
"name": "七玄门禁地",
"description": "七玄门的禁地,传说中隐藏着不为人知的秘密。",
"connections": {
"E": "TOWN_01"
},
"encounterPool": ["STRANGE_CULTIVATOR"],
"encounterChance": 0.5,
"npcIds": ["BLACKSMITH"],
"lootIds": ["CAOYAO"]
},
"CAVE_01": {
"id": "CAVE_01",
"name": "七玄门地牢",
"description": "七玄门的地下牢房,阴暗潮湿,传出阵阵呻吟声。",
"connections": {
"S": "VILLAGE_01"
},
"encounterPool": ["GUARD"],
"encounterChance": 0.5,
"npcIds": ["MODOCTOR"],
"lootIds": ["ZHENGBI", "ZHUTIANPING"]
}
}

View File

@ -1,24 +1,41 @@
{
"VILLAGER_1": {
"name": "老村长",
"name": "七玄门弟子",
"dialogue": {
"greeting": "你好,旅行者。你看起来很强大。",
"quest_response": "你想要帮忙吗?我们的地窖里有老鼠。",
"shop_response": "我现在没有东西卖给你。"
"greeting": "师弟,你来得正好,最近后山有些异动。",
"quest_response": "听说后山出现了一些奇怪的修士,门中长老正在调查。",
"shop_response": "我这里有些基础的疗伤药,需要吗?"
},
"hasShop": true,
"shopInventory": {
"POTION_01": {"price": 10},
"POTION_02": {"price": 20}
}
},
"BLACKSMITH": {
"name": "铁匠李奥",
"name": "铁匠铺老板",
"dialogue": {
"greeting": "欢迎来到我的铁匠铺。",
"quest_response": "你有空吗?我的铁矿用完了。",
"greeting": "欢迎光临,需要什么武器装备吗?",
"quest_response": "听说禁地那边有些奇怪的气息,不过没人敢靠近。",
"shop_response": "看一看你需要什么工具和武器。"
},
"hasShop": true,
"shopInventory": {
"2": {"price": 50},
"4": {"price": 150},
"5": {"price": 200}
"WEAPON_01": {"price": 50},
"ARMOR_01": {"price": 30}
}
},
"MODOCTOR": {
"name": "墨大夫",
"dialogue": {
"greeting": "小友,你来得正是时候,我需要你的帮助。",
"quest_response": "我被困在此地多日,若你能助我一臂之力,必有重谢。",
"shop_response": "我这里有一些珍贵的丹药,但价格不菲。"
},
"hasShop": true,
"shopInventory": {
"POTION_03": {"price": 100},
"CAOYAO": {"price": 150}
}
}
}

View File

@ -1,66 +1,90 @@
[
{
"id": "KILL_GOBLIN",
"name": "新手挑战:击败哥布林",
"description": "前往附近的森林,击败一只哥布林来证明你的勇气。",
"type": "kill",
"triggerType": "NPC",
"triggerValue": "VILLAGER_1",
{
"QUEST_001": {
"id": "QUEST_001",
"name": "七玄门初入江湖",
"description": "作为新入门的弟子,需要熟悉门派环境,完成基础任务。",
"type": "collect",
"target": {
"entityId": "GOBLIN",
"entityId": "ZHENGBI",
"count": 10
},
"required_level": 1,
"rewards": {
"xp": 50,
"gold": 20,
"item_id": 1,
"item_quantity": 1
"itemId": "POTION_01"
},
"triggerType": "NPC",
"triggerValue": "VILLAGER_1",
"dialogue": {
"root": {
"text": "你好啊,年轻人。村外的哥布林最近越来越猖狂了。",
"options": [
{ "text": "哥布林?我可以帮忙处理。", "next": "accept" },
{ "text": "那真是太可怕了,再见。", "next": "end" }
]
},
"accept": {
"text": "真的吗?那太好了!去森林里消灭一只哥布林,证明你的实力吧。",
"options": [
{ "text": "交给我吧!(接受任务)", "next": null, "action": "accept_quest:KILL_GOBLIN" }
]
},
"end": {
"text": "好吧,路上小心。",
"options": []
}
},
"next_quest_id": "FIND_NPC"
"start": "师弟门中最近需要一些银两你能帮我去后山收集10两银子吗",
"progress": "还差一些银两,继续努力。",
"complete": "很好,师弟表现不错,这是你的奖励。"
}
},
{
"id": "FIND_NPC",
"name": "寻找铁匠",
"description": "铁匠似乎有重要的消息要告诉你,去镇中心找他。",
"type": "talk",
"QUEST_002": {
"id": "QUEST_002",
"name": "后山除害",
"description": "后山出现了一些野兽,威胁门派安全,需要清除。",
"type": "kill",
"target": {
"npcId": "BLACKSMITH",
"entityId": "WOLF",
"count": 3
},
"rewards": {
"xp": 100,
"gold": 30,
"itemId": "WEAPON_01"
},
"triggerType": "NPC",
"triggerValue": "VILLAGER_1",
"dialogue": {
"start": "师弟,后山有三只野狼威胁弟子安全,你能帮我们解决吗?",
"progress": "野狼还未全部清除,小心应对。",
"complete": "太好了,后山安全了,这是给你的奖励。"
}
},
"QUEST_003": {
"id": "QUEST_003",
"name": "意外救墨大夫",
"description": "在地牢中发现被困的神秘人物,需要帮助他脱困。",
"type": "explore",
"target": {
"entityId": "CAVE_01",
"count": 1
},
"triggerType": "SYSTEM",
"triggerValue": "LEVEL_UP",
"required_level": 2,
"rewards": {
"xp": 100
"xp": 200,
"gold": 100,
"itemId": "POTION_03"
},
"triggerType": "SYSTEM",
"triggerValue": "EXPLORE_CAVE",
"dialogue": {
"root": {
"text": "你的等级提升了!村里的铁匠似乎想见你。",
"options": [
{ "text": "我会去看看的。(接受任务)", "next": null, "action": "accept_quest:FIND_NPC" }
]
}
"start": "小友,老夫被困在此地多日,若能助我脱困,必有重谢。",
"progress": "需要找到方法帮助墨大夫。",
"complete": "多谢小友相助,这是老夫的一点心意。"
}
},
"QUEST_004": {
"id": "QUEST_004",
"name": "发现长春功",
"description": "从墨大夫处学习到神秘功法,需要修炼至小成。",
"type": "level",
"target": {
"entityId": "PLAYER",
"count": 2
},
"next_quest_id": null
"rewards": {
"xp": 300,
"gold": 200,
"itemId": "ZHUTIANPING"
},
"triggerType": "NPC",
"triggerValue": "MODOCTOR",
"dialogue": {
"start": "小友,老夫观你骨骼精奇,可传授你长春功,但需谨慎修炼。",
"progress": "修炼需要时间,循序渐进。",
"complete": "恭喜小友,长春功已初见成效,这是掌天瓶,望善用之。"
}
}
]
}

View File

@ -169,6 +169,6 @@
]
},
"world": {
"currentTileId": "TOWN_01"
"currentTileId": "FOREST_01"
}
}

View File

@ -174,4 +174,6 @@ class ServiceContainer {
public function getEnemyRepository(): EnemyRepository { return $this->enemyRepository; }
public function getAbilityRepository(): AbilityRepository { return $this->abilityRepository; }
public function getNpcRepository(): NPCRepository { return $this->npcRepository; } // ⭐ 新增
public function getMapRepository(): MapRepository { return $this->mapRepository; } // ⭐ 新增
public function getQuestRepository(): QuestRepository { return $this->questRepository; } // ⭐ 新增
}

View File

@ -72,33 +72,6 @@ class DatabaseManager {
* 初始配置加载:将 JSON 数据填充到 SQLite
*/
public function loadInitialData(): void {
$jsonPath = __DIR__ . '/../../config/enemy_data.json';
if (!file_exists($jsonPath)) {
echo "❌ 警告: 找不到初始配置数据文件 enemy_data.json\n";
return;
}
// 仅在敌人表为空时填充数据
if ($this->connection->fetchOne('SELECT COUNT(*) FROM enemies') == 0) {
$data = json_decode(file_get_contents($jsonPath), true);
$this->connection->beginTransaction();
try {
foreach ($data as $enemy) {
$this->connection->insert('enemies', [
'name' => $enemy['name'],
'health' => $enemy['health'],
'attack' => $enemy['attack'],
'defense' => $enemy['defense'],
'xp_value' => $enemy['xp'],
'drop_table_id' => $enemy['dropId']
]);
}
$this->connection->commit();
echo "✅ 初始敌人数据已载入 SQLite 数据库。\n";
} catch (\Exception $e) {
$this->connection->rollBack();
echo "❌ 数据填充失败: " . $e->getMessage() . "\n";
}
}
}
}

View File

@ -120,6 +120,7 @@ class MapSystem implements EventListenerInterface {
*/
private function checkRandomEncounter(float $chance): bool {
$currentTile = $this->stateManager->getCurrentTile();
dd($currentTile);
if (!$currentTile->encounterPool || rand(1, 100) / 100 > $chance) {
return false;
}

View File

@ -141,4 +141,9 @@ class StateManager {
$this->currentTile = $this->mapRepository->createTile($tileId);
}
}
// ⭐ 新增:获取 MapRepository
public function getMapRepository(): MapRepository {
return $this->mapRepository;
}
}

View File

@ -204,7 +204,7 @@ class UIService implements EventListenerInterface {
$this->output->writeln("\n<fg=black;bg=cyan;options=bold> 📍 {$tile->name} </>");
$this->output->writeln(" <fg=white>{$tile->description}</>");
// 显示出口 - 使用方向箭头表示
// 显示出口 - 使用方向箭头表示,并显示目标位置名称
$directionMap = [
'N' => ['arrow' => '↑', 'label' => '北'],
'S' => ['arrow' => '↓', 'label' => '南'],
@ -216,7 +216,13 @@ class UIService implements EventListenerInterface {
foreach ($tile->connections as $dir => $targetId) {
if (isset($directionMap[$dir])) {
$arrow = $directionMap[$dir]['arrow'];
$moveDisplay[] = "<fg=green>{$arrow}</> {$directionMap[$dir]['label']}";
$label = $directionMap[$dir]['label'];
// 获取目标位置的名称
$targetTile = $this->stateManager->getMapRepository()->createTile($targetId);
$targetName = $targetTile ? $targetTile->name : '未知地点';
$moveDisplay[] = "<fg=green>{$arrow}</> {$label}(<fg=yellow>{$targetName}</>)";
}
}

View File

@ -0,0 +1,71 @@
<?php
require __DIR__ . '/../vendor/autoload.php';
use Game\Core\ServiceContainer;
use Game\Event\Event;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\BufferedOutput;
use Symfony\Component\Console\Helper\HelperSet;
use Symfony\Component\Console\Helper\QuestionHelper;
$input = new ArrayInput([]);
$output = new BufferedOutput();
$helperSet = new HelperSet(['question' => new QuestionHelper()]);
$container = new ServiceContainer($input, $output, $helperSet);
$dispatcher = $container->registerServices();
$stateManager = $container->getStateManager();
// 创建测试玩家
$player = new \Game\Model\Player("HanLi", 100, 10, 5);
$player->gainGold(50); // 给玩家一些初始金币
$stateManager->setPlayer($player);
$stateManager->setCurrentTileId('TOWN_01');
echo "=== 《凡人修仙传》第一阶段内容测试 ===\n\n";
// 测试地图
$mapRepo = $container->getMapRepository();
$tile = $mapRepo->createTile('TOWN_01');
echo "1. 地图测试:\n";
echo " - 位置: {$tile->name}\n";
echo " - 描述: {$tile->description}\n";
echo " - 连接: " . implode(', ', array_keys($tile->connections)) . "\n\n";
// 测试NPC
$npcRepo = $container->getNpcRepository();
$npc = $npcRepo->createNPC('VILLAGER_1');
echo "2. NPC测试:\n";
echo " - 名称: {$npc->getName()}\n";
echo " - 有商店: " . ($npc->hasShop ? '是' : '否') . "\n";
if ($npc->hasShop) {
echo " - 商店商品数: " . count($npc->shopInventory) . "\n";
}
echo " - 对话: {$npc->dialogue['greeting']}\n\n";
// 测试物品
$itemRepo = $container->getItemRepository();
$item = $itemRepo->find(1);
echo "3. 物品测试:\n";
echo " - 物品ID 1: {$item['name']}\n";
echo " - 类型: {$item['type']}\n";
echo " - 描述: {$item['description']}\n\n";
// 测试敌人
$enemyRepo = $container->getEnemyRepository();
$enemy = $enemyRepo->find('GOBLIN');
echo "4. 敌人测试:\n";
echo " - 敌人: {$enemy['name']}\n";
echo " - 生命: {$enemy['health']}\n";
echo " - 攻击: {$enemy['attack']}\n\n";
// 测试任务
$questRepo = $container->getQuestRepository();
$quest = $questRepo->find('QUEST_001');
echo "5. 任务测试:\n";
echo " - 任务: {$quest['name']}\n";
echo " - 描述: {$quest['description']}\n";
echo " - 类型: {$quest['type']}\n\n";
echo "=== 测试完成 ===\n";
echo "所有《凡人修仙传》第一阶段内容已成功配置!\n";

View File

@ -0,0 +1,54 @@
<?php
require __DIR__ . '/../vendor/autoload.php';
use Game\Core\ServiceContainer;
use Game\Event\Event;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\BufferedOutput;
use Symfony\Component\Console\Helper\HelperSet;
use Symfony\Component\Console\Helper\QuestionHelper;
$input = new ArrayInput([]);
$output = new BufferedOutput();
$helperSet = new HelperSet(['question' => new QuestionHelper()]);
$container = new ServiceContainer($input, $output, $helperSet);
$dispatcher = $container->registerServices();
$stateManager = $container->getStateManager();
// 创建测试玩家
$player = new \Game\Model\Player("HanLi", 100, 10, 5);
$player->gainGold(50); // 给玩家一些初始金币
$stateManager->setPlayer($player);
$stateManager->setCurrentTileId('TOWN_01');
echo "=== 《凡人修仙传》第一阶段地图显示测试 ===\n\n";
// 测试地图显示
$mapRepo = $container->getMapRepository();
$stateManager->setCurrentTileId('VILLAGE_01');
$dispatcher->dispatch(new Event('MapExploreRequest'));
dd(2);
// 手动调用UIService显示地图信息
$uiService = new \Game\System\UIService($output, $stateManager, $container->getQuestRepository());
echo "1. 地图显示测试:\n";
$uiService->handleEvent(new Event('ShowMenuEvent'));
echo "\n" . $output->fetch() . "\n";
echo "\n2. 目标位置名称验证:\n";
foreach ($tile->connections as $dir => $targetId) {
$targetTile = $mapRepo->createTile($targetId);
$directionMap = [
'N' => '北',
'S' => '南',
'E' => '东',
'W' => '西'
];
$direction = $directionMap[$dir] ?? $dir;
echo " - {$direction}方向: {$targetTile->name} (ID: {$targetId})\n";
}
echo "\n=== 测试完成 ===\n";
echo "地图显示已更新,现在会显示方向和目标位置名称!\n";