From b4ec385827057ec65803f00a070eafe1b03a3825 Mon Sep 17 00:00:00 2001 From: hantao Date: Tue, 2 Dec 2025 13:45:20 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=80=AA=E7=89=A9=E7=BE=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- save.json | 2 +- src/Core/Game.php | 2 +- src/Core/ItemDisplay.php | 8 +- src/Data/items.php | 152 ++++++-- src/Data/maps.php | 74 ++-- src/Data/npcs.php | 2 +- src/Entities/Item.php | 627 ++++++++++----------------------- src/Entities/Monster.php | 126 +++++-- src/Entities/Partner.php | 26 ++ src/Modules/Battle.php | 346 ++++++++++++------ src/Modules/InventoryPanel.php | 62 +++- src/Modules/TalentPanel.php | 4 +- 12 files changed, 757 insertions(+), 674 deletions(-) diff --git a/save.json b/save.json index 2ea72e2..d642fb5 100644 --- a/save.json +++ b/save.json @@ -1 +1 @@ -{"player":{"hp":195,"maxHp":100,"patk":10,"matk":5,"pdef":5,"mdef":3,"crit":5,"critdmg":150,"level":8,"exp":121,"maxExp":1702,"inventory":[{"name":"补气丹","type":"consume","quality":"common","level":5,"atk":0,"def":0,"hp":0,"crit":0,"critdmg":0,"heal":61,"affixes":[],"desc":"Lv.5 common品质的药剂","id":"692d5de978e03","quantity":1},{"name":"金疮药","type":"consume","quality":"rare","level":1,"atk":0,"def":0,"hp":0,"crit":0,"critdmg":0,"heal":60,"affixes":[],"desc":"Lv.1 rare品质的药剂","id":"692d5f6453b0e","quantity":1},{"name":"长生锁","type":"necklace","quality":"common","level":5,"atk":0,"def":0,"hp":37,"crit":0,"critdmg":0,"heal":0,"affixes":[],"desc":"Lv.5 common品质的项链","id":"692d5f86c4cfc","quantity":1},{"name":"培元丹","type":"consume","quality":"rare","level":5,"atk":0,"def":0,"hp":0,"crit":0,"critdmg":0,"heal":84,"affixes":[],"desc":"Lv.5 rare品质的药剂","id":"692d5f86c4d20","quantity":1},{"name":"眨眼剑法","type":"weapon","quality":"rare","level":5,"atk":0,"def":0,"hp":0,"crit":0,"critdmg":0,"heal":0,"affixes":["防御 +9"],"desc":"Lv.5 rare品质的武器","id":"692d5fd79b86b","quantity":1},{"name":"金疮药","type":"consume","quality":"rare","level":1,"atk":0,"def":0,"hp":0,"crit":0,"critdmg":0,"heal":62,"affixes":[],"desc":"Lv.1 rare品质的药剂","id":"692d5feae2480","quantity":1},{"name":"补气丹","type":"consume","quality":"rare","level":5,"atk":0,"def":0,"hp":0,"crit":0,"critdmg":0,"heal":82,"affixes":[],"desc":"Lv.5 rare品质的药剂","id":"692d601b0cb5b","quantity":1},{"name":"补气丹","type":"consume","quality":"common","level":3,"atk":0,"def":0,"hp":0,"crit":0,"critdmg":0,"heal":55,"affixes":[],"desc":"Lv.3 common品质的药剂","id":"692d62ef6dc0b","quantity":1},{"name":"铁刀","type":"weapon","quality":"common","level":1,"atk":6,"def":0,"hp":0,"crit":0,"critdmg":0,"heal":0,"affixes":[],"desc":"Lv.1 common品质的武器","id":"692d6301e1fee","quantity":1},{"name":"培元丹","type":"consume","quality":"rare","level":3,"atk":0,"def":0,"hp":0,"crit":0,"critdmg":0,"heal":70,"affixes":[],"desc":"Lv.3 rare品质的药剂","id":"692d6308a0469","quantity":1},{"name":"回灵丹","type":"consume","quality":"common","level":5,"atk":0,"def":0,"hp":0,"crit":0,"critdmg":0,"heal":63,"affixes":[],"desc":"Lv.5 common品质的药剂","id":"692d6324319ef","quantity":1},{"name":"金疮药","type":"consume","quality":"common","level":5,"atk":0,"def":0,"hp":0,"crit":0,"critdmg":0,"heal":59,"affixes":[],"desc":"Lv.5 common品质的药剂","id":"692d633849668","quantity":1},{"name":"回灵丹","type":"consume","quality":"common","level":5,"atk":0,"def":0,"hp":0,"crit":0,"critdmg":0,"heal":57,"affixes":[],"desc":"Lv.5 common品质的药剂","id":"692d6354cf448","quantity":1},{"name":"补气丹","type":"consume","quality":"rare","level":3,"atk":0,"def":0,"hp":0,"crit":0,"critdmg":0,"heal":74,"affixes":[],"desc":"Lv.3 rare品质的药剂","id":"692d636bb0590","quantity":1},{"name":"补气丹","type":"consume","quality":"rare","level":3,"atk":0,"def":0,"hp":0,"crit":0,"critdmg":0,"heal":71,"affixes":[],"desc":"Lv.3 rare品质的药剂","id":"692d63719d056","quantity":1},{"name":"金疮药","type":"consume","quality":"rare","level":1,"atk":0,"def":0,"hp":0,"crit":0,"critdmg":0,"heal":64,"affixes":[],"desc":"Lv.1 rare品质的药剂","id":"692d63945c855","quantity":1},{"name":"筑基丹","type":"consume","quality":"epic","level":3,"atk":0,"def":0,"hp":0,"crit":0,"critdmg":0,"heal":100,"affixes":[],"desc":"Lv.3 epic品质的药剂","id":"692d63cf9bb72","quantity":1},{"name":"铁刀","type":"weapon","quality":"epic","level":1,"atk":23,"def":0,"hp":0,"crit":0,"critdmg":14,"heal":0,"affixes":["暴击伤害 +2%","暴击率 +5%"],"desc":"Lv.1 epic品质的武器","id":"692d63d4b9340","quantity":1},{"name":"金疮药","type":"consume","quality":"common","level":3,"atk":0,"def":0,"hp":0,"crit":0,"critdmg":0,"heal":48,"affixes":[],"desc":"Lv.3 common品质的药剂","id":"692d6872b1db6","quantity":1},{"name":"金疮药","type":"consume","quality":"common","level":1,"atk":0,"def":0,"hp":0,"crit":0,"critdmg":0,"heal":39,"affixes":[],"desc":"Lv.1 common品质的药剂","id":"692d6878a0d36","quantity":2},{"name":"培元丹","type":"consume","quality":"common","level":3,"atk":0,"def":0,"hp":0,"crit":0,"critdmg":0,"heal":52,"affixes":[],"desc":"Lv.3 common品质的药剂","id":"692d6890591ff","quantity":1},{"name":"金疮药","type":"consume","quality":"common","level":1,"atk":0,"def":0,"hp":0,"crit":0,"critdmg":0,"heal":40,"affixes":[],"desc":"Lv.1 common品质的药剂","id":"692d6895766b4","quantity":1},{"name":"补气丹","type":"consume","quality":"common","level":3,"atk":0,"def":0,"hp":0,"crit":0,"critdmg":0,"heal":48,"affixes":[],"desc":"Lv.3 common品质的药剂","id":"692d68a6737d2","quantity":1},{"name":"金疮药","type":"consume","quality":"common","level":1,"atk":0,"def":0,"hp":0,"crit":0,"critdmg":0,"heal":38,"affixes":[],"desc":"Lv.1 common品质的药剂","id":"692d68ab8f8a1","quantity":1},{"name":"皮甲","type":"armor","quality":"common","level":3,"atk":0,"def":6,"hp":0,"crit":0,"critdmg":0,"heal":0,"affixes":[],"desc":"Lv.3 common品质的防具","id":"692d68b76fd22","quantity":1},{"name":"眨眼剑法","type":"weapon","quality":"rare","level":5,"atk":0,"def":0,"hp":0,"crit":0,"critdmg":0,"heal":0,"affixes":["攻击 +15"],"desc":"Lv.5 rare品质的武器","id":"692d68c76ade5","quantity":1},{"name":"铁刀","type":"weapon","quality":"common","level":1,"atk":7,"def":0,"hp":0,"crit":0,"critdmg":0,"heal":0,"affixes":[],"desc":"Lv.1 common品质的武器","id":"692d68cd5925f","quantity":1},{"name":"培元丹","type":"consume","quality":"common","level":5,"atk":0,"def":0,"hp":0,"crit":0,"critdmg":0,"heal":57,"affixes":[],"desc":"Lv.5 common品质的药剂","id":"692d68e16d0e1","quantity":1},{"name":"金疮药","type":"consume","quality":"common","level":1,"atk":0,"def":0,"hp":0,"crit":0,"critdmg":0,"heal":45,"affixes":[],"desc":"Lv.1 common品质的药剂","id":"692d68ed4ce33","quantity":1},{"name":"眨眼剑法","type":"weapon","quality":"rare","level":5,"atk":0,"def":0,"hp":0,"crit":0,"critdmg":0,"heal":0,"affixes":["攻击 +13"],"desc":"Lv.5 rare品质的武器","id":"692d68f68a3f7","quantity":1},{"name":"皮甲","type":"armor","quality":"epic","level":3,"atk":0,"def":17,"hp":56,"crit":0,"critdmg":0,"heal":0,"affixes":["防御 +9%","生命值 +40"],"desc":"Lv.3 epic品质的防具","id":"692d690162a73","quantity":1}],"equip":{"armor":{"name":"皮甲","type":"armor","quality":"common","level":3,"atk":0,"def":6,"hp":0,"crit":0,"critdmg":0,"heal":0,"affixes":[],"desc":"Lv.3 common品质的防具","id":"692d5e1b2eacd","quantity":1},"weapon":{"name":"铁刀","type":"weapon","quality":"common","level":1,"atk":6,"def":0,"hp":0,"crit":0,"critdmg":0,"heal":0,"affixes":[],"desc":"Lv.1 common品质的武器","id":"692d5eaaef7c1","quantity":1}},"spiritStones":701,"npcFlags":[],"talentPoints":12,"talents":{"hp":5,"patk":4,"matk":0,"pdef":0,"mdef":0,"crit":0,"critdmg":0},"partners":[{"id":"li_feiyu","name":"厉飞雨","level":7,"exp":182,"maxExp":1135,"baseStats":{"hp":100,"patk":15,"matk":5,"pdef":5,"mdef":3,"crit":10,"critdmg":150,"growth":1.2},"equip":{"weapon":{"name":"铁刀","type":"weapon","quality":"common","level":1,"atk":7,"def":0,"hp":0,"crit":0,"critdmg":0,"heal":0,"affixes":[],"desc":"Lv.1 common品质的武器","id":"692d5eb86bb40","quantity":1}},"talents":{"hp":0,"patk":6,"matk":0,"pdef":0,"mdef":0,"crit":6,"critdmg":6},"talentWeights":{"hp":1,"patk":3,"matk":1,"pdef":1,"mdef":1,"crit":3,"critdmg":2}}]},"dungeonId":1,"state":2} \ No newline at end of file +{"player":{"hp":504,"maxHp":50,"patk":10,"matk":5,"pdef":5,"mdef":3,"crit":5,"critdmg":130,"level":12,"exp":6529,"maxExp":8614,"inventory":[{"name":"金疮药","type":"consume","quality":"rare","level":3,"patk":0,"matk":0,"pdef":0,"mdef":0,"hp":0,"crit":0,"critdmg":0,"heal":71,"affixes":[],"desc":"Lv.3 rare品质的药剂","id":"692e53f0906d7","quantity":1},{"name":"补气丹","type":"consume","quality":"rare","level":5,"patk":0,"matk":0,"pdef":0,"mdef":0,"hp":0,"crit":0,"critdmg":0,"heal":78,"affixes":[],"desc":"Lv.5 rare品质的药剂","id":"692e54da4e8eb","quantity":1},{"name":"回灵丹","type":"consume","quality":"common","level":5,"patk":0,"matk":0,"pdef":0,"mdef":0,"hp":0,"crit":0,"critdmg":0,"heal":65,"affixes":[],"desc":"Lv.5 common品质的药剂","id":"692e5b3b79b6f","quantity":1},{"name":"回灵丹","type":"consume","quality":"rare","level":3,"patk":0,"matk":0,"pdef":0,"mdef":0,"hp":0,"crit":0,"critdmg":0,"heal":65,"affixes":[],"desc":"Lv.3 rare品质的药剂","id":"692e5bbc27698","quantity":1},{"name":"培元丹","type":"consume","quality":"rare","level":3,"patk":0,"matk":0,"pdef":0,"mdef":0,"hp":0,"crit":0,"critdmg":0,"heal":65,"affixes":[],"desc":"Lv.3 rare品质的药剂","id":"692e5c3646486","quantity":1},{"name":"金疮药","type":"consume","quality":"common","level":6,"patk":0,"matk":0,"pdef":0,"mdef":0,"hp":0,"crit":0,"critdmg":0,"heal":66,"affixes":[],"desc":"Lv.6 common品质的药剂","id":"692e5dcb727bb","quantity":1},{"name":"回灵丹","type":"consume","quality":"common","level":6,"patk":0,"matk":0,"pdef":0,"mdef":0,"hp":0,"crit":0,"critdmg":0,"heal":69,"affixes":[],"desc":"Lv.6 common品质的药剂","id":"692e5e0552daa","quantity":1},{"name":"寒冰剑","type":"weapon","quality":"epic","level":6,"patk":14,"matk":44,"pdef":0,"mdef":0,"hp":0,"crit":0,"critdmg":18,"heal":0,"affixes":["生命值 +75","物攻 +4%"],"desc":"Lv.6 epic品质的武器","id":"692e5e102f217","quantity":1},{"name":"补气丹","type":"consume","quality":"rare","level":6,"patk":0,"matk":0,"pdef":0,"mdef":0,"hp":0,"crit":0,"critdmg":0,"heal":86,"affixes":[],"desc":"Lv.6 rare品质的药剂","id":"692e5e284ed0a","quantity":1},{"name":"补气丹","type":"consume","quality":"common","level":6,"patk":0,"matk":0,"pdef":0,"mdef":0,"hp":0,"crit":0,"critdmg":0,"heal":70,"affixes":[],"desc":"Lv.6 common品质的药剂","id":"692e5e4e62333","quantity":1},{"name":"金疮药","type":"consume","quality":"common","level":6,"patk":0,"matk":0,"pdef":0,"mdef":0,"hp":0,"crit":0,"critdmg":0,"heal":67,"affixes":[],"desc":"Lv.6 common品质的药剂","id":"692e5e631f545","quantity":1},{"name":"回灵丹","type":"consume","quality":"common","level":10,"patk":0,"matk":0,"pdef":0,"mdef":0,"hp":0,"crit":0,"critdmg":0,"heal":89,"affixes":[],"desc":"Lv.10 common品质的药剂","id":"692e5e631f55c","quantity":1},{"name":"培元丹","type":"consume","quality":"common","level":6,"patk":0,"matk":0,"pdef":0,"mdef":0,"hp":0,"crit":0,"critdmg":0,"heal":67,"affixes":[],"desc":"Lv.6 common品质的药剂","id":"692e5e8a0b759","quantity":1},{"name":"金疮药","type":"consume","quality":"common","level":6,"patk":0,"matk":0,"pdef":0,"mdef":0,"hp":0,"crit":0,"critdmg":0,"heal":68,"affixes":[],"desc":"Lv.6 common品质的药剂","id":"692e631b26f46","quantity":1},{"name":"补气丹","type":"consume","quality":"rare","level":10,"patk":0,"matk":0,"pdef":0,"mdef":0,"hp":0,"crit":0,"critdmg":0,"heal":110,"affixes":[],"desc":"Lv.10 rare品质的药剂","id":"692e633d2753b","quantity":1},{"name":"培元丹","type":"consume","quality":"legendary","level":6,"patk":0,"matk":0,"pdef":0,"mdef":0,"hp":0,"crit":0,"critdmg":0,"heal":160,"affixes":[],"desc":"Lv.6 legendary品质的药剂","id":"692e633d2754c","quantity":1},{"name":"培元丹","type":"consume","quality":"common","level":10,"patk":0,"matk":0,"pdef":0,"mdef":0,"hp":0,"crit":0,"critdmg":0,"heal":83,"affixes":[],"desc":"Lv.10 common品质的药剂","id":"692e637fe0870","quantity":1},{"name":"补气丹","type":"consume","quality":"common","level":10,"patk":0,"matk":0,"pdef":0,"mdef":0,"hp":0,"crit":0,"critdmg":0,"heal":83,"affixes":[],"desc":"Lv.10 common品质的药剂","id":"692e639b58bc3","quantity":1},{"name":"筑基丹","type":"consume","quality":"rare","level":6,"patk":0,"matk":0,"pdef":0,"mdef":0,"hp":0,"crit":0,"critdmg":0,"heal":88,"affixes":[],"desc":"Lv.6 rare品质的药剂","id":"692e639b58bd9","quantity":1},{"name":"寒冰剑","type":"weapon","quality":"epic","level":11,"patk":19,"matk":52,"pdef":0,"mdef":0,"hp":0,"crit":9,"critdmg":0,"heal":0,"affixes":["生命值 +139","物攻 +10%"],"desc":"Lv.11 epic品质的武器","id":"692e64d48a0fb","quantity":1},{"name":"寒冰剑","type":"weapon","quality":"epic","level":1,"patk":21,"matk":10,"pdef":0,"mdef":0,"hp":0,"crit":0,"critdmg":16,"heal":0,"affixes":["暴击伤害 +3%","暴击率 +8%"],"desc":"Lv.1 epic品质的武器","id":"692e64fbdd698","quantity":1,"enhanceLevel":0},{"name":"金疮药","type":"consume","quality":"common","level":11,"patk":0,"matk":0,"pdef":0,"mdef":0,"hp":0,"crit":0,"critdmg":0,"heal":89,"affixes":[],"desc":"Lv.11 common品质的药剂","id":"692e65c48ecb5","quantity":1},{"name":"龙鳞甲","type":"armor","quality":"epic","level":15,"patk":0,"matk":0,"pdef":20,"mdef":15,"hp":0,"crit":0,"critdmg":0,"heal":0,"affixes":[],"desc":"Lv.15 common品质的防具","id":"692e6663ea7dc","quantity":1},{"name":"筑基丹","type":"consume","quality":"common","level":15,"patk":0,"matk":0,"pdef":0,"mdef":0,"hp":0,"crit":0,"critdmg":0,"heal":106,"affixes":[],"desc":"Lv.15 common品质的药剂","id":"692e667ede724","quantity":1},{"name":"回灵丹","type":"consume","quality":"common","level":11,"patk":0,"matk":0,"pdef":0,"mdef":0,"hp":0,"crit":0,"critdmg":0,"heal":88,"affixes":[],"desc":"Lv.11 common品质的药剂","id":"692e667ede73f","quantity":1},{"name":"皮甲","type":"armor","quality":"epic","level":13,"patk":0,"matk":0,"pdef":25,"mdef":8,"hp":95,"crit":0,"critdmg":0,"heal":0,"affixes":["生命值 +8%","魔攻 +35"],"desc":"Lv.13 epic品质的防具","id":"692e6713db559","quantity":1},{"name":"补气丹","type":"consume","quality":"rare","level":11,"patk":0,"matk":0,"pdef":0,"mdef":0,"hp":0,"crit":0,"critdmg":0,"heal":107,"affixes":[],"desc":"Lv.11 rare品质的药剂","id":"692e671b0b244","quantity":1},{"name":"培元丹","type":"consume","quality":"common","level":11,"patk":0,"matk":0,"pdef":0,"mdef":0,"hp":0,"crit":0,"critdmg":0,"heal":93,"affixes":[],"desc":"Lv.11 common品质的药剂","id":"692e673e93637","quantity":1},{"name":"补气丹","type":"consume","quality":"common","level":11,"patk":0,"matk":0,"pdef":0,"mdef":0,"hp":0,"crit":0,"critdmg":0,"heal":86,"affixes":[],"desc":"Lv.11 common品质的药剂","id":"692e67604eb32","quantity":1},{"name":"补气丹","type":"consume","quality":"epic","level":11,"patk":0,"matk":0,"pdef":0,"mdef":0,"hp":0,"crit":0,"critdmg":0,"heal":139,"affixes":[],"desc":"Lv.11 epic品质的药剂","id":"692e67c92279e","quantity":1},{"name":"筑基丹","type":"consume","quality":"common","level":15,"patk":0,"matk":0,"pdef":0,"mdef":0,"hp":0,"crit":0,"critdmg":0,"heal":114,"affixes":[],"desc":"Lv.15 common品质的药剂","id":"692e67fb7ba07","quantity":1},{"name":"法袍","type":"armor","quality":"common","level":13,"patk":0,"matk":0,"pdef":6,"mdef":18,"hp":0,"crit":0,"critdmg":0,"heal":0,"affixes":[],"desc":"Lv.13 common品质的防具","id":"692e6c7430f22","quantity":1},{"name":"金疮药","type":"consume","quality":"common","level":11,"patk":0,"matk":0,"pdef":0,"mdef":0,"hp":0,"crit":0,"critdmg":0,"heal":92,"affixes":[],"desc":"Lv.11 common品质的药剂","id":"692e6c838d847","quantity":1},{"name":"筑基丹","type":"consume","quality":"common","level":15,"patk":0,"matk":0,"pdef":0,"mdef":0,"hp":0,"crit":0,"critdmg":0,"heal":108,"affixes":[],"desc":"Lv.15 common品质的药剂","id":"692e6ca661b87","quantity":1},{"name":"皮甲","type":"armor","quality":"epic","level":15,"patk":0,"matk":0,"pdef":20,"mdef":15,"hp":0,"crit":0,"critdmg":0,"heal":0,"affixes":["生命值 +7%"],"desc":"Lv.15 rare品质的防具","id":"692e6cef065a1","quantity":1},{"name":"布衣","type":"armor","quality":"common","level":13,"patk":0,"matk":0,"pdef":6,"mdef":7,"hp":0,"crit":0,"critdmg":0,"heal":0,"affixes":[],"desc":"Lv.13 common品质的防具","id":"692e6cef065af","quantity":1},{"name":"皮甲","type":"armor","quality":"epic","level":3,"patk":0,"matk":0,"pdef":18,"mdef":5,"hp":61,"crit":0,"critdmg":0,"heal":0,"affixes":["物防 +9","生命值 +7%"],"desc":"Lv.3 epic品质的防具","id":"692e7b1565cd1","quantity":1,"enhanceLevel":0},{"name":"皮甲","type":"armor","quality":"epic","level":15,"patk":0,"matk":0,"pdef":20,"mdef":15,"hp":0,"crit":0,"critdmg":0,"heal":0,"affixes":[],"desc":"Lv.15 common品质的防具","id":"692e7c247231e","quantity":1},{"name":"筑基丹","type":"consume","quality":"common","level":15,"patk":0,"matk":0,"pdef":0,"mdef":0,"hp":0,"crit":0,"critdmg":0,"heal":107,"affixes":[],"desc":"Lv.15 common品质的药剂","id":"692e7c247234d","quantity":1},{"name":"寒冰剑","type":"weapon","quality":"rare","level":13,"patk":16,"matk":41,"pdef":0,"mdef":0,"hp":0,"crit":0,"critdmg":18,"heal":0,"affixes":["物攻 +29"],"desc":"Lv.13 rare品质的武器","id":"692e7c3ee47a1","quantity":1},{"name":"筑基丹","type":"consume","quality":"common","level":15,"patk":0,"matk":0,"pdef":0,"mdef":0,"hp":0,"crit":0,"critdmg":0,"heal":109,"affixes":[],"desc":"Lv.15 common品质的药剂","id":"692e7c3ee47f5","quantity":1},{"name":"培元丹","type":"consume","quality":"common","level":11,"patk":0,"matk":0,"pdef":0,"mdef":0,"hp":0,"crit":0,"critdmg":0,"heal":92,"affixes":[],"desc":"Lv.11 common品质的药剂","id":"692e7c3ee480b","quantity":1},{"name":"回灵丹","type":"consume","quality":"common","level":11,"patk":0,"matk":0,"pdef":0,"mdef":0,"hp":0,"crit":0,"critdmg":0,"heal":85,"affixes":[],"desc":"Lv.11 common品质的药剂","id":"692e7c60cb839","quantity":1},{"name":"皮甲","type":"armor","quality":"rare","level":13,"patk":0,"matk":0,"pdef":16,"mdef":6,"hp":0,"crit":0,"critdmg":0,"heal":0,"affixes":["物攻 +11%"],"desc":"Lv.13 rare品质的防具","id":"692e7c60cb847","quantity":1},{"name":"寒冰剑","type":"weapon","quality":"common","level":13,"patk":13,"matk":32,"pdef":0,"mdef":0,"hp":0,"crit":0,"critdmg":0,"heal":0,"affixes":[],"desc":"Lv.13 common品质的武器","id":"692e7c60cb862","quantity":1}],"equip":{"weapon":{"name":"烈焰刀","type":"weapon","quality":"legendary","level":1,"patk":34,"matk":35,"pdef":0,"mdef":0,"hp":0,"crit":10,"critdmg":0,"heal":0,"affixes":["暴击伤害 +3%","物攻 +8%","暴击率 +9"],"desc":"Lv.1 legendary品质的武器","id":"692e5cdba05b4","quantity":1,"enhanceLevel":0},"armor":{"name":"灵纹袍","type":"armor","quality":"epic","level":15,"patk":0,"matk":0,"pdef":20,"mdef":15,"hp":99,"crit":0,"critdmg":0,"heal":0,"affixes":["魔攻 +8%","物防 +25"],"desc":"Lv.15 epic品质的防具","id":"692e667ede6eb","quantity":1,"enhanceLevel":0},"necklace":{"name":"仙珠","type":"necklace","quality":"rare","level":5,"patk":0,"matk":0,"pdef":0,"mdef":8,"hp":55,"crit":0,"critdmg":0,"heal":0,"affixes":["暴击率 +7%"],"desc":"Lv.5 rare品质的项链","id":"692e539ee73e4","quantity":1},"ring":{"name":"银戒","type":"ring","quality":"common","level":10,"patk":0,"matk":0,"pdef":0,"mdef":0,"hp":0,"crit":6,"critdmg":0,"heal":0,"affixes":[],"desc":"Lv.10 common品质的戒指","id":"692e5dfa765cb","quantity":1},"boots":{"name":"龙鳞靴","type":"boots","quality":"common","level":8,"patk":0,"matk":0,"pdef":5,"mdef":3,"hp":0,"crit":0,"critdmg":0,"heal":0,"affixes":[],"desc":"Lv.8 common品质的鞋子","id":"692e631b26f60","quantity":1}},"spiritStones":7576,"npcFlags":{"gift_li_feiyu":true},"talentPoints":3,"talents":{"hp":15,"patk":15,"matk":0,"pdef":0,"mdef":0,"crit":0,"critdmg":0},"partners":[{"id":"li_feiyu","name":"厉飞雨","level":12,"exp":232,"maxExp":8614,"baseStats":{"hp":100,"patk":15,"matk":5,"pdef":5,"mdef":3,"crit":10,"critdmg":120,"growth":0.8},"equip":{"weapon":{"name":"青钢剑","type":"weapon","quality":"epic","level":1,"patk":26,"matk":7,"pdef":0,"mdef":0,"hp":0,"crit":6,"critdmg":0,"heal":0,"affixes":["暴击率 +2%","物攻 +12"],"desc":"Lv.1 epic品质的武器","id":"692e5d1cc104d","quantity":1,"enhanceLevel":0},"armor":{"name":"龙鳞甲","type":"armor","quality":"epic","level":8,"patk":0,"matk":0,"pdef":16,"mdef":12,"hp":76,"crit":0,"critdmg":0,"heal":0,"affixes":["生命值 +103","魔防 +10%"],"desc":"Lv.8 epic品质的防具","id":"692e7ad23293b","quantity":1,"enhanceLevel":0},"necklace":{"name":"金链","type":"necklace","quality":"common","level":5,"patk":0,"matk":0,"pdef":0,"mdef":0,"hp":35,"crit":0,"critdmg":0,"heal":0,"affixes":[],"desc":"Lv.5 common品质的项链","id":"692e5177750a5","quantity":1},"ring":{"name":"铜戒","type":"ring","quality":"rare","level":10,"patk":14,"matk":0,"pdef":0,"mdef":0,"hp":0,"crit":10,"critdmg":0,"heal":0,"affixes":["暴击率 +10%"],"desc":"Lv.10 rare品质的戒指","id":"692e635deb076","quantity":1},"boots":{"name":"疾风靴","type":"boots","quality":"common","level":8,"patk":0,"matk":0,"pdef":5,"mdef":4,"hp":0,"crit":0,"critdmg":0,"heal":0,"affixes":[],"desc":"Lv.8 common品质的鞋子","id":"692e6367949cd","quantity":1}},"talents":{"hp":2,"patk":11,"matk":0,"pdef":0,"mdef":0,"crit":11,"critdmg":9},"talentWeights":{"hp":1,"patk":3,"matk":1,"pdef":1,"mdef":1,"crit":3,"critdmg":2}}]},"dungeonId":3,"state":4} \ No newline at end of file diff --git a/src/Core/Game.php b/src/Core/Game.php index e7e14fc..2524231 100644 --- a/src/Core/Game.php +++ b/src/Core/Game.php @@ -97,7 +97,7 @@ class Game } $this->dungeonId = $data['dungeonId'] ?? $this->dungeonId; - $this->state = $data['state'] ?? $this->state; + $this->state = self::MENU; } } } diff --git a/src/Core/ItemDisplay.php b/src/Core/ItemDisplay.php index 7bad345..784597d 100644 --- a/src/Core/ItemDisplay.php +++ b/src/Core/ItemDisplay.php @@ -34,8 +34,10 @@ class ItemDisplay // 属性名称 private static array $statNames = [ - 'atk' => '攻击', - 'def' => '防御', + 'patk' => '物攻', + 'matk' => '魔攻', + 'pdef' => '物防', + 'mdef' => '魔防', 'hp' => '生命', 'crit' => '暴击', 'critdmg' => '暴伤', @@ -296,7 +298,7 @@ class ItemDisplay // 简要属性 $stats = []; - foreach (['atk', 'def', 'hp'] as $key) { + foreach (['patk', 'matk', 'pdef', 'mdef', 'hp'] as $key) { $value = $item[$key] ?? 0; if ($value > 0) { $statName = self::$statNames[$key] ?? $key; diff --git a/src/Data/items.php b/src/Data/items.php index 7ffc0e3..8636791 100644 --- a/src/Data/items.php +++ b/src/Data/items.php @@ -8,8 +8,10 @@ return [ // 词条名称定义 'affix_definitions' => [ - 'atk' => '攻击', - 'def' => '防御', + 'patk' => '物攻', + 'matk' => '魔攻', + 'pdef' => '物防', + 'mdef' => '魔防', 'hp' => '生命值', 'crit' => '暴击率', 'critdmg' => '暴击伤害', @@ -20,11 +22,52 @@ return [ 'weapon' => [ 'names' => ['铁剑', '玄铁剑', '青钢剑', '寒冰剑', '烈焰刀', '雷霆锤'], 'fixed_primary' => [ - 'atk' => ['base' => [5, 12, 22, 38], 'growth' => 1.8], + 'patk' => ['base' => [4, 10, 18, 30], 'growth' => 1.5], + 'matk' => ['base' => [2, 5, 10, 18], 'growth' => 0.8], + ], + // 特定物品的属性偏向配置 (覆盖默认 fixed_primary) + 'specific_config' => [ + '铁剑' => [ + 'fixed_primary' => [ + 'patk' => ['base' => [6, 14, 24, 40], 'growth' => 1.8], // 高物攻 + 'matk' => ['base' => [0, 0, 0, 0], 'growth' => 0.0], // 无魔攻 + ] + ], + '玄铁剑' => [ + 'fixed_primary' => [ + 'patk' => ['base' => [8, 18, 30, 50], 'growth' => 2.0], // 更高物攻 + 'matk' => ['base' => [0, 0, 0, 0], 'growth' => 0.0], + ] + ], + '青钢剑' => [ + 'fixed_primary' => [ + 'patk' => ['base' => [5, 12, 22, 35], 'growth' => 1.6], + 'matk' => ['base' => [1, 3, 6, 10], 'growth' => 0.5], + ] + ], + '寒冰剑' => [ + 'fixed_primary' => [ + 'patk' => ['base' => [2, 5, 10, 15], 'growth' => 0.8], // 低物攻 + 'matk' => ['base' => [6, 15, 28, 45], 'growth' => 2.0], // 高魔攻 + ] + ], + '烈焰刀' => [ + 'fixed_primary' => [ + 'patk' => ['base' => [4, 10, 18, 30], 'growth' => 1.5], // 均衡 + 'matk' => ['base' => [4, 10, 18, 30], 'growth' => 1.5], + ] + ], + '雷霆锤' => [ + 'fixed_primary' => [ + 'patk' => ['base' => [7, 16, 28, 45], 'growth' => 1.9], + 'matk' => ['base' => [2, 5, 10, 18], 'growth' => 0.8], + ] + ], ], 'random_primary_pool' => [ - 'crit' => ['weight' => 50, 'base' => [1, 3, 5, 10], 'growth' => 0.3], - 'critdmg' => ['weight' => 50, 'base' => [3, 8, 14, 24], 'growth' => 0.7], + 'crit' => ['weight' => 40, 'base' => [1, 3, 5, 10], 'growth' => 0.3], + 'critdmg' => ['weight' => 40, 'base' => [3, 8, 14, 24], 'growth' => 0.7], + 'matk' => ['weight' => 20, 'base' => [2, 5, 10, 18], 'growth' => 0.8], ], 'random_primary_count' => [ 'common' => [0, 0], @@ -33,18 +76,63 @@ return [ 'legendary' => [1, 2], ], 'affix_weights' => [ - 'atk' => 40, - 'crit' => 30, - 'critdmg' => 30, - 'hp' => 15, - 'def' => 10, + 'patk' => 30, + 'matk' => 20, + 'crit' => 25, + 'critdmg' => 25, + 'hp' => 10, ], ], 'armor' => [ - 'names' => ['布衣', '皮甲', '铁甲', '精钢甲', '玄武甲', '龙鳞甲'], + 'names' => ['布衣', '皮甲', '铁甲', '精钢甲', '玄武甲', '龙鳞甲', '法袍', '灵纹袍'], 'fixed_primary' => [ - 'def' => ['base' => [3, 8, 15, 26], 'growth' => 0.8], + 'pdef' => ['base' => [2, 6, 12, 20], 'growth' => 0.6], + 'mdef' => ['base' => [1, 4, 8, 15], 'growth' => 0.5], + ], + 'specific_config' => [ + '布衣' => [ + 'fixed_primary' => [ + 'pdef' => ['base' => [1, 3, 6, 10], 'growth' => 0.4], + 'mdef' => ['base' => [1, 3, 6, 10], 'growth' => 0.4], + ] + ], + '皮甲' => [ + 'fixed_primary' => [ + 'pdef' => ['base' => [3, 7, 14, 22], 'growth' => 0.7], + 'mdef' => ['base' => [1, 2, 4, 8], 'growth' => 0.3], + ] + ], + '铁甲' => [ + 'fixed_primary' => [ + 'pdef' => ['base' => [5, 12, 20, 35], 'growth' => 1.0], // 高物防 + 'mdef' => ['base' => [0, 1, 2, 5], 'growth' => 0.2], // 低魔防 + ] + ], + '精钢甲' => [ + 'fixed_primary' => [ + 'pdef' => ['base' => [7, 15, 25, 45], 'growth' => 1.2], + 'mdef' => ['base' => [1, 3, 6, 10], 'growth' => 0.3], + ] + ], + '玄武甲' => [ + 'fixed_primary' => [ + 'pdef' => ['base' => [10, 20, 35, 60], 'growth' => 1.5], + 'mdef' => ['base' => [5, 10, 18, 30], 'growth' => 0.8], + ] + ], + '法袍' => [ + 'fixed_primary' => [ + 'pdef' => ['base' => [1, 3, 6, 12], 'growth' => 0.4], + 'mdef' => ['base' => [5, 12, 20, 35], 'growth' => 1.0], // 高魔防 + ] + ], + '灵纹袍' => [ + 'fixed_primary' => [ + 'pdef' => ['base' => [2, 5, 10, 18], 'growth' => 0.5], + 'mdef' => ['base' => [8, 18, 30, 50], 'growth' => 1.3], // 极高魔防 + ] + ], ], 'random_primary_pool' => [ 'hp' => ['weight' => 100, 'base' => [10, 25, 45, 75], 'growth' => 3.5], @@ -56,18 +144,19 @@ return [ 'legendary' => [1, 1], ], 'affix_weights' => [ - 'def' => 40, + 'pdef' => 30, + 'mdef' => 30, 'hp' => 40, - 'atk' => 10, - 'crit' => 15, - 'critdmg' => 15, + 'patk' => 5, + 'matk' => 5, ], ], 'boots' => [ 'names' => ['布鞋', '皮靴', '铁靴', '疾风靴', '幽步靴', '龙鳞靴'], 'fixed_primary' => [ - 'def' => ['base' => [2, 5, 10, 18], 'growth' => 0.5], + 'pdef' => ['base' => [1, 4, 8, 15], 'growth' => 0.4], + 'mdef' => ['base' => [1, 3, 6, 12], 'growth' => 0.3], ], 'random_primary_pool' => [ 'hp' => ['weight' => 60, 'base' => [8, 20, 35, 60], 'growth' => 2.5], @@ -80,10 +169,10 @@ return [ 'legendary' => [1, 2], ], 'affix_weights' => [ - 'def' => 35, - 'hp' => 35, + 'pdef' => 25, + 'mdef' => 25, + 'hp' => 30, 'crit' => 20, - 'critdmg' => 10, ], ], @@ -93,8 +182,9 @@ return [ 'crit' => ['base' => [2, 5, 8, 12], 'growth' => 0.4], ], 'random_primary_pool' => [ - 'critdmg' => ['weight' => 60, 'base' => [5, 12, 20, 35], 'growth' => 0.8], - 'atk' => ['weight' => 40, 'base' => [3, 8, 15, 25], 'growth' => 1.0], + 'critdmg' => ['weight' => 40, 'base' => [5, 12, 20, 35], 'growth' => 0.8], + 'patk' => ['weight' => 30, 'base' => [2, 6, 12, 20], 'growth' => 0.8], + 'matk' => ['weight' => 30, 'base' => [2, 6, 12, 20], 'growth' => 0.8], ], 'random_primary_count' => [ 'common' => [0, 0], @@ -103,10 +193,10 @@ return [ 'legendary' => [1, 2], ], 'affix_weights' => [ - 'crit' => 35, - 'critdmg' => 35, - 'atk' => 20, - 'hp' => 10, + 'crit' => 30, + 'critdmg' => 30, + 'patk' => 20, + 'matk' => 20, ], ], @@ -116,7 +206,8 @@ return [ 'hp' => ['base' => [15, 35, 60, 100], 'growth' => 4.0], ], 'random_primary_pool' => [ - 'def' => ['weight' => 50, 'base' => [2, 6, 12, 20], 'growth' => 0.6], + 'pdef' => ['weight' => 25, 'base' => [1, 5, 10, 18], 'growth' => 0.5], + 'mdef' => ['weight' => 25, 'base' => [1, 5, 10, 18], 'growth' => 0.5], 'critdmg' => ['weight' => 50, 'base' => [3, 8, 15, 25], 'growth' => 0.5], ], 'random_primary_count' => [ @@ -126,10 +217,11 @@ return [ 'legendary' => [1, 2], ], 'affix_weights' => [ - 'hp' => 40, - 'def' => 30, - 'atk' => 15, + 'hp' => 30, + 'pdef' => 20, + 'mdef' => 20, 'crit' => 15, + 'critdmg' => 15, ], ], diff --git a/src/Data/maps.php b/src/Data/maps.php index 0ebb98e..60129cc 100644 --- a/src/Data/maps.php +++ b/src/Data/maps.php @@ -13,21 +13,24 @@ // ========== 通用装备模板 ========== $weaponTemplate = [ 'fixed_primary' => [ - 'atk' => ['base' => [5, 12, 22, 38], 'growth' => 1.8], + 'patk' => ['base' => [4, 10, 18, 30], 'growth' => 1.5], + 'matk' => ['base' => [2, 5, 10, 18], 'growth' => 0.8], ], 'random_primary_pool' => [ - 'crit' => ['weight' => 50, 'base' => [1, 3, 5, 10], 'growth' => 0.3], - 'critdmg' => ['weight' => 50, 'base' => [3, 8, 14, 24], 'growth' => 0.7], + 'crit' => ['weight' => 40, 'base' => [1, 3, 5, 10], 'growth' => 0.3], + 'critdmg' => ['weight' => 40, 'base' => [3, 8, 14, 24], 'growth' => 0.7], + 'matk' => ['weight' => 20, 'base' => [2, 5, 10, 18], 'growth' => 0.8], ], 'random_primary_count' => [ 'common' => [0, 0], 'rare' => [0, 1], 'epic' => [1, 1], 'legendary' => [1, 2] ], - 'affix_weights' => ['atk' => 40, 'crit' => 30, 'critdmg' => 30, 'hp' => 15, 'def' => 10], + 'affix_weights' => ['patk' => 30, 'matk' => 20, 'crit' => 25, 'critdmg' => 25, 'hp' => 10], ]; $armorTemplate = [ 'fixed_primary' => [ - 'def' => ['base' => [3, 8, 15, 26], 'growth' => 0.8], + 'pdef' => ['base' => [2, 6, 12, 20], 'growth' => 0.6], + 'mdef' => ['base' => [1, 4, 8, 15], 'growth' => 0.5], ], 'random_primary_pool' => [ 'hp' => ['weight' => 100, 'base' => [10, 25, 45, 75], 'growth' => 3.5], @@ -35,7 +38,7 @@ $armorTemplate = [ 'random_primary_count' => [ 'common' => [0, 0], 'rare' => [0, 1], 'epic' => [1, 1], 'legendary' => [1, 1], ], - 'affix_weights' => ['def' => 40, 'hp' => 40, 'atk' => 10, 'crit' => 15, 'critdmg' => 15], + 'affix_weights' => ['pdef' => 30, 'mdef' => 30, 'hp' => 40, 'patk' => 5, 'matk' => 5], ]; $ringTemplate = [ @@ -43,13 +46,14 @@ $ringTemplate = [ 'crit' => ['base' => [2, 5, 8, 12], 'growth' => 0.4], ], 'random_primary_pool' => [ - 'critdmg' => ['weight' => 60, 'base' => [5, 12, 20, 35], 'growth' => 0.8], - 'atk' => ['weight' => 40, 'base' => [3, 8, 15, 25], 'growth' => 1.0], + 'critdmg' => ['weight' => 40, 'base' => [5, 12, 20, 35], 'growth' => 0.8], + 'patk' => ['weight' => 30, 'base' => [2, 6, 12, 20], 'growth' => 0.8], + 'matk' => ['weight' => 30, 'base' => [2, 6, 12, 20], 'growth' => 0.8], ], 'random_primary_count' => [ 'common' => [0, 0], 'rare' => [0, 1], 'epic' => [1, 1], 'legendary' => [1, 2], ], - 'affix_weights' => ['crit' => 35, 'critdmg' => 35, 'atk' => 20, 'hp' => 10], + 'affix_weights' => ['crit' => 30, 'critdmg' => 30, 'patk' => 20, 'matk' => 20], ]; $necklaceTemplate = [ @@ -57,18 +61,20 @@ $necklaceTemplate = [ 'hp' => ['base' => [15, 35, 60, 100], 'growth' => 4.0], ], 'random_primary_pool' => [ - 'def' => ['weight' => 50, 'base' => [2, 6, 12, 20], 'growth' => 0.6], + 'pdef' => ['weight' => 25, 'base' => [1, 5, 10, 18], 'growth' => 0.5], + 'mdef' => ['weight' => 25, 'base' => [1, 5, 10, 18], 'growth' => 0.5], 'critdmg' => ['weight' => 50, 'base' => [3, 8, 15, 25], 'growth' => 0.5], ], 'random_primary_count' => [ 'common' => [0, 0], 'rare' => [0, 1], 'epic' => [1, 1], 'legendary' => [1, 2], ], - 'affix_weights' => ['hp' => 40, 'def' => 30, 'atk' => 15, 'crit' => 15], + 'affix_weights' => ['hp' => 30, 'pdef' => 20, 'mdef' => 20, 'crit' => 15, 'critdmg' => 15], ]; $bootsTemplate = [ 'fixed_primary' => [ - 'def' => ['base' => [2, 5, 10, 18], 'growth' => 0.5], + 'pdef' => ['base' => [1, 4, 8, 15], 'growth' => 0.4], + 'mdef' => ['base' => [1, 3, 6, 12], 'growth' => 0.3], ], 'random_primary_pool' => [ 'hp' => ['weight' => 60, 'base' => [8, 20, 35, 60], 'growth' => 2.5], @@ -77,7 +83,7 @@ $bootsTemplate = [ 'random_primary_count' => [ 'common' => [0, 0], 'rare' => [0, 1], 'epic' => [1, 1], 'legendary' => [1, 2], ], - 'affix_weights' => ['def' => 35, 'hp' => 35, 'crit' => 20, 'critdmg' => 10], + 'affix_weights' => ['pdef' => 25, 'mdef' => 25, 'hp' => 30, 'crit' => 20], ]; return [ @@ -119,6 +125,9 @@ return [ ['type' => 'armor', 'name' => '皮甲', 'rate' => 10] + $armorTemplate, ['type' => 'consume', 'name' => '黄龙丹', 'rate' => 25, 'heal' => 50], ], + 'minions' => [ + ['name' => '野狼帮帮众', 'hp' => 30, 'patk' => 5, 'matk' => 2, 'pdef' => 0, 'mdef' => 0, 'exp' => 10, 'count' => 2], + ], 'weight' => 30, ], [ @@ -132,10 +141,13 @@ return [ 'exp' => 100, 'spirit_stones' => 20, 'drops' => [ - ['type' => 'weapon', 'name' => '眨眼剑法', 'quality' => 'rare', 'atk' => 15, 'rate' => 20, 'affixes' => ['crit' => 5]], + ['type' => 'weapon', 'name' => '眨眼剑法', 'quality' => 'rare', 'patk' => 15, 'rate' => 20, 'affixes' => ['crit' => 5]], ['type' => 'necklace', 'name' => '长生锁', 'rate' => 15] + $necklaceTemplate, ['type' => 'consume', 'name' => '清灵散', 'rate' => 40, 'heal' => 80], ], + 'minions' => [ + ['name' => '铁奴', 'hp' => 80, 'patk' => 12, 'pdef' => 8, 'exp' => 30, 'count' => 1], + ], 'weight' => 10, ], ], @@ -188,7 +200,7 @@ return [ 'exp' => 150, 'spirit_stones' => 40, 'drops' => [ - ['type' => 'weapon', 'name' => '青叶法器', 'quality' => 'rare', 'atk' => 25, 'rate' => 20], + ['type' => 'weapon', 'name' => '青叶法器', 'quality' => 'rare', 'matk' => 25, 'rate' => 20], ['type' => 'ring', 'name' => '储物戒', 'rate' => 15] + $ringTemplate, ['type' => 'consume', 'name' => '合气丹', 'rate' => 30, 'heal' => 100], ], @@ -243,8 +255,8 @@ return [ 'exp' => 300, 'spirit_stones' => 100, 'drops' => [ - ['type' => 'weapon', 'name' => '金竺笔', 'quality' => 'epic', 'atk' => 45, 'rate' => 15, 'affixes' => ['atk' => 10]], - ['type' => 'armor', 'name' => '墨蛟甲', 'quality' => 'epic', 'def' => 30, 'rate' => 15], + ['type' => 'weapon', 'name' => '金竺笔', 'quality' => 'epic', 'matk' => 45, 'rate' => 15, 'affixes' => ['matk' => 10]], + ['type' => 'armor', 'name' => '墨蛟甲', 'quality' => 'epic', 'pdef' => 20, 'mdef' => 15, 'rate' => 15], ['type' => 'consume', 'name' => '筑基丹', 'rate' => 50, 'heal' => 500], ], 'weight' => 15, @@ -302,7 +314,7 @@ return [ 'exp' => 400, 'spirit_stones' => 150, 'drops' => [ - ['type' => 'weapon', 'name' => '烈焰刀', 'quality' => 'epic', 'atk' => 70, 'rate' => 20], + ['type' => 'weapon', 'name' => '烈焰刀', 'quality' => 'epic', 'patk' => 50, 'matk' => 30, 'rate' => 20], ['type' => 'ring', 'name' => '传音符', 'rate' => 20] + $ringTemplate, ['type' => 'consume', 'name' => '定颜丹', 'rate' => 10, 'heal' => 800], ], @@ -358,8 +370,8 @@ return [ 'exp' => 600, 'spirit_stones' => 250, 'drops' => [ - ['type' => 'weapon', 'name' => '血灵钻', 'quality' => 'epic', 'atk' => 100, 'rate' => 20, 'affixes' => ['crit' => 10]], - ['type' => 'armor', 'name' => '血灵甲', 'quality' => 'epic', 'def' => 60, 'rate' => 20], + ['type' => 'weapon', 'name' => '血灵钻', 'quality' => 'epic', 'matk' => 100, 'rate' => 20, 'affixes' => ['crit' => 10]], + ['type' => 'armor', 'name' => '血灵甲', 'quality' => 'epic', 'pdef' => 40, 'mdef' => 30, 'rate' => 20], ['type' => 'consume', 'name' => '血灵丹', 'rate' => 30, 'heal' => 1000], ], 'weight' => 15, @@ -414,7 +426,7 @@ return [ 'exp' => 1000, 'spirit_stones' => 400, 'drops' => [ - ['type' => 'weapon', 'name' => '青元剑', 'quality' => 'legendary', 'atk' => 150, 'rate' => 15, 'affixes' => ['atk' => 15]], + ['type' => 'weapon', 'name' => '青元剑', 'quality' => 'legendary', 'patk' => 100, 'matk' => 80, 'rate' => 15, 'affixes' => ['patk' => 15]], ['type' => 'consume', 'name' => '虚天鼎碎片', 'rate' => 10, 'heal' => 2000], // 剧情物品作为高回复药 ['type' => 'ring', 'name' => '黑煞戒', 'rate' => 20] + $ringTemplate, ], @@ -473,7 +485,7 @@ return [ 'exp' => 1500, 'spirit_stones' => 600, 'drops' => [ - ['type' => 'weapon', 'name' => '引魂钟', 'quality' => 'epic', 'atk' => 200, 'rate' => 20], + ['type' => 'weapon', 'name' => '引魂钟', 'quality' => 'epic', 'matk' => 200, 'rate' => 20], ['type' => 'boots', 'name' => '踏浪靴', 'rate' => 15] + $bootsTemplate, ['type' => 'consume', 'name' => '降尘丹', 'rate' => 25, 'heal' => 1500], ], @@ -529,7 +541,7 @@ return [ 'exp' => 2500, 'spirit_stones' => 1000, 'drops' => [ - ['type' => 'weapon', 'name' => '天都尸火', 'quality' => 'legendary', 'atk' => 300, 'rate' => 15, 'affixes' => ['critdmg' => 20]], + ['type' => 'weapon', 'name' => '天都尸火', 'quality' => 'legendary', 'matk' => 300, 'rate' => 15, 'affixes' => ['critdmg' => 20]], ['type' => 'consume', 'name' => '补天丹', 'rate' => 10, 'heal' => 3000], ['type' => 'necklace', 'name' => '虚天鼎', 'quality' => 'legendary', 'hp' => 2000, 'rate' => 5], ], @@ -585,8 +597,8 @@ return [ 'exp' => 4000, 'spirit_stones' => 1500, 'drops' => [ - ['type' => 'weapon', 'name' => '金蛟剪', 'quality' => 'legendary', 'atk' => 450, 'rate' => 15, 'affixes' => ['crit' => 15]], - ['type' => 'armor', 'name' => '金蛟鳞甲', 'quality' => 'legendary', 'def' => 250, 'rate' => 15], + ['type' => 'weapon', 'name' => '金蛟剪', 'quality' => 'legendary', 'patk' => 300, 'matk' => 200, 'rate' => 15, 'affixes' => ['crit' => 15]], + ['type' => 'armor', 'name' => '金蛟鳞甲', 'quality' => 'legendary', 'pdef' => 180, 'mdef' => 120, 'rate' => 15], ['type' => 'consume', 'name' => '九曲灵参', 'rate' => 10, 'heal' => 5000], ], 'weight' => 15, @@ -644,7 +656,7 @@ return [ 'exp' => 5000, 'spirit_stones' => 2000, 'drops' => [ - ['type' => 'weapon', 'name' => '落云剑', 'quality' => 'epic', 'atk' => 500, 'rate' => 20], + ['type' => 'weapon', 'name' => '落云剑', 'quality' => 'epic', 'patk' => 350, 'matk' => 250, 'rate' => 20], ['type' => 'necklace', 'name' => '定魂珠', 'rate' => 15] + $necklaceTemplate, ['type' => 'consume', 'name' => '培婴丹', 'rate' => 25, 'heal' => 3000], ], @@ -700,8 +712,8 @@ return [ 'exp' => 10000, 'spirit_stones' => 5000, 'drops' => [ - ['type' => 'weapon', 'name' => '黑风旗', 'quality' => 'legendary', 'atk' => 800, 'rate' => 15, 'affixes' => ['atk' => 20]], - ['type' => 'armor', 'name' => '魔龙甲', 'quality' => 'legendary', 'def' => 500, 'rate' => 15], + ['type' => 'weapon', 'name' => '黑风旗', 'quality' => 'legendary', 'matk' => 800, 'rate' => 15, 'affixes' => ['matk' => 20]], + ['type' => 'armor', 'name' => '魔龙甲', 'quality' => 'legendary', 'pdef' => 350, 'mdef' => 250, 'rate' => 15], ['type' => 'consume', 'name' => '万年灵乳', 'rate' => 20, 'heal' => 8000], ], 'weight' => 15, @@ -759,7 +771,7 @@ return [ 'exp' => 15000, 'spirit_stones' => 8000, 'drops' => [ - ['type' => 'weapon', 'name' => '八灵尺', 'quality' => 'legendary', 'atk' => 1200, 'rate' => 15, 'affixes' => ['crit' => 20]], + ['type' => 'weapon', 'name' => '八灵尺', 'quality' => 'legendary', 'matk' => 1200, 'rate' => 15, 'affixes' => ['crit' => 20]], ['type' => 'ring', 'name' => '雪晶珠', 'quality' => 'legendary', 'crit' => 15, 'rate' => 15], ['type' => 'consume', 'name' => '回阳水', 'rate' => 10, 'heal' => 10000], ], @@ -815,8 +827,8 @@ return [ 'exp' => 30000, 'spirit_stones' => 15000, 'drops' => [ - ['type' => 'weapon', 'name' => '青竹蜂云剑', 'quality' => 'legendary', 'atk' => 2000, 'rate' => 20, 'affixes' => ['atk' => 30, 'crit' => 20]], - ['type' => 'armor', 'name' => '五行甲', 'quality' => 'legendary', 'def' => 1500, 'rate' => 20], + ['type' => 'weapon', 'name' => '青竹蜂云剑', 'quality' => 'legendary', 'patk' => 1500, 'matk' => 1000, 'rate' => 20, 'affixes' => ['patk' => 30, 'crit' => 20]], + ['type' => 'armor', 'name' => '五行甲', 'quality' => 'legendary', 'pdef' => 1000, 'mdef' => 1000, 'rate' => 20], ['type' => 'consume', 'name' => '飞升令', 'rate' => 100, 'heal' => 99999], // 象征性物品 ], 'weight' => 15, diff --git a/src/Data/npcs.php b/src/Data/npcs.php index c449566..0140cd6 100644 --- a/src/Data/npcs.php +++ b/src/Data/npcs.php @@ -11,7 +11,7 @@ return [ 'min_level' => 1, 'desc' => '韩立在七玄门最好的朋友,虽无灵根但武功高强。', 'base_stats' => [ - 'hp' => 100, 'patk' => 15, 'matk' => 5, 'pdef' => 5, 'mdef' => 3, 'crit' => 10, 'critdmg' => 150, 'growth' => 1.2 + 'hp' => 100, 'patk' => 15, 'matk' => 5, 'pdef' => 5, 'mdef' => 3, 'crit' => 10, 'critdmg' => 130, 'growth' => 1.2 ], // 天赋权重:武功型,偏攻击和暴击 'talent_weights' => [ diff --git a/src/Entities/Item.php b/src/Entities/Item.php index ca3bfc7..764ae9a 100644 --- a/src/Entities/Item.php +++ b/src/Entities/Item.php @@ -3,9 +3,6 @@ namespace Game\Entities; /** * Simple representation of an equipment/consumable item. - * - * The game only needs an associative array for storage, but having a class - * makes random generation easier and keeps the logic tidy. */ class Item { @@ -15,12 +12,19 @@ class Item public int $level = 1; // Item level private array $affixes; + // Stats + public int $patk = 0; + public int $matk = 0; + public int $pdef = 0; + public int $mdef = 0; + public int $hp = 0; + public int $crit = 0; + public int $critdmg = 0; + public int $heal = 0; + public string $desc = ''; + /** * Generate a random item of the given type and level. - * @param string $type Item type (weapon, armor, etc.) - * @param int $level Item level - * @param string|null $specificName If provided, use this name instead of random selection - * @return array Item data array */ public static function randomItem(string $type, int $level = 1, ?string $specificName = null): array { @@ -30,323 +34,7 @@ class Item $data = require __DIR__ . '/../../src/Data/items.php'; } - // 品质对照表:affix 数量和索引 - $qualityConfig = [ - 'common' => ['affixes' => 0, 'index' => 0], - 'rare' => ['affixes' => 1, 'index' => 1], - 'epic' => ['affixes' => 2, 'index' => 2], - 'legendary' => ['affixes' => 3, 'index' => 3], - ]; - - // 随机品质 - $roll = rand(1, 100); - if ($roll <= 70) $quality = 'common'; // 70% 普通 - elseif ($roll <= 90) $quality = 'rare'; // 20% 稀有 - elseif ($roll <= 98) $quality = 'epic'; // 8% 史诗 - else $quality = 'legendary'; // 2% 传说 - - $item = new self(); - $item->type = $type; - $item->quality = $quality; - $item->level = $level; - - // 获取品质对应的词条数量和属性索引 - $affixCount = $qualityConfig[$quality]['affixes']; - $qualityIndex = $qualityConfig[$quality]['index']; - - // =========================== - // ① 基础名称与基础属性 (Scaling with Level) - // =========================== - - $typeConfig = $data['types'][$type] ?? null; - - if (!$typeConfig) { - $item->name = '未知物品'; - $item->desc = '未知'; - return $item->toArray(); // Helper method needed or manual array return - } - - $names = $typeConfig['names'] ?? ['未知物品']; - - // Use specific name if provided, otherwise random selection - if ($specificName !== null && in_array($specificName, $names)) { - $item->name = $specificName; - } else { - $item->name = $names[array_rand($names)]; - } - - // =========================== - // ① 生成主属性(固定 + 随机) - // =========================== - - // 初始化所有可能的属性为0 - $item->atk = 0; - $item->def = 0; - $item->hp = 0; - $item->crit = 0; - $item->critdmg = 0; - - if ($type === 'consume') { - // 消耗品保持原有逻辑 - $baseStats = $typeConfig['base_stats'] ?? [0,0,0,0]; - $growth = $typeConfig['growth'] ?? 0; - $item->heal = $baseStats[$qualityIndex] + ($level * $growth) + rand(0, 10); - $item->desc = "Lv.{$level} {$quality}品质的药剂"; - } else { - // 装备:固定主属性 + 随机主属性 - $fixedPrimaries = $typeConfig['fixed_primary'] ?? []; - $randomPool = $typeConfig['random_primary_pool'] ?? []; - $randomCountConfig = $typeConfig['random_primary_count'][$quality] ?? [0, 0]; - - // Step 1: 生成固定主属性(必定存在) - foreach ($fixedPrimaries as $statKey => $statConfig) { - $baseValue = $statConfig['base'][$qualityIndex]; - $growth = $statConfig['growth']; - - // 主属性数值 = 基础值 + 等级成长 + 随机波动 - $randomBonus = rand(0, max(1, (int)($baseValue * 0.15))); // 15%随机波动 - $finalValue = (int)($baseValue + ($level * $growth) + $randomBonus); - - // 赋值到对应属性 - switch ($statKey) { - case 'atk': - $item->atk = $finalValue; - break; - case 'def': - $item->def = $finalValue; - break; - case 'hp': - $item->hp = $finalValue; - break; - case 'crit': - $item->crit = $finalValue; - break; - case 'critdmg': - $item->critdmg = $finalValue; - break; - } - } - - // Step 2: 生成随机主属性(根据品质决定数量) - if (!empty($randomPool)) { - [$minCount, $maxCount] = $randomCountConfig; - $randomCount = rand($minCount, $maxCount); - - if ($randomCount > 0) { - // 使用权重随机选择额外主属性(不重复) - $selectedRandoms = []; - $availableStats = $randomPool; - - for ($i = 0; $i < $randomCount && !empty($availableStats); $i++) { - // 提取权重 - $weights = []; - foreach ($availableStats as $statKey => $statConfig) { - $weights[$statKey] = $statConfig['weight']; - } - - // 权重随机选择 - $selectedStat = self::weightedRandom($weights); - $selectedRandoms[] = $selectedStat; - - // 移除已选择的属性(避免重复) - unset($availableStats[$selectedStat]); - } - - // 生成随机主属性数值 - foreach ($selectedRandoms as $statKey) { - $statConfig = $randomPool[$statKey]; - $baseValue = $statConfig['base'][$qualityIndex]; - $growth = $statConfig['growth']; - - // 主属性数值 = 基础值 + 等级成长 + 随机波动 - $randomBonus = rand(0, max(1, (int)($baseValue * 0.15))); // 15%随机波动 - $finalValue = (int)($baseValue + ($level * $growth) + $randomBonus); - - // 赋值到对应属性 - switch ($statKey) { - case 'atk': - $item->atk = $finalValue; - break; - case 'def': - $item->def = $finalValue; - break; - case 'hp': - $item->hp = $finalValue; - break; - case 'crit': - $item->crit = $finalValue; - break; - case 'critdmg': - $item->critdmg = $finalValue; - break; - } - } - } - } - - // 设置描述 - $item->desc = "Lv.{$level} {$quality}品质的" . match($type) { - 'weapon' => '武器', - 'armor' => '防具', - 'ring' => '戒指', - 'necklace' => '项链', - default => '装备' - }; - } - - // =========================== - // ② 词条池(固定值 + 百分比) - // =========================== - - $affixNames = $data['affix_definitions']; - $affixWeights = $typeConfig['affix_weights'] ?? []; - - // =========================== - // ③ 随机 affix(使用权重系统,避免重复) - // =========================== - $selectedAffixes = []; - - for ($i = 0; $i < $affixCount; $i++) { - - if ($type == 'consume') break; - - if (empty($affixWeights)) break; - - // 移除已选择的词条,避免重复 - $availableWeights = array_diff_key($affixWeights, array_flip($selectedAffixes)); - - if (empty($availableWeights)) break; - - // 使用权重随机选择词条 - $key = self::weightedRandom($availableWeights); - $selectedAffixes[] = $key; - - // 固定 or 百分比? - $usePercent = (bool)rand(0, 1); - - if ($usePercent) { - // Percentages scale slower but better for higher levels - $base = rand(2, 8); // 提高百分比基础值 - $v = $base + floor($level / 3); // 每3级增加1% - $item->affixes[] = "{$affixNames[$key]} +{$v}%"; - } else { - // Flat values scale with level and quality - $qualityMultiplier = match($quality) { - 'legendary' => 2.0, - 'epic' => 1.5, - 'rare' => 1.2, - default => 1.0 - }; - - $base = rand(2, 8); - $multiplier = match($key) { - 'atk' => 1.5, - 'def' => 1.0, - 'hp' => 8, - 'crit' => 0.5, - 'critdmg' => 0.8, - default => 1 - }; - $v = floor(($base + ($level * $multiplier)) * $qualityMultiplier); - $item->affixes[] = "{$affixNames[$key]} +{$v}"; - } - } - - // =========================== - // ④ 返回数组格式 - // =========================== - return [ - 'name' => $item->name, - 'type' => $item->type, - 'quality' => $item->quality, - 'level' => $item->level, - 'atk' => $item->atk ?? 0, - 'def' => $item->def ?? 0, - 'hp' => $item->hp ?? 0, - 'crit' => $item->crit ?? 0, - 'critdmg' => $item->critdmg ?? 0, - 'heal' => $item->heal ?? 0, - 'affixes' => $item->affixes ?? [], - 'desc' => $item->desc, - ]; - } - - /** - * Weighted random selection helper - * @param array $weights Associative array of key => weight - * @return string Selected key - */ - private static function weightedRandom(array $weights): string - { - $totalWeight = array_sum($weights); - $rand = rand(1, $totalWeight); - - foreach ($weights as $key => $weight) { - $rand -= $weight; - if ($rand <= 0) { - return $key; - } - } - - // Fallback to first key - return array_key_first($weights); - } - - // =========================== - // ⑤ 生成特定物品(用于掉落) - // =========================== - /** - * Generate a specific item based on a configuration array. - * Expected keys: - * - type: Item type (weapon, armor, etc.) - * - name (optional): Specific item name (e.g., '铁剑'). If provided, this exact item will be generated with random quality/affixes - * - quality (optional): Force specific quality (overrides random quality) - * - level (optional): Item level - * - affixes (optional): Force specific affixes (overrides random affixes) - */ - public static function createFromSpec(array $spec, int $baseLevel): array - { - $type = $spec['type'] ?? 'weapon'; - $quality = $spec['quality'] ?? null; - $itemLevel = $spec['level'] ?? $baseLevel; - $affixes = $spec['affixes'] ?? []; - $specificName = $spec['name'] ?? null; - - // Load data definitions - static $data = null; - if ($data === null) { - $data = require __DIR__ . '/../../src/Data/items.php'; - } - - // Generate item with specific name (if provided) - $item = self::randomItem($type, $itemLevel, $specificName); - - // Override quality if specified (otherwise uses random quality from randomItem) - if ($quality) { - $item['quality'] = $quality; - } - - // Override affixes if specified (otherwise uses random affixes from randomItem) - if (!empty($affixes)) { - $item['affixes'] = $affixes; - } - - return $item; - } - - /** - * 使用详细配置生成装备(支持 maps.php 中的 fixed_primary, random_primary_pool 等) - * @param array $spec 掉落配置 - * @param int $baseLevel 基础等级 - * @return array - */ - public static function createFromSpecWithConfig(array $spec, int $baseLevel): array - { - $type = $spec['type'] ?? 'weapon'; - $name = $spec['name'] ?? '未知装备'; - $itemLevel = $spec['level'] ?? $baseLevel; - - // 品质配置 + // 品质对照表 $qualityConfig = [ 'common' => ['affixes' => 0, 'index' => 0], 'rare' => ['affixes' => 1, 'index' => 1], @@ -357,108 +45,114 @@ class Item // 随机品质 $roll = rand(1, 100); if ($roll <= 70) $quality = 'common'; - elseif ($roll <= 90) $quality = 'rare'; - elseif ($roll <= 98) $quality = 'epic'; - else $quality = 'legendary'; + elseif ($roll <= 90) $quality = 'rare'; + elseif ($roll <= 98) $quality = 'epic'; + else $quality = 'legendary'; - // 如果配置指定了品质,则使用指定品质 - if (isset($spec['quality'])) { - $quality = $spec['quality']; + $item = new self(); + $item->type = $type; + $item->quality = $quality; + $item->level = $level; + + $affixCount = $qualityConfig[$quality]['affixes']; + $qualityIndex = $qualityConfig[$quality]['index']; + + $typeConfig = $data['types'][$type] ?? null; + + if (!$typeConfig) { + $item->name = '未知物品'; + $item->desc = '未知'; + return $item->toArray(); } - $qualityIndex = $qualityConfig[$quality]['index']; - $affixCount = $qualityConfig[$quality]['affixes']; + $names = $typeConfig['names'] ?? ['未知物品']; + + if ($specificName !== null && in_array($specificName, $names)) { + $item->name = $specificName; + } else { + $item->name = $names[array_rand($names)]; + } // 初始化属性 - $item = [ - 'name' => $name, - 'type' => $type, - 'quality' => $quality, - 'level' => $itemLevel, - 'atk' => 0, - 'def' => 0, - 'hp' => 0, - 'crit' => 0, - 'critdmg' => 0, - 'heal' => 0, - 'affixes' => [], - 'desc' => "Lv.{$itemLevel} {$quality}品质", - ]; + $item->patk = 0; + $item->matk = 0; + $item->pdef = 0; + $item->mdef = 0; + $item->hp = 0; + $item->crit = 0; + $item->critdmg = 0; - // ===== 处理固定主属性 ===== - $fixedPrimary = $spec['fixed_primary'] ?? []; - foreach ($fixedPrimary as $statKey => $statConfig) { - $baseValues = $statConfig['base'] ?? [0, 0, 0, 0]; - $growth = $statConfig['growth'] ?? 0; + if ($type === 'consume') { + $baseStats = $typeConfig['base_stats'] ?? [0,0,0,0]; + $growth = $typeConfig['growth'] ?? 0; + $item->heal = $baseStats[$qualityIndex] + ($level * $growth) + rand(0, 10); + $item->desc = "Lv.{$level} {$quality}品质的药剂"; + } else { + // 检查是否有特定物品配置 + $specificConfig = $typeConfig['specific_config'][$item->name] ?? []; + + // 合并配置:优先使用特定配置,否则使用默认配置 + $fixedPrimaries = $specificConfig['fixed_primary'] ?? $typeConfig['fixed_primary'] ?? []; + $randomPool = $specificConfig['random_primary_pool'] ?? $typeConfig['random_primary_pool'] ?? []; + $randomCountConfig = $typeConfig['random_primary_count'][$quality] ?? [0, 0]; - $baseValue = $baseValues[$qualityIndex] ?? $baseValues[0]; - $randomBonus = rand(0, max(1, (int)($baseValue * 0.15))); - $finalValue = (int)($baseValue + ($itemLevel * $growth) + $randomBonus); + // 1. 固定主属性 + foreach ($fixedPrimaries as $statKey => $statConfig) { + $baseValue = $statConfig['base'][$qualityIndex]; + $growth = $statConfig['growth']; + $randomBonus = rand(0, max(1, (int)($baseValue * 0.15))); + $finalValue = (int)($baseValue + ($level * $growth) + $randomBonus); + $item->$statKey = $finalValue; + } - $item[$statKey] = $finalValue; - } + // 2. 随机主属性 + if (!empty($randomPool)) { + [$minCount, $maxCount] = $randomCountConfig; + $randomCount = rand($minCount, $maxCount); - // ===== 处理随机主属性 ===== - $randomPool = $spec['random_primary_pool'] ?? []; - $randomCountConfig = $spec['random_primary_count'][$quality] ?? [0, 0]; + if ($randomCount > 0) { + $selectedRandoms = []; + $availableStats = $randomPool; - if (!empty($randomPool)) { - [$minCount, $maxCount] = $randomCountConfig; - $randomCount = rand($minCount, $maxCount); - - if ($randomCount > 0) { - $availableStats = $randomPool; - $selectedRandoms = []; - - for ($i = 0; $i < $randomCount && !empty($availableStats); $i++) { - $weights = []; - foreach ($availableStats as $statKey => $statConfig) { - $weights[$statKey] = $statConfig['weight'] ?? 50; + for ($i = 0; $i < $randomCount && !empty($availableStats); $i++) { + $weights = []; + foreach ($availableStats as $statKey => $statConfig) { + $weights[$statKey] = $statConfig['weight']; + } + $selectedStat = self::weightedRandom($weights); + $selectedRandoms[] = $selectedStat; + unset($availableStats[$selectedStat]); } - $selectedStat = self::weightedRandom($weights); - $selectedRandoms[] = $selectedStat; - unset($availableStats[$selectedStat]); - } - - foreach ($selectedRandoms as $statKey) { - $statConfig = $randomPool[$statKey]; - $baseValues = $statConfig['base'] ?? [0, 0, 0, 0]; - $growth = $statConfig['growth'] ?? 0; - - $baseValue = $baseValues[$qualityIndex] ?? $baseValues[0]; - $randomBonus = rand(0, max(1, (int)($baseValue * 0.15))); - $finalValue = (int)($baseValue + ($itemLevel * $growth) + $randomBonus); - - $item[$statKey] = ($item[$statKey] ?? 0) + $finalValue; + foreach ($selectedRandoms as $statKey) { + $statConfig = $randomPool[$statKey]; + $baseValue = $statConfig['base'][$qualityIndex]; + $growth = $statConfig['growth']; + $randomBonus = rand(0, max(1, (int)($baseValue * 0.15))); + $finalValue = (int)($baseValue + ($level * $growth) + $randomBonus); + $item->$statKey += $finalValue; + } } } + + $item->desc = "Lv.{$level} {$quality}品质的" . match($type) { + 'weapon' => '武器', + 'armor' => '防具', + 'boots' => '鞋子', + 'ring' => '戒指', + 'necklace' => '项链', + default => '装备' + }; } - // ===== 生成词条 ===== - static $data = null; - if ($data === null) { - $data = require __DIR__ . '/../../src/Data/items.php'; - } - - $affixNames = $data['affix_definitions'] ?? [ - 'atk' => '攻击', - 'def' => '防御', - 'hp' => '生命值', - 'crit' => '暴击率', - 'critdmg' => '暴击伤害', - ]; - - $affixWeights = $spec['affix_weights'] ?? [ - 'atk' => 25, - 'def' => 25, - 'hp' => 25, - 'crit' => 15, - 'critdmg' => 10, - ]; + // 3. 词条 + $affixNames = $data['affix_definitions']; + $affixWeights = $typeConfig['affix_weights'] ?? []; + $item->affixes = []; $selectedAffixes = []; for ($i = 0; $i < $affixCount; $i++) { + if ($type == 'consume') break; if (empty($affixWeights)) break; $availableWeights = array_diff_key($affixWeights, array_flip($selectedAffixes)); @@ -471,8 +165,8 @@ class Item if ($usePercent) { $base = rand(2, 8); - $v = $base + floor($itemLevel / 3); - $item['affixes'][] = "{$affixNames[$key]} +{$v}%"; + $v = $base + floor($level / 3); + $item->affixes[] = "{$affixNames[$key]} +{$v}%"; } else { $qualityMultiplier = match($quality) { 'legendary' => 2.0, @@ -483,76 +177,109 @@ class Item $base = rand(2, 8); $multiplier = match($key) { - 'atk' => 1.5, - 'def' => 1.0, + 'patk' => 1.5, + 'matk' => 1.5, + 'pdef' => 1.0, + 'mdef' => 1.0, 'hp' => 8, 'crit' => 0.5, 'critdmg' => 0.8, default => 1 }; - $v = floor(($base + ($itemLevel * $multiplier)) * $qualityMultiplier); - $item['affixes'][] = "{$affixNames[$key]} +{$v}"; + $v = floor(($base + ($level * $multiplier)) * $qualityMultiplier); + $item->affixes[] = "{$affixNames[$key]} +{$v}"; } } - // 设置描述 - $item['desc'] = "Lv.{$itemLevel} {$quality}品质的" . match($type) { - 'weapon' => '武器', - 'armor' => '防具', - 'boots' => '鞋子', - 'ring' => '戒指', - 'necklace' => '项链', - default => '装备' - }; + return $item->toArray(); + } + + private static function weightedRandom(array $weights): string + { + $totalWeight = array_sum($weights); + $rand = rand(1, $totalWeight); + foreach ($weights as $key => $weight) { + $rand -= $weight; + if ($rand <= 0) return $key; + } + return array_key_first($weights); + } + + public static function createFromSpec(array $spec, int $baseLevel): array + { + $type = $spec['type'] ?? 'weapon'; + $quality = $spec['quality'] ?? null; + $itemLevel = $spec['level'] ?? $baseLevel; + $affixes = $spec['affixes'] ?? []; + $specificName = $spec['name'] ?? null; + + $item = self::randomItem($type, $itemLevel, $specificName); + + if ($quality) $item['quality'] = $quality; + if (!empty($affixes)) $item['affixes'] = $affixes; + + // Allow overriding specific stats if provided in spec (e.g. from maps.php drops) + foreach (['patk', 'matk', 'pdef', 'mdef', 'hp', 'crit', 'critdmg'] as $stat) { + if (isset($spec[$stat])) { + $item[$stat] = $spec[$stat]; + } + } return $item; } - /** - * 计算物品的售价(灵石) - * 基于品质、等级、属性数量计算 - */ + public static function createFromSpecWithConfig(array $spec, int $baseLevel): array + { + return self::createFromSpec($spec, $baseLevel); + } + + public function toArray(): array + { + return [ + 'name' => $this->name, + 'type' => $this->type, + 'quality' => $this->quality, + 'level' => $this->level, + 'patk' => $this->patk, + 'matk' => $this->matk, + 'pdef' => $this->pdef, + 'mdef' => $this->mdef, + 'hp' => $this->hp, + 'crit' => $this->crit, + 'critdmg' => $this->critdmg, + 'heal' => $this->heal, + 'affixes' => $this->affixes ?? [], + 'desc' => $this->desc, + ]; + } + public static function calculateSellPrice(array $item): int { - // 消耗品售价低 - if ($item['type'] === 'consume') { - $basePrice = match($item['quality']) { - 'common' => 1, - 'rare' => 3, - 'epic' => 8, - 'legendary' => 20, - default => 1 + if (($item['type'] ?? '') === 'consume') { + $basePrice = match($item['quality'] ?? 'common') { + 'common' => 1, 'rare' => 3, 'epic' => 8, 'legendary' => 20, default => 1 }; return (int)($basePrice + ($item['level'] ?? 1) * 0.5); } - // 装备基础价格(根据品质) - $basePrice = match($item['quality']) { - 'common' => 5, - 'rare' => 15, - 'epic' => 40, - 'legendary' => 100, - default => 5 + $basePrice = match($item['quality'] ?? 'common') { + 'common' => 5, 'rare' => 15, 'epic' => 40, 'legendary' => 100, default => 5 }; - // 等级加成(每级增加基础价格的10%) $levelBonus = $basePrice * ($item['level'] ?? 1) * 0.1; - // 主属性加成 $statBonus = 0; - $statBonus += ($item['atk'] ?? 0) * 0.5; - $statBonus += ($item['def'] ?? 0) * 0.5; + $statBonus += ($item['patk'] ?? 0) * 0.5; + $statBonus += ($item['matk'] ?? 0) * 0.5; + $statBonus += ($item['pdef'] ?? 0) * 0.5; + $statBonus += ($item['mdef'] ?? 0) * 0.5; $statBonus += ($item['hp'] ?? 0) * 0.1; $statBonus += ($item['crit'] ?? 0) * 1.0; $statBonus += ($item['critdmg'] ?? 0) * 0.3; - // 词条加成(每个词条增加20%) $affixCount = count($item['affixes'] ?? []); $affixBonus = $basePrice * $affixCount * 0.2; - $totalPrice = $basePrice + $levelBonus + $statBonus + $affixBonus; - - return max(1, (int)$totalPrice); + return max(1, (int)($basePrice + $levelBonus + $statBonus + $affixBonus)); } } - diff --git a/src/Entities/Monster.php b/src/Entities/Monster.php index 66d794a..a2097da 100644 --- a/src/Entities/Monster.php +++ b/src/Entities/Monster.php @@ -64,62 +64,116 @@ class Monster } // 3. Hydrate monster base stats from maps.php - $monster->name = $selectedMonster['name']; - $monster->level = $selectedMonster['level']; - $monster->baseHp = $selectedMonster['hp']; - $monster->hp = $selectedMonster['hp']; - $monster->basePatk = $selectedMonster['patk'] ?? $selectedMonster['atk'] ?? 4; - $monster->patk = $monster->basePatk; - $monster->baseMatk = $selectedMonster['matk'] ?? 2; - $monster->matk = $monster->baseMatk; - $monster->basePdef = $selectedMonster['pdef'] ?? $selectedMonster['def'] ?? 0; - $monster->pdef = $monster->basePdef; - $monster->baseMdef = $selectedMonster['mdef'] ?? 0; - $monster->mdef = $monster->baseMdef; - $monster->crit = $selectedMonster['crit'] ?? 5; - $monster->critdmg = $selectedMonster['critdmg'] ?? 150; - $monster->expReward = $selectedMonster['exp']; - $monster->spiritStoneReward = $selectedMonster['spirit_stones'] ?? 0; + $monster->hydrateFromConfig($selectedMonster); - // 4. Generate equipment from drops and equip them - $drops = $selectedMonster['drops'] ?? []; + return $monster; + } + + /** + * Create a group of monsters with random, diverse enemies (1-5 monsters) + * Each monster is independently selected from the dungeon's monster pool using weighted random selection + * @return Monster[] + */ + public static function createGroup(int $dungeonId): array + { + // Load data + static $maps = null; + if ($maps === null) { + $maps = require __DIR__ . '/../../src/Data/maps.php'; + } + + $monsterConfig = $maps[$dungeonId]['monsters'] ?? []; + if (empty($monsterConfig)) { + return [self::create($dungeonId)]; + } + + // Determine group size (1-5 enemies) + $groupSize = rand(1, 5); + $group = []; + + // Create each enemy independently using weighted random selection + for ($i = 0; $i < $groupSize; $i++) { + $totalWeight = 0; + foreach ($monsterConfig as $m) { + $totalWeight += $m['weight'] ?? 100; + } + + $rand = rand(1, $totalWeight); + $selectedConfig = null; + + foreach ($monsterConfig as $m) { + $rand -= $m['weight'] ?? 100; + if ($rand <= 0) { + $selectedConfig = $m; + break; + } + } + + if (!$selectedConfig) { + $selectedConfig = $monsterConfig[0]; + } + + // Create monster from selected config + $monster = new self(); + $monster->hydrateFromConfig($selectedConfig); + + // Add suffix to distinguish multiple monsters of same type + if ($groupSize > 1) { + $monster->name .= " (" . ($i + 1) . ")"; + } + + $group[] = $monster; + } + + return $group; + } + + public function hydrateFromConfig(array $config): void + { + $this->name = $config['name']; + $this->level = $config['level'] ?? 1; + $this->baseHp = $config['hp'] ?? 20; + $this->hp = $this->baseHp; + $this->basePatk = $config['patk'] ?? $config['atk'] ?? 4; + $this->patk = $this->basePatk; + $this->baseMatk = $config['matk'] ?? 2; + $this->matk = $this->baseMatk; + $this->basePdef = $config['pdef'] ?? $config['def'] ?? 0; + $this->pdef = $this->basePdef; + $this->baseMdef = $config['mdef'] ?? 0; + $this->mdef = $this->baseMdef; + $this->crit = $config['crit'] ?? 5; + $this->critdmg = $config['critdmg'] ?? 150; + $this->expReward = $config['exp'] ?? 0; + $this->spiritStoneReward = $config['spirit_stones'] ?? 0; + + // Drops & Equipment + $drops = $config['drops'] ?? []; foreach ($drops as $drop) { $type = $drop['type'] ?? ''; $rate = $drop['rate'] ?? 0; - // 消耗品放入掉落表,不装备 if ($type === 'consume') { $spec = $drop; unset($spec['rate']); - $item = Item::createFromSpec($spec, $monster->level); - $monster->dropTable[] = [ + $item = Item::createFromSpec($spec, $this->level); + $this->dropTable[] = [ 'item' => $item, 'rate' => $rate, ]; continue; } - // 装备类:生成并装备 if (in_array($type, ['weapon', 'armor', 'boots', 'ring', 'necklace'])) { - // 先判断是否生成这件装备(使用掉落率) - if (rand(1, 100) > $rate) { - continue; // 没有掉落这件装备 - } - - // 使用掉落配置生成装备 + if (rand(1, 100) > $rate) continue; $spec = $drop; unset($spec['rate']); - $item = Item::createFromSpecWithConfig($spec, $monster->level); - - // 装备到对应槽位(覆盖已有的) - $monster->equip[$type] = $item; + $item = Item::createFromSpecWithConfig($spec, $this->level); + $this->equip[$type] = $item; } } - // 5. Apply equipment stats to monster - $monster->applyEquipmentStats(); - - return $monster; + $this->applyEquipmentStats(); } /** diff --git a/src/Entities/Partner.php b/src/Entities/Partner.php index 043b30e..f2b94ce 100644 --- a/src/Entities/Partner.php +++ b/src/Entities/Partner.php @@ -8,6 +8,7 @@ class Partner public int $level = 1; public int $exp = 0; public int $maxExp = 100; + public int $hp = 100; // 当前血量 public array $baseStats = []; public array $equip = []; // weapon, armor, ring, boots, necklace @@ -56,6 +57,10 @@ class Partner $this->equip = $data['equip'] ?? []; $this->talents = $data['talents'] ?? $this->talents; $this->talentWeights = $data['talentWeights'] ?? $this->talentWeights; + + // 设置当前血量为最大血量 + $stats = $this->getStats(); + $this->hp = $data['hp'] ?? $stats['maxHp']; } /** @@ -166,6 +171,7 @@ class Partner /** * 根据权重自动分配天赋点 + * 重要: HP(生命值)总是必须至少加1点 */ private function autoAllocateTalent(int $points): void { @@ -184,6 +190,12 @@ class Partner $remaining -= $share; } + // 关键: 确保 HP 至少获得1点(HP是必须的) + if ($allocated['hp'] < 1) { + $allocated['hp'] = 1; + $remaining--; + } + // 剩余点数按权重优先分配 $sortedTalents = $this->talentWeights; arsort($sortedTalents); @@ -223,4 +235,18 @@ class Partner { return array_sum($this->talents); } + + /** + * 恢复队友血量 + */ + 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; // 返回实际恢复的血量 + } } diff --git a/src/Modules/Battle.php b/src/Modules/Battle.php index b5f503f..d4c2941 100644 --- a/src/Modules/Battle.php +++ b/src/Modules/Battle.php @@ -12,7 +12,8 @@ use Game\Entities\Partner; class Battle { public Player $player; - public Monster $monster; + /** @var Monster[] */ + public array $enemies = []; /** @var array 同伴当前HP */ private array $partnerHp = []; @@ -35,7 +36,7 @@ class Battle private string $reset = "\033[0m"; private int $round = 0; - private int $monsterMaxHp = 0; + private int $totalMaxHp = 0; public function __construct(public Game $game) { @@ -49,8 +50,8 @@ class Battle { $this->partnerHp = []; foreach ($this->player->partners as $partner) { - $stats = $partner->getStats(); - $this->partnerHp[$partner->id] = $stats['maxHp']; + // 从Partner对象的hp属性读取,允许队友在战斗外也能恢复 + $this->partnerHp[$partner->id] = $partner->hp; } } @@ -68,6 +69,31 @@ class Battle return $alive; } + /** + * 将战斗中的队友HP同步回Partner对象 + */ + private function syncPartnerHp(): void + { + foreach ($this->player->partners as $partner) { + $partner->hp = $this->partnerHp[$partner->id] ?? 0; + } + } + + /** + * 获取存活的敌人 + * @return Monster[] + */ + private function getAliveEnemies(): array + { + $alive = []; + foreach ($this->enemies as $enemy) { + if ($enemy->hp > 0) { + $alive[] = $enemy; + } + } + return $alive; + } + public function start() { $out = $this->game->output; @@ -77,8 +103,15 @@ class Battle while ($this->player->hp > 0) { Screen::delay(500000); - $this->monster = Monster::create($this->game->dungeonId); - $this->monsterMaxHp = $this->monster->hp; + + // 创建敌人群组 + $this->enemies = Monster::createGroup($this->game->dungeonId); + + $this->totalMaxHp = 0; + foreach ($this->enemies as $enemy) { + $this->totalMaxHp += $enemy->hp; + } + $this->round = 0; // 显示遭遇界面 @@ -88,7 +121,10 @@ class Battle // 战斗循环 while (true) { - if ($this->checkExit($out)) return; + if ($this->checkExit($out)) { + $this->syncPartnerHp(); + return; + } $this->round++; $this->renderBattleScreen($out, $playerFirst); @@ -105,23 +141,31 @@ class Battle Screen::delay(800000); if ($result) break; - if ($this->checkExit($out)) return; + if ($this->checkExit($out)) { + $this->syncPartnerHp(); + return; + } // 怪物攻击 - if ($this->monsterAttack($out)) { + if ($this->enemiesAttack($out)) { Screen::delay(1000000); + $this->syncPartnerHp(); return; } Screen::delay(800000); } else { // 怪物先攻 - if ($this->monsterAttack($out)) { + if ($this->enemiesAttack($out)) { Screen::delay(1000000); + $this->syncPartnerHp(); return; } Screen::delay(800000); - if ($this->checkExit($out)) return; + if ($this->checkExit($out)) { + $this->syncPartnerHp(); + return; + } // 玩家攻击 $result = $this->playerAttack($out); @@ -135,6 +179,8 @@ class Battle } Screen::delay(500000); + // 同步队友HP到Partner对象,然后保存状态 + $this->syncPartnerHp(); $this->game->saveState(); } } @@ -148,7 +194,11 @@ class Battle $out->writeln(""); $out->writeln(" {$this->red}⚔️ 遭遇敌人!{$this->reset}"); $out->writeln(""); - $out->writeln(" {$this->bold}{$this->white}{$this->monster->name}{$this->reset} {$this->cyan}Lv.{$this->monster->level}{$this->reset}"); + + 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); // 1秒 @@ -163,12 +213,29 @@ class Battle $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}"); - // 怪物信息 - $monsterHpPercent = max(0, $this->monster->hp) / $this->monsterMaxHp; - $monsterHpBar = $this->renderHpBar($monsterHpPercent, 20); - $monsterHpText = max(0, $this->monster->hp) . "/" . $this->monsterMaxHp; - $out->writeln("{$this->cyan}║{$this->reset} {$this->red}👹{$this->reset} {$this->bold}{$this->monster->name}{$this->reset} Lv.{$this->monster->level}"); - $out->writeln("{$this->cyan}║{$this->reset} {$monsterHpBar} {$this->white}{$monsterHpText}{$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}"); + continue; + } + $enemyHpPercent = max(0, $enemy->hp) / $enemy->baseHp; // 使用baseHp作为最大值近似,或者应该在hydrate时保存maxHp + // 实际上Monster没有maxHp属性,hp初始值就是最大值。但在战斗中hp会减少。 + // 我们需要知道最大HP。Monster::create时hp=baseHp+equipHp。 + // 简单起见,假设当前hp <= 初始hp。如果需要精确显示条,应该在Monster类加maxHp。 + // 这里暂时用 $enemy->baseHp + equipHp 估算,或者直接存一个 maxHp。 + // 为了简单,我们假设满血是初始状态。 + // 更好的做法是Monster类加一个maxHp属性。 + // 暂时用 $enemy->hp / $enemy->hp (如果满血) ... 不行。 + // 让我们修改Monster类加maxHp? 或者这里不显示条,只显示数值? + // 或者我们假定 create 出来的 hp 就是 maxHp。 + // $enemy->maxHp = $enemy->hp; // 在create里做最好。 + // 这里先只显示数值吧,或者大概估算。 + + $hpText = max(0, $enemy->hp); + $out->writeln("{$this->cyan}║{$this->reset} {$this->red}👹{$this->reset} {$this->bold}{$enemy->name}{$this->reset} Lv.{$enemy->level} HP: {$this->red}{$hpText}{$this->reset}"); + } + $out->writeln("{$this->cyan}║{$this->reset}"); // VS 分隔 @@ -204,7 +271,7 @@ class Battle private function renderHpBar(float $percent, int $width): string { $filled = (int)($percent * $width); - $empty = $width - $filled; + $empty = max($width - $filled,0); // 根据血量百分比选择颜色 if ($percent > 0.6) { @@ -221,7 +288,16 @@ class Battle private function determineFirstStrike(): bool { - $levelDiff = $this->player->level - $this->monster->level; + // Use the leader's level for comparison + $leader = $this->enemies[count($this->enemies) - 1]; // Assume leader is last or first? + // In createGroup we put minions first, so leader is last. + // Let's just use the highest level enemy. + $maxLevel = 0; + foreach ($this->enemies as $e) { + if ($e->level > $maxLevel) $maxLevel = $e->level; + } + + $levelDiff = $this->player->level - $maxLevel; $playerChance = 50; $levelBonus = max(-30, min(30, $levelDiff * 5)); $playerChance += $levelBonus; @@ -232,10 +308,21 @@ class Battle private function playerAttack($out): bool { $stats = $this->player->getStats(); + + // Target first alive enemy + $target = null; + foreach ($this->enemies as $enemy) { + if ($enemy->hp > 0) { + $target = $enemy; + break; + } + } + + if (!$target) return true; // All dead // 计算物理伤害和魔法伤害 - $physicalDamage = max(1, $stats['patk'] - $this->monster->pdef); - $magicDamage = max(0, $stats['matk'] - $this->monster->mdef); + $physicalDamage = max(1, $stats['patk'] - $target->pdef); + $magicDamage = max(0, $stats['matk'] - $target->mdef); $baseDamage = $physicalDamage + $magicDamage; $critRate = $stats['crit']; @@ -245,21 +332,26 @@ class Battle if ($isCrit) { $damage = (int)($baseDamage * ($critDmg / 100)); - $out->writeln("{$this->cyan}║{$this->reset} {$this->green}➤{$this->reset} 你发起攻击... {$this->red}{$this->bold}暴击!{$this->reset}"); + $out->writeln("{$this->cyan}║{$this->reset} {$this->green}➤{$this->reset} 你攻击 {$target->name}... {$this->red}{$this->bold}暴击!{$this->reset}"); $out->writeln("{$this->cyan}║{$this->reset} {$this->red}💥 造成 {$damage} 点伤害!{$this->reset}"); } else { $damage = $baseDamage; - $out->writeln("{$this->cyan}║{$this->reset} {$this->green}➤{$this->reset} 你发起攻击..."); + $out->writeln("{$this->cyan}║{$this->reset} {$this->green}➤{$this->reset} 你攻击 {$target->name}..."); $out->writeln("{$this->cyan}║{$this->reset} {$this->white}⚔️ 造成 {$damage} 点伤害{$this->reset}"); } - $this->monster->hp -= $damage; + $target->hp -= $damage; - if ($this->monster->hp <= 0) { - $this->monster->hp = 0; - Screen::delay(500000); - $this->showVictory($out, $stats); - return true; + if ($target->hp <= 0) { + $target->hp = 0; + $out->writeln("{$this->cyan}║{$this->reset} {$this->red}💀 {$target->name} 被击败了!{$this->reset}"); + + // Check if all enemies are dead + if (empty($this->getAliveEnemies())) { + Screen::delay(500000); + $this->showVictory($out, $stats); + return true; + } } return false; @@ -273,11 +365,22 @@ class Battle $alivePartners = $this->getAlivePartners(); foreach ($alivePartners as $partner) { + // Target first alive enemy + $target = null; + foreach ($this->enemies as $enemy) { + if ($enemy->hp > 0) { + $target = $enemy; + break; + } + } + + if (!$target) return true; // All dead + $stats = $partner->getStats(); // 计算物理伤害和魔法伤害 - $physicalDamage = max(1, $stats['patk'] - $this->monster->pdef); - $magicDamage = max(0, $stats['matk'] - $this->monster->mdef); + $physicalDamage = max(1, $stats['patk'] - $target->pdef); + $magicDamage = max(0, $stats['matk'] - $target->mdef); $baseDamage = $physicalDamage + $magicDamage; $critRate = $stats['crit']; @@ -287,21 +390,25 @@ class Battle if ($isCrit) { $damage = (int)($baseDamage * ($critDmg / 100)); - $out->writeln("{$this->cyan}║{$this->reset} {$this->magenta}➤{$this->reset} {$partner->name} 发起攻击... {$this->red}{$this->bold}暴击!{$this->reset}"); + $out->writeln("{$this->cyan}║{$this->reset} {$this->magenta}➤{$this->reset} {$partner->name} 攻击 {$target->name}... {$this->red}{$this->bold}暴击!{$this->reset}"); $out->writeln("{$this->cyan}║{$this->reset} {$this->red}💥 造成 {$damage} 点伤害!{$this->reset}"); } else { $damage = $baseDamage; - $out->writeln("{$this->cyan}║{$this->reset} {$this->magenta}➤{$this->reset} {$partner->name} 发起攻击..."); + $out->writeln("{$this->cyan}║{$this->reset} {$this->magenta}➤{$this->reset} {$partner->name} 攻击 {$target->name}..."); $out->writeln("{$this->cyan}║{$this->reset} {$this->white}⚔️ 造成 {$damage} 点伤害{$this->reset}"); } - $this->monster->hp -= $damage; + $target->hp -= $damage; - if ($this->monster->hp <= 0) { - $this->monster->hp = 0; - Screen::delay(500000); - $this->showVictory($out, $this->player->getStats()); - return true; + if ($target->hp <= 0) { + $target->hp = 0; + $out->writeln("{$this->cyan}║{$this->reset} {$this->red}💀 {$target->name} 被击败了!{$this->reset}"); + + if (empty($this->getAliveEnemies())) { + Screen::delay(500000); + $this->showVictory($out, $this->player->getStats()); + return true; + } } Screen::delay(400000); // 每个同伴攻击间隔 @@ -310,53 +417,58 @@ class Battle return false; } - private function monsterAttack($out): bool + private function enemiesAttack($out): bool { - // 选择攻击目标:玩家或存活的同伴 - $alivePartners = $this->getAlivePartners(); - $targets = ['player']; - foreach ($alivePartners as $partner) { - $targets[] = $partner->id; - } - - $targetIdx = array_rand($targets); - $target = $targets[$targetIdx]; - - if ($target === 'player') { - // 攻击玩家 - $playerStats = $this->player->getStats(); - $physicalDamage = max(1, $this->monster->patk - $playerStats['pdef']); - $magicDamage = max(0, $this->monster->matk - $playerStats['mdef']); - $damage = $physicalDamage + $magicDamage; - - $out->writeln("{$this->cyan}║{$this->reset} {$this->red}➤{$this->reset} {$this->monster->name} 向你发起攻击..."); - $out->writeln("{$this->cyan}║{$this->reset} {$this->red}💢 你受到 {$damage} 点伤害{$this->reset}"); - - $this->player->hp -= $damage; - - if ($this->player->hp <= 0) { - $this->player->hp = 0; - Screen::delay(500000); - $this->showDefeat($out); - return true; + $aliveEnemies = $this->getAliveEnemies(); + + foreach ($aliveEnemies as $enemy) { + // 选择攻击目标:玩家或存活的同伴 + $alivePartners = $this->getAlivePartners(); + $targets = ['player']; + foreach ($alivePartners as $partner) { + $targets[] = $partner->id; } - } else { - // 攻击同伴 - $partner = $this->player->partners[$target]; - $partnerStats = $partner->getStats(); - $physicalDamage = max(1, $this->monster->patk - $partnerStats['pdef']); - $magicDamage = max(0, $this->monster->matk - $partnerStats['mdef']); - $damage = $physicalDamage + $magicDamage; - $out->writeln("{$this->cyan}║{$this->reset} {$this->red}➤{$this->reset} {$this->monster->name} 向 {$partner->name} 发起攻击..."); - $out->writeln("{$this->cyan}║{$this->reset} {$this->red}💢 {$partner->name} 受到 {$damage} 点伤害{$this->reset}"); + $targetIdx = array_rand($targets); + $target = $targets[$targetIdx]; - $this->partnerHp[$target] -= $damage; + if ($target === 'player') { + // 攻击玩家 + $playerStats = $this->player->getStats(); + $physicalDamage = max(1, $enemy->patk - $playerStats['pdef']); + $magicDamage = max(0, $enemy->matk - $playerStats['mdef']); + $damage = $physicalDamage + $magicDamage; - if ($this->partnerHp[$target] <= 0) { - $this->partnerHp[$target] = 0; - $out->writeln("{$this->cyan}║{$this->reset} {$this->red}💀 {$partner->name} 倒下了!{$this->reset}"); + $out->writeln("{$this->cyan}║{$this->reset} {$this->red}➤{$this->reset} {$enemy->name} 向你发起攻击..."); + $out->writeln("{$this->cyan}║{$this->reset} {$this->red}💢 你受到 {$damage} 点伤害{$this->reset}"); + + $this->player->hp -= $damage; + + if ($this->player->hp <= 0) { + $this->player->hp = 0; + Screen::delay(500000); + $this->showDefeat($out, $enemy); + return true; + } + } else { + // 攻击同伴 + $partner = $this->player->partners[$target]; + $partnerStats = $partner->getStats(); + $physicalDamage = max(1, $enemy->patk - $partnerStats['pdef']); + $magicDamage = max(0, $enemy->matk - $partnerStats['mdef']); + $damage = $physicalDamage + $magicDamage; + + $out->writeln("{$this->cyan}║{$this->reset} {$this->red}➤{$this->reset} {$enemy->name} 向 {$partner->name} 发起攻击..."); + $out->writeln("{$this->cyan}║{$this->reset} {$this->red}💢 {$partner->name} 受到 {$damage} 点伤害{$this->reset}"); + + $this->partnerHp[$target] -= $damage; + + if ($this->partnerHp[$target] <= 0) { + $this->partnerHp[$target] = 0; + $out->writeln("{$this->cyan}║{$this->reset} {$this->red}💀 {$partner->name} 倒下了!{$this->reset}"); + } } + Screen::delay(400000); } return false; @@ -371,21 +483,45 @@ class Battle $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}"); - $out->writeln("{$this->yellow}║{$this->reset} 击败: {$this->white}{$this->monster->name}{$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']}"); + // 汇总经验和灵石 + $totalExp = 0; + $totalStones = 0; + $allDrops = []; + + foreach ($this->enemies as $enemy) { + $totalExp += $enemy->expReward; + $totalStones += $enemy->spiritStoneReward; + + // 掉落 + foreach ($enemy->getEquippedItems() as $item) { + $this->player->addItem($item); + $allDrops[] = $item; + } + foreach ($enemy->dropTable as $drop) { + if (rand(1, 100) <= $drop['rate']) { + $this->player->addItem($drop['item']); + $allDrops[] = $drop['item']; + } + } + } + // 经验 - $exp = $this->monster->expReward; $levelUpMsg = ""; - if ($this->player->gainExp($exp)) { + if ($this->player->gainExp($totalExp)) { $levelUpMsg = " {$this->yellow}🎊 升级! Lv.{$this->player->level}{$this->reset}"; } - $out->writeln("{$this->yellow}║{$this->reset} 经验: {$this->cyan}+{$exp}{$this->reset}{$levelUpMsg}"); + $out->writeln("{$this->yellow}║{$this->reset} 经验: {$this->cyan}+{$totalExp}{$this->reset}{$levelUpMsg}"); - // 同伴经验(存活的同伴获得经验) + // 同伴经验 $alivePartners = $this->getAlivePartners(); if (!empty($alivePartners)) { - $partnerExp = (int)($exp * 0.8); // 同伴获得80%经验 + $partnerExp = (int)($totalExp * 0.8); foreach ($alivePartners as $partner) { $partnerLevelUp = ""; if ($partner->gainExp($partnerExp)) { @@ -396,32 +532,14 @@ class Battle } // 灵石 - $spiritStones = $this->monster->spiritStoneReward; - if ($spiritStones > 0) { - $this->player->addSpiritStones($spiritStones); - $out->writeln("{$this->yellow}║{$this->reset} 灵石: {$this->yellow}+{$spiritStones}{$this->reset}"); + if ($totalStones > 0) { + $this->player->addSpiritStones($totalStones); + $out->writeln("{$this->yellow}║{$this->reset} 灵石: {$this->yellow}+{$totalStones}{$this->reset}"); } - // 掉落怪物装备 - $drops = []; - - // 1. 掉落怪物的装备(100%掉落) - foreach ($this->monster->getEquippedItems() as $item) { - $this->player->addItem($item); - $drops[] = $item; - } - - // 2. 消耗品按概率掉落 - foreach ($this->monster->dropTable as $drop) { - if (rand(1, 100) <= $drop['rate']) { - $this->player->addItem($drop['item']); - $drops[] = $drop['item']; - } - } - - if (!empty($drops)) { + if (!empty($allDrops)) { $out->writeln("{$this->yellow}║{$this->reset} {$this->white}掉落:{$this->reset}"); - foreach ($drops as $item) { + foreach ($allDrops as $item) { $out->writeln("{$this->yellow}║{$this->reset} " . ItemDisplay::renderDrop($item, "")); } } @@ -430,19 +548,21 @@ class Battle $out->writeln(""); $this->game->saveState(); - Screen::delay(1500000); // 1.5秒,让玩家看清战利品 + Screen::delay(1500000); } - private function showDefeat($out) + private function showDefeat($out, ?Monster $killer = null) { 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}{$this->monster->name}{$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}"); diff --git a/src/Modules/InventoryPanel.php b/src/Modules/InventoryPanel.php index 4f5863c..27765cb 100644 --- a/src/Modules/InventoryPanel.php +++ b/src/Modules/InventoryPanel.php @@ -186,16 +186,66 @@ class InventoryPanel $stats = $player->getStats(); $maxHp = $stats['maxHp']; - // 检查是否已满血 - if ($player->hp >= $maxHp) { - $out->writeln("你的生命值已满,无需使用!"); + // 检查玩家血量 + $playerNeedsHeal = $player->hp < $maxHp; + + // 检查队友血量 + $partnersNeedHeal = []; + foreach ($player->partners as $partner) { + $partnerStats = $partner->getStats(); + $partnerMaxHp = $partnerStats['maxHp']; + if ($partner->hp < $partnerMaxHp) { + $partnersNeedHeal[] = $partner; + } + } + + // 如果都不需要恢复 + if (!$playerNeedsHeal && empty($partnersNeedHeal)) { + $out->writeln("你和队友的生命值都已满,无需使用!"); Screen::sleep(1); return; } - // 使用 heal 方法恢复生命,不超过上限 - $actualHeal = $player->heal($item['heal']); - $out->writeln("你使用了 {$item['name']},恢复了 {$actualHeal} HP!(当前: {$player->hp}/{$maxHp})"); + // 选择恢复目标 + $target = null; + if ($playerNeedsHeal && !empty($partnersNeedHeal)) { + // 需要询问玩家选择 + $out->writeln(""); + $out->writeln("选择恢复目标:"); + $out->writeln("[1] 恢复自己"); + foreach ($partnersNeedHeal as $i => $partner) { + $out->writeln("[" . ($i + 2) . "] 恢复 {$partner->name}"); + } + + $choice = Screen::input($out, "选择:"); + $choiceInt = (int)$choice; + + if ($choiceInt === 1) { + $target = 'player'; + } elseif ($choiceInt >= 2 && $choiceInt - 2 < count($partnersNeedHeal)) { + $target = $partnersNeedHeal[$choiceInt - 2]; + } else { + $out->writeln("无效选择"); + Screen::sleep(1); + return; + } + } elseif ($playerNeedsHeal) { + $target = 'player'; + } elseif (!empty($partnersNeedHeal)) { + $target = $partnersNeedHeal[0]; + } + + // 使用消耗品进行恢复 + if ($target === 'player') { + $actualHeal = $player->heal($item['heal']); + $out->writeln("你使用了 {$item['name']},恢复了 {$actualHeal} HP!(当前: {$player->hp}/{$maxHp})"); + } else { + // 恢复队友 + $partnerStats = $target->getStats(); + $partnerMaxHp = $partnerStats['maxHp']; + $actualHeal = $target->heal($item['heal']); + $out->writeln("你使用了 {$item['name']} 来恢复 {$target->name},恢复了 {$actualHeal} HP!(当前: {$target->hp}/{$partnerMaxHp})"); + } // Decrease quantity or remove if (($player->inventory[$index]['quantity'] ?? 1) > 1) { diff --git a/src/Modules/TalentPanel.php b/src/Modules/TalentPanel.php index ac5e92c..cf3139e 100644 --- a/src/Modules/TalentPanel.php +++ b/src/Modules/TalentPanel.php @@ -63,11 +63,11 @@ class TalentPanel $this->game->output->writeln("{$this->cyan}║{$this->reset} 暴击: {$this->yellow}{$stats['crit']}%{$this->reset} 暴伤: {$this->yellow}{$stats['critdmg']}%{$this->reset}"); $this->game->output->writeln("{$this->cyan}╚════════════════════════════════════════╝{$this->reset}"); $this->game->output->writeln(""); - $this->game->output->writeln("[1-5] 加点 | [r] 重置天赋 | [99] 返回"); + $this->game->output->writeln("[1-5] 加点 | [r] 重置天赋 | [0] 返回"); $choice = Input::ask($this->game->output, "请选择: "); - if ($choice == 99) { + if ($choice == 0) { $this->game->state = Game::MENU; return; }